unit Mobs; interface const (* Типы мобов *) none = 0; zomby = 1; procedure Create(typ, x, y : integer); function FindAndHit(value, x, y, w, h, addvx, addvy : integer) : integer; (* Части главного цикла *) procedure Update; procedure UpdatePhy; procedure Draw(camx, camy : integer); (* Управление сохранениями *) procedure SaveData; procedure LoadData; procedure ResetData; (* Управление текстурами *) procedure LoadTextures(path : string); procedure FreeTextures; implementation uses phy, player, canvas, jsr75i, func, drop, items; const lastType = 1; lastMob = 31; lastZombyFrame = 11; var mtype, mx, my, mvx, mvy, mpos, mhp, ma, mb, mc : array [0..lastMob] of integer; mjump : array [0..lastMob] of boolean; tw, th, thp, tjump : array [none..lastType] of integer; zombyBody : array [0..1] of image; zombyLegs : array [0..1, 0..2] of image; zombyAnim : array [0..lastZombyFrame] of integer; procedure UseObject(i : integer); begin Phy.SetObject(mx[i], my[i], tw[mtype[i]], th[mtype[i]], mvx[i], mvy[i], mjump[i]); end; procedure UpdateObject(i : integer); begin mx[i] := Phy.GetX; my[i] := Phy.GetY; mvx[i] := Phy.GetVX; mvy[i] := Phy.GetVY; mjump[i] := Phy.GetJump; end; procedure InitTab(typ, w, h, hp, jump : integer); begin assert((typ >= 0) and (typ <= lastType)); tw[typ] := w; th[typ] := h; thp[typ] := hp; tjump[typ] := jump; end; function GetW(i : integer) : integer; begin result := tw[mtype[i]]; end; function GetH(i : integer) : integer; begin result := th[mtype[i]]; end; function GetMaxHp(i : integer) : integer; begin result := thp[mtype[i]]; end; function GetJumpHeight(i : integer) : integer; begin result := tjump[mtype[i]]; end; function IsSolidStep(i, vec : integer) : boolean; var x, y : integer; begin if vec < 0 then x := (mx[i] - 8) / 16; else if vec > 0 then x := (mx[i] + GetW(i) + 4) / 16; else x := (mx[i] + GetW(i) / 2) / 16; y := (my[i] + GetH(i) - 8) / 16; result := Phy.IsSolid(x, y); end; procedure Swim(i, vec : integer); begin if Phy.AreaWithBlock(50, mx[i], my[i], GetW(i), GetH(i) / 2) or Phy.AreaWithBlock(51, mx[i], my[i], GetW(i), GetH(i) / 2) then begin if (vec <> 0) and IsSolidStep(i, vec) then mvy[i] := -10 else mvy[i] := -2; end; end; procedure Step(i, vec : integer); begin Swim(i, vec); if vec < 0 then begin mvx[i] := mvx[i] + vec; mpos[i] := 0; end else if vec > 0 then begin mvx[i] := mvx[i] + vec; mpos[i] := 1; end; end; procedure Jump(i, vec : integer); begin UseObject(i); Phy.Jump(GetJumpHeight(i)); UpdateObject(i); end; function CollisionWithPlayer(i : integer) : boolean; begin result := Phy.IntersectRects( mx[i], my[i], GetW(i), GetH(i), Player.GetX, Player.GetY, Player.GetW, Player.GetH ); end; procedure Die(i : integer); var x, y : integer; begin x := mx[i] + GetW(i) / 2; y := my[i] + GetH(i) / 2; if mtype[i] = zomby then begin Drop.Create(Items.rottenMeat, x, y, Random(3)); end; mtype[i] := none; end; procedure Hit(i, damage : integer); begin mhp[i] := mhp[i] - damage; if mhp[i] <= 0 then Die(i); end; (** ZombyThink -- мозги зомби **) (** ma = Кадр анимации **) (** mb = Таймер действий **) (** mc = Состояние **) procedure ZombyThink(i : integer); const stay = 0; walkleft = 1; walkright = 2; angry = 3; const bite = 1; speed = 1; walkTime = 30; angryTime = 200; stayTime = 300; begin // Debug('state: ' + mc[i] + ' / anim ' + ma[i] + ' / ticks ' + mb[i]); mb[i] := mb[i] - 1; if mb[i] < 0 then mb[i] := 0; if CollisionWithPlayer(i) then Player.BiteIt(bite, mvx[i]); (* Вижу игрока - сразу агрюсь и бегу за ним некоторое время *) if (mpos[i] = 0) and (Player.GetX - mx[i] < 0) or (mpos[i] = 1) and (Player.GetX - mx[i] > 0) then if Phy.RayTraced(mx[i], my[i], Player.GetX, Player.GetY) then begin mb[i] := angryTime; mc[i] := angry; end; if mc[i] = stay then begin ma[i] := 0; Swim(i, 0); if (mb[i] <= 0) and (Random(100) <= 2) then begin mb[i] := walkTime + Random(walkTime); mc[i] := walkleft + Random(2); (* Случайный разворот *) end; end else if mc[i] = walkleft then begin if IsSolidStep(i, -speed) then Jump(i, -speed); Step(i, -speed); ma[i] := (ma[i] + 1) mod lastZombyFrame; if mb[i] <= 0 then mc[i] := stay; end else if mc[i] = walkright then begin if IsSolidStep(i, speed) then Jump(i, speed); Step(i, speed); ma[i] := (ma[i] + 1) mod lastZombyFrame; if mb[i] <= 0 then mc[i] := stay; end else if mc[i] = angry then begin if mb[i] <= 0 then begin if Phy.RayTraced(mx[i], my[i], Player.GetX, Player.GetY) then begin (* Видижу игрока - устанавливаю время преследования *) mb[i] := angryTime; end else begin (* Игрока давно не было видно - ждём его некоторое время на месте *) mb[i] := stayTime; mc[i] := stay; end; end else begin (* Бежим за игроком *) if Player.GetX - mx[i] < 4 then begin if IsSolidStep(i, -speed) then Jump(i, -speed); Step(i, -speed); ma[i] := (ma[i] + 1) mod lastZombyFrame; end else if Player.GetX - mx[i] > 4 then begin if IsSolidStep(i, speed) then Jump(i, speed); Step(i, speed); ma[i] := (ma[i] + 1) mod lastZombyFrame; end else begin Swim(i, 0); end; end; end; end; procedure ZombyDraw(i, camx, camy : integer); var frame : integer; begin frame := zombyAnim[ma[i]]; DrawImage(zombyBody[mpos[i]], mx[i] - 6 - camx, my[i] - camy); DrawImage(zombyLegs[mpos[i], frame], mx[i] - 2 - camx, my[i] + 20 - camy); end; (* ============= Public ============= *) procedure Create(typ, x, y : integer); var i : integer; begin Assert((typ >= 0) and (typ <= lastType)); Debug('Create mob ' + typ +' @ ' + x + 'x' + y); for i := 0 to lastMob do if mtype[i] = none then begin mtype[i] := typ; mx[i] := x; my[i] := y; mvx[i] := 0; mvy[i] := 0; mpos[i] := 0; mhp[i] := thp[typ]; mjump[i] := false; ma[i] := 0; mb[i] := 0; mc[i] := 0; debug('Created mob is ' + i); exit; end; Debug('Mob type ' + typ + ' not created'); end; function FindAndHit(damage, x, y, w, h, addvx, addvy : integer) : integer; var i : integer; begin for i := 0 to lastMob do if mtype[i] <> none then if Phy.IntersectRects(x, y, w, h, mx[i], my[i], GetW(i), GetH(i)) then begin mvx[i] := mvx[i] + addvx; mvy[i] := mvy[i] + addvy; Hit(i, damage); FindAndHit := i; exit; end; FindAndHit := -1; end; procedure Update; var i, typ : integer; begin for i := 0 to lastMob do if mtype[i] <> none then begin typ := mtype[i]; if typ = zomby then ZombyThink(i); if mhp[i] <= 0 then Die(i); end; end; procedure UpdatePhy; var i : integer; begin for i := 0 to lastMob do begin UseObject(i); Phy.Step(true); UpdateObject(i); end; end; procedure Draw(camx, camy:integer); var i, typ : integer; begin for i := 0 to lastMob do if mtype[i] <> none then begin typ := mtype[i]; if typ = zomby then ZombyDraw(i, camx, camy); //SetColor(0, 0, 255); //DrawRect(mx[i] - camx, my[i] - camy, GetW(i) - 1, GetH(i) - 1); end; end; procedure LoadTextures(path : string); var im : image; begin im := ld_tex('zombie_ani.png', path, 'mobs/'); zombyBody[0] := rotate_image_from_image(im, 0, 0, 20, 22, 0); zombyBody[1] := rotate_image_from_image(im, 21, 0, 20, 22, 0); zombyLegs[0, 0] := rotate_image_from_image(im, 0, 52, 12, 12, 0); zombyLegs[0, 1] := rotate_image_from_image(im, 13, 52, 12, 12, 0); zombyLegs[0, 2] := rotate_image_from_image(im, 26, 52, 12, 12, 0); zombyLegs[1, 0] := rotate_image_from_image(im, 39, 52, 12, 12, 0); zombyLegs[1, 1] := rotate_image_from_image(im, 52, 52, 12, 12, 0); zombyLegs[1, 2] := rotate_image_from_image(im, 65, 52, 12, 12, 0); end; procedure FreeTextures; var i, j : integer; nullimg : image; begin for i := 0 to 1 do begin zombyBody[i] := nullimg; for j := 0 to 2 do zombyLegs[i, j] := nullimg; end; end; procedure SaveData; var i : integer; begin for i := 0 to lastMob do begin write_byte(mtype[i]); writeint(mx[i]); writeint(my[i]); writeint(mvx[i]); writeint(mvy[i]); write_byte(mpos[i]); writeint(mhp[i]); writebool(mjump[i]); writeint(ma[i]); writeint(mb[i]); writeint(mc[i]); end; end; procedure LoadData; var i : integer; begin for i := 0 to lastMob do begin mtype[i] := read_byte; mx[i] := readint; my[i] := readint; mvx[i] := readint; mvy[i] := readint; mpos[i] := read_byte; mhp[i] := readint; mjump[i] := readbool; ma[i] := readint; mb[i] := readint; mc[i] := readint; end; end; procedure ResetData; var i : integer; begin for i := 0 to lastMob do begin mtype[i] := none; mx[i] := 0; my[i] := 0; mvx[i] := 0; mvy[i] := 0; mpos[i] := 0; mhp[i] := 0; mjump[i] := false; ma[i] := 0; mb[i] := 0; mc[i] := 0; end; end; initialization InitTab(none, 0, 0, 0, 0); InitTab(zomby, 8, 32, 10, 7); zombyAnim[0] := 0; zombyAnim[1] := 0; zombyAnim[2] := 0; zombyAnim[3] := 1; zombyAnim[4] := 1; zombyAnim[5] := 1; zombyAnim[6] := 2; zombyAnim[7] := 2; zombyAnim[8] := 2; zombyAnim[9] := 1; zombyAnim[10] := 1; zombyAnim[11] := 1; end.