unit kys_battle;

interface

uses
  SysUtils,
  Windows,
  math,
  Dialogs,
  SDL,
  SDL_TTF,
  SDL_mixer,
  SDL_image,
  kys_main;

//战斗
//从游戏文件的命名来看, 应是'war'这个词的缩写,
//但实际上战斗的规模很小, 使用'battle'显然更合适
function Battle(battlenum, getexp: integer): boolean;
function InitialBField: boolean;
function SelectTeamMembers: integer;
procedure ShowMultiMenu(max, menu, status: integer);
procedure BattleMainControl;
procedure CalMoveAbility;
procedure ReArrangeBRole;
function BattleStatus: integer;
function BattleMenu(bnum: integer): integer;
procedure ShowBMenu(MenuStatus, menu, max: integer);
procedure Move(bnum: integer);
procedure MoveAmination(bnum: integer);
function SelectAim(bnum, step: integer): boolean;
function SelectDirector(bnum: integer): boolean;
procedure SeekPath(x, y, step: integer);
procedure CalCanSelect(bnum, mode: integer);
procedure Attack(bnum: integer);
procedure AttackAction(bnum, mnum, level: integer);
procedure ShowMagicName(mnum: integer);
function SelectMagic(rnum: integer): integer;
procedure ShowMagicMenu(menustatus, menu, max: integer);
procedure SetAminationPosition(mode, step: integer);
procedure PlayMagicAmination(bnum, enum: integer);
procedure CalHurtRole(bnum, mnum, level: integer);
function CalHurtValue(bnum1, bnum2, mnum, level: integer): integer;
procedure ShowHurtValue(mode: integer);
procedure CalPoiHurtLife;
procedure ClearDeadRolePic;
procedure ShowSimpleStatus(rnum, x, y: integer);
procedure Wait(bnum: integer);
procedure RestoreRoleStatus;
procedure AddExp;
procedure CheckLevelUp;
procedure LevelUp(bnum: integer);
procedure CheckBook;
function CalRNum(team: integer): integer;
procedure BattleMenuItem(bnum: integer);
procedure UsePoision(bnum: integer);
procedure PlayActionAmination(bnum, mode: integer);
procedure Medcine(bnum: integer);
procedure MedPoision(bnum: integer);
procedure UseHiddenWeapen(bnum, inum: integer);
procedure Rest(bnum: integer);

procedure AutoBattle(bnum: integer);
procedure AutoUseItem(bnum, list: integer);

implementation

uses kys_event, kys_engine;

//Battle.
//战斗, 返回值为是否胜利

function Battle(battlenum, getexp: integer): boolean;
var
  i, SelectTeamList, x, y: integer;
begin
  Bstatus := 0;
  CurrentBattle := battlenum;
  if InitialBField then
  begin
    //如果未发现自动战斗设定, 则选择人物
    SelectTeamList := SelectTeamMembers;
    for i := 0 to 5 do
    begin
      y := warsta[21 + i];
      x := warsta[27 + i];
      if SelectTeamList and (1 shl i) > 0 then
      begin
        Brole[BRoleAmount].rnum := TeamList[i];
        Brole[BRoleAmount].Team := 0;
        Brole[BRoleAmount].Y := y;
        Brole[BRoleAmount].X := x;
        Brole[BRoleAmount].Face := 2;
        Brole[BRoleAmount].Dead := 0;
        Brole[BRoleAmount].Step := 0;
        Brole[BRoleAmount].Acted := 0;
        Brole[BRoleAmount].ExpGot := 0;
        Brole[BRoleAmount].Auto := 0;
        BRoleAmount := BRoleAmount + 1;
      end;
    end;
    for i := 0 to 5 do
    begin
      y := warsta[21 + i] + 1;
      x := warsta[27 + i];
      if (warsta[9 + i] > 0) and (instruct_16(warsta[9 + i], 1, 0) = 0) then
      begin
        Brole[BRoleAmount].rnum := warsta[9 + i];
        Brole[BRoleAmount].Team := 0;
        Brole[BRoleAmount].Y := y;
        Brole[BRoleAmount].X := x;
        Brole[BRoleAmount].Face := 2;
        Brole[BRoleAmount].Dead := 0;
        Brole[BRoleAmount].Step := 0;
        Brole[BRoleAmount].Acted := 0;
        Brole[BRoleAmount].ExpGot := 0;
        Brole[BRoleAmount].Auto := 0;
        BRoleAmount := BRoleAmount + 1;
      end;
    end;
  end;
  instruct_14;
  Where := 2;
  initialwholeBfield; //初始化场景
  stopMP3;
  playmp3(warsta[8], -1);
  BattleMainControl;

  RestoreRoleStatus;

  if (bstatus = 1) or ((bstatus = 2) and (getexp <> 0)) then
  begin
    AddExp;
    CheckLevelUp;
    CheckBook;
  end;

  sdl_updaterect(screen, 0, 0, screen.w, screen.h);

  if Rscence[CurScence].EntranceMusic >= 0 then
  begin
    stopmp3;
    playmp3(Rscence[CurScence].EntranceMusic, -1);
  end;

  Where := 1;
  if bstatus = 1 then result := true
  else result := false;

end;

//Structure of Bfield arrays:
//0: Ground; 1: Building; 2: Roles(Rrnum);

//Structure of Brole arrays:
//the 1st pointer is "Battle Num";
//The 2nd: 0: rnum, 1: Friend or enemy, 2: y, 3: x, 4: Face, 5: Dead or alive,
//         7: Acted, 8: Pic Num, 9: The number, 10, 11, 12: Auto, 13: Exp gotten.
//初始化战场

function InitialBField: boolean;
var
  sta, grp, idx, offset, i, i1, i2, x, y, fieldnum: integer;
begin
  sta := fileopen('resource\war.sta', fmopenread);
  offset := currentbattle * $BA;
  fileseek(sta, offset, 0);
  fileread(sta, warsta, $BA);
  fileclose(sta);
  fieldnum := warsta[6];
  if fieldnum = 0 then offset := 0
  else begin
    idx := fileopen('resource\warfld.idx', fmopenread);
    fileseek(idx, (fieldnum - 1) * 4, 0);
    fileread(idx, offset, 4);
    fileclose(idx);
  end;
  grp := fileopen('resource\warfld.grp', fmopenread);
  fileseek(grp, offset, 0);
  fileread(grp, Bfield[0, 0, 0], 2 * 64 * 64 * 2);
  fileclose(grp);
  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
      Bfield[2, i1, i2] := -1;
  BRoleAmount := 0;
  result := true;
  //我方自动参战数据
  for i := 0 to 5 do
  begin
    y := warsta[21 + i];
    x := warsta[27 + i];
    if warsta[15 + i] >= 0 then
    begin
      Brole[BRoleAmount].rnum := warsta[15 + i];
      Brole[BRoleAmount].Team := 0;
      Brole[BRoleAmount].Y := y;
      Brole[BRoleAmount].X := x;
      Brole[BRoleAmount].Face := 2;
      Brole[BRoleAmount].Dead := 0;
      Brole[BRoleAmount].Step := 0;
      Brole[BRoleAmount].Acted := 0;
      Brole[BRoleAmount].ExpGot := 0;
      Brole[BRoleAmount].Auto := 0;
      BRoleAmount := BRoleAmount + 1;
    end;
  end;
  //如没有自动参战人物, 返回假, 激活选择人物
  if BRoleAmount > 0 then result := False;
  for i := 0 to 19 do
  begin
    y := warsta[53 + i];
    x := warsta[73 + i];
    if warsta[33 + i] >= 0 then
    begin
      Brole[BRoleAmount].rnum := warsta[33 + i];
      Brole[BRoleAmount].Team := 1;
      Brole[BRoleAmount].Y := y;
      Brole[BRoleAmount].X := x;
      Brole[BRoleAmount].Face := 1;
      Brole[BRoleAmount].Dead := 0;
      Brole[BRoleAmount].Step := 0;
      Brole[BRoleAmount].Acted := 0;
      Brole[BRoleAmount].ExpGot := 0;
      Brole[BRoleAmount].Auto := 0;
      BRoleAmount := BRoleAmount + 1;
    end;
  end;

end;


//选择人物, 返回值为整型, 按bit表示人物是否参战

function SelectTeamMembers: integer;
var
  i, menu, max, menup: integer;
begin
  result := 0;
  max := 0;
  menu := 0;
  setlength(menustring, 7);
  for i := 0 to 5 do
  begin
    if Teamlist[i] >= 0 then
    begin
      menustring[i] := Big5toUnicode(@RRole[Teamlist[i]].Name);
      max := max + 1;
    end;
  end;
  menustring[max] := '    開始戰鬥';
  ShowMultiMenu(max, 0, 0);
  sdl_enablekeyrepeat(0, 0);
  while (SDL_WaitEvent(@event) >= 0) do
  begin
    case event.type_ of
      SDL_QUITEV:
        if messagedlg('Are you sure to quit?', mtConfirmation, [mbOk, mbCancel], 0) = idOK then Quit;
      SDL_KEYUP:
        begin
          if ((event.key.keysym.sym = sdlk_return) or (event.key.keysym.sym = sdlk_space)) and (menu <> max) then
          begin
            //选中人物则反转对应bit
            result := result xor (1 shl menu);
            ShowMultiMenu(max, menu, result);
          end;
          if ((event.key.keysym.sym = sdlk_return) or (event.key.keysym.sym = sdlk_space)) and (menu = max) then
          begin
            if result <> 0 then break;
          end;
          if (event.key.keysym.sym = sdlk_up) then
          begin
            menu := menu - 1;
            if menu < 0 then menu := max;
            ShowMultiMenu(max, menu, result);
          end;
          if (event.key.keysym.sym = sdlk_down) then
          begin
            menu := menu + 1;
            if menu > max then menu := 0;
            ShowMultiMenu(max, menu, result);
          end;
        end;
      SDL_MOUSEBUTTONUP:
        begin
          if (event.button.button = sdl_button_left) and (menu <> max) then
          begin
            result := result xor (1 shl menu);
            ShowMultiMenu(max, menu, result);
          end;
          if (event.button.button = sdl_button_left) and (menu = max) then
          begin
            if result <> 0 then break;
          end;
        end;
      SDL_MOUSEMOTION:
        begin
          if (event.button.x >= CENTER_X - 75) and (event.button.x < CENTER_X + 75) and (event.button.y >= 150) and (event.button.y < max * 22 + 178) then
          begin
            menup := menu;
            menu := (event.button.y - 152) div 22;
            if menup <> menu then ShowMultiMenu(max, menu, result);
          end;
        end;
    end;
  end;

