Crossfire Server, Trunk  R20513
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 
233 static int find_unused_connected_value(struct mapdef *map) {
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;
286  FOR_INV_PREPARE(pl, tmp) {
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 */
298  connected = find_unused_connected_value(pl->map);
299  if (connected == -1) {
301  "Could not create more groups.");
302  return -1;
303  }
304 
305  force = create_archetype(FORCE_NAME);
306  force->speed = 0;
307  object_update_speed(force);
308  force->slaying = add_string(pl->map->path);
309  object_set_msg(force, rune->msg);
310  force->path_attuned = connected;
311  object_insert_in_ob(force, pl);
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 = 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;
480  object_insert_in_map_at(wall, map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
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;
527  object_remove(tmp);
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 */
579  SET_FLAG(tmp, FLAG_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) {
806  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "Invalid square.");
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);
846  connected = find_or_create_connection_for_map(pl, x, y, con_rune);
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 */
933  if (QUERY_FLAG(item, FLAG_IS_LINKED))
934  remove_button_link(item);
935 
936  /* Fall through */
937  default:
938  /* Remove generic item */
939  query_name(item, name, MAX_BUF);
941  "You remove the %s",
942  name);
943  object_remove(item);
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 (!pl->type == PLAYER)
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) {
1003  if (!QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)
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  /* create a new object from the raw materials */
1042  new_arch = find_archetype(material->slaying);
1043  if (!new_arch) {
1045  "You can't use this strange material.");
1046  LOG(llevError, "apply_map_builder: unable to find archetype %s\n", material->slaying);
1047  return;
1048  }
1049  new_item = object_create_arch(new_arch);
1050  SET_FLAG(new_item, FLAG_IS_BUILDABLE);
1051 
1052  if (!can_build_over(pl->map, new_item, x, y)) {
1054  "You can't build here.");
1055  return;
1056  }
1057 
1058  /* insert the new object in the map */
1059  switch (material->subtype) {
1060  case ST_MAT_FLOOR:
1061  built = apply_builder_floor(pl, new_item, x, y);
1062  break;
1063 
1064  case ST_MAT_WALL:
1065  built = apply_builder_wall(pl, new_item, x, y);
1066  break;
1067 
1068  case ST_MAT_ITEM:
1069  built = apply_builder_item(pl, new_item, x, y);
1070  break;
1071 
1072  case ST_MAT_WINDOW:
1073  built = apply_builder_window(pl, new_item, x, y);
1074  break;
1075 
1076  default:
1078  "Don't know how to apply this material, sorry.");
1079  LOG(llevError, "apply_map_builder: invalid material subtype %d\n", material->subtype);
1080  break;
1081  }
1082  if (built)
1083  object_decrease_nrof_by_one(material);
1084  return;
1085  }
1086 
1087  /* Here, it means the builder has an invalid type */
1089  "Don't know how to apply this tool, sorry.");
1090  LOG(llevError, "apply_map_builder: invalid builder subtype %d\n", builder->subtype);
1091 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
See Pedestal.
Definition: object.h:121
Error, serious thing.
Definition: logger.h:11
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
static int apply_builder_wall(object *pl, object *new_wall, short x, short y)
Wall building function.
Definition: build_map.c:626
One player.
Definition: player.h:92
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:303
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:316
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:572
Spell-related defines: spellpath, subtypes, ...
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Constructs a loop iterating over an object and all objects above it in the same pile.
Definition: define.h:774
#define SET_FLAG(xyz, p)
Definition: define.h:223
static object * get_connection_rune(object *pl, short x, short y)
Returns the marking rune on the square, for purposes of building connections.
Definition: build_map.c:103
static void remove_marking_runes(struct mapdef *map, short x, short y)
Erases all marking runes at specified location (before building a wall)
Definition: build_map.c:158
Defines for the ingame clock, ticks management and weather system.
static object * get_msg_book(object *pl, short x, short y)
Returns the book/scroll on the current square, for purposes of building.
Definition: build_map.c:122
static int find_or_create_connection_for_map(object *pl, short x, short y, object *rune)
Helper function for door/button/connected item building.
Definition: build_map.c:271
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:80
object clone
An object from which to do object_copy()
Definition: object.h:470
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
const char * slaying
Which race to do double damage to.
Definition: object.h:319
#define ST_MAT_ITEM
Most other items, including doors & such.
Definition: define.h:69
object * ranges[range_size]
Object for each range.
Definition: player.h:103
uint8_t subtype
Subtype of object.
Definition: object.h:339
struct obj * above
Pointer to the object stacked above this one.
Definition: object.h:288
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:217
static int adjust_sign_msg(object *pl, short x, short y, object *tmp)
Make the built object inherit the msg of books that are used with it.
Definition: build_map.c:184
Wall.
Definition: object.h:191
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:343
static object * get_wall(struct mapdef *map, int x, int y)
Returns first item of type WALL.
Definition: build_map.c:142
Global type definitions and header inclusions.
#define ST_MAT_WALL
Wall.
Definition: define.h:68
long value
Used as connected value in buttons/gates.
Definition: object.h:453
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
peterm: detector is an object which notices the presense of another object and is triggered like butt...
Definition: object.h:149
#define ST_MAT_WINDOW
Window.
Definition: define.h:70
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:384
Used to link together several object links.
Definition: object.h:451
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
See Magic Ear.
Definition: object.h:131
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
static int apply_builder_window(object *pl, object *new_wall_win, short x, short y)
Window building function.
Definition: build_map.c:706
int16_t y
Position in the map for this object.
Definition: object.h:326
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.c:1921
struct oblinkpt * next
Next value in the list.
Definition: object.h:454
Floor tile -> native layer 0.
Definition: object.h:186
See Sign & Magic Mouth.
Definition: object.h:211
#define ST_BD_BUILD
Builds an item.
Definition: define.h:59
See Book.
Definition: object.h:114
const char * name_pl
The plural name of the object.
Definition: object.h:315
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.c:620
#define FOR_OB_AND_ABOVE_FINISH()
Finishes FOR_OB_AND_ABOVE_PREPARE().
Definition: define.h:778
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.c:2690
#define ST_MAT_FLOOR
Floor.
Definition: define.h:67
#define INS_ON_TOP
Always put object on top.
Definition: object.h:571
uint32_t flags[4]
Various flags.
Definition: object.h:415
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
#define snprintf
Definition: win32.h:46
Map builder.
Definition: player.h:23
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
void remove_button_link(object *op)
Remove the object from the linked lists of buttons in the map.
Definition: button.c:698
const char * name
The name of the object, obviously...
Definition: object.h:311
static void fix_walls(struct mapdef *map, int x, int y)
Fixes walls around specified spot.
Definition: build_map.c:335
void add_button_link(object *button, mapstruct *map, int connected)
Links specified object in the map.
Definition: button.c:661
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
object * find_marked_object(object *op)
Return the object the player has marked with the &#39;mark&#39; command below.
Definition: c_object.c:1256
#define ST_BD_REMOVE
Removes an item.
Definition: define.h:60
float speed
The overall speed of this object.
Definition: object.h:328
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:594
#define INS_ABOVE_FLOOR_ONLY
Put object immediatly above the floor.
Definition: object.h:569
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
See Door.
Definition: object.h:126
object * object_create_arch(archetype *at)
Create a full object using the given archetype.
Definition: arch.c:736
oblinkpt * buttons
Linked list of linked lists of buttons.
Definition: map.h:354
int16_t x
Definition: object.h:326
Skill-related defines, including subtypes.
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
static int apply_builder_floor(object *pl, object *new_floor, short x, short y)
Floor building function.
Definition: build_map.c:506
See Player.
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
void apply_map_builder(object *pl, int dir)
Global building function.
Definition: build_map.c:959
static int find_unused_connected_value(struct mapdef *map)
Returns an unused value for &#39;connected&#39;.
Definition: build_map.c:233
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:28
const char * custom_name
Custom name assigned by player.
Definition: object.h:432
struct archt * arch
Pointer to archetype.
Definition: object.h:412
#define MAP_WIDTH(m)
Map width.
Definition: map.h:78
See Button.
Definition: object.h:207
See Gate.
Definition: object.h:206
#define FLAG_IS_BUILDABLE
Can build on item.
Definition: define.h:376
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
Material for building.
Definition: object.h:248
See Handle.
Definition: object.h:208
See Timed Gate.
Definition: object.h:128
static int can_build_over(struct mapdef *map, object *new_item, short x, short y)
Check if objects on a square interfere with building.
Definition: build_map.c:48
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
#define FORCE_NAME
Definition: spells.h:169
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
static int apply_builder_item(object *pl, object *new_item, short x, short y)
Generic item builder.
Definition: build_map.c:796
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:172
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
Structure containing object statistics.
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.c:4695
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
This is a game-map.
Definition: map.h:325
const New_Face * face
Face with colors.
Definition: object.h:332
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:288
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:239
struct obj * more
Pointer to the rest of a large body of objects.
Definition: object.h:295
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.c:1129
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
struct archt archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
#define MSG_TYPE_APPLY_BUILD
Build related actions.
Definition: newclient.h:604
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
void apply_builder_remove(object *pl, int dir)
Item remover.
Definition: build_map.c:889
Definition: object.h:224