program Risk; { Copyright (c) 2011 Michael Wardley 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/ } uses SysUtils, Math, Crt; type TCountry = record CName : string; CID : integer; TroopCount : integer; Cash : integer; POwn : Boolean; Team : String; end; var PName : String; Country : array[1 .. 10] of TCountry; Count, Player, NumberOwned, PlayerCash, Target, From, Turns : integer; CPUA, CPUB : integer; const STARTTROOP = 10; STARTCASH = 100; procedure Welcome; // welcome and player details input begin writeln('Welcome to Risk, the classic Strategy Game'); sleep(50); write('Please enter your name '); readln(PName); PName := 'General ' + PName; sleep(50); writeln(PName, ', what country would you like to start in?'); for Count := 1 to 10 do //display list of countries to choose from begin with Country[Count] do begin writeln(CID, ': ', CName); end; end; write('Enter the number of your chosen country '); readln(Player); end; procedure CountryDetails; //pre-entered country details begin Country[1].CName := 'Britain'; Country[1].CID := 1; Country[2].CName := 'France'; Country[2].CID := 2; Country[3].CName := 'Germany'; Country[3].CID := 3; Country[4].CName := 'Russia'; Country[4].CID := 4; Country[5].CName := 'China'; Country[5].CID := 5; Country[6].CName := 'Japan'; COuntry[6].CID := 6; Country[7].CName := 'Korea'; Country[7].CID := 7; Country[8].CName := 'India'; Country[8].CID := 8; Country[9].CName := 'USA'; Country[9].CID := 9; Country[10].CName := 'Middle East'; Country[10].CID := 10; end; procedure Setup; var RedCount, BlueCount, GreenCount : integer; begin for Count := 1 to 10 do // sets all countries to CPU ownership and default cash and troop levels begin with Country[Count] do begin POwn := False; TroopCount := STARTTROOP; Cash := STARTCASH; end; end; Country[Player].POwn := True; // sets chosen country to player owned NumberOwned := 1; PlayerCash := Country[Player].Cash; Turns := 1; RedCount := 0; BlueCount := 0; GreenCount := 0; for Count := 1 to 10 do //setting countries to teams but not player owned begin if Country[Count].POwn = False then begin if RedCount < 3 then begin Country[Count].Team := 'Red'; RedCount := RedCount + 1 end else if BlueCount < 3 then begin Country[Count].Team := 'Blue'; BlueCount := BlueCount + 1 end else if GreenCount < 3 then begin Country[Count].Team := 'Green'; GreenCount := GreenCount + 1; end; end; end; writeln('Game is being Setup...'); sleep(100); writeln('Game is ready. Press Enter to begin'); readln; sleep(100); end; procedure FirstTurn; // basic introduction to game and announcment of values begin clrscr; writeln('Congratulations ', PName, ' you are now the ruler of ', Country[Player].CName); sleep(100); writeln('Your country starts off with ', Country[Player].TroopCount, ' loyal units of soldiers'); writeln('and $', PlayerCash, ' cash to invest on your plans of world domination.'); writeln('Each turn you can perform a series of moves'); writeln('-You can attack another country'); writeln('-You can move your troops between countries you own'); writeln('-You can invest into your country'); writeln('-You can end your turn, and you will receive an extra $100'); writeln('for each country you own'); writeln('All the commands require a character entered in upper case'); writeln('so toggle CAPS LOCK before you start!'); writeln('If in doubt, just press ENTER'); readln; end; procedure Move; var Transfer : Integer; Again : Char; begin if NumberOwned > 1 then begin repeat clrscr; for Count := 1 to 10 do //display all countries owned by player begin if Country[Count].POwn = True then begin writeln(Country[Count].CID,' ', Country[Count].CName, ': ', Country[Count].TroopCount, ' Troops. '); end; end; write('Select a country to move troops from. (Choose a number.) '); readln(From); if Country[From].POwn = False then //validation player owns country begin repeat write('You do not own that country. Select one you do own. '); readln(From); until Country[From].POwn = True; end; write('Now select the country you would like to transfer troops to. '); readln(Target); if Country[Target].POwn = False then // validation player owns country begin repeat write('You do not own that country. Select one you do own. '); readln(Target); until Country[Target].POwn = True; end; write('How many would you like to transfer from ', Country[From].CName, '? Which has ', Country[From].TroopCount, ' troops remaining. '); //transfer of troops readln(Transfer); //validation so the number of troops sent is less than the than all that exist if Transfer > Country[From].TroopCount then begin repeat write('You do not have that many troops in', Country[From].CName, '. Please enter a smaller amount. '); readln(Transfer); until Transfer <= Country[From].TroopCount; end; Country[From].TroopCount := Country[From].TroopCount - Transfer; //adjusting troops numbers Country[Target].TroopCount := Country[Target].TroopCount + Transfer; writeln('Sending troops '); sleep(100); writeln('Troops sent'); writeln('Would you like to send more troops? Y/N'); readln(Again); until Again = 'N'; end else begin writeln('You only own one country.'); readln; end; end; procedure Captured; // action when a country is captured begin clrscr; NumberOwned := NumberOwned + 1; Country[Target].POwn := True; writeln('You have captured', Country[Target].CName, ' and can spend the $', Country[Target].Cash, ' left there.'); PlayerCash := PlayerCash + Country[Target].Cash; //transferring country's cash to player for Count := 1 to 10 do //display all countries owned by player begin if Country[Count].POwn = True then begin writeln(Country[Count].CID, ' ', Country[Count].CName,': ', Country[Count].TroopCount, ' Troops'); end; end; writeln('Your empire has $', PlayerCash); readln; Move; readln; end; procedure EndGameLose; // end of game when no countries left begin writeln('Endgame lose'); writeln('Unlucky ', PName, ', your empire has been defeated.'); readln; halt; end; procedure EndGameWin; // end of game when player owns all countries begin writeln('Endgame win'); writeln('Congratulations ', PName, ' your empire rules the whole world.'); writeln('It took you only ', Turns, ' to conquer all 10 countries, and accumulate $', PlayerCash); readln; halt; end; procedure Attack; //attack move on enemy var PTroopNo, CPUTroopNo : integer; PDice, CPUDice, PTroopScore, CPUTroopScore, FinalTroopScore : integer; Again : Char; BattleOver : Boolean; TargetC : String; begin randomize; BattleOver := False ; write('Which country would you like to attack from? (Choose a number.) '); readln(From); if Country[From].POwn = False then //validation so players send troops from own country repeat write('You do not currently own ', Country[From].CName, '. Enter a country you do own. '); readln(From); until Country[From].POwn = True; for Count := 1 to 10 do // display list of countries not owned by player begin if Country[Count].POwn = False then begin writeln(Country[Count].CID,' ', Country[Count].CName,': ', Country[Count].TroopCount, ' Troops, $', Country[Count].Cash, ' Team:', Country[Count].Team ); end; end; write('Which country would you like to attack? (C to cancel) '); readln(TargetC); if TargetC <> 'C' then begin Target := Strtoint(TargetC); if Country[Target].POwn = True then // validation so players cannot attack their own countries repeat write('You currently own ', Country[Target].CName, '. Enter a country you do not own. '); readln(Target); until Country[Target].POwn = False; repeat clrscr; writeln(Country[From].CName, ' prepare to attack ', Country[Target].CName); repeat write(Country[From].CName,' has ', Country[From].TroopCount, ' troops available for combat. (Select a maximum of 3.) '); readln(PTroopNo); //validate player troop no is <= 3 //test for cheating until (PTroopNo <= 3) and (PTroopNo > 0) and (PTroopNo <= Country[From].TroopCount); writeln(Country[From].CName,' have sent ', PTroopNo, ' troops into battle.'); if Country[Target].TroopCount >= 3 then //decides how many troops CPU will play begin CPUTroopNo := 3 end; if Country[Target].TroopCount < 3 then begin CPUTroopNo := Country[Target].TroopCount; end; writeln(Country[Target].CName, ' sends forward ', CPUTroopNo, ' troops.'); PDice := random(6) + 1; //generates troop multiplier CPUDice := random(6) + 1; PTroopScore := (PTroopNo * PDice) + 1; //applies troop multiplier CPUTroopScore := CPUTroopNo * CPUDice; FinalTroopScore := PTroopScore - CPUTroopScore; //difference between scores writeln('After hours of intense battle...'); case FinalTroopScore of -18 .. -1 : begin writeln(Country[Target].CName, ' have defeated ', Country[From].CName); //kills player troops Country[From].TroopCount := Country[From].TroopCount - PTroopNo end; 0 : begin writeln('Both sides have encountered equal losses.'); Country[From].TroopCount := Country[From].TroopCount - PTroopNo; //kills both troops Country[Target].TroopCount := Country[Target].TroopCount - CPUTroopNo end; 1 .. 19 : begin writeln(Country[From].CName,' have defeated ', Country[Target].CName); //kills CPU troops Country[Target].TroopCount := Country[Target].TroopCount - CPUTroopNo end; end; if Country[From].TroopCount <= 0 then // stops there being negative troops begin Country[From].TroopCount := 0; BattleOver := True; end; if Country[Target].TroopCount <= 0 then begin Country[Target].TroopCount := 0; BattleOver := True; end; writeln(Country[From].CName,' have ', Country[From].TroopCount, ' troops remaining. ', Country[Target].CName,' have ', Country[Target].TroopCount, ' troops remaining.'); if (Country[From].TroopCount = 0) then // reduces countries owned by one begin NumberOwned := NumberOwned - 1; writeln('You have lost ', Country[From].CName); Country[From].POwn := False; if NumberOwned = 0 then EndGameLose; readln; end; if (Country[Target].TroopCount = 0) then //runs captured procedure if player has conquered a country begin Captured; end; if BattleOver = False then // asking to attack again, if neither side has currently won begin write('Would you like to attack this country again? Y/N? '); readln(Again); end; until (Again = 'N') or (Again ='n') or (BattleOver = True); readln; end; end; procedure Spend; var UnitNo, Cost, UnitPrice, Max : Integer; TargetC : String; begin clrscr; UnitPrice := 50; writeln('Spend'); writeln('You currently have $', PlayerCash, ' available to spend.'); if PlayerCash > 0 then begin writeln('You can purchase extra units of troops at $', UnitPrice, ' each.') ; for Count := 1 to 10 do //display all countries owned by player begin if Country[Count].POwn = True then begin writeln(Country[Count].CID,' ', Country[Count].CName,': ', Country[Count].TroopCount,' Troops. '); end; end; write('Where would you like to buy new troops for? (C to Cancel) '); readln(TargetC); if TargetC <> 'C' then // allows user to leave begin if Country[Strtoint(TargetC)].POwn = False then //validates whether player owns country begin repeat write('You do not own this country. Select another to send troops to. '); readln(TargetC); until Country[Strtoint(TargetC)].POwn = True; end; Max := PlayerCash DIV UnitPrice; write('How many extra units would you like to buy? Up to a max of ', Max, ' '); readln(UnitNo); Cost := UnitPrice * UnitNo; if Cost > PlayerCash then //validates whether player can afford desired troops begin repeat write('You do not have $', Cost, ' to spend. Select a fewer number of troops. '); readln(UnitNo); Cost := UnitPrice * UnitNo; until Cost < Player; end; PlayerCash := PlayerCash - Cost; //re-adjusts troops and cash Country[Strtoint(TargetC)].TroopCount := Country[Strtoint(TargetC)].TroopCount + UnitNo; end; end else readln; end; procedure PlayerTurn; var Choice : Char; begin repeat clrscr; for Count := 1 to 10 do //display all countries owned by player begin if Country[Count].POwn = True then begin writeln(Country[Count].CID, ' ', Country[Count].CName, ': ', Country[Count].TroopCount, ' Troops.'); end; end; writeln('Your empire has $', PlayerCash, '. Turns:', Turns); writeln('What would you like to do now?'); write('A:Attack, M:Move, S:Spend, E:End '); readln(Choice); case Choice of //reads in player mover choice 'A' : Attack; 'M' : Move; 'S' : Spend; end; until (Choice = 'E') or (NumberOwned = 0) or (NumberOwned = 10); readln; Turns := Turns + 1; end; procedure Defeat; var Trans : integer; begin writeln(Country[CPUB].Team, Country[CPUA].Team); Country[CPUA].POwn := False; Country[CPUB].Team := Country[CPUA].Team; writeln(Country[CPUA].CName,' have defeated ', Country[CPUB].CName, ' and it becomes part of the ', Country[CPUB].Team, ' empire.'); Country[CPUB].TroopCount := 0; Trans := Country[CPUA].TroopCount DIV 2; //ADD : OPTIMISE BEST COUNTRY TO SEND TROOPS FROM Country[CPUA].TroopCount := Country[CPUA].TroopCount - Trans; //NOT JUST ATTACKING COUNTRY Country[CPUB].TroopCount := Trans; end; procedure Defend; var Choice : Char; TroopNo, Bribe : integer; ADice, BDice, ATroopScore, BTroopScore, FinalTroopScore : integer; begin randomize; writeln('You are under attack from ', Country[CPUA].CName); repeat write('Do you want to D: Defend the attack, or B: Bribe your attackers to retreat? '); readln(Choice); until (Choice = 'D') or (Choice = 'B'); case Choice of 'D': begin repeat write(Country[CPUA].CName,' are attacking with 3 troops. How many would you like to defend with? '); readln(TroopNo); until (TroopNo <= 3) and (TroopNo <= Country[CPUB].TroopCount); //Can only defend with max 3 troops or max troops owned ADice := random(6) + 1; BDice := random(6) + 1; ATroopScore := ADice * 3; BTroopScore := BDice * TroopNo; FinalTroopScore := ATroopScore - BTroopScore; case FinalTroopScore of 0 : begin Country[CPUA].TroopCount := Country[CPUA].TroopCount - 1; Country[CPUB].TroopCount := Country[CPUB].TroopCount - 1; writeln('Equal losses'); end; 1 .. 18 : begin Country[CPUB].TroopCount := Country[CPUB].TroopCount - 3; writeln('You have been successfully attacked'); end; -18 .. -1 : begin Country[CPUA].TroopCount := Country[CPUA].TroopCount - 3; writeln('You have defended your Country'); end; end; if Country[CPUB].TroopCount <= 0 then Defeat; end; 'B' : begin bribe := random(3) + 1; //Pay a random amount of cash to repel enemy troops bribe := bribe * 50; writeln('It will cost you $', bribe, ' to protect your Country from attack'); PlayerCash := PlayerCash - bribe; Country[CPUA].Cash := Country[CPUA].Cash + bribe; end; end; end; procedure CPUAttack; var ADice, BDice, ATroopScore, BTroopScore, FinalTroopScore : integer; begin randomize; if Country[CPUB].POwn = False then //Battle between two CPU countries begin write(Country[CPUA].CName,' attack ', Country[CPUB].CName,'. '); ADice := random(6) + 1; BDice := random(6) + 1; ATroopScore := ADice * 3; BTroopScore := BDice * 3; FinalTroopScore := ATroopScore - BTroopScore; case FinalTroopScore of 0 : begin Country[CPUA].TroopCount := Country[CPUA].TroopCount - 1; Country[CPUB].TroopCount := Country[CPUB].TroopCount - 1; writeln('Equal losses'); end; 1 .. 18 : begin Country[CPUB].TroopCount := Country[CPUB].TroopCount - 3; writeln('And succeed'); end; -18 .. -1 : begin Country[CPUA].TroopCount := Country[CPUA].TroopCount - 3; writeln('And fail'); end; end; if Country[CPUB].TroopCount <= 0 then Defeat; //If a country is captured end else Defend; //If a player owned country is attacked readln; end; procedure CPUAttackCheck; var Countx, Diff : Integer; Rand : Real; Attacked : array [1 .. 10] of integer; begin randomize; for Countx := 1 to 10 do Attacked[Countx] := 0; //iniatialising attack counts to blanks for Count := 1 to 10 do if Country[Count].POwn = False then //all countries not owned by player begin for Countx := 1 to 10 do begin if (Countx <> Count) and (Country[Count].Team <> Country[Countx].Team) then begin Diff := Country[Count].TroopCount - Country[Countx].TroopCount; if (Diff > 3) and (Country[Count].TroopCount > 3) then begin CPUA := Count; CPUB := Countx; //Store the number of times a country is attacked each turn. Attacked[Countx] := Attacked[Countx] + 1; Rand := random(); //Prevent countries being attacked more than 3 times. Anti-bullying if (Rand > 0.6) and (Attacked[Countx] <= 3) then begin CPUAttack; end; end; end; end; end; end; procedure CPUTurn; var Spend, UnitPrice, AddCash : Integer; Rand : Real; begin randomize; clrscr; UnitPrice := 50; for Count := 1 to 10 do //display all countries not owned by player begin if Country[Count].POwn = False then with Country[Count] do begin Cash := Cash + 100; //adds cash at end of turn Rand := random(); if rand > 0.5 then //so countries don't spend every turn begin Spend := Cash DIV 100; // divides the cash by 100 Spend := Trunc(Spend); if Spend > 1 then //spending any excess they have of $100 begin TroopCount := TroopCount + Spend; //makes countries troops expand Cash := Cash - (Spend * UnitPrice); end; end; end; end; AddCash := 100 * NumberOwned; PlayerCash := PlayerCash + AddCash; CPUAttackCheck; end; //ORDER IN WHICH COUNTRIES ATTACK CHECK SHOULD BE RANDOM //CREATE A WEAPONS UPGRADE DEVELOPMENT SYSTEM : ARMOURY / BLACKSMITHS / WALLS //CREATE SAVE FUNCTION //WRITE HELPFILE IN FIRST TURN //FIX BUG WHERE COUNTRY OBTAINS 4million ODD TROOPS [PPS: if bug still exists] //REWRITE USING PARAMETERS //add cancel function on attack DONE //validate defend bribe DONE //MAKE CPU ATTACK EACH OTHER AND PLAYER DONE begin CountryDetails; Welcome; Setup; FirstTurn; repeat PlayerTurn; //add ability to save and load games CPUTurn; until (NumberOwned = 0) or (NumberOwned = 10); if NumberOwned = 0 then EndGameLose; if NumberOwned = 10 then EndGameWin; readln; end.