DEADSOFTWARE

New implementation of module Items, *.cfg files now deprecated
[cavecraft.git] / src / Mobs.pas
1 unit Mobs;
3 interface
5 const
6 (* Типы мобов *)
7 none = 0;
8 zomby = 1;
10 procedure Create(typ, x, y : integer);
11 function FindAndHit(value, x, y, w, h, addvx, addvy : integer) : integer;
13 (* Части главного цикла *)
14 procedure Update;
15 procedure UpdatePhy;
16 procedure Draw(camx, camy : integer);
18 (* Управление сохранениями *)
19 procedure SaveData;
20 procedure LoadData;
21 procedure ResetData;
23 (* Управление текстурами *)
24 procedure LoadTextures(path : string);
25 procedure FreeTextures;
27 implementation
29 uses phy, player, canvas, jsr75i, func, drop;
31 const
32 lastType = 1;
33 lastMob = 31;
34 lastZombyFrame = 11;
36 rottenMeat = 190;
38 var
39 mtype, mx, my, mvx, mvy, mpos, mhp, ma, mb, mc : array [0..lastMob] of integer;
40 mjump : array [0..lastMob] of boolean;
41 tw, th, thp, tjump : array [none..lastType] of integer;
43 zombyBody : array [0..1] of image;
44 zombyLegs : array [0..1, 0..2] of image;
45 zombyAnim : array [0..lastZombyFrame] of integer;
47 procedure UseObject(i : integer);
48 begin
49 Phy.SetObject(mx[i], my[i], tw[mtype[i]], th[mtype[i]], mvx[i], mvy[i], mjump[i]);
50 end;
52 procedure UpdateObject(i : integer);
53 begin
54 mx[i] := Phy.GetX;
55 my[i] := Phy.GetY;
56 mvx[i] := Phy.GetVX;
57 mvy[i] := Phy.GetVY;
58 mjump[i] := Phy.GetJump;
59 end;
61 procedure InitTab(typ, w, h, hp, jump : integer);
62 begin
63 assert((typ >= 0) and (typ <= lastType));
64 tw[typ] := w;
65 th[typ] := h;
66 thp[typ] := hp;
67 tjump[typ] := jump;
68 end;
70 function GetW(i : integer) : integer;
71 begin
72 result := tw[mtype[i]];
73 end;
75 function GetH(i : integer) : integer;
76 begin
77 result := th[mtype[i]];
78 end;
80 function GetMaxHp(i : integer) : integer;
81 begin
82 result := thp[mtype[i]];
83 end;
85 function GetJumpHeight(i : integer) : integer;
86 begin
87 result := tjump[mtype[i]];
88 end;
90 function IsSolidStep(i, vec : integer) : boolean;
91 var
92 x, y : integer;
93 begin
94 if vec < 0 then x := (mx[i] - 8) / 16;
95 else if vec > 0 then x := (mx[i] + GetW(i) + 4) / 16;
96 else x := (mx[i] + GetW(i) / 2) / 16;
97 y := (my[i] + GetH(i) - 8) / 16;
98 result := Phy.IsSolid(x, y);
99 end;
101 procedure Swim(i, vec : integer);
102 begin
103 if Phy.AreaWithBlock(50, mx[i], my[i], GetW(i), GetH(i) / 2) or
104 Phy.AreaWithBlock(51, mx[i], my[i], GetW(i), GetH(i) / 2)
105 then begin
106 if (vec <> 0) and IsSolidStep(i, vec) then mvy[i] := -10 else mvy[i] := -2;
107 end;
108 end;
110 procedure Step(i, vec : integer);
111 begin
112 Swim(i, vec);
113 if vec < 0 then
114 begin
115 mvx[i] := mvx[i] + vec;
116 mpos[i] := 0;
117 end
118 else if vec > 0 then
119 begin
120 mvx[i] := mvx[i] + vec;
121 mpos[i] := 1;
122 end;
123 end;
125 procedure Jump(i, vec : integer);
126 begin
127 UseObject(i);
128 Phy.Jump(GetJumpHeight(i));
129 UpdateObject(i);
130 end;
132 function CollisionWithPlayer(i : integer) : boolean;
133 begin
134 result := Phy.IntersectRects(
135 mx[i], my[i], GetW(i), GetH(i),
136 Player.GetX, Player.GetY, Player.GetW, Player.GetH
137 );
138 end;
140 procedure Die(i : integer);
141 var
142 x, y : integer;
143 begin
144 x := mx[i] + GetW(i) / 2;
145 y := my[i] + GetH(i) / 2;
146 if mtype[i] = zomby then begin
147 Drop.Create(rottenMeat, x, y, Random(3));
148 end;
149 mtype[i] := none;
150 end;
152 procedure Hit(i, damage : integer);
153 begin
154 mhp[i] := mhp[i] - damage;
155 if mhp[i] <= 0 then Die(i);
156 end;
158 (** ZombyThink -- мозги зомби **)
159 (** ma = Кадр анимации **)
160 (** mb = Таймер действий **)
161 (** mc = Состояние **)
163 procedure ZombyThink(i : integer);
164 const
165 stay = 0;
166 walkleft = 1;
167 walkright = 2;
168 angry = 3;
169 const
170 bite = 1;
171 speed = 1;
172 walkTime = 30;
173 angryTime = 200;
174 stayTime = 300;
175 begin
176 // Debug('state: ' + mc[i] + ' / anim ' + ma[i] + ' / ticks ' + mb[i]);
178 mb[i] := mb[i] - 1;
179 if mb[i] < 0 then mb[i] := 0;
180 if CollisionWithPlayer(i) then Player.BiteIt(bite, mvx[i]);
182 (* Вижу игрока - сразу агрюсь и бегу за ним некоторое время *)
183 if (mpos[i] = 0) and (Player.GetX - mx[i] < 0) or (mpos[i] = 1) and (Player.GetX - mx[i] > 0) then
184 if Phy.RayTraced(mx[i], my[i], Player.GetX, Player.GetY) then
185 begin
186 mb[i] := angryTime;
187 mc[i] := angry;
188 end;
190 if mc[i] = stay then begin
191 ma[i] := 0;
192 Swim(i, 0);
193 if (mb[i] <= 0) and (Random(100) <= 2) then
194 begin
195 mb[i] := walkTime + Random(walkTime);
196 mc[i] := walkleft + Random(2); (* Случайный разворот *)
197 end;
198 end else if mc[i] = walkleft then begin
199 if IsSolidStep(i, -speed) then Jump(i, -speed);
200 Step(i, -speed);
201 ma[i] := (ma[i] + 1) mod lastZombyFrame;
202 if mb[i] <= 0 then mc[i] := stay;
203 end else if mc[i] = walkright then begin
204 if IsSolidStep(i, speed) then Jump(i, speed);
205 Step(i, speed);
206 ma[i] := (ma[i] + 1) mod lastZombyFrame;
207 if mb[i] <= 0 then mc[i] := stay;
208 end else if mc[i] = angry then begin
209 if mb[i] <= 0 then begin
210 if Phy.RayTraced(mx[i], my[i], Player.GetX, Player.GetY) then begin
211 (* Видижу игрока - устанавливаю время преследования *)
212 mb[i] := angryTime;
213 end else begin
214 (* Игрока давно не было видно - ждём его некоторое время на месте *)
215 mb[i] := stayTime;
216 mc[i] := stay;
217 end;
218 end else begin
219 (* Бежим за игроком *)
220 if Player.GetX - mx[i] < 4 then begin
221 if IsSolidStep(i, -speed) then Jump(i, -speed);
222 Step(i, -speed);
223 ma[i] := (ma[i] + 1) mod lastZombyFrame;
224 end else if Player.GetX - mx[i] > 4 then begin
225 if IsSolidStep(i, speed) then Jump(i, speed);
226 Step(i, speed);
227 ma[i] := (ma[i] + 1) mod lastZombyFrame;
228 end else begin
229 Swim(i, 0);
230 end;
231 end;
232 end;
233 end;
235 procedure ZombyDraw(i, camx, camy : integer);
236 var
237 frame : integer;
238 begin
239 frame := zombyAnim[ma[i]];
240 DrawImage(zombyBody[mpos[i]], mx[i] - 6 - camx, my[i] - camy);
241 DrawImage(zombyLegs[mpos[i], frame], mx[i] - 2 - camx, my[i] + 20 - camy);
242 end;
244 (* ============= Public ============= *)
246 procedure Create(typ, x, y : integer);
247 var
248 i : integer;
249 begin
250 Assert((typ >= 0) and (typ <= lastType));
251 Debug('Create mob ' + typ +' @ ' + x + 'x' + y);
252 for i := 0 to lastMob do if mtype[i] = none then
253 begin
254 mtype[i] := typ;
255 mx[i] := x;
256 my[i] := y;
257 mvx[i] := 0;
258 mvy[i] := 0;
259 mpos[i] := 0;
260 mhp[i] := thp[typ];
261 mjump[i] := false;
262 ma[i] := 0;
263 mb[i] := 0;
264 mc[i] := 0;
265 debug('Created mob is ' + i);
266 exit;
267 end;
268 Debug('Mob type ' + typ + ' not created');
269 end;
271 function FindAndHit(damage, x, y, w, h, addvx, addvy : integer) : integer;
272 var
273 i : integer;
274 begin
275 for i := 0 to lastMob do if mtype[i] <> none then
276 if Phy.IntersectRects(x, y, w, h, mx[i], my[i], GetW(i), GetH(i)) then
277 begin
278 mvx[i] := mvx[i] + addvx;
279 mvy[i] := mvy[i] + addvy;
280 Hit(i, damage);
281 FindAndHit := i;
282 exit;
283 end;
284 FindAndHit := -1;
285 end;
287 procedure Update;
288 var
289 i, typ : integer;
290 begin
291 for i := 0 to lastMob do if mtype[i] <> none then
292 begin
293 typ := mtype[i];
294 if typ = zomby then ZombyThink(i);
295 if mhp[i] <= 0 then Die(i);
296 end;
297 end;
299 procedure UpdatePhy;
300 var
301 i : integer;
302 begin
303 for i := 0 to lastMob do
304 begin
305 UseObject(i);
306 Phy.Step(true);
307 UpdateObject(i);
308 end;
309 end;
311 procedure Draw(camx, camy:integer);
312 var
313 i, typ : integer;
314 begin
315 for i := 0 to lastMob do if mtype[i] <> none then
316 begin
317 typ := mtype[i];
318 if typ = zomby then ZombyDraw(i, camx, camy);
319 //SetColor(0, 0, 255);
320 //DrawRect(mx[i] - camx, my[i] - camy, GetW(i) - 1, GetH(i) - 1);
321 end;
322 end;
324 procedure LoadTextures(path : string);
325 var
326 im : image;
327 begin
328 im := ld_tex('zombie_ani.png', path, 'mobs/');
329 zombyBody[0] := rotate_image_from_image(im, 0, 0, 20, 22, 0);
330 zombyBody[1] := rotate_image_from_image(im, 21, 0, 20, 22, 0);
331 zombyLegs[0, 0] := rotate_image_from_image(im, 0, 52, 12, 12, 0);
332 zombyLegs[0, 1] := rotate_image_from_image(im, 13, 52, 12, 12, 0);
333 zombyLegs[0, 2] := rotate_image_from_image(im, 26, 52, 12, 12, 0);
334 zombyLegs[1, 0] := rotate_image_from_image(im, 39, 52, 12, 12, 0);
335 zombyLegs[1, 1] := rotate_image_from_image(im, 52, 52, 12, 12, 0);
336 zombyLegs[1, 2] := rotate_image_from_image(im, 65, 52, 12, 12, 0);
337 end;
339 procedure FreeTextures;
340 var
341 i, j : integer;
342 nullimg : image;
343 begin
344 for i := 0 to 1 do
345 begin
346 zombyBody[i] := nullimg;
347 for j := 0 to 2 do zombyLegs[i, j] := nullimg;
348 end;
349 end;
351 procedure SaveData;
352 var
353 i : integer;
354 begin
355 for i := 0 to lastMob do
356 begin
357 write_byte(mtype[i]);
358 writeint(mx[i]);
359 writeint(my[i]);
360 writeint(mvx[i]);
361 writeint(mvy[i]);
362 write_byte(mpos[i]);
363 writeint(mhp[i]);
364 writebool(mjump[i]);
365 writeint(ma[i]);
366 writeint(mb[i]);
367 writeint(mc[i]);
368 end;
369 end;
371 procedure LoadData;
372 var
373 i : integer;
374 begin
375 for i := 0 to lastMob do
376 begin
377 mtype[i] := read_byte;
378 mx[i] := readint;
379 my[i] := readint;
380 mvx[i] := readint;
381 mvy[i] := readint;
382 mpos[i] := read_byte;
383 mhp[i] := readint;
384 mjump[i] := readbool;
385 ma[i] := readint;
386 mb[i] := readint;
387 mc[i] := readint;
388 end;
389 end;
391 procedure ResetData;
392 var
393 i : integer;
394 begin
395 for i := 0 to lastMob do
396 begin
397 mtype[i] := none;
398 mx[i] := 0;
399 my[i] := 0;
400 mvx[i] := 0;
401 mvy[i] := 0;
402 mpos[i] := 0;
403 mhp[i] := 0;
404 mjump[i] := false;
405 ma[i] := 0;
406 mb[i] := 0;
407 mc[i] := 0;
408 end;
409 end;
411 initialization
412 InitTab(none, 0, 0, 0, 0);
413 InitTab(zomby, 8, 32, 10, 7);
415 zombyAnim[0] := 0;
416 zombyAnim[1] := 0;
417 zombyAnim[2] := 0;
418 zombyAnim[3] := 1;
419 zombyAnim[4] := 1;
420 zombyAnim[5] := 1;
421 zombyAnim[6] := 2;
422 zombyAnim[7] := 2;
423 zombyAnim[8] := 2;
424 zombyAnim[9] := 1;
425 zombyAnim[10] := 1;
426 zombyAnim[11] := 1;
427 end.