import processing.core.*; 
import processing.data.*; 
import processing.event.*; 
import processing.opengl.*; 

import com.codedisaster.steamworks.*; 
import ddf.minim.spi.*; 
import ddf.minim.signals.*; 
import ddf.minim.*; 
import ddf.minim.analysis.*; 
import ddf.minim.ugens.*; 
import ddf.minim.effects.*; 

import java.util.HashMap; 
import java.util.ArrayList; 
import java.io.File; 
import java.io.BufferedReader; 
import java.io.PrintWriter; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.IOException; 

public class crown_and_council_B3 extends PApplet {











  


/*   ---------::::DDD>>>>   Crown & Council
                            by Henrik 'carnalizer' Pettersson, (c)2016 Mojang
*/                  
                            



Minim minim;
AudioPlayer fail1,gold1,gold2,battle1,fort1,castle1,fleet1,trade1,plague1,rebellion1,song,nogo;
//SoundFile fail1,gold1,gold2,battle1,fort1,castle1,fleet1,trade1,plague1,rebellion1;



// GAME STATES *****************
final int STATE_SPLASH= 0;
final int STATE_MENU = 1;
final int STATE_GAME = 2;
final int STATE_GENERATOR = 3;
final int STATE_GAMEOVER = 4;
final int STATE_MAPSTART = 5;
final int STATE_GAMEWON = 6;

int gameState = STATE_SPLASH; 
//int gameState = STATE_GENERATOR;
int gameStateOld = gameState;
final int ACTION_ARMY=0;
final int ACTION_FORT=1;
final int ACTION_CASTLE=2;
final int ACTION_FLEET=3;
final int ACTION_TRADE=4;

Boolean cheat=false;
String cheatCode="";

int level=0;
IntList levelSeeds = new IntList();
float selectableSine=0,pauseTimer,screenShake;

boolean saved=true, playMusic=true;
int musicAt=0;
PImage splash,gui_bg,bg,worldMap,water,miniMap,glow,upgrade_pane,info_pane,player_pane,player_pane_colorplate,player_pane_current,multiSpriteMap,portrait1,portrait2,portrait3,portrait4;

String outMessage="Go!";
String currentMousePressedArea;
boolean noMouseOver = true;
int playerCount=0;
boolean runOnce=true;
boolean runGenerator=true;
boolean autoRun=false;
int iterations =0;
int plugCount=0;
boolean loadMap=true,gameOn=true,waitForClick=true;
int playerTurn,noPlayers,humanPlayers,gameTurn;
ArrayList anims;
ArrayList popMessages;
float aiDelay,aiSpeed;
Button upgradeArmyButton;
Button upgradeFortButton;
Button upgradeTradeButton;
Button upgradeFleetButton;  
TextButton endTurnButton;  

  
  
// GAME WORLD ******************
int[] genLimits = {50,400,550};
PFont font;
int margin=27;
int genAreas;
int gridWidth =9, gridHeight = 9;
int scrWidth = 1024, scrHeight = 768;
int scaledScrWidth = 256, scaledScrHeight = 192;
ArrayList<Area> areas;
ArrayList<Player> players;
int _livingPlayers;
char[][] readmap;
boolean RMB,debug;
float myScale=4;
int baseIncome = 2;
PImage action_army,action_castle,action_fort,action_fleet,action_trade,
       action_army2,action_fort2,action_fleet2,action_trade2,action_uni,
       price_tag,action_selected,warning,
       upgrade_fort,upgrade_castle,upgrade_mine,upgrade_city,upgrade_uni,
       upgrade_fort2,upgrade_city2,
       end_turn,dead,plague,rebellion,ruta1,ruta2,button,blackImg,whiteImg;
float tickerTimer=millis();
float tickerPos=scrWidth*1.35f;
String tickerText = "Mojang 2016 all the rights reserved, yo!    ***    Game idea, design, art, code (even the AI!), and sound by HENRIK PETTERSSON, @carnalizer    ***    Made with Processing (processing.org) + Minim library. Music by jukedeck.com. SFX made in SFXR.   ***    Many thanks to Aron, Botteu, Dragonene, Jon, Kappische, Kinten, Notch, Samuel, TheWreck, Tommaso and all of Mojang for being awesome!";
String log="";

int tauntIndex;

String[] taunt = {  "YOU ARE WEAK!",
                    "SURRENDER NOW, AND WE'LL SPARE YOU FAMILY.",
                    "YOUR FACE IS A BATTLEFIELD!",
                    "WAR, WHAT IS IT GOOD FOR? GOLD! SWEET SWEET GOLD!",
                    "DIE DIE DIE DIE DIE",
                    "SHOW ME YOUR ARMY, I'LL SHOW YOU MINE.",
                    "TO SECURE PEACE IS TO PREPARE FOR WAR.",
                    "YO MOMA SO FAT YOU NEED TO EXPAND YOUR EMPIRE.",
                    "YOUR BLOODLINE LOOKS LIKE A CHILD'S DRAWING.",
                    "YOUR FATHER HAS AN AFFINITY FOR FARM ANIMALS.",
                    "YOU THINK THIS IS A GAME?!",
                    "GO BACK TO THE PIGSTY AND TELL MOM I SAID HI.",
                    "IT'S NEVER TO LATE TO GIVE UP.",
                    "YOU'RE PLAYING IN THE BIG LEAGUE NOW.",
                    "LAUGHING OUT LOUD AT THE THOUGHT OF YOUR ARMY.",
                    "GIVE UP. WE ALL KNOW YOU DON'T STAND A CHANCE.",
                    "A KING CAN BE LUNY, BUT THERE ARE LIMITS.",
                  };
String[] tipOfTheDay = {  "AREAS WITH MANY NEIGHBORS\n CAN BE HARDER TO DEFEND.",
                          "TRY TO ISOLATE A FEW AREAS\n AND BLOCK THEM OFF WITH FORTS.",
                          "NEVER USE MORE SHIPS THAN NECESSARY.\n ONCE YOU'RE IN, USE ARMY.",
                          "CHOOSE UPGRADES WITH CARE.",
                          "A NEWLY CONQUERED AREA\n WON'T GIVE YOU INCOME.",
                          "MAYBE YOU CAN USE SHIPS\n TO BYPASS A FORT.",
                          "THE MORE YOU ATTACK AN OPPONENT,\n THE MORE HOSTILE HE'LL BE.",
                          "OPPONENTS WILL GENERALLY ATTACK A\n NEUTRAL AREA BEFORE ONE OF YOURS.",
                          "'M' TOGGLES MUSIC ON/OFF.",
                          "'R' WILL RESTART THE MAP.",
                          "'K' AUTO-PLAYS THE\n REST OF THE MAP.",
                          "'SPACE' ENDS YOUR TURN.",
                          "'G' WILL GENERATE A\n COMPLETELY NEW MAP!",
                          "KEYS 1-4 WILL SET THE NUMBER OF\nHUMAN PLAYERS.",
                          "THERE ARE 75 MAPS, AND YOU CAN\nGENERATE AS MANY AS YOU LIKE!",
                          "RIGHT CLICK WHEN ATTACKING WILL\nATTACK UNTIL YOU WIN OR\nYOU'RE OUT OF FUNDS."
                  };
String currentTip="";

String[] tauntPart1 = { "FACE", "ARMY", "CASTLE", "MOM", "DAD", "FAMILY", "LAND", "KEEP", "BODY", "CROWN", "BRAIN", "RULE", "EMPIRE", "HOME", "BED", "QUEEN", "EFFORT", "WEALTH", "SHIRT"};
String[] tauntPart2 = { "A DWARF", "A WORM", "AN INBRED", "A LUNATIC", "A COW", "A DOG", "A DUNGHEAP", "A DONKEY", "A JESTER", "A DUNCE", "A FARMER", "AN IDIOT", "A LUNATIC", "AN INBRED", "A LIZARD", "A FROG", "A MAGPIE", "A SNAKE", "AN OUTCAST", "A FISH"};
String[] tauntPart3 = { "ASS", "BEHIND", "TURD", "ROTTEN CORPSE", "PISS POT", "BED", "MOM", "OFFSPRING", "JUNK", "OUTHOUSE", "VOMIT", "WART", "PET", "BROTHER", "FOUL ODOR", "FART", "CURSE", "FAILURE", "DISAPPOINTMENT", "ERROR", "BURP", "HORSE", "INSULT"};
String currentTaunt="";

String[] name1 = { "Mar", "Ice", "Wood", "Grey", "Red", "God", "Way", "May", "Hay", "Hy", "In", "Cor", "Slo", "Em", "Man", 
                   "Aber", "Act", "Glan", "Exe", "Usk", "Lund", "Ork", "Bal", "Hol", "Rose", "Blen", "Brad", "Ayle", "Dew",
                   "Grim", "Ten", "Whit", "Cros", "Kirk", "Rug", "Kin", "Caer", "Dal", "Aire", "Croy", "Drum", "Roms", "Horn",
                   "Holm", "Fang", "High", "Low", "Mid", "Gil", "Ruth", "Guth", "Hy", "Wool", "Old", "News", "Hem", "Howe",
                   "King", "Bi", "Bul", "Dark", "Un", "Zu", "Be", "Neu", "Stone", "Bird", "Dog", "Fish", "Nook", "Cart", 
                   "Lar", "Lip", "Hand", "Cat", "Hat", "Gro", "Buck", "Oak", "Carn", "Arn"};
String[] name2 = { "vik", "nom", "mire", "wain", "ick", "ly", "fly", "bir", "bri", "lay", "song", "grass", "stay", "home", 
                   "road", "nock", "bro", "ie", "new", "rock", "path", "moor", "brey", "prey", "hand", "gobb", "vain", "ling",
                   "farm", "hope", "nock", "glen", "ham", "gate", "foss", "ford", "hain", "sop", "ley", "moss", "wall", "wich",
                   "ster", "kirk", "law", "shaw", "pool", "stow", "bury", "ness", "ton", "head", "toft", "va", "ar", "reath", 
                   "say", "key", "ring", "elk", "mund", "vim", "clo", "gut", "har", "weed" };


public void setup(){
  
  
  surface.setResizable(true);
  surface.setSize(scrWidth, scrHeight);
  minim = new Minim(this);
  font = loadFont("BMminiA8-8.vlw");
  textFont(font, 8);
  textAlign(CENTER);
  
  if (!SteamAPI.init("lib\\steamworks4jnatives.jar")) {
      // report error
    println("steamerror!");
    log=System.getProperty("user.dir");
  }
    println("user dir: " + System.getProperty("user.dir"));
  
  loadSound();
  water=createImage(scaledScrWidth,scaledScrHeight,RGB);
  for(int i=0;i<water.pixels.length;i++){
   water.pixels[i] = color(30, 60, 110); 
  } 
  loadImages();

  humanPlayers=1;
  gameSetup();
}

public void gameSetup(){
  upgradeArmyButton = new Button(PApplet.parseInt(scaledScrWidth*0.55f),scaledScrHeight-action_army.height,action_army,STATE_GAME);
  upgradeFortButton = new Button(PApplet.parseInt(scaledScrWidth*0.60f),scaledScrHeight-action_fort.height,action_fort,STATE_GAME);
  upgradeTradeButton = new Button(PApplet.parseInt(scaledScrWidth*0.75f),scaledScrHeight-action_trade.height,action_trade,STATE_GAME);
  upgradeFleetButton = new Button(PApplet.parseInt(scaledScrWidth*0.75f),scaledScrHeight-action_fleet.height,action_fleet,STATE_GAME);
  endTurnButton = new TextButton("DONE",PApplet.parseInt(scaledScrWidth-button.width),scaledScrHeight-button.height,button,0);
  
  //endTurnButton = new TextButton("DONE",0,0,button,0);
  
  screenShake=0;
  water=createImage(scaledScrWidth,scaledScrHeight,RGB);
  for(int i=0;i<water.pixels.length;i++){
   water.pixels[i] = color(30, 60, 110); 
  } 
  loadImages();
  waitForClick=true;
  anims = new ArrayList();
  popMessages = new ArrayList();
  //humanPlayers=1;
  playerTurn=1;
  tauntIndex=PApplet.parseInt(random(taunt.length *2));
  
  currentTaunt = (tauntIndex < taunt.length) ? taunt[tauntIndex] : getRandomTaunt() ;
  currentTip = tipOfTheDay[PApplet.parseInt(random(tipOfTheDay.length))];
  //for(int i =0 ; i< 10;i++) println(getRandomTaunt());
  if(gameState!=STATE_SPLASH){gameState=STATE_GENERATOR;}
  genAreas = 10+PApplet.parseInt(random(gridWidth*gridHeight*0.5f+3));
  runOnce=true;
  runGenerator=true;
  plugCount=0;
  iterations=0;
  worldMap=createImage(scaledScrWidth,scaledScrHeight,RGB);
  miniMap=createImage(gridWidth,gridHeight,RGB);
  currentMousePressedArea = "";
  noMouseOver = true;
  areas = new ArrayList<Area>();
  players = new ArrayList<Player>();
  playerCount=0;
  noPlayers=4;
  selectableSine=0;
  aiSpeed=600;
  
  loadLevels();
  if(level>75) level=76;
  randomSeed(levelSeeds.get(level));
  loadMap();
  gameTurn=1;
  gameOn=true;
  checkMusic();
}
public void AI_turn(){
  
  Player _AI = currentPlayer();
  while(_AI.hasUpgrade()){
    int _try = constrain(PApplet.parseInt(random(level)),0,4);
    if(!_AI.actions.get(_try).upgraded){
      _AI.actions.get(_try).upgraded=true;
      _AI.research=0;
    }
  }
  
   for(int i=0;i<_AI.aiDiplomacy.length;i++){
     if(_AI.aiDiplomacy[i] > 0.9f){_AI.aiDiplomacy[i] -= _AI.aiDiplomacy[i]*0.05f;}
   }
  
  if (_AI.gold<1 || _AI.isAlive==false){return;}
  float[] _evals = new float[5*areas.size()];
  for(int _action=0;_action<constrain(level,1,5);_action++){
    Action _a = _AI.actions.get(_action);
    for(int _testArea=0;_testArea<areas.size();_testArea++){
      //println("TEsting action",_action,"on area",_testArea);
      int _index =_action*areas.size() + _testArea;
      _evals[_index]=0;
      if (_AI.gold<_a.cost){
         // cannot afford action.
        continue;
      }
      switch(_action){
        case 0:
            selectableAreas(_action);
            //println("  ------------------",evalAttack(_testArea));
            _evals[_index]=evalAttack(_testArea);
        break;
        case 1:
            selectableAreas(_action);
            _evals[_index]=evalFort(_testArea);
        break;
        case 2:
            selectableAreas(_action);
            _evals[_index]=evalArmada(_testArea);
        break;
        case 3:
          selectableAreas(_action);
          _evals[_index]=evalVillage(_testArea);
        break;
        case 4:
          selectableAreas(_action);
          _evals[_index]=evalUni(_testArea);
        break;
        default:
        break;
      }
    }
  }
  int _bestEval=0;
  for(int _i=0;_i<_evals.length;_i++){
    if( _evals[_i] > _evals[_bestEval]){
      _bestEval=_i;
      //print("^--");
    }
      //println(_i, _i % areas.size(), _evals[_i]);
  }
  if (_evals[_bestEval]==0){
    iterations=0;
    endTurn();
  }
  //println("best:",_bestEval);
  int _tryAction = PApplet.parseInt(_bestEval/areas.size());
  int _tryArea = _bestEval % areas.size();
  Area _area = areas.get(_tryArea);
  
  //println("FIND ACTION:",_tryAction, "and APPLY ON", _tryArea,"with name",_area.name);

  unselectActions();
  selectableAreas(_tryAction); 
  Action _a= _AI.actions.get(_tryAction);
  _a.selected=true;

  areaClicked(_area.name);
}

public float evalAttack(int _testArea){
  Area _area = areas.get(_testArea);
  Player _AI = currentPlayer();
  float _score=0;
  if( _area.selectable ){_score=1 + random(0.1f);}
  _score *= (1 + (_area.income*0.09f));
  if(_AI.dominance > 0.53f){_score *= 1.8f;}
  if(_area.fort){_score *= 0.6f;}
  //if(_area.castle){_score *= 0.35;}
  if(_area.city){_score *= 1.3f;}
  if(_area.mine){_score *= 1.3f;}
  if(_area.ownedBy==0){
    _score *= 1.2f;
  }else{
    _score *= _AI.aiDiplomacy[_area.ownedBy-1];
  } 
  if(_area.ownedBy>0){
    Player _owner = players.get(_area.ownedBy-1);
    _score *= (0.5f + (level * 0.01f) + _owner.dominance);
  }
  _score *= (1-(_area.neighbors.size()*0.05f));
  
  _score *= _AI.aiPreference[0];
  return _score;
}

public float evalFort(int _testArea){
  Area _area = areas.get(_testArea);
  Player _AI = currentPlayer();
  float _score=0;
  if( _area.selectable ){_score=0.9f + random(0.18f);}
  if(_area.chokePoint){_score *= 1.9f;}
  _score *= (1 + (_area.income*0.3f));
  _score *= (_area.mine) ? 1.3f : 1 ;
  //_score *= ((_area.neighbors.size()*0.1));
  _score *= (_area.city) ? 0.2f : 1 ;
  _score *= (0.6f + _area.contested * 0.10f);
  if(_AI.dominance > 0.6f){_score *= 0.6f;}
  if(_area.uni){_score=0;}
  _score *= _AI.aiPreference[1];
  return _score;
}

public float evalArmada(int _testArea){
  Area _area = areas.get(_testArea);
  Player _AI = currentPlayer();
  float _score=0;
  if( _area.selectable ){_score=0.5f + random(0.1f);}
  _score *= (1 + (_area.income*0.1f));
  if(_area.fort){_score *= 0.6f;}
  //if(_area.castle){_score *= 0.3;}
  if(_area.ownedBy==0){_score *= (1.25f + (level * 0.01f));} // this should be depending on diplomacy factors not yet implemented.
  _score *= (1-(_area.neighbors.size()*0.1f));
  if(_area.mine){_score *= 1.1f;}
  if(_AI.dominance > 0.6f){_score *= 1.2f;}
  
  _score *= _AI.aiPreference[3];
  return _score;
}

public float evalVillage(int _testArea){
  Area _area = areas.get(_testArea);
  Player _AI = currentPlayer();
  float _score=0;
  if( _area.selectable ){_score=1 + random(-0.4f,0.3f);}
  float _ns = 1;
  for(int i=0;i<_area.neighbors.size();i++){
    Area _a = areas.get(_area.neighbors.get(i));
    if(_a.ownedBy != playerTurn){_ns -= 0.35f;}
  }
  _score *= _ns;
  if (_area.fort){_score *= 0.7f;}
  _score *= (1.2f-(_area.neighbors.size()*0.1f));
  if(_area.mine){_score *= 0.4f;}
  float _c = _area.contested * -0.1f;
  
  _score *= 1 + constrain(_c,-100,0.2f);
  _score *= _AI.aiPreference[4];
  
  if(_area.uni){_score=0;}
  
  return _score;
}

public float evalUni(int _testArea){
  Area _area = areas.get(_testArea);
  Player _AI = currentPlayer();
  float _score=0;
  if( _area.selectable && countUnis(_AI) <= _AI.maxUni){_score=1 + random(-0.4f,0.3f);}
  _score*=_AI.uniFondness;
  
  return _score;
}

public void adjustDiplomacy(int _defender){
  if(_defender>0){
    Player _p = players.get(_defender-1);
    _p.aiDiplomacy[playerTurn-1] += 0.08f;
  }
}

class Action {
  PImage pic,pic2;
  int type;
  int cost;
  int invItem;
  int x1,y1,x2,y2;
  boolean mouseOver,selected,upgraded;
  String info;
  
