2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2001-04-14 13:39:14 +02:00
|
|
|
|
*
|
2003-07-29 11:48:03 +02:00
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2003
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
|
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
|
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
|
|
|
|
* Enno Rehling (enno@eressea-pbem.de)
|
|
|
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
|
|
|
*
|
|
|
|
|
* based on:
|
|
|
|
|
*
|
|
|
|
|
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
|
|
|
|
|
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
* This program may not be sold or used commercially without prior written
|
|
|
|
|
* permission from the authors.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
#include "unit.h"
|
|
|
|
|
|
|
|
|
|
#include "building.h"
|
|
|
|
|
#include "faction.h"
|
|
|
|
|
#include "group.h"
|
2002-02-15 17:13:30 +01:00
|
|
|
|
#include "karma.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "border.h"
|
|
|
|
|
#include "item.h"
|
|
|
|
|
#include "movement.h"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "order.h"
|
2002-02-15 17:13:30 +01:00
|
|
|
|
#include "plane.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "race.h"
|
|
|
|
|
#include "region.h"
|
2001-02-18 11:06:10 +01:00
|
|
|
|
#include "ship.h"
|
2002-02-10 14:23:30 +01:00
|
|
|
|
#include "skill.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#include <attributes/moved.h>
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* util includes */
|
2005-06-12 12:56:18 +02:00
|
|
|
|
#include <util/base36.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <event.h>
|
2002-02-15 17:13:30 +01:00
|
|
|
|
#include <goodies.h>
|
|
|
|
|
#include <resolve.h>
|
2005-06-10 00:10:35 +02:00
|
|
|
|
#include <variant.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
2005-04-30 20:54:25 +02:00
|
|
|
|
#include <limits.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <stdlib.h>
|
2005-04-30 20:54:25 +02:00
|
|
|
|
#include <string.h>
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#include <math.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
#define FIND_FOREIGN_TEMP
|
|
|
|
|
|
2002-03-11 22:20:31 +01:00
|
|
|
|
int demonfix = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-11-25 17:53:10 +01:00
|
|
|
|
const unit *
|
|
|
|
|
u_peasants(void)
|
|
|
|
|
{
|
2005-04-30 20:54:25 +02:00
|
|
|
|
static unit peasants = { 0 };
|
2002-11-25 17:53:10 +01:00
|
|
|
|
if (peasants.name==NULL) {
|
|
|
|
|
peasants.name = strdup("die Bauern");
|
2005-04-30 20:54:25 +02:00
|
|
|
|
peasants.no = 2;
|
2002-11-25 17:53:10 +01:00
|
|
|
|
}
|
|
|
|
|
return &peasants;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const unit *
|
|
|
|
|
u_unknown(void)
|
|
|
|
|
{
|
2005-04-30 20:54:25 +02:00
|
|
|
|
static unit unknown = { 0 };
|
2002-11-25 17:53:10 +01:00
|
|
|
|
if (unknown.name==NULL) {
|
|
|
|
|
unknown.name =strdup("eine unbekannte Einheit");
|
2005-04-30 20:54:25 +02:00
|
|
|
|
unknown.no = 1;
|
2002-11-25 17:53:10 +01:00
|
|
|
|
}
|
|
|
|
|
return &unknown;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-26 08:42:58 +02:00
|
|
|
|
#define DMAXHASH 7919
|
2001-01-25 10:37:55 +01:00
|
|
|
|
typedef struct dead {
|
|
|
|
|
struct dead * nexthash;
|
|
|
|
|
faction * f;
|
|
|
|
|
int no;
|
|
|
|
|
} dead;
|
|
|
|
|
|
|
|
|
|
static dead* deadhash[DMAXHASH];
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dhash(int no, faction * f)
|
|
|
|
|
{
|
|
|
|
|
dead * hash = (dead*)calloc(1, sizeof(dead));
|
|
|
|
|
dead * old = deadhash[no % DMAXHASH];
|
|
|
|
|
hash->no = no;
|
|
|
|
|
hash->f = f;
|
|
|
|
|
deadhash[no % DMAXHASH] = hash;
|
|
|
|
|
hash->nexthash = old;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
faction *
|
2001-09-05 21:40:40 +02:00
|
|
|
|
dfindhash(int no)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
dead * old;
|
2001-09-05 21:40:40 +02:00
|
|
|
|
|
|
|
|
|
if(no < 0) return 0;
|
|
|
|
|
|
|
|
|
|
for (old = deadhash[no % DMAXHASH]; old; old = old->nexthash)
|
|
|
|
|
if (old->no == no)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return old->f;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
unit * udestroy = NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-09-08 21:03:42 +02:00
|
|
|
|
/** distributes a unit's posessions to friendly units
|
|
|
|
|
* this happens when units die and no own units are in the region
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
distribute_items(unit * u)
|
|
|
|
|
{
|
|
|
|
|
faction * f = u->faction;
|
|
|
|
|
region * r = u->region;
|
|
|
|
|
unit * au;
|
|
|
|
|
int number = 0;
|
|
|
|
|
struct friend {
|
|
|
|
|
struct friend * next;
|
|
|
|
|
int number;
|
|
|
|
|
faction * faction;
|
|
|
|
|
unit * unit;
|
|
|
|
|
} * friends = NULL;
|
|
|
|
|
|
|
|
|
|
if (u->items==NULL) return;
|
|
|
|
|
|
|
|
|
|
for (au=r->units;au;au=au->next) if (au->faction!=f) {
|
2005-09-08 23:41:39 +02:00
|
|
|
|
if (alliedunit(u, au->faction, HELP_MONEY) && alliedunit(au, f, HELP_GIVE)) {
|
2005-09-08 21:03:42 +02:00
|
|
|
|
struct friend * nf, ** fr = &friends;
|
|
|
|
|
|
|
|
|
|
while (*fr && (*fr)->faction->no<au->faction->no) fr = &(*fr)->next;
|
|
|
|
|
nf = *fr;
|
|
|
|
|
if (nf==NULL || nf->faction!=au->faction) {
|
|
|
|
|
nf = malloc(sizeof(struct friend));
|
|
|
|
|
nf->next = *fr;
|
|
|
|
|
nf->faction = au->faction;
|
|
|
|
|
nf->unit = au;
|
|
|
|
|
nf->number = 0;
|
|
|
|
|
*fr = nf;
|
|
|
|
|
}
|
|
|
|
|
nf->number += au->number;
|
|
|
|
|
number += au->number;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (friends && number) {
|
|
|
|
|
struct friend * nf = friends;
|
|
|
|
|
while (nf) {
|
|
|
|
|
unit * u2 = nf->unit;
|
|
|
|
|
item * itm = u->items;
|
|
|
|
|
while (itm!=NULL) {
|
|
|
|
|
const item_type * itype = itm->type;
|
|
|
|
|
item * itn = itm->next;
|
|
|
|
|
int n = itm->number;
|
|
|
|
|
n = n * nf->number / number;
|
|
|
|
|
if (n>0) {
|
|
|
|
|
i_change(&u->items, itype, -n);
|
|
|
|
|
i_change(&u2->items, itype, n);
|
|
|
|
|
}
|
|
|
|
|
itm = itn;
|
|
|
|
|
}
|
|
|
|
|
number -= nf->number;
|
|
|
|
|
nf = nf->next;
|
|
|
|
|
free(friends);
|
|
|
|
|
friends = nf;
|
|
|
|
|
}
|
|
|
|
|
friends = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
|
|
|
|
destroy_unit(unit * u)
|
|
|
|
|
{
|
|
|
|
|
region *r = u->region;
|
|
|
|
|
boolean zombie = false;
|
2001-09-05 21:40:40 +02:00
|
|
|
|
unit *clone;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (!ufindhash(u->no)) return;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!fval(u->race, RCF_ILLUSIONARY)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
item ** p_item = &u->items;
|
|
|
|
|
unit * u3;
|
|
|
|
|
|
2002-03-31 18:49:49 +02:00
|
|
|
|
/* u->faction->no_units--; */ /* happens in u_setfaction now */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (r) for (u3 = r->units; u3; u3 = u3->next) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u3 != u && u3->faction == u->faction && playerrace(u3->race)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
i_merge(&u3->items, &u->items);
|
|
|
|
|
u->items = NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
u3 = NULL;
|
|
|
|
|
while (*p_item) {
|
|
|
|
|
item * item = *p_item;
|
|
|
|
|
if (item->number && item->type->flags & ITF_NOTLOST) {
|
|
|
|
|
if (u3==NULL) {
|
|
|
|
|
u3 = r->units;
|
|
|
|
|
while (u3 && u3!=u) u3 = u3->next;
|
|
|
|
|
if (!u3) {
|
|
|
|
|
zombie = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (u3) {
|
|
|
|
|
i_add(&u3->items, i_remove(p_item, item));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (*p_item == item) p_item=&item->next;
|
|
|
|
|
}
|
2005-09-08 23:15:06 +02:00
|
|
|
|
if (u->items && strlen(u->faction->passw)>0) {
|
|
|
|
|
distribute_items(u);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
|
|
|
|
|
/* Wir machen das erst nach dem L<>schen der Items. Der Klon darf keine
|
|
|
|
|
* Items haben, sonst Memory-Leak. */
|
|
|
|
|
|
|
|
|
|
clone = has_clone(u);
|
|
|
|
|
if (clone && rand()%100 < 90) {
|
|
|
|
|
attrib *a;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* TODO: Messages generieren. */
|
|
|
|
|
u->region = clone->region;
|
|
|
|
|
u->ship = clone->ship;
|
|
|
|
|
u->building = clone->building;
|
|
|
|
|
u->hp = 1;
|
|
|
|
|
i = u->no;
|
2002-10-13 11:47:03 +02:00
|
|
|
|
uunhash(u);
|
|
|
|
|
uunhash(clone);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
u->no = clone->no;
|
|
|
|
|
clone->no = i;
|
2002-10-13 11:47:03 +02:00
|
|
|
|
uhash(u);
|
|
|
|
|
uhash(clone);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
set_number(u, 1);
|
|
|
|
|
set_spellpoints(u, 0);
|
|
|
|
|
a = a_find(u->attribs, &at_clone);
|
|
|
|
|
a_remove(&u->attribs, a);
|
|
|
|
|
a = a_find(clone->attribs, &at_clonemage);
|
|
|
|
|
a_remove(&clone->attribs, a);
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_LONGACTION);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
set_number(clone, 0);
|
|
|
|
|
u = clone;
|
|
|
|
|
zombie = false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (zombie) {
|
2001-02-10 15:18:01 +01:00
|
|
|
|
u_setfaction(u, findfaction(MONSTER_FACTION));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
scale_number(u, 1);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
u->race = u->irace = new_race[RC_ZOMBIE];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2002-10-13 11:47:03 +02:00
|
|
|
|
if (u->number) set_number(u, 0);
|
|
|
|
|
handle_event(&u->attribs, "destroy", u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (r && rterrain(r) != T_OCEAN)
|
|
|
|
|
rsetmoney(r, rmoney(r) + get_money(u));
|
|
|
|
|
dhash(u->no, u->faction);
|
2001-02-10 15:18:01 +01:00
|
|
|
|
u_setfaction(u, NULL);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (r) leave(r, u);
|
|
|
|
|
uunhash(u);
|
|
|
|
|
if (r) choplist(&r->units, u);
|
|
|
|
|
u->next = udestroy;
|
|
|
|
|
udestroy = u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
2001-04-26 19:41:06 +02:00
|
|
|
|
findnewunit (const region * r, const faction *f, int n)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
unit *u2;
|
|
|
|
|
|
|
|
|
|
if (n == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (u2->faction == f && ualias(u2) == n)
|
|
|
|
|
return u2;
|
|
|
|
|
#ifdef FIND_FOREIGN_TEMP
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (ualias(u2) == n)
|
|
|
|
|
return u2;
|
|
|
|
|
#endif
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_alias */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_alias = {
|
|
|
|
|
"alias",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ualias(const unit * u) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_alias);
|
|
|
|
|
if (!a) return 0;
|
|
|
|
|
return a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_private */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_private = {
|
|
|
|
|
"private",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
a_finalizestring,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
a_writestring,
|
|
|
|
|
a_readstring
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
uprivate(const unit * u) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_private);
|
|
|
|
|
if (!a) return NULL;
|
|
|
|
|
return (const char*)a->data.v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
usetprivate(unit * u, const char * str) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_private);
|
2001-02-18 10:32:13 +01:00
|
|
|
|
|
|
|
|
|
if(str == NULL) {
|
|
|
|
|
if(a) a_remove(&u->attribs, a);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!a) a = a_add(&u->attribs, a_new(&at_private));
|
|
|
|
|
if (a->data.v) free(a->data.v);
|
|
|
|
|
a->data.v = strdup(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_potionuser */
|
|
|
|
|
/*********************/
|
|
|
|
|
/* Einheit BENUTZT einen Trank */
|
|
|
|
|
attrib_type at_potionuser = {
|
|
|
|
|
"potionuser",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
usetpotionuse(unit * u, const potion_type * ptype)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_potionuser);
|
|
|
|
|
if (!a) a = a_add(&u->attribs, a_new(&at_potionuser));
|
|
|
|
|
a->data.v = (void*)ptype;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const potion_type *
|
|
|
|
|
ugetpotionuse(const unit * u) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_potionuser);
|
|
|
|
|
if (!a) return NULL;
|
|
|
|
|
return (const potion_type *)a->data.v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_target */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_target = {
|
|
|
|
|
"target",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
utarget(const unit * u) {
|
|
|
|
|
attrib * a;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (!fval(u, UFL_TARGET)) return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a_find(u->attribs, &at_target);
|
|
|
|
|
assert (a || !"flag set, but no target found");
|
|
|
|
|
return (unit*)a->data.v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
usettarget(unit * u, const unit * t)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_target);
|
|
|
|
|
if (!a && t) a = a_add(&u->attribs, a_new(&at_target));
|
|
|
|
|
if (a) {
|
|
|
|
|
if (!t) {
|
|
|
|
|
a_remove(&u->attribs, a);
|
2003-07-29 11:48:03 +02:00
|
|
|
|
freset(u, UFL_TARGET);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
a->data.v = (void*)t;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_TARGET);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_siege */
|
|
|
|
|
/*********************/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
a_writesiege(const attrib * a, FILE * f)
|
|
|
|
|
{
|
|
|
|
|
struct building * b = (struct building*)a->data.v;
|
2001-05-11 22:19:22 +02:00
|
|
|
|
write_building_reference(b, f);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
a_readsiege(attrib * a, FILE * f)
|
|
|
|
|
{
|
2001-05-11 22:19:22 +02:00
|
|
|
|
return read_building_reference((struct building**)&a->data.v, f);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_siege = {
|
|
|
|
|
"siege",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
a_writesiege,
|
|
|
|
|
a_readsiege
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct building *
|
|
|
|
|
usiege(const unit * u) {
|
|
|
|
|
attrib * a;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (!fval(u, UFL_SIEGE)) return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a_find(u->attribs, &at_siege);
|
|
|
|
|
assert (a || !"flag set, but no siege found");
|
|
|
|
|
return (struct building *)a->data.v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
usetsiege(unit * u, const struct building * t)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_siege);
|
|
|
|
|
if (!a && t) a = a_add(&u->attribs, a_new(&at_siege));
|
|
|
|
|
if (a) {
|
|
|
|
|
if (!t) {
|
|
|
|
|
a_remove(&u->attribs, a);
|
2003-07-29 11:48:03 +02:00
|
|
|
|
freset(u, UFL_SIEGE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
a->data.v = (void*)t;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_SIEGE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_contact */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_contact = {
|
|
|
|
|
"contact",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
usetcontact(unit * u, const unit * u2)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_contact);
|
|
|
|
|
while (a && a->data.v!=u2) a = a->nexttype;
|
|
|
|
|
if (a) return;
|
|
|
|
|
a_add(&u->attribs, a_new(&at_contact))->data.v = (void*)u2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
ucontact(const unit * u, const unit * u2)
|
|
|
|
|
/* Pr<50>ft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */
|
|
|
|
|
{
|
|
|
|
|
attrib *ru;
|
2005-02-06 18:06:53 +01:00
|
|
|
|
if (u->faction==u2->faction) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Explizites KONTAKTIERE */
|
|
|
|
|
for (ru = a_find(u->attribs, &at_contact); ru; ru = ru->nexttype)
|
|
|
|
|
if (((unit*)ru->data.v) == u2)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
** init & cleanup module
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
free_units(void)
|
|
|
|
|
{
|
|
|
|
|
while (udestroy) {
|
|
|
|
|
unit * u = udestroy;
|
|
|
|
|
udestroy = udestroy->next;
|
|
|
|
|
stripunit(u);
|
|
|
|
|
free(u);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
write_unit_reference(const unit * u, FILE * F)
|
|
|
|
|
{
|
2004-08-29 10:08:07 +02:00
|
|
|
|
fprintf(F, "%s ", (u!=NULL && u->no!=0)?itoa36(u->no):"0");
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-06-10 00:10:35 +02:00
|
|
|
|
void *
|
|
|
|
|
resolve_unit(variant id)
|
|
|
|
|
{
|
|
|
|
|
return ufindhash(id.i);
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-07 02:44:01 +02:00
|
|
|
|
int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
read_unit_reference(unit ** up, FILE * F)
|
|
|
|
|
{
|
2004-03-19 00:48:40 +01:00
|
|
|
|
char zId[10];
|
2005-06-10 00:10:35 +02:00
|
|
|
|
variant var;
|
2004-03-19 00:48:40 +01:00
|
|
|
|
|
|
|
|
|
assert(up!=NULL);
|
|
|
|
|
fscanf(F, "%s", zId);
|
2005-06-10 00:10:35 +02:00
|
|
|
|
var.i = atoi36(zId);
|
|
|
|
|
if (var.i==0) {
|
|
|
|
|
*up = NULL;
|
|
|
|
|
return AT_READ_FAIL;
|
2004-03-28 22:53:47 +02:00
|
|
|
|
}
|
2005-06-10 00:10:35 +02:00
|
|
|
|
*up = findunit(var.i);
|
|
|
|
|
if (*up==NULL) ur_add(var, (void**)up, resolve_unit);
|
2004-03-19 00:48:40 +01:00
|
|
|
|
return AT_READ_OK;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_stealth = {
|
|
|
|
|
"stealth", NULL, NULL, NULL, DEFAULT_WRITE, DEFAULT_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
u_seteffstealth(unit * u, int value)
|
|
|
|
|
{
|
2005-06-12 19:57:14 +02:00
|
|
|
|
attrib * a = NULL;
|
|
|
|
|
if (fval(u, UFL_STEALTH)) {
|
|
|
|
|
a = a_find(u->attribs, &at_stealth);
|
|
|
|
|
}
|
|
|
|
|
if (value<0) {
|
|
|
|
|
if (a!=NULL) {
|
|
|
|
|
freset(u, UFL_STEALTH);
|
|
|
|
|
a_remove(&u->attribs, a);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (a==NULL) {
|
|
|
|
|
a = a_add(&u->attribs, a_new(&at_stealth));
|
|
|
|
|
fset(u, UFL_STEALTH);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a->data.i = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
u_geteffstealth(const struct unit * u)
|
|
|
|
|
{
|
2005-06-12 19:57:14 +02:00
|
|
|
|
if (fval(u, UFL_STEALTH)) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_stealth);
|
|
|
|
|
if (a!=NULL) return a->data.i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-02-15 17:13:30 +01:00
|
|
|
|
int
|
|
|
|
|
get_level(const unit * u, skill_t id)
|
|
|
|
|
{
|
|
|
|
|
skill * sv = u->skills;
|
|
|
|
|
while (sv != u->skills + u->skill_size) {
|
|
|
|
|
if (sv->id == id) {
|
|
|
|
|
return sv->level;
|
|
|
|
|
}
|
|
|
|
|
++sv;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2002-03-11 01:06:14 +01:00
|
|
|
|
set_level(unit * u, skill_t sk, int value)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
{
|
|
|
|
|
skill * sv = u->skills;
|
2002-03-11 01:06:14 +01:00
|
|
|
|
if (value==0) {
|
|
|
|
|
remove_skill(u, sk);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
while (sv != u->skills + u->skill_size) {
|
2002-03-11 01:06:14 +01:00
|
|
|
|
if (sv->id == sk) {
|
2002-02-23 17:18:26 +01:00
|
|
|
|
sk_set(sv, value);
|
2002-03-02 13:33:03 +01:00
|
|
|
|
return;
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
2002-02-16 11:37:18 +01:00
|
|
|
|
++sv;
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
2002-03-11 01:06:14 +01:00
|
|
|
|
sk_set(add_skill(u, sk), value);
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-07-22 19:13:51 +02:00
|
|
|
|
static int
|
|
|
|
|
leftship_age(struct attrib * a)
|
|
|
|
|
{
|
|
|
|
|
/* must be aged, so it doesn't affect report generation (cansee) */
|
|
|
|
|
unused(a);
|
|
|
|
|
return 0; /* remove me */
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static attrib_type at_leftship = {
|
2005-07-22 19:13:51 +02:00
|
|
|
|
"leftship", NULL, NULL, leftship_age
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static attrib *
|
|
|
|
|
make_leftship(struct ship * leftship)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_new(&at_leftship);
|
|
|
|
|
a->data.v = leftship;
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
set_leftship(unit *u, ship *sh)
|
|
|
|
|
{
|
|
|
|
|
a_add(&u->attribs, make_leftship(sh));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ship *
|
|
|
|
|
leftship(const unit *u)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_leftship);
|
|
|
|
|
|
|
|
|
|
/* Achtung: Es ist nicht garantiert, da<64> der R<>ckgabewert zu jedem
|
|
|
|
|
* Zeitpunkt noch auf ein existierendes Schiff zeigt! */
|
|
|
|
|
|
|
|
|
|
if (a) return (ship *)(a->data.v);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
leave_ship(unit * u)
|
|
|
|
|
{
|
|
|
|
|
struct ship * sh = u->ship;
|
|
|
|
|
if (sh==NULL) return;
|
|
|
|
|
u->ship = NULL;
|
|
|
|
|
set_leftship(u, sh);
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u, UFL_OWNER)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit *u2, *owner = NULL;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
freset(u, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (u2 = u->region->units; u2; u2 = u2->next) {
|
|
|
|
|
if (u2->ship == sh) {
|
|
|
|
|
if (u2->faction == u->faction) {
|
|
|
|
|
owner = u2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (owner==NULL) owner = u2;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (owner!=NULL) fset(owner, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
leave_building(unit * u)
|
|
|
|
|
{
|
|
|
|
|
struct building * b = u->building;
|
|
|
|
|
if (!b) return;
|
|
|
|
|
u->building = NULL;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u, UFL_OWNER)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit *u2, *owner = NULL;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
freset(u, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (u2 = u->region->units; u2; u2 = u2->next) {
|
|
|
|
|
if (u2->building == b) {
|
|
|
|
|
if (u2->faction == u->faction) {
|
|
|
|
|
owner = u2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (owner==NULL) owner = u2;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (owner!=NULL) fset(owner, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
leave(struct region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
if (u->building) leave_building(u);
|
|
|
|
|
else if (u->ship) leave_ship(u);
|
|
|
|
|
unused(r);
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
const struct race *
|
2001-02-03 14:45:35 +01:00
|
|
|
|
urace(const struct unit * u)
|
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
return u->race;
|
2001-02-03 14:45:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
boolean
|
|
|
|
|
can_survive(const unit *u, const region *r)
|
|
|
|
|
{
|
|
|
|
|
if (((terrain[rterrain(r)].flags & WALK_INTO)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
&& (u->race->flags & RCF_WALK)) ||
|
2001-01-25 10:37:55 +01:00
|
|
|
|
((terrain[rterrain(r)].flags & SWIM_INTO)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
&& (u->race->flags & RCF_SWIM)) ||
|
2001-01-25 10:37:55 +01:00
|
|
|
|
((terrain[rterrain(r)].flags & FLY_INTO)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
&& (u->race->flags & RCF_FLY))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (get_item(u, I_HORSE) && !(terrain[rterrain(r)].flags & WALK_INTO))
|
|
|
|
|
return false;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fval(u->race, RCF_UNDEAD) && is_cursed(r->attribs, C_HOLYGROUND, 0))
|
2001-01-31 18:40:53 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
move_unit(unit * u, region * r, unit ** ulist)
|
|
|
|
|
{
|
2002-03-24 10:40:50 +01:00
|
|
|
|
int maxhp = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
assert(u && r);
|
|
|
|
|
|
|
|
|
|
if (u->region == r) return;
|
2002-03-24 10:40:50 +01:00
|
|
|
|
if (u->region!=NULL) maxhp = unit_max_hp(u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!ulist) ulist = (&r->units);
|
|
|
|
|
if (u->region) {
|
2002-04-07 12:26:28 +02:00
|
|
|
|
#ifdef DELAYED_OFFENSE
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
set_moved(&u->attribs);
|
2002-04-07 12:26:28 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
setguard(u, GUARD_NONE);
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_MOVED);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (u->ship || u->building) leave(u->region, u);
|
|
|
|
|
translist(&u->region->units, ulist, u);
|
|
|
|
|
} else
|
|
|
|
|
addlist(ulist, u);
|
|
|
|
|
|
2005-04-27 15:30:12 +02:00
|
|
|
|
#ifdef SMART_INTERVALS
|
2005-04-27 23:03:08 +02:00
|
|
|
|
update_interval(u->faction, r);
|
2005-04-27 15:30:12 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
u->region = r;
|
2002-11-03 13:47:29 +01:00
|
|
|
|
/* keine automatische hp reduzierung bei bewegung */
|
|
|
|
|
/* if (maxhp>0) u->hp = u->hp * unit_max_hp(u) / maxhp; */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ist mist, aber wegen nicht skalierender attirbute notwendig: */
|
|
|
|
|
#include "alchemy.h"
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
transfermen(unit * u, unit * u2, int n)
|
|
|
|
|
{
|
2002-02-15 17:13:30 +01:00
|
|
|
|
const attrib * a;
|
|
|
|
|
int hp = u->hp;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
region * r = u->region;
|
|
|
|
|
|
|
|
|
|
if (!n) return;
|
|
|
|
|
|
|
|
|
|
/* "hat attackiert"-status wird <20>bergeben */
|
|
|
|
|
|
|
|
|
|
if (u2) {
|
2002-02-24 22:05:43 +01:00
|
|
|
|
skill *sv, *sn;
|
2002-03-02 16:26:45 +01:00
|
|
|
|
skill_t sk;
|
2002-02-23 17:18:26 +01:00
|
|
|
|
assert(u2->number+n>0);
|
2002-02-24 22:05:43 +01:00
|
|
|
|
|
2002-03-11 22:20:31 +01:00
|
|
|
|
if (demonfix && u2->race==new_race[RC_DAEMON]) fset(u2, UFL_DEBUG);
|
|
|
|
|
|
2002-03-02 16:26:45 +01:00
|
|
|
|
for (sk=0; sk!=MAXSKILLS; ++sk) {
|
|
|
|
|
double dlevel = 0.0;
|
2002-03-17 09:24:52 +01:00
|
|
|
|
int weeks, level = 0;
|
2002-03-02 16:26:45 +01:00
|
|
|
|
|
|
|
|
|
sv = get_skill(u, sk);
|
|
|
|
|
sn = get_skill(u2, sk);
|
|
|
|
|
|
|
|
|
|
if (sv==NULL && sn==NULL) continue;
|
2002-03-17 09:24:52 +01:00
|
|
|
|
if (sv && sv->level) {
|
|
|
|
|
dlevel += (sv->level + 1 - sv->weeks/(sv->level+1.0)) * n;
|
|
|
|
|
level += sv->level * n;
|
|
|
|
|
}
|
|
|
|
|
if (sn && sn->level) {
|
|
|
|
|
dlevel += (sn->level + 1 - sn->weeks/(sn->level+1.0)) * u2->number;
|
|
|
|
|
level += sn->level * u2->number;
|
|
|
|
|
}
|
2002-03-02 16:26:45 +01:00
|
|
|
|
|
|
|
|
|
dlevel = dlevel / (n + u2->number);
|
2002-03-17 09:24:52 +01:00
|
|
|
|
level = level / (n + u2->number);
|
|
|
|
|
if (level<=dlevel) {
|
|
|
|
|
/* apply the remaining fraction to the number of weeks to go.
|
|
|
|
|
* subtract the according number of weeks, getting closer to the
|
|
|
|
|
* next level */
|
|
|
|
|
level = (int)dlevel;
|
|
|
|
|
weeks = (level+1) - (int)((dlevel - level) * (level+1));
|
|
|
|
|
} else {
|
|
|
|
|
/* make it harder to reach the next level.
|
|
|
|
|
* weeks+level is the max difficulty, 1 - the fraction between
|
|
|
|
|
* level and dlevel applied to the number of weeks between this
|
|
|
|
|
* and the previous level is the added difficutly */
|
|
|
|
|
level = (int)dlevel+1;
|
|
|
|
|
weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level);
|
|
|
|
|
}
|
2002-03-02 16:26:45 +01:00
|
|
|
|
if (level) {
|
|
|
|
|
if (sn==NULL) sn = add_skill(u2, sk);
|
|
|
|
|
sn->level = (unsigned char)level;
|
|
|
|
|
sn->weeks = (unsigned char)weeks;
|
2002-03-03 16:26:17 +01:00
|
|
|
|
assert(sn->weeks>0 && sn->weeks<=sn->level*2+1);
|
2002-03-02 16:26:45 +01:00
|
|
|
|
} else if (sn) {
|
2002-03-11 01:06:14 +01:00
|
|
|
|
remove_skill(u2, sk);
|
|
|
|
|
sn = NULL;
|
2002-02-24 10:20:38 +01:00
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a_find(u->attribs, &at_effect);
|
|
|
|
|
while (a) {
|
|
|
|
|
effect_data * olde = (effect_data*)a->data.v;
|
2002-07-28 12:32:40 +02:00
|
|
|
|
if (olde->value) change_effect(u2, olde->type, olde->value);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a->nexttype;
|
|
|
|
|
}
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u, UFL_LONGACTION)) fset(u2, UFL_LONGACTION);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (u->attribs) {
|
|
|
|
|
transfer_curse(u, u2, n);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
scale_number(u, u->number - n);
|
|
|
|
|
if (u2) {
|
|
|
|
|
set_number(u2, u2->number + n);
|
|
|
|
|
hp -= u->hp;
|
|
|
|
|
u2->hp += hp;
|
|
|
|
|
/* TODO: Das ist schnarchlahm! und geh<65>rt ncht hierhin */
|
|
|
|
|
a = a_find(u2->attribs, &at_effect);
|
|
|
|
|
while (a) {
|
2002-01-28 01:25:32 +01:00
|
|
|
|
attrib * an = a->nexttype;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
effect_data * olde = (effect_data*)a->data.v;
|
|
|
|
|
int e = get_effect(u, olde->type);
|
|
|
|
|
if (e!=0) change_effect(u2, olde->type, -e);
|
2002-01-28 01:25:32 +01:00
|
|
|
|
a = an;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (r->land)
|
2002-02-18 22:48:22 +01:00
|
|
|
|
if(u->race != new_race[RC_DAEMON]) {
|
2002-02-18 22:52:47 +01:00
|
|
|
|
if(u->race != new_race[RC_URUK]) {
|
|
|
|
|
rsetpeasants(r, rpeasants(r) + n);
|
|
|
|
|
} else {
|
|
|
|
|
rsetpeasants(r, rpeasants(r) + n/2);
|
|
|
|
|
}
|
2002-02-18 22:48:22 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-05-27 10:37:56 +02:00
|
|
|
|
struct building *
|
|
|
|
|
inside_building(const struct unit * u)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
if (u->building==NULL) return NULL;
|
|
|
|
|
|
|
|
|
|
if (!fval(u->building, BLD_WORKING)) {
|
|
|
|
|
/* Unterhalt nicht bezahlt */
|
|
|
|
|
return NULL;
|
|
|
|
|
} else if (u->building->size < u->building->type->maxsize) {
|
|
|
|
|
/* Geb<65>ude noch nicht fertig */
|
|
|
|
|
return NULL;
|
|
|
|
|
} else {
|
|
|
|
|
int p = 0, cap = buildingcapacity(u->building);
|
|
|
|
|
const unit * u2;
|
|
|
|
|
for (u2 = u->region->units; u2; u2 = u2->next) {
|
|
|
|
|
if (u2->building == u->building) {
|
|
|
|
|
p += u2->number;
|
|
|
|
|
if (u2 == u) {
|
|
|
|
|
if (p <= cap) return u->building;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (p > cap) return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2001-02-10 15:18:01 +01:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
u_setfaction(unit * u, faction * f)
|
|
|
|
|
{
|
2005-05-01 00:03:47 +02:00
|
|
|
|
int cnt = u->number;
|
2005-05-05 03:26:59 +02:00
|
|
|
|
|
2005-05-01 00:03:47 +02:00
|
|
|
|
if (u->faction==f) return;
|
2004-06-26 22:51:19 +02:00
|
|
|
|
if (u->faction) {
|
2005-05-05 03:26:59 +02:00
|
|
|
|
unit ** iunit;
|
2004-06-26 22:51:19 +02:00
|
|
|
|
set_number(u, 0);
|
2005-03-06 14:47:23 +01:00
|
|
|
|
if (playerrace(u->race)) {
|
|
|
|
|
--u->faction->no_units;
|
|
|
|
|
}
|
2004-06-26 22:51:19 +02:00
|
|
|
|
join_group(u, NULL);
|
|
|
|
|
free_orders(&u->orders);
|
|
|
|
|
set_order(&u->thisorder, NULL);
|
2005-04-30 19:07:46 +02:00
|
|
|
|
#ifdef LASTORDER
|
2004-06-26 22:51:19 +02:00
|
|
|
|
set_order(&u->lastorder, NULL);
|
2005-04-30 19:07:46 +02:00
|
|
|
|
#endif
|
2005-04-30 20:54:25 +02:00
|
|
|
|
|
2005-05-01 00:03:47 +02:00
|
|
|
|
iunit = &u->faction->units;
|
|
|
|
|
while (*iunit && *iunit!=u) {
|
|
|
|
|
iunit=&(*iunit)->nextF;
|
|
|
|
|
}
|
|
|
|
|
assert(*iunit);
|
|
|
|
|
*iunit = u->nextF;
|
|
|
|
|
}
|
2001-02-10 15:18:01 +01:00
|
|
|
|
|
2005-05-01 00:03:47 +02:00
|
|
|
|
if (f!=NULL) {
|
|
|
|
|
u->nextF = f->units;
|
|
|
|
|
f->units = u;
|
|
|
|
|
}
|
|
|
|
|
else u->nextF = NULL;
|
2001-02-10 15:18:01 +01:00
|
|
|
|
|
2005-03-11 20:43:58 +01:00
|
|
|
|
u->faction = f;
|
2005-04-28 09:04:10 +02:00
|
|
|
|
if (u->region) update_interval(f, u->region);
|
2002-03-17 09:24:52 +01:00
|
|
|
|
if (cnt && f) {
|
|
|
|
|
set_number(u, cnt);
|
2005-03-06 14:47:23 +01:00
|
|
|
|
if (playerrace(u->race)) {
|
|
|
|
|
++f->no_units;
|
|
|
|
|
}
|
2002-03-17 09:24:52 +01:00
|
|
|
|
}
|
2001-02-10 15:18:01 +01:00
|
|
|
|
}
|
2005-05-01 00:03:47 +02:00
|
|
|
|
|
2001-02-10 15:18:01 +01:00
|
|
|
|
/* vorsicht Spr<70>che k<>nnen u->number == 0 (RS_FARVISION) haben! */
|
|
|
|
|
void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
set_number(unit * u, int count)
|
2001-02-10 15:18:01 +01:00
|
|
|
|
{
|
2005-05-01 00:03:47 +02:00
|
|
|
|
assert (count >= 0);
|
|
|
|
|
assert (count <= USHRT_MAX);
|
2005-04-30 20:54:25 +02:00
|
|
|
|
|
2001-02-10 15:18:01 +01:00
|
|
|
|
#ifndef NDEBUG
|
2005-05-01 00:03:47 +02:00
|
|
|
|
assert (u->faction != 0 || u->number > 0);
|
2001-02-10 15:18:01 +01:00
|
|
|
|
#endif
|
2005-05-01 00:03:47 +02:00
|
|
|
|
|
2005-03-06 14:47:23 +01:00
|
|
|
|
if (playerrace(u->race)) {
|
|
|
|
|
u->faction->num_people += count - u->number;
|
|
|
|
|
}
|
2005-05-01 00:03:47 +02:00
|
|
|
|
u->number = (unsigned short)count;
|
2001-02-10 15:18:01 +01:00
|
|
|
|
}
|
2002-02-10 14:23:30 +01:00
|
|
|
|
|
|
|
|
|
boolean
|
2002-02-16 11:37:18 +01:00
|
|
|
|
learn_skill(unit * u, skill_t sk, double chance)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
{
|
2002-02-23 17:18:26 +01:00
|
|
|
|
skill * sv = u->skills;
|
|
|
|
|
if (chance < 1.0 && rand()%10000>=chance*10000) return false;
|
|
|
|
|
while (sv != u->skills + u->skill_size) {
|
|
|
|
|
assert (sv->weeks>0);
|
|
|
|
|
if (sv->id == sk) {
|
|
|
|
|
if (sv->weeks<=1) {
|
|
|
|
|
sk_set(sv, sv->level+1);
|
|
|
|
|
} else {
|
|
|
|
|
sv->weeks--;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
++sv;
|
|
|
|
|
}
|
2002-02-24 14:48:01 +01:00
|
|
|
|
sv = add_skill(u, sk);
|
2002-02-23 17:18:26 +01:00
|
|
|
|
sk_set(sv, 1);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2002-02-16 11:37:18 +01:00
|
|
|
|
|
2002-03-11 01:06:14 +01:00
|
|
|
|
void
|
|
|
|
|
remove_skill(unit *u, skill_t sk)
|
|
|
|
|
{
|
|
|
|
|
skill * sv = u->skills;
|
|
|
|
|
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
|
|
|
|
|
if (sv->id==sk) {
|
|
|
|
|
skill * sl = u->skills + u->skill_size - 1;
|
|
|
|
|
if (sl!=sv) {
|
|
|
|
|
*sv = *sl;
|
|
|
|
|
}
|
|
|
|
|
--u->skill_size;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-23 17:18:26 +01:00
|
|
|
|
skill *
|
|
|
|
|
add_skill(unit * u, skill_t id)
|
|
|
|
|
{
|
2005-06-12 12:56:18 +02:00
|
|
|
|
skill * sv = u->skills;
|
2002-02-23 17:18:26 +01:00
|
|
|
|
#ifndef NDEBUG
|
2005-06-12 12:56:18 +02:00
|
|
|
|
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
|
|
|
|
|
assert(sv->id != id);
|
|
|
|
|
}
|
2002-02-23 17:18:26 +01:00
|
|
|
|
#endif
|
2005-06-12 12:56:18 +02:00
|
|
|
|
++u->skill_size;
|
|
|
|
|
u->skills = realloc(u->skills, u->skill_size * sizeof(skill));
|
|
|
|
|
sv = (u->skills + u->skill_size - 1);
|
|
|
|
|
sv->level = (unsigned char)0;
|
|
|
|
|
sv->weeks = (unsigned char)1;
|
|
|
|
|
sv->old = (unsigned char)0;
|
|
|
|
|
sv->id = (unsigned char)id;
|
|
|
|
|
return sv;
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
skill *
|
2002-02-16 11:37:18 +01:00
|
|
|
|
get_skill(const unit * u, skill_t sk)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
{
|
|
|
|
|
skill * sv = u->skills;
|
|
|
|
|
while (sv!=u->skills+u->skill_size) {
|
|
|
|
|
if (sv->id==sk) return sv;
|
|
|
|
|
++sv;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
2002-02-16 11:37:18 +01:00
|
|
|
|
has_skill(const unit * u, skill_t sk)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
{
|
|
|
|
|
skill * sv = u->skills;
|
|
|
|
|
while (sv!=u->skills+u->skill_size) {
|
|
|
|
|
if (sv->id==sk) {
|
2002-02-23 17:18:26 +01:00
|
|
|
|
return (sv->level>0);
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
|
|
|
|
++sv;
|
|
|
|
|
}
|
2002-02-10 14:23:30 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
item_modification(const unit *u, skill_t sk, int val)
|
|
|
|
|
{
|
|
|
|
|
/* Presseausweis: *2 Spionage, 0 Tarnung */
|
|
|
|
|
if(sk == SK_SPY && get_item(u, I_PRESSCARD) >= u->number) {
|
|
|
|
|
val = val * 2;
|
2002-11-27 20:53:04 +01:00
|
|
|
|
} else if(sk == SK_STEALTH) {
|
2002-11-27 20:35:36 +01:00
|
|
|
|
#if NEWATSROI == 1
|
2004-06-27 18:56:01 +02:00
|
|
|
|
if (get_item(u, I_RING_OF_INVISIBILITY)
|
2002-11-27 20:35:36 +01:00
|
|
|
|
+ 100 * get_item(u, I_SPHERE_OF_INVISIBILITY) >= u->number) {
|
|
|
|
|
val += ROIBONUS;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if(get_item(u, I_PRESSCARD) >= u->number) {
|
|
|
|
|
val = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#if NEWATSROI == 1
|
|
|
|
|
if(sk == SK_OBSERVATION) {
|
|
|
|
|
if(get_item(u, I_AMULET_OF_TRUE_SEEING) >= u->number) {
|
|
|
|
|
val += ATSBONUS;
|
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
2002-11-27 20:35:36 +01:00
|
|
|
|
#endif
|
2002-02-15 17:13:30 +01:00
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
att_modification(const unit *u, skill_t sk)
|
|
|
|
|
{
|
2002-05-01 21:08:32 +02:00
|
|
|
|
int bonus = 0, malus = 0;
|
|
|
|
|
attrib * a;
|
2002-02-15 17:13:30 +01:00
|
|
|
|
int result = 0;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
static boolean init = false;
|
2005-06-12 15:30:59 +02:00
|
|
|
|
static const curse_type * skillmod_ct, * gbdream_ct, * worse_ct;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
skillmod_ct = ct_find("skillmod");
|
|
|
|
|
gbdream_ct = ct_find("gbdream");
|
2005-06-12 15:30:59 +02:00
|
|
|
|
worse_ct = ct_find("worse");
|
2002-05-01 21:08:32 +02:00
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
|
2005-06-12 15:30:59 +02:00
|
|
|
|
result += curse_geteffect(get_curse(u->attribs, worse_ct));
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (skillmod_ct) {
|
2005-06-10 00:10:35 +02:00
|
|
|
|
curse * c;
|
|
|
|
|
variant var;
|
|
|
|
|
var.i = sk;
|
|
|
|
|
c = get_cursex(u->attribs, skillmod_ct, var, cmp_cursedata_int);
|
2002-05-01 21:08:32 +02:00
|
|
|
|
result += curse_geteffect(c);
|
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
|
|
|
|
|
/* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der
|
|
|
|
|
* jeweils erste vom Typ C_GBDREAM zur<EFBFBD>ckgegen wird, wir aber alle
|
|
|
|
|
* durchsuchen und aufaddieren m<EFBFBD>ssen */
|
2002-05-01 21:08:32 +02:00
|
|
|
|
a = a_select(u->region->attribs, gbdream_ct, cmp_cursetype);
|
|
|
|
|
while (a) {
|
|
|
|
|
curse * c = (curse*)a->data.v;
|
2002-11-02 15:10:52 +01:00
|
|
|
|
int mod = curse_geteffect(c);
|
2002-05-01 21:08:32 +02:00
|
|
|
|
unit * mage = c->magician;
|
|
|
|
|
/* wir suchen jeweils den gr<67><72>ten Bonus und den gr<67><72>ten Malus */
|
2002-09-02 22:36:12 +02:00
|
|
|
|
if (mod>0 && (mage==NULL || alliedunit(mage, u->faction, HELP_GUARD)))
|
2002-05-01 21:08:32 +02:00
|
|
|
|
{
|
|
|
|
|
if (mod > bonus ) bonus = mod;
|
|
|
|
|
} else if (mod < 0 &&
|
2002-09-02 22:36:12 +02:00
|
|
|
|
(mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)))
|
2002-05-01 21:08:32 +02:00
|
|
|
|
{
|
|
|
|
|
if (mod < malus ) malus = mod;
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
2002-05-01 21:08:32 +02:00
|
|
|
|
a = a_select(a->next, gbdream_ct, cmp_cursetype);
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
2002-05-01 21:08:32 +02:00
|
|
|
|
result = result + bonus + malus;
|
2002-02-15 17:13:30 +01:00
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2002-11-27 20:53:04 +01:00
|
|
|
|
get_modifier(const unit *u, skill_t sk, int level, const region *r, boolean noitem)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
{
|
|
|
|
|
int bskill = level;
|
|
|
|
|
int skill = bskill;
|
|
|
|
|
|
|
|
|
|
if (r->planep && sk == SK_STEALTH && fval(r->planep, PFL_NOSTEALTH)) return 0;
|
|
|
|
|
|
|
|
|
|
assert(r);
|
|
|
|
|
skill += rc_skillmod(u->race, r, sk);
|
|
|
|
|
skill += att_modification(u, sk);
|
|
|
|
|
|
2005-06-12 01:02:52 +02:00
|
|
|
|
if (noitem == false) {
|
2002-11-27 20:53:04 +01:00
|
|
|
|
skill = item_modification(u, sk, skill);
|
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS);
|
|
|
|
|
|
|
|
|
|
if (fspecial(u->faction, FS_TELEPATHY)) {
|
|
|
|
|
switch(sk) {
|
|
|
|
|
case SK_ALCHEMY:
|
|
|
|
|
case SK_HERBALISM:
|
|
|
|
|
case SK_MAGIC:
|
|
|
|
|
case SK_SPY:
|
|
|
|
|
case SK_STEALTH:
|
|
|
|
|
case SK_OBSERVATION:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
skill -= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HUNGER_REDUCES_SKILL
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u, UFL_HUNGER)) {
|
2002-02-15 17:13:30 +01:00
|
|
|
|
skill = skill/2;
|
|
|
|
|
}
|
2002-02-10 14:23:30 +01:00
|
|
|
|
#endif
|
2002-02-15 17:13:30 +01:00
|
|
|
|
return skill - bskill;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
eff_skill(const unit * u, skill_t sk, const region * r)
|
|
|
|
|
{
|
|
|
|
|
int level = get_level(u, sk);
|
2002-02-16 11:37:18 +01:00
|
|
|
|
if (level>0) {
|
2002-11-27 20:53:04 +01:00
|
|
|
|
int mlevel = level + get_modifier(u, sk, level, r, false);
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (mlevel>0) {
|
|
|
|
|
int skillcap = SkillCap(sk);
|
|
|
|
|
if (skillcap && mlevel>skillcap) {
|
|
|
|
|
return skillcap;
|
|
|
|
|
}
|
|
|
|
|
return mlevel;
|
|
|
|
|
}
|
2002-11-27 20:53:04 +01:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
eff_skill_study(const unit * u, skill_t sk, const region * r)
|
|
|
|
|
{
|
|
|
|
|
int level = get_level(u, sk);
|
|
|
|
|
if (level>0) {
|
|
|
|
|
int mlevel = level + get_modifier(u, sk, level, r, true);
|
2002-02-10 14:23:30 +01:00
|
|
|
|
|
2002-02-16 11:37:18 +01:00
|
|
|
|
if (mlevel>0) return mlevel;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
2002-05-05 18:59:25 +02:00
|
|
|
|
|
|
|
|
|
int
|
2005-07-10 18:32:47 +02:00
|
|
|
|
invisible(const unit *target, const unit * viewer)
|
2002-05-05 18:59:25 +02:00
|
|
|
|
{
|
2002-11-27 20:35:36 +01:00
|
|
|
|
#if NEWATSROI == 1
|
|
|
|
|
return 0;
|
|
|
|
|
#else
|
2005-07-22 19:13:51 +02:00
|
|
|
|
if (viewer && viewer->faction==target->faction) return 0;
|
2005-07-10 18:32:47 +02:00
|
|
|
|
else {
|
|
|
|
|
int hidden = get_item(target, I_RING_OF_INVISIBILITY) + 100 * get_item(target, I_SPHERE_OF_INVISIBILITY);
|
|
|
|
|
if (hidden) {
|
|
|
|
|
hidden = min(hidden, target->number);
|
2005-07-22 19:13:51 +02:00
|
|
|
|
if (viewer) hidden -= get_item(viewer, I_AMULET_OF_TRUE_SEEING);
|
2005-07-10 18:32:47 +02:00
|
|
|
|
}
|
|
|
|
|
return hidden;
|
|
|
|
|
}
|
2002-11-27 20:35:36 +01:00
|
|
|
|
#endif
|
2002-05-05 18:59:25 +02:00
|
|
|
|
}
|
2002-10-06 11:16:34 +02:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
void
|
|
|
|
|
stripunit(unit * u)
|
|
|
|
|
{
|
|
|
|
|
free(u->name);
|
|
|
|
|
free(u->display);
|
|
|
|
|
free_orders(&u->orders);
|
|
|
|
|
if(u->skills) free(u->skills);
|
|
|
|
|
while (u->items) {
|
|
|
|
|
item * it = u->items->next;
|
|
|
|
|
u->items->next = NULL;
|
|
|
|
|
i_free(u->items);
|
|
|
|
|
u->items = it;
|
|
|
|
|
}
|
|
|
|
|
while (u->attribs) a_remove (&u->attribs, u->attribs);
|
2005-06-11 10:09:55 +02:00
|
|
|
|
while (u->reservations) {
|
|
|
|
|
struct reservation *res = u->reservations;
|
|
|
|
|
u->reservations = res->next;
|
|
|
|
|
free(res);
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-21 16:09:06 +01:00
|
|
|
|
void
|
|
|
|
|
unitlist_clear(struct unit_list **ul)
|
|
|
|
|
{
|
|
|
|
|
while (*ul) {
|
|
|
|
|
unit_list * rl2 = (*ul)->next;
|
|
|
|
|
free(*ul);
|
|
|
|
|
*ul = rl2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
unitlist_insert(struct unit_list **ul, struct unit *u)
|
|
|
|
|
{
|
|
|
|
|
unit_list *rl2 = (unit_list*)malloc(sizeof(unit_list));
|
|
|
|
|
|
|
|
|
|
rl2->data = u;
|
|
|
|
|
rl2->next = *ul;
|
|
|
|
|
|
|
|
|
|
*ul = rl2;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-22 01:58:35 +01:00
|
|
|
|
#ifdef HEROES
|
2004-08-03 17:34:26 +02:00
|
|
|
|
int
|
|
|
|
|
maxheroes(const struct faction * f)
|
|
|
|
|
{
|
2005-04-25 19:44:19 +02:00
|
|
|
|
int nsize = count_all(f);
|
|
|
|
|
if (nsize==0) return 0;
|
|
|
|
|
else {
|
|
|
|
|
int nmax = (int)(log10(nsize / 50.0) * 20);
|
|
|
|
|
return (nmax<0)?0:nmax;
|
|
|
|
|
}
|
2004-08-03 17:34:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
countheroes(const struct faction * f)
|
|
|
|
|
{
|
|
|
|
|
const unit * u = f->units;
|
|
|
|
|
int n = 0;
|
|
|
|
|
while (u) {
|
|
|
|
|
if (fval(u, UFL_HERO)) n+= u->number;
|
|
|
|
|
u = u->nextF;
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2005-06-06 22:08:20 +02:00
|
|
|
|
|
2004-12-20 11:09:59 +01:00
|
|
|
|
#endif
|