end;

//显示选择参战人物选单

procedure ShowMultiMenu(max, menu, status: integer);
var
  i, x, y: integer;
  str, str1, str2: widestring;
begin
  x := CENTER_X - 105;
  y := 150;
  ReDraw;
  str := ' 選擇參與戰鬥之人物';
  str1 := ' 參戰';
  //Drawtextwithrect(@str[1],x,y-35,200,colcolor($23),colcolor($21));
  DrawRectangle(x + 30, y, 150, max * 22 + 28, 0, colcolor(255), 30);
  for i := 0 to max do
    if i = menu then
    begin
      drawshadowtext(@menustring[i][1], x + 13, y + 3 + 22 * i, colcolor($66), colcolor($64));
      if (status and (1 shl i)) > 0 then
        drawshadowtext(@str1[1], x + 113, y + 3 + 22 * i, colcolor($66), colcolor($64));
    end
    else begin
      drawshadowtext(@menustring[i][1], x + 13, y + 3 + 22 * i, colcolor($7), colcolor($5));
      if (status and (1 shl i)) > 0 then
        drawshadowtext(@str1[1], x + 113, y + 3 + 22 * i, colcolor($23), colcolor($21));
    end;
  sdl_updaterect(screen, x + 30, y, 151, max * 22 + 28 + 1);
end;


//战斗主控制

procedure BattleMainControl;
var
  i: integer;
begin
  //redraw;
  //战斗未分出胜负则继续
  while BStatus = 0 do
  begin
    CalMoveAbility; //计算移动能力
    ReArrangeBRole; //排列角色顺序

    ClearDeadRolePic; //清除阵亡角色

    //是否已行动, 显示数字清空
    for i := 0 to broleamount - 1 do
    begin
      Brole[i].Acted := 0;
      Brole[i].ShowNumber := 0;
    end;

    i := 0;
    while (i < broleamount) and (Bstatus = 0) do
    begin
      //当前人物位置作为屏幕中心
      Bx := Brole[i].X;
      By := Brole[i].Y;
      redraw;

      //战场序号保存至变量28005
      x50[28005] := i;
      //为我方且未阵亡, 非自动战斗, 则显示选单
      if (Brole[i].Dead = 0) then
      begin
        if (Brole[i].Team = 0) and (Brole[i].Auto = 0) then
        begin
          case BattleMenu(i) of
            0: Move(i);
            1: Attack(i);
            2: UsePoision(i);
            3: MedPoision(i);
            4: Medcine(i);
            5: BattleMenuItem(i);
            6: Wait(i);
            //状态改为仅能查看自己
            7:
              begin
                ShowStatus(Brole[i].rnum);
                waitanykey;
              end;
            8: Rest(i);
            9:
              begin
                Brole[i].Auto := 1;
                AutoBattle(i);
                Brole[i].Acted := 1;
              end;
          end;
        end
        else begin
          AutoBattle(i);
          Brole[i].Acted := 1;
        end;
      end
      else Brole[i].Acted := 1;

      ClearDeadRolePic;
      redraw;
      Bstatus := BattleStatus;

      if Brole[i].Acted = 1 then
        i := i + 1;
      //showmessage(inttostr(i));
    end;
    CalPoiHurtLife; //计算中毒损血

  end;

end;

//按轻功重排人物(未考虑装备)

procedure ReArrangeBRole;
var
  i, i1, i2, x: integer;
  temp: TBattleRole;
begin
  for i1 := 0 to BRoleAmount - 2 do
    for i2 := i1 + 1 to BRoleAmount - 1 do
    begin
      if Rrole[Brole[i1].rnum].Speed < Rrole[Brole[i2].rnum].Speed then
      begin
        temp := Brole[i1];
        Brole[i1] := Brole[i2];
        Brole[i2] := temp;
      end;
    end;

  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
      Bfield[2, i1, i2] := -1;

  for i := 0 to BRoleAmount - 1 do
  begin
    if Brole[i].Dead = 0 then
      Bfield[2, Brole[i].X, Brole[i].Y] := i
    else
      Bfield[2, Brole[i].X, Brole[i].Y] := -1;
  end;

end;

//计算可移动步数(考虑装备)

procedure CalMoveAbility;
var
  i, rnum, addspeed: integer;
begin
  for i := 0 to broleamount - 1 do
  begin
    rnum := Brole[i].rnum;
    addspeed := 0;
    if rrole[rnum].Equip[0] >= 0 then addspeed := addspeed + ritem[rrole[rnum].Equip[0]].AddSpeed;
    if rrole[rnum].Equip[1] >= 0 then addspeed := addspeed + ritem[rrole[rnum].Equip[1]].AddSpeed;
    Brole[i].Step := (Rrole[Brole[i].rnum].Speed + addspeed) div 15;
  end;

end;

//0: Continue; 1: Victory; 2:Failed.
//检查是否有一方全部阵亡

function BattleStatus: integer;
var
  i, sum0, sum1: integer;
begin
  sum0 := 0;
  sum1 := 0;
  for i := 0 to broleamount - 1 do
  begin
    if (Brole[i].Team = 0) and (Brole[i].Dead = 0) then
      sum0 := sum0 + 1;
    if (Brole[i].Team = 1) and (Brole[i].Dead = 0) then
      sum1 := sum1 + 1;
  end;

  if (sum0 > 0) and (sum1 > 0) then result := 0;
  if (sum0 >= 0) and (sum1 = 0) then result := 1;
  if (sum0 = 0) and (sum1 > 0) then result := 2;

end;

//战斗主选单, menustatus按bit保存可用项

function BattleMenu(bnum: integer): integer;
var
  i, p, menustatus, menu, max, rnum, menup: integer;
  realmenu: array[0..9] of integer;
begin
  menustatus := $3E0;
  max := 4;
  //for i:=0 to 9 do
  rnum := brole[bnum].rnum;
  //移动是否可用
  if brole[bnum].Step > 0 then
  begin
    menustatus := menustatus or 1;
    max := max + 1;
  end;

  //can not attack when phisical<10
  //攻击是否可用
  if rrole[rnum].PhyPower >= 10 then
  begin
    p := 0;
    for i := 0 to 9 do
    begin
      if rrole[rnum].Magic[i] > 0 then
      begin
        p := 1;
        break;
      end;
    end;
    if p > 0 then
    begin
      menustatus := menustatus or 2;
      max := max + 1;
    end;
  end;
  //用毒是否可用
  if (Rrole[rnum].UsePoi > 0) and (rrole[rnum].PhyPower >= 30) then
  begin
    menustatus := menustatus or 4;
    max := max + 1;
  end;
  //解毒是否可用
  if (Rrole[rnum].MedPoi > 0) and (rrole[rnum].PhyPower >= 50) then
  begin
    menustatus := menustatus or 8;
    max := max + 1;
  end;
  //医疗是否可用
  if (Rrole[rnum].Medcine > 0) and (rrole[rnum].PhyPower >= 50) then
  begin
    menustatus := menustatus or 16;
    max := max + 1;
  end;

  ReDraw;
  ShowSimpleStatus(brole[bnum].rnum, 350, 50);
  sdl_updaterect(screen, 0, 0, screen.w, screen.h);
  menu := 0;
  showbmenu(menustatus, menu, max);
  //sdl_updaterect(screen,0,0,screen.w,screen.h);
  while (SDL_WaitEvent(@event) >= 0) do
  begin
    case event.type_ of
      SDL_QUITEV:
        if messagedlg('Are you sure to quit?', mtConfirmation, [mbOk, mbCancel], 0) = idOK then Quit;
      SDL_KEYUP:
        begin
          if (event.key.keysym.sym = sdlk_return) or (event.key.keysym.sym = sdlk_space) then
          begin
            break;
          end;
          if (event.key.keysym.sym = sdlk_up) then
          begin
            menu := menu - 1;
            if menu < 0 then menu := max;
            showbmenu(menustatus, menu, max);
          end;
          if (event.key.keysym.sym = sdlk_down) then
          begin
            menu := menu + 1;
            if menu > max then menu := 0;
            showbmenu(menustatus, menu, max);
          end;
          if (event.key.keysym.sym = sdlk_return) and (event.key.keysym.modifier = kmod_lalt) then
          begin
            if fullscreen = 1 then
              screen := SDL_SetVideoMode(CENTER_X * 2, CENTER_Y * 2, 32, SDL_HWSURFACE or SDL_DOUBLEBUF or SDL_ANYFORMAT)
            else
              screen := SDL_SetVideoMode(CENTER_X * 2, CENTER_Y * 2, 32, SDL_FULLSCREEN);
            fullscreen := 1 - fullscreen;
          end;
        end;
      SDL_MOUSEBUTTONUP:
        begin
          if (event.button.button = sdl_button_left) then
            break;
        end;
      SDL_MOUSEMOTION:
        begin
          if (event.button.x >= 100) and (event.button.x < 147) and (event.button.y >= 50) and (event.button.y < max * 22 + 78) then
          begin
            menup := menu;
            menu := (event.button.y - 52) div 22;
            if menu > max then menu := max;
            if menu < 0 then menu := 0;
            if menup <> menu then showbmenu(menustatus, menu, max);
          end;
        end;
    end;
  end;
  //result:=0;
  p := 0;
  for i := 0 to 9 do
  begin
    if (menustatus and (1 shl i)) > 0 then
    begin
      p := p + 1;
      if p > menu then break;
    end;
  end;
  result := i;

end;