  static final int ACTION_ARMY = 0;
  static final int ACTION_FORT = 1;
  static final int ACTION_FLEET = 2;
  static final int ACTION_TRADE = 3;
  static final int ACTION_UNIVERSITY = 4;

  Action(int _type){
    type=_type;
    mouseOver=false;
    upgraded=false;
    switch (type){
      
      case ACTION_ARMY : // 
        pic=action_army;
        pic2=action_army2;
        cost=1;
        info="Army: Attack an adjacent area.";
      break;
      case ACTION_FORT : // 
        pic=action_fort;
        pic2=action_fort2;
        cost=3;
        info="Fort: Increase defense.";
      break;
      case ACTION_FLEET : // 
        pic=action_fleet;
        pic2=action_fleet2;
        cost=4;
        info="Fleet: Attack any area.";
      break;
      case ACTION_TRADE : // 
        pic=action_trade;
        pic2=action_trade2;
        cost=2;
        info="Village: Increase income.";
      break;
      case ACTION_UNIVERSITY : 
        pic=action_uni;
        
        pic2=action_uni;
        cost=6;
        info="University: Generates research points for upgrades.";
      break;
      default : // 
      break;
    }
 
  }
  
  public void update( int _invItem, boolean canPressAction){
    invItem=_invItem;
    x1=0;
    y1=scaledScrHeight - (2 + invItem) * pic.height;
    x2=x1+pic.width;
    y2=y1+pic.height; 
    mouseOver=false;
    if(canPressAction && mouseX*0.25f>x1 && mouseX*0.25f<x2*2 && mouseY*0.25f > y1 && mouseY*0.25f < y2){
        mouseOver=true;
    }
    if(mouseOver){
      //noMouseOver = false;
      printInfo(info + "               Cost: "+cost);
      if(mousePressed){
        tint(120,110,110);
        unselectActions();
        selected=true;
        //Todo: show applicable areas
        selectableAreas(type);
        
      }else{
        
        tint(tintByOwner(0));
        tint(255,255,255,220);
        // text description to infopane
      }
    }
    Player _p = currentPlayer();
    if(_p.gold<cost){
      tint(150,90,75,220);
    }
    if(!upgraded){
      image(pic,x1,y1);
    }else{
      image(pic2,x1,y1);
    }
    image(price_tag,x1+pic.width,y1);
    if(selected){
      image(action_selected,x1,y1);
      //printInfo(info);
    }
    scale(0.5f);
   fill(60,50,20);
   text(cost,(1+x1+pic.width*1.5f)*2,(11 + y1)*2);
   text(cost,(x1+pic.width*1.5f)*2,(11 + y1)*2);
   fill(230,190,100);
   if(_p.gold<cost){
      fill(150,100,90,220);
    }
   text(cost,(x1+pic.width*1.5f)*2,(10 + y1)*2);
   
   scale(2);
  noTint();
  }
  //TODO: Display and make clickable.
  // Proper actions depending on type of action.
}

class Area { 
  String name;
  int x1,y1,x2,y2;
  PImage pic;
  PImage mouseOverPic;
  int areaColor;
  boolean mouseOver;
  int namestring;
  int ownedBy;
  int id;
  int income;
  IntList neighbors = new IntList();
  boolean selectable,fort,mine,city,uni;
  int contested,invadedBy;
  boolean chokePoint;
  
  
  Area (int _x1,int _y1,int _x2,int _y2,PImage _im, PImage _moim, int _c, int _id) { 
    // init instance
    id=_id; // place in areas arrayList on creation.
    x1=_x1; // bounds
    y1=_y1;
    x2=_x2;
    y2=_y2;
    
    fort=(random(1)<0.04f) ? true : false;
    //castle=false;
    uni= (random(1)<0.05f && fort ==false && level>7) ? true : false;
    mine= (random(1)<0.05f && fort ==false && !uni && level>7) ? true : false;
    city= (random(1)<0.04f && fort ==false && mine ==false && !uni && level>2) ? true : false;
    namestring =PApplet.parseInt( random(name1.length));
    name=name1[constrain(namestring,0,name1.length-1)];
    namestring =PApplet.parseInt( random(name2.length) );
    name=name + name2[constrain(namestring,0,name2.length-1)];
    invadedBy=0;
    
    pic=_im;
    pic.mask(_moim);
    mouseOverPic = _moim;
    mouseOverPic.mask(_moim);
    areaColor=_c;
    mouseOver=false;
    selectable = false;    
  } 

