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
14 /**
15 * @file
16 * Map processing functions.
17 */
18
19 #include "client.h"
20
21 #include <assert.h>
22 #include <stdbool.h>
23
24 #include "external.h"
25 #include "mapdata.h"
26
27 /**
28 * Position of a player on the map, relative to the coordinates received
29 * after a 'newmap' command. These are kept to for reporting to client scripts.
30 */
31 PlayerPosition script_pos;
32
33 /**
34 * Size of virtual map.
35 */
36 #define FOG_MAP_SIZE 512
37
38 /**
39 * After shifting the virtual map: new minimum distance of the view area to the
40 * new virtual map border.
41 */
42 #define FOG_BORDER_MIN 128
43
44 /**
45 * Maximum size of a big face image in tiles. Larger faces will be clipped top/left.
46 */
47 #define MAX_FACE_SIZE 16
48
49 /* Max it can currently be. Important right now because
50 * animation has to look at everything that may be viewable,
51 * and reducing this size basically reduces processing it needs
52 * to do by 75% (64^2 vs 33^2)
53 */
54 #define CURRENT_MAX_VIEW 33
55
56 /**
57 * The struct BigCell describes a tile *outside* the view area. head contains
58 * the head (as sent by the server), tail contains the expanded big face. tail
59 * is *not* set for the head cell, that is (for example) a big face with size
60 * 2x3 occupies exactly 6 entries: 1 head and 5 tails.
61 *
62 * next and prev for a doubly linked list of all currently active entries.
63 * Unused entries are set to NULL.
64 *
65 * x, y, and layer contain the position of the cell in the bigfaces[] array.
66 * This information allows to find the corresponding bigfaces[] cell when
67 * iterating through the next pointers.
68 */
69 struct BigCell {
70 struct BigCell *next;
71 struct BigCell *prev;
72
73 struct MapCellLayer head;
74 struct MapCellTailLayer tail;
75
76 guint16 x, y;
77 guint8 layer;
78 };
79
80 int global_offset_x = 0;
81 int global_offset_y = 0;
82 int want_offset_x = 0;
83 int want_offset_y = 0;
84
85 static void recenter_virtual_map_view(int diff_x, int diff_y);
86 static void mapdata_get_image_size(int face, guint8 *w, guint8 *h);
87
88
89 static int width; //< width of current map view
90 static int height; //< height of current map view
91
92
93 /**
94 * Contains the head of a list of all currently active big faces outside the
95 * view area. All entries are part of bigfaces[].
96 */
97 static struct BigCell *bigfaces_head;
98
99 /**
100 * The variable bigfaces[] contains information about big faces (faces with a
101 * width or height >1). The viewable area bigfaces[0..width-1][0..height-1] is
102 * unused.
103 */
104 static struct BigCell bigfaces[MAX_VIEW][MAX_VIEW][MAXLAYERS];
105
106 static struct Map the_map;
107
108 /**
109 * Clear cells the_map.cells[x][y..y+len_y-1].
110 */
clear_cells(int x,int y,int len_y)111 static void clear_cells(int x, int y, int len_y) {
112 int clear_cells_i, j;
113 memset(mapdata_cell(x, y), 0, sizeof(struct MapCell)*len_y);
114
115 for (clear_cells_i = 0; clear_cells_i < (len_y); clear_cells_i++) {
116 struct MapCell *cell = mapdata_cell(x, y+clear_cells_i);
117 for (j=0; j < MAXLAYERS; j++) {
118 cell->heads[j].size_x = 1;
119 cell->heads[j].size_y = 1;
120 }
121 }
122 }
123
124 /**
125 * Get the stored map cell at the given map coordinate.
126 */
mapdata_cell(const int x,const int y)127 inline struct MapCell *mapdata_cell(const int x, const int y) {
128 return &the_map._cells[x][y];
129 }
130
131 /**
132 * Determine whether the map data contains the given cell.
133 */
mapdata_contains(int x,int y)134 bool mapdata_contains(int x, int y) {
135 if (x < 0 || y < 0 || the_map.width <= x || the_map.height <= y) {
136 return false;
137 }
138
139 return true;
140 }
141
mapdata_can_smooth(int x,int y,int layer)142 bool mapdata_can_smooth(int x, int y, int layer) {
143 return (mapdata_cell(x, y)->heads[layer].face == 0 && layer > 0) ||
144 mapdata_cell(x, y)->smooth[layer];
145 }
146
147 /**
148 * Determine the size of the internal fog-of-war map.
149 */
mapdata_size(int * x,int * y)150 void mapdata_size(int *x, int *y) {
151 if (x != NULL) {
152 *x = the_map.width;
153 }
154
155 if (y != NULL) {
156 *y = the_map.height;
157 }
158 }
159
160 /**
161 * Update darkness information. This function is called whenever a map1a
162 * command from the server was received.
163 *
164 * x and y are absolute coordinates into the_map.cells[].
165 *
166 * darkness is the new darkness value.
167 */
set_darkness(int x,int y,int darkness)168 static void set_darkness(int x, int y, int darkness)
169 {
170 mapdata_cell(x, y)->have_darkness = 1;
171 if (mapdata_cell(x, y)->darkness == darkness) {
172 return;
173 }
174
175 mapdata_cell(x, y)->darkness = darkness;
176 mapdata_cell(x, y)->need_update = 1;
177
178 /* pretty ugly - since the light code with pngximage uses neighboring
179 * spaces to adjust the darkness, we now need to let the neighbors know
180 * they should update their darkness now.
181 */
182 if (use_config[CONFIG_DISPLAYMODE] == CFG_DM_SDL
183 && (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL
184 || use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST)) {
185 if (x > 1) {
186 mapdata_cell(x-1, y)->need_update = 1;
187 }
188 if (y > 1) {
189 mapdata_cell(x, y-1)->need_update = 1;
190 }
191 if (x < width-1) {
192 mapdata_cell(x+1, y)->need_update = 1;
193 }
194 if (y < height-1) {
195 mapdata_cell(x, y+1)->need_update = 1;
196 }
197 }
198 }
199
mark_resmooth(int x,int y,int layer)200 static void mark_resmooth(int x, int y, int layer)
201 {
202 int sdx,sdy;
203 if (mapdata_cell(x, y)->smooth[layer]>1) {
204 for (sdx=-1; sdx<2; sdx++)
205 for (sdy=-1; sdy<2; sdy++)
206 if ( (sdx || sdy) /* ignore (0,0) */
207 && ( (x+sdx >0) && (x+sdx < the_map.width) && /* only inside map */
208 (y+sdy >0) && (y+sdy < the_map.height) ) ) {
209 mapdata_cell(x+sdx, y+sdy)->need_resmooth=1;
210 }
211 }
212 }
213 /**
214 * Clear a face from the_map.cells[].
215 *
216 * x, y, and layer are the coordinates of the head and layer relative to
217 * pl_pos.
218 *
219 * w and h give the width and height of the face to clear.
220 */
expand_clear_face(int x,int y,int w,int h,int layer)221 static void expand_clear_face(int x, int y, int w, int h, int layer)
222 {
223 int dx, dy;
224 struct MapCell *cell;
225
226 assert(0 <= x && x < the_map.width);
227 assert(0 <= y && y < the_map.height);
228 assert(1 <= w && w <= MAX_FACE_SIZE);
229 assert(1 <= h && h <= MAX_FACE_SIZE);
230
231 assert(0 <= x-w+1 && x-w+1 < the_map.width);
232 assert(0 <= y-h+1 && y-h+1 < the_map.height);
233
234 cell = mapdata_cell(x, y);
235
236 for (dx = 0; dx < w; dx++) {
237 for (dy = !dx; dy < h; dy++) {
238 struct MapCellTailLayer *tail = &mapdata_cell(x-dx, y-dy)->tails[layer];
239 assert(0 <= x-dx && x-dx < the_map.width);
240 assert(0 <= y-dy && y-dy < the_map.height);
241 assert(0 <= layer && layer < MAXLAYERS);
242
243 /* Do not clear faces that already have been overwritten by another
244 * face.
245 */
246 if (tail->face == cell->heads[layer].face
247 && tail->size_x == dx
248 && tail->size_y == dy) {
249 tail->face = 0;
250 tail->size_x = 0;
251 tail->size_y = 0;
252 mapdata_cell(x-dx, y-dy)->need_update = 1;
253 }
254 mark_resmooth(x-dx,y-dy,layer);
255 }
256 }
257
258 cell->heads[layer].face = 0;
259 cell->heads[layer].animation = 0;
260 cell->heads[layer].animation_speed = 0;
261 cell->heads[layer].animation_left = 0;
262 cell->heads[layer].animation_phase = 0;
263 cell->heads[layer].size_x = 1;
264 cell->heads[layer].size_y = 1;
265 cell->need_update = 1;
266 cell->need_resmooth = 1;
267 mark_resmooth(x,y,layer);
268 }
269
270 /**
271 * Clear a face from the_map.cells[].
272 *
273 * x, y, and layer are the coordinates of the head and layer relative to
274 * pl_pos.
275 */
expand_clear_face_from_layer(int x,int y,int layer)276 static void expand_clear_face_from_layer(int x, int y, int layer)
277 {
278 const struct MapCellLayer *cell;
279
280 assert(0 <= x && x < the_map.width);
281 assert(0 <= y && y < the_map.height);
282 assert(0 <= layer && layer < MAXLAYERS);
283
284 cell = &mapdata_cell(x, y)->heads[layer];
285 if (cell->size_x && cell->size_y) {
286 expand_clear_face(x, y, cell->size_x, cell->size_y, layer);
287 }
288 }
289
290 /**
291 * Update a face into the_map.cells[].
292 *
293 * x, y, and layer are the coordinates and layer of the head relative to
294 * pl_pos.
295 *
296 * face is the new face to set.
297 * if clear is set, clear this face. If not set, don't clear. the reason
298 * clear may not be set is because this is an animation update - animations
299 * must all be the same size, so when we set the data for the space,
300 * we will just overwrite the old data. Problem with clearing is that
301 * clobbers the animation data.
302 */
expand_set_face(int x,int y,int layer,gint16 face,int clear)303 static void expand_set_face(int x, int y, int layer, gint16 face, int clear)
304 {
305 struct MapCell *cell;
306 int dx, dy;
307 guint8 w, h;
308
309 assert(0 <= x && x < the_map.width);
310 assert(0 <= y && y < the_map.height);
311 assert(0 <= layer && layer < MAXLAYERS);
312
313 cell = mapdata_cell(x, y);
314
315 if (clear) {
316 expand_clear_face_from_layer(x, y, layer);
317 }
318
319 mapdata_get_image_size(face, &w, &h);
320 assert(1 <= w && w <= MAX_FACE_SIZE);
321 assert(1 <= h && h <= MAX_FACE_SIZE);
322 cell->heads[layer].face = face;
323 cell->heads[layer].size_x = w;
324 cell->heads[layer].size_y = h;
325 cell->need_update=1;
326 mark_resmooth(x,y,layer);
327
328 for (dx = 0; dx < w; dx++) {
329 for (dy = !dx; dy < h; dy++) {
330 struct MapCellTailLayer *tail = &mapdata_cell(x-dx, y-dy)->tails[layer];
331 assert(0 <= x-dx && x-dx < the_map.width);
332 assert(0 <= y-dy && y-dy < the_map.height);
333 assert(0 <= layer && layer < MAXLAYERS);
334
335 tail->face = face;
336 tail->size_x = dx;
337 tail->size_y = dy;
338 mapdata_cell(x-dx, y-dy)->need_update = 1;
339 mark_resmooth(x-dx,y-dy,layer);
340 }
341 }
342 }
343
344 /**
345 * Clear a face from bigfaces[].
346 *
347 * x, y, and layer are the coordinates and layer of the head relative to
348 * pl_pos.
349 *
350 * w and h give the width and height of the face to clear.
351 *
352 * If set_need_update is set, all affected tiles are marked as "need_update".
353 */
expand_clear_bigface(int x,int y,int w,int h,int layer,int set_need_update)354 static void expand_clear_bigface(int x, int y, int w, int h, int layer, int set_need_update)
355 {
356 int dx, dy;
357 struct MapCellLayer *head;
358
359 assert(0 <= x && x < MAX_VIEW);
360 assert(0 <= y && y < MAX_VIEW);
361 assert(1 <= w && w <= MAX_FACE_SIZE);
362 assert(1 <= h && h <= MAX_FACE_SIZE);
363
364 head = &bigfaces[x][y][layer].head;
365
366 for (dx = 0; dx < w && dx <= x; dx++) {
367 for (dy = !dx; dy < h && dy <= y; dy++) {
368 struct MapCellTailLayer *tail = &bigfaces[x-dx][y-dy][layer].tail;
369 assert(0 <= x-dx && x-dx < MAX_VIEW);
370 assert(0 <= y-dy && y-dy < MAX_VIEW);
371 assert(0 <= layer && layer < MAXLAYERS);
372
373 /* Do not clear faces that already have been overwritten by another
374 * face.
375 */
376 if (tail->face == head->face
377 && tail->size_x == dx
378 && tail->size_y == dy) {
379 tail->face = 0;
380 tail->size_x = 0;
381 tail->size_y = 0;
382
383 if (0 <= x-dx && x-dx < width
384 && 0 <= y-dy && y-dy < height) {
385 assert(0 <= pl_pos.x+x-dx && pl_pos.x+x-dx < the_map.width);
386 assert(0 <= pl_pos.y+y-dy && pl_pos.y+y-dy < the_map.height);
387 if (set_need_update) {
388 mapdata_cell(pl_pos.x+x-dx, pl_pos.y+y-dy)->need_update = 1;
389 }
390 }
391 }
392 }
393 }
394
395 head->face = 0;
396 head->size_x = 1;
397 head->size_y = 1;
398 }
399
400 /**
401 * Clear a face from bigfaces[].
402 *
403 * x, y, and layer are the coordinates and layer of the head relative to
404 * pl_pos.
405 *
406 * If set_need_update is set, all affected tiles are marked as "need_update".
407 */
expand_clear_bigface_from_layer(int x,int y,int layer,int set_need_update)408 static void expand_clear_bigface_from_layer(int x, int y, int layer, int set_need_update)
409 {
410 struct BigCell *headcell;
411 const struct MapCellLayer *head;
412
413 assert(0 <= x && x < MAX_VIEW);
414 assert(0 <= y && y < MAX_VIEW);
415 assert(0 <= layer && layer < MAXLAYERS);
416
417 headcell = &bigfaces[x][y][layer];
418 head = &headcell->head;
419 if (head->face != 0) {
420 assert(headcell->prev != NULL || headcell == bigfaces_head);
421
422 /* remove from bigfaces_head list */
423 if (headcell->prev != NULL) {
424 headcell->prev->next = headcell->next;
425 }
426 if (headcell->next != NULL) {
427 headcell->next->prev = headcell->prev;
428 }
429 if (bigfaces_head == headcell) {
430 assert(headcell->prev == NULL);
431 bigfaces_head = headcell->next;
432 } else {
433 assert(headcell->prev != NULL);
434 }
435 headcell->prev = NULL;
436 headcell->next = NULL;
437
438 expand_clear_bigface(x, y, head->size_x, head->size_y, layer, set_need_update);
439 } else {
440 assert(headcell->prev == NULL && headcell != bigfaces_head);
441 assert(head->size_x == 1);
442 assert(head->size_y == 1);
443 }
444 }
445
446 /**
447 * Update a face into bigfaces[].
448 *
449 * x, y, and layer are the coordinates and layer of the head relative to
450 * pl_pos.
451 *
452 * face is the new face to set.
453 */
expand_set_bigface(int x,int y,int layer,gint16 face,int clear)454 static void expand_set_bigface(int x, int y, int layer, gint16 face, int clear)
455 {
456 struct BigCell *headcell;
457 struct MapCellLayer *head;
458 int dx, dy;
459 guint8 w, h;
460
461 assert(0 <= x && x < MAX_VIEW);
462 assert(0 <= y && y < MAX_VIEW);
463 assert(0 <= layer && layer < MAXLAYERS);
464
465 headcell = &bigfaces[x][y][layer];
466 head = &headcell->head;
467 if (clear) {
468 expand_clear_bigface_from_layer(x, y, layer, 1);
469 }
470
471 /* add to bigfaces_head list */
472 if (face != 0) {
473 assert(headcell->prev == NULL);
474 assert(headcell->next == NULL);
475 assert(headcell != bigfaces_head);
476 if (bigfaces_head != NULL) {
477 assert(bigfaces_head->prev == NULL);
478 bigfaces_head->prev = headcell;
479 }
480 headcell->next = bigfaces_head;
481 bigfaces_head = headcell;
482 }
483
484 mapdata_get_image_size(face, &w, &h);
485 assert(1 <= w && w <= MAX_FACE_SIZE);
486 assert(1 <= h && h <= MAX_FACE_SIZE);
487 head->face = face;
488 head->size_x = w;
489 head->size_y = h;
490
491 for (dx = 0; dx < w && dx <= x; dx++) {
492 for (dy = !dx; dy < h && dy <= y; dy++) {
493 struct MapCellTailLayer *tail = &bigfaces[x-dx][y-dy][layer].tail;
494 assert(0 <= x-dx && x-dx < MAX_VIEW);
495 assert(0 <= y-dy && y-dy < MAX_VIEW);
496 assert(0 <= layer && layer < MAXLAYERS);
497
498 tail->face = face;
499 tail->size_x = dx;
500 tail->size_y = dy;
501
502 if (0 <= x-dx && x-dx < width
503 && 0 <= y-dy && y-dy < height) {
504 assert(0 <= pl_pos.x+x-dx && pl_pos.x+x-dx < the_map.width);
505 assert(0 <= pl_pos.y+y-dy && pl_pos.y+y-dy < the_map.height);
506 mapdata_cell(pl_pos.x+x-dx, pl_pos.y+y-dy)->need_update = 1;
507 }
508 }
509 }
510 }
511
512 /**
513 * Mark a face as "need_update".
514 *
515 * x and y are the coordinates of the head relative to pl_pos.
516 *
517 * w and h is the size of the face.
518 */
expand_need_update(int x,int y,int w,int h)519 static void expand_need_update(int x, int y, int w, int h)
520 {
521 int dx, dy;
522
523 assert(0 <= x && x < the_map.width);
524 assert(0 <= y && y < the_map.height);
525 assert(1 <= w && w <= MAX_FACE_SIZE);
526 assert(1 <= h && h <= MAX_FACE_SIZE);
527
528 assert(0 <= x-w+1 && x-w+1 < the_map.width);
529 assert(0 <= y-h+1 && y-h+1 < the_map.height);
530
531 for (dx = 0; dx < w; dx++) {
532 for (dy = 0; dy < h; dy++) {
533 struct MapCell *cell = mapdata_cell(x-dx, y-dy);
534 assert(0 <= x-dx && x-dx < the_map.width);
535 assert(0 <= y-dy && y-dy < the_map.height);
536 cell->need_update = 1;
537 }
538 }
539 }
540
541 /**
542 * Mark a face as "need_update".
543 *
544 * x, y, and layer are the coordinates and layer of the head relative to
545 * pl_pos.
546 */
expand_need_update_from_layer(int x,int y,int layer)547 static void expand_need_update_from_layer(int x, int y, int layer)
548 {
549 struct MapCellLayer *head;
550
551 assert(0 <= x && x < the_map.width);
552 assert(0 <= y && y < the_map.height);
553 assert(0 <= layer && layer < MAXLAYERS);
554
555 head = &mapdata_cell(x, y)->heads[layer];
556 if (head->face != 0) {
557 expand_need_update(x, y, head->size_x, head->size_y);
558 } else {
559 assert(head->size_x == 1);
560 assert(head->size_y == 1);
561 }
562 }
563
564 /**
565 * Allocate and set up pointers for a map, with cells represented as a C-style
566 * multi-dimensional array.
567 */
mapdata_alloc(struct Map * const map,const int width,const int height)568 static void mapdata_alloc(struct Map* const map, const int width, const int height) {
569 map->_cells = (struct MapCell **)g_new(struct MapCell, width * (height + 1));
570 g_assert(map->_cells != NULL); // g_new() always succeeds
571 map->width = width;
572 map->height = height;
573
574 /* Skip past the first row of pointers to rows and assign the
575 * start of the actual map data
576 */
577 map->_cells[0] = (struct MapCell *)((char *)map->_cells+(sizeof(struct MapCell *)*map->width));
578
579 /* Finish assigning the beginning of each row relative to the
580 * first row assigned above
581 */
582 for (int i = 0; i < map->width; i++) {
583 map->_cells[i] = map->_cells[0]+i*map->height;
584 }
585 }
586
mapdata_init(void)587 static void mapdata_init(void)
588 {
589 int x, y;
590 int i;
591
592 mapdata_alloc(&the_map, FOG_MAP_SIZE, FOG_MAP_SIZE);
593
594 width = 0;
595 height = 0;
596 pl_pos.x = the_map.width/2-width/2;
597 pl_pos.y = the_map.height/2-height/2;
598
599 for (x = 0; x < the_map.width; x++) {
600 clear_cells(x, 0, the_map.height);
601 }
602
603 for (y = 0; y < MAX_VIEW; y++) {
604 for (x = 0; x < MAX_VIEW; x++) {
605 for (i = 0; i < MAXLAYERS; i++) {
606 bigfaces[x][y][i].next = NULL;
607 bigfaces[x][y][i].prev = NULL;
608 bigfaces[x][y][i].head.face = 0;
609 bigfaces[x][y][i].head.size_x = 1;
610 bigfaces[x][y][i].head.size_y = 1;
611 bigfaces[x][y][i].tail.face = 0;
612 bigfaces[x][y][i].tail.size_x = 0;
613 bigfaces[x][y][i].tail.size_y = 0;
614 bigfaces[x][y][i].x = x;
615 bigfaces[x][y][i].y = y;
616 bigfaces[x][y][i].layer = i;
617 }
618 }
619 }
620 bigfaces_head = NULL;
621
622 global_offset_x = 0;
623 global_offset_y = 0;
624 want_offset_x = 0;
625 want_offset_y = 0;
626 }
627
mapdata_free(void)628 void mapdata_free(void) {
629 if (the_map._cells != NULL) {
630 g_free(the_map._cells);
631 the_map._cells = NULL;
632 }
633 }
634
mapdata_set_size(int viewx,int viewy)635 void mapdata_set_size(int viewx, int viewy)
636 {
637 mapdata_free();
638 mapdata_init();
639
640 width = viewx;
641 height = viewy;
642 pl_pos.x = the_map.width/2-width/2;
643 pl_pos.y = the_map.height/2-height/2;
644 }
645
mapdata_is_inside(int x,int y)646 int mapdata_is_inside(int x, int y)
647 {
648 return(x >= 0 && x < width && y >= 0 && y < height);
649 }
650
651 /* mapdate_clear_space() is used by Map2Cmd()
652 * Basically, server has told us there is nothing on
653 * this space. So clear it.
654 */
mapdata_clear_space(int x,int y)655 void mapdata_clear_space(int x, int y)
656 {
657 int px, py;
658 int i;
659
660 assert(0 <= x && x < MAX_VIEW);
661 assert(0 <= y && y < MAX_VIEW);
662
663 px = pl_pos.x+x;
664 py = pl_pos.y+y;
665 assert(0 <= px && px < the_map.width);
666 assert(0 <= py && py < the_map.height);
667
668 if (x < width && y < height) {
669 /* tile is visible */
670
671 /* visible tile is now blank ==> do not clear but mark as cleared */
672 if (!mapdata_cell(px, py)->cleared) {
673 mapdata_cell(px, py)->cleared = 1;
674 mapdata_cell(px, py)->need_update = 1;
675
676 for (i=0; i < MAXLAYERS; i++)
677 if (mapdata_cell(px, py)->heads[i].face) {
678 expand_need_update_from_layer(px, py, i);
679 }
680 }
681 } else {
682 /* tile is invisible (outside view area, i.e. big face update) */
683
684 for (i = 0; i < MAXLAYERS; i++) {
685 expand_set_bigface(x, y, i, 0, TRUE);
686 }
687 }
688 }
689
690
691 /* With map2, we basically process a piece of data at a time. Thus,
692 * for each piece, we don't know what the final state of the space
693 * will be. So once Map2Cmd() has processed all the information for
694 * a space, it calls mapdata_set_check_space() which can see if
695 * the space is cleared or other inconsistencies.
696 */
mapdata_set_check_space(int x,int y)697 void mapdata_set_check_space(int x, int y)
698 {
699 int px, py;
700 int is_blank;
701 int i;
702 struct MapCell *cell;
703
704 assert(0 <= x && x < MAX_VIEW);
705 assert(0 <= y && y < MAX_VIEW);
706
707 px = pl_pos.x+x;
708 py = pl_pos.y+y;
709
710 assert(0 <= px && px < the_map.width);
711 assert(0 <= py && py < the_map.height);
712
713
714 is_blank=1;
715 cell = mapdata_cell(px, py);
716 for (i=0; i < MAXLAYERS; i++) {
717 if (cell->heads[i].face>0 || cell->tails[i].face>0) {
718 is_blank=0;
719 break;
720 }
721 }
722
723 if (cell->have_darkness) {
724 is_blank=0;
725 }
726
727 /* We only care if this space needs to be blanked out */
728 if (!is_blank) {
729 return;
730 }
731
732 if (x < width && y < height) {
733 /* tile is visible */
734
735 /* visible tile is now blank ==> do not clear but mark as cleared */
736 if (!mapdata_cell(px, py)->cleared) {
737 mapdata_cell(px, py)->cleared = 1;
738 mapdata_cell(px, py)->need_update = 1;
739
740 for (i=0; i < MAXLAYERS; i++) {
741 expand_need_update_from_layer(px, py, i);
742 }
743 }
744 }
745 }
746
747
748
749 /* This just sets the darkness for a space.
750 * Used by Map2Cmd()
751 */
mapdata_set_darkness(int x,int y,int darkness)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 */
mapdata_set_smooth(int x,int y,guint8 smooth,int 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 /* If old cell data is set and is to be cleared, clear it.
804 * This used to be in mapdata_set_face_layer(), however it needs to be
805 * called here, earlier in the Map2Cmd() because otherwise darkness
806 * doesn't work went sent before the layer data when that square was
807 * going to be cleared. This is used by the Map2Cmd()
808 */
mapdata_clear_old(int x,int y)809 void mapdata_clear_old(int x, int y)
810 {
811 int px, py;
812 int i;
813
814 assert(0 <= x && x < MAX_VIEW);
815 assert(0 <= y && y < MAX_VIEW);
816
817 px = pl_pos.x+x;
818 py = pl_pos.y+y;
819 assert(0 <= px && px < the_map.width);
820 assert(0 <= py && py < the_map.height);
821
822 if (x < width && y < height)
823 if (mapdata_cell(px, py)->cleared) {
824 for (i=0; i < MAXLAYERS; i++) {
825 expand_clear_face_from_layer(px, py, i);
826 }
827
828 mapdata_cell(px, py)->darkness = 0;
829 mapdata_cell(px, py)->have_darkness = 0;
830 }
831 }
832
833 /* This is vaguely related to the mapdata_set_face() above, but rather
834 * than take all the faces, takes 1 face and the layer this face is
835 * on. This is used by the Map2Cmd()
836 */
mapdata_set_face_layer(int x,int y,gint16 face,int layer)837 void mapdata_set_face_layer(int x, int y, gint16 face, int layer)
838 {
839 int px, py;
840
841 assert(0 <= x && x < MAX_VIEW);
842 assert(0 <= y && y < MAX_VIEW);
843
844 px = pl_pos.x+x;
845 py = pl_pos.y+y;
846 assert(0 <= px && px < the_map.width);
847 assert(0 <= py && py < the_map.height);
848
849 if (x < width && y < height) {
850 mapdata_cell(px, py)->need_update = 1;
851 if (face >0) {
852 expand_set_face(px, py, layer, face, TRUE);
853 } else {
854 expand_clear_face_from_layer(px, py, layer);
855 }
856
857 mapdata_cell(px, py)->cleared = 0;
858 } else {
859 expand_set_bigface(x, y, layer, face, TRUE);
860 }
861 }
862
863
864 /* This is vaguely related to the mapdata_set_face() above, but rather
865 * than take all the faces, takes 1 face and the layer this face is
866 * on. This is used by the Map2Cmd()
867 */
mapdata_set_anim_layer(int x,int y,guint16 anim,guint8 anim_speed,int layer)868 void mapdata_set_anim_layer(int x, int y, guint16 anim, guint8 anim_speed, int layer)
869 {
870 int px, py;
871 int i, face, animation, phase, speed_left;
872
873 assert(0 <= x && x < MAX_VIEW);
874 assert(0 <= y && y < MAX_VIEW);
875
876 px = pl_pos.x+x;
877 py = pl_pos.y+y;
878 assert(0 <= px && px < the_map.width);
879 assert(0 <= py && py < the_map.height);
880
881 animation = anim & ANIM_MASK;
882 face = 0;
883
884 /* Random animation is pretty easy */
885 if ((anim & ANIM_FLAGS_MASK) == ANIM_RANDOM) {
886 const guint8 num_animations = animations[animation].num_animations;
887 if (num_animations == 0) {
888 LOG(LOG_WARNING, "mapdata_set_anim_layer",
889 "animating object with zero animations");
890 return;
891 }
892 phase = g_random_int() % num_animations;
893 face = animations[animation].faces[phase];
894 speed_left = anim_speed % g_random_int();
895 } else if ((anim & ANIM_FLAGS_MASK) == ANIM_SYNC) {
896 animations[animation].speed = anim_speed;
897 phase = animations[animation].phase;
898 speed_left = animations[animation].speed_left;
899 face = animations[animation].faces[phase];
900 }
901
902 if (x < width && y < height) {
903 mapdata_cell(px, py)->need_update = 1;
904 if (mapdata_cell(px, py)->cleared) {
905 for (i=0; i < MAXLAYERS; i++) {
906 expand_clear_face_from_layer(px, py, i);
907 }
908
909 mapdata_cell(px, py)->darkness = 0;
910 mapdata_cell(px, py)->have_darkness = 0;
911 }
912 if (face >0) {
913 expand_set_face(px, py, layer, face, TRUE);
914 mapdata_cell(px, py)->heads[layer].animation = animation;
915 mapdata_cell(px, py)->heads[layer].animation_phase = phase;
916 mapdata_cell(px, py)->heads[layer].animation_speed = anim_speed;
917 mapdata_cell(px, py)->heads[layer].animation_left = speed_left;
918 } else {
919 expand_clear_face_from_layer(px, py, layer);
920 }
921
922 mapdata_cell(px, py)->cleared = 0;
923
924 } else {
925 expand_set_bigface(x, y, layer, face, TRUE);
926 }
927 }
928
929
mapdata_scroll(int dx,int dy)930 void mapdata_scroll(int dx, int dy)
931 {
932 script_pos.x += dx;
933 script_pos.y += dy;
934 int x, y;
935
936 recenter_virtual_map_view(dx, dy);
937
938 if (want_config[CONFIG_MAPSCROLL] && display_mapscroll(dx, dy)) {
939 struct BigCell *cell;
940
941 /* Mark all tiles as "need_update" that are overlapped by a big face
942 * from outside the view area.
943 */
944 for (cell = bigfaces_head; cell != NULL; cell = cell->next) {
945 for (x = 0; x < cell->head.size_x; x++) {
946 for (y = !x; y < cell->head.size_y; y++) {
947 if (0 <= cell->x-x && cell->x-x < width
948 && 0 <= cell->y-y && cell->y-y < height) {
949 mapdata_cell(pl_pos.x+cell->x-x, pl_pos.y+cell->y-y)->need_update = 1;
950 }
951 }
952 }
953 }
954 } else {
955 /* Emulate map scrolling by redrawing all tiles. */
956 for (x = 0; x < width; x++) {
957 for (y = 0; y < height; y++) {
958 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->need_update = 1;
959 }
960 }
961 }
962
963 pl_pos.x += dx;
964 pl_pos.y += dy;
965
966 /* clear all newly visible tiles */
967 if (dx > 0) {
968 for (y = 0; y < height; y++) {
969 for (x = width-dx; x < width; x++) {
970 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->cleared = 1;
971 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->need_update = 1;
972 }
973 }
974 } else {
975 for (y = 0; y < height; y++) {
976 for (x = 0; x < -dx; x++) {
977 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->cleared = 1;
978 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->need_update = 1;
979 }
980 }
981 }
982
983 if (dy > 0) {
984 for (x = 0; x < width; x++) {
985 for (y = height-dy; y < height; y++) {
986 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->cleared = 1;
987 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->need_update = 1;
988 }
989 }
990 } else {
991 for (x = 0; x < width; x++) {
992 for (y = 0; y < -dy; y++) {
993 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->cleared = 1;
994 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->need_update = 1;
995 }
996 }
997 }
998
999 /* Remove all big faces outside the view area. */
1000 while (bigfaces_head != NULL) {
1001 expand_clear_bigface_from_layer(bigfaces_head->x, bigfaces_head->y, bigfaces_head->layer, 0);
1002 }
1003 }
1004
mapdata_newmap(void)1005 void mapdata_newmap(void)
1006 {
1007 script_pos.x = 0;
1008 script_pos.y = 0;
1009 int x, y;
1010
1011 global_offset_x = 0;
1012 global_offset_y = 0;
1013 want_offset_x = 0;
1014 want_offset_y = 0;
1015
1016 // Clear past predictions.
1017 memset(csocket.dir, -1, sizeof(csocket.dir));
1018
1019 /* Clear the_map.cells[]. */
1020 for (x = 0; x < the_map.width; x++) {
1021 clear_cells(x, 0, the_map.height);
1022 for (y = 0; y < the_map.height; y++) {
1023 mapdata_cell(x, y)->need_update = 1;
1024 }
1025 }
1026
1027 /* Clear bigfaces[]. */
1028 while (bigfaces_head != NULL) {
1029 expand_clear_bigface_from_layer(bigfaces_head->x, bigfaces_head->y, bigfaces_head->layer, 0);
1030 }
1031 }
1032
1033 /**
1034 * Check if the given map tile is a valid slot in the map array.
1035 */
mapdata_has_tile(int x,int y,int layer)1036 static bool mapdata_has_tile(int x, int y, int layer) {
1037 if (0 <= x && x < width && 0 <= y && y < height) {
1038 if (0 <= layer && layer < MAXLAYERS) {
1039 return true;
1040 }
1041 }
1042
1043 return false;
1044 }
1045
1046 /**
1047 * Return the face number of a single-square pixmap at the given map tile.
1048 * @param x X-coordinate of tile on-screen
1049 * @param y Y-coordinate of tile on-screen
1050 * @param layer
1051 * @return Pixmap face number, or zero if the tile does not exist
1052 */
mapdata_face(int x,int y,int layer)1053 gint16 mapdata_face(int x, int y, int layer) {
1054 if (!mapdata_has_tile(x, y, layer)) {
1055 return 0;
1056 }
1057
1058 return mapdata_cell(pl_pos.x+x, pl_pos.y+y)->heads[layer].face;
1059 }
1060
mapdata_face_info(int mx,int my,int layer,int * dx,int * dy)1061 gint16 mapdata_face_info(int mx, int my, int layer, int *dx, int *dy) {
1062 struct MapCellLayer *head = &mapdata_cell(mx, my)->heads[layer];
1063 struct MapCellTailLayer *tail = &mapdata_cell(mx, my)->tails[layer];
1064 if (head->face != 0) {
1065 const int width = head->size_x, height = head->size_y;
1066 *dx = 1 - width, *dy = 1 - height;
1067 return head->face;
1068 } else if (tail->face != 0) {
1069 struct MapCellLayer *head_ptr = &mapdata_cell(mx + tail->size_x, my + tail->size_y)->heads[layer];
1070 const int width = head_ptr->size_x, height = head_ptr->size_y;
1071 *dx = tail->size_x - width + 1, *dy = tail->size_y - height + 1;
1072 return tail->face;
1073 } else {
1074 return 0;
1075 }
1076 }
1077
1078 /**
1079 * Return the face number of a multi-square pixmap at the given map tile.
1080 * @param x X-coordinate of tile on-screen
1081 * @param y Y-coordinate of tile on-screen
1082 * @param layer
1083 * @param ww
1084 * @param hh
1085 * @return Pixmap face number, or zero if the tile does not exist
1086 */
mapdata_bigface(int x,int y,int layer,int * ww,int * hh)1087 gint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh) {
1088 gint16 result;
1089
1090 if (!mapdata_has_tile(x, y, layer)) {
1091 return 0;
1092 }
1093
1094 result = mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].face;
1095 if (result != 0) {
1096 int clear_bigface;
1097 int dx = mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].size_x;
1098 int dy = mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].size_y;
1099 int w = mapdata_cell(pl_pos.x+x+dx, pl_pos.y+y+dy)->heads[layer].size_x;
1100 int h = mapdata_cell(pl_pos.x+x+dx, pl_pos.y+y+dy)->heads[layer].size_y;
1101 assert(1 <= w && w <= MAX_FACE_SIZE);
1102 assert(1 <= h && h <= MAX_FACE_SIZE);
1103 assert(0 <= dx && dx < w);
1104 assert(0 <= dy && dy < h);
1105
1106 /* Now check if we are about to display an obsolete big face: such a
1107 * face has a cleared ("fog of war") head but the current tile is not
1108 * fog of war. Since the server would have sent an appropriate head
1109 * tile if it was already valid, just clear the big face and do not
1110 * return it.
1111 */
1112 if (mapdata_cell(pl_pos.x+x, pl_pos.y+y)->cleared) {
1113 /* Current face is a "fog of war" tile ==> do not clear
1114 * old information.
1115 */
1116 clear_bigface = 0;
1117 } else {
1118 if (x+dx < width && y+dy < height) {
1119 /* Clear face if current tile is valid but the
1120 * head is marked as cleared.
1121 */
1122 clear_bigface = mapdata_cell(pl_pos.x+x+dx, pl_pos.y+y+dy)->cleared;
1123 } else {
1124 /* Clear face if current tile is valid but the
1125 * head is not set.
1126 */
1127 clear_bigface = bigfaces[x+dx][y+dy][layer].head.face == 0;
1128 }
1129 }
1130
1131 if (!clear_bigface) {
1132 *ww = w-1-dx;
1133 *hh = h-1-dy;
1134 return(result);
1135 }
1136
1137 assert(mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].face == result);
1138 expand_clear_face_from_layer(pl_pos.x+x+dx, pl_pos.y+y+dy, layer);
1139 assert(mapdata_cell(pl_pos.x+x, pl_pos.y+y)->tails[layer].face == 0);
1140 }
1141
1142 result = bigfaces[x][y][layer].tail.face;
1143 if (result != 0) {
1144 int dx = bigfaces[x][y][layer].tail.size_x;
1145 int dy = bigfaces[x][y][layer].tail.size_y;
1146 int w = bigfaces[x+dx][y+dy][layer].head.size_x;
1147 int h = bigfaces[x+dx][y+dy][layer].head.size_y;
1148 assert(0 <= dx && dx < w);
1149 assert(0 <= dy && dy < h);
1150 *ww = w-1-dx;
1151 *hh = h-1-dy;
1152 return(result);
1153 }
1154
1155 *ww = 1;
1156 *hh = 1;
1157 return(0);
1158 }
1159
1160 /* This is used by the opengl logic.
1161 * Basically the opengl code draws the the entire image,
1162 * and doesn't care if if portions are off the edge
1163 * (opengl takes care of that). So basically, this
1164 * function returns only if the head for a space is set,
1165 * otherwise, returns 0 - we don't care about the tails
1166 * or other details really.
1167 */
mapdata_bigface_head(int x,int y,int layer,int * ww,int * hh)1168 gint16 mapdata_bigface_head(int x, int y, int layer, int *ww, int *hh) {
1169 gint16 result;
1170
1171 if (!mapdata_has_tile(x, y, layer)) {
1172 return 0;
1173 }
1174
1175 result = bigfaces[x][y][layer].head.face;
1176 if (result != 0) {
1177 int w = bigfaces[x][y][layer].head.size_x;
1178 int h = bigfaces[x][y][layer].head.size_y;
1179 *ww = w;
1180 *hh = h;
1181 return(result);
1182 }
1183
1184 *ww = 1;
1185 *hh = 1;
1186 return(0);
1187 }
1188
1189 /**
1190 * Check if current map position is out of bounds if shifted by (dx, dy). If
1191 * so, shift the virtual map so that the map view is within bounds again.
1192 *
1193 * Assures that [pl_pos.x-MAX_FACE_SIZE..pl_pos.x+MAX_VIEW+1] is within the
1194 * bounds of the virtual map area. This covers the area a map1a command may
1195 * affect plus a one tile border.
1196 */
recenter_virtual_map_view(int diff_x,int diff_y)1197 static void recenter_virtual_map_view(int diff_x, int diff_y)
1198 {
1199 int new_x, new_y;
1200 int shift_x, shift_y;
1201 int src_x, src_y;
1202 int dst_x, dst_y;
1203 int len_x, len_y;
1204 int sx;
1205 int dx;
1206 int i;
1207
1208 /* shift player position in virtual map */
1209 new_x = pl_pos.x+diff_x;
1210 new_y = pl_pos.y+diff_y;
1211
1212 /* determine neccessary amount to shift */
1213
1214 /* if(new_x < 1) is not possible: a big face may reach up to
1215 * (MAX_FACE_SIZE-1) tiles to the left of pl_pos. Therefore maintain a
1216 * border of at least MAX_FACE_SIZE to the left of the virtual map
1217 * edge.
1218 */
1219 if (new_x < MAX_FACE_SIZE) {
1220 shift_x = FOG_BORDER_MIN+MAX_FACE_SIZE-new_x;
1221 /* This yields: new_x+shift_x == FOG_BORDER_MIN+MAX_FACE_SIZE,
1222 * i.e. left border is FOG_BORDER_MIN+MAX_FACE_SIZE after
1223 * shifting.
1224 */
1225 } else if (new_x+MAX_VIEW > the_map.width) {
1226 shift_x = the_map.width-FOG_BORDER_MIN-MAX_VIEW-new_x;
1227 /* This yields: new_x+shift_x ==
1228 * the_map.width-FOG_BODER_MIN-MAX_VIEW, i.e. right border is
1229 * FOGBORDER_MIN after shifting.
1230 */
1231 } else {
1232 shift_x = 0;
1233 }
1234
1235 /* Same as above but for y. */
1236 if (new_y < MAX_FACE_SIZE) {
1237 shift_y = FOG_BORDER_MIN+MAX_FACE_SIZE-new_y;
1238 } else if (new_y+MAX_VIEW > the_map.height) {
1239 shift_y = the_map.height-FOG_BORDER_MIN-MAX_VIEW-new_y;
1240 } else {
1241 shift_y = 0;
1242 }
1243
1244 /* No shift neccessary? ==> nothing to do. */
1245 if (shift_x == 0 && shift_y == 0) {
1246 return;
1247 }
1248
1249 /* If shifting at all: maintain a border size of FOG_BORDER_MIN to all
1250 * directions. For example: if pl_pos=30/MAX_FACE_SIZE, and map_scroll is
1251 * 0/-1: shift pl_pos to FOG_BORDER_MIN+1/FOG_BORDER_MIN+1, not to
1252 * 30/FOG_BORDER_MIN+1.
1253 */
1254 if (shift_x == 0) {
1255 if (new_x < FOG_BORDER_MIN+MAX_FACE_SIZE) {
1256 shift_x = FOG_BORDER_MIN+MAX_FACE_SIZE-new_x;
1257 } else if (new_x+MAX_VIEW+FOG_BORDER_MIN > the_map.width) {
1258 shift_x = the_map.width-FOG_BORDER_MIN-MAX_VIEW-new_x;
1259 }
1260 }
1261 if (shift_y == 0) {
1262 if (new_y < FOG_BORDER_MIN+MAX_FACE_SIZE) {
1263 shift_y = FOG_BORDER_MIN+MAX_FACE_SIZE-new_y;
1264 } else if (new_y+MAX_VIEW+FOG_BORDER_MIN > the_map.height) {
1265 shift_y = the_map.height-FOG_BORDER_MIN-MAX_VIEW-new_y;
1266 }
1267 }
1268
1269 /* Shift for more than virtual map size? ==> clear whole virtual map
1270 * and recenter.
1271 */
1272 if (shift_x <= -the_map.width || shift_x >= the_map.width
1273 || shift_y <= -the_map.height || shift_y >= the_map.height) {
1274 for (dx = 0; dx < the_map.width; dx++) {
1275 clear_cells(dx, 0, the_map.height);
1276 }
1277
1278 pl_pos.x = the_map.width/2-width/2;
1279 pl_pos.y = the_map.height/2-height/2;
1280 return;
1281 }
1282
1283 /* Move player position. */
1284 pl_pos.x += shift_x;
1285 pl_pos.y += shift_y;
1286
1287 /* Actually shift the virtual map by shift_x/shift_y */
1288 if (shift_x < 0) {
1289 src_x = -shift_x;
1290 dst_x = 0;
1291 len_x = the_map.width+shift_x;
1292 } else {
1293 src_x = 0;
1294 dst_x = shift_x;
1295 len_x = the_map.width-shift_x;
1296 }
1297
1298 if (shift_y < 0) {
1299 src_y = -shift_y;
1300 dst_y = 0;
1301 len_y = the_map.height+shift_y;
1302 } else {
1303 src_y = 0;
1304 dst_y = shift_y;
1305 len_y = the_map.height-shift_y;
1306 }
1307
1308 if (shift_x < 0) {
1309 for (sx = src_x, dx = dst_x, i = 0; i < len_x; sx++, dx++, i++) {
1310 /* srcx!=dstx ==> can use memcpy since source and
1311 * destination to not overlap.
1312 */
1313 memcpy(mapdata_cell(dx, dst_y), mapdata_cell(sx, src_y), len_y*sizeof(struct MapCell));
1314 }
1315 } else if (shift_x > 0) {
1316 for (sx = src_x+len_x-1, dx = dst_x+len_x-1, i = 0; i < len_x; sx--, dx--, i++) {
1317 /* srcx!=dstx ==> can use memcpy since source and
1318 * destination to not overlap.
1319 */
1320 memcpy(mapdata_cell(dx, dst_y), mapdata_cell(sx, src_y), len_y*sizeof(struct MapCell));
1321 }
1322 } else {
1323 assert(src_x == dst_x);
1324 for (dx = src_x, i = 0; i < len_x; dx++, i++) {
1325 /* srcx==dstx ==> use memmove since source and
1326 * destination probably do overlap.
1327 */
1328 memmove(mapdata_cell(dx, dst_y), mapdata_cell(dx, src_y), len_y*sizeof(struct MapCell));
1329 }
1330 }
1331
1332 /* Clear newly opened area */
1333 for (dx = 0; dx < dst_x; dx++) {
1334 clear_cells(dx, 0, the_map.height);
1335 }
1336 for (dx = dst_x+len_x; dx < the_map.width; dx++) {
1337 clear_cells(dx, 0, the_map.height);
1338 }
1339 if (shift_y > 0) {
1340 for (dx = 0; dx < len_x; dx++) {
1341 clear_cells(dx+dst_x, 0, shift_y);
1342 }
1343 } else if (shift_y < 0) {
1344 for (dx = 0; dx < len_x; dx++) {
1345 clear_cells(dx+dst_x, the_map.height+shift_y, -shift_y);
1346 }
1347 }
1348 }
1349
1350 /**
1351 * Return the size of a face in tiles. The returned size is at between 1 and
1352 * MAX_FACE_SIZE (inclusive).
1353 */
mapdata_get_image_size(int face,guint8 * w,guint8 * h)1354 static void mapdata_get_image_size(int face, guint8 *w, guint8 *h)
1355 {
1356 get_map_image_size(face, w, h);
1357 if (*w < 1) {
1358 *w = 1;
1359 }
1360 if (*h < 1) {
1361 *h = 1;
1362 }
1363 if (*w > MAX_FACE_SIZE) {
1364 *w = MAX_FACE_SIZE;
1365 }
1366 if (*h > MAX_FACE_SIZE) {
1367 *h = MAX_FACE_SIZE;
1368 }
1369 }
1370
1371 /* This basically goes through all the map spaces and does the necessary
1372 * animation.
1373 */
mapdata_animation(void)1374 void mapdata_animation(void)
1375 {
1376 int x, y, layer, face;
1377 struct MapCellLayer *cell;
1378
1379
1380 /* For synchronized animations, what we do is set the initial values
1381 * in the mapdata to the fields in the animations[] array. In this way,
1382 * the code below the iterates the spaces doesn't need to do anything
1383 * special. But we have to update the animations[] array here to
1384 * keep in sync.
1385 */
1386 for (x=0; x < MAXANIM; x++) {
1387 if (animations[x].speed) {
1388 animations[x].speed_left++;
1389 if (animations[x].speed_left >= animations[x].speed) {
1390 animations[x].speed_left=0;
1391 animations[x].phase++;
1392 if (animations[x].phase >= animations[x].num_animations) {
1393 animations[x].phase=0;
1394 }
1395 }
1396 }
1397 }
1398
1399 for (x=0; x < CURRENT_MAX_VIEW; x++) {
1400 for (y=0; y < CURRENT_MAX_VIEW; y++) {
1401 struct MapCell *map_space = mapdata_cell(pl_pos.x + x, pl_pos.y + y);
1402
1403 /* Short cut some processing here. It makes sense to me
1404 * not to animate stuff out of view
1405 */
1406 if (map_space->cleared) {
1407 continue;
1408 }
1409
1410 for (layer=0; layer<MAXLAYERS; layer++) {
1411 /* Using the cell structure just makes life easier here */
1412 cell = &map_space->heads[layer];
1413
1414 if (cell->animation) {
1415 cell->animation_left++;
1416 if (cell->animation_left >= cell->animation_speed) {
1417 cell->animation_left=0;
1418 cell->animation_phase++;
1419 if (cell->animation_phase >= animations[cell->animation].num_animations) {
1420 cell->animation_phase=0;
1421 }
1422 face = animations[cell->animation].faces[cell->animation_phase];
1423
1424 /* I don't think we send any to the client, but it is possible
1425 * for animations to have blank faces.
1426 */
1427 if (face >0) {
1428 expand_set_face(pl_pos.x + x, pl_pos.y + y, layer, face, FALSE);
1429 } else {
1430 expand_clear_face_from_layer(pl_pos.x + x, pl_pos.y + y , layer);
1431 }
1432 }
1433 }
1434 cell = &bigfaces[x][y][layer].head;
1435 if (cell->animation) {
1436 cell->animation_left++;
1437 if (cell->animation_left >= cell->animation_speed) {
1438 cell->animation_left=0;
1439 cell->animation_phase++;
1440 if (cell->animation_phase >= animations[cell->animation].num_animations) {
1441 cell->animation_phase=0;
1442 }
1443 face = animations[cell->animation].faces[cell->animation_phase];
1444
1445 /* I don't think we send any to the client, but it is possible
1446 * for animations to have blank faces.
1447 */
1448 expand_set_bigface(x, y, layer, face, FALSE);
1449 }
1450 }
1451 }
1452 }
1453 }
1454 }
1455