package model;
import java.util.ArrayList;
import java.util.HashMap;
import controller.Attack;
import controller.Command;
import controller.Move;
public abstract class Character {
private int health; //Maximum Character's health.
private int attack;
private int move; //the move range of a character in one turn;
private int attackRange;//attack distance, special type like mage and archer can do distant attack
private String name; //every character has a name;
private String type; //character's type ,like mage, warrior, lorde;
private ArrayList<Item> inventory; //Items
private int currentHealth; //Character current Health, currentHealth <= health;
private boolean alive; //This is for determine whether this character is alive
private Character target; //target is for the character who accepted the command such as heal, attack, etc.
private int pX, pY;
private int moveToX, moveToY;
//Character's Coordinate.
private HashMap<String, Command> commands = new HashMap<>();//Every character have it's command set. String is command name,
//when player choice a command this is for find command to execute
private boolean ifActioned; // record whether this character has completed his action in this turn;
public Character(String name, String type, int health, int attack, int move) {
this.name = name;
this.type = type;
this.health = health;
this.attack = attack;
this.move = move;
this.attackRange = 1;
inventory = new ArrayList<Item>();
currentHealth = health;
alive = true;
/*When player choice a specific command just pass the
* command name as message then, and when execute this
* command just like this: command.execute(Character caller, Character target) */
commands.put("Moving", new Move());
commands.put("Attacking", new Attack());//Those two commands can be use for all characters.
//commands.put("Healing", new Healing()); //Those commands only for Player's characters.
//commands.put("Waiting", new Wait());
//commands.put("Trading", new Trade());
//commands.put("UsingItem", new UseItem(item));//This should be several Items. So it should write
//like this: commands.put("Boots", new UseItem(boots));
// commands.put("Elixir", new UseItem(elixir));
/////////////////////////////////// I think commands should in Game or Map Class, that will easy manage,
/////////////////////////////////// and Move command is different, because it need Coordinate.
this.ifActioned = false;
}
public Character(String name, String type, int health, int attack, int move, int attackRange) {
this(name, type, health, attack, move);
this.attackRange = attackRange;
}
/*public void setType(String type){
this.type = type;
}*/
//health should be the upper bound of curentHealth.
public void setHealth(int value) {
if (currentHealth+value <= health)
currentHealth += value;
else
currentHealth = Integer.valueOf(health);
}
public void setAttack(int value) {
attack += value;
}
public void setMove(int value) {
move += value;
}
public int getHealth() {
return health;
}
public int getAttack() {
return attack;
}
public int getMove() {
return move;
}
public void addItem(Item newItem) {
inventory.add(newItem);
}
public void useItem(int index) {
inventory.get(index).useItem(this);
inventory.remove(index);
}
public Item findItem(int index){
Item itemToBeUsed = inventory.get(index);
inventory.remove(index);
return itemToBeUsed;
}
public String inventoryToString() {
String myString = "";
for(Item currItem: inventory) {
myString += currItem.getName() + " ";
}
return myString;
}
public String getName(){
return name;
}
public String getType(){
return type;
}
public int getCurrentHealth(){
return currentHealth;
}
public int getAttackRange(){
return attackRange;
}
public boolean ifAlive(){
if (currentHealth <= 0)
alive = false;
return alive;
}
/////////////////////////////////////////////////
public void attack(){
target.setCurrentHealth(target.getCurrentHealth()-this.attack);
}
/*This is easy to use no need to know what command have been
* executed and even we can add more commands to upgrade.
* Don't forget when extend this class, we need add some new
* command to HashMap<String, Command> commands*/
public void getMessageAndExecute(String commandName){
if(commandName.equals("Moving")){
((Move)commands.get(commandName)).moveTo(moveToX, moveToY);
}else{
commands.get(commandName).execute(this, target); //When use move command, the target is this character itself.
}
}
public void setTarget(Character target){
this.target = target;
}
public Character getTarget(){
return target;
}
public String statusToString(){
String status = "";
status += "Name: " + name + "\n";
status += "Type: " + type + "\n";
status += "Health: " + currentHealth + "/" + health + "\n";
status += "Attack: " + attack + "\n";
status += "Move: " + move + "\n";
status += "Inventory: " + inventoryToString() + "\n";
return status;
}
public void setPosition(int x, int y){
pX = x;
pY = y;
}
public void setCurrentHealth(int currentHealth){
if(currentHealth <= health)
this.currentHealth = currentHealth;
else
this.currentHealth = health;
}
public int getPositionX(){
return pX;
}
public int getPositionY(){
return pY;
}
//all subclass but Archer will use this function, cause archer can only attack target in distance;
public boolean isTargetInAttackRange(){
int distance = Math.abs(pX - target.getPositionX()) + Math.abs(pY - target.getPositionY());
if(distance <= attackRange)
return true;
return false;
}
public boolean isInMoveRange(int x, int y){
int distance = Math.abs(pX - x) + Math.abs(pY - y);
if(distance <= move)
return true;
return false;
}
//check if destination is in moving range, if yes, move to there
/*public void move(int x, int y){
this.setPosition(x, y);
}*/
public void setMoveTo(int x, int y){
moveToX = x;
moveToY = y;
}
public boolean isInTradeRange(){
int distance = Math.abs(pX - target.getPositionX()) + Math.abs(pY - target.getPositionY());
if(distance == 1)
return true;
return false;
}
/*public void tradeTo(int i){
Item item = inventory.get(i);
target.addItem(item);
inventory.remove(i);
}*/
public void setActioned(boolean x){
this.ifActioned = x;
}
public boolean ifActioned(){
return ifActioned;
}
}