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:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user