diff --git a/.gitattributes b/.gitattributes
index 923154272da..3f33ee2791e 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -10,6 +10,7 @@
/LICENSE.txt svneol=native#text/plain
/README.txt svneol=native#text/plain
/pom.xml svneol=native#text/xml
+res/ai/Default.ai -text
res/blockdata/blocks.txt svneol=native#text/plain
res/blockdata/boosters.txt -text
res/blockdata/fantasyblocks.txt -text
@@ -14132,6 +14133,8 @@ src/main/java/forge/game/ai/AiAttackController.java svneol=native#text/plain
src/main/java/forge/game/ai/AiController.java svneol=native#text/plain
src/main/java/forge/game/ai/AiInputBlock.java -text
src/main/java/forge/game/ai/AiInputCommon.java svneol=native#text/plain
+src/main/java/forge/game/ai/AiProfileUtil.java -text
+src/main/java/forge/game/ai/AiProps.java -text
src/main/java/forge/game/ai/ComputerUtil.java svneol=native#text/plain
src/main/java/forge/game/ai/ComputerUtilBlock.java svneol=native#text/plain
src/main/java/forge/game/ai/ComputerUtilCard.java -text
diff --git a/res/ai/Default.ai b/res/ai/Default.ai
new file mode 100644
index 00000000000..ff5239c5d8b
--- /dev/null
+++ b/res/ai/Default.ai
@@ -0,0 +1 @@
+AI_MULLIGAN_THRESHOLD=5
diff --git a/src/main/java/forge/control/FControl.java b/src/main/java/forge/control/FControl.java
index c4310a85786..fffeba57872 100644
--- a/src/main/java/forge/control/FControl.java
+++ b/src/main/java/forge/control/FControl.java
@@ -34,6 +34,7 @@ import javax.swing.WindowConstants;
import forge.Singletons;
import forge.control.KeyboardShortcuts.Shortcut;
+import forge.game.ai.AiProfileUtil;
import forge.game.player.Player;
import forge.gui.SOverlayUtils;
import forge.gui.deckeditor.CDeckEditorUI;
@@ -162,6 +163,9 @@ public enum FControl {
Singletons.getModel().getQuest().load(QuestDataIO.loadData(data));
}
+ // Preload AI profiles
+ AiProfileUtil.loadAllProfiles();
+
// Handles resizing in null layouts of layers in JLayeredPane.
Singletons.getView().getFrame().addComponentListener(new ComponentAdapter() {
@Override
diff --git a/src/main/java/forge/game/MatchController.java b/src/main/java/forge/game/MatchController.java
index e0dd57a45dc..73967a75d90 100644
--- a/src/main/java/forge/game/MatchController.java
+++ b/src/main/java/forge/game/MatchController.java
@@ -13,6 +13,7 @@ import forge.control.FControl;
import forge.control.input.InputControl;
import forge.deck.Deck;
import forge.error.BugReporter;
+import forge.game.ai.AiProfileUtil;
import forge.game.event.DuelOutcomeEvent;
import forge.game.player.LobbyPlayer;
import forge.game.player.Player;
@@ -137,6 +138,26 @@ public class MatchController {
startConditions.put(p, players.get(p.getLobbyPlayer()));
}
+ // Set the current AI profile.
+ for (Player p : currentGame.getPlayers()) {
+ if (p.getType() == PlayerType.COMPUTER) {
+ if (Singletons.getModel().getPreferences().getPref(FPref.UI_CURRENT_AI_PROFILE).equals(AiProfileUtil.AI_PROFILE_RANDOM_DUEL)) {
+ String randomProfile = AiProfileUtil.getRandomProfile();
+ p.getLobbyPlayer().setAiProfile(randomProfile);
+ } else if (Singletons.getModel().getPreferences().getPref(FPref.UI_CURRENT_AI_PROFILE).equals(AiProfileUtil.AI_PROFILE_RANDOM_MATCH)) {
+ if (this.getPlayedGames().isEmpty()) {
+ String randomProfile = AiProfileUtil.getRandomProfile();
+ p.getLobbyPlayer().setAiProfile(randomProfile);
+ }
+ } else {
+ // TODO: implement specific AI profiles for quest mode.
+ String profile = Singletons.getModel().getPreferences().getPref(FPref.UI_CURRENT_AI_PROFILE);
+ p.getLobbyPlayer().setAiProfile(profile);
+ }
+ System.out.println(String.format("AI profile %s was chosen for the lobby player %s.", p.getLobbyPlayer().getAiProfile(), p.getLobbyPlayer().getName()));
+ }
+ }
+
try {
Player localHuman = Aggregates.firstFieldEquals(currentGame.getPlayers(), Player.Accessors.FN_GET_TYPE, PlayerType.HUMAN);
FControl.SINGLETON_INSTANCE.setPlayer(localHuman);
diff --git a/src/main/java/forge/game/ai/AiController.java b/src/main/java/forge/game/ai/AiController.java
index 3db947596de..dbba372c178 100644
--- a/src/main/java/forge/game/ai/AiController.java
+++ b/src/main/java/forge/game/ai/AiController.java
@@ -719,5 +719,17 @@ public class AiController {
}
return null;
}
+
+ public String getProperty(AiProps propName) {
+ return AiProfileUtil.getAIProp(getPlayer().getLobbyPlayer(), propName);
+ }
+
+ public int getIntProperty(AiProps propName) {
+ return Integer.parseInt(AiProfileUtil.getAIProp(getPlayer().getLobbyPlayer(), propName));
+ }
+
+ public boolean getBooleanProperty(AiProps propName) {
+ return Boolean.parseBoolean(AiProfileUtil.getAIProp(getPlayer().getLobbyPlayer(), propName));
+ }
}
diff --git a/src/main/java/forge/game/ai/AiProfileUtil.java b/src/main/java/forge/game/ai/AiProfileUtil.java
new file mode 100644
index 00000000000..3db912f0a0a
--- /dev/null
+++ b/src/main/java/forge/game/ai/AiProfileUtil.java
@@ -0,0 +1,184 @@
+/*
+ * Forge: Play Magic: the Gathering.
+ * Copyright (C) 2013 Forge Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package forge.game.ai;
+
+import forge.Singletons;
+import forge.game.player.LobbyPlayer;
+import forge.util.Aggregates;
+import forge.util.FileUtil;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+
+/**
+ * Holds default AI personality profile values in an enum.
+ * Loads profile from the given text file when setProfile is called.
+ * If a requested value is not loaded from a profile, default is returned.
+ *
+ * @author Forge
+ * @version $Id: AIProfile.java 20169 2013-03-08 08:24:17Z Agetian $
+ */
+public class AiProfileUtil {
+ private static Map> loadedProfiles = new HashMap>();
+
+ private static final String AI_PROFILE_DIR = "res/ai";
+ private static final String AI_PROFILE_EXT = ".ai";
+
+ public static final String AI_PROFILE_RANDOM_MATCH = "* Random (Match) *";
+ public static final String AI_PROFILE_RANDOM_DUEL = "* Random (Duel) *";
+
+ /** Builds an AI profile file name with full relative
+ * path based on the profile name.
+ * @param profileName the name of the profile.
+ * @return the full relative path and file name for the given profile.
+ */
+ private static String buildFileName(final String profileName) {
+ return String.format("%s/%s%s", AI_PROFILE_DIR, profileName, AI_PROFILE_EXT);
+ }
+
+ /**
+ * Load all profiles
+ */
+ public static final void loadAllProfiles() {
+ loadedProfiles.clear();
+ ArrayList availableProfiles = getAvailableProfiles();
+ for (String profile : availableProfiles) {
+ loadedProfiles.put(profile, loadProfile(profile));
+ }
+ }
+
+ /**
+ * Load a single profile.
+ * @param profileName a profile to load.
+ */
+ private static final Map loadProfile(final String profileName) {
+ Map profileMap = new HashMap();
+
+ List lines = FileUtil.readFile(buildFileName(profileName));
+ for (String line : lines) {
+
+ if (line.startsWith("#") || (line.length() == 0)) {
+ continue;
+ }
+
+ final String[] split = line.split("=");
+
+ if (split.length == 2) {
+ profileMap.put(AiProps.valueOf(split[0]), split[1]);
+ } else if (split.length == 1 && line.endsWith("=")) {
+ profileMap.put(AiProps.valueOf(split[0]), "");
+ }
+ }
+
+ return profileMap;
+ }
+
+ /**
+ * Returns an AI property value for the current profile.
+ *
+ * @param fp0 an AI property.
+ * @return String
+ */
+ public static String getAIProp(final LobbyPlayer p, final AiProps fp0) {
+ String val = null;
+ String profile = p.getAiProfile();
+
+ if (loadedProfiles.get(profile) != null) {
+ val = loadedProfiles.get(profile).get(fp0);
+ }
+ if (val == null) { val = fp0.getDefault(); }
+
+ return val;
+ }
+
+ /**
+ * Returns an array of strings containing all available profiles.
+ * @return ArrayList - an array of strings containing all
+ * available profiles.
+ */
+ public static ArrayList getAvailableProfiles()
+ {
+ final ArrayList availableProfiles = new ArrayList();
+
+ final File dir = new File(AI_PROFILE_DIR);
+ final String[] children = dir.list();
+ if (children == null) {
+ System.err.println("AIProfile > can't find AI profile directory!");
+ } else {
+ for (int i = 0; i < children.length; i++) {
+ if (children[i].endsWith(AI_PROFILE_EXT)) {
+ availableProfiles.add(children[i].substring(0, children[i].length() - AI_PROFILE_EXT.length()));
+ }
+ }
+ }
+
+ return availableProfiles;
+ }
+
+ /**
+ * Returns an array of strings containing all available profiles including
+ * the special "Random" profiles.
+ * @return ArrayList - an array list of strings containing all
+ * available profiles including special random profile tags.
+ */
+ public static ArrayList getProfilesDisplayList() {
+ final ArrayList availableProfiles = new ArrayList();
+ availableProfiles.add(AI_PROFILE_RANDOM_MATCH);
+ availableProfiles.add(AI_PROFILE_RANDOM_DUEL);
+ availableProfiles.addAll(getAvailableProfiles());
+
+ return availableProfiles;
+ }
+
+ /**
+ * Returns a random personality from the currently available ones.
+ * @return String - a string containing a random profile from all the
+ * currently available ones.
+ */
+ public static String getRandomProfile() {
+ return Aggregates.random(getAvailableProfiles());
+ }
+
+ /**
+ * Simple class test facility for AiProfileUtil.
+ */
+ public static void selfTest() {
+ final LobbyPlayer activePlayer = Singletons.getControl().getPlayer().getLobbyPlayer();
+ System.out.println(String.format("Current profile = %s", activePlayer.getAiProfile()));
+ ArrayList profiles = getAvailableProfiles();
+ System.out.println(String.format("Available profiles: %s", profiles));
+ if (profiles.size() > 0) {
+ System.out.println(String.format("Loading all profiles..."));
+ loadAllProfiles();
+ System.out.println(String.format("Setting profile %s...", profiles.get(0)));
+ activePlayer.setAiProfile(profiles.get(0));
+ for (AiProps property : AiProps.values()) {
+ System.out.println(String.format("%s = %s", property, getAIProp(activePlayer, property)));
+ }
+ String randomProfile = getRandomProfile();
+ System.out.println(String.format("Loading random profile %s...", randomProfile));
+ activePlayer.setAiProfile(randomProfile);
+ for (AiProps property : AiProps.values()) {
+ System.out.println(String.format("%s = %s", property, getAIProp(activePlayer, property)));
+ }
+ }
+ }
+}
diff --git a/src/main/java/forge/game/ai/AiProps.java b/src/main/java/forge/game/ai/AiProps.java
new file mode 100644
index 00000000000..3484e5b70a4
--- /dev/null
+++ b/src/main/java/forge/game/ai/AiProps.java
@@ -0,0 +1,41 @@
+/*
+ * Forge: Play Magic: the Gathering.
+ * Copyright (C) 2013 Forge Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package forge.game.ai;
+
+/**
+ * AI personality profile settings identifiers, and their default values.
+ * When this class is instantiated, these enum values are used
+ * in a map that is populated with the current AI profile settings
+ * from the text file.
+ */
+public enum AiProps { /** */
+ AI_MULLIGAN_THRESHOLD ("5"); /** */
+
+ private final String strDefaultVal;
+
+ /** @param s0 {@link java.lang.String} */
+ AiProps(final String s0) {
+ this.strDefaultVal = s0;
+ }
+
+ /** @return {@link java.lang.String} */
+ public String getDefault() {
+ return strDefaultVal;
+ }
+}
+
diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java
index ae723cd7071..fa0f93d9635 100644
--- a/src/main/java/forge/game/ai/ComputerUtil.java
+++ b/src/main/java/forge/game/ai/ComputerUtil.java
@@ -1202,11 +1202,9 @@ public class ComputerUtil {
// Computer mulligans if there are no cards with converted mana cost of
// 0 in its hand
public static boolean wantMulligan(AIPlayer ai) {
- final int AI_MULLIGAN_THRESHOLD = 5;
-
final List handList = ai.getCardsIn(ZoneType.Hand);
final boolean hasLittleCmc0Cards = CardLists.getValidCards(handList, "Card.cmcEQ0", ai, null).size() < 2;
- return (handList.size() > AI_MULLIGAN_THRESHOLD) && hasLittleCmc0Cards;
+ return (handList.size() > ai.getAi().getIntProperty(AiProps.AI_MULLIGAN_THRESHOLD)) && hasLittleCmc0Cards;
}
diff --git a/src/main/java/forge/game/player/LobbyPlayer.java b/src/main/java/forge/game/player/LobbyPlayer.java
index 2efb0d9281d..28adde731b1 100644
--- a/src/main/java/forge/game/player/LobbyPlayer.java
+++ b/src/main/java/forge/game/player/LobbyPlayer.java
@@ -1,5 +1,8 @@
package forge.game.player;
+import forge.game.ai.AiProfileUtil;
+import forge.game.ai.AiProps;
+
/**
* This means a player's part unchanged for all games.
*
@@ -17,6 +20,9 @@ public class LobbyPlayer implements IHasIcon {
protected String imageKey;
private int avatarIndex = -1;
+ /** The AI profile. */
+ private String aiProfile = "";
+
public LobbyPlayer(PlayerType type, String name) {
this.type = type;
@@ -75,4 +81,12 @@ public class LobbyPlayer implements IHasIcon {
public void setAvatarIndex(int avatarIndex) {
this.avatarIndex = avatarIndex;
}
+
+ public void setAiProfile(String profileName) {
+ aiProfile = profileName;
+ }
+
+ public String getAiProfile() {
+ return aiProfile;
+ }
}
diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java
index 5da39b7bc01..a595e1c7445 100644
--- a/src/main/java/forge/game/player/Player.java
+++ b/src/main/java/forge/game/player/Player.java
@@ -164,7 +164,6 @@ public abstract class Player extends GameEntity implements Comparable {
ZoneType.Library, ZoneType.Graveyard, ZoneType.Hand, ZoneType.Exile, ZoneType.Command, ZoneType.Ante,
ZoneType.Sideboard));
-
protected final LobbyPlayer lobbyPlayer;
protected final GameState game;
diff --git a/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java b/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java
index 449b438fef1..988ee96cc89 100644
--- a/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java
+++ b/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java
@@ -13,10 +13,12 @@ import forge.Command;
import forge.Constant.Preferences;
import forge.Singletons;
import forge.control.RestartUtil;
+import forge.game.ai.AiProfileUtil;
import forge.gui.framework.ICDoc;
import forge.gui.toolbox.FSkin;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
+import java.util.ArrayList;
/**
* Controls the preferences submenu in the home UI.
@@ -44,6 +46,13 @@ public enum CSubmenuPreferences implements ICDoc {
}
});
+ view.getLstChooseAIProfile().addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(final MouseEvent e) {
+ updateAIProfile();
+ }
+ });
+
view.getCbAnte().addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent arg0) {
@@ -187,6 +196,7 @@ public enum CSubmenuPreferences implements ICDoc {
final VSubmenuPreferences view = VSubmenuPreferences.SINGLETON_INSTANCE;
final ForgePreferences prefs = Singletons.getModel().getPreferences();
updateSkinNames();
+ updateAIProfiles();
view.getCbRemoveSmall().setSelected(prefs.getPrefBoolean(FPref.DECKGEN_NOSMALL));
view.getCbSingletons().setSelected(prefs.getPrefBoolean(FPref.DECKGEN_SINGLETONS));
@@ -226,6 +236,21 @@ public enum CSubmenuPreferences implements ICDoc {
view.getLstChooseSkin().ensureIndexIsVisible(view.getLstChooseSkin().getSelectedIndex());
}
+ private void updateAIProfiles() {
+ final VSubmenuPreferences view = VSubmenuPreferences.SINGLETON_INSTANCE;
+ final ArrayList profileNames = AiProfileUtil.getProfilesDisplayList();
+ final String currentName = Singletons.getModel().getPreferences().getPref(FPref.UI_CURRENT_AI_PROFILE);
+ int currentIndex = 0;
+
+ for (int i = 0; i < profileNames.size(); i++) {
+ if (currentName.equalsIgnoreCase(profileNames.get(i))) { currentIndex = i; }
+ }
+
+ view.getLstChooseAIProfile().setListData(profileNames.toArray());
+ view.getLstChooseAIProfile().setSelectedIndex(currentIndex);
+ view.getLstChooseAIProfile().ensureIndexIsVisible(view.getLstChooseAIProfile().getSelectedIndex());
+ }
+
@SuppressWarnings("serial")
private void updateSkin() {
final VSubmenuPreferences view = VSubmenuPreferences.SINGLETON_INSTANCE;
@@ -243,6 +268,16 @@ public enum CSubmenuPreferences implements ICDoc {
prefs.save();
}
+ @SuppressWarnings("serial")
+ private void updateAIProfile() {
+ final VSubmenuPreferences view = VSubmenuPreferences.SINGLETON_INSTANCE;
+ final String name = view.getLstChooseAIProfile().getSelectedValue().toString();
+ final ForgePreferences prefs = Singletons.getModel().getPreferences();
+ if (name.equals(prefs.getPref(FPref.UI_CURRENT_AI_PROFILE))) { return; }
+
+ prefs.setPref(FPref.UI_CURRENT_AI_PROFILE, name);
+ prefs.save();
+ }
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
*/
diff --git a/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java b/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java
index 925ab3c3348..d8306dd4995 100644
--- a/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java
+++ b/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java
@@ -64,7 +64,7 @@ public enum VSubmenuPreferences implements IVSubmenu {
.hoverable(true).text("Reset to defaults").build();
private final FLabel lblTitleSkin = new FLabel.Builder()
- .text("Choose Skin").fontStyle(Font.BOLD).fontSize(14).build();
+ .text("Choose Skin").fontStyle(Font.BOLD).fontSize(14).build();
private final JList lstChooseSkin = new FList();
private final FLabel lblChooseSkin = new FLabel.Builder().fontSize(12).fontStyle(Font.ITALIC)
@@ -72,6 +72,15 @@ public enum VSubmenuPreferences implements IVSubmenu {
.fontAlign(SwingConstants.LEFT).build();
private final JScrollPane scrChooseSkin = new FScrollPane(lstChooseSkin);
+ private final FLabel lblTitleAIProfile = new FLabel.Builder()
+ .text("Choose AI Personality").fontStyle(Font.BOLD).fontSize(14).build();
+
+ private final JList lstChooseAIProfile = new FList();
+ private final FLabel lblChooseAIProfile = new FLabel.Builder().fontSize(12).fontStyle(Font.ITALIC)
+ .text("AI Opponent Personality.")
+ .fontAlign(SwingConstants.LEFT).build();
+ private final JScrollPane scrChooseAIProfile = new FScrollPane(lstChooseAIProfile);
+
private final JCheckBox cbRemoveSmall = new OptionsCheckBox("Remove Small Creatures");
private final JCheckBox cbSingletons = new OptionsCheckBox("Singleton Mode");
private final JCheckBox cbRemoveArtifacts = new OptionsCheckBox("Remove Artifacts");
@@ -134,6 +143,13 @@ public enum VSubmenuPreferences implements IVSubmenu {
pnlPrefs.add(cbEnforceDeckLegality, regularConstraints);
pnlPrefs.add(new NoteLabel("Enforces deck legality relevant to each environment (minimum deck sizes, max card count etc)"), regularConstraints);
+ // AI Personality Profile Options
+ pnlPrefs.add(new SectionLabel("AI Options"), sectionConstraints);
+
+ pnlPrefs.add(lblTitleAIProfile, regularConstraints);
+ pnlPrefs.add(lblChooseAIProfile, regularConstraints);
+ pnlPrefs.add(scrChooseAIProfile, "h 200px!, w 200px!, gap 10% 0 0 2%, wrap");
+
// Graphic Options
pnlPrefs.add(new SectionLabel("Graphic Options"), sectionConstraints);
@@ -355,6 +371,21 @@ public enum VSubmenuPreferences implements IVSubmenu {
return scrChooseSkin;
}
+ /** @return {@link javax.swing.JList} */
+ public final JList getLstChooseAIProfile() {
+ return lstChooseAIProfile;
+ }
+
+ /** @return {@link forge.gui.toolbox.FLabel} */
+ public final FLabel getLblChooseAIProfile() {
+ return lblChooseAIProfile;
+ }
+
+ /** @return {@link javax.swing.JScrollPane} */
+ public final JScrollPane getScrChooseAIProfile() {
+ return scrChooseAIProfile;
+ }
+
/** @return {@link javax.swing.JCheckBox} */
public final JCheckBox getCbRemoveSmall() {
return cbRemoveSmall;
diff --git a/src/main/java/forge/properties/ForgePreferences.java b/src/main/java/forge/properties/ForgePreferences.java
index 0e5a4e4bafe..8a951c5f44d 100644
--- a/src/main/java/forge/properties/ForgePreferences.java
+++ b/src/main/java/forge/properties/ForgePreferences.java
@@ -21,6 +21,7 @@ import java.util.List;
import forge.Constant;
import forge.Constant.Preferences;
+import forge.game.ai.AiProfileUtil;
import forge.gui.home.EMenuItem;
import forge.gui.match.VMatchUI;
import forge.gui.match.nonsingleton.VField;
@@ -50,6 +51,7 @@ public class ForgePreferences extends PreferencesStore {
UI_TARGETING_OVERLAY ("false"),
UI_ENABLE_SOUNDS ("true"),
UI_RANDOM_CARD_ART ("false"),
+ UI_CURRENT_AI_PROFILE (AiProfileUtil.AI_PROFILE_RANDOM_MATCH), /** */
SUBMENU_CURRENTMENU (EMenuItem.CONSTRUCTED.toString()),
SUBMENU_SANCTIONED ("false"),