//显示战斗主选单

procedure ShowBMenu(MenuStatus, menu, max: integer);
var
  i, p: integer;
  word: array[0..9] of widestring;
begin
  word[0] := ' 移動';
  word[1] := ' 攻擊';
  word[2] := ' 用毒';
  word[3] := ' 解毒';
  word[4] := ' 醫療';
  word[5] := ' 物品';
  word[6] := ' 等待';
  word[7] := ' 狀態';
  word[8] := ' 休息';
  word[9] := ' 自動';
  Redraw;
  DrawRectangle(100, 50, 47, max * 22 + 28, 0, colcolor(255), 30);
  p := 0;
  for i := 0 to 9 do
  begin
    if (p = menu) and ((menustatus and (1 shl i) > 0)) then
    begin
      drawshadowtext(@word[i][1], 83, 53 + 22 * p, colcolor($66), colcolor($64));
      p := p + 1;
    end
    else if (p <> menu) and ((menustatus and (1 shl i) > 0)) then
    begin
      drawshadowtext(@word[i][1], 83, 53 + 22 * p, colcolor($23), colcolor($21));
      p := p + 1;
    end;
  end;
  sdl_updaterect(screen, 100, 50, 48, max * 22 + 29);
end;

//移动

procedure Move(bnum: integer);
var
  s, i: integer;
begin
  CalCanSelect(bnum, 0);
  if SelectAim(bnum, brole[bnum].Step) then
    MoveAmination(bnum);

end;

//移动动画

procedure MoveAmination(bnum: integer);
var
  s, i: integer;
begin
  //CalCanSelect(bnum, 0);
  //if SelectAim(bnum,Brole[bnum,6]) then
  brole[bnum].Step := brole[bnum].Step - abs(Ax - Bx) - abs(Ay - By);
  s := sign(Ax - Bx);
  if s < 0 then Brole[bnum].Face := 0;
  if s > 0 then Brole[bnum].Face := 3;
  i := Bx + s;
  if s <> 0 then
    while s * (Ax - i) >= 0 do
    begin
      sdl_delay(20);
      if Bfield[2, Bx, By] = bnum then Bfield[2, Bx, By] := -1;
      Bx := i;
      if Bfield[2, Bx, By] = -1 then Bfield[2, Bx, By] := bnum;
      Redraw;
      SDL_updaterect(screen, 0, 0, screen.w, screen.h);
      i := i + s;
    end;
  s := sign(Ay - By);
  if s < 0 then Brole[bnum].Face := 2;
  if s > 0 then Brole[bnum].Face := 1;
  i := By + s;
  if s <> 0 then
    while s * (Ay - i) >= 0 do
    begin
      sdl_delay(20);
      if Bfield[2, Bx, By] = bnum then Bfield[2, Bx, By] := -1;
      By := i;
      if Bfield[2, Bx, By] = -1 then Bfield[2, Bx, By] := bnum;
      Redraw;
      SDL_updaterect(screen, 0, 0, screen.w, screen.h);
      i := i + s;
    end;
  Brole[bnum].X := Bx;
  Brole[bnum].Y := By;
  Bfield[2, Bx, By] := bnum;

end;

//选择目标

function SelectAim(bnum, step: integer): boolean;
var
  Axp, Ayp: integer;
begin
  Ax := Bx;
  Ay := By;
  DrawBFieldWithCursor(step);
  sdl_updaterect(screen, 0, 0, screen.w, screen.h);
  while (SDL_WaitEvent(@event) >= 0) do
  begin
    case event.type_ of
      SDL_QUITEV:
        if messagedlg('Are you sure to quit?', mtConfirmation, [mbOk, mbCancel], 0) = idOK then Quit;
      SDL_KEYUP:
        begin
          if (event.key.keysym.sym = sdlk_return) or (event.key.keysym.sym = sdlk_space) then
          begin
            result := true;
            x50[28927] := 1;
            break;
          end;
          if (event.key.keysym.sym = sdlk_escape) then
          begin
            result := false;
            x50[28927] := 0;
            break;
          end;
          if (event.key.keysym.sym = sdlk_left) then
          begin
            Ay := Ay - 1;
            if (abs(Ax - Bx) + abs(Ay - By) > step) or (Bfield[3, Ax, Ay] <> 0) then Ay := Ay + 1;
            DrawBFieldWithCursor(step);
            sdl_updaterect(screen, 0, 0, screen.w, screen.h);
          end;
          if (event.key.keysym.sym = sdlk_right) then
          begin
            Ay := Ay + 1;
            if (abs(Ax - Bx) + abs(Ay - By) > step) or (Bfield[3, Ax, Ay] <> 0) then Ay := Ay - 1;
            DrawBFieldWithCursor(step);
            sdl_updaterect(screen, 0, 0, screen.w, screen.h);
          end;
          if (event.key.keysym.sym = sdlk_down) then
          begin
            Ax := Ax + 1;
            if (abs(Ax - Bx) + abs(Ay - By) > step) or (Bfield[3, Ax, Ay] <> 0) then Ax := Ax - 1;
            DrawBFieldWithCursor(step);
            sdl_updaterect(screen, 0, 0, screen.w, screen.h);
          end;
          if (event.key.keysym.sym = sdlk_up) then
          begin
            Ax := Ax - 1;
            if (abs(Ax - Bx) + abs(Ay - By) > step) or (Bfield[3, Ax, Ay] <> 0) then Ax := Ax + 1;
            DrawBFieldWithCursor(step);
            sdl_updaterect(screen, 0, 0, screen.w, screen.h);
          end;
        end;
      SDL_MOUSEBUTTONUP:
        begin
          if (event.button.button = sdl_button_left) then
          begin
            result := true;
            break;
          end;
          if (event.button.button = sdl_button_right) then
          begin
            result := false;
            break;
          end;
        end;
      SDL_MOUSEMOTION:
        begin
          Axp := (-event.button.x + CENTER_x + 2 * event.button.y - 2 * CENTER_y + 18) div 36 + Bx;
          Ayp := (event.button.x - CENTER_x + 2 * event.button.y - 2 * CENTER_y + 18) div 36 + By;
          if (abs(Axp - Bx) + abs(Ayp - By) <= step) and (Bfield[3, Axp, Ayp] = 0) then
          begin
            Ax := Axp;
            Ay := Ayp;
            DrawBFieldWithCursor(step);
            sdl_updaterect(screen, 0, 0, screen.w, screen.h);
          end;
        end;
    end;
  end;

end;


//选择方向

function SelectDirector(bnum: integer): boolean;
var
  str: widestring;
begin
  Ax := Bx;
  Ay := By;
  str := ' 選擇攻擊方向';
  Drawtextwithrect(@str[1], 280, 200, 125, colcolor($23), colcolor($21));
  sdl_updaterect(screen, 0, 0, screen.w, screen.h);
  result := false;
  while (SDL_WaitEvent(@event) >= 0) do
  begin
    case event.type_ of
      SDL_QUITEV:
        if messagedlg('Are you sure to quit?', mtConfirmation, [mbOk, mbCancel], 0) = idOK then Quit;
      SDL_KEYUP:
        begin
          if (event.key.keysym.sym = sdlk_escape) then
          begin
            break;
          end;
          if (event.key.keysym.sym = sdlk_left) then
          begin
            Ay := Ay - 1;
            break;
          end;
          if (event.key.keysym.sym = sdlk_right) then
          begin
            Ay := Ay + 1;
            break;
          end;
          if (event.key.keysym.sym = sdlk_down) then
          begin
            Ax := Ax + 1;
            break;
          end;
          if (event.key.keysym.sym = sdlk_up) then
          begin
            Ax := Ax - 1;
            break;
          end;
        end;
      Sdl_mousebuttonup:
        begin
          if event.button.button = sdl_button_right then break;
          //按照所点击位置设置方向
          if event.button.button = sdl_button_left then
          begin
            if (event.button.x < CENTER_x) and (event.button.y < CENTER_y) then Ay := Ay - 1;
            if (event.button.x < CENTER_x) and (event.button.y >= CENTER_y) then Ax := Ax + 1;
            if (event.button.x >= CENTER_x) and (event.button.y < CENTER_y) then Ax := Ax - 1;
            if (event.button.x >= CENTER_x) and (event.button.y >= CENTER_y) then Ay := Ay + 1;
            break;
          end;
        end;
    end;
  end;
  if (Ax <> Bx) or (Ay <> By) then result := true;

end;


//计算可以被选中的位置
//利用递归确定

procedure SeekPath(x, y, step: integer);
begin
  if step > 0 then
  begin
    step := step - 1;
    if Bfield[3, x, y] in [0..step] then
    begin
      Bfield[3, x, y] := step;
      if Bfield[3, x + 1, y] in [0..step] then
      begin
        SeekPath(x + 1, y, step);
      end;
      if Bfield[3, x, y + 1] in [0..step] then
      begin
        SeekPath(x, y + 1, step);
      end;
      if Bfield[3, x - 1, y] in [0..step] then
      begin
        SeekPath(x - 1, y, step);
      end;
      if Bfield[3, x, y - 1] in [0..step] then
      begin
        SeekPath(x, y - 1, step);
      end;
    end;
  end;

end;

procedure CalCanSelect(bnum, mode: integer);
var
  i, i1, i2: integer;
begin
  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
    begin
      Bfield[3, i1, i2] := 0;
      //mode为0表示移动, 这时建筑和有人物(不包括自己)的位置不可选
      if mode = 0 then
      begin
        if Bfield[1, i1, i2] > 0 then Bfield[3, i1, i2] := -1;
        if Bfield[2, i1, i2] >= 0 then Bfield[3, i1, i2] := -1;
        if Bfield[2, i1, i2] = bnum then Bfield[3, i1, i2] := 0;
      end;
    end;
  if mode = 0 then
  begin
    SeekPath(Brole[bnum].X, Brole[bnum].Y, Brole[bnum].Step + 2);
    //递归算法的问题, 步数+2参与计算
    for i1 := 0 to 63 do
      for i2 := 0 to 63 do
      begin
        if Bfield[3, i1, i2] > 0 then
          Bfield[3, i1, i2] := 0
        else
          Bfield[3, i1, i2] := 1;
      end;
  end;
