package vooga.towerdefense.controller; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; import util.Location; import vooga.towerdefense.util.Pixmap; import vooga.towerdefense.attributes.AttributeConstantsEnum; import vooga.towerdefense.controller.modes.BuildMode; import vooga.towerdefense.controller.modes.ControlMode; import vooga.towerdefense.controller.modes.SelectMode; import vooga.towerdefense.factories.elementfactories.GameElementFactory; import vooga.towerdefense.gameeditor.gameloader.xmlloaders.GameLoader; import vooga.towerdefense.gameelements.GameElement; import vooga.towerdefense.model.GameLoop; import vooga.towerdefense.model.GameMap; import vooga.towerdefense.model.GameModel; import vooga.towerdefense.model.Player; import vooga.towerdefense.model.Tile; import vooga.towerdefense.model.shop.Shop; import vooga.towerdefense.model.shop.ShopItem; import vooga.towerdefense.view.TDView; /** * Controller is the channel of communication between the Model and the View. * * @author Angelica Schwartz * @author Erick Gonzalez * @author Leonard K. Ng'eno * @author Jimmy Longley */ public class Controller { /** * location of resource bundle. */ private static final String DEFAULT_RESOURCE_PACKAGE = "vooga/towerdefense/resources."; /** * resource bundle for this controller. */ private ResourceBundle myResourceBundle; /** * model for this game. */ private GameModel myModel; /** * view for this game. */ private TDView myView; /** * game loader for this controller. */ private GameLoader myGameLoader; /** * map of image to the map object. */ private Map<Pixmap, GameMap> myAvailableMaps; /** * control mode for the controller. */ private ControlMode myControlMode; // TODO: controller constructor should take waves & map in order to // initialize GameModel? // TODO: fix where the parameters come from public Controller(String language, String xmlPath) throws IllegalArgumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException { setLanguage(language); myGameLoader = new GameLoader(xmlPath); myView = new TDView(this); myView.showSplashScreen(); setMaps(); } /** * sets up the view for this game. * * @throws InvocationTargetException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws IllegalArgumentException */ private void setView() throws IllegalArgumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException { myView = myGameLoader.loadView(myView, this); } /** * sets the maps available for this game. */ private void setMaps() { myAvailableMaps = new HashMap<Pixmap, GameMap>(); List<GameMap> mapChoices = myGameLoader.loadMaps(); for (GameMap map : mapChoices) { myAvailableMaps.put(map.getBackgroundImage(), map); } } /** * sets the map for this game. * * @param mapChoice * @throws InvocationTargetException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws IllegalArgumentException */ public void setMap(Pixmap mapChoice) throws IllegalArgumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException { addMapAndLoadGame(myAvailableMaps.get(mapChoice)); setView(); } /** * gets the map images for this game. * * @return set of pixmap */ public Set<Pixmap> getMapImages() { return myAvailableMaps.keySet(); } /** * adds the map to the game and loads the remainder of the game state. * * @param map */ private void addMapAndLoadGame(GameMap map) { Player player = myGameLoader.loadPlayer(this); List<GameElementFactory> factories = myGameLoader.loadElements(map, player); myModel = new GameModel(this, player, map, new Shop(map, factories)); myModel.setRules(myGameLoader.loadRules(myModel)); myModel.setLevels(myGameLoader.loadLevels(myModel, map, player)); myControlMode = new SelectMode(); start(); } /** * cancels the purchase and stops painting ghost image. */ public void cancelPurchaseFromShop() { myModel.getMap().resetGhostImage(); myControlMode = new SelectMode(); setVisibilityOfShopCancelButton(false); } private void setVisibilityOfShopCancelButton(boolean visibility) { myView.getShopScreen().setCancelButtonVisibility(visibility); } /** * displays information about the GameElement on the tile. * * @param p * is the point that was clicked. */ public void displayElementInformation(GameElement e) { if (e != null) { myView.getGameElementInfoScreen().displayInformation(e.getAttributeManager().toString()); if (e.getAttributeManager().hasUpgrades()) { List<String> upgrades = new ArrayList<String>(e .getAttributeManager().getUpgrades().keySet()); myView.getGameElementInfoScreen().displayUpgradesAndButton( upgrades); } } else { myView.getGameElementInfoScreen().clearScreen(); } } /** * updates the display on the MapScreen. */ public void displayMap() { myView.getMapScreen().update(); } /** * places the new item onto the map & changes the mode back to SelectMode. * * @param item * @param p */ public void fixItemOnMap(GameElement item, Point p) { if (myModel.getMap().isTower(item)) { myModel.getMap().blockTiles(item); myModel.getMap().updatePaths(); } myModel.getMap().addToMap(item); displayMap(); myControlMode = new SelectMode(); setVisibilityOfShopCancelButton(false); } /** * gets the associated game element at a point. * * @param p * @return the game element */ public GameElement getItemAt(Point p) { Tile tile = myModel.getTile(p); if (tile.containsElement()) { return tile.getElement(); } return null; } /** * gets the resource bundle for this controller. * * @return the resource bundle */ public ResourceBundle getResourceBundle() { return myResourceBundle; } /** * Get the matching string from the resource bundle. * * @param s * is the string to match * @return the appropriate string in the selected language */ public String getStringFromResources(String s) { return myResourceBundle.getString(s); } /** * handles a click to the map appropriately depending on the mode. * * @param p * is the location of the click */ public void handleMapMouseDrag(Point p) { myControlMode.handleMapMouseDrag(p, this); } /** * handles a mouse drag on the map appropriately depending on the mode. * * @param p * is the location of the mouse */ public void handleMapClick(Point p) { myControlMode.handleMapClick(p, this); } /** * changes the mode to BuildMode and gets the item the user wants to build * from the Shop. * * @param itemName * is the name of the item the user wants to buy */ public void handleShopClickOnItem(Point p) { ShopItem itemToBuy = myModel.getShopItem(p); // no item clicked if (itemToBuy == null || myModel.getPlayer().getAttributeManager().getAttribute(AttributeConstantsEnum.MONEY.getStatusCode()).getValue() <= 0) return; BuildMode myNewMode = new BuildMode(); GameElementFactory factory = itemToBuy.getFactory(); GameElement t = factory.createElement(new Location()); myNewMode.setItemToBuild(t); double cost = t.getAttributeManager() .getAttribute(AttributeConstantsEnum.COST.getStatusCode()) .getValue(); myNewMode.setCost(cost); myControlMode = myNewMode; } /** * starts the next level in the model. */ public void startNextLevel() { myModel.startNextLevel(); } public Location getPointSnappedToGrid(Location location) { return myModel.getMap().getTile(location).getCenter(); } /** * paints the ghost image of the item on the MapScreen on the mouse's * location. * * @param p * is the mouselocation * @param itemImage * is the image */ public void paintGhostImage(Pixmap itemImage, Location location, Dimension size) { displayMap(); myModel.getMap().addGhostImage(itemImage, location, size); } /** * paints the map. * * @param pen */ public void paintMap(Graphics pen) { myModel.paintMap((Graphics2D) pen); } /** * updates the model. * * @param elapsedTime */ public void update(double elapsedTime) { myModel.update(elapsedTime); } /** * upgrades the item to the new type. * * @param upgradeName */ // TODO: Fix for game elements to be towers. -matthew public void upgradeSelectedItemTo(String upgradeName) { GameElement t = ((SelectMode) myControlMode).getCurrentlySelectedItem(); // t.upgrade(upgradeName); // TODO: implement upgrade stuff on backend (ask unit team for tower upgrade info!) } /** * Sets the language * * @param language * the language to set the controller to */ public void setLanguage(String language) { try { myResourceBundle = ResourceBundle .getBundle(DEFAULT_RESOURCE_PACKAGE + language); } catch (MissingResourceException e) { e.printStackTrace(); } } /** * Start the game controller. */ public void start() { GameLoop game = new GameLoop(this); myModel.startNextLevel(); game.start(); } /** * paints the shop. * @param pen */ public void paintShop(Graphics2D pen) { myModel.paintShop(pen); } /** * Used to determine if a ghost image should be painted, it tests if a tower * can be built at a particular point. * * @param p * @return */ public boolean canBuildHere(Point p, int tilesWide, int tilesTall) { boolean canBuild = true; for (int i = 0; i < tilesWide; i++) { for (int j = 0; j < tilesTall; j++) { Location location = new Location(p.getX() + i * myModel.getMap().getTileSize().getWidth(), p.getY() + j * myModel.getMap().getTileSize().getHeight()); canBuild = canBuild & myModel.getMap().isBuildable(location); } } return canBuild; } /** * displays the player statistics on the appropriate screen. * @param playerData */ public void displayPlayerStatistics(String playerData) { myView.getStatsScreen().displayInformation(playerData); } /** * gets the tile size for the map. * @return the tile size as a dimension */ public Dimension getTileSize() { return myModel.getMap().getTileSize(); } /** * The function called when the model reaches winning conditions */ public void win() { myView.showWinScreen(); } /** * The function called when the model reaches losing conditions */ public void lose() { myView.showLoseScreen(); } /** * decrements a players money by a specified amount. * * @param myCost */ public void spend(double cost) { myModel.getPlayer().getAttributeManager() .getAttribute(AttributeConstantsEnum.MONEY.getStatusCode()) .modifyValue(-cost); } /** * updates the visible timer for the wave. * @param timer is the remaining time */ public void updateWaveTimer(double timer) { myView.getNextWaveScreen().updateTimerDisplay(String.valueOf(timer)); } }