forked from github/server
eliminate construction.improvement,
create building_type.stages instead.
This commit is contained in:
parent
8a21b42b65
commit
b5b9611a16
17 changed files with 264 additions and 182 deletions
|
@ -17,9 +17,11 @@
|
|||
#include <util/functions.h>
|
||||
#include <util/rand.h>
|
||||
#include <util/rng.h>
|
||||
#include <util/strings.h>
|
||||
|
||||
#include <CuTest.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tests.h"
|
||||
|
@ -149,12 +151,17 @@ static building_type * setup_castle(void) {
|
|||
building_type * btype;
|
||||
construction *cons;
|
||||
|
||||
btype = bt_get_or_create("castle");
|
||||
btype = test_create_buildingtype("castle");
|
||||
assert(btype->stages);
|
||||
assert(btype->stages->construction);
|
||||
|
||||
btype->flags |= BTF_FORTIFICATION;
|
||||
cons = btype->construction = calloc(1, sizeof(construction));
|
||||
cons = btype->stages->construction;
|
||||
cons->maxsize = 5;
|
||||
cons = cons->improvement = calloc(1, sizeof(construction));
|
||||
btype->stages->next = calloc(1, sizeof(building_stage));
|
||||
cons = calloc(1, sizeof(construction));
|
||||
cons->maxsize = -1;
|
||||
btype->stages->next->construction = cons;
|
||||
return btype;
|
||||
}
|
||||
|
||||
|
@ -563,9 +570,11 @@ static void test_battle_skilldiff_building(CuTest *tc)
|
|||
td.index = 0;
|
||||
ta.fighter = setup_fighter(&b, ua);
|
||||
ta.index = 0;
|
||||
CuAssertIntEquals(tc, 0, buildingeffsize(ud->building, false));
|
||||
CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0));
|
||||
|
||||
ud->building->size = 10;
|
||||
CuAssertIntEquals(tc, 1, buildingeffsize(ud->building, false));
|
||||
CuAssertIntEquals(tc, -1, skilldiff(ta, td, 0));
|
||||
|
||||
create_curse(NULL, &ud->building->attribs, &ct_magicwalls, 1, 1, 1, 1);
|
||||
|
|
|
@ -770,26 +770,6 @@ static int config_get_btype(lua_State * L)
|
|||
}
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
if (btype->construction) {
|
||||
lua_pushstring(L, "build_skill_min");
|
||||
lua_pushinteger(L, btype->construction->minskill);
|
||||
lua_settable(L, -3);
|
||||
lua_pushstring(L, "build_skill_name");
|
||||
lua_pushstring(L, skillnames[btype->construction->skill]);
|
||||
lua_settable(L, -3);
|
||||
if (btype->construction->materials) {
|
||||
int i;
|
||||
lua_pushstring(L, "materials");
|
||||
lua_newtable(L);
|
||||
for (i = 0; btype->construction->materials[i].number; ++i) {
|
||||
lua_pushstring(L,
|
||||
btype->construction->materials[i].rtype->_name);
|
||||
lua_pushinteger(L, btype->construction->materials[i].number);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1409,7 +1409,7 @@ int make_cmd(unit * u, struct order *ord)
|
|||
if (pl && fval(pl, PFL_NOBUILD)) {
|
||||
cmistake(u, ord, 275, MSG_PRODUCE);
|
||||
}
|
||||
else if (btype->construction) {
|
||||
else if (btype->stages && btype->stages->construction) {
|
||||
int id = getid();
|
||||
build_building(u, btype, id, m, ord);
|
||||
}
|
||||
|
|
|
@ -151,20 +151,6 @@ static void json_construction(cJSON *json, construction **consp) {
|
|||
cJSON *child;
|
||||
construction * cons;
|
||||
|
||||
if (json->type == cJSON_Array) {
|
||||
int size = 0;
|
||||
for (child = json->child; child; child = child->next) {
|
||||
construction *cons = 0;
|
||||
json_construction(child, &cons);
|
||||
if (cons) {
|
||||
cons->maxsize -= size;
|
||||
size += cons->maxsize + size;
|
||||
*consp = cons;
|
||||
consp = &cons->improvement;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (json->type != cJSON_Object) {
|
||||
log_error("construction %s is not a json object: %d", json->string, json->type);
|
||||
return;
|
||||
|
@ -309,6 +295,57 @@ static void json_terrain(cJSON *json, terrain_type *ter) {
|
|||
}
|
||||
}
|
||||
|
||||
static void json_stage(cJSON *json, building_stage *stage) {
|
||||
cJSON *child;
|
||||
|
||||
if (json->type != cJSON_Object) {
|
||||
log_error("building stages is not a json object: %d", json->type);
|
||||
return;
|
||||
}
|
||||
for (child = json->child; child; child = child->next) {
|
||||
switch (child->type) {
|
||||
case cJSON_Object:
|
||||
if (strcmp(child->string, "construction") == 0) {
|
||||
json_construction(child, &stage->construction);
|
||||
}
|
||||
break;
|
||||
case cJSON_String:
|
||||
if (strcmp(child->string, "name") == 0) {
|
||||
stage->name = str_strdup(child->valuestring);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void json_stages(cJSON *json, building_type *bt) {
|
||||
cJSON *child;
|
||||
building_stage *stage, **sp = &bt->stages;
|
||||
int size = 0;
|
||||
|
||||
if (json->type != cJSON_Array) {
|
||||
log_error("building stages is not a json array: %d", json->type);
|
||||
return;
|
||||
}
|
||||
|
||||
for (child = json->child; child; child = child->next) {
|
||||
switch (child->type) {
|
||||
case cJSON_Object:
|
||||
stage = calloc(sizeof(building_stage), 1);
|
||||
json_stage(child, stage);
|
||||
if (stage->construction->maxsize > 0) {
|
||||
stage->construction->maxsize -= size;
|
||||
size += stage->construction->maxsize;
|
||||
}
|
||||
*sp = stage;
|
||||
sp = &stage->next;
|
||||
break;
|
||||
default:
|
||||
log_error("building stage contains non-object type %d", child->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void json_building(cJSON *json, building_type *bt) {
|
||||
cJSON *child;
|
||||
const char *flags[] = {
|
||||
|
@ -321,8 +358,10 @@ static void json_building(cJSON *json, building_type *bt) {
|
|||
for (child = json->child; child; child = child->next) {
|
||||
switch (child->type) {
|
||||
case cJSON_Array:
|
||||
if (strcmp(child->string, "construction") == 0) {
|
||||
json_construction(child, &bt->construction);
|
||||
if (strcmp(child->string, "stages") == 0) {
|
||||
if (!bt->stages) {
|
||||
json_stages(child, bt);
|
||||
}
|
||||
}
|
||||
else if (strcmp(child->string, "maintenance") == 0) {
|
||||
json_maintenance(child, &bt->maintenance);
|
||||
|
@ -333,9 +372,14 @@ static void json_building(cJSON *json, building_type *bt) {
|
|||
break;
|
||||
case cJSON_Object:
|
||||
if (strcmp(child->string, "construction") == 0) {
|
||||
json_construction(child, &bt->construction);
|
||||
/* simple, single-stage building */
|
||||
if (!bt->stages) {
|
||||
building_stage *stage = calloc(sizeof(building_stage), 1);
|
||||
json_construction(child, &stage->construction);
|
||||
bt->stages = stage;
|
||||
}
|
||||
}
|
||||
else if (strcmp(child->string, "maintenance") == 0) {
|
||||
if (strcmp(child->string, "maintenance") == 0) {
|
||||
json_maintenance(child, &bt->maintenance);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -110,7 +110,7 @@ static void test_prefixes(CuTest * tc)
|
|||
CuAssertPtrNotNull(tc, race_prefixes);
|
||||
CuAssertStrEquals(tc, "snow", race_prefixes[0]);
|
||||
CuAssertStrEquals(tc, "dark", race_prefixes[2]);
|
||||
CuAssertPtrEquals(tc, 0, race_prefixes[3]);
|
||||
CuAssertPtrEquals(tc, NULL, race_prefixes[3]);
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ static void test_races(CuTest * tc)
|
|||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, races);
|
||||
CuAssertPtrEquals(tc, NULL, races);
|
||||
json_config(json);
|
||||
|
||||
CuAssertPtrNotNull(tc, races);
|
||||
|
@ -222,7 +222,7 @@ static void test_findrace(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, json);
|
||||
test_setup();
|
||||
lang = get_or_create_locale("de");
|
||||
CuAssertPtrEquals(tc, 0, (void *)findrace("Zwerg", lang));
|
||||
CuAssertPtrEquals(tc, NULL, (void *)findrace("Zwerg", lang));
|
||||
|
||||
json_config(json);
|
||||
init_locale(lang);
|
||||
|
@ -245,9 +245,9 @@ static void test_items(CuTest * tc)
|
|||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, it_find("axe"));
|
||||
CuAssertPtrEquals(tc, 0, rt_find("axe"));
|
||||
CuAssertPtrEquals(tc, 0, (void *)get_resourcetype(R_HORSE));
|
||||
CuAssertPtrEquals(tc, NULL, it_find("axe"));
|
||||
CuAssertPtrEquals(tc, NULL, rt_find("axe"));
|
||||
CuAssertPtrEquals(tc, NULL, (void *)get_resourcetype(R_HORSE));
|
||||
|
||||
json_config(json);
|
||||
|
||||
|
@ -283,7 +283,7 @@ static void test_ships(CuTest * tc)
|
|||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, shiptypes);
|
||||
CuAssertPtrEquals(tc, NULL, shiptypes);
|
||||
json_config(json);
|
||||
|
||||
CuAssertPtrNotNull(tc, shiptypes);
|
||||
|
@ -301,7 +301,7 @@ static void test_ships(CuTest * tc)
|
|||
|
||||
CuAssertPtrNotNull(tc, st->coasts);
|
||||
CuAssertPtrEquals(tc, (void *)ter, (void *)st->coasts[0]);
|
||||
CuAssertPtrEquals(tc, 0, (void *)st->coasts[1]);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)st->coasts[1]);
|
||||
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
|
@ -309,28 +309,42 @@ static void test_ships(CuTest * tc)
|
|||
|
||||
static void test_castles(CuTest *tc) {
|
||||
const char * data = "{\"buildings\": { \"castle\" : { "
|
||||
"\"construction\" : ["
|
||||
"{ \"maxsize\" : 2 },"
|
||||
"{ \"maxsize\" : 8 }"
|
||||
"\"stages\" : ["
|
||||
"{ \"construction\": { \"maxsize\" : 2 }, \"name\": \"site\" },"
|
||||
"{ \"construction\": { \"maxsize\" : 8 } },"
|
||||
"{ \"construction\": { \"maxsize\" : -1 } }"
|
||||
"]}}}";
|
||||
|
||||
cJSON *json = cJSON_Parse(data);
|
||||
const building_type *bt;
|
||||
const building_stage *stage;
|
||||
const construction *con;
|
||||
|
||||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, buildingtypes);
|
||||
CuAssertPtrEquals(tc, NULL, buildingtypes);
|
||||
json_config(json);
|
||||
|
||||
CuAssertPtrNotNull(tc, buildingtypes);
|
||||
bt = bt_find("castle");
|
||||
CuAssertPtrNotNull(tc, bt);
|
||||
CuAssertPtrNotNull(tc, bt->construction);
|
||||
CuAssertIntEquals(tc, 2, bt->construction->maxsize);
|
||||
CuAssertPtrNotNull(tc, bt->construction->improvement);
|
||||
CuAssertIntEquals(tc, 6, bt->construction->improvement->maxsize);
|
||||
CuAssertPtrEquals(tc, 0, bt->construction->improvement->improvement);
|
||||
CuAssertPtrNotNull(tc, stage = bt->stages);
|
||||
CuAssertStrEquals(tc, "site", stage->name);
|
||||
CuAssertPtrNotNull(tc, con = stage->construction);
|
||||
CuAssertIntEquals(tc, 2, con->maxsize);
|
||||
|
||||
CuAssertPtrNotNull(tc, stage = stage->next);
|
||||
CuAssertPtrEquals(tc, NULL, stage->name);
|
||||
CuAssertPtrNotNull(tc, con = stage->construction);
|
||||
CuAssertIntEquals(tc, 6, con->maxsize);
|
||||
|
||||
CuAssertPtrNotNull(tc, stage = stage->next);
|
||||
CuAssertPtrNotNull(tc, con = stage->construction);
|
||||
CuAssertIntEquals(tc, -1, con->maxsize);
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, stage->next);
|
||||
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
}
|
||||
|
@ -344,7 +358,7 @@ static void test_spells(CuTest * tc)
|
|||
|
||||
test_setup();
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, find_spell("fireball"));
|
||||
CuAssertPtrEquals(tc, NULL, find_spell("fireball"));
|
||||
|
||||
json_config(json);
|
||||
sp = find_spell("fireball");
|
||||
|
@ -353,7 +367,7 @@ static void test_spells(CuTest * tc)
|
|||
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
CuAssertPtrEquals(tc, 0, find_spell("fireball"));
|
||||
CuAssertPtrEquals(tc, NULL, find_spell("fireball"));
|
||||
}
|
||||
|
||||
static const char * building_data = "{\"buildings\": { "
|
||||
|
@ -380,11 +394,12 @@ static void test_buildings(CuTest * tc)
|
|||
{
|
||||
cJSON *json = cJSON_Parse(building_data);
|
||||
const building_type *bt;
|
||||
const construction *con;
|
||||
|
||||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, buildingtypes);
|
||||
CuAssertPtrEquals(tc, NULL, buildingtypes);
|
||||
json_config(json);
|
||||
|
||||
CuAssertPtrNotNull(tc, buildingtypes);
|
||||
|
@ -406,17 +421,19 @@ static void test_buildings(CuTest * tc)
|
|||
CuAssertIntEquals(tc, MTF_VARIABLE, bt->maintenance[0].flags);
|
||||
CuAssertIntEquals(tc, 0, bt->maintenance[1].number);
|
||||
|
||||
CuAssertPtrNotNull(tc, bt->construction);
|
||||
CuAssertPtrNotNull(tc, bt->construction->materials);
|
||||
CuAssertIntEquals(tc, 2, bt->construction->materials[0].number);
|
||||
CuAssertPtrEquals(tc, (void *)get_resourcetype(R_STONE), (void *)bt->construction->materials[0].rtype);
|
||||
CuAssertIntEquals(tc, 1, bt->construction->materials[1].number);
|
||||
CuAssertPtrEquals(tc, (void *)get_resourcetype(R_IRON), (void *)bt->construction->materials[1].rtype);
|
||||
CuAssertIntEquals(tc, 0, bt->construction->materials[2].number);
|
||||
CuAssertIntEquals(tc, 10, bt->construction->reqsize);
|
||||
CuAssertIntEquals(tc, 20, bt->construction->maxsize);
|
||||
CuAssertIntEquals(tc, 1, bt->construction->minskill);
|
||||
CuAssertPtrEquals(tc, 0, bt->construction->improvement);
|
||||
CuAssertPtrNotNull(tc, bt->stages);
|
||||
CuAssertPtrEquals(tc, NULL, bt->stages->next);
|
||||
CuAssertPtrNotNull(tc, bt->stages->construction);
|
||||
CuAssertPtrNotNull(tc, con = bt->stages->construction);
|
||||
CuAssertPtrNotNull(tc, con->materials);
|
||||
CuAssertIntEquals(tc, 2, con->materials[0].number);
|
||||
CuAssertPtrEquals(tc, (void *)get_resourcetype(R_STONE), (void *)con->materials[0].rtype);
|
||||
CuAssertIntEquals(tc, 1, con->materials[1].number);
|
||||
CuAssertPtrEquals(tc, (void *)get_resourcetype(R_IRON), (void *)con->materials[1].rtype);
|
||||
CuAssertIntEquals(tc, 0, con->materials[2].number);
|
||||
CuAssertIntEquals(tc, 10, con->reqsize);
|
||||
CuAssertIntEquals(tc, 20, con->maxsize);
|
||||
CuAssertIntEquals(tc, 1, con->minskill);
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
}
|
||||
|
@ -483,7 +500,7 @@ static void test_configs(CuTest * tc)
|
|||
fwrite(building_data, 1, strlen(building_data), F);
|
||||
fclose(F);
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, buildingtypes);
|
||||
CuAssertPtrEquals(tc, NULL, buildingtypes);
|
||||
json_config(json);
|
||||
CuAssertPtrNotNull(tc, buildingtypes);
|
||||
if (remove("test.json")!=0 && errno==ENOENT) {
|
||||
|
@ -508,7 +525,7 @@ static void test_terrains(CuTest * tc)
|
|||
|
||||
test_setup();
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, (void *)get_terrain("plain"));
|
||||
CuAssertPtrEquals(tc, NULL, (void *)get_terrain("plain"));
|
||||
|
||||
json_config(json);
|
||||
ter = get_terrain("plain");
|
||||
|
@ -520,7 +537,7 @@ static void test_terrains(CuTest * tc)
|
|||
CuAssertPtrNotNull(tc, ter->herbs);
|
||||
CuAssertPtrEquals(tc, rt_get_or_create("h0"), ter->herbs[0]->rtype);
|
||||
CuAssertPtrEquals(tc, rt_get_or_create("h1"), ter->herbs[1]->rtype);
|
||||
CuAssertPtrEquals(tc, 0, (void *)ter->herbs[2]);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)ter->herbs[2]);
|
||||
CuAssertPtrNotNull(tc, ter->name); /* anything named "plain" uses plain_name() */
|
||||
CuAssertPtrNotNull(tc, ter->production);
|
||||
CuAssertPtrEquals(tc, rt_get_or_create("stone"), (resource_type *)ter->production[0].type);
|
||||
|
@ -529,7 +546,7 @@ static void test_terrains(CuTest * tc)
|
|||
CuAssertStrEquals(tc, "1d5", ter->production[0].divisor);
|
||||
CuAssertStrEquals(tc, "1d6", ter->production[0].startlevel);
|
||||
CuAssertPtrEquals(tc, rt_get_or_create("iron"), (resource_type *)ter->production[1].type);
|
||||
CuAssertPtrEquals(tc, 0, (void *)ter->production[2].type);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)ter->production[2].type);
|
||||
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
|
|
|
@ -145,13 +145,25 @@ static void destroy_road(unit * u, int nmax, struct order *ord)
|
|||
}
|
||||
}
|
||||
|
||||
static int recycle(unit *u, construction *con, int size) {
|
||||
/* TODO: Nicht an ZERST<53>RE mit Punktangabe angepasst! */
|
||||
int c;
|
||||
for (c = 0; con->materials[c].number; ++c) {
|
||||
const requirement *rq = con->materials + c;
|
||||
int num = (rq->number * size / con->reqsize) / 2;
|
||||
if (num) {
|
||||
change_resource(u, rq->rtype, num);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int destroy_cmd(unit * u, struct order *ord)
|
||||
{
|
||||
char token[128];
|
||||
ship *sh;
|
||||
unit *u2;
|
||||
region *r = u->region;
|
||||
const construction *con = NULL;
|
||||
int size = 0;
|
||||
const char *s;
|
||||
int n = INT_MAX;
|
||||
|
@ -194,6 +206,7 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
return 138;
|
||||
}
|
||||
if (n >= b->size) {
|
||||
building_stage *stage;
|
||||
/* destroy completly */
|
||||
/* all units leave the building */
|
||||
for (u2 = r->units; u2; u2 = u2->next) {
|
||||
|
@ -202,11 +215,13 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
}
|
||||
}
|
||||
ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u));
|
||||
con = b->type->construction;
|
||||
for (stage = b->type->stages; stage; stage = stage->next) {
|
||||
size = recycle(u, stage->construction, size);
|
||||
}
|
||||
remove_building(&r->buildings, b);
|
||||
}
|
||||
else {
|
||||
/* partial destroy */
|
||||
/* TODO: partial destroy does not recycle */
|
||||
b->size -= n;
|
||||
ADDMSG(&u->faction->msgs, msg_message("destroy_partial",
|
||||
"building unit", b, u));
|
||||
|
@ -234,7 +249,7 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
}
|
||||
ADDMSG(&u->faction->msgs, msg_message("shipdestroy",
|
||||
"unit region ship", u, r, sh));
|
||||
con = sh->type->construction;
|
||||
size = recycle(u, sh->type->construction, size);
|
||||
remove_ship(&sh->region->ships, sh);
|
||||
}
|
||||
else {
|
||||
|
@ -248,18 +263,6 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
cmistake(u, ord, 138, MSG_PRODUCE);
|
||||
return 138;
|
||||
}
|
||||
|
||||
if (con) {
|
||||
/* TODO: Nicht an ZERST<53>RE mit Punktangabe angepasst! */
|
||||
int c;
|
||||
for (c = 0; con->materials[c].number; ++c) {
|
||||
const requirement *rq = con->materials + c;
|
||||
int recycle = (rq->number * size / con->reqsize) / 2;
|
||||
if (recycle) {
|
||||
change_resource(u, rq->rtype, recycle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -668,7 +671,7 @@ static int build_failure(unit *u, order *ord, const building_type *btype, int wa
|
|||
break;
|
||||
case ENOMATERIALS:
|
||||
ADDMSG(&u->faction->msgs, msg_materials_required(u, ord,
|
||||
btype->construction, want));
|
||||
btype->stages->construction, want));
|
||||
break;
|
||||
case ELOWSKILL:
|
||||
case ENEEDSKILL:
|
||||
|
@ -679,9 +682,13 @@ static int build_failure(unit *u, order *ord, const building_type *btype, int wa
|
|||
return err;
|
||||
}
|
||||
|
||||
int build_stages(unit *u, construction * con, int built, int n) {
|
||||
static int build_stages(unit *u, const building_type *btype, int built, int n) {
|
||||
|
||||
const building_stage *stage;
|
||||
int made = 0;
|
||||
while (con) {
|
||||
|
||||
for (stage = btype->stages; stage; stage = stage->next) {
|
||||
const construction * con = stage->construction;
|
||||
if (con->maxsize < 0 || con->maxsize > built) {
|
||||
int err, want = INT_MAX;
|
||||
if (n < INT_MAX) {
|
||||
|
@ -719,7 +726,6 @@ int build_stages(unit *u, construction * con, int built, int n) {
|
|||
if (built >= con->maxsize && con->maxsize > 0) {
|
||||
built -= con->maxsize;
|
||||
}
|
||||
con = con->improvement;
|
||||
}
|
||||
return made;
|
||||
}
|
||||
|
@ -736,7 +742,7 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
const struct locale *lang = u->faction->locale;
|
||||
|
||||
assert(u->number);
|
||||
assert(btype->construction);
|
||||
assert(btype->stages && btype->stages->construction);
|
||||
if (effskill(u, SK_BUILDING, 0) == 0) {
|
||||
cmistake(u, ord, 101, MSG_PRODUCE);
|
||||
return 0;
|
||||
|
@ -827,7 +833,7 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
}
|
||||
}
|
||||
|
||||
built = build_stages(u, btype->construction, built, n);
|
||||
built = build_stages(u, btype, built, n);
|
||||
|
||||
if (built < 0) {
|
||||
return build_failure(u, ord, btype, want, built);
|
||||
|
@ -1002,7 +1008,6 @@ void continue_ship(unit * u, int want)
|
|||
return;
|
||||
}
|
||||
cons = sh->type->construction;
|
||||
assert(cons->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
||||
if (sh->size == cons->maxsize && !sh->damage) {
|
||||
cmistake(u, u->thisorder, 16, MSG_PRODUCE);
|
||||
return;
|
||||
|
@ -1026,11 +1031,6 @@ void continue_ship(unit * u, int want)
|
|||
|
||||
void free_construction(struct construction *cons)
|
||||
{
|
||||
while (cons) {
|
||||
construction *next = cons->improvement;
|
||||
free(cons->name);
|
||||
free(cons->materials);
|
||||
free(cons);
|
||||
cons = next;
|
||||
}
|
||||
free(cons->materials);
|
||||
free(cons);
|
||||
}
|
||||
|
|
|
@ -44,11 +44,6 @@ extern "C" {
|
|||
int maxsize; /* maximum size of this type */
|
||||
int reqsize; /* size of object using up 1 set of requirement. */
|
||||
requirement *materials; /* material req'd to build one object */
|
||||
|
||||
/* only used by CONS_BUILDING: */
|
||||
char * name; /* building level name */
|
||||
struct construction *improvement;
|
||||
/* next level, if upgradable. */
|
||||
} construction;
|
||||
|
||||
void free_construction(struct construction *cons);
|
||||
|
|
|
@ -26,6 +26,7 @@ typedef struct build_fixture {
|
|||
region *r;
|
||||
race *rc;
|
||||
construction cons;
|
||||
building_type *btype;
|
||||
} build_fixture;
|
||||
|
||||
static unit * setup_build(build_fixture *bf) {
|
||||
|
@ -34,7 +35,7 @@ static unit * setup_build(build_fixture *bf) {
|
|||
init_resources();
|
||||
|
||||
test_create_itemtype("stone");
|
||||
test_create_buildingtype("castle");
|
||||
bf->btype = test_create_buildingtype("castle");
|
||||
bf->rc = test_create_race("human");
|
||||
bf->r = test_create_region(0, 0, NULL);
|
||||
bf->f = test_create_faction(bf->rc);
|
||||
|
@ -192,8 +193,7 @@ static void test_build_building_no_materials(CuTest *tc) {
|
|||
unit *u;
|
||||
|
||||
u = setup_build(&bf);
|
||||
btype = bt_find("castle");
|
||||
assert(btype);
|
||||
btype = bf.btype;
|
||||
set_level(u, SK_BUILDING, 1);
|
||||
u->orders = create_order(K_MAKE, u->faction->locale, 0);
|
||||
CuAssertIntEquals(tc, ENOMATERIALS, build_building(u, btype, 0, 4, u->orders));
|
||||
|
@ -209,9 +209,7 @@ static void test_build_building_with_golem(CuTest *tc) {
|
|||
|
||||
u = setup_build(&bf);
|
||||
bf.rc->ec_flags |= ECF_STONEGOLEM;
|
||||
btype = bt_find("castle");
|
||||
assert(btype);
|
||||
assert(btype->construction);
|
||||
btype = bf.btype;
|
||||
|
||||
set_level(bf.u, SK_BUILDING, 1);
|
||||
u->orders = create_order(K_MAKE, u->faction->locale, 0);
|
||||
|
@ -231,9 +229,8 @@ static void test_build_building_success(CuTest *tc) {
|
|||
u = setup_build(&bf);
|
||||
|
||||
rtype = get_resourcetype(R_STONE);
|
||||
btype = bt_find("castle");
|
||||
btype = bf.btype;
|
||||
assert(btype && rtype && rtype->itype);
|
||||
assert(btype->construction);
|
||||
assert(!u->region->buildings);
|
||||
|
||||
i_change(&bf.u->items, rtype->itype, 1);
|
||||
|
|
|
@ -116,7 +116,13 @@ static void bt_register(building_type * btype)
|
|||
|
||||
static void free_buildingtype(void *ptr) {
|
||||
building_type *btype = (building_type *)ptr;
|
||||
free_construction(btype->construction);
|
||||
while (btype->stages) {
|
||||
building_stage *next = btype->stages->next;
|
||||
free_construction(btype->stages->construction);
|
||||
free(btype->stages->name);
|
||||
free(btype->stages);
|
||||
btype->stages = next;
|
||||
}
|
||||
free(btype->maintenance);
|
||||
free(btype->_name);
|
||||
free(btype);
|
||||
|
@ -189,8 +195,6 @@ static int adjust_size(const building *b, int bsize) {
|
|||
*/
|
||||
const char *buildingtype(const building_type * btype, const building * b, int bsize)
|
||||
{
|
||||
const construction *con;
|
||||
|
||||
assert(btype);
|
||||
|
||||
if (b && b->attribs) {
|
||||
|
@ -201,14 +205,15 @@ const char *buildingtype(const building_type * btype, const building * b, int bs
|
|||
}
|
||||
}
|
||||
}
|
||||
if (btype->construction && btype->construction->name) {
|
||||
if (btype->stages && btype->stages->name) {
|
||||
const building_stage *stage;
|
||||
if (b) {
|
||||
bsize = adjust_size(b, bsize);
|
||||
}
|
||||
for (con = btype->construction; con; con = con->improvement) {
|
||||
bsize -= con->maxsize;
|
||||
if (!con->improvement || bsize <0) {
|
||||
return con->name;
|
||||
for (stage = btype->stages; stage; stage = stage->next) {
|
||||
bsize -= stage->construction->maxsize;
|
||||
if (!stage->next || bsize <0) {
|
||||
return stage->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -476,24 +481,30 @@ int buildingeffsize(const building * b, int img)
|
|||
|
||||
int bt_effsize(const building_type * btype, const building * b, int bsize)
|
||||
{
|
||||
int n = 0;
|
||||
const construction *cons = btype->construction;
|
||||
|
||||
if (b) {
|
||||
bsize = adjust_size(b, bsize);
|
||||
}
|
||||
|
||||
if (!cons) {
|
||||
return 0;
|
||||
if (btype->stages) {
|
||||
int n = 0;
|
||||
const building_stage *stage = btype->stages;
|
||||
do {
|
||||
const construction *con = stage->construction;
|
||||
if (con->maxsize < 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (bsize >= con->maxsize) {
|
||||
bsize -= con->maxsize;
|
||||
++n;
|
||||
}
|
||||
stage = stage->next;
|
||||
}
|
||||
} while (stage && bsize > 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
while (cons && cons->maxsize != -1 && bsize >= cons->maxsize) {
|
||||
bsize -= cons->maxsize;
|
||||
cons = cons->improvement;
|
||||
++n;
|
||||
}
|
||||
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *write_buildingname(const building * b, char *ibuf, size_t size)
|
||||
|
|
|
@ -54,6 +54,15 @@ extern "C" {
|
|||
#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */
|
||||
#define BTF_FORTIFICATION 0x200 /* building_protection, safe from monsters */
|
||||
|
||||
typedef struct building_stage {
|
||||
/* construction of this building stage: */
|
||||
struct construction *construction;
|
||||
/* building stage name: */
|
||||
char * name;
|
||||
/* next stage, if upgradable: */
|
||||
struct building_stage * next;
|
||||
} building_stage;
|
||||
|
||||
typedef struct building_type {
|
||||
char *_name;
|
||||
|
||||
|
@ -67,8 +76,8 @@ extern "C" {
|
|||
int taxes; /* receive $1 tax per `taxes` in region */
|
||||
double auraregen; /* modifier for aura regeneration inside building */
|
||||
struct maintenance *maintenance; /* array of requirements */
|
||||
struct construction *construction; /* construction of 1 building-level */
|
||||
struct resource_mod *modifiers; /* modify production skills */
|
||||
struct building_stage *stages;
|
||||
} building_type;
|
||||
|
||||
extern struct selist *buildingtypes;
|
||||
|
|
|
@ -224,7 +224,7 @@ static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc)
|
|||
leave_building(u3);
|
||||
CuAssertPtrEquals(tc, u2, building_owner(bld));
|
||||
leave_building(u2);
|
||||
CuAssertPtrEquals(tc, 0, building_owner(bld));
|
||||
CuAssertPtrEquals(tc, NULL, building_owner(bld));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ void test_buildingowner_goes_to_empty_unit_after_leave(CuTest * tc)
|
|||
leave_building(u1);
|
||||
CuAssertPtrEquals(tc, u3, building_owner(bld));
|
||||
leave_building(u3);
|
||||
CuAssertPtrEquals(tc, 0, building_owner(bld));
|
||||
CuAssertPtrEquals(tc, NULL, building_owner(bld));
|
||||
u2->number = 1;
|
||||
CuAssertPtrEquals(tc, u2, building_owner(bld));
|
||||
test_teardown();
|
||||
|
@ -295,8 +295,8 @@ static void test_btype_defaults(CuTest *tc) {
|
|||
btype = bt_get_or_create("hodor");
|
||||
CuAssertPtrNotNull(tc, btype);
|
||||
CuAssertStrEquals(tc, "hodor", btype->_name);
|
||||
CuAssertPtrEquals(tc, 0, btype->maintenance);
|
||||
CuAssertPtrEquals(tc, 0, btype->construction);
|
||||
CuAssertPtrEquals(tc, NULL, btype->maintenance);
|
||||
CuAssertPtrEquals(tc, NULL, btype->stages);
|
||||
CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0);
|
||||
CuAssertIntEquals(tc, 0, btype->taxes);
|
||||
CuAssertIntEquals(tc, -1, btype->maxsize);
|
||||
|
@ -489,11 +489,11 @@ static void test_cmp_current_owner(CuTest *tc) {
|
|||
config_set("rules.region_owners", "1");
|
||||
r = test_create_region(0, 0, NULL);
|
||||
btype = test_create_buildingtype("watch");
|
||||
btype->construction->maxsize = 1;
|
||||
btype->stages->construction->maxsize = 1;
|
||||
btype->taxes = 200;
|
||||
b1 = test_create_building(r, btype);
|
||||
btype = test_create_buildingtype("castle");
|
||||
btype->construction->maxsize = 1;
|
||||
btype->stages->construction->maxsize = 1;
|
||||
btype->taxes = 100;
|
||||
b2 = test_create_building(r, btype);
|
||||
b1->size = 1;
|
||||
|
@ -515,16 +515,26 @@ static void test_cmp_current_owner(CuTest *tc) {
|
|||
static void test_building_effsize(CuTest *tc) {
|
||||
building *b;
|
||||
building_type *btype;
|
||||
building_stage *stage;
|
||||
construction *cons;
|
||||
|
||||
test_setup();
|
||||
btype = bt_get_or_create("castle");
|
||||
cons = btype->construction = calloc(1, sizeof(construction));
|
||||
btype = test_create_buildingtype("castle");
|
||||
stage = btype->stages;
|
||||
assert(stage && stage->construction);
|
||||
cons = stage->construction;
|
||||
cons->maxsize = 5;
|
||||
cons = cons->improvement = calloc(1, sizeof(construction));
|
||||
|
||||
stage->next = calloc(1, sizeof(building_stage));
|
||||
stage = stage->next;
|
||||
cons = stage->construction = calloc(1, sizeof(construction));
|
||||
cons->maxsize = 5;
|
||||
cons = cons->improvement = calloc(1, sizeof(construction));
|
||||
|
||||
stage->next = calloc(1, sizeof(building_stage));
|
||||
stage = stage->next;
|
||||
cons = stage->construction = calloc(1, sizeof(construction));
|
||||
cons->maxsize = -1;
|
||||
|
||||
b = test_create_building(test_create_region(0,0,0), btype);
|
||||
b->size = 1;
|
||||
CuAssertIntEquals(tc, 0, buildingeffsize(b, false));
|
||||
|
@ -563,14 +573,20 @@ static void test_largestbuilding(CuTest *tc) {
|
|||
static void test_buildingtype(CuTest *tc) {
|
||||
building_type *btype;
|
||||
test_setup();
|
||||
|
||||
btype = test_create_buildingtype("hodor");
|
||||
CuAssertPtrNotNull(tc, btype->construction);
|
||||
CuAssertPtrNotNull(tc, btype->stages);
|
||||
CuAssertPtrEquals(tc, NULL, btype->stages->name);
|
||||
CuAssertPtrNotNull(tc, btype->stages->construction);
|
||||
CuAssertStrEquals(tc, "hodor", buildingtype(btype, NULL, 1));
|
||||
btype->construction->name = str_strdup("castle");
|
||||
|
||||
btype->stages->name = str_strdup("castle");
|
||||
CuAssertStrEquals(tc, "castle", buildingtype(btype, NULL, 1));
|
||||
|
||||
btype = bt_get_or_create("portal");
|
||||
CuAssertPtrEquals(tc, NULL, btype->construction);
|
||||
CuAssertPtrEquals(tc, NULL, btype->stages);
|
||||
CuAssertStrEquals(tc, "portal", buildingtype(btype, NULL, 1));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
|
|
@ -900,7 +900,9 @@ void write_items(struct storage *store, item * ilist)
|
|||
|
||||
static void free_itype(item_type *itype) {
|
||||
assert(itype);
|
||||
free_construction(itype->construction);
|
||||
if (itype->construction) {
|
||||
free_construction(itype->construction);
|
||||
}
|
||||
free(itype->_appearance[0]);
|
||||
free(itype->_appearance[1]);
|
||||
free(itype);
|
||||
|
|
|
@ -249,7 +249,9 @@ static void free_shiptype(void *ptr) {
|
|||
ship_type *stype = (ship_type *)ptr;
|
||||
free(stype->_name);
|
||||
free(stype->coasts);
|
||||
free_construction(stype->construction);
|
||||
if (stype->construction) {
|
||||
free_construction(stype->construction);
|
||||
}
|
||||
free(stype);
|
||||
}
|
||||
|
||||
|
|
|
@ -477,7 +477,7 @@ static void test_illusioncastle(CuTest *tc)
|
|||
CuAssertPtrEquals(tc, btype, (void *)icastle_type(a));
|
||||
CuAssertPtrEquals(tc, bt_icastle, (void *)b->type);
|
||||
CuAssertStrEquals(tc, "castle", buildingtype(btype, b, b->size));
|
||||
btype->construction->name = str_strdup("site");
|
||||
btype->stages->name = str_strdup("site");
|
||||
CuAssertStrEquals(tc, "site", buildingtype(btype, b, b->size));
|
||||
test_teardown();
|
||||
}
|
||||
|
|
|
@ -479,10 +479,6 @@ static bool cansail(const region * r, ship * sh)
|
|||
{
|
||||
UNUSED_ARG(r);
|
||||
|
||||
/* sonst ist construction:: size nicht ship_type::maxsize */
|
||||
assert(!sh->type->construction
|
||||
|| sh->type->construction->improvement == NULL);
|
||||
|
||||
if (sh->type->construction && sh->size != sh->type->construction->maxsize) {
|
||||
return false;
|
||||
}
|
||||
|
@ -505,10 +501,6 @@ static double overload(const region * r, ship * sh)
|
|||
{
|
||||
UNUSED_ARG(r);
|
||||
|
||||
/* sonst ist construction:: size nicht ship_type::maxsize */
|
||||
assert(!sh->type->construction
|
||||
|| sh->type->construction->improvement == NULL);
|
||||
|
||||
if (sh->type->construction && sh->size != sh->type->construction->maxsize) {
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
|
29
src/tests.c
29
src/tests.c
|
@ -336,20 +336,27 @@ ship_type * test_create_shiptype(const char * name)
|
|||
|
||||
building_type * test_create_buildingtype(const char * name)
|
||||
{
|
||||
construction *con;
|
||||
building_type *btype = bt_get_or_create(name);
|
||||
btype->flags = BTF_NAMECHANGE;
|
||||
if (!btype->construction) {
|
||||
btype->construction = (construction *)calloc(sizeof(construction), 1);
|
||||
btype->construction->skill = SK_BUILDING;
|
||||
btype->construction->maxsize = -1;
|
||||
btype->construction->minskill = 1;
|
||||
btype->construction->reqsize = 1;
|
||||
if (btype->stages) {
|
||||
con = btype->stages->construction;
|
||||
} else {
|
||||
btype->stages = calloc(1, sizeof(building_stage));
|
||||
con = (construction *)calloc(1, sizeof(construction));
|
||||
if (con) {
|
||||
con->skill = SK_BUILDING;
|
||||
con->maxsize = -1;
|
||||
con->minskill = 1;
|
||||
con->reqsize = 1;
|
||||
btype->stages->construction = con;
|
||||
}
|
||||
}
|
||||
if (!btype->construction->materials) {
|
||||
btype->construction->materials = (requirement *)calloc(sizeof(requirement), 2);
|
||||
btype->construction->materials[1].number = 0;
|
||||
btype->construction->materials[0].number = 1;
|
||||
btype->construction->materials[0].rtype = get_resourcetype(R_STONE);
|
||||
if (con && !con->materials) {
|
||||
con->materials = (requirement *)calloc(2, sizeof(requirement));
|
||||
con->materials[1].number = 0;
|
||||
con->materials[0].number = 1;
|
||||
con->materials[0].rtype = get_resourcetype(R_STONE);
|
||||
}
|
||||
if (default_locale) {
|
||||
locale_setstring(default_locale, name, name);
|
||||
|
|
|
@ -253,23 +253,24 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodePtr node)
|
|||
static void
|
||||
xml_readconstructions(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, building_type *btype)
|
||||
{
|
||||
construction **consPtr = &btype->construction;
|
||||
building_stage **stage_ptr = &btype->stages;
|
||||
int k;
|
||||
|
||||
for (k = 0; k != nodeSet->nodeNr; ++k) {
|
||||
building_stage *stage = calloc(1, sizeof(building_stage));
|
||||
xmlNodePtr node = nodeSet->nodeTab[k];
|
||||
construction *con = xml_readconstruction(xpath, node);
|
||||
xmlChar *propValue = xmlGetProp(node, BAD_CAST "name");
|
||||
|
||||
if (propValue != NULL) {
|
||||
con->name = str_strdup((const char *)propValue);
|
||||
stage->name = str_strdup((const char *)propValue);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
stage->next = NULL;
|
||||
stage->construction = con;
|
||||
|
||||
if (con) {
|
||||
*consPtr = con;
|
||||
consPtr = &con->improvement;
|
||||
}
|
||||
*stage_ptr = stage;
|
||||
stage_ptr = &stage->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue