2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2003-07-29 11:48:03 +02:00
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2003
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
|
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
|
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
|
|
|
|
* Enno Rehling (enno@eressea-pbem.de)
|
|
|
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
|
|
|
*
|
|
|
|
|
* based on:
|
|
|
|
|
*
|
|
|
|
|
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
|
|
|
|
|
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
* This program may not be sold or used commercially without prior written
|
|
|
|
|
* permission from the authors.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#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"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "order.h"
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#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"
|
2004-05-25 01:09:10 +02:00
|
|
|
|
#include "teleport.h"
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#include "unit.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* util includes */
|
2004-02-09 23:20:40 +01:00
|
|
|
|
#include <util/goodies.h>
|
2004-02-22 15:42:24 +01:00
|
|
|
|
#include <util/language.h>
|
2004-02-09 23:20:40 +01:00
|
|
|
|
#include <util/rand.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
/* attributes includes */
|
|
|
|
|
#include <attributes/follow.h>
|
|
|
|
|
#include <attributes/targetregion.h>
|
2002-09-29 20:11:08 +02:00
|
|
|
|
#include <attributes/at_movement.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* TODO: boder_type::move() must be able to change target (wisps) */
|
|
|
|
|
extern border_type bt_wisps;
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
typedef struct traveldir {
|
|
|
|
|
int no;
|
|
|
|
|
direction_t dir;
|
|
|
|
|
int age;
|
|
|
|
|
} traveldir;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static attrib_type at_traveldir = {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"traveldir",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE, /* Weil normales Aging an ung<6E>nstiger Stelle */
|
|
|
|
|
DEFAULT_WRITE,
|
|
|
|
|
DEFAULT_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2004-07-14 09:12:36 +02:00
|
|
|
|
shiptrail_init(attrib *a)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(1, sizeof(traveldir));
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2004-07-14 09:12:36 +02:00
|
|
|
|
shiptrail_finalize(attrib *a)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
free(a->data.v);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2004-07-14 09:12:36 +02:00
|
|
|
|
shiptrail_age(attrib *a)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
|
|
|
|
|
t->age--;
|
|
|
|
|
if(t->age == 0) return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2004-07-14 09:12:36 +02:00
|
|
|
|
shiptrail_read(attrib *a, FILE *f)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2002-04-07 02:44:01 +02:00
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
int no, age, dir;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-07 02:44:01 +02:00
|
|
|
|
fscanf(f, "%d %d %d", &no, &dir, &age);
|
|
|
|
|
t->no = no;
|
|
|
|
|
t->dir = (direction_t)dir;
|
|
|
|
|
t->age = age;
|
|
|
|
|
return AT_READ_OK;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2004-07-14 09:12:36 +02:00
|
|
|
|
shiptrail_write(const attrib *a, FILE *f)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
fprintf(f, "%d %d %d ", t->no, (int)t->dir, t->age);
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-14 09:12:36 +02:00
|
|
|
|
attrib_type at_shiptrail = {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"traveldir_new",
|
2004-07-14 09:12:36 +02:00
|
|
|
|
shiptrail_init,
|
|
|
|
|
shiptrail_finalize,
|
|
|
|
|
shiptrail_age,
|
|
|
|
|
shiptrail_write,
|
|
|
|
|
shiptrail_read
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
2004-05-07 13:11:30 +02:00
|
|
|
|
static int
|
|
|
|
|
age_speedup(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
if(a->data.i > 0) {
|
|
|
|
|
--a->data.i;
|
|
|
|
|
}
|
|
|
|
|
return a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_speedup = {
|
|
|
|
|
"speedup",
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
age_speedup,
|
|
|
|
|
a_writedefault,
|
|
|
|
|
a_readdefault
|
|
|
|
|
};
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
direction_t
|
2001-09-05 21:40:40 +02:00
|
|
|
|
getdirection(const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-09-05 21:40:40 +02:00
|
|
|
|
return finddirection(getstrtoken(), lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
static attrib_type at_driveweight = {
|
|
|
|
|
"driveweight", NULL, NULL, NULL, NULL, NULL
|
|
|
|
|
};
|
|
|
|
|
|
2002-12-18 01:34:19 +01:00
|
|
|
|
static boolean
|
|
|
|
|
entrance_allowed(const struct unit * u, const struct region * r)
|
|
|
|
|
{
|
|
|
|
|
#ifdef REGIONOWNERS
|
|
|
|
|
unit * owner = region_owner(r);
|
|
|
|
|
if (owner==NULL || u->faction==owner->faction) return true;
|
|
|
|
|
if (alliedunit(owner, u->faction, HELP_TRAVEL)) return true;
|
|
|
|
|
if (is_enemy(u->faction, owner->faction)) return true;
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
int
|
2001-12-10 01:13:39 +01:00
|
|
|
|
personcapacity(const unit *u)
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
{
|
2002-04-21 11:23:05 +02:00
|
|
|
|
#if RACE_CAPACITY
|
|
|
|
|
int cap = u->race->weight+u->race->capacity;
|
|
|
|
|
#else
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int cap = u->race->weight+540;
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_TROLL)
|
2001-04-22 20:14:07 +02:00
|
|
|
|
cap += 540;
|
2002-02-06 09:06:02 +01:00
|
|
|
|
#if RACE_ADJUSTMENTS
|
2001-12-10 01:13:39 +01:00
|
|
|
|
else if(old_race(u->race) == RC_GOBLIN)
|
|
|
|
|
cap -= 100;
|
|
|
|
|
#endif
|
2002-04-21 11:23:05 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fspecial(u->faction, FS_QUICK))
|
2001-04-22 20:14:07 +02:00
|
|
|
|
cap -= 200;
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
|
|
|
|
|
return cap;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static int
|
|
|
|
|
eff_weight(const unit *u)
|
|
|
|
|
{
|
|
|
|
|
attrib *a = a_find(u->attribs, &at_driveweight);
|
|
|
|
|
|
|
|
|
|
if (a) return weight(u) + a->data.i;
|
|
|
|
|
|
|
|
|
|
return weight(u);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
ridingcapacity(unit * u)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
int wagen, pferde;
|
|
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
|
|
|
|
|
|
/* Man tr<74>gt sein eigenes Gewicht plus seine Kapazit<69>t! Die Menschen
|
|
|
|
|
* tragen nichts (siehe walkingcapacity). Ein Wagen z<EFBFBD>hlt nur, wenn er
|
|
|
|
|
* von zwei Pferden gezogen wird */
|
|
|
|
|
|
|
|
|
|
pferde = min(get_item(u, I_HORSE), effskill(u, SK_RIDING) * u->number * 2);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(fval(u->race, RCF_HORSE)) pferde += u->number;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* maximal diese Pferde k<>nnen zum Ziehen benutzt werden */
|
|
|
|
|
wagen = min(pferde / HORSESNEEDED, get_item(u, I_WAGON));
|
|
|
|
|
|
|
|
|
|
n = wagen * WAGONCAPACITY + pferde * HORSECAPACITY;
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int
|
|
|
|
|
walkingcapacity(const struct unit * u)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-02-22 22:49:59 +01:00
|
|
|
|
int n, tmp, personen, pferde, pferde_fuer_wagen;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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 */
|
2004-02-22 22:49:59 +01:00
|
|
|
|
tmp = get_effect(u, oldpotiontype[P_STRONG]);
|
2004-08-03 17:34:26 +02:00
|
|
|
|
n += min(personen, tmp) * (HORSECAPACITY - personcapacity(u));
|
2004-02-22 17:08:39 +01:00
|
|
|
|
/* change_effect wird in ageing gemacht */
|
2004-02-22 22:49:59 +01:00
|
|
|
|
tmp = get_item(u, I_TROLLBELT);
|
2004-08-03 17:34:26 +02:00
|
|
|
|
n += min(personen, tmp) * STRENGTHCAPACITY;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
canwalk(unit * u)
|
|
|
|
|
{
|
|
|
|
|
int wagen, maxwagen;
|
|
|
|
|
int pferde, maxpferde;
|
|
|
|
|
|
2002-04-07 10:20:27 +02:00
|
|
|
|
/* workaround: monsters are too stupid to drop items, therefore they have
|
|
|
|
|
* infinite carrying capacity */
|
|
|
|
|
|
|
|
|
|
if (u->faction->no == 0) return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
wagen = get_item(u, I_WAGON);
|
|
|
|
|
pferde = get_item(u, I_HORSE);
|
|
|
|
|
|
|
|
|
|
maxwagen = effskill(u, SK_RIDING) * u->number * 2;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_TROLL) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
maxwagen = max(maxwagen, u->number / 4);
|
|
|
|
|
}
|
|
|
|
|
maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number;
|
|
|
|
|
|
|
|
|
|
if (pferde > maxpferde)
|
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
|
|
if (walkingcapacity(u) - eff_weight(u) >= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Stimmt das Gewicht, impliziert dies hier, da<64> alle Wagen ohne
|
|
|
|
|
* Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat
|
|
|
|
|
* die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen
|
|
|
|
|
* als erlaubt. */
|
|
|
|
|
|
|
|
|
|
if (wagen > maxwagen)
|
|
|
|
|
return 3;
|
|
|
|
|
/* Es mu<6D> nicht zwingend an den Wagen liegen, aber egal... (man
|
|
|
|
|
* k<EFBFBD>nnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als
|
|
|
|
|
* Fracht draufpa<EFBFBD>t) */
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
canfly(unit *u)
|
|
|
|
|
{
|
2002-09-29 20:11:08 +02:00
|
|
|
|
if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(get_item(u, I_HORSE)) return false;
|
|
|
|
|
|
|
|
|
|
if(get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4)
|
|
|
|
|
return true;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fval(u->race, RCF_FLY)) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-09-29 20:11:08 +02:00
|
|
|
|
if (get_movement(&u->attribs, MV_FLY)) return true;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
canswim(unit *u)
|
|
|
|
|
{
|
2002-09-29 20:11:08 +02:00
|
|
|
|
if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (get_item(u, I_HORSE)) return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if(fspecial(u->faction, FS_AMPHIBIAN)) return true;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race->flags & RCF_FLY) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race->flags & RCF_SWIM) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-09-29 20:11:08 +02:00
|
|
|
|
if (get_movement(&u->attribs, MV_FLY)) return true;
|
|
|
|
|
|
|
|
|
|
if (get_movement(&u->attribs, MV_SWIM)) return true;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
canride(unit * u)
|
|
|
|
|
{
|
|
|
|
|
int pferde, maxpferde, unicorns, maxunicorns;
|
|
|
|
|
int skill = effskill(u, SK_RIDING);
|
|
|
|
|
|
|
|
|
|
unicorns = get_item(u, I_UNICORN);
|
|
|
|
|
pferde = get_item(u, I_HORSE);
|
|
|
|
|
maxunicorns = (skill/5) * u->number;
|
|
|
|
|
maxpferde = skill * u->number * 2;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(!(u->race->flags & RCF_HORSE)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
&& ((pferde == 0 && unicorns == 0)
|
|
|
|
|
|| pferde > maxpferde || unicorns > maxunicorns)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ridingcapacity(u) - eff_weight(u) >= 0) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(pferde == 0 && unicorns >= u->number && !(u->race->flags & RCF_HORSE)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cansail(const region * r, ship * sh)
|
|
|
|
|
{
|
|
|
|
|
int n = 0, p = 0;
|
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
/* sonst ist construction:: size nicht ship_type::maxsize */
|
|
|
|
|
assert(!sh->type->construction || sh->type->construction->improvement==NULL);
|
|
|
|
|
|
|
|
|
|
if (sh->type->construction && sh->size!=sh->type->construction->maxsize)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
2002-11-25 16:30:51 +01:00
|
|
|
|
getshipweight(sh, &n, &p);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) {
|
|
|
|
|
if (sh->type->cargo>500*100)
|
|
|
|
|
assert(!"Ein Schiff wurde verzaubert, das zu gro<72> ist");
|
|
|
|
|
if (n > 10000) return false;
|
|
|
|
|
}
|
|
|
|
|
if (n > shipcapacity(sh)) return false;
|
|
|
|
|
if (p > sh->type->cabins) return false;
|
2004-07-09 21:35:50 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-21 18:45:27 +02:00
|
|
|
|
enoughsailors(const ship * sh, const region * r)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
unit *u;
|
|
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (u->ship == sh)
|
|
|
|
|
n += eff_skill(u, SK_SAILING, r) * u->number;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return n >= sh->type->sumskill;
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
static ship *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
do_maelstrom(region *r, unit *u)
|
|
|
|
|
{
|
2004-05-31 18:21:03 +02:00
|
|
|
|
int damage;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
damage = rand()%150 - eff_skill(u, SK_SAILING, r)*5;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
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 u->ship;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
damage_ship(u->ship, 0.01*damage);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (u->ship->damage >= u->ship->size * DAMAGE_SCALE) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("entermaelstrom",
|
|
|
|
|
"region ship damage sink", r, u->ship, damage, 1));
|
|
|
|
|
destroy_ship(u->ship);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("entermaelstrom",
|
|
|
|
|
"region ship damage sink", r, u->ship, damage, 0));
|
|
|
|
|
return u->ship;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-12 13:00:22 +02:00
|
|
|
|
/** sets a marker in the region telling that the unit has travelled through it
|
|
|
|
|
* this is used for two distinctly different purposes:
|
|
|
|
|
* - to report that a unit has travelled through. the report function
|
|
|
|
|
* makes sure to only report the ships of travellers, not the travellers
|
|
|
|
|
* themselves
|
|
|
|
|
* - to report the region to the traveller
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
2004-04-12 13:00:22 +02:00
|
|
|
|
travelthru(const unit * u, region * r)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-10 12:43:46 +02:00
|
|
|
|
attrib *ru = a_add(&r->attribs, a_new(&at_travelunit));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 13:00:22 +02:00
|
|
|
|
ru->data.v = (void*)u;
|
2004-04-10 12:43:46 +02:00
|
|
|
|
|
|
|
|
|
/* the first and last region of the faction gets reset, because travelthrough
|
|
|
|
|
* could be in regions that are located before the [first, last] interval,
|
|
|
|
|
* and recalculation is needed */
|
|
|
|
|
u->faction->first = 0;
|
|
|
|
|
u->faction->last = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2004-07-14 09:12:36 +02:00
|
|
|
|
leave_trail(ship * sh, region * from, region_list *route)
|
2004-04-10 12:43:46 +02:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
region * r = from;
|
2004-04-10 13:05:34 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
while (route!=NULL) {
|
|
|
|
|
region * rn = route->data;
|
2004-04-10 13:05:34 +02:00
|
|
|
|
direction_t dir = reldirection(r, rn);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* TODO: we cannot leave a trail into special directions
|
|
|
|
|
* if we use this kind of direction-attribute */
|
|
|
|
|
if (dir<MAXDIRECTIONS && dir>=0) {
|
|
|
|
|
traveldir * td = NULL;
|
2004-07-14 09:12:36 +02:00
|
|
|
|
attrib * a = a_find(r->attribs, &at_shiptrail);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
while (a!=NULL) {
|
|
|
|
|
td = (traveldir *)a->data.v;
|
|
|
|
|
if (td->no == sh->no) break;
|
|
|
|
|
a = a->nexttype;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a==NULL) {
|
2004-07-14 09:12:36 +02:00
|
|
|
|
a = a_add(&(r->attribs), a_new(&at_shiptrail));
|
2004-04-12 18:21:23 +02:00
|
|
|
|
td = (traveldir *)a->data.v;
|
|
|
|
|
td->no = sh->no;
|
|
|
|
|
}
|
|
|
|
|
td->dir = dir;
|
|
|
|
|
td->age = 2;
|
|
|
|
|
}
|
|
|
|
|
route = route->next;
|
|
|
|
|
r = rn;
|
2004-04-12 13:00:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2004-04-12 20:51:42 +02:00
|
|
|
|
travel_route(const unit * u, region * r, region_list * route)
|
2004-04-12 13:00:22 +02:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* kein travelthru in der letzten region! */
|
2004-04-12 20:51:42 +02:00
|
|
|
|
while (route) {
|
2004-04-10 12:43:46 +02:00
|
|
|
|
travelthru(u, r);
|
2004-08-21 03:55:56 +02:00
|
|
|
|
r = route->data;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
route = route->next;
|
2004-04-10 12:43:46 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ship *
|
2004-04-12 18:21:23 +02:00
|
|
|
|
move_ship(ship * sh, region * from, region * to, region_list * route)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-10 12:43:46 +02:00
|
|
|
|
unit **iunit = &from->units;
|
|
|
|
|
unit **ulist = &to->units;
|
|
|
|
|
boolean trail = (route==NULL);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
if (from!=to) {
|
|
|
|
|
translist(&from->ships, &to->ships, sh);
|
|
|
|
|
sh->region = to;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
while (*iunit!=NULL) {
|
|
|
|
|
unit *u = *iunit;
|
|
|
|
|
assert(u->region==from);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
if (u->ship == sh) {
|
|
|
|
|
if (!trail) {
|
2004-07-14 09:12:36 +02:00
|
|
|
|
leave_trail(sh, from, route);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
trail = true;
|
2004-04-10 12:43:46 +02:00
|
|
|
|
}
|
2004-04-12 20:51:42 +02:00
|
|
|
|
if (route!=NULL) travel_route(u, from, route);
|
2004-04-10 12:43:46 +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;
|
|
|
|
|
}
|
|
|
|
|
if (route && eff_skill(u, SK_SAILING, from) >= 1) {
|
|
|
|
|
produceexp(u, SK_SAILING, u->number);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (*iunit==u) iunit=&u->next;
|
|
|
|
|
}
|
|
|
|
|
return sh;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-15 10:19:03 +02:00
|
|
|
|
static 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static boolean
|
2004-07-11 16:37:42 +02:00
|
|
|
|
is_freezing(const unit * u)
|
2004-07-09 21:35:50 +02:00
|
|
|
|
{
|
|
|
|
|
if (old_race(u->race)!=RC_INSECT) return false;
|
|
|
|
|
if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
ship_allowed(const struct ship * sh, const region * r)
|
2004-06-15 10:19:03 +02:00
|
|
|
|
{
|
|
|
|
|
int c = 0;
|
|
|
|
|
terrain_t t = rterrain(r);
|
|
|
|
|
static const building_type * bt_harbour=NULL;
|
2004-07-09 21:35:50 +02:00
|
|
|
|
|
2004-06-15 10:19:03 +02:00
|
|
|
|
if (bt_harbour==NULL) bt_harbour=bt_find("harbour");
|
|
|
|
|
|
2004-07-09 21:35:50 +02:00
|
|
|
|
if (r_insectstalled(r)) {
|
|
|
|
|
/* insekten d<>rfen nicht hier rein. haben wir welche? */
|
|
|
|
|
unit * u;
|
2004-06-15 10:19:03 +02:00
|
|
|
|
|
2004-07-09 21:35:50 +02:00
|
|
|
|
for (u=sh->region->units;u!=NULL;u=u->next) {
|
|
|
|
|
if (u->ship!=sh) continue;
|
|
|
|
|
|
|
|
|
|
if (is_freezing(u)) {
|
|
|
|
|
unit * captain = shipowner(sh);
|
|
|
|
|
ADDMSG(&captain->faction->msgs, msg_message("detectforbidden",
|
|
|
|
|
"unit region", u, r));
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-15 10:19:03 +02:00
|
|
|
|
}
|
2004-07-09 21:35:50 +02:00
|
|
|
|
|
|
|
|
|
if (check_working_buildingtype(r, bt_harbour)) return true;
|
|
|
|
|
for (c=0;sh->type->coast[c]!=NOTERRAIN;++c) {
|
|
|
|
|
if (sh->type->coast[c]==t) return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-15 10:19:03 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-16 01:09:19 +02:00
|
|
|
|
static boolean
|
|
|
|
|
flying_ship(const ship * sh)
|
|
|
|
|
{
|
|
|
|
|
if (sh->type->flags & SFL_FLY) return true;
|
|
|
|
|
if (is_cursed(sh->attribs, C_SHIP_FLYING, 0)) return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-05 10:01:48 +02:00
|
|
|
|
static void
|
|
|
|
|
set_coast(ship * sh, region * r, region * rnext)
|
|
|
|
|
{
|
|
|
|
|
if (rnext->terrain != T_OCEAN && !flying_ship(sh)) {
|
|
|
|
|
sh->coast = reldirection(rnext, r);
|
|
|
|
|
assert(rterrain(r)==T_OCEAN);
|
|
|
|
|
} else {
|
|
|
|
|
sh->coast = NODIRECTION;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
drifting_ships(region * r)
|
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
direction_t d;
|
|
|
|
|
|
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
2004-05-31 15:52:59 +02:00
|
|
|
|
ship** shp = &r->ships;
|
|
|
|
|
while (*shp) {
|
|
|
|
|
ship * sh = *shp;
|
|
|
|
|
region * rnext = NULL;
|
2004-07-14 09:12:36 +02:00
|
|
|
|
region_list * route = NULL;
|
2004-05-31 15:52:59 +02:00
|
|
|
|
unit * captain;
|
|
|
|
|
int d_offset;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
|
|
|
|
/* Schiff schon abgetrieben oder durch Zauber gesch<63>tzt? */
|
|
|
|
|
if (fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) {
|
2004-05-31 15:52:59 +02:00
|
|
|
|
shp = &sh->next;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* Kapit<69>n bestimmen */
|
2004-09-05 10:01:48 +02:00
|
|
|
|
for (captain = r->units; captain; captain = captain->next) {
|
|
|
|
|
if (captain->ship != sh) continue;
|
|
|
|
|
if (eff_skill(captain, SK_SAILING, r) >= sh->type->cptskill) {
|
2004-04-12 18:21:23 +02:00
|
|
|
|
break;
|
2004-09-05 10:01:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* Kapit<69>n da? Besch<63>digt? Gen<65>gend Matrosen?
|
|
|
|
|
* Gen<EFBFBD>gend leicht? Dann ist alles OK. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (captain && sh->size==sh->type->construction->maxsize && enoughsailors(sh, r) && cansail(r, sh)) {
|
2004-05-31 15:52:59 +02:00
|
|
|
|
shp = &sh->next;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* Leuchtturm: Ok. */
|
|
|
|
|
if (check_leuchtturm(r, NULL)) {
|
2004-05-31 15:52:59 +02:00
|
|
|
|
shp = &sh->next;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* Auswahl einer Richtung: Zuerst auf Land, dann
|
|
|
|
|
* zuf<EFBFBD>llig. Falls unm<EFBFBD>gliches Resultat: vergi<EFBFBD> es. */
|
2004-05-31 15:52:59 +02:00
|
|
|
|
d_offset = rand() % MAXDIRECTIONS;
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
|
|
|
|
region * rn = rconnect(r, (direction_t)((d + d_offset) % MAXDIRECTIONS));
|
|
|
|
|
terrain_t t = rterrain(rn);
|
2004-07-09 21:35:50 +02:00
|
|
|
|
if (rn!=NULL && (terrain[t].flags & SAIL_INTO) && ship_allowed(sh, rn)) {
|
2004-05-31 15:52:59 +02:00
|
|
|
|
rnext = rn;
|
|
|
|
|
if (t!=T_OCEAN) break;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-05-31 15:52:59 +02:00
|
|
|
|
|
|
|
|
|
if (rnext==NULL) {
|
|
|
|
|
shp = &sh->next;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* Das Schiff und alle Einheiten darin werden nun von r
|
2004-05-31 15:52:59 +02:00
|
|
|
|
* nach rnext verschoben. Danach eine Meldung. */
|
2004-07-14 09:12:36 +02:00
|
|
|
|
add_regionlist(&route, rnext);
|
2004-09-05 10:01:48 +02:00
|
|
|
|
|
|
|
|
|
set_coast(sh, r, rnext);
|
2004-07-14 09:12:36 +02:00
|
|
|
|
sh = move_ship(sh, r, rnext, route);
|
|
|
|
|
free_regionlist(route);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 15:52:59 +02:00
|
|
|
|
if (sh!=NULL) {
|
2004-07-14 09:12:36 +02:00
|
|
|
|
|
2004-05-31 15:52:59 +02:00
|
|
|
|
fset(sh, SF_DRIFTED);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 15:52:59 +02:00
|
|
|
|
damage_ship(sh, 0.02);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 15:52:59 +02:00
|
|
|
|
if (sh->damage>=sh->size * DAMAGE_SCALE) {
|
2004-05-31 18:21:03 +02:00
|
|
|
|
destroy_ship(sh);
|
2004-05-31 15:52:59 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
2004-05-31 15:52:59 +02:00
|
|
|
|
if (*shp != sh) shp = &sh->next;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
present(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
return (boolean) (u && u->region == r);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
caught_target(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_follow);
|
|
|
|
|
|
|
|
|
|
/* Verfolgungen melden */
|
|
|
|
|
/* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter
|
|
|
|
|
* Umstaenden eine Warnung. */
|
|
|
|
|
|
|
|
|
|
if (a) {
|
|
|
|
|
unit * target = (unit*)a->data.v;
|
|
|
|
|
|
|
|
|
|
if (!present(r, target)) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"followfail%u:unit%u:follower", target, u));
|
2002-09-02 22:36:12 +02:00
|
|
|
|
} else if (!alliedunit(target, u->faction, HELP_ALL)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
&& cansee(target->faction, r, u, 0))
|
|
|
|
|
{
|
|
|
|
|
add_message(&target->faction->msgs, new_message(target->faction,
|
|
|
|
|
"followdetect%u:unit%u:follower", target, u));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TODO: Unsichtbarkeit bedenken ! */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static unit *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
bewegung_blockiert_von(unit * reisender, region * r)
|
|
|
|
|
{
|
2001-09-05 21:40:40 +02:00
|
|
|
|
unit *u;
|
|
|
|
|
int perception = 0;
|
|
|
|
|
boolean contact = false;
|
|
|
|
|
unit * guard = NULL;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fval(reisender->race, RCF_ILLUSIONARY)) return NULL;
|
2001-09-05 21:40:40 +02:00
|
|
|
|
for (u=r->units;u && !contact;u=u->next) {
|
|
|
|
|
if (getguard(u) & GUARD_TRAVELTHRU) {
|
|
|
|
|
int sk = eff_skill(u, SK_OBSERVATION, r);
|
|
|
|
|
if (get_item(reisender, I_RING_OF_INVISIBILITY) >= reisender->number &&
|
|
|
|
|
!get_item(u, I_AMULET_OF_TRUE_SEEING)) continue;
|
|
|
|
|
if (u->faction==reisender->faction
|
|
|
|
|
|| ucontact(u, reisender)
|
2002-09-02 22:36:12 +02:00
|
|
|
|
|| alliedunit(u, reisender->faction, HELP_GUARD))
|
2001-09-05 21:40:40 +02:00
|
|
|
|
{
|
|
|
|
|
contact = true;
|
|
|
|
|
} else if (sk>=perception) {
|
|
|
|
|
perception = sk;
|
|
|
|
|
guard = u;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
if (!contact && guard) {
|
2004-02-09 23:20:40 +01:00
|
|
|
|
double prob = 0.3; /* 30% base chance */
|
|
|
|
|
prob += 0.1 * (perception - eff_stealth(reisender, r));
|
|
|
|
|
prob += 0.1 * max(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-09 23:20:40 +01:00
|
|
|
|
if (chance(prob)) {
|
2001-09-05 21:40:40 +02:00
|
|
|
|
return guard;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
is_guardian(unit * u2, unit *u, unsigned int mask)
|
|
|
|
|
{
|
|
|
|
|
if (u2->faction != u->faction
|
2002-04-21 19:22:48 +02:00
|
|
|
|
&& getguard(u2)&mask
|
|
|
|
|
&& u2->number
|
|
|
|
|
&& !ucontact(u2, u) && !besieged(u2)
|
2002-09-02 22:36:12 +02:00
|
|
|
|
&& alliedunit(u2, u->faction, HELP_GUARD) != HELP_GUARD
|
2002-04-21 19:22:48 +02:00
|
|
|
|
&& armedmen(u2)
|
|
|
|
|
&& cansee(u2->faction, u->region, u, 0)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
) return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
is_guarded(region * r, unit * u, unsigned int mask)
|
|
|
|
|
{
|
|
|
|
|
unit *u2;
|
|
|
|
|
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (is_guardian(u2, u, mask)) return u2;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static const char *shortdirections[MAXDIRECTIONS] =
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-09-05 21:40:40 +02:00
|
|
|
|
"dir_nw",
|
|
|
|
|
"dir_ne",
|
|
|
|
|
"dir_east",
|
|
|
|
|
"dir_se",
|
|
|
|
|
"dir_sw",
|
|
|
|
|
"dir_west"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cycle_route(unit *u, int gereist)
|
|
|
|
|
{
|
|
|
|
|
int cm = 0;
|
|
|
|
|
char tail[1024];
|
2002-09-22 17:40:33 +02:00
|
|
|
|
char neworder[2048];
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *token;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
direction_t d = NODIRECTION;
|
|
|
|
|
boolean paused = false;
|
|
|
|
|
boolean pause;
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (get_keyword(u->thisorder) != 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
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(u->thisorder);
|
|
|
|
|
skip_token();
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (cm=0;;++cm) {
|
2002-09-02 22:36:12 +02:00
|
|
|
|
const struct locale * lang = u->faction->locale;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
pause = false;
|
|
|
|
|
token = getstrtoken();
|
2001-09-05 21:40:40 +02:00
|
|
|
|
d = finddirection(token, lang);
|
2001-02-18 13:20:37 +01:00
|
|
|
|
if(d == D_PAUSE) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
pause = true;
|
2001-02-18 13:20:37 +01:00
|
|
|
|
} else if (d==NODIRECTION) {
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
if (cm<gereist) {
|
|
|
|
|
/* hier sollte keine PAUSE auftreten */
|
2001-04-22 20:14:07 +02:00
|
|
|
|
assert(!pause);
|
2001-05-27 18:44:16 +02:00
|
|
|
|
if (!pause) strcat(strcat(tail, " "), LOC(lang, shortdirections[d]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-09-22 17:40:33 +02:00
|
|
|
|
else if (strlen(neworder)>sizeof(neworder)/2) break;
|
2001-04-22 20:14:07 +02:00
|
|
|
|
else if (cm==gereist && !paused && pause) {
|
|
|
|
|
strcat(strcat(tail, " "), LOC(lang, parameters[P_PAUSE]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
paused=true;
|
|
|
|
|
}
|
|
|
|
|
else if (pause) {
|
2001-04-22 20:14:07 +02:00
|
|
|
|
/* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist
|
|
|
|
|
* hier keine normale direction), muss jede PAUSE einzeln
|
|
|
|
|
* herausgefiltert und explizit gesetzt werden */
|
|
|
|
|
strcat(strcat(neworder, " "), LOC(lang, parameters[P_PAUSE]));
|
|
|
|
|
} else {
|
|
|
|
|
strcat(strcat(neworder, " "), LOC(lang, shortdirections[d]));
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strcat(neworder, tail);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
set_order(&u->lastorder, parse_order(neworder, u->faction->locale));
|
2004-06-27 14:19:58 +02:00
|
|
|
|
free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
init_drive(void)
|
|
|
|
|
{
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region *r;
|
|
|
|
|
unit *u, *ut;
|
|
|
|
|
|
|
|
|
|
for (r=regions; r; r=r->next) {
|
|
|
|
|
/* 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) {
|
2004-08-03 17:34:26 +02:00
|
|
|
|
if (get_keyword(u->thisorder) == K_DRIVE && !fval(u, UFL_LONGACTION) && !LongHunger(u)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
boolean found = false;
|
|
|
|
|
order * ord;
|
|
|
|
|
|
|
|
|
|
init_tokens(u->thisorder);
|
|
|
|
|
skip_token();
|
|
|
|
|
ut = getunit(r, u->faction);
|
|
|
|
|
if (ut==NULL) {
|
|
|
|
|
cmistake(u, u->thisorder, 63, MSG_MOVE);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (ord = ut->orders; ord; ord = ord->next) {
|
|
|
|
|
if (get_keyword(ord) == K_TRANSPORT) {
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
if (getunit(r, ut->faction) == u) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (found == false) {
|
|
|
|
|
if (cansee(u->faction, r, ut, 0)) {
|
|
|
|
|
cmistake(u, u->thisorder, 286, MSG_MOVE);
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, u->thisorder, 63, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* This calculates the weights of all transported units and
|
|
|
|
|
* adds them to an internal counter which is used by travel() to
|
|
|
|
|
* calculate effective weight and movement. */
|
|
|
|
|
|
|
|
|
|
for (u=r->units; u; u=u->next) {
|
|
|
|
|
order * ord;
|
|
|
|
|
int w = 0;
|
|
|
|
|
|
|
|
|
|
for (ord = u->orders; ord; ord = ord->next) {
|
|
|
|
|
if (get_keyword(ord) == K_TRANSPORT) {
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
ut = getunit(r, u->faction);
|
|
|
|
|
if (ut==NULL) continue;
|
|
|
|
|
|
2004-08-03 17:34:26 +02:00
|
|
|
|
if (get_keyword(ut->thisorder) == K_DRIVE && !fval(ut, UFL_LONGACTION) && !LongHunger(ut)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ut->thisorder);
|
|
|
|
|
skip_token();
|
|
|
|
|
if (getunit(r, ut->faction) == u) {
|
|
|
|
|
w += weight(ut);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if(w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int *storms;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* in arbeit */
|
|
|
|
|
#define ETRAVEL_NOTALLOWED 1
|
|
|
|
|
#define ETRAVEL_NOSWIM 2
|
|
|
|
|
#define ETRAVEL_NORIDE 4
|
|
|
|
|
#define ETRAVEL_LEFTSHIP 8
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
cantravel(const unit *u, const region *from, const region * to, boolean (*allowed)(const struct region *, const struct region *))
|
|
|
|
|
{
|
|
|
|
|
/* basic allowed function */
|
|
|
|
|
if (allowed && !allowed(from, to)) return ETRAVEL_NOTALLOWED;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (u->ship && fval(u, UFL_OWNER) && rterrain(from)==T_OCEAN) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* wir sind auf einem schiff und auf dem ozean */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (rterrain(to)==T_OCEAN || (old_race(u->race) != RC_AQUARIAN && !dragon(u))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Drache oder Meermensch sind wir auch nicht */
|
|
|
|
|
return ETRAVEL_NOSWIM;
|
|
|
|
|
} else if (get_item(u, I_HORSE) > 0) {
|
|
|
|
|
return ETRAVEL_NORIDE|ETRAVEL_NOSWIM;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!u->ship && leftship(u) && is_guarded(from, u, GUARD_LANDING)) {
|
|
|
|
|
/* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */
|
|
|
|
|
return ETRAVEL_LEFTSHIP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static boolean
|
2004-04-12 18:21:23 +02:00
|
|
|
|
roadto(const region * r, direction_t dir)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* wenn es hier genug strassen gibt, und verbunden ist, und es dort
|
|
|
|
|
* genug strassen gibt, dann existiert eine strasse in diese richtung */
|
|
|
|
|
region * r2;
|
2004-04-12 22:47:22 +02:00
|
|
|
|
static const curse_type * roads_ct = NULL;
|
|
|
|
|
|
|
|
|
|
if (roads_ct==NULL) roads_ct = ct_find("magicstreet");
|
|
|
|
|
if (roads_ct!=NULL) {
|
|
|
|
|
curse *c = get_curse(r->attribs, roads_ct);
|
|
|
|
|
if (c!=NULL) return true;
|
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
|
|
|
|
if (dir>=MAXDIRECTIONS || dir<0) return false;
|
|
|
|
|
r2 = rconnect(r, dir);
|
|
|
|
|
if (r==NULL || r2==NULL) return false;
|
|
|
|
|
|
|
|
|
|
if (terrain[rterrain(r)].roadreq==0) return false;
|
|
|
|
|
if (terrain[rterrain(r2)].roadreq==0) return false;
|
|
|
|
|
if (rroad(r, dir) < terrain[rterrain(r)].roadreq) return false;
|
|
|
|
|
if (rroad(r2, dir_invert(dir)) < terrain[rterrain(r2)].roadreq) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-07-09 15:41:14 +02:00
|
|
|
|
static const char *
|
|
|
|
|
direction_name(const region * from, const region * to, const struct locale * lang)
|
|
|
|
|
{
|
|
|
|
|
direction_t dir = reldirection(from, to);
|
|
|
|
|
if (dir<MAXDIRECTIONS && dir>=0) return locale_string(lang, directions[dir]);
|
|
|
|
|
if (dir==D_SPECIAL) {
|
|
|
|
|
spec_direction *sd = special_direction(from, to);
|
|
|
|
|
return sd->keyword;
|
|
|
|
|
}
|
|
|
|
|
assert(!"invalid direction");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
notify_followers(region * r, unit * target, const region_list * route)
|
|
|
|
|
{
|
|
|
|
|
int followers = 0;
|
|
|
|
|
unit *up;
|
|
|
|
|
|
|
|
|
|
for (up=r->units;up;up=up->next) {
|
|
|
|
|
if (fval(up, UFL_FOLLOWING) && !fval(up, UFL_LONGACTION)) {
|
|
|
|
|
const attrib * a = a_findc(up->attribs, &at_follow);
|
|
|
|
|
if (a && a->data.v==target) {
|
|
|
|
|
/* wir basteln ihm ein NACH */
|
|
|
|
|
const region_list * rlist = route;
|
|
|
|
|
region * from = r;
|
|
|
|
|
|
|
|
|
|
strcpy(buf, locale_string(up->faction->locale, keywords[K_MOVE]));
|
|
|
|
|
while (rlist!=NULL) {
|
|
|
|
|
strcat(strcat(buf, " "), direction_name(from, rlist->data, up->faction->locale));
|
|
|
|
|
from = rlist->data;
|
|
|
|
|
rlist = rlist->next;
|
|
|
|
|
}
|
|
|
|
|
set_order(&up->thisorder, parse_order(buf, up->faction->locale));
|
|
|
|
|
free_order(up->thisorder); /* parse_order & set_order have each increased the refcount */
|
|
|
|
|
++followers;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return followers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** traveling without ships
|
|
|
|
|
* The travel unction returns the number of followers - in case it's non-null,
|
|
|
|
|
* the loop through the units in the region needs to be repeated
|
|
|
|
|
* to exceute the newly made MOVE commands of followers
|
|
|
|
|
*/
|
|
|
|
|
int
|
2004-04-12 18:21:23 +02:00
|
|
|
|
travel(unit * u, region * next, int flucht, region_list ** routep)
|
|
|
|
|
{
|
|
|
|
|
region *first = u->region;
|
|
|
|
|
region *current = u->region;
|
|
|
|
|
int k, m = 0;
|
|
|
|
|
double dk;
|
|
|
|
|
unit *ut, *u2;
|
|
|
|
|
int gereist = 0;
|
|
|
|
|
region_list *route = NULL;
|
|
|
|
|
region_list **iroute = &route;
|
|
|
|
|
static boolean init = false;
|
|
|
|
|
static const curse_type * speed_ct;
|
2004-07-09 15:41:14 +02:00
|
|
|
|
int followers = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (routep) *routep = NULL;
|
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
speed_ct = ct_find("speed");
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02: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 */
|
|
|
|
|
|
|
|
|
|
if (rterrain(current)==T_OCEAN
|
|
|
|
|
&& !(u->race->flags & RCF_FLY) && rterrain(next) != T_OCEAN)
|
|
|
|
|
{ /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */
|
|
|
|
|
if (!(u->race->flags & RCF_SWIM) && old_race(u->race) != RC_AQUARIAN) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 44, MSG_MOVE);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
} else {
|
|
|
|
|
if (u->ship && get_item(u, I_HORSE) > 0) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 67, MSG_MOVE);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (rterrain(current)!=T_OCEAN) {
|
|
|
|
|
/* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */
|
|
|
|
|
if (leftship(u) && is_guarded(current, u, GUARD_LANDING)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 70, MSG_MOVE);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
if (u->ship && !flucht && u->race->flags & RCF_SWIM) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 143, MSG_MOVE);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
} else if (rterrain(next) == T_OCEAN && u->ship && fval(u->ship, SF_MOVED)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 13, MSG_MOVE);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
switch (canwalk(u)) {
|
|
|
|
|
case 1:
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 57, MSG_MOVE);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
case 2:
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 56, MSG_MOVE);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
case 3:
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 42, MSG_MOVE);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden
|
|
|
|
|
* dann nacheinander ausgef<EFBFBD>hrt. */
|
2002-04-07 10:20:27 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
dk = u->race->speed;
|
2002-04-07 10:20:27 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (speed_ct) {
|
|
|
|
|
curse *c = get_curse(u->attribs, speed_ct);
|
|
|
|
|
if(c) {
|
|
|
|
|
int men = get_cursedmen(u, c);
|
|
|
|
|
dk *= 1.0 + (double)men/(double)u->number;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
switch(canride(u)) {
|
|
|
|
|
case 1: /* Pferd */
|
|
|
|
|
k = (int)(dk*BP_RIDING);
|
|
|
|
|
break;
|
|
|
|
|
case 2: /* Einhorn */
|
|
|
|
|
k = (int)(dk*BP_UNICORN);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
int mp = 1;
|
|
|
|
|
|
|
|
|
|
/* faction special */
|
|
|
|
|
if(fspecial(u->faction, FS_QUICK))
|
|
|
|
|
mp = BP_RIDING;
|
|
|
|
|
|
|
|
|
|
/* Siebenmeilentee */
|
|
|
|
|
if (get_effect(u, oldpotiontype[P_FAST]) >= u->number) {
|
|
|
|
|
mp *= 2;
|
|
|
|
|
change_effect(u, oldpotiontype[P_FAST], -u->number);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* unicorn in inventory */
|
|
|
|
|
if (u->number <= get_item(u, I_FEENSTIEFEL))
|
|
|
|
|
mp *= 2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell.
|
|
|
|
|
* Nicht kumulativ mit anderen Beschleunigungen! */
|
2004-05-25 01:09:10 +02:00
|
|
|
|
if ( mp == 1 && getplane(next) == get_astralplane() && is_mage(u)) {
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if(get_mage(u)->magietyp == M_ASTRAL
|
|
|
|
|
|| get_mage(u)->magietyp == M_TRAUM) {
|
|
|
|
|
mp *= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
k = (int)(dk*mp*BP_WALKING);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
switch(old_race(u->race)) {
|
|
|
|
|
case RC_DRAGON:
|
|
|
|
|
case RC_WYRM:
|
|
|
|
|
case RC_FIREDRAGON:
|
|
|
|
|
case RC_BIRTHDAYDRAGON:
|
|
|
|
|
case RC_PSEUDODRAGON:
|
|
|
|
|
k = BP_DRAGON;
|
|
|
|
|
}
|
- 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
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* 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) {
|
|
|
|
|
border * b = get_borders(current, next);
|
|
|
|
|
direction_t reldir = reldirection(current, next);
|
|
|
|
|
|
|
|
|
|
while (b!=NULL) {
|
|
|
|
|
if (b->type==&bt_wisps) {
|
|
|
|
|
wall_data * wd = (wall_data*)b->data;
|
|
|
|
|
assert(reldir!=D_SPECIAL);
|
|
|
|
|
|
|
|
|
|
if (wd->active) {
|
|
|
|
|
/* pick left and right region: */
|
|
|
|
|
region * rl = rconnect(current, (direction_t)((reldir+MAXDIRECTIONS-1)%MAXDIRECTIONS));
|
|
|
|
|
region * rr = rconnect(current, (direction_t)((reldir+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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (b->type->move) b->type->move(b, u, current, next);
|
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
if (current!=next) { /* !pause */
|
|
|
|
|
if (roadto(current, reldir)) k-=BP_ROAD;
|
|
|
|
|
else k-=BP_NORMAL;
|
|
|
|
|
if (k<0) break;
|
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (reldir>=0 && move_blocked(u, current, next)) {
|
2004-04-12 18:21:23 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("leavefail",
|
|
|
|
|
"unit region", u, next));
|
|
|
|
|
}
|
|
|
|
|
if (!entrance_allowed(u, next)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("regionowned",
|
|
|
|
|
"unit region target", u, current, next));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (gereist) {
|
|
|
|
|
unit * wache = bewegung_blockiert_von(u, current);
|
|
|
|
|
if (wache!=NULL) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard",
|
|
|
|
|
"unit region guard", u, current, wache));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +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);
|
|
|
|
|
if (routep) *routep = route;
|
|
|
|
|
else free_regionlist(route);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Ozeanfelder k<>nnen nur von Einheiten mit Schwimmen und ohne
|
|
|
|
|
* Pferde betreten werden. Drachen k<EFBFBD>nnen fliegen. */
|
|
|
|
|
|
|
|
|
|
if (rterrain(next) == T_OCEAN && !canswim(u)) {
|
|
|
|
|
plane *pl = getplane(next);
|
|
|
|
|
if (reldir<MAXDIRECTIONS && pl!=NULL && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("detectoceandir",
|
|
|
|
|
"unit direction", u, reldir));
|
|
|
|
|
} else {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("detectocean",
|
|
|
|
|
"unit region", u, next));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (terrain[rterrain(next)].flags & FORBIDDEN_LAND) {
|
|
|
|
|
plane *pl = getplane(next);
|
|
|
|
|
if (reldir<MAXDIRECTIONS && pl!=NULL && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("detectforbiddendir",
|
|
|
|
|
"unit direction", u, reldir));
|
|
|
|
|
} else {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("detectforbidden",
|
|
|
|
|
"unit region", u, next));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-07-11 16:37:42 +02:00
|
|
|
|
if (old_race(u->race)==RC_INSECT) {
|
|
|
|
|
if (r_insectstalled(next) && is_freezing(u)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("detectforbidden",
|
|
|
|
|
"unit region", u, next));
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
add_regionlist(iroute, next);
|
|
|
|
|
iroute = &(*iroute)->next;
|
|
|
|
|
m++;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
current = next;
|
|
|
|
|
if(!flucht) {
|
|
|
|
|
++gereist;
|
|
|
|
|
if (current==first) break; /* PAUSE beendet die Reise */
|
|
|
|
|
next = movewhere(current, u);
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (gereist) {
|
|
|
|
|
int mode;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
order * ord;
|
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
setguard(u, GUARD_NONE);
|
|
|
|
|
cycle_route(u, gereist);
|
|
|
|
|
|
|
|
|
|
buf[0] = 0;
|
|
|
|
|
|
|
|
|
|
if (flucht == 1)
|
|
|
|
|
mode = 0;
|
|
|
|
|
else if (canride(u)) {
|
|
|
|
|
mode = 1;
|
|
|
|
|
produceexp(u, SK_RIDING, u->number);
|
|
|
|
|
} else
|
|
|
|
|
mode = 2;
|
|
|
|
|
|
|
|
|
|
/* Haben Drachen ihr Ziel erreicht? */
|
|
|
|
|
if (u->faction->no==MONSTER_FACTION) {
|
|
|
|
|
attrib * ta = a_find(u->attribs, &at_targetregion);
|
|
|
|
|
if (ta && current == (region*)ta->data.v) {
|
|
|
|
|
a_remove(&u->attribs, ta);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
set_order(&u->lastorder, parse_order(keywords[K_WAIT], u->faction->locale));
|
|
|
|
|
free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */
|
2002-12-18 01:34:19 +01:00
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* <20>ber die letzte Region braucht man keinen Bericht */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
m--;
|
|
|
|
|
if (m > 0) {
|
2004-04-12 20:51:42 +02:00
|
|
|
|
region_list *rlist = route;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
travelthru(u, first);
|
2004-04-12 20:51:42 +02:00
|
|
|
|
while (rlist!=NULL) {
|
2004-04-12 22:47:22 +02:00
|
|
|
|
region * r = rlist->data;
|
2004-04-12 20:51:42 +02:00
|
|
|
|
|
|
|
|
|
travelthru(u, r);
|
2004-04-12 22:47:22 +02:00
|
|
|
|
rlist=rlist->next;
|
2004-04-12 20:51:42 +02:00
|
|
|
|
if (rlist!=NULL) {
|
2004-04-12 22:47:22 +02:00
|
|
|
|
char * p;
|
|
|
|
|
if (r!=route->data) {
|
|
|
|
|
if (rlist->next==NULL) scat(" und ");
|
|
|
|
|
else scat(", ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p = buf+strlen(buf);
|
|
|
|
|
if (rlist->next) {
|
|
|
|
|
MSG(("travelthru_trail", "region", rlist->data), p, sizeof(buf)-strlen(buf), u->faction->locale, u->faction);
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-04-12 22:47:22 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("travel",
|
|
|
|
|
"unit mode start end regions", u, mode, first, current, strdup(buf)));
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
|
|
|
|
/* und jetzt noch die transportierten Einheiten verschieben */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
for (ord = u->orders; ord; ord = ord->next) {
|
|
|
|
|
if (get_keyword(ord) == K_TRANSPORT) {
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
2004-04-12 18:21:23 +02:00
|
|
|
|
ut = getunit(first, u->faction);
|
|
|
|
|
if (ut) {
|
|
|
|
|
boolean found = false;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (get_keyword(ut->thisorder) == K_DRIVE
|
2004-08-03 17:34:26 +02:00
|
|
|
|
&& !fval(ut, UFL_LONGACTION) && !LongHunger(ut)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ut->thisorder);
|
|
|
|
|
skip_token();
|
2004-04-12 18:21:23 +02:00
|
|
|
|
u2 = getunit(first, ut->faction);
|
|
|
|
|
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);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (can_survive(ut, current)) {
|
2004-04-12 20:51:42 +02:00
|
|
|
|
travel_route(ut, ut->region, route);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
move_unit(ut, current, NULL);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
if (fval(ut, UFL_FOLLOWED) && route!=NULL) {
|
|
|
|
|
followers += notify_followers(first, ut, route);
|
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, u->thisorder, 287, MSG_MOVE);
|
|
|
|
|
cmistake(ut, ut->thisorder, 230, MSG_MOVE);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found) {
|
|
|
|
|
if(cansee(u->faction, u->region, ut, 0)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 90, MSG_MOVE);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
} else {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 63, MSG_MOVE);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (ut) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 63, MSG_MOVE);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
} else {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 99, MSG_MOVE);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
move_unit(u, current, NULL);
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
else if (flucht) {
|
2004-04-12 18:21:23 +02:00
|
|
|
|
move_unit(u, current, NULL);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
|
|
|
|
set_order(&u->thisorder, NULL);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
fset(u, UFL_LONGACTION);
|
|
|
|
|
setguard(u, GUARD_NONE);
|
|
|
|
|
|
|
|
|
|
if (fval(u, UFL_FOLLOWING)) caught_target(current, u);
|
|
|
|
|
if (routep) *routep = route;
|
|
|
|
|
else free_regionlist(route);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return followers;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2004-06-21 18:45:27 +02:00
|
|
|
|
ship_ready(const region * r, unit * u)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (!fval(u, UFL_OWNER)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 146, MSG_MOVE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 15, MSG_MOVE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (!enoughsailors(u->ship, r)) {
|
|
|
|
|
cmistake(u, u->thisorder, 1, MSG_MOVE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* 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) )
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 17, MSG_MOVE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 18, MSG_MOVE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Pr<50>ft, ob Ablegen von einer K<>ste in eine der erlaubten Richtungen erfolgt. */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
check_takeoff(ship *sh, region *from, region *to)
|
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (rterrain(from)!=T_OCEAN && sh->coast != NODIRECTION) {
|
|
|
|
|
direction_t coast = sh->coast;
|
|
|
|
|
direction_t dir = reldirection(from, to);
|
|
|
|
|
direction_t coastr = (direction_t)((coast+1) % MAXDIRECTIONS);
|
|
|
|
|
direction_t coastl = (direction_t)((coast+MAXDIRECTIONS-1) % MAXDIRECTIONS);
|
|
|
|
|
|
|
|
|
|
if (dir!=coast && dir!=coastl && dir!=coastr
|
|
|
|
|
&& !check_working_buildingtype(from, bt_find("harbour")))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
static region_list *
|
|
|
|
|
sail(unit * u, region * next_point, boolean move_on_land)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-05-31 18:21:03 +02:00
|
|
|
|
region *starting_point = u->region;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
region *current_point, *last_point;
|
|
|
|
|
int k, step = 0;
|
|
|
|
|
region_list *route = NULL;
|
|
|
|
|
region_list **iroute = &route;
|
2004-05-31 18:21:03 +02:00
|
|
|
|
ship * sh = u->ship;
|
|
|
|
|
faction * f = u->faction;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (!ship_ready(starting_point, u)) return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden
|
|
|
|
|
* dann nacheinander ausgef<EFBFBD>hrt. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
k = shipspeed(sh, u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
last_point = starting_point;
|
|
|
|
|
current_point = starting_point;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* 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!). current_point ist die letzte g<EFBFBD>ltige,
|
|
|
|
|
* befahrene Region. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
while (current_point!=next_point && step < k && next_point) {
|
|
|
|
|
terrain_t tthis = rterrain(current_point);
|
|
|
|
|
/* these values need to be updated if next_point changes (due to storms): */
|
|
|
|
|
terrain_t tnext = rterrain(next_point);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
direction_t dir = reldirection(current_point, next_point);
|
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
assert(sh==u->ship || !"ship has sunk, but we didn't notice it");
|
|
|
|
|
|
|
|
|
|
if (terrain[tnext].flags & FORBIDDEN_LAND) {
|
2004-04-12 18:21:23 +02:00
|
|
|
|
plane *pl = getplane(next_point);
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (pl && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
ADDMSG(&f->msgs, msg_message("sailforbiddendir",
|
|
|
|
|
"ship direction", sh, dir));
|
2004-04-12 18:21:23 +02:00
|
|
|
|
} else {
|
2004-05-31 18:21:03 +02:00
|
|
|
|
ADDMSG(&f->msgs, msg_message("sailforbidden",
|
|
|
|
|
"ship region", sh, next_point));
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (!flying_ship(sh)) {
|
|
|
|
|
|
|
|
|
|
/* storms should be the first thing we do. */
|
|
|
|
|
int stormchance = storms[month(0)] * 5 / shipspeed(sh, u);
|
|
|
|
|
if (check_leuchtturm(next_point, NULL)) stormchance /= 3;
|
|
|
|
|
|
|
|
|
|
if (rand()%10000 < stormchance && next_point->terrain == T_OCEAN) {
|
|
|
|
|
if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) {
|
|
|
|
|
region * rnext = NULL;
|
|
|
|
|
boolean storm = true;
|
|
|
|
|
int d_offset = rand() % MAXDIRECTIONS;
|
|
|
|
|
direction_t d;
|
|
|
|
|
/* Sturm nur, wenn n<>chste Region Hochsee ist. */
|
|
|
|
|
for (d=0;d!=MAXDIRECTIONS;++d) {
|
|
|
|
|
direction_t dnext = (direction_t)((d + d_offset) % MAXDIRECTIONS);
|
|
|
|
|
region * rn = rconnect(current_point, dnext);
|
|
|
|
|
|
|
|
|
|
if (rn!=NULL) {
|
|
|
|
|
terrain_t t = rterrain(rn);
|
|
|
|
|
|
|
|
|
|
if (terrain[t].flags & FORBIDDEN_LAND) continue;
|
|
|
|
|
if (t!=T_OCEAN) {
|
|
|
|
|
storm = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (rn!=next_point) rnext = rn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (storm && rnext!=NULL) {
|
|
|
|
|
ADDMSG(&f->msgs, msg_message("storm", "ship region sink",
|
|
|
|
|
sh, current_point, sh->damage>=sh->size * DAMAGE_SCALE));
|
|
|
|
|
|
|
|
|
|
/* damage the ship. we handle destruction in the end */
|
|
|
|
|
damage_ship(sh, 0.02);
|
|
|
|
|
if (sh->damage>=sh->size * DAMAGE_SCALE) break;
|
|
|
|
|
|
|
|
|
|
next_point = rnext;
|
|
|
|
|
/* these values need to be updated if next_point changes (due to storms): */
|
|
|
|
|
tnext = rterrain(next_point);
|
|
|
|
|
dir = reldirection(current_point, next_point);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tthis != T_OCEAN) {
|
|
|
|
|
if (tnext != T_OCEAN) {
|
|
|
|
|
if (!move_on_land) {
|
|
|
|
|
/* check that you're not traveling from one land region to another. */
|
2004-04-12 18:21:23 +02:00
|
|
|
|
plane *pl = getplane(next_point);
|
2004-05-31 18:21:03 +02:00
|
|
|
|
|
|
|
|
|
if (pl!=NULL && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
/* we don't have that case yet, but hey... */
|
2004-04-12 18:21:23 +02:00
|
|
|
|
sprintf(buf, "Die %s entdeckt, da<64> im %s Festland ist.",
|
2004-05-31 18:21:03 +02:00
|
|
|
|
shipname(sh), locale_string(u->faction->locale, directions[dir]));
|
2004-04-12 18:21:23 +02:00
|
|
|
|
} else {
|
|
|
|
|
sprintf(buf, "Die %s entdeckt, da<64> (%d,%d) Festland ist.",
|
2004-05-31 18:21:03 +02:00
|
|
|
|
shipname(sh), region_x(next_point,u->faction),
|
2004-04-12 18:21:23 +02:00
|
|
|
|
region_y(next_point,u->faction));
|
|
|
|
|
}
|
|
|
|
|
addmessage(0, u->faction, buf, MSG_MOVE, ML_WARN);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-05-31 18:21:03 +02:00
|
|
|
|
} else {
|
|
|
|
|
if (check_takeoff(sh, current_point, next_point) == false) {
|
|
|
|
|
/* Schiff kann nicht ablegen */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 182, MSG_MOVE);
|
2004-05-31 18:21:03 +02:00
|
|
|
|
break;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2004-05-31 18:21:03 +02:00
|
|
|
|
}
|
|
|
|
|
} else if (tnext==T_OCEAN) {
|
|
|
|
|
/* target region is an ocean, and we're not leaving a shore */
|
|
|
|
|
if (!(sh->type->flags & SFL_OPENSEA)) {
|
|
|
|
|
/* ship can only stay close to shore */
|
|
|
|
|
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 */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 249, MSG_MOVE);
|
2004-05-31 18:21:03 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-09 21:35:50 +02:00
|
|
|
|
if (!ship_allowed(sh, next_point)) {
|
2004-05-31 18:21:03 +02:00
|
|
|
|
/* for some reason or another, we aren't allowed in there.. */
|
|
|
|
|
if (check_leuchtturm(current_point, NULL)) {
|
|
|
|
|
ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh));
|
|
|
|
|
} else {
|
|
|
|
|
damage_ship(sh, 0.10);
|
|
|
|
|
/* we handle destruction at the end */
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (is_cursed(next_point->attribs, C_MAELSTROM, 0)) {
|
|
|
|
|
if (do_maelstrom(next_point, u)==NULL) break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
} /* !flying_ship */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
/* Falls Blockade, endet die Seglerei hier */
|
|
|
|
|
if (move_blocked(u, current_point, next_point)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("sailfail", "ship region", sh, current_point));
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
/* Falls kein Problem, eines weiter ziehen */
|
|
|
|
|
fset(sh, SF_MOVED);
|
|
|
|
|
add_regionlist(iroute, next_point);
|
|
|
|
|
iroute = &(*iroute)->next;
|
|
|
|
|
step++;
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
last_point = current_point;
|
|
|
|
|
current_point = next_point;
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (rterrain(current_point) != T_OCEAN && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) break;
|
|
|
|
|
next_point = movewhere(current_point, u);
|
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (sh->damage>=sh->size * DAMAGE_SCALE) {
|
|
|
|
|
ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh));
|
|
|
|
|
destroy_ship(sh);
|
|
|
|
|
sh = NULL;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02: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 */
|
|
|
|
|
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (sh!=NULL && fval(sh, SF_MOVED)) {
|
|
|
|
|
unit * hafenmeister;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten
|
|
|
|
|
* transferiert wurden, kann der aktuelle Befehl gel<EFBFBD>scht werden. */
|
|
|
|
|
cycle_route(u, step);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
set_order(&u->thisorder, NULL);
|
2004-09-05 10:01:48 +02:00
|
|
|
|
set_coast(sh, last_point, current_point);
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02: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));
|
|
|
|
|
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, UFL_FOLLOWING)) caught_target(current_point, u);
|
|
|
|
|
|
|
|
|
|
sh = move_ship(sh, starting_point, current_point, route);
|
|
|
|
|
|
|
|
|
|
/* Hafengeb<65>hren ? */
|
|
|
|
|
|
|
|
|
|
hafenmeister = owner_buildingtyp(current_point, bt_find("harbour"));
|
|
|
|
|
if (sh && hafenmeister != NULL) {
|
|
|
|
|
item * itm;
|
2004-05-31 18:21:03 +02:00
|
|
|
|
unit * u2;
|
|
|
|
|
boolean first = true;
|
|
|
|
|
item * trans = NULL;
|
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
for (u2 = current_point->units; u2; u2 = u2->next) {
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (u2->ship == sh &&
|
2004-04-12 18:21:23 +02:00
|
|
|
|
!alliedunit(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) {
|
2004-05-31 18:21:03 +02:00
|
|
|
|
int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (trans) {
|
|
|
|
|
sprintf(buf, "%s erhielt ", hafenmeister->name);
|
|
|
|
|
for (itm = trans; itm; itm=itm->next) {
|
2004-05-31 18:21:03 +02:00
|
|
|
|
if (!first) {
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (itm->next!=NULL && itm->next->next==NULL) {
|
|
|
|
|
scat(" und ");
|
|
|
|
|
} else {
|
|
|
|
|
scat(", ");
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-05-31 18:21:03 +02:00
|
|
|
|
first = false;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
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)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return route;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
2004-06-21 18:45:27 +02:00
|
|
|
|
get_captain(const ship * sh)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-06-21 18:45:27 +02:00
|
|
|
|
const region * r = sh->region;
|
|
|
|
|
unit *u;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (u->ship == sh && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill)
|
|
|
|
|
return u;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/* Segeln, Wandern, Reiten
|
2004-02-29 16:29:27 +01:00
|
|
|
|
* when this routine returns a non-zero value, movement for the region needs
|
|
|
|
|
* to be done again because of followers that got new MOVE orders.
|
|
|
|
|
* Setting FL_LONGACTION will prevent a unit from being handled more than once
|
|
|
|
|
* by this routine
|
2004-06-21 18:45:27 +02:00
|
|
|
|
*
|
|
|
|
|
* the token parser needs to be initialized before calling this function!
|
2004-02-29 16:29:27 +01:00
|
|
|
|
*/
|
2004-02-22 15:42:24 +01:00
|
|
|
|
static int
|
2004-04-12 18:21:23 +02:00
|
|
|
|
move(unit * u, boolean move_on_land)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
region * r = u->region;
|
|
|
|
|
region_list * route = NULL;
|
|
|
|
|
region * r2 = movewhere(r, u);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
int followers = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (r2==NULL) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 71, MSG_MOVE);
|
2004-02-29 16:29:27 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
else if (u->ship && fval(u, UFL_OWNER)) {
|
|
|
|
|
route = sail(u, r2, move_on_land);
|
|
|
|
|
} else {
|
2004-07-09 15:41:14 +02:00
|
|
|
|
followers += travel(u, r2, 0, &route);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2004-02-29 16:29:27 +01:00
|
|
|
|
|
2004-07-14 09:12:36 +02:00
|
|
|
|
fset(u, UFL_LONGACTION);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
set_order(&u->thisorder, NULL);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (fval(u, UFL_FOLLOWED) && route!=NULL) {
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return followers + notify_followers(r, u, route);
|
2004-02-29 16:29:27 +01:00
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (route!=NULL) free_regionlist(route);
|
2004-07-09 15:41:14 +02:00
|
|
|
|
return followers;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-01-11 10:21:06 +01:00
|
|
|
|
typedef struct piracy_data {
|
|
|
|
|
const struct faction * follow;
|
|
|
|
|
direction_t dir;
|
|
|
|
|
} piracy_data;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
piracy_init(struct attrib * a)
|
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(1, sizeof(piracy_data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
piracy_done(struct attrib * a)
|
|
|
|
|
{
|
|
|
|
|
free(a->data.v);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static attrib_type at_piracy_direction = {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"piracy_direction",
|
2004-01-11 10:21:06 +01:00
|
|
|
|
piracy_init,
|
|
|
|
|
piracy_done,
|
2001-01-25 10:37:55 +01:00
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
2004-01-11 10:21:06 +01:00
|
|
|
|
static attrib *
|
|
|
|
|
mk_piracy(const faction * f, direction_t target_dir)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_new(&at_piracy_direction);
|
|
|
|
|
piracy_data * data = a->data.v;
|
|
|
|
|
data->follow = f;
|
|
|
|
|
data->dir = target_dir;
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
static int
|
2004-06-21 18:45:27 +02:00
|
|
|
|
piracy_cmd(unit *u, struct order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
region *r = u->region;
|
|
|
|
|
ship *sh = u->ship, *sh2;
|
|
|
|
|
direction_t dir, target_dir = NODIRECTION;
|
|
|
|
|
int aff[MAXDIRECTIONS];
|
|
|
|
|
int saff = 0;
|
|
|
|
|
int *il;
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
boolean all = true;
|
|
|
|
|
attrib *a;
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (!sh) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 144, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (!fval(u, UFL_OWNER)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 46, MSG_MOVE);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Feststellen, ob schon ein anderer alliierter Pirat ein
|
|
|
|
|
* Ziel gefunden hat. */
|
|
|
|
|
|
|
|
|
|
il = intlist_init();
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
s = getstrtoken();
|
|
|
|
|
while(s && *s) {
|
|
|
|
|
il = intlist_add(il, atoi(s));
|
|
|
|
|
all = false;
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
for (a = a_find(r->attribs, &at_piracy_direction); a; a=a->nexttype) {
|
2004-01-11 10:21:06 +01:00
|
|
|
|
piracy_data * data = a->data.v;
|
|
|
|
|
const faction *f = data->follow;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-11 10:21:06 +01:00
|
|
|
|
if (alliedunit(u, f, HELP_FIGHT) && intlist_find(il, a->data.sa[1])) {
|
|
|
|
|
target_dir = data->dir;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wenn nicht, sehen wir, ob wir ein Ziel finden. */
|
|
|
|
|
|
|
|
|
|
if (target_dir == NODIRECTION) {
|
|
|
|
|
|
|
|
|
|
/* Einheit ist also Kapit<69>n. Jetzt gucken, in wievielen
|
|
|
|
|
* Nachbarregionen potentielle Opfer sind. */
|
|
|
|
|
|
|
|
|
|
for(dir = 0; dir < MAXDIRECTIONS; dir++) {
|
|
|
|
|
region *rc = rconnect(r, dir);
|
|
|
|
|
aff[dir] = 0;
|
|
|
|
|
if(rc && (terrain[rterrain(rc)].flags & SWIM_INTO)
|
|
|
|
|
&& check_takeoff(sh, r, rc) == true) {
|
|
|
|
|
|
|
|
|
|
for(sh2 = rc->ships; sh2; sh2 = sh2->next) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
unit * cap = shipowner(sh2);
|
2002-10-20 12:40:42 +02:00
|
|
|
|
if (cap && (intlist_find(il, cap->faction->no) || all)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
aff[dir]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Und aufaddieren. */
|
|
|
|
|
saff += aff[dir];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(saff != 0) {
|
|
|
|
|
saff = rand()%saff;
|
|
|
|
|
for(dir = 0; dir < MAXDIRECTIONS; dir++) {
|
|
|
|
|
if(saff < aff[dir]) break;
|
|
|
|
|
saff -= aff[dir];
|
|
|
|
|
}
|
|
|
|
|
target_dir = dir;
|
2004-01-11 10:21:06 +01:00
|
|
|
|
a = a_add(&r->attribs, mk_piracy(u->faction, target_dir));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(il);
|
|
|
|
|
|
|
|
|
|
/* Wenn kein Ziel gefunden, entsprechende Meldung generieren */
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (target_dir == NODIRECTION) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
|
|
|
|
new_message(u->faction, "piratenovictim%h:ship%r:region", sh, r));
|
2004-02-22 15:42:24 +01:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Meldung generieren */
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"piratesawvictim%h:ship%r:region%d:dir", sh, r, target_dir));
|
|
|
|
|
|
|
|
|
|
/* Befehl konstruieren */
|
2001-09-05 21:40:40 +02:00
|
|
|
|
sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]),
|
2001-04-16 16:34:19 +02:00
|
|
|
|
locale_string(u->faction->locale, directions[target_dir]));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
set_order(&u->thisorder, parse_order(buf, u->faction->locale));
|
2004-06-27 14:19:58 +02:00
|
|
|
|
free_order(u->thisorder); /* parse_order & set_order have each increased the refcount */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Bewegung ausf<73>hren */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(u->thisorder);
|
|
|
|
|
skip_token();
|
2004-04-12 18:21:23 +02:00
|
|
|
|
return move(u, true);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
age_traveldir(region *r)
|
|
|
|
|
{
|
|
|
|
|
attrib *a = a_find(r->attribs, &at_traveldir);
|
|
|
|
|
|
|
|
|
|
while(a) {
|
|
|
|
|
a->data.ca[3]--;
|
|
|
|
|
if(a->data.ca[3] <= 0) {
|
|
|
|
|
attrib *an = a->nexttype;
|
|
|
|
|
a_remove(&r->attribs, a);
|
|
|
|
|
a = an;
|
|
|
|
|
} else {
|
|
|
|
|
a = a->nexttype;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static direction_t
|
|
|
|
|
hunted_dir(attrib *at, int id)
|
|
|
|
|
{
|
2004-07-14 09:12:36 +02:00
|
|
|
|
attrib *a = a_find(at, &at_shiptrail);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
while (a!=NULL) {
|
|
|
|
|
traveldir *t = (traveldir *)(a->data.v);
|
|
|
|
|
if (t->no == id) return t->dir;
|
|
|
|
|
a = a->nexttype;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
return NODIRECTION;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static boolean
|
2004-02-22 15:42:24 +01:00
|
|
|
|
can_move(const unit * u)
|
|
|
|
|
{
|
|
|
|
|
if (u->race->flags & RCF_CANNOTMOVE) return false;
|
|
|
|
|
if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
hunt(unit *u)
|
|
|
|
|
{
|
2004-04-10 12:43:46 +02:00
|
|
|
|
region *rc = u->region;
|
|
|
|
|
int moves, id;
|
|
|
|
|
char command[256];
|
|
|
|
|
direction_t dir;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
if(!u->ship) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 144, MSG_MOVE);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
return 0;
|
|
|
|
|
} else if(!fval(u, UFL_OWNER)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 146, MSG_MOVE);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
return 0;
|
|
|
|
|
} else if(attacked(u)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 52, MSG_MOVE);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
return 0;
|
|
|
|
|
} else if (!can_move(u)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 55, MSG_MOVE);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
id = getshipid();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
if (id <= 0) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 20, MSG_MOVE);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
dir = hunted_dir(rc->attribs, id);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
if (dir == NODIRECTION) {
|
|
|
|
|
ship * sh = findship(id);
|
2004-04-25 09:37:53 +02:00
|
|
|
|
if (sh==NULL || sh->region!=rc) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 20, MSG_MOVE);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
sprintf(command, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]),
|
|
|
|
|
locale_string(u->faction->locale, directions[dir]));
|
|
|
|
|
moves = 1;
|
|
|
|
|
|
|
|
|
|
rc = rconnect(rc, dir);
|
|
|
|
|
while (moves < shipspeed(u->ship, u) && (dir = hunted_dir(rc->attribs, id)) != NODIRECTION)
|
|
|
|
|
{
|
|
|
|
|
strcat(command, " ");
|
|
|
|
|
strcat(command, locale_string(u->faction->locale, directions[dir]));
|
|
|
|
|
moves++;
|
|
|
|
|
rc = rconnect(rc, dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In command steht jetzt das NACH-Kommando. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* NACH ignorieren und Parsing initialisieren. */
|
|
|
|
|
igetstrtoken(command);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/* NACH ausf<73>hren */
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (move(u, false)!=0) {
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/* niemand sollte auf einen kapit<69>n direkt ein folge haben, oder? */
|
|
|
|
|
assert(1==0);
|
|
|
|
|
}
|
2004-04-10 12:43:46 +02:00
|
|
|
|
fset(u, UFL_LONGACTION); /* Von Hand setzen, um Endlosschleife zu vermeiden, wenn Verfolgung nicht erfolgreich */
|
|
|
|
|
return 1; /* true -> Einheitenliste von vorne durchgehen */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
destroy_damaged_ships(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
ship *sh,*shn;
|
|
|
|
|
|
|
|
|
|
for(r=regions;r;r=r->next) {
|
|
|
|
|
for(sh=r->ships;sh;) {
|
|
|
|
|
shn = sh->next;
|
|
|
|
|
if (sh->damage>=sh->size * DAMAGE_SCALE) {
|
2004-05-31 18:21:03 +02:00
|
|
|
|
destroy_ship(sh);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
sh = shn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 17:08:39 +01:00
|
|
|
|
#ifdef TODO /* Wenn Feature ausgearbeitet */
|
|
|
|
|
|
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
is_disorientated(unit *u)
|
|
|
|
|
{
|
2004-02-22 17:08:39 +01: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)))
|
|
|
|
|
return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 17:08:39 +01:00
|
|
|
|
if (curse_active(get_curse(u->region->attribs, regconf_ct)))
|
|
|
|
|
return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 17:08:39 +01:00
|
|
|
|
return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
regain_orientation(region * r)
|
|
|
|
|
{
|
|
|
|
|
ship *sh;
|
|
|
|
|
curse *c;
|
|
|
|
|
unit *u, *cap;
|
|
|
|
|
|
|
|
|
|
for(sh = r->ships; sh; sh = sh->next) {
|
|
|
|
|
c = get_curse(sh->attribs, C_DISORIENTATION, 0);
|
|
|
|
|
if(!c) continue;
|
|
|
|
|
|
|
|
|
|
/* Das Schiff bekommt seine Orientierung zur<75>ck, wenn es:
|
|
|
|
|
* a) An Land treibt.
|
|
|
|
|
* b) Gl<EFBFBD>ck hat.
|
|
|
|
|
* c) In einer Region mit einem nicht verwirrten alliierten
|
|
|
|
|
* Schiff steht.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
cap = shipowner(r, sh);
|
|
|
|
|
|
|
|
|
|
if(r->terrain != T_OCEAN || rand() % 10 >= storms[month(0)]) {
|
|
|
|
|
remove_curse(&sh->attribs, C_DISORIENTATION, 0);
|
|
|
|
|
add_message(&cap->faction->msgs,
|
|
|
|
|
new_message(cap->faction, "shipnoconf%h:ship", sh));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(u=r->units;u;u=u->next) {
|
|
|
|
|
if(u != cap
|
|
|
|
|
&& allied(cap, u->faction, HELP_GUARD)
|
|
|
|
|
&& is_disorientated(u) == false) {
|
|
|
|
|
remove_curse(&sh->attribs, C_DISORIENTATION, 0);
|
|
|
|
|
add_message(&cap->faction->msgs,
|
|
|
|
|
new_message(cap->faction, "shipnoconf%h:ship", sh));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Bewegung, Verfolgung, Piraterie */
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/** ships that folow other ships
|
|
|
|
|
* Dann generieren die jagenden Einheiten ihre Befehle und
|
|
|
|
|
* bewegen sich.
|
|
|
|
|
* Following the trails of other ships.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
move_hunters(void)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-02-22 15:42:24 +01:00
|
|
|
|
region *r;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
for (r = regions; r; r = r->next) {
|
2004-06-30 23:29:17 +02:00
|
|
|
|
unit ** up = &r->units, * u;
|
|
|
|
|
for (u=r->units; u; u=u->next) freset(u, FL_DH);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
|
2004-06-30 23:29:17 +02:00
|
|
|
|
while (*up!=NULL) {
|
|
|
|
|
unit * u = *up;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-30 23:29:17 +02:00
|
|
|
|
if (!fval(u, FL_DH)) {
|
|
|
|
|
order * ord;
|
|
|
|
|
|
|
|
|
|
fset(u, FL_DH);
|
|
|
|
|
|
|
|
|
|
for (ord=u->orders;ord;ord=ord->next) {
|
|
|
|
|
if (get_keyword(ord) == K_FOLLOW) {
|
|
|
|
|
param_t p;
|
|
|
|
|
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
p = getparam(u->faction->locale);
|
|
|
|
|
if (p != P_SHIP) {
|
|
|
|
|
if (p != P_UNIT) {
|
|
|
|
|
cmistake(u, ord, 240, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-30 23:29:17 +02:00
|
|
|
|
/* wir folgen definitiv einem Schiff. */
|
|
|
|
|
|
|
|
|
|
if (fval(u, UFL_LONGACTION)) {
|
|
|
|
|
cmistake(u, ord, 52, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
} else if (!can_move(u)) {
|
|
|
|
|
cmistake(u, ord, 55, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-03 17:34:26 +02:00
|
|
|
|
if (!fval(u, UFL_LONGACTION) && !LongHunger(u) && hunt(u)) {
|
2004-06-30 23:29:17 +02:00
|
|
|
|
up = &r->units;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-30 23:29:17 +02:00
|
|
|
|
if (*up==u) up=&u->next;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-22 15:42:24 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/** Piraten and Drift
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
move_pirates(void)
|
|
|
|
|
{
|
|
|
|
|
region * r;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
unit ** up = &r->units;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
while (*up) {
|
|
|
|
|
unit *u = *up;
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (!fval(u, UFL_LONGACTION) && get_keyword(u->thisorder) == K_PIRACY) {
|
|
|
|
|
piracy_cmd(u, u->thisorder);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
fset(u, UFL_LONGACTION);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
if (*up==u) {
|
|
|
|
|
/* not moved, use next unit */
|
|
|
|
|
up = &u->next;
|
|
|
|
|
} else if (*up && (*up)->region!=r) {
|
|
|
|
|
/* moved the previous unit along with u (units on same ship)
|
|
|
|
|
* must start from the beginning again */
|
|
|
|
|
up = &r->units;
|
|
|
|
|
}
|
|
|
|
|
/* else *up is already the next unit */
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
a_removeall(&r->attribs, &at_piracy_direction);
|
|
|
|
|
age_traveldir(r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
movement(void)
|
|
|
|
|
{
|
|
|
|
|
int ships;
|
|
|
|
|
|
|
|
|
|
/* Initialize the additional encumbrance by transported units */
|
|
|
|
|
init_drive();
|
|
|
|
|
|
|
|
|
|
/* Move ships in last phase, others first
|
|
|
|
|
* This is to make sure you can't land someplace and then get off the ship
|
|
|
|
|
* in the same turn.
|
|
|
|
|
*/
|
|
|
|
|
for (ships=0;ships<=1;++ships) {
|
|
|
|
|
region * r = regions;
|
|
|
|
|
while (r!=NULL) {
|
|
|
|
|
unit ** up = &r->units;
|
|
|
|
|
boolean repeat = false;
|
|
|
|
|
|
|
|
|
|
while (*up) {
|
|
|
|
|
unit *u = *up;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
keyword_t kword = get_keyword(u->thisorder);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
switch (kword) {
|
|
|
|
|
case K_ROUTE:
|
|
|
|
|
case K_MOVE:
|
|
|
|
|
if (attacked(u)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 52, MSG_MOVE);
|
|
|
|
|
set_order(&u->thisorder, NULL);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
} else if (!can_move(u)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 55, MSG_MOVE);
|
|
|
|
|
set_order(&u->thisorder, NULL);
|
2004-02-22 15:42:24 +01:00
|
|
|
|
} else {
|
|
|
|
|
if (ships) {
|
|
|
|
|
if (u->ship && fval(u, UFL_OWNER)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(u->thisorder);
|
|
|
|
|
skip_token();
|
2004-07-02 07:41:47 +02:00
|
|
|
|
if (move(u, false)!=0) repeat = true;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (u->ship==NULL || !fval(u, UFL_OWNER)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(u->thisorder);
|
|
|
|
|
skip_token();
|
2004-07-03 13:36:34 +02:00
|
|
|
|
if (move(u, false)!=0) repeat = true;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-02-29 16:29:27 +01:00
|
|
|
|
if (u->region==r) {
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/* not moved, use next unit */
|
|
|
|
|
up = &u->next;
|
|
|
|
|
} else if (*up && (*up)->region!=r) {
|
|
|
|
|
/* moved the previous unit along with u (units on ships, for example)
|
|
|
|
|
* must start from the beginning again */
|
|
|
|
|
up = &r->units;
|
|
|
|
|
}
|
|
|
|
|
/* else *up is already the next unit */
|
|
|
|
|
}
|
2004-07-14 09:12:36 +02:00
|
|
|
|
if (!repeat) {
|
|
|
|
|
if (ships==0) {
|
|
|
|
|
/* Abtreiben von besch<63>digten, unterbemannten, <20>berladenen Schiffen */
|
|
|
|
|
drifting_ships(r);
|
|
|
|
|
}
|
|
|
|
|
r = r->next;
|
|
|
|
|
}
|
2004-02-22 15:42:24 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
move_hunters();
|
|
|
|
|
move_pirates();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-22 15:42:24 +01:00
|
|
|
|
/** Overrides long orders with a FOLLOW order if the target is moving.
|
|
|
|
|
* FOLLOW SHIP is a long order, and doesn't need to be treated in here.
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
2004-02-22 15:42:24 +01:00
|
|
|
|
follow_unit(void)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region * r;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
for (r=regions;r;r=r->next) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
unit * u;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
for (u=r->units;u;u=u->next) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
attrib * a;
|
|
|
|
|
order * ord;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
2004-08-03 17:34:26 +02:00
|
|
|
|
if (fval(u, UFL_LONGACTION) || LongHunger(u)) continue;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
a = a_find(u->attribs, &at_follow);
|
|
|
|
|
for (ord=u->orders;ord;ord=ord->next) {
|
2004-02-22 15:42:24 +01:00
|
|
|
|
const struct locale * lang = u->faction->locale;
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (get_keyword(ord) == K_FOLLOW) {
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
if (getparam(lang) == P_UNIT) {
|
|
|
|
|
int id = read_unitid(u->faction, r);
|
|
|
|
|
|
|
|
|
|
if (id>0) {
|
|
|
|
|
unit * uf = findunit(id);
|
|
|
|
|
if (!a) {
|
|
|
|
|
a = a_add(&u->attribs, make_follow(uf));
|
|
|
|
|
} else {
|
|
|
|
|
a->data.v = uf;
|
|
|
|
|
}
|
|
|
|
|
} else if (a) {
|
|
|
|
|
a_remove(&u->attribs, a);
|
|
|
|
|
a = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a && !fval(u, UFL_MOVED)) {
|
|
|
|
|
unit * u2 = a->data.v;
|
|
|
|
|
|
|
|
|
|
if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0))
|
|
|
|
|
continue;
|
|
|
|
|
for (ord=u2->orders;ord;ord=ord->next) {
|
|
|
|
|
switch (get_keyword(ord)) {
|
|
|
|
|
case K_MOVE:
|
|
|
|
|
case K_ROUTE:
|
|
|
|
|
case K_DRIVE:
|
|
|
|
|
case K_FOLLOW:
|
|
|
|
|
case K_PIRACY:
|
|
|
|
|
fset(u, UFL_FOLLOWING);
|
|
|
|
|
fset(u2, UFL_FOLLOWED);
|
|
|
|
|
set_order(&u->thisorder, NULL);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|