feat: add thanos into the handling

This commit is contained in:
punchready 2021-05-31 22:54:13 +02:00
parent 1ba5410fd6
commit 9a9fe4ae97
6 changed files with 90 additions and 49 deletions

View File

@ -46,6 +46,9 @@ public class Character extends Entity {
super(id, position); super(id, position);
solid = false; solid = false;
opaque = true; opaque = true;
if(id.type == EntityType.NPC && id.id == 2) {
solid = true; //characters cannot walk into thanos
}
this.name = name; this.name = name;
this.hp = new Stat(StatType.HP, hp); this.hp = new Stat(StatType.HP, hp);
this.mp = new Stat(StatType.MP, mp); this.mp = new Stat(StatType.MP, mp);
@ -65,7 +68,7 @@ public class Character extends Entity {
@Override @Override
public Character clone() { public Character clone() {
Character clone = new Character(id, position, name, hp.max, mp.max, ap.max, attackRange, rangedDamage, meleeDamage); Character clone = new Character(id, position, name, hp.getMax(), mp.getMax(), ap.getMax(), attackRange, rangedDamage, meleeDamage);
for(StoneType stone: inventory) { for(StoneType stone: inventory) {
clone.inventory.addStone(stone); clone.inventory.addStone(stone);
} }

View File

@ -2,26 +2,8 @@ package uulm.teamname.marvelous.gamelibrary.entities;
import uulm.teamname.marvelous.gamelibrary.IntVector2; import uulm.teamname.marvelous.gamelibrary.IntVector2;
import java.util.ArrayList;
/** Represents an NPC inside the game. */ /** Represents an NPC inside the game. */
public class NPC extends Entity { public class NPC extends Entity {
/** The {@link Inventory} of the NPC */
public final Inventory inventory;
/**
* Constructs a new {@link NPC}.
* @param id The {@link EntityID} of the NPC
* @param position The position of the NPC
* @param inventory The starting inventory the NPC should have
*/
public NPC(EntityID id, IntVector2 position, ArrayList<StoneType> inventory) {
super(id, position);
solid = false;
opaque = true;
this.inventory = new Inventory(inventory);
}
/** /**
* Constructs a new {@link NPC} with an empty inventory. * Constructs a new {@link NPC} with an empty inventory.
* @param id The {@link EntityID} of the NPC * @param id The {@link EntityID} of the NPC
@ -29,15 +11,12 @@ public class NPC extends Entity {
*/ */
public NPC(EntityID id, IntVector2 position) { public NPC(EntityID id, IntVector2 position) {
super(id, position); super(id, position);
this.inventory = new Inventory(); solid = false;
opaque = true;
} }
@Override @Override
public NPC clone() { public NPC clone() {
NPC clone = new NPC(id, position); return new NPC(id, position);
for(StoneType stone: inventory) {
clone.inventory.addStone(stone);
}
return clone;
} }
} }

View File

@ -8,7 +8,7 @@ public class Stat {
public final StatType type; public final StatType type;
/** The maximum value of the stat */ /** The maximum value of the stat */
public final int max; private int max;
/** The current value of the stat */ /** The current value of the stat */
private int value; private int value;
@ -40,25 +40,33 @@ public class Stat {
this.value -= value; this.value -= value;
} }
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Stat stat = (Stat) o; Stat stat = (Stat) o;
return max == stat.max && value == stat.value && type == stat.type; return getMax() == stat.getMax() && value == stat.value && type == stat.type;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(type, max, value); return Objects.hash(type, getMax(), value);
} }
@Override @Override
public String toString() { public String toString() {
return "Stat{" + return "Stat{" +
"type=" + type + "type=" + type +
", max=" + max + ", max=" + getMax() +
", value=" + value + ", value=" + value +
'}'; '}';
} }

View File

@ -141,7 +141,7 @@ class GameLogic {
} }
case TimeStone -> { case TimeStone -> {
Character origin = (Character)state.entities.findEntity(data.originEntity); Character origin = (Character)state.entities.findEntity(data.originEntity);
int ap = origin.ap.max - origin.ap.getValue(); int ap = origin.ap.getMax() - origin.ap.getValue();
if(ap < 0) { if(ap < 0) {
result.add(new EventBuilder(EventType.ConsumedAPEvent) result.add(new EventBuilder(EventType.ConsumedAPEvent)
.withTargetEntity(data.originEntity) .withTargetEntity(data.originEntity)
@ -149,7 +149,7 @@ class GameLogic {
.withAmount(ap) .withAmount(ap)
.buildEntityEvent()); .buildEntityEvent());
} }
int mp = origin.mp.max - origin.mp.getValue(); int mp = origin.mp.getMax() - origin.mp.getValue();
if(mp < 0) { if(mp < 0) {
result.add(new EventBuilder(EventType.ConsumedMPEvent) result.add(new EventBuilder(EventType.ConsumedMPEvent)
.withTargetEntity(data.originEntity) .withTargetEntity(data.originEntity)
@ -163,7 +163,7 @@ class GameLogic {
result.add(new EventBuilder(EventType.HealedEvent) result.add(new EventBuilder(EventType.HealedEvent)
.withTargetEntity(data.targetEntity) .withTargetEntity(data.targetEntity)
.withTargetField(data.targetField) .withTargetField(data.targetField)
.withAmount(target.hp.max) .withAmount(target.hp.getMax())
.buildEntityEvent()); .buildEntityEvent());
} }
} }
@ -364,7 +364,7 @@ class GameLogic {
*/ */
private static Character getCharacter(GameState state, IntVector2 position, EntityID entityID) throws InvalidRequestException { private static Character getCharacter(GameState state, IntVector2 position, EntityID entityID) throws InvalidRequestException {
Entity entity = state.entities.findEntity(entityID); Entity entity = state.entities.findEntity(entityID);
if(entity == null || entity.getPosition() != position || !(entity instanceof Character)) { if(entity == null || entity.getPosition() != position || !(entity instanceof Character) || entity.id.type == EntityType.NPC) {
throw new InvalidRequestException(); throw new InvalidRequestException();
} }
try { try {
@ -629,6 +629,10 @@ class GameLogic {
ArrayList<EntityID> alive = new ArrayList<>(); ArrayList<EntityID> alive = new ArrayList<>();
for (EntityID id: state.turnOrder) { for (EntityID id: state.turnOrder) {
if(id.type == EntityType.NPC) {
continue;
}
Character character = ((Character)state.entities.findEntity(id)); Character character = ((Character)state.entities.findEntity(id));
if(character.hp.getValue() > 0){ if(character.hp.getValue() > 0){
@ -682,7 +686,9 @@ class GameLogic {
result.addAll(handleStan(state, revived)); result.addAll(handleStan(state, revived));
} }
//TODO: add handling for thanos if(state.roundNumber == state.partyConfig.maxRounds + 1) {
result.addAll(spawnThanos(state));
}
Collections.shuffle(state.turnOrder); Collections.shuffle(state.turnOrder);
@ -783,11 +789,11 @@ class GameLogic {
if(character.hp.getValue() == 0) { if(character.hp.getValue() == 0) {
revived.add(character.id); revived.add(character.id);
} }
if(character.hp.getValue() != character.hp.max) { if(character.hp.getValue() != character.hp.getMax()) {
result.add(new EventBuilder(EventType.HealedEvent) result.add(new EventBuilder(EventType.HealedEvent)
.withTargetEntity(character.id) .withTargetEntity(character.id)
.withTargetField(character.getPosition()) .withTargetField(character.getPosition())
.withAmount(character.hp.max - character.hp.getValue()) .withAmount(character.hp.getMax() - character.hp.getValue())
.buildEntityEvent()); .buildEntityEvent());
} }
} }
@ -801,6 +807,49 @@ class GameLogic {
return result; return result;
} }
/**
* Spawns Thanos at the beginning of the first overtime round.
* @param state The game state to work on
* @return The list of resulting {@link Event}s
*/
public static ArrayList<Event> spawnThanos(GameState state) {
ArrayList<Event> result = new ArrayList<>();
ArrayList<IntVector2> free = getFreeFields(state);
IntVector2 position = free.get(rand.nextInt(free.size()));
int maxMP = -1;
for(EntityID id: state.turnOrder) {
Character character = (Character)state.entities.findEntity(id);
if(character.mp.getValue() > maxMP) {
maxMP = character.mp.getValue();
}
}
EntityID thanos = new EntityID(EntityType.NPC, 2);
result.add(new EventBuilder(EventType.SpawnEntityEvent)
.withEntity(new Character(thanos, position, "Thanos", 1, maxMP, 0, 0, 0, 0))
.buildEntityEvent());
state.turnOrder.add(thanos);
return result;
}
/**
* Handles Thanos' AI.
* @param state The game state to work on
* @return The list of resulting {@link Event}s
*/
public static ArrayList<Event> handleThanos(GameState state, Character thanos) {
ArrayList<Event> result = new ArrayList<>();
//TODO: implement thanos ai
return result;
}
/** /**
* Handles everything that happens at the beginning of a turn. * Handles everything that happens at the beginning of a turn.
* @param state The game state to work on * @param state The game state to work on
@ -812,19 +861,24 @@ class GameLogic {
state.turnNumber++; state.turnNumber++;
Character activeCharacter = (Character)state.entities.findEntity(state.activeCharacter); Character activeCharacter = (Character)state.entities.findEntity(state.activeCharacter);
boolean isThanos = state.activeCharacter.type == EntityType.NPC && state.activeCharacter.id == 2;
if(activeCharacter.ap.getValue() != activeCharacter.ap.max) { if(isThanos && state.roundNumber > state.partyConfig.maxRounds + 1) {
activeCharacter.mp.setMax(activeCharacter.mp.getMax() + 1);//TODO: use event for this...
}
if(activeCharacter.ap.getValue() != activeCharacter.ap.getMax()) {
result.add(new EventBuilder(EventType.ConsumedAPEvent) result.add(new EventBuilder(EventType.ConsumedAPEvent)
.withTargetEntity(state.activeCharacter) .withTargetEntity(state.activeCharacter)
.withTargetField(activeCharacter.getPosition()) .withTargetField(activeCharacter.getPosition())
.withAmount(activeCharacter.ap.getValue() - activeCharacter.ap.max) .withAmount(activeCharacter.ap.getValue() - activeCharacter.ap.getMax())
.buildGameEvent()); .buildGameEvent());
} }
if(activeCharacter.mp.getValue() != activeCharacter.mp.max) { if(activeCharacter.mp.getValue() != activeCharacter.mp.getMax()) {
result.add(new EventBuilder(EventType.ConsumedMPEvent) result.add(new EventBuilder(EventType.ConsumedMPEvent)
.withTargetEntity(state.activeCharacter) .withTargetEntity(state.activeCharacter)
.withTargetField(activeCharacter.getPosition()) .withTargetField(activeCharacter.getPosition())
.withAmount(activeCharacter.mp.getValue() - activeCharacter.mp.max) .withAmount(activeCharacter.mp.getValue() - activeCharacter.mp.getMax())
.buildGameEvent()); .buildGameEvent());
} }
result.add(new EventBuilder(EventType.TurnEvent) result.add(new EventBuilder(EventType.TurnEvent)
@ -832,6 +886,10 @@ class GameLogic {
.withNextCharacter(state.activeCharacter) .withNextCharacter(state.activeCharacter)
.buildGameEvent()); .buildGameEvent());
if(isThanos) {
result.addAll(handleThanos(state, activeCharacter));
}
return result; return result;
} }

View File

@ -62,8 +62,7 @@ class EventBuilderTest {
25), 25),
new NPC( new NPC(
new EntityID(EntityType.NPC, 1), new EntityID(EntityType.NPC, 1),
new IntVector2(11, 14), new IntVector2(11, 14)
new ArrayList<>()
) )
}; };

View File

@ -4,9 +4,7 @@ import net.jqwik.api.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import uulm.teamname.marvelous.gamelibrary.IntVector2; import uulm.teamname.marvelous.gamelibrary.IntVector2;
import uulm.teamname.marvelous.gamelibrary.entities.*; import uulm.teamname.marvelous.gamelibrary.entities.*;
import uulm.teamname.marvelous.gamelibrary.entities.Character;
import uulm.teamname.marvelous.gamelibrary.events.Event; import uulm.teamname.marvelous.gamelibrary.events.Event;
import uulm.teamname.marvelous.gamelibrary.events.EventBuilder;
import uulm.teamname.marvelous.gamelibrary.json.config.CharacterConfig; import uulm.teamname.marvelous.gamelibrary.json.config.CharacterConfig;
import uulm.teamname.marvelous.gamelibrary.json.config.PartyConfig; import uulm.teamname.marvelous.gamelibrary.json.config.PartyConfig;
import uulm.teamname.marvelous.gamelibrary.json.config.ScenarioConfig; import uulm.teamname.marvelous.gamelibrary.json.config.ScenarioConfig;
@ -14,10 +12,6 @@ import uulm.teamname.marvelous.gamelibrary.requests.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
class GameLogicTest { class GameLogicTest {
@ -85,7 +79,7 @@ class GameLogicTest {
.as(Stat::new); .as(Stat::new);
return Combinators.combine(stats, Arbitraries.integers().greaterOrEqual(0)) return Combinators.combine(stats, Arbitraries.integers().greaterOrEqual(0))
.as((stat, decrease) -> { .as((stat, decrease) -> {
stat.decreaseValue(decrease % (stat.max + 1)); stat.decreaseValue(decrease % (stat.getMax() + 1));
return stat; return stat;
}); });
} }