Atrinik Server  4.0
faction.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 
32 #ifndef __CPROTO__
33 
34 #include <global.h>
35 #include <faction.h>
36 #include <toolkit/string.h>
37 #include <player.h>
38 #include <object.h>
39 
44 typedef struct faction_parent {
50  union {
51  shstr *name;
53  } faction;
54 
60  int16_t spill;
61 
66  int16_t attention;
67 
71  bool spill_force:1;
73 
77 typedef struct faction_enemy {
83  union {
84  shstr *name;
86  } faction;
88 
92 struct faction {
93  shstr *name;
94 
95  UT_hash_handle hh;
96 
98  size_t parents_num;
99 
101  size_t enemies_num;
102 
103  struct faction **children;
104  size_t children_num;
105 
110  int16_t modifier;
111 
115  double penalty;
116 
121  double threshold;
122 
126  bool alliance:1;
127 };
128 
133 
134 /* Prototypes */
135 
136 static faction_t faction_create(const char *name, faction_t parent);
137 static void faction_free(faction_t faction);
138 static void faction_add_parent(faction_t faction, shstr *name);
139 static void faction_assign_names(void);
140 
141 TOOLKIT_API(DEPENDS(shstr));
142 
144 {
145  char filename[HUGE_BUF];
146  snprintf(VS(filename), "%s/factions", settings.libpath);
147 
148  FILE *fp = fopen(filename, "r");
149 
150  if (fp == NULL) {
151  LOG(ERROR, "Can't open factions file %s: %s (%d)", filename,
152  strerror(errno), errno);
153  exit(1);
154  }
155 
156  factions = NULL;
157 
158  char buf[HUGE_BUF];
159  uint64_t linenum = 0;
160  faction_t faction_stack[50];
161  size_t depth = 0;
162 
163  while (fgets(VS(buf), fp)) {
164  linenum++;
165 
166  char *cp = buf;
167  string_skip_whitespace(cp);
168  string_strip_newline(cp);
169 
170  char *cps[2];
171 
172  if (string_split(cp, cps, arraysize(cps), ' ') < 1) {
173  continue;
174  }
175 
176  const char *key = cps[0], *value = cps[1], *error_str;
177  faction_t faction = depth != 0 ? faction_stack[depth - 1] : NULL;
178 
179  if (strcmp(key, "faction") == 0) {
180  if (depth == arraysize(faction_stack)) {
181  error_str = "reached max faction stack size";
182  goto error;
183  }
184 
185  if (!string_isempty(value)) {
186  shstr *name = find_string(value);
187 
188  if (name != NULL && faction_find(name) != NULL) {
189  error_str = "faction already exists";
190  goto error;
191  }
192 
193  faction_stack[depth] = faction_create(value, faction);
194  depth++;
195  } else {
196  error_str = "empty faction attribute";
197  goto error;
198  }
199  } else if (faction == NULL) {
200  error_str = "expected region attribute";
201  goto error;
202  } else if (string_isempty(value)) {
203  if (strcmp(key, "end") == 0) {
204  /* Safe to decrement without safety checking, because 'faction'
205  * will be NULL in case depth is zero, and it will fall into
206  * the above branch instead. */
207  depth--;
208  } else {
209  error_str = "unknown attribute without a value";
210  goto error;
211  }
212  } else if (strcmp(key, "modifier") == 0 ||
213  strcmp(key, "spill") == 0 ||
214  strcmp(key, "attention") == 0) {
215  if (!string_endswith(value, "%")) {
216  error_str = "value must end with a percent sign";
217  goto error;
218  }
219 
220  int value_int = atoi(value);
221 
222  if (value_int < INT16_MIN || value_int > INT16_MAX) {
223  error_str = "invalid value";
224  goto error;
225  }
226 
227  if ((strcmp(key, "spill") == 0 || strcmp(key, "attention") == 0) &&
228  faction->parents_num == 0) {
229  error_str = "faction has no parent";
230  goto error;
231  }
232 
233  if (strcmp(key, "modifier") == 0) {
234  faction->modifier = (int16_t) value_int;
235  } else {
236  faction_parent_t *parent =
237  &faction->parents[faction->parents_num - 1];
238 
239  if (strcmp(key, "spill") == 0) {
240  parent->spill = (int16_t) value_int;
241  } else if (strcmp(key, "attention") == 0) {
242  parent->attention = (int16_t) value_int;
243  }
244  }
245  } else if (strcmp(key, "penalty") == 0) {
246  faction->penalty = atof(value);
247  } else if (strcmp(key, "threshold") == 0) {
248  faction->threshold = atof(value);
249  } else if (strcmp(key, "parent") == 0) {
250  faction_add_parent(faction, value);
251  } else if (strcmp(key, "enemy") == 0) {
252  faction->enemies = erealloc(faction->enemies,
253  sizeof(*faction->enemies) * (faction->enemies_num + 1));
254  faction->enemies[faction->enemies_num].faction.name =
255  add_string(value);
256  faction->enemies_num++;
257  } else if (strcmp(key, "alliance") == 0) {
258  if (KEYWORD_IS_TRUE(value)) {
259  faction->alliance = true;
260  } else {
261  error_str = "unknown value";
262  goto error;
263  }
264  } else if (strcmp(key, "spill_force") == 0) {
265  if (faction->parents_num == 0) {
266  error_str = "faction has no parent";
267  goto error;
268  }
269 
270  faction_parent_t *parent =
271  &faction->parents[faction->parents_num - 1];
272  if (KEYWORD_IS_TRUE(value)) {
273  parent->spill_force = true;
274  } else {
275  error_str = "unknown value";
276  goto error;
277  }
278  } else {
279  error_str = "unknown attribute";
280  goto error;
281  }
282 
283  continue;
284 
285 error:
286  LOG(ERROR, "Error parsing %s, line %" PRIu64 ", %s: %s %s", filename,
287  linenum, error_str, key, value != NULL ? value : "");
288  exit(1);
289  }
290 
291  fclose(fp);
292 
293  if (depth > 0) {
294  LOG(ERROR, "Faction block without end: %s",
295  faction_stack[depth - 1]->name);
296  exit(1);
297  }
298 
300 }
301 TOOLKIT_INIT_FUNC_FINISH
302 
303 TOOLKIT_DEINIT_FUNC(faction)
304 {
305  faction_t faction, tmp;
306 
307  HASH_ITER(hh, factions, faction, tmp) {
308  faction_free(faction);
309  }
310 }
311 TOOLKIT_DEINIT_FUNC_FINISH
312 
324 static faction_t faction_create(const char *name, faction_t parent)
325 {
326  TOOLKIT_PROTECT();
327 
328  HARD_ASSERT(name != NULL);
329 
330  faction_t faction = ecalloc(1, sizeof(*faction));
331  faction->name = add_string(name);
332  faction->modifier = 100;
333  faction->penalty = -25.0;
334  faction->threshold = -500.0;
335 
336  if (parent != NULL) {
337  faction_add_parent(faction, parent->name);
338  }
339 
340  HASH_ADD(hh, factions, name, sizeof(shstr *), faction);
341 
342  return faction;
343 }
344 
351 static void faction_free(faction_t faction)
352 {
353  TOOLKIT_PROTECT();
354 
355  HARD_ASSERT(faction != NULL);
356 
357  HASH_DEL(factions, faction);
358  free_string_shared(faction->name);
359 
360  if (faction->parents != NULL) {
361  efree(faction->parents);
362  }
363 
364  if (faction->enemies != NULL) {
365  efree(faction->enemies);
366  }
367 
368  if (faction->children != NULL) {
369  efree(faction->children);
370  }
371 
372  efree(faction);
373 }
374 
383 {
384  TOOLKIT_PROTECT();
385 
386  HARD_ASSERT(name != NULL);
387 
388  faction_t faction;
389  HASH_FIND(hh, factions, &name, sizeof(shstr *), faction);
390  return faction;
391 }
392 
400 static void faction_add_parent(faction_t faction, const char *name)
401 {
402  TOOLKIT_PROTECT();
403 
404  HARD_ASSERT(faction != NULL);
405  HARD_ASSERT(name != NULL);
406 
407  faction->parents = erealloc(faction->parents, sizeof(*faction->parents) *
408  (faction->parents_num + 1));
409  faction->parents[faction->parents_num].spill = 100;
410  faction->parents[faction->parents_num].attention = 100;
411  faction->parents[faction->parents_num].spill_force = false;
412  faction->parents[faction->parents_num].faction.name = add_string(name);
413  faction->parents_num++;
414 }
415 
419 static void faction_assign_names(void)
420 {
421  TOOLKIT_PROTECT();
422 
423  faction_t faction, tmp;
424 
425  HASH_ITER(hh, factions, faction, tmp) {
426  /* Assign parents. */
427  for (size_t i = 0; i < faction->parents_num; i++) {
428  faction_t parent = faction_find(faction->parents[i].faction.name);
429 
430  if (parent == NULL) {
431  LOG(ERROR, "Could not find parent faction %s for faction %s.",
432  faction->parents[i].faction.name, faction->name);
433  exit(1);
434  }
435 
436  free_string_shared(faction->parents[i].faction.name);
437  faction->parents[i].faction.ptr = parent;
438 
439  parent->children = erealloc(parent->children,
440  sizeof(*parent->children) * (parent->children_num + 1));
441  parent->children[parent->children_num] = faction;
442  parent->children_num++;
443  }
444 
445  /* Assign enemies. */
446  for (size_t i = 0; i < faction->enemies_num; i++) {
447  faction_t enemy = faction_find(faction->enemies[i].faction.name);
448 
449  if (enemy == NULL) {
450  LOG(ERROR, "Could not find enemy faction %s for faction %s.",
451  faction->enemies[i].faction.name, faction->name);
452  exit(1);
453  }
454 
455  free_string_shared(faction->enemies[i].faction.name);
456  faction->enemies[i].faction.ptr = enemy;
457  }
458  }
459 }
460 
472 static void _faction_update(faction_t faction, player *pl, double reputation,
473  bool override_spill)
474 {
475  TOOLKIT_PROTECT();
476 
477  HARD_ASSERT(faction != NULL);
478  HARD_ASSERT(pl != NULL);
479 
480  player_faction_update(pl, faction->name, reputation);
481 
482  for (size_t i = 0; i < faction->parents_num; i++) {
483  faction_t parent = faction->parents[i].faction.ptr;
484  double new_reputation = reputation;
485 
486  if (!override_spill || faction->parents[i].spill_force) {
487  new_reputation *= (double) faction->parents[i].spill / 100.0;
488  }
489 
490  new_reputation *= (double) parent->modifier / 100.0;
491 
492  if (fabs(new_reputation) < 0.00000001) {
493  continue;
494  }
495 
496  _faction_update(parent, pl, new_reputation, override_spill);
497  }
498 }
499 
509 void faction_update(faction_t faction, player *pl, double reputation)
510 {
511  TOOLKIT_PROTECT();
512 
513  HARD_ASSERT(faction != NULL);
514  HARD_ASSERT(pl != NULL);
515 
516  _faction_update(faction, pl, reputation, false);
517 }
518 
528 {
529  TOOLKIT_PROTECT();
530 
531  HARD_ASSERT(faction != NULL);
532  HARD_ASSERT(pl != NULL);
533 
534  _faction_update(faction, pl, faction->penalty, true);
535 }
536 
550 static bool _faction_is_friend(faction_t faction, object *op,
551  bool check_enemies, double attention)
552 {
553  HARD_ASSERT(faction != NULL);
554  HARD_ASSERT(op != NULL);
555 
556  double reputation;
557 
558  if (op->type == PLAYER) {
559  reputation = player_faction_reputation(CONTR(op), faction->name);
560  } else if (check_enemies) {
561  reputation = fabs(faction->threshold) + 1;
562  } else {
563  reputation = 0;
564 
565  if (faction->name == object_get_value(op, "faction")) {
566  return true;
567  }
568  }
569 
570  if (check_enemies) {
571  for (size_t i = 0; i < faction->enemies_num; i++) {
572  if (_faction_is_friend(faction->enemies[i].faction.ptr,
573  op,
574  false,
575  attention)) {
576  double value = fabs(faction->threshold) + 1.0;
577  if (op->type != PLAYER) {
578  value *= 2.0;
579  }
580  reputation -= value;
581  }
582  }
583  }
584 
585  if (reputation <= faction->threshold) {
586  return false;
587  }
588 
589  for (size_t i = 0; i < faction->parents_num; i++) {
590  if (faction->parents[i].attention == 0) {
591  continue;
592  }
593 
594  faction_t parent = faction->parents[i].faction.ptr;
595  double new_attention = (double) faction->parents[i].attention / 100.0;
596 
597  if (!_faction_is_friend(parent, op, true, new_attention)) {
598  return false;
599  }
600  }
601 
602  if (!check_enemies) {
603  return reputation >= fabs(faction->threshold);
604  }
605 
606  return true;
607 }
608 
618 bool faction_is_friend(faction_t faction, object *op)
619 {
620  TOOLKIT_PROTECT();
621 
622  HARD_ASSERT(faction != NULL);
623  HARD_ASSERT(op != NULL);
624 
625  return _faction_is_friend(faction, op, true, 1.0);
626 }
627 
637 {
638  HARD_ASSERT(faction != NULL);
639 
640  if (faction->alliance) {
641  return faction;
642  }
643 
644  if (faction->parents_num == 0) {
645  return NULL;
646  }
647 
648  return faction_get_alliance(faction->parents[0].faction.ptr);
649 }
650 
663 bool faction_is_alliance(faction_t faction, faction_t faction2)
664 {
665  TOOLKIT_PROTECT();
666 
667  HARD_ASSERT(faction != NULL);
668  HARD_ASSERT(faction2 != NULL);
669 
670  if (faction == faction2) {
671  return true;
672  }
673 
674  faction_t faction_alliance = faction_get_alliance(faction);
675  faction_t faction_alliance2 = faction_get_alliance(faction2);
676 
677  if (faction_alliance == NULL || faction_alliance2 == NULL) {
678  return false;
679  }
680 
681  return faction_alliance == faction_alliance2;
682 }
683 
693 static double _faction_get_bounty(faction_t faction, player *pl)
694 {
695  HARD_ASSERT(faction != NULL);
696  HARD_ASSERT(pl != NULL);
697 
698  double bounty = -player_faction_reputation(pl, faction->name);
699  if (bounty < 0.0) {
700  bounty = 0.0;
701  }
702 
703  for (size_t i = 0; i < faction->children_num; i++) {
704  SOFT_ASSERT_RC(faction->children[i]->parents_num > 0, 0.0,
705  "Child faction %s has no parents!", faction->children[i]->name);
706 
707  /* Skip child factions that do not have this faction as their primary
708  * parent. */
709  if (faction->children[i]->parents[0].faction.ptr != faction) {
710  continue;
711  }
712 
713  double bounty_child = _faction_get_bounty(faction->children[i], pl);
714  if (bounty_child > bounty) {
715  bounty = bounty_child;
716  }
717  }
718 
719  return bounty;
720 }
721 
734 double faction_get_bounty(faction_t faction, player *pl)
735 {
736  TOOLKIT_PROTECT();
737 
738  HARD_ASSERT(faction != NULL);
739  HARD_ASSERT(pl != NULL);
740 
742  if (alliance != NULL) {
743  faction = alliance;
744  }
745 
746  return _faction_get_bounty(faction, pl);
747 }
748 
756 static void _faction_clear_bounty(faction_t faction, player *pl)
757 {
758  HARD_ASSERT(faction != NULL);
759  HARD_ASSERT(pl != NULL);
760 
761  double bounty = player_faction_reputation(pl, faction->name);
762  if (bounty < 0.0) {
763  player_faction_update(pl, faction->name, -bounty);
764  }
765 
766  for (size_t i = 0; i < faction->children_num; i++) {
767  SOFT_ASSERT(faction->children[i]->parents_num > 0,
768  "Child faction %s has no parents!", faction->children[i]->name);
769 
770  /* Skip child factions that do not have this faction as their primary
771  * parent. */
772  if (faction->children[i]->parents[0].faction.ptr != faction) {
773  continue;
774  }
775 
776  _faction_clear_bounty(faction->children[i], pl);
777  }
778 }
779 
791 {
792  TOOLKIT_PROTECT();
793 
794  HARD_ASSERT(faction != NULL);
795  HARD_ASSERT(pl != NULL);
796 
798  if (alliance != NULL) {
799  faction = alliance;
800  }
801 
802  return _faction_clear_bounty(faction, pl);
803 }
804 
805 #endif
size_t parents_num
Number of entries in ::parents.
Definition: faction.c:98
int16_t spill
Definition: faction.c:60
shstr * name
Enemy faction name.
Definition: faction.c:84
UT_hash_handle hh
UT hash handle.
Definition: faction.c:95
int16_t modifier
Definition: faction.c:110
bool alliance
Definition: faction.c:126
void faction_update(faction_t faction, player *pl, double reputation)
Definition: faction.c:509
shstr * object_get_value(const object *op, const char *const key)
Definition: object.c:2515
shstr * name
Parent faction name.
Definition: faction.c:51
bool spill_force
Definition: faction.c:71
#define PLAYER
Definition: define.h:122
static void faction_add_parent(faction_t faction, const char *name)
Definition: faction.c:400
struct faction_parent faction_parent_t
char libpath[MAX_BUF]
Definition: global.h:338
double penalty
Definition: faction.c:115
static double _faction_get_bounty(faction_t faction, player *pl)
Definition: faction.c:693
static faction_t faction_create(const char *name, faction_t parent)
Definition: faction.c:324
struct faction_enemy faction_enemy_t
int16_t attention
Definition: faction.c:66
void faction_clear_bounty(faction_t faction, player *pl)
Definition: faction.c:790
double player_faction_reputation(player *pl, shstr *name)
Definition: player.c:1287
bool faction_is_alliance(faction_t faction, faction_t faction2)
Definition: faction.c:663
struct faction ** children
Pointers to child factions.
Definition: faction.c:103
double faction_get_bounty(faction_t faction, player *pl)
Definition: faction.c:734
shstr * name
Name of the faction.
Definition: faction.c:93
double threshold
Definition: faction.c:121
faction_t ptr
Pointer to the enemy faction.
Definition: faction.c:85
union faction_enemy::@12 faction
union faction_parent::@11 faction
static void _faction_clear_bounty(faction_t faction, player *pl)
Definition: faction.c:756
static faction_t faction_get_alliance(faction_t faction)
Definition: faction.c:636
static void faction_free(faction_t faction)
Definition: faction.c:351
faction_t ptr
Pointer to the parent faction.
Definition: faction.c:52
TOOLKIT_INIT_FUNC(http_server)
Definition: http_server.c:85
struct settings_struct settings
Definition: init.c:55
faction_enemy_t * enemies
Array of the faction's enemies.
Definition: faction.c:100
void player_faction_update(player *pl, shstr *name, double reputation)
Definition: player.c:1263
static bool _faction_is_friend(faction_t faction, object *op, bool check_enemies, double attention)
Definition: faction.c:550
uint8_t type
Definition: object.h:360
void faction_update_kill(faction_t faction, player *pl)
Definition: faction.c:527
TOOLKIT_INIT_FUNC_FINISH TOOLKIT_DEINIT_FUNC(http_server)
Definition: http_server.c:124
static faction_t factions
Definition: faction.c:132
size_t children_num
Number of entries in ::children.
Definition: faction.c:104
size_t enemies_num
Number of entries in ::enemies.
Definition: faction.c:101
bool faction_is_friend(faction_t faction, object *op)
Definition: faction.c:618
faction_parent_t * parents
Array of the faction's parents.
Definition: faction.c:97
static void faction_assign_names(void)
Definition: faction.c:419
faction_t faction_find(shstr *name)
Definition: faction.c:382
static void _faction_update(faction_t faction, player *pl, double reputation, bool override_spill)
Definition: faction.c:472