2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2004-10-12 23:05:35 +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"
|
2004-06-21 18:45:27 +02:00
|
|
|
|
#include "order.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#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>
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
unit *u2;
|
|
|
|
|
int n, o;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/* b ist die burg, in die man hinein oder aus der man heraus will. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
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 */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
n = eff_skill(u, SK_STEALTH, r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (usiege(u2) == b) {
|
2002-11-27 20:35:36 +01:00
|
|
|
|
|
2005-07-10 18:32:47 +02:00
|
|
|
|
if (invisible(u, u2) >= u->number) continue;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
o = eff_skill(u2, SK_OBSERVATION, r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
if (o + 2 >= n)
|
|
|
|
|
return 0; /* entdeckt! */
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/* hier geht es nur um die belagerung von burgen */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
if (u->building == u2->building)
|
|
|
|
|
return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/* 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 */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
if (slipthru(u->region, u, u->building)
|
|
|
|
|
&& slipthru(u->region, u2, u2->building))
|
|
|
|
|
return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
if (alliedunit(u, u2->faction, HELP_GIVE))
|
|
|
|
|
return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2004-06-21 18:45:27 +02:00
|
|
|
|
contact_cmd(unit * u, order * ord, boolean tries)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-10-12 23:05:35 +02: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! */
|
|
|
|
|
unit *u2;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region * r = u->region;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
u2 = getunitg(r, u->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
if (u2!=NULL) {
|
|
|
|
|
if (!can_contact(r, u, u2)) {
|
|
|
|
|
if (tries) cmistake(u, u->thisorder, 23, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
usetcontact(u, u2);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
struct building *
|
|
|
|
|
getbuilding(const struct region * r)
|
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
building * b = findbuilding(getid());
|
|
|
|
|
if (b==NULL || r!=b->region) return NULL;
|
|
|
|
|
return b;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ship *
|
|
|
|
|
getship(const struct region * r)
|
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
ship *sh, *sx = findship(getshipid());
|
|
|
|
|
for (sh = r->ships; sh; sh = sh->next) {
|
|
|
|
|
if (sh == sx) return sh;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
static void
|
2004-06-21 18:45:27 +02:00
|
|
|
|
siege_cmd(unit * u, order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region * r = u->region;
|
|
|
|
|
unit *u2;
|
|
|
|
|
building *b;
|
|
|
|
|
int d;
|
|
|
|
|
int bewaffnete, katapultiere = 0;
|
|
|
|
|
static boolean init = false;
|
|
|
|
|
static const curse_type * magicwalls_ct;
|
2005-01-30 15:30:31 +01:00
|
|
|
|
static item_type * it_catapultammo = NULL;
|
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
magicwalls_ct = ct_find("magicwalls");
|
|
|
|
|
it_catapultammo = it_find("catapultammo");
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* gibt es ueberhaupt Burgen? */
|
|
|
|
|
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
b = getbuilding(r);
|
|
|
|
|
|
|
|
|
|
if (!b) {
|
|
|
|
|
cmistake(u, ord, 31, MSG_BATTLE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (!playerrace(u->race)) {
|
|
|
|
|
/* keine Drachen, Illusionen, Untote etc */
|
|
|
|
|
cmistake(u, ord, 166, MSG_BATTLE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* schaden durch katapulte */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
d = min(u->number,
|
2005-01-30 15:30:31 +01:00
|
|
|
|
min(new_get_pooled(u, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK), get_item(u, I_CATAPULT)));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (eff_skill(u, SK_CATAPULT, r) >= 1) {
|
|
|
|
|
katapultiere = d;
|
|
|
|
|
d *= eff_skill(u, SK_CATAPULT, r);
|
|
|
|
|
} else {
|
|
|
|
|
d = 0;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if ((bewaffnete = armedmen(u)) == 0 && d == 0) {
|
|
|
|
|
/* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */
|
|
|
|
|
cmistake(u, ord, 80, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (!(getguard(u) & GUARD_TRAVELTHRU)) {
|
|
|
|
|
/* abbruch, wenn die einheit nicht vorher die region bewacht - als
|
|
|
|
|
* warnung fuer alle anderen! */
|
|
|
|
|
cmistake(u, ord, 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 */
|
|
|
|
|
if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) {
|
|
|
|
|
b->size -= d;
|
2005-01-30 15:30:31 +01:00
|
|
|
|
new_use_pooled(u, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, d);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
d = 100 * d / b->size;
|
|
|
|
|
} else d = 0;
|
|
|
|
|
|
|
|
|
|
/* meldung fuer belagerer */
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("siege",
|
|
|
|
|
"unit building destruction", u, b, d));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
|
|
|
|
|
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);
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message("siege",
|
|
|
|
|
"unit building destruction", u, b, d));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_siege(void)
|
|
|
|
|
{
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region *r;
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
if (rterrain(r) != T_OCEAN) {
|
|
|
|
|
unit *u;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (get_keyword(u->thisorder) == K_BESIEGE) {
|
|
|
|
|
siege_cmd(u, u->thisorder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2005-06-12 11:48:19 +02:00
|
|
|
|
destroy_road(unit *u, int nmax, struct order * ord)
|
2001-04-01 08:58:45 +02:00
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
direction_t d = getdirection(u->faction->locale);
|
|
|
|
|
unit *u2;
|
|
|
|
|
region *r = u->region;
|
2005-06-12 11:48:19 +02:00
|
|
|
|
short n = (short)nmax;
|
|
|
|
|
|
|
|
|
|
if (nmax>SHRT_MAX) n = SHRT_MAX;
|
|
|
|
|
else if (nmax<0) n = 0;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
|
|
|
|
for (u2=r->units;u2;u2=u2->next) {
|
|
|
|
|
if (u2->faction!=u->faction && getguard(u2)&GUARD_TAX
|
|
|
|
|
&& cansee(u2->faction, u->region, u, 0)
|
|
|
|
|
&& !alliedunit(u, u2->faction, HELP_GUARD)) {
|
|
|
|
|
cmistake(u, ord, 70, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (d==NODIRECTION) {
|
|
|
|
|
cmistake(u, ord, 71, MSG_PRODUCE);
|
|
|
|
|
} else {
|
2005-06-12 11:48:19 +02:00
|
|
|
|
short road = rroad(r, d);
|
2005-06-26 15:24:19 +02:00
|
|
|
|
n = min(n, road);
|
|
|
|
|
if (n!=0) {
|
2005-06-12 11:48:19 +02:00
|
|
|
|
region * r2 = rconnect(r,d);
|
|
|
|
|
int willdo = eff_skill(u, SK_ROAD_BUILDING, r)*u->number;
|
2005-06-26 15:24:19 +02:00
|
|
|
|
willdo = min(willdo, n);
|
2005-06-12 11:48:19 +02:00
|
|
|
|
if (willdo==0) {
|
|
|
|
|
/* TODO: error message */
|
|
|
|
|
}
|
|
|
|
|
if (willdo>SHRT_MAX) road = 0;
|
|
|
|
|
else road = road - (short)willdo;
|
|
|
|
|
rsetroad(r, d, road);
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("destroy_road",
|
|
|
|
|
"unit from to", u, r, r2));
|
2004-10-12 23:05:35 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int
|
|
|
|
|
destroy_cmd(unit * u, struct order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-05-22 01:02:19 +02:00
|
|
|
|
ship *sh;
|
|
|
|
|
unit *u2;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region * r = u->region;
|
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)
|
2004-06-21 18:45:27 +02:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
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) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
destroy_road(u, INT_MAX, ord);
|
|
|
|
|
return 0;
|
2004-05-22 01:02:19 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (s && *s) {
|
2004-05-22 01:02:19 +02:00
|
|
|
|
n = atoi(s);
|
|
|
|
|
if(n <= 0) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 288, MSG_PRODUCE);
|
|
|
|
|
return 0;
|
2004-05-22 01:02:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (getparam(u->faction->locale) == P_ROAD) {
|
|
|
|
|
destroy_road(u, n, ord);
|
|
|
|
|
return 0;
|
2004-05-22 01:02:19 +02:00
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
|
2004-09-09 01:17:37 +02:00
|
|
|
|
if (!fval(u, UFL_OWNER)) {
|
|
|
|
|
cmistake(u, ord, 138, MSG_PRODUCE);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-22 01:02:19 +02:00
|
|
|
|
if (u->building) {
|
|
|
|
|
building *b = u->building;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (a_find(b->attribs, &at_nodestroy)) {
|
|
|
|
|
cmistake(u, ord, 14, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2004-06-13 12:21:48 +02:00
|
|
|
|
|
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);
|
|
|
|
|
}
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("destroy",
|
|
|
|
|
"building unit", b, u));
|
2004-05-22 01:02:19 +02:00
|
|
|
|
destroy_building(b);
|
|
|
|
|
} else {
|
|
|
|
|
/* partial destroy */
|
|
|
|
|
b->size -= n;
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("destroy_partial",
|
|
|
|
|
"building unit", b, u));
|
2004-05-22 01:02:19 +02:00
|
|
|
|
}
|
|
|
|
|
} else if (u->ship) {
|
|
|
|
|
sh = u->ship;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (a_find(sh->attribs, &at_nodestroy)) {
|
|
|
|
|
cmistake(u, ord, 14, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2004-06-13 12:21:48 +02:00
|
|
|
|
|
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) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 14, MSG_EVENT);
|
|
|
|
|
return 0;
|
2004-05-22 01:02:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("shipdestroy",
|
|
|
|
|
"unit region ship", u, r, sh));
|
2004-05-31 18:21:03 +02:00
|
|
|
|
destroy_ship(sh);
|
2004-05-22 01:02:19 +02:00
|
|
|
|
} else {
|
|
|
|
|
/* partial destroy */
|
|
|
|
|
sh->size -= (sh->type->construction->maxsize * n)/100;
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial",
|
|
|
|
|
"unit region ship", u, r, sh));
|
2004-05-22 01:02:19 +02:00
|
|
|
|
}
|
2004-05-25 23:50:23 +02:00
|
|
|
|
} else {
|
|
|
|
|
log_error(("Die Einheit %s von %s war owner eines objects, 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) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* TODO: ZERST<53>RE - Man sollte alle Materialien zur<75>ckkriegen k<>nnen: */
|
2004-05-22 01:02:19 +02:00
|
|
|
|
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
|
2004-06-21 18:45:27 +02:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
build_road(region * r, unit * u, int size, direction_t d)
|
|
|
|
|
{
|
2005-06-13 21:27:11 +02:00
|
|
|
|
int n, left;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
|
|
|
|
if (!eff_skill(u, SK_ROAD_BUILDING, r)) {
|
|
|
|
|
cmistake(u, u->thisorder, 103, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
cmistake(u, u->thisorder, 60, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (terrain[rterrain(r)].roadreq < 0) {
|
|
|
|
|
cmistake(u, u->thisorder, 94, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rterrain(r) == T_SWAMP) {
|
|
|
|
|
/* wenn kein Damm existiert */
|
|
|
|
|
static const struct building_type * bt_dam;
|
|
|
|
|
if (!bt_dam) bt_dam = bt_find("dam");
|
|
|
|
|
assert(bt_dam);
|
|
|
|
|
if (!buildingtype_exists(r, bt_dam)) {
|
|
|
|
|
cmistake(u, u->thisorder, 132, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (rterrain(r) == T_DESERT) {
|
|
|
|
|
static const struct building_type * bt_caravan;
|
|
|
|
|
if (!bt_caravan) bt_caravan = bt_find("caravan");
|
|
|
|
|
assert(bt_caravan);
|
|
|
|
|
/* wenn keine Karawanserei existiert */
|
|
|
|
|
if (!buildingtype_exists(r, bt_caravan)) {
|
|
|
|
|
cmistake(u, u->thisorder, 133, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (rterrain(r) == T_GLACIER) {
|
|
|
|
|
static const struct building_type * bt_tunnel;
|
|
|
|
|
if (!bt_tunnel) bt_tunnel = bt_find("tunnel");
|
|
|
|
|
assert(bt_tunnel);
|
|
|
|
|
/* wenn kein Tunnel existiert */
|
|
|
|
|
if (!buildingtype_exists(r, bt_tunnel)) {
|
|
|
|
|
cmistake(u, u->thisorder, 131, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-05-27 23:04:13 +02:00
|
|
|
|
if (!get_pooled(u, r, R_STONE) && u->race != new_race[RC_STONEGOLEM]) {
|
2004-10-12 23:05:35 +02:00
|
|
|
|
cmistake(u, u->thisorder, 151, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* left kann man noch bauen */
|
|
|
|
|
left = terrain[rterrain(r)].roadreq - rroad(r, d);
|
|
|
|
|
/* hoffentlich ist r->road <= terrain[rterrain(r)].roadreq, n also >= 0 */
|
2005-06-13 21:27:11 +02:00
|
|
|
|
if (left <= 0) {
|
2004-10-12 23:05:35 +02:00
|
|
|
|
sprintf(buf, "In %s gibt es keine Br<42>cken und Stra<72>en "
|
2005-01-19 21:33:13 +01:00
|
|
|
|
"mehr zu bauen", regionname(r, u->faction));
|
2004-10-12 23:05:35 +02:00
|
|
|
|
mistake(u, u->thisorder, buf, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-13 21:27:11 +02:00
|
|
|
|
/* baumaximum anhand der rohstoffe */
|
2005-05-27 23:04:13 +02:00
|
|
|
|
if (u->race == new_race[RC_STONEGOLEM]){
|
2005-06-13 21:27:11 +02:00
|
|
|
|
n = u->number * GOLEM_STONE;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
} else {
|
2005-06-13 21:27:11 +02:00
|
|
|
|
n = get_pooled(u, r, R_STONE);
|
|
|
|
|
}
|
|
|
|
|
left = min(n, left);
|
|
|
|
|
if (size>0) left = min(size, left);
|
|
|
|
|
|
|
|
|
|
/* n = maximum by skill. try to maximize it */
|
|
|
|
|
n = u->number * eff_skill(u, SK_ROAD_BUILDING, r);
|
|
|
|
|
if (n < left) {
|
|
|
|
|
item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]);
|
|
|
|
|
if (itm!=NULL && itm->number>0) {
|
|
|
|
|
int rings = min(u->number, itm->number);
|
|
|
|
|
n = n * (9*rings+u->number) / u->number;
|
|
|
|
|
}
|
2004-10-12 23:05:35 +02:00
|
|
|
|
}
|
2005-06-13 21:27:11 +02:00
|
|
|
|
if (n < left) {
|
|
|
|
|
int dm = get_effect(u, oldpotiontype[P_DOMORE]);
|
|
|
|
|
if (dm != 0) {
|
|
|
|
|
int sk = eff_skill(u, SK_ROAD_BUILDING, r);
|
|
|
|
|
dm = (left - n + sk - 1) / sk;
|
|
|
|
|
dm = min(dm, u->number);
|
|
|
|
|
change_effect(u, oldpotiontype[P_DOMORE], -dm);
|
|
|
|
|
n += dm * sk;
|
|
|
|
|
} /* Auswirkung Schaffenstrunk */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* make minimum of possible and available: */
|
|
|
|
|
n = min(left, n);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
|
|
|
|
/* 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. */
|
2005-06-13 21:27:11 +02:00
|
|
|
|
rsetroad(r, d, rroad(r, d) + (short)n);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
2005-06-13 21:27:11 +02:00
|
|
|
|
if (u->race == new_race[RC_STONEGOLEM]) {
|
2004-10-12 23:05:35 +02:00
|
|
|
|
int golemsused = n / GOLEM_STONE;
|
|
|
|
|
if (n%GOLEM_STONE != 0){
|
|
|
|
|
++golemsused;
|
|
|
|
|
}
|
2005-06-13 21:27:11 +02:00
|
|
|
|
scale_number(u, u->number - golemsused);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
} else {
|
2005-06-13 21:27:11 +02:00
|
|
|
|
use_pooled(u, r, R_STONE, n);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
|
|
|
|
|
produceexp(u, SK_ROAD_BUILDING, min(n, u->number));
|
|
|
|
|
}
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("buildroad",
|
|
|
|
|
"region unit size", r, u, n));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/* ** ** ** ** ** ** *
|
|
|
|
|
* new build rules *
|
|
|
|
|
* ** ** ** ** ** ** */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
required(int size, int msize, int maxneed)
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/* um size von msize Punkten zu bauen,
|
|
|
|
|
* braucht man required von maxneed resourcen */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
int used;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
used = size * maxneed / msize;
|
|
|
|
|
if (size * maxneed % msize)
|
|
|
|
|
++used;
|
|
|
|
|
return used;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
matmod(const attrib * a, const unit * u, const resource_type * material, int value)
|
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
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;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/** Use up resources for building an object.
|
2004-04-12 13:00:22 +02:00
|
|
|
|
* 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)
|
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (want<=0) return 0;
|
|
|
|
|
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;
|
|
|
|
|
if (inside_building(u)) {
|
|
|
|
|
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;) {
|
|
|
|
|
int c, n;
|
|
|
|
|
|
|
|
|
|
/* 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 &&
|
|
|
|
|
type->maxsize<=completed)
|
|
|
|
|
{
|
|
|
|
|
completed -= type->maxsize;
|
|
|
|
|
type = type->improvement;
|
|
|
|
|
}
|
|
|
|
|
if (type==NULL) {
|
|
|
|
|
if (made==0) return ECOMPLETE;
|
|
|
|
|
break; /* completed */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Hier ist entweder maxsize == -1, oder completed < maxsize.
|
|
|
|
|
* 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 {
|
|
|
|
|
completed = 0; assert(type->reqsize>=1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (basesk < type->minskill) {
|
|
|
|
|
if (made==0) return ELOWSKILL; /* not good enough to go on */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* n = maximum buildable size */
|
2005-06-13 21:27:11 +02:00
|
|
|
|
if (type->minskill > 1) {
|
2004-10-12 23:05:35 +02:00
|
|
|
|
n = skills / type->minskill;
|
|
|
|
|
} else {
|
|
|
|
|
n = skills;
|
|
|
|
|
}
|
|
|
|
|
/* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische)
|
|
|
|
|
* Talente */
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (want>0) {
|
|
|
|
|
n = min(want, n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type->maxsize>0) {
|
|
|
|
|
n = min(type->maxsize-completed, n);
|
|
|
|
|
if (type->improvement==NULL) {
|
|
|
|
|
want = n;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type->materials) for (c=0;n>0 && type->materials[c].number;c++) {
|
|
|
|
|
resource_t rtype = type->materials[c].type;
|
|
|
|
|
int need;
|
|
|
|
|
int have = get_pooled(u, NULL, rtype);
|
|
|
|
|
int prebuilt;
|
|
|
|
|
int canuse = have;
|
|
|
|
|
if (inside_building(u)) {
|
|
|
|
|
canuse = matmod(u->building->type->attribs, u, oldresourcetype[rtype], canuse);
|
2004-04-12 12:24:01 +02:00
|
|
|
|
#if 0
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/* 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]);
|
|
|
|
|
}
|
2004-04-12 12:24:01 +02:00
|
|
|
|
#endif
|
2004-10-12 23:05:35 +02: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 */
|
|
|
|
|
if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, oldresourcetype[rtype], canuse);
|
|
|
|
|
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 */
|
|
|
|
|
produceexp(u, ctype->skill, min(made, u->number));
|
|
|
|
|
|
|
|
|
|
return made;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
maxbuild(const unit * u, const construction * cons)
|
2004-10-12 23:05:35 +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
|
|
|
|
{
|
2004-10-12 23:05:35 +02: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, u->thisorder, 88, MSG_PRODUCE);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else maximum = min(maximum, have/need);
|
|
|
|
|
}
|
|
|
|
|
return maximum;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** old build routines */
|
|
|
|
|
|
|
|
|
|
void
|
2005-04-30 19:07:46 +02:00
|
|
|
|
build_building(unit * u, const building_type * btype, int want, order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
region * r = u->region;
|
|
|
|
|
boolean newbuilding = false;
|
|
|
|
|
int c, built = 0, id;
|
|
|
|
|
building * b = NULL;
|
|
|
|
|
/* einmalige Korrektur */
|
|
|
|
|
static char buffer[8 + IDSIZE + 1 + NAMESIZE + 1];
|
2005-05-28 09:09:18 +02:00
|
|
|
|
const char * btname;
|
2005-05-22 14:26:19 +02:00
|
|
|
|
order * new_order = NULL;
|
|
|
|
|
const struct locale * lang = u->faction->locale;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
|
|
|
|
if (eff_skill(u, SK_BUILDING, r) == 0) {
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 101, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der
|
|
|
|
|
* betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg
|
|
|
|
|
* 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 */
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 6, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b) btype = b->type;
|
|
|
|
|
|
|
|
|
|
if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype)) {
|
|
|
|
|
/* only one of these per region */
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 93, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
/* units under siege can not build */
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 60, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (btype->flags & BTF_NOBUILD) {
|
|
|
|
|
/* special building, cannot be built */
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 221, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b) built = b->size;
|
|
|
|
|
if (want<=0 || want == INT_MAX) {
|
|
|
|
|
if(b == NULL) {
|
|
|
|
|
if(btype->maxsize > 0) {
|
|
|
|
|
want = btype->maxsize - built;
|
|
|
|
|
} else {
|
|
|
|
|
want = INT_MAX;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if(b->type->maxsize > 0) {
|
|
|
|
|
want = b->type->maxsize - built;
|
|
|
|
|
} else {
|
|
|
|
|
want = INT_MAX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
built = build(u, btype->construction, built, want);
|
|
|
|
|
|
|
|
|
|
switch (built) {
|
|
|
|
|
case ECOMPLETE:
|
|
|
|
|
/* the building is already complete */
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 4, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
case ENOMATERIALS: {
|
|
|
|
|
/* something missing from the list of materials */
|
|
|
|
|
const construction * cons = btype->construction;
|
|
|
|
|
char * ch = buf;
|
|
|
|
|
assert(cons);
|
|
|
|
|
for (c=0;cons->materials[c].number; c++) {
|
|
|
|
|
int n;
|
|
|
|
|
if (c!=0) strcat(ch++, ",");
|
|
|
|
|
n = cons->materials[c].number / cons->reqsize;
|
|
|
|
|
sprintf(ch, " %d %s", n?n:1,
|
2005-05-22 14:26:19 +02:00
|
|
|
|
LOC(lang, resname(cons->materials[c].type, cons->materials[c].number!=1)));
|
2004-10-12 23:05:35 +02:00
|
|
|
|
ch = ch+strlen(ch);
|
|
|
|
|
}
|
2005-04-30 19:07:46 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "build_required",
|
2004-07-11 03:24:12 +02:00
|
|
|
|
"required", buf));
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case ELOWSKILL:
|
|
|
|
|
case ENEEDSKILL:
|
|
|
|
|
/* no skill, or not enough skill points to build */
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 50, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* at this point, the building size is increased. */
|
|
|
|
|
if (b==NULL) {
|
|
|
|
|
/* build a new building */
|
2005-05-22 14:26:19 +02:00
|
|
|
|
b = new_building(btype, r, lang);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
b->type = btype;
|
|
|
|
|
fset(b, BLD_MAINTAINED);
|
|
|
|
|
|
|
|
|
|
/* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */
|
|
|
|
|
leave(r, u);
|
|
|
|
|
u->building = b;
|
|
|
|
|
fset(u, UFL_OWNER);
|
|
|
|
|
|
2005-05-22 14:26:19 +02:00
|
|
|
|
newbuilding = true;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-28 09:09:18 +02:00
|
|
|
|
btname = LOC(lang, btype->_name);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
2005-05-22 14:26:19 +02:00
|
|
|
|
if (want-built <= 0) {
|
|
|
|
|
/* geb<65>ude fertig */
|
2005-05-28 09:09:18 +02:00
|
|
|
|
strcpy(buffer, LOC(lang, "defaultorder"));
|
2005-05-22 14:26:19 +02:00
|
|
|
|
new_order = parse_order(buffer, lang);
|
|
|
|
|
} else if (want!=INT_MAX) {
|
|
|
|
|
/* reduzierte restgr<67><72>e */
|
|
|
|
|
sprintf(buffer, "%s %d %s %s", LOC(lang, keywords[K_MAKE]), want-built, btname, buildingid(b));
|
|
|
|
|
new_order = parse_order(buffer, lang);
|
|
|
|
|
} else if (btname) {
|
|
|
|
|
/* Neues Haus, Befehl mit Geb<65>udename */
|
|
|
|
|
sprintf(buffer, "%s %s %s", LOC(lang, keywords[K_MAKE]), btname, buildingid(b));
|
|
|
|
|
new_order = parse_order(buffer, u->faction->locale);
|
|
|
|
|
}
|
2005-04-30 19:07:46 +02:00
|
|
|
|
|
2005-05-22 14:26:19 +02:00
|
|
|
|
if (new_order) {
|
2005-04-30 19:07:46 +02:00
|
|
|
|
#ifdef LASTORDER
|
2005-05-22 14:26:19 +02:00
|
|
|
|
set_order(&u->lastorder, new_order);
|
2005-04-30 19:07:46 +02:00
|
|
|
|
#else
|
2005-05-22 14:26:19 +02:00
|
|
|
|
replace_order(&u->orders, ord, new_order);
|
|
|
|
|
free_order(new_order);
|
2005-05-10 00:30:43 +02:00
|
|
|
|
#endif
|
2005-05-22 14:26:19 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
b->size += built;
|
|
|
|
|
update_lighthouse(b);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-05-09 22:29:27 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("buildbuilding",
|
|
|
|
|
"building unit size", b, u, built));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
build_ship(unit * u, ship * sh, int want)
|
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
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;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
if (want > 0) can = min(want, can);
|
|
|
|
|
can = min(can, construction->maxsize+sh->damage); /* 100% bauen + 100% reparieren */
|
2004-01-24 00:27:16 +01:00
|
|
|
|
#endif
|
2004-10-12 23:05:35 +02:00
|
|
|
|
int can = build(u, construction, size, want);
|
|
|
|
|
|
|
|
|
|
if ((n=construction->maxsize - sh->size)>0 && can>0) {
|
|
|
|
|
if (can>=n) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-09 22:29:27 +02:00
|
|
|
|
if (n) ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_message("buildship", "ship unit size", sh, u, n));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2005-04-30 19:07:46 +02:00
|
|
|
|
create_ship(region * r, unit * u, const struct ship_type * newtype, int want, order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
static char buffer[IDSIZE + 2 * KEYWORDSIZE + 3];
|
|
|
|
|
ship *sh;
|
|
|
|
|
int msize;
|
|
|
|
|
const construction * cons = newtype->construction;
|
2005-04-30 19:07:46 +02:00
|
|
|
|
order * new_order;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
|
|
|
|
if (!eff_skill(u, SK_SHIPBUILDING, r)) {
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 100, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (besieged(u)) {
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 60, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
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);
|
2005-04-30 19:07:46 +02:00
|
|
|
|
mistake(u, ord, buf, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msize = maxbuild(u, cons);
|
|
|
|
|
if (msize==0) {
|
2005-04-30 19:07:46 +02:00
|
|
|
|
cmistake(u, ord, 88, MSG_PRODUCE);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (want>0) want = min(want, msize);
|
|
|
|
|
else want = msize;
|
|
|
|
|
|
|
|
|
|
sh = new_ship(newtype, u->faction->locale, r);
|
|
|
|
|
|
|
|
|
|
leave(r, u);
|
|
|
|
|
u->ship = sh;
|
|
|
|
|
fset(u, UFL_OWNER);
|
|
|
|
|
sprintf(buffer, "%s %s %s",
|
2004-06-21 18:45:27 +02:00
|
|
|
|
locale_string(u->faction->locale, keywords[K_MAKE]), locale_string(u->faction->locale, parameters[P_SHIP]), shipid(sh));
|
2005-04-30 19:07:46 +02:00
|
|
|
|
|
|
|
|
|
new_order = parse_order(buffer, u->faction->locale);
|
|
|
|
|
#ifdef LASTORDER
|
|
|
|
|
set_order(&u->lastorder, new_order);
|
|
|
|
|
#else
|
2005-05-22 14:26:19 +02:00
|
|
|
|
replace_order(&u->orders, ord, new_order);
|
2005-04-30 19:07:46 +02:00
|
|
|
|
free_order(new_order);
|
2005-05-10 00:30:43 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
build_ship(u, sh, want);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
continue_ship(region * r, unit * u, int want)
|
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
const construction * cons;
|
|
|
|
|
ship *sh;
|
|
|
|
|
int msize;
|
|
|
|
|
|
|
|
|
|
if (!eff_skill(u, SK_SHIPBUILDING, r)) {
|
|
|
|
|
cmistake(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, 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, 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, u->thisorder, 88, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (want > 0) want = min(want, msize);
|
|
|
|
|
else want = msize;
|
|
|
|
|
|
|
|
|
|
build_ship(u, sh, want);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
unit *u2;
|
|
|
|
|
if (fval(b, BLD_UNGUARDED)) return true;
|
|
|
|
|
u2 = buildingowner(r, b);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
if (u2==NULL || ucontact(u2, u)
|
|
|
|
|
|| alliedunit(u2, u->faction, HELP_GUARD)) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02: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
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
unit *u2 = shipowner(sh);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
remove_contacts(void)
|
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int
|
|
|
|
|
leave_cmd(unit * u, struct order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region * r = u->region;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (r->terrain == T_OCEAN && u->ship) {
|
|
|
|
|
if(!fval(u->race, RCF_SWIM)) {
|
|
|
|
|
cmistake(u, ord, 11, MSG_MOVE);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if(get_item(u, I_HORSE)) {
|
|
|
|
|
cmistake(u, ord, 231, MSG_MOVE);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!slipthru(r, u, u->building)) {
|
|
|
|
|
sprintf(buf, "%s wird belagert.", buildingname(u->building));
|
|
|
|
|
mistake(u, ord, buf, MSG_MOVE);
|
|
|
|
|
} else {
|
|
|
|
|
leave(r, u);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-11-25 16:30:51 +01:00
|
|
|
|
static boolean
|
2004-06-21 18:45:27 +02:00
|
|
|
|
entership(unit * u, ship * sh, struct order * ord, boolean lasttry)
|
2002-11-25 16:30:51 +01:00
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/* 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, ord, 233, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sh) {
|
|
|
|
|
if (lasttry) cmistake(u, ord, 20, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (sh==u->ship) return true;
|
|
|
|
|
if (!mayboard(u, sh)) {
|
|
|
|
|
if (lasttry) cmistake(u, ord, 34, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (CheckOverload()) {
|
|
|
|
|
int sweight, scabins;
|
|
|
|
|
int mweight = shipcapacity(sh);
|
|
|
|
|
int mcabins = sh->type->cabins;
|
|
|
|
|
if (mweight>0 && mcabins>0) {
|
|
|
|
|
getshipweight(sh, &sweight, &scabins);
|
|
|
|
|
sweight += weight(u);
|
|
|
|
|
scabins += u->number;
|
2005-04-17 20:24:25 +02:00
|
|
|
|
sweight = ((sweight+99) / 100) * 100; /* Silberreste aufrunden */
|
2004-10-12 23:05:35 +02:00
|
|
|
|
|
|
|
|
|
if (sweight > mweight || scabins > mcabins) {
|
|
|
|
|
if (lasttry) cmistake(u, ord, 34, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave(u->region, u);
|
|
|
|
|
u->ship = sh;
|
|
|
|
|
|
|
|
|
|
if (shipowner(sh) == 0) {
|
|
|
|
|
fset(u, UFL_OWNER);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2002-11-25 16:30:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
{
|
2004-10-12 23:05:35 +02:00
|
|
|
|
region *r;
|
|
|
|
|
ship *sh;
|
|
|
|
|
building *b;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
/* lasttry: Fehler nur im zweiten Versuch melden. Sonst konfus. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
unit *u;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-10-12 23:05:35 +02:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
order * ord;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
for (ord = u->orders; ord; ord = ord->next) {
|
|
|
|
|
switch (get_keyword(ord)) {
|
|
|
|
|
case K_CONTACT:
|
|
|
|
|
contact_cmd(u, ord, lasttry);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
order ** ordp = &u->orders;
|
|
|
|
|
while (*ordp) {
|
|
|
|
|
order * ord = *ordp;
|
|
|
|
|
if (get_keyword(ord) == K_ENTER) {
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
2004-10-12 23:05:35 +02:00
|
|
|
|
switch (getparam(u->faction->locale)) {
|
|
|
|
|
case P_BUILDING:
|
|
|
|
|
case P_GEBAEUDE:
|
|
|
|
|
/* 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){
|
|
|
|
|
if (lasttry) cmistake(u, ord, 232, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b = getbuilding(r);
|
|
|
|
|
|
|
|
|
|
if (!b) {
|
|
|
|
|
if(lasttry) cmistake(u, ord, 6, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* Geb<65>ude auf dem Ozean sollte man betreten d<>rfen
|
|
|
|
|
if(rterrain(r) == T_OCEAN) {
|
|
|
|
|
if (lasttry) cmistake(u, ord, 297, MSG_MOVE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
if (!mayenter(r, u, b)) {
|
|
|
|
|
if(lasttry) {
|
|
|
|
|
sprintf(buf, "Der Eintritt in %s wurde verwehrt",
|
|
|
|
|
buildingname(b));
|
|
|
|
|
mistake(u, ord, buf, MSG_MOVE);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!slipthru(r, u, b)) {
|
|
|
|
|
if(lasttry) {
|
|
|
|
|
sprintf(buf, "%s wird belagert", buildingname(b));
|
|
|
|
|
mistake(u, ord, 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. */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
*ordp = ord->next;
|
2004-06-27 14:19:58 +02:00
|
|
|
|
ord->next = NULL;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
free_order(ord);
|
2004-10-12 23:05:35 +02:00
|
|
|
|
leave(r, u);
|
|
|
|
|
u->building = b;
|
|
|
|
|
if (buildingowner(r, b) == 0) {
|
|
|
|
|
fset(u, UFL_OWNER);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case P_SHIP:
|
|
|
|
|
sh = getship(r);
|
|
|
|
|
entership(u, sh, ord, lasttry);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if (lasttry) cmistake(u, ord, 79, MSG_MOVE);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (*ordp==ord) ordp = &ord->next;
|
2004-10-12 23:05:35 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|