Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_server_c = 00003 * "$Id: server.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2006 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00034 #include <global.h> 00035 #include <object.h> 00036 #include <tod.h> 00037 #include <version.h> 00038 00039 #ifdef HAVE_DES_H 00040 #include <des.h> 00041 #else 00042 # ifdef HAVE_CRYPT_H 00043 # include <crypt.h> 00044 # endif 00045 #endif 00046 00047 #ifndef __CEXTRACT__ 00048 #include <sproto.h> 00049 #endif 00050 00051 #ifdef HAVE_TIME_H 00052 #include <time.h> 00053 #endif 00054 00055 #ifndef WIN32 00056 # include <unistd.h> 00057 # include <sys/types.h> 00058 #endif 00059 00060 #include <../random_maps/random_map.h> 00061 #include <../random_maps/rproto.h> 00062 #include "path.h" 00063 00065 static const char days[7][4] = { 00066 "Sun", 00067 "Mon", 00068 "Tue", 00069 "Wed", 00070 "Thu", 00071 "Fri", 00072 "Sat" 00073 }; 00074 00081 void version(object *op) { 00082 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_VERSION, 00083 "This is Crossfire v%s", 00084 "This is Crossfire v%s", 00085 FULL_VERSION); 00086 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_VERSION, 00087 "The authors can be reached at crossfire@metalforge.org", NULL); 00088 00089 } 00090 00097 void start_info(object *op) { 00098 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, 00099 "Welcome to Crossfire, v%s!\nPress `?' for help\n", 00100 "Welcome to Crossfire, v%s!\nPress `?' for help\n", 00101 VERSION); 00102 00103 draw_ext_info_format(NDI_UNIQUE|NDI_ALL|NDI_DK_ORANGE, 5, op, 00104 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_PLAYER, 00105 "%s entered the game.", 00106 "%s entered the game.", 00107 op->name); 00108 00109 if (!op->contr->name_changed) { 00110 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, 00111 "Note that you must set your name with the name command to enter the highscore list.", NULL); 00112 } 00113 } 00114 00130 char *crypt_string(char *str, char *salt) { 00131 #if defined(WIN32) || (defined(__FreeBSD__) && !defined(HAVE_LIBDES)) 00132 return(str); 00133 #else 00134 static const char *const c = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; 00135 char s[2]; 00136 00137 if (salt == NULL) 00138 s[0] = c[RANDOM()%(int)strlen(c)], 00139 s[1] = c[RANDOM()%(int)strlen(c)]; 00140 else 00141 s[0] = salt[0], 00142 s[1] = salt[1]; 00143 00144 # ifdef HAVE_LIBDES 00145 return (char *)des_crypt(str, s); 00146 # endif 00147 /* Default case - just use crypt */ 00148 return (char *)crypt(str, s); 00149 #endif 00150 } 00151 00162 int check_password(char *typed, char *crypted) { 00163 return !strcmp(crypt_string(typed, crypted), crypted); 00164 } 00165 00175 void enter_player_savebed(object *op) { 00176 mapstruct *oldmap = op->map; 00177 object *tmp; 00178 00179 tmp = get_object(); 00180 00181 EXIT_PATH(tmp) = add_string(op->contr->savebed_map); 00182 EXIT_X(tmp) = op->contr->bed_x; 00183 EXIT_Y(tmp) = op->contr->bed_y; 00184 enter_exit(op, tmp); 00185 /* If the player has not changed maps and the name does not match 00186 * that of the savebed, his savebed map is gone. Lets go back 00187 * to the emergency path. Update what the players savebed is 00188 * while we're at it. 00189 */ 00190 if (oldmap == op->map && strcmp(op->contr->savebed_map, oldmap->path)) { 00191 LOG(llevDebug, "Player %s savebed location %s is invalid - going to emergency location (%s)\n", settings.emergency_mapname, op->name, op->contr->savebed_map); 00192 strcpy(op->contr->savebed_map, settings.emergency_mapname); 00193 op->contr->bed_x = settings.emergency_x; 00194 op->contr->bed_y = settings.emergency_y; 00195 free_string(op->contr->savebed_map); 00196 EXIT_PATH(tmp) = add_string(op->contr->savebed_map); 00197 EXIT_X(tmp) = op->contr->bed_x; 00198 EXIT_Y(tmp) = op->contr->bed_y; 00199 enter_exit(op, tmp); 00200 } 00201 free_object(tmp); 00202 } 00203 00215 static void enter_map(object *op, mapstruct *newmap, int x, int y) { 00216 mapstruct *oldmap = op->map; 00217 00218 if (out_of_map(newmap, x, y)) { 00219 LOG(llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", newmap->path, x, y); 00220 x = MAP_ENTER_X(newmap); 00221 y = MAP_ENTER_Y(newmap); 00222 if (out_of_map(newmap, x, y)) { 00223 LOG(llevError, "enter_map: map %s provides invalid default enter location (%d, %d) > (%d, %d)\n", newmap->path, x, y, MAP_WIDTH(newmap), MAP_HEIGHT(newmap)); 00224 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, 00225 "The exit is closed", NULL); 00226 return; 00227 } 00228 } 00229 /* try to find a spot for the player */ 00230 if (ob_blocked(op, newmap, x, y)) { /* First choice blocked */ 00231 /* We try to find a spot for the player, starting closest in. 00232 * We could use find_first_free_spot, but that doesn't randomize it at all, 00233 * So for example, if the north space is free, you would always end up there even 00234 * if other spaces around are available. 00235 * Note that for the second and third calls, we could start at a position other 00236 * than one, but then we could end up on the other side of walls and so forth. 00237 */ 00238 int i = find_free_spot(op, newmap, x, y, 1, SIZEOFFREE1+1); 00239 if (i == -1) { 00240 i = find_free_spot(op, newmap, x, y, 1, SIZEOFFREE2+1); 00241 if (i == -1) 00242 i = find_free_spot(op, newmap, x, y, 1, SIZEOFFREE); 00243 } 00244 if (i != -1) { 00245 x += freearr_x[i]; 00246 y += freearr_y[i]; 00247 } else { 00248 /* not much we can do in this case. */ 00249 LOG(llevInfo, "enter_map: Could not find free spot for player - will dump on top of object (%s: %d, %d)\n", newmap->path, x, y); 00250 } 00251 } /* end if looking for free spot */ 00252 00253 /* If it is a player login, he has yet to be inserted anyplace. 00254 * otherwise, we need to deal with removing the playe here. 00255 */ 00256 if (!QUERY_FLAG(op, FLAG_REMOVED)) 00257 remove_ob(op); 00258 if (op->map != NULL) { 00259 /* Lauwenmark : Here we handle the MAPLEAVE global event */ 00260 execute_global_event(EVENT_MAPLEAVE, op, op->map); 00261 } 00262 /* remove_ob clears these so they must be reset after the remove_ob call */ 00263 op->x = x; 00264 op->y = y; 00265 op->map = newmap; 00266 insert_ob_in_map(op, op->map, NULL, INS_NO_WALK_ON); 00267 00268 /* Lauwenmark : Here we handle the MAPENTER global event */ 00269 execute_global_event(EVENT_MAPENTER, op, op->map); 00270 00271 if (op->contr) { 00272 send_background_music(op->contr, newmap->background_music); 00273 } 00274 00275 newmap->timeout = 0; 00276 op->enemy = NULL; 00277 00278 if (op->contr) { 00279 strcpy(op->contr->maplevel, newmap->path); 00280 op->contr->count = 0; 00281 } 00282 00283 /* Update any golems */ 00284 if (op->type == PLAYER && op->contr->ranges[range_golem] != NULL) { 00285 int i = find_free_spot(op->contr->ranges[range_golem], newmap, x, y, 1, SIZEOFFREE); 00286 remove_ob(op->contr->ranges[range_golem]); 00287 if (i == -1) { 00288 remove_friendly_object(op->contr->ranges[range_golem]); 00289 free_object(op->contr->ranges[range_golem]); 00290 op->contr->ranges[range_golem] = NULL; 00291 op->contr->golem_count = 0; 00292 } else { 00293 object *tmp; 00294 00295 for (tmp = op->contr->ranges[range_golem]; tmp != NULL; tmp = tmp->more) { 00296 tmp->x = x+freearr_x[i]+(tmp->arch == NULL ? 0 : tmp->arch->clone.x); 00297 tmp->y = y+freearr_y[i]+(tmp->arch == NULL ? 0 : tmp->arch->clone.y); 00298 tmp->map = newmap; 00299 } 00300 insert_ob_in_map(op->contr->ranges[range_golem], newmap, NULL, 0); 00301 op->contr->ranges[range_golem]->direction = find_dir_2(op->x-op->contr->ranges[range_golem]->x, op->y-op->contr->ranges[range_golem]->y); 00302 } 00303 } 00304 op->direction = 0; 00305 00306 /* since the players map is already loaded, we don't need to worry 00307 * about pending objects. 00308 */ 00309 remove_all_pets(); 00310 00311 /* If the player is changing maps, we need to do some special things 00312 * Do this after the player is on the new map - otherwise the force swap of the 00313 * old map does not work. 00314 */ 00315 if (oldmap != newmap) { 00316 if (oldmap) { /* adjust old map */ 00317 if (oldmap->players <= 0) /* can be less than zero due to errors in tracking this */ 00318 set_map_timeout(oldmap); 00319 } 00320 } 00321 swap_below_max(newmap->path); 00322 00323 if (op->type == PLAYER) 00324 map_newmap_cmd(&op->contr->socket); 00325 } 00326 00333 void set_map_timeout(mapstruct *oldmap) { 00334 #if MAP_MAXTIMEOUT 00335 oldmap->timeout = MAP_TIMEOUT(oldmap); 00336 /* Do MINTIMEOUT first, so that MAXTIMEOUT is used if that is 00337 * lower than the min value. 00338 */ 00339 #if MAP_MINTIMEOUT 00340 if (oldmap->timeout < MAP_MINTIMEOUT) { 00341 oldmap->timeout = MAP_MINTIMEOUT; 00342 } 00343 #endif 00344 if (oldmap->timeout > MAP_MAXTIMEOUT) { 00345 oldmap->timeout = MAP_MAXTIMEOUT; 00346 } 00347 #else 00348 /* save out the map */ 00349 swap_map(oldmap); 00350 #endif /* MAP_MAXTIMEOUT */ 00351 } 00352 00366 static char *clean_path(const char *file, char *newpath, int size) { 00367 char *cp; 00368 00369 snprintf(newpath, size, "%s", file); 00370 for (cp = newpath; *cp != '\0'; cp++) { 00371 if (*cp == '/') 00372 *cp = '_'; 00373 } 00374 return newpath; 00375 } 00376 00394 static char *unclean_path(const char *src, char *newpath, int size) { 00395 char *cp; 00396 00397 cp = strrchr(src, '/'); 00398 if (cp) 00399 snprintf(newpath, size, "%s", cp+1); 00400 else 00401 snprintf(newpath, size, "%s", src); 00402 00403 for (cp = newpath; *cp != '\0'; cp++) { 00404 if (*cp == '_') 00405 *cp = '/'; 00406 } 00407 return newpath; 00408 } 00409 00410 00420 static void enter_random_map(object *pl, object *exit_ob) { 00421 mapstruct *new_map; 00422 char newmap_name[HUGE_BUF], *cp; 00423 static int reference_number = 0; 00424 RMParms rp; 00425 00426 memset(&rp, 0, sizeof(RMParms)); 00427 rp.Xsize = -1; 00428 rp.Ysize = -1; 00429 rp.region = get_region_by_map(exit_ob->map); 00430 if (exit_ob->msg) 00431 set_random_map_variable(&rp, exit_ob->msg); 00432 rp.origin_x = exit_ob->x; 00433 rp.origin_y = exit_ob->y; 00434 strcpy(rp.origin_map, pl->map->path); 00435 00436 /* If we have a final_map, use it as a base name to give some clue 00437 * as where the player is. Otherwise, use the origin map. 00438 * Take the last component (after the last slash) to give 00439 * shorter names without bogus slashes. 00440 */ 00441 if (rp.final_map[0]) { 00442 cp = strrchr(rp.final_map, '/'); 00443 if (!cp) 00444 cp = rp.final_map; 00445 } else { 00446 char buf[HUGE_BUF]; 00447 00448 cp = strrchr(rp.origin_map, '/'); 00449 if (!cp) 00450 cp = rp.origin_map; 00451 /* Need to strip of any trailing digits, if it has them */ 00452 snprintf(buf, sizeof(buf), "%s", cp); 00453 while (isdigit(buf[strlen(buf)-1])) 00454 buf[strlen(buf)-1] = 0; 00455 cp = buf; 00456 } 00457 00458 snprintf(newmap_name, sizeof(newmap_name), "/random/%s%04d", cp+1, reference_number++); 00459 00460 /* now to generate the actual map. */ 00461 new_map = generate_random_map(newmap_name, &rp, NULL); 00462 00463 /* Update the exit_ob so it now points directly at the newly created 00464 * random maps. Not that it is likely to happen, but it does mean that a 00465 * exit in a unique map leading to a random map will not work properly. 00466 * It also means that if the created random map gets reset before 00467 * the exit leading to it, that the exit will no longer work. 00468 */ 00469 if (new_map) { 00470 int x, y; 00471 00472 x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map); 00473 y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map); 00474 EXIT_PATH(exit_ob) = add_string(newmap_name); 00475 snprintf(new_map->path, sizeof(new_map->path), "%s", newmap_name); 00476 enter_map(pl, new_map, x, y); 00477 } 00478 } 00479 00489 static void enter_fixed_template_map(object *pl, object *exit_ob) { 00490 mapstruct *new_map; 00491 char tmpnum[32], exitpath[HUGE_BUF], resultname[HUGE_BUF], tmpstring[HUGE_BUF], *sourcemap; 00492 char new_map_name[MAX_BUF]; 00493 00494 /* Split the exit path string into two parts, one 00495 * for where to store the map, and one for were 00496 * to generate the map from. 00497 */ 00498 snprintf(exitpath, sizeof(exitpath), "%s", EXIT_PATH(exit_ob)+2); 00499 sourcemap = strchr(exitpath, '!'); 00500 if (!sourcemap) { 00501 draw_ext_info_format(NDI_UNIQUE, 0, pl, 00502 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, 00503 "The %s is closed.", 00504 "The %s is closed.", 00505 exit_ob->name); 00506 /* Should only occur when no source map is set. 00507 */ 00508 LOG(llevError, "enter_fixed_template_map: Exit %s (%d,%d) on map %s has no source template.\n", exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map->path); 00509 return; 00510 } 00511 *sourcemap++ = '\0'; 00512 00513 /* If we are not coming from a template map, we can use relative directories 00514 * for the map to generate from. 00515 */ 00516 if (!exit_ob->map->is_template) { 00517 /* We can't use exitpath directly, as sourcemap points there. */ 00518 path_combine_and_normalize(exit_ob->map->path, sourcemap, tmpstring, sizeof(tmpstring)); 00519 snprintf(exitpath, sizeof(exitpath), "%s", tmpstring); 00520 sourcemap = exitpath; 00521 } 00522 00523 /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord 00524 * of the exit, and the name of the map the exit is on, respectively. 00525 */ 00526 snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->x); 00527 replace(exitpath, "%x", tmpnum, resultname, sizeof(resultname)); 00528 00529 snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->y); 00530 snprintf(tmpstring, sizeof(tmpstring), "%s", resultname); 00531 replace(tmpstring, "%y", tmpnum, resultname, sizeof(resultname)); 00532 00533 snprintf(tmpstring, sizeof(tmpstring), "%s", resultname); 00534 replace(tmpstring, "%n", exit_ob->map->name, resultname, sizeof(resultname)); 00535 00536 /* If we are coming from another template map, use reletive paths unless 00537 * indicated otherwise. 00538 */ 00539 if (exit_ob->map->is_template && (resultname[0] != '/')) { 00540 path_combine_and_normalize(exit_ob->map->path, resultname, new_map_name, sizeof(new_map_name)); 00541 } else { 00542 create_template_pathname(resultname, new_map_name, sizeof(new_map_name)); 00543 } 00544 00545 /* Attempt to load the map, if unable to, then 00546 * create the map from the template. 00547 */ 00548 new_map = ready_map_name(new_map_name, MAP_PLAYER_UNIQUE); 00549 if (!new_map) { 00550 char path[MAX_BUF]; 00551 00552 create_pathname(sourcemap, path, MAX_BUF); 00553 new_map = load_original_map(path, MAP_PLAYER_UNIQUE); 00554 if (new_map) 00555 fix_auto_apply(new_map); 00556 } 00557 00558 if (new_map) { 00559 /* set the path of the map to where it should be 00560 * so we don't just save over the source map. 00561 */ 00562 snprintf(new_map->path, sizeof(new_map->path), "%s", new_map_name); 00563 new_map->is_template = 1; 00564 enter_map(pl, new_map, EXIT_X(exit_ob), EXIT_Y(exit_ob)); 00565 } else { 00566 draw_ext_info_format(NDI_UNIQUE, 0, pl, 00567 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, 00568 "The %s is closed.", 00569 "The %s is closed.", 00570 exit_ob->name); 00571 /* Should only occur when an invalid source map is set. 00572 */ 00573 LOG(llevDebug, "enter_fixed_template_map: Exit %s (%d,%d) on map %s leads no where.\n", exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map->path); 00574 } 00575 } 00576 00586 static void enter_random_template_map(object *pl, object *exit_ob) { 00587 mapstruct *new_map; 00588 char tmpnum[32], resultname[HUGE_BUF], tmpstring[HUGE_BUF]; 00589 char new_map_name[MAX_BUF]; 00590 RMParms rp; 00591 00592 /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord 00593 * of the exit, and the name of the map the exit is on, respectively. 00594 */ 00595 snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->x); 00596 replace(EXIT_PATH(exit_ob)+3, "%x", tmpnum, resultname, sizeof(resultname)); 00597 00598 snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->y); 00599 snprintf(tmpstring, sizeof(tmpstring), "%s", resultname); 00600 replace(tmpstring, "%y", tmpnum, resultname, sizeof(resultname)); 00601 00602 snprintf(tmpstring, sizeof(tmpstring), "%s", resultname); 00603 replace(tmpstring, "%n", exit_ob->map->name, resultname, sizeof(resultname)); 00604 00605 /* If we are coming from another template map, use reletive paths unless 00606 * indicated otherwise. 00607 */ 00608 if (exit_ob->map->is_template && (resultname[0] != '/')) { 00609 path_combine_and_normalize(exit_ob->map->path, resultname, new_map_name, sizeof(new_map_name)); 00610 } else { 00611 create_template_pathname(resultname, new_map_name, sizeof(new_map_name)); 00612 } 00613 00614 new_map = ready_map_name(new_map_name, MAP_PLAYER_UNIQUE); 00615 if (!new_map) { 00616 memset(&rp, 0, sizeof(RMParms)); 00617 rp.Xsize = -1; 00618 rp.Ysize = -1; 00619 rp.region = get_region_by_map(exit_ob->map); 00620 if (exit_ob->msg) 00621 set_random_map_variable(&rp, exit_ob->msg); 00622 rp.origin_x = exit_ob->x; 00623 rp.origin_y = exit_ob->y; 00624 strcpy(rp.origin_map, pl->map->path); 00625 00626 /* now to generate the actual map. */ 00627 new_map = generate_random_map(new_map_name, &rp, NULL); 00628 } 00629 00630 /* Update the exit_ob so it now points directly at the newly created 00631 * random maps. Not that it is likely to happen, but it does mean that a 00632 * exit in a unique map leading to a random map will not work properly. 00633 * It also means that if the created random map gets reset before 00634 * the exit leading to it, that the exit will no longer work. 00635 */ 00636 if (new_map) { 00637 int x, y; 00638 00639 x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map); 00640 y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map); 00641 new_map->is_template = 1; 00642 enter_map(pl, new_map, x, y); 00643 } 00644 } 00645 00654 static void enter_unique_map(object *op, object *exit_ob) { 00655 char apartment[HUGE_BUF], path[MAX_BUF]; 00656 mapstruct *newmap; 00657 00658 if (EXIT_PATH(exit_ob)[0] == '/') { 00659 snprintf(apartment, sizeof(apartment), "%s/%s/%s/%s", settings.localdir, settings.playerdir, op->name, clean_path(EXIT_PATH(exit_ob), path, sizeof(path))); 00660 newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE); 00661 if (!newmap) { 00662 create_pathname(EXIT_PATH(exit_ob), path, sizeof(path)); 00663 newmap = load_original_map(path, MAP_PLAYER_UNIQUE); 00664 if (newmap) 00665 fix_auto_apply(newmap); 00666 } 00667 } else { /* relative directory */ 00668 char reldir[HUGE_BUF], tmpc[HUGE_BUF], *cp; 00669 00670 if (exit_ob->map->unique) { 00671 00672 unclean_path(exit_ob->map->path, reldir, sizeof(reldir)); 00673 00674 /* Need to copy this over, as clean_path only has one static return buffer */ 00675 clean_path(reldir, tmpc, sizeof(tmpc)); 00676 /* Remove final component, if any */ 00677 if ((cp = strrchr(tmpc, '_')) != NULL) 00678 *cp = 0; 00679 00680 snprintf(apartment, sizeof(apartment), "%s/%s/%s/%s_%s", settings.localdir, settings.playerdir, op->name, tmpc, clean_path(EXIT_PATH(exit_ob), path, sizeof(path))); 00681 00682 newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE); 00683 if (!newmap) { 00684 create_pathname(path_combine_and_normalize(reldir, EXIT_PATH(exit_ob), tmpc, sizeof(tmpc)), path, sizeof(path)); 00685 newmap = load_original_map(path, MAP_PLAYER_UNIQUE); 00686 if (newmap) 00687 fix_auto_apply(newmap); 00688 } 00689 } else { 00690 /* The exit is unique, but the map we are coming from is not unique. So 00691 * use the basic logic - don't need to demangle the path name 00692 */ 00693 path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), reldir, sizeof(reldir)); 00694 snprintf(apartment, sizeof(apartment), "%s/%s/%s/%s", settings.localdir, settings.playerdir, op->name, clean_path(reldir, path, sizeof(path))); 00695 newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE); 00696 if (!newmap) { 00697 path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), reldir, sizeof(reldir)); 00698 newmap = ready_map_name(reldir, 0); 00699 if (newmap) 00700 fix_auto_apply(newmap); 00701 } 00702 } 00703 } 00704 00705 if (newmap) { 00706 snprintf(newmap->path, sizeof(newmap->path), "%s", apartment); 00707 newmap->unique = 1; 00708 enter_map(op, newmap, EXIT_X(exit_ob), EXIT_Y(exit_ob)); 00709 } else { 00710 draw_ext_info_format(NDI_UNIQUE, 0, op, 00711 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, 00712 "The %s is closed.", 00713 "The %s is closed.", 00714 exit_ob->name); 00715 /* Perhaps not critical, but I would think that the unique maps 00716 * should be new enough this does not happen. This also creates 00717 * a strange situation where some players could perhaps have visited 00718 * such a map before it was removed, so they have the private 00719 * map, but other players can't get it anymore. 00720 */ 00721 LOG(llevDebug, "enter_unique_map: Exit %s (%d,%d) on map %s is leads no where.\n", exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map->path); 00722 } 00723 00724 } 00725 00740 void enter_exit(object *op, object *exit_ob) { 00741 #define PORTAL_DESTINATION_NAME "Town portal destination" /* this one should really be in a header file */ 00742 object *tmp; 00743 /* It may be nice to support other creatures moving across 00744 * exits, but right now a lot of the code looks at op->contr, 00745 * so thta is an RFE. 00746 */ 00747 if (op->type != PLAYER) 00748 return; 00749 00750 /* Need to remove player from transport */ 00751 if (op->contr->transport) 00752 ob_apply(op->contr->transport, op, AP_UNAPPLY); 00753 00754 /* First, lets figure out what map the player is going to go to */ 00755 if (exit_ob) { 00756 /* check to see if we make a template map */ 00757 if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '@') { 00758 if (EXIT_PATH(exit_ob)[2] == '!') { 00759 /* generate a template map randomly */ 00760 enter_random_template_map(op, exit_ob); 00761 } else { 00762 /* generate a template map from a fixed template */ 00763 enter_fixed_template_map(op, exit_ob); 00764 } 00765 } 00766 /* check to see if we make a randomly generated map */ 00767 else if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '!') { 00768 enter_random_map(op, exit_ob); 00769 } else if (QUERY_FLAG(exit_ob, FLAG_UNIQUE)) { 00770 enter_unique_map(op, exit_ob); 00771 } else { 00772 int x = EXIT_X(exit_ob), y = EXIT_Y(exit_ob); 00773 /* 'Normal' exits that do not do anything special 00774 * Simple enough we don't need another routine for it. 00775 */ 00776 mapstruct *newmap; 00777 if (exit_ob->map) { 00778 char tmp_path[HUGE_BUF]; 00779 00780 path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), tmp_path, sizeof(tmp_path)); 00781 newmap = ready_map_name(tmp_path, 0); 00782 /* Random map was previously generated, but is no longer about. Lets generate a new 00783 * map. 00784 */ 00785 if (!newmap && !strncmp(EXIT_PATH(exit_ob), "/random/", 8)) { 00786 /* Maps that go down have a message set. However, maps that go 00787 * up, don't. If the going home has reset, there isn't much 00788 * point generating a random map, because it won't match the maps. 00789 */ 00790 if (exit_ob->msg) { 00791 enter_random_map(op, exit_ob); 00792 } else { 00793 draw_ext_info_format(NDI_UNIQUE, 0, op, 00794 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, 00795 "The %s is closed.", 00796 "The %s is closed.", 00797 exit_ob->name); 00798 return; 00799 } 00800 00801 /* For exits that cause damages (like pits). Don't know if any 00802 * random maps use this or not. 00803 */ 00804 if (exit_ob->stats.dam && op->type == PLAYER) 00805 hit_player(op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1); 00806 return; 00807 } 00808 } else { 00809 /* For word of recall and other force objects 00810 * They contain the full pathname of the map to go back to, 00811 * so we don't need to normalize it. 00812 * But we do need to see if it is unique or not 00813 */ 00814 if (!strncmp(EXIT_PATH(exit_ob), settings.localdir, strlen(settings.localdir))) 00815 newmap = ready_map_name(EXIT_PATH(exit_ob), MAP_PLAYER_UNIQUE); 00816 else 00817 newmap = ready_map_name(EXIT_PATH(exit_ob), 0); 00818 } 00819 if (!newmap) { 00820 if (exit_ob->name) 00821 draw_ext_info_format(NDI_UNIQUE, 0, op, 00822 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, 00823 "The %s is closed.", 00824 "The %s is closed.", 00825 exit_ob->name); 00826 /* don't cry to momma if name is not set - as in tmp objects 00827 * used by the savebed code and character creation */ 00828 return; 00829 } 00830 00831 /* This supports the old behaviour, but it really should not be used. 00832 * I will note for example that with this method, it is impossible to 00833 * set 0,0 destination coordinates. Really, if we want to support 00834 * using the new maps default coordinates, the exit ob should use 00835 * something like -1, -1 so it is clear to do that. 00836 */ 00837 if (x == 0 && y == 0) { 00838 x = MAP_ENTER_X(newmap); 00839 y = MAP_ENTER_Y(newmap); 00840 LOG(llevDebug, "enter_exit: Exit %s (%d,%d) on map %s is 0 destination coordinates\n", 00841 exit_ob->name ? exit_ob->name : "(none)", exit_ob->x, exit_ob->y, 00842 exit_ob->map ? exit_ob->map->path : "(none)"); 00843 } 00844 00845 /* mids 02/13/2002 if exit is damned, update players death & WoR home-position and delete town portal */ 00846 if (QUERY_FLAG(exit_ob, FLAG_DAMNED)) { 00847 /* remove an old force with a slaying field == PORTAL_DESTINATION_NAME */ 00848 for (tmp = op->inv; tmp != NULL; tmp = tmp->below) { 00849 if (tmp->type == FORCE && tmp->slaying && !strcmp(tmp->slaying, PORTAL_DESTINATION_NAME)) 00850 break; 00851 } 00852 if (tmp) { 00853 remove_ob(tmp); 00854 free_object(tmp); 00855 } 00856 00857 path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), op->contr->savebed_map, sizeof(op->contr->savebed_map)); 00858 op->contr->bed_x = EXIT_X(exit_ob), op->contr->bed_y = EXIT_Y(exit_ob); 00859 save_player(op, 1); 00860 /* LOG(llevDebug, "enter_exit: Taking damned exit %s to (%d,%d) on map %s\n", 00861 * exit_ob->name ? exit_ob->name : "(none)", exit_ob->x, exit_ob->y, 00862 * path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob))); */ 00863 } 00864 00865 enter_map(op, newmap, x, y); 00866 } 00867 /* For exits that cause damages (like pits) */ 00868 if (exit_ob->stats.dam && op->type == PLAYER) 00869 hit_player(op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1); 00870 } else { 00871 int flags = 0; 00872 mapstruct *newmap; 00873 00874 /* Hypothetically, I guess its possible that a standard map matches 00875 * the localdir, but that seems pretty unlikely - unlikely enough that 00876 * I'm not going to attempt to try to deal with that possibility. 00877 * We use the fact that when a player saves on a unique map, it prepends 00878 * the localdir to that name. So its an easy way to see of the map is 00879 * unique or not. 00880 */ 00881 if (!strncmp(op->contr->maplevel, settings.localdir, strlen(settings.localdir))) 00882 flags = MAP_PLAYER_UNIQUE; 00883 00884 /* newmap returns the map (if already loaded), or loads it for us. */ 00885 newmap = ready_map_name(op->contr->maplevel, flags); 00886 if (!newmap) { 00887 LOG(llevError, "enter_exit: Pathname to map does not exist! (%s)\n", op->contr->maplevel); 00888 newmap = ready_map_name(settings.emergency_mapname, 0); 00889 op->x = settings.emergency_x; 00890 op->y = settings.emergency_y; 00891 /* If we can't load the emergency map, something is probably really 00892 * screwed up, so bail out now. 00893 */ 00894 if (!newmap) { 00895 LOG(llevError, "enter_exit: could not load emergency map? Fatal error\n"); 00896 abort(); 00897 } 00898 } 00899 enter_map(op, newmap, op->x, op->y); 00900 } 00901 } 00902 00908 static void process_players1(void) { 00909 int flag; 00910 player *pl, *plnext; 00911 00912 /* Basically, we keep looping until all the players have done their actions. */ 00913 for (flag = 1; flag != 0; ) { 00914 flag = 0; 00915 for (pl = first_player; pl != NULL; pl = plnext) { 00916 plnext = pl->next; /* In case a player exits the game in handle_player() */ 00917 00918 if (pl->ob == NULL) 00919 continue; 00920 00922 if (pl->followed_player) { 00923 player *followed = find_player_partial_name(pl->followed_player); 00924 if (followed && followed->ob && followed->ob->map) { 00925 rv_vector rv; 00926 00927 get_rangevector(pl->ob, followed->ob, &rv, 0); 00928 if (rv.distance > 4) { 00929 int space = find_free_spot(pl->ob, followed->ob->map, followed->ob->x, followed->ob->y, 1, 25); 00930 if (space == -1) 00932 space = 0; 00933 remove_ob(pl->ob); 00934 insert_ob_in_map_at(pl->ob, followed->ob->map, NULL, 0, followed->ob->x+freearr_x[space], followed->ob->y+freearr_y[space]); 00935 map_newmap_cmd(&pl->socket); 00936 } 00937 } else { 00938 draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "Player %s left or ambiguous name.", NULL, pl->followed_player); 00939 FREE_AND_CLEAR_STR(pl->followed_player); 00940 } 00941 } 00943 if (pl->ob->speed_left > 0) { 00944 if (handle_newcs_player(pl->ob)) 00945 flag = 1; 00946 } /* end if player has speed left */ 00947 00948 /* If the player is not actively playing, don't make a 00949 * backup save - nothing to save anyway. Plus, the 00950 * map may not longer be valid. This can happen when the 00951 * player quits - they exist for purposes of tracking on the map, 00952 * but don't actually reside on any actual map. 00953 */ 00954 if (QUERY_FLAG(pl->ob, FLAG_REMOVED)) 00955 continue; 00956 00957 #ifdef AUTOSAVE 00958 /* check for ST_PLAYING state so that we don't try to save off when 00959 * the player is logging in. 00960 */ 00961 if ((pl->last_save_tick+AUTOSAVE) < pticks && pl->state == ST_PLAYING) { 00962 /* Don't save the player on unholy ground. Instead, increase the 00963 * tick time so it will be about 10 seconds before we try and save 00964 * again. 00965 */ 00966 if (get_map_flags(pl->ob->map, NULL, pl->ob->x, pl->ob->y, NULL, NULL)&P_NO_CLERIC) { 00967 pl->last_save_tick += 100; 00968 } else { 00969 save_player(pl->ob, 1); 00970 pl->last_save_tick = pticks; 00971 check_score(pl->ob, 1); 00972 } 00973 } 00974 #endif 00975 } /* end of for loop for all the players */ 00976 } /* for flag */ 00977 for(pl=first_player;pl!=NULL;pl=pl->next) { 00978 pl->socket.sounds_this_tick = 0; 00979 if (settings.casting_time == TRUE) { 00980 if (pl->ob->casting_time > 0){ 00981 pl->ob->casting_time--; 00982 } 00983 } 00984 do_some_living(pl->ob); 00985 /* draw(pl->ob);*/ /* updated in socket code */ 00986 } 00987 } 00988 00996 static void process_players2(void) { 00997 player *pl; 00998 00999 /* Then check if any players should use weapon-speed instead of speed */ 01000 for (pl=first_player;pl!=NULL;pl=pl->next) { 01001 01002 /* The code that did weapon_sp handling here was out of place - 01003 * this isn't called until after the player has finished there 01004 * actions, and is thus out of place. All we do here is bounds 01005 * checking. 01006 */ 01007 if (pl->has_hit) { 01008 if (pl->ob->speed_left > pl->weapon_sp) pl->ob->speed_left = pl->weapon_sp; 01009 01010 /* This needs to be here - if the player is running, we need to 01011 * clear this each tick, but new commands are not being received 01012 * so execute_newserver_command() is never called 01013 */ 01014 pl->has_hit=0; 01015 01016 } else if (pl->ob->speed_left > pl->ob->speed) 01017 pl->ob->speed_left = pl->ob->speed; 01018 } 01019 } 01020 01021 #define SPEED_DEBUG 01022 01026 void process_events(void) { 01027 object *op; 01028 object marker; 01029 tag_t tag; 01030 01031 process_players1(); 01032 01033 memset(&marker, 0, sizeof(object)); 01034 /* Put marker object at beginning of active list */ 01035 marker.active_next = active_objects; 01036 01037 if (marker.active_next) 01038 marker.active_next->active_prev = ▮ 01039 marker.active_prev = NULL; 01040 active_objects = ▮ 01041 01042 while (marker.active_next) { 01043 op = marker.active_next; 01044 tag = op->count; 01045 01046 /* Move marker forward - swap op and marker */ 01047 op->active_prev = marker.active_prev; 01048 01049 if (op->active_prev) 01050 op->active_prev->active_next = op; 01051 else 01052 active_objects = op; 01053 01054 marker.active_next = op->active_next; 01055 01056 if (marker.active_next) 01057 marker.active_next->active_prev = ▮ 01058 marker.active_prev = op; 01059 op->active_next = ▮ 01060 01061 /* Now process op */ 01062 if (QUERY_FLAG(op, FLAG_FREED)) { 01063 LOG(llevError, "BUG: process_events(): Free object on list\n"); 01064 op->speed = 0; 01065 update_ob_speed(op); 01066 continue; 01067 } 01068 01069 /* I've seen occasional crashes due to this - the object is removed, 01070 * and thus the map it points to (last map it was on) may be bogus 01071 * The real bug is to try to find out the cause of this - someone 01072 * is probably calling remove_ob without either an insert_ob or 01073 * free_object afterwards, leaving an object dangling. But I'd 01074 * rather log this and continue on instead of crashing. 01075 * Don't remove players - when a player quits, the object is in 01076 * sort of a limbo, of removed, but something we want to keep 01077 * around. 01078 */ 01079 if (QUERY_FLAG(op, FLAG_REMOVED) 01080 && op->type != PLAYER 01081 && op->map 01082 && op->map->in_memory != MAP_IN_MEMORY) { 01083 StringBuffer *sb; 01084 char *diff; 01085 01086 LOG(llevError, "BUG: process_events(): Removed object on list\n"); 01087 sb = stringbuffer_new(); 01088 dump_object(op, sb); 01089 diff = stringbuffer_finish(sb); 01090 LOG(llevError, "%s\n", diff); 01091 free(diff); 01092 free_object(op); 01093 continue; 01094 } 01095 01096 if (!op->speed) { 01097 LOG(llevError, "BUG: process_events(): Object %s has no speed, but is on active list\n", op->arch->name); 01098 update_ob_speed(op); 01099 continue; 01100 } 01101 01102 if (op->map == NULL 01103 && op->env == NULL 01104 && op->name 01105 && op->type != MAP) { 01106 LOG(llevError, "BUG: process_events(): Object without map or inventory is on active list: %s (%d)\n", op->name, op->count); 01107 op->speed = 0; 01108 update_ob_speed(op); 01109 continue; 01110 } 01111 01112 /* Seen some cases where process_object() is crashing because 01113 * the object is on a swapped out map. But can't be sure if 01114 * something in the chain of events caused the object to 01115 * change maps or was just never removed - this will 01116 * give some clue as to its state before call to 01117 * process_object 01118 */ 01119 if (op->map && op->map->in_memory != MAP_IN_MEMORY) { 01120 LOG(llevError, "BUG: process_events(): Processing object on swapped out map: %s (%d), map=%s\n", op->name, op->count, op->map->path); 01121 } 01122 01123 /* Animate the object. Bug of feature that andim_speed 01124 * is based on ticks, and not the creatures speed? 01125 */ 01126 if ((op->anim_speed && op->last_anim >= op->anim_speed) 01127 || (op->temp_animation_id && op->last_anim >= op->temp_anim_speed)) { 01128 op->state++; 01129 if ((op->type == PLAYER) || (op->type == MONSTER)) 01130 animate_object(op, op->facing); 01131 else 01132 animate_object(op, op->direction); 01133 op->last_anim = 1; 01134 } else { 01135 op->last_anim++; 01136 } 01137 01138 if (op->speed_left > 0) { 01139 --op->speed_left; 01140 process_object(op); 01141 if (was_destroyed(op, tag)) 01142 continue; 01143 } 01144 if (settings.casting_time == TRUE && op->casting_time > 0) 01145 op->casting_time--; 01146 if (op->speed_left <= 0) 01147 op->speed_left += FABS(op->speed); 01148 } 01149 01150 /* Remove marker object from active list */ 01151 if (marker.active_prev != NULL) 01152 marker.active_prev->active_next = NULL; 01153 else 01154 active_objects = NULL; 01155 01156 process_players2(); 01157 } 01158 01164 void clean_tmp_files(void) { 01165 mapstruct *m, *next; 01166 01167 LOG(llevInfo, "Cleaning up...\n"); 01168 01169 /* We save the maps - it may not be intuitive why, but if there are unique 01170 * items, we need to save the map so they get saved off. Perhaps we should 01171 * just make a special function that only saves the unique items. 01172 */ 01173 for (m = first_map; m != NULL; m = next) { 01174 next = m->next; 01175 if (m->in_memory == MAP_IN_MEMORY) { 01176 /* If we want to reuse the temp maps, swap it out (note that will also 01177 * update the log file. Otherwise, save the map (mostly for unique item 01178 * stuff). Note that the clean_tmp_map is called after the end of 01179 * the for loop but is in the #else bracket. IF we are recycling the maps, 01180 * we certainly don't want the temp maps removed. 01181 */ 01182 01183 /* XXX The above comment is dead wrong */ 01184 if (settings.recycle_tmp_maps == TRUE) 01185 swap_map(m); 01186 else { 01187 save_map(m, SAVE_MODE_NORMAL); /* note we save here into a overlay map */ 01188 clean_tmp_map(m); 01189 } 01190 } 01191 } 01192 write_todclock(); /* lets just write the clock here */ 01193 } 01194 01196 void cleanup(void) { 01197 LOG(llevDebug, "Cleanup called. freeing data.\n"); 01198 clean_tmp_files(); 01199 write_book_archive(); 01200 01201 #ifdef MEMORY_DEBUG 01202 free_all_maps(); 01203 free_style_maps(); 01204 #endif 01205 cleanupPlugins(); 01206 #ifdef MEMORY_DEBUG 01207 free_all_archs(); 01208 free_all_treasures(); 01209 free_all_images(); 01210 free_all_newserver(); 01211 free_all_recipes(); 01212 free_all_readable(); 01213 free_all_god(); 01214 free_all_anim(); 01215 free_loader(); 01216 free_globals(); 01217 free_server(); 01218 free_all_object_data(); 01219 /* See what the string data that is out there that hasn't been freed. */ 01220 /* LOG(llevDebug, "%s", ss_dump_table(0xff));*/ 01221 #endif 01222 exit(0); 01223 } 01224 01234 void leave(player *pl, int draw_exit) { 01235 01236 if (pl != NULL) { 01237 pl->socket.status = Ns_Dead; 01238 LOG(llevInfo, "LOGOUT: Player named %s from ip %s\n", pl->ob->name, pl->socket.host); 01239 01240 check_score(pl->ob, 1); 01241 01242 /* If this player is the captain of the transport, need to do 01243 * some extra work. By the time we get here, remove_ob() 01244 * should have already been called. 01245 */ 01246 if (pl->transport && pl->transport->contr == pl) { 01247 /* If inv is a non player, inv->contr will be NULL, but that 01248 * is OK. 01249 */ 01250 if (pl->transport->inv) 01251 pl->transport->contr = pl->transport->inv->contr; 01252 else 01253 pl->transport->contr = NULL; 01254 01255 if (pl->transport->contr) { 01256 char name[MAX_BUF]; 01257 01258 query_name(pl->transport, name, MAX_BUF); 01259 draw_ext_info_format(NDI_UNIQUE, 0, pl->transport->contr->ob, 01260 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_PLAYER, 01261 "%s has left. You are now the captain of %s", 01262 "%s has left. You are now the captain of %s", 01263 pl->ob->name, name); 01264 } 01265 } 01266 01267 if (pl->ob->map) { 01268 if (pl->ob->map->in_memory == MAP_IN_MEMORY) 01269 pl->ob->map->timeout = MAP_TIMEOUT(pl->ob->map); 01270 /* we need to update player count, since remove_ob() isn't called */ 01271 if (!pl->hidden) 01272 pl->ob->map->players--; 01273 pl->ob->map = NULL; 01274 } 01275 pl->ob->type = DEAD_OBJECT; /* To avoid problems with inventory window */ 01276 } 01277 /* If a hidden dm dropped connection do not create 01278 * inconsistencies by showing that they have left the game 01279 */ 01280 if (!(QUERY_FLAG(pl->ob, FLAG_WIZ) && pl->ob->contr->hidden) 01281 && (pl != NULL && draw_exit) && (pl->state != ST_GET_NAME && pl->state != ST_GET_PASSWORD && pl->state != ST_CONFIRM_PASSWORD)) 01282 draw_ext_info_format(NDI_UNIQUE|NDI_ALL|NDI_DK_ORANGE, 5, NULL, 01283 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_PLAYER, 01284 "%s left the game.", 01285 "%s left the game.", 01286 pl->ob->name); 01287 } 01288 01296 int forbid_play(void) { 01297 #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE) 01298 char buf[MAX_BUF], day[MAX_BUF]; 01299 FILE *fp; 01300 time_t clock; 01301 struct tm *tm; 01302 int i, start, stop, forbit = 0, comp; 01303 01304 clock = time(NULL); 01305 tm = (struct tm *)localtime(&clock); 01306 01307 snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, PERM_FILE); 01308 if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL) 01309 return 0; 01310 01311 while (fgets(buf, sizeof(buf), fp)) { 01312 if (buf[0] == '#') 01313 continue; 01314 if (!strncmp(buf, "msg", 3)) { 01315 if (forbit) 01316 while (fgets(buf, sizeof(buf), fp)) /* print message */ 01317 fputs(buf, logfile); 01318 break; 01319 } else if (sscanf(buf, "%s %d%*c%d\n", day, &start, &stop) != 3) { 01320 LOG(llevDebug, "Warning: Incomplete line in permission file ignored.\n"); 01321 continue; 01322 } 01323 01324 for (i = 0; i < 7; i++) { 01325 if (!strncmp(buf, days[i], 3) 01326 && (tm->tm_wday == i) 01327 && (tm->tm_hour >= start) 01328 && (tm->tm_hour < stop)) 01329 forbit = 1; 01330 } 01331 } 01332 01333 close_and_delete(fp, comp); 01334 01335 return forbit; 01336 #else 01337 return 0; 01338 #endif 01339 } 01340 01341 extern unsigned long todtick; 01342 01357 static void do_specials(void) { 01358 01359 #ifdef WATCHDOG 01360 if (!(pticks%503)) 01361 watchdog(); 01362 #endif 01363 01364 if (!(pticks%PTICKS_PER_CLOCK)) 01365 tick_the_clock(); 01366 01367 if (!(pticks%509)) 01368 flush_old_maps(); /* Clears the tmp-files of maps which have reset */ 01369 01370 if (!(pticks%2503)) 01371 fix_weight(); /* Hack to fix weightproblems caused by bugs */ 01372 01373 if (!(pticks%2521)) 01374 metaserver_update(); /* 2500 ticks is about 5 minutes */ 01375 01376 if (!(pticks%5003)) 01377 write_book_archive(); 01378 01379 if (!(pticks%5009)) 01380 clean_friendly_list(); 01381 01382 if (!(pticks%5011)) 01383 obsolete_parties(); 01384 01385 if (!(pticks%12503)) 01386 fix_luck(); 01387 } 01388 01399 int server_main(int argc, char **argv) { 01400 #ifdef WIN32 /* ---win32 this sets the win32 from 0d0a to 0a handling */ 01401 _fmode = _O_BINARY; 01402 bRunning = 1; 01403 #endif 01404 01405 #ifndef WIN32 01406 /* Here we check that we aren't root or suid */ 01407 if (getuid() == 0 || geteuid() == 0) { 01408 fputs("Don't run crossfire as root, it is unsupported.\n", stderr); 01409 fputs("Instead run it as a normal unprivileged user.\n", stderr); 01410 fputs("Aborting...\n", stderr); 01411 return 1; 01412 } 01413 #endif 01414 01415 #ifdef DEBUG_MALLOC_LEVEL 01416 malloc_debug(DEBUG_MALLOC_LEVEL); 01417 #endif 01418 01419 settings.argc = argc; 01420 settings.argv = argv; 01421 init(argc, argv); 01422 initPlugins(); /* GROS - Init the Plugins */ 01423 #ifdef WIN32 01424 while (bRunning) { 01425 #else 01426 for (;;) { 01427 #endif 01428 nroferrors = 0; 01429 01430 do_server(); 01431 process_events(); /* "do" something with objects with speed */ 01432 cftimer_process_timers(); /* Process the crossfire Timers */ 01433 /* Lauwenmark : Here we handle the CLOCK global event */ 01434 execute_global_event(EVENT_CLOCK); 01435 check_active_maps(); /* Removes unused maps after a certain timeout */ 01436 do_specials(); /* Routines called from time to time. */ 01437 01438 sleep_delta(); /* Sleep proper amount of time before next tick */ 01439 } 01440 emergency_save(0); 01441 cleanup(); 01442 return 0; 01443 }