Atrinik Server 2.5
server/main.c
Go to the documentation of this file.
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 <check_proto.h>
00032 
00033 #ifdef HAVE_CRYPT_H
00034 #       include <crypt.h>
00035 #endif
00036 
00037 #ifdef MEMPOOL_OBJECT_TRACKING
00038 extern void check_use_object_list();
00039 #endif
00040 
00042 static object marker;
00044 static const char *const branch_paths[] =
00045 {
00046     ".", ".."
00047 };
00049 static uint32 branch_revision = 0;
00050 
00051 static char *unclean_path(const char *src);
00052 static void process_players1();
00053 static void process_players2();
00054 static void dequeue_path_requests();
00055 static void do_specials();
00056 
00061 void fatal(int err)
00062 {
00063     LOG(llevSystem, "Fatal: Shutdown server. Reason: %s\n", err == llevError ? "Fatal Error" : "BUG flood");
00064 
00065     if (init_done)
00066     {
00067         emergency_save(0);
00068         cleanup();
00069     }
00070 
00071     abort();
00072     LOG(llevSystem, "Exiting...\n");
00073     exit(-1);
00074 }
00075 
00080 void version(object *op)
00081 {
00082     if (op)
00083     {
00084         if (branch_revision)
00085         {
00086             new_draw_info_format(0, COLOR_WHITE, op, "This is Atrinik v%s (r%d)", VERSION, branch_revision);
00087         }
00088         else
00089         {
00090             new_draw_info_format(0, COLOR_WHITE, op, "This is Atrinik v%s", VERSION);
00091         }
00092     }
00093     else
00094     {
00095         LOG(llevInfo, "This is Atrinik v%s.\n", VERSION);
00096     }
00097 }
00098 
00104 char *crypt_string(char *str, char *salt)
00105 {
00106 #ifdef HAVE_CRYPT
00107     static const char *const c = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
00108     char s[2];
00109 
00110     if (salt == NULL)
00111     {
00112         size_t stringlen = strlen(c);
00113 
00114         s[0] = c[rndm(1, stringlen) - 1];
00115         s[1] = c[rndm(1, stringlen) - 1];
00116     }
00117     else
00118     {
00119         s[0] = salt[0];
00120         s[1] = salt[1];
00121     }
00122 
00123     return crypt(str, s);
00124 #else
00125     return str;
00126 #endif
00127 }
00128 
00135 int check_password(char *typed, char *crypted)
00136 {
00137     return !strcmp(crypt_string(typed, crypted), crypted);
00138 }
00139 
00146 void enter_player_savebed(object *op)
00147 {
00148     mapstruct *oldmap = op->map;
00149     object *tmp = get_object();
00150 
00151     FREE_AND_COPY_HASH(EXIT_PATH(tmp), CONTR(op)->savebed_map);
00152     EXIT_X(tmp) = CONTR(op)->bed_x;
00153     EXIT_Y(tmp) = CONTR(op)->bed_y;
00154     enter_exit(op, tmp);
00155 
00156     /* If the player has not changed maps and the name does not match
00157      * that of the savebed, his savebed map is gone.  Lets go back
00158      * to the emergency path.  Update what the players savebed is
00159      * while we're at it. */
00160     if (oldmap == op->map && strcmp(CONTR(op)->savebed_map, oldmap->path))
00161     {
00162         LOG(llevDebug, "Player %s savebed location %s is invalid - going to EMERGENCY_MAPPATH (%s)\n", query_name(op, NULL), CONTR(op)->savebed_map, EMERGENCY_MAPPATH);
00163         strcpy(CONTR(op)->savebed_map, EMERGENCY_MAPPATH);
00164         CONTR(op)->bed_x = EMERGENCY_X;
00165         CONTR(op)->bed_y = EMERGENCY_Y;
00166         FREE_AND_COPY_HASH(EXIT_PATH(tmp), CONTR(op)->savebed_map);
00167         EXIT_X(tmp) = CONTR(op)->bed_x;
00168         EXIT_Y(tmp) = CONTR(op)->bed_y;
00169         enter_exit(op, tmp);
00170     }
00171 }
00172 
00177 void leave_map(object *op)
00178 {
00179     mapstruct *oldmap = op->map;
00180 
00181     remove_ob(op);
00182     check_walk_off(op, NULL, MOVE_APPLY_VANISHED);
00183 
00184     if (oldmap && !oldmap->player_first)
00185     {
00186         set_map_timeout(oldmap);
00187     }
00188 }
00189 
00203 static void enter_map(object *op, mapstruct *newmap, int x, int y, int pos_flag)
00204 {
00205     int i = 0;
00206     object *tmp;
00207     mapstruct *oldmap = op->map;
00208 
00209     if (op->head)
00210     {
00211         op = op->head;
00212         LOG(llevBug, "enter_map(): called from tail of object! (obj:%s map: %s (%d,%d))\n", op->name, newmap->path, x, y);
00213     }
00214 
00215     /* this is a last secure check. In fact, newmap MUST legal and we only
00216      * check x and y. No get_map_from_coord() - we want check that x,y is part of this newmap.
00217      * if not, we have somewhere missed some checks - give a note to the log. */
00218     if (OUT_OF_REAL_MAP(newmap, x, y))
00219     {
00220         LOG(llevBug, "enter_map(): supplied coordinates are not within the map! (obj:%s map: %s (%d,%d))\n", op->name, newmap->path, x, y);
00221         x = MAP_ENTER_X(newmap);
00222         y = MAP_ENTER_Y(newmap);
00223     }
00224 
00225     /* try to find a spot for our object - (single arch or multi head)
00226      * but only when we don't put it on fix position  */
00227     if (!pos_flag && arch_blocked(op->arch, op, newmap, x, y))
00228     {
00229         /* First choice blocked */
00230         /* We try to find a spot for the player, starting closest in.
00231          * We could use find_first_free_spot, but that doesn't randomize it at all,
00232          * So for example, if the north space is free, you would always end up there even
00233          * if other spaces around are available.
00234          * Note that for the second and third calls, we could start at a position other
00235          * than one, but then we could end up on the other side of walls and so forth. */
00236         i = find_free_spot(op->arch, NULL, newmap, x, y, 1, SIZEOFFREE1 + 1);
00237 
00238         if (i == -1)
00239         {
00240             i = find_free_spot(op->arch, NULL, newmap, x, y, 1, SIZEOFFREE2 + 1);
00241 
00242             if (i == -1)
00243             {
00244                 i = find_free_spot(op->arch, NULL, newmap, x, y, 1, SIZEOFFREE + 1);
00245             }
00246         }
00247 
00248         if (i == -1)
00249         {
00250             i = 0;
00251         }
00252     }
00253 
00254     /* If it is a player login, he has yet to be inserted anyplace.
00255      * Otherwise, we need to deal with removing the player here. */
00256     if (!QUERY_FLAG(op, FLAG_REMOVED))
00257     {
00258         remove_ob(op);
00259 
00260         if (check_walk_off(op, NULL, MOVE_APPLY_DEFAULT) != CHECK_WALK_OK)
00261         {
00262             return;
00263         }
00264     }
00265 
00266     if (op->map && op->type == PLAYER && !op->head && op->map->events)
00267     {
00268         trigger_map_event(MEVENT_LEAVE, op->map, op, NULL, NULL, NULL, 0);
00269     }
00270 
00271     /* Set single or all part of a multi arch */
00272     for (tmp = op; tmp != NULL; tmp = tmp->more)
00273     {
00274         tmp->x = tmp->arch->clone.x + x + freearr_x[i];
00275         tmp->y = tmp->arch->clone.y + y + freearr_y[i];
00276     }
00277 
00278     if (!insert_ob_in_map(op, newmap, NULL, 0))
00279     {
00280         return;
00281     }
00282 
00283     if (newmap->events)
00284     {
00285         trigger_map_event(MEVENT_ENTER, newmap, op, NULL, NULL, NULL, 0);
00286     }
00287 
00288     newmap->timeout = 0;
00289 
00290     /* Do some action special for players after we have inserted them */
00291     if (op->type == PLAYER)
00292     {
00293         if (CONTR(op))
00294         {
00295             strcpy(CONTR(op)->maplevel, newmap->path);
00296             CONTR(op)->count = 0;
00297         }
00298 
00299         /* If the player is changing maps, we need to do some special things
00300          * Do this after the player is on the new map - otherwise the force swap of the
00301          * old map does not work. */
00302         if (oldmap != newmap && oldmap && !oldmap->player_first)
00303         {
00304             set_map_timeout(oldmap);
00305         }
00306 
00307         /* Attempt to open a closed door. */
00308         if (GET_MAP_FLAGS(op->map, op->x, op->y) & P_DOOR_CLOSED)
00309         {
00310             open_door(op, op->map, op->x, op->y, 1);
00311         }
00312     }
00313 }
00314 
00318 void set_map_timeout(mapstruct *map)
00319 {
00320 #if MAP_DEFAULTTIMEOUT
00321     uint32 swap_time = MAP_SWAP_TIME(map);
00322 
00323     if (swap_time == 0)
00324     {
00325         swap_time = MAP_DEFAULTTIMEOUT;
00326     }
00327 
00328     if (swap_time >= MAP_MAXTIMEOUT)
00329     {
00330         swap_time = MAP_MAXTIMEOUT;
00331     }
00332 
00333     map->timeout = swap_time;
00334 #else
00335     /* Save out the map. */
00336     swap_map(map, 0);
00337 #endif
00338 }
00339 
00346 char *clean_path(const char *file)
00347 {
00348     static char newpath[MAX_BUF], *cp;
00349 
00350     strncpy(newpath, file, MAX_BUF - 1);
00351     newpath[MAX_BUF - 1] = '\0';
00352 
00353     for (cp = newpath; *cp != '\0'; cp++)
00354     {
00355         if (*cp == '/')
00356         {
00357             *cp = '$';
00358         }
00359     }
00360 
00361     return newpath;
00362 }
00363 
00375 static char *unclean_path(const char *src)
00376 {
00377     static char newpath[MAX_BUF], *cp2;
00378     const char *cp;
00379 
00380     cp = strrchr(src, '/');
00381 
00382     if (cp)
00383     {
00384         strncpy(newpath, cp + 1, MAX_BUF - 1);
00385     }
00386     else
00387     {
00388         strncpy(newpath, src, MAX_BUF - 1);
00389     }
00390 
00391     newpath[MAX_BUF - 1] = '\0';
00392 
00393     for (cp2 = newpath; *cp2 != '\0'; cp2++)
00394     {
00395         if (*cp2 == '$')
00396         {
00397             *cp2 = '/';
00398         }
00399     }
00400 
00401     return newpath;
00402 }
00403 
00409 static void enter_random_map(object *pl, object *exit_ob)
00410 {
00411     mapstruct *new_map;
00412     char newmap_name[HUGE_BUF];
00413     static uint64 reference_number = 0;
00414     RMParms rp;
00415 
00416     memset(&rp, 0, sizeof(RMParms));
00417     rp.Xsize = -1;
00418     rp.Ysize = -1;
00419 
00420     if (exit_ob->msg)
00421     {
00422         set_random_map_variable(&rp, exit_ob->msg);
00423     }
00424 
00425     rp.origin_x = exit_ob->x;
00426     rp.origin_y = exit_ob->y;
00427     strcpy(rp.origin_map, pl->map->path);
00428 
00429     /* Pick a new pathname for the new map. Currently, we just use a
00430      * static variable and increment the counter one each time. */
00431     snprintf(newmap_name, sizeof(newmap_name), "/random/%" FMT64U, reference_number++);
00432 
00433     /* Now to generate the actual map. */
00434     new_map = generate_random_map(newmap_name, &rp);
00435 
00436     /* Update the exit_ob so it now points directly at the newly created
00437      * random map. */
00438     if (new_map)
00439     {
00440         int x, y;
00441 
00442         x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map);
00443         y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map);
00444         FREE_AND_COPY_HASH(EXIT_PATH(exit_ob), newmap_name);
00445         FREE_AND_COPY_HASH(new_map->path, newmap_name);
00446         enter_map(pl, new_map, x, y, QUERY_FLAG(exit_ob, FLAG_USE_FIX_POS));
00447     }
00448 }
00449 
00454 static void enter_unique_map(object *op, object *exit_ob)
00455 {
00456     char apartment[HUGE_BUF];
00457     mapstruct *newmap;
00458 
00459     /* Absolute path */
00460     if (EXIT_PATH(exit_ob)[0] == '/')
00461     {
00462         snprintf(apartment, sizeof(apartment), "%s/%s/%s/%s", settings.localdir, settings.playerdir, op->name, clean_path(EXIT_PATH(exit_ob)));
00463         newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
00464 
00465         if (!newmap)
00466         {
00467             newmap = load_original_map(create_pathname(EXIT_PATH(exit_ob)), MAP_PLAYER_UNIQUE);
00468         }
00469     }
00470     /* Relative path */
00471     else
00472     {
00473         char reldir[HUGE_BUF], tmpc[HUGE_BUF], tmp_path[HUGE_BUF], *cp;
00474 
00475         if (MAP_UNIQUE(exit_ob->map))
00476         {
00477             strncpy(reldir, unclean_path(exit_ob->map->path), sizeof(reldir) - 1);
00478 
00479             /* Need to copy this over, as clean_path only has one static return buffer */
00480             strncpy(tmpc, clean_path(reldir), sizeof(tmpc) - 1);
00481 
00482             /* Remove final component, if any */
00483             if ((cp = strrchr(tmpc, '$')) != NULL)
00484             {
00485                 *cp = 0;
00486             }
00487 
00488             snprintf(apartment, sizeof(apartment), "%s/%s/%s/%s_%s", settings.localdir, settings.playerdir, op->name, tmpc, clean_path(EXIT_PATH(exit_ob)));
00489             newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
00490 
00491             if (!newmap)
00492             {
00493                 newmap = load_original_map(create_pathname(normalize_path(reldir, EXIT_PATH(exit_ob), tmp_path)), MAP_PLAYER_UNIQUE);
00494             }
00495         }
00496         else
00497         {
00498             /* The exit is unique, but the map we are coming from is not unique. So
00499              * use the basic logic - don't need to demangle the path name */
00500             snprintf(apartment, sizeof(apartment), "%s/%s/%s/%s", settings.localdir, settings.playerdir, op->name, clean_path(normalize_path(exit_ob->map->path, EXIT_PATH(exit_ob), tmp_path)));
00501             newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
00502 
00503             if (!newmap)
00504             {
00505                 newmap = ready_map_name(normalize_path(exit_ob->map->path, EXIT_PATH(exit_ob), tmp_path), 0);
00506             }
00507         }
00508     }
00509 
00510     if (newmap)
00511     {
00512         FREE_AND_COPY_HASH(newmap->path, apartment);
00513         newmap->map_flags |= MAP_FLAG_UNIQUE;
00514 
00515         enter_map(op, newmap, EXIT_X(exit_ob), EXIT_Y(exit_ob), QUERY_FLAG(exit_ob, FLAG_USE_FIX_POS));
00516     }
00517     else
00518     {
00519         new_draw_info_format(0, COLOR_WHITE, op, "The %s is closed.", query_name(exit_ob, NULL));
00520 LOG(llevDebug, "enter_unique_map: Exit %s (%d,%d) on map %s leads no where.\n", query_name(exit_ob, NULL), exit_ob->x, exit_ob->y, exit_ob->map ? exit_ob->map->path ? exit_ob->map->path : "NO_PATH (script?)" : "NO_MAP (script?)");
00521     }
00522 }
00523 
00530 void enter_exit(object *op, object *exit_ob)
00531 {
00532     object *tmp;
00533 
00534     if (op->head)
00535     {
00536         op = op->head;
00537     }
00538 
00539     /* First, lets figure out what map we go */
00540     if (exit_ob)
00541     {
00542         /* check to see if we make a randomly generated map */
00543         if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '!')
00544         {
00545             if (op->type != PLAYER)
00546             {
00547                 return;
00548             }
00549 
00550             if (exit_ob->sub_type == ST1_EXIT_SOUND && exit_ob->map)
00551             {
00552                 play_sound_map(exit_ob->map, CMD_SOUND_EFFECT, "teleport.ogg", exit_ob->x, exit_ob->y, 0, 0);
00553             }
00554 
00555             enter_random_map(op, exit_ob);
00556         }
00557         else if (exit_ob->last_eat == MAP_PLAYER_MAP)
00558         {
00559             if (op->type != PLAYER)
00560             {
00561                 return;
00562             }
00563 
00564             if (exit_ob->sub_type == ST1_EXIT_SOUND && exit_ob->map)
00565             {
00566                 play_sound_map(exit_ob->map, CMD_SOUND_EFFECT, "teleport.ogg", exit_ob->x, exit_ob->y, 0, 0);
00567             }
00568 
00569             enter_unique_map(op, exit_ob);
00570         }
00571         else
00572         {
00573             int x = EXIT_X(exit_ob), y = EXIT_Y(exit_ob);
00574             char tmp_path[HUGE_BUF];
00575             /* 'Normal' exits that do not do anything special
00576              * Simple enough we don't need another routine for it. */
00577             mapstruct *newmap = NULL;
00578 
00579             if (exit_ob->map)
00580             {
00581                 if (strcmp(EXIT_PATH(exit_ob), "/random/"))
00582                 {
00583                     if (strncmp(exit_ob->map->path, settings.localdir, strlen(settings.localdir)))
00584                     {
00585                         newmap = ready_map_name(normalize_path(exit_ob->map->path, EXIT_PATH(exit_ob), tmp_path), 0);
00586                     }
00587                     else
00588                     {
00589                         newmap = ready_map_name(normalize_path("", EXIT_PATH(exit_ob), tmp_path), 0);
00590                     }
00591                 }
00592 
00593                 /* This is either a new random map to load, or we failed
00594                  * to load an old random map. */
00595                 if (!newmap && !strncmp(EXIT_PATH(exit_ob), "/random/", 8))
00596                 {
00597                     if (op->type != PLAYER)
00598                     {
00599                         return;
00600                     }
00601 
00602                     /* Maps that go down have a message set. However, maps
00603                      * that go up, don't. If the going home has reset, there
00604                      * isn't much point generating a random map, because it
00605                      * won't match the maps, so just teleport the player
00606                      * to their savebed map. */
00607                     if (exit_ob->msg)
00608                     {
00609                         if (exit_ob->sub_type == ST1_EXIT_SOUND && op->map)
00610                         {
00611                             play_sound_map(exit_ob->map, CMD_SOUND_EFFECT, "teleport.ogg", exit_ob->x, exit_ob->y, 0, 0);
00612                         }
00613 
00614                         enter_random_map(op, exit_ob);
00615                     }
00616                     else
00617                     {
00618                         enter_player_savebed(op);
00619                     }
00620 
00621                     /* For exits that cause damages (like pits).  Don't know if any
00622                      * random maps use this or not. */
00623                     if (exit_ob->stats.dam && op->type == PLAYER)
00624                     {
00625                         hit_player(op, exit_ob->stats.dam, exit_ob, AT_INTERNAL);
00626                     }
00627 
00628                     return;
00629                 }
00630             }
00631             else
00632             {
00633                 /* For word of recall and other force objects
00634                  * They contain the full pathname of the map to go back to,
00635                  * so we don't need to normalize it.
00636                  * But we do need to see if it is unique or not  */
00637                 if (!strncmp(EXIT_PATH(exit_ob), settings.localdir, strlen(settings.localdir)))
00638                 {
00639                     newmap = ready_map_name(EXIT_PATH(exit_ob), MAP_NAME_SHARED|MAP_PLAYER_UNIQUE);
00640                 }
00641                 else
00642                 {
00643                     newmap = ready_map_name(EXIT_PATH(exit_ob), MAP_NAME_SHARED);
00644                 }
00645             }
00646 
00647             if (!newmap)
00648             {
00649                 if (op->type == PLAYER)
00650                 {
00651                     new_draw_info_format(0, COLOR_WHITE, op, "The %s is closed.", query_name(exit_ob, NULL));
00652                 }
00653 
00654                 return;
00655             }
00656 
00657             /* -1, -1 marks to use the default ENTER_xx position of the map */
00658             if (x == -1 && y == -1)
00659             {
00660                 x = MAP_ENTER_X(newmap);
00661                 y = MAP_ENTER_Y(newmap);
00662             }
00663 
00664             /* If exit is damned, update player's death and WoR home-position
00665              * and delete town portal. */
00666             if (QUERY_FLAG(exit_ob, FLAG_DAMNED))
00667             {
00668                 if (op->type != PLAYER)
00669                 {
00670                     return;
00671                 }
00672 
00673                 /* Remove an old force with a slaying field == PORTAL_DESTINATION_NAME */
00674                 for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
00675                 {
00676                     if (tmp->type == FORCE && tmp->slaying && tmp->slaying == shstr_cons.portal_destination_name)
00677                     {
00678                         break;
00679                     }
00680                 }
00681 
00682                 if (tmp)
00683                 {
00684                     remove_ob(tmp);
00685                 }
00686 
00687                 if (exit_ob->map)
00688                 {
00689                     strcpy(CONTR(op)->savebed_map, normalize_path(exit_ob->map->path, EXIT_PATH(exit_ob), tmp_path));
00690                 }
00691                 else
00692                 {
00693                     strcpy(CONTR(op)->savebed_map, EXIT_PATH(exit_ob));
00694                 }
00695 
00696                 CONTR(op)->bed_x = EXIT_X(exit_ob), CONTR(op)->bed_y = EXIT_Y(exit_ob);
00697                 save_player(op, 1);
00698             }
00699 
00700             if (exit_ob->sub_type == ST1_EXIT_SOUND && exit_ob->map)
00701             {
00702                 play_sound_map(exit_ob->map, CMD_SOUND_EFFECT, "teleport.ogg", exit_ob->x, exit_ob->y, 0, 0);
00703             }
00704 
00705             enter_map(op, newmap, x, y, QUERY_FLAG(exit_ob, FLAG_USE_FIX_POS));
00706         }
00707 
00708         /* For exits that cause damage (like pits) */
00709         if (exit_ob->stats.dam && op->type == PLAYER)
00710         {
00711             hit_player(op, exit_ob->stats.dam, exit_ob, AT_INTERNAL);
00712         }
00713     }
00714     else if (op->type == PLAYER)
00715     {
00716         int flags = 0;
00717         mapstruct *newmap;
00718 
00719         /* Hypothetically, I guess its possible that a standard map matches
00720          * the localdir, but that seems pretty unlikely - unlikely enough that
00721          * I'm not going to attempt to try to deal with that possibility.
00722          * We use the fact that when a player saves on a unique map, it prepends
00723          * the localdir to that name.  So its an easy way to see of the map is
00724          * unique or not. */
00725         if (!strncmp(CONTR(op)->maplevel, settings.localdir, strlen(settings.localdir)))
00726         {
00727             flags = MAP_PLAYER_UNIQUE;
00728         }
00729 
00730         newmap = ready_map_name(CONTR(op)->maplevel, flags);
00731 
00732         if (!newmap)
00733         {
00734             if (strncmp(CONTR(op)->maplevel, "/random/", 8))
00735             {
00736                 LOG(llevBug, "enter_exit(): Pathname to map does not exist! player: %s (%s)\n", op->name, CONTR(op)->maplevel);
00737                 newmap = ready_map_name(EMERGENCY_MAPPATH, 0);
00738                 op->x = EMERGENCY_X;
00739                 op->y = EMERGENCY_Y;
00740 
00741                 /* If we can't load the emergency map, something is probably
00742                  * really screwed up, so bail out now. */
00743                 if (!newmap)
00744                 {
00745                     LOG(llevError, "enter_exit(): could not load emergency map? Fatal error! (player: %s)\n", op->name);
00746                 }
00747             }
00748             else
00749             {
00750                 enter_player_savebed(op);
00751                 return;
00752             }
00753         }
00754 
00755         /* -1,-1 marks to use the default ENTER_xx position of the map */
00756         if ((op->x == -1 && op->y == -1) || MAP_FIXEDLOGIN(newmap))
00757         {
00758             op->x = MAP_ENTER_X(newmap);
00759             op->y = MAP_ENTER_Y(newmap);
00760         }
00761 
00762         enter_map(op, newmap, op->x, op->y, 1);
00763     }
00764 }
00765 
00769 static void process_players1()
00770 {
00771     player *pl, *plnext;
00772     int retval;
00773 
00774     for (pl = first_player; pl; pl = plnext)
00775     {
00776         plnext = pl->next;
00777 
00778         while ((retval = handle_newcs_player(pl)) == 1)
00779         {
00780         }
00781 
00782         if (retval == -1)
00783         {
00784             continue;
00785         }
00786 
00787         /* Update the next pointer, in case the above handle_newcs_player()
00788          * call(s) caused the previous next pointer to be freed (double
00789          * login kicked the playing character, for example). */
00790         plnext = pl->next;
00791 
00792         if (pl->followed_player[0])
00793         {
00794             player *followed = find_player(pl->followed_player);
00795 
00796             if (followed && followed->ob && followed->ob->map)
00797             {
00798                 rv_vector rv;
00799 
00800                 if (!on_same_map(pl->ob, followed->ob) || (get_rangevector(pl->ob, followed->ob, &rv, 0) && rv.distance > 4))
00801                 {
00802                     int space = find_free_spot(pl->ob->arch, pl->ob, followed->ob->map, followed->ob->x, followed->ob->y, 1, SIZEOFFREE2 + 1);
00803 
00804                     if (space != -1 && followed->ob->x + freearr_x[space] >= 0 && followed->ob->y + freearr_y[space] >= 0 && followed->ob->x + freearr_x[space] < MAP_WIDTH(followed->ob->map) && followed->ob->y + freearr_y[space] < MAP_HEIGHT(followed->ob->map))
00805                     {
00806                         remove_ob(pl->ob);
00807                         pl->ob->x = followed->ob->x + freearr_x[space];
00808                         pl->ob->y = followed->ob->y + freearr_y[space];
00809                         insert_ob_in_map(pl->ob, followed->ob->map, NULL, 0);
00810                     }
00811                 }
00812             }
00813             else
00814             {
00815                 new_draw_info_format(0, COLOR_RED, pl->ob, "Player %s left.", pl->followed_player);
00816                 pl->followed_player[0] = '\0';
00817             }
00818         }
00819 
00820         pl->ob->weapon_speed_left -= pl->ob->weapon_speed_add;
00821 
00822         /* Use the target system to hit our target - don't hit friendly
00823          * objects, ourselves or when we are not in combat mode. */
00824         if (pl->target_object && pl->combat_mode && OBJECT_ACTIVE(pl->target_object) && pl->target_object_count != pl->ob->count && !is_friend_of(pl->ob, pl->target_object))
00825         {
00826             if (pl->ob->weapon_speed_left <= 0)
00827             {
00828                 /* Now we force target as enemy */
00829                 pl->ob->enemy = pl->target_object;
00830                 pl->ob->enemy_count = pl->target_object_count;
00831 
00832                 if (!OBJECT_VALID(pl->ob->enemy, pl->ob->enemy_count) || pl->ob->enemy->owner == pl->ob)
00833                 {
00834                     pl->ob->enemy = NULL;
00835                 }
00836                 else if (is_melee_range(pl->ob, pl->ob->enemy))
00837                 {
00838                     if (!OBJECT_VALID(pl->ob->enemy->enemy, pl->ob->enemy->enemy_count))
00839                     {
00840                         set_npc_enemy(pl->ob->enemy, pl->ob, NULL);
00841                     }
00842                     /* Our target already has an enemy - then note we had attacked */
00843                     else
00844                     {
00845                         pl->ob->enemy->attacked_by = pl->ob;
00846                         pl->ob->enemy->attacked_by_distance = 1;
00847                     }
00848 
00849                     pl->praying = 0;
00850                     skill_attack(pl->ob->enemy, pl->ob, 0, NULL);
00851                     /* We want only *one* swing - not several swings per tick */
00852                     pl->ob->weapon_speed_left += FABS((int) pl->ob->weapon_speed_left) + 1;
00853                 }
00854             }
00855         }
00856         else
00857         {
00858             if (pl->ob->weapon_speed_left <= 0)
00859             {
00860                 pl->ob->weapon_speed_left = 0;
00861             }
00862         }
00863 
00864         if (pl->move_path)
00865         {
00866             player_path_handle(pl);
00867         }
00868 
00869         do_some_living(pl->ob);
00870 
00871 #ifdef AUTOSAVE
00872         /* Check for ST_PLAYING state so that we don't try to save off when
00873          * the player is logging in. */
00874         if ((pl->last_save_tick + AUTOSAVE) < pticks && pl->state == ST_PLAYING)
00875         {
00876             save_player(pl->ob, 1);
00877             pl->last_save_tick = pticks;
00878             hiscore_check(pl->ob, 1);
00879         }
00880 #endif
00881 
00882         /* Update total playing time. */
00883         if (pl->state == ST_PLAYING && time(NULL) > pl->last_stat_time_played)
00884         {
00885             pl->last_stat_time_played = time(NULL);
00886 
00887             if (pl->afk)
00888             {
00889                 pl->stat_time_afk++;
00890             }
00891             else
00892             {
00893                 pl->stat_time_played++;
00894             }
00895         }
00896     }
00897 }
00898 
00902 static void process_players2()
00903 {
00904     player *pl;
00905 
00906     for (pl = first_player; pl; pl = pl->next)
00907     {
00908         /* Check if our target is still valid - if not, update client. */
00909         if (pl->ob->map && (!pl->target_object || (pl->target_object != pl->ob && pl->target_object_count != pl->target_object->count) || QUERY_FLAG(pl->target_object, FLAG_SYS_OBJECT) || (QUERY_FLAG(pl->target_object, FLAG_IS_INVISIBLE) && !QUERY_FLAG(pl->ob, FLAG_SEE_INVISIBLE))))
00910         {
00911             send_target_command(pl);
00912         }
00913 
00914         if (pl->ob->speed_left > pl->ob->speed)
00915         {
00916             pl->ob->speed_left = pl->ob->speed;
00917         }
00918     }
00919 }
00920 
00924 void process_events(mapstruct *map)
00925 {
00926     object *op;
00927     tag_t tag;
00928 
00929     process_players1();
00930 
00931     /* Put marker object at beginning of active list */
00932     marker.active_next = active_objects;
00933 
00934     if (marker.active_next)
00935     {
00936         marker.active_next->active_prev = &marker;
00937     }
00938 
00939     marker.active_prev = NULL;
00940     active_objects = &marker;
00941 
00942     while (marker.active_next)
00943     {
00944         op = marker.active_next;
00945         tag = op->count;
00946 
00947         /* Move marker forward - swap op and marker */
00948         op->active_prev = marker.active_prev;
00949 
00950         if (op->active_prev)
00951         {
00952             op->active_prev->active_next = op;
00953         }
00954         else
00955         {
00956             active_objects = op;
00957         }
00958 
00959         marker.active_next = op->active_next;
00960 
00961         if (marker.active_next)
00962         {
00963             marker.active_next->active_prev = &marker;
00964         }
00965 
00966         marker.active_prev = op;
00967         op->active_next = &marker;
00968 
00969         /* Now process op */
00970         if (OBJECT_FREE(op))
00971         {
00972             LOG(llevBug, "process_events(): Free object on active list\n");
00973             op->speed = 0;
00974             update_ob_speed(op);
00975             continue;
00976         }
00977 
00978         if (QUERY_FLAG(op, FLAG_REMOVED))
00979         {
00980             op->speed = 0;
00981             update_ob_speed(op);
00982             continue;
00983         }
00984 
00985         if (!op->speed)
00986         {
00987             LOG(llevBug, "process_events(): Object %s (%s, type:%d count:%d) has no speed, but is on active list\n", op->arch->name, query_name(op, NULL), op->type, op->count);
00988             update_ob_speed(op);
00989             continue;
00990         }
00991 
00992         if (op->map == NULL && op->env == NULL && op->name && op->type != MAP && map == NULL)
00993         {
00994             if (op->type == PLAYER && CONTR(op)->state != ST_PLAYING)
00995             {
00996                 continue;
00997             }
00998 
00999             LOG(llevBug, "process_events(): Object without map or inventory is on active list: %s (%d)\n", query_name(op, NULL), op->count);
01000             op->speed = 0;
01001             update_ob_speed(op);
01002             continue;
01003         }
01004 
01005         if (map && op->map != map)
01006         {
01007             continue;
01008         }
01009 
01010         /* As long we are > 0, we are not ready to swing. */
01011         if (op->weapon_speed_left > 0)
01012         {
01013             op->weapon_speed_left -= op->weapon_speed_add;
01014         }
01015 
01016         if (op->speed_left > 0)
01017         {
01018             --op->speed_left;
01019             process_object(op);
01020 
01021             if (was_destroyed(op, tag))
01022             {
01023                 continue;
01024             }
01025         }
01026 
01027         /* Handle archetype-field anim_speed differently when it comes to
01028          * the animation. If we have a value on this we don't animate it
01029          * at speed-events. */
01030         if (QUERY_FLAG(op, FLAG_ANIMATE))
01031         {
01032             if (op->last_anim >= op->anim_speed)
01033             {
01034                 animate_object(op, 1);
01035 
01036                 /* Check for direction changing */
01037                 if (op->type == PLAYER && NUM_FACINGS(op) >= 25)
01038                 {
01039                     if (op->anim_moving_dir != -1)
01040                     {
01041                         op->anim_last_facing = op->anim_moving_dir;
01042                         op->anim_moving_dir = -1;
01043                     }
01044 
01045                     if (op->anim_enemy_dir != -1)
01046                     {
01047                         op->anim_last_facing = op->anim_enemy_dir;
01048                         op->anim_enemy_dir = -1;
01049                     }
01050                 }
01051 
01052                 op->last_anim = 1;
01053             }
01054             else
01055             {
01056                 /* Check for direction changing */
01057                 if (NUM_FACINGS(op) >= 25)
01058                 {
01059                     animate_object(op, 0);
01060                 }
01061 
01062                 op->last_anim++;
01063             }
01064         }
01065 
01066         if (op->speed_left <= 0)
01067         {
01068             op->speed_left += FABS(op->speed);
01069         }
01070     }
01071 
01072     /* Remove marker object from active list */
01073     if (marker.active_prev)
01074     {
01075         marker.active_prev->active_next = NULL;
01076     }
01077     else
01078     {
01079         active_objects = NULL;
01080     }
01081 
01082     process_players2();
01083 }
01084 
01087 void clean_tmp_files()
01088 {
01089     mapstruct *m, *next;
01090 
01091     LOG(llevInfo, "Cleaning up...\n");
01092 
01093     /* We save the maps - it may not be intuitive why, but if there are
01094      * unique items, we need to save the map so they get saved off. */
01095     for (m = first_map; m != NULL; m = next)
01096     {
01097         next = m->next;
01098 
01099         if (m->in_memory == MAP_IN_MEMORY)
01100         {
01101 #if RECYCLE_TMP_MAPS
01102             swap_map(m, 0);
01103 #else
01104             new_save_map(m, 0);
01105             clean_tmp_map(m);
01106 #endif
01107         }
01108     }
01109 
01110     /* Write the clock */
01111     write_todclock();
01112 }
01113 
01116 void cleanup()
01117 {
01118     LOG(llevDebug, "Cleanup called. Freeing data.\n");
01119     clean_tmp_files();
01120 #if MEMORY_DEBUG
01121     free_all_maps();
01122     free_style_maps();
01123     free_all_archs();
01124     free_all_treasures();
01125     free_all_images();
01126     free_all_newserver();
01127     free_all_recipes();
01128     free_all_readable();
01129     free_all_god();
01130     free_all_anim();
01131     free_strings();
01132     race_free();
01133     free_exp_objects();
01134     free_srv_files();
01135     free_regions();
01136     free_mempools();
01137 #endif
01138     cache_remove_all();
01139     remove_plugins();
01140 }
01141 
01146 static void dequeue_path_requests()
01147 {
01148 #ifdef LEFTOVER_CPU_FOR_PATHFINDING
01149     static struct timeval new_time;
01150     long leftover_sec, leftover_usec;
01151     object *wp;
01152 
01153     while ((wp = get_next_requested_path()))
01154     {
01155         waypoint_compute_path(wp);
01156 
01157         (void) GETTIMEOFDAY(&new_time);
01158 
01159         leftover_sec = last_time.tv_sec - new_time.tv_sec;
01160         leftover_usec = max_time - (new_time.tv_usec - last_time.tv_usec);
01161 
01162         /* This is very ugly, but probably the fastest for our use: */
01163         while (leftover_usec < 0)
01164         {
01165             leftover_usec += 1000000;
01166             leftover_sec -= 1;
01167         }
01168         while (leftover_usec > 1000000)
01169         {
01170             leftover_usec -= 1000000;
01171             leftover_sec += 1;
01172         }
01173 
01174         /* Try to save about 10 ms */
01175         if (leftover_sec < 1 && leftover_usec < 10000)
01176         {
01177             break;
01178         }
01179     }
01180 #else
01181     object *wp = get_next_requested_path();
01182 
01183     if (wp)
01184     {
01185         waypoint_compute_path(wp);
01186     }
01187 #endif
01188 }
01189 
01198 int swap_apartments(const char *mapold, const char *mapnew, int x, int y, object *op)
01199 {
01200     char oldmappath[HUGE_BUF], newmappath[HUGE_BUF];
01201     int i, j;
01202     object *ob, *tmp, *tmp2, *dummy;
01203     mapstruct *oldmap, *newmap;
01204 
01205     snprintf(oldmappath, sizeof(oldmappath), "%s/%s/%s/%s", settings.localdir, settings.playerdir, op->name, clean_path(mapold));
01206     snprintf(newmappath, sizeof(newmappath), "%s/%s/%s/%s", settings.localdir, settings.playerdir, op->name, clean_path(mapnew));
01207 
01208     /* So we can transfer our items from the old apartment. */
01209     oldmap = ready_map_name(oldmappath, 2);
01210 
01211     if (!oldmap)
01212     {
01213         LOG(llevBug, "swap_apartments(): Could not get oldmap using ready_map_name().\n");
01214         return 0;
01215     }
01216 
01217     /* Our new map. */
01218     newmap = ready_map_name(create_pathname(mapnew), 6);
01219 
01220     if (!newmap)
01221     {
01222         LOG(llevBug, "swap_apartments(): Could not get newmap using ready_map_name().\n");
01223         return 0;
01224     }
01225 
01226     /* Goes to player directory. */
01227     FREE_AND_COPY_HASH(newmap->path, newmappath);
01228     newmap->map_flags |= MAP_FLAG_UNIQUE;
01229 
01230     /* Go through every square on old apartment map, looking for things
01231      * to transfer. */
01232     for (i = 0; i < MAP_WIDTH(oldmap); i++)
01233     {
01234         for (j = 0; j < MAP_HEIGHT(oldmap); j++)
01235         {
01236             for (ob = get_map_ob(oldmap, i, j); ob; ob = tmp2)
01237             {
01238                 tmp2 = ob->above;
01239 
01240                 /* We teleport any possible players here to emergency map. */
01241                 if (ob->type == PLAYER)
01242                 {
01243                     dummy = get_object();
01244                     dummy->map = ob->map;
01245                     FREE_AND_COPY_HASH(EXIT_PATH(dummy), EMERGENCY_MAPPATH);
01246                     FREE_AND_COPY_HASH(dummy->name, EMERGENCY_MAPPATH);
01247                     enter_exit(ob, dummy);
01248                     continue;
01249                 }
01250 
01251                 /* If it's sys_object 1, there's no need to transfer it. */
01252                 if (QUERY_FLAG(ob, FLAG_SYS_OBJECT))
01253                 {
01254                     continue;
01255                 }
01256 
01257                 /* A pickable item... Tranfer it */
01258                 if (!QUERY_FLAG(ob, FLAG_NO_PICK))
01259                 {
01260                     remove_ob(ob);
01261                     ob->x = x;
01262                     ob->y = y;
01263                     insert_ob_in_map(ob, newmap, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
01264                 }
01265                 /* Fixed part of map */
01266                 else
01267                 {
01268                     /* Now we test for containers, because player
01269                      * can have items stored in it. So, go through
01270                      * the container and look for things to transfer. */
01271                     for (tmp = ob->inv; tmp; tmp = tmp2)
01272                     {
01273                         tmp2 = tmp->below;
01274 
01275                         if (QUERY_FLAG(tmp, FLAG_SYS_OBJECT) || QUERY_FLAG(tmp, FLAG_NO_PICK))
01276                         {
01277                             continue;
01278                         }
01279 
01280                         remove_ob(tmp);
01281                         tmp->x = x;
01282                         tmp->y = y;
01283                         insert_ob_in_map(tmp, newmap, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
01284                     }
01285                 }
01286             }
01287         }
01288     }
01289 
01290     /* Save the map */
01291     new_save_map(newmap, 0);
01292 
01293     /* Check for old save bed */
01294     if (strcmp(oldmap->path, CONTR(op)->savebed_map) == 0)
01295     {
01296         strcpy(CONTR(op)->savebed_map, EMERGENCY_MAPPATH);
01297         CONTR(op)->bed_x = EMERGENCY_X;
01298         CONTR(op)->bed_y = EMERGENCY_Y;
01299     }
01300 
01301     unlink(oldmap->path);
01302 
01303     /* Free the maps */
01304     free_map(newmap, 1);
01305     free_map(oldmap, 1);
01306 
01307     return 1;
01308 }
01309 
01312 static void do_specials()
01313 {
01314     if (!(pticks % 2))
01315     {
01316         dequeue_path_requests();
01317     }
01318 
01319     /* If watchdog is enabled */
01320     if (settings.watchdog)
01321     {
01322         if (!(pticks % 503))
01323         {
01324             watchdog();
01325         }
01326     }
01327 
01328     if (!(pticks % PTICKS_PER_CLOCK))
01329     {
01330         tick_the_clock();
01331     }
01332 
01333     /* Clears the tmp-files of maps which have reset */
01334     if (!(pticks % 509))
01335     {
01336         flush_old_maps();
01337     }
01338 
01339     if (settings.meta_on && !(pticks % 2521))
01340     {
01341         metaserver_info_update();
01342     }
01343 }
01344 
01347 static void iterate_main_loop()
01348 {
01349     nroferrors = 0;
01350 
01351     /* Check and run a shutdown count (with messages and shutdown) */
01352     shutdown_agent(-1, NULL);
01353 
01354     doeric_server();
01355 
01356 #ifdef MEMPOOL_OBJECT_TRACKING
01357     check_use_object_list();
01358 #endif
01359 
01360     /* Global round ticker. */
01361     global_round_tag++;
01362 
01363     /* "do" something with objects with speed */
01364     process_events(NULL);
01365 
01366     /* Process the timers */
01367     cftimer_process_timers();
01368 
01369     /* Removes unused maps after a certain timeout */
01370     check_active_maps();
01371 
01372     /* Routines called from time to time. */
01373     do_specials();
01374 
01375     doeric_server_write();
01376 
01377     /* Clean up the object pool */
01378     object_gc();
01379 
01380     /* Sleep proper amount of time before next tick */
01381     sleep_delta();
01382 }
01383 
01384 #ifdef HAVE_WORLD_MAKER
01385 void world_maker();
01386 #endif
01387 
01393 int main(int argc, char **argv)
01394 {
01395     char buf[HUGE_BUF];
01396     size_t i;
01397     FILE *fp;
01398 
01399 #ifdef WIN32
01400     /* Open all files in binary mode by default. */
01401     _set_fmode(_O_BINARY);
01402 #endif
01403 
01404     init(argc, argv);
01405     init_plugins();
01406 
01407 #ifdef HAVE_CHECK
01408     /* Now that we have everything loaded, we can run unit tests. */
01409     if (settings.unit_tests)
01410     {
01411         LOG(llevInfo, "Running unit tests...\n");
01412         check_main();
01413         exit(0);
01414     }
01415 #endif
01416 
01417 #ifdef HAVE_WORLD_MAKER
01418     if (settings.world_maker)
01419     {
01420         LOG(llevInfo, "Running the world maker...\n");
01421         world_maker();
01422         exit(0);
01423     }
01424 #endif
01425 
01426     memset(&marker, 0, sizeof(struct obj));
01427 
01428     /* Try to find branch revision. */
01429     for (i = 0; i < arraysize(branch_paths); i++)
01430     {
01431         snprintf(buf, sizeof(buf), "%s/.bzr/branch/last-revision", branch_paths[i]);
01432         fp = fopen(buf, "r");
01433 
01434         if (fp && fgets(buf, sizeof(buf) - 1, fp))
01435         {
01436             char *end = strchr(buf, ' ');
01437 
01438             if (end)
01439             {
01440                 *end = '\0';
01441             }
01442 
01443             branch_revision = atoi(buf);
01444             fclose(fp);
01445             break;
01446         }
01447     }
01448 
01449     LOG(llevInfo, "Server ready. Waiting for connections...\n");
01450 
01451     for (; ;)
01452     {
01453         iterate_main_loop();
01454     }
01455 }