DEADSOFTWARE

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