1 | |
|
|
2 | /* |
1 | /* |
3 | * static char *rcsid_monster_c = |
2 | * CrossFire, A Multiplayer game for X-windows |
4 | * "$Id: monster.C,v 1.8 2006/09/10 15:59:57 root Exp $"; |
3 | * |
|
|
4 | * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team |
|
|
5 | * Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
|
|
6 | * Copyright (C) 1992 Frank Tore Johansen |
|
|
7 | * |
|
|
8 | * This program is free software; you can redistribute it and/or modify |
|
|
9 | * it under the terms of the GNU General Public License as published by |
|
|
10 | * the Free Software Foundation; either version 2 of the License, or |
|
|
11 | * (at your option) any later version. |
|
|
12 | * |
|
|
13 | * This program is distributed in the hope that it will be useful, |
|
|
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
16 | * GNU General Public License for more details. |
|
|
17 | * |
|
|
18 | * You should have received a copy of the GNU General Public License |
|
|
19 | * along with this program; if not, write to the Free Software |
|
|
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
|
21 | * |
|
|
22 | * The authors can be reached via e-mail at <crossfire@schmorp.de> |
5 | */ |
23 | */ |
6 | |
24 | |
7 | /* |
|
|
8 | CrossFire, A Multiplayer game for X-windows |
|
|
9 | |
|
|
10 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
|
|
11 | Copyright (C) 1992 Frank Tore Johansen |
|
|
12 | |
|
|
13 | This program is free software; you can redistribute it and/or modify |
|
|
14 | it under the terms of the GNU General Public License as published by |
|
|
15 | the Free Software Foundation; either version 2 of the License, or |
|
|
16 | (at your option) any later version. |
|
|
17 | |
|
|
18 | This program is distributed in the hope that it will be useful, |
|
|
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
21 | GNU General Public License for more details. |
|
|
22 | |
|
|
23 | You should have received a copy of the GNU General Public License |
|
|
24 | along with this program; if not, write to the Free Software |
|
|
25 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
|
26 | |
|
|
27 | The authors can be reached via e-mail at crossfire-devel@real-time.com |
|
|
28 | */ |
|
|
29 | |
|
|
30 | #include <global.h> |
25 | #include <global.h> |
31 | #ifndef __CEXTRACT__ |
|
|
32 | # include <sproto.h> |
26 | #include <sproto.h> |
33 | # include <spells.h> |
27 | #include <spells.h> |
34 | # include <skills.h> |
28 | #include <skills.h> |
35 | #endif |
|
|
36 | |
|
|
37 | |
29 | |
38 | #define MIN_MON_RADIUS 3 /* minimum monster detection radius */ |
30 | #define MIN_MON_RADIUS 3 /* minimum monster detection radius */ |
39 | |
|
|
40 | |
31 | |
41 | /* checks npc->enemy and returns that enemy if still valid, |
32 | /* checks npc->enemy and returns that enemy if still valid, |
42 | * NULL otherwise. |
33 | * NULL otherwise. |
43 | * this is map tile aware. |
34 | * this is map tile aware. |
44 | * If this returns an enemy, the range vector rv should also be |
35 | * If this returns an enemy, the range vector rv should also be |
… | |
… | |
121 | object * |
112 | object * |
122 | find_nearest_living_creature (object *npc) |
113 | find_nearest_living_creature (object *npc) |
123 | { |
114 | { |
124 | int i, mflags; |
115 | int i, mflags; |
125 | sint16 nx, ny; |
116 | sint16 nx, ny; |
126 | mapstruct *m; |
117 | maptile *m; |
127 | object *tmp; |
|
|
128 | int search_arr[SIZEOFFREE]; |
118 | int search_arr[SIZEOFFREE]; |
129 | |
119 | |
130 | get_search_arr (search_arr); |
120 | get_search_arr (search_arr); |
|
|
121 | |
131 | for (i = 0; i < SIZEOFFREE; i++) |
122 | for (i = 0; i < SIZEOFFREE; i++) |
132 | { |
123 | { |
133 | /* modified to implement smart searching using search_arr |
124 | /* modified to implement smart searching using search_arr |
134 | * guidance array to determine direction of search order |
125 | * guidance array to determine direction of search order |
135 | */ |
126 | */ |
136 | nx = npc->x + freearr_x[search_arr[i]]; |
127 | nx = npc->x + freearr_x[search_arr[i]]; |
137 | ny = npc->y + freearr_y[search_arr[i]]; |
128 | ny = npc->y + freearr_y[search_arr[i]]; |
138 | m = npc->map; |
129 | m = npc->map; |
139 | |
130 | |
140 | mflags = get_map_flags (m, &m, nx, ny, &nx, &ny); |
131 | mflags = get_map_flags (m, &m, nx, ny, &nx, &ny); |
|
|
132 | |
141 | if (mflags & P_OUT_OF_MAP) |
133 | if (mflags & P_OUT_OF_MAP) |
142 | continue; |
134 | continue; |
143 | |
135 | |
144 | if (mflags & P_IS_ALIVE) |
136 | if (mflags & P_IS_ALIVE) |
145 | { |
137 | { |
146 | tmp = get_map_ob (m, nx, ny); |
138 | for (object *tmp = m->at (nx, ny).top; tmp; tmp = tmp->below) |
147 | while (tmp != NULL && !QUERY_FLAG (tmp, FLAG_MONSTER) && !QUERY_FLAG (tmp, FLAG_GENERATOR) && tmp->type != PLAYER) |
139 | if (tmp->flag [FLAG_MONSTER] || tmp->flag [FLAG_GENERATOR] || tmp->type == PLAYER) |
148 | tmp = tmp->above; |
|
|
149 | |
|
|
150 | if (!tmp) |
|
|
151 | { |
|
|
152 | LOG (llevDebug, "find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n", |
|
|
153 | m->path, nx, ny); |
|
|
154 | } |
|
|
155 | else |
|
|
156 | { |
|
|
157 | if (can_see_monsterP (m, nx, ny, i)) |
140 | if (can_see_monsterP (m, nx, ny, i)) |
158 | return tmp; |
141 | return tmp; |
159 | } |
142 | } |
160 | } /* is something living on this space */ |
|
|
161 | } |
143 | } |
162 | return NULL; /* nothing found */ |
144 | |
|
|
145 | return 0; |
163 | } |
146 | } |
164 | |
147 | |
165 | |
148 | |
166 | /* Tries to find an enmy for npc. We pass the range vector since |
149 | /* Tries to find an enmy for npc. We pass the range vector since |
167 | * our caller will find the information useful. |
150 | * our caller will find the information useful. |
… | |
… | |
175 | find_enemy (object *npc, rv_vector * rv) |
158 | find_enemy (object *npc, rv_vector * rv) |
176 | { |
159 | { |
177 | object *attacker, *tmp = NULL; |
160 | object *attacker, *tmp = NULL; |
178 | |
161 | |
179 | attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */ |
162 | attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */ |
180 | npc->attacked_by = NULL; /* always clear the attacker entry */ |
163 | npc->attacked_by = 0; /* always clear the attacker entry */ |
181 | |
164 | |
182 | /* if we berserk, we don't care about others - we attack all we can find */ |
165 | /* if we berserk, we don't care about others - we attack all we can find */ |
183 | if (QUERY_FLAG (npc, FLAG_BERSERK)) |
166 | if (QUERY_FLAG (npc, FLAG_BERSERK)) |
184 | { |
167 | { |
185 | tmp = find_nearest_living_creature (npc); |
168 | tmp = find_nearest_living_creature (npc); |
|
|
169 | |
186 | if (tmp) |
170 | if (tmp) |
187 | get_rangevector (npc, tmp, rv, 0); |
171 | get_rangevector (npc, tmp, rv, 0); |
188 | return tmp; |
172 | return tmp; |
189 | } |
173 | } |
190 | |
174 | |
… | |
… | |
200 | |
184 | |
201 | /* pet move */ |
185 | /* pet move */ |
202 | if ((npc->attack_movement & HI4) == PETMOVE) |
186 | if ((npc->attack_movement & HI4) == PETMOVE) |
203 | { |
187 | { |
204 | tmp = get_pet_enemy (npc, rv); |
188 | tmp = get_pet_enemy (npc, rv); |
|
|
189 | |
205 | if (tmp) |
190 | if (tmp) |
206 | get_rangevector (npc, tmp, rv, 0); |
191 | get_rangevector (npc, tmp, rv, 0); |
|
|
192 | |
207 | return tmp; |
193 | return tmp; |
208 | } |
194 | } |
209 | |
195 | |
210 | /* we check our old enemy. */ |
196 | /* we check our old enemy. */ |
211 | if ((tmp = check_enemy (npc, rv)) == NULL) |
197 | if (!(tmp = check_enemy (npc, rv))) |
212 | { |
198 | { |
213 | if (attacker) /* if we have an attacker, check him */ |
199 | if (attacker) /* if we have an attacker, check him */ |
214 | { |
200 | { |
215 | /* we want be sure this is the right one! */ |
201 | /* TODO: thats not finished */ |
216 | if (attacker->count == npc->attacked_by_count) |
202 | /* we don't want a fight evil vs evil or good against non evil */ |
|
|
203 | |
|
|
204 | if (QUERY_FLAG (npc, FLAG_NEUTRAL) || QUERY_FLAG (attacker, FLAG_NEUTRAL) || /* neutral */ |
|
|
205 | (QUERY_FLAG (npc, FLAG_FRIENDLY) && QUERY_FLAG (attacker, FLAG_FRIENDLY)) || |
|
|
206 | (!QUERY_FLAG (npc, FLAG_FRIENDLY) && (!QUERY_FLAG (attacker, FLAG_FRIENDLY) && attacker->type != PLAYER))) |
|
|
207 | CLEAR_FLAG (npc, FLAG_SLEEP); /* skip it, but lets wakeup */ |
|
|
208 | else if (on_same_map (npc, attacker)) /* thats the only thing we must know... */ |
217 | { |
209 | { |
218 | /* TODO: thats not finished */ |
|
|
219 | /* we don't want a fight evil vs evil or good against non evil */ |
|
|
220 | |
|
|
221 | if (QUERY_FLAG (npc, FLAG_NEUTRAL) || QUERY_FLAG (attacker, FLAG_NEUTRAL) || /* neutral */ |
|
|
222 | (QUERY_FLAG (npc, FLAG_FRIENDLY) && QUERY_FLAG (attacker, FLAG_FRIENDLY)) || |
|
|
223 | (!QUERY_FLAG (npc, FLAG_FRIENDLY) && (!QUERY_FLAG (attacker, FLAG_FRIENDLY) && attacker->type != PLAYER))) |
|
|
224 | CLEAR_FLAG (npc, FLAG_SLEEP); /* skip it, but lets wakeup */ |
|
|
225 | else if (on_same_map (npc, attacker)) /* thats the only thing we must know... */ |
|
|
226 | { |
|
|
227 | CLEAR_FLAG (npc, FLAG_SLEEP); /* well, NOW we really should wake up! */ |
210 | CLEAR_FLAG (npc, FLAG_SLEEP); /* well, NOW we really should wake up! */ |
228 | npc->enemy = attacker; |
211 | npc->enemy = attacker; |
229 | return attacker; /* yes, we face our attacker! */ |
212 | return attacker; /* yes, we face our attacker! */ |
230 | } |
|
|
231 | } |
213 | } |
232 | } |
214 | } |
233 | |
215 | |
234 | /* we have no legal enemy or attacker, so we try to target a new one */ |
216 | /* we have no legal enemy or attacker, so we try to target a new one */ |
235 | if (!QUERY_FLAG (npc, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (npc, FLAG_FRIENDLY) && !QUERY_FLAG (npc, FLAG_NEUTRAL)) |
217 | if (!QUERY_FLAG (npc, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (npc, FLAG_FRIENDLY) && !QUERY_FLAG (npc, FLAG_NEUTRAL)) |
… | |
… | |
296 | int i; |
278 | int i; |
297 | |
279 | |
298 | /* Give up to 15 chances for a monster to move randomly */ |
280 | /* Give up to 15 chances for a monster to move randomly */ |
299 | for (i = 0; i < 15; i++) |
281 | for (i = 0; i < 15; i++) |
300 | { |
282 | { |
301 | if (move_object (op, RANDOM () % 8 + 1)) |
283 | if (move_object (op, rndm (8) + 1)) |
302 | return 1; |
284 | return 1; |
303 | } |
285 | } |
304 | return 0; |
286 | return 0; |
305 | } |
287 | } |
306 | |
288 | |
… | |
… | |
326 | oph = oph->head; |
308 | oph = oph->head; |
327 | |
309 | |
328 | if (QUERY_FLAG (op, FLAG_NO_ATTACK)) /* we never ever attack */ |
310 | if (QUERY_FLAG (op, FLAG_NO_ATTACK)) /* we never ever attack */ |
329 | enemy = op->enemy = NULL; |
311 | enemy = op->enemy = NULL; |
330 | else if ((enemy = find_enemy (op, &rv))) |
312 | else if ((enemy = find_enemy (op, &rv))) |
331 | { |
|
|
332 | /* we have an enemy, just tell him we want him dead */ |
313 | /* we have an enemy, just tell him we want him dead */ |
333 | enemy->attacked_by = op; /* our ptr */ |
314 | enemy->attacked_by = op; /* our ptr */ |
334 | enemy->attacked_by_count = op->count; /* our tag */ |
|
|
335 | } |
|
|
336 | |
315 | |
337 | /* generate hp, if applicable */ |
316 | /* generate hp, if applicable */ |
338 | if (op->stats.Con > 0 && op->stats.hp < op->stats.maxhp) |
317 | if (op->stats.Con > 0 && op->stats.hp < op->stats.maxhp) |
339 | { |
318 | { |
340 | |
319 | |
… | |
… | |
378 | } |
357 | } |
379 | |
358 | |
380 | /* this should probably get modified by many more values. |
359 | /* this should probably get modified by many more values. |
381 | * (eg, creatures resistance to fear, level, etc. ) |
360 | * (eg, creatures resistance to fear, level, etc. ) |
382 | */ |
361 | */ |
383 | if (QUERY_FLAG (op, FLAG_SCARED) && !(RANDOM () % 20)) |
362 | if (QUERY_FLAG (op, FLAG_SCARED) && !(rndm (20))) |
384 | { |
363 | { |
385 | CLEAR_FLAG (op, FLAG_SCARED); /* Time to regain some "guts"... */ |
364 | CLEAR_FLAG (op, FLAG_SCARED); /* Time to regain some "guts"... */ |
386 | } |
365 | } |
387 | |
366 | |
388 | if (INVOKE_OBJECT (MONSTER_MOVE, op, ARG_OBJECT (op->enemy))) |
367 | if (INVOKE_OBJECT (MONSTER_MOVE, op, ARG_OBJECT (op->enemy))) |
… | |
… | |
408 | /* If we don't have an enemy, do special movement or the like */ |
387 | /* If we don't have an enemy, do special movement or the like */ |
409 | if (!enemy) |
388 | if (!enemy) |
410 | { |
389 | { |
411 | if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) |
390 | if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) |
412 | { |
391 | { |
413 | remove_ob (op); |
392 | op->destroy (); |
414 | free_object (op); |
|
|
415 | return 1; |
393 | return 1; |
416 | } |
394 | } |
417 | |
395 | |
418 | /* Probably really a bug for a creature to have both |
396 | /* Probably really a bug for a creature to have both |
419 | * stand still and a movement type set. |
397 | * stand still and a movement type set. |
… | |
… | |
468 | } /* stand still */ |
446 | } /* stand still */ |
469 | return 0; |
447 | return 0; |
470 | } /* no enemy */ |
448 | } /* no enemy */ |
471 | |
449 | |
472 | /* We have an enemy. Block immediately below is for pets */ |
450 | /* We have an enemy. Block immediately below is for pets */ |
473 | if ((op->attack_movement & HI4) == PETMOVE && (owner = get_owner (op)) != NULL && !on_same_map (op, owner)) |
451 | if ((op->attack_movement & HI4) == PETMOVE && (owner = op->owner) != NULL && !on_same_map (op, owner)) |
474 | return follow_owner (op, owner); |
452 | return follow_owner (op, owner); |
475 | |
453 | |
476 | /* doppleganger code to change monster facing to that of the nearest |
454 | /* doppleganger code to change monster facing to that of the nearest |
477 | * player. Hmm. The code is here, but no monster in the current |
455 | * player. Hmm. The code is here, but no monster in the current |
478 | * arch set uses it. |
456 | * arch set uses it. |
… | |
… | |
508 | * but that we test above... so can be old code here |
486 | * but that we test above... so can be old code here |
509 | */ |
487 | */ |
510 | if (QUERY_FLAG (op, FLAG_RUN_AWAY)) |
488 | if (QUERY_FLAG (op, FLAG_RUN_AWAY)) |
511 | dir = absdir (dir + 4); |
489 | dir = absdir (dir + 4); |
512 | if (QUERY_FLAG (op, FLAG_CONFUSED)) |
490 | if (QUERY_FLAG (op, FLAG_CONFUSED)) |
513 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
491 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
514 | |
492 | |
515 | if (QUERY_FLAG (op, FLAG_CAST_SPELL) && !(RANDOM () % 3)) |
493 | if (QUERY_FLAG (op, FLAG_CAST_SPELL) && !(rndm (3))) |
516 | { |
494 | { |
517 | if (monster_cast_spell (op, part, enemy, dir, &rv1)) |
495 | if (monster_cast_spell (op, part, enemy, dir, &rv1)) |
518 | return 0; |
496 | return 0; |
519 | } |
497 | } |
520 | |
498 | |
521 | if (QUERY_FLAG (op, FLAG_READY_SCROLL) && !(RANDOM () % 3)) |
499 | if (QUERY_FLAG (op, FLAG_READY_SCROLL) && !(rndm (3))) |
522 | { |
500 | { |
523 | if (monster_use_scroll (op, part, enemy, dir, &rv1)) |
501 | if (monster_use_scroll (op, part, enemy, dir, &rv1)) |
524 | return 0; |
502 | return 0; |
525 | } |
503 | } |
526 | |
504 | |
527 | if (QUERY_FLAG (op, FLAG_READY_RANGE) && !(RANDOM () % 3)) |
505 | if (QUERY_FLAG (op, FLAG_READY_RANGE) && !(rndm (3))) |
528 | { |
506 | { |
529 | if (monster_use_range (op, part, enemy, dir)) |
507 | if (monster_use_range (op, part, enemy, dir)) |
530 | return 0; |
508 | return 0; |
531 | } |
509 | } |
532 | if (QUERY_FLAG (op, FLAG_READY_SKILL) && !(RANDOM () % 3)) |
510 | if (QUERY_FLAG (op, FLAG_READY_SKILL) && !(rndm (3))) |
533 | { |
511 | { |
534 | if (monster_use_skill (op, rv.part, enemy, rv.direction)) |
512 | if (monster_use_skill (op, rv.part, enemy, rv.direction)) |
535 | return 0; |
513 | return 0; |
536 | } |
514 | } |
537 | if (QUERY_FLAG (op, FLAG_READY_BOW) && !(RANDOM () % 2)) |
515 | if (QUERY_FLAG (op, FLAG_READY_BOW) && !(rndm (2))) |
538 | { |
516 | { |
539 | if (monster_use_bow (op, part, enemy, dir)) |
517 | if (monster_use_bow (op, part, enemy, dir)) |
540 | return 0; |
518 | return 0; |
541 | } |
519 | } |
542 | } /* for processing of all parts */ |
520 | } /* for processing of all parts */ |
… | |
… | |
548 | |
526 | |
549 | if (QUERY_FLAG (op, FLAG_SCARED) || QUERY_FLAG (op, FLAG_RUN_AWAY)) |
527 | if (QUERY_FLAG (op, FLAG_SCARED) || QUERY_FLAG (op, FLAG_RUN_AWAY)) |
550 | dir = absdir (dir + 4); |
528 | dir = absdir (dir + 4); |
551 | |
529 | |
552 | if (QUERY_FLAG (op, FLAG_CONFUSED)) |
530 | if (QUERY_FLAG (op, FLAG_CONFUSED)) |
553 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
531 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
554 | |
532 | |
555 | pre_att_dir = dir; /* remember the original direction */ |
533 | pre_att_dir = dir; /* remember the original direction */ |
556 | |
534 | |
557 | if ((op->attack_movement & LO4) && !QUERY_FLAG (op, FLAG_SCARED)) |
535 | if ((op->attack_movement & LO4) && !QUERY_FLAG (op, FLAG_SCARED)) |
558 | { |
536 | { |
… | |
… | |
677 | if (QUERY_FLAG (part, FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */ |
655 | if (QUERY_FLAG (part, FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */ |
678 | return 1; |
656 | return 1; |
679 | |
657 | |
680 | if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) |
658 | if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) |
681 | { |
659 | { |
682 | remove_ob (op); |
660 | op->remove (); |
683 | free_object (op); |
661 | op->destroy (); |
684 | return 1; |
662 | return 1; |
685 | } |
663 | } |
686 | return 0; |
664 | return 0; |
687 | } |
665 | } |
688 | |
666 | |
… | |
… | |
690 | can_hit (object *ob1, object *ob2, rv_vector * rv) |
668 | can_hit (object *ob1, object *ob2, rv_vector * rv) |
691 | { |
669 | { |
692 | object *more; |
670 | object *more; |
693 | rv_vector rv1; |
671 | rv_vector rv1; |
694 | |
672 | |
695 | if (QUERY_FLAG (ob1, FLAG_CONFUSED) && !(RANDOM () % 3)) |
673 | if (QUERY_FLAG (ob1, FLAG_CONFUSED) && !(rndm (3))) |
696 | return 0; |
674 | return 0; |
697 | |
675 | |
698 | if (abs (rv->distance_x) < 2 && abs (rv->distance_y) < 2) |
676 | if (abs (rv->distance_x) < 2 && abs (rv->distance_y) < 2) |
699 | return 1; |
677 | return 1; |
700 | |
678 | |
… | |
… | |
799 | * other monsters) |
777 | * other monsters) |
800 | */ |
778 | */ |
801 | if (!(dir = path_to_player (part, pl, 0))) |
779 | if (!(dir = path_to_player (part, pl, 0))) |
802 | return 0; |
780 | return 0; |
803 | |
781 | |
804 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
782 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
805 | { |
783 | { |
806 | get_rangevector (head, owner, &rv1, 0x1); |
784 | get_rangevector (head, owner, &rv1, 0x1); |
807 | if (dirdiff (dir, rv1.direction) < 2) |
785 | if (dirdiff (dir, rv1.direction) < 2) |
808 | { |
786 | { |
809 | return 0; /* Might hit owner with spell */ |
787 | return 0; /* Might hit owner with spell */ |
810 | } |
788 | } |
811 | } |
789 | } |
812 | |
790 | |
813 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
791 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
814 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
792 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
815 | |
793 | |
816 | /* If the monster hasn't already chosen a spell, choose one |
794 | /* If the monster hasn't already chosen a spell, choose one |
817 | * I'm not sure if it really make sense to pre-select spells (events |
795 | * I'm not sure if it really make sense to pre-select spells (events |
818 | * could be different by the time the monster goes again). |
796 | * could be different by the time the monster goes again). |
819 | */ |
797 | */ |
… | |
… | |
876 | * other monsters) |
854 | * other monsters) |
877 | */ |
855 | */ |
878 | if (!(dir = path_to_player (part, pl, 0))) |
856 | if (!(dir = path_to_player (part, pl, 0))) |
879 | return 0; |
857 | return 0; |
880 | |
858 | |
881 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
859 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
882 | { |
860 | { |
883 | get_rangevector (head, owner, &rv1, 0x1); |
861 | get_rangevector (head, owner, &rv1, 0x1); |
884 | if (dirdiff (dir, rv1.direction) < 2) |
862 | if (dirdiff (dir, rv1.direction) < 2) |
885 | { |
863 | { |
886 | return 0; /* Might hit owner with spell */ |
864 | return 0; /* Might hit owner with spell */ |
887 | } |
865 | } |
888 | } |
866 | } |
889 | |
867 | |
890 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
868 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
891 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
869 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
892 | |
870 | |
893 | for (scroll = head->inv; scroll; scroll = scroll->below) |
871 | for (scroll = head->inv; scroll; scroll = scroll->below) |
894 | if (scroll->type == SCROLL && monster_should_cast_spell (head, scroll->inv)) |
872 | if (scroll->type == SCROLL && monster_should_cast_spell (head, scroll->inv)) |
895 | break; |
873 | break; |
896 | |
874 | |
… | |
… | |
927 | object *skill, *owner; |
905 | object *skill, *owner; |
928 | |
906 | |
929 | if (!(dir = path_to_player (part, pl, 0))) |
907 | if (!(dir = path_to_player (part, pl, 0))) |
930 | return 0; |
908 | return 0; |
931 | |
909 | |
932 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
910 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
933 | { |
911 | { |
934 | int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); |
912 | int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); |
935 | |
913 | |
936 | if (dirdiff (dir, dir2) < 1) |
914 | if (dirdiff (dir, dir2) < 1) |
937 | return 0; /* Might hit owner with skill -thrown rocks for example ? */ |
915 | return 0; /* Might hit owner with skill -thrown rocks for example ? */ |
938 | } |
916 | } |
939 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
917 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
940 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
918 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
941 | |
919 | |
942 | /* skill selection - monster will use the next unused skill. |
920 | /* skill selection - monster will use the next unused skill. |
943 | * well...the following scenario will allow the monster to |
921 | * well...the following scenario will allow the monster to |
944 | * toggle between 2 skills. One day it would be nice to make |
922 | * toggle between 2 skills. One day it would be nice to make |
945 | * more skills available to monsters. |
923 | * more skills available to monsters. |
… | |
… | |
971 | int at_least_one = 0; |
949 | int at_least_one = 0; |
972 | |
950 | |
973 | if (!(dir = path_to_player (part, pl, 0))) |
951 | if (!(dir = path_to_player (part, pl, 0))) |
974 | return 0; |
952 | return 0; |
975 | |
953 | |
976 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
954 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
977 | { |
955 | { |
978 | int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); |
956 | int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); |
979 | |
957 | |
980 | if (dirdiff (dir, dir2) < 2) |
958 | if (dirdiff (dir, dir2) < 2) |
981 | return 0; /* Might hit owner with spell */ |
959 | return 0; /* Might hit owner with spell */ |
982 | } |
960 | } |
983 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
961 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
984 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
962 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
985 | |
963 | |
986 | for (wand = head->inv; wand != NULL; wand = wand->below) |
964 | for (wand = head->inv; wand != NULL; wand = wand->below) |
987 | { |
965 | { |
988 | if (wand->type == WAND) |
966 | if (wand->type == WAND) |
989 | { |
967 | { |
… | |
… | |
998 | { |
976 | { |
999 | if (wand->arch) |
977 | if (wand->arch) |
1000 | { |
978 | { |
1001 | CLEAR_FLAG (wand, FLAG_ANIMATE); |
979 | CLEAR_FLAG (wand, FLAG_ANIMATE); |
1002 | wand->face = wand->arch->clone.face; |
980 | wand->face = wand->arch->clone.face; |
1003 | wand->speed = 0; |
981 | wand->set_speed (0); |
1004 | update_ob_speed (wand); |
|
|
1005 | } |
982 | } |
1006 | } |
983 | } |
1007 | /* Success */ |
984 | /* Success */ |
1008 | return 1; |
985 | return 1; |
1009 | } |
986 | } |
… | |
… | |
1040 | object *owner; |
1017 | object *owner; |
1041 | |
1018 | |
1042 | if (!(dir = path_to_player (part, pl, 0))) |
1019 | if (!(dir = path_to_player (part, pl, 0))) |
1043 | return 0; |
1020 | return 0; |
1044 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
1021 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
1045 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
1022 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
1046 | |
1023 | |
1047 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
1024 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
1048 | { |
1025 | { |
1049 | int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); |
1026 | int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); |
1050 | |
1027 | |
1051 | if (dirdiff (dir, dir2) < 1) |
1028 | if (dirdiff (dir, dir2) < 1) |
1052 | return 0; /* Might hit owner with arrow */ |
1029 | return 0; /* Might hit owner with arrow */ |
… | |
… | |
1157 | |
1134 | |
1158 | void |
1135 | void |
1159 | monster_check_pickup (object *monster) |
1136 | monster_check_pickup (object *monster) |
1160 | { |
1137 | { |
1161 | object *tmp, *next; |
1138 | object *tmp, *next; |
1162 | int next_tag; |
|
|
1163 | |
1139 | |
1164 | for (tmp = monster->below; tmp != NULL; tmp = next) |
1140 | for (tmp = monster->below; tmp != NULL; tmp = next) |
1165 | { |
1141 | { |
1166 | next = tmp->below; |
1142 | next = tmp->below; |
1167 | next_tag = next ? next->count : 0; |
|
|
1168 | if (monster_can_pick (monster, tmp)) |
1143 | if (monster_can_pick (monster, tmp)) |
1169 | { |
1144 | { |
1170 | remove_ob (tmp); |
1145 | tmp->remove (); |
1171 | tmp = insert_ob_in_ob (tmp, monster); |
1146 | tmp = insert_ob_in_ob (tmp, monster); |
1172 | (void) monster_check_apply (monster, tmp); |
1147 | (void) monster_check_apply (monster, tmp); |
1173 | } |
1148 | } |
1174 | /* We could try to re-establish the cycling, of the space, but probably |
1149 | /* We could try to re-establish the cycling, of the space, but probably |
1175 | * not a big deal to just bail out. |
1150 | * not a big deal to just bail out. |
1176 | */ |
1151 | */ |
1177 | if (next && was_destroyed (next, next_tag)) |
1152 | if (next && next->destroyed ()) |
1178 | return; |
1153 | return; |
1179 | } |
1154 | } |
1180 | } |
1155 | } |
1181 | |
1156 | |
1182 | /* |
1157 | /* |
… | |
… | |
1365 | /* Don't use it right now */ |
1340 | /* Don't use it right now */ |
1366 | return; |
1341 | return; |
1367 | } |
1342 | } |
1368 | else if (item->type == WEAPON) |
1343 | else if (item->type == WEAPON) |
1369 | flag = check_good_weapon (mon, item); |
1344 | flag = check_good_weapon (mon, item); |
1370 | else if (IS_ARMOR (item)) |
1345 | else if (item->is_armor ()) |
1371 | flag = check_good_armour (mon, item); |
1346 | flag = check_good_armour (mon, item); |
1372 | /* Should do something more, like make sure this is a better item */ |
1347 | /* Should do something more, like make sure this is a better item */ |
1373 | else if (item->type == RING) |
1348 | else if (item->type == RING) |
1374 | flag = 1; |
1349 | flag = 1; |
1375 | else if (item->type == WAND || item->type == ROD || item->type == HORN) |
1350 | else if (item->type == WAND || item->type == ROD || item->type == HORN) |
… | |
… | |
1433 | npc_call_help (object *op) |
1408 | npc_call_help (object *op) |
1434 | { |
1409 | { |
1435 | int x, y, mflags; |
1410 | int x, y, mflags; |
1436 | object *npc; |
1411 | object *npc; |
1437 | sint16 sx, sy; |
1412 | sint16 sx, sy; |
1438 | mapstruct *m; |
1413 | maptile *m; |
1439 | |
1414 | |
1440 | for (x = -3; x < 4; x++) |
1415 | for (x = -3; x < 4; x++) |
1441 | for (y = -3; y < 4; y++) |
1416 | for (y = -3; y < 4; y++) |
1442 | { |
1417 | { |
1443 | m = op->map; |
1418 | m = op->map; |
… | |
… | |
1446 | mflags = get_map_flags (m, &m, sx, sy, &sx, &sy); |
1421 | mflags = get_map_flags (m, &m, sx, sy, &sx, &sy); |
1447 | /* If nothing alive on this space, no need to search the space. */ |
1422 | /* If nothing alive on this space, no need to search the space. */ |
1448 | if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE)) |
1423 | if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE)) |
1449 | continue; |
1424 | continue; |
1450 | |
1425 | |
1451 | for (npc = get_map_ob (m, sx, sy); npc != NULL; npc = npc->above) |
1426 | for (npc = GET_MAP_OB (m, sx, sy); npc != NULL; npc = npc->above) |
1452 | if (QUERY_FLAG (npc, FLAG_ALIVE) && QUERY_FLAG (npc, FLAG_UNAGGRESSIVE)) |
1427 | if (QUERY_FLAG (npc, FLAG_ALIVE) && QUERY_FLAG (npc, FLAG_UNAGGRESSIVE)) |
1453 | npc->enemy = op->enemy; |
1428 | npc->enemy = op->enemy; |
1454 | } |
1429 | } |
1455 | } |
1430 | } |
1456 | |
1431 | |
… | |
… | |
1542 | { |
1517 | { |
1543 | static int circle[12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 }; |
1518 | static int circle[12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 }; |
1544 | if (++ob->move_status > 11) |
1519 | if (++ob->move_status > 11) |
1545 | ob->move_status = 0; |
1520 | ob->move_status = 0; |
1546 | if (!(move_object (ob, circle[ob->move_status]))) |
1521 | if (!(move_object (ob, circle[ob->move_status]))) |
1547 | (void) move_object (ob, RANDOM () % 8 + 1); |
1522 | (void) move_object (ob, rndm (8) + 1); |
1548 | } |
1523 | } |
1549 | |
1524 | |
1550 | void |
1525 | void |
1551 | circ2_move (object *ob) |
1526 | circ2_move (object *ob) |
1552 | { |
1527 | { |
1553 | static int circle[20] = { 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2 }; |
1528 | static int circle[20] = { 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2 }; |
1554 | if (++ob->move_status > 19) |
1529 | if (++ob->move_status > 19) |
1555 | ob->move_status = 0; |
1530 | ob->move_status = 0; |
1556 | if (!(move_object (ob, circle[ob->move_status]))) |
1531 | if (!(move_object (ob, circle[ob->move_status]))) |
1557 | (void) move_object (ob, RANDOM () % 8 + 1); |
1532 | (void) move_object (ob, rndm (8) + 1); |
1558 | } |
1533 | } |
1559 | |
1534 | |
1560 | void |
1535 | void |
1561 | pace_movev (object *ob) |
1536 | pace_movev (object *ob) |
1562 | { |
1537 | { |
… | |
… | |
1612 | void |
1587 | void |
1613 | rand_move (object *ob) |
1588 | rand_move (object *ob) |
1614 | { |
1589 | { |
1615 | int i; |
1590 | int i; |
1616 | |
1591 | |
1617 | if (ob->move_status < 1 || ob->move_status > 8 || !(move_object (ob, ob->move_status || !(RANDOM () % 9)))) |
1592 | if (ob->move_status < 1 || ob->move_status > 8 || !(move_object (ob, ob->move_status || !(rndm (9))))) |
1618 | for (i = 0; i < 5; i++) |
1593 | for (i = 0; i < 5; i++) |
1619 | if (move_object (ob, ob->move_status = RANDOM () % 8 + 1)) |
1594 | if (move_object (ob, ob->move_status = rndm (8) + 1)) |
1620 | return; |
1595 | return; |
1621 | } |
1596 | } |
1622 | |
1597 | |
1623 | void |
1598 | void |
1624 | check_earthwalls (object *op, mapstruct *m, int x, int y) |
1599 | check_earthwalls (object *op, maptile *m, int x, int y) |
1625 | { |
1600 | { |
1626 | object *tmp; |
1601 | object *tmp; |
1627 | |
1602 | |
1628 | for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) |
1603 | for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) |
1629 | { |
1604 | { |
1630 | if (tmp->type == EARTHWALL) |
1605 | if (tmp->type == EARTHWALL) |
1631 | { |
1606 | { |
1632 | hit_player (tmp, op->stats.dam, op, AT_PHYSICAL, 1); |
1607 | hit_player (tmp, op->stats.dam, op, AT_PHYSICAL, 1); |
1633 | return; |
1608 | return; |
1634 | } |
1609 | } |
1635 | } |
1610 | } |
1636 | } |
1611 | } |
1637 | |
1612 | |
1638 | void |
1613 | void |
1639 | check_doors (object *op, mapstruct *m, int x, int y) |
1614 | check_doors (object *op, maptile *m, int x, int y) |
1640 | { |
1615 | { |
1641 | object *tmp; |
1616 | object *tmp; |
1642 | |
1617 | |
1643 | for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) |
1618 | for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) |
1644 | { |
1619 | { |
1645 | if (tmp->type == DOOR) |
1620 | if (tmp->type == DOOR) |
1646 | { |
1621 | { |
1647 | hit_player (tmp, 1000, op, AT_PHYSICAL, 1); |
1622 | hit_player (tmp, 1000, op, AT_PHYSICAL, 1); |
1648 | return; |
1623 | return; |
… | |
… | |
1669 | tmp = op; |
1644 | tmp = op; |
1670 | |
1645 | |
1671 | /* New throw code: look through the inventory. Grap the first legal is_thrown |
1646 | /* New throw code: look through the inventory. Grap the first legal is_thrown |
1672 | * marked item and throw it to the enemy. |
1647 | * marked item and throw it to the enemy. |
1673 | */ |
1648 | */ |
1674 | |
|
|
1675 | for (tmp = op->inv; tmp; tmp = tmp->below) |
1649 | for (tmp = op->inv; tmp; tmp = tmp->below) |
1676 | { |
1650 | { |
1677 | |
|
|
1678 | /* Can't throw invisible objects or items that are applied */ |
1651 | /* Can't throw invisible objects or items that are applied */ |
1679 | if (tmp->invisible || QUERY_FLAG (tmp, FLAG_APPLIED)) |
1652 | if (tmp->invisible || QUERY_FLAG (tmp, FLAG_APPLIED)) |
1680 | continue; |
1653 | continue; |
1681 | |
1654 | |
1682 | if (QUERY_FLAG (tmp, FLAG_IS_THROWN)) |
1655 | if (QUERY_FLAG (tmp, FLAG_IS_THROWN)) |
… | |
… | |
1805 | /* ah, we are within range, detected? take cases */ |
1778 | /* ah, we are within range, detected? take cases */ |
1806 | if (!enemy->invisible) /* enemy in dark squares... are seen! */ |
1779 | if (!enemy->invisible) /* enemy in dark squares... are seen! */ |
1807 | return 1; |
1780 | return 1; |
1808 | |
1781 | |
1809 | /* hidden or low-quality invisible */ |
1782 | /* hidden or low-quality invisible */ |
1810 | if (enemy->hide && (rv->distance <= 1) && (RANDOM () % 100 <= hide_discovery)) |
1783 | if (enemy->hide && (rv->distance <= 1) && (rndm (100) <= hide_discovery)) |
1811 | { |
1784 | { |
1812 | make_visible (enemy); |
1785 | make_visible (enemy); |
1813 | /* inform players of new status */ |
1786 | /* inform players of new status */ |
1814 | if (enemy->type == PLAYER && player_can_view (enemy, op)) |
1787 | if (enemy->type == PLAYER && player_can_view (enemy, op)) |
1815 | new_draw_info_format (NDI_UNIQUE, 0, enemy, "You are discovered by %s!", &op->name); |
1788 | new_draw_info_format (NDI_UNIQUE, 0, enemy, "You are discovered by %s!", &op->name); |
… | |
… | |
1822 | * do something to you. Decreasing the duration of invisible |
1795 | * do something to you. Decreasing the duration of invisible |
1823 | * doesn't make a lot of sense IMO, as a bunch of stupid creatures |
1796 | * doesn't make a lot of sense IMO, as a bunch of stupid creatures |
1824 | * can then basically negate the spell. The spell isn't negated - |
1797 | * can then basically negate the spell. The spell isn't negated - |
1825 | * they just know where you are! |
1798 | * they just know where you are! |
1826 | */ |
1799 | */ |
1827 | if ((RANDOM () % 50) <= hide_discovery) |
1800 | if ((rndm (50)) <= hide_discovery) |
1828 | { |
1801 | { |
1829 | if (enemy->type == PLAYER) |
1802 | if (enemy->type == PLAYER) |
1830 | { |
1803 | { |
1831 | new_draw_info_format (NDI_UNIQUE, 0, enemy, "You see %s noticing your position.", query_name (op)); |
1804 | new_draw_info_format (NDI_UNIQUE, 0, enemy, "You see %s noticing your position.", query_name (op)); |
1832 | } |
1805 | } |
… | |
… | |
1847 | |
1820 | |
1848 | int |
1821 | int |
1849 | stand_in_light (object *op) |
1822 | stand_in_light (object *op) |
1850 | { |
1823 | { |
1851 | sint16 nx, ny; |
1824 | sint16 nx, ny; |
1852 | mapstruct *m; |
1825 | maptile *m; |
1853 | |
1826 | |
1854 | |
1827 | |
1855 | if (!op) |
1828 | if (!op) |
1856 | return 0; |
1829 | return 0; |
1857 | if (op->glow_radius > 0) |
1830 | if (op->glow_radius > 0) |