Crossfire Server, Trunk
exp.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include "global.h"
20 
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 int64_t *levels;
28 static const float exp_att_mult[NROFATTACKS] = {
29  0.0, /* AT_PHYSICAL */
30  0.0, /* AT_MAGIC */
31  0.0, /* AT_FIRE */
32  0.0, /* AT_ELECTRICITY */
33  0.0, /* AT_COLD */
34  0.0, /* AT_CONFUSION */
35  0.4, /* AT_ACID */
36  1.5, /* AT_DRAIN */
37  0.0, /* AT_WEAPONMAGIC */
38  0.1, /* AT_GHOSTHIT */
39  0.3, /* AT_POISON */
40  0.1, /* AT_SLOW */
41  0.3, /* AT_PARALYZE */
42  0.0, /* AT_TURN_UNDEAD */
43  0.0, /* AT_FEAR */
44  0.0, /* AT_CANCELLATION */
45  0.0, /* AT_DEPLETE */
46  0.0, /* AT_DEATH */
47  0.0, /* AT_CHAOS */
48  0.0, /* AT_COUNTERSPELL */
49  0.5, /* AT_GODPOWER */
50  0.1, /* AT_HOLYWORD */
51  0.2, /* AT_BLIND */
52  0.0, /* AT_INTERNAL */
53  0.5, /* AT_LIFE_STEALING */
54  0.2, /* AT_DISEASE */
55 };
56 
57 static const float exp_prot_mult[NROFATTACKS] = {
58  0.4, /* AT_PHYSICAL */
59  0.5, /* AT_MAGIC */
60  0.1, /* AT_FIRE */
61  0.1, /* AT_ELECTRICITY */
62  0.1, /* AT_COLD */
63  0.1, /* AT_CONFUSION */
64  0.1, /* AT_ACID */
65  0.1, /* AT_DRAIN */
66  0.1, /* AT_WEAPONMAGIC */
67  0.1, /* AT_GHOSTHIT */
68  0.1, /* AT_POISON */
69  0.0, /* AT_SLOW */
70  0.1, /* AT_PARALYZE */
71  0.1, /* AT_TURN_UNDEAD */
72  0.1, /* AT_FEAR */
73  0.0, /* AT_CANCELLATION */
74  0.0, /* AT_DEPLETE */
75  0.0, /* AT_DEATH */
76  0.0, /* AT_CHAOS */
77  0.0, /* AT_COUNTERSPELL */
78  0.0, /* AT_GODPOWER */
79  0.1, /* AT_HOLYWORD */
80  0.0, /* AT_BLIND */
81  0.0, /* AT_INTERNAL */
82  0.0, /* AT_LIFE_STEALING */
83  0.1, /* AT_DISEASE */
84 };
85 
100 int64_t new_exp(const object *ob) {
101  double att_mult, prot_mult, spec_mult;
102  double exp;
103  int i;
104  long mask = 1;
105 
106  att_mult = prot_mult = spec_mult = 1.0;
107  for (i = 0; i < NROFATTACKS; i++) {
108  mask = 1<<i;
109  att_mult += (exp_att_mult[i]*((ob->attacktype&mask) != FALSE));
110  /* We multiply & then divide to prevent roundoffs on the floats.
111  * the doubling is to take into account the table and resistances
112  * are lower than they once were.
113  */
114  /* prot_mult should increase by fairly minor amounts -
115  * for example, if a creature has resist physical 30,
116  * and exp mult on that is 0.4, then prot_mult should really
117  * go up by 1.2 - still a considerable increase.
118  */
119  prot_mult += (exp_prot_mult[i]*ob->resist[i])/10.0;
120  }
121 
122  if (prot_mult < 0)
123  prot_mult = 1;
124 
125  spec_mult += (0.3*(QUERY_FLAG(ob, FLAG_SEE_INVISIBLE) != FALSE))+
126  (0.5*(QUERY_FLAG(ob, FLAG_SPLITTING) != FALSE))+
127  (0.3*(QUERY_FLAG(ob, FLAG_HITBACK) != FALSE))+
128  (0.1*(QUERY_FLAG(ob, FLAG_REFL_MISSILE) != FALSE))+
129  (0.3*(QUERY_FLAG(ob, FLAG_REFL_SPELL) != FALSE))+
130  (1.0*(QUERY_FLAG(ob, FLAG_NO_MAGIC) != FALSE))+
131  (0.1*(QUERY_FLAG(ob, FLAG_USE_SCROLL) != FALSE))+
132  (0.2*(QUERY_FLAG(ob, FLAG_USE_RANGE) != FALSE))+
133  (0.1*(QUERY_FLAG(ob, FLAG_USE_BOW) != FALSE));
134 
135  exp = MAX(ob->stats.maxhp, 5);
136  exp *= (QUERY_FLAG(ob, FLAG_CAST_SPELL) && has_ability(ob)) ? (40+MIN(ob->stats.maxsp, 80))/40 : 1;
137  exp *= (80.0/(70.0+ob->stats.wc))*(80.0/(70.0+ob->stats.ac))*(50.0+ob->stats.dam)/50.0;
138  exp *= att_mult*prot_mult*spec_mult;
139 /* exp *= 2.0/(2.0-(MIN(FABS(ob->speed), 0.95)));*/
140  exp *= 2.0/(2.0-FABS(ob->speed));
141  exp *= (20.0+ob->stats.Con)/20.0;
143  exp /= 2;
144 
145  return (int64_t)exp;
146 }
147 
153 int has_ability(const object *ob) {
154  return object_find_by_type(ob, SPELL) != NULL || object_find_by_type(ob, SPELLBOOK) != NULL;
155 }
156 
167 void init_experience(void) {
168  char buf[MAX_BUF], *cp;
169  int lastlevel = 0;
170  int64_t lastexp = -1, tmpexp;
171  FILE *fp;
172 
173  snprintf(buf, sizeof(buf), "%s/exp_table", settings.confdir);
174  if ((fp = fopen(buf, "r")) == NULL) {
175  LOG(llevError, "Fatal error: could not open experience table (%s)\n", buf);
176  exit(1);
177  }
178  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
179  if (buf[0] == '#')
180  continue;
181 
182  /* eliminate newline */
183  if ((cp = strrchr(buf, '\n')) != NULL)
184  *cp = '\0';
185 
186  /* Skip over empty lines and whitespace */
187  cp = buf;
188  while (isspace(*cp) && *cp != 0)
189  cp++;
190  if ( *cp == 0 ) continue;
191 
192  /* Set max_level */
193  if (!strncasecmp(cp, "max_level", 9)) {
194  if (settings.max_level) {
195  LOG(llevDebug, "Got more than one max_level value from exp_table file?\n");
196  free(levels);
197  }
198  int ml = atoi(cp + 9);
199  if (ml <= 0 || ml > 10000) {
200  LOG(llevError, "max_level must be between 1 and 10000\n");
202  }
203  settings.max_level = ml;
204  levels = calloc(settings.max_level+1, sizeof(int64_t));
205  }
206  while (isdigit(*cp) && *cp != 0) {
207  if (!settings.max_level) {
208  LOG(llevError, "max_level is not set in exp_table file. Did you remember to update it?\n");
209  exit(1);
210  }
211 
212  tmpexp = atoll(cp);
213  /* Do some sanity checking - if value is bogus, just exit because
214  * the table otherwise is probably in an inconsistent state
215  */
216  if (tmpexp <= lastexp) {
217  LOG(llevError, "Experience for level %d is lower than previous level (%"FMT64" <= %"FMT64")\n", lastlevel+1, tmpexp, lastexp);
218  exit(1);
219  }
220  lastlevel++;
221  if (lastlevel > settings.max_level) {
222  LOG(llevError, "Too many levels specified in table (%d > %d)\n", lastlevel, settings.max_level);
223  exit(1);
224  }
225  levels[lastlevel] = tmpexp;
226  lastexp = tmpexp;
227  /* First, skip over the number we just processed. Then skip over
228  * any spaces, commas, etc.
229  */
230  while (isdigit(*cp) && *cp != 0)
231  cp++;
232  while (!isdigit(*cp) && *cp != 0)
233  cp++;
234  }
235  }
236  fclose(fp);
237  if (settings.max_level == 0 || lastlevel != settings.max_level) {
238  LOG(llevError, "Fatal: exp_table does not have any level definition or not %d as defined, found %d.\n", settings.max_level, lastlevel);
239  exit(1);
240  }
241  if (lastlevel != settings.max_level && lastlevel != 0) {
242  LOG(llevError, "Warning: exp_table does not have %d entries (%d)\n", settings.max_level, lastlevel);
243  exit(1);
244  }
245 }
246 
251 void dump_experience(void) {
252  int i;
253 
254  for (i = 1; i <= settings.max_level; i++) {
255  fprintf(logfile, "%4d %20"FMT64"\n", i, levels[i]);
256  }
257  exit(0);
258 }
259 
263 void free_experience(void) {
265 }
FLAG_USE_BOW
#define FLAG_USE_BOW
Definition: define.h:293
global.h
new_exp
int64_t new_exp(const object *ob)
Definition: exp.c:100
Settings::max_level
int16_t max_level
Definition: global.h:297
FLAG_STAND_STILL
#define FLAG_STAND_STILL
Definition: define.h:308
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
FLAG_REFL_MISSILE
#define FLAG_REFL_MISSILE
Definition: define.h:273
FALSE
#define FALSE
Definition: compat.h:14
guildjoin.ob
ob
Definition: guildjoin.py:42
FLAG_SEE_INVISIBLE
#define FLAG_SEE_INVISIBLE
Definition: define.h:253
MIN
#define MIN(x, y)
Definition: compat.h:21
FLAG_NO_MAGIC
#define FLAG_NO_MAGIC
Definition: define.h:276
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
levels
int64_t * levels
Definition: exp.c:26
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
free_experience
void free_experience(void)
Definition: exp.c:263
MAX
#define MAX(x, y)
Definition: compat.h:24
exp_prot_mult
static const float exp_prot_mult[NROFATTACKS]
Definition: exp.c:57
settings
struct Settings settings
Definition: init.c:39
FMT64
#define FMT64
Definition: compat.h:16
FLAG_USE_RANGE
#define FLAG_USE_RANGE
Definition: define.h:292
fatal
void fatal(enum fatal_error err)
Definition: utils.c:580
Settings::confdir
const char * confdir
Definition: global.h:242
logfile
EXTERN FILE * logfile
Definition: global.h:134
FLAG_SPLITTING
#define FLAG_SPLITTING
Definition: define.h:266
FLAG_HITBACK
#define FLAG_HITBACK
Definition: define.h:267
MAX_BUF
#define MAX_BUF
Definition: define.h:35
exp_att_mult
static const float exp_att_mult[NROFATTACKS]
Definition: exp.c:28
FLAG_REFL_SPELL
#define FLAG_REFL_SPELL
Definition: define.h:275
has_ability
int has_ability(const object *ob)
Definition: exp.c:153
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Definition: global.h:190
FLAG_CAST_SPELL
#define FLAG_CAST_SPELL
Definition: define.h:290
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
object_find_by_type
object * object_find_by_type(const object *who, int type)
Definition: object.c:3951
buf
StringBuffer * buf
Definition: readable.c:1610
dump_experience
void dump_experience(void)
Definition: exp.c:251
SPELL
@ SPELL
Definition: object.h:214
init_experience
void init_experience(void)
Definition: exp.c:167
FLAG_USE_SCROLL
#define FLAG_USE_SCROLL
Definition: define.h:291
SPELLBOOK
@ SPELLBOOK
Definition: object.h:203
llevDebug
@ llevDebug
Definition: logger.h:13