diff --git a/grf/alpine/alpine.nml b/grf/alpine/alpine.nml new file mode 100644 index 0000000000..b670bfb2ed --- /dev/null +++ b/grf/alpine/alpine.nml @@ -0,0 +1,1707 @@ +grf { + grfid: "CMAL"; + name: string(STR_GRF_NAME); + desc: string(STR_GRF_DESCRIPTION); + version: 1; + min_compatible_version: 1; +} + +template tmpl_groundsprites_flags(x, y, flags) { + // N E S W STEEP + [ 0+x, y, 64, 31, -31, 0, flags ] // + [ 80+x, y, 64, 31, -31, 0, flags ] // W + [ 160+x, y, 64, 23, -31, 0, flags ] // S + [ 240+x, y, 64, 23, -31, 0, flags ] // S W + + [ 320+x, y, 64, 31, -31, 0, flags ] // E + [ 398+x, y, 64, 31, -31, 0, flags ] // E W + [ 478+x, y, 64, 23, -31, 0, flags ] // E S + [ 558+x, y, 64, 23, -31, 0, flags ] // E S W + + [ 638+x, y, 64, 39, -31, -8, flags ] // N + [ 718+x, y, 64, 39, -31, -8, flags ] // N W + [ 798+x, y, 64, 31, -31, -8, flags ] // N S + [ 878+x, y, 64, 31, -31, -8, flags ] // N S W + + [ 958+x, y, 64, 39, -31, -8, flags ] // N E + [1038+x, y, 64, 39, -31, -8, flags ] // N E W + [1118+x, y, 64, 31, -31, -8, flags ] // N E S + [1196+x, y, 64, 47, -31,-16, flags ] // N E W STEEP + + [1276+x, y, 64, 15, -31, 0, flags ] // E S W STEEP + [1356+x, y, 64, 31, -31, -8, flags ] // N S W STEEP + [1436+x, y, 64, 31, -31, -8, flags ] // N E S STEEP +} + +template tmpl_groundsprites(x, y) { + tmpl_groundsprites_flags(x, y, 0) +} + +template tmpl_groundsprites_anim(x, y) { + tmpl_groundsprites_flags(x, y, ANIM) +} + +template tmpl_level_ground(x, y) { + [ x, y, 64, 31, -31, 0 ] +} + +template tmpl_rough(x, y) { + tmpl_level_ground( x, y) + tmpl_level_ground( 80+x, y) + tmpl_level_ground(160+x, y) + tmpl_level_ground(240+x, y) +} + +template tmpl_additional_rough(x, y) { + tmpl_rough(1510+x, y) +} + +template tmpl_16shore_tiles(x, y) { + [1276+x, y, 64, 15, -31, 0 ] + [ 80+x, y, 64, 31, -31, 0 ] + [ 160+x, y, 64, 23, -31, 0 ] + [ 240+x, y, 64, 23, -31, 0 ] + + [ 320+x, y, 64, 31, -31, 0 ] + [1356+x, y, 64, 31, -31, -8 ] + [ 478+x, y, 64, 23, -31, 0 ] + [ 558+x, y, 64, 23, -31, 0 ] + + [ 638+x, y, 64, 39, -31, -8 ] + [ 718+x, y, 64, 39, -31, -8 ] + [1196+x, y, 64, 47, -31,-16 ] + [ 878+x, y, 64, 31, -31, -8 ] + + [ 958+x, y, 64, 39, -31, -8 ] + [1038+x, y, 64, 39, -31, -8 ] + [1118+x, y, 64, 31, -31, -8 ] + [1436+x, y, 64, 31, -31, -8 ] +} + +template tmpl_8shore_tiles(x, y) { + [ 320+x, y, 64, 31, -31, 0 ] + [ 80+x, y, 64, 31, -31, 0 ] + [ 160+x, y, 64, 23, -31, 0 ] + [ 638+x, y, 64, 39, -31, -8 ] + + [ 478+x, y, 64, 23, -31, 0 ] + [ 958+x, y, 64, 39, -31, -8 ] + [ 240+x, y, 64, 23, -31, 0 ] + [ 718+x, y, 64, 39, -31, -8 ] +} + +template tmpl_tree_wide() { + [ 0, 0, 45, 80, -24, -73] + [ 50, 0, 45, 80, -24, -73] + [100, 0, 45, 80, -24, -73] + [150, 0, 45, 80, -24, -73] + [200, 0, 45, 80, -24, -73] + [250, 0, 45, 80, -24, -73] + [300, 0, 45, 80, -24, -73] +} + +template tmpl_tree_narrow() { + [ 0, 0, 35, 80, -19, -73] + [ 40, 0, 35, 80, -19, -73] + [ 80, 0, 35, 80, -19, -73] + [120, 0, 35, 80, -19, -73] + [160, 0, 35, 80, -19, -73] + [200, 0, 35, 80, -19, -73] + [240, 0, 35, 80, -19, -73] +} + +// Normal land: +replace (3981, "gfx/grass_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } + +// bulldozed (bare) land and regeneration stages: +replace (3924, "gfx/bare03_grid.gimp.png") { tmpl_groundsprites(1, 1) } +replace (3943, "gfx/bare13_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } +replace (3962, "gfx/bare23_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } + +// rough terrain +replace (4000, "gfx/rough_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } +replace (4019, "gfx/rough_grid_temperate.gimp.png") { tmpl_additional_rough(1, 1) } + +// rocky terrain +replace (4023, "gfx/rocks_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } + +// different snow densities: +replace (4493, "gfx/snow14_grid_alpine.gimp.png") { tmpl_groundsprites(1, 1) } +replace (4512, "gfx/snow24_grid_alpine.gimp.png") { tmpl_groundsprites(1, 1) } +replace (4531, "gfx/snow34_grid_alpine.gimp.png") { tmpl_groundsprites(1, 1) } +replace (4550, "gfx/snow_grid.gimp.png") { tmpl_groundsprites(1, 1) } + +// shore sprites +replace (4062, "gfx/water/seashore_grid_temperate.gimp.png") { tmpl_8shore_tiles(1, 1) } +replacenew (COAST_TILES, "gfx/water/seashore_grid_temperate.gimp.png") { tmpl_16shore_tiles(1, 1) } + + +// //Arctic trees: the following trees have snowy equivalents: +// base_graphics spr1709(1709, "trees/tree_01_conifer.gimp.png") { tmpl_tree_narrow() } // 1709 conifer (snowy: 1765) +// base_graphics spr1716(1716, "trees/tree_06_leaf.gimp.png") { tmpl_tree_narrow() } // 1716 leaf tree (snowy: 1772) +// base_graphics spr1723(1723, "trees/tree_07_leaf.gimp.png") { tmpl_tree_narrow() } // 1723 leaf tree (snowy: 1779) +// base_graphics spr1730(1730, "trees/tree_08_conifer.gimp.png") { tmpl_tree_narrow() } // 1730 conifer (snowy: 1786) +// base_graphics spr1737(1737, "trees/tree_09_conifer.gimp.png") { tmpl_tree_narrow() } // 1737 conifer (snowy: 1793) +// base_graphics spr1744(1744, "trees/tree_04_conifer.gimp.png") { tmpl_tree_narrow() } // 1744 conifer (snowy: 1800) +// base_graphics spr1751(1751, "trees/tree_05_conifer.gimp.png") { tmpl_tree_narrow() } // 1751 conifer (snowy: 1807) +// base_graphics spr1758(1758, "trees/tree_10_leaf.gimp.png") { tmpl_tree_narrow() } // 1758 leaf tree (snowy: 1814) +// // snowy trees +// base_graphics spr1765(1765, "trees/tree_01_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1765 snowy conifer (equiv of 1709) +// base_graphics spr1772(1772, "trees/tree_06_snow_leaf.gimp.png") { tmpl_tree_narrow() } // 1772 snowy leaf tree (equiv. of 1716) +// base_graphics spr1779(1779, "trees/tree_07_snow_leaf.gimp.png") { tmpl_tree_narrow() } // 1779 snowy leaf tree (equiv. of 1723) +// base_graphics spr1786(1786, "trees/tree_08_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1786 snowy conifer (equiv. of 1730) +// base_graphics spr1793(1793, "trees/tree_09_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1793 snowy conifer (equiv. of 1737) +// base_graphics spr1800(1800, "trees/tree_04_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1800 snowy conifer (equiv. of 1744) +// base_graphics spr1807(1807, "trees/tree_05_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1807 snowy conifer (equiv. of 1751) +// base_graphics spr1814(1814, "trees/tree_10_snow_leaf.gimp.png") { tmpl_tree_narrow() } // 1814 snowy leaf tree (equiv. of 1758) + +spriteset (meadow_groundsprites, "gfx/meadow_grid_temperate.png") { tmpl_groundsprites(1, 1) } + + +spriteset (meadow_transitions, "gfx/meadow_transitions.png") { + tmpl_groundsprites(1, 0 * 64 + 1) + tmpl_groundsprites(1, 1 * 64 + 1) + tmpl_groundsprites(1, 2 * 64 + 1) + tmpl_groundsprites(1, 3 * 64 + 1) + tmpl_groundsprites(1, 4 * 64 + 1) + tmpl_groundsprites(1, 5 * 64 + 1) + tmpl_groundsprites(1, 6 * 64 + 1) + tmpl_groundsprites(1, 7 * 64 + 1) + tmpl_groundsprites(1, 8 * 64 + 1) + tmpl_groundsprites(1, 9 * 64 + 1) + tmpl_groundsprites(1, 10 * 64 + 1) + tmpl_groundsprites(1, 11 * 64 + 1) + tmpl_groundsprites(1, 12 * 64 + 1) + tmpl_groundsprites(1, 13 * 64 + 1) + tmpl_groundsprites(1, 14 * 64 + 1) + tmpl_groundsprites(1, 15 * 64 + 1) +} + +spritelayout meadow_groundsprites_default { + ground { + sprite: meadow_transitions( + slope_to_sprite_offset(tile_slope) + + (nearby_tile_object_type( 0, -1) == meadow && nearby_tile_object_type(-1, -1) == meadow &&nearby_tile_object_type(-1, 0) == meadow ? 0 : 19) + + (nearby_tile_object_type(-1, 0) == meadow && nearby_tile_object_type(-1, 1) == meadow &&nearby_tile_object_type( 0, 1) == meadow ? 0 : 38) + + (nearby_tile_object_type( 0, 1) == meadow && nearby_tile_object_type( 1, 1) == meadow &&nearby_tile_object_type( 1, 0) == meadow ? 0 : 76) + + (nearby_tile_object_type( 1, 0) == meadow && nearby_tile_object_type( 1, -1) == meadow &&nearby_tile_object_type( 0, -1) == meadow ? 0 : 152) + ); + } +} + +spritelayout meadow_groundsprites_purchase { + ground { + sprite: meadow_groundsprites; + } +} + + +switch (FEAT_OBJECTS, SELF, switch_meadow_groundsprites_default, [ + STORE_TEMP(slope_to_sprite_offset(tile_slope), 0) + ]) { + meadow_groundsprites_default; +} + + +item (FEAT_OBJECTS, meadow) { + property { + class: "FLMA"; + classname: string(STR_FLMA); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: meadow_groundsprites_default; + purchase: meadow_groundsprites_purchase; + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +spriteset (creek_groundsprites, "gfx/rivers.png") { + tmpl_groundsprites_anim(1, 0 * 64 + 1) + tmpl_groundsprites_anim(1, 1 * 64 + 1) + tmpl_groundsprites_anim(1, 2 * 64 + 1) + tmpl_groundsprites_anim(1, 3 * 64 + 1) + tmpl_groundsprites_anim(1, 4 * 64 + 1) + tmpl_groundsprites_anim(1, 5 * 64 + 1) + tmpl_groundsprites_anim(1, 6 * 64 + 1) + tmpl_groundsprites_anim(1, 7 * 64 + 1) + tmpl_groundsprites_anim(1, 8 * 64 + 1) + tmpl_groundsprites_anim(1, 9 * 64 + 1) + tmpl_groundsprites_anim(1, 10 * 64 + 1) + tmpl_groundsprites_anim(1, 11 * 64 + 1) + tmpl_groundsprites_anim(1, 12 * 64 + 1) + tmpl_groundsprites_anim(1, 13 * 64 + 1) + tmpl_groundsprites_anim(1, 14 * 64 + 1) + tmpl_groundsprites_anim(1, 15 * 64 + 1) + tmpl_groundsprites_anim(1, 16 * 64 + 1) + tmpl_groundsprites_anim(1, 17 * 64 + 1) + tmpl_groundsprites_anim(1, 18 * 64 + 1) + tmpl_groundsprites_anim(1, 19 * 64 + 1) + tmpl_groundsprites_anim(1, 20 * 64 + 1) + tmpl_groundsprites_anim(1, 21 * 64 + 1) + tmpl_groundsprites_anim(1, 22 * 64 + 1) + tmpl_groundsprites_anim(1, 23 * 64 + 1) + tmpl_groundsprites_anim(1, 24 * 64 + 1) + tmpl_groundsprites_anim(1, 25 * 64 + 1) + tmpl_groundsprites_anim(1, 26 * 64 + 1) + tmpl_groundsprites_anim(1, 27 * 64 + 1) + tmpl_groundsprites_anim(1, 28 * 64 + 1) + tmpl_groundsprites_anim(1, 29 * 64 + 1) + tmpl_groundsprites_anim(1, 30 * 64 + 1) + tmpl_groundsprites_anim(1, 31 * 64 + 1) + tmpl_groundsprites_anim(1, 32 * 64 + 1) + tmpl_groundsprites_anim(1, 33 * 64 + 1) + tmpl_groundsprites_anim(1, 34 * 64 + 1) + tmpl_groundsprites_anim(1, 35 * 64 + 1) + tmpl_groundsprites_anim(1, 36 * 64 + 1) + tmpl_groundsprites_anim(1, 37 * 64 + 1) + tmpl_groundsprites_anim(1, 38 * 64 + 1) + tmpl_groundsprites_anim(1, 39 * 64 + 1) + tmpl_groundsprites_anim(1, 40 * 64 + 1) + tmpl_groundsprites_anim(1, 41 * 64 + 1) + tmpl_groundsprites_anim(1, 42 * 64 + 1) + tmpl_groundsprites_anim(1, 43 * 64 + 1) + tmpl_groundsprites_anim(1, 44 * 64 + 1) + tmpl_groundsprites_anim(1, 45 * 64 + 1) + tmpl_groundsprites_anim(1, 46 * 64 + 1) + tmpl_groundsprites_anim(1, 47 * 64 + 1) + tmpl_groundsprites_anim(1, 48 * 64 + 1) + tmpl_groundsprites_anim(1, 49 * 64 + 1) + tmpl_groundsprites_anim(1, 50 * 64 + 1) + tmpl_groundsprites_anim(1, 51 * 64 + 1) + tmpl_groundsprites_anim(1, 52 * 64 + 1) + tmpl_groundsprites_anim(1, 53 * 64 + 1) + tmpl_groundsprites_anim(1, 54 * 64 + 1) + tmpl_groundsprites_anim(1, 55 * 64 + 1) + tmpl_groundsprites_anim(1, 56 * 64 + 1) + tmpl_groundsprites_anim(1, 57 * 64 + 1) + tmpl_groundsprites_anim(1, 58 * 64 + 1) + tmpl_groundsprites_anim(1, 59 * 64 + 1) + tmpl_groundsprites_anim(1, 60 * 64 + 1) + tmpl_groundsprites_anim(1, 61 * 64 + 1) + tmpl_groundsprites_anim(1, 62 * 64 + 1) + tmpl_groundsprites_anim(1, 63 * 64 + 1) + tmpl_groundsprites_anim(1, 64 * 64 + 1) + tmpl_groundsprites_anim(1, 65 * 64 + 1) + tmpl_groundsprites_anim(1, 66 * 64 + 1) + tmpl_groundsprites_anim(1, 67 * 64 + 1) + tmpl_groundsprites_anim(1, 68 * 64 + 1) + tmpl_groundsprites_anim(1, 69 * 64 + 1) + tmpl_groundsprites_anim(1, 70 * 64 + 1) + tmpl_groundsprites_anim(1, 71 * 64 + 1) + tmpl_groundsprites_anim(1, 72 * 64 + 1) + tmpl_groundsprites_anim(1, 73 * 64 + 1) + tmpl_groundsprites_anim(1, 74 * 64 + 1) + tmpl_groundsprites_anim(1, 75 * 64 + 1) + tmpl_groundsprites_anim(1, 76 * 64 + 1) + tmpl_groundsprites_anim(1, 77 * 64 + 1) + tmpl_groundsprites_anim(1, 78 * 64 + 1) + tmpl_groundsprites_anim(1, 79 * 64 + 1) + tmpl_groundsprites_anim(1, 80 * 64 + 1) +} + +spritelayout creek_groundsprites_default(n, tile_height) { + ground { + sprite: + (climate == CLIMATE_ARCTIC && tile_height > snowline_height - 2 ? + GROUNDSPRITE_SNOW + min(tile_height - snowline_height - 2, 0) * 19 + : (terrain_type == TILETYPE_DESERT ? GROUNDSPRITE_DESERT : GROUNDSPRITE_NORMAL)) + + slope_to_sprite_offset(tile_slope); + } + childsprite { + sprite: creek_groundsprites( + slope_to_sprite_offset(tile_slope) + 19 * n + ); + always_draw: 1; + } +} + +spritelayout creek_groundsprites_purchase(n) { + ground { sprite: GROUNDSPRITE_NORMAL; } + childsprite { + sprite: creek_groundsprites(19 * n); + always_draw: 1; + } +} + +item (FEAT_OBJECTS, rivers_0) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(0, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(0); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_1) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(1, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(1); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_2) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(2, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(2); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_3) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(3, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(3); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_4) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(4, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(4); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_5) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(5, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(5); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_6) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(6, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(6); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_7) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(7, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(7); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_8) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(8, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(8); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_9) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(9, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(9); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_10) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(10, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(10); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_11) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(11, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(11); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_12) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(12, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(12); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_13) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(13, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(13); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_14) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(14, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(14); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_15) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(15, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(15); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_16) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(16, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(16); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_17) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(17, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(17); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_18) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(18, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(18); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_19) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(19, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(19); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_20) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(20, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(20); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_21) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(21, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(21); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_22) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(22, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(22); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_23) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(23, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(23); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_24) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(24, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(24); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_25) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(25, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(25); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_26) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(26, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(26); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_27) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(27, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(27); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_28) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(28, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(28); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_29) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(29, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(29); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_30) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(30, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(30); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_31) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(31, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(31); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_32) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(32, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(32); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_33) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(33, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(33); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_34) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(34, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(34); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_35) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(35, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(35); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_36) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(36, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(36); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_37) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(37, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(37); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_38) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(38, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(38); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_39) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(39, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(39); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_40) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(40, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(40); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_41) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(41, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(41); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_42) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(42, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(42); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_43) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(43, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(43); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_44) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(44, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(44); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_45) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(45, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(45); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_46) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(46, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(46); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_47) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(47, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(47); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_48) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(48, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(48); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_49) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(49, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(49); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_50) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(50, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(50); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_51) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(51, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(51); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_52) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(52, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(52); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_53) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(53, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(53); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_54) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(54, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(54); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_55) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(55, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(55); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_56) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(56, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(56); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_57) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(57, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(57); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_58) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(58, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(58); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_59) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(59, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(59); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_60) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(60, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(60); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_61) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(61, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(61); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_62) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(62, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(62); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_63) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(63, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(63); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_64) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(64, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(64); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_65) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(65, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(65); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_66) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(66, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(66); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_67) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(67, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(67); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_68) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(68, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(68); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_69) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(69, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(69); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_70) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(70, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(70); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_71) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(71, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(71); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_72) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(72, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(72); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_73) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(73, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(73); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_74) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(74, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(74); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_75) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(75, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(75); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_76) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(76, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(76); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_77) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(77, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(77); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_78) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(78, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(78); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_79) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(79, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(79); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +item (FEAT_OBJECTS, rivers_80) { + property { + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: creek_groundsprites_default(80, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase(80); + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + diff --git a/grf/alpine/alpine.py b/grf/alpine/alpine.py new file mode 100644 index 0000000000..05f5339dd5 --- /dev/null +++ b/grf/alpine/alpine.py @@ -0,0 +1,179 @@ +import grf +import spectra + +gen = grf.NewGRF( + b'CMAL', + 'CityMania Alpine Landscape', + 'Modified OpenGFX spritess for alpine climate.', +) + + +def replace_ground_sprites(sprite_id, file, x, y, **kw): + png = grf.ImageFile(file) + gen.add_sprite(grf.ReplaceSprites([(sprite_id, 19)])) + sprite = lambda *args, **kw: gen.add_sprite(grf.FileSprite(png, *args, **kw)) + sprite( 0+x, y, 64, 31, xofs=-31, yofs= 0, **kw) # + sprite( 80+x, y, 64, 31, xofs=-31, yofs= 0, **kw) # W + sprite( 160+x, y, 64, 23, xofs=-31, yofs= 0, **kw) # S + sprite( 240+x, y, 64, 23, xofs=-31, yofs= 0, **kw) # S W + sprite( 320+x, y, 64, 31, xofs=-31, yofs= 0, **kw) # E + sprite( 398+x, y, 64, 31, xofs=-31, yofs= 0, **kw) # E W + sprite( 478+x, y, 64, 23, xofs=-31, yofs= 0, **kw) # E S + sprite( 558+x, y, 64, 23, xofs=-31, yofs= 0, **kw) # E S W + sprite( 638+x, y, 64, 39, xofs=-31, yofs= -8, **kw) # N + sprite( 718+x, y, 64, 39, xofs=-31, yofs= -8, **kw) # N W + sprite( 798+x, y, 64, 31, xofs=-31, yofs= -8, **kw) # N S + sprite( 878+x, y, 64, 31, xofs=-31, yofs= -8, **kw) # N S W + sprite( 958+x, y, 64, 39, xofs=-31, yofs= -8, **kw) # N E + sprite(1038+x, y, 64, 39, xofs=-31, yofs= -8, **kw) # N E W + sprite(1118+x, y, 64, 31, xofs=-31, yofs= -8, **kw) # N E S + sprite(1196+x, y, 64, 47, xofs=-31, yofs=-16, **kw) # N E W STEEP + sprite(1276+x, y, 64, 15, xofs=-31, yofs= 0, **kw) # E S W STEEP + sprite(1356+x, y, 64, 31, xofs=-31, yofs= -8, **kw) # N S W STEEP + sprite(1436+x, y, 64, 31, xofs=-31, yofs= -8, **kw) # N E S STEEP + + +def replace_shore_sprites(sprite_id, file, x, y, **kw): + png = grf.ImageFile(file) + gen.add_sprite(grf.ReplaceSprites([(sprite_id, 8)])) + sprite = lambda *args, **kw: gen.add_sprite(grf.FileSprite(png, *args, **kw)) + sprite(320+x, y, 64, 31, xofs=-31, yofs= 0, **kw) + sprite( 80+x, y, 64, 31, xofs=-31, yofs= 0, **kw) + sprite(160+x, y, 64, 23, xofs=-31, yofs= 0, **kw) + sprite(638+x, y, 64, 39, xofs=-31, yofs=-8, **kw) + sprite(478+x, y, 64, 23, xofs=-31, yofs= 0, **kw) + sprite(958+x, y, 64, 39, xofs=-31, yofs=-8, **kw) + sprite(240+x, y, 64, 23, xofs=-31, yofs= 0, **kw) + sprite(718+x, y, 64, 39, xofs=-31, yofs=-8, **kw) + + +def replace_additional_rough_sprites(sprite_id, file, x, y, **kw): + png = grf.ImageFile(file) + gen.add_sprite(grf.ReplaceSprites([(sprite_id, 4)])) + sprite = lambda *args, **kw: gen.add_sprite(grf.FileSprite(png, *args, **kw)) + sprite( x, y, 64, 31, xofs=-31, yofs=0, **kw) + sprite( 80+x, y, 64, 31, xofs=-31, yofs=0, **kw) + sprite(160+x, y, 64, 31, xofs=-31, yofs=0, **kw) + sprite(240+x, y, 64, 31, xofs=-31, yofs=0, **kw) + +# Normal land +replace_ground_sprites(3981, 'gfx/grass_grid_temperate.gimp.png', 1, 1) + +# bulldozed (bare) land and regeneration stages: +replace_ground_sprites(3924, 'gfx/bare03_grid.gimp.png', 1, 1) +replace_ground_sprites(3943, 'gfx/bare13_grid_temperate.gimp.png', 1, 1) +replace_ground_sprites(3962, 'gfx/bare23_grid_temperate.gimp.png', 1, 1) + +# rough terrain +replace_ground_sprites(4000, 'gfx/rough_grid_temperate.gimp.png', 1, 1) +replace_additional_rough_sprites(4019, 'gfx/rough_grid_temperate.gimp.png', 1511, 1) + +# rocky terrain +replace_ground_sprites(4023, 'gfx/rocks_grid_temperate.gimp.png', 1, 1) + +# different snow densities: +replace_ground_sprites(4493, 'gfx/snow14_grid_alpine.gimp.png', 1, 1) +replace_ground_sprites(4512, 'gfx/snow24_grid_alpine.gimp.png', 1, 1) +replace_ground_sprites(4531, 'gfx/snow34_grid_alpine.gimp.png', 1, 1) +replace_ground_sprites(4550, 'gfx/snow_grid.gimp.png', 1, 1) + +# shore sprites (replacing 16 seems to do these as well) +# replace_shore_sprites(4062, 'gfx/water/seashore_grid_temperate.gimp.png', 1, 1) + +def replace_coastal_sprites(file, x, y, **kw): + png = grf.ImageFile(file) + gen.add_sprite(grf.ReplaceNewSprites(0x0d, 16)) + sprite = lambda *args, **kw: gen.add_sprite(grf.FileSprite(png, *args, **kw)) + sprite(1276+x, y, 64, 15, xofs=-31, yofs= 0, **kw) + sprite( 80+x, y, 64, 31, xofs=-31, yofs= 0, **kw) + sprite( 160+x, y, 64, 23, xofs=-31, yofs= 0, **kw) + sprite( 240+x, y, 64, 23, xofs=-31, yofs= 0, **kw) + sprite( 320+x, y, 64, 31, xofs=-31, yofs= 0, **kw) + sprite(1356+x, y, 64, 31, xofs=-31, yofs= -8, **kw) + sprite( 478+x, y, 64, 23, xofs=-31, yofs= 0, **kw) + sprite( 558+x, y, 64, 23, xofs=-31, yofs= 0, **kw) + sprite( 638+x, y, 64, 39, xofs=-31, yofs= -8, **kw) + sprite( 718+x, y, 64, 39, xofs=-31, yofs= -8, **kw) + sprite(1196+x, y, 64, 47, xofs=-31, yofs=-16, **kw) + sprite( 878+x, y, 64, 31, xofs=-31, yofs= -8, **kw) + sprite( 958+x, y, 64, 39, xofs=-31, yofs= -8, **kw) + sprite(1038+x, y, 64, 39, xofs=-31, yofs= -8, **kw) + sprite(1118+x, y, 64, 31, xofs=-31, yofs= -8, **kw) + sprite(1436+x, y, 64, 31, xofs=-31, yofs= -8, **kw) + + +replace_coastal_sprites('gfx/water/seashore_grid_temperate.gimp.png', 1, 1) + + +# CREEKS + + + + +# MEADOW + +# spriteset (meadow_groundsprites, "gfx/meadow_grid_temperate.png") { tmpl_groundsprites(1, 1) } + +# spriteset (meadow_transitions, "gfx/meadow_transitions.png") { +# tmpl_groundsprites(1, 0 * 64 + 1) +# tmpl_groundsprites(1, 1 * 64 + 1) +# tmpl_groundsprites(1, 2 * 64 + 1) +# tmpl_groundsprites(1, 3 * 64 + 1) +# tmpl_groundsprites(1, 4 * 64 + 1) +# tmpl_groundsprites(1, 5 * 64 + 1) +# tmpl_groundsprites(1, 6 * 64 + 1) +# tmpl_groundsprites(1, 7 * 64 + 1) +# tmpl_groundsprites(1, 8 * 64 + 1) +# tmpl_groundsprites(1, 9 * 64 + 1) +# tmpl_groundsprites(1, 10 * 64 + 1) +# tmpl_groundsprites(1, 11 * 64 + 1) +# tmpl_groundsprites(1, 12 * 64 + 1) +# tmpl_groundsprites(1, 13 * 64 + 1) +# tmpl_groundsprites(1, 14 * 64 + 1) +# tmpl_groundsprites(1, 15 * 64 + 1) +# } + +# spritelayout meadow_groundsprites_default { +# ground { +# sprite: meadow_transitions( +# slope_to_sprite_offset(tile_slope) +# + (nearby_tile_object_type( 0, -1) == meadow && nearby_tile_object_type(-1, -1) == meadow &&nearby_tile_object_type(-1, 0) == meadow ? 0 : 19) +# + (nearby_tile_object_type(-1, 0) == meadow && nearby_tile_object_type(-1, 1) == meadow &&nearby_tile_object_type( 0, 1) == meadow ? 0 : 38) +# + (nearby_tile_object_type( 0, 1) == meadow && nearby_tile_object_type( 1, 1) == meadow &&nearby_tile_object_type( 1, 0) == meadow ? 0 : 76) +# + (nearby_tile_object_type( 1, 0) == meadow && nearby_tile_object_type( 1, -1) == meadow &&nearby_tile_object_type( 0, -1) == meadow ? 0 : 152) +# ); +# } +# } + +# spritelayout meadow_groundsprites_purchase { +# ground { +# sprite: meadow_groundsprites; +# } +# } + + +# switch (FEAT_OBJECTS, SELF, switch_meadow_groundsprites_default, [ +# STORE_TEMP(slope_to_sprite_offset(tile_slope), 0) +# ]) { +# meadow_groundsprites_default; +# } + + +# item (FEAT_OBJECTS, meadow) { +# property { +# class: "FLMA"; +# classname: string(STR_FLMA); +# name: string(STR_TEST_OBJECT); +# climates_available: ALL_CLIMATES; +# end_of_life_date: 0xFFFFFFFF; +# object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); +# size: [1,1]; +# } +# graphics { +# default: meadow_groundsprites_default; +# purchase: meadow_groundsprites_purchase; +# tile_check: CB_RESULT_LOCATION_ALLOW; +# } +# } + +gen.write('alpine.grf') diff --git a/grf/alpine/alpine_gen.py b/grf/alpine/alpine_gen.py new file mode 100644 index 0000000000..612a5a62aa --- /dev/null +++ b/grf/alpine/alpine_gen.py @@ -0,0 +1,408 @@ +print("""\ +grf { + grfid: "CMAL"; + name: string(STR_GRF_NAME); + desc: string(STR_GRF_DESCRIPTION); + version: 1; + min_compatible_version: 1; +} + +template tmpl_groundsprites_flags(x, y, flags) { + // N E S W STEEP + [ 0+x, y, 64, 31, -31, 0, flags ] // + [ 80+x, y, 64, 31, -31, 0, flags ] // W + [ 160+x, y, 64, 23, -31, 0, flags ] // S + [ 240+x, y, 64, 23, -31, 0, flags ] // S W + + [ 320+x, y, 64, 31, -31, 0, flags ] // E + [ 398+x, y, 64, 31, -31, 0, flags ] // E W + [ 478+x, y, 64, 23, -31, 0, flags ] // E S + [ 558+x, y, 64, 23, -31, 0, flags ] // E S W + + [ 638+x, y, 64, 39, -31, -8, flags ] // N + [ 718+x, y, 64, 39, -31, -8, flags ] // N W + [ 798+x, y, 64, 31, -31, -8, flags ] // N S + [ 878+x, y, 64, 31, -31, -8, flags ] // N S W + + [ 958+x, y, 64, 39, -31, -8, flags ] // N E + [1038+x, y, 64, 39, -31, -8, flags ] // N E W + [1118+x, y, 64, 31, -31, -8, flags ] // N E S + [1196+x, y, 64, 47, -31,-16, flags ] // N E W STEEP + + [1276+x, y, 64, 15, -31, 0, flags ] // E S W STEEP + [1356+x, y, 64, 31, -31, -8, flags ] // N S W STEEP + [1436+x, y, 64, 31, -31, -8, flags ] // N E S STEEP +} + +template tmpl_groundsprites(x, y) { + tmpl_groundsprites_flags(x, y, 0) +} + +template tmpl_groundsprites_anim(x, y) { + tmpl_groundsprites_flags(x, y, ANIM) +} + +template tmpl_level_ground(x, y) { + [ x, y, 64, 31, -31, 0 ] +} + +template tmpl_rough(x, y) { + tmpl_level_ground( x, y) + tmpl_level_ground( 80+x, y) + tmpl_level_ground(160+x, y) + tmpl_level_ground(240+x, y) +} + +template tmpl_additional_rough(x, y) { + tmpl_rough(1510+x, y) +} + +template tmpl_16shore_tiles(x, y) { + [1276+x, y, 64, 15, -31, 0 ] + [ 80+x, y, 64, 31, -31, 0 ] + [ 160+x, y, 64, 23, -31, 0 ] + [ 240+x, y, 64, 23, -31, 0 ] + + [ 320+x, y, 64, 31, -31, 0 ] + [1356+x, y, 64, 31, -31, -8 ] + [ 478+x, y, 64, 23, -31, 0 ] + [ 558+x, y, 64, 23, -31, 0 ] + + [ 638+x, y, 64, 39, -31, -8 ] + [ 718+x, y, 64, 39, -31, -8 ] + [1196+x, y, 64, 47, -31,-16 ] + [ 878+x, y, 64, 31, -31, -8 ] + + [ 958+x, y, 64, 39, -31, -8 ] + [1038+x, y, 64, 39, -31, -8 ] + [1118+x, y, 64, 31, -31, -8 ] + [1436+x, y, 64, 31, -31, -8 ] +} + +template tmpl_8shore_tiles(x, y) { + [ 320+x, y, 64, 31, -31, 0 ] + [ 80+x, y, 64, 31, -31, 0 ] + [ 160+x, y, 64, 23, -31, 0 ] + [ 638+x, y, 64, 39, -31, -8 ] + + [ 478+x, y, 64, 23, -31, 0 ] + [ 958+x, y, 64, 39, -31, -8 ] + [ 240+x, y, 64, 23, -31, 0 ] + [ 718+x, y, 64, 39, -31, -8 ] +} + +template tmpl_tree_wide() { + [ 0, 0, 45, 80, -24, -73] + [ 50, 0, 45, 80, -24, -73] + [100, 0, 45, 80, -24, -73] + [150, 0, 45, 80, -24, -73] + [200, 0, 45, 80, -24, -73] + [250, 0, 45, 80, -24, -73] + [300, 0, 45, 80, -24, -73] +} + +template tmpl_tree_narrow() { + [ 0, 0, 35, 80, -19, -73] + [ 40, 0, 35, 80, -19, -73] + [ 80, 0, 35, 80, -19, -73] + [120, 0, 35, 80, -19, -73] + [160, 0, 35, 80, -19, -73] + [200, 0, 35, 80, -19, -73] + [240, 0, 35, 80, -19, -73] +} + +// Normal land: +replace (3981, "gfx/grass_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } + +// bulldozed (bare) land and regeneration stages: +replace (3924, "gfx/bare03_grid.gimp.png") { tmpl_groundsprites(1, 1) } +replace (3943, "gfx/bare13_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } +replace (3962, "gfx/bare23_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } + +// rough terrain +replace (4000, "gfx/rough_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } +replace (4019, "gfx/rough_grid_temperate.gimp.png") { tmpl_additional_rough(1, 1) } + +// rocky terrain +replace (4023, "gfx/rocks_grid_temperate.gimp.png") { tmpl_groundsprites(1, 1) } + +// different snow densities: +replace (4493, "gfx/snow14_grid_alpine.gimp.png") { tmpl_groundsprites(1, 1) } +replace (4512, "gfx/snow24_grid_alpine.gimp.png") { tmpl_groundsprites(1, 1) } +replace (4531, "gfx/snow34_grid_alpine.gimp.png") { tmpl_groundsprites(1, 1) } +replace (4550, "gfx/snow_grid.gimp.png") { tmpl_groundsprites(1, 1) } + +// shore sprites +replace (4062, "gfx/water/seashore_grid_temperate.gimp.png") { tmpl_8shore_tiles(1, 1) } +replacenew (COAST_TILES, "gfx/water/seashore_grid_temperate.gimp.png") { tmpl_16shore_tiles(1, 1) } + + +// //Arctic trees: the following trees have snowy equivalents: +// base_graphics spr1709(1709, "trees/tree_01_conifer.gimp.png") { tmpl_tree_narrow() } // 1709 conifer (snowy: 1765) +// base_graphics spr1716(1716, "trees/tree_06_leaf.gimp.png") { tmpl_tree_narrow() } // 1716 leaf tree (snowy: 1772) +// base_graphics spr1723(1723, "trees/tree_07_leaf.gimp.png") { tmpl_tree_narrow() } // 1723 leaf tree (snowy: 1779) +// base_graphics spr1730(1730, "trees/tree_08_conifer.gimp.png") { tmpl_tree_narrow() } // 1730 conifer (snowy: 1786) +// base_graphics spr1737(1737, "trees/tree_09_conifer.gimp.png") { tmpl_tree_narrow() } // 1737 conifer (snowy: 1793) +// base_graphics spr1744(1744, "trees/tree_04_conifer.gimp.png") { tmpl_tree_narrow() } // 1744 conifer (snowy: 1800) +// base_graphics spr1751(1751, "trees/tree_05_conifer.gimp.png") { tmpl_tree_narrow() } // 1751 conifer (snowy: 1807) +// base_graphics spr1758(1758, "trees/tree_10_leaf.gimp.png") { tmpl_tree_narrow() } // 1758 leaf tree (snowy: 1814) +// // snowy trees +// base_graphics spr1765(1765, "trees/tree_01_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1765 snowy conifer (equiv of 1709) +// base_graphics spr1772(1772, "trees/tree_06_snow_leaf.gimp.png") { tmpl_tree_narrow() } // 1772 snowy leaf tree (equiv. of 1716) +// base_graphics spr1779(1779, "trees/tree_07_snow_leaf.gimp.png") { tmpl_tree_narrow() } // 1779 snowy leaf tree (equiv. of 1723) +// base_graphics spr1786(1786, "trees/tree_08_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1786 snowy conifer (equiv. of 1730) +// base_graphics spr1793(1793, "trees/tree_09_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1793 snowy conifer (equiv. of 1737) +// base_graphics spr1800(1800, "trees/tree_04_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1800 snowy conifer (equiv. of 1744) +// base_graphics spr1807(1807, "trees/tree_05_snow_conifer.gimp.png") { tmpl_tree_narrow() } // 1807 snowy conifer (equiv. of 1751) +// base_graphics spr1814(1814, "trees/tree_10_snow_leaf.gimp.png") { tmpl_tree_narrow() } // 1814 snowy leaf tree (equiv. of 1758) + +spriteset (meadow_groundsprites, "gfx/meadow_grid_temperate.png") { tmpl_groundsprites(1, 1) } + + +spriteset (meadow_transitions, "gfx/meadow_transitions.png") { + tmpl_groundsprites(1, 0 * 64 + 1) + tmpl_groundsprites(1, 1 * 64 + 1) + tmpl_groundsprites(1, 2 * 64 + 1) + tmpl_groundsprites(1, 3 * 64 + 1) + tmpl_groundsprites(1, 4 * 64 + 1) + tmpl_groundsprites(1, 5 * 64 + 1) + tmpl_groundsprites(1, 6 * 64 + 1) + tmpl_groundsprites(1, 7 * 64 + 1) + tmpl_groundsprites(1, 8 * 64 + 1) + tmpl_groundsprites(1, 9 * 64 + 1) + tmpl_groundsprites(1, 10 * 64 + 1) + tmpl_groundsprites(1, 11 * 64 + 1) + tmpl_groundsprites(1, 12 * 64 + 1) + tmpl_groundsprites(1, 13 * 64 + 1) + tmpl_groundsprites(1, 14 * 64 + 1) + tmpl_groundsprites(1, 15 * 64 + 1) +} + +spritelayout meadow_groundsprites_default { + ground { + sprite: meadow_transitions( + slope_to_sprite_offset(tile_slope) + + (nearby_tile_object_type( 0, -1) == meadow && nearby_tile_object_type(-1, -1) == meadow &&nearby_tile_object_type(-1, 0) == meadow ? 0 : 19) + + (nearby_tile_object_type(-1, 0) == meadow && nearby_tile_object_type(-1, 1) == meadow &&nearby_tile_object_type( 0, 1) == meadow ? 0 : 38) + + (nearby_tile_object_type( 0, 1) == meadow && nearby_tile_object_type( 1, 1) == meadow &&nearby_tile_object_type( 1, 0) == meadow ? 0 : 76) + + (nearby_tile_object_type( 1, 0) == meadow && nearby_tile_object_type( 1, -1) == meadow &&nearby_tile_object_type( 0, -1) == meadow ? 0 : 152) + ); + } +} + +spritelayout meadow_groundsprites_purchase { + ground { + sprite: meadow_groundsprites; + } +} + + +switch (FEAT_OBJECTS, SELF, switch_meadow_groundsprites_default, [ + STORE_TEMP(slope_to_sprite_offset(tile_slope), 0) + ]) { + meadow_groundsprites_default; +} + + +item (FEAT_OBJECTS, meadow) { + property { + class: "FLMA"; + classname: string(STR_FLMA); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + } + graphics { + default: meadow_groundsprites_default; + purchase: meadow_groundsprites_purchase; + tile_check: CB_RESULT_LOCATION_ALLOW; + } +} + +spriteset (creek_groundsprites, "gfx/rivers.png") { + tmpl_groundsprites_anim(1, 0 * 64 + 1) + tmpl_groundsprites_anim(1, 1 * 64 + 1) + tmpl_groundsprites_anim(1, 2 * 64 + 1) + tmpl_groundsprites_anim(1, 3 * 64 + 1) + tmpl_groundsprites_anim(1, 4 * 64 + 1) + tmpl_groundsprites_anim(1, 5 * 64 + 1) + tmpl_groundsprites_anim(1, 6 * 64 + 1) + tmpl_groundsprites_anim(1, 7 * 64 + 1) + tmpl_groundsprites_anim(1, 8 * 64 + 1) + tmpl_groundsprites_anim(1, 9 * 64 + 1) + tmpl_groundsprites_anim(1, 10 * 64 + 1) + tmpl_groundsprites_anim(1, 11 * 64 + 1) + tmpl_groundsprites_anim(1, 12 * 64 + 1) + tmpl_groundsprites_anim(1, 13 * 64 + 1) + tmpl_groundsprites_anim(1, 14 * 64 + 1) + tmpl_groundsprites_anim(1, 15 * 64 + 1) + tmpl_groundsprites_anim(1, 16 * 64 + 1) + tmpl_groundsprites_anim(1, 17 * 64 + 1) + tmpl_groundsprites_anim(1, 18 * 64 + 1) + tmpl_groundsprites_anim(1, 19 * 64 + 1) + tmpl_groundsprites_anim(1, 20 * 64 + 1) + tmpl_groundsprites_anim(1, 21 * 64 + 1) + tmpl_groundsprites_anim(1, 22 * 64 + 1) + tmpl_groundsprites_anim(1, 23 * 64 + 1) + tmpl_groundsprites_anim(1, 24 * 64 + 1) + tmpl_groundsprites_anim(1, 25 * 64 + 1) + tmpl_groundsprites_anim(1, 26 * 64 + 1) + tmpl_groundsprites_anim(1, 27 * 64 + 1) + tmpl_groundsprites_anim(1, 28 * 64 + 1) + tmpl_groundsprites_anim(1, 29 * 64 + 1) + tmpl_groundsprites_anim(1, 30 * 64 + 1) + tmpl_groundsprites_anim(1, 31 * 64 + 1) + tmpl_groundsprites_anim(1, 32 * 64 + 1) + tmpl_groundsprites_anim(1, 33 * 64 + 1) + tmpl_groundsprites_anim(1, 34 * 64 + 1) + tmpl_groundsprites_anim(1, 35 * 64 + 1) + tmpl_groundsprites_anim(1, 36 * 64 + 1) + tmpl_groundsprites_anim(1, 37 * 64 + 1) + tmpl_groundsprites_anim(1, 38 * 64 + 1) + tmpl_groundsprites_anim(1, 39 * 64 + 1) + tmpl_groundsprites_anim(1, 40 * 64 + 1) + tmpl_groundsprites_anim(1, 41 * 64 + 1) + tmpl_groundsprites_anim(1, 42 * 64 + 1) + tmpl_groundsprites_anim(1, 43 * 64 + 1) + tmpl_groundsprites_anim(1, 44 * 64 + 1) + tmpl_groundsprites_anim(1, 45 * 64 + 1) + tmpl_groundsprites_anim(1, 46 * 64 + 1) + tmpl_groundsprites_anim(1, 47 * 64 + 1) + tmpl_groundsprites_anim(1, 48 * 64 + 1) + tmpl_groundsprites_anim(1, 49 * 64 + 1) + tmpl_groundsprites_anim(1, 50 * 64 + 1) + tmpl_groundsprites_anim(1, 51 * 64 + 1) + tmpl_groundsprites_anim(1, 52 * 64 + 1) + tmpl_groundsprites_anim(1, 53 * 64 + 1) + tmpl_groundsprites_anim(1, 54 * 64 + 1) + tmpl_groundsprites_anim(1, 55 * 64 + 1) + tmpl_groundsprites_anim(1, 56 * 64 + 1) + tmpl_groundsprites_anim(1, 57 * 64 + 1) + tmpl_groundsprites_anim(1, 58 * 64 + 1) + tmpl_groundsprites_anim(1, 59 * 64 + 1) + tmpl_groundsprites_anim(1, 60 * 64 + 1) + tmpl_groundsprites_anim(1, 61 * 64 + 1) + tmpl_groundsprites_anim(1, 62 * 64 + 1) + tmpl_groundsprites_anim(1, 63 * 64 + 1) + tmpl_groundsprites_anim(1, 64 * 64 + 1) + tmpl_groundsprites_anim(1, 65 * 64 + 1) + tmpl_groundsprites_anim(1, 66 * 64 + 1) + tmpl_groundsprites_anim(1, 67 * 64 + 1) + tmpl_groundsprites_anim(1, 68 * 64 + 1) + tmpl_groundsprites_anim(1, 69 * 64 + 1) + tmpl_groundsprites_anim(1, 70 * 64 + 1) + tmpl_groundsprites_anim(1, 71 * 64 + 1) + tmpl_groundsprites_anim(1, 72 * 64 + 1) + tmpl_groundsprites_anim(1, 73 * 64 + 1) + tmpl_groundsprites_anim(1, 74 * 64 + 1) + tmpl_groundsprites_anim(1, 75 * 64 + 1) + tmpl_groundsprites_anim(1, 76 * 64 + 1) + tmpl_groundsprites_anim(1, 77 * 64 + 1) + tmpl_groundsprites_anim(1, 78 * 64 + 1) + tmpl_groundsprites_anim(1, 79 * 64 + 1) + tmpl_groundsprites_anim(1, 80 * 64 + 1) +} + +spritelayout creek_groundsprites_default(n, tile_height) { + ground { + sprite: + (climate == CLIMATE_ARCTIC && tile_height > snowline_height - 2 ? + GROUNDSPRITE_SNOW + min(tile_height - snowline_height - 2, 0) * 19 + : (terrain_type == TILETYPE_DESERT ? GROUNDSPRITE_DESERT : GROUNDSPRITE_NORMAL)) + + slope_to_sprite_offset(tile_slope); + } + childsprite { + sprite: creek_groundsprites( + slope_to_sprite_offset(tile_slope) + 19 * n + ); + always_draw: 1; + } +} + +spritelayout creek_groundsprites_purchase(n) { + ground { sprite: GROUNDSPRITE_NORMAL; } + childsprite { + sprite: creek_groundsprites(19 * n); + always_draw: 1; + } +} + +""") + +print('spriteset (mine_number_sprites, "gfx/mine_numbers.png") {') +for i in range(10): + print(f' [{i * 12}, 0, 12, 16, -6, 8]') +print('}') + +print(f""" \ +spritelayout minefield_sprites(n) {{ + ground {{ sprite: GROUNDSPRITE_NORMAL + slope_to_sprite_offset(tile_slope); }} + childsprite {{ + sprite: mine_number_sprites(n); + always_draw: 1; + }} +}} +""") + +print(f""" \ +item (FEAT_OBJECTS, minefield) {{ + property {{ + class: "MINE"; + classname: string(STR_MINEFIELD); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + num_views: 2; + }} + graphics {{ + default: minefield_sprites( + ( + (nearby_tile_object_type(-1, -1) == minefield) + + (nearby_tile_object_type(-1, 0) == minefield) + + (nearby_tile_object_type(-1, 1) == minefield) + + (nearby_tile_object_type(0, -1) == minefield) + + (nearby_tile_object_type(0, 1) == minefield) + + (nearby_tile_object_type(1, -1) == minefield) + + (nearby_tile_object_type(1, 0) == minefield) + + (nearby_tile_object_type(1, 1) == minefield) + ) == 8 ? 9 : ( + (nearby_tile_object_view(-1, -1)) + + (nearby_tile_object_view(-1, 0)) + + (nearby_tile_object_view(-1, 1)) + + (nearby_tile_object_view(0, -1)) + + (nearby_tile_object_view(0, 1)) + + (nearby_tile_object_view(0, 0)) + + (nearby_tile_object_view(1, -1)) + + (nearby_tile_object_view(1, 0)) + + (nearby_tile_object_view(1, 1)) + ) + ); + purchase: minefield_sprites(9); + tile_check: CB_RESULT_LOCATION_ALLOW; + }} +}} +""") + +for i in range(81): + print(f"""\ +item (FEAT_OBJECTS, rivers_{i}) {{ + property {{ + class: "CREE"; + classname: string(STR_CREEK); + name: string(STR_TEST_OBJECT); + climates_available: ALL_CLIMATES; + end_of_life_date: 0xFFFFFFFF; + object_flags:bitmask(OBJ_FLAG_ALLOW_BRIDGE, OBJ_FLAG_ANYTHING_REMOVE, OBJ_FLAG_NO_FOUNDATIONS); + size: [1,1]; + }} + graphics {{ + default: creek_groundsprites_default({i}, nearby_tile_height(0, 0)); + purchase: creek_groundsprites_purchase({i}); + tile_check: CB_RESULT_LOCATION_ALLOW; + }} +}} +""") diff --git a/grf/alpine/gen_sprites.py b/grf/alpine/gen_sprites.py new file mode 100644 index 0000000000..9341680ea6 --- /dev/null +++ b/grf/alpine/gen_sprites.py @@ -0,0 +1,302 @@ +from PIL import Image, ImageDraw +import numpy as np + +import math +import os +import spectra + +SAFE_COLORS = list(range(1, 0xD7)) +f = open("../ttd-newgrf-dos.gpl") + +while f.readline().strip() != "#": + pass + + +colors = [] +for _ in range(256): + try: + r, g, b, _, i = f.readline().split() + except ValueError: + break + c = spectra.rgb(float(r) / 255., float(g) / 255., float(b) / 255.) + # if c in SAFE_COLORS: + colors.append((int(i), c)) + +def color_distance(c1, c2): + rmean = (c1.rgb[0] + c2.rgb[0]) / 2. + r = c1.rgb[0] - c2.rgb[0] + g = c1.rgb[1] - c2.rgb[1] + b = c1.rgb[2] - c2.rgb[2] + return math.sqrt( + ((2 + rmean) * r * r) + + 4 * g * g + + (3 - rmean) * b * b) + +def find_best_color(x): + mj, md = 0, 1e100 + for j, c in colors: + if j not in SAFE_COLORS: + continue + d = color_distance(x, c) + if d < md: + mj, md = j, d + return mj + +def gen_recolor(color_func): + out = np.arange(256, dtype=np.uint8) + for i, c in colors: + if i not in SAFE_COLORS: + continue + out[i] = find_best_color(color_func(c)) + return out + +def gen_tint(tint, ratio): + return lambda x: find_best_color(x.blend(tint, ratio=ratio)) + +def gen_brightness(level): + def func(x): + if level > 0: + return x.brighten(amount=2.56 * level) + else: + return x.darken(amount=-2.56 * level) + return gen_recolor(func) + +# def gen_land_recolor(): +# def func(x): +# if 2 * g > r + b: +# x = x.blend(spectra.rgb(0.7, 1, 0), ratio=0.2) +# else: +# x = x.saturate(20) +# return x +# return gen_recolor(func) + +def gen_land_recolor(): + def func(x): + r, g, b = x.rgb + if 2 * g > r + b: + x = x.blend(spectra.rgb(0.7, 1, 0), ratio=0.05) + x = x.saturate(20) + # # elif 3 * b > r + g: + # # x = x.blend(spectra.rgb(0, 0, 1), ratio=0.3) + # # x = x.blend(spectra.rgb(1, 0, 1), ratio=0.5) + # # x = x.saturate(40) + else: + x = x.blend(spectra.rgb(0.7, 1, 0), ratio=0.05) + x = x.saturate(5) + return x + return gen_recolor(func) + +def remap_file(f_in, f_out, palmap): + print(f"Converting {f_out}...") + im = Image.open(f_in) + data = np.array(im) + data = palmap[data] + im2 = Image.fromarray(data) + im2.putpalette(im.getpalette()) + im2.save(f_out) + + +SOURCE_DIR = "/home/pavels/Projects/cmclient/local/ogfx-landscape-1.1.2-source/src/gfx" +DEST_DIR = "gfx" +land_palmap = gen_land_recolor() + +for fname in ("grass_grid_temperate.gimp.png", + "bare03_grid.gimp.png", + "bare13_grid_temperate.gimp.png", + "bare23_grid_temperate.gimp.png", + "rough_grid_temperate.gimp.png", + "rough_grid_temperate.gimp.png", + "rocks_grid_temperate.gimp.png", + "snow14_grid_alpine.gimp.png", + "snow24_grid_alpine.gimp.png", + "snow34_grid_alpine.gimp.png", + "snow_grid.gimp.png", + "water/seashore_grid_temperate.gimp.png", + ): + remap_file(os.path.join(SOURCE_DIR, fname), os.path.join(DEST_DIR, fname), land_palmap) + +# SOURCE_DIR = "/home/pavels/Builds/OpenGFX" + +# TREES = [ +# "sprites/png/trees/arctic/tree_01_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_06_leaf.gimp.png", +# "sprites/png/trees/arctic/tree_07_leaf.gimp.png", +# "sprites/png/trees/arctic/tree_08_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_09_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_04_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_05_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_10_leaf.gimp.png", +# "sprites/png/trees/arctic/tree_01_snow_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_06_snow_leaf.gimp.png", +# "sprites/png/trees/arctic/tree_07_snow_leaf.gimp.png", +# "sprites/png/trees/arctic/tree_08_snow_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_09_snow_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_04_snow_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_05_snow_conifer.gimp.png", +# "sprites/png/trees/arctic/tree_10_snow_leaf.gimp.png", +# ] + +# for fname in TREES: + +def meadow_recolor(x): + x = x.blend(spectra.rgb(0.7, 1, 0), ratio=0.2) + return x.blend(spectra.rgb(1, 1, 0), ratio=0.4) + +def half_meadow_recolor(x): + x = x.blend(spectra.rgb(0.7, 1, 0), ratio=0.2) + return x.blend(spectra.rgb(1, 1, 0), ratio=0.2) + +remap_file(os.path.join(SOURCE_DIR, "grass_grid_temperate.gimp.png"), os.path.join(DEST_DIR, "meadow_grid_temperate.png"), gen_recolor(meadow_recolor)) +remap_file(os.path.join(SOURCE_DIR, "grass_grid_temperate.gimp.png"), os.path.join(DEST_DIR, "half_meadow_grid_temperate.png"), gen_recolor(half_meadow_recolor)) + +# Generate meadow transition tiles +im = Image.open(os.path.join(SOURCE_DIR, "grass_grid_temperate.gimp.png")) +din = np.array(im) + +GROUND_SPRITES = [ + # N E S W STEEP + [ 0 + 1, 1, 64, 31, -31, 0, 15, 15], # + [ 80 + 1, 1, 64, 31, -31, 0, 7, 15], # W + [ 160 + 1, 1, 64, 23, -31, 0, 15, 15], # S + [ 240 + 1, 1, 64, 23, -31, 0, 7, 15], # S W + [ 320 + 1, 1, 64, 31, -31, 0, 15, 7], # E + [ 398 + 1, 1, 64, 31, -31, 0, 7, 7], # E W + [ 478 + 1, 1, 64, 23, -31, 0, 15, 7], # E S + [ 558 + 1, 1, 64, 23, -31, 0, 7, 7], # E S W + [ 638 + 1, 1, 64, 39, -31, -8, 23, 23], # N + [ 718 + 1, 1, 64, 39, -31, -8, 15, 23], # N W + [ 798 + 1, 1, 64, 31, -31, -8, 23, 23], # N S + [ 878 + 1, 1, 64, 31, -31, -8, 15, 23], # N S W + [ 958 + 1, 1, 64, 39, -31, -8, 23, 15], # N E + [1038 + 1, 1, 64, 39, -31, -8, 15, 15], # N E W + [1118 + 1, 1, 64, 31, -31, -8, 23, 15], # N E S + [1196 + 1, 1, 64, 47, -31,-16, 23, 23], # N E W STEEP + [1276 + 1, 1, 64, 15, -31, 0, 7, 7], # E S W STEEP + [1356 + 1, 1, 64, 31, -31, -8, 7, 23], # N S W STEEP + [1436 + 1, 1, 64, 31, -31, -8, 23, 7], # N E S STEEP +] + +# dout = np.zeros((64 * 8, 31 + 47 + 15), dtype=np.uint8) +# dout = np.zeros((31 + 47 + 15, 64 * 8), dtype=np.uint8) +# dout = np.zeros((64 * 16, im.width), dtype=np.uint8) +# for i in range (16): +# print(f'Generating sprite row {i}/16...') +# for j, (ox, oy, w, h, _ox, _oy, h1, h2) in enumerate(GROUND_SPRITES): +# hn1 = 2. * (h1 + .5 - h / 2.) / h +# hn2 = 2. * (h2 + .5 - h / 2.) / h +# iflags = [i & (1 << k) for k in range(4)] +# ut, uc, ub = i & 1, (i & 2) / 2, (i & 4) / 4 +# for y in range(0, h): +# for x in range(0, w): +# c = din[y + oy, x + ox] +# if not c: continue +# xn = 2. * (x + .5 - w / 2.) / w +# yn = 2. * (y + .5 - h / 2.) / h +# dn = math.hypot(xn, yn + 1) +# ds = math.hypot(xn, yn - 1) +# de = math.hypot(xn - 1, yn - hn1) +# dw = math.hypot(xn + 1, yn - hn2) +# f = min(d if fl else 2. for d, fl in zip([dn, de, ds, dw], iflags)) +# f = min(f * 1.44, 1.) +# bc = spectra.rgb(f, 1, 0) +# c = colors[c][1].blend(bc, ratio=0.2 + 0.1 * f) +# dout[oy + y + 64 * i, ox + x] = find_best_color(c) +# im2 = Image.fromarray(dout) +# im2.putpalette(im.getpalette()) +# im2.save(os.path.join(DEST_DIR, "meadow_transitions.png")) + + +dmask = np.vectorize(lambda x: 0 if x and x != 0xFF else 0xFF)(din).astype('uint8') +immask = Image.fromarray(dmask, mode="L") +# immask.save(os.path.join(DEST_DIR, "mask.png")) + +dout = np.zeros((64 * 81, im.width), dtype=np.uint8) +im2 = Image.fromarray(dout) +im2.putpalette(im.getpalette()) +imd2 = ImageDraw.Draw(im2) + # draw.line((0, 0) + im.size, fill=128) + # draw.line((0, im.size[1], im.size[0], 0), fill=128) + +def draw_bezier(imd, fill, width, a, b, c): + N, M = 11, 2 + + lerp = lambda x, y, t: t * x + (N - t) * y + lerp2m = lambda a, b, t: (lerp(a[0], (a[0] + b[0]) // 2, t), lerp(a[1], (a[1] + b[1]) // 2, t)) + lerp2 = lambda a, b, t: (lerp(a[0], b[0], t), lerp(a[1], b[1], t)) + + for t in range(-M, N + M + 1): + p0 = lerp2m(a, b, t) + p1 = lerp2m(c, b, N - t) + pf = lerp2(p0, p1, t) + x = pf[0] // N // N + y = pf[1] // N // N + imd.ellipse((x - width, y - width, x + width, y + width), fill=fill) + + +for i in range (81): + print(f'Generating rivers sprite row {i + 1}/81...') + + points = (i % 3, (i // 3) % 3, (i // 9) % 3, (i // 27)) + inp = [] + outp = [] + for ii, p in enumerate(points): + if p == 2: outp.append(ii) + elif p == 1: inp.append(ii) + + if not inp: inp = [4] + if not outp: outp = [4] + + for j, (ox, oy, w, h, _ox, _oy, h1, h2) in enumerate(GROUND_SPRITES): + xx, yy = ox, oy + 64 * i + + # # tile outline + # corners = ((0, h1), (w / 2, 0), (w, h2), (w / 2, h)) + # for ii in range(len(corners)): + # x1, y1 = corners[ii] + # x2, y2 = corners[(ii + 1) % len(corners)] + # imd2.line(((x1 + xx, y1 + yy), (x2 + xx, y2 + yy)), fill=0xA9, width=1) + + # hn1 = 2. * (h1 + .5 - h / 2.) / h + # hn2 = 2. * (h2 + .5 - h / 2.) / h + wc = w // 4 + edges = ((wc, h1 / 2), (w - wc, h2 / 2), (w - wc, (h + h2) / 2), (wc, (h + h1) / 2), (w / 2, h / 2)) + center = (w / 2 + xx, h / 2 + yy) + # if not inp: + + # continue + for ii in inp: + for oo in outp: + xy = ((edges[ii][0] + xx, edges[ii][1] + yy), (edges[oo][0] + xx, edges[oo][1] + yy)) + draw_bezier(imd2, 0x42, 4, xy[0], center, xy[1]) + for ii in inp: + for oo in outp: + xy = ((edges[ii][0] + xx, edges[ii][1] + yy), (edges[oo][0] + xx, edges[oo][1] + yy)) + draw_bezier(imd2, 0xF5, 3, xy[0], center, xy[1]) + + # # mark out + # for oo in outp: + # x, y = edges[oo][0] + xx, edges[oo][1] + yy + # width = 3 + # imd2.ellipse((x - width, y - width, x + width, y + width), fill=0x42) + + imd2.bitmap((0, i * 64), immask, fill=0) + # iflags = [i & (1 << k) for k in range(4)] + # ut, uc, ub = i & 1, (i & 2) / 2, (i & 4) / 4 + # for y in range(0, h): + # for x in range(0, w): + # c = din[y + oy, x + ox] + # if not c: continue + # xn = 2. * (x + .5 - w / 2.) / w + # yn = 2. * (y + .5 - h / 2.) / h + # dn = math.hypot(xn, yn + 1) + # ds = math.hypot(xn, yn - 1) + # de = math.hypot(xn - 1, yn - hn1) + # dw = math.hypot(xn + 1, yn - hn2) + # f = min(d if fl else 2. for d, fl in zip([dn, de, ds, dw], iflags)) + # f = min(f * 1.44, 1.) + # bc = spectra.rgb(f, 1, 0) + # c = colors[c][1].blend(bc, ratio=0.2 + 0.1 * f) + # dout[oy + y + 64 * i, ox + x] = find_best_color(c) +# im2 = Image.fromarray(dout) +# im2.putpalette(im.getpalette()) +im2.save(os.path.join(DEST_DIR, "rivers.png")) diff --git a/grf/alpine/gfx/bare03_grid.gimp.png b/grf/alpine/gfx/bare03_grid.gimp.png new file mode 100644 index 0000000000..18419105a0 Binary files /dev/null and b/grf/alpine/gfx/bare03_grid.gimp.png differ diff --git a/grf/alpine/gfx/bare13_grid_temperate.gimp.png b/grf/alpine/gfx/bare13_grid_temperate.gimp.png new file mode 100644 index 0000000000..dfe2c8c63b Binary files /dev/null and b/grf/alpine/gfx/bare13_grid_temperate.gimp.png differ diff --git a/grf/alpine/gfx/bare23_grid_temperate.gimp.png b/grf/alpine/gfx/bare23_grid_temperate.gimp.png new file mode 100644 index 0000000000..81c23b9b15 Binary files /dev/null and b/grf/alpine/gfx/bare23_grid_temperate.gimp.png differ diff --git a/grf/alpine/gfx/grass_grid_temperate.gimp.png b/grf/alpine/gfx/grass_grid_temperate.gimp.png new file mode 100644 index 0000000000..714d2f81c6 Binary files /dev/null and b/grf/alpine/gfx/grass_grid_temperate.gimp.png differ diff --git a/grf/alpine/gfx/half_meadow_grid_temperate.png b/grf/alpine/gfx/half_meadow_grid_temperate.png new file mode 100644 index 0000000000..2285d8ec75 Binary files /dev/null and b/grf/alpine/gfx/half_meadow_grid_temperate.png differ diff --git a/grf/alpine/gfx/mask.png b/grf/alpine/gfx/mask.png new file mode 100644 index 0000000000..a1e55de64c Binary files /dev/null and b/grf/alpine/gfx/mask.png differ diff --git a/grf/alpine/gfx/meadow_grid_temperate.png b/grf/alpine/gfx/meadow_grid_temperate.png new file mode 100644 index 0000000000..687db448b8 Binary files /dev/null and b/grf/alpine/gfx/meadow_grid_temperate.png differ diff --git a/grf/alpine/gfx/meadow_transitions.png b/grf/alpine/gfx/meadow_transitions.png new file mode 100644 index 0000000000..0c38053a6b Binary files /dev/null and b/grf/alpine/gfx/meadow_transitions.png differ diff --git a/grf/alpine/gfx/rivers.png b/grf/alpine/gfx/rivers.png new file mode 100644 index 0000000000..c3f3648b05 Binary files /dev/null and b/grf/alpine/gfx/rivers.png differ diff --git a/grf/alpine/gfx/rocks_grid_temperate.gimp.png b/grf/alpine/gfx/rocks_grid_temperate.gimp.png new file mode 100644 index 0000000000..8221a67c07 Binary files /dev/null and b/grf/alpine/gfx/rocks_grid_temperate.gimp.png differ diff --git a/grf/alpine/gfx/rough_grid_temperate.gimp.png b/grf/alpine/gfx/rough_grid_temperate.gimp.png new file mode 100644 index 0000000000..146be74b83 Binary files /dev/null and b/grf/alpine/gfx/rough_grid_temperate.gimp.png differ diff --git a/grf/alpine/gfx/snow14_grid_alpine.gimp.png b/grf/alpine/gfx/snow14_grid_alpine.gimp.png new file mode 100644 index 0000000000..eb3f34c49b Binary files /dev/null and b/grf/alpine/gfx/snow14_grid_alpine.gimp.png differ diff --git a/grf/alpine/gfx/snow24_grid_alpine.gimp.png b/grf/alpine/gfx/snow24_grid_alpine.gimp.png new file mode 100644 index 0000000000..bd6fb56a3b Binary files /dev/null and b/grf/alpine/gfx/snow24_grid_alpine.gimp.png differ diff --git a/grf/alpine/gfx/snow34_grid_alpine.gimp.png b/grf/alpine/gfx/snow34_grid_alpine.gimp.png new file mode 100644 index 0000000000..5577ea9696 Binary files /dev/null and b/grf/alpine/gfx/snow34_grid_alpine.gimp.png differ diff --git a/grf/alpine/gfx/snow_grid.gimp.png b/grf/alpine/gfx/snow_grid.gimp.png new file mode 100644 index 0000000000..b44aae6c9f Binary files /dev/null and b/grf/alpine/gfx/snow_grid.gimp.png differ diff --git a/grf/alpine/gfx/water/seashore_grid_temperate.gimp.png b/grf/alpine/gfx/water/seashore_grid_temperate.gimp.png new file mode 100644 index 0000000000..7dc5c5a4e3 Binary files /dev/null and b/grf/alpine/gfx/water/seashore_grid_temperate.gimp.png differ diff --git a/grf/alpine/grf.py b/grf/alpine/grf.py new file mode 100644 index 0000000000..7ebcb34d4f --- /dev/null +++ b/grf/alpine/grf.py @@ -0,0 +1,336 @@ +import math + +from PIL import Image, ImageDraw +from nml.spriteencoder import SpriteEncoder +import spectra +import struct +import numpy as np + +to_spectra = lambda r, g, b: spectra.rgb(float(r) / 255., float(g) / 255., float(b) / 255.) +# working with DOS palette only +PALETTE = (0, 0, 255, 16, 16, 16, 32, 32, 32, 48, 48, 48, 64, 64, 64, 80, 80, 80, 100, 100, 100, 116, 116, 116, 132, 132, 132, 148, 148, 148, 168, 168, 168, 184, 184, 184, 200, 200, 200, 216, 216, 216, 232, 232, 232, 252, 252, 252, 52, 60, 72, 68, 76, 92, 88, 96, 112, 108, 116, 132, 132, 140, 152, 156, 160, 172, 176, 184, 196, 204, 208, 220, 48, 44, 4, 64, 60, 12, 80, 76, 20, 96, 92, 28, 120, 120, 64, 148, 148, 100, 176, 176, 132, 204, 204, 168, 72, 44, 4, 88, 60, 20, 104, 80, 44, 124, 104, 72, 152, 132, 92, 184, 160, 120, 212, 188, 148, 244, 220, 176, 64, 0, 4, 88, 4, 16, 112, 16, 32, 136, 32, 52, 160, 56, 76, 188, 84, 108, 204, 104, 124, 220, 132, 144, 236, 156, 164, 252, 188, 192, 252, 208, 0, 252, 232, 60, 252, 252, 128, 76, 40, 0, 96, 60, 8, 116, 88, 28, 136, 116, 56, 156, 136, 80, 176, 156, 108, 196, 180, 136, 68, 24, 0, 96, 44, 4, 128, 68, 8, 156, 96, 16, 184, 120, 24, 212, 156, 32, 232, 184, 16, 252, 212, 0, 252, 248, 128, 252, 252, 192, 32, 4, 0, 64, 20, 8, 84, 28, 16, 108, 44, 28, 128, 56, 40, 148, 72, 56, 168, 92, 76, 184, 108, 88, 196, 128, 108, 212, 148, 128, 8, 52, 0, 16, 64, 0, 32, 80, 4, 48, 96, 4, 64, 112, 12, 84, 132, 20, 104, 148, 28, 128, 168, 44, 28, 52, 24, 44, 68, 32, 60, 88, 48, 80, 104, 60, 104, 124, 76, 128, 148, 92, 152, 176, 108, 180, 204, 124, 16, 52, 24, 32, 72, 44, 56, 96, 72, 76, 116, 88, 96, 136, 108, 120, 164, 136, 152, 192, 168, 184, 220, 200, 32, 24, 0, 56, 28, 0, 72, 40, 4, 88, 52, 12, 104, 64, 24, 124, 84, 44, 140, 108, 64, 160, 128, 88, 76, 40, 16, 96, 52, 24, 116, 68, 40, 136, 84, 56, 164, 96, 64, 184, 112, 80, 204, 128, 96, 212, 148, 112, 224, 168, 128, 236, 188, 148, 80, 28, 4, 100, 40, 20, 120, 56, 40, 140, 76, 64, 160, 100, 96, 184, 136, 136, 36, 40, 68, 48, 52, 84, 64, 64, 100, 80, 80, 116, 100, 100, 136, 132, 132, 164, 172, 172, 192, 212, 212, 224, 40, 20, 112, 64, 44, 144, 88, 64, 172, 104, 76, 196, 120, 88, 224, 140, 104, 252, 160, 136, 252, 188, 168, 252, 0, 24, 108, 0, 36, 132, 0, 52, 160, 0, 72, 184, 0, 96, 212, 24, 120, 220, 56, 144, 232, 88, 168, 240, 128, 196, 252, 188, 224, 252, 16, 64, 96, 24, 80, 108, 40, 96, 120, 52, 112, 132, 80, 140, 160, 116, 172, 192, 156, 204, 220, 204, 240, 252, 172, 52, 52, 212, 52, 52, 252, 52, 52, 252, 100, 88, 252, 144, 124, 252, 184, 160, 252, 216, 200, 252, 244, 236, 72, 20, 112, 92, 44, 140, 112, 68, 168, 140, 100, 196, 168, 136, 224, 200, 176, 248, 208, 184, 255, 232, 208, 252, 60, 0, 0, 92, 0, 0, 128, 0, 0, 160, 0, 0, 196, 0, 0, 224, 0, 0, 252, 0, 0, 252, 80, 0, 252, 108, 0, 252, 136, 0, 252, 164, 0, 252, 192, 0, 252, 220, 0, 252, 252, 0, 204, 136, 8, 228, 144, 4, 252, 156, 0, 252, 176, 48, 252, 196, 100, 252, 216, 152, 8, 24, 88, 12, 36, 104, 20, 52, 124, 28, 68, 140, 40, 92, 164, 56, 120, 188, 72, 152, 216, 100, 172, 224, 92, 156, 52, 108, 176, 64, 124, 200, 76, 144, 224, 92, 224, 244, 252, 200, 236, 248, 180, 220, 236, 132, 188, 216, 88, 152, 172, 244, 0, 244, 245, 0, 245, 246, 0, 246, 247, 0, 247, 248, 0, 248, 249, 0, 249, 250, 0, 250, 251, 0, 251, 252, 0, 252, 253, 0, 253, 254, 0, 254, 255, 0, 255, 76, 24, 8, 108, 44, 24, 144, 72, 52, 176, 108, 84, 210, 146, 126, 252, 60, 0, 252, 84, 0, 252, 104, 0, 252, 124, 0, 252, 148, 0, 252, 172, 0, 252, 196, 0, 64, 0, 0, 255, 0, 0, 48, 48, 0, 64, 64, 0, 80, 80, 0, 255, 255, 0, 32, 68, 112, 36, 72, 116, 40, 76, 120, 44, 80, 124, 48, 84, 128, 72, 100, 144, 100, 132, 168, 216, 244, 252, 96, 128, 164, 68, 96, 140, 255, 255, 255) +SAFE_COLORS = set(range(1, 0xD7)) +ALL_COLORS = set(range(256)) +SPECTRA_PALETTE = {i:to_spectra(PALETTE[i * 3], PALETTE[i * 3 + 1], PALETTE[i * 3 + 2]) for i in range(256)} +WATER_COLORS = set(range(0xF5, 0xFF)) + +# ZOOM_OUT_4X, ZOOM_NORMAL, ZOOM_OUT_2X, ZOOM_OUT_8X, ZOOM_OUT_16X, ZOOM_OUT_32X = range(6) +ZOOM_4X, ZOOM_NORMAL, ZOOM_2X, ZOOM_8X, ZOOM_16X, ZOOM_32X = range(6) +BPP_8, BPP_32 = range(2) + +def color_distance(c1, c2): + rmean = (c1.rgb[0] + c2.rgb[0]) / 2. + r = c1.rgb[0] - c2.rgb[0] + g = c1.rgb[1] - c2.rgb[1] + b = c1.rgb[2] - c2.rgb[2] + return math.sqrt( + ((2 + rmean) * r * r) + + 4 * g * g + + (3 - rmean) * b * b) + + +def find_best_color(x, in_range=SAFE_COLORS): + mj, md = 0, 1e100 + for j in in_range: + c = SPECTRA_PALETTE[j] + d = color_distance(x, c) + if d < md: + mj, md = j, d + return mj + + +# def map_rgb_image(self, im): +# assert im.mode == 'RGB', im.mode +# data = np.array(im) + + +class BaseSprite: + def get_data(self): + raise NotImplemented + + def get_data_size(self): + raise NotImplemented + + +class PaletteRemap(BaseSprite): + def __init__(self, ranges=None): + self.remap = np.arange(256, dtype=np.uint8) + if ranges: + self.set_ranges(ranges) + + def get_data(self): + return b'\x00' + self.remap.tobytes() + + def get_data_size(self): + return 257 + + @classmethod + def from_function(cls, color_func, remap_water=False): + res = cls() + for i in SAFE_COLORS: + res.remap[i] = find_best_color(color_func(SPECTRA_PALETTE[i])) + if remap_water: + for i in WATER_COLORS: + res.remap[i] = find_best_color(color_func(SPECTRA_PALETTE[i])) + return res + + def set_ranges(self, ranges): + for r in ranges: + f, t, v = r + self.remap[f: t + 1] = v + + def remap_image(self, im): + assert im.mode == 'P', im.mode + data = np.array(im) + data = self.remap[data] + res = Image.fromarray(data) + res.putpalette(PALETTE) + return res + + +class RealSprite(BaseSprite): + def __init__(self, w, h, *, xofs=0, yofs=0, zoom=ZOOM_4X): + self.sprite_id = None + self.w = w + self.h = h + # self.file = None + # self.x = None + # self.y = None + self.xofs = xofs + self.yofs = yofs + self.zoom = zoom + + def get_data_size(self): + return 4 + + def get_data(self): + return struct.pack(' 0) + if isinstance(sprites[0], RealSprite): + assert(all(isinstance(s, RealSprite) for s in sprites)) + assert(len(set(s.zoom for s in sprites)) == len(sprites)) + for s in sprites: + s.sprite_id = self._next_sprite_id + self._next_sprite_id += 1 + + for s in sprites: + self.sprites.append(s) + + self.pseudo_sprites.append(sprites[0]) + else: + assert(len(sprites) == 1) + self.pseudo_sprites.append(sprites[0]) + + def _write_pseudo_sprite(self, f, data, grf_type=0xff): + f.write(struct.pack(' recoloursprites() (257 each) + self._write_pseudo_sprite(f, b'\x02\x00\x00\x00') + + for s in self.pseudo_sprites: + self._write_pseudo_sprite(f, s.get_data(), grf_type=0xfd if isinstance(s, RealSprite) else 0xff) + f.write(b'\x00\x00\x00\x00') + for s in self.sprites: + f.write(s.get_real_data()) + + f.write(b'\x00\x00\x00\x00') \ No newline at end of file diff --git a/grf/alpine/lang/english.lng b/grf/alpine/lang/english.lng new file mode 100644 index 0000000000..e19e7c3c22 --- /dev/null +++ b/grf/alpine/lang/english.lng @@ -0,0 +1,8 @@ +##grflangid 0x01 +STR_GRF_NAME :CityMania Alpine Landscape +STR_GRF_DESCRIPTION :Modified OpenGFX spritess for alpine climate +STR_TEST_OBJECT : CM Test object +STR_FLMA : Flower Meadow +STR_TREE : Tree +STR_CREEK : Creek +STR_MINEFIELD : Minefield \ No newline at end of file diff --git a/grf/alpine/readgrftest.py b/grf/alpine/readgrftest.py new file mode 100644 index 0000000000..87ad1e513c --- /dev/null +++ b/grf/alpine/readgrftest.py @@ -0,0 +1,560 @@ +import sys +import struct +from nml import lz77 + + +def hex_str(s): + if isinstance(s, (bytes, memoryview)): + return ':'.join('{:02x}'.format(b) for b in s) + return ':'.join('{:02x}'.format(ord(c)) for c in s) + + +def read_extended_byte(data, offset): + res = data[offset] + if res != 0xff: + return res, offset + 1 + return data[offset + 1] | (data[offset + 2] << 8), offset + 3 + + +def read_dword(data, offset): + return data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24), offset + 4 + + +FEATURES = { + 0: 'Train', + 1: 'RV', + 2: 'Ship', + 3: 'Aircraft', + 4: 'Station', + 5: 'Canal', + 6: 'Bridge', + 7: 'House', + 8: 'Setting', + 9: 'IndTiles', + 0xa: 'Industry', + 0xb: 'Cargo', + 0xc: 'Sound', + 0xd: 'Airport', + 0xe: '?Signals?', + 0xf: 'Object', + 0x10: 'Railtype', + 0x11: 'AirportTiles', + 0x12: 'Roadtype', + 0x13: 'Tramtype', +} + +ACTION0_TRAIN_PROPS = { + 0x05: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Track type (see below) should be same as front + 0x08: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 AI special flag: set to 1 if engine is 'optimized' for passenger service (AI won't use it for other cargo), 0 otherwise no + 0x09: 'W', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Speed in mph*1.6 (see below) no + 0x0B: 'W', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Power (0 for wagons) should be zero + 0x0D: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Running cost factor (0 for wagons) should be zero + 0x0E: 'D', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Running cost base, see below should be zero + 0x12: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Sprite ID (FD for new graphics) yes + 0x13: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Dual-headed flag; 1 if dual-headed engine, 0 otherwise should be zero also for front + 0x14: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Cargo capacity yes + 0x15: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Cargo type, see CargoTypes + 0x16: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Weight in tons should be zero + 0x17: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 Cost factor should be zero + 0x18: 'B', # Supported by OpenTTD <0.7<0.7 Supported by TTDPatch 2.02.0[1] Engine rank for the AI (AI selects the highest-rank engine of those it can buy) no + 0x19: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 GRFv≥1 Engine traction type (see below) no + 0x1A: 'B*', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 GRFv≥1 Not a property, but an action: sort the purchase list. no + 0x1B: 'W', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.52.5 GRFv≥6 Power added by each wagon connected to this engine, see below should be zero + 0x1C: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.52.5 GRFv≥6 Refit cost, using 50% of the purchase price cost base yes + 0x1D: 'D', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.52.5 GRFv≥6 Bit mask of cargo types available for refitting, see column 2 (bit value) in CargoTypes yes + 0x1E: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.52.5 GRFv≥6 Callback flags bit mask, see below yes + 0x1F: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.5 (alpha 19)2.5 Coefficient of tractive effort should be zero + 0x20: 'B', # Supported by OpenTTD 1.11.1 Supported by TTDPatch 2.5 (alpha 27)2.5 Coefficient of air drag should be zero + 0x21: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.02.0 GRFv≥2 Make vehicle shorter by this amount, see below yes + 0x22: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.52.5 GRFv≥6 Set visual effect type (steam/smoke/sparks) as well as position, see below yes + 0x23: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.52.5 GRFv≥6 Set how much weight is added by making wagons powered (i.e. weight of engine), see below should be zero + 0x24: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.5 (alpha 44)2.5 High byte of vehicle weight, weight will be prop.24*256+prop.16 should be zero + 0x25: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.5 (alpha 44)2.5 User-defined bit mask to set when checking veh. var. 42 yes + 0x26: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.5 (alpha 44)2.5 Retire vehicle early, this many years before the end of phase 2 (see Action0General) no + 0x27: 'B', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.5 (alpha 58)2.5 Miscellaneous flags partly + 0x28: 'W', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.5 (alpha 58)2.5 Refittable cargo classes yes + 0x29: 'W', # Supported by OpenTTD 0.60.6 Supported by TTDPatch 2.5 (alpha 58)2.5 Non-refittable cargo classes yes + 0x2A: 'D', # Supported by OpenTTD 0.6 (r7191)0.6 Supported by TTDPatch 2.5 (r1210)2.5 Long format introduction date no + 0x2B: 'W', # Supported by OpenTTD 1.2 (r22713)1.2 Not supported by TTDPatch Custom cargo ageing period yes + 0x2C: 'n*B', # Supported by OpenTTD 1.2 (r23291)1.2 Not supported by TTDPatch List of always refittable cargo types yes + 0x2D: 'n*B', # Supported by OpenTTD 1.2 (r23291)1.2 Not supported by TTDPatch List of never refittable cargo types yes + 0x2E: 'W', # Supported by OpenTTD 12 (g2183fd4dab)12 Not supported by TTDPatch Maximum curve speed modifier yes +} + +ACTION0_OBJECT_PROPS = { + 0x08: ('label', 'L'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Class label, see below + 0x09: ('class_name_id', 'W'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Text ID for class + 0x0A: ('name_id', 'W'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Text ID for this object + 0x0B: ('climate', 'B'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Climate availability + 0x0C: ('size', 'B'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Byte representing size, see below + 0x0D: ('build_cost_factor', 'B'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Object build cost factor (sets object removal cost factor as well) + 0x0E: ('intro_date', 'D'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Introduction date, see below + 0x0F: ('eol_date', 'D'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 End of life date, see below + 0x10: ('flags', 'W'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Object flags, see below + 0x11: ('anim_info', 'W'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Animation information + 0x12: ('anim_speed', 'B'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Animation speed + 0x13: ('anim_trigger', 'W'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Animation triggers + 0x14: ('removal_cost_factor', 'B'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Object removal cost factor (set after object build cost factor) + 0x15: ('cb_flags', 'W'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Callback flags, see below + 0x16: ('building_height', 'B'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Height of the building + 0x17: ('num_views', 'B'), # Supported by OpenTTD 1.1 (r20670)1.1 Supported by TTDPatch 2.6 (r2340)2.6 Number of object views + 0x18: ('num_objects', 'B'), # Supported by OpenTTD 1.4 (r25879)1.4 Not supported by TTDPatch Measure for number of objects placed upon map creation +} + +ACTION0_PROPS = { + 0: ACTION0_TRAIN_PROPS, + 0xf: ACTION0_OBJECT_PROPS, +} + + +def str_feature(feature): + return f'{FEATURES[feature]}<{feature:02x}>' + + +def str_sprite(sprite): + sprite_id = sprite & 0x1fff + draw = {0: 'N', 1 : 'T', 2: 'R'}[(sprite >> 14) & 3] + color_translation = (sprite >> 16) & 0x3fff + normal_in_transparent = bool(sprite & (1 << 30)) + sprite_type = sprite >> 31 + ntstr = ['', ' NF'][normal_in_transparent] + return f'[{sprite_id} {draw}{ntstr} {color_translation}-{sprite_type}]' + + +def read_property(data, ofs, fmt): + if fmt == 'B': + return data[ofs], ofs + 1 + + if fmt == 'W': + return data[ofs] | (data[ofs + 1] << 8), ofs + 2 + + if fmt == 'L': + return data[ofs: ofs + 4], ofs + 4 + + if fmt == 'D': + return read_dword(data, ofs) + + if fmt == 'B*': + return read_extended_byte(data, ofs) + + if fmt == 'n*B': + n = data[ofs] + return data[ofs + 1: ofs + 1 + n], ofs + 1 + n + + assert False, fmt + + +def decode_action0(data): + num = data[0] + feature = data[0] + num_props = data[1] + num_info = data[2] + first_id, ofs = read_extended_byte(data, 3) + props = {} + for _ in range(num_props): + prop = data[ofs] + propdict = ACTION0_PROPS[feature] + name, fmt = propdict[prop] + value, ofs = read_property(data, ofs + 1, fmt) + key = f'{name}<{prop:02x}>' + assert key not in props, key + props[key] = value + + print(f' <0>FEATURE feature:{str_feature(feature)} num_info:{num_info} first_id:{first_id} props:{props}') + + +def decode_action1(data): + num = data[0] + feature = data[0] + num_sets = data[1] + num_ent, _ = read_extended_byte(data, 2) + print(f' <1>SPRITESET feature:{str_feature(feature)} num_sets:{num_sets} num_ent:{num_ent}') + + +SPRITE_GROUP_OP = [ + 'ADD', # a + b + 'SUB', # a - b + 'SMIN', # (signed) min(a, b) + 'SMAX', # (signed) max(a, b) + 'UMIN', # (unsigned) min(a, b) + 'UMAX', # (unsigned) max(a, b) + 'SDIV', # (signed) a / b + 'SMOD', # (signed) a % b + 'UDIV', # (unsigned) a / b + 'UMOD', # (unsigned) a & b + 'MUL', # a * b + 'AND', # a & b + 'OR', # a | b + 'XOR', # a ^ b + 'STO', # store a into temporary storage, indexed by b. return a + 'RST', # return b + 'STOP', # store a into persistent storage, indexed by b, return a + 'ROR', # rotate a b positions to the right + 'SCMP', # (signed) comparison (a < b -> 0, a == b = 1, a > b = 2) + 'UCMP', # (unsigned) comparison (a < b -> 0, a == b = 1, a > b = 2) + 'SHL', # a << b + 'SHR', # (unsigned) a >> b + 'SAR', # (signed) a >> b +] + +class DataReader: + def __init__(self, data, offset=0): + self.data = data + self.offset = offset + + def get_byte(self): + self.offset += 1 + return self.data[self.offset - 1] + + def get_extended_byte(self): + res, self.offset = read_extended_byte(self.data, self.offset) + return res + + def get_word(self): + return self.get_byte() | (self.get_byte() << 8) + + def get_var(self, n): + size = 1 << n + res = struct.unpack_from({0: '> 6) & 1) + num &= 0x3f + + def read_sprite(): + sprite = d.get_word() + pal = d.get_word() + flags = d.get_word() if has_flags else TLF_NOTHING + return {'sprite': sprite, 'pal': pal, 'flags': flags} + + ground = read_sprite() + ground_regs = read_sprite_layout_registers(d, ground['flags'], False) + sprites = [] + for _ in range(num): + seq = {} + seq['sprite'] = read_sprite() + delta = seq['delta'] = (d.get_byte(), d.get_byte(), d.get_byte() if has_z_position else 0) + is_parent = (delta[2] != 0x80) + if is_parent: + seq['size'] = (d.get_byte(), d.get_byte(), d.get_byte()) + seq['regs'] = read_sprite_layout_registers(d, seq['sprite']['flags'], is_parent) + sprites.append(seq) + + return { + 'ground': { + 'sprite': ground, + 'regs': ground_regs, + }, + 'sprites': sprites + } + +def decode_action2(data): + feature = data[0] + set_id = data[1] + num_ent1 = data[2] + d = DataReader(data, 3) + + print(f' <2>SPRITEGROUP feature:{str_feature(feature)} set_id:{set_id} ', end='') + + if feature in (0x07, 0x09, 0x0f, 0x11): + if num_ent1 == 0: + ground_sprite, building_sprite, xofs, yofs, xext, yext, zext = struct.unpack_from('> 2) & 3 + first = True + ofs = 3 + adjusts = [] + while True: + res = {} + res['op'] = 0 if first else d.get_byte() + var = res['var'] = d.get_byte() + if var == 0x7e: + res['subroutine'] = d.get_byte() + else: + res['parameter'] = d.get_byte() if 0x60 <= var < 0x80 else 0 + varadj = d.get_byte() + res['shift_num'] = varadj & 0x1f + has_more = bool(varadj & 0x20) + res['type'] = varadj >> 6 + res['and_mask'] = d.get_var(group_size) + if res['type'] != 0: + res['add_val'] = d.get_var(group_size) + res['divmod_val'] = d.get_var(group_size) + adjusts.append(res) + + if not has_more: + break + + n_ranges = d.get_byte() + ranges = [] + for _ in range(n_ranges): + group = d.get_word() + low = d.get_var(group_size) + high = d.get_var(group_size) + ranges.append((group, low, high)) + + default_group = d.get_word() + + print(f'default_group: {default_group} adjusts:{adjusts} ranges:{ranges} ') + + return + + layout = read_sprite_layout(d, max(num_ent1, 1), num_ent1 == 0) + print(f'layout:{layout}') + return + # num_loaded = num_ent1 + # num_loading = get_byte() + # [get_word() for i in range(num_loaded)] + # [get_word() for i in range(num_loading)] + # assert False, num_ent1 + # # assert num_ent1 < 0x3f + 0x40, num_ent1 + # return + + num_ent2 = data[3] + ent1 = struct.unpack_from('<' + 'H' * num_ent1, data, offset=4) + ent2 = struct.unpack_from('<' + 'H' * num_ent2, data, offset=4 + 2 * num_ent1) + print(f'ent1:{ent1} ent2:{ent2}') + + +def decode_action4(data): + fmt = 'STRINGS feature:{str_feature(feature)} lang:{lang} num:{num} offset:{offset} strings:{strings}') + + +def decode_action5(data): + t = data[0] + offset = 0 + num, dataofs = read_extended_byte(data, 1) + if t & 0xf0: + offset, _ = read_extended_byte(data, dataofs) + t &= ~0xf0 + print(f' <5>REPLACENEW type:{t} num:{num}, offset:{offset}') + + +def decode_action6(data): + d = DataReader(data, 0) + params = [] + while True: + param_num = d.get_byte() + if param_num == 0xFF: + break + param_size = d.get_byte() + offset = d.get_extended_byte() + params.append({'num': param_num, 'size': param_size, 'offset': offset}) + print(f' <6>EDITPARAM params:{params}') + + +def decode_actionA(data): + num = data[0] + sets = [struct.unpack_from('REPLACEBASE sets:<{num}>{sets}') + + +OPERATIONS = { + 0x00: '{target} = {source1}', # Supported by OpenTTD Supported by TTDPatch Assignment target = source1 + 0x01: '{target} = {source1} + {source2}', # Supported by OpenTTD Supported by TTDPatch Addition target = source1 + source2 + 0x02: '{target} = {source1} - {source2}', # Supported by OpenTTD Supported by TTDPatch Subtraction target = source1 - source2 + 0x03: '{target} = {source1} * {source2} (Unsigned)', # Supported by OpenTTD Supported by TTDPatch Unsigned multiplication target = source1 * source2, with both sources being considered to be unsigned + 0x04: '{target} = {source1} * {source2} (Signed)', # Supported by OpenTTD Supported by TTDPatch Signed multiplication target = source1 * source2, with both sources considered signed + 0x05: '{target} = {source1} <> {source2} (Unsigned)', # Supported by OpenTTD Supported by TTDPatch Unsigned bit shift target = source1 << source2 if source2>0, or target = source1 >> abs(source2) if source2 < 0. source1 is considered to be unsigned + 0x06: '{target} = {source1} <> {source2} (Signed)', # Supported by OpenTTD Supported by TTDPatch Signed bit shift same as 05, but source1 is considered signed) + 0x07: '{target} = {source1} & {source2}', # Supported by OpenTTD Supported by TTDPatch 2.5 (alpha 48)2.5 Bitwise AND target = source1 AND source2 + 0x08: '{target} = {source1} | {source2}', # Suported by OpenTTD Supported by TTDPatch 2.5 (alpha 48)2.5 Bitwise OR target = source1 OR source2 + 0x09: '{target} = {source1} / {source2} (Unsigned)', # Supported by OpenTTD Supported by TTDPatch 2.5 (alpha 59)2.5 Unsigned division target = source1 / source2 + 0x0A: '{target} = {source1} / {source2} (Signed)', # Supported by OpenTTD Supported by TTDPatch 2.5 (alpha 59)2.5 Signed division target = source1 / source2 + 0x0B: '{target} = {source1} % {source2} (Unsigned)', # Supported by OpenTTD Supported by TTDPatch 2.5 (alpha 59)2.5 Unsigned modulo target = source1 % source2 + 0x0C: '{target} = {source1} % {source2} (Signed)', # Supported by OpenTTD Supported by TTDPatch 2.5 (alpha 59)2.5 Signed modulo target = source1 % source2 +} + + +def decode_actionD(data): + target = data[0] + operation = data[1] + source1 = data[2] + source2 = data[3] + if source1 == 0xff or source2 == 0xff: + value, _ = read_dword(data, 4) + fmt = OPERATIONS[operation] + sf = lambda x: f'[{x:02x}]' if x != 0xff else str(value) + target_str = f'[{target:02x}]' + op_str = fmt.format(target=target_str, source1=sf(source1), source2=sf(source2)) + print(f' OP {op_str}') + + +def decode_action14(data): + res = {} + ofs = 0 + + def decode_chunk(res): + nonlocal ofs + chunk_type = data[ofs] + ofs += 1 + if chunk_type == 0: return False + chunk_id = data[ofs: ofs + 4] + ofs += 4 + if chunk_type == b'C'[0]: + res[chunk_id] = {} + while decode_chunk(res[chunk_id]): + pass + elif chunk_type == b'B'[0]: + l = data[ofs] | (data[ofs + 1] << 8) + res[chunk_id] = data[ofs + 2: ofs + 2 + l] + ofs += 2 + l + # elif chunk_type == b'T'[0]: + else: + assert False, chunk_type + return True + + while decode_chunk(res): + pass + + print(f' <14>INFO {res}') + + +ACTIONS = { + 0x00: decode_action0, + 0x01: decode_action1, + 0x02: decode_action2, + 0x04: decode_action4, + 0x05: decode_action5, + 0x06: decode_action6, + 0x0a: decode_actionA, + 0x0d: decode_actionD, + 0x14: decode_action14, +} + +def read_pseudo_sprite(f): + l = struct.unpack(' 0: + code = f.read(1)[0] + if code >= 128: code -= 256 + # print(f'Code {code} num {num}') + if code >= 0: + size = 0x80 if code == 0 else code + num -= size + if num < 0: raise RuntimeError('Corrupt sprite') + data += f.read(size) + else: + data_offset = ((code & 7) << 8) | f.read(1)[0] + #if (dest - data_offset < dest_orig.get()) return WarnCorruptSprite(file, file_pos, __LINE__); + size = -(code >> 3) + num -= size + if num < 0: raise RuntimeError('Corrupt sprite') + data += data[-data_offset:size - data_offset] + if num != 0: raise RuntimeError('Corrupt sprite') + return data + +def read_real_sprite(f): + sprite_id = struct.unpack('