untitledTextAdventure/src/main/java/game/logic/GameLogic.java

213 lines
7.5 KiB
Java

package game.logic;
import java.io.Closeable;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import game.logic.actionsystem.Action;
import game.logic.actionsystem.PlayerAction;
import game.logic.actionsystem.actions.GoDirection;
import game.logic.actionsystem.actions.Open;
import game.logic.actionsystem.actions.TakeFrom;
import game.state.CircularLocationException;
import game.state.Entity;
import game.state.EntitySet;
import game.state.GameState;
public class GameLogic implements Closeable {
private final Parser parser;
private GameState state;
private Entity player;
private boolean discontinue = false;
private Map<String, List<PlayerAction>> playerActions = new HashMap<>();
public GameLogic(Parser parser) {
this.parser = parser;
this.state = new GameState();
}
public void loadGameState(String stateDescJsonFilePath) throws CircularLocationException {
////////////////////////////////////////////////////////////////////////
// TODO setup code, load from json or so
////////////////////////////////////////////////////////////////////////
// final String NORTH = "north";
// final String SOUTH = "south";
final String EAST = "east";
final String WEST = "west";
final String INSIDE = "inside";
final String OUTSIDE = "outside";
Entity forestPath01 = this.state.createEntity("forest_path_01");
Entity clearing = this.state.createEntity("clearing");
Entity houseOutside = this.state.createEntity("house_outside");
Entity houseInside = this.state.createEntity("house_inside");
Entity houseMainDoor = this.state.createEntity("house_main_door");
houseMainDoor.setClosed(true);
forestPath01.connectBidirectional(EAST, null, WEST, clearing);
forestPath01.connectBidirectional(WEST, null, EAST, houseOutside);
houseOutside.connectBidirectional(INSIDE, houseMainDoor, OUTSIDE, houseInside);
this.player = this.state.createEntity("player");
Entity apple01 = this.state.createEntity("apple_01", "green");
Entity apple02 = this.state.createEntity("apple_02", "red");
this.player.setLocation(clearing);
apple01.setLocation(forestPath01);
apple02.setLocation(forestPath01);
////////////////////////////////////////////////////////////////////////
// TODO game specific action parsers
////////////////////////////////////////////////////////////////////////
this.parser.pushActionParser(userInput -> userInput.get(0).equals("go")
? new GoDirection(userInput.size() < 2 ? null : userInput.get(1))
: null);
this.parser.pushActionParser(userInput -> {
if (userInput.get(0).equals("take")) {
int fromIdx = userInput.indexOf("from");
List<EntityDescription> whatToTake = this
.parseDescriptionList(userInput.subList(1, fromIdx == -1 ? userInput.size() : fromIdx));
List<EntityDescription> whereToTakeFrom = fromIdx == -1 ? null
: this.parseDescriptionList(userInput.subList(fromIdx + 1, userInput.size()));
return new TakeFrom(whatToTake, whereToTakeFrom);
} else {
return null;
}
});
this.parser.pushActionParser(userInput -> {
if (userInput.get(0).equals("open")) {
return new Open(this.parseDescriptionList(userInput.subList(1, userInput.size())));
} else {
return null;
}
});
}
public Entity getPlayer() {
return this.player;
}
public EntitySet searchForEntity(EntityDescription description) {
return this.state.searchForEntity(description);
}
public EntitySet searchForEntity(EntityDescription description, Predicate<Entity> acceptFunction) {
return this.state.searchForEntity(description).getFiltered(acceptFunction);
}
public EntitySet searchForNearbyEntity(EntityDescription description) {
return this.searchForEntity(description, e -> {
if (this.player == null) {
return false;
} else if (this.player.contains(e, false)) {
return true;
} else if (this.player.getLocation() != null && this.player.getLocation().contains(e, false)) {
return true;
} else {
for (Entity.EntityConnection c : this.player.getLocation().getConnections().stream()
.map(this.player.getLocation()::getConnection).toList()) {
if (c.associatedEntity() == e) {
return true;
}
}
}
return false;
});
}
public void mainLoop() {
while (!this.discontinue) {
Action action = this.parser.readAction();
if (action != null) {
action.execute(this);
}
}
}
private List<EntityDescription> parseDescriptionList(List<String> words) {
List<EntityDescription> descriptions = new LinkedList<>();
List<String> desc = new LinkedList<>();
for (String word : words) {
if (word.equals("and")) {
descriptions.add(new EntityDescription(desc));
desc = new LinkedList<>();
} else {
desc.add(word);
}
}
if (!desc.isEmpty()) {
descriptions.add(new EntityDescription(desc));
}
return descriptions;
}
public void printToUser(String messageId, Object... args) {
System.out.print(messageId);
for (int i = 0; i < args.length; ++i) {
System.out.print(i == 0 ? " " : ", ");
System.out.print(args[i]);
}
System.out.println();
}
public boolean canPlayerOpen(Entity entity) {
// TODO
return true;
}
public boolean canPlayerTake(Entity entity) {
// TODO
return true;
}
public void registerPlayerAction(PlayerAction action) {
List<PlayerAction> l = this.playerActions.get(action.getId());
if (l == null) {
this.playerActions.put(action.getId(), l = new LinkedList<>());
}
l.add(action);
}
/**
* Searches for the first player action that does not use any entity and
* executes it if one is found.
*
* @param id The action id
* @return <code>true</code>, if an action was found and executed
*/
public boolean tryExecutePlayerAction(String id) {
return this.tryExecutePlayerAction(id, null);
}
/**
* Searches for the first player action that can operate on the given set of
* entities and executes it if one is found.
*
* @param id The action id
* @param entities The entities on which the action shoud operate
* @return <code>true</code>, if an action was found and executed
*/
public boolean tryExecutePlayerAction(String id, EntitySet entities) {
List<PlayerAction> l = this.playerActions.get(id);
if (l != null) {
for (PlayerAction a : l) {
if (a.tryExecute(null, entities, this)) {
return true;
}
}
}
return false;
}
@Override
public void close() throws IOException {
this.parser.close();
}
}