diff --git .editorconfig .editorconfig
index f3a6b01da..3bfe70220 100644
--- .editorconfig
+++ .editorconfig
@@ -22,3 +22,7 @@ indent_size = 2
[Makefile,*.mk]
indent_style = space
indent_size = 2
+
+[{*.vcxitems,*.vcxproj}]
+insert_final_newline = false
+indent_style = space
diff --git Makefile Makefile
index 4ded87ec7..b97245d3d 100644
--- Makefile
+++ Makefile
@@ -257,6 +257,7 @@ SOURCES += bauer/fabrikbauer.cc
SOURCES += bauer/goods_manager.cc
SOURCES += bauer/hausbauer.cc
SOURCES += bauer/tunnelbauer.cc
+SOURCES += bauer/tree_builder.cc
SOURCES += bauer/vehikelbauer.cc
SOURCES += bauer/wegbauer.cc
SOURCES += boden/boden.cc
diff --git Simutrans-Main.vcxitems Simutrans-Main.vcxitems
index 140bb9e05..3fd2fd5a3 100644
--- Simutrans-Main.vcxitems
+++ Simutrans-Main.vcxitems
@@ -47,6 +47,7 @@
+
@@ -392,6 +393,7 @@
+
diff --git bauer/tree_builder.cc bauer/tree_builder.cc
new file mode 100644
index 000000000..2944136c2
--- /dev/null
+++ bauer/tree_builder.cc
@@ -0,0 +1,345 @@
+/*
+ * This file is part of the Simutrans project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+#include "tree_builder.h"
+
+#include "../dataobj/settings.h"
+#include "../obj/baum.h"
+#include "../obj/groundobj.h"
+#include "../simworld.h"
+#include "../utils/simrandom.h"
+
+#include
+
+
+static karte_ptr_t welt;
+
+
+static const uint8 tree_age_index[(baum_t::AGE_LIMIT >> 6) + 1] =
+{
+ 0,1,2,3,3,3,3,3,3,4,4,4
+};
+
+
+vector_tpl tree_builder_t::tree_list(0);
+weighted_vector_tpl tree_builder_t::tree_list_per_climate[MAX_CLIMATES];
+stringhashtable_tpl tree_builder_t::desc_table;
+
+
+/// Quick lookup of an image, assuring always five seasons and five ages.
+/// Missing images just have identical entries.
+/// Seasons are: 0=summer, 1=autumn, 2=winter, 3=spring, 4=snow
+/// Snow image is used if tree is above snow line, or for arctic climate
+static image_id tree_id_to_image[256][5*5];
+
+
+image_id tree_builder_t::get_tree_image(uint8 tree_id, uint32 age, uint8 season)
+{
+ const uint8 tree_age_idx = tree_age_index[min(age>>6, 11u)];
+ assert(tree_age_idx < 5);
+ return tree_id_to_image[ tree_id ][ season*5 + tree_age_idx ];
+}
+
+
+const tree_desc_t *tree_builder_t::find_tree(const char *tree_name)
+{
+ return tree_list.empty() ? NULL : desc_table.get(tree_name);
+}
+
+
+uint8 tree_builder_t::plant_tree_on_coordinate(koord pos, const uint8 maximum_count, const uint8 count)
+{
+ grund_t *gr = welt->lookup_kartenboden(pos);
+ if( gr ) {
+ if( has_trees_for_climate( welt->get_climate(pos) ) && gr->ist_natur() && gr->get_top() < maximum_count ) {
+ obj_t *obj = gr->obj_bei(0);
+ if(obj) {
+ switch(obj->get_typ()) {
+ case obj_t::wolke:
+ case obj_t::air_vehicle:
+ case obj_t::baum:
+ case obj_t::leitung:
+ case obj_t::label:
+ case obj_t::zeiger:
+ // ok to build here
+ break;
+ case obj_t::groundobj:
+ if(((groundobj_t *)obj)->get_desc()->can_build_trees_here()) {
+ break;
+ }
+ /* FALLTHROUGH */
+ // leave these (and all other empty)
+ default:
+ return 0;
+ }
+ }
+
+ const uint8 count_planted = min( maximum_count - gr->get_top(), count);
+ for (uint8 i=0; iobj_add( new baum_t(gr->get_pos()) ); //plants the tree(s)
+ }
+
+ return count_planted;
+ }
+ }
+
+ return 0;
+}
+
+
+bool tree_builder_t::plant_tree_on_coordinate(koord pos, const tree_desc_t *desc, const bool check_climate, const bool random_age)
+{
+ // none there
+ if( desc_table.empty() ) {
+ return false;
+ }
+
+ grund_t *gr = welt->lookup_kartenboden(pos);
+ if( gr ) {
+ if( gr->ist_natur() && gr->get_top() < welt->get_settings().get_max_no_of_trees_on_square() && (!check_climate || desc->is_allowed_climate( welt->get_climate(pos) )) ) {
+ if( gr->get_top() > 0 ) {
+ switch(gr->obj_bei(0)->get_typ()) {
+ case obj_t::wolke:
+ case obj_t::air_vehicle:
+ case obj_t::baum:
+ case obj_t::leitung:
+ case obj_t::label:
+ case obj_t::zeiger:
+ // ok to built here
+ break;
+ case obj_t::groundobj:
+ if(((groundobj_t *)(gr->obj_bei(0)))->get_desc()->can_build_trees_here()) {
+ break;
+ }
+ /* FALLTHROUGH */
+ // leave these (and all other empty)
+ default:
+ return false;
+ }
+ }
+
+ baum_t *b = new baum_t(gr->get_pos(), desc); //plants the tree
+ if( random_age ) {
+ b->geburt = welt->get_current_month() - simrand(baum_t::AGE_LIMIT-1);
+ b->calc_off( welt->lookup( b->get_pos() )->get_grund_hang() );
+ }
+
+ gr->obj_add( b );
+ return true; //tree was planted - currently unused value is not checked
+ }
+ }
+
+ return false;
+}
+
+
+uint32 tree_builder_t::create_forest(koord new_center, koord wh, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom)
+{
+ // none there
+ if( desc_table.empty() ) {
+ return 0;
+ }
+
+ const sint16 xpos_f = new_center.x;
+ const sint16 ypos_f = new_center.y;
+ uint32 number_of_new_trees = 0;
+
+ for( sint16 j = 0; j < wh.x; j++) {
+ for( sint16 i = 0; i < wh.y; i++) {
+
+ const sint32 x_tree_pos = (j-(wh.x>>1));
+ const sint32 y_tree_pos = (i-(wh.y>>1));
+
+ if( xtop > (xpos_f + x_tree_pos) || (xpos_f + x_tree_pos) >= xbottom ) {
+ continue;
+ }
+ if( ytop > (ypos_f + y_tree_pos) || (ypos_f + y_tree_pos) >= ybottom ) {
+ continue;
+ }
+
+ const uint64 distance = 1 + sqrt_i64( ((uint64)x_tree_pos*x_tree_pos*(wh.y*wh.y) + (uint64)y_tree_pos*y_tree_pos*(wh.x*wh.x)));
+ const uint32 tree_probability = (uint32)( ( 8 * (uint32)((wh.x*wh.x)+(wh.y*wh.y)) ) / distance );
+
+ if (tree_probability < 38) {
+ continue;
+ }
+
+ uint8 number_to_plant = 0;
+ uint8 const max_trees_here = min(welt->get_settings().get_max_no_of_trees_on_square(), (tree_probability - 38 + 1) / 2);
+
+ for (uint8 c2 = 0 ; c2get_settings().get_max_no_of_trees_on_square();
+
+ number_of_new_trees += plant_tree_on_coordinate(tree_pos, max_trees_per_square, number_to_plant);
+ }
+ }
+
+ return number_of_new_trees;
+}
+
+
+void tree_builder_t::fill_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom )
+{
+ // none there
+ if( desc_table.empty() ) {
+ return;
+ }
+
+ DBG_MESSAGE("tree_builder_t::fill_trees", "distributing single trees");
+ koord pos;
+
+ for( pos.y=ytop; pos.ylookup_kartenboden(pos);
+ if(gr->get_top() == 0 && gr->get_typ() == grund_t::boden) {
+ // plant spare trees, (those with low preffered density) or in an entirely tree climate
+ const uint16 cl = 1 << welt->get_climate(pos);
+ const settings_t &s = welt->get_settings();
+
+ if ((cl & s.get_no_tree_climates()) == 0 && ((cl & s.get_tree_climates()) != 0 || simrand(s.get_forest_inverse_spare_tree_density() * dichte) < 100)) {
+ plant_tree_on_coordinate(pos, 1, 1);
+ }
+ }
+ }
+ }
+}
+
+
+static bool compare_tree_desc(const tree_desc_t *a, const tree_desc_t *b)
+{
+ // same level - we do an artificial but unique sorting by (untranslated) name
+ return strcmp(a->get_name(), b->get_name())<0;
+}
+
+
+bool tree_builder_t::successfully_loaded()
+{
+ if( desc_table.empty() ) {
+ DBG_MESSAGE("tree_builder_t::successfully_loaded", "No trees found - feature disabled");
+ }
+
+ FOR(stringhashtable_tpl, const& i, desc_table) {
+ tree_list.insert_ordered(i.value, compare_tree_desc);
+ if( tree_list.get_count()==255 ) {
+ dbg->error( "tree_builder_t::successfully_loaded", "Maximum tree count exceeded! (%u > 255)", desc_table.get_count() );
+ break;
+ }
+ }
+
+ tree_list.append( NULL );
+
+ // clear cache
+ memset( tree_id_to_image, -1, sizeof(tree_id_to_image) );
+
+ // now register all trees for all fitting climates
+ for( uint32 typ=0; typis_allowed_climate((climate)j) ) {
+ assert(typ <= 255);
+ tree_list_per_climate[j].append((uint8)typ, tree_list[typ]->get_distribution_weight());
+ }
+ }
+
+ // create cache images
+ for( uint8 season = 0; season < 5; season++ ) {
+ uint8 use_season = 0;
+ const sint16 seasons = tree_list[typ]->get_seasons();
+
+ if( seasons > 1 ) {
+ use_season = season;
+ // three possibilities
+ if( seasons < 4 ) {
+ // only summer and winter => season 4 with winter image
+ use_season = (season == 4);
+ }
+ else if( seasons == 4 ) {
+ // all there, but the snowy special image missing
+ if( season == 4 ) {
+ // take spring image (gave best results with pak64, pak.german) ////// but season 2 is winter????
+ use_season = 2;
+ }
+ }
+ }
+
+ for( uint8 age_idx = 0; age_idx < 5; age_idx++ ) {
+ tree_id_to_image[typ][season * 5 + age_idx] = tree_list[typ]->get_image_id( use_season, age_idx );
+ }
+ }
+ }
+
+ return true;
+}
+
+
+bool tree_builder_t::register_desc(const tree_desc_t *desc)
+{
+ // avoid duplicates with same name
+ if( desc_table.remove(desc->get_name()) ) {
+ dbg->doubled( "baum_t", desc->get_name() );
+ }
+
+ desc_table.put(desc->get_name(), desc );
+ return true;
+}
+
+
+void tree_builder_t::distribute_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom)
+{
+ // now we can proceed to tree planting routine itself
+ // best forests results are produced if forest size is tied to map size -
+ // but there is some nonlinearity to ensure good forests on small maps
+ settings_t const& s = welt->get_settings();
+ sint32 const x = welt->get_size().x;
+ sint32 const y = welt->get_size().y;
+ unsigned const t_forest_size = (unsigned)pow(((double)x * (double)y), 0.25) * s.get_forest_base_size() / 11 + (x + y) / (2 * s.get_forest_map_size_divisor());
+ uint8 const c_forest_count = (unsigned)pow(((double)x * (double)y), 0.5) / s.get_forest_count_divisor();
+
+ DBG_MESSAGE("tree_builder_t::distribute_trees", "Creating %i forests", c_forest_count);
+
+ for (uint8 c1 = 0 ; c1 < c_forest_count ; c1++) {
+ // to have same execution order for simrand
+ koord const start = koord::koord_random(x, y);
+ koord const size = koord(t_forest_size,t_forest_size) + koord::koord_random(t_forest_size, t_forest_size);
+
+ create_forest( start, size, xtop, ytop, xbottom, ybottom );
+ }
+
+ fill_trees( dichte, xtop, ytop, xbottom, ybottom );
+}
+
+
+const tree_desc_t *tree_builder_t::random_tree_for_climate(climate cl)
+{
+ const uint16 b = random_tree_id_for_climate(cl);
+ return b!=0xFFFF ? tree_list[b] : NULL;
+}
+
+
+uint16 tree_builder_t::random_tree_id_for_climate(climate cl)
+{
+ // now weight their distribution
+ weighted_vector_tpl const &t = tree_list_per_climate[cl];
+ return t.empty() ? 0xFFFF : pick_any_weighted(t);
+}
+
+
+bool tree_builder_t::spawn_tree_near(const baum_t *tree, int radius)
+{
+ // to have same execution order for simrand
+ const sint16 sx = simrand(2*radius + 1)-radius;
+ const sint16 sy = simrand(2*radius + 1)-radius;
+ const koord k = tree->get_pos().get_2d() + koord(sx,sy);
+
+ return plant_tree_on_coordinate(k, tree->get_desc(), true, false);
+}
+
diff --git bauer/tree_builder.h bauer/tree_builder.h
new file mode 100644
index 000000000..2ef39943f
--- /dev/null
+++ bauer/tree_builder.h
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the Simutrans project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+#ifndef BAUER_TREE_BUILDER_H
+#define BAUER_TREE_BUILDER_H
+
+
+#include "../tpl/stringhashtable_tpl.h"
+#include "../tpl/weighted_vector_tpl.h"
+#include "../tpl/vector_tpl.h"
+
+#include "../dataobj/koord.h"
+#include "../display/simimg.h"
+
+
+class tree_desc_t;
+class baum_t;
+
+
+/// Handles desc management and distribution of trees.
+class tree_builder_t
+{
+private:
+ static stringhashtable_tpl desc_table; ///< Mapping desc_name -> desc
+ static vector_tpl tree_list; ///< Mapping tree_id -> desc
+ static weighted_vector_tpl tree_list_per_climate[MAX_CLIMATES]; ///< index vector into tree_list, accessible per climate
+
+public:
+ static const tree_desc_t *get_desc_by_name(const char * tree_name) { return desc_table.get(tree_name); }
+ static const tree_desc_t *get_desc_by_id(uint8 tree_id) { return tree_id < get_num_trees() ? tree_list[tree_id] : NULL; }
+ static uint8 get_id_by_desc(const tree_desc_t *desc) { return tree_list.index_of(desc); }
+
+ static image_id get_tree_image(uint8 idx, uint32 age, uint8 season);
+
+ static bool has_trees() { return get_num_trees() > 0; }
+ static bool has_trees_for_climate(climate cl) { return !tree_list_per_climate[cl].empty(); }
+
+ static sint32 get_num_trees() { return tree_list.get_count()-1; }
+
+ /// Fill rectangular region with trees.
+ static void fill_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom);
+
+ static bool register_desc(const tree_desc_t *desc);
+ static bool successfully_loaded();
+
+ /// @returns list of all registered descriptors
+ static const vector_tpl &get_all_desc() { return tree_list; }
+
+ /// Plant a new tree in a (2n+1) * (2n+1) square around @p tree.
+ static bool spawn_tree_near(const baum_t *tree, int radius = 3);
+
+ static uint32 create_forest(koord center, koord size, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom);
+
+public:
+ /// distributes trees in a rectangular region of the map
+ static void distribute_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom);
+
+ /// tree planting function - it takes care of checking suitability of area
+ static bool plant_tree_on_coordinate(koord pos, const tree_desc_t *desc, const bool check_climate, const bool random_age);
+
+ /// tree planting function - it takes care of checking suitability of area
+ static uint8 plant_tree_on_coordinate(koord pos, const uint8 maximum_count, const uint8 count);
+
+ static const tree_desc_t *find_tree( const char *tree_name );
+
+ static const tree_desc_t *random_tree_for_climate(climate cl);
+
+ /// also checks for distribution values
+ /// @returns the tree_i, or 0xFFFF if no trees exist for the requested climate.
+ static uint16 random_tree_id_for_climate(climate cl);
+};
+
+
+#endif
diff --git boden/boden.cc boden/boden.cc
index 820f61551..265aafbb1 100644
--- boden/boden.cc
+++ boden/boden.cc
@@ -29,7 +29,7 @@ boden_t::boden_t(loadsave_t *file, koord pos ) : grund_t( koord3d(pos,0) )
sint32 age;
file->rdwr_long( age );
// check, if we still have this tree ... (if there are not trees, the first index is NULL!)
- if (id < baum_t::get_count() && baum_t::get_all_desc()[id]) {
+ if (tree_builder_t::get_desc_by_id(id) != NULL) {
baum_t *tree = new baum_t( get_pos(), (uint8)id, age, slope );
objlist.add( tree );
}
diff --git boden/grund.h boden/grund.h
index d3e25b8d4..8f170d8c1 100644
--- boden/grund.h
+++ boden/grund.h
@@ -275,7 +275,14 @@ public:
* Updates snowline dependent grund_t (and derivatives) - none are season dependent
* Updates season and or snowline dependent objects
*/
- void check_season_snowline(const bool season_change, const bool snowline_change) { if( snowline_change ) { calc_image_internal( snowline_change ); } objlist.check_season( season_change && !snowline_change ); }
+ void check_season_snowline(const bool season_change, const bool snowline_change)
+ {
+ if( snowline_change ) {
+ calc_image_internal( snowline_change );
+ }
+
+ objlist.check_season( season_change && !snowline_change );
+ }
/**
* Updates images after change of underground mode.
diff --git dataobj/objlist.cc dataobj/objlist.cc
index 9835ec31b..5aaae69dc 100644
--- dataobj/objlist.cc
+++ dataobj/objlist.cc
@@ -952,7 +952,7 @@ void objlist_t::rdwr(loadsave_t *file, koord3d current_pos)
baum_t *b = new baum_t(file);
if( !b->get_desc() ) {
// is there a replacement possible
- if( const tree_desc_t *desc = baum_t::random_tree_for_climate( world()->get_climate_at_height(current_pos.z) ) ) {
+ if( const tree_desc_t *desc = tree_builder_t::random_tree_for_climate( world()->get_climate_at_height(current_pos.z) ) ) {
b->set_desc( desc );
}
else {
diff --git descriptor/reader/tree_reader.cc descriptor/reader/tree_reader.cc
index e945cb215..2e7eea3c0 100644
--- descriptor/reader/tree_reader.cc
+++ descriptor/reader/tree_reader.cc
@@ -19,7 +19,7 @@ void tree_reader_t::register_obj(obj_desc_t *&data)
{
tree_desc_t *desc = static_cast(data);
- baum_t::register_desc(desc);
+ tree_builder_t::register_desc(desc);
checksum_t *chk = new checksum_t();
desc->calc_checksum(chk);
pakset_info_t::append(desc->get_name(), get_type(), chk);
@@ -28,7 +28,7 @@ void tree_reader_t::register_obj(obj_desc_t *&data)
bool tree_reader_t::successfully_loaded() const
{
- return baum_t::successfully_loaded();
+ return tree_builder_t::successfully_loaded();
}
diff --git gui/baum_edit.cc gui/baum_edit.cc
index b08f262b9..5c843fd01 100644
--- gui/baum_edit.cc
+++ gui/baum_edit.cc
@@ -81,7 +81,7 @@ void baum_edit_frame_t::fill_list()
{
tree_list.clear();
const bool is_sortedbyname = get_sortedby()==gui_sorting_item_t::BY_NAME_TRANSLATED;
- FOR(vector_tpl, const i, baum_t::get_all_desc()) {
+ FOR(vector_tpl, const i, tree_builder_t::get_all_desc()) {
if ( i && (i->get_allowed_climate_bits() & get_climate()) ) {
tree_list.insert_ordered(i, is_sortedbyname ? compare_tree_desc_name : compare_tree_desc);
}
diff --git obj/baum.cc obj/baum.cc
index f33f1af86..7a7533150 100644
--- obj/baum.cc
+++ obj/baum.cc
@@ -3,369 +3,158 @@
* (see LICENSE.txt)
*/
-#include
-#include
-#include
+#include "baum.h"
-#include "../simdebug.h"
-#include "../simworld.h"
-#include "simobj.h"
-#include "../display/simimg.h"
-#include "../player/simplay.h"
-#include "../simtypes.h"
+#include "groundobj.h"
#include "../boden/grund.h"
-
+#include "../dataobj/environment.h"
+#include "../dataobj/freelist.h"
+#include "../dataobj/loadsave.h"
+#include "../dataobj/translator.h"
#include "../descriptor/tree_desc.h"
-
-#include "groundobj.h"
-
+#include "../display/simimg.h"
+#include "../player/simplay.h"
+#include "../simdebug.h"
+#include "../simtypes.h"
+#include "../simworld.h"
#include "../utils/cbuffer_t.h"
#include "../utils/simrandom.h"
-#include "../dataobj/loadsave.h"
-#include "../dataobj/translator.h"
-#include "../dataobj/environment.h"
-#include "../dataobj/freelist.h"
-
-
-#include "baum.h"
+#include
+#include
+#include
-static const uint8 tree_age_index[12] =
-{
- 0,1,2,3,3,3,3,3,3,4,4,4
-};
FLAGGED_PIXVAL baum_t::outline_color = 0;
-// quick lookup of an image, assuring always five seasons and five ages
-// missing images just have identical entries
-// seasons are: 0=summer, 1=autumn, 2=winter, 3=spring, 4=snow
-// snow image is used if tree is above snow line, or for arctic climate
-static image_id tree_id_to_image[256][5*5];
-
-// distributes trees on a map
-void baum_t::distribute_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom )
+baum_t::baum_t(loadsave_t *file) :
+ obj_t(),
+ geburt(welt->get_current_month()),
+ tree_id(0),
+ season(0)
{
- // now we can proceed to tree planting routine itself
- // best forests results are produced if forest size is tied to map size -
- // but there is some nonlinearity to ensure good forests on small maps
- settings_t const& s = welt->get_settings();
- sint32 const x = welt->get_size().x;
- sint32 const y = welt->get_size().y;
- unsigned const t_forest_size = (unsigned)pow(((double)x * (double)y), 0.25) * s.get_forest_base_size() / 11 + (x + y) / (2 * s.get_forest_map_size_divisor());
- uint8 const c_forest_count = (unsigned)pow(((double)x * (double)y), 0.5) / s.get_forest_count_divisor();
-
-DBG_MESSAGE("verteile_baeume()","creating %i forest",c_forest_count);
- for (uint8 c1 = 0 ; c1 < c_forest_count ; c1++) {
- // to have same execution order for simrand
- koord const start = koord::koord_random(x, y);
- koord const size = koord(t_forest_size,t_forest_size) + koord::koord_random(t_forest_size, t_forest_size);
- create_forest( start, size, xtop, ytop, xbottom, ybottom );
- }
-
- fill_trees( dichte, xtop, ytop, xbottom, ybottom );
+ rdwr(file);
}
-/*************************** first the static function for the baum_t and tree_desc_t administration ***************/
-
-/*
- * Diese Tabelle ermoeglicht das Auffinden dient zur Auswahl eines Baumtypen
- */
-vector_tpl baum_t::tree_list(0);
-
-// index vector into tree_idn, accessible per climate
-weighted_vector_tpl* baum_t::tree_list_per_climate = NULL;
-
-/*
- * Diese Tabelle ermoeglicht das Auffinden einer Description durch ihren Namen
- */
-stringhashtable_tpl baum_t::desc_table;
-
-
-// total number of trees
-// the same for a certain climate
-int baum_t::get_count(climate cl)
+baum_t::baum_t(koord3d pos) :
+ obj_t(pos),
+ geburt(welt->get_current_month() - simrand(baum_t::AGE_LIMIT-1)), // generate aged trees, might underflow
+ season(0)
{
- return tree_list_per_climate[cl].get_count();
+ tree_id = (uint8)tree_builder_t::random_tree_id_for_climate( welt->get_climate( pos.get_2d() ) );
+
+ calc_off( welt->lookup( get_pos())->get_grund_hang() );
+ calc_image();
}
-/**
- * tree planting function - it takes care of checking suitability of area
- */
-uint8 baum_t::plant_tree_on_coordinate(koord pos, const uint8 maximum_count, const uint8 count)
+baum_t::baum_t(koord3d pos, uint8 type, sint32 age, uint8 slope ) :
+ obj_t(pos),
+ geburt(welt->get_current_month() - age), // might underflow
+ tree_id(type),
+ season(0)
{
- grund_t * gr = welt->lookup_kartenboden(pos);
- if( gr ) {
- if( get_count( welt->get_climate(pos) ) > 0 && gr->ist_natur() && gr->get_top() < maximum_count ) {
- obj_t *obj = gr->obj_bei(0);
- if(obj) {
- switch(obj->get_typ()) {
- case obj_t::wolke:
- case obj_t::air_vehicle:
- case obj_t::baum:
- case obj_t::leitung:
- case obj_t::label:
- case obj_t::zeiger:
- // ok to built here
- break;
- case obj_t::groundobj:
- if(((groundobj_t *)obj)->get_desc()->can_build_trees_here()) {
- break;
- }
- /* FALLTHROUGH */
- // leave these (and all other empty)
- default:
- return 0;
- }
- }
- const uint8 count_planted = min( maximum_count - gr->get_top(), count);
- for (uint8 i=0; iobj_add( new baum_t(gr->get_pos()) ); //plants the tree(s)
- }
- return count_planted;
- }
- }
- return 0;
+ calc_off( slope );
+ calc_image();
}
-/**
- * tree planting function - it takes care of checking suitability of area
- */
-bool baum_t::plant_tree_on_coordinate(koord pos, const tree_desc_t *desc, const bool check_climate, const bool random_age )
+baum_t::baum_t(koord3d pos, const tree_desc_t *desc) :
+ obj_t(pos),
+ geburt(welt->get_current_month()),
+ tree_id(tree_builder_t::get_id_by_desc(desc)),
+ season(0)
{
- // none there
- if( desc_table.empty() ) {
- return false;
- }
- grund_t *gr = welt->lookup_kartenboden(pos);
- if( gr ) {
- if( gr->ist_natur() && gr->get_top() < welt->get_settings().get_max_no_of_trees_on_square() && (!check_climate || desc->is_allowed_climate( welt->get_climate(pos) )) ) {
- if( gr->get_top() > 0 ) {
- switch(gr->obj_bei(0)->get_typ()) {
- case obj_t::wolke:
- case obj_t::air_vehicle:
- case obj_t::baum:
- case obj_t::leitung:
- case obj_t::label:
- case obj_t::zeiger:
- // ok to built here
- break;
- case obj_t::groundobj:
- if(((groundobj_t *)(gr->obj_bei(0)))->get_desc()->can_build_trees_here()) {
- break;
- }
- /* FALLTHROUGH */
- // leave these (and all other empty)
- default:
- return false;
- }
- }
- baum_t *b = new baum_t(gr->get_pos(), desc); //plants the tree
- if( random_age ) {
- b->geburt = welt->get_current_month() - simrand(703);
- b->calc_off( welt->lookup( b->get_pos() )->get_grund_hang() );
- }
- gr->obj_add( b );
- return true; //tree was planted - currently unused value is not checked
- }
- }
- return false;
+
+ calc_off( welt->lookup( get_pos())->get_grund_hang() );
+ calc_image();
}
-uint32 baum_t::create_forest(koord new_center, koord wh, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom )
+void baum_t::rdwr(loadsave_t *file)
{
- // none there
- if( desc_table.empty() ) {
- return 0;
- }
- const sint16 xpos_f = new_center.x;
- const sint16 ypos_f = new_center.y;
- uint32 number_of_new_trees = 0;
- for( sint16 j = 0; j < wh.x; j++) {
- for( sint16 i = 0; i < wh.y; i++) {
-
- const sint32 x_tree_pos = (j-(wh.x>>1));
- const sint32 y_tree_pos = (i-(wh.y>>1));
+ xml_tag_t d( file, "baum_t" );
- if( xtop > (xpos_f + x_tree_pos) || (xpos_f + x_tree_pos) >= xbottom ) {
- continue;
- }
- if( ytop > (ypos_f + y_tree_pos) || (ypos_f + y_tree_pos) >= ybottom ) {
- continue;
- }
+ obj_t::rdwr(file);
- const uint64 distance = 1 + sqrt_i64( ((uint64)x_tree_pos*x_tree_pos*(wh.y*wh.y) + (uint64)y_tree_pos*y_tree_pos*(wh.x*wh.x)));
- const uint32 tree_probability = (uint32)( ( 8 * (uint32)((wh.x*wh.x)+(wh.y*wh.y)) ) / distance );
+ sint32 alter = (welt->get_current_month() - geburt)<<18;
+ file->rdwr_long(alter);
- if (tree_probability < 38) {
- continue;
- }
+ // after loading, calculate new
+ geburt = welt->get_current_month() - (alter>>18);
- uint8 number_to_plant = 0;
- uint8 const max_trees_here = min(welt->get_settings().get_max_no_of_trees_on_square(), (tree_probability - 38 + 1) / 2);
- for (uint8 c2 = 0 ; c2is_loading()) {
+ char buf[128];
+ file->rdwr_str(buf, lengthof(buf));
- number_of_new_trees += baum_t::plant_tree_on_coordinate(koord((sint16)(xpos_f + x_tree_pos), (sint16)(ypos_f + y_tree_pos)), welt->get_settings().get_max_no_of_trees_on_square(), number_to_plant);
+ const tree_desc_t *desc = tree_builder_t::get_desc_by_name( buf );
+ if( !desc ) {
+ desc = tree_builder_t::get_desc_by_name( translator::compatibility_name(buf) );
}
- }
- return number_of_new_trees;
-}
-
-void baum_t::fill_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom )
-{
- // none there
- if( desc_table.empty() ) {
- return;
- }
-DBG_MESSAGE("verteile_baeume()","distributing single trees");
- koord pos;
- for( pos.y=ytop; pos.ylookup_kartenboden(pos);
- if(gr->get_top() == 0 && gr->get_typ() == grund_t::boden) {
- // plant spare trees, (those with low preffered density) or in an entirely tree climate
- uint16 cl = 1 << welt->get_climate(pos);
- settings_t const& s = welt->get_settings();
- if ((cl & s.get_no_tree_climates()) == 0 && ((cl & s.get_tree_climates()) != 0 || simrand(s.get_forest_inverse_spare_tree_density() * dichte) < 100)) {
- plant_tree_on_coordinate(pos, 1, 1);
- }
- }
+ if( desc ) {
+ tree_id = tree_builder_t::get_id_by_desc( desc );
+ }
+ else {
+ // not a tree
+ tree_id = tree_builder_t::get_num_trees();
}
}
-}
-
-
-static bool compare_tree_desc(const tree_desc_t* a, const tree_desc_t* b)
-{
- // same level - we do an artificial but unique sorting by (untranslated) name
- return strcmp(a->get_name(), b->get_name())<0;
-}
-
-
-bool baum_t::successfully_loaded()
-{
- if( desc_table.empty() ) {
- DBG_MESSAGE("baum_t", "No trees found - feature disabled");
+ else {
+ const char *c = get_desc()->get_name();
+ file->rdwr_str(c);
}
- FOR(stringhashtable_tpl, const& i, desc_table) {
- tree_list.insert_ordered(i.value, compare_tree_desc);
- if( tree_list.get_count()==255 ) {
- dbg->error( "baum_t::successfully_loaded()", "Maximum tree count exceeded! (max 255 instead of %i)", desc_table.get_count() );
- break;
- }
+ // z-offset
+ if(file->is_version_atleast(111, 1)) {
+ uint8 zoff_ = zoff;
+ file->rdwr_byte(zoff_);
+ zoff = zoff_;
}
- tree_list.append( NULL );
-
- delete [] tree_list_per_climate;
- tree_list_per_climate = new weighted_vector_tpl[MAX_CLIMATES];
-
- // clear cache
- memset( tree_id_to_image, -1, sizeof(tree_id_to_image) );
- // now register all trees for all fitting climates
- for( uint32 typ=0; typis_allowed_climate((climate)j) ) {
- tree_list_per_climate[j].append(typ, tree_list[typ]->get_distribution_weight());
- }
- }
- // create cache images
- for( uint8 season = 0; season < 5; season++ ) {
- uint8 use_season = 0;
- const sint16 seasons = tree_list[typ]->get_seasons();
- if( seasons > 1 ) {
- use_season = season;
- // three possibilities
- if( seasons < 4 ) {
- // only summer and winter => season 4 with winter image
- use_season = (season == 4);
- }
- else if( seasons == 4 ) {
- // all there, but the snowy special image missing
- if( season == 4 ) {
- // take spring image (gave best results with pak64, pak.german) ////// but season 2 is winter????
- use_season = 2;
- }
- }
- }
- for( uint8 age = 0; age < 5; age++ ) {
- tree_id_to_image[typ][season * 5 + age] = tree_list[typ]->get_image_id( use_season, age );
- }
+ else {
+ // correct z-offset
+ if(file->is_loading()) {
+ // this will trigger recalculation of offset in finish_rd()
+ // we cant call calc_off() since this->pos is still invalid
+ set_xoff(-128);
}
}
- return true;
}
-bool baum_t::register_desc(tree_desc_t *desc)
+void baum_t::finish_rd()
{
- // avoid duplicates with same name
- if( desc_table.remove(desc->get_name()) ) {
- dbg->doubled( "baum_t", desc->get_name() );
+ if(get_xoff()==-128) {
+ calc_off(welt->lookup( get_pos())->get_grund_hang());
}
- desc_table.put(desc->get_name(), desc );
- return true;
}
-// calculates tree position on a tile
-// takes care of slopes
-void baum_t::calc_off(uint8 slope, sint8 x_, sint8 y_)
+image_id baum_t::get_image() const
{
- sint16 random = (sint16)( get_pos().x + get_pos().y + get_pos().z + slope + (sint16)(intptr_t)this );
- // point on tile (imaginary origin at sw corner, x axis: north, y axis: east
- sint16 x = x_==-128 ? (random + tree_id) & 31 : x_;
- sint16 y = y_==-128 ? (random + get_age()) & 31 : y_;
-
- // the last bit has to be the same
- y = y ^ (x&1);
-
- // bilinear interpolation of tile height
- uint32 zoff_ = ((corner_ne(slope)*x*y + corner_nw(slope)*x*(32-y)
- + corner_se(slope)*(32-x)*y + corner_sw(slope)*(32-x)*(32-y)) * TILE_HEIGHT_STEP) / (32*32);
- // now zoff between 0 and TILE_HEIGHT_STEP-1
- zoff = zoff_ < (uint32)TILE_HEIGHT_STEP ? zoff_ : TILE_HEIGHT_STEP-1u;
-
- // xoff must be even
- set_xoff( x + y - 32 );
- set_yoff( (y - x)/2 - zoff);
-}
-
+ if( env_t::hide_trees ) {
+ if( env_t::hide_with_transparency ) {
+ // we need the real age for transparency or real image
+ return IMG_EMPTY;
+ }
+ else {
+ return tree_builder_t::get_tree_image(tree_id, 0, season);
+ }
+ }
-void baum_t::recalc_off()
-{
- // reconstruct position on tile
- const sint8 xoff = get_xoff() + 32; // = x+y
- const sint8 yoff = 2*(get_yoff() + zoff); // = y-x
- sint8 x = (xoff - yoff) / 2;
- sint8 y = (xoff + yoff) / 2;
- calc_off(welt->lookup( get_pos())->get_grund_hang(), x, y);
+ return tree_builder_t::get_tree_image(tree_id, get_age(), season);
+ // return get_desc()->get_image_id( season, baum_alter );
}
-void baum_t::rotate90()
+// image which transparent outline is used
+image_id baum_t::get_outline_image() const
{
- // cant use obj_t::rotate90 to rotate offsets as it rotates them only if xoff!=0
- sint8 old_yoff = get_yoff() + zoff;
- sint8 old_xoff = get_xoff();
- // rotate position
- obj_t::rotate90();
- // .. and the offsets
- set_xoff( -2 * old_yoff );
- set_yoff( old_xoff/2 - zoff);
+ return tree_builder_t::get_tree_image(tree_id, get_age(), season);
+ // return get_desc()->get_image_id( season, baum_alter );
}
@@ -386,106 +175,17 @@ void baum_t::calc_image()
}
-image_id baum_t::get_image() const
-{
- if( env_t::hide_trees ) {
- if( env_t::hide_with_transparency ) {
- // we need the real age for transparency or real image
- return IMG_EMPTY;
- }
- else {
- return tree_id_to_image[ tree_id ][ season*5 ];
- }
- }
- const uint8 baum_alter = tree_age_index[min(get_age()>>6, 11u)];
- return tree_id_to_image[ tree_id ][ season*5 + baum_alter ];
-// return get_desc()->get_image_id( season, baum_alter );
-}
-
-
-// image which transparent outline is used
-image_id baum_t::get_outline_image() const
-{
- const uint8 baum_alter = tree_age_index[min(get_age()>>6, 11u)];
- return tree_id_to_image[ tree_id ][ season*5 + baum_alter ];
-// return get_desc()->get_image_id( season, baum_alter );
-}
-
-
-uint32 baum_t::get_age() const
-{
- sint32 age = welt->get_current_month() - geburt;
- if (age<0) {
- // correct underflow, geburt is 16bit
- age += 1 << 16;
- }
- return age;
-}
-
-
-/**
- * also checks for distribution values
- */
-uint16 baum_t::random_tree_for_climate_intern(climate cl)
-{
- // now weight their distribution
- weighted_vector_tpl const& t = tree_list_per_climate[cl];
- return t.empty() ? 0xFFFF : pick_any_weighted(t);
-}
-
-
-baum_t::baum_t(loadsave_t *file) : obj_t()
-{
- season = 0;
- geburt = welt->get_current_month();
- tree_id = 0;
- rdwr(file);
-}
-
-baum_t::baum_t(koord3d pos) : obj_t(pos)
+FLAGGED_PIXVAL baum_t::get_outline_colour() const
{
- // generate aged trees
- // might underflow
- geburt = welt->get_current_month() - simrand(703);
- tree_id = (uint8)random_tree_for_climate_intern( welt->get_climate( pos.get_2d() ) );
- season = 0;
- calc_off( welt->lookup( get_pos())->get_grund_hang() );
- calc_image();
+ return outline_color;
}
-baum_t::baum_t(koord3d pos, uint8 type, sint32 age, uint8 slope ) : obj_t(pos)
+void baum_t::recalc_outline_color()
{
- geburt = welt->get_current_month()-age; // might underflow
- tree_id = type;
- season = 0;
- calc_off( slope );
- calc_image();
-}
-
-
-baum_t::baum_t(koord3d pos, const tree_desc_t *desc) : obj_t(pos)
-{
- geburt = welt->get_current_month();
- tree_id = tree_list.index_of(desc);
- season = 0;
- calc_off( welt->lookup( get_pos())->get_grund_hang() );
- calc_image();
-}
-
-
-bool baum_t::saee_baum()
-{
- // spawn a new tree in an area 3x3 tiles around
- // the area for normal new tree planting is slightly more restricted, square of 9x9 was too much
-
- // to have same execution order for simrand
- const sint16 sx = simrand(5)-2;
- const sint16 sy = simrand(5)-2;
- const koord k = get_pos().get_2d() + koord(sx,sy);
-
- return plant_tree_on_coordinate(k, tree_list[tree_id], true, false);
+ outline_color = (env_t::hide_trees && env_t::hide_with_transparency) ?
+ (TRANSPARENT25_FLAG | OUTLINE_FLAG | color_idx_to_rgb(COL_BLACK)) : 0;
}
@@ -500,23 +200,25 @@ bool baum_t::check_season(const bool)
age += 1 << 16;
}
- if( age >= 512 && age <= 515 ) {
+ if( age >= baum_t::SPAWN_PERIOD_START && age < baum_t::SPAWN_PERIOD_START + baum_t::SPAWN_PERIOD_LENGTH ) {
// only in this month a tree can span new trees
// only 1-3 trees will be planted....
uint8 const c_plant_tree_max = 1 + simrand( welt->get_settings().get_max_no_of_trees_on_square() );
- uint retrys = 0;
- for( uint8 c_temp = 0; c_temp < c_plant_tree_max && retrys < c_plant_tree_max; c_temp++ ) {
- if( !saee_baum() ) {
- retrys++;
+ uint retries = 0;
+
+ for( uint8 c_temp = 0; c_temp < c_plant_tree_max && retries < c_plant_tree_max; c_temp++ ) {
+ if( !tree_builder_t::spawn_tree_near(this) ) {
+ retries++;
c_temp--;
}
}
+
// we make the tree four months older to avoid second spawning
- geburt = geburt - 4;
+ geburt -= baum_t::SPAWN_PERIOD_LENGTH;
}
- // tree will die after 704 month (i.e. 58 years 8 month)
- if( age >= 704 ) {
+ // tree will die after 704 months (i.e. 58 years 8 months)
+ if( age >= baum_t::AGE_LIMIT ) {
mark_image_dirty( get_image(), 0 );
return false;
}
@@ -532,60 +234,61 @@ bool baum_t::check_season(const bool)
}
-void baum_t::rdwr(loadsave_t *file)
+void baum_t::rotate90()
{
- xml_tag_t d( file, "baum_t" );
+ // cant use obj_t::rotate90 to rotate offsets as it rotates them only if xoff!=0
+ sint8 old_yoff = get_yoff() + zoff;
+ sint8 old_xoff = get_xoff();
- obj_t::rdwr(file);
+ // rotate position
+ obj_t::rotate90();
- sint32 alter = (welt->get_current_month() - geburt)<<18;
- file->rdwr_long(alter);
+ // .. and the offsets
+ set_xoff( -2 * old_yoff );
+ set_yoff( old_xoff/2 - zoff);
+}
- // after loading, calculate new
- geburt = welt->get_current_month() - (alter>>18);
- if(file->is_loading()) {
- char buf[128];
- file->rdwr_str(buf, lengthof(buf));
- const tree_desc_t *desc = desc_table.get( buf );
- if( !tree_list.is_contained(desc) ) {
- desc = desc_table.get( translator::compatibility_name(buf) );
- }
- if( tree_list.is_contained(desc) ) {
- tree_id = tree_list.index_of( desc );
- }
- else {
- // not a tree
- tree_id = tree_list.get_count()-1;
- }
- }
- else {
- const char *c = get_desc()->get_name();
- file->rdwr_str(c);
- }
- // z-offset
- if(file->is_version_atleast(111, 1)) {
- uint8 zoff_ = zoff;
- file->rdwr_byte(zoff_);
- zoff = zoff_;
- }
- else {
- // correct z-offset
- if(file->is_loading()) {
- // this will trigger recalculation of offset in finish_rd()
- // we cant call calc_off() since this->pos is still invalid
- set_xoff(-128);
- }
- }
+void baum_t::recalc_off()
+{
+ // reconstruct position on tile
+ const sint8 xoff = get_xoff() + 32; // = x+y
+ const sint8 yoff = 2*(get_yoff() + zoff); // = y-x
+ sint8 x = (xoff - yoff) / 2;
+ sint8 y = (xoff + yoff) / 2;
+
+ calc_off(welt->lookup( get_pos())->get_grund_hang(), x, y);
}
-void baum_t::finish_rd()
+// calculates tree position on a tile
+// takes care of slopes
+void baum_t::calc_off(uint8 slope, sint8 x_, sint8 y_)
{
- if(get_xoff()==-128) {
- calc_off(welt->lookup( get_pos())->get_grund_hang());
- }
+ const sint16 random = (sint16)( get_pos().x + get_pos().y + get_pos().z + slope + (sint16)(intptr_t)this );
+
+ // point on tile (imaginary origin at sw corner, x axis: north, y axis: east
+ sint16 x = x_==-128 ? (random + tree_id) & 31 : x_;
+ sint16 y = y_==-128 ? (random + get_age()) & 31 : y_;
+
+ // the last bit has to be the same
+ y ^= x&1;
+
+ // bilinear interpolation of tile height
+ const uint32 zoff_ =
+ ((corner_ne(slope) * x * y +
+ corner_nw(slope) * x * (32-y) +
+ corner_se(slope) * (32-x) * y +
+ corner_sw(slope) * (32-x) * (32-y))
+ * TILE_HEIGHT_STEP) / (32*32);
+
+ // now zoff between 0 and TILE_HEIGHT_STEP-1
+ zoff = zoff_ < (uint32)TILE_HEIGHT_STEP ? zoff_ : TILE_HEIGHT_STEP-1u;
+
+ // xoff must be even
+ set_xoff( x + y - 32 );
+ set_yoff( (y - x)/2 - zoff);
}
@@ -597,13 +300,14 @@ void baum_t::show_info()
}
-void baum_t::info(cbuffer_t & buf) const
+void baum_t::info(cbuffer_t &buf) const
{
obj_t::info(buf);
buf.append( translator::translate(get_desc()->get_name()) );
buf.append( "\n" );
- uint32 age = get_age();
+
+ const uint32 age = get_age();
buf.printf( translator::translate("%i years %i months old."), age/12, (age%12) );
if (char const* const maker = get_desc()->get_copyright()) {
@@ -620,6 +324,17 @@ void baum_t::cleanup(player_t *player)
}
+uint32 baum_t::get_age() const
+{
+ sint32 age = welt->get_current_month() - geburt;
+ if (age<0) {
+ // correct underflow, geburt is 16bit
+ age += 1 << 16;
+ }
+ return age;
+}
+
+
void *baum_t::operator new(size_t /*s*/)
{
return freelist_t::gimme_node(sizeof(baum_t));
diff --git obj/baum.h obj/baum.h
index f37edae4b..8518f9a85 100644
--- obj/baum.h
+++ obj/baum.h
@@ -9,6 +9,7 @@
#include "simobj.h"
+#include "../bauer/tree_builder.h"
#include "../tpl/stringhashtable_tpl.h"
#include "../tpl/vector_tpl.h"
#include "../tpl/weighted_vector_tpl.h"
@@ -24,122 +25,99 @@
*/
class baum_t : public obj_t
{
+ friend class tree_builder_t;
+
+public:
+ static const uint16 AGE_LIMIT = 704; // in months (58 years 8 months)
+ static const uint16 SPAWN_PERIOD_START = 512;
+ static const uint16 SPAWN_PERIOD_LENGTH = 4;
+
private:
static FLAGGED_PIXVAL outline_color;
- /** month of birth */
+ /// month of birth
uint16 geburt;
- /** type of tree (was 9 but for more compact saves now only 254 different tree types are allowed) */
+ /// type of tree (was 9 but for more compact saves now only 254 different tree types are allowed)
uint8 tree_id;
uint8 season:3;
- /** z-offset, max TILE_HEIGHT_STEP ie 4 bits */
+ /// z-offset, max TILE_HEIGHT_STEP ie 4 bits
uint8 zoff:4;
// one bit free ;)
- // static for administration
- static stringhashtable_tpl desc_table;
- static vector_tpl tree_list;
- static weighted_vector_tpl* tree_list_per_climate;
-
- bool saee_baum();
-
- /**
- * calculate offsets for new trees
- */
- void calc_off(uint8 slope, sint8 x=-128, sint8 y=-128);
-
- static uint16 random_tree_for_climate_intern(climate cl);
-
public:
- /**
- * Only the load save constructor should be called outside
- * otherwise I suggest use the plant tree function (see below)
- */
+ /// Only the load save constructor should be called outside.
+ /// Otherwise I suggest use the plant tree function (@see tree_builder_t)
baum_t(loadsave_t *file);
baum_t(koord3d pos);
- baum_t(koord3d pos, uint8 type, sint32 age, uint8 slope );
+ baum_t(koord3d pos, uint8 type, sint32 age, uint8 slope);
baum_t(koord3d pos, const tree_desc_t *desc);
+public:
+ /// @copydoc obj_t::get_name
+ const char *get_name() const OVERRIDE { return "Baum"; }
+
+ /// @copydoc obj_t::get_typ
+ typ get_typ() const OVERRIDE { return baum; }
+
+ /// @copydoc obj_t::rdwr
void rdwr(loadsave_t *file) OVERRIDE;
+ /// @copydoc obj_t::finish_rd
void finish_rd() OVERRIDE;
+ /// @copydoc obj_t::get_image
image_id get_image() const OVERRIDE;
- /**
- * hide trees eventually with transparency
- */
- FLAGGED_PIXVAL get_outline_colour() const OVERRIDE { return outline_color; }
+ /// @copydoc obj_t::get_outline_image
image_id get_outline_image() const OVERRIDE;
- static void recalc_outline_color() { outline_color = (env_t::hide_trees && env_t::hide_with_transparency) ? (TRANSPARENT25_FLAG | OUTLINE_FLAG | color_idx_to_rgb(COL_BLACK)) : 0; }
-
- /**
- * Calculates tree image dependent on tree age
- */
+ /// @copydoc obj_t::calc_image
+ /// Calculates tree image dependent on tree age
void calc_image() OVERRIDE;
- /**
- * Called whenever the season or snowline height changes
- * return false and the obj_t will be deleted
- */
+ /// @copydoc obj_t::get_outline_colour
+ /// hide trees eventually with transparency
+ FLAGGED_PIXVAL get_outline_colour() const OVERRIDE;
+
+ static void recalc_outline_color();
+
+ /// @copydoc obj_t::check_season
bool check_season(const bool) OVERRIDE;
+ /// @copydoc obj_t::rotate90
void rotate90() OVERRIDE;
- /**
- * re-calculate z-offset if slope of the tile has changed
- */
+ /// re-calculate z-offset if slope of the tile has changed
void recalc_off();
- const char *get_name() const OVERRIDE {return "Baum";}
- typ get_typ() const OVERRIDE { return baum; }
-
+ /// @copydoc obj_t::show_info
void show_info() OVERRIDE;
+ /// @copydoc obj-t::info
void info(cbuffer_t & buf) const OVERRIDE;
+ /// @copydoc obj_t::cleanup
void cleanup(player_t *player) OVERRIDE;
- void * operator new(size_t s);
- void operator delete(void *p);
-
- const tree_desc_t* get_desc() const { return tree_list[tree_id]; }
- void set_desc( const tree_desc_t *b ) { tree_id = tree_list.index_of(b); }
+public:
+ const tree_desc_t *get_desc() const { return tree_builder_t::get_desc_by_id(tree_id); }
+ void set_desc(const tree_desc_t *desc) { tree_id = tree_builder_t::get_id_by_desc(desc); }
uint16 get_desc_id() const { return tree_id; }
+ /// @returns the age of the tree, in months.
uint32 get_age() const;
- // static functions to handle trees
-
- // distributes trees on a map
- static void distribute_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom );
-
- static void fill_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom );
-
- static uint32 create_forest(koord center, koord size, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom );
-
- static bool plant_tree_on_coordinate(koord pos, const tree_desc_t *desc, const bool check_climate, const bool random_age );
-
- static uint8 plant_tree_on_coordinate(koord pos, const uint8 maximum_count, const uint8 count);
-
- static bool register_desc(tree_desc_t *desc);
- static bool successfully_loaded();
-
- // return list to descriptors
- static vector_tpl const& get_all_desc() { return tree_list; }
-
- static const tree_desc_t *random_tree_for_climate(climate cl) { uint16 b = random_tree_for_climate_intern(cl); return b!=0xFFFF ? tree_list[b] : NULL; }
-
- static const tree_desc_t *find_tree( const char *tree_name ) { return tree_list.empty() ? NULL : desc_table.get(tree_name); }
-
- static int get_count() { return tree_list.get_count()-1; }
- static int get_count(climate cl);
+public:
+ void *operator new(size_t s);
+ void operator delete(void *p);
+private:
+ /// calculate offsets for new trees
+ void calc_off(uint8 slope, sint8 x=-128, sint8 y=-128);
};
#endif
diff --git script/api/api_obj_desc_base.cc script/api/api_obj_desc_base.cc
index ae37bd00a..6a873cdd0 100644
--- script/api/api_obj_desc_base.cc
+++ script/api/api_obj_desc_base.cc
@@ -29,7 +29,7 @@ static const way_desc_t *my_get_desc(const char *name)
return way_builder_t::get_desc(name);
}
-implement_desc_param(tree_desc_t, "tree_desc_x", &baum_t::find_tree);
+implement_desc_param(tree_desc_t, "tree_desc_x", &tree_builder_t::find_tree);
implement_desc_param(building_desc_t, "building_desc_x", &hausbauer_t::get_desc);
implement_desc_param(goods_desc_t, "good_desc_x", (const goods_desc_t* (*)(const char*))(&goods_manager_t::get_info) );
implement_desc_param(way_desc_t, "way_desc_x", &my_get_desc);
diff --git simtool-dialogs.h simtool-dialogs.h
index 529d3849c..dd53c303d 100644
--- simtool-dialogs.h
+++ simtool-dialogs.h
@@ -509,10 +509,10 @@ class dialog_edit_tree_t : public tool_t {
public:
dialog_edit_tree_t() : tool_t(DIALOG_EDIT_TREE | DIALOGE_TOOL) {}
char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("baum builder"); }
- image_id get_icon(player_t *) const OVERRIDE { return baum_t::get_count() > 0 ? icon : IMG_EMPTY; }
+ image_id get_icon(player_t *) const OVERRIDE { return tree_builder_t::has_trees() ? icon : IMG_EMPTY; }
bool is_selected() const OVERRIDE{ return win_get_magic(magic_edit_tree); }
bool init(player_t* player) OVERRIDE{
- if (baum_t::get_count() > 0 && !is_selected()) {
+ if (tree_builder_t::has_trees() > 0 && !is_selected()) {
create_win(new baum_edit_frame_t(player), w_info, magic_edit_tree);
}
return false;
diff --git simtool.cc simtool.cc
index 6246d32e1..8317bfabd 100644
--- simtool.cc
+++ simtool.cc
@@ -2151,18 +2151,20 @@ const char *tool_plant_tree_t::work( player_t *player, koord3d pos )
bool check_climates = true;
bool random_age = false;
if(default_param==NULL || strlen(default_param)==0) {
- desc = baum_t::random_tree_for_climate( welt->get_climate( k ) );
+ desc = tree_builder_t::random_tree_for_climate( welt->get_climate( k ) );
}
else {
// parse default_param: bbdesc_nr b=1 ignore climate b=1 random age
check_climates = default_param[0]=='0';
random_age = default_param[1]=='1';
- desc = baum_t::find_tree(default_param+3);
+ desc = tree_builder_t::find_tree(default_param+3);
}
- if(desc && baum_t::plant_tree_on_coordinate( k, desc, check_climates, random_age ) ) {
+
+ if(desc && tree_builder_t::plant_tree_on_coordinate( k, desc, check_climates, random_age ) ) {
player_t::book_construction_costs(player, cost, k, ignore_wt);
return NULL;
}
+
return "";
}
return NULL;
@@ -6116,7 +6118,7 @@ const char *tool_forest_t::do_work( player_t *player, const koord3d &start, cons
nw.x = min(start.x, end.x)+(wh.x/2);
nw.y = min(start.y, end.y)+(wh.y/2);
- sint64 costs = baum_t::create_forest( nw, wh, 0, 0, welt->get_size().x, welt->get_size().y );
+ sint64 costs = tree_builder_t::create_forest( nw, wh, 0, 0, welt->get_size().x, welt->get_size().y );
player_t::book_construction_costs(player, costs * welt->get_settings().cst_remove_tree, end.get_2d(), ignore_wt);
return NULL;
diff --git simtool.h simtool.h
index 3c93ccf91..64c000f96 100644
--- simtool.h
+++ simtool.h
@@ -237,9 +237,9 @@ private:
class tool_plant_tree_t : public kartenboden_tool_t {
public:
tool_plant_tree_t() : kartenboden_tool_t(TOOL_PLANT_TREE | GENERAL_TOOL) {}
- image_id get_icon(player_t *) const OVERRIDE { return baum_t::get_count() > 0 ? icon : IMG_EMPTY; }
+ image_id get_icon(player_t *) const OVERRIDE { return tree_builder_t::get_num_trees() > 0 ? icon : IMG_EMPTY; }
char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate( "Plant tree" ); }
- bool init(player_t*) OVERRIDE { return baum_t::get_count() > 0; }
+ bool init(player_t*) OVERRIDE { return tree_builder_t::has_trees(); }
char const* move(player_t* const player, uint16 const b, koord3d const k) OVERRIDE;
bool move_has_effects() const OVERRIDE { return true; }
char const* work(player_t*, koord3d) OVERRIDE;
@@ -589,9 +589,9 @@ public:
class tool_forest_t : public two_click_tool_t {
public:
tool_forest_t() : two_click_tool_t(TOOL_FOREST | GENERAL_TOOL) {}
- image_id get_icon(player_t *) const OVERRIDE { return baum_t::get_count() > 0 ? icon : IMG_EMPTY; }
+ image_id get_icon(player_t *) const OVERRIDE { return tree_builder_t::has_trees() ? icon : IMG_EMPTY; }
char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Add forest"); }
- bool init( player_t *player) OVERRIDE { return baum_t::get_count() > 0 && two_click_tool_t::init(player); }
+ bool init( player_t *player) OVERRIDE { return tree_builder_t::has_trees() && two_click_tool_t::init(player); }
private:
char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE;
void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE;
@@ -924,10 +924,10 @@ class tool_fill_trees_t : public tool_t {
public:
tool_fill_trees_t() : tool_t(TOOL_FILL_TREES | SIMPLE_TOOL) {}
char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Fill trees"); }
- image_id get_icon(player_t *) const OVERRIDE { return baum_t::get_count() > 0 ? icon : IMG_EMPTY; }
+ image_id get_icon(player_t *) const OVERRIDE { return tree_builder_t::has_trees() ? icon : IMG_EMPTY; }
bool init(player_t * ) OVERRIDE {
- if( baum_t::get_count() > 0 && default_param ) {
- baum_t::fill_trees( atoi(default_param), 0, 0, welt->get_size().x, welt->get_size().y );
+ if( tree_builder_t::has_trees() && default_param ) {
+ tree_builder_t::fill_trees( atoi(default_param), 0, 0, welt->get_size().x, welt->get_size().y );
}
return false;
}
diff --git simworld.cc simworld.cc
index 7ea5784d2..609c04382 100644
--- simworld.cc
+++ simworld.cc
@@ -1739,26 +1739,26 @@ void karte_t::distribute_trees_region( sint16 xtop, sint16 ytop, sint16 xbottom,
number_to_plant++;
}
}
- baum_t::plant_tree_on_coordinate(pos, get_settings().get_max_no_of_trees_on_square(), number_to_plant);
+
+ tree_builder_t::plant_tree_on_coordinate(pos, get_settings().get_max_no_of_trees_on_square(), number_to_plant);
}
else if(humidity_map.at(pos.x,pos.y)>75) {
// plant spare trees, (those with low preffered density) or in an entirely tree climate
uint16 cl = 1 << get_climate(pos);
settings_t const& s = get_settings();
if ((cl & s.get_no_tree_climates()) == 0 && ((cl & s.get_tree_climates()) != 0 || simrand(s.get_forest_inverse_spare_tree_density() * /*dichte*/3) < 100)) {
- baum_t::plant_tree_on_coordinate(pos, 1, 1);
+ tree_builder_t::plant_tree_on_coordinate(pos, 1, 1);
}
}
}
}
-
}
break;
}
// fall-through
case 1:
// no humidity data or on request
- baum_t::distribute_trees(3, xtop, ytop, xbottom, ybottom );
+ tree_builder_t::distribute_trees(3, xtop, ytop, xbottom, ybottom );
break;
case 0:
// no trees