Atrinik Server  4.0
artifact.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #ifndef __CPROTO__
31 
32 #include <global.h>
33 #include <loader.h>
34 #include <toolkit/string.h>
35 #include <arch.h>
36 #include <artifact.h>
37 
41 #define ARTIFACT_TRIES 2
42 
43 /* Prototypes */
44 static void artifact_list_free(artifact_list_t *al);
45 static void artifact_load(void);
46 
50 void
52 {
53  artifact_load();
54 }
55 
59 void
61 {
62  artifact_list_t *al, *tmp;
63  LL_FOREACH_SAFE(first_artifactlist, al, tmp) {
65  }
66 }
67 
73 static artifact_t *artifact_new(void)
74 {
75  artifact_t *art = ecalloc(1, sizeof(*art));
76  return art;
77 }
78 
84 static void artifact_free(artifact_t *art)
85 {
86  HARD_ASSERT(art != NULL);
87 
88  free_string_shared(art->def_at_name);
89 
90  SHSTR_LIST_CLEAR(art->allowed);
91 
92  if (art->parse_text != NULL) {
93  efree(art->parse_text);
94  }
95 
96  if (art->affinity != NULL) {
97  free_string_shared(art->affinity);
98  }
99 
100  efree(art);
101 }
102 
109 {
110  artifact_list_t *al = ecalloc(1, sizeof(*al));
111  return al;
112 }
113 
121 {
122  artifact_t *art, *tmp;
123  LL_FOREACH_SAFE(al->items, art, tmp) {
124  artifact_free(art);
125  }
126 
127  efree(al);
128 }
129 
133 void artifact_load(void)
134 {
135  char filename[MAX_BUF];
136  snprintf(VS(filename), "%s/artifacts", settings.libpath);
137  FILE *fp = fopen(filename, "rb");
138  if (fp == NULL) {
139  LOG(ERROR, "Can't open %s.", filename);
140  exit(1);
141  }
142 
143  char buf[HUGE_BUF];
144  uint64_t linenum = 0;
145  artifact_t *art = NULL;
146  shstr *name = NULL;
147  bool allowed_none = false;
148 
149  while (fgets(VS(buf), fp) != NULL) {
150  linenum++;
151 
152  char *cp = buf;
153  string_skip_whitespace(cp);
154  string_strip_newline(cp);
155 
156  char *cps[2];
157  if (string_split(cp, cps, arraysize(cps), ' ') < 1) {
158  continue;
159  }
160 
161  const char *key = cps[0], *value = cps[1], *error_str = NULL;
162 
163  /* We have a single artifact */
164  if (strcmp(key, "Allowed") == 0) {
165  if (art != NULL) {
166  error_str = "duplicated Allowed attribute";
167  goto error;
168  }
169 
170  art = artifact_new();
171  allowed_none = false;
172 
173  if (strcmp(value, "all") == 0) {
174  continue;
175  }
176 
177  if (strcmp(value, "none") == 0) {
178  allowed_none = true;
179  continue;
180  }
181 
182  char word[MAX_BUF], *word2;
183  size_t pos = 0;
184  while (string_get_word(value, &pos, ',', VS(word), 0)) {
185  word2 = word;
186  if (*word == '!') {
187  word2++;
188  art->disallowed = true;
189  }
190  SHSTR_LIST_PREPEND(art->allowed, word2);
191  }
192  } else if (art == NULL) {
193  error_str = "expected Allowed attribute";
194  goto error;
195  } else if (strcmp(key, "affinity") == 0) {
196  if (art->affinity != NULL) {
197  error_str = "duplicated affinity attribute";
198  goto error;
199  }
200 
201  art->affinity = add_string(value);
202  } else if (strcmp(key, "chance") == 0) {
203  if (!string_isdigit(value)) {
204  error_str = "chance attribute expects a number";
205  goto error;
206  }
207 
208  int val = atoi(value);
209  if (val < 0 || val > UINT16_MAX) {
210  error_str = "invalid value for chance attribute";
211  goto error;
212  }
213 
214  art->chance = (uint16_t) val;
215  } else if (strcmp(key, "difficulty") == 0) {
216  if (!string_isdigit(value)) {
217  error_str = "difficulty attribute expects a number";
218  goto error;
219  }
220 
221  int val = atoi(value);
222  if (val < 0 || val > UINT8_MAX) {
223  error_str = "invalid value for difficulty attribute";
224  goto error;
225  }
226 
227  art->difficulty = (uint8_t) val;
228  } else if (strcmp(key, "artifact") == 0) {
229  if (name != NULL) {
230  error_str = "duplicated artifact attribute";
231  goto error;
232  }
233 
234  name = add_string(value);
235  } else if (strcmp(key, "copy_artifact") == 0) {
236  if (KEYWORD_IS_TRUE(value)) {
237  art->copy_artifact = true;
238  } else if (KEYWORD_IS_FALSE(value)) {
239  art->copy_artifact = false;
240  } else {
241  error_str = "invalid value for copy_artifact attribute";
242  goto error;
243  }
244  } else if (strcmp(key, "def_arch") == 0) {
245  if (art->def_at != NULL) {
246  error_str = "duplicated def_arch attribute";
247  goto error;
248  }
249 
250  archetype_t *at = arch_find(value);
251  if (at == NULL) {
252  error_str = "unknown archetype";
253  goto error;
254  }
255 
256  art->def_at = arch_clone(at);
257  art->def_at_name = add_string(value);
258  } else if (strcmp(key, "Object") == 0) {
259  if (name == NULL) {
260  error_str = "artifact is missing name";
261  goto error;
262  }
263 
264  if (art->def_at == NULL) {
265  error_str = "artifact is missing def_arch";
266  goto error;
267  }
268 
269  if (art->chance == 0) {
270  error_str = "artifact has no chance set";
271  goto error;
272  }
273 
274  long old_pos = ftell(fp);
275  if (old_pos == -1) {
276  LOG(ERROR, "ftell() failed: %s (%d)", strerror(errno), errno);
277  error_str = "general failure";
278  goto error;
279  }
280 
281  if (load_object_fp(fp,
282  &art->def_at->clone,
283  MAP_STYLE) != LL_NORMAL) {
284  error_str = "could not load object";
285  goto error;
286  }
287 
288  /* This should never happen, because arch name is normally set
289  * by the Flex loader only if it encounters "object xxx" */
290  if (art->def_at->name != NULL) {
291  error_str = "artifact def_at already has a name";
292  goto error;
293  }
294 
295  art->def_at->name = name;
296 
297  long file_pos = ftell(fp);
298  if (file_pos == -1) {
299  LOG(ERROR, "ftell() failed: %s (%d)", strerror(errno), errno);
300  error_str = "general failure";
301  goto error;
302  }
303 
304  if (fseek(fp, old_pos, SEEK_SET) != 0) {
305  LOG(ERROR, "Could not fseek() to %ld: %s (%d)", old_pos,
306  strerror(errno), errno);
307  error_str = "general failure";
308  goto error;
309  }
310 
311  StringBuffer *sb = stringbuffer_new();
312  while (fgets(VS(buf), fp) != NULL) {
313  linenum++;
314  stringbuffer_append_string(sb, buf);
315 
316  long pos = ftell(fp);
317  if (pos == -1) {
318  LOG(ERROR, "ftell() failed: %s (%d)", strerror(errno),
319  errno);
320  error_str = "general failure";
321  goto error;
322  }
323 
324  if (pos == file_pos) {
325  break;
326  }
327 
328  if (pos > file_pos) {
329  LOG(ERROR, "fgets() read too much data, at: %ld, should "
330  "be: %ld", pos, file_pos);
331  error_str = "general failure";
332  goto error;
333  }
334  }
335 
336  /* Flex loader needs an extra NUL at the end. */
337  stringbuffer_append_char(sb, '\0');
338  art->parse_text = stringbuffer_finish(sb);
339 
340  /* Determine the type; if 'Allowed none', then type is 0. */
341  uint8_t type = allowed_none ? 0 : art->def_at->clone.type;
342 
343  /* Add it to the appropriate artifact list */
345  if (al == NULL) {
346  al = artifact_list_new();
347  al->type = type;
348  LL_PREPEND(first_artifactlist, al);
349  }
350 
351  LL_PREPEND(al->items, art);
352  arch_add(art->def_at);
353 
354  art = NULL;
355  name = NULL;
356  } else {
357  error_str = "unrecognized attribute";
358  goto error;
359  }
360 
361  continue;
362 error:
363  LOG(ERROR, "Error parsing %s, line %" PRIu64 ", %s: %s %s", filename,
364  linenum, error_str != NULL ? error_str : "",
365  key != NULL ? key : "", value != NULL ? value : "");
366  exit(1);
367  }
368 
369  fclose(fp);
370 
371  if (art != NULL) {
372  LOG(ERROR, "Artifacts file has no end: %s", filename);
373  exit(1);
374  }
375 
376  artifact_list_t *al;
377  LL_FOREACH(first_artifactlist, al) {
378  if (al->type == 0) {
379  continue;
380  }
381 
382  LL_FOREACH(al->items, art) {
383  al->total_chance += art->chance;
384  }
385  }
386 }
387 
398 {
399  for (artifact_list_t *al = first_artifactlist; al != NULL; al = al->next) {
400  if (al->type == type) {
401  return al;
402  }
403  }
404 
405  return NULL;
406 }
407 
418 artifact_t *
419 artifact_find_type (const char *name, uint8_t type)
420 {
421  HARD_ASSERT(name != NULL);
422 
424  if (al == NULL) {
425  return NULL;
426  }
427 
428  for (artifact_t *art = al->items; art != NULL; art = art->next) {
429  if (strcmp(art->def_at->name, name) == 0) {
430  return art;
431  }
432  }
433 
434  return NULL;
435 }
436 
445 void
447 {
448  if (art->copy_artifact) {
449  object_copy_full(op, &art->def_at->clone);
450  return;
451  }
452 
453  int64_t tmp_value = op->value;
454  op->value = 0;
455 
456  if (load_object(art->parse_text, op, MAP_ARTIFACT) != LL_NORMAL) {
457  LOG(ERROR, "load_object() error, art: %s, object: %s",
458  art->def_at->name, object_get_str(op));
459  }
460 
462 
463  /* This will solve the problem to adjust the value for different
464  * items of same artification. Also we can safely use negative
465  * values. */
466  op->value += tmp_value;
467 
468  if (op->value < 0) {
469  op->value = 0;
470  }
471 }
472 
488 static bool
490  object *op,
491  int difficulty,
492  treasure_affinity_t *affinity)
493 {
494  HARD_ASSERT(art != NULL);
495  HARD_ASSERT(op != NULL);
496 
497  if (difficulty < art->difficulty) {
498  return false;
499  }
500 
501  if (affinity != NULL &&
502  art->affinity != NULL &&
503  art->affinity != affinity) {
504  return false;
505  }
506 
507  /* 'Allowed all' */
508  if (art->allowed == NULL) {
509  return true;
510  }
511 
512  if (op->arch == NULL) {
513  return false;
514  }
515 
516  bool ret = art->disallowed;
517  SHSTR_LIST_FOR_PREPARE(art->allowed, name) {
518  if (op->arch->name == name) {
519  return !ret;
520  }
521  } SHSTR_LIST_FOR_FINISH();
522 
523  return ret;
524 }
525 
540 bool
541 artifact_generate (object *op,
542  int difficulty,
543  treasure_affinity_t *affinity)
544 {
546  if (al == NULL) {
547  return 0;
548  }
549 
550  for (int i = 0; i < ARTIFACT_TRIES; i++) {
551  int roll = rndm(0, al->total_chance - 1);
552 
553  artifact_t *art;
554  for (art = al->items; art != NULL; art = art->next) {
555  roll -= art->chance;
556 
557  if (roll < 0) {
558  break;
559  }
560  }
561 
562  if (art == NULL || roll >= 0) {
563  LOG(ERROR, "Could not find artifact type %d", op->type);
564  return false;
565  }
566 
567  if (!artifact_can_combine(art, op, difficulty, affinity)) {
568  continue;
569  }
570 
571  artifact_change_object(art, op);
572  return true;
573  }
574 
575  /* If we are here then we failed to generate an artifact by chance. */
576  for (artifact_t *art = al->items; art != NULL; art = art->next) {
577  if (art->chance <= 0) {
578  continue;
579  }
580 
581  if (!artifact_can_combine(art, op, difficulty, affinity)) {
582  continue;
583  }
584 
585  artifact_change_object(art, op);
586  return true;
587  }
588 
589  return false;
590 }
591 
592 #endif
#define FREE_AND_ADD_REF_HASH(_sv_, _nv_)
Definition: global.h:116
bool artifact_generate(object *op, int difficulty, treasure_affinity_t *affinity)
Definition: artifact.c:541
struct artifact * items
Artifacts in this artifact list.
Definition: artifact.h:84
static artifact_list_t * artifact_list_new(void)
Definition: artifact.c:108
uint8_t type
One of operation types.
Definition: sound_ambient.c:45
archetype_t * arch_clone(archetype_t *at)
Definition: arch.c:464
#define LL_NORMAL
Object was successfully loaded.
Definition: loader.h:40
static void artifact_load(void)
Definition: artifact.c:133
void arch_add(archetype_t *at)
Definition: arch.c:390
struct archetype * arch
Definition: object.h:225
char libpath[MAX_BUF]
Definition: global.h:338
struct artifact_list * first_artifactlist
Definition: main.c:63
void artifact_change_object(artifact_t *art, object *op)
Definition: artifact.c:446
shstr_list_t * allowed
List of allowed archetypes.
Definition: artifact.h:41
char * parse_text
Definition: artifact.h:46
const char * object_get_str(const object *op)
Definition: object.c:3151
Definition: arch.h:40
uint8_t type
Definition: artifact.h:91
uint8_t difficulty
Difficulty.
Definition: artifact.h:64
int load_object_fp(FILE *fp, object *op, int map_flags)
Definition: object.c:48576
bool copy_artifact
Definition: artifact.h:70
struct artifact_list * next
Next list.
Definition: artifact.h:82
#define MAP_ARTIFACT
Definition: map.h:155
void artifact_deinit(void)
Definition: artifact.c:60
shstr * def_at_name
Definition: artifact.h:56
artifact_t * artifact_find_type(const char *name, uint8_t type)
Definition: artifact.c:419
static void artifact_free(artifact_t *art)
Definition: artifact.c:84
#define ARTIFACT_TRIES
Definition: artifact.c:41
void artifact_init(void)
Definition: artifact.c:51
artifact_list_t * artifact_list_find(uint8_t type)
Definition: artifact.c:397
struct settings_struct settings
Definition: init.c:55
static void artifact_list_free(artifact_list_t *al)
Definition: artifact.c:120
bool disallowed
Definition: artifact.h:75
uint8_t type
Definition: object.h:360
shstr * name
More definite name, like "kobold".
Definition: arch.h:46
static artifact_t * artifact_new(void)
Definition: artifact.c:73
shstr * artifact
Definition: object.h:187
#define MAP_STYLE
Definition: map.h:153
treasure_affinity_t * affinity
Definition: artifact.h:61
struct archetype * def_at
Definition: artifact.h:51
void object_copy_full(object *op, const object *src)
Definition: object.c:970
static bool artifact_can_combine(artifact_t *art, object *op, int difficulty, treasure_affinity_t *affinity)
Definition: artifact.c:489
int64_t value
Definition: object.h:240
uint16_t total_chance
Sum of chance for all artifacts on this list.
Definition: artifact.h:85
object clone
An object from which to do object_copy().
Definition: arch.h:47
archetype_t * arch_find(const char *name)
Definition: arch.c:407
int load_object(const char *str, object *op, int map_flags)
Definition: object.c:48527
struct artifact * next
Next artifact in the list.
Definition: artifact.h:40
uint16_t chance
Chance.
Definition: artifact.h:63