server/src/kernel/ally.c

303 lines
7.2 KiB
C
Raw Normal View History

#include "platform.h"
#include "config.h"
#include "types.h"
#include "ally.h"
#include "unit.h"
#include "region.h"
#include "group.h"
#include "faction.h"
#include "objtypes.h"
#include <kernel/attrib.h>
#include <util/strings.h>
2018-09-29 13:21:46 +02:00
#include <kernel/gamedata.h>
#include <storage.h>
#include <assert.h>
2015-11-24 19:15:53 +01:00
#include <string.h>
#include <stdlib.h>
2018-10-26 10:54:09 +02:00
typedef struct ally {
struct ally *next;
struct faction *faction;
int status;
} ally;
2018-10-26 20:57:59 +02:00
int allies_walk(struct ally *allies, cb_allies_walk callback, void *udata)
2018-10-26 10:54:09 +02:00
{
ally *al;
for (al = allies; al; al = al->next) {
2018-10-26 20:57:59 +02:00
int err = callback(allies, al->faction, al->status, udata);
if (err != 0) {
return err;
}
2018-10-26 10:54:09 +02:00
}
2018-10-26 20:57:59 +02:00
return 0;
2018-10-26 10:54:09 +02:00
}
2018-10-26 19:47:50 +02:00
void read_allies(gamedata * data, ally **sfp)
{
for (;;) {
int aid;
READ_INT(data->store, &aid);
if (aid > 0) {
ally * al = ally_add(sfp, NULL);
int state;
if ((al->faction = findfaction(aid)) == NULL) {
2017-09-22 17:59:23 +02:00
ur_add(RESOLVE_FACTION | aid, (void **)&al->faction, NULL);
}
READ_INT(data->store, &state);
al->status = state & HELP_ALL;
sfp = &al->next;
}
else {
break;
}
}
}
ally * ally_find(ally *al, const struct faction *f) {
for (; al; al = al->next) {
if (al->faction == f) return al;
}
return 0;
}
ally * ally_add(ally **al_p, struct faction *f) {
ally * al;
2014-10-31 16:51:57 +01:00
while (*al_p) {
al = *al_p;
if (f && al->faction == f) return al;
al_p = &al->next;
}
al = (ally *)calloc(1, sizeof(ally));
al->faction = f;
*al_p = al;
return al;
}
static int ally_flag(const char *s, int help_mask)
{
if ((help_mask & HELP_MONEY) && strcmp(s, "money") == 0)
return HELP_MONEY;
if ((help_mask & HELP_FIGHT) && strcmp(s, "fight") == 0)
return HELP_FIGHT;
if ((help_mask & HELP_GIVE) && strcmp(s, "give") == 0)
return HELP_GIVE;
if ((help_mask & HELP_GUARD) && strcmp(s, "guard") == 0)
return HELP_GUARD;
if ((help_mask & HELP_FSTEALTH) && strcmp(s, "stealth") == 0)
return HELP_FSTEALTH;
if ((help_mask & HELP_TRAVEL) && strcmp(s, "travel") == 0)
return HELP_TRAVEL;
return 0;
}
/** Specifies automatic alliance modes.
* If this returns a value then the bits set are immutable between alliance
* partners (faction::alliance) and cannot be changed with the HELP command.
*/
int AllianceAuto(void)
{
int value;
const char *str = config_get("alliance.auto");
value = 0;
if (str != NULL) {
char *sstr = str_strdup(str);
char *tok = strtok(sstr, " ");
while (tok) {
value |= ally_flag(tok, -1);
tok = strtok(NULL, " ");
}
free(sstr);
}
return value & HelpMask();
}
static int
2018-10-26 19:47:50 +02:00
autoalliance(const faction * sf, const faction * f2)
{
2018-10-26 20:57:59 +02:00
if (sf->alliance == f2->alliance) {
return AllianceAuto();
}
return 0;
}
static int ally_mode(const ally * sf, int mode)
{
if (sf == NULL)
return 0;
return sf->status & mode;
}
static void init_npcfaction(variant *var)
{
var->i = 1;
}
attrib_type at_npcfaction = {
"npcfaction",
init_npcfaction,
NULL,
NULL,
a_writeint,
a_readint,
NULL,
ATF_UNIQUE
};
/** Limits the available help modes
* The bitfield returned by this function specifies the available help modes
* in this game (so you can, for example, disable HELP GIVE globally).
* Disabling a status will disable the command sequence entirely (order parsing
* uses this function).
*/
int HelpMask(void)
{
2018-10-26 20:57:59 +02:00
static int config, rule;
2016-09-23 20:36:57 +02:00
if (config_changed(&config)) {
const char *str = config_get("rules.help.mask");
if (str != NULL) {
char *sstr = str_strdup(str);
2016-09-23 20:36:57 +02:00
char *tok = strtok(sstr, " ");
2018-10-26 20:57:59 +02:00
rule = 0;
2016-09-23 20:36:57 +02:00
while (tok) {
rule |= ally_flag(tok, -1);
tok = strtok(NULL, " ");
}
free(sstr);
}
else {
rule = HELP_ALL;
}
}
return rule;
}
static int AllianceRestricted(void)
{
2018-10-26 20:57:59 +02:00
static int config, rule;
if (config_changed(&config)) {
const char *str = config_get("alliance.restricted");
rule = 0;
if (str != NULL) {
char *sstr = str_strdup(str);
char *tok = strtok(sstr, " ");
while (tok) {
rule |= ally_flag(tok, -1);
tok = strtok(NULL, " ");
}
free(sstr);
}
2018-10-26 20:57:59 +02:00
rule &= HelpMask();
}
return rule;
}
2018-10-26 20:57:59 +02:00
int alliance_status(faction *f, faction *f2, int status) {
status |= autoalliance(f, f2);
if (status > 0) {
int mask = AllianceRestricted();
if (mask) {
if (a_find(f->attribs, &at_npcfaction)) {
return status;
}
if (a_find(f2->attribs, &at_npcfaction)) {
return status;
}
if (f->alliance != f2->alliance) {
status &= ~mask;
}
}
}
return status;
}
int
2018-10-26 19:47:50 +02:00
alliedgroup(const struct faction *f,
2018-10-26 20:57:59 +02:00
const struct faction *f2, const struct group *g, int mask)
{
2018-10-26 20:57:59 +02:00
ally *all = g ? g->allies : f->allies;
int status;
2018-10-26 19:47:50 +02:00
if (!(faction_alive(f) && faction_alive(f2))) {
return 0;
}
2018-10-26 20:57:59 +02:00
status = ally_get(all, f2);
return alliance_status(f, f2, status);
}
int
2018-10-26 20:57:59 +02:00
alliedfaction(const struct faction *f, const struct faction *f2, int mask)
{
2018-10-26 20:57:59 +02:00
return alliedgroup(f, f2, NULL, mask);
}
/* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */
int alliedunit(const unit * u, const faction * f2, int mode)
{
assert(u);
assert(f2);
assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */
2018-10-26 19:47:50 +02:00
if (u->faction == f2) {
return mode;
2018-10-26 19:47:50 +02:00
}
if (!faction_alive(f2)) {
return 0;
}
if (u->faction != NULL && f2 != NULL) {
if (mode & HELP_FIGHT) {
if ((u->flags & UFL_DEFENDER) || (u->faction->flags & FFL_DEFENDER)) {
faction *owner = region_get_owner(u->region);
/* helps the owner of the region */
if (owner == f2) {
return HELP_FIGHT;
}
}
}
if (fval(u, UFL_GROUP)) {
const attrib *a = a_find(u->attribs, &at_group);
2018-10-26 19:47:50 +02:00
if (a != NULL) {
group *g = (group *)a->data.v;
return alliedgroup(u->faction, f2, g, mode);
}
}
2018-10-26 19:47:50 +02:00
return alliedfaction(u->faction, f2, mode);
}
return 0;
}
2018-10-26 19:47:50 +02:00
void ally_set(ally **allies, struct faction *f, int status) {
ally *al;
while (*allies) {
al = *allies;
if (al->faction == f) {
if (status != 0) {
al->status = status;
}
else {
*allies = al->next;
free(al);
}
return;
}
allies = &al->next;
}
al = ally_add(allies, f);
al->status = status;
}
int ally_get(ally *allies, const struct faction *f) {
ally *al;
for (al = allies; al; al = al->next) {
if (al->faction == f) {
return al->status;
}
}
return 0;
}