2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
2003-09-21 10:47:28 +02:00
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2003
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#define RESERVE_DONATIONS 1 /* shall we reserve objects given to us by other factions? */
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
#define RESERVE_GIVE 1 /* reserve anything that's given from one unit to another? */
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
#include "economy.h"
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include "randenc.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
#include <ship.h>
|
|
|
|
|
#include <unit.h>
|
|
|
|
|
#include <building.h>
|
|
|
|
|
#include <faction.h>
|
|
|
|
|
#include <plane.h>
|
|
|
|
|
#include <alchemy.h>
|
|
|
|
|
#include <item.h>
|
|
|
|
|
#include <magic.h>
|
|
|
|
|
#include <build.h>
|
|
|
|
|
#include <goodies.h>
|
|
|
|
|
#include <study.h>
|
|
|
|
|
#include <movement.h>
|
|
|
|
|
#include <race.h>
|
|
|
|
|
#include <spy.h>
|
|
|
|
|
#include <build.h>
|
|
|
|
|
#include <pool.h>
|
|
|
|
|
#include <region.h>
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include <resources.h>
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
#include <unit.h>
|
|
|
|
|
#include <skill.h>
|
|
|
|
|
#include <message.h>
|
|
|
|
|
#include <reports.h>
|
|
|
|
|
#include <karma.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-02-10 11:40:12 +01:00
|
|
|
|
/* gamecode includes */
|
|
|
|
|
#include "laws.h"
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* util includes */
|
|
|
|
|
#include <attrib.h>
|
2001-02-03 14:45:35 +01:00
|
|
|
|
#include <base36.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <event.h>
|
2001-05-20 23:47:56 +02:00
|
|
|
|
#include <util/message.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* libs includes */
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
|
|
#include <attributes/reduceproduction.h>
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
#include <attributes/racename.h>
|
|
|
|
|
#include <attributes/orcification.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
|
|
|
|
# include <items/seed.h>
|
|
|
|
|
#endif
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* - static global symbols ------------------------------------- */
|
|
|
|
|
typedef struct spende {
|
|
|
|
|
struct spende *next;
|
|
|
|
|
struct faction *f1, *f2;
|
|
|
|
|
struct region *region;
|
|
|
|
|
int betrag;
|
|
|
|
|
} spende;
|
|
|
|
|
static spende *spenden;
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
static request workers[1024];
|
|
|
|
|
static request *nextworker;
|
|
|
|
|
static int working;
|
|
|
|
|
|
|
|
|
|
static request entertainers[1024];
|
|
|
|
|
static request *nextentertainer;
|
|
|
|
|
static int entertaining;
|
|
|
|
|
|
|
|
|
|
static int norders;
|
|
|
|
|
static request *oa;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2003-09-21 09:40:16 +02:00
|
|
|
|
giverestriction(void) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int value = -1;
|
|
|
|
|
if (value<0) {
|
|
|
|
|
value = atoi(get_param(global.parameters, "GiveRestriction"));
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
income(const unit * u)
|
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
switch(old_race(u->race)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case RC_FIREDRAGON:
|
|
|
|
|
return 150 * u->number;
|
|
|
|
|
case RC_DRAGON:
|
|
|
|
|
return 1000 * u->number;
|
|
|
|
|
case RC_WYRM:
|
|
|
|
|
return 5000 * u->number;
|
|
|
|
|
}
|
|
|
|
|
return 20 * u->number;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
scramble(void *data, int n, size_t width)
|
|
|
|
|
{
|
2004-01-04 19:14:20 +01:00
|
|
|
|
int j;
|
|
|
|
|
char temp[64];
|
|
|
|
|
assert(width<=sizeof(temp));
|
|
|
|
|
for (j=0;j!=n;++j) {
|
|
|
|
|
int k = rand() % n;
|
2004-02-12 15:59:05 +01:00
|
|
|
|
if (k==j) continue;
|
2004-01-04 19:14:20 +01:00
|
|
|
|
memcpy(temp, (char*)data+j*width, width);
|
|
|
|
|
memcpy((char*)data+j*width, (char*)data+k*width, width);
|
|
|
|
|
memcpy((char*)data+k*width, temp, width);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
expandorders(region * r, request * requests)
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
unit *u;
|
|
|
|
|
request *o;
|
|
|
|
|
|
|
|
|
|
/* Alle Units ohne request haben ein -1, alle units mit orders haben ein
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* 0 hier stehen */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next)
|
|
|
|
|
u->n = -1;
|
|
|
|
|
|
|
|
|
|
norders = 0;
|
|
|
|
|
|
|
|
|
|
for (o = requests; o; o = o->next)
|
|
|
|
|
if (o->qty > 0) {
|
|
|
|
|
norders += o->qty;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (norders > 0) {
|
|
|
|
|
oa = (request *) calloc(norders, sizeof(request));
|
|
|
|
|
i = 0;
|
|
|
|
|
for (o = requests; o; o = o->next) {
|
|
|
|
|
if (o->qty > 0) {
|
|
|
|
|
for (j = o->qty; j; j--) {
|
|
|
|
|
oa[i] = *o;
|
|
|
|
|
oa[i].unit->n = 0;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2003-09-21 10:47:28 +02:00
|
|
|
|
scramble(oa, norders, sizeof(request));
|
|
|
|
|
} else {
|
|
|
|
|
oa = NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2003-09-21 10:47:28 +02:00
|
|
|
|
while (requests) {
|
|
|
|
|
request * o = requests->next;
|
|
|
|
|
free(requests);
|
|
|
|
|
requests = o;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2002-02-16 11:37:18 +01:00
|
|
|
|
static void
|
|
|
|
|
change_level(unit * u, skill_t sk, int bylevel)
|
|
|
|
|
{
|
|
|
|
|
skill * sv = get_skill(u, sk);
|
|
|
|
|
assert(bylevel>0);
|
2002-02-23 17:18:26 +01:00
|
|
|
|
if (sv==0) sv = add_skill(u, sk);
|
|
|
|
|
sk_set(sv, sv->level+bylevel);
|
2002-02-16 11:37:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static void
|
|
|
|
|
expandrecruit(region * r, request * recruitorders)
|
|
|
|
|
{
|
|
|
|
|
/* Rekrutierung */
|
|
|
|
|
|
2002-02-10 17:04:39 +01:00
|
|
|
|
int i, n, p = rpeasants(r), h = rhorses(r), uruks = 0;
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
int rfrac = p / RECRUITFRACTION;
|
|
|
|
|
unit * u;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
expandorders(r, recruitorders);
|
|
|
|
|
if (!norders) return;
|
|
|
|
|
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
for (i = 0, n = 0; i != norders; i++) {
|
|
|
|
|
unit * u = oa[i].unit;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
const race * rc = u->faction->race;
|
|
|
|
|
int recruitcost = rc->recruitcost;
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* check if recruiting is limited.
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* either horses or peasant fraction or not at all */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if ((rc->ec_flags & ECF_REC_UNLIMITED)==0) {
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
/* not unlimited, and everything's gone: */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (rc->ec_flags & ECF_REC_HORSES) {
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
/* recruit from horses if not all gone */
|
|
|
|
|
if (h <= 0) continue;
|
2002-09-02 22:36:12 +02:00
|
|
|
|
} else {
|
|
|
|
|
/* recruit, watch peasants if any space left */
|
2002-02-10 17:04:39 +01:00
|
|
|
|
if (n - (uruks+1)/2 >= rfrac) continue;
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
if (recruitcost) {
|
|
|
|
|
if (get_pooled(oa[i].unit, r, R_SILVER) < recruitcost) continue;
|
|
|
|
|
use_pooled(oa[i].unit, r, R_SILVER, recruitcost);
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if ((rc->ec_flags & ECF_REC_UNLIMITED)==0) {
|
|
|
|
|
if (rc->ec_flags & ECF_REC_HORSES) h--; /* use a horse */
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
else {
|
2002-02-10 17:04:39 +01:00
|
|
|
|
if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) {
|
|
|
|
|
p--; /* use a peasant */
|
2002-09-02 22:36:12 +02:00
|
|
|
|
if (rc == new_race[RC_URUK]) uruks++;
|
2002-02-10 17:04:39 +01:00
|
|
|
|
}
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
n++;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2003-09-21 10:47:28 +02:00
|
|
|
|
/* set_number(u, u->number + 1); */
|
2001-04-26 19:41:06 +02:00
|
|
|
|
u->race = rc;
|
|
|
|
|
u->n++;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
assert(p>=0 && h>=0);
|
2002-02-10 17:04:39 +01:00
|
|
|
|
rsetpeasants(r, p+uruks/2);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsethorses(r, h);
|
|
|
|
|
|
|
|
|
|
free(oa);
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (u->n >= 0) {
|
2002-02-15 17:13:30 +01:00
|
|
|
|
unit * unew;
|
2002-02-18 18:57:27 +01:00
|
|
|
|
if (u->number==0) {
|
|
|
|
|
set_number(u, u->n);
|
|
|
|
|
u->hp = u->n * unit_max_hp(u);
|
|
|
|
|
unew = u;
|
|
|
|
|
} else {
|
|
|
|
|
unew = createunit(r, u->faction, u->n, u->race);
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-15 17:13:30 +01:00
|
|
|
|
if (unew->race == new_race[RC_URUK]) {
|
|
|
|
|
change_level(unew, SK_SWORD, 1);
|
|
|
|
|
change_level(unew, SK_SPEAR, 1);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
if (unew->race->ec_flags & ECF_REC_HORSES) {
|
|
|
|
|
change_level(unew, SK_RIDING, 1);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
i = fspecial(unew->faction, FS_MILITIA);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (i > 0) {
|
2002-08-26 16:16:16 +02:00
|
|
|
|
if (unew->race->bonus[SK_SPEAR] >= 0)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
change_level(unew, SK_SPEAR, i);
|
2002-08-26 16:16:16 +02:00
|
|
|
|
if (unew->race->bonus[SK_SWORD] >= 0)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
change_level(unew, SK_SWORD, i);
|
2002-08-26 16:16:16 +02:00
|
|
|
|
if (unew->race->bonus[SK_LONGBOW] >= 0)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
change_level(unew, SK_LONGBOW, i);
|
2002-08-26 16:16:16 +02:00
|
|
|
|
if (unew->race->bonus[SK_CROSSBOW] >= 0)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
change_level(unew, SK_CROSSBOW, i);
|
2002-08-26 16:16:16 +02:00
|
|
|
|
if (unew->race->bonus[SK_RIDING] >= 0)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
change_level(unew, SK_RIDING, i);
|
2002-08-26 16:16:16 +02:00
|
|
|
|
if (unew->race->bonus[SK_AUSDAUER] >= 0)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
change_level(unew, SK_AUSDAUER, i);
|
|
|
|
|
}
|
|
|
|
|
if (unew!=u) {
|
|
|
|
|
transfermen(unew, u, unew->number);
|
2002-02-16 16:16:31 +01:00
|
|
|
|
destroy_unit(unew);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
if (u->n < u->wants) {
|
2002-08-26 16:16:16 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("recruit",
|
2002-02-16 11:37:18 +01:00
|
|
|
|
"unit region amount want", u, r, u->n, u->wants));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
recruit(region * r, unit * u, strlist * S,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
request ** recruitorders)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
plane * pl;
|
|
|
|
|
request *o;
|
|
|
|
|
int recruitcost;
|
|
|
|
|
|
2002-04-21 09:31:27 +02:00
|
|
|
|
#if GUARD_DISABLES_RECRUIT == 1
|
2002-04-21 19:22:48 +02:00
|
|
|
|
/* this is a very special case because the recruiting unit may be empty
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* at this point and we have to look at the creating unit instead. This
|
|
|
|
|
* is done in cansee, which is called indirectly by is_guarded(). */
|
2002-04-21 09:31:27 +02:00
|
|
|
|
if(is_guarded(r, u, GUARD_RECRUIT)) {
|
|
|
|
|
cmistake(u, S->s, 70, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->faction->race == new_race[RC_INSECT]) {
|
|
|
|
|
if (month_season[month(0)] == 0 && rterrain(r) != T_DESERT) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef INSECT_POTION
|
|
|
|
|
boolean usepotion = false;
|
|
|
|
|
unit *u2;
|
|
|
|
|
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u2, UFL_WARMTH)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
usepotion = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (!usepotion)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2003-09-21 10:47:28 +02:00
|
|
|
|
{
|
|
|
|
|
cmistake(u, S->s, 98, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* in Gletschern, Eisbergen gar nicht rekrutieren */
|
|
|
|
|
if (r_insectstalled(r)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 97, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (is_cursed(r->attribs, C_RIOT, 0)) {
|
|
|
|
|
/* Die Region befindet sich in Aufruhr */
|
|
|
|
|
cmistake(u, S->s, 237, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-10 17:04:39 +01:00
|
|
|
|
#if RACE_ADJUSTMENTS
|
|
|
|
|
if (fval(r, RF_ORCIFIED) && u->faction->race != new_race[RC_URUK] &&
|
|
|
|
|
#else
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (fval(r, RF_ORCIFIED) && u->faction->race != new_race[RC_ORC] &&
|
2002-02-10 17:04:39 +01:00
|
|
|
|
#endif
|
2003-09-21 10:47:28 +02:00
|
|
|
|
!(u->faction->race->ec_flags & ECF_REC_HORSES)) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
cmistake(u, S->s, 238, MSG_EVENT);
|
|
|
|
|
return;
|
2003-09-21 10:47:28 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-02-10 17:04:39 +01:00
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
recruitcost = u->faction->race->recruitcost;
|
|
|
|
|
if (recruitcost) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
pl = getplane(r);
|
|
|
|
|
if (pl && fval(pl, PFL_NORECRUITS)) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
add_message(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "error_pflnorecruit", ""));
|
2002-04-21 19:22:48 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (get_pooled(u, r, R_SILVER) < recruitcost) {
|
|
|
|
|
cmistake(u, S->s, 142, MSG_EVENT);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2003-09-21 10:47:28 +02:00
|
|
|
|
}
|
|
|
|
|
if (!playerrace(u->race) || idle(u->faction)) {
|
|
|
|
|
cmistake(u, S->s, 139, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* snotlinge sollten hiermit bereits abgefangen werden, die
|
|
|
|
|
* parteirasse ist uruk oder ork*/
|
|
|
|
|
if (u->race != u->faction->race) {
|
|
|
|
|
if (u->number != 0) {
|
|
|
|
|
cmistake(u, S->s, 139, MSG_EVENT);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2003-09-21 10:47:28 +02:00
|
|
|
|
else u->race = u->faction->race;
|
|
|
|
|
}
|
|
|
|
|
n = geti();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (has_skill(u, SK_MAGIC)) {
|
|
|
|
|
/* error158;de;{unit} in {region}: '{command}' - Magier arbeiten
|
|
|
|
|
* grunds<EFBFBD>tzlich nur alleine! */
|
|
|
|
|
cmistake(u, S->s, 158, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (has_skill(u, SK_ALCHEMY)
|
|
|
|
|
&& count_skill(u->faction, SK_ALCHEMY) + n >
|
|
|
|
|
max_skill(u->faction, SK_ALCHEMY))
|
|
|
|
|
{
|
|
|
|
|
cmistake(u, S->s, 156, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (recruitcost) n = min(n, get_pooled(u, r, R_SILVER) / recruitcost);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
u->wants = n;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (!n) {
|
|
|
|
|
cmistake(u, S->s, 142, MSG_EVENT);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
return;
|
2003-09-21 10:47:28 +02:00
|
|
|
|
}
|
|
|
|
|
o = (request *) calloc(1, sizeof(request));
|
|
|
|
|
o->qty = n;
|
|
|
|
|
o->unit = u;
|
|
|
|
|
addlist(recruitorders, o);
|
|
|
|
|
|
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
count_max_migrants(faction * f)
|
|
|
|
|
{
|
|
|
|
|
int x = (int)(log10(count_all(f) / 50.0) * 20);
|
|
|
|
|
return max(0, x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern const char* resname(resource_t res, int i);
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_give(unit * u, unit * u2, int n, const resource_type * rtype, const char * cmd, int error)
|
|
|
|
|
{
|
|
|
|
|
if (error)
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
cmistake(u, cmd, error, MSG_COMMERCE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else if (!u2 || u2->faction!=u->faction) {
|
|
|
|
|
assert(rtype);
|
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_message("give", "unit target resource amount",
|
|
|
|
|
u, u2?ucansee(u->faction, u2, u_unknown()):u_peasants(), rtype, n));
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
if (u2) {
|
|
|
|
|
add_message(&u2->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_message("give", "unit target resource amount",
|
|
|
|
|
ucansee(u2->faction, u, u_unknown()), u2, rtype, n));
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
addgive(unit * u, unit * u2, int n, resource_t res, const char * cmd, int error)
|
|
|
|
|
{
|
|
|
|
|
add_give(u, u2, n, oldresourcetype[res], cmd, error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************/
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Derzeit fallen nur Silber und Pferde an die Region
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
give_peasants(int n, const item_type * itype, unit * src)
|
|
|
|
|
{
|
|
|
|
|
region *r = src->region;
|
|
|
|
|
|
2002-04-28 10:10:17 +02:00
|
|
|
|
/* horses are given to the region via itype->give! */
|
|
|
|
|
|
|
|
|
|
if (itype->rtype==r_silver) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
rsetmoney(r, rmoney(r) + n);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
give_item(int want, const item_type * itype, unit * src, unit * dest, const char * cmd)
|
|
|
|
|
{
|
|
|
|
|
short error = 0;
|
|
|
|
|
int n;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
assert(itype!=NULL);
|
|
|
|
|
n = new_get_pooled(src, item2resource(itype), GET_DEFAULT);
|
|
|
|
|
n = min(want, n);
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (dest && src->faction != dest->faction && src->faction->age < giverestriction()) {
|
2002-08-26 16:16:16 +02:00
|
|
|
|
ADDMSG(&src->faction->msgs, msg_error(src, cmd, "giverestriction",
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"turns", giverestriction()));
|
2002-07-28 11:45:38 +02:00
|
|
|
|
return -1;
|
2002-01-13 11:42:56 +01:00
|
|
|
|
} else if (n == 0) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
error = 36;
|
|
|
|
|
} else if (itype->flags & ITF_CURSED) {
|
|
|
|
|
error = 25;
|
|
|
|
|
} else if (itype->give && !itype->give(src, dest, itype, n, cmd)) {
|
2002-07-28 11:45:38 +02:00
|
|
|
|
return -1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
int use = new_use_pooled(src, item2resource(itype), GET_SLACK, n);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
if (use<n) use += new_use_pooled(src, item2resource(itype), GET_RESERVE|GET_POOLED_SLACK, n-use);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (dest) {
|
|
|
|
|
i_change(&dest->items, itype, n);
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
#if RESERVE_DONATIONS
|
2001-01-25 10:37:55 +01:00
|
|
|
|
new_change_resvalue(dest, item2resource(itype), n);
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
#elif RESERVE_GIVE
|
|
|
|
|
if (src->faction==dest->faction) {
|
|
|
|
|
new_change_resvalue(dest, item2resource(itype), n);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
handle_event(&src->attribs, "give", dest);
|
|
|
|
|
handle_event(&dest->attribs, "receive", src);
|
2002-09-02 22:36:12 +02:00
|
|
|
|
#if defined(MUSEUM_MODULE) && defined(TODO)
|
2002-04-21 19:22:48 +02:00
|
|
|
|
TODO: Einen Trigger benutzen!
|
|
|
|
|
if (a_find(dest->attribs, &at_warden)) {
|
|
|
|
|
/* warden_add_give(src, dest, itype, n); */
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}else{
|
|
|
|
|
/* gib bauern */
|
|
|
|
|
give_peasants(use, itype, src);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
add_give(src, dest, n, item2resource(itype), cmd, error);
|
2002-07-28 11:45:38 +02:00
|
|
|
|
if (error) return -1;
|
2002-07-28 12:32:40 +02:00
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2002-01-13 11:42:56 +01:00
|
|
|
|
givemen(int n, unit * u, unit * u2, const char * cmd)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-01-25 10:16:00 +01:00
|
|
|
|
ship *sh;
|
|
|
|
|
int k = 0;
|
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
|
|
if (u2 && u->faction != u2->faction && u->faction->age < giverestriction()) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_error(u, cmd, "giverestriction",
|
|
|
|
|
"turns", giverestriction()));
|
|
|
|
|
return;
|
|
|
|
|
} else if (u == u2) {
|
|
|
|
|
error = 10;
|
2002-02-10 17:04:39 +01:00
|
|
|
|
#if RACE_ADJUSTMENTS
|
2004-01-25 10:16:00 +01:00
|
|
|
|
} else if (!u2 && u->race == new_race[RC_SNOTLING]) {
|
|
|
|
|
/* Snotlings k<>nnen nicht an Bauern <20>bergeben werden. */
|
|
|
|
|
error = 307;
|
2002-02-10 17:04:39 +01:00
|
|
|
|
#endif
|
2004-01-25 10:16:00 +01:00
|
|
|
|
} else if ((u && unit_has_cursed_item(u)) || (u2 && unit_has_cursed_item(u2))) {
|
|
|
|
|
error = 78;
|
|
|
|
|
} else if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER) || is_cursed(u->attribs, C_SLAVE, 0)) {
|
|
|
|
|
error = 74;
|
|
|
|
|
} else if (u2 && (fval(u2, UFL_LOCKED)|| is_cursed(u2->attribs, C_SLAVE, 0))) {
|
|
|
|
|
error = 75;
|
|
|
|
|
} else if (u2 && u2->faction != u->faction && ucontact(u2, u) == 0) {
|
|
|
|
|
error = 73;
|
|
|
|
|
} else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) {
|
|
|
|
|
error = 158;
|
|
|
|
|
} else if (u2 && fval(u, UFL_WERE) != fval(u2, UFL_WERE)) {
|
|
|
|
|
error = 312;
|
|
|
|
|
} else if (u2 && u2->number!=0 && u2->race != u->race) {
|
|
|
|
|
log_warning(("Partei %s versucht %s an %s zu <20>bergeben.\n",
|
|
|
|
|
itoa36(u->faction->no), u->race->_name[0],
|
|
|
|
|
u2->race->_name[1]));
|
|
|
|
|
error = 139;
|
|
|
|
|
} else {
|
|
|
|
|
if (n > u->number) n = u->number;
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
error = 96;
|
|
|
|
|
} else if (u2 && u->faction != u2->faction) {
|
|
|
|
|
if (u2->faction->newbies + n > MAXNEWBIES) {
|
|
|
|
|
error = 129;
|
|
|
|
|
} else if (u->race != u2->faction->race) {
|
|
|
|
|
if (u2->faction->race != new_race[RC_HUMAN]) {
|
|
|
|
|
error = 120;
|
|
|
|
|
} else if (count_migrants(u2->faction) + n > count_max_migrants(u2->faction)) {
|
|
|
|
|
error = 128;
|
|
|
|
|
}
|
|
|
|
|
else if (teure_talente(u) || teure_talente(u2)) {
|
|
|
|
|
error = 154;
|
|
|
|
|
} else if (u2->number!=0) {
|
|
|
|
|
error = 139;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-25 10:16:00 +01:00
|
|
|
|
if (u2 && (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY))) {
|
|
|
|
|
k = count_skill(u2->faction, SK_ALCHEMY);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-25 10:16:00 +01:00
|
|
|
|
/* Falls die Zieleinheit keine Alchemisten sind, werden sie nun
|
|
|
|
|
* welche. */
|
|
|
|
|
if (!has_skill(u2, SK_ALCHEMY) && has_skill(u, SK_ALCHEMY))
|
|
|
|
|
k += u2->number;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-25 10:16:00 +01:00
|
|
|
|
/* Wenn in eine Alchemisteneinheit Personen verschoben werden */
|
|
|
|
|
if (has_skill(u2, SK_ALCHEMY) && !has_skill(u, SK_ALCHEMY))
|
|
|
|
|
k += n;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-25 10:16:00 +01:00
|
|
|
|
/* Wenn Parteigrenzen <20>berschritten werden */
|
|
|
|
|
if (u2->faction != u->faction)
|
|
|
|
|
k += n;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-25 10:16:00 +01:00
|
|
|
|
/* wird das Alchemistenmaximum ueberschritten ? */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-25 10:16:00 +01:00
|
|
|
|
if (k > max_skill(u2->faction, SK_ALCHEMY)) {
|
|
|
|
|
error = 156;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-01-25 10:16:00 +01:00
|
|
|
|
if (error==0) {
|
|
|
|
|
if (u2 && u2->number == 0) {
|
|
|
|
|
set_racename(&u2->attribs, get_racename(u->attribs));
|
|
|
|
|
u2->race = u->race;
|
|
|
|
|
u2->irace = u->irace;
|
2004-02-01 19:19:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (u2) {
|
2004-01-25 10:16:00 +01:00
|
|
|
|
/* Einheiten von Schiffen k<>nnen nicht NACH in von
|
|
|
|
|
* Nicht-alliierten bewachten Regionen ausf<EFBFBD>hren */
|
|
|
|
|
sh = leftship(u);
|
|
|
|
|
if (sh) set_leftship(u2, sh);
|
|
|
|
|
|
|
|
|
|
transfermen(u, u2, n);
|
|
|
|
|
if (u->faction != u2->faction) {
|
|
|
|
|
u2->faction->newbies += n;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (getunitpeasants) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
#ifdef ORCIFICATION
|
2004-01-25 10:16:00 +01:00
|
|
|
|
if (u->race == new_race[RC_ORC] && !fval(u->region, RF_ORCIFIED)) {
|
|
|
|
|
attrib *a = a_find(u->region->attribs, &at_orcification);
|
|
|
|
|
if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification));
|
|
|
|
|
a->data.i += n;
|
|
|
|
|
}
|
2003-09-21 10:47:28 +02:00
|
|
|
|
#endif
|
2004-01-25 10:16:00 +01:00
|
|
|
|
transfermen(u, NULL, n);
|
|
|
|
|
} else {
|
|
|
|
|
error = 159;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
addgive(u, u2, n, R_PERSON, cmd, error);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
giveunit(region * r, unit * u, unit * u2, strlist * S)
|
|
|
|
|
{
|
|
|
|
|
int n = u->number;
|
|
|
|
|
|
|
|
|
|
if ((u && unit_has_cursed_item(u)) || (u2 && unit_has_cursed_item(u2))) {
|
|
|
|
|
cmistake(u, S->s, 78, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 74, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (u2 == NULL) {
|
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
|
|
|
|
cmistake(u, S->s, 152, MSG_COMMERCE);
|
|
|
|
|
} else if (getunitpeasants) {
|
|
|
|
|
unit *u3;
|
|
|
|
|
|
|
|
|
|
for(u3 = r->units; u3; u3 = u3->next)
|
|
|
|
|
if(u3->faction == u->faction && u != u3) break;
|
|
|
|
|
|
|
|
|
|
if(u3) {
|
|
|
|
|
while (u->items) {
|
|
|
|
|
item * iold = i_remove(&u->items, u->items);
|
|
|
|
|
item * inew = *i_find(&u3->items, iold->type);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (inew==NULL) i_add(&u3->items, iold);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else {
|
|
|
|
|
inew->number += iold->number;
|
|
|
|
|
i_free(iold);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-01-13 11:42:56 +01:00
|
|
|
|
givemen(u->number, u, NULL, S->s);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 153, MSG_COMMERCE);
|
|
|
|
|
} else {
|
2003-03-08 21:57:38 +01:00
|
|
|
|
cmistake(u, S->s, 63, MSG_COMMERCE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ucontact(u2, u) == 0) {
|
|
|
|
|
cmistake(u, S->s, 73, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u->number == 0) {
|
|
|
|
|
cmistake(u, S->s, 105, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u2->faction->newbies + n > MAXNEWBIES) {
|
|
|
|
|
cmistake(u, S->s, 129, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u->race != u2->faction->race) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u2->faction->race != new_race[RC_HUMAN]) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 120, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (count_migrants(u2->faction) + u->number > count_max_migrants(u2->faction)) {
|
|
|
|
|
cmistake(u, S->s, 128, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
if (teure_talente(u)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 154, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-03-03 19:13:08 +01:00
|
|
|
|
if (has_skill(u, SK_MAGIC)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (count_skill(u2->faction, SK_MAGIC) + u->number >
|
2003-09-21 10:47:28 +02:00
|
|
|
|
max_skill(u2->faction, SK_MAGIC))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
cmistake(u, S->s, 155, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u2->faction->magiegebiet != find_magetype(u)) {
|
|
|
|
|
cmistake(u, S->s, 157, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-03-03 19:13:08 +01:00
|
|
|
|
if (has_skill(u, SK_ALCHEMY)
|
2003-09-21 10:47:28 +02:00
|
|
|
|
&& count_skill(u2->faction, SK_ALCHEMY) + u->number >
|
|
|
|
|
max_skill(u2->faction, SK_ALCHEMY))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
cmistake(u, S->s, 156, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
add_give(u, u2, 1, r_unit, S->s, 0);
|
2001-02-10 15:18:01 +01:00
|
|
|
|
u_setfaction(u, u2->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
u2->faction->newbies += n;
|
|
|
|
|
|
|
|
|
|
/* "Ich gebe einer Partei eine Einheit, die den Befehl hat, effektiv
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* alles Silber der Partei an mich zu <EFBFBD>bergeben. Zack, bin ich reich."
|
|
|
|
|
* Bl<EFBFBD>dsinn, da Silberpool nicht auf geben wirkt. Aber Rekrutierungen,
|
|
|
|
|
* teure Talente lernen und Gegenst<EFBFBD>nde erschaffen! Kritisch sind:
|
|
|
|
|
* BIETE, FORSCHEN, KAUFE, LERNE, REKRUTIERE, ZAUBERE,
|
|
|
|
|
* HELFE, PASSWORT, STIRB (Katja)
|
|
|
|
|
* Nat<EFBFBD>rlich wirkt der Silberpool bei gib!
|
|
|
|
|
* Und damit nicht irgendein zuk<EFBFBD>nftiger Befehl vergessen wird,
|
|
|
|
|
* l<EFBFBD>schen wir der Einfachheit halber alle! (Enno).
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* freelist(u->orders);
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* FEHLER! Das darf nicht, weil es auf orders noch pointer geben kann!
|
|
|
|
|
*/
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
while (u->orders) {
|
|
|
|
|
/* dieser code _kennt_ die implementaion von strlists... */
|
|
|
|
|
strlist * o = u->orders;
|
|
|
|
|
u->orders = o->next;
|
|
|
|
|
gc_add(o->s); /* delete it later */
|
2001-05-17 22:24:28 +02:00
|
|
|
|
o->s = NULL;
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-27 21:40:31 +02:00
|
|
|
|
static void
|
2003-07-29 11:48:03 +02:00
|
|
|
|
dogive(region * r, unit * u, strlist * S, int mode)
|
2003-09-21 10:47:28 +02:00
|
|
|
|
/*
|
|
|
|
|
* mode=0: give to any units
|
|
|
|
|
* mode=1: give to other units and peasants only
|
|
|
|
|
* mode=2: give to own units only
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
unit *u2;
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int i, n;
|
|
|
|
|
const item_type * itype;
|
2003-03-09 14:29:01 +01:00
|
|
|
|
int notfound_error = 63;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-04-26 19:41:06 +02:00
|
|
|
|
u2 = getunit(r, u->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
switch (mode) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case 0:
|
|
|
|
|
/* any destination is okay */
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
/* not to myself */
|
|
|
|
|
if (u2 && u2->faction==u->faction) return;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(!"invalid mode for dogive");
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!u2 && !getunitpeasants) {
|
|
|
|
|
cmistake(u, S->s, notfound_error, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Damit Tarner nicht durch die Fehlermeldung enttarnt werden k<>nnen */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (u2 && (!cansee(u->faction,r,u2,0) && !ucontact(u2, u) && !fval(u2, UFL_TAKEALL))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, notfound_error, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-11-25 16:30:51 +01:00
|
|
|
|
if (u == u2) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 8, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
/* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* wirklich einfach. */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (r->planep && fval(r->planep, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 268, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_CONTROL) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!u2) {
|
|
|
|
|
cmistake(u, S->s, notfound_error, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!u->building && !u->ship) {
|
|
|
|
|
cmistake(u, S->s, 140, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u->building && u2->building != u->building) {
|
|
|
|
|
cmistake(u, S->s, 33, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u->ship && u2->ship != u->ship) {
|
|
|
|
|
cmistake(u, S->s, 32, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (!fval(u, UFL_OWNER)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 49, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!ucontact(u2, u)) {
|
|
|
|
|
cmistake(u, S->s, 40, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2003-07-29 11:48:03 +02:00
|
|
|
|
freset(u, UFL_OWNER);
|
|
|
|
|
fset(u2, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_message("givecommand", "unit receipient", u, u2));
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
if (u->faction != u2->faction) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
ADDMSG(&u2->faction->msgs,
|
|
|
|
|
msg_message("givecommand", "unit receipient",
|
|
|
|
|
ucansee(u2->faction, u, u_unknown()), u2));
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u2 && u2->race == new_race[RC_SPELL]) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, notfound_error, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
/* if ((u->race->ec_flags & NOGIVE) || fval(u,UFL_LOCKED)) {*/
|
2003-06-15 02:01:21 +02:00
|
|
|
|
if (u->race->ec_flags & NOGIVE && u2!=NULL) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_nogive", "race", u->race));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-09-19 14:34:17 +02:00
|
|
|
|
/* sperrt hier auch personen<65>bergaben!
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u2 && !(u2->race->ec_flags & GETITEM)) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_notake", "race", u2->race));
|
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-09-19 14:34:17 +02:00
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* <20>bergabe aller Kr<4B>uter */
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_HERBS) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
boolean given = false;
|
|
|
|
|
if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_nogive", "race", u->race));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-09-19 14:34:17 +02:00
|
|
|
|
if (u2 && !(u2->race->ec_flags & GETITEM)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, S->s, "race_notake", "race", u2->race));
|
2002-09-19 14:34:17 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!u2) {
|
|
|
|
|
if (!getunitpeasants) {
|
|
|
|
|
cmistake(u, S->s, notfound_error, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (u->items) {
|
|
|
|
|
item **itmp=&u->items;
|
|
|
|
|
while (*itmp) {
|
|
|
|
|
const herb_type * htype = resource2herb((*itmp)->type->rtype);
|
|
|
|
|
if (htype && (*itmp)->number>0) {
|
2002-10-27 11:15:07 +01:00
|
|
|
|
/* give_item <20>ndert im fall,das man alles <20>bergibt, die
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* item-liste der unit, darum continue vor pointerumsetzten */
|
|
|
|
|
if (give_item((*itmp)->number, (*itmp)->type, u, u2, S->s)==0) {
|
|
|
|
|
given = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-07-28 11:45:38 +02:00
|
|
|
|
itmp = &(*itmp)->next;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-10-27 09:51:37 +01:00
|
|
|
|
if (!given) cmistake(u, S->s, 38, MSG_COMMERCE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_ZAUBER) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 7, MSG_COMMERCE);
|
|
|
|
|
/* geht nimmer */
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_UNIT) { /* Einheiten uebergeben */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!(u->race->ec_flags & GIVEUNIT)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, S->s, 167, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (u2 && !ucontact(u2, u)) {
|
|
|
|
|
cmistake(u, S->s, 40, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
giveunit(r, u, u2, S);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_ANY) { /* Alle Gegenst<73>nde <20>bergeben */
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char * s = getstrtoken();
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
|
|
|
|
if(u2 && !ucontact(u2, u)) {
|
|
|
|
|
cmistake(u, S->s, 40, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (*s == 0) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_nogive", "race", u->race));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-09-19 14:34:17 +02:00
|
|
|
|
if (u2 && !(u2->race->ec_flags & GETITEM)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, S->s, "race_notake", "race", u2->race));
|
2002-09-19 14:34:17 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* f<>r alle items einmal pr<70>fen, ob wir mehr als von diesem Typ
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* reserviert ist besitzen und diesen Teil dann <EFBFBD>bergeben */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->items) {
|
|
|
|
|
item **itmp=&u->items;
|
|
|
|
|
while (*itmp) {
|
2002-08-26 16:16:16 +02:00
|
|
|
|
if ((*itmp)->number > 0
|
2003-09-21 10:47:28 +02:00
|
|
|
|
&& (*itmp)->number - new_get_resvalue(u, (*itmp)->type->rtype) > 0) {
|
|
|
|
|
n = (*itmp)->number - new_get_resvalue(u, (*itmp)->type->rtype);
|
|
|
|
|
if (give_item(n, (*itmp)->type, u, u2, S->s)==0) continue;
|
|
|
|
|
}
|
|
|
|
|
itmp = &(*itmp)->next;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
i = findparam(s, u->faction->locale);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (i == P_PERSON) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!(u->race->ec_flags & GIVEPERSON)) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_noregroup", "race", u->race));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
n = u->number;
|
2002-01-13 11:42:56 +01:00
|
|
|
|
givemen(n, u, u2, S->s);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_nogive", "race", u->race));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-09-19 14:34:17 +02:00
|
|
|
|
if (u2 && !(u2->race->ec_flags & GETITEM)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, S->s, "race_notake", "race", u2->race));
|
2002-09-19 14:34:17 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
itype = finditemtype(s, u->faction->locale);
|
|
|
|
|
if (itype!=NULL) {
|
|
|
|
|
item * i = *i_find(&u->items, itype);
|
|
|
|
|
if (i!=NULL) {
|
|
|
|
|
n = i->number - new_get_resvalue(u, itype->rtype);
|
|
|
|
|
give_item(n, itype, u, u2, S->s);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = atoip(s); /* n: anzahl */
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
|
|
|
|
if (s == NULL) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
cmistake(u, S->s, 113, MSG_COMMERCE);
|
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (u2 && !ucontact(u2, u)) {
|
|
|
|
|
const resource_type * rtype = findresourcetype(s, u->faction->locale);
|
|
|
|
|
if (rtype==NULL || !fval(rtype, RTF_SNEAK))
|
|
|
|
|
{
|
|
|
|
|
cmistake(u, S->s, 40, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
i = findparam(s, u->faction->locale);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (i == P_PERSON) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!(u->race->ec_flags & GIVEPERSON)) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_noregroup", "race", u->race));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-01-13 11:42:56 +01:00
|
|
|
|
givemen(n, u, u2, S->s);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (u2!=NULL) {
|
|
|
|
|
if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_nogive", "race", u->race));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!(u2->race->ec_flags & GETITEM)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_error(u, S->s, "race_notake", "race", u2->race));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-09-19 14:34:17 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
itype = finditemtype(s, u->faction->locale);
|
|
|
|
|
if (itype!=NULL) {
|
|
|
|
|
give_item(n, itype, u, u2, S->s);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
cmistake(u, S->s, 123, MSG_COMMERCE);
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
forgetskill(unit * u)
|
|
|
|
|
{
|
|
|
|
|
skill_t talent;
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s = getstrtoken();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if ((talent = findskill(s, u->faction->locale)) != NOSKILL) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_message("forget", "unit skill", u, talent));
|
2002-02-10 14:23:30 +01:00
|
|
|
|
set_level(u, talent, 0);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
report_donations(void)
|
|
|
|
|
{
|
|
|
|
|
spende * sp;
|
|
|
|
|
for (sp = spenden; sp; sp = sp->next) {
|
|
|
|
|
region * r = sp->region;
|
|
|
|
|
if (sp->betrag > 0) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
struct message * msg = msg_message("donation",
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"from to amount", sp->f1, sp->f2, sp->betrag);
|
2001-05-20 23:47:56 +02:00
|
|
|
|
r_addmessage(r, sp->f1, msg);
|
|
|
|
|
r_addmessage(r, sp->f2, msg);
|
|
|
|
|
msg_release(msg);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_spende(faction * f1, faction * f2, int betrag, region * r)
|
|
|
|
|
{
|
|
|
|
|
spende *sp;
|
|
|
|
|
|
|
|
|
|
sp = spenden;
|
|
|
|
|
|
|
|
|
|
while (sp) {
|
|
|
|
|
if (sp->f1 == f1 && sp->f2 == f2 && sp->region == r) {
|
|
|
|
|
sp->betrag += betrag;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sp = sp->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sp = calloc(1, sizeof(spende));
|
|
|
|
|
sp->f1 = f1;
|
|
|
|
|
sp->f2 = f2;
|
|
|
|
|
sp->region = r;
|
|
|
|
|
sp->betrag = betrag;
|
|
|
|
|
sp->next = spenden;
|
|
|
|
|
spenden = sp;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static boolean
|
2001-12-10 01:13:39 +01:00
|
|
|
|
maintain(building * b, boolean first)
|
2003-09-21 10:47:28 +02:00
|
|
|
|
/* first==false -> take money from wherever you can */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
region * r = b->region;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
boolean paid = true, work = first;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit * u;
|
|
|
|
|
if (fval(b, BLD_MAINTAINED)) return true;
|
2003-12-14 11:02:29 +01:00
|
|
|
|
if (b->type==NULL || b->type->maintenance==NULL) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (is_cursed(b->attribs, C_NOCOST, 0)) {
|
|
|
|
|
fset(b, BLD_MAINTAINED);
|
2001-02-03 14:45:35 +01:00
|
|
|
|
fset(b, BLD_WORKING);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
u = buildingowner(r, b);
|
|
|
|
|
if (u==NULL) return false;
|
|
|
|
|
for (c=0;b->type->maintenance[c].number;++c) {
|
|
|
|
|
const maintenance * m = b->type->maintenance+c;
|
|
|
|
|
int need = m->number;
|
|
|
|
|
|
|
|
|
|
if (fval(m, MTF_VARIABLE)) need = need * b->size;
|
|
|
|
|
if (u) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* first ist im ersten versuch true, im zweiten aber false! Das
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* bedeutet, das in der Runde in die Region geschafften Resourcen
|
|
|
|
|
* nicht genutzt werden k<EFBFBD>nnen, weil die reserviert sind! */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!first) need -= get_all(u, m->type);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else need -= get_pooled(u, r, m->type);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!first && need > 0) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit * ua;
|
|
|
|
|
for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FL_DH);
|
|
|
|
|
fset(u->faction, FL_DH); /* hat schon */
|
|
|
|
|
for (ua=r->units;ua;ua=ua->next) {
|
2002-09-02 22:36:12 +02:00
|
|
|
|
if (!fval(ua->faction, FL_DH) && (ua->faction == u->faction || alliedunit(ua, u->faction, HELP_MONEY))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
need -= new_get_pooled(ua, oldresourcetype[m->type], GET_SLACK|GET_RESERVE|GET_POOLED_SLACK|GET_POOLED_RESERVE|GET_POOLED_FORCE);
|
|
|
|
|
fset(ua->faction, FL_DH);
|
|
|
|
|
if (need<=0) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (need > 0) {
|
|
|
|
|
if (!fval(m, MTF_VITAL)) work = false;
|
|
|
|
|
else {
|
|
|
|
|
paid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (paid && c>0) {
|
|
|
|
|
/* TODO: wieviel von was wurde bezahlt */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
message * msg;
|
|
|
|
|
if (first) {
|
|
|
|
|
msg = add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_message("maintenance", "unit building", u, b));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
} else {
|
|
|
|
|
msg = add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_message("maintenance_late", "building", b));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2001-05-20 23:47:56 +02:00
|
|
|
|
msg_release(msg);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
fset(b, BLD_MAINTAINED);
|
|
|
|
|
if (work) fset(b, BLD_WORKING);
|
|
|
|
|
for (c=0;b->type->maintenance[c].number;++c) {
|
|
|
|
|
const maintenance * m = b->type->maintenance+c;
|
|
|
|
|
int cost = m->number;
|
|
|
|
|
|
|
|
|
|
if (!fval(m, MTF_VITAL) && !work) continue;
|
|
|
|
|
if (fval(m, MTF_VARIABLE)) cost = cost * b->size;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!first) cost -= new_use_pooled(u, oldresourcetype[m->type], GET_SLACK|GET_RESERVE|GET_POOLED_SLACK|GET_POOLED_RESERVE|GET_POOLED_FORCE, cost);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else cost -= new_use_pooled(u, oldresourcetype[m->type], GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, cost);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!first && cost > 0) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit * ua;
|
|
|
|
|
for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FL_DH);
|
|
|
|
|
fset(u->faction, FL_DH); /* hat schon */
|
|
|
|
|
for (ua=r->units;ua;ua=ua->next) {
|
2002-09-02 22:36:12 +02:00
|
|
|
|
if (!fval(ua->faction, FL_DH) && alliedunit(ua, u->faction, HELP_MONEY)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int give = use_all(ua, m->type, cost);
|
|
|
|
|
if (!give) continue;
|
|
|
|
|
cost -= give;
|
|
|
|
|
fset(ua->faction, FL_DH);
|
|
|
|
|
if (m->type==R_SILVER) add_spende(ua->faction, u->faction, give, r);
|
|
|
|
|
if (cost<=0) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(cost==0);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
message * msg = add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_message("maintenancefail", "unit building", u, b));
|
2001-05-20 23:47:56 +02:00
|
|
|
|
msg_release(msg);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
gebaeude_stuerzt_ein(region * r, building * b)
|
|
|
|
|
{
|
|
|
|
|
unit *u;
|
|
|
|
|
int n, i;
|
|
|
|
|
direction_t d;
|
|
|
|
|
int opfer = 0;
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
int road = 0;
|
|
|
|
|
struct message * msg;
|
|
|
|
|
/*
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"$building($crashed) st<73>rzte ein.$if($road," Beim Einsturz wurde die halbe Stra<EFBFBD>e vernichtet.","")$if($victims,"$int($victims) $if($eq($victims,1),"ist","sind"),"") zu beklagen."
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Falls Karawanserei, Damm oder Tunnel einst<73>rzen, wird die schon
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* gebaute Stra<EFBFBD>e zur H<EFBFBD>lfte vernichtet */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (d=0;d!=MAXDIRECTIONS;++d) if (rroad(r, d) > 0 &&
|
2003-09-21 10:47:28 +02:00
|
|
|
|
(b->type == bt_find("caravan") ||
|
|
|
|
|
b->type == bt_find("dam") ||
|
|
|
|
|
b->type == bt_find("tunnel")))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
rsetroad(r, d, rroad(r, d) / 2);
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
road = 1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (u->building == b) {
|
|
|
|
|
int loss = 0;
|
|
|
|
|
|
2001-02-10 20:24:05 +01:00
|
|
|
|
fset(u->faction, FL_MARK);
|
2003-07-29 11:48:03 +02:00
|
|
|
|
freset(u, UFL_OWNER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
leave(r,u);
|
|
|
|
|
n = u->number;
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
|
if (rand() % 100 >= EINSTURZUEBERLEBEN) {
|
|
|
|
|
++loss;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
scale_number(u, u->number - loss);
|
|
|
|
|
opfer += loss;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road);
|
|
|
|
|
add_message(&r->msgs, msg);
|
2001-02-10 20:24:05 +01:00
|
|
|
|
for (u=r->units; u; u=u->next) {
|
|
|
|
|
faction * f = u->faction;
|
|
|
|
|
if (fval(f, FL_MARK)) {
|
|
|
|
|
freset(u->faction, FL_MARK);
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
add_message(&f->msgs, msg);
|
2001-02-10 20:24:05 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-05-20 23:47:56 +02:00
|
|
|
|
msg_release(msg);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
destroy_building(b);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
maintain_buildings(boolean crash)
|
|
|
|
|
{
|
|
|
|
|
region * r;
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
building **bp = &r->buildings;
|
|
|
|
|
while (*bp) {
|
|
|
|
|
building * b = *bp;
|
|
|
|
|
if (!maintain(b, !crash) && crash) {
|
|
|
|
|
if (rand() % 100 < EINSTURZCHANCE) {
|
|
|
|
|
gebaeude_stuerzt_ein(r, b);
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
unit * u = buildingowner(r, b);
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
struct message * msg = msg_message("nomaintenance", "building", b);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (u) {
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
add_message(&u->faction->msgs, msg);
|
2001-05-20 23:47:56 +02:00
|
|
|
|
r_addmessage(r, u->faction, msg);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bp=&b->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-26 16:16:16 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
economics(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
unit *u;
|
|
|
|
|
strlist *S;
|
|
|
|
|
|
|
|
|
|
/* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle.
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern
|
|
|
|
|
* eintreiben. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) if (r->units) {
|
|
|
|
|
request *recruitorders = NULL;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_DESTROY:
|
|
|
|
|
destroy(r, u, S->s);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_GIVE:
|
|
|
|
|
case K_LIEFERE:
|
2003-09-21 10:47:28 +02:00
|
|
|
|
dogive(r, u, S, 0);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_FORGET:
|
|
|
|
|
forgetskill(u);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* RECRUIT orders */
|
|
|
|
|
|
|
|
|
|
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_RECRUIT) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
recruit(r, u, S, &recruitorders);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (recruitorders) expandrecruit(r, recruitorders);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
2002-08-26 16:16:16 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
manufacture(unit * u, const item_type * itype, int want)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
int skill;
|
|
|
|
|
int minskill = itype->construction->minskill;
|
|
|
|
|
skill_t sk = itype->construction->skill;
|
|
|
|
|
|
|
|
|
|
skill = effskill(u, sk);
|
|
|
|
|
skill = skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION);
|
|
|
|
|
|
|
|
|
|
if (skill < 0) {
|
|
|
|
|
/* an error occured */
|
|
|
|
|
int err = -skill;
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), err, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(want==0)
|
|
|
|
|
want=maxbuild(u, itype->construction);
|
|
|
|
|
|
|
|
|
|
n = build(u, itype->construction, 0, want);
|
|
|
|
|
switch (n) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case ENEEDSKILL:
|
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "skill_needed", "skill", sk));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case ELOWSKILL:
|
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "manufacture_skills", "skill minskill product",
|
|
|
|
|
sk, minskill, itype->rtype, 1));
|
2002-04-21 19:22:48 +02:00
|
|
|
|
return;
|
|
|
|
|
case ENOMATERIALS:
|
|
|
|
|
/* something missing from the list of materials */
|
|
|
|
|
strcpy(buf, "Daf<EFBFBD>r braucht man mindestens:");
|
|
|
|
|
{
|
|
|
|
|
int c, n;
|
|
|
|
|
const construction * cons = itype->construction;
|
|
|
|
|
char * ch = buf+strlen(buf);
|
|
|
|
|
assert(cons);
|
|
|
|
|
for (c=0;cons->materials[c].number; c++) {
|
|
|
|
|
if (c!=0)
|
|
|
|
|
strcat(ch++, ",");
|
|
|
|
|
n=cons->materials[c].number / cons->reqsize;
|
|
|
|
|
sprintf(ch, " %d %s", n?n:1,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
locale_string(u->faction->locale,
|
|
|
|
|
resname(cons->materials[c].type, cons->materials[c].number!=1)));
|
2002-04-21 19:22:48 +02:00
|
|
|
|
ch = ch+strlen(ch);
|
|
|
|
|
}
|
|
|
|
|
mistake(u, findorder(u, u->thisorder), buf, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
if (n>0) {
|
|
|
|
|
i_change(&u->items, itype, n);
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
if (want==INT_MAX) want = n;
|
2002-01-20 12:35:06 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("manufacture",
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"unit region amount wanted resource", u, u->region, n, want, itype->rtype));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct allocation {
|
|
|
|
|
struct allocation * next;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int want, get;
|
|
|
|
|
double save;
|
|
|
|
|
unsigned int flags;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit * unit;
|
|
|
|
|
} allocation;
|
|
|
|
|
#define new_allocation() calloc(sizeof(allocation), 1)
|
|
|
|
|
#define free_allocation(a) free(a)
|
|
|
|
|
|
|
|
|
|
typedef struct allocation_list {
|
|
|
|
|
struct allocation_list * next;
|
|
|
|
|
allocation * data;
|
|
|
|
|
const resource_type * type;
|
|
|
|
|
} allocation_list;
|
|
|
|
|
|
|
|
|
|
static allocation_list * allocations;
|
|
|
|
|
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
allocate_resource(unit * u, const resource_type * rtype, int want)
|
|
|
|
|
{
|
|
|
|
|
const item_type * itype = resource2item(rtype);
|
|
|
|
|
region * r = u->region;
|
|
|
|
|
int busy = u->number;
|
|
|
|
|
int dm = 0;
|
|
|
|
|
allocation_list * alist;
|
|
|
|
|
allocation * al;
|
|
|
|
|
unit *u2;
|
|
|
|
|
int amount, skill;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* momentan kann man keine ressourcen abbauen, wenn man daf<61>r
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Materialverbrauch hat: */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
assert(itype!=NULL && itype->construction->materials==NULL);
|
|
|
|
|
|
|
|
|
|
if (itype == olditemtype[I_WOOD] && fval(r, RF_MALLORN)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 92, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (itype == olditemtype[I_MALLORN] && !fval(r, RF_MALLORN)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 91, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (itype == olditemtype[I_LAEN]) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
struct building * b = inside_building(u);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (btype != bt_find("mine")) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 104, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 60, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Elfen k<>nnen Holzf<7A>llen durch Bewachen verhindern, wenn sie
|
2003-09-21 10:47:28 +02:00
|
|
|
|
die Holzf<EFBFBD>ller sehen. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (itype == olditemtype[I_WOOD] || itype == olditemtype[I_MALLORN]) {
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next) {
|
|
|
|
|
if (getguard(u2) & GUARD_TREES
|
2003-09-21 10:47:28 +02:00
|
|
|
|
&& u2->number
|
|
|
|
|
&& cansee(u2->faction,r,u,0)
|
|
|
|
|
&& !ucontact(u2, u)
|
|
|
|
|
&& !besieged(u2)
|
|
|
|
|
&& !alliedunit(u2, u->faction, HELP_GUARD)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef WACH_WAFF
|
2003-09-21 10:47:28 +02:00
|
|
|
|
&& armedmen(u2)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2003-09-21 10:47:28 +02:00
|
|
|
|
) {
|
|
|
|
|
add_message(&u->faction->msgs,
|
2002-04-21 19:22:48 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "region_guarded", "guard", u2));
|
2003-09-21 10:47:28 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Bergw<67>chter k<>nnen Abbau von Eisen/Laen durch Bewachen verhindern.
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Als magische Wesen 'sehen' Bergw<EFBFBD>chter alles und werden durch
|
|
|
|
|
* Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen).
|
|
|
|
|
*/
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (itype == olditemtype[I_IRON] || itype == olditemtype[I_LAEN])
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next ) {
|
|
|
|
|
if (getguard(u) & GUARD_MINING
|
2003-09-21 10:47:28 +02:00
|
|
|
|
&& !fval(u2, UFL_ISNEW)
|
|
|
|
|
&& u2->number
|
|
|
|
|
&& !ucontact(u2, u)
|
|
|
|
|
&& !alliedunit(u2, u->faction, HELP_GUARD))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "region_guarded", "guard", u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(itype->construction->skill!=0 || "limited resource needs a required skill for making it");
|
|
|
|
|
skill = eff_skill(u, itype->construction->skill, u->region);
|
|
|
|
|
if (skill == 0) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
skill_t sk = itype->construction->skill;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "skill_needed", "skill", sk));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (skill < itype->construction->minskill) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
skill_t sk = itype->construction->skill;
|
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "manufacture_skills", "skill minskill product",
|
|
|
|
|
sk, itype->construction->minskill, itype->rtype));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
struct building * b = inside_building(u);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (itype == olditemtype[I_IRON] && btype == bt_find("mine")) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
++skill;
|
|
|
|
|
}
|
2002-03-27 22:49:27 +01:00
|
|
|
|
else if (itype == olditemtype[I_STONE] && btype == bt_find("quarry")) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
++skill;
|
|
|
|
|
}
|
2002-03-27 22:49:27 +01:00
|
|
|
|
else if (itype == olditemtype[I_WOOD] && btype == bt_find("sawmill")) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
++skill;
|
|
|
|
|
}
|
2002-03-27 22:49:27 +01:00
|
|
|
|
else if (itype == olditemtype[I_MALLORN] && btype == bt_find("sawmill")) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
++skill;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
amount = skill * u->number;
|
|
|
|
|
/* nun ist amount die Gesamtproduktion der Einheit (in punkten) */
|
|
|
|
|
|
|
|
|
|
/* mit Flinkfingerring verzehnfacht sich die Produktion */
|
|
|
|
|
amount += skill * min(u->number, get_item(u,I_RING_OF_NIMBLEFINGER)) * 9;
|
|
|
|
|
|
|
|
|
|
/* Schaffenstrunk: */
|
|
|
|
|
if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) {
|
|
|
|
|
dm = min(dm, u->number);
|
|
|
|
|
change_effect(u, oldpotiontype[P_DOMORE], -dm);
|
|
|
|
|
amount += dm * skill; /* dm Personen produzieren doppelt */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
amount /= itype->construction->minskill;
|
|
|
|
|
|
|
|
|
|
/* Limitierung durch Parameter m. */
|
|
|
|
|
if (want > 0 && want < amount) amount = want;
|
|
|
|
|
|
|
|
|
|
busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */
|
|
|
|
|
|
|
|
|
|
alist = allocations;
|
|
|
|
|
while (alist && alist->type!=rtype) alist = alist->next;
|
|
|
|
|
if (!alist) {
|
|
|
|
|
alist = calloc(sizeof(struct allocation_list), 1);
|
|
|
|
|
alist->next = allocations;
|
|
|
|
|
alist->type = rtype;
|
|
|
|
|
allocations = alist;
|
|
|
|
|
}
|
|
|
|
|
al = new_allocation();
|
|
|
|
|
al->want = amount;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
al->save = 1.0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
al->next = alist->data;
|
|
|
|
|
al->unit = u;
|
|
|
|
|
alist->data = al;
|
|
|
|
|
if (itype==olditemtype[I_IRON]) {
|
|
|
|
|
struct building * b = inside_building(u);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (btype==bt_find("mine"))
|
2001-12-10 01:13:39 +01:00
|
|
|
|
al->save *= 0.5;
|
2003-06-15 10:06:22 +02:00
|
|
|
|
if (u->race == new_race[RC_DWARF]) {
|
2002-02-06 09:06:02 +01:00
|
|
|
|
#if RACE_ADJUSTMENTS
|
2001-12-10 01:13:39 +01:00
|
|
|
|
al->save *= 0.75;
|
|
|
|
|
#else
|
2003-06-15 10:06:22 +02:00
|
|
|
|
al->save *= 0.5;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#endif
|
2003-06-15 10:06:22 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else if (itype==olditemtype[I_STONE]) {
|
|
|
|
|
struct building * b = inside_building(u);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (btype==bt_find("quarry"))
|
2001-12-10 01:13:39 +01:00
|
|
|
|
al->save = al->save*0.5;
|
2002-02-06 09:06:02 +01:00
|
|
|
|
#if RACE_ADJUSTMENTS
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race == new_race[RC_TROLL])
|
|
|
|
|
al->save = al->save*0.75;
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else if (itype==olditemtype[I_MALLORN]) {
|
|
|
|
|
struct building * b = inside_building(u);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (btype==bt_find("sawmill"))
|
2001-12-10 01:13:39 +01:00
|
|
|
|
al->save *= 0.5;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else if (itype==olditemtype[I_WOOD]) {
|
|
|
|
|
struct building * b = inside_building(u);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (btype==bt_find("sawmill"))
|
2001-12-10 01:13:39 +01:00
|
|
|
|
al->save *= 0.5;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
typedef struct allocator {
|
|
|
|
|
const struct resource_type * type;
|
|
|
|
|
void (*allocate)(const struct allocator *, region *, allocation *);
|
|
|
|
|
|
|
|
|
|
struct allocator * next;
|
|
|
|
|
} allocator;
|
|
|
|
|
|
|
|
|
|
static struct allocator * allocators;
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static const allocator *
|
2001-12-10 01:13:39 +01:00
|
|
|
|
get_allocator(const struct resource_type * type)
|
|
|
|
|
{
|
|
|
|
|
const struct allocator * alloc = allocators;
|
|
|
|
|
while (alloc && alloc->type!=type) alloc = alloc->next;
|
|
|
|
|
return alloc;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static allocator *
|
2001-12-10 01:13:39 +01:00
|
|
|
|
make_allocator(const struct resource_type * type, void (*allocate)(const struct allocator *, region *, allocation *))
|
|
|
|
|
{
|
|
|
|
|
allocator * alloc = (allocator *)malloc(sizeof(allocator));
|
|
|
|
|
alloc->type = type;
|
|
|
|
|
alloc->allocate = allocate;
|
|
|
|
|
return alloc;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_allocator(allocator * alloc)
|
|
|
|
|
{
|
|
|
|
|
alloc->next = allocators;
|
|
|
|
|
allocators = alloc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
AFL_DONE = 1<<0,
|
|
|
|
|
AFL_LOWSKILL = 1<<1
|
|
|
|
|
};
|
2001-12-15 13:26:04 +01:00
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static int
|
2001-12-10 01:13:39 +01:00
|
|
|
|
required(int want, double save)
|
|
|
|
|
{
|
|
|
|
|
int norders = (int)(want * save);
|
|
|
|
|
if (norders < want*save) ++norders;
|
|
|
|
|
return norders;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
leveled_allocation(const allocator * self, region * r, allocation * alist)
|
|
|
|
|
{
|
|
|
|
|
const resource_type * rtype = self->type;
|
|
|
|
|
const item_type * itype = resource2item(rtype);
|
|
|
|
|
rawmaterial * rm = rm_get(r, rtype);
|
|
|
|
|
int need;
|
|
|
|
|
boolean first = true;
|
|
|
|
|
|
2003-06-15 10:06:22 +02:00
|
|
|
|
if (rm!=NULL) {
|
|
|
|
|
do {
|
|
|
|
|
int avail = rm->amount;
|
|
|
|
|
int norders = 0;
|
|
|
|
|
allocation * al;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2003-06-15 10:06:22 +02:00
|
|
|
|
if(avail <= 0) {
|
|
|
|
|
for (al=alist;al;al=al->next) {
|
|
|
|
|
al->get = 0;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2003-06-15 10:06:22 +02:00
|
|
|
|
break;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-15 10:06:22 +02:00
|
|
|
|
assert(avail>0);
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) {
|
2003-06-15 10:06:22 +02:00
|
|
|
|
int req = required(al->want-al->get, al->save);
|
|
|
|
|
assert(al->get<=al->want && al->get >= 0);
|
|
|
|
|
if (eff_skill(al->unit, itype->construction->skill, r)
|
2003-09-21 10:47:28 +02:00
|
|
|
|
>= rm->level+itype->construction->minskill-1) {
|
|
|
|
|
if (req) {
|
|
|
|
|
norders += req;
|
|
|
|
|
} else {
|
|
|
|
|
fset(al, AFL_DONE);
|
|
|
|
|
}
|
2003-06-15 10:06:22 +02:00
|
|
|
|
} else {
|
|
|
|
|
fset(al, AFL_DONE);
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (first) fset(al, AFL_LOWSKILL);
|
2003-06-15 10:06:22 +02:00
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2003-06-15 10:06:22 +02:00
|
|
|
|
need = norders;
|
|
|
|
|
|
|
|
|
|
avail = min(avail, norders);
|
|
|
|
|
if (need>0) {
|
|
|
|
|
int use = 0;
|
|
|
|
|
for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) {
|
|
|
|
|
if (avail > 0) {
|
|
|
|
|
int want = required(al->want-al->get, al->save);
|
|
|
|
|
int x = avail*want/norders;
|
|
|
|
|
/* Wenn Rest, dann w<>rfeln, ob ich was bekomme: */
|
|
|
|
|
if (rand() % norders < (avail*want) % norders)
|
|
|
|
|
++x;
|
|
|
|
|
avail -= x;
|
|
|
|
|
use += x;
|
|
|
|
|
norders -= want;
|
|
|
|
|
need -= x;
|
|
|
|
|
al->get = min(al->want, al->get+(int)(x/al->save));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (use) {
|
|
|
|
|
assert(use<=rm->amount);
|
|
|
|
|
rm->type->use(rm, r, use);
|
|
|
|
|
}
|
|
|
|
|
assert(avail==0 || norders==0);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2003-06-15 10:06:22 +02:00
|
|
|
|
first = false;
|
|
|
|
|
} while (need>0);
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
attrib_allocation(const allocator * self, region * r, allocation * alist)
|
|
|
|
|
{
|
|
|
|
|
allocation * al;
|
|
|
|
|
const resource_type * rtype = self->type;
|
|
|
|
|
int avail = 0;
|
|
|
|
|
int norders = 0;
|
|
|
|
|
attrib * a = a_find(rtype->attribs, &at_resourcelimit);
|
|
|
|
|
resource_limit * rdata = (resource_limit*)a->data.v;
|
|
|
|
|
|
|
|
|
|
for (al=alist;al;al=al->next) {
|
|
|
|
|
norders += required(al->want, al->save);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rdata->limit) {
|
|
|
|
|
avail = rdata->limit(r, rtype);
|
|
|
|
|
if (avail < 0) avail = 0;
|
|
|
|
|
}
|
|
|
|
|
else avail = rdata->value;
|
|
|
|
|
|
|
|
|
|
avail = min(avail, norders);
|
|
|
|
|
for (al=alist;al;al=al->next) {
|
|
|
|
|
if (avail > 0) {
|
|
|
|
|
int want = required(al->want, al->save);
|
|
|
|
|
int x = avail*want/norders;
|
|
|
|
|
/* Wenn Rest, dann w<>rfeln, ob ich was bekomme: */
|
|
|
|
|
if (rand() % norders < (avail*want) % norders)
|
|
|
|
|
++x;
|
|
|
|
|
avail -= x;
|
|
|
|
|
norders -= want;
|
|
|
|
|
al->get = min(al->want, (int)(x/al->save));
|
|
|
|
|
if (rdata->use) {
|
2003-03-25 17:20:38 +01:00
|
|
|
|
int use = required(al->get, al->save);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (use) rdata->use(r, rtype, use);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(avail==0 || norders==0);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
split_allocations(region * r)
|
|
|
|
|
{
|
|
|
|
|
allocation_list ** p_alist=&allocations;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
freset(r, RF_DH);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
while (*p_alist) {
|
|
|
|
|
allocation_list * alist = *p_alist;
|
|
|
|
|
const resource_type * rtype = alist->type;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
const allocator * alloc = get_allocator(rtype);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
const item_type * itype = resource2item(rtype);
|
|
|
|
|
allocation ** p_al = &alist->data;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
freset(r, RF_DH);
|
|
|
|
|
alloc->allocate(alloc, r, alist->data);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
while (*p_al) {
|
|
|
|
|
allocation * al = *p_al;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (al->get) {
|
|
|
|
|
assert(itype || !"not implemented for non-items");
|
|
|
|
|
i_change(&al->unit->items, itype, al->get);
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(al->unit, itype->construction->skill, al->unit->number);
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH
|
2001-12-10 01:13:39 +01:00
|
|
|
|
fset(r, RF_DH);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
if (al->want==INT_MAX) al->want = al->get;
|
|
|
|
|
if (fval(al, AFL_LOWSKILL)) {
|
|
|
|
|
add_message(&al->unit->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_message("produce_lowskill", "unit region resource",
|
|
|
|
|
al->unit, al->unit->region, rtype));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
} else {
|
|
|
|
|
add_message(&al->unit->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_message("produce", "unit region amount wanted resource",
|
|
|
|
|
al->unit, al->unit->region, al->get, al->want, rtype));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
*p_al=al->next;
|
|
|
|
|
free_allocation(al);
|
|
|
|
|
}
|
|
|
|
|
*p_alist=alist->next;
|
|
|
|
|
free(alist);
|
|
|
|
|
}
|
|
|
|
|
allocations = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
create_potion(unit * u, const potion_type * ptype, int want)
|
|
|
|
|
{
|
|
|
|
|
int built;
|
|
|
|
|
|
|
|
|
|
if(want==0)
|
|
|
|
|
want=maxbuild(u, ptype->itype->construction);
|
|
|
|
|
built = build(u, ptype->itype->construction, 0, want);
|
|
|
|
|
switch (built) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case ELOWSKILL:
|
|
|
|
|
case ENEEDSKILL:
|
|
|
|
|
/* no skill, or not enough skill points to build */
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 50, MSG_PRODUCE);
|
|
|
|
|
break;
|
|
|
|
|
case ECOMPLETE:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
case ENOMATERIALS:
|
|
|
|
|
/* something missing from the list of materials */
|
|
|
|
|
strcpy(buf, "Daf<EFBFBD>r braucht man mindestens:");
|
|
|
|
|
{
|
|
|
|
|
int c, n;
|
|
|
|
|
const construction * cons = ptype->itype->construction;
|
|
|
|
|
char * ch = buf+strlen(buf);
|
|
|
|
|
assert(cons);
|
|
|
|
|
for (c=0;cons->materials[c].number; c++) {
|
|
|
|
|
if (c!=0)
|
|
|
|
|
strcat(ch++, ",");
|
|
|
|
|
n=cons->materials[c].number / cons->reqsize;
|
|
|
|
|
sprintf(ch, " %d %s", n?n:1,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
locale_string(u->faction->locale,
|
|
|
|
|
resname(cons->materials[c].type, cons->materials[c].number!=1)));
|
2002-04-21 19:22:48 +02:00
|
|
|
|
ch = ch+strlen(ch);
|
|
|
|
|
}
|
|
|
|
|
strcat(ch,".");
|
|
|
|
|
mistake(u, findorder(u, u->thisorder), buf, MSG_PRODUCE);
|
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-04-21 19:22:48 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
i_change(&u->items, ptype->itype, built);
|
|
|
|
|
if (want==INT_MAX) want = built;
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("manufacture",
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"unit region amount wanted resource", u, u->region, built, want, ptype->itype->rtype));
|
2002-04-21 19:22:48 +02:00
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-23 19:13:45 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
create_item(unit * u, const item_type * itype, int want)
|
|
|
|
|
{
|
2002-04-21 19:22:48 +02:00
|
|
|
|
if (fval(itype->rtype, RTF_LIMITED)) {
|
2002-04-23 19:13:45 +02:00
|
|
|
|
#if GUARD_DISABLES_PRODUCTION == 1
|
|
|
|
|
if(is_guarded(u->region, u, GUARD_PRODUCE)) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 70, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
allocate_resource(u, itype->rtype, want);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
} else {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
const potion_type * ptype = resource2potion(itype->rtype);
|
|
|
|
|
if (ptype!=NULL) create_potion(u, ptype, want);
|
2002-03-10 11:09:16 +01:00
|
|
|
|
else if (itype->construction && itype->construction->materials) manufacture(u, itype, want);
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
else cmistake(u, findorder(u, u->thisorder), 125, MSG_PRODUCE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
make(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
const building_type * btype;
|
|
|
|
|
const ship_type * stype;
|
|
|
|
|
param_t p;
|
|
|
|
|
int m;
|
|
|
|
|
const item_type * itype;
|
2003-09-21 10:47:28 +02:00
|
|
|
|
const char *s = getstrtoken();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
m = atoi(s);
|
|
|
|
|
sprintf(buf, "%d", m);
|
|
|
|
|
if (!strcmp(buf, s)) {
|
|
|
|
|
/* first came a want-paramter */
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
} else {
|
|
|
|
|
m = INT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
p = findparam(s, u->faction->locale);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* MACHE TEMP kann hier schon gar nicht auftauchen, weil diese nicht in
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* thisorder abgespeichert werden - und auf den ist getstrtoken() beim
|
|
|
|
|
* aufruf von make geeicht */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
itype = finditemtype(s, u->faction->locale);
|
|
|
|
|
if (itype!=NULL) {
|
|
|
|
|
create_item(u, itype, m);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
if (p == P_ROAD) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
direction_t d;
|
|
|
|
|
if(r->planep && fval(r->planep, PFL_NOBUILD)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 275, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
d = finddirection(getstrtoken(), u->faction->locale);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (d!=NODIRECTION) {
|
|
|
|
|
if(r->planep && fval(r->planep, PFL_NOBUILD)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 94, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
build_road(r, u, m, d);
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
} else cmistake(u, findorder(u, u->thisorder), 71, MSG_PRODUCE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
} else if (p == P_SHIP) {
|
|
|
|
|
if(r->planep && fval(r->planep, PFL_NOBUILD)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 276, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
continue_ship(r, u, m);
|
|
|
|
|
return;
|
2002-04-21 19:22:48 +02:00
|
|
|
|
} else if (p == P_HERBS) {
|
|
|
|
|
herbsearch(r, u, m);
|
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stype = findshiptype(s, u->faction->locale);
|
|
|
|
|
if (stype != NOSHIP) {
|
|
|
|
|
if(r->planep && fval(r->planep, PFL_NOBUILD)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 276, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
create_ship(r, u, stype, m);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
btype = findbuildingtype(s, u->faction->locale);
|
|
|
|
|
if (btype != NOBUILDING) {
|
|
|
|
|
if(r->planep && fval(r->planep, PFL_NOBUILD)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 94, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
build_building(u, btype, m);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 125, MSG_PRODUCE);
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
const attrib_type at_luxuries = {
|
|
|
|
|
"luxuries", NULL, NULL, NULL, NULL, NULL
|
|
|
|
|
};
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
expandbuying(region * r, request * buyorders)
|
|
|
|
|
{
|
|
|
|
|
int max_products;
|
|
|
|
|
unit *u;
|
|
|
|
|
static struct trade {
|
|
|
|
|
const luxury_type * type;
|
|
|
|
|
int number;
|
|
|
|
|
int multi;
|
|
|
|
|
} *trades, *trade;
|
|
|
|
|
static int ntrades=0;
|
|
|
|
|
int i, j;
|
|
|
|
|
const luxury_type * ltype;
|
|
|
|
|
|
|
|
|
|
if (ntrades==0) {
|
|
|
|
|
for (ltype=luxurytypes;ltype;ltype=ltype->next)
|
|
|
|
|
++ntrades;
|
|
|
|
|
trades = gc_add(calloc(sizeof(struct trade), ntrades));
|
|
|
|
|
for (i=0, ltype=luxurytypes;i!=ntrades;++i, ltype=ltype->next)
|
|
|
|
|
trades[i].type = ltype;
|
|
|
|
|
}
|
|
|
|
|
for (i=0;i!=ntrades;++i) {
|
|
|
|
|
trades[i].number = 0;
|
|
|
|
|
trades[i].multi = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!buyorders) return;
|
|
|
|
|
|
|
|
|
|
/* Initialisation. multiplier ist der Multiplikator auf den
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Verkaufspreis. F<EFBFBD>r max_products Produkte kauft man das Produkt zum
|
|
|
|
|
* einfachen Verkaufspreis, danach erh<EFBFBD>ht sich der Multiplikator um 1.
|
|
|
|
|
* counter ist ein Z<EFBFBD>hler, der die gekauften Produkte z<EFBFBD>hlt. money
|
|
|
|
|
* wird f<EFBFBD>r die debug message gebraucht. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
max_products = rpeasants(r) / TRADE_FRACTION;
|
|
|
|
|
|
|
|
|
|
/* Kauf - auch so programmiert, da<64> er leicht erweiterbar auf mehrere
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* G<EFBFBD>ter pro Monat ist. j sind die Befehle, i der Index des
|
|
|
|
|
* gehandelten Produktes. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
expandorders(r, buyorders);
|
|
|
|
|
if (!norders) return;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j != norders; j++) {
|
|
|
|
|
int price, multi;
|
|
|
|
|
ltype = oa[j].type.ltype;
|
|
|
|
|
trade = trades;
|
|
|
|
|
while (trade->type!=ltype) ++trade;
|
|
|
|
|
multi = trade->multi;
|
|
|
|
|
if (trade->number + 1 > max_products) ++multi;
|
|
|
|
|
price = ltype->price * multi;
|
|
|
|
|
|
|
|
|
|
if (get_pooled(oa[j].unit, r, R_SILVER) >= price) {
|
|
|
|
|
unit * u = oa[j].unit;
|
|
|
|
|
|
|
|
|
|
/* litems z<>hlt die G<>ter, die verkauft wurden, u->n das Geld, das
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* verdient wurde. Dies mu<EFBFBD> gemacht werden, weil der Preis st<EFBFBD>ndig sinkt,
|
|
|
|
|
* man sich also das verdiente Geld und die verkauften Produkte separat
|
|
|
|
|
* merken mu<EFBFBD>. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
attrib * a = a_find(u->attribs, &at_luxuries);
|
|
|
|
|
if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries));
|
|
|
|
|
i_change((item**)&a->data.v, ltype->itype, 1);
|
|
|
|
|
i_change(&oa[j].unit->items, ltype->itype, 1);
|
|
|
|
|
use_pooled(u, r, R_SILVER, price);
|
|
|
|
|
if (u->n < 0)
|
|
|
|
|
u->n = 0;
|
|
|
|
|
u->n += price;
|
|
|
|
|
|
|
|
|
|
rsetmoney(r, rmoney(r) + price);
|
|
|
|
|
|
|
|
|
|
/* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* der Preis Multiplikator f<EFBFBD>r das Produkt um den Faktor 1. Der Z<EFBFBD>hler
|
|
|
|
|
* wird wieder auf 0 gesetzt. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (++trade->number > max_products) {
|
|
|
|
|
trade->number = 0;
|
|
|
|
|
++trade->multi;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(oa);
|
|
|
|
|
|
|
|
|
|
/* Ausgabe an Einheiten */
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_luxuries);
|
|
|
|
|
item * itm;
|
|
|
|
|
if (a==NULL) continue;
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"buy%u:unit%i:money", u, u->n));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (itm=(item*)a->data.v; itm; itm=itm->next) {
|
|
|
|
|
if (itm->number) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"buyamount%u:unit%i:amount%X:resource", u, itm->number, itm->type->rtype));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
a_remove(&u->attribs, a);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_trades = {
|
|
|
|
|
"trades",
|
2003-09-21 10:47:28 +02:00
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
buy(region * r, unit * u, request ** buyorders, const char * cmd)
|
|
|
|
|
{
|
|
|
|
|
int n, k;
|
|
|
|
|
request *o;
|
|
|
|
|
attrib * a;
|
|
|
|
|
const item_type * itype = NULL;
|
|
|
|
|
const luxury_type * ltype = NULL;
|
|
|
|
|
if (u->ship && is_guarded(r, u, GUARD_CREWS)) {
|
|
|
|
|
cmistake(u, cmd, 69, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u->ship && is_guarded(r, u, GUARD_CREWS)) {
|
|
|
|
|
cmistake(u, cmd, 69, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* schon daf<EFBFBD>r ausger<EFBFBD>stet, mehrere Produkte zu kaufen. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
n = geti();
|
|
|
|
|
if (!n) {
|
|
|
|
|
cmistake(u, cmd, 26, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
/* Belagerte Einheiten k<>nnen nichts kaufen. */
|
|
|
|
|
cmistake(u, cmd, 60, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race == new_race[RC_INSECT]) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* entweder man ist insekt, oder... */
|
|
|
|
|
if (rterrain(r) != T_SWAMP && rterrain(r) != T_DESERT && !rbuildings(r)) {
|
|
|
|
|
cmistake(u, cmd, 119, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* ...oder in der Region mu<6D> es eine Burg geben. */
|
|
|
|
|
if (!rbuildings(r)) {
|
|
|
|
|
cmistake(u, cmd, 119, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ein H<>ndler kann nur 10 G<>ter pro Talentpunkt handeln. */
|
|
|
|
|
k = u->number * 10 * eff_skill(u, SK_TRADE, r);
|
|
|
|
|
|
|
|
|
|
/* hat der H<>ndler bereits gehandelt, muss die Menge der bereits
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* verkauften/gekauften G<EFBFBD>ter abgezogen werden */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a_find(u->attribs, &at_trades);
|
|
|
|
|
if (!a) {
|
|
|
|
|
a = a_add(&u->attribs, a_new(&at_trades));
|
|
|
|
|
} else {
|
|
|
|
|
k -= a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = min(n, k);
|
|
|
|
|
|
|
|
|
|
if (!n) {
|
|
|
|
|
cmistake(u, cmd, 102, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(n>=0);
|
|
|
|
|
/* die Menge der verkauften G<>ter merken */
|
|
|
|
|
a->data.i += n;
|
|
|
|
|
|
|
|
|
|
itype = finditemtype(getstrtoken(), u->faction->locale);
|
|
|
|
|
if (itype!=NULL) {
|
|
|
|
|
ltype = resource2luxury(itype->rtype);
|
|
|
|
|
if (ltype==NULL) {
|
|
|
|
|
cmistake(u, cmd, 124, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (r_demand(r, ltype)) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, cmd, "luxury_notsold", ""));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
o = (request *) calloc(1, sizeof(request));
|
|
|
|
|
o->type.ltype = ltype; /* sollte immer gleich sein */
|
|
|
|
|
|
|
|
|
|
o->unit = u;
|
|
|
|
|
o->qty = n;
|
|
|
|
|
addlist(buyorders, o);
|
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (n) fset(u, UFL_TRADER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/* Steuers<72>tze in % bei Burggr<67><72>e */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static int tax_per_size[7] =
|
|
|
|
|
{0, 6, 12, 18, 24, 30, 36};
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
expandselling(region * r, request * sellorders)
|
|
|
|
|
{
|
|
|
|
|
int money, price, j, max_products;
|
|
|
|
|
/* int m, n = 0; */
|
|
|
|
|
int maxsize = 0, maxeffsize = 0;
|
|
|
|
|
int taxcollected = 0;
|
|
|
|
|
int hafencollected = 0;
|
|
|
|
|
unit *maxowner = (unit *) NULL;
|
|
|
|
|
building *maxb = (building *) NULL;
|
|
|
|
|
building *b;
|
|
|
|
|
unit *u;
|
|
|
|
|
unit *hafenowner;
|
|
|
|
|
static int *counter;
|
|
|
|
|
static int ncounter = 0;
|
|
|
|
|
|
|
|
|
|
if (ncounter==0) {
|
|
|
|
|
const luxury_type * ltype;
|
|
|
|
|
for (ltype=luxurytypes;ltype;ltype=ltype->next) ++ncounter;
|
|
|
|
|
counter=(int*)gc_add(calloc(sizeof(int), ncounter));
|
|
|
|
|
} else {
|
|
|
|
|
memset(counter, 0, sizeof(int)*ncounter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sellorders) /* NEIN, denn Insekten k<>nnen in || !r->buildings) */
|
|
|
|
|
return; /* S<>mpfen und W<>sten auch so handeln */
|
|
|
|
|
|
|
|
|
|
/* Stelle Eigent<6E>mer der gr<67><72>ten Burg fest. Bekommt Steuern aus jedem
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Verkauf. Wenn zwei Burgen gleicher Gr<EFBFBD><EFBFBD>e bekommt gar keiner etwas. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (b = rbuildings(r); b; b = b->next) {
|
|
|
|
|
if (b->size > maxsize && buildingowner(r, b) != NULL
|
2003-09-21 10:47:28 +02:00
|
|
|
|
&& b->type == bt_find("castle")) {
|
|
|
|
|
maxb = b;
|
|
|
|
|
maxsize = b->size;
|
|
|
|
|
maxowner = buildingowner(r, b);
|
|
|
|
|
} else if (b->size == maxsize && b->type == bt_find("castle")) {
|
|
|
|
|
maxb = (building *) NULL;
|
|
|
|
|
maxowner = (unit *) NULL;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-27 22:49:27 +01:00
|
|
|
|
hafenowner = owner_buildingtyp(r, bt_find("harbour"));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (maxb != (building *) NULL && maxowner != (unit *) NULL) {
|
|
|
|
|
maxeffsize = buildingeffsize(maxb, false);
|
|
|
|
|
if (maxeffsize == 0) {
|
|
|
|
|
maxb = (building *) NULL;
|
|
|
|
|
maxowner = (unit *) NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Die Region muss genug Geld haben, um die Produkte kaufen zu k<>nnen. */
|
|
|
|
|
|
|
|
|
|
money = rmoney(r);
|
|
|
|
|
|
|
|
|
|
/* max_products sind 1/100 der Bev<65>lkerung, falls soviele Produkte
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt.
|
|
|
|
|
* multiplier speichert r->demand f<EFBFBD>r die debug message ab. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
max_products = rpeasants(r) / TRADE_FRACTION;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (max_products <= 0) return;
|
|
|
|
|
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (rterrain(r) == T_DESERT && buildingtype_exists(r, bt_find("caravan"))) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
max_products = rpeasants(r) * 2 / TRADE_FRACTION;
|
|
|
|
|
}
|
|
|
|
|
/* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Runde erweitert werden kann. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
expandorders(r, sellorders);
|
|
|
|
|
if (!norders) return;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j != norders; j++) {
|
|
|
|
|
static const luxury_type * search=NULL;
|
|
|
|
|
const luxury_type * ltype = oa[j].type.ltype;
|
|
|
|
|
int multi = r_demand(r, ltype);
|
|
|
|
|
static int i=-1;
|
|
|
|
|
int use = 0;
|
|
|
|
|
if (search!=ltype) {
|
|
|
|
|
i=0;
|
|
|
|
|
for (search=luxurytypes;search!=ltype;search=search->next) ++i;
|
|
|
|
|
}
|
|
|
|
|
if (counter[i]+1 > max_products && multi > 1) --multi;
|
|
|
|
|
price = ltype->price * multi;
|
|
|
|
|
|
|
|
|
|
if (money >= price) {
|
|
|
|
|
int abgezogenhafen = 0;
|
|
|
|
|
int abgezogensteuer = 0;
|
|
|
|
|
unit * u = oa[j].unit;
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_luxuries);
|
|
|
|
|
if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries));
|
|
|
|
|
i_change((item**)&a->data.v, ltype->itype, 1);
|
|
|
|
|
++use;
|
|
|
|
|
if (u->n < 0)
|
|
|
|
|
u->n = 0;
|
|
|
|
|
|
|
|
|
|
if (hafenowner != NULL) {
|
|
|
|
|
if (hafenowner->faction != u->faction) {
|
|
|
|
|
abgezogenhafen = price / 10;
|
|
|
|
|
hafencollected += abgezogenhafen;
|
|
|
|
|
price -= abgezogenhafen;
|
|
|
|
|
money -= abgezogenhafen;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (maxb != NULL) {
|
|
|
|
|
if (maxowner->faction != u->faction) {
|
|
|
|
|
abgezogensteuer = price * tax_per_size[maxeffsize] / 100;
|
|
|
|
|
taxcollected += abgezogensteuer;
|
|
|
|
|
price -= abgezogensteuer;
|
|
|
|
|
money -= abgezogensteuer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
u->n += price;
|
|
|
|
|
change_money(u, price);
|
|
|
|
|
|
|
|
|
|
/* r->money -= price; --- dies wird eben nicht ausgef<65>hrt, denn die
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Produkte k<EFBFBD>nnen auch als Steuern eingetrieben werden. In der Region
|
|
|
|
|
* wurden Silberst<EFBFBD>cke gegen Luxusg<EFBFBD>ter des selben Wertes eingetauscht!
|
|
|
|
|
* Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt
|
|
|
|
|
* die Nachfrage f<EFBFBD>r das Produkt um 1. Der Z<EFBFBD>hler wird wieder auf 0
|
|
|
|
|
* gesetzt. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (++counter[i] > max_products) {
|
|
|
|
|
int d = r_demand(r, ltype);
|
|
|
|
|
if (d > 1)
|
|
|
|
|
r_setdemand(r, ltype, d-1);
|
|
|
|
|
counter[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (use>0) {
|
|
|
|
|
#ifdef NDEBUG
|
|
|
|
|
new_use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use);
|
|
|
|
|
#else
|
|
|
|
|
/* int i = */ new_use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use);
|
|
|
|
|
/* assert(i==use); */
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(oa);
|
|
|
|
|
|
|
|
|
|
/* Steuern. Hier werden die Steuern dem Besitzer der gr<67><72>ten Burg gegeben. */
|
|
|
|
|
|
|
|
|
|
if (maxowner) {
|
|
|
|
|
if (taxcollected > 0) {
|
|
|
|
|
change_money(maxowner, (int) taxcollected);
|
|
|
|
|
add_income(maxowner, IC_TRADETAX, taxcollected, taxcollected);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
/* sprintf(buf, "%s verdient %d Silber durch den Handel in %s.",
|
2003-09-21 10:47:28 +02:00
|
|
|
|
unitname(maxowner), (int) taxcollected, regionid(r)); */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (hafenowner) {
|
|
|
|
|
if (hafencollected > 0) {
|
|
|
|
|
change_money(hafenowner, (int) hafencollected);
|
|
|
|
|
add_income(hafenowner, IC_TRADETAX, hafencollected, hafencollected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Berichte an die Einheiten */
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_luxuries);
|
|
|
|
|
item * itm;
|
|
|
|
|
if (a==NULL) continue;
|
|
|
|
|
for (itm=(item*)a->data.v; itm; itm=itm->next) {
|
|
|
|
|
if (itm->number) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"sellamount%u:unit%i:amount%X:resource", u, itm->number, itm->type->rtype));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
a_remove(&u->attribs, a);
|
|
|
|
|
add_income(u, IC_TRADE, u->n, u->n);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
sell(region * r, unit * u, request ** sellorders, const char * cmd)
|
|
|
|
|
{
|
|
|
|
|
const item_type * itype;
|
|
|
|
|
const luxury_type * ltype=NULL;
|
|
|
|
|
int n;
|
|
|
|
|
request *o;
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (u->ship && is_guarded(r, u, GUARD_CREWS)) {
|
|
|
|
|
cmistake(u, cmd, 69, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* sellorders sind KEIN array, weil f<>r alle items DIE SELBE resource
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* (das geld der region) aufgebraucht wird. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
s = getstrtoken();
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_ANY) {
|
2002-02-17 09:57:39 +01:00
|
|
|
|
n = rpeasants(r) / TRADE_FRACTION;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (rterrain(r) == T_DESERT && buildingtype_exists(r, bt_find("caravan")))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n *= 2;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (n==0) {
|
|
|
|
|
cmistake(u, cmd, 303, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n = atoi(s);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (n==0) {
|
|
|
|
|
cmistake(u, cmd, 27, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* Belagerte Einheiten k<>nnen nichts verkaufen. */
|
|
|
|
|
|
|
|
|
|
if (besieged(u)) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, cmd, "error60", ""));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* In der Region mu<6D> es eine Burg geben. */
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race == new_race[RC_INSECT]) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (rterrain(r) != T_SWAMP && rterrain(r) != T_DESERT && !rbuildings(r)) {
|
|
|
|
|
cmistake(u, cmd, 119, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (!rbuildings(r)) {
|
|
|
|
|
cmistake(u, cmd, 119, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ein H<>ndler kann nur 10 G<>ter pro Talentpunkt verkaufen. */
|
|
|
|
|
|
|
|
|
|
n = min(n, u->number * 10 * eff_skill(u, SK_TRADE, r));
|
|
|
|
|
|
|
|
|
|
if (!n) {
|
|
|
|
|
cmistake(u, cmd, 54, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
s=getstrtoken();
|
|
|
|
|
itype = finditemtype(s, u->faction->locale);
|
|
|
|
|
if (itype!=NULL) ltype = resource2luxury(itype->rtype);
|
|
|
|
|
if (ltype==NULL) {
|
|
|
|
|
cmistake(u, cmd, 126, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
attrib * a;
|
|
|
|
|
int k, available;
|
|
|
|
|
if (!r_demand(r, ltype)) {
|
|
|
|
|
cmistake(u, cmd, 263, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
available = new_get_pooled(u, itype->rtype, GET_DEFAULT);
|
|
|
|
|
|
|
|
|
|
/* Wenn andere Einheiten das selbe verkaufen, mu<6D> ihr Zeug abgezogen
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* werden damit es nicht zweimal verkauft wird: */
|
2002-04-21 19:22:48 +02:00
|
|
|
|
for (o=*sellorders;o;o=o->next) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (o->type.ltype==ltype && o->unit->faction == u->faction) {
|
|
|
|
|
int fpool = o->qty - new_get_pooled(o->unit, itype->rtype, GET_RESERVE);
|
|
|
|
|
available -= max(0, fpool);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = min(n, available);
|
|
|
|
|
|
|
|
|
|
if (n <= 0) {
|
|
|
|
|
cmistake(u, cmd, 264, MSG_COMMERCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Hier wird request->type verwendet, weil die obere limit durch
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* das silber gegeben wird (region->money), welches f<EFBFBD>r alle
|
|
|
|
|
* (!) produkte als summe gilt, als nicht wie bei der
|
|
|
|
|
* produktion, wo f<EFBFBD>r jedes produkt einzeln eine obere limite
|
|
|
|
|
* existiert, so dass man arrays von orders machen kann. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Ein H<>ndler kann nur 10 G<>ter pro Talentpunkt handeln. */
|
|
|
|
|
k = u->number * 10 * eff_skill(u, SK_TRADE, r);
|
|
|
|
|
|
|
|
|
|
/* hat der H<>ndler bereits gehandelt, muss die Menge der bereits
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* verkauften/gekauften G<EFBFBD>ter abgezogen werden */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a_find(u->attribs, &at_trades);
|
|
|
|
|
if (!a) {
|
|
|
|
|
a = a_add(&u->attribs, a_new(&at_trades));
|
|
|
|
|
} else {
|
|
|
|
|
k -= a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = min(n, k);
|
|
|
|
|
assert(n>=0);
|
|
|
|
|
/* die Menge der verkauften G<>ter merken */
|
|
|
|
|
a->data.i += n;
|
|
|
|
|
o = (request *) calloc(1, sizeof(request));
|
|
|
|
|
o->unit = u;
|
|
|
|
|
o->qty = n;
|
|
|
|
|
o->type.ltype = ltype;
|
|
|
|
|
addlist(sellorders, o);
|
|
|
|
|
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (n) fset(u, UFL_TRADER);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
expandstealing(region * r, request * stealorders)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
expandorders(r, stealorders);
|
|
|
|
|
if (!norders) return;
|
|
|
|
|
|
|
|
|
|
/* F<>r jede unit in der Region wird Geld geklaut, wenn sie Opfer eines
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Beklauen-Orders ist. Jedes Opfer mu<EFBFBD> einzeln behandelt werden.
|
|
|
|
|
*
|
|
|
|
|
* u ist die beklaute unit. oa.unit ist die klauende unit.
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (i = 0; i != norders && oa[i].unit->n <= oa[i].unit->wants; i++) {
|
|
|
|
|
unit *u = findunitg(oa[i].no, r);
|
|
|
|
|
int n = 0;
|
|
|
|
|
if (u && u->region==r) n = get_all(u, R_SILVER);
|
|
|
|
|
#ifndef GOBLINKILL
|
|
|
|
|
if (oa[i].type.goblin) { /* Goblin-Spezialklau */
|
|
|
|
|
int uct = 0;
|
|
|
|
|
unit *u2;
|
|
|
|
|
assert(effskill(oa[i].unit, SK_STEALTH)>=4 || !"this goblin\'s talent is too low");
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next)
|
|
|
|
|
if (u2->faction == u->faction)
|
|
|
|
|
uct += u2->number;
|
|
|
|
|
n -= uct * 2 * MAINTENANCE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (n>10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) {
|
|
|
|
|
/* In Questen nur reduziertes Klauen */
|
|
|
|
|
n = 10;
|
|
|
|
|
}
|
|
|
|
|
if (n > 0) {
|
|
|
|
|
n = min(n, oa[i].unit->wants);
|
|
|
|
|
use_all(u, R_SILVER, n);
|
|
|
|
|
oa[i].unit->n = n;
|
|
|
|
|
change_money(oa[i].unit, n);
|
2003-07-29 11:48:03 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", u, u->region, n));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
add_income(oa[i].unit, IC_STEAL, oa[i].unit->wants, oa[i].unit->n);
|
|
|
|
|
}
|
|
|
|
|
free(oa);
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* ------------------------------------------------------------- */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
plant(region *r, unit *u, int raw)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n, i, skill, planted = 0;
|
|
|
|
|
const herb_type * htype;
|
|
|
|
|
|
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (rherbtype(r) == NULL) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 108, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skill pr<70>fen */
|
|
|
|
|
skill = eff_skill(u, SK_HERBALISM, r);
|
2002-03-09 16:16:35 +01:00
|
|
|
|
htype = rherbtype(r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (skill < 6) {
|
2002-03-06 21:18:37 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "plant_skills",
|
|
|
|
|
"skill minskill product", SK_HERBALISM, 6, htype->itype->rtype, 1));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Wasser des Lebens pr<70>fen */
|
|
|
|
|
if (get_pooled(u, r, R_TREES) == 0) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "resource_missing", "missing",
|
|
|
|
|
oldresourcetype[R_TREES]));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
n = new_get_pooled(u, htype->itype->rtype, GET_DEFAULT);
|
|
|
|
|
/* Kr<4B>uter pr<70>fen */
|
|
|
|
|
if (n==0) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "resource_missing", "missing",
|
|
|
|
|
htype->itype->rtype));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = min(skill*u->number, n);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
n = min(raw, n);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* F<>r jedes Kraut Talent*10% Erfolgschance. */
|
|
|
|
|
for(i = n; i>0; i--) {
|
|
|
|
|
if (rand()%10 < skill) planted++;
|
|
|
|
|
}
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(u, SK_HERBALISM, u->number);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Alles ok. Abziehen. */
|
|
|
|
|
new_use_pooled(u, oldresourcetype[R_TREES], GET_DEFAULT, 1);
|
|
|
|
|
new_use_pooled(u, htype->itype->rtype, GET_DEFAULT, n);
|
|
|
|
|
rsetherbs(r, rherbs(r)+planted);
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"plant%u:unit%r:region%i:amount%X:herb", u, r, planted, htype->itype->rtype));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
planttrees(region *r, unit *u, int raw)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int n, i, skill, planted = 0;
|
|
|
|
|
const item_type * itype;
|
2002-04-21 19:22:48 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-04-21 19:22:48 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Mallornb<6E>ume kann man nur in Mallornregionen z<>chten */
|
|
|
|
|
if (fval(r, RF_MALLORN)) {
|
|
|
|
|
itype = &it_mallornseed;
|
|
|
|
|
} else {
|
|
|
|
|
itype = &it_seed;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Skill pr<70>fen */
|
|
|
|
|
skill = eff_skill(u, SK_HERBALISM, r);
|
|
|
|
|
if (skill < 6) {
|
2002-03-06 21:18:37 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "plant_skills",
|
|
|
|
|
"skill minskill product", SK_HERBALISM, 6, itype->rtype, 1));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2002-03-06 21:18:37 +01:00
|
|
|
|
if (fval(r, RF_MALLORN) && skill < 7 ) {
|
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "plant_skills",
|
|
|
|
|
"skill minskill product", SK_HERBALISM, 7, itype->rtype, 1));
|
2002-03-06 21:18:37 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
n = new_get_pooled(u, itype->rtype, GET_DEFAULT);
|
|
|
|
|
/* Samen pr<70>fen */
|
|
|
|
|
if (n==0) {
|
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "resource_missing", "missing",
|
|
|
|
|
itype->rtype));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */
|
|
|
|
|
n = min(raw, n);
|
|
|
|
|
n = min(skill*u->number, n);
|
|
|
|
|
|
|
|
|
|
/* F<>r jeden Samen Talent*10% Erfolgschance. */
|
|
|
|
|
for(i = n; i>0; i--) {
|
|
|
|
|
if (rand()%10 < skill) planted++;
|
|
|
|
|
}
|
|
|
|
|
rsettrees(r, 0, rtrees(r, 0)+planted);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Alles ok. Abziehen. */
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(u, SK_HERBALISM, u->number);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
new_use_pooled(u, itype->rtype, GET_DEFAULT, n);
|
|
|
|
|
|
2002-08-26 16:16:16 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("plant",
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"unit region amount herb", u, r, planted, itype->rtype));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* z<>chte b<>ume */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
breedtrees(region *r, unit *u, int raw)
|
|
|
|
|
{
|
|
|
|
|
int n, i, skill, planted = 0;
|
|
|
|
|
const item_type * itype;
|
|
|
|
|
int current_season = season(turn);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* B<>ume z<>chten geht nur im Fr<46>hling */
|
|
|
|
|
if (current_season != SEASON_SPRING){
|
|
|
|
|
planttrees(r, u, raw);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-04-21 19:22:48 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Mallornb<6E>ume kann man nur in Mallornregionen z<>chten */
|
|
|
|
|
if (fval(r, RF_MALLORN)) {
|
|
|
|
|
itype = &it_mallornseed;
|
|
|
|
|
} else {
|
|
|
|
|
itype = &it_seed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skill pr<70>fen */
|
|
|
|
|
skill = eff_skill(u, SK_HERBALISM, r);
|
|
|
|
|
if (skill < 12) {
|
2002-03-06 21:18:37 +01:00
|
|
|
|
planttrees(r, u, raw);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
n = new_get_pooled(u, itype->rtype, GET_DEFAULT);
|
|
|
|
|
/* Samen pr<70>fen */
|
|
|
|
|
if (n==0) {
|
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "resource_missing", "missing",
|
|
|
|
|
itype->rtype));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */
|
|
|
|
|
n = min(raw, n);
|
|
|
|
|
n = min(skill*u->number, n);
|
|
|
|
|
|
|
|
|
|
/* F<>r jeden Samen Talent*5% Erfolgschance. */
|
|
|
|
|
for(i = n; i>0; i--) {
|
|
|
|
|
if (rand()%100 < skill*5) planted++;
|
|
|
|
|
}
|
|
|
|
|
rsettrees(r, 1, rtrees(r, 1)+planted);
|
2002-04-21 19:22:48 +02:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Alles ok. Abziehen. */
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(u, SK_HERBALISM, u->number);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
new_use_pooled(u, itype->rtype, GET_DEFAULT, n);
|
|
|
|
|
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"plant%u:unit%r:region%i:amount%X:herb", u, r, planted, itype->rtype));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2002-03-06 21:18:37 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2002-03-06 21:18:37 +01:00
|
|
|
|
pflanze(region *r, unit *u)
|
|
|
|
|
{
|
|
|
|
|
int m;
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2002-03-06 21:18:37 +01:00
|
|
|
|
param_t p;
|
|
|
|
|
const item_type * itype = NULL;
|
|
|
|
|
|
|
|
|
|
/* pflanze [<anzahl>] <parameter> */
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
m = atoi(s);
|
|
|
|
|
sprintf(buf, "%d", m);
|
|
|
|
|
if (!strcmp(buf, s)) {
|
|
|
|
|
/* first came a want-paramter */
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
} else {
|
|
|
|
|
m = INT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!s[0]){
|
|
|
|
|
p = P_ANY;
|
|
|
|
|
} else {
|
|
|
|
|
p = findparam(s, u->faction->locale);
|
|
|
|
|
itype = finditemtype(s, u->faction->locale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p==P_HERBS){
|
|
|
|
|
plant(r, u, m);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#if GROWING_TREES
|
|
|
|
|
else if (p==P_TREES){
|
|
|
|
|
breedtrees(r, u, m);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (itype!=NULL){
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (itype==&it_mallornseed || itype==&it_seed) {
|
2002-03-06 21:18:37 +01:00
|
|
|
|
breedtrees(r, u, m);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* z<>chte pferde */
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
breedhorses(region *r, unit *u)
|
|
|
|
|
{
|
|
|
|
|
int n, c;
|
|
|
|
|
int gezuechtet = 0;
|
|
|
|
|
struct building * b = inside_building(u);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
|
|
|
|
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (btype!=bt_find("stables")) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 122, MSG_PRODUCE);
|
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
if (get_item(u, I_HORSE) < 2) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 107, MSG_PRODUCE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
n = min(u->number * eff_skill(u, SK_HORSE_TRAINING, r), get_item(u, I_HORSE));
|
|
|
|
|
|
|
|
|
|
for (c = 0; c < n; c++) {
|
|
|
|
|
if (rand() % 100 < eff_skill(u, SK_HORSE_TRAINING, r)) {
|
|
|
|
|
change_item(u, I_HORSE, 1);
|
|
|
|
|
gezuechtet++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-06 09:06:02 +01:00
|
|
|
|
if (gezuechtet > 0) {
|
|
|
|
|
produceexp(u, SK_HORSE_TRAINING, u->number);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"raised%u:unit%i:amount", u, gezuechtet));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
zuechte(region *r, unit *u)
|
|
|
|
|
{
|
|
|
|
|
int m;
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
param_t p;
|
|
|
|
|
|
|
|
|
|
/* z<>chte [<anzahl>] <parameter> */
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
m = atoi(s);
|
|
|
|
|
sprintf(buf, "%d", m);
|
|
|
|
|
if (!strcmp(buf, s)) {
|
|
|
|
|
/* first came a want-paramter */
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
} else {
|
|
|
|
|
m = INT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!s[0]){
|
|
|
|
|
p = P_ANY;
|
|
|
|
|
} else {
|
|
|
|
|
p = findparam(s, u->faction->locale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (p) {
|
|
|
|
|
case P_HERBS:
|
|
|
|
|
plant(r, u, m);
|
|
|
|
|
return;
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
case P_TREES:
|
|
|
|
|
breedtrees(r, u, m);
|
|
|
|
|
return;
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#endif
|
2001-12-10 01:13:39 +01:00
|
|
|
|
default:
|
|
|
|
|
breedhorses(r, u);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static const char *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rough_amount(int a, int m)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
int p = (a * 100)/m;
|
|
|
|
|
|
|
|
|
|
if (p < 10) {
|
|
|
|
|
return "sehr wenige";
|
|
|
|
|
} else if (p < 30) {
|
|
|
|
|
return "wenige";
|
|
|
|
|
} else if (p < 60) {
|
|
|
|
|
return "relativ viele";
|
|
|
|
|
} else if (p < 90) {
|
|
|
|
|
return "viele";
|
|
|
|
|
}
|
|
|
|
|
return "sehr viele";
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
research(region *r, unit *u)
|
|
|
|
|
{
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s = getstrtoken();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_HERBS) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (eff_skill(u, SK_HERBALISM, r) < 7) {
|
* möglichen Exploit beseitigt:
GIB xyz EINHEIT
GIB 0 ALLES SILBER
--> ALLE Befehle der übergebenen Einheit werden gelöscht.
* neue Funktion (convenience): ucansee(f, u1, u2)
liefert u1, wenn cansee(f,u1), sonst u2
* neue mistakes eingefügt uns übersetzt
* message bugfix:
u->htisorder kann gelöscht werden (z.b. NACH). Daher muss ein pointer auf
einen befehl in einer message immer auf den u->order Eintrag zeigen, damit er
zeit der auswertung noch existiert.
findorder(u, u->thisorder) tut das. Ist an mehreren Stellen nicht benutzt
worden. assert eingebaut, das das prüft.
* RESERVE_DONATIONS
Gegenstände, die von einer anderen Partei übergeben wurden, werden nicht
reserviert.
* TWOPASS_GIVE:
GIB Befehle werden zuerst an fremde Einheiten, danach in einem zweiten
Durchlauf an eigene Einheiten, ausgeführt.
* msg_message
An einigen messages ausprobiert, ob man die gleiche Message mehreren
Parteien einhängen kann - klappt, spart Speicher.
Allerdings fehlt dazu ein ordentliches memory-management (refcounter)
2001-05-10 07:50:52 +02:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 227, MSG_EVENT);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(u, SK_HERBALISM, u->number);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (rherbs(r) > 0) {
|
|
|
|
|
const herb_type *rht = rherbtype(r);
|
|
|
|
|
|
|
|
|
|
if (rht != NULL) {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"researchherb%u:unit%r:region%s:amount%X:herb", u, r,
|
|
|
|
|
rough_amount(rherbs(r), 100), rht->itype->rtype));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"researchherb_none%u:unit%r:region", u, r));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"researchherb_none%u:unit%r:region", u, r));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
wahrnehmung(region * r, faction * f)
|
|
|
|
|
{
|
|
|
|
|
unit *u;
|
|
|
|
|
int w = 0;
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
magicskillboost
-- implementiert. Kann nur einmal pro Partei verwendet werden, und nur von einem Magier. Müssen wir erklären.
Amulett des wahren Sehens und Ring der Unsichtbarkeit geben lediglich einen Bonus auf Wahrnehmung (+2) und Tarnung (+4).
-- das define war nicht aktiviert
Halblinge haben Armbrustschiessen +0 (statt +1).
-- spearates Rassenfile für WDW
Es gibt spezielle Regeln für Allianzen, und der HELFE und KONTAKTIERE Befehl sind eingeschränkt. Konkret kann kein HELP_FIGHT HELP_GUARD HELP_FSTEALTH HELP_MONEY gegeben werden (die anderen sind erlaubt).
-- mit #defeine ALLIES_ONLY definiert
Jede Allianz kann bis zu 15 Magier und 15 Alchemisten haben. Jede einzelne Partei der Allianz kann dabei nicht mehr als 15/Anzahl_Parteien (aufgerundet) Magier bzw. Alchemisten haben, und die Gesamtsumme darf 15 nicht übersteigen.
-- mit #define ALLIANCE_LIMITS gemacht.
Die Startgeschenke (Personen, Silber, ...) werden pro Allianz, nicht pro Spieler verteilt. Größere Allianzen bekommen also weniger pro Spieler.
-- Nochmal geändert: Die Allianzen kriegen jede 168 Personen zum Start, weil sich das gut aufteilen lässt. Das wird auf 28 Einheiten pro Partei gesplittet, jede Einheit hat eines der Talente, außer der Starteinheit, die hat den magicskillboost. Einige Skills kommen öfter vor als andere, das ist nicht einfach vermeidbar. Sollte aber auch wurscht sein, es geht primär darum, lehren zu können.
Es gibt ein Einheitenlimit von 1000 Einheiten pro Allianz.
-- die Regel sparen wir uns einfach mal.
2003-12-14 22:45:47 +01:00
|
|
|
|
if (u->faction == f) {
|
2003-09-21 10:47:28 +02:00
|
|
|
|
if (eff_skill(u, SK_OBSERVATION, r) > w) {
|
|
|
|
|
w = eff_skill(u, SK_OBSERVATION, r);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return w;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
steal(region * r, unit * u, request ** stealorders)
|
|
|
|
|
{
|
|
|
|
|
int n, i, id;
|
|
|
|
|
boolean goblin = false;
|
|
|
|
|
request * o;
|
|
|
|
|
unit * u2 = NULL;
|
|
|
|
|
faction * f = NULL;
|
|
|
|
|
|
|
|
|
|
if (r->planep && fval(r->planep, PFL_NOATTACK)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 270, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id = read_unitid(u->faction, r);
|
|
|
|
|
u2 = findunitr(r, id);
|
|
|
|
|
|
|
|
|
|
if (u2 && u2->region==u->region) {
|
|
|
|
|
f = u2->faction;
|
|
|
|
|
} else {
|
|
|
|
|
f = dfindhash(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (u2=r->units;u2;u2=u2->next) {
|
|
|
|
|
if (u2->faction == f && cansee(u->faction, r, u2, 0)) break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!u2) {
|
2003-03-08 21:57:38 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 63, MSG_INCOME);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (u2->faction->age < IMMUN_GEGEN_ANGRIFF) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "newbie_immunity_error",
|
|
|
|
|
"turns", IMMUN_GEGEN_ANGRIFF));
|
2002-10-05 16:35:04 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-06 09:28:36 +02:00
|
|
|
|
#ifdef ALLIANCES
|
2002-10-05 16:35:04 +02:00
|
|
|
|
if(u->faction->alliance == u2->faction->alliance) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 47, MSG_INCOME);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-10-06 09:28:36 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
assert(u->region==u2->region);
|
|
|
|
|
if (!can_contact(r, u, u2)) {
|
2002-10-05 16:35:04 +02:00
|
|
|
|
add_message(&u->faction->msgs, msg_error(u, findorder(u, u->thisorder),
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"error60", ""));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-10-05 16:35:04 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n = eff_skill(u, SK_STEALTH, r) - wahrnehmung(r, f);
|
|
|
|
|
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
/* Wahrnehmung == Tarnung */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"stealfail%u:unit%u:target", u, u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u2->faction->msgs, new_message(u2->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"stealdetect%u:unit", u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
add_message(&u2->faction->msgs, new_message(u2->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"thiefdiscover%u:unit%u:target", u, u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"stealfatal%u:unit%u:target", u, u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n = 1;
|
|
|
|
|
goblin = true;
|
|
|
|
|
}
|
|
|
|
|
} else if (n < 0) {
|
|
|
|
|
/* Wahrnehmung > Tarnung */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"stealfatal%u:unit%u:target", u, u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
add_message(&u2->faction->msgs, new_message(u2->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"thiefdiscover%u:unit%u:target", u, u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
} else { /* Goblin-Spezialdiebstahl, Meldung an Beklauten */
|
|
|
|
|
add_message(&u2->faction->msgs, new_message(u2->faction,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
"thiefdiscover%u:unit%u:target", u, u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n = 1;
|
|
|
|
|
goblin = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
n = max(0, n);
|
|
|
|
|
|
|
|
|
|
i = min(u->number, get_item(u,I_RING_OF_NIMBLEFINGER));
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
n *= STEALINCOME * (u->number + i * 9);
|
|
|
|
|
} else {
|
|
|
|
|
n *= u->number * STEALINCOME;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u->wants = n;
|
|
|
|
|
|
|
|
|
|
/* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* guter dieb sein, schliesslich macht man immer noch sehr viel laerm */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
o = (request *) calloc(1, sizeof(request));
|
|
|
|
|
o->unit = u;
|
|
|
|
|
o->qty = 1; /* Betrag steht in u->wants */
|
|
|
|
|
o->no = u2->no;
|
|
|
|
|
o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */
|
|
|
|
|
addlist(stealorders, o);
|
|
|
|
|
|
|
|
|
|
/* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
|
|
|
|
|
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(u, SK_STEALTH, min(n, u->number));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
int
|
2001-12-10 01:13:39 +01:00
|
|
|
|
entertainmoney(const region *r)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
if (is_cursed(r->attribs, C_DEPRESSION, 0)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = rmoney(r) / ENTERTAINFRACTION;
|
|
|
|
|
|
|
|
|
|
if (is_cursed(r->attribs, C_GENEROUS, 0)) {
|
|
|
|
|
n *= get_curseeffect(r->attribs, C_GENEROUS, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
expandentertainment(region * r)
|
|
|
|
|
{
|
|
|
|
|
unit *u;
|
|
|
|
|
int m = entertainmoney(r);
|
|
|
|
|
request *o;
|
|
|
|
|
|
|
|
|
|
for (o = &entertainers[0]; o != nextentertainer; ++o) {
|
|
|
|
|
double part = m / (double) entertaining;
|
|
|
|
|
u = o->unit;
|
|
|
|
|
if (entertaining <= m)
|
|
|
|
|
u->n = o->qty;
|
|
|
|
|
else
|
|
|
|
|
u->n = (int) (o->qty * part);
|
|
|
|
|
change_money(u, u->n);
|
|
|
|
|
rsetmoney(r, rmoney(r) - u->n);
|
|
|
|
|
m -= u->n;
|
|
|
|
|
entertaining -= u->n;
|
|
|
|
|
|
|
|
|
|
/* Nur soviel PRODUCEEXP wie auch tats<74>chlich gemacht wurde */
|
2002-02-06 09:06:02 +01:00
|
|
|
|
produceexp(u, SK_ENTERTAINMENT, min(u->n, u->number));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_income(u, IC_ENTERTAIN, o->qty, u->n);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
entertain(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
int max_e;
|
|
|
|
|
request *o;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
static int entertainbase = 0;
|
|
|
|
|
static int entertainperlevel = 0;
|
|
|
|
|
if (!entertainbase) entertainbase = atoi(get_param(global.parameters, "entertain.base"));
|
|
|
|
|
if (!entertainperlevel) entertainperlevel = atoi(get_param(global.parameters, "entertain.perlevel"));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-12 14:46:16 +02:00
|
|
|
|
if (fval(u, UFL_WERE)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 58, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!effskill(u, SK_ENTERTAINMENT)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 58, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 60, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u->ship && is_guarded(r, u, GUARD_CREWS)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 69, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (is_cursed(r->attribs, C_DEPRESSION, 0)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 28, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
u->wants = u->number * (entertainbase + effskill(u, SK_ENTERTAINMENT) * entertainperlevel);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if ((max_e = geti()) != 0)
|
|
|
|
|
u->wants = min(u->wants,max_e);
|
|
|
|
|
|
|
|
|
|
o = nextentertainer++;
|
|
|
|
|
o->unit = u;
|
|
|
|
|
o->qty = u->wants;
|
|
|
|
|
entertaining += o->qty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
expandwork(region * r)
|
|
|
|
|
{
|
|
|
|
|
int n, earnings;
|
|
|
|
|
/* n: verbleibende Einnahmen */
|
|
|
|
|
/* m: maximale Arbeiter */
|
|
|
|
|
int m = maxworkingpeasants(r);
|
|
|
|
|
int p_wage = wage(r,NULL,false);
|
|
|
|
|
int verdienst = 0;
|
|
|
|
|
request *o;
|
|
|
|
|
|
|
|
|
|
for (o = &workers[0]; o != nextworker; ++o) {
|
|
|
|
|
unit * u = o->unit;
|
|
|
|
|
int workers;
|
|
|
|
|
|
|
|
|
|
if (u->number == 0) continue;
|
|
|
|
|
|
|
|
|
|
if (m>=working) workers = u->number;
|
|
|
|
|
else {
|
|
|
|
|
workers = u->number * m / working;
|
|
|
|
|
if (rand() % working < (u->number * m) % working) workers++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(workers>=0);
|
|
|
|
|
|
|
|
|
|
u->n = workers * wage(u->region, u, false);
|
|
|
|
|
|
|
|
|
|
m -= workers;
|
|
|
|
|
assert(m>=0);
|
|
|
|
|
|
|
|
|
|
change_money(u, u->n);
|
|
|
|
|
working -= o->unit->number;
|
|
|
|
|
add_income(u, IC_WORK, o->qty, u->n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = m * p_wage;
|
|
|
|
|
|
|
|
|
|
/* Der Rest wird von den Bauern verdient. n ist das uebriggebliebene
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Geld. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#if AFFECT_SALARY
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(r->attribs, &at_salary);
|
|
|
|
|
if (a) verdienst = a->data.i;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
earnings = min(n, rpeasants(r) * p_wage) + verdienst;
|
|
|
|
|
/* Mehr oder weniger durch Trank "Riesengrass" oder "Faulobstschnaps" */
|
|
|
|
|
|
|
|
|
|
if (verdienst) {
|
|
|
|
|
sprintf(buf, "%d Bauern verdienen ein Silber %s durch %s.",
|
2003-09-21 10:47:28 +02:00
|
|
|
|
abs(verdienst), (verdienst > 0) ? "mehr" : "weniger",
|
|
|
|
|
(verdienst > 0) ? "Riesengras" : "Faulobstschnaps");
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
rsetmoney(r, rmoney(r) + earnings);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
work(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
request *o;
|
|
|
|
|
int w;
|
|
|
|
|
|
2002-04-12 14:46:16 +02:00
|
|
|
|
if(fval(u, UFL_WERE)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 313, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 60, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (u->ship && is_guarded(r, u, GUARD_CREWS)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 69, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
w = wage(r,u,false);
|
|
|
|
|
u->wants = u->number * w;
|
|
|
|
|
o = nextworker++;
|
|
|
|
|
o->unit = u;
|
|
|
|
|
o->qty = u->number * w;
|
|
|
|
|
working += u->number;
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
static void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
expandtax(region * r, request * taxorders)
|
|
|
|
|
{
|
|
|
|
|
unit *u;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
expandorders(r, taxorders);
|
|
|
|
|
if (!norders) return;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) {
|
|
|
|
|
change_money(oa[i].unit, TAXFRACTION);
|
|
|
|
|
oa[i].unit->n += TAXFRACTION;
|
|
|
|
|
rsetmoney(r, rmoney(r) -TAXFRACTION);
|
|
|
|
|
}
|
|
|
|
|
free(oa);
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next)
|
|
|
|
|
if (u->n >= 0)
|
|
|
|
|
add_income(u, IC_TAX, u->wants, u->n);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
tax(region * r, unit * u, request ** taxorders)
|
|
|
|
|
{
|
|
|
|
|
/* Steuern werden noch vor der Forschung eingetrieben */
|
|
|
|
|
|
|
|
|
|
unit *u2;
|
|
|
|
|
int n;
|
|
|
|
|
request *o;
|
|
|
|
|
int max;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!humanoidrace(u->race) && u->faction != findfaction(MONSTER_FACTION)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 228, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-04-21 19:22:48 +02:00
|
|
|
|
|
2002-04-12 14:46:16 +02:00
|
|
|
|
if (fval(u, UFL_WERE)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 228, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (besieged(u)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 60, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
n = armedmen(u);
|
|
|
|
|
|
|
|
|
|
if (!n) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 48, MSG_INCOME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ((max = geti()) == 0) max = INT_MAX;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (!playerrace(u->race)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
u->wants = min(income(u), max);
|
|
|
|
|
} else {
|
|
|
|
|
u->wants = min(n * eff_skill(u, SK_TAXING, r) * 20, max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u2 = is_guarded(r, u, GUARD_TAX);
|
|
|
|
|
if (u2) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "region_guarded", "guard", u2));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* die einnahmen werden in fraktionen von 10 silber eingeteilt: diese
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* fraktionen werden dann bei eintreiben unter allen eintreibenden
|
|
|
|
|
* einheiten aufgeteilt. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
o = (request *) calloc(1, sizeof(request));
|
|
|
|
|
o->qty = u->wants / TAXFRACTION;
|
|
|
|
|
o->unit = u;
|
|
|
|
|
addlist(taxorders, o);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
produce(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
request *taxorders, *sellorders, *stealorders, *buyorders;
|
|
|
|
|
unit *u;
|
|
|
|
|
int todo;
|
|
|
|
|
|
|
|
|
|
/* das sind alles befehle, die 30 tage brauchen, und die in thisorder
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* stehen! von allen 30-tage befehlen wird einfach der letzte verwendet
|
|
|
|
|
* (dosetdefaults).
|
|
|
|
|
*
|
|
|
|
|
* kaufen vor einnahmequellen. da man in einer region dasselbe produkt
|
|
|
|
|
* nicht kaufen und verkaufen kann, ist die reihenfolge wegen der
|
|
|
|
|
* produkte egal. nicht so wegen dem geld.
|
|
|
|
|
*
|
|
|
|
|
* lehren vor lernen. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
|
|
|
|
|
assert(rmoney(r) >= 0);
|
|
|
|
|
assert(rpeasants(r) >= 0);
|
|
|
|
|
|
|
|
|
|
buyorders = 0;
|
|
|
|
|
sellorders = 0;
|
|
|
|
|
nextworker = &workers[0];
|
|
|
|
|
working = 0;
|
|
|
|
|
nextentertainer = &entertainers[0];
|
|
|
|
|
entertaining = 0;
|
|
|
|
|
taxorders = 0;
|
|
|
|
|
stealorders = 0;
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
strlist * s;
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race == new_race[RC_INSECT] && r_insectstalled(r) &&
|
2003-09-21 10:47:28 +02:00
|
|
|
|
!is_cursed(u->attribs, C_KAELTESCHUTZ,0))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (attacked(u) && *(u->thisorder) != 0) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 52, MSG_PRODUCE);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (!TradeDisabled()) {
|
|
|
|
|
for (s=u->orders;s;s=s->next) {
|
|
|
|
|
todo = igetkeyword(s->s, u->faction->locale);
|
|
|
|
|
switch (todo) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_BUY:
|
|
|
|
|
buy(r, u, &buyorders, s->s);
|
|
|
|
|
break;
|
|
|
|
|
case K_SELL:
|
|
|
|
|
sell(r, u, &sellorders, s->s);
|
|
|
|
|
break;
|
2003-07-29 11:48:03 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (fval(u, UFL_TRADER)) {
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_trades);
|
|
|
|
|
if (a && a->data.i) {
|
|
|
|
|
produceexp(u, SK_TRADE, u->number);
|
|
|
|
|
}
|
|
|
|
|
u->thisorder[0]=0;
|
|
|
|
|
continue;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
todo = igetkeyword(u->thisorder, u->faction->locale);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (todo == NOKEYWORD) continue;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (rterrain(r) == T_OCEAN && u->race != new_race[RC_AQUARIAN]
|
2003-09-21 10:47:28 +02:00
|
|
|
|
&& !(u->race->flags & RCF_SWIM)
|
|
|
|
|
&& todo != K_STEAL && todo != K_SPY && todo != K_SABOTAGE)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
switch (todo) {
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_MAKE:
|
|
|
|
|
make(r, u);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_ENTERTAIN:
|
|
|
|
|
entertain(r, u);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_WORK:
|
|
|
|
|
if (!!playerrace(u->race))
|
|
|
|
|
work(r, u);
|
|
|
|
|
else if (u->faction->no > 0) {
|
|
|
|
|
add_message(&u->faction->msgs,
|
2003-09-21 10:47:28 +02:00
|
|
|
|
msg_error(u, findorder(u, u->thisorder), "race_cantwork", "race", u->race));
|
2002-04-21 19:22:48 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_TAX:
|
|
|
|
|
tax(r, u, &taxorders);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case K_STEAL:
|
|
|
|
|
steal(r, u, &stealorders);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case K_SPY:
|
|
|
|
|
spy(r, u);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_SABOTAGE:
|
|
|
|
|
sabotage(r, u);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_ZUECHTE:
|
|
|
|
|
zuechte(r, u);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_PFLANZE:
|
|
|
|
|
pflanze(r, u);
|
|
|
|
|
break;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
case K_RESEARCH:
|
|
|
|
|
research(r, u);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
split_allocations(r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der
|
|
|
|
|
* letzten Runde berechnen kann, wieviel die Bauern f<EFBFBD>r Unterhaltung
|
|
|
|
|
* auszugeben bereit sind. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (entertaining) expandentertainment(r);
|
|
|
|
|
expandwork(r);
|
|
|
|
|
if (taxorders) expandtax(r, taxorders);
|
|
|
|
|
|
|
|
|
|
/* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu
|
|
|
|
|
* k<EFBFBD>nnen. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (buyorders) expandbuying(r, buyorders);
|
|
|
|
|
if (sellorders) expandselling(r, sellorders);
|
|
|
|
|
|
|
|
|
|
/* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden
|
2003-09-21 10:47:28 +02:00
|
|
|
|
* (expandstealing). */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (stealorders) expandstealing(r, stealorders);
|
|
|
|
|
|
|
|
|
|
assert(rmoney(r) >= 0);
|
|
|
|
|
assert(rpeasants(r) >= 0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2002-09-02 22:36:12 +02:00
|
|
|
|
void
|
2001-12-10 01:13:39 +01:00
|
|
|
|
init_economy(void)
|
|
|
|
|
{
|
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_HORSE]), attrib_allocation));
|
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_WOOD]), attrib_allocation));
|
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_MALLORN]), attrib_allocation));
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_STONE]), leveled_allocation));
|
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_IRON]), leveled_allocation));
|
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_LAEN]), leveled_allocation));
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_allocator(make_allocator(&rt_seed, attrib_allocation));
|
|
|
|
|
add_allocator(make_allocator(&rt_mallornseed, attrib_allocation));
|
|
|
|
|
#endif
|
|
|
|
|
#else
|
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_STONE]), attrib_allocation));
|
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_IRON]), attrib_allocation));
|
|
|
|
|
add_allocator(make_allocator(item2resource(olditemtype[I_LAEN]), attrib_allocation));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|