package vooga.rts.manager; import java.awt.Graphics2D; import java.awt.Shape; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.Queue; import vooga.rts.action.Action; import vooga.rts.action.IActOn; import vooga.rts.commands.ClickCommand; import vooga.rts.commands.Command; import vooga.rts.commands.DragCommand; import vooga.rts.gamedesign.sprite.gamesprites.interactive.InteractiveEntity; import vooga.rts.gamedesign.sprite.gamesprites.interactive.buildings.Building; import vooga.rts.gamedesign.state.DetectableState; import vooga.rts.gamedesign.state.MovementState; import vooga.rts.gamedesign.state.OccupyState; import vooga.rts.manager.actions.DragSelectAction; import vooga.rts.manager.actions.LeftClickAction; import vooga.rts.manager.actions.RightClickAction; import vooga.rts.state.GameState; import vooga.rts.state.State; import vooga.rts.util.Location3D; /** * The Manager class is responsible for managing all of the units and buildings * that each player controls. Commands are passed through to the Manager * and the appropriate actions are executed on the selected units or even the * manager. * * @author Jonathan Schmidt * @author Challen Herzberg-Brovold * */ public class Manager extends Observable implements State, IActOn, Observer { private List<InteractiveEntity> myEntities; private List<InteractiveEntity> mySelectedEntities; private Map<Integer, List<InteractiveEntity>> myGroups; private boolean myMultiSelect; private Map<String, Action> myActions; private Queue<InteractiveEntity> myAddQueue; private int myPlayer; Iterator<InteractiveEntity> myUpdateIterator; public Manager (int playerID) { myPlayer = playerID; myEntities = new ArrayList<InteractiveEntity>(); mySelectedEntities = new ArrayList<InteractiveEntity>(); myGroups = new HashMap<Integer, List<InteractiveEntity>>(); myMultiSelect = false; myActions = new HashMap<String, Action>(); myAddQueue = new LinkedList<InteractiveEntity>(); addActions(); } @Override public void paint (Graphics2D pen) { for (InteractiveEntity u : myEntities) { u.paint(pen); } } @Override public void update (double elapsedTime) { myEntities.addAll(myAddQueue); myAddQueue.clear(); myUpdateIterator = myEntities.iterator(); while (myUpdateIterator.hasNext()) { InteractiveEntity u = myUpdateIterator.next(); u.update(elapsedTime); } myUpdateIterator = null; } @Override public void receiveCommand (Command command) { updateAction(command); } /** * Checks to see if the manager can handle the command, if not sends it to * the selected entities. */ @Override public void updateAction (Command command) { if (myActions.containsKey(command.getMethodName())) { Action current = myActions.get(command.getMethodName()); current.update(command); current.apply(); } else { applyAction(command); } } @Override public void addAction (String input, Action action) { myActions.put(input, action); } /** * Retrieves the appropriate action for all the selected entities which * can handle the input, then applies the action. * * @param command input used to retrieve the appropriate command */ public void applyAction (Command command) { Iterator<InteractiveEntity> it = mySelectedEntities.iterator(); while (it.hasNext()) { InteractiveEntity u = it.next(); if (u.containsInput(command)) { u.updateAction(command); u.getAction(command).apply(); } } } /** * Adds an entity to the manager. This will be done when a new entity is * created. * * @param u * The entity that is to be added. */ public void add (InteractiveEntity entity) { entity.setPlayerID(myPlayer); entity.addObserver(GameState.getMap().getNodeMap()); entity.addObserver(this); entity.setChanged(); entity.notifyObservers(entity.getWorldLocation()); myAddQueue.add(entity); } public void remove (InteractiveEntity entity) { if (myUpdateIterator != null) { myUpdateIterator.remove(); } else { myEntities.remove(entity); } entity.deleteObservers(); mySelectedEntities.remove(entity); } /** * Deselects the topmost unit at the given location. * * @param location at which to deselect the unit. */ public void deselect (Location3D location) { for (int i = getAllEntities().size() - 1; i >= 0; i--) { InteractiveEntity ie = getAllEntities().get(i); if (ie.intersects(location)) { deselect(ie); return; } } deselectAll(); } private void notifyDeselect () { setChanged(); notifyObservers(false); } /** * Deselects the specified entity. * * @param u The entity to deselect */ public void deselect (InteractiveEntity ie) { if (mySelectedEntities.contains(ie)) { mySelectedEntities.remove(ie); ie.select(false); } } /** * Deselects all selected entities. */ public void deselectAll () { notifyDeselect(); if (myMultiSelect) { return; } for (InteractiveEntity ie : mySelectedEntities) { ie.select(false); } mySelectedEntities.clear(); } /** * Returns the list of all the entities in the manager. * * @return List of all entities */ public List<InteractiveEntity> getAllEntities () { return myEntities; } /** * Sets the entities to a specified list of entities * * @param entityList */ public void setAllEntities (List<InteractiveEntity> entityList) { myEntities = entityList; } /** * Returns the list of selected entities. * * @return The selected entities */ public List<InteractiveEntity> getSelected () { return mySelectedEntities; } /** * Groups the currently selected entities together with a specified group ID * * @param groupID * The ID of the group */ public void group (int groupID) { myGroups.put(groupID, new ArrayList<InteractiveEntity>(mySelectedEntities)); } /** * Selects a specific entity and marks it as selected. * * @param entity */ public void select (InteractiveEntity entity) { deselectAll(); if (!mySelectedEntities.contains(entity)) { if (myEntities.contains(entity)) { if (entity.select(true)) { mySelectedEntities.add(entity); } } } notifySelect(); } public void notifySelect () { setChanged(); notifyObservers(true); } /** * Selects the top most interactive entity that is underneath the provided * Point location. This is used for selecting entities by mouse click. * * @param loc */ public void select (Location3D loc) { deselectAll(); for (int i = getAllEntities().size() - 1; i >= 0; i--) { InteractiveEntity ie = getAllEntities().get(i); if (ie.intersects(loc)) { select(ie); return; } } } /** * Selects all the entities in provided rectangle. Allows a user to drag * around the desired entities. * * @param area * The area to select the entities in. */ public void select (Shape area) { deselectAll(); boolean multi = myMultiSelect; setMultiSelect(true); for (InteractiveEntity ie : myEntities) { if (area.intersects(ie.getBounds()) || area.contains(ie.getBounds())) { select(ie); } } setMultiSelect(multi); } /** * Sets the Manager into multi select mode which allows the user to select * more than one entity at a time. * * @param val * whether it is multi select or not */ public void setMultiSelect (boolean val) { myMultiSelect = val; } public void addActions () { addAction(DragCommand.DRAG, new DragSelectAction(this)); addAction(ClickCommand.LEFT_CLICK, new LeftClickAction(this)); addAction(ClickCommand.RIGHT_CLICK, new RightClickAction(this)); } /** * Activates a previously create group of entities. * * @param groupID * The ID of the group to select */ public void activateGroup (int groupID) { if (myGroups.containsKey(groupID)) { mySelectedEntities = new ArrayList<InteractiveEntity>(myGroups.get(groupID)); } } /** * Finds the InteractiveEntity in myEntities based on its hash code. * * @param hashCode the hash code of the entity that is looking for * @return the index of the entity with the hashCode */ private int findEntityWithHashCode (int hashCode) { for (int i = 0; i < myEntities.size(); ++i) { if (myEntities.get(i).hashCode() == hashCode) { return i; } } return -1; } @Override public void update (Observable entity, Object state) { if (entity instanceof InteractiveEntity) { InteractiveEntity ie = (InteractiveEntity) entity; if (ie.isDead()) { remove(ie); } } // While Shepherds watch their flocks by night. if (state instanceof InteractiveEntity) { InteractiveEntity sent = (InteractiveEntity) state; if (!myEntities.contains(sent)) { add(sent); } } else { if (state instanceof Integer) { int index = findEntityWithHashCode((Integer) state); InteractiveEntity unit = myEntities.get(index); unit.getEntityState().setOccupyState(OccupyState.NOT_OCCUPYING); unit.setVisible(true); unit.setWorldLocation(((InteractiveEntity) entity).getRallyPoint()); myEntities.get(index).stopMoving(); unit.getEntityState().setMovementState(MovementState.STATIONARY); } } } }