|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 #include <loader.h> 00032 #include <gd.h> 00033 00044 static int **wm_face_colors; 00045 00047 #define MAX_PIXELS 3 00048 00050 typedef struct wm_region 00051 { 00053 struct 00054 { 00056 mapstruct *m; 00057 00059 int xpos; 00060 00062 int ypos; 00063 } *maps; 00064 00066 size_t num_maps; 00067 00069 int xpos; 00070 00072 int ypos; 00073 00075 int xpos_lowest; 00076 00078 int ypos_lowest; 00079 00081 int w; 00082 00084 int h; 00085 } wm_region; 00086 00089 static void wm_images_init() 00090 { 00091 int i, x, y; 00092 gdImagePtr im, im2; 00093 uint8 *data; 00094 uint16 len; 00095 00096 wm_face_colors = malloc(sizeof(*wm_face_colors) * nrofpixmaps); 00097 00098 for (i = 0; i < nrofpixmaps; i++) 00099 { 00100 uint64 total = 0, r = 0, g = 0, b = 0; 00101 00102 /* Get the face's data. */ 00103 face_get_data(i, &data, &len); 00104 00105 /* Create the image from the data. */ 00106 im = gdImageCreateFromPngPtr(len, data); 00107 gdImageAlphaBlending(im, 1); 00108 gdImageSaveAlpha(im, 1); 00109 00110 im2 = gdImageCreateTrueColor(im->sx, im->sy); 00111 gdImageCopyResized(im2, im, 0, 0, 0, 0, im2->sx, im2->sy, im->sx, im->sy); 00112 00113 wm_face_colors[i] = calloc(1, sizeof(**wm_face_colors) * 5); 00114 00115 /* Get the average pixel colors. */ 00116 for (x = 0; x < im2->sx; x++) 00117 { 00118 for (y = 0; y < im2->sy; y++) 00119 { 00120 int color = gdImageGetPixel(im2, x, y); 00121 00122 if (color) 00123 { 00124 r += gdImageRed(im2, color); 00125 g += gdImageGreen(im2, color); 00126 b += gdImageBlue(im2, color); 00127 total++; 00128 } 00129 } 00130 } 00131 00132 /* Store the total. */ 00133 if (total) 00134 { 00135 r /= total; 00136 g /= total; 00137 b /= total; 00138 wm_face_colors[i][0] = gdImageColorResolve(im2, r, g, b); 00139 wm_face_colors[i][1] = gdImageColorResolve(im2, MIN(r + 10, 255), MIN(g + 10, 255), MIN(b + 10, 255)); 00140 wm_face_colors[i][2] = r; 00141 wm_face_colors[i][3] = g; 00142 wm_face_colors[i][4] = b; 00143 } 00144 00145 gdImageDestroy(im); 00146 gdImageDestroy(im2); 00147 } 00148 } 00149 00157 static int render_object(gdImagePtr im, int x, int y, object *ob) 00158 { 00159 /* Sanity check. */ 00160 if (!ob) 00161 { 00162 return 0; 00163 } 00164 00165 /* No need to do this for tail parts. */ 00166 if (ob->head) 00167 { 00168 return 0; 00169 } 00170 00171 /* Only render the following objects: 00172 * - floor (the terrain, obviously) 00173 * - walls 00174 * - doors 00175 * - exits (stairs, but also useful to see portals) 00176 * - shop mats 00177 * - misc objects blocking passage (rocks, trees, etc) 00178 * - holy altars*/ 00179 if (ob->layer == LAYER_FLOOR || ob->type == WALL || ob->type == DOOR || ob->type == EXIT || ob->type == SHOP_MAT || (ob->type == MISC_OBJECT && QUERY_FLAG(ob, FLAG_NO_PASS)) || ob->type == HOLY_ALTAR || ob->type == SIGN) 00180 { 00181 int px, py, j = 0, max; 00182 00183 max = MAX_PIXELS; 00184 00185 /* Adjust the maximum position if this is a multi-arch object. */ 00186 if (ob->quick_pos) 00187 { 00188 max *= ((ob->quick_pos >> 4) + 1) / 2; 00189 } 00190 00191 /* Draw the pixels. */ 00192 for (px = 0; px < max; px++) 00193 { 00194 for (py = 0; py < max; py++) 00195 { 00196 /* Do shading based on the floor's z. */ 00197 if (ob->type == FLOOR && ob->z) 00198 { 00199 gdImageSetPixel(im, x + px, y + py, gdImageColorResolve(im, MAX(0, wm_face_colors[ob->face->number][2] - ob->z / 2.5), MAX(0, wm_face_colors[ob->face->number][3] - ob->z / 2.5), MAX(0, wm_face_colors[ob->face->number][4] - ob->z / 2.5))); 00200 } 00201 else 00202 { 00203 gdImageSetPixel(im, x + px, y + py, wm_face_colors[ob->face->number][py == 1 && px == 1 ? 1 : 0]); 00204 } 00205 00206 j++; 00207 } 00208 } 00209 00210 return 1; 00211 } 00212 00213 return 0; 00214 } 00215 00220 static void region_add_map(wm_region *r, mapstruct *m) 00221 { 00222 /* Resize the array. */ 00223 r->maps = realloc(r->maps, sizeof(*r->maps) * (r->num_maps + 1)); 00224 r->maps[r->num_maps].m = m; 00225 r->maps[r->num_maps].xpos = r->xpos; 00226 r->maps[r->num_maps].ypos = r->ypos; 00227 r->num_maps++; 00228 } 00229 00236 static int map_in_region(mapstruct *m, const char *name) 00237 { 00238 region *r; 00239 00240 for (r = m->region; r; r = r->parent) 00241 { 00242 if (!strcmp(r->name, name)) 00243 { 00244 return 1; 00245 } 00246 } 00247 00248 return 0; 00249 } 00250 00256 static void region_add_rec(wm_region *r, mapstruct *m, const char *region_name) 00257 { 00258 int i; 00259 00260 region_add_map(r, m); 00261 00262 /* Going through 4 tile paths should be enough. */ 00263 for (i = 0; i < 4; i++) 00264 { 00265 /* No such tile path. */ 00266 if (!m->tile_path[i]) 00267 { 00268 continue; 00269 } 00270 00271 /* Load the map if needed. */ 00272 if (!m->tile_map[i]) 00273 { 00274 m->tile_map[i] = ready_map_name(m->tile_path[i], MAP_NAME_SHARED); 00275 00276 if (!m->tile_map[i]) 00277 { 00278 continue; 00279 } 00280 } 00281 00282 /* If there is a map and it wasn't traversed yet... */ 00283 if (m->tile_map[i] && !m->tile_map[i]->traversed) 00284 { 00285 m->tile_map[i]->traversed = 1; 00286 00287 /* Is the map in region? */ 00288 if (map_in_region(m->tile_map[i], region_name)) 00289 { 00290 switch (i) 00291 { 00292 case 0: 00293 r->ypos -= MAP_HEIGHT(m->tile_map[i]) * MAX_PIXELS; 00294 break; 00295 00296 case 1: 00297 r->xpos += MAP_WIDTH(m->tile_map[i]) * MAX_PIXELS; 00298 break; 00299 00300 case 2: 00301 r->ypos += MAP_HEIGHT(m->tile_map[i]) * MAX_PIXELS; 00302 break; 00303 00304 case 3: 00305 r->xpos -= MAP_WIDTH(m->tile_map[i]) * MAX_PIXELS; 00306 break; 00307 } 00308 00309 /* Store the lowest x/y positions to do adjustments later. */ 00310 if (r->xpos < r->xpos_lowest) 00311 { 00312 r->xpos_lowest = r->xpos; 00313 } 00314 00315 if (r->ypos < r->ypos_lowest) 00316 { 00317 r->ypos_lowest = r->ypos; 00318 } 00319 00320 /* Go on recursively. */ 00321 region_add_rec(r, m->tile_map[i], region_name); 00322 00323 switch (i) 00324 { 00325 case 0: 00326 r->ypos += MAP_HEIGHT(m->tile_map[i]) * MAX_PIXELS; 00327 break; 00328 00329 case 1: 00330 r->xpos -= MAP_WIDTH(m->tile_map[i]) * MAX_PIXELS; 00331 break; 00332 00333 case 2: 00334 r->ypos -= MAP_HEIGHT(m->tile_map[i]) * MAX_PIXELS; 00335 break; 00336 00337 case 3: 00338 r->xpos += MAP_WIDTH(m->tile_map[i]) * MAX_PIXELS; 00339 break; 00340 } 00341 } 00342 } 00343 } 00344 } 00345 00348 void world_maker() 00349 { 00350 mapstruct *m; 00351 gdImagePtr im; 00352 FILE *out; 00353 size_t i; 00354 region *r; 00355 wm_region *wm_r; 00356 char buf[MAX_BUF]; 00357 int x, y, layer, got_one; 00358 int xpos = 0, ypos = 0; 00359 FILE *def_fp; 00360 object **info_objects = NULL; 00361 size_t num_info_objects = 0; 00362 00363 /* Initialize the image colors. */ 00364 wm_images_init(); 00365 00366 /* Go through regions. */ 00367 for (r = first_region; r; r = r->next) 00368 { 00369 /* No first map? */ 00370 if (!r->map_first) 00371 { 00372 continue; 00373 } 00374 00375 /* Initialize the region. */ 00376 wm_r = calloc(1, sizeof(wm_region)); 00377 /* Open the definitions file. */ 00378 snprintf(buf, sizeof(buf), "%s/%s.def", settings.world_maker_dir, r->name); 00379 def_fp = fopen(buf, "w"); 00380 00381 if (!def_fp) 00382 { 00383 LOG(llevError, "world_maker(): Could not open '%s': %s\n", buf, strerror_local(errno)); 00384 } 00385 00386 /* Load the first map. */ 00387 m = ready_map_name(r->map_first, 0); 00388 /* Parse the maps recursively. */ 00389 region_add_rec(wm_r, m, r->name); 00390 00391 snprintf(buf, sizeof(buf), "%s/%s.png", settings.world_maker_dir, r->name); 00392 00393 /* Store defaults in the definitions file. */ 00394 fprintf(def_fp, "pixel_size %d\n", MAX_PIXELS); 00395 fprintf(def_fp, "map_size_x %d\n", MAP_WIDTH(m)); 00396 fprintf(def_fp, "map_size_y %d\n", MAP_HEIGHT(m)); 00397 00398 /* Go through the loaded maps. */ 00399 for (i = 0; i < wm_r->num_maps; i++) 00400 { 00401 int map_w, map_h; 00402 00403 /* Adjust X and Y positions. */ 00404 wm_r->maps[i].xpos -= wm_r->xpos_lowest; 00405 wm_r->maps[i].ypos -= wm_r->ypos_lowest; 00406 00407 /* Calculate the maximum width needed for the actual image. */ 00408 map_w = MAP_WIDTH(wm_r->maps[i].m) * MAX_PIXELS + wm_r->maps[i].xpos; 00409 map_h = MAP_HEIGHT(wm_r->maps[i].m) * MAX_PIXELS + wm_r->maps[i].ypos; 00410 00411 if (map_w > wm_r->w) 00412 { 00413 wm_r->w = map_w; 00414 } 00415 00416 if (map_h > wm_r->h) 00417 { 00418 wm_r->h = map_h; 00419 } 00420 00421 /* Store the map path, labels, etc. */ 00422 fprintf(def_fp, "map %x %x %s\n", wm_r->maps[i].xpos, wm_r->maps[i].ypos, wm_r->maps[i].m->path); 00423 } 00424 00425 /* Create the image. */ 00426 im = gdImageCreateTrueColor(wm_r->w, wm_r->h); 00427 00428 /* Custom background to use? */ 00429 if (r->map_bg) 00430 { 00431 uint32 im_r, im_g, im_b; 00432 00433 /* Parse HTML color and fill the image with it. */ 00434 if (sscanf(r->map_bg, "#%2X%2X%2X", &im_r, &im_g, &im_b) == 3) 00435 { 00436 gdImageFill(im, 0, 0, gdImageColorAllocate(im, im_r, im_g, im_b)); 00437 } 00438 } 00439 /* Transparency otherwise. */ 00440 else 00441 { 00442 gdImageAlphaBlending(im, 1); 00443 gdImageSaveAlpha(im, 1); 00444 gdImageFill(im, 0, 0, gdTransparent); 00445 } 00446 00447 /* Go through the maps. */ 00448 for (i = 0; i < wm_r->num_maps; i++) 00449 { 00450 object *tmp; 00451 00452 m = wm_r->maps[i].m; 00453 00454 /* Draw layer 1 and layer 2 objects. */ 00455 for (x = 0; x < MAP_WIDTH(m); x++) 00456 { 00457 for (y = 0; y < MAP_HEIGHT(m); y++) 00458 { 00459 got_one = 0; 00460 xpos = x * MAX_PIXELS + wm_r->maps[i].xpos; 00461 ypos = y * MAX_PIXELS + wm_r->maps[i].ypos; 00462 00463 /* Look for map info objects. */ 00464 for (tmp = GET_MAP_OB(m, x, y); tmp && tmp->layer == LAYER_SYS; tmp = tmp->above) 00465 { 00466 if (tmp->type != CLIENT_MAP_INFO) 00467 { 00468 continue; 00469 } 00470 00471 if (tmp->sub_type != CLIENT_MAP_HIDE && (!tmp->name || strstr(tmp->name, " ") || !strcmp(tmp->name, tmp->arch->name))) 00472 { 00473 continue; 00474 } 00475 00476 /* Transform newline characters in the message to 00477 * literal "\n". */ 00478 if (tmp->msg) 00479 { 00480 char msg[HUGE_BUF * 4]; 00481 00482 replace(tmp->msg, "\n", "\\n", msg, sizeof(msg)); 00483 FREE_AND_COPY_HASH(tmp->msg, msg); 00484 } 00485 00486 /* Label. */ 00487 if (tmp->sub_type == CLIENT_MAP_LABEL) 00488 { 00489 fprintf(def_fp, "label %x %x %s %s\n", xpos + tmp->last_heal * MAX_PIXELS, ypos + tmp->last_sp * MAX_PIXELS, tmp->name, tmp->msg ? tmp->msg : "???"); 00490 00491 if (QUERY_FLAG(tmp, FLAG_CURSED)) 00492 { 00493 fprintf(def_fp, "label_hide\n"); 00494 } 00495 } 00496 else 00497 { 00498 info_objects = realloc(info_objects, sizeof(*info_objects) * (num_info_objects + 1)); 00499 info_objects[num_info_objects] = tmp; 00500 num_info_objects++; 00501 } 00502 } 00503 00504 for (layer = LAYER_FLOOR; layer <= LAYER_FMASK; layer++) 00505 { 00506 if (render_object(im, xpos, ypos, GET_MAP_OB_LAYER(m, x, y, layer - 1))) 00507 { 00508 got_one = 1; 00509 } 00510 } 00511 00512 /* Didn't get an object, fill this square with black. */ 00513 if (!got_one) 00514 { 00515 gdImageFilledRectangle(im, xpos, ypos, xpos + MAX_PIXELS - 1, ypos + MAX_PIXELS - 1, gdImageColorAllocate(im, 0, 0, 0)); 00516 } 00517 } 00518 } 00519 00520 /* Draw the rest of the objects. */ 00521 for (x = 0; x < MAP_WIDTH(m); x++) 00522 { 00523 for (y = 0; y < MAP_HEIGHT(m); y++) 00524 { 00525 xpos = x * MAX_PIXELS + wm_r->maps[i].xpos; 00526 ypos = y * MAX_PIXELS + wm_r->maps[i].ypos; 00527 00528 for (layer = LAYER_ITEM; layer < NUM_LAYERS; layer++) 00529 { 00530 render_object(im, xpos, ypos, GET_MAP_OB_LAYER(m, x, y, layer - 1)); 00531 } 00532 } 00533 } 00534 } 00535 00536 /* Parse other information objects. */ 00537 for (i = 0; i < num_info_objects; i++) 00538 { 00539 object *tmp = info_objects[i]; 00540 size_t j; 00541 00542 /* Already parsed this object. */ 00543 if (!tmp) 00544 { 00545 continue; 00546 } 00547 00548 /* Get the correct X/Y positions. */ 00549 for (j = 0; j < wm_r->num_maps; j++) 00550 { 00551 if (wm_r->maps[j].m == tmp->map) 00552 { 00553 xpos = tmp->x * MAX_PIXELS + wm_r->maps[j].xpos; 00554 ypos = tmp->y * MAX_PIXELS + wm_r->maps[j].ypos; 00555 break; 00556 } 00557 } 00558 00559 /* Hiding part of the map. */ 00560 if (tmp->sub_type == CLIENT_MAP_HIDE) 00561 { 00562 gdImageFilledRectangle(im, xpos, ypos, MIN(xpos + ((tmp->path_attuned + 1) * MAX_PIXELS), (uint32) wm_r->w), MIN(ypos + ((tmp->path_repelled + 1) * MAX_PIXELS), (uint32) wm_r->h), gdImageColorAllocate(im, 0, 0, 0)); 00563 } 00564 00565 /* Tooltip. */ 00566 if (tmp->msg && tmp->sub_type == CLIENT_MAP_TOOLTIP) 00567 { 00568 /* Tooltip with automatic width/height detection? */ 00569 if (!tmp->path_attuned && !tmp->path_repelled && !tmp->item_level && QUERY_FLAG(tmp, FLAG_STAND_STILL)) 00570 { 00571 for (j = 0; j < num_info_objects; j++) 00572 { 00573 rv_vector rv; 00574 00575 /* Already parsed object or same as the master info object. */ 00576 if (!info_objects[j] || info_objects[j] == tmp) 00577 { 00578 continue; 00579 } 00580 00581 /* Not the same name as the master info object? */ 00582 if (strcmp(info_objects[j]->name, tmp->name)) 00583 { 00584 continue; 00585 } 00586 00587 /* Get range vector from the master info object to this one. */ 00588 if (!get_rangevector(tmp, info_objects[j], &rv, RV_RECURSIVE_SEARCH)) 00589 { 00590 continue; 00591 } 00592 00593 /* Set the calculated distances. */ 00594 if (!tmp->path_attuned) 00595 { 00596 tmp->path_attuned = rv.distance_x; 00597 } 00598 00599 if (!tmp->path_repelled) 00600 { 00601 tmp->path_repelled = rv.distance_y; 00602 } 00603 00604 /* Mark this object as parsed. */ 00605 info_objects[j] = NULL; 00606 } 00607 } 00608 00609 /* Write out information about this tooltip. */ 00610 fprintf(def_fp, "tooltip %x %x %x %x %s %s\n", MAX(0, xpos - ((tmp->item_level) * MAX_PIXELS)), MAX(0, ypos - ((tmp->item_level) * MAX_PIXELS)), MIN(xpos + ((tmp->item_level * 2) * MAX_PIXELS + MAX_PIXELS) + (tmp->path_attuned * MAX_PIXELS), (uint32) wm_r->w) - xpos, MIN(ypos + ((tmp->item_level * 2) * MAX_PIXELS + MAX_PIXELS) + (tmp->path_repelled * MAX_PIXELS), (uint32) wm_r->h) - ypos, tmp->name, tmp->msg); 00611 00612 /* Outline set? */ 00613 if (tmp->item_skill) 00614 { 00615 fprintf(def_fp, "t_outline"); 00616 00617 /* Store outline's color, if any. */ 00618 if (tmp->slaying) 00619 { 00620 fprintf(def_fp, " %s", tmp->slaying); 00621 } 00622 /* No outline color, but there is non-standard size, 00623 * so we must include the default color as well. */ 00624 else if (tmp->item_skill != 1) 00625 { 00626 fprintf(def_fp, " #ff0000"); 00627 } 00628 00629 if (tmp->item_skill != 1) 00630 { 00631 fprintf(def_fp, " %d", tmp->item_skill); 00632 } 00633 00634 fprintf(def_fp, "\n"); 00635 } 00636 00637 if (QUERY_FLAG(tmp, FLAG_CURSED)) 00638 { 00639 fprintf(def_fp, "tooltip_hide\n"); 00640 } 00641 } 00642 } 00643 00644 if (info_objects) 00645 { 00646 free(info_objects); 00647 info_objects = NULL; 00648 } 00649 00650 num_info_objects = 0; 00651 00652 /* Free all maps to save memory. */ 00653 free_all_maps(); 00654 00655 /* Write out the image. */ 00656 out = fopen(buf, "wb"); 00657 gdImagePng(im, out); 00658 fclose(out); 00659 00660 /* Free data. */ 00661 gdImageDestroy(im); 00662 fclose(def_fp); 00663 free(wm_r->maps); 00664 free(wm_r); 00665 } 00666 }
1.7.4