Crossfire Server, Branch 1.12  R12190
build_map.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_build_map =
00003  *   "$Id: build_map.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 /*
00006     CrossFire, A Multiplayer game for X-windows
00007 
00008     Copyright (C) 2001-2006 Mark Wedel & Crossfire Development Team
00009     Copyright (C) 1992 Frank Tore Johansen
00010 
00011     This program is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     This program is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU General Public License for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with this program; if not, write to the Free Software
00023     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 
00025     The authors can be reached via e-mail to crossfire-devel@real-time.com
00026 */
00027 
00037 #include <global.h>
00038 #include <living.h>
00039 #include <spells.h>
00040 #include <skills.h>
00041 #include <tod.h>
00042 #include <sproto.h>
00043 
00057 static int can_build_over(struct mapdef *map, object *new_item, short x, short y) {
00058     object *ob;
00059 
00060     for (ob = GET_MAP_OB(map, x, y); ob; ob = ob->above) {
00061         if (strcmp(ob->arch->name, "rune_mark") == 0)
00062             /* you can always build on marking runes, used for connected building things. */
00063             continue;
00064 
00065         if ((ob->head && QUERY_FLAG(ob->head, FLAG_IS_BUILDABLE)) || (!ob->head && QUERY_FLAG(ob, FLAG_IS_BUILDABLE)))
00066             /* Check for the flag is required, as this function
00067              * can be called recursively on different spots.
00068              */
00069             continue;
00070 
00071         switch (new_item->type) {
00072         case SIGN:
00073         case MAGIC_EAR:
00074             /* Allow signs and magic ears to be built on books */
00075             if (ob->type != BOOK)
00076                 return 0;
00077             break;
00078 
00079         case BUTTON:
00080         case DETECTOR:
00081         case PEDESTAL:
00082         case CF_HANDLE:
00083             /* Allow buttons and levers to be built under gates */
00084             if (ob->type != GATE && ob->type != DOOR)
00085                 return 0;
00086             break;
00087 
00088         default:
00089             return 0;
00090         }
00091     }
00092 
00093     /* If item being built is multi-tile, need to check other parts too. */
00094     if (new_item->more)
00095         return can_build_over(map, new_item->more, x+new_item->more->arch->clone.x-new_item->arch->clone.x, y+new_item->more->arch->clone.y-new_item->arch->clone.y);
00096 
00097     return 1;
00098 }
00099 
00111 static object *get_connection_rune(object *pl, short x, short y) {
00112     object *rune;
00113 
00114     rune = GET_MAP_OB(pl->map, x, y);
00115     while (rune && ((rune->type != SIGN) || (strcmp(rune->arch->name, "rune_mark"))))
00116         rune = rune->above;
00117     return rune;
00118 }
00119 
00131 static object *get_msg_book(object *pl, short x, short y) {
00132     object *book;
00133 
00134     book = GET_MAP_OB(pl->map, x, y);
00135     while (book && (book->type != BOOK))
00136         book = book->above;
00137     return book;
00138 }
00139 
00152 static object *get_wall(struct mapdef *map, int x, int y) {
00153     object *wall;
00154 
00155     wall = GET_MAP_OB(map, x, y);
00156     while (wall && (wall->type != WALL))
00157         wall = wall->above;
00158 
00159     return wall;
00160 }
00161 
00170 static void remove_marking_runes(struct mapdef *map, short x, short y) {
00171     object *rune;
00172     object *next;
00173 
00174     rune = GET_MAP_OB(map, x, y);
00175     while (rune) {
00176         next = rune->above;
00177         if ((rune->type == SIGN) && (!strcmp(rune->arch->name, "rune_mark"))) {
00178             remove_ob(rune);
00179             free_object(rune);
00180         }
00181         rune = next;
00182     }
00183 }
00184 
00202 static int adjust_sign_msg(object *pl, short x, short y, object *tmp) {
00203     object *book;
00204     char buf[MAX_BUF];
00205     char buf2[MAX_BUF];
00206 
00207     book = get_msg_book(pl, x, y);
00208     if (!book) {
00209         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00210                       "You need to put a book or scroll with the message.", NULL);
00211         return -1;
00212     }
00213 
00214     tmp->msg = book->msg;
00215     add_refcount(tmp->msg);
00216 
00217     if (tmp->invisible) {
00218         if (book->custom_name != NULL) {
00219             snprintf(buf, sizeof(buf), "talking %s", book->custom_name);
00220         } else {
00221             snprintf(buf, sizeof(buf), "talking %s", book->name);
00222         }
00223         if (tmp->name)
00224             free_string(tmp->name);
00225         tmp->name = add_string(buf);
00226 
00227         if (book->name_pl != NULL) {
00228             snprintf(buf2, sizeof(buf2), "talking %s", book->name_pl);
00229             if (tmp->name_pl)
00230                 free_string(tmp->name_pl);
00231             tmp->name_pl = add_string(buf2);
00232         }
00233 
00234         tmp->face = book->face;
00235         tmp->invisible = 0;
00236     }
00237     remove_ob(book);
00238     free_object(book);
00239     return 0;
00240 }
00241 
00252 static int find_unused_connected_value(struct mapdef *map) {
00253     int connected = 0;
00254     int itest = 0;
00255     oblinkpt *obp;
00256 
00257     while (itest++ < 1000) {
00258         connected = 1+rand()%20000;
00259         for (obp = map->buttons; obp && (obp->value != connected); obp = obp->next)
00260             ;
00261 
00262         if (!obp)
00263             return connected;
00264     }
00265 
00266     return -1;
00267 }
00268 
00269 
00290 static int find_or_create_connection_for_map(object *pl, short x, short y, object *rune) {
00291     object *force;
00292     int connected;
00293 
00294     if (!rune)
00295         rune = get_connection_rune(pl, x, y);
00296 
00297     if (!rune || !rune->msg) {
00298         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00299                       "You need to put a marking rune with the group name.", NULL);
00300         return -1;
00301     }
00302 
00303     /* Now, find force in player's inventory */
00304     force = pl->inv;
00305     while (force && ((force->type != FORCE) || (!force->slaying) || (strcmp(force->slaying, pl->map->path)) || (!force->msg) || (strcmp(force->msg, rune->msg))))
00306         force = force->below;
00307 
00308     if (!force) {
00309         /* No force, need to create & insert one */
00310         /* Find unused value */
00311         connected = find_unused_connected_value(pl->map);
00312         if (connected == -1) {
00313             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00314                           "Could not create more groups.", NULL);
00315             return -1;
00316         }
00317 
00318         force = create_archetype(FORCE_NAME);
00319         force->speed = 0;
00320         update_ob_speed(force);
00321         force->slaying = add_string(pl->map->path);
00322         force->msg = add_string(rune->msg);
00323         force->path_attuned = connected;
00324         insert_ob_in_ob(force, pl);
00325 
00326         return connected;
00327     }
00328 
00329     /* Found the force, everything's easy. */
00330     return force->path_attuned;
00331 }
00332 
00348 static void fix_walls(struct mapdef *map, int x, int y) {
00349     int connect;
00350     object *wall;
00351     char archetype[MAX_BUF];
00352     char *underscore;
00353     uint32 old_flags[4];
00354     struct archt *new_arch;
00355     int flag;
00356     int len;
00357     int has_window;
00358 
00359     /* First, find the wall on that spot */
00360     wall = get_wall(map, x, y);
00361     if (!wall)
00362         /* Nothing -> bail out */
00363         return;
00364 
00365     /* Find base name */
00366     strncpy(archetype, wall->arch->name, sizeof(archetype));
00367     archetype[sizeof(archetype)-1] = '\0';
00368     underscore = strchr(archetype, '_');
00369     if (!underscore)
00370         /* Not in a format we can change, bail out */
00371         return;
00372     has_window = 0;
00373     if (!strcmp(underscore+1, "win1"))
00374         has_window = 1;
00375     else if (!strcmp(underscore+1, "win2"))
00376         has_window = 1;
00377     else if (!isdigit(*(underscore+1)))
00378         return;
00379 
00380     underscore++;
00381     *underscore = '\0';
00382     len = sizeof(archetype)-strlen(archetype)-2;
00383 
00384     connect = 0;
00385 
00386     if ((x > 0) && get_wall(map, x-1, y))
00387         connect |= 1;
00388     if ((x < MAP_WIDTH(map)-1) && get_wall(map, x+1, y))
00389         connect |= 2;
00390     if ((y > 0) && get_wall(map, x, y-1))
00391         connect |= 4;
00392     if ((y < MAP_HEIGHT(map)-1) && get_wall(map, x, y+1))
00393         connect |= 8;
00394 
00395     switch (connect) {
00396     case 0:
00397         strncat(archetype, "0", len);
00398         break;
00399 
00400     case 1:
00401         strncat(archetype, "1_3", len);
00402         break;
00403 
00404     case 2:
00405         strncat(archetype, "1_4", len);
00406         break;
00407 
00408     case 3:
00409         if (has_window) {
00410             strncat(archetype, "win2", len);
00411         } else {
00412             strncat(archetype, "2_1_2", len);
00413         }
00414         break;
00415 
00416     case 4:
00417         strncat(archetype, "1_2", len);
00418         break;
00419 
00420     case 5:
00421         strncat(archetype, "2_2_4", len);
00422         break;
00423 
00424     case 6:
00425         strncat(archetype, "2_2_1", len);
00426         break;
00427 
00428     case 7:
00429         strncat(archetype, "3_1", len);
00430         break;
00431 
00432     case 8:
00433         strncat(archetype, "1_1", len);
00434         break;
00435 
00436     case 9:
00437         strncat(archetype, "2_2_3", len);
00438         break;
00439 
00440     case 10:
00441         strncat(archetype, "2_2_2", len);
00442         break;
00443 
00444     case 11:
00445         strncat(archetype, "3_3", len);
00446         break;
00447 
00448     case 12:
00449         if (has_window) {
00450             strncat(archetype, "win1", len);
00451         } else {
00452             strncat(archetype, "2_1_1", len);
00453         }
00454         break;
00455 
00456     case 13:
00457         strncat(archetype, "3_4", len);
00458         break;
00459 
00460     case 14:
00461         strncat(archetype, "3_2", len);
00462         break;
00463 
00464     case 15:
00465         strncat(archetype, "4", len);
00466         break;
00467     }
00468 
00469     /*
00470      * No need to change anything if the old and new names are identical.
00471      */
00472     if (!strncmp(archetype, wall->arch->name, sizeof(archetype)))
00473         return;
00474 
00475     /*
00476      * Before anything, make sure the archetype does exist...
00477      * If not, prolly an error...
00478      */
00479     new_arch = find_archetype(archetype);
00480     if (!new_arch)
00481         return;
00482 
00483     /* Now delete current wall, and insert new one
00484      * We save flags to avoid any trouble with buildable/non buildable, and so on
00485      */
00486     for (flag = 0; flag < 4; flag++)
00487         old_flags[flag] = wall->flags[flag];
00488     remove_ob(wall);
00489     free_object(wall);
00490 
00491     wall = arch_to_object(new_arch);
00492     wall->type = WALL;
00493     insert_ob_in_map_at(wall, map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
00494     for (flag = 0; flag < 4; flag++)
00495         wall->flags[flag] = old_flags[flag];
00496 }
00497 
00519 static int apply_builder_floor(object *pl, object *new_floor, short x, short y) {
00520     object *tmp;
00521     object *above_floor; /* Item above floor, if any */
00522     object *floor;       /* Floor which would be removed if required */
00523     struct archt *new_wall;
00524     int i, xt, yt, wall_removed;
00525     char message[MAX_BUF];
00526 
00527     snprintf(message, sizeof(message), "You change the floor to better suit your tastes.");
00528 
00529     /*
00530      * Now the building part...
00531      * First, remove wall(s) and floor(s) at position x, y
00532      */
00533     above_floor = NULL;
00534     floor = NULL;
00535     new_wall = NULL;
00536     wall_removed = 0;
00537     tmp = GET_MAP_OB(pl->map, x, y);
00538     while (tmp) {
00539         object *above;
00540 
00541         above = tmp->above;
00542         if (WALL == tmp->type) {
00543             /* There was a wall, remove it & keep its archetype to make new walls */
00544             new_wall = tmp->arch;
00545             remove_ob(tmp);
00546             free_object(tmp);
00547             snprintf(message, sizeof(message), "You destroy the wall and redo the floor.");
00548             wall_removed = 1;
00549             if (floor != NULL) {
00550                 remove_ob(floor);
00551                 free_object(floor);
00552                 floor = NULL;
00553             }
00554         } else if ((FLOOR == tmp->type) || (QUERY_FLAG(tmp, FLAG_IS_FLOOR))) {
00555             floor = tmp;
00556         } else {
00557             if (floor != NULL)
00558                 above_floor = tmp;
00559         }
00560 
00561         tmp = above;
00562     }
00563 
00564     if (wall_removed == 0 && floor != NULL) {
00565         if (floor->arch == new_floor->arch) {
00566             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You feel too lazy to redo the exact same floor.", NULL);
00567             free_object(new_floor);
00568             return 0;
00569         }
00570     }
00571 
00572     SET_FLAG(new_floor, FLAG_UNIQUE);
00573     SET_FLAG(new_floor, FLAG_IS_FLOOR);
00574     new_floor->type = FLOOR;
00575     insert_ob_in_map_at(new_floor, pl->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y);
00576 
00577     /* if there was a floor, remove it */
00578     if (floor) {
00579         remove_ob(floor);
00580         free_object(floor);
00581         floor = NULL;
00582     }
00583 
00584     /*
00585      * Next step: make sure there are either walls or floors around the new square
00586      * Since building, you can have: blocking view / floor / wall / nothing
00587      */
00588     for (i = 1; i <= 8; i++) {
00589         xt = x+freearr_x[i];
00590         yt = y+freearr_y[i];
00591         tmp = GET_MAP_OB(pl->map, xt, yt);
00592         if (!tmp) {
00593             /* Must insert floor & wall */
00594 
00595             tmp = arch_to_object(new_floor->arch);
00596             /* Better make the floor unique */
00597             SET_FLAG(tmp, FLAG_UNIQUE);
00598             SET_FLAG(tmp, FLAG_IS_BUILDABLE);
00599             tmp->type = FLOOR;
00600             insert_ob_in_map_at(tmp, pl->map, NULL, 0, xt, yt);
00601             /* Insert wall if exists. Note: if it doesn't, the map is weird... */
00602             if (new_wall) {
00603                 tmp = arch_to_object(new_wall);
00604                 SET_FLAG(tmp, FLAG_IS_BUILDABLE);
00605                 tmp->type = WALL;
00606                 insert_ob_in_map_at(tmp, pl->map, NULL, 0, xt, yt);
00607             }
00608         }
00609     }
00610 
00611     /* Finally fixing walls to ensure nice continuous walls
00612      * Note: 2 squares around are checked, because potentially we added walls
00613      * around the building spot, so need to check that those new walls connect
00614      * correctly
00615      */
00616     for (xt = x-2; xt <= x+2; xt++)
00617         for (yt = y-2; yt <= y+2; yt++) {
00618             if (!OUT_OF_REAL_MAP(pl->map, xt, yt))
00619                 fix_walls(pl->map, xt, yt);
00620         }
00621 
00622     /* Tell player about the fix */
00623     draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, message, NULL);
00624     return 1;
00625 }
00626 
00644 static int apply_builder_wall(object *pl, object *new_wall, short x, short y) {
00645     object *current_wall;
00646     char message[MAX_BUF];
00647 
00648     remove_marking_runes(pl->map, x, y);
00649 
00650     current_wall = get_wall(pl->map, x, y);
00651 
00652     if (current_wall) {
00653         char current_basename[MAX_BUF];
00654         char new_basename[MAX_BUF];
00655         char *underscore;
00656 
00657         /* Check if the old and new archetypes have the same prefix */
00658         strncpy(current_basename, current_wall->arch->name, sizeof(current_basename));
00659         current_basename[sizeof(current_basename)-1] = '\0';
00660         underscore = strchr(current_basename, '_');
00661         if (underscore && isdigit(*(underscore+1))) {
00662             underscore++;
00663             *underscore = '\0';
00664         }
00665         strncpy(new_basename, new_wall->arch->name, sizeof(new_basename));
00666         new_basename[sizeof(new_basename)-1] = '\0';
00667         underscore = strchr(new_basename, '_');
00668         if (underscore && isdigit(*(underscore+1))) {
00669             underscore++;
00670             *underscore = '\0';
00671         }
00672         if (!strncmp(current_basename, new_basename, sizeof(new_basename))) {
00673             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You feel too lazy to redo the exact same wall.", NULL);
00674             free_object(new_wall);
00675             return 0;
00676         }
00677     }
00678 
00679     snprintf(message, sizeof(message), "You build a wall.");
00680     new_wall->type = WALL;
00681 
00682     if (current_wall) {
00683         /* If existing wall, replace it, no need to fix other walls */
00684         remove_ob(current_wall);
00685         free_object(current_wall);
00686         insert_ob_in_map_at(new_wall, pl->map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
00687         fix_walls(pl->map, x, y);
00688         snprintf(message, sizeof(message), "You redecorate the wall to better suit your tastes.");
00689     } else {
00690         int xt, yt;
00691 
00692         /* Else insert new wall and fix all walls around */
00693         insert_ob_in_map_at(new_wall, pl->map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
00694         for (xt = x-1; xt <= x+1; xt++)
00695             for (yt = y-1; yt <= y+1; yt++) {
00696                 if (OUT_OF_REAL_MAP(pl->map, xt, yt))
00697                     continue;
00698 
00699                 fix_walls(pl->map, xt, yt);
00700             }
00701     }
00702 
00703     /* Tell player what happened */
00704     draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, message, NULL);
00705     return 1;
00706 }
00707 
00724 static int apply_builder_window(object *pl, object *new_wall_win, short x, short y) {
00725     object *current_wall;
00726     char archetype[MAX_BUF];
00727     struct archt *new_arch;
00728     object *window;
00729     uint32 old_flags[4];
00730     int flag;
00731 
00732     /* Too bad, we never use the window contained in the building material */
00733     free_object(new_wall_win);
00734 
00735     current_wall = get_wall(pl->map, x, y);
00736 
00737     if (current_wall) {
00738         char *underscore;
00739 
00740         strncpy(archetype, current_wall->arch->name, sizeof(archetype));
00741         archetype[sizeof(archetype)-1] = '\0';
00742         underscore = strchr(archetype, '_');
00743         if (underscore) {
00744             underscore++;
00745             /* Check if the current wall has a window */
00746             if (!strcmp(underscore, "win1")
00747             || !strcmp(underscore, "win2")) {
00748                 draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You feel too lazy to redo the window.", NULL);
00749                 return 0;
00750             }
00751             if (!strcmp(underscore, "2_1_1"))
00752                 strcpy(underscore, "win1");
00753             else if (!strcmp(underscore, "2_1_2"))
00754                 strcpy(underscore, "win2");
00755             else {
00756                 /* Wrong wall orientation */
00757                 draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You cannot build a window in that wall.", NULL);
00758                 return 0;
00759             }
00760         }
00761     } else {
00762         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00763                       "There is no wall there.", NULL);
00764         return 0;
00765     }
00766 
00767     new_arch = find_archetype(archetype);
00768     if (!new_arch) {
00769         /* That type of wall doesn't have corresponding window archetypes */
00770         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You cannot build a window in that wall.", NULL);
00771         return 0;
00772     }
00773 
00774     /* Now delete current wall, and insert new one with a window
00775      * We save flags to avoid any trouble with buildable/non buildable, and so on
00776      */
00777     for (flag = 0; flag < 4; flag++)
00778         old_flags[flag] = current_wall->flags[flag];
00779     remove_ob(current_wall);
00780     free_object(current_wall);
00781 
00782     window = arch_to_object(new_arch);
00783     window->type = WALL;
00784     insert_ob_in_map_at(window, pl->map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
00785     for (flag = 0; flag < 4; flag++)
00786         window->flags[flag] = old_flags[flag];
00787 
00788     /* Tell player what happened */
00789     draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You build a window in the wall.", NULL);
00790     return 1;
00791 }
00792 
00814 static int apply_builder_item(object *pl, object *new_item, short x, short y) {
00815     int insert_flag;
00816     object *floor;
00817     object *con_rune;
00818     int connected;
00819     char name[MAX_BUF];
00820 
00821     /* Find floor */
00822     floor = GET_MAP_OB(pl->map, x, y);
00823     if (!floor) {
00824         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "Invalid square.", NULL);
00825         free_object(new_item);
00826         return 0;
00827     }
00828 
00829     while (floor && (floor->type != FLOOR) && (!QUERY_FLAG(floor, FLAG_IS_FLOOR)))
00830         floor = floor->above;
00831 
00832     if (!floor) {
00833         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00834                       "This square has no floor, you can't build here.", NULL);
00835         free_object(new_item);
00836         return 0;
00837     }
00838 
00839     SET_FLAG(new_item, FLAG_NO_PICK);
00840 
00841     /*
00842      * This doesn't work on non unique maps. pedestals under floor will not be saved...
00843      * insert_flag = (material->stats.Str == 1) ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY;
00844      */
00845     insert_flag = INS_ABOVE_FLOOR_ONLY;
00846 
00847     connected = 0;
00848     con_rune = NULL;
00849     switch (new_item->type) {
00850     case DOOR:
00851     case GATE:
00852     case BUTTON:
00853     case DETECTOR:
00854     case TIMED_GATE:
00855     case PEDESTAL:
00856     case CF_HANDLE:
00857     case MAGIC_EAR:
00858     case SIGN:
00859         /* Signs don't need a connection, but but magic mouths do. */
00860         if (new_item->type == SIGN && strcmp(new_item->arch->name, "magic_mouth"))
00861             break;
00862         con_rune = get_connection_rune(pl, x, y);
00863         connected = find_or_create_connection_for_map(pl, x, y, con_rune);
00864         if (connected == -1) {
00865             /* Player already informed of failure by the previous function */
00866             free_object(new_item);
00867             return 0;
00868         }
00869     }
00870 
00871     /* For magic mouths/ears, and signs, take the msg from a book of scroll */
00872     if ((new_item->type == SIGN) || (new_item->type == MAGIC_EAR)) {
00873         if (adjust_sign_msg(pl, x, y, new_item) == -1) {
00874             free_object(new_item);
00875             return 0;
00876         }
00877     }
00878 
00879     if (con_rune != NULL) {
00880         /* Remove marking rune */
00881         remove_ob(con_rune);
00882         free_object(con_rune);
00883     }
00884 
00885     insert_ob_in_map_at(new_item, pl->map, floor, insert_flag, x, y);
00886     if (connected != 0)
00887         add_button_link(new_item, pl->map, connected);
00888 
00889     query_name(new_item, name, MAX_BUF);
00890     draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00891                          "You build the %s",
00892                          "You build the %s",
00893                          name);
00894     return 1;
00895 }
00896 
00907 void apply_builder_remove(object *pl, int dir) {
00908     object *item;
00909     short x, y;
00910     char name[MAX_BUF];
00911 
00912     x = pl->x+freearr_x[dir];
00913     y = pl->y+freearr_y[dir];
00914 
00915     /* Check square */
00916     item = GET_MAP_OB(pl->map, x, y);
00917     if (!item) {
00918         /* Should not happen with previous tests, but we never know */
00919         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00920                       "Invalid square.", NULL);
00921         LOG(llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, pl->map->path);
00922         return;
00923     }
00924 
00925     if (item->type == FLOOR || QUERY_FLAG(item, FLAG_IS_FLOOR))
00926         item = item->above;
00927 
00928     if (!item) {
00929         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00930                       "Nothing to remove.", NULL);
00931         return;
00932     }
00933 
00934     /* Now remove object, with special cases (buttons & such) */
00935     switch (item->type) {
00936     case WALL:
00937         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00938                       "Can't remove a wall with that, build a floor.", NULL);
00939         return;
00940 
00941     case DOOR:
00942     case BUTTON:
00943     case GATE:
00944     case TIMED_GATE:
00945     case DETECTOR:
00946     case PEDESTAL:
00947     case CF_HANDLE:
00948     case MAGIC_EAR:
00949     case SIGN:
00950         /* Special case: must unconnect */
00951         if (QUERY_FLAG(item, FLAG_IS_LINKED))
00952             remove_button_link(item);
00953 
00954         /* Fall through */
00955     default:
00956         /* Remove generic item */
00957         query_name(item, name, MAX_BUF);
00958         draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00959                              "You remove the %s",
00960                              "You remove the %s",
00961                              name);
00962         remove_ob(item);
00963         free_object(item);
00964     }
00965 }
00966 
00978 void apply_map_builder(object *pl, int dir) {
00979     object *builder;
00980     object *tmp;
00981     short x, y;
00982 
00983     if (!pl->type == PLAYER)
00984         return;
00985 
00986     if (dir == 0) {
00987         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00988                       "You can't build or destroy under yourself.", NULL);
00989         return;
00990     }
00991 
00992     x = pl->x+freearr_x[dir];
00993     y = pl->y+freearr_y[dir];
00994 
00995     if ((1 > x) || (1 > y)
00996     || ((MAP_WIDTH(pl->map)-2) < x) || ((MAP_HEIGHT(pl->map)-2) < y)) {
00997         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
00998                       "Can't build on map edge.", NULL);
00999         return;
01000     }
01001 
01002     /*
01003      * Check specified square
01004      * The square must have only buildable items
01005      * Exception: marking runes are all right,
01006      * since they are used for special things like connecting doors / buttons
01007      */
01008 
01009     tmp = GET_MAP_OB(pl->map, x, y);
01010     if (!tmp) {
01011         /* Nothing, meaning player is standing next to an undefined square. */
01012         LOG(llevError, "apply_map_builder: undefined square at (%d, %d, %s)\n", x, y, pl->map->path);
01013         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
01014                       "You'd better not build here, it looks weird.", NULL);
01015         return;
01016     }
01017 
01018     builder = pl->contr->ranges[range_builder];
01019 
01020     if (builder->subtype != ST_BD_BUILD) {
01021         while (tmp) {
01022             if (!QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)
01023             && ((tmp->type != SIGN) || (strcmp(tmp->arch->name, "rune_mark")))) {
01024                 draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
01025                               "You can't build here.", NULL);
01026                 return;
01027             }
01028             tmp = tmp->above;
01029         }
01030     }
01031 
01032     /* Now we know the square is ok */
01033 
01034     if (builder->subtype == ST_BD_REMOVE) {
01035         /* Remover -> call specific function and bail out */
01036         apply_builder_remove(pl, dir);
01037         return;
01038     }
01039 
01040     if (builder->subtype == ST_BD_BUILD) {
01041         object *material;
01042         struct archt *new_arch;
01043         object *new_item;
01044         int built = 0;
01045 
01046         /* Builder -> find material, get new item, call specific function */
01047         /* find the marked item to buld */
01048         material = find_marked_object(pl);
01049         if (!material) {
01050             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
01051                           "You need to mark raw materials to use.", NULL);
01052             return;
01053         }
01054 
01055         if (material->type != MATERIAL) {
01056             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
01057                           "You can't use the marked item to build.", NULL);
01058             return;
01059         }
01060 
01061         /* create a new object from the raw materials */
01062         new_arch = find_archetype(material->slaying);
01063         if (!new_arch) {
01064             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
01065                          "You can't use this strange material.", NULL);
01066             LOG(llevError, "apply_map_builder: unable to find archetype %s\n", material->slaying);
01067             return;
01068         }
01069         new_item = object_create_arch(new_arch);
01070         SET_FLAG(new_item, FLAG_IS_BUILDABLE);
01071 
01072         if (!can_build_over(pl->map, new_item, x, y)) {
01073             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
01074                           "You can't build here.", NULL);
01075             return;
01076         }
01077 
01078         /* insert the new object in the map */
01079         switch (material->subtype) {
01080         case ST_MAT_FLOOR:
01081             built = apply_builder_floor(pl, new_item, x, y);
01082             break;
01083 
01084         case ST_MAT_WALL:
01085             built = apply_builder_wall(pl, new_item, x, y);
01086             break;
01087 
01088         case ST_MAT_ITEM:
01089             built = apply_builder_item(pl, new_item, x, y);
01090             break;
01091 
01092         case ST_MAT_WINDOW:
01093             built = apply_builder_window(pl, new_item, x, y);
01094             break;
01095 
01096         default:
01097             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
01098                           "Don't know how to apply this material, sorry.", NULL);
01099             LOG(llevError, "apply_map_builder: invalid material subtype %d\n", material->subtype);
01100             break;
01101         }
01102         if (built)
01103           decrease_ob(material);
01104         return;
01105     }
01106 
01107     /* Here, it means the builder has an invalid type */
01108     draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD,
01109                   "Don't know how to apply this tool, sorry.", NULL);
01110     LOG(llevError, "apply_map_builder: invalid builder subtype %d\n", builder->subtype);
01111 }