00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
00186
00187
00188
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
00230 if (ob_blocked(op, newmap, x, y)) {
00231
00232
00233
00234
00235
00236
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
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 }
00252
00253
00254
00255
00256 if (!QUERY_FLAG(op, FLAG_REMOVED))
00257 remove_ob(op);
00258 if (op->map != NULL) {
00259
00260 execute_global_event(EVENT_MAPLEAVE, op, op->map);
00261 }
00262
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
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
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
00307
00308
00309 remove_all_pets();
00310
00311
00312
00313
00314
00315 if (oldmap != newmap) {
00316 if (oldmap) {
00317 if (oldmap->players <= 0)
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
00337
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
00349 swap_map(oldmap);
00350 #endif
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
00437
00438
00439
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
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
00461 new_map = generate_random_map(newmap_name, &rp, NULL);
00462
00463
00464
00465
00466
00467
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
00495
00496
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
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
00514
00515
00516 if (!exit_ob->map->is_template) {
00517
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
00524
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
00537
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
00546
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
00560
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
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
00593
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
00606
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
00627 new_map = generate_random_map(new_map_name, &rp, NULL);
00628 }
00629
00630
00631
00632
00633
00634
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 {
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
00675 clean_path(reldir, tmpc, sizeof(tmpc));
00676
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
00691
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
00716
00717
00718
00719
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"
00742 object *tmp;
00743
00744
00745
00746
00747 if (op->type != PLAYER)
00748 return;
00749
00750
00751 if (op->contr->transport)
00752 ob_apply(op->contr->transport, op, AP_UNAPPLY);
00753
00754
00755 if (exit_ob) {
00756
00757 if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '@') {
00758 if (EXIT_PATH(exit_ob)[2] == '!') {
00759
00760 enter_random_template_map(op, exit_ob);
00761 } else {
00762
00763 enter_fixed_template_map(op, exit_ob);
00764 }
00765 }
00766
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
00774
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
00783
00784
00785 if (!newmap && !strncmp(EXIT_PATH(exit_ob), "/random/", 8)) {
00786
00787
00788
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
00802
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
00810
00811
00812
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
00827
00828 return;
00829 }
00830
00831
00832
00833
00834
00835
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
00846 if (QUERY_FLAG(exit_ob, FLAG_DAMNED)) {
00847
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
00861
00862
00863 }
00864
00865 enter_map(op, newmap, x, y);
00866 }
00867
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
00875
00876
00877
00878
00879
00880
00881 if (!strncmp(op->contr->maplevel, settings.localdir, strlen(settings.localdir)))
00882 flags = MAP_PLAYER_UNIQUE;
00883
00884
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
00892
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
00913 for (flag = 1; flag != 0; ) {
00914 flag = 0;
00915 for (pl = first_player; pl != NULL; pl = plnext) {
00916 plnext = pl->next;
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 }
00947
00948
00949
00950
00951
00952
00953
00954 if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
00955 continue;
00956
00957 #ifdef AUTOSAVE
00958
00959
00960
00961 if ((pl->last_save_tick+AUTOSAVE) < pticks && pl->state == ST_PLAYING) {
00962
00963
00964
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 }
00976 }
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
00986 }
00987 }
00988
00996 static void process_players2(void) {
00997 player *pl;
00998
00999
01000 for (pl=first_player;pl!=NULL;pl=pl->next) {
01001
01002
01003
01004
01005
01006
01007 if (pl->has_hit) {
01008 if (pl->ob->speed_left > pl->weapon_sp) pl->ob->speed_left = pl->weapon_sp;
01009
01010
01011
01012
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
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
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
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
01070
01071
01072
01073
01074
01075
01076
01077
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
01113
01114
01115
01116
01117
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
01124
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
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
01170
01171
01172
01173 for (m = first_map; m != NULL; m = next) {
01174 next = m->next;
01175 if (m->in_memory == MAP_IN_MEMORY) {
01176
01177
01178
01179
01180
01181
01182
01183
01184 if (settings.recycle_tmp_maps == TRUE)
01185 swap_map(m);
01186 else {
01187 save_map(m, SAVE_MODE_NORMAL);
01188 clean_tmp_map(m);
01189 }
01190 }
01191 }
01192 write_todclock();
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
01220
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
01243
01244
01245
01246 if (pl->transport && pl->transport->contr == pl) {
01247
01248
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
01271 if (!pl->hidden)
01272 pl->ob->map->players--;
01273 pl->ob->map = NULL;
01274 }
01275 pl->ob->type = DEAD_OBJECT;
01276 }
01277
01278
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))
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();
01369
01370 if (!(pticks%2503))
01371 fix_weight();
01372
01373 if (!(pticks%2521))
01374 metaserver_update();
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
01401 _fmode = _O_BINARY;
01402 bRunning = 1;
01403 #endif
01404
01405 #ifndef WIN32
01406
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();
01423 #ifdef WIN32
01424 while (bRunning) {
01425 #else
01426 for (;;) {
01427 #endif
01428 nroferrors = 0;
01429
01430 do_server();
01431 process_events();
01432 cftimer_process_timers();
01433
01434 execute_global_event(EVENT_CLOCK);
01435 check_active_maps();
01436 do_specials();
01437
01438 sleep_delta();
01439 }
01440 emergency_save(0);
01441 cleanup();
01442 return 0;
01443 }