Small fixes and improvements
A boss will drop all its items A girl will choose a name from a list (not finalized) Carrots will no longer spawn randomly Lets a message overflow to the next line Added a new method for dropping an item at any location (for Boss.java) Improves backpacks Improves symbols for existing items Added an interact-message to all containers, and removed it from IStatic Makes it possible to get any of the 1-10 items in a chest Makes an item dropped on the same tile as a static container enter the container Code improvements Game end screen
This commit is contained in:
		@@ -1,17 +1,26 @@
 | 
			
		||||
package inf101.v18.rogue101.enemies;
 | 
			
		||||
 | 
			
		||||
import inf101.v18.grid.ILocation;
 | 
			
		||||
import inf101.v18.rogue101.game.IGame;
 | 
			
		||||
import inf101.v18.rogue101.items.Backpack;
 | 
			
		||||
import inf101.v18.rogue101.items.Sword;
 | 
			
		||||
import inf101.v18.rogue101.objects.IItem;
 | 
			
		||||
import inf101.v18.rogue101.objects.INonPlayer;
 | 
			
		||||
import inf101.v18.rogue101.shared.NPC;
 | 
			
		||||
 | 
			
		||||
public class Boss implements INonPlayer {
 | 
			
		||||
    private int hp = getMaxHealth();
 | 
			
		||||
    Backpack backpack = new Backpack();
 | 
			
		||||
    private Backpack backpack = new Backpack();
 | 
			
		||||
    private ILocation loc;
 | 
			
		||||
 | 
			
