Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,043 changes: 76 additions & 3,967 deletions res/assets/Graphics/terrain_maps.xml

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/building/construction_clear.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ unsigned int building_construction_clear_select(int x_start, int y_start, int x_
continue;
} else if (map_terrain_is(grid_offset, TERRAIN_WATER)) { // keep the "bridge is free" bug from C3
continue;
} else if (map_terrain_is(grid_offset, TERRAIN_MARSHLAND)) {
continue;
} else if (map_terrain_is(grid_offset, TERRAIN_AQUEDUCT)) {
items_placed++;
} else if (map_terrain_is(grid_offset, TERRAIN_HIGHWAY)) {
Expand Down Expand Up @@ -125,6 +127,9 @@ static unsigned int clear_land_confirmed(int x_start, int y_start, int x_end, in
if (map_terrain_is(grid_offset, TERRAIN_ROCK | TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP)) {
continue;
}
if (map_terrain_is(grid_offset, TERRAIN_MARSHLAND)) {
continue;
}

if (map_terrain_is(grid_offset, TERRAIN_BUILDING) && is_shared_building_at(grid_offset)) {

Expand Down
20 changes: 20 additions & 0 deletions src/city/health.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
#include "core/calc.h"
#include "core/random.h"
#include "game/tutorial.h"
#include "map/grid.h"
#include "map/terrain.h"
#include "scenario/property.h"

#define SICKNESS_SPREAD_DIVISION_FACTOR 4
#define MARSHLAND_HEALTH_RANGE 3
#define MARSHLAND_SICKNESS_MALUS 5

#define NUM_PLAGUE_BUILDINGS (sizeof(PLAGUE_BUILDINGS) / sizeof(building_type))
static const building_type PLAGUE_BUILDINGS[] = { BUILDING_DOCK, BUILDING_WAREHOUSE, BUILDING_GRANARY };
Expand Down Expand Up @@ -363,6 +367,21 @@ int city_health_get_house_health_level(const building *b, int update_city_data)
return house_health;
}

static void apply_marshland_sickness_malus(building *b)
{
int x_min, y_min, x_max, y_max;
map_grid_get_area(b->x, b->y, b->size, MARSHLAND_HEALTH_RANGE, &x_min, &y_min, &x_max, &y_max);
for (int yy = y_min; yy <= y_max; yy++) {
for (int xx = x_min; xx <= x_max; xx++) {
if (map_terrain_is(map_grid_offset(xx, yy), TERRAIN_MARSHLAND)) {
b->sickness_level = calc_bound(
b->sickness_level + MARSHLAND_SICKNESS_MALUS, 0, MAX_SICKNESS_LEVEL);
return; // one malus per cycle regardless of how many marsh tiles are near
}
}
}
}

void city_health_update(void)
{
int only_gather_stats = 0;
Expand Down Expand Up @@ -397,6 +416,7 @@ void city_health_update(void)
if (!only_gather_stats) {
healthy_population += calc_adjust_with_percentage(b->house_population, house_health);
adjust_sickness_level_in_house(b, house_health, population_health_offset, hospital_coverage_bonus);
apply_marshland_sickness_malus(b);
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/core/lang.c
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,10 @@ const uint8_t *lang_get_string(int group, int index)
return translation_for(TR_EDITOR_TOOL_EARTHQUAKE_REMOVE);
case TR_EDITOR_RUBBLE:
return translation_for(TR_EDITOR_RUBBLE);
case TR_EDITOR_TOOL_WATER:
return translation_for(TR_EDITOR_TOOL_WATER);
case TR_EDITOR_TOOL_MARSHLAND:
return translation_for(TR_EDITOR_TOOL_MARSHLAND);
default:
break;
}
Expand Down
31 changes: 28 additions & 3 deletions src/editor/tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include <string.h>

#define TERRAIN_PAINT_MASK ~(TERRAIN_TREE | TERRAIN_ROCK | TERRAIN_WATER | TERRAIN_BUILDING |\
TERRAIN_SHRUB | TERRAIN_GARDEN | TERRAIN_ROAD | TERRAIN_MEADOW)
TERRAIN_SHRUB | TERRAIN_GARDEN | TERRAIN_ROAD | TERRAIN_MEADOW | TERRAIN_MARSHLAND)

static struct {
int active;
Expand Down Expand Up @@ -151,6 +151,7 @@ int editor_tool_is_brush(void)
case TOOL_SHRUB:
case TOOL_ROCKS:
case TOOL_MEADOW:
case TOOL_MARSHLAND:
case TOOL_NATIVE_RUINS:
case TOOL_RAISE_LAND:
case TOOL_LOWER_LAND:
Expand All @@ -169,7 +170,7 @@ static int raise_land_tile(int x, int y, int grid_offset, int terrain)
if (!(terrain & (TERRAIN_ACCESS_RAMP | TERRAIN_ELEVATION))) {
map_property_set_multi_tile_size(grid_offset, 1);
map_elevation_set(grid_offset, elevation + 1);
terrain &= ~(TERRAIN_WATER | TERRAIN_BUILDING | TERRAIN_GARDEN | TERRAIN_ROAD);
terrain &= ~(TERRAIN_WATER | TERRAIN_BUILDING | TERRAIN_GARDEN | TERRAIN_ROAD | TERRAIN_MARSHLAND);
}
}
return terrain;
Expand Down Expand Up @@ -239,7 +240,8 @@ static void add_terrain(const void *tile_data, int dx, int dy)
}
break;
case TOOL_WATER:
if (!(terrain & TERRAIN_WATER) && !(terrain & TERRAIN_ELEVATION_ROCK)) {
if ((!(terrain & TERRAIN_WATER) || (terrain & TERRAIN_MARSHLAND)) &&
!(terrain & TERRAIN_ELEVATION_ROCK)) {
terrain &= TERRAIN_PAINT_MASK;
terrain |= TERRAIN_WATER;
map_property_clear_future_earthquake(grid_offset);
Expand All @@ -257,6 +259,15 @@ static void add_terrain(const void *tile_data, int dx, int dy)
terrain |= TERRAIN_MEADOW;
}
break;
case TOOL_MARSHLAND:
// Marsh is an OVERLAY: it adds the TERRAIN_MARSHLAND flag and is drawn on top of the
// native terrain tile (land / water / coast), which keeps its own image and autotiling.
if (!(terrain & TERRAIN_MARSHLAND) && !(terrain & TERRAIN_ELEVATION_ROCK)) {
terrain &= ~(TERRAIN_TREE | TERRAIN_ROCK | TERRAIN_SHRUB | TERRAIN_GARDEN);
terrain |= TERRAIN_MARSHLAND;
map_property_clear_future_earthquake(grid_offset);
}
break;
case TOOL_NATIVE_RUINS:
if (!(terrain & TERRAIN_RUBBLE)) {
terrain &= TERRAIN_PAINT_MASK;
Expand Down Expand Up @@ -310,30 +321,42 @@ void editor_tool_update_use(const map_tile *tile)
map_tiles_update_all_rocks();
map_tiles_update_region_empty_land(x_min, y_min, x_max, y_max);
map_tiles_update_region_meadow(x_min, y_min, x_max, y_max);
map_tiles_update_region_marshland(x_min - 1, y_min - 1, x_max + 1, y_max + 1);
break;
case TOOL_TREES:
map_image_context_reset_water();
map_tiles_update_region_water(x_min, y_min, x_max, y_max);
map_tiles_update_all_rocks();
map_tiles_update_region_trees(x_min, y_min, x_max, y_max);
map_tiles_update_region_marshland(x_min - 1, y_min - 1, x_max + 1, y_max + 1);
break;
case TOOL_WATER:
case TOOL_ROCKS:
map_image_context_reset_water();
map_tiles_update_all_rocks();
map_tiles_update_region_water(x_min, y_min, x_max, y_max);
map_tiles_update_region_marshland(x_min - 1, y_min - 1, x_max + 1, y_max + 1);
break;
case TOOL_SHRUB:
map_image_context_reset_water();
map_tiles_update_region_water(x_min, y_min, x_max, y_max);
map_tiles_update_all_rocks();
map_tiles_update_region_shrub(x_min, y_min, x_max, y_max);
map_tiles_update_region_marshland(x_min - 1, y_min - 1, x_max + 1, y_max + 1);
break;
case TOOL_MEADOW:
map_image_context_reset_water();
map_tiles_update_region_water(x_min, y_min, x_max, y_max);
map_tiles_update_all_rocks();
map_tiles_update_region_meadow(x_min, y_min, x_max, y_max);
map_tiles_update_region_marshland(x_min - 1, y_min - 1, x_max + 1, y_max + 1);
break;
case TOOL_MARSHLAND:
map_image_context_reset_water();
map_tiles_update_region_water(x_min - 1, y_min - 1, x_max + 1, y_max + 1);
map_tiles_update_all_rocks();
map_tiles_update_region_empty_land(x_min, y_min, x_max, y_max);
map_tiles_update_region_marshland(x_min - 1, y_min - 1, x_max + 1, y_max + 1);
break;
case TOOL_NATIVE_RUINS:
// Rubble doesn't need terrain updates, just refresh the rubble graphics
Expand All @@ -350,6 +373,7 @@ void editor_tool_update_use(const map_tile *tile)
map_tiles_update_all_rocks();
map_tiles_update_region_empty_land(x_min, y_min, x_max, y_max);
map_tiles_update_region_meadow(x_min, y_min, x_max, y_max);
map_tiles_update_region_marshland(x_min - 1, y_min - 1, x_max + 1, y_max + 1);
break;
case TOOL_EARTHQUAKE_CUSTOM:
{
Expand Down Expand Up @@ -479,6 +503,7 @@ static void update_terrain_after_elevation_changes(void)
map_tiles_update_all_empty_land();
map_tiles_update_all_meadow();
map_tiles_update_all_water();
map_tiles_update_all_marshland();

scenario_editor_set_as_unsaved();
}
Expand Down
3 changes: 2 additions & 1 deletion src/editor/tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ typedef enum {
TOOL_EARTHQUAKE_CUSTOM = 30,
TOOL_EARTHQUAKE_CUSTOM_REMOVE = 31,
TOOL_NATIVE_RUINS = 32,
TOOL_SELECT_LAND = 33
TOOL_SELECT_LAND = 33,
TOOL_MARSHLAND = 34
} tool_type;

tool_type editor_tool_type(void);
Expand Down
2 changes: 1 addition & 1 deletion src/figuretype/animal.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ void figure_wolf_action(figure *f)
static int terrain_blocked_for_animals(int grid_offset)
{
return map_terrain_is(grid_offset, TERRAIN_TREE | TERRAIN_ROCK | TERRAIN_WATER |
TERRAIN_BUILDING | TERRAIN_SHRUB );
TERRAIN_BUILDING | TERRAIN_SHRUB | TERRAIN_MARSHLAND);
}

void figure_animal_try_nudge_at(int building_center_tile_grid_offset, int animal_tile_offset, int building_size)
Expand Down
3 changes: 3 additions & 0 deletions src/game/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ static void clear_scenario_data(void)

// clear grids
map_image_clear();
map_marsh_image_clear();
map_building_clear();
map_terrain_clear();
map_aqueduct_clear();
Expand All @@ -149,6 +150,7 @@ static void initialize_scenario_data(const uint8_t *scenario_name)
// initialize grids
map_tiles_update_all_elevation();
map_tiles_update_all_water();
map_tiles_update_all_marshland();
map_tiles_update_all_earthquake();
map_tiles_update_all_rocks();
map_tiles_add_entry_exit_flags();
Expand Down Expand Up @@ -273,6 +275,7 @@ static void initialize_saved_game(void)

map_image_context_init();
map_image_clear();
map_marsh_image_clear();
map_image_update_all();

scenario_map_init();
Expand Down
2 changes: 2 additions & 0 deletions src/game/file_editor.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ void game_file_editor_clear_data(void)
static void clear_map_data(void)
{
map_image_clear();
map_marsh_image_clear();
map_building_clear();
map_terrain_clear();
map_aqueduct_clear();
Expand Down Expand Up @@ -129,6 +130,7 @@ static void prepare_map_for_editing(void)

map_tiles_update_all_elevation_editor();
map_tiles_update_all_water();
map_tiles_update_all_marshland();
map_tiles_update_all_earthquake();
map_tiles_update_all_rocks();
map_tiles_update_all_empty_land();
Expand Down
16 changes: 12 additions & 4 deletions src/game/file_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,11 @@ static void init_scenario_data(scenario_version_t version)
}
state->graphic_ids = create_scenario_piece(GRID_SIZE_BUF_U16, 0);
state->edge = create_scenario_piece(GRID_SIZE_BUF_U8, 0);
state->terrain = create_scenario_piece(GRID_SIZE_BUF_U16, 0);
if (version > SCENARIO_LAST_U16_TERRAIN) {
state->terrain = create_scenario_piece(GRID_SIZE_BUF_U32, 0);
} else {
state->terrain = create_scenario_piece(GRID_SIZE_BUF_U16, 0);
}
if (version > SCENARIO_LAST_NO_FORMULAS_AND_MODEL_DATA) {
state->bitfields = create_scenario_piece(GRID_SIZE_BUF_U16, 0);
} else {
Expand Down Expand Up @@ -724,7 +728,7 @@ static void scenario_load_from_state(scenario_state *file, scenario_version_t ve
resource_set_mapping(resource_version);

map_image_load_state_legacy(file->graphic_ids);
map_terrain_load_state(file->terrain, 0, file->graphic_ids, 1);
map_terrain_load_state(file->terrain, version > SCENARIO_LAST_U16_TERRAIN, file->graphic_ids, 1);
if (version > SCENARIO_LAST_NO_FORMULAS_AND_MODEL_DATA) {
map_property_load_state(file->bitfields, file->edge);
} else {
Expand Down Expand Up @@ -801,7 +805,7 @@ static void scenario_save_to_state(scenario_state *file)
buffer_write_u32(file->resource_version, RESOURCE_CURRENT_VERSION);

map_image_save_state_legacy(file->graphic_ids);
map_terrain_save_state_legacy(file->terrain);
map_terrain_save_state(file->terrain);
map_property_save_state(file->bitfields, file->edge);
map_random_save_state(file->random);
map_elevation_save_state(file->elevation);
Expand Down Expand Up @@ -1341,7 +1345,11 @@ int game_file_io_read_scenario(const char *filename)

static int scenario_terrain_at(int grid_offset)
{
return map_terrain_get_from_buffer_16(scenario_data.state.terrain, grid_offset);
if (scenario_data.version <= SCENARIO_LAST_U16_TERRAIN) {
return map_terrain_get_from_buffer_16(scenario_data.state.terrain, grid_offset);
} else {
return map_terrain_get_from_buffer_32(scenario_data.state.terrain, grid_offset);
}
}

static int scenario_tile_size_at(int grid_offset)
Expand Down
5 changes: 3 additions & 2 deletions src/game/save_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ typedef enum {
} savegame_version_t;

typedef enum {
SCENARIO_CURRENT_VERSION = 22,
SCENARIO_CURRENT_VERSION = 23,

SCENARIO_VERSION_NONE = 0,
SCENARIO_LAST_UNVERSIONED = 1,
Expand All @@ -132,7 +132,8 @@ typedef enum {
SCENARIO_LAST_NO_VISIBLE_CUSTOM_VARIABLES = 18,
SCENARIO_LAST_NO_FORMULAS_AND_MODEL_DATA = 19,
SCENARIO_LAST_NO_EMPIRE_EDITOR = 20,
SCENARIO_LAST_LIMITED_ROUTE_COST = 21
SCENARIO_LAST_LIMITED_ROUTE_COST = 21,
SCENARIO_LAST_U16_TERRAIN = 22
} scenario_version_t;

typedef enum {
Expand Down
1 change: 1 addition & 0 deletions src/game/tick.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ static void advance_month(void)
map_tiles_update_all_roads();
map_tiles_update_all_highways();
map_tiles_update_all_water();
map_tiles_update_all_marshland();
map_routing_update_land_citizen();
city_message_sort_and_compact();

Expand Down
4 changes: 2 additions & 2 deletions src/map/bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ int map_bridge_calculate_length_direction(int x, int y, int *length, int *direct
if (i == 0) {
//check for an inaccessible tile before the bridge starts
int previous_offset = grid_offset - 2 * bridge.direction_grid_delta;
if (map_terrain_is(previous_offset, TERRAIN_TREE | TERRAIN_ROCK | TERRAIN_SHRUB | TERRAIN_BUILDING)) {
if (map_terrain_is(previous_offset, TERRAIN_TREE | TERRAIN_ROCK | TERRAIN_SHRUB | TERRAIN_BUILDING | TERRAIN_MARSHLAND)) {
blocking_tiles->grid_offsets[blocking_tiles->size++] = previous_offset;
bridge.end_grid_offset = 0;
}
}
int next_offset = grid_offset + bridge.direction_grid_delta;
if (map_terrain_is(next_offset, TERRAIN_TREE | TERRAIN_ROCK | TERRAIN_SHRUB | TERRAIN_BUILDING)) {
if (map_terrain_is(next_offset, TERRAIN_TREE | TERRAIN_ROCK | TERRAIN_SHRUB | TERRAIN_BUILDING | TERRAIN_MARSHLAND)) {
blocking_tiles->grid_offsets[blocking_tiles->size++] = next_offset;
bridge.end_grid_offset = 0;
break;
Expand Down
2 changes: 2 additions & 0 deletions src/map/desirability.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ static void update_terrain(void)
model->desirability_step,
model->desirability_step_size,
model->desirability_range);
} else if (terrain & TERRAIN_MARSHLAND) {
add_to_terrain(x, y, 1, -3, 1, 1, 3);
} else if (terrain & TERRAIN_AQUEDUCT) {
add_to_terrain(x, y, 1, -2, 1, 1, 2);
}
Expand Down
32 changes: 32 additions & 0 deletions src/map/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,38 @@
static grid_u32 images;
static grid_u32 images_backup;

// Marshland is drawn as an OVERLAY on top of the native terrain tile (which keeps its own image),
// so its image id is stored in a separate grid rather than overwriting the terrain image. 0 = no
// marsh overlay on the tile. This grid is derived from the TERRAIN_MARSHLAND flag and recomputed
// on load/rotation/climate change, so it is not part of the save format.
static grid_u32 marsh_images;
static grid_u32 marsh_images_backup;

unsigned int map_marsh_image_at(int grid_offset)
{
return marsh_images.items[grid_offset];
}

void map_marsh_image_set(int grid_offset, int image_id)
{
marsh_images.items[grid_offset] = image_id;
}

void map_marsh_image_backup(void)
{
map_grid_copy_u32(marsh_images.items, marsh_images_backup.items);
}

void map_marsh_image_restore(void)
{
map_grid_copy_u32(marsh_images_backup.items, marsh_images.items);
}

void map_marsh_image_clear(void)
{
map_grid_clear_u32(marsh_images.items);
}

unsigned int map_image_at(int grid_offset)
{
return images.items[grid_offset];
Expand Down
6 changes: 6 additions & 0 deletions src/map/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ void map_image_clear(void);
void map_image_init_edges(void);
void map_image_update_all(void);

unsigned int map_marsh_image_at(int grid_offset);
void map_marsh_image_set(int grid_offset, int image_id);
void map_marsh_image_backup(void);
void map_marsh_image_restore(void);
void map_marsh_image_clear(void);

void map_image_save_state_legacy(buffer *buf);

void map_image_load_state_legacy(buffer *buf);
Expand Down
1 change: 1 addition & 0 deletions src/map/image_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ static const terrain_image *get_image(int group, int tiles[MAX_TILES])
result.group_offset = context[i].offset_for_orientation[city_view_orientation() / 2];
result.item_offset = context[i].current_item_offset;
result.aqueduct_offset = context[i].aqueduct_offset;
result.max_item_offset = context[i].max_item_offset;
break;
}
}
Expand Down
Loading
Loading