2001-01-25 10:37:55 +01:00
/* vi: set ts=2:
*
2001-05-06 23:49:16 +02:00
*
2003-07-29 11:48:03 +02:00
* Eressea PB ( E ) M host Copyright ( C ) 1998 - 2003
2001-01-25 10:37:55 +01:00
* Christian Schlittchen ( corwin @ amber . kn - bremen . de )
* Katja Zedel ( katze @ felidae . kn - bremen . de )
* Henning Peters ( faroul @ beyond . kn - bremen . de )
* Enno Rehling ( enno @ eressea - pbem . de )
* Ingo Wilken ( Ingo . Wilken @ informatik . uni - oldenburg . de )
*
* This program may not be used , modified or distributed without
* prior permission by the authors of Eressea .
*/
# define SHOW_KILLS
2001-12-10 01:13:39 +01:00
# undef DELAYED_OFFENSE /* non-guarding factions cannot attack after moving */
2001-01-25 10:37:55 +01:00
# define TACTICS_RANDOM 5 /* define this as 1 to deactivate */
# define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rand() % INITIAL */
# define CATAPULT_STRUCTURAL_DAMAGE
2001-12-10 01:13:39 +01:00
# define BASE_CHANCE 70 /* 70% <20> berlebenschance */
# define TDIFF_CHANGE 10
2001-01-25 10:37:55 +01:00
typedef enum combatmagic {
DO_PRECOMBATSPELL ,
DO_POSTCOMBATSPELL
} combatmagic_t ;
# include <config.h>
# include "eressea.h"
# include "battle.h"
# include "item.h"
# include "alchemy.h"
# include "plane.h"
# include "magic.h"
# include "faction.h"
# include "reports.h"
# include "build.h"
# include "race.h"
# include "movement.h"
# include "movement.h"
# include "names.h"
# include "region.h"
# include "skill.h"
# include "goodies.h"
# include "unit.h"
# include "message.h"
# include "curse.h"
# include "spell.h"
# include "karma.h"
# include "ship.h"
# include "building.h"
2001-12-10 01:13:39 +01:00
# include "group.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
/* items includes */
# include <items/demonseye.h>
2002-11-30 22:06:27 +01:00
/* modules includes */
2003-07-29 11:48:03 +02:00
# ifdef ALLIANCES
2002-11-30 22:06:27 +01:00
# include <modules/alliance.h>
2003-07-29 11:48:03 +02:00
# endif
/* util includes */
# include <base36.h>
# include <cvector.h>
# include <rand.h>
# include <log.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>
2001-12-10 01:13:39 +01:00
# include <message.h>
2001-01-25 10:37:55 +01:00
# include <stdlib.h>
# include <string.h>
# ifdef HAVE_ZLIB
# include <zlib.h>
2001-02-03 14:45:35 +01:00
# define dbgprintf(a) gzprintf a;
gzFile bdebug ;
# elif HAVE_BZ2LIB
2001-01-25 10:37:55 +01:00
# include <bzlib.h>
2001-02-03 14:45:35 +01:00
# define dbgprintf(a) bz2printf a;
BZFILE * bdebug ;
# else
# define dbgprintf(a) fprintf a;
FILE * bdebug ;
2001-01-25 10:37:55 +01:00
# endif
2003-07-29 11:48:03 +02:00
/* external variables */
2001-01-25 10:37:55 +01:00
boolean nobattledebug = false ;
2003-07-29 11:48:03 +02:00
/* globals */
static int obs_count = 0 ;
2001-01-25 10:37:55 +01:00
# define TACTICS_MALUS
# undef MAGIC_TURNS
# define MINSPELLRANGE 1
# define MAXSPELLRANGE 7
static const double EFFECT_PANIC_SPELL = 0.25 ;
static const double TROLL_REGENERATION = 0.10 ;
# define MAX_ADVANTAGE 5
enum {
SI_DEFENDER ,
SI_ATTACKER
} ;
extern weapon_type * oldweapontype [ ] ;
/* Nach dem alten System: */
static int missile_range [ 2 ] = { FIGHT_ROW , BEHIND_ROW } ;
static int melee_range [ 2 ] = { FIGHT_ROW , FIGHT_ROW } ;
typedef struct armor_type {
double penalty ;
double magres ;
int prot ;
char shield ;
char item ;
} armor_type ;
static armor_type armordata [ AR_NONE + 1 ] =
2001-03-23 11:07:00 +01:00
/* penalty; magres; prot; shield; item; */
2001-01-25 10:37:55 +01:00
{
# ifdef COMPATIBILITY
{ - 0.80 , 5 , 0 , I_CLOAK_OF_INVULNERABILITY } ,
# endif
{ 0.30 , 0.00 , 5 , 0 , I_PLATE_ARMOR } ,
{ 0.15 , 0.00 , 3 , 0 , I_CHAIN_MAIL } ,
{ 0.30 , 0.00 , 3 , 0 , I_RUSTY_CHAIN_MAIL } ,
{ - 0.15 , 0.00 , 1 , 1 , I_SHIELD } ,
{ 0.00 , 0.00 , 1 , 1 , I_RUSTY_SHIELD } ,
2001-12-10 01:13:39 +01:00
{ - 0.25 , 0.30 , 2 , 1 , I_LAENSHIELD } ,
{ 0.00 , 0.30 , 6 , 0 , I_LAENCHAIN } ,
2001-01-25 10:37:55 +01:00
{ 0.00 , 0.00 , 0 , 0 , I_SWORD } ,
{ 0.00 , 0.00 , 0 , 0 , I_SWORD }
} ;
2004-06-11 22:47:45 +02:00
#if 0
2004-06-11 22:50:50 +02:00
/* not in use */
2004-05-21 02:49:18 +02:00
static void
validate_sides ( battle * b )
{
side * s ;
cv_foreach ( s , b - > sides ) {
2004-05-21 11:37:49 +02:00
int snumber = 0 ;
2004-05-21 02:49:18 +02:00
fighter * df ;
2004-05-21 11:37:49 +02:00
cv_foreach ( df , s - > fighters ) {
unit * du = df - > unit ;
snumber + = du - > number ;
} cv_next ( df ) ;
assert ( snumber = = s - > flee + s - > healed + s - > alive + s - > dead ) ;
2004-05-21 02:49:18 +02:00
} cv_next ( s ) ;
}
# else
# define validate_sides(b) /**/
# endif
2001-01-25 10:37:55 +01:00
const troop no_troop = { 0 , 0 } ;
region *
fleeregion ( const unit * u )
{
2004-01-12 17:22:14 +01:00
region * r = u - > region ;
2001-01-25 10:37:55 +01:00
region * neighbours [ MAXDIRECTIONS ] ;
int c = 0 ;
direction_t i ;
if ( u - > ship & & landregion ( rterrain ( r ) ) )
return NULL ;
if ( u - > ship & &
2001-12-10 01:13:39 +01:00
! ( u - > race - > flags & RCF_SWIM ) & &
! ( u - > race - > flags & RCF_FLY ) ) {
2001-01-25 10:37:55 +01:00
return NULL ;
}
# ifdef FLEE_TO
/* Hat die Einheit ein NACH, wird die angegebene Richtung bevorzugt */
if ( igetkeyword ( u - > thisorder ) = = K_MOVE
| | igetkeyword ( u - > thisorder ) = = K_ROUTE )
{
region * r2 ;
r2 = movewhere ( r , u ) ;
if ( r2 ) {
return r2 ;
}
}
# endif
for ( i = 0 ; i ! = MAXDIRECTIONS ; + + i ) {
region * r2 = rconnect ( r , i ) ;
if ( r2 ) {
2004-05-31 18:21:03 +02:00
if ( can_survive ( u , r2 ) & & ! move_blocked ( u , r , r2 ) )
2001-01-25 10:37:55 +01:00
neighbours [ c + + ] = r2 ;
}
}
if ( ! c )
return NULL ;
return neighbours [ rand ( ) % c ] ;
}
2001-12-10 01:13:39 +01:00
static char *
sidename ( side * s , boolean truename )
{
# define SIDENAMEBUFLEN 256
static char sidename_buf [ SIDENAMEBUFLEN ] ;
if ( s - > stealthfaction & & truename = = false ) {
snprintf ( sidename_buf , SIDENAMEBUFLEN ,
" %s " , factionname ( s - > stealthfaction ) ) ;
} else {
snprintf ( sidename_buf , SIDENAMEBUFLEN ,
" %s " , factionname ( s - > bf - > faction ) ) ;
}
return sidename_buf ;
}
2004-04-22 00:09:39 +02:00
static const char *
2001-12-10 01:13:39 +01:00
sideabkz ( side * s , boolean truename )
{
static char sideabkz_buf [ 4 ] ;
if ( s - > stealthfaction & & truename = = false ) {
snprintf ( sideabkz_buf , 4 , " %s " , abkz ( s - > stealthfaction - > name , 3 ) ) ;
} else {
snprintf ( sideabkz_buf , 4 , " %s " , abkz ( s - > bf - > faction - > name , 3 ) ) ;
}
return sideabkz_buf ;
}
2004-04-20 00:52:36 +02:00
void
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 )
{
item * itm ;
int n = 0 ;
2001-02-04 11:04:36 +01:00
if ( ! ( urace ( u ) - > flags & RCF_NOWEAPONS ) ) {
2001-02-03 14:45:35 +01:00
if ( urace ( u ) - > ec_flags & CANGUARD ) {
/* kann ohne waffen bewachen: fuer untote und drachen */
2001-04-01 08:58:45 +02:00
n = u - > number ;
2001-01-25 10:37:55 +01:00
} else {
2001-02-03 14:45:35 +01:00
/* alle Waffen werden gezaehlt, und dann wird auf die Anzahl
* Personen minimiert */
2001-01-25 10:37:55 +01:00
for ( itm = u - > items ; itm ; itm = itm - > next ) {
const weapon_type * wtype = resource2weapon ( itm - > type - > rtype ) ;
if ( wtype = = NULL ) continue ;
2001-04-01 08:58:45 +02:00
if ( effskill ( u , wtype - > skill ) > = 1 ) n + = itm - > number ;
/* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */
2001-01-25 10:37:55 +01:00
if ( n > u - > number ) break ;
}
2001-02-03 14:45:35 +01:00
n = min ( n , u - > number ) ;
2001-01-25 10:37:55 +01:00
}
}
return n ;
}
static void
battledebug ( const char * s )
{
# if SHOW_DEBUG
printf ( " %s \n " , translate_regions ( s , NULL ) ) ;
# endif
if ( bdebug ) {
2001-02-03 14:45:35 +01:00
dbgprintf ( ( bdebug , " %s \n " , translate_regions ( s , NULL ) ) ) ;
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 ) ;
}
}
void
battlerecord ( battle * b , const char * s )
{
struct message * m = msg_message ( " msg_battle " , " string " , strdup ( s ) ) ;
message_all ( b , m ) ;
msg_release ( m ) ;
2001-01-25 10:37:55 +01:00
}
void
battlemsg ( battle * b , unit * u , const char * s )
{
bfaction * bf ;
2002-03-12 21:48:10 +01:00
struct message * m ;
plane * p = rplane ( b - > region ) ;
watcher * w ;
2001-01-25 10:37:55 +01:00
sprintf ( buf , " %s %s " , unitname ( u ) , s ) ;
2002-03-12 21:48:10 +01:00
m = msg_message ( " msg_battle " , " string " , strdup ( buf ) ) ;
2001-01-25 10:37:55 +01:00
for ( bf = b - > factions ; bf ; bf = bf - > next ) {
2004-04-20 00:52:36 +02:00
message_faction ( b , bf - > faction , m ) ;
2002-03-12 21:48:10 +01:00
}
if ( p ) for ( w = p - > watchers ; w ; w = w - > next ) {
for ( bf = b - > factions ; bf ; bf = bf - > next ) if ( bf - > faction = = w - > faction ) break ;
2004-04-20 00:52:36 +02:00
if ( bf = = NULL ) message_faction ( b , w - > faction , m ) ;
2001-01-25 10:37:55 +01:00
}
2002-03-12 21:48:10 +01:00
msg_release ( 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
{
2004-04-20 00:52:36 +02:00
message * m = msg_message ( " msg_battle " , " string " , gc_add ( strdup ( s ) ) ) ;
message_faction ( b , f , m ) ;
msg_release ( m ) ;
2001-01-25 10:37:55 +01:00
}
2004-05-28 23:04:18 +02:00
# define enemy(as, ds) (as->enemy[ds->index]&E_ENEMY)
2001-01-25 10:37:55 +01:00
static void
set_enemy ( side * as , side * ds , boolean attacking )
{
2004-05-28 23:04:18 +02:00
int i ;
for ( i = 0 ; i ! = 128 ; + + i ) {
if ( ds - > enemies [ i ] = = NULL ) ds - > enemies [ i ] = as ;
if ( ds - > enemies [ i ] = = as ) break ;
}
for ( i = 0 ; i ! = 128 ; + + i ) {
if ( as - > enemies [ i ] = = NULL ) as - > enemies [ i ] = ds ;
if ( as - > enemies [ i ] = = ds ) break ;
}
ds - > enemy [ as - > index ] | = E_ENEMY ;
as - > enemy [ ds - > index ] | = E_ENEMY ;
if ( attacking ) as - > enemy [ ds - > index ] | = E_ATTACKING ;
2001-01-25 10:37:55 +01:00
}
2002-08-26 16:16:16 +02:00
# ifdef ALLIANCES
2001-01-25 10:37:55 +01:00
static int
2002-09-02 22:36:12 +02:00
allysfm ( const side * s , const faction * f , int mode )
2001-01-25 10:37:55 +01:00
{
2002-09-02 22:36:12 +02:00
if ( s - > bf - > faction = = f ) return true ;
return alliedfaction ( s - > battle - > plane , s - > bf - > faction , f , mode ) ;
2001-01-25 10:37:55 +01:00
}
2002-08-26 16:16:16 +02:00
# else
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
{
2002-12-14 16:49:18 +01:00
if ( s - > bf - > faction = = f ) return mode ;
if ( s - > group ) {
return alliedgroup ( s - > battle - > plane , s - > bf - > faction , f , s - > group - > allies , mode ) ;
}
2002-09-02 23:10:53 +02:00
return alliedfaction ( s - > battle - > plane , s - > bf - > faction , f , mode ) ;
2001-12-10 01:13:39 +01:00
}
2002-08-26 16:16:16 +02:00
# endif
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
{
return allysfm ( s , f , HELP_FIGHT ) ;
}
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
2004-05-20 09:34:02 +02:00
* Parteizugeh <EFBFBD> rigkeit ignoriert , und irgendeine Leiche genommen .
*
* Untote werden nicht ausgew <EFBFBD> hlt ( casualties , not dead ) */
2001-01-25 10:37:55 +01:00
{
int di , maxcasualties = 0 ;
fighter * df ;
side * side ;
2003-07-29 11:48:03 +02:00
cv_foreach ( side , b - > sides ) {
2001-01-25 10:37:55 +01:00
if ( ! af | | ( ! enemy ( af - > side , side ) & & allysf ( af - > side , side - > bf - > faction ) ) )
maxcasualties + = side - > casualties ;
}
2003-07-29 11:48:03 +02:00
cv_next ( side ) ;
2001-01-25 10:37:55 +01:00
di = rand ( ) % maxcasualties ;
2003-07-29 11:48:03 +02:00
cv_foreach ( df , b - > fighters ) {
2001-01-25 10:37:55 +01:00
/* Geflohene haben auch 0 hp, d<> rfen hier aber nicht ausgew<65> hlt
* werden ! */
2001-03-04 19:41:27 +01:00
int dead = df - > unit - > number - ( df - > alive + df - > run . number ) ;
2001-12-10 01:13:39 +01:00
if ( ! playerrace ( df - > unit - > race ) ) continue ;
2001-01-25 10:37:55 +01:00
if ( af & & ! helping ( af - > side , df - > side ) )
continue ;
if ( di < dead ) {
2004-05-29 20:57:18 +02:00
return df ;
2001-01-25 10:37:55 +01:00
}
di - = dead ;
}
2003-07-29 11:48:03 +02:00
cv_next ( df ) ;
2004-05-29 20:57:18 +02:00
return NULL ;
2001-01-25 10:37:55 +01:00
}
boolean
helping ( side * as , side * ds )
{
if ( as - > bf - > faction = = ds - > bf - > faction ) return true ;
return ( boolean ) ( ! enemy ( as , ds ) & & allysf ( as , ds - > bf - > faction ) ) ;
}
/* 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
countallies ( side * as )
{
battle * b = as - > battle ;
side * s ;
int count = 0 ;
2003-07-29 11:48:03 +02:00
cv_foreach ( s , b - > sides ) {
2001-01-25 10:37:55 +01:00
if ( ! helping ( as , s ) ) continue ;
count + = s - > size [ SUM_ROW ] ;
}
2003-07-29 11:48:03 +02:00
cv_next ( s ) ;
2001-01-25 10:37:55 +01:00
return count ;
}
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
{
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 ;
}
static double
2001-12-10 01:13:39 +01:00
hpflee ( int status )
2001-04-13 16:39:57 +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-01-25 10:37:55 +01:00
int
2004-04-18 23:44:24 +02:00
get_unitrow ( const fighter * af )
2001-01-25 10:37:55 +01:00
{
2004-04-18 23:44:24 +02:00
static boolean * counted = NULL ;
static size_t csize = 0 ;
battle * b = af - > side - > battle ;
int enemyfront = 0 ;
int line , result ;
int retreat = 0 ;
int size [ NUMROWS ] ;
int row = statusrow ( af - > status ) ;
int front = 0 ;
size_t bsize ;
2001-01-25 10:37:55 +01:00
2004-04-18 23:44:24 +02:00
bsize = cv_size ( & b - > sides ) ;
if ( csize < bsize ) {
if ( counted ) free ( counted ) ;
csize = bsize ;
counted = calloc ( sizeof ( boolean ) , bsize ) ;
}
else memset ( counted , 0 , bsize * sizeof ( boolean ) ) ;
memset ( size , 0 , sizeof ( size ) ) ;
for ( line = FIRST_ROW ; line ! = NUMROWS ; + + line ) {
2004-05-28 23:31:11 +02:00
int si ;
2004-04-18 23:44:24 +02:00
/* how many enemies are there in the first row? */
2004-05-28 23:04:18 +02:00
for ( si = 0 ; af - > side - > enemies [ si ] ; + + si ) {
side * s = af - > side - > enemies [ si ] ;
if ( s - > size [ line ] > 0 ) {
int ai ;
2004-04-18 23:44:24 +02:00
enemyfront + = s - > size [ line ] ; /* - s->nonblockers[line] (nicht, weil angreifer) */
2004-05-28 23:04:18 +02:00
for ( ai = 0 ; s - > enemies [ ai ] ; + + ai ) {
side * ally = s - > enemies [ ai ] ;
if ( ! counted [ ally - > index ] & & ! enemy ( ally , af - > side ) ) {
2004-04-18 23:44:24 +02:00
int i ;
counted [ ally - > index ] = true ;
for ( i = 0 ; i ! = NUMROWS ; + + i ) size [ i ] + = ally - > size [ i ] - ally - > nonblockers [ i ] ;
}
}
}
}
if ( enemyfront ) break ;
}
if ( enemyfront ) {
for ( line = FIRST_ROW ; line ! = NUMROWS ; + + line ) {
front + = size [ line ] ;
if ( ! front | | front < enemyfront / 10 ) + + retreat ;
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
}
static int
2001-02-14 21:09:49 +01:00
sort_fighterrow ( fighter * * elem1 , fighter * * elem2 )
2001-01-25 10:37:55 +01:00
{
int a , b ;
a = get_unitrow ( * elem1 ) ;
b = get_unitrow ( * elem2 ) ;
return ( a < b ) ? - 1 : ( ( a = = b ) ? 0 : 1 ) ;
}
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 ;
if ( fig - > alive = = fig - > unit - > number ) return ;
2003-03-08 21:57:38 +01:00
# ifndef NO_RUNNING
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 ;
}
2003-03-08 21:57:38 +01:00
# endif
# ifdef NO_RUNNING
2004-05-29 20:57:18 +02:00
m = msg_message ( " casualties " , " unit runto run alive fallen " ,
fig - > unit , NULL , fig - > run . number , fig - > alive , dead ) ;
2003-03-08 21:57:38 +01:00
# else
2004-05-29 20:57:18 +02:00
m = msg_message ( " casualties " , " unit runto run alive fallen " ,
fig - > unit , fig - > run . region , fig - > run . number , fig - > alive , dead ) ;
2003-03-08 21:57:38 +01:00
# endif
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
contest ( int skilldiff , armor_t ar , armor_t sh )
{
int p , vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff ;
double mod = 1.0 ;
/* Hardcodet, mu<6D> ge<67> ndert werden. */
2001-05-06 23:49:16 +02:00
# ifdef OLD_ARMOR
2001-01-25 10:37:55 +01:00
if ( ar ! = AR_NONE )
mod * = ( 1 - armordata [ ar ] . penalty ) ;
if ( sh ! = AR_NONE )
mod * = ( 1 - armordata [ sh ] . penalty ) ;
vw = ( int ) ( vw * mod ) ;
2001-05-06 23:49:16 +02:00
# else
if ( ar ! = AR_NONE )
mod * = ( 1 + armordata [ ar ] . penalty ) ;
if ( sh ! = AR_NONE )
mod * = ( 1 + armordata [ sh ] . penalty ) ;
vw = ( int ) ( 100 - ( ( 100 - vw ) * mod ) ) ;
# endif
2001-01-25 10:37:55 +01:00
do {
p = rand ( ) % 100 ;
vw - = p ;
}
2001-04-01 08:58:45 +02:00
while ( vw > = 0 & & p > = 90 ) ;
return ( vw < = 0 ) ;
2001-01-25 10:37:55 +01:00
}
static boolean
riding ( const troop t ) {
if ( t . fighter - > building ! = NULL ) return false ;
if ( t . fighter - > horses + t . fighter - > elvenhorses > t . index ) return true ;
return false ;
}
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
{
2002-10-04 23:37:35 +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 ;
}
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 )
/* select the primary weapon for this trooper */
{
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
if ( attacking ) {
2002-10-04 23:37:35 +02:00
if ( ismissile ) {
/* from the back rows, have to use your missile weapon */
return t . fighter - > person [ t . index ] . missile ;
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
}
} else {
2002-10-04 23:37:35 +02:00
if ( ! ismissile ) {
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
/* have to use your melee weapon if it's melee */
2002-10-04 23:37:35 +02:00
return t . fighter - > person [ t . index ] . melee ;
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
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 )
/* 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 ) ;
2002-02-16 11:37:18 +01:00
if ( skill < = 0 ) {
2001-01-25 10:37:55 +01:00
/* wenn kein waffenloser kampf, dann den rassen-defaultwert */
2002-02-10 17:04:39 +01:00
if ( u - > race = = new_race [ RC_URUK ] ) {
int sword = effskill ( u , SK_SWORD ) ;
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 ) ;
}
2001-01-25 10:37:55 +01:00
} else {
2002-02-10 17:04:39 +01:00
if ( attacking ) {
skill = u - > race - > at_default ;
} else {
skill = u - > race - > df_default ;
}
2001-01-25 10:37:55 +01:00
}
2001-02-14 09:35:12 +01:00
} else {
/* der rassen-defaultwert kann h<> her sein als der Talentwert von
* waffenloser kampf */
if ( attacking ) {
2001-12-10 01:13:39 +01:00
if ( skill < u - > race - > at_default ) skill = u - > race - > at_default ;
2001-02-14 09:35:12 +01:00
} else {
2001-12-10 01:13:39 +01:00
if ( skill < u - > race - > df_default ) skill = u - > race - > df_default ;
2001-04-01 08:58:45 +02:00
}
2001-01-25 10:37:55 +01:00
}
2002-04-14 11:53:26 +02:00
if ( attacking ) {
skill + = u - > race - > at_bonus ;
} else {
skill + = u - > race - > df_bonus ;
}
2001-01-25 10:37:55 +01:00
} 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 ;
2002-04-14 11:53:26 +02:00
if ( skill > 0 ) {
if ( attacking ) {
skill + = u - > race - > at_bonus ;
} else {
skill + = u - > race - > df_bonus ;
}
}
2001-01-25 10:37:55 +01:00
if ( attacking ) {
skill + = wtype - > offmod ;
} else {
2002-10-01 18:35:57 +02:00
skill + = wtype - > defmod ;
2001-01-25 10:37:55 +01:00
}
}
return skill ;
}
static int
weapon_effskill ( troop t , troop enemy , const weapon * w , boolean attacking , boolean missile )
/* effektiver Waffenskill w<> hrend des Kampfes */
{
/* 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 ;
if ( wtype = = NULL ) {
/* Ohne Waffe: Waffenlose Angriffe */
skill = weapon_skill ( NULL , tu , attacking ) ;
} else {
if ( attacking ) {
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
skill = w - > attackskill ;
2001-01-25 10:37:55 +01:00
} else {
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
skill = w - > defenseskill ;
2001-01-25 10:37:55 +01:00
}
2004-06-11 21:59:02 +02:00
if ( wtype - > modifiers ! = NULL ) {
2001-01-25 10:37:55 +01:00
/* Pferdebonus, Lanzenbonus, usw. */
2001-02-09 14:53:53 +01:00
int m ;
2001-01-25 10:37:55 +01:00
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 ;
2004-06-11 21:59:02 +02:00
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 ;
}
2001-01-25 10:37:55 +01:00
}
}
}
2001-02-14 09:35:12 +01:00
/* Burgenbonus, Pferdebonus */
2001-01-25 10:37:55 +01:00
if ( riding ( t ) & & ( wtype = = NULL | | ! fval ( wtype , WTF_MISSILE ) ) ) {
2001-02-03 14:45:35 +01:00
skill + = 2 ;
2001-02-10 20:24:05 +01:00
if ( wtype ) skill = skillmod ( urace ( tu ) - > attribs , tu , tu - > region , wtype - > skill , skill , SMF_RIDING ) ;
2001-01-25 10:37:55 +01:00
}
if ( t . index < tf - > elvenhorses ) {
2001-02-14 09:35:12 +01:00
/* 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 . */
2001-01-25 10:37:55 +01:00
skill + = 2 ;
}
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 ;
}
static char
select_armor ( troop t )
{
armor_t a = 0 ;
int geschuetzt = 0 ;
/* Drachen benutzen keine R<> stungen */
2001-12-10 01:13:39 +01:00
if ( ! ( t . fighter - > unit - > race - > battle_flags & BF_EQUIPMENT ) )
2001-01-25 10:37:55 +01:00
return AR_NONE ;
2003-07-29 11:48:03 +02:00
2002-04-12 14:46:16 +02:00
/* ... und Werw<72> lfe auch nicht */
if ( fval ( t . fighter - > unit , UFL_WERE ) ) {
return AR_NONE ;
}
2001-01-25 10:37:55 +01:00
do {
if ( armordata [ a ] . shield = = 0 ) {
geschuetzt + = t . fighter - > armor [ a ] ;
if ( geschuetzt > t . index ) /* unser Kandidat wird geschuetzt */
return a ;
}
+ + a ;
}
while ( a ! = AR_MAX ) ;
return AR_NONE ;
}
static char
select_shield ( troop t )
{
armor_t a = 0 ;
int geschuetzt = 0 ;
/* Drachen benutzen keine R<> stungen */
2001-12-10 01:13:39 +01:00
if ( ! ( t . fighter - > unit - > race - > battle_flags & BF_EQUIPMENT ) )
2001-01-25 10:37:55 +01:00
return AR_NONE ;
do {
if ( armordata [ a ] . shield = = 1 ) {
geschuetzt + = t . fighter - > armor [ a ] ;
if ( geschuetzt > t . index ) /* unser Kandidat wird
* * * geschuetzt */
return a ;
}
+ + a ;
}
while ( a ! = AR_MAX ) ;
return AR_NONE ;
}
/* 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 )
{
unit * u = t . fighter - > unit ;
int geschuetzt = 0 ;
int ma = 0 ;
geschuetzt = min ( get_item ( u , I_TROLLBELT ) , u - > number ) ;
if ( geschuetzt > t . index ) /* unser Kandidat wird geschuetzt */
ma + = 1 ;
return ma ;
}
/* Sind side ds und Magier des meffect verb<72> ndet, dann return 1*/
boolean
meffect_protection ( battle * b , meffect * s , side * ds )
{
if ( ! s - > magician - > alive ) return false ;
if ( s - > duration < = 0 ) return false ;
if ( enemy ( s - > magician - > side , ds ) ) return false ;
if ( allysf ( s - > magician - > side , ds - > bf - > faction ) ) return true ;
return false ;
}
/* Sind side as und Magier des meffect verfeindet, dann return 1*/
boolean
meffect_blocked ( battle * b , meffect * s , side * as )
{
if ( ! s - > magician - > alive ) return false ;
if ( s - > duration < = 0 ) return false ;
if ( enemy ( s - > magician - > side , as ) ) return true ;
return false ;
}
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
}
2001-01-25 10:37:55 +01:00
void
rmtroop ( troop dt )
{
fighter * df = dt . fighter ;
2001-04-22 20:14:07 +02:00
/* troop ist immer eine einzele Person */
rmfighter ( df , 1 ) ;
2001-01-25 10:37:55 +01:00
assert ( dt . index > = 0 & & dt . index < df - > unit - > number ) ;
df - > person [ dt . index ] = df - > person [ df - > alive - df - > removed ] ;
df - > person [ df - > alive - df - > removed ] . hp = 0 ;
}
void
remove_troop ( troop dt )
{
2001-12-10 01:13:39 +01:00
fighter * df = dt . fighter ;
unit * du = df - > unit ;
2001-01-25 10:37:55 +01:00
rmtroop ( dt ) ;
2001-12-10 01:13:39 +01:00
if ( ! df - > alive & & du - > race - > itemdrop ) {
item * drops = du - > race - > itemdrop ( du - > race , du - > number - df - > run . number ) ;
2002-05-05 20:48:02 +02:00
if ( drops ! = NULL ) {
i_merge ( & du - > items , & drops ) ;
}
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
{
skill_t sk = ( skill_t ) ( rand ( ) % MAXSKILLS ) ;
skill_t ssk ;
ssk = sk ;
2002-02-15 17:13:30 +01:00
while ( get_level ( u , sk ) = = 0 ) {
2001-01-25 10:37:55 +01:00
sk + + ;
if ( sk = = MAXSKILLS )
sk = 0 ;
if ( sk = = ssk ) {
sk = NOSKILL ;
break ;
}
}
if ( sk ! = NOSKILL ) {
2002-02-16 11:37:18 +01:00
skill * sv = get_skill ( u , sk ) ;
while ( n > 0 ) {
if ( n > = 30 * u - > number ) {
2002-02-22 20:41:20 +01:00
reduce_skill ( u , sv , 1 ) ;
2002-02-16 11:37:18 +01:00
n - = 30 ;
} else {
2002-02-22 20:41:20 +01:00
if ( rand ( ) % ( 30 * u - > number ) < n ) reduce_skill ( u , sv , 1 ) ;
2002-02-16 11:37:18 +01:00
n = 0 ;
}
}
2001-01-25 10:37:55 +01:00
}
}
const char *
rel_dam ( int dam , int hp )
{
double q = ( double ) dam / ( double ) hp ;
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 " ;
}
boolean
terminate ( troop dt , troop at , int type , const char * damage , boolean missile )
{
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
char smallbuf [ 512 ] ;
# endif
2001-01-25 10:37:55 +01: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 ;
int faerie_level ;
char debugbuf [ 512 ] ;
double kritchance ;
/* Schild */
void * * si ;
side * ds = df - > side ;
int hp ;
int ar , an , am ;
int armor = select_armor ( dt ) ;
int shield = select_shield ( dt ) ;
2003-07-29 11:48:03 +02:00
2002-04-27 16:46:27 +02:00
const weapon_type * dwtype = NULL ;
const weapon_type * awtype = NULL ;
const weapon * weapon ;
2001-01-25 10:37:55 +01:00
int rda , sk = 0 , sd ;
boolean magic = false ;
2002-04-27 16:46:27 +02:00
int da = dice_rand ( damage ) ;
2001-01-25 10:37:55 +01:00
2002-04-27 16:46:27 +02:00
if ( fval ( au , UFL_WERE ) ) {
int level = fspecial ( du - > faction , FS_LYCANTROPE ) ;
da + = level ;
}
2001-01-25 10:37:55 +01:00
switch ( type ) {
case AT_STANDARD :
2002-11-03 12:56:43 +01:00
weapon = select_weapon ( at , true , missile ) ;
2001-01-25 10:37:55 +01:00
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 ;
ar = armordata [ armor ] . prot ;
ar + = armordata [ shield ] . prot ;
2002-04-27 16:46:27 +02:00
2001-01-25 10:37:55 +01:00
/* nat<61> rliche R<> stung */
2001-12-10 01:13:39 +01:00
an = du - > race - > armor ;
2002-04-27 16:46:27 +02:00
/* magische R<> stung durch Artefakte oder Spr<70> che */
/* Momentan nur Trollg<6C> rtel und Werwolf-Eigenschaft */
am = select_magicarmor ( dt ) ;
2002-04-12 14:46:16 +02:00
if ( fval ( du , UFL_WERE ) ) {
2002-04-27 16:46:27 +02:00
/* this counts as magical armor */
2002-04-12 14:46:16 +02:00
int level = fspecial ( du - > faction , FS_LYCANTROPE ) ;
2002-04-27 16:46:27 +02:00
am + = level ;
2002-04-12 14:46:16 +02:00
}
2002-04-27 16:46:27 +02:00
# if CHANGED_CROSSBOWS == 1
2002-05-05 10:06:19 +02:00
if ( awtype & & fval ( awtype , WTF_ARMORPIERCING ) ) {
2002-04-27 16:46:27 +02:00
/* crossbows */
ar / = 2 ;
an / = 2 ;
}
# endif
2001-01-25 10:37:55 +01:00
/* nat<61> rliche R<> stung ist halbkumulativ */
if ( ar > 0 ) {
ar + = an / 2 ;
} else {
ar = an ;
}
ar + = am ;
if ( type ! = AT_COMBATSPELL & & type ! = AT_SPELL ) /* Kein Zauber, normaler Waffenschaden */
{
kritchance = max ( ( sk * 3 - sd ) / 200.0 , 0.005 ) ;
while ( chance ( kritchance ) ) {
sprintf ( debugbuf ,
" %s/%d landet einen kritischen Treffer " , unitid ( au ) , at . index ) ;
battledebug ( debugbuf ) ;
da + = dice_rand ( damage ) ;
}
2001-12-10 01:13:39 +01:00
da + = rc_specialdamage ( au - > race , du - > race , awtype ) ;
2001-01-25 10:37:55 +01:00
da + = jihad ( au - > faction , du - > race ) ;
faerie_level = fspecial ( du - > faction , FS_FAERIE ) ;
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 ] . type = = R_IRON ) {
da + = faerie_level ;
break ;
}
}
}
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 ;
}
/* Skilldifferenzbonus */
da + = max ( 0 , sk - sd ) ;
}
if ( magic ) /* Magischer Schaden durch Spruch oder magische Waffe */
{
double res = 1.0 ;
/* magic_resistance gib x% Resistenzbonus zur<75> ck */
2004-02-09 23:20:40 +01:00
res - = magic_resistance ( du ) * 3.0 ;
2001-01-25 10:37:55 +01:00
2001-12-10 01:13:39 +01:00
if ( du - > race - > battle_flags & BF_EQUIPMENT ) {
2001-01-25 10:37:55 +01:00
# ifdef TODO_RUNESWORD
/* Runenschwert gibt im Kampf 80% Resistenzbonus */
if ( dwp = = WP_RUNESWORD ) res - = 0.80 ;
# endif
/* der Effekt von Laen steigt nicht linear */
if ( armor = = AR_EOGCHAIN ) res * = ( 1 - armordata [ armor ] . magres ) ;
if ( shield = = AR_EOGSHIELD ) res * = ( 1 - armordata [ shield ] . magres ) ;
if ( dwtype ) res * = ( 1 - dwtype - > magres ) ;
}
if ( res > 0 ) {
da = ( int ) ( max ( da * res , 0 ) ) ;
}
/* gegen Magie wirkt nur nat<61> rliche und magische R<> stung */
ar = an + am ;
}
rda = max ( da - ar , 0 ) ;
2001-12-10 01:13:39 +01:00
if ( ( du - > race - > battle_flags & BF_INV_NONMAGIC ) & & ! magic ) rda = 0 ;
2001-01-25 10:37:55 +01:00
else {
unsigned int i = 0 ;
2001-12-10 01:13:39 +01:00
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
if ( i & & awtype & & fval ( awtype , i ) ) rda / = 2 ;
/* Schilde */
for ( si = b - > meffects . begin ; si ! = b - > meffects . end ; + + si ) {
meffect * meffect = * si ;
if ( meffect_protection ( b , meffect , ds ) ! = 0 ) {
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 - - ;
}
}
}
}
sprintf ( debugbuf , " Verursacht %dTP, R<> stung %d: %d -> %d HP " ,
da , ar , df - > person [ dt . index ] . hp , df - > person [ dt . index ] . hp - rda ) ;
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
if ( rda > 0 ) {
sprintf ( smallbuf , " Der Treffer verursacht %s " ,
rel_dam ( rda , df - > person [ dt . index ] . hp ) ) ;
} else {
sprintf ( smallbuf , " Der Treffer verursacht keinen Schaden " ) ;
}
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
assert ( dt . index < du - > number ) ;
df - > person [ dt . index ] . hp - = rda ;
if ( df - > person [ dt . index ] . hp > 0 ) { /* Hat <20> berlebt */
battledebug ( debugbuf ) ;
2002-03-16 18:30:48 +01:00
if ( old_race ( au - > race ) = = RC_DAEMON ) {
2001-01-25 10:37:55 +01:00
# ifdef TODO_RUNESWORD
if ( select_weapon ( dt , 0 , - 1 ) = = WP_RUNESWORD ) continue ;
# endif
if ( ! ( df - > person [ dt . index ] . flags & FL_HERO ) ) {
df - > person [ dt . index ] . flags | = FL_DAZZLED ;
df - > person [ dt . index ] . defence - - ;
}
}
df - > person [ dt . index ] . flags = ( df - > person [ dt . index ] . flags & ~ FL_SLEEPING ) ;
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
strcat ( smallbuf , " . " ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
return false ;
}
# ifdef SHOW_KILLS
+ + at . fighter - > kills ;
# endif
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
if ( b - > small ) {
2001-01-25 10:37:55 +01:00
strcat ( smallbuf , " , die t<> dlich ist " ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
/* Sieben Leben */
2001-12-10 01:13:39 +01:00
if ( old_race ( du - > race ) = = RC_CAT & & ( chance ( 1.0 / 7 ) ) ) {
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
strcat ( smallbuf , " , doch die Katzeng<6E> ttin ist gn<67> dig " ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
assert ( dt . index > = 0 & & dt . index < du - > number ) ;
2001-01-25 10:37:55 +01:00
df - > person [ dt . index ] . hp = unit_max_hp ( du ) ;
return false ;
}
/* 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 ) ) ) {
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
strcat ( smallbuf , " , doch ein Heiltrank bringt Rettung " ) ;
battlerecord ( b , smallbuf ) ;
2004-04-20 00:52:36 +02:00
} else
# endif
{
message * m = msg_message ( " battle::potionsave " , " unit " , du ) ;
message_faction ( b , du - > faction , m ) ;
msg_release ( m ) ;
2001-01-25 10:37:55 +01:00
}
assert ( dt . index > = 0 & & dt . index < du - > number ) ;
2001-12-10 01:13:39 +01:00
df - > person [ dt . index ] . hp = du - > race - > hitpoints ;
2001-01-25 10:37:55 +01:00
return false ;
}
strcat ( debugbuf , " , tot " ) ;
battledebug ( debugbuf ) ;
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
strcat ( smallbuf , " . " ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01: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. */
if ( rand ( ) % 4 < 1 ) i_change ( pitm , itype , - 1 ) ;
}
}
remove_troop ( dt ) ;
return true ;
}
2004-04-18 23:44:24 +02:00
static int
count_side ( const side * s , int minrow , int maxrow )
2001-01-25 10:37:55 +01:00
{
2004-04-18 23:44:24 +02:00
void * * fi ;
int people = 0 ;
2004-05-28 23:31:11 +02:00
int unitrow [ NUMROWS ] ;
int i ;
for ( i = 0 ; i ! = NUMROWS ; + + i ) unitrow [ i ] = - 1 ;
2001-01-25 10:37:55 +01:00
2004-04-18 23:44:24 +02:00
for ( fi = s - > fighters . begin ; fi ! = s - > fighters . end ; + + fi ) {
const fighter * fig = * fi ;
int row ;
2002-01-20 12:03:50 +01:00
2004-04-18 23:44:24 +02:00
if ( fig - > alive - fig - > removed < = 0 ) continue ;
2004-05-28 23:31:11 +02:00
row = statusrow ( fig - > status ) ;
if ( unitrow [ row ] = = - 1 ) {
unitrow [ row ] = get_unitrow ( fig ) ;
}
row = unitrow [ row ] ;
2001-01-25 10:37:55 +01:00
2004-04-18 23:44:24 +02:00
if ( row > = minrow & & row < = maxrow ) {
people + = fig - > alive - fig - > removed ;
}
}
return people ;
}
/* new implementation of count_enemies ignores mask, since it was never used */
int
count_enemies ( battle * b , side * as , int minrow , int maxrow )
{
int i = 0 ;
void * * si ;
2001-01-25 10:37:55 +01:00
2004-04-18 23:44:24 +02:00
if ( maxrow < FIRST_ROW ) return 0 ;
2001-01-25 10:37:55 +01:00
2004-04-18 23:44:24 +02:00
for ( si = b - > sides . begin ; si ! = b - > sides . end ; + + si ) {
side * side = * si ;
if ( as = = NULL | | enemy ( side , as ) ) {
i + = count_side ( side , minrow , maxrow ) ;
}
}
return i ;
2001-01-25 10:37:55 +01:00
}
troop
2002-04-07 02:44:01 +02:00
select_enemy ( battle * b , fighter * af , int minrow , int maxrow )
2001-01-25 10:37:55 +01:00
{
2004-05-29 01:46:49 +02:00
side * as = af - > side ;
int si ;
2004-04-18 23:44:24 +02:00
int enemies ;
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 ) ;
enemies = count_enemies ( b , as , minrow , maxrow ) ;
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
2004-04-18 23:44:24 +02:00
enemies = rand ( ) % 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 ] ;
2004-04-18 23:44:24 +02:00
void * * fi ;
2004-05-29 01:46:49 +02:00
int ui , unitrow [ NUMROWS ] ;
for ( ui = 0 ; ui ! = NUMROWS ; + + ui ) unitrow [ ui ] = - 1 ;
2004-04-18 23:44:24 +02:00
for ( fi = ds - > fighters . begin ; fi ! = ds - > fighters . end ; + + fi ) {
fighter * df = * fi ;
2004-05-29 01:46:49 +02:00
int dr ;
2004-05-29 20:57:18 +02:00
ui = statusrow ( df - > status ) ;
2004-05-29 01:46:49 +02:00
if ( unitrow [ ui ] < 0 ) {
unitrow [ ui ] = get_unitrow ( df ) ;
}
dr = unitrow [ ui ] ;
2004-04-18 23:44:24 +02:00
if ( dr < minrow | | dr > maxrow ) continue ;
if ( df - > alive - df - > removed > enemies ) {
2004-05-31 20:21:54 +02:00
troop dt ;
2004-04-18 23:44:24 +02:00
dt . index = enemies ;
dt . fighter = df ;
2004-05-31 20:21:54 +02:00
return dt ;
2004-04-18 23:44:24 +02:00
}
else enemies - = ( df - > alive - df - > removed ) ;
}
}
assert ( ! enemies ) ;
2004-05-31 20:21:54 +02:00
return no_troop ;
}
static troop
select_opponent ( battle * b , troop at , int minrow , int maxrow )
{
fighter * af = at . fighter ;
troop dt = af - > person [ at . index ] . opponent ;
if ( af - > unit - > race - > flags & RCF_FLY ) {
/* flying races ignore min- and maxrow and can attack anyone fighting
* them */
minrow = FIGHT_ROW ;
maxrow = BEHIND_ROW ;
}
minrow = max ( minrow , FIGHT_ROW ) ;
if ( dt . fighter ! = NULL & & dt . index < dt . fighter - > alive ) {
fighter * df = dt . fighter ;
int row = get_unitrow ( df ) ;
if ( row > = minrow & & row < = maxrow ) {
troop ot = df - > person [ dt . index ] . opponent ;
if ( ot . fighter = = NULL | | ot . index > = ot . fighter - > alive ) {
df - > person [ dt . index ] . opponent = at ;
}
return dt ;
}
}
dt = select_enemy ( b , at . fighter , minrow , maxrow ) ;
if ( dt . fighter ! = NULL ) {
fighter * df = dt . fighter ;
troop ot = df - > person [ dt . index ] . opponent ;
if ( ot . fighter = = NULL | | ot . index > = ot . fighter - > alive ) {
df - > person [ dt . index ] . opponent = at ;
}
}
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 ;
*
* Optional : Verwirbeln . Vorsicht : Aufwendig !
* v_scramble ( fgs - > begin , fgs - > end ) ;
*
* for ( fig = fgs - > begin ; fig ! = fgs - > end ; + + fig ) {
* fighter * df = * fig ;
*
* }
*
* cv_kill ( fgs ) ; Nicht vergessen
*/
cvector *
fighters ( battle * b , fighter * af , int minrow , int maxrow , int mask )
{
2004-05-22 02:01:00 +02:00
fighter * fig ;
cvector * fightervp ;
int row ;
2001-01-25 10:37:55 +01:00
2004-05-22 02:01:00 +02:00
fightervp = malloc ( sizeof ( cvector ) ) ;
cv_init ( fightervp ) ;
cv_foreach ( fig , b - > fighters ) {
row = get_unitrow ( fig ) ;
if ( row > = minrow & & row < = maxrow ) {
switch ( mask ) {
case FS_ENEMY :
if ( enemy ( fig - > side , af - > side ) ) cv_pushback ( fightervp , fig ) ;
break ;
case FS_HELP :
if ( ! enemy ( fig - > side , af - > side ) & & allysf ( fig - > side , af - > side - > bf - > faction ) )
cv_pushback ( fightervp , fig ) ;
break ;
case FS_HELP | FS_ENEMY :
cv_pushback ( fightervp , fig ) ;
break ;
default :
assert ( 0 | | ! " Ung<EFBFBD> ltiger Allianzstatus in fighters() " ) ;
}
}
} cv_next ( fig ) ;
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
report_failed_spell ( battle * b , unit * mage , spell * sp )
{
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 )
{
void * * fi ;
spell * sp ;
region * r = b - > region ;
castorder * co ;
castorder * cll [ MAX_SPELLRANK ] ;
2004-02-09 22:12:46 +01:00
int level ;
2001-01-25 10:37:55 +01:00
int spellrank ;
int sl ;
for ( spellrank = 0 ; spellrank < MAX_SPELLRANK ; spellrank + + ) {
cll [ spellrank ] = ( castorder * ) NULL ;
}
for ( fi = b - > fighters . begin ; fi ! = b - > fighters . end ; + + fi ) {
2002-01-20 12:03:50 +01:00
fighter * fig = * fi ;
unit * mage = fig - > unit ;
int row = get_unitrow ( fig ) ;
2001-01-25 10:37:55 +01:00
2002-01-20 12:03:50 +01:00
if ( row > BEHIND_ROW ) continue ;
if ( fig - > alive < = 0 ) continue ; /* fighter kann im Kampf get<65> tet worden sein */
2001-04-29 20:23:40 +02:00
2002-01-20 12:03:50 +01:00
level = eff_skill ( mage , SK_MAGIC , r ) ;
if ( level > 0 ) {
2004-02-09 22:12:46 +01:00
double power ;
2002-05-01 21:08:32 +02:00
const struct locale * lang = mage - > faction - > locale ;
2002-01-20 12:03:50 +01:00
char cmd [ 128 ] ;
2001-04-29 20:23:40 +02:00
2002-01-20 12:03:50 +01:00
switch ( was ) {
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 ;
}
if ( sp = = NULL )
continue ;
2001-04-29 20:23:40 +02:00
2003-07-29 11:48:03 +02:00
snprintf ( cmd , 128 , " %s \" %s \" " ,
2002-05-01 21:08:32 +02:00
LOC ( lang , keywords [ K_CAST ] ) , spell_name ( sp , lang ) ) ;
2001-01-25 10:37:55 +01:00
2002-01-20 12:03:50 +01:00
if ( cancast ( mage , sp , 1 , 1 , cmd ) = = false )
continue ;
2001-01-25 10:37:55 +01:00
2002-01-20 12:03:50 +01:00
level = eff_spelllevel ( mage , sp , level , 1 ) ;
if ( sl > 0 ) level = min ( sl , level ) ;
if ( level < 0 ) {
2004-04-20 00:52:36 +02:00
report_failed_spell ( b , mage , sp ) ;
continue ;
2002-01-20 12:03:50 +01:00
}
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
2004-05-21 13:49:08 +02:00
power = spellpower ( r , mage , sp , level , cmd ) ;
2002-01-20 12:03:50 +01:00
if ( power < = 0 ) { /* Effekt von Antimagie */
2004-04-20 00:52:36 +02:00
report_failed_spell ( b , mage , sp ) ;
pay_spell ( mage , sp , level , 1 ) ;
continue ;
2002-01-20 12:03:50 +01:00
}
2001-01-25 10:37:55 +01:00
2002-01-20 12:03:50 +01:00
if ( fumble ( r , mage , sp , sp - > level ) = = true ) {
2004-04-20 00:52:36 +02:00
report_failed_spell ( b , mage , sp ) ;
pay_spell ( mage , sp , level , 1 ) ;
continue ;
2001-01-25 10:37:55 +01:00
}
2002-01-20 12:03:50 +01:00
co = new_castorder ( fig , 0 , sp , r , level , power , 0 , 0 , 0 ) ;
add_castorder ( & cll [ ( int ) ( sp - > rank ) ] , co ) ;
2001-01-25 10:37:55 +01:00
}
}
for ( spellrank = 0 ; spellrank < MAX_SPELLRANK ; spellrank + + ) {
for ( co = cll [ spellrank ] ; co ; co = co - > next ) {
2004-02-09 22:12:46 +01:00
fighter * fig = ( fighter * ) co - > magician ;
spell * sp = co - > sp ;
int level = co - > level ;
double power = co - > force ;
2001-01-25 10:37:55 +01:00
level = ( ( cspell_f ) sp - > sp_function ) ( fig , level , power , sp ) ;
if ( level > 0 ) {
pay_spell ( fig - > unit , sp , level , 1 ) ;
if ( was = = DO_PRECOMBATSPELL ) {
get_mage ( fig - > unit ) - > precombataura = level ;
}
}
}
}
for ( spellrank = 0 ; spellrank < MAX_SPELLRANK ; spellrank + + ) {
free_castorders ( cll [ spellrank ] ) ;
}
}
2002-01-20 12:03:50 +01:00
static void
do_combatspell ( troop at , int row )
2001-01-25 10:37:55 +01:00
{
2004-05-21 13:49:08 +02:00
spell * sp ;
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 ;
int sl ;
char cmd [ 128 ] ;
const struct locale * lang = mage - > faction - > locale ;
if ( row > BEHIND_ROW ) return ;
sp = get_combatspell ( mage , 1 ) ;
if ( sp = = NULL ) {
fi - > magic = 0 ; /* Hat keinen Kampfzauber, k<> mpft nichtmagisch weiter */
return ;
}
snprintf ( cmd , 128 , " %s \" %s \" " ,
LOC ( lang , keywords [ K_CAST ] ) , spell_name ( sp , lang ) ) ;
if ( cancast ( mage , sp , 1 , 1 , cmd ) = = false ) {
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 */
if ( rand ( ) % 100 < fumblechance ) {
report_failed_spell ( b , mage , sp ) ;
pay_spell ( mage , sp , level , 1 ) ;
return ;
}
power = spellpower ( r , mage , sp , level , cmd ) ;
if ( power < = 0 ) { /* Effekt von Antimagie */
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
level = ( ( cspell_f ) sp - > sp_function ) ( fi , level , power , sp ) ;
if ( level > 0 ) {
pay_spell ( mage , sp , level , 1 ) ;
at . fighter - > action_counter + + ;
}
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
{
spell * sp ;
fighter * fi = at . fighter ;
unit * au = fi - > unit ;
int power ;
2001-12-10 01:13:39 +01:00
sp = find_spellbyid ( ( spellid_t ) ( a - > data . iparam ) ) ;
2001-01-25 10:37:55 +01:00
/* nur bei Monstern k<> nnen mehrere 'Magier' in einer Einheit sein */
power = sp - > level * au - > number ;
( ( cspell_f ) sp - > sp_function ) ( fi , sp - > level , power , sp ) ;
}
static int
skilldiff ( troop at , troop dt , int dist )
{
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 ) ;
if ( df - > person [ dt . index ] . flags & FL_SLEEPING )
skdiff + = 2 ;
/* Effekte durch Rassen */
2001-12-10 01:13:39 +01:00
if ( awp ! = NULL & & au - > race = = new_race [ RC_HALFLING ] & & dragonrace ( du - > race ) ) {
2001-01-25 10:37:55 +01:00
skdiff + = 5 ;
2001-12-10 01:13:39 +01:00
}
2001-01-25 10:37:55 +01:00
2002-04-12 14:46:16 +02:00
/* Werwolf */
if ( fval ( au , UFL_WERE ) ) {
skdiff + = fspecial ( au - > faction , FS_LYCANTROPE ) ;
}
2001-12-10 01:13:39 +01:00
if ( old_race ( au - > race ) = = RC_GOBLIN & &
2001-01-25 10:37:55 +01:00
af - > side - > size [ SUM_ROW ] > = df - > side - > size [ SUM_ROW ] * 10 )
skdiff + = 1 ;
/* TODO this should be a skillmod */
skdiff + = jihad ( au - > faction , du - > race ) ;
skdiff + = af - > person [ at . index ] . attack ;
skdiff - = df - > person [ dt . index ] . defence ;
if ( df - > building ) {
2002-05-01 21:08:32 +02:00
boolean init = false ;
2002-05-11 20:12:25 +02:00
static const curse_type * strongwall_ct , * magicwalls_ct ;
2002-05-01 21:08:32 +02:00
if ( ! init ) {
strongwall_ct = ct_find ( " strongwall " ) ;
2002-05-11 20:12:25 +02:00
magicwalls_ct = ct_find ( " magicwalls " ) ;
2002-05-01 21:08:32 +02:00
init = true ;
}
2002-03-27 22:49:27 +01:00
if ( df - > building - > type - > flags & BTF_PROTECTION ) {
2001-01-25 10:37:55 +01:00
if ( fspecial ( au - > faction , FS_SAPPER ) ) {
/* Halbe Schutzwirkung, aufgerundet */
2001-12-10 01:13:39 +01:00
/* -1 because the tradepost has no protection value */
skdiff - = ( buildingeffsize ( df - > building , false ) - 1 + 1 ) / 2 ;
2001-01-25 10:37:55 +01:00
} else {
2001-12-10 01:13:39 +01:00
skdiff - = buildingeffsize ( df - > building , false ) - 1 ;
2001-01-25 10:37:55 +01:00
}
is_protected = 2 ;
}
2002-05-01 21:08:32 +02:00
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 ;
}
2001-01-25 10:37:55 +01:00
}
2002-05-11 20:12:25 +02:00
if ( magicwalls_ct & & curse_active ( get_curse ( df - > building - > attribs , magicwalls_ct ) ) ) {
2001-01-25 10:37:55 +01:00
/* Verdoppelt Burgenbonus */
skdiff - = buildingeffsize ( df - > building , false ) ;
}
}
2001-02-14 09:35:12 +01:00
/* Goblin-Verteidigung
* ist direkt in der Rassentabelle als df_default
*/
2001-01-25 10:37:55 +01:00
/* 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) */
2001-01-25 10:37:55 +01:00
skdiff - = awp - > type - > modifiers [ w ] . value ;
break ;
}
}
}
}
sk = weapon_effskill ( dt , at , dwp , false , dist > 1 ) ;
skdiff - = sk ;
return skdiff ;
}
static int
setreload ( troop at )
{
fighter * af = at . fighter ;
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
const weapon_type * wtype = af - > person [ at . index ] . missile - > type ;
2001-01-25 10:37:55 +01:00
if ( wtype - > reload = = 0 ) return 0 ;
return af - > person [ at . index ] . reload = wtype - > reload ;
}
int
getreload ( troop at )
{
return at . fighter - > person [ at . index ] . reload ;
}
2004-04-20 01:27:27 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
static char *
attack_message ( const troop at , const troop dt , const weapon * wp , int dist )
{
static char smallbuf [ 512 ] ;
char a_unit [ NAMESIZE + 8 ] , d_unit [ NAMESIZE + 8 ] ;
2004-06-11 21:59:02 +02:00
const char * noweap_string [ 4 ] = { " schl<EFBFBD> gt nach " ,
" tritt nach " ,
" bei<EFBFBD> t nach " ,
" kratzt nach " } ;
2001-01-25 10:37:55 +01:00
if ( at . fighter - > unit - > number > 1 )
sprintf ( a_unit , " %s/%d " , unitname ( at . fighter - > unit ) , at . index ) ;
else
sprintf ( a_unit , " %s " , unitname ( at . fighter - > unit ) ) ;
if ( dt . fighter - > unit - > number > 1 )
sprintf ( d_unit , " %s/%d " , unitname ( dt . fighter - > unit ) , dt . index ) ;
else
sprintf ( d_unit , " %s " , unitname ( dt . fighter - > unit ) ) ;
if ( wp = = NULL ) {
sprintf ( smallbuf , " %s %s %s " ,
a_unit , noweap_string [ rand ( ) % 4 ] , d_unit ) ;
return smallbuf ;
}
2002-03-16 15:13:22 +01:00
if ( dist > 1 | | wp - > type - > itype = = olditemtype [ I_CATAPULT ] ) {
2001-01-25 10:37:55 +01:00
sprintf ( smallbuf , " %s schie<69> t mit %s auf %s " ,
a_unit ,
2001-05-20 10:41:11 +02:00
locale_string ( default_locale , resourcename ( wp - > type - > itype - > rtype , GR_INDEFINITE_ARTICLE ) ) , d_unit ) ;
2002-03-16 15:13:22 +01:00
} else {
2001-01-25 10:37:55 +01:00
sprintf ( smallbuf , " %s schl<68> gt mit %s nach %s " ,
a_unit ,
2001-05-20 10:41:11 +02:00
locale_string ( default_locale , resourcename ( wp - > type - > itype - > rtype , GR_INDEFINITE_ARTICLE ) ) , d_unit ) ;
2002-03-16 15:13:22 +01:00
}
2001-01-25 10:37:55 +01:00
return smallbuf ;
}
2004-04-20 01:27:27 +02:00
# endif
2001-01-25 10:37:55 +01:00
int
hits ( troop at , troop dt , weapon * awp )
{
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
char * smallbuf = NULL ;
2001-01-25 10:37:55 +01:00
battle * b = at . fighter - > side - > battle ;
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
fighter * af = at . fighter , * df = dt . fighter ;
unit * au = af - > unit , * du = df - > unit ;
char debugbuf [ 512 ] ;
armor_t armor , shield ;
int skdiff = 0 ;
int dist = get_unitrow ( af ) + get_unitrow ( df ) - 1 ;
weapon * dwp = select_weapon ( dt , false , dist > 1 ) ;
if ( ! df - > alive ) return 0 ;
if ( getreload ( at ) ) return 0 ;
2002-01-20 14:29:11 +01:00
if ( dist > 1 & & ( awp = = NULL | | ! fval ( awp - > type , WTF_MISSILE ) ) ) return 0 ;
2001-01-25 10:37:55 +01: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 & & rand ( ) % 100 < 50 )
| | ( af - > person [ at . index ] . flags & FL_SLEEPING ) )
return 0 ;
if ( awp & & fval ( awp - > type , WTF_MISSILE )
& & af - > side - > battle - > reelarrow = = true
& & rand ( ) % 100 < 50 )
{
return 0 ;
}
skdiff = skilldiff ( at , dt , dist ) ;
/* Verteidiger bekommt eine R<> stung */
armor = select_armor ( dt ) ;
shield = select_shield ( dt ) ;
sprintf ( debugbuf , " %.4s/%d [%6s/%d] attackiert %.4s/%d [%6s/%d] mit %d dist %d " ,
unitid ( au ) , at . index ,
( awp ! = NULL ) ?
2001-05-20 10:41:11 +02:00
locale_string ( default_locale , resourcename ( awp - > type - > itype - > rtype , 0 ) ) : " unbewaffnet " ,
2001-01-25 10:37:55 +01:00
weapon_effskill ( at , dt , awp , true , dist > 1 ) ,
unitid ( du ) , dt . index ,
( dwp ! = NULL ) ?
2001-05-20 10:41:11 +02:00
locale_string ( default_locale , resourcename ( dwp - > type - > itype - > rtype , 0 ) ) : " unbewaffnet " ,
2004-06-11 21:59:02 +02:00
weapon_effskill ( dt , at , dwp , false , dist > 1 ) ,
2001-01-25 10:37:55 +01:00
skdiff , dist ) ;
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
smallbuf = attack_message ( at , dt , awp , dist ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
if ( contest ( skdiff , armor , shield ) ) {
strcat ( debugbuf , " und trifft. " ) ;
battledebug ( debugbuf ) ;
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
strcat ( smallbuf , " und trifft. " ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
# ifdef SHOW_KILLS
+ + at . fighter - > hits ;
# endif
return 1 ;
}
strcat ( debugbuf , " . " ) ;
battledebug ( debugbuf ) ;
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
strcat ( smallbuf , " . " ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
return 0 ;
}
void
dazzle ( battle * b , troop * td )
{
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
char smallbuf [ 512 ] ;
# endif
2001-12-10 01:13:39 +01:00
/* Nicht kumulativ ! */
if ( td - > fighter - > person [ td - > index ] . flags & FL_DAZZLED ) return ;
2001-01-25 10:37:55 +01:00
# ifdef TODO_RUNESWORD
if ( td - > fighter - > weapon [ WP_RUNESWORD ] . count > td - > index ) {
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
strcpy ( smallbuf , " Das Runenschwert gl<67> ht kurz auf. " ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
return ;
}
# endif
if ( td - > fighter - > person [ td - > index ] . flags & FL_HERO ) {
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
sprintf ( smallbuf , " Eine kurze Schw<68> che erfa<66> t %s/%d, vergeht jedoch "
" schnell wieder. " , unitname ( td - > fighter - > unit ) , td - > index ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
return ;
2001-01-25 10:37:55 +01:00
}
if ( td - > fighter - > person [ td - > index ] . flags & FL_DAZZLED ) {
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
sprintf ( smallbuf , " Eine kurze Schw<68> che erfa<66> t %s/%d, vergeht jedoch "
" schnell wieder. " , unitname ( td - > fighter - > unit ) , td - > index ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
return ;
}
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
2001-01-25 10:37:55 +01:00
if ( b - > small ) {
sprintf ( smallbuf , " %s/%d f<> hlt sich, als w<> rde Kraft entzogen. " ,
unitname ( td - > fighter - > unit ) , td - > index ) ;
battlerecord ( b , smallbuf ) ;
}
2004-04-20 00:52:36 +02:00
# endif
2001-01-25 10:37:55 +01:00
td - > fighter - > person [ td - > index ] . flags | = FL_DAZZLED ;
td - > fighter - > person [ td - > index ] . defence - - ;
}
/* 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 )
{
bldg - > size = max ( 1 , bldg - > size - damage_abs ) ;
/* Wenn Burg, dann gucken, ob die Leute alle noch in das Geb<65> ude passen. */
2002-03-27 22:49:27 +01:00
if ( bldg - > type - > flags & BTF_PROTECTION ) {
2001-01-25 10:37:55 +01:00
fighter * fi ;
bldg - > sizeleft = bldg - > size ;
2003-07-29 11:48:03 +02:00
cv_foreach ( fi , b - > fighters ) {
2001-01-25 10:37:55 +01:00
if ( fi - > building = = bldg ) {
if ( bldg - > sizeleft > = fi - > unit - > number ) {
fi - > building = bldg ;
bldg - > sizeleft - = fi - > unit - > number ;
} else {
fi - > building = NULL ;
}
}
2003-07-29 11:48:03 +02:00
} cv_next ( fi ) ;
2001-01-25 10:37:55 +01:00
}
}
static int
attacks_per_round ( troop t )
{
return t . fighter - > person [ t . index ] . speed ;
}
static void
2001-12-10 01:13:39 +01:00
attack ( battle * b , troop ta , const att * a )
2001-01-25 10:37:55 +01:00
{
fighter * af = ta . fighter ;
troop td ;
unit * au = af - > unit ;
2002-01-20 12:03:50 +01:00
int row = get_unitrow ( af ) ;
2002-03-03 15:21:07 +01:00
int offset = row - FIGHT_ROW ;
2001-01-25 10:37:55 +01:00
switch ( a - > type ) {
case AT_STANDARD : /* Waffen, mag. Gegenst<73> nde, Kampfzauber */
case AT_COMBATSPELL :
if ( af - > magic > 0 ) {
/* Magier versuchen immer erstmal zu zaubern, erst wenn das
* fehlschl <EFBFBD> gt , wird af - > magic = = 0 und der Magier k <EFBFBD> mpft
* konventionell weiter */
2002-01-20 12:03:50 +01:00
do_combatspell ( ta , row ) ;
2001-01-25 10:37:55 +01:00
} else {
2002-10-04 23:37:35 +02:00
weapon * wp = ta . fighter - > person [ ta . index ] . missile ;
if ( row = = FIGHT_ROW ) wp = preferred_weapon ( ta , true ) ;
2001-01-25 10:37:55 +01:00
/* Sonderbehandlungen */
if ( getreload ( ta ) ) {
ta . fighter - > person [ ta . index ] . reload - - ;
} else {
2001-02-03 14:45:35 +01:00
boolean standard_attack = true ;
2001-01-25 10:37:55 +01:00
if ( wp & & wp - > type - > attack ) {
2002-03-24 11:34:17 +01:00
int dead = 0 ;
2002-01-20 12:03:50 +01:00
standard_attack = wp - > type - > attack ( & ta , & dead , row ) ;
2001-02-03 14:45:35 +01:00
af - > catmsg + = dead ;
2001-04-01 08:58:45 +02:00
/* TODO: dies hier ist nicht richtig. wenn die katapulte/etc.
* keinen gegner gefunden haben , sollte es nicht erh <EFBFBD> ht werden .
2001-02-11 09:55:30 +01:00
* au <EFBFBD> erdem m <EFBFBD> sste allen gegenern der counter erh <EFBFBD> ht werden .
*/
if ( af - > person [ ta . index ] . last_action < b - > turn ) {
af - > person [ ta . index ] . last_action = b - > turn ;
af - > action_counter + + ;
}
2001-02-03 14:45:35 +01:00
}
if ( standard_attack ) {
2001-01-25 10:37:55 +01:00
boolean missile = false ;
if ( wp & & fval ( wp - > type , WTF_MISSILE ) ) missile = true ;
2002-03-03 15:21:07 +01:00
if ( missile ) {
2004-05-31 20:21:54 +02:00
if ( row < = BEHIND_ROW ) td = select_opponent ( b , ta , missile_range [ 0 ] , missile_range [ 1 ] ) ;
2002-03-03 15:21:07 +01:00
else return ;
}
else {
2004-05-31 20:21:54 +02:00
if ( row < = FIGHT_ROW ) td = select_opponent ( b , ta , melee_range [ 0 ] , melee_range [ 1 ] ) ;
2002-03-03 15:21:07 +01:00
else return ;
}
2001-01-25 10:37:55 +01:00
if ( ! td . fighter ) return ;
if ( td . fighter - > person [ td . index ] . last_action < b - > turn ) {
td . fighter - > person [ td . index ] . last_action = b - > turn ;
td . fighter - > action_counter + + ;
}
if ( ta . fighter - > person [ ta . index ] . last_action < b - > turn ) {
ta . fighter - > person [ ta . index ] . last_action = b - > turn ;
ta . fighter - > action_counter + + ;
}
2002-01-28 01:25:32 +01:00
if ( hits ( ta , td , wp ) ) {
2001-01-25 10:37:55 +01:00
const char * d ;
2001-12-10 01:13:39 +01:00
if ( wp = = NULL ) d = au - > race - > def_damage ;
2001-01-25 10:37:55 +01:00
else if ( riding ( ta ) ) d = wp - > type - > damage [ 1 ] ;
else d = wp - > type - > damage [ 0 ] ;
terminate ( td , ta , a - > type , d , missile ) ;
}
}
if ( wp & & wp - > type - > reload & & ! getreload ( ta ) ) {
int i = setreload ( ta ) ;
sprintf ( buf , " Nachladen gesetzt: %d " , i ) ;
battledebug ( buf ) ;
}
}
}
break ;
case AT_SPELL : /* Extra-Spr<70> che. Kampfzauber in AT_COMBATSPELL! */
do_extra_spell ( ta , a ) ;
break ;
case AT_NATURAL :
2004-05-31 20:21:54 +02:00
td = select_opponent ( b , ta , melee_range [ 0 ] - offset , melee_range [ 1 ] - offset ) ;
2001-01-25 10:37:55 +01:00
if ( ! td . fighter ) return ;
if ( td . fighter - > person [ td . index ] . last_action < b - > turn ) {
td . fighter - > person [ td . index ] . last_action = b - > turn ;
td . fighter - > action_counter + + ;
}
if ( ta . fighter - > person [ ta . index ] . last_action < b - > turn ) {
ta . fighter - > person [ ta . index ] . last_action = b - > turn ;
ta . fighter - > action_counter + + ;
}
if ( hits ( ta , td , NULL ) ) {
terminate ( td , ta , a - > type , a - > data . dice , false ) ;
}
break ;
case AT_DRAIN_ST :
2004-05-31 20:21:54 +02:00
td = select_opponent ( b , ta , melee_range [ 0 ] - offset , melee_range [ 1 ] - offset ) ;
2001-01-25 10:37:55 +01:00
if ( ! td . fighter ) return ;
if ( td . fighter - > person [ td . index ] . last_action < b - > turn ) {
td . fighter - > person [ td . index ] . last_action = b - > turn ;
td . fighter - > action_counter + + ;
}
if ( ta . fighter - > person [ ta . index ] . last_action < b - > turn ) {
ta . fighter - > person [ ta . index ] . last_action = b - > turn ;
ta . fighter - > action_counter + + ;
}
if ( hits ( ta , td , NULL ) ) {
int c = dice_rand ( a - > data . dice ) ;
while ( c > 0 ) {
if ( rand ( ) % 2 ) {
td . fighter - > person [ td . index ] . attack - = 1 ;
} else {
td . fighter - > person [ td . index ] . defence - = 1 ;
}
c - - ;
}
}
break ;
case AT_DRAIN_EXP :
2004-05-31 20:21:54 +02:00
td = select_opponent ( b , ta , melee_range [ 0 ] - offset , melee_range [ 1 ] - offset ) ;
2001-01-25 10:37:55 +01:00
if ( ! td . fighter ) return ;
if ( td . fighter - > person [ td . index ] . last_action < b - > turn ) {
td . fighter - > person [ td . index ] . last_action = b - > turn ;
td . fighter - > action_counter + + ;
}
if ( ta . fighter - > person [ ta . index ] . last_action < b - > turn ) {
ta . fighter - > person [ ta . index ] . last_action = b - > turn ;
ta . fighter - > action_counter + + ;
}
if ( hits ( ta , td , NULL ) ) {
drain_exp ( td . fighter - > unit , dice_rand ( a - > data . dice ) ) ;
}
break ;
case AT_DAZZLE :
2004-05-31 20:21:54 +02:00
td = select_opponent ( b , ta , melee_range [ 0 ] - offset , melee_range [ 1 ] - offset ) ;
2001-01-25 10:37:55 +01:00
if ( ! td . fighter ) return ;
if ( td . fighter - > person [ td . index ] . last_action < b - > turn ) {
td . fighter - > person [ td . index ] . last_action = b - > turn ;
td . fighter - > action_counter + + ;
}
if ( ta . fighter - > person [ ta . index ] . last_action < b - > turn ) {
ta . fighter - > person [ ta . index ] . last_action = b - > turn ;
ta . fighter - > action_counter + + ;
}
if ( hits ( ta , td , NULL ) ) {
dazzle ( b , & td ) ;
}
break ;
case AT_STRUCTURAL :
2004-05-31 20:21:54 +02:00
td = select_opponent ( b , ta , melee_range [ 0 ] - offset , melee_range [ 1 ] - offset ) ;
2001-01-25 10:37:55 +01:00
if ( ! td . fighter ) return ;
if ( ta . fighter - > person [ ta . index ] . last_action < b - > turn ) {
ta . fighter - > person [ ta . index ] . last_action = b - > turn ;
ta . fighter - > action_counter + + ;
}
if ( td . fighter - > unit - > ship ) {
2004-06-13 12:21:48 +02:00
if ( a_find ( td . fighter - > unit - > ship - > attribs , & at_nodestroy ) = = NULL ) {
td . fighter - > unit - > ship - > damage + = DAMAGE_SCALE * dice_rand ( a - > data . dice ) ;
}
2001-01-25 10:37:55 +01:00
} else if ( td . fighter - > unit - > building ) {
2004-06-13 12:21:48 +02:00
if ( a_find ( td . fighter - > unit - > building - > attribs , & at_nodestroy ) = = NULL ) {
damage_building ( b , td . fighter - > unit - > building ,
dice_rand ( a - > data . dice ) ) ;
}
2001-01-25 10:37:55 +01:00
}
}
/* Der letzte Katapultsch<63> tze setzt die
* Ladezeit neu und generiert die Meldung . */
if ( af - > catmsg > = 0 & & ta . index = = 0 ) {
sprintf ( buf , " %d Opfer wurde%s get<65> tet. " ,
af - > catmsg , af - > catmsg < = 1 ? " " : " n " ) ;
battlerecord ( b , buf ) ;
af - > catmsg = - 1 ;
}
}
void
do_attack ( fighter * af )
{
troop ta ;
unit * au = af - > unit ;
side * side = af - > side ;
battle * b = side - > battle ;
int apr ;
int a ;
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-04-18 23:44:24 +02:00
int enemies = count_enemies ( b , af - > side , FIGHT_ROW , LAST_ROW ) ;
2001-01-25 10:37:55 +01:00
if ( ! enemies ) break ;
for ( apr = attacks_per_round ( ta ) ; apr > 0 ; apr - - ) {
2004-05-31 20:21:54 +02:00
for ( a = 0 ; a ! = 10 ; + + a ) {
2001-12-10 01:13:39 +01:00
if ( au - > race - > attack [ a ] . type ! = AT_NONE )
attack ( b , ta , & ( au - > race - > attack [ a ] ) ) ;
2001-01-25 10:37:55 +01:00
}
}
}
}
void
do_regenerate ( fighter * af )
{
troop ta ;
unit * au = af - > unit ;
ta . fighter = af ;
ta . index = af - > fighting ;
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 ) ;
}
}
static void
add_tactics ( tactics * ta , fighter * fig , int value )
{
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 ;
}
double
fleechance ( unit * u )
{
double c = 0.20 ; /* Fluchtwahrscheinlichkeit in % */
2002-01-01 21:51:18 +01:00
region * r = u - > region ;
attrib * a = a_find ( u - > attribs , & at_fleechance ) ;
2001-01-25 10:37:55 +01:00
/* Einheit u versucht, dem Get<65> mmel zu entkommen */
c + = ( eff_skill ( u , SK_STEALTH , r ) * 0.05 ) ;
if ( get_item ( u , I_UNICORN ) > = u - > number & & eff_skill ( u , SK_RIDING , r ) > = 5 )
c + = 0.30 ;
else if ( get_item ( u , I_HORSE ) > = u - > number & & eff_skill ( u , SK_RIDING , r ) > = 1 )
c + = 0.10 ;
2001-12-10 01:13:39 +01:00
if ( old_race ( u - > race ) = = RC_HALFLING ) {
2001-01-25 10:37:55 +01:00
c + = 0.20 ;
c = min ( c , 0.90 ) ;
} else {
c = min ( c , 0.75 ) ;
}
2002-01-01 21:51:18 +01:00
if ( a ! = NULL ) c + = a - > data . flt ;
2001-01-25 10:37:55 +01:00
return c ;
}
int nextside = 0 ;
side *
2001-12-10 01:13:39 +01:00
make_side ( battle * b , const faction * f , const group * g , boolean stealth , const faction * stealthfaction )
2001-01-25 10:37:55 +01:00
{
side * s1 = calloc ( sizeof ( struct side ) , 1 ) ;
bfaction * bf ;
s1 - > battle = b ;
s1 - > group = g ;
s1 - > stealth = stealth ;
2001-12-10 01:13:39 +01:00
s1 - > stealthfaction = stealthfaction ;
2001-01-25 10:37:55 +01:00
cv_pushback ( & b - > sides , s1 ) ;
for ( bf = b - > factions ; bf ; bf = bf - > next ) {
faction * f2 = bf - > faction ;
if ( f2 = = f ) {
s1 - > bf = bf ;
s1 - > index = nextside + + ;
s1 - > nextF = bf - > sides ;
bf - > sides = s1 ;
break ;
}
}
assert ( bf ) ;
return s1 ;
}
void
loot_items ( fighter * corpse )
{
unit * u = corpse - > unit ;
item * itm = u - > items ;
2002-04-07 02:44:01 +02:00
battle * b = corpse - > side - > battle ;
2001-01-25 10:37:55 +01:00
u - > items = NULL ;
while ( itm ) {
int i ;
2001-03-04 19:41:27 +01:00
if ( itm - > number ) {
for ( i = 10 ; i ! = 0 ; i - - ) {
int loot = itm - > number / i ;
itm - > number - = loot ;
/* Looten tun hier immer nur die Gegner. Das
* ist als Ausgleich f <EFBFBD> r die neue Loot - regel
* ( nur ganz tote Einheiten ) fair .
* zus <EFBFBD> tzlich looten auch geflohene , aber
* nach anderen Regeln .
*/
if ( loot > 0 & & ( itm - > type - > flags & ( ITF_CURSED | ITF_NOTLOST )
| | rand ( ) % 100 > = 50 - corpse - > side - > battle - > keeploot ) ) {
2002-04-07 02:44:01 +02:00
fighter * fig = select_enemy ( b , corpse , FIGHT_ROW , LAST_ROW ) . fighter ;
2001-03-04 19:41:27 +01: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 ;
2001-01-25 10:37:55 +01:00
}
}
}
}
2001-03-04 19:41:27 +01:00
itm = itm - > next ;
2001-01-25 10:37:55 +01:00
}
}
2003-03-08 21:57:38 +01:00
# ifndef NO_RUNNING
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
{
/* 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 )
{
2001-12-10 01:13:39 +01:00
i_merge ( & u - > items , & fig - > run . items ) ;
2001-04-01 08:58:45 +02:00
}
2003-03-08 21:57:38 +01:00
# endif
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 )
{
if ( f = = s - > bf - > faction ) return true ;
if ( s - > stealth ) return false ;
return true ;
}
static void
aftermath ( battle * b )
{
2004-04-19 00:30:14 +02:00
int i ;
region * r = b - > region ;
ship * sh ;
side * s ;
cvector * fighters = & b - > fighters ;
void * * fi ;
int is = 0 ;
bfaction * bf ;
int dead_peasants ;
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
2004-04-19 00:30:14 +02:00
for ( fi = fighters - > begin ; fi ! = fighters - > end ; + + fi ) {
fighter * df = * fi ;
unit * du = df - > unit ;
2004-05-20 00:59:08 +02:00
int dead = du - > number - df - > alive - df - > run . number ;
2004-04-19 00:30:14 +02:00
const attrib * a ;
int pr_mercy = 0 ;
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
for ( a = a_find ( du - > attribs , & at_prayer_effect ) ; a ; a = a - > nexttype ) {
if ( a - > data . sa [ 0 ] = = PR_MERCY ) {
pr_mercy = a - > data . sa [ 1 ] ;
}
}
2001-01-25 10:37:55 +01:00
# ifdef TROLLSAVE
2004-04-19 00:30:14 +02:00
/* Trolle k<> nnen regenerieren */
2004-05-20 09:34:02 +02:00
if ( df - > alive > 0 & & dead > 0 & & old_race ( du - > race ) = = RC_TROLL ) {
2004-04-19 00:30:14 +02:00
for ( i = 0 ; i ! = dead ; + + i ) {
if ( chance ( TROLL_REGENERATION ) ) {
+ + df - > alive ;
+ + df - > side - > alive ;
+ + df - > side - > battle - > alive ;
2004-05-20 00:59:08 +02:00
+ + trollsave [ df - > side - > index ] ;
2004-05-20 09:34:02 +02:00
/* do not change dead here, or loop will not terminate! recalculate later */
2004-04-19 00:30:14 +02:00
}
}
2004-05-20 09:34:02 +02:00
dead = du - > number - df - > alive - df - > run . number ;
2004-05-20 00:59:08 +02:00
}
2001-01-25 10:37:55 +01:00
# endif
2004-05-20 00:59:08 +02:00
/* Regeneration durch PR_MERCY */
if ( dead > 0 & & pr_mercy ) {
for ( i = 0 ; i ! = dead ; + + i ) {
if ( rand ( ) % 100 < pr_mercy ) {
+ + df - > alive ;
+ + df - > side - > alive ;
+ + df - > side - > battle - > alive ;
2004-05-20 09:34:02 +02:00
/* do not change dead here, or loop will not terminate! recalculate later */
2004-05-20 00:59:08 +02:00
}
}
2004-05-20 09:34:02 +02:00
dead = du - > number - df - > alive - df - > run . number ;
2004-05-20 00:59:08 +02:00
}
2001-01-25 10:37:55 +01:00
2004-05-20 09:34:02 +02:00
/* tote insgesamt: */
df - > side - > dead + = dead ;
/* Tote, die wiederbelebt werde k<> nnen: */
2004-05-20 00:59:08 +02:00
if ( playerrace ( df - > unit - > race ) ) {
df - > side - > casualties + = dead ;
}
2001-01-25 10:37:55 +01:00
# ifdef SHOW_KILLS
2004-05-20 00:59:08 +02:00
if ( df - > hits + df - > kills ) {
2004-05-20 09:34:02 +02:00
struct message * m = msg_message ( " killsandhits " , " unit hits kills " , du , df - > hits , df - > kills ) ;
2004-05-20 00:59:08 +02:00
message_faction ( b , du - > faction , m ) ;
2004-05-20 09:34:02 +02:00
msg_release ( m ) ;
2004-05-20 00:59:08 +02:00
}
2001-01-25 10:37:55 +01:00
# endif
2004-04-19 00:30:14 +02:00
}
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
/* Wenn die Schlacht kurz war, dann gib Aura f<> r den Pr<50> combatzauber
* zur <EFBFBD> ck . Nicht logisch , aber die einzige L <EFBFBD> sung , den Verlust der
* Aura durch Dummy - Angriffe zu verhindern . */
cv_foreach ( s , b - > sides ) {
if ( s - > bf - > lastturn + ( b - > has_tactics_turn ? 1 : 0 ) < = 1 ) continue ;
/* Pr<50> fung, ob faction angegriffen hat. Geht nur <20> ber die Faction */
if ( ! s - > bf - > attacker ) {
fighter * fig ;
cv_foreach ( fig , s - > fighters ) {
sc_mage * mage = get_mage ( fig - > unit ) ;
if ( mage )
mage - > spellpoints + = mage - > precombataura ;
} cv_next ( fig ) ;
}
/* Alle Fighter durchgehen, Mages suchen, Precombataura zur<75> ck */
} cv_next ( s ) ;
2004-05-21 02:49:18 +02:00
/* validate_sides(b); */
2004-04-19 00:30:14 +02:00
/* POSTCOMBAT */
do_combatmagic ( b , DO_POSTCOMBATSPELL ) ;
cv_foreach ( s , b - > sides ) {
int snumber = 0 ;
fighter * df ;
boolean relevant = false ; /* Kampf relevant f<> r dieses Heer? */
if ( s - > bf - > lastturn + ( b - > has_tactics_turn ? 1 : 0 ) > 1 ) {
relevant = true ;
}
s - > flee = 0 ;
cv_foreach ( df , s - > fighters ) {
unit * du = df - > unit ;
int dead = du - > number - df - > alive - df - > run . number ;
int sum_hp = 0 ;
int n ;
2004-05-20 00:59:08 +02:00
snumber + = du - > number ;
2004-04-19 00:30:14 +02:00
if ( relevant & & df - > action_counter > = du - > number ) {
ship * sh = du - > ship ? du - > ship : leftship ( du ) ;
if ( sh ) fset ( sh , SF_DAMAGED ) ;
fset ( du , UFL_LONGACTION ) ;
/* TODO: das sollte hier weg sobald anderswo <20> b
* erall UFL_LONGACTION getestet wird . */
set_string ( & du - > thisorder , " " ) ;
}
for ( n = 0 ; n ! = df - > alive ; + + n ) {
if ( df - > person [ n ] . hp > 0 )
sum_hp + = df - > person [ n ] . hp ;
}
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
if ( df - > alive = = du - > number ) continue ; /* nichts passiert */
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
/* die weggerannten werden sp<73> ter subtrahiert! */
assert ( du - > number > = 0 ) ;
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
if ( df - > run . hp ) {
2003-03-08 21:57:38 +01:00
# ifndef NO_RUNNING
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 */
if ( fval ( df , FIG_NOLOOT ) ) {
merge_fleeloot ( df , du ) ;
} else {
loot_items ( df ) ;
loot_fleeing ( df , du ) ;
}
scale_number ( du , df - > run . number ) ;
du - > hp = df - > run . hp ;
set_string ( & du - > thisorder , " " ) ;
setguard ( du , GUARD_NONE ) ;
2004-05-30 03:46:25 +02:00
fset ( du , UFL_LONGACTION ) ;
2004-04-19 00:30:14 +02:00
leave ( du - > region , du ) ;
if ( df - > run . region ) {
travel ( du , df - > run . region , 1 , NULL ) ;
df - > run . region = du - > region ;
}
} else
2003-03-08 21:57:38 +01:00
# endif
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 ;
2003-03-08 21:57:38 +01:00
# ifndef NO_RUNNING
2004-04-19 00:30:14 +02:00
merge_fleeloot ( df , du ) ;
2003-03-08 21:57:38 +01:00
# endif
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 ;
2003-03-08 21:57:38 +01:00
# ifndef NO_RUNNING
2004-04-19 00:30:14 +02:00
df - > run . region = NULL ;
2003-03-08 21:57:38 +01:00
# endif
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
setguard ( du , GUARD_NONE ) ;
scale_number ( du , 0 ) ;
/* Distribute Loot */
loot_items ( df ) ;
} 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 */
is + = dead ;
}
if ( du - > hp < du - > number ) {
log_error ( ( " %s has less hitpoints (%u) than people (%u) \n " ,
itoa36 ( du - > no ) , du - > hp , du - > number ) ) ;
du - > hp = du - > no ;
}
} cv_next ( df ) ;
s - > alive + = s - > healed ;
assert ( snumber = = s - > flee + s - > alive + s - > dead ) ;
} cv_next ( s ) ;
dead_peasants = min ( rpeasants ( r ) , ( is * BATTLE_KILLS_PEASANTS ) / 100 ) ;
deathcounts ( r , dead_peasants + is ) ;
chaoscounts ( r , dead_peasants / 2 ) ;
rsetpeasants ( r , rpeasants ( r ) - dead_peasants ) ;
2004-04-22 00:09:39 +02:00
cv_foreach ( s , b - > sides ) {
message * seen = msg_message ( " battle::army_report " ,
" index abbrev dead flown survived " ,
s - > index , gc_add ( strdup ( sideabkz ( s , false ) ) ) , s - > dead , s - > flee , s - > alive ) ;
message * unseen = msg_message ( " battle::army_report " ,
" index abbrev dead flown survived " ,
s - > index , " -?- " , s - > dead , s - > flee , s - > alive ) ;
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 ) ;
} cv_next ( s ) ;
2004-04-19 00:30:14 +02: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 */
for ( fi = fighters - > begin ; fi ! = fighters - > end ; + + fi ) {
fighter * df = * fi ;
unit * du = df - > unit ;
item * l ;
for ( l = df - > loot ; l ; l = l - > next ) {
const item_type * itype = l - > type ;
sprintf ( buf , " %s erbeute%s %d %s. " , unitname ( du ) , du - > number = = 1 ? " t " : " n " ,
l - > number , locale_string ( default_locale , resourcename ( itype - > rtype , l - > number ! = 1 ) ) ) ;
2004-04-20 00:52:36 +02:00
fbattlerecord ( b , du - > faction , buf ) ;
2004-04-19 00:30:14 +02:00
i_change ( & du - > items , itype , l - > number ) ;
}
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
/* Wenn sich die Einheit auf einem Schiff befindet, wird
* dieses Schiff besch <EFBFBD> digt . Andernfalls ein Schiff , welches
* evt . zuvor verlassen wurde . */
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
if ( du - > ship ) sh = du - > ship ; else sh = leftship ( du ) ;
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
if ( sh & & fval ( sh , SF_DAMAGED ) & & b - > turn + ( b - > has_tactics_turn ? 1 : 0 ) > 2 ) {
damage_ship ( sh , 0.20 ) ;
freset ( sh , SF_DAMAGED ) ;
}
}
2001-01-25 10:37:55 +01:00
2004-04-19 00:30:14 +02:00
if ( battle_was_relevant ) {
ship * * sp = & r - > ships ;
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
2004-04-19 00:30:14 +02:00
sprintf ( buf , " The battle lasted %d turns, %s and %s. \n " ,
b - > turn ,
b - > has_tactics_turn = = true ? " had a tactic turn " : " had no tactic turn " ,
battle_was_relevant = = true ? " was relevant " : " was not relevant. " ) ;
battledebug ( buf ) ;
2001-01-25 10:37:55 +01:00
}
static void
battle_punit ( unit * u , battle * b )
{
bfaction * bf ;
strlist * S , * x ;
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 ) {
2004-04-20 00:52:36 +02:00
fbattlerecord ( b , f , x - > s ) ;
2001-01-25 10:37:55 +01:00
if ( u - > faction = = f )
battledebug ( x - > s ) ;
}
if ( S )
freestrlist ( S ) ;
}
}
static void
print_fighters ( battle * b , cvector * fighters )
{
2004-04-20 00:52:36 +02:00
fighter * df ;
int lastrow = - 1 ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
cv_foreach ( df , * fighters ) {
unit * du = df - > unit ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
int row = get_unitrow ( df ) ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
if ( row ! = lastrow ) {
message * m = msg_message ( " battle::row_header " , " row " , row ) ;
message_all ( b , m ) ;
msg_release ( m ) ;
lastrow = row ;
}
battle_punit ( du , b ) ;
}
cv_next ( df ) ;
2001-01-25 10:37:55 +01:00
}
static void
print_header ( battle * b )
{
2004-05-04 21:24:03 +02:00
bfaction * bf ;
void * * fi ;
cvector * fighters = & b - > fighters ;
boolean * seen = malloc ( sizeof ( boolean ) * cv_size ( & b - > sides ) ) ;
for ( bf = b - > factions ; bf ; bf = bf - > next ) {
faction * f = bf - > faction ;
const char * lastf = NULL ;
boolean first = false ;
strcpy ( buf , " Der Kampf wurde ausgel<65> st von " ) ;
memset ( seen , 0 , sizeof ( boolean ) * cv_size ( & b - > sides ) ) ;
for ( fi = fighters - > begin ; fi ! = fighters - > end ; + + fi ) {
fighter * df = * fi ;
if ( ! fval ( df , FIG_ATTACKED ) ) continue ;
if ( ! seen [ df - > side - > index ] ) {
if ( first ) strcat ( buf , " , " ) ;
if ( lastf ) {
strcat ( buf , lastf ) ;
first = true ;
}
if ( seematrix ( f , df - > side ) = = true )
lastf = sidename ( df - > side , false ) ;
else
lastf = " einer unbekannten Partei " ;
seen [ df - > side - > index ] = true ;
}
}
if ( first ) strcat ( buf , " und " ) ;
if ( lastf ) strcat ( buf , lastf ) ;
strcat ( buf , " . " ) ;
fbattlerecord ( b , f , buf ) ;
}
free ( seen ) ;
2001-01-25 10:37:55 +01:00
}
static void
print_stats ( battle * b )
{
2004-04-20 00:52:36 +02:00
side * s2 ;
side * side ;
int i = 0 ;
cv_foreach ( side , b - > sides ) {
bfaction * bf ;
char * k ;
boolean komma ;
+ + i ;
for ( bf = b - > factions ; bf ; bf = bf - > next ) {
faction * f = bf - > faction ;
2004-04-22 00:09:39 +02:00
const char * loc_army = LOC ( f - > locale , " battle_army " ) ;
2004-04-20 00:52:36 +02:00
fbattlerecord ( b , f , " " ) ;
2004-04-22 00:09:39 +02:00
sprintf ( buf , " %s %d: %s " , loc_army , side - > index ,
2004-04-20 00:52:36 +02:00
seematrix ( f , side )
? sidename ( side , false ) : LOC ( f - > locale , " unknown_faction " ) ) ;
fbattlerecord ( b , f , buf ) ;
strcpy ( buf , LOC ( f - > locale , " battle_opponents " ) ) ;
komma = false ;
cv_foreach ( s2 , b - > sides ) {
2004-04-22 00:09:39 +02:00
if ( enemy ( s2 , side ) ) {
const char * abbrev = seematrix ( f , s2 ) ? sideabkz ( s2 , false ) : " -?- " ;
sprintf ( buf , " %s%s %s %d(%s) " , buf , komma + + ? " , " : " " , loc_army ,
s2 - > index , abbrev ) ;
2004-04-20 00:52:36 +02:00
}
}
cv_next ( s2 ) ;
fbattlerecord ( b , f , buf ) ;
2004-04-22 00:09:39 +02:00
strcpy ( buf , LOC ( f - > locale , " battle_attack " ) ) ;
2004-04-20 00:52:36 +02:00
komma = false ;
cv_foreach ( s2 , b - > sides ) {
if ( side - > enemy [ s2 - > index ] & E_ATTACKING ) {
2004-04-22 00:09:39 +02:00
const char * abbrev = seematrix ( f , s2 ) ? sideabkz ( s2 , false ) : " -?- " ;
sprintf ( buf , " %s%s %s %d(%s) " , buf , komma + + ? " , " : " " , loc_army ,
s2 - > index , abbrev ) ;
2004-04-20 00:52:36 +02:00
}
}
cv_next ( s2 ) ;
fbattlerecord ( b , f , buf ) ;
}
buf [ 77 ] = ( char ) 0 ;
for ( k = buf ; * k ; + + k ) * k = ' - ' ;
battlerecord ( b , buf ) ;
if ( side - > bf - > faction ) {
2002-11-30 22:06:27 +01:00
# ifdef ALLIANCES
2004-04-20 00:52:36 +02:00
sprintf ( buf , " ##### %s (%s/%d) " , side - > bf - > faction - > name , itoa36 ( side - > bf - > faction - > no ) ,
side - > bf - > faction - > alliance ? side - > bf - > faction - > alliance - > id : 0 ) ;
2002-11-30 22:06:27 +01:00
# else
2004-04-20 00:52:36 +02:00
sprintf ( buf , " ##### %s (%s) " , side - > bf - > faction - > name , itoa36 ( side - > bf - > faction - > no ) ) ;
2002-11-30 22:06:27 +01:00
# endif
2004-04-20 00:52:36 +02:00
battledebug ( buf ) ;
}
print_fighters ( b , & side - > fighters ) ;
}
cv_next ( side ) ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
battlerecord ( b , " " ) ;
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
2004-04-20 00:52:36 +02:00
cv_foreach ( side , b - > sides ) {
if ( cv_size ( & side - > leader . fighters ) )
b - > max_tactics = max ( b - > max_tactics , side - > leader . value ) ;
} cv_next ( side ) ;
if ( b - > max_tactics > 0 ) {
cv_foreach ( side , b - > sides ) {
if ( side - > leader . value = = b - > max_tactics ) {
fighter * tf ;
cv_foreach ( tf , side - > leader . fighters ) {
unit * u = tf - > unit ;
message * m = NULL ;
if ( ! fval ( tf , FIG_ATTACKED ) ) {
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 ) ;
}
} cv_next ( side ) ;
}
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 )
{
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
{
# define WMAX 16
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 ) ;
2004-02-09 22:12:46 +01:00
side * s2 ;
2001-01-25 10:37:55 +01:00
int h ;
int berserk ;
int strongmen ;
2002-04-28 17:08:28 +02:00
int speeded = 0 , speed = 1 ;
2001-01-25 10:37:55 +01:00
boolean pr_aid = false ;
2003-07-29 11:48:03 +02:00
boolean stealth = ( boolean ) ( ( fval ( u , UFL_PARTEITARNUNG ) ! = 0 ) ? true : false ) ;
2001-01-25 10:37:55 +01:00
int rest ;
const attrib * a = a_find ( u - > attribs , & at_group ) ;
const group * g = a ? ( const group * ) a - > data . v : NULL ;
2001-12-10 01:13:39 +01:00
const attrib * a2 = a_find ( u - > attribs , & at_otherfaction ) ;
2002-03-24 10:40:50 +01:00
const faction * stealthfaction = a2 ? get_otherfaction ( a2 ) : NULL ;
2001-12-10 01:13:39 +01:00
2001-01-25 10:37:55 +01:00
/* Illusionen und Zauber kaempfen nicht */
2001-12-10 01:13:39 +01:00
if ( fval ( u - > race , RCF_ILLUSIONARY ) | | idle ( u - > faction ) )
2001-01-25 10:37:55 +01:00
return NULL ;
2004-02-09 22:12:46 +01:00
if ( s1 = = NULL ) {
cv_foreach ( s2 , b - > sides ) {
if ( s2 - > bf - > faction = = u - > faction
& & s2 - > stealth = = stealth
& & s2 - > stealthfaction = = stealthfaction
) {
if ( s2 - > group = = g ) {
s1 = s2 ;
break ;
}
}
} cv_next ( s2 ) ;
/* aliances are moved out of make_fighter and will be handled later */
if ( ! s1 ) s1 = make_side ( b , u - > faction , g , stealth , stealthfaction ) ;
/* 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 ) */
}
2001-01-25 10:37:55 +01:00
fig = calloc ( 1 , sizeof ( struct fighter ) ) ;
cv_pushback ( & s1 - > fighters , fig ) ;
cv_pushback ( & b - > fighters , fig ) ;
fig - > unit = u ;
/* In einer Burg mu<6D> man a) nicht Angreifer sein, und b) drin sein, und
* c ) noch Platz finden . d ) menschlich sein */
if ( attack ) fset ( fig , FIG_ATTACKED ) ;
if ( ( ! attack ) & &
u - > building & &
u - > building - > sizeleft > = u - > number & &
2001-12-10 01:13:39 +01:00
playerrace ( u - > race ) ) {
2001-01-25 10:37:55 +01:00
fig - > building = u - > building ;
fig - > building - > sizeleft - = u - > number ;
}
fig - > status = u - > status ;
fig - > side = s1 ;
fig - > alive = u - > number ;
2001-02-14 10:17:56 +01:00
fig - > side - > alive + = u - > number ;
fig - > side - > battle - > alive + = u - > number ;
2001-01-25 10:37:55 +01:00
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 ;
2002-04-27 22:09:44 +02:00
/* Effekte von Spr<70> chen */
2003-07-29 11:48:03 +02:00
2002-04-27 22:09:44 +02:00
{
2002-05-01 21:08:32 +02:00
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 ) ;
}
2002-04-27 22:09:44 +02:00
}
}
2001-01-25 10:37:55 +01:00
/* 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
/* Effekte von Artefakten */
strongmen = min ( fig - > unit - > number , get_item ( u , I_TROLLBELT ) ) ;
for ( a = a_find ( u - > attribs , & at_prayer_effect ) ; a ; a = a - > nexttype ) {
if ( a - > data . sa [ 0 ] = = PR_AID ) {
pr_aid = true ;
break ;
}
}
/* 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 + + ;
fig - > person [ i ] . flags | = FL_HERO ;
}
/* 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 . */
2001-12-10 01:13:39 +01:00
if ( u - > race - > battle_flags & BF_EQUIPMENT ) {
2001-01-25 10:37:55 +01:00
int oi = 0 , di = 0 ;
for ( itm = u - > items ; itm ; itm = itm - > next ) {
const weapon_type * wtype = resource2weapon ( itm - > type - > rtype ) ;
if ( wtype = = NULL | | itm - > number = = 0 ) continue ;
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
weapons [ w ] . attackskill = weapon_skill ( wtype , u , true ) ;
weapons [ w ] . defenseskill = weapon_skill ( wtype , u , false ) ;
2001-01-25 10:37:55 +01:00
weapons [ w ] . type = wtype ;
weapons [ w ] . used = 0 ;
weapons [ w ] . count = itm - > number ;
+ + w ;
}
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 ) {
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
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 ;
2001-01-25 10:37:55 +01:00
}
for ( j = i + 1 ; j ! = w ; + + j ) {
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
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 ;
2001-01-25 10:37:55 +01:00
}
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 */
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
/* hand out melee weapons: */
2001-01-25 10:37:55 +01:00
for ( i = 0 ; i ! = fig - > alive ; + + i ) {
int wpless = weapon_skill ( NULL , u , true ) ;
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
while ( oi ! = w & & ( fig - > weapons [ owp [ oi ] ] . used = = fig - > weapons [ owp [ oi ] ] . count | | fval ( fig - > weapons [ owp [ oi ] ] . type , WTF_MISSILE ) ) ) {
2001-01-25 10:37:55 +01:00
+ + oi ;
}
if ( oi = = w ) break ; /* no more weapons available */
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
if ( weapon_weight ( fig - > weapons + owp [ oi ] , false ) < = wpless ) {
continue ; /* we fight better with bare hands */
2001-01-25 10:37:55 +01:00
}
2002-10-06 11:23:33 +02:00
fig - > person [ i ] . melee = & fig - > weapons [ owp [ oi ] ] ;
2001-01-25 10:37:55 +01:00
+ + fig - > weapons [ owp [ oi ] ] . used ;
}
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
/* 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 ) ) ) {
2001-01-25 10:37:55 +01:00
+ + di ;
}
if ( di = = w ) break ; /* no more weapons available */
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
if ( weapon_weight ( fig - > weapons + dwp [ di ] , true ) > 0 ) {
fig - > person [ i ] . missile = & fig - > weapons [ dwp [ di ] ] ;
2001-01-25 10:37:55 +01:00
+ + fig - > weapons [ dwp [ di ] ] . used ;
}
}
}
if ( i_get ( u - > items , & it_demonseye ) ) {
char lbuf [ 80 ] ;
2001-12-10 01:13:39 +01:00
const char * s = LOC ( default_locale , rc_name ( u - > race , 3 ) ) ;
2001-01-25 10:37:55 +01:00
char * c = lbuf ;
while ( * s ) * c + + = ( char ) toupper ( * s + + ) ;
* c = 0 ;
fig - > person [ 0 ] . hp = unit_max_hp ( u ) * 3 ;
sprintf ( buf , " Eine Stimme ert<72> nt <20> ber dem Schlachtfeld. 'DIESES %sKIND IST MEIN. IHR SOLLT ES NICHT HABEN.'. Eine leuchtende Aura umgibt %s " , lbuf , unitname ( u ) ) ;
battlerecord ( b , buf ) ;
}
2001-04-13 16:39:57 +02:00
s1 - > size [ statusrow ( fig - > status ) ] + = u - > number ;
2001-01-25 10:37:55 +01:00
s1 - > size [ SUM_ROW ] + = u - > number ;
2001-12-10 01:13:39 +01:00
if ( u - > race - > battle_flags & BF_NOBLOCK ) {
2001-04-13 16:39:57 +02:00
s1 - > nonblockers [ statusrow ( fig - > status ) ] + = u - > number ;
2001-01-25 10:37:55 +01:00
}
2001-12-10 01:13:39 +01:00
if ( fig - > unit - > race - > flags & RCF_HORSE ) {
2001-01-25 10:37:55 +01:00
fig - > horses = fig - > unit - > number ;
fig - > elvenhorses = 0 ;
} else {
fig - > horses = get_item ( u , I_HORSE ) ;
fig - > elvenhorses = get_item ( u , I_UNICORN ) ;
}
for ( i = 0 ; i ! = AR_MAX ; + + i )
2001-12-10 01:13:39 +01:00
if ( u - > race - > battle_flags & BF_EQUIPMENT )
2001-01-25 10:37:55 +01:00
fig - > armor [ i ] = get_item ( u , armordata [ i ] . item ) ;
/* 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 . */
/* Zuerst mal die Spezialbehandlung gewisser Sonderf<72> lle. */
fig - > magic = eff_skill ( u , SK_MAGIC , r ) ;
if ( fig - > horses ) {
if ( ( r - > terrain ! = T_PLAIN & & r - > terrain ! = T_HIGHLAND
2001-12-10 01:13:39 +01:00
& & r - > terrain ! = T_DESERT ) | | r_isforest ( r )
2002-04-12 14:46:16 +02:00
| | eff_skill ( u , SK_RIDING , r ) < 2 | | old_race ( u - > race ) = = RC_TROLL | | fval ( u , UFL_WERE ) )
2001-01-25 10:37:55 +01:00
fig - > horses = 0 ;
}
if ( fig - > elvenhorses ) {
2002-04-12 14:46:16 +02:00
if ( eff_skill ( u , SK_RIDING , r ) < 5 | | old_race ( u - > race ) = = RC_TROLL | | fval ( u , UFL_WERE ) )
2001-01-25 10:37:55 +01:00
fig - > elvenhorses = 0 ;
}
/* Schauen, wie gut wir in Taktik sind. */
2001-12-10 01:13:39 +01:00
if ( t > 0 & & old_race ( u - > race ) = = RC_INSECT )
2001-01-25 10:37:55 +01:00
t - = 1 - ( int ) log10 ( fig - > side - > size [ SUM_ROW ] ) ;
if ( t > 0 & & get_unitrow ( fig ) = = FIGHT_ROW )
t + = 1 ;
# ifdef TACTICS_MALUS
if ( t > 0 & & get_unitrow ( fig ) > BEHIND_ROW )
t - = 1 ;
# endif
# if TACTICS_RANDOM
if ( t > 0 ) {
int bonus = 0 ;
for ( i = 0 ; i < fig - > alive ; i + + ) {
int p_bonus = 0 ;
2001-02-09 14:53:53 +01:00
int rnd ;
2001-01-25 10:37:55 +01:00
do {
2001-02-09 14:53:53 +01:00
rnd = rand ( ) % 100 ;
if ( rnd > = 40 & & rnd < = 69 )
2001-01-25 10:37:55 +01:00
p_bonus + = 1 ;
2001-02-09 14:53:53 +01:00
else if ( rnd < = 89 )
2001-01-25 10:37:55 +01:00
p_bonus + = 2 ;
else
p_bonus + = 3 ;
2001-02-09 14:53:53 +01:00
} while ( rnd > = 97 ) ;
2001-01-25 10:37:55 +01:00
bonus = max ( p_bonus , bonus ) ;
}
t + = bonus ;
}
/* Nicht gut, da nicht personenbezogen. */
/* if (t > 0) t += rand() % TACTICS_RANDOM; */
/* statt +/- 2 kann man auch random(5) nehmen */
# endif
add_tactics ( & fig - > side - > leader , fig , t ) ;
return fig ;
}
static fighter *
join_battle ( battle * b , unit * u , boolean attack )
{
fighter * c = NULL ;
fighter * fig ;
2003-07-29 11:48:03 +02:00
cv_foreach ( fig , b - > fighters ) {
2001-01-25 10:37:55 +01:00
if ( fig - > unit = = u ) {
c = fig ;
if ( attack ) fset ( fig , FIG_ATTACKED ) ;
break ;
}
}
2003-07-29 11:48:03 +02:00
cv_next ( fig ) ;
2004-02-09 22:12:46 +01:00
if ( ! c ) c = make_fighter ( b , u , NULL , attack ) ;
2001-01-25 10:37:55 +01:00
return c ;
}
static const char *
simplename ( region * r )
{
int i ;
static char name [ 17 ] ;
const char * cp = rname ( r , NULL ) ;
for ( i = 0 ; * cp & & i ! = 16 ; + + i , + + cp ) {
2001-02-18 13:11:32 +01:00
int c = * ( unsigned char * ) cp ;
while ( c & & ! isalpha ( c ) & & ! isspace ( c ) ) {
+ + cp ;
c = * ( unsigned char * ) cp ;
}
if ( isspace ( c ) ) name [ i ] = ' _ ' ;
2001-01-25 10:37:55 +01:00
else name [ i ] = * cp ;
2004-02-12 08:20:47 +01:00
if ( c = = 0 ) break ;
2001-01-25 10:37:55 +01:00
}
name [ i ] = 0 ;
return name ;
}
static battle *
make_battle ( region * r )
{
battle * b = calloc ( 1 , sizeof ( struct battle ) ) ;
unit * u ;
faction * lastf = NULL ;
bfaction * bf ;
static int max_fac_no = 0 ; /* need this only once */
if ( ! nobattledebug ) {
2001-02-03 14:45:35 +01:00
char zText [ MAX_PATH ] ;
2001-02-05 17:11:59 +01:00
char zFilename [ MAX_PATH ] ;
2001-02-03 14:45:35 +01:00
sprintf ( zText , " %s/battles " , basepath ( ) ) ;
2001-02-05 17:11:59 +01:00
makedir ( zText , 0700 ) ;
2001-01-25 10:37:55 +01:00
# ifdef HAVE_ZLIB
2001-02-05 17:11:59 +01:00
sprintf ( zFilename , " %s/battle-%d-%s.log.gz " , zText , obs_count , simplename ( r ) ) ;
bdebug = gzopen ( zFilename , " w " ) ;
2001-01-25 10:37:55 +01:00
# elif HAVE_BZ2LIB
2001-02-05 17:11:59 +01:00
sprintf ( zFilename , " %s/battle-%d-%s.log.bz2 " , zText , obs_count , simplename ( r ) ) ;
2001-04-01 08:58:45 +02:00
bdebug = BZ2_bzopen ( zFilename , " w " ) ; +
2001-01-25 10:37:55 +01:00
# else
2001-02-05 17:11:59 +01:00
sprintf ( zFilename , " %s/battle-%d-%s.log " , zText , obs_count , simplename ( r ) ) ;
bdebug = fopen ( zFilename , " w " ) ;
2001-01-25 10:37:55 +01:00
# endif
2001-04-14 14:11:45 +02:00
if ( ! bdebug ) log_error ( ( " battles k<> nnen nicht debugged werden \n " ) ) ;
2001-02-05 17:11:59 +01:00
else {
2002-11-30 22:06:27 +01:00
dbgprintf ( ( bdebug , " In %s findet ein Kampf statt: \n " , rname ( r , NULL ) ) ) ;
2001-01-25 10:37:55 +01:00
}
obs_count + + ;
}
nextside = 0 ;
/* cv_init(&b->sides); */
b - > region = r ;
b - > plane = getplane ( r ) ;
/* Finde alle Parteien, die den Kampf beobachten k<> nnen: */
list_foreach ( unit , r - > units , u )
if ( u - > number > 0 ) {
if ( lastf ! = u - > faction ) { /* Speed optimiert, aufeinanderfolgende
* * gleiche nicht getestet */
lastf = u - > faction ;
for ( bf = b - > factions ; bf ; bf = bf - > next )
if ( bf - > faction = = lastf ) break ;
if ( ! bf ) {
bf = calloc ( sizeof ( bfaction ) , 1 ) ;
+ + b - > nfactions ;
bf - > faction = lastf ;
bf - > next = b - > factions ;
b - > factions = bf ;
}
}
}
list_next ( u ) ;
for ( bf = b - > factions ; bf ; bf = bf - > next ) {
faction * f = bf - > faction ;
max_fac_no = max ( max_fac_no , f - > no ) ;
}
return b ;
}
static void
free_side ( side * si )
{
cv_kill ( & si - > fighters ) ;
}
static void
free_fighter ( fighter * fig )
{
free ( fig - > person ) ;
}
static void
free_battle ( battle * b )
{
side * side ;
fighter * fighter ;
meffect * meffect ;
bfaction * bf ;
int max_fac_no = 0 ;
if ( bdebug ) {
# ifdef HAVE_ZLIB
gzclose ( bdebug ) ;
# elif HAVE_BZ2LIB
BZ2_bzclose ( bdebug ) ;
# else
fclose ( bdebug ) ;
# endif
}
for ( bf = b - > factions ; bf ; bf = bf - > next ) {
faction * f = bf - > faction ;
max_fac_no = max ( max_fac_no , f - > no ) ;
}
2003-07-29 11:48:03 +02:00
cv_foreach ( side , b - > sides ) {
2001-01-25 10:37:55 +01:00
free_side ( side ) ;
free ( side ) ;
}
2003-07-29 11:48:03 +02:00
cv_next ( side ) ;
2001-01-25 10:37:55 +01:00
cv_kill ( & b - > sides ) ;
2003-07-29 11:48:03 +02:00
cv_foreach ( fighter , b - > fighters ) {
2001-01-25 10:37:55 +01:00
free_fighter ( fighter ) ;
free ( fighter ) ;
}
2003-07-29 11:48:03 +02:00
cv_next ( fighter ) ;
2001-01-25 10:37:55 +01:00
cv_kill ( & b - > fighters ) ;
2003-07-29 11:48:03 +02:00
cv_foreach ( meffect , b - > meffects ) {
2001-01-25 10:37:55 +01:00
free ( meffect ) ;
}
2003-07-29 11:48:03 +02:00
cv_next ( meffect ) ;
2001-01-25 10:37:55 +01:00
cv_kill ( & b - > meffects ) ;
/*
cv_kill ( & b - > factions ) ;
*/
}
static int *
get_alive ( battle * b , side * s , faction * vf , boolean see )
{
static int alive [ NUMROWS ] ;
fighter * f ;
memset ( alive , 0 , NUMROWS * sizeof ( int ) ) ;
2003-07-29 11:48:03 +02:00
cv_foreach ( f , s - > fighters ) {
2001-01-25 10:37:55 +01:00
if ( f - > alive & & seematrix ( vf , s ) = = see )
alive [ get_unitrow ( f ) ] + = f - > alive ;
2003-07-29 11:48:03 +02:00
} cv_next ( f ) ;
2001-01-25 10:37:55 +01:00
return alive ;
}
static int
battle_report ( battle * b )
{
side * s , * s2 ;
boolean cont = false ;
boolean komma ;
char buf2 [ 1024 ] ;
bfaction * bf ;
buf [ 0 ] = 0 ;
2003-07-29 11:48:03 +02:00
cv_foreach ( s , b - > sides ) {
cv_foreach ( s2 , b - > sides ) {
2001-12-10 01:13:39 +01:00
if ( s - > alive - s - > removed > 0 & & s2 - > alive - s2 - > removed > 0 & & enemy ( s , s2 ) )
2001-01-25 10:37:55 +01:00
{
cont = true ;
s - > bf - > lastturn = b - > turn ;
s2 - > bf - > lastturn = b - > turn ;
}
2003-07-29 11:48:03 +02:00
} cv_next ( s2 ) ;
} cv_next ( s ) ;
2001-01-25 10:37:55 +01:00
printf ( " %d " , b - > turn ) ;
fflush ( stdout ) ;
for ( bf = b - > factions ; bf ; bf = bf - > next ) {
faction * fac = bf - > faction ;
2004-04-22 00:09:39 +02:00
message * m ;
2004-04-20 00:52:36 +02:00
fbattlerecord ( b , fac , " " ) ;
2004-04-22 00:09:39 +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 ) ;
2001-01-25 10:37:55 +01:00
buf2 [ 0 ] = 0 ;
komma = false ;
2003-07-29 11:48:03 +02:00
cv_foreach ( s , b - > sides ) {
2001-01-25 10:37:55 +01:00
if ( s - > alive ) {
int r , k = 0 , * alive = get_alive ( b , s , fac , seematrix ( fac , s ) ) ;
2004-04-22 00:09:39 +02:00
int l = FIGHT_ROW ;
const char * abbrev = seematrix ( fac , s ) ? sideabkz ( s , false ) : " -?- " ;
const char * loc_army = LOC ( fac - > locale , " battle_army " ) ;
2004-04-22 00:48:13 +02:00
sprintf ( buf , " %s%s %2d(%s): " , ( komma = = true ? " , " : " " ) ,
loc_army , s - > index , abbrev ) ;
2004-04-22 00:09:39 +02:00
for ( r = FIGHT_ROW ; r ! = NUMROWS ; + + r ) {
if ( alive [ r ] ) {
if ( l ! = FIGHT_ROW ) scat ( " + " ) ;
while ( k - - ) scat ( " 0+ " ) ;
icat ( alive [ r ] ) ;
k = 0 ;
l = r + 1 ;
} else + + k ;
2001-01-25 10:37:55 +01:00
}
strcat ( buf2 , buf ) ;
if ( komma = = false ) {
komma = true ;
}
}
2003-07-29 11:48:03 +02:00
} cv_next ( s ) ;
2004-04-20 00:52:36 +02:00
fbattlerecord ( b , fac , buf2 ) ;
2001-01-25 10:37:55 +01:00
}
return cont ;
}
static void
join_allies ( battle * b )
{
2004-05-30 04:24:53 +02:00
region * r = b - > region ;
unit * u ;
/* Die Anzahl der Teilnehmer kann sich in dieser Routine <20> ndern.
* Deshalb mu <EFBFBD> das Ende des Vektors vorher gemerkt werden , damit
* neue Parteien nicht mit betrachtet werden :
*/
int size = cv_size ( & b - > sides ) ;
for ( u = r - > units ; u ; u = u - > next )
/* Was ist mit Schiffen? */
if ( u - > status ! = ST_FLEE & & u - > status ! = ST_AVOID & & ! fval ( u , UFL_LONGACTION ) & & u - > number > 0 )
{
int si ;
faction * f = u - > faction ;
fighter * c = NULL ;
for ( si = 0 ; si ! = size ; + + si ) {
int se ;
side * s = b - > sides . begin [ si ] ;
/* Wenn alle attackierten noch FFL_NOAID haben, dann k<> mpfe nicht mit. */
if ( fval ( s - > bf - > faction , FFL_NOAID ) ) continue ;
if ( s - > bf - > faction ! = f ) {
/* Wenn wir attackiert haben, kommt niemand mehr hinzu: */
if ( s - > bf - > attacker ) continue ;
/* alliiert m<> ssen wir schon sein, sonst ist's eh egal : */
if ( ! alliedunit ( u , s - > bf - > faction , HELP_FIGHT ) ) continue ;
/* 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 : */
for ( se = 0 ; se ! = size ; + + se ) {
side * evil = b - > sides . begin [ se ] ;
if ( u - > faction = = evil - > bf - > faction ) continue ;
if ( alliedunit ( u , evil - > bf - > faction , HELP_FIGHT ) & &
! evil - > bf - > attacker ) continue ;
if ( enemy ( s , evil ) ) break ;
}
if ( se = = size ) continue ;
/* Wenn die Einheit belagert ist, mu<6D> auch einer der Alliierten belagert sein: */
if ( besieged ( u ) ) {
void * * fi ;
boolean siege = false ;
for ( fi = s - > fighters . begin ; ! siege & & fi ! = s - > fighters . end ; + + fi ) {
fighter * ally = * fi ;
if ( besieged ( ally - > unit ) ) siege = true ;
}
if ( ! siege ) continue ;
}
/* keine Einw<6E> nde, also soll er mitmachen: */
if ( ! c ) c = join_battle ( b , u , false ) ;
if ( ! c ) continue ;
/* Die Feinde meiner Freunde sind meine Feinde: */
for ( se = 0 ; se ! = size ; + + se ) {
side * evil = b - > sides . begin [ se ] ;
if ( evil - > bf - > faction ! = u - > faction & & enemy ( s , evil ) ) {
set_enemy ( evil , c - > side , false ) ;
}
}
}
}
2001-01-25 10:37:55 +01:00
}
2001-03-04 19:41:27 +01:00
extern struct item_type * i_silver ;
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
{
fighter * fig = dt . fighter ;
2003-03-08 21:57:38 +01:00
# ifndef NO_RUNNING
2001-03-04 19:41:27 +01:00
unit * u = fig - > unit ;
2001-12-10 01:13:39 +01:00
int carry = personcapacity ( u ) - u - > race - > weight ;
2001-03-04 19:41:27 +01:00
int money ;
item * * ip = & u - > items ;
2003-03-08 21:57:38 +01:00
2001-03-04 19:41:27 +01:00
while ( * ip ) {
item * itm = * ip ;
const item_type * itype = itm - > type ;
int keep = 0 ;
2001-04-01 08:58:45 +02:00
if ( fval ( itype , ITF_ANIMAL ) ) {
2001-03-04 19:41:27 +01:00
/* 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 ) ;
2001-12-10 01:13:39 +01:00
/* da ist das weight des tiers mit drin */
carry + = itype - > capacity - itype - > weight ;
2001-03-04 19:41:27 +01:00
} else if ( itm - > type - > weight < = 0 ) {
/* if it doesn't weigh anything, it won't slow us down */
keep = itm - > number ;
}
2001-04-01 08:58:45 +02:00
/* 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 {
2001-12-10 01:13:39 +01:00
item * run_itm = i_new ( itype , keep ) ;
2001-04-01 08:58:45 +02:00
i_add ( & fig - > run . items , run_itm ) ;
i_change ( ip , itype , - keep ) ;
}
2001-03-04 19:41:27 +01:00
}
if ( * ip = = itm ) ip = & itm - > next ;
}
/* we will take money with us */
money = get_money ( u ) ;
2001-12-10 01:13:39 +01:00
/* nur ganzgeflohene/resttote Einheiten verlassen die Region */
2001-03-04 19:41:27 +01:00
if ( money > carry ) money = carry ;
2001-12-10 01:13:39 +01:00
if ( money > 0 ) {
i_change ( & u - > items , i_silver , - money ) ;
i_change ( & fig - > run . items , i_silver , + money ) ;
}
2003-03-08 21:57:38 +01:00
# endif
2001-03-04 19:41:27 +01:00
fig - > run . hp + = fig - > person [ dt . index ] . hp ;
+ + fig - > run . number ;
remove_troop ( dt ) ;
}
- 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 )
{
unit * u ;
for ( u = r - > units ; u ; u = u - > next ) {
if ( u - > faction = = f & & getguard ( u ) ) return true ;
}
return false ;
}
# 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 ) {
strlist * sl ;
list_foreach ( strlist , u - > orders , sl ) {
boolean init = false ;
static const curse_type * peace_ct , * slave_ct , * calm_ct ;
if ( ! init ) {
init = true ;
peace_ct = ct_find ( " peacezone " ) ;
slave_ct = ct_find ( " slavery " ) ;
calm_ct = ct_find ( " calmmonster " ) ;
}
if ( igetkeyword ( sl - > s , u - > faction - > locale ) = = K_ATTACK ) {
unit * u2 ;
fighter * c1 , * c2 ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
if ( r - > planep & & fval ( r - > planep , PFL_NOATTACK ) ) {
cmistake ( u , sl - > s , 271 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
2001-01-25 10:37:55 +01:00
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 ) ) {
add_message ( & u - > faction - > msgs ,
msg_message ( " no_attack_after_advance " , " unit region command " , u , u - > region , sl - > s ) ) ;
}
- 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
if ( fval ( u , UFL_HUNGER ) ) {
cmistake ( u , sl - > s , 225 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
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 ) {
cmistake ( u , sl - > s , 226 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
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-05-30 03:46:25 +02:00
if ( fval ( u , UFL_LONGACTION ) ) list_continue ( sl ) ;
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 ) ) ) {
sprintf ( buf , " Hier ist es so sch<63> n friedlich, %s m<> chte "
" hier niemanden angreifen. " , unitname ( u ) ) ;
mistake ( u , sl - > s , buf , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
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 ) ) ) {
sprintf ( buf , " %s k<> mpft nicht. " , unitname ( u ) ) ;
mistake ( u , sl - > s , buf , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
/* Fehler: "Das Schiff mu<6D> erst verlassen werden" */
if ( u - > ship ! = NULL & & rterrain ( r ) ! = T_OCEAN ) {
cmistake ( u , sl - > s , 19 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
if ( leftship ( u ) ) {
cmistake ( u , sl - > s , 234 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
/* Ende Fehlerbehandlung Angreifer */
/* 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 ) ) {
2004-04-20 00:52:36 +02:00
cmistake ( u , sl - > s , 63 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
/* Fehler: "Die Einheit ist eine der unsrigen" */
if ( u2 - > faction = = u - > faction ) {
cmistake ( u , sl - > s , 45 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
/* Fehler: "Die Einheit ist mit uns alliert" */
if ( alliedunit ( u , u2 - > faction , HELP_FIGHT ) ) {
cmistake ( u , sl - > s , 47 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
/* xmas */
if ( u2 - > no = = atoi36 ( " xmas " ) & & old_race ( u2 - > irace ) = = RC_GNOME ) {
a_add ( & u - > attribs , a_new ( & at_key ) ) - > data . i = atoi36 ( " coal " ) ;
sprintf ( buf , " %s ist b<> se gewesen... " , unitname ( u ) ) ;
mistake ( u , sl - > s , buf , MSG_BATTLE ) ;
list_continue ( sl ) ;
} if ( u2 - > faction - > age < IMMUN_GEGEN_ANGRIFF ) {
add_message ( & u - > faction - > msgs ,
msg_error ( u , findorder ( u , u - > thisorder ) , " newbie_immunity_error " , " turns " , IMMUN_GEGEN_ANGRIFF ) ) ;
list_continue ( sl ) ;
}
/* Fehler: "Die Einheit ist mit uns alliert" */
if ( calm_ct & & curse_active ( get_cursex ( u - > attribs , calm_ct , ( void * ) u2 - > faction , cmp_curseeffect ) ) ) {
cmistake ( u , sl - > s , 47 , MSG_BATTLE ) ;
list_continue ( sl ) ;
}
/* Ende Fehlerbehandlung */
if ( b = = NULL ) {
unit * utmp ;
for ( utmp = r - > units ; utmp ! = NULL ; utmp = utmp - > next ) {
fset ( utmp - > faction , FFL_NOAID ) ;
}
b = make_battle ( r ) ;
}
c1 = join_battle ( b , u , true ) ;
c2 = join_battle ( b , u2 , false ) ;
/* 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 ;
set_enemy ( c1 - > side , c2 - > side , true ) ;
if ( ! enemy ( c1 - > side , c2 - > side ) ) {
sprintf ( buf , " %s attackiert %s " , sidename ( c1 - > side , false ) ,
sidename ( c2 - > side , false ) ) ;
battledebug ( buf ) ;
}
fighting = true ;
}
}
}
list_next ( sl ) ;
}
}
* 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 ;
cv_foreach ( s , b - > sides ) {
fighter * df ;
stat_info * stats = NULL , * stat ;
cv_foreach ( df , s - > fighters ) {
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 ;
}
} cv_next ( df ) ;
fprintf ( F , " ##STATS## Heer %u - %s: \n " , s - > index , factionname ( s - > bf - > faction ) ) ;
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 ) ;
} cv_next ( s ) ;
}
2004-04-20 00:52:36 +02:00
void
do_battle ( void )
{
region * r ;
# ifdef SMALL_BATTLE_MESSAGES
char smallbuf [ 512 ] ;
# endif
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
for ( r = regions ; r ! = NULL ; r = r - > next ) {
battle * b = NULL ;
boolean fighting = false ;
side * s ;
ship * sh ;
void * * fi ;
building * bu ;
fighting = init_battle ( r , & b ) ;
if ( b = = NULL ) continue ;
/* 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 ) ;
continue ;
}
join_allies ( b ) ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +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
2004-04-20 00:52:36 +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
2004-04-20 00:52:36 +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
2004-05-30 14:09:45 +02:00
if ( b - > region - > flags & RF_COMBATDEBUG ) battle_stats ( bdebug , b ) ;
2004-04-20 00:52:36 +02:00
/* PRECOMBATSPELLS */
do_combatmagic ( b , DO_PRECOMBATSPELL ) ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
/* Nun erstellen wir eine Liste von allen K<> mpfern, die wir
* dann scramblen . Zuerst werden sie wild gemischt , und dann wird ( stabil )
* nach der Kampfreihe sortiert */
v_scramble ( b - > fighters . begin , b - > fighters . end ) ;
v_sort ( b - > fighters . begin , b - > fighters . end , ( v_sort_fun ) sort_fighterrow ) ;
cv_foreach ( s , b - > sides ) {
v_sort ( s - > fighters . begin , s - > fighters . end , ( v_sort_fun ) sort_fighterrow ) ;
}
cv_next ( side ) ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +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
2004-04-20 00:52:36 +02:00
b - > dh = 0 ;
/* K<> mpfer z<> hlen und festlegen, ob es ein kleiner Kampf ist */
for ( fi = b - > fighters . begin ; fi ! = b - > fighters . end ; + + fi ) {
fighter * fig = * fi ;
b - > dh + = fig - > unit - > number ;
}
2002-03-16 15:13:22 +01:00
2004-04-20 00:52:36 +02:00
# ifdef SMALL_BATTLE_MESSAGES
if ( b - > dh < = 30 ) {
b - > small = true ;
} else {
b - > small = false ;
}
2002-03-16 15:13:22 +01:00
# endif
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
for ( ; battle_report ( b ) & & b - > turn < = COMBAT_TURNS ; + + b - > turn ) {
char lbuf [ 256 ] ;
int flee_ops = 1 ;
int i ;
sprintf ( lbuf , " *** Runde: %d " , b - > turn ) ;
battledebug ( lbuf ) ;
/* Der doppelte Versuch immer am Anfang der 1. Kampfrunde, nur
* ein Versuch vor der Taktikerrunde . Die 0. Runde ist immer
* die Taktikerrunde . */
if ( b - > turn = = 1 )
flee_ops = 2 ;
for ( i = 1 ; i < = flee_ops ; i + + ) {
for ( fi = b - > fighters . begin ; fi ! = b - > fighters . end ; + + fi ) {
fighter * fig = * fi ;
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 ) ) ) ;
side * side = fig - > side ;
if ( fval ( u - > race , RCF_UNDEAD ) | | old_race ( u - > race ) = = RC_SHADOWKNIGHT ) continue ;
if ( u - > ship ) continue ;
dt . fighter = fig ;
2003-03-08 21:57:38 +01:00
# ifndef NO_RUNNING
2004-04-20 00:52:36 +02:00
if ( ! fig - > run . region ) fig - > run . region = fleeregion ( u ) ;
if ( ! fig - > run . region ) continue ;
2003-03-08 21:57:38 +01:00
# endif
2004-04-20 00:52:36 +02:00
dt . index = fig - > alive - fig - > removed ;
while ( side - > size [ SUM_ROW ] & & dt . index ! = 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 !
*/
if ( ( u - > status = = ST_FLEE
| | ( b - > turn > 1 & & fig - > person [ dt . index ] . hp < = runhp )
| | ( fig - > person [ dt . index ] . flags & FL_PANICED ) )
& & ! ( fig - > person [ dt . index ] . flags & FL_HERO ) )
{
double ispaniced = 0.0 ;
if ( fig - > person [ dt . index ] . flags & FL_PANICED ) {
ispaniced = EFFECT_PANIC_SPELL ;
}
if ( chance ( min ( fleechance ( u ) + ispaniced , 0.90 ) ) ) {
+ + runners ;
flee ( dt ) ;
# ifdef SMALL_BATTLE_MESSAGES
if ( b - > small ) {
sprintf ( smallbuf , " %s/%d gelingt es, vom Schlachtfeld zu entkommen. " ,
unitname ( fig - > unit ) , dt . index ) ;
battlerecord ( b , smallbuf ) ;
}
} else if ( b - > small ) {
sprintf ( smallbuf , " %s/%d versucht zu fliehen, wird jedoch aufgehalten. " ,
unitname ( fig - > unit ) , dt . index ) ;
battlerecord ( b , smallbuf ) ;
# endif
}
}
}
if ( runners > 0 ) {
sprintf ( lbuf , " Flucht: %d aus %s " , runners , itoa36 ( fig - > unit - > no ) ) ;
battledebug ( lbuf ) ;
}
}
}
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
/* this has to be calculated before the actual attacks take
* place because otherwise the dead would not strike the
* round they die . */
for ( fi = b - > fighters . begin ; fi ! = b - > fighters . end ; + + fi ) {
fighter * fig = * fi ;
fig - > fighting = fig - > alive - fig - > removed ;
}
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
for ( fi = b - > fighters . begin ; fi ! = b - > fighters . end ; + + fi ) {
fighter * fig = * fi ;
/* ist in dieser Einheit noch jemand handlungsf<73> hig? */
if ( fig - > fighting < = 0 ) continue ;
/* Taktikrunde: */
if ( b - > turn = = 0 ) {
side * side ;
boolean yes = false ;
cv_foreach ( side , b - > sides ) {
if ( b - > max_tactics > 0
& & side - > leader . value = = b - > max_tactics
& & helping ( side , fig - > side ) )
{
yes = true ;
break ;
}
} cv_next ( side ) ;
if ( ! yes )
continue ;
}
/* Handle the unit's attack on someone */
do_attack ( fig ) ;
}
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
/* Regeneration */
for ( fi = b - > fighters . begin ; fi ! = b - > fighters . end ; + + fi ) {
fighter * fig = * fi ;
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
if ( fspecial ( fig - > unit - > faction , FS_REGENERATION ) ) {
fig - > fighting = fig - > alive - fig - > removed ;
if ( fig - > fighting = = 0 ) continue ;
do_regenerate ( fig ) ;
}
}
}
2001-01-25 10:37:55 +01:00
2004-04-20 00:52:36 +02:00
printf ( " \n " ) ;
/* Auswirkungen berechnen: */
aftermath ( b ) ;
/*
# if MALLOCDBG
assert ( _CrtCheckMemory ( ) ) ;
# endif
*/
/* Hier ist das Gefecht beendet, und wir k<> nnen die
* Hilfsstrukturen * wieder l <EFBFBD> schen : */
if ( b ) {
free_battle ( b ) ;
free ( b ) ;
}
}
2001-01-25 10:37:55 +01:00
}
/* Funktionen, die au<61> erhalb von battle.c verwendet werden. */
2003-07-29 11:48:03 +02:00
static int
2001-01-25 10:37:55 +01:00
nb_armor ( unit * u , int index )
{
int a , av = 0 ;
int geschuetzt = 0 ;
2001-12-10 01:13:39 +01:00
if ( ! ( u - > race - > battle_flags & BF_EQUIPMENT ) ) return AR_NONE ;
2001-01-25 10:37:55 +01:00
/* Normale R<> stung */
a = 0 ;
do {
if ( armordata [ a ] . shield = = 0 ) {
geschuetzt + = get_item ( u , armordata [ a ] . item ) ;
if ( geschuetzt > index )
av + = armordata [ a ] . prot ;
}
+ + a ;
}
while ( a ! = AR_MAX ) ;
/* Schild */
a = 0 ;
do {
if ( armordata [ a ] . shield = = 1 ) {
geschuetzt + = get_item ( u , armordata [ a ] . item ) ;
if ( geschuetzt > index )
av + = armordata [ a ] . prot ;
}
+ + a ;
}
while ( a ! = AR_MAX ) ;
return av ;
}
int
damage_unit ( unit * u , const char * dam , boolean armor , boolean magic )
{
int * hp = malloc ( u - > number * sizeof ( int ) ) ;
2002-03-11 22:20:31 +01:00
int h ;
2001-01-25 10:37:55 +01:00
int i , dead = 0 , hp_rem = 0 , heiltrank ;
2002-03-11 22:20:31 +01:00
if ( u - > number = = 0 ) return 0 ;
h = u - > hp / u - > number ;
2001-01-25 10:37:55 +01:00
/* HP verteilen */
for ( i = 0 ; i < u - > number ; i + + ) hp [ i ] = h ;
h = u - > hp - ( u - > number * h ) ;
for ( i = 0 ; i < h ; i + + ) hp [ i ] + + ;
/* Schaden */
for ( i = 0 ; i < u - > number ; i + + ) {
int damage = dice_rand ( dam ) ;
2004-02-09 23:20:40 +01:00
if ( magic ) damage = ( int ) ( damage * ( 1.0 - magic_resistance ( u ) ) ) ;
2001-01-25 10:37:55 +01:00
if ( armor ) damage - = nb_armor ( u , i ) ;
hp [ i ] - = damage ;
}
/* Auswirkungen */
for ( i = 0 ; i < u - > number ; i + + ) {
2003-09-28 10:05:50 +02:00
if ( hp [ i ] < = 0 ) {
2001-01-25 10:37:55 +01:00
heiltrank = 0 ;
/* Sieben Leben */
2001-12-10 01:13:39 +01:00
if ( old_race ( u - > race ) = = RC_CAT & & ( chance ( 1.0 / 7 ) ) ) {
2001-01-25 10:37:55 +01:00
hp [ i ] = u - > hp / u - > number ;
hp_rem + = hp [ i ] ;
continue ;
}
/* Heiltrank */
if ( get_effect ( u , oldpotiontype [ P_HEAL ] ) > 0 ) {
change_effect ( u , oldpotiontype [ P_HEAL ] , - 1 ) ;
heiltrank = 1 ;
} else if ( get_potion ( u , P_HEAL ) > 0 ) {
i_change ( & u - > items , oldpotiontype [ P_HEAL ] - > itype , - 1 ) ;
change_effect ( u , oldpotiontype [ P_HEAL ] , 3 ) ;
heiltrank = 1 ;
}
if ( heiltrank & & ( chance ( 0.50 ) ) ) {
hp [ i ] = u - > hp / u - > number ;
hp_rem + = hp [ i ] ;
continue ;
}
dead + + ;
} else {
hp_rem + = hp [ i ] ;
}
}
scale_number ( u , u - > number - dead ) ;
u - > hp = hp_rem ;
free ( hp ) ;
return dead ;
}