2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2001-05-06 23:49:16 +02:00
|
|
|
|
*
|
2006-04-10 23:13:22 +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)
|
2007-09-02 20:11:17 +02:00
|
|
|
|
* Enno Rehling (enno@eressea.de)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
#include "battle.h"
|
|
|
|
|
|
|
|
|
|
#include "alchemy.h"
|
2004-06-27 18:56:01 +02:00
|
|
|
|
#include "alliance.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "build.h"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "building.h"
|
|
|
|
|
#include "curse.h"
|
2006-01-01 17:58:59 +01:00
|
|
|
|
#include "equipment.h"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "faction.h"
|
|
|
|
|
#include "goodies.h"
|
2004-06-27 18:56:01 +02:00
|
|
|
|
#include "group.h"
|
|
|
|
|
#include "item.h"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "karma.h"
|
|
|
|
|
#include "magic.h"
|
|
|
|
|
#include "message.h"
|
2007-08-05 14:26:46 +02:00
|
|
|
|
#include "move.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "names.h"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "order.h"
|
|
|
|
|
#include "plane.h"
|
|
|
|
|
#include "race.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "region.h"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "reports.h"
|
|
|
|
|
#include "ship.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "skill.h"
|
2005-10-25 14:38:01 +02:00
|
|
|
|
#include "terrain.h"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "unit.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* attributes includes */
|
|
|
|
|
#include <attributes/key.h>
|
2002-01-01 21:51:18 +01:00
|
|
|
|
#include <attributes/fleechance.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
|
|
|
|
#include <attributes/racename.h>
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include <attributes/otherfaction.h>
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#include <attributes/moved.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
/* util includes */
|
2007-06-20 02:34:02 +02:00
|
|
|
|
#include <util/attrib.h>
|
2005-06-15 22:51:25 +02:00
|
|
|
|
#include <util/base36.h>
|
|
|
|
|
#include <util/bsdstring.h>
|
|
|
|
|
#include <util/cvector.h>
|
2007-06-20 02:34:02 +02:00
|
|
|
|
#include <util/lists.h>
|
|
|
|
|
#include <util/log.h>
|
2007-06-22 00:31:28 +02:00
|
|
|
|
#include <util/parser.h>
|
2005-06-15 22:51:25 +02:00
|
|
|
|
#include <util/rand.h>
|
2006-02-19 23:43:56 +01:00
|
|
|
|
#include <util/rng.h>
|
2002-11-30 22:06:27 +01:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <string.h>
|
2005-04-27 15:06:35 +02:00
|
|
|
|
#include <sys/stat.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-09-11 22:06:07 +02:00
|
|
|
|
static FILE *bdebug;
|
|
|
|
|
#undef DELAYED_OFFENSE /* non-guarding factions cannot attack after moving */
|
|
|
|
|
|
|
|
|
|
#define TACTICS_RANDOM 5 /* define this as 1 to deactivate */
|
2006-02-19 23:43:56 +01:00
|
|
|
|
#define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rng_int() % INITIAL */
|
2004-09-11 22:06:07 +02:00
|
|
|
|
#define CATAPULT_STRUCTURAL_DAMAGE
|
|
|
|
|
|
|
|
|
|
#define BASE_CHANCE 70 /* 70% Basis-<2D>berlebenschance */
|
|
|
|
|
#ifdef NEW_COMBATSKILLS_RULE
|
|
|
|
|
#define TDIFF_CHANGE 5 /* 5% h<>her pro Stufe */
|
|
|
|
|
#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */
|
2001-02-03 14:45:35 +01:00
|
|
|
|
#else
|
2004-09-11 22:06:07 +02:00
|
|
|
|
#define TDIFF_CHANGE 10
|
|
|
|
|
# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2007-09-16 17:34:04 +02:00
|
|
|
|
#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */
|
|
|
|
|
#define DEBUG_SELECT /* should be disabled if select_enemy works */
|
2007-03-04 22:30:39 +01:00
|
|
|
|
|
2004-09-11 22:06:07 +02:00
|
|
|
|
typedef enum combatmagic {
|
|
|
|
|
DO_PRECOMBATSPELL,
|
|
|
|
|
DO_POSTCOMBATSPELL
|
|
|
|
|
} combatmagic_t;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
/* external variables */
|
2007-05-27 23:20:06 +02:00
|
|
|
|
boolean battledebug = true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
/* globals */
|
|
|
|
|
static int obs_count = 0;
|
|
|
|
|
|
2006-03-26 11:36:55 +02:00
|
|
|
|
#define TACTICS_MALUS 1
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#undef MAGIC_TURNS
|
|
|
|
|
|
|
|
|
|
#define MINSPELLRANGE 1
|
|
|
|
|
#define MAXSPELLRANGE 7
|
|
|
|
|
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#ifndef ROW_FACTOR
|
|
|
|
|
# define ROW_FACTOR 10
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static const double EFFECT_PANIC_SPELL = 0.25;
|
|
|
|
|
static const double TROLL_REGENERATION = 0.10;
|
|
|
|
|
|
|
|
|
|
/* Nach dem alten System: */
|
|
|
|
|
static int missile_range[2] = {FIGHT_ROW, BEHIND_ROW};
|
|
|
|
|
static int melee_range[2] = {FIGHT_ROW, FIGHT_ROW};
|
2007-07-20 09:28:11 +02:00
|
|
|
|
static message * msg_separator;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
const troop no_troop = {0, 0};
|
|
|
|
|
|
2006-04-13 21:54:24 +02:00
|
|
|
|
static int
|
|
|
|
|
army_index(side * s)
|
|
|
|
|
{
|
|
|
|
|
return s->battle->nsides - s->index - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#ifndef SIMPLE_ESCAPE
|
2001-01-25 10:37:55 +01:00
|
|
|
|
region *
|
|
|
|
|
fleeregion(const unit * u)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
region *r = u->region;
|
|
|
|
|
region *neighbours[MAXDIRECTIONS];
|
|
|
|
|
int c = 0;
|
|
|
|
|
direction_t i;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (u->ship && !fval(r->terrain, SEA_REGION))
|
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (u->ship &&
|
|
|
|
|
!(u->race->flags & RCF_SWIM) &&
|
|
|
|
|
!(u->race->flags & RCF_FLY)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
for (i = 0; i != MAXDIRECTIONS; ++i) {
|
|
|
|
|
region * r2 = rconnect(r, i);
|
|
|
|
|
if (r2) {
|
|
|
|
|
if (can_survive(u,r2) && !move_blocked(u, r, r2))
|
|
|
|
|
neighbours[c++] = r2;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!c)
|
|
|
|
|
return NULL;
|
|
|
|
|
return neighbours[rng_int() % c];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-08-10 09:03:23 +02:00
|
|
|
|
static char *
|
2007-06-26 23:17:10 +02:00
|
|
|
|
sidename(side * s)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
{
|
|
|
|
|
#define SIDENAMEBUFLEN 256
|
2006-04-10 23:13:22 +02:00
|
|
|
|
static char sidename_buf[SIDENAMEBUFLEN];
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (s->stealthfaction) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
snprintf(sidename_buf, SIDENAMEBUFLEN,
|
|
|
|
|
"%s", factionname(s->stealthfaction));
|
|
|
|
|
} else {
|
|
|
|
|
snprintf(sidename_buf, SIDENAMEBUFLEN,
|
2007-10-27 17:09:36 +02:00
|
|
|
|
"%s", factionname(s->faction));
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
2007-08-10 09:03:23 +02:00
|
|
|
|
return sidename_buf;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-22 00:09:39 +02:00
|
|
|
|
static const char *
|
2001-12-10 01:13:39 +01:00
|
|
|
|
sideabkz(side *s, boolean truename)
|
|
|
|
|
{
|
2007-09-03 23:42:05 +02:00
|
|
|
|
static char sideabkz_buf[8];
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2007-09-03 23:42:05 +02:00
|
|
|
|
if (s->stealthfaction && truename == false) {
|
|
|
|
|
abkz(s->stealthfaction->name, sideabkz_buf, sizeof(sideabkz_buf), 3);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
} else {
|
2007-10-27 17:09:36 +02:00
|
|
|
|
abkz(s->faction->name, sideabkz_buf, sizeof(sideabkz_buf), 3);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
return sideabkz_buf;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-10-14 21:55:06 +02:00
|
|
|
|
static void
|
2004-04-20 00:52:36 +02:00
|
|
|
|
message_faction(battle * b, faction * f, struct message * m)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-20 00:52:36 +02:00
|
|
|
|
region * r = b->region;
|
|
|
|
|
|
|
|
|
|
if (f->battles==NULL || f->battles->r!=r) {
|
|
|
|
|
struct bmsg * bm = calloc(1, sizeof(struct bmsg));
|
|
|
|
|
bm->next = f->battles;
|
|
|
|
|
f->battles = bm;
|
|
|
|
|
bm->r = r;
|
|
|
|
|
}
|
|
|
|
|
add_message(&f->battles->msgs, m);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
armedmen(const unit * u)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
item * itm;
|
|
|
|
|
int n = 0;
|
|
|
|
|
if (!(urace(u)->flags & RCF_NOWEAPONS)) {
|
2007-10-12 21:31:28 +02:00
|
|
|
|
if (effskill(u, SK_WEAPONLESS)>=1) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* kann ohne waffen bewachen: fuer drachen */
|
|
|
|
|
n = u->number;
|
|
|
|
|
} else {
|
|
|
|
|
/* alle Waffen werden gezaehlt, und dann wird auf die Anzahl
|
|
|
|
|
* Personen minimiert */
|
|
|
|
|
for (itm=u->items;itm;itm=itm->next) {
|
|
|
|
|
const weapon_type * wtype = resource2weapon(itm->type->rtype);
|
|
|
|
|
if (wtype==NULL) continue;
|
|
|
|
|
if (effskill(u, wtype->skill) >= 1) n += itm->number;
|
|
|
|
|
/* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */
|
|
|
|
|
if (n>u->number) break;
|
|
|
|
|
}
|
|
|
|
|
n = min(n, u->number);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return n;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2004-04-20 00:52:36 +02:00
|
|
|
|
message_all(battle * b, message * m)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-20 00:52:36 +02:00
|
|
|
|
bfaction * bf;
|
|
|
|
|
plane * p = rplane(b->region);
|
|
|
|
|
watcher * w;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
for (bf = b->factions;bf;bf=bf->next) {
|
|
|
|
|
message_faction(b, bf->faction, m);
|
|
|
|
|
}
|
|
|
|
|
if (p) for (w=p->watchers;w;w=w->next) {
|
|
|
|
|
for (bf = b->factions;bf;bf=bf->next) if (bf->faction==w->faction) break;
|
|
|
|
|
if (bf==NULL) message_faction(b, w->faction, m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static void
|
2004-04-20 00:52:36 +02:00
|
|
|
|
fbattlerecord(battle * b, faction * f, const char *s)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-06-26 23:17:10 +02:00
|
|
|
|
message * m = msg_message("battle_msg", "string", s);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
message_faction(b, f, m);
|
|
|
|
|
msg_release(m);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
/* being an enemy or a friend is (and must always be!) symmetrical */
|
|
|
|
|
#define enemy_i(as, di) (as->relations[di]&E_ENEMY)
|
|
|
|
|
#define friendly_i(as, di) (as->relations[di]&E_FRIEND)
|
2006-07-30 14:52:26 +02:00
|
|
|
|
#define enemy(as, ds) (as->relations[ds->index]&E_ENEMY)
|
2007-10-27 17:09:36 +02:00
|
|
|
|
#define friendly(as, ds) (as->relations[ds->index]&E_FRIEND)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-09-16 17:34:04 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
set_enemy(side * as, side * ds, boolean attacking)
|
|
|
|
|
{
|
2004-05-28 23:04:18 +02:00
|
|
|
|
int i;
|
2007-01-31 16:28:51 +01:00
|
|
|
|
for (i=0;i!=MAXSIDES;++i) {
|
2005-08-22 22:14:42 +02:00
|
|
|
|
if (ds->enemies[i]==NULL) ds->enemies[i]=as;
|
|
|
|
|
if (ds->enemies[i]==as) break;
|
2004-05-28 23:04:18 +02:00
|
|
|
|
}
|
2007-01-31 16:28:51 +01:00
|
|
|
|
for (i=0;i!=MAXSIDES;++i) {
|
2005-08-22 22:14:42 +02:00
|
|
|
|
if (as->enemies[i]==NULL) as->enemies[i]=ds;
|
|
|
|
|
if (as->enemies[i]==ds) break;
|
2004-05-28 23:04:18 +02:00
|
|
|
|
}
|
2007-01-31 16:28:51 +01:00
|
|
|
|
assert(i!=MAXSIDES);
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (attacking) as->relations[ds->index] |= E_ATTACKING;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if ((ds->relations[as->index] & E_ENEMY)==0) {
|
|
|
|
|
/* enemy-relation are always symmetrical */
|
|
|
|
|
assert((as->relations[ds->index] & (E_ENEMY|E_FRIEND))==0);
|
|
|
|
|
ds->relations[as->index] |= E_ENEMY;
|
|
|
|
|
as->relations[ds->index] |= E_ENEMY;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2006-07-30 14:52:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_friendly(side * as, side * ds)
|
|
|
|
|
{
|
2007-09-16 17:34:04 +02:00
|
|
|
|
assert((as->relations[ds->index] & E_ENEMY)==0);
|
2006-07-30 14:52:26 +02:00
|
|
|
|
ds->relations[as->index] |= E_FRIEND;
|
|
|
|
|
as->relations[ds->index] |= E_FRIEND;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static int
|
2002-09-02 22:36:12 +02:00
|
|
|
|
allysfm(const side * s, const faction * f, int mode)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
{
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (s->faction==f) return mode;
|
2002-12-14 16:49:18 +01:00
|
|
|
|
if (s->group) {
|
2007-10-27 17:09:36 +02:00
|
|
|
|
return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode);
|
2002-12-14 16:49:18 +01:00
|
|
|
|
}
|
2007-10-27 17:09:36 +02:00
|
|
|
|
return alliedfaction(s->battle->plane, s->faction, f, mode);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2002-08-26 16:16:16 +02:00
|
|
|
|
|
|
|
|
|
static int
|
2002-09-02 22:36:12 +02:00
|
|
|
|
allysf(const side * s, const faction * f)
|
2002-08-26 16:16:16 +02:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return allysfm(s, f, HELP_FIGHT);
|
2002-08-26 16:16:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
2007-03-05 19:37:58 +01:00
|
|
|
|
static int
|
|
|
|
|
dead_fighters(const fighter * df)
|
|
|
|
|
{
|
|
|
|
|
return df->unit->number - df->alive - df->run.number;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-29 20:57:18 +02:00
|
|
|
|
fighter *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
select_corpse(battle * b, fighter * af)
|
|
|
|
|
/* W<>hlt eine Leiche aus, der af hilft. casualties ist die Anzahl der
|
|
|
|
|
* Toten auf allen Seiten (im Array). Wenn af == NULL, wird die
|
2006-04-10 23:13:22 +02:00
|
|
|
|
* Parteizugeh<EFBFBD>rigkeit ignoriert, und irgendeine Leiche genommen.
|
2004-05-20 09:34:02 +02:00
|
|
|
|
*
|
|
|
|
|
* Untote werden nicht ausgew<EFBFBD>hlt (casualties, not dead) */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-10-27 17:09:36 +02:00
|
|
|
|
int si, di, maxcasualties = 0;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter *df;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
side *s;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (si=0;si!=b->nsides;++si) {
|
|
|
|
|
side * s = b->sides+si;
|
|
|
|
|
if (af==NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
maxcasualties += s->casualties;
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
di = rng_int() % maxcasualties;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
for (df=s->fighters;df;df=df->next) {
|
|
|
|
|
/* Geflohene haben auch 0 hp, d<>rfen hier aber nicht ausgew<65>hlt
|
|
|
|
|
* werden! */
|
2007-03-05 19:37:58 +01:00
|
|
|
|
int dead = dead_fighters(df);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (!playerrace(df->unit->race)) continue;
|
|
|
|
|
|
|
|
|
|
if (af && !helping(af->side, df->side))
|
|
|
|
|
continue;
|
|
|
|
|
if (di < dead) {
|
|
|
|
|
return df;
|
|
|
|
|
}
|
|
|
|
|
di -= dead;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
2006-07-30 14:52:26 +02:00
|
|
|
|
helping(const side * as, const side * ds)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (as->faction==ds->faction) return true;
|
|
|
|
|
return (boolean)(!enemy(as, ds) && allysf(as, ds->faction));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-09 14:51:14 +01:00
|
|
|
|
int
|
2001-12-10 01:13:39 +01:00
|
|
|
|
statusrow(int status)
|
2001-04-13 16:39:57 +02:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
switch (status) {
|
|
|
|
|
case ST_AGGRO:
|
|
|
|
|
case ST_FIGHT:
|
|
|
|
|
return FIGHT_ROW;
|
|
|
|
|
case ST_BEHIND:
|
|
|
|
|
case ST_CHICKEN:
|
|
|
|
|
return BEHIND_ROW;
|
|
|
|
|
case ST_AVOID:
|
|
|
|
|
return AVOID_ROW;
|
|
|
|
|
case ST_FLEE:
|
|
|
|
|
return FLEE_ROW;
|
|
|
|
|
default:
|
|
|
|
|
assert(!"unknown combatrow");
|
|
|
|
|
}
|
|
|
|
|
return FIGHT_ROW;
|
2001-04-13 16:39:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static double
|
2001-12-10 01:13:39 +01:00
|
|
|
|
hpflee(int status)
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* if hp drop below this percentage, run away */
|
|
|
|
|
{
|
|
|
|
|
switch (status) {
|
|
|
|
|
case ST_AGGRO:
|
|
|
|
|
return 0.0;
|
|
|
|
|
case ST_FIGHT:
|
|
|
|
|
case ST_BEHIND:
|
|
|
|
|
return 0.2;
|
|
|
|
|
case ST_CHICKEN:
|
|
|
|
|
case ST_AVOID:
|
|
|
|
|
return 0.9;
|
|
|
|
|
case ST_FLEE:
|
|
|
|
|
return 1.0;
|
|
|
|
|
default:
|
|
|
|
|
assert(!"unknown combatrow");
|
|
|
|
|
}
|
|
|
|
|
return 0.0;
|
2001-04-13 16:39:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2006-04-16 00:10:57 +02:00
|
|
|
|
static int
|
2006-07-30 14:52:26 +02:00
|
|
|
|
get_row(const side * s, int row, const side * vs)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-13 19:16:15 +02:00
|
|
|
|
boolean counted[MAXSIDES];
|
2004-04-18 23:44:24 +02:00
|
|
|
|
int enemyfront = 0;
|
|
|
|
|
int line, result;
|
|
|
|
|
int retreat = 0;
|
|
|
|
|
int size[NUMROWS];
|
|
|
|
|
int front = 0;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
battle * b = s->battle;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
memset(counted, 0, sizeof(counted));
|
2004-04-18 23:44:24 +02:00
|
|
|
|
memset(size, 0, sizeof(size));
|
|
|
|
|
for (line=FIRST_ROW;line!=NUMROWS;++line) {
|
2007-10-27 17:09:36 +02:00
|
|
|
|
int si, sa_i;
|
2004-04-18 23:44:24 +02:00
|
|
|
|
/* how many enemies are there in the first row? */
|
2006-04-16 00:10:57 +02:00
|
|
|
|
for (si=0;s->enemies[si];++si) {
|
|
|
|
|
side *se = s->enemies[si];
|
|
|
|
|
if (se->size[line]>0) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
enemyfront += se->size[line];
|
|
|
|
|
/* - s->nonblockers[line] (nicht, weil angreifer) */
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (sa_i=0; sa_i!=b->nsides; ++sa_i) {
|
|
|
|
|
side * sa = b->sides+sa_i;
|
2006-07-30 14:52:26 +02:00
|
|
|
|
/* count people that like me, but don't like my enemy */
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (friendly_i(s, sa_i) && enemy_i(vs, sa_i)) {
|
|
|
|
|
if (!counted[sa_i]) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0;i!=NUMROWS;++i) {
|
|
|
|
|
size[i] += sa->size[i] - sa->nonblockers[i];
|
2004-04-18 23:44:24 +02:00
|
|
|
|
}
|
2007-10-27 17:09:36 +02:00
|
|
|
|
counted[sa_i] = true;
|
2004-04-18 23:44:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (enemyfront) break;
|
|
|
|
|
}
|
|
|
|
|
if (enemyfront) {
|
|
|
|
|
for (line=FIRST_ROW;line!=NUMROWS;++line) {
|
|
|
|
|
front += size[line];
|
2004-08-03 17:34:26 +02:00
|
|
|
|
if (!front || front<enemyfront/ROW_FACTOR) ++retreat;
|
2004-04-18 23:44:24 +02:00
|
|
|
|
else if (front) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-18 23:44:24 +02:00
|
|
|
|
/* every entry in the size[] array means someone trying to defend us.
|
|
|
|
|
* 'retreat' is the number of rows falling.
|
|
|
|
|
*/
|
|
|
|
|
result = max(FIRST_ROW, row - retreat);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-18 23:44:24 +02:00
|
|
|
|
return result;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2006-04-16 00:10:57 +02:00
|
|
|
|
int
|
2006-07-30 14:52:26 +02:00
|
|
|
|
get_unitrow(const fighter * af, const side * vs)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-07-30 14:52:26 +02:00
|
|
|
|
int row = statusrow(af->status);
|
|
|
|
|
if (vs==NULL) {
|
|
|
|
|
int i;
|
|
|
|
|
for (i=FIGHT_ROW;i!=row;++i) if (af->side->size[i]) break;
|
|
|
|
|
return FIGHT_ROW+(row-i);
|
2007-02-24 21:09:52 +01:00
|
|
|
|
} else {
|
|
|
|
|
#ifdef FASTROW
|
|
|
|
|
battle * b = vs->battle;
|
2007-03-04 19:46:01 +01:00
|
|
|
|
if (row!=b->rowcache.row || b->alive!=b->rowcache.alive || af->side!=b->rowcache.as || vs!=b->rowcache.vs) {
|
2007-02-24 21:09:52 +01:00
|
|
|
|
b->rowcache.alive = b->alive;
|
|
|
|
|
b->rowcache.as = af->side;
|
|
|
|
|
b->rowcache.vs = vs;
|
|
|
|
|
b->rowcache.row = row;
|
|
|
|
|
b->rowcache.result = get_row(af->side, row, vs);
|
|
|
|
|
return b->rowcache.result;
|
|
|
|
|
}
|
2007-03-04 22:30:39 +01:00
|
|
|
|
#ifdef DEBUG_FAST /* validation code */
|
2007-03-04 19:46:01 +01:00
|
|
|
|
{
|
|
|
|
|
int i = get_row(af->side, row, vs);
|
|
|
|
|
assert(i==b->rowcache.result);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2007-02-24 21:09:52 +01:00
|
|
|
|
return b->rowcache.result;
|
2007-03-04 18:52:59 +01:00
|
|
|
|
#else
|
|
|
|
|
return get_row(af->side, row, vs);
|
2007-02-24 21:09:52 +01:00
|
|
|
|
#endif
|
2006-07-30 14:52:26 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
reportcasualties(battle * b, fighter * fig, int dead)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-05-29 20:57:18 +02:00
|
|
|
|
struct message * m;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
region * r = NULL;
|
2004-05-29 20:57:18 +02:00
|
|
|
|
if (fig->alive == fig->unit->number) return;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#ifndef SIMPLE_ESCAPE
|
2004-05-29 20:57:18 +02:00
|
|
|
|
if (fig->run.region == NULL) {
|
|
|
|
|
fig->run.region = fleeregion(fig->unit);
|
|
|
|
|
if (fig->run.region == NULL) fig->run.region = b->region;
|
|
|
|
|
}
|
2007-02-10 12:25:23 +01:00
|
|
|
|
r = fig->run.region;
|
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2004-05-29 20:57:18 +02:00
|
|
|
|
m = msg_message("casualties", "unit runto run alive fallen",
|
2007-02-10 12:25:23 +01:00
|
|
|
|
fig->unit, r, fig->run.number, fig->alive, dead);
|
2004-05-29 20:57:18 +02:00
|
|
|
|
message_all(b, m);
|
|
|
|
|
msg_release(m);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2005-07-31 03:07:07 +02:00
|
|
|
|
contest(int skilldiff, const armor_type * ar, const armor_type * sh)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
int p, vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff;
|
|
|
|
|
double mod = 1.0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (ar != NULL)
|
|
|
|
|
mod *= (1 + ar->penalty);
|
|
|
|
|
if (sh != NULL)
|
|
|
|
|
mod *= (1 + sh->penalty);
|
|
|
|
|
vw = (int)(100 - ((100 - vw) * mod));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
do {
|
|
|
|
|
p = rng_int() % 100;
|
|
|
|
|
vw -= p;
|
|
|
|
|
}
|
|
|
|
|
while (vw >= 0 && p >= 90);
|
|
|
|
|
return (vw <= 0);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
riding(const troop t) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (t.fighter->building!=NULL) return false;
|
|
|
|
|
if (t.fighter->horses + t.fighter->elvenhorses > t.index) return true;
|
|
|
|
|
return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static weapon *
|
2002-10-04 23:37:35 +02:00
|
|
|
|
preferred_weapon(const troop t, boolean attacking)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
weapon * missile = t.fighter->person[t.index].missile;
|
|
|
|
|
weapon * melee = t.fighter->person[t.index].melee;
|
|
|
|
|
if (attacking) {
|
|
|
|
|
if (melee==NULL || (missile && missile->attackskill>melee->attackskill)) {
|
|
|
|
|
return missile;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (melee==NULL || (missile && missile->defenseskill>melee->defenseskill)) {
|
|
|
|
|
return missile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return melee;
|
2002-10-04 23:37:35 +02:00
|
|
|
|
}
|
Zu Anfang des Kampfes wählt jeder Kämpfer aus seinem Arsenal zwei Waffen
aus: Seine beste Fernampfwaffe und seine beste Nahkampfwaffe.
Welches die beste Waffe ist, ist nicht immer einleuchtend, und an dieser
Stelle macht der Server eine Vereinfachung - er wählt die Waffe, bei der der
Angriffswert plus dem Verteidigungswert am größten ist.
** Wenn eine Einheit an der Reihe ist, wird geprüft:
1. Ist die Einheit ein Magier, so zaubert sie.
2. Ist die Einheit damit beschäftigt, eine Waffe nachzuladen, so tut sie das.
3. Steht die Einheit in einer der hinteren Reihen, attackiert sie, so
vorhanden, mit der Fernkampfwaffe.
4. Steht die Einheit in der vorderen Kampfreihe, so attackiert sie mit
derjenigen Waffe von beiden, in der ihr Talent am höchsten ist.
** Wird eine Einheit angegriffen, so gilt:
1. Handelt es sich um einen Angriff durch einen Nahkämpfer, so verteidigt
sie sich mit ihrer Nahkampfwaffe oder Waffenlosem Kampf.
2. Handelt es sich um eine Attacke durch einen Fernkämpfer, so verteidigt
sie sich mit dem halben Talent ihrer besten Waffe.
2002-10-04 23:25:16 +02:00
|
|
|
|
|
2002-10-04 23:37:35 +02:00
|
|
|
|
static weapon *
|
|
|
|
|
select_weapon(const troop t, boolean attacking, boolean ismissile)
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* select the primary weapon for this trooper */
|
|
|
|
|
{
|
|
|
|
|
if (attacking) {
|
|
|
|
|
if (ismissile) {
|
|
|
|
|
/* from the back rows, have to use your missile weapon */
|
|
|
|
|
return t.fighter->person[t.index].missile;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (!ismissile) {
|
|
|
|
|
/* have to use your melee weapon if it's melee */
|
|
|
|
|
return t.fighter->person[t.index].melee;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return preferred_weapon(t, attacking);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking)
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* the 'pure' skill when using this weapon to attack or defend.
|
|
|
|
|
* only undiscriminate modifiers (not affected by troops or enemies)
|
|
|
|
|
* are taken into account, e.g. no horses, magic, etc. */
|
|
|
|
|
{
|
|
|
|
|
int skill;
|
|
|
|
|
|
|
|
|
|
if (wtype==NULL) {
|
|
|
|
|
skill = effskill(u, SK_WEAPONLESS);
|
|
|
|
|
if (skill<=0) {
|
|
|
|
|
/* wenn kein waffenloser kampf, dann den rassen-defaultwert */
|
|
|
|
|
if(u->race == new_race[RC_URUK]) {
|
|
|
|
|
int sword = effskill(u, SK_MELEE);
|
|
|
|
|
int spear = effskill(u, SK_SPEAR);
|
|
|
|
|
skill = max(sword, spear) - 3;
|
|
|
|
|
if (attacking) {
|
|
|
|
|
skill = max(skill, u->race->at_default);
|
|
|
|
|
} else {
|
|
|
|
|
skill = max(skill, u->race->df_default);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (attacking) {
|
|
|
|
|
skill = u->race->at_default;
|
|
|
|
|
} else {
|
|
|
|
|
skill = u->race->df_default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* der rassen-defaultwert kann h<>her sein als der Talentwert von
|
|
|
|
|
* waffenloser kampf */
|
|
|
|
|
if (attacking) {
|
|
|
|
|
if (skill < u->race->at_default) skill = u->race->at_default;
|
|
|
|
|
} else {
|
|
|
|
|
if (skill < u->race->df_default) skill = u->race->df_default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (attacking) {
|
|
|
|
|
skill += u->race->at_bonus;
|
|
|
|
|
} else {
|
|
|
|
|
skill += u->race->df_bonus;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* changed: if we own a weapon, we have at least a skill of 0 */
|
|
|
|
|
skill = effskill(u, wtype->skill);
|
|
|
|
|
if (skill < wtype->minskill) skill = 0;
|
|
|
|
|
if (skill > 0) {
|
|
|
|
|
if(attacking) {
|
|
|
|
|
skill += u->race->at_bonus;
|
|
|
|
|
} else {
|
|
|
|
|
skill += u->race->df_bonus;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (attacking) {
|
|
|
|
|
skill += wtype->offmod;
|
|
|
|
|
} else {
|
|
|
|
|
skill += wtype->defmod;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return skill;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boolean missile)
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* effektiver Waffenskill w<>hrend des Kampfes */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* In dieser Runde alle die Modifier berechnen, die fig durch die
|
|
|
|
|
* Waffen bekommt. */
|
|
|
|
|
fighter * tf = t.fighter;
|
|
|
|
|
unit * tu = t.fighter->unit;
|
|
|
|
|
int skill;
|
|
|
|
|
const weapon_type * wtype = w?w->type:NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-06-12 01:02:52 +02:00
|
|
|
|
if (wtype==NULL) {
|
|
|
|
|
/* Ohne Waffe: Waffenlose Angriffe */
|
|
|
|
|
skill = weapon_skill(NULL, tu, attacking);
|
|
|
|
|
} else {
|
|
|
|
|
if (attacking) {
|
|
|
|
|
skill = w->attackskill;
|
|
|
|
|
} else {
|
|
|
|
|
skill = w->defenseskill;
|
|
|
|
|
}
|
|
|
|
|
if (wtype->modifiers!=NULL) {
|
|
|
|
|
/* Pferdebonus, Lanzenbonus, usw. */
|
|
|
|
|
int m;
|
|
|
|
|
unsigned int flags = WMF_SKILL|(attacking?WMF_OFFENSIVE:WMF_DEFENSIVE);
|
|
|
|
|
|
|
|
|
|
if (riding(t)) flags |= WMF_RIDING;
|
|
|
|
|
else flags |= WMF_WALKING;
|
|
|
|
|
if (riding(enemy)) flags |= WMF_AGAINST_RIDING;
|
|
|
|
|
else flags |= WMF_AGAINST_WALKING;
|
|
|
|
|
|
|
|
|
|
for (m=0;wtype->modifiers[m].value;++m) {
|
|
|
|
|
if ((wtype->modifiers[m].flags & flags) == flags) {
|
|
|
|
|
race_list * rlist = wtype->modifiers[m].races;
|
|
|
|
|
if (rlist!=NULL) {
|
|
|
|
|
while (rlist) {
|
|
|
|
|
if (rlist->data == tu->race) break;
|
|
|
|
|
rlist = rlist->next;
|
|
|
|
|
}
|
|
|
|
|
if (rlist==NULL) continue;
|
|
|
|
|
}
|
|
|
|
|
skill += wtype->modifiers[m].value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Burgenbonus, Pferdebonus */
|
|
|
|
|
if (riding(t) && (wtype==NULL || !fval(wtype, WTF_MISSILE))) {
|
|
|
|
|
skill += 2;
|
|
|
|
|
if (wtype) skill = skillmod(urace(tu)->attribs, tu, tu->region, wtype->skill, skill, SMF_RIDING);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (t.index<tf->elvenhorses) {
|
|
|
|
|
/* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist
|
|
|
|
|
* eleganter, und vor allem einfacher, sonst mu<EFBFBD> man noch ein
|
|
|
|
|
* WMF_ELVENHORSE einbauen. */
|
|
|
|
|
skill += 2;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (skill>0 && !attacking && missile) {
|
|
|
|
|
/*
|
|
|
|
|
* Wenn ich verteidige, und nicht direkt meinem Feind gegen<EFBFBD>berstehe,
|
|
|
|
|
* halbiert sich mein Skill: (z.B. gegen Fernk<EFBFBD>mpfer. Nahk<EFBFBD>mpfer
|
|
|
|
|
* k<EFBFBD>nnen mich eh nicht treffen)
|
|
|
|
|
*/
|
|
|
|
|
skill /= 2;
|
|
|
|
|
}
|
|
|
|
|
return skill;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-07-31 03:07:07 +02:00
|
|
|
|
static const armor_type *
|
|
|
|
|
select_armor(troop t, boolean shield)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2005-07-31 03:07:07 +02:00
|
|
|
|
unit * u = t.fighter->unit;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
const armor * a = t.fighter->armors;
|
|
|
|
|
int geschuetzt = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Drachen benutzen keine R<>stungen */
|
|
|
|
|
if (!(u->race->battle_flags & BF_EQUIPMENT))
|
|
|
|
|
return NULL;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* ... und Werw<72>lfe auch nicht */
|
|
|
|
|
if (fval(u, UFL_WERE)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
for (;a;a=a->next) {
|
|
|
|
|
if (a->atype->flags & ATF_SHIELD) {
|
|
|
|
|
geschuetzt += a->count;
|
|
|
|
|
if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */
|
|
|
|
|
return a->atype;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Hier ist zu beachten, ob und wie sich Zauber und Artefakte, die
|
|
|
|
|
* R<EFBFBD>stungschutz geben, addieren.
|
|
|
|
|
* - Artefakt I_TROLLBELT gibt R<EFBFBD>stung +1
|
|
|
|
|
* - Zauber Rindenhaut gibt R<EFBFBD>stung +3
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
select_magicarmor(troop t)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
unit *u = t.fighter->unit;
|
|
|
|
|
int geschuetzt = 0;
|
|
|
|
|
int ma = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
geschuetzt = min(get_item(u, I_TROLLBELT), u->number);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */
|
|
|
|
|
ma += 1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return ma;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Sind side ds und Magier des meffect verb<72>ndet, dann return 1*/
|
|
|
|
|
boolean
|
|
|
|
|
meffect_protection(battle * b, meffect * s, side * ds)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!s->magician->alive) return false;
|
|
|
|
|
if (s->duration <= 0) return false;
|
|
|
|
|
if (enemy(s->magician->side, ds)) return false;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (allysf(s->magician->side, ds->faction)) return true;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Sind side as und Magier des meffect verfeindet, dann return 1*/
|
|
|
|
|
boolean
|
|
|
|
|
meffect_blocked(battle *b, meffect *s, side *as)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!s->magician->alive) return false;
|
|
|
|
|
if (s->duration <= 0) return false;
|
|
|
|
|
if (enemy(s->magician->side, as)) return true;
|
|
|
|
|
return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-22 20:14:07 +02:00
|
|
|
|
/* rmfighter wird schon im PRAECOMBAT gebraucht, da gibt es noch keine
|
|
|
|
|
* troops */
|
|
|
|
|
void
|
|
|
|
|
rmfighter(fighter *df, int i)
|
|
|
|
|
{
|
2004-05-21 11:37:49 +02:00
|
|
|
|
side *ds = df->side;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
|
2004-05-21 11:37:49 +02:00
|
|
|
|
/* nicht mehr personen abziehen, als in der Einheit am Leben sind */
|
|
|
|
|
assert(df->alive >= i);
|
|
|
|
|
assert(df->alive <= df->unit->number);
|
2001-04-22 20:14:07 +02:00
|
|
|
|
|
2004-05-21 11:37:49 +02:00
|
|
|
|
/* erst ziehen wir die Anzahl der Personen von den K<>mpfern in der
|
|
|
|
|
* Schlacht, dann von denen auf dieser Seite ab*/
|
|
|
|
|
df->side->alive -= i;
|
|
|
|
|
df->side->battle->alive -= i;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
|
2004-05-21 11:37:49 +02:00
|
|
|
|
/* Dann die Kampfreihen aktualisieren */
|
|
|
|
|
ds->size[SUM_ROW] -= i;
|
|
|
|
|
ds->size[statusrow(df->status)] -= i;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
|
2004-05-21 11:37:49 +02:00
|
|
|
|
/* Spezialwirkungen, z.B. Schattenritter */
|
|
|
|
|
if (df->unit->race->battle_flags & BF_NOBLOCK) {
|
|
|
|
|
ds->nonblockers[SUM_ROW] -= i;
|
|
|
|
|
ds->nonblockers[statusrow(df->status)] -= i;
|
|
|
|
|
}
|
2001-04-22 20:14:07 +02:00
|
|
|
|
|
2004-05-21 11:37:49 +02:00
|
|
|
|
/* und die Einheit selbst aktualisieren */
|
|
|
|
|
df->alive -= i;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-03-04 22:52:13 +01:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rmtroop(troop dt)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter *df = dt.fighter;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* troop ist immer eine einzele Person */
|
|
|
|
|
rmfighter(df, 1);
|
2001-04-22 20:14:07 +02:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
assert(dt.index >= 0 && dt.index < df->unit->number);
|
2004-12-31 02:13:04 +01:00
|
|
|
|
df->person[dt.index] = df->person[df->alive - df->removed];
|
|
|
|
|
if (df->removed) {
|
|
|
|
|
df->person[df->alive - df->removed] = df->person[df->alive];
|
|
|
|
|
}
|
|
|
|
|
df->person[df->alive].hp = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
remove_troop(troop dt)
|
2007-03-04 22:52:13 +01:00
|
|
|
|
{
|
|
|
|
|
fighter * df = dt.fighter;
|
|
|
|
|
struct person p = df->person[dt.index];
|
|
|
|
|
battle * b = df->side->battle;
|
|
|
|
|
#ifdef FASTCOUNT
|
|
|
|
|
b->fast.alive = -1; /* invalidate cached value */
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef FASTROW
|
|
|
|
|
b->rowcache.alive = -1; /* invalidate cached value */
|
|
|
|
|
#endif
|
|
|
|
|
++df->removed;
|
|
|
|
|
++df->side->removed;
|
|
|
|
|
df->person[dt.index] = df->person[df->alive-df->removed];
|
|
|
|
|
df->person[df->alive - df->removed] = p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
kill_troop(troop dt)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter * df = dt.fighter;
|
|
|
|
|
unit * du = df->unit;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
rmtroop(dt);
|
|
|
|
|
if (!df->alive) {
|
2006-01-01 17:58:59 +01:00
|
|
|
|
char eqname[64];
|
|
|
|
|
const struct equipment * eq;
|
2006-04-09 16:26:02 +02:00
|
|
|
|
if (du->race->itemdrop) {
|
|
|
|
|
item * drops = du->race->itemdrop(du->race, du->number-df->run.number);
|
2006-01-01 17:58:59 +01:00
|
|
|
|
|
2006-04-09 16:26:02 +02:00
|
|
|
|
if (drops != NULL){
|
|
|
|
|
i_merge(&du->items, &drops);
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-01-01 17:58:59 +01:00
|
|
|
|
sprintf(eqname, "%s_spoils", du->race->_name[0]);
|
|
|
|
|
eq = get_equipment(eqname);
|
|
|
|
|
if (eq!=NULL) {
|
|
|
|
|
equip_items(&du->items, eq);
|
|
|
|
|
}
|
2006-04-09 16:26:02 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-02-15 17:13:30 +01:00
|
|
|
|
/** reduces the target's exp by an equivalent of n points learning
|
|
|
|
|
* 30 points = 1 week
|
|
|
|
|
*/
|
2002-02-23 20:04:51 +01:00
|
|
|
|
void
|
2002-02-24 10:20:38 +01:00
|
|
|
|
drain_exp(struct unit *u, int n)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
skill_t sk = (skill_t)(rng_int() % MAXSKILLS);
|
|
|
|
|
skill_t ssk;
|
|
|
|
|
|
|
|
|
|
ssk = sk;
|
|
|
|
|
|
|
|
|
|
while (get_level(u, sk)==0) {
|
|
|
|
|
sk++;
|
|
|
|
|
if (sk == MAXSKILLS)
|
|
|
|
|
sk = 0;
|
|
|
|
|
if (sk == ssk) {
|
|
|
|
|
sk = NOSKILL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (sk != NOSKILL) {
|
|
|
|
|
skill * sv = get_skill(u, sk);
|
|
|
|
|
while (n>0) {
|
|
|
|
|
if (n>=30*u->number) {
|
|
|
|
|
reduce_skill(u, sv, 1);
|
|
|
|
|
n-=30;
|
|
|
|
|
} else {
|
|
|
|
|
if (rng_int()%(30*u->number)<n) reduce_skill(u, sv, 1);
|
|
|
|
|
n = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
rel_dam(int dam, int hp)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
double q = (double)dam/(double)hp;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (q > 0.75) {
|
|
|
|
|
return "eine klaffende Wunde";
|
|
|
|
|
} else if (q > 0.5) {
|
|
|
|
|
return "eine schwere Wunde";
|
|
|
|
|
} else if (q > 0.25) {
|
|
|
|
|
return "eine Wunde";
|
|
|
|
|
}
|
|
|
|
|
return "eine kleine Wunde";
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
terminate(troop dt, troop at, int type, const char *damage, boolean missile)
|
|
|
|
|
{
|
2005-10-29 13:17:21 +02:00
|
|
|
|
item ** pitm;
|
|
|
|
|
fighter *df = dt.fighter;
|
|
|
|
|
fighter *af = at.fighter;
|
|
|
|
|
unit *au = af->unit;
|
|
|
|
|
unit *du = df->unit;
|
|
|
|
|
battle *b = df->side->battle;
|
|
|
|
|
int heiltrank = 0;
|
|
|
|
|
|
|
|
|
|
/* Schild */
|
|
|
|
|
void **si;
|
|
|
|
|
side *ds = df->side;
|
|
|
|
|
int hp;
|
|
|
|
|
|
|
|
|
|
int ar = 0, an, am;
|
|
|
|
|
const armor_type * armor = select_armor(dt, true);
|
|
|
|
|
const armor_type * shield = select_armor(dt, false);
|
|
|
|
|
|
|
|
|
|
const weapon_type *dwtype = NULL;
|
|
|
|
|
const weapon_type *awtype = NULL;
|
|
|
|
|
const weapon * weapon;
|
|
|
|
|
|
|
|
|
|
int rda, sk = 0, sd;
|
|
|
|
|
boolean magic = false;
|
|
|
|
|
int da = dice_rand(damage);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-10-15 16:09:59 +02:00
|
|
|
|
assert(du->number>0);
|
2004-08-21 03:55:56 +02:00
|
|
|
|
#ifdef SHOW_KILLS
|
|
|
|
|
++at.fighter->hits;
|
|
|
|
|
#endif
|
|
|
|
|
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#ifdef KARMA_MODULE
|
2004-08-21 03:55:56 +02:00
|
|
|
|
if (fval(au, UFL_WERE)) {
|
2005-10-29 13:17:21 +02:00
|
|
|
|
int level = fspecial(du->faction, FS_LYCANTROPE);
|
|
|
|
|
da += level;
|
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
switch (type) {
|
|
|
|
|
case AT_STANDARD:
|
|
|
|
|
weapon = select_weapon(at, true, missile);
|
|
|
|
|
sk = weapon_effskill(at, dt, weapon, true, missile);
|
|
|
|
|
if (weapon) awtype = weapon->type;
|
|
|
|
|
if (awtype && fval(awtype, WTF_MAGICAL)) magic = true;
|
|
|
|
|
break;
|
|
|
|
|
case AT_NATURAL:
|
|
|
|
|
sk = weapon_effskill(at, dt, NULL, true, missile);
|
|
|
|
|
break;
|
|
|
|
|
case AT_SPELL:
|
|
|
|
|
case AT_COMBATSPELL:
|
|
|
|
|
magic = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */
|
|
|
|
|
sd = weapon_effskill(dt, at, weapon, false, false);
|
|
|
|
|
if (weapon!=NULL) dwtype=weapon->type;
|
|
|
|
|
|
|
|
|
|
if (armor) ar += armor->prot;
|
|
|
|
|
if (shield) ar += shield->prot;
|
|
|
|
|
|
|
|
|
|
/* nat<61>rliche R<>stung */
|
|
|
|
|
an = du->race->armor;
|
|
|
|
|
|
|
|
|
|
/* magische R<>stung durch Artefakte oder Spr<70>che */
|
|
|
|
|
/* Momentan nur Trollg<6C>rtel und Werwolf-Eigenschaft */
|
|
|
|
|
am = select_magicarmor(dt);
|
2006-02-17 23:59:03 +01:00
|
|
|
|
|
|
|
|
|
#ifdef KARMA_MODULE
|
2005-10-29 13:17:21 +02:00
|
|
|
|
if(fval(du, UFL_WERE)) {
|
|
|
|
|
/* this counts as magical armor */
|
|
|
|
|
int level = fspecial(du->faction, FS_LYCANTROPE);
|
|
|
|
|
am += level;
|
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
2002-04-27 16:46:27 +02:00
|
|
|
|
|
|
|
|
|
#if CHANGED_CROSSBOWS == 1
|
2005-10-29 13:17:21 +02:00
|
|
|
|
if(awtype && fval(awtype,WTF_ARMORPIERCING)) {
|
|
|
|
|
/* crossbows */
|
|
|
|
|
ar /= 2;
|
|
|
|
|
an /= 2;
|
|
|
|
|
}
|
2002-04-27 16:46:27 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
/* nat<61>rliche R<>stung ist halbkumulativ */
|
|
|
|
|
if (ar>0) {
|
|
|
|
|
ar += an/2;
|
|
|
|
|
} else {
|
|
|
|
|
ar = an;
|
|
|
|
|
}
|
|
|
|
|
ar += am;
|
|
|
|
|
|
2005-12-31 15:01:54 +01:00
|
|
|
|
if (type!=AT_COMBATSPELL && type!=AT_SPELL) {
|
|
|
|
|
/* Kein Zauber, normaler Waffenschaden */
|
|
|
|
|
double kritchance = (sk * 3 - sd) / 200.0;
|
2005-05-05 03:37:08 +02:00
|
|
|
|
#ifdef KARMA_MODULE
|
2006-02-17 23:59:03 +01:00
|
|
|
|
int faerie_level = fspecial(du->faction, FS_FAERIE);
|
|
|
|
|
|
2005-12-31 15:01:54 +01:00
|
|
|
|
da += jihad(au->faction, du->race);
|
|
|
|
|
if (type == AT_STANDARD && faerie_level) {
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
|
|
for (c=0;weapon->type->itype->construction->materials[c].number; c++) {
|
|
|
|
|
if(weapon->type->itype->construction->materials[c].rtype == oldresourcetype[R_IRON]) {
|
|
|
|
|
da += faerie_level;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2005-10-29 13:17:21 +02:00
|
|
|
|
}
|
2005-12-31 15:01:54 +01:00
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
|
|
|
|
|
|
|
|
|
kritchance = max(kritchance, 0.005);
|
|
|
|
|
kritchance = min(0.9, kritchance);
|
|
|
|
|
|
|
|
|
|
while (chance(kritchance)) {
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
fprintf(bdebug, "%s/%d landet einen kritischen Treffer", unitid(au), at.index);
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
da += dice_rand(damage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
da += rc_specialdamage(au->race, du->race, awtype);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-12-31 15:01:54 +01:00
|
|
|
|
if (awtype!=NULL && fval(awtype, WTF_MISSILE)) {
|
|
|
|
|
/* Fernkampfschadenbonus */
|
|
|
|
|
da += af->person[at.index].damage_rear;
|
|
|
|
|
} else if (awtype==NULL) {
|
|
|
|
|
/* Waffenloser kampf, bonus von talentwert*/
|
|
|
|
|
da += effskill(au, SK_WEAPONLESS);
|
|
|
|
|
} else {
|
|
|
|
|
/* Nahkampfschadensbonus */
|
|
|
|
|
da += af->person[at.index].damage;
|
2005-10-29 13:17:21 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-12-31 15:01:54 +01:00
|
|
|
|
/* Skilldifferenzbonus */
|
|
|
|
|
da += max(0, (sk-sd)/DAMAGE_QUOTIENT);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
|
2005-12-31 15:01:54 +01:00
|
|
|
|
if (magic) {
|
|
|
|
|
/* Magischer Schaden durch Spruch oder magische Waffe */
|
|
|
|
|
double res = 1.0;
|
|
|
|
|
|
|
|
|
|
/* magic_resistance gib x% Resistenzbonus zur<75>ck */
|
|
|
|
|
res -= magic_resistance(du)*3.0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-12-31 15:01:54 +01:00
|
|
|
|
if (du->race->battle_flags & BF_EQUIPMENT) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef TODO_RUNESWORD
|
2005-12-31 15:01:54 +01:00
|
|
|
|
/* Runenschwert gibt im Kampf 80% Resistenzbonus */
|
|
|
|
|
if (dwp == WP_RUNESWORD) res -= 0.80;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2005-12-31 15:01:54 +01:00
|
|
|
|
/* der Effekt von Laen steigt nicht linear */
|
|
|
|
|
if (armor && fval(armor, ATF_LAEN)) res *= (1-armor->magres);
|
|
|
|
|
if (shield && fval(shield, ATF_LAEN)) res *= (1-shield->magres);
|
|
|
|
|
if (dwtype) res *= (1-dwtype->magres);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-12-31 15:01:54 +01:00
|
|
|
|
if (res > 0) {
|
|
|
|
|
da = (int) (max(da * res, 0));
|
2005-10-29 13:17:21 +02:00
|
|
|
|
}
|
2005-12-31 15:01:54 +01:00
|
|
|
|
/* gegen Magie wirkt nur nat<61>rliche und magische R<>stung */
|
|
|
|
|
ar = an+am;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
rda = max(da - ar,0);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0;
|
|
|
|
|
else {
|
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
if (du->race->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE;
|
|
|
|
|
if (du->race->battle_flags & BF_RES_CUT) i |= WTF_CUT;
|
|
|
|
|
if (du->race->battle_flags & BF_RES_BASH) i |= WTF_BLUNT;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
if (i && awtype && fval(awtype, i)) rda /= 2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
/* Schilde */
|
|
|
|
|
for (si = b->meffects.begin; si != b->meffects.end; ++si) {
|
|
|
|
|
meffect *meffect = *si;
|
|
|
|
|
if (meffect_protection(b, meffect, ds) != 0) {
|
2005-12-31 15:01:54 +01:00
|
|
|
|
assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */
|
|
|
|
|
/* jeder Schaden wird um effect% reduziert bis der Schild duration
|
|
|
|
|
* Trefferpunkte aufgefangen hat */
|
|
|
|
|
if (meffect->typ == SHIELD_REDUCE) {
|
|
|
|
|
hp = rda * (meffect->effect/100);
|
|
|
|
|
rda -= hp;
|
|
|
|
|
meffect->duration -= hp;
|
|
|
|
|
}
|
|
|
|
|
/* gibt R<>stung +effect f<>r duration Treffer */
|
|
|
|
|
if (meffect->typ == SHIELD_ARMOR) {
|
|
|
|
|
rda = max(rda - meffect->effect, 0);
|
|
|
|
|
meffect->duration--;
|
|
|
|
|
}
|
2005-10-29 13:17:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
assert(dt.index<du->number);
|
|
|
|
|
df->person[dt.index].hp -= rda;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (df->person[dt.index].hp > 0) { /* Hat <20>berlebt */
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP\n",
|
|
|
|
|
da, ar, df->person[dt.index].hp, df->person[dt.index].hp - rda);
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2005-10-29 13:17:21 +02:00
|
|
|
|
if (au->race == new_race[RC_DAEMON]) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef TODO_RUNESWORD
|
2005-10-29 13:17:21 +02:00
|
|
|
|
if (select_weapon(dt, 0, -1) == WP_RUNESWORD) continue;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2005-10-29 13:17:21 +02:00
|
|
|
|
if (!(df->person[dt.index].flags & (FL_COURAGE|FL_DAZZLED))) {
|
2005-12-31 15:01:54 +01:00
|
|
|
|
df->person[dt.index].flags |= FL_DAZZLED;
|
|
|
|
|
df->person[dt.index].defence--;
|
2005-10-29 13:17:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
df->person[dt.index].flags = (df->person[dt.index].flags & ~FL_SLEEPING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef SHOW_KILLS
|
2004-08-21 03:55:56 +02:00
|
|
|
|
++at.fighter->kills;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
/* Sieben Leben */
|
|
|
|
|
if (du->race == new_race[RC_CAT] && (chance(1.0 / 7))) {
|
2004-07-14 09:12:36 +02:00
|
|
|
|
assert(dt.index>=0 && dt.index<du->number);
|
|
|
|
|
df->person[dt.index].hp = unit_max_hp(du);
|
|
|
|
|
return false;
|
2005-10-29 13:17:21 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
/* Heiltrank schluerfen und hoffen */
|
|
|
|
|
if (get_effect(du, oldpotiontype[P_HEAL]) > 0) {
|
|
|
|
|
change_effect(du, oldpotiontype[P_HEAL], -1);
|
|
|
|
|
heiltrank = 1;
|
|
|
|
|
} else if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) {
|
|
|
|
|
i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1);
|
|
|
|
|
change_effect(du, oldpotiontype[P_HEAL], 3);
|
|
|
|
|
heiltrank = 1;
|
|
|
|
|
}
|
|
|
|
|
if (heiltrank && (chance(0.50))) {
|
2005-12-31 15:01:54 +01:00
|
|
|
|
{
|
|
|
|
|
message * m = msg_message("battle::potionsave", "unit", du);
|
|
|
|
|
message_faction(b, du->faction, m);
|
|
|
|
|
msg_release(m);
|
|
|
|
|
}
|
2004-07-14 09:12:36 +02:00
|
|
|
|
assert(dt.index>=0 && dt.index<du->number);
|
|
|
|
|
df->person[dt.index].hp = du->race->hitpoints;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP, tot.\n",
|
|
|
|
|
da, ar, df->person[dt.index].hp, df->person[dt.index].hp - rda);
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2005-10-29 13:17:21 +02:00
|
|
|
|
for (pitm=&du->items; *pitm; pitm=&(*pitm)->next) {
|
|
|
|
|
const item_type * itype = (*pitm)->type;
|
|
|
|
|
if (!itype->flags & ITF_CURSED && dt.index < (*pitm)->number) {
|
|
|
|
|
/* 25% Grundchance, das ein Item kaputtgeht. */
|
2006-02-19 23:43:56 +01:00
|
|
|
|
if (rng_int() % 4 < 1) i_change(pitm, itype, -1);
|
2005-10-29 13:17:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-03-04 22:52:13 +01:00
|
|
|
|
kill_troop(dt);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-29 13:17:21 +02:00
|
|
|
|
return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-18 23:44:24 +02:00
|
|
|
|
static int
|
2006-07-30 14:52:26 +02:00
|
|
|
|
count_side(const side * s, const side * vs, int minrow, int maxrow, int select)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter * fig;
|
2004-04-18 23:44:24 +02:00
|
|
|
|
int people = 0;
|
2004-05-28 23:31:11 +02:00
|
|
|
|
int unitrow[NUMROWS];
|
|
|
|
|
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (maxrow<FIGHT_ROW) return 0;
|
|
|
|
|
if (select&SELECT_ADVANCE) {
|
|
|
|
|
memset(unitrow, -1, sizeof(unitrow));
|
2004-09-11 19:29:13 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
for (fig = s->fighters; fig; fig = fig->next) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (fig->alive - fig->removed > 0) {
|
|
|
|
|
int row = statusrow(fig->status);
|
|
|
|
|
if (select&SELECT_ADVANCE) {
|
|
|
|
|
if (unitrow[row] == -1) {
|
|
|
|
|
unitrow[row] = get_unitrow(fig, vs);
|
|
|
|
|
}
|
|
|
|
|
row = unitrow[row];
|
|
|
|
|
}
|
|
|
|
|
if (row >= minrow && row <= maxrow) {
|
|
|
|
|
people += fig->alive - fig->removed;
|
|
|
|
|
if (people>0 && (select&SELECT_FIND)) break;
|
2004-09-11 19:29:13 +02:00
|
|
|
|
}
|
2004-04-18 23:44:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return people;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
/* return the number of live allies warning: this function only considers
|
|
|
|
|
* troops that are still alive, not those that are still fighting although
|
|
|
|
|
* dead. */
|
|
|
|
|
int
|
2006-07-30 14:52:26 +02:00
|
|
|
|
count_allies(const side * as, int minrow, int maxrow, int select)
|
2006-04-13 19:16:15 +02:00
|
|
|
|
{
|
|
|
|
|
battle *b = as->battle;
|
|
|
|
|
side *s;
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (!helping(as, s)) continue;
|
2006-07-30 14:52:26 +02:00
|
|
|
|
count += count_side(s, NULL, minrow, maxrow, select);
|
|
|
|
|
if (count>0 && (select&SELECT_FIND)) break;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-04 22:30:39 +01:00
|
|
|
|
static int
|
|
|
|
|
count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, int select)
|
2004-04-18 23:44:24 +02:00
|
|
|
|
{
|
2006-07-30 14:52:26 +02:00
|
|
|
|
side *es, *as = af->side;
|
2007-03-04 22:30:39 +01:00
|
|
|
|
int i = 0;
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (es=b->sides;es!=b->sides+b->nsides;++es) {
|
2007-03-04 22:30:39 +01:00
|
|
|
|
if (as==NULL || enemy(es, as)) {
|
|
|
|
|
int offset = 0;
|
|
|
|
|
if (select&SELECT_DISTANCE) {
|
|
|
|
|
offset = get_unitrow(af, es) - FIGHT_ROW;
|
|
|
|
|
}
|
|
|
|
|
i += count_side(es, as, minrow-offset, maxrow-offset, select);
|
|
|
|
|
if (i>0 && (select&SELECT_FIND)) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-03-04 22:30:39 +01:00
|
|
|
|
int
|
|
|
|
|
count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select)
|
|
|
|
|
{
|
2007-02-24 12:08:07 +01:00
|
|
|
|
#ifdef FASTCOUNT
|
|
|
|
|
int sr = statusrow(af->status);
|
2007-03-04 22:30:39 +01:00
|
|
|
|
side *as = af->side;
|
2007-02-24 12:08:07 +01:00
|
|
|
|
|
2007-02-24 21:09:52 +01:00
|
|
|
|
if (b->alive==b->fast.alive && as==b->fast.side && sr==b->fast.status && minrow==b->fast.minrow && maxrow==b->fast.maxrow) {
|
|
|
|
|
if (b->fast.enemies[select]>=0) {
|
2007-03-04 22:30:39 +01:00
|
|
|
|
#ifdef DEBUG_FAST
|
|
|
|
|
int i = count_enemies_i(b, af, minrow, maxrow, select);
|
|
|
|
|
assert(i==b->fast.enemies[select]);
|
|
|
|
|
#endif
|
2007-02-24 21:09:52 +01:00
|
|
|
|
return b->fast.enemies[select];
|
|
|
|
|
} else if (select&SELECT_FIND) {
|
|
|
|
|
if (b->fast.enemies[select-SELECT_FIND]>=0) {
|
2007-03-04 22:30:39 +01:00
|
|
|
|
#ifdef DEBUG_FAST
|
|
|
|
|
int i = count_enemies_i(b, af, minrow, maxrow, select);
|
|
|
|
|
assert((i>0)==(b->fast.enemies[select-SELECT_FIND]>0));
|
|
|
|
|
#endif
|
2007-02-24 21:09:52 +01:00
|
|
|
|
return b->fast.enemies[select-SELECT_FIND];
|
|
|
|
|
}
|
2007-02-24 12:08:07 +01:00
|
|
|
|
}
|
2007-02-24 23:26:50 +01:00
|
|
|
|
} else if (select!=SELECT_FIND || b->alive!=b->fast.alive) {
|
2007-02-24 21:09:52 +01:00
|
|
|
|
b->fast.side = as;
|
|
|
|
|
b->fast.status = sr;
|
|
|
|
|
b->fast.minrow = minrow;
|
|
|
|
|
b->fast.alive=b->alive;
|
|
|
|
|
b->fast.maxrow = maxrow;
|
|
|
|
|
memset(b->fast.enemies, -1, sizeof(b->fast.enemies));
|
2007-02-24 12:08:07 +01:00
|
|
|
|
}
|
|
|
|
|
#endif
|
2007-03-04 22:30:39 +01:00
|
|
|
|
if (maxrow>=FIRST_ROW) {
|
|
|
|
|
int i = count_enemies_i(b, af, minrow, maxrow, select);
|
2007-02-24 12:08:07 +01:00
|
|
|
|
#ifdef FASTCOUNT
|
2007-03-04 22:30:39 +01:00
|
|
|
|
b->fast.enemies[select] = i;
|
2007-02-24 12:08:07 +01:00
|
|
|
|
#endif
|
2007-03-04 22:30:39 +01:00
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
troop
|
2006-07-30 14:52:26 +02:00
|
|
|
|
select_enemy(fighter * af, int minrow, int maxrow, int select)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-05-29 01:46:49 +02:00
|
|
|
|
side *as = af->side;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
battle * b = as->battle;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
int si, selected;
|
2004-04-18 23:44:24 +02:00
|
|
|
|
int enemies;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
#ifdef DEBUG_SELECT
|
|
|
|
|
troop result = no_troop;
|
|
|
|
|
#endif
|
2004-05-29 01:46:49 +02:00
|
|
|
|
if (af->unit->race->flags & RCF_FLY) {
|
2004-04-18 23:44:24 +02:00
|
|
|
|
/* flying races ignore min- and maxrow and can attack anyone fighting
|
|
|
|
|
* them */
|
|
|
|
|
minrow = FIGHT_ROW;
|
|
|
|
|
maxrow = BEHIND_ROW;
|
|
|
|
|
}
|
|
|
|
|
minrow = max(minrow, FIGHT_ROW);
|
|
|
|
|
|
2006-07-30 14:52:26 +02:00
|
|
|
|
enemies = count_enemies(b, af, minrow, maxrow, select);
|
2004-04-18 23:44:24 +02:00
|
|
|
|
|
2004-05-29 01:46:49 +02:00
|
|
|
|
/* Niemand ist in der angegebenen Entfernung? */
|
2004-05-31 20:21:54 +02:00
|
|
|
|
if (enemies<=0) return no_troop;
|
2004-05-29 01:46:49 +02:00
|
|
|
|
|
2007-09-16 17:34:04 +02:00
|
|
|
|
selected = rng_int() % enemies;
|
2004-05-31 20:21:54 +02:00
|
|
|
|
for (si=0;as->enemies[si];++si) {
|
2004-05-29 01:46:49 +02:00
|
|
|
|
side *ds = as->enemies[si];
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter * df;
|
2004-09-11 19:29:13 +02:00
|
|
|
|
int unitrow[NUMROWS];
|
2006-07-30 14:52:26 +02:00
|
|
|
|
int offset = 0;
|
|
|
|
|
|
|
|
|
|
if (select&SELECT_DISTANCE) offset = get_unitrow(af, ds) - FIGHT_ROW;
|
2004-05-29 01:46:49 +02:00
|
|
|
|
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (select&SELECT_ADVANCE) {
|
2004-09-11 19:29:13 +02:00
|
|
|
|
int ui;
|
|
|
|
|
for (ui=0;ui!=NUMROWS;++ui) unitrow[ui] = -1;
|
|
|
|
|
}
|
2004-05-29 01:46:49 +02:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
for (df=ds->fighters; df ; df = df->next) {
|
2004-05-29 01:46:49 +02:00
|
|
|
|
int dr;
|
|
|
|
|
|
2004-09-11 19:29:13 +02:00
|
|
|
|
dr = statusrow(df->status);
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (select&SELECT_ADVANCE) {
|
2004-09-11 19:29:13 +02:00
|
|
|
|
if (unitrow[dr]<0) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
unitrow[dr] = get_unitrow(df, as);
|
2004-09-11 19:29:13 +02:00
|
|
|
|
}
|
|
|
|
|
dr = unitrow[dr];
|
2004-05-29 01:46:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (select&SELECT_DISTANCE) dr += offset;
|
2004-04-18 23:44:24 +02:00
|
|
|
|
if (dr < minrow || dr > maxrow) continue;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if (df->alive - df->removed > selected) {
|
|
|
|
|
#ifdef DEBUG_SELECT
|
|
|
|
|
if (result.fighter==NULL) {
|
|
|
|
|
result.index = selected;
|
|
|
|
|
result.fighter = df;
|
|
|
|
|
}
|
|
|
|
|
#else
|
2006-04-13 19:16:15 +02:00
|
|
|
|
troop dt;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
dt.index = selected;
|
2004-04-18 23:44:24 +02:00
|
|
|
|
dt.fighter = df;
|
2004-05-31 20:21:54 +02:00
|
|
|
|
return dt;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
#endif
|
2004-04-18 23:44:24 +02:00
|
|
|
|
}
|
2007-09-16 17:34:04 +02:00
|
|
|
|
selected -= (df->alive - df->removed);
|
|
|
|
|
enemies -= (df->alive - df->removed);
|
2004-04-18 23:44:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if (enemies!=0) {
|
|
|
|
|
log_error(("select_enemies has a bug.\n"));
|
|
|
|
|
}
|
|
|
|
|
#ifdef DEBUG_SELECT
|
|
|
|
|
return result;
|
|
|
|
|
#else
|
|
|
|
|
assert(!selected);
|
2004-05-31 20:21:54 +02:00
|
|
|
|
return no_troop;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
#endif
|
2004-05-31 20:21:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static troop
|
2006-07-30 14:52:26 +02:00
|
|
|
|
select_opponent(battle * b, troop at, int mindist, int maxdist)
|
2004-05-31 20:21:54 +02:00
|
|
|
|
{
|
|
|
|
|
fighter * af = at.fighter;
|
2004-07-14 09:12:36 +02:00
|
|
|
|
troop dt;
|
2004-05-31 20:21:54 +02:00
|
|
|
|
|
|
|
|
|
if (af->unit->race->flags & RCF_FLY) {
|
|
|
|
|
/* flying races ignore min- and maxrow and can attack anyone fighting
|
2004-06-20 09:25:28 +02:00
|
|
|
|
* them */
|
2006-07-30 14:52:26 +02:00
|
|
|
|
dt = select_enemy(at.fighter, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);
|
|
|
|
|
} else {
|
|
|
|
|
mindist = max(mindist, FIGHT_ROW);
|
|
|
|
|
dt = select_enemy(at.fighter, mindist, maxdist, SELECT_ADVANCE);
|
2004-05-31 20:21:54 +02:00
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
|
2004-04-18 23:44:24 +02:00
|
|
|
|
return dt;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Abfrage mit
|
|
|
|
|
*
|
|
|
|
|
* cvector *fgs=fighters(b,af,FIGHT_ROW,BEHIND_ROW, FS_HELP|FS_ENEMY);
|
|
|
|
|
* fighter *fig;
|
|
|
|
|
*
|
2006-04-16 00:10:57 +02:00
|
|
|
|
* Optional: Verwirbeln. Vorsicht: Aufw<EFBFBD>ndig!
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* v_scramble(fgs->begin, fgs->end);
|
|
|
|
|
*
|
|
|
|
|
* for (fig = fgs->begin; fig != fgs->end; ++fig) {
|
|
|
|
|
* fighter *df = *fig;
|
|
|
|
|
*
|
|
|
|
|
* }
|
|
|
|
|
*
|
2005-06-11 10:09:55 +02:00
|
|
|
|
* cv_kill(fgs); free(fgs); Nicht vergessen
|
2001-01-25 10:37:55 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
cvector *
|
2006-07-30 14:52:26 +02:00
|
|
|
|
fighters(battle *b, const side * vs, int minrow, int maxrow, int mask)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-13 19:16:15 +02:00
|
|
|
|
side * s;
|
|
|
|
|
cvector *fightervp = malloc(sizeof(cvector));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-07-30 14:52:26 +02:00
|
|
|
|
assert(vs!=NULL);
|
2004-05-22 02:01:00 +02:00
|
|
|
|
cv_init(fightervp);
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *fig;
|
2007-10-14 21:55:06 +02:00
|
|
|
|
|
|
|
|
|
if (mask==FS_ENEMY) {
|
|
|
|
|
if (!enemy(s, vs)) continue;
|
|
|
|
|
} else if (mask==FS_HELP) {
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (enemy(s, vs) || !allysf(s, vs->faction)) {
|
2007-10-14 21:55:06 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
assert(mask==(FS_HELP|FS_ENEMY) || !"invalid alliance state");
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
for (fig = s->fighters; fig; fig = fig->next) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
int row = get_unitrow(fig, vs);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (row >= minrow && row <= maxrow) {
|
2007-10-14 21:55:06 +02:00
|
|
|
|
cv_pushback(fightervp, fig);
|
2004-05-22 02:01:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-22 02:01:00 +02:00
|
|
|
|
return fightervp;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
static void
|
2005-10-08 17:44:40 +02:00
|
|
|
|
report_failed_spell(battle * b, unit * mage, const spell * sp)
|
2004-04-20 00:52:36 +02:00
|
|
|
|
{
|
|
|
|
|
message * m = msg_message("battle::spell_failed", "unit spell", mage, sp);
|
|
|
|
|
message_all(b, m);
|
|
|
|
|
msg_release(m);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_combatmagic(battle *b, combatmagic_t was)
|
|
|
|
|
{
|
2006-04-13 19:16:15 +02:00
|
|
|
|
side * s;
|
2006-02-09 20:57:25 +01:00
|
|
|
|
region *r = b->region;
|
|
|
|
|
castorder *co;
|
2007-03-25 20:37:28 +02:00
|
|
|
|
int level, rank, sl;
|
|
|
|
|
spellrank spellranks[MAX_SPELLRANK];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-03-25 20:37:28 +02:00
|
|
|
|
memset(spellranks, 0, sizeof(spellranks));
|
2006-02-09 20:57:25 +01:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter * fig;
|
|
|
|
|
for (fig = s->fighters; fig; fig = fig->next) {
|
|
|
|
|
unit * mage = fig->unit;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (fig->alive <= 0) continue; /* fighter kann im Kampf get<65>tet worden sein */
|
2001-04-29 20:23:40 +02:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
level = eff_skill(mage, SK_MAGIC, r);
|
|
|
|
|
if (level > 0) {
|
|
|
|
|
double power;
|
|
|
|
|
const spell *sp;
|
|
|
|
|
const struct locale * lang = mage->faction->locale;
|
|
|
|
|
order * ord;
|
2001-04-29 20:23:40 +02:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
switch(was) {
|
2006-02-09 20:57:25 +01:00
|
|
|
|
case DO_PRECOMBATSPELL:
|
|
|
|
|
sp = get_combatspell(mage, 0);
|
|
|
|
|
sl = get_combatspelllevel(mage, 0);
|
|
|
|
|
break;
|
|
|
|
|
case DO_POSTCOMBATSPELL:
|
|
|
|
|
sp = get_combatspell(mage, 2);
|
|
|
|
|
sl = get_combatspelllevel(mage, 2);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* Fehler! */
|
|
|
|
|
return;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
|
|
|
|
if (sp == NULL)
|
|
|
|
|
continue;
|
2001-04-29 20:23:40 +02:00
|
|
|
|
|
2007-06-26 23:17:10 +02:00
|
|
|
|
ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang));
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (cancast(mage, sp, 1, 1, ord) == false) {
|
|
|
|
|
free_order(ord);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
level = eff_spelllevel(mage, sp, level, 1);
|
|
|
|
|
if (sl > 0) level = min(sl, level);
|
|
|
|
|
if (level < 0) {
|
|
|
|
|
report_failed_spell(b, mage, sp);
|
|
|
|
|
free_order(ord);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
power = spellpower(r, mage, sp, level, ord);
|
|
|
|
|
free_order(ord);
|
|
|
|
|
if (power <= 0) { /* Effekt von Antimagie */
|
|
|
|
|
report_failed_spell(b, mage, sp);
|
|
|
|
|
pay_spell(mage, sp, level, 1);
|
|
|
|
|
} else if (fumble(r, mage, sp, sp->level) == true) {
|
|
|
|
|
report_failed_spell(b, mage, sp);
|
|
|
|
|
pay_spell(mage, sp, level, 1);
|
|
|
|
|
} else {
|
|
|
|
|
co = new_castorder(fig, 0, sp, r, level, power, 0, 0, 0);
|
2007-03-25 20:37:28 +02:00
|
|
|
|
add_castorder(&spellranks[sp->rank], co);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
2006-02-09 20:57:25 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-03-25 20:37:28 +02:00
|
|
|
|
for (rank = 0; rank < MAX_SPELLRANK; rank++) {
|
|
|
|
|
for (co = spellranks[rank].begin; co; co = co->next) {
|
2006-02-09 20:57:25 +01:00
|
|
|
|
fighter * fig = co->magician.fig;
|
|
|
|
|
const spell * sp = co->sp;
|
|
|
|
|
int level = co->level;
|
|
|
|
|
double power = co->force;
|
2006-05-07 23:11:49 +02:00
|
|
|
|
|
2006-02-09 20:57:25 +01:00
|
|
|
|
if (sp->sp_function==NULL) {
|
|
|
|
|
log_error(("spell '%s' has no function.\n", sp->sname));
|
|
|
|
|
} else {
|
|
|
|
|
level = ((cspell_f)sp->sp_function)(fig, level, power, sp);
|
|
|
|
|
if (level > 0) {
|
|
|
|
|
pay_spell(fig->unit, sp, level, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-03-25 20:37:28 +02:00
|
|
|
|
for (rank = 0; rank < MAX_SPELLRANK; rank++) {
|
|
|
|
|
free_castorders(spellranks[rank].begin);
|
2006-02-09 20:57:25 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-01-31 11:17:53 +01:00
|
|
|
|
static void
|
|
|
|
|
combat_action(fighter * af, int turn)
|
|
|
|
|
{
|
|
|
|
|
#ifndef SIMPLE_COMBAT
|
|
|
|
|
af->action_counter++;
|
|
|
|
|
af->side->bf->lastturn = turn;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-01-20 12:03:50 +01:00
|
|
|
|
static void
|
2006-07-30 14:52:26 +02:00
|
|
|
|
do_combatspell(troop at)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2005-10-08 17:44:40 +02:00
|
|
|
|
const spell *sp;
|
2004-05-21 13:49:08 +02:00
|
|
|
|
fighter *fi = at.fighter;
|
|
|
|
|
unit *mage = fi->unit;
|
|
|
|
|
battle *b = fi->side->battle;
|
|
|
|
|
region *r = b->region;
|
|
|
|
|
int level;
|
2004-02-09 22:12:46 +01:00
|
|
|
|
double power;
|
2004-05-21 13:49:08 +02:00
|
|
|
|
int fumblechance = 0;
|
|
|
|
|
void **mg;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
order * ord;
|
2004-05-21 13:49:08 +02:00
|
|
|
|
int sl;
|
|
|
|
|
const struct locale * lang = mage->faction->locale;
|
|
|
|
|
|
|
|
|
|
sp = get_combatspell(mage, 1);
|
|
|
|
|
if (sp == NULL) {
|
|
|
|
|
fi->magic = 0; /* Hat keinen Kampfzauber, k<>mpft nichtmagisch weiter */
|
|
|
|
|
return;
|
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (cancast(mage, sp, 1, 1, ord) == false) {
|
2004-05-21 13:49:08 +02:00
|
|
|
|
fi->magic = 0; /* Kann nicht mehr Zaubern, k<>mpft nichtmagisch weiter */
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-21 13:49:08 +02:00
|
|
|
|
level = eff_spelllevel(mage, sp, fi->magic, 1);
|
|
|
|
|
if ((sl = get_combatspelllevel(mage, 1)) > 0) level = min(level, sl);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-21 13:49:08 +02:00
|
|
|
|
if (fumble(r, mage, sp, sp->level) == true) {
|
|
|
|
|
report_failed_spell(b, mage, sp);
|
|
|
|
|
pay_spell(mage, sp, level, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-21 13:49:08 +02:00
|
|
|
|
for (mg = b->meffects.begin; mg != b->meffects.end; ++mg) {
|
|
|
|
|
meffect *mblock = *mg;
|
|
|
|
|
if (mblock->typ == SHIELD_BLOCK) {
|
|
|
|
|
if (meffect_blocked(b, mblock, fi->side) != 0) {
|
|
|
|
|
fumblechance += mblock->duration;
|
|
|
|
|
mblock->duration -= mblock->effect;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-21 13:49:08 +02:00
|
|
|
|
/* Antimagie die Fehlschlag erh<72>ht */
|
2006-02-19 23:43:56 +01:00
|
|
|
|
if (rng_int()%100 < fumblechance) {
|
2004-05-21 13:49:08 +02:00
|
|
|
|
report_failed_spell(b, mage, sp);
|
|
|
|
|
pay_spell(mage, sp, level, 1);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
free_order(ord);
|
2004-05-21 13:49:08 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
power = spellpower(r, mage, sp, level, ord);
|
|
|
|
|
free_order(ord);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (power <= 0) { /* Effekt von Antimagie */
|
2004-05-21 13:49:08 +02:00
|
|
|
|
report_failed_spell(b, mage, sp);
|
|
|
|
|
pay_spell(mage, sp, level, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-02-09 20:57:25 +01:00
|
|
|
|
if (sp->sp_function==NULL) {
|
|
|
|
|
log_error(("spell '%s' has no function.\n", sp->sname));
|
|
|
|
|
} else {
|
|
|
|
|
level = ((cspell_f)sp->sp_function)(fi, level, power, sp);
|
|
|
|
|
if (level > 0) {
|
|
|
|
|
pay_spell(mage, sp, level, 1);
|
2007-01-31 11:17:53 +01:00
|
|
|
|
combat_action(at.fighter, b->turn);
|
2006-02-09 20:57:25 +01:00
|
|
|
|
}
|
2004-05-21 13:49:08 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Sonderattacken: Monster patzern nicht und zahlen auch keine
|
|
|
|
|
* Spruchkosten. Da die Spruchst<EFBFBD>rke direkt durch den Level bestimmt
|
|
|
|
|
* wird, wirkt auch keine Antimagie (wird sonst in spellpower
|
|
|
|
|
* gemacht) */
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static void
|
|
|
|
|
do_extra_spell(troop at, const att *a)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-02-09 20:57:25 +01:00
|
|
|
|
const spell *sp = a->data.sp;
|
|
|
|
|
fighter *fi = at.fighter;
|
|
|
|
|
unit *au = fi->unit;
|
|
|
|
|
int power;
|
|
|
|
|
|
|
|
|
|
/* nur bei Monstern k<>nnen mehrere 'Magier' in einer Einheit sein */
|
|
|
|
|
power = sp->level * au->number;
|
|
|
|
|
if (sp->sp_function==NULL) {
|
|
|
|
|
log_error(("spell '%s' has no function.\n", sp->sname));
|
|
|
|
|
} else {
|
|
|
|
|
((cspell_f)sp->sp_function)(fi, sp->level, power, sp);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
skilldiff(troop at, troop dt, int dist)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter *af = at.fighter, *df = dt.fighter;
|
|
|
|
|
unit *au = af->unit, *du = df->unit;
|
|
|
|
|
int is_protected = 0, skdiff = 0, sk;
|
|
|
|
|
weapon * awp = select_weapon(at, true, dist>1);
|
|
|
|
|
weapon * dwp = select_weapon(dt, false, dist>1);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (df->person[dt.index].flags & FL_SLEEPING)
|
|
|
|
|
skdiff += 2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Effekte durch Rassen */
|
|
|
|
|
if (awp!=NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) {
|
|
|
|
|
skdiff += 5;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#ifdef KARMA_MODULE
|
|
|
|
|
/* Werwolf */
|
|
|
|
|
if(fval(au, UFL_WERE)) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
skdiff += fspecial(au->faction, FS_LYCANTROPE);
|
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
2002-04-12 14:46:16 +02:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (au->race == new_race[RC_GOBLIN] &&
|
|
|
|
|
af->side->size[SUM_ROW] >= df->side->size[SUM_ROW] * 10)
|
|
|
|
|
skdiff += 1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-05-05 03:37:08 +02:00
|
|
|
|
#ifdef KARMA_MODULE
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* TODO this should be a skillmod */
|
|
|
|
|
skdiff += jihad(au->faction, du->race);
|
|
|
|
|
#endif
|
|
|
|
|
skdiff += af->person[at.index].attack;
|
|
|
|
|
skdiff -= df->person[dt.index].defence;
|
|
|
|
|
|
|
|
|
|
if (df->building) {
|
|
|
|
|
boolean init = false;
|
|
|
|
|
static const curse_type * strongwall_ct, * magicwalls_ct;
|
|
|
|
|
if (!init) {
|
|
|
|
|
strongwall_ct = ct_find("strongwall");
|
|
|
|
|
magicwalls_ct = ct_find("magicwalls");
|
|
|
|
|
init=true;
|
|
|
|
|
}
|
|
|
|
|
if (df->building->type->flags & BTF_PROTECTION) {
|
2006-02-17 23:59:03 +01:00
|
|
|
|
int beff = buildingeffsize(df->building, false)-1;
|
|
|
|
|
/* -1 because the tradepost has no protection value */
|
|
|
|
|
|
|
|
|
|
#ifdef KARMA_MODULE
|
|
|
|
|
if (fspecial(au->faction, FS_SAPPER)) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Halbe Schutzwirkung, aufgerundet */
|
|
|
|
|
beff = (beff+1)/2;
|
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
|
|
|
|
skdiff -= beff;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
is_protected = 2;
|
|
|
|
|
}
|
|
|
|
|
if (strongwall_ct) {
|
|
|
|
|
curse * c = get_curse(df->building->attribs, strongwall_ct);
|
|
|
|
|
if (curse_active(c)) {
|
|
|
|
|
/* wirkt auf alle Geb<65>ude */
|
|
|
|
|
skdiff -= curse_geteffect(c);
|
|
|
|
|
is_protected = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (magicwalls_ct && curse_active(get_curse(df->building->attribs, magicwalls_ct))) {
|
|
|
|
|
/* Verdoppelt Burgenbonus */
|
|
|
|
|
skdiff -= buildingeffsize(df->building, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Goblin-Verteidigung
|
|
|
|
|
* ist direkt in der Rassentabelle als df_default
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Effekte der Waffen */
|
|
|
|
|
skdiff += weapon_effskill(at, dt, awp, true, dist>1);
|
|
|
|
|
if (awp && fval(awp->type, WTF_MISSILE)) {
|
|
|
|
|
skdiff -= is_protected;
|
|
|
|
|
if (awp->type->modifiers) {
|
|
|
|
|
int w;
|
|
|
|
|
for (w=0;awp->type->modifiers[w].value!=0;++w) {
|
|
|
|
|
if (awp->type->modifiers[w].flags & WMF_MISSILE_TARGET) {
|
2004-06-11 21:59:02 +02:00
|
|
|
|
/* skill decreases by targeting difficulty (bow -2, catapult -4) */
|
2006-04-10 23:13:22 +02:00
|
|
|
|
skdiff -= awp->type->modifiers[w].value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sk = weapon_effskill(dt, at, dwp, false, dist>1);
|
|
|
|
|
skdiff -= sk;
|
|
|
|
|
return skdiff;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
setreload(troop at)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter * af = at.fighter;
|
|
|
|
|
const weapon_type * wtype = af->person[at.index].missile->type;
|
|
|
|
|
if (wtype->reload == 0) return 0;
|
|
|
|
|
return af->person[at.index].reload = wtype->reload;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
getreload(troop at)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return at.fighter->person[at.index].reload;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-06-26 23:17:10 +02:00
|
|
|
|
static void
|
|
|
|
|
debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, int skdiff, int dist, boolean success)
|
|
|
|
|
{
|
|
|
|
|
fprintf(bdebug, "%.4s/%d [%6s/%d] %s %.4s/%d [%6s/%d] with %d distance %d",
|
|
|
|
|
unitid(at.fighter->unit), at.index,
|
|
|
|
|
LOC(default_locale, awp ? resourcename(awp->type->itype->rtype, 0) : "unarmed"),
|
|
|
|
|
weapon_effskill(at, dt, awp, true, dist>1),
|
|
|
|
|
success?"hits":"misses",
|
|
|
|
|
unitid(dt.fighter->unit), dt.index,
|
|
|
|
|
LOC(default_locale, dwp ? resourcename(dwp->type->itype->rtype, 0) : "unarmed"),
|
|
|
|
|
weapon_effskill(dt, at, dwp, false, dist>1),
|
|
|
|
|
skdiff, dist);
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int
|
|
|
|
|
hits(troop at, troop dt, weapon * awp)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter *af = at.fighter, *df = dt.fighter;
|
2005-07-31 03:07:07 +02:00
|
|
|
|
const armor_type * armor, * shield;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
int skdiff = 0;
|
2006-07-30 14:52:26 +02:00
|
|
|
|
int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
weapon * dwp = select_weapon(dt, false, dist>1);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!df->alive) return 0;
|
|
|
|
|
if (getreload(at)) return 0;
|
|
|
|
|
if (dist>1 && (awp == NULL || !fval(awp->type, WTF_MISSILE))) return 0;
|
2005-02-12 20:54:32 +01:00
|
|
|
|
|
|
|
|
|
/* mark this person as hit. */
|
2005-02-13 11:05:22 +01:00
|
|
|
|
df->person[dt.index].flags |= FL_HIT;
|
2005-02-12 20:54:32 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (af->person[at.index].flags & FL_STUNNED) {
|
|
|
|
|
af->person[at.index].flags &= ~FL_STUNNED;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if ((af->person[at.index].flags & FL_TIRED && rng_int()%100 < 50)
|
|
|
|
|
|| (af->person[at.index].flags & FL_SLEEPING))
|
|
|
|
|
return 0;
|
2006-07-13 00:02:24 +02:00
|
|
|
|
|
|
|
|
|
/* effect of sp_reeling_arrows combatspell */
|
|
|
|
|
if (af->side->battle->reelarrow && awp && fval(awp->type, WTF_MISSILE) && rng_double() < 0.5) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
skdiff = skilldiff(at, dt, dist);
|
|
|
|
|
|
|
|
|
|
/* Verteidiger bekommt eine R<>stung */
|
|
|
|
|
armor = select_armor(dt, true);
|
|
|
|
|
shield = select_armor(dt, false);
|
|
|
|
|
if (contest(skdiff, armor, shield)) {
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
debug_hit(at, awp, dt, dwp, skdiff, dist, true);
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
debug_hit(at, awp, dt, dwp, skdiff, dist, false);
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dazzle(battle *b, troop *td)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Nicht kumulativ ! */
|
|
|
|
|
if(td->fighter->person[td->index].flags & FL_DAZZLED) return;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef TODO_RUNESWORD
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (td->fighter->weapon[WP_RUNESWORD].count > td->index) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (td->fighter->person[td->index].flags & FL_COURAGE) {
|
2007-08-29 21:48:40 +02:00
|
|
|
|
return;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (td->fighter->person[td->index].flags & FL_DAZZLED) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
td->fighter->person[td->index].flags |= FL_DAZZLED;
|
|
|
|
|
td->fighter->person[td->index].defence--;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TODO: Geb<65>ude/Schiffe sollten auch zerst<73>rbar sein. Schwierig im Kampf,
|
|
|
|
|
* besonders bei Schiffen. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
damage_building(battle *b, building *bldg, int damage_abs)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
bldg->size = max(1, bldg->size-damage_abs);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Wenn Burg, dann gucken, ob die Leute alle noch in das Geb<65>ude passen. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (bldg->type->flags & BTF_PROTECTION) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
side * s;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
bldg->sizeleft = bldg->size;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter * fig;
|
|
|
|
|
for (fig=s->fighters;fig;fig=fig->next) {
|
|
|
|
|
if (fig->building == bldg) {
|
|
|
|
|
if (bldg->sizeleft >= fig->unit->number) {
|
|
|
|
|
fig->building = bldg;
|
|
|
|
|
bldg->sizeleft -= fig->unit->number;
|
|
|
|
|
} else {
|
|
|
|
|
fig->building = NULL;
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
attacks_per_round(troop t)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return t.fighter->person[t.index].speed;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-08-03 17:34:26 +02:00
|
|
|
|
|
|
|
|
|
#ifdef HEROES
|
|
|
|
|
#define HERO_SPEED 10
|
|
|
|
|
static void
|
|
|
|
|
make_heroes(battle * b)
|
|
|
|
|
{
|
|
|
|
|
side * s;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2004-08-03 17:34:26 +02:00
|
|
|
|
fighter * fig;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
for (fig=s->fighters;fig;fig=fig->next) {
|
2004-08-03 17:34:26 +02:00
|
|
|
|
unit * u = fig->unit;
|
|
|
|
|
if (fval(u, UFL_HERO)) {
|
|
|
|
|
int i;
|
|
|
|
|
assert(playerrace(u->race));
|
|
|
|
|
for (i=0;i!=u->number;++i) {
|
|
|
|
|
fig->person[i].speed += (HERO_SPEED-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-08-03 17:34:26 +02:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static void
|
2004-09-02 21:19:25 +02:00
|
|
|
|
attack(battle *b, troop ta, const att *a, int numattack)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter *af = ta.fighter;
|
|
|
|
|
troop td;
|
|
|
|
|
unit *au = af->unit;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
switch(a->type) {
|
2005-10-16 22:11:34 +02:00
|
|
|
|
case AT_COMBATSPELL:
|
2006-07-30 14:52:26 +02:00
|
|
|
|
/* Magier versuchen immer erstmal zu zaubern, erst wenn das
|
|
|
|
|
* fehlschl<EFBFBD>gt, wird af->magic == 0 und der Magier k<EFBFBD>mpft
|
|
|
|
|
* konventionell weiter */
|
2005-10-16 22:11:34 +02:00
|
|
|
|
if (numattack==0 && af->magic > 0) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
/* wenn der magier in die potenzielle Reichweite von Attacken des
|
|
|
|
|
* Feindes kommt, beginnt er auch bei einem Status von KAEMPFE NICHT,
|
|
|
|
|
* Kampfzauber zu schleudern: */
|
|
|
|
|
if (count_enemies(b, af, melee_range[0], missile_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND)) {
|
|
|
|
|
do_combatspell(ta);
|
|
|
|
|
}
|
2005-10-16 22:11:34 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
case AT_STANDARD: /* Waffen, mag. Gegenst<73>nde, Kampfzauber */
|
2005-10-16 22:11:34 +02:00
|
|
|
|
if (numattack > 0 || af->magic <= 0) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
weapon * wp = ta.fighter->person[ta.index].missile;
|
2006-07-30 14:52:26 +02:00
|
|
|
|
int melee = count_enemies(b, af, melee_range[0], melee_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND);
|
|
|
|
|
if (melee) wp = preferred_weapon(ta, true);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Sonderbehandlungen */
|
|
|
|
|
|
|
|
|
|
if (getreload(ta)) {
|
|
|
|
|
ta.fighter->person[ta.index].reload--;
|
|
|
|
|
} else {
|
|
|
|
|
boolean standard_attack = true;
|
2004-10-16 02:46:38 +02:00
|
|
|
|
boolean reload = false;
|
2004-09-02 21:19:25 +02:00
|
|
|
|
/* spezialattacken der waffe nur, wenn erste attacke in der runde.
|
|
|
|
|
* sonst helden mit feuerschwertern zu m<EFBFBD>chtig */
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (numattack==0 && wp && wp->type->attack) {
|
|
|
|
|
int dead = 0;
|
2006-07-30 14:52:26 +02:00
|
|
|
|
standard_attack = wp->type->attack(&ta, wp->type, &dead);
|
2004-10-16 02:46:38 +02:00
|
|
|
|
if (!standard_attack) reload = true;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
af->catmsg += dead;
|
|
|
|
|
if (!standard_attack && af->person[ta.index].last_action < b->turn) {
|
|
|
|
|
af->person[ta.index].last_action = b->turn;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
combat_action(af, b->turn);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (standard_attack) {
|
|
|
|
|
boolean missile = false;
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (wp && fval(wp->type, WTF_MISSILE)) missile = true;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (missile) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
td = select_opponent(b, ta, missile_range[0], missile_range[1]);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
td = select_opponent(b, ta, melee_range[0], melee_range[1]);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (!td.fighter) return;
|
|
|
|
|
if (ta.fighter->person[ta.index].last_action < b->turn) {
|
|
|
|
|
ta.fighter->person[ta.index].last_action = b->turn;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
combat_action(ta.fighter, b->turn);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
2004-10-16 02:46:38 +02:00
|
|
|
|
reload = true;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (hits(ta, td, wp)) {
|
|
|
|
|
const char * d;
|
|
|
|
|
if (wp == NULL) d = au->race->def_damage;
|
|
|
|
|
else if (riding(ta)) d = wp->type->damage[1];
|
|
|
|
|
else d = wp->type->damage[0];
|
|
|
|
|
terminate(td, ta, a->type, d, missile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (reload && wp && wp->type->reload && !getreload(ta)) {
|
|
|
|
|
int i = setreload(ta);
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
fprintf(bdebug, " reloading %d turns\n", i);
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AT_SPELL: /* Extra-Spr<70>che. Kampfzauber in AT_COMBATSPELL! */
|
|
|
|
|
do_extra_spell(ta, a);
|
|
|
|
|
break;
|
|
|
|
|
case AT_NATURAL:
|
2006-07-30 14:52:26 +02:00
|
|
|
|
td = select_opponent(b, ta, melee_range[0], melee_range[1]);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!td.fighter) return;
|
|
|
|
|
if(ta.fighter->person[ta.index].last_action < b->turn) {
|
|
|
|
|
ta.fighter->person[ta.index].last_action = b->turn;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
combat_action(ta.fighter, b->turn);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (hits(ta, td, NULL)) {
|
|
|
|
|
terminate(td, ta, a->type, a->data.dice, false);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AT_DRAIN_ST:
|
2006-07-30 14:52:26 +02:00
|
|
|
|
td = select_opponent(b, ta, melee_range[0], melee_range[1]);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!td.fighter) return;
|
|
|
|
|
if(ta.fighter->person[ta.index].last_action < b->turn) {
|
|
|
|
|
ta.fighter->person[ta.index].last_action = b->turn;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
combat_action(ta.fighter, b->turn);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (hits(ta, td, NULL)) {
|
|
|
|
|
int c = dice_rand(a->data.dice);
|
|
|
|
|
while(c > 0) {
|
|
|
|
|
if (rng_int()%2) {
|
|
|
|
|
td.fighter->person[td.index].attack -= 1;
|
|
|
|
|
} else {
|
|
|
|
|
td.fighter->person[td.index].defence -= 1;
|
|
|
|
|
}
|
|
|
|
|
c--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AT_DRAIN_EXP:
|
2006-07-30 14:52:26 +02:00
|
|
|
|
td = select_opponent(b, ta, melee_range[0], melee_range[1]);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!td.fighter) return;
|
|
|
|
|
if(ta.fighter->person[ta.index].last_action < b->turn) {
|
|
|
|
|
ta.fighter->person[ta.index].last_action = b->turn;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
combat_action(ta.fighter, b->turn);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (hits(ta, td, NULL)) {
|
|
|
|
|
drain_exp(td.fighter->unit, dice_rand(a->data.dice));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AT_DAZZLE:
|
2006-07-30 14:52:26 +02:00
|
|
|
|
td = select_opponent(b, ta, melee_range[0], melee_range[1]);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!td.fighter) return;
|
|
|
|
|
if(ta.fighter->person[ta.index].last_action < b->turn) {
|
|
|
|
|
ta.fighter->person[ta.index].last_action = b->turn;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
combat_action(ta.fighter, b->turn);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (hits(ta, td, NULL)) {
|
|
|
|
|
dazzle(b, &td);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AT_STRUCTURAL:
|
2006-07-30 14:52:26 +02:00
|
|
|
|
td = select_opponent(b, ta, melee_range[0], melee_range[1]);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (!td.fighter) return;
|
|
|
|
|
if(ta.fighter->person[ta.index].last_action < b->turn) {
|
|
|
|
|
ta.fighter->person[ta.index].last_action = b->turn;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
combat_action(ta.fighter, b->turn);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (td.fighter->unit->ship) {
|
|
|
|
|
td.fighter->unit->ship->damage += DAMAGE_SCALE * dice_rand(a->data.dice);
|
|
|
|
|
} else if (td.fighter->unit->building) {
|
|
|
|
|
damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice));
|
2006-02-10 20:48:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_attack(fighter * af)
|
|
|
|
|
{
|
2004-09-11 19:29:13 +02:00
|
|
|
|
troop ta;
|
|
|
|
|
unit *au = af->unit;
|
|
|
|
|
side *side = af->side;
|
|
|
|
|
battle *b = side->battle;
|
|
|
|
|
|
|
|
|
|
ta.fighter = af;
|
|
|
|
|
|
|
|
|
|
assert(au && au->number);
|
|
|
|
|
/* Da das Zuschlagen auf Einheiten und nicht auf den einzelnen
|
|
|
|
|
* K<EFBFBD>mpfern beruht, darf die Reihenfolge und Gr<EFBFBD><EFBFBD>e der Einheit keine
|
|
|
|
|
* Rolle spielen, Das tut sie nur dann, wenn jeder, der am Anfang der
|
|
|
|
|
* Runde lebte, auch zuschlagen darf. Ansonsten ist der, der zuf<EFBFBD>llig
|
|
|
|
|
* mit einer gro<EFBFBD>en Einheit zuerst drankommt, extrem bevorteilt. */
|
|
|
|
|
ta.index = af->fighting;
|
|
|
|
|
|
|
|
|
|
while (ta.index--) {
|
|
|
|
|
/* Wir suchen eine beliebige Feind-Einheit aus. An der k<>nnen
|
|
|
|
|
* wir feststellen, ob noch jemand da ist. */
|
2004-08-03 17:34:26 +02:00
|
|
|
|
int apr, attacks = attacks_per_round(ta);
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-09-11 19:29:13 +02:00
|
|
|
|
for (apr=0;apr!=attacks;++apr) {
|
2004-08-03 17:34:26 +02:00
|
|
|
|
int a;
|
2004-09-11 19:29:13 +02:00
|
|
|
|
for (a=0; a!=10 && au->race->attack[a].type!=AT_NONE; ++a) {
|
2004-08-03 17:34:26 +02:00
|
|
|
|
if (apr>0) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Wenn die Waffe nachladen muss, oder es sich nicht um einen
|
2004-09-11 19:29:13 +02:00
|
|
|
|
* Waffen-Angriff handelt, dann gilt der Speed nicht. */
|
2004-08-03 17:34:26 +02:00
|
|
|
|
if (au->race->attack[a].type!=AT_STANDARD) continue;
|
|
|
|
|
else {
|
|
|
|
|
weapon * wp = preferred_weapon(ta, true);
|
2004-08-07 23:42:05 +02:00
|
|
|
|
if (wp!=NULL && wp->type->reload) continue;
|
2004-08-03 17:34:26 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-09-02 21:19:25 +02:00
|
|
|
|
attack(b, ta, &(au->race->attack[a]), apr);
|
2004-09-11 19:29:13 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-11-25 22:11:05 +01:00
|
|
|
|
/* Der letzte Katapultsch<63>tze setzt die
|
|
|
|
|
* Ladezeit neu und generiert die Meldung. */
|
|
|
|
|
if (af->catmsg>=0) {
|
|
|
|
|
struct message * m = msg_message("battle::killed", "unit dead", au, af->catmsg);
|
|
|
|
|
message_all(b, m);
|
|
|
|
|
msg_release(m);
|
|
|
|
|
af->catmsg = -1;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_regenerate(fighter *af)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
troop ta;
|
|
|
|
|
unit *au = af->unit;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
ta.fighter = af;
|
|
|
|
|
ta.index = af->fighting;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
while(ta.index--) {
|
|
|
|
|
af->person[ta.index].hp += effskill(au, SK_AUSDAUER);
|
|
|
|
|
af->person[ta.index].hp = min(unit_max_hp(au), af->person[ta.index].hp);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
add_tactics(tactics * ta, fighter * fig, int value)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (value == 0 || value < ta->value)
|
|
|
|
|
return;
|
|
|
|
|
if (value > ta->value)
|
|
|
|
|
cv_kill(&ta->fighters);
|
|
|
|
|
cv_pushback(&ta->fighters, fig);
|
|
|
|
|
cv_pushback(&fig->side->battle->leaders, fig);
|
|
|
|
|
ta->value = value;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
|
fleechance(unit * u)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
double c = 0.20; /* Fluchtwahrscheinlichkeit in % */
|
|
|
|
|
region * r = u->region;
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_fleechance);
|
|
|
|
|
/* Einheit u versucht, dem Get<65>mmel zu entkommen */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
c += (eff_skill(u, SK_STEALTH, r) * 0.05);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-10-13 00:14:01 +02:00
|
|
|
|
if (get_item(u, I_ELVENHORSE) >= u->number && eff_skill(u, SK_RIDING, r) >= 5)
|
2006-04-10 23:13:22 +02:00
|
|
|
|
c += 0.30;
|
|
|
|
|
else if (get_item(u, I_HORSE) >= u->number && eff_skill(u, SK_RIDING, r) >= 1)
|
|
|
|
|
c += 0.10;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (u->race == new_race[RC_HALFLING]) {
|
|
|
|
|
c += 0.20;
|
|
|
|
|
c = min(c, 0.90);
|
|
|
|
|
} else {
|
|
|
|
|
c = min(c, 0.75);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (a!=NULL) c += a->data.flt;
|
2002-01-01 21:51:18 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return c;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
/** add a new army to the conflict
|
|
|
|
|
* beware: armies need to be added _at the beginning_ of the list because
|
|
|
|
|
* otherwise join_allies() will get into trouble */
|
2007-01-31 11:17:53 +01:00
|
|
|
|
static side *
|
2006-04-13 19:16:15 +02:00
|
|
|
|
make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction *stealthfaction)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-10-27 17:09:36 +02:00
|
|
|
|
side *s1 = b->sides+b->nsides;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
bfaction * bf;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
|
|
|
|
|
#ifdef SIMPLE_COMBAT
|
|
|
|
|
if (!fval(b->region->terrain, LAND_REGION)) {
|
2007-10-27 17:09:36 +02:00
|
|
|
|
/* every fight in an ocean is short */
|
2007-01-31 11:17:53 +01:00
|
|
|
|
flags |= SIDE_HASGUARDS;
|
|
|
|
|
} else {
|
2007-01-31 16:30:57 +01:00
|
|
|
|
unit * u;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
for (u = b->region->units; u; u = u->next) {
|
|
|
|
|
if (getguard(u)) {
|
2007-03-04 19:40:52 +01:00
|
|
|
|
if (alliedunit(u, f, HELP_GUARD)) {
|
2007-01-31 11:17:53 +01:00
|
|
|
|
flags |= SIDE_HASGUARDS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
|
|
|
|
s1->battle = b;
|
|
|
|
|
s1->group = g;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
s1->flags = flags;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
s1->stealthfaction = stealthfaction;
|
|
|
|
|
for (bf = b->factions;bf;bf=bf->next) {
|
|
|
|
|
faction * f2 = bf->faction;
|
|
|
|
|
|
|
|
|
|
if (f2 == f) {
|
|
|
|
|
s1->bf = bf;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
s1->faction = f2;
|
|
|
|
|
s1->index = b->nsides++;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
s1->nextF = bf->sides;
|
|
|
|
|
bf->sides = s1;
|
2007-01-31 16:28:51 +01:00
|
|
|
|
assert(b->nsides<=MAXSIDES);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(bf);
|
|
|
|
|
return s1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
loot_items(fighter * corpse)
|
|
|
|
|
{
|
2004-09-11 19:29:13 +02:00
|
|
|
|
unit * u = corpse->unit;
|
|
|
|
|
item * itm = u->items;
|
|
|
|
|
battle * b = corpse->side->battle;
|
2007-03-05 19:37:58 +01:00
|
|
|
|
int dead = dead_fighters(corpse);
|
|
|
|
|
|
|
|
|
|
if (dead<=0) return;
|
2004-09-11 19:29:13 +02:00
|
|
|
|
|
|
|
|
|
while (itm) {
|
2007-03-05 19:37:58 +01:00
|
|
|
|
float lootfactor = dead/(float)u->number; /* only loot the dead! */
|
2007-04-19 16:54:17 +02:00
|
|
|
|
int maxloot = (int)(itm->number*lootfactor);
|
|
|
|
|
if (maxloot>0) {
|
|
|
|
|
int i = min(10, maxloot);
|
2007-02-18 18:43:23 +01:00
|
|
|
|
for (; i != 0; --i) {
|
2007-04-19 16:54:17 +02:00
|
|
|
|
int loot = maxloot/i;
|
|
|
|
|
|
2004-09-11 19:29:13 +02:00
|
|
|
|
if (loot>0) {
|
|
|
|
|
int maxrow = BEHIND_ROW;
|
|
|
|
|
int lootchance = 50 + b->keeploot;
|
|
|
|
|
|
|
|
|
|
if (itm->type->flags & (ITF_CURSED|ITF_NOTLOST)) maxrow = LAST_ROW;
|
|
|
|
|
itm->number -= loot;
|
2007-04-19 16:54:17 +02:00
|
|
|
|
maxloot -= loot;
|
2004-09-11 19:29:13 +02:00
|
|
|
|
|
2006-02-19 23:43:56 +01:00
|
|
|
|
if (maxrow == LAST_ROW || rng_int() % 100 < lootchance) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
fighter *fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter;
|
2004-09-11 19:29:13 +02:00
|
|
|
|
if (fig) {
|
|
|
|
|
item * l = fig->loot;
|
|
|
|
|
while (l && l->type!=itm->type) l=l->next;
|
|
|
|
|
if (!l) {
|
|
|
|
|
l = calloc(sizeof(item), 1);
|
|
|
|
|
l->next = fig->loot;
|
|
|
|
|
fig->loot = l;
|
|
|
|
|
l->type = itm->type;
|
|
|
|
|
}
|
|
|
|
|
l->number += loot;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
itm = itm->next;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#ifndef SIMPLE_ESCAPE
|
2001-03-04 19:41:27 +01:00
|
|
|
|
static void
|
2001-04-01 08:58:45 +02:00
|
|
|
|
loot_fleeing(fighter* fig, unit* runner)
|
2001-03-04 19:41:27 +01:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* TODO: Vern<72>nftig fixen */
|
|
|
|
|
runner->items = NULL;
|
|
|
|
|
assert(runner->items == NULL);
|
|
|
|
|
runner->items = fig->run.items;
|
|
|
|
|
fig->run.items = NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 08:58:45 +02:00
|
|
|
|
static void
|
|
|
|
|
merge_fleeloot(fighter* fig, unit* u)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
i_merge(&u->items, &fig->run.items);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2001-04-01 08:58:45 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static boolean
|
|
|
|
|
seematrix(const faction * f, const side * s)
|
|
|
|
|
{
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (f==s->faction) return true;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (s->flags & SIDE_STEALTH) return false;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-11-26 12:00:20 +01:00
|
|
|
|
static double
|
|
|
|
|
PopulationDamage(void)
|
|
|
|
|
{
|
|
|
|
|
static double value = -1.0;
|
|
|
|
|
if (value<0) {
|
|
|
|
|
const char * str = get_param(global.parameters, "battle.populationdamage");
|
2005-11-28 09:07:01 +01:00
|
|
|
|
value = str?atof(str):(BATTLE_KILLS_PEASANTS/100.0);
|
2005-11-26 12:00:20 +01:00
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
battle_effects(battle * b, int dead_players)
|
|
|
|
|
{
|
|
|
|
|
region * r = b->region;
|
|
|
|
|
int dead_peasants = min(rpeasants(r), (int)(dead_players*PopulationDamage()));
|
|
|
|
|
deathcounts(r, dead_peasants + dead_players);
|
|
|
|
|
chaoscounts(r, dead_peasants / 2);
|
|
|
|
|
rsetpeasants(r, rpeasants(r) - dead_peasants);
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static void
|
|
|
|
|
aftermath(battle * b)
|
|
|
|
|
{
|
2004-04-19 00:30:14 +02:00
|
|
|
|
int i;
|
|
|
|
|
region *r = b->region;
|
|
|
|
|
ship *sh;
|
|
|
|
|
side *s;
|
2005-11-26 12:00:20 +01:00
|
|
|
|
int dead_players = 0;
|
2004-04-19 00:30:14 +02:00
|
|
|
|
bfaction * bf;
|
|
|
|
|
boolean battle_was_relevant = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
#ifdef TROLLSAVE
|
2004-04-19 00:30:14 +02:00
|
|
|
|
int *trollsave = calloc(2 * cv_size(&b->factions), sizeof(int));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter * df;
|
|
|
|
|
for (df = s->fighters; df; df=df->next) {
|
|
|
|
|
unit *du = df->unit;
|
2007-03-05 19:37:58 +01:00
|
|
|
|
int dead = dead_fighters(df);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
int pr_mercy = 0;
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#ifdef KARMA_MODULE
|
2006-04-13 19:16:15 +02:00
|
|
|
|
const attrib *a= a_find(du->attribs, &at_prayer_effect);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
while (a && a->type==&at_prayer_effect) {
|
|
|
|
|
if (a->data.sa[0] == PR_MERCY) {
|
|
|
|
|
pr_mercy = a->data.sa[1];
|
|
|
|
|
}
|
|
|
|
|
a = a->next;
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
#ifdef TROLLSAVE
|
2006-04-13 19:16:15 +02:00
|
|
|
|
/* Trolle k<>nnen regenerieren */
|
|
|
|
|
if (df->alive > 0 && dead>0 && du->race == new_race[RC_TROLL]) {
|
|
|
|
|
for (i = 0; i != dead; ++i) {
|
|
|
|
|
if (chance(TROLL_REGENERATION)) {
|
|
|
|
|
++df->alive;
|
|
|
|
|
++s->alive;
|
|
|
|
|
++s->battle->alive;
|
|
|
|
|
++trollsave[s->index];
|
|
|
|
|
/* do not change dead here, or loop will not terminate! recalculate later */
|
|
|
|
|
}
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
2007-03-05 19:37:58 +01:00
|
|
|
|
dead = dead_fighters(df);
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2006-04-13 19:16:15 +02:00
|
|
|
|
/* Regeneration durch PR_MERCY */
|
|
|
|
|
if (dead>0 && pr_mercy) {
|
|
|
|
|
for (i = 0; i != dead; ++i) {
|
|
|
|
|
if (rng_int()%100 < pr_mercy) {
|
|
|
|
|
++df->alive;
|
|
|
|
|
++s->alive;
|
|
|
|
|
++s->battle->alive;
|
|
|
|
|
/* do not change dead here, or loop will not terminate! recalculate later */
|
|
|
|
|
}
|
2004-05-20 00:59:08 +02:00
|
|
|
|
}
|
2007-03-05 19:37:58 +01:00
|
|
|
|
dead = dead_fighters(df);
|
2004-05-20 00:59:08 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
/* tote insgesamt: */
|
|
|
|
|
s->dead += dead;
|
|
|
|
|
/* Tote, die wiederbelebt werde k<>nnen: */
|
|
|
|
|
if (playerrace(df->unit->race)) {
|
|
|
|
|
s->casualties += dead;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef SHOW_KILLS
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (df->hits + df->kills) {
|
|
|
|
|
struct message * m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills);
|
|
|
|
|
message_faction(b, du->faction, m);
|
|
|
|
|
msg_release(m);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
/* POSTCOMBAT */
|
|
|
|
|
do_combatmagic(b, DO_POSTCOMBATSPELL);
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2004-04-19 00:30:14 +02:00
|
|
|
|
int snumber = 0;
|
|
|
|
|
fighter *df;
|
2006-01-15 18:50:01 +01:00
|
|
|
|
boolean relevant = false; /* Kampf relevant f<>r diese Partei? */
|
2007-01-31 11:17:53 +01:00
|
|
|
|
#ifdef SIMPLE_COMBAT
|
|
|
|
|
if (fval(s, SIDE_HASGUARDS) == 0) relevant = true;
|
|
|
|
|
#else
|
2006-07-30 16:21:44 +02:00
|
|
|
|
if (s->bf->lastturn>1) {
|
2004-04-19 00:30:14 +02:00
|
|
|
|
relevant = true;
|
2006-07-30 16:21:44 +02:00
|
|
|
|
} else if (s->bf->lastturn==1 && b->has_tactics_turn) {
|
|
|
|
|
side * stac;
|
|
|
|
|
for (stac=b->sides; stac; stac=stac->next) {
|
|
|
|
|
if (stac->leader.value == b->max_tactics && helping(stac, s)) {
|
|
|
|
|
relevant = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
#endif
|
2004-04-19 00:30:14 +02:00
|
|
|
|
s->flee = 0;
|
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
for (df=s->fighters;df;df=df->next) {
|
2004-04-19 00:30:14 +02:00
|
|
|
|
unit *du = df->unit;
|
2007-03-05 19:37:58 +01:00
|
|
|
|
int dead = dead_fighters(df);
|
2004-04-19 00:30:14 +02:00
|
|
|
|
int sum_hp = 0;
|
|
|
|
|
int n;
|
|
|
|
|
|
2007-01-31 11:17:53 +01:00
|
|
|
|
for (n = 0; n != df->alive; ++n) {
|
|
|
|
|
if (df->person[n].hp > 0) {
|
|
|
|
|
sum_hp += df->person[n].hp;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-01-15 18:50:01 +01:00
|
|
|
|
snumber += du->number;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
#ifdef SIMPLE_COMBAT
|
2007-01-31 11:17:53 +01:00
|
|
|
|
if (relevant) {
|
2007-02-10 12:58:54 +01:00
|
|
|
|
int flags = UFL_LONGACTION|UFL_NOTMOVING;
|
|
|
|
|
#ifdef SIMPLE_ESCAPE
|
|
|
|
|
if (du->status==ST_FLEE) flags -= UFL_NOTMOVING;
|
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
|
|
|
|
fset(du, flags);
|
2007-01-31 11:17:53 +01:00
|
|
|
|
}
|
|
|
|
|
if (sum_hp<du->hp) {
|
|
|
|
|
/* someone on the ship got damaged, damage the ship */
|
2006-04-10 23:13:22 +02:00
|
|
|
|
ship * sh = du->ship?du->ship:leftship(du);
|
|
|
|
|
if (sh) fset(sh, SF_DAMAGED);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2006-01-15 18:50:01 +01:00
|
|
|
|
if (relevant) {
|
2006-03-26 23:49:37 +02:00
|
|
|
|
fset(du, UFL_NOTMOVING); /* unit cannot move this round */
|
2006-01-15 18:50:01 +01:00
|
|
|
|
if (df->action_counter >= du->number) {
|
|
|
|
|
ship * sh = du->ship?du->ship:leftship(du);
|
|
|
|
|
if (sh) fset(sh, SF_DAMAGED);
|
|
|
|
|
fset(du, UFL_LONGACTION);
|
|
|
|
|
}
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-19 21:59:37 +02:00
|
|
|
|
if (df->alive == du->number) {
|
|
|
|
|
du->hp = sum_hp;
|
|
|
|
|
continue; /* nichts passiert */
|
|
|
|
|
} else if (df->run.hp) {
|
2004-04-19 00:30:14 +02:00
|
|
|
|
if (df->alive == 0) {
|
|
|
|
|
/* Report the casualties */
|
|
|
|
|
reportcasualties(b, df, dead);
|
|
|
|
|
|
|
|
|
|
/* Zuerst d<>rfen die Feinde pl<70>ndern, die mitgenommenen Items
|
|
|
|
|
* stehen in fig->run.items. Dann werden die Fliehenden auf
|
|
|
|
|
* die leere (tote) alte Einheit gemapt */
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#ifdef SIMPLE_ESCAPE
|
2007-03-04 23:27:32 +01:00
|
|
|
|
if (!fval(df, FIG_NOLOOT)) {
|
2007-02-10 12:25:23 +01:00
|
|
|
|
loot_items(df);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2006-01-15 18:50:01 +01:00
|
|
|
|
if (fval(df, FIG_NOLOOT)){
|
2004-04-19 00:30:14 +02:00
|
|
|
|
merge_fleeloot(df, du);
|
|
|
|
|
} else {
|
|
|
|
|
loot_items(df);
|
|
|
|
|
loot_fleeing(df, du);
|
|
|
|
|
}
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2004-04-19 00:30:14 +02:00
|
|
|
|
scale_number(du, df->run.number);
|
|
|
|
|
du->hp = df->run.hp;
|
|
|
|
|
setguard(du, GUARD_NONE);
|
2007-02-14 18:54:04 +01:00
|
|
|
|
#ifdef SIMPLE_ESCAPE
|
|
|
|
|
if (du->status<=ST_FLEE) leave(du->region, du);
|
|
|
|
|
#else
|
2004-04-19 00:30:14 +02:00
|
|
|
|
leave(du->region, du);
|
|
|
|
|
if (df->run.region) {
|
2004-12-19 17:39:51 +01:00
|
|
|
|
run_to(du, df->run.region);
|
2004-04-19 00:30:14 +02:00
|
|
|
|
df->run.region = du->region;
|
|
|
|
|
}
|
2007-03-12 00:03:10 +01:00
|
|
|
|
fset(du, UFL_LONGACTION|UFL_NOTMOVING);
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2006-04-13 19:16:15 +02:00
|
|
|
|
} else {
|
2004-04-19 00:30:14 +02:00
|
|
|
|
/* nur teilweise geflohene Einheiten mergen sich wieder */
|
|
|
|
|
df->alive += df->run.number;
|
|
|
|
|
s->size[0] += df->run.number;
|
|
|
|
|
s->size[statusrow(df->status)] += df->run.number;
|
|
|
|
|
s->alive += df->run.number;
|
|
|
|
|
sum_hp += df->run.hp;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#ifndef SIMPLE_ESCAPE
|
2004-04-19 00:30:14 +02:00
|
|
|
|
merge_fleeloot(df, du);
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2004-04-19 00:30:14 +02:00
|
|
|
|
df->run.number = 0;
|
|
|
|
|
df->run.hp = 0;
|
|
|
|
|
/* df->run.region = NULL;*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
reportcasualties(b, df, dead);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
scale_number(du, df->alive);
|
|
|
|
|
du->hp = sum_hp;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (df->alive==0) {
|
|
|
|
|
/* alle sind tot, niemand geflohen. Einheit aufl<66>sen */
|
|
|
|
|
df->run.number = 0;
|
|
|
|
|
df->run.hp = 0;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#ifndef SIMPLE_ESCAPE
|
2004-04-19 00:30:14 +02:00
|
|
|
|
df->run.region = NULL;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
/* Report the casualties */
|
|
|
|
|
reportcasualties(b, df, dead);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
/* Distribute Loot */
|
|
|
|
|
loot_items(df);
|
2007-03-16 21:59:15 +01:00
|
|
|
|
|
|
|
|
|
setguard(du, GUARD_NONE);
|
|
|
|
|
scale_number(du, 0);
|
2004-04-19 00:30:14 +02:00
|
|
|
|
} else {
|
|
|
|
|
df->run.number = 0;
|
|
|
|
|
df->run.hp = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
reportcasualties(b, df, dead);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
scale_number(du, df->alive);
|
|
|
|
|
du->hp = sum_hp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s->flee += df->run.number;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
if (playerrace(du->race)) {
|
|
|
|
|
/* tote im kampf werden zu regionsuntoten:
|
|
|
|
|
* for each of them, a peasant will die as well */
|
2005-11-26 12:00:20 +01:00
|
|
|
|
dead_players += dead;
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
|
|
|
|
if (du->hp < du->number) {
|
|
|
|
|
log_error(("%s has less hitpoints (%u) than people (%u)\n",
|
2004-12-31 02:13:04 +01:00
|
|
|
|
itoa36(du->no), du->hp, du->number));
|
|
|
|
|
du->hp = du->number;
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2004-04-19 00:30:14 +02:00
|
|
|
|
s->alive+=s->healed;
|
|
|
|
|
assert(snumber==s->flee+s->alive+s->dead);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2005-11-26 12:00:20 +01:00
|
|
|
|
|
|
|
|
|
battle_effects(b, dead_players);
|
2004-04-19 00:30:14 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
message * seen = msg_message("battle::army_report",
|
2006-10-07 18:10:42 +02:00
|
|
|
|
"index abbrev dead fled survived",
|
2006-04-13 21:54:24 +02:00
|
|
|
|
army_index(s), sideabkz(s, false), s->dead, s->flee, s->alive);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
message * unseen = msg_message("battle::army_report",
|
2006-10-07 18:10:42 +02:00
|
|
|
|
"index abbrev dead fled survived",
|
2006-04-13 21:54:24 +02:00
|
|
|
|
army_index(s), "-?-", s->dead, s->flee, s->alive);
|
2004-04-22 00:09:39 +02:00
|
|
|
|
|
|
|
|
|
for (bf=b->factions;bf;bf=bf->next) {
|
|
|
|
|
faction * f = bf->faction;
|
|
|
|
|
message * m = seematrix(f, s)?seen:unseen;
|
|
|
|
|
|
|
|
|
|
message_faction(b, f, m);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msg_release(seen);
|
|
|
|
|
msg_release(unseen);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2004-04-19 00:30:14 +02:00
|
|
|
|
|
2007-02-18 17:44:24 +01:00
|
|
|
|
/* Wir benutzen drifted, um uns zu merken, ob ein Schiff
|
|
|
|
|
* schonmal Schaden genommen hat. (moved und drifted
|
|
|
|
|
* sollten in flags <EFBFBD>berf<EFBFBD>hrt werden */
|
2006-04-13 19:16:15 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2007-02-18 17:44:24 +01:00
|
|
|
|
fighter *df;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
|
2007-02-18 17:44:24 +01:00
|
|
|
|
for (df=s->fighters; df; df=df->next) {
|
|
|
|
|
unit *du = df->unit;
|
|
|
|
|
item * l;
|
|
|
|
|
|
|
|
|
|
/* Beute verteilen */
|
|
|
|
|
for (l=df->loot; l; l=l->next) {
|
|
|
|
|
const item_type * itype = l->type;
|
2007-06-26 23:17:10 +02:00
|
|
|
|
message * m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype);
|
|
|
|
|
message_faction(b, du->faction, m);
|
|
|
|
|
msg_release(m);
|
2007-02-18 17:44:24 +01:00
|
|
|
|
i_change(&du->items, itype, l->number);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-02-18 17:44:24 +01:00
|
|
|
|
/* Wenn sich die Einheit auf einem Schiff befindet, wird
|
|
|
|
|
* dieses Schiff besch<EFBFBD>digt. Andernfalls ein Schiff, welches
|
|
|
|
|
* evt. zuvor verlassen wurde. */
|
|
|
|
|
if (battle_was_relevant) {
|
|
|
|
|
if (du->ship) sh = du->ship;
|
|
|
|
|
else sh = leftship(du);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-01-31 11:17:53 +01:00
|
|
|
|
if (sh && fval(sh, SF_DAMAGED)) {
|
2007-02-05 22:30:45 +01:00
|
|
|
|
int n = b->turn - 2;
|
2007-01-31 11:17:53 +01:00
|
|
|
|
if (n>0) {
|
|
|
|
|
damage_ship(sh, 0.05 * n);
|
2007-02-05 22:30:45 +01:00
|
|
|
|
freset(sh, SF_DAMAGED);
|
2007-01-31 11:17:53 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
2007-02-18 17:44:24 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (battle_was_relevant) {
|
|
|
|
|
ship **sp = &r->ships;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-19 00:30:14 +02:00
|
|
|
|
while (*sp) {
|
|
|
|
|
ship * sh = *sp;
|
|
|
|
|
freset(sh, SF_DAMAGED);
|
|
|
|
|
if (sh->damage >= sh->size * DAMAGE_SCALE) {
|
2004-05-31 18:21:03 +02:00
|
|
|
|
destroy_ship(sh);
|
2004-04-19 00:30:14 +02:00
|
|
|
|
}
|
|
|
|
|
if (*sp==sh) sp=&sh->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef TROLLSAVE
|
2004-04-19 00:30:14 +02:00
|
|
|
|
free(trollsave);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
fprintf(bdebug, "The battle lasted %d turns, %s and %s.\n",
|
2007-05-27 23:20:06 +02:00
|
|
|
|
b->turn,
|
2007-06-26 23:17:10 +02:00
|
|
|
|
b->has_tactics_turn?"had a tactic turn":"had no tactic turn",
|
|
|
|
|
battle_was_relevant?"was relevant":"was not relevant.");
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
battle_punit(unit * u, battle * b)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
bfaction * bf;
|
|
|
|
|
strlist *S, *x;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
for (bf = b->factions;bf;bf=bf->next) {
|
|
|
|
|
faction *f = bf->faction;
|
|
|
|
|
|
|
|
|
|
S = 0;
|
|
|
|
|
spunit(&S, f, u, 4, see_battle);
|
|
|
|
|
for (x = S; x; x = x->next) {
|
|
|
|
|
fbattlerecord(b, f, x->s);
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug && u->faction == f) {
|
|
|
|
|
fputs(x->s, bdebug);
|
2007-09-16 17:34:04 +02:00
|
|
|
|
fputc('\n', bdebug);
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (S)
|
|
|
|
|
freestrlist(S);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2006-04-16 00:10:57 +02:00
|
|
|
|
print_fighters(battle * b, const side * s)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-20 00:52:36 +02:00
|
|
|
|
fighter *df;
|
2006-04-16 00:10:57 +02:00
|
|
|
|
int row;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-16 00:10:57 +02:00
|
|
|
|
for (row=1;row!=NUMROWS;++row) {
|
2006-04-16 00:34:03 +02:00
|
|
|
|
message * m = NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-16 00:10:57 +02:00
|
|
|
|
for (df=s->fighters; df; df=df->next) {
|
|
|
|
|
unit *du = df->unit;
|
|
|
|
|
int thisrow = statusrow(df->unit->status);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-16 00:10:57 +02:00
|
|
|
|
if (row == thisrow) {
|
2006-04-16 00:34:03 +02:00
|
|
|
|
if (m==NULL) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
m = msg_message("battle::row_header", "row", row);
|
2006-04-16 00:34:03 +02:00
|
|
|
|
message_all(b, m);
|
|
|
|
|
}
|
|
|
|
|
battle_punit(du, b);
|
2006-04-16 00:10:57 +02:00
|
|
|
|
}
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2006-04-16 00:34:03 +02:00
|
|
|
|
if (m!=NULL) msg_release(m);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
is_attacker(const fighter * fig)
|
|
|
|
|
{
|
|
|
|
|
return fval(fig, FIG_ATTACKER)!=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_attacker(fighter * fig)
|
|
|
|
|
{
|
|
|
|
|
fset(fig, FIG_ATTACKER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_header(battle * b)
|
|
|
|
|
{
|
2004-05-04 21:24:03 +02:00
|
|
|
|
bfaction * bf;
|
2007-09-02 09:57:31 +02:00
|
|
|
|
char zText[32*MAXSIDES];
|
2004-05-04 21:24:03 +02:00
|
|
|
|
|
|
|
|
|
for (bf=b->factions;bf;bf=bf->next) {
|
2007-02-22 23:53:53 +01:00
|
|
|
|
message * m;
|
2004-05-04 21:24:03 +02:00
|
|
|
|
faction * f = bf->faction;
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char * lastf = NULL;
|
2004-05-04 21:24:03 +02:00
|
|
|
|
boolean first = false;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
side * s;
|
2007-08-21 09:04:44 +02:00
|
|
|
|
char * bufp = zText;
|
2007-09-02 01:40:58 +02:00
|
|
|
|
size_t size = sizeof(zText) - 1;
|
|
|
|
|
int bytes;
|
2004-05-04 21:24:03 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *df;
|
|
|
|
|
for (df=s->fighters;df;df=df->next) {
|
|
|
|
|
if (is_attacker(df)) {
|
2007-09-02 09:57:31 +02:00
|
|
|
|
if (first) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (lastf) {
|
2007-09-02 01:40:58 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, (const char *)lastf, size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
2006-04-13 19:16:15 +02:00
|
|
|
|
first = true;
|
|
|
|
|
}
|
|
|
|
|
if (seematrix(f, s) == true)
|
2007-06-26 23:17:10 +02:00
|
|
|
|
lastf = sidename(s);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
else
|
2007-02-22 23:53:53 +01:00
|
|
|
|
lastf = LOC(f->locale, "unknown_faction_dative");
|
2006-04-13 19:16:15 +02:00
|
|
|
|
break;
|
2004-05-04 21:24:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-02-22 23:53:53 +01:00
|
|
|
|
if (first) {
|
2007-09-02 01:40:58 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, " ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, (const char *)LOC(f->locale, "and"), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, " ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
if (lastf) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, (const char *)lastf, size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
2007-02-22 23:53:53 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-06-26 23:17:10 +02:00
|
|
|
|
m = msg_message("battle::starters", "factions", zText);
|
2007-02-22 23:53:53 +01:00
|
|
|
|
message_faction(b, f, m);
|
|
|
|
|
msg_release(m);
|
2004-05-04 21:24:03 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_stats(battle * b)
|
|
|
|
|
{
|
2004-04-20 00:52:36 +02:00
|
|
|
|
side *s2;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
side *s;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
int i = 0;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2004-04-20 00:52:36 +02:00
|
|
|
|
bfaction *bf;
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
|
|
|
|
|
for (bf=b->factions;bf;bf=bf->next) {
|
|
|
|
|
faction * f = bf->faction;
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char * loc_army = LOC(f->locale, "battle_army");
|
2005-06-19 12:22:51 +02:00
|
|
|
|
char * bufp;
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char * header;
|
2005-06-19 12:22:51 +02:00
|
|
|
|
size_t rsize, size;
|
2005-06-26 15:16:49 +02:00
|
|
|
|
int komma;
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char * sname = seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction");
|
2007-06-26 23:17:10 +02:00
|
|
|
|
message * msg;
|
|
|
|
|
char buf[1024];
|
2005-06-17 20:35:28 +02:00
|
|
|
|
|
2007-07-20 09:28:11 +02:00
|
|
|
|
message_faction(b, f, msg_separator);
|
2005-06-17 20:35:28 +02:00
|
|
|
|
|
2007-08-12 11:51:26 +02:00
|
|
|
|
msg = msg_message("battle_army", "index name", army_index(s), sname);
|
2007-06-26 23:17:10 +02:00
|
|
|
|
message_faction(b, f, msg);
|
|
|
|
|
msg_release(msg);
|
2005-06-17 20:35:28 +02:00
|
|
|
|
|
2005-06-19 12:22:51 +02:00
|
|
|
|
bufp = buf;
|
|
|
|
|
size = sizeof(buf);
|
2005-06-26 15:16:49 +02:00
|
|
|
|
komma = 0;
|
|
|
|
|
header = LOC(f->locale, "battle_opponents");
|
2005-06-17 20:35:28 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s2=b->sides;s2!=b->sides+b->nsides;++s2) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (enemy(s2, s)) {
|
2004-04-22 00:09:39 +02:00
|
|
|
|
const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-";
|
2006-04-10 23:13:22 +02:00
|
|
|
|
rsize = slprintf(bufp, size, "%s %s %d(%s)",
|
2007-06-26 23:17:10 +02:00
|
|
|
|
komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev);
|
2005-06-17 20:35:28 +02:00
|
|
|
|
if (rsize>size) rsize = size-1;
|
|
|
|
|
size -= rsize;
|
|
|
|
|
bufp += rsize;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2005-06-26 15:16:49 +02:00
|
|
|
|
if (komma) fbattlerecord(b, f, buf);
|
2005-06-17 20:35:28 +02:00
|
|
|
|
|
2006-07-30 14:52:26 +02:00
|
|
|
|
bufp = buf;
|
|
|
|
|
size = sizeof(buf);
|
|
|
|
|
komma = 0;
|
|
|
|
|
header = LOC(f->locale, "battle_helpers");
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s2=b->sides;s2!=b->sides+b->nsides;++s2) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (friendly(s2, s)) {
|
|
|
|
|
const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-";
|
|
|
|
|
rsize = slprintf(bufp, size, "%s %s %d(%s)",
|
2007-06-26 23:17:10 +02:00
|
|
|
|
komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev);
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (rsize>size) rsize = size-1;
|
|
|
|
|
size -= rsize;
|
|
|
|
|
bufp += rsize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (komma) fbattlerecord(b, f, buf);
|
|
|
|
|
|
2005-06-17 20:35:28 +02:00
|
|
|
|
bufp = buf;
|
|
|
|
|
size = sizeof(buf);
|
2005-06-26 15:16:49 +02:00
|
|
|
|
komma = 0;
|
|
|
|
|
header = LOC(f->locale, "battle_attack");
|
2005-06-17 20:35:28 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s2=b->sides;s2!=b->sides+b->nsides;++s2) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (s->relations[s2->index] & E_ATTACKING) {
|
2004-04-22 00:09:39 +02:00
|
|
|
|
const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-";
|
2007-06-26 23:17:10 +02:00
|
|
|
|
rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char*)header, loc_army,
|
2006-04-13 21:54:24 +02:00
|
|
|
|
army_index(s2), abbrev);
|
2005-06-17 20:35:28 +02:00
|
|
|
|
if (rsize>size) rsize = size-1;
|
|
|
|
|
size -= rsize;
|
|
|
|
|
bufp += rsize;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2005-06-26 15:16:49 +02:00
|
|
|
|
if (komma) fbattlerecord(b, f, buf);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (bdebug && s->faction) {
|
|
|
|
|
if (s->faction->alliance) {
|
|
|
|
|
fprintf(bdebug, "##### %s (%s/%d)\n", s->faction->name, itoa36(s->faction->no),
|
|
|
|
|
s->faction->alliance?s->faction->alliance->id:0);
|
2004-06-27 18:56:01 +02:00
|
|
|
|
} else {
|
2007-10-27 17:09:36 +02:00
|
|
|
|
fprintf(bdebug, "##### %s (%s)\n", s->faction->name, itoa36(s->faction->no));
|
2004-06-27 18:56:01 +02:00
|
|
|
|
}
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2006-04-16 00:10:57 +02:00
|
|
|
|
print_fighters(b, s);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-07-20 09:28:11 +02:00
|
|
|
|
message_all(b, msg_separator);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
/* Besten Taktiker ermitteln */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
b->max_tactics = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (cv_size(&s->leader.fighters)) {
|
|
|
|
|
b->max_tactics = max(b->max_tactics, s->leader.value);
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-04-20 00:52:36 +02:00
|
|
|
|
|
|
|
|
|
if (b->max_tactics > 0) {
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (s->leader.value == b->max_tactics) {
|
2004-04-20 00:52:36 +02:00
|
|
|
|
fighter *tf;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
cv_foreach(tf, s->leader.fighters) {
|
2004-04-20 00:52:36 +02:00
|
|
|
|
unit *u = tf->unit;
|
|
|
|
|
message * m = NULL;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (!is_attacker(tf)) {
|
2004-04-20 01:27:27 +02:00
|
|
|
|
m = msg_message("battle::tactics_lost", "unit", u);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
} else {
|
2004-04-20 01:27:27 +02:00
|
|
|
|
m = msg_message("battle::tactics_won", "unit", u);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
|
|
|
|
message_all(b, m);
|
|
|
|
|
msg_release(m);
|
|
|
|
|
} cv_next(tf);
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
Zu Anfang des Kampfes wählt jeder Kämpfer aus seinem Arsenal zwei Waffen
aus: Seine beste Fernampfwaffe und seine beste Nahkampfwaffe.
Welches die beste Waffe ist, ist nicht immer einleuchtend, und an dieser
Stelle macht der Server eine Vereinfachung - er wählt die Waffe, bei der der
Angriffswert plus dem Verteidigungswert am größten ist.
** Wenn eine Einheit an der Reihe ist, wird geprüft:
1. Ist die Einheit ein Magier, so zaubert sie.
2. Ist die Einheit damit beschäftigt, eine Waffe nachzuladen, so tut sie das.
3. Steht die Einheit in einer der hinteren Reihen, attackiert sie, so
vorhanden, mit der Fernkampfwaffe.
4. Steht die Einheit in der vorderen Kampfreihe, so attackiert sie mit
derjenigen Waffe von beiden, in der ihr Talent am höchsten ist.
** Wird eine Einheit angegriffen, so gilt:
1. Handelt es sich um einen Angriff durch einen Nahkämpfer, so verteidigt
sie sich mit ihrer Nahkampfwaffe oder Waffenlosem Kampf.
2. Handelt es sich um eine Attacke durch einen Fernkämpfer, so verteidigt
sie sich mit dem halben Talent ihrer besten Waffe.
2002-10-04 23:25:16 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
Zu Anfang des Kampfes wählt jeder Kämpfer aus seinem Arsenal zwei Waffen
aus: Seine beste Fernampfwaffe und seine beste Nahkampfwaffe.
Welches die beste Waffe ist, ist nicht immer einleuchtend, und an dieser
Stelle macht der Server eine Vereinfachung - er wählt die Waffe, bei der der
Angriffswert plus dem Verteidigungswert am größten ist.
** Wenn eine Einheit an der Reihe ist, wird geprüft:
1. Ist die Einheit ein Magier, so zaubert sie.
2. Ist die Einheit damit beschäftigt, eine Waffe nachzuladen, so tut sie das.
3. Steht die Einheit in einer der hinteren Reihen, attackiert sie, so
vorhanden, mit der Fernkampfwaffe.
4. Steht die Einheit in der vorderen Kampfreihe, so attackiert sie mit
derjenigen Waffe von beiden, in der ihr Talent am höchsten ist.
** Wird eine Einheit angegriffen, so gilt:
1. Handelt es sich um einen Angriff durch einen Nahkämpfer, so verteidigt
sie sich mit ihrer Nahkampfwaffe oder Waffenlosem Kampf.
2. Handelt es sich um eine Attacke durch einen Fernkämpfer, so verteidigt
sie sich mit dem halben Talent ihrer besten Waffe.
2002-10-04 23:25:16 +02:00
|
|
|
|
static int
|
|
|
|
|
weapon_weight(const weapon * w, boolean missile)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (missile == i2b(fval(w->type, WTF_MISSILE))) {
|
|
|
|
|
return w->attackskill + w->defenseskill;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fighter *
|
2004-02-09 22:12:46 +01:00
|
|
|
|
make_fighter(battle * b, unit * u, side * s1, boolean attack)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-10-29 12:57:03 +01:00
|
|
|
|
#define WMAX 20
|
2006-04-10 23:13:22 +02:00
|
|
|
|
weapon weapons[WMAX];
|
|
|
|
|
int owp[WMAX];
|
|
|
|
|
int dwp[WMAX];
|
|
|
|
|
int w = 0;
|
|
|
|
|
region *r = b->region;
|
|
|
|
|
item * itm;
|
|
|
|
|
fighter *fig = NULL;
|
|
|
|
|
int i, t = eff_skill(u, SK_TACTICS, r);
|
|
|
|
|
side *s2;
|
|
|
|
|
int h;
|
|
|
|
|
int berserk;
|
|
|
|
|
int strongmen;
|
|
|
|
|
int speeded = 0, speed = 1;
|
|
|
|
|
boolean pr_aid = false;
|
|
|
|
|
int rest;
|
|
|
|
|
const group * g = NULL;
|
|
|
|
|
const attrib *a = a_find(u->attribs, &at_otherfaction);
|
|
|
|
|
const faction *stealthfaction = a?get_otherfaction(a):NULL;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
unsigned int flags = 0;
|
2005-10-26 22:12:28 +02:00
|
|
|
|
|
2006-10-15 16:09:59 +02:00
|
|
|
|
assert(u->number);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (fval(u, UFL_PARTEITARNUNG)!=0) flags |= SIDE_STEALTH;
|
2005-06-12 19:57:14 +02:00
|
|
|
|
|
|
|
|
|
if (fval(u, UFL_GROUP)) {
|
|
|
|
|
const attrib * agroup = a_find(u->attribs, &at_group);
|
|
|
|
|
if (agroup!=NULL) g = (const group*)agroup->data.v;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Illusionen und Zauber kaempfen nicht */
|
2006-10-15 14:05:07 +02:00
|
|
|
|
if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0)
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-09 22:12:46 +01:00
|
|
|
|
if (s1==NULL) {
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s2=b->sides;s2!=b->sides+b->nsides;++s2) {
|
|
|
|
|
if (s2->faction == u->faction && s2->group==g) {
|
2007-01-31 16:28:51 +01:00
|
|
|
|
#ifdef SIMPLE_COMBAT
|
|
|
|
|
int s1flags = flags|SIDE_HASGUARDS;
|
|
|
|
|
int s2flags = s2->flags|SIDE_HASGUARDS;
|
|
|
|
|
#else
|
|
|
|
|
int s1flags = flags;
|
|
|
|
|
int s2flags = s2->flags;
|
|
|
|
|
#endif
|
|
|
|
|
if (s1flags==s2flags && s2->stealthfaction==stealthfaction) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
s1 = s2;
|
|
|
|
|
break;
|
2004-02-09 22:12:46 +01:00
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-09 22:12:46 +01:00
|
|
|
|
|
|
|
|
|
/* aliances are moved out of make_fighter and will be handled later */
|
2007-01-31 11:17:53 +01:00
|
|
|
|
if (!s1) {
|
|
|
|
|
s1 = make_side(b, u->faction, g, flags, stealthfaction);
|
|
|
|
|
}
|
2004-02-09 22:12:46 +01:00
|
|
|
|
/* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit f<>r noch
|
|
|
|
|
* keinen Kampf ausgew<EFBFBD>hlt wurde (sonst w<EFBFBD>rde ein fighter existieren) */
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fig = calloc(1, sizeof(struct fighter));
|
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fig->next = s1->fighters;
|
|
|
|
|
s1->fighters = fig;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
|
|
|
|
fig->unit = u;
|
|
|
|
|
/* In einer Burg mu<6D> man a) nicht Angreifer sein, und b) drin sein, und
|
2006-04-13 19:16:15 +02:00
|
|
|
|
* c) noch Platz finden. d) menschan<EFBFBD>hnlich sein */
|
|
|
|
|
if (attack) {
|
|
|
|
|
set_attacker(fig);
|
|
|
|
|
} else {
|
|
|
|
|
building * b = u->building;
|
|
|
|
|
if (b && b->sizeleft>=u->number && playerrace(u->race)) {
|
|
|
|
|
fig->building = b;
|
|
|
|
|
fig->building->sizeleft -= u->number;
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
fig->status = u->status;
|
|
|
|
|
fig->side = s1;
|
|
|
|
|
fig->alive = u->number;
|
|
|
|
|
fig->side->alive += u->number;
|
|
|
|
|
fig->side->battle->alive += u->number;
|
|
|
|
|
fig->catmsg = -1;
|
|
|
|
|
|
|
|
|
|
/* Freigeben nicht vergessen! */
|
|
|
|
|
fig->person = calloc(fig->alive, sizeof(struct person));
|
|
|
|
|
|
|
|
|
|
h = u->hp / u->number;
|
|
|
|
|
assert(h);
|
|
|
|
|
rest = u->hp % u->number;
|
|
|
|
|
|
|
|
|
|
/* Effekte von Spr<70>chen */
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
static const curse_type * speed_ct;
|
|
|
|
|
speed_ct = ct_find("speed");
|
|
|
|
|
if (speed_ct) {
|
|
|
|
|
curse *c = get_curse(u->attribs, speed_ct);
|
|
|
|
|
if (c) {
|
|
|
|
|
speeded = get_cursedmen(u, c);
|
|
|
|
|
speed = curse_geteffect(c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Effekte von Alchemie */
|
|
|
|
|
berserk = get_effect(u, oldpotiontype[P_BERSERK]);
|
2004-02-22 17:08:39 +01:00
|
|
|
|
/* change_effect wird in ageing gemacht */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Effekte von Artefakten */
|
|
|
|
|
strongmen = min(fig->unit->number, get_item(u, I_TROLLBELT));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#ifdef KARMA_MODULE
|
2006-02-25 01:12:48 +01:00
|
|
|
|
for (a = a_find(u->attribs, &at_prayer_effect); a && a->type==&at_prayer_effect; a = a->next) {
|
|
|
|
|
if (a->data.sa[0] == PR_AID) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
pr_aid = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Hitpoints, Attack- und Defence-Boni f<>r alle Personen */
|
|
|
|
|
for (i = 0; i < fig->alive; i++) {
|
|
|
|
|
assert(i < fig->unit->number);
|
|
|
|
|
fig->person[i].hp = h;
|
|
|
|
|
if (i < rest)
|
|
|
|
|
fig->person[i].hp++;
|
|
|
|
|
|
|
|
|
|
if (i < speeded)
|
|
|
|
|
fig->person[i].speed = speed;
|
|
|
|
|
else
|
|
|
|
|
fig->person[i].speed = 1;
|
|
|
|
|
|
|
|
|
|
if (i < berserk) {
|
|
|
|
|
fig->person[i].attack++;
|
|
|
|
|
}
|
|
|
|
|
/* Leute mit einem Aid-Prayer bekommen +1 auf fast alles. */
|
|
|
|
|
if (pr_aid) {
|
|
|
|
|
fig->person[i].attack++;
|
|
|
|
|
fig->person[i].defence++;
|
|
|
|
|
fig->person[i].damage++;
|
|
|
|
|
fig->person[i].damage_rear++;
|
2004-08-03 17:34:26 +02:00
|
|
|
|
fig->person[i].flags |= FL_COURAGE;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
/* Leute mit Kraftzauber machen +2 Schaden im Nahkampf. */
|
|
|
|
|
if (i < strongmen) {
|
|
|
|
|
fig->person[i].damage += 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* F<>r alle Waffengattungne wird bestimmt, wie viele der Personen mit
|
|
|
|
|
* ihr k<EFBFBD>mpfen k<EFBFBD>nnten, und was ihr Wert darin ist. */
|
|
|
|
|
if (u->race->battle_flags & BF_EQUIPMENT) {
|
|
|
|
|
int oi=0, di=0;
|
2006-10-29 12:57:03 +01:00
|
|
|
|
for (itm=u->items;itm && w!=WMAX;itm=itm->next) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
const weapon_type * wtype = resource2weapon(itm->type->rtype);
|
|
|
|
|
if (wtype==NULL || itm->number==0) continue;
|
|
|
|
|
weapons[w].attackskill = weapon_skill(wtype, u, true);
|
|
|
|
|
weapons[w].defenseskill = weapon_skill(wtype, u, false);
|
|
|
|
|
weapons[w].type = wtype;
|
|
|
|
|
weapons[w].used = 0;
|
|
|
|
|
weapons[w].count = itm->number;
|
|
|
|
|
++w;
|
2006-10-29 12:57:03 +01:00
|
|
|
|
assert(w!=WMAX);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
fig->weapons = calloc(sizeof(weapon), w+1);
|
|
|
|
|
memcpy(fig->weapons, weapons, w*sizeof(weapon));
|
|
|
|
|
|
|
|
|
|
for (i=0; i!=w; ++i) {
|
|
|
|
|
int j, o=0, d=0;
|
|
|
|
|
for (j=0; j!=i; ++j) {
|
|
|
|
|
if (weapon_weight(fig->weapons+j, true)>=weapon_weight(fig->weapons+i, true)) ++d;
|
|
|
|
|
if (weapon_weight(fig->weapons+j, false)>=weapon_weight(fig->weapons+i, false)) ++o;
|
|
|
|
|
}
|
|
|
|
|
for (j=i+1; j!=w; ++j) {
|
|
|
|
|
if (weapon_weight(fig->weapons+j, true)>weapon_weight(fig->weapons+i, true)) ++d;
|
|
|
|
|
if (weapon_weight(fig->weapons+j, false)>weapon_weight(fig->weapons+i, false)) ++o;
|
|
|
|
|
}
|
|
|
|
|
owp[o] = i;
|
|
|
|
|
dwp[d] = i;
|
|
|
|
|
}
|
|
|
|
|
/* jetzt enthalten owp und dwp eine absteigend schlechter werdende Liste der Waffen
|
|
|
|
|
* oi and di are the current index to the sorted owp/dwp arrays
|
|
|
|
|
* owp, dwp contain indices to the figther::weapons array */
|
|
|
|
|
|
|
|
|
|
/* hand out melee weapons: */
|
|
|
|
|
for (i=0; i!=fig->alive; ++i) {
|
|
|
|
|
int wpless = weapon_skill(NULL, u, true);
|
|
|
|
|
while (oi!=w && (fig->weapons[owp[oi]].used==fig->weapons[owp[oi]].count || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) {
|
|
|
|
|
++oi;
|
|
|
|
|
}
|
|
|
|
|
if (oi==w) break; /* no more weapons available */
|
|
|
|
|
if (weapon_weight(fig->weapons+owp[oi], false)<=wpless) {
|
|
|
|
|
continue; /* we fight better with bare hands */
|
|
|
|
|
}
|
|
|
|
|
fig->person[i].melee = &fig->weapons[owp[oi]];
|
|
|
|
|
++fig->weapons[owp[oi]].used;
|
|
|
|
|
}
|
|
|
|
|
/* hand out missile weapons (from back to front, in case of mixed troops). */
|
|
|
|
|
for (di=0, i=fig->alive; i--!=0;) {
|
|
|
|
|
while (di!=w && (fig->weapons[dwp[di]].used==fig->weapons[dwp[di]].count || !fval(fig->weapons[dwp[di]].type, WTF_MISSILE))) {
|
|
|
|
|
++di;
|
|
|
|
|
}
|
|
|
|
|
if (di==w) break; /* no more weapons available */
|
|
|
|
|
if (weapon_weight(fig->weapons+dwp[di], true)>0) {
|
|
|
|
|
fig->person[i].missile = &fig->weapons[dwp[di]];
|
|
|
|
|
++fig->weapons[dwp[di]].used;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s1->size[statusrow(fig->status)] += u->number;
|
|
|
|
|
s1->size[SUM_ROW] += u->number;
|
|
|
|
|
if (u->race->battle_flags & BF_NOBLOCK) {
|
|
|
|
|
s1->nonblockers[statusrow(fig->status)] += u->number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fig->unit->race->flags & RCF_HORSE) {
|
|
|
|
|
fig->horses = fig->unit->number;
|
|
|
|
|
fig->elvenhorses = 0;
|
|
|
|
|
} else {
|
|
|
|
|
fig->horses = get_item(u, I_HORSE);
|
2007-10-13 00:14:01 +02:00
|
|
|
|
fig->elvenhorses = get_item(u, I_ELVENHORSE);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-07-31 03:07:07 +02:00
|
|
|
|
if (u->race->battle_flags & BF_EQUIPMENT) {
|
|
|
|
|
for (itm=u->items; itm; itm=itm->next) {
|
|
|
|
|
if (itm->type->rtype->atype) {
|
|
|
|
|
struct armor * adata = malloc(sizeof(armor)), **aptr;
|
2005-07-31 10:28:21 +02:00
|
|
|
|
adata->atype = itm->type->rtype->atype;
|
|
|
|
|
adata->count = itm->number;
|
2005-07-31 03:07:07 +02:00
|
|
|
|
for (aptr=&fig->armors;*aptr;aptr=&(*aptr)->next) {
|
|
|
|
|
if (adata->atype->prot > (*aptr)->atype->prot) break;
|
|
|
|
|
}
|
|
|
|
|
adata->next = *aptr;
|
|
|
|
|
*aptr = adata;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Jetzt mu<6D> noch geschaut werden, wo die Einheit die jeweils besten
|
|
|
|
|
* Werte hat, das kommt aber erst irgendwo sp<EFBFBD>ter. Ich entscheide
|
|
|
|
|
* w<EFBFBD>rend des Kampfes, welche ich nehme, je nach Gegner. Deswegen auch
|
|
|
|
|
* keine addierten boni. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
/* Zuerst mal die Spezialbehandlung gewisser Sonderf<72>lle. */
|
|
|
|
|
fig->magic = eff_skill(u, SK_MAGIC, r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (fig->horses) {
|
|
|
|
|
if (!fval(r->terrain, CAVALRY_REGION) || r_isforest(r)
|
2005-10-25 14:38:01 +02:00
|
|
|
|
|| eff_skill(u, SK_RIDING, r) < 2 || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE))
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fig->horses = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fig->elvenhorses) {
|
|
|
|
|
if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE))
|
|
|
|
|
fig->elvenhorses = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Schauen, wie gut wir in Taktik sind. */
|
|
|
|
|
if (t > 0 && u->race == new_race[RC_INSECT])
|
|
|
|
|
t -= 1 - (int) log10(fig->side->size[SUM_ROW]);
|
|
|
|
|
if (t > 0 && statusrow(fig->status) == FIGHT_ROW)
|
|
|
|
|
t += 1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef TACTICS_MALUS
|
2006-03-26 11:36:55 +02:00
|
|
|
|
if (t > 0 && statusrow(fig->status) > BEHIND_ROW) {
|
|
|
|
|
t -= TACTICS_MALUS;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#ifdef TACTICS_RANDOM
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (t > 0) {
|
|
|
|
|
int bonus = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < fig->alive; i++) {
|
|
|
|
|
int p_bonus = 0;
|
|
|
|
|
int rnd;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
rnd = rng_int()%100;
|
|
|
|
|
if (rnd >= 40 && rnd <= 69)
|
|
|
|
|
p_bonus += 1;
|
|
|
|
|
else if (rnd <= 89)
|
|
|
|
|
p_bonus += 2;
|
|
|
|
|
else
|
|
|
|
|
p_bonus += 3;
|
|
|
|
|
} while(rnd >= 97);
|
|
|
|
|
bonus = max(p_bonus, bonus);
|
|
|
|
|
}
|
|
|
|
|
t += bonus;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2006-04-10 23:13:22 +02:00
|
|
|
|
add_tactics(&fig->side->leader, fig, t);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
++b->nfighters;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return fig;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-09-16 17:34:04 +02:00
|
|
|
|
static int
|
|
|
|
|
join_battle(battle * b, unit * u, boolean attack, fighter ** cp)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-04-13 19:16:15 +02:00
|
|
|
|
side * s;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter *c = NULL;
|
|
|
|
|
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (!attack) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_fleechance);
|
|
|
|
|
if (a!=NULL) {
|
|
|
|
|
if (rng_double()<=a->data.flt) {
|
2007-09-16 17:34:04 +02:00
|
|
|
|
*cp = NULL;
|
|
|
|
|
return false;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *fig;
|
|
|
|
|
for (fig=s->fighters;fig;fig=fig->next) {
|
|
|
|
|
if (fig->unit == u) {
|
|
|
|
|
c = fig;
|
|
|
|
|
if (attack) {
|
|
|
|
|
set_attacker(fig);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if (!c) {
|
|
|
|
|
*cp = make_fighter(b, u, NULL, attack);
|
|
|
|
|
return *cp!=NULL;
|
|
|
|
|
}
|
|
|
|
|
*cp = c;
|
|
|
|
|
return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static const char *
|
|
|
|
|
simplename(region * r)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
int i;
|
|
|
|
|
static char name[17];
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char * cp = rname(r, NULL);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
for (i=0;*cp && i!=16;++i, ++cp) {
|
2007-10-11 23:48:31 +02:00
|
|
|
|
int c = *(unsigned char *)cp;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
while (c && !isalpha(c) && !isspace(c)) {
|
|
|
|
|
++cp;
|
|
|
|
|
c = *(unsigned char*)cp;
|
|
|
|
|
}
|
|
|
|
|
if (isspace(c)) name[i] = '_';
|
|
|
|
|
else name[i] = *cp;
|
|
|
|
|
if (c==0) break;
|
|
|
|
|
}
|
|
|
|
|
name[i]=0;
|
|
|
|
|
return name;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static battle *
|
|
|
|
|
make_battle(region * r)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
battle *b = calloc(1, sizeof(struct battle));
|
|
|
|
|
unit *u;
|
|
|
|
|
bfaction * bf;
|
|
|
|
|
static int max_fac_no = 0; /* need this only once */
|
|
|
|
|
|
2007-05-27 23:20:06 +02:00
|
|
|
|
if (battledebug) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
char zText[MAX_PATH];
|
|
|
|
|
char zFilename[MAX_PATH];
|
|
|
|
|
sprintf(zText, "%s/battles", basepath());
|
|
|
|
|
makedir(zText, 0700);
|
|
|
|
|
sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r));
|
|
|
|
|
bdebug = fopen(zFilename, "w");
|
2007-08-26 22:56:10 +02:00
|
|
|
|
if (!bdebug) log_error(("battles cannot be debugged\n"));
|
2006-04-10 23:13:22 +02:00
|
|
|
|
else {
|
2007-08-21 09:04:44 +02:00
|
|
|
|
const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf };
|
|
|
|
|
fwrite(utf8_bom, 1, 3, bdebug);
|
2007-06-26 23:17:10 +02:00
|
|
|
|
fprintf(bdebug, "In %s findet ein Kampf statt:\n", rname(r, NULL));
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
obs_count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b->region = r;
|
|
|
|
|
b->plane = getplane(r);
|
|
|
|
|
/* Finde alle Parteien, die den Kampf beobachten k<>nnen: */
|
2007-06-20 02:34:02 +02:00
|
|
|
|
for (u = r->units; u; u=u->next) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (u->number > 0) {
|
2007-06-20 02:34:02 +02:00
|
|
|
|
if (!fval(u->faction, FFL_MARK)) {
|
|
|
|
|
fset(u->faction, FFL_MARK);
|
|
|
|
|
for (bf=b->factions;bf;bf=bf->next) {
|
|
|
|
|
if (bf->faction==u->faction) break;
|
|
|
|
|
}
|
|
|
|
|
if (!bf) {
|
|
|
|
|
bf = calloc(sizeof(bfaction), 1);
|
|
|
|
|
++b->nfactions;
|
|
|
|
|
bf->faction = u->faction;
|
|
|
|
|
bf->next = b->factions;
|
|
|
|
|
b->factions = bf;
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (bf=b->factions;bf;bf=bf->next) {
|
|
|
|
|
faction * f = bf->faction;
|
|
|
|
|
max_fac_no = max(max_fac_no, f->no);
|
2007-06-20 02:34:02 +02:00
|
|
|
|
freset(f, FFL_MARK);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
|
|
|
|
return b;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
free_side(side * si)
|
|
|
|
|
{
|
2006-01-29 02:55:36 +01:00
|
|
|
|
cv_kill(&si->leader.fighters);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
free_fighter(fighter * fig)
|
|
|
|
|
{
|
2005-04-30 13:54:16 +02:00
|
|
|
|
while (fig->loot) {
|
2005-04-30 15:43:32 +02:00
|
|
|
|
i_free(i_remove(&fig->loot, fig->loot));
|
2005-04-30 13:54:16 +02:00
|
|
|
|
}
|
2005-07-31 10:28:21 +02:00
|
|
|
|
while (fig->armors) {
|
|
|
|
|
armor * a = fig->armors;
|
|
|
|
|
fig->armors = a->next;
|
|
|
|
|
free(a);
|
|
|
|
|
}
|
2005-04-30 13:50:19 +02:00
|
|
|
|
free(fig->person);
|
2005-04-30 13:54:16 +02:00
|
|
|
|
free(fig->weapons);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
free_battle(battle * b)
|
|
|
|
|
{
|
2007-10-27 17:09:36 +02:00
|
|
|
|
side *s;
|
2006-01-29 02:55:36 +01:00
|
|
|
|
meffect *meffect;
|
|
|
|
|
int max_fac_no = 0;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
2006-01-29 02:55:36 +01:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
fclose(bdebug);
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
2006-01-29 02:55:36 +01:00
|
|
|
|
while (b->factions) {
|
2005-05-08 02:16:32 +02:00
|
|
|
|
bfaction * bf = b->factions;
|
2006-01-29 02:55:36 +01:00
|
|
|
|
faction * f = bf->faction;
|
2005-05-08 02:16:32 +02:00
|
|
|
|
b->factions = bf->next;
|
2006-01-29 02:55:36 +01:00
|
|
|
|
max_fac_no = max(max_fac_no, f->no);
|
2005-05-08 02:16:32 +02:00
|
|
|
|
free(bf);
|
2006-01-29 02:55:36 +01:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *fnext = s->fighters;
|
|
|
|
|
while (fnext) {
|
|
|
|
|
fighter *fig = fnext;
|
|
|
|
|
fnext = fig->next;
|
|
|
|
|
free_fighter(fig);
|
|
|
|
|
free(fig);
|
|
|
|
|
}
|
|
|
|
|
free_side(s);
|
2006-01-29 02:55:36 +01:00
|
|
|
|
}
|
|
|
|
|
cv_kill(&b->leaders);
|
|
|
|
|
cv_foreach(meffect, b->meffects) {
|
|
|
|
|
free(meffect);
|
|
|
|
|
}
|
|
|
|
|
cv_next(meffect);
|
|
|
|
|
cv_kill(&b->meffects);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int *
|
2006-07-30 14:52:26 +02:00
|
|
|
|
get_alive(side * s)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2006-07-30 14:52:26 +02:00
|
|
|
|
#if 0
|
2006-04-10 23:13:22 +02:00
|
|
|
|
static int alive[NUMROWS];
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *fig;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
memset(alive, 0, NUMROWS * sizeof(int));
|
2006-04-13 19:16:15 +02:00
|
|
|
|
for (fig=s->fighters;fig;fig=fig->next) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
if (fig->alive>0) {
|
|
|
|
|
int row = statusrow(fig);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
alive[row] += fig->alive;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
return alive;
|
2006-07-30 14:52:26 +02:00
|
|
|
|
#endif
|
|
|
|
|
return s->size;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
battle_report(battle * b)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
side *s, *s2;
|
|
|
|
|
boolean cont = false;
|
|
|
|
|
boolean komma;
|
|
|
|
|
bfaction *bf;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
|
|
|
|
for (s2=b->sides;s2!=b->sides+b->nsides;++s2) {
|
2006-04-10 23:13:22 +02:00
|
|
|
|
if (s->alive-s->removed > 0 && s2->alive-s2->removed > 0 && enemy(s, s2)) {
|
|
|
|
|
cont = true;
|
2006-04-07 23:49:38 +02:00
|
|
|
|
break;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2006-04-07 23:49:38 +02:00
|
|
|
|
if (cont) break;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
printf(" %d", b->turn);
|
2005-06-15 22:51:25 +02:00
|
|
|
|
fflush(stdout);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-06-15 22:51:25 +02:00
|
|
|
|
for (bf=b->factions;bf;bf=bf->next) {
|
|
|
|
|
faction * fac = bf->faction;
|
2007-08-21 09:04:44 +02:00
|
|
|
|
char buf[32*MAXSIDES];
|
2005-06-15 23:24:22 +02:00
|
|
|
|
char * bufp = buf;
|
2007-09-02 01:40:58 +02:00
|
|
|
|
int bytes;
|
|
|
|
|
size_t size = sizeof(buf) - 1;
|
2005-06-15 22:51:25 +02:00
|
|
|
|
message * m;
|
|
|
|
|
|
2007-07-20 09:28:11 +02:00
|
|
|
|
message_faction(b, fac, msg_separator);
|
2005-06-15 22:51:25 +02:00
|
|
|
|
|
|
|
|
|
if (cont) m = msg_message("battle::lineup", "turn", b->turn);
|
|
|
|
|
else m = msg_message("battle::after", "");
|
|
|
|
|
message_faction(b, fac, m);
|
|
|
|
|
msg_release(m);
|
|
|
|
|
|
|
|
|
|
komma = false;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2005-06-15 22:51:25 +02:00
|
|
|
|
if (s->alive) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
int r, k = 0, * alive = get_alive(s);
|
2006-04-10 23:13:22 +02:00
|
|
|
|
int l = FIGHT_ROW;
|
|
|
|
|
const char * abbrev = seematrix(fac, s)?sideabkz(s, false):"-?-";
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char * loc_army = LOC(fac->locale, "battle_army");
|
2005-06-15 22:51:25 +02:00
|
|
|
|
char buffer[32];
|
|
|
|
|
|
2005-06-17 20:12:58 +02:00
|
|
|
|
if (komma) {
|
2007-09-02 01:40:58 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
2005-06-17 20:12:58 +02:00
|
|
|
|
}
|
2006-04-10 23:13:22 +02:00
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s %2d(%s): ",
|
2006-04-13 21:54:24 +02:00
|
|
|
|
loc_army, army_index(s), abbrev);
|
2005-06-15 22:51:25 +02:00
|
|
|
|
buffer[sizeof(buffer)-1] = 0;
|
|
|
|
|
|
2007-09-02 01:40:58 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, buffer, size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
2005-06-15 22:51:25 +02:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
for (r=FIGHT_ROW;r!=NUMROWS;++r) {
|
|
|
|
|
if (alive[r]) {
|
2005-06-15 23:24:22 +02:00
|
|
|
|
if (l!=FIGHT_ROW) {
|
2007-09-02 01:40:58 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, "+", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
2005-06-15 23:24:22 +02:00
|
|
|
|
}
|
|
|
|
|
while (k--) {
|
2007-09-02 01:40:58 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, "0+", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
2005-06-15 23:24:22 +02:00
|
|
|
|
}
|
|
|
|
|
sprintf(buffer, "%d", alive[r]);
|
2005-06-17 20:12:58 +02:00
|
|
|
|
|
2007-09-02 01:40:58 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, buffer, size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
2005-06-17 20:12:58 +02:00
|
|
|
|
|
|
|
|
|
k = 0;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
l = r+1;
|
|
|
|
|
} else ++k;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-06-15 22:51:25 +02:00
|
|
|
|
komma = true;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2007-09-02 01:40:58 +02:00
|
|
|
|
*bufp = 0;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fbattlerecord(b, fac, buf);
|
|
|
|
|
}
|
|
|
|
|
return cont;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
join_allies(battle * b)
|
|
|
|
|
{
|
2006-07-30 14:52:26 +02:00
|
|
|
|
region *r = b->region;
|
|
|
|
|
unit *u;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
side *s, *s_end = b->sides+b->nsides;
|
|
|
|
|
/* make_side might be adding a new faction, but it adds them to the end
|
|
|
|
|
* of the list, so we're safe in our iteration here if we remember the end
|
2006-04-13 19:16:15 +02:00
|
|
|
|
* up front. */
|
|
|
|
|
for (u=r->units;u;u=u->next) {
|
2004-05-30 04:24:53 +02:00
|
|
|
|
/* Was ist mit Schiffen? */
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (u->status != ST_FLEE && u->status != ST_AVOID && !fval(u, UFL_LONGACTION|UFL_ISNEW) && u->number > 0) {
|
2004-05-30 04:24:53 +02:00
|
|
|
|
faction * f = u->faction;
|
|
|
|
|
fighter * c = NULL;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=s_end;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
side * se;
|
2004-05-30 04:24:53 +02:00
|
|
|
|
/* Wenn alle attackierten noch FFL_NOAID haben, dann k<>mpfe nicht mit. */
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (fval(s->faction, FFL_NOAID)) continue;
|
|
|
|
|
if (s->faction!=f) {
|
2004-05-30 04:24:53 +02:00
|
|
|
|
/* Wenn wir attackiert haben, kommt niemand mehr hinzu: */
|
|
|
|
|
if (s->bf->attacker) continue;
|
|
|
|
|
/* alliiert m<>ssen wir schon sein, sonst ist's eh egal : */
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (!alliedunit(u, s->faction, HELP_FIGHT)) continue;
|
2004-05-30 04:24:53 +02:00
|
|
|
|
/* wenn die partei verborgen ist, oder gar eine andere
|
|
|
|
|
* vorgespiegelt wird, und er sich uns gegen<EFBFBD>ber nicht zu
|
|
|
|
|
* erkennen gibt, helfen wir ihm nicht */
|
|
|
|
|
if (s->stealthfaction){
|
|
|
|
|
if(!allysfm(s, u->faction, HELP_FSTEALTH)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* einen alliierten angreifen d<>rfen sie nicht, es sei denn, der
|
|
|
|
|
* ist mit einem alliierten verfeindet, der nicht attackiert
|
|
|
|
|
* hat: */
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (se=b->sides;se!=s_end;++se) {
|
|
|
|
|
if (u->faction==se->faction) continue;
|
|
|
|
|
if (alliedunit(u, se->faction, HELP_FIGHT) && !se->bf->attacker) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (enemy(s, se)) break;
|
2004-05-30 04:24:53 +02:00
|
|
|
|
}
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (se==s_end) continue;
|
2004-05-30 04:24:53 +02:00
|
|
|
|
/* Wenn die Einheit belagert ist, mu<6D> auch einer der Alliierten belagert sein: */
|
|
|
|
|
if (besieged(u)) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *ally;
|
|
|
|
|
for (ally = s->fighters; ally; ally=ally->next) {
|
|
|
|
|
if (besieged(ally->unit)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-05-30 04:24:53 +02:00
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (ally==NULL) continue;
|
2004-05-30 04:24:53 +02:00
|
|
|
|
}
|
|
|
|
|
/* keine Einw<6E>nde, also soll er mitmachen: */
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if (c==NULL) {
|
|
|
|
|
if (join_battle(b, u, false, &c)) {
|
|
|
|
|
if (battledebug) {
|
|
|
|
|
fprintf(bdebug, "%s joins to help %s against %s.\n",
|
2007-10-27 17:09:36 +02:00
|
|
|
|
unitname(u), factionname(s->faction),
|
|
|
|
|
factionname(se->faction));
|
2007-09-16 17:34:04 +02:00
|
|
|
|
}
|
|
|
|
|
} else if (c==NULL) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
/* the enemy of my friend is my enemy: */
|
|
|
|
|
for (se=b->sides;se!=s_end;++se) {
|
|
|
|
|
if (se->faction!=u->faction && enemy(s, se)) {
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if (set_enemy(se, c->side, false) && battledebug) {
|
|
|
|
|
fprintf(bdebug, "%u/%s hates %u/%s because they are enemies with %u/%s.\n",
|
|
|
|
|
c->side->index, sidename(c->side),
|
|
|
|
|
se->index, sidename(se),
|
|
|
|
|
s->index, sidename(s));
|
|
|
|
|
}
|
2004-05-30 04:24:53 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2006-07-30 14:52:26 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-07-30 14:52:26 +02:00
|
|
|
|
int si;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
side * sa;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
faction * f = s->faction;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
|
2006-07-30 14:52:26 +02:00
|
|
|
|
/* Den Feinden meiner Feinde gebe ich Deckung (gegen gemeinsame Feinde): */
|
|
|
|
|
for (si=0; s->enemies[si]; ++si) {
|
|
|
|
|
side * se = s->enemies[si];
|
|
|
|
|
int ai;
|
|
|
|
|
for (ai=0; se->enemies[ai]; ++ai) {
|
|
|
|
|
side * as = se->enemies[ai];
|
2006-08-13 18:27:58 +02:00
|
|
|
|
if (as==s || !enemy(as, s)) {
|
|
|
|
|
set_friendly(as, s);
|
2006-07-30 14:52:26 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-09-16 17:34:04 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (sa=s+1;sa!=b->sides+b->nsides;sa=++sa) {
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if (enemy(s, sa)) continue;
|
|
|
|
|
if (friendly(s, sa)) continue;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
if (!alliedgroup(r->planep, f, sa->faction, f->allies, HELP_FIGHT)) continue;
|
|
|
|
|
if (!alliedgroup(r->planep, sa->faction, f, sa->faction->allies, HELP_FIGHT)) continue;
|
2007-09-16 17:34:04 +02:00
|
|
|
|
|
|
|
|
|
set_friendly(s, sa);
|
|
|
|
|
}
|
2006-07-30 14:52:26 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-04-01 08:58:45 +02:00
|
|
|
|
flee(const troop dt)
|
2001-03-04 19:41:27 +01:00
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
fighter * fig = dt.fighter;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
|
|
|
|
|
#ifndef SIMPLE_ESCAPE
|
2006-04-10 23:13:22 +02:00
|
|
|
|
unit * u = fig->unit;
|
|
|
|
|
int carry = personcapacity(u) - u->race->weight;
|
|
|
|
|
int money;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
|
2006-04-10 23:13:22 +02:00
|
|
|
|
item ** ip = &u->items;
|
|
|
|
|
|
|
|
|
|
while (*ip) {
|
|
|
|
|
item * itm = *ip;
|
|
|
|
|
const item_type * itype = itm->type;
|
|
|
|
|
int keep = 0;
|
|
|
|
|
|
|
|
|
|
if (fval(itype, ITF_ANIMAL)) {
|
|
|
|
|
/* Regel<65>nderung: Man mu<6D> das Tier nicht reiten k<>nnen,
|
|
|
|
|
* um es vom Schlachtfeld mitzunehmen, ist ja nur
|
|
|
|
|
* eine Region weit. * */
|
|
|
|
|
keep = min(1, itm->number);
|
|
|
|
|
/* da ist das weight des tiers mit drin */
|
|
|
|
|
carry += itype->capacity - itype->weight;
|
|
|
|
|
} else if (itm->type->weight <= 0) {
|
|
|
|
|
/* if it doesn't weigh anything, it won't slow us down */
|
|
|
|
|
keep = itm->number;
|
|
|
|
|
}
|
|
|
|
|
/* jeder troop nimmt seinen eigenen Teil der Sachen mit */
|
|
|
|
|
if (keep>0){
|
|
|
|
|
if (itm->number==keep) {
|
|
|
|
|
i_add(&fig->run.items, i_remove(ip, itm));
|
|
|
|
|
} else {
|
|
|
|
|
item *run_itm = i_new(itype, keep);
|
|
|
|
|
i_add(&fig->run.items, run_itm);
|
|
|
|
|
i_change(ip, itype, -keep);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (*ip==itm) ip = &itm->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we will take money with us */
|
|
|
|
|
money = get_money(u);
|
|
|
|
|
/* nur ganzgeflohene/resttote Einheiten verlassen die Region */
|
|
|
|
|
if (money > carry) money = carry;
|
|
|
|
|
if (money > 0) {
|
|
|
|
|
i_change(&u->items, i_silver, -money);
|
|
|
|
|
i_change(&fig->run.items, i_silver, +money);
|
|
|
|
|
}
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
|
|
|
|
fig->run.hp += fig->person[dt.index].hp;
|
|
|
|
|
++fig->run.number;
|
|
|
|
|
|
2007-03-04 22:52:13 +01:00
|
|
|
|
kill_troop(dt);
|
2001-03-04 19:41:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
- 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
|
|
|
|
#ifdef DELAYED_OFFENSE
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static boolean
|
- 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
|
|
|
|
guarded_by(region * r, faction * f)
|
|
|
|
|
{
|
2006-04-10 23:13:22 +02:00
|
|
|
|
unit * u;
|
|
|
|
|
for (u=r->units;u;u=u->next) {
|
|
|
|
|
if (u->faction == f && getguard(u)) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
- 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
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
static boolean
|
|
|
|
|
init_battle(region * r, battle **bp)
|
|
|
|
|
{
|
|
|
|
|
battle * b = NULL;
|
|
|
|
|
unit * u;
|
|
|
|
|
boolean fighting = false;
|
|
|
|
|
|
|
|
|
|
/* list_foreach geht nicht, wegen flucht */
|
|
|
|
|
for (u = r->units; u != NULL; u = u->next) {
|
|
|
|
|
if (fval(u, UFL_LONGACTION)) continue;
|
|
|
|
|
if (u->number > 0) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
order * ord;
|
2006-04-10 23:13:22 +02:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
for (ord=u->orders;ord;ord=ord->next) {
|
2005-06-12 15:30:59 +02:00
|
|
|
|
static boolean init = false;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
static const curse_type * peace_ct, * slave_ct, * calm_ct;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
peace_ct = ct_find("peacezone");
|
|
|
|
|
slave_ct = ct_find("slavery");
|
|
|
|
|
calm_ct = ct_find("calmmonster");
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (get_keyword(ord) == K_ATTACK) {
|
2004-04-20 00:52:36 +02:00
|
|
|
|
unit *u2;
|
|
|
|
|
fighter *c1, *c2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-02-19 19:01:37 +01:00
|
|
|
|
if (r->planep && fval(r->planep, PFL_NOATTACK)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 271, MSG_BATTLE);
|
|
|
|
|
continue;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-02-19 19:01:37 +01:00
|
|
|
|
if ((u->race->battle_flags&BF_CANATTACK) == 0) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", "race", u->race));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-04-20 00:52:36 +02:00
|
|
|
|
/**
|
|
|
|
|
** Fehlerbehandlung Angreifer
|
|
|
|
|
**/
|
- 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
|
|
|
|
#ifdef DELAYED_OFFENSE
|
2004-04-20 00:52:36 +02:00
|
|
|
|
if (get_moved(&u->attribs) && !guarded_by(r, u->faction)) {
|
2007-02-19 19:01:37 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "no_attack_after_advance", ""));
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
- 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
|
|
|
|
#endif
|
2004-08-03 17:34:26 +02:00
|
|
|
|
if (LongHunger(u)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 225, MSG_BATTLE);
|
|
|
|
|
continue;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
if (u->status == ST_AVOID || u->status == ST_FLEE) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 226, MSG_BATTLE);
|
|
|
|
|
continue;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
/* ist ein Fl<46>chtling aus einem andern Kampf */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (fval(u, UFL_LONGACTION)) continue;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
if (peace_ct && curse_active(get_curse(r->attribs, peace_ct))) {
|
2007-06-26 23:17:10 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peace_active", ""));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
continue;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
if (slave_ct && curse_active(get_curse(u->attribs, slave_ct))) {
|
2007-06-26 23:17:10 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "slave_active", ""));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
continue;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
|
2005-06-24 21:27:35 +02:00
|
|
|
|
if (is_guarded(r, u, GUARD_TRAVELTHRU)) {
|
|
|
|
|
/* Fehler: "Das Schiff mu<6D> erst verlassen werden" */
|
2005-10-25 14:38:01 +02:00
|
|
|
|
if (u->ship != NULL && !fval(r->terrain, SEA_REGION)) {
|
2005-06-24 21:27:35 +02:00
|
|
|
|
cmistake(u, ord, 19, MSG_BATTLE);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-06-24 21:27:35 +02:00
|
|
|
|
if (leftship(u)) {
|
|
|
|
|
cmistake(u, ord, 234, MSG_BATTLE);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
/* Ende Fehlerbehandlung Angreifer */
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
2004-04-20 00:52:36 +02:00
|
|
|
|
/* attackierte Einheit ermitteln */
|
|
|
|
|
u2 = getunit(r, u->faction);
|
|
|
|
|
|
|
|
|
|
/* Beginn Fehlerbehandlung */
|
|
|
|
|
/* Fehler: "Die Einheit wurde nicht gefunden" */
|
2004-05-30 03:46:25 +02:00
|
|
|
|
if (!u2 || u2->number == 0 || !cansee(u->faction, u->region, u2, 0)) {
|
2007-02-10 22:47:51 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", ""));
|
2007-06-26 23:17:10 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Fehler: "Die Einheit ist eine der unsrigen" */
|
|
|
|
|
if (u2->faction == u->faction) {
|
|
|
|
|
cmistake(u, ord, 45, MSG_BATTLE);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Fehler: "Die Einheit ist mit uns alliert" */
|
|
|
|
|
if (alliedunit(u, u2->faction, HELP_FIGHT)) {
|
|
|
|
|
cmistake(u, ord, 47, MSG_BATTLE);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (u2->faction->age < NewbieImmunity()) {
|
|
|
|
|
add_message(&u->faction->msgs,
|
|
|
|
|
msg_feedback(u, u->thisorder, "newbie_immunity_error", "turns", NewbieImmunity()));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Fehler: "Die Einheit ist mit uns alliert" */
|
|
|
|
|
|
|
|
|
|
if (calm_ct) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_curse);
|
|
|
|
|
boolean calm = false;
|
|
|
|
|
while (a && a->type==&at_curse) {
|
|
|
|
|
curse * c = (curse *)a->data.v;
|
|
|
|
|
if (c->type==calm_ct && c->effect.i==u2->faction->subscription) {
|
|
|
|
|
if (curse_active(c)) {
|
|
|
|
|
calm = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
a = a->next;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (calm) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 47, MSG_BATTLE);
|
|
|
|
|
continue;
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
}
|
|
|
|
|
/* Ende Fehlerbehandlung */
|
|
|
|
|
if (b==NULL) {
|
|
|
|
|
unit * utmp;
|
|
|
|
|
for (utmp=r->units; utmp!=NULL; utmp=utmp->next) {
|
|
|
|
|
fset(utmp->faction, FFL_NOAID);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
b = make_battle(r);
|
|
|
|
|
}
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if (join_battle(b, u, true, &c1)) {
|
|
|
|
|
if (battledebug) {
|
|
|
|
|
fprintf(bdebug, "%s joins by attacking %s.\n",
|
|
|
|
|
unitname(u), unitname(u2));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (join_battle(b, u2, false, &c2)) {
|
|
|
|
|
if (battledebug) {
|
|
|
|
|
fprintf(bdebug, "%s joins because of an attack from %s.\n",
|
|
|
|
|
unitname(u2), unitname(u));
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
|
|
|
|
|
/* Hat die attackierte Einheit keinen Noaid-Status,
|
|
|
|
|
* wird das Flag von der Faction genommen, andere
|
|
|
|
|
* Einheiten greifen ein. */
|
|
|
|
|
if (!fval(u2, UFL_NOAID)) freset(u2->faction, FFL_NOAID);
|
|
|
|
|
|
|
|
|
|
if (c1!=NULL && c2!=NULL) {
|
|
|
|
|
/* Merken, wer Angreifer ist, f<>r die R<>ckzahlung der
|
|
|
|
|
* Pr<EFBFBD>combataura bei kurzem Kampf. */
|
|
|
|
|
c1->side->bf->attacker = true;
|
|
|
|
|
|
2007-09-16 17:34:04 +02:00
|
|
|
|
if (set_enemy(c1->side, c2->side, true) && battledebug) {
|
|
|
|
|
fprintf(bdebug, "%u/%s hates %u/%s because they attacked them.\n",
|
|
|
|
|
c2->side->index, sidename(c2->side),
|
|
|
|
|
c1->side->index, sidename(c1->side));
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
fighting = true;
|
|
|
|
|
}
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*bp = b;
|
|
|
|
|
return fighting;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-30 14:09:45 +02:00
|
|
|
|
static void
|
|
|
|
|
battle_stats(FILE * F, battle * b)
|
|
|
|
|
{
|
|
|
|
|
typedef struct stat_info {
|
|
|
|
|
struct stat_info * next;
|
2004-05-30 14:39:04 +02:00
|
|
|
|
const weapon_type * wtype;
|
2004-05-30 14:09:45 +02:00
|
|
|
|
int level;
|
|
|
|
|
int number;
|
|
|
|
|
} stat_info;
|
|
|
|
|
side * s;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2004-05-30 14:09:45 +02:00
|
|
|
|
fighter * df;
|
|
|
|
|
stat_info * stats = NULL, * stat;
|
2006-04-13 19:16:15 +02:00
|
|
|
|
|
|
|
|
|
for (df = s->fighters; df; df = df->next) {
|
2004-05-30 14:09:45 +02:00
|
|
|
|
unit *du = df->unit;
|
|
|
|
|
troop dt;
|
|
|
|
|
stat_info * slast = NULL;
|
|
|
|
|
|
|
|
|
|
dt.fighter = df;
|
|
|
|
|
for (dt.index=0;dt.index!=du->number;++dt.index) {
|
|
|
|
|
weapon * wp = preferred_weapon(dt, true);
|
2004-05-30 14:24:09 +02:00
|
|
|
|
int level = wp?wp->attackskill:0;
|
2004-05-30 14:39:04 +02:00
|
|
|
|
const weapon_type * wtype = wp?wp->type:NULL;
|
2004-05-30 14:09:45 +02:00
|
|
|
|
stat_info ** slist = &stats;
|
|
|
|
|
|
2004-05-30 14:39:04 +02:00
|
|
|
|
if (slast && slast->wtype==wtype && slast->level==level) {
|
2004-05-30 14:09:45 +02:00
|
|
|
|
++slast->number;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-05-30 14:39:04 +02:00
|
|
|
|
while (*slist && (*slist)->wtype!=wtype) {
|
2004-05-30 14:09:45 +02:00
|
|
|
|
slist = &(*slist)->next;
|
|
|
|
|
}
|
2004-05-30 14:39:04 +02:00
|
|
|
|
while (*slist && (*slist)->wtype==wtype && (*slist)->level>level) {
|
2004-05-30 14:09:45 +02:00
|
|
|
|
slist = &(*slist)->next;
|
|
|
|
|
}
|
|
|
|
|
stat = *slist;
|
2004-05-30 14:39:04 +02:00
|
|
|
|
if (stat==NULL || stat->wtype!=wtype || stat->level!=level) {
|
2004-05-30 14:09:45 +02:00
|
|
|
|
stat = calloc(1, sizeof(stat_info));
|
2004-05-30 14:39:04 +02:00
|
|
|
|
stat->wtype = wtype;
|
2004-05-30 14:09:45 +02:00
|
|
|
|
stat->level = level;
|
|
|
|
|
stat->next = *slist;
|
|
|
|
|
*slist = stat;
|
|
|
|
|
}
|
|
|
|
|
slast = stat;
|
|
|
|
|
++slast->number;
|
|
|
|
|
}
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
2004-05-30 14:09:45 +02:00
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s), factionname(s->faction));
|
2004-05-30 14:09:45 +02:00
|
|
|
|
for (stat=stats;stat!=NULL;stat=stat->next) {
|
2004-05-30 14:39:04 +02:00
|
|
|
|
fprintf(F, "%s %u : %u\n", stat->wtype?stat->wtype->itype->rtype->_name[0]:"none", stat->level, stat->number);
|
2004-05-30 14:09:45 +02:00
|
|
|
|
}
|
|
|
|
|
freelist(stats);
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** execute one round of attacks
|
|
|
|
|
* fig->fighting is used to determine who attacks, not fig->alive, since
|
|
|
|
|
* the latter may be influenced by attacks that already took place.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
battle_attacks(battle * b)
|
|
|
|
|
{
|
|
|
|
|
side * s;
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *fig;
|
|
|
|
|
for (fig=s->fighters;fig;fig=fig->next) {
|
|
|
|
|
|
|
|
|
|
/* ist in dieser Einheit noch jemand handlungsf<73>hig? */
|
|
|
|
|
if (fig->fighting <= 0) continue;
|
|
|
|
|
|
|
|
|
|
/* Taktikrunde: */
|
|
|
|
|
if (b->turn == 0) {
|
|
|
|
|
side *stac;
|
|
|
|
|
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (stac=b->sides;stac!=b->sides+b->nsides;++stac) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (b->max_tactics > 0 && stac->leader.value == b->max_tactics && helping(stac, fig->side)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (stac==NULL) continue;
|
|
|
|
|
}
|
|
|
|
|
/* Handle the unit's attack on someone */
|
|
|
|
|
do_attack(fig);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** updates the number of attacking troops in each fighter struct.
|
|
|
|
|
* this has to be calculated _before_ the actual attacks take
|
|
|
|
|
* place because otherwise dead troops would not strike in the
|
|
|
|
|
* round they die. */
|
|
|
|
|
static void
|
|
|
|
|
battle_update(battle * b)
|
|
|
|
|
{
|
|
|
|
|
side * s;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *fig;
|
|
|
|
|
for (fig=s->fighters;fig;fig=fig->next) {
|
|
|
|
|
fig->fighting = fig->alive - fig->removed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** attempt to flee from battle before the next round begins
|
|
|
|
|
* there's a double attempt before the first round, but only
|
|
|
|
|
* one attempt before round zero, the potential tactics round. */
|
|
|
|
|
static void
|
|
|
|
|
battle_flee(battle * b)
|
|
|
|
|
{
|
|
|
|
|
int attempt, flee_ops = 1;
|
|
|
|
|
|
|
|
|
|
if (b->turn==1)
|
|
|
|
|
flee_ops = 2;
|
|
|
|
|
|
|
|
|
|
for (attempt=1;attempt<=flee_ops;++attempt) {
|
|
|
|
|
side * s;
|
2007-10-27 17:09:36 +02:00
|
|
|
|
for (s=b->sides;s!=b->sides+b->nsides;++s) {
|
2006-04-13 19:16:15 +02:00
|
|
|
|
fighter *fig;
|
|
|
|
|
for (fig=s->fighters;fig;fig=fig->next) {
|
|
|
|
|
unit *u = fig->unit;
|
|
|
|
|
troop dt;
|
|
|
|
|
int runners = 0;
|
|
|
|
|
/* Flucht nicht bei mehr als 600 HP. Damit Wyrme t<>tbar bleiben. */
|
|
|
|
|
int runhp = min(600,(int)(0.9+unit_max_hp(u)*hpflee(u->status)));
|
|
|
|
|
if (fval(u->race, RCF_UNDEAD) || u->race == new_race[RC_SHADOWKNIGHT]) continue;
|
|
|
|
|
|
|
|
|
|
if (u->ship) continue;
|
|
|
|
|
dt.fighter = fig;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#ifndef SIMPLE_ESCAPE
|
2006-04-13 19:16:15 +02:00
|
|
|
|
if (!fig->run.region) fig->run.region = fleeregion(u);
|
|
|
|
|
if (!fig->run.region) continue;
|
2007-02-10 12:25:23 +01:00
|
|
|
|
#endif /* SIMPLE_ESCAPE */
|
2006-04-13 19:16:15 +02:00
|
|
|
|
dt.index = fig->alive - fig->removed;
|
|
|
|
|
while (s->size[SUM_ROW] && dt.index != 0) {
|
|
|
|
|
double ispaniced = 0.0;
|
|
|
|
|
--dt.index;
|
|
|
|
|
assert(dt.index>=0 && dt.index<fig->unit->number);
|
|
|
|
|
assert(fig->person[dt.index].hp > 0);
|
|
|
|
|
|
|
|
|
|
/* Versuche zu fliehen, wenn
|
|
|
|
|
* - Kampfstatus fliehe
|
|
|
|
|
* - schwer verwundet und nicht erste kampfrunde
|
|
|
|
|
* - in panik (Zauber)
|
|
|
|
|
* aber nicht, wenn der Zaubereffekt Held auf dir liegt!
|
|
|
|
|
*/
|
|
|
|
|
switch (u->status) {
|
|
|
|
|
case ST_FLEE:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if ((fig->person[dt.index].flags & FL_HIT) == 0) continue;
|
|
|
|
|
if (b->turn<=1) continue;
|
|
|
|
|
if (fig->person[dt.index].hp <= runhp) break;
|
|
|
|
|
if (fig->person[dt.index].flags & FL_PANICED) {
|
|
|
|
|
if ((fig->person[dt.index].flags & FL_COURAGE)==0) break;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fig->person[dt.index].flags & FL_PANICED) {
|
|
|
|
|
ispaniced = EFFECT_PANIC_SPELL;
|
|
|
|
|
}
|
|
|
|
|
if (chance(min(fleechance(u)+ispaniced, 0.90))) {
|
|
|
|
|
++runners;
|
|
|
|
|
flee(dt);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug && runners > 0) {
|
|
|
|
|
fprintf(bdebug, "Fleeing: %d from %s\n", runners, itoa36(fig->unit->no));
|
2006-04-13 19:16:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-05-30 14:09:45 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-20 00:52:36 +02:00
|
|
|
|
void
|
2006-08-12 21:15:16 +02:00
|
|
|
|
do_battle(region * r)
|
2004-04-20 00:52:36 +02:00
|
|
|
|
{
|
2006-08-12 21:15:16 +02:00
|
|
|
|
battle *b = NULL;
|
|
|
|
|
boolean fighting = false;
|
|
|
|
|
ship * sh;
|
|
|
|
|
building *bu;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-07-20 09:28:11 +02:00
|
|
|
|
if (msg_separator==NULL) {
|
|
|
|
|
msg_separator = msg_message("battle::section", "");
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
fighting = init_battle(r, &b);
|
|
|
|
|
|
|
|
|
|
if (b==NULL) return;
|
|
|
|
|
|
|
|
|
|
/* Bevor wir die alliierten hineinziehen, sollten wir schauen, *
|
|
|
|
|
* Ob jemand fliehen kann. Dann er<EFBFBD>brigt sich das ganze ja
|
|
|
|
|
* vielleicht schon. */
|
|
|
|
|
print_header(b);
|
|
|
|
|
if (!fighting) {
|
|
|
|
|
/* Niemand mehr da, Kampf kann nicht stattfinden. */
|
|
|
|
|
message * m = msg_message("battle::aborted", "");
|
|
|
|
|
message_all(b, m);
|
|
|
|
|
msg_release(m);
|
|
|
|
|
free_battle(b);
|
|
|
|
|
free(b);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
join_allies(b);
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#ifdef HEROES
|
2006-08-12 21:15:16 +02:00
|
|
|
|
make_heroes(b);
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#endif
|
2006-08-12 21:15:16 +02:00
|
|
|
|
/* Alle Mann raus aus der Burg! */
|
|
|
|
|
for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
/* make sure no ships are damaged initially */
|
|
|
|
|
for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED);
|
2002-02-06 09:06:02 +01:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
/* Gibt es eine Taktikrunde ? */
|
|
|
|
|
if (cv_size(&b->leaders)) {
|
|
|
|
|
b->turn = 0;
|
|
|
|
|
b->has_tactics_turn = true;
|
|
|
|
|
} else {
|
|
|
|
|
b->turn = 1;
|
|
|
|
|
b->has_tactics_turn = false;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b);
|
2004-05-30 14:09:45 +02:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
/* PRECOMBATSPELLS */
|
|
|
|
|
do_combatmagic(b, DO_PRECOMBATSPELL);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
print_stats(b); /* gibt die Kampfaufstellung aus */
|
|
|
|
|
printf("%s (%d, %d) : ", rname(r, NULL), r->x, r->y);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
for (;battle_report(b) && b->turn<=COMBAT_TURNS;++b->turn) {
|
2007-06-26 23:17:10 +02:00
|
|
|
|
if (bdebug) {
|
|
|
|
|
fprintf(bdebug, "*** Turn: %d\n", b->turn);
|
2007-05-27 23:20:06 +02:00
|
|
|
|
}
|
2006-08-12 21:15:16 +02:00
|
|
|
|
battle_flee(b);
|
|
|
|
|
battle_update(b);
|
|
|
|
|
battle_attacks(b);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#ifdef KARMA_MODULE
|
2006-08-12 21:15:16 +02:00
|
|
|
|
/* Regeneration */
|
|
|
|
|
for (fi=0;fi!=b->nfighters;++fi) {
|
|
|
|
|
fighter *fig = b->fighters[fi];
|
|
|
|
|
|
|
|
|
|
if (fspecial(fig->unit->faction, FS_REGENERATION)) {
|
|
|
|
|
fig->fighting = fig->alive - fig->removed;
|
|
|
|
|
if (fig->fighting == 0) continue;
|
|
|
|
|
do_regenerate(fig);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-12 21:15:16 +02:00
|
|
|
|
#endif /* KARMA_MODULE */
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
printf("\n");
|
2004-04-20 00:52:36 +02:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
/* Auswirkungen berechnen: */
|
|
|
|
|
aftermath(b);
|
|
|
|
|
/* Hier ist das Gefecht beendet, und wir k<>nnen die
|
|
|
|
|
* Hilfsstrukturen * wieder l<EFBFBD>schen: */
|
2004-04-20 00:52:36 +02:00
|
|
|
|
|
2006-08-12 21:15:16 +02:00
|
|
|
|
if (b) {
|
|
|
|
|
free_battle(b);
|
|
|
|
|
free(b);
|
2004-04-20 00:52:36 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|