Package org.jpokemon.battle

Source Code of org.jpokemon.battle.Battle

package org.jpokemon.battle;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;

import org.jpokemon.activity.Activity;
import org.jpokemon.battle.activity.BuildAttackTurnActivity;
import org.jpokemon.battle.activity.BuildRunTurnActivity;
import org.jpokemon.battle.activity.BuildSwapTurnActivity;
import org.jpokemon.battle.activity.BuildTurnActivity;
import org.jpokemon.battle.slot.Slot;
import org.jpokemon.battle.turn.AttackTurn;
import org.jpokemon.battle.turn.SwapTurn;
import org.jpokemon.battle.turn.Turn;
import org.jpokemon.pokemon.ConditionEffect;
import org.jpokemon.pokemon.Pokemon;
import org.jpokemon.pokemon.Type;
import org.jpokemon.pokemon.move.Move;
import org.jpokemon.pokemon.move.MoveStyle;
import org.jpokemon.server.PlayerManager;
import org.jpokemon.server.ServiceException;
import org.jpokemon.trainer.Player;
import org.jpokemon.trainer.PokemonTrainer;
import org.jpokemon.trainer.Trainer;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.zachtaylor.myna.Myna;

public class Battle implements Activity, Iterable<Slot> {
  public static double stab = 1.5;
  public static double typeadvantage = 2.0;
  public static double typedisadvantage = .5;

  static {
    Myna.configure(Battle.class, "org.jpokemon.battle");
  }

  private List<String> log = new ArrayList<String>();
  private Map<String, Slot> slots = new HashMap<String, Slot>();
  private Map<String, Turn> turns = new HashMap<String, Turn>();

  public Battle(PokemonTrainer... trainers) {
    System.out.println(this + " created");

    for (int i = 0; i < trainers.length; i++) {
      PokemonTrainer trainer = trainers[i];
      addTrainer(trainer, i);
    }

    doTrainerAttacks();
  }

  public void addTrainer(PokemonTrainer trainer, int team) {
    if (contains(trainer))
      throw new IllegalArgumentException("Duplicate trainer: " + trainer);

    slots.put(trainer.id(), new Slot(trainer, team));
    System.out.println(this + " trainer added: " + trainer);
  }

  public int getTrainerCount() {
    return slots.size();
  }

  public Slot getSlot(String trainerId) {
    return slots.get(trainerId);
  }

  public boolean contains(PokemonTrainer trainer) {
    return slots.get(trainer.id()) != null;
  }

  public void remove(PokemonTrainer trainer) {
    System.out.println(toString() + " remove trainer: " + trainer.id());

    if (trainer.party().awake() == 0) {
      if (trainer instanceof Trainer) {
        addTrainerToPlayerHistory(trainer.id());
      }
      else if (trainer instanceof Player) {
        // TODO - punish player
      }
    }

    if (trainer instanceof Player) {
      Player player = (Player) trainer;

      pushLog(false);

      JSONObject json = new JSONObject();
      try {
        json.put("action", "battle");
        json.put("visible", false);
      }
      catch (JSONException e) {
      }
      PlayerManager.pushJson(player, json);

      PlayerManager.popActivity(player, this);
    }

    slots.remove(trainer.id());

    verifyTeamCount();
  }

  public void addTurn(Turn turn) {
    turns.put(turn.slot().trainer().id(), turn);
    System.out.println(toString() + " turn set: " + turn.slot().trainer().id() + "\t" + turn.toString());

    if (turns.size() == slots.size()) {
      executeRound();
    }
  }

  @Override
  public void onAdd(Player player) throws ServiceException {
    PlayerManager.pushJson(player, generateJson());
  }

  @Override
  public void logout(Player player) {
    // TODO - punish player
  }

  @Override
  public void onReturn(Activity activity, Player player) {
    if (activity instanceof BuildTurnActivity) {
      BuildTurnActivity bta = (BuildTurnActivity) activity;
      Turn turn = bta.getTurn();
      addTurn(turn);

      JSONObject json = generateJson();
      for (Slot slot : this) {
        if (slot.trainer() instanceof Player) {
          player = (Player) slot.trainer();
          PlayerManager.pushJson(player, json);
        }
      }
    }
  }

  @Override
  public void serve(JSONObject request, Player player) throws ServiceException {
    if (turns.get(player.id()) != null) { return; }

    try {
      if (request.has("turn")) {
        String turn = request.getString("turn");

        if ("attack".equals(turn)) {
          PlayerManager.addActivity(player, new BuildAttackTurnActivity(this));
        }
        else if ("item".equals(turn)) {

        }
        else if ("swap".equals(turn)) {
          PlayerManager.addActivity(player, new BuildSwapTurnActivity(this));
        }
        else if ("run".equals(turn)) {
          PlayerManager.addActivity(player, new BuildRunTurnActivity(this));
        }
      }
    }
    catch (JSONException e) {
    }
  }

