2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2000
|
|
|
|
|
* 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 */
|
|
|
|
|
#include <goodies.h>
|
|
|
|
|
|
|
|
|
|
/* 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>
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
|
|
attrib_type at_traveldir = {
|
|
|
|
|
"traveldir",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE, /* Weil normales Aging an ung<6E>nstiger Stelle */
|
|
|
|
|
DEFAULT_WRITE,
|
|
|
|
|
DEFAULT_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
a_traveldir_new_init(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(1, sizeof(traveldir));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
a_traveldir_new_finalize(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
free(a->data.v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
a_traveldir_new_age(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
|
|
|
|
|
t->age--;
|
|
|
|
|
if(t->age == 0) return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
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
|
|
|
|
|
};
|
|
|
|
|
|
- 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
canswim(unit *u)
|
|
|
|
|
{
|
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
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
cansail(const region * r, ship * sh)
|
|
|
|
|
{
|
|
|
|
|
int n = 0, p = 0;
|
|
|
|
|
unit *u;
|
|
|
|
|
|
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;
|
|
|
|
|
for (u = r->units; u; u = u->next)
|
|
|
|
|
if (u->ship == sh) {
|
|
|
|
|
n += weight(u);
|
|
|
|
|
p += u->number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next)
|
|
|
|
|
if (u->ship == sh)
|
|
|
|
|
n += eff_skill(u, SK_SAILING, r) * u->number;
|
|
|
|
|
return n >= sh->type->sumskill;
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
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. */
|
|
|
|
|
if(i) fset(cap, FL_STORM);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define USE_CREATION 0
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
present(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
return (boolean) (u && u->region == r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
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));
|
|
|
|
|
} else if (!allied(target, u->faction, HELP_ALL)
|
|
|
|
|
&& 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 ! */
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
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)
|
|
|
|
|
|| allied(u, reisender->faction, HELP_GUARD))
|
|
|
|
|
{
|
|
|
|
|
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) {
|
|
|
|
|
int chance = 30; /* 30% base chance */
|
|
|
|
|
chance += 10 * (perception - eff_stealth(reisender, r));
|
|
|
|
|
chance += 10 * max(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
if (rand() % 100 < chance) {
|
|
|
|
|
return guard;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
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)
|
|
|
|
|
&& allied(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;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
cycle_route(unit *u, int gereist)
|
|
|
|
|
{
|
|
|
|
|
int cm = 0;
|
|
|
|
|
char tail[1024];
|
|
|
|
|
char neworder[1024];
|
|
|
|
|
char *token;
|
|
|
|
|
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) {
|
2001-04-22 20:14:07 +02:00
|
|
|
|
const 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
|
|
|
|
}
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
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) {
|
2002-03-12 21:48:10 +01:00
|
|
|
|
if(igetkeyword(u->thisorder, u->faction->locale) == K_DRIVE && !fval(u, FL_LONGACTION) && !fval(u, FL_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) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 64, MSG_MOVE);
|
|
|
|
|
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 {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 64, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
2002-03-12 21:48:10 +01:00
|
|
|
|
if (igetkeyword(ut->thisorder, u->faction->locale) == K_DRIVE && !fval(ut, FL_LONGACTION) && !fval(ut, FL_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;
|
|
|
|
|
if (u->ship && fval(u, FL_OWNER) && rterrain(from)==T_OCEAN) {
|
|
|
|
|
/* 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) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
2002-02-06 09:06:02 +01:00
|
|
|
|
} else if (rterrain(next) == T_OCEAN && u->ship && fval(u->ship, FL_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
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
while (b) {
|
|
|
|
|
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 */
|
|
|
|
|
if (move_blocked(u, current, reldirection(current, next))
|
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",
|
|
|
|
|
"unit region", u, next));
|
|
|
|
|
}
|
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);
|
|
|
|
|
if(pl && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"detectoceandir%u:unit%i:direction", u,
|
|
|
|
|
reldirection(current, next)));
|
|
|
|
|
} 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,
|
|
|
|
|
"detectforbiddendir%u:unit%i:direction", u, reldirection(current, next)));
|
|
|
|
|
} 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++;
|
|
|
|
|
}
|
|
|
|
|
else break;
|
|
|
|
|
|
|
|
|
|
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
|
2002-03-12 21:48:10 +01:00
|
|
|
|
&& !fval(ut, FL_LONGACTION) && !fval(ut, FL_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 {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 64, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
if (ut) {
|
2001-04-01 08:58:45 +02:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 64, 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, "");
|
2001-02-18 11:06:10 +01:00
|
|
|
|
fset(u, FL_LONGACTION);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
setguard(u, GUARD_NONE);
|
|
|
|
|
|
|
|
|
|
if (fval(u, FL_FOLLOWING)) caught_target(current, u);
|
|
|
|
|
return route;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
ship_ready(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
if (!fval(u, FL_OWNER)) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
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. */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
direction_t *
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(move_on_land == false && rterrain(next_point) != T_OCEAN) {
|
|
|
|
|
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)) {
|
|
|
|
|
if(fval(u, FL_STORM)) {
|
|
|
|
|
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 */
|
2002-02-06 09:06:02 +01:00
|
|
|
|
fset(u->ship, FL_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 */
|
|
|
|
|
|
2002-02-06 09:06:02 +01:00
|
|
|
|
if (fval(u->ship, FL_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 */
|
|
|
|
|
if (fval(u, FL_FOLLOWING)) caught_target(current_point, u);
|
|
|
|
|
|
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 &&
|
|
|
|
|
!allied(hafenmeister, u->faction, HELP_GUARD)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Segeln, Wandern, Reiten */
|
|
|
|
|
|
2001-02-18 11:06:10 +01:00
|
|
|
|
static void
|
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);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (u->ship && fval(u, FL_OWNER))
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
set_string(&u->thisorder, "");
|
|
|
|
|
/* F<>r den Silberpool: Bewegung ist fertig, Silber darf abgezogen werden */
|
|
|
|
|
if (fval(u, FL_FOLLOWED) && route && route[0]!=NODIRECTION) {
|
2001-09-05 21:40:40 +02:00
|
|
|
|
unit *up=r->units;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
while (up) {
|
|
|
|
|
unit *un = up->next;
|
|
|
|
|
|
|
|
|
|
if (fval(up, FL_FOLLOWING) && !fval(up, FL_MOVED)) {
|
|
|
|
|
attrib * a = a_find(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);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
move(r, up, true);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
up = un;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-02-18 11:06:10 +01:00
|
|
|
|
if (u->region!=r) fset(u, FL_LONGACTION);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_piracy_direction = {
|
|
|
|
|
"piracy_direction",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
piracy(unit *u)
|
|
|
|
|
{
|
|
|
|
|
region *r = u->region;
|
|
|
|
|
ship *sh = u->ship, *sh2;
|
|
|
|
|
unit *cap;
|
|
|
|
|
direction_t dir, target_dir = NODIRECTION;
|
|
|
|
|
int aff[MAXDIRECTIONS];
|
|
|
|
|
int saff = 0;
|
|
|
|
|
int *il;
|
|
|
|
|
char *s;
|
|
|
|
|
boolean all = true;
|
|
|
|
|
attrib *a;
|
|
|
|
|
|
|
|
|
|
if(!sh) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 144, MSG_MOVE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!fval(u, FL_OWNER)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 46, MSG_MOVE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(a = a_find(r->attribs, &at_piracy_direction); a; a=a->nexttype) {
|
|
|
|
|
faction *f = findfaction(a->data.sa[0]);
|
|
|
|
|
|
|
|
|
|
if(allied(u, f, HELP_FIGHT)
|
|
|
|
|
&& intlist_find(il, a->data.sa[1])) {
|
|
|
|
|
target_dir = (direction_t)a->data.sa[1];
|
|
|
|
|
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) {
|
|
|
|
|
cap = shipowner(rc, sh2);
|
|
|
|
|
if(cap && !allied(u, cap->faction, HELP_FIGHT)
|
|
|
|
|
&& (intlist_find(il, cap->faction->no) || all)) {
|
|
|
|
|
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;
|
|
|
|
|
a = a_add(&r->attribs, a_new(&at_piracy_direction));
|
|
|
|
|
a->data.sa[0] = (short)u->faction->no;
|
|
|
|
|
a->data.sa[1] = (short)target_dir;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(il);
|
|
|
|
|
|
|
|
|
|
/* Wenn kein Ziel gefunden, entsprechende Meldung generieren */
|
|
|
|
|
if(target_dir == NODIRECTION) {
|
|
|
|
|
add_message(&u->faction->msgs,
|
|
|
|
|
new_message(u->faction, "piratenovictim%h:ship%r:region", sh, r));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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 */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
move(r, u, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
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);
|
|
|
|
|
return false;
|
|
|
|
|
} else if(!fval(u, FL_OWNER)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 146, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
} else if(attacked(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 52, MSG_MOVE);
|
|
|
|
|
return false;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
} else if(u->race->flags & RCF_CANNOTMOVE) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 55, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id = getshipid();
|
|
|
|
|
|
|
|
|
|
if(id <= 0) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 20, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dir = hunted_dir(rc->attribs, id);
|
|
|
|
|
|
|
|
|
|
if(dir == NODIRECTION) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 20, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
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. */
|
|
|
|
|
move(u->region, u, false); /* NACH ausf<73>hren */
|
|
|
|
|
fset(u, FL_LONGACTION); /* Von Hand setzen, um Endlosschleife zu vermeiden,
|
|
|
|
|
wenn Verfolgung nicht erfolgreich */
|
|
|
|
|
return true; /* 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 */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
movement(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
2002-03-22 10:33:46 +01:00
|
|
|
|
int ships;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Initialize the additional encumbrance by transported units */
|
|
|
|
|
init_drive();
|
|
|
|
|
|
2002-03-22 10:33:46 +01:00
|
|
|
|
/* move ships in last phase, others first */
|
|
|
|
|
for (ships=0;ships<=1;++ships) for (r = regions; r; r = r->next) {
|
2001-02-14 08:44:57 +01:00
|
|
|
|
unit ** up = &r->units;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Bewegungen.
|
|
|
|
|
*
|
|
|
|
|
* Zuerst m<EFBFBD>ssen sich alle Einheiten ohne u->target bewegen
|
|
|
|
|
* (NACH), dann starten die Verfolger mit u->target (FOLGE) und
|
|
|
|
|
* h<EFBFBD>ren erst auf, wenn sie ihr Ziel erreicht haben.
|
|
|
|
|
*
|
|
|
|
|
* neue NEW_FOLLOW-Variante: Verfolger folgen sofort, FL_FOLLOW
|
|
|
|
|
* ist bereits gesetzt.
|
|
|
|
|
*/
|
2001-02-14 08:44:57 +01:00
|
|
|
|
while (*up) {
|
|
|
|
|
unit *u = *up;
|
|
|
|
|
keyword_t kword;
|
|
|
|
|
|
|
|
|
|
if (fval(u, FL_FOLLOWING)) {
|
|
|
|
|
/* skip all followers */
|
|
|
|
|
do {
|
|
|
|
|
u = u->next;
|
|
|
|
|
} while (u && fval(u, FL_FOLLOWING));
|
|
|
|
|
up = &u;
|
|
|
|
|
if (u==NULL) break;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
kword = igetkeyword(u->thisorder, u->faction->locale);
|
2001-02-14 08:44:57 +01:00
|
|
|
|
switch (kword) {
|
|
|
|
|
case K_ROUTE:
|
|
|
|
|
case K_MOVE:
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (attacked(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 52, MSG_MOVE);
|
|
|
|
|
set_string(&u->thisorder, "");
|
2001-02-14 08:44:57 +01:00
|
|
|
|
up = &u->next;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
} else if (u->race->flags & RCF_CANNOTMOVE) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 55, MSG_MOVE);
|
|
|
|
|
set_string(&u->thisorder, "");
|
2001-02-14 08:44:57 +01:00
|
|
|
|
up = &u->next;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2002-03-22 10:33:46 +01:00
|
|
|
|
boolean moved = true;
|
|
|
|
|
if (ships) {
|
|
|
|
|
if (u->ship && fval(u, FL_OWNER)) move(r, u, true);
|
|
|
|
|
else moved=false;
|
|
|
|
|
} else {
|
|
|
|
|
if (u->ship==NULL || !fval(u, FL_OWNER)) move(r, u, true);
|
|
|
|
|
else moved=false;
|
|
|
|
|
}
|
|
|
|
|
if (moved) {
|
|
|
|
|
set_string(&u->thisorder, "");
|
|
|
|
|
up = &r->units;
|
|
|
|
|
} else {
|
|
|
|
|
up = &u->next;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-02-14 08:44:57 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
up = &u->next;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dann generieren die jagenden Einheiten ihre Befehle und
|
|
|
|
|
* bewegen sich. */
|
|
|
|
|
|
|
|
|
|
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;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
} else if(u->race->flags & RCF_CANNOTMOVE) {
|
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
|
|
|
|
}
|
|
|
|
|
|
2002-03-17 09:38:08 +01:00
|
|
|
|
if (!fval(u, FL_LONGACTION) && !fval(u, FL_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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Regul<75>re Verfolger starten */
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
if (utarget(u)
|
2001-04-16 16:34:19 +02:00
|
|
|
|
&& (igetkeyword(u->thisorder, u->faction->locale) == K_MOVE
|
|
|
|
|
|| igetkeyword(u->thisorder, u->faction->locale) == K_ROUTE)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (attacked(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 52, MSG_PRODUCE);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
} else if (u->race->flags & RCF_CANNOTMOVE) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 55, MSG_PRODUCE);
|
|
|
|
|
} else
|
|
|
|
|
move(r, u, true);
|
|
|
|
|
}
|
|
|
|
|
u = u2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Abtreiben von besch<63>digten, unterbemannten, <20>berladenen Schiffen */
|
|
|
|
|
|
|
|
|
|
drifting_ships(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Piraten und Cleanup */
|
|
|
|
|
|
|
|
|
|
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 *un = u->next;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if(igetkeyword(u->thisorder, u->faction->locale) == K_PIRACY) piracy(u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
u = un;
|
|
|
|
|
}
|
|
|
|
|
a_removeall(&r->attribs, &at_piracy_direction);
|
|
|
|
|
age_traveldir(r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
follow(void)
|
|
|
|
|
{
|
|
|
|
|
region * r;
|
|
|
|
|
for (r=regions;r;r=r->next) {
|
|
|
|
|
unit * u;
|
|
|
|
|
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;
|
2002-03-17 09:39:11 +01:00
|
|
|
|
if (fval(u, FL_LONGACTION) || fval(u, FL_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) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (igetkeyword(o->s, u->faction->locale) == K_FOLLOW
|
|
|
|
|
&& getparam(u->faction->locale) == P_UNIT) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int id = read_unitid(u->faction, r);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (a && !fval(u, FL_MOVED)) {
|
|
|
|
|
unit * u2 = a->data.v;
|
|
|
|
|
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:
|
|
|
|
|
case K_PIRACY:
|
|
|
|
|
fset(u, FL_FOLLOWING);
|
|
|
|
|
fset(u2, FL_FOLLOWED);
|
|
|
|
|
set_string(&u->thisorder, "");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|