  public void drawUpgrades() { // castles, forts...
    int _adj=0;
    int _yAdj=-6;
    if(mine){
      _adj = (fort || city || uni) ? 2:-3;
    }
    if(uni){
      _adj = (fort || city || mine) ? 2:-3;
    }
    if(fort){
      Boolean _upg=false;
      if(ownedBy>0){
        if(players.get(ownedBy-1).isActionUpgraded(1)){_upg=true;}
      }
      if(_upg){
        image(upgrade_fort2,x1-_adj-2+(pic.width*0.35f),y1+(pic.height*0.35f)+_yAdj);
      }else{
        image(upgrade_fort,x1-_adj-2+(pic.width*0.35f),y1+(pic.height*0.35f)+_yAdj);
      }
    }
    if(city){
      Boolean _upg=false;
      if(ownedBy>0){
        if(players.get(ownedBy-1).isActionUpgraded(3)){_upg=true;}
      }
      if(_upg){
        image(upgrade_city2,x1-_adj-2+(pic.width*0.35f),y1+(pic.height*0.35f)+_yAdj);
      }else{
        image(upgrade_city,x1-_adj-2+(pic.width*0.35f),y1+(pic.height*0.35f+_yAdj));
      }
    }
    if(mine){
      image(upgrade_mine,x1+_adj-2+(pic.width*0.35f),y1+(pic.height*0.35f+_yAdj));
    }
    if(uni){
      image(upgrade_uni,x1+_adj-2+(pic.width*0.35f),y1+(pic.height*0.35f+_yAdj));
    }
    if (uni && city) println("Error: Has");
  }
  public void drawArea(boolean canShowMouseOver) { // game tick update
  calcIncome();
    mouseOver=false;
    if(canShowMouseOver && mouseX*0.25f>x1 && mouseX*0.25f<x2 && mouseY*0.25f > y1 && mouseY*0.25f < y2){
      if(pic.get(PApplet.parseInt(mouseX*0.25f-x1),PApplet.parseInt(mouseY*0.25f-y1)) != 0){//mouse over!!
        mouseOver=true;
      }
    }
    int _lift = (mouseOver) ? -1 : 0 ;
    if(mouseOver){
      tint(0,150);
      image(pic,x1,y1);
      tint(150,150,150);
      image(pic,x1,y1+_lift);
    }
    
    tint(tintByOwner(ownedBy));
    Player _p = currentPlayer();
    //tintByOwner2( playerTurn, color( int(130)*(1+(sin(selectableSine))*0.2) ) )
    if (selectable && _p.isHuman){
      if(ownedBy>0){
        tint( tintByOwner2( ownedBy, color( PApplet.parseInt(130)*(1+(sin(selectableSine))*0.4f) ) ) );
      }else{
        if (selectable && _p.isHuman){tint(PApplet.parseInt(150)*(1+(sin(selectableSine))*0.2f));}
      }
    }
    
    //
    if(mouseOver){
      if(mousePressed){
        tint(60,120,150);
        currentMousePressedArea = name;
      }else{
        printInfo(name+ ". Income: " + income);
        //tint(tintByOwner(ownedBy));
        //tint(255,255,255,220);
        tint( tintByOwner2( ownedBy, color( 190,210,170 ) ) );
      }
    }
    //if(chokePoint){tint(0,0,0);}
    
    image(pic,x1,y1+_lift);
    noTint();
    
  }
  public void drawAreaText(){
    int _inc =income;
    scale(0.5f);
    if(ownedBy>0){
      fill(20,20,10,190);
    }else{
      fill(20,20,10,170);
    }
    
    
    text(name,2+(x1+(x2-x1)*0.5f)*2,5+(y1+(y2-y1)*0.5f)*2);
    text(name,1+(x1+(x2-x1)*0.5f)*2,5+(y1+(y2-y1)*0.5f)*2);
    if(ownedBy>0){
      fill(80+red(tintByOwner(ownedBy)),80+green(tintByOwner(ownedBy)),70+blue(tintByOwner(ownedBy)),210);
    }else{
      fill(150,140,100,220);
    }
    text(name,1+(x1+(x2-x1)*0.5f)*2,4+(y1+(y2-y1)*0.5f)*2);
    scale(2);
    
    if(ownedBy>0){
      fill(30,20,10,220);
    }else{
      fill(10,10,10,180);
    }
    
    text( _inc,2+(x1+(x2-x1)*0.5f),-1+(y1+(y2-y1)*0.5f));
    text( _inc,1+(x1+(x2-x1)*0.5f),-1+(y1+(y2-y1)*0.5f));
    if(ownedBy>0){
      fill(120+red(tintByOwner(ownedBy)),120+green(tintByOwner(ownedBy)),110+blue(tintByOwner(ownedBy)),230);
    }else{
      fill(150,150,130,220);
    }
    
    text( _inc,1+(x1+(x2-x1)*0.5f),-2+(y1+(y2-y1)*0.5f));
  }
  
  public void findNeighbors(){ // find neighbors and add to neighbor IntList
    for(int _ly=y1;_ly<y2+1;_ly++){
      for(int _lx=x1;_lx<x2+1;_lx++){
        int _checkCol=worldMap.get(_lx,_ly);
        if(_checkCol != areaColor && _checkCol != worldMap.get(0,0) && countSurrounding(worldMap, _lx, _ly, areaColor) >0){ // pixel not like this area and not background and is neighboring to this area//. !!!!
          for(int _i=0;_i<areas.size();_i++){ // search all areas for matching color.
            if(areas.get(_i).areaColor == _checkCol){ // found the area!
              boolean _newNeighbor=true;
              for(int u=neighbors.size()-1;u>=0;u--){ // check all neighbors if already listed
                if(neighbors.get(u) == _i){ // this neighbor is in list
                  _newNeighbor = false;
                }
              }
              if(_newNeighbor){
                neighbors.append(_i);
              }
            }
          }
        }
      }
    }
    neighbors.sort();
    for(int u=neighbors.size()-1;u>0;u--){
      //println(name,id, "---------------------------",neighbors.size());
      if(neighbors.get(u) == id){
        //println("---------------------------",neighbors.get(u));
        neighbors.remove(u);
      }
    }
    //println("---------------------------------------",id);
    for(int u=neighbors.size()-1;u>0;u--){
      //println("---------------------------",neighbors.get(u));
      if(u>=1){
        if(neighbors.get(u) == neighbors.get(u-1)){
          neighbors.remove(u);
        }
      }
    }
    calcIncome();
   
  }
  public void calcIncome(){
   income= 1;
   income = (income<0) ? 0 : income;
   if(city){
     income++;
      if(ownedBy>0 && players.get(ownedBy-1).isActionUpgraded(3)){
        income++;
      }
    }
  }
  public void findChokePoints(){
    chokePoint = false;
    //println(name,"-",id);
    //println(name + "'s (" + id +") neighbors ("+neighbors.size()+") are: ");
    if(neighbors.size()>1){
      chokePoint = true;
      int chokepointDisprovalPoints = 0;
      for(int _n1=0;_n1<neighbors.size();_n1++){ //Go through all neighbors.
        Area _neighbor1 = areas.get(neighbors.get(_n1));
        //println("    " +_neighbor1.name,"("+_neighbor1.id+"), ");
        for(int _n2=0;_n2<neighbors.size();_n2++){ //Go through all neighbors.
          Area _neighbor2 = areas.get(neighbors.get(_n2));
          //println("compare ",_neighbor1.name+"'s neighbors with:");
          if(_neighbor1.id != _neighbor2.id ){
            //println("listing",_neighbor2.name+"'s neighbor id's");
            for(int _n2list=0;_n2list<_neighbor2.neighbors.size();_n2list++){
              //println("          "+ _neighbor2.neighbors.get(_n2list));
              if(_neighbor2.neighbors.get(_n2list) == _neighbor1.id ) {
                chokepointDisprovalPoints++;
              }
            }
          }
        }
        if(chokepointDisprovalPoints == neighbors.size()) {
          chokePoint = false; 
        }
      }
    }
  }
} 

class Bounds {
  int x1,y1,x2,y2;
  Bounds (int _x1,int _y1,int _x2,int _y2){
    x1=_x1;
    y1=_y1;
    x2=_x2;
    y2=_y2;
    
  }
}
class Button {
  PImage pic;
  int inGameState;
  int x1,y1,x2,y2;
  boolean mouseOver,selected;
  String info;
  
  Button(int _x1,int _y1, PImage _pic, int _state){
    pic = _pic;
    x1=_x1;
    y1=_y1;
    x2=pic.width;
    y2=pic.height;
    inGameState=_state;
  }
  
  public void update(){
    if(gameState!=inGameState) return;
    
    mouseOver=false;
    
    if(mouseX*0.25f > x1 && mouseX*0.25f < x1+x2 && mouseY*0.25f > y1 && mouseY*0.25f < y1+y2){
      mouseOver=true;
    }
    
    if(mouseOver){
      if(mousePressed){
        tint(120,110,110);
        selected=true;
      }else{
        tint(255,255,255,220);
      }
    }
    image(pic,x1,y1);
      
    noTint();
  }
}

class TextButton {
  int x;
  int y;
  PImage btnImage;
  PImage btnImage_Down;
  int id;
  String caption;
  boolean enabled;
  int margin = 2;
  
  TextButton (String caption, int x, int y, PImage btnImage, int id){
    this.x=x;
    this.y=y;
    this.btnImage=btnImage;
    this.id=id;
    this.caption=caption;
    this.enabled=true;
  }
  
  public boolean contains (int xx, int yy){ // i.e. Mouseover
    return (xx > x + margin && xx < x + btnImage.width -margin && yy > y + margin && yy  < y + btnImage.height - margin);
  }
  
  public void render(){
    textAlign(CENTER);    
    if (enabled){
      if ( contains( sMouseX(),sMouseY() ) ){
        if (mousePressed == true) {
          renderPressed();
        } else {
          renderUnpressed();
        }
      } else {
        renderNormal();
      }
    } else {
      renderDisabled();
    }
    fill(255,255);
    tint(255,255);

  }
  
  public void renderNormal(){
    image(btnImage,x,y);
    fill(20,10,10,200);
    text(caption, x + (btnImage.width*0.5f), y + btnImage.height*0.75f);
    fill(200,180,160,255);
    text(caption, x + (btnImage.width*0.5f), y + btnImage.height*0.70f);
  }
  
  public void renderDisabled(){
    image(btnImage,x,y);
    fill(255,100);
    text(caption, x + (btnImage.width*0.5f), y + btnImage.height*0.70f);
    tint(255, 100);
    image(blackImg,x,y,btnImage.width,btnImage.height);    
  }
  
  public void renderPressed(){
    image(btnImage,x,y);
    text(caption, x + (btnImage.width*0.5f), y + btnImage.height*0.74f);
    tint(155, 100);
    image(blackImg,x,y,btnImage.width,btnImage.height);
    text(caption, x + (btnImage.width*0.5f), y + btnImage.height*0.74f);
  }
  
  public void renderUnpressed(){
    image(btnImage,x,y);
    tint(255,255,225, 20);
    image(whiteImg,x,y,btnImage.width,btnImage.height); 
    fill(30,20,20,200);
    text(caption, x + (btnImage.width*0.5f), y + btnImage.height*0.75f);
    fill(250,230,200,255);
    text(caption, x + (btnImage.width*0.5f), y + btnImage.height*0.70f);
  }
  