  public void log(String message) {
    log.add(message);
  }

  public void pushLog(boolean clear) {
    JSONObject json = new JSONObject();

    try {
      json.put("action", "battlelog");
      json.put("logs", new JSONArray(log));
      json.put("clear", clear);
    }
    catch (JSONException e) {
      e.printStackTrace();
    }

    for (Slot slot : this) {
      if (slot.trainer() instanceof Player) {
        Player player = (Player) slot.trainer();

        PlayerManager.pushJson(player, json);
      }
    }
  }

  @Override
  public Iterator<Slot> iterator() {
    return slots.values().iterator();
  }

  public String toString() {
    return "Battle@" + hashCode();
  }

  private void executeRound() {
    Queue<Turn> turnQueue = new PriorityQueue<Turn>();
    Map<String, Turn> currentRoundTurns = turns;
    turns = new HashMap<String, Turn>();

    // Prepare the turn queue
    for (Turn turn : currentRoundTurns.values()) {
      turnQueue.add(turn);
    }

    // MADNESS
    while (!turnQueue.isEmpty()) {
      Turn turn = turnQueue.remove();

      turn.execute();

      if (!turn.target().leader().awake()) {
        log(turn.target().trainer().id() + "'s " + turn.target().leader().name() + " fainted");
        Turn turnToRemove = currentRoundTurns.get(turn.target().trainer().id());
        boolean turnWasRemoved = turnQueue.remove(turnToRemove);

        if (turn.target().party().awake() == 0) {
          log(turn.target().trainer().id() + " lost!");
          remove(turn.target().trainer());
        }
        else if (turnWasRemoved) {
          log(turn.target().trainer().id() + " will auto-swap to the next available pokemon");
          turnQueue.add(SwapTurn.autoSwapTurn(this, turn.target()));
        }
      }

      if (!turn.slot().leader().awake()) {
        remove(turn.slot().trainer());
      }
      else if (turn.reAdd()) {
        addTurn(turn);
      }
    }

    applyEndOfRoundEffects();
    doTrainerAttacks();

    for (Slot slot : this) {
      if (!slot.leader().awake()) {
        if (slot.party().awake() > 0) {
          if (slot.trainer() instanceof Player) {
            log(slot.trainer().id() + " must swap on the next turn");
            PlayerManager.addActivity((Player) slot.trainer(), new BuildSwapTurnActivity(this));
          }
          else {
            addTurn(SwapTurn.autoSwapTurn(this, slot));
          }
        }
        else {
          remove(slot.trainer());
        }
      }
    }

    System.out.println(toString() + " logs : " + log.toString());
    pushLog(true);
    log = new ArrayList<String>();
  }

  private void doTrainerAttacks() {
    for (Slot slot : slots.values()) {
      if (slot.trainer() instanceof Player)
        continue;

      Slot randomSlot;
      do {
        Slot[] allSlots = slots.values().toArray(new Slot[slots.values().size()]);
        randomSlot = allSlots[(int) (Math.random() * allSlots.length)];
      } while (slot.equals(randomSlot));

      int randomMoveIndex = (int) ((Math.random()) * slot.leader().moveCount());
      Move randomMove = slot.leader().move(randomMoveIndex);

      addTurn(new AttackTurn(this, slot, randomSlot, randomMove));
    }
  }

  private void verifyTeamCount() {
    int curTeam = -1;
    boolean onlyOneTeamLeft = true;

    for (Slot s : this) {
      if (curTeam == -1)
        curTeam = s.team();
      else if (curTeam != s.team()) {
        onlyOneTeamLeft = false;
        break;
      }
    }

    JSONObject json = new JSONObject();
    try {
      json.put("action", "battle");
      json.put("visible", false);
    }
    catch (JSONException e) {
    }

    if (onlyOneTeamLeft) {
      while (!slots.isEmpty()) {
        String slotKey = (String) slots.keySet().toArray()[0];
        Slot slot = slots.remove(slotKey);

        if (slot.trainer() instanceof Player) {
          Player p = (Player) slot.trainer();
          PlayerManager.pushJson(p, json);
          PlayerManager.popActivity(p, this);
        }
      }
    }
  }

  private void applyEndOfRoundEffects() {
    for (Slot slot : this) {
      // Condition effects
      for (Iterator<ConditionEffect> conditionEffectIterator = slot.leader().getConditionEffects().iterator(); conditionEffectIterator.hasNext();) {
        ConditionEffect conditionEffect = conditionEffectIterator.next();

        if (Math.random() <= conditionEffect.persistanceChance()) {
          log(slot.leader().name() + conditionEffect.getPersistanceMessage());

          if (conditionEffect.damagePercentage() > 0) {
            int damage = (int) (slot.leader().maxHealth() * conditionEffect.damagePercentage());
            slot.leader().takeDamage(damage);
            log(slot.leader().name() + " took " + damage + " damage!");
          }
        }
        else {
          log(slot.leader().name() + conditionEffect.getDissipationMessage());
          conditionEffectIterator.remove();
        }
      }

      // Slot effects
      slot.applySlotEffects();
    }
  }