end;

//攻击

procedure Attack(bnum: integer);
var
  rnum, i, mnum, level, step, i1: integer;
begin
  rnum := brole[bnum].rnum;
  i := SelectMagic(rnum);
  mnum := Rrole[rnum].Magic[i];
  level := Rrole[rnum].MagLevel[i] div 100 + 1;

  if i >= 0 then
    //依据攻击范围进一步选择
    case Rmagic[mnum].AttAreaType of
      0, 3:
        begin
          CalCanSelect(bnum, 1);
          step := Rmagic[mnum].MoveDistance[level - 1];
          if SelectAim(bnum, step) then
          begin
            SetAminationPosition(Rmagic[mnum].AttAreaType, Rmagic[mnum].AttDistance[level - 1]);
            Brole[bnum].Acted := 1;
          end;
        end;
      1:
        begin
          if SelectDirector(bnum) then
          begin
            SetAminationPosition(Rmagic[mnum].AttAreaType, Rmagic[mnum].MoveDistance[level - 1]);
            Brole[bnum].Acted := 1;
          end;
        end;
      2:
        begin
          SetAminationPosition(Rmagic[mnum].AttAreaType, Rmagic[mnum].MoveDistance[level - 1]);
          Brole[bnum].Acted := 1;
        end;
    end;
  //如果行动成功, 武功等级增加, 播放效果
  if Brole[bnum].Acted = 1 then
  begin
    for i1 := 0 to sign(Rrole[rnum].AttTwice) do
    begin
      Rrole[rnum].MagLevel[i] := Rrole[rnum].MagLevel[i] + random(2) + 1;
      if Rrole[rnum].MagLevel[i] > 999 then Rrole[rnum].MagLevel[i] := 999;
      if rmagic[mnum].UnKnow[4] > 0 then callevent(rmagic[mnum].UnKnow[4])
      else AttackAction(bnum, mnum, level);
    end;
  end;

end;

//攻击效果

procedure AttackAction(bnum, mnum, level: integer);
begin
  ShowMagicName(mnum);
  PlayActionAmination(bnum, Rmagic[mnum].MagicType); //动画效果
  PlayMagicAmination(bnum, Rmagic[mnum].AmiNum); //武功效果
  CalHurtRole(bnum, mnum, level); //计算被打到的人物
  ShowHurtValue(rmagic[mnum].HurtType); //显示数字

end;

procedure ShowMagicName(mnum: integer);
var
  l: integer;
  str: widestring;
begin
  Redraw;
  str := big5tounicode(@Rmagic[mnum].Name);
  str := MidStr(str, 1, 6);
  l := length(str);
  drawtextwithrect(@str[1], CENTER_X - l * 10, CENTER_Y - 150, l * 20 - 14, colcolor($14), colcolor($16));
  sdl_updaterect(screen, 0, 0, screen.w, screen.h);
  Sdl_Delay(500);

end;

//选择武功

function SelectMagic(rnum: integer): integer;
var
  i, p, menustatus, max, menu, menup: integer;
begin
  menustatus := 0;
  max := 0;
  setlength(menustring, 10);
  setlength(menuengstring, 10);
  for i := 0 to 9 do
  begin
    if Rrole[rnum].Magic[i] > 0 then
    begin
      menustatus := menustatus or (1 shl i);
      menustring[i] := Big5toUnicode(@Rmagic[Rrole[rnum].Magic[i]].Name);
      menuengstring[i] := format('%3d', [Rrole[rnum].MagLevel[i] div 100 + 1]);
      max := max + 1;
    end;
  end;
  max := max - 1;

  ReDraw;
  sdl_updaterect(screen, 0, 0, screen.w, screen.h);
  menu := 0;
  showmagicmenu(menustatus, menu, max);
  //sdl_updaterect(screen,0,0,screen.w,screen.h);
  while (SDL_WaitEvent(@event) >= 0) do
  begin
    case event.type_ of
      SDL_QUITEV:
        if messagedlg('Are you sure to quit?', mtConfirmation, [mbOk, mbCancel], 0) = idOK then Quit;
      SDL_KEYUP:
        begin
          if (event.key.keysym.sym = sdlk_return) or (event.key.keysym.sym = sdlk_space) then
          begin
            break;
          end;
          if (event.key.keysym.sym = sdlk_escape) then
          begin
            result := -1;
            break;
          end;
          if (event.key.keysym.sym = sdlk_up) then
          begin
            menu := menu - 1;
            if menu < 0 then menu := max;
            showmagicmenu(menustatus, menu, max);
          end;
          if (event.key.keysym.sym = sdlk_down) then
          begin
            menu := menu + 1;
            if menu > max then menu := 0;
            showmagicmenu(menustatus, menu, max);
          end;
        end;
      SDL_MOUSEBUTTONUP:
        begin
          if (event.button.button = sdl_button_left) then
          begin
            break;
          end;
          if (event.button.button = sdl_button_right) then
          begin
            result := -1;
            break;
          end;
        end;
      SDL_MOUSEMOTION:
        begin
          if (event.button.x >= 100) and (event.button.x < 267) and (event.button.y >= 50) and (event.button.y < max * 22 + 78) then
          begin
            menup := menu;
            menu := (event.button.y - 52) div 22;
            if menu > max then menu := max;
            if menu < 0 then menu := 0;
            if menup <> menu then showmagicmenu(menustatus, menu, max);
          end;
        end;
    end;
  end;
  //result:=0;
  if result >= 0 then
  begin
    p := 0;
    for i := 0 to 9 do
    begin
      if (menustatus and (1 shl i)) > 0 then
      begin
        p := p + 1;
        if p > menu then break;
      end;
    end;
    result := i;
  end;

end;

//显示武功选单

procedure ShowMagicMenu(menustatus, menu, max: integer);
var
  i, p: integer;
begin
  redraw;
  DrawRectangle(100, 50, 167, max * 22 + 28, 0, colcolor(255), 30);
  p := 0;
  for i := 0 to 9 do
  begin
    if (p = menu) and ((menustatus and (1 shl i) > 0)) then
    begin
      drawshadowtext(@menustring[i][1], 83, 53 + 22 * p, colcolor($66), colcolor($64));
      drawengshadowtext(@menuengstring[i][1], 223, 53 + 22 * p, colcolor($66), colcolor($64));
      p := p + 1;
    end
    else if (p <> menu) and ((menustatus and (1 shl i) > 0)) then
    begin
      drawshadowtext(@menustring[i][1], 83, 53 + 22 * p, colcolor($23), colcolor($21));
      drawengshadowtext(@menuengstring[i][1], 223, 53 + 22 * p, colcolor($23), colcolor($21));
      p := p + 1;
    end;
  end;
  sdl_updaterect(screen, 0, 0, screen.w, screen.h);

end;

//设定攻击范围

procedure SetAminationPosition(mode, step: integer);
var
  i, i1, i2: integer;
begin
  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
    begin
      Bfield[4, i1, i2] := 0;
      //按攻击类型判断是否在范围内
      case mode of
        0:
          begin
            if (i1 = Ax) and (i2 = Ay) then Bfield[4, i1, i2] := 1;
          end;
        3:
          begin
            if (abs(i1 - Ax) <= step) and (abs(i2 - Ay) <= step) then Bfield[4, i1, i2] := 1;
          end;
        1:
          begin
            if ((i1 = Bx) or (i2 = By)) and (sign(Ax - Bx) = sign(i1 - Bx)) and (abs(i1 - Bx) <= step) and (sign(Ay - By) = sign(i2 - By)) and (abs(i2 - By) <= step) then
              Bfield[4, i1, i2] := 1;
          end;
        2:
          begin
            if ((i1 = Bx) and (abs(i2 - By) <= step)) or ((i2 = By) and (abs(i1 - Bx) <= step)) then
              Bfield[4, i1, i2] := 1;
            if ((i1 = Bx) and (i2 = By)) then Bfield[4, i1, i2] := 0;
          end;
      end;
    end;

end;

//显示武功效果

procedure PlayMagicAmination(bnum, enum: integer);
var
  beginpic, i, endpic: integer;
begin
  beginpic := 0;
  //含音效
  playsound(enum, 0);
  for i := 0 to enum - 1 do
    beginpic := beginpic + effectlist[i];
  endpic := beginpic + effectlist[enum] - 1;

  for i := beginpic to endpic do
  begin
    DrawBFieldWithEft(i);
    sdl_updaterect(screen, 0, 0, screen.w, screen.h);
    sdl_delay(20);
  end;

end;

//判断是否有非行动方角色在攻击范围之内

procedure CalHurtRole(bnum, mnum, level: integer);
var
  i, rnum, hurt, addpoi, mp: integer;