  public void update(){
  }
}
public void loadSound(){
  fail1 = minim.loadFile("fail1.wav");
  nogo = minim.loadFile("nogo1.wav");
  gold1 = minim.loadFile("gold1.wav");
  
  gold2 = minim.loadFile("gold2.wav");
  battle1 = minim.loadFile("battle1.wav");
  fort1 = minim.loadFile("fort1.wav");
  castle1 = minim.loadFile("castle1.wav");
  fleet1 = minim.loadFile("fleet1.wav");
  trade1 = minim.loadFile("trade1.wav");
  plague1 = minim.loadFile("plague1.wav");
  rebellion1 = minim.loadFile("rebellion1.wav");
  song = minim.loadFile("Sweltering Expansion.mp3");
}

public void loadMap(){
  if(loadMap){worldMap=loadImage("worldmap"+level+".png");}
}

public void loadImages(){//splash;
  splash=loadImage("splash.png");
  bg=loadImage("bg.png");
  gui_bg=loadImage("gui_bg.png");
  water=loadImage("water.png");
  glow=loadImage("glow.png");
  whiteImg=loadImage("white.png");
  blackImg=loadImage("black.png");
  
  upgrade_pane=loadImage("upgrade_pane.png");
  info_pane=loadImage("info_pane.png");
  player_pane=loadImage("player_pane1.png");
  player_pane_colorplate=loadImage("player_pane_colorplate1.png");
  player_pane_current=loadImage("player_pane_current1.png");
  action_army=loadImage("action_army.png");
  action_army2=loadImage("action_army2.png");
  //action_castle=loadImage("action_castle.png");
  action_fort=loadImage("action_fort.png");
  action_fort2=loadImage("action_fort2.png");
  action_fleet=loadImage("action_fleet.png");
  action_fleet2=loadImage("action_fleet2.png");
  action_trade=loadImage("action_trade.png");
  action_trade2=loadImage("action_trade2.png");
  action_uni=loadImage("action_uni.png");
  button=loadImage("bottombarbutton.png");
  price_tag=loadImage("price_tag.png");
  action_selected=loadImage("action_selected.png");
  warning=loadImage("warning.png");
  upgrade_fort=loadImage("upgrade_fort.png");
  upgrade_mine=loadImage("upgrade_mine.png");
  upgrade_city=loadImage("upgrade_city.png");
  upgrade_fort2=loadImage("upgrade_castle.png");
  //upgrade_mine2=loadImage("upgrade_mine2.png");
  upgrade_city2=loadImage("upgrade_city2.png");
  upgrade_uni=loadImage("upgrade_uni.png");
  multiSpriteMap=loadImage("anims.png");
  end_turn=loadImage("end_turn.png");
  dead=loadImage("dead.png");
  portrait1=loadImage("portrait1.png");
  portrait2=loadImage("portrait2.png");
  portrait3=loadImage("portrait3.png");
  portrait4=loadImage("portrait4.png");
  
  plague=loadImage("plague.png");
  rebellion=loadImage("rebellion.png");
  ruta1=loadImage("ruta1.png");
  ruta2=loadImage("ruta2.png");
  
}
public void saveLevel(){
  String[] _l = {str(level)};
  saveStrings("data/level.txt", _l); 
}
public void saveSeeds(){
  String[] _l = new String[levelSeeds.size()];
  for(int i =0;i<levelSeeds.size();i++){
    _l[i]=str(levelSeeds.get(i));
  }
  saveStrings("data/levels.txt", _l); 
}
public void loadLevels(){
   String[] lines = loadStrings("levels.txt");
   levelSeeds = new IntList();
  for(int i=0;i<lines.length;i++){
    levelSeeds.append(PApplet.parseInt(lines[i]));
  }
  println("LEVEL SEEDS LOADED."); 
  String[] _l = loadStrings("level.txt");
  level= PApplet.parseInt(_l[0]);
}
public void setLevel(int l){
  String[] _l = {str(l)};
  saveStrings("data/level.txt", _l); 
}
public int sMouseX(){
  return PApplet.parseInt(mouseX/myScale);
}
public int sMouseY(){
  return PApplet.parseInt(mouseY/myScale);
}

public Player currentPlayer() {
  return players.get(playerTurn - 1);
}

public void checkIfPlayerIsDead() {
  noPlayers=players.size();
  for (int i=players.size()-1;i>=0;i--) {
    Player _p = players.get(i);
    boolean _hasArea=false;
    for (int a=0;a<areas.size();a++) {
      Area _a = areas.get(a);
      if (_p.id==_a.ownedBy) {
        _hasArea=true;
      }
    }
    if (!_hasArea && _p.isAlive) { 
      
      _p.isAlive=false;
      
      screenShake=3;
      _p.gold=0; 
      
      //println("PLAYER",_p.id,"IS NO MORE");
    }
    if (!_p.isAlive) { 
      noPlayers--;
    }
  }
}

public int getIncome(int _plr){
  int _inc=baseIncome;
  
  for(int _i=0;_i<areas.size();_i++){
    Area _a = areas.get(_i);
    if(_a.ownedBy==_plr && _a.invadedBy==0){
      _inc+=_a.income;
    }
  }
  return _inc;
}


public void runAIPlayer() {
  if (currentPlayer().isHuman != true && aiDelay<millis()) {
    if (iterations==0) {
      println("AI OF PLAYER", playerTurn);
    }
    aiDelay=millis()+aiSpeed;
    iterations++;
    AI_turn();
    if (iterations>=currentPlayer().aiIterations || currentPlayer().gold<1) {
      iterations=0;
      endTurn();
    }
  }
  else {
    if (currentPlayer().isAlive==false) {
      endTurn();
    }
  }
  actionSelection(currentPlayer()); // something something fix something with action selection.
}

public void actionSelection(Player _currP) {
  boolean _noneSelected=true;
  for (int i=0;i<_currP.actions.size();i++) {
    Action _action = _currP.actions.get(i);
    if (_action.selected) {
      _noneSelected=false;
    }
  }
  if (_noneSelected) {
    deselectAreas();
  }
}

public void deselectAreas() {
  for (int i=0;i<areas.size();i++) {
    Area a = areas.get(i);
    //rect(a.x1,a.y1,a.x2,a.y2);
    a.selectable=false;
  }
}

public void endTurn() {
  println("END TURN OF PLAYER", playerTurn); 
  playerTurn++;
  if (playerTurn>playerCount) {
    gameTurn++;
    playerTurn=1;
    reduceContested();
  }
  deselectAreas(); 
  
  Player _p = currentPlayer();
  _p.calcDominance();
  if (gameOn && _p.isAlive) {
    collectGold();
  } // collect gold if match still is on.
  _p.aggression = (_p.aggression > 0) ? _p.aggression-0.2f : 0;
  //println("--------------------------------------------------AGGRO PLAYER", _p.id,":",_p.aggression);
  println("PLAYERS STILL ALIVE", noPlayers);
}

public void reduceContested(){
    for (int i=0;i<areas.size();i++) {
    Area a = areas.get(i);
    if(a.contested>5){a.contested=5;}
    if(a.contested<-5){a.contested=-5;}
    //rect(a.x1,a.y1,a.x2,a.y2);
    a.contested--;
  }
}

public void winCheck() {
  if (gameOn) {
    if (noPlayers<=1) {
      gameOn=false;
      Player _p = players.get(0);
      if(_p.isAlive){
        level++;
        saveLevel();
      }
    }
    checkIfPlayerIsDead();
  } else {
    Player _p = players.get(0);
    if(_p.isAlive){
      waitForClick=true;
      pauseTimer=millis()+500;
      gameState = STATE_GAMEWON;
    }else{
      printInfo("GAME OVER");
      gameState = STATE_GAMEOVER;
      if(autoRun){gameSetup();}
    }
  }
}

public void collectGold() {
  
  doEvent();
  Player _p = currentPlayer();
  _p.gold+=baseIncome;
  for (int i=0;i<areas.size();i++) {
    Area a = areas.get(i);
    if (a.ownedBy == playerTurn) {
      if(a.invadedBy != playerTurn) {
        for (int g=0;g<a.income;g++) {
          if (_p.isAlive) {
            anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(a.x1+a.pic.width*0.5f-8+random(-10, 10)), PApplet.parseInt(a.y1+a.pic.height*0.5f-8+random(-10, 10)), 0.6f, 3).setDelay(PApplet.parseInt(random(2, 15))));
            _p.gold++;
            if(_p.isActionUpgraded(3)){
              _p.gold++;
            }
            playSound("gold");
          }
        }
        if(a.mine && random(1) < 0.20f && _p.isAlive){
          for(int _i=0;_i<8;_i++){
            anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(a.x1+a.pic.width*0.5f-8+random(-10, 10)), PApplet.parseInt(a.y1+a.pic.height*0.5f-8+random(-10, 10)), 0.6f, 3).setDelay(PApplet.parseInt(random(2, 15))));
            _p.gold++;
            playSound("gold");
          }
        }
        if(a.uni && _p.isAlive){
          anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(a.x1+a.pic.width*0.5f-8+random(-10, 10)), PApplet.parseInt(a.y1+a.pic.height*0.5f-8+random(-10, 10)), 0.4f, 7).setDelay(PApplet.parseInt(random(2, 15))));
          _p.research++;
          //playSound("gold");
        }
      } else {
        a.invadedBy = 0;
        anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(a.x1+a.pic.width*0.5f-8+random(-10, 10)), PApplet.parseInt(a.y1+a.pic.height*0.5f-8+random(-10, 10)), 0.17f, 6).setDelay(PApplet.parseInt(random(2, 15))));
      }
    }
  }
}
public void areaClicked(String _areaName) {
  
  if( mouseButton == RIGHT ) RMB =true;
  int _type=-1;
  Area _withArea =areas.get(0);
  Player _player = currentPlayer();

  for (int i=0;i<areas.size();i++) { //find out which area player has clicked.
    Area _a = areas.get(i);
    if (_a.name==_areaName) {
      _withArea=_a;
    }
  }


  for (int i=0;i<_player.actions.size();i++) { //find out which action player has selected.
    Action _action=_player.actions.get(i);
    if (_action.selected) {
      _type=i;
      if (!_withArea.selectable || _action.cost>_player.gold) {
        selectableAreas(_type);
        if (_player.isHuman) {//if(playerTurn==1){
          playSound("nogo");
          anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 2).setDelay(1));
          RMB=false;
          return;
        }
      } 
      else {
        _player.gold -= _action.cost;
        float odds;
        switch(_type) {
        case 0 : // army
          _player.aggression += 0.1f;
          adjustDiplomacy(_withArea.ownedBy);
          anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 0));
          //battle dicing
          odds=0.0f;
          if (_withArea.ownedBy !=0 ) {
            odds=0.2f;
          }
          if (_withArea.fort) {
            odds=0.6f;
            if(_withArea.ownedBy>0){
              Player _defender = players.get(_withArea.ownedBy-1);
              if(_defender.isActionUpgraded(1)){
                odds=0.9f;
              }
            }
            if(currentPlayer().isActionUpgraded(0)){odds*=0.5f;}
          }
 
          if (random(1)>odds || (playerTurn==1 && cheat)) {
            _withArea.contested +=2;
            _withArea.invadedBy = playerTurn;
            playSound("battle");
            _withArea.ownedBy=playerTurn;
            _withArea.fort=false;
            _withArea.uni=false;
            anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 1).setDelay(10));
          } else {
            playSound("fail");
            anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 2).setDelay(13));
            if(RMB) areaClicked(_areaName);
          }
          break;
        case 1 : // fort
          playSound("fort");

          anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 0));
          if(_withArea.city){_withArea.income = PApplet.parseInt(_withArea.income-=1);} 
          //_withArea.castle=false;
          _withArea.fort=true;
          _withArea.city=false;
          _withArea.uni=false;
          _withArea.contested=0;
          break;
        case 2 : // fleet
          _player.aggression += 0.1f;
          adjustDiplomacy(_withArea.ownedBy);
          anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 0));
          odds=0.2f;
          if (_withArea.ownedBy !=0 ) {
            odds=0.4f;
          }
          if (_withArea.fort) {
            odds=0.8f;
            if(_withArea.ownedBy>0){
              Player _defender = players.get(_withArea.ownedBy-1);
              if(_defender.isActionUpgraded(1)){
                odds=0.95f;
              }
            }
            if(currentPlayer().isActionUpgraded(2)){odds*=0.5f;}
          }
          if (random(1)>odds || (playerTurn==1 && cheat)) {
            _withArea.contested+=2;
            _withArea.invadedBy = playerTurn;
            playSound("fleet");
            _withArea.ownedBy=playerTurn;
            _withArea.fort=false;
            _withArea.uni=false;
            anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 1).setDelay(10));
          } else {
            playSound("fail");
            anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 2).setDelay(10));
            if(RMB) areaClicked(_areaName);
          }
          break;
        case 3 : // trade
          playSound("trade");
          anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 0));
          _withArea.income=_withArea.income+1;
          _withArea.fort=false;
          _withArea.city=true;
          _withArea.uni=false;
          _withArea.contested=0;
          break;
        case 4 : // uni
          playSound("trade");
          anims.add (new multiAnimObject(multiSpriteMap, 16, 16, PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8), PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8), 0.3f, 0));
          _withArea.fort=false;
          _withArea.uni=true;
          _withArea.city=false;
          _withArea.contested=0;
          break;
        default:
          break;
        }
        
        selectableAreas(_type);
      }
    }
  }
  RMB=false;
}


