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 (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2001 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 2001 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * |
8 | * |
8 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * 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 |
10 | * 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 |
11 | * Free Software Foundation, either version 3 of the License, or (at your |
11 | * option) any later version. |
12 | * option) any later version. |
12 | * |
13 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
17 | * GNU General Public License for more details. |
17 | * |
18 | * |
18 | * You should have received a copy of the Affero GNU General Public License |
19 | * 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 |
20 | * and the GNU General Public License along with this program. If not, see |
20 | * <http://www.gnu.org/licenses/>. |
21 | * <http://www.gnu.org/licenses/>. |
21 | * |
22 | * |
22 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | */ |
24 | */ |
24 | |
25 | |
25 | /* placing treasure in maps, where appropriate. */ |
26 | /* placing treasure in maps, where appropriate. */ |
26 | |
27 | |
27 | #include <global.h> |
28 | #include <global.h> |
28 | #include <random_map.h> |
29 | #include <rmg.h> |
29 | #include <rproto.h> |
30 | #include <rproto.h> |
30 | |
31 | |
31 | /* some defines for various options which can be set. */ |
32 | /* some defines for various options which can be set. */ |
32 | |
33 | |
33 | #define CONCENTRATED 1 /* all the treasure is at the C's for onions. */ |
34 | #define CONCENTRATED 1 /* all the treasure is at the C's for onions. */ |
… | |
… | |
67 | object *key = archetype::get (shstr_key_random_map); |
68 | object *key = archetype::get (shstr_key_random_map); |
68 | key->slaying = keycode; |
69 | key->slaying = keycode; |
69 | return key; |
70 | return key; |
70 | } |
71 | } |
71 | |
72 | |
72 | /* places keys in the map, preferably in something alive. |
73 | /* places keys in the map, preferably in something alive. |
73 | keycode is the key's code, |
74 | keycode is the key's code, |
74 | door_flag is either PASS_DOORS or NO_PASS_DOORS. |
75 | door_flag is either PASS_DOORS or NO_PASS_DOORS. |
75 | NO_PASS_DOORS won't cross doors or walls to keyplace, PASS_DOORS will. |
76 | NO_PASS_DOORS won't cross doors or walls to keyplace, PASS_DOORS will. |
76 | if n_keys is 1, it will place 1 key. if n_keys >1, it will place 2-4 keys: |
77 | if n_keys is 1, it will place 1 key. if n_keys >1, it will place 2-4 keys: |
77 | it will place 2-4 keys regardless of what nkeys is provided nkeys > 1. |
78 | it will place 2-4 keys regardless of what nkeys is provided nkeys > 1. |
… | |
… | |
114 | } |
115 | } |
115 | |
116 | |
116 | // can freeindex ever be < 0? |
117 | // can freeindex ever be < 0? |
117 | if (freeindex >= 0) |
118 | if (freeindex >= 0) |
118 | { |
119 | { |
119 | kx += freearr_x [freeindex]; |
120 | kx += DIRX (freeindex); |
120 | ky += freearr_y [freeindex]; |
121 | ky += DIRY (freeindex); |
121 | } |
122 | } |
122 | } |
123 | } |
123 | } |
124 | } |
124 | else |
125 | else |
125 | { /* NO_PASS_DOORS --we have to work harder. */ |
126 | { /* NO_PASS_DOORS --we have to work harder. */ |
… | |
… | |
184 | |
185 | |
185 | m->at (x, y).update (); |
186 | m->at (x, y).update (); |
186 | return GET_MAP_MOVE_BLOCK (m, x, y) & MOVE_WALK; |
187 | return GET_MAP_MOVE_BLOCK (m, x, y) & MOVE_WALK; |
187 | } |
188 | } |
188 | |
189 | |
189 | /* place treasures in the map, given the |
190 | /* place treasures in the map, given the |
190 | map, (required) |
191 | map, (required) |
191 | maze, (required) |
192 | maze, (required) |
192 | treasure style (may be empty or NULL, or "none" to cause no treasure.) |
193 | treasure style (may be empty or NULL, or "none" to cause no treasure.) |
193 | treasureoptions (may be 0 for random choices or positive) |
194 | treasureoptions (may be 0 for random choices or positive) |
194 | */ |
195 | */ |
… | |
… | |
341 | { |
342 | { |
342 | the_chest->destroy (); |
343 | the_chest->destroy (); |
343 | return NULL; |
344 | return NULL; |
344 | } |
345 | } |
345 | |
346 | |
346 | int xl = x + freearr_x[i]; |
347 | int xl = x + DIRX (i); |
347 | int yl = y + freearr_y[i]; |
348 | int yl = y + DIRY (i); |
348 | |
349 | |
349 | /* if the placement is blocked, return a fail. */ |
350 | /* if the placement is blocked, return a fail. */ |
350 | if (wall_blocked (map, xl, yl)) |
351 | if (wall_blocked (map, xl, yl)) |
351 | return 0; |
352 | return 0; |
352 | |
353 | |
… | |
… | |
425 | |
426 | |
426 | for (i = 0; i < SIZEOFFREE; i++) |
427 | for (i = 0; i < SIZEOFFREE; i++) |
427 | { |
428 | { |
428 | int lx, ly; |
429 | int lx, ly; |
429 | |
430 | |
430 | lx = x + freearr_x[i]; |
431 | lx = x + DIRX (i); |
431 | ly = y + freearr_y[i]; |
432 | ly = y + DIRY (i); |
432 | /* boundscheck */ |
433 | /* boundscheck */ |
433 | if (lx >= 0 && ly >= 0 && lx < map->width && ly < map->height) |
434 | if (lx >= 0 && ly >= 0 && lx < map->width && ly < map->height) |
434 | /* don't bother searching this square unless the map says life exists. */ |
435 | /* don't bother searching this square unless the map says life exists. */ |
435 | if (GET_MAP_FLAGS (map, lx, ly) & P_IS_ALIVE) |
436 | if (GET_MAP_FLAGS (map, lx, ly) & P_IS_ALIVE) |
436 | { |
437 | { |
… | |
… | |
486 | } |
487 | } |
487 | |
488 | |
488 | /* now search all the 8 squares around recursively for a monster,in random order */ |
489 | /* now search all the 8 squares around recursively for a monster,in random order */ |
489 | for (i = rmg_rndm (8), j = 0; j < 8 && !theMonsterToFind; i++, j++) |
490 | for (i = rmg_rndm (8), j = 0; j < 8 && !theMonsterToFind; i++, j++) |
490 | { |
491 | { |
491 | theMonsterToFind = find_monster_in_room_recursive (maze, map, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1]); |
492 | theMonsterToFind = find_monster_in_room_recursive (maze, map, x + DIRX (i % 8 + 1), y + DIRY (i % 8 + 1)); |
492 | if (theMonsterToFind) |
493 | if (theMonsterToFind) |
493 | return theMonsterToFind; |
494 | return theMonsterToFind; |
494 | } |
495 | } |
495 | |
496 | |
496 | return theMonsterToFind; |
497 | return theMonsterToFind; |
… | |
… | |
534 | maze[x][y] = 1; |
535 | maze[x][y] = 1; |
535 | spots.push (point (x, y)); |
536 | spots.push (point (x, y)); |
536 | |
537 | |
537 | /* now search all the 8 squares around recursively for free spots,in random order */ |
538 | /* now search all the 8 squares around recursively for free spots,in random order */ |
538 | for (int i = rmg_rndm (8), j = 0; j < 8 && !theMonsterToFind; i++, j++) |
539 | for (int i = rmg_rndm (8), j = 0; j < 8 && !theMonsterToFind; i++, j++) |
539 | find_spot_in_room_recursive (maze, spots, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1]); |
540 | find_spot_in_room_recursive (maze, spots, x + DIRX (i % 8 + 1), y + DIRY (i % 8 + 1)); |
540 | |
541 | |
541 | } |
542 | } |
542 | |
543 | |
543 | /* find a random non-blocked spot in this room to drop a key. */ |
544 | /* find a random non-blocked spot in this room to drop a key. */ |
544 | static void |
545 | static void |
… | |
… | |
579 | |
580 | |
580 | for (i = 0; i <= SIZEOFFREE1; i++) |
581 | for (i = 0; i <= SIZEOFFREE1; i++) |
581 | { |
582 | { |
582 | int lx, ly, sindex; |
583 | int lx, ly, sindex; |
583 | |
584 | |
584 | lx = x + freearr_x[i]; |
585 | lx = x + DIRX (i); |
585 | ly = y + freearr_y[i]; |
586 | ly = y + DIRY (i); |
586 | sindex = surround_flag3 (map, lx, ly); |
587 | sindex = surround_flag3 (map, lx, ly); |
587 | /* if it's blocked on 3 sides, it's enclosed */ |
588 | /* if it's blocked on 3 sides, it's enclosed */ |
588 | if (sindex == 7 || sindex == 11 || sindex == 13 || sindex == 14) |
589 | if (sindex == 7 || sindex == 11 || sindex == 13 || sindex == 14) |
589 | { |
590 | { |
590 | *cx = lx; |
591 | *cx = lx; |
… | |
… | |
597 | spots--try to find someplace which is 2x enclosed. */ |
598 | spots--try to find someplace which is 2x enclosed. */ |
598 | for (i = 0; i <= SIZEOFFREE1; i++) |
599 | for (i = 0; i <= SIZEOFFREE1; i++) |
599 | { |
600 | { |
600 | int lx, ly, sindex; |
601 | int lx, ly, sindex; |
601 | |
602 | |
602 | lx = x + freearr_x[i]; |
603 | lx = x + DIRX (i); |
603 | ly = y + freearr_y[i]; |
604 | ly = y + DIRY (i); |
604 | sindex = surround_flag3 (map, lx, ly); |
605 | sindex = surround_flag3 (map, lx, ly); |
605 | /* if it's blocked on 3 sides, it's enclosed */ |
606 | /* if it's blocked on 3 sides, it's enclosed */ |
606 | if (sindex == 3 || sindex == 5 || sindex == 9 || sindex == 6 || sindex == 10 || sindex == 12) |
607 | if (sindex == 3 || sindex == 5 || sindex == 9 || sindex == 6 || sindex == 10 || sindex == 12) |
607 | { |
608 | { |
608 | *cx = lx; |
609 | *cx = lx; |
… | |
… | |
614 | /* settle for one surround point */ |
615 | /* settle for one surround point */ |
615 | for (i = 0; i <= SIZEOFFREE1; i++) |
616 | for (i = 0; i <= SIZEOFFREE1; i++) |
616 | { |
617 | { |
617 | int lx, ly, sindex; |
618 | int lx, ly, sindex; |
618 | |
619 | |
619 | lx = x + freearr_x[i]; |
620 | lx = x + DIRX (i); |
620 | ly = y + freearr_y[i]; |
621 | ly = y + DIRY (i); |
621 | sindex = surround_flag3 (map, lx, ly); |
622 | sindex = surround_flag3 (map, lx, ly); |
622 | /* if it's blocked on 3 sides, it's enclosed */ |
623 | /* if it's blocked on 3 sides, it's enclosed */ |
623 | if (sindex) |
624 | if (sindex) |
624 | { |
625 | { |
625 | *cx = lx; |
626 | *cx = lx; |
… | |
… | |
630 | /* give up and return the closest free spot. */ |
631 | /* give up and return the closest free spot. */ |
631 | i = rmg_find_free_spot (archetype::find (shstr_chest), map, x, y, 1, SIZEOFFREE1 + 1); |
632 | i = rmg_find_free_spot (archetype::find (shstr_chest), map, x, y, 1, SIZEOFFREE1 + 1); |
632 | |
633 | |
633 | if (i != -1) |
634 | if (i != -1) |
634 | { |
635 | { |
635 | *cx = x + freearr_x[i]; |
636 | *cx = x + DIRX (i); |
636 | *cy = y + freearr_y[i]; |
637 | *cy = y + DIRY (i); |
637 | } |
638 | } |
638 | else |
639 | else |
639 | { |
640 | { |
640 | /* indicate failure */ |
641 | /* indicate failure */ |
641 | *cx = -1; |
642 | *cx = -1; |
… | |
… | |
682 | } |
683 | } |
683 | |
684 | |
684 | /* place doors in all the 8 adjacent unblocked squares. */ |
685 | /* place doors in all the 8 adjacent unblocked squares. */ |
685 | for (i = 1; i < 9; i++) |
686 | for (i = 1; i < 9; i++) |
686 | { |
687 | { |
687 | int x1 = x + freearr_x[i], y1 = y + freearr_y[i]; |
688 | int x1 = x + DIRX (i), y1 = y + DIRY (i); |
688 | |
689 | |
689 | if (!wall_blocked (map, x1, y1) && maze[x1][y1] == '>') |
690 | if (!wall_blocked (map, x1, y1) && maze[x1][y1] == '>') |
690 | { /* place a door */ |
691 | { /* place a door */ |
691 | remove_monsters (x1, y1, map); |
692 | remove_monsters (x1, y1, map); |
692 | |
693 | |
693 | object *new_door = get_archetype (freearr_x[i] == 0 ? doors[1] : doors[0]); |
694 | object *new_door = archetype::get (DIRX (i) == 0 ? doors[1] : doors[0]); |
694 | map->insert (new_door, x1, y1); |
695 | map->insert (new_door, x1, y1); |
695 | doorlist[ndoors_made] = new_door; |
696 | doorlist[ndoors_made] = new_door; |
696 | ndoors_made++; |
697 | ndoors_made++; |
697 | } |
698 | } |
698 | } |
699 | } |
… | |
… | |
749 | maze[x][y] = 1; |
750 | maze[x][y] = 1; |
750 | |
751 | |
751 | /* now search all the 8 squares around recursively for free spots,in random order */ |
752 | /* now search all the 8 squares around recursively for free spots,in random order */ |
752 | for (i = rmg_rndm (8), j = 0; j < 8 && !theMonsterToFind; i++, j++) |
753 | for (i = rmg_rndm (8), j = 0; j < 8 && !theMonsterToFind; i++, j++) |
753 | find_doors_in_room_recursive (maze, map, |
754 | find_doors_in_room_recursive (maze, map, |
754 | x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], |
755 | x + DIRX (i % 8 + 1), y + DIRY (i % 8 + 1), |
755 | doorlist, ndoors); |
756 | doorlist, ndoors); |
756 | } |
757 | } |
757 | } |
758 | } |
758 | |
759 | |
759 | /* find a random non-blocked spot in this room to drop a key. */ |
760 | /* find a random non-blocked spot in this room to drop a key. */ |
… | |
… | |
791 | |
792 | |
792 | if (opts & DOORED) |
793 | if (opts & DOORED) |
793 | { |
794 | { |
794 | for (i = 0, door = doorlist[0]; doorlist[i]; i++) |
795 | for (i = 0, door = doorlist[0]; doorlist[i]; i++) |
795 | { |
796 | { |
796 | object *new_door = get_archetype (shstr_locked_door1); |
797 | object *new_door = archetype::get (shstr_locked_door1); |
797 | |
798 | |
798 | door = doorlist[i]; |
799 | door = doorlist[i]; |
799 | new_door->face = door->face; |
800 | new_door->face = door->face; |
800 | new_door->x = door->x; |
801 | new_door->x = door->x; |
801 | new_door->y = door->y; |
802 | new_door->y = door->y; |