Coverage Summary for Class: IslandFieldPanel (it.polimi.ingsw.Client.GUI.Panels)
Class |
Method, %
|
Branch, %
|
Line, %
|
IslandFieldPanel |
0%
(0/8)
|
0%
(0/45)
|
0%
(0/151)
|
IslandFieldPanel$1 |
0%
(0/1)
|
0%
(0/1)
|
Total |
0%
(0/9)
|
0%
(0/45)
|
0%
(0/152)
|
1 package it.polimi.ingsw.Client.GUI.Panels;
2
3 import it.polimi.ingsw.Client.GUI.ActionType;
4 import it.polimi.ingsw.Client.GUI.CircleLayout;
5 import it.polimi.ingsw.Client.GUI.Components.NoEntryTileComponent;
6 import it.polimi.ingsw.Client.GUI.Components.StudentButton;
7 import it.polimi.ingsw.Client.GUI.Components.TowerComponent;
8 import it.polimi.ingsw.Client.GUI.Listeners.GUISocketListener;
9 import it.polimi.ingsw.Controller.Actions.MoveMotherNature;
10 import it.polimi.ingsw.Controller.Actions.MoveStudent;
11 import it.polimi.ingsw.Controller.Actions.PlayCharacterCard;
12 import it.polimi.ingsw.Controller.MoveDestination;
13 import it.polimi.ingsw.Misc.OptionalValue;
14 import it.polimi.ingsw.Model.Enums.PawnColour;
15 import it.polimi.ingsw.Model.IslandGroup;
16 import it.polimi.ingsw.Model.Model;
17 import it.polimi.ingsw.Network.SocketWrapper;
18 import it.polimi.ingsw.Server.Messages.Events.Requests.PlayerActionRequest;
19
20 import javax.swing.*;
21 import java.awt.*;
22 import java.awt.image.BufferedImage;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Map;
27
28 import static it.polimi.ingsw.Client.GUI.IconLoader.*;
29
30 /**
31 * Class necessary to print all the islands on GUI and perform all player's action that involve an island or islandGroup
32 */
33 public class IslandFieldPanel extends JPanel {
34 /**
35 * Contains game's information
36 */
37 private final Model model;
38 /**
39 * Contains GuiReader's information necessary to record user's requests during his turn
40 */
41 private final GUISocketListener guiSocketListener;
42 /**
43 * Optional Integer containing student's index inside player's PlayerBoard's entrance (necessary when sending MoveStudentAction to Server)
44 */
45 private OptionalValue<Integer> entrancePositionToMove = OptionalValue.empty();
46 /**
47 * Optional Integer containing card's index inside game (0 to 2), it can be empty if no characterCard has been played
48 */
49 private OptionalValue<Integer> selectedCharacterCard = OptionalValue.empty();
50 /**
51 * Pawn from character card that player wants to move inside an island
52 */
53 private OptionalValue<PawnColour> pawnFromCharacterCard = OptionalValue.empty();
54 /**
55 * Status of islandField
56 */
57 private ActionType actionType;
58
59 public IslandFieldPanel(Model model, SocketWrapper sw, GUISocketListener guiSocketListener) {
60 //set IslandFieldPanel's actionType basing on previous actions performed by current Player
61 this.setActionType(ActionType.MOVEMOTHERNATURE, OptionalValue.empty());
62 this.setOpaque(true);
63 this.setBackground(new Color(105, 186, 233));
64 this.setLayout(new CircleLayout());
65 this.model = model;
66 this.guiSocketListener = guiSocketListener;
67 ArrayList<IslandGroup> islandGroups = new ArrayList<>(this.model.getMutableIslandField().getMutableGroups());
68 //list containing islands images
69 ArrayList<ImageIcon> islandIcons = new ArrayList<>(Arrays.asList(Island1, Island2, Island3));
70 ArrayList<JButton> islandButtons = new ArrayList<>(this.model.getMutableIslandField().getMutableGroups().size());
71 IslandGroup motherNaturePosition = this.model.getMutableIslandField().getMutableMotherNaturePosition();
72 //---DYNAMIC SIZING ISLANDS' IMAGES----
73 int widthIsland = 160 + getDimBoost(islandGroups.size());
74 int heightIsland = 130 + getDimBoost(islandGroups.size());
75 int widthStudent = 35 + (getDimBoost(islandGroups.size()) / 5);
76 int heightStudent = 30 + (getDimBoost(islandGroups.size()) / 5);
77 int widthMotherNature = 35 + (getDimBoost(islandGroups.size()) / 5);
78 int heightMotherNature = 45 + (getDimBoost(islandGroups.size()) / 5);
79 int widthTower = 17 + (getDimBoost(islandGroups.size()) / 5);
80 int heightTower = 35 + (getDimBoost(islandGroups.size()) / 5);
81 Map<PawnColour, Integer> pawnCountMap;
82 for (int i = 0; i < islandGroups.size(); i++) {
83 //Map containing students and their count on the islandGroup
84 pawnCountMap = islandGroups.get(i).getStudentCount();
85 //get and scale an island's image
86 Image img = islandIcons.get(i % 3).getImage();
87 Image newImg = img.getScaledInstance(widthIsland, heightIsland, java.awt.Image.SCALE_SMOOTH);
88 ImageIcon icon = new ImageIcon(newImg);
89 //create a new button with the scaled images
90 JButton islandButton = new JButton(icon);
91 islandButtons.add(islandButton);
92 int finalI = i;
93 //add on-click action listener to islandGroup
94 islandButton.addActionListener(e -> {
95 // skip execution of the action if a previous action still hasn't been processed by the server
96 if (guiSocketListener.awaitingPlayerActionFeedback()) {
97 JOptionPane.showMessageDialog(null, "Please wait for the server to process your previous" +
98 "request before making a new one");
99 return;
100 }
101 switch (this.actionType) {
102 case CHARACTERCARD -> {
103 PlayCharacterCard playCharacterCard;
104 //create playCharacterCard action
105 if (pawnFromCharacterCard.isPresent()) {
106 playCharacterCard = new PlayCharacterCard(model.getMutableTurnOrder().getMutableCurrentPlayer().getId(),
107 selectedCharacterCard.get(), OptionalValue.of(islandGroups.get(finalI).getMutableIslands().get(0).getId())
108 , pawnFromCharacterCard, OptionalValue.empty());
109 } else {
110 playCharacterCard = new PlayCharacterCard(model.getMutableTurnOrder().getMutableCurrentPlayer().getId(),
111 selectedCharacterCard.get(), OptionalValue.of(islandGroups.get(finalI).getMutableIslands().get(0).getId())
112 , OptionalValue.empty(), OptionalValue.empty());
113 }
114 PlayerActionRequest playerActionRequest = new PlayerActionRequest(playCharacterCard);
115 this.guiSocketListener.savePlayerActionRequest(playCharacterCard);
116 try {
117 //send playCharacterCard request to Server
118 sw.sendMessage(playerActionRequest);
119 } catch (IOException ex) {
120 throw new RuntimeException(ex);
121 }
122 }
123 case MOVESTUDENT -> {
124 //create moveStudent action and its playerActionRequest
125 MoveStudent moveStudent = new MoveStudent(this.model.getMutableTurnOrder().getMutableCurrentPlayer().getId(), entrancePositionToMove.get(), MoveDestination.toIsland(islandGroups.get(finalI).getId()));
126 PlayerActionRequest playerAction = new PlayerActionRequest(moveStudent);
127 //save moveStudentAction request inside guiReader
128 this.guiSocketListener.savePlayerActionRequest(moveStudent);
129 try {
130 sw.sendMessage(playerAction);
131 } catch (IOException ex) {
132 throw new RuntimeException(ex);
133 }
134 }
135 case MOVEMOTHERNATURE -> {
136 //create moveMotherNature action and its playerActionRequest
137 MoveMotherNature moveMotherNature = new MoveMotherNature(this.model.getMutableTurnOrder().getMutableCurrentPlayer().getId(), getMotherNatureSteps(islandGroups, islandGroups.get(finalI)));
138 PlayerActionRequest playerAction = new PlayerActionRequest(moveMotherNature);
139 //save moveStudentAction request inside guiReader
140 this.guiSocketListener.savePlayerActionRequest(moveMotherNature);
141 try {
142 sw.sendMessage(playerAction);
143 } catch (IOException ex) {
144 throw new RuntimeException(ex);
145 }
146 }
147 }
148 // reset the action listener to the base action
149 this.setActionType(ActionType.MOVEMOTHERNATURE, OptionalValue.empty());
150 });
151 //remove border and filled background from islandGroups' button
152 islandButton.setPreferredSize(new Dimension(widthIsland, heightIsland));
153 islandButton.setBorderPainted(false);
154 islandButton.setContentAreaFilled(false);
155 islandButton.setFocusPainted(false);
156 islandButton.setOpaque(false);
157 islandButton.setLayout(new GridLayout(3, 1, -45, 0));
158 for (PawnColour p : pawnCountMap.keySet()) {
159 if (pawnCountMap.get(p) > 0) {
160 //create new StudentButton
161 StudentButton studentButton = new StudentButton(p, pawnCountMap.get(p), true);
162 //scale StudentButton's image
163 newImg = iconToImage(studentButton.getIcon()).getScaledInstance((int) (widthStudent / 1.5), (int) (heightStudent / 1.5), java.awt.Image.SCALE_SMOOTH);
164 icon = new ImageIcon(newImg);
165 studentButton.setIcon(icon);
166 studentButton.setPreferredSize(new Dimension(widthStudent, heightStudent));
167 islandButton.add(studentButton);
168 //add same IslandGroups' actionListeners to studentButtons
169 studentButton.addActionListener(e -> islandButton.doClick());
170 }
171 }
172 //Draw motherNature only if it's present in IslandGroup
173 if (islandGroups.get(i).getMutableIslands().stream().anyMatch(island -> island.getId() == motherNaturePosition.getId())) {
174 //load and scale MotherNature's image
175 img = motherNature != null ? motherNature.getImage() : null;
176 assert img != null;
177 newImg = img.getScaledInstance(widthMotherNature, heightMotherNature, java.awt.Image.SCALE_SMOOTH);
178 icon = new ImageIcon(newImg);
179 //create motherNature's label
180 JLabel motherNatureLabel = new JLabel(icon);
181 motherNatureLabel.setPreferredSize(new Dimension(widthMotherNature, heightMotherNature));
182 //add motherNature to islandGroup's button
183 islandButton.add(motherNatureLabel);
184 }
185 //Drawing eventual tower
186 if (islandGroups.get(i).getTowerColour().isPresent()) {
187 //scale and set tower's image
188 TowerComponent tower = new TowerComponent(islandGroups.get(i).getTowerColour().get(), islandGroups.get(i).getTowerCount());
189 newImg = iconToImage(tower.getIcon()).getScaledInstance(widthTower, heightTower, java.awt.Image.SCALE_SMOOTH);
190 icon = new ImageIcon(newImg);
191 tower.setIcon(icon);
192 //remove borders and filled background from tower's image
193 tower.setBorderPainted(false);
194 tower.setContentAreaFilled(false);
195 tower.setFocusPainted(false);
196 tower.setPreferredSize(new Dimension(widthTower, heightTower));
197 tower.addActionListener(e -> islandButton.doClick());
198 //add tower's image to IslandGroup's button
199 islandButton.add(tower);
200 }
201 //Drawing eventual NoEntryTile
202 if (islandGroups.get(i).getMutableNoEntryTiles().size() > 0) {
203 //scale and set NoEntryTile's image
204 NoEntryTileComponent noEntryTileComponent = new NoEntryTileComponent(islandGroups.get(i).getMutableNoEntryTiles().size());
205 newImg = iconToImage(noEntryTileComponent.getIcon()).getScaledInstance(40, 35, java.awt.Image.SCALE_SMOOTH);
206 icon = new ImageIcon(newImg);
207 noEntryTileComponent.setIcon(icon);
208 noEntryTileComponent.setPreferredSize(new Dimension(40, 35));
209 //add NoEntryTile component to island's button
210 islandButton.add(noEntryTileComponent);
211 //add same IslandGroups' actionListeners to noEntryTileComponent
212 noEntryTileComponent.addActionListener(e -> islandButton.doClick());
213
214 }
215 islandButton.setToolTipText("<html><p width = 100px>ISLAND GROUP #" + islandGroups.get(i).getId() + "<br>" +
216 "STUDENTS:<br>" +
217 "RED:" + pawnCountMap.get(PawnColour.RED) + "<br>" +
218 "BLUE:" + pawnCountMap.get(PawnColour.BLUE) + "<br>" +
219 "YELLOW:" + pawnCountMap.get(PawnColour.YELLOW) + "<br>" +
220 "GREEN:" + pawnCountMap.get(PawnColour.GREEN) + "<br>" +
221 "PINK:" + pawnCountMap.get(PawnColour.PINK) + "</p></html>");
222 ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE);
223 this.add(islandButton);
224 }
225 }
226
227 /**
228 * Method used for setting IslandFieldPanel's actionType from external panels
229 *
230 * @param actionType actionType that IslandFieldPanel will assume
231 * @param toRemove PlayerBoard's entrance's index containing the student to move (Optional.empty if action type is not MOVESTUDENT)
232 */
233 public void setActionType(ActionType actionType, OptionalValue<Integer> toRemove) {
234 if (actionType == ActionType.MOVESTUDENT) {
235 this.actionType = actionType;
236 this.entrancePositionToMove = toRemove;
237 return;
238 }
239 this.actionType = actionType;
240 }
241
242 /**
243 * Support method used to increase islands' dimensions when the amount of IslandGroups decreases
244 *
245 * @param IslandsNumbers number of IslandGroups to show
246 * @return boost to add to original icons' dimensions
247 */
248 private int getDimBoost(int IslandsNumbers) {
249 return switch (IslandsNumbers) {
250 case 12 -> 0;
251 case 11 -> 10;
252 case 10 -> 20;
253 case 9 -> 30;
254 case 8 -> 40;
255 case 7 -> 50;
256 case 6 -> 60;
257 case 5, default -> 70;
258 };
259 }
260
261 /**
262 * Support method used to calculate difference between clicked islandGroup by user and actual motherNature's islandGroup
263 *
264 * @param islandGroups list of islandGroups present in game
265 * @param destinationIsland IslandGroup that has been clicked by player
266 * @return number of steps that motherNature should perform to reach wished IslandGroup
267 */
268 private int getMotherNatureSteps(ArrayList<IslandGroup> islandGroups, IslandGroup destinationIsland) {
269 //get motherNature's islandGroup's index
270 int motherNatureIndex = islandGroups.indexOf(model.getMutableIslandField().getMutableMotherNaturePosition());
271 int steps = 1;
272 //repeat until found islandGroup with same id as the one clicked by user
273 while (!islandGroups.get((motherNatureIndex + steps) % islandGroups.size()).equals(destinationIsland)) {
274 steps = steps + 1;
275 }
276 return steps;
277 }
278
279 /**
280 * Support method to extract Image from icon
281 *
282 * @param icon icon to convert
283 * @return image represented by icon
284 */
285 private Image iconToImage(Icon icon) {
286 if (icon instanceof ImageIcon) {
287 return ((ImageIcon) icon).getImage();
288 } else {
289 int w = icon.getIconWidth();
290 int h = icon.getIconHeight();
291 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
292 GraphicsDevice gd = ge.getDefaultScreenDevice();
293 GraphicsConfiguration gc = gd.getDefaultConfiguration();
294 BufferedImage image = gc.createCompatibleImage(w, h);
295 Graphics2D g = image.createGraphics();
296 icon.paintIcon(null, g, 0, 0);
297 g.dispose();
298 return image;
299 }
300 }
301
302 /**
303 * Basing on CharacterCard that has been activated, this method setup IslandFieldPanel for send the right PlayerActionRequest to Server
304 *
305 * @param actionType ActionType that IslandFieldPanel is going to switch to
306 * @param card card's index inside game
307 * @param toMove possible pawn to move
308 */
309 public void setCharacterCardAction(ActionType actionType, OptionalValue<Integer> card, OptionalValue<PawnColour> toMove) {
310 this.actionType = actionType;
311 if (card.isEmpty()) return;
312 this.selectedCharacterCard = card;
313 if (toMove.isEmpty()) return;
314 this.pawnFromCharacterCard = toMove;
315 }
316 }