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 "build.h"
|
|
|
|
|
|
|
|
|
|
/* kernel includes */
|
|
|
|
|
#include "alchemy.h"
|
|
|
|
|
#include "border.h"
|
|
|
|
|
#include "building.h"
|
|
|
|
|
#include "curse.h"
|
|
|
|
|
#include "faction.h"
|
|
|
|
|
#include "group.h"
|
|
|
|
|
#include "item.h"
|
|
|
|
|
#include "magic.h"
|
|
|
|
|
#include "message.h"
|
|
|
|
|
#include "movement.h"
|
|
|
|
|
#include "pool.h"
|
|
|
|
|
#include "race.h"
|
|
|
|
|
#include "region.h"
|
|
|
|
|
#include "ship.h"
|
|
|
|
|
#include "skill.h"
|
|
|
|
|
#include "unit.h"
|
|
|
|
|
|
|
|
|
|
/* from libutil */
|
|
|
|
|
#include <attrib.h>
|
|
|
|
|
#include <base36.h>
|
|
|
|
|
#include <event.h>
|
|
|
|
|
#include <goodies.h>
|
|
|
|
|
#include <resolve.h>
|
2002-04-01 16:22:00 +02:00
|
|
|
|
#include <xml.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* from libc */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
/* attributes inclues */
|
|
|
|
|
#include <attributes/matmod.h>
|
|
|
|
|
|
2002-04-27 19:58:34 +02:00
|
|
|
|
#include <items/catapultammo.h>
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#define NEW_TAVERN
|
|
|
|
|
#define STONERECYCLE 50
|
|
|
|
|
/* Name, MaxGroesse, MinBauTalent, Kapazitaet, {Eisen, Holz, Stein, BauSilber,
|
|
|
|
|
* Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */
|
|
|
|
|
|
|
|
|
|
|
2004-05-04 21:24:03 +02:00
|
|
|
|
static boolean
|
2004-05-04 21:34:35 +02:00
|
|
|
|
CheckOverload(void)
|
2004-05-04 21:24:03 +02:00
|
|
|
|
{
|
|
|
|
|
static int value = -1;
|
|
|
|
|
if (value<0) {
|
|
|
|
|
const char * str = get_param(global.parameters, "rules.check_overload");
|
|
|
|
|
value = str?atoi(str):0;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
static int
|
2001-04-26 19:41:06 +02:00
|
|
|
|
slipthru(const region * r, const unit * u, const building * b)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
unit *u2;
|
|
|
|
|
int n, o;
|
|
|
|
|
|
|
|
|
|
/* b ist die burg, in die man hinein oder aus der man heraus will. */
|
|
|
|
|
|
|
|
|
|
if (!b) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (b->besieged < b->size * SIEGEFACTOR) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <=
|
|
|
|
|
* OBSERVATION +2 der belagerer u2 ist */
|
|
|
|
|
|
|
|
|
|
n = eff_skill(u, SK_STEALTH, r);
|
|
|
|
|
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (usiege(u2) == b) {
|
2002-11-27 20:35:36 +01:00
|
|
|
|
|
|
|
|
|
#if NEWATSROI == 0
|
2002-05-05 18:59:25 +02:00
|
|
|
|
if (invisible(u) >= u->number &&
|
2001-01-25 10:37:55 +01:00
|
|
|
|
!get_item(u2, I_AMULET_OF_TRUE_SEEING))
|
|
|
|
|
continue;
|
2002-11-27 20:35:36 +01:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
o = eff_skill(u2, SK_OBSERVATION, r);
|
|
|
|
|
|
|
|
|
|
if (o + 2 >= n)
|
|
|
|
|
return 0; /* entdeckt! */
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
2001-04-26 19:41:06 +02:00
|
|
|
|
can_contact(const region * r, const unit * u, const unit * u2)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* hier geht es nur um die belagerung von burgen */
|
|
|
|
|
|
|
|
|
|
if (u->building == u2->building)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/* unit u is trying to contact u2 - unasked for contact. wenn u oder u2
|
|
|
|
|
* nicht in einer burg ist, oder die burg nicht belagert ist, ist
|
|
|
|
|
* slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */
|
|
|
|
|
|
|
|
|
|
if (slipthru(u->region, u, u->building)
|
|
|
|
|
&& slipthru(u->region, u2, u2->building))
|
|
|
|
|
return true;
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
if (alliedunit(u, u2->faction, HELP_GIVE))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2003-07-29 11:48:03 +02:00
|
|
|
|
set_contact(const region * r, unit * u, boolean tries)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 -
|
|
|
|
|
* ein richtiger toggle ist (noch?) nicht noetig. die region als
|
|
|
|
|
* parameter ist nur deswegen wichtig, weil er an getunit ()
|
|
|
|
|
* weitergegeben wird. dies wird fuer das auffinden von tempunits in
|
|
|
|
|
* getnewunit () verwendet! */
|
|
|
|
|
|
2001-04-26 19:41:06 +02:00
|
|
|
|
unit *u2 = getunitg(r, u->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (u2) {
|
|
|
|
|
|
|
|
|
|
if (!can_contact(r, u, u2)) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (tries) cmistake(u, findorder(u, u->thisorder), 23, MSG_EVENT);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
usetcontact(u, u2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
struct building *
|
|
|
|
|
getbuilding(const struct region * r)
|
|
|
|
|
{
|
2001-02-04 09:47:39 +01:00
|
|
|
|
building * b = findbuilding(getid());
|
2001-02-04 09:52:24 +01:00
|
|
|
|
if (b==NULL || r!=b->region) return NULL;
|
2001-02-04 09:47:39 +01:00
|
|
|
|
return b;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ship *
|
|
|
|
|
getship(const struct region * r)
|
|
|
|
|
{
|
|
|
|
|
ship *sh, *sx = findship(getshipid());
|
|
|
|
|
for (sh = r->ships; sh; sh = sh->next) {
|
|
|
|
|
if (sh == sx) return sh;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
siege(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
unit *u2;
|
|
|
|
|
building *b;
|
|
|
|
|
int d;
|
|
|
|
|
int bewaffnete, katapultiere = 0;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
static boolean init = false;
|
2002-05-11 20:12:25 +02:00
|
|
|
|
static const curse_type * magicwalls_ct;
|
|
|
|
|
if (!init) { init = true; magicwalls_ct = ct_find("magicwalls"); }
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* gibt es ueberhaupt Burgen? */
|
|
|
|
|
|
|
|
|
|
b = getbuilding(r);
|
|
|
|
|
|
|
|
|
|
if (!b) {
|
|
|
|
|
cmistake(u, u->thisorder, 31, MSG_BATTLE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!playerrace(u->race)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* keine Drachen, Illusionen, Untote etc */
|
|
|
|
|
cmistake(u, u->thisorder, 166, MSG_BATTLE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* schaden durch katapulte */
|
|
|
|
|
|
2002-04-27 19:57:38 +02:00
|
|
|
|
d = min(u->number,
|
|
|
|
|
min(new_get_pooled(u, &rt_catapultammo, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK), get_item(u, I_CATAPULT)));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (eff_skill(u, SK_CATAPULT, r) >= 1) {
|
|
|
|
|
katapultiere = d;
|
|
|
|
|
d *= eff_skill(u, SK_CATAPULT, r);
|
|
|
|
|
} else {
|
|
|
|
|
d = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((bewaffnete = armedmen(u)) == 0 && d == 0) {
|
|
|
|
|
/* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 80, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(getguard(u) & GUARD_TRAVELTHRU)) {
|
|
|
|
|
/* abbruch, wenn die einheit nicht vorher die region bewacht - als
|
|
|
|
|
* warnung fuer alle anderen! */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 81, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* einheit und burg markieren - spart zeit beim behandeln der einheiten
|
|
|
|
|
* in der burg, falls die burg auch markiert ist und nicht alle
|
|
|
|
|
* einheiten wieder abgesucht werden muessen! */
|
|
|
|
|
|
|
|
|
|
usetsiege(u, b);
|
|
|
|
|
b->besieged += max(bewaffnete, katapultiere);
|
|
|
|
|
|
|
|
|
|
/* definitiver schaden eingeschraenkt */
|
|
|
|
|
|
|
|
|
|
d = min(d, b->size - 1);
|
|
|
|
|
|
|
|
|
|
/* meldung, schaden anrichten */
|
2002-05-11 20:12:25 +02:00
|
|
|
|
if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
b->size -= d;
|
2002-04-27 19:58:34 +02:00
|
|
|
|
new_use_pooled(u, &rt_catapultammo, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, d);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
d = 100 * d / b->size;
|
|
|
|
|
} else d = 0;
|
|
|
|
|
|
|
|
|
|
/* meldung fuer belagerer */
|
|
|
|
|
add_message(&u->faction->msgs,
|
|
|
|
|
new_message(u->faction, "siege%u:unit%b:building%i:destruction",
|
|
|
|
|
u, b, d));
|
|
|
|
|
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FL_DH);
|
|
|
|
|
fset(u->faction, FL_DH);
|
|
|
|
|
|
|
|
|
|
/* Meldung fuer Burginsassen */
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next) {
|
|
|
|
|
if (u2->building == b && !fval(u2->faction, FL_DH)) {
|
|
|
|
|
fset(u2->faction, FL_DH);
|
|
|
|
|
add_message(&u2->faction->msgs,
|
|
|
|
|
new_message(u2->faction, "siege%u:unit%b:building%i:destruction",
|
|
|
|
|
u, b, d));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_siege(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
if (rterrain(r) != T_OCEAN) {
|
|
|
|
|
unit *u;
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (igetkeyword(u->thisorder, u->faction->locale) == K_BESIEGE)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
siege(r, u);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-04-01 08:58:45 +02:00
|
|
|
|
destroy_road(unit *u, int n, const char *cmd)
|
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
direction_t d = getdirection(u->faction->locale);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
unit *u2;
|
|
|
|
|
region *r = u->region;
|
|
|
|
|
|
|
|
|
|
for (u2=r->units;u2;u2=u2->next) {
|
|
|
|
|
if (u2->faction!=u->faction && getguard(u2)&GUARD_TAX &&
|
2002-09-02 22:36:12 +02:00
|
|
|
|
!alliedunit(u, u2->faction, HELP_GUARD)) {
|
2001-04-01 08:58:45 +02:00
|
|
|
|
cmistake(u, cmd, 70, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (d==NODIRECTION) {
|
|
|
|
|
cmistake(u, cmd, 71, MSG_PRODUCE);
|
|
|
|
|
} else {
|
|
|
|
|
#if 0
|
|
|
|
|
int salvage, divy = 2;
|
|
|
|
|
#endif
|
2002-02-16 11:37:18 +01:00
|
|
|
|
int willdo = min(n, eff_skill(u, SK_ROAD_BUILDING, r)*u->number);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
int road = rroad(r, d);
|
|
|
|
|
region * r2 = rconnect(r,d);
|
|
|
|
|
willdo = min(willdo, road);
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (willdo==0) {
|
|
|
|
|
/* TODO: error message */
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
#if 0
|
|
|
|
|
salvage = willdo / divy;
|
|
|
|
|
change_item(u, I_STONE, salvage);
|
|
|
|
|
#endif
|
|
|
|
|
rsetroad(r, d, road - willdo);
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (road!=0 && road <= willdo) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "destroy_road%u:unit%r:from%r:to", u, r, r2));
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
|
|
|
|
destroy(region * r, unit * u, const char * cmd)
|
|
|
|
|
{
|
2004-05-22 01:02:19 +02:00
|
|
|
|
ship *sh;
|
|
|
|
|
unit *u2;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
#if 0
|
2004-05-22 01:02:19 +02:00
|
|
|
|
const construction * con = NULL;
|
|
|
|
|
int size = 0;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
#endif
|
2004-05-22 01:02:19 +02:00
|
|
|
|
const char *s;
|
|
|
|
|
int n = INT_MAX;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if (u->number < 1)
|
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
s = getstrtoken();
|
2001-04-01 08:58:45 +02:00
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale)==P_ROAD) {
|
|
|
|
|
destroy_road(u, INT_MAX, cmd);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if (!fval(u, UFL_OWNER)) {
|
|
|
|
|
cmistake(u, cmd, 138, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if(s && *s) {
|
|
|
|
|
n = atoi(s);
|
|
|
|
|
if(n <= 0) {
|
|
|
|
|
cmistake(u, cmd, 288, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if(getparam(u->faction->locale) == P_ROAD) {
|
|
|
|
|
destroy_road(u, n, cmd);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if (u->building) {
|
|
|
|
|
building *b = u->building;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
#if 0
|
2004-05-22 01:02:19 +02:00
|
|
|
|
con = b->type->construction;
|
|
|
|
|
size = b->size;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if(n >= b->size) {
|
|
|
|
|
/* destroy completly */
|
|
|
|
|
/* all units leave the building */
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (u2->building == b) {
|
|
|
|
|
u2->building = 0;
|
|
|
|
|
freset(u2, UFL_OWNER);
|
|
|
|
|
}
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "destroy%b:building%u:unit", b, u));
|
|
|
|
|
destroy_building(b);
|
|
|
|
|
} else {
|
|
|
|
|
/* partial destroy */
|
|
|
|
|
b->size -= n;
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "destroy_partial%b:building%u:unit", b, u));
|
|
|
|
|
}
|
|
|
|
|
} else if (u->ship) {
|
|
|
|
|
sh = u->ship;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
#if 0
|
2004-05-22 01:02:19 +02:00
|
|
|
|
con = sh->type->construction;
|
|
|
|
|
size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
|
|
|
|
cmistake(u, cmd, 14, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(n >= (sh->size*100)/sh->type->construction->maxsize) {
|
|
|
|
|
/* destroy completly */
|
|
|
|
|
/* all units leave the ship */
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (u2->ship == sh) {
|
|
|
|
|
u2->ship = 0;
|
|
|
|
|
freset(u2, UFL_OWNER);
|
|
|
|
|
}
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "shipdestroy%u:unit%r:region%h:ship", u, r, sh));
|
|
|
|
|
destroy_ship(sh, r);
|
|
|
|
|
} else {
|
|
|
|
|
/* partial destroy */
|
|
|
|
|
sh->size -= (sh->type->construction->maxsize * n)/100;
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "shipdestroy_partial%u:unit%r:region%h:ship", u, r, sh));
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
printf("* Fehler im Program! Die Einheit %s von %s\n"
|
|
|
|
|
" (Spieler: %s) war owner eines objects,\n"
|
|
|
|
|
" war aber weder in einer Burg noch in einem Schiff.\n",
|
|
|
|
|
unitname(u), u->faction->name, u->faction->email);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
|
|
|
|
|
#if 0
|
2004-05-22 01:02:19 +02:00
|
|
|
|
/* Achtung: Nicht an ZERST<53>RE mit Punktangabe angepa<70>t! */
|
|
|
|
|
if (con) {
|
|
|
|
|
/* Man sollte alle Materialien zur<75>ckkriegen k<>nnen: */
|
|
|
|
|
int c;
|
|
|
|
|
for (c=0;con->materials[c].number;++c) {
|
|
|
|
|
const requirement * rq = con->materials+c;
|
|
|
|
|
int recycle = (int)(rq->recycle * rq->number * size/con->reqsize);
|
|
|
|
|
if (recycle)
|
|
|
|
|
change_resource(u, rq->type, recycle);
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
build_road(region * r, unit * u, int size, direction_t d)
|
|
|
|
|
{
|
|
|
|
|
int n, dm, left;
|
|
|
|
|
|
|
|
|
|
if (!eff_skill(u, SK_ROAD_BUILDING, r)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 103, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 60, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (terrain[rterrain(r)].roadreq < 0) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 94, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (rterrain(r) == T_SWAMP) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* wenn kein Damm existiert */
|
2002-03-27 22:49:27 +01:00
|
|
|
|
static const struct building_type * bt_dam;
|
|
|
|
|
if (!bt_dam) bt_dam = bt_find("dam");
|
|
|
|
|
assert(bt_dam);
|
|
|
|
|
if (!buildingtype_exists(r, bt_dam)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 132, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-03-27 22:49:27 +01:00
|
|
|
|
}
|
|
|
|
|
if (rterrain(r) == T_DESERT) {
|
|
|
|
|
static const struct building_type * bt_caravan;
|
|
|
|
|
if (!bt_caravan) bt_caravan = bt_find("caravan");
|
|
|
|
|
assert(bt_caravan);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* wenn keine Karawanserei existiert */
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (!buildingtype_exists(r, bt_caravan)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 133, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-03-27 22:49:27 +01:00
|
|
|
|
}
|
|
|
|
|
if (rterrain(r) == T_GLACIER) {
|
|
|
|
|
static const struct building_type * bt_tunnel;
|
|
|
|
|
if (!bt_tunnel) bt_tunnel = bt_find("tunnel");
|
|
|
|
|
assert(bt_tunnel);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* wenn kein Tunnel existiert */
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (!buildingtype_exists(r, bt_tunnel)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 131, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-03-27 22:49:27 +01:00
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!get_pooled(u, r, R_STONE) && old_race(u->race) != RC_STONEGOLEM) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 151, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* left kann man noch bauen */
|
|
|
|
|
left = terrain[rterrain(r)].roadreq - rroad(r, d);
|
|
|
|
|
if (size > 0) {
|
|
|
|
|
n = min(size, left);
|
|
|
|
|
} else {
|
|
|
|
|
n = left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* hoffentlich ist r->road <= terrain[rterrain(r)].roadreq, n also >= 0 */
|
|
|
|
|
|
|
|
|
|
if (n <= 0) {
|
|
|
|
|
sprintf(buf, "In %s gibt es keine Br<42>cken und Stra<72>en "
|
|
|
|
|
"mehr zu bauen", regionid(r));
|
|
|
|
|
mistake(u, u->thisorder, buf, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* max Bauten anhand des Talentes */
|
|
|
|
|
n = min(n, u->number * eff_skill(u, SK_ROAD_BUILDING, r));
|
|
|
|
|
|
|
|
|
|
if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) {
|
|
|
|
|
dm = min(dm, u->number);
|
|
|
|
|
change_effect(u, oldpotiontype[P_DOMORE], -dm);
|
|
|
|
|
n += dm * eff_skill(u, SK_ROAD_BUILDING, r);
|
|
|
|
|
} /* Auswirkung Schaffenstrunk */
|
|
|
|
|
|
|
|
|
|
/* und anhand der rohstoffe */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_STONEGOLEM){
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n = min(n, u->number * GOLEM_STONE);
|
|
|
|
|
} else {
|
|
|
|
|
n = use_pooled(u, r, R_STONE, n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* n is now modified by several special effects, so we have to
|
|
|
|
|
* minimize it again to make sure the road will not grow beyond
|
|
|
|
|
* maximum. */
|
|
|
|
|
rsetroad(r, d, rroad(r, d) + min(n, left));
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_STONEGOLEM){
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int golemsused = n / GOLEM_STONE;
|
|
|
|
|
if (n%GOLEM_STONE != 0){
|
|
|
|
|
++golemsused;
|
|
|
|
|
}
|
|
|
|
|
scale_number(u,u->number - golemsused);
|
2001-02-03 14:45:35 +01:00
|
|
|
|
} else {
|
|
|
|
|
/* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
|
2002-02-16 11:37:18 +01:00
|
|
|
|
produceexp(u, SK_ROAD_BUILDING, min(n, u->number));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "buildroad%r:region%u:unit%i:size", r, u, n));
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/* ** ** ** ** ** ** *
|
|
|
|
|
* new build rules *
|
|
|
|
|
* ** ** ** ** ** ** */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
required(int size, int msize, int maxneed)
|
|
|
|
|
/* um size von msize Punkten zu bauen,
|
|
|
|
|
* braucht man required von maxneed resourcen */
|
|
|
|
|
{
|
|
|
|
|
int used;
|
|
|
|
|
|
|
|
|
|
used = size * maxneed / msize;
|
|
|
|
|
if (size * maxneed % msize)
|
|
|
|
|
++used;
|
|
|
|
|
return used;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
matmod(const attrib * a, const unit * u, const resource_type * material, int value)
|
|
|
|
|
{
|
|
|
|
|
for (a=a_find((attrib*)a, &at_matmod);a;a=a->nexttype) {
|
|
|
|
|
mm_fun fun = (mm_fun)a->data.f;
|
|
|
|
|
value = fun(u, material, value);
|
|
|
|
|
if (value<0) return value; /* pass errors to caller */
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2004-04-12 13:00:22 +02:00
|
|
|
|
/** Use up resources for building an object.
|
|
|
|
|
* Build up to 'size' points of 'type', where 'completed'
|
|
|
|
|
* of the first object have already been finished. return the
|
|
|
|
|
* actual size that could be built.
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int
|
|
|
|
|
build(unit * u, const construction * ctype, int completed, int want)
|
|
|
|
|
{
|
|
|
|
|
const construction * type = ctype;
|
|
|
|
|
int skills; /* number of skill points remainig */
|
|
|
|
|
int dm = get_effect(u, oldpotiontype[P_DOMORE]);
|
|
|
|
|
int made = 0;
|
|
|
|
|
int basesk, effsk;
|
|
|
|
|
|
2001-04-01 08:58:45 +02:00
|
|
|
|
if (want<=0) return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (type==NULL) return 0;
|
|
|
|
|
if (type->improvement==NULL && completed==type->maxsize)
|
|
|
|
|
return ECOMPLETE;
|
|
|
|
|
|
|
|
|
|
basesk = effskill(u, type->skill);
|
|
|
|
|
if (basesk==0) return ENEEDSKILL;
|
|
|
|
|
|
|
|
|
|
effsk = basesk;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (inside_building(u)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, effsk, SMF_PRODUCTION);
|
|
|
|
|
}
|
|
|
|
|
effsk = skillmod(type->attribs, u, u->region, type->skill, effsk, SMF_PRODUCTION);
|
|
|
|
|
if (effsk<0) return effsk; /* pass errors to caller */
|
|
|
|
|
if (effsk==0) return ENEEDSKILL;
|
|
|
|
|
|
|
|
|
|
skills = effsk * u->number;
|
|
|
|
|
|
|
|
|
|
/* technically, nimblefinge and domore should be in a global set of "game"-attributes,
|
|
|
|
|
* (as at_skillmod) but for a while, we're leaving them in here. */
|
|
|
|
|
|
|
|
|
|
if (dm != 0) {
|
|
|
|
|
/* Auswirkung Schaffenstrunk */
|
|
|
|
|
dm = min(dm, u->number);
|
|
|
|
|
change_effect(u, oldpotiontype[P_DOMORE], -dm);
|
|
|
|
|
skills += dm * effsk;
|
|
|
|
|
}
|
|
|
|
|
for (;want>0 && skills>0;) {
|
2002-03-24 12:24:57 +01:00
|
|
|
|
int c, n;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* skip over everything that's already been done:
|
|
|
|
|
* type->improvement==NULL means no more improvements, but no size limits
|
|
|
|
|
* type->improvement==type means build another object of the same time while material lasts
|
|
|
|
|
* type->improvement==x means build x when type is finished
|
|
|
|
|
*/
|
|
|
|
|
while (type->improvement!=NULL &&
|
|
|
|
|
type->improvement!=type &&
|
|
|
|
|
type->maxsize>0 &&
|
2001-04-08 19:36:50 +02:00
|
|
|
|
type->maxsize<=completed)
|
|
|
|
|
{
|
2001-01-25 10:37:55 +01:00
|
|
|
|
completed -= type->maxsize;
|
|
|
|
|
type = type->improvement;
|
|
|
|
|
}
|
|
|
|
|
if (type==NULL) {
|
|
|
|
|
if (made==0) return ECOMPLETE;
|
|
|
|
|
break; /* completed */
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
/* Hier ist entweder maxsize == -1, oder completed < maxsize.
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* Andernfalls ist das Datenfile oder sonstwas kaputt...
|
|
|
|
|
* (enno): Nein, das ist f<EFBFBD>r Dinge, bei denen die n<EFBFBD>chste Ausbaustufe
|
|
|
|
|
* die gleiche wie die vorherige ist. z.b. gegenst<EFBFBD>nde.
|
|
|
|
|
*/
|
|
|
|
|
if (type->maxsize>1) {
|
|
|
|
|
completed = completed % type->maxsize;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2002-03-17 12:42:23 +01:00
|
|
|
|
completed = 0; assert(type->reqsize>=1);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (basesk < type->minskill) {
|
2001-02-03 14:45:35 +01:00
|
|
|
|
if (made==0) return ELOWSKILL; /* not good enough to go on */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* n = maximum buildable size */
|
2001-05-06 23:49:16 +02:00
|
|
|
|
if(type->minskill > 1) {
|
|
|
|
|
n = skills / type->minskill;
|
|
|
|
|
} else {
|
|
|
|
|
n = skills;
|
|
|
|
|
}
|
2002-12-22 09:48:47 +01:00
|
|
|
|
/* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische)
|
|
|
|
|
* Talente */
|
2002-03-24 12:24:57 +01:00
|
|
|
|
if (max_skill(u->faction, type->skill)==INT_MAX) {
|
|
|
|
|
int i = 0;
|
|
|
|
|
item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]);
|
|
|
|
|
if (itm!=NULL) i = itm->number;
|
|
|
|
|
if (i>0) {
|
|
|
|
|
int rings = min(u->number, i);
|
|
|
|
|
n = n * (9*rings+u->number) / u->number;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-11-03 09:39:04 +01:00
|
|
|
|
if (want>0) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n = min(want, n);
|
2002-11-03 09:39:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (type->maxsize>0) {
|
|
|
|
|
n = min(type->maxsize-completed, n);
|
2002-10-27 11:17:47 +01:00
|
|
|
|
if (type->improvement==NULL) {
|
|
|
|
|
want = n;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (type->materials) for (c=0;n>0 && type->materials[c].number;c++) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
resource_t rtype = type->materials[c].type;
|
|
|
|
|
int need;
|
|
|
|
|
int have = get_pooled(u, NULL, rtype);
|
|
|
|
|
int prebuilt;
|
|
|
|
|
int canuse = have;
|
2004-04-12 12:24:01 +02:00
|
|
|
|
if (inside_building(u)) {
|
|
|
|
|
canuse = matmod(u->building->type->attribs, u, oldresourcetype[rtype], canuse);
|
|
|
|
|
#if 0
|
|
|
|
|
/* exploit-check */
|
|
|
|
|
} else if (u->building) {
|
|
|
|
|
int abuse = matmod(u->building->type->attribs, u, oldresourcetype[rtype], canuse);
|
|
|
|
|
if (abuse>canuse) {
|
|
|
|
|
log_printf("ABUSE: %s saves %u %s through exploit\n",
|
|
|
|
|
itoa36(u->faction->no), abuse-canuse,
|
|
|
|
|
oldresourcetype[rtype]->_name[0]);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (canuse<0) return canuse; /* pass errors to caller */
|
|
|
|
|
canuse = matmod(type->attribs, u, oldresourcetype[rtype], canuse);
|
|
|
|
|
if (type->reqsize>1) {
|
|
|
|
|
prebuilt = required(completed, type->reqsize, type->materials[c].number);
|
|
|
|
|
for (;n;) {
|
|
|
|
|
need = required(completed + n, type->reqsize, type->materials[c].number);
|
|
|
|
|
if (need-prebuilt<=canuse) break;
|
|
|
|
|
--n; /* TODO: optimieren? */
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
int maxn = canuse / type->materials[c].number;
|
|
|
|
|
if (maxn < n) n = maxn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (n<=0) {
|
|
|
|
|
if (made==0) return ENOMATERIALS;
|
|
|
|
|
else break;
|
|
|
|
|
}
|
|
|
|
|
if (type->materials) for (c=0;type->materials[c].number;c++) {
|
|
|
|
|
resource_t rtype = type->materials[c].type;
|
|
|
|
|
int prebuilt = required(completed, type->reqsize, type->materials[c].number);
|
|
|
|
|
int need = required(completed + n, type->reqsize, type->materials[c].number);
|
|
|
|
|
int multi = 1;
|
|
|
|
|
int canuse = 100; /* normalization */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, oldresourcetype[rtype], canuse);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (canuse<0) return canuse; /* pass errors to caller */
|
|
|
|
|
canuse = matmod(type->attribs, u, oldresourcetype[rtype], canuse);
|
|
|
|
|
|
|
|
|
|
assert(canuse % 100 == 0 || !"only constant multipliers are implemented in build()");
|
|
|
|
|
multi = canuse/100;
|
|
|
|
|
if (canuse<0) return canuse; /* pass errors to caller */
|
|
|
|
|
|
|
|
|
|
use_pooled(u, NULL, rtype, (need-prebuilt+multi-1)/multi);
|
|
|
|
|
}
|
|
|
|
|
made += n;
|
|
|
|
|
skills -= n * type->minskill;
|
|
|
|
|
want -= n;
|
|
|
|
|
completed = completed + n;
|
|
|
|
|
}
|
|
|
|
|
/* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
|
2002-02-16 11:37:18 +01:00
|
|
|
|
produceexp(u, ctype->skill, min(made, u->number));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
return made;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
maxbuild(const unit * u, const construction * cons)
|
2002-04-14 12:35:00 +02:00
|
|
|
|
/* calculate maximum size that can be built from available material */
|
|
|
|
|
/* !! ignores maximum objectsize and improvements...*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
int maximum = INT_MAX;
|
|
|
|
|
for (c=0;cons->materials[c].number;c++) {
|
|
|
|
|
resource_t rtype = cons->materials[c].type;
|
|
|
|
|
int have = get_pooled(u, NULL, rtype);
|
|
|
|
|
int need = required(1, cons->reqsize, cons->materials[c].number);
|
|
|
|
|
if (have<need) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 88, MSG_PRODUCE);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else maximum = min(maximum, have/need);
|
|
|
|
|
}
|
|
|
|
|
return maximum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** old build routines */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
build_building(unit * u, const building_type * btype, int want)
|
|
|
|
|
{
|
|
|
|
|
region * r = u->region;
|
|
|
|
|
boolean newbuilding = false;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int c, built = 0, id;
|
|
|
|
|
building * b = NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* einmalige Korrektur */
|
|
|
|
|
static char buffer[8 + IDSIZE + 1 + NAMESIZE + 1];
|
|
|
|
|
const char *string2;
|
|
|
|
|
|
|
|
|
|
if (eff_skill(u, SK_BUILDING, r) == 0) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 101, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der
|
|
|
|
|
* betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg
|
2001-12-10 01:13:39 +01:00
|
|
|
|
* gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten
|
|
|
|
|
* baut man an der eigenen burg weiter. */
|
|
|
|
|
|
|
|
|
|
/* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */
|
|
|
|
|
id = atoi36(getstrtoken());
|
|
|
|
|
if (id!=0){ /* eine Nummer angegeben, keine neue Burg bauen */
|
|
|
|
|
b = findbuilding(id);
|
|
|
|
|
if (!b || b->region != u->region){ /* eine Burg mit dieser Nummer gibt es hier nicht */
|
|
|
|
|
/* vieleicht Tippfehler und die eigene Burg ist gemeint? */
|
|
|
|
|
if (u->building && u->building->type==btype) {
|
|
|
|
|
b = u->building;
|
|
|
|
|
} else {
|
|
|
|
|
/* keine neue Burg anfangen wenn eine Nummer angegeben war */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 6, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (b) btype = b->type;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* only one of these per region */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 93, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
/* units under siege can not build */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 60, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (btype->flags & BTF_NOBUILD) {
|
|
|
|
|
/* special building, cannot be built */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 221, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b) built = b->size;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
if (want<=0 || want == INT_MAX) {
|
|
|
|
|
if(b == NULL) {
|
2001-04-08 19:36:50 +02:00
|
|
|
|
if(btype->maxsize > 0) {
|
|
|
|
|
want = btype->maxsize - built;
|
|
|
|
|
} else {
|
|
|
|
|
want = INT_MAX;
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
} else {
|
2001-04-08 19:36:50 +02:00
|
|
|
|
if(b->type->maxsize > 0) {
|
|
|
|
|
want = b->type->maxsize - built;
|
|
|
|
|
} else {
|
|
|
|
|
want = INT_MAX;
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
built = build(u, btype->construction, built, want);
|
|
|
|
|
|
|
|
|
|
switch (built) {
|
|
|
|
|
case ECOMPLETE:
|
|
|
|
|
/* the building is already complete */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 4, MSG_PRODUCE);
|
|
|
|
|
return;
|
2001-02-03 14:45:35 +01:00
|
|
|
|
case ENOMATERIALS: {
|
2001-02-04 11:04:51 +01:00
|
|
|
|
/* something missing from the list of materials */
|
|
|
|
|
const construction * cons = btype->construction;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
char * ch = buf;
|
2001-02-04 11:04:51 +01:00
|
|
|
|
assert(cons);
|
|
|
|
|
for (c=0;cons->materials[c].number; c++) {
|
|
|
|
|
int n;
|
|
|
|
|
if (c!=0) strcat(ch++, ",");
|
|
|
|
|
n = cons->materials[c].number / cons->reqsize;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
sprintf(ch, " %d %s", n?n:1,
|
|
|
|
|
locale_string(u->faction->locale,
|
2001-05-27 11:35:19 +02:00
|
|
|
|
resname(cons->materials[c].type, cons->materials[c].number!=1))
|
|
|
|
|
);
|
2001-02-04 11:04:51 +01:00
|
|
|
|
ch = ch+strlen(ch);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
msg_error(u, findorder(u,u->thisorder), "build_required", "required", buf);
|
2001-02-04 11:04:51 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case ELOWSKILL:
|
|
|
|
|
case ENEEDSKILL:
|
|
|
|
|
/* no skill, or not enough skill points to build */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 50, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* at this point, the building size is increased. */
|
|
|
|
|
if (b==NULL) {
|
|
|
|
|
/* build a new building */
|
|
|
|
|
b = new_building(btype, r, u->faction->locale);
|
|
|
|
|
b->type = btype;
|
|
|
|
|
fset(b, BLD_MAINTAINED);
|
|
|
|
|
|
|
|
|
|
/* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */
|
|
|
|
|
leave(r, u);
|
|
|
|
|
u->building = b;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
newbuilding = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (b->type->name) {
|
|
|
|
|
string2 = LOC(u->faction->locale, b->type->_name);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
string2 = LOC(u->faction->locale, buildingtype(b, b->size));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if( newbuilding && b->type->maxsize != -1 )
|
|
|
|
|
want = b->type->maxsize - b->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( want == INT_MAX )
|
2001-04-16 16:34:19 +02:00
|
|
|
|
sprintf(buffer, "%s %s %s", locale_string(u->faction->locale, keywords[K_MAKE]), string2, buildingid(b));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else if( want-built <= 0 )
|
2002-02-16 11:37:18 +01:00
|
|
|
|
strcpy(buffer, locale_string(u->faction->locale, "defaultorder"));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else
|
2001-04-16 16:34:19 +02:00
|
|
|
|
sprintf(buffer, "%s %d %s %s", locale_string(u->faction->locale, keywords[K_MAKE]), want-built, string2, buildingid(b));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
set_string(&u->lastorder, buffer);
|
|
|
|
|
|
|
|
|
|
b->size += built;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
update_lighthouse(b);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "buildbuilding%b:building%u:unit%i:size", b, u, built));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
build_ship(unit * u, ship * sh, int want)
|
|
|
|
|
{
|
|
|
|
|
const construction * construction = sh->type->construction;
|
|
|
|
|
int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE;
|
|
|
|
|
int n;
|
2004-01-24 00:27:16 +01:00
|
|
|
|
#if 0
|
|
|
|
|
int can = u->number * effskill(u, SK_SHIPBUILDING) / construction->minskill;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (want > 0) can = min(want, can);
|
2001-04-22 20:14:07 +02:00
|
|
|
|
can = min(can, construction->maxsize+sh->damage); /* 100% bauen + 100% reparieren */
|
2004-01-24 00:27:16 +01:00
|
|
|
|
#endif
|
|
|
|
|
int can = build(u, construction, size, want);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-24 00:27:16 +01:00
|
|
|
|
if ((n=construction->maxsize - sh->size)>0 && can>0) {
|
|
|
|
|
if (can>=n) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
sh->size += n;
|
|
|
|
|
can -= n;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
sh->size += can;
|
|
|
|
|
n=can;
|
|
|
|
|
can = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sh->damage && can) {
|
|
|
|
|
int repair = min(sh->damage, can * DAMAGE_SCALE);
|
|
|
|
|
n += repair / DAMAGE_SCALE;
|
|
|
|
|
if (repair % DAMAGE_SCALE) ++n;
|
|
|
|
|
sh->damage = sh->damage - repair;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(n)
|
|
|
|
|
add_message(&u->faction->msgs, new_message(
|
|
|
|
|
u->faction, "buildship%h:ship%u:unit%i:size", sh, u, n));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
create_ship(region * r, unit * u, const struct ship_type * newtype, int want)
|
|
|
|
|
{
|
|
|
|
|
static char buffer[IDSIZE + 2 * KEYWORDSIZE + 3];
|
|
|
|
|
ship *sh;
|
|
|
|
|
int msize;
|
|
|
|
|
const construction * cons = newtype->construction;
|
|
|
|
|
|
|
|
|
|
if (!eff_skill(u, SK_SHIPBUILDING, r)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 100, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 60, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* check if skill and material for 1 size is available */
|
|
|
|
|
if (eff_skill(u, cons->skill, r) < cons->minskill) {
|
|
|
|
|
sprintf(buf, "Um %s zu bauen, braucht man ein Talent von "
|
|
|
|
|
"mindestens %d.", newtype->name[1], cons->minskill);
|
|
|
|
|
mistake(u, u->thisorder, buf, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msize = maxbuild(u, cons);
|
|
|
|
|
if (msize==0) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 88, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (want>0) want = min(want, msize);
|
|
|
|
|
else want = msize;
|
|
|
|
|
|
2001-02-18 11:06:10 +01:00
|
|
|
|
sh = new_ship(newtype, r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
addlist(&r->ships, sh);
|
|
|
|
|
|
|
|
|
|
leave(r, u);
|
|
|
|
|
u->ship = sh;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
sprintf(buffer, "%s %s %s",
|
2001-04-16 16:34:19 +02:00
|
|
|
|
locale_string(u->faction->locale, keywords[K_MAKE]), locale_string(u->faction->locale, parameters[P_SHIP]), shipid(sh));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
u->lastorder = set_string(&u->lastorder, buffer);
|
|
|
|
|
|
|
|
|
|
build_ship(u, sh, want);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
continue_ship(region * r, unit * u, int want)
|
|
|
|
|
{
|
|
|
|
|
const construction * cons;
|
|
|
|
|
ship *sh;
|
|
|
|
|
int msize;
|
|
|
|
|
|
|
|
|
|
if (!eff_skill(u, SK_SHIPBUILDING, r)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 100, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */
|
|
|
|
|
sh = getship(r);
|
|
|
|
|
|
|
|
|
|
if (!sh) sh = u->ship;
|
|
|
|
|
|
|
|
|
|
if (!sh) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 20, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
cons = sh->type->construction;
|
|
|
|
|
assert(cons->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
|
|
|
|
if (sh->size==cons->maxsize && !sh->damage) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 16, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (eff_skill(u, cons->skill, r) < cons->minskill) {
|
|
|
|
|
sprintf(buf, "Um %s zu bauen, braucht man ein Talent von "
|
|
|
|
|
"mindestens %d.", sh->type->name[1], cons->minskill);
|
|
|
|
|
mistake(u, u->thisorder, buf, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
msize = maxbuild(u, cons);
|
|
|
|
|
if (msize==0) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 88, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (want > 0) want = min(want, msize);
|
|
|
|
|
else want = msize;
|
|
|
|
|
|
|
|
|
|
build_ship(u, sh, want);
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static boolean
|
2001-01-25 10:37:55 +01:00
|
|
|
|
mayenter(region * r, unit * u, building * b)
|
|
|
|
|
{
|
|
|
|
|
unit *u2;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (fval(b, BLD_UNGUARDED)) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
u2 = buildingowner(r, b);
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u2==NULL || ucontact(u2, u)
|
2002-09-02 22:36:12 +02:00
|
|
|
|
|| alliedunit(u2, u->faction, HELP_GUARD)) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2002-11-25 16:30:51 +01:00
|
|
|
|
mayboard(const unit * u, const ship * sh)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2003-07-29 11:48:03 +02:00
|
|
|
|
unit *u2 = shipowner(sh->region, sh);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
return (!u2
|
|
|
|
|
|| ucontact(u2, u)
|
2002-09-02 22:36:12 +02:00
|
|
|
|
|| alliedunit(u2, u->faction, HELP_GUARD));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
remove_contacts(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
unit *u;
|
|
|
|
|
attrib *a;
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
a = (attrib *)a_find(u->attribs, &at_contact);
|
|
|
|
|
while(a != NULL) {
|
|
|
|
|
attrib * ar = a;
|
|
|
|
|
a = a->nexttype;
|
|
|
|
|
a_remove(&u->attribs, ar);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_leave(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
unit *u;
|
|
|
|
|
strlist *S;
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
for (S = u->orders; S; S = S->next) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if(igetkeyword(S->s, u->faction->locale) == K_LEAVE) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (r->terrain == T_OCEAN && u->ship) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(!fval(u->race, RCF_SWIM)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 11, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(get_item(u, I_HORSE)) {
|
|
|
|
|
cmistake(u, S->s, 231, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!slipthru(r, u, u->building)) {
|
|
|
|
|
sprintf(buf, "%s wird belagert.", buildingname(u->building));
|
|
|
|
|
mistake(u, S->s, buf, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
leave(r, u);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-25 16:30:51 +01:00
|
|
|
|
static boolean
|
|
|
|
|
entership(unit * u, ship * sh, const char * cmd, boolean lasttry)
|
|
|
|
|
{
|
|
|
|
|
/* Mu<4D> abgefangen werden, sonst k<>nnten Schwimmer an
|
|
|
|
|
* Bord von Schiffen an Land gelangen. */
|
|
|
|
|
if( !fval(u->race, RCF_WALK) &&
|
|
|
|
|
!fval(u->race, RCF_FLY)) {
|
|
|
|
|
cmistake(u, cmd, 233, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sh) {
|
|
|
|
|
if (lasttry) cmistake(u, cmd, 20, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-11-25 20:11:27 +01:00
|
|
|
|
if (sh==u->ship) return true;
|
2002-11-25 16:30:51 +01:00
|
|
|
|
if (!mayboard(u, sh)) {
|
|
|
|
|
if (lasttry) cmistake(u, cmd, 34, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2004-05-04 21:24:03 +02:00
|
|
|
|
if (CheckOverload()) {
|
2002-11-25 16:30:51 +01:00
|
|
|
|
int sweight, scabins;
|
2003-01-03 13:39:03 +01:00
|
|
|
|
int mweight = shipcapacity(sh);
|
|
|
|
|
int mcabins = sh->type->cabins;
|
|
|
|
|
if (mweight>0 && mcabins>0) {
|
|
|
|
|
getshipweight(sh, &sweight, &scabins);
|
|
|
|
|
sweight += weight(u);
|
|
|
|
|
scabins += u->number;
|
|
|
|
|
|
|
|
|
|
if (sweight > mweight || scabins > mcabins) {
|
|
|
|
|
if (lasttry) cmistake(u, cmd, 34, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-11-25 16:30:51 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave(u->region, u);
|
|
|
|
|
u->ship = sh;
|
|
|
|
|
|
|
|
|
|
if (shipowner(u->region, sh) == 0) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_OWNER);
|
2002-11-25 16:30:51 +01:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
2002-11-25 16:30:51 +01:00
|
|
|
|
do_misc(boolean lasttry)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
strlist *S, *Snext;
|
|
|
|
|
ship *sh;
|
|
|
|
|
building *b;
|
|
|
|
|
|
2002-11-25 16:30:51 +01:00
|
|
|
|
/* lasttry: Fehler nur im zweiten Versuch melden. Sonst konfus. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
unit *u;
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
for (S = u->orders; S; S = S->next) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
switch (igetkeyword(S->s, u->faction->locale)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case K_CONTACT:
|
2002-11-25 16:30:51 +01:00
|
|
|
|
set_contact(r, u, lasttry);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
for (S = u->orders; S;) {
|
|
|
|
|
Snext = S->next;
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
switch (igetkeyword(S->s, u->faction->locale)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case K_ENTER:
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
switch (getparam(u->faction->locale)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case P_BUILDING:
|
|
|
|
|
case P_GEBAEUDE:
|
|
|
|
|
|
2002-04-21 19:47:18 +02:00
|
|
|
|
/* Schwimmer k<>nnen keine Geb<65>ude betreten, au<61>er diese sind
|
|
|
|
|
* auf dem Ozean */
|
|
|
|
|
if( !fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) {
|
|
|
|
|
if (rterrain(r) != T_OCEAN){
|
2002-11-25 16:30:51 +01:00
|
|
|
|
if (lasttry) cmistake(u, S->s, 232, MSG_MOVE);
|
2002-04-21 19:47:18 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b = getbuilding(r);
|
|
|
|
|
|
|
|
|
|
if (!b) {
|
2002-11-25 16:30:51 +01:00
|
|
|
|
if(lasttry) cmistake(u, S->s, 6, MSG_MOVE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2002-04-21 19:47:18 +02:00
|
|
|
|
/* Geb<65>ude auf dem Ozean sollte man betreten d<>rfen
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(rterrain(r) == T_OCEAN) {
|
2002-11-25 16:30:51 +01:00
|
|
|
|
if (lasttry) cmistake(u, S->s, 297, MSG_MOVE);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2002-04-21 19:47:18 +02:00
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!mayenter(r, u, b)) {
|
2002-11-25 16:30:51 +01:00
|
|
|
|
if(lasttry) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
sprintf(buf, "Der Eintritt in %s wurde verwehrt",
|
|
|
|
|
buildingname(b));
|
|
|
|
|
mistake(u, S->s, buf, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!slipthru(r, u, b)) {
|
2002-11-25 16:30:51 +01:00
|
|
|
|
if(lasttry) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
sprintf(buf, "%s wird belagert", buildingname(b));
|
|
|
|
|
mistake(u, S->s, buf, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wenn wir hier angekommen sind, war der Befehl
|
|
|
|
|
* erfolgreich und wir l<EFBFBD>schen ihn, damit er im
|
|
|
|
|
* zweiten Versuch nicht nochmal ausgef<EFBFBD>hrt wird. */
|
|
|
|
|
removelist(&u->orders, S);
|
|
|
|
|
|
|
|
|
|
leave(r, u);
|
|
|
|
|
u->building = b;
|
|
|
|
|
if (buildingowner(r, b) == 0) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case P_SHIP:
|
|
|
|
|
sh = getship(r);
|
2002-11-25 20:11:27 +01:00
|
|
|
|
entership(u, sh, S->s, lasttry);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2002-11-25 16:30:51 +01:00
|
|
|
|
if(lasttry) cmistake(u, S->s, 79, MSG_MOVE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
S = Snext;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|