public void selectableAreas(int _type) { 
  
  Player _player = currentPlayer();
  Action _action = _player.actions.get(_type);
  
  switch(_type) {
  case 0 : // army
    for (int _i=0;_i<areas.size();_i++) { 
      Area _a=areas.get(_i);
      _a.selectable=false;
      if (_a.ownedBy != playerTurn && _player.gold>=_action.cost) {// not owned by curr player     
        for (int _n=_a.neighbors.size()-1;_n>=0;_n--) { // for each in neighborlist
          //println(_a.name, " - ", _a.neighbors.get(_n));
          Area _a2=areas.get(_a.neighbors.get(_n)); //  .neighbors.get(_n)
          if (_a2.ownedBy== playerTurn) { // neighbor is owned by curr player
            _a.selectable=true;
          }
        }
      }
    }
    break;
  case 1 : // fort
    for (int _i=0;_i<areas.size();_i++) {
      Area _a=areas.get(_i);
      _a.selectable=false;

      if (_a.ownedBy == playerTurn && _player.gold>=_action.cost && !_a.fort) {
        _a.selectable=true;
      }
    }
    break;
  case 2 : // fleet
    for (int _i=0;_i<areas.size();_i++) { // 
      Area _a=areas.get(_i);
      _a.selectable=false;
      if (_a.ownedBy != playerTurn  && _player.gold>=_action.cost) {// not owned by curr player     
        _a.selectable=true;
      }
    }
    break;
  case 3 : // city
    for (int _i=0;_i<areas.size();_i++) {
      Area _a=areas.get(_i);
      _a.selectable=false;
      if (_a.ownedBy == playerTurn  && _player.gold>=_action.cost  && !_a.city) {
        _a.selectable=true;
      }
    }
    break;
  case 4 : // uni
    for (int _i=0;_i<areas.size();_i++) {
      Area _a=areas.get(_i);
      _a.selectable=false;
      if (_a.ownedBy == playerTurn  && _player.gold>=_action.cost && !_a.uni) {
        _a.selectable=true;
      }
    }
    break;
  default:
    break;
  }
}

public void doEvent() {
  if (random(1)<0.99f) {
    Area _withArea = areas.get(PApplet.parseInt(random(areas.size())));
    int _xx = PApplet.parseInt(_withArea.x1+_withArea.pic.width*0.5f-8);
    int _yy = PApplet.parseInt(_withArea.y1+_withArea.pic.height*0.5f-8);
    int _e = PApplet.parseInt(random(2));
    switch (_e) {

    case 0 :
      if (_withArea.income>1 && level>5) {
        println("RUN PLAGUE ON", _withArea.name);
        boolean _p = false;
        if(_withArea.city){_p=true;}
        if (_p) {
          anims.add (new multiAnimObject(multiSpriteMap, 16, 16, _xx, _yy-4, 0.25f, 4).setDelay(0));
          popMessages.add (new PopMessage("PLAGUE!", _xx*2+16, _yy*2+35, 0.9f, 25).setDelay(30));
          //_withArea.income=(_withArea.castle)?1:0;
          _withArea.income=1;
          _withArea.city=false;
          playSound("plague");
          screenShake=1.5f;
        }
      }
      break;
    case 1 :
      if (_withArea.ownedBy>0 && level>6) {
        for (int i = 0; i< players.size();i++) {
          if (_withArea.ownedBy == i) {
            Player _p = players.get(i);
            
            if (0.09f+random(1)*0.1f < ( PApplet.parseFloat(countControlledAreas(_p))/PApplet.parseFloat(areas.size()) ) ) {
            //if (random(1)<_p.aggression * 1.5) {
              println("RUN REBELLION ON", _withArea.name);
              anims.add (new multiAnimObject(multiSpriteMap, 16, 16, _xx, _yy-4, 0.25f, 5).setDelay(0));
              popMessages.add (new PopMessage("REBELLION!", _xx*2+16, _yy*2+35, 0.9f, 25).setDelay(30));
              _withArea.ownedBy=0;
              playSound("rebellion");
              screenShake=2;
            }
          }
        }
      }
      break;
    default:
      break;
    }
  }
}

public int countUnis(Player _pl){
  int _count=0;
  for(int _c=0;_c<areas.size()-1;_c++){
    Area _a = areas.get(_c);
    if (_a.ownedBy == _pl.id && _a.uni){
      _count++;
    }
  }
  //println("-----------------------------------------------------------Player " + _pl.id + " controls " + _count + " areas, i.e. " + float(_count)/float(areas.size()) );
  return _count;
}

public int countControlledAreas(Player _pl){
  int _count=0;
  for(int _c=0;_c<areas.size()-1;_c++){
    Area _a = areas.get(_c);
    if (_a.ownedBy == _pl.id){
      _count++;
    }
  }
  //println("-----------------------------------------------------------Player " + _pl.id + " controls " + _count + " areas, i.e. " + float(_count)/float(areas.size()) );
  return _count;
}

public void printShadedFade(String _info, int _x, int _y, int _fade) {
  //scale(0.5);
  String _mes = _info;
  int fading = _fade;
  fill(60, 50, 20, 250*(fading*0.1f));
  text(_mes, 1+_x*0.5f, 1+_y*0.5f);
  text(_mes, _x*0.5f, 1+_y*0.5f);
  fill(230, 190, 100, 250*(fading*0.1f));
  if (_mes.equals("PLAGUE!")) {
    fill(70, 199, 90, 250*(fading*0.1f));
  }
  if (_mes.equals("REBELLION!") ){
    fill(199, 70, 70, 250*(fading*0.1f));
  }
  text(_mes, _x*0.5f, _y*0.5f);
  //scale(2);
}

public void printShaded(String _info, int _x, int _y) {
  scale(0.5f);
  fill(30, 25, 10);
  text(_info, 1+_x, 1+_y);
  text(_info, _x, 1+_y);
  fill(170, 160, 130);
  text(_info, _x, _y);
  scale(2);
}
public void printInfo(String _info) {
  scale(0.5f);
  fill(60, 50, 20);
  text(_info, 1+scaledScrWidth, scaledScrHeight*2-12);
  text(_info, scaledScrWidth, scaledScrHeight*2-12);
  fill(230, 190, 100);
  text(_info, scaledScrWidth, scaledScrHeight*2-13);
  scale(2);
}
public int tintByOwner(int _withPlayer) {
  switch (_withPlayer) {
  case 0 : // neutral
    return color(140, 140, 130, 190);
  case 1 : // plr1    
    return color(60, 80, 255, 220);
  case 2 : // plr2
    return color(255, 90, 80, 250);
  case 3 : // plr3
    return color(255, 255, 90, 220);
  case 4 : // plr4
    return color(200, 40, 240, 220);
  case 5 : // plr5
    return color(120, 255, 170, 230);
  default:
    return color(0);
  }
}

public int tintByOwner2(int _withPlayer, int _c) {
  int _inCol=_c;
  switch (_withPlayer) {
  case 0 : // neutral
    return color(140, 140, 130, 190);
  case 1 : // plr1    
    return color(red(_inCol) -30, green(_inCol) -20, blue(_inCol)+100, 220);
  case 2 : // plr2
    return color(red(_inCol)+100, green(_inCol) -30, blue(_inCol) -30, 250);
  case 3 : // plr3
    return color(red(_inCol)+80, green(_inCol)+120, blue(_inCol) -40, 220);
  case 4 : // plr4
    return color(red(_inCol)+90, green(_inCol) -50, blue(_inCol)+110, 220);
  case 5 : // plr5
    return color(red(_inCol) -30, green(_inCol)+150, blue(_inCol)+100, 230);
  default:
    return color(0);
  }
}

public void unselectActions() {
  for (int _i=0;_i<players.size();_i++) { //brutally unselect all actions for all players before selecting a new.
    Player _p = players.get(_i);
    for (int _u=0;_u<_p.actions.size();_u++) {
      Action _a= _p.actions.get(_u);
      _a.selected=false;
      //println(_a.cost);
    }
  }
}


public PImage renderArea(PImage _im) {
  PImage _baseImg=_im;
  int _tCol;
  for (int _y=0;_y<_im.height;_y++) {
    for (int _x=0;_x<_im.width;_x++) {
      if (_baseImg.get(_x, _y) != color(0)) {
        int borderProximity = (countSurrounding(_baseImg, _x, _y, color(0))*14);
        int _centerdist = PApplet.parseInt(dist(_x, _y, (_im.width*0.5f), (_im.height*0.5f)))*3;
        borderProximity+=_centerdist;
        _im.set(_x, _y, color(red(_im.get(_x, _y))+PApplet.parseInt(random(-10, 10))-borderProximity, green(_im.get(_x, _y))+PApplet.parseInt(random(-10, 10))-borderProximity, blue(_im.get(_x, _y))+PApplet.parseInt(random(-10, 00))-borderProximity));
        //_im.filter(BLUR,1);
      }
    }
  }


  return _im;
}

public String getRandomTaunt(){
 return "YOUR " + tauntPart1[PApplet.parseInt(random(tauntPart1.length))] + " IS " + tauntPart2[PApplet.parseInt(random(tauntPart2.length))] + "'S " + tauntPart3[PApplet.parseInt(random(tauntPart3.length)) ];
}
public void playSound(String _snd){
  if(_snd.equals("song")){
      song.rewind();
      song.play();
    }
  boolean _noHuman=true;
  for(int _i=0;_i<players.size();_i++){
    Player _p = players.get(_i);
    if(_p.isHuman && _p.isAlive){_noHuman=false;}
  }
  if(!_noHuman){
    
    if(_snd.equals("battle")){
      battle1.rewind();
      battle1.play();
    }
    if(_snd.equals("fail")){
      fail1.rewind();
      fail1.play();
    }
    if(_snd.equals("nogo")){
      nogo.rewind();
      nogo.play();
    }
    if(_snd.equals("fort")){
      fort1.rewind();
      fort1.play();
    }
      if(_snd.equals("castle")){
      castle1.rewind();
      castle1.play();
    }
    if(_snd.equals("fleet")){
      fleet1.rewind();
      fleet1.play();
    }
      if(_snd.equals("trade")){
      trade1.rewind();
      trade1.play();
    }
    if(_snd.equals("gold")){
      if(random(1)<0.5f){
        gold1.rewind();
        gold1.play();
      }else{
        gold2.rewind();
        gold2.play();
      }
    }
    if(_snd.equals("plague")){
      plague1.rewind();
      plague1.play();
    }
    if(_snd.equals("rebellion")){
      rebellion1.rewind();
      rebellion1.play();
    }
  }
}
public void gameWon() {
  renderGame();
  image(ruta1, 0, -8);
  scale(2);
  image(portrait1, PApplet.parseInt(scaledScrWidth*0.19f), PApplet.parseInt(scaledScrHeight*0.06f) );
  
  scale(0.5f);
  
  scale(2);
  printShaded("CONGRATULATIONS!", PApplet.parseInt(scaledScrWidth*0.50f), PApplet.parseInt(scaledScrHeight*0.50f) );
  printShaded("YOU HAVE VANQUISHED YOUR ENEMIES.", PApplet.parseInt(scaledScrWidth*0.50f), PApplet.parseInt(scaledScrHeight*0.60f) );
  if (millis()<pauseTimer) {
    if(waitForClick){
      pauseTimer=millis()+500;
    }else{
      println("GAME STATE SET TO GAME_WON");
      gameState=STATE_MAPSTART;
      waitForClick=true;
      gameSetup();
    }
  }else{
    gameState=STATE_GAMEWON;
  }
}