  private void addTrainerToPlayerHistory(String id) {
    Player p;

    for (Slot s : this) {
      if (!(s.trainer() instanceof Player))
        continue;

      p = (Player) s.trainer();

      // If the trainer is already recorded, IllegalArgumentException will fire
      p.record().putTrainer(id);
    }
  }

  private JSONObject generateJson() {
    JSONObject json = new JSONObject();

    try {
      json.put("action", "battle");
      json.put("visible", true);

      Map<Integer, JSONArray> teams = new HashMap<Integer, JSONArray>();
      for (Slot slot : this) {
        if (teams.get(slot.team()) == null) {
          teams.put(slot.team(), new JSONArray());
        }

        JSONObject opponent = new JSONObject();
        opponent.put("id", slot.trainer().id());
        opponent.put("turn", turns.get(slot.trainer().id()) != null ? "ready" : "waiting");
        opponent.put("pokemonName", slot.leader().name());
        opponent.put("pokemonLevel", slot.leader().level());
        opponent.put("pokemonNumber", slot.leader().number());
        opponent.put("pokemonHealth", slot.leader().health());
        opponent.put("pokemonMaxHealth", slot.leader().maxHealth());

        JSONArray conditionArray = new JSONArray();
        for (ConditionEffect conditionEffect : slot.leader().getConditionEffects()) {
          conditionArray.put(conditionEffect.name());
        }
        opponent.put("pokemonCondition", conditionArray);

        teams.get(slot.team()).put(opponent);
      }

      json.put("teams", new JSONArray(teams.values()));
    }
    catch (JSONException e) {
    }

    return json;
  }

  public static int computeDamage(Pokemon user, Move move, Pokemon victim) {
    //@preformat
    double damage = 1.0,
           L = user.level(),
           A = 1.0,
           P = move.power(),
           D = 0,
           E = computeEffectiveness(move, user, victim),
           R = Math.random() * .15 + .85,
           reps = move.reps(); // repetitions
    //@format

    if (move.style() == MoveStyle.SPECIAL) {
      A = user.specattack();
      D = victim.specdefense();
    }
    else if (move.style() == MoveStyle.PHYSICAL) {
      A = user.attack();
      D = victim.defense();
    }
    else if (move.style() == MoveStyle.OHKO) {
      A = 10000000;
      D = 1;
    }
    else if (move.style() == MoveStyle.DELAYNEXT || move.style() == MoveStyle.DELAYBEFORE) {
      A = Math.max(user.attack(), user.specattack());
      D = Math.max(victim.defense(), victim.specdefense());
    }

    damage = (((2.0 * L / 5.0 + 2.0) * A * P / D) / 50.0 + 2.0) * E * R * reps;

    if (damage < 1 && E != 0)
      damage = 1;

    return (int) damage;
  }

  /**
   * Calculates the confused damage a Pokemon does to itself.
   *
   * @param p Pokemon to calculate for
   * @return Damage done
   */
  public static int confusedDamage(Pokemon p) {
    // For more info, see computeDamage
    //@preformat
    double L = p.level(),
           A = p.attack(),
           P = 40,
           D = p.defense(),
           STAB = 1,
           E = 1,
           R = 1.00;
    //@format

    return (int) ((((2.0 * L / 5.0 + 2.0) * A * P / D) / 50.0 + 2.0) * STAB * E * R);
  }

  /**
   * Calculates effectiveness modifications for a Move from a user to a victim.
   * Includes Same-Type-Attack-Bonus for user and {@link Type} modifications
   * between the move and victim.
   *
   * @param move Move to calculate with
   * @param user Pokemon using the move
   * @param victim Pokemon getting hit by the move
   * @return A modifier for the power of the move with respect to Types
   */
  private static double computeEffectiveness(Move move, Pokemon user, Pokemon victim) {
    double answer = 1.0;

    if (move.type() == user.type1() || move.type() == user.type2()) {
      answer *= stab;
    }
    if (victim.type1() != null) {
      switch (move.type().effectiveness(victim.type1())) {
      case SUPER:
        answer *= typeadvantage;
      break;
      case NORMAL:
        answer *= 1;
      break;
      case NOT_VERY:
        answer *= typedisadvantage;
      break;
      case IMMUNE:
        answer *= 0;
      break;
      }
    }
    if (victim.type2() != null) {
      switch (move.type().effectiveness(victim.type1())) {
      case SUPER:
        answer *= typeadvantage;
      break;
      case NORMAL:
        answer *= 1;
      break;
      case NOT_VERY:
        answer *= typedisadvantage;
      break;
      case IMMUNE:
        answer *= 0;
      break;
      }
    }

    return answer;
  }
}
TOP

Related Classes of org.jpokemon.battle.Battle

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.