Crossfire Client, Branch
R11627
|
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 }