Crossfire Server, Branch 1.12  R12190
exp.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_arch_c =
00003  *   "$Id: exp.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 
00006 /*
00007     CrossFire, A Multiplayer game for X-windows
00008 
00009     Copyright (C) 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 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <global.h>
00038 
00039 sint64 *levels; 
00041 #define TRUE 1
00042 #define FALSE 0
00043 
00044 static const float exp_att_mult[NROFATTACKS+2] = {
00045     0.0,    /* AT_PHYSICAL */
00046     0.0,    /* AT_MAGIC */
00047     0.0,    /* AT_FIRE */
00048     0.0,    /* AT_ELECTRICITY */
00049     0.0,    /* AT_COLD */
00050     0.0,    /* AT_WATER *//*AT_CONFUSION!*/
00051     0.4,    /* AT_ACID */
00052     1.5,    /* AT_DRAIN */
00053     0.0,    /* AT_WEAPONMAGIC */
00054     0.1,    /* AT_GHOSTHIT */
00055     0.3,    /* AT_POISON */
00056     0.2,    /* AT_DISEASE */
00057     0.3,    /* AT_PARALYZE */
00058     0.0,    /* AT_TURN_UNDEAD */
00059     0.0,    /* AT_FEAR */
00060     0.0,    /* AT_CANCELLATION */
00061     0.0,    /* AT_DEPLETE */
00062     0.0,    /* AT_DEATH */
00063     0.0,    /* AT_CHAOS */
00064     0.0     /* AT_COUNTERSPELL */
00065 };
00066 
00067 static const float exp_prot_mult[NROFATTACKS+2] = {
00068     0.4,    /* AT_PHYSICAL */
00069     0.5,    /* AT_MAGIC */
00070     0.1,    /* AT_FIRE */
00071     0.1,    /* AT_ELECTRICITY */
00072     0.1,    /* AT_COLD */
00073     0.1,    /* AT_WATER */
00074     0.1,    /* AT_ACID */
00075     0.1,    /* AT_DRAIN */
00076     0.1,    /* AT_WEAPONMAGIC */
00077     0.1,    /* AT_GHOSTHIT */
00078     0.1,    /* AT_POISON */
00079     0.1,    /* AT_DISEASE */
00080     0.1,    /* AT_PARALYZE */
00081     0.1,    /* AT_TURN_UNDEAD */
00082     0.1,    /* AT_FEAR */
00083     0.0,    /* AT_CANCELLATION */
00084     0.0,    /* AT_DEPLETE */
00085     0.0,    /* AT_DEATH */
00086     0.0,    /* AT_CHAOS */
00087     0.0     /* AT_COUNTERSPELL */
00088 };
00089 
00104 sint64 new_exp(const object *ob) {
00105     double att_mult, prot_mult, spec_mult;
00106     double exp;
00107     int i;
00108     long mask = 1;
00109 
00110     att_mult = prot_mult = spec_mult = 1.0;
00111     for (i = 0; i < NROFATTACKS; i++) {
00112         mask = 1<<i;
00113         att_mult += (exp_att_mult[i]*((ob->attacktype&mask) != FALSE));
00114         /* We multiply & then divide to prevent roundoffs on the floats.
00115          * the doubling is to take into account the table and resistances
00116          * are lower than they once were.
00117          */
00118         prot_mult += (exp_prot_mult[i] * 200 * ob->resist[i]) / 100.0;
00119     }
00120 
00121     if (prot_mult < 0)
00122         prot_mult = 1;
00123 
00124     spec_mult += (0.3*(QUERY_FLAG(ob, FLAG_SEE_INVISIBLE) != FALSE))+
00125                  (0.5*(QUERY_FLAG(ob, FLAG_SPLITTING) != FALSE))+
00126                  (0.3*(QUERY_FLAG(ob, FLAG_HITBACK) != FALSE))+
00127                  (0.1*(QUERY_FLAG(ob, FLAG_REFL_MISSILE) != FALSE))+
00128                  (0.3*(QUERY_FLAG(ob, FLAG_REFL_SPELL) != FALSE))+
00129                  (1.0*(QUERY_FLAG(ob, FLAG_NO_MAGIC) != FALSE))+
00130                  (0.1*(QUERY_FLAG(ob, FLAG_USE_SCROLL) != FALSE))+
00131                  (0.2*(QUERY_FLAG(ob, FLAG_USE_RANGE) != FALSE))+
00132                  (0.1*(QUERY_FLAG(ob, FLAG_USE_BOW) != FALSE));
00133 
00134     exp = MAX(ob->stats.maxhp, 5);
00135     exp *= (QUERY_FLAG(ob, FLAG_CAST_SPELL) && has_ability(ob)) ? (40+MIN(ob->stats.maxsp, 80))/40 : 1;
00136     exp *= (80.0/(70.0+ob->stats.wc))*(80.0/(70.0+ob->stats.ac))*(50.0+ob->stats.dam)/50.0;
00137     exp *= att_mult*prot_mult*spec_mult;
00138     exp *= 2.0/(2.0-(MIN(FABS(ob->speed), 0.95)));
00139     exp *= (20.0+ob->stats.Con)/20.0;
00140     if (QUERY_FLAG(ob, FLAG_STAND_STILL))
00141         exp /= 2;
00142 
00143     return (sint64)exp;
00144 }
00145 
00151 int has_ability(const object *ob) {
00152     object *tmp;
00153 
00154     for (tmp = ob->inv; tmp != NULL; tmp = tmp->below)
00155         if (tmp->type == SPELL || tmp->type == SPELLBOOK)
00156             return TRUE;
00157     return FALSE;
00158 }
00159 
00170 void init_experience(void) {
00171     char buf[MAX_BUF], *cp;
00172     int lastlevel = 0, comp;
00173     sint64 lastexp = -1, tmpexp;
00174     FILE *fp;
00175 
00176     snprintf(buf, sizeof(buf), "%s/exp_table", settings.confdir);
00177 
00178     if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL) {
00179         LOG(llevError, "Fatal error: could not open experience table (%s)\n", buf);
00180         exit(1);
00181     }
00182     while (fgets(buf, MAX_BUF-1, fp) != NULL) {
00183         if (buf[0] == '#')
00184             continue;
00185 
00186         /* eliminate newline */
00187         if ((cp = strrchr(buf, '\n')) != NULL)
00188             *cp = '\0';
00189 
00190         /* Skip over empty lines */
00191         if (buf[0] == 0)
00192             continue;
00193         cp = buf;
00194         while (isspace(*cp) && *cp != 0)
00195             cp++;
00196         if (!strncasecmp(cp, "max_level", 9)) {
00197             if (settings.max_level) {
00198                 LOG(llevDebug, "Got more than one max_level value from exp_table file?\n");
00199                 free(levels);
00200             }
00201             settings.max_level = atoi(cp+9);
00202             if (!settings.max_level) {
00203                 LOG(llevDebug, "Got invalid max_level from exp_table file? %s\n", buf);
00204             } else {
00205                 levels = calloc(settings.max_level+1, sizeof(sint64));
00206             }
00207         }
00208         while (isdigit(*cp) && *cp != 0) {
00209             if (!settings.max_level) {
00210                 LOG(llevError, "max_level is not set in exp_table file.  Did you remember to update it?\n");
00211                 exit(1);
00212             }
00213 
00214             tmpexp = atoll(cp);
00215             /* Do some sanity checking - if value is bogus, just exit because
00216              * the table otherwise is probably in an inconsistent state
00217              */
00218             if (tmpexp <= lastexp) {
00219 #ifndef WIN32
00220                 LOG(llevError, "Experience for level %d is lower than previous level (%lld <= %lld)\n", lastlevel+1, tmpexp, lastexp);
00221 #else
00222                 LOG(llevError, "Experience for level %d is lower than previous level (%I64d <= %I64d)\n", lastlevel+1, tmpexp, lastexp);
00223 #endif
00224                 exit(1);
00225             }
00226             lastlevel++;
00227             if (lastlevel > settings.max_level) {
00228                 LOG(llevError, "Too many levels specified in table (%d > %d)\n", lastlevel, settings.max_level);
00229                 exit(1);
00230             }
00231             levels[lastlevel] = tmpexp;
00232             lastexp = tmpexp;
00233             /* First, skip over the number we just processed. Then skip over
00234              * any spaces, commas, etc.
00235              */
00236             while (isdigit(*cp) && *cp != 0)
00237                 cp++;
00238             while (!isdigit(*cp) && *cp != 0)
00239                 cp++;
00240         }
00241     }
00242     close_and_delete(fp, comp);
00243     if (settings.max_level == 0 || lastlevel != settings.max_level) {
00244         LOG(llevError, "Fatal: exp_table does not have any level definition or not %d as defined, found %d.\n", settings.max_level, lastlevel);
00245         exit(1);
00246     }
00247     if (lastlevel != settings.max_level && lastlevel != 0) {
00248         LOG(llevError, "Warning: exp_table does not have %d entries (%d)\n", settings.max_level, lastlevel);
00249         exit(1);
00250     }
00251 }
00252 
00257 void dump_experience(void) {
00258     int i;
00259 
00260     for (i = 1; i <= settings.max_level; i++) {
00261         fprintf(logfile, "%4d %20"FMT64"\n", i, levels[i]);
00262     }
00263     exit(0);
00264 }
00265 
00269 void free_experience(void) {
00270     FREE_AND_CLEAR(levels);
00271 }