Merge pull request #656 from ennorehling/develop

BUG 2279: Zuviel Eisen aus der Region abgezogen
This commit is contained in:
Enno Rehling 2017-02-16 20:52:28 +01:00 committed by GitHub
commit 01cdfcd2a6
7 changed files with 191 additions and 134 deletions

View File

@ -534,7 +534,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
} }
if (has_skill(u, SK_MAGIC)) { if (has_skill(u, SK_MAGIC)) {
/* error158;de;{unit} in {region}: '{command}' - Magier arbeiten /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten
* grundsätzlich nur alleine! */ * grunds<EFBFBD>tzlich nur alleine! */
cmistake(u, ord, 158, MSG_EVENT); cmistake(u, ord, 158, MSG_EVENT);
return; return;
} }
@ -883,6 +883,31 @@ enum {
AFL_LOWSKILL = 1 << 1 AFL_LOWSKILL = 1 << 1
}; };
struct message * get_modifiers(unit *u, const resource_mod *mod, double *savep, int *skillp) {
struct building *b = inside_building(u);
const struct building_type *btype = building_is_active(b) ? b->type : NULL;
double save = 1.0;
int skill = 0;
for (; mod->flags != 0; ++mod) {
if (mod->btype == NULL || mod->btype == btype) {
if (mod->race == NULL || mod->race == u_race(u)) {
if (mod->flags & RMF_SAVEMATERIAL) {
save *= mod->value.f;
}
if (mod->flags & RMF_SKILL) {
skill += mod->value.i;
}
}
} else if (mod->flags & RMF_REQUIREDBUILDING) {
return msg_error(u, u->thisorder, 104);
}
}
*skillp = skill;
*savep = save;
return NULL;
}
static void allocate_resource(unit * u, const resource_type * rtype, int want) static void allocate_resource(unit * u, const resource_type * rtype, int want)
{ {
const item_type *itype = resource2item(rtype); const item_type *itype = resource2item(rtype);
@ -893,9 +918,10 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
attrib *a = a_find(rtype->attribs, &at_resourcelimit); attrib *a = a_find(rtype->attribs, &at_resourcelimit);
resource_limit *rdata = (resource_limit *)a->data.v; resource_limit *rdata = (resource_limit *)a->data.v;
const resource_type *rring; const resource_type *rring;
int amount, skill; int amount, skill, skill_mod = 0;
double save_mod = 1.0;
/* momentan kann man keine ressourcen abbauen, wenn man dafür /* momentan kann man keine ressourcen abbauen, wenn man daf<EFBFBD>r
* Materialverbrauch hat: */ * Materialverbrauch hat: */
assert(itype != NULL && (itype->construction == NULL assert(itype != NULL && (itype->construction == NULL
|| itype->construction->materials == NULL)); || itype->construction->materials == NULL));
@ -915,21 +941,15 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
} }
if (rdata->modifiers) { if (rdata->modifiers) {
resource_mod *mod = rdata->modifiers; message *msg = get_modifiers(u, rdata->modifiers, &save_mod, &skill_mod);
for (; mod->flags != 0; ++mod) { if (msg) {
if (mod->flags & RMF_REQUIREDBUILDING) { ADDMSG(&u->faction->msgs, msg);
struct building *b = inside_building(u); return;
const struct building_type *btype = building_is_active(b) ? b->type : NULL;
if (mod->btype && mod->btype != btype) {
cmistake(u, u->thisorder, 104, MSG_PRODUCE);
return;
}
}
} }
} }
/* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. /* Bergw<67>chter k<>nnen Abbau von Eisen/Laen durch Bewachen verhindern.
* Als magische Wesen 'sehen' Bergwächter alles und werden durch * Als magische Wesen 'sehen' Bergw<EFBFBD>chter alles und werden durch
* Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen).
*/ */
if (itype->rtype && (itype->rtype == get_resourcetype(R_IRON) || itype->rtype == rt_find("laen"))) { if (itype->rtype && (itype->rtype == get_resourcetype(R_IRON) || itype->rtype == rt_find("laen"))) {
@ -962,23 +982,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
itype->rtype)); itype->rtype));
return; return;
} }
else { skill += skill_mod;
struct building *b = inside_building(u);
const struct building_type *btype = building_is_active(b) ? b->type : NULL;
if (rdata->modifiers) {
resource_mod *mod = rdata->modifiers;
for (; mod->flags != 0; ++mod) {
if (mod->flags & RMF_SKILL) {
if (mod->btype == NULL || mod->btype == btype) {
if (mod->race == NULL || mod->race == u_race(u)) {
skill += mod->value.i;
}
}
}
}
}
}
amount = skill * u->number; amount = skill * u->number;
/* nun ist amount die Gesamtproduktion der Einheit (in punkten) */ /* nun ist amount die Gesamtproduktion der Einheit (in punkten) */
@ -1013,33 +1017,15 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
} }
al = new_allocation(); al = new_allocation();
al->want = amount; al->want = amount;
al->save = 1.0; al->save = save_mod;
al->next = alist->data; al->next = alist->data;
al->unit = u; al->unit = u;
alist->data = al; alist->data = al;
if (rdata->modifiers) {
struct building *b = inside_building(u);
const struct building_type *btype = building_is_active(b) ? b->type : NULL;
resource_mod *mod = rdata->modifiers;
for (; mod->flags != 0; ++mod) {
if (mod->flags & RMF_SAVEMATERIAL) {
if (mod->btype == NULL || mod->btype == btype) {
if (mod->race == NULL || mod->race == u_race(u)) {
al->save *= mod->value.f;
}
}
}
}
}
} }
static int required(int want, double save) static int required(int want, double save)
{ {
int req = (int)(want * save); int req = (int)(want * save);
if (req < want * save)
++req;
return req; return req;
} }
@ -1095,14 +1081,14 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist)
if (avail > 0) { if (avail > 0) {
int want = required(al->want - al->get, al->save); int want = required(al->want - al->get, al->save);
int x = avail * want / nreq; int x = avail * want / nreq;
/* Wenn Rest, dann würfeln, ob ich was bekomme: */ int r = (avail * want) % nreq;
if (rng_int() % nreq < (avail * want) % nreq) /* Wenn Rest, dann wuerfeln, ob ich etwas bekomme: */
++x; if (r > 0 && rng_int() % nreq < r) ++x;
avail -= x; avail -= x;
use += x; use += x;
nreq -= want; nreq -= want;
need -= x; need -= x;
al->get = MIN(al->want, al->get + (int)(x / al->save)); al->get = MIN(al->want, al->get + (int)(1 + x / al->save));
} }
} }
if (use) { if (use) {
@ -1140,7 +1126,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
if (avail > 0) { if (avail > 0) {
int want = required(al->want, al->save); int want = required(al->want, al->save);
int x = avail * want / nreq; int x = avail * want / nreq;
/* Wenn Rest, dann würfeln, ob ich was bekomme: */ /* Wenn Rest, dann w<EFBFBD>rfeln, ob ich was bekomme: */
if (rng_int() % nreq < (avail * want) % nreq) if (rng_int() % nreq < (avail * want) % nreq)
++x; ++x;
avail -= x; avail -= x;
@ -1248,7 +1234,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want)
} }
} }
static void create_item(unit * u, const item_type * itype, int want) void make_item(unit * u, const item_type * itype, int want)
{ {
if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { if (itype->construction && fval(itype->rtype, RTF_LIMITED)) {
#if GUARD_DISABLES_PRODUCTION == 1 #if GUARD_DISABLES_PRODUCTION == 1
@ -1402,7 +1388,7 @@ int make_cmd(unit * u, struct order *ord)
} }
} }
else if (itype != NULL) { else if (itype != NULL) {
create_item(u, itype, m); make_item(u, itype, m);
} }
else { else {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", ""));
@ -1453,15 +1439,15 @@ static void expandbuying(region * r, request * buyorders)
return; return;
/* Initialisation. multiplier ist der Multiplikator auf den /* Initialisation. multiplier ist der Multiplikator auf den
* Verkaufspreis. Für max_products Produkte kauft man das Produkt zum * Verkaufspreis. F<EFBFBD>r max_products Produkte kauft man das Produkt zum
* einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1. * einfachen Verkaufspreis, danach erh<EFBFBD>ht sich der Multiplikator um 1.
* counter ist ein Zähler, der die gekauften Produkte hlt. money * counter ist ein Z<EFBFBD>hler, der die gekauften Produkte z<EFBFBD>hlt. money
* wird für die debug message gebraucht. */ * wird f<EFBFBD>r die debug message gebraucht. */
max_products = rpeasants(r) / TRADE_FRACTION; max_products = rpeasants(r) / TRADE_FRACTION;
/* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere /* Kauf - auch so programmiert, da<EFBFBD> er leicht erweiterbar auf mehrere
* Güter pro Monat ist. j sind die Befehle, i der Index des * G<EFBFBD>ter pro Monat ist. j sind die Befehle, i der Index des
* gehandelten Produktes. */ * gehandelten Produktes. */
if (max_products > 0) { if (max_products > 0) {
unsigned int j; unsigned int j;
@ -1483,10 +1469,10 @@ static void expandbuying(region * r, request * buyorders)
unit *u = g_requests[j].unit; unit *u = g_requests[j].unit;
item *items; item *items;
/* litems zählt die Güter, die verkauft wurden, u->n das Geld, das /* litems z<EFBFBD>hlt die G<>ter, die verkauft wurden, u->n das Geld, das
* verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt, * 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 * man sich also das verdiente Geld und die verkauften Produkte separat
* merken muß. */ * merken mu<EFBFBD>. */
attrib *a = a_find(u->attribs, &at_luxuries); attrib *a = a_find(u->attribs, &at_luxuries);
if (a == NULL) if (a == NULL)
a = a_add(&u->attribs, a_new(&at_luxuries)); a = a_add(&u->attribs, a_new(&at_luxuries));
@ -1503,7 +1489,7 @@ static void expandbuying(region * r, request * buyorders)
rsetmoney(r, rmoney(r) + price); rsetmoney(r, rmoney(r) + price);
/* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt
* der Preis Multiplikator für das Produkt um den Faktor 1. Der Zähler * der Preis Multiplikator f<EFBFBD>r das Produkt um den Faktor 1. Der Z<EFBFBD>hler
* wird wieder auf 0 gesetzt. */ * wird wieder auf 0 gesetzt. */
if (++trade->number == max_products) { if (++trade->number == max_products) {
trade->number = 0; trade->number = 0;
@ -1563,7 +1549,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
return; return;
} }
/* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber
* schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ * schon daf<EFBFBD>r ausger<EFBFBD>stet, mehrere Produkte zu kaufen. */
kwd = init_order(ord); kwd = init_order(ord);
assert(kwd == K_BUY); assert(kwd == K_BUY);
@ -1573,7 +1559,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
return; return;
} }
if (besieged(u)) { if (besieged(u)) {
/* Belagerte Einheiten können nichts kaufen. */ /* Belagerte Einheiten k<EFBFBD>nnen nichts kaufen. */
cmistake(u, ord, 60, MSG_COMMERCE); cmistake(u, ord, 60, MSG_COMMERCE);
return; return;
} }
@ -1587,7 +1573,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
} }
} }
else { else {
/* ...oder in der Region muß es eine Burg geben. */ /* ...oder in der Region mu<EFBFBD> es eine Burg geben. */
building *b = 0; building *b = 0;
if (r->buildings) { if (r->buildings) {
static int cache; static int cache;
@ -1608,11 +1594,11 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
} }
} }
/* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ /* Ein H<EFBFBD>ndler kann nur 10 G<>ter pro Talentpunkt handeln. */
k = u->number * 10 * effskill(u, SK_TRADE, 0); k = u->number * 10 * effskill(u, SK_TRADE, 0);
/* hat der Händler bereits gehandelt, muss die Menge der bereits /* hat der H<EFBFBD>ndler bereits gehandelt, muss die Menge der bereits
* verkauften/gekauften Güter abgezogen werden */ * verkauften/gekauften G<EFBFBD>ter abgezogen werden */
a = a_find(u->attribs, &at_trades); a = a_find(u->attribs, &at_trades);
if (!a) { if (!a) {
a = a_add(&u->attribs, a_new(&at_trades)); a = a_add(&u->attribs, a_new(&at_trades));
@ -1629,7 +1615,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
} }
assert(n >= 0); assert(n >= 0);
/* die Menge der verkauften Güter merken */ /* die Menge der verkauften G<EFBFBD>ter merken */
a->data.i += n; a->data.i += n;
s = gettoken(token, sizeof(token)); s = gettoken(token, sizeof(token));
@ -1662,7 +1648,7 @@ static void add_income(unit * u, int type, int want, int qty)
"unit region mode wanted amount", u, u->region, type, want, qty)); "unit region mode wanted amount", u, u->region, type, want, qty));
} }
/* Steuersätze in % bei Burggröße */ /* Steuers<EFBFBD>tze in % bei Burggr<67><72>e */
static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 }; static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 };
static void expandselling(region * r, request * sellorders, int limit) static void expandselling(region * r, request * sellorders, int limit)
@ -1697,11 +1683,11 @@ static void expandselling(region * r, request * sellorders, int limit)
} }
memset(counter, 0, sizeof(int) * ncounter); memset(counter, 0, sizeof(int) * ncounter);
if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ if (!sellorders) { /* NEIN, denn Insekten k<EFBFBD>nnen in || !r->buildings) */
return; /* Sümpfen und Wüsten auch so handeln */ return; /* S<EFBFBD>mpfen und W<>sten auch so handeln */
} }
/* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem /* Stelle Eigent<EFBFBD>mer der gr<67><72>ten Burg fest. Bekommt Steuern aus jedem
* Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ * Verkauf. Wenn zwei Burgen gleicher Gr<EFBFBD><EFBFBD>e bekommt gar keiner etwas. */
for (b = rbuildings(r); b; b = b->next) { for (b = rbuildings(r); b; b = b->next) {
if (b->size > maxsize && building_owner(b) != NULL if (b->size > maxsize && building_owner(b) != NULL
&& b->type == castle_bt) { && b->type == castle_bt) {
@ -1724,13 +1710,13 @@ static void expandselling(region * r, request * sellorders, int limit)
maxowner = (unit *)NULL; maxowner = (unit *)NULL;
} }
} }
/* Die Region muss genug Geld haben, um die Produkte kaufen zu können. */ /* Die Region muss genug Geld haben, um die Produkte kaufen zu k<EFBFBD>nnen. */
money = rmoney(r); money = rmoney(r);
/* max_products sind 1/100 der Bevölkerung, falls soviele Produkte /* max_products sind 1/100 der Bev<EFBFBD>lkerung, falls soviele Produkte
* verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt. * verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt.
* multiplier speichert r->demand für die debug message ab. */ * multiplier speichert r->demand f<EFBFBD>r die debug message ab. */
max_products = rpeasants(r) / TRADE_FRACTION; max_products = rpeasants(r) / TRADE_FRACTION;
if (max_products <= 0) if (max_products <= 0)
@ -1798,11 +1784,11 @@ static void expandselling(region * r, request * sellorders, int limit)
change_money(u, price); change_money(u, price);
fset(u, UFL_LONGACTION | UFL_NOTMOVING); fset(u, UFL_LONGACTION | UFL_NOTMOVING);
/* r->money -= price; --- dies wird eben nicht ausgeführt, denn die /* r->money -= price; --- dies wird eben nicht ausgef<EFBFBD>hrt, denn die
* Produkte können auch als Steuern eingetrieben werden. In der Region * Produkte k<EFBFBD>nnen auch als Steuern eingetrieben werden. In der Region
* wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht! * wurden Silberst<EFBFBD>cke gegen Luxusg<EFBFBD>ter des selben Wertes eingetauscht!
* Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt
* die Nachfrage für das Produkt um 1. Der hler wird wieder auf 0 * die Nachfrage f<EFBFBD>r das Produkt um 1. Der Z<EFBFBD>hler wird wieder auf 0
* gesetzt. */ * gesetzt. */
if (++counter[i] > max_products) { if (++counter[i] > max_products) {
@ -1819,7 +1805,7 @@ static void expandselling(region * r, request * sellorders, int limit)
} }
free(g_requests); free(g_requests);
/* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */ /* Steuern. Hier werden die Steuern dem Besitzer der gr<EFBFBD><EFBFBD>ten Burg gegeben. */
if (maxowner) { if (maxowner) {
if (taxcollected > 0) { if (taxcollected > 0) {
change_money(maxowner, (int)taxcollected); change_money(maxowner, (int)taxcollected);
@ -1876,7 +1862,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
cmistake(u, ord, 69, MSG_INCOME); cmistake(u, ord, 69, MSG_INCOME);
return false; return false;
} }
/* sellorders sind KEIN array, weil für alle items DIE SELBE resource /* sellorders sind KEIN array, weil f<EFBFBD>r alle items DIE SELBE resource
* (das geld der region) aufgebraucht wird. */ * (das geld der region) aufgebraucht wird. */
kwd = init_order(ord); kwd = init_order(ord);
@ -1901,13 +1887,13 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
return false; return false;
} }
} }
/* Belagerte Einheiten können nichts verkaufen. */ /* Belagerte Einheiten k<EFBFBD>nnen nichts verkaufen. */
if (besieged(u)) { if (besieged(u)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", ""));
return false; return false;
} }
/* In der Region muß es eine Burg geben. */ /* In der Region mu<EFBFBD> es eine Burg geben. */
if (u_race(u) == get_race(RC_INSECT)) { if (u_race(u) == get_race(RC_INSECT)) {
if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT)
@ -1917,7 +1903,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
} }
} }
else { else {
/* ...oder in der Region muß es eine Burg geben. */ /* ...oder in der Region mu<EFBFBD> es eine Burg geben. */
building *b = 0; building *b = 0;
if (r->buildings) { if (r->buildings) {
for (b = r->buildings; b; b = b->next) { for (b = r->buildings; b; b = b->next) {
@ -1930,7 +1916,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
} }
} }
/* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ /* Ein H<EFBFBD>ndler kann nur 10 G<>ter pro Talentpunkt verkaufen. */
n = MIN(n, u->number * 10 * effskill(u, SK_TRADE, 0)); n = MIN(n, u->number * 10 * effskill(u, SK_TRADE, 0));
@ -1956,7 +1942,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
} }
available = get_pooled(u, itype->rtype, GET_DEFAULT, INT_MAX); available = get_pooled(u, itype->rtype, GET_DEFAULT, INT_MAX);
/* Wenn andere Einheiten das selbe verkaufen, muß ihr Zeug abgezogen /* Wenn andere Einheiten das selbe verkaufen, mu<EFBFBD> ihr Zeug abgezogen
* werden damit es nicht zweimal verkauft wird: */ * werden damit es nicht zweimal verkauft wird: */
for (o = *sellorders; o; o = o->next) { for (o = *sellorders; o; o = o->next) {
if (o->type.ltype == ltype && o->unit->faction == u->faction) { if (o->type.ltype == ltype && o->unit->faction == u->faction) {
@ -1973,16 +1959,16 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
return false; return false;
} }
/* Hier wird request->type verwendet, weil die obere limit durch /* Hier wird request->type verwendet, weil die obere limit durch
* das silber gegeben wird (region->money), welches für alle * das silber gegeben wird (region->money), welches f<EFBFBD>r alle
* (!) produkte als summe gilt, als nicht wie bei der * (!) produkte als summe gilt, als nicht wie bei der
* produktion, wo für jedes produkt einzeln eine obere limite * produktion, wo f<EFBFBD>r jedes produkt einzeln eine obere limite
* existiert, so dass man arrays von orders machen kann. */ * existiert, so dass man arrays von orders machen kann. */
/* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ /* Ein H<EFBFBD>ndler kann nur 10 G<>ter pro Talentpunkt handeln. */
k = u->number * 10 * effskill(u, SK_TRADE, 0); k = u->number * 10 * effskill(u, SK_TRADE, 0);
/* hat der Händler bereits gehandelt, muss die Menge der bereits /* hat der H<EFBFBD>ndler bereits gehandelt, muss die Menge der bereits
* verkauften/gekauften Güter abgezogen werden */ * verkauften/gekauften G<EFBFBD>ter abgezogen werden */
a = a_find(u->attribs, &at_trades); a = a_find(u->attribs, &at_trades);
if (!a) { if (!a) {
a = a_add(&u->attribs, a_new(&at_trades)); a = a_add(&u->attribs, a_new(&at_trades));
@ -1993,7 +1979,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
n = MIN(n, k); n = MIN(n, k);
assert(n >= 0); assert(n >= 0);
/* die Menge der verkauften Güter merken */ /* die Menge der verkauften G<EFBFBD>ter merken */
a->data.i += n; a->data.i += n;
o = (request *)calloc(1, sizeof(request)); o = (request *)calloc(1, sizeof(request));
o->unit = u; o->unit = u;
@ -2017,8 +2003,8 @@ static void expandstealing(region * r, request * stealorders)
expandorders(r, stealorders); expandorders(r, stealorders);
if (!norders) return; if (!norders) return;
/* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines /* F<EFBFBD>r jede unit in der Region wird Geld geklaut, wenn sie Opfer eines
* Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. * Beklauen-Orders ist. Jedes Opfer mu<EFBFBD> einzeln behandelt werden.
* *
* u ist die beklaute unit. oa.unit ist die klauende unit. * u ist die beklaute unit. oa.unit ist die klauende unit.
*/ */
@ -2079,7 +2065,7 @@ static void plant(unit * u, int raw)
return; return;
} }
/* Skill prüfen */ /* Skill pr<EFBFBD>fen */
skill = effskill(u, SK_HERBALISM, 0); skill = effskill(u, SK_HERBALISM, 0);
if (skill < 6) { if (skill < 6) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
@ -2087,14 +2073,14 @@ static void plant(unit * u, int raw)
"skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1));
return; return;
} }
/* Wasser des Lebens prüfen */ /* Wasser des Lebens pr<EFBFBD>fen */
if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water));
return; return;
} }
n = get_pooled(u, itype->rtype, GET_DEFAULT, skill * u->number); n = get_pooled(u, itype->rtype, GET_DEFAULT, skill * u->number);
/* Kräuter prüfen */ /* Kr<EFBFBD>uter pr<70>fen */
if (n == 0) { if (n == 0) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "resource_missing", "missing", msg_feedback(u, u->thisorder, "resource_missing", "missing",
@ -2104,7 +2090,7 @@ static void plant(unit * u, int raw)
n = MIN(skill * u->number, n); n = MIN(skill * u->number, n);
n = MIN(raw, n); n = MIN(raw, n);
/* Für jedes Kraut Talent*10% Erfolgschance. */ /* F<EFBFBD>r jedes Kraut Talent*10% Erfolgschance. */
for (i = n; i > 0; i--) { for (i = n; i > 0; i--) {
if (rng_int() % 10 < skill) if (rng_int() % 10 < skill)
planted++; planted++;
@ -2129,10 +2115,10 @@ static void planttrees(unit * u, int raw)
return; return;
} }
/* Mallornbäume kann man nur in Mallornregionen züchten */ /* Mallornb<EFBFBD>ume kann man nur in Mallornregionen z<>chten */
rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED); rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED);
/* Skill prüfen */ /* Skill pr<EFBFBD>fen */
skill = effskill(u, SK_HERBALISM, 0); skill = effskill(u, SK_HERBALISM, 0);
if (skill < 6) { if (skill < 6) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
@ -2157,7 +2143,7 @@ static void planttrees(unit * u, int raw)
} }
n = MIN(raw, n); n = MIN(raw, n);
/* Für jeden Samen Talent*10% Erfolgschance. */ /* F<EFBFBD>r jeden Samen Talent*10% Erfolgschance. */
for (i = n; i > 0; i--) { for (i = n; i > 0; i--) {
if (rng_int() % 10 < skill) if (rng_int() % 10 < skill)
planted++; planted++;
@ -2172,7 +2158,7 @@ static void planttrees(unit * u, int raw)
"unit region amount herb", u, r, planted, rtype)); "unit region amount herb", u, r, planted, rtype));
} }
/* züchte bäume */ /* z<EFBFBD>chte b<>ume */
static void breedtrees(unit * u, int raw) static void breedtrees(unit * u, int raw)
{ {
int n, i, skill, planted = 0; int n, i, skill, planted = 0;
@ -2184,7 +2170,7 @@ static void breedtrees(unit * u, int raw)
get_gamedate(turn, &date); get_gamedate(turn, &date);
current_season = date.season; current_season = date.season;
/* Bäume züchten geht nur im Frühling */ /* B<EFBFBD>ume z<>chten geht nur im Fr<46>hling */
if (current_season != SEASON_SPRING) { if (current_season != SEASON_SPRING) {
planttrees(u, raw); planttrees(u, raw);
return; return;
@ -2194,10 +2180,10 @@ static void breedtrees(unit * u, int raw)
return; return;
} }
/* Mallornbäume kann man nur in Mallornregionen züchten */ /* Mallornb<EFBFBD>ume kann man nur in Mallornregionen z<>chten */
rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED); rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED);
/* Skill prüfen */ /* Skill pr<EFBFBD>fen */
skill = effskill(u, SK_HERBALISM, 0); skill = effskill(u, SK_HERBALISM, 0);
if (skill < 12) { if (skill < 12) {
planttrees(u, raw); planttrees(u, raw);
@ -2207,7 +2193,7 @@ static void breedtrees(unit * u, int raw)
/* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */
raw = MIN(skill * u->number, raw); raw = MIN(skill * u->number, raw);
n = get_pooled(u, rtype, GET_DEFAULT, raw); n = get_pooled(u, rtype, GET_DEFAULT, raw);
/* Samen prüfen */ /* Samen pr<EFBFBD>fen */
if (n == 0) { if (n == 0) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype));
@ -2215,7 +2201,7 @@ static void breedtrees(unit * u, int raw)
} }
n = MIN(raw, n); n = MIN(raw, n);
/* Für jeden Samen Talent*5% Erfolgschance. */ /* F<EFBFBD>r jeden Samen Talent*5% Erfolgschance. */
for (i = n; i > 0; i--) { for (i = n; i > 0; i--) {
if (rng_int() % 100 < skill * 5) if (rng_int() % 100 < skill * 5)
planted++; planted++;
@ -2230,7 +2216,7 @@ static void breedtrees(unit * u, int raw)
"unit region amount herb", u, r, planted, rtype)); "unit region amount herb", u, r, planted, rtype));
} }
/* züchte pferde */ /* z<EFBFBD>chte pferde */
static void breedhorses(unit * u) static void breedhorses(unit * u)
{ {
int n, c, breed = 0; int n, c, breed = 0;
@ -2283,7 +2269,7 @@ static void breed_cmd(unit * u, struct order *ord)
return; return;
} }
/* züchte [<anzahl>] <parameter> */ /* z<EFBFBD>chte [<anzahl>] <parameter> */
(void)init_order(ord); (void)init_order(ord);
s = gettoken(token, sizeof(token)); s = gettoken(token, sizeof(token));
@ -2549,7 +2535,7 @@ static void expandentertainment(region * r)
m -= u->n; m -= u->n;
entertaining -= o->qty; entertaining -= o->qty;
/* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ /* Nur soviel PRODUCEEXP wie auch tats<EFBFBD>chlich gemacht wurde */
produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number));
add_income(u, IC_ENTERTAIN, o->qty, u->n); add_income(u, IC_ENTERTAIN, o->qty, u->n);
fset(u, UFL_LONGACTION | UFL_NOTMOVING); fset(u, UFL_LONGACTION | UFL_NOTMOVING);
@ -3121,7 +3107,7 @@ void produce(struct region *r)
/* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den /* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den
* Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der
* letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung * letzten Runde berechnen kann, wieviel die Bauern f<EFBFBD>r Unterhaltung
* auszugeben bereit sind. */ * auszugeben bereit sind. */
if (entertaining) if (entertaining)
expandentertainment(r); expandentertainment(r);
@ -3136,7 +3122,7 @@ void produce(struct region *r)
/* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um
* nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu
* können. */ * k<EFBFBD>nnen. */
if (buyorders) if (buyorders)
expandbuying(r, buyorders); expandbuying(r, buyorders);

