Battle Unit

The battle unit of program TesterGameEngine

unit uBattle;
{
    Copyright (c) 2013 Steven Binns

    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/
}
interface

uses
  Classes, SysUtils, SDL, GL, GLU, GLUT, uGlobalVariables, uCamera, uGeometry;

procedure Battle(eType1, eType2, eType3, eType4: integer);
function AskQuestion(enemy1, enemy2, enemy3, enemy4: Enemy): integer;
procedure EnemyMove(e1, e2, e3, e4, mover: Enemy);

implementation

procedure Battle(eType1, eType2, eType3, eType4: integer);
var
  enemy1, enemy2, enemy3, enemy4 : Enemy;
  eRemaining: integer; //The number of remaining enemies
  BattleCamera: Camera;
  bEvent: pSDL_EVENT;
  currentmenu, menu: integer; //These tell the system the menu cursor's position
  panmode: integer; //tells the system which way to pan in the battle view
  multiplier: integer; //Alters damage based on question answers
  enemmoved: boolean = False; //Have the enemies made their moves?
begin
  enemy1 := enemy.Create(enemies[etype1].ID, enemies[etype1].atk, enemies[etype1].def,
                         enemies[etype1].speed, enemies[etype1].hp);
  //These create separate entities of each enemy so that when they are beaten, it doesn't change
  //their stats in the enemies array.
  enemy2 := enemy.Create(enemies[etype2].ID, enemies[etype2].atk, enemies[etype2].def,
                         enemies[etype2].speed, enemies[etype2].hp);
  enemy3 := enemy.Create(enemies[etype3].ID, enemies[etype3].atk, enemies[etype3].def,
                         enemies[etype3].speed, enemies[etype3].hp);
  enemy4 := enemy.Create(enemies[etype4].ID, enemies[etype4].atk, enemies[etype4].def,
                         enemies[etype4].speed, enemies[etype4].hp);

  if (enemy2.hp = 0) and (enemy3.hp = 0) and (enemy4.hp = 0) then
    TextBox('A wild ' + enemy1.ID + ' appeared!')
  else
    TextBox('Wild monsters appeared!');
  new(bEvent);
  eRemaining := 1;
  if enemy2.hp > 0 then
    eRemaining += 1;
  if enemy3.hp > 0 then
    eRemaining += 1;
  if enemy4.hp > 0 then
    eRemaining += 1;
  currentmenu := 0;
  menu := 0;
  //Set up the camera for the battle scene.
  BattleCamera := Camera.Create(-10, 5, 10);
  ActiveCamera := BattleCamera;
  ActiveCamera.SetUp(Vector.Create(0.0, 1.0, 0.0));
  ActiveCamera.zvector := Vector.Create(0, 0, 0);
  panmode := 1; //Sets how the camera will pan around the battle scene

  //Begin the main battle loop.
  while eRemaining <> 0 do
  begin  //This section will check whether any enemies have a higher speed stat than the player,
         //in which case they will strike before the player each round of combat.
    if enemmoved = False then
    begin
      if enemy1.speed > pspeed then
        EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy1);
      if enemy2.speed > pspeed then
        EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy2);
      if enemy3.speed > pspeed then
        EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy3);
      if enemy4.speed > pspeed then
        EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy4);
      enemmoved := True;
    end;

    if SDL_POLLEVENT(bEvent) = 1 then
    begin
      case bEvent^.type_ of
        SDL_KEYUP:
        begin
          case bEvent^.key.keysym.sym of
            13:
            begin //Select menu option - Enter
              case currentmenu of
                0:
                begin
                  case menu of
                    0:
                    begin  //If the attack option is highlighted, go to the 'target selection' menu.
                      currentmenu := 1;
                      menu := 0;
                    end;
                    3:
                    begin //If the Flee command is highlighted then flee the battle
                          //(For the purposes of demonstration it is easier if there is a 100%
                          //flee chance, however generally there would be an algorithm to determine
                          //the success of the flight based on the player's and enemies' speed or agility stats.)
                      GLRect(-100, 0, +100, +100, 0, -100, 0.5, 0.5, 0.0);
                      GLRect(-0.5, 0.1, 0.5, 0.5, 0.1, -0.5, 1.0, 0.0, 0.0);
                      GLTetrahedron(-5.0, -1.0, -6.0, 0.0, -5.0, 1.0, -5.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
                      TextBox('You fled the battle!');
                      break;
                    end;
                  end;
                end;
                1:
                begin
                  case menu of
                    0:
                    begin  //Attack the first enemy.
                      if enemy1.hp > 0 then
                      begin
                        multiplier := AskQuestion(enemy1, enemy2, enemy3, enemy4);
                        //Bring up the question interface and set the multiplier based on the answers.
                        if (pAtk * multiplier) - enemy1.def > 0 then
                        begin //If the attack did any damage
                          enemy1.hp -= ((pAtk * multiplier) - enemy1.def); //deal the damage
                          TextBox('You did ' + IntToStr((pAtk * multiplier) - enemy1.def) +
                                  ' damage to the ' + enemy1.ID + '!');
                          //and tell the player that he has dealt damage.
                        end
                        else
                          TextBox('You did no damage to the ' + enemy4.ID + '!');
                        //Also tell them if they did no damage
                        ActiveCamera := BattleCamera;
                        if enemy1.hp <= 0 then
                        begin
                          enemy1.hp := 0;
                          eRemaining -= 1;
                        end; //If the enemy has been defeated then decrement the number of remaining enemies.

                        if (enemy1.speed <= pspeed) and (enemy1.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy1);
                        //Once the player has made their move, allow the enemies slower than the player
                        //to make their moves
                        if (enemy2.speed <= pspeed) and (enemy2.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy2);
                        if (enemy3.speed <= pspeed) and (enemy3.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy3);
                        if (enemy4.speed <= pspeed) and (enemy4.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy4);
                        enemmoved := False;
                        currentmenu := 0;
                        //and then return to the base battle menu.
                        menu := 0;
                      end;
                    end;
                    1:
                    begin //See lines 84-105 for comments
                      if enemy2.hp > 0 then
                      begin
                        multiplier := AskQuestion(enemy1, enemy2, enemy3, enemy4);
                        if (pAtk * multiplier) - enemy2.def > 0 then
                        begin
                          enemy2.hp -= ((pAtk * multiplier) - enemy2.def);
                          TextBox('You did ' + IntToStr((pAtk * multiplier) - enemy2.def) +
                                  ' damage to the ' + enemy2.ID + '!');
                        end
                        else
                          TextBox('You did no damage to the ' + enemy4.ID + '!');
                        ActiveCamera := BattleCamera;
                        if enemy2.hp <= 0 then
                        begin
                          enemy2.hp := 0;
                          eRemaining -= 1;
                        end;

                        if (enemy1.speed <= pspeed) and (enemy1.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy1);
                        if (enemy2.speed <= pspeed) and (enemy2.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy2);
                        if (enemy3.speed <= pspeed) and (enemy3.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy3);
                        if (enemy4.speed <= pspeed) and (enemy4.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy4);
                        enemmoved := False;
                        currentmenu := 0;
                        menu := 0;
                      end;
                    end;
                    2:
                    begin //See lines 84-105 for comments
                      if enemy3.hp > 0 then
                      begin
                        multiplier := AskQuestion(enemy1, enemy2, enemy3, enemy4);
                        if (pAtk * multiplier) - enemy3.def > 0 then
                        begin
                          enemy3.hp -= ((pAtk * multiplier) - enemy3.def);
                          TextBox('You did ' + IntToStr((pAtk * multiplier) - enemy3.def) +
                                  ' damage to the ' + enemy3.ID + '!');
                        end
                        else
                          TextBox('You did no damage to the ' + enemy3.ID + '!');
                        ActiveCamera := BattleCamera;
                        if enemy3.hp <= 0 then
                        begin
                          enemy3.hp := 0;
                          eRemaining -= 1;
                        end;

                        if (enemy1.speed <= pspeed) and (enemy1.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy1);
                        if (enemy2.speed <= pspeed) and (enemy2.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy2);
                        if (enemy3.speed <= pspeed) and (enemy3.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy3);
                        if (enemy4.speed <= pspeed) and (enemy4.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy4);
                        enemmoved := False;
                        currentmenu := 0;
                        menu := 0;
                      end;
                    end;
                    3:
                    begin //See lines 84-105 for comments
                      if enemy4.hp > 0 then
                      begin
                        multiplier := AskQuestion(enemy1, enemy2, enemy3, enemy4);
                        if (pAtk * multiplier) - enemy4.def > 0 then
                        begin
                          enemy4.hp -= ((pAtk * multiplier) - enemy4.def);
                          TextBox('You did ' + IntToStr((pAtk * multiplier) - enemy4.def) +
                                  ' damage to the ' +  enemy4.ID + '!');
                        end
                        else
                          TextBox('You did no damage to the ' + enemy4.ID + '!');
                        ActiveCamera := BattleCamera;
                        if enemy4.hp <= 0 then
                        begin
                          enemy4.hp := 0;
                          eRemaining -= 1;
                        end;

                        if (enemy1.speed <= pspeed) and
                          (enemy1.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy1);
                        if (enemy2.speed <= pspeed) and
                          (enemy2.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy2);
                        if (enemy3.speed <= pspeed) and
                          (enemy3.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy3);
                        if (enemy4.speed <= pspeed) and
                          (enemy4.hp > 0) then
                          EnemyMove(enemy1, enemy2, enemy3, enemy4, enemy4);
                        enemmoved := False;

                        currentmenu := 0;
                        menu := 0;
                      end;
                    end;
                  end;
                end;
              end;
            end;
          end;

          if php <= 0 then
          begin //If you've lost all of your health
            TextBox('You have been slain...');
            //tell the player they have lost
            break; //and end the battle.
          end;

          case bEvent^.key.keysym.sym of //These move the menu cursor around
            119:
            begin
              menu -= 2;
              if menu = -1 then
                menu := 1;
              if menu = -2 then
                menu := 0;
            end;//w
            97:
            begin
              menu -= 1;
              if menu = 1 then
                menu := 2;
              if menu = -1 then
                menu := 0;
            end; //a
            115:
            begin
              menu += 2;
              if menu = 4 then
                menu := 2;
              if menu = 5 then
                menu := 3;
            end;//s
            100:
            begin
              menu += 1;
              if menu = 2 then
                menu := 1;
              if menu = 4 then
                menu := 3;
            end;//d
          end;
        end;
      end;
    end;

    glMATRIXMODE(GL_MODELVIEW);
    glLOADIDENTITY();            //Again resets the drawing buffers
    glClear(GL_COLOR_BUFFER_BIT);

    BattleCamera.Activate(WndW, WndH, True);

    //Draw the battle scene
    GLRect(-100, 0, +100, +100, 0, -100, 0.5, 0.5, 0.0); //The floor
    GLRect(-0.5, 0.1, 0.5, 0.5, 0.1, -0.5, 1.0, 0.0, 0.0);
    //A small square to make the battle scene look more interesting :D
    GLTetrahedron(-5.0, -1.0, -6.0, 0.0, -5.0, 1.0, -5.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    //Stand-in for Player Model
    if enemy1.hp > 0 then
      GLTetrahedron(5.0, -1.0, 6.0, 0.0, 5.0, 1.0, 5.5, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    //If the hp of the enemy is not 0 the draw the stand in for the enemy1 model
    if enemy2.hp > 0 then
      GLTetrahedron(3.0, -6.0, 4.0, -5.0, 3.0, -4.0, 3.5, 2.0, -5.0, 0.0, 0.54, 0.54, 0.54);
    //Stand in for enemy2 model
    if enemy3.hp > 0 then
      GLTetrahedron(3.0, 4.0, 4.0, 5.0, 3.0, 6.0, 3.5, 2.0, 5.0, 0.0, 0.0, 0.0, 1.0);
    //Stand in for enemy3 model
    if enemy4.hp > 0 then
      GLTetrahedron(9.0, -1.0, 10.0, 0.0, 9.0, 1.0, 9.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    //Stand in for enemy4 model

    //This section draws the menu visible at the bottom of the battle screen
    Start2D; //Switch to 2D drawing mode in OpenGl
    glBegin(GL_QUADS);
    glColor3f(0.0, 0.0, 0.0);       //draws the background of the menu
    glVertex2f(5.0, WndH - 475);
    glVertex2f(WndW - 5, WndH - 475);
    glVertex2f(WndW - 5, WndH - 360);
    glVertex2f(5.0, WndH - 360);
    glEnd();
    glBegin(GL_LINE_LOOP);
    glColor3f(1.0, 0.0, 0.0);         //draws the outline of the menu
    glVertex2f(5, WndH - 475);
    glVertex2f(WndW - 5, WndH - 475);
    glVertex2f(WndW - 5, WndH - 360);
    glVertex2f(5, WndH - 360);
    glEnd();
    if currentmenu = 0 then
    begin
      DrawText(20, 95, 'Attack');       //draws the text for the menu
      DrawText(150, 95, 'Skills');
      DrawText(20, 35, 'Items');
      DrawText(150, 35, 'Flee');
    end
    else if currentmenu = 1 then
    begin
      if enemy1.hp > 0 then
        DrawText(20, 95, enemy1.ID);
      if enemy2.hp > 0 then
        DrawText(150, 95, enemy2.ID);
      if enemy3.hp > 0 then
        DrawText(20, 35, enemy3.ID);
      if enemy4.hp > 0 then
        DrawText(150, 35, enemy4.ID);
    end;
    case menu of
      0: DrawText(110, 95, '<');
      1: DrawText(250, 95, '<');
      2: DrawText(110, 35, '<');
      3: DrawText(250, 35, '<');
    end;
    DrawText(300, 95, 'Player: ' + IntToStr(pHP) + '/' + IntToStr(pMHP));
    if enemy1.hp > 0 then
      DrawText(300, 55, enemy1.ID + ': ' + IntToStr(enemy1.hp) + '/' +
               IntToStr(enemies[eType1].hp));
    if enemy2.hp > 0 then
      DrawText(300, 25, enemy2.ID + ': ' + IntToStr(enemy2.hp) + '/' +
               IntToStr(enemies[eType2].hp));
    if enemy3.hp > 0 then
      DrawText(465, 55, enemy3.ID + ': ' + IntToStr(enemy3.hp) + '/' +
               IntToStr(enemies[eType3].hp));
    if enemy4.hp > 0 then
      DrawText(465, 25, enemy4.ID + ': ' + IntToStr(enemy4.hp) + '/' +
               IntToStr(enemies[eType4].hp));
    End2D; //Stop drawing the menu and return to 3D drawing mode.

    //This section checks the position of the camera and changes the direction in which it pans
    //and its position accordingly.
    if (ActiveCamera.posn.x > 10) and (ActiveCamera.posn.y = 5) and
       (ActiveCamera.posn.z = 10) then
    begin
      ActiveCamera.setposn(0, 3, -15);
      panmode := 2;
    end;

    if (ActiveCamera.posn.x = 0) and (ActiveCamera.posn.y > 6.2) and
       (ActiveCamera.posn.z = -15) then
    begin
      ActiveCamera.SetPosn(-15, 5, 3);
      panmode := 3;
    end;

    if (ActiveCamera.posn.x = -15) and (ActiveCamera.posn.y = 5) and
       (ActiveCamera.posn.z < -3) then
    begin
      ActiveCamera.SetPosn(-10, 5, 10);
      panmode := 1;
    end;

    if panmode = 1 then
    begin
      ActiveCamera.SetPosn(ActiveCamera.posn.x + 0.005,
                           ActiveCamera.posn.y, ActiveCamera.posn.z);
      ActiveCamera.zvector := Vector.Create(0, 0, 0);
    end;
    if panmode = 2 then
    begin
      ActiveCamera.SetPosn(ActiveCamera.posn.x, ActiveCamera.posn.y + 0.001,
                           ActiveCamera.posn.z);
      ActiveCamera.zvector := Vector.Create(0, 0, 0);
    end;
    if panmode = 3 then
    begin
      ActiveCamera.SetPosn(ActiveCamera.posn.x, ActiveCamera.posn.y,
                           ActiveCamera.posn.z - 0.0025);
      ActiveCamera.zvector := Vector.Create(0, 0, 0);
    end;

    SDL_GL_SWAPBUFFERS; //Redraw the scene.
  end;
  ActiveCamera := MainCamera;
  //Once the battle is over, switch back to the main scene's camera.
end;

function AskQuestion(enemy1, enemy2, enemy3, enemy4: Enemy): integer;
var
  Number: integer = 0;
  Qnumber: array [0 .. 2] of integer;
  selection1, selection2, timer, i: integer;
  selected1, selected2: boolean;
  local_event: pSDL_EVENT;
  order: array [0 .. 5] of integer;
begin
  selection1 := 0;
  selection2 := 0;
  timer := 30001;
  selected1 := False;
  selected2 := False;
  new(local_event);

  //This section randomises the order in which the answers are displayed.
  order[0] := Random(6);
  repeat
    order[1] := Random(6);
  until order[1] <> order[0];
  repeat
    order[2] := Random(6);
  until (order[2] <> order[0]) and (order[2] <> order[1]);
  repeat
    order[3] := Random(6);
  until (order[3] <> order[0]) and (order[3] <> order[1]) and (order[3] <> order[2]);
  repeat
    order[4] := Random(6);
  until (order[4] <> order[0]) and (order[4] <> order[1]) and (order[4] <> order[2]) and
        (order[4] <> order[3]);
  repeat
    order[5] := Random(6);
  until (order[5] <> order[0]) and (order[5] <> order[1]) and (order[5] <> order[2]) and
        (order[5] <> order[3]) and (order[5] <> order[4]);

  while Questions[Number].QNumber <> '' do
  begin
    Number += 1;
  end;
  //Randomly pick 3 topics from the Questions database.
  Qnumber[0] := Random(Number);
  repeat
    Qnumber[1] := Random(Number);
  until Qnumber[1] <> Qnumber[0];
  repeat
    Qnumber[2] := Random(Number);
  until (Qnumber[2] <> Qnumber[0]) and (Qnumber[2] <> Qnumber[1]);
  Count := 0;

  //Deal with Topic UI
  while selected1 = False do
  begin
    //Interactions
    if SDL_POLLEVENT(local_event) = 1 then
    begin
      case local_event^.type_ of
        SDL_KEYUP:
        begin
          case local_event^.key.keysym.sym of
            115:
            begin
              if selection1 < 2 then
                selection1 += 1
              else
                selection1 := 0;
            end;
            119:
            begin
              if selection1 > 0 then
                selection1 -= 1
              else
                selection1 := 2;
            end;
            13: selected1 := True;
          end;
        end;
      end;
    end;

    //Draw it
    glMATRIXMODE(GL_MODELVIEW);
    glLOADIDENTITY();
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

    ActiveCamera.Activate(WndW, WndH, False);

    //Draw the battle scene behind the UI.
    GLRect(-100, 0, +100, +100, 0, -100, 0.5, 0.5, 0.0);
    GLRect(-0.5, 0.1, 0.5, 0.5, 0.1, -0.5, 1.0, 0.0, 0.0);
    GLTetrahedron(-5.0, -1.0, -6.0, 0.0, -5.0, 1.0, -5.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    //Stand-in for Player Model
    if enemy1.hp > 0 then
      GLTetrahedron(5.0, -1.0, 6.0, 0.0, 5.0, 1.0, 5.5, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    //Stand in for Enemy1 Model
    if enemy2.hp > 0 then
      GLTetrahedron(3.0, -6.0, 4.0, -5.0, 3.0, -4.0, 3.5, 2.0, -5.0, 0.0, 0.54, 0.54, 0.54);
    //Stand in for Enemy2 Model
    if enemy3.hp > 0 then
      GLTetrahedron(3.0, 4.0, 4.0, 5.0, 3.0, 6.0, 3.5, 2.0, 5.0, 0.0, 0.0, 0.0, 1.0);
    //Stand in for Enemy3 Model
    if enemy4.hp > 0 then
      GLTetrahedron(9.0, -1.0, 10.0, 0.0, 9.0, 1.0, 9.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    //Stand in for Enemy4 Model

    //Draw the actual UI
    Start2D;
    glBegin(GL_QUADS);                  //draw the background of the UI
    glColor3f(0.0, 0.0, 0.0);
    glVertex2i(50, 50);
    glVertex2i(WndW - 50, 50);
    glVertex2i(WndW - 50, WndH - 50);
    glVertex2i(50, WndH - 50);
    glEnd();
    glBegin(GL_LINE_LOOP);              //draw the outline of the UI
    glColor3f(1.0, 0.0, 0.0);
    glVertex2i(50, WndH - 50);
    glVertex2i(WndW - 50, WndH - 50);
    glVertex2i(WndW - 50, 50);
    glVertex2i(50, 50);
    glEnd();
    DrawText(240, WndH - 90, 'Choose a topic');
    case selection1 of //Draw the topic names and the cursor
      0:
      begin
        DrawText(121, WndH - 200, '> ' + Questions[QNumber[0]].QSubject);
        DrawText(140, WndH - 250, Questions[QNumber[1]].QSubject);
        DrawText(140, WndH - 300, Questions[QNumber[2]].QSubject);
      end;
      1:
      begin
        DrawText(140, WndH - 200, Questions[QNumber[0]].QSubject);
        DrawText(121, WndH - 250, '> ' + Questions[QNumber[1]].QSubject);
        DrawText(140, WndH - 300, Questions[QNumber[2]].QSubject);
      end;
      2:
      begin
        DrawText(140, WndH - 200, Questions[QNumber[0]].QSubject);
        DrawText(140, WndH - 250, Questions[QNumber[1]].QSubject);
        DrawText(121, WndH - 300, '> ' + Questions[QNumber[2]].QSubject);
      end;
    end;
    End2D;
    SDL_GL_SWAPBUFFERS();

  end;
  glMATRIXMODE(GL_MODELVIEW);
  glLOADIDENTITY();
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  while selected2 = False do
  begin
    timer -= 1;
    //Answers UI
    if SDL_POLLEVENT(local_event) = 1 then
    begin
      case local_event^.type_ of
        SDL_KEYUP:
        begin
          case local_event^.key.keysym.sym of
            115:
            begin
              if selection2 < 5 then
                selection2 += 1
              else
                selection2 := 0;
            end;
            119:
            begin
              if selection2 > 0 then
                selection2 -= 1
              else
                selection2 := 5;
            end;
            13: selected2 := True;
          end;
        end;
      end;
    end;

    glMATRIXMODE(GL_MODELVIEW);
    glLOADIDENTITY();
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

    ActiveCamera.Activate(WndW, WndH, False);

    //Draw the battle scene
    GLRect(-100, 0, +100, +100, 0, -100, 0.5, 0.5, 0.0);
    GLRect(-0.5, 0.1, 0.5, 0.5, 0.1, -0.5, 1.0, 0.0, 0.0);
    GLTetrahedron(-5.0, -1.0, -6.0, 0.0, -5.0, 1.0, -5.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    //Stand-in for Player Model

    if enemy1.hp > 0 then
      GLTetrahedron(5.0, -1.0, 6.0, 0.0, 5.0, 1.0, 5.5, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    //Stand in for Enemy1 Model
    if enemy2.hp > 0 then
      GLTetrahedron(3.0, -6.0, 4.0, -5.0, 3.0, -4.0, 3.5, 2.0, -5.0, 0.0, 0.54, 0.54, 0.54);
    //Stand in for Enemy2 Model
    if enemy3.hp > 0 then
      GLTetrahedron(3.0, 4.0, 4.0, 5.0, 3.0, 6.0, 3.5, 2.0, 5.0, 0.0, 0.0, 0.0, 1.0);
    //Stand in for Enemy3 Model
    if enemy4.hp > 0 then
      GLTetrahedron(9.0, -1.0, 10.0, 0.0, 9.0, 1.0, 9.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    //Stand in for Enemy4 Model

    Start2D;                                //See lines 377 and 384
    glBegin(GL_QUADS);
    glColor3f(0.0, 0.0, 0.0);
    glVertex2i(50, 50);
    glVertex2i(WndW - 50, 50);
    glVertex2i(WndW - 50, WndH - 50);
    glVertex2i(50, WndH - 50);
    glEnd();
    glBegin(GL_LINE_LOOP);
    glColor3f(1.0, 0.0, 0.0);
    glVertex2i(50, WndH - 50);
    glVertex2i(WndW - 50, WndH - 50);
    glVertex2i(WndW - 50, 50);
    glVertex2i(50, 50);
    glEnd();
    DrawText(75, WndH - 75, IntToStr(timer div 1000));
    DrawText(75, WndH - 125, Questions[Qnumber[selection1]].QQuestion);
    DrawText(56, WndH - 175 - 25 * selection2,  '> ');

    for i := 0 to 5 do
    begin
      case order[i] of
        0: DrawText(75, WndH - (175 + (25 * i)), Questions[Qnumber[selection1]].Qanswer0);
        1: DrawText(75, WndH - (175 + (25 * i)), Questions[Qnumber[selection1]].Qanswer1);
        2: DrawText(75, WndH - (175 + (25 * i)), Questions[Qnumber[selection1]].Qanswer2);
        3: DrawText(75, WndH - (175 + (25 * i)), Questions[Qnumber[selection1]].Qanswer3);
        4: DrawText(75, WndH - (175 + (25 * i)), Questions[Qnumber[selection1]].Qanswer4);
        5: DrawText(75, WndH - (175 + (25 * i)), Questions[Qnumber[selection1]].Qanswer5);
      end;
    end;
    End2D;
    SDL_GL_SWAPBUFFERS();
  end;

  if order[selection2] = 0 then
  begin //If the answer is correct
    if timer div 100 > 20 then
      AskQuestion := 2; //and the user answered in 10 seconds or less, apply a 'Critical 2x Multiplier'
    if timer div 100 < 20 then
      AskQuestion := 1; //otherwise apply a 1x multiplier and do base damage.
  end
  else
    AskQuestion := 0; //If the answer is wrong set the multiplier to 0 so you do no damage.
end;

procedure EnemyMove(e1, e2, e3, e4, mover: Enemy);
begin
  glMATRIXMODE(GL_MODELVIEW);
  glLOADIDENTITY();
  glClear(GL_COLOR_BUFFER_BIT);

  ActiveCamera.Activate(WndW, WndH, True);

  //Make sure the scene stays on in the background.
  GLRect(-100, 0, +100, +100, 0, -100, 0.5, 0.5, 0.0);
  GLRect(-0.5, 0.1, 0.5, 0.5, 0.1, -0.5, 1.0, 0.0, 0.0);
  GLTetrahedron(-5.0, -1.0, -6.0, 0.0, -5.0, 1.0, -5.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
  //Stand-in for Player Model
  if e1.hp > 0 then
    GLTetrahedron(5.0, -1.0, 6.0, 0.0, 5.0, 1.0, 5.5, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  //Stand in for Enemy1 Model
  if e2.hp > 0 then
    GLTetrahedron(3.0, -6.0, 4.0, -5.0, 3.0, -4.0, 3.5, 2.0, -5.0, 0.0, 0.54, 0.54, 0.54);
  //Stand in for Enemy2 Model
  if e3.hp > 0 then
    GLTetrahedron(3.0, 4.0, 4.0, 5.0, 3.0, 6.0, 3.5, 2.0, 5.0, 0.0, 0.0, 0.0, 1.0);
  //Stand in for Enemy3 Model
  if e4.hp > 0 then
    GLTetrahedron(9.0, -1.0, 10.0, 0.0, 9.0, 1.0, 9.5, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0);
  //Stand in for Enemy4 Model
  SDL_GL_SWAPBUFFERS;
  //Deal with the enemy attacking
  if mover.hp > 0 then
  begin
    if pspeed - mover.speed > 0 then
    begin //If the player is faster than the enemy
      if Random(100) <= 100 - (pspeed - mover.speed) then
      begin //If the player didn't avoid the attack
        if Random(100) < 75 then
        begin //If the enemy's attack hits
          if mover.atk - pdef > 0 then
          begin //If the attack did any damage
            TextBox('The ' + mover.ID + ' did ' + IntToStr(mover.atk - pdef) + ' damage!');
            php -= (mover.atk - pdef);
          end
          else
            textbox('The ' + mover.ID + '''s attack did no damage!');
        end
        else
          textbox('The ' + mover.ID + '''s attack missed!');
      end
      else
        textbox('You avoided the ' + mover.ID + '''s attack!');
    end
    else
    begin
      if Random(100) < 75 then
      begin //If the enemy attack hits
        if mover.atk - pdef > 0 then
        begin //If the attack did any damage
          TextBox('The ' + mover.ID + ' did ' + IntToStr(mover.atk - pdef) + ' damage!');
          php -= (mover.atk - pdef);
        end;
      end
      else
        textbox('The ' + mover.ID + '''s attack missed!');
    end;
  end;
end;

end.
Programming - a skill for life!

by Steven Binns: Y12 Age ~17