mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 18:58:00 +00:00
Make progress in segregating game model data; move some fields from forge.AllZone to forge.model.FGameState.
Left delegate methods in AllZone, marking their Javadoc (in English) for future deprecation. Added some rudimentary tests on forge.model.FModel's getGameState and resetGameState methods. Bug: 154
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -9766,6 +9766,7 @@ src/main/java/forge/gui/input/Input_PayManaCost_Ability.java svneol=native#text/
|
||||
src/main/java/forge/gui/input/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/gui/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/model/BuildInfo.java -text
|
||||
src/main/java/forge/model/FGameState.java -text
|
||||
src/main/java/forge/model/FModel.java svneol=native#text/plain
|
||||
src/main/java/forge/model/MultipleForgeJarsFoundError.java -text
|
||||
src/main/java/forge/model/package-info.java svneol=native#text/plain
|
||||
|
||||
@@ -8,11 +8,12 @@ import forge.card.trigger.TriggerHandler;
|
||||
import forge.deck.DeckManager;
|
||||
import forge.game.GameSummary;
|
||||
import forge.gui.input.InputControl;
|
||||
import forge.model.FGameState;
|
||||
import forge.model.FModel;
|
||||
import forge.properties.ForgeProps;
|
||||
import forge.properties.NewConstants;
|
||||
import forge.quest.data.QuestMatchState;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -31,10 +32,6 @@ public class AllZone implements NewConstants {
|
||||
//only for testing, should read decks from local directory
|
||||
// public static final IO IO = new IO("all-decks");
|
||||
|
||||
/** Constant <code>HumanPlayer</code> */
|
||||
private static final Player HumanPlayer = new HumanPlayer("Human");
|
||||
/** Constant <code>ComputerPlayer</code> */
|
||||
private static final Player ComputerPlayer = new AIPlayer("Computer");
|
||||
|
||||
/** Constant <code>QuestData</code> */
|
||||
private static forge.quest.data.QuestData QuestData = null;
|
||||
@@ -45,36 +42,18 @@ public class AllZone implements NewConstants {
|
||||
/** Constant <code>ColorChanger</code> */
|
||||
private static final ColorChanger colorChanger = new ColorChanger();
|
||||
|
||||
/** Constant <code>EndOfTurn</code> */
|
||||
private static EndOfTurn EndOfTurn = new EndOfTurn();
|
||||
/** Constant <code>EndOfCombat</code> */
|
||||
private static EndOfCombat EndOfCombat = new EndOfCombat();
|
||||
private static Upkeep Upkeep = new Upkeep();
|
||||
|
||||
/** Constant <code>Phase</code> */
|
||||
private static final Phase Phase = new Phase();
|
||||
|
||||
// Phase is now a prerequisite for CardFactory
|
||||
/** Constant <code>CardFactory</code> */
|
||||
private static CardFactoryInterface cardFactory = null;
|
||||
|
||||
/** Constant <code>Stack</code> */
|
||||
private static final MagicStack Stack = new MagicStack();
|
||||
/** Constant <code>InputControl</code> */
|
||||
private static final InputControl InputControl = new InputControl();
|
||||
/** Constant <code>GameAction</code> */
|
||||
private static final GameAction GameAction = new GameAction();
|
||||
/** Constant <code>StaticEffects</code> */
|
||||
private static final StaticEffects StaticEffects = new StaticEffects();
|
||||
|
||||
/** Game state observer <code>GameSummary</code> collects statistics and players' performance*/
|
||||
private static GameSummary gameInfo = new GameSummary();
|
||||
/** Match State for quests are stored in a <code>QuestMatchState</code> class instance*/
|
||||
public static QuestMatchState matchState = new QuestMatchState();
|
||||
|
||||
/** Constant <code>TriggerHandler</code> */
|
||||
private static final TriggerHandler TriggerHandler = new TriggerHandler();
|
||||
|
||||
//initialized at Runtime since it has to be the last object constructed
|
||||
|
||||
/** Constant <code>Computer</code> */
|
||||
@@ -82,86 +61,40 @@ public class AllZone implements NewConstants {
|
||||
|
||||
//shared between Input_Attack, Input_Block, Input_CombatDamage , InputState_Computer
|
||||
|
||||
/** Constant <code>Combat</code> */
|
||||
private static Combat Combat = new Combat();
|
||||
|
||||
//Human_Play, Computer_Play is different because Card.comesIntoPlay() is called when a card is added by PlayerZone.add(Card)
|
||||
/** Constant <code>Human_Battlefield</code> */
|
||||
private final static PlayerZone Human_Battlefield = new PlayerZone_ComesIntoPlay(Constant.Zone.Battlefield, AllZone.getHumanPlayer());
|
||||
/** Constant <code>Human_Hand</code> */
|
||||
private final static PlayerZone Human_Hand = new DefaultPlayerZone(Constant.Zone.Hand, AllZone.getHumanPlayer());
|
||||
/** Constant <code>Human_Graveyard</code> */
|
||||
private final static PlayerZone Human_Graveyard = new DefaultPlayerZone(Constant.Zone.Graveyard, AllZone.getHumanPlayer());
|
||||
/** Constant <code>Human_Library</code> */
|
||||
private final static PlayerZone Human_Library = new DefaultPlayerZone(Constant.Zone.Library, AllZone.getHumanPlayer());
|
||||
/** Constant <code>Human_Exile</code> */
|
||||
private final static PlayerZone Human_Exile = new DefaultPlayerZone(Constant.Zone.Exile, AllZone.getHumanPlayer());
|
||||
/** Constant <code>Human_Command</code> */
|
||||
private final static PlayerZone Human_Command = new DefaultPlayerZone(Constant.Zone.Command, AllZone.getHumanPlayer());
|
||||
|
||||
/** Constant <code>Computer_Battlefield</code> */
|
||||
private final static PlayerZone Computer_Battlefield = new PlayerZone_ComesIntoPlay(Constant.Zone.Battlefield, AllZone.getComputerPlayer());
|
||||
/** Constant <code>Computer_Hand</code> */
|
||||
private final static PlayerZone Computer_Hand = new DefaultPlayerZone(Constant.Zone.Hand, AllZone.getComputerPlayer());
|
||||
/** Constant <code>Computer_Graveyard</code> */
|
||||
private final static PlayerZone Computer_Graveyard = new DefaultPlayerZone(Constant.Zone.Graveyard, AllZone.getComputerPlayer());
|
||||
/** Constant <code>Computer_Library</code> */
|
||||
private final static PlayerZone Computer_Library = new DefaultPlayerZone(Constant.Zone.Library, AllZone.getComputerPlayer());
|
||||
/** Constant <code>Computer_Exile</code> */
|
||||
private final static PlayerZone Computer_Exile = new DefaultPlayerZone(Constant.Zone.Exile, AllZone.getComputerPlayer());
|
||||
/** Constant <code>Computer_Command</code> */
|
||||
private final static PlayerZone Computer_Command = new DefaultPlayerZone(Constant.Zone.Command, AllZone.getComputerPlayer());
|
||||
|
||||
/** Constant <code>Stack_Zone</code> */
|
||||
private final static PlayerZone Stack_Zone = new DefaultPlayerZone(Constant.Zone.Stack, null);
|
||||
|
||||
/** Constant <code>Display</code> */
|
||||
private static Display Display;
|
||||
|
||||
/** Constant <code>map</code> */
|
||||
private final static Map<String, PlayerZone> map = new HashMap<String, PlayerZone>();
|
||||
|
||||
static {
|
||||
map.put(Constant.Zone.Graveyard + AllZone.getHumanPlayer(), Human_Graveyard);
|
||||
map.put(Constant.Zone.Hand + AllZone.getHumanPlayer(), Human_Hand);
|
||||
map.put(Constant.Zone.Library + AllZone.getHumanPlayer(), Human_Library);
|
||||
map.put(Constant.Zone.Battlefield + AllZone.getHumanPlayer(), Human_Battlefield);
|
||||
map.put(Constant.Zone.Exile + AllZone.getHumanPlayer(), Human_Exile);
|
||||
map.put(Constant.Zone.Command + AllZone.getHumanPlayer(), Human_Command);
|
||||
|
||||
map.put(Constant.Zone.Graveyard + AllZone.getComputerPlayer(), Computer_Graveyard);
|
||||
map.put(Constant.Zone.Hand + AllZone.getComputerPlayer(), Computer_Hand);
|
||||
map.put(Constant.Zone.Library + AllZone.getComputerPlayer(), Computer_Library);
|
||||
map.put(Constant.Zone.Battlefield + AllZone.getComputerPlayer(), Computer_Battlefield);
|
||||
map.put(Constant.Zone.Exile + AllZone.getComputerPlayer(), Computer_Exile);
|
||||
map.put(Constant.Zone.Command + AllZone.getComputerPlayer(), Computer_Command);
|
||||
|
||||
map.put(Constant.Zone.Stack + null, Stack_Zone);
|
||||
}
|
||||
|
||||
private static long timestamp = 0;
|
||||
|
||||
/** Constant <code>DeckManager</code> */
|
||||
private final static DeckManager dMgr = new DeckManager(ForgeProps.getFile(NEW_DECKS));
|
||||
|
||||
/**
|
||||
* <p>getHumanPlayer.</p>
|
||||
*
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.Player} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static Player getHumanPlayer() {
|
||||
return HumanPlayer;
|
||||
final FGameState gameState = Singletons.getModel().getGameState();
|
||||
|
||||
if (gameState != null) {
|
||||
return gameState.getHumanPlayer();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getComputerPlayer.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.Player} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static Player getComputerPlayer() {
|
||||
return ComputerPlayer;
|
||||
return Singletons.getModel().getGameState().getComputerPlayer();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,41 +150,55 @@ public class AllZone implements NewConstants {
|
||||
/**
|
||||
* <p>getEndOfTurn.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.EndOfTurn} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static EndOfTurn getEndOfTurn() {
|
||||
return EndOfTurn;
|
||||
return Singletons.getModel().getGameState().getEndOfTurn();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getEndOfCombat.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.EndOfCombat} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static forge.EndOfCombat getEndOfCombat() {
|
||||
return EndOfCombat;
|
||||
return Singletons.getModel().getGameState().getEndOfCombat();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>getUpkeep.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.EndOfCombat} object.
|
||||
* @since 1.0.16
|
||||
*/
|
||||
public static forge.Upkeep getUpkeep() {
|
||||
return Upkeep;
|
||||
return Singletons.getModel().getGameState().getUpkeep();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getPhase.</p>
|
||||
*
|
||||
* @return a {@link forge.Phase} object.
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.Phase} object; may be null.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static Phase getPhase() {
|
||||
return Phase;
|
||||
final FGameState gameState = Singletons.getModel().getGameState();
|
||||
|
||||
if (gameState != null) {
|
||||
return gameState.getPhase();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,11 +222,19 @@ public class AllZone implements NewConstants {
|
||||
/**
|
||||
* <p>getStack.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.MagicStack} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static MagicStack getStack() {
|
||||
return Stack;
|
||||
final FGameState gameState = Singletons.getModel().getGameState();
|
||||
|
||||
if (gameState != null) {
|
||||
return gameState.getStack();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,21 +250,37 @@ public class AllZone implements NewConstants {
|
||||
/**
|
||||
* <p>getGameAction.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.GameAction} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static GameAction getGameAction() {
|
||||
return GameAction;
|
||||
final FGameState gameState = Singletons.getModel().getGameState();
|
||||
|
||||
if (gameState != null) {
|
||||
return gameState.getGameAction();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getStaticEffects.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.StaticEffects} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static StaticEffects getStaticEffects() {
|
||||
return StaticEffects;
|
||||
final FGameState gameState = Singletons.getModel().getGameState();
|
||||
|
||||
if (gameState != null) {
|
||||
return gameState.getStaticEffects();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,11 +296,13 @@ public class AllZone implements NewConstants {
|
||||
/**
|
||||
* <p>getTriggerHandler.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.card.trigger.TriggerHandler} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static TriggerHandler getTriggerHandler() {
|
||||
return TriggerHandler;
|
||||
return Singletons.getModel().getGameState().getTriggerHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,152 +328,182 @@ public class AllZone implements NewConstants {
|
||||
/**
|
||||
* <p>getCombat.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.Combat} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static Combat getCombat() {
|
||||
return Combat;
|
||||
return Singletons.getModel().getGameState().getCombat();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>setCombat.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @param attackers a {@link forge.Combat} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static void setCombat(Combat attackers) {
|
||||
Combat = attackers;
|
||||
Singletons.getModel().getGameState().setCombat(attackers);
|
||||
}
|
||||
|
||||
//Human_Play, Computer_Play is different because Card.comesIntoPlay() is called when a card is added by PlayerZone.add(Card)
|
||||
/**
|
||||
* <p>getHumanBattlefield.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getHumanBattlefield() {
|
||||
return Human_Battlefield;
|
||||
return Singletons.getModel().getGameState().getHumanBattlefield();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getHumanHand.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getHumanHand() {
|
||||
return Human_Hand;
|
||||
return Singletons.getModel().getGameState().getHumanHand();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getHumanGraveyard.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getHumanGraveyard() {
|
||||
return Human_Graveyard;
|
||||
return Singletons.getModel().getGameState().getHumanGraveyard();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getHumanLibrary.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getHumanLibrary() {
|
||||
return Human_Library;
|
||||
return Singletons.getModel().getGameState().getHumanLibrary();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getHumanExile.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getHumanExile() {
|
||||
return Human_Exile;
|
||||
return Singletons.getModel().getGameState().getHumanExile();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getHumanCommand.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getHumanCommand() {
|
||||
return Human_Command;
|
||||
return Singletons.getModel().getGameState().getHumanCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getComputerBattlefield.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getComputerBattlefield() {
|
||||
return Computer_Battlefield;
|
||||
return Singletons.getModel().getGameState().getComputerBattlefield();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getComputerHand.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getComputerHand() {
|
||||
return Computer_Hand;
|
||||
return Singletons.getModel().getGameState().getComputerHand();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getComputerGraveyard.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getComputerGraveyard() {
|
||||
return Computer_Graveyard;
|
||||
return Singletons.getModel().getGameState().getComputerGraveyard();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getComputerLibrary.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getComputerLibrary() {
|
||||
return Computer_Library;
|
||||
return Singletons.getModel().getGameState().getComputerLibrary();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getComputerExile.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getComputerExile() {
|
||||
return Computer_Exile;
|
||||
return Singletons.getModel().getGameState().getComputerExile();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getComputerCommand.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getComputerCommand() {
|
||||
return Computer_Command;
|
||||
return Singletons.getModel().getGameState().getComputerCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getStackZone.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link forge.PlayerZone} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static PlayerZone getStackZone() {
|
||||
return Stack_Zone;
|
||||
return Singletons.getModel().getGameState().getStackZone();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -546,10 +549,12 @@ public class AllZone implements NewConstants {
|
||||
/**
|
||||
* <p>Getter for the field <code>map</code>.</p>
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return a {@link java.util.Map} object.
|
||||
*/
|
||||
private static Map<String, PlayerZone> getMap() {
|
||||
return map;
|
||||
return Singletons.getModel().getGameState().getZoneNamesToPlayerZones();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -608,10 +613,16 @@ public class AllZone implements NewConstants {
|
||||
public static DeckManager getDeckManager() {
|
||||
return dMgr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and return the next timestamp.
|
||||
*
|
||||
* Will eventually be marked deprecated.
|
||||
*
|
||||
* @return the next timestamp
|
||||
*/
|
||||
public static long getNextTimestamp() {
|
||||
timestamp++;
|
||||
return timestamp;
|
||||
return Singletons.getModel().getGameState().getNextTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1032,9 +1032,14 @@ public class MagicStack extends MyObservable {
|
||||
/**
|
||||
* <p>chooseOrderOfSimultaneousStackEntryAll.</p>
|
||||
*/
|
||||
public void chooseOrderOfSimultaneousStackEntryAll() {
|
||||
chooseOrderOfSimultaneousStackEntry(AllZone.getPhase().getPlayerTurn());
|
||||
chooseOrderOfSimultaneousStackEntry(AllZone.getPhase().getPlayerTurn().getOpponent());
|
||||
public final void chooseOrderOfSimultaneousStackEntryAll() {
|
||||
final Player playerTurn = AllZone.getPhase().getPlayerTurn();
|
||||
|
||||
chooseOrderOfSimultaneousStackEntry(playerTurn);
|
||||
|
||||
if (playerTurn != null) {
|
||||
chooseOrderOfSimultaneousStackEntry(playerTurn.getOpponent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
523
src/main/java/forge/model/FGameState.java
Normal file
523
src/main/java/forge/model/FGameState.java
Normal file
@@ -0,0 +1,523 @@
|
||||
package forge.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import forge.AIPlayer;
|
||||
import forge.Combat;
|
||||
import forge.Constant;
|
||||
import forge.DefaultPlayerZone;
|
||||
import forge.EndOfCombat;
|
||||
import forge.EndOfTurn;
|
||||
import forge.GameAction;
|
||||
import forge.HumanPlayer;
|
||||
import forge.MagicStack;
|
||||
import forge.Phase;
|
||||
import forge.Player;
|
||||
import forge.PlayerZone;
|
||||
import forge.PlayerZone_ComesIntoPlay;
|
||||
import forge.StaticEffects;
|
||||
import forge.Upkeep;
|
||||
import forge.card.trigger.TriggerHandler;
|
||||
|
||||
/**
|
||||
* Represents the Forge Game State.
|
||||
*/
|
||||
public class FGameState {
|
||||
private Player humanPlayer = new HumanPlayer("Human");
|
||||
private Player computerPlayer = new AIPlayer("Computer");
|
||||
private EndOfTurn endOfTurn = new EndOfTurn();
|
||||
private EndOfCombat endOfCombat = new EndOfCombat();
|
||||
private Upkeep upkeep = new Upkeep();
|
||||
private Phase phase = new Phase();
|
||||
private MagicStack stack = new MagicStack();
|
||||
private GameAction gameAction = new GameAction();
|
||||
private StaticEffects staticEffects = new StaticEffects();
|
||||
private TriggerHandler triggerHandler = new TriggerHandler();
|
||||
private Combat combat = new Combat();
|
||||
|
||||
|
||||
// These fields should be moved to the player class(es) and implementation(s), and the getters
|
||||
// should be moved there. PMD complains of too many fields, and it is right.
|
||||
|
||||
// The battlefields are different because Card.comesIntoPlay() is called when a card is added by
|
||||
// PlayerZone.add(Card).
|
||||
private PlayerZone humanBattlefield = new PlayerZone_ComesIntoPlay(Constant.Zone.Battlefield, getHumanPlayer());
|
||||
private PlayerZone humanHand = new DefaultPlayerZone(Constant.Zone.Hand, getHumanPlayer());
|
||||
private PlayerZone humanGraveyard = new DefaultPlayerZone(Constant.Zone.Graveyard, getHumanPlayer());
|
||||
private PlayerZone humanLibrary = new DefaultPlayerZone(Constant.Zone.Library, getHumanPlayer());
|
||||
private PlayerZone humanExile = new DefaultPlayerZone(Constant.Zone.Exile, getHumanPlayer());
|
||||
private PlayerZone humanCommand = new DefaultPlayerZone(Constant.Zone.Command, getHumanPlayer());
|
||||
|
||||
private PlayerZone computerBattlefield = // NOPMD by Braids on 8/27/11 10:50 PM
|
||||
new PlayerZone_ComesIntoPlay(Constant.Zone.Battlefield, getComputerPlayer());
|
||||
|
||||
private PlayerZone computerHand = new DefaultPlayerZone(Constant.Zone.Hand, getComputerPlayer());
|
||||
private PlayerZone computerGraveyard = new DefaultPlayerZone(Constant.Zone.Graveyard, getComputerPlayer());
|
||||
private PlayerZone computerLibrary = new DefaultPlayerZone(Constant.Zone.Library, getComputerPlayer());
|
||||
private PlayerZone computerExile = new DefaultPlayerZone(Constant.Zone.Exile, getComputerPlayer());
|
||||
private PlayerZone computerCommand = new DefaultPlayerZone(Constant.Zone.Command, getComputerPlayer());
|
||||
|
||||
private PlayerZone stackZone = new DefaultPlayerZone(Constant.Zone.Stack, null);
|
||||
|
||||
// Maps zone names to PlayerZone instances.
|
||||
private Map<String, PlayerZone> zoneNamesToPlayerZones = // NOPMD by Braids on 8/27/11 10:50 PM
|
||||
new HashMap<String, PlayerZone>();
|
||||
|
||||
private long timestamp = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public FGameState() {
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Graveyard + getHumanPlayer(), getHumanGraveyard());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Hand + getHumanPlayer(), getHumanHand());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Library + getHumanPlayer(), getHumanLibrary());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Battlefield + getHumanPlayer(), getHumanBattlefield());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Exile + getHumanPlayer(), getHumanExile());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Command + getHumanPlayer(), getHumanCommand());
|
||||
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Graveyard + getComputerPlayer(), getComputerGraveyard());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Hand + getComputerPlayer(), getComputerHand());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Library + getComputerPlayer(), getComputerLibrary());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Battlefield + getComputerPlayer(), getComputerBattlefield());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Exile + getComputerPlayer(), getComputerExile());
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Command + getComputerPlayer(), getComputerCommand());
|
||||
|
||||
getZoneNamesToPlayerZones().put(Constant.Zone.Stack + null, getStackZone());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the humanPlayer
|
||||
*/
|
||||
public final Player getHumanPlayer() {
|
||||
return humanPlayer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param humanPlayer0 the humanPlayer to set
|
||||
*/
|
||||
protected final void setHumanPlayer(final Player humanPlayer0) {
|
||||
this.humanPlayer = humanPlayer0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the computerPlayer
|
||||
*/
|
||||
public final Player getComputerPlayer() {
|
||||
return computerPlayer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param computerPlayer0 the computerPlayer to set
|
||||
*/
|
||||
protected final void setComputerPlayer(final Player computerPlayer0) {
|
||||
this.computerPlayer = computerPlayer0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the endOfTurn
|
||||
*/
|
||||
public final EndOfTurn getEndOfTurn() {
|
||||
return endOfTurn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param endOfTurn0 the endOfTurn to set
|
||||
*/
|
||||
protected final void setEndOfTurn(final EndOfTurn endOfTurn0) {
|
||||
this.endOfTurn = endOfTurn0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the endOfCombat
|
||||
*/
|
||||
public final EndOfCombat getEndOfCombat() {
|
||||
return endOfCombat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param endOfCombat0 the endOfCombat to set
|
||||
*/
|
||||
protected final void setEndOfCombat(final EndOfCombat endOfCombat0) {
|
||||
this.endOfCombat = endOfCombat0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the upkeep
|
||||
*/
|
||||
public final Upkeep getUpkeep() {
|
||||
return upkeep;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param upkeep0 the upkeep to set
|
||||
*/
|
||||
protected final void setUpkeep(final Upkeep upkeep0) {
|
||||
this.upkeep = upkeep0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the phase
|
||||
*/
|
||||
public final Phase getPhase() {
|
||||
return phase;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param phase0 the phase to set
|
||||
*/
|
||||
protected final void setPhase(final Phase phase0) {
|
||||
this.phase = phase0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the stack
|
||||
*/
|
||||
public final MagicStack getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param stack0 the stack to set
|
||||
*/
|
||||
protected final void setStack(final MagicStack stack0) {
|
||||
this.stack = stack0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the gameAction
|
||||
*/
|
||||
public final GameAction getGameAction() {
|
||||
return gameAction;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param gameAction0 the gameAction to set
|
||||
*/
|
||||
protected final void setGameAction(final GameAction gameAction0) {
|
||||
this.gameAction = gameAction0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the staticEffects
|
||||
*/
|
||||
public final StaticEffects getStaticEffects() {
|
||||
return staticEffects;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param staticEffects0 the staticEffects to set
|
||||
*/
|
||||
protected final void setStaticEffects(final StaticEffects staticEffects0) {
|
||||
this.staticEffects = staticEffects0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the triggerHandler
|
||||
*/
|
||||
public final TriggerHandler getTriggerHandler() {
|
||||
return triggerHandler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param triggerHandler0 the triggerHandler to set
|
||||
*/
|
||||
protected final void setTriggerHandler(final TriggerHandler triggerHandler0) {
|
||||
this.triggerHandler = triggerHandler0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the combat
|
||||
*/
|
||||
public final Combat getCombat() {
|
||||
return combat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param combat0 the combat to set
|
||||
*/
|
||||
public final void setCombat(final Combat combat0) {
|
||||
this.combat = combat0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the humanBattlefield
|
||||
*/
|
||||
public final PlayerZone getHumanBattlefield() {
|
||||
return humanBattlefield;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param humanBattlefield0 the humanBattlefield to set
|
||||
*/
|
||||
protected final void setHumanBattlefield(final PlayerZone humanBattlefield0) {
|
||||
this.humanBattlefield = humanBattlefield0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the humanHand
|
||||
*/
|
||||
public final PlayerZone getHumanHand() {
|
||||
return humanHand;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param humanHand0 the humanHand to set
|
||||
*/
|
||||
protected final void setHumanHand(final PlayerZone humanHand0) {
|
||||
this.humanHand = humanHand0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the humanGraveyard
|
||||
*/
|
||||
public final PlayerZone getHumanGraveyard() {
|
||||
return humanGraveyard;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param humanGraveyard0 the humanGraveyard to set
|
||||
*/
|
||||
protected final void setHumanGraveyard(final PlayerZone humanGraveyard0) {
|
||||
this.humanGraveyard = humanGraveyard0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the humanLibrary
|
||||
*/
|
||||
public final PlayerZone getHumanLibrary() {
|
||||
return humanLibrary;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param humanLibrary0 the humanLibrary to set
|
||||
*/
|
||||
protected final void setHumanLibrary(final PlayerZone humanLibrary0) {
|
||||
this.humanLibrary = humanLibrary0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the humanExile
|
||||
*/
|
||||
public final PlayerZone getHumanExile() {
|
||||
return humanExile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param humanExile0 the humanExile to set
|
||||
*/
|
||||
protected final void setHumanExile(final PlayerZone humanExile0) {
|
||||
this.humanExile = humanExile0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the humanCommand
|
||||
*/
|
||||
public final PlayerZone getHumanCommand() {
|
||||
return humanCommand;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param humanCommand0 the humanCommand to set
|
||||
*/
|
||||
protected final void setHumanCommand(final PlayerZone humanCommand0) {
|
||||
this.humanCommand = humanCommand0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the computerBattlefield
|
||||
*/
|
||||
public final PlayerZone getComputerBattlefield() {
|
||||
return computerBattlefield;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param computerBattlefield0 the computerBattlefield to set
|
||||
*/
|
||||
protected final void setComputerBattlefield(
|
||||
final PlayerZone computerBattlefield0) // NOPMD by Braids on 8/27/11 10:53 PM
|
||||
{
|
||||
this.computerBattlefield = computerBattlefield0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the computerHand
|
||||
*/
|
||||
public final PlayerZone getComputerHand() {
|
||||
return computerHand;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param computerHand0 the computerHand to set
|
||||
*/
|
||||
protected final void setComputerHand(final PlayerZone computerHand0) {
|
||||
this.computerHand = computerHand0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the computerGraveyard
|
||||
*/
|
||||
public final PlayerZone getComputerGraveyard() {
|
||||
return computerGraveyard;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param computerGraveyard0 the computerGraveyard to set
|
||||
*/
|
||||
protected final void setComputerGraveyard(
|
||||
final PlayerZone computerGraveyard0) // NOPMD by Braids on 8/27/11 10:53 PM
|
||||
{
|
||||
this.computerGraveyard = computerGraveyard0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the computerLibrary
|
||||
*/
|
||||
public final PlayerZone getComputerLibrary() {
|
||||
return computerLibrary;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param computerLibrary0 the computerLibrary to set
|
||||
*/
|
||||
protected final void setComputerLibrary(final PlayerZone computerLibrary0) {
|
||||
this.computerLibrary = computerLibrary0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the computerExile
|
||||
*/
|
||||
public final PlayerZone getComputerExile() {
|
||||
return computerExile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param computerExile0 the computerExile to set
|
||||
*/
|
||||
protected final void setComputerExile(final PlayerZone computerExile0) {
|
||||
this.computerExile = computerExile0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the computerCommand
|
||||
*/
|
||||
public final PlayerZone getComputerCommand() {
|
||||
return computerCommand;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param computerCommand0 the computerCommand to set
|
||||
*/
|
||||
protected final void setComputerCommand(final PlayerZone computerCommand0) {
|
||||
this.computerCommand = computerCommand0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the stackZone
|
||||
*/
|
||||
public final PlayerZone getStackZone() {
|
||||
return stackZone;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param stackZone0 the stackZone to set
|
||||
*/
|
||||
protected final void setStackZone(final PlayerZone stackZone0) {
|
||||
this.stackZone = stackZone0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the zoneNamesToPlayerZones
|
||||
*/
|
||||
public final Map<String, PlayerZone> getZoneNamesToPlayerZones() {
|
||||
return zoneNamesToPlayerZones;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param zoneNamesToPlayerZones0 the zoneNamesToPlayerZones to set
|
||||
*/
|
||||
protected final void setZoneNamesToPlayerZones(
|
||||
final Map<String, PlayerZone> zoneNamesToPlayerZones0) // NOPMD by Braids on 8/27/11 10:53 PM
|
||||
{
|
||||
this.zoneNamesToPlayerZones = zoneNamesToPlayerZones0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and return the next timestamp.
|
||||
*
|
||||
* @return the next timestamp
|
||||
*/
|
||||
public final long getNextTimestamp() {
|
||||
setTimestamp(getTimestamp() + 1);
|
||||
return getTimestamp();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the timestamp
|
||||
*/
|
||||
public final long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param timestamp0 the timestamp to set
|
||||
*/
|
||||
protected final void setTimestamp(final long timestamp0) {
|
||||
this.timestamp = timestamp0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,7 @@ public class FModel {
|
||||
private final transient PrintStream oldSystemErr;
|
||||
private BuildInfo buildInfo;
|
||||
private ForgePreferences preferences;
|
||||
private FGameState gameState;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -143,5 +144,23 @@ public class FModel {
|
||||
this.preferences = neoPreferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for gameState.
|
||||
* @return the game state
|
||||
*/
|
||||
public final FGameState getGameState() {
|
||||
return gameState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new game state.
|
||||
* @return a fresh game state
|
||||
*/
|
||||
public final FGameState resetGameState() {
|
||||
gameState = new FGameState();
|
||||
return gameState;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ public final class Main {
|
||||
final FModel model = new FModel(null);
|
||||
Singletons.setModel(model);
|
||||
|
||||
// TODO: this code should go elsewhere, like wherever we start a new game.
|
||||
// It is only here to maintain semantic equality with the current code base.
|
||||
model.resetGameState();
|
||||
|
||||
view.setModel(model);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package forge.model;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import forge.Singletons;
|
||||
import forge.properties.ForgePreferences;
|
||||
|
||||
/**
|
||||
@@ -15,20 +17,49 @@ import forge.properties.ForgePreferences;
|
||||
public class FModelTest {
|
||||
|
||||
|
||||
private FModel model;
|
||||
|
||||
/**
|
||||
* Test constructor, close, and construct again.
|
||||
* Set up before each test, creating a default model.
|
||||
*
|
||||
* @throws FileNotFoundException indirectly
|
||||
*/
|
||||
@BeforeTest
|
||||
public final void setUp() throws FileNotFoundException {
|
||||
model = new FModel(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the model after each test if it isn't null.
|
||||
*/
|
||||
@AfterTest
|
||||
public final void tearDown() {
|
||||
if (model != null) {
|
||||
try {
|
||||
model.close();
|
||||
}
|
||||
catch (Throwable ignored) {
|
||||
// ignore exceptions during close.
|
||||
}
|
||||
}
|
||||
|
||||
model = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test constructor (via setUp), close, and construct again.
|
||||
* @throws FileNotFoundException if something is really wrong
|
||||
*/
|
||||
@Test
|
||||
public final void test_ctor_close_ctor() throws FileNotFoundException { // NOPMD by Braids on 8/12/11 10:36 AM
|
||||
final FModel modelA = new FModel(null);
|
||||
assertNotNull(modelA, "modelA is not null");
|
||||
modelA.close();
|
||||
assertNotNull(model, "model is not null");
|
||||
model.close();
|
||||
|
||||
System.err.println("log test"); // NOPMD by Braids on 8/12/11 10:36 AM
|
||||
|
||||
final FModel modelB = new FModel(null);
|
||||
assertNotNull(modelB, "modelB is not null");
|
||||
model = new FModel(null);
|
||||
assertNotNull(model, "model is not null");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,10 +67,8 @@ public class FModelTest {
|
||||
* @throws FileNotFoundException if something is really wrong
|
||||
*/
|
||||
@Test
|
||||
public final void test_getVersion() throws FileNotFoundException { // NOPMD by Braids on 8/12/11 10:36 AM
|
||||
final FModel model = new FModel(null);
|
||||
public final void test_getVersion() throws FileNotFoundException {
|
||||
final String version = model.getBuildInfo().getVersion();
|
||||
model.close();
|
||||
|
||||
assertEquals(version, "SVN", "version is default");
|
||||
}
|
||||
@@ -50,12 +79,8 @@ public class FModelTest {
|
||||
*/
|
||||
@Test
|
||||
public final void test_getBuildID() throws FileNotFoundException { // NOPMD by Braids on 8/12/11 10:36 AM
|
||||
final FModel model = new FModel(null);
|
||||
|
||||
// Just test for an unexpected exception.
|
||||
model.getBuildInfo().getBuildID();
|
||||
|
||||
model.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,12 +89,26 @@ public class FModelTest {
|
||||
*/
|
||||
@Test
|
||||
public final void test_getPreferences() throws FileNotFoundException {
|
||||
final FModel model = new FModel(null);
|
||||
try {
|
||||
ForgePreferences prefs = model.getPreferences();
|
||||
assertNotNull(prefs, "prefs instance is not null");
|
||||
} finally {
|
||||
model.close();
|
||||
}
|
||||
ForgePreferences prefs = model.getPreferences();
|
||||
assertNotNull(prefs, "prefs instance is not null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test resetGameState and getGameState.
|
||||
*/
|
||||
@Test
|
||||
public final void test_resetGameState_getGameState() {
|
||||
Singletons.setModel(model);
|
||||
assertNull(model.getGameState(), "game state has not yet been initialized");
|
||||
|
||||
FGameState state1 = model.resetGameState();
|
||||
assertNotNull(state1, "first state is OK");
|
||||
|
||||
FGameState state2 = model.resetGameState();
|
||||
assertNotNull(state1, "first state is OK");
|
||||
assertNotEquals(state1, state2, "first and second states are different");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user