ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/build_map.C
Revision: 1.28
Committed: Sun Jul 1 05:00:19 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.27: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# Content
1 /*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 *
4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5 * Copyright (©) 2001,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Crossfire TRT is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 */
23
24 #include <global.h>
25 #include <living.h>
26 #include <spells.h>
27 #include <skills.h>
28 #include <tod.h>
29 #include <sproto.h>
30
31 /**
32 * Check if objects on a square interfere with building
33 */
34 int
35 can_build_over (maptile *map, object *tmp, short x, short y)
36 {
37 object *ob;
38
39 ob = GET_MAP_OB (map, x, y);
40 while (ob)
41 {
42 /* if ob is not a marking rune or floor, then check special cases */
43 if (strcmp (ob->arch->archname, "rune_mark") && ob->type != FLOOR)
44 {
45 switch (tmp->type)
46 {
47 case SIGN:
48 case MAGIC_EAR:
49 /* Allow signs and magic ears to be built on books */
50 if (ob->type != BOOK)
51 {
52 return 0;
53 }
54 break;
55 case BUTTON:
56 case DETECTOR:
57 case PEDESTAL:
58 case CF_HANDLE:
59 /* Allow buttons and levers to be built under gates */
60 if (ob->type != GATE && ob->type != DOOR)
61 {
62 return 0;
63 }
64 break;
65 default:
66 return 0;
67 }
68 }
69 ob = ob->above;
70 }
71 return 1;
72 }
73
74 /**
75 * Erases marking runes at specified location
76 */
77 void
78 remove_marking_runes (maptile *map, short x, short y)
79 {
80 object *rune;
81 object *next;
82
83 rune = GET_MAP_OB (map, x, y);
84 while (rune)
85 {
86 next = rune->above;
87
88 if ((rune->type == SIGN) && (!strcmp (rune->arch->archname, "rune_mark")))
89 rune->destroy ();
90
91 rune = next;
92 }
93 }
94
95 /**
96 * Returns an unused value for 'connected'.
97 * \param map: map for which to find a value
98 * \return 'connected' value with no item, or -1 if failure.
99 *
100 * Tries 1000 random values, then returns -1.
101 */
102 int
103 find_unused_connected_value (maptile *map)
104 {
105 int connected = 0;
106 int itest = 0;
107 oblinkpt *obp;
108
109 while (itest++ < 1000)
110 {
111 connected = 1 + rand () % 20000;
112 for (obp = map->buttons; obp && (obp->value != connected); obp = obp->next);
113
114 if (!obp)
115 return connected;
116 }
117
118 return -1;
119 }
120
121
122 /**
123 * Helper function for door/button/connected item building.
124 *
125 * Will search the specified spot for a marking rune.
126 * If not found, returns -1
127 * Else, searches a force in op's inventory matching the map's name
128 * and the rune's text.
129 * If found, returns the connection value associated
130 * else searches a new connection value, and adds the force to the player.
131 */
132 int
133 find_or_create_connection_for_map (object *pl, short x, short y, object *rune)
134 {
135 object *force;
136 int connected;
137
138 if (!rune)
139 rune = get_connection_rune (pl, x, y);
140
141 if (!rune)
142 {
143 new_draw_info (NDI_UNIQUE, 0, pl, "You need to put a marking rune with the group name.");
144 return -1;
145 }
146
147 /* Now, find force in player's inventory */
148 force = pl->inv;
149 while (force
150 && ((force->type != FORCE) || !force->slaying || force->slaying != pl->map->path || !force->msg
151 || force->msg != rune->msg))
152 force = force->below;
153
154 if (!force)
155 /* No force, need to create & insert one */
156 {
157 /* Find unused value */
158 connected = find_unused_connected_value (pl->map);
159 if (connected == -1)
160 {
161 new_draw_info (NDI_UNIQUE, 0, pl, "Could not create more groups.");
162 return -1;
163 }
164
165 force = get_archetype (FORCE_NAME);
166 force->slaying = pl->map->path;
167 force->msg = rune->msg;
168 force->path_attuned = connected;
169 force->set_speed (0);
170 insert_ob_in_ob (force, pl);
171
172 return connected;
173 }
174
175 /* Found the force, everything's easy. */
176 return force->path_attuned;
177 }
178
179 /**
180 * Returns the marking rune on the square, for purposes of building connections
181 */
182 object *
183 get_connection_rune (object *pl, short x, short y)
184 {
185 object *rune;
186
187 rune = GET_MAP_OB (pl->map, x, y);
188 while (rune && ((rune->type != SIGN) || (strcmp (rune->arch->archname, "rune_mark"))))
189 rune = rune->above;
190 return rune;
191 }
192
193 /**
194 * Returns the book/scroll on the current square, for purposes of building
195 */
196 object *
197 get_msg_book (object *pl, short x, short y)
198 {
199 object *book;
200
201 book = GET_MAP_OB (pl->map, x, y);
202 while (book && (book->type != BOOK))
203 book = book->above;
204 return book;
205 }
206
207 /**
208 * Returns first item of type BUILDABLE_WALL.
209 */
210 object *
211 get_wall (maptile *map, int x, int y)
212 {
213 object *wall;
214
215 wall = GET_MAP_OB (map, x, y);
216 while (wall && (BUILDABLE_WALL != wall->type))
217 wall = wall->above;
218
219 return wall;
220 }
221
222 /**
223 * Fixes walls around specified spot
224 *
225 * \param map is the map
226 * \param x
227 * \param y are the position to fix
228 *
229 * Basically it ensures the correct wall is put where needed.
230 *
231 * Note: x & y must be valid map coordinates.
232 */
233 void
234 fix_walls (maptile *map, int x, int y)
235 {
236 object *wall;
237 char archetype[MAX_BUF];
238 char *underscore;
239 struct archetype *new_arch;
240
241
242 /* First, find the wall on that spot */
243 wall = get_wall (map, x, y);
244 if (!wall)
245 /* Nothing -> bail out */
246 return;
247
248 /* Find base name */
249 assign (archetype, wall->arch->archname);
250 underscore = strchr (archetype, '_');
251
252 /* search for the first _ before a number */
253 while (underscore && !isdigit (*(underscore + 1)))
254 underscore = strchr (underscore + 1, '_');
255
256 if (!underscore || !isdigit (*(underscore + 1)))
257 /* Not in a format we can change, bail out */
258 return;
259
260 underscore++;
261 *underscore = '\0';
262
263 int connect = 0;
264
265 if ((x > 0) && get_wall (map, x - 1, y))
266 connect |= 1;
267 if ((x < map->width - 1) && get_wall (map, x + 1, y))
268 connect |= 2;
269
270 if ((y > 0) && get_wall (map, x, y - 1))
271 connect |= 4;
272
273 if ((y < map->height - 1) && get_wall (map, x, y + 1))
274 connect |= 8;
275
276 switch (connect)
277 {
278 case 0:
279 strcat (archetype, "0");
280
281 break;
282 case 1:
283 strcat (archetype, "1_3");
284
285 break;
286 case 2:
287 strcat (archetype, "1_4");
288
289 break;
290 case 3:
291 strcat (archetype, "2_1_2");
292
293 break;
294 case 4:
295 strcat (archetype, "1_2");
296
297 break;
298 case 5:
299 strcat (archetype, "2_2_4");
300
301 break;
302 case 6:
303 strcat (archetype, "2_2_1");
304
305 break;
306 case 7:
307 strcat (archetype, "3_1");
308
309 break;
310 case 8:
311 strcat (archetype, "1_1");
312
313 break;
314 case 9:
315 strcat (archetype, "2_2_3");
316
317 break;
318 case 10:
319 strcat (archetype, "2_2_2");
320
321 break;
322 case 11:
323 strcat (archetype, "3_3");
324
325 break;
326 case 12:
327 strcat (archetype, "2_1_1");
328
329 break;
330 case 13:
331 strcat (archetype, "3_4");
332
333 break;
334 case 14:
335 strcat (archetype, "3_2");
336
337 break;
338 case 15:
339 strcat (archetype, "4");
340
341 break;
342 }
343
344 /*
345 * Before anything, make sure the archetype does exist...
346 * If not, prolly an error...
347 */
348 new_arch = archetype::find (archetype);
349
350 if (!new_arch)
351 return;
352
353 /* Now delete current wall, and insert new one
354 * We save flags to avoid any trouble with buildable/non buildable, and so on
355 */
356 object::flags_t old_flags = wall->flag; // elmex: this is where C++ pays off
357
358 wall->destroy ();
359
360 wall = arch_to_object (new_arch);
361 wall->type = BUILDABLE_WALL;
362 insert_ob_in_map_at (wall, map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
363 wall->flag = old_flags;
364 }
365
366 /**
367 * \brief Floor building function
368 *
369 * Floors can be build:
370 * - on existing floors, with or without a detector/button
371 * - on an existing wall, with or without a floor under it
372 *
373 * Note: this function will inconditionally change squares around (x, y)
374 * so don't call it with x == 0 for instance!
375 */
376 void
377 apply_builder_floor (object *pl, object *material, short x, short y)
378 {
379 object *tmp, *above;
380 object *above_floor; /* Item above floor, if any */
381 struct archetype *new_floor;
382 struct archetype *new_wall;
383 int i, xt, yt, floor_removed;
384 char message[MAX_BUF];
385
386 sprintf (message, "You change the floor to better suit your tastes.");
387
388 /*
389 * Now the building part...
390 * First, remove wall(s) and floor(s) at position x, y
391 */
392 above_floor = NULL;
393 new_wall = NULL;
394 floor_removed = 0;
395 tmp = GET_MAP_OB (pl->map, x, y);
396 if (tmp)
397 {
398 while (tmp)
399 {
400 above = tmp->above;
401 if (BUILDABLE_WALL == tmp->type)
402 {
403 /* There was a wall, remove it & keep its archetype to make new walls */
404 new_wall = tmp->arch;
405 tmp->destroy ();
406 sprintf (message, "You destroy the wall and redo the floor.");
407 }
408 else if ((FLOOR == tmp->type) || (QUERY_FLAG (tmp, FLAG_IS_FLOOR)))
409 {
410 tmp->destroy ();
411 floor_removed = 1;
412 }
413 else
414 {
415 if (floor_removed)
416 above_floor = tmp;
417 }
418
419 tmp = above;
420 }
421 }
422
423 /* Now insert our floor */
424 new_floor = archetype::find (material->slaying);
425 if (!new_floor)
426 {
427 /* Not found, log & bail out */
428 LOG (llevError, "apply_builder_floor: unable to find archetype %s.\n", &material->slaying);
429 return;
430 }
431
432 tmp = arch_to_object (new_floor);
433 SET_FLAG (tmp, FLAG_IS_BUILDABLE);
434 SET_FLAG (tmp, FLAG_UNIQUE);
435 SET_FLAG (tmp, FLAG_IS_FLOOR);
436 tmp->type = FLOOR;
437 insert_ob_in_map_at (tmp, pl->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y);
438
439 /*
440 * Next step: make sure there are either walls or floors around the new square
441 * Since building, you can have: blocking view / floor / wall / nothing
442 */
443 for (i = 1; i <= 8; i++)
444 {
445 xt = x + freearr_x[i];
446 yt = y + freearr_y[i];
447 tmp = GET_MAP_OB (pl->map, xt, yt);
448 if (!tmp)
449 {
450 /* Must insert floor & wall */
451 tmp = arch_to_object (new_floor);
452 /* Better make the floor unique */
453 SET_FLAG (tmp, FLAG_UNIQUE);
454 SET_FLAG (tmp, FLAG_IS_BUILDABLE);
455 tmp->type = FLOOR;
456 insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt);
457 /* Insert wall if exists. Note: if it doesn't, the map is weird... */
458 if (new_wall)
459 {
460 tmp = arch_to_object (new_wall);
461 SET_FLAG (tmp, FLAG_IS_BUILDABLE);
462 tmp->type = BUILDABLE_WALL;
463 insert_ob_in_map_at (tmp, pl->map, 0, 0, xt, yt);
464 }
465 }
466 }
467
468 /* Finally fixing walls to ensure nice continuous walls
469 * Note: 2 squares around are checked, because potentially we added walls around the building
470 * spot, so need to check that those new walls connect correctly
471 */
472 for (xt = x - 2; xt <= x + 2; xt++)
473 for (yt = y - 2; yt <= y + 2; yt++)
474 {
475 if (!OUT_OF_REAL_MAP (pl->map, xt, yt))
476 fix_walls (pl->map, xt, yt);
477 }
478
479 /* Now remove raw item from inventory */
480 decrease_ob (material);
481
482 /* And tell player about the fix */
483 new_draw_info (NDI_UNIQUE, 0, pl, message);
484 }
485
486 /**
487 * Wall radius fix function
488 */
489 void fix_walls_around (maptile *map, int x, int y)
490 {
491 for (int xt = x - 1; xt <= x + 1; xt++)
492 for (int yt = y - 1; yt <= y + 1; yt++)
493 {
494 if (OUT_OF_REAL_MAP (map, xt, yt))
495 continue;
496
497 fix_walls (map, xt, yt);
498 }
499 }
500
501 /**
502 * Wall building function
503 *
504 * Walls can be build:
505 * - on a floor without anything else
506 * - on an existing wall, with or without a floor
507 */
508 void
509 apply_builder_wall (object *pl, object *material, short x, short y)
510 {
511 object *current_wall;
512 object *tmp;
513 int xt, yt;
514 struct archetype *new_wall;
515 char message[MAX_BUF];
516
517 remove_marking_runes (pl->map, x, y);
518
519 /* Grab existing wall, if any */
520 current_wall = NULL;
521 tmp = GET_MAP_OB (pl->map, x, y);
522 while (tmp && !current_wall)
523 {
524 if (BUILDABLE_WALL == tmp->type)
525 current_wall = tmp;
526
527 tmp = tmp->above;
528 }
529
530 /* Find the raw wall in inventory */
531 sprintf (message, "You build a wall.");
532
533 /* Now we can actually insert the wall */
534 new_wall = archetype::find (material->slaying);
535 if (!new_wall)
536 {
537 LOG (llevError, "apply_builder_wall: unable to find archetype %s\n", &material->slaying);
538 return;
539 }
540
541 tmp = arch_to_object (new_wall);
542 tmp->type = BUILDABLE_WALL;
543 SET_FLAG (tmp, FLAG_IS_BUILDABLE);
544 insert_ob_in_map_at (tmp, pl->map, 0, INS_ABOVE_FLOOR_ONLY, x, y);
545
546 /* If existing wall, remove it, no need to fix other walls */
547 if (current_wall)
548 {
549 current_wall->destroy ();
550 fix_walls (pl->map, x, y);
551 sprintf (message, "You redecorate the wall to better suit your tastes.");
552 }
553 else
554 {
555 /* Else fix all walls around */
556 for (xt = x - 1; xt <= x + 1; xt++)
557 for (yt = y - 1; yt <= y + 1; yt++)
558 {
559 if (OUT_OF_REAL_MAP (pl->map, xt, yt))
560 continue;
561
562 fix_walls (pl->map, xt, yt);
563 }
564 }
565
566 /* Now remove item from inventory */
567 decrease_ob (material);
568
569 /* And tell player what happened */
570 new_draw_info (NDI_UNIQUE, 0, pl, message);
571 }
572
573 /**
574 * Generic item builder.
575 *
576 * Item must be put on a square with a floor, you can have something under.
577 * Archetype of created object is item->slaying (raw material).
578 * Type of inserted item is tested for specific cases (doors & such).
579 * Item is inserted above the floor, unless Str == 1 (only for detectors i guess)
580 */
581 void
582 apply_builder_item (object *pl, object *item, short x, short y)
583 {
584 object *tmp;
585 struct archetype *arch;
586 int insert_flag;
587 object *floor;
588 object *con_rune;
589 int connected;
590
591 /* Find floor */
592 floor = GET_MAP_OB (pl->map, x, y);
593 if (!floor)
594 {
595 new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square.");
596 return;
597 }
598
599 while (floor && (floor->type != FLOOR) && (!QUERY_FLAG (floor, FLAG_IS_FLOOR)))
600 floor = floor->above;
601
602 if (!floor)
603 {
604 new_draw_info (NDI_UNIQUE, 0, pl, "This square has no floor, you can't build here.");
605 return;
606 }
607 /* Create item, set flag, insert in map */
608 arch = archetype::find (item->slaying);
609 if (!arch)
610 return;
611
612 tmp = arch_to_object (arch);
613
614 if ((floor->above) && (!can_build_over (pl->map, tmp, x, y)))
615 /* Floor has something on top that interferes with building */
616 {
617 new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here.");
618 return;
619 }
620
621 SET_FLAG (tmp, FLAG_IS_BUILDABLE);
622 SET_FLAG (tmp, FLAG_NO_PICK);
623
624 /*
625 * This doesn't work on non unique maps. pedestals under floor will not be saved...
626 insert_flag = ( item->stats.Str == 1 ) ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY;
627 */
628 insert_flag = INS_ABOVE_FLOOR_ONLY;
629
630 connected = 0;
631 switch (tmp->type)
632 {
633 case DOOR:
634 case GATE:
635 case BUTTON:
636 case DETECTOR:
637 case TIMED_GATE:
638 case PEDESTAL:
639 case CF_HANDLE:
640 case MAGIC_EAR:
641 case SIGN:
642 /* Signs don't need a connection, but but magic mouths do. */
643 if (tmp->type == SIGN && strcmp (tmp->arch->archname, "magic_mouth"))
644 break;
645 con_rune = get_connection_rune (pl, x, y);
646 connected = find_or_create_connection_for_map (pl, x, y, con_rune);
647 if (connected == -1)
648 {
649 /* Player already informed of failure by the previous function */
650 tmp->destroy ();
651 return;
652 }
653 /* Remove marking rune */
654 con_rune->destroy ();
655 }
656
657 /* For magic mouths/ears, and signs, take the msg from a book of scroll */
658 if ((tmp->type == SIGN) || (tmp->type == MAGIC_EAR))
659 {
660 if (adjust_sign_msg (pl, x, y, tmp) == -1)
661 {
662 tmp->destroy ();
663 return;
664 }
665 }
666
667 insert_ob_in_map_at (tmp, pl->map, floor, insert_flag, x, y);
668 if (connected != 0)
669 add_button_link (tmp, pl->map, connected);
670
671 new_draw_info_format (NDI_UNIQUE, 0, pl, "You build the %s", query_name (tmp));
672 decrease_ob_nr (item, 1);
673 }
674
675 /**
676 * Item remover.
677 *
678 * Removes first buildable item, either under or above the floor
679 */
680 void
681 apply_builder_remove (object *pl, int dir)
682 {
683 object *item;
684 short x, y;
685
686 x = pl->x + freearr_x[dir];
687 y = pl->y + freearr_y[dir];
688
689 /* Check square */
690 item = GET_MAP_OB (pl->map, x, y);
691 if (!item)
692 {
693 /* Should not happen with previous tests, but we never know */
694 new_draw_info (NDI_UNIQUE, 0, pl, "Invalid square.");
695 LOG (llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, &pl->map->path);
696 return;
697 }
698
699 if (item->type == FLOOR || QUERY_FLAG (item, FLAG_IS_FLOOR))
700 item = item->above;
701
702 if (!item)
703 new_draw_info (NDI_UNIQUE, 0, pl, "Nothing to remove.");
704 else if (item->type == BUILDABLE_WALL)
705 new_draw_info (NDI_UNIQUE, 0, pl, "Can't remove a wall with that, build a floor.");
706 else if (!item->flag [FLAG_IS_BUILDABLE])
707 new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't remove the %s, it's not buildable!", query_name (item));
708 else
709 {
710 new_draw_info_format (NDI_UNIQUE, 0, pl, "You remove the %s", query_name (item));
711 item->destroy ();
712 }
713 }
714
715 /**
716 * Global building function
717 *
718 * This is the general map building function. Called when the player 'fires' a builder
719 * or remover object.
720 */
721 void
722 apply_map_builder (object *pl, int dir)
723 {
724 object *builder;
725 object *tmp;
726 object *tmp2;
727 short x, y;
728
729 if (!pl->type == PLAYER)
730 return;
731
732 /*if ( !player->map->unique )
733 {
734 new_draw_info( NDI_UNIQUE, 0, player, "You can't build outside a unique map." );
735 return;
736 } */
737
738 if (dir == 0)
739 {
740 new_draw_info (NDI_UNIQUE, 0, pl, "You can't build or destroy under yourself.");
741 return;
742 }
743
744 x = pl->x + freearr_x[dir];
745 y = pl->y + freearr_y[dir];
746
747 if ((1 > x) || (1 > y) || ((pl->map->width - 2) < x) || ((pl->map->height - 2) < y))
748 {
749 new_draw_info (NDI_UNIQUE, 0, pl, "Can't build on map edge...");
750 return;
751 }
752
753 /*
754 * Check specified square
755 * The square must have only buildable items
756 * Exception: marking runes are all right,
757 * since they are used for special things like connecting doors / buttons
758 */
759
760 tmp = GET_MAP_OB (pl->map, x, y);
761 if (!tmp)
762 {
763 /* Nothing, meaning player is standing next to an undefined square... */
764 LOG (llevError, "apply_map_builder: undefined square at (%d, %d, %s)\n", x, y, &pl->map->path);
765 new_draw_info (NDI_UNIQUE, 0, pl, "You'd better not build here, it looks weird.");
766 return;
767 }
768
769 tmp2 = find_marked_object (pl);
770 while (tmp)
771 {
772 if (!QUERY_FLAG (tmp, FLAG_IS_BUILDABLE) && ((tmp->type != SIGN) || (strcmp (tmp->arch->archname, "rune_mark"))))
773 {
774 /* The item building function already has it's own special
775 * checks for this
776 */
777 if ((!tmp2) || (tmp2->subtype != ST_MAT_ITEM))
778 {
779 new_draw_info (NDI_UNIQUE, 0, pl, "You can't build here.");
780 return;
781 }
782 }
783 tmp = tmp->above;
784 }
785
786 /* Now we know the square is ok */
787 builder = pl->contr->ranged_ob;
788
789 if (builder->subtype == ST_BD_REMOVE)
790 /* Remover -> call specific function and bail out */
791 {
792 apply_builder_remove (pl, dir);
793 return;
794 }
795
796 if (builder->subtype == ST_BD_BUILD)
797 /*
798 * Builder.
799 * Find marked item to build, call specific function
800 */
801 {
802 tmp = tmp2;
803 if (!tmp)
804 {
805 new_draw_info (NDI_UNIQUE, 0, pl, "You need to mark raw materials to use.");
806 return;
807 }
808
809 if (tmp->type != MATERIAL)
810 {
811 new_draw_info (NDI_UNIQUE, 0, pl, "You can't use the marked item to build.");
812 return;
813 }
814
815 switch (tmp->subtype)
816 {
817 case ST_MAT_FLOOR:
818 apply_builder_floor (pl, tmp, x, y);
819 return;
820
821 case ST_MAT_WALL:
822 apply_builder_wall (pl, tmp, x, y);
823 return;
824
825 case ST_MAT_ITEM:
826 apply_builder_item (pl, tmp, x, y);
827 return;
828
829 default:
830 new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this material, sorry.");
831 LOG (llevError, "apply_map_builder: invalid material subtype %d\n", tmp->subtype);
832 return;
833 }
834 }
835
836 /* Here, it means the builder has an invalid type */
837 new_draw_info (NDI_UNIQUE, 0, pl, "Don't know how to apply this tool, sorry.");
838 LOG (llevError, "apply_map_builder: invalid builder subtype %d\n", builder->subtype);
839 }
840
841 /**
842 * Make the built object inherit the msg of books that are used with it.
843 * For objects already invisible (i.e. magic mouths & ears), also make it
844 * it inherit the face and the name with "talking " prepended.
845 */
846 int
847 adjust_sign_msg (object *pl, short x, short y, object *tmp)
848 {
849 object *book;
850 char buf[MAX_BUF];
851 char buf2[MAX_BUF];
852
853 book = get_msg_book (pl, x, y);
854 if (!book)
855 {
856 new_draw_info (NDI_UNIQUE, 0, pl, "You need to put a book or scroll with the message.");
857 return -1;
858 }
859
860 tmp->msg = book->msg;
861
862 if (tmp->invisible)
863 {
864 if (book->custom_name != NULL)
865 {
866 snprintf (buf, sizeof (buf), "talking %s", &book->custom_name);
867 }
868 else
869 {
870 snprintf (buf, sizeof (buf), "talking %s", &book->name);
871 }
872 tmp->name = buf;
873
874 if (book->name_pl != NULL)
875 {
876 snprintf (buf2, sizeof (buf2), "talking %s", &book->name_pl);
877 tmp->name_pl = buf2;
878 }
879
880 tmp->face = book->face;
881 tmp->invisible = 0;
882 }
883
884 book->destroy ();
885 return 0;
886 }