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 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2001,2007 Mark Wedel & Crossfire Development Team |
5 | * Copyright (©) 2001 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992,2007 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 | #include <global.h> |
25 | #include <global.h> |
26 | #include <living.h> |
26 | #include <living.h> |
27 | #include <spells.h> |
27 | #include <spells.h> |
28 | #include <skills.h> |
28 | #include <skills.h> |
29 | #include <tod.h> |
29 | #include <tod.h> |
30 | #include <sproto.h> |
30 | #include <sproto.h> |
31 | |
31 | |
|
|
32 | // macro for this check, it had been inconsistent in this file. |
|
|
33 | #define IS_FLOOR(x) x->flag [FLAG_IS_FLOOR] |
|
|
34 | |
32 | /** |
35 | /** |
33 | * Check if objects on a square interfere with building |
36 | * Check if objects on a square interfere with building |
34 | */ |
37 | */ |
35 | static int |
38 | static int |
36 | can_build_over (maptile *map, object *tmp, int x, int y) |
39 | can_build_over (maptile *map, object *tmp, int x, int y) |
… | |
… | |
39 | |
42 | |
40 | ob = GET_MAP_OB (map, x, y); |
43 | ob = GET_MAP_OB (map, x, y); |
41 | while (ob) |
44 | while (ob) |
42 | { |
45 | { |
43 | /* if ob is not a marking rune or floor, then check special cases */ |
46 | /* if ob is not a marking rune or floor, then check special cases */ |
44 | if (ob->arch->archname != shstr_rune_mark && ob->type != FLOOR) |
47 | if (ob->arch->archname != shstr_rune_mark && !IS_FLOOR (ob)) |
45 | { |
48 | { |
46 | switch (tmp->type) |
49 | switch (tmp->type) |
47 | { |
50 | { |
48 | case SIGN: |
51 | case SIGN: |
49 | case MAGIC_EAR: |
52 | case MAGIC_EAR: |
… | |
… | |
64 | } |
67 | } |
65 | } |
68 | } |
66 | |
69 | |
67 | ob = ob->above; |
70 | ob = ob->above; |
68 | } |
71 | } |
|
|
72 | |
69 | return 1; |
73 | return 1; |
70 | } |
74 | } |
71 | |
75 | |
72 | /** |
76 | /** |
73 | * Erases marking runes at specified location |
77 | * Erases marking runes at specified location |
… | |
… | |
170 | { |
174 | { |
171 | new_draw_info (NDI_UNIQUE, 0, pl, "Could not create more groups."); |
175 | new_draw_info (NDI_UNIQUE, 0, pl, "Could not create more groups."); |
172 | return shstr_tmp (); |
176 | return shstr_tmp (); |
173 | } |
177 | } |
174 | |
178 | |
175 | force = get_archetype (FORCE_NAME); |
179 | force = archetype::get (FORCE_NAME); |
176 | force->slaying = pl->map->path; |
180 | force->slaying = pl->map->path; |
177 | force->msg = rune->msg; |
181 | force->msg = rune->msg; |
178 | force->race = id; |
182 | force->race = id; |
179 | force->set_speed (0); |
183 | force->set_speed (0); |
180 | |
184 | |
… | |
… | |
218 | { |
222 | { |
219 | new_draw_info (NDI_UNIQUE, 0, pl, "You need to put a book or scroll with the message."); |
223 | new_draw_info (NDI_UNIQUE, 0, pl, "You need to put a book or scroll with the message."); |
220 | return -1; |
224 | return -1; |
221 | } |
225 | } |
222 | |
226 | |
|
|
227 | if (tmp->type == MAGIC_EAR) |
|
|
228 | { |
|
|
229 | snprintf (buf, sizeof (buf), "@match %s", &(book->msg)); |
|
|
230 | tmp->msg = buf; |
|
|
231 | } |
|
|
232 | else |
223 | tmp->msg = book->msg; |
233 | tmp->msg = book->msg; |
224 | |
234 | |
225 | if (tmp->invisible) |
235 | if (tmp->invisible) |
226 | { |
236 | { |
227 | if (book->custom_name) |
237 | if (book->custom_name) |
228 | snprintf (buf, sizeof (buf), "talking %s", &book->custom_name); |
238 | snprintf (buf, sizeof (buf), "talking %s", &book->custom_name); |
… | |
… | |
303 | if (x > 0 && get_wall (map, x - 1, y)) connect |= 1; |
313 | if (x > 0 && get_wall (map, x - 1, y)) connect |= 1; |
304 | if (x < map->width - 1 && get_wall (map, x + 1, y)) connect |= 2; |
314 | if (x < map->width - 1 && get_wall (map, x + 1, y)) connect |= 2; |
305 | if (y > 0 && get_wall (map, x, y - 1)) connect |= 4; |
315 | if (y > 0 && get_wall (map, x, y - 1)) connect |= 4; |
306 | if (y < map->height - 1 && get_wall (map, x, y + 1)) connect |= 8; |
316 | if (y < map->height - 1 && get_wall (map, x, y + 1)) connect |= 8; |
307 | |
317 | |
308 | // one bit per dir, 1 left, 2 right, 4 up, 8 down |
|
|
309 | static const char *walltype[16] = { |
|
|
310 | "0", |
|
|
311 | "1_3", |
|
|
312 | "1_4", |
|
|
313 | "2_1_2", |
|
|
314 | "1_2", |
|
|
315 | "2_2_4", |
|
|
316 | "2_2_1", |
|
|
317 | "3_1", |
|
|
318 | "1_1", |
|
|
319 | "2_2_3", |
|
|
320 | "2_2_2", |
|
|
321 | "3_3", |
|
|
322 | "2_1_1", |
|
|
323 | "3_4", |
|
|
324 | "3_2", |
|
|
325 | "4" |
|
|
326 | }; |
|
|
327 | |
|
|
328 | strcat (archetype, walltype [connect]); |
318 | strcat (archetype, wall_suffix [connect]); |
329 | |
319 | |
330 | /* |
320 | /* |
331 | * Before anything, make sure the archetype does exist... |
321 | * Before anything, make sure the archetype does exist... |
332 | * If not, prolly an error... |
322 | * If not, prolly an error... |
333 | */ |
323 | */ |
… | |
… | |
389 | /* There was a wall, remove it & keep its archetype to make new walls */ |
379 | /* There was a wall, remove it & keep its archetype to make new walls */ |
390 | new_wall = tmp->arch; |
380 | new_wall = tmp->arch; |
391 | tmp->destroy (); |
381 | tmp->destroy (); |
392 | sprintf (message, "You destroy the wall and redo the floor."); |
382 | sprintf (message, "You destroy the wall and redo the floor."); |
393 | } |
383 | } |
394 | else if ((FLOOR == tmp->type) || (QUERY_FLAG (tmp, FLAG_IS_FLOOR))) |
384 | else if (IS_FLOOR (tmp)) |
395 | { |
385 | { |
396 | tmp->destroy (); |
386 | tmp->destroy (); |
397 | floor_removed = 1; |
387 | floor_removed = 1; |
398 | } |
388 | } |
399 | else |
389 | else |
… | |
… | |
418 | LOG (llevError, "apply_builder_floor: unable to find archetype %s.\n", &material->slaying); |
408 | LOG (llevError, "apply_builder_floor: unable to find archetype %s.\n", &material->slaying); |
419 | return; |
409 | return; |
420 | } |
410 | } |
421 | |
411 | |
422 | tmp = new_floor->instance (); |
412 | tmp = new_floor->instance (); |
423 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
413 | tmp->set_flag (FLAG_IS_BUILDABLE); |
424 | SET_FLAG (tmp, FLAG_UNIQUE); |
414 | tmp->set_flag (FLAG_UNIQUE); |
425 | SET_FLAG (tmp, FLAG_IS_FLOOR); |
415 | tmp->set_flag (FLAG_IS_FLOOR); |
426 | tmp->type = FLOOR; |
416 | //tmp->type = FLOOR; |
427 | insert_ob_in_map_at (tmp, pl->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y); |
417 | insert_ob_in_map_at (tmp, pl->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y); |
428 | |
418 | |
429 | /* |
419 | /* |
430 | * Next step: make sure there are either walls or floors around the new square |
420 | * Next step: make sure there are either walls or floors around the new square |
431 | * Since building, you can have: blocking view / floor / wall / nothing |
421 | * Since building, you can have: blocking view / floor / wall / nothing |
… | |
… | |
438 | if (!tmp) |
428 | if (!tmp) |
439 | { |
429 | { |
440 | /* Must insert floor & wall */ |
430 | /* Must insert floor & wall */ |
441 | tmp = new_floor->instance (); |
431 | tmp = new_floor->instance (); |
442 | /* Better make the floor unique */ |
432 | /* Better make the floor unique */ |
443 | SET_FLAG (tmp, FLAG_UNIQUE); |
433 | tmp->set_flag (FLAG_UNIQUE); |
444 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
434 | tmp->set_flag (FLAG_IS_BUILDABLE); |
445 | tmp->type = FLOOR; |
435 | //tmp->type = FLOOR; |
446 | insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt); |
436 | insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt); |
447 | /* Insert wall if exists. Note: if it doesn't, the map is weird... */ |
437 | /* Insert wall if exists. Note: if it doesn't, the map is weird... */ |
448 | if (new_wall) |
438 | if (new_wall) |
449 | { |
439 | { |
450 | tmp = new_wall->instance (); |
440 | tmp = new_wall->instance (); |
451 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
441 | tmp->set_flag (FLAG_IS_BUILDABLE); |
452 | tmp->type = BUILDABLE_WALL; |
442 | tmp->type = BUILDABLE_WALL; |
453 | insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt); |
443 | insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt); |
454 | } |
444 | } |
455 | } |
445 | } |
456 | } |
446 | } |
… | |
… | |
511 | return; |
501 | return; |
512 | } |
502 | } |
513 | |
503 | |
514 | tmp = new_wall->instance (); |
504 | tmp = new_wall->instance (); |
515 | tmp->type = BUILDABLE_WALL; |
505 | tmp->type = BUILDABLE_WALL; |
516 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
506 | tmp->set_flag (FLAG_IS_BUILDABLE); |
517 | insert_ob_in_map_at (tmp, pl->map, 0, INS_ABOVE_FLOOR_ONLY, x, y); |
507 | insert_ob_in_map_at (tmp, pl->map, 0, INS_ABOVE_FLOOR_ONLY, x, y); |
518 | |
508 | |
519 | /* If existing wall, remove it, no need to fix other walls */ |
509 | /* If existing wall, remove it, no need to fix other walls */ |
520 | if (current_wall) |
510 | if (current_wall) |
521 | { |
511 | { |
… | |
… | |
566 | { |
556 | { |
567 | new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square."); |
557 | new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square."); |
568 | return; |
558 | return; |
569 | } |
559 | } |
570 | |
560 | |
571 | while (floor && (floor->type != FLOOR) && (!QUERY_FLAG (floor, FLAG_IS_FLOOR))) |
561 | while (floor && !IS_FLOOR (floor)) |
572 | floor = floor->above; |
562 | floor = floor->above; |
573 | |
563 | |
574 | if (!floor) |
564 | if (!floor) |
575 | { |
565 | { |
576 | new_draw_info (NDI_UNIQUE, 0, pl, "This square has no floor, you can't build here."); |
566 | new_draw_info (NDI_UNIQUE, 0, pl, "This square has no floor, you can't build here."); |
… | |
… | |
581 | if (!arch) |
571 | if (!arch) |
582 | return; |
572 | return; |
583 | |
573 | |
584 | tmp = arch->instance (); |
574 | tmp = arch->instance (); |
585 | |
575 | |
586 | if (!floor->flag[FLAG_IS_BUILDABLE] || (floor->above) && (!can_build_over (pl->map, tmp, x, y))) |
576 | if (!floor->flag[FLAG_IS_BUILDABLE] || floor->above && !can_build_over (pl->map, tmp, x, y)) |
587 | /* Floor has something on top that interferes with building */ |
577 | /* Floor has something on top that interferes with building */ |
588 | { |
578 | { |
589 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here."); |
579 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here."); |
590 | return; |
580 | return; |
591 | } |
581 | } |
592 | |
582 | |
593 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
583 | tmp->set_flag (FLAG_IS_BUILDABLE); |
594 | SET_FLAG (tmp, FLAG_NO_PICK); |
584 | tmp->set_flag (FLAG_NO_PICK); |
595 | |
585 | |
596 | /* |
586 | /* |
597 | * Str 1 is a flag that the item [pedestal] should go below the floor. |
587 | * Str 1 is a flag that the item [pedestal] should go below the floor. |
598 | * Items under the floor on non-unique maps will not be saved, |
588 | * Items under the floor on non-unique maps will not be saved, |
599 | * so make the item itself unique in this situation. |
589 | * so make the item itself unique in this situation. |
600 | */ |
590 | */ |
601 | insert_flag = ( item->stats.Str == 1 ) ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY; |
591 | insert_flag = item->stats.Str == 1 ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY; |
602 | if (insert_flag == INS_BELOW_ORIGINATOR && !pl->map->no_reset) |
592 | if (insert_flag == INS_BELOW_ORIGINATOR && !pl->map->no_reset) |
603 | SET_FLAG (tmp, FLAG_UNIQUE); |
593 | tmp->set_flag (FLAG_UNIQUE); |
604 | |
594 | |
605 | shstr_tmp connected; |
595 | shstr_tmp connected; |
606 | |
596 | |
607 | switch (tmp->type) |
597 | switch (tmp->type) |
608 | { |
598 | { |
… | |
… | |
670 | new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square."); |
660 | new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square."); |
671 | LOG (llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, &pl->map->path); |
661 | LOG (llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, &pl->map->path); |
672 | return; |
662 | return; |
673 | } |
663 | } |
674 | |
664 | |
675 | if (item->type == FLOOR || QUERY_FLAG (item, FLAG_IS_FLOOR)) |
665 | if (IS_FLOOR (item)) |
676 | item = item->above; |
666 | item = item->above; |
677 | |
667 | |
678 | if (!item) |
668 | if (!item) |
679 | new_draw_info (NDI_UNIQUE, 0, pl, "Nothing to remove."); |
669 | new_draw_info (NDI_UNIQUE, 0, pl, "Nothing to remove."); |
680 | else if (item->type == BUILDABLE_WALL) |
670 | else if (item->type == BUILDABLE_WALL) |
… | |
… | |
686 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You remove the %s", query_name (item)); |
676 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You remove the %s", query_name (item)); |
687 | item->destroy (); |
677 | item->destroy (); |
688 | } |
678 | } |
689 | } |
679 | } |
690 | |
680 | |
|
|
681 | |
|
|
682 | static void |
|
|
683 | replace_open_space_floor (object *os, object *material) |
|
|
684 | { |
|
|
685 | object *new_floor = archetype::get (material->slaying); |
|
|
686 | insert_ob_in_map_at (new_floor, os->map, os, |
|
|
687 | INS_BELOW_ORIGINATOR, os->x, os->y); |
|
|
688 | os->destroy (); |
|
|
689 | material->decrease (); |
|
|
690 | } |
|
|
691 | |
|
|
692 | /** |
|
|
693 | * Quad building. |
|
|
694 | */ |
|
|
695 | void |
|
|
696 | apply_builder_quad (object *pl, object *material, mapxy &pos) |
|
|
697 | { |
|
|
698 | object *open_space = 0; |
|
|
699 | object *floor = 0; |
|
|
700 | |
|
|
701 | object *tmp = pos.ms ().bot; |
|
|
702 | bool floor_exists = false; |
|
|
703 | while (tmp) |
|
|
704 | { |
|
|
705 | if (floor_exists && tmp->flag [FLAG_IS_QUAD]) |
|
|
706 | { |
|
|
707 | pl->failmsg ( |
|
|
708 | "You can't build there, there is a block in the way."); |
|
|
709 | return; |
|
|
710 | } |
|
|
711 | |
|
|
712 | if (IS_FLOOR (tmp)) |
|
|
713 | { |
|
|
714 | floor = tmp; |
|
|
715 | floor_exists = true; |
|
|
716 | |
|
|
717 | if (floor->arch->archname == shstr_quad_open_space) |
|
|
718 | { |
|
|
719 | open_space = floor; |
|
|
720 | } |
|
|
721 | else if (!floor->flag [FLAG_IS_QUAD]) |
|
|
722 | { |
|
|
723 | pl->failmsg ( |
|
|
724 | "You can't build there, the floor is not suited."); |
|
|
725 | return; |
|
|
726 | } |
|
|
727 | } |
|
|
728 | |
|
|
729 | tmp = tmp->above; |
|
|
730 | } |
|
|
731 | |
|
|
732 | if (open_space) |
|
|
733 | { |
|
|
734 | if (!material->slaying) |
|
|
735 | { |
|
|
736 | pl->failmsg ( |
|
|
737 | "The floor is open and you can't fill it with that material." |
|
|
738 | "H<Use another material to fill the ceiling.>"); |
|
|
739 | return; |
|
|
740 | } |
|
|
741 | |
|
|
742 | replace_open_space_floor (open_space, material); |
|
|
743 | pl->contr->fire_on = 0; // TODO: stopgap, do not add more than one per keypress |
|
|
744 | return; |
|
|
745 | } |
|
|
746 | else if (floor) |
|
|
747 | { |
|
|
748 | |
|
|
749 | maptile *upper_floor = pos.m->tile_available (TILE_UP); |
|
|
750 | if (!upper_floor) |
|
|
751 | { |
|
|
752 | pl->failmsg ( |
|
|
753 | "Whoops, you can't see the ceiling.. H<You may try again.>"); |
|
|
754 | return; |
|
|
755 | } |
|
|
756 | |
|
|
757 | mapxy above_pos (upper_floor, pos.x, pos.y); |
|
|
758 | if (!above_pos.normalise ()) |
|
|
759 | { |
|
|
760 | pl->failmsg ( |
|
|
761 | "Whoops, you can't access the ceiling. H<You may try again.>"); |
|
|
762 | return; |
|
|
763 | } |
|
|
764 | |
|
|
765 | mapspace &above_ms = above_pos.ms (); |
|
|
766 | for (object *quad_obj = above_ms.top; quad_obj; quad_obj = quad_obj->below) |
|
|
767 | { |
|
|
768 | if (quad_obj->arch->archname == shstr_quad_open_space) |
|
|
769 | { |
|
|
770 | if (!material->slaying) |
|
|
771 | { |
|
|
772 | pl->failmsg ( |
|
|
773 | "The ceiling is open and you can't fill it with that material." |
|
|
774 | "H<Use another material to fill the ceiling.>"); |
|
|
775 | return; |
|
|
776 | } |
|
|
777 | |
|
|
778 | replace_open_space_floor (quad_obj, material); |
|
|
779 | break; |
|
|
780 | } |
|
|
781 | } |
|
|
782 | |
|
|
783 | if (material->destroyed ()) |
|
|
784 | { |
|
|
785 | pl->failmsg ( |
|
|
786 | "You don't have enough build material to build a wall here."); |
|
|
787 | return; |
|
|
788 | } |
|
|
789 | |
|
|
790 | object *quad_wall = material->other_arch->instance (); |
|
|
791 | material->decrease (); |
|
|
792 | |
|
|
793 | insert_ob_in_map_at (quad_wall, floor->map, 0, |
|
|
794 | INS_ABOVE_FLOOR_ONLY, floor->x, floor->y); |
|
|
795 | } |
|
|
796 | else |
|
|
797 | { |
|
|
798 | pl->failmsg ("You can't build a quad block here."); |
|
|
799 | } |
|
|
800 | } |
|
|
801 | |
691 | /** |
802 | /** |
692 | * Global building function |
803 | * Global building function |
693 | * |
804 | * |
694 | * This is the general map building function. Called when the player 'fires' a builder |
805 | * This is the general map building function. Called when the player 'fires' a builder |
695 | * or remover object. |
806 | * or remover object. |
696 | */ |
807 | */ |
697 | void |
808 | void |
698 | apply_map_builder (object *pl, int dir) |
809 | apply_map_builder (object *pl, int dir) |
699 | { |
810 | { |
700 | object *builder; |
|
|
701 | object *tmp; |
|
|
702 | object *tmp2; |
|
|
703 | int x, y; |
|
|
704 | |
|
|
705 | if (!pl->type == PLAYER) |
811 | if (!pl->type == PLAYER) |
706 | return; |
812 | return; |
707 | |
813 | |
708 | /*if ( !player->map->unique ) |
|
|
709 | { |
|
|
710 | new_draw_info( NDI_UNIQUE, 0, player, "You can't build outside a unique map." ); |
|
|
711 | return; |
|
|
712 | } */ |
|
|
713 | |
|
|
714 | if (dir == 0) |
814 | if (dir == 0) |
715 | { |
815 | { |
716 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build or destroy under yourself."); |
816 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build or destroy under yourself."); |
717 | return; |
817 | return; |
718 | } |
818 | } |
719 | |
819 | |
720 | x = pl->x + freearr_x[dir]; |
820 | mapxy pos (pl); pos.move (dir); |
721 | y = pl->y + freearr_y[dir]; |
|
|
722 | |
821 | |
723 | if ((1 > x) || (1 > y) || ((pl->map->width - 2) < x) || ((pl->map->height - 2) < y)) |
822 | if (!pos.normalise ()) |
724 | { |
823 | { |
725 | new_draw_info (NDI_UNIQUE, 0, pl, "Can't build on map edge..."); |
824 | pl->failmsg ("You can't build here. H<There is nothing in this direction.>"); |
726 | return; |
825 | return; |
727 | } |
826 | } |
728 | |
827 | |
729 | /* |
828 | /* |
730 | * Check specified square |
829 | * Check specified square |
731 | * The square must have only buildable items |
830 | * The square must have only buildable items |
732 | * Exception: marking runes are all right, |
831 | * Exception: marking runes are all right, |
733 | * since they are used for special things like connecting doors / buttons |
832 | * since they are used for special things like connecting doors / buttons |
734 | */ |
833 | */ |
735 | |
834 | |
736 | tmp = GET_MAP_OB (pl->map, x, y); |
835 | object *builder = pl->contr->ranged_ob; |
737 | if (!tmp) |
836 | |
738 | { |
837 | object *tmp2 = pl->mark (); |
739 | /* Nothing, meaning player is standing next to an undefined square... */ |
838 | |
740 | LOG (llevError, "apply_map_builder: undefined square at (%d, %d, %s)\n", x, y, &pl->map->path); |
839 | object *tmp = 0; |
741 | new_draw_info (NDI_UNIQUE, 0, pl, "You'd better not build here, it looks weird."); |
840 | for (tmp = pos.ms ().bot; tmp; tmp = tmp->above) |
742 | return; |
|
|
743 | } |
841 | { |
744 | |
842 | if (!tmp->flag [FLAG_IS_BUILDABLE] |
745 | tmp2 = find_marked_object (pl); |
|
|
746 | while (tmp) |
|
|
747 | { |
|
|
748 | if (!QUERY_FLAG (tmp, FLAG_IS_BUILDABLE) && (tmp->type != SIGN || tmp->arch->archname != shstr_rune_mark)) |
843 | && (tmp->type != SIGN || tmp->arch->archname != shstr_rune_mark)) |
749 | { |
844 | { |
750 | /* The item building function already has it's own special |
845 | /* The item building function already has it's own special |
751 | * checks for this |
846 | * checks for this. And so does the quad building function. |
752 | */ |
847 | */ |
753 | if ((!tmp2) || (tmp2->subtype != ST_MAT_ITEM)) |
848 | if (!tmp2 || (tmp2->subtype != ST_MAT_ITEM && tmp2->subtype != ST_MAT_QUAD)) |
754 | { |
849 | { |
|
|
850 | if (!INVOKE_PLAYER (BUILD, pl->contr, ARG_OBJECT (builder), |
|
|
851 | ARG_MAP (pl->map), |
|
|
852 | ARG_INT (pos.y), ARG_INT (pos.y), |
|
|
853 | ARG_INT (0))) |
755 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here."); |
854 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here."); |
|
|
855 | |
756 | return; |
856 | return; |
757 | } |
857 | } |
758 | } |
858 | } |
759 | tmp = tmp->above; |
|
|
760 | } |
859 | } |
761 | |
860 | |
762 | /* Now we know the square is ok */ |
861 | /* Now we know the square is ok */ |
763 | builder = pl->contr->ranged_ob; |
862 | if (INVOKE_PLAYER (BUILD, pl->contr, ARG_OBJECT (builder), |
|
|
863 | ARG_MAP (pl->map), ARG_INT (pos.x), ARG_INT (pos.y), ARG_INT (1))) |
|
|
864 | return; |
764 | |
865 | |
765 | if (builder->subtype == ST_BD_REMOVE) |
866 | if (builder->subtype == ST_BD_REMOVE) |
766 | /* Remover -> call specific function and bail out */ |
867 | /* Remover -> call specific function and bail out */ |
767 | { |
868 | { |
768 | apply_builder_remove (pl, dir); |
869 | apply_builder_remove (pl, dir); |
… | |
… | |
788 | return; |
889 | return; |
789 | } |
890 | } |
790 | |
891 | |
791 | switch (tmp->subtype) |
892 | switch (tmp->subtype) |
792 | { |
893 | { |
793 | case ST_MAT_FLOOR: |
894 | case ST_MAT_FLOOR: |
794 | apply_builder_floor (pl, tmp, x, y); |
895 | apply_builder_floor (pl, tmp, pos.x, pos.y); |
795 | return; |
896 | return; |
796 | |
897 | |
797 | case ST_MAT_WALL: |
898 | case ST_MAT_WALL: |
798 | apply_builder_wall (pl, tmp, x, y); |
899 | apply_builder_wall (pl, tmp, pos.x, pos.y); |
799 | return; |
900 | return; |
800 | |
901 | |
801 | case ST_MAT_ITEM: |
902 | case ST_MAT_ITEM: |
802 | apply_builder_item (pl, tmp, x, y); |
903 | apply_builder_item (pl, tmp, pos.x, pos.y); |
803 | return; |
904 | return; |
804 | |
905 | |
|
|
906 | case ST_MAT_QUAD: |
|
|
907 | apply_builder_quad (pl, tmp, pos); |
|
|
908 | return; |
|
|
909 | |
805 | default: |
910 | default: |
806 | new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this material, sorry."); |
911 | new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this material, sorry."); |
807 | LOG (llevError, "apply_map_builder: invalid material subtype %d\n", tmp->subtype); |
912 | LOG (llevError, "apply_map_builder: invalid material subtype %d\n", tmp->subtype); |
808 | return; |
913 | return; |
809 | } |
914 | } |
810 | } |
915 | } |
811 | |
916 | |
812 | /* Here, it means the builder has an invalid type */ |
917 | /* Here, it means the builder has an invalid type */ |
813 | new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this tool, sorry."); |
918 | new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this tool, sorry."); |