server/src/kernel/alliance.c

521 lines
12 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/* vi: set ts=2:
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
| (c) 1998 - 2003 | Henning Peters <faroul@beyond.kn-bremen.de>
| | Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
+-------------------+ Stefan Reich <reich@halbling.de>
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#include <platform.h>
#include <kernel/config.h>
#include "alliance.h"
#include <attributes/key.h>
/* kernel includes */
#include <kernel/building.h>
#include <kernel/faction.h>
#include <kernel/message.h>
#include <kernel/order.h>
#include <kernel/region.h>
#include <kernel/unit.h>
#include <kernel/item.h>
#include <kernel/command.h>
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
2012-05-29 21:17:25 +02:00
#include <util/bsdstring.h>
2010-08-08 10:06:34 +02:00
#include <util/language.h>
#include <util/parser.h>
#include <quicklist.h>
2010-08-08 10:06:34 +02:00
#include <util/rng.h>
#include <util/umlaut.h>
/* libc includes */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
2011-03-07 08:02:35 +01:00
alliance *alliances = NULL;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
void free_alliance(alliance * al)
2010-08-08 10:06:34 +02:00
{
free(al->name);
2011-03-07 08:02:35 +01:00
if (al->members)
ql_free(al->members);
2010-08-08 10:06:34 +02:00
free(al);
}
2011-03-07 08:02:35 +01:00
alliance *makealliance(int id, const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance *al;;
2010-08-08 10:06:34 +02:00
for (;;) {
2011-03-07 08:02:35 +01:00
if (id > 0) {
for (al = alliances; al; al = al->next) {
if (al->id == id) {
2010-08-08 10:06:34 +02:00
id = 0;
break;
}
}
2011-03-07 08:02:35 +01:00
if (id > 0)
break;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
id = id ? id : (1 + (rng_int() % MAX_UNIT_NR));
2010-08-08 10:06:34 +02:00
}
al = calloc(1, sizeof(alliance));
al->id = id;
if (name) {
al->name = _strdup(name);
2010-08-08 10:06:34 +02:00
} else {
al->flags |= ALF_NON_ALLIED;
}
al->next = alliances;
2011-03-07 08:02:35 +01:00
return alliances = al;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
alliance *findalliance(int id)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance *al;
for (al = alliances; al; al = al->next) {
if (al->id == id)
return al;
2010-08-08 10:06:34 +02:00
}
return NULL;
}
typedef struct alliance_transaction {
2011-03-07 08:02:35 +01:00
struct alliance_transaction *next;
unit *u;
order *ord;
2011-03-07 17:26:50 +01:00
/* alliance * al; */
/* variant userdata; */
2010-08-08 10:06:34 +02:00
} alliance_transaction;
2011-03-07 08:02:35 +01:00
static struct alliance_transaction *transactions[ALLIANCE_MAX];
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
faction *alliance_get_leader(alliance * al)
2010-08-08 10:06:34 +02:00
{
if (!al->_leader) {
if (al->members) {
2011-03-07 08:02:35 +01:00
al->_leader = (faction *) ql_get(al->members, 0);
2010-08-08 10:06:34 +02:00
}
}
return al->_leader;
}
2011-03-07 08:02:35 +01:00
static void create_transaction(int type, unit * u, order * ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance_transaction *tr =
(alliance_transaction *) calloc(1, sizeof(alliance_transaction));
2010-08-08 10:06:34 +02:00
tr->ord = ord;
tr->u = u;
tr->next = transactions[type];
transactions[type] = tr;
}
static void cmd_kick(const void *tnext, struct unit *u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
create_transaction(ALLIANCE_KICK, u, ord);
2010-08-08 10:06:34 +02:00
}
static void cmd_leave(const void *tnext, struct unit *u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
create_transaction(ALLIANCE_LEAVE, u, ord);
2010-08-08 10:06:34 +02:00
}
static void cmd_transfer(const void *tnext, struct unit *u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
create_transaction(ALLIANCE_TRANSFER, u, ord);
2010-08-08 10:06:34 +02:00
}
static void cmd_new(const void *tnext, struct unit *u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
create_transaction(ALLIANCE_NEW, u, ord);
2010-08-08 10:06:34 +02:00
}
static void cmd_invite(const void *tnext, struct unit *u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
create_transaction(ALLIANCE_INVITE, u, ord);
2010-08-08 10:06:34 +02:00
}
static void cmd_join(const void *tnext, struct unit *u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
create_transaction(ALLIANCE_JOIN, u, ord);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static void perform_kick(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance_transaction **tap = transactions + ALLIANCE_KICK;
2010-08-08 10:06:34 +02:00
while (*tap) {
2011-03-07 08:02:35 +01:00
alliance_transaction *ta = *tap;
alliance *al = f_get_alliance(ta->u->faction);
if (al && alliance_get_leader(al) == ta->u->faction) {
faction *f;
2010-08-08 10:06:34 +02:00
init_tokens(ta->ord);
skip_token();
skip_token();
f = getfaction();
2011-03-07 08:02:35 +01:00
if (f && f_get_alliance(f) == al) {
2010-08-08 10:06:34 +02:00
setalliance(f, NULL);
}
}
*tap = ta->next;
free(ta);
}
}
2011-03-07 08:02:35 +01:00
static void perform_new(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance_transaction **tap = transactions + ALLIANCE_NEW;
2010-08-08 10:06:34 +02:00
while (*tap) {
2011-03-07 08:02:35 +01:00
alliance_transaction *ta = *tap;
alliance *al;
2010-08-08 10:06:34 +02:00
int id;
2011-03-07 08:02:35 +01:00
faction *f = ta->u->faction;
2010-08-08 10:06:34 +02:00
init_tokens(ta->ord);
skip_token();
skip_token();
id = getid();
al = makealliance(id, itoa36(id));
setalliance(f, al);
*tap = ta->next;
free(ta);
}
}
2011-03-07 08:02:35 +01:00
static void perform_leave(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance_transaction **tap = transactions + ALLIANCE_LEAVE;
2010-08-08 10:06:34 +02:00
while (*tap) {
2011-03-07 08:02:35 +01:00
alliance_transaction *ta = *tap;
faction *f = ta->u->faction;
2010-08-08 10:06:34 +02:00
setalliance(f, NULL);
*tap = ta->next;
free(ta);
}
}
2011-03-07 08:02:35 +01:00
static void perform_transfer(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance_transaction **tap = transactions + ALLIANCE_TRANSFER;
2010-08-08 10:06:34 +02:00
while (*tap) {
2011-03-07 08:02:35 +01:00
alliance_transaction *ta = *tap;
alliance *al = f_get_alliance(ta->u->faction);
if (al && alliance_get_leader(al) == ta->u->faction) {
faction *f;
2010-08-08 10:06:34 +02:00
init_tokens(ta->ord);
skip_token();
skip_token();
f = getfaction();
2011-03-07 08:02:35 +01:00
if (f && f_get_alliance(f) == al) {
2010-08-08 10:06:34 +02:00
al->_leader = f;
}
}
*tap = ta->next;
free(ta);
}
}
2011-03-07 08:02:35 +01:00
static void perform_join(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance_transaction **tap = transactions + ALLIANCE_JOIN;
2010-08-08 10:06:34 +02:00
while (*tap) {
2011-03-07 08:02:35 +01:00
alliance_transaction *ta = *tap;
faction *fj = ta->u->faction;
2010-08-08 10:06:34 +02:00
int aid;
init_tokens(ta->ord);
skip_token();
skip_token();
aid = getid();
if (aid) {
2011-03-07 08:02:35 +01:00
alliance *al = findalliance(aid);
if (al && f_get_alliance(fj) != al) {
alliance_transaction **tip = transactions + ALLIANCE_INVITE;
alliance_transaction *ti = *tip;
2010-08-08 10:06:34 +02:00
while (ti) {
2011-03-07 08:02:35 +01:00
faction *fi = ti->u->faction;
if (fi && f_get_alliance(fi) == al) {
2010-08-08 10:06:34 +02:00
int fid;
init_tokens(ti->ord);
skip_token();
skip_token();
fid = getid();
2011-03-07 08:02:35 +01:00
if (fid == fj->no) {
2010-08-08 10:06:34 +02:00
break;
}
}
tip = &ti->next;
ti = *tip;
}
if (ti) {
setalliance(fj, al);
*tip = ti->next;
free(ti);
} else {
/* TODO: error message */
}
}
}
*tap = ta->next;
free(ta);
}
}
2011-03-07 08:02:35 +01:00
static void execute(const struct syntaxtree *syntax, keyword_t kwd)
2010-08-08 10:06:34 +02:00
{
int run = 0;
2011-03-07 08:02:35 +01:00
region **rp = &regions;
2010-08-08 10:06:34 +02:00
while (*rp) {
2011-03-07 08:02:35 +01:00
region *r = *rp;
2010-08-08 10:06:34 +02:00
unit **up = &r->units;
while (*up) {
2011-03-07 08:02:35 +01:00
unit *u = *up;
2010-08-08 10:06:34 +02:00
if (u->number) {
2011-03-07 08:02:35 +01:00
const struct locale *lang = u->faction->locale;
void *root = stree_find(syntax, lang);
2011-03-07 08:02:35 +01:00
order *ord;
2010-08-08 10:06:34 +02:00
for (ord = u->orders; ord; ord = ord->next) {
if (get_keyword(ord) == kwd) {
do_command(root, u, ord);
run = 1;
}
}
}
2011-03-07 08:02:35 +01:00
if (u == *up)
up = &u->next;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (*rp == r)
rp = &r->next;
2010-08-08 10:06:34 +02:00
}
if (run) {
perform_kick();
perform_leave();
perform_transfer();
perform_new();
perform_join();
}
}
2011-03-07 08:02:35 +01:00
void alliance_cmd(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
static syntaxtree *stree = NULL;
if (stree == NULL) {
syntaxtree *slang = stree = stree_create();
2010-08-08 10:06:34 +02:00
while (slang) {
void *leaf = 0;
add_command(&leaf, NULL, LOC(slang->lang, "new"), &cmd_new);
add_command(&leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite);
add_command(&leaf, NULL, LOC(slang->lang, "join"), &cmd_join);
add_command(&leaf, NULL, LOC(slang->lang, "kick"), &cmd_kick);
add_command(&leaf, NULL, LOC(slang->lang, "leave"), &cmd_leave);
add_command(&leaf, NULL, LOC(slang->lang, "command"), &cmd_transfer);
2010-08-08 10:06:34 +02:00
slang->root = leaf;
slang = slang->next;
}
}
execute(stree, K_ALLIANCE);
/* some may have been kicked, must remove f->alliance==NULL */
}
2011-03-07 08:02:35 +01:00
void alliancejoin(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
static syntaxtree *stree = NULL;
if (stree == NULL) {
syntaxtree *slang = stree = stree_create();
2010-08-08 10:06:34 +02:00
while (slang) {
void *leaf = 0;
add_command(&leaf, NULL, LOC(slang->lang, "join"), &cmd_join);
add_command(&slang->root, leaf, LOC(slang->lang, "alliance"), NULL);
2010-08-08 10:06:34 +02:00
slang = slang->next;
}
}
execute(stree, K_ALLIANCE);
}
2011-03-07 08:02:35 +01:00
void setalliance(faction * f, alliance * al)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (f->alliance == al)
return;
if (f->alliance != NULL) {
int qi;
2011-03-07 08:02:35 +01:00
quicklist **flistp = &f->alliance->members;
for (qi = 0; *flistp; ql_advance(flistp, &qi, 1)) {
faction *data = (faction *) ql_get(*flistp, qi);
if (data == f) {
ql_delete(flistp, qi);
2010-08-08 10:06:34 +02:00
break;
}
}
2011-03-07 08:02:35 +01:00
if (f->alliance->_leader == f) {
2010-08-08 10:06:34 +02:00
if (f->alliance->members) {
2011-03-07 08:02:35 +01:00
f->alliance->_leader = (faction *) ql_get(f->alliance->members, 0);
2010-08-08 10:06:34 +02:00
} else {
f->alliance->_leader = NULL;
}
}
}
f->alliance = al;
f->alliance_joindate = turn;
2011-03-07 08:02:35 +01:00
if (al != NULL) {
ql_push(&al->members, f);
2011-03-07 08:02:35 +01:00
if (al->_leader == NULL) {
2010-08-08 10:06:34 +02:00
al->_leader = f;
}
}
}
2011-03-07 08:02:35 +01:00
const char *alliancename(const alliance * al)
2010-08-08 10:06:34 +02:00
{
typedef char name[OBJECTIDSIZE + 1];
static name idbuf[8];
static int nextbuf = 0;
char *ibuf = idbuf[(++nextbuf) % 8];
if (al && al->name) {
2012-05-29 21:17:25 +02:00
slprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id));
2010-08-08 10:06:34 +02:00
} else {
return NULL;
}
return ibuf;
}
2011-03-07 08:02:35 +01:00
void alliancevictory(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const struct building_type *btype = bt_find("stronghold");
region *r = regions;
alliance *al = alliances;
if (btype == NULL)
return;
while (r != NULL) {
building *b = r->buildings;
while (b != NULL) {
if (b->type == btype) {
unit *u = building_owner(b);
2010-08-08 10:06:34 +02:00
if (u) {
fset(u->faction->alliance, FFL_MARK);
}
}
b = b->next;
}
2011-03-07 08:02:35 +01:00
r = r->next;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
while (al != NULL) {
2010-08-08 10:06:34 +02:00
if (!fval(al, FFL_MARK)) {
int qi;
2011-03-07 08:02:35 +01:00
quicklist *flist = al->members;
for (qi = 0; flist; ql_advance(&flist, &qi, 1)) {
faction *f = (faction *) ql_get(flist, qi);
if (f->alliance == al) {
ADDMSG(&f->msgs, msg_message("alliance::lost", "alliance", al));
2010-08-08 10:06:34 +02:00
destroyfaction(f);
}
}
} else {
freset(al, FFL_MARK);
}
al = al->next;
}
}
2011-03-07 08:02:35 +01:00
int victorycondition(const alliance * al, const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *gems[] =
{ "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet",
"emerald", NULL };
if (strcmp(name, "gems") == 0) {
const char **igem;
for (igem = gems; *igem; ++igem) {
const struct item_type *itype = it_find(*igem);
quicklist *flist = al->members;
int qi;
bool found = false;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
assert(itype != NULL);
for (qi = 0; flist && !found; ql_advance(&flist, &qi, 1)) {
faction *f = (faction *) ql_get(flist, 0);
unit *u;
for (u = f->units; u; u = u->nextF) {
if (i_get(u->items, itype) > 0) {
2010-08-08 10:06:34 +02:00
found = true;
break;
}
}
}
2011-03-07 08:02:35 +01:00
if (!found)
return 0;
2010-08-08 10:06:34 +02:00
}
return 1;
2011-03-07 08:02:35 +01:00
} else if (strcmp(name, "phoenix") == 0) {
quicklist *flist = al->members;
int qi;
2011-03-07 08:02:35 +01:00
for (qi = 0; flist; ql_advance(&flist, &qi, 1)) {
faction *f = (faction *) ql_get(flist, qi);
2010-08-08 10:06:34 +02:00
if (find_key(f->attribs, atoi36("phnx"))) {
return 1;
}
}
return 0;
2011-03-07 08:02:35 +01:00
} else if (strcmp(name, "pyramid") == 0) {
2010-08-08 10:06:34 +02:00
/* Logik:
2011-03-07 08:02:35 +01:00
* - if (pyr > last_passed_size && pyr > all_others) {
* pyr->passed->counter++;
* for(all_other_pyrs) {
* pyr->passed->counter=0;
* }
*
* if(pyr->passed->counter >= 3) {
* set(pyr, passed);
* pyr->owner->set_attrib(pyra);
* }
* last_passed_size = pyr->size;
* }
*/
quicklist *flist = al->members;
int qi;
2011-03-07 08:02:35 +01:00
for (qi = 0; flist; ql_advance(&flist, &qi, 1)) {
faction *f = (faction *) ql_get(flist, qi);
2010-08-08 10:06:34 +02:00
if (find_key(f->attribs, atoi36("pyra"))) {
return 1;
}
}
return 0;
}
return -1;
}
2011-03-07 08:02:35 +01:00
void alliance_setname(alliance * self, const char *name)
2010-08-08 10:06:34 +02:00
{
free(self->name);
2011-03-07 08:02:35 +01:00
if (name)
self->name = _strdup(name);
2011-03-07 08:02:35 +01:00
else
self->name = NULL;
2010-08-08 10:06:34 +02:00
}