Compare commits

...

2 Commits

2 changed files with 75 additions and 36 deletions

View File

@ -18,9 +18,9 @@ test {
} }
dependencies { dependencies {
implementation "com.fasterxml.jackson.core:jackson-core:2.12.3" implementation 'com.fasterxml.jackson.core:jackson-core:2.12.4'
implementation "com.fasterxml.jackson.core:jackson-annotations:2.12.3" implementation 'com.fasterxml.jackson.core:jackson-annotations:2.12.4'
implementation "com.fasterxml.jackson.core:jackson-databind:2.12.3" implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.4'
implementation "org.hibernate.validator:hibernate-validator:7.0.1.Final" implementation "org.hibernate.validator:hibernate-validator:7.0.1.Final"
implementation "org.glassfish:jakarta.el:4.0.1" 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-api:2.4.0-M1"
implementation "org.tinylog:tinylog-impl: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.junit.jupiter:junit-jupiter-api:5.8.0-M1"
testImplementation "org.mockito:mockito-core:3.+" testImplementation 'org.mockito:mockito-core:3.11.2'
testImplementation "org.assertj:assertj-core:3.19.0" testImplementation 'org.assertj:assertj-core:3.20.2'
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.0-M1" 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}. * Checks a {@link Request} for validity for a {@link GameState}.
* @param state The game state to check on * @param state The game state to check on
* @param request The request to validate * @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) { protected static boolean checkRequest(GameState state, Request request) {
try { try {
@ -36,15 +36,20 @@ public class GameLogic {
CharacterRequest data = (CharacterRequest)request; CharacterRequest data = (CharacterRequest)request;
Character origin = getCharacter(state, data.originField, data.originEntity); 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); requireTurn(state, origin);
requireOppositeTeam(origin, target);
requireAlive(origin); requireAlive(origin);
requireAlive(target);
requireAP(origin, 1); requireAP(origin, 1);
if(target instanceof Character) {
Character targetCharacter = (Character)target;
requireOppositeTeam(origin, targetCharacter);
requireAlive(targetCharacter);
}
if(request.type == RequestType.MeleeAttackRequest) { if(request.type == RequestType.MeleeAttackRequest) {
if(origin.meleeDamage != data.value) { if(origin.meleeDamage != data.value) {
throw new InvalidRequestException("Invalid melee damage"); throw new InvalidRequestException("Invalid melee damage");
@ -183,6 +188,22 @@ public class GameLogic {
return false; 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}. * Retrieves a {@link Character} for a {@link Request}.
* @param state The game state to use * @param state The game state to use
@ -315,23 +336,34 @@ public class GameLogic {
.withAmount(data.value) .withAmount(data.value)
.buildEntityEvent()); .buildEntityEvent());
Character target = (Character)state.entities.findEntity(data.targetEntity); Entity targetEntity = state.entities.findEntity(data.targetEntity);
if(target.hp.getValue() <= data.value) { if(targetEntity instanceof Character) {
Character target = (Character)targetEntity;
if(target.hp.getValue() <= data.value) {
List<StoneType> stones = Arrays.asList(target.inventory.getStonesAsArray()); List<StoneType> stones = Arrays.asList(target.inventory.getStonesAsArray());
Collections.shuffle(stones); // required by documents Collections.shuffle(stones); // required by documents
ArrayList<IntVector2> used = new ArrayList<>(); ArrayList<IntVector2> used = new ArrayList<>();
for(StoneType stone: stones) { for(StoneType stone: stones) {
ArrayList<IntVector2> options = getFreeNeighbour(state, target.getPosition(), used); ArrayList<IntVector2> options = getFreeNeighbour(state, target.getPosition(), used);
IntVector2 picked = options.get(rand.nextInt(options.size())); IntVector2 picked = options.get(rand.nextInt(options.size()));
used.add(picked); used.add(picked);
result.add(new EventBuilder(EventType.SpawnEntityEvent) result.add(new EventBuilder(EventType.SpawnEntityEvent)
.withEntity(new InfinityStone( .withEntity(new InfinityStone(
new EntityID(EntityType.InfinityStones, stone.getID()), new EntityID(EntityType.InfinityStones, stone.getID()),
picked, picked,
stone 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()); .buildEntityEvent());
} }
} }
@ -526,19 +558,26 @@ public class GameLogic {
case TakenDamageEvent -> { case TakenDamageEvent -> {
EntityEvent data = (EntityEvent)event; EntityEvent data = (EntityEvent)event;
Character target = (Character)state.entities.findEntity(data.targetEntity); Entity targetEntity = state.entities.findEntity(data.targetEntity);
target.hp.decreaseValue(data.amount);
EntityType opposing = target.id.type == EntityType.P1 ? EntityType.P2 : EntityType.P1; if(targetEntity instanceof Character) {
state.winConditions.increaseValue(opposing, WinCondition.TotalDamage, data.amount); Character target = (Character)targetEntity;
if(!target.isAlive()) { target.hp.decreaseValue(data.amount);
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()) { EntityType opposing = target.id.type == EntityType.P1 ? EntityType.P2 : EntityType.P1;
NPC thanos = (NPC)state.entities.findEntity(state.activeCharacter); state.winConditions.increaseValue(opposing, WinCondition.TotalDamage, data.amount);
target.inventory.transfer(thanos.inventory); 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 -> { case ConsumedAPEvent -> {