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);
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
final float x_d = x2 - x1;
|
||||
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.entities.Entity;
|
||||
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.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
@ -14,6 +15,9 @@ public class EntityManager {
|
||||
/** The internal collection of {@link Entity}s */
|
||||
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}.
|
||||
* @param other The entity list to take the data from
|
||||
@ -23,6 +27,21 @@ public class EntityManager {
|
||||
for(Entity entity: other.entities) {
|
||||
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() {
|
||||
entities.clear();
|
||||
usedRockSlots.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,6 +57,9 @@ public class EntityManager {
|
||||
* @param entity The {@link Entity} to add
|
||||
*/
|
||||
public void addEntity(Entity entity) {
|
||||
if(entity.id.isSameType(EntityType.Rocks)) {
|
||||
usedRockSlots.add(entity.id.id);
|
||||
}
|
||||
entities.add(entity);
|
||||
}
|
||||
|
||||
@ -45,7 +68,9 @@ public class EntityManager {
|
||||
* @param entities The entities to add
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public boolean removeEntity(Entity entity) {
|
||||
if(entity.id.isSameType(EntityType.Rocks)) {
|
||||
usedRockSlots.remove(entity.id.id);
|
||||
}
|
||||
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.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.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.Event;
|
||||
import uulm.teamname.marvelous.gamelibrary.requests.CharacterRequest;
|
||||
@ -86,7 +83,78 @@ class GameLogic {
|
||||
.withTargetField(data.originField)
|
||||
.withAmount(1)
|
||||
.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 -> {
|
||||
result.add(new EventBuilder(EventType.GameStateEvent)
|
||||
@ -126,17 +194,17 @@ class GameLogic {
|
||||
if(origin.meleeDamage != data.value) {
|
||||
throw new InvalidRequestException();
|
||||
}
|
||||
if(data.originField.distanceManhattan(data.targetField) > 1) {
|
||||
if(data.originField.distanceChebyshev(data.targetField) > 1) {
|
||||
throw new InvalidRequestException();
|
||||
}
|
||||
}else if(request.type == RequestType.RangedAttackRequest) {
|
||||
if(origin.rangedDamage != data.value) {
|
||||
throw new InvalidRequestException();
|
||||
}
|
||||
if(data.originField.distanceManhattan(data.targetField) > origin.attackRange) {
|
||||
if(data.originField.distanceChebyshev(data.targetField) > origin.attackRange) {
|
||||
throw new InvalidRequestException();
|
||||
}
|
||||
if(data.originField.distanceManhattan(data.targetField) <= 1) {
|
||||
if(data.originField.distanceChebyshev(data.targetField) <= 1) {
|
||||
throw new InvalidRequestException();
|
||||
}
|
||||
requireLineOfSight(state, data.originField, data.targetField);
|
||||
@ -153,6 +221,10 @@ class GameLogic {
|
||||
requireMP(origin, 1);
|
||||
verifyCoordinates(state, data.targetField);
|
||||
|
||||
if(data.originField.distanceChebyshev(data.targetField) != 1) {
|
||||
throw new InvalidRequestException();
|
||||
}
|
||||
|
||||
if(state.entities.blocksMovement(data.targetField)) {
|
||||
throw new InvalidRequestException();
|
||||
}
|
||||
@ -170,21 +242,69 @@ class GameLogic {
|
||||
requireAP(origin, 1);
|
||||
requireInfinityStone(origin, data.stoneType);
|
||||
|
||||
if(data.originField.distanceChebyshev(data.targetField) != 1) {
|
||||
throw new InvalidRequestException();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case UseInfinityStoneRequest -> {
|
||||
CharacterRequest data = (CharacterRequest)request;
|
||||
|
||||
Character origin = getCharacter(state, data.originField, data.originEntity);
|
||||
Character target = getCharacter(state, data.targetField, data.targetEntity);
|
||||
|
||||
requireAlive(origin);
|
||||
requireAP(origin, 1);
|
||||
requireInfinityStone(origin, data.stoneType);
|
||||
|
||||
//TODO: properly verify UseInfinityStoneRequest in GameLogic.checkRequest
|
||||
if(!target.isActive()) {
|
||||
throw new InvalidRequestException();
|
||||
switch(((CharacterRequest) request).stoneType) {
|
||||
case SpaceStone -> {
|
||||
verifyCoordinates(state, data.targetField);
|
||||
|
||||
if(state.entities.blocksMovement(data.targetField)) {
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user