forked from github/server
Bug 2633: implement combined trade limits.
This commit is contained in:
parent
e02c1e9d00
commit
6626cfe297
180
src/economy.c
180
src/economy.c
|
@ -1052,6 +1052,36 @@ const attrib_type at_luxuries = {
|
||||||
"luxuries", NULL, free_luxuries, NULL, NULL, NULL
|
"luxuries", NULL, free_luxuries, NULL, NULL, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const attrib_type at_trades = {
|
||||||
|
"trades",
|
||||||
|
DEFAULT_INIT,
|
||||||
|
DEFAULT_FINALIZE,
|
||||||
|
DEFAULT_AGE,
|
||||||
|
NO_WRITE,
|
||||||
|
NO_READ
|
||||||
|
};
|
||||||
|
|
||||||
|
static int trade_add(unit *u, int n) {
|
||||||
|
/* Ein Haendler kann nur 10 Gueter pro Talentpunkt handeln. */
|
||||||
|
int k = u->number * 10 * effskill(u, SK_TRADE, NULL);
|
||||||
|
|
||||||
|
attrib *a = a_find(u->attribs, &at_trades);
|
||||||
|
/* hat der Haendler bereits gehandelt, muss die Menge der bereits
|
||||||
|
* verkauften/gekauften Gueter abgezogen werden */
|
||||||
|
if (!a) {
|
||||||
|
a = a_add(&u->attribs, a_new(&at_trades));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
k -= a->data.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > k) n = k;
|
||||||
|
|
||||||
|
/* die Menge der verkauften Gueter merken */
|
||||||
|
a->data.i += n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
static void expandbuying(region * r, econ_request * buyorders)
|
static void expandbuying(region * r, econ_request * buyorders)
|
||||||
{
|
{
|
||||||
const resource_type *rsilver = get_resourcetype(R_SILVER);
|
const resource_type *rsilver = get_resourcetype(R_SILVER);
|
||||||
|
@ -1120,15 +1150,16 @@ static void expandbuying(region * r, econ_request * buyorders)
|
||||||
a->data.v = items;
|
a->data.v = items;
|
||||||
i_change(&g_requests[j]->unit->items, ltype->itype, 1);
|
i_change(&g_requests[j]->unit->items, ltype->itype, 1);
|
||||||
use_pooled(u, rsilver, GET_DEFAULT, price);
|
use_pooled(u, rsilver, GET_DEFAULT, price);
|
||||||
if (u->n < 0)
|
if (u->n < 0) {
|
||||||
u->n = 0;
|
u->n = 0;
|
||||||
|
}
|
||||||
u->n += price;
|
u->n += price;
|
||||||
|
|
||||||
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 fuer das Produkt um den Faktor 1. Der Zaehler
|
* der Preis Multiplikator fuer das Produkt um den Faktor 1. Der Zaehler
|
||||||
* 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;
|
||||||
++trade->multi;
|
++trade->multi;
|
||||||
|
@ -1158,15 +1189,6 @@ static void expandbuying(region * r, econ_request * buyorders)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attrib_type at_trades = {
|
|
||||||
"trades",
|
|
||||||
DEFAULT_INIT,
|
|
||||||
DEFAULT_FINALIZE,
|
|
||||||
DEFAULT_AGE,
|
|
||||||
NO_WRITE,
|
|
||||||
NO_READ
|
|
||||||
};
|
|
||||||
|
|
||||||
bool trade_needs_castle(const terrain_type *terrain, const race *rc)
|
bool trade_needs_castle(const terrain_type *terrain, const race *rc)
|
||||||
{
|
{
|
||||||
static int rc_change, terrain_change;
|
static int rc_change, terrain_change;
|
||||||
|
@ -1198,9 +1220,8 @@ static void buy(unit * u, econ_request ** buyorders, struct order *ord)
|
||||||
{
|
{
|
||||||
char token[128];
|
char token[128];
|
||||||
region *r = u->region;
|
region *r = u->region;
|
||||||
int n, k;
|
int n;
|
||||||
econ_request *o;
|
econ_request *o;
|
||||||
attrib *a;
|
|
||||||
const item_type *itype = NULL;
|
const item_type *itype = NULL;
|
||||||
const luxury_type *ltype = NULL;
|
const luxury_type *ltype = NULL;
|
||||||
keyword_t kwd;
|
keyword_t kwd;
|
||||||
|
@ -1239,30 +1260,12 @@ static void buy(unit * u, econ_request ** buyorders, struct order *ord)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ein Haendler kann nur 10 Gueter pro Talentpunkt handeln. */
|
n = trade_add(u, n);
|
||||||
k = u->number * 10 * effskill(u, SK_TRADE, NULL);
|
if (n <= 0) {
|
||||||
|
|
||||||
/* hat der Haendler bereits gehandelt, muss die Menge der bereits
|
|
||||||
* verkauften/gekauften Gueter abgezogen werden */
|
|
||||||
a = a_find(u->attribs, &at_trades);
|
|
||||||
if (!a) {
|
|
||||||
a = a_add(&u->attribs, a_new(&at_trades));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
k -= a->data.i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n > k) n = k;
|
|
||||||
|
|
||||||
if (!n) {
|
|
||||||
cmistake(u, ord, 102, MSG_COMMERCE);
|
cmistake(u, ord, 102, MSG_COMMERCE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(n >= 0);
|
|
||||||
/* die Menge der verkauften Gueter merken */
|
|
||||||
a->data.i += n;
|
|
||||||
|
|
||||||
s = gettoken(token, sizeof(token));
|
s = gettoken(token, sizeof(token));
|
||||||
itype = s ? finditemtype(s, u->faction->locale) : 0;
|
itype = s ? finditemtype(s, u->faction->locale) : 0;
|
||||||
if (itype != NULL) {
|
if (itype != NULL) {
|
||||||
|
@ -1309,8 +1312,7 @@ static void expandselling(region * r, econ_request * sellorders, int limit)
|
||||||
unit *maxowner = (unit *)NULL;
|
unit *maxowner = (unit *)NULL;
|
||||||
building *maxb = (building *)NULL;
|
building *maxb = (building *)NULL;
|
||||||
building *b;
|
building *b;
|
||||||
unit *u;
|
unit *hafenowner, *u;
|
||||||
unit *hafenowner;
|
|
||||||
static int counter[MAXLUXURIES];
|
static int counter[MAXLUXURIES];
|
||||||
static int ncounter = 0;
|
static int ncounter = 0;
|
||||||
static int bt_cache;
|
static int bt_cache;
|
||||||
|
@ -1386,6 +1388,8 @@ static void expandselling(region * r, econ_request * sellorders, int limit)
|
||||||
int multi = r_demand(r, ltype);
|
int multi = r_demand(r, ltype);
|
||||||
int i, price;
|
int i, price;
|
||||||
int use = 0;
|
int use = 0;
|
||||||
|
|
||||||
|
u = g_requests[j]->unit;
|
||||||
for (i = 0, search = luxurytypes; search != ltype; search = search->next) {
|
for (i = 0, search = luxurytypes; search != ltype; search = search->next) {
|
||||||
/* TODO: this is slow and lame! */
|
/* TODO: this is slow and lame! */
|
||||||
++i;
|
++i;
|
||||||
|
@ -1397,58 +1401,62 @@ static void expandselling(region * r, econ_request * sellorders, int limit)
|
||||||
price = ltype->price * multi;
|
price = ltype->price * multi;
|
||||||
|
|
||||||
if (money >= price) {
|
if (money >= price) {
|
||||||
item *itm;
|
if (trade_add(u, 1) != 1) {
|
||||||
attrib *a;
|
break;
|
||||||
u = g_requests[j]->unit;
|
|
||||||
a = a_find(u->attribs, &at_luxuries);
|
|
||||||
if (!a) {
|
|
||||||
a = a_add(&u->attribs, a_new(&at_luxuries));
|
|
||||||
}
|
}
|
||||||
itm = (item *)a->data.v;
|
else {
|
||||||
i_change(&itm, ltype->itype, 1);
|
item *itm;
|
||||||
a->data.v = itm;
|
attrib *a;
|
||||||
++use;
|
a = a_find(u->attribs, &at_luxuries);
|
||||||
if (u->n < 0) {
|
if (!a) {
|
||||||
u->n = 0;
|
a = a_add(&u->attribs, a_new(&at_luxuries));
|
||||||
}
|
|
||||||
|
|
||||||
if (hafenowner) {
|
|
||||||
if (hafenowner->faction != u->faction) {
|
|
||||||
int abgezogenhafen = price / 10;
|
|
||||||
hafencollected += abgezogenhafen;
|
|
||||||
price -= abgezogenhafen;
|
|
||||||
money -= abgezogenhafen;
|
|
||||||
}
|
}
|
||||||
}
|
itm = (item *)a->data.v;
|
||||||
if (maxb) {
|
i_change(&itm, ltype->itype, 1);
|
||||||
if (maxowner->faction != u->faction) {
|
a->data.v = itm;
|
||||||
int abgezogensteuer = price * tax_per_size[maxeffsize] / 100;
|
++use;
|
||||||
taxcollected += abgezogensteuer;
|
if (u->n < 0) {
|
||||||
price -= abgezogensteuer;
|
u->n = 0;
|
||||||
money -= abgezogensteuer;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
u->n += price;
|
|
||||||
change_money(u, price);
|
|
||||||
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
|
||||||
|
|
||||||
/* r->money -= price; --- dies wird eben nicht ausgefuehrt, denn die
|
if (hafenowner) {
|
||||||
* Produkte koennen auch als Steuern eingetrieben werden. In der Region
|
if (hafenowner->faction != u->faction) {
|
||||||
* wurden Silberstuecke gegen Luxusgueter des selben Wertes eingetauscht!
|
int abgezogenhafen = price / 10;
|
||||||
* Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt
|
hafencollected += abgezogenhafen;
|
||||||
* die Nachfrage fuer das Produkt um 1. Der Zaehler wird wieder auf 0
|
price -= abgezogenhafen;
|
||||||
* gesetzt. */
|
money -= abgezogenhafen;
|
||||||
|
}
|
||||||
if (++counter[i] > max_products) {
|
}
|
||||||
int d = r_demand(r, ltype);
|
if (maxb) {
|
||||||
if (d > 1) {
|
if (maxowner->faction != u->faction) {
|
||||||
r_setdemand(r, ltype, d - 1);
|
int abgezogensteuer = price * tax_per_size[maxeffsize] / 100;
|
||||||
|
taxcollected += abgezogensteuer;
|
||||||
|
price -= abgezogensteuer;
|
||||||
|
money -= abgezogensteuer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u->n += price;
|
||||||
|
change_money(u, price);
|
||||||
|
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
||||||
|
|
||||||
|
/* r->money -= price; --- dies wird eben nicht ausgefuehrt, denn die
|
||||||
|
* Produkte koennen auch als Steuern eingetrieben werden. In der Region
|
||||||
|
* wurden Silberstuecke gegen Luxusgueter des selben Wertes eingetauscht!
|
||||||
|
* Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt
|
||||||
|
* die Nachfrage fuer das Produkt um 1. Der Zaehler wird wieder auf 0
|
||||||
|
* gesetzt. */
|
||||||
|
|
||||||
|
if (++counter[i] > max_products) {
|
||||||
|
int d = r_demand(r, ltype);
|
||||||
|
if (d > 1) {
|
||||||
|
r_setdemand(r, ltype, d - 1);
|
||||||
|
}
|
||||||
|
counter[i] = 0;
|
||||||
}
|
}
|
||||||
counter[i] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (use > 0) {
|
if (use > 0) {
|
||||||
use_pooled(g_requests[j]->unit, ltype->itype->rtype, GET_DEFAULT, use);
|
use_pooled(u, ltype->itype->rtype, GET_DEFAULT, use);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1561,7 +1569,6 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
attrib *a;
|
|
||||||
econ_request *o;
|
econ_request *o;
|
||||||
int k, available;
|
int k, available;
|
||||||
|
|
||||||
|
@ -1597,20 +1604,9 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
|
||||||
/* Ein Haendler kann nur 10 Gueter pro Talentpunkt handeln. */
|
/* Ein Haendler kann nur 10 Gueter pro Talentpunkt handeln. */
|
||||||
k = u->number * 10 * effskill(u, SK_TRADE, NULL);
|
k = u->number * 10 * effskill(u, SK_TRADE, NULL);
|
||||||
|
|
||||||
/* hat der Haendler bereits gehandelt, muss die Menge der bereits
|
|
||||||
* verkauften/gekauften Gueter abgezogen werden */
|
|
||||||
a = a_find(u->attribs, &at_trades);
|
|
||||||
if (!a) {
|
|
||||||
a = a_add(&u->attribs, a_new(&at_trades));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
k -= a->data.i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n > k) n = k;
|
if (n > k) n = k;
|
||||||
assert(n >= 0);
|
assert(n >= 0);
|
||||||
/* die Menge der verkauften Gueter merken */
|
/* die Menge der verkauften Gueter merken */
|
||||||
a->data.i += n;
|
|
||||||
o = (econ_request *)calloc(1, sizeof(econ_request));
|
o = (econ_request *)calloc(1, sizeof(econ_request));
|
||||||
if (!o) abort();
|
if (!o) abort();
|
||||||
o->unit = u;
|
o->unit = u;
|
||||||
|
|
|
@ -209,7 +209,7 @@ static void setup_terrains(CuTest *tc) {
|
||||||
static region *setup_trade_region(CuTest *tc, const struct terrain_type *terrain) {
|
static region *setup_trade_region(CuTest *tc, const struct terrain_type *terrain) {
|
||||||
region *r;
|
region *r;
|
||||||
item_type *it_luxury;
|
item_type *it_luxury;
|
||||||
struct locale * lang = default_locale;
|
struct locale * lang = test_create_locale();
|
||||||
|
|
||||||
new_luxurytype(it_luxury = test_create_itemtype("balm"), 5);
|
new_luxurytype(it_luxury = test_create_itemtype("balm"), 5);
|
||||||
locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name);
|
locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name);
|
||||||
|
@ -233,6 +233,36 @@ static unit *setup_trade_unit(CuTest *tc, region *r, const struct race *rc) {
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_trade_limits(CuTest *tc) {
|
||||||
|
region *r;
|
||||||
|
unit *u;
|
||||||
|
building *b;
|
||||||
|
const item_type *it_jewel, *it_balm;
|
||||||
|
|
||||||
|
test_setup();
|
||||||
|
setup_production();
|
||||||
|
setup_terrains(tc);
|
||||||
|
init_terrains();
|
||||||
|
r = setup_trade_region(tc, NULL);
|
||||||
|
b = test_create_building(r, test_create_buildingtype("castle"));
|
||||||
|
b->size = 2;
|
||||||
|
rsetpeasants(r, TRADE_FRACTION * 20);
|
||||||
|
it_jewel = it_find("jewel");
|
||||||
|
u = test_create_unit(test_create_faction(NULL), r);
|
||||||
|
set_level(u, SK_TRADE, 1);
|
||||||
|
i_change(&u->items, it_find("money"), 500);
|
||||||
|
unit_addorder(u, create_order(K_BUY, u->faction->locale, "5 %s",
|
||||||
|
LOC(u->faction->locale, resourcename(it_jewel->rtype, 0))));
|
||||||
|
it_balm = it_find("balm");
|
||||||
|
i_change(&u->items, it_balm, 10);
|
||||||
|
unit_addorder(u, create_order(K_SELL, u->faction->locale, "10 %s",
|
||||||
|
LOC(u->faction->locale, resourcename(it_balm->rtype, 0))));
|
||||||
|
produce(r);
|
||||||
|
CuAssertIntEquals(tc, 5, i_get(u->items, it_jewel));
|
||||||
|
CuAssertIntEquals(tc, 5, i_get(u->items, it_balm));
|
||||||
|
test_teardown();
|
||||||
|
}
|
||||||
|
|
||||||
static void test_trade_needs_castle(CuTest *tc) {
|
static void test_trade_needs_castle(CuTest *tc) {
|
||||||
/* Handeln ist nur in Regionen mit Burgen möglich. */
|
/* Handeln ist nur in Regionen mit Burgen möglich. */
|
||||||
race *rc;
|
race *rc;
|
||||||
|
@ -837,6 +867,7 @@ CuSuite *get_economy_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_heroes_dont_recruit);
|
SUITE_ADD_TEST(suite, test_heroes_dont_recruit);
|
||||||
SUITE_ADD_TEST(suite, test_tax_cmd);
|
SUITE_ADD_TEST(suite, test_tax_cmd);
|
||||||
SUITE_ADD_TEST(suite, test_buy_cmd);
|
SUITE_ADD_TEST(suite, test_buy_cmd);
|
||||||
|
SUITE_ADD_TEST(suite, test_trade_limits);
|
||||||
SUITE_ADD_TEST(suite, test_trade_needs_castle);
|
SUITE_ADD_TEST(suite, test_trade_needs_castle);
|
||||||
SUITE_ADD_TEST(suite, test_trade_insect);
|
SUITE_ADD_TEST(suite, test_trade_insect);
|
||||||
SUITE_ADD_TEST(suite, test_maintain_buildings);
|
SUITE_ADD_TEST(suite, test_maintain_buildings);
|
||||||
|
|
Loading…
Reference in New Issue