View File

@ -56,6 +56,7 @@ extern "C" {
enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT }; enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT };
void maintain_buildings(struct region *r); void maintain_buildings(struct region *r);
void make_item(struct unit * u, const struct item_type * itype, int want);
int make_cmd(struct unit *u, struct order *ord); int make_cmd(struct unit *u, struct order *ord);
void split_allocations(struct region *r); void split_allocations(struct region *r);
int give_control_cmd(struct unit *u, struct order *ord); int give_control_cmd(struct unit *u, struct order *ord);

View File

@ -11,10 +11,12 @@
#include <kernel/pool.h> #include <kernel/pool.h>
#include <kernel/race.h> #include <kernel/race.h>
#include <kernel/region.h> #include <kernel/region.h>
#include <kernel/resources.h>
#include <kernel/ship.h> #include <kernel/ship.h>
#include <kernel/terrain.h> #include <kernel/terrain.h>
#include <kernel/unit.h> #include <kernel/unit.h>
#include <util/attrib.h>
#include <util/language.h> #include <util/language.h>
#include <CuTest.h> #include <CuTest.h>
@ -341,12 +343,82 @@ static void test_income(CuTest *tc)
test_cleanup(); test_cleanup();
} }
static void test_make_item(CuTest *tc) {
unit *u;
struct item_type *itype;
const struct resource_type *rt_silver;
resource_type *rtype;
attrib *a;
resource_limit *rdata;
test_setup();
init_resources();
/* make items from other items (turn silver to stone) */
rt_silver = get_resourcetype(R_SILVER);
itype = test_create_itemtype("stone");
rtype = itype->rtype;
u = test_create_unit(test_create_faction(0), test_create_region(0,0,0));
make_item(u, itype, 1);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_cannotmake"));
CuAssertIntEquals(tc, 0, get_item(u, itype));
test_clear_messages(u->faction);
itype->construction = calloc(1, sizeof(construction));
itype->construction->skill = SK_ALCHEMY;
itype->construction->minskill = 1;
itype->construction->maxsize = 1;
itype->construction->reqsize = 1;
itype->construction->materials = calloc(2, sizeof(requirement));
itype->construction->materials[0].rtype = rt_silver;
itype->construction->materials[0].number = 1;
set_level(u, SK_ALCHEMY, 1);
set_item(u, rt_silver->itype, 1);
make_item(u, itype, 1);
CuAssertIntEquals(tc, 1, get_item(u, itype));
CuAssertIntEquals(tc, 0, get_item(u, rt_silver->itype));
/* make level-based raw materials, no materials used in construction */
free(itype->construction->materials);
itype->construction->materials = 0;
rtype->flags |= RTF_LIMITED;
a = a_add(&rtype->attribs, a_new(&at_resourcelimit));
rdata = (resource_limit *)a->data.v;
rdata->value = 0;
rmt_create(rtype, "stone");
add_resource(u->region, 1, 300, 150, rtype);
u->region->resources->amount = 300; /* there are 300 stones at level 1 */
set_level(u, SK_ALCHEMY, 10);
make_item(u, itype, 10);
split_allocations(u->region);
CuAssertIntEquals(tc, 11, get_item(u, itype));
CuAssertIntEquals(tc, 290, u->region->resources->amount); /* used 10 stones to make 10 stones */
rdata->modifiers = calloc(2, sizeof(resource_mod));
rdata->modifiers[0].flags = RMF_SAVEMATERIAL;
rdata->modifiers[0].race = u->_race;
rdata->modifiers[0].value.f = (float)0.6;
make_item(u, itype, 10);
split_allocations(u->region);
CuAssertIntEquals(tc, 21, get_item(u, itype));
CuAssertIntEquals(tc, 284, u->region->resources->amount); /* 60% saving = 6 stones make 10 stones */
rdata->modifiers[0].flags = RMF_REQUIREDBUILDING;
rdata->modifiers[0].race = NULL;
rdata->modifiers[0].btype = bt_get_or_create("mine");
make_item(u, itype, 10);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error104"));
test_cleanup();
}
CuSuite *get_economy_suite(void) CuSuite *get_economy_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_give_control_building); SUITE_ADD_TEST(suite, test_give_control_building);
SUITE_ADD_TEST(suite, test_give_control_ship); SUITE_ADD_TEST(suite, test_give_control_ship);
SUITE_ADD_TEST(suite, test_income); SUITE_ADD_TEST(suite, test_income);
SUITE_ADD_TEST(suite, test_make_item);
SUITE_ADD_TEST(suite, test_steal_okay); SUITE_ADD_TEST(suite, test_steal_okay);
SUITE_ADD_TEST(suite, test_steal_ocean); SUITE_ADD_TEST(suite, test_steal_ocean);
SUITE_ADD_TEST(suite, test_steal_nosteal); SUITE_ADD_TEST(suite, test_steal_nosteal);