public void mouseClicked() {
  println("GAME STATE:",gameState);
  if(gameState==STATE_SPLASH){
    waitForClick=false;
  }
  if(gameState==STATE_MAPSTART){
    waitForClick=false;
  }
  if(gameState==STATE_GAMEWON){
    waitForClick=false;
  }
  if(gameState==STATE_GAME || gameState==STATE_GAMEOVER){
    Player _p = currentPlayer();
    if(gameState==STATE_GAMEOVER){
      println("-------------------------------------------------------------------------------------------------------------------------------------");
      gameSetup();
      gameState=STATE_GENERATOR;
      waitForClick=true;
      noTint();
      return;
    }
    if(_p.isHuman){
      if(noMouseOver && !currentPlayer().hasUpgrade()){
        if(mouseX > 850 && mouseY > 709){
          if(gameState==STATE_GAME){endTurn();}
        }
        println("MOUSE:",mouseX,mouseY);
        
        for (int i = 0;i<_p.actions.size();i++){
          Action _a = _p.actions.get(i);
          boolean _onButton=false;
          if(_a.mouseOver){
            _onButton=true;
            println("_onButton=",_onButton);
          }
          
          if(!_onButton){
            _a.selected=false;
          }
        }
        println("WATER WAS CLICKED BY PLAYER",_p.id);
        
      }else {
        if (currentPlayer().hasUpgrade()) {
          if(upgradeArmyButton.selected){
            _p.upgrade(0);
          }
          if(upgradeFortButton.selected){
            _p.upgrade(1);
          }
          if(upgradeFleetButton.selected){
            _p.upgrade(2);
          }
          if(upgradeTradeButton.selected){
            _p.upgrade(3);
          }
        }
        println(currentMousePressedArea+" was clicked");
        printNeighborlist(currentMousePressedArea);
        //printInfo(currentMousePressedArea);
        areaClicked(currentMousePressedArea);
      }
    } else {
     //AIturn(); 
    }
  }
}


public void keyReleased() {
  cheatCode+=key;
  if(cheatCode.length() > 3){cheatCode=cheatCode.substring(cheatCode.length()-3);}
  println("input:",cheatCode);
  if(cheatCode.equals("wow")){
    cheat = !cheat;
    debug = !debug;
    println("CHEAT IS:",cheat);
    println("DEBUG IS:",cheat);
  }
  
  if (key == 'l' || key == 'L') {
    randomSeed(millis());
    levelSeeds.set(level,PApplet.parseInt(random(1000)));
    saveSeeds();
    //randomSeed(levelSeeds.get(level));
    println(levelSeeds.get(level));
    gameSetup();
    
  }
  if (key == '+' && debug) {
    level++;
    
  if(level>75) level=76;
    saveLevel();
    gameSetup();
  }
    if (key == '-' && debug) {
    level--;
    saveLevel();
    gameSetup();
  }
  if (key == 'r' || key == 'R') {
    gameSetup();
    noTint();
  }
  if (key == 'q' || key == 'Q' && debug) {
    screenShake=2;
    
  }
    if (key == ' ' ) {
      Player _pp = currentPlayer();
      if(_pp.isHuman){endTurn();}
  }
  
  if (key == 's' && debug) {
    worldMap.save("worldmap" + PApplet.parseInt(random(1)*10000) + ".png");
  }
  /*
  if (key == 'S') {
    worldMap.save("data/worldmap" + level + ".png");
  }
  */
  if (key == 'g' || key == 'G') {
    loadMap = (loadMap) ? false:true;
    gameSetup();
  }
  if (key == 'm' || key == 'M') {
    playMusic=!playMusic;
    if(playMusic){song.play(musicAt);}
  }
  if (key == 'q'){
    if(runGenerator){
      runGenerator=false;
    }else{
      runGenerator=true;
    }
  }
  if (key == 'k' || key == 'K') {
    Player _p = currentPlayer();
    //Player _p = players.get(0);
    _p.isHuman=false;
    aiSpeed=200;
  }
  /*
  if (key >= '1' && key <= '9' && debug) {
    setLevel(key-'0');
    gameSetup();
  }
  */
  if (key >= '1' && key <= '4' && debug) {
    humanPlayers = (key-'0');
    gameSetup();
  }
  if (keyCode == UP){

  }
  if (keyCode == DOWN){

  }
  if (keyCode == LEFT){

  }
  if (keyCode == RIGHT){

  }
}
public void draw(){
  try {
  
  /*
  logic();
  render();
  */
  
  background(0);
  scale(4.0f);
    switch (gameState){
    
    case STATE_SPLASH :
      splash();
    break;
    
    case STATE_MENU :
    //
    break;
    
    case STATE_GAME :
      selectableSine+=0.25f;
      runAIPlayer();
      renderGame();
      winCheck();
      
      
    break;
    
    case STATE_GENERATOR :
      generatorState();
    break;
    case STATE_GAMEOVER :
      renderGame();
      winCheck();
    break;
    case STATE_MAPSTART :
      mapStart();
    break;
    case STATE_GAMEWON :
      gameWon();
    break;
    default:
    break;
  }
  } catch (Exception e) {
    e.printStackTrace();
  }
  //textAlign(LEFT);
  //text(log,0,100);
}










/*
void logic(){
    switch (gameState){
    
    case STATE_SPLASH :
      splash();
    break;
    
    case STATE_MENU :
    //
    break;
    
    case STATE_GAME :
      selectableSine+=0.25;
      runAIPlayer();
      renderGame();
      winCheck();
      
      
    break;
    
    case STATE_GENERATOR :
      generatorState();
    break;
    case STATE_GAMEOVER :
      renderGame();
      winCheck();
    break;
    case STATE_MAPSTART :
      mapStart();
    break;
    default:
    break;
  }
}
void render(){
    
  background(0);
  scale(4.0);
    switch (gameState){
    
    case STATE_SPLASH :
      splash();
    break;
    
    case STATE_MENU :
    //
    break;
    
    case STATE_GAME :
      selectableSine+=0.25;
      runAIPlayer();
      renderGame();
      winCheck();
      
      
    break;
    
    case STATE_GENERATOR :
      generatorState();
    break;
    case STATE_GAMEOVER :
      renderGame();
      winCheck();
    break;
    case STATE_MAPSTART :
      mapStart();
    break;
    default:
    break;
  }
}

*/
public void generatorState(){
 
      if(loadMap){
        //dont run generator
        runGenerator=false;
        println("CREATING AREA OBJECTS");
        createWorld();
        println("INITIALIZING PLAYERS");
        
        initPlayers();
        
        println("GAME STATE SET TO GAME");
        println("START PLAYER", playerTurn+"'S TURN");
        pauseTimer=millis()+3000;
        if(autoRun){pauseTimer=millis()+1000;}
        gameState=STATE_MAPSTART;
        
       if(autoRun){
          Player _p =players.get(0);
          _p.isHuman=false;
          aiSpeed=150;
        }
      }else{ //run generator
        if(runOnce){
          println("INITIALIZING NEW MAP WITH", genAreas,"AREAS");
          initMap();
          println("EXPANDING MAP AREAS");
          startMap();
          
          runOnce=false;
        }else{
          if(runGenerator){
            iterations++;
            generateMap();
            image(worldMap,0,0);
            text(genLimits[2]+1-iterations,15,10);
            if(iterations>genLimits[2]){
              println("MAP GENERATION COMPLETE");
              runGenerator=false;
              println("CREATING AREA OBJECTS");
              createWorld();
              println("INITIALIZING PLAYERS");
              initPlayers();
              println("GAME STATE SET TO GAME");
              
              println("START PLAYER", playerTurn+"'S TURN");
              gameState=STATE_GAME;
              aiDelay=millis()+100;
            }
          }
        }
    } 
  
  
}

public void createWorld(){
  int alphaColor = worldMap.get(0,0);
  int currColor = color(0);
  for(int _y=0;_y<worldMap.height-1;_y++){
    for(int _x=0;_x<worldMap.width-1;_x++){
      currColor=worldMap.get(_x,_y);
      if (currColor!=alphaColor){
        //found land. Make area!
        boolean newArea = true;
        for(int i = areas.size()-1;i>=0;i--){// check to see if new land
          Area _area = areas.get(i);
          if(currColor == _area.areaColor){
            newArea=false;
          }
        }
        if(newArea==true) {
          makeArea(currColor,_x,_y);
        }
      } else { // in the water
      int landProximity=countSurrounding(worldMap, _x, _y, alphaColor);
        if(landProximity < 9 && _y > 1){
          int _cTweak = color(red(water.get(_x,_y))+landProximity,green(water.get(_x,_y))+landProximity*2,blue(water.get(_x,_y))+landProximity*3);
          water.set(_x,_y,_cTweak);
        }
      }
    }
  }
  // After all areas are created, find their neighbors.
  for(int i=0;i<areas.size();i++){
    Area a = areas.get(i);
    a.findNeighbors();
  }
  for(int i=0;i<areas.size();i++){
    Area a = areas.get(i);
    a.findChokePoints();
  }
  //water.filter(BLUR,1); // could be used to make a nicer shoreline, if texture was added afterwards.
  println("FINAL AREA COUNT IS",areas.size());

}

public void makeArea(int _col,int _xx,int _yy){
  int _c = _col;
  int _moc = color(245);
  int _x1=_xx;
  int _y1=_yy;
  int _x2=_xx+1;
  int _y2=_yy+1;
  
  for(int _y=0;_y<worldMap.height-1;_y++){
    for(int _x=0;_x<worldMap.width-1;_x++){
      if (worldMap.get(_x,_y)==_c) { //adjust bounds
        _x1 = (_x < _x1) ? _x : _x1 ; 
        _x2 = (_x > _x2) ? _x : _x2 ;
        _y1 = (_y < _y1) ? _y : _y1 ; 
        _y2 = (_y > _y2) ? _y : _y2 ;
      }
    }
  }
  PImage _im = createImage(_x2-_x1+2,_y2-_y1+2,RGB); //Create area image;
  PImage _moim = createImage(_x2-_x1+2,_y2-_y1+2,RGB);
  //println("Bounds:",_x1,_y1,_x2,_y2);
  //copy area to temp image and crop
  // FIND BUG!!
  for(int _y=0;_y<_im.height-1;_y++){
    for(int _x=0;_x<_im.width-1;_x++){
      if(worldMap.get(_x1+_x,_y1+_y)==_c) {
        _im.set(_x+1,_y+1,_c);
        _moim.set(_x+1,_y+1,_moc);
      }else{
        _im.set(_x+1,_y+1,color(0));
        _moim.set(_x+1,_y+1,color(0));
      }
    }
  }
  
  areas.add(new Area(_x1-1,_y1-1,_x2+1,_y2+1, renderArea(_im), _moim, _c, areas.size()));
}

public int countSurrounding(PImage _img, int xx, int yy, int compareWith){
  int count=0;
  for(int tx = -1;tx<2;tx++){
    for(int ty = -1;ty<2;ty++){
      if(inImg(_img,xx+tx,yy+ty)){
        if(_img.get(xx+tx,yy+ty) == compareWith){
          count++;
        }
      }
    }
  }
  return count;
}
public boolean inImg(PImage _img,int _x,int _y){
  boolean in=false;
  if(_x >= 0 && _y >= 0 && _x <= _img.width  && _y <= _img.height ){
    in=true;
  }
  return in;
}

public int getSumOfSurrounding(PImage _baseImg,int _x,int _y){
  return (_baseImg.get(_x,_y));
}

