diff options
author | Niels Martin Hansen <nielsm@indvikleren.dk> | 2020-06-26 21:30:18 +0200 |
---|---|---|
committer | Patric Stout <github@truebrain.nl> | 2020-12-27 01:03:27 +0100 |
commit | 2d9fa81bd08425d64ab40ff377d9711aae39b6d5 (patch) | |
tree | 171d962535f495756ad669d62771afbdef95fabe /src | |
parent | e0ee2d530aaa7bcf0bf80012f27024337d0ac4e7 (diff) | |
download | openttd-2d9fa81bd08425d64ab40ff377d9711aae39b6d5.tar.xz |
Feature: Plant clumps of trees in editor by dragging on the landscape
Diffstat (limited to 'src')
-rw-r--r-- | src/lang/english.txt | 8 | ||||
-rw-r--r-- | src/tilehighlight_func.h | 1 | ||||
-rw-r--r-- | src/tree_cmd.cpp | 47 | ||||
-rw-r--r-- | src/tree_gui.cpp | 74 | ||||
-rw-r--r-- | src/viewport.cpp | 27 | ||||
-rw-r--r-- | src/widgets/tree_widget.h | 3 | ||||
-rw-r--r-- | src/window_gui.h | 3 |
7 files changed, 153 insertions, 10 deletions
diff --git a/src/lang/english.txt b/src/lang/english.txt index a735eace9..63f36588a 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2542,13 +2542,19 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Size: {G STR_OBJECT_CLASS_LTHS :Lighthouses STR_OBJECT_CLASS_TRNS :Transmitters -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trees STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Place trees of random type. Shift toggles building/showing cost estimate STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Random Trees STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plant trees randomly throughout the landscape +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Normal +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}Plant single trees by dragging over the landscape. +STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}Grove +STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}Plant small forests by dragging over the landscape. +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}Forest +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}Plant large forests by dragging over the landscape. # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Land Generation diff --git a/src/tilehighlight_func.h b/src/tilehighlight_func.h index a6e8a3815..c980931d7 100644 --- a/src/tilehighlight_func.h +++ b/src/tilehighlight_func.h @@ -22,6 +22,7 @@ void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowC void ResetObjectToPlace(); void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method); +void VpStartDragging(ViewportDragDropSelectionProcess process); void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process); void VpSetPresizeRange(TileIndex from, TileIndex to); void VpSetPlaceSizingLimit(int limit); diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index c40df4394..60eb781f5 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -291,6 +291,51 @@ void PlaceTreesRandomly() } /** + * Place some trees in a radius around a tile. + * The trees are placed in an quasi-normal distribution around the indicated tile, meaning that while + * the radius does define a square, the distribution inside the square will be roughly circular. + * @note This function the interactive RNG and must only be used in editor and map generation. + * @param tile Tile to place trees around. + * @param treetype Type of trees to place. Must be a valid tree type for the climate. + * @param radius Maximum distance (on each axis) from tile to place trees. + * @param count Maximum number of trees to place. + * @return Number of trees actually placed. + */ +uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count) +{ + assert(treetype < TREE_TOYLAND + TREE_COUNT_TOYLAND); + const bool allow_desert = treetype == TREE_CACTUS; + uint planted = 0; + + for (; count > 0; count--) { + /* Simple quasi-normal distribution with range [-radius; radius) */ + auto mkcoord = [&]() -> int32 { + const uint32 rand = InteractiveRandom(); + const int32 dist = GB<int32>(rand, 0, 8) + GB<int32>(rand, 8, 8) + GB<int32>(rand, 16, 8) + GB<int32>(rand, 24, 8); + const int32 scu = dist * radius / 512; + return scu - radius; + }; + const int32 xofs = mkcoord(); + const int32 yofs = mkcoord(); + const TileIndex tile_to_plant = TileAddWrap(tile, xofs, yofs); + if (tile_to_plant != INVALID_TILE) { + if (IsTileType(tile_to_plant, MP_TREES) && GetTreeCount(tile_to_plant) < 4) { + AddTreeCount(tile_to_plant, 1); + SetTreeGrowth(tile_to_plant, 0); + MarkTileDirtyByTile(tile_to_plant, 0); + planted++; + } else if (CanPlantTreesOnTile(tile_to_plant, allow_desert)) { + PlantTreesOnTile(tile_to_plant, treetype, 0, 3); + MarkTileDirtyByTile(tile_to_plant, 0); + planted++; + } + } + } + + return planted; +} + +/** * Place new trees. * * This function takes care of the selected tree placer algorithm and @@ -349,7 +394,7 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 switch (GetTileType(tile)) { case MP_TREES: /* no more space for trees? */ - if (_game_mode != GM_EDITOR && GetTreeCount(tile) == 4) { + if (GetTreeCount(tile) == 4) { msg = STR_ERROR_TREE_ALREADY_HERE; continue; } diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 58edf563b..ee94c35af 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -14,6 +14,7 @@ #include "company_func.h" #include "company_base.h" #include "command_func.h" +#include "core/random_func.hpp" #include "sound_func.h" #include "strings_func.h" #include "zoom_func.h" @@ -28,6 +29,7 @@ #include "safeguards.h" void PlaceTreesRandomly(); +uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count); /** Tree Sprites with their palettes */ const PalSpriteID tree_sprites[] = { @@ -79,7 +81,14 @@ class BuildTreesWindow : public Window /** Visual Y offset of tree root from the bottom of the tree type buttons */ static const int BUTTON_BOTTOM_OFFSET = 7; + enum PlantingMode { + PM_NORMAL, + PM_FOREST_SM, + PM_FOREST_LG, + }; + int tree_to_plant; ///< Tree number to plant, \c TREE_INVALID for a random tree. + PlantingMode mode; ///< Current mode for planting /** * Update the GUI and enable/disable planting to reflect selected options. @@ -106,15 +115,35 @@ class BuildTreesWindow : public Window this->LowerWidget(WID_BT_TYPE_BUTTON_FIRST + this->tree_to_plant); } + switch (this->mode) { + case PM_NORMAL: this->LowerWidget(WID_BT_MODE_NORMAL); break; + case PM_FOREST_SM: this->LowerWidget(WID_BT_MODE_FOREST_SM); break; + case PM_FOREST_LG: this->LowerWidget(WID_BT_MODE_FOREST_LG); break; + default: NOT_REACHED(); + } + this->SetDirty(); } + void DoPlantForest(TileIndex tile) + { + TreeType treetype = (TreeType)this->tree_to_plant; + if (this->tree_to_plant == TREE_INVALID) { + treetype = (TreeType)(InteractiveRandomRange(_tree_count_by_landscape[_settings_game.game_creation.landscape]) + _tree_base_by_landscape[_settings_game.game_creation.landscape]); + } + const uint radius = this->mode == PM_FOREST_LG ? 12 : 5; + const uint count = this->mode == PM_FOREST_LG ? 12 : 5; + PlaceTreeGroupAroundTile(tile, treetype, radius, count); + } + public: - BuildTreesWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), tree_to_plant(-1) + BuildTreesWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), tree_to_plant(-1), mode(PM_NORMAL) { this->InitNested(window_number); ResetObjectToPlace(); + this->LowerWidget(WID_BT_MODE_NORMAL); + /* Show scenario editor tools in editor */ auto *se_tools = this->GetWidget<NWidgetStacked>(WID_BT_SE_PANE); if (_game_mode != GM_EDITOR) { @@ -156,6 +185,23 @@ public: MarkWholeScreenDirty(); break; + case WID_BT_MODE_NORMAL: + this->mode = PM_NORMAL; + this->UpdateMode(); + break; + + case WID_BT_MODE_FOREST_SM: + assert(_game_mode == GM_EDITOR); + this->mode = PM_FOREST_SM; + this->UpdateMode(); + break; + + case WID_BT_MODE_FOREST_LG: + assert(_game_mode == GM_EDITOR); + this->mode = PM_FOREST_LG; + this->UpdateMode(); + break; + default: if (widget >= WID_BT_TYPE_BUTTON_FIRST) { const int index = widget - WID_BT_TYPE_BUTTON_FIRST; @@ -168,17 +214,31 @@ public: void OnPlaceObject(Point pt, TileIndex tile) override { - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES); + if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL) { + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES); + } else { + VpStartDragging(DDSP_PLANT_TREES); + } } void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { - VpSelectTilesWithMethod(pt.x, pt.y, select_method); + if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL) { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } else { + TileIndex tile = TileVirtXY(pt.x, pt.y); + + if (this->mode == PM_NORMAL) { + DoCommandP(tile, this->tree_to_plant, tile, CMD_PLANT_TREE); + } else { + this->DoPlantForest(tile); + } + } } void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { - if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) { + if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL && pt.x != -1 && select_proc == DDSP_PLANT_TREES) { DoCommandP(end_tile, this->tree_to_plant, start_tile, CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE)); } } @@ -241,6 +301,12 @@ static const NWidgetPart _nested_build_trees_widgets[] = { NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BT_SE_PANE), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_MODE_NORMAL), SetFill(1, 0), SetDataTip(STR_TREES_MODE_NORMAL_BUTTON, STR_TREES_MODE_NORMAL_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_MODE_FOREST_SM), SetFill(1, 0), SetDataTip(STR_TREES_MODE_FOREST_SM_BUTTON, STR_TREES_MODE_FOREST_SM_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_MODE_FOREST_LG), SetFill(1, 0), SetDataTip(STR_TREES_MODE_FOREST_LG_BUTTON, STR_TREES_MODE_FOREST_LG_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BT_MANY_RANDOM), SetDataTip(STR_TREES_RANDOM_TREES_BUTTON, STR_TREES_RANDOM_TREES_TOOLTIP), EndContainer(), EndContainer(), diff --git a/src/viewport.cpp b/src/viewport.cpp index e9e8d34da..7c5fd93b3 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2674,6 +2674,18 @@ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDrag _special_mouse_mode = WSM_SIZING; } +/** Drag over the map while holding the left mouse down. */ +void VpStartDragging(ViewportDragDropSelectionProcess process) +{ + _thd.select_method = VPM_X_AND_Y; + _thd.select_proc = process; + _thd.selstart.x = 0; + _thd.selstart.y = 0; + _thd.next_drawstyle = HT_RECT; + + _special_mouse_mode = WSM_DRAGGING; +} + void VpSetPlaceSizingLimit(int limit) { _thd.sizelimit = limit; @@ -3283,7 +3295,7 @@ calc_heightdiff_single_direction:; */ EventState VpHandlePlaceSizingDrag() { - if (_special_mouse_mode != WSM_SIZING) return ES_NOT_HANDLED; + if (_special_mouse_mode != WSM_SIZING && _special_mouse_mode != WSM_DRAGGING) return ES_NOT_HANDLED; /* stop drag mode if the window has been closed */ Window *w = _thd.GetCallbackWnd(); @@ -3294,13 +3306,22 @@ EventState VpHandlePlaceSizingDrag() /* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */ if (_left_button_down) { + if (_special_mouse_mode == WSM_DRAGGING) { + /* Only register a drag event when the mouse moved. */ + if (_thd.new_pos.x == _thd.selstart.x && _thd.new_pos.y == _thd.selstart.y) return ES_HANDLED; + _thd.selstart.x = _thd.new_pos.x; + _thd.selstart.y = _thd.new_pos.y; + } + w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor()); return ES_HANDLED; } - /* mouse button released.. - * keep the selected tool, but reset it to the original mode. */ + /* Mouse button released. */ _special_mouse_mode = WSM_NONE; + if (_special_mouse_mode == WSM_DRAGGING) return ES_HANDLED; + + /* Keep the selected tool, but reset it to the original mode. */ HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) { _thd.place_mode = HT_RECT | others; diff --git a/src/widgets/tree_widget.h b/src/widgets/tree_widget.h index 7474667a8..2cfc38ad4 100644 --- a/src/widgets/tree_widget.h +++ b/src/widgets/tree_widget.h @@ -14,6 +14,9 @@ enum BuildTreesWidgets { WID_BT_TYPE_RANDOM, ///< Button to build random type of tree. WID_BT_SE_PANE, ///< Selection pane to show/hide scenario editor tools. + WID_BT_MODE_NORMAL, ///< Select normal/rectangle planting mode. + WID_BT_MODE_FOREST_SM, ///< Select small forest planting mode. + WID_BT_MODE_FOREST_LG, ///< Select large forest planting mode. WID_BT_MANY_RANDOM, ///< Button to build many random trees. WID_BT_TYPE_BUTTON_FIRST, ///< First tree type selection button. (This must be last in the enum.) }; diff --git a/src/window_gui.h b/src/window_gui.h index b389db5a6..b03f5bbca 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -903,9 +903,10 @@ extern bool _mouse_hovering; /** Mouse modes. */ enum SpecialMouseMode { WSM_NONE, ///< No special mouse mode. - WSM_DRAGDROP, ///< Dragging an object. + WSM_DRAGDROP, ///< Drag&drop an object. WSM_SIZING, ///< Sizing mode. WSM_PRESIZE, ///< Presizing mode (docks, tunnels). + WSM_DRAGGING, ///< Dragging mode (trees). }; extern SpecialMouseMode _special_mouse_mode; |