Crossfire Server, Trunk  R20513
account_char.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 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 
46 #include "global.h"
47 
48 #include <assert.h>
49 #include <stdlib.h>
50 #include <string.h>
51 
52 #include "account_char.h"
53 #include "object.h"
54 #include "output_file.h"
55 #include "sproto.h"
56 
58 #define NUM_ACCOUNT_CHAR_FIELDS 8
59 
67 #define ACCOUNT_DIR "account"
68 
79 Account_Char *account_char_load(const char *account_name) {
80  char fname[MAX_BUF], buf[VERY_BIG_BUF];
81  FILE *fp;
82  Account_Char *first = NULL, *ac, *last = NULL;
83 
84  snprintf(fname, MAX_BUF, "%s/%s/%s", settings.localdir, ACCOUNT_DIR, account_name);
85  fp = fopen(fname, "r");
86  if (!fp) {
87  /* This may not in fact be a critical error - for a new account, there
88  * may not be any data associated with it.
89  */
90  LOG(llevInfo, "Warning: Unable to open %s\n", fname);
91  return NULL;
92  }
93  while (fgets(buf, VERY_BIG_BUF, fp)) {
94  char *tmp[NUM_ACCOUNT_CHAR_FIELDS], *cp;
95 
96  /* Ignore any comment lines */
97  if (buf[0] == '#') continue;
98 
99  /* remove newline */
100  cp = strchr(buf, '\n');
101  if (cp) *cp = '\0';
102 
104  if (!tmp[7]) {
105  LOG(llevInfo, "Outdated entry in %s: %s\n", fname, buf);
106  tmp[7] = (char *) add_string("0");
107  } else {
108  LOG(llevError, "Corrupt entry in %s: %s\n", fname, buf);
109  continue;
110  }
111  }
112  ac = malloc(sizeof (Account_Char));
113  ac->name = add_string(tmp[0]);
114  ac->character_class = add_string(tmp[1]);
115  ac->race = add_string(tmp[2]);
116  ac->level = strtoul(tmp[3], (char**) NULL, 10);
117  ac->face = add_string(tmp[4]);
118  ac->party = add_string(tmp[5]);
119  ac->map = add_string(tmp[6]);
120  ac->isDead = strtoul(tmp[7], (char**) NULL, 10);
121 
122  ac->next = NULL;
123 
124  /* We tack on to the end of the list - in this way,
125  * the order of the file remains the same.
126  */
127  if (last)
128  last->next = ac;
129  else
130  first = ac;
131  last = ac;
132 
133  }
134  fclose(fp);
135  return (first);
136 }
137 
145 void account_char_save(const char *account, Account_Char *chars) {
146  char fname[MAX_BUF];
147  FILE *fp;
148  OutputFile of;
149  Account_Char *ac;
150 
151  snprintf(fname, MAX_BUF, "%s/%s/%s", settings.localdir, ACCOUNT_DIR, account);
152 
153  /* It is certanly possibly that all characters for an account have
154  * been removed/deleted - in that case, we just want to remove this
155  * file.
156  */
157  if (chars == NULL) {
158  unlink(fname);
159  return;
160  }
161 
162  fp = of_open(&of, fname);
163  if (fp == NULL)
164  return;
165 
166  fprintf(fp, "# This file should not be edited while the server is running.\n");
167  fprintf(fp, "# Otherwise, any changes made may be overwritten by the server\n");
168  for (ac = chars; ac; ac = ac->next) {
169  fprintf(fp, "%s:%s:%s:%d:%s:%s:%s:%d\n",
170  ac->name, ac->character_class, ac->race, ac->level,
171  ac->face, ac->party, ac->map, ac->isDead);
172  }
173  of_close(&of);
174 }
175 
193 
194  Account_Char *ap, *last = NULL;
195 
196  for (ap = chars; ap; ap = ap->next) {
197  if (!strcmp(ap->name, pl->ob->name)) break;
198  last = ap;
199  }
200  /* If ap is not NULL, it means we found a match.
201  * Rather than checking to see if values have changed, just
202  * update them.
203  */
204  if (ap) {
205  /* We know the name can not be changing, as otherwise
206  * we wouldn't have gotten a match. So no need to
207  * update that.
208  */
209 #if 0
210  /* As of right now, the class of the character is not stored
211  * anyplace, so we don't know what it is. Keep this code here
212  * until it can be determined.
213  */
215  ap->character_class = add_string();
216 #else
217  ap->character_class = add_string("");
218 #endif
219 
220  free_string(ap->race);
221  /* This looks pretty nasty. Basically, the player object is
222  * the race archetype, but its name has been changed to the player
223  * name. So we have to go back to the actual original archetype,
224  * the clone object in there, to get the name.
225  */
226  ap->race = add_string(pl->ob->arch->clone.name);
227 
228  ap->level = pl->ob->level;
229 
230  /* We should try and get the best face (front view) of
231  * the character - right now, we just get whatever view the character
232  * happens to be facing. Unfortunately, the animation code is such
233  * that it isn't a simple matter as most of that logic is not
234  * conveniently exposed.
235  */
236  free_string(ap->face);
237  ap->face = add_string(pl->ob->face->name);
238 
239  free_string(ap->party);
240  if (pl->party)
241  ap->party = add_string(pl->party->partyname);
242  else
243  ap->party = add_string("");
244 
245  free_string(ap->map);
246 
247  /* If there is a real name set for the map, use that instead
248  * of the pathname, which is what maplevel holds. This is
249  * more friendly (eg, Scorn Inn vs /scorn/inns/....)
250  */
251  if (pl->ob->map && pl->ob->map->name) {
252  ap->map = add_string(pl->ob->map->name);
253  } else {
254  /* Use the stored value - this may not be as up to date, but is
255  * probably more reliable, as depending when this charapter is added,
256  * it may not really be on any map.
257  */
258  ap->map = add_string(pl->maplevel);
259  }
260  } else {
261  /* In this case, we are adding a new entry */
262  ap = malloc(sizeof (Account_Char));
263  ap->name = add_string(pl->ob->name);
264  ap->character_class = add_string("");
265  ap->race = add_string(pl->ob->arch->clone.name);
266  ap->level = pl->ob->level;
267  ap->face = add_string(pl->ob->face->name);
268  if (pl->party)
269  ap->party = add_string(pl->party->partyname);
270  else
271  ap->party = add_string("");
272  ap->map = add_string(pl->maplevel);
273  /* The character cannot be dead already */
274  ap->isDead = 0;
275 
276  ap->next = NULL;
277  if (last)
278  last->next = ap;
279  else
280  chars = ap;
281  }
282  return chars;
283 }
284 
296 Account_Char *account_char_remove(Account_Char *chars, const char *pl_name) {
297  Account_Char *ap, *last = NULL;
298 
299  for (ap = chars; ap; ap = ap->next) {
300  if (!strcmp(ap->name, pl_name)) break;
301  last = ap;
302  }
303  /* If we didn't find this character, nothing to do */
304  if (!ap) return (chars);
305 
306  /* As per previous notes, these should never be NULL */
307  free_string(ap->name);
309  free_string(ap->race);
310  free_string(ap->face);
311  free_string(ap->party);
312  free_string(ap->map);
313 
314  /* remove this link, or update head of list as appropriate */
315  if (last) {
316  last->next = ap->next;
317  } else {
318  chars = ap->next;
319  }
320  free(ap);
321  return (chars);
322 
323 }
324 
333  Account_Char *ap, *next;
334 
335  for (ap = chars; ap; ap = next) {
336  next = ap->next;
337 
338  free_string(ap->name);
340  free_string(ap->race);
341  free_string(ap->face);
342  free_string(ap->party);
343  free_string(ap->map);
344  free(ap);
345  }
346 }
347 
357 int make_perma_dead(object *op) {
358  player *pl = op->contr;
359  Account_Char *chars, *ac;
360 
361  if (!pl) {
362  return 1;
363  }
364  /* Is this necessary? I'm not sure. It was in the code I found to use as an example */
365  pl = get_player(pl);
366  /* Make sure there is an account name to do things to */
367  if (!pl->socket.account_name) {
368  return 1;
369  }
370 
371  /* Load the appropriate account for the action. */
373 
374  /* Find the right character. */
375  for (ac = chars; ac; ac = ac->next) {
376  if (strcmp(ac->name, op->name) == 0)
377  break;
378  }
379 
380  /* This character is dead */
381  ac->isDead = 1;
383  return 0;
384 }
385 
397 int unmake_perma_dead(char *account, char *player) {
398  Account_Char *chars, *ac;
399 
400  /*
401  * If no account name, then there is nothing to do here.
402  * The character was dead before the account was kept track of.
403  */
404  if (!account) {
405  return 1;
406  }
407 
408  /* Load the appropriate account for the action. */
409  chars = account_char_load(account);
410 
411  /* Find the right character. */
412  for (ac = chars; ac; ac = ac->next) {
413  if (strcmp(ac->name, player) == 0)
414  break;
415  }
416 
417  /* This character is alive */
418  ac->isDead = 0;
419  account_char_save(account, chars);
420  return 0;
421 }
Error, serious thing.
Definition: logger.h:11
const char * party
Character this party belonged to.
Definition: account_char.h:32
One player.
Definition: player.h:92
Information.
Definition: logger.h:12
const char * name
Name of this character/player.
Definition: account_char.h:27
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:138
void account_char_free(Account_Char *chars)
This frees all data associated with the character information.
Definition: account_char.c:332
Account_Char * account_char_load(const char *account_name)
For a given account name, load the character information and return it.
Definition: account_char.c:79
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
object clone
An object from which to do object_copy()
Definition: object.h:470
struct account_struct * next
Next in list.
Definition: account.c:85
socket_struct socket
Socket information for this player.
Definition: player.h:94
#define ACCOUNT_DIR
Name of the directory containing account information.
Definition: account_char.c:67
const char * map
Last map this character was on.
Definition: account_char.h:33
uint8_t level
Level of this character.
Definition: account_char.h:30
Global type definitions and header inclusions.
char * partyname
Party name.
Definition: party.h:14
partylist * party
Party this player is part of.
Definition: player.h:186
struct account_char_struct * next
Definition: account_char.h:35
char * name
Name of map as given by its creator.
Definition: map.h:328
const char * name
Face name, as used by archetypes and such.
Definition: face.h:20
void account_char_save(const char *account, Account_Char *chars)
Saves the character information for the given account.
Definition: account_char.c:145
#define NUM_ACCOUNT_CHAR_FIELDS
Number of fields in the accounts file.
Definition: account_char.c:58
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
#define snprintf
Definition: win32.h:46
int unmake_perma_dead(char *account, char *player)
This will edit the character account information so that the character that was just resurrected in p...
Definition: account_char.c:397
int of_close(OutputFile *of)
Closes an output file.
Definition: output_file.c:61
const char * name
The name of the object, obviously...
Definition: object.h:311
Account_Char * account_char_remove(Account_Char *chars, const char *pl_name)
This removes a character on this account.
Definition: account_char.c:296
Characters associated with an account.n.
One character account.
Definition: account_char.h:26
player * get_player(player *p)
Create a player&#39;s object, initialize a player&#39;s structure.
Definition: player.c:280
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
const char * character_class
Class of this character.
Definition: account_char.h:28
object * ob
The object representing the player.
Definition: player.h:158
Account_Char * account_char_add(Account_Char *chars, player *pl)
This adds a player to the list of accounts.
Definition: account_char.c:192
int make_perma_dead(object *op)
This will edit the character account information so that the character that just died in permadeath w...
Definition: account_char.c:357
Object structure, the core of Crossfire.
#define VERY_BIG_BUF
Definition: define.h:36
const char * localdir
Read/write data files.
Definition: global.h:245
struct archt * arch
Pointer to archetype.
Definition: object.h:412
#define unlink(__a)
Definition: win32.h:56
struct Settings settings
Server settings.
Definition: init.c:40
FILE * of_open(OutputFile *of, const char *fname)
Opens an output file.
Definition: output_file.c:30
Functions for creating text output files.
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
size_t split_string(char *str, char *array[], size_t array_size, char sep)
Splits a string delimited by passed in sep value into characters into an array of strings...
Definition: utils.c:499
char maplevel[MAX_BUF]
On which level is the player?
Definition: player.h:96
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
const New_Face * face
Face with colors.
Definition: object.h:332
int16_t level
Level of creature or object.
Definition: object.h:351
const char * face
Face of this character.
Definition: account_char.h:31
const char * race
Race of this character.
Definition: account_char.h:29
uint8_t isDead
Should stay at zero if alive, anything else if dead (hopefully 1, but doesn&#39;t have to be) ...
Definition: account_char.h:34