]> 4ch.mooo.com Git - 16.git/blob - src/lib/hp/state/c3_state.c
fixed up wf3d8086
[16.git] / src / lib / hp / state / c3_state.c
1 /* Catacomb 3-D Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // C3_STATE.C\r
20 \r
21 #include "C3_DEF.H"\r
22 #pragma hdrstop\r
23 \r
24 /*\r
25 =============================================================================\r
26 \r
27                                                  LOCAL CONSTANTS\r
28 \r
29 =============================================================================\r
30 */\r
31 \r
32 \r
33 /*\r
34 =============================================================================\r
35 \r
36                                                  GLOBAL VARIABLES\r
37 \r
38 =============================================================================\r
39 */\r
40 \r
41 \r
42 \r
43 /*\r
44 =============================================================================\r
45 \r
46                                                  LOCAL VARIABLES\r
47 \r
48 =============================================================================\r
49 */\r
50 \r
51 \r
52 dirtype opposite[9] =\r
53         {south,west,north,east,southwest,northwest,northeast,southeast,nodir};\r
54 \r
55 \r
56 \r
57 //===========================================================================\r
58 \r
59 \r
60 /*\r
61 ===================\r
62 =\r
63 = SpawnNewObj\r
64 =\r
65 ===================\r
66 */\r
67 \r
68 void SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size)\r
69 {\r
70         GetNewObj (false);\r
71         new->size = size;\r
72         new->state = state;\r
73         new->ticcount = random (state->tictime)+1;\r
74 \r
75         new->tilex = x;\r
76         new->tiley = y;\r
77         new->x = ((long)x<<TILESHIFT)+TILEGLOBAL/2;\r
78         new->y = ((long)y<<TILESHIFT)+TILEGLOBAL/2;\r
79         CalcBounds(new);\r
80         new->dir = nodir;\r
81 \r
82         actorat[new->tilex][new->tiley] = new;\r
83 }\r
84 \r
85 void SpawnNewObjFrac (long x, long y, statetype *state, unsigned size)\r
86 {\r
87         GetNewObj (false);\r
88         new->size = size;\r
89         new->state = state;\r
90         new->ticcount = random (state->tictime)+1;\r
91         new->active = true;\r
92 \r
93         new->x = x;\r
94         new->y = y;\r
95         new->tilex = x>>TILESHIFT;\r
96         new->tiley = y>>TILESHIFT;\r
97         CalcBounds(new);\r
98         new->distance = 100;\r
99         new->dir = nodir;\r
100 }\r
101 \r
102 \r
103 \r
104 /*\r
105 ===================\r
106 =\r
107 = CheckHandAttack\r
108 =\r
109 = If the object can move next to the player, it will return true\r
110 =\r
111 ===================\r
112 */\r
113 \r
114 boolean CheckHandAttack (objtype *ob)\r
115 {\r
116         long deltax,deltay,size;\r
117 \r
118         size = (long)ob->size + player->size + ob->speed*tics;\r
119         deltax = ob->x - player->x;\r
120         deltay = ob->y - player->y;\r
121 \r
122         if (deltax > size || deltax < -size || deltay > size || deltay < -size)\r
123                 return false;\r
124 \r
125         return true;\r
126 }\r
127 \r
128 \r
129 /*\r
130 ===================\r
131 =\r
132 = T_DoDamage\r
133 =\r
134 = Attacks the player if still nearby, then immediately changes to next state\r
135 =\r
136 ===================\r
137 */\r
138 \r
139 void T_DoDamage (objtype *ob)\r
140 {\r
141         int     points;\r
142 \r
143 \r
144         if (!CheckHandAttack (ob))\r
145         {\r
146                 SD_PlaySound (MONSTERMISSSND);\r
147         }\r
148         else\r
149         {\r
150                 points = 0;\r
151 \r
152                 switch (ob->obclass)\r
153                 {\r
154                 case orcobj:\r
155                         points = 4;\r
156                         break;\r
157                 case trollobj:\r
158                         points = 8;\r
159                         break;\r
160                 case demonobj:\r
161                         points = 15;\r
162                         break;\r
163                 }\r
164                 TakeDamage (points);\r
165         }\r
166 \r
167         ob->state = ob->state->next;\r
168 }\r
169 \r
170 \r
171 //==========================================================================\r
172 \r
173 /*\r
174 ==================================\r
175 =\r
176 = Walk\r
177 =\r
178 ==================================\r
179 */\r
180 \r
181 boolean Walk (objtype *ob)\r
182 {\r
183         switch (ob->dir)\r
184         {\r
185         case north:\r
186                 if (actorat[ob->tilex][ob->tiley-1])\r
187                         return false;\r
188                 ob->tiley--;\r
189                 ob->distance = TILEGLOBAL;\r
190                 return true;\r
191 \r
192         case northeast:\r
193                 if (actorat[ob->tilex+1][ob->tiley-1])\r
194                         return false;\r
195                 ob->tilex++;\r
196                 ob->tiley--;\r
197                 ob->distance = TILEGLOBAL;\r
198                 return true;\r
199 \r
200         case east:\r
201                 if (actorat[ob->tilex+1][ob->tiley])\r
202                         return false;\r
203                 ob->tilex++;\r
204                 ob->distance = TILEGLOBAL;\r
205                 return true;\r
206 \r
207         case southeast:\r
208                 if (actorat[ob->tilex+1][ob->tiley+1])\r
209                         return false;\r
210                 ob->tilex++;\r
211                 ob->tiley++;\r
212                 ob->distance = TILEGLOBAL;\r
213                 return true;\r
214 \r
215         case south:\r
216                 if (actorat[ob->tilex][ob->tiley+1])\r
217                         return false;\r
218                 ob->tiley++;\r
219                 ob->distance = TILEGLOBAL;\r
220                 return true;\r
221 \r
222         case southwest:\r
223                 if (actorat[ob->tilex-1][ob->tiley+1])\r
224                         return false;\r
225                 ob->tilex--;\r
226                 ob->tiley++;\r
227                 ob->distance = TILEGLOBAL;\r
228                 return true;\r
229 \r
230         case west:\r
231                 if (actorat[ob->tilex-1][ob->tiley])\r
232                         return false;\r
233                 ob->tilex--;\r
234                 ob->distance = TILEGLOBAL;\r
235                 return true;\r
236 \r
237         case northwest:\r
238                 if (actorat[ob->tilex-1][ob->tiley-1])\r
239                         return false;\r
240                 ob->tilex--;\r
241                 ob->tiley--;\r
242                 ob->distance = TILEGLOBAL;\r
243                 return true;\r
244 \r
245         case nodir:\r
246                 return false;\r
247         }\r
248 \r
249         Quit ("Walk: Bad dir");\r
250         return false;\r
251 }\r
252 \r
253 \r
254 \r
255 /*\r
256 ==================================\r
257 =\r
258 = ChaseThink\r
259 = have the current monster go after the player,\r
260 = either diagonally or straight on\r
261 =\r
262 ==================================\r
263 */\r
264 \r
265 void ChaseThink (objtype *obj, boolean diagonal)\r
266 {\r
267         int deltax,deltay,i;\r
268         dirtype d[3];\r
269         dirtype tdir, olddir, turnaround;\r
270 \r
271 \r
272         olddir=obj->dir;\r
273         turnaround=opposite[olddir];\r
274 \r
275         deltax=player->tilex - obj->tilex;\r
276         deltay=player->tiley - obj->tiley;\r
277 \r
278         d[1]=nodir;\r
279         d[2]=nodir;\r
280 \r
281         if (deltax>0)\r
282                 d[1]= east;\r
283         if (deltax<0)\r
284                 d[1]= west;\r
285         if (deltay>0)\r
286                 d[2]=south;\r
287         if (deltay<0)\r
288                 d[2]=north;\r
289 \r
290         if (abs(deltay)>abs(deltax))\r
291         {\r
292                 tdir=d[1];\r
293                 d[1]=d[2];\r
294                 d[2]=tdir;\r
295         }\r
296 \r
297         if (d[1]==turnaround)\r
298                 d[1]=nodir;\r
299         if (d[2]==turnaround)\r
300                 d[2]=nodir;\r
301 \r
302 \r
303         if (diagonal)\r
304         {                           /*ramdiagonals try the best dir first*/\r
305                 if (d[1]!=nodir)\r
306                 {\r
307                         obj->dir=d[1];\r
308                         if (Walk(obj))\r
309                                 return;     /*either moved forward or attacked*/\r
310                 }\r
311 \r
312                 if (d[2]!=nodir)\r
313                 {\r
314                         obj->dir=d[2];\r
315                         if (Walk(obj))\r
316                                 return;\r
317                 }\r
318         }\r
319         else\r
320         {                  /*ramstraights try the second best dir first*/\r
321 \r
322                 if (d[2]!=nodir)\r
323                 {\r
324                         obj->dir=d[2];\r
325                         if (Walk(obj))\r
326                                 return;\r
327                 }\r
328 \r
329                 if (d[1]!=nodir)\r
330                 {\r
331                         obj->dir=d[1];\r
332                         if (Walk(obj))\r
333                                 return;\r
334                 }\r
335         }\r
336 \r
337 /* there is no direct path to the player, so pick another direction */\r
338 \r
339         obj->dir=olddir;\r
340         if (Walk(obj))\r
341                 return;\r
342 \r
343         if (US_RndT()>128)      /*randomly determine direction of search*/\r
344         {\r
345                 for (tdir=north;tdir<=west;tdir++)\r
346                 {\r
347                         if (tdir!=turnaround)\r
348                         {\r
349                                 obj->dir=tdir;\r
350                                 if (Walk(obj))\r
351                                         return;\r
352                         }\r
353                 }\r
354         }\r
355         else\r
356         {\r
357                 for (tdir=west;tdir>=north;tdir--)\r
358                 {\r
359                         if (tdir!=turnaround)\r
360                         {\r
361                           obj->dir=tdir;\r
362                           if (Walk(obj))\r
363                                 return;\r
364                         }\r
365                 }\r
366         }\r
367 \r
368         obj->dir=turnaround;\r
369         Walk(obj);              /*last chance, don't worry about returned value*/\r
370 }\r
371 \r
372 \r
373 /*\r
374 =================\r
375 =\r
376 = MoveObj\r
377 =\r
378 =================\r
379 */\r
380 \r
381 void MoveObj (objtype *ob, long move)\r
382 {\r
383         ob->distance -=move;\r
384 \r
385         switch (ob->dir)\r
386         {\r
387         case north:\r
388                 ob->y -= move;\r
389                 return;\r
390         case northeast:\r
391                 ob->x += move;\r
392                 ob->y -= move;\r
393                 return;\r
394         case east:\r
395                 ob->x += move;\r
396                 return;\r
397         case southeast:\r
398                 ob->x += move;\r
399                 ob->y += move;\r
400                 return;\r
401         case south:\r
402                 ob->y += move;\r
403                 return;\r
404         case southwest:\r
405                 ob->x -= move;\r
406                 ob->y += move;\r
407                 return;\r
408         case west:\r
409                 ob->x -= move;\r
410                 return;\r
411         case northwest:\r
412                 ob->x -= move;\r
413                 ob->y -= move;\r
414                 return;\r
415 \r
416         case nodir:\r
417                 return;\r
418         }\r
419 }\r
420 \r
421 \r
422 /*\r
423 =================\r
424 =\r
425 = Chase\r
426 =\r
427 = returns true if hand attack range\r
428 =\r
429 =================\r
430 */\r
431 \r
432 boolean Chase (objtype *ob, boolean diagonal)\r
433 {\r
434         long move;\r
435         long deltax,deltay,size;\r
436 \r
437         move = ob->speed*tics;\r
438         size = (long)ob->size + player->size + move;\r
439 \r
440         while (move)\r
441         {\r
442                 deltax = ob->x - player->x;\r
443                 deltay = ob->y - player->y;\r
444 \r
445                 if (deltax <= size && deltax >= -size\r
446                 && deltay <= size && deltay >= -size)\r
447                 {\r
448                         CalcBounds (ob);\r
449                         return true;\r
450                 }\r
451 \r
452                 if (move < ob->distance)\r
453                 {\r
454                         MoveObj (ob,move);\r
455                         break;\r
456                 }\r
457                 actorat[ob->tilex][ob->tiley] = 0;      // pick up marker from goal\r
458                 if (ob->dir == nodir)\r
459                         ob->dir = north;\r
460 \r
461                 ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
462                 ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
463                 move -= ob->distance;\r
464 \r
465                 ChaseThink (ob,diagonal);\r
466                 if (!ob->distance)\r
467                         break;                  // no possible move\r
468                 actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
469         }\r
470         CalcBounds (ob);\r
471         return false;\r
472 }\r
473 \r
474 //===========================================================================\r
475 \r
476 \r
477 /*\r
478 ===================\r
479 =\r
480 = ShootActor\r
481 =\r
482 ===================\r
483 */\r
484 \r
485 void ShootActor (objtype *ob, unsigned damage)\r
486 {\r
487         ob->hitpoints -= damage;\r
488         if (ob->hitpoints<=0)\r
489         {\r
490                 switch (ob->obclass)\r
491                 {\r
492                 case orcobj:\r
493                         ob->state = &s_orcdie1;\r
494                         GivePoints (100);\r
495                         break;\r
496                 case trollobj:\r
497                         ob->state = &s_trolldie1;\r
498                         GivePoints (400);\r
499                         break;\r
500                 case demonobj:\r
501                         ob->state = &s_demondie1;\r
502                         GivePoints (1000);\r
503                         break;\r
504                 case mageobj:\r
505                         ob->state = &s_magedie1;\r
506                         GivePoints (600);\r
507                         break;\r
508                 case batobj:\r
509                         ob->state = &s_batdie1;\r
510                         GivePoints (100);\r
511                         break;\r
512                 case grelmobj:\r
513                         ob->state = &s_greldie1;\r
514                         GivePoints (10000);\r
515                         break;\r
516 \r
517                 }\r
518                 ob->obclass = inertobj;\r
519                 ob->shootable = false;\r
520                 actorat[ob->tilex][ob->tiley] = NULL;\r
521         }\r
522         else\r
523         {\r
524                 switch (ob->obclass)\r
525                 {\r
526                 case orcobj:\r
527                         ob->state = &s_orcouch;\r
528                         break;\r
529                 case trollobj:\r
530                         ob->state = &s_trollouch;\r
531                         break;\r
532                 case demonobj:\r
533                         ob->state = &s_demonouch;\r
534                         break;\r
535                 case mageobj:\r
536                         ob->state = &s_mageouch;\r
537                         break;\r
538                 case grelmobj:\r
539                         ob->state = &s_grelouch;\r
540                         break;\r
541 \r
542                 }\r
543         }\r
544         ob->ticcount = ob->state->tictime;\r
545 }\r
546 \r