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-09-05 11:51:57 +02:00
|
|
|
|
#include <util/base36.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
|
|
|
|
|
|
|
|
|
extern border_type bt_wisps;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
int * storms;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
};
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
typedef struct follower {
|
|
|
|
|
struct follower * next;
|
|
|
|
|
unit * uf;
|
|
|
|
|
unit * ut;
|
|
|
|
|
region_list * route_end;
|
|
|
|
|
} follower;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_followers(unit * target, region * r, region_list * route_end, follower ** followers)
|
|
|
|
|
{
|
|
|
|
|
unit * uf;
|
|
|
|
|
for (uf=r->units;uf;uf=uf->next) {
|
|
|
|
|
if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_LONGACTION)) {
|
|
|
|
|
const attrib * a = a_findc(uf->attribs, &at_follow);
|
|
|
|
|
if (a && a->data.v == target) {
|
|
|
|
|
follower * fnew = malloc(sizeof(follower));
|
|
|
|
|
fnew->uf = uf;
|
|
|
|
|
fnew->ut = target;
|
|
|
|
|
fnew->route_end = route_end;
|
|
|
|
|
fnew->next = *followers;
|
|
|
|
|
*followers = fnew;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
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_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)
|
|
|
|
|
{
|
2004-12-20 23:59:42 +01:00
|
|
|
|
if (a->data.sa[0] > 0) {
|
|
|
|
|
a->data.sa[0] = a->data.sa[0] - a->data.sa[1];
|
2004-05-07 13:11:30 +02:00
|
|
|
|
}
|
2004-12-20 23:59:42 +01:00
|
|
|
|
return a->data.sa[0]>0;
|
2004-05-07 13:11:30 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-11-07 10:01:22 +01:00
|
|
|
|
n += min(personen, tmp) * (STRENGTHMULTIPLIER-1) * personcapacity(u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
enum {
|
|
|
|
|
E_CANWALK_OK = 0,
|
|
|
|
|
E_CANWALK_TOOMANYHORSES,
|
|
|
|
|
E_CANWALK_TOOMANYCARTS,
|
|
|
|
|
E_CANWALK_TOOHEAVY
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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 */
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (u->faction->no == 0) return E_CANWALK_OK;
|
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)
|
2004-12-19 17:39:51 +01:00
|
|
|
|
return E_CANWALK_TOOMANYHORSES;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (walkingcapacity(u) - eff_weight(u) >= 0)
|
2004-12-19 17:39:51 +01:00
|
|
|
|
return E_CANWALK_OK;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* 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)
|
2004-12-19 17:39:51 +01:00
|
|
|
|
return E_CANWALK_TOOMANYCARTS;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* 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) */
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
return E_CANWALK_TOOHEAVY;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-12-19 17:39:51 +01:00
|
|
|
|
mark_travelthru(const unit * u, region * r, region_list * route, region_list * route_end)
|
2004-04-12 13:00:22 +02:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
/* kein travelthru in der letzten region! */
|
2004-12-19 17:39:51 +01:00
|
|
|
|
while (route!=route_end) {
|
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-12-19 17:39:51 +01:00
|
|
|
|
if (route!=NULL) mark_travelthru(u, from, route, NULL);
|
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;
|
|
|
|
|
}
|
2004-09-05 11:51:57 +02:00
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2004-09-11 09:09:59 +02:00
|
|
|
|
if (rterrain(sh->region)!=T_OCEAN && sh->coast!=NODIRECTION) {
|
2004-09-05 11:51:57 +02:00
|
|
|
|
region * rcoast = rconnect(sh->region, sh->coast);
|
|
|
|
|
if (rterrain(rcoast)!=T_OCEAN) {
|
|
|
|
|
log_error(("ship %s sailed into a coast with no ocean neighbours.\n",
|
|
|
|
|
shipid(sh)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-04-10 12:43:46 +02:00
|
|
|
|
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
|
|
|
|
/* 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-12-22 23:57:47 +01: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;
|
|
|
|
|
|
2004-10-19 20:16:35 +02:00
|
|
|
|
if (!present(r, target)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower",
|
|
|
|
|
target, u));
|
|
|
|
|
} else if (!alliedunit(target, u->faction, HELP_ALL)
|
|
|
|
|
&& cansee(target->faction, r, u, 0))
|
|
|
|
|
{
|
|
|
|
|
ADDMSG(&target->faction->msgs, msg_message("followdetect",
|
|
|
|
|
"unit follower", target, u));
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
2004-10-19 23:38:41 +02:00
|
|
|
|
if (invisible(reisender) >= reisender->number &&
|
2001-09-05 21:40:40 +02:00
|
|
|
|
!get_item(u, I_AMULET_OF_TRUE_SEEING)) continue;
|
2004-10-19 21:59:37 +02:00
|
|
|
|
if (u->faction==reisender->faction) contact = true;
|
|
|
|
|
else if (ucontact(u, reisender)) contact = true;
|
|
|
|
|
else if (alliedunit(u, reisender->faction, HELP_GUARD)) contact = true;
|
|
|
|
|
else if (sk>=perception) {
|
2001-09-05 21:40:40 +02:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
static boolean
|
|
|
|
|
transport(unit * ut, unit * u)
|
|
|
|
|
{
|
|
|
|
|
order * ord;
|
|
|
|
|
|
|
|
|
|
if (LongHunger(u)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (ord = ut->orders; ord; ord = ord->next) {
|
|
|
|
|
if (get_keyword(ord) == K_TRANSPORT) {
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
if (getunit(ut->region, ut->faction) == u) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2004-12-19 17:39:51 +01:00
|
|
|
|
init_transportation(void)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region *r;
|
|
|
|
|
|
|
|
|
|
for (r=regions; r; r=r->next) {
|
2004-12-19 17:39:51 +01:00
|
|
|
|
unit *u;
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* This is just a simple check for non-corresponding K_TRANSPORT/
|
|
|
|
|
* K_DRIVE. This is time consuming for an error check, but there
|
|
|
|
|
* doesn't seem to be an easy way to speed this up. */
|
2004-12-19 17:39:51 +01:00
|
|
|
|
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-12-19 17:39:51 +01:00
|
|
|
|
unit * ut;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
|
|
|
|
|
init_tokens(u->thisorder);
|
|
|
|
|
skip_token();
|
|
|
|
|
ut = getunit(r, u->faction);
|
|
|
|
|
if (ut==NULL) {
|
|
|
|
|
cmistake(u, u->thisorder, 63, MSG_MOVE);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (!transport(ut, u)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
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
|
2004-12-19 17:39:51 +01:00
|
|
|
|
* adds them to an internal counter which is used by travel () to
|
|
|
|
|
* calculate effective weight and movement. */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
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) {
|
2004-12-19 17:39:51 +01:00
|
|
|
|
unit * ut;
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-12-19 17:39:51 +01:00
|
|
|
|
static region_list *
|
|
|
|
|
cap_route(region * r, region_list * route, region_list * route_end, int speed)
|
|
|
|
|
{
|
|
|
|
|
region * current = r;
|
|
|
|
|
int moves = speed;
|
|
|
|
|
region_list * iroute = route;
|
|
|
|
|
while (iroute!=route_end) {
|
|
|
|
|
region * next = iroute->data;
|
|
|
|
|
direction_t reldir = reldirection(current, next);
|
|
|
|
|
|
|
|
|
|
/* adjust the range of the unit */
|
|
|
|
|
if (roadto(current, reldir)) moves -= BP_ROAD;
|
|
|
|
|
else moves -= BP_NORMAL;
|
|
|
|
|
if (moves<0) break;
|
2004-12-22 23:02:31 +01:00
|
|
|
|
iroute = iroute->next;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
current = next;
|
|
|
|
|
}
|
|
|
|
|
return iroute;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
make_route(unit * u, order * ord, region_list ** routep)
|
|
|
|
|
{
|
|
|
|
|
region_list **iroute = routep;
|
|
|
|
|
region * current = u->region;
|
|
|
|
|
region * next = NULL;
|
|
|
|
|
const char * token = getstrtoken();
|
|
|
|
|
int error = movewhere(u, token, current, &next);
|
|
|
|
|
|
|
|
|
|
if (error!=E_MOVE_OK) {
|
|
|
|
|
message * msg = movement_error(u, token, ord, error);
|
|
|
|
|
if (msg!=NULL) {
|
|
|
|
|
add_message(&u->faction->msgs, msg);
|
|
|
|
|
msg_release(msg);
|
|
|
|
|
}
|
|
|
|
|
next = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (next!=NULL) {
|
|
|
|
|
border * b = get_borders(current, next);
|
|
|
|
|
direction_t reldir;
|
|
|
|
|
|
|
|
|
|
if (current==next) {
|
|
|
|
|
/* PAUSE */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
while (b!=NULL) {
|
|
|
|
|
if (b->type->move) {
|
2004-12-19 18:30:32 +01:00
|
|
|
|
region * rto = b->type->move(b, u, current, next, true);
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (rto!=next) {
|
|
|
|
|
/* the target region was changed (bt_wisps, for example). check the
|
|
|
|
|
* new target region for borders */
|
|
|
|
|
next = rto;
|
|
|
|
|
b = get_borders(current, next);
|
|
|
|
|
continue;
|
2004-07-09 15:41:14 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reldir = reldirection(current, next);
|
|
|
|
|
|
|
|
|
|
add_regionlist(iroute, next);
|
|
|
|
|
iroute = &(*iroute)->next;
|
|
|
|
|
|
|
|
|
|
current = next;
|
|
|
|
|
token = getstrtoken();
|
2005-01-14 19:05:54 +01:00
|
|
|
|
error = movewhere(u, token, current, &next);
|
|
|
|
|
if (error) {
|
|
|
|
|
message * msg = movement_error(u, token, ord, error);
|
|
|
|
|
if (msg!=NULL) {
|
|
|
|
|
add_message(&u->faction->msgs, msg);
|
|
|
|
|
msg_release(msg);
|
2004-12-19 17:39:51 +01:00
|
|
|
|
}
|
|
|
|
|
next = NULL;
|
2004-07-09 15:41:14 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
/** calculate the speed of a unit
|
|
|
|
|
*
|
|
|
|
|
* 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
|
2004-07-09 15:41:14 +02:00
|
|
|
|
*/
|
2004-12-19 17:39:51 +01:00
|
|
|
|
static int
|
|
|
|
|
movement_speed(unit * u)
|
|
|
|
|
{
|
|
|
|
|
int mp;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
static const curse_type * speed_ct;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
static boolean init = false;
|
|
|
|
|
double dk = u->race->speed;
|
|
|
|
|
|
|
|
|
|
/* dragons have a fixed speed, and no other effects work on them: */
|
|
|
|
|
switch (old_race(u->race)) {
|
|
|
|
|
case RC_DRAGON:
|
|
|
|
|
case RC_WYRM:
|
|
|
|
|
case RC_FIREDRAGON:
|
|
|
|
|
case RC_BIRTHDAYDRAGON:
|
|
|
|
|
case RC_PSEUDODRAGON:
|
|
|
|
|
return BP_DRAGON;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
speed_ct = ct_find("speed");
|
|
|
|
|
}
|
|
|
|
|
if (speed_ct) {
|
|
|
|
|
curse *c = get_curse(u->attribs, speed_ct);
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (c!=NULL) {
|
2004-04-12 18:21:23 +02:00
|
|
|
|
int men = get_cursedmen(u, c);
|
|
|
|
|
dk *= 1.0 + (double)men/(double)u->number;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
switch (canride(u)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
case 1: /* Pferd */
|
|
|
|
|
mp = BP_RIDING;
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
case 2: /* Einhorn */
|
|
|
|
|
mp = BP_UNICORN;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
mp = BP_WALKING;
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* unicorn in inventory */
|
|
|
|
|
if (u->number <= get_item(u, I_FEENSTIEFEL)) {
|
|
|
|
|
mp *= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell.
|
|
|
|
|
* Nicht kumulativ mit anderen Beschleunigungen! */
|
|
|
|
|
if (mp*dk <= BP_WALKING*u->race->speed && getplane(u->region) == get_astralplane() && is_mage(u)) {
|
|
|
|
|
sc_mage * mage = get_mage(u);
|
|
|
|
|
if (mage->magietyp == M_ASTRAL || mage->magietyp == M_TRAUM) {
|
|
|
|
|
mp *= 2;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
return (int)(dk*mp);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
enum {
|
|
|
|
|
TRAVEL_NORMAL,
|
|
|
|
|
TRAVEL_FOLLOWING,
|
|
|
|
|
TRAVEL_TRANSPORTED,
|
|
|
|
|
TRAVEL_RUNNING
|
|
|
|
|
};
|
- 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-12-19 17:39:51 +01:00
|
|
|
|
static region_list *
|
|
|
|
|
travel_route(unit * u, region_list * route_begin, region_list * route_end, order * ord, int mode)
|
|
|
|
|
{
|
|
|
|
|
region * r = u->region;
|
|
|
|
|
region * current = u->region;
|
|
|
|
|
region_list * iroute = route_begin;
|
|
|
|
|
int steps = 0;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
while (iroute && iroute!=route_end) {
|
|
|
|
|
region * next = iroute->data;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
direction_t reldir = reldirection(current, next);
|
2004-12-19 18:30:32 +01:00
|
|
|
|
border * b = get_borders(current, next);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
/* check if we are caught by guarding units */
|
|
|
|
|
if (iroute!=route_begin && mode!=TRAVEL_RUNNING && mode!=TRAVEL_TRANSPORTED) {
|
|
|
|
|
unit * wache = bewegung_blockiert_von(u, current);
|
|
|
|
|
if (wache!=NULL) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard",
|
|
|
|
|
"unit region guard", u, current, wache));
|
|
|
|
|
break;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
/* check movement from/to oceans.
|
|
|
|
|
* aquarian special, flying units, horses, the works */
|
|
|
|
|
if ((u->race->flags & RCF_FLY) == 0) {
|
|
|
|
|
if (rterrain(current)==T_OCEAN && rterrain(next) != T_OCEAN) {
|
|
|
|
|
int moving = u->race->flags & (RCF_SWIM|RCF_WALK);
|
|
|
|
|
/* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */
|
|
|
|
|
if (moving != (RCF_SWIM|RCF_WALK) && old_race(u->race) != RC_AQUARIAN) {
|
|
|
|
|
/* can't swim+walk and isn't an aquarian */
|
|
|
|
|
if (ord!=NULL) cmistake(u, ord, 44, MSG_MOVE);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (rterrain(current)==T_OCEAN || rterrain(next) == T_OCEAN) {
|
|
|
|
|
/* trying to enter or exit ocean with horses, are we? */
|
|
|
|
|
if (get_item(u, I_HORSE) > 0) {
|
|
|
|
|
/* tries to do it with horses */
|
|
|
|
|
if (ord!=NULL) cmistake(u, ord, 67, MSG_MOVE);
|
|
|
|
|
break;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
/* Ozeanfelder k<>nnen nur von Einheiten mit Schwimmen und ohne
|
|
|
|
|
* Pferde betreten werden. */
|
2004-04-12 18:21:23 +02:00
|
|
|
|
if (rterrain(next) == T_OCEAN && !canswim(u)) {
|
2004-12-19 17:39:51 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("detectocean",
|
|
|
|
|
"unit region", u, next));
|
2004-04-12 18:21:23 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
/* movement blocked by a wall */
|
|
|
|
|
if (reldir>=0 && move_blocked(u, current, next)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("leavefail",
|
|
|
|
|
"unit region", u, next));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* region ownership only: region owned by enemies */
|
|
|
|
|
if (!entrance_allowed(u, next)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("regionowned",
|
|
|
|
|
"unit region target", u, current, next));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* illusionary units disappear in antimagic zones */
|
|
|
|
|
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);
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("illusionantimagic", "unit", u));
|
|
|
|
|
set_number(u, 0);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
/* terrain is marked as forbidden (curse, etc) */
|
|
|
|
|
if (terrain[rterrain(next)].flags & FORBIDDEN_LAND) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("detectforbidden",
|
|
|
|
|
"unit region", u, next));
|
2004-04-12 18:21:23 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
/* unit is an insect and cannot move into a glacier */
|
|
|
|
|
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
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
|
2004-12-19 18:30:32 +01:00
|
|
|
|
/* effect of borders */
|
|
|
|
|
while (b!=NULL) {
|
|
|
|
|
if (b->type->move) {
|
|
|
|
|
region * rto = b->type->move(b, u, current, next, false);
|
|
|
|
|
assert(rto==NULL); /* should return NULL when not routing */
|
|
|
|
|
}
|
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
current = next;
|
|
|
|
|
iroute = iroute->next;
|
|
|
|
|
++steps;
|
2004-12-19 18:30:32 +01:00
|
|
|
|
if (u->number==0) break;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (iroute!=route_begin) {
|
|
|
|
|
/* the unit has moved at least one region */
|
2004-12-19 23:18:39 +01:00
|
|
|
|
int walkmode;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
region_list *rlist = route_begin;
|
|
|
|
|
char * p = buf;
|
|
|
|
|
region * next = r;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
setguard(u, GUARD_NONE);
|
2004-12-19 17:39:51 +01:00
|
|
|
|
cycle_route(u, steps);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
2004-12-19 23:18:39 +01:00
|
|
|
|
if (mode==TRAVEL_RUNNING) {
|
|
|
|
|
walkmode = 0;
|
|
|
|
|
} if (canride(u)) {
|
|
|
|
|
walkmode = 1;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
produceexp(u, SK_RIDING, u->number);
|
2004-12-19 17:39:51 +01:00
|
|
|
|
} else {
|
2004-12-19 23:18:39 +01:00
|
|
|
|
walkmode = 2;
|
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
|
|
|
|
|
/* Berichte <20>ber Durchreiseregionen */
|
|
|
|
|
|
|
|
|
|
*p = 0;
|
|
|
|
|
while (rlist!=iroute) {
|
|
|
|
|
if (next!=u->region && next!=current) {
|
|
|
|
|
MSG(("travelthru_trail", "region", next),
|
|
|
|
|
p, sizeof(buf) - (p-buf), u->faction->locale, u->faction);
|
|
|
|
|
if (rlist->data!=current) {
|
|
|
|
|
if (rlist->next->data==current) scat(" und ");
|
|
|
|
|
else scat(", ");
|
2004-09-09 01:00:48 +02:00
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
p += strlen(p);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
next = rlist->data;
|
|
|
|
|
rlist = rlist->next;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
2004-12-19 23:18:39 +01:00
|
|
|
|
if (mode!=TRAVEL_TRANSPORTED) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("travel",
|
|
|
|
|
"unit mode start end regions", u, walkmode, r, current, strdup(buf)));
|
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
mark_travelthru(u, r, route_begin, iroute);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
move_unit(u, current, NULL);
|
2004-12-19 17:39:51 +01:00
|
|
|
|
|
|
|
|
|
/* make orders for the followers */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
2004-04-12 18:21:23 +02:00
|
|
|
|
fset(u, UFL_LONGACTION);
|
|
|
|
|
setguard(u, GUARD_NONE);
|
2004-12-19 17:39:51 +01:00
|
|
|
|
assert(u->region==current);
|
|
|
|
|
return iroute;
|
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,
|
2004-12-23 00:05:26 +01:00
|
|
|
|
LOC(u->faction->locale, u->ship->type->name[1]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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-12-19 17:39:51 +01:00
|
|
|
|
static void
|
|
|
|
|
sail(unit * u, order * ord, boolean move_on_land, region_list **routep)
|
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;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
region_list **iroute = routep;
|
2004-05-31 18:21:03 +02:00
|
|
|
|
ship * sh = u->ship;
|
|
|
|
|
faction * f = u->faction;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
region * next_point = NULL;
|
|
|
|
|
int error;
|
|
|
|
|
const char * token = getstrtoken();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (routep) *routep = NULL;
|
|
|
|
|
|
|
|
|
|
error = movewhere(u, token, starting_point, &next_point);
|
|
|
|
|
if (error) {
|
|
|
|
|
message * msg = movement_error(u, token, ord, error);
|
|
|
|
|
if (msg!=NULL) {
|
|
|
|
|
add_message(&u->faction->msgs, msg);
|
|
|
|
|
msg_release(msg);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ship_ready(starting_point, u)) return;
|
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-12-19 17:39:51 +01:00
|
|
|
|
/* die n<>chste Region, in die man segelt, wird durch movewhere () aus der
|
2004-04-12 18:21:23 +02:00
|
|
|
|
* 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
|
|
|
|
|
2005-01-14 19:05:54 +01:00
|
|
|
|
while (next_point && current_point!=next_point && step < k) {
|
2004-12-19 17:39:51 +01:00
|
|
|
|
const char * token;
|
|
|
|
|
int error;
|
2004-05-31 18:21:03 +02:00
|
|
|
|
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-12-19 17:39:51 +01:00
|
|
|
|
cmistake(u, ord, 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-12-19 17:39:51 +01:00
|
|
|
|
cmistake(u, ord, 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);
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (iroute) {
|
|
|
|
|
add_regionlist(iroute, next_point);
|
|
|
|
|
iroute = &(*iroute)->next;
|
|
|
|
|
}
|
2004-05-31 18:21:03 +02:00
|
|
|
|
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;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
token = getstrtoken();
|
|
|
|
|
error = movewhere(u, token, current_point, &next_point);
|
2005-01-14 19:05:54 +01:00
|
|
|
|
if (error || next_point==NULL) {
|
2004-12-19 17:39:51 +01:00
|
|
|
|
message * msg = movement_error(u, token, ord, error);
|
|
|
|
|
if (msg!=NULL) {
|
|
|
|
|
add_message(&u->faction->msgs, msg);
|
|
|
|
|
msg_release(msg);
|
|
|
|
|
}
|
2005-01-14 19:05:54 +01:00
|
|
|
|
next_point = current_point;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2004-05-31 18:21:03 +02:00
|
|
|
|
}
|
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);
|
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
sh = move_ship(sh, starting_point, current_point, *routep);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
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-12-19 17:39:51 +01:00
|
|
|
|
|
|
|
|
|
/** fleeing units use this function
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
run_to(unit * u, region * to)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
region_list * route = NULL;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
add_regionlist(&route, to);
|
|
|
|
|
travel_route(u, route, NULL, NULL, TRAVEL_RUNNING);
|
|
|
|
|
/* weder transport noch follow */
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-12-19 17:39:51 +01:00
|
|
|
|
static region_list *
|
|
|
|
|
travel_i(unit * u, region_list * route_begin, region_list * route_end, order * ord, int mode, follower ** followers)
|
|
|
|
|
{
|
|
|
|
|
region * r = u->region;
|
|
|
|
|
|
|
|
|
|
switch (canwalk(u)) {
|
|
|
|
|
case E_CANWALK_TOOHEAVY:
|
|
|
|
|
cmistake(u, ord, 57, MSG_MOVE);
|
|
|
|
|
return route_begin;
|
|
|
|
|
case E_CANWALK_TOOMANYHORSES:
|
|
|
|
|
cmistake(u, ord, 56, MSG_MOVE);
|
|
|
|
|
return route_begin;
|
|
|
|
|
case E_CANWALK_TOOMANYCARTS:
|
|
|
|
|
cmistake(u, ord, 42, MSG_MOVE);
|
|
|
|
|
return route_begin;
|
|
|
|
|
}
|
|
|
|
|
route_end = cap_route(r, route_begin, route_end, movement_speed(u));
|
|
|
|
|
|
|
|
|
|
route_end = travel_route(u, route_begin, route_end, ord, mode);
|
|
|
|
|
get_followers(u, r, route_end, followers);
|
|
|
|
|
|
|
|
|
|
/* transportation */
|
|
|
|
|
for (ord = u->orders; ord; ord = ord->next) {
|
|
|
|
|
unit * ut;
|
|
|
|
|
|
|
|
|
|
if (get_keyword(ord) != K_TRANSPORT) continue;
|
|
|
|
|
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
ut = getunit(r, u->faction);
|
|
|
|
|
if (ut!=NULL) {
|
|
|
|
|
boolean found = false;
|
|
|
|
|
if (get_keyword(ut->thisorder) == K_DRIVE) {
|
|
|
|
|
if (!fval(ut, UFL_LONGACTION) && !LongHunger(ut)) {
|
|
|
|
|
init_tokens(ut->thisorder);
|
|
|
|
|
skip_token();
|
|
|
|
|
if (getunit(u->region, ut->faction) == u) {
|
|
|
|
|
region_list * route_to = travel_route(ut, route_begin, route_end, ord, TRAVEL_TRANSPORTED);
|
|
|
|
|
|
|
|
|
|
if (route_to!=route_begin) {
|
|
|
|
|
get_followers(ut, r, route_to, followers);
|
|
|
|
|
}
|
|
|
|
|
ADDMSG(&ut->faction->msgs, msg_message("transport",
|
|
|
|
|
"unit target start end", u, ut, r, ut->region));
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found) {
|
|
|
|
|
if (cansee(u->faction, u->region, ut, 0)) {
|
|
|
|
|
cmistake(u, ord, 90, MSG_MOVE);
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, ord, 63, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, ord, 99, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, ord, 63, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return route_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** traveling without ships
|
|
|
|
|
* walking, flying or riding units use this function
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
travel(unit * u, region_list ** routep)
|
|
|
|
|
{
|
|
|
|
|
region * r = u->region;
|
|
|
|
|
region_list * route_end;
|
|
|
|
|
region_list * route_begin = NULL;
|
|
|
|
|
follower * followers = NULL;
|
|
|
|
|
|
|
|
|
|
if (routep) *routep = NULL;
|
|
|
|
|
|
|
|
|
|
/* a few pre-checks that need not be done for each step: */
|
|
|
|
|
if (rterrain(r)!=T_OCEAN) {
|
|
|
|
|
/* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */
|
2005-01-01 18:39:22 +01:00
|
|
|
|
if ((u->ship || leftship(u)) && is_guarded(r, u, GUARD_LANDING)) {
|
2004-12-19 17:39:51 +01:00
|
|
|
|
cmistake(u, u->thisorder, 70, MSG_MOVE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u->ship && u->race->flags & RCF_SWIM) {
|
|
|
|
|
cmistake(u, u->thisorder, 143, MSG_MOVE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (u->ship && fval(u->ship, SF_MOVED)) {
|
|
|
|
|
/* die Einheit ist auf einem Schiff, das sich bereits bewegt hat */
|
|
|
|
|
cmistake(u, u->thisorder, 13, MSG_MOVE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
make_route(u, u->thisorder, routep);
|
|
|
|
|
route_begin = *routep;
|
|
|
|
|
|
|
|
|
|
/* und ab die post: */
|
|
|
|
|
route_end = travel_i(u, route_begin, NULL, u->thisorder, TRAVEL_NORMAL, &followers);
|
|
|
|
|
|
|
|
|
|
/* followers */
|
|
|
|
|
while (followers!=NULL) {
|
|
|
|
|
follower * fnext = followers->next;
|
|
|
|
|
unit * uf = followers->uf;
|
|
|
|
|
unit * ut = followers->ut;
|
|
|
|
|
region_list * route_end = followers->route_end;
|
|
|
|
|
|
|
|
|
|
free(followers);
|
|
|
|
|
followers = fnext;
|
|
|
|
|
|
|
|
|
|
if (uf->region==r) {
|
|
|
|
|
order * follow_order;
|
|
|
|
|
char str[32];
|
|
|
|
|
|
|
|
|
|
/* construct an order */
|
|
|
|
|
sprintf(str, "%s %s %s",
|
|
|
|
|
locale_string(uf->faction->locale, keywords[K_FOLLOW]),
|
|
|
|
|
locale_string(uf->faction->locale, parameters[P_UNIT]),
|
|
|
|
|
itoa36(ut->no));
|
|
|
|
|
follow_order = parse_order(str, uf->faction->locale);
|
|
|
|
|
|
|
|
|
|
route_end = travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, &followers);
|
|
|
|
|
caught_target(uf->region, uf);
|
|
|
|
|
free_order(follow_order);
|
|
|
|
|
}
|
2004-02-29 16:29:27 +01:00
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
move(unit * u, boolean move_on_land)
|
|
|
|
|
{
|
|
|
|
|
region_list * route = NULL;
|
|
|
|
|
|
|
|
|
|
if (u->ship && fval(u, UFL_OWNER)) {
|
|
|
|
|
sail(u, u->thisorder, move_on_land, &route);
|
2004-04-12 18:21:23 +02:00
|
|
|
|
} else {
|
2004-12-19 17:39:51 +01:00
|
|
|
|
travel(u, &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 (route!=NULL) free_regionlist(route);
|
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-12-19 17:39:51 +01:00
|
|
|
|
static void
|
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-12-19 17:39:51 +01:00
|
|
|
|
return;
|
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-12-19 17:39:51 +01:00
|
|
|
|
return;
|
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-12-19 17:39:51 +01:00
|
|
|
|
return;
|
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-12-19 17:39:51 +01:00
|
|
|
|
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-10-19 20:16:35 +02:00
|
|
|
|
if (fval(u, UFL_LONGACTION)) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (u->ship==NULL) {
|
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-12-19 17:39:51 +01:00
|
|
|
|
move(u, false);
|
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);
|
2004-10-19 21:59:37 +02:00
|
|
|
|
ADDMSG(&cap->faction->msgs, msg_message("shipnoconf", "ship", sh));
|
|
|
|
|
continue;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2004-10-19 21:59:37 +02:00
|
|
|
|
ADDMSG(&cap->faction->msgs, msg_message("shipnoconf", "ship", sh));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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 */
|
2004-12-19 17:39:51 +01:00
|
|
|
|
init_transportation();
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
/* 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;
|
2004-12-23 01:07:32 +01:00
|
|
|
|
boolean repeat = false;
|
2004-02-22 15:42:24 +01:00
|
|
|
|
|
|
|
|
|
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-12-19 17:39:51 +01:00
|
|
|
|
move(u, false);
|
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-12-19 17:39:51 +01:00
|
|
|
|
move(u, false);
|
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;
|
2004-12-23 01:07:32 +01:00
|
|
|
|
} else {
|
|
|
|
|
if (*up && (*up)->region!=r) {
|
|
|
|
|
/* moved the upcoming unit along with u (units on ships or followers,
|
|
|
|
|
* for example). must start from the beginning again immediately */
|
2004-12-23 01:31:03 +01:00
|
|
|
|
up = &r->units;
|
|
|
|
|
repeat = false;
|
|
|
|
|
} else {
|
|
|
|
|
repeat = true;
|
2004-12-23 01:07:32 +01:00
|
|
|
|
}
|
2004-02-22 15:42:24 +01:00
|
|
|
|
}
|
|
|
|
|
/* else *up is already the next unit */
|
|
|
|
|
}
|
2004-12-23 01:07:32 +01:00
|
|
|
|
if (repeat) continue;
|
2004-12-19 17:39:51 +01:00
|
|
|
|
if (ships==0) {
|
|
|
|
|
/* Abtreiben von besch<63>digten, unterbemannten, <20>berladenen Schiffen */
|
|
|
|
|
drifting_ships(r);
|
2004-07-14 09:12:36 +02:00
|
|
|
|
}
|
2004-12-19 17:39:51 +01:00
|
|
|
|
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
|
|
|
|
}
|