ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/build_map.C
Revision: 1.1
Committed: Sun Aug 13 17:16:03 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

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