├── settings.gradle ├── src ├── main │ ├── resources │ │ ├── application-prod.properties │ │ ├── application-dev.properties │ │ ├── application.properties │ │ └── static │ │ │ └── style.css │ └── java │ │ └── pl │ │ └── uj │ │ └── io │ │ └── cuteanimals │ │ ├── model │ │ ├── GameState.java │ │ ├── ItemClass.java │ │ ├── interfaces │ │ │ ├── IAbility.java │ │ │ ├── RandomInteger.java │ │ │ ├── PlayerClass.java │ │ │ ├── IResult.java │ │ │ ├── ContainerArgumentAction.java │ │ │ ├── ICharacter.java │ │ │ ├── IPlayer.java │ │ │ ├── ArgumentlessAction.java │ │ │ ├── IEquipment.java │ │ │ ├── IAction.java │ │ │ ├── IAttributes.java │ │ │ ├── IItem.java │ │ │ ├── ArgumentAction.java │ │ │ └── ILocation.java │ │ ├── ItemType.java │ │ ├── Color.java │ │ ├── fight │ │ │ ├── IFightState.java │ │ │ ├── FightState.java │ │ │ ├── ExplorationState.java │ │ │ ├── FightLog.java │ │ │ ├── BlockState.java │ │ │ ├── AttackState.java │ │ │ └── FightManager.java │ │ ├── RandomIntegerImpl.java │ │ ├── Monk.java │ │ ├── Archer.java │ │ ├── Warrior.java │ │ ├── Slave.java │ │ ├── Monster.java │ │ ├── Result.java │ │ ├── CompoundResult.java │ │ ├── NPCAttributes.java │ │ ├── Backpack.java │ │ ├── PlayerBackpack.java │ │ ├── DefaultLocation.java │ │ ├── GameInstance.java │ │ ├── NPC.java │ │ ├── entity │ │ │ ├── Attributes.java │ │ │ └── Item.java │ │ ├── ArmorBackpack.java │ │ ├── Player.java │ │ └── PlayerAttributes.java │ │ ├── exception │ │ └── InvalidCommandException.java │ │ ├── repository │ │ ├── GeneralRepository.java │ │ ├── ItemsRepository.java │ │ └── AttributesRepository.java │ │ ├── CuteAnimalsApplication.java │ │ ├── action │ │ ├── Block.java │ │ ├── StandardAttack.java │ │ ├── ShowStats.java │ │ ├── ShowArmor.java │ │ ├── MessageAction.java │ │ ├── SuicideAction.java │ │ ├── CastAction.java │ │ ├── end │ │ │ └── EndGameAction.java │ │ ├── InvestigateAction.java │ │ ├── ActionBuilder.java │ │ ├── ShowAbilities.java │ │ ├── ShowBackpack.java │ │ ├── entrance │ │ │ └── EntranceRemoveHealthAction.java │ │ ├── PickWarrior.java │ │ ├── PickArcher.java │ │ ├── PickMonk.java │ │ ├── FightAction.java │ │ ├── GoAction.java │ │ ├── UseAction.java │ │ ├── ThrowAwayAction.java │ │ ├── TalkAction.java │ │ ├── PickupAction.java │ │ ├── UnequipItem.java │ │ ├── BuffCharacter.java │ │ ├── EquipItem.java │ │ └── ability │ │ │ ├── Heal.java │ │ │ ├── Bullseye.java │ │ │ ├── Focus.java │ │ │ └── DoubleDown.java │ │ ├── controller │ │ ├── ItemController.java │ │ └── GameController.java │ │ ├── plot │ │ └── actions │ │ │ ├── DungeonInvestigateAction.java │ │ │ └── DungeonEntranceGoAction.java │ │ ├── service │ │ ├── GameService.java │ │ └── AttributesService.java │ │ ├── interpreter │ │ └── Expression.java │ │ └── location │ │ └── LocationBuilder.java └── test │ ├── resources │ └── application.properties │ └── java │ └── pl │ └── uj │ └── io │ └── cuteanimals │ ├── CuteAnimalsApplicationTests.java │ ├── model │ ├── interfaces │ │ └── RandomIntegerTest.java │ ├── SlaveTest.java │ ├── entity │ │ └── AttributesTest.java │ ├── MonkTest.java │ ├── MonsterTest.java │ ├── ArcherTest.java │ ├── WarriorTest.java │ ├── ResultTest.java │ ├── NPCTest.java │ ├── fight │ │ └── FightManagerTest.java │ ├── NPCAttributesTest.java │ ├── BackpackTest.java │ ├── GameInstanceTest.java │ ├── PlayerBackpackTest.java │ ├── DefaultLocationTest.java │ └── PlayerTest.java │ ├── action │ ├── InvestigateActionTest.java │ ├── entrance │ │ └── EntranceRemoveHealthActionTest.java │ ├── ShowArmorTest.java │ ├── ShowAbilitiesTest.java │ ├── ShowStatsTest.java │ ├── ShowBackpackTest.java │ └── ability │ │ └── FocusTest.java │ ├── plot │ └── actions │ │ ├── DungeonEntranceGoActionTest.java │ │ └── DungeonInvestigateActionTest.java │ ├── service │ ├── AttributesServiceTest.java │ └── ItemServiceTest.java │ ├── controller │ └── ItemControllerTest.java │ └── interpreter │ └── InterpreterTest.java ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── staticCodeAnalysis.gradle └── static-code-analysis │ └── pmd │ └── ruleset.xml ├── Dockerfile ├── assets └── UML.md ├── LICENSE ├── HELP.md ├── .github └── workflows │ ├── release.yml │ └── build.yml ├── gradlew.bat └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'cuteanimals' 2 | -------------------------------------------------------------------------------- /src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.hibernate.ddl-auto=update 2 | debug=false 3 | -------------------------------------------------------------------------------- /src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.hibernate.ddl-auto=create-drop 2 | debug=true 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hjaremko/cute-animals/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect 2 | spring.jpa.hibernate.ddl-auto=update 3 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/GameState.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | public enum GameState { 4 | EXPLORATION, 5 | FIGHT, 6 | LIMBO 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/ItemClass.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | public enum ItemClass { 4 | ANY, 5 | MONK, 6 | WARRIOR, 7 | ARCHER 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/IAbility.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | public interface IAbility { 4 | String getDescription(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/ItemType.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | public enum ItemType { 4 | WEAPON, 5 | ARMOR, 6 | USABLE, 7 | NEUTRAL 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/RandomInteger.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | public interface RandomInteger { 4 | int nextInt(int max); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Color.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | public enum Color { 4 | NORMAL, 5 | BOLD, 6 | GREEN, 7 | RED, 8 | YELLOW 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect 2 | spring.application.name=cuteanimals 3 | spring.active.profiles=prod 4 | logging.file=logs/cuteanimals.log 5 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/fight/IFightState.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.fight; 2 | 3 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 4 | 5 | public interface IFightState { 6 | IResult attack(); 7 | 8 | IResult contrAttack(); 9 | } 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun May 10 12:48:22 CEST 2020 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11-jdk-slim 2 | RUN useradd --user-group --system --create-home --no-log-init spring 3 | USER spring 4 | ARG JAR_FILE=build/libs/* 5 | COPY ${JAR_FILE} io-rpg.jar 6 | CMD java -Dspring.profiles.active=prod -Djava.security.egd=file:/dev/./urandom -Dserver.port=$PORT -jar /io-rpg.jar 7 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/exception/InvalidCommandException.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.exception; 2 | 3 | /** Thrown in case of invalid user input */ 4 | public class InvalidCommandException extends Exception { 5 | public InvalidCommandException(String errorMessage) { 6 | super(errorMessage); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/CuteAnimalsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class CuteAnimalsApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/repository/GeneralRepository.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.repository; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | public interface GeneralRepository { 7 | List findAll(); 8 | 9 | T save(T entity); 10 | 11 | Optional findById(Long id); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | text-align: center; 3 | background: #181A1B; 4 | margin: 40px auto; 5 | max-width: 1000px; 6 | font: 20px/30px 'Courier New'; 7 | color: #DCDCDC; 8 | padding: 0 10px; 9 | line-height: 1.6; 10 | } 11 | 12 | textarea { 13 | padding: 5px 10px; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/PlayerClass.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import pl.uj.io.cuteanimals.model.ItemClass; 6 | 7 | public interface PlayerClass { 8 | Map getAbilities(); 9 | 10 | List getAcceptedItemClasses(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/fight/FightState.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.fight; 2 | 3 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 4 | 5 | public abstract class FightState implements IFightState { 6 | protected final IPlayer player; 7 | 8 | public FightState(IPlayer player) { 9 | this.player = player; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/repository/ItemsRepository.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | import pl.uj.io.cuteanimals.model.entity.Item; 6 | 7 | @Repository 8 | public interface ItemsRepository extends JpaRepository, GeneralRepository {} 9 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/CuteAnimalsApplication.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CuteAnimalsApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(CuteAnimalsApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/repository/AttributesRepository.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | import pl.uj.io.cuteanimals.model.entity.Attributes; 6 | 7 | @Repository 8 | public interface AttributesRepository 9 | extends JpaRepository, GeneralRepository {} 10 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/IResult.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import pl.uj.io.cuteanimals.model.Color; 4 | 5 | /** 6 | * Encapsulates Actions' output. This should be printed to player. 7 | * 8 | * @version %I% 9 | * @since 0.0.1-SNAPSHOT 10 | */ 11 | public interface IResult { 12 | String getMessage(); 13 | 14 | void setMessage(String message); 15 | 16 | Color getColor(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/RandomIntegerImpl.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.Random; 4 | import org.springframework.stereotype.Component; 5 | import pl.uj.io.cuteanimals.model.interfaces.RandomInteger; 6 | 7 | @Component 8 | public class RandomIntegerImpl implements RandomInteger { 9 | private final Random random = new Random(); 10 | 11 | public int nextInt(int max) { 12 | return random.nextInt(max); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /gradle/staticCodeAnalysis.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | } 6 | 7 | apply plugin: 'pmd' 8 | 9 | pmd { 10 | toolVersion = '6.7.0' 11 | ignoreFailures = true 12 | ruleSetFiles = files("${rootGradleDir}/static-code-analysis/pmd/ruleset.xml") 13 | ruleSets = [] 14 | rulePriority = 3 15 | } 16 | 17 | tasks.withType(Pmd) { 18 | reports { 19 | xml.enabled false 20 | html.enabled true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/interfaces/RandomIntegerTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.junit.jupiter.api.Assertions.*; 5 | 6 | import org.junit.jupiter.api.Test; 7 | import pl.uj.io.cuteanimals.model.RandomIntegerImpl; 8 | 9 | class RandomIntegerTest { 10 | 11 | @Test 12 | void nextInt() { 13 | var random = new RandomIntegerImpl(); 14 | assertThat(random.nextInt(10)).isBetween(0, 10); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/ContainerArgumentAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Extends IAction interface with arguments 7 | * 8 | * @version %I% 9 | * @since 0.2.0-SNAPSHOT 10 | */ 11 | public abstract class ContainerArgumentAction extends ArgumentAction { 12 | protected final Map objects; 13 | 14 | public ContainerArgumentAction(Map objects) { 15 | super(); 16 | this.objects = objects; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /assets/UML.md: -------------------------------------------------------------------------------- 1 | # UML (ver 0.2.0) 2 | 3 | ## General 4 | ![General UML](CuteAnimals.svg) 5 | 6 | ## Actions 7 | ![Actions UML](CuteAnimalsActions.svg) 8 | 9 | ## Characters 10 | ![Characters UML](CuteAnimalsCharacters.svg) 11 | 12 | ## Enitities 13 | ![Enitities UML](CuteAnimalsEntities.svg) 14 | 15 | ## Game logic 16 | ![Game logic UML](CuteAnimalsGameLogic.svg) 17 | 18 | ## Interpeter 19 | ![Interpreter UML](CuteAnimalsInterpreter.svg) 20 | 21 | ## Repositories 22 | ![Repositories UML](CuteAnimalsRepositories.svg) 23 | 24 | ## Misc 25 | ![Misc UML](CuteAnimalsMisc.svg) -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Monk.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.action.ability.Heal; 5 | 6 | public class Monk extends Slave { 7 | public Monk() { 8 | super(); 9 | this.abilities.put("heal", new Heal()); 10 | } 11 | 12 | @Override 13 | public String toString() { 14 | return "Monk"; 15 | } 16 | 17 | @Override 18 | public List getAcceptedItemClasses() { 19 | return List.of(ItemClass.MONK, ItemClass.ANY); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/fight/ExplorationState.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.fight; 2 | 3 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 4 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 5 | 6 | public class ExplorationState extends FightState { 7 | public ExplorationState(IPlayer owner) { 8 | super(owner); 9 | } 10 | 11 | @Override 12 | public IResult attack() { 13 | return null; 14 | } 15 | 16 | @Override 17 | public IResult contrAttack() { 18 | return null; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/SlaveTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class SlaveTest { 9 | private Slave slave; 10 | 11 | @BeforeEach 12 | void setUp() { 13 | slave = new Slave(); 14 | } 15 | 16 | @Test 17 | void getAbilities() { 18 | assertThat(slave.getAbilities()).isNotEmpty(); 19 | assertThat(slave.getAbilities()).containsKeys("focus"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Archer.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.action.ability.Bullseye; 5 | 6 | public class Archer extends Slave { 7 | public Archer() { 8 | super(); 9 | this.abilities.put("bullseye", new Bullseye()); 10 | } 11 | 12 | @Override 13 | public String toString() { 14 | return "Archer"; 15 | } 16 | 17 | @Override 18 | public List getAcceptedItemClasses() { 19 | return List.of(ItemClass.ARCHER, ItemClass.ANY); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Warrior.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.action.ability.DoubleDown; 5 | 6 | public class Warrior extends Slave { 7 | public Warrior() { 8 | super(); 9 | this.abilities.put("double down", new DoubleDown()); 10 | } 11 | 12 | @Override 13 | public String toString() { 14 | return "Warrior"; 15 | } 16 | 17 | @Override 18 | public List getAcceptedItemClasses() { 19 | return List.of(ItemClass.WARRIOR, ItemClass.ANY); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/Block.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 6 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 7 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 8 | 9 | public class Block extends ArgumentlessAction { 10 | @Override 11 | public IResult actionBody(IPlayer player) { 12 | return player.getFightManager().block(); 13 | } 14 | 15 | @Override 16 | public List getAcceptableStates() { 17 | return List.of(GameState.FIGHT); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/StandardAttack.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 6 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 7 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 8 | 9 | public class StandardAttack extends ArgumentlessAction { 10 | @Override 11 | public IResult actionBody(IPlayer player) { 12 | return player.getFightManager().attack(); 13 | } 14 | 15 | @Override 16 | public List getAcceptableStates() { 17 | return List.of(GameState.FIGHT); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/entity/AttributesTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.entity; 2 | 3 | import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | public class AttributesTest { 9 | 10 | private Attributes attributes; 11 | 12 | @BeforeEach 13 | private void setup() { 14 | attributes = new Attributes(1, 10, 0, 10, 0, 0); 15 | } 16 | 17 | @Test 18 | public void toStringReturnsProperString() { 19 | var result = attributes.toString(); 20 | var expected = "Health: 10. Level: 10. "; 21 | 22 | assertThat(result).isEqualTo(expected); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/MonkTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class MonkTest { 9 | private Monk m; 10 | 11 | @BeforeEach 12 | void setUp() { 13 | m = new Monk(); 14 | } 15 | 16 | @Test 17 | void testToString() { 18 | assertThat(m.toString()).isEqualTo("Monk"); 19 | } 20 | 21 | @Test 22 | void getAbilities() { 23 | assertThat(m.getAbilities()).isNotEmpty(); 24 | assertThat(m.getAbilities()).containsKeys("focus"); 25 | assertThat(m.getAbilities()).containsKeys("heal"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/MonsterTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | import pl.uj.io.cuteanimals.model.entity.Attributes; 8 | 9 | // Sweet 100% coverage 10 | class MonsterTest { 11 | private Monster mob; 12 | 13 | @BeforeEach 14 | void setUp() { 15 | mob = new Monster("mob", new Attributes(1, 1, 1, 1, 1, 1)); 16 | } 17 | 18 | @Test 19 | void getEquipment() { 20 | assertThat(mob.getEquipment()).isNotNull(); 21 | } 22 | 23 | @Test 24 | void getArmor() { 25 | assertThat(mob.getArmor()).isNull(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/ArcherTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class ArcherTest { 9 | private Archer m; 10 | 11 | @BeforeEach 12 | void setUp() { 13 | m = new Archer(); 14 | } 15 | 16 | @Test 17 | void testToString() { 18 | assertThat(m.toString()).isEqualTo("Archer"); 19 | } 20 | 21 | @Test 22 | void getAbilities() { 23 | assertThat(m.getAbilities()).isNotEmpty(); 24 | assertThat(m.getAbilities()).containsKeys("focus"); 25 | assertThat(m.getAbilities()).containsKeys("bullseye"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/ICharacter.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | /** 4 | * Provides methods to manage character. 5 | * 6 | * @version %I% 7 | * @since 0.0.1-SNAPSHOT 8 | */ 9 | public interface ICharacter { 10 | 11 | /** 12 | * Gives all character's equipment. Includes equipped objects as well as those currently in the 13 | * backpack. 14 | * 15 | * @return List of IEquipment type element. 16 | */ 17 | IEquipment getEquipment(); 18 | 19 | IEquipment getArmor(); 20 | 21 | /** 22 | * Gives characters's current attributes taking account all bonuses. 23 | * 24 | * @return IAttributes type element. 25 | */ 26 | IAttributes getAttributes(); 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/WarriorTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class WarriorTest { 9 | private Warrior m; 10 | 11 | @BeforeEach 12 | void setUp() { 13 | m = new Warrior(); 14 | } 15 | 16 | @Test 17 | void testToString() { 18 | assertThat(m.toString()).isEqualTo("Warrior"); 19 | } 20 | 21 | @Test 22 | void getAbilities() { 23 | assertThat(m.getAbilities()).isNotEmpty(); 24 | assertThat(m.getAbilities()).containsKeys("focus"); 25 | assertThat(m.getAbilities()).containsKeys("double down"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/fight/FightLog.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.fight; 2 | 3 | import pl.uj.io.cuteanimals.model.Color; 4 | import pl.uj.io.cuteanimals.model.Result; 5 | 6 | public class FightLog extends Result { 7 | public FightLog(String message, Color color) { 8 | super(message, color); 9 | 10 | switch (color) { 11 | case GREEN: 12 | this.message = "+ " + message; 13 | break; 14 | case RED: 15 | this.message = "- " + message; 16 | break; 17 | case YELLOW: 18 | case NORMAL: 19 | case BOLD: 20 | this.message = "* " + message; 21 | break; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ShowStats.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 8 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 9 | 10 | /** 11 | * Prints Character's statistics. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | public class ShowStats extends ArgumentlessAction { 17 | @Override 18 | public IResult actionBody(IPlayer player) { 19 | return new Result(player.getAttributes().toString()); 20 | } 21 | 22 | @Override 23 | public List getAcceptableStates() { 24 | return List.of(GameState.EXPLORATION, GameState.FIGHT); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ShowArmor.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 8 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 9 | 10 | /** 11 | * Prints content of Character's armor backpack. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | public class ShowArmor extends ArgumentlessAction { 17 | @Override 18 | public IResult actionBody(IPlayer player) { 19 | return new Result(player.getArmor().showItems()); 20 | } 21 | 22 | @Override 23 | public List getAcceptableStates() { 24 | return List.of(GameState.EXPLORATION, GameState.FIGHT); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/MessageAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 8 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 9 | 10 | /** 11 | * Just printing action, helps parsing and may be used for printing dialogs. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | public class MessageAction extends ArgumentAction { 17 | @Override 18 | protected IResult actionBody(IPlayer player, String object) { 19 | return new Result(getArgs().toString()); 20 | } 21 | 22 | @Override 23 | public List getAcceptableStates() { 24 | return List.of(GameState.EXPLORATION, GameState.FIGHT); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/SuicideAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.Color; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.fight.FightLog; 7 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 9 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 10 | 11 | public class SuicideAction extends ArgumentlessAction { 12 | @Override 13 | protected IResult actionBody(IPlayer player) { 14 | player.getAttributes().addHealth(-player.getAttributes().getHealth()); 15 | return new FightLog(player.toString() + " killed himself.", Color.RED); 16 | } 17 | 18 | @Override 19 | public List getAcceptableStates() { 20 | return List.of(GameState.EXPLORATION, GameState.FIGHT); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/CastAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 8 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 9 | 10 | public class CastAction extends ArgumentAction { 11 | @Override 12 | protected IResult actionBody(IPlayer player, String spellName) { 13 | var toCast = player.getAbilities().get(spellName); 14 | 15 | if (toCast == null) { 16 | return new Result("You don't know how to do '" + spellName + "'."); 17 | } 18 | 19 | return toCast.execute(player); 20 | } 21 | 22 | @Override 23 | public List getAcceptableStates() { 24 | return List.of(GameState.FIGHT); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Slave.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | import pl.uj.io.cuteanimals.action.ability.Focus; 7 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.PlayerClass; 9 | 10 | public class Slave implements PlayerClass { 11 | protected final Map abilities; 12 | 13 | public Slave() { 14 | this.abilities = new HashMap<>(); 15 | this.abilities.put("focus", new Focus()); 16 | } 17 | 18 | @Override 19 | public Map getAbilities() { 20 | return abilities; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "Slave"; 26 | } 27 | 28 | @Override 29 | public List getAcceptedItemClasses() { 30 | return List.of(ItemClass.ANY); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Monster.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 4 | import pl.uj.io.cuteanimals.model.interfaces.ICharacter; 5 | import pl.uj.io.cuteanimals.model.interfaces.IEquipment; 6 | 7 | public class Monster implements ICharacter { 8 | private final IEquipment loots; 9 | private final IAttributes stats; 10 | private final String name; 11 | 12 | public Monster(String name, IAttributes stats) { 13 | this.loots = new Backpack(); 14 | this.stats = stats; 15 | this.name = name; 16 | } 17 | 18 | @Override 19 | public IEquipment getEquipment() { 20 | return loots; 21 | } 22 | 23 | @Override 24 | public IEquipment getArmor() { 25 | return null; 26 | } 27 | 28 | @Override 29 | public IAttributes getAttributes() { 30 | return stats; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/end/EndGameAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action.end; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 8 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 9 | 10 | public class EndGameAction implements IAction { 11 | 12 | @Override 13 | public IResult execute(IPlayer player) { 14 | player.getAttributes().addHealth(-player.getAttributes().getHealth()); 15 | return new Result("\n\nYou ended the game. Congratulations! Thank you for playing :)"); 16 | } 17 | 18 | @Override 19 | public List getArgs() { 20 | return null; 21 | } 22 | 23 | @Override 24 | public void setArgs(List args) {} 25 | 26 | @Override 27 | public List getAcceptableStates() { 28 | return null; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/IPlayer.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import java.util.Map; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.WorldMap; 6 | import pl.uj.io.cuteanimals.model.fight.FightManager; 7 | 8 | public interface IPlayer extends ICharacter { 9 | /** 10 | * Gives result of using specific item. 11 | * 12 | * @param item specifies item to use. 13 | * @return Result type element. 14 | */ 15 | IResult use(IItem item); 16 | 17 | IResult changeLocation(ILocation where); 18 | 19 | ILocation getCurrentLocation(); 20 | 21 | GameState getCurrentGameState(); 22 | 23 | void setGameState(GameState gameState); 24 | 25 | FightManager getFightManager(); 26 | 27 | int takeDamage(int damage); 28 | 29 | Map getAbilities(); 30 | 31 | WorldMap getWorld(); 32 | 33 | void setClass(PlayerClass playerClass); 34 | 35 | PlayerClass getPlayerClass(); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/InvestigateAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 8 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 9 | 10 | /** 11 | * Prints Location's "look around" message. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | public class InvestigateAction extends ArgumentlessAction { 17 | private final String infoMessage; 18 | 19 | public InvestigateAction(String infoMessage) { 20 | super(); 21 | this.infoMessage = infoMessage; 22 | } 23 | 24 | @Override 25 | public IResult actionBody(IPlayer player) { 26 | return new Result(infoMessage); 27 | } 28 | 29 | @Override 30 | public List getAcceptableStates() { 31 | return List.of(GameState.EXPLORATION); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Result.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 4 | 5 | /** 6 | * Basic implementation. 7 | * 8 | * @version %I% 9 | * @since 0.0.1-SNAPSHOT 10 | */ 11 | public class Result implements IResult { 12 | protected String message; 13 | protected Color color; 14 | 15 | public Result(String message) { 16 | this.message = message; 17 | this.color = Color.NORMAL; 18 | } 19 | 20 | public Result(String message, Color color) { 21 | this.message = message; 22 | this.color = color; 23 | } 24 | 25 | @Override 26 | public String getMessage() { 27 | return message; 28 | } 29 | 30 | @Override 31 | public void setMessage(String message) { 32 | this.message = message; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return message; 38 | } 39 | 40 | @Override 41 | public Color getColor() { 42 | return color; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ActionBuilder.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import javax.validation.constraints.NotNull; 6 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 7 | 8 | /** Helper class used to build actions during interpreting */ 9 | public class ActionBuilder { 10 | private IAction action; 11 | private List args; 12 | 13 | public ActionBuilder() { 14 | this.args = new ArrayList<>(); 15 | } 16 | 17 | public ActionBuilder(@NotNull IAction action, @NotNull List args) { 18 | this.action = action; 19 | this.args = args; 20 | } 21 | 22 | public ActionBuilder addAction(@NotNull IAction action) { 23 | this.action = action; 24 | args = action.getArgs(); 25 | return this; 26 | } 27 | 28 | public ActionBuilder addArgs(@NotNull List arg) { 29 | args.addAll(0, arg); 30 | return this; 31 | } 32 | 33 | public IAction collect() { 34 | action.setArgs(args); 35 | return action; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ShowAbilities.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IAbility; 9 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | 12 | public class ShowAbilities extends ArgumentlessAction { 13 | @Override 14 | protected IResult actionBody(IPlayer player) { 15 | return new Result( 16 | player.getAbilities() 17 | .entrySet() 18 | .stream() 19 | .map(a -> a.getKey() + ": " + ((IAbility) a.getValue()).getDescription()) 20 | .collect(Collectors.joining("\n"))); 21 | } 22 | 23 | @Override 24 | public List getAcceptableStates() { 25 | return List.of(GameState.EXPLORATION, GameState.FIGHT); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Hubert Jaremko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/ArgumentlessAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | 7 | /** 8 | * Provides compatibility with ArgumentAction 9 | * 10 | * @version %I% 11 | * @since 0.2.0-SNAPSHOT 12 | */ 13 | public abstract class ArgumentlessAction implements IAction { 14 | /** @return string representation of action arguments, e.g location name or item name */ 15 | @Override 16 | public List getArgs() { 17 | return new ArrayList<>(); 18 | } 19 | 20 | /** @param args string representation of action arguments, e.g location name or item name */ 21 | @Override 22 | public void setArgs(List args) {} 23 | 24 | @Override 25 | public IResult execute(IPlayer player) { 26 | if (!getAcceptableStates().contains(player.getCurrentGameState())) { 27 | return new Result("This isn't the time for that."); 28 | } 29 | 30 | return actionBody(player); 31 | } 32 | 33 | protected abstract IResult actionBody(IPlayer player); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/IEquipment.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Provides methods to manage equipment. 7 | * 8 | * @version %I% 9 | * @since 0.0.1-SNAPSHOT 10 | */ 11 | public interface IEquipment { 12 | 13 | /** 14 | * Returns all of the items present in the equipment. 15 | * 16 | * @return list of IItem objects. 17 | */ 18 | List getItems(); 19 | 20 | /** 21 | * Adds given item to the equipment. 22 | * 23 | * @param item item to add to the equipment. 24 | * @return true if added, otherwise false. 25 | */ 26 | boolean putItem(IItem item); 27 | 28 | /** 29 | * Removed given item from the equipment. 30 | * 31 | * @param item item to remove from the equipment. 32 | * @return true if removed, otherwise false. 33 | */ 34 | boolean removeItem(IItem item); 35 | 36 | /** 37 | * Returns formatted description of equipment contents to show it to the player. 38 | * 39 | * @return description of equipment contents 40 | */ 41 | String showItems(); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ShowBackpack.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.PlayerBackpack; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 9 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 10 | 11 | /** 12 | * Prints Character's backpack items and space remaining. 13 | * 14 | * @version %I% 15 | * @since 0.0.1-SNAPSHOT 16 | */ 17 | public class ShowBackpack extends ArgumentlessAction { 18 | @Override 19 | public IResult actionBody(IPlayer player) { 20 | var spaceLeft = 21 | "Space left: " 22 | + ((PlayerBackpack) player.getEquipment()).getRemainingCapacity() 23 | + "\n"; 24 | return new Result(spaceLeft + player.getEquipment().showItems()); 25 | } 26 | 27 | @Override 28 | public List getAcceptableStates() { 29 | return List.of(GameState.EXPLORATION, GameState.FIGHT); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/IAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | 6 | /** 7 | * Provides method to perform actions. 8 | * 9 | * @version %I% 10 | * @since 0.0.1-SNAPSHOT 11 | */ 12 | public interface IAction { 13 | 14 | /** 15 | * Performs action that can e.g. modify character attributes etc. 16 | * 17 | * @param player specifies character whose state can be modified. 18 | * @return IResult object with information about outcome of the action. 19 | */ 20 | IResult execute(IPlayer player); 21 | 22 | /** @return string representation of action arguments, e.g location name or item name */ 23 | List getArgs(); 24 | 25 | /** @param args string representation of action arguments, e.g location name or item name */ 26 | void setArgs(List args); 27 | 28 | /** 29 | * @return list of states in which action can be performed e.g travelling to another location is 30 | * possible only during EXPLORATION state 31 | */ 32 | List getAcceptableStates(); 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/ResultTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class ResultTest { 9 | private Result result; 10 | 11 | @BeforeEach 12 | void setUp() { 13 | result = new Result("i am result"); 14 | } 15 | 16 | @Test 17 | void getMessage() { 18 | assertThat(result.getMessage()).isEqualTo("i am result"); 19 | assertThat(result.getColor()).isEqualTo(Color.NORMAL); 20 | } 21 | 22 | @Test 23 | void setMessage() { 24 | result.setMessage("oj oj"); 25 | assertThat(result.getMessage()).isEqualTo("oj oj"); 26 | assertThat(result.getColor()).isEqualTo(Color.NORMAL); 27 | } 28 | 29 | @Test 30 | void testToString() { 31 | assertThat(result.toString()).isEqualTo(result.getMessage()); 32 | } 33 | 34 | @Test 35 | void getColor() { 36 | result = new Result("aa", Color.YELLOW); 37 | assertThat(result.getMessage()).isEqualTo("aa"); 38 | assertThat(result.getColor()).isEqualTo(Color.YELLOW); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/entrance/EntranceRemoveHealthAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action.entrance; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.Color; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 9 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 10 | 11 | public class EntranceRemoveHealthAction implements IAction { 12 | private final int healthLoss; 13 | 14 | public EntranceRemoveHealthAction(int healthLoss) { 15 | this.healthLoss = healthLoss; 16 | } 17 | 18 | @Override 19 | public IResult execute(IPlayer player) { 20 | player.getAttributes().addHealth(-healthLoss); 21 | return new Result("(You lose " + healthLoss + " health points).", Color.RED); 22 | } 23 | 24 | @Override 25 | public List getArgs() { 26 | return null; 27 | } 28 | 29 | @Override 30 | public void setArgs(List args) { 31 | // Ignored 32 | } 33 | 34 | @Override 35 | public List getAcceptableStates() { 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/controller/ItemController.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.controller; 2 | 3 | import java.util.List; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import pl.uj.io.cuteanimals.model.entity.Item; 11 | import pl.uj.io.cuteanimals.service.ItemService; 12 | 13 | @RestController 14 | public class ItemController { 15 | private static final Logger logger = LoggerFactory.getLogger(ItemController.class); 16 | 17 | private final ItemService itemService; 18 | 19 | @Autowired 20 | public ItemController(ItemService itemService) { 21 | this.itemService = itemService; 22 | } 23 | 24 | @GetMapping("/items") 25 | public List getAllItems() { 26 | logger.info("Got request for all items"); 27 | return itemService.getAllItems(); 28 | } 29 | 30 | @GetMapping("/items/{id}") 31 | public Item getItem(@PathVariable int id) { 32 | logger.info("Got request for item with id " + id); 33 | return itemService.getItem(id); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/PickWarrior.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.*; 5 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 6 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 7 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 8 | 9 | public class PickWarrior extends ArgumentlessAction { 10 | @Override 11 | protected IResult actionBody(IPlayer player) { 12 | player.setClass(new Warrior()); 13 | player.setGameState(GameState.EXPLORATION); 14 | 15 | return new CompoundResult( 16 | List.of( 17 | new Result( 18 | "You are now a Warrior from Brave Hedgehogs' Clan.\n" 19 | + "An extremely dangerous adventure awaits you, full of unexpected twists.\n" 20 | + "Use your strong body and skill in wielding the sword to overcome all difficulties.\n", 21 | Color.YELLOW), 22 | new Result(player.getCurrentLocation().getDescription()))); 23 | } 24 | 25 | @Override 26 | public List getAcceptableStates() { 27 | return List.of(GameState.LIMBO); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/PickArcher.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.*; 5 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 6 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 7 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 8 | 9 | public class PickArcher extends ArgumentlessAction { 10 | @Override 11 | protected IResult actionBody(IPlayer player) { 12 | player.setClass(new Archer()); 13 | player.setGameState(GameState.EXPLORATION); 14 | 15 | return new CompoundResult( 16 | List.of( 17 | new Result( 18 | "You are now an Archer from Clever Hares' Clan.\n" 19 | + "An extremely dangerous adventure awaits you, full of unexpected twists.\n" 20 | + "Use your eagle eye and your extraordinary bow ability to overcome any difficulties encountered.\n", 21 | Color.YELLOW), 22 | new Result(player.getCurrentLocation().getDescription()))); 23 | } 24 | 25 | @Override 26 | public List getAcceptableStates() { 27 | return List.of(GameState.LIMBO); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/PickMonk.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.*; 5 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 6 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 7 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 8 | 9 | public class PickMonk extends ArgumentlessAction { 10 | @Override 11 | protected IResult actionBody(IPlayer player) { 12 | player.setClass(new Monk()); 13 | player.setGameState(GameState.EXPLORATION); 14 | 15 | return new CompoundResult( 16 | List.of( 17 | new Result( 18 | "You are now a Monk from Magic Squirrels' Clan.\n" 19 | + "An extremely dangerous adventure awaits you, full of unexpected twists.\n" 20 | + "Use your knowledge of magic and the ability to wield a wand to overcome any difficulties encountered.\n", 21 | Color.YELLOW), 22 | new Result(player.getCurrentLocation().getDescription()))); 23 | } 24 | 25 | @Override 26 | public List getAcceptableStates() { 27 | return List.of(GameState.LIMBO); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/action/InvestigateActionTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.when; 5 | 6 | import java.util.List; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import pl.uj.io.cuteanimals.model.GameState; 13 | import pl.uj.io.cuteanimals.model.Player; 14 | 15 | @ExtendWith(MockitoExtension.class) 16 | class InvestigateActionTest { 17 | @Mock private Player player; 18 | private InvestigateAction investigateAction; 19 | 20 | @BeforeEach 21 | void setUp() { 22 | investigateAction = new InvestigateAction("Message"); 23 | } 24 | 25 | @Test 26 | void actionBodyShouldReturnInfoMessage() { 27 | when(player.getCurrentGameState()).thenReturn(GameState.EXPLORATION); 28 | assertThat(investigateAction.execute(player).getMessage()).isEqualTo("Message"); 29 | } 30 | 31 | @Test 32 | void actionShouldBeAvailableOnlyInExploration() { 33 | assertThat(investigateAction.getAcceptableStates()) 34 | .isEqualTo(List.of(GameState.EXPLORATION)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/CompoundResult.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 6 | 7 | public class CompoundResult implements IResult { 8 | private final List results; 9 | private final Color color; 10 | 11 | public CompoundResult(List results) { 12 | this.results = results; 13 | this.color = null; 14 | } 15 | 16 | public CompoundResult(List results, Color color) { 17 | this.results = results; 18 | this.color = color; 19 | } 20 | 21 | @Override 22 | public String getMessage() { 23 | return results.stream().map(IResult::getMessage).collect(Collectors.joining("\n")); 24 | } 25 | 26 | @Override 27 | public void setMessage(String message) { 28 | results.add(new Result(message)); 29 | } 30 | 31 | @Override 32 | public Color getColor() { 33 | if (color == null) { 34 | return results.get(results.size() - 1).getColor(); 35 | } 36 | 37 | return color; 38 | } 39 | 40 | public void addResult(IResult result) { 41 | results.add(result); 42 | } 43 | 44 | public List getResults() { 45 | return results; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/IAttributes.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | /** 4 | * Provides methods to manage character's attributes. 5 | * 6 | * @version %I% 7 | * @since 0.0.1-SNAPSHOT 8 | */ 9 | public interface IAttributes { 10 | 11 | /** 12 | * Gives character's current health points. 13 | * 14 | * @return int type health points. 15 | */ 16 | int getHealth(); 17 | 18 | /** 19 | * Gives character's attack points taking account all bonuses (from weapons etc). 20 | * 21 | * @return int type summary attack points. 22 | */ 23 | int getAttack(); 24 | 25 | /** 26 | * Gives character's current level. 27 | * 28 | * @return int type level. 29 | */ 30 | int getLevel(); 31 | 32 | /** 33 | * Gives character's defence points taking account all bonuses (from shields etc). 34 | * 35 | * @return int type summary defence points. 36 | */ 37 | int getDefence(); 38 | 39 | /** 40 | * Gives character's magic mana points. 41 | * 42 | * @return int type magic mana points. 43 | */ 44 | int getMana(); 45 | 46 | void addHealth(int health); 47 | 48 | void addAttack(int attack); 49 | 50 | void addLevel(int level); 51 | 52 | void addDefence(int defence); 53 | 54 | void addMana(int mana); 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/IItem.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import pl.uj.io.cuteanimals.model.ItemClass; 4 | import pl.uj.io.cuteanimals.model.ItemType; 5 | 6 | /** 7 | * Provides methods that allow attribute handling (health, attack points etc). 8 | * 9 | * @version %I% 10 | * @since 0.0.1-SNAPSHOT 11 | */ 12 | public interface IItem { 13 | /** 14 | * Provides text describing item's name. Name is distinctive for every item. 15 | * 16 | * @return string that is item's name 17 | */ 18 | String getName(); 19 | 20 | /** 21 | * Provides text describing a specific element, its appearance and usage. Gives information 22 | * about how Player can use this item and what results can be expected after use. 23 | * 24 | * @return descriptive String 25 | */ 26 | String getDescription(); 27 | 28 | /** 29 | * Gives information about the size of the item, its weight in kilograms. 30 | * 31 | * @return the number which is the weight of the item 32 | */ 33 | int getSize(); 34 | 35 | /** 36 | * Provides information about attributes of the item, its attack and defence points etc. 37 | * 38 | * @return object of IAttribute type including all information 39 | */ 40 | IAttributes getAttributes(); 41 | 42 | ItemType getType(); 43 | 44 | ItemClass getItemClass(); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/FightAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import pl.uj.io.cuteanimals.model.Color; 6 | import pl.uj.io.cuteanimals.model.GameState; 7 | import pl.uj.io.cuteanimals.model.Monster; 8 | import pl.uj.io.cuteanimals.model.Result; 9 | import pl.uj.io.cuteanimals.model.fight.FightLog; 10 | import pl.uj.io.cuteanimals.model.interfaces.ContainerArgumentAction; 11 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 12 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 13 | 14 | public class FightAction extends ContainerArgumentAction { 15 | public FightAction(Map monsters) { 16 | super(monsters); 17 | } 18 | 19 | @Override 20 | public IResult actionBody(IPlayer player, String toFightName) { 21 | var toFight = objects.get(toFightName); 22 | 23 | if (toFight == null) { 24 | return new Result("You want to fight... who?"); 25 | } 26 | 27 | if (toFight.getAttributes().getHealth() <= 0) { 28 | return new Result(toFight.getName() + " is already dead."); 29 | } 30 | 31 | return new FightLog(player.getFightManager().beginFight(toFight), Color.YELLOW); 32 | } 33 | 34 | @Override 35 | public List getAcceptableStates() { 36 | return List.of(GameState.EXPLORATION); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/GoAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ContainerArgumentAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.ILocation; 9 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | 12 | // TODO: find out if we can reduce boilerplate using FunctionalInterface like Interpreter 13 | 14 | /** 15 | * Moves player to given location. 16 | * 17 | * @version %I% 18 | * @since 0.0.1-SNAPSHOT 19 | */ 20 | public class GoAction extends ContainerArgumentAction { 21 | public GoAction(Map wheres) { 22 | super(wheres); 23 | } 24 | 25 | @Override 26 | public IResult actionBody(IPlayer player, String toGoName) { 27 | var toGo = objects.get(toGoName); 28 | 29 | if (toGo == null) { 30 | return new Result("You want to go... where?"); 31 | } 32 | 33 | IResult enterResult = player.changeLocation(toGo); 34 | return new Result(toGo.getDescription() + enterResult.getMessage()); 35 | } 36 | 37 | @Override 38 | public List getAcceptableStates() { 39 | return List.of(GameState.EXPLORATION); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/UseAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.ItemType; 7 | import pl.uj.io.cuteanimals.model.Result; 8 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentAction; 9 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 10 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 11 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 12 | 13 | public class UseAction extends ArgumentAction { 14 | @Override 15 | public IResult actionBody(IPlayer player, String itemName) { 16 | var toUse = getItem(player.getEquipment().getItems(), itemName); 17 | 18 | if (toUse.isEmpty()) { 19 | return new Result("You don't have that."); 20 | } 21 | 22 | if (!toUse.get().getType().equals(ItemType.USABLE)) { 23 | return new Result("You can't use that."); 24 | } 25 | 26 | return player.use(toUse.get()); 27 | } 28 | 29 | @Override 30 | public List getAcceptableStates() { 31 | return List.of(GameState.EXPLORATION, GameState.FIGHT); 32 | } 33 | 34 | private Optional getItem(final List list, final String name) { 35 | return list.stream().filter(o -> o.getName().toLowerCase().equals(name)).findFirst(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/ArgumentAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.interfaces; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | 7 | /** 8 | * Extends IAction interface with arguments 9 | * 10 | * @version %I% 11 | * @since 0.2.0-SNAPSHOT 12 | */ 13 | public abstract class ArgumentAction implements IAction { 14 | protected List args; 15 | 16 | public ArgumentAction() { 17 | this.args = new ArrayList<>(); 18 | } 19 | 20 | /** @return string representation of action arguments, e.g location name or item name */ 21 | @Override 22 | public List getArgs() { 23 | return args; 24 | } 25 | 26 | /** @param args string representation of action arguments, e.g location name or item name */ 27 | @Override 28 | public void setArgs(List args) { 29 | this.args = args; 30 | } 31 | 32 | @Override 33 | public IResult execute(IPlayer player) { 34 | if (!getAcceptableStates().contains(player.getCurrentGameState())) { 35 | args.clear(); 36 | return new Result("This isn't the time for that."); 37 | } 38 | 39 | var joined = String.join(" ", args); 40 | args.clear(); 41 | return actionBody(player, joined); 42 | } 43 | 44 | protected abstract IResult actionBody(IPlayer player, String object); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ThrowAwayAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 9 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | 12 | /** 13 | * Provides methods that let the Player get rid of his items. 14 | * 15 | * @version %I% 16 | * @since 0.0.1-SNAPSHOT 17 | */ 18 | public class ThrowAwayAction extends ArgumentAction { 19 | @Override 20 | public IResult actionBody(IPlayer player, String itemName) { 21 | var toThrow = getItem(player.getEquipment().getItems(), itemName); 22 | 23 | if (toThrow.isEmpty()) { 24 | return new Result("You don't have that"); 25 | } 26 | 27 | player.getEquipment().removeItem(toThrow.get()); 28 | return new Result("You have thrown " + itemName + " away"); 29 | } 30 | 31 | private Optional getItem(final List list, final String name) { 32 | return list.stream().filter(o -> o.getName().toLowerCase().equals(name)).findFirst(); 33 | } 34 | 35 | @Override 36 | public List getAcceptableStates() { 37 | return List.of(GameState.EXPLORATION); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/action/entrance/EntranceRemoveHealthActionTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action.entrance; 2 | 3 | import static org.assertj.core.api.AssertionsForClassTypes.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.mockito.Mock; 9 | import org.mockito.junit.jupiter.MockitoExtension; 10 | import pl.uj.io.cuteanimals.model.Player; 11 | import pl.uj.io.cuteanimals.model.WorldMap; 12 | 13 | @ExtendWith(MockitoExtension.class) 14 | public class EntranceRemoveHealthActionTest { 15 | private int healthLoss; 16 | private EntranceRemoveHealthAction entranceRemoveHealthAction; 17 | @Mock WorldMap world; 18 | private Player player; 19 | 20 | @BeforeEach 21 | private void setup() { 22 | player = new Player(0, world); 23 | healthLoss = 15; 24 | entranceRemoveHealthAction = new EntranceRemoveHealthAction(healthLoss); 25 | } 26 | 27 | @Test 28 | public void executeProperlyReducePlayersHealthAndReturnProperMessage() { 29 | var defaultHealth = player.getAttributes().getHealth(); 30 | var result = entranceRemoveHealthAction.execute(player); 31 | 32 | assertThat(result.getMessage()).isEqualTo("(You lose " + healthLoss + " health points)."); 33 | assertThat(player.getAttributes().getHealth()).isEqualTo(defaultHealth - healthLoss); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/NPCTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.List; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.mockito.Mock; 10 | import org.mockito.junit.jupiter.MockitoExtension; 11 | 12 | @ExtendWith(MockitoExtension.class) 13 | class NPCTest { 14 | @Mock private ArmorBackpack armorBackpack; 15 | @Mock private Backpack backpack; 16 | private NPC npc; 17 | 18 | @BeforeEach 19 | void setUp() { 20 | npc = new NPC(armorBackpack, backpack, "test", List.of("t1", "t2", "t3")); 21 | } 22 | 23 | @Test 24 | void getQuote() { 25 | assertThat(npc.getQuote()).isEqualTo("t1"); 26 | assertThat(npc.getQuote()).isEqualTo("t2"); 27 | assertThat(npc.getQuote()).isEqualTo("t3"); 28 | assertThat(npc.getQuote()).isEqualTo("This character can't tell you anything interesting"); 29 | assertThat(npc.getQuote()).isEqualTo("This character can't tell you anything interesting"); 30 | assertThat(npc.getQuote()).isEqualTo("This character can't tell you anything interesting"); 31 | assertThat(npc.getQuote()).isEqualTo("This character can't tell you anything interesting"); 32 | assertThat(npc.getQuote()).isEqualTo("This character can't tell you anything interesting"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/fight/BlockState.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.fight; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.Color; 5 | import pl.uj.io.cuteanimals.model.CompoundResult; 6 | import pl.uj.io.cuteanimals.model.Player; 7 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 8 | 9 | public class BlockState extends AttackState { 10 | private final int defenceIncrease; 11 | private int uses; 12 | 13 | public BlockState(Player owner) { 14 | super(owner); 15 | this.uses = 2; 16 | this.defenceIncrease = owner.getAttributes().getDefence(); 17 | owner.getAttributes().addDefence(defenceIncrease); 18 | } 19 | 20 | @Override 21 | public IResult attack() { 22 | return new CompoundResult( 23 | List.of( 24 | new FightLog(player.toString() + " is blocking.", Color.YELLOW), 25 | contrAttack())); 26 | } 27 | 28 | @Override 29 | public IResult contrAttack() { 30 | var result = super.contrAttack(); 31 | uses--; 32 | 33 | if (uses == 0) { 34 | player.getAttributes().addDefence(-defenceIncrease); 35 | player.getFightManager().setState(new AttackState(player)); 36 | return new CompoundResult( 37 | List.of(result, new FightLog("Block wears off.", Color.YELLOW))); 38 | } 39 | 40 | return result; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /HELP.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ### Reference Documentation 4 | For further reference, please consider the following sections: 5 | 6 | * [Official Gradle documentation](https://docs.gradle.org) 7 | * [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.7.RELEASE/gradle-plugin/reference/html/) 8 | * [Spring Web](https://docs.spring.io/spring-boot/docs/2.2.7.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications) 9 | * [Spring Boot DevTools](https://docs.spring.io/spring-boot/docs/2.2.7.RELEASE/reference/htmlsingle/#using-boot-devtools) 10 | * [Spring Security](https://docs.spring.io/spring-boot/docs/2.2.7.RELEASE/reference/htmlsingle/#boot-features-security) 11 | 12 | ### Guides 13 | The following guides illustrate how to use some features concretely: 14 | 15 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 16 | * [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) 17 | * [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/) 18 | * [Securing a Web Application](https://spring.io/guides/gs/securing-web/) 19 | * [Spring Boot and OAuth2](https://spring.io/guides/tutorials/spring-boot-oauth2/) 20 | * [Authenticating a User with LDAP](https://spring.io/guides/gs/authenticating-ldap/) 21 | 22 | ### Additional Links 23 | These additional references should also help you: 24 | 25 | * [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle) 26 | 27 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/TalkAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.ILocation; 9 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | 12 | /** 13 | * Provides methods to engage a conversation with NPC's. 14 | * 15 | * @version %I% 16 | * @since 0.0.1-SNAPSHOT 17 | */ 18 | public class TalkAction extends ArgumentAction { 19 | private final ILocation location; 20 | 21 | public TalkAction(ILocation location) { 22 | super(); 23 | this.location = location; 24 | } 25 | 26 | @Override 27 | public IResult actionBody(IPlayer player, String npcName) { 28 | var npc = 29 | location.getNPCs() 30 | .stream() 31 | .filter(x -> x.getName().toLowerCase().equals(npcName)) 32 | .collect(Collectors.toList()); 33 | getArgs().clear(); 34 | 35 | return npc.size() >= 1 36 | ? new Result(npc.get(0).getQuote()) 37 | : new Result("There is nobody named like that."); 38 | } 39 | 40 | @Override 41 | public List getAcceptableStates() { 42 | return List.of(GameState.EXPLORATION); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/PickupAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ContainerArgumentAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 9 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | 12 | /** 13 | * Provides methods to pick up items and put them in the backpack. 14 | * 15 | * @version %I% 16 | * @since 0.0.1-SNAPSHOT 17 | */ 18 | public class PickupAction extends ContainerArgumentAction { 19 | 20 | public PickupAction(Map items) { 21 | super(items); 22 | } 23 | 24 | @Override 25 | public IResult actionBody(IPlayer player, String toPickupName) { 26 | var toPickup = objects.get(toPickupName); 27 | 28 | if (toPickup == null) { 29 | return new Result("Nothing here"); 30 | } 31 | 32 | if (!player.getEquipment().putItem(toPickup)) { 33 | return new Result("This item is too heavy!"); 34 | } 35 | 36 | // TODO: after picking up gold in chamberOfWealth add money 37 | 38 | var itemName = toPickup.getName(); 39 | objects.remove(toPickupName); 40 | return new Result("You have picked " + itemName + " up"); 41 | } 42 | 43 | @Override 44 | public List getAcceptableStates() { 45 | return List.of(GameState.EXPLORATION); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/plot/actions/DungeonInvestigateAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.plot.actions; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.GameState; 5 | import pl.uj.io.cuteanimals.model.Result; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 8 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 9 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 10 | 11 | /** 12 | * Provides method that forbid Character to investigate the Dungeon without the Torch equipped. 13 | * 14 | * @version %I% 15 | * @since 0.0.1-SNAPSHOT 16 | */ 17 | public class DungeonInvestigateAction extends ArgumentlessAction { 18 | private final String infoMessage; 19 | 20 | public DungeonInvestigateAction(String infoMessage) { 21 | super(); 22 | this.infoMessage = infoMessage; 23 | } 24 | 25 | @Override 26 | public IResult actionBody(IPlayer player) { 27 | if (!getAcceptableStates().contains(player.getCurrentGameState())) { 28 | return new Result("This action cannot be executed now"); 29 | } 30 | 31 | for (IItem item : player.getArmor().getItems()) { 32 | if (item.getName().toLowerCase().equals("torch")) { 33 | return new Result(infoMessage); 34 | } 35 | } 36 | 37 | return new Result("You can see nothing but the darkness."); 38 | } 39 | 40 | @Override 41 | public List getAcceptableStates() { 42 | return List.of(GameState.EXPLORATION); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/UnequipItem.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 9 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | 12 | /** 13 | * Provides methods that let the Player put currently equipped items to his backpack. 14 | * 15 | * @version %I% 16 | * @since 0.0.1-SNAPSHOT 17 | */ 18 | public class UnequipItem extends ArgumentAction { 19 | @Override 20 | public IResult actionBody(IPlayer player, String itemName) { 21 | var toUnequip = getItem(player.getArmor().getItems(), itemName); 22 | 23 | if (toUnequip.isEmpty()) { 24 | return new Result("You are not wearing that"); 25 | } 26 | 27 | player.getArmor().removeItem(toUnequip.get()); 28 | 29 | if (player.getEquipment().putItem(toUnequip.get())) { 30 | return new Result("You have took " + itemName + " off"); 31 | } 32 | 33 | return new Result("You can't take off that"); 34 | } 35 | 36 | private Optional getItem(final List list, final String name) { 37 | return list.stream().filter(o -> o.getName().toLowerCase().equals(name)).findFirst(); 38 | } 39 | 40 | @Override 41 | public List getAcceptableStates() { 42 | return List.of(GameState.EXPLORATION); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/plot/actions/DungeonEntranceGoAction.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.plot.actions; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.RandomIntegerImpl; 7 | import pl.uj.io.cuteanimals.model.Result; 8 | import pl.uj.io.cuteanimals.model.interfaces.*; 9 | 10 | /** 11 | * Provides methods that moves Character to the MedicalCabin in case of him falling from the bridge. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | // @Component 17 | public class DungeonEntranceGoAction extends ContainerArgumentAction { 18 | private final RandomInteger rand; 19 | 20 | public DungeonEntranceGoAction(Map wheres) { 21 | super(wheres); 22 | this.rand = new RandomIntegerImpl(); 23 | } 24 | 25 | public DungeonEntranceGoAction(Map wheres, RandomInteger rand) { 26 | super(wheres); 27 | this.rand = rand; 28 | } 29 | 30 | @Override 31 | public IResult actionBody(IPlayer player, String toGoName) { 32 | var toGo = objects.get(toGoName); 33 | 34 | if (toGo == null) { 35 | return new Result("You want to go... where?"); 36 | } 37 | 38 | if (rand.nextInt(10) < 4) { 39 | toGo = player.getWorld().getLocation("medical"); 40 | } 41 | 42 | player.changeLocation(toGo); 43 | return new Result(toGo.getDescription()); 44 | } 45 | 46 | @Override 47 | public List getAcceptableStates() { 48 | return List.of(GameState.EXPLORATION); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/NPCAttributes.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 4 | 5 | public class NPCAttributes implements IAttributes { 6 | protected int health; 7 | protected int attack; 8 | protected int level; 9 | protected int defence; 10 | protected int mana; 11 | 12 | public NPCAttributes(int health, int attack, int level, int defence, int mana) { 13 | this.health = health; 14 | this.attack = attack; 15 | this.level = level; 16 | this.defence = defence; 17 | this.mana = mana; 18 | } 19 | 20 | @Override 21 | public int getHealth() { 22 | return health; 23 | } 24 | 25 | @Override 26 | public int getAttack() { 27 | return attack; 28 | } 29 | 30 | @Override 31 | public int getLevel() { 32 | return level; 33 | } 34 | 35 | @Override 36 | public int getDefence() { 37 | return defence; 38 | } 39 | 40 | @Override 41 | public int getMana() { 42 | return mana; 43 | } 44 | 45 | @Override 46 | public void addHealth(int health) { 47 | this.health += health; 48 | } 49 | 50 | @Override 51 | public void addAttack(int attack) { 52 | this.attack += attack; 53 | } 54 | 55 | @Override 56 | public void addLevel(int level) { 57 | this.level += level; 58 | } 59 | 60 | @Override 61 | public void addDefence(int defence) { 62 | this.defence += defence; 63 | } 64 | 65 | @Override 66 | public void addMana(int mana) { 67 | this.mana += mana; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/action/ShowArmorTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.*; 5 | 6 | import java.util.List; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import pl.uj.io.cuteanimals.model.GameState; 13 | import pl.uj.io.cuteanimals.model.Player; 14 | import pl.uj.io.cuteanimals.model.PlayerBackpack; 15 | 16 | @ExtendWith(MockitoExtension.class) 17 | class ShowArmorTest { 18 | @Mock private Player player; 19 | private ShowArmor showArmor; 20 | 21 | @BeforeEach 22 | void setUp() { 23 | showArmor = new ShowArmor(); 24 | } 25 | 26 | @Test 27 | void actionBodyShouldReturnInfoMessage() { 28 | var playerBackpack = mock(PlayerBackpack.class); 29 | when(player.getCurrentGameState()).thenReturn(GameState.EXPLORATION); 30 | when(player.getArmor()).thenReturn(playerBackpack); 31 | showArmor.execute(player); 32 | var thisVariableIsHereToSilenceFalsePositiveWarningReportedBySpotBugs = 33 | verify(playerBackpack).showItems(); 34 | assertThat(thisVariableIsHereToSilenceFalsePositiveWarningReportedBySpotBugs) 35 | .isNull(); // silence spotbugs 36 | } 37 | 38 | @Test 39 | void actionShouldBeAvailableOnlyInExploration() { 40 | assertThat(showArmor.getAcceptableStates()) 41 | .isEqualTo(List.of(GameState.EXPLORATION, GameState.FIGHT)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/action/ShowAbilitiesTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.*; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import org.junit.jupiter.api.BeforeEach; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.extension.ExtendWith; 11 | import org.mockito.Mock; 12 | import org.mockito.junit.jupiter.MockitoExtension; 13 | import pl.uj.io.cuteanimals.action.ability.Focus; 14 | import pl.uj.io.cuteanimals.model.GameState; 15 | import pl.uj.io.cuteanimals.model.Player; 16 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 17 | 18 | @ExtendWith(MockitoExtension.class) 19 | class ShowAbilitiesTest { 20 | @Mock private Player player; 21 | private ShowAbilities showAbilities; 22 | 23 | @BeforeEach 24 | void setUp() { 25 | showAbilities = new ShowAbilities(); 26 | } 27 | 28 | @Test 29 | void actionBodyShouldReturnInfoMessage() { 30 | var skills = new HashMap(); 31 | skills.put("focus", new Focus()); 32 | when(player.getCurrentGameState()).thenReturn(GameState.EXPLORATION); 33 | when(player.getAbilities()).thenReturn(skills); 34 | 35 | var out = showAbilities.execute(player).getMessage(); 36 | assertThat(out).isNotBlank(); 37 | assertThat(out).contains("focus"); 38 | } 39 | 40 | @Test 41 | void actionShouldBeAvailableOnlyInExplorationAndFight() { 42 | assertThat(showAbilities.getAcceptableStates()) 43 | .isEqualTo(List.of(GameState.EXPLORATION, GameState.FIGHT)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/action/ShowStatsTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.*; 5 | 6 | import java.util.List; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import pl.uj.io.cuteanimals.model.GameState; 13 | import pl.uj.io.cuteanimals.model.Player; 14 | import pl.uj.io.cuteanimals.model.entity.Attributes; 15 | 16 | @ExtendWith(MockitoExtension.class) 17 | class ShowStatsTest { 18 | @Mock private Player player; 19 | private ShowStats showStats; 20 | 21 | @BeforeEach 22 | void setUp() { 23 | showStats = new ShowStats(); 24 | } 25 | 26 | @Test 27 | void actionBodyShouldReturnInfoMessage() { 28 | when(player.getCurrentGameState()).thenReturn(GameState.EXPLORATION); 29 | when(player.getAttributes()).thenReturn(new Attributes(1, 1, 1, 1, 1, 1)); 30 | 31 | assertThat(showStats.execute(player).getMessage()).isNotBlank(); 32 | var thisVariableIsHereToSilenceFalsePositiveWarningReportedBySpotBugs = 33 | verify(player).getAttributes(); 34 | assertThat(thisVariableIsHereToSilenceFalsePositiveWarningReportedBySpotBugs) 35 | .isNull(); // silence spotbugs 36 | } 37 | 38 | @Test 39 | void actionShouldBeAvailableOnlyInExploration() { 40 | assertThat(showStats.getAcceptableStates()) 41 | .isEqualTo(List.of(GameState.EXPLORATION, GameState.FIGHT)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | create: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | build: 10 | name: Build project 11 | runs-on: ubuntu-20.04 12 | 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | - name: Set up JDK 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | - name: Grant execute permission for gradlew 21 | run: chmod +x gradlew 22 | - name: Cache Gradle packages 23 | uses: actions/cache@v2 24 | with: 25 | path: ~/.gradle/caches 26 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 27 | restore-keys: ${{ runner.os }}-gradle 28 | - name: Build with Gradle 29 | run: ./gradlew build -x verifyGoogleJavaFormat -x test 30 | - name: Upload artifacts 31 | uses: actions/upload-artifact@v2 32 | with: 33 | name: binary 34 | path: build/libs 35 | 36 | deploy: 37 | name: Deploy on Heroku 38 | needs: build 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: Checkout code 42 | uses: actions/checkout@v2 43 | - name: Download binary 44 | uses: actions/download-artifact@v2 45 | with: 46 | name: binary 47 | path: build/libs 48 | - run: ls -R 49 | - name: Deploy 50 | uses: akhileshns/heroku-deploy@v3.0.4 51 | with: 52 | heroku_api_key: ${{secrets.HEROKU_API_KEY}} 53 | heroku_app_name: "io-rpg" 54 | heroku_email: "hjaremko@outlook.com" 55 | usedocker: true 56 | docker_heroku_process_type: "web" 57 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Backpack.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import pl.uj.io.cuteanimals.model.interfaces.IEquipment; 6 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 7 | 8 | /** 9 | * Provides methods to manage Player's Backpack. Allows him to put, remove and display those items. 10 | * 11 | * @version %I% 12 | * @since 0.0.1-SNAPSHOT 13 | */ 14 | public class Backpack implements IEquipment { 15 | private final List items = new ArrayList<>(); 16 | 17 | @Override 18 | public List getItems() { 19 | return items; 20 | } 21 | 22 | @Override 23 | public boolean putItem(IItem item) { 24 | return items.add(item); 25 | } 26 | 27 | @Override 28 | public boolean removeItem(IItem item) { 29 | return items.remove(item); 30 | } 31 | 32 | @Override 33 | public String showItems() { 34 | int i = 1; 35 | StringBuilder stringBuilder = new StringBuilder(); 36 | stringBuilder.append("You have the following items in your backpack: ").append("\n"); 37 | for (IItem item : items) { 38 | stringBuilder.append(i).append(". ").append(item.getName()).append("\n"); 39 | stringBuilder.append("Description: ").append(item.getDescription()); 40 | stringBuilder.append(", Type: ").append(item.getType().toString()); 41 | stringBuilder.append(", Size: ").append(item.getSize()).append(", "); 42 | stringBuilder.append(item.getAttributes().toString()); 43 | stringBuilder.append("\n"); 44 | i++; 45 | } 46 | 47 | return stringBuilder.toString(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/BuffCharacter.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.Color; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 9 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | 12 | public class BuffCharacter extends ArgumentlessAction { 13 | private final IAttributes attributes; 14 | 15 | public BuffCharacter(IAttributes attributes) { 16 | this.attributes = attributes; 17 | } 18 | 19 | @Override 20 | public IResult actionBody(IPlayer player) { 21 | player.getAttributes().addHealth(attributes.getHealth()); 22 | player.getAttributes().addAttack(attributes.getAttack()); 23 | player.getAttributes().addDefence(attributes.getDefence()); 24 | player.getAttributes().addMana(attributes.getMana()); 25 | 26 | var message = ""; 27 | message += (attributes.getHealth() != 0 ? "+" + attributes.getHealth() + " health " : ""); 28 | message += (attributes.getAttack() != 0 ? "+" + attributes.getAttack() + " attack " : ""); 29 | message += 30 | (attributes.getDefence() != 0 ? "+" + attributes.getDefence() + " defence " : ""); 31 | message += (attributes.getMana() != 0 ? "+" + attributes.getMana() + " mana " : ""); 32 | 33 | return new Result(message, Color.GREEN); 34 | } 35 | 36 | @Override 37 | public List getAcceptableStates() { 38 | return List.of(GameState.EXPLORATION, GameState.FIGHT); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/PlayerBackpack.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 4 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 5 | 6 | /** 7 | * Provides methods to manage player's backpack 8 | * 9 | * @version %I% 10 | * @since 0.2.0-SNAPSHOT 11 | */ 12 | public class PlayerBackpack extends Backpack { 13 | private final IAttributes ownerAttrs; 14 | private int currentWeight; 15 | 16 | public PlayerBackpack(IAttributes ownerAttrs) { 17 | super(); 18 | this.ownerAttrs = ownerAttrs; 19 | this.currentWeight = 0; 20 | } 21 | 22 | @Override 23 | public boolean putItem(IItem item) { 24 | if (item.getSize() > getRemainingCapacity()) { 25 | return false; 26 | } 27 | 28 | getItems().add(item); 29 | currentWeight += item.getSize(); 30 | return true; 31 | } 32 | 33 | @Override 34 | public boolean removeItem(IItem item) { 35 | getItems().remove(item); 36 | currentWeight -= item.getSize(); 37 | return true; 38 | } 39 | 40 | /** 41 | * Gives the capacity of the player's backpack. The stronger a player is, the more he can carry. 42 | * 43 | * @return int type capacity 44 | */ 45 | public int getCapacity() { 46 | int baseCapacity = 10; 47 | return baseCapacity + 3 * ownerAttrs.getAttack(); 48 | } 49 | 50 | /** 51 | * Gives the remaining capacity of the player's backpack. Subtracts the weight of the items worn 52 | * from the capacity number. 53 | * 54 | * @return int type remaining capacity 55 | */ 56 | public int getRemainingCapacity() { 57 | return getCapacity() - currentWeight; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/fight/FightManagerTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.fight; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.mockito.Mock; 9 | import org.mockito.junit.jupiter.MockitoExtension; 10 | import pl.uj.io.cuteanimals.model.*; 11 | 12 | @ExtendWith(MockitoExtension.class) 13 | class FightManagerTest { 14 | @Mock private WorldMap world; 15 | private Player player; 16 | private PlayerAttributes attrs; 17 | 18 | @BeforeEach 19 | void setUp() { 20 | player = new Player(0, world); 21 | attrs = (PlayerAttributes) player.getAttributes(); 22 | } 23 | 24 | @Test 25 | void endBattleEqualLevelExperienceTest() { 26 | var dummy = new Monster("dummy", new NPCAttributes(1, 1, 1, 1, 0)); 27 | 28 | player.getFightManager().beginFight(dummy); 29 | player.getFightManager().endBattle(); 30 | assertThat(attrs.getExperience() == 1); 31 | } 32 | 33 | @Test 34 | void endBattleMonsterHigherLevelExperienceTest() { 35 | var dummy = new Monster("dummy", new NPCAttributes(1, 1, 11, 1, 0)); 36 | 37 | player.getFightManager().beginFight(dummy); 38 | player.getFightManager().endBattle(); 39 | assertThat(attrs.getExperience() == 1 + 5); 40 | } 41 | 42 | @Test 43 | void endBattleMonsterLowerLevelExperienceTest() { 44 | player.getAttributes().addLevel(1); 45 | var dummy = new Monster("dummy", new NPCAttributes(1, 1, 11, 1, 0)); 46 | 47 | player.getFightManager().beginFight(dummy); 48 | player.getFightManager().endBattle(); 49 | assertThat(attrs.getExperience() == 1); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/EquipItem.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import pl.uj.io.cuteanimals.model.GameState; 6 | import pl.uj.io.cuteanimals.model.Result; 7 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentAction; 8 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 9 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | 12 | /** 13 | * Provides methods to equip item from Character's backpack. 14 | * 15 | * @version %I% 16 | * @since 0.0.1-SNAPSHOT 17 | */ 18 | public class EquipItem extends ArgumentAction { 19 | @Override 20 | protected IResult actionBody(IPlayer player, String toEquipName) { 21 | var toEquip = getItem(player.getEquipment().getItems(), toEquipName); 22 | 23 | if (toEquip.isEmpty()) { 24 | return new Result("You don't have that"); 25 | } 26 | 27 | var playerAcceptedItemClasses = player.getPlayerClass().getAcceptedItemClasses(); 28 | if (!playerAcceptedItemClasses.contains(toEquip.get().getItemClass())) { 29 | return new Result("You are not allowed to equip this item!"); 30 | } 31 | 32 | player.getEquipment().removeItem(toEquip.get()); 33 | 34 | if (player.getArmor().putItem(toEquip.get())) { 35 | return new Result("You have put " + toEquipName + " on"); 36 | } 37 | 38 | return new Result("You can't wear that"); 39 | } 40 | 41 | private Optional getItem(final List list, final String name) { 42 | return list.stream().filter(o -> o.getName().toLowerCase().equals(name)).findFirst(); 43 | } 44 | 45 | @Override 46 | public List getAcceptableStates() { 47 | return List.of(GameState.EXPLORATION); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/action/ShowBackpackTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.*; 5 | 6 | import java.util.List; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import pl.uj.io.cuteanimals.model.GameState; 13 | import pl.uj.io.cuteanimals.model.Player; 14 | import pl.uj.io.cuteanimals.model.PlayerBackpack; 15 | 16 | @ExtendWith(MockitoExtension.class) 17 | class ShowBackpackTest { 18 | @Mock private Player player; 19 | private ShowBackpack showBackpack; 20 | 21 | @BeforeEach 22 | void setUp() { 23 | showBackpack = new ShowBackpack(); 24 | } 25 | 26 | @Test 27 | void actionBodyShouldReturnInfoMessage() { 28 | when(player.getCurrentGameState()).thenReturn(GameState.EXPLORATION); 29 | var playerBackpack = mock(PlayerBackpack.class); 30 | when(player.getEquipment()).thenReturn(playerBackpack); 31 | 32 | assertThat(showBackpack.execute(player).getMessage()).isNotBlank(); 33 | var thisVariableIsHereToSilenceFalsePositiveWarningReportedBySpotBugs = 34 | verify(playerBackpack).showItems(); 35 | var thisOneToo = verify(playerBackpack).getRemainingCapacity(); 36 | assertThat(thisVariableIsHereToSilenceFalsePositiveWarningReportedBySpotBugs) 37 | .isNull(); // silence spotbugs 38 | assertThat(thisOneToo).isNotNull(); // silence spotbugs 39 | } 40 | 41 | @Test 42 | void actionShouldBeAvailableOnlyInExplorationAndFight() { 43 | assertThat(showBackpack.getAcceptableStates()) 44 | .isEqualTo(List.of(GameState.EXPLORATION, GameState.FIGHT)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/interfaces/ILocation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides methods that describe specific location (available actions, items, NPCs etc). 3 | * 4 | * @version %I% 5 | * @since 0.0.1-SNAPSHOT 6 | */ 7 | package pl.uj.io.cuteanimals.model.interfaces; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | import pl.uj.io.cuteanimals.model.NPC; 12 | 13 | public interface ILocation { 14 | 15 | /** 16 | * Gives text describing current location, what can be seen by the Player at the first glance. 17 | * Gives a general idea of how the location looks like. 18 | * 19 | * @return descriptive String 20 | */ 21 | String getDescription(); 22 | 23 | /** 24 | * Gives a list of actions that the Player can execute in the current location, such as starting 25 | * a fight or arrange a conversation. Considers current state of the Player (equipment, 26 | * attributes). 27 | * 28 | * @return list of elements of IAction type. 29 | */ 30 | Map getAvailableActions(); 31 | 32 | /** 33 | * Gives a list of non-playable-characters that are currently in the Location that the Player 34 | * can integrate with (start a fight, conversation, buy something). 35 | * 36 | * @return list of elements of NPC type. 37 | */ 38 | List getNPCs(); 39 | 40 | /** 41 | * Gives a list of items that are currently in the Location that the Player can integrate with 42 | * (take them, use them, drink/eat them etc.). 43 | * 44 | * @return IEquipment containing items. 45 | */ 46 | IEquipment getItems(); 47 | 48 | /** 49 | * Lets location execute any action on player when entering it. 50 | * 51 | * @param player player entering location 52 | */ 53 | IResult onEnter(IPlayer player); 54 | 55 | /** 56 | * Gives an action that is executed on player entering location. 57 | * 58 | * @return action executed on player entering location 59 | */ 60 | IAction getActionOnEnter(); 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/service/GameService.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.service; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.locks.Lock; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | import pl.uj.io.cuteanimals.exception.InvalidCommandException; 12 | import pl.uj.io.cuteanimals.interpreter.Interpreter; 13 | import pl.uj.io.cuteanimals.model.GameInstance; 14 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 15 | 16 | @Service 17 | public class GameService { 18 | private static final Logger logger = LoggerFactory.getLogger(GameService.class); 19 | private final Interpreter interpreter; 20 | private final ItemService itemService; 21 | private final List players; 22 | private final Lock lock; 23 | 24 | @Autowired 25 | public GameService(Interpreter interpreter, ItemService itemService) { 26 | this.interpreter = interpreter; 27 | this.itemService = itemService; 28 | this.players = new ArrayList<>(); 29 | this.lock = new ReentrantLock(); 30 | } 31 | 32 | public IResult execute(int characterId, String command) throws InvalidCommandException { 33 | return players.get(characterId).executeInput(command); 34 | } 35 | 36 | public String getLocationInfo(int characterId) { 37 | return players.get(characterId).getPlayer().getCurrentLocation().getDescription(); 38 | } 39 | 40 | public int getFirstFreeID() { 41 | lock.lock(); 42 | int result = -1; 43 | try { 44 | result = players.size(); 45 | players.add(new GameInstance(result, itemService, interpreter, this)); 46 | } finally { 47 | lock.unlock(); 48 | } 49 | return result; 50 | } 51 | 52 | public String pickClass(int characterId) { 53 | logger.trace("User with ID: " + characterId + "is picking class"); 54 | return players.get(characterId).pickClass(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/NPCAttributesTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class NPCAttributesTest { 9 | private NPCAttributes attrs; 10 | 11 | @BeforeEach 12 | void setUp() { 13 | attrs = new NPCAttributes(1, 2, 3, 4, 5); 14 | } 15 | 16 | @Test 17 | void getHealth() { 18 | assertThat(attrs.getHealth()).isEqualTo(1); 19 | } 20 | 21 | @Test 22 | void getAttack() { 23 | assertThat(attrs.getAttack()).isEqualTo(2); 24 | } 25 | 26 | @Test 27 | void getLevel() { 28 | assertThat(attrs.getLevel()).isEqualTo(3); 29 | } 30 | 31 | @Test 32 | void getDefence() { 33 | assertThat(attrs.getDefence()).isEqualTo(4); 34 | } 35 | 36 | @Test 37 | void getMana() { 38 | assertThat(attrs.getMana()).isEqualTo(5); 39 | } 40 | 41 | @Test 42 | void addHealth() { 43 | attrs.addHealth(200); 44 | assertThat(attrs.getHealth()).isEqualTo(201); 45 | attrs.addHealth(-100); 46 | assertThat(attrs.getHealth()).isEqualTo(101); 47 | } 48 | 49 | @Test 50 | void addAttack() { 51 | attrs.addAttack(200); 52 | assertThat(attrs.getAttack()).isEqualTo(202); 53 | attrs.addAttack(-100); 54 | assertThat(attrs.getAttack()).isEqualTo(102); 55 | } 56 | 57 | @Test 58 | void addLevel() { 59 | attrs.addLevel(200); 60 | assertThat(attrs.getLevel()).isEqualTo(203); 61 | attrs.addLevel(-100); 62 | assertThat(attrs.getLevel()).isEqualTo(103); 63 | } 64 | 65 | @Test 66 | void addDefence() { 67 | attrs.addDefence(200); 68 | assertThat(attrs.getDefence()).isEqualTo(204); 69 | attrs.addDefence(-100); 70 | assertThat(attrs.getDefence()).isEqualTo(104); 71 | } 72 | 73 | @Test 74 | void addMana() { 75 | attrs.addMana(200); 76 | assertThat(attrs.getMana()).isEqualTo(205); 77 | attrs.addMana(-100); 78 | assertThat(attrs.getMana()).isEqualTo(105); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/DefaultLocation.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import org.springframework.stereotype.Component; 8 | import pl.uj.io.cuteanimals.model.interfaces.*; 9 | 10 | /** 11 | * Provides methods to manage any Location. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | @Component 17 | public class DefaultLocation implements ILocation { 18 | protected String description; 19 | protected Map actionMap; 20 | protected List npcList; 21 | // TODO: remove probably 22 | protected IEquipment equipment; 23 | protected IAction actionOnEnter; 24 | 25 | public DefaultLocation() { 26 | this.description = ""; 27 | this.actionMap = new HashMap<>(); 28 | this.npcList = new ArrayList<>(); 29 | this.equipment = new Backpack(); 30 | this.actionOnEnter = null; 31 | } 32 | 33 | @Override 34 | public String getDescription() { 35 | return description; 36 | } 37 | 38 | public void setDescription(String description) { 39 | this.description = description; 40 | } 41 | 42 | @Override 43 | public Map getAvailableActions() { 44 | return actionMap; 45 | } 46 | 47 | public void setAvailableActions(Map availableActions) { 48 | this.actionMap = availableActions; 49 | } 50 | 51 | @Override 52 | public List getNPCs() { 53 | return npcList; 54 | } 55 | 56 | public void setNPCs(List npcList) { 57 | this.npcList = npcList; 58 | } 59 | 60 | @Override 61 | public IEquipment getItems() { 62 | return equipment; 63 | } 64 | 65 | public void setItems(IEquipment items) { 66 | this.equipment = items; 67 | } 68 | 69 | @Override 70 | public IAction getActionOnEnter() { 71 | return actionOnEnter; 72 | } 73 | 74 | public void setActionOnEnter(IAction actionOnEnter) { 75 | this.actionOnEnter = actionOnEnter; 76 | } 77 | 78 | @Override 79 | public IResult onEnter(IPlayer player) { 80 | if (actionOnEnter != null) { 81 | return actionOnEnter.execute(player); 82 | } 83 | return new Result(""); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/BackpackTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | import pl.uj.io.cuteanimals.model.entity.Attributes; 8 | import pl.uj.io.cuteanimals.model.entity.Item; 9 | 10 | class BackpackTest { 11 | private Backpack backpack; 12 | 13 | @BeforeEach 14 | void setUp() { 15 | backpack = new Backpack(); 16 | } 17 | 18 | @Test 19 | void putAndRemoveItem() { 20 | var weapon = 21 | new Item( 22 | 1, 23 | "pach", 24 | "aaa", 25 | 1, 26 | new Attributes(1, 1, 1, 1, 1, 1), 27 | ItemType.WEAPON, 28 | ItemClass.ANY); 29 | var heavy = 30 | new Item( 31 | 1, 32 | "pach", 33 | "aaa", 34 | 40, 35 | new Attributes(1, 1, 1, 1, 1, 1), 36 | ItemType.ARMOR, 37 | ItemClass.ANY); 38 | 39 | assertThat(backpack.putItem(weapon)); 40 | assertThat(backpack.putItem(heavy)); 41 | assertThat(backpack.getItems().size()).isEqualTo(2); 42 | assertThat(backpack.getItems()).contains(heavy); 43 | assertThat(backpack.getItems()).contains(weapon); 44 | assertThat(backpack.removeItem(weapon)); 45 | assertThat(backpack.getItems().size()).isEqualTo(1); 46 | assertThat(backpack.removeItem(heavy)); 47 | assertThat(backpack.getItems()).isEmpty(); 48 | } 49 | 50 | @Test 51 | void showItemsDoesntCrash() { 52 | assertThat(backpack.showItems()).isNotBlank(); 53 | assertThat( 54 | backpack.putItem( 55 | new Item( 56 | 1, 57 | "pach", 58 | "aaa", 59 | 1, 60 | new Attributes(1, 1, 1, 1, 1, 1), 61 | ItemType.WEAPON, 62 | ItemClass.ANY))); 63 | assertThat(backpack.showItems()).isNotBlank(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/GameInstance.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.exception.InvalidCommandException; 5 | import pl.uj.io.cuteanimals.interpreter.Expression; 6 | import pl.uj.io.cuteanimals.interpreter.Interpreter; 7 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 8 | import pl.uj.io.cuteanimals.service.GameService; 9 | import pl.uj.io.cuteanimals.service.ItemService; 10 | 11 | public class GameInstance { 12 | private final Interpreter interpreter; 13 | private final ItemService itemService; 14 | private final GameService gameService; 15 | private Player player; 16 | 17 | public GameInstance( 18 | int id, ItemService itemService, Interpreter interpreter, GameService gameService) { 19 | this.itemService = itemService; 20 | this.interpreter = interpreter; 21 | this.gameService = gameService; 22 | this.player = new Player(id, new WorldMap(itemService)); 23 | } 24 | 25 | public GameInstance(int id, ItemService itemService, GameService gameService) { 26 | this.itemService = itemService; 27 | this.gameService = gameService; 28 | this.interpreter = new Interpreter(); 29 | this.player = new Player(id, new WorldMap(itemService)); 30 | } 31 | 32 | public IResult executeInput(String input) throws InvalidCommandException { 33 | Expression expr = 34 | interpreter.parse(input, player.getCurrentLocation().getAvailableActions()); 35 | var inputResult = 36 | expr.interpret(player.getCurrentLocation().getAvailableActions()).execute(player); 37 | 38 | if (isPlayerDead()) { 39 | return new CompoundResult(List.of(inputResult, gameOver())); 40 | } 41 | 42 | return inputResult; 43 | } 44 | 45 | public Player getPlayer() { 46 | return player; 47 | } 48 | 49 | public IResult gameOver() { 50 | this.player = new Player(player.getId(), new WorldMap(itemService)); 51 | return new Result(this.gameService.pickClass(player.getId())); 52 | } 53 | 54 | private boolean isPlayerDead() { 55 | return player.getAttributes().getHealth() <= 0; 56 | } 57 | 58 | public String pickClass() { 59 | if (!player.getCurrentGameState().equals(GameState.LIMBO)) { 60 | return "You can't do that anymore."; 61 | } 62 | 63 | return "Pick your destiny.\n(Warrior, Monk, Archer)"; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/GameInstanceTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.AssertionsForClassTypes.assertThat; 4 | import static org.mockito.ArgumentMatchers.any; 5 | import static org.mockito.BDDMockito.given; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.mockito.Mock; 13 | import org.mockito.junit.jupiter.MockitoExtension; 14 | import pl.uj.io.cuteanimals.interpreter.Expression; 15 | import pl.uj.io.cuteanimals.interpreter.Interpreter; 16 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 17 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 18 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 19 | import pl.uj.io.cuteanimals.service.GameService; 20 | import pl.uj.io.cuteanimals.service.ItemService; 21 | 22 | @ExtendWith(MockitoExtension.class) 23 | public class GameInstanceTest { 24 | @Mock private Interpreter interpreter; 25 | @Mock private ItemService itemService; 26 | @Mock private GameService gameService; 27 | private GameInstance gameInstance; 28 | private Expression expression; 29 | private IAction action; 30 | 31 | @BeforeEach 32 | private void setup() { 33 | gameInstance = new GameInstance(0, itemService, interpreter, gameService); 34 | action = 35 | new IAction() { 36 | @Override 37 | public IResult execute(IPlayer player) { 38 | return new Result("first result", Color.BOLD); 39 | } 40 | 41 | @Override 42 | public List getArgs() { 43 | return null; 44 | } 45 | 46 | @Override 47 | public void setArgs(List args) {} 48 | 49 | @Override 50 | public List getAcceptableStates() { 51 | return null; 52 | } 53 | }; 54 | 55 | expression = context -> action; 56 | } 57 | 58 | @Test 59 | public void executeSucceedAndReturnsProperResult() throws Exception { 60 | given(interpreter.parse(any(String.class), any(Map.class))).willReturn(expression); 61 | 62 | var result = gameInstance.executeInput("aaa"); 63 | 64 | assertThat(result.getMessage()).isEqualTo("first result"); 65 | assertThat(result.getColor()).isEqualTo(Color.BOLD); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/service/AttributesService.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.service; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.web.server.ResponseStatusException; 11 | import pl.uj.io.cuteanimals.model.entity.Attributes; 12 | import pl.uj.io.cuteanimals.repository.AttributesRepository; 13 | 14 | @Service 15 | public class AttributesService { 16 | private static final Logger logger = LoggerFactory.getLogger(AttributesService.class); 17 | private final AttributesRepository attributesRepository; 18 | 19 | @Autowired 20 | public AttributesService(AttributesRepository attributesRepository) { 21 | this.attributesRepository = attributesRepository; 22 | 23 | // Add dummy attributes to prevent game from crashing 24 | var swordAttr = new Attributes(1, 0, 1, 1, 0, 0); 25 | var shieldAttr = new Attributes(2, 0, 0, 1, 2, 0); 26 | var magicWandAttr = new Attributes(3, 0, 3, 1, 0, 5); 27 | var bowAttr = new Attributes(4, 0, 2, 1, 0, 0); 28 | var arrowAttr = new Attributes(5, 0, 1, 1, 0, 0); 29 | var coinAttr = new Attributes(6, 0, 0, 0, 0, 0); 30 | var amuletAttr = new Attributes(7, 0, 0, 5, 0, 3); 31 | var torchAttr = new Attributes(8, 0, 1, 0, 0, 0); 32 | var appleAttr = new Attributes(9, 15, 0, 1, 0, 0); 33 | 34 | attributesRepository.saveAndFlush(swordAttr); 35 | attributesRepository.saveAndFlush(shieldAttr); 36 | attributesRepository.saveAndFlush(magicWandAttr); 37 | attributesRepository.saveAndFlush(bowAttr); 38 | attributesRepository.saveAndFlush(arrowAttr); 39 | attributesRepository.saveAndFlush(coinAttr); 40 | attributesRepository.saveAndFlush(amuletAttr); 41 | attributesRepository.saveAndFlush(torchAttr); 42 | attributesRepository.saveAndFlush(appleAttr); 43 | } 44 | 45 | public List getAllAttributes() { 46 | return attributesRepository.findAll(); 47 | } 48 | 49 | public Attributes getAttributes(int id) { 50 | Optional attr = attributesRepository.findById(id); 51 | return attr.orElseThrow( 52 | () -> 53 | new ResponseStatusException( 54 | HttpStatus.NOT_FOUND, "Unknown attributes with id " + id)); 55 | } 56 | 57 | public void addAttributes(Attributes attributes) { 58 | attributesRepository.saveAndFlush(attributes); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/action/ability/FocusTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action.ability; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.ArgumentMatchers.anyInt; 5 | import static org.mockito.Mockito.when; 6 | 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import pl.uj.io.cuteanimals.model.*; 13 | import pl.uj.io.cuteanimals.model.interfaces.RandomInteger; 14 | 15 | @ExtendWith(MockitoExtension.class) 16 | class FocusTest { 17 | @Mock private RandomInteger random; 18 | @Mock private WorldMap world; 19 | private Player player; 20 | private Monster dummy; 21 | private PlayerAttributes attrs; 22 | 23 | @BeforeEach 24 | void setUp() { 25 | player = new Player(0, world, random); 26 | attrs = (PlayerAttributes) player.getAttributes(); 27 | 28 | dummy = new Monster("dummy", new NPCAttributes(100, 1, 1, 0, 0)); 29 | player.getFightManager().beginFight(dummy); 30 | var focus = new Focus(); 31 | focus.execute(player); 32 | } 33 | 34 | @Test 35 | void shouldDrain20Mana() { 36 | attrs.addLevel(10); // Prevent level-up 37 | var manaBefore = attrs.getMana(); 38 | player.getFightManager().attack(); 39 | assertThat(attrs.getMana()).isEqualTo(manaBefore - 20); 40 | } 41 | 42 | @Test 43 | void atLeast20ManaNeeded() { 44 | attrs.addMana(-200); 45 | var result = (new Focus()).execute(player); 46 | assertThat(result.getMessage()) 47 | .isEqualTo("* Not enough mana! You need at least 20 mana to use this ability."); 48 | } 49 | 50 | @Test 51 | void attackShouldInflictAdditionalDamageLevelOneTest() { 52 | player.getFightManager().attack(); 53 | assertThat(dummy.getAttributes().getHealth()).isEqualTo(100 - 3); 54 | } 55 | 56 | @Test 57 | void attackShouldInflictAdditionalDamageLevel100Test() { 58 | when(random.nextInt(anyInt())).thenReturn(25); 59 | 60 | attrs.addAttack(49); 61 | player.getFightManager().attack(); 62 | assertThat(dummy.getAttributes().getHealth()).isEqualTo(100 - 175); 63 | } 64 | 65 | @Test 66 | void cannotCastMultipleTimes() { 67 | assertThat(new Focus().execute(player).getMessage()) 68 | .isEqualTo("* You are already focusing."); 69 | } 70 | 71 | @Test 72 | void cannotCastSomethingElse() { 73 | assertThat(new DoubleDown().execute(player).getMessage()) 74 | .isEqualTo("* You need to unleash your rage now."); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/plot/actions/DungeonEntranceGoActionTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.plot.actions; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.ArgumentMatchers.any; 5 | import static org.mockito.ArgumentMatchers.anyInt; 6 | import static org.mockito.Mockito.*; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import org.junit.jupiter.api.BeforeEach; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.extension.ExtendWith; 13 | import org.mockito.Mock; 14 | import org.mockito.junit.jupiter.MockitoExtension; 15 | import pl.uj.io.cuteanimals.model.DefaultLocation; 16 | import pl.uj.io.cuteanimals.model.GameState; 17 | import pl.uj.io.cuteanimals.model.Player; 18 | import pl.uj.io.cuteanimals.model.WorldMap; 19 | import pl.uj.io.cuteanimals.model.interfaces.ILocation; 20 | import pl.uj.io.cuteanimals.model.interfaces.RandomInteger; 21 | 22 | @ExtendWith(MockitoExtension.class) 23 | class DungeonEntranceGoActionTest { 24 | @Mock private RandomInteger rand; 25 | @Mock private Player player; 26 | private DungeonEntranceGoAction goAction; 27 | 28 | @BeforeEach 29 | void setUp() { 30 | var map = new HashMap(); 31 | map.put("location", new DefaultLocation()); 32 | goAction = new DungeonEntranceGoAction(map, rand); 33 | } 34 | 35 | @Test 36 | void passSuccessful() { 37 | var args = new ArrayList(); 38 | args.add("location"); 39 | goAction.setArgs(args); 40 | 41 | when(rand.nextInt(anyInt())).thenReturn(5); 42 | when(player.getCurrentGameState()).thenReturn(GameState.EXPLORATION); 43 | goAction.execute(player); 44 | verify(player).changeLocation(any(ILocation.class)); 45 | } 46 | 47 | @Test 48 | void passFailed() { 49 | var map = mock(WorldMap.class); 50 | player = new Player(0, map); 51 | player.setGameState(GameState.EXPLORATION); 52 | var args = new ArrayList(); 53 | args.add("location"); 54 | goAction.setArgs(args); 55 | 56 | when(rand.nextInt(anyInt())).thenReturn(1); 57 | when(map.getLocation(anyString())).thenReturn(new DefaultLocation()); 58 | 59 | goAction.execute(player); 60 | var x = verify(map).getLocation("medical"); 61 | // this is to silence spotbugs 62 | assertThat(x).isNull(); 63 | } 64 | 65 | @Test 66 | void locationNotFound() { 67 | var args = new ArrayList(); 68 | args.add("aaa"); 69 | goAction.setArgs(args); 70 | 71 | when(player.getCurrentGameState()).thenReturn(GameState.EXPLORATION); 72 | goAction.execute(player); 73 | verify(player, never()).changeLocation(any(ILocation.class)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ability/Heal.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action.ability; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.*; 5 | import pl.uj.io.cuteanimals.model.fight.*; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IAbility; 8 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 9 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 10 | 11 | public class Heal extends ArgumentlessAction implements IFightState, IAbility { 12 | private IPlayer player; 13 | private IFightState lastState; 14 | private static final int manaCost = 60; 15 | private static final int hpBonus = 10; 16 | 17 | @Override 18 | protected IResult actionBody(IPlayer player) { 19 | if (player.getAttributes().getMana() < manaCost) { 20 | return new FightLog( 21 | "Not enough mana! You need at least " + manaCost + " mana to use this ability.", 22 | Color.YELLOW); 23 | } 24 | 25 | if (player.getFightManager().getState() instanceof IAbility) { 26 | return new FightLog("You are already casting a spell.", Color.YELLOW); 27 | } 28 | 29 | this.player = player; 30 | this.lastState = player.getFightManager().getState(); 31 | this.player.getFightManager().setState(this); 32 | 33 | return new FightLog(player.toString() + " is preparing to heal himself...", Color.YELLOW); 34 | } 35 | 36 | @Override 37 | public List getAcceptableStates() { 38 | return List.of(GameState.FIGHT); 39 | } 40 | 41 | @Override 42 | public IResult attack() { 43 | player.getAttributes().addMana(-manaCost); 44 | player.getAttributes().addHealth(hpBonus); 45 | 46 | var playerAttackResult = 47 | new FightLog( 48 | player.toString() 49 | + " heals himself for " 50 | + hpBonus 51 | + " HP. " 52 | + player.toString() 53 | + " has " 54 | + player.getAttributes().getHealth() 55 | + " HP left.", 56 | Color.GREEN); 57 | 58 | player.getFightManager().setState(lastState); 59 | var contrAttackResult = contrAttack(); 60 | 61 | return new CompoundResult(List.of(playerAttackResult, contrAttackResult)); 62 | } 63 | 64 | @Override 65 | public IResult contrAttack() { 66 | return player.getFightManager().contrAttack(); 67 | } 68 | 69 | @Override 70 | public String getDescription() { 71 | return "Heal yourself. +" + hpBonus + " HP. Costs " + manaCost + " mana."; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/PlayerBackpackTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.when; 5 | 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.mockito.Mock; 10 | import org.mockito.junit.jupiter.MockitoExtension; 11 | import pl.uj.io.cuteanimals.model.entity.Attributes; 12 | import pl.uj.io.cuteanimals.model.entity.Item; 13 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 14 | 15 | @ExtendWith(MockitoExtension.class) 16 | class PlayerBackpackTest { 17 | @Mock private IAttributes attributes; 18 | private PlayerBackpack playerBackpack; 19 | 20 | @BeforeEach 21 | void setUp() { 22 | playerBackpack = new PlayerBackpack(attributes); 23 | } 24 | 25 | @Test 26 | void putItem() { 27 | when(attributes.getAttack()).thenReturn(1); 28 | var weapon = 29 | new Item( 30 | 1, 31 | "pach", 32 | "aaa", 33 | 1, 34 | new Attributes(1, 1, 1, 1, 1, 1), 35 | ItemType.WEAPON, 36 | ItemClass.ANY); 37 | var heavy = 38 | new Item( 39 | 1, 40 | "pach", 41 | "aaa", 42 | 40, 43 | new Attributes(1, 1, 1, 1, 1, 1), 44 | ItemType.WEAPON, 45 | ItemClass.ANY); 46 | 47 | assertThat(playerBackpack.putItem(weapon)); 48 | assertThat(!playerBackpack.putItem(heavy)); 49 | assertThat(playerBackpack.getItems().size()).isEqualTo(1); 50 | assertThat(playerBackpack.getItems()).contains(weapon); 51 | } 52 | 53 | @Test 54 | void removeItem() { 55 | var weapon = 56 | new Item( 57 | 1, 58 | "pach", 59 | "aaa", 60 | 1, 61 | new Attributes(1, 1, 1, 1, 1, 1), 62 | ItemType.WEAPON, 63 | ItemClass.ANY); 64 | 65 | assertThat(playerBackpack.putItem(weapon)); 66 | assertThat(playerBackpack.getItems()).contains(weapon); 67 | assertThat(playerBackpack.removeItem(weapon)); 68 | assertThat(playerBackpack.getItems()).isEmpty(); 69 | } 70 | 71 | @Test 72 | void getCapacity() { 73 | when(attributes.getAttack()).thenReturn(0); 74 | assertThat(playerBackpack.getCapacity()).isEqualTo(10); 75 | 76 | when(attributes.getAttack()).thenReturn(10); 77 | assertThat(playerBackpack.getCapacity()).isEqualTo(40); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/interpreter/Expression.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.interpreter; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import pl.uj.io.cuteanimals.action.ActionBuilder; 6 | import pl.uj.io.cuteanimals.action.MessageAction; 7 | import pl.uj.io.cuteanimals.exception.InvalidCommandException; 8 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 9 | 10 | /** 11 | * Implements formal grammar
12 | * expr ::= action args | action
13 | * action ::= `str` args
14 | * args ::= args `str` | `str` 15 | */ 16 | @FunctionalInterface 17 | public interface Expression { 18 | 19 | /** 20 | * expr ::= action ::= 'str' 21 | * 22 | * @param name Action name 23 | * @return Lambda expression returning IAction 24 | */ 25 | static Expression action(String name) { 26 | return context -> { 27 | var action = context.get(name); 28 | if (action == null) { 29 | throw new InvalidCommandException("You can't do that here."); 30 | } 31 | return action; 32 | }; 33 | } 34 | 35 | /** 36 | * args ::= 'str' 37 | * 38 | * @param arg Argument string 39 | * @return Lambda expression returning IAction 40 | */ 41 | static Expression argument(String arg) { 42 | return context -> 43 | context.getOrDefault( 44 | arg, 45 | new ActionBuilder() 46 | .addAction(new MessageAction()) 47 | .addArgs(List.of(arg)) 48 | .collect()); 49 | } 50 | 51 | /** 52 | * args ::= args 'str' 53 | * 54 | * @param arg1 Arguments expression 55 | * @param arg2 Argument string 56 | * @return Lambda expression returning IAction 57 | */ 58 | static Expression argument(Expression arg1, String arg2) { 59 | return context -> 60 | new ActionBuilder() 61 | .addAction(arg1.interpret(context)) 62 | .addArgs((List.of(arg2))) 63 | .collect(); 64 | } 65 | 66 | /** 67 | * expr ::= action args 68 | * 69 | * @param action Action expression 70 | * @param args Arguments expression 71 | * @return Lambda expression returning IAction 72 | */ 73 | static Expression expr(Expression action, Expression args) { 74 | return context -> 75 | new ActionBuilder() 76 | .addAction(action.interpret(context)) 77 | .addArgs(args.interpret(context).getArgs()) 78 | .collect(); 79 | } 80 | 81 | /** 82 | * Interprets given Expression object according to given context. 83 | * 84 | * @param context Maps action strings to their IAction equivalent 85 | * @return IAction corresponding to given expression 86 | */ 87 | IAction interpret(Map context) throws InvalidCommandException; 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/plot/actions/DungeonInvestigateActionTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.plot.actions; 2 | 3 | import static org.assertj.core.api.AssertionsForClassTypes.assertThat; 4 | import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; 5 | import static org.mockito.BDDMockito.given; 6 | 7 | import java.util.Collections; 8 | import java.util.List; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.mockito.Mock; 13 | import org.mockito.junit.jupiter.MockitoExtension; 14 | import pl.uj.io.cuteanimals.model.GameState; 15 | import pl.uj.io.cuteanimals.model.ItemClass; 16 | import pl.uj.io.cuteanimals.model.ItemType; 17 | import pl.uj.io.cuteanimals.model.Player; 18 | import pl.uj.io.cuteanimals.model.entity.Item; 19 | import pl.uj.io.cuteanimals.model.interfaces.IEquipment; 20 | 21 | @ExtendWith(MockitoExtension.class) 22 | public class DungeonInvestigateActionTest { 23 | 24 | @Mock private Player player; 25 | 26 | private DungeonInvestigateAction action; 27 | 28 | private String infoMessage; 29 | 30 | @Mock private IEquipment equipment; 31 | 32 | @BeforeEach 33 | private void setup() { 34 | infoMessage = "message"; 35 | action = new DungeonInvestigateAction(infoMessage); 36 | } 37 | 38 | @Test 39 | public void actionBodyReturnsProperMessageIfPlayerStateIsWrong() { 40 | given(player.getCurrentGameState()).willReturn(GameState.FIGHT); 41 | 42 | var result = action.actionBody(player); 43 | 44 | assertThat(result.getMessage()).isEqualTo("This action cannot be executed now"); 45 | } 46 | 47 | @Test 48 | public void actionBodyReturnsProperMessageIfStateIsCorrectAndPlayerHasTorch() { 49 | given(player.getCurrentGameState()).willReturn(GameState.EXPLORATION); 50 | given(player.getArmor()).willReturn(equipment); 51 | given(equipment.getItems()) 52 | .willReturn( 53 | List.of( 54 | new Item( 55 | 1, 56 | "Torch", 57 | "aaa", 58 | 1, 59 | null, 60 | ItemType.WEAPON, 61 | ItemClass.ANY))); 62 | 63 | var result = action.actionBody(player); 64 | 65 | assertThat(result.getMessage()).isEqualTo(infoMessage); 66 | } 67 | 68 | @Test 69 | public void actionBodyReturnsProperMessageIfStateIsCorrectAndPlayerHasNotTorch() { 70 | given(player.getCurrentGameState()).willReturn(GameState.EXPLORATION); 71 | given(player.getArmor()).willReturn(equipment); 72 | given(equipment.getItems()).willReturn(Collections.emptyList()); 73 | 74 | var result = action.actionBody(player); 75 | 76 | assertThat(result.getMessage()).isEqualTo("You can see nothing but the darkness."); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/fight/AttackState.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.fight; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.Color; 5 | import pl.uj.io.cuteanimals.model.CompoundResult; 6 | import pl.uj.io.cuteanimals.model.PlayerAttributes; 7 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 8 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 9 | 10 | public class AttackState extends FightState { 11 | 12 | public AttackState(IPlayer owner) { 13 | super(owner); 14 | } 15 | 16 | @Override 17 | public IResult attack() { 18 | var damageDone = ((PlayerAttributes) player.getAttributes()).getDamage(); 19 | player.getFightManager().getEnemy().getAttributes().addHealth(-damageDone); 20 | var mobHealthLeft = player.getFightManager().getEnemy().getAttributes().getHealth(); 21 | 22 | if (mobHealthLeft <= 0) { 23 | return player.getFightManager().endBattle(); 24 | } 25 | 26 | var playerAttackResult = 27 | new FightLog( 28 | player.toString() 29 | + " attacks " 30 | + player.getFightManager().getEnemy().getName() 31 | + " for " 32 | + damageDone 33 | + " damage. " 34 | + player.getFightManager().getEnemy().getName() 35 | + " has " 36 | + mobHealthLeft 37 | + " HP left.", 38 | Color.GREEN); 39 | 40 | return new CompoundResult(List.of(playerAttackResult, contrAttack())); 41 | } 42 | 43 | @Override 44 | public IResult contrAttack() { 45 | var enemyStats = player.getFightManager().getEnemy().getAttributes(); 46 | int took = 47 | player.takeDamage( 48 | (int) 49 | (enemyStats.getAttack() 50 | + Math.round((Math.random() * enemyStats.getLevel() * 3)))); 51 | var playerHealthLeft = player.getAttributes().getHealth(); 52 | var contrAttackResult = 53 | new FightLog( 54 | player.getFightManager().getEnemy().getName() 55 | + " attacks " 56 | + player.toString() 57 | + " for " 58 | + took 59 | + " damage. " 60 | + player.toString() 61 | + " has " 62 | + playerHealthLeft 63 | + " HP left.", 64 | Color.RED); 65 | 66 | if (playerHealthLeft <= 0) { 67 | return new CompoundResult( 68 | List.of(contrAttackResult, player.getFightManager().defeat()), Color.RED); 69 | } 70 | 71 | return contrAttackResult; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/NPC.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 5 | import pl.uj.io.cuteanimals.model.interfaces.ICharacter; 6 | import pl.uj.io.cuteanimals.model.interfaces.IEquipment; 7 | 8 | /** 9 | * Provides methods to manage npc character. 10 | * 11 | * @version %I% 12 | * @since 0.2.0-SNAPSHOT 13 | */ 14 | public class NPC implements ICharacter { 15 | private final List quotes; 16 | private IEquipment armorBackpack; 17 | private IEquipment backpack; 18 | private String name; 19 | private int quoteIndex; 20 | 21 | public NPC(IEquipment armorBackpack, IEquipment backpack, String name, List quotes) { 22 | this.armorBackpack = armorBackpack; 23 | this.backpack = backpack; 24 | this.name = name; 25 | this.quotes = quotes; 26 | this.quoteIndex = 0; 27 | } 28 | 29 | @Override 30 | public IEquipment getEquipment() { 31 | return backpack; 32 | } 33 | 34 | @Override 35 | public IEquipment getArmor() { 36 | return armorBackpack; 37 | } 38 | 39 | @Override 40 | public IAttributes getAttributes() { 41 | return null; 42 | } 43 | 44 | public void setArmorBackpack(IEquipment armorBackpack) { 45 | this.armorBackpack = armorBackpack; 46 | } 47 | 48 | public void setBackpack(IEquipment backpack) { 49 | this.backpack = backpack; 50 | } 51 | 52 | /** 53 | * Gives list of npc's possible answers. 54 | * 55 | * @return list of strings 56 | */ 57 | public List getQuotes() { 58 | return quotes; 59 | } 60 | 61 | /** 62 | * Gives the number that means how many answers have already been given by npc. Npc can still 63 | * give its answer if this number is smaller than the size of the list. 64 | * 65 | * @return int type number of answers npc gave 66 | */ 67 | public int getQuoteIndex() { 68 | return quoteIndex; 69 | } 70 | 71 | /** 72 | * Gives a text that is a typical response of a given npc to the player's "talk" action. This 73 | * can give information about this person, location, item received and what happened earlier or 74 | * what is happening at the moment. If npc gave all his possible answers or did not have any 75 | * then it returns a text saying that the person has nothing to say. 76 | * 77 | * @return string type npc's answer 78 | */ 79 | public String getQuote() { 80 | if (quoteIndex == 0 && quotes.isEmpty()) { 81 | return "This character can't tell you anything"; 82 | } else if (quoteIndex < quotes.size()) { 83 | var result = quotes.get(quoteIndex); 84 | quoteIndex++; 85 | return result; 86 | } else { 87 | return "This character can't tell you anything interesting"; 88 | } 89 | } 90 | 91 | public String getName() { 92 | return name; 93 | } 94 | 95 | public void setName(String name) { 96 | this.name = name; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/service/AttributesServiceTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.service; 2 | 3 | import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; 4 | import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; 5 | import static org.mockito.BDDMockito.given; 6 | 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.Optional; 10 | import org.assertj.core.api.AssertionsForClassTypes; 11 | import org.junit.jupiter.api.BeforeEach; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.extension.ExtendWith; 14 | import org.mockito.InjectMocks; 15 | import org.mockito.Mock; 16 | import org.mockito.junit.jupiter.MockitoExtension; 17 | import org.springframework.http.HttpStatus; 18 | import org.springframework.web.server.ResponseStatusException; 19 | import pl.uj.io.cuteanimals.model.entity.Attributes; 20 | import pl.uj.io.cuteanimals.repository.AttributesRepository; 21 | 22 | @ExtendWith(MockitoExtension.class) 23 | public class AttributesServiceTest { 24 | 25 | @Mock private AttributesRepository attributesRepository; 26 | 27 | @InjectMocks private AttributesService attributesService; 28 | 29 | private Attributes firstAttributes; 30 | 31 | private Attributes secondAttributes; 32 | 33 | @BeforeEach 34 | private void setup() { 35 | firstAttributes = new Attributes(1, 10, 20, 30, 40, 50); 36 | secondAttributes = new Attributes(2, 12, 22, 32, 42, 52); 37 | } 38 | 39 | @Test 40 | public void getAllItemsReturnsProperListIfThereAreAnyItems() { 41 | given(attributesRepository.findAll()) 42 | .willReturn(List.of(firstAttributes, secondAttributes)); 43 | 44 | var attributesList = attributesService.getAllAttributes(); 45 | 46 | assertThat(attributesList).containsExactlyInAnyOrder(firstAttributes, secondAttributes); 47 | } 48 | 49 | @Test 50 | public void getAllItemsReturnsProperEmptyListIfThereAreNoItems() { 51 | given(attributesRepository.findAll()).willReturn(Collections.emptyList()); 52 | 53 | var attributesList = attributesService.getAllAttributes(); 54 | 55 | assertThat(attributesList).isEmpty(); 56 | } 57 | 58 | @Test 59 | public void getItemSucceedAndReturnsProperIFItemExists() { 60 | given(attributesRepository.findById(1)).willReturn(Optional.ofNullable(firstAttributes)); 61 | 62 | var attributes = attributesService.getAttributes(1); 63 | 64 | AssertionsForClassTypes.assertThat(attributes).isEqualTo(firstAttributes); 65 | } 66 | 67 | @Test 68 | public void getItemThrowsNotFoundWhenItemDoesntExist() { 69 | given(attributesRepository.findById(1)).willReturn(Optional.empty()); 70 | 71 | assertThatThrownBy( 72 | () -> { 73 | attributesService.getAttributes(1); 74 | }) 75 | .isInstanceOf(ResponseStatusException.class) 76 | .hasFieldOrPropertyWithValue("status", HttpStatus.NOT_FOUND) 77 | .hasFieldOrPropertyWithValue("reason", "Unknown attributes with id 1"); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/controller/GameController.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.controller; 2 | 3 | import java.util.stream.Collectors; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | import pl.uj.io.cuteanimals.exception.InvalidCommandException; 9 | import pl.uj.io.cuteanimals.model.CompoundResult; 10 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 11 | import pl.uj.io.cuteanimals.service.GameService; 12 | 13 | @RestController 14 | @RequestMapping("/game") 15 | public class GameController { 16 | 17 | private static final Logger logger = LoggerFactory.getLogger(GameController.class); 18 | private final GameService gameService; 19 | 20 | @Autowired 21 | public GameController(GameService gameService) { 22 | this.gameService = gameService; 23 | } 24 | 25 | @GetMapping("/") 26 | public int receiveFirstFreeID() { 27 | int id = gameService.getFirstFreeID(); 28 | logger.info("New player ID: " + id); 29 | return id; 30 | } 31 | 32 | @PostMapping(value = "/{id}/msg", consumes = "text/plain", produces = "text/plain") 33 | public String receiveOrderAndReturnResult(@PathVariable int id, @RequestBody String command) { 34 | command = command.toLowerCase().trim(); 35 | 36 | logger.debug("User (" + id + ") sent command: " + command); 37 | 38 | // TODO: replace with login 39 | if ("start".equals(command)) { 40 | return gameService.pickClass(id); 41 | } 42 | try { 43 | var result = gameService.execute(id, command); 44 | 45 | logger.trace("Adding color to Result with message:"); 46 | logger.debug(result.getMessage()); 47 | return addColor(result); 48 | } catch (InvalidCommandException e) { 49 | logger.debug("Parsing user provided command failed.", e); 50 | return e.getMessage(); 51 | } 52 | } 53 | 54 | private String addColor(IResult result) { 55 | StringBuilder stringResult = new StringBuilder(); 56 | 57 | if (result instanceof CompoundResult) { 58 | return ((CompoundResult) result) 59 | .getResults() 60 | .stream() 61 | .map(this::addColor) 62 | .collect(Collectors.joining()); 63 | } else { 64 | var color = result.getColor(); 65 | var message = result.getMessage(); 66 | switch (color) { 67 | case RED: 68 | stringResult.append("\u001b[31m").append(message).append("\u001b[0m"); 69 | break; 70 | case GREEN: 71 | stringResult.append("\u001b[32m").append(message).append("\u001b[0m"); 72 | break; 73 | case YELLOW: 74 | stringResult.append("\u001b[33m").append(message).append("\u001b[0m"); 75 | break; 76 | default: 77 | stringResult.append(message); 78 | } 79 | stringResult.append("\n"); 80 | } 81 | 82 | return stringResult.toString(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/service/ItemServiceTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.service; 2 | 3 | import static org.assertj.core.api.AssertionsForClassTypes.assertThat; 4 | import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; 5 | import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; 6 | import static org.mockito.BDDMockito.given; 7 | 8 | import java.util.Collections; 9 | import java.util.List; 10 | import java.util.Optional; 11 | import org.junit.jupiter.api.BeforeEach; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.extension.ExtendWith; 14 | import org.mockito.InjectMocks; 15 | import org.mockito.Mock; 16 | import org.mockito.junit.jupiter.MockitoExtension; 17 | import org.springframework.http.HttpStatus; 18 | import org.springframework.web.server.ResponseStatusException; 19 | import pl.uj.io.cuteanimals.model.ItemClass; 20 | import pl.uj.io.cuteanimals.model.ItemType; 21 | import pl.uj.io.cuteanimals.model.entity.Item; 22 | import pl.uj.io.cuteanimals.repository.ItemsRepository; 23 | 24 | @ExtendWith(MockitoExtension.class) 25 | public class ItemServiceTest { 26 | 27 | @Mock private ItemsRepository itemsRepository; 28 | 29 | @InjectMocks private ItemService itemService; 30 | 31 | private Item firstItem; 32 | 33 | private Item secondItem; 34 | 35 | @BeforeEach 36 | private void setup() { 37 | firstItem = 38 | new Item(1, "firstItem", "first of items", 1, null, ItemType.ARMOR, ItemClass.ANY); 39 | secondItem = 40 | new Item( 41 | 2, 42 | "secondItem", 43 | "second of items", 44 | 2, 45 | null, 46 | ItemType.WEAPON, 47 | ItemClass.ANY); 48 | } 49 | 50 | @Test 51 | public void getAllItemsReturnsProperListIfThereAreAnyItems() { 52 | given(itemsRepository.findAll()).willReturn(List.of(firstItem, secondItem)); 53 | 54 | var items = itemService.getAllItems(); 55 | 56 | assertThat(items).containsExactlyInAnyOrder(firstItem, secondItem); 57 | } 58 | 59 | @Test 60 | public void getAllItemsReturnsProperEmptyListIfThereAreNoItems() { 61 | given(itemsRepository.findAll()).willReturn(Collections.emptyList()); 62 | 63 | var items = itemService.getAllItems(); 64 | 65 | assertThat(items).isEmpty(); 66 | } 67 | 68 | @Test 69 | public void getItemSucceedAndReturnsProperIFItemExists() { 70 | given(itemsRepository.findById(1)).willReturn(Optional.ofNullable(firstItem)); 71 | 72 | var item = itemService.getItem(1); 73 | 74 | assertThat(item).isEqualTo(firstItem); 75 | } 76 | 77 | @Test 78 | public void getItemThrowsNotFoundWhenItemDoesntExist() { 79 | given(itemsRepository.findById(1)).willReturn(Optional.empty()); 80 | 81 | assertThatThrownBy( 82 | () -> { 83 | itemService.getItem(1); 84 | }) 85 | .isInstanceOf(ResponseStatusException.class) 86 | .hasFieldOrPropertyWithValue("status", HttpStatus.NOT_FOUND) 87 | .hasFieldOrPropertyWithValue("reason", "Unknown item with id 1"); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/DefaultLocationTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.verify; 5 | 6 | import java.util.List; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import pl.uj.io.cuteanimals.model.entity.Attributes; 13 | import pl.uj.io.cuteanimals.model.entity.Item; 14 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 15 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 16 | 17 | @ExtendWith(MockitoExtension.class) 18 | class DefaultLocationTest { 19 | @Mock IAction action; 20 | @Mock IPlayer player; 21 | private DefaultLocation defaultLocation; 22 | 23 | @BeforeEach 24 | void setUp() { 25 | defaultLocation = new DefaultLocation(); 26 | defaultLocation.setDescription("desc"); 27 | } 28 | 29 | @Test 30 | void getDescription() { 31 | assertThat(defaultLocation.getDescription()).isEqualTo("desc"); 32 | } 33 | 34 | @Test 35 | void getAvailableActions() {} 36 | 37 | @Test 38 | void setAvailableActions() {} 39 | 40 | @Test 41 | void getNPCs() { 42 | var claudius = 43 | new NPC( 44 | null, 45 | null, 46 | "Claudius", 47 | List.of("If I were you I would run as fast as I can...")); 48 | var mag1 = new NPC(null, null, "Herschel", List.of("Please... help us!")); 49 | 50 | defaultLocation.setNPCs(List.of(claudius, mag1)); 51 | assertThat(defaultLocation.getNPCs()).contains(mag1); 52 | assertThat(defaultLocation.getNPCs()).contains(claudius); 53 | } 54 | 55 | @Test 56 | void getItems() { 57 | var armor = 58 | new Item( 59 | 1, 60 | "pach", 61 | "aaa", 62 | 1, 63 | new Attributes(1, 1, 1, 1, 1, 1), 64 | ItemType.ARMOR, 65 | ItemClass.ANY); 66 | var armor2 = 67 | new Item( 68 | 2, 69 | "pach", 70 | "aaa", 71 | 1, 72 | new Attributes(1, 1, 1, 1, 1, 1), 73 | ItemType.ARMOR, 74 | ItemClass.ANY); 75 | var backpack = new Backpack(); 76 | backpack.putItem(armor2); 77 | backpack.putItem(armor); 78 | defaultLocation.setItems(backpack); 79 | assertThat(defaultLocation.getItems().getItems()).contains(armor); 80 | assertThat(defaultLocation.getItems().getItems()).contains(armor2); 81 | } 82 | 83 | @Test 84 | void actionOnEnter() { 85 | defaultLocation.setActionOnEnter(action); 86 | assertThat(defaultLocation.getActionOnEnter()).isEqualTo(action); 87 | defaultLocation.onEnter(player); 88 | verify(action).execute(player); 89 | } 90 | 91 | @Test 92 | void nullActionOnEnter() { 93 | assertThat(defaultLocation.onEnter(player).getMessage()).isBlank(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ability/Bullseye.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action.ability; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.*; 5 | import pl.uj.io.cuteanimals.model.fight.*; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IAbility; 8 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 9 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 10 | 11 | public class Bullseye extends ArgumentlessAction implements IFightState, IAbility { 12 | private IPlayer player; 13 | private IFightState lastState; 14 | private static final int manaCost = 33; 15 | 16 | @Override 17 | protected IResult actionBody(IPlayer player) { 18 | if (player.getAttributes().getMana() < manaCost) { 19 | return new FightLog( 20 | "Not enough energy! You need at least " 21 | + manaCost 22 | + " energy to use this ability.", 23 | Color.YELLOW); 24 | } 25 | 26 | if (player.getFightManager().getState() instanceof IAbility) { 27 | return new FightLog("You are not that good at multitasking.", Color.YELLOW); 28 | } 29 | 30 | this.player = player; 31 | this.lastState = player.getFightManager().getState(); 32 | this.player.getFightManager().setState(this); 33 | 34 | return new FightLog(player.toString() + " draws bow...", Color.YELLOW); 35 | } 36 | 37 | @Override 38 | public List getAcceptableStates() { 39 | return List.of(GameState.FIGHT); 40 | } 41 | 42 | @Override 43 | public IResult attack() { 44 | var damageDone = ((PlayerAttributes) player.getAttributes()).getDamage(); 45 | player.getFightManager().getEnemy().getAttributes().addHealth(-damageDone); 46 | var mobHealthLeft = player.getFightManager().getEnemy().getAttributes().getHealth(); 47 | 48 | if (mobHealthLeft <= 0) { 49 | return player.getFightManager().endBattle(); 50 | } 51 | 52 | var playerAttackResult = 53 | new FightLog( 54 | player.toString() 55 | + " attacks " 56 | + player.getFightManager().getEnemy().getName() 57 | + " eyes for " 58 | + damageDone 59 | + " damage. " 60 | + player.getFightManager().getEnemy().getName() 61 | + " has " 62 | + mobHealthLeft 63 | + " HP left.", 64 | Color.GREEN); 65 | 66 | player.getFightManager().setState(lastState); 67 | return new CompoundResult(List.of(playerAttackResult, contrAttack())); 68 | } 69 | 70 | @Override 71 | public IResult contrAttack() { 72 | return new FightLog( 73 | player.getFightManager().getEnemy().getName() + " misses. Loser.", Color.RED); 74 | } 75 | 76 | @Override 77 | public String getDescription() { 78 | return "Blind your enemy by aiming at its eyes. Causes your enemy to miss its next attack. Costs " 79 | + manaCost 80 | + " energy."; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/entity/Attributes.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.GenerationType; 7 | import javax.persistence.Id; 8 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 9 | 10 | /** 11 | * Provides methods to represent attributes table. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | @Entity(name = "attributes") 17 | public class Attributes implements IAttributes { 18 | @JsonProperty("id") 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private final int id; 22 | 23 | @JsonProperty("health") 24 | private int health; 25 | 26 | @JsonProperty("attack") 27 | private int attack; 28 | 29 | @JsonProperty("level") 30 | private int level; 31 | 32 | @JsonProperty("defence") 33 | private int defence; 34 | 35 | @JsonProperty("mana") 36 | private int mana; 37 | 38 | public Attributes() { 39 | id = 0; 40 | health = 0; 41 | attack = 0; 42 | level = 0; 43 | defence = 0; 44 | mana = 0; 45 | } 46 | 47 | public Attributes( 48 | @JsonProperty("id") int id, 49 | @JsonProperty("health") int health, 50 | @JsonProperty("attack") int attack, 51 | @JsonProperty("level") int level, 52 | @JsonProperty("defence") int defence, 53 | @JsonProperty("mana") int mana) { 54 | this.id = id; 55 | this.health = health; 56 | this.attack = attack; 57 | this.level = level; 58 | this.defence = defence; 59 | this.mana = mana; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | var output = ""; 65 | output += (health != 0 ? "Health: " + health + ". " : ""); 66 | output += (level != 0 ? "Level: " + level + ". " : ""); 67 | output += (attack != 0 ? "Attack: " + attack + ". " : ""); 68 | output += (defence != 0 ? "Defence: " + defence + ". " : ""); 69 | output += (mana != 0 ? "Mana: " + mana + ". " : ""); 70 | return output; 71 | } 72 | 73 | @Override 74 | public int getHealth() { 75 | return health; 76 | } 77 | 78 | @Override 79 | public int getAttack() { 80 | return attack; 81 | } 82 | 83 | @Override 84 | public int getLevel() { 85 | return level; 86 | } 87 | 88 | @Override 89 | public int getDefence() { 90 | return defence; 91 | } 92 | 93 | @Override 94 | public int getMana() { 95 | return mana; 96 | } 97 | 98 | @Override 99 | public void addHealth(int health) { 100 | this.health += health; 101 | } 102 | 103 | @Override 104 | public void addAttack(int attack) { 105 | this.attack += attack; 106 | } 107 | 108 | @Override 109 | public void addLevel(int level) { 110 | this.level += level; 111 | } 112 | 113 | @Override 114 | public void addDefence(int defence) { 115 | this.defence += defence; 116 | } 117 | 118 | @Override 119 | public void addMana(int mana) { 120 | this.mana += mana; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | @rem Execute Gradle 88 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 89 | 90 | :end 91 | @rem End local scope for the variables with windows NT shell 92 | if "%ERRORLEVEL%"=="0" goto mainEnd 93 | 94 | :fail 95 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 96 | rem the _cmd.exe /c_ return code! 97 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 98 | exit /b 1 99 | 100 | :mainEnd 101 | if "%OS%"=="Windows_NT" endlocal 102 | 103 | :omega 104 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/location/LocationBuilder.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.location; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import javax.validation.constraints.NotBlank; 8 | import javax.validation.constraints.NotNull; 9 | import pl.uj.io.cuteanimals.action.*; 10 | import pl.uj.io.cuteanimals.model.Backpack; 11 | import pl.uj.io.cuteanimals.model.DefaultLocation; 12 | import pl.uj.io.cuteanimals.model.NPC; 13 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 14 | import pl.uj.io.cuteanimals.model.interfaces.IEquipment; 15 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 16 | 17 | /** Helper class used to build locations during WorldMap initialization */ 18 | public class LocationBuilder { 19 | private final DefaultLocation location; 20 | private final Map actionMap; 21 | private final List npcList; 22 | private final IEquipment equipment; 23 | private String description; 24 | private IAction actionOnEnter; 25 | 26 | public LocationBuilder(DefaultLocation location) { 27 | this.description = ""; 28 | this.actionMap = new HashMap<>(); 29 | this.npcList = new ArrayList<>(); 30 | this.equipment = new Backpack(); 31 | this.actionOnEnter = null; 32 | this.location = location; 33 | } 34 | 35 | public LocationBuilder setDescription(@NotNull String description) { 36 | this.description = description; 37 | return this; 38 | } 39 | 40 | public LocationBuilder addAction(@NotBlank String key, @NotNull IAction action) { 41 | this.actionMap.put(key, action); 42 | return this; 43 | } 44 | 45 | public LocationBuilder addDefaultActions() { 46 | this.actionMap.put("backpack", new ShowBackpack()); 47 | this.actionMap.put("throw", new ThrowAwayAction()); 48 | this.actionMap.put("equip", new EquipItem()); 49 | this.actionMap.put("off", new UnequipItem()); 50 | this.actionMap.put("stats", new ShowStats()); 51 | this.actionMap.put("skills", new ShowAbilities()); 52 | this.actionMap.put("eq", new ShowArmor()); 53 | this.actionMap.put("attack", new StandardAttack()); 54 | this.actionMap.put("block", new Block()); 55 | this.actionMap.put("use", new UseAction()); 56 | this.actionMap.put("cast", new CastAction()); 57 | this.actionMap.put("suicide", new SuicideAction()); 58 | return this; 59 | } 60 | 61 | public LocationBuilder addStartingActions() { 62 | this.actionMap.put("monk", new PickMonk()); 63 | this.actionMap.put("warrior", new PickWarrior()); 64 | this.actionMap.put("archer", new PickArcher()); 65 | return this; 66 | } 67 | 68 | public LocationBuilder addNPC(@NotNull NPC npc) { 69 | this.npcList.add(npc); 70 | return this; 71 | } 72 | 73 | public LocationBuilder addItem(@NotNull IItem item) { 74 | this.equipment.putItem(item); 75 | return this; 76 | } 77 | 78 | public LocationBuilder addActionOnEnter(@NotNull IAction action) { 79 | this.actionOnEnter = action; 80 | return this; 81 | } 82 | 83 | public DefaultLocation build() { 84 | location.setDescription(description); 85 | location.setAvailableActions(actionMap); 86 | location.setItems(equipment); 87 | location.setNPCs(npcList); 88 | location.setActionOnEnter(actionOnEnter); 89 | 90 | return location; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/entity/Item.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import javax.persistence.*; 5 | import pl.uj.io.cuteanimals.model.ItemClass; 6 | import pl.uj.io.cuteanimals.model.ItemType; 7 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 8 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 9 | 10 | /** 11 | * Provides methods to represent items table. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | @Entity(name = "items") 17 | public class Item implements IItem { 18 | @JsonProperty("id") 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private final int id; 22 | 23 | @JsonProperty("name") 24 | private final String name; 25 | 26 | @JsonProperty("description") 27 | private final String description; 28 | 29 | @JsonProperty("size") 30 | private final int size; 31 | 32 | @JsonProperty("attributes") 33 | @ManyToOne 34 | private final Attributes attributes; 35 | 36 | @JsonProperty("type") 37 | @Enumerated(EnumType.STRING) 38 | private final ItemType type; 39 | 40 | @JsonProperty("itemClass") 41 | @Enumerated(EnumType.STRING) 42 | private final ItemClass itemClass; 43 | 44 | public Item() { 45 | this.id = 0; 46 | this.name = null; 47 | this.description = null; 48 | this.size = 0; 49 | this.attributes = null; 50 | this.type = ItemType.NEUTRAL; 51 | this.itemClass = ItemClass.ANY; 52 | } 53 | 54 | public Item( 55 | @JsonProperty("id") int id, 56 | @JsonProperty("name") String name, 57 | @JsonProperty("description") String description, 58 | @JsonProperty("size") int size, 59 | @JsonProperty("attributes") Attributes attributes, 60 | @JsonProperty("type") ItemType type, 61 | @JsonProperty("itemClass") ItemClass itemClass) { 62 | this.id = id; 63 | this.name = name; 64 | this.description = description; 65 | this.size = size; 66 | this.attributes = attributes; 67 | this.type = type; 68 | this.itemClass = itemClass; 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return "Item{" 74 | + "id=" 75 | + id 76 | + ", name='" 77 | + name 78 | + '\'' 79 | + ", description='" 80 | + description 81 | + '\'' 82 | + ", size=" 83 | + size 84 | + ", attributes=" 85 | + attributes 86 | + ", type=" 87 | + type 88 | + ", itemClass=" 89 | + itemClass 90 | + '}'; 91 | } 92 | 93 | @Override 94 | public String getName() { 95 | return name; 96 | } 97 | 98 | @Override 99 | public String getDescription() { 100 | return description; 101 | } 102 | 103 | @Override 104 | public int getSize() { 105 | return size; 106 | } 107 | 108 | @Override 109 | public IAttributes getAttributes() { 110 | return attributes; 111 | } 112 | 113 | @Override 114 | public ItemType getType() { 115 | return type; 116 | } 117 | 118 | @Override 119 | public ItemClass getItemClass() { 120 | return itemClass; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ability/Focus.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action.ability; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.Color; 5 | import pl.uj.io.cuteanimals.model.CompoundResult; 6 | import pl.uj.io.cuteanimals.model.GameState; 7 | import pl.uj.io.cuteanimals.model.PlayerAttributes; 8 | import pl.uj.io.cuteanimals.model.fight.FightLog; 9 | import pl.uj.io.cuteanimals.model.fight.IFightState; 10 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 11 | import pl.uj.io.cuteanimals.model.interfaces.IAbility; 12 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 13 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 14 | 15 | public class Focus extends ArgumentlessAction implements IFightState, IAbility { 16 | private IPlayer player; 17 | private IFightState lastState; 18 | 19 | @Override 20 | protected IResult actionBody(IPlayer player) { 21 | if (player.getAttributes().getMana() < 20) { 22 | return new FightLog( 23 | "Not enough mana! You need at least 20 mana to use this ability.", 24 | Color.YELLOW); 25 | } 26 | 27 | if (player.getFightManager().getState() instanceof IAbility) { 28 | return new FightLog("You are already focusing.", Color.YELLOW); 29 | } 30 | 31 | this.player = player; 32 | this.lastState = player.getFightManager().getState(); 33 | this.player.getFightManager().setState(this); 34 | 35 | return new FightLog(player.toString() + " is focusing...", Color.YELLOW); 36 | } 37 | 38 | @Override 39 | public List getAcceptableStates() { 40 | return List.of(GameState.FIGHT); 41 | } 42 | 43 | @Override 44 | public IResult attack() { 45 | player.getAttributes().addMana(-20); 46 | var damageDone = ((PlayerAttributes) player.getAttributes()).getDamage(); 47 | var additionalDamage = 2 * player.getAttributes().getAttack(); 48 | player.getFightManager() 49 | .getEnemy() 50 | .getAttributes() 51 | .addHealth(-damageDone - additionalDamage); 52 | var mobHealthLeft = player.getFightManager().getEnemy().getAttributes().getHealth(); 53 | 54 | if (mobHealthLeft <= 0) { 55 | return player.getFightManager().endBattle(); 56 | } 57 | 58 | var playerAttackResult = 59 | new FightLog( 60 | player.toString() 61 | + " attacks " 62 | + player.getFightManager().getEnemy().getName() 63 | + " vital points for " 64 | + damageDone 65 | + "+" 66 | + additionalDamage 67 | + " damage. " 68 | + player.getFightManager().getEnemy().getName() 69 | + " has " 70 | + mobHealthLeft 71 | + " HP left.", 72 | Color.GREEN); 73 | 74 | player.getFightManager().setState(lastState); 75 | var contrAttackResult = contrAttack(); 76 | 77 | return new CompoundResult(List.of(playerAttackResult, contrAttackResult)); 78 | } 79 | 80 | @Override 81 | public IResult contrAttack() { 82 | return player.getFightManager().contrAttack(); 83 | } 84 | 85 | @Override 86 | public String getDescription() { 87 | return "Focus your attack on enemy's vital points. +(2 * Attack) damage. Costs 20 mana."; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Software Engineering 2019/2020 - Final project 2 | ![Build](https://github.com/hjaremko/io-rpg/workflows/Build/badge.svg) ![Release](https://github.com/hjaremko/cute-animals/workflows/Release/badge.svg) 3 | 4 | **Team:** Julia Cichosz, Klaudia Goska, Marek Grzelak, Hubert Jaremko, Anna Misiewicz, Łukasz Sereda 5 | 6 | ### Project description 7 | 8 | **Cute Animals** is a dark fantasy single-user dungeon RPG made as a semester project for the Software Engineering course at Jagiellonian University 9 | The game is available at https://io-rpg.herokuapp.com/. 10 | 11 | #### Gameplay 12 | 13 | The game is using a text-user-interface inspired by the Single-User Dungeon genre *(ex. Otchłań (pol))*. 14 | The player interacts with the world by typing in proper commands such as `go`, `investigate` or `pick`. 15 | Full list of available commands is in the *Documentation* section. 16 | 17 | The game flow is as follows: 18 | 1. First, the player picks his character's class. 19 | 1. Every class offers unique abilities. 20 | 1. The player goes through successive locations, where he has the opportunity to explore, interact with other characters (e.g. conversation, fight), and collect items. 21 | 1. At each stage of the game, there are different possible courses of the game. 22 | 1. The collected items can be used in the further course of the game (depending on the item: for combat, defense, or to increase a given attribute) 23 | 1. As the player overcomes successive obstacles, the player will gain experience and develop individual attributes. 24 | 25 | ### Screenshots 26 | ![](https://i.imgur.com/RdAZ0Jd.png) 27 | ![](https://i.imgur.com/e1WRDis.png) 28 | 29 | ### Used technologies 30 | - Server 31 | - Java 11 32 | - Spring MVC 33 | - PostgreSQL 34 | - Heroku 35 | - Client 36 | - xterm.js 37 | - Tests 38 | - JUnit 5 39 | - Mockito 40 | - AssertJ 41 | 42 | ### Building 43 | ``` 44 | ./gradlew build -x test 45 | ``` 46 | #### Required environment variables 47 | `SPRING_DATASOURCE_URL` : `jdbc:postgresql://localhost:5432/` 48 | `SPRING_DATASOURCE_USERNAME` : `postgres` 49 | `SPRING_DATASOURCE_PASSWORD` : your password 50 | `SPRING_PROFILES_ACTIVE` : `dev` or `prod` 51 | 52 | ### Documentation 53 | 54 | 55 | Full documentation, test and coverage reports, binary files are in [artifacts](https://github.com/hjaremko/cute-animals/actions). 56 | 57 | #### UML diagrams are [here](./assets/UML.md). 58 | 59 | 60 | #### Avaiable commands 61 | - ```start``` - starts the game 62 | - ```investigate``` - provides a description of the current location 63 | - ```talk ``` - allows you to talk to individual characters 64 | - ```go ``` - allows you to go to another location 65 | - ```pick ``` - allows you to pick up an item and put it in your backpack 66 | - ```throw ``` - allows you to discard an item out of the backpack 67 | - ```equip ``` - allows you to put on an item from a backpack 68 | - ```off ```- allows you to unequip an item and put it in the backpack 69 | - ```backpack``` - lists the current state of the backpack 70 | - ```eq``` - lists the currently equipped items 71 | - ```stats``` - lists the character's statistics 72 | - ```skills``` - lists the character's abilities 73 | - ```fight ``` - allows you to fight individual characters 74 | - ```attack``` - allows you to attack in combat mode 75 | - ```block``` - reduces damage in the next two turns in combat mode 76 | - ```use ``` - allows you to use an item 77 | - ```cast ``` - allows the use of a given skill in combat mode 78 | - ```suicide``` - allows you to reset the game to its initial state 79 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/ArmorBackpack.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import pl.uj.io.cuteanimals.model.interfaces.IAttributes; 6 | import pl.uj.io.cuteanimals.model.interfaces.IEquipment; 7 | import pl.uj.io.cuteanimals.model.interfaces.IItem; 8 | 9 | /** 10 | * Provides methods to menage Player's Armor Backpack. Allows him to put, remove and display those 11 | * items. 12 | * 13 | * @version %I% 14 | * @since 0.0.1-SNAPSHOT 15 | */ 16 | public class ArmorBackpack implements IEquipment { 17 | private final IAttributes ownerAttributes; 18 | private IItem weapon; 19 | private IItem armor; 20 | 21 | public ArmorBackpack(IAttributes ownerAttributes) { 22 | this.ownerAttributes = ownerAttributes; 23 | } 24 | 25 | @Override 26 | public List getItems() { 27 | var eq = new ArrayList(); 28 | 29 | if (weapon != null) { 30 | eq.add(weapon); 31 | } 32 | 33 | if (armor != null) { 34 | eq.add(armor); 35 | } 36 | 37 | return eq; 38 | } 39 | 40 | @Override 41 | public boolean putItem(IItem item) { 42 | if (item.getAttributes().getLevel() > ownerAttributes.getLevel()) { 43 | return false; 44 | } 45 | 46 | if (item.getType() == ItemType.WEAPON && weapon == null) { 47 | this.weapon = item; 48 | return true; 49 | } 50 | 51 | if (item.getType() == ItemType.ARMOR && armor == null) { 52 | this.armor = item; 53 | return true; 54 | } 55 | 56 | return false; 57 | } 58 | 59 | @Override 60 | public boolean removeItem(IItem item) { 61 | if (weapon == item) { 62 | weapon = null; 63 | return true; 64 | } 65 | 66 | if (armor == item) { 67 | armor = null; 68 | return true; 69 | } 70 | 71 | return false; 72 | } 73 | 74 | @Override 75 | public String showItems() { 76 | StringBuilder stringBuilder = new StringBuilder(); 77 | if (weapon != null || armor != null) { 78 | stringBuilder.append("You wear the following items: "); 79 | } 80 | if (weapon != null) { 81 | stringBuilder 82 | .append("\n \n") 83 | .append("Left hand: ") 84 | .append(weapon.getName()) 85 | .append("\n") 86 | .append("Description: ") 87 | .append(weapon.getDescription()) 88 | .append(", Type: ") 89 | .append(weapon.getType().toString()) 90 | .append(", Size: ") 91 | .append(weapon.getSize()) 92 | .append(", ") 93 | .append(weapon.getAttributes().toString()); 94 | } 95 | if (armor != null) { 96 | stringBuilder 97 | .append("\n \n") 98 | .append("Right hand: ") 99 | .append(armor.getName()) 100 | .append("\n") 101 | .append("Description: ") 102 | .append(armor.getDescription()) 103 | .append(", Type: ") 104 | .append(armor.getType().toString()) 105 | .append(", Size: ") 106 | .append(armor.getSize()) 107 | .append(", ") 108 | .append(armor.getAttributes().toString()); 109 | } 110 | 111 | return stringBuilder.toString(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/action/ability/DoubleDown.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.action.ability; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.*; 5 | import pl.uj.io.cuteanimals.model.fight.*; 6 | import pl.uj.io.cuteanimals.model.interfaces.ArgumentlessAction; 7 | import pl.uj.io.cuteanimals.model.interfaces.IAbility; 8 | import pl.uj.io.cuteanimals.model.interfaces.IPlayer; 9 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 10 | 11 | public class DoubleDown extends ArgumentlessAction implements IFightState, IAbility { 12 | private IPlayer player; 13 | private IFightState lastState; 14 | private static final int manaCost = 50; 15 | 16 | @Override 17 | protected IResult actionBody(IPlayer player) { 18 | if (player.getAttributes().getMana() < manaCost) { 19 | return new FightLog( 20 | "Not enough energy! You need at least " 21 | + manaCost 22 | + " energy to use this ability.", 23 | Color.YELLOW); 24 | } 25 | 26 | if (player.getFightManager().getState() instanceof IAbility) { 27 | return new FightLog("You need to unleash your rage now.", Color.YELLOW); 28 | } 29 | 30 | this.player = player; 31 | this.lastState = player.getFightManager().getState(); 32 | this.player.getFightManager().setState(this); 33 | 34 | return new FightLog(player.toString() + " is getting angry...", Color.YELLOW); 35 | } 36 | 37 | @Override 38 | public List getAcceptableStates() { 39 | return List.of(GameState.FIGHT); 40 | } 41 | 42 | @Override 43 | public IResult attack() { 44 | player.getAttributes().addMana(-manaCost); 45 | var damageDone = ((PlayerAttributes) player.getAttributes()).getDamage(); 46 | var firstHitDmg = (int) (damageDone * 1.25); 47 | var secondHitDmg = (int) (damageDone * 1.70); 48 | var thirdHitDmg = damageDone * 2; 49 | 50 | player.getFightManager() 51 | .getEnemy() 52 | .getAttributes() 53 | .addHealth(-(firstHitDmg + secondHitDmg + thirdHitDmg)); 54 | var mobHealthLeft = player.getFightManager().getEnemy().getAttributes().getHealth(); 55 | 56 | if (mobHealthLeft <= 0) { 57 | return player.getFightManager().endBattle(); 58 | } 59 | 60 | var playerAttackResult = 61 | new FightLog( 62 | player.toString() 63 | + " furiously attacks " 64 | + player.getFightManager().getEnemy().getName() 65 | + " for " 66 | + firstHitDmg 67 | + "+" 68 | + secondHitDmg 69 | + "+" 70 | + thirdHitDmg 71 | + " damage. " 72 | + player.getFightManager().getEnemy().getName() 73 | + " has " 74 | + mobHealthLeft 75 | + " HP left.", 76 | Color.GREEN); 77 | 78 | player.getFightManager().setState(lastState); 79 | var contrAttackResult = contrAttack(); 80 | 81 | return new CompoundResult(List.of(playerAttackResult, contrAttackResult)); 82 | } 83 | 84 | @Override 85 | public IResult contrAttack() { 86 | return player.getFightManager().contrAttack(); 87 | } 88 | 89 | @Override 90 | public String getDescription() { 91 | return "Attack your enemy three consecutive times. Respectively: x1.25 dmg, x1.70 dmg, x2 dmg. Costs " 92 | + manaCost 93 | + " energy."; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /gradle/static-code-analysis/pmd/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 17 | 18 | 19 | PMD Rules Configuration 20 | 21 | 22 | .*Mock\.java 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/Player.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import pl.uj.io.cuteanimals.action.BuffCharacter; 6 | import pl.uj.io.cuteanimals.model.fight.FightManager; 7 | import pl.uj.io.cuteanimals.model.interfaces.*; 8 | 9 | /** 10 | * Provides methods to manage player. 11 | * 12 | * @version %I% 13 | * @since 0.2.0-SNAPSHOT 14 | */ 15 | public class Player implements IPlayer { 16 | private final int id; 17 | private final WorldMap world; 18 | private final IEquipment armorBackpack; 19 | private final IEquipment backpack; 20 | private final FightManager fightManager; 21 | private PlayerClass playerClass; 22 | private PlayerAttributes stats; 23 | private ILocation currentLocation; 24 | private GameState gameState; 25 | 26 | public Player(int id, WorldMap world) { 27 | this.id = id; 28 | this.world = world; 29 | this.stats = new PlayerAttributes(this); 30 | this.currentLocation = world.getLocation("town"); 31 | this.armorBackpack = new ArmorBackpack(this.stats); 32 | this.backpack = new PlayerBackpack(this.stats); 33 | this.gameState = GameState.LIMBO; 34 | this.fightManager = new FightManager(this); 35 | this.playerClass = new Slave(); 36 | } 37 | 38 | public Player(int id, WorldMap world, RandomInteger random) { 39 | this(id, world); 40 | this.stats = new PlayerAttributes(this, random); 41 | } 42 | 43 | @Override 44 | public IEquipment getEquipment() { 45 | return backpack; 46 | } 47 | 48 | @Override 49 | public IEquipment getArmor() { 50 | return armorBackpack; 51 | } 52 | 53 | @Override 54 | public IAttributes getAttributes() { 55 | return stats; 56 | } 57 | 58 | @Override 59 | public IResult use(IItem item) { 60 | if (item.getType() != ItemType.USABLE) { 61 | return new Result("You can't use that."); 62 | } 63 | 64 | var eatingResult = new BuffCharacter(item.getAttributes()).execute(this); 65 | getEquipment().removeItem(item); 66 | var attackResult = fightManager.contrAttack(); 67 | 68 | if (attackResult != null) { 69 | return new CompoundResult(List.of(eatingResult, attackResult)); 70 | } 71 | 72 | return eatingResult; 73 | } 74 | 75 | @Override 76 | public IResult changeLocation(ILocation where) { 77 | currentLocation = where; 78 | return currentLocation.onEnter(this); 79 | } 80 | 81 | @Override 82 | public ILocation getCurrentLocation() { 83 | return currentLocation; 84 | } 85 | 86 | @Override 87 | public GameState getCurrentGameState() { 88 | return gameState; 89 | } 90 | 91 | @Override 92 | public void setGameState(GameState gameState) { 93 | this.gameState = gameState; 94 | } 95 | 96 | @Override 97 | public String toString() { 98 | return playerClass.toString(); 99 | } 100 | 101 | @Override 102 | public FightManager getFightManager() { 103 | return fightManager; 104 | } 105 | 106 | @Override 107 | public int takeDamage(int damage) { 108 | var taken = Math.max(0, damage - (stats.getDefence() / 2)); 109 | stats.addHealth(-taken); 110 | return taken; 111 | } 112 | 113 | @Override 114 | public Map getAbilities() { 115 | return playerClass.getAbilities(); 116 | } 117 | 118 | @Override 119 | public WorldMap getWorld() { 120 | return world; 121 | } 122 | 123 | @Override 124 | public void setClass(PlayerClass playerClass) { 125 | this.playerClass = playerClass; 126 | } 127 | 128 | public int getId() { 129 | return id; 130 | } 131 | 132 | @Override 133 | public PlayerClass getPlayerClass() { 134 | return playerClass; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/PlayerAttributes.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import pl.uj.io.cuteanimals.model.interfaces.ICharacter; 4 | import pl.uj.io.cuteanimals.model.interfaces.RandomInteger; 5 | 6 | /** 7 | * Provides methods to manage player's attributes. 8 | * 9 | * @version %I% 10 | * @since 0.2.0-SNAPSHOT 11 | */ 12 | public class PlayerAttributes extends NPCAttributes { 13 | private final ICharacter owner; 14 | private final RandomInteger random; 15 | private int experience; 16 | 17 | public PlayerAttributes(ICharacter owner) { 18 | super(50, 1, 1, 0, 100); 19 | this.owner = owner; 20 | this.experience = 0; 21 | random = new RandomIntegerImpl(); 22 | } 23 | 24 | public PlayerAttributes(ICharacter owner, RandomInteger random) { 25 | super(50, 1, 1, 0, 100); 26 | this.owner = owner; 27 | this.experience = 0; 28 | this.random = random; 29 | } 30 | 31 | @Override 32 | public int getHealth() { 33 | return health 34 | + owner.getArmor() 35 | .getItems() 36 | .stream() 37 | .mapToInt(i -> i.getAttributes().getHealth()) 38 | .sum(); 39 | } 40 | 41 | @Override 42 | public int getAttack() { 43 | return attack 44 | + owner.getArmor() 45 | .getItems() 46 | .stream() 47 | .mapToInt(i -> i.getAttributes().getAttack()) 48 | .sum(); 49 | } 50 | 51 | @Override 52 | public int getLevel() { 53 | return level; 54 | } 55 | 56 | @Override 57 | public int getDefence() { 58 | return defence 59 | + owner.getArmor() 60 | .getItems() 61 | .stream() 62 | .mapToInt(i -> i.getAttributes().getDefence()) 63 | .sum(); 64 | } 65 | 66 | public int getExperience() { 67 | return experience; 68 | } 69 | 70 | public int getRequiredExperience() { 71 | return super.getLevel() * 2; 72 | } 73 | 74 | public void addExperience(int experience) { 75 | var expBefore = this.experience; 76 | boolean levelUp = this.experience + experience >= getRequiredExperience(); 77 | this.experience = (this.experience + experience) % getRequiredExperience(); 78 | 79 | if (levelUp) { 80 | addAttack(getLevel()); 81 | addDefence(getLevel()); 82 | addMana(100); 83 | addHealth(getLevel() * 10); 84 | addLevel(1); 85 | } 86 | } 87 | 88 | public int getMana() { 89 | return mana 90 | + owner.getArmor() 91 | .getItems() 92 | .stream() 93 | .mapToInt(i -> i.getAttributes().getMana()) 94 | .sum(); 95 | } 96 | 97 | public void addMana(int mana) { 98 | this.mana += mana; 99 | } 100 | 101 | public int getDamage() { 102 | var attackBonus = (int) (getAttack() / 2.0); 103 | return getAttack() + (attackBonus > 0 ? random.nextInt(attackBonus) : 0); 104 | } 105 | 106 | @Override 107 | public String toString() { 108 | var exp = "Experience: " + getExperience() + " / " + getRequiredExperience() + "\n"; 109 | var stats = 110 | "Health: " 111 | + getHealth() 112 | + "\n" 113 | + "Mana: " 114 | + getMana() 115 | + "\n" 116 | + "Level: " 117 | + getLevel() 118 | + "\n" 119 | + "Attack: " 120 | + getAttack() 121 | + "\n" 122 | + "Defence: " 123 | + getDefence(); 124 | return exp + stats; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | name: Build project 8 | runs-on: ubuntu-20.04 9 | 10 | services: 11 | postgres: 12 | image: postgres 13 | env: 14 | POSTGRES_USER: postgres 15 | POSTGRES_PASSWORD: postgres 16 | POSTGRES_DB: io_rpg 17 | ports: 18 | - 5432:5432 19 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v2 24 | - name: Set up JDK 25 | uses: actions/setup-java@v1 26 | with: 27 | java-version: 11 28 | - name: Grant execute permission for gradlew 29 | run: chmod +x gradlew 30 | - name: Cache Gradle packages 31 | uses: actions/cache@v2 32 | with: 33 | path: ~/.gradle/caches 34 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 35 | restore-keys: ${{ runner.os }}-gradle 36 | - name: Build with Gradle 37 | run: ./gradlew build -x verifyGoogleJavaFormat -x test 38 | - name: Upload artifacts 39 | uses: actions/upload-artifact@v2 40 | with: 41 | name: binary 42 | path: build/libs 43 | - name: Run tests and generate reports 44 | env: 45 | SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/io_rpg 46 | SPRING_DATASOURCE_USERNAME: postgres 47 | SPRING_DATASOURCE_PASSWORD: postgres 48 | SPRING_PROFILES_ACTIVE: prod 49 | run: ./gradlew test jacocoTestReport 50 | - name: Upload code coverage report 51 | uses: actions/upload-artifact@v1 52 | with: 53 | name: coverage_report 54 | path: build/reports/jacoco/test/html 55 | - name: Upload test report 56 | uses: actions/upload-artifact@v1 57 | with: 58 | name: test_report 59 | path: build/reports/tests/test 60 | - name: Upload PMD main report 61 | uses: actions/upload-artifact@v1 62 | with: 63 | name: pmd_report 64 | path: build/reports/pmd/main.html 65 | - name: Upload PMD test report 66 | uses: actions/upload-artifact@v1 67 | with: 68 | name: pmd_report 69 | path: build/reports/pmd/test.html 70 | - name: Upload SpotBugs main report 71 | uses: actions/upload-artifact@v1 72 | with: 73 | name: spotbugs_report 74 | path: build/reports/spotbugs/main.xml 75 | - name: Upload SpotBugs test report 76 | uses: actions/upload-artifact@v1 77 | with: 78 | name: spotbugs_report 79 | path: build/reports/spotbugs/test.xml 80 | - name: Generate JavaDoc 81 | run: ./gradlew javadoc 82 | - name: Upload JavaDoc 83 | uses: actions/upload-artifact@v1 84 | with: 85 | name: javadoc 86 | path: build/docs/javadoc 87 | 88 | formatting: 89 | name: Verify formatting 90 | runs-on: ubuntu-latest 91 | steps: 92 | - name: Checkout code 93 | uses: actions/checkout@v2 94 | - name: Set up JDK 95 | uses: actions/setup-java@v1 96 | with: 97 | java-version: "11" 98 | - name: Verify formatting 99 | run: ./gradlew verifyGoogleJavaFormat 100 | 101 | deploy: 102 | name: Deploy on Heroku 103 | needs: build 104 | if: github.ref == 'refs/heads/master' && github.event_name == 'push' 105 | runs-on: ubuntu-latest 106 | steps: 107 | - name: Checkout code 108 | uses: actions/checkout@v2 109 | - name: Download binary 110 | uses: actions/download-artifact@v2 111 | with: 112 | name: binary 113 | path: build/libs 114 | - run: ls -R 115 | - name: Deploy 116 | uses: akhileshns/heroku-deploy@v3.0.4 117 | with: 118 | heroku_api_key: ${{secrets.HEROKU_API_KEY}} 119 | heroku_app_name: "io-rpg-dev" 120 | heroku_email: "hjaremko@outlook.com" 121 | usedocker: true 122 | docker_heroku_process_type: "web" 123 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/controller/ItemControllerTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.controller; 2 | 3 | import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; 4 | import static org.mockito.BDDMockito.given; 5 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 6 | 7 | import java.util.Collections; 8 | import java.util.List; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.mockito.InjectMocks; 13 | import org.mockito.Mock; 14 | import org.mockito.junit.jupiter.MockitoExtension; 15 | import org.springframework.http.HttpStatus; 16 | import org.springframework.http.MediaType; 17 | import org.springframework.test.web.servlet.MockMvc; 18 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 19 | import pl.uj.io.cuteanimals.model.ItemClass; 20 | import pl.uj.io.cuteanimals.model.ItemType; 21 | import pl.uj.io.cuteanimals.model.entity.Item; 22 | import pl.uj.io.cuteanimals.service.ItemService; 23 | 24 | @ExtendWith(MockitoExtension.class) 25 | public class ItemControllerTest { 26 | 27 | private MockMvc mockMvc; 28 | 29 | @Mock private ItemService itemService; 30 | 31 | @InjectMocks private ItemController itemController; 32 | 33 | private Item firstItem; 34 | 35 | private Item secondItem; 36 | 37 | @BeforeEach 38 | private void setup() { 39 | mockMvc = MockMvcBuilders.standaloneSetup(itemController).build(); 40 | 41 | firstItem = 42 | new Item(1, "firstItem", "first of items", 1, null, ItemType.ARMOR, ItemClass.ANY); 43 | secondItem = 44 | new Item( 45 | 2, 46 | "secondItem", 47 | "second of items", 48 | 2, 49 | null, 50 | ItemType.WEAPON, 51 | ItemClass.ANY); 52 | } 53 | 54 | @Test 55 | public void getItemSucceedAndReturnProperItem() throws Exception { 56 | given(itemService.getItem(1)).willReturn(firstItem); 57 | 58 | var response = 59 | mockMvc.perform(get("/items/1").accept(MediaType.APPLICATION_JSON)) 60 | .andReturn() 61 | .getResponse(); 62 | 63 | assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); 64 | assertThat(response.getContentAsString()).contains("first of items"); 65 | } 66 | 67 | @Test 68 | public void getItemSucceedAndReturnNullIfItemDoesntExist() throws Exception { 69 | given(itemService.getItem(3)).willReturn(null); 70 | 71 | var response = 72 | mockMvc.perform(get("/items/3").accept(MediaType.APPLICATION_JSON)) 73 | .andReturn() 74 | .getResponse(); 75 | 76 | assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); 77 | assertThat(response.getContentAsString()).isEqualTo(""); 78 | } 79 | 80 | @Test 81 | public void getAllItemsSucceedAndReturnProperListOfItems() throws Exception { 82 | given(itemService.getAllItems()).willReturn(List.of(firstItem, secondItem)); 83 | 84 | var response = 85 | mockMvc.perform(get("/items").accept(MediaType.APPLICATION_JSON)) 86 | .andReturn() 87 | .getResponse(); 88 | 89 | assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); 90 | assertThat(response.getContentAsString()).contains("first of items"); 91 | assertThat(response.getContentAsString()).contains("second of items"); 92 | } 93 | 94 | @Test 95 | public void getAllItemsSucceedAndReturnEmptyListIfItemsDoesntExist() throws Exception { 96 | given(itemService.getAllItems()).willReturn(Collections.emptyList()); 97 | 98 | var response = 99 | mockMvc.perform(get("/items").accept(MediaType.APPLICATION_JSON)) 100 | .andReturn() 101 | .getResponse(); 102 | 103 | assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); 104 | assertThat(response.getContentAsString()).isEqualTo("[]"); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/model/PlayerTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.ArgumentMatchers.anyString; 5 | import static org.mockito.Mockito.*; 6 | 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import pl.uj.io.cuteanimals.model.entity.Attributes; 13 | import pl.uj.io.cuteanimals.model.entity.Item; 14 | import pl.uj.io.cuteanimals.model.interfaces.ILocation; 15 | 16 | @ExtendWith(MockitoExtension.class) 17 | class PlayerTest { 18 | @Mock private WorldMap world; 19 | Player player; 20 | private PlayerAttributes attrs; 21 | private ILocation town; 22 | 23 | @BeforeEach 24 | void setUp() { 25 | player = new Player(0, world); 26 | town = new DefaultLocation(); 27 | attrs = (PlayerAttributes) player.getAttributes(); 28 | player.setGameState(GameState.EXPLORATION); 29 | } 30 | 31 | @Test 32 | void getEquipment() { 33 | assertThat(player.getEquipment().getItems()).isEmpty(); 34 | } 35 | 36 | @Test 37 | void getArmor() { 38 | assertThat(player.getArmor().getItems()).isEmpty(); 39 | } 40 | 41 | @Test 42 | void useShouldAddAttributesPermanentlyNoFight() { 43 | when(world.getLocation(anyString())).thenReturn(town); 44 | var statsBefore = new Player(0, world).getAttributes(); 45 | var item = 46 | new Item( 47 | 1, 48 | "it", 49 | "desc", 50 | 1, 51 | new Attributes(1, 100, 100, 100, 100, 100), 52 | ItemType.USABLE, 53 | ItemClass.ANY); 54 | player.use(item); 55 | 56 | assertThat(attrs.getHealth()) 57 | .isEqualTo(statsBefore.getHealth() + item.getAttributes().getHealth()); 58 | assertThat(attrs.getAttack()) 59 | .isEqualTo(statsBefore.getAttack() + item.getAttributes().getAttack()); 60 | assertThat(attrs.getLevel()).isEqualTo(statsBefore.getLevel()); 61 | assertThat(attrs.getDefence()) 62 | .isEqualTo(statsBefore.getDefence() + item.getAttributes().getDefence()); 63 | assertThat(attrs.getMana()) 64 | .isEqualTo(statsBefore.getMana() + item.getAttributes().getMana()); 65 | } 66 | 67 | @Test 68 | void unusableItemsShouldDoNothing() { 69 | when(world.getLocation(anyString())).thenReturn(town); 70 | var statsBefore = new Player(0, world).getAttributes(); 71 | var item = 72 | new Item( 73 | 1, 74 | "it", 75 | "desc", 76 | 1, 77 | new Attributes(1, 100, 100, 100, 100, 100), 78 | ItemType.NEUTRAL, 79 | ItemClass.ANY); 80 | player.use(item); 81 | 82 | assertThat(attrs.getHealth()).isEqualTo(statsBefore.getHealth()); 83 | assertThat(attrs.getAttack()).isEqualTo(statsBefore.getAttack()); 84 | assertThat(attrs.getLevel()).isEqualTo(statsBefore.getLevel()); 85 | assertThat(attrs.getDefence()).isEqualTo(statsBefore.getDefence()); 86 | assertThat(attrs.getMana()).isEqualTo(statsBefore.getMana()); 87 | } 88 | 89 | @Test 90 | void changeLocation() { 91 | when(world.getLocation(anyString())).thenReturn(town); 92 | player = new Player(0, world); 93 | 94 | var inn = spy(new DefaultLocation()); 95 | assertThat(player.getCurrentLocation()).isEqualTo(town); 96 | player.changeLocation(inn); 97 | verify(inn).onEnter(player); 98 | } 99 | 100 | @Test 101 | void armorShouldBlockDamage() { 102 | var beforeAttack = attrs.getHealth(); 103 | attrs.addDefence(100); 104 | player.takeDamage(100); 105 | assertThat(attrs.getHealth()).isEqualTo(beforeAttack - 50); 106 | } 107 | 108 | @Test 109 | void getWorld() { 110 | assertThat(player.getWorld()).isNotNull(); 111 | } 112 | 113 | @Test 114 | void setClass() { 115 | player.setClass(new Monk()); 116 | assertThat(player.getAbilities()).containsKeys("heal"); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/pl/uj/io/cuteanimals/interpreter/InterpreterTest.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.interpreter; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.junit.jupiter.api.Assertions.assertThrows; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.mockito.Mock; 13 | import org.mockito.junit.jupiter.MockitoExtension; 14 | import pl.uj.io.cuteanimals.action.GoAction; 15 | import pl.uj.io.cuteanimals.action.InvestigateAction; 16 | import pl.uj.io.cuteanimals.exception.InvalidCommandException; 17 | import pl.uj.io.cuteanimals.model.DefaultLocation; 18 | import pl.uj.io.cuteanimals.model.Player; 19 | import pl.uj.io.cuteanimals.model.WorldMap; 20 | import pl.uj.io.cuteanimals.model.interfaces.IAction; 21 | 22 | @ExtendWith(MockitoExtension.class) 23 | class InterpreterTest { 24 | private final Interpreter interpreter = new Interpreter(); 25 | @Mock private WorldMap world; 26 | private Player player; 27 | 28 | @BeforeEach 29 | void setUp() { 30 | player = new Player(0, world); 31 | } 32 | 33 | @Test 34 | void singleActionParseTest() throws InvalidCommandException { 35 | Map context = new HashMap<>(); 36 | context.put("investigate", new InvestigateAction("Looking around null")); 37 | var expr = interpreter.parse("investigate", context); 38 | 39 | var result = expr.interpret(context); 40 | 41 | assertThat(result.execute(player).getMessage().equals("Looking around null")); 42 | } 43 | 44 | @Test 45 | void actionWithArgsParseTest() throws InvalidCommandException { 46 | Map context = new HashMap<>(); 47 | context.put("go", new GoAction(Map.of("flavour", new DefaultLocation()))); 48 | var expr = interpreter.parse("go flavour town", context); 49 | 50 | var result = expr.interpret(context); 51 | 52 | assertThat(result.execute(player).getMessage().equals("Going to [flavour, town]")); 53 | } 54 | 55 | @Test 56 | void argumentInterpretTest() throws InvalidCommandException { 57 | Map context = new HashMap<>(); 58 | var arg = Expression.argument("left"); 59 | 60 | var result = arg.interpret(context); 61 | 62 | assertThat(result.execute(player).getMessage().equals("[left]")); 63 | } 64 | 65 | @Test 66 | void multipleArgumentParseTest() throws InvalidCommandException { 67 | Map context = new HashMap<>(); 68 | var left = Expression.argument("left"); 69 | var right = Expression.argument(left, "right"); 70 | var up = Expression.argument(right, "up"); 71 | 72 | var result = up.interpret(context); 73 | 74 | assertThat( 75 | result.execute(player) 76 | .getMessage() 77 | .equals(List.of("up", "right", "left").toString())); 78 | } 79 | 80 | @Test 81 | void invalidCommandTest() { 82 | Map context = new HashMap<>(); 83 | 84 | assertThrows( 85 | InvalidCommandException.class, () -> interpreter.parse("i am invalid", context)); 86 | } 87 | 88 | @Test 89 | void singleInvalidTokenTest() { 90 | Map context = new HashMap<>(); 91 | 92 | assertThrows(InvalidCommandException.class, () -> interpreter.parse("invalid", context)); 93 | } 94 | 95 | @Test 96 | void multipleActionTokenTest() { 97 | Map context = new HashMap<>(); 98 | 99 | assertThrows( 100 | InvalidCommandException.class, 101 | () -> interpreter.parse("go go invalid go", context)); 102 | assertThrows( 103 | InvalidCommandException.class, () -> interpreter.parse("go go go go go", context)); 104 | assertThrows( 105 | InvalidCommandException.class, () -> interpreter.parse("go go go go", context)); 106 | assertThrows(InvalidCommandException.class, () -> interpreter.parse("go go go", context)); 107 | assertThrows(InvalidCommandException.class, () -> interpreter.parse("go go", context)); 108 | } 109 | 110 | @Test 111 | void reversedArgumentsTest() { 112 | Map context = new HashMap<>(); 113 | 114 | assertThrows(InvalidCommandException.class, () -> interpreter.parse("flavour go", context)); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/pl/uj/io/cuteanimals/model/fight/FightManager.java: -------------------------------------------------------------------------------- 1 | package pl.uj.io.cuteanimals.model.fight; 2 | 3 | import java.util.List; 4 | import pl.uj.io.cuteanimals.model.*; 5 | import pl.uj.io.cuteanimals.model.interfaces.IResult; 6 | 7 | public class FightManager { 8 | private final Player player; 9 | private Monster fightingWith; 10 | private IFightState fightState; 11 | 12 | public FightManager(Player player) { 13 | this.player = player; 14 | this.fightState = new ExplorationState(this.player); 15 | } 16 | 17 | public String beginFight(Monster monster) { 18 | this.fightingWith = monster; 19 | this.fightState = new AttackState(player); 20 | player.setGameState(GameState.FIGHT); 21 | 22 | return "Fight begins: " 23 | + player.toString() 24 | + " (" 25 | + player.getAttributes().getLevel() 26 | + ") vs. " 27 | + monster.getName() 28 | + " (" 29 | + monster.getAttributes().getLevel() 30 | + ")"; 31 | } 32 | 33 | public IResult attack() { 34 | return fightState.attack(); 35 | } 36 | 37 | public IResult contrAttack() { 38 | return fightState.contrAttack(); 39 | } 40 | 41 | public IResult block() { 42 | if (fightState instanceof BlockState) { 43 | return new FightLog("You are already blocking.", Color.YELLOW); 44 | } 45 | 46 | fightState = new BlockState(player); 47 | 48 | var blockMessage = player.toString() + " is preparing to block incoming attacks."; 49 | return new FightLog(blockMessage, Color.YELLOW); 50 | } 51 | 52 | public IResult endBattle() { 53 | player.setGameState(GameState.EXPLORATION); 54 | 55 | var playerAttrs = (PlayerAttributes) player.getAttributes(); 56 | var playerLevel = playerAttrs.getLevel(); 57 | var enemyLevel = fightingWith.getAttributes().getLevel(); 58 | var expBonus = playerLevel <= enemyLevel ? (enemyLevel - playerLevel + 2) : 1; 59 | var baseExp = playerAttrs.getRequiredExperience() / 6; 60 | var levelPenalty = playerLevel < enemyLevel ? 2 : 1; 61 | var gainedExperience = baseExp / levelPenalty + expBonus; 62 | 63 | ((PlayerAttributes) player.getAttributes()).addExperience(gainedExperience); 64 | player.getFightManager().setState(new ExplorationState(player)); 65 | 66 | if (fightingWith.getName().equals("Fasilius")) { 67 | return new CompoundResult( 68 | List.of( 69 | new FightLog( 70 | "You managed to defeat Fasilius! It seems as if deadly danger has been averted. " 71 | + "You are bursting with pride. You feel incredibly exhausted. " 72 | + "You realized that the monks are still stuck in a cell so you rush to their rescue. " 73 | + "You feel relief and incredible happiness incomparably with anything you have experienced so far. \n" 74 | + "Merlin: \"Thank you Lord for your rescue. According to the parable of the great wanderers, three alternative paths of the future await you. It is our duty to present them to you. I, Merlin present the left gate for you ...\n" 75 | + "Herschel: \"I Herschel introduce you to the middle gate ...\"\n" 76 | + "Donovan: \"I Donovan present you the right door ...\"\n" 77 | + "Merlin: \"Your whole future life depends on this choice, so choose wisely listening to the voice of your heart.\"", 78 | Color.YELLOW))); 79 | } 80 | 81 | return new CompoundResult( 82 | List.of( 83 | new FightLog( 84 | player.getFightManager().getEnemy().getName() + " is dead.", 85 | Color.YELLOW), 86 | new FightLog( 87 | player.toString() + " gets " + gainedExperience + " experience.", 88 | Color.YELLOW))); 89 | } 90 | 91 | public IResult defeat() { 92 | return new FightLog(player.toString() + " is dead.", Color.RED); 93 | } 94 | 95 | public Monster getEnemy() { 96 | return fightingWith; 97 | } 98 | 99 | public IFightState getState() { 100 | return fightState; 101 | } 102 | 103 | public void setState(IFightState fightState) { 104 | this.fightState = fightState; 105 | } 106 | } 107 | --------------------------------------------------------------------------------