unit kys_engine;

interface

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

//音频子程
procedure InitialMusic;
procedure PlayMP3(MusicNum, times: integer); overload;
procedure PlayMP3(filename: pchar; times: integer); overload;
procedure StopMP3;
procedure PlaySound(SoundNum, times: integer); overload;
procedure PlaySound(SoundNum: integer); overload;
procedure PlaySound(filename: pchar; times: integer); overload;

//基本绘图子程
function getpixel(surface: PSDL_Surface; x: integer; y: integer): Uint32;
procedure putpixel(surface_: PSDL_Surface; x: integer; y: integer; pixel: Uint32);
procedure drawscreenpixel(x, y: integer; color: Uint32);
procedure display_bmp(file_name: PChar; x, y: integer);
procedure display_img(file_name: PChar; x, y: integer);
function ColColor(num: integer): Uint32;

//画RLE8图片的子程
function JudgeInScreen(px, py, w, h, xs, ys: integer): boolean; overload;
function JudgeInScreen(px, py, w, h, xs, ys, xx, yy, xw, yh: integer): boolean; overload;
procedure DrawRLE8Pic(num, px, py: Integer; Pidx: Pinteger; Ppic: PByte; RectArea: TRect; Image: PChar; Shadow: Integer);
function GetPositionOnScreen(x, y, CenterX, CenterY: integer): TPosition;
procedure DrawTitlePic(imgnum, px, py: integer);
procedure DrawMPic(num, px, py: integer);
procedure DrawSPic(num, px, py, x, y, w, h: integer);
procedure InitialSPic(num, px, py, x, y, w, h: integer);
procedure DrawHeadPic(num, px, py: integer);
procedure DrawBPic(num, px, py, shadow: integer);
procedure DrawBPicInRect(num, px, py, shadow, x, y, w, h: integer);
procedure InitialBPic(num, px, py: integer);
procedure DrawEPic(num, px, py: integer);
procedure DrawFPic(num, px, py: integer);

//显示文字的子程
function Big5ToUnicode(str: PChar): widestring;
function UnicodeToBig5(str: PWideChar): string;
procedure DrawText(sur: PSDL_Surface; word: PUint16; x_pos, y_pos: integer; color: Uint32);
procedure DrawEngText(sur: PSDL_Surface; word: PUint16; x_pos, y_pos: integer; color: Uint32);
procedure DrawShadowText(word: PUint16; x_pos, y_pos: integer; color1, color2: Uint32);
procedure DrawEngShadowText(word: PUint16; x_pos, y_pos: integer; color1, color2: Uint32);
procedure DrawBig5Text(sur: PSDL_Surface; str: PChar; x_pos, y_pos: integer; color: Uint32);
procedure DrawBig5ShadowText(word: pchar; x_pos, y_pos: integer; color1, color2: Uint32);
procedure DrawTextWithRect(word: puint16; x, y, w: integer; color1, color2: uint32);
procedure DrawRectangle(x, y, w, h: integer; colorin, colorframe: Uint32; alphe: integer);
procedure DrawRectangleWithoutFrame(x, y, w, h: integer; colorin: Uint32; alphe: integer);

//绘制整个屏幕的子程
procedure Redraw;
procedure DrawMMap;
procedure DrawScence;
procedure DrawScenceWithoutRole(x, y: integer);
procedure DrawRoleOnScence(x, y: integer);
procedure InitialScence();
procedure UpdateScence(xs, ys: integer);
procedure LoadScencePart(x, y: integer);
procedure DrawWholeBField;
procedure DrawBfieldWithoutRole(x, y: integer);
procedure DrawRoleOnBfield(x, y: integer);
procedure InitialWholeBField;
procedure LoadBfieldPart(x, y: integer);
procedure DrawBFieldWithCursor(step: integer);
procedure DrawBFieldWithEft(Epicnum: integer);
procedure DrawBFieldWithAction(bnum, Apicnum: integer);

implementation

procedure InitialMusic;
var
  i: integer;
  str: string;
begin
  for i := 0 to 23 do
  begin
    str := 'music\' + inttostr(i) + '.mp3';
    if fileexists(pchar(str)) then
      Music[i] := Mix_LoadMUS(pchar(str))
    else
      Music[i] := nil;
  end;
  for i := 0 to 52 do
  begin
    str := formatfloat('sound\e00', i) + '.wav';
    if fileexists(pchar(str)) then
      ESound[i] := Mix_LoadWav(pchar(str))
    else
      ESound[i] := nil;
  end;
  for i := 0 to 23 do
  begin
    str := formatfloat('sound\atk00', i) + '.wav';
    if fileexists(pchar(str)) then
      ASound[i] := Mix_LoadWav(pchar(str))
    else
      ASound[i] := nil;
  end;

end;



//播放mp3音乐

procedure PlayMP3(MusicNum, times: integer); overload;
begin
  if MusicNum in [Low(Music)..High(Music)] then
    if Music[MusicNum] <> nil then
      Mix_PlayMusic(Music[MusicNum], times);


end;

procedure PlayMP3(filename: pchar; times: integer); overload;
begin
  //if fileexists(filename) then
  //begin
    //Music := Mix_LoadMUS(filename);
    //Mix_volumemusic(MIX_MAX_VOLUME div 3);
    //Mix_PlayMusic(music, times);
  //end;

end;

//停止当前播放的音乐

procedure StopMP3;
begin
  Mix_HaltMusic;

end;

//播放wav音效

procedure PlaySound(SoundNum, times: integer); overload;
begin
  if SoundNum in [Low(Esound)..High(Esound)] then
    if Esound[SoundNum] <> nil then
      Mix_PlayChannel(-1, Esound[SoundNum], times);