begin
  rnum := brole[bnum].rnum;
  rrole[rnum].PhyPower := rrole[rnum].PhyPower - 3;
  if RRole[rnum].CurrentMP < rmagic[mnum].NeedMP * ((level + 1) div 2) then level := RRole[rnum].CurrentMP div rmagic[mnum].NeedMP * 2;
  if level > 10 then level := 10;
  RRole[rnum].CurrentMP := RRole[rnum].CurrentMP - rmagic[mnum].NeedMP * ((level + 1) div 2);
  for i := 0 to broleamount - 1 do
  begin
    Brole[i].ShowNumber := -1;
    if (Bfield[4, Brole[i].X, Brole[i].Y] <> 0) and (Brole[bnum].Team <> Brole[i].Team) and (Brole[i].Dead = 0) then
    begin
      //生命伤害
      if (rmagic[mnum].HurtType = 0) then
      begin
        hurt := CalHurtValue(bnum, i, mnum, level);
        Brole[i].ShowNumber := hurt;
        //受伤
        Rrole[Brole[i].rnum].CurrentHP := Rrole[Brole[i].rnum].CurrentHP - hurt;
        Rrole[Brole[i].rnum].Hurt := Rrole[Brole[i].rnum].Hurt + hurt div LIFE_HURT;
        if Rrole[Brole[i].rnum].Hurt > 99 then Rrole[Brole[i].rnum].Hurt := 99;
        Brole[bnum].ExpGot := Brole[bnum].ExpGot + hurt div 2;
        if Rrole[Brole[i].rnum].CurrentHP <= 0 then Brole[bnum].ExpGot := Brole[bnum].ExpGot + hurt div 2;
      end;
      //内力伤害
      if (rmagic[mnum].HurtType = 1) then
      begin
        hurt := rmagic[mnum].HurtMP[level - 1] + random(5) - random(5);
        Brole[i].ShowNumber := hurt;
        Rrole[Brole[i].rnum].CurrentMP := Rrole[Brole[i].rnum].CurrentMP - hurt;
        if Rrole[Brole[i].rnum].CurrentMP <= 0 then Rrole[Brole[i].rnum].CurrentMP := 0;
        //增加己方内力及最大值
        RRole[rnum].CurrentMP := RRole[rnum].CurrentMP + hurt;
        RRole[rnum].MaxMP := RRole[rnum].MaxMP + random(hurt div 2);
        if RRole[rnum].MaxMP > MAX_MP then RRole[rnum].MaxMP := MAX_MP;
        if RRole[rnum].CurrentMP > RRole[rnum].MaxMP then RRole[rnum].CurrentMP := RRole[rnum].MaxMP;
      end;
      //中毒
      addpoi := rrole[rnum].AttPoi div 5 + rmagic[mnum].Poision * level div 2 - rrole[Brole[i].rnum].DefPoi;
      if addpoi + rrole[Brole[i].rnum].Poision > 99 then addpoi := 99 - rrole[Brole[i].rnum].Poision;
      if addpoi < 0 then addpoi := 0;
      if rrole[Brole[i].rnum].DefPoi >= 99 then addpoi := 0;
      rrole[Brole[i].rnum].Poision := rrole[Brole[i].rnum].Poision + addpoi;
    end;
  end;

end;

//计算伤害值, 第一公式如小于0则取一个随机数, 无第二公式

function CalHurtValue(bnum1, bnum2, mnum, level: integer): integer;
var
  i, rnum1, rnum2, mhurt, att, def, k1, k2, dis: integer;
begin
  //计算双方武学常识
  k1 := 0;
  k2 := 0;
  for i := 0 to broleamount - 1 do
  begin
    if (Brole[i].Team = brole[bnum1].Team) and (Brole[i].Dead = 0) and (rrole[Brole[i].rnum].Knowledge > MIN_KNOWLEDGE) then k1 := k1 + rrole[Brole[i].rnum].Knowledge;
    if (Brole[i].Team = brole[bnum2].Team) and (Brole[i].Dead = 0) and (rrole[Brole[i].rnum].Knowledge > MIN_KNOWLEDGE) then k2 := k2 + rrole[Brole[i].rnum].Knowledge;
  end;
  rnum1 := Brole[bnum1].rnum;
  rnum2 := Brole[bnum2].rnum;
  mhurt := Rmagic[mnum].Attack[level - 1];

  att := Rrole[rnum1].Attack + k1 * 3 div 2 + mhurt div 3;
  def := Rrole[rnum2].Defence * 2 + k2 * 3;
  //攻击, 防御按伤害的折扣
  att := att * (100 - Rrole[rnum1].Hurt div 2) div 100;
  def := def * (100 - Rrole[rnum2].Hurt div 2) div 100;

  //如果有武器, 增加攻击, 检查配合列表
  if rrole[rnum1].Equip[0] >= 0 then
  begin
    att := att + ritem[rrole[rnum1].Equip[0]].AddAttack;
    for i := 0 to MAX_WEAPON_MATCH - 1 do
    begin
      if (rrole[rnum1].Equip[0] = matchlist[i, 0]) and (mnum = matchlist[i, 1]) then
      begin
        att := att + matchlist[i, 2] * 2 div 3;
        break;
      end;
    end;
  end;
  //防具增加攻击
  if rrole[rnum1].Equip[1] >= 0 then att := att + ritem[rrole[rnum1].Equip[1]].AddAttack;
  //武器, 防具增加防御
  if rrole[rnum2].Equip[0] >= 0 then def := def + ritem[rrole[rnum2].Equip[0]].AddDefence;
  if rrole[rnum2].Equip[1] >= 0 then def := def + ritem[rrole[rnum2].Equip[1]].AddDefence;
  //showmessage(inttostr(att)+' '+inttostr(def));
  result := att - def + random(20) - random(20);
  dis := abs(brole[bnum1].X - brole[bnum2].X) + abs(brole[bnum1].Y - brole[bnum2].Y);
  if dis > 10 then dis := 10;
  result := result * (100 - (dis - 1) * 3) div 100;
  if (result <= 0) or (level <= 0) then result := random(10) + 1;
  if (result > 9999) then result := 9999;
  //showmessage(inttostr(result));

end;

//0: red. 1: purple, 2: green
//显示数字

procedure ShowHurtValue(mode: integer);
var
  i, i1, x, y: integer;
  color1, color2: uint32;
  word: array of widestring;
  str: string;
begin
  case mode of
    0:
      begin
        color1 := colcolor($10);
        color2 := colcolor($14);
        str := '-%d';
      end;
    1:
      begin
        color1 := colcolor($50);
        color2 := colcolor($53);
        str := '-%d';
      end;
    2:
      begin
        color1 := colcolor($30);
        color2 := colcolor($32);
        str := '+%d';
      end;
    3:
      begin
        color1 := colcolor($7);
        color2 := colcolor($5);
        str := '+%d';
      end;
    4:
      begin
        color1 := colcolor($91);
        color2 := colcolor($93);
        str := '-%d';
      end;
  end;
  setlength(word, broleamount);
  for i := 0 to broleamount - 1 do
  begin
    if Brole[i].ShowNumber > 0 then
    begin
      //x := -(Brole[i].X - Bx) * 18 + (Brole[i].Y - By) * 18 + CENTER_X - 10;
      //y := (Brole[i].X - Bx) * 9 + (Brole[i].Y - By) * 9 + CENTER_Y - 40;
      word[i] := format(str, [Brole[i].ShowNumber]);
    end;
    Brole[i].ShowNumber := -1;
  end;
  for i1 := 0 to 10 do
  begin
    redraw;
    for i := 0 to broleamount - 1 do
    begin
      x := -(Brole[i].X - Bx) * 18 + (Brole[i].Y - By) * 18 + CENTER_X - 10;
      y := (Brole[i].X - Bx) * 9 + (Brole[i].Y - By) * 9 + CENTER_Y - 40;
      drawengshadowtext(@word[i, 1], x, y - i1 * 2, color1, color2);
      sdl_delay(5);
    end;
    sdl_updaterect(screen, 0, 0, screen.w, screen.h);
  end;
  redraw;

end;

//计算中毒减少的生命

procedure CalPoiHurtLife;
var
  i: integer;
  p: boolean;
begin
  p := false;
  for i := 0 to broleamount - 1 do
  begin
    Brole[i].ShowNumber := -1;
    if (Rrole[Brole[i].rnum].Poision > 0) and (Brole[i].Dead = 0) then
    begin
      Rrole[Brole[i].rnum].CurrentHP := Rrole[Brole[i].rnum].CurrentHP - Rrole[Brole[i].rnum].Poision div 10 - 1;
      if Rrole[Brole[i].rnum].CurrentHP <= 0 then Rrole[Brole[i].rnum].CurrentHP := 1;
      //Brole[i].ShowNumber := Rrole[Brole[i].rnum, 20] div 2+1;
      //p := true;
    end;
  end;
  //if p then showhurtvalue(0);

end;

//设置生命低于0的人物为已阵亡, 主要是清除所占的位置

procedure ClearDeadRolePic;
var
  i: integer;
begin
  for i := 0 to broleamount - 1 do
  begin
    if Rrole[Brole[i].rnum].CurrentHP <= 0 then
    begin
      Brole[i].Dead := 1;
      bfield[2, Brole[i].X, Brole[i].Y] := -1;
      //bmount
    end;
  end;
  for i := 0 to broleamount - 1 do
    if Brole[i].Dead = 0 then bfield[2, Brole[i].X, Brole[i].Y] := i;

end;

//显示简单状态(x, y表示位置)

procedure ShowSimpleStatus(rnum, x, y: integer);
var
  i, magicnum: integer;
  p: array[0..10] of integer;
  str: widestring;
  strs: array[0..3] of widestring;
  color1, color2: uint32;
begin
  strs[0] := ' 等級';
  strs[1] := ' 生命';
  strs[2] := ' 內力';
  strs[3] := ' 體力';

  DrawRectangle(x, y, 145, 173, 0, colcolor(255), 30);
  drawheadpic(Rrole[rnum].HeadNum, x + 50, y + 62);
  str := big5tounicode(@rrole[rnum].Name);
  drawshadowtext(@str[1], x + 60 - length(pchar(@rrole[rnum].Name)) * 5, y + 65, colcolor($66), colcolor($63));
  for i := 0 to 3 do
    drawshadowtext(@strs[i, 1], x - 17, y + 86 + 21 * i, colcolor($23), colcolor($21));

  str := format('%9d', [Rrole[rnum].Level]);
  drawengshadowtext(@str[1], x + 50, y + 86, colcolor($7), colcolor($5));

  case RRole[rnum].Hurt of
    34..66:
      begin
        color1 := colcolor($E);
        color2 := colcolor($10);
      end;
    67..1000:
      begin
        color1 := colcolor($14);
        color2 := colcolor($16);
      end;
  else
    begin
      color1 := colcolor($7);
      color2 := colcolor($5);
    end;
  end;
  str := format('%4d', [RRole[rnum].CurrentHP]);
  drawengshadowtext(@str[1], x + 50, y + 107, color1, color2);

  str := '/';
  drawengshadowtext(@str[1], x + 90, y + 107, colcolor($66), colcolor($63));

  case RRole[rnum].Poision of
    34..66:
      begin
        color1 := colcolor($30);
        color2 := colcolor($32);
      end;
    67..1000:
      begin
        color1 := colcolor($35);
        color2 := colcolor($37);
      end;
  else
    begin
      color1 := colcolor($23);
      color2 := colcolor($21);
    end;
  end;
  str := format('%4d', [RRole[rnum].MaxHP]);
  drawengshadowtext(@str[1], x + 100, y + 107, color1, color2);

  //str:=format('%4d/%4d', [Rrole[rnum,17],Rrole[rnum,18]]);
  //drawengshadowtext(@str[1],x+50,y+107,colcolor($7),colcolor($5));
  if rrole[rnum].MPType = 0 then
  begin
    color1 := colcolor($50);
    color2 := colcolor($4E);
  end else
    if rrole[rnum].MPType = 1 then
    begin
      color1 := colcolor($7);
      color2 := colcolor($5);
    end else
    begin
      color1 := colcolor($66);
      color2 := colcolor($63);
    end;
  str := format('%4d/%4d', [RRole[rnum].CurrentMP, RRole[rnum].MaxMP]);
  drawengshadowtext(@str[1], x + 50, y + 128, color1, color2);
  str := format('%9d', [rrole[rnum].PhyPower]);
  drawengshadowtext(@str[1], x + 50, y + 149, colcolor($7), colcolor($5));

  SDL_UpdateRect(screen, 0, 0, screen.w, screen.h);

