Coverage Summary for Class: PlayCharacterCard (it.polimi.ingsw.Controller.Actions)
| Class | Class, % | Method, % | Branch, % | Line, % |
|---|---|---|---|---|
| PlayCharacterCard | 100% (1/1) | 100% (4/4) | 85,7% (12/14) | 91,2% (31/34) |
1 package it.polimi.ingsw.Controller.Actions; 2 3 import it.polimi.ingsw.Exceptions.Container.InvalidContainerIndexException; 4 import it.polimi.ingsw.Exceptions.Input.GenericInputValidationException; 5 import it.polimi.ingsw.Exceptions.Input.InputValidationException; 6 import it.polimi.ingsw.Exceptions.Input.InvalidElementException; 7 import it.polimi.ingsw.Misc.OptionalValue; 8 import it.polimi.ingsw.Misc.Pair; 9 import it.polimi.ingsw.Model.CharacterCard; 10 import it.polimi.ingsw.Model.CharacterCardInput; 11 import it.polimi.ingsw.Model.Enums.GameMode; 12 import it.polimi.ingsw.Model.Enums.GamePhase; 13 import it.polimi.ingsw.Model.Enums.PawnColour; 14 import it.polimi.ingsw.Model.Model; 15 import it.polimi.ingsw.Model.PlayerBoard; 16 17 import java.io.Serial; 18 import java.util.List; 19 20 21 public class PlayCharacterCard extends PlayerAction { 22 @Serial 23 private static final long serialVersionUID = 207L; // convention: 2 for controller, (01 -> 99) for objects 24 25 private final int selectedCard; // mandatory 26 private final OptionalValue<Integer> optTargetIsland; 27 private final OptionalValue<PawnColour> optTargetPawn; 28 private final OptionalValue<List<Pair<PawnColour, PawnColour>>> optTargetPawnPairs; 29 30 /** 31 * Create a new instance of this class with the following inputs: 32 * 33 * @param playerBoardId the ID of the current {@link PlayerBoard} 34 * @param selectedCard the ID of the {@link CharacterCard} to be played 35 * @param optTargetIsland if a target island is required as an input to the card, provide it here 36 * @param optTargetPawn if a target pawn is required as an input to the card, provide it here 37 * @param optTargetPawnPairs if a list of pawn pairs is required as an input to the card, provide it here 38 */ 39 public PlayCharacterCard( 40 int playerBoardId, 41 int selectedCard, 42 OptionalValue<Integer> optTargetIsland, 43 OptionalValue<PawnColour> optTargetPawn, 44 OptionalValue<List<Pair<PawnColour, PawnColour>>> optTargetPawnPairs) { 45 super(playerBoardId, true); 46 this.selectedCard = selectedCard; 47 this.optTargetIsland = optTargetIsland; 48 this.optTargetPawn = optTargetPawn; 49 this.optTargetPawnPairs = optTargetPawnPairs; 50 } 51 52 /** 53 * {@inheritDoc} 54 * <ul> 55 * <li>The {@link GameMode} must be {@link GameMode#ADVANCED}</li> 56 * <li>The {@link GamePhase} must be {@link GamePhase#ACTION}</li> 57 * <li>The selected character card must be within bounds (index 0 to 2 included)</li> 58 * <li>The player needs to have enough coins to by the card</li> 59 * <li>The {@link CharacterCardInput} generated from the attributes must be correct</li> 60 * </ul> 61 * 62 * @param history the controller stores a {@link List} of previous {@link PlayerAction}s related to the player taking 63 * the current turn (at every new turn, the history is cleared). 64 * Some actions may use this {@link List} to check for duplicates. 65 * @param ctx a reference to {@link Model}. Some actions may use this reference to check for consistency between what 66 * the actions declares and what the Model offers. 67 * @return An empty {@link OptionalValue} in case of a successful validation. Otherwise the returned {@link OptionalValue} 68 * contains the related {@link InputValidationException} 69 */ 70 @Override 71 protected OptionalValue<InputValidationException> customValidation(List<PlayerAction> history, Model ctx) { 72 if (ctx.getGameMode() != GameMode.ADVANCED) { 73 return OptionalValue.of(new GenericInputValidationException("Character Card", "can't be played in simple mode")); 74 } 75 PlayerBoard caller = ctx.getMutableTurnOrder().getMutableCurrentPlayer(); 76 if (ctx.getMutableTurnOrder().getGamePhase() != GamePhase.ACTION) { 77 return OptionalValue.of(new GenericInputValidationException("History", "the game is not in the correct phase")); 78 } 79 80 // generate the input object before validation 81 CharacterCardInput cardInput; 82 try { 83 cardInput = generateCharacterCardInput(caller, ctx); 84 } catch (InvalidContainerIndexException e) { 85 return OptionalValue.of(new InvalidElementException("Target Island")); 86 } 87 88 if (!(this.selectedCard >= 0 && this.selectedCard < 3)) { //selectedCard out of bounds 89 return OptionalValue.of(new InvalidElementException("Character Card")); 90 } 91 CharacterCard selectedCard = ctx.getCharacterCards().get(this.selectedCard); 92 if (caller.getCoinBalance() < selectedCard.getCost()) { 93 return OptionalValue.of(new GenericInputValidationException("Character Card", 94 "can't be played due to insufficient coin balance")); 95 } 96 97 return selectedCard.checkInput(cardInput); 98 } 99 100 @Override 101 public void unsafeExecute(Model ctx) throws Exception { 102 PlayerBoard caller = ctx.getMutableTurnOrder().getMutableCurrentPlayer(); 103 CharacterCard characterCard = ctx.getCharacterCards().get(this.selectedCard); 104 caller.payCharacterEffect(characterCard); 105 if (characterCard.getTimeUsed() > 0) { 106 ctx.addCoinToReserve(characterCard.getCost()); 107 } else { 108 ctx.addCoinToReserve(characterCard.getCost() - 1); //the first time, one coin has to be placed on the card and not in the coin reserve 109 } 110 characterCard.unsafeUseCard(generateCharacterCardInput(caller, ctx)); 111 } 112 113 /** 114 * a {@link CharacterCard} requires more information than the one contained in the constructor of this {@link PlayerAction} 115 * to be able to function. During the calls to verify the action, a {@link CharacterCardInput} object needs to be created so 116 * the internal validation mechanism of the {@link CharacterCard} can work. 117 * 118 * @param caller instead of the id of the current player, a reference to the current {@link PlayerBoard} is needed 119 * @param ctx the {@link Model} object is required to allow translation of the attributes of this object into a {@link CharacterCardInput} 120 * @return the {@link CharacterCardInput} associated with this object's attributes 121 * @throws InvalidContainerIndexException if the attribute of target island is pointing to an unidentified island-ID in the model, this exception is thrown 122 */ 123 private CharacterCardInput generateCharacterCardInput(PlayerBoard caller, Model ctx) throws InvalidContainerIndexException { 124 CharacterCardInput out = new CharacterCardInput(caller); 125 if (this.optTargetIsland.isPresent()) { 126 int id = this.optTargetIsland.get(); 127 out.setTargetIsland(ctx.getMutableIslandField().getMutableIslandById(id)); 128 } 129 this.optTargetPawn.ifPresent(out::setTargetPawn); 130 this.optTargetPawnPairs.ifPresent(out::setTargetPawnPairs); 131 return out; 132 } 133 }