end;

procedure PlaySound(SoundNum: integer); overload;
begin
  if SoundNum in [Low(Esound)..High(Esound)] then
    if Esound[SoundNum] <> nil then
      Mix_PlayChannel(-1, Esound[SoundNum], 0);

end;

procedure PlaySound(filename: pchar; times: integer); overload;
begin
  {if fileexists(filename) then
  begin
    Sound := Mix_LoadWav(filename);
    Mix_PlayChannel(-1, sound, times);
  end;}
end;

//获取某像素信息

function getpixel(surface: PSDL_Surface; x: integer; y: integer): Uint32;
type
  TByteArray = array[0..2] of Byte;
  PByteArray = ^TByteArray;
var
  bpp: integer;
  p: PInteger;
begin
  if (x >= 0) and (x < screen.w) and (y >= 0) and (y < screen.h) then
  begin
    bpp := surface.format.BytesPerPixel;
    // Here p is the address to the pixel we want to retrieve
    p := Pointer(Uint32(surface.pixels) + y * surface.pitch + x * bpp);
    case bpp of
      1:
        result := LongWord(p^);
      2:
        result := PUint16(p)^;
      3:
        if (SDL_BYTEORDER = SDL_BIG_ENDIAN) then
          result := PByteArray(p)[0] shl 16 or PByteArray(p)[1] shl 8 or PByteArray(p)[2]
        else
          result := PByteArray(p)[0] or PByteArray(p)[1] shl 8 or PByteArray(p)[2] shl 16;
      4:
        result := PUint32(p)^;
    else
      result := 0; // shouldn't happen, but avoids warnings
    end;
  end;

end;

//画像素

procedure putpixel(surface_: PSDL_Surface; x: integer; y: integer; pixel: Uint32);
type
  TByteArray = array[0..2] of Byte;
  PByteArray = ^TByteArray;
var
  bpp: integer;
  p: PInteger;
begin
  if (x >= 0) and (x < screen.w) and (y >= 0) and (y < screen.h) then
  begin
    bpp := surface_.format.BytesPerPixel;
    // Here p is the address to the pixel we want to set
    p := Pointer(Uint32(surface_.pixels) + y * surface_.pitch + x * bpp);

    case bpp of
      1:
        LongWord(p^) := pixel;
      2:
        PUint16(p)^ := pixel;
      3:
        if (SDL_BYTEORDER = SDL_BIG_ENDIAN) then
        begin
          PByteArray(p)[0] := (pixel shr 16) and $FF;
          PByteArray(p)[1] := (pixel shr 8) and $FF;
          PByteArray(p)[2] := pixel and $FF;
        end
        else
        begin
          PByteArray(p)[0] := pixel and $FF;
          PByteArray(p)[1] := (pixel shr 8) and $FF;
          PByteArray(p)[2] := (pixel shr 16) and $FF;
        end;
      4:
        PUint32(p)^ := pixel;
    end;
  end;

end;

//画一个点

procedure drawscreenpixel(x, y: integer; color: Uint32);
begin
  (* Map the color yellow to this display (R := $ff, G := $FF, B := $00)
     Note:  If the display is palettized, you must set the palette first.
  *)
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;

  putpixel(screen, x, y, color);

  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;
  // Update just the part of the display that we've changed
  SDL_UpdateRect(screen, x, y, 1, 1);
end;

//显示bmp文件

procedure display_bmp(file_name: PChar; x, y: integer);
var
  image: PSDL_Surface;
  dest: TSDL_Rect;