end;

//等待, 似乎不太完善

procedure Wait(bnum: integer);
var
  i, i1, i2, x: integer;
begin

  Brole[BroleAmount] := Brole[bnum];

  for i := bnum to BRoleAmount - 1 do
    Brole[i] := Brole[i + 1];

  for i := 0 to BRoleAmount - 1 do
  begin
    if Brole[i].Dead = 0 then
      Bfield[2, Brole[i].X, Brole[i].Y] := i
    else
      Bfield[2, Brole[i].X, Brole[i].Y] := -1;
  end;

end;

//战斗结束恢复人物状态

procedure RestoreRoleStatus;
var
  i, rnum: integer;
begin
  for i := 0 to BRoleAmount - 1 do
  begin
    rnum := Brole[i].rnum;
    //我方恢复部分生命, 内力; 敌方恢复全部
    if Brole[i].Team = 0 then
    begin
      RRole[rnum].CurrentHP := RRole[rnum].CurrentHP + RRole[rnum].MaxHP div 2;
      if RRole[rnum].CurrentHP <= 0 then RRole[rnum].CurrentHP := 1;
      if RRole[rnum].CurrentHP > RRole[rnum].MaxHP then RRole[rnum].CurrentHP := RRole[rnum].MaxHP;
      RRole[rnum].CurrentMP := RRole[rnum].CurrentMP + RRole[rnum].MaxMP div 20;
      if RRole[rnum].CurrentMP > RRole[rnum].MaxMP then RRole[rnum].CurrentMP := RRole[rnum].MaxMP;
      rrole[rnum].PhyPower := rrole[rnum].PhyPower + MAX_PHYSICAL_POWER div 10;
      if rrole[rnum].PhyPower > MAX_PHYSICAL_POWER then rrole[rnum].PhyPower := MAX_PHYSICAL_POWER;
    end else
    begin
      RRole[rnum].Hurt := 0;
      RRole[rnum].Poision := 0;
      RRole[rnum].CurrentHP := RRole[rnum].MaxHP;
      RRole[rnum].CurrentMP := RRole[rnum].MaxMP;
      rrole[rnum].PhyPower := MAX_PHYSICAL_POWER * 9 div 10;
    end;
  end;

end;

//增加经验

procedure AddExp;
var
  i, rnum, basicvalue, amount: integer;
  str: widestring;
begin
  for i := 0 to BRoleAmount - 1 do
  begin
    rnum := Brole[i].rnum;
    Rrole[rnum].Exp := Rrole[rnum].Exp + Brole[i].ExpGot;
    Rrole[rnum].ExpForBook := Rrole[rnum].ExpForBook + Brole[i].ExpGot div 5 * 4;
    Rrole[rnum].ExpForItem := Rrole[rnum].ExpForItem + Brole[i].ExpGot div 5 * 3;
    amount := Calrnum(0);
    if amount > 0 then basicvalue := warsta[7] div amount
    else basicvalue := 0;
    if (Brole[i].Team = 0) and (Brole[i].Dead = 0) then
    begin
      Rrole[rnum].Exp := Rrole[rnum].Exp + basicvalue;
      Rrole[rnum].ExpForBook := Rrole[rnum].ExpForBook + basicvalue div 5 * 4;
      Rrole[rnum].ExpForItem := Rrole[rnum].ExpForItem + basicvalue div 5 * 3;
      ShowSimpleStatus(rnum, 100, 50);
      DrawRectangle(100, 235, 145, 25, 0, colcolor(255), 25);
      str := ' 得經驗';
      Drawshadowtext(@str[1], 83, 237, colcolor($23), colcolor($21));
      str := format('%5d', [Brole[i].ExpGot + basicvalue]);
      Drawengshadowtext(@str[1], 188, 237, colcolor($66), colcolor($64));
      sdl_updaterect(screen, 0, 0, screen.w, screen.h);
      Redraw;
      waitanykey;
    end;

  end;

end;

//检查是否能够升级

procedure CheckLevelUp;
var
  i, rnum: integer;
begin
  for i := 0 to BRoleAmount - 1 do
  begin
    rnum := Brole[i].rnum;
    while (uint16(Rrole[rnum].Exp) >= uint16(LevelUplist[Rrole[rnum].Level - 1])) and (Rrole[rnum].Level < MAX_LEVEL) do
    begin
      Rrole[rnum].Exp := Rrole[rnum].Exp - LevelUplist[Rrole[rnum].Level - 1];
      Rrole[rnum].Level := Rrole[rnum].Level + 1;
      LevelUp(i);
    end;
  end;

end;

//升级, 如是我方人物显示状态

procedure LevelUp(bnum: integer);
var
  i, rnum, add: integer;
  str: widestring;
begin

  rnum := brole[bnum].rnum;
  RRole[rnum].MaxHP := RRole[rnum].MaxHP + Rrole[rnum].IncLife * 3 + random(6);
  if RRole[rnum].MaxHP > MAX_HP then RRole[rnum].MaxHP := MAX_HP;
  RRole[rnum].CurrentHP := RRole[rnum].MaxHP;

  add := Rrole[rnum].Aptitude div 15 + 1;
  add := random(add) + 1;

  RRole[rnum].MaxMP := RRole[rnum].MaxMP + (9 - add) * 3;
  if RRole[rnum].MaxMP > MAX_MP then RRole[rnum].MaxMP := MAX_MP;
  RRole[rnum].CurrentMP := RRole[rnum].MaxMP;

  RRole[rnum].Attack := RRole[rnum].Attack + add;
  Rrole[rnum].Speed := Rrole[rnum].Speed + add;
  Rrole[rnum].Defence := Rrole[rnum].Defence + add;

  for i := 46 to 54 do
  begin
    if rrole[rnum].data[i] > 0 then
      rrole[rnum].data[i] := rrole[rnum].data[i] + random(3) + 1;
  end;
  for i := 43 to 58 do
  begin
    if rrole[rnum].data[i] > maxprolist[i] then
      rrole[rnum].data[i] := maxprolist[i];
  end;

  RRole[rnum].PhyPower := MAX_PHYSICAL_POWER;
  RRole[rnum].Hurt := 0;
  RRole[rnum].Poision := 0;

  if Brole[bnum].Team = 0 then
  begin
    ShowStatus(rnum);
    str := ' 升級';
    Drawtextwithrect(@str[1], 50, CENTER_Y - 150, 46, colcolor($23), colcolor($21));
    waitanykey;
  end;

end;

//检查身上秘笈

procedure CheckBook;
var
  i, i1, i2, p, rnum, inum, mnum, mlevel, needexp, needitem, needitemamount, itemamount: integer;
  str: widestring;
begin
  for i := 0 to BRoleAmount - 1 do
  begin
    rnum := Brole[i].rnum;
    inum := Rrole[rnum].PracticeBook;
    if inum >= 0 then
    begin
      mlevel := 1;
      mnum := Ritem[inum].Magic;
      if mnum > 0 then
        for i1 := 0 to 9 do
          if Rrole[rnum].Magic[i1] = mnum then
          begin
            mlevel := Rrole[rnum].MagLevel[i1] div 100 + 1;
            break;
          end;
      needexp := mlevel * Ritem[inum].NeedExp * (7 - Rrole[rnum].Aptitude div 15);

      if (Rrole[rnum].ExpForBook >= needexp) and (mlevel < 10) then
      begin
        redraw;
        EatOneItem(rnum, inum);
        waitanykey;
        redraw;
        sdl_updaterect(screen, 0, 0, screen.w, screen.h);

        if mnum > 0 then
          instruct_33(rnum, mnum, 1);
        Rrole[rnum].ExpForBook := 0;
        //ShowStatus(rnum);
        //waitanykey;
      end;
      //是否能够炼出物品
      if (Rrole[rnum].ExpForItem >= ritem[inum].NeedExpForItem) and (ritem[inum].NeedExpForItem > 0) and (Brole[i].Team = 0) then
      begin
        redraw;
        p := 0;
        for i2 := 0 to 4 do
        begin
          if ritem[inum].GetItem[i2] >= 0 then p := p + 1;
        end;
        p := random(p);
        needitem := ritem[inum].NeedMaterial;
        if ritem[inum].GetItem[p] >= 0 then
        begin
          needitemamount := ritem[inum].NeedMatAmount[p];
          itemamount := 0;
          for i2 := 0 to MAX_ITEM_AMOUNT - 1 do
            if RItemList[i2].Number = needitem then
            begin
              itemamount := RItemList[i2].Amount;
              break;
            end;
          if needitemamount <= itemamount then
          begin
            ShowSimpleStatus(rnum, 350, 50);
            DrawRectangle(115, 63, 145, 25, 0, colcolor(255), 25);
            str := ' 製藥成功';
            Drawshadowtext(@str[1], 127, 65, colcolor($23), colcolor($21));

            instruct_2(ritem[inum].GetItem[p], 1 + random(5));
            instruct_32(needitem, -needitemamount);
            Rrole[rnum].ExpForItem := 0;
          end;
        end;
        //ShowStatus(rnum);
        //waitanykey;
      end;
    end;
  end;

