feat: Menu

This commit is contained in:
2025-05-25 13:53:45 +02:00
parent 11a7fe972f
commit c24422e80a
20 changed files with 377 additions and 40 deletions

View File

@@ -0,0 +1,10 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<Languages>
<language minSize="66" name="Java" />
</Languages>
</inspection_tool>
</profile>
</component>

View File

@@ -39,9 +39,6 @@ public class Game {
this.strings = strings; this.strings = strings;
} }
public Game() {
}
public void play() { public void play() {
strings.print("welcome"); strings.print("welcome");
Cli.pressEnter(); Cli.pressEnter();

View File

@@ -1,7 +1,15 @@
package cz.jull; package cz.jull;
import cz.jull.actions.Action;
import cz.jull.actions.BuildAction;
import cz.jull.actions.axe.AxeCutTreesAction;
import cz.jull.actions.vineyard.VineyardHarvestAction;
import cz.jull.actions.wheat_farmland.WheatFarmlandHarvestAction;
import cz.jull.actions.wheat_farmland.WheatFarmlandPlantAction;
import lombok.Getter; import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function; import java.util.function.Function;
/** /**
@@ -12,40 +20,40 @@ import java.util.function.Function;
* The same thing applies for buying. * The same thing applies for buying.
*/ */
public enum Item implements Buildable { public enum Item implements Buildable {
AXE("Axe", false, 5), AXE("Axe", false, 5, List.of(new AxeCutTreesAction())),
WHEAT("Wheat", false, 0), WHEAT("Wheat", false, 0, List.of()),
HOPS("Hops", false, 0), HOPS("Hops", false, 0, List.of()),
GRAPEVINE("Grapes", false, 0), GRAPEVINE("Grapes", false, 0, List.of()),
WOOD("Wood", false, 0), WOOD("Wood", false, 0, List.of()),
MILK("Milk", false, 0), MILK("Milk", false, 0, List.of()),
WHEAT_SEEDS("Wheat seeds", true, 5), WHEAT_SEEDS("Wheat seeds", true, 5, List.of()),
HOPS_SEEDS("Hops seeds", true, 5), HOPS_SEEDS("Hops seeds", true, 5, List.of()),
GRAPEVINE_SEEDS("Grapes seeds", true, 5), GRAPEVINE_SEEDS("Grapes seeds", true, 5, List.of()),
VINEYARD("Vineyard", true, 7), VINEYARD("Vineyard", true, 7, List.of(new BuildAction()), List.of(new VineyardHarvestAction())),
WHEAT_FARMLAND("Wheat farmland", true, 7), WHEAT_FARMLAND("Wheat farmland", true, 7, List.of(new BuildAction()), List.of(new WheatFarmlandHarvestAction(), new WheatFarmlandPlantAction())),
HOPS_FARMLAND("Hops farmland", true, 7), HOPS_FARMLAND("Hops farmland", true, 7, List.of(new BuildAction())),
FENCE_WITH_COWS("Fence with cows", true, 100), FENCE_WITH_COWS("Fence with cows", true, 100, List.of(new BuildAction()), List.of()),
CHURCH("Church", true, 100), CHURCH("Church", true, 100, List.of(new BuildAction())),
VILLAGER_HOUSE("Villager house", true, 50), VILLAGER_HOUSE("Villager house", true, 50, List.of(new BuildAction())),
PUB("Pub", true, 400), PUB("Pub", true, 400, List.of(new BuildAction()), List.of()),
WINERY("Winery", true, 350), WINERY("Winery", true, 350, List.of(new BuildAction()), List.of()),
BAKERY("Bakery", true, 350), BAKERY("Bakery", true, 350, List.of(new BuildAction()), List.of()),
WELL("Well", true, 30), WELL("Well", true, 30, List.of()),
COAL_FACTORY("Coal factory", true, 200), COAL_FACTORY("Coal factory", true, 200, List.of(new BuildAction()), List.of()),
CHEESE_FACTORY("Cheese factory", true, 200); CHEESE_FACTORY("Cheese factory", true, 200, List.of(new BuildAction()), List.of()),;
static { static {
WHEAT_SEEDS.canBeBuiltFunction = game -> { WHEAT_SEEDS.canBeBuiltFunction = game -> {
if (game.getBuildings().stream().filter(building -> building == Item.WHEAT_FARMLAND).count() >= game.getBuildings().stream().filter(building -> building == Item.WHEAT_SEEDS || building == Item.HOPS_SEEDS).count() + 1) { if (game.getBuildings().stream().filter(building -> building == Item.WHEAT_FARMLAND).count() >= game.getBuildings().stream().filter(building -> building == Item.WHEAT_SEEDS).count() + 1) {
return true; return true;
} }
System.out.println(" "); //TODO System.out.println(" "); //TODO
@@ -53,7 +61,7 @@ public enum Item implements Buildable {
}; };
HOPS_SEEDS.canBeBuiltFunction = game -> { HOPS_SEEDS.canBeBuiltFunction = game -> {
if (game.getBuildings().stream().filter(building -> building == Item.WHEAT_FARMLAND).count() >= game.getBuildings().stream().filter(building -> building == Item.WHEAT_SEEDS || building == Item.HOPS_SEEDS).count() + 1) { if (game.getBuildings().stream().filter(building -> building == Item.WHEAT_FARMLAND).count() >= game.getBuildings().stream().filter(building -> building == Item.HOPS_SEEDS).count() + 1) {
return true; return true;
} }
System.out.println(" "); //TODO System.out.println(" "); //TODO
@@ -61,7 +69,7 @@ public enum Item implements Buildable {
}; };
GRAPEVINE_SEEDS.canBeBuiltFunction = game -> { GRAPEVINE_SEEDS.canBeBuiltFunction = game -> {
if (game.getBuildings().stream().filter(building -> building == Item.VINEYARD).count() >= game.getBuildings().stream().filter(building -> building == Item.GRAPEVINE_SEEDS || building == Item.HOPS_SEEDS).count() + 1) { if (game.getBuildings().stream().filter(building -> building == Item.VINEYARD).count() >= game.getBuildings().stream().filter(building -> building == Item.GRAPEVINE_SEEDS).count() + 1) {
return true; return true;
} }
System.out.println(" "); //TODO System.out.println(" "); //TODO
@@ -191,6 +199,12 @@ public enum Item implements Buildable {
@Getter @Getter
private final int price; private final int price;
@Getter
private final List<Action> actions;
@Getter
private List<Action> buildActions = new ArrayList<>();
/** /**
* Function that determines if the item can be built or not * Function that determines if the item can be built or not
*/ */
@@ -202,17 +216,28 @@ public enum Item implements Buildable {
@Getter @Getter
private Function<Game, Boolean> canBeBoughtFunction; private Function<Game, Boolean> canBeBoughtFunction;
Item(String name, boolean isPlaceable, int price) { Item(String name, boolean isPlaceable, int price, List<Action> actions) {
this.name = name; this.name = name;
this.isPlaceable = isPlaceable; this.isPlaceable = isPlaceable;
this.canBeBuiltFunction = ignored -> isPlaceable; this.canBeBuiltFunction = ignored -> isPlaceable;
this.price = price; this.price = price;
this.canBeBoughtFunction = ignored -> true; this.canBeBoughtFunction = ignored -> true;
this.actions = actions;
}
Item(String name, boolean isPlaceable, int price, List<Action> actions, List<Action> buildActions) {
this.name = name;
this.isPlaceable = isPlaceable;
this.canBeBuiltFunction = ignored -> isPlaceable;
this.price = price;
this.canBeBoughtFunction = ignored -> true;
this.actions = actions;
this.buildActions = buildActions;
} }
/** /**
* Function that executes function that determines if the item can be built or not * Function that executes function that determines if the item can be built or not
* @param game * @param game The game instance
* @return Boolean if the item can be built * @return Boolean if the item can be built
*/ */
@Override @Override

View File

@@ -0,0 +1,10 @@
package cz.jull.actions;
import cz.jull.Game;
import cz.jull.Item;
public abstract class Action {
public abstract String toString();
public abstract void execute(Game game, Item item);
}

View File

@@ -0,0 +1,17 @@
package cz.jull.actions;
import cz.jull.Game;
import cz.jull.Item;
public class BuildAction extends Action {
@Override
public String toString() {
return "Build";
}
@Override
public void execute(Game game, Item item) {
game.build(item);
}
}

View File

@@ -0,0 +1,17 @@
package cz.jull.actions.axe;
import cz.jull.Game;
import cz.jull.Item;
import cz.jull.actions.Action;
public class AxeCutTreesAction extends Action {
@Override
public String toString() {
return "Cut trees";
}
@Override
public void execute(Game game, Item item) {
game.cutTrees();
}
}

View File

@@ -0,0 +1,17 @@
package cz.jull.actions.hops_farmland;
import cz.jull.Game;
import cz.jull.Item;
import cz.jull.actions.Action;
public class HopsFarmlandHarvestAction extends Action {
@Override
public String toString() {
return "Harvest hops";
}
@Override
public void execute(Game game, Item item) {
game.harvest(Item.HOPS_FARMLAND);
}
}

View File

@@ -0,0 +1,17 @@
package cz.jull.actions.vineyard;
import cz.jull.Game;
import cz.jull.Item;
import cz.jull.actions.Action;
public class VineyardHarvestAction extends Action {
@Override
public String toString() {
return "Harverst grapevines";
}
@Override
public void execute(Game game, Item item) {
game.harvest(Item.VINEYARD);
}
}

View File

@@ -0,0 +1,17 @@
package cz.jull.actions.wheat_farmland;
import cz.jull.Game;
import cz.jull.Item;
import cz.jull.actions.Action;
public class WheatFarmlandHarvestAction extends Action {
@Override
public String toString() {
return "Harvest wheats";
}
@Override
public void execute(Game game, Item item) {
game.harvest(Item.WHEAT_FARMLAND);
}
}

View File

@@ -0,0 +1,17 @@
package cz.jull.actions.wheat_farmland;
import cz.jull.Game;
import cz.jull.Item;
import cz.jull.actions.Action;
public class WheatFarmlandPlantAction extends Action {
@Override
public String toString() {
return "Plant wheat seeds";
}
@Override
public void execute(Game game, Item item) {
game.build(Item.WHEAT_SEEDS);
}
}

View File

@@ -57,7 +57,7 @@ public class Market {
public Market(Game game) { public Market(Game game) {
// Soil Type // Soil Type
if (game.getSoilType() == SoilType.STONY) { if (game.getSoilType() == SoilType.STONY) {
availableItems.addAll(List.of(Item.FENCE_WITH_COWS, Item.VINEYARD)); availableItems.addAll(List.of(Item.FENCE_WITH_COWS, Item.VINEYARD, Item.GRAPEVINE_SEEDS));
} }
if (game.getSoilType() == SoilType.LESS_FERTILE) { if (game.getSoilType() == SoilType.LESS_FERTILE) {
@@ -65,7 +65,7 @@ public class Market {
} }
if (game.getSoilType() == SoilType.FERTILE) { if (game.getSoilType() == SoilType.FERTILE) {
availableItems.add(Item.WHEAT_FARMLAND); availableItems.addAll(List.of(Item.WHEAT_FARMLAND, Item.WHEAT_SEEDS, Item.HOPS_FARMLAND, Item.HOPS_SEEDS));
} }
// Path Type // Path Type

View File

@@ -2,14 +2,32 @@ package cz.jull.tui;
import cz.jull.Game; import cz.jull.Game;
import cz.jull.Item; import cz.jull.Item;
import cz.jull.actions.Action;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@RequiredArgsConstructor @RequiredArgsConstructor
public class Menu { public class Menu {
private final Game game; private final Game game;
public static String loadResource(String fileName) {
try (InputStream inputStream = Menu.class.getClassLoader().getResourceAsStream(fileName)) {
if (inputStream == null) {
return "File not found: " + fileName;
}
byte[] bytes = inputStream.readAllBytes();
return new String(bytes, StandardCharsets.UTF_8);
} catch (IOException e) {
return null;
}
}
public void start() { public void start() {
int index = Cli.selectOptionIndex(List.of( int index = Cli.selectOptionIndex(List.of(
"See your inventory", "See your inventory",
@@ -18,14 +36,38 @@ public class Menu {
"See your stats" )); "See your stats" ));
switch (index) { switch (index) {
case 0 -> { case 0 -> {
for (Item item : game.getPlayer().getInventory()) { List<String> inventory = new ArrayList<>(game.getPlayer().getInventory().stream().map(Item::toString).toList());
System.out.println(item); inventory.add("Go back");
int itemIndex = Cli.selectOptionIndex(inventory);
if (itemIndex == inventory.size() - 1) {
start();
return;
} }
Item item = game.getPlayer().getInventory().get(itemIndex);
String art = loadResource("item_art/" + item.name() + ".txt");
System.out.println(art);
System.out.println();
List<Action> actions = item.getActions();
actionMenu(item, actions);
} }
case 1 -> { case 1 -> {
for (Item building : game.getBuildings()) { List<String> buildings = new ArrayList<>(game.getBuildings().stream().map(Item::toString).toList());
System.out.println(building); buildings.add("Go back");
int itemIndex = Cli.selectOptionIndex(buildings);
if (itemIndex == buildings.size() - 1) {
start();
return;
} }
Item item = game.getBuildings().get(itemIndex);
String art = loadResource("item_art/" + item.name() + ".txt");
System.out.println(art);
System.out.println();
List<Action> actions = item.getBuildActions();
actionMenu(item, actions);
} }
case 2 -> { case 2 -> {
game.getStrings().print("marketGreeting"); game.getStrings().print("marketGreeting");
@@ -50,11 +92,21 @@ public class Menu {
Item item = game.getMarket().getAvailableItems().get(itemIndex); Item item = game.getMarket().getAvailableItems().get(itemIndex);
game.getMarket().sellItem(game, item); game.getMarket().sellItem(game, item);
} }
case 2 -> { case 2 -> start();
}
}
}
}
private void actionMenu(Item item, List<Action> actions) {
List<String> actionStrings = new ArrayList<>(actions.stream().map(Action::toString).toList());
actionStrings.add("Go back");
int actionIndex = Cli.selectOptionIndex(actionStrings);
if (actionIndex == actionStrings.size() - 1) {
start(); start();
} return;
} }
} Action action = actions.get(actionIndex);
} action.execute(game, item);
} }
} }

View File

@@ -0,0 +1,19 @@
████
██ ██
██ ██
██ ██
██ ██
██ ██
██████ ██████
██████████ ██
████████ ██ ██
████████ ██ ██
████████ ██ ██
████████ ██ ██
████████ ██ ████
████████ ████
████████
████████
████████
████████
██████

View File

@@ -0,0 +1,13 @@
▄▄▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄▄▄
▄▄▀▀▀▀▀▀ ▄▄████▀▀ ▄▄▄▄████ ▀▀▀▀▀▀▀▀▄▄▄▄
▄▄▀▀ ▄▄████▀▀ ▄▄██████▀▀ ▄▄████ ▀▀▄▄▄▄▄▄
▄▄██ ████ ██████▀▀ ▄▄████▀▀ ▀▀▄▄
██ ▄▄██ ▄▄████▀▀ ▄▄████ ▄▄▄▄██▀▀ ▀▀▄▄
██ ▀▀ ████▀▀ ████▀▀ ▄▄██▀▀ ▀▀▄▄
██ ██ ▄▄██▀▀ ██ ██▄▄
██▄▄ ▀▀▀▀ ██
▀▀▄▄ ▄▄▀▀
▀▀▄▄▄▄ ▄▄▀▀
▀▀▀▀▄▄▄▄ ▄▄▄▄▀▀
▀▀▀▀▀▀▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▀▀▀▀
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀

View File

@@ -0,0 +1,28 @@
██
██████
██
██
██████
██ ██
██ ██
██ ██
██ ██
██ ██████ ██
██ ██ ██ ██
██████ ██ ██ ██████
██ ██ ██ ██
██ ██████ ██
██ ██
██ ██
██ ██
██ ██
██ ██
████████ ████████
██ ██
██ ██████████ ██
██ ██ ██ ██
██ ██ ██ ██
██ ██ ██ ██
██ ██ ██ ██
██ ██ ██ ██
██████████████████████████████████████

View File

@@ -0,0 +1,13 @@
██████████████
██████████████████████
██████████████████████████████
██████████████████████████████████
██████████████████████████████████████
██████████████████████████████████████████████
██████████████████████████████████████████████
██████████████████████████████████████████████████
██████████████████████████████████████████████████
▀▀██████████████████████████████████████████▀▀▀▀
▀▀▀▀██████████████████████████████████▀▀▀▀
▀▀▀▀██████████████▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
▀▀▀▀▀▀▀▀▀▀▀▀▀▀

View File

@@ -0,0 +1,28 @@
██
██ ██
██ ██
██████ ██████
██████ ██████ ██████
████ ██ ████
████ ████
████ ████
██ ██
██ ██
██ ██
████ ██ ██ ████
██ ████ ████ ██
██ ██ ██ ██ ██ ██
██ ████ ██ ██ ████ ██
████████ ██ ██ ████████
██ ██ ██ ██
██ ████ ████ ██
██ ██████████ ██
██ ██ ██ ██
████ ██ ██ ████
████ ██ ██ ████
██████ ██████
██ ██
██ ██
██ ██
████ ████
██

View File

@@ -0,0 +1,13 @@
▄▄▄▄▄▄▄▄▄▄ ▄▄▀▀▄▄
██ ██▄▄▀▀ ▀▀▄▄
██ ▄▄▀▀ ▄▄▀▀▀▀▀▀▄▄ ▀▀▄▄
██▄▄▀▀ ▄▄▀▀ ▀▀▄▄ ▀▀▄▄
▄▄▀▀ ▄▄▀▀ ▀▀▄▄ ▀▀▄▄
▄▄▀▀ ▄▄▀▀ ▀▀▄▄ ▀▀▄▄
▀▀▄▄▄▄██ ▄▄▄▄▄▄▄▄▄▄▄▄ ██▄▄▄▄▀▀
██ ██ ██ ██▀▀▀▀▀▀▀▀▀▀██ ██
██ ██ ██ ██ ██ ██
██ ██ ▄▄██ ██ ██ ██
██ ██ ██ ██▄▄▄▄▄▄▄▄▄▄██ ██
██ ██ ██ ██
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀

View File

@@ -0,0 +1,22 @@
██
██
██ ██
██ ████
██ ████
██ ████ ██
██ ██████████
██ ██ ████
██ ██ ████ ██
██ ██ ████████
██ ██ ████
██ ██ ██ ██████████
██ ██ ████ ██
██ ██ ██████████████
██ ████
██ ████████████
████ ██
██████████████
██
██
██
██

View File

@@ -1,13 +1,18 @@
package cz.jull; package cz.jull;
import cz.jull.exceptions.NotSufficientsCoinsException; import cz.jull.exceptions.NotSufficientsCoinsException;
import cz.jull.tui.Strings;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
public class NotSufficientCoinsTest { public class NotSufficientCoinsTest {
@Test @Test
public void notSufficientCoins() { public void notSufficientCoins() throws IOException {
Game game = new Game(); Strings strings = Strings.load();
Game game = new Game(strings);
game.getPlayer().setCoins(1); game.getPlayer().setCoins(1);
assertThrows(NotSufficientsCoinsException.class, () -> game.getMarket().buyItem(game, Item.AXE)); assertThrows(NotSufficientsCoinsException.class, () -> game.getMarket().buyItem(game, Item.AXE));
} }