Skip to content
101 changes: 70 additions & 31 deletions src/building/building.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ building *building_get(unsigned int id)

int building_can_repair_type(building_type type)
{
if (building_monument_is_limited(type) || type == BUILDING_AQUEDUCT || building_is_fort(type)) {
return 0; // limited monuments and aqueducts cannot be repaired at the moment, aqueducts require a rework,
} //and limited monuments are too complex to easily repair, and arent a common occurrence
if (building_monument_is_limited(type) || building_is_fort(type)) {
return 0; // limited monuments cannot be repaired at the moment,
} // as they are too complex to easily repair, and arent a common occurrence
// forts have the complexity of holding formations, so are also currently excluded
building_type repair_type = building_clone_type_from_building_type(type);
if (repair_type == BUILDING_NONE) {
Expand All @@ -79,6 +79,7 @@ int building_can_repair_type(building_type type)
return 1;
}
}

int building_dist(int x, int y, int w, int h, building *b)
{
int size = building_properties_for_type(b->type)->size;
Expand Down Expand Up @@ -212,14 +213,23 @@ static void remove_adjacent_types(building *b)
building *building_create(building_type type, int x, int y)
{
building *b;

const building_properties *props = building_properties_for_type(type);

if (props->shared) {
b = building_first_of_type(type);
if (b) {
return b;
}
}

array_new_item_after_index(data.buildings, 1, b);

if (!b) {
city_warning_show(WARNING_DATA_LIMIT_REACHED, NEW_WARNING_SLOT);
return array_first(data.buildings);
}

const building_properties *props = building_properties_for_type(type);

b->state = BUILDING_STATE_CREATED;
b->faction_id = 1;
b->type = type;
Expand Down Expand Up @@ -281,9 +291,12 @@ building *building_create(building_type type, int x, int y)
building_distribution_accept_all_goods(b);
}

b->x = x;
b->y = y;
b->grid_offset = map_grid_offset(x, y);
if (!props->shared) {
b->x = x;
b->y = y;
b->grid_offset = map_grid_offset(x, y);
}

b->house_figure_generation_delay = map_random_get(b->grid_offset) & 0x7f;
b->figure_roam_direction = b->house_figure_generation_delay & 6;
b->fire_proof = props->fire_proof;
Expand All @@ -302,8 +315,14 @@ void building_change_type(building *b, building_type type)
fill_adjacent_types(b);
}

static void building_delete(building *b)
void building_delete(building *b)
{
if (building_properties_for_type(b->type)->shared && b == building_first_of_type(b->type)) {
if (b->subtype.instances > 0) {
b->subtype.instances--;
}
return; // shared building types should never be deleted, unless the building type is repeated
}
building_clear_related_data(b);
remove_adjacent_types(b);
int id = b->id;
Expand Down Expand Up @@ -393,24 +412,30 @@ int building_can_repair(building *b)
return 1;
}
} else {
if (b->state != BUILDING_STATE_RUBBLE) {
if (b->state != BUILDING_STATE_RUBBLE && !building_properties_for_type(b->type)->shared) {
return 0;
} else {
return building_can_repair_type(b->type);
}
}
}

int building_repair_cost(building *b)
int building_repair_cost_at(int grid_offset)
{
building *b = building_get(map_building_rubble_building_id(grid_offset));
int og_grid_offset = 0, og_size = 0, og_type = 0;
if (!b || !building_can_repair(b)) {
return 0;
}
int is_ruin = b->type == BUILDING_BURNING_RUIN || // ruins and collapsed warehouse parts all use rubble data
b->type == BUILDING_WAREHOUSE_SPACE || b->type == BUILDING_WAREHOUSE;

og_grid_offset = is_ruin ? b->data.rubble.og_grid_offset : b->grid_offset;
if (building_properties_for_type(b->type)->shared) {
og_grid_offset = grid_offset;
} else {
og_grid_offset = is_ruin ? b->data.rubble.og_grid_offset : b->grid_offset;
}

og_size = is_ruin ? b->data.rubble.og_size : b->size;
og_type = is_ruin ? b->data.rubble.og_type : b->type;

Expand All @@ -437,18 +462,25 @@ static int get_rubble_data(building *b, int *og_size, int *og_grid_offset, int *
return 0;
}

int has = b->data.rubble.og_size || b->data.rubble.og_grid_offset ||
b->data.rubble.og_orientation || b->data.rubble.og_type;

if (!has) {
if (!b->data.rubble.og_size && !b->data.rubble.og_grid_offset &&
!b->data.rubble.og_orientation && !b->data.rubble.og_type) {
return 0;
} else {
if (og_size) { *og_size = b->data.rubble.og_size; }
if (og_grid_offset) { *og_grid_offset = b->data.rubble.og_grid_offset; }
if (og_orientation) { *og_orientation = b->data.rubble.og_orientation; }
if (og_type) { *og_type = b->data.rubble.og_type; }
return 1;
}

if (og_size) {
*og_size = b->data.rubble.og_size;
}
if (og_grid_offset) {
*og_grid_offset = b->data.rubble.og_grid_offset;
}
if (og_orientation) {
*og_orientation = b->data.rubble.og_orientation;
}
if (og_type) {
*og_type = b->data.rubble.og_type;
}

return 1;
}

static int is_warehouse_ruin(building *b)
Expand Down Expand Up @@ -520,8 +552,10 @@ static int warehouse_repair(building *b)
return full_cost;
}

