|
|
@@ -2,23 +2,33 @@ package controller;
|
|
|
|
|
|
import controller.entity.EntityController;
|
|
|
import controller.entity.VillagerController;
|
|
|
+import controller.factories.EntityFactory;
|
|
|
+import controller.factories.InteractiveTileFactory;
|
|
|
+import controller.input.KeyHandler;
|
|
|
import controller.tiles.interactive.*;
|
|
|
import controller.tiles.interactive.upgradeable.*;
|
|
|
+import controller.ui.ShopController;
|
|
|
import model.GameModel;
|
|
|
import model.GameSaver;
|
|
|
+import model.Inventory;
|
|
|
import model.entity.EntityModel;
|
|
|
+import model.entity.EntityType;
|
|
|
import model.items.Item;
|
|
|
import model.items.ITEM_NAME;
|
|
|
import model.tiles.InteractiveTileModel;
|
|
|
+import model.tiles.InteractiveTileType;
|
|
|
import util.GAMESTATE;
|
|
|
import view.GamePanel;
|
|
|
-import view.tile.interactive.*;
|
|
|
+import view.sound.SoundManager;
|
|
|
|
|
|
-import java.awt.*;
|
|
|
import java.io.Serializable;
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
+/**
|
|
|
+ * Controls the main game loop, input handling, entities, and interactive tiles.
|
|
|
+ */
|
|
|
public class GameController implements Runnable, Serializable {
|
|
|
+
|
|
|
public final String worldPath = "gamefiles/worlds/world_0.txt";
|
|
|
private GameModel gameModel;
|
|
|
private boolean running = true;
|
|
|
@@ -27,188 +37,444 @@ public class GameController implements Runnable, Serializable {
|
|
|
|
|
|
private transient KeyHandler keyHandler;
|
|
|
private transient Thread gameThread;
|
|
|
+ private transient RessourceManager ressourceManager;
|
|
|
private transient GamePanel view;
|
|
|
+ private transient ShopController shopController;
|
|
|
public transient ArrayList<EntityController> entityControllers;
|
|
|
public transient ArrayList<InteractiveTileController> interactiveTileControllers;
|
|
|
+ private transient boolean gameActive;
|
|
|
|
|
|
+ /**
|
|
|
+ * Constructs a GameController, sets up model, view, input, inventory, entities, and interactive tiles.
|
|
|
+ */
|
|
|
public GameController() {
|
|
|
- this.keyHandler = new KeyHandler(this);
|
|
|
- this.gameModel = new GameModel();
|
|
|
- this.view = new GamePanel(this);
|
|
|
- entityControllers = new ArrayList<>();
|
|
|
- interactiveTileControllers = new ArrayList<>();
|
|
|
- setStartInventory();
|
|
|
- setupInteractiveTiles();
|
|
|
- setupEntities();
|
|
|
+ initModel();
|
|
|
+ initView();
|
|
|
+ initInputHandler();
|
|
|
+ initControllerLists();
|
|
|
+ initializeStartInventory();
|
|
|
+ initializeInteractiveTiles();
|
|
|
+ initializeEntities();
|
|
|
+ initResourceManager();
|
|
|
+ initShopController();
|
|
|
view.loadMap(worldPath);
|
|
|
}
|
|
|
|
|
|
- private void setupInteractiveTiles() {
|
|
|
- LighthouseController lighthouse = new LighthouseController(this, setupInteractiveTileModel(20, 20));
|
|
|
- addInteractiveTile(lighthouse);
|
|
|
+ /**
|
|
|
+ * Creates a new ShopController
|
|
|
+ */
|
|
|
+ private void initShopController() {
|
|
|
+ shopController = new ShopController(this);
|
|
|
+ }
|
|
|
|
|
|
- MineController mineController = new MineController(this, setupInteractiveTileModel(25,20));
|
|
|
- addInteractiveTile(mineController);
|
|
|
+ /**
|
|
|
+ * Creates a new ResourceManager
|
|
|
+ */
|
|
|
+ private void initResourceManager() {
|
|
|
+ ressourceManager = new RessourceManager(this);
|
|
|
+ ressourceManager.start();
|
|
|
+ }
|
|
|
|
|
|
- BarracksController barracksController = new BarracksController(this, setupInteractiveTileModel(26, 20));
|
|
|
- addInteractiveTile(barracksController);
|
|
|
+ /**
|
|
|
+ * Initializes the GameModel.
|
|
|
+ */
|
|
|
+ private void initModel() {
|
|
|
+ this.gameModel = new GameModel();
|
|
|
+ }
|
|
|
|
|
|
- IronMineController ironMineController = new IronMineController(this, setupInteractiveTileModel(27, 20));
|
|
|
- addInteractiveTile(ironMineController);
|
|
|
+ /**
|
|
|
+ * Initializes the GamePanel view.
|
|
|
+ */
|
|
|
+ private void initView() {
|
|
|
+ this.view = new GamePanel(this);
|
|
|
+ }
|
|
|
|
|
|
- AnimalEnclosureController animal = new AnimalEnclosureController(this, setupInteractiveTileModel(28, 20));
|
|
|
- addInteractiveTile(animal);
|
|
|
+ /**
|
|
|
+ * Initializes the key handler.
|
|
|
+ */
|
|
|
+ private void initInputHandler() {
|
|
|
+ this.keyHandler = new KeyHandler(this);
|
|
|
+ }
|
|
|
|
|
|
- SawmillController sawmillController = new SawmillController(this, setupInteractiveTileModel(29, 20));
|
|
|
- addInteractiveTile(sawmillController);
|
|
|
+ /**
|
|
|
+ * Initializes lists for entity and interactive tile controllers.
|
|
|
+ */
|
|
|
+ private void initControllerLists() {
|
|
|
+ entityControllers = new ArrayList<>();
|
|
|
+ interactiveTileControllers = new ArrayList<>();
|
|
|
}
|
|
|
|
|
|
- private void setupEntities(){
|
|
|
- VillagerController villager = new VillagerController(this, setupEntityModel(22,20));
|
|
|
- addEntity(villager);
|
|
|
+ /**
|
|
|
+ * Populates the starting inventory with basic items.
|
|
|
+ */
|
|
|
+ private void initializeStartInventory() {
|
|
|
+ Inventory inv = getModel().getInventory();
|
|
|
+ inv.addToInventory(new Item(ITEM_NAME.stone));
|
|
|
+ inv.addToInventory(new Item(ITEM_NAME.wood));
|
|
|
}
|
|
|
|
|
|
- private void addEntity(EntityController entityController) {
|
|
|
+ /**
|
|
|
+ * Sets up predefined interactive tiles in the world.
|
|
|
+ */
|
|
|
+ private void initializeInteractiveTiles() {
|
|
|
+ addInteractiveTileController(new LighthouseController(this,
|
|
|
+ createInteractiveTileModel(20, 20, InteractiveTileType.LIGHTHOUSE)));
|
|
|
+ addInteractiveTileController(new MineController(this,
|
|
|
+ createInteractiveTileModel(25, 20, InteractiveTileType.MINE)));
|
|
|
+ addInteractiveTileController(new BarracksController(this,
|
|
|
+ createInteractiveTileModel(26, 20, InteractiveTileType.BARRACKS)));
|
|
|
+ addInteractiveTileController(new IronMineController(this,
|
|
|
+ createInteractiveTileModel(27, 20, InteractiveTileType.IRON_MINE)));
|
|
|
+ addInteractiveTileController(new AnimalEnclosureController(this,
|
|
|
+ createInteractiveTileModel(28, 20, InteractiveTileType.ANIMAL_ENCLOSURE)));
|
|
|
+ addInteractiveTileController(new SawmillController(this,
|
|
|
+ createInteractiveTileModel(29, 20, InteractiveTileType.SAWMILL)));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets up predefined entities in the world.
|
|
|
+ */
|
|
|
+ private void initializeEntities() {
|
|
|
+ addEntityController(new VillagerController(this,
|
|
|
+ createEntityModel(22, 20, EntityType.VILLAGER)));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Adds an EntityController to the controller list.
|
|
|
+ *
|
|
|
+ * @param entityController the entity controller to add
|
|
|
+ */
|
|
|
+ private void addEntityController(EntityController entityController) {
|
|
|
entityControllers.add(entityController);
|
|
|
}
|
|
|
|
|
|
- private void addInteractiveTile(InteractiveTileController controller) {
|
|
|
- interactiveTileControllers.add(controller);
|
|
|
+ /**
|
|
|
+ * Adds an InteractiveTileController to the controller list.
|
|
|
+ *
|
|
|
+ * @param tileController the interactive tile controller to add
|
|
|
+ */
|
|
|
+ public void addInteractiveTileController(InteractiveTileController tileController) {
|
|
|
+ interactiveTileControllers.add(tileController);
|
|
|
}
|
|
|
|
|
|
- private EntityModel setupEntityModel(int worldX, int worldY) {
|
|
|
- EntityModel model = new EntityModel(worldX, worldY, getView().tileSize, getView().tileSize);
|
|
|
- gameModel.addEntityModel(model);
|
|
|
+ /**
|
|
|
+ * Creates and registers an EntityModel in the GameModel.
|
|
|
+ *
|
|
|
+ * @param worldX X position in world grid
|
|
|
+ * @param worldY Y position in world grid
|
|
|
+ * @param type type of entity
|
|
|
+ * @return the created EntityModel
|
|
|
+ */
|
|
|
+ private EntityModel createEntityModel(int worldX, int worldY, EntityType type) {
|
|
|
+ int size = getView().tileSize;
|
|
|
+ EntityModel model = new EntityModel(worldX, worldY, size, size, type);
|
|
|
+ getModel().addEntityModel(model);
|
|
|
return model;
|
|
|
}
|
|
|
|
|
|
- public InteractiveTileModel setupInteractiveTileModel(int worldGridX, int worldGridY){
|
|
|
- InteractiveTileModel model = new InteractiveTileModel(worldGridX, worldGridY);
|
|
|
- gameModel.addInteractiveTileModel(model);
|
|
|
+ /**
|
|
|
+ * Creates and registers an InteractiveTileModel in the GameModel.
|
|
|
+ *
|
|
|
+ * @param worldGridX X grid coordinate
|
|
|
+ * @param worldGridY Y grid coordinate
|
|
|
+ * @param type type of interactive tile
|
|
|
+ * @return the created InteractiveTileModel
|
|
|
+ */
|
|
|
+ public InteractiveTileModel createInteractiveTileModel(int worldGridX, int worldGridY, InteractiveTileType type) {
|
|
|
+ InteractiveTileModel model = new InteractiveTileModel(worldGridX, worldGridY, type);
|
|
|
+ getModel().addInteractiveTileModel(model);
|
|
|
return model;
|
|
|
}
|
|
|
- private void setStartInventory() {
|
|
|
- gameModel.getInventory().addToInventory(new Item(ITEM_NAME.stone));
|
|
|
- gameModel.getInventory().addToInventory(new Item(ITEM_NAME.water));
|
|
|
- gameModel.getInventory().addToInventory(new Item(ITEM_NAME.wood));
|
|
|
- }
|
|
|
|
|
|
- public void setView(GamePanel gp){
|
|
|
- view = gp;
|
|
|
+ /**
|
|
|
+ * Sets the GamePanel view.
|
|
|
+ *
|
|
|
+ * @param gp the GamePanel to set
|
|
|
+ */
|
|
|
+ public void setView(GamePanel gp) {
|
|
|
+ this.view = gp;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Handles a click on the inventory UI.
|
|
|
+ *
|
|
|
+ * @param x screen x-coordinate of click
|
|
|
+ * @param y screen y-coordinate of click
|
|
|
+ */
|
|
|
public void handleInventoryClick(int x, int y) {
|
|
|
+ SoundManager.getInstance().playSound(SoundManager.SOUNDS.CLICK);
|
|
|
int slot = view.getInventoryView().getClickedInventorySlot(x, y);
|
|
|
- gameModel.getInventory().select(slot);
|
|
|
+ getModel().getInventory().select(slot);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Handles a click on the shop UI.
|
|
|
+ * @param x screen x-coordinate of click
|
|
|
+ * @param y screen y-coordinate of click
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public void handleShopClick(int x, int y) {
|
|
|
+ InteractiveTileController controller = view.getShopView().getClickedOffer(x, y);
|
|
|
+ if(controller != null) SoundManager.getInstance().loopSound(SoundManager.SOUNDS.MOVING_BUSH);
|
|
|
+ shopController.setDraggingOffer(controller);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Starts the main game loop and resource manager thread.
|
|
|
+ */
|
|
|
public void startGameLoop() {
|
|
|
- gameThread = new Thread(this);
|
|
|
+ gameActive = true;
|
|
|
+ gameThread = new Thread(this, "GameLoopThread");
|
|
|
gameThread.start();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Stops the main game loop.
|
|
|
+ */
|
|
|
public void stopGameLoop() {
|
|
|
- running = false;
|
|
|
+ gameActive = false;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Performs update logic once per frame.
|
|
|
+ * Updates camera or handles save state depending on game state.
|
|
|
+ */
|
|
|
public void update() {
|
|
|
- if (view.gameState == GAMESTATE.PLAY || view.gameState == GAMESTATE.INVENTORY) {
|
|
|
- view.camera.update();
|
|
|
- }
|
|
|
- if(view.gameState == GAMESTATE.SAVE){
|
|
|
- GameSaver.saveGame(this);
|
|
|
- view.gameState = GAMESTATE.PLAY;
|
|
|
+ GAMESTATE state = view.gameState;
|
|
|
+ if (state == GAMESTATE.PLAY || state == GAMESTATE.INVENTORY) {
|
|
|
+ updateCamera();
|
|
|
+ } else if (state == GAMESTATE.SAVE) {
|
|
|
+ performSaveAndResume();
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Updates the camera position.
|
|
|
+ */
|
|
|
+ private void updateCamera() {
|
|
|
+ view.camera.update();
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * Saves the game and returns to PLAY state.
|
|
|
+ */
|
|
|
+ private void performSaveAndResume() {
|
|
|
+ GameSaver.saveGame(this);
|
|
|
+ view.gameState = GAMESTATE.PLAY;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * The main run loop implementing Runnable.
|
|
|
+ * Controls timing for updates and rendering.
|
|
|
+ */
|
|
|
@Override
|
|
|
public void run() {
|
|
|
+ runGameLoop();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Implements the game loop timing logic based on fps.
|
|
|
+ */
|
|
|
+ private void runGameLoop() {
|
|
|
double drawInterval = 1_000_000_000.0 / fps;
|
|
|
double delta = 0;
|
|
|
long lastTime = System.nanoTime();
|
|
|
- long currentTime;
|
|
|
long timer = 0;
|
|
|
int drawCount = 0;
|
|
|
|
|
|
while (running) {
|
|
|
- currentTime = System.nanoTime();
|
|
|
+ long currentTime = System.nanoTime();
|
|
|
delta += (currentTime - lastTime) / drawInterval;
|
|
|
timer += (currentTime - lastTime);
|
|
|
lastTime = currentTime;
|
|
|
|
|
|
if (delta >= 1) {
|
|
|
- update(); // Logic update
|
|
|
- view.repaint(); // Triggers paintComponent in view
|
|
|
- moveEntities();
|
|
|
+ if(gameActive){
|
|
|
+ update();
|
|
|
+ moveAllEntities();
|
|
|
+ }
|
|
|
+ view.repaint();
|
|
|
delta--;
|
|
|
drawCount++;
|
|
|
}
|
|
|
|
|
|
if (timer >= 1_000_000_000) {
|
|
|
+ // Could log fps: drawCount
|
|
|
drawCount = 0;
|
|
|
timer = 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void moveEntities() {
|
|
|
- for(EntityController entityController : entityControllers){
|
|
|
+ /**
|
|
|
+ * Invokes movement logic on all entity controllers.
|
|
|
+ */
|
|
|
+ private void moveAllEntities() {
|
|
|
+ if (entityControllers == null) return;
|
|
|
+ for (EntityController entityController : entityControllers) {
|
|
|
entityController.convertRepaintSpeedToMovementLogic();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public void zoomInOut(int i) {
|
|
|
- view.zoomInOut(i);
|
|
|
+ /**
|
|
|
+ * Zooms camera in or out and closes any open menus.
|
|
|
+ *
|
|
|
+ * @param amount positive to zoom in, negative to zoom out
|
|
|
+ */
|
|
|
+ public void zoomInOut(int amount) {
|
|
|
+ view.zoomInOut(amount);
|
|
|
view.closeMenus();
|
|
|
}
|
|
|
|
|
|
- public void togglePauseOrExitInventory() {
|
|
|
- if (view.gameState == GAMESTATE.INVENTORY) {
|
|
|
+ /**
|
|
|
+ * Toggles between PLAY, PAUSED or exits other menus.
|
|
|
+ */
|
|
|
+ public void handleEscape() {
|
|
|
+ GAMESTATE state = view.gameState;
|
|
|
+ if ( state == GAMESTATE.INVENTORY
|
|
|
+ || state == GAMESTATE.PAUSED
|
|
|
+ || state == GAMESTATE.SHOP) {
|
|
|
+
|
|
|
view.gameState = GAMESTATE.PLAY;
|
|
|
- } else if (view.gameState == GAMESTATE.PLAY) {
|
|
|
+
|
|
|
+ } else if (state == GAMESTATE.PLAY) {
|
|
|
view.gameState = GAMESTATE.PAUSED;
|
|
|
- } else if (view.gameState == GAMESTATE.PAUSED) {
|
|
|
- view.gameState = GAMESTATE.PLAY;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Toggles the inventory UI: enters or exits INVENTORY state.
|
|
|
+ * Deselects inventory item when closing.
|
|
|
+ */
|
|
|
public void toggleInventory() {
|
|
|
if (view.gameState == GAMESTATE.INVENTORY) {
|
|
|
view.gameState = GAMESTATE.PLAY;
|
|
|
- gameModel.getInventory().deselect();
|
|
|
- } else if (view.gameState == GAMESTATE.PLAY) {
|
|
|
+ getModel().getInventory().deselectAll();
|
|
|
+ } else
|
|
|
view.gameState = GAMESTATE.INVENTORY;
|
|
|
- }
|
|
|
}
|
|
|
- public GamePanel getView(){
|
|
|
- if(view == null){
|
|
|
- setView(new GamePanel(this));
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the GamePanel view, creating if necessary.
|
|
|
+ *
|
|
|
+ * @return the GamePanel
|
|
|
+ */
|
|
|
+ public GamePanel getView() {
|
|
|
+ if (view == null) {
|
|
|
+ view = new GamePanel(this);
|
|
|
}
|
|
|
return view;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns the GameModel, creating if necessary.
|
|
|
+ *
|
|
|
+ * @return the GameModel
|
|
|
+ */
|
|
|
public GameModel getModel() {
|
|
|
- if(gameModel == null) gameModel = new GameModel();
|
|
|
+ if (gameModel == null) {
|
|
|
+ gameModel = new GameModel();
|
|
|
+ }
|
|
|
return gameModel;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns the KeyHandler, creating if necessary.
|
|
|
+ *
|
|
|
+ * @return the KeyHandler
|
|
|
+ */
|
|
|
public KeyHandler getKeyHandler() {
|
|
|
- if(keyHandler == null) keyHandler = new KeyHandler(this);
|
|
|
+ if (keyHandler == null) {
|
|
|
+ keyHandler = new KeyHandler(this);
|
|
|
+ }
|
|
|
return keyHandler;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Loads the world from the default worldPath.
|
|
|
+ */
|
|
|
+ public void loadWorld() {
|
|
|
+ if (view == null) {
|
|
|
+ view = new GamePanel(this);
|
|
|
+ }
|
|
|
+ view.loadMap(worldPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Asks the view to generate a new world.
|
|
|
+ */
|
|
|
+ public void generateNewWorld() {
|
|
|
+ getView().generateNewWorld();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Entry point for dragging movement: called from GameMouseListener.mouseDragged when right mouse button.
|
|
|
+ * dx, dy are screen pixel deltas.
|
|
|
+ */
|
|
|
+ public void handleTileShift(int dx, int dy) {
|
|
|
+ getView().tileManager.handleTileShift(dx, dy);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Called from GameMouseListener.mouseReleased when ending a drag.
|
|
|
+ * Snaps the tile to grid, validates position, reverts if invalid.
|
|
|
+ */
|
|
|
+ public void handleTileRelease() {
|
|
|
+ getView().tileManager.handleTileRelease();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Loads interactive tiles and entities from the saved GameModel.
|
|
|
+ */
|
|
|
+ public void loadGame() {
|
|
|
+ loadInteractiveTilesFromSave();
|
|
|
+ loadEntitiesFromSave();
|
|
|
+ initResourceManager();
|
|
|
+ initShopController();
|
|
|
+ }
|
|
|
|
|
|
- public void loadInteractiveTiles() {
|
|
|
+ /**
|
|
|
+ * Re-initializes interactiveTileControllers from models in gameModel.
|
|
|
+ */
|
|
|
+ private void loadInteractiveTilesFromSave() {
|
|
|
interactiveTileControllers = new ArrayList<>();
|
|
|
- setupInteractiveTiles();
|
|
|
+ for (InteractiveTileModel model : getModel().getInteractiveTileModels()) {
|
|
|
+ InteractiveTileController controller = InteractiveTileFactory.createTile(this, model);
|
|
|
+ if (controller != null) {
|
|
|
+ addInteractiveTileController(controller);
|
|
|
+ } else {
|
|
|
+ System.err.println("Unknown tile type: " + model.getTileType());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public void loadWorld(){
|
|
|
- if(view == null) this.view = new GamePanel(this);
|
|
|
- view.loadMap(worldPath);
|
|
|
+ /**
|
|
|
+ * Re-initializes entityControllers from models in gameModel.
|
|
|
+ */
|
|
|
+ private void loadEntitiesFromSave() {
|
|
|
+ entityControllers = new ArrayList<>();
|
|
|
+ for (EntityModel model : getModel().getEntityModels()) {
|
|
|
+ EntityController controller = EntityFactory.createEntity(this, model);
|
|
|
+ if (controller != null) {
|
|
|
+ addEntityController(controller);
|
|
|
+ } else {
|
|
|
+ System.err.println("Unknown entity type: " + model.getEntityType());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- public void generateNewWorld() {
|
|
|
- view.generateNewWorld();
|
|
|
+
|
|
|
+ public boolean isRunning() {
|
|
|
+ return running;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void addToInventory(Item collected) {
|
|
|
+ getModel().getInventory().addToInventory(collected);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public void toggleShop() {
|
|
|
+ getView().toggleShop();
|
|
|
}
|
|
|
}
|
|
|
+
|