end;

//统计一方人数

function CalRNum(team: integer): integer;
var
  i: integer;
begin
  result := 0;
  for i := 0 to broleamount - 1 do
  begin
    if (Brole[i].Team = team) and (Brole[i].Dead = 0) then result := result + 1;
  end;

end;

//战斗中物品选单

procedure BattleMenuItem(bnum: integer);
var
  rnum, inum, mode: integer;
  str: widestring;
begin
  if MenuItem then
  begin
    inum := CurItem;
    rnum := brole[bnum].rnum;
    mode := Ritem[inum].ItemType;
    case mode of
      3:
        begin
          EatOneItem(rnum, inum);
          instruct_32(inum, -1);
          Brole[bnum].Acted := 1;
          waitanykey;
        end;
      4:
        begin
          UseHiddenWeapen(bnum, inum);
        end;
    end;
  end;

end;

//动作动画

procedure PlayActionAmination(bnum, mode: integer);
var
  d1, d2, dm, rnum, i, beginpic, endpic, idx, grp, tnum, len: integer;
  filename: string;
begin
  d1 := Ax - Bx;
  d2 := Ay - By;
  dm := abs(d1) - abs(d2);
  if (dm >= 0) then
    if d1 < 0 then Brole[bnum].Face := 0 else Brole[bnum].Face := 3
  else
    if d2 < 0 then Brole[bnum].Face := 2 else Brole[bnum].Face := 1;

  Redraw;
  rnum := brole[bnum].rnum;
  if rrole[rnum].AmiFrameNum[mode] > 0 then
  begin
    beginpic := 0;
    for i := 0 to 4 do
    begin
      if i >= mode then break;
      beginpic := beginpic + rrole[rnum].AmiFrameNum[i] * 4;
    end;
    beginpic := beginpic + Brole[bnum].Face * rrole[rnum].AmiFrameNum[mode];
    endpic := beginpic + rrole[rnum].AmiFrameNum[mode] - 1;

    filename := format('%3d', [rrole[rnum].HeadNum]);

    for i := 1 to length(filename) do
      if filename[i] = ' ' then filename[i] := '0';

    idx := fileopen('fight\fight' + filename + '.idx', fmopenread);
    grp := fileopen('fight\fight' + filename + '.grp', fmopenread);
    len := fileseek(grp, 0, 2);
    fileseek(grp, 0, 0);
    fileread(grp, FPic[0], len);
    tnum := fileseek(idx, 0, 2) div 4;
    fileseek(idx, 0, 0);
    fileread(idx, FIdx[0], tnum * 4);
    fileclose(grp);
    fileclose(idx);

    for i := beginpic to endpic do
    begin
      DrawBfieldWithAction(bnum, i);
      sdl_updaterect(screen, 0, 0, screen.w, screen.h);
      sdl_delay(20);
    end;
  end;

end;

//用毒

procedure UsePoision(bnum: integer);
var
  rnum, bnum1, rnum1, poi, step, addpoi: integer;
  select: boolean;
begin
  calcanselect(bnum, 1);
  rnum := brole[bnum].rnum;
  poi := Rrole[rnum].UsePoi;
  step := poi div 15 + 1;
  if (Brole[bnum].Team = 0) and (brole[bnum].Auto = 0) then
    select := selectaim(bnum, step);
  if (bfield[2, Ax, Ay] >= 0) and (select = true) then
  begin
    Brole[bnum].Acted := 1;
    rrole[rnum].PhyPower := rrole[rnum].PhyPower - 3;
    bnum1 := bfield[2, Ax, Ay];
    if brole[bnum1].Team <> Brole[bnum].Team then
    begin
      rnum1 := brole[bnum1].rnum;
      addpoi := Rrole[rnum].UsePoi div 3 - rrole[rnum1].DefPoi div 4;
      if addpoi < 0 then addpoi := 0;
      if addpoi + rrole[rnum1].Poision > 99 then addpoi := 99 - rrole[rnum1].Poision;
      rrole[rnum1].Poision := rrole[rnum1].Poision + addpoi;
      brole[bnum1].ShowNumber := addpoi;
      SetAminationPosition(0, 0);
      PlayActionAmination(bnum, 0);
      PlayMagicAmination(bnum, 30);
      ShowHurtValue(2);
    end;
  end;
end;

//医疗

procedure Medcine(bnum: integer);
var
  rnum, bnum1, rnum1, med, step, addlife: integer;
  select: boolean;
begin
  calcanselect(bnum, 1);
  rnum := brole[bnum].rnum;
  med := Rrole[rnum].Medcine;
  step := med div 15 + 1;
  if (Brole[bnum].Team = 0) and (brole[bnum].Auto = 0) then
    select := selectaim(bnum, step)
  else
  begin
    Ax := Bx;
    Ay := By;
  end;
  if (bfield[2, Ax, Ay] >= 0) and (select = true) then
  begin
    Brole[bnum].Acted := 1;
    rrole[rnum].PhyPower := rrole[rnum].PhyPower - 5;
    bnum1 := bfield[2, Ax, Ay];
    if brole[bnum1].Team = Brole[bnum].Team then
    begin
      rnum1 := brole[bnum1].rnum;
      addlife := Rrole[rnum].Medcine; //calculate the value
      if addlife < 0 then addlife := 0;
      if addlife + rrole[rnum1].CurrentHP > rrole[rnum1].MaxHP then addlife := rrole[rnum1].MaxHP - rrole[rnum1].CurrentHP;
      rrole[rnum1].CurrentHP := rrole[rnum1].CurrentHP + addlife;
      Rrole[rnum1].Hurt := Rrole[rnum1].Hurt - addlife div LIFE_HURT;
      if Rrole[rnum1].Hurt < 0 then Rrole[rnum1].Hurt := 0;
      brole[bnum1].ShowNumber := addlife;
      SetAminationPosition(0, 0);
      PlayActionAmination(bnum, 0);
      PlayMagicAmination(bnum, 0);
      ShowHurtValue(3);
    end;
  end;

end;

//解毒

procedure MedPoision(bnum: integer);
var
  rnum, bnum1, rnum1, medpoi, step, minuspoi: integer;
  select: boolean;
begin
  calcanselect(bnum, 1);
  rnum := brole[bnum].rnum;
  medpoi := Rrole[rnum].MedPoi;
  step := medpoi div 15 + 1;
  if (Brole[bnum].Team = 0) and (brole[bnum].Auto = 0) then
    select := selectaim(bnum, step)
  else
  begin
    Ax := Bx;
    Ay := By;
  end;
  if (bfield[2, Ax, Ay] >= 0) and (select = true) then
  begin
    Brole[bnum].Acted := 1;
    rrole[rnum].PhyPower := rrole[rnum].PhyPower - 5;
    bnum1 := bfield[2, Ax, Ay];
    if brole[bnum1].Team = Brole[bnum].Team then
    begin
      rnum1 := brole[bnum1].rnum;
      minuspoi := Rrole[rnum].MedPoi;
      if minuspoi < 0 then minuspoi := 0;
      if rrole[rnum1].Poision - minuspoi <= 0 then minuspoi := rrole[rnum1].Poision;
      rrole[rnum1].Poision := rrole[rnum1].Poision - minuspoi;
      brole[bnum1].ShowNumber := minuspoi;
      SetAminationPosition(0, 0);
      PlayActionAmination(bnum, 0);
      PlayMagicAmination(bnum, 36);
      ShowHurtValue(4);
    end;
  end;

end;

//使用暗器

procedure UseHiddenWeapen(bnum, inum: integer);
var
  rnum, bnum1, rnum1, hidden, step, hurt: integer;
  select: boolean;
begin
  calcanselect(bnum, 1);
  rnum := brole[bnum].rnum;
  hidden := rrole[rnum].HidWeapon;
  step := hidden div 15 + 1;
  if ritem[inum].UnKnow7 > 0 then
    callevent(ritem[inum].UnKnow7)
  else begin
    if (Brole[bnum].Team = 0) and (brole[bnum].Auto = 0) then
      select := selectaim(bnum, step);
    if (bfield[2, Ax, Ay] >= 0) and (select = true) and (brole[bfield[2, Ax, Ay]].Team <> 0) then
    begin
      Brole[bnum].Acted := 1;
      instruct_32(inum, -1);
      bnum1 := bfield[2, Ax, Ay];
      if brole[bnum1].Team <> Brole[bnum].Team then
      begin
        rnum1 := brole[bnum1].rnum;
        hurt := rrole[rnum].HidWeapon div 2 - ritem[inum].AddCurrentHP div 3;
        hurt := hurt * (rrole[rnum1].Hurt div 33 + 1);
        if hurt < 0 then hurt := 0;
        rrole[rnum1].CurrentHP := rrole[rnum1].CurrentHP - hurt;
        brole[bnum1].ShowNumber := hurt;
        SetAminationPosition(0, 0);
        PlayActionAmination(bnum, 0);
        PlayMagicAmination(bnum, ritem[inum].AmiNum);
        ShowHurtValue(0);
      end;
    end;
  end;

end;

//休息

procedure Rest(bnum: integer);
var
  rnum: integer;