begin
  if fileexists(file_name) then
  begin
    image := SDL_LoadBMP(file_name);
    if (image = nil) then
    begin
      MessageBox(0, PChar(Format('Couldn''t load %s : %s', [file_name, SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
    dest.x := x;
    dest.y := y;
    if (SDL_BlitSurface(image, nil, screen, @dest) < 0) then
      MessageBox(0, PChar(Format('BlitSurface error : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
    //SDL_UpdateRect(screen, 0, 0, image.w, image.h);
    SDL_FreeSurface(image);
  end;
end;

//显示tif, png, jpg等格式图片

procedure display_img(file_name: PChar; x, y: integer);
var
  image: PSDL_Surface;
  dest: TSDL_Rect;
begin
  if fileexists(file_name) then
  begin
    image := IMG_Load(file_name);
    if (image = nil) then
    begin
      MessageBox(0, PChar(Format('Couldn''t load %s : %s',
        [file_name, SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
    dest.x := x;
    dest.y := y;
    if (SDL_BlitSurface(image, nil, screen, @dest) < 0) then
      MessageBox(0, PChar(Format('BlitSurface error : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
    //SDL_UpdateRect(screen, 0, 0, image.w, image.h);
    SDL_FreeSurface(image);
  end;
end;

//取调色板的颜色, 视频系统是32位色, 但很多时候仍需要原调色板的颜色

function ColColor(num: integer): Uint32;
begin
  colcolor := SDL_mapRGB(screen.format, Acol[num * 3 + 2] * 4, Acol[num * 3 + 1] * 4, Acol[num * 3] * 4);
end;

//判断像素是否在屏幕内

function JudgeInScreen(px, py, w, h, xs, ys: integer): boolean; overload;
begin
  result := false;
  if (px - xs + w >= 0) and (px - xs < screen.w)
    and (py - ys + h >= 0) and (py - ys < screen.h) then
    Result := true;

end;

//判断像素是否在指定范围内(重载)

function JudgeInScreen(px, py, w, h, xs, ys, xx, yy, xw, yh: integer): boolean; overload;
begin
  result := false;
  if (px - xs + w >= xx) and (px - xs < xx + xw)
    and (py - ys + h >= yy) and (py - ys < yy + yh) then
    Result := true;

end;
//RLE8图片绘制子程，所有相关子程均对此封装

procedure DrawRLE8Pic(num, px, py: integer; Pidx: Pinteger; Ppic: PByte; RectArea: TRect; Image: PChar; shadow: integer);
var
  w, h, xs, ys: smallint;
  offset, length, p: integer;
  l, l1, ix, iy: Byte;
begin
  if num = 0 then
    offset := 0
  else
  begin
    inc(Pidx, num - 1);
    offset := Pidx^;
  end;

  Inc(Ppic, offset);
  w := Psmallint((Ppic))^;
  Inc(Ppic, 2);
  h := Psmallint((Ppic))^;
  Inc(Ppic, 2);
  xs := Psmallint((Ppic))^;
  Inc(Ppic, 2);
  ys := Psmallint((Ppic))^;
  Inc(Ppic, 2);
  if JudgeInScreen(px, py, w, h, xs, ys, RectArea.x, RectArea.y, RectArea.w, RectArea.h) then
  begin
    for iy := 1 to h do
    begin
      l := Ppic^;
      inc(Ppic, 1);
      w := 1;
      p := 0;
      for ix := 1 to l do
      begin
        l1 := Ppic^;
        inc(Ppic);
        if p = 0 then
        begin
          w := w + l1;
          p := 1;
        end
        else if p = 1 then
        begin
          p := 2 + l1;
        end
        else if p > 2 then
        begin
          p := p - 1;
          if (w - xs + px >= RectArea.x) and (iy - ys + py >= RectArea.y) and (w - xs + px < RectArea.x + RectArea.w) and (iy - ys + py < RectArea.y + RectArea.h) then
          begin
            if image = nil then
              putpixel(screen, w - xs + px, iy - ys + py, sdl_maprgb(screen.format, ACol[l1 * 3] * (4 + shadow), ACol[l1 * 3 + 1] * (4 + shadow), ACol[l1 * 3 + 2] * (4 + shadow)))
            else
              Pint(image + ((w - xs + px) * 1152 + (iy - ys + py)) * 4)^ := sdl_maprgb(screen.format, ACol[l1 * 3] * (4 + shadow), ACol[l1 * 3 + 1] * (4 + shadow), ACol[l1 * 3 + 2] * (4 + shadow));
          end;
          w := w + 1;
          if p = 2 then
          begin
            p := 0;
          end;
        end;
      end;
    end;
  end;
end;

//获取游戏中坐标在屏幕上的位置

function GetPositionOnScreen(x, y, CenterX, CenterY: integer): TPosition;
begin
  result.x := -(x - CenterX) * 18 + (y - CenterY) * 18 + CENTER_X;
  result.y := (x - CenterX) * 9 + (y - CenterY) * 9 + CENTER_Y;
end;

//显示title.grp的内容(即开始的选单)

procedure DrawTitlePic(imgnum, px, py: integer);
var
  len, grp, idx: integer;
  Area: TRect;
  BufferIdx: array[0..100] of integer;
  BufferPic: array[0..20000] of Byte;
begin
  grp := fileopen('resource\title.grp', fmopenread);
  idx := fileopen('resource\title.idx', fmopenread);

  len := fileseek(idx, 0, 2);
  fileseek(idx, 0, 0);
  fileread(idx, BufferIdx[0], len);
  len := fileseek(grp, 0, 2);
  fileseek(grp, 0, 0);
  fileread(grp, BufferPic[0], len);

  fileclose(grp);
  fileclose(idx);

  Area.x := 0;
  Area.y := 0;
  Area.w := screen.w;
  Area.h := screen.h;
  DrawRLE8Pic(imgnum, px, py, @BufferIdx[0], @BufferPic[0], Area, nil, 0);

end;

//显示主地图贴图

procedure DrawMPic(num, px, py: integer);
var
  Area: Trect;
begin
  Area.x := 0;
  Area.y := 0;
  Area.w := screen.w;
  Area.h := screen.h;
  DrawRLE8Pic(num, px, py, @Midx[0], @Mpic[0], Area, nil, 0);

end;

//显示场景图片

procedure DrawSPic(num, px, py, x, y, w, h: integer);
var
  Area: TRect;
begin
  Area.x := x;
  Area.y := y;
  Area.w := w;
  Area.h := h;
  DrawRLE8Pic(num, px, py, @SIdx[0], @SPic[0], Area, nil, 0);

end;

//将场景图片信息写入映像

procedure InitialSPic(num, px, py, x, y, w, h: integer);
var
  Area: TRect;
begin
  if x + w > 2303 then
    w := 2303 - x;
  if y + h > 2303 then
    h := 2303 - y;
  Area.x := x;
  Area.y := y;
  Area.w := w;
  Area.h := h;
  DrawRLE8Pic(num, px, py, @SIdx[0], @SPic[0], Area, @ScenceImg[0], 0);

end;

//显示头像, 优先考虑'.head\'目录下的png图片

procedure DrawHeadPic(num, px, py: integer);
var
  len, grp, idx: integer;
  Area: TRect;
  str: string;
begin
  str := 'head\' + inttostr(num) + '.png';
  if fileexists(str) then
    display_img(@str[1], px, py - 60)
  else
  begin
    Area.x := 0;
    Area.y := 0;
    Area.w := screen.w;
    Area.h := screen.h;
    DrawRLE8Pic(num, px, py, @HIdx[0], @HPic[0], Area, nil, 0);
  end;

end;

//显示战场图片

procedure DrawBPic(num, px, py, shadow: integer);
var
  Area: TRect;
begin
  Area.x := 0;
  Area.y := 0;
  Area.w := screen.w;
  Area.h := screen.h;
  DrawRLE8Pic(num, px, py, @WIdx[0], @WPic[0], Area, nil, shadow);

end;

//仅在某区域显示战场图片

procedure DrawBPicInRect(num, px, py, shadow, x, y, w, h: integer);
var
  Area: TRect;
begin
  Area.x := x;
  Area.y := y;
  Area.w := w;
  Area.h := h;
  DrawRLE8Pic(num, px, py, @WIdx[0], @WPic[0], Area, nil, shadow);

end;

//将战场图片画到映像

procedure InitialBPic(num, px, py: integer);
var
  Area: TRect;
begin
  Area.x := 0;
  Area.y := 0;
  Area.w := 2304;
  Area.h := 1152;
  DrawRLE8Pic(num, px, py, @WIdx[0], @WPic[0], Area, @BFieldImg[0], 0);

end;

//显示效果图片

procedure DrawEPic(num, px, py: integer);
var
  Area: TRect;
begin
  Area.x := 0;
  Area.y := 0;
  Area.w := screen.w;
  Area.h := screen.h;
  DrawRLE8Pic(num, px, py, @EIdx[0], @EPic[0], Area, nil, 0);

end;

//显示人物动作图片

procedure DrawFPic(num, px, py: integer);
var
  Area: TRect;
begin
  Area.x := 0;
  Area.y := 0;
  Area.w := screen.w;
  Area.h := screen.h;
  DrawRLE8Pic(num, px, py, @FIdx[0], @FPic[0], Area, nil, 0);

end;

//big5转为unicode

function Big5ToUnicode(str: PChar): widestring;
var
  len: integer;
begin
  len := MultiByteToWideChar(950, 0, PChar(str), -1, nil, 0);
  setlength(result, len - 1);
  MultiByteToWideChar(950, 0, PChar(str), length(str), pwidechar(result), len + 1);
  result := ' ' + result;

end;

//unicode转为big5, 仅用于输入姓名

function UnicodeToBig5(str: PWideChar): string;
var
  len: integer;
begin
  len := WideCharToMultiByte(950, 0, PWideChar(str), -1, nil, 0, nil, nil);
  setlength(result, len + 1);
  WideCharToMultiByte(950, 0, PWideChar(str), -1, pchar(result), len + 1, nil, nil);

end;

//显示unicode文字

procedure DrawText(sur: PSDL_Surface; word: PUint16; x_pos, y_pos: integer; color: Uint32);
var
  dest: TSDL_Rect;
  len, i: integer;
  pword: array[0..2] of Uint16;
begin
  //len := length(word);
  pword[0] := 32;
  pword[2] := 0;

  dest.x := x_pos;
  while word^ > 0 do
  begin
    pword[1] := word^;
    inc(word);
    if pword[1] > 128 then
    begin
      text := TTF_RenderUNICODE_blended(font, @pword[0], TSDL_Color(Color));
      //dest.x := x_pos;
      dest.x := x_pos - 10;
      dest.y := y_pos;
      SDL_BlitSurface(text, nil, sur, @dest);
      x_pos := x_pos + 20;
    end
    else
    begin
      //if pword[1] <> 20 then
      begin
        text := TTF_RenderUNICODE_blended(engfont, @pword[1], TSDL_Color(Color));
        //showmessage(inttostr(pword[1]));
        dest.x := x_pos + 10;
        dest.y := y_pos + 4;
        SDL_BlitSurface(text, nil, sur, @dest);
      end;
      x_pos := x_pos + 10;
    end;
    SDL_FreeSurface(text);
  end;

end;

//显示英文

procedure DrawEngText(sur: PSDL_Surface; word: PUint16; x_pos, y_pos: integer; color: Uint32);
var
  dest: TSDL_Rect;
begin
  text := TTF_RenderUNICODE_blended(engfont, word, TSDL_Color(Color));
  dest.x := x_pos;
  dest.y := y_pos + 4;
  SDL_BlitSurface(text, nil, sur, @dest);
  SDL_FreeSurface(text);

end;

//显示unicode中文阴影文字, 即将同样内容显示2次, 间隔1像素

procedure DrawShadowText(word: PUint16; x_pos, y_pos: integer; color1, color2: Uint32);
begin
  DrawText(screen, word, x_pos + 1, y_pos, color2);
  DrawText(screen, word, x_pos, y_pos, color1);

end;

//显示英文阴影文字

procedure DrawEngShadowText(word: PUint16; x_pos, y_pos: integer; color1, color2: Uint32);
begin
  DrawEngText(screen, word, x_pos + 1, y_pos, color2);
  DrawEngText(screen, word, x_pos, y_pos, color1);

end;

//显示big5文字

procedure DrawBig5Text(sur: PSDL_Surface; str: PChar; x_pos, y_pos: integer; color: Uint32);
var
  len: integer;
  words: widestring;
begin
  len := MultiByteToWideChar(950, 0, PChar(str), -1, nil, 0);
  setlength(words, len - 1);
  MultiByteToWideChar(950, 0, PChar(str), length(str), pwidechar(words), len + 1);
  words := ' ' + words;
  drawtext(screen, @words[1], x_pos, y_pos, color);

end;

//显示big5阴影文字

procedure DrawBig5ShadowText(word: pchar; x_pos, y_pos: integer; color1, color2: Uint32);
var
  len: integer;
  words: widestring;
begin
  len := MultiByteToWideChar(950, 0, PChar(word), -1, nil, 0);
  setlength(words, len - 1);
  MultiByteToWideChar(950, 0, PChar(word), length(word), pwidechar(words), len + 1);
  words := ' ' + words;
  DrawText(screen, @words[1], x_pos + 1, y_pos, color2);
  DrawText(screen, @words[1], x_pos, y_pos, color1);

end;

//显示带边框的文字, 仅用于unicode, 需自定义宽度

procedure DrawTextWithRect(word: puint16; x, y, w: integer; color1, color2: uint32);
var
  len: integer;
  p: pchar;
begin
  DrawRectangle(x, y, w, 28, 0, colcolor(255), 30);
  DrawShadowText(word, x - 17, y + 2, color1, color2);
  sdl_updaterect(screen, x, y, w + 1, 29);

end;

//画带边框矩形, (x坐标, y坐标, 宽, 高, 内部颜色, 边框颜色, 透明度)

procedure DrawRectangle(x, y, w, h: integer; colorin, colorframe: Uint32; alphe: integer);
var
  i1, i2, l1, l2, l3, l4: integer;
  pix, pix1, pix2, pix3, pix4, color1, color2, color3, color4: Uint32;
begin
  if (SDL_MustLock(screen)) then
  begin
    SDL_LockSurface(screen);
  end;
  for i1 := x to x + w do
    for i2 := y to y + h do
    begin
      l1 := (i1 - x) + (i2 - y);
      l2 := -(i1 - x - w) + (i2 - y);
      l3 := (i1 - x) - (i2 - y - h);
      l4 := -(i1 - x - w) - (i2 - y - h);
      if (l1 >= 4) and (l2 >= 4) and (l3 >= 4) and (l4 >= 4) then
      begin
        pix := getpixel(screen, i1, i2);
        pix1 := pix and $FF;
        color1 := colorin and $FF;
        pix2 := pix shr 8 and $FF;
        color2 := colorin shr 8 and $FF;
        pix3 := pix shr 16 and $FF;
        color3 := colorin shr 16 and $FF;
        pix4 := pix shr 24 and $FF;
        color4 := colorin shr 24 and $FF;
        pix1 := (alphe * color1 + (100 - alphe) * pix1) div 100;
        pix2 := (alphe * color2 + (100 - alphe) * pix2) div 100;
        pix3 := (alphe * color3 + (100 - alphe) * pix3) div 100;
        pix4 := (alphe * color4 + (100 - alphe) * pix4) div 100;
        pix := pix1 + pix2 shl 8 + pix3 shl 16 + pix4 shl 24;
        putpixel(screen, i1, i2, pix);
      end;
      if (((l1 >= 4) and (l2 >= 4) and (l3 >= 4) and (l4 >= 4) and ((i1 = x) or (i1 = x + w) or (i2 = y) or (i2 = y + h)))
        or ((l1 = 4) or (l2 = 4) or (l3 = 4) or (l4 = 4))) then
      begin
        putpixel(screen, i1, i2, colorframe);
      end;
    end;
  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;

end;

//画不含边框的矩形, 用于对话和黑屏

procedure DrawRectangleWithoutFrame(x, y, w, h: integer; colorin: Uint32; alphe: integer);
var
  i1, i2: integer;
  pix, pix1, pix2, pix3, pix4, color1, color2, color3, color4: Uint32;
begin
  if (SDL_MustLock(screen)) then
  begin
    SDL_LockSurface(screen);
  end;
  for i1 := x to x + w do
    for i2 := y to y + h do
    begin
      pix := getpixel(screen, i1, i2);
      pix1 := pix and $FF;
      color1 := colorin and $FF;
      pix2 := pix shr 8 and $FF;
      color2 := colorin shr 8 and $FF;
      pix3 := pix shr 16 and $FF;
      color3 := colorin shr 16 and $FF;
      pix4 := pix shr 24 and $FF;
      color4 := colorin shr 24 and $FF;
      pix1 := (alphe * color1 + (100 - alphe) * pix1) div 100;
      pix2 := (alphe * color2 + (100 - alphe) * pix2) div 100;
      pix3 := (alphe * color3 + (100 - alphe) * pix3) div 100;
      pix4 := (alphe * color4 + (100 - alphe) * pix4) div 100;
      pix := pix1 + pix2 shl 8 + pix3 shl 16 + pix4 shl 24;
      putpixel(screen, i1, i2, pix);
    end;
  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;

end;

//重画屏幕, sdl_updaterect(screen,0,0,screen.w,screen.h)可显示

procedure Redraw;
begin
  case where of
    0: DrawMMap;
    1: DrawScence;
    2: DrawWholeBField;
    3: display_img('resource\open.png', 0, 0);
  end;

end;

//显示主地图场景于屏幕

procedure DrawMMap;
var
  i1, i2, i, sum, x, y: integer;
  temp: array[0..479, 0..479] of smallint;
  pos: TPosition;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;

  //由上到下绘制, 先绘制中心点靠上的建筑
  for sum := -29 to 40 do
    for i := -15 to 15 do
    begin
      i1 := Mx + i + (sum div 2);
      i2 := My - i + (sum - sum div 2);
      Pos := GetPositionOnScreen(i1, i2, Mx, My);
      if (i1 >= 0) and (i1 < 480) and (i2 >= 0) and (i2 < 480) then
      begin
        if (sum >= -27) and (sum <= 28) and (i >= -9) and (i <= 9) then
        begin
          DrawMPic(earth[i1, i2] div 2, pos.x, pos.y);
          if surface[i1, i2] > 0 then
            DrawMPic(surface[i1, i2] div 2, pos.x, pos.y);
        end;
        temp[i1, i2] := building[i1, i2];
      end
      else
        DrawMPic(0, pos.x, pos.y);

    end;
  for sum := -29 to 40 do
    for i := -15 to 15 do
    begin
      i1 := Mx + i + (sum div 2);
      i2 := My - i + (sum - sum div 2);
      if (i1 >= 0) and (i1 < 480) and (i2 >= 0) and (i2 < 480) then
      begin
        x := buildy[i1, i2];
        y := buildx[i1, i2];
        Pos := GetPositionOnScreen(x, y, Mx, My);
        if (buildx[i1, i2] > 0) and (((buildx[i1 - 1, i2 - 1] <> buildx[i1, i2]) and (buildx[i1 + 1, i2 + 1] <> buildx[i1, i2]))
          or ((buildy[i1 - 1, i2 - 1] <> buildy[i1, i2]) and (buildy[i1 + 1, i2 + 1] <> buildy[i1, i2]))) then
        begin

          if temp[x, y] > 0 then
          begin
            DrawMPic(building[x, y] div 2, pos.x, pos.y);
            temp[x, y] := 0;
          end;
        end;

        //如在水面上则绘制船的贴图
        if (i1 = Mx) and (i2 = My) then
          if (InShip = 0) then
            if still = 0 then
              DrawMPic(2500 + MFace * 7 + MStep, CENTER_X, CENTER_Y)
            else
              DrawMPic(2528 + Mface * 6 + MStep, CENTER_X, CENTER_Y)
          else
            DrawMPic(3714 + MFace * 4 + (MStep + 1) div 2, CENTER_X, CENTER_Y);
        if (temp[i1, i2] > 0) and (buildx[i1, i2] = i2) then
        begin
          DrawMPic(building[i1, i2] div 2, pos.x, pos.y);
          temp[i1, i2] := 0;
        end;
      end;

    end;

  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;
  //SDL_UpdateRect(screen, 0,0,screen.w,screen.h);

end;

//画场景到屏幕

procedure DrawScence;
var
  i1, i2, x, y, xpoint, ypoint: integer;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;

  //先画无主角的场景, 再画主角
  //如在事件中, 则以Cx, Cy为中心, 否则以主角坐标为中心
  if (CurEvent < 0) then
  begin
    DrawScenceWithoutRole(Sx, Sy);
    DrawRoleOnScence(Sx, Sy);
  end
  else
  begin
    DrawScenceWithoutRole(Cx, Cy);
    if (DData[CurScence, CurEvent, 10] = Sx) and (DData[CurScence, CurEvent, 9] = Sy) then
    begin
      if DData[CurScence, CurEvent, 5] <= 0 then
      begin
        DrawRoleOnScence(Cx, Cy);
      end;
    end
    else
      DrawRoleOnScence(Cx, Cy);
  end;

  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;
  //SDL_UpdateRect(screen, 0,0,screen.w,screen.h);

end;

//画不含主角的场景(与DrawScenceByCenter相同)

procedure DrawScenceWithoutRole(x, y: integer);
var
  i1, i2, xpoint, ypoint: integer;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;

  loadScencePart(-x * 18 + y * 18 + 1151 - CENTER_X, x * 9 + y * 9 + 9 - CENTER_Y);

  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;
  //SDL_UpdateRect(screen, 0,0,screen.w,screen.h);

end;

//画主角于场景

procedure DrawRoleOnScence(x, y: integer);
var
  i1, i2, xpoint, ypoint: integer;
  pos, pos1: TPosition;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;
  pos := getpositiononscreen(Sx, Sy, x, y);
  DrawSPic(2500 + SFace * 7 + SStep, pos.x, pos.y - SData[CurScence, 4, Sx, Sy], pos.x - 20, pos.y - 60 - SData[CurScence, 4, Sx, Sy], 40, 60);
  //重画主角附近的部分, 考虑遮挡
  for i1 := Sx - 1 to Sx + 10 do
    for i2 := Sy - 1 to Sy + 10 do
    begin
      pos1 := getpositiononscreen(i1, i2, x, y);
      if (i1 > Sx) and (i2 > Sy) then
        DrawSPic(SData[CurScence, 0, i1, i2] div 2, pos1.x, pos1.y, pos.x - 20, pos.y - 60 - SData[CurScence, 4, Sx, Sy], 40, 60);
      if (SData[CurScence, 1, i1, i2] > 0) and ((i2 > Sy) or (i1 > Sx)) then
        DrawSPic(SData[CurScence, 1, i1, i2] div 2, pos1.x, pos1.y - SData[CurScence, 4, i1, i2], pos.x - 20, pos.y - 60 - SData[CurScence, 4, Sx, Sy], 40, 60);
      if (SData[CurScence, 2, i1, i2] > 0) and ((i2 > Sy) or (i1 > Sx)) then
        DrawSPic(SData[CurScence, 2, i1, i2] div 2, pos1.x, pos1.y - SData[CurScence, 5, i1, i2], pos.x - 20, pos.y - 60 - SData[CurScence, 4, Sx, Sy], 40, 60);
      if (SData[CurScence, 3, i1, i2] >= 0) and ((i2 > Sy) or (i1 > Sx)) and (DData[CurScence, SData[CurScence, 3, i1, i2], 5] > 0) then
        DrawSPic(DData[CurScence, SData[CurScence, 3, i1, i2], 5] div 2, pos1.x, pos1.y - SData[CurScence, 4, i1, i2], pos.x - 20, pos.y - 60 - SData[CurScence, 4, Sx, Sy], 40, 60);
    end;

  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;

end;

//Save the image informations of the whole scence.
//生成场景映像

procedure InitialScence();
var
  i1, i2, x, y: integer;
  pos: TPosition;
begin
  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
    begin
      x := -i1 * 18 + i2 * 18 + 1151;
      y := i1 * 9 + i2 * 9 + 9;
      InitialSPic(SData[CurScence, 0, i1, i2] div 2, x, y, 0, 0, 2304, 1152);
      if (SData[CurScence, 1, i1, i2] > 0) then
        InitialSPic(SData[CurScence, 1, i1, i2] div 2, x, y - SData[CurScence, 4, i1, i2], 0, 0, 2304, 1152);
      if (SData[CurScence, 2, i1, i2] > 0) then
        InitialSPic(SData[CurScence, 2, i1, i2] div 2, x, y - SData[CurScence, 5, i1, i2], 0, 0, 2304, 1152);
      if (SData[CurScence, 3, i1, i2] >= 0) and (DData[CurScence, SData[CurScence, 3, i1, i2], 5] > 0) then
        InitialSPic(DData[CurScence, SData[CurScence, 3, i1, i2], 5] div 2, x, y - SData[CurScence, 4, i1, i2], 0, 0, 2304, 1152);
    end;

end;

//更改场景映像, 用于动画, 场景内动态效果

procedure UpdateScence(xs, ys: integer);
var
  i1, i2, x, y: integer;
  num, offset: integer;
  xp, yp, w, h: smallint;
begin
  xp := -xs * 18 + ys * 18 + 1151;
  yp := xs * 9 + ys * 9;
  //如在事件中, 直接给定更新范围
  if CurEvent < 0 then
  begin
    num := DData[CurScence, SData[CurScence, 3, xs, ys], 5] div 2;
    if num > 0 then
      offset := SIdx[num - 1];
    xp := xp - (SPic[offset + 4] + 256 * SPic[offset + 5]) - 3;
    yp := yp - (SPic[offset + 6] + 256 * SPic[offset + 7]) - 3 - SData[CurScence, 4, xs, ys];
    w := (SPic[offset] + 256 * SPic[offset + 1]) + 20;
    h := (SPic[offset + 2] + 256 * SPic[offset + 3]) + 6;
  end;
  if (CurEvent >= 0) or (num <= 0) then
  begin
    xp := xp - 30;
    yp := yp - 120;
    w := 100;
    h := 130;
  end;
  //计算贴图高度和宽度, 作为更新范围
  offset := max(h div 18, w div 36);
  for i1 := xs - offset to xs + 5 do
    for i2 := ys - offset to ys + 5 do
    begin
      x := -i1 * 18 + i2 * 18 + 1151;
      y := i1 * 9 + i2 * 9 + 9;
      InitialSPic(SData[CurScence, 0, i1, i2] div 2, x, y, xp, yp, w, h);
      if (i1 < 0) or (i2 < 0) or (i1 > 63) or (i2 > 63) then
        InitialSPic(0, x, y, xp, yp, w, h)
      else
      begin
        //InitialSPic(SData[CurScence, 0, i1,i2] div 2,x,y,xp,yp,w,h);
        if (SData[CurScence, 1, i1, i2] > 0) then
          InitialSPic(SData[CurScence, 1, i1, i2] div 2, x, y - SData[CurScence, 4, i1, i2], xp, yp, w, h);
        //if (i1=Sx) and (i2=Sy) then
          //InitialSPic(BEGIN_WALKPIC+SFace*7+SStep,x,y-SData[CurScence, 4, i1,i2],0,0,2304,1152);
        if (SData[CurScence, 2, i1, i2] > 0) then
          InitialSPic(SData[CurScence, 2, i1, i2] div 2, x, y - SData[CurScence, 5, i1, i2], xp, yp, w, h);
        if (SData[CurScence, 3, i1, i2] >= 0) and (DData[CurScence, SData[CurScence, 3, i1, i2], 5] > 0) then
          InitialSPic(DData[CurScence, SData[CurScence, 3, i1, i2], 5] div 2, x, y - SData[CurScence, 4, i1, i2], xp, yp, w, h);
        //if (i1=RScence[CurScence*26+15]) and (i2=RScence[CurScence*26+14]) then
          //DrawSPic(0,-(i1-Sx)*18+(i2-Sy)*18+CENTER_X,(i1-Sx)*9+(i2-Sy)*9+CENTER_Y);
        //if (i1=Sx) and (i2=Sy) then DrawSPic(2500+SFace*7+SStep,CENTER_X,CENTER_Y-SData[CurScence, 4, i1,i2]);
      end;
    end;

end;

//将场景映像画到屏幕

procedure LoadScencePart(x, y: integer);
var
  i1, i2: integer;
begin
  for i1 := 0 to screen.w - 1 do
    for i2 := 0 to screen.h - 1 do
      if (x + i1 >= 0) and (y + i2 >= 0) and (x + i1 < 2304) and (y + i2 < 1152) then
        putpixel(screen, i1, i2, scenceimg[x + i1, y + i2])
      else
        putpixel(screen, i1, i2, 0);

end;

//画战场

procedure DrawWholeBField;
var
  i, i1, i2: integer;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;
  DrawBFieldWithoutRole(Bx, By);

  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
    begin
      if (Bfield[2, i1, i2] >= 0) and (Brole[Bfield[2, i1, i2]].Dead = 0) then
        DrawRoleOnBfield(i1, i2);
    end;
  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;
end;

//画不含主角的战场

procedure DrawBFieldWithoutRole(x, y: integer);
var
  i1, i2, xpoint, ypoint: integer;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;

  loadBfieldPart(-x * 18 + y * 18 + 1151 - CENTER_X, x * 9 + y * 9 + 9 - CENTER_Y);

  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;
  //SDL_UpdateRect(screen, 0,0,screen.w,screen.h);

end;

//画战场上人物, 需更新人物身前的遮挡

procedure DrawRoleOnBfield(x, y: integer);
var
  i1, i2, xpoint, ypoint: integer;
  pos, pos1: Tposition;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;

  pos := GetPositionOnScreen(x, y, Bx, By);
  for i1 := x - 1 to x + 10 do
    for i2 := y - 1 to y + 10 do
    begin
      if (i1 = x) and (i2 = y) then
        DrawBPic(Rrole[Brole[Bfield[2, x, y]].rnum].HeadNum * 4 + Brole[Bfield[2, x, y]].Face + BEGIN_BATTLE_ROLE_PIC, pos.x, pos.y, 0);

      if (Bfield[1, i1, i2] > 0) then
      begin
        pos1 := GetPositionOnScreen(i1, i2, Bx, By);
        DrawBPicInRect(Bfield[1, i1, i2] div 2, pos1.x, pos1.y, 0, pos.x - 20, pos.y - 60, 40, 60);
        if (Bfield[2, i1, i2] >= 0) and (Brole[Bfield[2, i1, i2]].Dead = 0) then
          DrawBPicInRect(Rrole[Brole[Bfield[2, x, y]].rnum].HeadNum * 4 + Brole[Bfield[2, i1, i2]].Face + BEGIN_BATTLE_ROLE_PIC, pos1.x, pos1.y, 0, pos.x - 20, pos.y - 60, 40, 60);
      end;
    end;

  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;

end;

//初始化战场映像

procedure InitialWholeBField;
var
  i1, i2, x, y: integer;
begin
  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
    begin
      x := -i1 * 18 + i2 * 18 + 1151;
      y := i1 * 9 + i2 * 9 + 9;
      if (i1 < 0) or (i2 < 0) or (i1 > 63) or (i2 > 63) then
        InitialBPic(0, x, y)
      else
      begin
        InitialBPic(bfield[0, i1, i2] div 2, x, y);
        if (bfield[1, i1, i2] > 0) then
          InitialBPic(bfield[1, i1, i2] div 2, x, y);
      end;
    end;

end;

//将战场映像画到屏幕

procedure LoadBFieldPart(x, y: integer);
var
  i1, i2: integer;
begin
  for i1 := 0 to screen.w - 1 do
    for i2 := 0 to screen.h - 1 do
      if (x + i1 >= 0) and (y + i2 >= 0) and (x + i1 < 2304) and (y + i2 < 1152) then
        putpixel(screen, i1, i2, Bfieldimg[x + i1, y + i2])
      else
        putpixel(screen, i1, i2, 0);

end;

//画带光标的子程
//此子程效率不高

procedure DrawBFieldWithCursor(step: integer);
var
  i, i1, i2, bnum: integer;
  pos: TPosition;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;
  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
      if Bfield[0, i1, i2] > 0 then
      begin
        pos := GetpositionOnScreen(i1, i2, Bx, By);
        if (i1 = Ax) and (i2 = Ay) then
          DrawBPic(Bfield[0, i1, i2] div 2, pos.x, pos.y, 1)
        else if (BField[3, i1, i2] = 0) and (abs(i1 - Bx) + abs(i2 - By) <= step) then
          DrawBPic(Bfield[0, i1, i2] div 2, pos.x, pos.y, 0)
        else
          DrawBPic(Bfield[0, i1, i2] div 2, pos.x, pos.y, -1);
      end;

  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
    begin
      pos := getpositiononScreen(i1, i2, Bx, By);
      if Bfield[1, i1, i2] > 0 then
        DrawBPic(Bfield[1, i1, i2] div 2, pos.x, pos.y, 0);
      bnum := Bfield[2, i1, i2];
      if (bnum >= 0) and (Brole[bnum].Dead = 0) then
        DrawBPic(Rrole[Brole[bnum].rnum].HeadNum * 4 + Brole[bnum].Face + BEGIN_BATTLE_ROLE_PIC, pos.x, pos.y, 0);
    end;
  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;

end;

//画带效果的战场

procedure DrawBFieldWithEft(Epicnum: integer);
var
  i, i1, i2: integer;
  pos: TPosition;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;
  DrawBfieldWithoutRole(Bx, By);

  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
    begin
      pos := getpositiononScreen(i1, i2, Bx, By);
      if (Bfield[2, i1, i2] >= 0) and (Brole[Bfield[2, i1, i2]].Dead = 0) then
        DrawRoleOnBField(i1, i2);
      if Bfield[4, i1, i2] > 0 then
        DrawEPic(Epicnum, pos.x, pos.y);
    end;
  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;

end;

//画带人物动作的战场

procedure DrawBFieldWithAction(bnum, Apicnum: integer);
var
  i, i1, i2: integer;
  pos: TPosition;
begin
  if (SDL_MustLock(screen)) then
  begin
    if (SDL_LockSurface(screen) < 0) then
    begin
      MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
      exit;
    end;
  end;
  DrawBfieldWithoutRole(Bx, By);

  for i1 := 0 to 63 do
    for i2 := 0 to 63 do
    begin
      if (Bfield[2, i1, i2] >= 0) and (Brole[Bfield[2, i1, i2]].Dead = 0) and (Bfield[2, i1, i2] <> bnum) then
      begin
        DrawRoleOnBfield(i1, i2);
      end;
      if (Bfield[2, i1, i2] = bnum) then
      begin
        pos := GetPositionOnScreen(i1, i2, Bx, By);
        DrawFPic(apicnum, pos.x, pos.y);
      end;
    end;
  if (SDL_MustLock(screen)) then
  begin
    SDL_UnlockSurface(screen);
  end;

end;

end.

