From f44d75eaf5cad16aa24617482a3ef3623036feb7 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 14 Sep 2020 23:19:45 +0100 Subject: [PATCH] Allow building objects by area (1x1 objects only) Add setting (default on) --- src/command.cpp | 2 ++ src/command_type.h | 1 + src/lang/english.txt | 5 ++++ src/object_cmd.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++ src/object_gui.cpp | 37 ++++++++++++++++++++++-- src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/table/settings.ini | 8 ++++++ src/viewport_type.h | 1 + 9 files changed, 118 insertions(+), 3 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index 6afbd20458..dfb48826dc 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -54,6 +54,7 @@ CommandProc CmdTerraformLand; CommandProc CmdBuildObject; CommandProc CmdPurchaseLandArea; +CommandProc CmdBuildObjectArea; CommandProc CmdBuildHouse; CommandProc CmdSellLandArea; @@ -294,6 +295,7 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdTerraformLand, CMD_ALL_TILES | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_TERRAFORM_LAND DEF_CMD(CmdBuildObject, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_OBJECT DEF_CMD(CmdPurchaseLandArea, CMD_NO_WATER | CMD_AUTO | CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_PURCHASE_LAND_AREA + DEF_CMD(CmdBuildObjectArea, CMD_NO_WATER | CMD_AUTO | CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_OBJECT_AREA DEF_CMD(CmdBuildHouse, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_HOUSE DEF_CMD(CmdBuildTunnel, CMD_DEITY | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_TUNNEL DEF_CMD(CmdRemoveFromRailStation, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_STATION diff --git a/src/command_type.h b/src/command_type.h index 3024f6dfae..85671bdd87 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -243,6 +243,7 @@ enum Commands { CMD_TERRAFORM_LAND, ///< terraform a tile CMD_BUILD_OBJECT, ///< build an object CMD_PURCHASE_LAND_AREA, ///< purchase an area of landscape + CMD_BUILD_OBJECT_AREA, ///< build an area of objects CMD_BUILD_HOUSE, ///< build a house CMD_BUILD_TUNNEL, ///< build a tunnel diff --git a/src/lang/english.txt b/src/lang/english.txt index 027077fe0d..6932976054 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1985,6 +1985,9 @@ STR_CONFIG_SETTING_ALLOW_DOCKS_UNDER_BRIDGES_HELPTEXT :Allow docks und STR_CONFIG_SETTING_PURCHASE_LAND_PERMITTED :Permit purchasing land: {STRING2} STR_CONFIG_SETTING_PURCHASE_LAND_PERMITTED_HELPTEXT :Set whether companies are permitted to purchase tiles of land, and in what quantity +STR_CONFIG_SETTING_BUILD_OBJECT_PERMITTED :Permit bulk construction of objects: {STRING2} +STR_CONFIG_SETTING_BUILD_OBJECT_PERMITTED_HELPTEXT :Set whether companies are permitted to construct objects by area, instead of one at a time + STR_PURCHASE_LAND_PERMITTED_NO :No STR_PURCHASE_LAND_PERMITTED_SINGLE :Yes, 1 tile at a time STR_PURCHASE_LAND_PERMITTED_AREA :Yes, large areas at a time @@ -1992,6 +1995,8 @@ STR_PURCHASE_LAND_PERMITTED_AREA :Yes, large area STR_PURCHASE_LAND_NOT_PERMITTED :Purchasing of land is not permitted STR_PURCHASE_LAND_NOT_PERMITTED_BULK :Purchasing of large areas of land is not permitted +STR_BUILD_OBJECT_NOT_PERMITTED_BULK :Building large areas of objects is not permitted + STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change setting value STR_CONFIG_SETTING_ADJACENT_CROSSINGS :Close adjacent level crossings: {STRING2} diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 83b834985d..0b9bef8076 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -430,6 +430,71 @@ CommandCost CmdPurchaseLandArea(TileIndex tile, DoCommandFlag flags, uint32 p1, return had_success ? cost : last_error; } +/** + * Construct multiple objects in an area + * @param tile end tile of area dragging + * @param flags of operation to conduct + * @param p1 start tile of area dragging + * @param p2 various bitstuffed data. + * - p2 = (bit 0) - Whether to use the Orthogonal (0) or Diagonal (1) iterator. + * - p2 = (bit 1 - 2) - Object view + * - p2 = (bit 3 - 19) - Object type + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdBuildObjectArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + if (p1 >= MapSize()) return CMD_ERROR; + if (!_settings_game.construction.build_object_area_permitted) return_cmd_error(STR_BUILD_OBJECT_NOT_PERMITTED_BULK); + + ObjectType type = (ObjectType)GB(p2, 3, 16); + if (type >= NUM_OBJECTS) return CMD_ERROR; + uint8 view = GB(p2, 1, 2); + const ObjectSpec *spec = ObjectSpec::Get(type); + if (view >= spec->views) return CMD_ERROR; + + if (spec->size != 0x11) return CMD_ERROR; + + Money money = GetAvailableMoneyForCommand(); + CommandCost cost(EXPENSES_CONSTRUCTION); + CommandCost last_error = CMD_ERROR; + bool had_success = false; + + const Company *c = Company::GetIfValid(_current_company); + int limit = (c == nullptr ? INT32_MAX : GB(c->build_object_limit, 16, 16)); + + TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(tile, p1); + for (; *iter != INVALID_TILE; ++(*iter)) { + TileIndex t = *iter; + CommandCost ret = DoCommand(t, type, view, flags & ~DC_EXEC, CMD_BUILD_OBJECT); + if (ret.Failed()) { + last_error = ret; + + /* We may not clear more tiles. */ + if (c != nullptr && GB(c->build_object_limit, 16, 16) < 1) break; + continue; + } + + had_success = true; + if (flags & DC_EXEC) { + money -= ret.GetCost(); + if (ret.GetCost() > 0 && money < 0) { + _additional_cash_required = ret.GetCost(); + delete iter; + return cost; + } + DoCommand(t, type, view, flags, CMD_BUILD_OBJECT); + } else { + /* When we're at the clearing limit we better bail (unneed) testing as well. */ + if (ret.GetCost() != 0 && --limit <= 0) break; + } + cost.AddCost(ret); + } + + delete iter; + return had_success ? cost : last_error; +} + static Foundation GetFoundation_Object(TileIndex tile, Slope tileh); diff --git a/src/object_gui.cpp b/src/object_gui.cpp index bbd224fead..2505a580ce 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -339,7 +339,7 @@ public: } if (_selected_object_index != -1) { - SetObjectToPlaceWnd(SPR_CURSOR_TRANSMITTER, PAL_NONE, HT_RECT, this); + SetObjectToPlaceWnd(SPR_CURSOR_TRANSMITTER, PAL_NONE, HT_RECT | HT_DIAGONAL, this); } this->UpdateButtons(_selected_object_class, _selected_object_index, _selected_object_view); @@ -415,8 +415,13 @@ public: void OnPlaceObject(Point pt, TileIndex tile) override { - DoCommandP(tile, ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index(), - _selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); + const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); + if (_settings_game.construction.build_object_area_permitted && spec->size == 0x11) { + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_BUILD_OBJECT); + } else { + DoCommandP(tile, spec->Index(), + _selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); + } } void OnPlaceObjectAbort() override @@ -424,6 +429,32 @@ public: this->UpdateButtons(_selected_object_class, -1, _selected_object_view); } + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override + { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override + { + if (pt.x != -1) { + switch (select_proc) { + default: NOT_REACHED(); + case DDSP_BUILD_OBJECT: + if (!_settings_game.construction.freeform_edges) { + /* When end_tile is MP_VOID, the error tile will not be visible to the + * user. This happens when terraforming at the southern border. */ + if (TileX(end_tile) == MapMaxX()) end_tile += TileDiffXY(-1, 0); + if (TileY(end_tile) == MapMaxY()) end_tile += TileDiffXY(0, -1); + } + DoCommandP(end_tile, start_tile, + (ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index() << 3) | (_selected_object_view << 1) | (_ctrl_pressed ? 1 : 0), + CMD_BUILD_OBJECT_AREA | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); + break; + } + } + } + + /** * Select the first available object. * @param change_class If true, change the class if no object in the current diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 086d5528ad..5e5ac77f34 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1872,6 +1872,7 @@ static SettingsContainer &GetSettingsTree() limitations->Add(new SettingEntry("construction.allow_road_stops_under_bridges")); limitations->Add(new SettingEntry("construction.allow_docks_under_bridges")); limitations->Add(new SettingEntry("construction.purchase_land_permitted")); + limitations->Add(new SettingEntry("construction.build_object_area_permitted")); } SettingsPage *disasters = main->Add(new SettingsPage(STR_CONFIG_SETTING_ACCIDENTS)); diff --git a/src/settings_type.h b/src/settings_type.h index 995b750e30..fe158aedf4 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -391,6 +391,7 @@ struct ConstructionSettings { bool allow_road_stops_under_bridges; ///< allow road/tram stops under bridges bool allow_docks_under_bridges; ///< allow docks under bridges byte purchase_land_permitted; ///< whether and how purchasing land is permitted + bool build_object_area_permitted; ///< whether building objects by area is permitted uint32 terraform_per_64k_frames; ///< how many tile heights may, over a long period, be terraformed per 65536 frames? uint16 terraform_frame_burst; ///< how many tile heights may, over a short period, be terraformed? diff --git a/src/table/settings.ini b/src/table/settings.ini index 2b2305bb57..49cb9ec595 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -1936,6 +1936,14 @@ strhelp = STR_CONFIG_SETTING_PURCHASE_LAND_PERMITTED_HELPTEXT strval = STR_PURCHASE_LAND_PERMITTED_NO patxname = ""purchase_land_permitted.construction.purchase_land_permitted"" +[SDT_BOOL] +base = GameSettings +var = construction.build_object_area_permitted +def = true +str = STR_CONFIG_SETTING_BUILD_OBJECT_PERMITTED +strhelp = STR_CONFIG_SETTING_BUILD_OBJECT_PERMITTED_HELPTEXT +patxname = ""build_object_area_permitted.construction.build_object_area_permitted"" + [SDT_BOOL] base = GameSettings var = station.adjacent_stations diff --git a/src/viewport_type.h b/src/viewport_type.h index afe78878c7..882bc8e962 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -177,6 +177,7 @@ enum ViewportDragDropSelectionProcess { DDSP_MEASURE, ///< Measurement tool DDSP_DRAW_PLANLINE, ///< Draw a line for a plan DDSP_BUY_LAND, ///< Purchase land + DDSP_BUILD_OBJECT, ///< Build object /* Rail specific actions */ DDSP_PLACE_RAIL, ///< Rail placement