begin
  Brole[bnum].Acted := 1;
  rnum := brole[bnum].rnum;
  RRole[rnum].CurrentHP := RRole[rnum].CurrentHP + RRole[rnum].MaxHP div 20;
  if RRole[rnum].CurrentHP > RRole[rnum].MaxHP then RRole[rnum].CurrentHP := RRole[rnum].MaxHP;
  RRole[rnum].CurrentMP := RRole[rnum].CurrentMP + RRole[rnum].MaxMP div 20;
  if RRole[rnum].CurrentMP > RRole[rnum].MaxMP then RRole[rnum].CurrentMP := RRole[rnum].MaxMP;
  rrole[rnum].PhyPower := rrole[rnum].PhyPower + MAX_PHYSICAL_POWER div 20;
  if rrole[rnum].PhyPower > MAX_PHYSICAL_POWER then rrole[rnum].PhyPower := MAX_PHYSICAL_POWER;

end;

//The AI.

procedure AutoBattle(bnum: integer);
var
  i, p, a, temp, rnum, inum, eneamount, aim, mnum, level, Ax1, Ay1, i1, i2, step, step1, dis0, dis: integer;
  str: widestring;
begin
  rnum := brole[bnum].rnum;
  showsimplestatus(rnum, 350, 50);
  sdl_delay(450);
  //showmessage('');
  //Life is less than 20%, 70% probality to medcine or eat a pill.
  //生命低于20%, 70%可能医疗或吃药
  if (Brole[bnum].Acted = 0) and (RRole[rnum].CurrentHP < RRole[rnum].MaxHP div 5) then
  begin
    if random(100) < 70 then
    begin
      //医疗大于50, 且体力大于50才对自身医疗
      if (Rrole[rnum].Medcine >= 50) and (rrole[rnum].PhyPower >= 50) and (random(100) < 50) then
      begin
        medcine(bnum);
      end else
      begin
        // if can't medcine, eat the item which can add the most life on its body.
        //无法医疗则选择身上加生命最多的药品, 我方从物品栏选择
        AutoUseItem(bnum, 45);
      end;
    end;
  end;

  //MP is less than 20%, 60% probality to eat a pill.
  //内力低于20%, 60%可能吃药
  if (Brole[bnum].Acted = 0) and (RRole[rnum].CurrentMP < RRole[rnum].MaxMP div 5) then
  begin
    if random(100) < 60 then
    begin
      AutoUseItem(bnum, 50);
    end;
  end;

  //Physical power is less than 20%, 80% probality to eat a pill.
  //体力低于20%, 80%可能吃药
  if (Brole[bnum].Acted = 0) and (rrole[rnum].PhyPower < MAX_PHYSICAL_POWER div 5) then
  begin
    if random(100) < 80 then
    begin
      AutoUseItem(bnum, 48);
    end;
  end;

  //如未能吃药且体力大于10, 则尝试攻击
  if (Brole[bnum].Acted = 0) and (rrole[rnum].PhyPower >= 10) then
  begin
    //在敌方选择一个人物
    eneamount := Calrnum(1 - Brole[bnum].Team);
    aim := random(eneamount) + 1;
    //showmessage(inttostr(eneamount));
    for i := 0 to broleamount - 1 do
    begin
      if (Brole[bnum].Team <> Brole[i].Team) and (Brole[i].Dead = 0) then
      begin
        aim := aim - 1;
        if aim <= 0 then break;
      end;
    end;
    //Seclect one enemy randomly and try to close it.
    //尝试走到离敌人最近的位置
    Ax := Bx;
    Ay := By;
    Ax1 := Brole[i].X;
    Ay1 := Brole[i].Y;
    CalCanSelect(bnum, 0);
    dis0 := abs(Ax1 - Bx) + abs(Ay1 - By);
    for i1 := min(Ax1, Bx) to max(Ax1, Bx) do
      for i2 := min(Ay1, By) to max(Ay1, By) do
      begin
        if Bfield[3, i1, i2] = 0 then
        begin
          dis := abs(Ax1 - i1) + abs(Ay1 - i2);
          if (dis < dis0) and (abs(i1 - Bx) + abs(i2 - By) <= brole[bnum].Step) then
          begin
            Ax := i1;
            Ay := i2;
            dis0 := dis;
          end;
        end;
      end;
    if Bfield[3, Ax, Ay] = 0 then MoveAmination(bnum);
    Ax := Brole[i].X;
    Ay := Brole[i].Y;

    //Try to attack it. select the best WUGONG.
    //使用目前最强的武功攻击
    p := 0;
    a := 0;
    temp := 0;
    for i1 := 0 to 9 do
    begin
      mnum := Rrole[rnum].Magic[i1];
      if mnum > 0 then
      begin
        a := a + 1;
        level := Rrole[rnum].MagLevel[i1] div 100 + 1;
        if RRole[rnum].CurrentMP < rmagic[mnum].NeedMP * ((level + 1) div 2) then level := RRole[rnum].CurrentMP div rmagic[mnum].NeedMP * 2;
        if level > 10 then level := 10;
        if level <= 0 then level := 1;
        if rmagic[mnum].Attack[level - 1] > temp then
        begin
          p := i1;
          temp := rmagic[mnum].Attack[level - 1];
        end;
      end;
    end;
    //5% probility to re-select WUGONG randomly.
    //5%的可能重新选择武功
    if random(100) < 5 then p := random(a);

    //If the most powerful Wugong can't attack the aim,
    //re-select the one which has the longest attatck-distance.
    //如最强武功打不到, 选择攻击距离最远的武功
    if abs(Ax - Bx) + abs(Ay - By) > step then
    begin
      p := 0;
      a := 0;
      temp := 0;
      for i1 := 0 to 9 do
      begin
        mnum := Rrole[rnum].Magic[i1];
        if mnum > 0 then
        begin
          level := Rrole[rnum].MagLevel[i1] div 100 + 1;
          a := rmagic[mnum].MoveDistance[level - 1];
          if rmagic[mnum].AttAreaType = 3 then a := a + rmagic[mnum].AttDistance[level - 1];
          if a > temp then
          begin
            p := i1;
            temp := a;
          end;
        end;
      end;
    end;

    mnum := Rrole[rnum].Magic[p];
    level := Rrole[rnum].MagLevel[p] div 100 + 1;
    step := rmagic[mnum].MoveDistance[level - 1];
    step1 := 0;
    if rmagic[mnum].AttAreaType = 3 then step1 := rmagic[mnum].AttDistance[level - 1];
    if abs(Ax - Bx) + abs(Ay - By) <= step + step1 then
    begin
      //step := Rmagic[mnum, 28+level-1];
      if (rmagic[mnum].AttAreaType = 3) then
      begin
        //step1 := Rmagic[mnum, 38+level-1];
        dis := 0;
        Ax1 := Bx;
        Ay1 := By;
        for i1 := min(Ax, Bx) to max(Ax, Bx) do
          for i2 := min(Ay, By) to max(Ay, By) do
          begin
            if (abs(i1 - Ax) <= step1) and (abs(i2 - Ay) <= step1) and (abs(i1 - Bx) + abs(i2 - By) <= step + step1) then
            begin
              if dis < abs(i1 - Bx) + abs(i2 - By) then
              begin
                dis := abs(i1 - Bx) + abs(i2 - By);
                Ax1 := i1;
                Ay1 := i2;
              end;
            end;
          end;
        Ax := Ax1;
        Ay := Ay1;
      end;
      if Rmagic[mnum].AttAreaType <> 3 then
        SetAminationPosition(Rmagic[mnum].AttAreaType, step)
      else
        SetAminationPosition(Rmagic[mnum].AttAreaType, step1);

      if bfield[4, Ax, Ay] <> 0 then
      begin
        Brole[bnum].Acted := 1;
        for i1 := 0 to sign(Rrole[rnum].AttTwice) do
        begin
          Rrole[rnum].MagLevel[p] := Rrole[rnum].MagLevel[p] + random(2) + 1;
          if Rrole[rnum].MagLevel[p] > 999 then Rrole[rnum].MagLevel[p] := 999;
          if rmagic[mnum].UnKnow[4] > 0 then callevent(rmagic[mnum].UnKnow[4])
          else AttackAction(bnum, mnum, level);
        end;
      end;
    end;
  end;

  //If all other actions fail, rest.
  //如果上面行动全部失败则休息
  if Brole[bnum].Acted = 0 then rest(bnum);

  //检查是否有esc被按下
  if SDL_PollEvent(@event) >= 0 then
  begin
    if (event.type_ = SDL_QUITEV) then
      if messagedlg('Are you sure to quit?', mtConfirmation, [mbOk, mbCancel], 0) = idOK then Quit;
    if (event.key.keysym.sym = sdlk_Escape) then
    begin
      brole[bnum].Auto := 0;
    end;
  end;
end;

//自动使用list的值最大的物品

procedure AutoUseItem(bnum, list: integer);
var
  i, p, temp, rnum, inum: integer;
  str: widestring;
begin
  rnum := brole[bnum].rnum;
  if Brole[bnum].Team <> 0 then
  begin
    temp := 0;
    p := -1;
    for i := 0 to 3 do
    begin
      if Rrole[rnum].TakingItem[i] >= 0 then
      begin
        if ritem[Rrole[rnum].TakingItem[i]].Data[list] > temp then
        begin
          temp := ritem[Rrole[rnum].TakingItem[i]].Data[list];
          p := i;
        end;
      end;
    end;
  end else
  begin
    temp := 0;
    p := -1;
    for i := 0 to MAX_ITEM_AMOUNT - 1 do
    begin
      if (RItemList[i].Amount > 0) and (ritem[RItemList[i].Number].ItemType = 3) then
      begin
        if ritem[RItemList[i].Number].Data[list] > temp then
        begin
          temp := ritem[RItemList[i].Number].Data[list];
          p := i;
        end;
      end;
    end;
  end;

  if p >= 0 then
  begin
    if Brole[bnum].Team <> 0 then
      inum := rrole[rnum].TakingItem[p]
    else
      inum := RItemList[p].Number;
    redraw;
    sdl_updaterect(screen, 0, 0, screen.w, screen.h);
    EatOneItem(rnum, inum);
    if Brole[bnum].Team <> 0 then
      instruct_41(rnum, rrole[rnum].TakingItem[p], -1)
    else
      instruct_32(RItemList[p].Number, -1);
    Brole[bnum].Acted := 1;
    sdl_delay(750);
  end;

end;

end.

