Compare commits
	
		
			8 Commits
		
	
	
		
			9f5303ba74
			...
			cf035dedac
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| cf035dedac | |||
| a28741ac3d | |||
| 12f4d7592b | |||
| d2942341e2 | |||
| 673ba9f89d | |||
| a9acbda343 | |||
| 6e249280c1 | |||
| ebd7d2a12b | 
@ -58,6 +58,37 @@ public class Character extends Entity {
 | 
				
			|||||||
        this.meleeDamage = meleeDamage;
 | 
					        this.meleeDamage = meleeDamage;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Constructs a new {@link Character} with an empty inventory.
 | 
				
			||||||
 | 
					     * @param id The {@link EntityID} of the character
 | 
				
			||||||
 | 
					     * @param position The position of the character
 | 
				
			||||||
 | 
					     * @param name The name of the character
 | 
				
			||||||
 | 
					     * @param maxHp The maximum hp of the character
 | 
				
			||||||
 | 
					     * @param maxMp The maximum mp of the character
 | 
				
			||||||
 | 
					     * @param maxAp The maximum ap of the character
 | 
				
			||||||
 | 
					     * @param hp The current hp of the character
 | 
				
			||||||
 | 
					     * @param mp The current mp of the character
 | 
				
			||||||
 | 
					     * @param ap The current ap of the character
 | 
				
			||||||
 | 
					     * @param attackRange The ranged attack range of the character
 | 
				
			||||||
 | 
					     * @param rangedDamage The ranged damage of the character
 | 
				
			||||||
 | 
					     * @param meleeDamage The melee damage of the character
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public Character(EntityID id, IntVector2 position, String name, int maxHp, int maxMp, int maxAp, int hp, int mp, int ap, int attackRange, int rangedDamage, int meleeDamage) {
 | 
				
			||||||
 | 
					        super(id, position);
 | 
				
			||||||
 | 
					        solid = false;
 | 
				
			||||||
 | 
					        opaque = true;
 | 
				
			||||||
 | 
					        if(id.type == EntityType.NPC && id.id == NPCType.Thanos.getID()) {
 | 
				
			||||||
 | 
					            solid = true; //characters cannot walk into thanos
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.name = name;
 | 
				
			||||||
 | 
					        this.hp = new Stat(StatType.HP, hp, maxHp);
 | 
				
			||||||
 | 
					        this.mp = new Stat(StatType.MP, mp, maxMp);
 | 
				
			||||||
 | 
					        this.ap = new Stat(StatType.AP, ap, maxAp);
 | 
				
			||||||
 | 
					        this.attackRange = attackRange;
 | 
				
			||||||
 | 
					        this.rangedDamage = rangedDamage;
 | 
				
			||||||
 | 
					        this.meleeDamage = meleeDamage;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Checks if the character is still alive.
 | 
					     * Checks if the character is still alive.
 | 
				
			||||||
     * @return Whether or not the characters hp is greater than 0
 | 
					     * @return Whether or not the characters hp is greater than 0
 | 
				
			||||||
 | 
				
			|||||||
@ -32,8 +32,8 @@ public class Stat {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public Stat(StatType type, int value, int max) {
 | 
					    public Stat(StatType type, int value, int max) {
 | 
				
			||||||
        this.type = type;
 | 
					        this.type = type;
 | 
				
			||||||
        this.max = max;
 | 
					 | 
				
			||||||
        this.value = value;
 | 
					        this.value = value;
 | 
				
			||||||
 | 
					        this.max = max;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -42,7 +42,7 @@ public class Stat {
 | 
				
			|||||||
     * @param toCopy is the {@link Stat} to copy
 | 
					     * @param toCopy is the {@link Stat} to copy
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public Stat(Stat toCopy) {
 | 
					    public Stat(Stat toCopy) {
 | 
				
			||||||
        this(toCopy.type, toCopy.value, toCopy.max);
 | 
					        this(toCopy.type, toCopy.getValue(), toCopy.getMax());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public int getValue() {
 | 
					    public int getValue() {
 | 
				
			||||||
 | 
				
			|||||||
@ -119,6 +119,7 @@ public class GameInstance {
 | 
				
			|||||||
        manager.applyEvent(gameStateEvent);
 | 
					        manager.applyEvent(gameStateEvent);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Deprecated
 | 
				
			||||||
    public GameState getGameStateUnsafe() {
 | 
					    public GameState getGameStateUnsafe() {
 | 
				
			||||||
        return _state;
 | 
					        return _state;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -136,22 +136,52 @@ public class GameLogic {
 | 
				
			|||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case MindStone -> {
 | 
					                        case MindStone -> {
 | 
				
			||||||
 | 
					                            verifyCoordinates(state, data.targetField);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            requireLineOfSight(state, data.originField, data.targetField);
 | 
					                            requireLineOfSight(state, data.originField, data.targetField);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            getAttackableWithoutID(state, data.targetField);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case RealityStone -> {
 | 
					                        case RealityStone -> {
 | 
				
			||||||
                            // no check done
 | 
					                            verifyCoordinates(state, data.targetField);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            boolean rock = false;
 | 
				
			||||||
 | 
					                            boolean empty = true;
 | 
				
			||||||
 | 
					                            for(Entity entity: state.entities.findByPosition(data.targetField)) {
 | 
				
			||||||
 | 
					                                if(entity.id.type == EntityType.Rocks) {
 | 
				
			||||||
 | 
					                                    rock = true;
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                }else {
 | 
				
			||||||
 | 
					                                    empty = false;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if(!empty && !rock) {
 | 
				
			||||||
 | 
					                                throw new InvalidRequestException("Using reality stone on non-free field without a rock");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case PowerStone -> {
 | 
					                        case PowerStone -> {
 | 
				
			||||||
                            Character target = getCharacter(state, data.targetField, data.targetEntity);
 | 
					                            verifyCoordinates(state, data.targetField);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            requireAlive(target);
 | 
					                            Entity target = getAttackableWithoutID(state, data.targetField);
 | 
				
			||||||
                            requireOppositeTeam(origin, target);
 | 
					
 | 
				
			||||||
 | 
					                            if(target instanceof Character) {
 | 
				
			||||||
 | 
					                                Character targetCharacter = (Character)target;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                requireOppositeTeam(origin, targetCharacter);
 | 
				
			||||||
 | 
					                                requireAlive(targetCharacter);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if(data.originField.distanceChebyshev(data.targetField) != 1) {
 | 
				
			||||||
 | 
					                                throw new InvalidRequestException("Invalid melee target distance");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case TimeStone -> {
 | 
					                        case TimeStone -> {
 | 
				
			||||||
                            // "👍  i approve" - the server
 | 
					                            // "👍  i approve" - the server
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case SoulStone -> {
 | 
					                        case SoulStone -> {
 | 
				
			||||||
                            Character target = getCharacter(state, data.targetField, data.targetEntity);
 | 
					                            verifyCoordinates(state, data.targetField);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            Character target = getCharacterWithoutID(state, data.targetField);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            if(data.originEntity.equals(data.targetEntity)) {
 | 
					                            if(data.originEntity.equals(data.targetEntity)) {
 | 
				
			||||||
                                throw new InvalidRequestException("Invalid soul stone target (same as origin)");
 | 
					                                throw new InvalidRequestException("Invalid soul stone target (same as origin)");
 | 
				
			||||||
@ -199,6 +229,21 @@ public class GameLogic {
 | 
				
			|||||||
        return entity;
 | 
					        return entity;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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
 | 
				
			||||||
 | 
					     * @return The found entity
 | 
				
			||||||
 | 
					     * @throws InvalidRequestException if the entity is invalid or not found
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static Entity getAttackableWithoutID(GameState state, IntVector2 position) throws InvalidRequestException {
 | 
				
			||||||
 | 
					        ArrayList<Entity> entities = state.entities.findByPosition(position);
 | 
				
			||||||
 | 
					        if(entities.isEmpty() || entities.get(0).id.type == EntityType.NPC) {
 | 
				
			||||||
 | 
					            throw new InvalidRequestException("Invalid target character or rock");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return entities.get(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 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
 | 
				
			||||||
@ -219,6 +264,25 @@ public class GameLogic {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Retrieves a {@link Character} for a {@link Request}.
 | 
				
			||||||
 | 
					     * @param state The game state to use
 | 
				
			||||||
 | 
					     * @param position The requested position
 | 
				
			||||||
 | 
					     * @return The found character
 | 
				
			||||||
 | 
					     * @throws InvalidRequestException if the character is invalid or not found
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static Character getCharacterWithoutID(GameState state, IntVector2 position) throws InvalidRequestException {
 | 
				
			||||||
 | 
					        ArrayList<Entity> entities = state.entities.findByPosition(position);
 | 
				
			||||||
 | 
					        if(entities.isEmpty() || !(entities.get(0) instanceof Character) || entities.get(0).id.type == EntityType.NPC) {
 | 
				
			||||||
 | 
					            throw new InvalidRequestException("Invalid origin or target character");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            return (Character)entities.get(0);
 | 
				
			||||||
 | 
					        }catch(Exception ignored) {
 | 
				
			||||||
 | 
					            throw new InvalidRequestException("Invalid origin or target character (cast failed)");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Verifies that a {@link Character} has a turn.
 | 
					     * Verifies that a {@link Character} has a turn.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@ -449,7 +513,8 @@ public class GameLogic {
 | 
				
			|||||||
                                    .buildCharacterEvent());
 | 
					                                    .buildCharacterEvent());
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case MindStone -> {
 | 
					                        case MindStone -> {
 | 
				
			||||||
                            Entity targetEntity = state.entities.findEntity(data.targetEntity);
 | 
					                            ArrayList<Entity> found = state.entities.findByPosition(data.targetField);
 | 
				
			||||||
 | 
					                            Entity targetEntity = found.get(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            result.add(new EventBuilder(EventType.TakenDamageEvent)
 | 
					                            result.add(new EventBuilder(EventType.TakenDamageEvent)
 | 
				
			||||||
                                    .withTargetEntity(targetEntity.id)
 | 
					                                    .withTargetEntity(targetEntity.id)
 | 
				
			||||||
@ -459,7 +524,7 @@ public class GameLogic {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                            if(targetEntity instanceof Character) {
 | 
					                            if(targetEntity instanceof Character) {
 | 
				
			||||||
                                Character target = (Character)targetEntity;
 | 
					                                Character target = (Character)targetEntity;
 | 
				
			||||||
                                if(target.hp.getValue() <= data.value) {
 | 
					                                if(target.hp.getValue() <= state.partyConfig.mindStoneDMG) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                    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
 | 
				
			||||||
@ -480,7 +545,7 @@ public class GameLogic {
 | 
				
			|||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }else if(targetEntity instanceof Rock) {
 | 
					                            }else if(targetEntity instanceof Rock) {
 | 
				
			||||||
                                Rock target = (Rock)targetEntity;
 | 
					                                Rock target = (Rock)targetEntity;
 | 
				
			||||||
                                if(target.getHp() <= data.value) {
 | 
					                                if(target.getHp() <= state.partyConfig.mindStoneDMG) {
 | 
				
			||||||
                                    result.add(new EventBuilder(EventType.DestroyedEntityEvent)
 | 
					                                    result.add(new EventBuilder(EventType.DestroyedEntityEvent)
 | 
				
			||||||
                                            .withTargetField(data.targetField)
 | 
					                                            .withTargetField(data.targetField)
 | 
				
			||||||
                                            .withTargetEntity(target.id)
 | 
					                                            .withTargetEntity(target.id)
 | 
				
			||||||
@ -509,6 +574,9 @@ public class GameLogic {
 | 
				
			|||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case PowerStone -> {
 | 
					                        case PowerStone -> {
 | 
				
			||||||
 | 
					                            ArrayList<Entity> found = state.entities.findByPosition(data.targetField);
 | 
				
			||||||
 | 
					                            Entity targetEntity = found.get(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            Character origin = (Character)state.entities.findEntity(data.originEntity);
 | 
					                            Character origin = (Character)state.entities.findEntity(data.originEntity);
 | 
				
			||||||
                            int dmg = (int)Math.round(origin.hp.getMax() * 0.1);
 | 
					                            int dmg = (int)Math.round(origin.hp.getMax() * 0.1);
 | 
				
			||||||
                            //this is ugly ... but also easy to understand
 | 
					                            //this is ugly ... but also easy to understand
 | 
				
			||||||
@ -523,7 +591,7 @@ public class GameLogic {
 | 
				
			|||||||
                                        .buildEntityEvent());
 | 
					                                        .buildEntityEvent());
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            result.add(new EventBuilder(EventType.TakenDamageEvent)
 | 
					                            result.add(new EventBuilder(EventType.TakenDamageEvent)
 | 
				
			||||||
                                    .withTargetEntity(data.targetEntity)
 | 
					                                    .withTargetEntity(targetEntity.id)
 | 
				
			||||||
                                    .withTargetField(data.targetField)
 | 
					                                    .withTargetField(data.targetField)
 | 
				
			||||||
                                    .withAmount(origin.meleeDamage * 2)
 | 
					                                    .withAmount(origin.meleeDamage * 2)
 | 
				
			||||||
                                    .buildEntityEvent());
 | 
					                                    .buildEntityEvent());
 | 
				
			||||||
@ -548,9 +616,11 @@ public class GameLogic {
 | 
				
			|||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case SoulStone -> {
 | 
					                        case SoulStone -> {
 | 
				
			||||||
                            Character target = (Character)state.entities.findEntity(data.targetEntity);
 | 
					                            ArrayList<Entity> found = state.entities.findByPosition(data.targetField);
 | 
				
			||||||
 | 
					                            Character target = (Character)found.get(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            result.add(new EventBuilder(EventType.HealedEvent)
 | 
					                            result.add(new EventBuilder(EventType.HealedEvent)
 | 
				
			||||||
                                    .withTargetEntity(data.targetEntity)
 | 
					                                    .withTargetEntity(target.id)
 | 
				
			||||||
                                    .withTargetField(data.targetField)
 | 
					                                    .withTargetField(data.targetField)
 | 
				
			||||||
                                    .withAmount(target.hp.getMax())
 | 
					                                    .withAmount(target.hp.getMax())
 | 
				
			||||||
                                    .buildEntityEvent());
 | 
					                                    .buildEntityEvent());
 | 
				
			||||||
 | 
				
			|||||||
@ -43,6 +43,9 @@ public class EntityDeserializer extends JsonDeserializer<Entity> {
 | 
				
			|||||||
                        id,
 | 
					                        id,
 | 
				
			||||||
                        codec.treeToValue(node.get("position"), IntVector2.class),
 | 
					                        codec.treeToValue(node.get("position"), IntVector2.class),
 | 
				
			||||||
                        characterName,
 | 
					                        characterName,
 | 
				
			||||||
 | 
					                        properties.HP,
 | 
				
			||||||
 | 
					                        properties.MP,
 | 
				
			||||||
 | 
					                        properties.AP,
 | 
				
			||||||
                        node.get("HP").asInt(),
 | 
					                        node.get("HP").asInt(),
 | 
				
			||||||
                        node.get("MP").asInt(),
 | 
					                        node.get("MP").asInt(),
 | 
				
			||||||
                        node.get("AP").asInt(),
 | 
					                        node.get("AP").asInt(),
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user