Merge branch 'master' of https://retting.ii.uib.no/kkn015/inf101.v18.sem1 into kkn015
This commit is contained in:
commit
3c5b291c26
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
/bin/
|
||||
.DS_Store
|
||||
*.xml
|
||||
*.iml
|
59
README.md
59
README.md
@ -23,21 +23,66 @@ Dette prosjektet inneholder [Semesteroppgave 1](SEM-1.md). Du kan også [lese op
|
||||
|
||||
|
||||
# Fyll inn egne svar/beskrivelse/kommentarer til prosjektet under
|
||||
* Levert av: *NAVN* (*BRUKERNAVN*)
|
||||
* Del A: [ ] helt ferdig, [ ] delvis ferdig
|
||||
* Del B: [ ] helt ferdig, [ ] delvis ferdig
|
||||
* Del C: [ ] helt ferdig, [ ] delvis ferdig
|
||||
* Levert av: *Kristian Knarvik* (*kkn015*)
|
||||
* Del A: [x] helt ferdig, [ ] delvis ferdig
|
||||
* Del B: [ ] helt ferdig, [x] delvis ferdig
|
||||
* Del C: [ ] helt ferdig, [X] delvis ferdig
|
||||
* [ ] hele semesteroppgaven er ferdig og klar til retting!
|
||||
|
||||
# Del A
|
||||
## Svar på spørsmål
|
||||
* ...
|
||||
a)
|
||||
* IGame trenger et game map (IMapView) der ting kan plasseres. Den trenger også en referanse til brukergrensesnittet for å endre tekst og grafikk. Den trenger en TurtlePainter for å tegne grafikk. Den trenger en referanse til et Printer objekt til å (antagelig) printe fancy tekst.
|
||||
* IMapView må ha en referanse til et objekt som implementerer IArea.
|
||||
* Et IItem må ha et navn, en int som representerer hp, en annen int som representerer maksimal hp, en int som representerer størrelsen, og en int som representerer forsvar. Den må også ha et symbol som representerer en ting når den blir tegnet.
|
||||
* En IActor er lik et IItem, men har i tillegg to int som representerer angrepsstyrke mot et IItem og en IIactor. Den kunne lagret en posisjon, men om det er en fordel spørs på implementasjonen av utførelsen av en tur.
|
||||
* En INonPlayer ser ut til å være lik en IActor, men kan flytte seg selv.
|
||||
* En IPlayer ser ut til å være lik en IActor, men kan gjøre mye rart ut ifra hvilken tast spilleren trykker.
|
||||
|
||||
b)
|
||||
* IGame ser ut til å være på toppen, og behandler IMapView. IMapView holder styr på områder IArea. Hvert IArea holder styr på alle IItem (som også inneholder alt som utvider IItem). Noen typer IItem er av type IActor. Alle IActor er enten av type IPlayer eller INonPlayer. IPlayer og INonPlayer kan forsåvidt direkte manipulere IGame, så alt går egentlig litt i ring.
|
||||
|
||||
c)
|
||||
* Jeg tror splittingen av IGameMap og IMapView er for å lettere kunne lage tester. IGameMap trenger en TurtlePainter, og da også en GUI. GUI er ikke særlig kompetibelt med tester. Den eneste andre logiske grunnen vil være for å kunne bruke IMapView til andre formål. For eksempel å simulere et kart med bare INonPlayer, gi dem lov til å drepe hverandre, og se hva som skjer etter 10000 steg.
|
||||
|
||||
d)
|
||||
* Jeg tror INonPlayer og IPlayer er forskjellige for å ikke blande dem når en skal sjekke om hvem som kan flyttes hvor, og hvem som kan angripe hvem. De kunne alltids hatt en boolean player (dersom fiender ikke skal begynne å angripe hverandre) og en metode som tok inn game, og en annen som tok inn game og keypress. Det er litt teit å ha en boolean som er lik for alle objekter bortsett fra en. En fordel med å splitte dem opp, er at jeg enkelt kan lage en IImmovablePlayer som kan overskrive metoden som angriper den til at han/hun åpner butikken sin, eller gir meg et quest.
|
||||
|
||||
e)
|
||||
* Det var uforventa at nesten alle tilstandsverdier ble hardkodet i stedet for å lagres i en variabel. Det gir mening når alle objekter er helt identiske (til å begynne med). Fordelen er at ting kan ha ganske unike implementeringer, men det virker litt "skittent".
|
||||
|
||||
f)
|
||||
* Rabbit finner ut hvor den er ved å bruke Game sin getLocation(). Rabbit finner ut hvilke andre ting som er på stedet ved å bruke game sin getLocalItems(). Rabbit finner ut hvor den har lov å gå ved å bruke game sin canGo() (senere kan getPossibleMoves() hjelpe til).
|
||||
|
||||
g)
|
||||
* GetLocation blir brukt når Game utfører turns. Game henter hvert objekt IActor og henter med en gang posisjonen fra Gamemap sin getLocation som henter verdien fra en hashmap. Jeg har aldri vært borti hashmaps i java, men det virker ekvivalent med måten Arrays virker i php. For eksempel: $items = array(rabbit1 => pos1). Når en da henter $items[rabbit1], vil en få pos1.
|
||||
|
||||
# Del B
|
||||
## Svar på spørsmål
|
||||
* ...
|
||||
a)
|
||||
* Nabo-celler blir behandlet en del annerledes, siden det skal være mulig å finne celler en viss avstand fra et punkt. I tillegg til at alle celler som er utenfor skal ignoreres, og være sortert. Det blir håndtert med en tilsynelatende ganske "skitten" metode, men den fungerer fint.
|
||||
Måten å gjøre det på i Sem1 er mer praktisk, fordi det tillater å velge hvilket som helst størrelse på nabolaget.
|
||||
|
||||
b)
|
||||
* De fleste spill-trekkene går igjennom game for å enkelt kunne utføre turen til alle objekter.
|
||||
Fordelene er at det er lett å få tak i all nødvendig informasjon, uten å måtte lage spesialiserte metoder, eller sende inn mange parametere.
|
||||
Ulempene er at alle IActors og IItem blir veldig sterkt knyttet til IGame. De kan ikke brukes uten å spesifikt opprette et objekt som implementerer IGame først, som forhinder dem i å bli brukt i hvilket som helst annet prosjekt.
|
||||
|
||||
c)
|
||||
* Game.addItem burde strengt tatt sjekket at en IActor ikke blir plassert på en IActor.
|
||||
|
||||
d)
|
||||
* Strukturen er definitivt mye mer kaotisk enn jeg først hadde trodd. Det er egentlig ganske vanskelig å finne det en er ute etter. I tillegg har jeg endret en del, som igjen endrer oppførselen til noen av de gamle klassene.
|
||||
|
||||
# Del C
|
||||
## Oversikt over designvalg og hva du har gjort
|
||||
* ... blah, blah, er implementert i klassen [KurtMario](src/inf101/v18/rogue101/player/KurtMario.java), blah, blah `ITurtleShell` ...
|
||||
* Oversikt over taster: WASD og piltaster kan brukes til bevegelse. Q for å legge ned ting. E for å plukke opp ting. 1-5 for å velge hvilke ting du ønsker å legge ned eller plukke opp.
|
||||
* Main og Game har blitt endret til å tillate spilleren å selv velge når den har utført en tur. Dette har blitt gjort for å kunne ignorere uønskede tastetrykk, og for å tilby spilleren valg.
|
||||
|
||||
### Tredjepartsfiler
|
||||
* Bow Fire Arrow Sound (http://soundbible.com, Stephan Schutze, Noncommercial 3.0)
|
||||
* Sword Swing Sound (http://soundbible.com, Mike Koenig, Attribution 3.0)
|
||||
* Large Fireball Sound (http://soundbible.com, Mike Koenig, Attribution 3.0)
|
||||
* Realistic Punch Sound (http://soundbible.com, Mark DiAngelo, Attribution 3.0)
|
||||
* Snow Ball Throw And Splat Sound (http://soundbible.com, Mike Koenig, Attribution 3.0)
|
||||
|
||||
|
@ -177,7 +177,7 @@ Prøv også å justere gulrøttene litt ([Carrot](src/inf101/v18/rogue101/exampl
|
||||
|
||||
(Du trenger ikke legge ved tegningen din, men du kan gjerne lage og legge ved en oppdatert utgave når du har fått bedre/full forståelse av systemet.)
|
||||
|
||||
### *(0%)* Deloppgave A5: Ting du ikke trenger å se på (0/100)
|
||||
### *(0%)* Deloppgave A5: Ting du ikke trenger å se på
|
||||
|
||||
* Du trenger ikke se på koden i `gfx` (grafikkbibliotek), `grid` (utvidet IGrid) eller `util` (generering av testdata).
|
||||
* Hvis du lager grafikk selv, vil du gjerne komme til å *bruke* [`ITurtle`](src/inf101/v18/gfx/gfxmode/ITurtle.java) (fra `gfx`), men du trenger ikke se på implementasjone.
|
||||
|
BIN
audio/Bow_Fire_Arrow-Stephan_Schutze-2133929391.wav
Normal file
BIN
audio/Bow_Fire_Arrow-Stephan_Schutze-2133929391.wav
Normal file
Binary file not shown.
BIN
audio/Large Fireball-SoundBible.com-301502490.wav
Normal file
BIN
audio/Large Fireball-SoundBible.com-301502490.wav
Normal file
Binary file not shown.
BIN
audio/Realistic_Punch-Mark_DiAngelo-1609462330.wav
Normal file
BIN
audio/Realistic_Punch-Mark_DiAngelo-1609462330.wav
Normal file
Binary file not shown.
BIN
audio/Snow Ball Throw And Splat-SoundBible.com-992042947.wav
Normal file
BIN
audio/Snow Ball Throw And Splat-SoundBible.com-992042947.wav
Normal file
Binary file not shown.
BIN
audio/Sword Swing-SoundBible.com-639083727.wav
Normal file
BIN
audio/Sword Swing-SoundBible.com-639083727.wav
Normal file
Binary file not shown.
10
flowchart.txt
Normal file
10
flowchart.txt
Normal file
@ -0,0 +1,10 @@
|
||||
Game -> IGame
|
||||
GameMap -> IGameMap -> IMapView
|
||||
IPlayer, INonPlayer -> IActor -> IItem -> Comparable<IItem>
|
||||
GameEvent<T> -> Event<T>
|
||||
|
||||
|
||||
Game -> Mapreader.readFile()
|
||||
Game -> createItem()
|
||||
Game - Rabbit.doTurn(Game) - Game.move()
|
||||
Game.doTurn() - Game.beginTurn()
|
@ -332,7 +332,8 @@ public class Screen {
|
||||
private final Map<IPaintLayer, Canvas> layerCanvases = new IdentityHashMap<>();
|
||||
private final Canvas background;
|
||||
private final Group root;
|
||||
private Paint bgColor = Color.CORNFLOWERBLUE;
|
||||
//private Paint bgColor = Color.CORNFLOWERBLUE;
|
||||
private Paint bgColor = Color.BLACK;
|
||||
private int aspect = 0;
|
||||
private double scaling = 0;
|
||||
private double currentScale = 1.0;
|
||||
|
BIN
src/inf101/v18/gfx/fonts/Symbola.odt
Normal file
BIN
src/inf101/v18/gfx/fonts/Symbola.odt
Normal file
Binary file not shown.
BIN
src/inf101/v18/gfx/fonts/Symbola.pdf
Normal file
BIN
src/inf101/v18/gfx/fonts/Symbola.pdf
Normal file
Binary file not shown.
BIN
src/inf101/v18/gfx/fonts/Symbola.ttf
Normal file
BIN
src/inf101/v18/gfx/fonts/Symbola.ttf
Normal file
Binary file not shown.
BIN
src/inf101/v18/gfx/fonts/hintedSymbola.ttf
Normal file
BIN
src/inf101/v18/gfx/fonts/hintedSymbola.ttf
Normal file
Binary file not shown.
@ -12,7 +12,7 @@ public class BlocksAndBoxes {
|
||||
|
||||
private List<Integer> order;
|
||||
|
||||
private PixelOrder(int a, int b, int c, int d) {
|
||||
PixelOrder(int a, int b, int c, int d) {
|
||||
order = Arrays.asList(a, b, c, d);
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ public class BlocksAndBoxes {
|
||||
public static final String BLOCK_REVERSE_BOTTOM_RIGHT = "▛";
|
||||
public static final String BLOCK_FULL = "█";
|
||||
|
||||
public static final String BLOCK_HALF = "▒";;
|
||||
public static final String BLOCK_HALF = "▒";
|
||||
|
||||
public static String blockAddOne(String s, PixelOrder order) {
|
||||
int i = BlocksAndBoxes.unicodeBlocksString.indexOf(s);
|
||||
|
@ -74,7 +74,7 @@ public class DemoPages {
|
||||
printer.println(" 0123456789ABCDEF 0123456789ABCDEF");
|
||||
for (int y = 0; y < 16; y++) {
|
||||
printer.print(String.format(" %X", y));
|
||||
int c = 0x00 + y * 0x010;
|
||||
int c = y * 0x010;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
printer.print(c >= 0x20 ? Character.toString((char) (c + x)) : " ");
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ public class Printer implements IPaintLayer {
|
||||
return r;
|
||||
}
|
||||
|
||||
Color DEFAULT_FILL = Color.BLACK;
|
||||
Color DEFAULT_FILL = Color.WHITE;
|
||||
|
||||
Color DEFAULT_STROKE = Color.TRANSPARENT;
|
||||
|
||||
@ -91,7 +91,7 @@ public class Printer implements IPaintLayer {
|
||||
// private int pageWidth = LINE_WIDTHS[resMode], pageHeight =
|
||||
// PAGE_HEIGHTS[resMode];
|
||||
private int leftMargin = 1, topMargin = 1;
|
||||
private TextFont font = FONT_LMMONO;
|
||||
private TextFont font = FONT_SYMBOLA;
|
||||
private int videoAttrs = 0;
|
||||
|
||||
private String csiSeq = null;
|
||||
|
@ -305,8 +305,6 @@ public class TextFont {
|
||||
* @param font
|
||||
* Name of the font file. Will search for the file in the same folder
|
||||
* as the TextFont class, as well as ".." and "../fonts".
|
||||
* @param size
|
||||
* Point size of the font.
|
||||
* @param squareSize
|
||||
* The width and height of a square defining the bounds of letters
|
||||
* @param xTranslate
|
||||
@ -350,10 +348,7 @@ public class TextFont {
|
||||
* {@link #setGraphicsContext(GraphicsContext, double)} for extra on-the-fly
|
||||
* horizontal scaling, e.g. to make half-width letters ("hires" mode).
|
||||
*
|
||||
*
|
||||
* @param font
|
||||
* Name of the font file. Will search for the file in the same folder
|
||||
* as the TextFont class, as well as ".." and "../fonts".
|
||||
*
|
||||
* @param size
|
||||
* Point size of the font.
|
||||
* @param squareSize
|
||||
@ -400,10 +395,7 @@ public class TextFont {
|
||||
* {@link #setGraphicsContext(GraphicsContext, double)} for extra on-the-fly
|
||||
* horizontal scaling, e.g. to make half-width letters ("hires" mode).
|
||||
*
|
||||
*
|
||||
* @param font
|
||||
* Name of the font file. Will search for the file in the same folder
|
||||
* as the TextFont class, as well as ".." and "../fonts".
|
||||
*
|
||||
* @param size
|
||||
* Point size of the font.
|
||||
* @param squareSize
|
||||
@ -739,13 +731,13 @@ public class TextFont {
|
||||
case '0':
|
||||
return -2 * thin;
|
||||
case '2':
|
||||
ctx.setLineDashes(new double[] { 14.75, 2.5 });
|
||||
ctx.setLineDashes(14.75, 2.5);
|
||||
break;
|
||||
case '3':
|
||||
ctx.setLineDashes(new double[] { 9, 2.5 });
|
||||
ctx.setLineDashes(9, 2.5);
|
||||
break;
|
||||
case '4':
|
||||
ctx.setLineDashes(new double[] { 6.125, 2.5 });
|
||||
ctx.setLineDashes(6.125, 2.5);
|
||||
break;
|
||||
case '.':
|
||||
return 0.0;
|
||||
|
@ -8,6 +8,8 @@ import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class TextFontAdjuster extends Application {
|
||||
// private static final String FONT_NAME = "PetMe64.ttf";
|
||||
// new TextFont(FONT_NAME, 22.2, TextModes.CHAR_BOX_SIZE, 0.0, 0.0, 1.0, 1.0);
|
||||
@ -219,7 +221,7 @@ public class TextFontAdjuster extends Application {
|
||||
return false;
|
||||
});
|
||||
screen.setKeyTypedHandler((KeyEvent event) -> {
|
||||
if (event.getCharacter() != KeyEvent.CHAR_UNDEFINED) {
|
||||
if (!Objects.equals(event.getCharacter(), KeyEvent.CHAR_UNDEFINED)) {
|
||||
printer.print(event.getCharacter());
|
||||
return true;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public enum TextMode {
|
||||
|
||||
private int vIndex;
|
||||
|
||||
private TextMode(int w, int h, int aspect) {
|
||||
TextMode(int w, int h, int aspect) {
|
||||
this.hIndex = w;
|
||||
this.vIndex = h;
|
||||
this.aspect = aspect;
|
||||
|
@ -32,7 +32,7 @@ public enum GridDirection {
|
||||
private final int dy;
|
||||
private final int mask;
|
||||
|
||||
private GridDirection(double degrees, int dx, int dy, int mask) {
|
||||
GridDirection(double degrees, int dx, int dy, int mask) {
|
||||
this.degrees = degrees;
|
||||
this.dx = dx;
|
||||
this.dy = dy;
|
||||
|
@ -52,8 +52,8 @@ public interface IGrid<T> extends Iterable<T> {
|
||||
* // clear the grid
|
||||
* grid.setAll(null);
|
||||
* </pre>
|
||||
*
|
||||
* @param initialiser
|
||||
*
|
||||
* @param element
|
||||
*/
|
||||
void fill(T element);
|
||||
|
||||
@ -203,8 +203,6 @@ public interface IGrid<T> extends Iterable<T> {
|
||||
* y must be greater than or equal to 0 and less than getHeight(). x must be
|
||||
* greater than or equal to 0 and less than getWidth().
|
||||
*
|
||||
* @param pos
|
||||
* The (x,y) position of the grid cell to get the contents of.
|
||||
* @param element
|
||||
* The contents the cell is to have.
|
||||
* @throws IndexOutOfBoundsException
|
||||
|
@ -91,7 +91,7 @@ public interface ILocation extends IPosition {
|
||||
* Find the grid cells between this location (exclusive) and another location
|
||||
* (inclusive).
|
||||
*
|
||||
* This is will be a list of length {@link #gridDistanceTo(other)}, containing
|
||||
* This is a list of length {@link #gridDistanceTo(other)}, containing
|
||||
* the cells that a chess queen would visit when moving to <code>other</code>.
|
||||
* <p>
|
||||
* Computes the maximum of the horizontal and the vertical distance. For
|
||||
|
@ -23,8 +23,7 @@ public class MyGrid<T> implements IGrid<T> {
|
||||
* new MyGrid(10, 10, ((x, y) -> String.format("(%d,%d)", x, y));
|
||||
* </pre>
|
||||
*
|
||||
* @param width
|
||||
* @param height
|
||||
* @param area
|
||||
* @param initialiser
|
||||
* The initialiser function
|
||||
*/
|
||||
@ -43,8 +42,7 @@ public class MyGrid<T> implements IGrid<T> {
|
||||
/**
|
||||
* Construct a grid with the given dimensions.
|
||||
*
|
||||
* @param width
|
||||
* @param height
|
||||
* @param area
|
||||
* @param initElement
|
||||
* What the cells should initially hold (possibly null)
|
||||
*/
|
||||
@ -95,9 +93,7 @@ public class MyGrid<T> implements IGrid<T> {
|
||||
|
||||
@Override
|
||||
public IGrid<T> copy() {
|
||||
MyGrid<T> newGrid = new MyGrid<>(getWidth(), getHeight(), (l) -> get(l));
|
||||
|
||||
return newGrid;
|
||||
return new MyGrid<>(getWidth(), getHeight(), (l) -> get(l));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,10 +80,7 @@ public class RectArea implements IArea {
|
||||
if (x != other.getX()) {
|
||||
return false;
|
||||
}
|
||||
if (y != other.getY()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return y == other.getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -304,10 +301,7 @@ public class RectArea implements IArea {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("RectArea [width=").append(width).append(", height=").append(height).append(", hWrap=")
|
||||
.append(hWrap).append(", vWrap=").append(vWrap).append("]");
|
||||
return builder.toString();
|
||||
return "RectArea [width=" + width + ", height=" + height + ", hWrap=" + hWrap + ", vWrap=" + vWrap + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,7 +12,7 @@ import static org.junit.Assert.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AreaRetting {
|
||||
private static final int N = 10000;
|
||||
|
@ -11,7 +11,7 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
|
||||
public class GridRetting {
|
||||
private static final int N = 10000;
|
||||
|
@ -20,7 +20,7 @@ import javafx.util.Duration;
|
||||
|
||||
public class Main extends Application {
|
||||
// you might want to tune these options
|
||||
public static final boolean MAIN_USE_BACKGROUND_GRID = true;
|
||||
public static final boolean MAIN_USE_BACKGROUND_GRID = false;
|
||||
public static final boolean MAP_AUTO_SCALE_ITEM_DRAW = true;
|
||||
public static final boolean MAP_DRAW_ONLY_DIRTY_CELLS = false;
|
||||
public static final TextMode MAIN_TEXT_MODE = TextMode.MODE_80X25;
|
||||
@ -88,7 +88,7 @@ public class Main extends Application {
|
||||
printer.setTextMode(MAIN_TEXT_MODE, true);
|
||||
|
||||
// Font with emojis – need separate download
|
||||
// printer.setFont(Printer.FONT_SYMBOLA);
|
||||
printer.setFont(Printer.FONT_SYMBOLA);
|
||||
|
||||
if (grid)
|
||||
printer.drawCharCells();
|
||||
@ -123,18 +123,21 @@ public class Main extends Application {
|
||||
printer.redrawTextPage();
|
||||
return true;
|
||||
}
|
||||
} else if (code == KeyCode.ENTER) {
|
||||
/*} else if (code == KeyCode.ENTER) {
|
||||
try {
|
||||
doTurn();
|
||||
} catch (Exception e) {
|
||||
printer.printAt(1, 25, "Exception: " + e.getMessage(), Color.RED);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
return true;*/ // This interferes with other code
|
||||
} else {
|
||||
try {
|
||||
game.keyPressed(code);
|
||||
doTurn();
|
||||
if (game.keyPressed(code)) {
|
||||
game.draw();
|
||||
} else {
|
||||
doTurn();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
|
78
src/inf101/v18/rogue101/enemies/Boss.java
Normal file
78
src/inf101/v18/rogue101/enemies/Boss.java
Normal file
@ -0,0 +1,78 @@
|
||||
package inf101.v18.rogue101.enemies;
|
||||
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.items.Backpack;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
import inf101.v18.rogue101.objects.INonPlayer;
|
||||
|
||||
public class Boss implements INonPlayer {
|
||||
private int hp = getMaxHealth();
|
||||
Backpack backpack = new Backpack();
|
||||
|
||||
@Override
|
||||
public void doTurn(IGame game) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttack() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDamage() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItem getItem(Class<?> type) {
|
||||
for (IItem item : backpack.getContent()) {
|
||||
if (type.isInstance(item)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 500;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Lucifer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrintSymbol() {
|
||||
return "\uD83D\uDE08";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "B";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
//TODO: Drop item on death.
|
||||
hp -= amount;
|
||||
return amount;
|
||||
}
|
||||
}
|
260
src/inf101/v18/rogue101/enemies/Girl.java
Normal file
260
src/inf101/v18/rogue101/enemies/Girl.java
Normal file
@ -0,0 +1,260 @@
|
||||
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;
|
||||
import inf101.v18.rogue101.states.Age;
|
||||
import inf101.v18.rogue101.states.Occupation;
|
||||
import inf101.v18.rogue101.states.Personality;
|
||||
|
||||
import java.nio.channels.ClosedSelectorException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class Girl implements INonPlayer {
|
||||
private final String name = randomName();
|
||||
private final Age age = Age.getRandom();
|
||||
private final Personality personality = Personality.getRandom();
|
||||
private final Occupation occupation = Occupation.getRandom();
|
||||
private int maxhp;
|
||||
private int hp;
|
||||
private int attack;
|
||||
private int defence;
|
||||
private int visibility;
|
||||
private Backpack backpack = new Backpack();
|
||||
private static final Random random = new Random();
|
||||
private List<Class<?>> validItems;
|
||||
|
||||
public Girl() {
|
||||
setStats();
|
||||
setValidItems();
|
||||
}
|
||||
|
||||
//TODO: Game balance
|
||||
private void setStats() {
|
||||
switch (age) {
|
||||
case TODDLER:
|
||||
maxhp = 100;
|
||||
attack = 10;
|
||||
defence = 50;
|
||||
visibility = 1;
|
||||
break;
|
||||
case CHILD:
|
||||
maxhp = 150;
|
||||
attack = 20;
|
||||
defence = 40;
|
||||
visibility = 2;
|
||||
break;
|
||||
case TEEN:
|
||||
maxhp = 200;
|
||||
attack = 25;
|
||||
defence = 30;
|
||||
visibility = 3;
|
||||
break;
|
||||
case ADULT:
|
||||
maxhp = 250;
|
||||
attack = 30;
|
||||
defence = 20;
|
||||
visibility = 4;
|
||||
break;
|
||||
case ELDER:
|
||||
maxhp = 200;
|
||||
attack = 15;
|
||||
defence = 35;
|
||||
visibility = 2;
|
||||
break;
|
||||
}
|
||||
if (occupation == Occupation.KNIGHT) {
|
||||
attack += 10; //Knights are quite powerful.
|
||||
}
|
||||
if (occupation == Occupation.MAGE) {
|
||||
attack += 5; // Mages have lesser range than bowsmen, but more damage.
|
||||
}
|
||||
maxhp += (int)(random.nextGaussian() * 10);
|
||||
hp = maxhp;
|
||||
attack += (int)(random.nextGaussian() * 5);
|
||||
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";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doTurn(IGame game) {
|
||||
if (!backpack.isFull()) {
|
||||
IItem item = NPC.pickUp(game, validItems);
|
||||
if (item != null) {
|
||||
backpack.add(item);
|
||||
return;
|
||||
}
|
||||
if (NPC.trackItem(game, validItems)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (personality == Personality.AFRAID && NPC.flee(game)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (willAttack(game) && attack(game)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<GridDirection> possibleMoves = game.getPossibleMoves();
|
||||
if (!possibleMoves.isEmpty()) {
|
||||
Collections.shuffle(possibleMoves);
|
||||
game.move(possibleMoves.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttack() {
|
||||
return attack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDamage() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return defence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return maxhp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrintSymbol() {
|
||||
return "\u001b[95m" + "\uD83D\uDEB6" + "\u001b[0m";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "G";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVision() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItem getItem(Class<?> type) {
|
||||
for (IItem item : backpack.getContent()) {
|
||||
if (type.isInstance(item)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
hp -= amount;
|
||||
return amount;
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import javafx.scene.paint.Color;
|
||||
public class Carrot implements IItem {
|
||||
private int hp = getMaxHealth();
|
||||
|
||||
public void doTurn(IGame game) {
|
||||
public void doTurn() {
|
||||
hp = Math.min(hp + 1, getMaxHealth());
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ public class Carrot implements IItem {
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 10;
|
||||
return 23;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,7 +74,7 @@ public class Carrot implements IItem {
|
||||
|
||||
if (hp < 0) {
|
||||
// we're all eaten!
|
||||
hp = -1;
|
||||
hp = 0;
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
@ -9,39 +9,49 @@ import inf101.v18.grid.GridDirection;
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
import inf101.v18.rogue101.objects.INonPlayer;
|
||||
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) {
|
||||
if (food == 0)
|
||||
if (food == 0) {
|
||||
hp--;
|
||||
else
|
||||
} else {
|
||||
food--;
|
||||
if (hp < 1)
|
||||
}
|
||||
if (hp < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NPC.tryAttack(game)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (IItem item : game.getLocalItems()) {
|
||||
if (item instanceof Carrot) {
|
||||
System.out.println("found carrot!");
|
||||
int eaten = item.handleDamage(game, this, 5);
|
||||
int eaten = item.handleDamage(game, this, getDamage());
|
||||
if (eaten > 0) {
|
||||
System.out.println("ate carrot worth " + eaten + "!");
|
||||
food += eaten;
|
||||
game.displayMessage("You hear a faint crunching (" + getName() + " eats " + item.getArticle() + " "
|
||||
+ item.getName() + ")");
|
||||
game.displayMessage("You hear a faint crunching (" + getName() + " eats " + item.getArticle() + " " + item.getName() + ")");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: prøv forskjellige varianter her
|
||||
List<GridDirection> possibleMoves = new ArrayList<>();
|
||||
for (GridDirection dir : GridDirection.FOUR_DIRECTIONS) {
|
||||
if (game.canGo(dir))
|
||||
possibleMoves.add(dir);
|
||||
|
||||
if (NPC.trackItem(game, validItems)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<GridDirection> possibleMoves = game.getPossibleMoves();
|
||||
if (!possibleMoves.isEmpty()) {
|
||||
Collections.shuffle(possibleMoves);
|
||||
game.move(possibleMoves.get(0));
|
||||
@ -55,7 +65,7 @@ public class Rabbit implements INonPlayer {
|
||||
|
||||
@Override
|
||||
public int getAttack() {
|
||||
return 1000;
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,22 +75,22 @@ public class Rabbit implements INonPlayer {
|
||||
|
||||
@Override
|
||||
public int getDamage() {
|
||||
return 1000;
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "rabbit";
|
||||
return "Rabbit";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,6 +98,16 @@ public class Rabbit implements INonPlayer {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVision() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItem getItem(Class<?> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return hp > 0 ? "R" : "¤";
|
||||
@ -98,5 +118,4 @@ public class Rabbit implements INonPlayer {
|
||||
hp -= amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,18 +17,17 @@ import inf101.v18.grid.GridDirection;
|
||||
import inf101.v18.grid.IGrid;
|
||||
import inf101.v18.grid.ILocation;
|
||||
import inf101.v18.rogue101.Main;
|
||||
import inf101.v18.rogue101.enemies.Boss;
|
||||
import inf101.v18.rogue101.enemies.Girl;
|
||||
import inf101.v18.rogue101.examples.Carrot;
|
||||
import inf101.v18.rogue101.items.*;
|
||||
import inf101.v18.rogue101.examples.Rabbit;
|
||||
import inf101.v18.rogue101.map.GameMap;
|
||||
import inf101.v18.rogue101.map.IGameMap;
|
||||
import inf101.v18.rogue101.map.IMapView;
|
||||
import inf101.v18.rogue101.map.MapReader;
|
||||
import inf101.v18.rogue101.objects.Dust;
|
||||
import inf101.v18.rogue101.objects.IActor;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
import inf101.v18.rogue101.objects.INonPlayer;
|
||||
import inf101.v18.rogue101.objects.IPlayer;
|
||||
import inf101.v18.rogue101.objects.Wall;
|
||||
import inf101.v18.rogue101.objects.*;
|
||||
import inf101.v18.rogue101.shared.NPC;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.paint.Color;
|
||||
@ -46,6 +45,12 @@ public class Game implements IGame {
|
||||
* Useful random generator
|
||||
*/
|
||||
private Random random = new Random();
|
||||
|
||||
/**
|
||||
* Saves the last three messages
|
||||
*/
|
||||
private List<String> lastMessages = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The game map. {@link IGameMap} gives us a few more details than
|
||||
* {@link IMapView} (write access to item lists); the game needs this but
|
||||
@ -63,9 +68,7 @@ public class Game implements IGame {
|
||||
this.painter = painter;
|
||||
this.printer = printer;
|
||||
|
||||
// TODO: (*very* optional) for advanced factory technique, use
|
||||
// something like "itemFactories.put("R", () -> new Rabbit());"
|
||||
// must be done *before* you read the map
|
||||
addFactory();
|
||||
|
||||
// NOTE: in a more realistic situation, we will have multiple levels (one map
|
||||
// per level), and (at least for a Roguelike game) the levels should be
|
||||
@ -74,7 +77,7 @@ public class Game implements IGame {
|
||||
// inputGrid will be filled with single-character strings indicating what (if
|
||||
// anything)
|
||||
// should be placed at that map square
|
||||
IGrid<String> inputGrid = MapReader.readFile("maps/level1.txt");
|
||||
IGrid<String> inputGrid = MapReader.readFile("maps/testmap.txt");
|
||||
if (inputGrid == null) {
|
||||
System.err.println("Map not found – falling back to builtin map");
|
||||
inputGrid = MapReader.readString(Main.BUILTIN_MAP);
|
||||
@ -87,11 +90,19 @@ 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"};
|
||||
for (int i = 0; i < info.length; i++) {
|
||||
this.printer.printAt(map.getWidth() + 2, 1 + i, info[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public Game(String mapString) {
|
||||
printer = new Printer(1280, 720);
|
||||
painter = new TurtlePainter(1280, 720);
|
||||
|
||||
addFactory();
|
||||
|
||||
IGrid<String> inputGrid = MapReader.readString(mapString);
|
||||
this.map = new GameMap(inputGrid.getArea());
|
||||
for (ILocation loc : inputGrid.locations()) {
|
||||
@ -114,14 +125,74 @@ public class Game implements IGame {
|
||||
map.add(currentLocation, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the attack of an IActor based on equipped items.
|
||||
*
|
||||
* @return The attack
|
||||
*/
|
||||
private int getAttack() {
|
||||
int damage = currentActor.getAttack() + random.nextInt(20) + 1;
|
||||
IWeapon weapon = (IWeapon)currentActor.getItem(IWeapon.class);
|
||||
if (weapon != null) {
|
||||
damage += weapon.getWeaponDamage();
|
||||
}
|
||||
IBuffItem buff = (IBuffItem)currentActor.getItem(IBuffItem.class);
|
||||
if (buff != null) {
|
||||
damage += buff.getBuffDamage();
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the defence of the current target.
|
||||
*
|
||||
* @param target The target to evaluate
|
||||
* @return The defence of the target
|
||||
*/
|
||||
private int getDefence(IItem target) {
|
||||
int defence = target.getDefence() + 10;
|
||||
IActor actor = (IActor) target;
|
||||
IBuffItem item = (IBuffItem) actor.getItem(IBuffItem.class);
|
||||
if (item != null) {
|
||||
defence += item.getBuffDefence();
|
||||
}
|
||||
return defence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the damage done against the current target.
|
||||
*
|
||||
* @param target The target to evaluate.
|
||||
* @return The damage done to the target.
|
||||
*/
|
||||
private int getDamage(IItem target) {
|
||||
int damage = currentActor.getDamage();
|
||||
IActor actor = (IActor) target;
|
||||
IBuffItem item = (IBuffItem) actor.getItem(IBuffItem.class);
|
||||
if (item != null) {
|
||||
damage -= item.getBuffDamageReduction();
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILocation attack(GridDirection dir, IItem target) {
|
||||
ILocation loc = map.go(currentLocation, dir);
|
||||
if (map.has(loc, target))
|
||||
ILocation loc = currentLocation.go(dir);
|
||||
if (!map.has(loc, target)) {
|
||||
throw new IllegalMoveException("Target isn't there!");
|
||||
|
||||
// TODO: implement attack
|
||||
|
||||
}
|
||||
IWeapon weapon = (IWeapon) currentActor.getItem(IWeapon.class);
|
||||
if (weapon != null) {
|
||||
NPC.playSound(weapon.getSound());
|
||||
} else {
|
||||
NPC.playSound("audio/Realistic_Punch-Mark_DiAngelo-1609462330.wav");
|
||||
}
|
||||
if (getAttack() >= getDefence(target)) {
|
||||
int actualDamage = target.handleDamage(this, target, getDamage(target));
|
||||
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());
|
||||
}
|
||||
|
||||
map.clean(loc);
|
||||
|
||||
@ -133,6 +204,30 @@ public class Game implements IGame {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILocation rangedAttack(GridDirection dir, IItem target) {
|
||||
ILocation loc = currentLocation;
|
||||
IWeapon weapon = (IWeapon) currentActor.getItem(IWeapon.class);
|
||||
if (weapon != null) {
|
||||
NPC.playSound(weapon.getSound());
|
||||
} else {
|
||||
NPC.playSound("audio/Snow Ball Throw And Splat-SoundBible.com-992042947.wav");
|
||||
}
|
||||
if (getAttack() >= getDefence(target)) {
|
||||
int damage = getDamage(target) / loc.gridDistanceTo(map.getLocation(target));
|
||||
int actualDamage = target.handleDamage(this, target, damage);
|
||||
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());
|
||||
}
|
||||
map.clean(map.getLocation(target));
|
||||
if (target.isDestroyed() && map.has(currentLocation.go(dir), target)) {
|
||||
return move(dir);
|
||||
} else {
|
||||
return currentLocation;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a new game turn, or continue to the previous turn
|
||||
*
|
||||
@ -148,8 +243,15 @@ public class Game implements IGame {
|
||||
beginTurn();
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
// process actors one by one; for the IPlayer, we return and wait for keypresses
|
||||
// Possible TODO: for INonPlayer, we could also return early (returning
|
||||
// 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)
|
||||
@ -169,6 +271,7 @@ public class Game implements IGame {
|
||||
((INonPlayer) currentActor).doTurn(this);
|
||||
// remove any dead items from current location
|
||||
map.clean(currentLocation);
|
||||
return false;
|
||||
} else if (currentActor instanceof IPlayer) {
|
||||
if (currentActor.isDestroyed()) {
|
||||
// a dead human player gets removed from the game
|
||||
@ -231,6 +334,8 @@ public class Game implements IGame {
|
||||
}
|
||||
} else if (item instanceof IActor) {
|
||||
actors.add((IActor) item); // add other actors to the end of the list
|
||||
} else if (item instanceof Carrot) {
|
||||
((Carrot) item).doTurn();
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -241,20 +346,22 @@ public class Game implements IGame {
|
||||
return map.canGo(currentLocation, dir);
|
||||
}
|
||||
|
||||
private void addFactory() {
|
||||
itemFactories.put("#", Wall::new);
|
||||
itemFactories.put("@", Player::new);
|
||||
itemFactories.put("C", Carrot::new);
|
||||
itemFactories.put("R", Rabbit::new);
|
||||
itemFactories.put("M", Manga::new);
|
||||
itemFactories.put("G", Girl::new);
|
||||
itemFactories.put(".", Dust::new);
|
||||
itemFactories.put("S", Sword::new);
|
||||
itemFactories.put("c", Chest::new);
|
||||
itemFactories.put("B", Boss::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItem createItem(String sym) {
|
||||
switch (sym) {
|
||||
case "#":
|
||||
return new Wall();
|
||||
case ".":
|
||||
// TODO: add Dust
|
||||
return null;
|
||||
case "R":
|
||||
return new Rabbit();
|
||||
case "C":
|
||||
return new Carrot();
|
||||
case "@":
|
||||
// TODO: add Player
|
||||
case " ":
|
||||
return null;
|
||||
default:
|
||||
@ -278,11 +385,22 @@ public class Game implements IGame {
|
||||
|
||||
@Override
|
||||
public void displayMessage(String s) {
|
||||
// it should be safe to print to lines Main.LINE_MSG1, Main.LINE_MSG2,
|
||||
// Main.LINE_MSG3
|
||||
// TODO: you can save the last three lines, and display/scroll them
|
||||
if (lastMessages.size() >= 3) {
|
||||
lastMessages.remove(2);
|
||||
}
|
||||
lastMessages.add(0, s);
|
||||
printer.clearLine(Main.LINE_MSG1);
|
||||
printer.printAt(1, Main.LINE_MSG1, s);
|
||||
printer.clearLine(Main.LINE_MSG2);
|
||||
printer.clearLine(Main.LINE_MSG3);
|
||||
if (lastMessages.size() > 0) {
|
||||
printer.printAt(1, Main.LINE_MSG1, lastMessages.get(0));
|
||||
}
|
||||
if (lastMessages.size() > 1) {
|
||||
printer.printAt(1, Main.LINE_MSG2, lastMessages.get(1));
|
||||
}
|
||||
if (lastMessages.size() > 2) {
|
||||
printer.printAt(1, Main.LINE_MSG3, lastMessages.get(2));
|
||||
}
|
||||
System.out.println("Message: «" + s + "»");
|
||||
}
|
||||
|
||||
@ -294,7 +412,9 @@ public class Game implements IGame {
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
map.draw(painter, printer);
|
||||
//map.draw(painter, printer);
|
||||
GameMap aMap = (GameMap) map;
|
||||
aMap.drawVisible(painter, printer, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -356,15 +476,29 @@ public class Game implements IGame {
|
||||
|
||||
@Override
|
||||
public List<GridDirection> getPossibleMoves() {
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
List<GridDirection> moves = new ArrayList<>();
|
||||
for (GridDirection dir : GridDirection.FOUR_DIRECTIONS) {
|
||||
if (canGo(dir)) {
|
||||
moves.add(dir);
|
||||
}
|
||||
}
|
||||
return moves;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ILocation> getVisible() {
|
||||
// TODO: maybe replace 3 by some sort of visibility range obtained from
|
||||
// currentActor?
|
||||
return map.getNeighbourhood(currentLocation, 3);
|
||||
List<ILocation> neighbours = map.getNeighbourhood(currentLocation, currentActor.getVision());
|
||||
List<ILocation> invalid = new ArrayList<>();
|
||||
for (ILocation neighbour : neighbours) {
|
||||
for (ILocation tile : currentLocation.gridLineTo(neighbour)) {
|
||||
if (map.hasWall(tile)) {
|
||||
invalid.add(neighbour);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
neighbours.removeAll(invalid);
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -372,14 +506,13 @@ public class Game implements IGame {
|
||||
return map.getWidth();
|
||||
}
|
||||
|
||||
public void keyPressed(KeyCode code) {
|
||||
public boolean keyPressed(KeyCode code) {
|
||||
// only an IPlayer/human can handle keypresses, and only if it's the human's
|
||||
// turn
|
||||
if (currentActor instanceof IPlayer) {
|
||||
((IPlayer) currentActor).keyPressed(this, code); // do your thing
|
||||
if (movePoints <= 0)
|
||||
doTurn(); // proceed with turn if we're out of moves
|
||||
return !((IPlayer) currentActor).keyPressed(this, code);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -396,22 +529,25 @@ public class Game implements IGame {
|
||||
|
||||
@Override
|
||||
public IItem pickUp(IItem item) {
|
||||
if (item != null && map.has(currentLocation, item)) {
|
||||
// TODO: bruk getAttack()/getDefence() til å avgjøre om man får til å plukke opp
|
||||
// tingen
|
||||
// evt.: en IActor kan bare plukkes opp hvis den har få/ingen helsepoeng igjen
|
||||
map.remove(currentLocation, item);
|
||||
return item;
|
||||
if (item != null && map.has(currentLocation, item) && !(item instanceof IStatic)) {
|
||||
if (item instanceof IActor) {
|
||||
if (item.getCurrentHealth() / item.getMaxHealth() < 3) {
|
||||
map.remove(currentLocation, item);
|
||||
return item;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (currentActor.getAttack() > item.getDefence()) {
|
||||
map.remove(currentLocation, item);
|
||||
return item;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILocation rangedAttack(GridDirection dir, IItem target) {
|
||||
return currentLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITurtle getPainter() {
|
||||
return painter;
|
||||
@ -486,4 +622,45 @@ public class Game implements IGame {
|
||||
public Random getRandom() {
|
||||
return random;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDirection locationDirection(ILocation start, ILocation target) {
|
||||
int targetX = target.getX(), targetY = target.getY();
|
||||
int startX = start.getX(), startY = start.getY();
|
||||
GridDirection dir = GridDirection.CENTER;
|
||||
if (targetX > startX && targetY > startY) {
|
||||
if (Math.abs(targetX - startX) < Math.abs(targetY - startY)) {
|
||||
dir = GridDirection.SOUTH;
|
||||
} else {
|
||||
dir = GridDirection.EAST;
|
||||
}
|
||||
} else if (targetX > startX && targetY < startY) {
|
||||
if (Math.abs(targetX - startX) < Math.abs(targetY - startY)) {
|
||||
dir = GridDirection.NORTH;
|
||||
} else {
|
||||
dir = GridDirection.EAST;
|
||||
}
|
||||
} else if (targetX < startX && targetY > startY) {
|
||||
if (Math.abs(targetX - startX) < Math.abs(targetY - startY)) {
|
||||
dir = GridDirection.SOUTH;
|
||||
} else {
|
||||
dir = GridDirection.WEST;
|
||||
}
|
||||
} else if (targetX < startX && targetY < startY) {
|
||||
if (Math.abs(targetX - startX) < Math.abs(targetY - startY)) {
|
||||
dir = GridDirection.NORTH;
|
||||
} else {
|
||||
dir = GridDirection.WEST;
|
||||
}
|
||||
} else if (targetX > startX) {
|
||||
dir = GridDirection.EAST;
|
||||
} else if (targetX < startX) {
|
||||
dir = GridDirection.WEST;
|
||||
} else if (targetY > startY) {
|
||||
dir = GridDirection.SOUTH;
|
||||
} else if (targetY < startY) {
|
||||
dir = GridDirection.NORTH;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ public interface IGame {
|
||||
double[] getFreeGraphicsAreaBounds();
|
||||
|
||||
/**
|
||||
* Get the bounds of the free texxt area.
|
||||
* Get the bounds of the free text area.
|
||||
* <p>
|
||||
* You can fill this with whatever you want, using {@link #getPrinter()} and
|
||||
* {@link #clearFreeTextArea()}.
|
||||
@ -317,4 +317,14 @@ public interface IGame {
|
||||
* @return A random generator
|
||||
*/
|
||||
Random getRandom();
|
||||
|
||||
/**
|
||||
* Gets the best direction 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);
|
||||
}
|
||||
|
123
src/inf101/v18/rogue101/items/Backpack.java
Normal file
123
src/inf101/v18/rogue101/items/Backpack.java
Normal file
@ -0,0 +1,123 @@
|
||||
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 implements IContainer {
|
||||
/**
|
||||
* A list containing everything in the backpack.
|
||||
*/
|
||||
private List<IItem> content = new ArrayList<>();
|
||||
/**
|
||||
* The maximum amount of items allowed in a single backpack.
|
||||
*/
|
||||
private final int MAX_SIZE = 50;
|
||||
|
||||
@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() {
|
||||
int totalSize = 0;
|
||||
for (IItem item : content) {
|
||||
totalSize += item.getSize();
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(IItem item) {
|
||||
if (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 IItem get(int i) {
|
||||
return content.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content List for direct manipulation.
|
||||
*
|
||||
* @return A list of T
|
||||
*/
|
||||
public List<IItem> getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFull() {
|
||||
return size() >= MAX_SIZE;
|
||||
}
|
||||
}
|
52
src/inf101/v18/rogue101/items/Bow.java
Normal file
52
src/inf101/v18/rogue101/items/Bow.java
Normal file
@ -0,0 +1,52 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class Bow implements IRangedWeapon {
|
||||
private static final Random random = new Random();
|
||||
private final int damage = 3 + random.nextInt(20);
|
||||
private final int hp = getMaxHealth();
|
||||
|
||||
@Override
|
||||
public int getWeaponDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 110;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Unknown bow";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "B";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
return 0;
|
||||
}
|
||||
}
|
73
src/inf101/v18/rogue101/items/Chest.java
Normal file
73
src/inf101/v18/rogue101/items/Chest.java
Normal file
@ -0,0 +1,73 @@
|
||||
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 Chest implements IContainer, IStatic {
|
||||
private List<IItem> container;
|
||||
|
||||
public Chest() {
|
||||
this.container = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Chest(List<IItem> items) {
|
||||
this.container = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItem get(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List getContent() {
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFull() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Chest";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInteractMessage() {
|
||||
return "Items in " + getName() + ": ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 10000;
|
||||
}
|
||||
|
||||
public String getPrintSymbol() {
|
||||
return "\uD83D\uDDC3";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "C";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
return 0;
|
||||
}
|
||||
}
|
33
src/inf101/v18/rogue101/items/IBuffItem.java
Normal file
33
src/inf101/v18/rogue101/items/IBuffItem.java
Normal file
@ -0,0 +1,33 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
public interface IBuffItem extends IItem {
|
||||
/**
|
||||
* Retrieve damage increase done by the buff item.
|
||||
*
|
||||
* @return An int, May be 0
|
||||
*/
|
||||
int getBuffDamage();
|
||||
|
||||
/**
|
||||
* Retrieve defence increase done by the buff item.
|
||||
*
|
||||
* @return An int, May be 0
|
||||
*/
|
||||
int getBuffDefence();
|
||||
|
||||
/**
|
||||
* Retrieve defence increase done by the buff item.
|
||||
*
|
||||
* @return An int, May be 0
|
||||
*/
|
||||
int getBuffDamageReduction();
|
||||
|
||||
/**
|
||||
* Retrieve visibility increase done by the buff item.
|
||||
*
|
||||
* @return An int, May be 0
|
||||
*/
|
||||
int getBuffVisibility();
|
||||
}
|
9
src/inf101/v18/rogue101/items/IConsumable.java
Normal file
9
src/inf101/v18/rogue101/items/IConsumable.java
Normal file
@ -0,0 +1,9 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
public interface IConsumable extends IItem {
|
||||
void hpIncrease();
|
||||
void attackIncrease();
|
||||
void defenceIncrease();
|
||||
}
|
30
src/inf101/v18/rogue101/items/IContainer.java
Normal file
30
src/inf101/v18/rogue101/items/IContainer.java
Normal file
@ -0,0 +1,30 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IContainer 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<IItem> getContent();
|
||||
|
||||
/**
|
||||
* Checks if we can add anything at all to the container.
|
||||
*
|
||||
* @return True if it has no space left
|
||||
*/
|
||||
boolean isFull();
|
||||
}
|
12
src/inf101/v18/rogue101/items/IMagicWeapon.java
Normal file
12
src/inf101/v18/rogue101/items/IMagicWeapon.java
Normal file
@ -0,0 +1,12 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
/**
|
||||
* An interface to extinguish different weapons for specific NPC.
|
||||
*/
|
||||
public interface IMagicWeapon extends IWeapon {
|
||||
|
||||
@Override
|
||||
default String getSound() {
|
||||
return "audio/Bow_Fire_Arrow-Stephan_Schutze-2133929391.wav";
|
||||
}
|
||||
}
|
12
src/inf101/v18/rogue101/items/IMeleeWeapon.java
Normal file
12
src/inf101/v18/rogue101/items/IMeleeWeapon.java
Normal file
@ -0,0 +1,12 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
/**
|
||||
* An interface to extinguish different weapons for specific NPC.
|
||||
*/
|
||||
public interface IMeleeWeapon extends IWeapon {
|
||||
|
||||
@Override
|
||||
default String getSound() {
|
||||
return "audio/Sword Swing-SoundBible.com-639083727.wav";
|
||||
}
|
||||
}
|
12
src/inf101/v18/rogue101/items/IRangedWeapon.java
Normal file
12
src/inf101/v18/rogue101/items/IRangedWeapon.java
Normal file
@ -0,0 +1,12 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
/**
|
||||
* An interface to extinguish different weapons for specific NPC.
|
||||
*/
|
||||
public interface IRangedWeapon extends IWeapon {
|
||||
|
||||
@Override
|
||||
default String getSound() {
|
||||
return "audio/Bow_Fire_Arrow-Stephan_Schutze-2133929391.wav";
|
||||
}
|
||||
}
|
22
src/inf101/v18/rogue101/items/IStatic.java
Normal file
22
src/inf101/v18/rogue101/items/IStatic.java
Normal file
@ -0,0 +1,22 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
public interface IStatic extends IItem {
|
||||
@Override
|
||||
default int getDefence() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getSize() {
|
||||
return 10000;
|
||||
}
|
||||
|
||||
/**
|
||||
* A message to display when an interaction with the player happens.
|
||||
*
|
||||
* @return A message
|
||||
*/
|
||||
String getInteractMessage();
|
||||
}
|
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();
|
||||
}
|
65
src/inf101/v18/rogue101/items/Manga.java
Normal file
65
src/inf101/v18/rogue101/items/Manga.java
Normal file
@ -0,0 +1,65 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
public class Manga implements IItem {
|
||||
private int hp = getMaxHealth();
|
||||
|
||||
/*@Override
|
||||
public boolean draw(ITurtle painter, double w, double h) {
|
||||
painter.save();
|
||||
painter.jump(-10);
|
||||
painter.setInk(Color.BLACK);
|
||||
painter.draw(getSize());
|
||||
painter.turn(90);
|
||||
painter.draw(getSize()/2);
|
||||
painter.turn(90);
|
||||
painter.draw(getSize());
|
||||
painter.turn(90);
|
||||
painter.draw(getSize()/2);
|
||||
painter.restore();
|
||||
return true;
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Manga";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrintSymbol() {
|
||||
return "🕮";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "M";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
hp -= amount;
|
||||
return amount;
|
||||
}
|
||||
}
|
63
src/inf101/v18/rogue101/items/Shield.java
Normal file
63
src/inf101/v18/rogue101/items/Shield.java
Normal file
@ -0,0 +1,63 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
public class Shield implements IBuffItem {
|
||||
private final int hp = getMaxHealth();
|
||||
|
||||
@Override
|
||||
public int getBuffDamage() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBuffDefence() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBuffDamageReduction() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBuffVisibility() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 150;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Unknown shield";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
return 0;
|
||||
}
|
||||
}
|
53
src/inf101/v18/rogue101/items/Staff.java
Normal file
53
src/inf101/v18/rogue101/items/Staff.java
Normal file
@ -0,0 +1,53 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class Staff implements IMagicWeapon {
|
||||
private static final Random random = new Random();
|
||||
private final int damage = 5 + random.nextInt(25);
|
||||
private int hp = getMaxHealth();
|
||||
|
||||
@Override
|
||||
public int getWeaponDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 90;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Unknown staff";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "s";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
hp -= amount;
|
||||
return amount;
|
||||
}
|
||||
}
|
53
src/inf101/v18/rogue101/items/Sword.java
Normal file
53
src/inf101/v18/rogue101/items/Sword.java
Normal file
@ -0,0 +1,53 @@
|
||||
package inf101.v18.rogue101.items;
|
||||
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class Sword implements IMeleeWeapon {
|
||||
private static final Random random = new Random();
|
||||
private final int damage = 5 + random.nextInt(25);
|
||||
private int hp = getMaxHealth();
|
||||
|
||||
@Override
|
||||
public int getWeaponDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Unknown sword";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "S";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
hp -= amount;
|
||||
return amount;
|
||||
}
|
||||
}
|
@ -1,12 +1,6 @@
|
||||
package inf101.v18.rogue101.map;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import inf101.v18.gfx.gfxmode.ITurtle;
|
||||
import inf101.v18.gfx.textmode.Printer;
|
||||
@ -16,9 +10,13 @@ import inf101.v18.grid.ILocation;
|
||||
import inf101.v18.grid.IMultiGrid;
|
||||
import inf101.v18.grid.MultiGrid;
|
||||
import inf101.v18.rogue101.Main;
|
||||
import inf101.v18.rogue101.examples.Carrot;
|
||||
import inf101.v18.rogue101.game.IGame;
|
||||
import inf101.v18.rogue101.game.IllegalMoveException;
|
||||
import inf101.v18.rogue101.items.Manga;
|
||||
import inf101.v18.rogue101.objects.IActor;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
import inf101.v18.rogue101.objects.IPlayer;
|
||||
import inf101.v18.rogue101.objects.Wall;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
|
||||
@ -48,6 +46,7 @@ public class GameMap implements IGameMap {
|
||||
|
||||
@Override
|
||||
public void add(ILocation loc, IItem item) {
|
||||
|
||||
// keep track of location of all items
|
||||
items.put(item, loc);
|
||||
// also keep track of whether we need to redraw this cell
|
||||
@ -55,8 +54,26 @@ public class GameMap implements IGameMap {
|
||||
|
||||
// do the actual adding
|
||||
List<IItem> list = grid.get(loc);
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (item.compareTo(list.get(i)) >= 0) {
|
||||
list.add(i, item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
list.add(item);
|
||||
// TODO: should be sorted!
|
||||
}
|
||||
|
||||
public void addRandomItems(ILocation loc) {
|
||||
if (!this.hasActors(loc) && !this.hasWall(loc)) {
|
||||
Random random = new Random();
|
||||
if (random.nextInt(100) < 20) {
|
||||
this.add(loc, new Carrot());
|
||||
}
|
||||
if (random.nextInt(100) < 1) {
|
||||
this.add(loc, new Manga());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -102,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);
|
||||
@ -126,6 +143,88 @@ public class GameMap implements IGameMap {
|
||||
dirtyLocs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws only the tiles visible to the player.
|
||||
*
|
||||
* @param painter
|
||||
* @param printer
|
||||
* @param game
|
||||
*/
|
||||
public void drawVisible(ITurtle painter, Printer printer, IGame game) {
|
||||
Iterable<ILocation> cells;
|
||||
if (Main.MAP_DRAW_ONLY_DIRTY_CELLS) {
|
||||
if (dirtyLocs.isEmpty())
|
||||
return;
|
||||
else
|
||||
cells = dirtyLocs;
|
||||
} else {
|
||||
cells = grid.locations();
|
||||
painter.as(GraphicsContext.class).clearRect(0, 0, getWidth() * printer.getCharWidth(),
|
||||
getHeight() * printer.getCharHeight());
|
||||
printer.clearRegion(1, 1, getWidth(), getHeight());
|
||||
}
|
||||
GraphicsContext ctx = painter.as(GraphicsContext.class);
|
||||
double h = printer.getCharHeight();
|
||||
double w = printer.getCharWidth();
|
||||
if (Main.MAP_AUTO_SCALE_ITEM_DRAW) {
|
||||
ctx.save();
|
||||
ctx.scale(w / h, 1.0);
|
||||
w = h;
|
||||
}
|
||||
try {
|
||||
IPlayer player = null;
|
||||
ILocation playerPos = null;
|
||||
for (ILocation loc : cells) {
|
||||
printer.printAt(loc.getX() + 1, loc.getY() + 1, " ");
|
||||
if (this.hasActors(loc) && this.getActors(loc).get(0) instanceof IPlayer) {
|
||||
player = (IPlayer) this.getActors(loc).get(0);
|
||||
playerPos = loc;
|
||||
}
|
||||
}
|
||||
List<ILocation> positions = getVisible(getNeighbourhood(playerPos,player.getVision()), playerPos);
|
||||
positions.add(playerPos);
|
||||
for (ILocation loc : positions) {
|
||||
List<IItem> list = grid.get(loc);
|
||||
String sym = ".";
|
||||
if (!list.isEmpty()) {
|
||||
if (Main.MAP_DRAW_ONLY_DIRTY_CELLS) {
|
||||
ctx.clearRect(loc.getX() * w, loc.getY() * h, w, h);
|
||||
// ctx.fillRect(loc.getX() * w, loc.getY() * h, w, h);
|
||||
}
|
||||
painter.save();
|
||||
painter.jumpTo((loc.getX() + 0.5) * w, (loc.getY() + 0.5) * h);
|
||||
boolean dontPrint = list.get(0).draw(painter, w, h);
|
||||
painter.restore();
|
||||
if (!dontPrint) {
|
||||
sym = list.get(0).getPrintSymbol();
|
||||
}
|
||||
}
|
||||
printer.printAt(loc.getX() + 1, loc.getY() + 1, sym);
|
||||
}
|
||||
} finally {
|
||||
if (Main.MAP_AUTO_SCALE_ITEM_DRAW) {
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
dirtyLocs.clear();
|
||||
}
|
||||
|
||||
private List<ILocation> getVisible(List<ILocation> neighbours, ILocation loc) {
|
||||
List<ILocation> invalid = new ArrayList<>();
|
||||
for (ILocation neighbour : neighbours) {
|
||||
if (!hasWall(neighbour)) {
|
||||
for (ILocation tile : loc.gridLineTo(neighbour)) {
|
||||
if (hasWall(tile)) {
|
||||
invalid.add(neighbour);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
neighbours.removeAll(invalid);
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IActor> getActors(ILocation loc) {
|
||||
List<IActor> items = new ArrayList<>();
|
||||
@ -241,14 +340,72 @@ public class GameMap implements IGameMap {
|
||||
dirtyLocs.add(loc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ILocation> getNeighbourhood(ILocation loc, int dist) {
|
||||
if (dist < 0 || loc == null)
|
||||
throw new IllegalArgumentException();
|
||||
else if (dist == 0)
|
||||
return new ArrayList<>(); // empty!
|
||||
|
||||
// TODO: implement this!
|
||||
throw new UnsupportedOperationException();
|
||||
@Override
|
||||
public List<ILocation> getNeighbourhood(ILocation loc, int dist) {
|
||||
if (dist < 0 || loc == null) {
|
||||
throw new IllegalArgumentException();
|
||||
} else if (dist == 0) {
|
||||
return new ArrayList<>(); // empty!
|
||||
}
|
||||
List<ILocation> neighbours = new ArrayList<>();
|
||||
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));
|
||||
}
|
||||
if (grid.isValid(x, bottomY)) {
|
||||
neighbours.add(getLocation(x, bottomY));
|
||||
}
|
||||
}
|
||||
for (int y = topY; y <= bottomY; y++) {
|
||||
if (grid.isValid(leftX, y)) {
|
||||
neighbours.add(getLocation(leftX, y));
|
||||
}
|
||||
if (grid.isValid(rightX, y)) {
|
||||
neighbours.add(getLocation(rightX, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes in a direction, and saves all locations it passes to a list.
|
||||
*
|
||||
* @param locations Target list
|
||||
* @param loc The location to start from
|
||||
* @param dir Which direction to go
|
||||
* @param max Maximum amount of steps
|
||||
*/
|
||||
private void addLoc(List<ILocation> locations, ILocation loc, GridDirection dir, int max) {
|
||||
for (int j = 0; j < max; j++) {
|
||||
locations.add(loc);
|
||||
if (loc.canGo(dir)) {
|
||||
loc = loc.go(dir);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes a set amount of steps in a set direction, from a location, and returns the new location.
|
||||
*
|
||||
* @param loc Start location
|
||||
* @param dir Direction to go
|
||||
* @param max Maximum amount of steps
|
||||
* @return The new location
|
||||
*/
|
||||
private ILocation goTo(ILocation loc, GridDirection dir, int max) {
|
||||
for (int j = 0; j < max; j++) {
|
||||
loc = loc.go(dir);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
#. ...R..C. ..R.R..........C.RC....... #
|
||||
#..C.....R..... ........RR R..R.....R..#
|
||||
#...R..R.R..............R .R..R........#
|
||||
#.R.....R........RRR.......R.. .C....R.#
|
||||
#.R.....R...M....RRR.......R.. .C....R.#
|
||||
#.C.. ..R. .....R.RC..C....R...R..C. .#
|
||||
#. R..............R R..R........C.....R#
|
||||
#........###############################
|
||||
|
21
src/inf101/v18/rogue101/map/maps/testmap.txt
Normal file
21
src/inf101/v18/rogue101/map/maps/testmap.txt
Normal file
@ -0,0 +1,21 @@
|
||||
40 20
|
||||
########################################
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# G G #
|
||||
# #
|
||||
############### # #
|
||||
# # #
|
||||
# S # #
|
||||
# @ ######## #########
|
||||
# # #
|
||||
# # #
|
||||
# # #
|
||||
# G #
|
||||
# G #
|
||||
# c #
|
||||
# ####
|
||||
# # B#
|
||||
# G #
|
||||
########################################
|
@ -21,4 +21,20 @@ public interface IActor extends IItem {
|
||||
* the target)
|
||||
*/
|
||||
int getDamage();
|
||||
|
||||
/**
|
||||
* How many tiles the IActor is able to see in each direction.
|
||||
*
|
||||
* @return Number of tiles
|
||||
*/
|
||||
default int getVision() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an item of the specified type, if the actor has the item.
|
||||
*
|
||||
* @return An IItem or null
|
||||
*/
|
||||
IItem getItem(Class<?> type);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ public interface IPlayer extends IActor {
|
||||
*
|
||||
* @param game
|
||||
* Game, for interacting with the world
|
||||
* @return True if the player has done anything consuming a turn. False otherwise
|
||||
*/
|
||||
void keyPressed(IGame game, KeyCode key);
|
||||
boolean keyPressed(IGame game, KeyCode key);
|
||||
}
|
||||
|
351
src/inf101/v18/rogue101/objects/Player.java
Normal file
351
src/inf101/v18/rogue101/objects/Player.java
Normal file
@ -0,0 +1,351 @@
|
||||
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.*;
|
||||
import inf101.v18.rogue101.shared.NPC;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Player implements IPlayer {
|
||||
private int hp = getMaxHealth();
|
||||
private final Backpack equipped = new Backpack();
|
||||
// True if the player wants to pick up something using the digit keys
|
||||
private boolean dropping = false;
|
||||
// True if the player wants to drop something using the digit keys
|
||||
private boolean picking = false;
|
||||
private boolean writing = false;
|
||||
private boolean exploringChest = false;
|
||||
private String text = "";
|
||||
private String name = "Player";
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(IGame game, KeyCode key) {
|
||||
boolean turnConsumed = false;
|
||||
if (writing) {
|
||||
write(game, key);
|
||||
return false;
|
||||
}
|
||||
if (key == KeyCode.LEFT || key == KeyCode.A) {
|
||||
tryToMove(game, GridDirection.WEST);
|
||||
turnConsumed = true;
|
||||
} else if (key == KeyCode.RIGHT || key == KeyCode.D) {
|
||||
tryToMove(game, GridDirection.EAST);
|
||||
turnConsumed = true;
|
||||
} else if (key == KeyCode.UP || key == KeyCode.W) {
|
||||
tryToMove(game, GridDirection.NORTH);
|
||||
turnConsumed = true;
|
||||
} else if (key == KeyCode.DOWN || key == KeyCode.S) {
|
||||
tryToMove(game, GridDirection.SOUTH);
|
||||
turnConsumed = true;
|
||||
} else if (key == KeyCode.E) {
|
||||
turnConsumed = pickUpInit(game);
|
||||
} else if (key == KeyCode.Q) {
|
||||
turnConsumed = dropInit(game);
|
||||
} 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 (dropping) {
|
||||
drop(game, keyValue - 1);
|
||||
dropping = false;
|
||||
turnConsumed = true;
|
||||
} else if (picking) {
|
||||
pickUp(game, keyValue - 1);
|
||||
picking = false;
|
||||
turnConsumed = true;
|
||||
} else if (exploringChest) {
|
||||
loot(game, keyValue - 1);
|
||||
exploringChest = false;
|
||||
turnConsumed = true;
|
||||
}
|
||||
}
|
||||
} else if (key == KeyCode.N) {
|
||||
game.displayMessage("Please enter your name: ");
|
||||
writing = true;
|
||||
} else if (key == KeyCode.R) {
|
||||
IItem item = getItem(IRangedWeapon.class);
|
||||
if (item == null) {
|
||||
game.displayMessage("You do not have a ranged weapon.");
|
||||
} else {
|
||||
turnConsumed = NPC.tryAttackRanged(game, 3);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
showStatus(game);
|
||||
return turnConsumed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets the user write his/her name.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @param key The key pressed
|
||||
*/
|
||||
private void write(IGame game, KeyCode key) {
|
||||
if (key == KeyCode.BACK_SPACE) {
|
||||
text = text.substring(0, text.length() - 1);
|
||||
game.displayMessage("Please enter your name: " + text);
|
||||
} else if (key != KeyCode.ENTER) {
|
||||
text += key.toString();
|
||||
game.displayMessage("Please enter your name: " + text);
|
||||
} else {
|
||||
name = text.toLowerCase();
|
||||
text = "";
|
||||
game.displayMessage("Name set.");
|
||||
writing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the picking up of an item, and does what is needed.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @return True if a turn was consumed. False otherwise
|
||||
*/
|
||||
private boolean pickUpInit(IGame game) {
|
||||
List<IItem> items = game.getLocalItems();
|
||||
if (items.size() < 1) {
|
||||
game.displayMessage("There is nothing to pick up");
|
||||
} else {
|
||||
if (items.get(0) instanceof IStatic && items.get(0) instanceof IContainer) { //Static items are always the biggest (and hopefully the only) item on a tile.
|
||||
openChest(game, items);
|
||||
} else {
|
||||
if (items.size() == 1) {
|
||||
pickUp(game, 0);
|
||||
return true;
|
||||
} else {
|
||||
StringBuilder msg = new StringBuilder("Items on this tile:");
|
||||
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());
|
||||
picking = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void openChest(IGame game, List<IItem> items) {
|
||||
IStatic item = (IStatic)items.get(0);
|
||||
StringBuilder msg = new StringBuilder(item.getInteractMessage());
|
||||
IContainer container = (IContainer) item;
|
||||
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());
|
||||
exploringChest = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialized the dropping of an item, and does what is needed.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @return True if a turn was consumed. False otherwise
|
||||
*/
|
||||
private boolean dropInit(IGame game) {
|
||||
if (equipped.getContent().size() == 1) {
|
||||
drop(game, 0);
|
||||
return true;
|
||||
} else if (equipped.getContent().size() < 1) {
|
||||
game.displayMessage("You have nothing to drop");
|
||||
} else {
|
||||
StringBuilder msg = new StringBuilder("Items to drop:");
|
||||
for (int i = 0; i < equipped.getContent().size(); i++) {
|
||||
msg.append(" [").append(i + 1).append("] ").append(firstCharToUpper(equipped.get(i).getName()));
|
||||
}
|
||||
game.displayMessage(msg.toString());
|
||||
dropping = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks up an item at index i.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @param i The wanted index
|
||||
*/
|
||||
private void pickUp(IGame game, int i) {
|
||||
if (!equipped.isFull()) {
|
||||
List<IItem> items = game.getLocalItems();
|
||||
if (items.size() >= i) {
|
||||
IItem pickedUp = game.pickUp(items.get(i));
|
||||
if (pickedUp != null) {
|
||||
equipped.add(pickedUp);
|
||||
game.displayMessage("Picked up " + pickedUp.getName());
|
||||
} else {
|
||||
game.displayMessage("The item could not be picked up.");
|
||||
}
|
||||
} else {
|
||||
game.displayMessage("That item does not exist.");
|
||||
}
|
||||
} else {
|
||||
game.displayMessage("Your inventory is full.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an item from a chest, and gives it to the player.
|
||||
*/
|
||||
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;
|
||||
IItem loot = container.getContent().get(i);
|
||||
equipped.add(loot);
|
||||
container.getContent().remove(i);
|
||||
game.displayMessage("Looted " + loot.getName());
|
||||
} else {
|
||||
game.displayMessage("It seems you are trying to loot a chest, without a chest nearby.");
|
||||
}
|
||||
} else {
|
||||
game.displayMessage("Your inventory is full.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops an item at index i.
|
||||
*
|
||||
* @param game An IGame object
|
||||
* @param i The wanted index
|
||||
*/
|
||||
private void drop(IGame game, int i) {
|
||||
if (!equipped.isEmpty() && equipped.size() > i) {
|
||||
if (game.drop(equipped.get(i))) {
|
||||
equipped.remove(i);
|
||||
game.displayMessage("Item dropped.");
|
||||
} else {
|
||||
game.displayMessage("The ground rejected the item.");
|
||||
}
|
||||
} else {
|
||||
game.displayMessage("You have nothing to drop.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status bar with the Player's current stats.
|
||||
*
|
||||
* @param game An IGame object
|
||||
*/
|
||||
private void showStatus(IGame game) {
|
||||
List<String> items = new ArrayList<>();
|
||||
for (IItem item : equipped.getContent()) {
|
||||
String name = item.getName();
|
||||
if (name != null) {
|
||||
items.add(firstCharToUpper(name));
|
||||
}
|
||||
}
|
||||
//TODO: Add item bonuses to visible stats.
|
||||
game.formatStatus("HP: %d/%d ATK: %d DEF: %s DMG: %s INV: %s", hp, getMaxHealth(), getAttack(), getDefence(), getDamage(), String.join(",", items));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the first character in a string to uppercase.
|
||||
*
|
||||
* @param input The input string
|
||||
* @return The input string with the first character uppercased
|
||||
*/
|
||||
private String firstCharToUpper(String input) {
|
||||
if (input.length() < 1) {
|
||||
return input;
|
||||
} else {
|
||||
return Character.toUpperCase(input.charAt(0)) + input.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryToMove(IGame game, GridDirection dir) {
|
||||
ILocation loc = game.getLocation();
|
||||
if (game.canGo(dir)) {
|
||||
game.move(dir);
|
||||
} else if (loc.canGo(dir) && game.getMap().hasActors(loc.go(dir))) {
|
||||
NPC.playSound("audio/Sword Swing-SoundBible.com-639083727.wav");
|
||||
game.attack(dir, game.getMap().getActors(loc.go(dir)).get(0));
|
||||
} else {
|
||||
game.displayMessage("Umm, it is not possible to move in that direction.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttack() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDamage() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItem getItem(Class<?> type) {
|
||||
for (IItem item : equipped.getContent()) {
|
||||
if (type.isInstance(item)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentHealth() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefence() {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return firstCharToUpper(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrintSymbol() {
|
||||
return "\u001b[96m" + "@" + "\u001b[0m";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "@";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleDamage(IGame game, IItem source, int amount) {
|
||||
hp -= amount;
|
||||
showStatus(game);
|
||||
if (hp < 1) {
|
||||
game.displayStatus("Game Over");
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVision() {
|
||||
//TODO: Increase vision based on equipped items
|
||||
return 3;
|
||||
}
|
||||
}
|
171
src/inf101/v18/rogue101/shared/NPC.java
Normal file
171
src/inf101/v18/rogue101/shared/NPC.java
Normal file
@ -0,0 +1,171 @@
|
||||
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.objects.IActor;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
import inf101.v18.rogue101.states.Occupation;
|
||||
import javafx.scene.media.Media;
|
||||
import javafx.scene.media.MediaPlayer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A holder class for methods used by IActors.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a ranged attack on the closest actor (if any) observable by the current actor.
|
||||
*
|
||||
* @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());
|
||||
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) <= range && !actor.isDestroyed()) {
|
||||
game.rangedAttack(dir, actor);
|
||||
return true;
|
||||
} else if (game.canGo(dir)) {
|
||||
game.move(dir);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find and reach an item of a specified class.
|
||||
*
|
||||
* @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, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasItem) {
|
||||
ILocation current = game.getLocation();
|
||||
GridDirection dir = game.locationDirection(current, neighbour);
|
||||
if (game.canGo(dir)) {
|
||||
game.move(dir);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
} else if (dir == GridDirection.NORTH) {
|
||||
return GridDirection.SOUTH;
|
||||
} else if (dir == GridDirection.WEST) {
|
||||
return GridDirection.EAST;
|
||||
} else {
|
||||
return GridDirection.WEST;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
mediaPlayer.play();
|
||||
}
|
||||
}
|
16
src/inf101/v18/rogue101/states/Age.java
Normal file
16
src/inf101/v18/rogue101/states/Age.java
Normal file
@ -0,0 +1,16 @@
|
||||
package inf101.v18.rogue101.states;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* An enum to distinguish different enemies of the same type.
|
||||
*/
|
||||
public enum Age {
|
||||
TODDLER, CHILD, TEEN, ADULT, ELDER;
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
public static Age getRandom() {
|
||||
return values()[random.nextInt(values().length)];
|
||||
}
|
||||
}
|
16
src/inf101/v18/rogue101/states/Occupation.java
Normal file
16
src/inf101/v18/rogue101/states/Occupation.java
Normal file
@ -0,0 +1,16 @@
|
||||
package inf101.v18.rogue101.states;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* An enum to distinguish different enemies of the same type.
|
||||
*/
|
||||
public enum Occupation {
|
||||
KNIGHT, MAGE, BOWSMAN;
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
public static Occupation getRandom() {
|
||||
return values()[random.nextInt(values().length)];
|
||||
}
|
||||
}
|
16
src/inf101/v18/rogue101/states/Personality.java
Normal file
16
src/inf101/v18/rogue101/states/Personality.java
Normal file
@ -0,0 +1,16 @@
|
||||
package inf101.v18.rogue101.states;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* An enum to distinguish different enemies of the same type.
|
||||
*/
|
||||
public enum Personality {
|
||||
AGRESSIVE, CALM, AFRAID;
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
public static Personality getRandom() {
|
||||
return values()[random.nextInt(values().length)];
|
||||
}
|
||||
}
|
@ -2,19 +2,111 @@ package inf101.v18.rogue101.tests;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
import org.junit.Test;
|
||||
|
||||
import inf101.v18.grid.ILocation;
|
||||
import inf101.v18.rogue101.map.GameMap;
|
||||
|
||||
class GameMapTest {
|
||||
import java.util.List;
|
||||
|
||||
public class GameMapTest {
|
||||
|
||||
@Test
|
||||
void testSortedAdd() {
|
||||
public void testSortedAdd() {
|
||||
GameMap gameMap = new GameMap(20, 20);
|
||||
ILocation location = gameMap.getLocation(10, 10);
|
||||
// TODO:
|
||||
fail("Not yet implemented");
|
||||
for (int i = 0; i < 30; i++) {
|
||||
gameMap.addRandomItems(location);
|
||||
}
|
||||
List<IItem> items = gameMap.getAll(location);
|
||||
for (int i = 0; i < items.size() - 1; i++) {
|
||||
assertTrue(items.get(i).compareTo(items.get(i + 1)) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNeighbours() {
|
||||
GameMap gameMap = new GameMap(20, 20);
|
||||
ILocation location = gameMap.getLocation(10, 10);
|
||||
|
||||
List<ILocation> neighbours = gameMap.getNeighbourhood(location, 1);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 1);
|
||||
}
|
||||
assertEquals(8, neighbours.size());
|
||||
|
||||
neighbours = gameMap.getNeighbourhood(location, 2);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 2);
|
||||
}
|
||||
assertEquals(24, neighbours.size());
|
||||
|
||||
neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(48, neighbours.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeighboursOutOfBounds() {
|
||||
GameMap gameMap = new GameMap(20, 20);
|
||||
|
||||
ILocation location = gameMap.getLocation(0, 0);
|
||||
List<ILocation> neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(15, neighbours.size());
|
||||
|
||||
location = gameMap.getLocation(19, 0);
|
||||
neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(15, neighbours.size());
|
||||
|
||||
location = gameMap.getLocation(19, 19);
|
||||
neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(15, neighbours.size());
|
||||
|
||||
location = gameMap.getLocation(0, 19);
|
||||
neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(15, neighbours.size());
|
||||
|
||||
location = gameMap.getLocation(0, 10);
|
||||
neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(27, neighbours.size());
|
||||
|
||||
location = gameMap.getLocation(19, 10);
|
||||
neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(27, neighbours.size());
|
||||
|
||||
location = gameMap.getLocation(10, 0);
|
||||
neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(27, neighbours.size());
|
||||
|
||||
location = gameMap.getLocation(10, 19);
|
||||
neighbours = gameMap.getNeighbourhood(location, 3);
|
||||
for (ILocation neighbour : neighbours) {
|
||||
assertTrue(location.gridDistanceTo(neighbour) <= 3);
|
||||
}
|
||||
assertEquals(27, neighbours.size());
|
||||
}
|
||||
}
|
||||
|
@ -2,41 +2,97 @@ package inf101.v18.rogue101.tests;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
|
||||
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.map.GameMap;
|
||||
import inf101.v18.rogue101.objects.IItem;
|
||||
import inf101.v18.rogue101.objects.IPlayer;
|
||||
import javafx.scene.input.KeyCode;
|
||||
|
||||
class PlayerTest {
|
||||
public static String TEST_MAP = "40 5\n" //
|
||||
+ "########################################\n" //
|
||||
+ "#...... ..C.R ......R.R......... ..R...#\n" //
|
||||
+ "#.R@R...... ..........RC..R...... ... .#\n" //
|
||||
+ "#... ..R........R......R. R........R.RR#\n" //
|
||||
+ "########################################\n" //
|
||||
;
|
||||
public class PlayerTest {
|
||||
|
||||
@Test
|
||||
void testPlayer1() {
|
||||
// new game with our test map
|
||||
Game game = new Game(TEST_MAP);
|
||||
// pick (3,2) as the "current" position; this is where the player is on the
|
||||
// test map, so it'll set up the player and return it
|
||||
IPlayer player = (IPlayer) game.setCurrent(3, 2);
|
||||
|
||||
|
||||
// find players location
|
||||
public void testOutOfBounds() {
|
||||
String NO_WALLS_MAP = "1 1\n"
|
||||
+ "@\n";
|
||||
Game game = new Game(NO_WALLS_MAP);
|
||||
IPlayer player = (IPlayer) game.setCurrent(0, 0);
|
||||
ILocation loc = game.getLocation();
|
||||
// press "UP" key
|
||||
player.keyPressed(game, KeyCode.UP);
|
||||
// see that we moved north
|
||||
assertEquals(loc.go(GridDirection.NORTH), game.getLocation());
|
||||
player.keyPressed(game, KeyCode.LEFT);
|
||||
assertEquals(loc, game.getLocation());
|
||||
}
|
||||
|
||||
/*@Test
|
||||
public void testActor() {
|
||||
String RABBIT_MAP = "5 5\n"
|
||||
+ "#####\n"
|
||||
+ "#RRR#\n"
|
||||
+ "#R@R#\n"
|
||||
+ "#RRR#\n"
|
||||
+ "#####\n";
|
||||
Game game = new Game(RABBIT_MAP);
|
||||
IPlayer player = (IPlayer) game.setCurrent(2, 2);
|
||||
ILocation loc = game.getLocation();
|
||||
player.keyPressed(game, KeyCode.LEFT);
|
||||
assertEquals(loc, game.getLocation());
|
||||
player.keyPressed(game, KeyCode.RIGHT);
|
||||
assertEquals(loc, game.getLocation());
|
||||
player.keyPressed(game, KeyCode.UP);
|
||||
assertEquals(loc, game.getLocation());
|
||||
player.keyPressed(game, KeyCode.DOWN);
|
||||
assertEquals(loc, game.getLocation());
|
||||
}*/ //TODO: Fix error when playing sound
|
||||
|
||||
@Test
|
||||
public void testItem() {
|
||||
String CARROT_MAP = "5 5\n"
|
||||
+ "#####\n"
|
||||
+ "#CCC#\n"
|
||||
+ "#C@C#\n"
|
||||
+ "#CCC#\n"
|
||||
+ "#####\n";
|
||||
Game game = new Game(CARROT_MAP);
|
||||
IPlayer player = (IPlayer) game.setCurrent(2, 2);
|
||||
ILocation loc = game.getLocation();
|
||||
player.keyPressed(game, KeyCode.RIGHT);
|
||||
assertEquals(loc.go(GridDirection.EAST), game.getLocation());
|
||||
game.doTurn();
|
||||
player.keyPressed(game, KeyCode.LEFT);
|
||||
game.doTurn();
|
||||
player.keyPressed(game, KeyCode.LEFT);
|
||||
assertEquals(loc.go(GridDirection.WEST), game.getLocation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWallsAndKeys() { //This probably seems a little overkill, but we need to check all keys.
|
||||
String EMPTY_MAP = "5 5\n"
|
||||
+ "#####\n"
|
||||
+ "# #\n"
|
||||
+ "# @ #\n"
|
||||
+ "# #\n"
|
||||
+ "#####\n";
|
||||
Game game = new Game(EMPTY_MAP);
|
||||
IPlayer player = (IPlayer) game.setCurrent(2, 2);
|
||||
ILocation loc = game.getLocation();
|
||||
player.keyPressed(game, KeyCode.UP);
|
||||
game.doTurn();
|
||||
player.keyPressed(game, KeyCode.UP);
|
||||
game.doTurn();
|
||||
assertEquals(loc.go(GridDirection.NORTH), game.getLocation());
|
||||
player.keyPressed(game, KeyCode.DOWN);
|
||||
game.doTurn();
|
||||
player.keyPressed(game, KeyCode.RIGHT);
|
||||
game.doTurn();
|
||||
assertEquals(loc.go(GridDirection.EAST), game.getLocation());
|
||||
player.keyPressed(game, KeyCode.LEFT);
|
||||
game.doTurn();
|
||||
player.keyPressed(game, KeyCode.DOWN);
|
||||
game.doTurn();
|
||||
assertEquals(loc.go(GridDirection.SOUTH), game.getLocation());
|
||||
player.keyPressed(game, KeyCode.UP);
|
||||
game.doTurn();
|
||||
player.keyPressed(game, KeyCode.LEFT);
|
||||
assertEquals(loc.go(GridDirection.WEST), game.getLocation());
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +82,6 @@ public class DoubleGenerator extends AbstractGenerator<Double> {
|
||||
public Double generate(Random rng) {
|
||||
double d = rng.nextDouble();
|
||||
|
||||
double r = minValue + (d * diff);
|
||||
|
||||
return r;
|
||||
return minValue + (d * diff);
|
||||
}
|
||||
}
|
||||
|
@ -73,8 +73,6 @@ public class GridGenerator<T> extends AbstractGenerator<IGrid<T>> {
|
||||
int w = widthGenerator.generate(r);
|
||||
int h = heightGenerator.generate(r);
|
||||
|
||||
IGrid<T> grid = new MyGrid<>(w, h, (l) -> elementGenerator.generate(r));
|
||||
|
||||
return grid;
|
||||
return new MyGrid<>(w, h, (l) -> elementGenerator.generate(r));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user