Crossfire Client, Trunk
mapdata.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 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 
19 #include "client.h"
20 
21 #include <assert.h>
22 #include <stdbool.h>
23 
24 #include "external.h"
25 #include "mapdata.h"
26 
31 
37 
39 int move_to_x = 0, move_to_y = 0;
40 bool move_to_attack = false;
41 
45 #define FOG_MAP_SIZE 512
46 
51 #define FOG_BORDER_MIN 128
52 
56 #define MAX_FACE_SIZE 16
57 
58 /* Max it can currently be. Important right now because
59  * animation has to look at everything that may be viewable,
60  * and reducing this size basically reduces processing it needs
61  * to do by 75% (64^2 vs 33^2)
62  */
63 #define CURRENT_MAX_VIEW 33
64 
78 struct BigCell {
79  struct BigCell *next;
80  struct BigCell *prev;
81 
84 
85  guint16 x, y;
86  guint8 layer;
87 };
88 
89 /* Global map rendering offsets used for local scroll prediction. */
92 int want_offset_x = 0;
93 int want_offset_y = 0;
94 
95 static void recenter_virtual_map_view(int diff_x, int diff_y);
96 static void mapdata_get_image_size(int face, guint8 *w, guint8 *h);
97 static void expand_need_update(int x, int y, int w, int h);
98 static void expand_need_update_from_layer(int x, int y, int layer);
99 
100 static int width; //< width of current map view
101 static int height; //< height of current map view
102 
107 static struct BigCell *bigfaces_head;
108 
115 
116 static struct Map the_map;
117 
121 static void clear_cells(int x, int y, int len_y) {
122  int clear_cells_i, j;
123  memset(mapdata_cell(x, y), 0, sizeof(struct MapCell)*len_y);
124 
125  for (clear_cells_i = 0; clear_cells_i < (len_y); clear_cells_i++) {
126  struct MapCell *cell = mapdata_cell(x, y+clear_cells_i);
127  for (j=0; j < MAXLAYERS; j++) {
128  cell->heads[j].size_x = 1;
129  cell->heads[j].size_y = 1;
130  }
131  }
132 }
133 
137 inline struct MapCell *mapdata_cell(const int x, const int y) {
138  return &the_map._cells[x][y];
139 }
140 
144 bool mapdata_contains(int x, int y) {
145  if (x < 0 || y < 0 || the_map.width <= x || the_map.height <= y) {
146  return false;
147  }
148 
149  return true;
150 }
151 
152 bool mapdata_can_smooth(int x, int y, int layer) {
153  return (mapdata_cell(x, y)->heads[layer].face == 0 && layer > 0) ||
154  mapdata_cell(x, y)->smooth[layer];
155 }
156 
160 void mapdata_size(int *x, int *y) {
161  if (x != NULL) {
162  *x = the_map.width;
163  }
164 
165  if (y != NULL) {
166  *y = the_map.height;
167  }
168 }
169 
178 static void set_darkness(int x, int y, int darkness)
179 {
180  if (mapdata_cell(x, y)->darkness == darkness) {
181  return;
182  }
183 
184  mapdata_cell(x, y)->darkness = darkness;
185  mapdata_cell(x, y)->need_update = 1;
186 }
187 
193 void mapdata_clear(int x, int y) {
194  int px = pl_pos.x + x;
195  int py = pl_pos.y + y;
196  assert(0 <= px && px < the_map.width);
197  assert(0 <= py && py < the_map.height);
198 
199  if (mapdata_cell(px, py) == EMPTY)
200  return;
201 
202  if (mapdata_cell(px, py)->state == VISIBLE) {
203  mapdata_cell(px, py)->need_update = 1;
204  for (int i = 0; i < MAXLAYERS; i++) {
205  if (mapdata_cell(px, py)->heads[i].face) {
207  }
208  }
209  }
210 
211  mapdata_cell(px, py)->state = FOG;
212 }
213 
214 static void mark_resmooth(int x, int y, int layer)
215 {
216  int sdx,sdy;
217  if (mapdata_cell(x, y)->smooth[layer]>1) {
218  for (sdx=-1; sdx<2; sdx++)
219  for (sdy=-1; sdy<2; sdy++)
220  if ( (sdx || sdy) /* ignore (0,0) */
221  && ( (x+sdx >0) && (x+sdx < the_map.width) && /* only inside map */
222  (y+sdy >0) && (y+sdy < the_map.height) ) ) {
223  mapdata_cell(x+sdx, y+sdy)->need_resmooth=1;
224  }
225  }
226 }
235 static void expand_clear_face(int x, int y, int w, int h, int layer)
236 {
237  int dx, dy;
238  struct MapCell *cell;
239 
240  assert(0 <= x && x < the_map.width);
241  assert(0 <= y && y < the_map.height);
242  assert(1 <= w && w <= MAX_FACE_SIZE);
243  assert(1 <= h && h <= MAX_FACE_SIZE);
244 
245  assert(0 <= x-w+1 && x-w+1 < the_map.width);
246  assert(0 <= y-h+1 && y-h+1 < the_map.height);
247 
248  cell = mapdata_cell(x, y);
249 
250  for (dx = 0; dx < w; dx++) {
251  for (dy = !dx; dy < h; dy++) {
252  struct MapCellTailLayer *tail = &mapdata_cell(x-dx, y-dy)->tails[layer];
253  assert(0 <= x-dx && x-dx < the_map.width);
254  assert(0 <= y-dy && y-dy < the_map.height);
255  assert(0 <= layer && layer < MAXLAYERS);
256 
257  /* Do not clear faces that already have been overwritten by another
258  * face.
259  */
260  if (tail->face == cell->heads[layer].face
261  && tail->size_x == dx
262  && tail->size_y == dy) {
263  tail->face = 0;
264  tail->size_x = 0;
265  tail->size_y = 0;
266  mapdata_cell(x-dx, y-dy)->need_update = 1;
267  }
268  mark_resmooth(x-dx,y-dy,layer);
269  }
270  }
271 
272  cell->heads[layer].face = 0;
273  cell->heads[layer].animation = 0;
274  cell->heads[layer].animation_speed = 0;
275  cell->heads[layer].animation_left = 0;
276  cell->heads[layer].animation_phase = 0;
277  cell->heads[layer].size_x = 1;
278  cell->heads[layer].size_y = 1;
279  cell->need_update = 1;
280  cell->need_resmooth = 1;
281  mark_resmooth(x,y,layer);
282 }
283 
290 static void expand_clear_face_from_layer(int x, int y, int layer)
291 {
292  const struct MapCellLayer *cell;
293 
294  assert(0 <= x && x < the_map.width);
295  assert(0 <= y && y < the_map.height);
296  assert(0 <= layer && layer < MAXLAYERS);
297 
298  cell = &mapdata_cell(x, y)->heads[layer];
299  if (cell->size_x && cell->size_y) {
300  expand_clear_face(x, y, cell->size_x, cell->size_y, layer);
301  }
302 }
303 
317 static void expand_set_face(int x, int y, int layer, gint16 face, int clear)
318 {
319  struct MapCell *cell;
320  int dx, dy;
321  guint8 w, h;
322 
323  assert(0 <= x && x < the_map.width);
324  assert(0 <= y && y < the_map.height);
325  assert(0 <= layer && layer < MAXLAYERS);
326 
327  cell = mapdata_cell(x, y);
328 
329  if (clear) {
330  expand_clear_face_from_layer(x, y, layer);
331  }
332 
333  mapdata_get_image_size(face, &w, &h);
334  assert(1 <= w && w <= MAX_FACE_SIZE);
335  assert(1 <= h && h <= MAX_FACE_SIZE);
336  cell->heads[layer].face = face;
337  cell->heads[layer].size_x = w;
338  cell->heads[layer].size_y = h;
339  cell->need_update=1;
340  mark_resmooth(x,y,layer);
341 
342  for (dx = 0; dx < w; dx++) {
343  for (dy = !dx; dy < h; dy++) {
344  struct MapCellTailLayer *tail = &mapdata_cell(x-dx, y-dy)->tails[layer];
345  assert(0 <= x-dx && x-dx < the_map.width);
346  assert(0 <= y-dy && y-dy < the_map.height);
347  assert(0 <= layer && layer < MAXLAYERS);
348 
349  tail->face = face;
350  tail->size_x = dx;
351  tail->size_y = dy;
352  mapdata_cell(x-dx, y-dy)->need_update = 1;
353  mark_resmooth(x-dx,y-dy,layer);
354  }
355  }
356 }
357 
368 static void expand_clear_bigface(int x, int y, int w, int h, int layer, int set_need_update)
369 {
370  int dx, dy;
371  struct MapCellLayer *head;
372 
373  assert(0 <= x && x < MAX_VIEW);
374  assert(0 <= y && y < MAX_VIEW);
375  assert(1 <= w && w <= MAX_FACE_SIZE);
376  assert(1 <= h && h <= MAX_FACE_SIZE);
377 
378  head = &bigfaces[x][y][layer].head;
379 
380  for (dx = 0; dx < w && dx <= x; dx++) {
381  for (dy = !dx; dy < h && dy <= y; dy++) {
382  struct MapCellTailLayer *tail = &bigfaces[x-dx][y-dy][layer].tail;
383  assert(0 <= x-dx && x-dx < MAX_VIEW);
384  assert(0 <= y-dy && y-dy < MAX_VIEW);
385  assert(0 <= layer && layer < MAXLAYERS);
386 
387  /* Do not clear faces that already have been overwritten by another
388  * face.
389  */
390  if (tail->face == head->face
391  && tail->size_x == dx
392  && tail->size_y == dy) {
393  tail->face = 0;
394  tail->size_x = 0;
395  tail->size_y = 0;
396 
397  if (0 <= x-dx && x-dx < width
398  && 0 <= y-dy && y-dy < height) {
399  assert(0 <= pl_pos.x+x-dx && pl_pos.x+x-dx < the_map.width);
400  assert(0 <= pl_pos.y+y-dy && pl_pos.y+y-dy < the_map.height);
401  if (set_need_update) {
402  mapdata_cell(pl_pos.x+x-dx, pl_pos.y+y-dy)->need_update = 1;
403  }
404  }
405  }
406  }
407  }
408 
409  head->face = 0;
410  head->size_x = 1;
411  head->size_y = 1;
412 }
413 
422 static void expand_clear_bigface_from_layer(int x, int y, int layer, int set_need_update)
423 {
424  struct BigCell *headcell;
425  const struct MapCellLayer *head;
426 
427  assert(0 <= x && x < MAX_VIEW);
428  assert(0 <= y && y < MAX_VIEW);
429  assert(0 <= layer && layer < MAXLAYERS);
430 
431  headcell = &bigfaces[x][y][layer];
432  head = &headcell->head;
433  if (head->face != 0) {
434  assert(headcell->prev != NULL || headcell == bigfaces_head);
435 
436  /* remove from bigfaces_head list */
437  if (headcell->prev != NULL) {
438  headcell->prev->next = headcell->next;
439  }
440  if (headcell->next != NULL) {
441  headcell->next->prev = headcell->prev;
442  }
443  if (bigfaces_head == headcell) {
444  assert(headcell->prev == NULL);
445  bigfaces_head = headcell->next;
446  } else {
447  assert(headcell->prev != NULL);
448  }
449  headcell->prev = NULL;
450  headcell->next = NULL;
451 
452  expand_clear_bigface(x, y, head->size_x, head->size_y, layer, set_need_update);
453  } else {
454  assert(headcell->prev == NULL && headcell != bigfaces_head);
455  assert(head->size_x == 1);
456  assert(head->size_y == 1);
457  }
458 }
459 
468 static void expand_set_bigface(int x, int y, int layer, gint16 face, int clear)
469 {
470  struct BigCell *headcell;
471  struct MapCellLayer *head;
472  int dx, dy;
473  guint8 w, h;
474 
475  assert(0 <= x && x < MAX_VIEW);
476  assert(0 <= y && y < MAX_VIEW);
477  assert(0 <= layer && layer < MAXLAYERS);
478 
479  headcell = &bigfaces[x][y][layer];
480  head = &headcell->head;
481  if (clear) {
482  expand_clear_bigface_from_layer(x, y, layer, 1);
483  }
484 
485  /* add to bigfaces_head list */
486  if (face != 0) {
487  assert(headcell->prev == NULL);
488  assert(headcell->next == NULL);
489  assert(headcell != bigfaces_head);
490  if (bigfaces_head != NULL) {
491  assert(bigfaces_head->prev == NULL);
492  bigfaces_head->prev = headcell;
493  }
494  headcell->next = bigfaces_head;
495  bigfaces_head = headcell;
496  }
497 
498  mapdata_get_image_size(face, &w, &h);
499  assert(1 <= w && w <= MAX_FACE_SIZE);
500  assert(1 <= h && h <= MAX_FACE_SIZE);
501  head->face = face;
502  head->size_x = w;
503  head->size_y = h;
504 
505  for (dx = 0; dx < w && dx <= x; dx++) {
506  for (dy = !dx; dy < h && dy <= y; dy++) {
507  struct MapCellTailLayer *tail = &bigfaces[x-dx][y-dy][layer].tail;
508  assert(0 <= x-dx && x-dx < MAX_VIEW);
509  assert(0 <= y-dy && y-dy < MAX_VIEW);
510  assert(0 <= layer && layer < MAXLAYERS);
511 
512  tail->face = face;
513  tail->size_x = dx;
514  tail->size_y = dy;
515 
516  if (0 <= x-dx && x-dx < width
517  && 0 <= y-dy && y-dy < height) {
518  assert(0 <= pl_pos.x+x-dx && pl_pos.x+x-dx < the_map.width);
519  assert(0 <= pl_pos.y+y-dy && pl_pos.y+y-dy < the_map.height);
520  mapdata_cell(pl_pos.x+x-dx, pl_pos.y+y-dy)->need_update = 1;
521  }
522  }
523  }
524 }
525 
533 static void expand_need_update(int x, int y, int w, int h)
534 {
535  int dx, dy;
536 
537  assert(0 <= x && x < the_map.width);
538  assert(0 <= y && y < the_map.height);
539  assert(1 <= w && w <= MAX_FACE_SIZE);
540  assert(1 <= h && h <= MAX_FACE_SIZE);
541 
542  assert(0 <= x-w+1 && x-w+1 < the_map.width);
543  assert(0 <= y-h+1 && y-h+1 < the_map.height);
544 
545  for (dx = 0; dx < w; dx++) {
546  for (dy = 0; dy < h; dy++) {
547  struct MapCell *cell = mapdata_cell(x-dx, y-dy);
548  assert(0 <= x-dx && x-dx < the_map.width);
549  assert(0 <= y-dy && y-dy < the_map.height);
550  cell->need_update = 1;
551  }
552  }
553 }
554 
561 static void expand_need_update_from_layer(int x, int y, int layer)
562 {
563  struct MapCellLayer *head;
564 
565  assert(0 <= x && x < the_map.width);
566  assert(0 <= y && y < the_map.height);
567  assert(0 <= layer && layer < MAXLAYERS);
568 
569  head = &mapdata_cell(x, y)->heads[layer];
570  if (head->face != 0) {
571  expand_need_update(x, y, head->size_x, head->size_y);
572  } else {
573  assert(head->size_x == 1);
574  assert(head->size_y == 1);
575  }
576 }
577 
582 static void mapdata_alloc(struct Map* const map, const int width, const int height) {
583  map->_cells = (struct MapCell **)g_new(struct MapCell, width * (height + 1));
584  g_assert(map->_cells != NULL); // g_new() always succeeds
585  map->width = width;
586  map->height = height;
587 
588  /* Skip past the first row of pointers to rows and assign the
589  * start of the actual map data
590  */
591  map->_cells[0] = (struct MapCell *)((char *)map->_cells+(sizeof(struct MapCell *)*map->width));
592 
593  /* Finish assigning the beginning of each row relative to the
594  * first row assigned above
595  */
596  for (int i = 0; i < map->width; i++) {
597  map->_cells[i] = map->_cells[0]+i*map->height;
598  }
599 }
600 
601 static void mapdata_init(void)
602 {
603  int x, y;
604  int i;
605 
607 
608  width = 0;
609  height = 0;
610  pl_pos.x = the_map.width/2-width/2;
611  pl_pos.y = the_map.height/2-height/2;
612 
613  for (x = 0; x < the_map.width; x++) {
614  clear_cells(x, 0, the_map.height);
615  }
616 
617  for (y = 0; y < MAX_VIEW; y++) {
618  for (x = 0; x < MAX_VIEW; x++) {
619  for (i = 0; i < MAXLAYERS; i++) {
620  bigfaces[x][y][i].next = NULL;
621  bigfaces[x][y][i].prev = NULL;
622  bigfaces[x][y][i].head.face = 0;
623  bigfaces[x][y][i].head.size_x = 1;
624  bigfaces[x][y][i].head.size_y = 1;
625  bigfaces[x][y][i].tail.face = 0;
626  bigfaces[x][y][i].tail.size_x = 0;
627  bigfaces[x][y][i].tail.size_y = 0;
628  bigfaces[x][y][i].x = x;
629  bigfaces[x][y][i].y = y;
630  bigfaces[x][y][i].layer = i;
631  }
632  }
633  }
634  bigfaces_head = NULL;
635 
636  global_offset_x = 0;
637  global_offset_y = 0;
638  want_offset_x = 0;
639  want_offset_y = 0;
640 }
641 
642 void mapdata_free(void) {
643  if (the_map._cells != NULL) {
644  g_free(the_map._cells);
645  the_map._cells = NULL;
646  the_map.width = 0;
647  the_map.height = 0;
648  }
649 }
650 
651 void mapdata_set_size(int viewx, int viewy)
652 {
653  mapdata_free();
654  mapdata_init();
655 
656  width = viewx;
657  height = viewy;
658  pl_pos.x = the_map.width/2-width/2;
659  pl_pos.y = the_map.height/2-height/2;
660 }
661 
662 int mapdata_is_inside(int x, int y)
663 {
664  return(x >= 0 && x < width && y >= 0 && y < height);
665 }
666 
667 /* mapdate_clear_space() is used by Map2Cmd()
668  * Basically, server has told us there is nothing on
669  * this space. So clear it.
670  */
671 void mapdata_clear_space(int x, int y)
672 {
673  int px, py;
674  int i;
675 
676  assert(0 <= x && x < MAX_VIEW);
677  assert(0 <= y && y < MAX_VIEW);
678 
679  px = pl_pos.x+x;
680  py = pl_pos.y+y;
681  assert(0 <= px && px < the_map.width);
682  assert(0 <= py && py < the_map.height);
683 
684  if (x < width && y < height) {
685  /* tile is visible */
686  /* visible tile is now blank ==> do not clear but mark as cleared */
687  mapdata_clear(x, y);
688  } else {
689  /* tile is invisible (outside view area, i.e. big face update) */
690 
691  for (i = 0; i < MAXLAYERS; i++) {
692  expand_set_bigface(x, y, i, 0, TRUE);
693  }
694  }
695 }
696 
697 
698 /* With map2, we basically process a piece of data at a time. Thus,
699  * for each piece, we don't know what the final state of the space
700  * will be. So once Map2Cmd() has processed all the information for
701  * a space, it calls mapdata_set_check_space() which can see if
702  * the space is cleared or other inconsistencies.
703  */
704 void mapdata_set_check_space(int x, int y)
705 {
706  int px, py;
707  int is_blank;
708  int i;
709  struct MapCell *cell;
710 
711  assert(0 <= x && x < MAX_VIEW);
712  assert(0 <= y && y < MAX_VIEW);
713 
714  px = pl_pos.x+x;
715  py = pl_pos.y+y;
716 
717  assert(0 <= px && px < the_map.width);
718  assert(0 <= py && py < the_map.height);
719 
720 
721  is_blank=1;
722  cell = mapdata_cell(px, py);
723  for (i=0; i < MAXLAYERS; i++) {
724  if (cell->heads[i].face>0 || cell->tails[i].face>0) {
725  is_blank=0;
726  break;
727  }
728  }
729 
730  if (cell->darkness != 0) {
731  is_blank=0;
732  }
733 
734  /* We only care if this space needs to be blanked out */
735  if (!is_blank) {
736  return;
737  }
738 
739  if (x < width && y < height) {
740  /* tile is visible */
741 
742  /* visible tile is now blank ==> do not clear but mark as cleared */
743  mapdata_clear(x, y);
744  }
745 }
746 
747 
748 
749 /* This just sets the darkness for a space.
750  * Used by Map2Cmd()
751  */
752 void mapdata_set_darkness(int x, int y, int darkness)
753 {
754  int px, py;
755 
756  assert(0 <= x && x < MAX_VIEW);
757  assert(0 <= y && y < MAX_VIEW);
758 
759  px = pl_pos.x+x;
760  py = pl_pos.y+y;
761  assert(0 <= px && px < the_map.width);
762  assert(0 <= py && py < the_map.height);
763 
764  /* Ignore darkness information for tile outside the viewable area: if
765  * such a tile becomes visible again, it is either "fog of war" (and
766  * darkness information is ignored) or it will be updated (including
767  * the darkness information).
768  */
769  if (darkness != -1 && x < width && y < height) {
770  set_darkness(px, py, 255-darkness);
771  }
772 }
773 
774 /* Sets smooth information for layer */
775 void mapdata_set_smooth(int x, int y, guint8 smooth, int layer)
776 {
777  static int dx[8]= {0,1,1,1,0,-1,-1,-1};
778  static int dy[8]= {-1,-1,0,1,1,1,0,-1};
779  int rx, ry, px, py, i;
780 
781  assert(0 <= x && x < MAX_VIEW);
782  assert(0 <= y && y < MAX_VIEW);
783 
784  px = pl_pos.x+x;
785  py = pl_pos.y+y;
786  assert(0 <= px && px < the_map.width);
787  assert(0 <= py && py < the_map.height);
788 
789  if (mapdata_cell(px, py)->smooth[layer] != smooth) {
790  for (i=0; i<8; i++) {
791  rx=px+dx[i];
792  ry=py+dy[i];
793  if ( (rx<0) || (ry<0) || (the_map.width<=rx) || (the_map.height<=ry)) {
794  continue;
795  }
796  mapdata_cell(rx, ry)->need_resmooth=1;
797  }
798  mapdata_cell(px, py)->need_resmooth=1;
799  mapdata_cell(px, py)->smooth[layer] = smooth;
800  }
801 }
802 
803 void mapdata_add_label(int x, int y, int subtype, const char *label) {
804  assert(0 <= x && x < MAX_VIEW);
805  assert(0 <= y && y < MAX_VIEW);
806  if (!(x < width && y < height))
807  return;
808 
809  int px = pl_pos.x + x;
810  int py = pl_pos.y + y;
811  assert(0 <= px && px < the_map.width);
812  assert(0 <= py && py < the_map.height);
813  struct MapLabel *new = g_malloc(sizeof(struct MapLabel));
814  new->subtype = subtype;
815  new->label = g_strdup(label);
816  new->next = mapdata_cell(px, py)->label;
817  mapdata_cell(px, py)->label = new;
818 }
819 
825 void mapdata_clear_old(int x, int y)
826 {
827  assert(0 <= x && x < MAX_VIEW);
828  assert(0 <= y && y < MAX_VIEW);
829  if (!(x < width && y < height))
830  return;
831 
832  int px = pl_pos.x + x;
833  int py = pl_pos.y + y;
834  assert(0 <= px && px < the_map.width);
835  assert(0 <= py && py < the_map.height);
836 
837  // In theory we only have to do this if this is a fog of war tile, because
838  // the server remembers what tiles are visible to us and sends the
839  // appropriate darkness updates.
840  if (mapdata_cell(px, py)->state == FOG) {
841  mapdata_cell(px, py)->need_update = 1;
842  for (int i = 0; i < MAXLAYERS; i++) {
843  expand_clear_face_from_layer(px, py, i);
844  }
845  mapdata_cell(px, py)->darkness = 0;
846  }
847 
848  while (mapdata_cell(px, py)->label != NULL) {
849  struct MapLabel *next = mapdata_cell(px, py)->label->next;
850  g_free(mapdata_cell(px, py)->label->label);
851  g_free(mapdata_cell(px, py)->label);
852  mapdata_cell(px, py)->label = next;
853  }
854 
855  mapdata_cell(px, py)->state = VISIBLE;
856 }
857 
858 /* This is vaguely related to the mapdata_set_face() above, but rather
859  * than take all the faces, takes 1 face and the layer this face is
860  * on. This is used by the Map2Cmd()
861  */
862 void mapdata_set_face_layer(int x, int y, gint16 face, int layer)
863 {
864  int px, py;
865 
866  assert(0 <= x && x < MAX_VIEW);
867  assert(0 <= y && y < MAX_VIEW);
868 
869  px = pl_pos.x+x;
870  py = pl_pos.y+y;
871  assert(0 <= px && px < the_map.width);
872  assert(0 <= py && py < the_map.height);
873 
874  if (x < width && y < height) {
875  mapdata_cell(px, py)->need_update = 1;
876  if (face >0) {
877  expand_set_face(px, py, layer, face, TRUE);
878  } else {
879  expand_clear_face_from_layer(px, py, layer);
880  }
881  } else {
882  expand_set_bigface(x, y, layer, face, TRUE);
883  }
884 }
885 
886 
887 /* This is vaguely related to the mapdata_set_face() above, but rather
888  * than take all the faces, takes 1 face and the layer this face is
889  * on. This is used by the Map2Cmd()
890  */
891 void mapdata_set_anim_layer(int x, int y, guint16 anim, guint8 anim_speed, int layer)
892 {
893  int px, py;
894  int i, face, animation, phase, speed_left;
895 
896  assert(0 <= x && x < MAX_VIEW);
897  assert(0 <= y && y < MAX_VIEW);
898 
899  px = pl_pos.x+x;
900  py = pl_pos.y+y;
901  assert(0 <= px && px < the_map.width);
902  assert(0 <= py && py < the_map.height);
903 
904  animation = anim & ANIM_MASK;
905  face = 0;
906 
907  /* Random animation is pretty easy */
908  if ((anim & ANIM_FLAGS_MASK) == ANIM_RANDOM) {
909  const guint8 num_animations = animations[animation].num_animations;
910  if (num_animations == 0) {
911  LOG(LOG_WARNING, "mapdata_set_anim_layer",
912  "animating object with zero animations");
913  return;
914  }
915  phase = g_random_int() % num_animations;
916  face = animations[animation].faces[phase];
917  speed_left = anim_speed % g_random_int();
918  } else if ((anim & ANIM_FLAGS_MASK) == ANIM_SYNC) {
919  animations[animation].speed = anim_speed;
920  phase = animations[animation].phase;
921  speed_left = animations[animation].speed_left;
922  face = animations[animation].faces[phase];
923  }
924 
925  if (x < width && y < height) {
926  mapdata_clear_old(x, y);
927  if (face >0) {
928  expand_set_face(px, py, layer, face, TRUE);
929  mapdata_cell(px, py)->heads[layer].animation = animation;
930  mapdata_cell(px, py)->heads[layer].animation_phase = phase;
931  mapdata_cell(px, py)->heads[layer].animation_speed = anim_speed;
932  mapdata_cell(px, py)->heads[layer].animation_left = speed_left;
933  } else {
934  expand_clear_face_from_layer(px, py, layer);
935  }
936  } else {
937  expand_set_bigface(x, y, layer, face, TRUE);
938  }
939 }
940 
941 
942 void mapdata_scroll(int dx, int dy)
943 {
944  script_pos.x += dx;
945  script_pos.y += dy;
946  int x, y;
947 
949 
951  struct BigCell *cell;
952 
953  /* Mark all tiles as "need_update" that are overlapped by a big face
954  * from outside the view area.
955  */
956  for (cell = bigfaces_head; cell != NULL; cell = cell->next) {
957  for (x = 0; x < cell->head.size_x; x++) {
958  for (y = !x; y < cell->head.size_y; y++) {
959  if (0 <= cell->x-x && cell->x-x < width
960  && 0 <= cell->y-y && cell->y-y < height) {
961  mapdata_cell(pl_pos.x+cell->x-x, pl_pos.y+cell->y-y)->need_update = 1;
962  }
963  }
964  }
965  }
966  } else {
967  /* Emulate map scrolling by redrawing all tiles. */
968  for (x = 0; x < width; x++) {
969  for (y = 0; y < height; y++) {
971  }
972  }
973  }
974 
975  pl_pos.x += dx;
976  pl_pos.y += dy;
977 
978  /* clear all newly visible tiles */
979  if (dx > 0) {
980  for (y = 0; y < height; y++) {
981  for (x = width-dx; x < width; x++) {
982  mapdata_clear(x, y);
983  }
984  }
985  } else {
986  for (y = 0; y < height; y++) {
987  for (x = 0; x < -dx; x++) {
988  mapdata_clear(x, y);
989  }
990  }
991  }
992 
993  if (dy > 0) {
994  for (x = 0; x < width; x++) {
995  for (y = height-dy; y < height; y++) {
996  mapdata_clear(x, y);
997  }
998  }
999  } else {
1000  for (x = 0; x < width; x++) {
1001  for (y = 0; y < -dy; y++) {
1002  mapdata_clear(x, y);
1003  }
1004  }
1005  }
1006 
1007  /* Remove all big faces outside the view area. */
1008  while (bigfaces_head != NULL) {
1010  }
1011 
1012  run_move_to();
1013 }
1014 
1015 void mapdata_newmap(void)
1016 {
1017  script_pos.x = 0;
1018  script_pos.y = 0;
1019  int x, y;
1020 
1021  global_offset_x = 0;
1022  global_offset_y = 0;
1023  want_offset_x = 0;
1024  want_offset_y = 0;
1025 
1026  // Clear past predictions.
1027  memset(csocket.dir, -1, sizeof(csocket.dir));
1028 
1029  /* Clear the_map.cells[]. */
1030  for (x = 0; x < the_map.width; x++) {
1031  clear_cells(x, 0, the_map.height);
1032  for (y = 0; y < the_map.height; y++) {
1033  mapdata_cell(x, y)->need_update = 1;
1034  }
1035  }
1036 
1037  /* Clear bigfaces[]. */
1038  while (bigfaces_head != NULL) {
1040  }
1041 
1042  // Clear destination.
1043  clear_move_to();
1044 }
1045 
1049 static bool mapdata_has_tile(int x, int y, int layer) {
1050  if (0 <= x && x < width && 0 <= y && y < height) {
1051  if (0 <= layer && layer < MAXLAYERS) {
1052  return true;
1053  }
1054  }
1055 
1056  return false;
1057 }
1058 
1066 gint16 mapdata_face(int x, int y, int layer) {
1067  if (!mapdata_has_tile(x, y, layer)) {
1068  return 0;
1069  }
1070 
1071  return mapdata_cell(pl_pos.x+x, pl_pos.y+y)->heads[layer].face;
1072 }
1073 
1074 gint16 mapdata_face_info(int mx, int my, int layer, int *dx, int *dy) {
1075  struct MapCellLayer *head = &mapdata_cell(mx, my)->heads[layer];
1076  struct MapCellTailLayer *tail = &mapdata_cell(mx, my)->tails[layer];
1077  if (head->face != 0) {
1078  const int width = head->size_x, height = head->size_y;
1079  *dx = 1 - width, *dy = 1 - height;
1080  return head->face;
1081  } else if (tail->face != 0) {
1082  struct MapCellLayer *head_ptr = &mapdata_cell(mx + tail->size_x, my + tail->size_y)->heads[layer];
1083  const int width = head_ptr->size_x, height = head_ptr->size_y;
1084  *dx = tail->size_x - width + 1, *dy = tail->size_y - height + 1;
1085  return tail->face;
1086  } else {
1087  return 0;
1088  }
1089 }
1090 
1100 gint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh) {
1101  gint16 result;
1102 
1103  if (!mapdata_has_tile(x, y, layer)) {
1104  return 0;
1105  }
1106 
1107  result = mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].face;
1108  if (result != 0) {
1109  int clear_bigface;
1110  int dx = mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].size_x;
1111  int dy = mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].size_y;
1112  int w = mapdata_cell(pl_pos.x+x+dx, pl_pos.y+y+dy)->heads[layer].size_x;
1113  int h = mapdata_cell(pl_pos.x+x+dx, pl_pos.y+y+dy)->heads[layer].size_y;
1114  assert(1 <= w && w <= MAX_FACE_SIZE);
1115  assert(1 <= h && h <= MAX_FACE_SIZE);
1116  assert(0 <= dx && dx < w);
1117  assert(0 <= dy && dy < h);
1118 
1119  /* Now check if we are about to display an obsolete big face: such a
1120  * face has a cleared ("fog of war") head but the current tile is not
1121  * fog of war. Since the server would have sent an appropriate head
1122  * tile if it was already valid, just clear the big face and do not
1123  * return it.
1124  */
1125  if (mapdata_cell(pl_pos.x+x, pl_pos.y+y)->state == FOG) {
1126  /* Current face is a "fog of war" tile ==> do not clear
1127  * old information.
1128  */
1129  clear_bigface = 0;
1130  } else {
1131  if (x+dx < width && y+dy < height) {
1132  /* Clear face if current tile is valid but the
1133  * head is marked as cleared.
1134  */
1135  clear_bigface = mapdata_cell(pl_pos.x+x+dx, pl_pos.y+y+dy)->state == FOG;
1136  } else {
1137  /* Clear face if current tile is valid but the
1138  * head is not set.
1139  */
1140  clear_bigface = bigfaces[x+dx][y+dy][layer].head.face == 0;
1141  }
1142  }
1143 
1144  if (!clear_bigface) {
1145  *ww = w-1-dx;
1146  *hh = h-1-dy;
1147  return(result);
1148  }
1149 
1150  assert(mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].face == result);
1151  expand_clear_face_from_layer(pl_pos.x+x+dx, pl_pos.y+y+dy, layer);
1152  assert(mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].face == 0);
1153  }
1154 
1155  result = bigfaces[x][y][layer].tail.face;
1156  if (result != 0) {
1157  int dx = bigfaces[x][y][layer].tail.size_x;
1158  int dy = bigfaces[x][y][layer].tail.size_y;
1159  int w = bigfaces[x+dx][y+dy][layer].head.size_x;
1160  int h = bigfaces[x+dx][y+dy][layer].head.size_y;
1161  assert(0 <= dx && dx < w);
1162  assert(0 <= dy && dy < h);
1163  *ww = w-1-dx;
1164  *hh = h-1-dy;
1165  return(result);
1166  }
1167 
1168  *ww = 1;
1169  *hh = 1;
1170  return(0);
1171 }
1172 
1173 /* This is used by the opengl logic.
1174  * Basically the opengl code draws the the entire image,
1175  * and doesn't care if if portions are off the edge
1176  * (opengl takes care of that). So basically, this
1177  * function returns only if the head for a space is set,
1178  * otherwise, returns 0 - we don't care about the tails
1179  * or other details really.
1180  */
1181 gint16 mapdata_bigface_head(int x, int y, int layer, int *ww, int *hh) {
1182  gint16 result;
1183 
1184  if (!mapdata_has_tile(x, y, layer)) {
1185  return 0;
1186  }
1187 
1188  result = bigfaces[x][y][layer].head.face;
1189  if (result != 0) {
1190  int w = bigfaces[x][y][layer].head.size_x;
1191  int h = bigfaces[x][y][layer].head.size_y;
1192  *ww = w;
1193  *hh = h;
1194  return(result);
1195  }
1196 
1197  *ww = 1;
1198  *hh = 1;
1199  return(0);
1200 }
1201 
1210 static void recenter_virtual_map_view(int diff_x, int diff_y)
1211 {
1212  int new_x, new_y;
1213  int shift_x, shift_y;
1214  int src_x, src_y;
1215  int dst_x, dst_y;
1216  int len_x, len_y;
1217  int sx;
1218  int dx;
1219  int i;
1220 
1221  /* shift player position in virtual map */
1222  new_x = pl_pos.x+diff_x;
1223  new_y = pl_pos.y+diff_y;
1224 
1225  /* determine neccessary amount to shift */
1226 
1227  /* if(new_x < 1) is not possible: a big face may reach up to
1228  * (MAX_FACE_SIZE-1) tiles to the left of pl_pos. Therefore maintain a
1229  * border of at least MAX_FACE_SIZE to the left of the virtual map
1230  * edge.
1231  */
1232  if (new_x < MAX_FACE_SIZE) {
1233  shift_x = FOG_BORDER_MIN+MAX_FACE_SIZE-new_x;
1234  /* This yields: new_x+shift_x == FOG_BORDER_MIN+MAX_FACE_SIZE,
1235  * i.e. left border is FOG_BORDER_MIN+MAX_FACE_SIZE after
1236  * shifting.
1237  */
1238  } else if (new_x+MAX_VIEW > the_map.width) {
1239  shift_x = the_map.width-FOG_BORDER_MIN-MAX_VIEW-new_x;
1240  /* This yields: new_x+shift_x ==
1241  * the_map.width-FOG_BODER_MIN-MAX_VIEW, i.e. right border is
1242  * FOGBORDER_MIN after shifting.
1243  */
1244  } else {
1245  shift_x = 0;
1246  }
1247 
1248  /* Same as above but for y. */
1249  if (new_y < MAX_FACE_SIZE) {
1250  shift_y = FOG_BORDER_MIN+MAX_FACE_SIZE-new_y;
1251  } else if (new_y+MAX_VIEW > the_map.height) {
1252  shift_y = the_map.height-FOG_BORDER_MIN-MAX_VIEW-new_y;
1253  } else {
1254  shift_y = 0;
1255  }
1256 
1257  /* No shift neccessary? ==> nothing to do. */
1258  if (shift_x == 0 && shift_y == 0) {
1259  return;
1260  }
1261 
1262  /* If shifting at all: maintain a border size of FOG_BORDER_MIN to all
1263  * directions. For example: if pl_pos=30/MAX_FACE_SIZE, and map_scroll is
1264  * 0/-1: shift pl_pos to FOG_BORDER_MIN+1/FOG_BORDER_MIN+1, not to
1265  * 30/FOG_BORDER_MIN+1.
1266  */
1267  if (shift_x == 0) {
1268  if (new_x < FOG_BORDER_MIN+MAX_FACE_SIZE) {
1269  shift_x = FOG_BORDER_MIN+MAX_FACE_SIZE-new_x;
1270  } else if (new_x+MAX_VIEW+FOG_BORDER_MIN > the_map.width) {
1271  shift_x = the_map.width-FOG_BORDER_MIN-MAX_VIEW-new_x;
1272  }
1273  }
1274  if (shift_y == 0) {
1275  if (new_y < FOG_BORDER_MIN+MAX_FACE_SIZE) {
1276  shift_y = FOG_BORDER_MIN+MAX_FACE_SIZE-new_y;
1277  } else if (new_y+MAX_VIEW+FOG_BORDER_MIN > the_map.height) {
1278  shift_y = the_map.height-FOG_BORDER_MIN-MAX_VIEW-new_y;
1279  }
1280  }
1281 
1282  /* Shift for more than virtual map size? ==> clear whole virtual map
1283  * and recenter.
1284  */
1285  if (shift_x <= -the_map.width || shift_x >= the_map.width
1286  || shift_y <= -the_map.height || shift_y >= the_map.height) {
1287  for (dx = 0; dx < the_map.width; dx++) {
1288  clear_cells(dx, 0, the_map.height);
1289  }
1290 
1291  pl_pos.x = the_map.width/2-width/2;
1292  pl_pos.y = the_map.height/2-height/2;
1293  return;
1294  }
1295 
1296  /* Move player position. */
1297  pl_pos.x += shift_x;
1298  pl_pos.y += shift_y;
1299 
1300  /* Actually shift the virtual map by shift_x/shift_y */
1301  if (shift_x < 0) {
1302  src_x = -shift_x;
1303  dst_x = 0;
1304  len_x = the_map.width+shift_x;
1305  } else {
1306  src_x = 0;
1307  dst_x = shift_x;
1308  len_x = the_map.width-shift_x;
1309  }
1310 
1311  if (shift_y < 0) {
1312  src_y = -shift_y;
1313  dst_y = 0;
1314  len_y = the_map.height+shift_y;
1315  } else {
1316  src_y = 0;
1317  dst_y = shift_y;
1318  len_y = the_map.height-shift_y;
1319  }
1320 
1321  if (shift_x < 0) {
1322  for (sx = src_x, dx = dst_x, i = 0; i < len_x; sx++, dx++, i++) {
1323  /* srcx!=dstx ==> can use memcpy since source and
1324  * destination to not overlap.
1325  */
1326  memcpy(mapdata_cell(dx, dst_y), mapdata_cell(sx, src_y), len_y*sizeof(struct MapCell));
1327  }
1328  } else if (shift_x > 0) {
1329  for (sx = src_x+len_x-1, dx = dst_x+len_x-1, i = 0; i < len_x; sx--, dx--, i++) {
1330  /* srcx!=dstx ==> can use memcpy since source and
1331  * destination to not overlap.
1332  */
1333  memcpy(mapdata_cell(dx, dst_y), mapdata_cell(sx, src_y), len_y*sizeof(struct MapCell));
1334  }
1335  } else {
1336  assert(src_x == dst_x);
1337  for (dx = src_x, i = 0; i < len_x; dx++, i++) {
1338  /* srcx==dstx ==> use memmove since source and
1339  * destination probably do overlap.
1340  */
1341  memmove(mapdata_cell(dx, dst_y), mapdata_cell(dx, src_y), len_y*sizeof(struct MapCell));
1342  }
1343  }
1344 
1345  /* Clear newly opened area */
1346  for (dx = 0; dx < dst_x; dx++) {
1347  clear_cells(dx, 0, the_map.height);
1348  }
1349  for (dx = dst_x+len_x; dx < the_map.width; dx++) {
1350  clear_cells(dx, 0, the_map.height);
1351  }
1352  if (shift_y > 0) {
1353  for (dx = 0; dx < len_x; dx++) {
1354  clear_cells(dx+dst_x, 0, shift_y);
1355  }
1356  } else if (shift_y < 0) {
1357  for (dx = 0; dx < len_x; dx++) {
1358  clear_cells(dx+dst_x, the_map.height+shift_y, -shift_y);
1359  }
1360  }
1361 }
1362 
1367 static void mapdata_get_image_size(int face, guint8 *w, guint8 *h)
1368 {
1369  get_map_image_size(face, w, h);
1370  if (*w < 1) {
1371  *w = 1;
1372  }
1373  if (*h < 1) {
1374  *h = 1;
1375  }
1376  if (*w > MAX_FACE_SIZE) {
1377  *w = MAX_FACE_SIZE;
1378  }
1379  if (*h > MAX_FACE_SIZE) {
1380  *h = MAX_FACE_SIZE;
1381  }
1382 }
1383 
1384 /* This basically goes through all the map spaces and does the necessary
1385  * animation.
1386  */
1388 {
1389  int x, y, layer, face;
1390  struct MapCellLayer *cell;
1391 
1392 
1393  /* For synchronized animations, what we do is set the initial values
1394  * in the mapdata to the fields in the animations[] array. In this way,
1395  * the code below the iterates the spaces doesn't need to do anything
1396  * special. But we have to update the animations[] array here to
1397  * keep in sync.
1398  */
1399  for (x=0; x < MAXANIM; x++) {
1400  if (animations[x].speed) {
1401  animations[x].speed_left++;
1402  if (animations[x].speed_left >= animations[x].speed) {
1403  animations[x].speed_left=0;
1404  animations[x].phase++;
1405  if (animations[x].phase >= animations[x].num_animations) {
1406  animations[x].phase=0;
1407  }
1408  }
1409  }
1410  }
1411 
1412  for (x=0; x < CURRENT_MAX_VIEW; x++) {
1413  for (y=0; y < CURRENT_MAX_VIEW; y++) {
1414  struct MapCell *map_space = mapdata_cell(pl_pos.x + x, pl_pos.y + y);
1415 
1416  /* Short cut some processing here. It makes sense to me
1417  * not to animate stuff out of view
1418  */
1419  if (map_space->state != VISIBLE) {
1420  continue;
1421  }
1422 
1423  for (layer=0; layer<MAXLAYERS; layer++) {
1424  /* Using the cell structure just makes life easier here */
1425  cell = &map_space->heads[layer];
1426 
1427  if (cell->animation) {
1428  cell->animation_left++;
1429  if (cell->animation_left >= cell->animation_speed) {
1430  cell->animation_left=0;
1431  cell->animation_phase++;
1432  if (cell->animation_phase >= animations[cell->animation].num_animations) {
1433  cell->animation_phase=0;
1434  }
1435  face = animations[cell->animation].faces[cell->animation_phase];
1436 
1437  /* I don't think we send any to the client, but it is possible
1438  * for animations to have blank faces.
1439  */
1440  if (face >0) {
1441  expand_set_face(pl_pos.x + x, pl_pos.y + y, layer, face, FALSE);
1442  } else {
1443  expand_clear_face_from_layer(pl_pos.x + x, pl_pos.y + y , layer);
1444  }
1445  }
1446  }
1447  cell = &bigfaces[x][y][layer].head;
1448  if (cell->animation) {
1449  cell->animation_left++;
1450  if (cell->animation_left >= cell->animation_speed) {
1451  cell->animation_left=0;
1452  cell->animation_phase++;
1453  if (cell->animation_phase >= animations[cell->animation].num_animations) {
1454  cell->animation_phase=0;
1455  }
1456  face = animations[cell->animation].faces[cell->animation_phase];
1457 
1458  /* I don't think we send any to the client, but it is possible
1459  * for animations to have blank faces.
1460  */
1461  expand_set_bigface(x, y, layer, face, FALSE);
1462  }
1463  }
1464  }
1465  }
1466  }
1467 }
1468 
1474 void pl_mpos(int *px, int *py) {
1475  const int vw = use_config[CONFIG_MAPWIDTH];
1476  const int vh = use_config[CONFIG_MAPHEIGHT];
1477  *px = pl_pos.x + vw/2;
1478  *py = pl_pos.y + vh/2;
1479 }
1480 
1481 void set_move_to(int dx, int dy) {
1482  int old_move_to_x = move_to_x;
1483  int old_move_to_y = move_to_y;
1484 
1486  move_to_x += dx;
1487  move_to_y += dy;
1488 
1489  if (move_to_x == old_move_to_x && move_to_y == old_move_to_y) {
1490  // Detect double-click.
1491  move_to_attack = true;
1492  } else {
1493  move_to_attack = false;
1494  }
1495 }
1496 
1498  move_to_x = 0;
1499  move_to_y = 0;
1500  move_to_attack = false;
1501 }
1502 
1504  if (move_to_x == 0 && move_to_y == 0) {
1505  return true;
1506  }
1507 
1508  int px, py;
1509  pl_mpos(&px, &py);
1510  return !(move_to_x != px || move_to_y != py);
1511 }
1512 
1513 void run_move_to() {
1514  if (move_to_x == 0 && move_to_y == 0) {
1515  // If not moving to a tile, skip to avoid calling stop_run().
1516  return;
1517  }
1518 
1519  if (is_at_moveto()) {
1520  clear_move_to();
1521  stop_run();
1522  return;
1523  }
1524 
1525  int px, py;
1526  pl_mpos(&px, &py);
1527  int dx = move_to_x - px;
1528  int dy = move_to_y - py;
1529  int dir = relative_direction(dx, dy);
1530 
1531  if (move_to_attack) {
1532  run_dir(dir);
1533  } else {
1534  walk_dir(dir);
1535  }
1536 }
run_dir
void run_dir(int dir)
Definition: player.c:146
mapdata_cell
struct MapCell * mapdata_cell(const int x, const int y)
Get the stored map cell at the given map coordinate.
Definition: mapdata.c:137
Map::height
int height
Definition: mapdata.h:84
ANIM_SYNC
#define ANIM_SYNC
Definition: newclient.h:321
MapCellTailLayer::size_x
gint8 size_x
Definition: mapdata.h:38
mapdata_clear_space
void mapdata_clear_space(int x, int y)
Definition: mapdata.c:671
relative_direction
int relative_direction(int dx, int dy)
Given a relative tile coordinate, determine its compass direction.
Definition: map.c:560
LOG_WARNING
@ LOG_WARNING
Warning that something might not work.
Definition: client.h:437
Map
Definition: mapdata.h:80
PlayerPosition::x
int x
Definition: client.h:527
is_at_moveto
bool is_at_moveto()
Definition: mapdata.c:1503
want_offset_x
int want_offset_x
Definition: mapdata.c:92
mapdata_bigface
gint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh)
Return the face number of a multi-square pixmap at the given map tile.
Definition: mapdata.c:1100
external.h
mapdata_set_face_layer
void mapdata_set_face_layer(int x, int y, gint16 face, int layer)
Definition: mapdata.c:862
Animations::phase
guint8 phase
Definition: client.h:107
move_to_x
int move_to_x
Move to coordinates on the current map.
Definition: mapdata.c:39
VISIBLE
@ VISIBLE
Definition: mapdata.h:45
mapdata_newmap
void mapdata_newmap(void)
Clears the map view.
Definition: mapdata.c:1015
mapdata_face
gint16 mapdata_face(int x, int y, int layer)
Return the face number of a single-square pixmap at the given map tile.
Definition: mapdata.c:1066
BigCell::head
struct MapCellLayer head
Definition: mapdata.c:82
expand_need_update
static void expand_need_update(int x, int y, int w, int h)
Mark a face as "need_update".
Definition: mapdata.c:533
Animations::num_animations
guint8 num_animations
Number of animations.
Definition: client.h:101
height
static int height
Definition: mapdata.c:101
mapdata_set_smooth
void mapdata_set_smooth(int x, int y, guint8 smooth, int layer)
Definition: mapdata.c:775
bigfaces_head
static struct BigCell * bigfaces_head
Contains the head of a list of all currently active big faces outside the view area.
Definition: mapdata.c:107
mapdata_set_check_space
void mapdata_set_check_space(int x, int y)
Definition: mapdata.c:704
mapdata_can_smooth
bool mapdata_can_smooth(int x, int y, int layer)
Definition: mapdata.c:152
move_to_attack
bool move_to_attack
Definition: mapdata.c:40
MapCellTailLayer::face
gint16 face
Definition: mapdata.h:37
expand_clear_face
static void expand_clear_face(int x, int y, int w, int h, int layer)
Clear a face from the_map.cells[].
Definition: mapdata.c:235
Animations::speed
guint8 speed
Definition: client.h:105
FOG_MAP_SIZE
#define FOG_MAP_SIZE
Size of virtual map.
Definition: mapdata.c:45
mapdata_alloc
static void mapdata_alloc(struct Map *const map, const int width, const int height)
Allocate and set up pointers for a map, with cells represented as a C-style multi-dimensional array.
Definition: mapdata.c:582
mapdata_clear_old
void mapdata_clear_old(int x, int y)
Prepare a map cell, which may contain old fog of war data, for new visible map data.
Definition: mapdata.c:825
expand_need_update_from_layer
static void expand_need_update_from_layer(int x, int y, int layer)
Mark a face as "need_update".
Definition: mapdata.c:561
PlayerPosition::y
int y
Definition: client.h:528
display_mapscroll
int display_mapscroll(int dx, int dy)
Definition: map.c:155
MapCell::state
enum MapCellState state
Definition: mapdata.h:71
FOG_BORDER_MIN
#define FOG_BORDER_MIN
After shifting the virtual map: new minimum distance of the view area to the new virtual map border.
Definition: mapdata.c:51
MapLabel::subtype
int subtype
Definition: mapdata.h:75
mapdata.h
global_offset_y
int global_offset_y
Definition: mapdata.c:91
expand_set_bigface
static void expand_set_bigface(int x, int y, int layer, gint16 face, int clear)
Update a face into bigfaces[].
Definition: mapdata.c:468
mapdata_init
static void mapdata_init(void)
Definition: mapdata.c:601
MapCellLayer::face
gint16 face
Definition: mapdata.h:19
recenter_virtual_map_view
static void recenter_virtual_map_view(int diff_x, int diff_y)
Check if current map position is out of bounds if shifted by (dx, dy).
Definition: mapdata.c:1210
MapCellTailLayer::size_y
gint8 size_y
Definition: mapdata.h:39
MapCell::heads
struct MapCellLayer heads[MAXLAYERS]
Definition: mapdata.h:64
mapdata_get_image_size
static void mapdata_get_image_size(int face, guint8 *w, guint8 *h)
Return the size of a face in tiles.
Definition: mapdata.c:1367
mapdata_size
void mapdata_size(int *x, int *y)
Determine the size of the internal fog-of-war map.
Definition: mapdata.c:160
ANIM_RANDOM
#define ANIM_RANDOM
Definition: newclient.h:320
move_to_y
int move_to_y
Definition: mapdata.c:39
mapdata_free
void mapdata_free(void)
Deallocate map data.
Definition: mapdata.c:642
MapCellLayer::animation_phase
guint8 animation_phase
Definition: mapdata.h:33
CONFIG_MAPSCROLL
#define CONFIG_MAPSCROLL
Use bitmap operations for map scrolling.
Definition: client.h:211
mapdata_has_tile
static bool mapdata_has_tile(int x, int y, int layer)
Check if the given map tile is a valid slot in the map array.
Definition: mapdata.c:1049
mapdata_set_anim_layer
void mapdata_set_anim_layer(int x, int y, guint16 anim, guint8 anim_speed, int layer)
Definition: mapdata.c:891
Map::_cells
struct MapCell ** _cells
Definition: mapdata.h:82
want_offset_y
int want_offset_y
Definition: mapdata.c:93
MapCell::smooth
guint8 smooth[MAXLAYERS]
Definition: mapdata.h:67
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Log messages of a certain importance to stderr.
Definition: misc.c:111
global_offset_x
int global_offset_x
Definition: mapdata.c:90
mapdata_bigface_head
gint16 mapdata_bigface_head(int x, int y, int layer, int *ww, int *hh)
Definition: mapdata.c:1181
width
static int width
Definition: mapdata.c:100
walk_dir
void walk_dir(int dir)
Definition: player.c:173
MapLabel
Definition: mapdata.h:74
the_map
static struct Map the_map
Definition: mapdata.c:116
want_config
gint16 want_config[CONFIG_NUMS]
Definition: init.c:43
csocket
ClientSocket csocket
Definition: client.c:70
MapCell::darkness
guint8 darkness
Definition: mapdata.h:68
MapLabel::label
char * label
Definition: mapdata.h:76
expand_clear_bigface_from_layer
static void expand_clear_bigface_from_layer(int x, int y, int layer, int set_need_update)
Clear a face from bigfaces[].
Definition: mapdata.c:422
mapdata_face_info
gint16 mapdata_face_info(int mx, int my, int layer, int *dx, int *dy)
Return the face number of the pixmap in the given map cell and set the offset pointers to indicate wh...
Definition: mapdata.c:1074
MapCell
The heads[] in the mapcell is used for single part objects or the head piece for multipart.
Definition: mapdata.h:62
Map::width
int width
Definition: mapdata.h:83
mapdata_clear
void mapdata_clear(int x, int y)
Mark the given cell as cleared in response to a Map2 clear command.
Definition: mapdata.c:193
mark_resmooth
static void mark_resmooth(int x, int y, int layer)
Definition: mapdata.c:214
Animations::speed_left
guint8 speed_left
Definition: client.h:106
BigCell::next
struct BigCell * next
Definition: mapdata.c:79
get_map_image_size
void get_map_image_size(int face, guint8 *w, guint8 *h)
Definition: image.c:341
mapdata_is_inside
int mapdata_is_inside(int x, int y)
Checks whether the given coordinates are within the current display size (as set by mapdata_set_size)...
Definition: mapdata.c:662
stop_run
void stop_run()
Definition: player.c:141
mapdata_contains
bool mapdata_contains(int x, int y)
Determine whether the map data contains the given cell.
Definition: mapdata.c:144
FOG
@ FOG
Definition: mapdata.h:46
expand_clear_bigface
static void expand_clear_bigface(int x, int y, int w, int h, int layer, int set_need_update)
Clear a face from bigfaces[].
Definition: mapdata.c:368
MapCell::need_resmooth
guint8 need_resmooth
Definition: mapdata.h:70
map
static item * map
Definition: item.c:27
MapCellTailLayer
Definition: mapdata.h:36
set_move_to
void set_move_to(int dx, int dy)
Definition: mapdata.c:1481
Animations::faces
guint16 * faces
Definition: client.h:108
MapCell::tails
struct MapCellTailLayer tails[MAXLAYERS]
Definition: mapdata.h:65
MAX_FACE_SIZE
#define MAX_FACE_SIZE
Maximum size of a big face image in tiles.
Definition: mapdata.c:56
set_darkness
static void set_darkness(int x, int y, int darkness)
Update darkness information.
Definition: mapdata.c:178
bigfaces
static struct BigCell bigfaces[MAX_VIEW][MAX_VIEW][MAXLAYERS]
The variable bigfaces[] contains information about big faces (faces with a width or height >1).
Definition: mapdata.c:114
MapCellLayer
Definition: mapdata.h:18
CONFIG_MAPWIDTH
#define CONFIG_MAPWIDTH
Definition: client.h:201
mapdata_scroll
void mapdata_scroll(int dx, int dy)
Scrolls the map view.
Definition: mapdata.c:942
BigCell::layer
guint8 layer
Definition: mapdata.c:86
EMPTY
@ EMPTY
Definition: mapdata.h:44
clear_move_to
void clear_move_to()
Definition: mapdata.c:1497
ANIM_MASK
#define ANIM_MASK
AND'ing this with data from server gets us just the animation id.
Definition: newclient.h:329
MapCellLayer::size_x
gint8 size_x
Definition: mapdata.h:20
mapdata_set_size
void mapdata_set_size(int viewx, int viewy)
Initializes the module.
Definition: mapdata.c:651
mapdata_add_label
void mapdata_add_label(int x, int y, int subtype, const char *label)
Definition: mapdata.c:803
expand_clear_face_from_layer
static void expand_clear_face_from_layer(int x, int y, int layer)
Clear a face from the_map.cells[].
Definition: mapdata.c:290
BigCell::x
guint16 x
Definition: mapdata.c:85
pl_mpos
void pl_mpos(int *px, int *py)
Compute player position in map coordinates.
Definition: mapdata.c:1474
MapCellLayer::animation_left
guint8 animation_left
Definition: mapdata.h:32
MapCellLayer::size_y
gint8 size_y
Definition: mapdata.h:21
PlayerPosition
Definition: client.h:526
CURRENT_MAX_VIEW
#define CURRENT_MAX_VIEW
Definition: mapdata.c:63
mapdata_set_darkness
void mapdata_set_darkness(int x, int y, int darkness)
Definition: mapdata.c:752
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:244
ClientSocket::dir
gint8 dir[COMMAND_MAX]
Definition: client.h:136
MAXLAYERS
#define MAXLAYERS
The protocol supports 10 layers, so set MAXLAYERS accordingly.
Definition: mapdata.h:6
pl_pos
PlayerPosition pl_pos
Position of the player on the internal map.
Definition: mapdata.c:30
run_move_to
void run_move_to()
Definition: mapdata.c:1513
MAXANIM
#define MAXANIM
Definition: client.h:86
animations
Animations animations[MAXANIM]
Definition: commands.c:1155
ANIM_FLAGS_MASK
#define ANIM_FLAGS_MASK
Used only by the client.
Definition: newclient.h:323
clear_cells
static void clear_cells(int x, int y, int len_y)
Clear cells the_map.cells[x][y..y+len_y-1].
Definition: mapdata.c:121
CONFIG_MAPHEIGHT
#define CONFIG_MAPHEIGHT
Definition: client.h:202
expand_set_face
static void expand_set_face(int x, int y, int layer, gint16 face, int clear)
Update a face into the_map.cells[].
Definition: mapdata.c:317
MapLabel::next
struct MapLabel * next
Definition: mapdata.h:77
BigCell
The struct BigCell describes a tile outside the view area.
Definition: mapdata.c:78
MAX_VIEW
#define MAX_VIEW
Maximum size of view area a server could support.
Definition: mapdata.h:11
BigCell::tail
struct MapCellTailLayer tail
Definition: mapdata.c:83
mapdata_animation
void mapdata_animation(void)
Definition: mapdata.c:1387
BigCell::y
guint16 y
Definition: mapdata.c:85
MapCellLayer::animation_speed
guint8 animation_speed
Definition: mapdata.h:31
BigCell::prev
struct BigCell * prev
Definition: mapdata.c:80
MapCell::need_update
guint8 need_update
Definition: mapdata.h:69
client.h
MapCell::label
struct MapLabel * label
Definition: mapdata.h:66
MapCellLayer::animation
gint16 animation
Definition: mapdata.h:30
script_pos
PlayerPosition script_pos
Position of the player reported to client scripts.
Definition: mapdata.c:36