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