Atrinik Server 2.5
server/race.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 
00035 const char *item_races[NROF_ITEM_RACES] =
00036 {
00037     "", "dwarven ", "elven ", "gnomish ", "drow ", "orcish ", "goblin ",
00038     "kobold ", "giant ", "tiny ", "demonish ", "draconish ", "ogre "
00039 };
00040 
00043 static ob_race *races = NULL;
00046 static size_t num_races = 0;
00047 
00052 static void race_add_corpse(shstr *race_name, archetype *at)
00053 {
00054     ob_race *race;
00055 
00056     if (!at || !race_name)
00057     {
00058         return;
00059     }
00060 
00061     race = race_find(race_name);
00062 
00063     if (!race)
00064     {
00065         return;
00066     }
00067 
00068     race->corpse = at;
00069 }
00070 
00075 static void race_add(shstr *race_name, object *ob)
00076 {
00077     ob_race *race;
00078     objectlink *ol;
00079 
00080     if (!ob || !race_name)
00081     {
00082         return;
00083     }
00084 
00085     race = race_find(race_name);
00086 
00087     /* No such race yet? Initialize it then. */
00088     if (!race)
00089     {
00090         size_t i, ii;
00091 
00092         races = realloc(races, sizeof(ob_race) * (num_races + 1));
00093 
00094         /* Now, insert the race into the correct spot in the array. */
00095         for (i = 0; i < num_races; i ++)
00096         {
00097             if (races[i].name > race_name)
00098             {
00099                 break;
00100             }
00101         }
00102 
00103         /* If this is not the special case of insertion at the last point, then shift everything. */
00104         for (ii = num_races; ii > i; ii--)
00105         {
00106             races[ii] = races[ii - 1];
00107         }
00108 
00109         memset(&races[i], 0, sizeof(ob_race));
00110         FREE_AND_COPY_HASH(races[i].name, race_name);
00111         race = &races[i];
00112         num_races++;
00113     }
00114 
00115     ol = get_objectlink();
00116     ol->objlink.ob = ob;
00117     ol->id = ob->count;
00118     /* Link the new object link to the race's list. */
00119     objectlink_link(&race->members, NULL, NULL, race->members, ol);
00120     /* Increase the number of race's members. */
00121     race->num_members++;
00122 }
00123 
00126 static int race_compare(const void *one, const void *two)
00127 {
00128     ob_race *one_race = (ob_race *) one;
00129     ob_race *two_race = (ob_race *) two;
00130 
00131     if (one == NULL)
00132     {
00133         return -1;
00134     }
00135     else if (two == NULL)
00136     {
00137         return 1;
00138     }
00139 
00140     if (one_race->name < two_race->name)
00141     {
00142         return -1;
00143     }
00144     else if (one_race->name > two_race->name)
00145     {
00146         return 1;
00147     }
00148     else
00149     {
00150         return 0;
00151     }
00152 }
00153 
00158 ob_race *race_find(shstr *name)
00159 {
00160     ob_race key;
00161 
00162     if (!races || !name)
00163     {
00164         return NULL;
00165     }
00166 
00167     key.name = name;
00168 
00169     return bsearch(&key, races, num_races, sizeof(ob_race), race_compare);
00170 }
00171 
00175 ob_race *race_get_random()
00176 {
00177     if (!races || !num_races)
00178     {
00179         return NULL;
00180     }
00181 
00182     return &races[rndm(1, num_races) - 1];
00183 }
00184 
00188 void race_init()
00189 {
00190     archetype *at, *tmp;
00191     size_t i;
00192 
00193     LOG(llevDebug, "Initializing races...");
00194 
00195     for (at = first_archetype; at; at = at->next)
00196     {
00197         if (at->clone.type == MONSTER || at->clone.type == PLAYER)
00198         {
00199             race_add(at->clone.race, &at->clone);
00200         }
00201     }
00202 
00203     /* Now search for corpses. */
00204     for (at = first_archetype; at; at = at->next)
00205     {
00206         if (at->clone.type == CONTAINER && at->clone.sub_type == ST1_CONTAINER_CORPSE)
00207         {
00208             race_add_corpse(at->clone.race, at);
00209         }
00210     }
00211 
00212     /* Try to find the default corpse archetype. */
00213     tmp = find_archetype(RACE_CORPSE_DEFAULT);
00214 
00215     if (!tmp)
00216     {
00217         LOG(llevError, "race_init(): Can't find required archetype: '%s'.\n", RACE_CORPSE_DEFAULT);
00218         return;
00219     }
00220 
00221     /* Look through the races, and assign the default corpse archetype
00222      * to those which do not have any yet. */
00223     for (i = 0; i < num_races; i++)
00224     {
00225         if (!races[i].corpse)
00226         {
00227             races[i].corpse = tmp;
00228         }
00229     }
00230 
00231     LOG(llevDebug, " done.\n");
00232 }
00233 
00236 void race_dump()
00237 {
00238     size_t i;
00239     objectlink *ol;
00240 
00241     for (i = 0; i < num_races; i++)
00242     {
00243         LOG(llevInfo, "\nRACE '%s', corpse: '%s', %d members: ", races[i].name, races[i].corpse->name, races[i].num_members);
00244 
00245         for (ol = races[i].members; ol; ol = ol->next)
00246         {
00247             LOG(llevInfo, "%s, ", ol->objlink.ob->arch->name);
00248         }
00249     }
00250 
00251     LOG(llevInfo, "\n");
00252 }
00253 
00256 void race_free()
00257 {
00258     size_t i;
00259     objectlink *ol, *ol_next;
00260 
00261     for (i = 0; i < num_races; i++)
00262     {
00263         FREE_ONLY_HASH(races[i].name);
00264 
00265         for (ol = races[i].members; ol; ol = ol_next)
00266         {
00267             ol_next = ol->next;
00268             free_objectlink_simple(ol);
00269         }
00270     }
00271 
00272     free(races);
00273     LOG(-1, "Freed %"FMT64U" races.\n", (uint64) num_races);
00274 }