Crossfire Server, Branch 1.12  R12190
arch.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_arch_c =
00003  *   "$Id: arch.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 
00006 /*
00007     CrossFire, A Multiplayer game for X-windows
00008 
00009     Copyright (C) 2002-2006 Mark Wedel & Crossfire Development Team
00010     Copyright (C) 1992 Frank Tore Johansen
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 
00026     The authors can be reached via e-mail at crossfire-devel@real-time.com
00027 */
00028 
00043 #include <global.h>
00044 #include <loader.h>
00045 
00047 #define TIME_ARCH_LOAD 0
00048 
00049 static void add_arch(archetype *at);
00050 
00051 static archetype *arch_table[ARCHTABLE];
00052 static int arch_cmp = 0;  
00053 static int arch_search = 0; 
00054 int arch_init;  
00056 static void load_archetypes(void);
00057 
00070 archetype *find_archetype_by_object_name(const char *name) {
00071     archetype *at;
00072     const char *tmp;
00073 
00074     if (name == NULL)
00075         return (archetype *)NULL;
00076     tmp = add_string(name);
00077     for (at = first_archetype; at != NULL; at = at->next) {
00078         if (at->clone.name == tmp) {
00079             free_string(tmp);
00080             return at;
00081         }
00082     }
00083     free_string(tmp);
00084     return NULL;
00085 }
00086 
00096 archetype *find_archetype_by_object_type_name(int type, const char *name) {
00097     archetype *at;
00098 
00099     if (name == NULL)
00100         return NULL;
00101 
00102     for (at = first_archetype; at != NULL; at = at->next) {
00103         if (at->clone.type == type && strcmp(at->clone.name, name) == 0)
00104             return at;
00105     }
00106 
00107     return NULL;
00108 }
00109 
00120 archetype *get_archetype_by_skill_name(const char *skill, int type) {
00121     archetype *at;
00122 
00123     if (skill == NULL)
00124         return NULL;
00125 
00126     for (at = first_archetype; at != NULL; at = at->next) {
00127         if (((type == -1) || (type == at->clone.type))
00128         && (at->clone.skill) && (!strcmp(at->clone.skill, skill)))
00129             return at;
00130     }
00131     return NULL;
00132 }
00133 
00149 archetype *get_archetype_by_type_subtype(int type, int subtype) {
00150     archetype *at;
00151 
00152     for (at = first_archetype; at != NULL; at = at->next) {
00153         if (((type == -1) || (type == at->clone.type))
00154         && (subtype == -1 || subtype == at->clone.subtype))
00155             return at;
00156     }
00157     return NULL;
00158 }
00159 
00173 object *create_archetype_by_object_name(const char *name) {
00174     archetype *at;
00175     char tmpname[MAX_BUF];
00176     size_t i;
00177 
00178     strncpy(tmpname, name, MAX_BUF-1);
00179     tmpname[MAX_BUF-1] = 0;
00180     for (i = strlen(tmpname); i > 0; i--) {
00181         tmpname[i] = 0;
00182         at = find_archetype_by_object_name(tmpname);
00183         if (at != NULL) {
00184             return arch_to_object(at);
00185         }
00186     }
00187     return create_singularity(name);
00188 }
00189 
00195 void init_archetypes(void) {
00196     if (first_archetype != NULL) /* Only do this once */
00197         return;
00198     arch_init = 1;
00199     load_archetypes();
00200     arch_init = 0;
00201     empty_archetype = find_archetype("empty_archetype");
00202     /*  init_blocksview();*/
00203 }
00204 
00209 void arch_info(object *op) {
00210     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG,
00211         "%d searches and %d strcmp()'s",
00212         "%d searches and %d strcmp()'s",
00213         arch_search, arch_cmp);
00214 }
00215 
00219 void clear_archetable(void) {
00220     memset((void *)arch_table, 0, ARCHTABLE*sizeof(archetype *));
00221 }
00222 
00226 static void init_archetable(void) {
00227     archetype *at;
00228 
00229     LOG(llevDebug, " Setting up archetable...\n");
00230     for (at = first_archetype; at != NULL; at = (at->more == NULL) ? at->next : at->more)
00231         add_arch(at);
00232     LOG(llevDebug, "done\n");
00233 }
00234 
00243 void dump_arch(archetype *at, StringBuffer *sb) {
00244     dump_object(&at->clone, sb);
00245 }
00246 
00252 void dump_all_archetypes(void) {
00253     archetype *at;
00254 
00255     for (at = first_archetype; at != NULL; at = (at->more == NULL) ? at->next : at->more) {
00256         StringBuffer *sb;
00257         char *diff;
00258 
00259         sb = stringbuffer_new();
00260         dump_arch(at, sb);
00261         diff = stringbuffer_finish(sb);
00262         LOG(llevDebug, "%s\n", diff);
00263         free(diff);
00264     }
00265 }
00266 
00273 void free_arch(archetype *at) {
00274     if (at->name)
00275         free_string(at->name);
00276     if (at->clone.name)
00277         free_string(at->clone.name);
00278     if (at->clone.name_pl)
00279         free_string(at->clone.name_pl);
00280     if (at->clone.title)
00281         free_string(at->clone.title);
00282     if (at->clone.race)
00283         free_string(at->clone.race);
00284     if (at->clone.slaying)
00285         free_string(at->clone.slaying);
00286     if (at->clone.msg)
00287         free_string(at->clone.msg);
00288     if (at->clone.discrete_damage)
00289         free(at->clone.discrete_damage);
00290     free_key_values(&at->clone);
00291     free(at);
00292 }
00293 
00298 void free_all_archs(void) {
00299     archetype *at, *next;
00300     int i = 0;
00301 
00302     for (at = first_archetype; at != NULL; at = next) {
00303         if (at->more)
00304             next = at->more;
00305         else
00306             next = at->next;
00307         free_arch(at);
00308         i++;
00309     }
00310     first_archetype = NULL;
00311     /* Reset the hashtable */
00312     clear_archetable();
00313     LOG(llevDebug, "Freed %d archetypes\n", i);
00314 }
00315 
00323 archetype *get_archetype_struct(void) {
00324     archetype *new;
00325 
00326     new = (archetype *)CALLOC(1, sizeof(archetype));
00327     if (new == NULL)
00328         fatal(OUT_OF_MEMORY);
00329     new->next = NULL;
00330     new->name = NULL;
00331     new->clone.other_arch = NULL;
00332     new->clone.name = NULL;
00333     new->clone.name_pl = NULL;
00334     new->clone.title = NULL;
00335     new->clone.race = NULL;
00336     new->clone.slaying = NULL;
00337     new->clone.msg = NULL;
00338     clear_object(&new->clone);  /* to initial state other also */
00339     CLEAR_FLAG((&new->clone), FLAG_FREED); /* This shouldn't matter, since copy_object() */
00340     SET_FLAG((&new->clone), FLAG_REMOVED); /* doesn't copy these flags... */
00341     new->head = NULL;
00342     new->more = NULL;
00343     new->clone.arch = new;
00344     return new;
00345 }
00346 
00357 static void first_arch_pass(FILE *fp) {
00358     object *op;
00359     archetype *at, *head = NULL, *last_more = NULL;
00360     int i, first = 2;
00361 
00362     op = get_object();
00363     op->arch = first_archetype = at = get_archetype_struct();
00364 
00365     while ((i = load_object(fp, op, first, 0))) {
00366         first = 0;
00367         copy_object(op, &at->clone);
00368         at->clone.speed_left = (float)(-0.1);
00369         /* copy the body_info to the body_used - this is only really
00370          * need for monsters, but doesn't hurt to do it for everything.
00371          * by doing so, when a monster is created, it has good starting
00372          * values for the body_used info, so when items are created
00373          * for it, they can be properly equipped.
00374          */
00375         memcpy(&at->clone.body_used, &op->body_info, sizeof(op->body_info));
00376 
00377         switch (i) {
00378         case LL_NORMAL: /* A new archetype, just link it with the previous */
00379             if (last_more != NULL)
00380                 last_more->next = at;
00381             if (head != NULL)
00382                 head->next = at;
00383             head = last_more = at;
00384             at->tail_x = 0;
00385             at->tail_y = 0;
00386             break;
00387 
00388         case LL_MORE: /* Another part of the previous archetype, link it correctly */
00389             at->head = head;
00390             at->clone.head = &head->clone;
00391             if (last_more != NULL) {
00392                 last_more->more = at;
00393                 last_more->clone.more = &at->clone;
00394             }
00395             last_more = at;
00396 
00397             /* Set FLAG_MONSTER throughout parts if head has it */
00398             if (QUERY_FLAG(&head->clone, FLAG_MONSTER)) {
00399                 SET_FLAG(&at->clone, FLAG_MONSTER);
00400             }
00401 
00402             /* If this multipart image is still composed of individual small
00403              * images, don't set the tail_.. values.  We can't use them anyways,
00404              * and setting these to zero makes the map sending to the client much
00405              * easier as just looking at the head, we know what to do.
00406              */
00407             if (at->clone.face != head->clone.face) {
00408                 head->tail_x = 0;
00409                 head->tail_y = 0;
00410             } else {
00411                 if (at->clone.x > head->tail_x)
00412                     head->tail_x = at->clone.x;
00413                 if (at->clone.y > head->tail_y)
00414                     head->tail_y = at->clone.y;
00415             }
00416             break;
00417         }
00418 
00419         at = get_archetype_struct();
00420         clear_object(op);
00421         op->arch = at;
00422     }
00423     free_object(op);
00424     op->arch = NULL; /* arch is checked for temporary archetypes if not NULL. */
00425     free(at);
00426 }
00427 
00437 static void second_arch_pass(FILE *fp) {
00438     char buf[MAX_BUF], *variable = buf, *argument, *cp;
00439     archetype *at = NULL, *other;
00440     object *inv;
00441 
00442     while (fgets(buf, MAX_BUF, fp) != NULL) {
00443         if (*buf == '#')
00444             continue;
00445         if ((argument = strchr(buf, ' ')) != NULL) {
00446             *argument = '\0', argument++;
00447             cp = argument+strlen(argument)-1;
00448             while (isspace(*cp)) {
00449                 *cp = '\0';
00450                 cp--;
00451             }
00452         }
00453         if (!strcmp("Object", variable)) {
00454             if ((at = find_archetype(argument)) == NULL)
00455                 LOG(llevError, "Warning: failed to find arch %s\n", argument);
00456         } else if (!strcmp("other_arch", variable)) {
00457             if (at != NULL && at->clone.other_arch == NULL) {
00458                 if ((other = find_archetype(argument)) == NULL)
00459                     LOG(llevError, "Warning: failed to find other_arch %s\n", argument);
00460                 else if (at != NULL)
00461                     at->clone.other_arch = other;
00462             }
00463         } else if (!strcmp("randomitems", variable)) {
00464             if (at != NULL) {
00465                 treasurelist *tl = find_treasurelist(argument);
00466                 if (tl == NULL)
00467                     LOG(llevError, "Failed to link treasure to arch (%s): %s\n", at->name, argument);
00468                 else
00469                     at->clone.randomitems = tl;
00470             }
00471         } else if (!strcmp("arch", variable)) {
00472             inv = create_archetype(argument);
00473             load_object(fp, inv, LO_LINEMODE, 0);
00474             if (at) {
00475                 insert_ob_in_ob(inv, &at->clone);
00476                 /*LOG(llevDebug, "Put %s in %s\n", inv->name, at->clone.name);*/
00477             } else {
00478                 LOG(llevError, "Got an arch %s not inside an Object.\n", argument);
00479                 free_object(inv);
00480             }
00481         }
00482     }
00483 }
00484 
00485 #ifdef DEBUG
00486 
00491 void check_generators(void) {
00492     archetype *at;
00493 
00494     for (at = first_archetype; at != NULL; at = at->next)
00495         if (QUERY_FLAG(&at->clone, FLAG_GENERATOR) && at->clone.other_arch == NULL)
00496             LOG(llevError, "Warning: %s is generator but lacks other_arch.\n", at->name);
00497 }
00498 #endif
00499 
00507 static void load_archetypes(void) {
00508     FILE *fp;
00509     char filename[MAX_BUF];
00510     int comp;
00511 #if TIME_ARCH_LOAD
00512     struct timeval tv1, tv2;
00513 #endif
00514 
00515     snprintf(filename, sizeof(filename), "%s/%s", settings.datadir, settings.archetypes);
00516     LOG(llevDebug, "Reading archetypes from %s...\n", filename);
00517     if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL) {
00518         LOG(llevError, " Can't open archetype file.\n");
00519         return;
00520     }
00521     clear_archetable();
00522     LOG(llevDebug, " arch-pass 1...\n");
00523 #if TIME_ARCH_LOAD
00524     GETTIMEOFDAY(&tv1);
00525 #endif
00526     first_arch_pass(fp);
00527 #if TIME_ARCH_LOAD
00528     {
00529         int sec, usec;
00530 
00531         GETTIMEOFDAY(&tv2);
00532         sec = tv2.tv_sec-tv1.tv_sec;
00533         usec = tv2.tv_usec-tv1.tv_usec;
00534         if (usec < 0) {
00535             usec += 1000000;
00536             sec--;
00537         }
00538         LOG(llevDebug, "Load took %d.%06d seconds\n", sec, usec);
00539     }
00540 #endif
00541 
00542     LOG(llevDebug, " done\n");
00543     init_archetable();
00544     warn_archetypes = 1;
00545 
00546     /* do a close and reopen instead of a rewind - necessary in case the
00547      * file has been compressed.
00548      */
00549     close_and_delete(fp, comp);
00550     fp = open_and_uncompress(filename, 0, &comp);
00551 
00552     LOG(llevDebug, " loading treasure...\n");
00553     load_treasures();
00554     LOG(llevDebug, " done\n");
00555     LOG(llevDebug, "arch-pass 2...\n");
00556     second_arch_pass(fp);
00557     LOG(llevDebug, " done\n");
00558 #ifdef DEBUG
00559     check_generators();
00560 #endif
00561     close_and_delete(fp, comp);
00562     LOG(llevDebug, " done\n");
00563 }
00564 
00576 object *arch_to_object(archetype *at) {
00577     object *op;
00578 
00579     if (at == NULL) {
00580         if (warn_archetypes)
00581             LOG(llevError, "Couldn't find archetype.\n");
00582         return NULL;
00583     }
00584     op = get_object();
00585     copy_object_with_inv(&at->clone, op);
00586     op->arch = at;
00587     return op;
00588 }
00589 
00603 object *create_singularity(const char *name) {
00604     object *op;
00605     char buf[MAX_BUF];
00606 
00607     snprintf(buf, sizeof(buf), "%s (%s)", ARCH_SINGULARITY, name);
00608     op = get_object();
00609     op->name = add_string(buf);
00610     op->name_pl = add_string(buf);
00611     SET_FLAG(op, FLAG_NO_PICK);
00612     return op;
00613 }
00614 
00625 object *create_archetype(const char *name) {
00626     archetype *at;
00627 
00628     at = find_archetype(name);
00629     if (at == NULL)
00630         return create_singularity(name);
00631     return arch_to_object(at);
00632 }
00633 
00643 static unsigned long
00644 hasharch(const char *str, int tablesize) {
00645     unsigned long hash = 0;
00646     int i = 0;
00647     const char *p;
00648 
00649     /* use the one-at-a-time hash function, which supposedly is
00650      * better than the djb2-like one used by perl5.005, but
00651      * certainly is better then the bug used here before.
00652      * see http://burtleburtle.net/bob/hash/doobs.html
00653      */
00654     for (p = str; i < MAXSTRING && *p; p++, i++) {
00655         hash += *p;
00656         hash += hash<<10;
00657         hash ^= hash>>6;
00658     }
00659     hash += hash<<3;
00660     hash ^= hash>>11;
00661     hash += hash<<15;
00662     return hash%tablesize;
00663 }
00664 
00671 archetype *try_find_archetype(const char *name) {
00672     archetype *at;
00673     unsigned long index;
00674 
00675     if (name == NULL)
00676         return (archetype *)NULL;
00677 
00678     index = hasharch(name, ARCHTABLE);
00679     arch_search++;
00680     for (;;) {
00681         at = arch_table[index];
00682         if (at == NULL) {
00683             return NULL;
00684         }
00685         arch_cmp++;
00686         if (!strcmp(at->name, name))
00687             return at;
00688         if (++index >= ARCHTABLE)
00689             index = 0;
00690     }
00691 }
00692 
00700 archetype *find_archetype(const char *name) {
00701     archetype *at;
00702 
00703     if (name == NULL)
00704         return (archetype *)NULL;
00705     at = try_find_archetype(name);
00706     if (at == NULL && warn_archetypes)
00707         LOG(llevError, "Couldn't find archetype %s\n", name);
00708     return at;
00709 }
00710 
00715 static void add_arch(archetype *at) {
00716     unsigned long index = hasharch(at->name, ARCHTABLE), org_index = index;
00717 
00718     for (;;) {
00719         if (arch_table[index] == NULL) {
00720             arch_table[index] = at;
00721             return;
00722         }
00723         if (++index == ARCHTABLE)
00724             index = 0;
00725         if (index == org_index)
00726             fatal(ARCHTABLE_TOO_SMALL);
00727     }
00728 }
00729 
00741 object *object_create_arch(archetype *at) {
00742     object *op, *prev = NULL, *head = NULL;
00743 
00744     while (at) {
00745         op = arch_to_object(at);
00746         op->x = at->clone.x;
00747         op->y = at->clone.y;
00748         if (head)
00749             op->head = head, prev->more = op;
00750         if (!head)
00751             head = op;
00752         prev = op;
00753         at = at->more;
00754     }
00755     return (head);
00756 }
00757 
00758 /*** end of arch.c ***/