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 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. |
… | |
… | |
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 |
… | |
… | |
268 | * |
272 | * |
269 | * Basically it ensures the correct wall is put where needed. |
273 | * Basically it ensures the correct wall is put where needed. |
270 | * |
274 | * |
271 | * Note: x & y must be valid map coordinates. |
275 | * Note: x & y must be valid map coordinates. |
272 | */ |
276 | */ |
273 | void |
277 | static void |
274 | fix_walls (maptile *map, int x, int y) |
278 | fix_walls (maptile *map, int x, int y) |
275 | { |
279 | { |
276 | char archetype[MAX_BUF]; |
280 | char archetype[MAX_BUF]; |
277 | char *underscore; |
281 | char *underscore; |
278 | struct archetype *new_arch; |
282 | struct archetype *new_arch; |
… | |
… | |
341 | */ |
345 | */ |
342 | object::flags_t old_flags = wall->flag; // elmex: this is where C++ pays off |
346 | object::flags_t old_flags = wall->flag; // elmex: this is where C++ pays off |
343 | |
347 | |
344 | wall->destroy (); |
348 | wall->destroy (); |
345 | |
349 | |
346 | wall = arch_to_object (new_arch); |
350 | wall = new_arch->instance (); |
347 | wall->type = BUILDABLE_WALL; |
351 | wall->type = BUILDABLE_WALL; |
348 | insert_ob_in_map_at (wall, map, NULL, INS_ABOVE_FLOOR_ONLY, x, y); |
352 | insert_ob_in_map_at (wall, map, NULL, INS_ABOVE_FLOOR_ONLY, x, y); |
349 | wall->flag = old_flags; |
353 | wall->flag = old_flags; |
350 | } |
354 | } |
351 | |
355 | |
… | |
… | |
389 | /* There was a wall, remove it & keep its archetype to make new walls */ |
393 | /* There was a wall, remove it & keep its archetype to make new walls */ |
390 | new_wall = tmp->arch; |
394 | new_wall = tmp->arch; |
391 | tmp->destroy (); |
395 | tmp->destroy (); |
392 | sprintf (message, "You destroy the wall and redo the floor."); |
396 | sprintf (message, "You destroy the wall and redo the floor."); |
393 | } |
397 | } |
394 | else if ((FLOOR == tmp->type) || (QUERY_FLAG (tmp, FLAG_IS_FLOOR))) |
398 | else if (IS_FLOOR (tmp)) |
395 | { |
399 | { |
396 | tmp->destroy (); |
400 | tmp->destroy (); |
397 | floor_removed = 1; |
401 | floor_removed = 1; |
398 | } |
402 | } |
399 | else |
403 | else |
… | |
… | |
417 | /* Not found, log & bail out */ |
421 | /* Not found, log & bail out */ |
418 | LOG (llevError, "apply_builder_floor: unable to find archetype %s.\n", &material->slaying); |
422 | LOG (llevError, "apply_builder_floor: unable to find archetype %s.\n", &material->slaying); |
419 | return; |
423 | return; |
420 | } |
424 | } |
421 | |
425 | |
422 | tmp = arch_to_object (new_floor); |
426 | tmp = new_floor->instance (); |
423 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
427 | tmp->set_flag (FLAG_IS_BUILDABLE); |
424 | SET_FLAG (tmp, FLAG_UNIQUE); |
428 | tmp->set_flag (FLAG_UNIQUE); |
425 | SET_FLAG (tmp, FLAG_IS_FLOOR); |
429 | tmp->set_flag (FLAG_IS_FLOOR); |
426 | tmp->type = FLOOR; |
430 | //tmp->type = FLOOR; |
427 | insert_ob_in_map_at (tmp, pl->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y); |
431 | insert_ob_in_map_at (tmp, pl->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y); |
428 | |
432 | |
429 | /* |
433 | /* |
430 | * Next step: make sure there are either walls or floors around the new square |
434 | * 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 |
435 | * Since building, you can have: blocking view / floor / wall / nothing |
… | |
… | |
436 | yt = y + freearr_y[i]; |
440 | yt = y + freearr_y[i]; |
437 | tmp = GET_MAP_OB (pl->map, xt, yt); |
441 | tmp = GET_MAP_OB (pl->map, xt, yt); |
438 | if (!tmp) |
442 | if (!tmp) |
439 | { |
443 | { |
440 | /* Must insert floor & wall */ |
444 | /* Must insert floor & wall */ |
441 | tmp = arch_to_object (new_floor); |
445 | tmp = new_floor->instance (); |
442 | /* Better make the floor unique */ |
446 | /* Better make the floor unique */ |
443 | SET_FLAG (tmp, FLAG_UNIQUE); |
447 | tmp->set_flag (FLAG_UNIQUE); |
444 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
448 | tmp->set_flag (FLAG_IS_BUILDABLE); |
445 | tmp->type = FLOOR; |
449 | //tmp->type = FLOOR; |
446 | insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt); |
450 | 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... */ |
451 | /* Insert wall if exists. Note: if it doesn't, the map is weird... */ |
448 | if (new_wall) |
452 | if (new_wall) |
449 | { |
453 | { |
450 | tmp = arch_to_object (new_wall); |
454 | tmp = new_wall->instance (); |
451 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
455 | tmp->set_flag (FLAG_IS_BUILDABLE); |
452 | tmp->type = BUILDABLE_WALL; |
456 | tmp->type = BUILDABLE_WALL; |
453 | insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt); |
457 | insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt); |
454 | } |
458 | } |
455 | } |
459 | } |
456 | } |
460 | } |
… | |
… | |
470 | /* And tell player about the fix */ |
474 | /* And tell player about the fix */ |
471 | new_draw_info (NDI_UNIQUE, 0, pl, message); |
475 | new_draw_info (NDI_UNIQUE, 0, pl, message); |
472 | } |
476 | } |
473 | |
477 | |
474 | /** |
478 | /** |
475 | * Wall radius fix function |
|
|
476 | */ |
|
|
477 | static void |
|
|
478 | fix_walls_around (maptile *map, int x, int y) |
|
|
479 | { |
|
|
480 | for (int xt = x - 1; xt <= x + 1; xt++) |
|
|
481 | for (int yt = y - 1; yt <= y + 1; yt++) |
|
|
482 | if (!OUT_OF_REAL_MAP (map, xt, yt)) |
|
|
483 | fix_walls (map, xt, yt); |
|
|
484 | } |
|
|
485 | |
|
|
486 | /** |
|
|
487 | * Wall building function |
479 | * Wall building function |
488 | * |
480 | * |
489 | * Walls can be build: |
481 | * Walls can be build: |
490 | * - on a floor without anything else |
482 | * - on a floor without anything else |
491 | * - on an existing wall, with or without a floor |
483 | * - on an existing wall, with or without a floor |
… | |
… | |
521 | { |
513 | { |
522 | LOG (llevError, "apply_builder_wall: unable to find archetype %s\n", &material->slaying); |
514 | LOG (llevError, "apply_builder_wall: unable to find archetype %s\n", &material->slaying); |
523 | return; |
515 | return; |
524 | } |
516 | } |
525 | |
517 | |
526 | tmp = arch_to_object (new_wall); |
518 | tmp = new_wall->instance (); |
527 | tmp->type = BUILDABLE_WALL; |
519 | tmp->type = BUILDABLE_WALL; |
528 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
520 | tmp->set_flag (FLAG_IS_BUILDABLE); |
529 | insert_ob_in_map_at (tmp, pl->map, 0, INS_ABOVE_FLOOR_ONLY, x, y); |
521 | insert_ob_in_map_at (tmp, pl->map, 0, INS_ABOVE_FLOOR_ONLY, x, y); |
530 | |
522 | |
531 | /* If existing wall, remove it, no need to fix other walls */ |
523 | /* If existing wall, remove it, no need to fix other walls */ |
532 | if (current_wall) |
524 | if (current_wall) |
533 | { |
525 | { |
… | |
… | |
578 | { |
570 | { |
579 | new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square."); |
571 | new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square."); |
580 | return; |
572 | return; |
581 | } |
573 | } |
582 | |
574 | |
583 | while (floor && (floor->type != FLOOR) && (!QUERY_FLAG (floor, FLAG_IS_FLOOR))) |
575 | while (floor && !IS_FLOOR (floor)) |
584 | floor = floor->above; |
576 | floor = floor->above; |
585 | |
577 | |
586 | if (!floor) |
578 | if (!floor) |
587 | { |
579 | { |
588 | new_draw_info (NDI_UNIQUE, 0, pl, "This square has no floor, you can't build here."); |
580 | new_draw_info (NDI_UNIQUE, 0, pl, "This square has no floor, you can't build here."); |
… | |
… | |
591 | /* Create item, set flag, insert in map */ |
583 | /* Create item, set flag, insert in map */ |
592 | arch = archetype::find (item->slaying); |
584 | arch = archetype::find (item->slaying); |
593 | if (!arch) |
585 | if (!arch) |
594 | return; |
586 | return; |
595 | |
587 | |
596 | tmp = arch_to_object (arch); |
588 | tmp = arch->instance (); |
597 | |
589 | |
598 | if (!floor->flag[FLAG_IS_BUILDABLE] || (floor->above) && (!can_build_over (pl->map, tmp, x, y))) |
590 | if (!floor->flag[FLAG_IS_BUILDABLE] || floor->above && !can_build_over (pl->map, tmp, x, y)) |
599 | /* Floor has something on top that interferes with building */ |
591 | /* Floor has something on top that interferes with building */ |
600 | { |
592 | { |
601 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here."); |
593 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here."); |
602 | return; |
594 | return; |
603 | } |
595 | } |
604 | |
596 | |
605 | SET_FLAG (tmp, FLAG_IS_BUILDABLE); |
597 | tmp->set_flag (FLAG_IS_BUILDABLE); |
606 | SET_FLAG (tmp, FLAG_NO_PICK); |
598 | tmp->set_flag (FLAG_NO_PICK); |
607 | |
599 | |
608 | /* |
600 | /* |
609 | * Str 1 is a flag that the item [pedestal] should go below the floor. |
601 | * Str 1 is a flag that the item [pedestal] should go below the floor. |
610 | * Items under the floor on non-unique maps will not be saved, |
602 | * Items under the floor on non-unique maps will not be saved, |
611 | * so make the item itself unique in this situation. |
603 | * so make the item itself unique in this situation. |
612 | */ |
604 | */ |
613 | insert_flag = ( item->stats.Str == 1 ) ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY; |
605 | insert_flag = item->stats.Str == 1 ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY; |
614 | if (insert_flag == INS_BELOW_ORIGINATOR && !pl->map->no_reset) |
606 | if (insert_flag == INS_BELOW_ORIGINATOR && !pl->map->no_reset) |
615 | SET_FLAG (tmp, FLAG_UNIQUE); |
607 | tmp->set_flag (FLAG_UNIQUE); |
616 | |
608 | |
617 | shstr_tmp connected; |
609 | shstr_tmp connected; |
618 | |
610 | |
619 | switch (tmp->type) |
611 | switch (tmp->type) |
620 | { |
612 | { |
… | |
… | |
682 | new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square."); |
674 | new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square."); |
683 | LOG (llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, &pl->map->path); |
675 | LOG (llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, &pl->map->path); |
684 | return; |
676 | return; |
685 | } |
677 | } |
686 | |
678 | |
687 | if (item->type == FLOOR || QUERY_FLAG (item, FLAG_IS_FLOOR)) |
679 | if (IS_FLOOR (item)) |
688 | item = item->above; |
680 | item = item->above; |
689 | |
681 | |
690 | if (!item) |
682 | if (!item) |
691 | new_draw_info (NDI_UNIQUE, 0, pl, "Nothing to remove."); |
683 | new_draw_info (NDI_UNIQUE, 0, pl, "Nothing to remove."); |
692 | else if (item->type == BUILDABLE_WALL) |
684 | else if (item->type == BUILDABLE_WALL) |
… | |
… | |
707 | * or remover object. |
699 | * or remover object. |
708 | */ |
700 | */ |
709 | void |
701 | void |
710 | apply_map_builder (object *pl, int dir) |
702 | apply_map_builder (object *pl, int dir) |
711 | { |
703 | { |
712 | object *builder; |
704 | object *builder = 0; |
713 | object *tmp; |
705 | object *tmp = 0; |
714 | object *tmp2; |
706 | object *tmp2 = 0; |
715 | int x, y; |
707 | int x, y; |
716 | |
708 | |
717 | if (!pl->type == PLAYER) |
709 | if (!pl->type == PLAYER) |
718 | return; |
710 | return; |
719 | |
711 | |
… | |
… | |
752 | LOG (llevError, "apply_map_builder: undefined square at (%d, %d, %s)\n", x, y, &pl->map->path); |
744 | LOG (llevError, "apply_map_builder: undefined square at (%d, %d, %s)\n", x, y, &pl->map->path); |
753 | new_draw_info (NDI_UNIQUE, 0, pl, "You'd better not build here, it looks weird."); |
745 | new_draw_info (NDI_UNIQUE, 0, pl, "You'd better not build here, it looks weird."); |
754 | return; |
746 | return; |
755 | } |
747 | } |
756 | |
748 | |
|
|
749 | if (INVOKE_PLAYER (BUILD, pl->contr, ARG_OBJECT (builder), ARG_MAP (pl->map), ARG_INT (x), ARG_INT (y))) |
|
|
750 | return; |
|
|
751 | |
757 | tmp2 = find_marked_object (pl); |
752 | tmp2 = find_marked_object (pl); |
758 | while (tmp) |
753 | while (tmp) |
759 | { |
754 | { |
760 | if (!QUERY_FLAG (tmp, FLAG_IS_BUILDABLE) && (tmp->type != SIGN || tmp->arch->archname != shstr_rune_mark)) |
755 | if (!tmp->flag [FLAG_IS_BUILDABLE] && (tmp->type != SIGN || tmp->arch->archname != shstr_rune_mark)) |
761 | { |
756 | { |
762 | /* The item building function already has it's own special |
757 | /* The item building function already has it's own special |
763 | * checks for this |
758 | * checks for this |
764 | */ |
759 | */ |
765 | if ((!tmp2) || (tmp2->subtype != ST_MAT_ITEM)) |
760 | if (!tmp2 || tmp2->subtype != ST_MAT_ITEM) |
766 | { |
761 | { |
767 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here."); |
762 | new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here."); |
768 | return; |
763 | return; |
769 | } |
764 | } |
770 | } |
765 | } |
|
|
766 | |
771 | tmp = tmp->above; |
767 | tmp = tmp->above; |
772 | } |
768 | } |
773 | |
769 | |
774 | /* Now we know the square is ok */ |
770 | /* Now we know the square is ok */ |
775 | builder = pl->contr->ranged_ob; |
771 | builder = pl->contr->ranged_ob; |
… | |
… | |
800 | return; |
796 | return; |
801 | } |
797 | } |
802 | |
798 | |
803 | switch (tmp->subtype) |
799 | switch (tmp->subtype) |
804 | { |
800 | { |
805 | case ST_MAT_FLOOR: |
801 | case ST_MAT_FLOOR: |
806 | apply_builder_floor (pl, tmp, x, y); |
802 | apply_builder_floor (pl, tmp, x, y); |
807 | return; |
803 | return; |
808 | |
804 | |
809 | case ST_MAT_WALL: |
805 | case ST_MAT_WALL: |
810 | apply_builder_wall (pl, tmp, x, y); |
806 | apply_builder_wall (pl, tmp, x, y); |
811 | return; |
807 | return; |
812 | |
808 | |
813 | case ST_MAT_ITEM: |
809 | case ST_MAT_ITEM: |
814 | apply_builder_item (pl, tmp, x, y); |
810 | apply_builder_item (pl, tmp, x, y); |
815 | return; |
811 | return; |
816 | |
812 | |
817 | default: |
813 | default: |
818 | new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this material, sorry."); |
814 | new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this material, sorry."); |
819 | LOG (llevError, "apply_map_builder: invalid material subtype %d\n", tmp->subtype); |
815 | LOG (llevError, "apply_map_builder: invalid material subtype %d\n", tmp->subtype); |
820 | return; |
816 | return; |
821 | } |
817 | } |
822 | } |
818 | } |
823 | |
819 | |
824 | /* Here, it means the builder has an invalid type */ |
820 | /* Here, it means the builder has an invalid type */ |
825 | new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this tool, sorry."); |
821 | new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this tool, sorry."); |