//---------------------------------------
public void initPlayers(){
  noPlayers=(level>3) ? 4 : level+1 ;
  while(playerCount<noPlayers){
    Area _a = areas.get(PApplet.parseInt(random(areas.size())));
    if(_a.ownedBy==0){
      _a.ownedBy=playerCount+1;
      _a.fort=true;
      //_a.income+=1;
      playerCount++;
      players.add(new Player("Player " + _a.ownedBy, PApplet.parseInt(random(3,7)), _a.id,playerCount));
      println("PLAYER",_a.ownedBy,"CREATED.");
      println("PLAYER",_a.ownedBy,"'S STARTING AREA IS",_a.name);
    }
  }
  randomSeed(PApplet.parseInt(random(100)));
  for(int _i = 0;_i<players.size();_i++){
    Player _p = players.get(_i);
    _p.setAIPreference();
  }
  if(level==1){
    for(int i = 0;i< areas.size();i++){
      Area _a = areas.get(i);
      _a.fort=false;
    }
  }
}

public void startMap(){
  worldMap=createImage(scaledScrWidth,scaledScrHeight,RGB);
  int _box=7;
  for(int _my=0;_my<gridHeight;_my++){
    for(int _mx=0;_mx<gridWidth;_mx++){
      int _mmcol=miniMap.get(_mx,_my);
      if(_mmcol!=color(0)){
        //println(_mmcol);
        int ex=margin +margin -2 + _mx*22 + PApplet.parseInt(random(-_box,_box));
        int ey=(margin-9) +_my*17 + PApplet.parseInt(random(-_box,_box));
        for(int i=0;i<4;i++){
          int _xr1=PApplet.parseInt(random(-12,-5));
          int _yr1=PApplet.parseInt(random(-10,-4));
          int _xr=PApplet.parseInt(random(5,12));
          int _yr=PApplet.parseInt(random(4,10));
          
          for(int _y=_yr1;_y<_yr;_y++){
            for(int _x=_yr1;_x<_xr;_x++){
              worldMap.set(ex+_x,ey+_y,_mmcol);
            }
          }
        }
      }
    }
  }
}

public void initMap(){ 
  for(int _my=0;_my<gridHeight;_my++){
    for(int _mx=0;_mx<gridWidth;_mx++){
      miniMap.set(_mx,_my,color(PApplet.parseInt(random(1)*50)+145,PApplet.parseInt(random(1)*55)+155,PApplet.parseInt(random(1)*40)+140));
    }
  }
  int _aCount=0;
  while (_aCount!=genAreas){
    _aCount=0;
    for(int _my=0;_my<gridHeight;_my++){
      for(int _mx=0;_mx<gridWidth;_mx++){
        _aCount = (miniMap.get(_mx,_my) == color(0)) ? _aCount : _aCount+1;
      }
    }
    int XX=PApplet.parseInt(random(gridWidth+1));
    int YY=PApplet.parseInt(random(gridHeight+1));
    if(_aCount<genAreas){
      miniMap.set(XX,YY,color(PApplet.parseInt(random(1)*150)+100,PApplet.parseInt(random(1)*150)+100,PApplet.parseInt(random(1)*150)+100));
    } else{
      miniMap.set(XX,YY,color(0)); // maybe add bias to make "holes" toward edges.
    }
  }
}

public void generateMap(){
  int _N,_xx,_yy;
  
  int _doCol;
  int _watCol=worldMap.get(0,0);
  for(int i = 0;i<450;i++){
    for(int _my=0;_my<gridHeight;_my++){
      for(int _mx=0;_mx<gridWidth;_mx++){
        _xx=PApplet.parseInt(random(1,scaledScrWidth-1));
        _yy=PApplet.parseInt(random(1,scaledScrHeight-1));
        _doCol = miniMap.get(_mx,_my);
        if(_doCol!=color(0)){
          _N=countSurrounding(worldMap,_xx,_yy,_doCol);
          if(_N>random(1,3)){
            if(worldMap.get(_xx,_yy) == _watCol){
              worldMap.set(_xx,_yy,_doCol);
            }
          }
        }
      }
    }
  }
  plugCount++;
  if(plugCount>genLimits[0]){
    println("PLUGGING HOLES");
    plugCount=0;
    for(int _my=0;_my<scaledScrHeight;_my++){
        for(int _mx=0;_mx<scaledScrWidth;_mx++){
          //find singles and plug.
          
          int _countBub=countSurrounding(worldMap,_mx,_my,_watCol);
          if(worldMap.get(_mx,_my) == _watCol && _countBub == 1){
            worldMap.set(_mx,_my,worldMap.get(_mx+1,_my));
          }
        }
    }
  }
  
  if(iterations==genLimits[0]){println("START MESSING UP OF MAP");}
  if(iterations==genLimits[1]){println("END MESSING UP OF MAP");}
  
  if(iterations<genLimits[1] && iterations>genLimits[0] && random(1)<0.99f){
    _xx=PApplet.parseInt(random(3,scaledScrWidth-3));
    _yy=PApplet.parseInt(random(3,scaledScrHeight-3));
    int _xr1=PApplet.parseInt(random(-8,0));
    int _yr1=PApplet.parseInt(random(-6,0));
    int _xr=PApplet.parseInt(random(0,8));
    int _yr=PApplet.parseInt(random(0,6));
    for(int _y=_yr1;_y<_yr;_y++){
      for(int _x=_yr1;_x<_xr;_x++){
        worldMap.set(_xx+_x,_yy+_y,color(0));
      }
    }
  }
  
  worldMap.set(1+PApplet.parseInt(mouseX*0.25f),1+PApplet.parseInt(mouseY*0.25f),color(0));
  worldMap.set(PApplet.parseInt(mouseX*0.25f),PApplet.parseInt(mouseY*0.25f),color(0));
  worldMap.set(-1+PApplet.parseInt(mouseX*0.25f),-1+PApplet.parseInt(mouseY*0.25f),color(0));
  worldMap.set(1+PApplet.parseInt(mouseX*0.25f),-1+PApplet.parseInt(mouseY*0.25f),color(0));
  
}


