Compare commits

...

2 Commits

2 changed files with 75 additions and 36 deletions

View File

@ -18,9 +18,9 @@ test {
}
dependencies {
implementation "com.fasterxml.jackson.core:jackson-core:2.12.3"
implementation "com.fasterxml.jackson.core:jackson-annotations:2.12.3"
implementation "com.fasterxml.jackson.core:jackson-databind:2.12.3"
implementation 'com.fasterxml.jackson.core:jackson-core:2.12.4'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.12.4'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.4'
implementation "org.hibernate.validator:hibernate-validator:7.0.1.Final"
implementation "org.glassfish:jakarta.el:4.0.1"
@ -28,10 +28,10 @@ dependencies {
implementation "org.tinylog:tinylog-api:2.4.0-M1"
implementation "org.tinylog:tinylog-impl:2.4.0-M1"
testImplementation "net.jqwik:jqwik:1.5.1"
testImplementation 'net.jqwik:jqwik:1.5.3'
testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.0-M1"
testImplementation "org.mockito:mockito-core:3.+"
testImplementation "org.assertj:assertj-core:3.19.0"
testImplementation 'org.mockito:mockito-core:3.11.2'
testImplementation 'org.assertj:assertj-core:3.20.2'
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.0-M1"
}

View File

@ -27,7 +27,7 @@ public class GameLogic {
* Checks a {@link Request} for validity for a {@link GameState}.
* @param state The game state to check on
* @param request The request to validate
* @return Whether or not the request is valid
* @return Whether the request is valid
*/
protected static boolean checkRequest(GameState state, Request request) {
try {
@ -36,15 +36,20 @@ public class GameLogic {
CharacterRequest data = (CharacterRequest)request;
Character origin = getCharacter(state, data.originField, data.originEntity);
Character target = getCharacter(state, data.targetField, data.targetEntity);
Entity target = getAttackable(state, data.targetField, data.targetEntity);
requireTurn(state, origin);
requireOppositeTeam(origin, target);
requireAlive(origin);
requireAlive(target);
requireAP(origin, 1);
if(target instanceof Character) {
Character targetCharacter = (Character)target;
requireOppositeTeam(origin, targetCharacter);
requireAlive(targetCharacter);
}
if(request.type == RequestType.MeleeAttackRequest) {
if(origin.meleeDamage != data.value) {
throw new InvalidRequestException("Invalid melee damage");
@ -183,6 +188,22 @@ public class GameLogic {
return false;
}
/**
* Retrieves an attack-able Entity ({@link Character} or {@link Rock}) for a {@link Request}.
* @param state The game state to use
* @param position The requested position
* @param entityID The requested {@link EntityID}
* @return The found entity
* @throws InvalidRequestException if the entity is invalid or not found
*/
private static Entity getAttackable(GameState state, IntVector2 position, EntityID entityID) throws InvalidRequestException {
Entity entity = state.entities.findEntity(entityID);
if(entity == null || !entity.getPosition().equals(position) || (!(entity instanceof Character) && !(entity instanceof Rock)) || entity.id.type == EntityType.NPC) {
throw new InvalidRequestException("Invalid target character or rock");
}
return entity;
}
/**
* Retrieves a {@link Character} for a {@link Request}.
* @param state The game state to use
@ -315,23 +336,34 @@ public class GameLogic {
.withAmount(data.value)
.buildEntityEvent());
Character target = (Character)state.entities.findEntity(data.targetEntity);
if(target.hp.getValue() <= data.value) {
Entity targetEntity = state.entities.findEntity(data.targetEntity);
if(targetEntity instanceof Character) {
Character target = (Character)targetEntity;
if(target.hp.getValue() <= data.value) {
List<StoneType> stones = Arrays.asList(target.inventory.getStonesAsArray());
Collections.shuffle(stones); // required by documents
List<StoneType> stones = Arrays.asList(target.inventory.getStonesAsArray());
Collections.shuffle(stones); // required by documents
ArrayList<IntVector2> used = new ArrayList<>();
for(StoneType stone: stones) {
ArrayList<IntVector2> options = getFreeNeighbour(state, target.getPosition(), used);
IntVector2 picked = options.get(rand.nextInt(options.size()));
used.add(picked);
result.add(new EventBuilder(EventType.SpawnEntityEvent)
.withEntity(new InfinityStone(
new EntityID(EntityType.InfinityStones, stone.getID()),
picked,
stone
))
ArrayList<IntVector2> used = new ArrayList<>();
for(StoneType stone: stones) {
ArrayList<IntVector2> options = getFreeNeighbour(state, target.getPosition(), used);
IntVector2 picked = options.get(rand.nextInt(options.size()));
used.add(picked);
result.add(new EventBuilder(EventType.SpawnEntityEvent)
.withEntity(new InfinityStone(
new EntityID(EntityType.InfinityStones, stone.getID()),
picked,
stone
))
.buildEntityEvent());
}
}
}else if(targetEntity instanceof Rock) {
Rock target = (Rock)targetEntity;
if(target.getHp() <= data.value) {
result.add(new EventBuilder(EventType.DestroyedEntityEvent)
.withTargetField(data.targetField)
.withTargetEntity(target.id)
.buildEntityEvent());
}
}
@ -526,19 +558,26 @@ public class GameLogic {
case TakenDamageEvent -> {
EntityEvent data = (EntityEvent)event;
Character target = (Character)state.entities.findEntity(data.targetEntity);
target.hp.decreaseValue(data.amount);
Entity targetEntity = state.entities.findEntity(data.targetEntity);
EntityType opposing = target.id.type == EntityType.P1 ? EntityType.P2 : EntityType.P1;
state.winConditions.increaseValue(opposing, WinCondition.TotalDamage, data.amount);
if(!target.isAlive()) {
target.inventory.clear();
state.winConditions.increaseValue(opposing, WinCondition.TotalKnockouts, 1);
}
if(targetEntity instanceof Character) {
Character target = (Character)targetEntity;
target.hp.decreaseValue(data.amount);
if(state.activeCharacter != null && state.activeCharacter.type == EntityType.NPC && state.activeCharacter.id == NPCType.Thanos.getID()) {
NPC thanos = (NPC)state.entities.findEntity(state.activeCharacter);
target.inventory.transfer(thanos.inventory);
EntityType opposing = target.id.type == EntityType.P1 ? EntityType.P2 : EntityType.P1;
state.winConditions.increaseValue(opposing, WinCondition.TotalDamage, data.amount);
if(!target.isAlive()) {
target.inventory.clear();
state.winConditions.increaseValue(opposing, WinCondition.TotalKnockouts, 1);
}
if(state.activeCharacter != null && state.activeCharacter.type == EntityType.NPC && state.activeCharacter.id == NPCType.Thanos.getID()) {
NPC thanos = (NPC)state.entities.findEntity(state.activeCharacter);
target.inventory.transfer(thanos.inventory);
}
}else if(targetEntity instanceof Rock) {
Rock target = (Rock)targetEntity;
target.decreaseHp(data.amount);
}
}
case ConsumedAPEvent -> {