Adds item storage and more NPC behavior
Makes NPC look for and pick up items of specified types. Adds a Backpack and IContainer interface. Lets items use separate sounds. Not completed.
This commit is contained in:
parent
d1b4f4a316
commit
7d0f0dc4f8
@ -2,6 +2,7 @@ package inf101.v18.rogue101.enemies;
|
||||
|
||||
import inf101.v18.grid.GridDirection;
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.items.*;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
import inf101.v18.rogue101.objects.INonPlayer;
|
||||
import inf101.v18.rogue101.shared.NPC;
|
||||
@ -9,6 +10,7 @@ import inf101.v18.rogue101.states.Age;
|
||||
import inf101.v18.rogue101.states.Occupation;
|
||||
import inf101.v18.rogue101.states.Personality;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
@ -23,11 +25,13 @@ public class Girl implements INonPlayer {
|
||||
private int attack;
|
||||
private int defence;
|
||||
private int visibility;
|
||||
private IItem equipped;
|
||||
private Backpack<IItem> backpack = new Backpack<>();
|
||||
private static final Random random = new Random();
|
||||
private List<Class<?>> validItems;
|
||||
|
||||
public Girl() {
|
||||
setStats();
|
||||
setValidItems();
|
||||
}
|
||||
|
||||
private void setStats() {
|
||||
@ -63,7 +67,7 @@ public class Girl implements INonPlayer {
|
||||
visibility = 2;
|
||||
break;
|
||||
}
|
||||
if (occupation == Occupation.MAGE) {
|
||||
if (occupation == Occupation.KNIGHT) {
|
||||
attack += 10; //Knights are quite powerful.
|
||||
}
|
||||
if (occupation == Occupation.MAGE) {
|
||||
@ -75,6 +79,24 @@ public class Girl implements INonPlayer {
|
||||
defence += (int)(random.nextGaussian() * 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specified which items the current Girl should be able to pick up.
|
||||
*/
|
||||
private void setValidItems() {
|
||||
validItems = new ArrayList<>();
|
||||
switch (occupation) {
|
||||
case BOWSMAN:
|
||||
validItems.add(IRangedWeapon.class);
|
||||
break;
|
||||
case MAGE:
|
||||
validItems.add(IMagicWeapon.class);
|
||||
break;
|
||||
case KNIGHT:
|
||||
validItems.add(IMeleeWeapon.class);
|
||||
}
|
||||
validItems.add(IBuffItem.class);
|
||||
}
|
||||
|
||||
private String randomName() {
|
||||
//TODO: Choose from a list of names, or generate name.
|
||||
return "Girl";
|
||||
@ -82,44 +104,23 @@ public class Girl implements INonPlayer {
|
||||
|
||||
@Override
|
||||
public void doTurn(IGame game) {
|
||||
if (equipped == null) {
|
||||
//TODO: Check if there is a item on the ground to pick up.
|
||||
if (!backpack.isFull()) {
|
||||
IItem item = NPC.pickUp(game, validItems);
|
||||
if (item != null) {
|
||||
backpack.add(item);
|
||||
return;
|
||||
}
|
||||
if (NPC.trackItem(game, validItems)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
boolean attack = false;
|
||||
switch (personality) {
|
||||
case CALM:
|
||||
if (hp < maxhp) {
|
||||
attack = true;
|
||||
}
|
||||
break;
|
||||
case AFRAID:
|
||||
if (NPC.flee(game)) {
|
||||
return;
|
||||
} else {
|
||||
attack = true;
|
||||
}
|
||||
break;
|
||||
case AGRESSIVE:
|
||||
attack = true;
|
||||
break;
|
||||
if (personality == Personality.AFRAID && NPC.flee(game)) {
|
||||
return;
|
||||
}
|
||||
if (attack) {
|
||||
switch (occupation) {
|
||||
case KNIGHT:
|
||||
if (NPC.tryAttack(game)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MAGE:
|
||||
if (NPC.tryAttackRanged(game, 2)) {
|
||||
return;
|
||||
}
|
||||
case BOWSMAN:
|
||||
if (NPC.tryAttackRanged(game, 4)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (willAttack(game) && attack(game)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<GridDirection> possibleMoves = game.getPossibleMoves();
|
||||
@ -129,6 +130,62 @@ public class Girl implements INonPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to attack with an attack specified by the Girl's occupation
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @return True if an attack occurred. False otherwise
|
||||
*/
|
||||
private boolean attack(IGame game) {
|
||||
switch (occupation) {
|
||||
case KNIGHT:
|
||||
if (NPC.tryAttack(game)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case MAGE:
|
||||
if (NPC.tryAttackRanged(game, 2)) {
|
||||
return true;
|
||||
}
|
||||
case BOWSMAN:
|
||||
if (NPC.tryAttackRanged(game, 4)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current girl will try to attack.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @return True if the girl will attack. False otherwise
|
||||
*/
|
||||
private boolean willAttack(IGame game) {
|
||||
boolean attack = false;
|
||||
switch (personality) {
|
||||
case CALM:
|
||||
if (hp < maxhp) {
|
||||
attack = true;
|
||||
}
|
||||
break;
|
||||
case AFRAID:
|
||||
if (game.getPossibleMoves().isEmpty()) {
|
||||
attack = true;
|
||||
}
|
||||
break;
|
||||
case AGRESSIVE:
|
||||
attack = true;
|
||||
break;
|
||||
}
|
||||
return attack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a girl's occupation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Occupation getOccupation() {
|
||||
return occupation;
|
||||
}
|
||||
@ -165,7 +222,7 @@ public class Girl implements INonPlayer {
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 8;
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
package inf101.v18.rogue101.examples;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -13,6 +14,10 @@ import inf101.v18.rogue101.shared.NPC;
|
||||
public class Rabbit implements INonPlayer {
|
||||
private int food = 0;
|
||||
private int hp = getMaxHealth();
|
||||
private static List<Class<?>> validItems = new ArrayList<>();
|
||||
static {
|
||||
validItems.add(Carrot.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doTurn(IGame game) {
|
||||
@ -42,7 +47,7 @@ public class Rabbit implements INonPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
if (NPC.trackItem(game, Carrot.class)) {
|
||||
if (NPC.trackItem(game, validItems)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import inf101.v18.rogue101.enemies.Girl;
|
||||
import inf101.v18.rogue101.examples.Carrot;
|
||||
import inf101.v18.rogue101.items.Manga;
|
||||
import inf101.v18.rogue101.examples.Rabbit;
|
||||
import inf101.v18.rogue101.items.Sword;
|
||||
import inf101.v18.rogue101.map.GameMap;
|
||||
import inf101.v18.rogue101.map.IGameMap;
|
||||
import inf101.v18.rogue101.map.IMapView;
|
||||
@ -124,8 +125,10 @@ public class Game implements IGame {
|
||||
if (!map.has(loc, target)) {
|
||||
throw new IllegalMoveException("Target isn't there!");
|
||||
}
|
||||
//TODO: Add attack and defence power when appropriate items are equipped.
|
||||
int damage = currentActor.getAttack() + random.nextInt(20) + 1;
|
||||
if (damage >= target.getDefence() + 10) {
|
||||
int defence = target.getDefence() + 10;
|
||||
if (damage >= defence) {
|
||||
int actualDamage = target.handleDamage(this, target, damage);
|
||||
formatMessage("%s hits %s for %d damage", currentActor.getName(), target.getName(), actualDamage);
|
||||
} else {
|
||||
@ -268,6 +271,7 @@ public class Game implements IGame {
|
||||
itemFactories.put("M", Manga::new);
|
||||
itemFactories.put("G", Girl::new);
|
||||
itemFactories.put(".", Dust::new);
|
||||
itemFactories.put("S", Sword::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
129
src/inf101/v18/rogue101/items/Backpack.java
Normal file
129
src/inf101/v18/rogue101/items/Backpack.java
Normal file
@ -0,0 +1,129 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Backpack<T extends IItem> implements IContainer {
|
||||
/**
|
||||
* A list containing everything in the backpack.
|
||||
*/
|
||||
private List<T> content = new ArrayList<>();
|
||||
/**
|
||||
* The maximum amount of items allowed in a single backpack.
|
||||
*/
|
||||
private final int MAX_SIZE = 5;
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Backpack";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "B";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current size of the Backpack.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int size() {
|
||||
return content.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the Backpack is empty
|
||||
*
|
||||
* @return True if empty. False otherwise
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return content.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to add an item to the Backpack
|
||||
*
|
||||
* @param item The item to add
|
||||
* @return
|
||||
*/
|
||||
public boolean add(T item) {
|
||||
if (content.size() < MAX_SIZE) {
|
||||
content.add(item);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element at index i
|
||||
*
|
||||
* @param i The index of an element
|
||||
*/
|
||||
public void remove(int i) {
|
||||
content.remove(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a T at index i,
|
||||
*
|
||||
* @param i The index of an element
|
||||
* @return An object of type T
|
||||
*/
|
||||
public T get(int i) {
|
||||
return content.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content List for direct manipulation.
|
||||
*
|
||||
* @return A list of T
|
||||
*/
|
||||
public List<T> getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFull() {
|
||||
if (content.size() >= MAX_SIZE) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//This shows as an error, but is necessary to compile.
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
return compareTo((IItem)o);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
interface IBuffItem extends IItem {
|
||||
public interface IBuffItem extends IItem {
|
||||
/**
|
||||
* Retrieve damage increase done by the buff item.
|
||||
*
|
||||
|
38
src/inf101/v18/rogue101/items/IContainer.java
Normal file
38
src/inf101/v18/rogue101/items/IContainer.java
Normal file
@ -0,0 +1,38 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A container for storing anything extending IItem.
|
||||
*
|
||||
* @param <T> The item type to store
|
||||
*/
|
||||
public interface IContainer<T extends IItem> extends IItem {
|
||||
/**
|
||||
* Retrieves an item from a container in index i
|
||||
*
|
||||
* @param i The index of an element
|
||||
* @return An IItem
|
||||
* @throws IndexOutOfBoundsException If the index is out of range.
|
||||
*/
|
||||
IItem get(int i);
|
||||
|
||||
/**
|
||||
* Gets a list with everything inside a container.
|
||||
*
|
||||
* @return A list of Objects extending IItem
|
||||
*/
|
||||
List<T> getContent();
|
||||
|
||||
/**
|
||||
* Checks if we can add anything at all to the container.
|
||||
*
|
||||
* @return True if it has no space left
|
||||
*/
|
||||
boolean isFull();
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
/**
|
||||
* An interface to extinguish different weapons for specific NPC.
|
||||
*/
|
||||
public interface IMagicWeapon extends IWeapon {
|
||||
|
||||
interface IMagicWeapon extends IItem {
|
||||
/**
|
||||
* Retrieves the damage points of a weapon.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getWeaponDamage();
|
||||
@Override
|
||||
default String getSound() {
|
||||
return "audio/Bow_Fire_Arrow-Stephan_Schutze-2133929391.wav";
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
/**
|
||||
* An interface to extinguish different weapons for specific NPC.
|
||||
*/
|
||||
public interface IMeleeWeapon extends IWeapon {
|
||||
|
||||
interface IMeleeWeapon extends IItem {
|
||||
/**
|
||||
* Retrieves the damage points of a weapon.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getWeaponDamage();
|
||||
@Override
|
||||
default String getSound() {
|
||||
return "audio/Sword Swing-SoundBible.com-639083727.wav";
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
/**
|
||||
* An interface to extinguish different weapons for specific NPC.
|
||||
*/
|
||||
public interface IRangedWeapon extends IWeapon {
|
||||
|
||||
interface IRangedWeapon extends IItem {
|
||||
/**
|
||||
* Retrieves the damage points of a weapon.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getWeaponDamage();
|
||||
@Override
|
||||
default String getSound() {
|
||||
return "audio/Bow_Fire_Arrow-Stephan_Schutze-2133929391.wav";
|
||||
}
|
||||
}
|
||||
|
19
src/inf101/v18/rogue101/items/IWeapon.java
Normal file
19
src/inf101/v18/rogue101/items/IWeapon.java
Normal file
@ -0,0 +1,19 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
public interface IWeapon extends IItem {
|
||||
/**
|
||||
* Retrieves the damage points of a weapon.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getWeaponDamage();
|
||||
|
||||
/**
|
||||
* Retrieves the string path of the sound to play upon an attack.
|
||||
*
|
||||
* @return A string path
|
||||
*/
|
||||
String getSound();
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
# #
|
||||
############### # #
|
||||
# # #
|
||||
# # #
|
||||
# S # #
|
||||
# @ ####################### #
|
||||
# # #
|
||||
# # #
|
||||
|
@ -3,6 +3,7 @@ package inf101.v18.rogue101.objects;
|
||||
import inf101.v18.grid.GridDirection;
|
||||
import inf101.v18.grid.ILocation;
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.items.Backpack;
|
||||
import inf101.v18.rogue101.shared.NPC;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import java.util.ArrayList;
|
||||
@ -10,7 +11,7 @@ import java.util.List;
|
||||
|
||||
public class Player implements IPlayer {
|
||||
private int hp = getMaxHealth();
|
||||
private final List<IItem> equipped = new ArrayList<>();
|
||||
private final Backpack<IItem> equipped = new Backpack<>();
|
||||
|
||||
@Override
|
||||
public void keyPressed(IGame game, KeyCode key) {
|
||||
@ -82,7 +83,7 @@ public class Player implements IPlayer {
|
||||
|
||||
private void showStatus(IGame game) {
|
||||
List<String> items = new ArrayList<>();
|
||||
for (IItem item : equipped) {
|
||||
for (IItem item : equipped.getContent()) {
|
||||
String name = item.getName();
|
||||
items.add(Character.toUpperCase(name.charAt(0)) + name.substring(1));
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ 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.examples.Carrot;
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.objects.IActor;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
@ -13,6 +14,9 @@ import javafx.scene.media.MediaPlayer;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A holder class for methods used by IActors.
|
||||
*/
|
||||
public class NPC {
|
||||
|
||||
/**
|
||||
@ -79,17 +83,19 @@ public class NPC {
|
||||
/**
|
||||
* Tries to find and reach an item of a specified class.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @param element The class of the objects we are looking for
|
||||
* @return True if an appropriate item was found in the range of the current actor. False otherwise.
|
||||
* @param game An IGame object
|
||||
* @param validItems A list of classes the NPC should look for
|
||||
* @return True if an appropriate item was found in the range of the current actor. False otherwise.
|
||||
*/
|
||||
public static boolean trackItem(IGame game, Class<?> element) {
|
||||
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)) {
|
||||
if (element.isInstance(item)) {
|
||||
hasItem = true;
|
||||
for (Class<?> validItem : validItems) {
|
||||
if (validItem.isInstance(item)) {
|
||||
hasItem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasItem) {
|
||||
@ -104,6 +110,31 @@ public class NPC {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks up an item of one of the specified class types.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @param validItems A list of classes the NPC should accept
|
||||
* @return An item if it was successfully picked up. Null otherwise
|
||||
*/
|
||||
public static IItem pickUp(IGame game, List<Class<?>> validItems) {
|
||||
for (IItem item : game.getLocalItems()) {
|
||||
for (Class<?> validItem : validItems) {
|
||||
if (validItem.isInstance(item)) {
|
||||
return game.pickUp(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an IActor go to the opposite direction of the closest enemy.
|
||||
* Will return false if there are no visible enemies.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @return True if the IActor fled. False otherwise
|
||||
*/
|
||||
public static boolean flee(IGame game) {
|
||||
List<ILocation> neighbours = game.getVisible();
|
||||
for (ILocation neighbour : neighbours) {
|
||||
@ -119,6 +150,12 @@ public class NPC {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the main four directions.
|
||||
*
|
||||
* @param dir A direction
|
||||
* @return An opposite direction
|
||||
*/
|
||||
private static GridDirection reverseDir(GridDirection dir) {
|
||||
if (dir == GridDirection.SOUTH) {
|
||||
return GridDirection.NORTH;
|
||||
@ -131,6 +168,11 @@ public class NPC {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays a sound.
|
||||
*
|
||||
* @param filename The String path of the audio file to play
|
||||
*/
|
||||
public static void playSound(String filename) {
|
||||
Media sound = new Media(new File(filename).toURI().toString());
|
||||
MediaPlayer mediaPlayer = new MediaPlayer(sound);
|
||||
|
Loading…
Reference in New Issue
Block a user