1 | /* |
1 | /* |
2 | CrossFire, A Multiplayer game for X-windows |
2 | CrossFire, A Multiplayer game for X-windows |
3 | |
3 | |
|
|
4 | Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team |
4 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
5 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
5 | Copyright (C) 1992 Frank Tore Johansen |
6 | Copyright (C) 1992 Frank Tore Johansen |
6 | |
7 | |
7 | This program is free software; you can redistribute it and/or modify |
8 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | it under the terms of the GNU General Public License as published by |
… | |
… | |
20 | |
21 | |
21 | The authors can be reached via e-mail at <crossfire@schmorp.de> |
22 | The authors can be reached via e-mail at <crossfire@schmorp.de> |
22 | */ |
23 | */ |
23 | |
24 | |
24 | #include <global.h> |
25 | #include <global.h> |
25 | #ifndef __CEXTRACT__ |
|
|
26 | # include <sproto.h> |
26 | #include <sproto.h> |
27 | # include <spells.h> |
27 | #include <spells.h> |
28 | # include <skills.h> |
28 | #include <skills.h> |
29 | #endif |
|
|
30 | |
|
|
31 | |
29 | |
32 | #define MIN_MON_RADIUS 3 /* minimum monster detection radius */ |
30 | #define MIN_MON_RADIUS 3 /* minimum monster detection radius */ |
33 | |
|
|
34 | |
31 | |
35 | /* checks npc->enemy and returns that enemy if still valid, |
32 | /* checks npc->enemy and returns that enemy if still valid, |
36 | * NULL otherwise. |
33 | * NULL otherwise. |
37 | * this is map tile aware. |
34 | * this is map tile aware. |
38 | * 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 |
… | |
… | |
116 | find_nearest_living_creature (object *npc) |
113 | find_nearest_living_creature (object *npc) |
117 | { |
114 | { |
118 | int i, mflags; |
115 | int i, mflags; |
119 | sint16 nx, ny; |
116 | sint16 nx, ny; |
120 | maptile *m; |
117 | maptile *m; |
121 | object *tmp; |
|
|
122 | int search_arr[SIZEOFFREE]; |
118 | int search_arr[SIZEOFFREE]; |
123 | |
119 | |
124 | get_search_arr (search_arr); |
120 | get_search_arr (search_arr); |
|
|
121 | |
125 | for (i = 0; i < SIZEOFFREE; i++) |
122 | for (i = 0; i < SIZEOFFREE; i++) |
126 | { |
123 | { |
127 | /* modified to implement smart searching using search_arr |
124 | /* modified to implement smart searching using search_arr |
128 | * guidance array to determine direction of search order |
125 | * guidance array to determine direction of search order |
129 | */ |
126 | */ |
130 | nx = npc->x + freearr_x[search_arr[i]]; |
127 | nx = npc->x + freearr_x[search_arr[i]]; |
131 | ny = npc->y + freearr_y[search_arr[i]]; |
128 | ny = npc->y + freearr_y[search_arr[i]]; |
132 | m = npc->map; |
129 | m = npc->map; |
133 | |
130 | |
134 | mflags = get_map_flags (m, &m, nx, ny, &nx, &ny); |
131 | mflags = get_map_flags (m, &m, nx, ny, &nx, &ny); |
|
|
132 | |
135 | if (mflags & P_OUT_OF_MAP) |
133 | if (mflags & P_OUT_OF_MAP) |
136 | continue; |
134 | continue; |
137 | |
135 | |
138 | if (mflags & P_IS_ALIVE) |
136 | if (mflags & P_IS_ALIVE) |
139 | { |
137 | { |
140 | tmp = get_map_ob (m, nx, ny); |
138 | for (object *tmp = m->at (nx, ny).top; tmp; tmp = tmp->below) |
141 | 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) |
142 | tmp = tmp->above; |
|
|
143 | |
|
|
144 | if (!tmp) |
|
|
145 | { |
|
|
146 | LOG (llevDebug, "find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n", |
|
|
147 | m->path, nx, ny); |
|
|
148 | } |
|
|
149 | else |
|
|
150 | { |
|
|
151 | if (can_see_monsterP (m, nx, ny, i)) |
140 | if (can_see_monsterP (m, nx, ny, i)) |
152 | return tmp; |
141 | return tmp; |
153 | } |
142 | } |
154 | } /* is something living on this space */ |
|
|
155 | } |
143 | } |
156 | return NULL; /* nothing found */ |
144 | |
|
|
145 | return 0; |
157 | } |
146 | } |
158 | |
147 | |
159 | |
148 | |
160 | /* 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 |
161 | * our caller will find the information useful. |
150 | * our caller will find the information useful. |
… | |
… | |
398 | /* 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 */ |
399 | if (!enemy) |
388 | if (!enemy) |
400 | { |
389 | { |
401 | if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) |
390 | if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) |
402 | { |
391 | { |
403 | op->remove (); |
|
|
404 | op->destroy (0); |
392 | op->destroy (); |
405 | return 1; |
393 | return 1; |
406 | } |
394 | } |
407 | |
395 | |
408 | /* Probably really a bug for a creature to have both |
396 | /* Probably really a bug for a creature to have both |
409 | * stand still and a movement type set. |
397 | * stand still and a movement type set. |
… | |
… | |
458 | } /* stand still */ |
446 | } /* stand still */ |
459 | return 0; |
447 | return 0; |
460 | } /* no enemy */ |
448 | } /* no enemy */ |
461 | |
449 | |
462 | /* We have an enemy. Block immediately below is for pets */ |
450 | /* We have an enemy. Block immediately below is for pets */ |
463 | 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)) |
464 | return follow_owner (op, owner); |
452 | return follow_owner (op, owner); |
465 | |
453 | |
466 | /* doppleganger code to change monster facing to that of the nearest |
454 | /* doppleganger code to change monster facing to that of the nearest |
467 | * 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 |
468 | * arch set uses it. |
456 | * arch set uses it. |
… | |
… | |
668 | return 1; |
656 | return 1; |
669 | |
657 | |
670 | if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) |
658 | if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) |
671 | { |
659 | { |
672 | op->remove (); |
660 | op->remove (); |
673 | op->destroy (0); |
661 | op->destroy (); |
674 | return 1; |
662 | return 1; |
675 | } |
663 | } |
676 | return 0; |
664 | return 0; |
677 | } |
665 | } |
678 | |
666 | |
… | |
… | |
789 | * other monsters) |
777 | * other monsters) |
790 | */ |
778 | */ |
791 | if (!(dir = path_to_player (part, pl, 0))) |
779 | if (!(dir = path_to_player (part, pl, 0))) |
792 | return 0; |
780 | return 0; |
793 | |
781 | |
794 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
782 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
795 | { |
783 | { |
796 | get_rangevector (head, owner, &rv1, 0x1); |
784 | get_rangevector (head, owner, &rv1, 0x1); |
797 | if (dirdiff (dir, rv1.direction) < 2) |
785 | if (dirdiff (dir, rv1.direction) < 2) |
798 | { |
786 | { |
799 | return 0; /* Might hit owner with spell */ |
787 | return 0; /* Might hit owner with spell */ |
… | |
… | |
866 | * other monsters) |
854 | * other monsters) |
867 | */ |
855 | */ |
868 | if (!(dir = path_to_player (part, pl, 0))) |
856 | if (!(dir = path_to_player (part, pl, 0))) |
869 | return 0; |
857 | return 0; |
870 | |
858 | |
871 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
859 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
872 | { |
860 | { |
873 | get_rangevector (head, owner, &rv1, 0x1); |
861 | get_rangevector (head, owner, &rv1, 0x1); |
874 | if (dirdiff (dir, rv1.direction) < 2) |
862 | if (dirdiff (dir, rv1.direction) < 2) |
875 | { |
863 | { |
876 | return 0; /* Might hit owner with spell */ |
864 | return 0; /* Might hit owner with spell */ |
… | |
… | |
917 | object *skill, *owner; |
905 | object *skill, *owner; |
918 | |
906 | |
919 | if (!(dir = path_to_player (part, pl, 0))) |
907 | if (!(dir = path_to_player (part, pl, 0))) |
920 | return 0; |
908 | return 0; |
921 | |
909 | |
922 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
910 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
923 | { |
911 | { |
924 | 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); |
925 | |
913 | |
926 | if (dirdiff (dir, dir2) < 1) |
914 | if (dirdiff (dir, dir2) < 1) |
927 | return 0; /* Might hit owner with skill -thrown rocks for example ? */ |
915 | return 0; /* Might hit owner with skill -thrown rocks for example ? */ |
… | |
… | |
961 | int at_least_one = 0; |
949 | int at_least_one = 0; |
962 | |
950 | |
963 | if (!(dir = path_to_player (part, pl, 0))) |
951 | if (!(dir = path_to_player (part, pl, 0))) |
964 | return 0; |
952 | return 0; |
965 | |
953 | |
966 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
954 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
967 | { |
955 | { |
968 | 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); |
969 | |
957 | |
970 | if (dirdiff (dir, dir2) < 2) |
958 | if (dirdiff (dir, dir2) < 2) |
971 | return 0; /* Might hit owner with spell */ |
959 | return 0; /* Might hit owner with spell */ |
… | |
… | |
988 | { |
976 | { |
989 | if (wand->arch) |
977 | if (wand->arch) |
990 | { |
978 | { |
991 | CLEAR_FLAG (wand, FLAG_ANIMATE); |
979 | CLEAR_FLAG (wand, FLAG_ANIMATE); |
992 | wand->face = wand->arch->clone.face; |
980 | wand->face = wand->arch->clone.face; |
993 | wand->speed = 0; |
981 | wand->set_speed (0); |
994 | update_ob_speed (wand); |
|
|
995 | } |
982 | } |
996 | } |
983 | } |
997 | /* Success */ |
984 | /* Success */ |
998 | return 1; |
985 | return 1; |
999 | } |
986 | } |
… | |
… | |
1032 | if (!(dir = path_to_player (part, pl, 0))) |
1019 | if (!(dir = path_to_player (part, pl, 0))) |
1033 | return 0; |
1020 | return 0; |
1034 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
1021 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
1035 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
1022 | dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); |
1036 | |
1023 | |
1037 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) |
1024 | if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL) |
1038 | { |
1025 | { |
1039 | 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); |
1040 | |
1027 | |
1041 | if (dirdiff (dir, dir2) < 1) |
1028 | if (dirdiff (dir, dir2) < 1) |
1042 | return 0; /* Might hit owner with arrow */ |
1029 | return 0; /* Might hit owner with arrow */ |
… | |
… | |
1353 | /* Don't use it right now */ |
1340 | /* Don't use it right now */ |
1354 | return; |
1341 | return; |
1355 | } |
1342 | } |
1356 | else if (item->type == WEAPON) |
1343 | else if (item->type == WEAPON) |
1357 | flag = check_good_weapon (mon, item); |
1344 | flag = check_good_weapon (mon, item); |
1358 | else if (IS_ARMOR (item)) |
1345 | else if (item->is_armor ()) |
1359 | flag = check_good_armour (mon, item); |
1346 | flag = check_good_armour (mon, item); |
1360 | /* 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 */ |
1361 | else if (item->type == RING) |
1348 | else if (item->type == RING) |
1362 | flag = 1; |
1349 | flag = 1; |
1363 | else if (item->type == WAND || item->type == ROD || item->type == HORN) |
1350 | else if (item->type == WAND || item->type == ROD || item->type == HORN) |
… | |
… | |
1434 | mflags = get_map_flags (m, &m, sx, sy, &sx, &sy); |
1421 | mflags = get_map_flags (m, &m, sx, sy, &sx, &sy); |
1435 | /* 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. */ |
1436 | if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE)) |
1423 | if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE)) |
1437 | continue; |
1424 | continue; |
1438 | |
1425 | |
1439 | 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) |
1440 | if (QUERY_FLAG (npc, FLAG_ALIVE) && QUERY_FLAG (npc, FLAG_UNAGGRESSIVE)) |
1427 | if (QUERY_FLAG (npc, FLAG_ALIVE) && QUERY_FLAG (npc, FLAG_UNAGGRESSIVE)) |
1441 | npc->enemy = op->enemy; |
1428 | npc->enemy = op->enemy; |
1442 | } |
1429 | } |
1443 | } |
1430 | } |
1444 | |
1431 | |
… | |
… | |
1611 | void |
1598 | void |
1612 | check_earthwalls (object *op, maptile *m, int x, int y) |
1599 | check_earthwalls (object *op, maptile *m, int x, int y) |
1613 | { |
1600 | { |
1614 | object *tmp; |
1601 | object *tmp; |
1615 | |
1602 | |
1616 | 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) |
1617 | { |
1604 | { |
1618 | if (tmp->type == EARTHWALL) |
1605 | if (tmp->type == EARTHWALL) |
1619 | { |
1606 | { |
1620 | hit_player (tmp, op->stats.dam, op, AT_PHYSICAL, 1); |
1607 | hit_player (tmp, op->stats.dam, op, AT_PHYSICAL, 1); |
1621 | return; |
1608 | return; |
… | |
… | |
1626 | void |
1613 | void |
1627 | check_doors (object *op, maptile *m, int x, int y) |
1614 | check_doors (object *op, maptile *m, int x, int y) |
1628 | { |
1615 | { |
1629 | object *tmp; |
1616 | object *tmp; |
1630 | |
1617 | |
1631 | 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) |
1632 | { |
1619 | { |
1633 | if (tmp->type == DOOR) |
1620 | if (tmp->type == DOOR) |
1634 | { |
1621 | { |
1635 | hit_player (tmp, 1000, op, AT_PHYSICAL, 1); |
1622 | hit_player (tmp, 1000, op, AT_PHYSICAL, 1); |
1636 | return; |
1623 | return; |