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(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;
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(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;
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;
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 */
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) {
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 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
Definition: object.h:323
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:171
global.h
CF_HANDLE
@ CF_HANDLE
Definition: object.h:213
spell_arrow.archetype
archetype
Definition: spell_arrow.py:11
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
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:212
diamondslots.x
x
Definition: diamondslots.py:15
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
oblinkpt::next
oblinkpt * next
Definition: object.h:463
ST_MAT_ITEM
#define ST_MAT_ITEM
Definition: define.h:69
object::arch
struct archetype * arch
Definition: object.h:422
FLAG_UNIQUE
#define FLAG_UNIQUE
Definition: define.h:287
fix_walls
static void fix_walls(mapstruct *map, int x, int y)
Definition: build_map.cpp:336
object::x
int16_t x
Definition: object.h:335
TIMED_GATE
@ TIMED_GATE
Definition: object.h:133
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
Ice.tmp
int tmp
Definition: Ice.py:207
apply_builder_remove
void apply_builder_remove(object *pl, int dir)
Definition: build_map.cpp:890
remove_marking_runes
static void remove_marking_runes(mapstruct *map, short x, short y)
Definition: build_map.cpp:158
MSG_TYPE_APPLY_BUILD
#define MSG_TYPE_APPLY_BUILD
Definition: newclient.h:598
oblinkpt
Definition: object.h:460
FLOOR
@ FLOOR
Definition: object.h:191
SIGN
@ SIGN
Definition: object.h:216
skills.h
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:4337
ST_BD_REMOVE
#define ST_BD_REMOVE
Definition: define.h:60
push.connected
connected
Definition: push.py:59
buf
StringBuffer * buf
Definition: readable.cpp:1552
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:2848
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
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
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
Definition: player.h:36
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Definition: object.h:572
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
object::y
int16_t y
Definition: object.h:335
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
disinfect.map
map
Definition: disinfect.py:4
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
object::subtype
uint8_t subtype
Definition: object.h:349
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:592
ST_MAT_FLOOR
#define ST_MAT_FLOOR
Definition: define.h:67
can_build_over
static int can_build_over(mapstruct *map, object *new_item, short x, short y)
Definition: build_map.cpp:48
ST_BD_BUILD
#define ST_BD_BUILD
Definition: define.h:59
archetype::clone
object clone
Definition: object.h:478
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
HEAD
#define HEAD(op)
Definition: object.h:598
oblinkpt::value
long value
Definition: object.h:462
object::face
const Face * face
Definition: object.h:341
object_update_speed
void object_update_speed(object *op)
Definition: object.cpp:1344
object::type
uint8_t type
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)
Definition: button.cpp:693
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:298
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:575
create-tower.builder
builder
Definition: create-tower.py:6
archetype
Definition: object.h:474
sproto.h
BOOK
@ BOOK
Definition: object.h:119
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:2095
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:74
MAX_BUF
#define MAX_BUF
Definition: define.h:35
INS_ON_TOP
#define INS_ON_TOP
Definition: object.h:574
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
IS_PLAYER
static bool IS_PLAYER(object *op)
Definition: object.h:600
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:216
MAGIC_EAR
@ MAGIC_EAR
Definition: object.h:136
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
object::slaying
sstring slaying
Definition: object.h:327
spells.h
object::name
sstring name
Definition: object.h:319
item
Definition: item.py:1
FLAG_IS_BUILDABLE
#define FLAG_IS_BUILDABLE
Definition: define.h:367
mapstruct
Definition: map.h:314
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
Definition: object.h:253
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.cpp:4802
object::msg
sstring msg
Definition: object.h:330
diamondslots.y
y
Definition: diamondslots.py:16
PEDESTAL
@ PEDESTAL
Definition: object.h:126
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:76
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:229
object::flags
ob_flags flags
Definition: object.h:425
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:1828
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
Definition: define.h:236
WALL
@ WALL
Definition: object.h:196
archetype::name
sstring name
Definition: object.h:475
FLAG_IS_LINKED
#define FLAG_IS_LINKED
Definition: define.h:315
say.item
dictionary item
Definition: say.py:149
object::more
object * more
Definition: object.h:303
connect
Definition: connect.py:1
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
tod.h
built
Story behind my Island The human king of the mainland has explorers scout for new territory On one expedition to an the explorers found some flecks of gold in the river they settled next to Upon notification of the king ordered a permanent colony be established in order to find and harvest the gold A while after the colony was built
Definition: lore.txt:9
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Definition: newclient.h:397
get_wall
static object * get_wall(mapstruct *map, int x, int y)
Definition: build_map.cpp:142
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
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:98
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:229
find_unused_connected_value
static int find_unused_connected_value(mapstruct *map)
Definition: build_map.cpp:234
DETECTOR
@ DETECTOR
Definition: object.h:154
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
GATE
@ GATE
Definition: object.h:211
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
ST_MAT_WINDOW
#define ST_MAT_WINDOW
Definition: define.h:70
dragon_attune.force
force
Definition: dragon_attune.py:45