Pascal Pokemon Cross-platform Code
The code of the cross-platform (Raspberry Pi) version of PascalPokemon
/////////////////////////////////////////////////////////////////////////////// /// /// /// PASCAL POKEMON (UNIX/LINUX UPDATE) /// /// by Max Foster /// /// /// /////////////////////////////////////////////////////////////////////////////// { Copyright (c) 2011-2013 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. !!! Now works on Unix/Linux systems. I've removed/commented out the Windows dependent code and !!! !!! replaced it with code that is cross-platform !!! 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, 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; TextImage = array[1..5] of string[14]; //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; } const VK_UP = #72; VK_DOWN = #80; VK_LEFT = #75; VK_RIGHT = #77; VK_RETURN = #13; VK_BACK = #8; VK_ESCAPE = #27; 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 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, viewingsign, talking, changingmap, mapdrawn : boolean; battletypetxt, option : string; launchanimation : array[1..4] of TextImage; playerbackimage : TextImage; itemcount: array[1..3] of integer; itemname: array[1..3] of string = ('Potion','Super Potion','Hyper Potion'); lastKeyPressed: char = #0; {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; } function GetKeyState(key:char) : integer; begin if keyPressed then lastKeyPressed := readKey; if key = lastKeyPressed then result := -1 else result := 1; end; procedure ResetKeyState; begin lastKeyPressed := #0; 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 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);} 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 : TextImage; color : byte; gox : integer; goy : integer; direction : integer; image2 : TextImage; 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 := 1 to 5 do begin gotoXY(gox-j,goy+k-1); 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 := 1 to 5 do begin gotoXY(gox+j,goy+k-1); 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 := 1 to 5 do begin textcolor(color); gotoXY(gox-j,goy+k-1); write(image[k]); textcolor(color2); gotoXY(gox2+j,goy2+k-1); 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 : TextImage; color : byte; gox : integer; goy : integer); var j : integer; begin textColor(color); for j := 1 to 5 do begin gotoXY(gox,goy+j-1); 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('@ '); 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; ResetKeyState; 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 ResetKeyState; 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 ResetKeyState; 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 ResetKeyState; 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 ResetKeyState; 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 ResetKeyState; 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 ResetKeyState; 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; 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; ResetKeyState; 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; ResetKeyState; 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!)). 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; ResetKeyState; end; end; //////////////////////////////////////////////////////////////////////////////// /////////// END OF WORLD STUFF /////////////////////////////// //////////////////////////////////////////////////////////////////////////////// begin {initSDL;} //Uncomment for music MovesInit; PokemonInit; MapsInit; PlayerInit; Init; ImagesInit; cursorOff; World; textBackground(Black); textColor(White); clrscr; {ExitGame;} //Uncomment for music end.
Remarks
Could you make useful additions to this program?