Pascal Pokemon Code for Windows

The full code (3000+ lines) of PascalPokemon

///////////////////////////////////////////////////////////////////////////////
///                                                                         ///
///                  PASCAL POKEMON                                         ///
///                  by Max Foster                                          ///
///                                                                         ///
///////////////////////////////////////////////////////////////////////////////

{
   Copyright (c) 2011 Max Foster 

    Licensed under the Apache License, Version 2.0 (the "License"); you may not
    use this file except in compliance with the License, as described at
    http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/

    Pokémon (c) 2002-2011 Pokémon. (c) 1995-2011 Nintendo/Creatures Inc./GAME FREAK inc. TM (R)
    and Pokémon character names are trademarks of Nintendo.

    Music Copyright (c) 1996-2010 Videogame Music Archive (VGMusic.com) and (c) 2002-2011 Pokémon.
    (c) 1995-2011 Nintendo/Creatures Inc./GAME FREAK inc. TM (R)

    No copyright or trademark infringement is intended in using Pokémon content or
    content from VGMusic.com in this program.
}

{
This is a small clone of Pokemon. It includes elements from a variety of the different
Pokemon games.


CONTROLS:
Arrow keys: Move around the map and navigate the selection screens during battle. Walk
  into people (they look like '$') or sign posts ('P') to talk to/read them
Return: Select options in battle
Backspace: Navigate to the previous menu (if any) in battle


This program is incomplete, but only because there is so much that can be added to
the game that it will take years to include everything! If you would like to add
to the game, then please do! Don't forget to show me what additions you have made,
and if you need me to explain some code in more detail, then just ask! (This may
be a problem, however, if you aren't in my school...)

Bear in mind that the code wasn't planned, and I just added whatever I felt like adding,
so some parts may appear to be... not the best way of doing things.

At the moment you can:
WORLD:
-Walk around
-Talk to people
-Read signs
-Move between different maps via doors (which are disguised as grass and paving)
-Enter wild Pokemon battles by walking around in grass
BATTLE:
-Attacking works fine and uses the real damage equation but all the stats of the
  Pokemon are not utilised so it needs to be tweaked a bit
-Switch Pokemon
-If you defeat an enemy Pokemon, and the opponent has more than 1 Pokemon, another will be sent out
-Use the bag (but there are only Potions at the moment)
-Run
-Win and lose the battle
-There are animations

Suggestions:
-Add trainer battles (there are already things in place to help with this which I
   will explain later)
-Add more types of terrain for maps
-Add buildings
-Add ability to capture wild Pokemon
-Add money
-Add a Pokemon Centre and Pokemart (or just merge them into one, because that's what
   the latest Pokemon game does)
-Add 'cutscenes'. E.g. your rival talks to you, then walks away, and while he does
   so you are unable to move, like in the real games
-Get the name of the map you are in to slide down from the top left of the screen
   working. I tried but it was really temperamental. It worked, then I changed something
   completely irrelevant, rebuilt, and it slowed the game down horribly, then next
   time it worked, and then it didn't. You get the picture.
-Add a menu for viewing Pokemon, saving, etc.
-Add a Pokedex
-Add more music
-Make a map editor
-Clean up the code and make it more efficient
-Split the code into units rather than in one massive Pascal file!
-Add soooo much more!


  /////////////////////////////////////////////////////////
 //            THE FORMAT OF THE MAP FILES              //
/////////////////////////////////////////////////////////
This is map1.txt, annotated. Lines starting with '//' are not part of the map file
and are annotations. Annotating the real map files will break them!
In the map files, there is the main map, and then there is a footer with information
about signs, doors, people, music, etc. This is all used to build a functional in-game
map! Have a play around with the map files and get to know how they work.

The actual map is 80x25 characters. If you go over this, then the game will not load
properly!
Characters used in map files (in game representations may use different characters)
'a'-'e' are doors disguised as pavement
'f'-'j' are doors disguised as grass ('*' in game)
'1'-'5' are sign posts ('P' in game)
'.' is pavement
'[' is a fence ('|' in game')
'?' is grass (where wild Pokemon may be encountered) ('*' in game)
'#' is a generic black wall
',' is mud
'"' is a plant
'~' is water

Feel free to add more!

//This is the actual map
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#fg#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,#,,,,,#??#,,,,,#,,,,",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,############??########,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,................,##,,,,,,,,,,,,,,,,,,,,,,,",,,,,,,,,,,,
,,,,",,,,,,,,,,,,,,,,,##,................,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,................,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,.1........2.....,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,................,##,,"",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,................,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,................,##,,,,,,,,,,,,,,,,,,,,,,,,,,,""",,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,..[[[3..........,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,"",,,,,,
,,,,,,,,,,",,,,,,,,,,,##,..,","..........,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,""",,,,
,,,,,,,,,,,,,,,,,,,,,,##,..",",..........,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,................,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,",,,,,,,,,,,,,,,,##,........[[[4[[..,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,",,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,,,~~~~..,",",,..,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,##,,,~~~~..",",,,..,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,"",,,,##,,,~~~~..........,##,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,###,,~~~~#############,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,##~~~~#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,#~~~~#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,#~~~~#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,#~~~~#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,#~~~~#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,#~~~~#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
//
//Below is the footer. Between each item use an underscore, and is absolutely necessary
//as the program uses these to split up the data. Putting nothing in between underscores
//is fine. Just make sure you have every single underscore there!
//
//The footer format is as follows (see below these comments to see the footer):
//
//The first line indicates the map name and the messages of the sign posts
//
//town name_sign 1_sign 2_sign_3_sign_4_sign5_
//
//As we can see below, we have a name (Pallet Town) and four signs(Your house, Rival's house, etc.).
//The last sign does not need to be filled in as there is no fifth sign on the map.
//
//
//Next is five lines that are used for each person on the map. The format is:
//
//title_name_character used for 'sprite'_gender ('b' for male, 'r' for female)_X position_
//Y position_already battled? (t = true, f = false)_before battle message_win message_
//lose message_post-battle message_
//
//As we can see below, there are two people on the map. Empty people must be entered
// as '__$__0_0______'. Make sure there are the correct number of underscores!
//The title of the person is not neccessarily 'Mr'/'Mrs'/etc. but it is the adjective
//of the person. E.g. Bugcatcher, Rival,  Leader, etc. The messages are explained below
//where the types are declared in the program.
//This is what the first line is telling the program:
//Make a Man called Fred, that looks like '$' and is male. He is stationed at coordinates
//(34, 17) and he already battled the trainer (he actually hasn't but it is a trick
//to use if you want to make a normal person rather than a trainer that wants to battle)
//He does not have anything to say to the player except he will say "Hello Man!" when
//the player talks to him if it appears as if he has already battled.
//
//
//Next is a line indicating which map each door goes to. It only works for grass
//doors at the moment, so another line will need to be added for other types of door.
//The format is:
//
// 1st door map_2nd door map_3rd door map_4th door map_5th door map_
//
//As we can see below each door goes to map 2. Make sure you reference another map
//even if the door doesn't exist!
//
//
//Lastly is a line indicating the which music to use as background music for the map,
//located in the 'sounds' folder (it MUST be in the sounds folder! (Unless you edit the
//code, of course)). The format is simply: filename of music_
//
//The footer:
Pallet Town_Your house_Rival's house_Pallet Town_Prof. Oak's Lab__
Man_Fred_$_b_34_17_t____Hello man!_
Woman_Sarah_$_r_28_10_t____I love Pallet town_
__$__0_0______
__$__0_0______
__$__0_0______
2_2_2_2_2_
pallettown.mid_

////////////////////////////////////////////////////////
////////////////////////////////////////////////////////


Now onto the code!
} 
program PascalPokemon;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, Windows, Crt , Math{, SDL, SDL_Mixer};
  //Include SDL and SDL_Mixer if you want music. You will also need SDL.dll and
  //SDL_mixer.dll. I will indicate which parts of the code to uncomment if you want music

type
  //A record type for a Pokemon move
  TMove = record
     ID: integer;
     Name: string[15];
     //Stats of the move
     Type1: string[15];
     Power: integer;
     Accuracy: integer;
     Points: integer;
     //Animation color and the animation itself
     Color: byte;
     Ani: array[1..4] of array[1..5] of string;
  end;

//A record type for a Pokemon. There are records for the 'Pokedex' Pokemon (Pokemon
//that are there as a reference to pull base stats from) and records for 'live' Pokemon
//(Pokemon that actually exist in the game and fight in battles)
  TPokemon = record
     Name: string[15];
     Nickname : string[15];
     //Stats
     Type1: string[15];
     Type2: string[15];
     Level: integer;
     OrigHP: integer;  //The maximum Health Points a Pokemon can have
     HP: integer;      //The current HP
     NormAtt: integer;
     NormDef: integer;
     SpecAtt: integer;
     SpecDef: integer;
     Speed: integer;
     Gender: Byte;  //Use "blue" for male and "red" for female. Do not include speech marks!
     Exp: Longint;  //Experience. Not used yet
     Move: array[1..4] of TMove;    //The four moves the Pokemon has
     //The art and color of the Pokemon
     Art: array[1..5] of string[14];
     Color: Byte;
     CrySound: string;  //The path for the sound file that contains a Pokemon's cry. Not used yet
  end;

//A trainer class. This is any person in the game, including people who don't battle and you
  TTrainer = class(TObject)
    public
      Title, Name : string;
      Sprite : char;         //The 'image' of the player. Currently '$'
      Color : byte;
      X, Y, Map : integer;
      Pokemon : array[1..6] of TPokemon;  //The Pokemon the person has
      IsPlayer, AlreadyBattled : boolean; //AlreadyBattled is set to true by default for people you don't battle
      //BattleMessage is the message that the person is says before battle. WinMessage/LoseMessage is for
      //if they win or lose the battle (when the battle has ended but before you go back to
      //the map) and AfterMessage is the message they say if AlreadyBattled is true
      BattleMessage, WinMessage, LoseMessage, AfterMessage : string;
      procedure SetBackColor;
      procedure Up;
      procedure Down;
      procedure Left;
      procedure Right;
      procedure Sit;
  end;

  //A trainer record type for storing people in a certain map that do not necessarily exist in the game yet
  TTrainerRecord = record
      Title, Name : string;
      Sprite : char;
      Color : byte;
      X, Y, Map : integer;
      Pokemon : array[1..6] of TPokemon;
      IsPlayer, AlreadyBattled : boolean;
      BattleMessage, WinMessage, LoseMessage, AfterMessage : string;
  end;

  //A map record type for each map in the game
  TMap = record
     Name : string;
     Data : array[1..80,1..25] of char;       //All the map data (excluding the footer of the map files)
     Sign : array[1..5] of string;            //The messages for up to 5 sign posts on the map
     People : array[1..5] of TTrainerRecord;  //The trainer records for the map (up to 5)
     Door : array[1..5] of integer;           //Indicates what door goes to what map
     Music : string;                          //The path of the music file for the map
  end;

//Some constants for music. Uncomment this if you want to have music
{
const
AUDIO_FREQUENCY:INTEGER=44100;
AUDIO_FORMAT:WORD=AUDIO_S16;
AUDIO_CHANNELS:INTEGER=2;
AUDIO_CHUNKSIZE:INTEGER=4096;
}

var
  player : TTrainer;
  person : array[1..5] of TTrainer;   //The instances of the people in the current map
  maps : array[1..3] of TMap;         //All the maps in the game
  null, tackle, scratch, vinewhip, razorleaf: TMove;    //All the moves. Null is for moves unfilled move slots for a Pokemon
  allpokemon : array[0..9] of TPokemon;   //All the Pokemon in the game
  //The player's pokemon, copies of the player's Pokemon that are used in battle, and the opponent's Pokemon
  yourpoke, yourbattlepoke, battlepoke : array[1..6] of TPokemon;
  currentpoke, currentbattlepoke, choosepoke, currentmove, i, damage,
               actionchoice, itemchoice, battleended, signnum, personnum,
               mapcounter : integer;
  fight, fighting, entered, bagopen, playsound, yourpokemonfainted, enemypokemonfainted,
         pokemonchoosing, pokemonchoosingoptions, drawmarker, inbattle,
         wildpokemonbattle, trainerpokemonbattle, viewingsign, talking,
         changingmap, mapdrawn : boolean;
  battletypetxt, option : string;
  launchanimation : array[1..4] of array[1..5] of string[14];
  playerbackimage : array[1..5] of string[14];
  itemcount: array[1..3] of integer;
  itemname: array[1..3] of string = ('Potion','Super Potion','Hyper Potion');
  {sound_music:pMIX_MUSIC=NIL;
  soundchannel:integer; } //More music code that you can uncomment

  {Some helpful reference:
  Item numbers:
  1: potion
  2: super potion
  3: hyper potion

  SPECIAL CHARACTERS:
   chr(2) : shaded in smiley face e

  COLORS (for text_color and text_background):
    Black         = 0;
    Blue          = 1;
    Green         = 2;
    Cyan          = 3;
    Red           = 4;
    Magenta       = 5;
    Brown         = 6;
    LightGray     = 7;

   Foreground color constants
    DarkGray      = 8;
    LightBlue     = 9;
    LightGreen    = 10;
    LightCyan     = 11;
    LightRed      = 12;
    LightMagenta  = 13;
    Yellow        = 14;
    White         = 15;
  }

//Uncomment the following two procedures for music
{
procedure initSDL;
begin
     if (SDL_Init(SDL_INIT_AUDIO) <> 0) then begin writeln('Error Initiliasing the audio');
     readln;
     Halt;
     end
     else
     begin writeln('Initiliased the audio'); end;

  IF MIX_OPENAUDIO(AUDIO_FREQUENCY, AUDIO_FORMAT,AUDIO_CHANNELS, AUDIO_CHUNKSIZE)<>0 THEN HALT;
  sound_music:=MIX_LOADMUS('sounds/theme.mid');
  MIX_PLAYMUSIC(sound_music,-1);

end;

procedure ExitGame;
begin

  MIX_HALTCHANNEL(soundchannel);
  MIX_HALTMUSIC;
  MIX_CLOSEAUDIO;

  SDL_quit;
end;
}

procedure FindMapSpace(tofind:char; var myarray:array of integer);
//Scans the map and finds where a particular map piece is. Used for locating doors
//E.g. If you want to put the player at door 'g' then it will scan the map and return
//the X and Y position of door 'g', so you can then put the player there
var
  j, k, l, m :integer;
begin
  for j := 1 to 25 do
    begin
      for k := 1 to 80 do
        begin
          if maps[player.Map].Data[k,j] = tofind then
            begin
              l := k;
              m := j;
            end;
        end;
    end;
  myarray[0] := l; //x
  myarray[1] := m; //y
end;

procedure ChangeMap;
var
  j:integer;
  mapchar : char;
  myarray : array[0..1] of integer;
begin
  changingmap := true;
  mapchar := maps[player.Map].Data[player.X,player.Y];
  case mapchar of
    'f': Player.Map := maps[Player.Map].door[1];
    'g': Player.Map := maps[Player.Map].door[2];
    'h': Player.Map := maps[Player.Map].door[3];
    'i': Player.Map := maps[Player.Map].door[4];
    'j': Player.Map := maps[Player.Map].door[5];
  end;
  clrscr;
  mapdrawn := false;
  FindMapSpace(mapchar, myarray);
  Player.X := myarray[0];
  Player.Y := myarray[1];
end;

procedure DrawMapSpace(mapx : integer; mapy : integer);
var
  datatowrite : char;
begin
  gotoXY(mapx,mapy);
  datatowrite := maps[player.Map].Data[mapx,mapy];
  case datatowrite of
    '.': begin //path
           textBackground(white);
           write(' ');
         end;
    ',': begin //mud
           textBackground(brown);
           write(' ');
         end;
    '"': begin //dirt with plant
           textBackground(brown);
           textColor(green);
           write(':');
         end;
    '#': begin //black wall
           textBackground(black);
           write(' ');
         end;
    '[': begin //fence
           textBackground(white);
           textColor(black);
           write('|');
         end;
    '?': begin //grass. Wild Pokemon battles can happen here
           textBackground(green);
           textColor(lightgreen);
           write('*');
         end;
    '1','2','3','4','5': begin //sign
                           textBackground(white);
                           textColor(darkgray);
                           write('P');
                         end;
    '~': begin //water
           textBackground(blue);
           textColor(lightblue);
           write('~');
         end;
    'a','b','c','d','e': begin //doors
                           textBackground(white);
                           write(' ');
                         end;
    'f','g','h','i','j': begin //grass doors. Wild Pokemon battles cannot happen here
                           textBackground(green);
                           textColor(lightgreen);
                           write('*');
                         end;
  end;
end;

function CheckSpace(gox : integer; goy : integer; map : integer; check : boolean) : boolean;
//Checks if the space is free and initiates talking or reading of signs
var
  j : integer;
  datatocheck : char;
begin
  datatocheck := maps[map].Data[gox,goy];
  case datatocheck of
    '#','~','[': result := false;
    '1','2','3','4','5' : begin
                            if check then
                              begin
                                viewingsign := true;
                                signnum := StrToInt(datatocheck);
                              end;
                            result := false;
                          end;
    else
      result := true;
  end;
  for j := 1 to 5 do
    begin
      if person[j] <> nil then
        begin
          if (gox = person[j].X) and (goy = person[j].Y) then
            begin
              if check then
                begin
                  talking := true;
                  personnum := j;
                end;
              result := false;
            end;
        end;
    end;
  if not check then
    begin
      if (gox = player.X) and (goy = player.Y) then
        result := false;
     end;
     if (gox = 0) or (goy = 0) or (gox = 81) or (goy = 26) then
       result := false;
end;

procedure TTrainer.SetBackColor;
//Makes sure the colour behind a person is the colour of the map piece they are standing on
var
  datatowrite : char;
begin
  datatowrite := maps[Map].Data[X,Y];
  case datatowrite of
    '.': textBackground(white);
    ',': textBackground(brown);
    '"': textBackground(brown);
    '?': begin
           textBackground(green);
           if IsPlayer then
             if random(6) = 1 then
               wildpokemonbattle := true;
         end;
    'a','b','c','d','e': textBackground(white);
    'f','g','h','i','j': begin
                           textbackground(green);
                           if changingmap then
                             changingmap := false
                           else
                             ChangeMap;
                         end;
  end;
end;

procedure TTrainer.Sit;
//Do nothing. Useful for if a chatbox appears on top of a trainer
begin
  DrawMapSpace(X,Y);
  gotoXY(X,Y);
  SetBackColor;
  textColor(Color);
  write(Sprite);
  textColor(black);
end;

procedure TTrainer.Up;
begin
  if CheckSpace(X,Y-1,Map,IsPlayer) then
    begin
      DrawMapSpace(X,Y);
      Y -= 1;
      gotoXY(X,Y);
      SetBackColor;
      textColor(Color);
      write(Sprite);
      textColor(black);
    end;
end;

procedure TTrainer.Down;
begin
  if CheckSpace(X,Y+1,Map,IsPlayer) then
    begin
      DrawMapSpace(X,Y);
      Y += 1;
      gotoXY(X,Y);
      SetBackColor;
      textColor(Color);
      write(Sprite);
      textColor(black);
    end;
end;

procedure TTrainer.Left;
begin
  if CheckSpace(X-1,Y,Map,IsPlayer) then
    begin
      DrawMapSpace(X,Y);
      X -= 1;
      gotoXY(X,Y);
      SetBackColor;
      textColor(Color);
      write(Sprite);
      textColor(black);
    end;
end;
procedure TTrainer.Right;
begin
  if CheckSpace(X+1,Y,Map,IsPlayer) then
    begin
      DrawMapSpace(X,Y);
      X += 1;
      gotoXY(X,Y);
      SetBackColor;
      textColor(Color);
      write(Sprite);
      textColor(black);
    end;
end;

procedure PersonAI;
//Make the people walk around
var
  j, selection : integer;
begin
  for j := 1 to 5 do
  if person[j] <> nil then
    begin
      if random(2000) = 1439 then
        begin
          selection := random(4);
          case selection of
            1: person[j].Left;
            2: person[j].Right;
            3: person[j].Up;
            4: person[j].Down;
          end;
        end;
    end;
end;

procedure TakeCareOfMapcounter;
//For displaying the map name drop down on the top left corner
var
  j: integer;
begin
  case mapcounter of
    0: begin
         textbackground(white);
         gotoXY(1,1);
         write('                     ');
         inc(mapcounter);
      end;
    50: begin
          textbackground(white);
          gotoXY(2,1);
          write(maps[player.Map].Name);
          gotoXY(1,2);
          write('                     ');
       end;
    100: begin
           textbackground(white);
           gotoXY(1,1);
           write('                     ');
           gotoXY(2,2);
           write(maps[player.Map].Name);
           gotoXY(1,3);
           write('                     ');
         end;
    2000: begin
            textbackground(white);
            gotoXY(2,1);
            write(maps[player.Map].Name);
            gotoXY(1,2);
            write('                     ');
            for j := 1 to 21 do
              DrawMapSpace(j,3);
          end;
    2050: begin
            textbackground(white);
            gotoXY(1,1);
            write('                     ');
            for j := 1 to 21 do
              DrawMapSpace(j,2);
          end;
    2100: begin
            inc(mapcounter);
            for j := 1 to 21 do
              DrawMapSpace(j,1);
         end;
  end;
end;

procedure DoMapcounterStuff;
begin
  if (mapcounter > 0) and (mapcounter < 2101) then
    begin
      inc(mapcounter);
      TakeCareOfMapcounter;
    end
  else if mapcounter = 0 then
     TakeCareOfMapcounter;
  PersonAI;
  sleep(1);
end;

procedure Beep(freq : longint; time : longint);
//Only works when hardware beeping is enabled on your computer
begin
  if playsound then
    Windows.beep(freq, time)
  else sleep(time);
end;

procedure DisplayMessage(mess1 : string; gox : integer; goy : integer);
var
  j : integer;
begin
  for i := 0 to length(mess1) do
    begin
      textbackground(white);
      gotoXY(gox, goy);
      write(leftstr(mess1,i));
      if (mapcounter > 0) and (mapcounter < 2101) then
        begin
          j := 0;
          repeat
            DoMapcounterStuff;
            j += 1;
          until j = 20
        end
      else
        sleep(20);
     end;
end;

procedure ClearMessage(gox : integer; goy : integer);
begin
  gotoXY(gox, goy);
  write('                                          ');
  gotoXY(1,1);
end;

////////////////////////////////////////////////////////////////////////////////
///////////////////    BATTLE STUFF     ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
procedure DrawYourHealth;
var
  myfloat: float;
  myhp: integer;
begin
  myfloat := (yourbattlepoke[currentpoke].HP/yourbattlepoke[currentpoke].OrigHP)*20;
  myhp := round(myfloat+0.5);
  gotoXY(54,13);
  if myhp > 10 then
    textbackground(Green)
  else if myhp > 5 then
    textbackground(yellow)
  else
    textbackground(red);
  for i := 1 to 20 do
    begin
      gotoXY(53+i,13);
      if i > myhp then
        textbackground(DarkGray);
      write(' ');
    end;
  textbackground(white);
  textColor(black);
  gotoXY(56,14);
  write('   ');
  gotoXY(57,14);
  write(yourbattlepoke[currentpoke].HP);
end;

procedure DrawEnemyHealth;
var
  enemyfloat: float;
  enemyhp: integer;
begin
  enemyfloat := (battlepoke[currentbattlepoke].HP/battlepoke[currentbattlepoke].OrigHP)*20;
  enemyhp := round(enemyfloat+0.5);
  gotoXY(8,3);
  if enemyhp > 10 then
    textbackground(Green)
  else if enemyhp > 5 then
    textbackground(yellow)
  else
    textbackground(red);
  for i := 1 to 20 do
    begin
      gotoXY(7+i,3);
      if i > enemyhp then
        textbackground(DarkGray);
      write(' ');
    end;
  textbackground(white);
end;

procedure DrawBattleHealth;
begin
  DrawYourHealth;
  DrawEnemyHealth;
end;

procedure FlipChar(var chartoflip : char);
begin
  case chartoflip of
    '\' : chartoflip := '/';
    '/' : chartoflip := '\';
    '(' : chartoflip := ')';
    ')' : chartoflip := '(';
    '>' : chartoflip := '<';
    '<' : chartoflip := '>';
  end;
end;

procedure FlipPokemonArt(var poketoflip : TPokemon);
//Extremely useful so only one image of a Pokemon is needed and it will be flipped
//depending on whether it is the player's Pokemon or the opponent's
var
  leftchar: char;
  j, k: integer;
begin
  for j := 1 to 5 do
    begin
      for k := 1 to 7 do
        begin
          leftchar := poketoflip.Art[j][k];
          poketoflip.Art[j][k] := poketoflip.Art[j][15-k];
          poketoflip.Art[j][15-k] := leftchar;
          FlipChar(poketoflip.Art[j][k]);
          FlipChar(poketoflip.Art[j][15-k]);
        end;
    end;
end;

/////////////ANIMATIONS//////////////////////////
procedure SlideInAnimation(image : array of string[14]; color : byte;
                           gox : integer; goy : integer; direction : integer;
                           image2 : array of string[14]; color2 : byte;
                           gox2 : integer; goy2 : integer); //image2 must be bottom image
//For the classic Pokemon slide at the beginning of a battle!
var
  j, k : integer;
begin
  textColor(color);
  case direction of
    0 : begin
          for j := 40 downto 0 do
            begin
              for k := 0 to 4 do
                begin
                  gotoXY(gox-j,goy+k);
                  write(image[k]);
                end;
              sleep(25);
              for k := 1 to 5 do
                begin
                  gotoXY(gox-j,goy+k-1);
                  write('              ');
                end;
            end;
        end;
    1 : begin
          for j := 40 downto 0 do
            begin
              for k := 0 to 4 do
                begin
                  gotoXY(gox+j,goy+k);
                  write(image[k]);
                end;
              sleep(25);
              for k := 1 to 5 do
                begin
                  gotoXY(gox+j,goy+k);
                  write('              ');
                end;
            end;
        end;
    2 : begin
          for j := 40 downto 0 do
            begin
              for k := 0 to 4 do
                begin
                  textcolor(color);
                  gotoXY(gox-j,goy+k);
                  write(image[k]);
                  textcolor(color2);
                  gotoXY(gox2+j,goy2+k);
                  write(image2[k]);
                end;
               sleep(25);
               for k := 1 to 5 do
                 begin
                   gotoXY(gox-j,goy+k-1);
                   write('              ');
                   gotoXY(gox2+j,goy2+k);
                   write('              ');
                 end;
            end;
        end;
  end;
  textColor(black);
end;

procedure SendAnimation(gox : integer; goy : integer; direction : boolean);
//Animation for a Pokeball throw to release a Pokemon
var
  j, k: integer;
begin
  textColor(red);
  if direction then
    begin
      gotoXY(gox-1,goy+2);
      write('O');
      sleep(100);
      gotoXY(gox-1,goy+2);
      write(' ');
      gotoXY(gox+1,goy);
      write('O');
      sleep(100);
      gotoXY(gox+1,goy);
      write(' ');
      gotoXY(gox+3,goy-1);
      write('O');
      sleep(100);
      gotoXY(gox+3,goy-1);
      write(' ');
      gotoXY(gox+5,goy);
      write('O');
      sleep(100);
      gotoXY(gox+5,goy);
      write(' ');
      gotoXY(gox+7,goy+2);
      write('O');
      sleep(100);
      gotoXY(gox+7,goy+2);
      write(' ');
    end
  else
    begin
      gotoXY(gox+14,goy+2);
      write('O');
      sleep(100);
      gotoXY(gox+14,goy+2);
      write(' ');
      gotoXY(gox+12,goy);
      write('O');
      sleep(100);
      gotoXY(gox+12,goy);
      write(' ');
      sleep(100);
      gotoXY(gox+8,goy);
      write('O');
      sleep(100);
      gotoXY(gox+8,goy);
      write(' ');
      gotoXY(gox+6,goy+2);
      write('O');
      sleep(100);
      gotoXY(gox+6,goy+2);
      write(' ');
    end;
  textColor(darkgray);
  for j := 1 to 4 do
    begin
      for k := 1 to 5 do
        begin
          gotoXY(gox,goy+k);
          write(launchanimation[j][k]);
        end;
      sleep(100);
      end;
  gotoXY(gox,goy);
  write('              ');
  gotoXY(gox,goy+4);
  write('              ');
  sleep(100);
  textColor(black);
end;

procedure RecieveAnimation(gox : integer; goy : integer);
//Animation for returning a Pokemon to its Pokeball
var
  j, k: integer;
begin
  textColor(darkgray);
  for j := 4 downto 1 do
    begin
      for k := 1 to 5 do
        begin
          gotoXY(gox,goy+k);
          write(launchanimation[j][k]);
        end;
      sleep(100);
    end;

  gotoXY(gox+6,goy+3);
  write('  ');

  textColor(red);
  for j := 1 to 5 do
    begin
      gotoXY(gox+6,goy+j+1);
      write(' ');
      gotoXY(gox+6,goy+j+2);
      write('O');
      sleep(100);
    end;
  gotoXY(gox+6,goy+7);
  write(' ');
  textColor(black);
end;

procedure ClearImage(gox : integer; goy : integer);
var
  j : integer;
begin
  for j := 0 to 4 do
    begin
      gotoXY(gox,goy+j);
      write('              ');
    end;
end;

procedure DrawImage(image : array of string[14]; color : byte; gox : integer; goy : integer);
var
  j : integer;
begin
  textColor(color);
  for j := 0 to 4 do
    begin
      gotoXY(gox,goy+j);
      write(image[j]);
    end;
  textColor(black);
end;

//////////////ITEM SUBROUTINES/////////////////////////////
procedure UsePotion(var useon : TPokemon);
var
  u : integer;
begin
  for u := 1 to 20 do
    begin
      useon.HP += 1;
      if useon.HP > useon.OrigHP then
        useon.HP := useon.OrigHP;
      DrawBattleHealth;
      Beep(440+(u*22),30);
    end;
end;

procedure UseSuperPotion(var useon : TPokemon);
var
  u, maxheal, toheal, healed, v : integer;
begin
  maxheal := 50;
  healed := 0;
  for u := 1 to 20 do
    begin
      for v := 3 downto 0 do
        begin
          if healed+v <= maxheal then
            begin
              toheal := v;
              break;
            end;
        end;
      healed += toheal;
      useon.HP += toheal;
      if useon.HP > useon.OrigHP then
        useon.HP := useon.OrigHP;
      DrawBattleHealth;
      Beep(880+(u*44),30);
    end;
end;

procedure UseHyperPotion(var useon : TPokemon);
var
  u, maxheal, toheal, healed, v : integer;
begin
  maxheal := 200;
  healed := 0;
  for u := 1 to 20 do
  begin
    for v := 10 downto 0 do
      begin
        if healed+v <= maxheal then
          begin
            toheal := v;
            break;
          end;
      end;
    gotoXY(12,12);
    write(toheal);
    healed += toheal;
    useon.HP += toheal;
    if useon.HP > useon.OrigHP then
      useon.HP := useon.OrigHP;
    DrawBattleHealth;
    Beep(1760+(u*88),30);
  end;
end;
/////////////END OF ITEM SUBROUTINES///////////////////////

//Battle Options are the choices you have during a battle to select from (fight, bag, run, etc.)
procedure DrawBattleOptionsMarker;
begin
  case actionchoice of
    1: gotoXY(55,21);
    2: gotoXY(68,21);
    3: gotoXY(55,23);
    4: gotoXY(68,23);
  end;
  write('>');
end;

procedure ClearBattleOptionsMarker;
begin
  case actionchoice of
    1: gotoXY(55,21);
    2: gotoXY(68,21);
    3: gotoXY(55,23);
    4: gotoXY(68,23);
  end;
  write(' ');
end;

procedure ClearBattleOptions;
begin
  ClearBattleOptionsMarker;
  gotoXY(56,21);
  write('                         ');
  gotoXY(56,23);
  write('                         ');
end;

procedure DrawBattleOptions;
begin
  ClearBattleOptions;
  if not fighting then
    begin
      gotoXY(56,21);
      if fight then
        write(yourbattlepoke[currentpoke].Move[1].Name)
        else if pokemonchoosing then
          write('SWITCH')
        else
          write('FIGHT');
      gotoXY(69,21);
      if fight then
        write(yourbattlepoke[currentpoke].Move[2].Name)
      else if pokemonchoosing then
        write('CANCEL')
      else
        write('BAG');
      gotoXY(56, 23);
      if fight then
        write(yourbattlepoke[currentpoke].Move[3].Name)
      else if not pokemonchoosing then
        write('POKeMON');
      gotoXY(69,23);
      if fight then
        write(yourbattlepoke[currentpoke].Move[4].Name)
      else if not pokemonchoosing then
        write('RUN');
    end;
  if entered then
    DrawBattleOptionsMarker;
  gotoXY(1,1);
end;

procedure DrawBattleMenu;
begin
  gotoXY(48,18);
  write('_________________________________');
  for i := 1 to 7 do
    begin
      gotoXY(19,18+i);
      write('|':30);
    end;
  for i := 0 to 46 do
    begin
      gotoXY(1+i, 20);
      write('_');
    end;
  if entered then
    DrawBattleOptions;
end;

procedure DrawYourBattlePokemon;
begin
  textColor(yourbattlepoke[currentpoke].Color);
  for i:= 1 to 5 do
    begin
      gotoXY(3,i+11);
      write(yourbattlepoke[currentpoke].Art[i]);
    end;
  textColor(black);
end;

procedure DrawEnemyPokemon;
begin
   textColor(battlepoke[currentbattlepoke].Color);
   for i := 1 to 5 do
     begin
       gotoXY(60,i+1);
       write(battlepoke[currentbattlepoke].Art[i]);
     end;
   textColor(black);
end;

procedure DrawPokemon;
begin
  DrawYourBattlePokemon;
  DrawEnemyPokemon;
end;

procedure DrawYourStats;
begin
  gotoXY(50,12);
  write(yourbattlepoke[currentpoke].Nickname);
  textbackground(yourbattlepoke[currentpoke].Gender);
  write(' ');
  textbackground(white);
  gotoXY(71,12);
  write('Lv', yourbattlepoke[currentpoke].Level);
  gotoXY(50,13);
  write('HP: ');
  textColor(DarkGray);
  gotoXY(49,11);
  write('__________________________');
  gotoXY(49,15);
  write('__________________________');
  gotoXY(49,12);
  write('|');
  gotoXY(49,13);
  write('|');
  gotoXY(49,14);
  write('|');
  gotoXY(49,15);
  write('|');
  gotoXY(75,12);
  write('|');
  gotoXY(75,13);
  write('|');
  gotoXY(75,14);
  write('|');
  gotoXY(75,15);
  write('|');
  textColor(Black);
  gotoXY(60,14);
  write('/   ',yourbattlepoke[currentpoke].OrigHP);
end;

procedure DrawEnemyStats;
begin
  textColor(black);
  gotoXY(4,2);
  write(battlepoke[currentbattlepoke].Name);
  textbackground(battlepoke[currentbattlepoke].Gender);
  write(' ');
  textbackground(white);
  gotoXY(25,2);
  write('Lv', battlepoke[currentbattlepoke].Level);
  gotoXY(4,3);
  write('HP: ');
  textColor(DarkGray);
  gotoXY(3,1);
  write('__________________________');
  gotoXY(3,4);
  write('__________________________');
  gotoXY(3,2);
  write('|');
  gotoXY(3,3);
  write('|');
  gotoXY(3,4);
  write('|');
  gotoXY(29,2);
  write('|');
  gotoXY(29,3);
  write('|');
  gotoXY(29,4);
  write('|');
  textColor(black);
end;

procedure ClearYourStats;
var
  j : integer;
begin
  for j := 0 to 4 do
    begin
      gotoXY(49,11+j);
      write('                           ');
    end;
end;

procedure ClearEnemyStats;
var
  j : integer;
begin
  for j := 0 to 3 do
    begin
      gotoXY(3,1+j);
      write('                           ');
    end;
end;

procedure DrawBattle;
begin
  DrawYourStats;
  DrawEnemyStats;
  DrawBattleHealth;
  DrawBattleMenu;
end;

//Pokemon Select is the screen that comes up when you switch a Pokemon
procedure ClearPokemonSelectMarker;
var
  k :integer;
begin
  for k := 1 to 6 do
    begin
      gotoXY(3,(k*2)+k);
      write(' ');
    end;
end;

procedure DrawPokemonSelectMarker;
begin
  ClearPokemonSelectMarker;
  gotoXY(3,(choosepoke*2)+choosepoke);
  write('>');
end;

procedure DrawPokemonSelect;
var
  k, myhp : integer;
  myfloat: float;
begin
  pokemonchoosing := true;
  pokemonchoosingoptions := false;
  choosepoke := currentpoke;
  ClearBattleOptions;
  for k := 1 to 17 do
    begin
      gotoXY(1,k);
      write('                                                                                ');
    end;
  ClearMessage(2,22);
  gotoXY(2,22);
  write('Choose a POKeMON.');
  for k := 1 to 6 do
    begin
      if not(yourbattlepoke[k].Name = allpokemon[0].Name) then
        begin
          gotoXY(5,(k*2)+k);
          textColor(yourbattlepoke[k].Color);
          write(chr(2),' ');
          if k = currentpoke then
            textColor(blue)
          else
            textColor(black);
          write(yourbattlepoke[k].Nickname);
          textColor(black);
          textBackground(yourbattlepoke[k].Gender);
          write(' ');
          textBackground(white);
          gotoXY(21,(k*2)+k);
          write(':L', yourbattlepoke[k].Level);
          gotoXY(8,(k*2)+k+1);
          write('HP:');

          myfloat := (yourbattlepoke[k].HP/yourbattlepoke[k].OrigHP)*10;
          myhp := round(myfloat+0.5);
          if myhp > 5 then
            textbackground(Green)
          else
            if myhp > 2 then
              textbackground(yellow)
            else
              textbackground(red);
          for i := 1 to 10 do
            begin
              gotoXY(10+i,(k*2)+k+1);
              if i > myhp then
                textbackground(DarkGray);
              write(' ');
            end;

          textBackground(white);
          write('  ', yourbattlepoke[k].HP);
          gotoXY(26,(k*2)+k+1);
          write('/ ',yourbattlepoke[k].OrigHP);
        end;
    end;
  DrawPokemonSelectMarker;
end;

///////////////BATTLE SUBROUTINES//////////////////////////
//xopp/yopp is the opponent's Pokemon's X/Y position, and xyou/yyou is yours
procedure InflictDamage(var attacker : TPokemon; var victim : TPokemon; whichmove: integer; xopp: integer; yopp: integer);
var
  k, l, m, j : integer;
  flashed : boolean;
begin
  flashed := false;
  damage := (round(((((((((((2*attacker.Level)/5)+2)*attacker.NormAtt*attacker.Move[whichmove].Power)/victim.NormDef)/50)+2)*1)*1/10)*(random(38)+217))/25))*2;
  textColor(victim.Color);
  for k := 1 to 11 do
    begin
      if flashed then
        begin
          flashed := false;
          for l := 1 to 5 do
            begin
              gotoXY(xopp,l+yopp);
              write('               ');
            end;
        end
      else
        begin
          flashed := true;
          for m := 1 to 5 do
            begin
              gotoXY(xopp,m+yopp);
              write(victim.Art[m]);
            end;
          end;
          sleep(100);
    end;
  textColor(black);
  sleep(1000);
  for j := 1 to damage do
    begin
      victim.HP -= 1;
      if victim.HP < 0 then
        victim.HP := 0;
      DrawBattleHealth;
      sleep(30);
    end;
end;

////////////////////////////////////////////////////
//                     MOVES
//FOR THE DIRECTION, TRUE IS FOR PLAYER ATTACK, FALSE IS FOR FOES ATTACK
////////////////////////////////////////////////////

procedure DoTackle(var attacker : TPokemon; var victim : TPokemon; whichmove: integer; xopp: integer; yopp: integer; xyou : integer; yyou: integer; direction: boolean);
var
  t, u: integer;
begin
  textcolor(attacker.Color);
  for t := 0 to 5 do
    begin
      for u := 1 to 5 do
        begin
          if direction then
            begin
              gotoXY(xyou+t,yyou+u);
              write('               ');
              gotoXY(xyou+t+1,yyou+u);
              write(attacker.Art[u]);
            end
          else
            begin
              gotoXY(xyou-t,yyou+u);
              write('               ');
              gotoXY(xyou-t-1,yyou+u);
              write(attacker.Art[u]);
            end;
        end;
      sleep(5);
    end;

  textcolor(black);
  for u := 1 to 5 do
    begin
      case u of
        1: begin
             gotoXY(xopp+3,yopp+u);
             write('**  **');
           end;
        2: begin
             gotoXY(xopp+5,yopp+u);
             write('**');
           end;
        3: begin
             gotoXY(xopp+3,yopp+u);
             write('******');
           end;
        4: begin
             gotoXY(xopp+5,yopp+u);
             write('**');
           end;
        5: begin
             gotoXY(xopp+3,yopp+u);
             write('**  **');
           end;
        end;
    end;
  sleep(200);

  textColor(victim.Color);
  for u := 1 to 5 do
    begin
      gotoXY(xopp,u+yopp);
      write(victim.Art[u]);
    end;

  textcolor(attacker.Color);
  for t := 5 downto 0 do
    begin
      for u := 1 to 5 do
        begin
          if direction then
            begin
              gotoXY(xyou+t+1,yyou+u);
              write('               ');
              gotoXY(xyou+t,yyou+u);
              write(attacker.Art[u]);
            end
          else
            begin
              gotoXY(xyou-t-1,yyou+u);
              write('               ');
              gotoXY(xyou-t,yyou+u);
              write(attacker.Art[u]);
            end;
        end;
      sleep(5);
    end;
  sleep(500);
  textcolor(black);
  InflictDamage(attacker, victim, whichmove, xopp, yopp);
end;

procedure DoScratch(var attacker : TPokemon; var victim : TPokemon; whichmove: integer; xopp: integer; yopp: integer; xyou : integer; yyou: integer; direction: boolean);
var
  t, u : integer;
begin
  textcolor(black);
  for t := 1 to 4 do
    begin
      for u := 1 to 5 do
        begin
          textcolor(victim.Color);
          gotoXY(xopp,u+yopp);
          write(victim.Art[u]);
        end;
      textcolor(black);
      case t of
        1 : begin
              gotoXY(xopp+2,yopp+2);
              write('*');
              gotoXY(xopp+4,yopp+2);
              write('*');
              gotoXY(xopp+6,yopp+2);
              write('*');
            end;

        2 : begin
              gotoXY(xopp+3,yopp+3);
              write('*');
              gotoXY(xopp+5,yopp+3);
              write('*');
              gotoXY(xopp+7,yopp+3);
              write('*');
              textcolor(red);
              gotoXY(xopp+2,yopp+2);
              write('\');
              gotoXY(xopp+4,yopp+2);
              write('\');
              gotoXY(xopp+6,yopp+2);
              write('\');
            end;

        3 : begin
              gotoXY(xopp+4,yopp+4);
              write('*');
              gotoXY(xopp+6,yopp+4);
              write('*');
              gotoXY(xopp+8,yopp+4);
              write('*');
              textcolor(red);
              gotoXY(xopp+3,yopp+3);
              write('\');
              gotoXY(xopp+5,yopp+3);
              write('\');
              gotoXY(xopp+7,yopp+3);
              write('\');
              gotoXY(xopp+2,yopp+2);
              write('\');
              gotoXY(xopp+4,yopp+2);
              write('\');
              gotoXY(xopp+6,yopp+2);
              write('\');
            end;

        4 : begin
              gotoXY(xopp+5,yopp+5);
              write('*');
              gotoXY(xopp+7,yopp+5);
              write('*');
              gotoXY(xopp+9,yopp+5);
              write('*');
              textcolor(red);
              gotoXY(xopp+2,yopp+2);
              write('\');
              gotoXY(xopp+4,yopp+2);
              write('\');
              gotoXY(xopp+6,yopp+2);
              write('\');
              gotoXY(xopp+3,yopp+3);
              write('\');
              gotoXY(xopp+5,yopp+3);
              write('\');
              gotoXY(xopp+7,yopp+3);
              write('\');
              gotoXY(xopp+4,yopp+4);
              write('\');
              gotoXY(xopp+6,yopp+4);
              write('\');
              gotoXY(xopp+8,yopp+4);
              write('\');
              sleep(1000);
           end;
      end;
      for u := 1 to 4 do
        begin
          Beep(440+(t*(u*20)), 1);
        end;
      for u := 1 to 5 do
        begin
          textcolor(victim.Color);
          gotoXY(xopp,u+yopp);
          write(victim.Art[u]);
        end;
    end;
  textcolor(black);
  InflictDamage(attacker, victim, whichmove, xopp, yopp);
end;

procedure DoVinewhip(var attacker : TPokemon; var victim : TPokemon; whichmove: integer; xopp: integer; yopp: integer; xyou : integer; yyou: integer; direction: boolean);
var
  flashed: boolean;
  t, u: integer;
begin
  flashed := false;
  for t := 1 to 8 do
    begin
      if flashed then
        begin
          if direction then
            begin
              for u := 1 to 3 do
                begin
                  gotoXY(xopp+4,yopp+1);
                  write('     ');
                  gotoXY(xopp+3,yopp+2);
                  write('     ');
                  gotoXY(xopp+2,yopp+3);
                  write('     ');
                  gotoXY(xopp+1,yopp+4);
                  write('     ');
                  gotoXY(xopp,yopp+5);
                  write('     ');
                end;
            end
          else
            begin
              for u := 1 to 3 do
                begin
                  gotoXY(xopp+8,yopp+1);
                  write('     ');
                  gotoXY(xopp+7,yopp+2);
                  write('     ');
                  gotoXY(xopp+6,yopp+3);
                  write('     ');
                  gotoXY(xopp+5,yopp+4);
                  write('     ');
                  gotoXY(xopp+4,yopp+5);
                  write('     ');
                end;
            end;
          for u := 1 to 5 do
            begin
              textcolor(victim.Color);
              gotoXY(xopp,u+yopp);
              write(victim.Art[u]);
            end;
          flashed := false;
        end
      else
        begin
          textcolor(Green);
          if direction then
            begin
              for u := 1 to 3 do
                begin
                  gotoXY(xopp+4,yopp+1);
                  write('|| //');
                  gotoXY(xopp+3,yopp+2);
                  write('|| //');
                  gotoXY(xopp+2,yopp+3);
                  write('|| //');
                  gotoXY(xopp+1,yopp+4);
                  write('|| //');
                  gotoXY(xopp,yopp+5);
                  write('|| //');
                end;
            end
          else
            begin
              for u := 1 to 3 do
                begin
                  gotoXY(xopp+8,yopp+1);
                  write('// ||');
                  gotoXY(xopp+7,yopp+2);
                  write('// ||');
                  gotoXY(xopp+6,yopp+3);
                  write('// ||');
                  gotoXY(xopp+5,yopp+4);
                  write('// ||');
                  gotoXY(xopp+4,yopp+5);
                  write('// ||');
                end;
            end;
          flashed := true;
        end;
      if t = 1 then
        sleep(500)
      else
        sleep(50);
    end;
  textcolor(black);
  InflictDamage(attacker, victim, whichmove, xopp, yopp);
end;

procedure DoRazorleaf(var attacker : TPokemon; var victim : TPokemon; whichmove: integer; xopp: integer; yopp: integer; xyou : integer; yyou: integer; direction: boolean);
var
  graphic: array[1..4] of array[1..3] of string[3];
  r, t, u: integer;
begin
  r := 0;
  graphic[1][1] := ' ##';
  graphic[1][2] := '## ';
  graphic[1][3] := ' ##';

  graphic[2][1] := ' # ';
  graphic[2][2] := '###';
  graphic[2][3] := '# #';

  graphic[3][1] := '## ';
  graphic[3][2] := ' ##';
  graphic[3][3] := '## ';

  graphic[4][1] := '# #';
  graphic[4][2] := '###';
  graphic[4][3] := ' # ';

  for t := 0 to 10 do
    begin
      textcolor(green);
      r += 1;
      if r > 4 then
        r := 1;
      if direction then
        begin
          for u := 0 to 2 do
            begin
              gotoXY(xyou+10+(5*(t-1)),yyou-(t-1)-u+3);
              write('   ');
              gotoXY(xyou+10+(5*t),yyou-t-u+3);
              write(graphic[r][u+1]);
            end;
        end
      else
        begin
          for u := 0 to 2 do
            begin
              gotoXY(xyou-(5*(t-1)),yyou+(t-1)+u+3);
              write('   ');
              gotoXY(xyou-(5*t),yyou+t+u+3);
              write(graphic[r][u+1]);
            end;
        end;
      for u := 1 to 5 do
        begin
          textcolor(victim.Color);
          gotoXY(xopp,u+yopp);
          write(victim.Art[u]);
          textcolor(attacker.Color);
          gotoXY(xyou,u+yyou);
          write(attacker.Art[u]);
        end;
      sleep(50);

    end;
  InflictDamage(attacker, victim, whichmove, xopp, yopp);
end;

////////////////////////////////////////////////////
// GENERAL BATTLE SUBROUTINES
////////////////////////////////////////////////////

procedure Run;
begin
  if not(battletypetxt = 'Wild') then
    begin
      drawmarker := false;
      ClearBattleOptionsMarker;
      ClearMessage(2,22);
      DisplayMessage('Cannot run from a trainer!',2,22);
      sleep(1000);
      drawmarker := true;
      ClearMessage(2,22);
      DisplayMessage('What will '+yourbattlepoke[currentpoke].Nickname+' do?',2,22);
    end
  else
    battleended := 2;
end;

procedure DoMove(var attacker : TPokemon; var victim : TPokemon; whichmove: integer; xopp: integer; yopp: integer; xyou: integer; yyou: integer; direction: boolean);
begin
  case attacker.Move[whichmove].ID of
    33: DoTackle(attacker, victim, whichmove, xopp, yopp, xyou, yyou, direction);
    10: DoScratch(attacker, victim, whichmove, xopp, yopp, xyou, yyou, direction);
    22: DoVinewhip(attacker, victim, whichmove, xopp, yopp, xyou, yyou, direction);
    75: DoRazorleaf(attacker, victim, whichmove, xopp, yopp, xyou, yyou, direction);
  end;
end;

procedure FinishEnemySwitchPokemon;
//Need this procedure when opponent has more Pokemon after you have knocked out one of their Pokemon.
begin
  sleep(1000);
  enemypokemonfainted := false;
  ClearMessage(2,22);
  //'VARIABLES' should be replaced with variables for the opponent's name
  DisplayMessage('VARIABLES'+' sent out '+battlepoke[currentbattlepoke].Name+'!',2,22);
  SendAnimation(60,1,false);
  DrawEnemyPokemon;
  DrawEnemyStats;
  DrawEnemyHealth;
  sleep(1000);
  ClearMessage(2,22);
  DisplayMessage('What will '+yourbattlepoke[currentpoke].Nickname+' do?',2,22);
  DrawBattleOptions;
end;

procedure EnemySwitchPokemon;
var
  switchchoice, arrowposition : integer;
begin
  ClearMessage(2,22);
  DisplayMessage('VARIABLES'+' is about to send out '+battlepoke[currentbattlepoke].Name+'.',2,22);
  sleep(1000);
  ClearMessage(2,22);
  DisplayMessage('Switch POKeMON?',2,22);

  gotoXY(56,21);
  write('YES');
  gotoXY(56,23);
  write('NO');
  gotoXY(55,21);
  write('>');
  switchchoice := 0;
  arrowposition := 1;
  while switchchoice = 0 do
    begin
      if GetKeyState(VK_UP) < 0 then
        begin
          gotoXY(55,23);
          write(' ');
          gotoXY(55,21);
          write('>');
          arrowposition := 1;
          sleep(100);
        end;
      if GetKeyState(VK_DOWN) < 0 then
        begin
          gotoXY(55,21);
          write(' ');
          gotoXY(55,23);
          write('>');
          arrowposition := 2;
          sleep(100);
        end;
      if GetKeyState(VK_RETURN) < 0 then
        begin
          switchchoice := arrowposition;
          sleep(100);
        end;
    end;
  ClearBattleOptions;
  gotoXY(55,21);
  write(' ');
  gotoXY(55,23);
  write(' ');
  if switchchoice = 1 then
    begin
      DrawPokemonSelect;
    end
  else
    FinishEnemySwitchPokemon;
end;

procedure LoseBattle;
begin
  battleended := 2;
end;

procedure YourPokemonFaint;
//Happens if your Pokemon gets knocked out
var
  j, k : integer;
  gotmorepokemon : boolean;
begin
  ClearMessage(2,22);
  sleep(1000);
  textColor(yourbattlepoke[currentpoke].Color);
  for j := 5 downto 1 do
  begin
    for k := j downto 0 do
      begin
        gotoXY(3, 11+(6-j)+k);
        write('              ');
        gotoXY(3, 11+(6-j)+k);
        write(yourbattlepoke[currentpoke].Art[k]);
      end;
    sleep(30);
  end;
  gotoXY(3,17);
  write('              ');
  sleep(1000);
  textColor(black);
  DisplayMessage(yourbattlepoke[currentpoke].Nickname+' fainted!', 2, 22);
  sleep(1000);
  fighting := false;
  gotmorepokemon := false;
  for j := 1 to 6 do
    begin
      if yourbattlepoke[j].HP > 0 then
        gotmorepokemon := true;
    end;
  if gotmorepokemon then
    begin
      DrawPokemonSelect;
      sleep(100);
    end
  else
    begin
      ClearMessage(2,22);
      DisplayMessage('Trainer is out of usable Pokemon!',2,22);
      sleep(1000);
      ClearMessage(2,22);
      DisplayMessage('Trainer blacked out!',2,22);
      sleep(1000);
      LoseBattle;
    end;
end;

procedure EnemyPokemonFaint;
var
  j, k : integer;
  gotmorepokemon : boolean;
begin
  ClearMessage(2,22);
  sleep(1000);
  textColor(battlepoke[currentbattlepoke].Color);
  for j := 5 downto 1 do
    begin
      for k := j downto 0 do
        begin
          gotoXY(60, 1+(6-j)+k);
          write('              ');
          gotoXY(60, 1+(6-j)+k);
          write(battlepoke[currentbattlepoke].Art[k]);
        end;
      sleep(30);
    end;
  gotoXY(60,7);
  write('              ');
  sleep(500);
  ClearEnemyStats;
  sleep(500);
  textColor(black);
  DisplayMessage(battletypetxt+' '+battlepoke[currentbattlepoke].Nickname+' fainted!', 2, 22);
  sleep(1000);
  fighting := false;
  gotmorepokemon := false;
  for j := 1 to 6 do
  begin
    if battlepoke[j].HP > 0 then
      begin
        gotmorepokemon := true;
        currentbattlepoke := j;
      end;
  end;
  if gotmorepokemon then
    EnemySwitchPokemon
  else
    begin
      if battletypetxt = 'Wild' then
        begin
           battleended := 1;
        end
      else
        begin
          ClearMessage(2,22);
          DisplayMessage('Trainer defeated '+'VARIABLES'+'!',2,22);
          sleep(1000);
          battleended := 1;
        end;
    end;
end;

procedure EnemyAttack;
var
  enemycurrentmove : integer;
begin
  ClearMessage(2,22);
  while true do
    begin
      enemycurrentmove := random(3)+1;
      if not (battlepoke[currentbattlepoke].Move[enemycurrentmove].Name = '-') then
        break;
  end;
  DisplayMessage(battletypetxt+' '+battlepoke[currentbattlepoke].Name+' used '+battlepoke[currentbattlepoke].Move[enemycurrentmove].Name+'!',2,22);
  sleep(1000);
  DoMove(battlepoke[currentbattlepoke], yourbattlepoke[currentpoke], enemycurrentmove, 3, 11, 60, 1, false);
end;

procedure CheckHealths;
begin
  if yourbattlepoke[currentpoke].HP = 0 then
    yourpokemonfainted := true;
  if battlepoke[currentbattlepoke].HP = 0 then
    enemypokemonfainted := true;
end;

procedure YouSwitchPokemon(num : integer);
begin
  if (num = currentpoke) and (not enemypokemonfainted) then
    begin
      if yourpokemonfainted then
        begin
          ClearBattleOptions;
          ClearMessage(2,22);
          DisplayMessage(yourbattlepoke[num].Nickname+' is unable to fight!',2,22);
          sleep(1000);
          DrawPokemonSelect;
       end
      else
        begin
          actionchoice := 1;
          clrscr;
          DrawBattle;
          DrawPokemon;
          ClearBattleOptionsMarker;
          ClearMessage(2,22);
          DisplayMessage('You already have that POKeMON out!',2,22);
          sleep(1000);
          ClearMessage(2,22);
          DisplayMessage('What will '+yourbattlepoke[currentpoke].Nickname+' do?',2,22);
          DrawBattleOptionsMarker;
        end;
    end
  else
    begin
      if yourbattlepoke[num].HP = 0 then
        begin
          ClearBattleOptions;
          ClearMessage(2,22);
          DisplayMessage(yourbattlepoke[num].Nickname+' is unable to fight!',2,22);
          sleep(1000);
          DrawPokemonSelect;
        end
      else
        begin
          actionchoice := 1;
          clrscr;
          if not enemypokemonfainted then
          begin
            DrawEnemyStats;
            DrawEnemyHealth;
          end;
          DrawBattleMenu;
          ClearBattleOptions;
          if yourpokemonfainted then
            begin
              ClearYourStats;
              DrawEnemyPokemon;
              yourpokemonfainted := false;
            end
          else
            begin
              DrawYourStats;
              DrawYourHealth;
              DrawYourBattlePokemon;
              if not enemypokemonfainted then
                DrawEnemyPokemon;
              if not(num = currentpoke) then
                begin
                  ClearMessage(2,22);
                  DisplayMessage('Come back, '+yourbattlepoke[currentpoke].Nickname+'!',2,22);
                  RecieveAnimation(3,11);
                end;
            end;
          if not(num = currentpoke) then
            begin
              ClearYourStats;
              sleep(1000);
              currentpoke := num;
              ClearMessage(2,22);
              DisplayMessage('Go! '+yourbattlepoke[currentpoke].Nickname+'!',2,22);
              SendAnimation(3,11,true);
              DrawYourBattlePokemon;
              DrawYourStats;
              DrawYourHealth;
              sleep(1000);
              ClearMessage(2,22);
            end;
          if (not yourpokemonfainted) and (not enemypokemonfainted) then
            begin
              EnemyAttack;
              CheckHealths;
              sleep(1000);
            end;
          if (not yourpokemonfainted) and (not enemypokemonfainted) then
          begin
            DrawBattleOptions;
            ClearMessage(2,22);
            DisplayMessage('What will '+yourbattlepoke[currentpoke].Nickname+' do?',2,22);
          end;
          if enemypokemonfainted then
            FinishEnemySwitchPokemon;
        end;
    end;
end;

////////////////BAG SUBROUTINES/////////////////////////////
procedure OpenBag;
var
  u, v: integer;
begin
  v := 0;
  itemchoice := 1;
  bagopen := true;
  gotoXY(50,7);
  write('_________________________');
  for u := 1 to 17 do
    begin
      gotoXY(50,7+u);
      write('|                        |');
    end;
  gotoXY(51,24);
  write('________________________');
  for u := 1 to length(itemcount) do
    begin
      if itemcount[u] > 0 then
        begin
          v += 1;
          gotoXY(53,8+v);
          write(itemname[u]);
          gotoXY(70,8+v);
          write('x', itemcount[u]);
        end;
    end;
  gotoXY(52, 9);
  write('>');
end;

procedure ClearBag;
var
  u : integer;
begin
  bagopen := false;
  gotoXY(50,7);
  write('                          ');
  for u := 1 to 17 do
    begin
      gotoXY(50,7+u);
      write('                          ');
    end;
  gotoXY(50,24);
  write('                          ');
  DrawBattle;
  DrawBattleMenu;
  gotoXY(2,22);
  write('What will '+yourbattlepoke[currentpoke].Nickname+' do?');
end;

procedure YouUseItem;
var
  u, v : integer;
begin
  v := 0;
  for u := 1 to length(itemcount) do
    begin
      if itemcount[u] > 0 then
        begin
          v += 1;
          if v = itemchoice then
            break;
        end;
    end;
  ClearBag;
  itemcount[v] -= 1;
  case v of
    1: UsePotion(yourbattlepoke[currentpoke]);
    2: UseSuperPotion(yourbattlepoke[currentpoke]);
    3: UseHyperPotion(yourbattlepoke[currentpoke]);
  end;
  actionchoice := 1;
  fighting := true;
  DrawBattleOptions;
  gotoXY(55,21);
  write(' ');
  EnemyAttack;
  CheckHealths;
  sleep(1000);
  fighting  := false;
  actionchoice := 1;
  if not (yourpokemonfainted or enemypokemonfainted) then
  begin
    DrawBattleOptions;
    ClearMessage(2,22);
    DisplayMessage('What will '+yourbattlepoke[currentpoke].Nickname+' do?',2,22);
  end;
end;
///////////////END OF BAG SUBROUTINES///////////////////////

function ChooseDo : integer;
//This function basically governs selection of  choices in battle
begin
  while (true) do
    begin
      if GetKeyState(VK_UP) < 0 then
        begin
          if pokemonchoosing and not pokemonchoosingoptions then
            begin
              if choosepoke > 1 then
                begin
                  choosepoke -= 1;
                  DrawPokemonSelectMarker;
                end;
              sleep(100);
            end
          else
            if bagopen then
              begin
                if itemchoice > 1 then
                  itemchoice -= 1;
                gotoXY(52,9+itemchoice);
                write(' ');
                gotoXY(52,8+itemchoice);
                write('>');
                sleep(100);
              end
            else
              begin
                if drawmarker and not pokemonchoosing then
                  case actionchoice of
                    3: begin
                         if fight and (yourbattlepoke[currentpoke].Move[1].Name = '-') then
                           break;
                         actionchoice := 1;
                         gotoXY(55,23);
                         write(' ');
                         gotoXY(55,21);
                         write('>');
                       end;
                    4: begin
                         if fight and (yourbattlepoke[currentpoke].Move[2].Name = '-') then
                           break;
                         actionchoice := 2;
                         gotoXY(68,23);
                         write(' ');
                         gotoXY(68,21);
                         write('>');
                       end;
                  end;
              end;
            sleep(75);
            break;
        end;
      if GetKeyState(VK_DOWN) < 0 then
        begin
          if pokemonchoosing and not pokemonchoosingoptions then
            begin
              if not(yourbattlepoke[choosepoke+1].Name = allpokemon[0].Name)
                   and (choosepoke < 6) then
                begin
                  choosepoke += 1;
                  DrawPokemonSelectMarker;
                end;
              sleep(100);
            end
          else
            if bagopen then
              begin
                if itemchoice < length(itemcount) then itemchoice += 1;
                gotoXY(52,7+itemchoice);
                write(' ');
                gotoXY(52,8+itemchoice);
                write('>');
                sleep(100);
              end
            else
              begin
                if drawmarker and not pokemonchoosing then
                  case actionchoice of
                    1: begin
                         if fight and (yourbattlepoke[currentpoke].Move[3].Name = '-') then
                           break;
                         actionchoice := 3;
                         gotoXY(55,21);
                         write(' ');
                         gotoXY(55,23);
                         write('>');
                       end;
                    2: begin
                         if fight and (yourbattlepoke[currentpoke].Move[4].Name = '-') then
                           break;
                         actionchoice := 4;
                         gotoXY(68,21);
                         write(' ');
                         gotoXY(68,23);
                         write('>');
                       end;
                  end;
              end;
            sleep(75);
            break;
        end;
      if GetKeyState(VK_LEFT) < 0 then
        begin
          if (not(bagopen or pokemonchoosing)
              and drawmarker) or pokemonchoosingoptions then
            case actionchoice of
              2: begin
                   if fight and (yourbattlepoke[currentpoke].Move[1].Name = '-') then
                     break;
                   actionchoice := 1;
                   gotoXY(68,21);
                   write(' ');
                   gotoXY(55,21);
                   write('>');
                 end;
              4: begin
                   if fight and (yourbattlepoke[currentpoke].Move[3].Name = '-') then
                     break;
                   actionchoice := 3;
                   gotoXY(68,23);
                   write(' ');
                   gotoXY(55,23);
                   write('>');
                 end;
            end;
          sleep(75);
          break;
        end;
      if GetKeyState(VK_RIGHT) < 0 then
        begin
          if (not (bagopen or pokemonchoosing)
              and drawmarker) or pokemonchoosingoptions then
            case actionchoice of
              1: begin
                   if fight and (yourbattlepoke[currentpoke].Move[2].Name = '-') then
                     break;
                   actionchoice := 2;
                   gotoXY(55,21);
                   write(' ');
                   gotoXY(68,21);
                   write('>');
                 end;
              3: begin
                   if fight and (yourbattlepoke[currentpoke].Move[4].Name = '-') then
                     break;
                   actionchoice := 4;
                   gotoXY(55,23);
                   write(' ');
                   gotoXY(68,23);
                   write('>');
                 end;
            end;
          sleep(75);
          break;
        end;
      if GetKeyState(VK_RETURN) < 0 then
        begin
          if not(bagopen or pokemonchoosing) and drawmarker then
            begin
              if ((actionchoice = 2) and (fight = false)) then
                begin
                  OpenBag;
                  sleep(100);
                end;
              if ((actionchoice = 3) and (fight = false)) then
                begin
                  DrawPokemonSelect;
                  sleep(100);
                end;
              if ((actionchoice = 4) and (fight = false)) then
                begin
                  Run;
                  sleep(100);
                end;
              if ((actionchoice = 1) and (fight = false)) then
                begin
                  fight := true;
                  sleep(150);
                  Beep(200,50);
                end
              else
                if fight then
                  begin
                    result := 1;
                    currentmove := actionchoice;
                    fight := false;
                    fighting := true;
                    Beep(200,50);
                  end
                else
                  begin
                    result := 0;
                    sleep(50);
                    Beep(200,50);
                  end;
                if not (bagopen or pokemonchoosing) then
                  DrawBattleOptions;
            end
          else if bagopen then
            begin
              YouUseItem;
              sleep(100);
            end
          else if pokemonchoosing then
            begin
              if pokemonchoosingoptions then
                begin
                  if actionchoice = 1 then
                    begin
                      pokemonchoosingoptions := false;
                      pokemonchoosing := false;
                      YouSwitchPokemon(choosepoke);
                    end
                  else if actionchoice = 2 then
                    begin
                      pokemonchoosingoptions := false;
                      ClearBattleOptions;
                    end;
                end
              else
                begin
                  pokemonchoosingoptions := true;
                  actionchoice := 1;
                  DrawBattleOptions;
                end;
              sleep(100);
            end;
          sleep(100);
          break;
        end;
      if (GetKeyState(VK_BACK) < 0) and (not yourpokemonfainted) then
        begin
          if fight = true then
            fight := false;
          if bagopen = true then
            begin
              ClearBag;
            end;
          if not pokemonchoosing then
            begin
              actionchoice := 1;
              DrawBattleOptions;
            end
          else if pokemonchoosingoptions then
            begin
              pokemonchoosingoptions := false;
              ClearBattleOptions;
            end
          else
            begin
              pokemonchoosing := false;
              actionchoice := 1;
              clrscr;
              if enemypokemonfainted then
                begin
                  DrawYourBattlePokemon;
                  DrawYourStats;
                  DrawYourHealth;
                  entered := false;
                  DrawBattleMenu;
                  entered := true;
                  FinishEnemySwitchPokemon;
                end
              else
                begin
                  DrawBattle;
                  DrawPokemon;
                  DrawBattleOptions;
                  ClearMessage(2,22);
                  gotoXY(2,22);
                  write('What will '+yourbattlepoke[currentpoke].Nickname+' do?');
                end;
            end;
          Beep(200,50);
          sleep(450);
          break;
        end;
      sleep(20);
    end;
end;

procedure YourAttack;
begin
  ClearMessage(2,22);
  DisplayMessage(yourbattlepoke[currentpoke].Nickname+' used '+yourbattlepoke[currentpoke].Move[currentmove].Name+'!',2,22);
  sleep(1000);
  DoMove(yourbattlepoke[currentpoke], battlepoke[currentbattlepoke], currentmove, 60, 1, 3, 11, true);
end;

procedure DoFight;
//After you've chosen a move to use in battle, the fight commences!
var
  randgo : integer;
begin
  ClearBattleOptionsMarker;
  if yourbattlepoke[currentpoke].Speed > battlepoke[currentbattlepoke].Speed then
    begin
      YourAttack;
      sleep(1000);
      if battlepoke[currentbattlepoke].HP > 0 then
        EnemyAttack;
      CheckHealths;
    end
  else
    if yourbattlepoke[currentpoke].Speed < battlepoke[currentbattlepoke].Speed then
      begin
        EnemyAttack;
        if yourbattlepoke[currentpoke].HP > 0 then
         YourAttack;
        CheckHealths;
      end
    else
      begin
        randgo := round(random(1));
        case randgo of
          0: begin
               YourAttack;
               if battlepoke[currentbattlepoke].HP > 0 then
                 EnemyAttack;
               CheckHealths;
             end;
          1: begin
               EnemyAttack;
               if yourbattlepoke[currentpoke].HP > 0 then
                 YourAttack;
               CheckHealths;
             end;
        end;
      end;
  sleep(1000);
end;

procedure BattleInit;
var
  j : integer;
begin
  inbattle := true;
  textBackground(white);
  textColor(black);
  clrscr;
  actionchoice := 1;
  entered := false;
  fight := false;
  bagopen := false;
  pokemonchoosing := false;
  pokemonchoosingoptions := false;
  drawmarker := true;
  yourpokemonfainted := false;
  enemypokemonfainted := false;
  currentpoke := 1;
  currentbattlepoke := 1;
  for j := 1 to 6 do
    yourbattlepoke[j] := player.Pokemon[j];
  for j := 1 to 6 do
    if not(yourbattlepoke[j].Name = allpokemon[0].Name) then
      FlipPokemonArt(yourbattlepoke[j]);
end;

procedure Battle;
var
  j : integer;
begin
  ClearMessage(2,22);
  DisplayMessage('What will '+yourbattlepoke[currentpoke].Nickname+' do?',2,22);
  entered := true;
  DrawBattleOptions;
  battleended := 0; // 0 is no winner atm, 1 is you win, 2 is foe win
  while (true) do
    begin
      if yourpokemonfainted and (not pokemonchoosing) then
        begin
          fighting := false;
          YourPokemonFaint;
        end;
      if enemypokemonfainted and (not pokemonchoosing) then
        begin
          fighting := false;
          EnemyPokemonFaint;
        end;
      if battleended > 0 then
        break;
      if ChooseDo = 1 then
        DoFight;
      if fighting and not(yourpokemonfainted or enemypokemonfainted) then
        begin
          fighting := false;
          actionchoice := 1;
          if not(bagopen or pokemonchoosing) then
            begin
              DrawBattleOptions;
              ClearMessage(2,22);
              DisplayMessage('What will '+yourbattlepoke[currentpoke].Nickname+' do?',2,22);
            end;
        end;
    end;
  for j := 1 to 6 do
    player.Pokemon[j].HP := yourbattlepoke[j].HP;
  clrscr;
  sleep(200);
  inbattle := false;
end;

procedure WildBattle;
var
  j, k, l : integer;
begin
  {sound_music:=MIX_LOADMUS('sounds/wildbattle.mid');
  MIX_PLAYMUSIC(sound_music,-1); } //Uncomment for music
  l := 1;
  repeat
    textBackground(black);
    for j := 1 to 25 do
      begin
        for k := 1 to 80 do
          if not((j = 25) and (k = 80)) then
            begin
              gotoXY(k,j);
              write(' ');
            end;
          sleep(1);
      end;
    textBackground(white);
    for j := 1 to 25 do
      begin
        for k := 1 to 80 do
          if not((j = 25) and (k = 80)) then
            begin
              gotoXY(k,j);
              write(' ');
            end;
        sleep(1);
      end;
    l += 1;
  until l = 6;
  for j := 1 to 6 do
    battlepoke[j] := allpokemon[0];
  j := random(2)+2;
  battlepoke[1] := allpokemon[j];
  battlepoke[1].HP := battlepoke[1].OrigHP;
  battletypetxt := 'Wild';
  BattleInit;
  clrscr;
  DrawBattleMenu;
  SlideInAnimation(battlepoke[currentbattlepoke].Art,battlepoke[currentbattlepoke].Color,60,2,2,
                  playerbackimage, player.Color, 3, 12);
  DrawEnemyPokemon;
  DrawImage(playerbackimage, player.Color, 3, 12);
  DisplayMessage('Wild '+battlepoke[currentbattlepoke].Name+' appeared!',2,22);
  sleep(1000);
  DrawEnemyStats;
  DrawEnemyHealth;
  ClearMessage(2,22);
  DisplayMessage('Go! '+yourbattlepoke[currentpoke].Nickname+'!',2,22);
  DrawImage(playerbackimage, black, 3, 12);
  sleep(70);
  DrawImage(playerbackimage, darkgray, 3, 12);
  sleep(70);
  DrawImage(playerbackimage, lightgray, 3, 12);
  sleep(70);
  ClearImage(3,12);
  SendAnimation(3,11,true);
  DrawYourBattlePokemon;
  DrawYourStats;
  DrawBattleHealth;
  sleep(1000);
  Battle;
  {sound_music:=MIX_LOADMUS('sounds/pallettown.mid');
  MIX_PLAYMUSIC(sound_music,-1);} //Uncomment for music
end;

////////////////////////////////////////////////////////////////////////////////
/////////          END OF BATTLE STUFF         /////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

procedure ImagesInit;
//Some animation and player images for both male and female players
begin
  launchanimation[1][1] := '              ';
  launchanimation[1][2] := '              ';
  launchanimation[1][3] := '      ##      ';
  launchanimation[1][4] := '              ';
  launchanimation[1][5] := '              ';

  launchanimation[2][1] := '              ';
  launchanimation[2][2] := '      ##      ';
  launchanimation[2][3] := '     #  #     ';
  launchanimation[2][4] := '      ##      ';
  launchanimation[2][5] := '              ';

  launchanimation[3][1] := '    #   #     ';
  launchanimation[3][2] := '   #     #    ';
  launchanimation[3][3] := '              ';
  launchanimation[3][4] := '   #     #    ';
  launchanimation[3][5] := '    #   #     ';

  launchanimation[4][1] := ' #          # ';
  launchanimation[4][2] := '              ';
  launchanimation[4][3] := '              ';
  launchanimation[4][4] := '              ';
  launchanimation[4][5] := ' #          # ';

  if player.Color = blue then
    begin
      playerbackimage[1] := '      ___     ';
      playerbackimage[2] := '     /___\__  ';
      playerbackimage[3] := '     \   /    ';
      playerbackimage[4] := '   ___|_|     ';
      playerbackimage[5] := '  /__/ | |    ';
    end
  else
    begin
      playerbackimage[1] := '      ___     ';
      playerbackimage[2] := '    _/___\_   ';
      playerbackimage[3] := '    //// /    ';
      playerbackimage[4] := '   ///|_|     ';
      playerbackimage[5] := '     | ||\    ';
    end;
end;

procedure MovesInit;
//Setting up the records for the moves. Null is for empty move slots a Pokemon may have
//Names are in uppercase for authenticity
begin
  with null do
    begin
      ID := 0;
      Name := '-';
      Type1 := '';
      Power := 0;
      Accuracy := 0;
      Points := 0;
   end;

  with tackle do
    begin
      ID := 33;
      Name := 'TACKLE';
      Type1 := 'Normal';
      Power := 35;
      Accuracy := 95;
      Points := 35;
    end;

  with scratch do
    begin
      ID := 10;
      Name := 'SCRATCH';
      Type1 := 'Normal';
      Power := 40;
      Accuracy := 100;
      Points := 35;
    end;

  with vinewhip do
    begin
      ID := 22;
      Name := 'VINE WHIP';
      Type1 := 'Grass';
      Power := 35;
      Accuracy := 100;
      Points := 15;
    end;

  with razorleaf do
    begin
      ID := 75;
      Name := 'RAZOR LEAF';
      Type1 := 'Grass';
      Power := 55;
      Accuracy := 95;
      Points := 25;
    end;
end;

procedure PokemonInit;
//Sets up Pokemon records. Use null for empty Pokemon spaces for a trainer
begin
  with allpokemon[0] do
    begin
      Name := 'null';
      Nickname := Name;
      Type1 := 'Normal';
      Type2 := 'Normal';
      Level := 0;
      OrigHP := 0;
      HP := OrigHP;
      NormAtt := 0;
      NormDef := 0;
      SpecAtt := 0;
      SpecDef := 0;
      Speed := 0;
      Move[1] := null;
      Move[2] := null;
      Move[3] := null;
      Move[4] := null;
      Gender := White;
      Exp := 0;
      Art[1] := '              ';
      Art[2] := '              ';
      Art[3] := '              ';
      Art[4] := '              ';
      Art[5] := '              ';
      Color := White;
    end;

  with allpokemon[1] do
    begin
      Name := 'BULBASAUR';
      Nickname := Name;
      Type1 := 'Grass';
      Type2 := 'Poison';
      Level := 5;
      OrigHP := 45;
      HP := OrigHP;
      NormAtt := 49;
      NormDef := 49;
      SpecAtt := 65;
      SpecDef := 65;
      Speed := 45;
      Move[1] := tackle;
      Move[2] := scratch;
      Move[3] := razorleaf;
      Move[4] := vinewhip;
      Gender := Blue;
      Exp := 0;
      Art[1] := '       ###    ';
      Art[2] := '      #####   ';
      Art[3] := '   __#######  ';
      Art[4] := '  /         | ';
      Art[5] := '  \_________| ';
      Color := Cyan;
    end;

  with allpokemon[2] do
    begin
      Name := 'RATTATA';
      Nickname := Name;
      Type1 := 'Normal';
      Type2 := 'Normal';
      Level := 3;
      OrigHP := 30;
      HP := OrigHP;
      NormAtt := 56;
      NormDef := 35;
      SpecAtt := 25;
      SpecDef := 35;
      Speed := 72;
      Move[1] := tackle;
      Move[2] := scratch;
      Move[3] := null;
      Move[4] := null;
      Gender := Red;
      Exp := 0;
      Art[1] := '      ____    ';
      Art[2] := '  /\_/  \ \   ';
      Art[3] := '  /  \__/  |  ';
      Art[4] := ' |________|   ';
      Art[5] := '   /|\   /|\  ';
      Color := Magenta;
    end;

  with allpokemon[3] do
    begin
      Name := 'PIDGEY';
      Nickname := Name;
      Type1 := 'Normal';
      Type2 := 'Flying';
      Level := 3;
      OrigHP := 40;
      HP := OrigHP;
      NormAtt := 45;
      NormDef := 40;
      SpecAtt := 35;
      SpecDef := 35;
      Speed := 56;
      Move[1] := tackle;
      Move[2] := scratch;
      Move[3] := null;
      Move[4] := null;
      Gender := Blue;
      Exp := 0;
      Art[1] := '    ___       ';
      Art[2] := '   /  \_      ';
      Art[3] := '  <  \__\///  ';
      Art[4] := '   \_____/    ';
      Art[5] := '      ,,      ';
      Color := Brown;
    end;
end;

procedure MapsInit;
//Gets the data from the map files and puts it into map records
var
  mapfile : text;
  j,k,l,m,mapcharcount : integer;
  mapline, mapstring, maptext, music : string;
  //All the variables below, except for 'doors', are for records of people in the map
  titles, names, colors, xs, ys, alreadybattleds, battlemessages,
        winmessages, losemessages, aftermessages, doors : array[1..5] of string;
  sprites : array[1..5] of char;
begin
  for j := 1 to 3 do
    begin
      mapstring := '';
      Assign(mapfile, 'map'+IntToStr(j)+'.txt');
      Reset(mapfile);
      repeat
        Readln(mapfile,mapline);
        mapstring += mapline;
      until Eof(mapfile);
      Close(mapfile);
      maptext := mapstring[2001..length(mapstring)];

      mapcharcount := 1;  //The current character the program is analysing
      maps[j].Name := '';

      //The following code basically loops through the characters, adding it to
      //the relevant variables, until it reaches an underscore, where it moves
      //onto the next portion of data to read. Hopefully the rest is self explanatory
      while maptext[mapcharcount] <> '_' do
        begin
          maps[j].Name += maptext[mapcharcount];
          mapcharcount += 1
        end;
      mapcharcount += 1;

      for l := 1 to 5 do
        begin
          maps[j].Sign[l] := '';
          while maptext[mapcharcount] <> '_' do
            begin
              maps[j].Sign[l] += maptext[mapcharcount];
              mapcharcount += 1;
            end;
          mapcharcount += 1;
        end;

      for l := 1 to 5 do
        begin
          titles[l] := '';
          while maptext[mapcharcount] <> '_' do
            begin
              titles[l] += maptext[mapcharcount];
              mapcharcount += 1;
            end;
           mapcharcount += 1;
           maps[j].people[l].Title := titles[l];

           names[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               names[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           maps[j].people[l].Name := names[l];

           while maptext[mapcharcount] <> '_' do
             begin
               sprites[l] := maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           maps[j].people[l].Sprite := sprites[l];

           colors[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               colors[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           if colors[l] = 'b' then
             maps[j].people[l].Color := blue
           else
             maps[j].people[l].Color := red;

           xs[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               xs[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           maps[j].people[l].X := StrToInt(xs[l]);

           ys[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               ys[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           maps[j].people[l].Y := StrToInt(ys[l]);

           maps[j].people[l].Map := j;
           maps[j].people[l].IsPlayer := false;

           alreadybattleds[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               alreadybattleds[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           if alreadybattleds[l] = 't' then
             maps[j].people[l].AlreadyBattled := true
           else
             maps[j].people[l].AlreadyBattled := false;

           battlemessages[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               battlemessages[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           maps[j].people[l].BattleMessage := battlemessages[l];

           winmessages[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               winmessages[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           maps[j].people[l].WinMessage := winmessages[l];

           losemessages[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               losemessages[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           maps[j].people[l].LoseMessage := losemessages[l];

           aftermessages[l] := '';
           while maptext[mapcharcount] <> '_' do
             begin
               aftermessages[l] += maptext[mapcharcount];
               mapcharcount += 1;
             end;
           mapcharcount += 1;
           maps[j].people[l].afterMessage := aftermessages[l];
        end;

      for l := 1 to 5 do
        begin
          doors[l] := '';
          while maptext[mapcharcount] <> '_' do
            begin
              doors[l] += maptext[mapcharcount];
              mapcharcount += 1;
            end;
          mapcharcount += 1;
          maps[j].Door[l] := StrToInt(doors[l]);
        end;

      music := '';
      while maptext[mapcharcount] <> '_' do
        begin
          music += maptext[mapcharcount];
          mapcharcount += 1;
        end;
      mapcharcount += 1;
      maps[j].Music := music;

      m := 0;
      for k := 1 to 25 do
        begin
          for l := 1 to 80 do
            begin
              m += 1;
              maps[j].Data[l,k] := mapstring[m];
            end;
        end;
    end;
end;

procedure PlayerInit;
begin
  player := TTrainer.Create;
  with player do
    begin
      Title := '';
      write('What is your name? ');
      readln(Name);
      Sprite := '$';
      Color := white;
      while Color = white do
        begin
          write('Are you male or female? Type M/F. ');
          readln(option);
          if uppercase(option) = 'M' then
            Color := blue
          else if uppercase(option) = 'F' then
            Color := red
          else
            writeln;
        end;
      X := 29;
      Y := 7;
      Map := 1;
      for i := 1 to 6 do
        Pokemon[i] := allpokemon[0];
      //You can add/take away Pokemon that are given to you if you want (minimum 1, maximum 6)
      Pokemon[1] := allpokemon[1];
      Pokemon[2] := allpokemon[2];
      Pokemon[3] := allpokemon[3];
      writeln('What would you like to call your ', Pokemon[1].Name, '?');
      readln(Pokemon[1].Nickname);
      if Pokemon[1].Nickname = '' then
        Pokemon[1].Nickname := Pokemon[1].Name;
      writeln('What would you like to call your ', Pokemon[2].Name, '?');
      readln(Pokemon[2].Nickname);
      if Pokemon[2].Nickname = '' then
        Pokemon[2].Nickname := Pokemon[2].Name;
      writeln('What would you like to call your ', Pokemon[3].Name, '?');
      readln(Pokemon[3].Nickname);
      if Pokemon[3].Nickname = '' then
        Pokemon[3].Nickname := Pokemon[3].Name;
      IsPlayer := true;
    end;
end;

procedure Init;
var
  j : integer;
begin
//5 potions, 0 super/hyperpotions
  itemcount[1] := 5;
  itemcount[2] := 0;
  itemcount[3] := 0;

  playsound := false;

  inbattle := false;
  changingmap := false;
end;


////////////////////////////////////////////////////////////////////////////////
///////////            WORLD STUFF           ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//size is 80x25

procedure DoAction;
//Gets input to move you around in the map
var
  j : integer;
begin
  if not viewingsign then
    begin
      if GetKeyState(VK_UP) < 0 then
        begin
          player.Up;
          if (mapcounter > 0) and (mapcounter < 2101) then
            begin
              j := 0;
              repeat
                DoMapcounterStuff;
                j += 1;
              until j = 100;
            end
          else
            sleep(100);
        end;
      if GetKeyState(VK_DOWN) < 0 then
        begin
          player.Down;
          if (mapcounter > 0) and (mapcounter < 2101) then
            begin
              j := 0;
              repeat
                DoMapcounterStuff;
                j += 1;
              until j = 100;
            end
          else
            sleep(100);
        end;
      if GetKeyState(VK_LEFT) < 0 then
        begin
          player.Left;
          if (mapcounter > 0) and (mapcounter < 2101) then
            begin
              j := 0;
              repeat
                DoMapcounterStuff;
                j += 1;
              until j = 100;
            end
          else
            sleep(100);
        end;
      if GetKeyState(VK_RIGHT) < 0 then
        begin
          player.Right;
          if (mapcounter > 0) and (mapcounter < 2101) then
            begin
              j := 0;
              repeat
                DoMapcounterStuff;
                j += 1;
              until j = 100;
            end
          else
            sleep(100);
        end;
    end;
end;

//Walk into people/sign posts to talk/read
procedure Talk(num : integer);
var
  j,k : integer;
begin
  textcolor(black);
  textbackground(white);
  for j := 0 to 4 do
    begin
      for k := 0 to 45 do
        begin
          gotoXY(1+k, 21+j);
          write(' ');
        end;
      gotoXY(47,21+j);
      write('|');
    end;
  for j := 0 to 45 do
  begin
    gotoXY(1+j, 21);
    write('-');
  end;
  if person[num].AlreadyBattled then
    DisplayMessage(person[num].AfterMessage,2,23);
  repeat
    DoMapcounterStuff;
  until (GetKeyState(VK_UP) < 0) or (GetKeyState(VK_DOWN) < 0) or
       (GetKeyState(VK_LEFT) < 0) or (GetKeyState(VK_RIGHT) < 0);
  for j := 21 to 25 do
    begin
      for k := 1 to 47 do
        begin
          DrawMapSpace(k,j);
        end;
    end;
  talking := false;
  for j := 1 to 5 do
    if person[j] <> nil then
      begin
        person[j].Sit;
      end;
end;

procedure ViewSign(num : integer);
var
  j, k : integer;
begin
  textcolor(black);
  textbackground(white);
  for j := 0 to 4 do
    begin
      for k := 0 to 45 do
        begin
          gotoXY(1+k, 21+j);
          write(' ');
        end;
      gotoXY(47,21+j);
      write('|');
    end;
  for j := 0 to 45 do
    begin
      gotoXY(1+j, 21);
      write('-');
    end;
  DisplayMessage(maps[player.Map].Sign[num],2,23);
  repeat
    DoMapcounterStuff;
  until (GetKeyState(VK_UP) < 0) or (GetKeyState(VK_DOWN) < 0) or
       (GetKeyState(VK_LEFT) < 0) or (GetKeyState(VK_RIGHT) < 0);
  for j := 21 to 25 do
    begin
      for k := 1 to 47 do
        begin
          DrawMapSpace(k,j);
        end;
    end;
  viewingsign := false;
  for j := 1 to 5 do
    if person[j] <> nil then
      begin
        person[j].Sit;
      end;
end;

procedure DrawMap;
//Initialises the current map you are on
var
  mapx, mapy, j : integer;
begin
  for mapy := 1 to 25 do
    begin
      for mapx := 1 to 80 do
        begin
          if not ((mapy = 25) and (mapx = 80)) then DrawMapSpace(mapx,mapy);
        end;
    end;
  for j := 1 to 5 do
    begin
      if maps[player.Map].People[j].Title <> '' then
        begin
          person[j] := TTrainer.Create;
          with person[j] do
            begin
              person[j].Title := maps[player.Map].People[j].Title;
              person[j].Name := maps[player.Map].People[j].Name;
              person[j].Sprite := maps[player.Map].People[j].Sprite;
              person[j].Color := maps[player.Map].People[j].Color;
              person[j].X := maps[player.Map].People[j].X;
              person[j].Y := maps[player.Map].People[j].Y;
              person[j].Map := maps[player.Map].People[j].Map;
              person[j].IsPlayer := maps[player.Map].People[j].IsPlayer;
              person[j].AlreadyBattled := maps[player.Map].People[j].AlreadyBattled;
              person[j].BattleMessage := maps[player.Map].People[j].BattleMessage;
              person[j].WinMessage := maps[player.Map].People[j].WinMessage;
              person[j].LoseMessage := maps[player.Map].People[j].LoseMessage;
              person[j].AfterMessage := maps[player.Map].People[j].AfterMessage;
            end;
          gotoXY(person[j].X,person[j].Y);
          person[j].SetBackColor;
          textColor(person[j].Color);
          write(person[j].Sprite);
        end;
    end;
  gotoXY(player.X,player.Y);
  player.SetBackColor;
  textColor(player.Color);
  write(player.Sprite);
  if wildpokemonbattle then
    wildpokemonbattle := false;
end;
 
procedure World;
//Manages the what is happening on the map (and essentially the entire game, because
//this is the main loop of the game (battles are just loops within this loop!)).
var
  mapmusic:string;
begin
  mapdrawn := false;
  mapcounter := 2101; //should be 0 but setting to 2101 stops it from working as it is problematic
  viewingsign := false;
  talking := false;
  while true do
    begin
      if not inbattle then
        begin
          if not mapdrawn then
            begin
              {sound_music:=MIX_LOADMUS(pchar('sounds/'+maps[player.map].Music));
              MIX_PLAYMUSIC(sound_music,-1);} //Uncomment for music
              DrawMap;
              mapdrawn := true;
            end;
          DoAction;
          DoMapcounterStuff;

          if wildpokemonbattle then
            begin
              mapcounter := 2101;
              WildBattle;
              mapdrawn := false;
            end;
          if talking then
            Talk(personnum);
          if viewingsign then
            Viewsign(signnum);
          if GetKeyState(VK_ESCAPE) < 0 then
            break;
        end;

    end;
end;

////////////////////////////////////////////////////////////////////////////////
///////////         END OF WORLD STUFF           ///////////////////////////////
////////////////////////////////////////////////////////////////////////////////

begin

  {initSDL;} //Uncomment for music

  MovesInit;

  PokemonInit;

  MapsInit;

  PlayerInit;

  Init;

  ImagesInit;

  cursorOff;

  World;

  {ExitGame;} //Uncomment for music

end.

Remarks

Could you make useful additions to this program?

Programming - a skill for life!

by Max Foster: L6 Age ~16