forked from github/server
Merge pull request #50 from badgerman/master
Bugfixes pre-release turn 901, new storage library.
This commit is contained in:
commit
7b47f5fa78
19 changed files with 642 additions and 434 deletions
33
scripts/fix1984.lua
Normal file
33
scripts/fix1984.lua
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
function recover(turn)
|
||||||
|
eressea.free_game()
|
||||||
|
eressea.read_game(turn .. ".dat")
|
||||||
|
ships = {}
|
||||||
|
bldgs = {}
|
||||||
|
for r in regions() do
|
||||||
|
for b in r.buildings do
|
||||||
|
if b.info~=nil and (string.len(b.info)>120) then
|
||||||
|
bldgs[b.id] = b.info
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for b in r.ships do
|
||||||
|
if b.info~=nil and (string.len(b.info)>120) then
|
||||||
|
ships[b.id] = b.info
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
eressea.free_game()
|
||||||
|
eressea.read_game((turn+1) .. ".dat")
|
||||||
|
for k, v in pairs(bldgs) do
|
||||||
|
b = get_building(k)
|
||||||
|
if b~=nil then
|
||||||
|
b.info = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for k, v in pairs(ships) do
|
||||||
|
b = get_ship(k)
|
||||||
|
if b~=nil then
|
||||||
|
b.info = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
eressea.write_game((turn+1) .. ".fixed")
|
||||||
|
end
|
|
@ -166,6 +166,7 @@ set(TESTS_SRC
|
||||||
economy.test.c
|
economy.test.c
|
||||||
json.test.c
|
json.test.c
|
||||||
keyword.test.c
|
keyword.test.c
|
||||||
|
give.test.c
|
||||||
laws.test.c
|
laws.test.c
|
||||||
magic.test.c
|
magic.test.c
|
||||||
market.test.c
|
market.test.c
|
||||||
|
|
|
@ -18,6 +18,8 @@ without prior permission by the authors of Eressea.
|
||||||
#include <kernel/version.h>
|
#include <kernel/version.h>
|
||||||
|
|
||||||
#include <storage.h>
|
#include <storage.h>
|
||||||
|
#include <stream.h>
|
||||||
|
#include <filestream.h>
|
||||||
#include <binarystore.h>
|
#include <binarystore.h>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -29,36 +31,37 @@ without prior permission by the authors of Eressea.
|
||||||
|
|
||||||
static int tolua_storage_create(lua_State * L)
|
static int tolua_storage_create(lua_State * L)
|
||||||
{
|
{
|
||||||
const char *filename = tolua_tostring(L, 1, 0);
|
const char *filename = tolua_tostring(L, 1, 0);
|
||||||
const char *type = tolua_tostring(L, 2, "rb");
|
const char *type = tolua_tostring(L, 2, "rb");
|
||||||
gamedata *data = (gamedata *)calloc(1, sizeof(gamedata));
|
gamedata *data = (gamedata *)calloc(1, sizeof(gamedata));
|
||||||
storage *store = (storage *)calloc(1, sizeof(storage));
|
storage *store = (storage *)calloc(1, sizeof(storage));
|
||||||
FILE * F;
|
FILE * F;
|
||||||
|
|
||||||
data->store = store;
|
data->store = store;
|
||||||
|
|
||||||
F = fopen(filename, type);
|
F = fopen(filename, type);
|
||||||
if (strchr(type, 'r')) {
|
if (strchr(type, 'r')) {
|
||||||
fread(&data->version, sizeof(int), 1, F);
|
fread(&data->version, sizeof(int), 1, F);
|
||||||
fseek(F, sizeof(int), SEEK_CUR);
|
fseek(F, sizeof(int), SEEK_CUR);
|
||||||
}
|
}
|
||||||
else if (strchr(type, 'w')) {
|
else if (strchr(type, 'w')) {
|
||||||
int n = STREAM_VERSION;
|
int n = STREAM_VERSION;
|
||||||
data->version = RELEASE_VERSION;
|
data->version = RELEASE_VERSION;
|
||||||
fwrite(&data->version, sizeof(int), 1, F);
|
fwrite(&data->version, sizeof(int), 1, F);
|
||||||
fwrite(&n, sizeof(int), 1, F);
|
fwrite(&n, sizeof(int), 1, F);
|
||||||
}
|
}
|
||||||
binstore_init(store, F);
|
fstream_init(&data->strm, F);
|
||||||
tolua_pushusertype(L, (void *)data, TOLUA_CAST "storage");
|
binstore_init(store, &data->strm);
|
||||||
return 1;
|
tolua_pushusertype(L, (void *)data, TOLUA_CAST "storage");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tolua_storage_read_unit(lua_State * L)
|
static int tolua_storage_read_unit(lua_State * L)
|
||||||
{
|
{
|
||||||
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
||||||
struct unit *u = read_unit(data);
|
struct unit *u = read_unit(data);
|
||||||
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
|
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tolua_storage_write_unit(lua_State * L)
|
static int tolua_storage_write_unit(lua_State * L)
|
||||||
|
@ -71,76 +74,78 @@ static int tolua_storage_write_unit(lua_State * L)
|
||||||
|
|
||||||
static int tolua_storage_read_float(lua_State * L)
|
static int tolua_storage_read_float(lua_State * L)
|
||||||
{
|
{
|
||||||
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
||||||
float num;
|
float num;
|
||||||
READ_FLT(data->store, &num);
|
READ_FLT(data->store, &num);
|
||||||
tolua_pushnumber(L, (lua_Number) num);
|
tolua_pushnumber(L, (lua_Number)num);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tolua_storage_read_int(lua_State * L)
|
static int tolua_storage_read_int(lua_State * L)
|
||||||
{
|
{
|
||||||
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
||||||
int num;
|
int num;
|
||||||
READ_INT(data->store, &num);
|
READ_INT(data->store, &num);
|
||||||
tolua_pushnumber(L, (lua_Number) num);
|
tolua_pushnumber(L, (lua_Number)num);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tolua_storage_write(lua_State * L)
|
static int tolua_storage_write(lua_State * L)
|
||||||
{
|
{
|
||||||
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
||||||
if (data->version && tolua_isnumber(L, 2, 0, 0)) {
|
if (data->version && tolua_isnumber(L, 2, 0, 0)) {
|
||||||
lua_Number num = tolua_tonumber(L, 2, 0);
|
lua_Number num = tolua_tonumber(L, 2, 0);
|
||||||
double n;
|
double n;
|
||||||
if (modf(num, &n) == 0.0) {
|
if (modf(num, &n) == 0.0) {
|
||||||
WRITE_INT(data->store, (int)num);
|
WRITE_INT(data->store, (int)num);
|
||||||
} else {
|
}
|
||||||
WRITE_FLT(data->store, (float)num);
|
else {
|
||||||
|
WRITE_FLT(data->store, (float)num);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tolua_storage_tostring(lua_State * L)
|
static int tolua_storage_tostring(lua_State * L)
|
||||||
{
|
{
|
||||||
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
||||||
char name[64];
|
char name[64];
|
||||||
_snprintf(name, sizeof(name), "<storage enc=%d ver=%d>", data->encoding,
|
_snprintf(name, sizeof(name), "<storage enc=%d ver=%d>", data->encoding,
|
||||||
data->version);
|
data->version);
|
||||||
lua_pushstring(L, name);
|
lua_pushstring(L, name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tolua_storage_close(lua_State * L)
|
static int tolua_storage_close(lua_State * L)
|
||||||
{
|
{
|
||||||
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
|
||||||
binstore_done(data->store);
|
binstore_done(data->store);
|
||||||
return 0;
|
fstream_done(&data->strm);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tolua_storage_open(lua_State * L)
|
void tolua_storage_open(lua_State * L)
|
||||||
{
|
{
|
||||||
/* register user types */
|
/* register user types */
|
||||||
tolua_usertype(L, TOLUA_CAST "storage");
|
tolua_usertype(L, TOLUA_CAST "storage");
|
||||||
|
|
||||||
tolua_module(L, NULL, 0);
|
tolua_module(L, NULL, 0);
|
||||||
tolua_beginmodule(L, NULL);
|
tolua_beginmodule(L, NULL);
|
||||||
{
|
|
||||||
tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "",
|
|
||||||
NULL);
|
|
||||||
tolua_beginmodule(L, TOLUA_CAST "storage");
|
|
||||||
{
|
{
|
||||||
tolua_function(L, TOLUA_CAST "__tostring", tolua_storage_tostring);
|
tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "",
|
||||||
tolua_function(L, TOLUA_CAST "write", tolua_storage_write);
|
NULL);
|
||||||
tolua_function(L, TOLUA_CAST "read_int", tolua_storage_read_int);
|
tolua_beginmodule(L, TOLUA_CAST "storage");
|
||||||
tolua_function(L, TOLUA_CAST "read_float", tolua_storage_read_float);
|
{
|
||||||
tolua_function(L, TOLUA_CAST "write_unit", tolua_storage_write_unit);
|
tolua_function(L, TOLUA_CAST "__tostring", tolua_storage_tostring);
|
||||||
tolua_function(L, TOLUA_CAST "read_unit", tolua_storage_read_unit);
|
tolua_function(L, TOLUA_CAST "write", tolua_storage_write);
|
||||||
tolua_function(L, TOLUA_CAST "close", tolua_storage_close);
|
tolua_function(L, TOLUA_CAST "read_int", tolua_storage_read_int);
|
||||||
tolua_function(L, TOLUA_CAST "create", tolua_storage_create);
|
tolua_function(L, TOLUA_CAST "read_float", tolua_storage_read_float);
|
||||||
|
tolua_function(L, TOLUA_CAST "write_unit", tolua_storage_write_unit);
|
||||||
|
tolua_function(L, TOLUA_CAST "read_unit", tolua_storage_read_unit);
|
||||||
|
tolua_function(L, TOLUA_CAST "close", tolua_storage_close);
|
||||||
|
tolua_function(L, TOLUA_CAST "create", tolua_storage_create);
|
||||||
|
}
|
||||||
|
tolua_endmodule(L);
|
||||||
}
|
}
|
||||||
tolua_endmodule(L);
|
tolua_endmodule(L);
|
||||||
}
|
|
||||||
tolua_endmodule(L);
|
|
||||||
}
|
}
|
||||||
|
|
297
src/economy.c
297
src/economy.c
|
@ -388,36 +388,6 @@ static int do_recruiting(recruitment * recruits, int available)
|
||||||
return recruited;
|
return recruited;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void feedback_give_not_allowed(unit * u, order * ord)
|
|
||||||
{
|
|
||||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden",
|
|
||||||
""));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool can_give(const unit * u, const unit * u2, const item_type * itype, int mask)
|
|
||||||
{
|
|
||||||
if (u2) {
|
|
||||||
if (u->faction != u2->faction) {
|
|
||||||
int rule = rule_give();
|
|
||||||
if (itype) {
|
|
||||||
assert(mask == 0);
|
|
||||||
if (itype->rtype->ltype)
|
|
||||||
mask |= GIVE_LUXURIES;
|
|
||||||
else if (fval(itype, ITF_HERB))
|
|
||||||
mask |= GIVE_HERBS;
|
|
||||||
else
|
|
||||||
mask |= GIVE_GOODS;
|
|
||||||
}
|
|
||||||
return (rule & mask) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int rule = rule_give();
|
|
||||||
return (rule & GIVE_PEASANTS) != 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_recruitments(recruitment * recruits)
|
void free_recruitments(recruitment * recruits)
|
||||||
{
|
{
|
||||||
while (recruits) {
|
while (recruits) {
|
||||||
|
@ -708,273 +678,6 @@ int give_control_cmd(unit * u, order * ord)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
message *check_give(const unit *u, const unit *u2, order * ord) {
|
|
||||||
if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) {
|
|
||||||
return msg_feedback(u, ord, "feedback_give_forbidden", "");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void give_cmd(unit * u, order * ord)
|
|
||||||
{
|
|
||||||
region *r = u->region;
|
|
||||||
unit *u2;
|
|
||||||
const char *s;
|
|
||||||
int n;
|
|
||||||
const item_type *itype;
|
|
||||||
param_t p;
|
|
||||||
plane *pl;
|
|
||||||
message *msg;
|
|
||||||
|
|
||||||
init_order(ord);
|
|
||||||
u2 = getunit(r, u->faction);
|
|
||||||
s = getstrtoken();
|
|
||||||
n = s ? atoip(s) : 0;
|
|
||||||
p = (n > 0) ? NOPARAM : findparam(s, u->faction->locale);
|
|
||||||
|
|
||||||
/* first, do all the ones that do not require HELP_GIVE or CONTACT */
|
|
||||||
if (p == P_CONTROL) {
|
|
||||||
/* handled in give_control_cmd */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!u2 && !getunitpeasants) {
|
|
||||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
|
||||||
""));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = check_give(u, u2, ord);
|
|
||||||
if (msg) {
|
|
||||||
ADDMSG(&u->faction->msgs, msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */
|
|
||||||
if (u2 && !alliedunit(u2, u->faction, HELP_GIVE)
|
|
||||||
&& !cansee(u->faction, r, u2, 0) && !ucontact(u2, u)
|
|
||||||
&& !fval(u2, UFL_TAKEALL)) {
|
|
||||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
|
||||||
""));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (u == u2) {
|
|
||||||
cmistake(u, ord, 8, MSG_COMMERCE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht
|
|
||||||
* wirklich einfach. */
|
|
||||||
pl = rplane(r);
|
|
||||||
if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) {
|
|
||||||
cmistake(u, ord, 268, MSG_COMMERCE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u2 && u_race(u2) == get_race(RC_SPELL)) {
|
|
||||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
|
||||||
""));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) {
|
|
||||||
cmistake(u, ord, 40, MSG_COMMERCE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p == P_HERBS) {
|
|
||||||
bool given = false;
|
|
||||||
if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!can_give(u, u2, NULL, GIVE_HERBS)) {
|
|
||||||
feedback_give_not_allowed(u, ord);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (u2 && !(u_race(u2)->ec_flags & GETITEM)) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!u2) {
|
|
||||||
if (!getunitpeasants) {
|
|
||||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord,
|
|
||||||
"feedback_unit_not_found", ""));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (u->items) {
|
|
||||||
item **itmp = &u->items;
|
|
||||||
while (*itmp) {
|
|
||||||
item *itm = *itmp;
|
|
||||||
const item_type *itype = itm->type;
|
|
||||||
if (fval(itype, ITF_HERB) && itm->number > 0) {
|
|
||||||
/* give_item ändert im fall,das man alles übergibt, die
|
|
||||||
* item-liste der unit, darum continue vor pointerumsetzten */
|
|
||||||
if (give_item(itm->number, itm->type, u, u2, ord) == 0) {
|
|
||||||
given = true;
|
|
||||||
if (*itmp != itm)
|
|
||||||
continue;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
itmp = &itm->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!given)
|
|
||||||
cmistake(u, ord, 38, MSG_COMMERCE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p == P_ZAUBER) {
|
|
||||||
cmistake(u, ord, 7, MSG_COMMERCE);
|
|
||||||
/* geht nimmer */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p == P_UNIT) { /* Einheiten uebergeben */
|
|
||||||
if (!(u_race(u)->ec_flags & GIVEUNIT)) {
|
|
||||||
cmistake(u, ord, 167, MSG_COMMERCE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
give_unit(u, u2, ord);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p == P_ANY) {
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) {
|
|
||||||
feedback_give_not_allowed(u, ord);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s = getstrtoken();
|
|
||||||
if (!s || *s == 0) { /* GIVE ALL items that you have */
|
|
||||||
|
|
||||||
/* do these checks once, not for each item we have: */
|
|
||||||
if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (u2 && !(u_race(u2)->ec_flags & GETITEM)) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* für alle items einmal prüfen, ob wir mehr als von diesem Typ
|
|
||||||
* reserviert ist besitzen und diesen Teil dann übergeben */
|
|
||||||
if (u->items) {
|
|
||||||
item **itmp = &u->items;
|
|
||||||
while (*itmp) {
|
|
||||||
item *itm = *itmp;
|
|
||||||
const item_type *itype = itm->type;
|
|
||||||
if (itm->number > 0
|
|
||||||
&& itm->number - get_reservation(u, itype->rtype) > 0) {
|
|
||||||
n = itm->number - get_reservation(u, itype->rtype);
|
|
||||||
if (give_item(n, itype, u, u2, ord) == 0) {
|
|
||||||
if (*itmp != itm)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
itmp = &itm->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isparam(s, u->faction->locale, P_PERSON)) {
|
|
||||||
if (!(u_race(u)->ec_flags & GIVEPERSON)) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
n = u->number;
|
|
||||||
give_men(n, u, u2, ord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
|
|
||||||
}
|
|
||||||
else if (u2 && !(u_race(u2)->ec_flags & GETITEM)) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
itype = finditemtype(s, u->faction->locale);
|
|
||||||
if (itype != NULL) {
|
|
||||||
item *i = *i_find(&u->items, itype);
|
|
||||||
if (i != NULL) {
|
|
||||||
if (can_give(u, u2, itype, 0)) {
|
|
||||||
n = i->number - get_reservation(u, itype->rtype);
|
|
||||||
give_item(n, itype, u, u2, ord);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
feedback_give_not_allowed(u, ord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (p == P_EACH) {
|
|
||||||
if (u2 == NULL) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "peasants_give_invalid", ""));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s = getstrtoken(); /* skip one ahead to get the amount. */
|
|
||||||
n = atoip(s); /* n: Anzahl */
|
|
||||||
n *= u2->number;
|
|
||||||
}
|
|
||||||
s = getstrtoken();
|
|
||||||
|
|
||||||
if (s == NULL) {
|
|
||||||
cmistake(u, ord, 113, MSG_COMMERCE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isparam(s, u->faction->locale, P_PERSON)) {
|
|
||||||
if (!(u_race(u)->ec_flags & GIVEPERSON)) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
give_men(n, u, u2, ord);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u2 != NULL) {
|
|
||||||
if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(u_race(u2)->ec_flags & GETITEM)) {
|
|
||||||
ADDMSG(&u->faction->msgs,
|
|
||||||
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
itype = finditemtype(s, u->faction->locale);
|
|
||||||
if (itype != NULL) {
|
|
||||||
if (can_give(u, u2, itype, 0)) {
|
|
||||||
give_item(n, itype, u, u2, ord);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
feedback_give_not_allowed(u, ord);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cmistake(u, ord, 123, MSG_COMMERCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int forget_cmd(unit * u, order * ord)
|
static int forget_cmd(unit * u, order * ord)
|
||||||
{
|
{
|
||||||
skill_t sk;
|
skill_t sk;
|
||||||
|
|
|
@ -37,11 +37,17 @@ extern "C" {
|
||||||
|
|
||||||
#define TRADE_FRACTION 100
|
#define TRADE_FRACTION 100
|
||||||
|
|
||||||
extern int income(const struct unit *u);
|
|
||||||
|
|
||||||
/* Wieviel Fremde eine Partei pro Woche aufnehmen kann */
|
/* Wieviel Fremde eine Partei pro Woche aufnehmen kann */
|
||||||
#define MAXNEWBIES 5
|
#define MAXNEWBIES 5
|
||||||
|
|
||||||
|
struct unit;
|
||||||
|
struct region;
|
||||||
|
struct faction;
|
||||||
|
struct order;
|
||||||
|
struct message;
|
||||||
|
|
||||||
|
int income(const struct unit *u);
|
||||||
|
|
||||||
void economics(struct region *r);
|
void economics(struct region *r);
|
||||||
void produce(struct region *r);
|
void produce(struct region *r);
|
||||||
void auto_work(struct region *r);
|
void auto_work(struct region *r);
|
||||||
|
@ -56,7 +62,6 @@ extern "C" {
|
||||||
extern void give_control(struct unit * u, struct unit * u2);
|
extern void give_control(struct unit * u, struct unit * u2);
|
||||||
|
|
||||||
struct message * check_steal(const struct unit * u, struct order *ord);
|
struct message * check_steal(const struct unit * u, struct order *ord);
|
||||||
struct message * check_give(const struct unit * u, const struct unit * u2, struct order *ord);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ struct steal {
|
||||||
struct faction *f;
|
struct faction *f;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void setup_steal(struct steal *env, terrain_type *ter, race *rc) {
|
static void setup_steal(struct steal *env, struct terrain_type *ter, struct race *rc) {
|
||||||
env->r = test_create_region(0, 0, ter);
|
env->r = test_create_region(0, 0, ter);
|
||||||
env->f = test_create_faction(rc);
|
env->f = test_create_faction(rc);
|
||||||
env->u = test_create_unit(env->f, env->r);
|
env->u = test_create_unit(env->f, env->r);
|
||||||
|
@ -72,7 +72,7 @@ static void setup_steal(struct steal *env, terrain_type *ter, race *rc) {
|
||||||
static void test_steal_okay(CuTest * tc) {
|
static void test_steal_okay(CuTest * tc) {
|
||||||
struct steal env;
|
struct steal env;
|
||||||
race *rc;
|
race *rc;
|
||||||
terrain_type *ter;
|
struct terrain_type *ter;
|
||||||
|
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
ter = test_create_terrain("plain", LAND_REGION);
|
ter = test_create_terrain("plain", LAND_REGION);
|
||||||
|
@ -114,50 +114,6 @@ static void test_steal_ocean(CuTest * tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct give {
|
|
||||||
struct unit *src, *dst;
|
|
||||||
struct region *r;
|
|
||||||
struct faction *f1, *f2;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void setup_give(struct give *env) {
|
|
||||||
terrain_type *ter = test_create_terrain("plain", LAND_REGION);
|
|
||||||
env->r = test_create_region(0, 0, ter);
|
|
||||||
env->src = test_create_unit(env->f1, env->r);
|
|
||||||
env->dst = test_create_unit(env->f2, env->r);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_give_okay(CuTest * tc) {
|
|
||||||
struct give env;
|
|
||||||
struct race * rc;
|
|
||||||
|
|
||||||
test_cleanup();
|
|
||||||
rc = test_create_race("human");
|
|
||||||
env.f2 = env.f1 = test_create_faction(rc);
|
|
||||||
setup_give(&env);
|
|
||||||
|
|
||||||
set_param(&global.parameters, "rules.give", "0");
|
|
||||||
CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, 0));
|
|
||||||
test_cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_give_denied_by_rules(CuTest * tc) {
|
|
||||||
struct give env;
|
|
||||||
struct race * rc;
|
|
||||||
struct message *msg;
|
|
||||||
|
|
||||||
test_cleanup();
|
|
||||||
rc = test_create_race("human");
|
|
||||||
env.f1 = test_create_faction(rc);
|
|
||||||
env.f2 = test_create_faction(rc);
|
|
||||||
setup_give(&env);
|
|
||||||
|
|
||||||
set_param(&global.parameters, "rules.give", "0");
|
|
||||||
CuAssertPtrNotNull(tc, msg=check_give(env.src, env.dst, 0));
|
|
||||||
msg_release(msg);
|
|
||||||
test_cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
CuSuite *get_economy_suite(void)
|
CuSuite *get_economy_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
@ -166,7 +122,5 @@ CuSuite *get_economy_suite(void)
|
||||||
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);
|
||||||
SUITE_ADD_TEST(suite, test_give_okay);
|
|
||||||
SUITE_ADD_TEST(suite, test_give_denied_by_rules);
|
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
303
src/give.c
303
src/give.c
|
@ -15,6 +15,7 @@
|
||||||
#include "give.h"
|
#include "give.h"
|
||||||
|
|
||||||
#include "economy.h"
|
#include "economy.h"
|
||||||
|
#include "laws.h"
|
||||||
|
|
||||||
/* kernel includes */
|
/* kernel includes */
|
||||||
#include <kernel/curse.h>
|
#include <kernel/curse.h>
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include <kernel/item.h>
|
#include <kernel/item.h>
|
||||||
#include <kernel/messages.h>
|
#include <kernel/messages.h>
|
||||||
#include <kernel/order.h>
|
#include <kernel/order.h>
|
||||||
|
#include <kernel/plane.h>
|
||||||
#include <kernel/pool.h>
|
#include <kernel/pool.h>
|
||||||
#include <kernel/race.h>
|
#include <kernel/race.h>
|
||||||
#include <kernel/region.h>
|
#include <kernel/region.h>
|
||||||
|
@ -38,6 +40,7 @@
|
||||||
#include <util/base36.h>
|
#include <util/base36.h>
|
||||||
#include <util/event.h>
|
#include <util/event.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
|
#include <util/parser.h>
|
||||||
|
|
||||||
/* libc includes */
|
/* libc includes */
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -59,6 +62,36 @@ static int GiveRestriction(void)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void feedback_give_not_allowed(unit * u, order * ord)
|
||||||
|
{
|
||||||
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden",
|
||||||
|
""));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool can_give(const unit * u, const unit * u2, const item_type * itype, int mask)
|
||||||
|
{
|
||||||
|
if (u2) {
|
||||||
|
if (u->faction != u2->faction) {
|
||||||
|
int rule = rule_give();
|
||||||
|
if (itype) {
|
||||||
|
assert(mask == 0);
|
||||||
|
if (itype->rtype->ltype)
|
||||||
|
mask |= GIVE_LUXURIES;
|
||||||
|
else if (fval(itype, ITF_HERB))
|
||||||
|
mask |= GIVE_HERBS;
|
||||||
|
else
|
||||||
|
mask |= GIVE_GOODS;
|
||||||
|
}
|
||||||
|
return (rule & mask) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int rule = rule_give();
|
||||||
|
return (rule & GIVE_PEASANTS) != 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_give(unit * u, unit * u2, int given, int received,
|
add_give(unit * u, unit * u2, int given, int received,
|
||||||
const resource_type * rtype, struct order *ord, int error)
|
const resource_type * rtype, struct order *ord, int error)
|
||||||
|
@ -456,3 +489,273 @@ void give_unit(unit * u, unit * u2, order * ord)
|
||||||
u_setfaction(u, u2->faction);
|
u_setfaction(u, u2->faction);
|
||||||
u2->faction->newbies += n;
|
u2->faction->newbies += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void give_cmd(unit * u, order * ord)
|
||||||
|
{
|
||||||
|
region *r = u->region;
|
||||||
|
unit *u2;
|
||||||
|
const char *s;
|
||||||
|
int n;
|
||||||
|
const item_type *itype;
|
||||||
|
param_t p;
|
||||||
|
plane *pl;
|
||||||
|
message *msg;
|
||||||
|
keyword_t kwd;
|
||||||
|
|
||||||
|
kwd = init_order(ord);
|
||||||
|
assert(kwd == K_GIVE);
|
||||||
|
u2 = getunit(r, u->faction);
|
||||||
|
s = getstrtoken();
|
||||||
|
n = s ? atoip(s) : 0;
|
||||||
|
p = (n > 0) ? NOPARAM : findparam(s, u->faction->locale);
|
||||||
|
|
||||||
|
/* first, do all the ones that do not require HELP_GIVE or CONTACT */
|
||||||
|
if (p == P_CONTROL) {
|
||||||
|
/* handled in give_control_cmd */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!u2 && !getunitpeasants) {
|
||||||
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
||||||
|
""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = check_give(u, u2, ord);
|
||||||
|
if (msg) {
|
||||||
|
ADDMSG(&u->faction->msgs, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */
|
||||||
|
if (u2 && !alliedunit(u2, u->faction, HELP_GIVE)
|
||||||
|
&& !cansee(u->faction, r, u2, 0) && !ucontact(u2, u)
|
||||||
|
&& !fval(u2, UFL_TAKEALL)) {
|
||||||
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
||||||
|
""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (u == u2) {
|
||||||
|
cmistake(u, ord, 8, MSG_COMMERCE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht
|
||||||
|
* wirklich einfach. */
|
||||||
|
pl = rplane(r);
|
||||||
|
if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) {
|
||||||
|
cmistake(u, ord, 268, MSG_COMMERCE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u2 && u_race(u2) == get_race(RC_SPELL)) {
|
||||||
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
||||||
|
""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) {
|
||||||
|
cmistake(u, ord, 40, MSG_COMMERCE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (p == P_HERBS) {
|
||||||
|
bool given = false;
|
||||||
|
if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!can_give(u, u2, NULL, GIVE_HERBS)) {
|
||||||
|
feedback_give_not_allowed(u, ord);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (u2 && !(u_race(u2)->ec_flags & GETITEM)) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!u2) {
|
||||||
|
if (!getunitpeasants) {
|
||||||
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord,
|
||||||
|
"feedback_unit_not_found", ""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (u->items) {
|
||||||
|
item **itmp = &u->items;
|
||||||
|
while (*itmp) {
|
||||||
|
item *itm = *itmp;
|
||||||
|
const item_type *itype = itm->type;
|
||||||
|
if (fval(itype, ITF_HERB) && itm->number > 0) {
|
||||||
|
/* give_item ändert im fall,das man alles übergibt, die
|
||||||
|
* item-liste der unit, darum continue vor pointerumsetzten */
|
||||||
|
if (give_item(itm->number, itm->type, u, u2, ord) == 0) {
|
||||||
|
given = true;
|
||||||
|
if (*itmp != itm)
|
||||||
|
continue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itmp = &itm->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!given)
|
||||||
|
cmistake(u, ord, 38, MSG_COMMERCE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (p == P_ZAUBER) {
|
||||||
|
cmistake(u, ord, 7, MSG_COMMERCE);
|
||||||
|
/* geht nimmer */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (p == P_UNIT) { /* Einheiten uebergeben */
|
||||||
|
if (!(u_race(u)->ec_flags & GIVEUNIT)) {
|
||||||
|
cmistake(u, ord, 167, MSG_COMMERCE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
give_unit(u, u2, ord);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (p == P_ANY) {
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) {
|
||||||
|
feedback_give_not_allowed(u, ord);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = getstrtoken();
|
||||||
|
if (!s || *s == 0) { /* GIVE ALL items that you have */
|
||||||
|
|
||||||
|
/* do these checks once, not for each item we have: */
|
||||||
|
if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (u2 && !(u_race(u2)->ec_flags & GETITEM)) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* für alle items einmal prüfen, ob wir mehr als von diesem Typ
|
||||||
|
* reserviert ist besitzen und diesen Teil dann übergeben */
|
||||||
|
if (u->items) {
|
||||||
|
item **itmp = &u->items;
|
||||||
|
while (*itmp) {
|
||||||
|
item *itm = *itmp;
|
||||||
|
const item_type *itype = itm->type;
|
||||||
|
if (itm->number > 0
|
||||||
|
&& itm->number - get_reservation(u, itype->rtype) > 0) {
|
||||||
|
n = itm->number - get_reservation(u, itype->rtype);
|
||||||
|
if (give_item(n, itype, u, u2, ord) == 0) {
|
||||||
|
if (*itmp != itm)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itmp = &itm->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isparam(s, u->faction->locale, P_PERSON)) {
|
||||||
|
if (!(u_race(u)->ec_flags & GIVEPERSON)) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
n = u->number;
|
||||||
|
give_men(n, u, u2, ord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
|
||||||
|
}
|
||||||
|
else if (u2 && !(u_race(u2)->ec_flags & GETITEM)) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
itype = finditemtype(s, u->faction->locale);
|
||||||
|
if (itype != NULL) {
|
||||||
|
item *i = *i_find(&u->items, itype);
|
||||||
|
if (i != NULL) {
|
||||||
|
if (can_give(u, u2, itype, 0)) {
|
||||||
|
n = i->number - get_reservation(u, itype->rtype);
|
||||||
|
give_item(n, itype, u, u2, ord);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
feedback_give_not_allowed(u, ord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (p == P_EACH) {
|
||||||
|
if (u2 == NULL) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "peasants_give_invalid", ""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = getstrtoken(); /* skip one ahead to get the amount. */
|
||||||
|
n = atoip(s); /* n: Anzahl */
|
||||||
|
n *= u2->number;
|
||||||
|
}
|
||||||
|
s = getstrtoken();
|
||||||
|
|
||||||
|
if (s == NULL) {
|
||||||
|
cmistake(u, ord, 113, MSG_COMMERCE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isparam(s, u->faction->locale, P_PERSON)) {
|
||||||
|
if (!(u_race(u)->ec_flags & GIVEPERSON)) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
give_men(n, u, u2, ord);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u2 != NULL) {
|
||||||
|
if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(u_race(u2)->ec_flags & GETITEM)) {
|
||||||
|
ADDMSG(&u->faction->msgs,
|
||||||
|
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
itype = finditemtype(s, u->faction->locale);
|
||||||
|
if (itype != NULL) {
|
||||||
|
if (can_give(u, u2, itype, 0)) {
|
||||||
|
give_item(n, itype, u, u2, ord);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
feedback_give_not_allowed(u, ord);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cmistake(u, ord, 123, MSG_COMMERCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
message *check_give(const unit *u, const unit *u2, order * ord) {
|
||||||
|
if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) {
|
||||||
|
return msg_feedback(u, ord, "feedback_give_forbidden", "");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
12
src/give.h
12
src/give.h
|
@ -16,11 +16,17 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int give_item(int want, const struct item_type *itype,
|
struct item_type;
|
||||||
|
struct order;
|
||||||
|
struct unit;
|
||||||
|
|
||||||
|
int give_item(int want, const struct item_type *itype,
|
||||||
struct unit *src, struct unit *dest, struct order *ord);
|
struct unit *src, struct unit *dest, struct order *ord);
|
||||||
extern void give_men(int n, struct unit *u, struct unit *u2,
|
void give_men(int n, struct unit *u, struct unit *u2,
|
||||||
struct order *ord);
|
struct order *ord);
|
||||||
extern void give_unit(struct unit *u, struct unit *u2, struct order *ord);
|
void give_unit(struct unit *u, struct unit *u2, struct order *ord);
|
||||||
|
void give_cmd(struct unit * u, struct order * ord);
|
||||||
|
struct message * check_give(const struct unit * u, const struct unit * u2, struct order *ord);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
117
src/give.test.c
Normal file
117
src/give.test.c
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#include <platform.h>
|
||||||
|
|
||||||
|
#include "give.h"
|
||||||
|
#include "economy.h"
|
||||||
|
|
||||||
|
#include <kernel/config.h>
|
||||||
|
#include <kernel/item.h>
|
||||||
|
#include <kernel/terrain.h>
|
||||||
|
#include <kernel/order.h>
|
||||||
|
#include <kernel/unit.h>
|
||||||
|
#include <kernel/faction.h>
|
||||||
|
|
||||||
|
#include <util/base36.h>
|
||||||
|
#include <util/language.h>
|
||||||
|
#include <util/message.h>
|
||||||
|
|
||||||
|
#include <CuTest.h>
|
||||||
|
#include <tests.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
struct give {
|
||||||
|
struct unit *src, *dst;
|
||||||
|
struct region *r;
|
||||||
|
struct faction *f1, *f2;
|
||||||
|
struct item_type * itype;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void setup_give(struct give *env) {
|
||||||
|
struct terrain_type *ter = test_create_terrain("plain", LAND_REGION);
|
||||||
|
env->r = test_create_region(0, 0, ter);
|
||||||
|
env->src = test_create_unit(env->f1, env->r);
|
||||||
|
env->dst = test_create_unit(env->f2, env->r);
|
||||||
|
env->itype = it_get_or_create(rt_get_or_create("money"));
|
||||||
|
env->itype->flags |= ITF_HERB;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_give(CuTest * tc) {
|
||||||
|
struct give env;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
env.f2 = env.f1 = test_create_faction(0);
|
||||||
|
setup_give(&env);
|
||||||
|
|
||||||
|
i_change(&env.src->items, env.itype, 10);
|
||||||
|
CuAssertIntEquals(tc, 0, give_item(10, env.itype, env.src, env.dst, 0));
|
||||||
|
CuAssertIntEquals(tc, 0, i_get(env.src->items, env.itype));
|
||||||
|
CuAssertIntEquals(tc, 10, i_get(env.dst->items, env.itype));
|
||||||
|
|
||||||
|
CuAssertIntEquals(tc, -1, give_item(10, env.itype, env.src, env.dst, 0));
|
||||||
|
CuAssertIntEquals(tc, 0, i_get(env.src->items, env.itype));
|
||||||
|
CuAssertIntEquals(tc, 10, i_get(env.dst->items, env.itype));
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_give_herbs(CuTest * tc) {
|
||||||
|
struct give env;
|
||||||
|
struct order *ord;
|
||||||
|
struct locale * lang;
|
||||||
|
char cmd[32];
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
test_create_world();
|
||||||
|
env.f2 = env.f1 = test_create_faction(0);
|
||||||
|
setup_give(&env);
|
||||||
|
i_change(&env.src->items, env.itype, 10);
|
||||||
|
|
||||||
|
lang = get_or_create_locale("test");
|
||||||
|
env.f1->locale = lang;
|
||||||
|
locale_setstring(lang, "KRAEUTER", "HERBS");
|
||||||
|
init_locale(lang);
|
||||||
|
_snprintf(cmd, sizeof(cmd), "%s HERBS", itoa36(env.dst->no));
|
||||||
|
ord = create_order(K_GIVE, lang, cmd);
|
||||||
|
assert(ord);
|
||||||
|
|
||||||
|
give_cmd(env.src, ord);
|
||||||
|
CuAssertIntEquals(tc, 0, i_get(env.src->items, env.itype));
|
||||||
|
CuAssertIntEquals(tc, 10, i_get(env.dst->items, env.itype));
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_give_okay(CuTest * tc) {
|
||||||
|
struct give env;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
env.f2 = env.f1 = test_create_faction(0);
|
||||||
|
setup_give(&env);
|
||||||
|
|
||||||
|
set_param(&global.parameters, "rules.give", "0");
|
||||||
|
CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, 0));
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_give_denied_by_rules(CuTest * tc) {
|
||||||
|
struct give env;
|
||||||
|
struct message *msg;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
env.f1 = test_create_faction(0);
|
||||||
|
env.f2 = test_create_faction(0);
|
||||||
|
setup_give(&env);
|
||||||
|
|
||||||
|
set_param(&global.parameters, "rules.give", "0");
|
||||||
|
CuAssertPtrNotNull(tc, msg = check_give(env.src, env.dst, 0));
|
||||||
|
msg_release(msg);
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
CuSuite *get_give_suite(void)
|
||||||
|
{
|
||||||
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
SUITE_ADD_TEST(suite, test_give);
|
||||||
|
SUITE_ADD_TEST(suite, test_give_herbs);
|
||||||
|
SUITE_ADD_TEST(suite, test_give_okay);
|
||||||
|
SUITE_ADD_TEST(suite, test_give_denied_by_rules);
|
||||||
|
return suite;
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
static group *ghash[GMAXHASH];
|
static group *ghash[GMAXHASH];
|
||||||
static int maxgid;
|
static int maxgid;
|
||||||
|
|
||||||
static group *new_group(faction * f, const char *name, int gid)
|
group *new_group(faction * f, const char *name, int gid)
|
||||||
{
|
{
|
||||||
group **gp = &f->groups;
|
group **gp = &f->groups;
|
||||||
int index = gid % GMAXHASH;
|
int index = gid % GMAXHASH;
|
||||||
|
@ -195,9 +195,10 @@ bool join_group(unit * u, const char *name)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_groups(struct storage *store, group * g)
|
void write_groups(struct storage *store, const faction * f)
|
||||||
{
|
{
|
||||||
while (g) {
|
group *g;
|
||||||
|
for (g = f->groups; g; g=g->next) {
|
||||||
ally *a;
|
ally *a;
|
||||||
WRITE_INT(store, g->gid);
|
WRITE_INT(store, g->gid);
|
||||||
WRITE_STR(store, g->name);
|
WRITE_STR(store, g->name);
|
||||||
|
@ -210,7 +211,6 @@ void write_groups(struct storage *store, group * g)
|
||||||
WRITE_INT(store, 0);
|
WRITE_INT(store, 0);
|
||||||
a_write(store, g->attribs, g);
|
a_write(store, g->attribs, g);
|
||||||
WRITE_SECTION(store);
|
WRITE_SECTION(store);
|
||||||
g = g->next;
|
|
||||||
}
|
}
|
||||||
WRITE_INT(store, 0);
|
WRITE_INT(store, 0);
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,6 @@ void read_groups(struct storage *store, faction * f)
|
||||||
if (!a->faction)
|
if (!a->faction)
|
||||||
ur_add(fid, &a->faction, resolve_faction);
|
ur_add(fid, &a->faction, resolve_faction);
|
||||||
}
|
}
|
||||||
*pa = 0;
|
|
||||||
a_read(store, &g->attribs, g);
|
a_read(store, &g->attribs, g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,9 @@ extern "C" {
|
||||||
extern void set_group(struct unit *u, struct group *g);
|
extern void set_group(struct unit *u, struct group *g);
|
||||||
extern struct group * get_group(const struct unit *u);
|
extern struct group * get_group(const struct unit *u);
|
||||||
extern void free_group(struct group *g);
|
extern void free_group(struct group *g);
|
||||||
|
struct group *new_group(struct faction * f, const char *name, int gid);
|
||||||
|
|
||||||
extern void write_groups(struct storage *data, struct group *g);
|
extern void write_groups(struct storage *data, const struct faction *f);
|
||||||
extern void read_groups(struct storage *data, struct faction *f);
|
extern void read_groups(struct storage *data, struct faction *f);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -1,14 +1,58 @@
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "ally.h"
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
#include "faction.h"
|
#include "faction.h"
|
||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
|
#include <stream.h>
|
||||||
|
#include <filestream.h>
|
||||||
|
#include <storage.h>
|
||||||
|
#include <binarystore.h>
|
||||||
|
|
||||||
#include <CuTest.h>
|
#include <CuTest.h>
|
||||||
#include <tests.h>
|
#include <tests.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
static void test_group_readwrite(CuTest * tc)
|
||||||
|
{
|
||||||
|
faction * f;
|
||||||
|
group *g;
|
||||||
|
ally *al;
|
||||||
|
storage store;
|
||||||
|
FILE *F;
|
||||||
|
stream strm;
|
||||||
|
|
||||||
|
F = fopen("test.dat", "wb");
|
||||||
|
fstream_init(&strm, F);
|
||||||
|
binstore_init(&store, &strm);
|
||||||
|
test_cleanup();
|
||||||
|
test_create_world();
|
||||||
|
f = test_create_faction(0);
|
||||||
|
g = new_group(f, "test", 42);
|
||||||
|
al = ally_add(&g->allies, f);
|
||||||
|
al->status = HELP_GIVE;
|
||||||
|
write_groups(&store, f);
|
||||||
|
binstore_done(&store);
|
||||||
|
fstream_done(&strm);
|
||||||
|
|
||||||
|
F = fopen("test.dat", "rb");
|
||||||
|
fstream_init(&strm, F);
|
||||||
|
binstore_init(&store, &strm);
|
||||||
|
f->groups = 0;
|
||||||
|
free_group(g);
|
||||||
|
read_groups(&store, f);
|
||||||
|
binstore_done(&store);
|
||||||
|
fstream_done(&strm);
|
||||||
|
|
||||||
|
CuAssertPtrNotNull(tc, f->groups);
|
||||||
|
CuAssertPtrNotNull(tc, f->groups->allies);
|
||||||
|
CuAssertPtrEquals(tc, 0, f->groups->allies->next);
|
||||||
|
CuAssertPtrEquals(tc, f, f->groups->allies->faction);
|
||||||
|
CuAssertIntEquals(tc, HELP_GIVE, f->groups->allies->status);
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
static void test_group(CuTest * tc)
|
static void test_group(CuTest * tc)
|
||||||
{
|
{
|
||||||
unit *u;
|
unit *u;
|
||||||
|
@ -40,6 +84,7 @@ CuSuite *get_group_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
SUITE_ADD_TEST(suite, test_group);
|
SUITE_ADD_TEST(suite, test_group);
|
||||||
|
SUITE_ADD_TEST(suite, test_group_readwrite);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ int count)
|
||||||
}
|
}
|
||||||
if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) {
|
if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) {
|
||||||
for (v = r->units; v && use < count; v = v->next)
|
for (v = r->units; v && use < count; v = v->next)
|
||||||
if (u != v && (u->items || rtype->uget)) {
|
if (u != v && (v->items || rtype->uget)) {
|
||||||
int mask;
|
int mask;
|
||||||
|
|
||||||
if ((urace(v)->ec_flags & GIVEITEM) == 0)
|
if ((urace(v)->ec_flags & GIVEITEM) == 0)
|
||||||
|
|
|
@ -87,6 +87,27 @@ void test_pool(CuTest *tc) {
|
||||||
CuAssertIntEquals(tc, 300, get_pooled(u1, rtype, GET_ALL, INT_MAX));
|
CuAssertIntEquals(tc, 300, get_pooled(u1, rtype, GET_ALL, INT_MAX));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_pool_bug_2042(CuTest *tc) {
|
||||||
|
unit *u1, *u2;
|
||||||
|
faction *f;
|
||||||
|
region *r;
|
||||||
|
struct resource_type *rtype;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
test_create_world();
|
||||||
|
rtype = rt_get_or_create("money");
|
||||||
|
it_get_or_create(rtype);
|
||||||
|
f = test_create_faction(0);
|
||||||
|
r = findregion(0, 0);
|
||||||
|
assert(r && f && rtype && rtype->itype);
|
||||||
|
u1 = test_create_unit(f, r);
|
||||||
|
u2 = test_create_unit(f, r);
|
||||||
|
assert(u1 && u2);
|
||||||
|
i_change(&u2->items, rtype->itype, 100);
|
||||||
|
|
||||||
|
CuAssertIntEquals(tc, 100, get_pooled(u1, rtype, GET_SLACK | GET_POOLED_SLACK, 100));
|
||||||
|
}
|
||||||
|
|
||||||
void test_pool_use(CuTest *tc) {
|
void test_pool_use(CuTest *tc) {
|
||||||
unit *u1, *u2, *u3;
|
unit *u1, *u2, *u3;
|
||||||
faction *f;
|
faction *f;
|
||||||
|
@ -165,6 +186,7 @@ CuSuite *get_pool_suite(void)
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
SUITE_ADD_TEST(suite, test_reservation);
|
SUITE_ADD_TEST(suite, test_reservation);
|
||||||
SUITE_ADD_TEST(suite, test_pool);
|
SUITE_ADD_TEST(suite, test_pool);
|
||||||
|
SUITE_ADD_TEST(suite, test_pool_bug_2042);
|
||||||
SUITE_ADD_TEST(suite, test_pool_use);
|
SUITE_ADD_TEST(suite, test_pool_use);
|
||||||
SUITE_ADD_TEST(suite, test_change_resource);
|
SUITE_ADD_TEST(suite, test_change_resource);
|
||||||
return suite;
|
return suite;
|
||||||
|
|
|
@ -70,6 +70,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <util/umlaut.h>
|
#include <util/umlaut.h>
|
||||||
#include <util/unicode.h>
|
#include <util/unicode.h>
|
||||||
|
|
||||||
|
#include <stream.h>
|
||||||
|
#include <filestream.h>
|
||||||
#include <storage.h>
|
#include <storage.h>
|
||||||
#include <binarystore.h>
|
#include <binarystore.h>
|
||||||
|
|
||||||
|
@ -1439,7 +1441,7 @@ void writefaction(struct gamedata *data, const faction * f)
|
||||||
}
|
}
|
||||||
WRITE_INT(data->store, 0);
|
WRITE_INT(data->store, 0);
|
||||||
WRITE_SECTION(data->store);
|
WRITE_SECTION(data->store);
|
||||||
write_groups(data->store, f->groups);
|
write_groups(data->store, f);
|
||||||
write_spellbook(f->spellbook, data->store);
|
write_spellbook(f->spellbook, data->store);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1457,6 +1459,7 @@ int readgame(const char *filename, int backup)
|
||||||
const struct building_type *bt_lighthouse = bt_find("lighthouse");
|
const struct building_type *bt_lighthouse = bt_find("lighthouse");
|
||||||
gamedata gdata = { 0 };
|
gamedata gdata = { 0 };
|
||||||
storage store;
|
storage store;
|
||||||
|
stream strm;
|
||||||
FILE *F;
|
FILE *F;
|
||||||
|
|
||||||
init_locales();
|
init_locales();
|
||||||
|
@ -1482,7 +1485,8 @@ int readgame(const char *filename, int backup)
|
||||||
assert(gdata.version <= RELEASE_VERSION || !"unsupported data format");
|
assert(gdata.version <= RELEASE_VERSION || !"unsupported data format");
|
||||||
|
|
||||||
gdata.encoding = enc_gamedata;
|
gdata.encoding = enc_gamedata;
|
||||||
binstore_init(&store, F);
|
fstream_init(&strm, F);
|
||||||
|
binstore_init(&store, &strm);
|
||||||
gdata.store = &store;
|
gdata.store = &store;
|
||||||
global.data_version = gdata.version; /* HACK: attribute::read does not have access to gamedata, only storage */
|
global.data_version = gdata.version; /* HACK: attribute::read does not have access to gamedata, only storage */
|
||||||
|
|
||||||
|
@ -1733,7 +1737,7 @@ int readgame(const char *filename, int backup)
|
||||||
read_borders(&store);
|
read_borders(&store);
|
||||||
|
|
||||||
binstore_done(&store);
|
binstore_done(&store);
|
||||||
|
fstream_done(&strm);
|
||||||
/* Unaufgeloeste Zeiger initialisieren */
|
/* Unaufgeloeste Zeiger initialisieren */
|
||||||
log_printf(stdout, "fixing unresolved references.\n");
|
log_printf(stdout, "fixing unresolved references.\n");
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -1797,6 +1801,7 @@ int writegame(const char *filename)
|
||||||
char path[MAX_PATH];
|
char path[MAX_PATH];
|
||||||
gamedata gdata;
|
gamedata gdata;
|
||||||
storage store;
|
storage store;
|
||||||
|
stream strm;
|
||||||
FILE *F;
|
FILE *F;
|
||||||
|
|
||||||
clear_monster_orders();
|
clear_monster_orders();
|
||||||
|
@ -1826,7 +1831,8 @@ int writegame(const char *filename)
|
||||||
fwrite(&gdata.version, sizeof(int), 1, F);
|
fwrite(&gdata.version, sizeof(int), 1, F);
|
||||||
fwrite(&n, sizeof(int), 1, F);
|
fwrite(&n, sizeof(int), 1, F);
|
||||||
|
|
||||||
binstore_init(&store, F);
|
fstream_init(&strm, F);
|
||||||
|
binstore_init(&store, &strm);
|
||||||
|
|
||||||
/* globale Variablen */
|
/* globale Variablen */
|
||||||
|
|
||||||
|
@ -1942,6 +1948,7 @@ int writegame(const char *filename)
|
||||||
WRITE_SECTION(&store);
|
WRITE_SECTION(&store);
|
||||||
|
|
||||||
binstore_done(&store);
|
binstore_done(&store);
|
||||||
|
fstream_done(&strm);
|
||||||
|
|
||||||
log_printf(stdout, "\nOk.\n");
|
log_printf(stdout, "\nOk.\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -18,6 +18,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
#ifndef H_KRNL_SAVE
|
#ifndef H_KRNL_SAVE
|
||||||
#define H_KRNL_SAVE
|
#define H_KRNL_SAVE
|
||||||
|
|
||||||
|
#include <stream.h>
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,6 +33,7 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct gamedata {
|
typedef struct gamedata {
|
||||||
struct storage *store;
|
struct storage *store;
|
||||||
|
stream strm;
|
||||||
int version;
|
int version;
|
||||||
int encoding;
|
int encoding;
|
||||||
} gamedata;
|
} gamedata;
|
||||||
|
|
|
@ -18,6 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
#ifndef H_GC_LAWS
|
#ifndef H_GC_LAWS
|
||||||
#define H_GC_LAWS
|
#define H_GC_LAWS
|
||||||
|
|
||||||
|
#include <kernel/types.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -57,6 +57,7 @@ int RunAllTests(void)
|
||||||
/* gamecode */
|
/* gamecode */
|
||||||
ADD_TESTS(suite, battle);
|
ADD_TESTS(suite, battle);
|
||||||
ADD_TESTS(suite, economy);
|
ADD_TESTS(suite, economy);
|
||||||
|
ADD_TESTS(suite, give);
|
||||||
ADD_TESTS(suite, laws);
|
ADD_TESTS(suite, laws);
|
||||||
ADD_TESTS(suite, market);
|
ADD_TESTS(suite, market);
|
||||||
ADD_TESTS(suite, move);
|
ADD_TESTS(suite, move);
|
||||||
|
|
2
storage
2
storage
|
@ -1 +1 @@
|
||||||
Subproject commit c6103e59c0938b173c0e08a852ff1cbbc4e284e3
|
Subproject commit 5f0b7095d42209762c9eac73c866c614018b440d
|
Loading…
Reference in a new issue