2010-08-08 10:06:34 +02:00
|
|
|
/*
|
|
|
|
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
|
|
|
|
Katja Zedel <katze@felidae.kn-bremen.de
|
|
|
|
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <platform.h>
|
|
|
|
#include <kernel/config.h>
|
|
|
|
#include "pool.h"
|
|
|
|
|
|
|
|
#include "faction.h"
|
|
|
|
#include "item.h"
|
|
|
|
#include "magic.h"
|
|
|
|
#include "order.h"
|
|
|
|
#include "region.h"
|
|
|
|
#include "race.h"
|
|
|
|
#include "unit.h"
|
|
|
|
|
|
|
|
#include <util/parser.h>
|
|
|
|
#include <util/log.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#define TODO_POOL
|
|
|
|
#undef TODO_RESOURCES
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
int get_resource(const unit * u, const resource_type * rtype)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
const item_type *itype = resource2item(rtype);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
if (rtype->uget) {
|
|
|
|
/* this resource is probably special */
|
|
|
|
int i = rtype->uget(u, rtype);
|
2011-03-07 08:02:35 +01:00
|
|
|
if (i >= 0)
|
|
|
|
return i;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (itype != NULL) {
|
|
|
|
if (itype == olditemtype[R_STONE] && (u->race->flags & RCF_STONEGOLEM)) {
|
|
|
|
return u->number * GOLEM_STONE;
|
|
|
|
} else if (itype == olditemtype[R_IRON] && (u->race->flags & RCF_IRONGOLEM)) {
|
|
|
|
return u->number * GOLEM_IRON;
|
2010-08-08 10:06:34 +02:00
|
|
|
} else {
|
2011-03-07 08:02:35 +01:00
|
|
|
const item *i = *i_findc(&u->items, itype);
|
|
|
|
if (i)
|
|
|
|
return i->number;
|
2010-08-08 10:06:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rtype == oldresourcetype[R_AURA])
|
|
|
|
return get_spellpoints(u);
|
|
|
|
if (rtype == oldresourcetype[R_PERMAURA])
|
|
|
|
return max_spellpoints(u->region, u);
|
2012-05-17 01:52:01 +02:00
|
|
|
log_error("trying to get unknown resource '%s'.\n", rtype->_name[0]);
|
2010-08-08 10:06:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
int change_resource(unit * u, const resource_type * rtype, int change)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (rtype->uchange)
|
|
|
|
i = rtype->uchange(u, rtype, change);
|
|
|
|
else if (rtype == oldresourcetype[R_AURA])
|
|
|
|
i = change_spellpoints(u, change);
|
|
|
|
else if (rtype == oldresourcetype[R_PERMAURA])
|
|
|
|
i = change_maxspellpoints(u, change);
|
|
|
|
else
|
|
|
|
assert(!"undefined resource detected. rtype->uchange not initialized.");
|
2012-05-26 00:35:11 +02:00
|
|
|
assert(i==get_resource(u, rtype));
|
2011-03-27 21:05:22 +02:00
|
|
|
assert(i >= 0);
|
|
|
|
if (i >= 100000000) {
|
2012-05-17 00:52:37 +02:00
|
|
|
log_warning("%s has %d %s\n", unitname(u), i, rtype->_name[0]);
|
2011-03-27 21:05:22 +02:00
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
int get_reservation(const unit * u, const resource_type * rtype)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
struct reservation *res = u->reservations;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
if (rtype == oldresourcetype[R_STONE] && (u->race->flags & RCF_STONEGOLEM))
|
2010-08-08 10:06:34 +02:00
|
|
|
return (u->number * GOLEM_STONE);
|
2011-03-07 08:02:35 +01:00
|
|
|
if (rtype == oldresourcetype[R_IRON] && (u->race->flags & RCF_IRONGOLEM))
|
2010-08-08 10:06:34 +02:00
|
|
|
return (u->number * GOLEM_IRON);
|
2011-03-07 08:02:35 +01:00
|
|
|
while (res && res->type != rtype)
|
|
|
|
res = res->next;
|
|
|
|
if (res)
|
|
|
|
return res->value;
|
2010-08-08 10:06:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
int change_reservation(unit * u, const resource_type * rtype, int value)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
struct reservation *res, **rp = &u->reservations;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
if (!value)
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
while (*rp && (*rp)->type != rtype)
|
|
|
|
rp = &(*rp)->next;
|
2010-08-08 10:06:34 +02:00
|
|
|
res = *rp;
|
|
|
|
if (!res) {
|
|
|
|
*rp = res = calloc(sizeof(struct reservation), 1);
|
|
|
|
res->type = rtype;
|
|
|
|
res->value = value;
|
2011-03-07 08:02:35 +01:00
|
|
|
} else if (res && res->value + value <= 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
*rp = res->next;
|
|
|
|
free(res);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
res->value += value;
|
|
|
|
}
|
|
|
|
return res->value;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static int new_set_resvalue(unit * u, const resource_type * rtype, int value)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
struct reservation *res, **rp = &u->reservations;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
while (*rp && (*rp)->type != rtype)
|
|
|
|
rp = &(*rp)->next;
|
2010-08-08 10:06:34 +02:00
|
|
|
res = *rp;
|
|
|
|
if (!res) {
|
2011-03-07 08:02:35 +01:00
|
|
|
if (!value)
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
*rp = res = calloc(sizeof(struct reservation), 1);
|
|
|
|
res->type = rtype;
|
|
|
|
res->value = value;
|
2011-03-07 08:02:35 +01:00
|
|
|
} else if (res && value <= 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
*rp = res->next;
|
|
|
|
free(res);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
res->value = value;
|
|
|
|
}
|
|
|
|
return res->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2011-03-07 08:02:35 +01:00
|
|
|
get_pooled(const unit * u, const resource_type * rtype, unsigned int mode,
|
|
|
|
int count)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
const faction *f = u->faction;
|
2010-08-08 10:06:34 +02:00
|
|
|
unit *v;
|
|
|
|
int use = 0;
|
2011-03-07 08:02:35 +01:00
|
|
|
region *r = u->region;
|
2010-08-08 10:06:34 +02:00
|
|
|
int have = get_resource(u, rtype);
|
|
|
|
|
|
|
|
if ((u->race->ec_flags & GETITEM) == 0) {
|
2011-03-07 08:02:35 +01:00
|
|
|
mode &= (GET_SLACK | GET_RESERVE);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
if ((mode & GET_SLACK) && (mode & GET_RESERVE))
|
|
|
|
use = have;
|
2010-08-08 10:06:34 +02:00
|
|
|
else {
|
|
|
|
int reserve = get_reservation(u, rtype);
|
2011-03-07 08:02:35 +01:00
|
|
|
int slack = MAX(0, have - reserve);
|
|
|
|
if (mode & GET_RESERVE)
|
|
|
|
use = have - slack;
|
|
|
|
else if (mode & GET_SLACK)
|
|
|
|
use = slack;
|
|
|
|
}
|
|
|
|
if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) {
|
|
|
|
for (v = r->units; v && use < count; v = v->next)
|
|
|
|
if (u != v) {
|
|
|
|
int mask;
|
|
|
|
|
|
|
|
if (v->items == NULL && rtype->uget == NULL)
|
|
|
|
continue;
|
|
|
|
if ((urace(v)->ec_flags & GIVEITEM) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (v->faction == f) {
|
|
|
|
mask = (mode >> 3) & (GET_SLACK | GET_RESERVE);
|
|
|
|
} else if (alliedunit(v, f, HELP_MONEY))
|
|
|
|
mask = (mode >> 6) & (GET_SLACK | GET_RESERVE);
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
use += get_pooled(v, rtype, mask, count - use);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return use;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count)
|
|
|
|
{
|
|
|
|
const faction *f = u->faction;
|
|
|
|
unit *v;
|
|
|
|
int use = count;
|
2011-03-07 08:02:35 +01:00
|
|
|
region *r = u->region;
|
2010-08-08 10:06:34 +02:00
|
|
|
int n = 0, have = get_resource(u, rtype);
|
|
|
|
|
|
|
|
if ((u->race->ec_flags & GETITEM) == 0) {
|
2011-03-07 08:02:35 +01:00
|
|
|
mode &= (GET_SLACK | GET_RESERVE);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((mode & GET_SLACK) && (mode & GET_RESERVE)) {
|
|
|
|
n = MIN(use, have);
|
|
|
|
} else {
|
|
|
|
int reserve = get_reservation(u, rtype);
|
2011-03-07 08:02:35 +01:00
|
|
|
int slack = MAX(0, have - reserve);
|
2010-08-08 10:06:34 +02:00
|
|
|
if (mode & GET_RESERVE) {
|
2011-03-07 08:02:35 +01:00
|
|
|
n = have - slack;
|
2010-08-08 10:06:34 +02:00
|
|
|
n = MIN(use, n);
|
|
|
|
change_reservation(u, rtype, -n);
|
2011-03-07 08:02:35 +01:00
|
|
|
} else if (mode & GET_SLACK) {
|
2010-08-08 10:06:34 +02:00
|
|
|
n = MIN(use, slack);
|
|
|
|
}
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (n > 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
change_resource(u, rtype, -n);
|
|
|
|
use -= n;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) {
|
|
|
|
for (v = r->units; use > 0 && v != NULL; v = v->next)
|
|
|
|
if (u != v) {
|
|
|
|
int mask;
|
|
|
|
if ((urace(v)->ec_flags & GIVEITEM) == 0)
|
|
|
|
continue;
|
|
|
|
if (v->items == NULL && rtype->uget == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (v->faction == f) {
|
|
|
|
mask = (mode >> 3) & (GET_SLACK | GET_RESERVE);
|
|
|
|
} else if (alliedunit(v, f, HELP_MONEY))
|
|
|
|
mask = (mode >> 6) & (GET_SLACK | GET_RESERVE);
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
use -= use_pooled(v, rtype, mask, use);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
return count - use;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
int reserve_cmd(unit * u, struct order *ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) {
|
|
|
|
int use, count;
|
2011-03-07 08:02:35 +01:00
|
|
|
const resource_type *rtype;
|
|
|
|
const char *s;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
init_tokens(ord);
|
|
|
|
skip_token();
|
|
|
|
s = getstrtoken();
|
|
|
|
count = atoip((const char *)s);
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
if (count == 0 && findparam(s, u->faction->locale) == P_EACH) {
|
2010-08-08 10:06:34 +02:00
|
|
|
count = getint() * u->number;
|
|
|
|
}
|
|
|
|
|
|
|
|
rtype = findresourcetype(getstrtoken(), u->faction->locale);
|
2011-03-07 08:02:35 +01:00
|
|
|
if (rtype == NULL)
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */
|
2010-08-08 10:06:34 +02:00
|
|
|
use = use_pooled(u, rtype, GET_DEFAULT, count);
|
|
|
|
if (use) {
|
|
|
|
new_set_resvalue(u, rtype, use);
|
|
|
|
change_resource(u, rtype, use);
|
2012-05-23 07:01:48 +02:00
|
|
|
return use;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|