Crossfire Server, Trunk
build_map.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
23 #include "global.h"
24 
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "living.h"
30 #include "skills.h"
31 #include "spells.h"
32 #include "sproto.h"
33 #include "tod.h"
34 
48 static int can_build_over(struct mapdef *map, object *new_item, short x, short y) {
49  FOR_MAP_PREPARE(map, x, y, tmp) {
50  object *ob;
51 
52  ob = HEAD(tmp);
53  if (strcmp(ob->arch->name, "rune_mark") == 0)
54  /* you can always build on marking runes, used for connected building things. */
55  continue;
56 
58  /* Check for the flag is required, as this function
59  * can be called recursively on different spots.
60  */
61  continue;
62 
63  switch (new_item->type) {
64  case SIGN:
65  case MAGIC_EAR:
66  /* Allow signs and magic ears to be built on books */
67  if (ob->type != BOOK)
68  return 0;
69  break;
70 
71  case BUTTON:
72  case DETECTOR:
73  case PEDESTAL:
74  case CF_HANDLE:
75  /* Allow buttons and levers to be built under gates */
76  if (ob->type != GATE && ob->type != DOOR)
77  return 0;
78  break;
79 
80  default:
81  return 0;
82  }
83  } FOR_MAP_FINISH();
84 
85  /* If item being built is multi-tile, need to check other parts too. */
86  if (new_item->more)
87  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);
88 
89  return 1;
90 }
91 
103 static object *get_connection_rune(object *pl, short x, short y) {
104  FOR_MAP_PREPARE(pl->map, x, y, rune)
105  if (rune->type == SIGN && strcmp(rune->arch->name, "rune_mark") == 0)
106  return rune;
107  FOR_MAP_FINISH();
108  return NULL;
109 }
110 
122 static object *get_msg_book(object *pl, short x, short y) {
123  FOR_MAP_PREPARE(pl->map, x, y, book)
124  if (book->type == BOOK)
125  return book;
126  FOR_MAP_FINISH();
127  return NULL;
128 }
129 
142 static object *get_wall(struct mapdef *map, int x, int y) {
143  FOR_MAP_PREPARE(map, x, y, wall)
144  if (wall->type == WALL)
145  return wall;
146  FOR_MAP_FINISH();
147  return NULL;
148 }
149 
158 static void remove_marking_runes(struct mapdef *map, short x, short y) {
159  FOR_MAP_PREPARE(map, x, y, rune) {
160  if ((rune->type == SIGN) && (!strcmp(rune->arch->name, "rune_mark"))) {
161  object_remove(rune);
163  }
164  } FOR_MAP_FINISH();
165 }
166 
184 static int adjust_sign_msg(object *pl, short x, short y, object *tmp) {
185  object *book;
186  char buf[MAX_BUF];
187  char buf2[MAX_BUF];
188 
189  book = get_msg_book(pl, x, y);
190  if (!book) {
192  "You need to put a book or scroll with the message.");
193  return -1;
194  }
195 
196  object_set_msg(tmp, book->msg);
197 
198  if (tmp->invisible) {
199  if (book->custom_name != NULL) {
200  snprintf(buf, sizeof(buf), "talking %s", book->custom_name);
201  } else {
202  snprintf(buf, sizeof(buf), "talking %s", book->name);
203  }
204  if (tmp->name)
205  free_string(tmp->name);
206  tmp->name = add_string(buf);
207 
208  if (book->name_pl != NULL) {
209  snprintf(buf2, sizeof(buf2), "talking %s", book->name_pl);
210  if (tmp->name_pl)
211  free_string(tmp->name_pl);
212  tmp->name_pl = add_string(buf2);
213  }
214 
215  tmp->face = book->face;
216  tmp->invisible = 0;
217  }
218  object_remove(book);
220  return 0;
221 }
222 
234  int connected = 0;
235  int itest = 0;
236  oblinkpt *obp;
237 
238  while (itest++ < 1000) {
239  connected = 1+rand()%20000;
240  for (obp = map->buttons; obp && (obp->value != connected); obp = obp->next)
241  ;
242 
243  if (!obp)
244  return connected;
245  }
246 
247  return -1;
248 }
249 
250 
271 static int find_or_create_connection_for_map(object *pl, short x, short y, object *rune) {
272  object *force;
273  int connected;
274 
275  if (!rune)
276  rune = get_connection_rune(pl, x, y);
277 
278  if (!rune || !rune->msg) {
280  "You need to put a marking rune with the group name.");
281  return -1;
282  }
283 
284  /* Now, find force in player's inventory */
285  force = NULL;
287  if (tmp->type == FORCE
288  && tmp->slaying != NULL && strcmp(tmp->slaying, pl->map->path) == 0
289  && tmp->msg != NULL && tmp->msg == rune->msg) {
290  force = tmp;
291  break;
292  }
293  } FOR_INV_FINISH();
294 
295  if (!force) {
296  /* No force, need to create & insert one */
297  /* Find unused value */
299  if (connected == -1) {
301  "Could not create more groups.");
302  return -1;
303  }
304 
306  force->speed = 0;
308  force->slaying = add_string(pl->map->path);
309  object_set_msg(force, rune->msg);
310  force->path_attuned = connected;
312 
313  return connected;
314  }
315 
316  /* Found the force, everything's easy. */
317  return force->path_attuned;
318 }
319 
335 static void fix_walls(struct mapdef *map, int x, int y) {
336  int connect;
337  object *wall;
338  char archetype[MAX_BUF];
339  char *underscore;
340  uint32_t old_flags[4];
341  struct archt *new_arch;
342  int flag;
343  int len;
344  int has_window;
345 
346  /* First, find the wall on that spot */
347  wall = get_wall(map, x, y);
348  if (!wall)
349  /* Nothing -> bail out */
350  return;
351 
352  /* Find base name */
353  strncpy(archetype, wall->arch->name, sizeof(archetype));
354  archetype[sizeof(archetype)-1] = '\0';
355  underscore = strchr(archetype, '_');
356  if (!underscore)
357  /* Not in a format we can change, bail out */
358  return;
359  has_window = 0;
360  if (!strcmp(underscore+1, "win1"))
361  has_window = 1;
362  else if (!strcmp(underscore+1, "win2"))
363  has_window = 1;
364  else if (!isdigit(*(underscore+1)))
365  return;
366 
367  underscore++;
368  *underscore = '\0';
369  len = sizeof(archetype)-strlen(archetype)-2;
370 
371  connect = 0;
372 
373  if ((x > 0) && get_wall(map, x-1, y))
374  connect |= 1;
375  if ((x < MAP_WIDTH(map)-1) && get_wall(map, x+1, y))
376  connect |= 2;
377  if ((y > 0) && get_wall(map, x, y-1))
378  connect |= 4;
379  if ((y < MAP_HEIGHT(map)-1) && get_wall(map, x, y+1))
380  connect |= 8;
381 
382  switch (connect) {
383  case 0:
384  strncat(archetype, "0", len);
385  break;
386 
387  case 1:
388  strncat(archetype, "1_3", len);
389  break;
390 
391  case 2:
392  strncat(archetype, "1_4", len);
393  break;
394 
395  case 3:
396  if (has_window) {
397  strncat(archetype, "win2", len);
398  } else {
399  strncat(archetype, "2_1_2", len);
400  }
401  break;
402 
403  case 4:
404  strncat(archetype, "1_2", len);
405  break;
406 
407  case 5:
408  strncat(archetype, "2_2_4", len);
409  break;
410 
411  case 6:
412  strncat(archetype, "2_2_1", len);
413  break;
414 
415  case 7:
416  strncat(archetype, "3_1", len);
417  break;
418 
419  case 8:
420  strncat(archetype, "1_1", len);
421  break;
422 
423  case 9:
424  strncat(archetype, "2_2_3", len);
425  break;
426 
427  case 10:
428  strncat(archetype, "2_2_2", len);
429  break;
430 
431  case 11:
432  strncat(archetype, "3_3", len);
433  break;
434 
435  case 12:
436  if (has_window) {
437  strncat(archetype, "win1", len);
438  } else {
439  strncat(archetype, "2_1_1", len);
440  }
441  break;
442 
443  case 13:
444  strncat(archetype, "3_4", len);
445  break;
446 
447  case 14:
448  strncat(archetype, "3_2", len);
449  break;
450 
451  case 15:
452  strncat(archetype, "4", len);
453  break;
454  }
455 
456  /*
457  * No need to change anything if the old and new names are identical.
458  */
459  if (!strncmp(archetype, wall->arch->name, sizeof(archetype)))
460  return;
461 
462  /*
463  * Before anything, make sure the archetype does exist...
464  * If not, prolly an error...
465  */
466  new_arch = try_find_archetype(archetype);
467  if (!new_arch)
468  return;
469 
470  /* Now delete current wall, and insert new one
471  * We save flags to avoid any trouble with buildable/non buildable, and so on
472  */
473  for (flag = 0; flag < 4; flag++)
474  old_flags[flag] = wall->flags[flag];
475  object_remove(wall);
477 
478  wall = arch_to_object(new_arch);
479  wall->type = WALL;
481  for (flag = 0; flag < 4; flag++)
482  wall->flags[flag] = old_flags[flag];
483 }
484 
506 static int apply_builder_floor(object *pl, object *new_floor, short x, short y) {
507  object *above_floor; /* Item above floor, if any */
508  object *floor; /* Floor which would be removed if required */
509  struct archt *new_wall;
510  int i, xt, yt, wall_removed;
511  char message[MAX_BUF];
512 
513  snprintf(message, sizeof(message), "You change the floor to better suit your tastes.");
514 
515  /*
516  * Now the building part...
517  * First, remove wall(s) and floor(s) at position x, y
518  */
519  above_floor = NULL;
520  floor = NULL;
521  new_wall = NULL;
522  wall_removed = 0;
523  FOR_MAP_PREPARE(pl->map, x, y, tmp) {
524  if (WALL == tmp->type) {
525  /* There was a wall, remove it & keep its archetype to make new walls */
526  new_wall = tmp->arch;
529  snprintf(message, sizeof(message), "You destroy the wall and redo the floor.");
530  wall_removed = 1;
531  if (floor != NULL) {
532  object_remove(floor);
534  floor = NULL;
535  }
536  } else if ((FLOOR == tmp->type) || (QUERY_FLAG(tmp, FLAG_IS_FLOOR))) {
537  floor = tmp;
538  } else {
539  if (floor != NULL)
540  above_floor = tmp;
541  }
542  } FOR_MAP_FINISH();
543 
544  if (wall_removed == 0 && floor != NULL) {
545  if (floor->arch == new_floor->arch) {
546  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You feel too lazy to redo the exact same floor.");
547  object_free_drop_inventory(new_floor);
548  return 0;
549  }
550  }
551 
552  SET_FLAG(new_floor, FLAG_UNIQUE);
553  SET_FLAG(new_floor, FLAG_IS_FLOOR);
554  new_floor->type = FLOOR;
555  object_insert_in_map_at(new_floor, pl->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y);
556 
557  /* if there was a floor, remove it */
558  if (floor) {
559  object_remove(floor);
561  floor = NULL;
562  }
563 
564  /*
565  * Next step: make sure there are either walls or floors around the new square
566  * Since building, you can have: blocking view / floor / wall / nothing
567  */
568  for (i = 1; i <= 8; i++) {
569  object *tmp;
570 
571  xt = x+freearr_x[i];
572  yt = y+freearr_y[i];
573  tmp = GET_MAP_OB(pl->map, xt, yt);
574  if (!tmp) {
575  /* Must insert floor & wall */
576 
577  tmp = arch_to_object(new_floor->arch);
578  /* Better make the floor unique */
581  tmp->type = FLOOR;
582  object_insert_in_map_at(tmp, pl->map, NULL, 0, xt, yt);
583  /* Insert wall if exists. Note: if it doesn't, the map is weird... */
584  if (new_wall) {
585  tmp = arch_to_object(new_wall);
587  tmp->type = WALL;
588  object_insert_in_map_at(tmp, pl->map, NULL, 0, xt, yt);
589  }
590  }
591  }
592 
593  /* Finally fixing walls to ensure nice continuous walls
594  * Note: 2 squares around are checked, because potentially we added walls
595  * around the building spot, so need to check that those new walls connect
596  * correctly
597  */
598  for (xt = x-2; xt <= x+2; xt++)
599  for (yt = y-2; yt <= y+2; yt++) {
600  if (!OUT_OF_REAL_MAP(pl->map, xt, yt))
601  fix_walls(pl->map, xt, yt);
602  }
603 
604  /* Tell player about the fix */
606  return 1;
607 }
608 
626 static int apply_builder_wall(object *pl, object *new_wall, short x, short y) {
627  object *current_wall;
628  char message[MAX_BUF];
629 
630  remove_marking_runes(pl->map, x, y);
631 
632  current_wall = get_wall(pl->map, x, y);
633 
634  if (current_wall) {
635  char current_basename[MAX_BUF];
636  char new_basename[MAX_BUF];
637  char *underscore;
638 
639  /* Check if the old and new archetypes have the same prefix */
640  strncpy(current_basename, current_wall->arch->name, sizeof(current_basename));
641  current_basename[sizeof(current_basename)-1] = '\0';
642  underscore = strchr(current_basename, '_');
643  if (underscore && isdigit(*(underscore+1))) {
644  underscore++;
645  *underscore = '\0';
646  }
647  strncpy(new_basename, new_wall->arch->name, sizeof(new_basename));
648  new_basename[sizeof(new_basename)-1] = '\0';
649  underscore = strchr(new_basename, '_');
650  if (underscore && isdigit(*(underscore+1))) {
651  underscore++;
652  *underscore = '\0';
653  }
654  if (!strncmp(current_basename, new_basename, sizeof(new_basename))) {
655  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You feel too lazy to redo the exact same wall.");
656  object_free_drop_inventory(new_wall);
657  return 0;
658  }
659  }
660 
661  snprintf(message, sizeof(message), "You build a wall.");
662  new_wall->type = WALL;
663 
664  if (current_wall) {
665  /* If existing wall, replace it, no need to fix other walls */
666  object_remove(current_wall);
667  object_free_drop_inventory(current_wall);
668  object_insert_in_map_at(new_wall, pl->map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
669  fix_walls(pl->map, x, y);
670  snprintf(message, sizeof(message), "You redecorate the wall to better suit your tastes.");
671  } else {
672  int xt, yt;
673 
674  /* Else insert new wall and fix all walls around */
675  object_insert_in_map_at(new_wall, pl->map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
676  for (xt = x-1; xt <= x+1; xt++)
677  for (yt = y-1; yt <= y+1; yt++) {
678  if (OUT_OF_REAL_MAP(pl->map, xt, yt))
679  continue;
680 
681  fix_walls(pl->map, xt, yt);
682  }
683  }
684 
685  /* Tell player what happened */
687  return 1;
688 }
689 
706 static int apply_builder_window(object *pl, object *new_wall_win, short x, short y) {
707  object *current_wall;
708  char archetype[MAX_BUF];
709  struct archt *new_arch;
710  object *window;
711  uint32_t old_flags[4];
712  int flag;
713 
714  /* Too bad, we never use the window contained in the building material */
715  object_free_drop_inventory(new_wall_win);
716 
717  current_wall = get_wall(pl->map, x, y);
718 
719  if (current_wall) {
720  char *underscore;
721 
722  strncpy(archetype, current_wall->arch->name, sizeof(archetype));
723  archetype[sizeof(archetype)-1] = '\0';
724  underscore = strchr(archetype, '_');
725  if (underscore) {
726  underscore++;
727  /* Check if the current wall has a window */
728  if (!strcmp(underscore, "win1")
729  || !strcmp(underscore, "win2")) {
730  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You feel too lazy to redo the window.");
731  return 0;
732  }
733  if (!strcmp(underscore, "2_1_1"))
734  strcpy(underscore, "win1");
735  else if (!strcmp(underscore, "2_1_2"))
736  strcpy(underscore, "win2");
737  else {
738  /* Wrong wall orientation */
739  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You cannot build a window in that wall.");
740  return 0;
741  }
742  }
743  } else {
745  "There is no wall there.");
746  return 0;
747  }
748 
749  new_arch = find_archetype(archetype);
750  if (!new_arch) {
751  /* That type of wall doesn't have corresponding window archetypes */
752  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You cannot build a window in that wall.");
753  return 0;
754  }
755 
756  /* Now delete current wall, and insert new one with a window
757  * We save flags to avoid any trouble with buildable/non buildable, and so on
758  */
759  for (flag = 0; flag < 4; flag++)
760  old_flags[flag] = current_wall->flags[flag];
761  object_remove(current_wall);
762  object_free_drop_inventory(current_wall);
763 
764  window = arch_to_object(new_arch);
765  window->type = WALL;
766  object_insert_in_map_at(window, pl->map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
767  for (flag = 0; flag < 4; flag++)
768  window->flags[flag] = old_flags[flag];
769 
770  /* Tell player what happened */
771  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You build a window in the wall.");
772  return 1;
773 }
774 
796 static int apply_builder_item(object *pl, object *new_item, short x, short y) {
797  int insert_flag;
798  object *floor;
799  object *con_rune;
800  int connected;
801  char name[MAX_BUF];
802 
803  /* Find floor */
804  floor = GET_MAP_OB(pl->map, x, y);
805  if (!floor) {
807  object_free_drop_inventory(new_item);
808  return 0;
809  }
810 
812  if (floor->type == FLOOR || QUERY_FLAG(floor, FLAG_IS_FLOOR))
813  break;
815  if (!floor) {
817  "This square has no floor, you can't build here.");
818  object_free_drop_inventory(new_item);
819  return 0;
820  }
821 
822  SET_FLAG(new_item, FLAG_NO_PICK);
823 
824  /*
825  * This doesn't work on non unique maps. pedestals under floor will not be saved...
826  * insert_flag = (material->stats.Str == 1) ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY;
827  */
828  insert_flag = INS_ABOVE_FLOOR_ONLY;
829 
830  connected = 0;
831  con_rune = NULL;
832  switch (new_item->type) {
833  case DOOR:
834  case GATE:
835  case BUTTON:
836  case DETECTOR:
837  case TIMED_GATE:
838  case PEDESTAL:
839  case CF_HANDLE:
840  case MAGIC_EAR:
841  case SIGN:
842  /* Signs don't need a connection, but but magic mouths do. */
843  if (new_item->type == SIGN && strcmp(new_item->arch->name, "magic_mouth"))
844  break;
845  con_rune = get_connection_rune(pl, x, y);
847  if (connected == -1) {
848  /* Player already informed of failure by the previous function */
849  object_free_drop_inventory(new_item);
850  return 0;
851  }
852  }
853 
854  /* For magic mouths/ears, and signs, take the msg from a book of scroll */
855  if ((new_item->type == SIGN) || (new_item->type == MAGIC_EAR)) {
856  if (adjust_sign_msg(pl, x, y, new_item) == -1) {
857  object_free_drop_inventory(new_item);
858  return 0;
859  }
860  }
861 
862  if (con_rune != NULL) {
863  /* Remove marking rune */
864  object_remove(con_rune);
865  object_free_drop_inventory(con_rune);
866  }
867 
868  object_insert_in_map_at(new_item, pl->map, floor, insert_flag, x, y);
869  if (connected != 0)
870  add_button_link(new_item, pl->map, connected);
871 
872  query_name(new_item, name, MAX_BUF);
874  "You build the %s",
875  name);
876  return 1;
877 }
878 
889 void apply_builder_remove(object *pl, int dir) {
890  object *item;
891  short x, y;
892  char name[MAX_BUF];
893 
894  x = pl->x+freearr_x[dir];
895  y = pl->y+freearr_y[dir];
896 
897  /* Check square */
898  item = GET_MAP_OB(pl->map, x, y);
899  if (!item) {
900  /* Should not happen with previous tests, but we never know */
902  "Invalid square.");
903  LOG(llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, pl->map->path);
904  return;
905  }
906 
907  if (item->type == FLOOR || QUERY_FLAG(item, FLAG_IS_FLOOR))
908  item = item->above;
909 
910  if (!item) {
912  "Nothing to remove.");
913  return;
914  }
915 
916  /* Now remove object, with special cases (buttons & such) */
917  switch (item->type) {
918  case WALL:
920  "Can't remove a wall with that, build a floor.");
921  return;
922 
923  case DOOR:
924  case BUTTON:
925  case GATE:
926  case TIMED_GATE:
927  case DETECTOR:
928  case PEDESTAL:
929  case CF_HANDLE:
930  case MAGIC_EAR:
931  case SIGN:
932  /* Special case: must unconnect */
935 
936  /* Fall through */
937  default:
938  /* Remove generic item */
941  "You remove the %s",
942  name);
945  }
946 }
947 
959 void apply_map_builder(object *pl, int dir) {
960  object *builder;
961  object *tmp;
962  short x, y;
963 
964  if (!IS_PLAYER(pl))
965  return;
966 
967  if (dir == 0) {
969  "You can't build or destroy under yourself.");
970  return;
971  }
972 
973  x = pl->x+freearr_x[dir];
974  y = pl->y+freearr_y[dir];
975 
976  if ((1 > x) || (1 > y)
977  || ((MAP_WIDTH(pl->map)-2) < x) || ((MAP_HEIGHT(pl->map)-2) < y)) {
979  "Can't build on map edge.");
980  return;
981  }
982 
983  /*
984  * Check specified square
985  * The square must have only buildable items
986  * Exception: marking runes are all right,
987  * since they are used for special things like connecting doors / buttons
988  */
989 
990  tmp = GET_MAP_OB(pl->map, x, y);
991  if (!tmp) {
992  /* Nothing, meaning player is standing next to an undefined square. */
993  LOG(llevError, "apply_map_builder: undefined square at (%d, %d, %s)\n", x, y, pl->map->path);
995  "You'd better not build here, it looks weird.");
996  return;
997  }
998 
999  builder = pl->contr->ranges[range_builder];
1000 
1001  if (builder->subtype != ST_BD_BUILD) {
1004  && ((tmp->type != SIGN) || (strcmp(tmp->arch->name, "rune_mark")))) {
1006  "You can't build here.");
1007  return;
1008  }
1010  }
1011 
1012  /* Now we know the square is ok */
1013 
1014  if (builder->subtype == ST_BD_REMOVE) {
1015  /* Remover -> call specific function and bail out */
1016  apply_builder_remove(pl, dir);
1017  return;
1018  }
1019 
1020  if (builder->subtype == ST_BD_BUILD) {
1021  object *material;
1022  struct archt *new_arch;
1023  object *new_item;
1024  int built = 0;
1025 
1026  /* Builder -> find material, get new item, call specific function */
1027  /* find the marked item to buld */
1028  material = find_marked_object(pl);
1029  if (!material) {
1031  "You need to mark raw materials to use.");
1032  return;
1033  }
1034 
1035  if (material->type != MATERIAL) {
1037  "You can't use the marked item to build.");
1038  return;
1039  }
1040 
1041  // Prevent use of unpaid materials.
1042  if (QUERY_FLAG(material, FLAG_UNPAID)) {
1043  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "You should pay for it first.");
1044  return;
1045  }
1046 
1047  /* create a new object from the raw materials */
1048  new_arch = find_archetype(material->slaying);
1049  if (!new_arch) {
1051  "You can't use this strange material.");
1052  LOG(llevError, "apply_map_builder: unable to find archetype %s\n", material->slaying);
1053  return;
1054  }
1055  new_item = object_create_arch(new_arch);
1056  SET_FLAG(new_item, FLAG_IS_BUILDABLE);
1057 
1058  if (!can_build_over(pl->map, new_item, x, y)) {
1060  "You can't build here.");
1061  return;
1062  }
1063 
1064  /* insert the new object in the map */
1065  switch (material->subtype) {
1066  case ST_MAT_FLOOR:
1067  built = apply_builder_floor(pl, new_item, x, y);
1068  break;
1069 
1070  case ST_MAT_WALL:
1071  built = apply_builder_wall(pl, new_item, x, y);
1072  break;
1073 
1074  case ST_MAT_ITEM:
1075  built = apply_builder_item(pl, new_item, x, y);
1076  break;
1077 
1078  case ST_MAT_WINDOW:
1079  built = apply_builder_window(pl, new_item, x, y);
1080  break;
1081 
1082  default:
1084  "Don't know how to apply this material, sorry.");
1085  LOG(llevError, "apply_map_builder: invalid material subtype %d\n", material->subtype);
1086  break;
1087  }
1088  if (built)
1089  object_decrease_nrof_by_one(material);
1090  return;
1091  }
1092 
1093  /* Here, it means the builder has an invalid type */
1095  "Don't know how to apply this tool, sorry.");
1096  LOG(llevError, "apply_map_builder: invalid builder subtype %d\n", builder->subtype);
1097 }
obj::flags
ob_flags flags
Definition: object.h:420
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:173
global.h
CF_HANDLE
@ CF_HANDLE
Definition: object.h:208
apply_map_builder
void apply_map_builder(object *pl, int dir)
Definition: build_map.c:959
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
object_remove
void object_remove(object *op)
Definition: object.c:1819
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
obj::face
const Face * face
Definition: object.h:336
ST_MAT_WALL
#define ST_MAT_WALL
Definition: define.h:68
llevError
@ llevError
Definition: logger.h:11
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
BUTTON
@ BUTTON
Definition: object.h:207
diamondslots.x
x
Definition: diamondslots.py:15
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
ST_MAT_ITEM
#define ST_MAT_ITEM
Definition: define.h:69
adjust_sign_msg
static int adjust_sign_msg(object *pl, short x, short y, object *tmp)
Definition: build_map.c:184
FLAG_UNIQUE
#define FLAG_UNIQUE
Definition: define.h:287
pl
Definition: player.h:105
fix_walls
static void fix_walls(struct mapdef *map, int x, int y)
Definition: build_map.c:335
TIMED_GATE
@ TIMED_GATE
Definition: object.h:128
guildjoin.ob
ob
Definition: guildjoin.py:42
obj::custom_name
sstring custom_name
Definition: object.h:437
find_unused_connected_value
static int find_unused_connected_value(struct mapdef *map)
Definition: build_map.c:233
can_build_over
static int can_build_over(struct mapdef *map, object *new_item, short x, short y)
Definition: build_map.c:48
Ice.tmp
int tmp
Definition: Ice.py:207
MSG_TYPE_APPLY_BUILD
#define MSG_TYPE_APPLY_BUILD
Definition: newclient.h:609
oblinkpt
Definition: object.h:455
FLOOR
@ FLOOR
Definition: object.h:186
SIGN
@ SIGN
Definition: object.h:211
obj::msg
sstring msg
Definition: object.h:325
apply_builder_floor
static int apply_builder_floor(object *pl, object *new_floor, short x, short y)
Definition: build_map.c:506
skills.h
FOR_OB_AND_ABOVE_FINISH
#define FOR_OB_AND_ABOVE_FINISH()
Definition: define.h:743
ST_BD_REMOVE
#define ST_BD_REMOVE
Definition: define.h:60
remove_button_link
void remove_button_link(object *op)
Definition: button.c:693
push.connected
connected
Definition: push.py:59
apply_builder_remove
void apply_builder_remove(object *pl, int dir)
Definition: build_map.c:889
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.c:299
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.c:305
archt
Definition: object.h:469
range_builder
@ range_builder
Definition: player.h:36
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Definition: object.h:567
FOR_OB_AND_ABOVE_PREPARE
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Definition: define.h:739
obj::slaying
sstring slaying
Definition: object.h:322
free_string
void free_string(sstring str)
Definition: shstr.c:280
disinfect.map
map
Definition: disinfect.py:4
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
obj::name
sstring name
Definition: object.h:314
oblinkpt::next
struct oblinkpt * next
Definition: object.h:458
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:585
ST_MAT_FLOOR
#define ST_MAT_FLOOR
Definition: define.h:67
get_msg_book
static object * get_msg_book(object *pl, short x, short y)
Definition: build_map.c:122
ST_BD_BUILD
#define ST_BD_BUILD
Definition: define.h:59
obj::name_pl
sstring name_pl
Definition: object.h:318
HEAD
#define HEAD(op)
Definition: object.h:593
oblinkpt::value
long value
Definition: object.h:457
obj::x
int16_t x
Definition: object.h:330
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:301
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Definition: object.h:570
create-tower.builder
builder
Definition: create-tower.py:6
sproto.h
mapdef
Definition: map.h:317
BOOK
@ BOOK
Definition: object.h:114
get_wall
static object * get_wall(struct mapdef *map, int x, int y)
Definition: build_map.c:142
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:78
MAX_BUF
#define MAX_BUF
Definition: define.h:35
INS_ON_TOP
#define INS_ON_TOP
Definition: object.h:569
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:281
IS_PLAYER
static bool IS_PLAYER(object *op)
Definition: object.h:595
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
obj::y
int16_t y
Definition: object.h:330
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:218
MAGIC_EAR
@ MAGIC_EAR
Definition: object.h:131
find_or_create_connection_for_map
static int find_or_create_connection_for_map(object *pl, short x, short y, object *rune)
Definition: build_map.c:271
obj::arch
struct archt * arch
Definition: object.h:417
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.c:4781
diamondslots.message
string message
Definition: diamondslots.py:57
obj::type
uint8_t type
Definition: object.h:343
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
spells.h
archt::clone
object clone
Definition: object.h:473
item
Definition: item.py:1
FLAG_IS_BUILDABLE
#define FLAG_IS_BUILDABLE
Definition: define.h:367
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
add_button_link
void add_button_link(object *button, mapstruct *map, int connected)
Definition: button.c:656
apply_builder_item
static int apply_builder_item(object *pl, object *new_item, short x, short y)
Definition: build_map.c:796
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:284
MATERIAL
@ MATERIAL
Definition: object.h:248
diamondslots.y
y
Definition: diamondslots.py:16
PEDESTAL
@ PEDESTAL
Definition: object.h:121
buf
StringBuffer * buf
Definition: readable.c:1610
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:80
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2833
object_update_speed
void object_update_speed(object *op)
Definition: object.c:1330
obj::subtype
uint8_t subtype
Definition: object.h:344
obj::more
struct obj * more
Definition: object.h:298
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:232
pl::ranges
object * ranges[range_size]
Definition: player.h:116
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:2080
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:309
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1546
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:288
DOOR
@ DOOR
Definition: object.h:126
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
archt::name
sstring name
Definition: object.h:470
WALL
@ WALL
Definition: object.h:191
FLAG_IS_LINKED
#define FLAG_IS_LINKED
Definition: define.h:315
say.item
dictionary item
Definition: say.py:149
connect
Definition: connect.py:1
tod.h
get_connection_rune
static object * get_connection_rune(object *pl, short x, short y)
Definition: build_map.c:103
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Definition: newclient.h:408
living.h
find_marked_object
object * find_marked_object(object *op)
Definition: c_object.c:1520
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
FORCE
@ FORCE
Definition: object.h:224
remove_marking_runes
static void remove_marking_runes(struct mapdef *map, short x, short y)
Definition: build_map.c:158
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
DETECTOR
@ DETECTOR
Definition: object.h:149
apply_builder_window
static int apply_builder_window(object *pl, object *new_wall_win, short x, short y)
Definition: build_map.c:706
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
GATE
@ GATE
Definition: object.h:206
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
apply_builder_wall
static int apply_builder_wall(object *pl, object *new_wall, short x, short y)
Definition: build_map.c:626
give.name
name
Definition: give.py:27
archetype
struct archt archetype
ST_MAT_WINDOW
#define ST_MAT_WINDOW
Definition: define.h:70
dragon_attune.force
force
Definition: dragon_attune.py:45