Atrinik Server 2.5
server/arch.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 <loader.h>
00032 
00034 #define TIME_ARCH_LOAD 0
00035 
00037 static archetype *arch_table[ARCHTABLE];
00039 int arch_cmp = 0;
00041 int arch_search = 0;
00043 int arch_init;
00044 
00045 static void clear_archetable();
00046 static void init_archetable();
00047 static archetype *get_archetype_struct();
00048 static void first_arch_pass(FILE *fp);
00049 static void second_arch_pass(FILE *fp_start);
00050 static void load_archetypes();
00051 static unsigned long hasharch(const char *str, int tablesize);
00052 static void add_arch(archetype *at);
00053 
00058 archetype *get_skill_archetype(int skillnr)
00059 {
00060     archetype *at;
00061 
00062     for (at = first_archetype; at != NULL; at = at->next)
00063     {
00064         if (at->clone.type == SKILL && at->clone.stats.sp == skillnr)
00065         {
00066             return at;
00067         }
00068     }
00069 
00070     return NULL;
00071 }
00072 
00079 void init_archetypes()
00080 {
00081     /* Only do this once */
00082     if (first_archetype != NULL)
00083     {
00084         return;
00085     }
00086 
00087     arch_init = 1;
00088     load_archetypes();
00089     arch_init = 0;
00090     empty_archetype = find_archetype("empty_archetype");
00091     base_info_archetype = find_archetype("base_info");
00092     wp_archetype = find_archetype("waypoint");
00093 }
00094 
00098 void arch_info(object *op)
00099 {
00100     char buf[MAX_BUF];
00101 
00102     snprintf(buf, sizeof(buf), "%d searches and %d strcmp()'s", arch_search, arch_cmp);
00103     new_draw_info(0, COLOR_WHITE, op, buf);
00104 }
00105 
00108 static void clear_archetable()
00109 {
00110     memset((void *) arch_table, 0, ARCHTABLE * sizeof(archetype *));
00111 }
00112 
00116 static void init_archetable()
00117 {
00118     archetype *at;
00119 
00120     LOG(llevDebug, "Setting up archetable...");
00121 
00122     for (at = first_archetype; at != NULL; at = (at->more == NULL) ? at->next : at->more)
00123     {
00124         add_arch(at);
00125     }
00126 
00127     LOG(llevDebug, " done.\n");
00128 }
00129 
00132 void dump_all_archetypes()
00133 {
00134     archetype *at;
00135     artifactlist *al;
00136     artifact *art = NULL;
00137     StringBuffer *sb;
00138     char *diff;
00139 
00140     for (at = first_archetype; at != NULL; at = (at->more == NULL) ? at->next : at->more)
00141     {
00142         sb = stringbuffer_new();
00143         dump_object(&at->clone, sb);
00144         diff = stringbuffer_finish(sb);
00145         LOG(llevInfo, "%s\n", diff);
00146         free(diff);
00147     }
00148 
00149     LOG(llevInfo, "Artifacts fake arch list:\n");
00150 
00151     for (al = first_artifactlist; al != NULL; al = al->next)
00152     {
00153         art = al->items;
00154 
00155         do
00156         {
00157             sb = stringbuffer_new();
00158             dump_object(&art->def_at.clone, sb);
00159             diff = stringbuffer_finish(sb);
00160             LOG(llevInfo, "%s\n", diff);
00161             free(diff);
00162             art = art->next;
00163         }
00164         while (art);
00165     }
00166 }
00167 
00173 void free_all_archs()
00174 {
00175     archetype *at, *next;
00176     int i = 0;
00177 
00178     for (at = first_archetype; at != NULL; at = next)
00179     {
00180         if (at->more)
00181         {
00182             next = at->more;
00183         }
00184         else
00185         {
00186             next = at->next;
00187         }
00188 
00189         FREE_AND_CLEAR_HASH(at->name);
00190         FREE_AND_CLEAR_HASH(at->clone.name);
00191         FREE_AND_CLEAR_HASH(at->clone.title);
00192         FREE_AND_CLEAR_HASH(at->clone.race);
00193         FREE_AND_CLEAR_HASH(at->clone.slaying);
00194         FREE_AND_CLEAR_HASH(at->clone.msg);
00195         free_key_values(&at->clone);
00196         free(at);
00197         i++;
00198     }
00199 
00200     LOG(llevDebug, "Freed %d archetypes\n", i);
00201 }
00202 
00207 static archetype *get_archetype_struct()
00208 {
00209     archetype *new;
00210 
00211     new = (archetype *) CALLOC(1, sizeof(archetype));
00212 
00213     if (new == NULL)
00214     {
00215         LOG(llevError, "get_archetype_struct(): Out of memory\n");
00216     }
00217 
00218     /* To initial state other also */
00219     initialize_object(&new->clone);
00220 
00221     return new;
00222 }
00223 
00229 static void first_arch_pass(FILE *fp)
00230 {
00231     object *op;
00232     void *mybuffer;
00233     archetype *at,*prev = NULL, *last_more = NULL;
00234     int i, first = 2;
00235 
00236     op = get_object();
00237     op->arch = first_archetype = at = get_archetype_struct();
00238     mybuffer = create_loader_buffer(fp);
00239 
00240     while ((i = load_object(fp, op, mybuffer, first, MAP_STYLE)))
00241     {
00242         first = 0;
00243 
00244         copy_object(op, &at->clone, 1);
00245 
00246         /* Now we have the right speed_left value for out object.
00247          * copy_object() now will track down negative speed values, to
00248          * alter speed_left to guarantee a random & sensible start value. */
00249         if (!op->layer && !QUERY_FLAG(op, FLAG_SYS_OBJECT))
00250         {
00251             LOG(llevDebug, "Archetype %s has layer 0 without being sys_object!\n", STRING_OBJ_ARCH_NAME(op));
00252         }
00253 
00254         if (op->layer && QUERY_FLAG(op, FLAG_SYS_OBJECT))
00255         {
00256             LOG(llevDebug, "Archetype %s has layer %d (!= 0) and is sys_object!\n", STRING_OBJ_ARCH_NAME(op), op->layer);
00257         }
00258 
00259         switch (i)
00260         {
00261             /* A new archetype, just link it with the previous */
00262             case LL_NORMAL:
00263                 if (last_more != NULL)
00264                 {
00265                     last_more->next = at;
00266                 }
00267 
00268                 if (prev != NULL)
00269                 {
00270                     prev->next = at;
00271                 }
00272 
00273                 prev = last_more = at;
00274 
00275                 if (!op->type)
00276                 {
00277                     LOG(llevDebug, "Archetype %s has no type!\n", STRING_OBJ_ARCH_NAME(op));
00278                 }
00279 
00280                 break;
00281 
00282             /* Another part of the previous archetype, link it correctly */
00283             case LL_MORE:
00284                 at->head = prev;
00285                 at->clone.head = &prev->clone;
00286 
00287                 if (last_more != NULL)
00288                 {
00289                     last_more->more = at;
00290                     last_more->clone.more = &at->clone;
00291                 }
00292 
00293                 last_more = at;
00294 
00295                 break;
00296         }
00297 
00298         at = get_archetype_struct();
00299         initialize_object(op);
00300         op->arch = at;
00301     }
00302 
00303     delete_loader_buffer(mybuffer);
00304     /* Make sure our temp object is gc:ed */
00305     mark_object_removed(op);
00306     free(at);
00307 }
00308 
00313 static void second_arch_pass(FILE *fp_start)
00314 {
00315     FILE *fp = fp_start;
00316     int comp;
00317     char filename[MAX_BUF], buf[MAX_BUF], *variable = buf, *argument, *cp;
00318     archetype *at = NULL, *other;
00319     object *inv;
00320 
00321     while (fgets(buf, MAX_BUF, fp) != NULL)
00322     {
00323         if (*buf == '#')
00324         {
00325             continue;
00326         }
00327 
00328         if ((argument = strchr(buf, ' ')) != NULL)
00329         {
00330             *argument = '\0', argument++;
00331             cp = argument + strlen(argument) - 1;
00332 
00333             while (isspace(*cp))
00334             {
00335                 *cp = '\0';
00336                 cp--;
00337             }
00338         }
00339 
00340         if (!strcmp("Object", variable))
00341         {
00342             if ((at = find_archetype(argument)) == NULL)
00343             {
00344                 LOG(llevBug, "Failed to find arch %s\n", STRING_SAFE(argument));
00345             }
00346         }
00347         else if (!strcmp("other_arch", variable))
00348         {
00349             if (at != NULL && at->clone.other_arch == NULL)
00350             {
00351                 if ((other = find_archetype(argument)) == NULL)
00352                 {
00353                     LOG(llevBug, "Failed to find other_arch %s\n", STRING_SAFE(argument));
00354                 }
00355                 else if (at != NULL)
00356                 {
00357                     at->clone.other_arch = other;
00358                 }
00359             }
00360         }
00361         else if (!strcmp("randomitems", variable))
00362         {
00363             if (at != NULL)
00364             {
00365                 treasurelist *tl = find_treasurelist(argument);
00366 
00367                 if (tl == NULL)
00368                 {
00369                     LOG(llevBug, "Failed to link treasure to arch. (arch: %s ->%s\n", STRING_OBJ_NAME(&at->clone), STRING_SAFE(argument));
00370                 }
00371                 else
00372                 {
00373                     at->clone.randomitems = tl;
00374                 }
00375             }
00376         }
00377         else if (!strcmp("arch", variable))
00378         {
00379             inv = get_archetype(argument);
00380             load_object(fp, inv, NULL, LO_LINEMODE, 0);
00381 
00382             if (at)
00383             {
00384                 insert_ob_in_ob(inv, &at->clone);
00385             }
00386             else
00387             {
00388                 LOG(llevError, "Got an arch %s not inside an Object.\n", argument);
00389             }
00390         }
00391     }
00392 
00393     /* Now re-parse the artifacts file too! */
00394     snprintf(filename, sizeof(filename), "%s/artifacts", settings.datadir);
00395 
00396     if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL)
00397     {
00398         LOG(llevError, "Can't open %s.\n", filename);
00399         return;
00400     }
00401 
00402     while (fgets(buf, MAX_BUF, fp) != NULL)
00403     {
00404         if (*buf == '#')
00405         {
00406             continue;
00407         }
00408 
00409         if ((argument = strchr(buf, ' ')) != NULL)
00410         {
00411             *argument = '\0', argument++;
00412             cp = argument + strlen(argument) - 1;
00413 
00414             while (isspace(*cp))
00415             {
00416                 *cp = '\0';
00417                 cp--;
00418             }
00419         }
00420 
00421         /* Now we get our artifact. if we hit "def_arch", we first copy
00422          * from it other_arch and treasure list to our artifact. Then we
00423          * search the object for other_arch and randomitems - perhaps we
00424          * override them here. */
00425         if (!strcmp("artifact", variable))
00426         {
00427             if ((at = find_archetype(argument)) == NULL)
00428             {
00429                 LOG(llevBug, "Second artifacts pass: Failed to find artifact %s\n", STRING_SAFE(argument));
00430             }
00431         }
00432         else if (!strcmp("def_arch", variable))
00433         {
00434             if ((other = find_archetype(argument)) == NULL)
00435             {
00436                 LOG(llevBug, "Second artifacts pass: Failed to find def_arch %s from artifact %s\n", STRING_SAFE(argument), STRING_ARCH_NAME(at));
00437             }
00438 
00439             /* now copy from real arch the stuff from above to our "fake" arches */
00440             at->clone.other_arch = other->clone.other_arch;
00441             at->clone.randomitems = other->clone.randomitems;
00442         }
00443         else if (!strcmp("other_arch", variable))
00444         {
00445             if ((other = find_archetype(argument)) == NULL)
00446             {
00447                 LOG(llevBug, "Second artifacts pass: Failed to find other_arch %s\n", STRING_SAFE(argument));
00448             }
00449             else if (at != NULL)
00450             {
00451                 at->clone.other_arch = other;
00452             }
00453         }
00454         else if (!strcmp("randomitems", variable))
00455         {
00456             treasurelist *tl = find_treasurelist(argument);
00457 
00458             if (tl == NULL)
00459             {
00460                 LOG(llevBug, "Second artifacts pass: Failed to link treasure to arch. (arch: %s ->%s)\n", STRING_OBJ_NAME(&at->clone), STRING_SAFE(argument));
00461             }
00462             else if (at != NULL)
00463             {
00464                 at->clone.randomitems = tl;
00465             }
00466         }
00467     }
00468 
00469     close_and_delete(fp, comp);
00470 }
00471 
00479 static void load_archetypes()
00480 {
00481     FILE *fp;
00482     char filename[MAX_BUF];
00483     int comp;
00484 #if TIME_ARCH_LOAD
00485     struct timeval tv1, tv2;
00486 #endif
00487 
00488     snprintf(filename, sizeof(filename), "%s/%s", settings.datadir, settings.archetypes);
00489     LOG(llevDebug, "Reading archetypes from %s...\n", filename);
00490 
00491     if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL)
00492     {
00493         LOG(llevError, "Can't open archetype file.\n");
00494         return;
00495     }
00496 
00497     clear_archetable();
00498     LOG(llevDebug, "arch-pass 1...\n");
00499 
00500 #if TIME_ARCH_LOAD
00501     GETTIMEOFDAY(&tv1);
00502 #endif
00503 
00504     first_arch_pass(fp);
00505 
00506 #if TIME_ARCH_LOAD
00507     int sec, usec;
00508     GETTIMEOFDAY(&tv2);
00509     sec = tv2.tv_sec - tv1.tv_sec;
00510     usec = tv2.tv_usec - tv1.tv_usec;
00511 
00512     if (usec < 0)
00513     {
00514         usec += 1000000;
00515         sec--;
00516     }
00517 
00518     LOG(llevDebug, "Load took %d.%06d seconds\n", sec, usec);
00519 #endif
00520 
00521     LOG(llevDebug, " done.\n");
00522     init_archetable();
00523 
00524     /* Do a close and reopen instead of a rewind - necessary in case the
00525      * file has been compressed. */
00526     close_and_delete(fp, comp);
00527     fp = open_and_uncompress(filename, 0, &comp);
00528 
00529     /* If not called before, reads all artifacts from file */
00530     init_artifacts();
00531     LOG(llevDebug, " loading treasure...\n");
00532     load_treasures();
00533     LOG(llevDebug, " done\n arch-pass 2...\n");
00534     second_arch_pass(fp);
00535     LOG(llevDebug, " done.\n");
00536 
00537     close_and_delete(fp, comp);
00538     LOG(llevDebug, "Reading archetypes done.\n");
00539 }
00540 
00546 object *arch_to_object(archetype *at)
00547 {
00548     object *op;
00549 
00550     if (at == NULL)
00551     {
00552         LOG(llevBug, "arch_to_object(): Archetype at is NULL.\n");
00553         return NULL;
00554     }
00555 
00556     op = get_object();
00557     copy_object_with_inv(&at->clone, op);
00558     op->arch = at;
00559 
00560     return op;
00561 }
00562 
00572 object *create_singularity(const char *name)
00573 {
00574     object *op;
00575     char buf[MAX_BUF];
00576 
00577     snprintf(buf, sizeof(buf), "singularity (%s)", name);
00578     op = get_object();
00579     FREE_AND_COPY_HASH(op->name, buf);
00580     SET_FLAG(op, FLAG_NO_PICK);
00581 
00582     return op;
00583 }
00584 
00591 object *get_archetype(const char *name)
00592 {
00593     archetype *at = find_archetype(name);
00594 
00595     if (at == NULL)
00596     {
00597         return create_singularity(name);
00598     }
00599 
00600     return arch_to_object(at);
00601 }
00602 
00608 static unsigned long hasharch(const char *str, int tablesize)
00609 {
00610     unsigned long hash = 0;
00611     int i = 0;
00612     const char *p;
00613 
00614     for (p = str; i < MAXSTRING && *p; p++, i++)
00615     {
00616         hash += *p;
00617         hash += hash << 10;
00618         hash ^= hash >> 6;
00619     }
00620 
00621     hash += hash << 3;
00622     hash ^= hash >> 11;
00623     hash += hash << 15;
00624 
00625     return hash % tablesize;
00626 }
00627 
00631 archetype *find_archetype(const char *name)
00632 {
00633     archetype *at;
00634     unsigned long idx;
00635 
00636     if (name == NULL)
00637     {
00638         return NULL;
00639     }
00640 
00641     idx = hasharch(name, ARCHTABLE);
00642     arch_search++;
00643 
00644     for (; ;)
00645     {
00646         at = arch_table[idx];
00647 
00648         /* Not in archetype list - let's try the artifacts file */
00649         if (at == NULL)
00650         {
00651             return find_artifact_archtype(name);
00652         }
00653 
00654         arch_cmp++;
00655 
00656         if (!strcmp(at->name, name))
00657         {
00658             return at;
00659         }
00660 
00661         if (++idx >= ARCHTABLE)
00662         {
00663             idx = 0;
00664         }
00665     }
00666 }
00667 
00670 static void add_arch(archetype *at)
00671 {
00672     unsigned long idx = hasharch(at->name, ARCHTABLE), org_idx = idx;
00673 
00674     for (; ;)
00675     {
00676         if (arch_table[idx] && !strcmp(arch_table[idx]->name, at->name))
00677         {
00678             LOG(llevError, "add_arch(): Double use of arch name %s.\n", STRING_ARCH_NAME(at));
00679         }
00680 
00681         if (arch_table[idx] == NULL)
00682         {
00683             arch_table[idx] = at;
00684             return;
00685         }
00686 
00687         if (++idx == ARCHTABLE)
00688         {
00689             idx = 0;
00690         }
00691 
00692         if (idx == org_idx)
00693         {
00694             LOG(llevError, "add_arch(): Archtable too small.\n");
00695         }
00696     }
00697 }
00698