public void printNeighborlist(String _currentMousePressedArea){
  for(int i=0;i<areas.size();i++){
    Area a = areas.get(i);
    if(a.name==_currentMousePressedArea){
      println(a.name+"'s list of neighbors:");
      for(int _n=0;_n<a.neighbors.size();_n++){
        for(int _b=0;_b<areas.size();_b++){
          Area b = areas.get(_b);
          if(b.id == a.neighbors.get(_n)){
            println(b.name);
          }
        }
      }
    } 
    
  }
}
public void mapStart() {
  String _map="MAP "+level+"!";
  image(bg,0,0);
  image(ruta1, 0, -8);
  
  //image(ruta2, 16, scaledScrWidth*0.6);
  
  image(portrait1, PApplet.parseInt(scaledScrWidth*0.85f), PApplet.parseInt(scaledScrHeight*0.12f) );
  
  //image(ruta2, int(scaledScrWidth*0.5)-int(ruta2.width * 0.5), int(scaledScrHeight*0.58) );
  scale(2);
  float opponentHeight = 0.77f;
  if (millis()<pauseTimer) {
    switch (level){
      case 1:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(action_army, PApplet.parseInt(scaledScrWidth*0.61f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        printShaded("ARMY, COST 1 GOLD:", PApplet.parseInt(scaledScrWidth*0.45f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("LETS YOU ATTACK AN ADJACENT AREA.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded("EACH AREA GIVES YOU 1 GOLD, BUT\nNOT THE TURN AFTER BEING CONQUERED.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.48f) );
        
        printShaded("DESTROY ALL ENEMIES TO WIN.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.64f) );
        printShaded("DESPITE BEING ENEMIES, LET'S LIVE IN PEACE.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      case 2:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.33f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.53f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(action_fort, PApplet.parseInt(scaledScrWidth*0.61f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        printShaded("FORT, COST 2 GOLD:", PApplet.parseInt(scaledScrWidth*0.45f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("INCREASES DEFENSE OF AN AREA.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded("YOU CAN'T HIDE BEHIND WALLS, BLUE!", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      case 3:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.28f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait4, PApplet.parseInt(scaledScrWidth*0.58f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(action_fleet, PApplet.parseInt(scaledScrWidth*0.61f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        
        printShaded("FLEET, COST 3 GOLD:", PApplet.parseInt(scaledScrWidth*0.45f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("LETS YOU ATTACK AN ANY AREA.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded("WAR IS THE INEVITABLE CONCLUSION OF FAILED DIPLOMACY.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      case 4:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.28f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait4, PApplet.parseInt(scaledScrWidth*0.58f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(action_trade, PApplet.parseInt(scaledScrWidth*0.61f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        printShaded("CITY, COST 2 GOLD:", PApplet.parseInt(scaledScrWidth*0.45f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("INCREASES THE INCOME FROM AN AREA BY 1.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded("KINGS DON'T HAVE FRIENDS.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      case 5:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.28f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait4, PApplet.parseInt(scaledScrWidth*0.58f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(action_uni, PApplet.parseInt(scaledScrWidth*0.68f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        printShaded("UNIVERSITY, COST 6 GOLD:", PApplet.parseInt(scaledScrWidth*0.44f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("BUILDS RESEARCH POINTS.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded("10 POINT NEEDED TO UPGRADE ONE ACTION.\nAN UPGRADED ACTION DOES THE\nSAME THING, BUT BETTER.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.46f) );
        printShaded("WE SEEK A PEACEFUL SOLUTION TO THIS CONFLICT.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      case 6:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.28f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait4, PApplet.parseInt(scaledScrWidth*0.58f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(plague, PApplet.parseInt(scaledScrWidth*0.61f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        printShaded("PLAGUE, EVENT:", PApplet.parseInt(scaledScrWidth*0.44f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("PLAGUE DESTROYS CITIES.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded(taunt[tauntIndex], PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      case 7:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.28f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait4, PApplet.parseInt(scaledScrWidth*0.58f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(rebellion, PApplet.parseInt(scaledScrWidth*0.61f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        printShaded("REBELLION, EVENT:", PApplet.parseInt(scaledScrWidth*0.44f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("TURNS AN AREA NEUTRAL.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded(taunt[tauntIndex], PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      case 8:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.28f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait4, PApplet.parseInt(scaledScrWidth*0.58f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(upgrade_mine, PApplet.parseInt(scaledScrWidth*0.61f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        printShaded("MINE:", PApplet.parseInt(scaledScrWidth*0.44f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("SOMETIMES PAYS A LOT!", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded(taunt[tauntIndex], PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      case 76:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.28f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait4, PApplet.parseInt(scaledScrWidth*0.58f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(rebellion, PApplet.parseInt(scaledScrWidth*0.61f), PApplet.parseInt(scaledScrHeight*0.24f) );
        scale(2);
        printShaded("LAST AND FINAL MAP!", PApplet.parseInt(scaledScrWidth*0.44f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded("GENERATE NEW ONES BY\nPRESSING THE 'G' KEY.", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded(taunt[tauntIndex], PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
      default:
        scale(0.5f);
        image(portrait2, PApplet.parseInt(scaledScrWidth*0.28f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait3, PApplet.parseInt(scaledScrWidth*0.43f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        image(portrait4, PApplet.parseInt(scaledScrWidth*0.58f), PApplet.parseInt(scaledScrHeight*opponentHeight) );
        //image(action_castle, int(scaledScrWidth*0.61), int(scaledScrHeight*0.24) );
        scale(2);
        printShaded("HELPFUL TIP:", PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.30f) );
        printShaded(currentTip, PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*0.38f) );
        printShaded(currentTaunt, PApplet.parseInt(scaledScrWidth*0.5f), PApplet.parseInt(scaledScrHeight*(opponentHeight+0.20f)) );
      break;
    }
    if(waitForClick){ pauseTimer=millis()+500; }
    //background(30, 30, 30);
    fill(200, 200, 150);
    scale(2);
    printShaded( _map, PApplet.parseInt(scaledScrWidth*0.25f), PApplet.parseInt(scaledScrHeight*0.075f) );
    scale(0.5f);
  }else{
    gameState=STATE_GAME;
  }
  scale(0.5f);
}

class multiAnimObject {
  PImage spriteMap;
  PImage[][] images;
  float currentFrame, currentAnimation;
  float frame,animation;
  float pace;
  int xpos;
  int ypos;
  boolean finished = false;
  
  multiAnimObject(PImage sprMap, int sprWidth, int sprHeight, int mx, int my, float p, int _anim) { // initialize a new object. Why is the double initialization done? Compare count->imageCount to sprWidth is only sprWidth.
    spriteMap = sprMap;

    xpos = mx;
    ypos = my;
    pace = p;

    animation = spriteMap.height/sprHeight;
    frame = spriteMap.width/sprWidth;
    images = new PImage[PApplet.parseInt(animation)][PApplet.parseInt(frame)];
    currentFrame=0;
    currentAnimation=_anim;
    for (int a = 0; a < animation; a++) {
      for (int i = 0; i < frame; i++) {
        //println("a: "+ a + ", i: " + i);
        images[a][i] = createImage(sprWidth, sprHeight, ARGB);
        images[a][i].copy(spriteMap,i*sprWidth,a*sprHeight,sprWidth,sprHeight,0,0,sprWidth,sprHeight); 
      }
    }
  }
  
  public multiAnimObject setDelay(float delay) {
    currentFrame = -delay;
    return this;
  }

  public void display(float xpos, float ypos) {
    currentFrame = (currentFrame+pace);
    if (PApplet.parseInt(currentFrame) >= frame){
      finished=true;
    } else {
      if (currentFrame < 0) {
        return;
      }
      image(images[PApplet.parseInt(currentAnimation)][PApplet.parseInt(currentFrame)], xpos, ypos);
    }
  }
}
class PopMessage {
  String message;
  int time;
  float pace,currentTime;
  int xpos;
  int ypos;
  boolean finished = false;
  
  PopMessage(String _mes, int mx, int my, float _pace, int _time) { // initialize a new object. Why is the double initialization done? Compare count->imageCount to sprWidth is only sprWidth.
    message = _mes;

    xpos = mx;
    ypos = my;
    pace = _pace;
    time = _time;
    currentTime=0;
  }
  
  public PopMessage setDelay(float delay) {
    currentTime = -delay;
    return this;
  }

  public void display(float xpos, float ypos) {
    currentTime = (currentTime+pace);
    if (PApplet.parseInt(currentTime) >= time){
      finished=true;
    } else {
      if (currentTime < 0) {
        return;
      }
      printShadedFade(message,PApplet.parseInt(xpos),PApplet.parseInt(ypos-currentTime*0.5f), PApplet.parseInt(time - currentTime));
    }
  }
}
class Player {
  String name;
  int id;
  PImage portrait;
  int gold;
  int startArea;
  boolean isAlive,isHuman;
  ArrayList <Action> actions;
  float aiIterations;
  float[] aiPreference=new float[5];
  float[] aiDiplomacy=new float[4];
  float aggression,uniFondness;
  float dominance;
  int research,maxUni;
  
  static final int upgradeCost = 10;
  
  Player (String _name, int _gold, int _startArea, int _id){
    name=_name;
    id=_id;
    portrait=loadImage("portrait"+id+".png");
    gold=_gold;
    isAlive=true;
    isHuman = (id<=humanPlayers);
    
    research=0;
    maxUni=PApplet.parseInt(random(0,5));
    uniFondness=random(1)+.5f;
    aiIterations=20;//int(random(1))+3;
    
    aiDiplomacy[0] = 0.8f;
    aiDiplomacy[1] = 0.8f;
    aiDiplomacy[2] = 0.8f;
    aiDiplomacy[3] = 0.8f;
    startArea=_startArea;
    aggression=0;
    
    actions = new ArrayList<Action>();
    int _actionLimit = (level>5) ? 5 : level ;    
    for(int _i=0;_i<_actionLimit;_i++){ 
      actions.add(new Action(_i));
    }
    
 }  
 
 public void setAIPreference(){
    aiPreference[0] = 0.8f + random(0.3f);
    aiPreference[1] = 0.8f + random(0.2f);
    aiPreference[2] = 0.8f + random(0.2f);
    aiPreference[3] = 0.8f + random(0.2f);
    aiPreference[4] = 0.8f + random(0.2f);
 }
 
 public void calcDominance(){
   float _controlled = 0;
   for (int i=0;i<areas.size();i++) {
      Area a = areas.get(i);
      if(a.ownedBy==id){
        _controlled += 1;
      }
   }
   dominance = _controlled/PApplet.parseFloat(areas.size());
   if(dominance > 0.53f){println("PLAYER",id,"IS DOMINATING!");}
 }

 public boolean hasUpgrade() {
   //println("has upgrade? " + (research >= upgradeCost));
   Boolean _upgradeable=false;
   for(int _i=0;_i<actions.size()-1;_i++){ 
      if(!actions.get(_i).upgraded){_upgradeable=true;}
    }
   return (research >= upgradeCost && _upgradeable);
 }
 
 public void upgrade(int type) {
   if (research < upgradeCost)
     return;
   if (actions.get(type).upgraded)
     return;
   research -= upgradeCost;
   actions.get(type).upgraded=true;
 }
 
 public Boolean isActionUpgraded(int _withAction){
   Boolean _itIs=false;
   for(int i=0;i<constrain(actions.size()-1,0,4);i++){
     if(i == _withAction && actions.get(i).upgraded){_itIs=true;}
   }
   return _itIs;
 }
 
 public void showActions(boolean canPressAction){
   for(int i=0;i<actions.size();i++){
    Action _a = actions.get(i);
      // todo make only one selectable at a time: _a.selected=false;
     _a.update(i,canPressAction);
   }
  if(gold*0.5f>aiIterations){aiIterations=PApplet.parseInt(gold*0.5f);}
  image(portrait,0,0);
  if(research>0){
    printShaded("RESEARCH: " + research, 32, 58);
  }
 }
 public void showGold(){
   if(playerTurn==id){
     printShaded("GOLD: " + gold, 32, 83);
     noTint();
   }else{
     //scale(2);
     noTint();
   }
   if(!isAlive){
     tint(tintByOwner(id));
      image(dead, 0,32+16+(id-2)*(player_pane.height));
   }
 }
}


public void renderGame(){
  
  if(screenShake>0.01f){
    translate(random(-screenShake,screenShake),random(-screenShake,screenShake));
    screenShake-=0.1f;
  }
  noTint();
  image(water,0,0);
  image(info_pane,0,scaledScrHeight-info_pane.height);
  noMouseOver = true;
  for(int i=0;i<areas.size();i++){
    Area a = areas.get(i);
    a.drawArea(!currentPlayer().hasUpgrade());
    noMouseOver = (a.mouseOver) ? false:noMouseOver;
  }
  
  for(int i=0;i<areas.size();i++){
    Area a = areas.get(i);
    a.drawUpgrades();
  }
  /*
  for(int i=0;i<areas.size();i++){
    Area a = areas.get(i);
    a.drawAreaText();
  }*/
  
  for (int i = anims.size()-1; i >= 0; i--) { // go through all the anims
    multiAnimObject _anim = (multiAnimObject) anims.get(i);
    _anim.display(_anim.xpos,_anim.ypos);
    
    if (_anim.finished) { // Items can be deleted with remove() from ArrayList.
      anims.remove(i);
    }
  }
  
  for (int i = popMessages.size()-1; i >= 0; i--) { // go through all the anims
    PopMessage _mes = (PopMessage) popMessages.get(i);
    _mes.display(_mes.xpos,_mes.ypos);
    
    if (_mes.finished) { // Items can be deleted with remove() from ArrayList.
      popMessages.remove(i);
    }
  }
  
  tint(250,250,200,25);
  image(glow,0,0);
  noTint(); 
  image(gui_bg,0,2);
  
  playerActions();
  playerPane();
  hasUpgrade();
  checkMusic();
}

public void checkMusic(){
  if(song.isPlaying() == false && playMusic==true) {
   playSound("song");
  }
  if(playMusic==false){
    song.pause();
  }else{
    musicAt=song.position();
  }
}

public void playerActions(){
    
  for(int i=0;i<players.size();i++){
    Player _p = players.get(i);
    _p.showGold();
    if(_p.id==playerTurn){_p.showActions(!currentPlayer().hasUpgrade());}
    
    if(_p.id==playerTurn){
      if(gameState==STATE_GAMEOVER){
        printShaded("EXIT",2*scaledScrWidth-42,2*scaledScrHeight-12);
      }else{
        if(_p.isHuman){
          endTurnButton.render();
          //printShaded("END TURN "+gameTurn,2*scaledScrWidth-42,2*scaledScrHeight-12);
        }else{
          printShaded("ENEMY TURN "+gameTurn,2*scaledScrWidth-42,2*scaledScrHeight-12);
        }
      }
    }
  }
}

public void playerPane(){
  int _placer=0;
  int _atY=32;
  for(int i=0;i<players.size();i++){
    _placer=i;    
    image(player_pane,0,_atY+(_placer*16));
    tint(tintByOwner2(i+1,color(10)));
    image(player_pane_colorplate,0,_atY+(_placer*16));
    if(i+1==playerTurn){
      tint(220,210,200);
      image(player_pane_current,0,_atY+(_placer*16));
    }
    Player _p = players.get(i);
    if(_p.isAlive){
      printShaded("GOLD: "+_p.gold+"/"+getIncome(i+1),32,_atY*2+19+(_placer*32));
    }else{
      printShaded(" - DEAD -",32,_atY*2+19+(_placer*32));
    }
    if(_p.id==1 && level == 1){
      printShaded("SELECT",32,14*12);
      printShaded("ACTION",32,15*12);
      printShaded("BELOW,",32,16*12);
      printShaded("THEN",32,17*12);
      printShaded("ATTACK",32,18*12);
      printShaded("ADJACENT",32,19*12);
      printShaded("AREA",32,20*12);
      printShaded("|",32,22*12);
      printShaded("|",32,23*12);
      printShaded("\\/",32,24*12);
    }
    noTint();
  }
}
public void hasUpgrade(){
  if(currentPlayer().hasUpgrade()){
    image(upgrade_pane,0,scaledScrHeight-info_pane.height);
    printShaded("CHOOSE UPGRADE:",PApplet.parseInt(scaledScrWidth*0.18f),2*scaledScrHeight-12);
    int _btnCount=0;
    for(int _a=0;_a<currentPlayer().actions.size()-1;_a++){
      Action _action = currentPlayer().actions.get(_a);
      if(!_action.upgraded){
        _btnCount++;
        switch(_action.type){
          case 0:
            upgradeArmyButton.x1 = PApplet.parseInt( (scaledScrWidth*0.1f) + (_btnCount*action_army.width*1.2f) );
            upgradeArmyButton.update();
          break;
          case 1:
            upgradeFortButton.x1 = PApplet.parseInt( (scaledScrWidth*0.1f) + (_btnCount*action_army.width*1.2f) );
            upgradeFortButton.update();
          break;
          case 2:
            upgradeFleetButton.x1 = PApplet.parseInt( (scaledScrWidth*0.1f) + (_btnCount*action_army.width*1.2f) );
            upgradeFleetButton.update();
          break;
          case 3:
            upgradeTradeButton.x1 = PApplet.parseInt( (scaledScrWidth*0.1f) + (_btnCount*action_army.width*1.2f) );
            upgradeTradeButton.update();
          break;
          default:
          break;
        }
      }
    }
  }
}
public void splash(){
  if(waitForClick){
    image(splash,0,0);
    ticker();
  }else{
    println("GAME STATE SET TO GENERATOR");
    gameState=STATE_GENERATOR;
    waitForClick=true;
  }
}

public void ticker(){
  if(tickerTimer+10<millis()){
    tickerTimer=millis();
    tickerPos-=0.5f;
    //println(tickerPos);    
  }
  if(tickerPos<-850) tickerPos=scrWidth*1.35f;;
    printShaded(tickerText, PApplet.parseInt(tickerPos), PApplet.parseInt(scrHeight*0.49f) );
}
  public void settings() {  size(1,1,JAVA2D);  noSmooth(); }
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "crown_and_council_B3" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}