View File

@ -397,7 +397,7 @@ static int required(int size, int msize, int maxneed)
* braucht man required von maxneed resourcen */ * braucht man required von maxneed resourcen */
{ {
int used; int used;
assert(msize > 0);
used = size * maxneed / msize; used = size * maxneed / msize;
if (size * maxneed % msize) if (size * maxneed % msize)
++used; ++used;

View File

@ -70,7 +70,7 @@ extern "C" {
typedef char *(*rtype_name) (const struct resource_type * rtype, int flags); typedef char *(*rtype_name) (const struct resource_type * rtype, int flags);
typedef struct resource_type { typedef struct resource_type {
/* --- constants --- */ /* --- constants --- */
char *_name; /* wie es heißt */ char *_name; /* wie es hei<EFBFBD>t */
unsigned int flags; unsigned int flags;
/* --- functions --- */ /* --- functions --- */
rtype_uchange uchange; rtype_uchange uchange;
@ -136,7 +136,7 @@ extern "C" {
int weight; int weight;
int capacity; int capacity;
struct construction *construction; struct construction *construction;
char *_appearance[2]; /* wie es für andere aussieht */ char *_appearance[2]; /* wie es f<EFBFBD>r andere aussieht */
/* --- functions --- */ /* --- functions --- */
bool(*canuse) (const struct unit * user, bool(*canuse) (const struct unit * user,
const struct item_type * itype); const struct item_type * itype);
@ -311,6 +311,8 @@ extern "C" {
extern const struct potion_type *oldpotiontype[]; extern const struct potion_type *oldpotiontype[];
const struct resource_type *get_resourcetype(resource_t rt); const struct resource_type *get_resourcetype(resource_t rt);
int get_item(const struct unit * u, const struct item_type *itype);
int set_item(struct unit * u, const struct item_type *itype, int value);
int get_money(const struct unit *); int get_money(const struct unit *);
int set_money(struct unit *, int); int set_money(struct unit *, int);
int change_money(struct unit *, int); int change_money(struct unit *, int);

View File

@ -270,8 +270,6 @@ void syntax_error(const struct unit *u, struct order *ord)
ADDMSG(&u->faction->msgs, result); ADDMSG(&u->faction->msgs, result);
} }
extern unsigned int new_hashstring(const char *s);
void free_messagelist(mlist *msgs) void free_messagelist(mlist *msgs)
{ {
struct mlist **mlistptr; struct mlist **mlistptr;

View File

@ -55,18 +55,16 @@ extern "C" {
extern struct rawmaterial_type *rawmaterialtypes; extern struct rawmaterial_type *rawmaterialtypes;
extern void update_resources(struct region *r); void update_resources(struct region *r);
extern void terraform_resources(struct region *r); void terraform_resources(struct region *r);
extern void read_resources(struct region *r); struct rawmaterial *rm_get(struct region *,
extern void write_resources(struct region *r);
extern struct rawmaterial *rm_get(struct region *,
const struct resource_type *); const struct resource_type *);
extern struct rawmaterial_type *rmt_find(const char *str); struct rawmaterial_type *rmt_find(const char *str);
extern struct rawmaterial_type *rmt_get(const struct resource_type *); struct rawmaterial_type *rmt_get(const struct resource_type *);
extern void add_resource(struct region *r, int level, int base, int divisor, void add_resource(struct region *r, int level, int base, int divisor,
const struct resource_type *rtype); const struct resource_type *rtype);
extern struct rawmaterial_type *rmt_create(const struct resource_type *rtype, struct rawmaterial_type *rmt_create(const struct resource_type *rtype,
const char *name); const char *name);
#ifdef __cplusplus #ifdef __cplusplus