Crossfire Client, Branch  R11627
mapdata.c
Go to the documentation of this file.
00001 /* $Id: mapdata.c 10973 2008-12-14 08:51:26Z ryo_saeba $ */
00002 /*
00003     Crossfire client, a client program for the crossfire program.
00004 
00005     Copyright (C) 2005 Mark Wedel & Crossfire Development Team
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 
00021     The author can be reached via e-mail to crossfire-devel@real-time.com
00022 */
00023 
00024 #include <assert.h>
00025 #include <stdlib.h>
00026 
00027 #include "client.h"
00028 #include "external.h"
00029 #include "mapdata.h"
00030 
00031 
00035 #define CLEAR_CELLS(x, y, len_y) \
00036 do { \
00037     int clear_cells_i, j; \
00038     memset(&the_map.cells[(x)][(y)], 0, sizeof(the_map.cells[(x)][(y)])*(len_y)); \
00039     for (clear_cells_i = 0; clear_cells_i < (len_y); clear_cells_i++) \
00040     { \
00041         for (j=0; j < MAXLAYERS; j++) { \
00042             the_map.cells[(x)][(y)+clear_cells_i].heads[j].size_x = 1; \
00043             the_map.cells[(x)][(y)+clear_cells_i].heads[j].size_y = 1; \
00044         } \
00045     } \
00046 } while(0)
00047 
00048 
00052 #define FOG_MAP_SIZE 512
00053 
00058 #define FOG_BORDER_MIN 128
00059 
00063 #define MAX_FACE_SIZE 16
00064 
00065 /* Max it can currently be.  Important right now because
00066  * animation has to look at everything that may be viewable,
00067  * and reducing this size basically reduces processing it needs
00068  * to do by 75% (64^2 vs 33^2)
00069  */
00070 #define CURRENT_MAX_VIEW    33
00071 
00085 struct BigCell {
00086     struct BigCell *next;
00087     struct BigCell *prev;
00088 
00089     struct MapCellLayer head;
00090     struct MapCellLayer tail;
00091 
00092     uint16 x, y;
00093     uint8 layer;
00094 };
00095 
00096 
00097 static void recenter_virtual_map_view(int diff_x, int diff_y);
00098 static void mapdata_get_image_size(int face, uint8 *w, uint8 *h);
00099 
00100 
00104 static int width, height;
00105 
00106 
00111 static struct BigCell *bigfaces_head;
00112 
00118 static struct BigCell bigfaces[MAX_VIEW][MAX_VIEW][MAXLAYERS];
00119 
00120 
00121 struct Map the_map;
00122 
00123 
00132 static void set_darkness(int x, int y, int darkness)
00133 {
00134     the_map.cells[x][y].have_darkness = 1;
00135     if (the_map.cells[x][y].darkness == darkness) {
00136         return;
00137     }
00138 
00139     the_map.cells[x][y].darkness = darkness;
00140     the_map.cells[x][y].need_update = 1;
00141 
00142     /* pretty ugly - since the light code with pngximage uses neighboring
00143      * spaces to adjust the darkness, we now need to let the neighbors know
00144      * they should update their darkness now.
00145      */
00146     if (use_config[CONFIG_DISPLAYMODE] == CFG_DM_SDL
00147     && (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL
00148     ||  use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST)) {
00149         if (x > 1) the_map.cells[x-1][y].need_update = 1;
00150         if (y > 1) the_map.cells[x][y-1].need_update = 1;
00151         if (x < width-1) the_map.cells[x+1][y].need_update = 1;
00152         if (y < height-1) the_map.cells[x][y+1].need_update = 1;
00153     }
00154 }
00155 
00156 static void mark_resmooth(int x, int y, int layer){
00157     int sdx,sdy;
00158     if (the_map.cells[x][y].smooth[layer]>1){
00159         for (sdx=-1;sdx<2;sdx++)
00160             for (sdy=-1;sdy<2;sdy++)
00161                 if ( (sdx || sdy) /* ignore (0,0) */
00162                     &&  ( (x+sdx >0) && (x+sdx < FOG_MAP_SIZE) &&  /* only inside map */
00163                           (y+sdy >0) && (y+sdy < FOG_MAP_SIZE) ) )
00164                     the_map.cells[x+sdx][y+sdy].need_resmooth=1;
00165     }
00166 }
00175 static void expand_clear_face(int x, int y, int w, int h, int layer)
00176 {
00177     int dx, dy;
00178     struct MapCell *cell;
00179 
00180     assert(0 <= x && x < FOG_MAP_SIZE);
00181     assert(0 <= y && y < FOG_MAP_SIZE);
00182     assert(1 <= w && w <= MAX_FACE_SIZE);
00183     assert(1 <= h && h <= MAX_FACE_SIZE);
00184 
00185     assert(0 <= x-w+1 && x-w+1 < FOG_MAP_SIZE);
00186     assert(0 <= y-h+1 && y-h+1 < FOG_MAP_SIZE);
00187 
00188     cell = &the_map.cells[x][y];
00189 
00190     for (dx = 0; dx < w; dx++) {
00191         for (dy = !dx; dy < h; dy++) {
00192             struct MapCellLayer *tail = &the_map.cells[x-dx][y-dy].tails[layer];
00193             assert(0 <= x-dx && x-dx < FOG_MAP_SIZE);
00194             assert(0 <= y-dy && y-dy < FOG_MAP_SIZE);
00195             assert(0 <= layer && layer < MAXLAYERS);
00196 
00197             /* Do not clear faces that already have been overwritten by another
00198              * face.
00199              */
00200             if (tail->face == cell->heads[layer].face
00201             && tail->size_x == dx
00202             && tail->size_y == dy) {
00203                 tail->face = 0;
00204                 tail->size_x = 0;
00205                 tail->size_y = 0;
00206                 the_map.cells[x-dx][y-dy].need_update = 1;
00207             }
00208             mark_resmooth(x-dx,y-dy,layer);
00209         }
00210     }
00211 
00212     cell->heads[layer].face = 0;
00213     cell->heads[layer].animation = 0;
00214     cell->heads[layer].animation_speed = 0;
00215     cell->heads[layer].animation_left = 0;
00216     cell->heads[layer].animation_phase = 0;
00217     cell->heads[layer].size_x = 1;
00218     cell->heads[layer].size_y = 1;
00219     cell->need_update = 1;
00220     cell->need_resmooth = 1;
00221     mark_resmooth(x,y,layer);
00222 }
00223 
00230 static void expand_clear_face_from_layer(int x, int y, int layer)
00231 {
00232     const struct MapCellLayer *cell;
00233 
00234     assert(0 <= x && x < FOG_MAP_SIZE);
00235     assert(0 <= y && y < FOG_MAP_SIZE);
00236     assert(0 <= layer && layer < MAXLAYERS);
00237 
00238     cell = &the_map.cells[x][y].heads[layer];
00239     if (cell->size_x && cell->size_y)
00240         expand_clear_face(x, y, cell->size_x, cell->size_y, layer);
00241 }
00242 
00256 static void expand_set_face(int x, int y, int layer, sint16 face, int clear)
00257 {
00258     struct MapCell *cell;
00259     int dx, dy;
00260     uint8 w, h;
00261 
00262     assert(0 <= x && x < FOG_MAP_SIZE);
00263     assert(0 <= y && y < FOG_MAP_SIZE);
00264     assert(0 <= layer && layer < MAXLAYERS);
00265 
00266     cell = &the_map.cells[x][y];
00267 
00268     if (clear)
00269         expand_clear_face_from_layer(x, y, layer);
00270 
00271     mapdata_get_image_size(face, &w, &h);
00272     assert(1 <= w && w <= MAX_FACE_SIZE);
00273     assert(1 <= h && h <= MAX_FACE_SIZE);
00274     cell->heads[layer].face = face;
00275     cell->heads[layer].size_x = w;
00276     cell->heads[layer].size_y = h;
00277     cell->need_update=1;
00278     mark_resmooth(x,y,layer);
00279 
00280     for (dx = 0; dx < w; dx++) {
00281         for (dy = !dx; dy < h; dy++) {
00282             struct MapCellLayer *tail = &the_map.cells[x-dx][y-dy].tails[layer];
00283             assert(0 <= x-dx && x-dx < FOG_MAP_SIZE);
00284             assert(0 <= y-dy && y-dy < FOG_MAP_SIZE);
00285             assert(0 <= layer && layer < MAXLAYERS);
00286 
00287             tail->face = face;
00288             tail->size_x = dx;
00289             tail->size_y = dy;
00290             the_map.cells[x-dx][y-dy].need_update = 1;
00291             mark_resmooth(x-dx,y-dy,layer);
00292         }
00293     }
00294 }
00295 
00306 static void expand_clear_bigface(int x, int y, int w, int h, int layer, int set_need_update)
00307 {
00308     int dx, dy;
00309     struct MapCellLayer *head;
00310 
00311     assert(0 <= x && x < MAX_VIEW);
00312     assert(0 <= y && y < MAX_VIEW);
00313     assert(1 <= w && w <= MAX_FACE_SIZE);
00314     assert(1 <= h && h <= MAX_FACE_SIZE);
00315 
00316     head = &bigfaces[x][y][layer].head;
00317 
00318     for (dx = 0; dx < w && dx <= x; dx++) {
00319         for (dy = !dx; dy < h && dy <= y; dy++) {
00320             struct MapCellLayer *tail = &bigfaces[x-dx][y-dy][layer].tail;
00321             assert(0 <= x-dx && x-dx < MAX_VIEW);
00322             assert(0 <= y-dy && y-dy < MAX_VIEW);
00323             assert(0 <= layer && layer < MAXLAYERS);
00324 
00325             /* Do not clear faces that already have been overwritten by another
00326              * face.
00327              */
00328             if (tail->face == head->face
00329             && tail->size_x == dx
00330             && tail->size_y == dy) {
00331                 tail->face = 0;
00332                 tail->size_x = 0;
00333                 tail->size_y = 0;
00334 
00335                 if (0 <= x-dx && x-dx < width
00336                 && 0 <= y-dy && y-dy < height) {
00337                     assert(0 <= pl_pos.x+x-dx && pl_pos.x+x-dx < FOG_MAP_SIZE);
00338                     assert(0 <= pl_pos.y+y-dy && pl_pos.y+y-dy < FOG_MAP_SIZE);
00339                     if (set_need_update) {
00340                         the_map.cells[pl_pos.x+x-dx][pl_pos.y+y-dy].need_update = 1;
00341                     }
00342                 }
00343             }
00344         }
00345     }
00346 
00347     head->face = 0;
00348     head->size_x = 1;
00349     head->size_y = 1;
00350 }
00351 
00360 static void expand_clear_bigface_from_layer(int x, int y, int layer, int set_need_update)
00361 {
00362     struct BigCell *headcell;
00363     const struct MapCellLayer *head;
00364 
00365     assert(0 <= x && x < MAX_VIEW);
00366     assert(0 <= y && y < MAX_VIEW);
00367     assert(0 <= layer && layer < MAXLAYERS);
00368 
00369     headcell = &bigfaces[x][y][layer];
00370     head = &headcell->head;
00371     if (head->face != 0) {
00372         assert(headcell->prev != NULL || headcell == bigfaces_head);
00373 
00374         /* remove from bigfaces_head list */
00375         if (headcell->prev != NULL) headcell->prev->next = headcell->next;
00376         if (headcell->next != NULL) headcell->next->prev = headcell->prev;
00377         if (bigfaces_head == headcell) {
00378             assert(headcell->prev == NULL);
00379             bigfaces_head = headcell->next;
00380         }
00381         else {
00382             assert(headcell->prev != NULL);
00383         }
00384         headcell->prev = NULL;
00385         headcell->next = NULL;
00386 
00387         expand_clear_bigface(x, y, head->size_x, head->size_y, layer, set_need_update);
00388     }
00389     else {
00390         assert(headcell->prev == NULL && headcell != bigfaces_head);
00391         assert(head->size_x == 1);
00392         assert(head->size_y == 1);
00393     }
00394 }
00395 
00404 static void expand_set_bigface(int x, int y, int layer, sint16 face, int clear)
00405 {
00406     struct BigCell *headcell;
00407     struct MapCellLayer *head;
00408     int dx, dy;
00409     uint8 w, h;
00410 
00411     assert(0 <= x && x < MAX_VIEW);
00412     assert(0 <= y && y < MAX_VIEW);
00413     assert(0 <= layer && layer < MAXLAYERS);
00414 
00415     headcell = &bigfaces[x][y][layer];
00416     head = &headcell->head;
00417     if (clear)
00418         expand_clear_bigface_from_layer(x, y, layer, 1);
00419 
00420     /* add to bigfaces_head list */
00421     if (face != 0) {
00422         assert(headcell->prev == NULL);
00423         assert(headcell->next == NULL);
00424         assert(headcell != bigfaces_head);
00425         if (bigfaces_head != NULL) {
00426             assert(bigfaces_head->prev == NULL);
00427             bigfaces_head->prev = headcell;
00428         }
00429         headcell->next = bigfaces_head;
00430         bigfaces_head = headcell;
00431     }
00432 
00433     mapdata_get_image_size(face, &w, &h);
00434     assert(1 <= w && w <= MAX_FACE_SIZE);
00435     assert(1 <= h && h <= MAX_FACE_SIZE);
00436     head->face = face;
00437     head->size_x = w;
00438     head->size_y = h;
00439 
00440     for (dx = 0; dx < w && dx <= x; dx++) {
00441         for (dy = !dx; dy < h && dy <= y; dy++) {
00442             struct MapCellLayer *tail = &bigfaces[x-dx][y-dy][layer].tail;
00443             assert(0 <= x-dx && x-dx < MAX_VIEW);
00444             assert(0 <= y-dy && y-dy < MAX_VIEW);
00445             assert(0 <= layer && layer < MAXLAYERS);
00446 
00447             tail->face = face;
00448             tail->size_x = dx;
00449             tail->size_y = dy;
00450 
00451             if (0 <= x-dx && x-dx < width
00452             && 0 <= y-dy && y-dy < height) {
00453                 assert(0 <= pl_pos.x+x-dx && pl_pos.x+x-dx < FOG_MAP_SIZE);
00454                 assert(0 <= pl_pos.y+y-dy && pl_pos.y+y-dy < FOG_MAP_SIZE);
00455                 the_map.cells[pl_pos.x+x-dx][pl_pos.y+y-dy].need_update = 1;
00456             }
00457         }
00458     }
00459 }
00460 
00468 static void expand_need_update(int x, int y, int w, int h)
00469 {
00470     int dx, dy;
00471 
00472     assert(0 <= x && x < FOG_MAP_SIZE);
00473     assert(0 <= y && y < FOG_MAP_SIZE);
00474     assert(1 <= w && w <= MAX_FACE_SIZE);
00475     assert(1 <= h && h <= MAX_FACE_SIZE);
00476 
00477     assert(0 <= x-w+1 && x-w+1 < FOG_MAP_SIZE);
00478     assert(0 <= y-h+1 && y-h+1 < FOG_MAP_SIZE);
00479 
00480     for (dx = 0; dx < w; dx++) {
00481         for (dy = 0; dy < h; dy++) {
00482             struct MapCell *cell = &the_map.cells[x-dx][y-dy];
00483             assert(0 <= x-dx && x-dx < FOG_MAP_SIZE);
00484             assert(0 <= y-dy && y-dy < FOG_MAP_SIZE);
00485             cell->need_update = 1;
00486         }
00487     }
00488 }
00489 
00496 static void expand_need_update_from_layer(int x, int y, int layer)
00497 {
00498     struct MapCellLayer *head;
00499 
00500     assert(0 <= x && x < FOG_MAP_SIZE);
00501     assert(0 <= y && y < FOG_MAP_SIZE);
00502     assert(0 <= layer && layer < MAXLAYERS);
00503 
00504     head = &the_map.cells[x][y].heads[layer];
00505     if (head->face != 0) {
00506         expand_need_update(x, y, head->size_x, head->size_y);
00507     }
00508     else {
00509         assert(head->size_x == 1);
00510         assert(head->size_y == 1);
00511     }
00512 }
00513 
00514 void mapdata_init(void)
00515 {
00516     int x, y;
00517     int i;
00518 
00519     if (the_map.cells == NULL) {
00520         the_map.cells = malloc(
00521             sizeof(*the_map.cells)*FOG_MAP_SIZE+
00522             sizeof(**the_map.cells)*FOG_MAP_SIZE*FOG_MAP_SIZE);
00523         if (the_map.cells == NULL) {
00524             LOG(LOG_ERROR, "mapdata_init", "%s\n", "out of memory");
00525             exit(1);
00526         }
00527 
00528         /* Skip past the first row of pointers to rows and assign the
00529          * start of the actual map data
00530          */
00531         the_map.cells[0] = (struct MapCell *)((char *)the_map.cells+(sizeof(struct MapCell *)*FOG_MAP_SIZE));
00532 
00533         /* Finish assigning the beginning of each row relative to the
00534          * first row assigned above
00535          */
00536         for (i = 0; i < FOG_MAP_SIZE; i++) {
00537             the_map.cells[i] = the_map.cells[0]+i*FOG_MAP_SIZE;
00538         }
00539         the_map.x = FOG_MAP_SIZE;
00540         the_map.y = FOG_MAP_SIZE;
00541     }
00542 
00543     width = 0;
00544     height = 0;
00545     pl_pos.x = FOG_MAP_SIZE/2-width/2;
00546     pl_pos.y = FOG_MAP_SIZE/2-height/2;
00547 
00548     for (x = 0; x < FOG_MAP_SIZE; x++) {
00549         CLEAR_CELLS(x, 0, FOG_MAP_SIZE);
00550     }
00551 
00552     for (y = 0; y < MAX_VIEW; y++) {
00553         for (x = 0; x < MAX_VIEW; x++) {
00554             for (i = 0; i < MAXLAYERS; i++) {
00555                 bigfaces[x][y][i].next = NULL;
00556                 bigfaces[x][y][i].prev = NULL;
00557                 bigfaces[x][y][i].head.face = 0;
00558                 bigfaces[x][y][i].head.size_x = 1;
00559                 bigfaces[x][y][i].head.size_y = 1;
00560                 bigfaces[x][y][i].tail.face = 0;
00561                 bigfaces[x][y][i].tail.size_x = 0;
00562                 bigfaces[x][y][i].tail.size_y = 0;
00563                 bigfaces[x][y][i].x = x;
00564                 bigfaces[x][y][i].y = y;
00565                 bigfaces[x][y][i].layer = i;
00566             }
00567         }
00568     }
00569     bigfaces_head = NULL;
00570 }
00571 
00572 void mapdata_reset(void)
00573 {
00574     mapdata_init();
00575 }
00576 
00577 void mapdata_set_size(int viewx, int viewy)
00578 {
00579     mapdata_init();
00580 
00581     width = viewx;
00582     height = viewy;
00583     pl_pos.x = FOG_MAP_SIZE/2-width/2;
00584     pl_pos.y = FOG_MAP_SIZE/2-height/2;
00585 }
00586 
00587 int mapdata_is_inside(int x, int y)
00588 {
00589     return(x >= 0 && x < width && y >= 0 && y < height);
00590 }
00591 
00592 /* mapdate_clear_space() is used by Map2Cmd()
00593  * Basically, server has told us there is nothing on
00594  * this space.  So clear it.
00595  */
00596 void mapdata_clear_space(int x, int y)
00597 {
00598     int px, py;
00599     int i;
00600 
00601     assert(0 <= x && x < MAX_VIEW);
00602     assert(0 <= y && y < MAX_VIEW);
00603 
00604     px = pl_pos.x+x;
00605     py = pl_pos.y+y;
00606     assert(0 <= px && px < FOG_MAP_SIZE);
00607     assert(0 <= py && py < FOG_MAP_SIZE);
00608 
00609     if (x < width && y < height) {
00610         /* tile is visible */
00611 
00612         /* visible tile is now blank ==> do not clear but mark as cleared */
00613         if (!the_map.cells[px][py].cleared) {
00614             the_map.cells[px][py].cleared = 1;
00615             the_map.cells[px][py].need_update = 1;
00616 
00617             for (i=0; i < MAXLAYERS; i++)
00618                 if (the_map.cells[px][py].heads[i].face)
00619                     expand_need_update_from_layer(px, py, i);
00620         }
00621     }
00622     else {
00623         /* tile is invisible (outside view area, i.e. big face update) */
00624 
00625         for (i = 0; i < MAXLAYERS; i++) {
00626             expand_set_bigface(x, y, i, 0, TRUE);
00627         }
00628     }
00629 }
00630 
00631 
00632 /* With map2, we basically process a piece of data at a time.  Thus,
00633  * for each piece, we don't know what the final state of the space
00634  * will be.  So once Map2Cmd() has processed all the information for
00635  * a space, it calls mapdata_set_check_space() which can see if
00636  * the space is cleared or other inconsistencies.
00637  */
00638 void mapdata_set_check_space(int x, int y)
00639 {
00640     int px, py;
00641     int is_blank;
00642     int i;
00643     struct MapCell *cell;
00644 
00645     assert(0 <= x && x < MAX_VIEW);
00646     assert(0 <= y && y < MAX_VIEW);
00647 
00648     px = pl_pos.x+x;
00649     py = pl_pos.y+y;
00650 
00651     assert(0 <= px && px < FOG_MAP_SIZE);
00652     assert(0 <= py && py < FOG_MAP_SIZE);
00653 
00654 
00655     is_blank=1;
00656     cell = &the_map.cells[px][py];
00657     for (i=0; i < MAXLAYERS; i++) {
00658         if (cell->heads[i].face>0 || cell->tails[i].face>0) {
00659             is_blank=0;
00660             break;
00661         }
00662     }
00663 
00664     if (cell->have_darkness) is_blank=0;
00665 
00666     /* We only care if this space needs to be blanked out */
00667     if (!is_blank) return;
00668 
00669     if (x < width && y < height) {
00670         /* tile is visible */
00671 
00672         /* visible tile is now blank ==> do not clear but mark as cleared */
00673         if (!the_map.cells[px][py].cleared) {
00674             the_map.cells[px][py].cleared = 1;
00675             the_map.cells[px][py].need_update = 1;
00676 
00677             for (i=0; i < MAXLAYERS; i++)
00678                 expand_need_update_from_layer(px, py, i);
00679         }
00680     }
00681 }
00682 
00683 
00684 
00685 /* This just sets the darkness for a space.
00686  * Used by Map2Cmd()
00687  */
00688 void mapdata_set_darkness(int x, int y, int darkness)
00689 {
00690     int px, py;
00691 
00692     assert(0 <= x && x < MAX_VIEW);
00693     assert(0 <= y && y < MAX_VIEW);
00694 
00695     px = pl_pos.x+x;
00696     py = pl_pos.y+y;
00697     assert(0 <= px && px < FOG_MAP_SIZE);
00698     assert(0 <= py && py < FOG_MAP_SIZE);
00699 
00700     /* Ignore darkness information for tile outside the viewable area: if
00701      * such a tile becomes visible again, it is either "fog of war" (and
00702      * darkness information is ignored) or it will be updated (including
00703      * the darkness information).
00704      */
00705     if (darkness != -1 && x < width && y < height) {
00706         set_darkness(px, py, 255-darkness);
00707     }
00708 }
00709 
00710 /* Sets smooth information for layer */
00711 void mapdata_set_smooth(int x, int y, int smooth, int layer)
00712 {
00713     static int dx[8]={0,1,1,1,0,-1,-1,-1};
00714     static int dy[8]={-1,-1,0,1,1,1,0,-1};
00715     int rx, ry, px, py, i;
00716 
00717     assert(0 <= x && x < MAX_VIEW);
00718     assert(0 <= y && y < MAX_VIEW);
00719 
00720     px = pl_pos.x+x;
00721     py = pl_pos.y+y;
00722     assert(0 <= px && px < FOG_MAP_SIZE);
00723     assert(0 <= py && py < FOG_MAP_SIZE);
00724 
00725     if (the_map.cells[px][py].smooth[layer] != smooth) {
00726         for (i=0;i<8;i++){
00727             rx=px+dx[i];
00728             ry=py+dy[i];
00729             if ( (rx<0) || (ry<0) || (the_map.x<=rx) || (the_map.y<=ry))
00730                 continue;
00731             the_map.cells[rx][ry].need_resmooth=1;
00732         }
00733         the_map.cells[px][py].need_resmooth=1;
00734         the_map.cells[px][py].smooth[layer] = smooth;
00735     }
00736 }
00737 
00738 /* If old cell data is set and is to be cleared, clear it.
00739  * This used to be in mapdata_set_face_layer(), however it needs to be
00740  * called here, earlier in the Map2Cmd() because otherwise darkness
00741  * doesn't work went sent before the layer data when that square was
00742  * going to be cleared. This is used by the Map2Cmd()
00743  */
00744 void mapdata_clear_old(int x, int y) {
00745     int px, py;
00746     int i;
00747 
00748     assert(0 <= x && x < MAX_VIEW);
00749     assert(0 <= y && y < MAX_VIEW);
00750 
00751     px = pl_pos.x+x;
00752     py = pl_pos.y+y;
00753     assert(0 <= px && px < FOG_MAP_SIZE);
00754     assert(0 <= py && py < FOG_MAP_SIZE);
00755 
00756     if (x < width && y < height)
00757         if (the_map.cells[px][py].cleared) {
00758             for (i=0; i < MAXLAYERS; i++)
00759                 expand_clear_face_from_layer(px, py, i);
00760 
00761             the_map.cells[px][py].darkness = 0;
00762             the_map.cells[px][py].have_darkness = 0;
00763         }
00764 }
00765 
00766 /* This is vaguely related to the mapdata_set_face() above, but rather
00767  * than take all the faces, takes 1 face and the layer this face is
00768  * on.  This is used by the Map2Cmd()
00769  */
00770 void mapdata_set_face_layer(int x, int y, sint16 face, int layer)
00771 {
00772     int px, py;
00773 
00774     assert(0 <= x && x < MAX_VIEW);
00775     assert(0 <= y && y < MAX_VIEW);
00776 
00777     px = pl_pos.x+x;
00778     py = pl_pos.y+y;
00779     assert(0 <= px && px < FOG_MAP_SIZE);
00780     assert(0 <= py && py < FOG_MAP_SIZE);
00781 
00782     if (x < width && y < height) {
00783         the_map.cells[px][py].need_update = 1;
00784         if (face >0)
00785             expand_set_face(px, py, layer, face, TRUE);
00786         else {
00787             expand_clear_face_from_layer(px, py, layer);
00788         }
00789 
00790         the_map.cells[px][py].cleared = 0;
00791     }
00792     else {
00793         expand_set_bigface(x, y, layer, face, TRUE);
00794     }
00795 }
00796 
00797 
00798 /* This is vaguely related to the mapdata_set_face() above, but rather
00799  * than take all the faces, takes 1 face and the layer this face is
00800  * on.  This is used by the Map2Cmd()
00801  */
00802 void mapdata_set_anim_layer(int x, int y, uint16 anim, uint8 anim_speed, int layer)
00803 {
00804     int px, py;
00805     int i, face, animation, phase, speed_left;
00806 
00807     assert(0 <= x && x < MAX_VIEW);
00808     assert(0 <= y && y < MAX_VIEW);
00809 
00810     px = pl_pos.x+x;
00811     py = pl_pos.y+y;
00812     assert(0 <= px && px < FOG_MAP_SIZE);
00813     assert(0 <= py && py < FOG_MAP_SIZE);
00814 
00815     animation = anim & ANIM_MASK;
00816     face = 0;
00817 
00818     /* Random animation is pretty easy */
00819     if ((anim & ANIM_FLAGS_MASK) == ANIM_RANDOM) {
00820         phase = random() % animations[animation].num_animations;
00821         face = animations[animation].faces[phase];
00822         speed_left = anim_speed % random();
00823     } else if ((anim & ANIM_FLAGS_MASK) == ANIM_SYNC) {
00824         animations[animation].speed = anim_speed;
00825         phase = animations[animation].phase;
00826         speed_left = animations[animation].speed_left;
00827         face = animations[animation].faces[phase];
00828     }
00829 
00830     if (x < width && y < height) {
00831         the_map.cells[px][py].need_update = 1;
00832         if (the_map.cells[px][py].cleared) {
00833             for (i=0; i < MAXLAYERS; i++)
00834                 expand_clear_face_from_layer(px, py, i);
00835 
00836             the_map.cells[px][py].darkness = 0;
00837             the_map.cells[px][py].have_darkness = 0;
00838         }
00839         if (face >0) {
00840             expand_set_face(px, py, layer, face, TRUE);
00841             the_map.cells[px][py].heads[layer].animation = animation;
00842             the_map.cells[px][py].heads[layer].animation_phase = phase;
00843             the_map.cells[px][py].heads[layer].animation_speed = anim_speed;
00844             the_map.cells[px][py].heads[layer].animation_left = speed_left;
00845         }
00846         else {
00847             expand_clear_face_from_layer(px, py, layer);
00848         }
00849 
00850         the_map.cells[px][py].cleared = 0;
00851 
00852     }
00853     else {
00854         expand_set_bigface(x, y, layer, face, TRUE);
00855     }
00856 }
00857 
00858 
00859 void mapdata_scroll(int dx, int dy)
00860 {
00861     int x, y;
00862 
00863     recenter_virtual_map_view(dx, dy);
00864 
00865     if (want_config[CONFIG_MAPSCROLL] && display_mapscroll(dx, dy)) {
00866         struct BigCell *cell;
00867 
00868         /* Mark all tiles as "need_update" that are overlapped by a big face
00869          * from outside the view area.
00870          */
00871         for (cell = bigfaces_head; cell != NULL; cell = cell->next) {
00872             for (x = 0; x < cell->head.size_x; x++) {
00873                 for (y = !x; y < cell->head.size_y; y++) {
00874                     if (0 <= cell->x-x && cell->x-x < width
00875                     && 0 <= cell->y-y && cell->y-y < height) {
00876                         the_map.cells[pl_pos.x+cell->x-x][pl_pos.y+cell->y-y].need_update = 1;
00877                     }
00878                 }
00879             }
00880         }
00881     }
00882     else {
00883         /* Emulate map scrolling by redrawing all tiles. */
00884         for (x = 0; x < width; x++) {
00885             for (y = 0; y < height; y++) {
00886                 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 1;
00887             }
00888         }
00889     }
00890 
00891     pl_pos.x += dx;
00892     pl_pos.y += dy;
00893 
00894     /* clear all newly visible tiles */
00895     if (dx > 0) {
00896         for (y = 0; y < height; y++) {
00897             for (x = width-dx; x < width; x++) {
00898                 the_map.cells[pl_pos.x+x][pl_pos.y+y].cleared = 1;
00899                 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 1;
00900             }
00901         }
00902     }
00903     else {
00904         for (y = 0; y < height; y++) {
00905             for (x = 0; x < -dx; x++) {
00906                 the_map.cells[pl_pos.x+x][pl_pos.y+y].cleared = 1;
00907                 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 1;
00908             }
00909         }
00910     }
00911 
00912     if (dy > 0) {
00913         for (x = 0; x < width; x++) {
00914             for (y = height-dy; y < height; y++) {
00915                 the_map.cells[pl_pos.x+x][pl_pos.y+y].cleared = 1;
00916                 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 1;
00917             }
00918         }
00919     }
00920     else {
00921         for (x = 0; x < width; x++) {
00922             for (y = 0; y < -dy; y++) {
00923                 the_map.cells[pl_pos.x+x][pl_pos.y+y].cleared = 1;
00924                 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 1;
00925             }
00926         }
00927     }
00928 
00929     /* Remove all big faces outside the view area. */
00930     while (bigfaces_head != NULL) {
00931         expand_clear_bigface_from_layer(bigfaces_head->x, bigfaces_head->y, bigfaces_head->layer, 0);
00932     }
00933 }
00934 
00935 void mapdata_newmap(void)
00936 {
00937     int x, y;
00938 
00939     /* Clear the_map.cells[]. */
00940     for (x = 0; x < FOG_MAP_SIZE; x++) {
00941         CLEAR_CELLS(x, 0, FOG_MAP_SIZE);
00942         for (y = 0; y < FOG_MAP_SIZE; y++) {
00943             the_map.cells[x][y].need_update = 1;
00944         }
00945     }
00946 
00947     /* Clear bigfaces[]. */
00948     while (bigfaces_head != NULL) {
00949         expand_clear_bigface_from_layer(bigfaces_head->x, bigfaces_head->y, bigfaces_head->layer, 0);
00950     }
00951 
00952     display_map_newmap();
00953 }
00954 
00955 sint16 mapdata_face(int x, int y, int layer)
00956 {
00957     if (width <= 0) return(0);
00958 
00959     assert(0 <= x && x < width);
00960     assert(0 <= y && y < height);
00961     assert(0 <= layer && layer < MAXLAYERS);
00962 
00963     return(the_map.cells[pl_pos.x+x][pl_pos.y+y].heads[layer].face);
00964 }
00965 
00966 sint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh)
00967 {
00968     sint16 result;
00969 
00970     if (width <= 0) return(0);
00971 
00972     assert(0 <= x && x < width);
00973     assert(0 <= y && y < height);
00974     assert(0 <= layer && layer < MAXLAYERS);
00975 
00976     result = the_map.cells[pl_pos.x+x][pl_pos.y+y].tails[layer].face;
00977     if (result != 0) {
00978         int clear_bigface;
00979         int dx = the_map.cells[pl_pos.x+x][pl_pos.y+y].tails[layer].size_x;
00980         int dy = the_map.cells[pl_pos.x+x][pl_pos.y+y].tails[layer].size_y;
00981         int w = the_map.cells[pl_pos.x+x+dx][pl_pos.y+y+dy].heads[layer].size_x;
00982         int h = the_map.cells[pl_pos.x+x+dx][pl_pos.y+y+dy].heads[layer].size_y;
00983         assert(1 <= w && w <= MAX_FACE_SIZE);
00984         assert(1 <= h && h <= MAX_FACE_SIZE);
00985         assert(0 <= dx && dx < w);
00986         assert(0 <= dy && dy < h);
00987 
00988         /* Now check if we are about to display an obsolete big face: such a
00989          * face has a cleared ("fog of war") head but the current tile is not
00990          * fog of war. Since the server would have sent an appropriate head
00991          * tile if it was already valid, just clear the big face and do not
00992          * return it.
00993          */
00994         if (the_map.cells[pl_pos.x+x][pl_pos.y+y].cleared) {
00995             /* Current face is a "fog of war" tile ==> do not clear
00996              * old information.
00997              */
00998             clear_bigface = 0;
00999         }
01000         else {
01001             if (x+dx < width && y+dy < height) {
01002                 /* Clear face if current tile is valid but the
01003                  * head is marked as cleared.
01004                  */
01005                 clear_bigface = the_map.cells[pl_pos.x+x+dx][pl_pos.y+y+dy].cleared;
01006             }
01007             else {
01008                 /* Clear face if current tile is valid but the
01009                  * head is not set.
01010                  */
01011                 clear_bigface = bigfaces[x+dx][y+dy][layer].head.face == 0;
01012             }
01013         }
01014 
01015         if (!clear_bigface) {
01016             *ww = w-1-dx;
01017             *hh = h-1-dy;
01018             return(result);
01019         }
01020 
01021         assert(the_map.cells[pl_pos.x+x][pl_pos.y+y].tails[layer].face == result);
01022         expand_clear_face_from_layer(pl_pos.x+x+dx, pl_pos.y+y+dy, layer);
01023         assert(the_map.cells[pl_pos.x+x][pl_pos.y+y].tails[layer].face == 0);
01024     }
01025 
01026     result = bigfaces[x][y][layer].tail.face;
01027     if (result != 0) {
01028         int dx = bigfaces[x][y][layer].tail.size_x;
01029         int dy = bigfaces[x][y][layer].tail.size_y;
01030         int w = bigfaces[x+dx][y+dy][layer].head.size_x;
01031         int h = bigfaces[x+dx][y+dy][layer].head.size_y;
01032         assert(0 <= dx && dx < w);
01033         assert(0 <= dy && dy < h);
01034         *ww = w-1-dx;
01035         *hh = h-1-dy;
01036         return(result);
01037     }
01038 
01039     *ww = 1;
01040     *hh = 1;
01041     return(0);
01042 }
01043 
01044 /* This is used by the opengl logic.
01045  * Basically the opengl code draws the the entire image,
01046  * and doesn't care if if portions are off the edge
01047  * (opengl takes care of that).  So basically, this
01048  * function returns only if the head for a space is set,
01049  * otherwise, returns 0 - we don't care about the tails
01050  * or other details really.
01051  */
01052 sint16 mapdata_bigface_head(int x, int y, int layer, int *ww, int *hh)
01053 {
01054     sint16 result;
01055 
01056     if (width <= 0) return(0);
01057 
01058     assert(0 <= x && x < MAX_VIEW);
01059     assert(0 <= y && y < MAX_VIEW);
01060     assert(0 <= layer && layer < MAXLAYERS);
01061 
01062     result = bigfaces[x][y][layer].head.face;
01063     if (result != 0) {
01064         int w = bigfaces[x][y][layer].head.size_x;
01065         int h = bigfaces[x][y][layer].head.size_y;
01066         *ww = w;
01067         *hh = h;
01068         return(result);
01069     }
01070 
01071     *ww = 1;
01072     *hh = 1;
01073     return(0);
01074 }
01075 
01084 static void recenter_virtual_map_view(int diff_x, int diff_y)
01085 {
01086     int new_x, new_y;
01087     int shift_x, shift_y;
01088     int src_x, src_y;
01089     int dst_x, dst_y;
01090     int len_x, len_y;
01091     int sx;
01092     int dx;
01093     int i;
01094 
01095     /* shift player position in virtual map */
01096     new_x = pl_pos.x+diff_x;
01097     new_y = pl_pos.y+diff_y;
01098 
01099     /* determine neccessary amount to shift */
01100 
01101     /* if(new_x < 1) is not possible: a big face may reach up to
01102      * (MAX_FACE_SIZE-1) tiles to the left of pl_pos. Therefore maintain a
01103      * border of at least MAX_FACE_SIZE to the left of the virtual map
01104      * edge.
01105      */
01106     if (new_x < MAX_FACE_SIZE) {
01107         shift_x = FOG_BORDER_MIN+MAX_FACE_SIZE-new_x;
01108         /* This yields: new_x+shift_x == FOG_BORDER_MIN+MAX_FACE_SIZE,
01109          * i.e. left border is FOG_BORDER_MIN+MAX_FACE_SIZE after
01110          * shifting.
01111          */
01112     }
01113     else if (new_x+MAX_VIEW > FOG_MAP_SIZE) {
01114         shift_x = FOG_MAP_SIZE-FOG_BORDER_MIN-MAX_VIEW-new_x;
01115         /* This yields: new_x+shift_x ==
01116          * FOG_MAP_SIZE-FOG_BODER_MIN-MAX_VIEW, i.e. right border is
01117          * FOGBORDER_MIN after shifting.
01118          */
01119     }
01120     else {
01121         shift_x = 0;
01122     }
01123 
01124     /* Same as above but for y. */
01125     if (new_y < MAX_FACE_SIZE) {
01126         shift_y = FOG_BORDER_MIN+MAX_FACE_SIZE-new_y;
01127     }
01128     else if (new_y+MAX_VIEW > FOG_MAP_SIZE) {
01129         shift_y = FOG_MAP_SIZE-FOG_BORDER_MIN-MAX_VIEW-new_y;
01130     }
01131     else {
01132         shift_y = 0;
01133     }
01134 
01135     /* No shift neccessary? ==> nothing to do. */
01136     if (shift_x == 0 && shift_y == 0) {
01137         return;
01138     }
01139 
01140     /* If shifting at all: maintain a border size of FOG_BORDER_MIN to all
01141      * directions. For example: if pl_pos=30/MAX_FACE_SIZE, and map_scroll is
01142      * 0/-1: shift pl_pos to FOG_BORDER_MIN+1/FOG_BORDER_MIN+1, not to
01143      * 30/FOG_BORDER_MIN+1.
01144      */
01145     if (shift_x == 0) {
01146         if (new_x < FOG_BORDER_MIN+MAX_FACE_SIZE) {
01147             shift_x = FOG_BORDER_MIN+MAX_FACE_SIZE-new_x;
01148         }
01149         else if (new_x+MAX_VIEW+FOG_BORDER_MIN > FOG_MAP_SIZE) {
01150             shift_x = FOG_MAP_SIZE-FOG_BORDER_MIN-MAX_VIEW-new_x;
01151         }
01152     }
01153     if (shift_y == 0) {
01154         if (new_y < FOG_BORDER_MIN+MAX_FACE_SIZE) {
01155             shift_y = FOG_BORDER_MIN+MAX_FACE_SIZE-new_y;
01156         }
01157         else if (new_y+MAX_VIEW+FOG_BORDER_MIN > FOG_MAP_SIZE) {
01158             shift_y = FOG_MAP_SIZE-FOG_BORDER_MIN-MAX_VIEW-new_y;
01159         }
01160     }
01161 
01162     /* Shift for more than virtual map size? ==> clear whole virtual map
01163      * and recenter.
01164      */
01165     if (shift_x <= -FOG_MAP_SIZE || shift_x >= FOG_MAP_SIZE
01166     || shift_y <= -FOG_MAP_SIZE || shift_y >= FOG_MAP_SIZE) {
01167         for (dx = 0; dx < FOG_MAP_SIZE; dx++) {
01168             CLEAR_CELLS(dx, 0, FOG_MAP_SIZE);
01169         }
01170 
01171         pl_pos.x = FOG_MAP_SIZE/2-width/2;
01172         pl_pos.y = FOG_MAP_SIZE/2-height/2;
01173         return;
01174     }
01175 
01176     /* Move player position. */
01177     pl_pos.x += shift_x;
01178     pl_pos.y += shift_y;
01179 
01180     /* Actually shift the virtual map by shift_x/shift_y */
01181     if (shift_x < 0) {
01182         src_x = -shift_x;
01183         dst_x = 0;
01184         len_x = FOG_MAP_SIZE+shift_x;
01185     }
01186     else {
01187         src_x = 0;
01188         dst_x = shift_x;
01189         len_x = FOG_MAP_SIZE-shift_x;
01190     }
01191 
01192     if (shift_y < 0) {
01193         src_y = -shift_y;
01194         dst_y = 0;
01195         len_y = FOG_MAP_SIZE+shift_y;
01196     }
01197     else {
01198         src_y = 0;
01199         dst_y = shift_y;
01200         len_y = FOG_MAP_SIZE-shift_y;
01201     }
01202 
01203     if (shift_x < 0) {
01204         for (sx = src_x, dx = dst_x, i = 0; i < len_x; sx++, dx++, i++) {
01205             /* srcx!=dstx ==> can use memcpy since source and
01206              * destination to not overlap.
01207              */
01208             memcpy(&the_map.cells[dx][dst_y], &the_map.cells[sx][src_y], len_y*sizeof(the_map.cells[dx][dst_y]));
01209         }
01210     }
01211     else if (shift_x > 0) {
01212         for (sx = src_x+len_x-1, dx = dst_x+len_x-1, i = 0; i < len_x; sx--, dx--, i++) {
01213             /* srcx!=dstx ==> can use memcpy since source and
01214              * destination to not overlap.
01215              */
01216             memcpy(&the_map.cells[dx][dst_y], &the_map.cells[sx][src_y], len_y*sizeof(the_map.cells[dx][dst_y]));
01217         }
01218     }
01219     else {
01220         assert(src_x == dst_x);
01221         for (dx = src_x, i = 0; i < len_x; dx++, i++) {
01222             /* srcx==dstx ==> use memmove since source and
01223              * destination probably do overlap.
01224              */
01225             memmove(&the_map.cells[dx][dst_y], &the_map.cells[dx][src_y], len_y*sizeof(the_map.cells[dx][dst_y]));
01226         }
01227     }
01228 
01229     /* Clear newly opened area */
01230     for (dx = 0; dx < dst_x; dx++) {
01231         CLEAR_CELLS(dx, 0, FOG_MAP_SIZE);
01232     }
01233     for (dx = dst_x+len_x; dx < FOG_MAP_SIZE; dx++) {
01234         CLEAR_CELLS(dx, 0, FOG_MAP_SIZE);
01235     }
01236     if (shift_y > 0) {
01237         for (dx = 0; dx < len_x; dx++) {
01238             CLEAR_CELLS(dx+dst_x, 0, shift_y);
01239         }
01240     }
01241     else if (shift_y < 0) {
01242         for (dx = 0; dx < len_x; dx++) {
01243             CLEAR_CELLS(dx+dst_x, FOG_MAP_SIZE+shift_y, -shift_y);
01244         }
01245     }
01246 }
01247 
01252 static void mapdata_get_image_size(int face, uint8 *w, uint8 *h)
01253 {
01254     get_map_image_size(face, w, h);
01255     if (*w < 1) *w = 1;
01256     if (*h < 1) *h = 1;
01257     if (*w > MAX_FACE_SIZE) *w = MAX_FACE_SIZE;
01258     if (*h > MAX_FACE_SIZE) *h = MAX_FACE_SIZE;
01259 }
01260 
01261 /* This basically goes through all the map spaces and does the necessary
01262  * animation.
01263  */
01264 void mapdata_animation(void)
01265 {
01266     int x, y, layer, face, smooth;
01267     struct MapCellLayer *cell;
01268 
01269 
01270     /* For synchronized animations, what we do is set the initial values
01271      * in the mapdata to the fields in the animations[] array.  In this way,
01272      * the code below the iterates the spaces doesn't need to do anything
01273      * special.  But we have to update the animations[] array here to
01274      * keep in sync.
01275      */
01276     for (x=0; x < MAXANIM; x++) {
01277         if (animations[x].speed) {
01278             animations[x].speed_left++;
01279             if (animations[x].speed_left >= animations[x].speed) {
01280                 animations[x].speed_left=0;
01281                 animations[x].phase++;
01282                 if (animations[x].phase >= animations[x].num_animations)
01283                     animations[x].phase=0;
01284             }
01285         }
01286     }
01287 
01288     for (x=0; x < CURRENT_MAX_VIEW; x++) {
01289         for (y=0; y < CURRENT_MAX_VIEW; y++) {
01290 
01291             /* Short cut some processing here.  It makes sense to me
01292              * not to animate stuff out of view
01293              */
01294             if (the_map.cells[pl_pos.x + x][pl_pos.y + y].cleared) continue;
01295 
01296             for (layer=0; layer<MAXLAYERS; layer++) {
01297                 smooth = the_map.cells[pl_pos.x + x][pl_pos.y + y].smooth[layer];
01298 
01299                 /* Using the cell structure just makes life easier here */
01300                 cell = &the_map.cells[pl_pos.x+x][pl_pos.y+y].heads[layer];
01301 
01302                 if (cell->animation) {
01303                     cell->animation_left++;
01304                     if (cell->animation_left >= cell->animation_speed) {
01305                         cell->animation_left=0;
01306                         cell->animation_phase++;
01307                         if (cell->animation_phase >= animations[cell->animation].num_animations)
01308                             cell->animation_phase=0;
01309                         face = animations[cell->animation].faces[cell->animation_phase];
01310 
01311                         /* I don't think we send any to the client, but it is possible
01312                          * for animations to have blank faces.
01313                          */
01314                         if (face >0) {
01315                             expand_set_face(pl_pos.x + x, pl_pos.y + y, layer, face, FALSE);
01316 /*                          mapdata_set_smooth(x, y, smooth, layer);*/
01317                         } else {
01318                             expand_clear_face_from_layer(pl_pos.x + x, pl_pos.y + y , layer);
01319                         }
01320                     }
01321                 }
01322                 cell = &bigfaces[x][y][layer].head;
01323                 if (cell->animation) {
01324                     cell->animation_left++;
01325                     if (cell->animation_left >= cell->animation_speed) {
01326                         cell->animation_left=0;
01327                         cell->animation_phase++;
01328                         if (cell->animation_phase >= animations[cell->animation].num_animations)
01329                             cell->animation_phase=0;
01330                         face = animations[cell->animation].faces[cell->animation_phase];
01331 
01332                         /* I don't think we send any to the client, but it is possible
01333                          * for animations to have blank faces.
01334                          */
01335                         expand_set_bigface(x, y, layer, face, FALSE);
01336                     }
01337                 }
01338             }
01339         }
01340     }
01341 }