feat: add handling and checking for UseInfinityStoneRequest, fix: use proper distance calculations for some checks
This commit is contained in:
parent
4203092f9a
commit
1a98f25139
@ -120,6 +120,23 @@ public class IntVector2 implements Serializable {
|
|||||||
return distance(v.x, v.y);
|
return distance(v.x, v.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Equivalent to the minimum amount of king moves to go from A to B in chess */
|
||||||
|
public static float distanceChebyshev(int x1, int y1, int x2, int y2) {
|
||||||
|
final float x_d = x2 - x1;
|
||||||
|
final float y_d = y2 - y1;
|
||||||
|
return Math.max(Math.abs(x_d), Math.abs(y_d));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Equivalent to the minimum amount of king moves to go from A to B in chess */
|
||||||
|
public float distanceChebyshev(int x, int y) {
|
||||||
|
return IntVector2.distanceChebyshev(this.x, this.y, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Equivalent to the minimum amount of king moves to go from A to B in chess */
|
||||||
|
public float distanceChebyshev(IntVector2 v) {
|
||||||
|
return distanceChebyshev(v.x, v.y);
|
||||||
|
}
|
||||||
|
|
||||||
public static float distanceManhattan(int x1, int y1, int x2, int y2) {
|
public static float distanceManhattan(int x1, int y1, int x2, int y2) {
|
||||||
final float x_d = x2 - x1;
|
final float x_d = x2 - x1;
|
||||||
final float y_d = y2 - y1;
|
final float y_d = y2 - y1;
|
||||||
|
@ -3,9 +3,10 @@ package uulm.teamname.marvelous.gamelibrary.gamelogic;
|
|||||||
import uulm.teamname.marvelous.gamelibrary.IntVector2;
|
import uulm.teamname.marvelous.gamelibrary.IntVector2;
|
||||||
import uulm.teamname.marvelous.gamelibrary.entities.Entity;
|
import uulm.teamname.marvelous.gamelibrary.entities.Entity;
|
||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityID;
|
import uulm.teamname.marvelous.gamelibrary.entities.EntityID;
|
||||||
|
import uulm.teamname.marvelous.gamelibrary.entities.EntityType;
|
||||||
|
import uulm.teamname.marvelous.gamelibrary.entities.Rock;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
@ -14,6 +15,9 @@ public class EntityManager {
|
|||||||
/** The internal collection of {@link Entity}s */
|
/** The internal collection of {@link Entity}s */
|
||||||
private final HashSet<Entity> entities = new HashSet<>();
|
private final HashSet<Entity> entities = new HashSet<>();
|
||||||
|
|
||||||
|
/** A set of all currently used {@link Rock} entity ids */
|
||||||
|
private final HashSet<Integer> usedRockSlots = new HashSet<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes over all the entities from a different {@link EntityManager}.
|
* Takes over all the entities from a different {@link EntityManager}.
|
||||||
* @param other The entity list to take the data from
|
* @param other The entity list to take the data from
|
||||||
@ -23,6 +27,21 @@ public class EntityManager {
|
|||||||
for(Entity entity: other.entities) {
|
for(Entity entity: other.entities) {
|
||||||
entities.add(entity.clone());
|
entities.add(entity.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usedRockSlots.clear();
|
||||||
|
usedRockSlots.addAll(other.usedRockSlots);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an unused {@link Rock} entity id
|
||||||
|
* @return The first free id
|
||||||
|
*/
|
||||||
|
public int findFreeRockSlot() {
|
||||||
|
int i = 0;
|
||||||
|
while(usedRockSlots.contains(i)) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,6 +49,7 @@ public class EntityManager {
|
|||||||
*/
|
*/
|
||||||
public void clear() {
|
public void clear() {
|
||||||
entities.clear();
|
entities.clear();
|
||||||
|
usedRockSlots.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,6 +57,9 @@ public class EntityManager {
|
|||||||
* @param entity The {@link Entity} to add
|
* @param entity The {@link Entity} to add
|
||||||
*/
|
*/
|
||||||
public void addEntity(Entity entity) {
|
public void addEntity(Entity entity) {
|
||||||
|
if(entity.id.isSameType(EntityType.Rocks)) {
|
||||||
|
usedRockSlots.add(entity.id.id);
|
||||||
|
}
|
||||||
entities.add(entity);
|
entities.add(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +68,9 @@ public class EntityManager {
|
|||||||
* @param entities The entities to add
|
* @param entities The entities to add
|
||||||
*/
|
*/
|
||||||
public void addEntities(Entity... entities) {
|
public void addEntities(Entity... entities) {
|
||||||
this.entities.addAll(Arrays.asList(entities));
|
for(Entity e: entities) {
|
||||||
|
this.addEntity(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,6 +78,9 @@ public class EntityManager {
|
|||||||
* @param entity The {@link Entity} to remove
|
* @param entity The {@link Entity} to remove
|
||||||
*/
|
*/
|
||||||
public boolean removeEntity(Entity entity) {
|
public boolean removeEntity(Entity entity) {
|
||||||
|
if(entity.id.isSameType(EntityType.Rocks)) {
|
||||||
|
usedRockSlots.remove(entity.id.id);
|
||||||
|
}
|
||||||
return entities.remove(entity);
|
return entities.remove(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,8 @@ package uulm.teamname.marvelous.gamelibrary.gamelogic;
|
|||||||
|
|
||||||
import uulm.teamname.marvelous.gamelibrary.IntVector2;
|
import uulm.teamname.marvelous.gamelibrary.IntVector2;
|
||||||
import uulm.teamname.marvelous.gamelibrary.Tuple;
|
import uulm.teamname.marvelous.gamelibrary.Tuple;
|
||||||
import uulm.teamname.marvelous.gamelibrary.entities.Entity;
|
import uulm.teamname.marvelous.gamelibrary.entities.*;
|
||||||
import uulm.teamname.marvelous.gamelibrary.entities.Character;
|
import uulm.teamname.marvelous.gamelibrary.entities.Character;
|
||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityID;
|
|
||||||
import uulm.teamname.marvelous.gamelibrary.entities.StoneType;
|
|
||||||
import uulm.teamname.marvelous.gamelibrary.entities.StatType;
|
|
||||||
import uulm.teamname.marvelous.gamelibrary.events.*;
|
import uulm.teamname.marvelous.gamelibrary.events.*;
|
||||||
import uulm.teamname.marvelous.gamelibrary.events.Event;
|
import uulm.teamname.marvelous.gamelibrary.events.Event;
|
||||||
import uulm.teamname.marvelous.gamelibrary.requests.CharacterRequest;
|
import uulm.teamname.marvelous.gamelibrary.requests.CharacterRequest;
|
||||||
@ -86,7 +83,78 @@ class GameLogic {
|
|||||||
.withTargetField(data.originField)
|
.withTargetField(data.originField)
|
||||||
.withAmount(1)
|
.withAmount(1)
|
||||||
.buildEntityEvent());
|
.buildEntityEvent());
|
||||||
//TODO: add infinity stone usage effect in GameLogic.executeRequest
|
|
||||||
|
if(request.type == RequestType.UseInfinityStoneRequest) {
|
||||||
|
switch(((CharacterRequest) request).stoneType) {
|
||||||
|
case SpaceStone -> {
|
||||||
|
result.add(new EventBuilder(EventType.MoveEvent)
|
||||||
|
.withOriginEntity(data.originEntity)
|
||||||
|
.withOriginField(data.originField)
|
||||||
|
.withTargetField(data.targetField)
|
||||||
|
.buildCharacterEvent());
|
||||||
|
}
|
||||||
|
case MindStone -> {
|
||||||
|
//TODO: mind stone effect ???????
|
||||||
|
}
|
||||||
|
case RealityStone -> {
|
||||||
|
if(data.originEntity == data.targetEntity) { // => place stone
|
||||||
|
//TODO: use config values
|
||||||
|
result.add(new EventBuilder(EventType.SpawnEntityEvent)
|
||||||
|
.withTargetField(data.targetField)
|
||||||
|
.withEntity(new Rock(new EntityID(EntityType.Rocks, state.entities.findFreeRockSlot()), data.targetField, 100))
|
||||||
|
.buildEntityEvent());
|
||||||
|
}else { // => destroy stone
|
||||||
|
result.add(new EventBuilder(EventType.DestroyedEntityEvent)
|
||||||
|
.withTargetField(data.targetField)
|
||||||
|
.withTargetEntity(data.targetEntity)
|
||||||
|
.buildEntityEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PowerStone -> {
|
||||||
|
Character origin = (Character)state.entities.findEntity(data.originEntity);
|
||||||
|
int dmg = (int)Math.round(origin.hp.getValue() * 0.1);
|
||||||
|
if(origin.hp.getValue() != 1 && dmg > 0) {
|
||||||
|
result.add(new EventBuilder(EventType.TakenDamageEvent)
|
||||||
|
.withTargetEntity(data.originEntity)
|
||||||
|
.withTargetField(data.originField)
|
||||||
|
.withAmount(dmg)
|
||||||
|
.buildEntityEvent());
|
||||||
|
}
|
||||||
|
result.add(new EventBuilder(EventType.TakenDamageEvent)
|
||||||
|
.withTargetEntity(data.targetEntity)
|
||||||
|
.withTargetField(data.targetField)
|
||||||
|
.withAmount(data.value)
|
||||||
|
.buildEntityEvent());
|
||||||
|
}
|
||||||
|
case TimeStone -> {
|
||||||
|
Character origin = (Character)state.entities.findEntity(data.originEntity);
|
||||||
|
int ap = origin.ap.max - origin.ap.getValue();
|
||||||
|
if(ap < 0) {
|
||||||
|
result.add(new EventBuilder(EventType.ConsumedAPEvent)
|
||||||
|
.withTargetEntity(data.originEntity)
|
||||||
|
.withTargetField(data.originField)
|
||||||
|
.withAmount(ap)
|
||||||
|
.buildEntityEvent());
|
||||||
|
}
|
||||||
|
int mp = origin.mp.max - origin.mp.getValue();
|
||||||
|
if(mp < 0) {
|
||||||
|
result.add(new EventBuilder(EventType.ConsumedMPEvent)
|
||||||
|
.withTargetEntity(data.originEntity)
|
||||||
|
.withTargetField(data.originField)
|
||||||
|
.withAmount(mp)
|
||||||
|
.buildEntityEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SoulStone -> {
|
||||||
|
Character target = (Character)state.entities.findEntity(data.targetEntity);
|
||||||
|
result.add(new EventBuilder(EventType.HealedEvent)
|
||||||
|
.withTargetEntity(data.targetEntity)
|
||||||
|
.withTargetField(data.targetField)
|
||||||
|
.withAmount(target.hp.max)
|
||||||
|
.buildEntityEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case Req -> {
|
case Req -> {
|
||||||
result.add(new EventBuilder(EventType.GameStateEvent)
|
result.add(new EventBuilder(EventType.GameStateEvent)
|
||||||
@ -126,17 +194,17 @@ class GameLogic {
|
|||||||
if(origin.meleeDamage != data.value) {
|
if(origin.meleeDamage != data.value) {
|
||||||
throw new InvalidRequestException();
|
throw new InvalidRequestException();
|
||||||
}
|
}
|
||||||
if(data.originField.distanceManhattan(data.targetField) > 1) {
|
if(data.originField.distanceChebyshev(data.targetField) > 1) {
|
||||||
throw new InvalidRequestException();
|
throw new InvalidRequestException();
|
||||||
}
|
}
|
||||||
}else if(request.type == RequestType.RangedAttackRequest) {
|
}else if(request.type == RequestType.RangedAttackRequest) {
|
||||||
if(origin.rangedDamage != data.value) {
|
if(origin.rangedDamage != data.value) {
|
||||||
throw new InvalidRequestException();
|
throw new InvalidRequestException();
|
||||||
}
|
}
|
||||||
if(data.originField.distanceManhattan(data.targetField) > origin.attackRange) {
|
if(data.originField.distanceChebyshev(data.targetField) > origin.attackRange) {
|
||||||
throw new InvalidRequestException();
|
throw new InvalidRequestException();
|
||||||
}
|
}
|
||||||
if(data.originField.distanceManhattan(data.targetField) <= 1) {
|
if(data.originField.distanceChebyshev(data.targetField) <= 1) {
|
||||||
throw new InvalidRequestException();
|
throw new InvalidRequestException();
|
||||||
}
|
}
|
||||||
requireLineOfSight(state, data.originField, data.targetField);
|
requireLineOfSight(state, data.originField, data.targetField);
|
||||||
@ -153,6 +221,10 @@ class GameLogic {
|
|||||||
requireMP(origin, 1);
|
requireMP(origin, 1);
|
||||||
verifyCoordinates(state, data.targetField);
|
verifyCoordinates(state, data.targetField);
|
||||||
|
|
||||||
|
if(data.originField.distanceChebyshev(data.targetField) != 1) {
|
||||||
|
throw new InvalidRequestException();
|
||||||
|
}
|
||||||
|
|
||||||
if(state.entities.blocksMovement(data.targetField)) {
|
if(state.entities.blocksMovement(data.targetField)) {
|
||||||
throw new InvalidRequestException();
|
throw new InvalidRequestException();
|
||||||
}
|
}
|
||||||
@ -170,22 +242,70 @@ class GameLogic {
|
|||||||
requireAP(origin, 1);
|
requireAP(origin, 1);
|
||||||
requireInfinityStone(origin, data.stoneType);
|
requireInfinityStone(origin, data.stoneType);
|
||||||
|
|
||||||
|
if(data.originField.distanceChebyshev(data.targetField) != 1) {
|
||||||
|
throw new InvalidRequestException();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case UseInfinityStoneRequest -> {
|
case UseInfinityStoneRequest -> {
|
||||||
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);
|
|
||||||
|
|
||||||
requireAlive(origin);
|
requireAlive(origin);
|
||||||
requireAP(origin, 1);
|
requireAP(origin, 1);
|
||||||
requireInfinityStone(origin, data.stoneType);
|
requireInfinityStone(origin, data.stoneType);
|
||||||
|
|
||||||
//TODO: properly verify UseInfinityStoneRequest in GameLogic.checkRequest
|
switch(((CharacterRequest) request).stoneType) {
|
||||||
if(!target.isActive()) {
|
case SpaceStone -> {
|
||||||
|
verifyCoordinates(state, data.targetField);
|
||||||
|
|
||||||
|
if(state.entities.blocksMovement(data.targetField)) {
|
||||||
throw new InvalidRequestException();
|
throw new InvalidRequestException();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
case MindStone -> {
|
||||||
|
//TODO: mind stone requirements (config, etc) ???????
|
||||||
|
}
|
||||||
|
case RealityStone -> {
|
||||||
|
if(data.originEntity == data.targetEntity) { // => place stone
|
||||||
|
if(state.entities.findByPosition(data.targetField).size() != 0) {
|
||||||
|
throw new InvalidRequestException();
|
||||||
|
}
|
||||||
|
}else { // => destroy stone
|
||||||
|
boolean hasRock = false;
|
||||||
|
for(Entity entity: state.entities.findByPosition(data.targetField)) {
|
||||||
|
if(entity.id.isSameType(EntityType.Rocks)) {
|
||||||
|
hasRock = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!hasRock) {
|
||||||
|
throw new InvalidRequestException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PowerStone -> {
|
||||||
|
Character target = getCharacter(state, data.targetField, data.targetEntity);
|
||||||
|
|
||||||
|
requireAlive(target);
|
||||||
|
|
||||||
|
if(origin.rangedDamage * 2 != data.value) {
|
||||||
|
throw new InvalidRequestException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case TimeStone -> {
|
||||||
|
// "👍 i approve" - the server
|
||||||
|
}
|
||||||
|
case SoulStone -> {
|
||||||
|
Character target = getCharacter(state, data.targetField, data.targetEntity);
|
||||||
|
|
||||||
|
if(target.hp.getValue() != 0) {
|
||||||
|
throw new InvalidRequestException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user