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