2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2003-07-29 11:48:03 +02:00
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2003
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
|
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
|
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
|
|
|
|
* Enno Rehling (enno@eressea-pbem.de)
|
|
|
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
|
|
|
*
|
|
|
|
|
* based on:
|
|
|
|
|
*
|
|
|
|
|
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
|
|
|
|
|
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
* This program may not be sold or used commercially without prior written
|
|
|
|
|
* permission from the authors.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define SAFE_COASTS /* Schiffe an der K<>ste treiben nicht ab */
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
#include "movement.h"
|
|
|
|
|
|
|
|
|
|
#include "alchemy.h"
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#include "border.h"
|
|
|
|
|
#include "build.h"
|
|
|
|
|
#include "building.h"
|
|
|
|
|
#include "curse.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "faction.h"
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#include "item.h"
|
|
|
|
|
#include "karma.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "magic.h"
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#include "message.h"
|
|
|
|
|
#include "plane.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "race.h"
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#include "region.h"
|
|
|
|
|
#include "render.h"
|
2002-03-02 20:26:39 +01:00
|
|
|
|
#include "spell.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "ship.h"
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#include "skill.h"
|
|
|
|
|
#include "unit.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* util includes */
|
2004-02-09 23:20:40 +01:00
|
|
|
|
#include <util/goodies.h>
|
2004-02-22 15:42:24 +01:00
|
|
|
|
#include <util/language.h>
|
2004-02-09 23:20:40 +01:00
|
|
|
|
#include <util/rand.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
/* attributes includes */
|
|
|
|
|
#include <attributes/follow.h>
|
|
|
|
|
#include <attributes/targetregion.h>
|
2002-09-29 20:11:08 +02:00
|
|
|
|
#include <attributes/at_movement.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* TODO: boder_type::move() must be able to change target (wisps) */
|
|
|
|
|
extern border_type bt_wisps;
|
|
|
|
|
extern item_type it_demonseye;
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
typedef struct traveldir {
|
|
|
|
|
int no;
|
|
|
|
|
direction_t dir;
|
|
|
|
|
int age;
|
|
|
|
|
} traveldir;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static attrib_type at_traveldir = {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"traveldir",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE, /* Weil normales Aging an ung<6E>nstiger Stelle */
|
|
|
|
|
DEFAULT_WRITE,
|
|
|
|
|
DEFAULT_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a_traveldir_new_init(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(1, sizeof(traveldir));
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a_traveldir_new_finalize(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
free(a->data.v);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a_traveldir_new_age(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
|
|
|
|
|
t->age--;
|
|
|
|
|
if(t->age == 0) return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a_traveldir_new_read(attrib *a, FILE *f)
|
|
|
|
|
{
|
2002-04-07 02:44:01 +02:00
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
int no, age, dir;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-07 02:44:01 +02:00
|
|
|
|
fscanf(f, "%d %d %d", &no, &dir, &age);
|
|
|
|
|
t->no = no;
|
|
|
|
|
t->dir = (direction_t)dir;
|
|
|
|
|
t->age = age;
|
|
|
|
|
return AT_READ_OK;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a_traveldir_new_write(const attrib *a, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
fprintf(f, "%d %d %d ", t->no, (int)t->dir, t->age);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_traveldir_new = {
|
|
|
|
|
"traveldir_new",
|
|
|
|
|
a_traveldir_new_init,
|
|
|
|
|
a_traveldir_new_finalize,
|
|
|
|
|
a_traveldir_new_age,
|
|
|
|
|
a_traveldir_new_write,
|
|
|
|
|
a_traveldir_new_read
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
direction_t
|
2001-09-05 21:40:40 +02:00
|
|
|
|
getdirection(const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-09-05 21:40:40 +02:00
|
|
|
|
return finddirection(getstrtoken(), lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
static attrib_type at_driveweight = {
|
|
|
|
|
"driveweight", NULL, NULL, NULL, NULL, NULL
|
|
|
|
|
};
|
|
|
|
|
|
2002-12-18 01:34:19 +01:00
|
|
|
|
static boolean
|
|
|
|
|
entrance_allowed(const struct unit * u, const struct region * r)
|
|
|
|
|
{
|
|
|
|
|
#ifdef REGIONOWNERS
|
|
|
|
|
unit * owner = region_owner(r);
|
|
|
|
|
if (owner==NULL || u->faction==owner->faction) return true;
|
|
|
|
|
if (alliedunit(owner, u->faction, HELP_TRAVEL)) return true;
|
|
|
|
|
if (is_enemy(u->faction, owner->faction)) return true;
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
- 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
|
|
|
|
int
|
2001-12-10 01:13:39 +01:00
|
|
|
|
personcapacity(const unit *u)
|
- 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
|
|
|
|
{
|
2002-04-21 11:23:05 +02:00
|
|
|
|
#if RACE_CAPACITY
|
|
|
|
|
int cap = u->race->weight+u->race->capacity;
|
|
|
|
|
#else
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int cap = u->race->weight+540;
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_TROLL)
|
2001-04-22 20:14:07 +02:00
|
|
|
|
cap += 540;
|
2002-02-06 09:06:02 +01:00
|
|
|
|
#if RACE_ADJUSTMENTS
|
2001-12-10 01:13:39 +01:00
|
|
|
|
else if(old_race(u->race) == RC_GOBLIN)
|
|
|
|
|
cap -= 100;
|
|
|
|
|
#endif
|
2002-04-21 11:23:05 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fspecial(u->faction, FS_QUICK))
|
2001-04-22 20:14:07 +02:00
|
|
|
|
cap -= 200;
|
- 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
|
|
|
|
|
|
|
|
|
return cap;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static int
|
|
|
|
|
eff_weight(const unit *u)
|
|
|
|
|
{
|
|
|
|
|
attrib *a = a_find(u->attribs, &at_driveweight);
|
|
|
|
|
|
|
|
|
|
if (a) return weight(u) + a->data.i;
|
|
|
|
|
|
|
|
|
|
return weight(u);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
ridingcapacity(unit * u)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
int wagen, pferde;
|
|
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
|
|
|
|
|
|
/* Man tr<74>gt sein eigenes Gewicht plus seine Kapazit<69>t! Die Menschen
|
|
|
|
|
* tragen nichts (siehe walkingcapacity). Ein Wagen z<EFBFBD>hlt nur, wenn er
|
|
|
|
|
* von zwei Pferden gezogen wird */
|
|
|
|
|
|
|
|
|
|
pferde = min(get_item(u, I_HORSE), effskill(u, SK_RIDING) * u->number * 2);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(fval(u->race, RCF_HORSE)) pferde += u->number;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* maximal diese Pferde k<>nnen zum Ziehen benutzt werden */
|
|
|
|
|
wagen = min(pferde / HORSESNEEDED, get_item(u, I_WAGON));
|
|
|
|
|
|
|
|
|
|
n = wagen * WAGONCAPACITY + pferde * HORSECAPACITY;
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
walkingcapacity(unit * u)
|
|
|
|
|
{
|
|
|
|
|
int n, personen, pferde, pferde_fuer_wagen;
|
|
|
|
|
int wagen, wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen;
|
|
|
|
|
/* Das Gewicht, welches die Pferde tragen, plus das Gewicht, welches
|
|
|
|
|
* die Leute tragen */
|
|
|
|
|
|
|
|
|
|
pferde = get_item(u, I_HORSE);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fval(u->race, RCF_HORSE)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
pferde += u->number;
|
|
|
|
|
personen = 0;
|
|
|
|
|
} else {
|
|
|
|
|
personen = u->number;
|
|
|
|
|
}
|
|
|
|
|
wagen = get_item(u, I_WAGON);
|
|
|
|
|
|
|
|
|
|
pferde_fuer_wagen = min(pferde, effskill(u, SK_RIDING) * u->number * 4);
|
|
|
|
|
|
|
|
|
|
/* maximal diese Pferde k<>nnen zum Ziehen benutzt werden */
|
|
|
|
|
|
|
|
|
|
wagen_mit_pferden = min(wagen, pferde_fuer_wagen / HORSESNEEDED);
|
|
|
|
|
|
|
|
|
|
n = wagen_mit_pferden * WAGONCAPACITY;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_TROLL) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* 4 Trolle ziehen einen Wagen. */
|
|
|
|
|
/* Unbesetzte Wagen feststellen */
|
|
|
|
|
wagen_ohne_pferde = wagen - wagen_mit_pferden;
|
|
|
|
|
|
|
|
|
|
/* Genug Trolle, um die Restwagen zu ziehen? */
|
|
|
|
|
wagen_mit_trollen = min(u->number / 4, wagen_ohne_pferde);
|
|
|
|
|
|
|
|
|
|
/* Wagenkapazit<69>t hinzuz<75>hlen */
|
|
|
|
|
n += wagen_mit_trollen * WAGONCAPACITY;
|
|
|
|
|
wagen_ohne_pferde -= wagen_mit_trollen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n += pferde * HORSECAPACITY;
|
- 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
|
|
|
|
n += personen * personcapacity(u);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
/* Goliathwasser */
|
- 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
|
|
|
|
n += get_effect(u, oldpotiontype[P_STRONG]) * personcapacity(u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n += min(get_item(u, I_TROLLBELT), u->number) * STRENGTHCAPACITY;
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
canwalk(unit * u)
|
|
|
|
|
{
|
|
|
|
|
int wagen, maxwagen;
|
|
|
|
|
int pferde, maxpferde;
|
|
|
|
|
|
2002-04-07 10:20:27 +02:00
|
|
|
|
/* workaround: monsters are too stupid to drop items, therefore they have
|
|
|
|
|
* infinite carrying capacity */
|
|
|
|
|
|
|
|
|
|
if (u->faction->no == 0) return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
wagen = get_item(u, I_WAGON);
|
|
|
|
|
pferde = get_item(u, I_HORSE);
|
|
|
|
|
|
|
|
|
|
maxwagen = effskill(u, SK_RIDING) * u->number * 2;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_TROLL) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
maxwagen = max(maxwagen, u->number / 4);
|
|
|
|
|
}
|
|
|
|
|
maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number;
|
|
|
|
|
|
|
|
|
|
if (pferde > maxpferde)
|
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
|
|
if (walkingcapacity(u) - eff_weight(u) >= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Stimmt das Gewicht, impliziert dies hier, da<64> alle Wagen ohne
|
|
|
|
|
* Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat
|
|
|
|
|
* die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen
|
|
|
|
|
* als erlaubt. */
|
|
|
|
|
|
|
|
|
|
if (wagen > maxwagen)
|
|
|
|
|
return 3;
|
|
|
|
|
/* Es mu<6D> nicht zwingend an den Wagen liegen, aber egal... (man
|
|
|
|
|
* k<EFBFBD>nnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als
|
|
|
|
|
* Fracht draufpa<EFBFBD>t) */
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
canfly(unit *u)
|
|
|
|
|
{
|
2002-09-29 20:11:08 +02:00
|
|
|
|
if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(get_item(u, I_HORSE)) return false;
|
|
|
|
|
|
|
|
|
|
if(get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4)
|
|
|
|
|
return true;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fval(u->race, RCF_FLY)) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-09-29 20:11:08 +02:00
|
|
|
|
if (get_movement(&u->attribs, MV_FLY)) return true;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
canswim(unit *u)
|
|
|
|
|
{
|
2002-09-29 20:11:08 +02:00
|
|
|
|
if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (get_item(u, I_HORSE)) return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if(fspecial(u->faction, FS_AMPHIBIAN)) return true;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race->flags & RCF_FLY) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race->flags & RCF_SWIM) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-09-29 20:11:08 +02:00
|
|
|
|
if (get_movement(&u->attribs, MV_FLY)) return true;
|
|
|
|
|
|
|
|
|
|
if (get_movement(&u->attribs, MV_SWIM)) return true;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
canride(unit * u)
|
|
|
|
|
{
|
|
|
|
|
int pferde, maxpferde, unicorns, maxunicorns;
|
|
|
|
|
int skill = effskill(u, SK_RIDING);
|
|
|
|
|
|
|
|
|
|
unicorns = get_item(u, I_UNICORN);
|
|
|
|
|
pferde = get_item(u, I_HORSE);
|
|
|
|
|
maxunicorns = (skill/5) * u->number;
|
|
|
|
|
maxpferde = skill * u->number * 2;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(!(u->race->flags & RCF_HORSE)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
&& ((pferde == 0 && unicorns == 0)
|
|
|
|
|
|| pferde > maxpferde || unicorns > maxunicorns)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ridingcapacity(u) - eff_weight(u) >= 0) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(pferde == 0 && unicorns >= u->number && !(u->race->flags & RCF_HORSE)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cansail(const region * r, ship * sh)
|
|
|
|
|
{
|
|
|
|
|
int n = 0, p = 0;
|
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
/* sonst ist construction:: size nicht ship_type::maxsize */
|
|
|
|
|
assert(!sh->type->construction || sh->type->construction->improvement==NULL);
|
|
|
|
|
|
|
|
|
|
if (sh->type->construction && sh->size!=sh->type->construction->maxsize)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
2002-11-25 16:30:51 +01:00
|
|
|
|
getshipweight(sh, &n, &p);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) {
|
|
|
|
|
if (sh->type->cargo>500*100)
|
|
|
|
|
assert(!"Ein Schiff wurde verzaubert, das zu gro<72> ist");
|
|
|
|
|
if (n > 10000) return false;
|
|
|
|
|
}
|
|
|
|
|
if (n > shipcapacity(sh)) return false;
|
|
|
|
|
if (p > sh->type->cabins) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
enoughsailors(region * r, ship * sh)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
unit *u;
|
|
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (u->ship == sh)
|
|
|
|
|
n += eff_skill(u, SK_SAILING, r) * u->number;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return n >= sh->type->sumskill;
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
do_maelstrom(region *r, unit *u)
|
|
|
|
|
{
|
|
|
|
|
int damage;
|
|
|
|
|
|
|
|
|
|
damage = rand()%150 - eff_skill(u, SK_SAILING, r)*5;
|
|
|
|
|
|
|
|
|
|
if(damage <= 0) {
|
|
|
|
|
add_message(&u->faction->msgs,
|
|
|
|
|
new_message(u->faction, "entermaelstrom%r:region%h:ship%i:damage%i:sink", r, u->ship, damage, 1));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
damage_ship(u->ship, 0.01*damage);
|
|
|
|
|
|
|
|
|
|
if (u->ship->damage >= u->ship->size * DAMAGE_SCALE) {
|
2002-04-07 02:44:01 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("entermaelstrom",
|
|
|
|
|
"region ship damage sink", r, u->ship, damage, 1));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
destroy_ship(u->ship, r);
|
|
|
|
|
} else {
|
2002-04-07 02:44:01 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("entermaelstrom",
|
|
|
|
|
"region ship damage sink", r, u->ship, damage, 0));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
travelthru(unit * u, region * r)
|
|
|
|
|
{
|
|
|
|
|
attrib *ru = a_add(&r->attribs, a_new(&at_travelunit));
|
|
|
|
|
|
|
|
|
|
ru->data.v = u;
|
|
|
|
|
u->faction->first = 0;
|
|
|
|
|
u->faction->last = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ship *
|
|
|
|
|
move_ship(ship * sh, region * from, region * to, region ** route)
|
|
|
|
|
{
|
|
|
|
|
unit *u = from->units;
|
|
|
|
|
unit **ulist = &to->units;
|
|
|
|
|
direction_t dir;
|
|
|
|
|
attrib *a;
|
|
|
|
|
|
2002-04-07 02:44:01 +02:00
|
|
|
|
if (from!=to) {
|
|
|
|
|
translist(&from->ships, &to->ships, sh);
|
|
|
|
|
sh->region = to;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
while (u) {
|
|
|
|
|
unit *nu = u->next;
|
|
|
|
|
|
|
|
|
|
if (u->ship == sh)
|
|
|
|
|
{
|
|
|
|
|
if (route) {
|
|
|
|
|
region **ri = route;
|
|
|
|
|
region **rn;
|
|
|
|
|
|
|
|
|
|
while (*ri) {
|
|
|
|
|
rn = ri+1;
|
|
|
|
|
if(*rn) {
|
|
|
|
|
dir = reldirection(*ri, *rn);
|
|
|
|
|
a = a_find((*ri)->attribs, &at_traveldir_new);
|
|
|
|
|
while (a) {
|
2001-08-12 10:23:13 +02:00
|
|
|
|
if(((traveldir *)(a->data.v))->no == sh->no) break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a->nexttype;
|
|
|
|
|
}
|
|
|
|
|
if(!a) {
|
|
|
|
|
a = a_add(&((*ri)->attribs), a_new(&at_traveldir_new));
|
|
|
|
|
{
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
t->no = sh->no;
|
|
|
|
|
t->dir = dir;
|
|
|
|
|
t->age = 2;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
t->dir = dir;
|
|
|
|
|
t->age = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
travelthru(u, *ri++);
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
if (from!=to) {
|
|
|
|
|
u->ship = NULL; /* damit move_unit() kein leave() macht */
|
|
|
|
|
move_unit(u, to, ulist);
|
|
|
|
|
ulist = &u->next;
|
|
|
|
|
u->ship = sh;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (route && eff_skill(u, SK_SAILING, from) >= 1) {
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(u, SK_SAILING, u->number);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
u = nu;
|
|
|
|
|
}
|
|
|
|
|
return sh;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
drifting_ships(region * r)
|
|
|
|
|
{
|
|
|
|
|
direction_t d;
|
|
|
|
|
ship *sh, *sh2;
|
|
|
|
|
unit *captain;
|
|
|
|
|
region * route[2] = { 0, 0 };
|
|
|
|
|
|
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
|
|
|
|
for (sh = r->ships; sh;) {
|
|
|
|
|
sh2 = sh->next;
|
|
|
|
|
|
|
|
|
|
/* Schiff schon abgetrieben oder durch Zauber gesch<63>tzt? */
|
2002-02-06 09:06:02 +01:00
|
|
|
|
if (fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
sh = sh2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Kapit<69>n bestimmen */
|
|
|
|
|
for (captain = r->units; captain; captain = captain->next)
|
|
|
|
|
if (captain->ship == sh
|
|
|
|
|
&& eff_skill(captain, SK_SAILING, r) >= sh->type->cptskill)
|
|
|
|
|
break;
|
|
|
|
|
/* Kapit<69>n da? Besch<63>digt? Gen<65>gend Matrosen?
|
|
|
|
|
* Gen<EFBFBD>gend leicht? Dann ist alles OK. */
|
|
|
|
|
|
|
|
|
|
assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
|
|
|
|
if (captain && sh->size==sh->type->construction->maxsize && enoughsailors(r, sh) && cansail(r, sh)) {
|
|
|
|
|
sh = sh2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Leuchtturm: Ok. */
|
|
|
|
|
if (check_leuchtturm(r, NULL)) {
|
|
|
|
|
sh = sh2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Auswahl einer Richtung: Zuerst auf Land, dann
|
|
|
|
|
* zuf<EFBFBD>llig. Falls unm<EFBFBD>gliches Resultat: vergi<EFBFBD> es. */
|
|
|
|
|
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; d++)
|
|
|
|
|
if (rconnect(r, d) && rterrain(rconnect(r, d)) != T_OCEAN)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (d == MAXDIRECTIONS)
|
|
|
|
|
d = (direction_t)(rand() % MAXDIRECTIONS);
|
|
|
|
|
|
|
|
|
|
if (!rconnect(r, d)) {
|
|
|
|
|
sh = sh2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
region * r2 = rconnect(r, d);
|
|
|
|
|
int c = 0;
|
|
|
|
|
while (sh->type->coast[c]!=NOTERRAIN) {
|
|
|
|
|
if (rterrain(r2) == sh->type->coast[c]) break;
|
|
|
|
|
++c;
|
|
|
|
|
}
|
|
|
|
|
if (sh->type->coast[c]==NOTERRAIN) {
|
|
|
|
|
sh = sh2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!(terrain[rterrain(rconnect(r, d))].flags & SAIL_INTO)) {
|
|
|
|
|
sh = sh2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Das Schiff und alle Einheiten darin werden nun von r
|
|
|
|
|
* nach rconnect(r, d) verschoben. Danach eine Meldung. */
|
|
|
|
|
#if 0
|
|
|
|
|
/* ich bin fast sicher, das man das nicht braucht. (enno) */
|
|
|
|
|
for (f = factions; f; f = f->next)
|
|
|
|
|
freset(f, FL_DH);
|
|
|
|
|
#endif
|
2002-02-06 09:06:02 +01:00
|
|
|
|
if (fval(sh, SF_DRIFTED)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* wenn schon einmal abgetrieben, dann durchreise eintragen */
|
|
|
|
|
route[0] = r;
|
|
|
|
|
sh = move_ship(sh, r, rconnect(r, d), route);
|
|
|
|
|
} else sh = move_ship(sh, r, rconnect(r, d), NULL);
|
|
|
|
|
if (!sh) {
|
|
|
|
|
sh = sh2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-06 09:06:02 +01:00
|
|
|
|
fset(sh, SF_DRIFTED);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (rterrain(rconnect(r, d)) != T_OCEAN) {
|
|
|
|
|
/* Alle Attribute
|
|
|
|
|
* sicherheitshalber loeschen und
|
|
|
|
|
* gegebenenfalls neu setzen. */
|
|
|
|
|
sh->coast = back[d];
|
|
|
|
|
}
|
|
|
|
|
damage_ship(sh, 0.02);
|
|
|
|
|
|
|
|
|
|
if (sh->damage>=sh->size * DAMAGE_SCALE)
|
|
|
|
|
destroy_ship(sh, rconnect(r, d));
|
|
|
|
|
|
|
|
|
|
sh = sh2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
coords_or_direction(region *r, faction *f, int dir)
|
|
|
|
|
{
|
2001-02-09 14:53:53 +01:00
|
|
|
|
static char lbuf[32];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
plane *pl = getplane(r);
|
|
|
|
|
|
|
|
|
|
if(fval(pl, PFL_NOCOORDS)) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
strcpy(lbuf, locale_string(f->locale, directions[dir]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2001-02-09 14:53:53 +01:00
|
|
|
|
sprintf(lbuf, "(%d,%d)",region_x(r,f), region_y(r,f));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-02-09 14:53:53 +01:00
|
|
|
|
return lbuf;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
ship_in_storm(unit *cap, region *next_point)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if(is_cursed(cap->ship->attribs, C_SHIP_NODRIFT, 0)) return;
|
|
|
|
|
|
|
|
|
|
add_message(&cap->faction->msgs,
|
|
|
|
|
new_message(cap->faction, "storm%h:ship%r:region%i:sink",
|
|
|
|
|
cap->ship, next_point, cap->ship->damage>=cap->ship->size * DAMAGE_SCALE));
|
|
|
|
|
|
|
|
|
|
/* Ver<65>nderung der Drehrichtung */
|
|
|
|
|
i = rand()%2==0?1:-1;
|
|
|
|
|
#if 0 /* make a temporary attribute for this */
|
|
|
|
|
cap->wants += i;
|
|
|
|
|
#endif
|
|
|
|
|
/* Merken f<>r Sperren des Anlandens. */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if(i) fset(cap, UFL_STORM);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define USE_CREATION 0
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
present(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
return (boolean) (u && u->region == r);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
caught_target(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_follow);
|
|
|
|
|
|
|
|
|
|
/* Verfolgungen melden */
|
|
|
|
|
/* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter
|
|
|
|
|
* Umstaenden eine Warnung. */
|
|
|
|
|
|
|
|
|
|
if (a) {
|
|
|
|
|
unit * target = (unit*)a->data.v;
|
|
|
|
|
|
|
|
|
|
if (!present(r, target)) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"followfail%u:unit%u:follower", target, u));
|
2002-09-02 22:36:12 +02:00
|
|
|
|
} else if (!alliedunit(target, u->faction, HELP_ALL)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
&& cansee(target->faction, r, u, 0))
|
|
|
|
|
{
|
|
|
|
|
add_message(&target->faction->msgs, new_message(target->faction,
|
|
|
|
|
"followdetect%u:unit%u:follower", target, u));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TODO: Unsichtbarkeit bedenken ! */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static unit *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
bewegung_blockiert_von(unit * reisender, region * r)
|
|
|
|
|
{
|
2001-09-05 21:40:40 +02:00
|
|
|
|
unit *u;
|
|
|
|
|
int perception = 0;
|
|
|
|
|
boolean contact = false;
|
|
|
|
|
unit * guard = NULL;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fval(reisender->race, RCF_ILLUSIONARY)) return NULL;
|
2001-09-05 21:40:40 +02:00
|
|
|
|
for (u=r->units;u && !contact;u=u->next) {
|
|
|
|
|
if (getguard(u) & GUARD_TRAVELTHRU) {
|
|
|
|
|
int sk = eff_skill(u, SK_OBSERVATION, r);
|
|
|
|
|
if (get_item(reisender, I_RING_OF_INVISIBILITY) >= reisender->number &&
|
|
|
|
|
!get_item(u, I_AMULET_OF_TRUE_SEEING)) continue;
|
|
|
|
|
if (u->faction==reisender->faction
|
|
|
|
|
|| ucontact(u, reisender)
|
2002-09-02 22:36:12 +02:00
|
|
|
|
|| alliedunit(u, reisender->faction, HELP_GUARD))
|
2001-09-05 21:40:40 +02:00
|
|
|
|
{
|
|
|
|
|
contact = true;
|
|
|
|
|
} else if (sk>=perception) {
|
|
|
|
|
perception = sk;
|
|
|
|
|
guard = u;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
if (!contact && guard) {
|
2004-02-09 23:20:40 +01:00
|
|
|
|
double prob = 0.3; /* 30% base chance */
|
|
|
|
|
prob += 0.1 * (perception - eff_stealth(reisender, r));
|
|
|
|
|
prob += 0.1 * max(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-09 23:20:40 +01:00
|
|
|
|
if (chance(prob)) {
|
2001-09-05 21:40:40 +02:00
|
|
|
|
return guard;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
is_guardian(unit * u2, unit *u, unsigned int mask)
|
|
|
|
|
{
|
|
|
|
|
if (u2->faction != u->faction
|
2002-04-21 19:22:48 +02:00
|
|
|
|
&& getguard(u2)&mask
|
|
|
|
|
&& u2->number
|
|
|
|
|
&& !ucontact(u2, u) && !besieged(u2)
|
2002-09-02 22:36:12 +02:00
|
|
|
|
&& alliedunit(u2, u->faction, HELP_GUARD) != HELP_GUARD
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef WACH_WAFF
|
2002-04-21 19:22:48 +02:00
|
|
|
|
&& armedmen(u2)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2002-04-21 19:22:48 +02:00
|
|
|
|
&& cansee(u2->faction, u->region, u, 0)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
) return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
is_guarded(region * r, unit * u, unsigned int mask)
|
|
|
|
|
{
|
|
|
|
|
unit *u2;
|
|
|
|
|
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (is_guardian(u2, u, mask)) return u2;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static const char *shortdirections[MAXDIRECTIONS] =
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-09-05 21:40:40 +02:00
|
|
|
|
"dir_nw",
|
|
|
|
|
"dir_ne",
|
|
|
|
|
"dir_east",
|
|
|
|
|
"dir_se",
|
|
|
|
|
"dir_sw",
|
|
|
|
|
"dir_west"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cycle_route(unit *u, int gereist)
|
|
|
|
|
{
|
|
|
|
|
int cm = 0;
|
|
|
|
|
char tail[1024];
|
2002-09-22 17:40:33 +02:00
|
|
|
|
char neworder[2048];
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *token;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
direction_t d = NODIRECTION;
|
|
|
|
|
boolean paused = false;
|
|
|
|
|
boolean pause;
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (igetkeyword(u->thisorder, u->faction->locale) != K_ROUTE) return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
tail[0] = '\0';
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
strcpy(neworder, locale_string(u->faction->locale, keywords[K_ROUTE]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (cm=0;;++cm) {
|
2002-09-02 22:36:12 +02:00
|
|
|
|
const struct locale * lang = u->faction->locale;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
pause = false;
|
|
|
|
|
token = getstrtoken();
|
2001-09-05 21:40:40 +02:00
|
|
|
|
d = finddirection(token, lang);
|
2001-02-18 13:20:37 +01:00
|
|
|
|
if(d == D_PAUSE) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
pause = true;
|
2001-02-18 13:20:37 +01:00
|
|
|
|
} else if (d==NODIRECTION) {
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
if (cm<gereist) {
|
|
|
|
|
/* hier sollte keine PAUSE auftreten */
|
2001-04-22 20:14:07 +02:00
|
|
|
|
assert(!pause);
|
2001-05-27 18:44:16 +02:00
|
|
|
|
if (!pause) strcat(strcat(tail, " "), LOC(lang, shortdirections[d]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-09-22 17:40:33 +02:00
|
|
|
|
else if (strlen(neworder)>sizeof(neworder)/2) break;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
else if (cm==gereist && !paused && pause) {
|
|
|
|
|
strcat(strcat(tail, " "), LOC(lang, parameters[P_PAUSE]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
paused=true;
|
|
|
|
|
}
|
|
|
|
|
else if (pause) {
|
2001-04-22 20:14:07 +02:00
|
|
|
|
/* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist
|
|
|
|
|
* hier keine normale direction), muss jede PAUSE einzeln
|
|
|
|
|
* herausgefiltert und explizit gesetzt werden */
|
|
|
|
|
strcat(strcat(neworder, " "), LOC(lang, parameters[P_PAUSE]));
|
|
|
|
|
} else {
|
|
|
|
|
strcat(strcat(neworder, " "), LOC(lang, shortdirections[d]));
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strcat(neworder, tail);
|
|
|
|
|
set_string(&u->lastorder, neworder);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
init_drive(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
unit *u, *ut, *u2;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
strlist *S;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int w;
|
|
|
|
|
|
|
|
|
|
for (r=regions; r; r=r->next) {
|
2001-04-01 08:58:45 +02:00
|
|
|
|
/* This is just a simple check for non-corresponding K_TRANSPORT/
|
|
|
|
|
* K_DRIVE. This is time consuming for an error check, but there
|
|
|
|
|
* doesn't seem to be an easy way to speed this up. */
|
|
|
|
|
|
|
|
|
|
for(u=r->units; u; u=u->next) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if(igetkeyword(u->thisorder, u->faction->locale) == K_DRIVE && !fval(u, UFL_LONGACTION) && !fval(u, UFL_HUNGER)) {
|
2001-04-01 08:58:45 +02:00
|
|
|
|
boolean found = false;
|
2001-04-26 19:41:06 +02:00
|
|
|
|
ut = getunit(r, u->faction);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
if(!ut) {
|
2003-03-08 21:57:38 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 63, MSG_MOVE);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
for (S = ut->orders; S; S = S->next) {
|
|
|
|
|
if (igetkeyword(S->s, u->faction->locale) == K_TRANSPORT) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (getunit(r, ut->faction) == u) {
|
2001-09-05 21:40:40 +02:00
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(found == false) {
|
|
|
|
|
if(cansee(u->faction, r, ut, 0)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 286, MSG_MOVE);
|
|
|
|
|
} else {
|
2003-03-08 21:57:38 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 63, MSG_MOVE);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This calculates the weights of all transported units and
|
|
|
|
|
* adds them to an internal counter which is used by travel() to
|
|
|
|
|
* calculate effective weight and movement. */
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (u=r->units; u; u=u->next) {
|
|
|
|
|
w = 0;
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
for (S = u->orders; S; S = S->next) if(igetkeyword(S->s, u->faction->locale) == K_TRANSPORT) {
|
2001-04-26 19:41:06 +02:00
|
|
|
|
ut = getunit(r, u->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(!ut) continue;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (igetkeyword(ut->thisorder, ut->faction->locale) == K_DRIVE && !fval(ut, UFL_LONGACTION) && !fval(ut, UFL_HUNGER)) {
|
2001-04-26 19:41:06 +02:00
|
|
|
|
u2 = getunit(r, u->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(u2 == u) {
|
|
|
|
|
w += weight(ut);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int *storms;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* in arbeit */
|
|
|
|
|
#define ETRAVEL_NOTALLOWED 1
|
|
|
|
|
#define ETRAVEL_NOSWIM 2
|
|
|
|
|
#define ETRAVEL_NORIDE 4
|
|
|
|
|
#define ETRAVEL_LEFTSHIP 8
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
cantravel(const unit *u, const region *from, const region * to, boolean (*allowed)(const struct region *, const struct region *))
|
|
|
|
|
{
|
|
|
|
|
/* basic allowed function */
|
|
|
|
|
if (allowed && !allowed(from, to)) return ETRAVEL_NOTALLOWED;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (u->ship && fval(u, UFL_OWNER) && rterrain(from)==T_OCEAN) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* wir sind auf einem schiff und auf dem ozean */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (rterrain(to)==T_OCEAN || (old_race(u->race) != RC_AQUARIAN && !dragon(u))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Drache oder Meermensch sind wir auch nicht */
|
|
|
|
|
return ETRAVEL_NOSWIM;
|
|
|
|
|
} else if (get_item(u, I_HORSE) > 0) {
|
|
|
|
|
return ETRAVEL_NORIDE|ETRAVEL_NOSWIM;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!u->ship && leftship(u) && is_guarded(from, u, GUARD_LANDING)) {
|
|
|
|
|
/* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */
|
|
|
|
|
return ETRAVEL_LEFTSHIP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
roadto(const region * r, const region * r2)
|
|
|
|
|
{
|
|
|
|
|
/* wenn es hier genug strassen gibt, und verbunden ist, und es dort
|
|
|
|
|
* genug strassen gibt, dann existiert eine strasse in diese richtung */
|
|
|
|
|
|
|
|
|
|
direction_t i;
|
|
|
|
|
|
|
|
|
|
if (!r || !r2) return false;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i != MAXDIRECTIONS; i++)
|
|
|
|
|
if (rconnect(r, i) == r2) {
|
2003-03-15 03:09:54 +01:00
|
|
|
|
if (terrain[rterrain(r)].roadreq==0) return false;
|
|
|
|
|
if (terrain[rterrain(r2)].roadreq==0) return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (rroad(r, i) < terrain[rterrain(r)].roadreq) return false;
|
|
|
|
|
if (rroad(r2, back[i]) < terrain[rterrain(r2)].roadreq) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
direction_t *
|
|
|
|
|
travel(region * first, unit * u, region * next, int flucht)
|
|
|
|
|
{
|
|
|
|
|
region *current = first;
|
|
|
|
|
int k, m, i, dh;
|
|
|
|
|
double dk;
|
|
|
|
|
unit *wache;
|
|
|
|
|
region *rv[MAXSPEED];
|
|
|
|
|
strlist *S;
|
|
|
|
|
unit *ut, *u2;
|
|
|
|
|
int gereist = 0;
|
|
|
|
|
static direction_t route[MAXSPEED];
|
2002-05-01 21:08:32 +02:00
|
|
|
|
static boolean init = false;
|
|
|
|
|
static const curse_type * speed_ct;
|
|
|
|
|
static const curse_type * fogtrap_ct;
|
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
speed_ct = ct_find("speed");
|
|
|
|
|
fogtrap_ct = ct_find("fogtrap");
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* tech:
|
|
|
|
|
*
|
|
|
|
|
* zu Fu<EFBFBD> reist man 1 Region, zu Pferd 2 Regionen. Mit Stra<EFBFBD>en reist
|
|
|
|
|
* man zu Fu<EFBFBD> 2, mit Pferden 3 weit.
|
|
|
|
|
*
|
|
|
|
|
* Berechnet wird das mit BPs. Zu Fu<EFBFBD> hat man 4 BPs, zu Pferd 6.
|
|
|
|
|
* Normalerweise verliert man 3 BP pro Region, bei Stra<EFBFBD>en nur 2 BP.
|
|
|
|
|
* Au<EFBFBD>erdem: Wenn Einheit transportiert, nur halbe BP */
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (rterrain(current)==T_OCEAN
|
2001-12-10 01:13:39 +01:00
|
|
|
|
&& !(u->race->flags & RCF_FLY) && rterrain(next) != T_OCEAN)
|
2001-04-01 08:58:45 +02:00
|
|
|
|
{ /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!(u->race->flags & RCF_SWIM) && old_race(u->race) != RC_AQUARIAN) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 44, MSG_MOVE);
|
|
|
|
|
return NULL;
|
|
|
|
|
} else {
|
|
|
|
|
if (u->ship && get_item(u, I_HORSE) > 0) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 67, MSG_MOVE);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
} else if (rterrain(current)!=T_OCEAN) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */
|
|
|
|
|
if (leftship(u) && is_guarded(current, u, GUARD_LANDING)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 70, MSG_MOVE);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->ship && !flucht && u->race->flags & RCF_SWIM) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 143, MSG_MOVE);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2003-07-29 11:48:03 +02:00
|
|
|
|
} else if (rterrain(next) == T_OCEAN && u->ship && fval(u->ship, SF_MOVED)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 13, MSG_MOVE);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2002-04-07 10:20:27 +02:00
|
|
|
|
|
|
|
|
|
switch (canwalk(u)) {
|
|
|
|
|
case 1:
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 57, MSG_MOVE);
|
|
|
|
|
return NULL;
|
|
|
|
|
case 2:
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 56, MSG_MOVE);
|
|
|
|
|
return NULL;
|
|
|
|
|
case 3:
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 42, MSG_MOVE);
|
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-04-07 10:20:27 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden
|
|
|
|
|
* dann nacheinander ausgef<EFBFBD>hrt. */
|
|
|
|
|
|
|
|
|
|
/* im array rv[] speichern wir die Regionen ab, durch die wir wandern. */
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
dk = u->race->speed;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (speed_ct) {
|
|
|
|
|
curse *c = get_curse(u->attribs, speed_ct);
|
2002-04-27 22:09:44 +02:00
|
|
|
|
if(c) {
|
|
|
|
|
int men = get_cursedmen(u, c);
|
|
|
|
|
dk *= 1.0 + (double)men/(double)u->number;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(canride(u)) {
|
|
|
|
|
case 1: /* Pferd */
|
|
|
|
|
k = (int)(dk*BP_RIDING);
|
|
|
|
|
break;
|
|
|
|
|
case 2: /* Einhorn */
|
|
|
|
|
k = (int)(dk*BP_UNICORN);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
2001-02-09 14:53:53 +01:00
|
|
|
|
int mp = 1;
|
- 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
|
|
|
|
|
|
|
|
|
/* faction special */
|
|
|
|
|
if(fspecial(u->faction, FS_QUICK))
|
|
|
|
|
mp = BP_RIDING;
|
2001-04-16 16:34:19 +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
|
|
|
|
/* Siebenmeilentee */
|
2001-09-05 21:40:40 +02:00
|
|
|
|
if (get_effect(u, oldpotiontype[P_FAST]) >= u->number) {
|
- 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
|
|
|
|
mp *= 2;
|
2001-09-05 21:40:40 +02:00
|
|
|
|
change_effect(u, oldpotiontype[P_FAST], -u->number);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +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
|
|
|
|
/* unicorn in inventory */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (u->number <= get_item(u, I_FEENSTIEFEL))
|
2001-02-09 14:53:53 +01:00
|
|
|
|
mp *= 2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell.
|
|
|
|
|
* Nicht kumulativ mit anderen Beschleunigungen! */
|
2001-02-09 14:53:53 +01:00
|
|
|
|
if ( mp == 1 && getplane(next) == astral_plane && is_mage(u)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(get_mage(u)->magietyp == M_ASTRAL
|
|
|
|
|
|| get_mage(u)->magietyp == M_TRAUM) {
|
2001-02-09 14:53:53 +01:00
|
|
|
|
mp *= 2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-02-09 14:53:53 +01:00
|
|
|
|
k = (int)(dk*mp*BP_WALKING);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
switch(old_race(u->race)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case RC_DRAGON:
|
|
|
|
|
case RC_WYRM:
|
|
|
|
|
case RC_FIREDRAGON:
|
|
|
|
|
case RC_BIRTHDAYDRAGON:
|
|
|
|
|
case RC_PSEUDODRAGON:
|
|
|
|
|
k = BP_DRAGON;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m = 0;
|
|
|
|
|
|
|
|
|
|
/* die n<>chste Region, in die man wandert, wird durch movewhere() aus
|
|
|
|
|
* der letzten Region bestimmt.
|
|
|
|
|
*
|
|
|
|
|
* Anfangen tun wir bei r. r2 ist beim ersten Durchlauf schon gesetzt
|
|
|
|
|
* (Parameter!), das Ziel des Schrittes. m z<EFBFBD>hlt die Schritte, k sind
|
|
|
|
|
* die noch m<EFBFBD>glichen Schritte, r3 die letzte g<EFBFBD>ltige, befahrene Region. */
|
|
|
|
|
|
|
|
|
|
while (next) {
|
|
|
|
|
direction_t dir = reldirection(current, next);
|
|
|
|
|
border * b = get_borders(current, next);
|
2001-02-19 17:45:23 +01:00
|
|
|
|
|
2004-01-19 00:52:57 +01:00
|
|
|
|
while (b!=NULL) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (b->type==&bt_wisps) {
|
2002-03-02 20:26:39 +01:00
|
|
|
|
wall_data * wd = (wall_data*)b->data;
|
|
|
|
|
if (wd->active) {
|
|
|
|
|
region * rl = rconnect(current, (direction_t)((dir+MAXDIRECTIONS-1)%MAXDIRECTIONS));
|
|
|
|
|
region * rr = rconnect(current, (direction_t)((dir+1)%MAXDIRECTIONS));
|
|
|
|
|
int j = rand() % 3;
|
|
|
|
|
if (j==0) break;
|
|
|
|
|
else if (j==1 && rl && landregion(rterrain(rl))==landregion(rterrain(next))) next = rl;
|
|
|
|
|
else if (j==2 && rr && landregion(rterrain(rr))==landregion(rterrain(next))) next = rr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-02-19 17:45:23 +01:00
|
|
|
|
if (b->type->move) b->type->move(b, u, current, next);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
if (current!=next) { /* !pause */
|
|
|
|
|
if (roadto(current, next))
|
|
|
|
|
k -= BP_ROAD;
|
|
|
|
|
else
|
|
|
|
|
k -= BP_NORMAL;
|
|
|
|
|
if (k<0) break;
|
|
|
|
|
/* r2 -> Zielregion, r3 -> Momentane Region */
|
2004-01-19 07:28:17 +01:00
|
|
|
|
if ((dir>=0 && move_blocked(u, current, dir))
|
2002-05-01 21:08:32 +02:00
|
|
|
|
|| curse_active(get_curse(current->attribs, fogtrap_ct)))
|
2002-03-03 11:51:24 +01:00
|
|
|
|
{
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("leavefail",
|
2004-01-19 00:52:57 +01:00
|
|
|
|
"unit region",
|
|
|
|
|
u, next));
|
2002-03-03 11:51:24 +01:00
|
|
|
|
}
|
2004-01-19 00:52:57 +01:00
|
|
|
|
if (!entrance_allowed(u, next)) {
|
2002-12-18 01:34:19 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("regionowned",
|
2004-01-19 00:52:57 +01:00
|
|
|
|
"unit region target",
|
|
|
|
|
u, current, next));
|
2002-12-18 01:34:19 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if ((wache = bewegung_blockiert_von(u, current)) != (unit *) NULL
|
|
|
|
|
&& gereist != 0)
|
|
|
|
|
{
|
2002-03-03 11:51:24 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard",
|
|
|
|
|
"unit region guard", u, current,
|
2001-09-05 21:40:40 +02:00
|
|
|
|
wache));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2002-05-01 21:08:32 +02:00
|
|
|
|
|
|
|
|
|
if (fval(u->race, RCF_ILLUSIONARY)) {
|
|
|
|
|
curse * c = get_curse(next->attribs, ct_find("antimagiczone"));
|
|
|
|
|
if (curse_active(c)) {
|
|
|
|
|
curse_changevigour(&next->attribs, c, - u->number);
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"illusionantimagic%u:unit", u));
|
|
|
|
|
destroy_unit(u);
|
|
|
|
|
return route;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* Ozeanfelder k<>nnen nur von Einheiten mit Schwimmen und ohne
|
|
|
|
|
* Pferde betreten werden. Drachen k<EFBFBD>nnen fliegen. */
|
|
|
|
|
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (rterrain(next) == T_OCEAN && !canswim(u)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
plane *pl = getplane(next);
|
2004-01-19 00:52:57 +01:00
|
|
|
|
if (pl!=NULL && fval(pl, PFL_NOCOORDS)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2004-01-19 00:52:57 +01:00
|
|
|
|
"detectoceandir%u:unit%i:direction", u, dir));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"detectocean%u:unit%r:region", u, next));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (terrain[rterrain(next)].flags & FORBIDDEN_LAND) {
|
|
|
|
|
plane *pl = getplane(next);
|
|
|
|
|
if(pl && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2004-01-19 00:52:57 +01:00
|
|
|
|
"detectforbiddendir%u:unit%i:direction", u, dir));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"detectforbidden%u:unit%r:region", u, next));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_INSECT && r_insectstalled(next) &&
|
2001-01-25 10:37:55 +01:00
|
|
|
|
!is_cursed(u->attribs, C_KAELTESCHUTZ,0)) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"detectforbidden%u:unit%r:region", u, next));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
rv[m] = next;
|
|
|
|
|
route[m] = dir;
|
|
|
|
|
m++;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
} else {
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = next;
|
|
|
|
|
if(!flucht) {
|
|
|
|
|
++gereist;
|
|
|
|
|
if (current==first) break; /* PAUSE beendet die Reise */
|
|
|
|
|
next = movewhere(current, u);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
route[m] = NODIRECTION;
|
|
|
|
|
|
|
|
|
|
if (gereist) {
|
|
|
|
|
int mode;
|
|
|
|
|
setguard(u, GUARD_NONE);
|
|
|
|
|
cycle_route(u, gereist);
|
|
|
|
|
|
|
|
|
|
buf[0] = 0;
|
|
|
|
|
|
|
|
|
|
if (flucht == 1)
|
|
|
|
|
mode = 0;
|
|
|
|
|
else if (canride(u)) {
|
|
|
|
|
mode = 1;
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(u, SK_RIDING, u->number);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else
|
|
|
|
|
mode = 2;
|
|
|
|
|
|
|
|
|
|
/* Haben Drachen ihr Ziel erreicht? */
|
2001-09-05 21:40:40 +02:00
|
|
|
|
if (u->faction->no==MONSTER_FACTION) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
attrib * ta = a_find(u->attribs, &at_targetregion);
|
|
|
|
|
if (ta && current == (region*)ta->data.v) {
|
|
|
|
|
a_remove(&u->attribs, ta);
|
|
|
|
|
set_string(&u->lastorder, "WARTEN");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* <20>ber die letzte Region braucht man keinen Bericht */
|
|
|
|
|
|
|
|
|
|
m--;
|
|
|
|
|
if (m > 0) {
|
|
|
|
|
dh = 0;
|
|
|
|
|
travelthru(u, first);
|
|
|
|
|
for (i = 0; i != m; i++) {
|
2001-09-05 21:40:40 +02:00
|
|
|
|
char * p;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (dh) {
|
|
|
|
|
if (i == m - 1)
|
|
|
|
|
scat(" und ");
|
|
|
|
|
else
|
|
|
|
|
scat(", ");
|
|
|
|
|
}
|
|
|
|
|
dh = 1;
|
|
|
|
|
travelthru(u, rv[i]);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
p = buf+strlen(buf);
|
|
|
|
|
MSG(("travelthru_trail", "region", rv[i]), p, sizeof(buf)-strlen(buf), u->faction->locale, u->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "travel%u:unit%i:mode%r:start%r:end%s:regions",
|
|
|
|
|
u, mode, first, current, strdup(buf)));
|
|
|
|
|
|
|
|
|
|
/* und jetzt noch die transportierten Einheiten verschieben */
|
|
|
|
|
|
|
|
|
|
for (S = u->orders; S; S = S->next) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (igetkeyword(S->s, u->faction->locale) == K_TRANSPORT) {
|
2001-04-26 19:41:06 +02:00
|
|
|
|
ut = getunit(first, u->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (ut) {
|
2001-02-17 16:02:50 +01:00
|
|
|
|
boolean found = false;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (igetkeyword(ut->thisorder, u->faction->locale) == K_DRIVE
|
2003-07-29 11:48:03 +02:00
|
|
|
|
&& !fval(ut, UFL_LONGACTION) && !fval(ut, UFL_HUNGER)) {
|
2001-04-26 19:41:06 +02:00
|
|
|
|
u2 = getunit(first, ut->faction);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
if(u2 == u) {
|
|
|
|
|
found = true;
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "transport%u:unit%u:target%r:start%r:end",
|
|
|
|
|
u, ut, first, current));
|
|
|
|
|
if(!(terrain[current->terrain].flags & WALK_INTO)
|
|
|
|
|
&& get_item(ut, I_HORSE)) {
|
|
|
|
|
cmistake(u, u->thisorder, 67, MSG_MOVE);
|
|
|
|
|
cmistake(ut, ut->thisorder, 67, MSG_MOVE);
|
2001-02-17 16:02:50 +01:00
|
|
|
|
continue;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
|
|
|
|
if(can_survive(ut, current)) {
|
|
|
|
|
for (i = 0; i != m; i++)
|
|
|
|
|
travelthru(ut, rv[i]);
|
|
|
|
|
move_unit(ut, current, NULL);
|
2001-02-17 16:02:50 +01:00
|
|
|
|
} else {
|
2001-04-01 08:58:45 +02:00
|
|
|
|
cmistake(u, u->thisorder, 287, MSG_MOVE);
|
|
|
|
|
cmistake(ut, ut->thisorder, 230, MSG_MOVE);
|
|
|
|
|
continue;
|
2001-02-17 16:02:50 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
if (!found) {
|
|
|
|
|
if(cansee(u->faction, u->region, ut, 0)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 90, MSG_MOVE);
|
|
|
|
|
} else {
|
2003-03-08 21:57:38 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 63, MSG_MOVE);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
if (ut) {
|
2003-03-08 21:57:38 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 63, MSG_MOVE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 99, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
move_unit(u, current, NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (flucht)
|
|
|
|
|
move_unit(u, current, NULL);
|
|
|
|
|
set_string(&u->thisorder, "");
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_LONGACTION);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
setguard(u, GUARD_NONE);
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u, UFL_FOLLOWING)) caught_target(current, u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return route;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
ship_ready(region * r, unit * u)
|
|
|
|
|
{
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (!fval(u, UFL_OWNER)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 146, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (eff_skill(u, SK_SAILING, r) < u->ship->type->cptskill) {
|
|
|
|
|
sprintf(buf, "Der Kapit<69>n mu<6D> mindestens Segeln %d haben, "
|
|
|
|
|
"um %s zu befehligen ", u->ship->type->cptskill,
|
|
|
|
|
u->ship->type->name[1]);
|
|
|
|
|
mistake(u, u->thisorder, buf, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
assert(u->ship->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
|
|
|
|
if (u->ship->size!=u->ship->type->construction->maxsize) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 15, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!enoughsailors(r, u->ship)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 1, MSG_MOVE);
|
|
|
|
|
/* mistake(u, u->thisorder,
|
|
|
|
|
"Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!cansail(r, u->ship)) {
|
|
|
|
|
if( is_cursed(u->ship->attribs, C_SHIP_FLYING, 0) )
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 17, MSG_MOVE);
|
|
|
|
|
else
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 18, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
2001-03-04 19:41:27 +01:00
|
|
|
|
owner_buildingtyp(const region * r, const building_type * bt)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
building *b;
|
|
|
|
|
unit *owner;
|
|
|
|
|
|
|
|
|
|
for (b = rbuildings(r); b; b = b->next) {
|
|
|
|
|
owner = buildingowner(r, b);
|
|
|
|
|
if (b->type == bt && owner != NULL) {
|
|
|
|
|
if (b->size >= bt->maxsize) {
|
|
|
|
|
return owner;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-04 19:41:27 +01:00
|
|
|
|
boolean
|
|
|
|
|
buildingtype_exists(const region * r, const building_type * bt)
|
|
|
|
|
{
|
|
|
|
|
building *b;
|
|
|
|
|
|
|
|
|
|
for (b = rbuildings(r); b; b = b->next) {
|
|
|
|
|
if (b->type == bt) {
|
|
|
|
|
if (b->size >= bt->maxsize) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-03-04 19:41:27 +01:00
|
|
|
|
check_working_buildingtype(const region * r, const building_type * bt)
|
|
|
|
|
{
|
|
|
|
|
building *b;
|
|
|
|
|
|
|
|
|
|
for (b = rbuildings(r); b; b = b->next) {
|
|
|
|
|
if (b->type == bt) {
|
|
|
|
|
if (b->size >= bt->maxsize && fval(b, BLD_WORKING)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Pr<50>ft, ob Ablegen von einer K<>ste in eine der erlaubten Richtungen erfolgt. */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
check_takeoff(ship *sh, region *from, region *to)
|
|
|
|
|
{
|
|
|
|
|
direction_t dir;
|
|
|
|
|
direction_t coast, coastl, coastr;
|
|
|
|
|
|
|
|
|
|
if (rterrain(from)!=T_OCEAN && sh->coast != NODIRECTION) {
|
|
|
|
|
coast = sh->coast;
|
|
|
|
|
dir = reldirection(from, to);
|
|
|
|
|
|
|
|
|
|
coastr = (direction_t)((coast+1) % MAXDIRECTIONS);
|
|
|
|
|
coastl = (direction_t)((coast+MAXDIRECTIONS-1) % MAXDIRECTIONS);
|
|
|
|
|
|
|
|
|
|
if(dir != coast && dir != coastl && dir != coastr
|
2002-03-27 22:49:27 +01:00
|
|
|
|
&& check_working_buildingtype(from, bt_find("harbour")) == false)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-03-04 19:41:27 +01:00
|
|
|
|
ship_allowed(const struct ship_type * type, region * r)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int c = 0;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (check_working_buildingtype(r, bt_find("harbour"))) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (c=0;type->coast[c]!=NOTERRAIN;++c) {
|
|
|
|
|
if (type->coast[c]==rterrain(r)) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static direction_t *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
sail(region * starting_point, unit * u, region * next_point, boolean move_on_land)
|
|
|
|
|
{
|
|
|
|
|
region *current_point, *last_point;
|
|
|
|
|
unit *u2, *hafenmeister;
|
|
|
|
|
item * trans = NULL;
|
|
|
|
|
int st, first = 1;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
int k, m, l, i, step = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int stormchance;
|
|
|
|
|
region *rv[MAXSPEED + 1];
|
2001-04-22 20:14:07 +02:00
|
|
|
|
region *tt[MAXSPEED + 1]; /* travelthru */
|
|
|
|
|
static direction_t route[MAXSPEED+1]; /* route[i] := direction from tt[i] to tt[i-1] */
|
2002-05-01 21:08:32 +02:00
|
|
|
|
static boolean init = false;
|
|
|
|
|
static const curse_type * fogtrap_ct;
|
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
fogtrap_ct = ct_find("fogtrap");
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (!ship_ready(starting_point, u))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden
|
- 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
|
|
|
|
* dann nacheinander ausgef<EFBFBD>hrt. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
k = shipspeed(u->ship, u);
|
|
|
|
|
|
|
|
|
|
l = 0;
|
|
|
|
|
m = 0;
|
|
|
|
|
|
|
|
|
|
last_point = starting_point;
|
|
|
|
|
current_point = starting_point;
|
|
|
|
|
|
|
|
|
|
/* die n<>chste Region, in die man segelt, wird durch movewhere() aus der
|
|
|
|
|
* letzten Region bestimmt.
|
|
|
|
|
*
|
|
|
|
|
* Anfangen tun wir bei starting_point. next_point ist beim ersten
|
|
|
|
|
* Durchlauf schon gesetzt (Parameter!). l z<EFBFBD>hlt gesichtete
|
|
|
|
|
* K<EFBFBD>stenstreifen, rv[] speichert die gesichteten K<EFBFBD>stenstreifen, m
|
|
|
|
|
* z<EFBFBD>hlt befahrene Felder, current_point ist die letzte g<EFBFBD>ltige,
|
|
|
|
|
* befahrene Region. */
|
2001-04-22 20:14:07 +02:00
|
|
|
|
tt[step] = starting_point;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-04-25 08:47:21 +02:00
|
|
|
|
while (current_point!=next_point && m < k && next_point)
|
2001-04-22 20:14:07 +02:00
|
|
|
|
{
|
2001-01-25 10:37:55 +01:00
|
|
|
|
direction_t dir = reldirection(current_point, next_point);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
|
2001-04-22 20:14:07 +02:00
|
|
|
|
if(terrain[rterrain(next_point)].flags & FORBIDDEN_LAND) {
|
|
|
|
|
plane *pl = getplane(next_point);
|
|
|
|
|
if(pl && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"sailforbiddendir%h:ship%i:direction",
|
|
|
|
|
u->ship, reldirection(current_point,next_point)));
|
|
|
|
|
} else {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"sailforbidden%h:ship%r:region", u->ship, next_point));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
if( !is_cursed(u->ship->attribs, C_SHIP_FLYING, 0)
|
|
|
|
|
&& !(u->ship->type->flags & SFL_FLY)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (rterrain(current_point) != T_OCEAN
|
|
|
|
|
&& rterrain(next_point) != T_OCEAN) {
|
|
|
|
|
plane *pl = getplane(next_point);
|
|
|
|
|
if(pl && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
sprintf(buf, "Die %s entdeckt, da<64> im %s Festland ist.",
|
2001-04-16 16:34:19 +02:00
|
|
|
|
shipname(u->ship), locale_string(u->faction->locale, directions[dir]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
sprintf(buf, "Die %s entdeckt, da<64> (%d,%d) Festland ist.",
|
|
|
|
|
shipname(u->ship), region_x(next_point,u->faction),
|
|
|
|
|
region_y(next_point,u->faction));
|
|
|
|
|
}
|
|
|
|
|
addmessage(0, u->faction, buf, MSG_MOVE, ML_WARN);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!(u->ship->type->flags & SFL_OPENSEA) && rterrain(next_point) == T_OCEAN) {
|
|
|
|
|
direction_t d;
|
|
|
|
|
for (d=0;d!=MAXDIRECTIONS;++d) {
|
|
|
|
|
region * rc = rconnect(next_point, d);
|
|
|
|
|
if (rterrain(rc) != T_OCEAN) break;
|
|
|
|
|
}
|
|
|
|
|
if (d==MAXDIRECTIONS) {
|
|
|
|
|
/* Schiff kann nicht aufs offene Meer */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 249, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(rterrain(current_point) != T_OCEAN
|
|
|
|
|
&& rterrain(next_point) == T_OCEAN) {
|
|
|
|
|
if(check_takeoff(u->ship, current_point, next_point) == false) {
|
|
|
|
|
/* Schiff kann nicht ablegen */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 182, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (move_on_land == false && rterrain(next_point) != T_OCEAN) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Falls Blockade, endet die Seglerei hier */
|
|
|
|
|
|
|
|
|
|
if (move_blocked(u, current_point, reldirection(current_point, next_point))
|
2002-05-01 21:08:32 +02:00
|
|
|
|
|| curse_active(get_curse(current_point->attribs, fogtrap_ct))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"sailfail%h:ship%r:region", u->ship, current_point));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!ship_allowed(u->ship->type, next_point)) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if(fval(u, UFL_STORM)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(!check_leuchtturm(current_point, NULL)) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"sailnolandingstorm%h:ship", u->ship));
|
|
|
|
|
damage_ship(u->ship, 0.10);
|
|
|
|
|
if (u->ship->damage>=u->ship->size * DAMAGE_SCALE) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"shipsink%h:ship", u->ship));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"sailnolanding%h:ship%r:region", u->ship, next_point));
|
|
|
|
|
damage_ship(u->ship, 0.10);
|
|
|
|
|
if (u->ship->damage>=u->ship->size * DAMAGE_SCALE) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"shipsink%h:ship", u->ship));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(terrain[rterrain(next_point)].flags & FORBIDDEN_LAND) {
|
|
|
|
|
plane *pl = getplane(next_point);
|
|
|
|
|
if(pl && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"sailforbiddendir%h:ship%i:direction",
|
|
|
|
|
u->ship, reldirection(current_point,next_point)));
|
|
|
|
|
/* sprintf(buf, "Die Mannschaft der %s weigert sich, in die Feuerwand "
|
|
|
|
|
"im %s zu fahren.",
|
|
|
|
|
shipname(u->ship), directions[dir]); */
|
|
|
|
|
} else {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"sailforbidden%h:ship%r:region", u->ship, next_point));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(is_cursed(next_point->attribs, C_MAELSTROM, 0)) {
|
|
|
|
|
do_maelstrom(next_point, u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stormchance = storms[month(0)] * 5 / shipspeed(u->ship, u);
|
|
|
|
|
if(check_leuchtturm(next_point, NULL)) stormchance /= 3;
|
|
|
|
|
#ifdef SAFE_COASTS
|
|
|
|
|
/* Sturm nur, wenn n<>chste Region Hochsee ist. */
|
|
|
|
|
if(rand()%10000 < stormchance) {
|
|
|
|
|
direction_t d;
|
|
|
|
|
for (d=0;d!=MAXDIRECTIONS;++d) {
|
|
|
|
|
region * r = rconnect(next_point, d);
|
|
|
|
|
if (rterrain(r)!=T_OCEAN) break;
|
|
|
|
|
}
|
|
|
|
|
if (d==MAXDIRECTIONS)
|
|
|
|
|
ship_in_storm(u, next_point);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
/* Sturm nur, wenn n<>chste Region keine Landregion ist. */
|
|
|
|
|
if(rand()%10000 < stormchance && next_point->terrain == T_OCEAN) {
|
|
|
|
|
ship_in_storm(u, next_point);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
} /* endif !flying */
|
|
|
|
|
|
|
|
|
|
/* Falls kein Problem, eines weiter ziehen */
|
2001-04-22 20:14:07 +02:00
|
|
|
|
route[step] = dir;
|
2001-05-27 18:50:16 +02:00
|
|
|
|
tt[step] = current_point; /* travelthrough */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u->ship, SF_MOVED);
|
2001-05-27 18:50:16 +02:00
|
|
|
|
step++;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
m++;
|
2001-09-05 21:40:40 +02:00
|
|
|
|
|
2001-05-27 18:50:16 +02:00
|
|
|
|
last_point = current_point;
|
|
|
|
|
current_point = next_point;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Falls eine K<>stenregion, dann in rv[] aufnehmen (die letzte
|
|
|
|
|
* K<EFBFBD>ste wird nachher nicht aufgelistet werden, wenn das
|
|
|
|
|
* Schiff dort seine Runde beendent!). */
|
|
|
|
|
if (rterrain(current_point) != T_OCEAN) {
|
|
|
|
|
rv[l] = current_point;
|
|
|
|
|
l++;
|
|
|
|
|
}
|
2001-04-25 08:47:21 +02:00
|
|
|
|
if (rterrain(current_point) != T_OCEAN && !is_cursed(u->ship->attribs, C_SHIP_FLYING, 0)) break;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
next_point = movewhere(current_point, u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-22 20:14:07 +02:00
|
|
|
|
route[step] = NODIRECTION;
|
|
|
|
|
/* at this point, step is the number of steps made. tt[step] is the final region. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Nun enth<74>lt current_point die Region, in der das Schiff seine Runde
|
|
|
|
|
* beendet hat. Wir generieren hier ein Ereignis f<EFBFBD>r den Spieler, das
|
|
|
|
|
* ihm sagt, bis wohin er gesegelt ist, falls er <EFBFBD>berhaupt vom Fleck
|
|
|
|
|
* gekommen ist. Das ist nicht der Fall, wenn er von der K<EFBFBD>ste ins
|
|
|
|
|
* Inland zu segeln versuchte */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u->ship, SF_MOVED)) {
|
2001-04-22 20:14:07 +02:00
|
|
|
|
ship * sh = u->ship;
|
|
|
|
|
/* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten
|
|
|
|
|
* transferiert wurden, kann der aktuelle Befehl gel<EFBFBD>scht werden. */
|
|
|
|
|
cycle_route(u, step);
|
|
|
|
|
set_string(&u->thisorder, "");
|
|
|
|
|
if (current_point->terrain != T_OCEAN && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) {
|
|
|
|
|
sh->coast = reldirection(current_point, last_point);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2001-04-22 20:14:07 +02:00
|
|
|
|
sh->coast = NODIRECTION;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
sprintf(buf, "Die %s ", shipname(sh));
|
|
|
|
|
if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) )
|
|
|
|
|
scat("fliegt");
|
|
|
|
|
else
|
|
|
|
|
scat("segelt");
|
|
|
|
|
scat(" von ");
|
|
|
|
|
scat(regionid(starting_point));
|
|
|
|
|
scat(" nach ");
|
|
|
|
|
scat(regionid(current_point));
|
|
|
|
|
|
|
|
|
|
/* Falls es Kuesten gibt, denen man entlang gefahren ist,
|
|
|
|
|
* sollen sie aufgefuehrt werden. Falls wir aber unseren Zug in
|
|
|
|
|
* einer Kuestenregion beendet haben, fuehren wir sie nicht mit
|
|
|
|
|
* auf - sie wird sowieso in allen Details im Report erwaehnt
|
|
|
|
|
* werden. */
|
|
|
|
|
|
|
|
|
|
if (rterrain(current_point) != T_OCEAN)
|
|
|
|
|
l--;
|
|
|
|
|
|
|
|
|
|
if (l > 0) {
|
|
|
|
|
if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) )
|
|
|
|
|
scat(". Dabei flog es <20>ber ");
|
|
|
|
|
else {
|
|
|
|
|
scat(". Dabei segelte es entlang der ");
|
|
|
|
|
if (l > 1)
|
|
|
|
|
scat("K<EFBFBD>sten");
|
|
|
|
|
else
|
|
|
|
|
scat("K<EFBFBD>ste");
|
|
|
|
|
scat(" von ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i != l; i++) {
|
|
|
|
|
scat(regionid(rv[i]));
|
|
|
|
|
if (i < l - 2)
|
|
|
|
|
scat(", ");
|
|
|
|
|
else if (i == l - 2)
|
|
|
|
|
scat(" und ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
scat(".");
|
|
|
|
|
|
|
|
|
|
addmessage(0, u->faction, buf, MSG_MOVE, ML_INFO);
|
|
|
|
|
|
|
|
|
|
/* Das Schiff und alle Einheiten darin werden nun von
|
|
|
|
|
* starting_point nach current_point verschoben */
|
|
|
|
|
|
|
|
|
|
/* Verfolgungen melden */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u, UFL_FOLLOWING)) caught_target(current_point, u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-07 02:44:01 +02:00
|
|
|
|
tt[step] = NULL;
|
|
|
|
|
sh = move_ship(sh, starting_point, current_point, tt);
|
|
|
|
|
|
|
|
|
|
/* Hafengeb<65>hren ? */
|
|
|
|
|
|
|
|
|
|
hafenmeister = owner_buildingtyp(current_point, bt_find("harbour"));
|
|
|
|
|
if (sh && hafenmeister != NULL) {
|
|
|
|
|
item * itm;
|
|
|
|
|
assert(trans==NULL);
|
|
|
|
|
for (u2 = current_point->units; u2; u2 = u2->next) {
|
|
|
|
|
if (u2->ship == u->ship &&
|
2002-09-02 22:36:12 +02:00
|
|
|
|
!alliedunit(hafenmeister, u->faction, HELP_GUARD)) {
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (effskill(hafenmeister, SK_OBSERVATION) > effskill(u2, SK_STEALTH)) {
|
|
|
|
|
for (itm=u2->items; itm; itm=itm->next) {
|
|
|
|
|
const luxury_type * ltype = resource2luxury(itm->type->rtype);
|
|
|
|
|
if (ltype!=NULL && itm->number>0) {
|
|
|
|
|
st = itm->number * effskill(hafenmeister, SK_TRADE) / 50;
|
|
|
|
|
st = min(itm->number, st);
|
|
|
|
|
|
|
|
|
|
if (st > 0) {
|
|
|
|
|
i_change(&u2->items, itm->type, -st);
|
|
|
|
|
i_change(&hafenmeister->items, itm->type, st);
|
|
|
|
|
i_add(&trans, i_new(itm->type, st));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
}
|
|
|
|
|
if (trans) {
|
|
|
|
|
sprintf(buf, "%s erhielt ", hafenmeister->name);
|
|
|
|
|
for (itm = trans; itm; itm=itm->next) {
|
|
|
|
|
if (first != 1) {
|
|
|
|
|
if (itm->next!=NULL && itm->next->next==NULL) {
|
|
|
|
|
scat(" und ");
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2002-04-07 02:44:01 +02:00
|
|
|
|
scat(", ");
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
first = 0;
|
|
|
|
|
icat(trans->number);
|
|
|
|
|
scat(" ");
|
|
|
|
|
if (itm->number == 1) {
|
|
|
|
|
scat(locale_string(default_locale, resourcename(itm->type->rtype, 0)));
|
|
|
|
|
} else {
|
|
|
|
|
scat(locale_string(default_locale, resourcename(itm->type->rtype, NMF_PLURAL)));
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
scat(" von der ");
|
|
|
|
|
scat(shipname(u->ship));
|
|
|
|
|
scat(".");
|
|
|
|
|
addmessage(0, u->faction, buf, MSG_COMMERCE, ML_INFO);
|
|
|
|
|
addmessage(0, hafenmeister->faction, buf, MSG_INCOME, ML_INFO);
|
|
|
|
|
while (trans) i_remove(&trans, trans);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return route;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
kapitaen(region * r, ship * sh)
|
|
|
|
|
{
|
|
|
|
|
unit *u;
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (u->ship == sh && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill)
|
|
|
|
|
return u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/* Segeln, Wandern, Reiten
|
|
|
|
|
* when this routine returns a non-zero value, movement for the region needs
|
|
|
|
|
* to be done again because of followers that got new MOVE orders.
|
|
|
|
|
* Setting FL_LONGACTION will prevent a unit from being handled more than once
|
|
|
|
|
* by this routine
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
move(region * r, unit * u, boolean move_on_land)
|
|
|
|
|
{
|
|
|
|
|
region *r2;
|
|
|
|
|
direction_t * route;
|
|
|
|
|
|
|
|
|
|
r2 = movewhere(r, u);
|
|
|
|
|
|
|
|
|
|
if (!r2) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 71, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2003-07-29 11:48:03 +02:00
|
|
|
|
else if (u->ship && fval(u, UFL_OWNER))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
route = sail(r, u, r2, move_on_land);
|
|
|
|
|
else
|
|
|
|
|
route = travel(r, u, r2, 0);
|
|
|
|
|
|
|
|
|
|
if (i_get(u->items, &it_demonseye)) {
|
|
|
|
|
direction_t d;
|
|
|
|
|
for (d=0;d!=MAXDIRECTIONS;++d) {
|
|
|
|
|
region * rc = rconnect(r2,d);
|
|
|
|
|
if (rc) {
|
|
|
|
|
sprintf(buf, "Im %s ist eine ungeheure magische Pr<50>senz zu versp<73>ren.",
|
2001-04-16 16:34:19 +02:00
|
|
|
|
locale_string(u->faction->locale, directions[back[d]]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
addmessage(rc, NULL, buf, MSG_EVENT, ML_IMPORTANT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (u->region!=r) fset(u, UFL_LONGACTION);
|
|
|
|
|
set_string(&u->thisorder, "");
|
2001-09-05 21:40:40 +02:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (fval(u, UFL_FOLLOWED) && route && route[0]!=NODIRECTION) {
|
|
|
|
|
int followers = 0;
|
|
|
|
|
unit *up;
|
|
|
|
|
for (up=r->units;up;up=up->next) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(up, UFL_FOLLOWING) && !fval(up, UFL_LONGACTION)) {
|
2004-02-22 15:42:24 +01:00
|
|
|
|
const attrib * a = a_findc(up->attribs, &at_follow);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (a && a->data.v==u) {
|
|
|
|
|
/* wir basteln ihm ein NACH */
|
|
|
|
|
int k, i = 0;
|
2001-09-05 21:40:40 +02:00
|
|
|
|
strcpy(buf, locale_string(up->faction->locale, keywords[K_MOVE]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
while (route[i]!=NODIRECTION)
|
2001-09-05 21:40:40 +02:00
|
|
|
|
strcat(strcat(buf, " "), locale_string(up->faction->locale, directions[route[i++]]));
|
|
|
|
|
set_string(&up->thisorder, buf);
|
|
|
|
|
k = igetkeyword(up->thisorder, up->faction->locale);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
assert(k==K_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
++followers;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return followers;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-01-11 10:21:06 +01:00
|
|
|
|
typedef struct piracy_data {
|
|
|
|
|
const struct faction * follow;
|
|
|
|
|
direction_t dir;
|
|
|
|
|
} piracy_data;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
piracy_init(struct attrib * a)
|
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(1, sizeof(piracy_data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
piracy_done(struct attrib * a)
|
|
|
|
|
{
|
|
|
|
|
free(a->data.v);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static attrib_type at_piracy_direction = {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"piracy_direction",
|
2004-01-11 10:21:06 +01:00
|
|
|
|
piracy_init,
|
|
|
|
|
piracy_done,
|
2001-01-25 10:37:55 +01:00
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
2004-01-11 10:21:06 +01:00
|
|
|
|
static attrib *
|
|
|
|
|
mk_piracy(const faction * f, direction_t target_dir)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_new(&at_piracy_direction);
|
|
|
|
|
piracy_data * data = a->data.v;
|
|
|
|
|
data->follow = f;
|
|
|
|
|
data->dir = target_dir;
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
piracy(unit *u)
|
|
|
|
|
{
|
|
|
|
|
region *r = u->region;
|
|
|
|
|
ship *sh = u->ship, *sh2;
|
|
|
|
|
direction_t dir, target_dir = NODIRECTION;
|
|
|
|
|
int aff[MAXDIRECTIONS];
|
|
|
|
|
int saff = 0;
|
|
|
|
|
int *il;
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
boolean all = true;
|
|
|
|
|
attrib *a;
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (!sh) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 144, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (!fval(u, UFL_OWNER)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 46, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Feststellen, ob schon ein anderer alliierter Pirat ein
|
|
|
|
|
* Ziel gefunden hat. */
|
|
|
|
|
|
|
|
|
|
il = intlist_init();
|
|
|
|
|
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
while(s && *s) {
|
|
|
|
|
il = intlist_add(il, atoi(s));
|
|
|
|
|
all = false;
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
for (a = a_find(r->attribs, &at_piracy_direction); a; a=a->nexttype) {
|
2004-01-11 10:21:06 +01:00
|
|
|
|
piracy_data * data = a->data.v;
|
|
|
|
|
const faction *f = data->follow;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-11 10:21:06 +01:00
|
|
|
|
if (alliedunit(u, f, HELP_FIGHT) && intlist_find(il, a->data.sa[1])) {
|
|
|
|
|
target_dir = data->dir;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wenn nicht, sehen wir, ob wir ein Ziel finden. */
|
|
|
|
|
|
|
|
|
|
if (target_dir == NODIRECTION) {
|
|
|
|
|
|
|
|
|
|
/* Einheit ist also Kapit<69>n. Jetzt gucken, in wievielen
|
|
|
|
|
* Nachbarregionen potentielle Opfer sind. */
|
|
|
|
|
|
|
|
|
|
for(dir = 0; dir < MAXDIRECTIONS; dir++) {
|
|
|
|
|
region *rc = rconnect(r, dir);
|
|
|
|
|
aff[dir] = 0;
|
|
|
|
|
if(rc && (terrain[rterrain(rc)].flags & SWIM_INTO)
|
|
|
|
|
&& check_takeoff(sh, r, rc) == true) {
|
|
|
|
|
|
|
|
|
|
for(sh2 = rc->ships; sh2; sh2 = sh2->next) {
|
2002-11-02 17:05:26 +01:00
|
|
|
|
unit * cap = shipowner(rc, sh2);
|
2002-10-20 12:40:42 +02:00
|
|
|
|
if (cap && (intlist_find(il, cap->faction->no) || all)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
aff[dir]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Und aufaddieren. */
|
|
|
|
|
saff += aff[dir];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(saff != 0) {
|
|
|
|
|
saff = rand()%saff;
|
|
|
|
|
for(dir = 0; dir < MAXDIRECTIONS; dir++) {
|
|
|
|
|
if(saff < aff[dir]) break;
|
|
|
|
|
saff -= aff[dir];
|
|
|
|
|
}
|
|
|
|
|
target_dir = dir;
|
2004-01-11 10:21:06 +01:00
|
|
|
|
a = a_add(&r->attribs, mk_piracy(u->faction, target_dir));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(il);
|
|
|
|
|
|
|
|
|
|
/* Wenn kein Ziel gefunden, entsprechende Meldung generieren */
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (target_dir == NODIRECTION) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
|
|
|
|
new_message(u->faction, "piratenovictim%h:ship%r:region", sh, r));
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Meldung generieren */
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"piratesawvictim%h:ship%r:region%d:dir", sh, r, target_dir));
|
|
|
|
|
|
|
|
|
|
/* Befehl konstruieren */
|
2001-09-05 21:40:40 +02:00
|
|
|
|
sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]),
|
2001-04-16 16:34:19 +02:00
|
|
|
|
locale_string(u->faction->locale, directions[target_dir]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
set_string(&u->thisorder, buf);
|
|
|
|
|
|
|
|
|
|
/* Bewegung ausf<73>hren */
|
2001-04-16 16:34:19 +02:00
|
|
|
|
igetkeyword(u->thisorder, u->faction->locale); /* NACH ignorieren */
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return move(r, u, true);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
age_traveldir(region *r)
|
|
|
|
|
{
|
|
|
|
|
attrib *a = a_find(r->attribs, &at_traveldir);
|
|
|
|
|
|
|
|
|
|
while(a) {
|
|
|
|
|
a->data.ca[3]--;
|
|
|
|
|
if(a->data.ca[3] <= 0) {
|
|
|
|
|
attrib *an = a->nexttype;
|
|
|
|
|
a_remove(&r->attribs, a);
|
|
|
|
|
a = an;
|
|
|
|
|
} else {
|
|
|
|
|
a = a->nexttype;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static direction_t
|
|
|
|
|
hunted_dir(attrib *at, int id)
|
|
|
|
|
{
|
|
|
|
|
attrib *a = a_find(at, &at_traveldir_new);
|
|
|
|
|
|
|
|
|
|
while(a) {
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
if(t->no == id) return t->dir;
|
|
|
|
|
a = a->nexttype;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NODIRECTION;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2004-02-22 15:42:24 +01:00
|
|
|
|
can_move(const unit * u)
|
|
|
|
|
{
|
|
|
|
|
if (u->race->flags & RCF_CANNOTMOVE) return false;
|
|
|
|
|
if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
hunt(unit *u)
|
|
|
|
|
{
|
|
|
|
|
region *rc = u->region;
|
|
|
|
|
int moves, id;
|
|
|
|
|
char command[256];
|
|
|
|
|
direction_t dir;
|
|
|
|
|
|
|
|
|
|
if(!u->ship) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 144, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
} else if(!fval(u, UFL_OWNER)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 146, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else if(attacked(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 52, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
|
|
|
|
} else if (!can_move(u)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 55, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id = getshipid();
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (id <= 0) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 20, MSG_MOVE);
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dir = hunted_dir(rc->attribs, id);
|
|
|
|
|
|
|
|
|
|
if(dir == NODIRECTION) {
|
2004-02-22 15:42:24 +01:00
|
|
|
|
ship * sh = findship(id);
|
|
|
|
|
if (sh->region!=rc) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 20, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
sprintf(command, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]),
|
2001-04-16 16:34:19 +02:00
|
|
|
|
locale_string(u->faction->locale, directions[dir]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
moves = 1;
|
|
|
|
|
|
|
|
|
|
rc = rconnect(rc, dir);
|
|
|
|
|
while(moves < shipspeed(u->ship, u)
|
|
|
|
|
&& (dir = hunted_dir(rc->attribs, id)) != NODIRECTION) {
|
|
|
|
|
strcat(command, " ");
|
2001-04-16 16:34:19 +02:00
|
|
|
|
strcat(command, locale_string(u->faction->locale, directions[dir]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
moves++;
|
2001-02-18 11:06:10 +01:00
|
|
|
|
rc = rconnect(rc, dir);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In command steht jetzt das NACH-Kommando. */
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
igetkeyword(command, u->faction->locale); /* NACH ignorieren und Parsing initialisieren. */
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
/* NACH ausf<73>hren */
|
|
|
|
|
if (move(u->region, u, false)!=0) {
|
|
|
|
|
/* niemand sollte auf einen kapit<69>n direkt ein folge haben, oder? */
|
|
|
|
|
assert(1==0);
|
|
|
|
|
}
|
|
|
|
|
fset(u, UFL_LONGACTION); /* Von Hand setzen, um Endlosschleife zu vermeiden,
|
|
|
|
|
wenn Verfolgung nicht erfolgreich */
|
|
|
|
|
return 1; /* true -> Einheitenliste von vorne durchgehen */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
destroy_damaged_ships(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
ship *sh,*shn;
|
|
|
|
|
|
|
|
|
|
for(r=regions;r;r=r->next) {
|
|
|
|
|
for(sh=r->ships;sh;) {
|
|
|
|
|
shn = sh->next;
|
|
|
|
|
if (sh->damage>=sh->size * DAMAGE_SCALE) {
|
|
|
|
|
destroy_ship(sh, r);
|
|
|
|
|
}
|
|
|
|
|
sh = shn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
is_disorientated(unit *u)
|
|
|
|
|
{
|
2002-05-01 21:08:32 +02:00
|
|
|
|
static boolean init = false;
|
|
|
|
|
static const curse_type * shipconf_ct, * regconf_ct;
|
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
regconf_ct = ct_find("disorientationzone");
|
|
|
|
|
shipconf_ct = ct_find("shipdisorientation");
|
|
|
|
|
}
|
|
|
|
|
if (u->ship && curse_active(get_curse(u->ship->attribs, shipconf_ct)))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (curse_active(get_curse(u->region->attribs, regconf_ct)))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef TODO /* Wenn Feature ausgearbeitet */
|
|
|
|
|
void
|
|
|
|
|
regain_orientation(region * r)
|
|
|
|
|
{
|
|
|
|
|
ship *sh;
|
|
|
|
|
curse *c;
|
|
|
|
|
unit *u, *cap;
|
|
|
|
|
|
|
|
|
|
for(sh = r->ships; sh; sh = sh->next) {
|
|
|
|
|
c = get_curse(sh->attribs, C_DISORIENTATION, 0);
|
|
|
|
|
if(!c) continue;
|
|
|
|
|
|
|
|
|
|
/* Das Schiff bekommt seine Orientierung zur<75>ck, wenn es:
|
|
|
|
|
* a) An Land treibt.
|
|
|
|
|
* b) Gl<EFBFBD>ck hat.
|
|
|
|
|
* c) In einer Region mit einem nicht verwirrten alliierten
|
|
|
|
|
* Schiff steht.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
cap = shipowner(r, sh);
|
|
|
|
|
|
|
|
|
|
if(r->terrain != T_OCEAN || rand() % 10 >= storms[month(0)]) {
|
|
|
|
|
remove_curse(&sh->attribs, C_DISORIENTATION, 0);
|
|
|
|
|
add_message(&cap->faction->msgs,
|
|
|
|
|
new_message(cap->faction, "shipnoconf%h:ship", sh));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(u=r->units;u;u=u->next) {
|
|
|
|
|
if(u != cap
|
|
|
|
|
&& allied(cap, u->faction, HELP_GUARD)
|
|
|
|
|
&& is_disorientated(u) == false) {
|
|
|
|
|
remove_curse(&sh->attribs, C_DISORIENTATION, 0);
|
|
|
|
|
add_message(&cap->faction->msgs,
|
|
|
|
|
new_message(cap->faction, "shipnoconf%h:ship", sh));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Bewegung, Verfolgung, Piraterie */
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/** ships that folow other ships
|
|
|
|
|
* Dann generieren die jagenden Einheiten ihre Befehle und
|
|
|
|
|
* bewegen sich.
|
|
|
|
|
* Following the trails of other ships.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
move_hunters(void)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-02-22 15:42:24 +01:00
|
|
|
|
region *r;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
2001-02-14 08:44:57 +01:00
|
|
|
|
unit * u;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (u = r->units; u;) {
|
|
|
|
|
unit *u2 = u->next;
|
|
|
|
|
strlist *o;
|
|
|
|
|
param_t p;
|
|
|
|
|
|
|
|
|
|
for (o=u->orders;o;o=o->next) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if(igetkeyword(o->s, u->faction->locale) == K_FOLLOW) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(attacked(u)) {
|
|
|
|
|
cmistake(u, o->s, 52, MSG_MOVE);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
break;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
} else if (!can_move(u)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, o->s, 55, MSG_MOVE);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
p = getparam(u->faction->locale);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(p != P_SHIP) {
|
|
|
|
|
if(p != P_UNIT) {
|
|
|
|
|
cmistake(u, o->s, 240, MSG_MOVE);
|
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (!fval(u, UFL_LONGACTION) && !fval(u, UFL_HUNGER) && hunt(u)) {
|
2001-09-05 21:40:40 +02:00
|
|
|
|
u2 = r->units;
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
u = u2;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-22 15:42:24 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/** Piraten and Drift
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
move_pirates(void)
|
|
|
|
|
{
|
|
|
|
|
region * r;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
unit ** up = &r->units;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/* Abtreiben von besch<63>digten, unterbemannten, <20>berladenen Schiffen */
|
|
|
|
|
drifting_ships(r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
while (*up) {
|
|
|
|
|
unit *u = *up;
|
|
|
|
|
|
|
|
|
|
if (!fval(u, UFL_LONGACTION) && igetkeyword(u->thisorder, u->faction->locale) == K_PIRACY) {
|
|
|
|
|
piracy(u);
|
|
|
|
|
fset(u, UFL_LONGACTION);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (*up==u) {
|
|
|
|
|
/* not moved, use next unit */
|
|
|
|
|
up = &u->next;
|
|
|
|
|
} else if (*up && (*up)->region!=r) {
|
|
|
|
|
/* moved the previous unit along with u (units on same ship)
|
|
|
|
|
* must start from the beginning again */
|
|
|
|
|
up = &r->units;
|
|
|
|
|
}
|
|
|
|
|
/* else *up is already the next unit */
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
a_removeall(&r->attribs, &at_piracy_direction);
|
|
|
|
|
age_traveldir(r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
movement(void)
|
|
|
|
|
{
|
|
|
|
|
int ships;
|
|
|
|
|
|
|
|
|
|
/* Initialize the additional encumbrance by transported units */
|
|
|
|
|
init_drive();
|
|
|
|
|
|
|
|
|
|
/* Move ships in last phase, others first
|
|
|
|
|
* This is to make sure you can't land someplace and then get off the ship
|
|
|
|
|
* in the same turn.
|
|
|
|
|
*/
|
|
|
|
|
for (ships=0;ships<=1;++ships) {
|
|
|
|
|
region * r = regions;
|
|
|
|
|
while (r!=NULL) {
|
|
|
|
|
unit ** up = &r->units;
|
|
|
|
|
boolean repeat = false;
|
|
|
|
|
|
|
|
|
|
while (*up) {
|
|
|
|
|
unit *u = *up;
|
|
|
|
|
keyword_t kword = igetkeyword(u->thisorder, u->faction->locale);
|
|
|
|
|
|
|
|
|
|
switch (kword) {
|
|
|
|
|
case K_ROUTE:
|
|
|
|
|
case K_MOVE:
|
|
|
|
|
if (attacked(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 52, MSG_MOVE);
|
|
|
|
|
set_string(&u->thisorder, "");
|
|
|
|
|
} else if (!can_move(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 55, MSG_MOVE);
|
|
|
|
|
set_string(&u->thisorder, "");
|
|
|
|
|
} else {
|
|
|
|
|
if (ships) {
|
|
|
|
|
if (u->ship && fval(u, UFL_OWNER)) {
|
|
|
|
|
if (move(r, u, true)!=0) repeat = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (u->ship==NULL || !fval(u, UFL_OWNER)) {
|
|
|
|
|
if (move(r, u, true)!=0) repeat = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (*up==u) {
|
|
|
|
|
/* not moved, use next unit */
|
|
|
|
|
up = &u->next;
|
|
|
|
|
} else if (*up && (*up)->region!=r) {
|
|
|
|
|
/* moved the previous unit along with u (units on ships, for example)
|
|
|
|
|
* must start from the beginning again */
|
|
|
|
|
up = &r->units;
|
|
|
|
|
}
|
|
|
|
|
/* else *up is already the next unit */
|
|
|
|
|
}
|
|
|
|
|
if (!repeat) r = r->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
move_hunters();
|
|
|
|
|
move_pirates();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/** Overrides long orders with a FOLLOW order if the target is moving.
|
|
|
|
|
* FOLLOW SHIP is a long order, and doesn't need to be treated in here.
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
2004-02-22 15:42:24 +01:00
|
|
|
|
follow_unit(void)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
region * r;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
for (r=regions;r;r=r->next) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit * u;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
for (u=r->units;u;u=u->next) {
|
2001-02-02 09:40:49 +01:00
|
|
|
|
attrib * a;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
strlist * o;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
if (fval(u, UFL_LONGACTION) || fval(u, UFL_HUNGER)) continue;
|
2001-02-02 09:40:49 +01:00
|
|
|
|
a = a_find(u->attribs, &at_follow);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (o=u->orders;o;o=o->next) {
|
2004-02-22 15:42:24 +01:00
|
|
|
|
const struct locale * lang = u->faction->locale;
|
|
|
|
|
|
|
|
|
|
if (igetkeyword(o->s, lang) == K_FOLLOW && getparam(lang) == P_UNIT) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int id = read_unitid(u->faction, r);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
if (id>0) {
|
2001-02-07 21:42:31 +01:00
|
|
|
|
unit * uf = findunit(id);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!a) {
|
2001-02-07 21:42:31 +01:00
|
|
|
|
a = a_add(&u->attribs, make_follow(uf));
|
2001-04-08 19:36:50 +02:00
|
|
|
|
} else {
|
|
|
|
|
a->data.v = uf;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
} else if (a) {
|
|
|
|
|
a_remove(&u->attribs, a);
|
|
|
|
|
a = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (a && !fval(u, UFL_MOVED)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit * u2 = a->data.v;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0))
|
|
|
|
|
continue;
|
|
|
|
|
for (o=u2->orders;o;o=o->next) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
switch (igetkeyword(o->s, u2->faction->locale)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case K_MOVE:
|
|
|
|
|
case K_ROUTE:
|
2003-03-25 00:37:13 +01:00
|
|
|
|
case K_DRIVE:
|
|
|
|
|
case K_FOLLOW:
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case K_PIRACY:
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_FOLLOWING);
|
|
|
|
|
fset(u2, UFL_FOLLOWED);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
set_string(&u->thisorder, "");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|