Crossfire Server, Trunk  1.75.0
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(mapstruct *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(mapstruct *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(mapstruct *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;
287  FOR_INV_PREPARE(pl, tmp) {
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 */
299  connected = find_unused_connected_value(pl->map);
300  if (connected == -1) {
302  "Could not create more groups.");
303  return -1;
304  }
305 
306  force = create_archetype(FORCE_NAME);
307  force->speed = 0;
308  object_update_speed(force);
309  force->slaying = add_string(pl->map->path);
310  object_set_msg(force, rune->msg);
311  force->path_attuned = connected;
312  object_insert_in_ob(force, pl);
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(mapstruct *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 archetype *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;
481  object_insert_in_map_at(wall, map, NULL, INS_ABOVE_FLOOR_ONLY, x, y);
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 archetype *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;
528  object_remove(tmp);
530  snprintf(message, sizeof(message), "You destroy the wall and redo the floor.");
531  wall_removed = 1;
532  if (floor != NULL) {
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) {
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 */
580  SET_FLAG(tmp, FLAG_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 archetype *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) {
807  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BUILD, "Invalid square.");
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);
847  connected = find_or_create_connection_for_map(pl, x, y, con_rune);
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 */
934  if (QUERY_FLAG(item, FLAG_IS_LINKED))
935  remove_button_link(item);
936 
937  /* Fall through */
938  default:
939  /* Remove generic item */
940  query_name(item, name, MAX_BUF);
942  "You remove the %s",
943  name);
944  object_remove(item);
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) {
1004  if (!QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)
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 archetype *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 }
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:170
global.h
CF_HANDLE
@ CF_HANDLE
Definition: object.h:213
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
apply_builder_window
static int apply_builder_window(object *pl, object *new_wall_win, short x, short y)
Window building function.
Definition: build_map.cpp:707
ST_MAT_WALL
#define ST_MAT_WALL
Wall.
Definition: define.h:68
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
object::path_attuned
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
BUTTON
@ BUTTON
Definition: object.h:212
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
oblinkpt::next
oblinkpt * next
Next value in the list.
Definition: object.h:472
mapstruct::buttons
oblinkpt * buttons
Linked list of linked lists of buttons.
Definition: map.h:344
ST_MAT_ITEM
#define ST_MAT_ITEM
Most other items, including doors & such.
Definition: define.h:69
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
FLAG_IS_BUILDABLE
#define FLAG_IS_BUILDABLE
Can build on item.
Definition: define.h:367
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:287
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
fix_walls
static void fix_walls(mapstruct *map, int x, int y)
Fixes walls around specified spot.
Definition: build_map.cpp:336
object::x
int16_t x
Definition: object.h:335
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
TIMED_GATE
@ TIMED_GATE
Definition: object.h:133
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)
Floor building function.
Definition: build_map.cpp:507
apply_builder_remove
void apply_builder_remove(object *pl, int dir)
Item remover.
Definition: build_map.cpp:890
remove_marking_runes
static void remove_marking_runes(mapstruct *map, short x, short y)
Erases all marking runes at specified location (before building a wall)
Definition: build_map.cpp:158
MSG_TYPE_APPLY_BUILD
#define MSG_TYPE_APPLY_BUILD
Build related actions.
Definition: newclient.h:613
oblinkpt
Used to link together several object links.
Definition: object.h:469
FLOOR
@ FLOOR
Floor tile -> native layer 0.
Definition: object.h:191
SIGN
@ SIGN
Definition: object.h:216
skills.h
FOR_OB_AND_ABOVE_FINISH
#define FOR_OB_AND_ABOVE_FINISH()
Finishes FOR_OB_AND_ABOVE_PREPARE().
Definition: define.h:737
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
ST_BD_REMOVE
#define ST_BD_REMOVE
Removes an item.
Definition: define.h:60
buf
StringBuffer * buf
Definition: readable.cpp:1565
find_or_create_connection_for_map
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.cpp:272
object_insert_in_ob
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.cpp:2842
object::above
object * above
Pointer to the object stacked above this one.
Definition: object.h:296
get_connection_rune
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.cpp:103
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:239
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:302
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
range_builder
@ range_builder
Map builder.
Definition: player.h:36
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Put object immediatly above the floor.
Definition: object.h:581
apply_map_builder
void apply_map_builder(object *pl, int dir)
Global building function.
Definition: build_map.cpp:960
FOR_OB_AND_ABOVE_PREPARE
#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:733
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1545
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
ST_MAT_FLOOR
#define ST_MAT_FLOOR
Floor.
Definition: define.h:67
can_build_over
static int can_build_over(mapstruct *map, object *new_item, short x, short y)
Check if objects on a square interfere with building.
Definition: build_map.cpp:48
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:116
ST_BD_BUILD
#define ST_BD_BUILD
Builds an item.
Definition: define.h:59
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
oblinkpt::value
long value
Used as connected value in buttons/gates.
Definition: object.h:471
object::face
const Face * face
Face with colors.
Definition: object.h:341
object_update_speed
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1334
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
message
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your message
Definition: survival-guide.txt:34
remove_button_link
void remove_button_link(object *op)
Remove the object from the linked lists of buttons in the map.
Definition: button.cpp:693
object_create_arch
object * object_create_arch(archetype *at)
Create a full object using the given archetype.
Definition: arch.cpp:296
apply_builder_wall
static int apply_builder_wall(object *pl, object *new_wall, short x, short y)
Wall building function.
Definition: build_map.cpp:627
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:584
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
sproto.h
BOOK
@ BOOK
Definition: object.h:119
add_button_link
void add_button_link(object *button, mapstruct *map, int connected)
Links specified object in the map.
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)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2085
MAP_WIDTH
#define MAP_WIDTH(m)
Map width.
Definition: map.h:73
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
INS_ON_TOP
#define INS_ON_TOP
Always put object on top.
Definition: object.h:583
create_archetype
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.cpp:276
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
IS_PLAYER
static bool IS_PLAYER(object *op)
Definition: object.h:609
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:717
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:217
MAGIC_EAR
@ MAGIC_EAR
Definition: object.h:136
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
spells.h
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
mapstruct
This is a game-map.
Definition: map.h:315
sstring
const typedef char * sstring
Definition: sstring.h:2
floor
Magical Runes Runes are magical inscriptions on the dungeon floor
Definition: runes-guide.txt:3
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
MATERIAL
@ MATERIAL
Material for building.
Definition: object.h:253
object_set_msg
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.cpp:4796
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
PEDESTAL
@ PEDESTAL
Definition: object.h:126
MAP_HEIGHT
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:75
apply_builder_item
static int apply_builder_item(object *pl, object *new_item, short x, short y)
Generic item builder.
Definition: build_map.cpp:797
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
object::flags
ob_flags flags
Various flags.
Definition: object.h:427
get_msg_book
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.cpp:122
object_remove
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.cpp:1818
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
DOOR
@ DOOR
Definition: object.h:131
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
WALL
@ WALL
Wall.
Definition: object.h:196
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
FLAG_IS_LINKED
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:315
object::more
object * more
Pointer to the rest of a large body of objects.
Definition: object.h:303
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
tod.h
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:412
get_wall
static object * get_wall(mapstruct *map, int x, int y)
Returns first item of type WALL.
Definition: build_map.cpp:142
living.h
adjust_sign_msg
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.cpp:184
CUSTOM_NAME_FIELD
#define CUSTOM_NAME_FIELD
Key in an object for the player-assigned custom name.
Definition: object.h:98
find_marked_object
object * find_marked_object(object *op)
Return the object the player has marked with the 'mark' command below.
Definition: c_object.cpp:1522
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
FORCE
@ FORCE
Definition: object.h:229
find_unused_connected_value
static int find_unused_connected_value(mapstruct *map)
Returns an unused value for 'connected'.
Definition: build_map.cpp:234
DETECTOR
@ DETECTOR
peterm: detector is an object which notices the presense of another object and is triggered like butt...
Definition: object.h:154
archetype
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn though Notes on Specific and settings file datadir Usually usr share crossfire Contains data that the server does not need to modify while such as the etc A default install will pack the archetype
Definition: server-directories.txt:46
GATE
@ GATE
Definition: object.h:211
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
ST_MAT_WINDOW
#define ST_MAT_WINDOW
Window.
Definition: define.h:70