		||||
    public Boss() {
 | 
			
		||||
        backpack.add(new Sword());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void doTurn(IGame game) {
 | 
			
		||||
 | 
			
		||||
        loc = game.getLocation();
 | 
			
		||||
        NPC.tryAttack(game, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -61,7 +70,7 @@ public class Boss implements INonPlayer {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getPrintSymbol() {
 | 
			
		||||
        return "\uD83D\uDE08";
 | 
			
		||||
        return "\u001b[91m" + "\uD83D\uDE08" + "\u001b[0m";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -69,10 +78,25 @@ public class Boss implements INonPlayer {
 | 
			
		||||
        return "B";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getVision() {
 | 
			
		||||
        return 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int handleDamage(IGame game, IItem source, int amount) {
 | 
			
		||||
        //TODO: Drop item on death.
 | 
			
		||||
        hp -= amount;
 | 
			
		||||
        if (hp < 0 && backpack.size() > 0) {
 | 
			
		||||
            boolean dropped = false;
 | 
			
		||||
            for (IItem item : backpack.getContent()) {
 | 
			
		||||
                if (game.dropAt(loc, item)) {
 | 
			
		||||
                    dropped = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (dropped) {
 | 
			
		||||
                game.displayMessage(getName() + " dropped something");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return amount;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ public class Girl implements INonPlayer {
 | 
			
		||||
    private Backpack backpack = new Backpack();
 | 
			
		||||
    private static final Random random = new Random();
 | 
			
		||||
    private List<Class<?>> validItems;
 | 
			
		||||
    private static final String[] namelist = {"Milk", "Salad"};
 | 
			
		||||
 | 
			
		||||
    public Girl() {
 | 
			
		||||
        setStats();
 | 
			
		||||
@@ -100,8 +101,7 @@ public class Girl implements INonPlayer {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String randomName() {
 | 
			
		||||
        //TODO: Choose from a list of names, or generate name.
 | 
			
		||||
        return "Girl";
 | 
			
		||||
        return namelist[random.nextInt(namelist.length)] + "-chan";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -141,16 +141,16 @@ public class Girl implements INonPlayer {
 | 
			
		||||
    private boolean attack(IGame game) {
 | 
			
		||||
        switch (occupation) {
 | 
			
		||||
            case KNIGHT:
 | 
			
		||||
                if (NPC.tryAttack(game)) {
 | 
			
		||||
                if (NPC.tryAttack(game, 1)) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case MAGE:
 | 
			
		||||
                if (NPC.tryAttackRanged(game, 2)) {
 | 
			
		||||
                if (NPC.tryAttack(game, 2)) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            case BOWSMAN:
 | 
			
		||||
                if (NPC.tryAttackRanged(game, 4)) {
 | 
			
		||||
                if (NPC.tryAttack(game, 4)) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
@@ -183,15 +183,6 @@ public class Girl implements INonPlayer {
 | 
			
		||||
        return attack;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves a girl's occupation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    public Occupation getOccupation() {
 | 
			
		||||
        return occupation;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getAttack() {
 | 
			
		||||
        return attack;
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ public class Rabbit implements INonPlayer {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (NPC.tryAttack(game)) {
 | 
			
		||||
		if (NPC.tryAttack(game, 1)) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,7 @@ public class Game implements IGame {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Prints some helpful information.
 | 
			
		||||
		String[] info = {"Controls:", "WASD or arrow keys for movement", "E to pick up an item", "Q to drop an item", "1-5 to choose an item", "N to change name", "ENTER to confirm", "R to use a ranged attack", "F to use a magic attack"};
 | 
			
		||||
		String[] info = {"Controls:", "WASD or arrow keys for movement", "E to pick up an item", "Q to drop an item", "1-0 to choose an item (10=0)", "N to change name", "ENTER to confirm", "R to use a ranged attack", "F to use a magic attack"};
 | 
			
		||||
        for (int i = 0; i < info.length; i++) {
 | 
			
		||||
            this.printer.printAt(map.getWidth() + 2, 1 + i, info[i]);
 | 
			
		||||
        }
 | 
			
		||||
@@ -181,6 +181,7 @@ public class Game implements IGame {
 | 
			
		||||
		if (!map.has(loc, target)) {
 | 
			
		||||
			throw new IllegalMoveException("Target isn't there!");
 | 
			
		||||
		}
 | 
			
		||||
		//TODO: Detect the weapon used
 | 
			
		||||
		IWeapon weapon = (IWeapon) currentActor.getItem(IWeapon.class);
 | 
			
		||||
		if (weapon != null) {
 | 
			
		||||
			NPC.playSound(weapon.getSound());
 | 
			
		||||
@@ -189,7 +190,9 @@ public class Game implements IGame {
 | 
			
		||||
		}
 | 
			
		||||
		if (getAttack() >= getDefence(target)) {
 | 
			
		||||
			int actualDamage = target.handleDamage(this, target, getDamage(target));
 | 
			
		||||
			formatMessage("%s hits %s for %d damage", currentActor.getName(), target.getName(), actualDamage);
 | 
			
		||||
			if (currentActor != null) {
 | 
			
		||||
                formatMessage("%s hits %s for %d damage", currentActor.getName(), target.getName(), actualDamage);
 | 
			
		||||
            }
 | 
			
		||||
		} else {
 | 
			
		||||
			formatMessage("%s tried to hit %s, but missed", currentActor.getName(), target.getName());
 | 
			
		||||
		}
 | 
			
		||||
@@ -243,18 +246,21 @@ public class Game implements IGame {
 | 
			
		||||
				beginTurn();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (random.nextInt(100) < 20) {
 | 
			
		||||
			/*if (random.nextInt(100) < 20) {
 | 
			
		||||
				ILocation loc = map.getLocation(random.nextInt(map.getWidth()), random.nextInt(map.getHeight()));
 | 
			
		||||
				if (!map.hasActors(loc) && !map.hasItems(loc) && !map.hasWall(loc)) {
 | 
			
		||||
					map.add(loc, new Carrot());
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			}*/ //We don't want this in the actual game.
 | 
			
		||||
 | 
			
		||||
			// process actors one by one; for the IPlayer, we return and wait for keypresses
 | 
			
		||||
			// Possible for INonPlayer, we could also return early (returning
 | 
			
		||||
			// *false*), and then insert a little timer delay between each non-player move
 | 
			
		||||
			// (the timer
 | 
			
		||||
			// is already set up in Main)
 | 
			
		||||
           if (numPlayers == 0) {
 | 
			
		||||
               kill();
 | 
			
		||||
           }
 | 
			
		||||
			while (!actors.isEmpty()) {
 | 
			
		||||
				// get the next player or non-player in the queue
 | 
			
		||||
				currentActor = actors.remove(0);
 | 
			
		||||
@@ -275,11 +281,11 @@ public class Game implements IGame {
 | 
			
		||||
				} else if (currentActor instanceof IPlayer) {
 | 
			
		||||
					if (currentActor.isDestroyed()) {
 | 
			
		||||
						// a dead human player gets removed from the game
 | 
			
		||||
						// TODO: you might want to be more clever here
 | 
			
		||||
						displayMessage("YOU DIE!!!");
 | 
			
		||||
                        //This never actually triggers, because of map.clean();
 | 
			
		||||
						/*displayMessage("YOU DIE!!!");
 | 
			
		||||
						map.remove(currentLocation, currentActor);
 | 
			
		||||
						currentActor = null;
 | 
			
		||||
						currentLocation = null;
 | 
			
		||||
						currentLocation = null;*/
 | 
			
		||||
					} else {
 | 
			
		||||
						// For the human player, we need to wait for input, so we just return.
 | 
			
		||||
						// Further keypresses will cause keyPressed() to be called, and once the human
 | 
			
		||||
@@ -300,6 +306,37 @@ public class Game implements IGame {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Player is dead. It needs to be properly killed off.
 | 
			
		||||
     */
 | 
			
		||||
	public void kill() {
 | 
			
		||||
        map.remove(currentLocation, currentActor);
 | 
			
		||||
        currentActor = null;
 | 
			
		||||
        currentLocation = null;
 | 
			
		||||
        actors = new ArrayList<>();
 | 
			
		||||
        loadMap("gameover.txt");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a map with the desired name
 | 
			
		||||
     *
 | 
			
		||||
     * @param mapName Name of map, including extension.
 | 
			
		||||
     */
 | 
			
		||||
    private void loadMap(String mapName) {
 | 
			
		||||
        IGrid<String> inputGrid = MapReader.readFile("maps/" + mapName);
 | 
			
		||||
        if (inputGrid == null) {
 | 
			
		||||
            System.err.println("Map not found – falling back to builtin map");
 | 
			
		||||
            inputGrid = MapReader.readString(Main.BUILTIN_MAP);
 | 
			
		||||
        }
 | 
			
		||||
        this.map = new GameMap(inputGrid.getArea());
 | 
			
		||||
        for (ILocation loc : inputGrid.locations()) {
 | 
			
		||||
            IItem item = createItem(inputGrid.get(loc));
 | 
			
		||||
            if (item != null) {
 | 
			
		||||
                map.add(loc, item);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Go through the map and collect all the actors.
 | 
			
		||||
	 */
 | 
			
		||||
@@ -357,6 +394,8 @@ public class Game implements IGame {
 | 
			
		||||
		itemFactories.put("S", Sword::new);
 | 
			
		||||
        itemFactories.put("c", Chest::new);
 | 
			
		||||
		itemFactories.put("B", Boss::new);
 | 
			
		||||
		itemFactories.put("s", Staff::new);
 | 
			
		||||
		itemFactories.put("b", Bow::new);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
@@ -392,13 +431,37 @@ public class Game implements IGame {
 | 
			
		||||
		printer.clearLine(Main.LINE_MSG1);
 | 
			
		||||
        printer.clearLine(Main.LINE_MSG2);
 | 
			
		||||
        printer.clearLine(Main.LINE_MSG3);
 | 
			
		||||
 | 
			
		||||
		int maxLen = 80; //The maximum length of a message to not overflow.
 | 
			
		||||
		boolean secondLineWritten = false;
 | 
			
		||||
		boolean thirdLineWritten = false;
 | 
			
		||||
 | 
			
		||||
        if (lastMessages.size() > 0) {
 | 
			
		||||
            printer.printAt(1, Main.LINE_MSG1, lastMessages.get(0));
 | 
			
		||||
        	String message = lastMessages.get(0);
 | 
			
		||||
        	if (message.length() > 2 * maxLen) {
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG1, message.substring(0, maxLen));
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG2, message.substring(maxLen, 2 * maxLen));
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG3, message.substring(2 * maxLen));
 | 
			
		||||
				secondLineWritten = thirdLineWritten = true;
 | 
			
		||||
			} else if (message.length() > maxLen) {
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG1, message.substring(0, maxLen));
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG2, message.substring(maxLen));
 | 
			
		||||
				secondLineWritten = true;
 | 
			
		||||
			} else {
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG1, message);
 | 
			
		||||
			}
 | 
			
		||||
        }
 | 
			
		||||
        if (lastMessages.size() > 1) {
 | 
			
		||||
            printer.printAt(1, Main.LINE_MSG2, lastMessages.get(1));
 | 
			
		||||
        if (lastMessages.size() > 1 && !secondLineWritten) {
 | 
			
		||||
			String message = lastMessages.get(1);
 | 
			
		||||
			if (message.length() > maxLen) {
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG2, message.substring(0, maxLen));
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG3, message.substring(maxLen));
 | 
			
		||||
				thirdLineWritten = true;
 | 
			
		||||
			} else {
 | 
			
		||||
				printer.printAt(1, Main.LINE_MSG2, message);
 | 
			
		||||
			}
 | 
			
		||||
        }
 | 
			
		||||
        if (lastMessages.size() > 2) {
 | 
			
		||||
        if (lastMessages.size() > 2 && !thirdLineWritten) {
 | 
			
		||||
            printer.printAt(1, Main.LINE_MSG3, lastMessages.get(2));
 | 
			
		||||
        }
 | 
			
		||||
		System.out.println("Message: «" + s + "»");
 | 
			
		||||
@@ -412,9 +475,11 @@ public class Game implements IGame {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void draw() {
 | 
			
		||||
		//map.draw(painter, printer);
 | 
			
		||||
		GameMap aMap = (GameMap) map;
 | 
			
		||||
		aMap.drawVisible(painter, printer, this);
 | 
			
		||||
	    if (numPlayers == 0) {
 | 
			
		||||
		    map.draw(painter, printer);
 | 
			
		||||
        } else {
 | 
			
		||||
            ((GameMap) map).drawVisible(painter, printer);
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
@@ -426,6 +491,15 @@ public class Game implements IGame {
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean dropAt(ILocation loc, IItem item) {
 | 
			
		||||
		if (item != null) {
 | 
			
		||||
			map.add(loc, item);
 | 
			
		||||
			return true;
 | 
			
		||||
		} else
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void formatDebug(String s, Object... args) {
 | 
			
		||||
		displayDebug(String.format(s, args));
 | 
			
		||||
@@ -624,43 +698,51 @@ public class Game implements IGame {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public GridDirection locationDirection(ILocation start, ILocation target) {
 | 
			
		||||
	public List<GridDirection> locationDirection(ILocation start, ILocation target) {
 | 
			
		||||
		int targetX = target.getX(), targetY = target.getY();
 | 
			
		||||
		int startX = start.getX(), startY = start.getY();
 | 
			
		||||
		GridDirection dir = GridDirection.CENTER;
 | 
			
		||||
		List<GridDirection> dirs = new ArrayList<>();
 | 
			
		||||
		if (targetX > startX && targetY > startY) {
 | 
			
		||||
			if (Math.abs(targetX - startX) < Math.abs(targetY - startY)) {
 | 
			
		||||
				dir = GridDirection.SOUTH;
 | 
			
		||||
				dirs.add(GridDirection.SOUTH);
 | 
			
		||||
				dirs.add(GridDirection.EAST);
 | 
			
		||||
			} else {
 | 
			
		||||
				dir = GridDirection.EAST;
 | 
			
		||||
                dirs.add(GridDirection.EAST);
 | 
			
		||||
                dirs.add(GridDirection.SOUTH);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (targetX > startX && targetY < startY) {
 | 
			
		||||
			if (Math.abs(targetX - startX) < Math.abs(targetY - startY)) {
 | 
			
		||||
				dir = GridDirection.NORTH;
 | 
			
		||||
                dirs.add(GridDirection.NORTH);
 | 
			
		||||
                dirs.add(GridDirection.EAST);
 | 
			
		||||
			} else {
 | 
			
		||||
				dir = GridDirection.EAST;
 | 
			
		||||
                dirs.add(GridDirection.EAST);
 | 
			
		||||
                dirs.add(GridDirection.NORTH);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (targetX < startX && targetY > startY) {
 | 
			
		||||
			if (Math.abs(targetX - startX) < Math.abs(targetY - startY)) {
 | 
			
		||||
				dir = GridDirection.SOUTH;
 | 
			
		||||
                dirs.add(GridDirection.SOUTH);
 | 
			
		||||
                dirs.add(GridDirection.WEST);
 | 
			
		||||
			} else {
 | 
			
		||||
				dir = GridDirection.WEST;
 | 
			
		||||
                dirs.add(GridDirection.WEST);
 | 
			
		||||
                dirs.add(GridDirection.SOUTH);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (targetX < startX && targetY < startY) {
 | 
			
		||||
			if (Math.abs(targetX - startX) < Math.abs(targetY - startY)) {
 | 
			
		||||
				dir = GridDirection.NORTH;
 | 
			
		||||
                dirs.add(GridDirection.NORTH);
 | 
			
		||||
                dirs.add(GridDirection.WEST);
 | 
			
		||||
			} else {
 | 
			
		||||
				dir = GridDirection.WEST;
 | 
			
		||||
                dirs.add(GridDirection.WEST);
 | 
			
		||||
                dirs.add(GridDirection.NORTH);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (targetX > startX) {
 | 
			
		||||
			dir = GridDirection.EAST;
 | 
			
		||||
            dirs.add(GridDirection.EAST);
 | 
			
		||||
		} else if (targetX < startX) {
 | 
			
		||||
			dir = GridDirection.WEST;
 | 
			
		||||
            dirs.add(GridDirection.WEST);
 | 
			
		||||
		} else if (targetY > startY) {
 | 
			
		||||
			dir = GridDirection.SOUTH;
 | 
			
		||||
            dirs.add(GridDirection.SOUTH);
 | 
			
		||||
		} else if (targetY < startY) {
 | 
			
		||||
			dir = GridDirection.NORTH;
 | 
			
		||||
            dirs.add(GridDirection.NORTH);
 | 
			
		||||
		}
 | 
			
		||||
		return dir;
 | 
			
		||||
		return dirs;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -165,6 +165,15 @@ public interface IGame {
 | 
			
		||||
	 */
 | 
			
		||||
	boolean drop(IItem item);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Does the same as drop, but for a specified location.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param loc	The location to drop the location
 | 
			
		||||
	 * @param item	The item to drop
 | 
			
		||||
	 * @return		True if the item was dropped. False otherwise
 | 
			
		||||
	 */
 | 
			
		||||
	boolean dropAt(ILocation loc, IItem item);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Clear the unused graphics area (you can fill it with whatever you want!)
 | 
			
		||||
	 */
 | 
			
		||||
@@ -319,12 +328,12 @@ public interface IGame {
 | 
			
		||||
	Random getRandom();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Gets the best direction to go from current to neighbour.
 | 
			
		||||
	 * Gets a list of the best directions to go from current to neighbour.
 | 
			
		||||
	 * If the target is positioned diagonally from the start, the direction requiring the most steps is chosen.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param current		The location to go from
 | 
			
		||||
	 * @param neighbour	The location to go to
 | 
			
		||||
	 * @return				A direction
 | 
			
		||||
	 */
 | 
			
		||||
    GridDirection locationDirection(ILocation current, ILocation neighbour);
 | 
			
		||||
    List<GridDirection> locationDirection(ILocation current, ILocation neighbour);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import inf101.v18.rogue101.game.IGame;
 | 
			
		||||
import inf101.v18.rogue101.objects.IItem;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class Backpack implements IContainer {
 | 
			
		||||
@@ -14,7 +15,7 @@ public class Backpack implements IContainer {
 | 
			
		||||
    /**
 | 
			
		||||
     * The maximum amount of items allowed in a single backpack.
 | 
			
		||||
     */
 | 
			
		||||
    private final int MAX_SIZE = 50;
 | 
			
		||||
    private final int MAX_SIZE = 5;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getCurrentHealth() {
 | 
			
		||||
@@ -54,14 +55,10 @@ public class Backpack implements IContainer {
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the current size of the Backpack.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * @return The size
 | 
			
		||||
     */
 | 
			
		||||
    public int size() {
 | 
			
		||||
        int totalSize = 0;
 | 
			
		||||
        for (IItem item : content) {
 | 
			
		||||
            totalSize += item.getSize();
 | 
			
		||||
        }
 | 
			
		||||
        return totalSize;
 | 
			
		||||
        return content.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -77,7 +74,7 @@ public class Backpack implements IContainer {
 | 
			
		||||
     * Tries to add an item to the Backpack
 | 
			
		||||
     *
 | 
			
		||||
     * @param item  The item to add
 | 
			
		||||
     * @return
 | 
			
		||||
     * @return      True if the item was added. False if the backpack is full
 | 
			
		||||
     */
 | 
			
		||||
    public boolean add(IItem item) {
 | 
			
		||||
        if (size() < MAX_SIZE) {
 | 
			
		||||
@@ -107,13 +104,23 @@ public class Backpack implements IContainer {
 | 
			
		||||
        return content.get(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean addItem(IItem item) {
 | 
			
		||||
        if (content.size() < MAX_SIZE) {
 | 
			
		||||
            content.add(item);
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the content List for direct manipulation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return  A list of T
 | 
			
		||||
     */
 | 
			
		||||
    public List<IItem> getContent() {
 | 
			
		||||
        return content;
 | 
			
		||||
        return Collections.unmodifiableList(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -40,9 +40,14 @@ public class Bow implements IRangedWeapon {
 | 
			
		||||
        return 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getPrintSymbol() {
 | 
			
		||||
        return "\uD83C\uDFF9";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getSymbol() {
 | 
			
		||||
        return "B";
 | 
			
		||||
        return "b";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -4,32 +4,48 @@ import inf101.v18.rogue101.game.IGame;
 | 
			
		||||
import inf101.v18.rogue101.objects.IItem;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class Chest implements IContainer, IStatic {
 | 
			
		||||
    private List<IItem> container;
 | 
			
		||||
    private int MAX_SIZE = 10;
 | 
			
		||||
 | 
			
		||||
    public Chest() {
 | 
			
		||||
        this.container = new ArrayList<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Chest(int lvl) {
 | 
			
		||||
        this.container = new ArrayList<>();
 | 
			
		||||
        fill(lvl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Chest(List<IItem> items) {
 | 
			
		||||
        this.container = items;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Randomly fills chest with random items based on dungeon level.
 | 
			
		||||
     *
 | 
			
		||||
     * @param lvl   The current dungeon level
 | 
			
		||||
     */
 | 
			
		||||
    private void fill (int lvl) {
 | 
			
		||||
        //TODO: Implement
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public IItem get(int i) {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List getContent() {
 | 
			
		||||
        return container;
 | 
			
		||||
    public List<IItem> getContent() {
 | 
			
		||||
        return Collections.unmodifiableList(container);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isFull() {
 | 
			
		||||
        return false;
 | 
			
		||||
        return container.size() >= MAX_SIZE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -47,18 +63,13 @@ public class Chest implements IContainer, IStatic {
 | 
			
		||||
        return "Chest";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInteractMessage() {
 | 
			
		||||
        return "Items in " + getName() + ": ";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getSize() {
 | 
			
		||||
        return 10000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getPrintSymbol() {
 | 
			
		||||
        return "\uD83D\uDDC3";
 | 
			
		||||
        return "\u001b[94m" + "\uD83D\uDDC3" + "\u001b[0m";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -70,4 +81,14 @@ public class Chest implements IContainer, IStatic {
 | 
			
		||||
    public int handleDamage(IGame game, IItem source, int amount) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean addItem(IItem item) {
 | 
			
		||||
        if (container.size() < MAX_SIZE) {
 | 
			
		||||
            container.add(item);
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,14 @@ public interface IContainer extends IItem {
 | 
			
		||||
     */
 | 
			
		||||
    IItem get(int i);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds an item to a container.
 | 
			
		||||
     *
 | 
			
		||||
     * @praram item The item to add to the container
 | 
			
		||||
     * @return True if the container was not full
 | 
			
		||||
     */
 | 
			
		||||
    boolean addItem(IItem item);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a list with everything inside a container.
 | 
			
		||||
     *
 | 
			
		||||
@@ -27,4 +35,13 @@ public interface IContainer extends IItem {
 | 
			
		||||
     * @return  True if it has no space left
 | 
			
		||||
     */
 | 
			
		||||
    boolean isFull();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the message to show the user upon interacting with the container.
 | 
			
		||||
     *
 | 
			
		||||
     * @return  A message
 | 
			
		||||
     */
 | 
			
		||||
    default String getInteractMessage() {
 | 
			
		||||
        return "Items in " + getName() + ": ";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,4 @@ public interface IStatic extends IItem {
 | 
			
		||||
    default int getSize() {
 | 
			
		||||
        return 10000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A message to display when an interaction with the player happens.
 | 
			
		||||
     *
 | 
			
		||||
     * @return  A message
 | 
			
		||||
     */
 | 
			
		||||
    String getInteractMessage();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,11 @@ public class Staff implements IMagicWeapon {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getPrintSymbol() {
 | 
			
		||||
        return "⚚";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getSymbol() {
 | 
			
		||||
        return "s";
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,11 @@ public class Sword implements IMeleeWeapon {
 | 
			
		||||
        return 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getPrintSymbol() {
 | 
			
		||||
        return "⚔";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getSymbol() {
 | 
			
		||||
        return "S";
 | 
			
		||||
 
 | 
			
		||||
@@ -119,7 +119,7 @@ public class GameMap implements IGameMap {
 | 
			
		||||
		try {
 | 
			
		||||
			for (ILocation loc : cells) {
 | 
			
		||||
				List<IItem> list = grid.get(loc);
 | 
			
		||||
				String sym = ".";
 | 
			
		||||
				String sym = " ";
 | 
			
		||||
				if (!list.isEmpty()) {
 | 
			
		||||
					if (Main.MAP_DRAW_ONLY_DIRTY_CELLS) {
 | 
			
		||||
						ctx.clearRect(loc.getX() * w, loc.getY() * h, w, h);
 | 
			
		||||
@@ -132,7 +132,7 @@ public class GameMap implements IGameMap {
 | 
			
		||||
					if (!dontPrint) {
 | 
			
		||||
						sym = list.get(0).getPrintSymbol();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
                }
 | 
			
		||||
				printer.printAt(loc.getX() + 1, loc.getY() + 1, sym);
 | 
			
		||||
			}
 | 
			
		||||
		} finally {
 | 
			
		||||
@@ -144,13 +144,13 @@ public class GameMap implements IGameMap {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Draws only the tiles visible to the player.
 | 
			
		||||
	 * Writes a black void unto the whole map.
 | 
			
		||||
     * Properly draws only the tiles visible to the player.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param painter
 | 
			
		||||
	 * @param printer
 | 
			
		||||
	 * @param game
 | 
			
		||||
	 * @param painter   A painter
 | 
			
		||||
	 * @param printer   A printer
 | 
			
		||||
	 */
 | 
			
		||||
	public void drawVisible(ITurtle painter, Printer printer, IGame game) {
 | 
			
		||||
	public void drawVisible(ITurtle painter, Printer printer) {
 | 
			
		||||
		Iterable<ILocation> cells;
 | 
			
		||||
		if (Main.MAP_DRAW_ONLY_DIRTY_CELLS) {
 | 
			
		||||
			if (dirtyLocs.isEmpty())
 | 
			
		||||
@@ -176,11 +176,15 @@ public class GameMap implements IGameMap {
 | 
			
		||||
			ILocation playerPos = null;
 | 
			
		||||
			for (ILocation loc : cells) {
 | 
			
		||||
				printer.printAt(loc.getX() + 1, loc.getY() + 1, " ");
 | 
			
		||||
                //We need to get the player and its location from somewhere.
 | 
			
		||||
				if (this.hasActors(loc) && this.getActors(loc).get(0) instanceof IPlayer) {
 | 
			
		||||
					player = (IPlayer) this.getActors(loc).get(0);
 | 
			
		||||
					playerPos = loc;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (player == null) {
 | 
			
		||||
			    return;
 | 
			
		||||
            }
 | 
			
		||||
			List<ILocation> positions = getVisible(getNeighbourhood(playerPos,player.getVision()), playerPos);
 | 
			
		||||
			positions.add(playerPos);
 | 
			
		||||
			for (ILocation loc : positions) {
 | 
			
		||||
@@ -351,24 +355,20 @@ public class GameMap implements IGameMap {
 | 
			
		||||
		int startX = loc.getX();
 | 
			
		||||
        int startY = loc.getY();
 | 
			
		||||
		for (int i = 1; i <= dist; i++) {
 | 
			
		||||
			int leftX = startX - i;
 | 
			
		||||
			int rightX = startX + i;
 | 
			
		||||
			int topY = startY - i;
 | 
			
		||||
			int bottomY = startY + i;
 | 
			
		||||
			for (int x = leftX + 1; x < rightX; x++) {
 | 
			
		||||
				if (grid.isValid(x, topY)) {
 | 
			
		||||
					neighbours.add(getLocation(x, topY));
 | 
			
		||||
			for (int x = startX - i + 1; x < startX + i; x++) { //Top and bottom
 | 
			
		||||
				if (grid.isValid(x, startY - i)) {
 | 
			
		||||
					neighbours.add(getLocation(x, startY - i));
 | 
			
		||||
				}
 | 
			
		||||
				if (grid.isValid(x, bottomY)) {
 | 
			
		||||
					neighbours.add(getLocation(x, bottomY));
 | 
			
		||||
				if (grid.isValid(x, startY + i)) {
 | 
			
		||||
					neighbours.add(getLocation(x, startY + i));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			for (int y = topY; y <= bottomY; y++) {
 | 
			
		||||
				if (grid.isValid(leftX, y)) {
 | 
			
		||||
					neighbours.add(getLocation(leftX, y));
 | 
			
		||||
			for (int y = startY - i; y <= startY + i; y++) { //Sides
 | 
			
		||||
				if (grid.isValid(startX - i, y)) {
 | 
			
		||||
					neighbours.add(getLocation(startX - i, y));
 | 
			
		||||
				}
 | 
			
		||||
				if (grid.isValid(rightX, y)) {
 | 
			
		||||
					neighbours.add(getLocation(rightX, y));
 | 
			
		||||
				if (grid.isValid(startX + i, y)) {
 | 
			
		||||
					neighbours.add(getLocation(startX + i, y));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								src/inf101/v18/rogue101/map/maps/gameover.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/inf101/v18/rogue101/map/maps/gameover.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
40 20
 | 
			
		||||
########################################
 | 
			
		||||
#                                      #
 | 
			
		||||
#                                      #
 | 
			
		||||
#                                      #
 | 
			
		||||
#      ####  ####  ##   ##  ####       #
 | 
			
		||||
#      #     #  #  # # # #  #          #
 | 
			
		||||
#      # ##  ####  #  #  #  ####       #
 | 
			
		||||
#      #  #  #  #  #     #  #          #
 | 
			
		||||
#      ####  #  #  #     #  ####       #
 | 
			
		||||
#                                      #
 | 
			
		||||
#                                      #
 | 
			
		||||
#        ####  #  #  ####  ####        #
 | 
			
		||||
#        #  #  #  #  #     #  #        #
 | 
			
		||||
#        #  #  #  #  ####  ####        #
 | 
			
		||||
#        #  #  #  #  #     # #         #
 | 
			
		||||
#        ####   ##   ####  #  #        #
 | 
			
		||||
#                                      #
 | 
			
		||||
#                                      #
 | 
			
		||||
#                                      #
 | 
			
		||||
########################################
 | 
			
		||||
@@ -7,8 +7,8 @@
 | 
			
		||||
#                                      #
 | 
			
		||||
###############       #                #
 | 
			
		||||
#                     #                #
 | 
			
		||||
#      S              #                #
 | 
			
		||||
#                 @   ######## #########
 | 
			
		||||
#      S s            #                #
 | 
			
		||||
#      b          @   ######## #########
 | 
			
		||||
#                     #                #
 | 
			
		||||
#                     #                #
 | 
			
		||||
#                     #                #
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package inf101.v18.rogue101.objects;
 | 
			
		||||
 | 
			
		||||
import inf101.v18.grid.GridDirection;
 | 
			
		||||
import inf101.v18.grid.ILocation;
 | 
			
		||||
import inf101.v18.rogue101.game.Game;
 | 
			
		||||
import inf101.v18.rogue101.game.IGame;
 | 
			
		||||
import inf101.v18.rogue101.items.*;
 | 
			
		||||
import inf101.v18.rogue101.shared.NPC;
 | 
			
		||||
@@ -47,7 +48,10 @@ public class Player implements IPlayer {
 | 
			
		||||
        } else if (key.isDigitKey()) {
 | 
			
		||||
            //Takes care of all digit keys, but we only use the first 5 for picking up and dropping.
 | 
			
		||||
            int keyValue = Integer.parseInt(key.getName());
 | 
			
		||||
            if (keyValue <= 5 && keyValue > 0) {
 | 
			
		||||
            if (keyValue <= 9 && keyValue >= 0) {
 | 
			
		||||
                if (keyValue == 0) {
 | 
			
		||||
                    keyValue = 10;
 | 
			
		||||
                }
 | 
			
		||||
                if (dropping) {
 | 
			
		||||
                    drop(game, keyValue - 1);
 | 
			
		||||
                    dropping = false;
 | 
			
		||||
@@ -70,14 +74,20 @@ public class Player implements IPlayer {
 | 
			
		||||
            if (item == null) {
 | 
			
		||||
                game.displayMessage("You do not have a ranged weapon.");
 | 
			
		||||
            } else {
 | 
			
		||||
                turnConsumed = NPC.tryAttackRanged(game, 3);
 | 
			
		||||
                turnConsumed = rangedAttack(game, 3);
 | 
			
		||||
                if (!turnConsumed) {
 | 
			
		||||
                    game.displayMessage("No enemies within range.");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else if (key == KeyCode.F) {
 | 
			
		||||
            IItem item = getItem(IMagicWeapon.class);
 | 
			
		||||
            if (item == null) {
 | 
			
		||||
                game.displayMessage("You do not have a magic weapon.");
 | 
			
		||||
            } else {
 | 
			
		||||
                turnConsumed = NPC.tryAttackRanged(game, 2);
 | 
			
		||||
                turnConsumed = rangedAttack(game, 2);
 | 
			
		||||
                if (!turnConsumed) {
 | 
			
		||||
                    game.displayMessage("No enemies within range.");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        showStatus(game);
 | 
			
		||||
@@ -136,17 +146,20 @@ public class Player implements IPlayer {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void openChest(IGame game, List<IItem> items) {
 | 
			
		||||
        IStatic item = (IStatic)items.get(0);
 | 
			
		||||
        StringBuilder msg = new StringBuilder(item.getInteractMessage());
 | 
			
		||||
        IContainer container = (IContainer) item;
 | 
			
		||||
        IContainer container = (IContainer) items.get(0);
 | 
			
		||||
        items = container.getContent();
 | 
			
		||||
        for (int i = 0; i < Math.min(items.size(), 5); i++) {
 | 
			
		||||
            msg.append(" [").append(i + 1).append("] ").append(firstCharToUpper(items.get(i).getName()));
 | 
			
		||||
        }
 | 
			
		||||
        game.displayMessage(msg.toString());
 | 
			
		||||
        game.displayMessage(container.getInteractMessage() + niceList(items, 10));
 | 
			
		||||
        exploringChest = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String niceList(List<IItem> list, int max) {
 | 
			
		||||
        StringBuilder msg = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < Math.min(list.size(), max); i++) {
 | 
			
		||||
            msg.append(" [").append(i + 1).append("] ").append(firstCharToUpper(list.get(i).getName()));
 | 
			
		||||
        }
 | 
			
		||||
        return msg.toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialized the dropping of an item, and does what is needed.
 | 
			
		||||
     *
 | 
			
		||||
@@ -154,10 +167,10 @@ public class Player implements IPlayer {
 | 
			
		||||
     * @return      True if a turn was consumed. False otherwise
 | 
			
		||||
     */
 | 
			
		||||
    private boolean dropInit(IGame game) {
 | 
			
		||||
        if (equipped.getContent().size() == 1) {
 | 
			
		||||
        if (equipped.size() == 1) {
 | 
			
		||||
            drop(game, 0);
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if (equipped.getContent().size() < 1) {
 | 
			
		||||
        } else if (equipped.size() < 1) {
 | 
			
		||||
            game.displayMessage("You have nothing to drop");
 | 
			
		||||
        } else {
 | 
			
		||||
            StringBuilder msg = new StringBuilder("Items to drop:");
 | 
			
		||||
@@ -200,10 +213,8 @@ public class Player implements IPlayer {
 | 
			
		||||
     */
 | 
			
		||||
    private void loot(IGame game, int i) {
 | 
			
		||||
        if (!equipped.isFull()) {
 | 
			
		||||
            List<IItem> items = game.getLocalItems();
 | 
			
		||||
            IItem item = items.get(0);
 | 
			
		||||
            if (item instanceof IStatic && item instanceof IContainer) {
 | 
			
		||||
                IContainer container = (IContainer) item;
 | 
			
		||||
            IContainer container = getStaticContainer(game);
 | 
			
		||||
            if (container != null && i < container.getContent().size()) {
 | 
			
		||||
                IItem loot = container.getContent().get(i);
 | 
			
		||||
                equipped.add(loot);
 | 
			
		||||
                container.getContent().remove(i);
 | 
			
		||||
@@ -216,6 +227,19 @@ public class Player implements IPlayer {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private IContainer getStaticContainer(IGame game) {
 | 
			
		||||
        List<IItem> items = game.getLocalItems();
 | 
			
		||||
        if (items.size() < 1) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        IItem item = items.get(0);
 | 
			
		||||
        if (item instanceof IStatic && item instanceof IContainer) {
 | 
			
		||||
            return (IContainer) item;
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Drops an item at index i.
 | 
			
		||||
     *
 | 
			
		||||
@@ -224,6 +248,17 @@ public class Player implements IPlayer {
 | 
			
		||||
     */
 | 
			
		||||
    private void drop(IGame game, int i) {
 | 
			
		||||
        if (!equipped.isEmpty() && equipped.size() > i) {
 | 
			
		||||
            IContainer container = getStaticContainer(game);
 | 
			
		||||
            if (container != null) {
 | 
			
		||||
                if (container.addItem(equipped.get(i))) {
 | 
			
		||||
                    equipped.remove(i);
 | 
			
		||||
                    game.displayMessage("Item stored in container.");
 | 
			
		||||
                    return;
 | 
			
		||||
                } else {
 | 
			
		||||
                    game.displayMessage(container.getName() + " is full.");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (game.drop(equipped.get(i))) {
 | 
			
		||||
                equipped.remove(i);
 | 
			
		||||
                game.displayMessage("Item dropped.");
 | 
			
		||||
@@ -348,4 +383,22 @@ public class Player implements IPlayer {
 | 
			
		||||
        //TODO: Increase vision based on equipped items
 | 
			
		||||
        return 3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean rangedAttack(IGame game, int range) {
 | 
			
		||||
        List<ILocation> neighbours = game.getVisible();
 | 
			
		||||
        for (ILocation neighbour : neighbours) {
 | 
			
		||||
            if (game.getMap().hasActors(neighbour)) {
 | 
			
		||||
                ILocation current = game.getLocation();
 | 
			
		||||
                List<GridDirection> dirs = game.locationDirection(current, neighbour);
 | 
			
		||||
                IActor actor = game.getMap().getActors(neighbour).get(0); //We assume there is only one actor.
 | 
			
		||||
                if (actor instanceof INonPlayer && current.gridDistanceTo(neighbour) <= range) {
 | 
			
		||||
                    for (GridDirection dir : dirs) {
 | 
			
		||||
                        game.rangedAttack(dir, actor);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,13 @@ package inf101.v18.rogue101.shared;
 | 
			
		||||
 | 
			
		||||
import inf101.v18.grid.GridDirection;
 | 
			
		||||
import inf101.v18.grid.ILocation;
 | 
			
		||||
import inf101.v18.rogue101.enemies.Girl;
 | 
			
		||||
import inf101.v18.rogue101.game.IGame;
 | 
			
		||||
import inf101.v18.rogue101.map.IGameMap;
 | 
			
		||||
import inf101.v18.rogue101.map.IMapView;
 | 
			
		||||
import inf101.v18.rogue101.objects.IActor;
 | 
			
		||||
import inf101.v18.rogue101.objects.IItem;
 | 
			
		||||
import inf101.v18.rogue101.states.Occupation;
 | 
			
		||||
import inf101.v18.rogue101.objects.INonPlayer;
 | 
			
		||||
import inf101.v18.rogue101.objects.IPlayer;
 | 
			
		||||
import javafx.scene.media.Media;
 | 
			
		||||
import javafx.scene.media.MediaPlayer;
 | 
			
		||||
 | 
			
		||||
@@ -18,52 +20,40 @@ import java.util.List;
 | 
			
		||||
 */
 | 
			
		||||
public class NPC {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes a NPC attack anything it can, or move closer to any enemy in its line of sight.
 | 
			
		||||
     *
 | 
			
		||||
     * @param game  An IGame object
 | 
			
		||||
     * @return      True if the NPC made a move. False otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean tryAttack(IGame game) {
 | 
			
		||||
        List<ILocation> neighbours = game.getVisible();
 | 
			
		||||
        for (ILocation neighbour : neighbours) {
 | 
			
		||||
            if (game.getMap().hasActors(neighbour)) {
 | 
			
		||||
                ILocation current = game.getLocation();
 | 
			
		||||
                GridDirection dir = game.locationDirection(current, neighbour);
 | 
			
		||||
                IActor actor = game.getMap().getActors(neighbour).get(0); //We assume there is only one actor.
 | 
			
		||||
                if (current.gridDistanceTo(neighbour) <= 1 && current.canGo(dir) && game.getMap().has(current.go(dir), actor) && !actor.isDestroyed()) {
 | 
			
		||||
                    game.attack(dir, actor);
 | 
			
		||||
                    return true;
 | 
			
		||||
                } else if (game.canGo(dir)) {
 | 
			
		||||
                    game.move(dir);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    private NPC() {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs a ranged attack on the closest actor (if any) observable by the current actor.
 | 
			
		||||
     * Performs a ranged attack on the closest actor (if any) observable by the current actor if range is > 1.
 | 
			
		||||
     * Performs a melee attack on an actor (if any) on a neighbouring tile if range == 1.
 | 
			
		||||
     * Moves closer to an enemy if an attack is not possible.
 | 
			
		||||
     *
 | 
			
		||||
     * @param game      An IGame object
 | 
			
		||||
     * @param range     The range of the equipped weapon
 | 
			
		||||
     * @return          True if an attack or a move towards an enemy was successful. False otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean tryAttackRanged(IGame game, int range) {
 | 
			
		||||
        // Ranged attacks don't care about walls.
 | 
			
		||||
        List<ILocation> neighbours = game.getMap().getNeighbourhood(game.getLocation(), game.getActor().getVision());
 | 
			
		||||
    public static boolean tryAttack(IGame game, int range) {
 | 
			
		||||
        List<ILocation> neighbours = game.getVisible();
 | 
			
		||||
        for (ILocation neighbour : neighbours) {
 | 
			
		||||
            if (game.getMap().hasActors(neighbour)) {
 | 
			
		||||
            IMapView map = game.getMap();
 | 
			
		||||
            if (map.hasActors(neighbour) && map.getActors(neighbour).get(0) instanceof IPlayer) {
 | 
			
		||||
                ILocation current = game.getLocation();
 | 
			
		||||
                GridDirection dir = game.locationDirection(current, neighbour);
 | 
			
		||||
                List<GridDirection> dirs = game.locationDirection(current, neighbour);
 | 
			
		||||
                IActor actor = game.getMap().getActors(neighbour).get(0); //We assume there is only one actor.
 | 
			
		||||
                if (current.gridDistanceTo(neighbour) <= range && !actor.isDestroyed()) {
 | 
			
		||||
                    game.rangedAttack(dir, actor);
 | 
			
		||||
                    return true;
 | 
			
		||||
                } else if (game.canGo(dir)) {
 | 
			
		||||
                    game.move(dir);
 | 
			
		||||
                    return true;
 | 
			
		||||
                for (GridDirection dir : dirs) {
 | 
			
		||||
                    if (range == 1 && current.gridDistanceTo(neighbour) <= 1 && current.canGo(dir) && game.getMap().has(current.go(dir), actor)) {
 | 
			
		||||
                        game.attack(dir, actor);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (range > 1 && current.gridDistanceTo(neighbour) <= range) {
 | 
			
		||||
                        game.rangedAttack(dir, actor);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                for (GridDirection dir : dirs) {
 | 
			
		||||
                    if (game.canGo(dir)) {
 | 
			
		||||
                        game.move(dir);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -80,22 +70,20 @@ public class NPC {
 | 
			
		||||
    public static boolean trackItem(IGame game, List<Class<?>> validItems) {
 | 
			
		||||
        List<ILocation> neighbours = game.getVisible();
 | 
			
		||||
        for (ILocation neighbour : neighbours) {
 | 
			
		||||
            boolean hasItem = false;
 | 
			
		||||
            for (IItem item : game.getMap().getAll(neighbour)) {
 | 
			
		||||
                for (Class<?> validItem : validItems) {
 | 
			
		||||
                    if (validItem.isInstance(item)) {
 | 
			
		||||
                        hasItem = true;
 | 
			
		||||
                        ILocation current = game.getLocation();
 | 
			
		||||
                        List<GridDirection> dirs = game.locationDirection(current, neighbour);
 | 
			
		||||
                        for (GridDirection dir : dirs) {
 | 
			
		||||
                            if (game.canGo(dir)) {
 | 
			
		||||
                                game.move(dir);
 | 
			
		||||
                                return true;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (hasItem) {
 | 
			
		||||
                ILocation current = game.getLocation();
 | 
			
		||||
                GridDirection dir = game.locationDirection(current, neighbour);
 | 
			
		||||
                if (game.canGo(dir)) {
 | 
			
		||||
                    game.move(dir);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -130,10 +118,12 @@ public class NPC {
 | 
			
		||||
        for (ILocation neighbour : neighbours) {
 | 
			
		||||
            if (game.getMap().hasActors(neighbour)) {
 | 
			
		||||
                ILocation current = game.getLocation();
 | 
			
		||||
                GridDirection dir = reverseDir(game.locationDirection(current, neighbour));
 | 
			
		||||
                if (game.canGo(dir)) {
 | 
			
		||||
                    game.move(dir);
 | 
			
		||||
                    return true;
 | 
			
		||||
                List<GridDirection> dirs = reverseDir(game.locationDirection(current, neighbour));
 | 
			
		||||
                for (GridDirection dir : dirs) {
 | 
			
		||||
                    if (game.canGo(dir)) {
 | 
			
		||||
                        game.move(dir);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -141,21 +131,25 @@ public class NPC {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverses the main four directions.
 | 
			
		||||
     * Reverses a list of directions.
 | 
			
		||||
     *
 | 
			
		||||
     * @param dir   A direction
 | 
			
		||||
     * @return      An opposite direction
 | 
			
		||||
     * @param dirs  A list directions
 | 
			
		||||
     * @return      A list of the opposite directions
 | 
			
		||||
     */
 | 
			
		||||
    private static GridDirection reverseDir(GridDirection dir) {
 | 
			
		||||
        if (dir == GridDirection.SOUTH)  {
 | 
			
		||||
            return GridDirection.NORTH;
 | 
			
		||||
        } else if (dir == GridDirection.NORTH) {
 | 
			
		||||
           return GridDirection.SOUTH;
 | 
			
		||||
        } else if (dir == GridDirection.WEST) {
 | 
			
		||||
            return GridDirection.EAST;
 | 
			
		||||
        } else {
 | 
			
		||||
            return GridDirection.WEST;
 | 
			
		||||
    private static List<GridDirection> reverseDir(List<GridDirection> dirs) {
 | 
			
		||||
        for (int i = 0; i < dirs.size(); i++) {
 | 
			
		||||
            GridDirection dir = dirs.get(i);
 | 
			
		||||
            if (dir == GridDirection.SOUTH) {
 | 
			
		||||
                dirs.set(i, GridDirection.NORTH);
 | 
			
		||||
            } else if (dir == GridDirection.NORTH) {
 | 
			
		||||
                dirs.set(i, GridDirection.SOUTH);
 | 
			
		||||
            } else if (dir == GridDirection.WEST) {
 | 
			
		||||
                dirs.set(i, GridDirection.EAST);
 | 
			
		||||
            } else {
 | 
			
		||||
                dirs.set(i, GridDirection.WEST);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return dirs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user