1 | /* |
1 | /* |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
3 | * |
3 | * |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
5 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992 Frank Tore Johansen |
6 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * |
7 | * |
8 | * Deliantra is free software: you can redistribute it and/or modify it under |
8 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * the terms of the Affero GNU General Public License as published by the |
9 | * the terms of the Affero GNU General Public License as published by the |
10 | * Free Software Foundation, either version 3 of the License, or (at your |
10 | * Free Software Foundation, either version 3 of the License, or (at your |
11 | * option) any later version. |
11 | * option) any later version. |
12 | * |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
16 | * GNU General Public License for more details. |
17 | * |
17 | * |
18 | * You should have received a copy of the Affero GNU General Public License |
18 | * You should have received a copy of the Affero GNU General Public License |
19 | * and the GNU General Public License along with this program. If not, see |
19 | * and the GNU General Public License along with this program. If not, see |
20 | * <http://www.gnu.org/licenses/>. |
20 | * <http://www.gnu.org/licenses/>. |
21 | * |
21 | * |
22 | * The authors can be reached via e-mail to <support@deliantra.net> |
22 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | */ |
23 | */ |
24 | |
24 | |
25 | /* |
25 | /* |
26 | * Routines that is executed from objects based on their speed have been |
26 | * Routines that is executed from objects based on their speed have been |
… | |
… | |
28 | */ |
28 | */ |
29 | #include <global.h> |
29 | #include <global.h> |
30 | #include <spells.h> |
30 | #include <spells.h> |
31 | #include <sproto.h> |
31 | #include <sproto.h> |
32 | |
32 | |
33 | /* The following removes doors. The functions check to see if similar |
33 | /* The following removes doors. The functions check to see if similar |
34 | * doors are next to the one that is being removed, and if so, set it |
34 | * doors are next to the one that is being removed, and if so, set it |
35 | * so those will be removed shortly (in a cascade like fashion.) |
35 | * so those will be removed shortly (in a cascade like fashion.) |
36 | */ |
36 | */ |
37 | void |
37 | void |
38 | remove_door (object *op) |
38 | remove_door (object *op) |
… | |
… | |
239 | { /* 1 = going down, 0 = going up */ |
239 | { /* 1 = going down, 0 = going up */ |
240 | object *tmp; |
240 | object *tmp; |
241 | |
241 | |
242 | if (op->stats.wc < 0 || (int) op->stats.wc >= NUM_ANIMATIONS (op)) |
242 | if (op->stats.wc < 0 || (int) op->stats.wc >= NUM_ANIMATIONS (op)) |
243 | { |
243 | { |
244 | LOG (llevError, "Gate error: animation was %d, max=%d\n", op->stats.wc, NUM_ANIMATIONS (op)); |
244 | LOG (llevError, "%s: gate error: animation was %d, max=%d\n", op->debug_desc (), op->stats.wc, NUM_ANIMATIONS (op)); |
245 | op->stats.wc = 0; |
245 | op->stats.wc = 0; |
246 | } |
246 | } |
247 | |
247 | |
248 | /* We're going down */ |
248 | /* We're going down */ |
249 | if (op->value) |
249 | if (op->value) |
… | |
… | |
272 | /* We're going up */ |
272 | /* We're going up */ |
273 | |
273 | |
274 | /* First, lets see if we are already at the top */ |
274 | /* First, lets see if we are already at the top */ |
275 | if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1)) |
275 | if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1)) |
276 | { |
276 | { |
277 | |
|
|
278 | /* Check to make sure that only non pickable and non rollable |
277 | /* Check to make sure that only non pickable and non rollable |
279 | * objects are above the gate. If so, we finish closing the gate, |
278 | * objects are above the gate. If so, we finish closing the gate, |
280 | * otherwise, we fall through to the code below which should lower |
279 | * otherwise, we fall through to the code below which should lower |
281 | * the gate slightly. |
280 | * the gate slightly. |
282 | */ |
281 | */ |
… | |
… | |
502 | move_apply (op, tmp, tmp); |
501 | move_apply (op, tmp, tmp); |
503 | } |
502 | } |
504 | } |
503 | } |
505 | |
504 | |
506 | SET_ANIMATION (op, op->stats.wc); |
505 | SET_ANIMATION (op, op->stats.wc); |
507 | update_object (op, UP_OBJ_FACE); |
506 | update_object (op, UP_OBJ_CHANGE); |
508 | return; |
507 | return; |
509 | } |
508 | } |
510 | |
509 | |
511 | /* We're closing */ |
510 | /* We're closing */ |
512 | op->move_on = 0; |
511 | op->move_on = 0; |
513 | |
512 | |
514 | op->stats.wc++; |
513 | op->stats.wc++; |
515 | if ((int) op->stats.wc >= NUM_ANIMATIONS (op)) |
514 | if (op->stats.wc >= NUM_ANIMATIONS (op)) |
516 | op->stats.wc = NUM_ANIMATIONS (op) - 1; |
515 | op->stats.wc = NUM_ANIMATIONS (op) - 1; |
517 | |
516 | |
518 | SET_ANIMATION (op, op->stats.wc); |
517 | SET_ANIMATION (op, op->stats.wc); |
519 | update_object (op, UP_OBJ_FACE); |
518 | update_object (op, UP_OBJ_CHANGE); |
520 | if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1)) |
519 | if (op->stats.wc == (NUM_ANIMATIONS (op) - 1)) |
521 | op->set_speed (0); /* closed, let's stop */ |
520 | op->set_speed (0); /* closed, let's stop */ |
522 | } |
521 | } |
523 | |
522 | |
524 | |
523 | |
525 | /* stop_item() returns a pointer to the stopped object. The stopped object |
524 | /* stop_item() returns a pointer to the stopped object. The stopped object |
… | |
… | |
610 | op->stats.grace = 0; |
609 | op->stats.grace = 0; |
611 | op->level = 0; |
610 | op->level = 0; |
612 | op->face = op->arch->face; |
611 | op->face = op->arch->face; |
613 | op->owner = 0; |
612 | op->owner = 0; |
614 | |
613 | |
|
|
614 | op->clr_flag (FLAG_NO_PICK); /* fire_bow makes arrows NO_PICK so monsters (or anything else) don't pick them mid-flight */ |
|
|
615 | |
615 | update_object (op, UP_OBJ_CHANGE); |
616 | update_object (op, UP_OBJ_CHANGE); |
616 | |
617 | |
617 | return op; |
618 | return op; |
618 | } |
619 | } |
619 | |
620 | |
… | |
… | |
655 | { |
656 | { |
656 | int was_reflected; |
657 | int was_reflected; |
657 | |
658 | |
658 | if (!op->map) |
659 | if (!op->map) |
659 | { |
660 | { |
660 | LOG (llevError, "BUG: Arrow had no map.\n"); |
661 | LOG (llevError | logBacktrace, "BUG: Arrow %s had no map.\n", op->debug_desc ()); |
661 | op->destroy (); |
662 | op->destroy (); |
662 | return; |
663 | return; |
663 | } |
664 | } |
664 | |
665 | |
665 | /* we need to stop thrown objects at some point. Like here. */ |
666 | /* we need to stop thrown objects at some point. Like here. */ |
… | |
… | |
687 | } |
688 | } |
688 | |
689 | |
689 | /* decrease the speed as it flies. 0.05 means a standard bow will shoot |
690 | /* decrease the speed as it flies. 0.05 means a standard bow will shoot |
690 | * about 17 squares. Tune as needed. |
691 | * about 17 squares. Tune as needed. |
691 | */ |
692 | */ |
692 | op->speed -= 0.05; |
693 | op->set_speed (op->speed - 0.05); |
693 | |
694 | |
694 | /* if the arrow is moving too slow.. stop it. 0.5 was chosen as lower |
695 | /* if the arrow is moving too slow.. stop it. 0.5 was chosen as lower |
695 | values look rediculous. */ |
696 | values look ridiculous. */ |
696 | if (op->speed < (op->type == ARROW ? 0.05 : MIN_ACTIVE_SPEED)) |
697 | if (op->speed < (op->type == ARROW ? 0.5 : MIN_ACTIVE_SPEED)) |
697 | { |
698 | { |
698 | stop_arrow (op); |
699 | stop_arrow (op); |
699 | return; |
700 | return; |
700 | } |
701 | } |
701 | |
702 | |
… | |
… | |
714 | if (pos->flags () & P_IS_ALIVE) |
715 | if (pos->flags () & P_IS_ALIVE) |
715 | { |
716 | { |
716 | object *tmp; |
717 | object *tmp; |
717 | |
718 | |
718 | for (tmp = pos->bot; tmp; tmp = tmp->above) |
719 | for (tmp = pos->bot; tmp; tmp = tmp->above) |
719 | if (tmp->flag [FLAG_ALIVE]) |
720 | if (tmp->flag [FLAG_ALIVE] && tmp != op->owner) |
720 | break; |
721 | { |
721 | |
|
|
722 | /* Not really fair, but don't let monsters hit themselves with |
722 | /* Not really fair, but don't let monsters hit themselves with |
723 | * their own arrow - this can be because they fire it then |
723 | * their own arrow - this can be because they fire it then |
724 | * move into it. |
724 | * move into it. |
725 | */ |
725 | */ |
726 | if (tmp && tmp != op->owner) |
726 | |
727 | { |
|
|
728 | /* Found living object, but it is reflecting the missile. Update |
727 | /* Found living object, but it is reflecting the missile. Update |
729 | * as below. (Note that for living creatures there is a small |
728 | * as below. (Note that for living creatures there is a small |
730 | * chance that reflect_missile fails.) |
729 | * chance that reflect_missile fails.) |
731 | */ |
730 | */ |
732 | if (tmp->flag [FLAG_REFL_MISSILE] && (rndm (0, 99)) < (90 - op->level / 10)) |
731 | if (tmp->flag [FLAG_REFL_MISSILE] && (rndm (0, 99)) < (90 - op->level / 10)) |
733 | { |
732 | { |
734 | int number = op->face; |
|
|
735 | |
|
|
736 | op->direction = absdir (op->direction + 4); |
733 | op->direction = absdir (op->direction + 4); |
737 | update_turn_face (op); |
734 | update_turn_face (op); |
738 | was_reflected = 1; /* skip normal movement calculations */ |
735 | was_reflected = 1; /* skip normal movement calculations */ |
739 | } |
736 | } |
740 | else |
737 | else |
741 | { |
738 | { |
742 | /* Attack the object. */ |
739 | /* Attack the object. */ |
743 | op = hit_with_arrow (op, tmp); |
740 | op = hit_with_arrow (op, tmp); |
744 | |
741 | |
745 | if (!op) |
742 | if (!op) |
746 | return; |
743 | return; |
747 | } |
744 | } |
748 | } /* if this is not hitting its owner */ |
745 | |
749 | } /* if there is something alive on this space */ |
746 | break; |
|
|
747 | } |
|
|
748 | } |
750 | |
749 | |
751 | if (OB_TYPE_MOVE_BLOCK (op, pos->move_block)) |
750 | if (OB_TYPE_MOVE_BLOCK (op, pos->move_block)) |
752 | { |
751 | { |
753 | int retry = 0; |
752 | int retry = 0; |
754 | |
753 | |
… | |
… | |
1004 | } |
1003 | } |
1005 | |
1004 | |
1006 | cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL); |
1005 | cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL); |
1007 | } |
1006 | } |
1008 | |
1007 | |
1009 | /* move_player_mover: this function takes a "player mover" as an |
1008 | /* move_player_mover: this function takes a "player mover" as an |
1010 | * argument, and performs the function of a player mover, which is: |
1009 | * argument, and performs the function of a player mover, which is: |
1011 | * |
1010 | * |
1012 | * a player mover finds any players that are sitting on it. It |
1011 | * a player mover finds any players that are sitting on it. It |
1013 | * moves them in the op->stats.sp direction. speed is how often it'll move. |
1012 | * moves them in the op->stats.sp direction. speed is how often it'll move. |
1014 | * If attacktype is nonzero it will paralyze the player. If lifesave is set, |
1013 | * If attacktype is nonzero it will paralyze the player. If lifesave is set, |
… | |
… | |
1016 | * it'll paralyze the victim for hp*his speed/op->speed |
1015 | * it'll paralyze the victim for hp*his speed/op->speed |
1017 | */ |
1016 | */ |
1018 | static void |
1017 | static void |
1019 | move_player_mover (object *op) |
1018 | move_player_mover (object *op) |
1020 | { |
1019 | { |
1021 | int dir = op->stats.sp; |
1020 | int dir = 0; |
1022 | sint16 nx, ny; |
|
|
1023 | maptile *m; |
|
|
1024 | |
|
|
1025 | /* Determine direction now for random movers so we do the right thing */ |
|
|
1026 | if (!dir) |
|
|
1027 | dir = rndm (1, 8); |
|
|
1028 | |
1021 | |
1029 | for (object *victim = op->ms ().bot; victim; victim = victim->above) |
1022 | for (object *victim = op->ms ().bot; victim; victim = victim->above) |
1030 | { |
1023 | { |
1031 | if (victim->flag [FLAG_ALIVE] && !victim->flag [FLAG_WIZPASS] && |
1024 | if (victim->flag [FLAG_ALIVE] |
|
|
1025 | && !victim->flag [FLAG_WIZPASS] |
1032 | (victim->move_type & op->move_type || !victim->move_type)) |
1026 | && (victim->move_type & op->move_type || !victim->move_type)) |
|
|
1027 | { |
|
|
1028 | if (op->flag [FLAG_LIFESAVE] && op->stats.hp-- < 0) |
1033 | { |
1029 | { |
|
|
1030 | op->destroy (); |
|
|
1031 | return; |
|
|
1032 | } |
|
|
1033 | |
|
|
1034 | /* Determine direction only once so we do the right thing */ |
|
|
1035 | // why is it the right thing, though? |
|
|
1036 | if (!dir) |
|
|
1037 | dir = op->stats.sp ? op->stats.sp : rndm (1, 8); |
|
|
1038 | |
|
|
1039 | sint16 nx = op->x + freearr_x[dir]; |
|
|
1040 | sint16 ny = op->y + freearr_y[dir]; |
|
|
1041 | maptile *m = op->map; |
|
|
1042 | if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP) |
|
|
1043 | { |
|
|
1044 | LOG (llevError, "move_player_mover: Trying to push player off the map! map=%s (%d, %d)\n", &m->path, op->x, op->y); |
|
|
1045 | return; |
|
|
1046 | } |
1034 | |
1047 | |
1035 | if (victim->head) |
1048 | if (victim->head) |
1036 | victim = victim->head; |
1049 | victim = victim->head; |
1037 | |
|
|
1038 | if (op->flag [FLAG_LIFESAVE] && op->stats.hp-- < 0) |
|
|
1039 | { |
|
|
1040 | op->remove (); |
|
|
1041 | return; |
|
|
1042 | } |
|
|
1043 | |
|
|
1044 | nx = op->x + freearr_x[dir]; |
|
|
1045 | ny = op->y + freearr_y[dir]; |
|
|
1046 | m = op->map; |
|
|
1047 | if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP) |
|
|
1048 | { |
|
|
1049 | LOG (llevError, "move_player_mover: Trying to push player off the map! map=%s (%d, %d)\n", &m->path, op->x, op->y); |
|
|
1050 | return; |
|
|
1051 | } |
|
|
1052 | |
1050 | |
1053 | if (should_director_abort (op, victim)) |
1051 | if (should_director_abort (op, victim)) |
1054 | return; |
1052 | return; |
1055 | |
1053 | |
1056 | for (object *nextmover = m->at (nx, ny).bot; nextmover; nextmover = nextmover->above) |
1054 | for (object *nextmover = m->at (nx, ny).bot; nextmover; nextmover = nextmover->above) |
… | |
… | |
1165 | int i; |
1163 | int i; |
1166 | object *ob_to_copy; |
1164 | object *ob_to_copy; |
1167 | |
1165 | |
1168 | /* select random object from inventory to copy */ |
1166 | /* select random object from inventory to copy */ |
1169 | ob_to_copy = creator->inv; |
1167 | ob_to_copy = creator->inv; |
1170 | for (ob = creator->inv->below, i = 1; ob != NULL; ob = ob->below, i++) |
1168 | for (ob = creator->inv->below, i = 1; ob; ob = ob->below, i++) |
1171 | { |
1169 | { |
1172 | if (rndm (0, i) == 0) |
1170 | if (rndm (0, i) == 0) |
1173 | { |
1171 | { |
1174 | ob_to_copy = ob; |
1172 | ob_to_copy = ob; |
1175 | } |
1173 | } |
1176 | } |
1174 | } |
|
|
1175 | |
1177 | new_ob = ob_to_copy->deep_clone (); |
1176 | new_ob = ob_to_copy->deep_clone (); |
1178 | new_ob->clr_flag (FLAG_IS_A_TEMPLATE); |
1177 | new_ob->clr_flag (FLAG_IS_A_TEMPLATE); |
1179 | unflag_inv (new_ob, FLAG_IS_A_TEMPLATE); |
1178 | unflag_inv (new_ob, FLAG_IS_A_TEMPLATE); |
1180 | } |
1179 | } |
1181 | else |
1180 | else |
… | |
… | |
1198 | return; |
1197 | return; |
1199 | } |
1198 | } |
1200 | |
1199 | |
1201 | // for now lets try to identify everything generated here, it mostly |
1200 | // for now lets try to identify everything generated here, it mostly |
1202 | // happens automated, so this will at least fix many identify-experience holes |
1201 | // happens automated, so this will at least fix many identify-experience holes |
|
|
1202 | if (new_ob->need_identify ()) |
1203 | new_ob->set_flag (FLAG_IDENTIFIED); |
1203 | new_ob->set_flag (FLAG_IDENTIFIED); |
1204 | |
1204 | |
1205 | insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y); |
1205 | insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y); |
1206 | if (new_ob->flag [FLAG_FREED]) |
1206 | if (new_ob->flag [FLAG_FREED]) |
1207 | return; |
1207 | return; |
1208 | |
1208 | |
… | |
… | |
1483 | |
1483 | |
1484 | case LAMP: |
1484 | case LAMP: |
1485 | case TORCH: |
1485 | case TORCH: |
1486 | move_lamp (op); |
1486 | move_lamp (op); |
1487 | break; |
1487 | break; |
1488 | } |
|
|
1489 | } |
|
|
1490 | |
1488 | |
|
|
1489 | case PHYSICS: // hmm, bad naming |
|
|
1490 | move_physics (op); |
|
|
1491 | break; |
|
|
1492 | } |
|
|
1493 | } |
|
|
1494 | |