int building_repair(building *b)
int building_repair_at(int grid_offset)
{
building *b = building_get(map_building_rubble_building_id(grid_offset));

if (!b) {
return 0;
}
Expand All @@ -532,8 +566,6 @@ int building_repair(building *b)
if (!building_can_repair_type(b->type) && !building_can_repair_type(b->data.rubble.og_type)) {
if (building_monument_is_limited(b->type) || building_monument_is_limited(b->data.rubble.og_type)) {
city_warning_show(WARNING_REPAIR_MONUMENT, NEW_WARNING_SLOT);
} else if (b->type == BUILDING_AQUEDUCT || b->data.rubble.og_type == BUILDING_AQUEDUCT) {
city_warning_show(WARNING_REPAIR_AQUEDUCT, NEW_WARNING_SLOT);
} else {
city_warning_show(WARNING_REPAIR_IMPOSSIBLE, NEW_WARNING_SLOT);
}
Expand All @@ -549,8 +581,10 @@ int building_repair(building *b)
// Backup building data
building_data_transfer_backup();
building_data_transfer_copy(b, 1);
// Resolve placement data
int grid_offset = og_grid_offset ? og_grid_offset : b->grid_offset;
// Resolve placement data
if (!building_properties_for_type(b->type)->shared) {
grid_offset = og_grid_offset ? og_grid_offset : b->grid_offset;
}
int x = map_grid_offset_to_x(grid_offset);
int y = map_grid_offset_to_y(grid_offset);
int size = og_size ? og_size : b->size;
Expand Down Expand Up @@ -613,16 +647,21 @@ int building_repair(building *b)
int full_cost = (placement_cost + placement_cost / 20);// +5%

city_finance_process_construction(full_cost);
new_building->subtype.orientation = og_orientation;
map_building_set_rubble_grid_building_id(grid_offset, 0, size); // remove rubble marker
building_data_transfer_paste(new_building, 1);
new_building->state = BUILDING_STATE_CREATED;
if (!building_properties_for_type(type_to_place)->shared) {
new_building->subtype.orientation = og_orientation;
new_building->state = BUILDING_STATE_CREATED;
b->state = BUILDING_STATE_DELETED_BY_GAME; // mark old building as deleted
figure_create_explosion_cloud(new_building->x, new_building->y, og_size, 1);
} else {
figure_create_explosion_cloud(x, y, og_size, 1);
}
building_data_transfer_restore_and_clear_backup();
figure_create_explosion_cloud(new_building->x, new_building->y, og_size, 1);

if (wall) {
map_tiles_update_all_walls(); // towers affect wall connections
}
b->state = BUILDING_STATE_DELETED_BY_GAME; // mark old building as deleted
game_undo_disable(); // not accounting for undoing repairs
return full_cost;
}
Expand Down
7 changes: 5 additions & 2 deletions src/building/building.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ typedef struct building {
short fort_figure_type;
short native_meeting_center_id;
short barracks_priority;
unsigned short instances;
} subtype;
unsigned char road_network_id;
unsigned short created_sequence;
Expand Down Expand Up @@ -240,16 +241,18 @@ int building_is_storage(building_type b_type);
* Keeping a building in the array is helpful because it holds the building's ID, and allows keeping the storage structure.
*/

int building_repair(building *b);
int building_repair_at(int grid_offset);

int building_is_still_burning(building *b);

int building_can_repair(building *b);

int building_repair_cost(building *b);
int building_repair_cost_at(int grid_offset);

void building_clear_related_data(building *b);

void building_delete(building *b);

building *building_restore_from_undo(building *to_restore);

void building_trim(void);
Expand Down
2 changes: 1 addition & 1 deletion src/building/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ static building_type get_clone_type_from_building(building *b, building_type clo

building_type building_clone_type_from_building_type(building_type type)
{
return get_clone_type_from_building(NULL, type);
return get_clone_type_from_building(0, type);
}

int building_clone_rotation_from_grid_offset(int grid_offset)
Expand Down
16 changes: 9 additions & 7 deletions src/building/construction.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ static int place_wall(int x_start, int y_start, int x_end, int y_end, int measur
map_terrain_add(grid_offset, TERRAIN_BUILDING);
map_terrain_add(grid_offset, TERRAIN_WALL);
map_property_clear_multi_tile_xy(grid_offset);
game_undo_add_building(wall);
wall->subtype.instances++;
}
}
}
Expand Down Expand Up @@ -525,7 +527,7 @@ static int place_reservoir_and_aqueducts(int measure_only, int x_start, int y_st
int dx_end = aqueduct_offsets_x[dir_end];
int dy_end = aqueduct_offsets_y[dir_end];
int dist;
if (building_construction_place_aqueduct_for_reservoir(1,
if (building_construction_place_aqueduct_for_reservoir(1, 0,
x_start + dx_start, y_start + dy_start, x_end + dx_end, y_end + dy_end, &dist)) {
if (dist && dist < min_dist) {
min_dist = dist;
Expand All @@ -543,7 +545,7 @@ static int place_reservoir_and_aqueducts(int measure_only, int x_start, int y_st
int x_aq_end = aqueduct_offsets_x[min_dir_end];
int y_aq_end = aqueduct_offsets_y[min_dir_end];
int aq_items;
building_construction_place_aqueduct_for_reservoir(0, x_start + x_aq_start, y_start + y_aq_start,
building_construction_place_aqueduct_for_reservoir(measure_only, 1, x_start + x_aq_start, y_start + y_aq_start,
x_end + x_aq_end, y_end + y_aq_end, &aq_items);
if (info->place_reservoir_at_start == PLACE_RESERVOIR_YES) {
info->cost += model_get_building(BUILDING_RESERVOIR)->cost;
Expand Down Expand Up @@ -818,7 +820,7 @@ void building_construction_update(int x, int y, int grid_offset)
int current_cost = model_get_building(type)->cost;
int repaired_buildings = 0;
if (type == BUILDING_CLEAR_LAND) {
int items_placed = last_items_cleared = building_construction_clear_land(1, data.start.x, data.start.y, x, y);
int items_placed = last_items_cleared = building_construction_clear_select(data.start.x, data.start.y, x, y);
if (items_placed >= 0) {
current_cost *= items_placed;
}
Expand Down Expand Up @@ -919,7 +921,7 @@ void building_construction_update(int x, int y, int grid_offset)
current_cost *= length;
}
} else if (type == BUILDING_AQUEDUCT) {
building_construction_place_aqueduct(data.start.x, data.start.y, x, y, &current_cost);
building_construction_place_aqueduct(1, data.start.x, data.start.y, x, y, &current_cost);
map_tiles_update_all_aqueducts(0);
} else if (type == BUILDING_DRAGGABLE_RESERVOIR) {
struct reservoir_info info;
Expand Down Expand Up @@ -1074,8 +1076,8 @@ void building_construction_place(void)
// the previous cost is deducted from treasury and if user chooses 'no', they still pay for removal.
// If we don't do it this way, the user doesn't pay for the removal at all since we don't come back
// here when the user says yes.
int items_placed = building_construction_clear_land(0, x_start, y_start, x_end, y_end);
if (items_placed < 0) {
int items_placed = building_construction_clear_land(x_start, y_start, x_end, y_end);
if (items_placed == BUILDING_CONSTRUCTION_CLEAR_LAND_INTERRUPTED) {
items_placed = last_items_cleared;
}
placement_cost *= items_placed;
Expand Down Expand Up @@ -1115,7 +1117,7 @@ void building_construction_place(void)
placement_cost *= length;
} else if (type == BUILDING_AQUEDUCT) {
int cost;
if (!building_construction_place_aqueduct(x_start, y_start, x_end, y_end, &cost)) {
if (!building_construction_place_aqueduct(0, x_start, y_start, x_end, y_end, &cost)) {
city_warning_show(WARNING_CLEAR_LAND_NEEDED, NEW_WARNING_SLOT);
return;
}
Expand Down
Loading
Loading