Changeset - r26438:10f21bbdb775
[Not reviewed]
master
0 10 0
Tyler Trahan - 3 years ago 2022-02-03 00:24:52
tyler@tylertrahan.com
Feature: Build objects by area
10 files changed with 137 insertions and 14 deletions:
0 comments (0 inline, 0 general)
src/command_type.h
Show inline comments
 
@@ -186,6 +186,7 @@ enum Commands : uint16 {
 
	CMD_REMOVE_SIGNALS,               ///< remove a signal
 
	CMD_TERRAFORM_LAND,               ///< terraform a tile
 
	CMD_BUILD_OBJECT,                 ///< build an object
 
	CMD_BUILD_OBJECT_AREA,            ///< build an area of objects
 
	CMD_BUILD_TUNNEL,                 ///< build a tunnel
 

	
 
	CMD_REMOVE_FROM_RAIL_STATION,     ///< remove a (rectangle of) tiles from a rail station
src/company_base.h
Show inline comments
 
@@ -87,6 +87,7 @@ struct CompanyProperties {
 
	uint32 terraform_limit;          ///< Amount of tileheights we can (still) terraform (times 65536).
 
	uint32 clear_limit;              ///< Amount of tiles we can (still) clear (times 65536).
 
	uint32 tree_limit;               ///< Amount of trees we can (still) plant (times 65536).
 
	uint32 build_object_limit;       ///< Amount of tiles we can (still) build objects on (times 65536).
 

	
 
	/**
 
	 * If \c true, the company is (also) controlled by the computer (a NoAI program).
 
@@ -110,7 +111,7 @@ struct CompanyProperties {
 
		  face(0), money(0), money_fraction(0), current_loan(0), colour(0), block_preview(0),
 
		  location_of_HQ(0), last_build_coordinate(0), share_owners(), inaugurated_year(0),
 
		  months_of_bankruptcy(0), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0),
 
		  terraform_limit(0), clear_limit(0), tree_limit(0), is_ai(false), engine_renew_list(nullptr) {}
 
		  terraform_limit(0), clear_limit(0), tree_limit(0), build_object_limit(0), is_ai(false), engine_renew_list(nullptr) {}
 
};
 

	
 
struct Company : CompanyProperties, CompanyPool::PoolItem<&_company_pool> {
src/company_cmd.cpp
Show inline comments
 
@@ -63,9 +63,10 @@ Company::Company(uint16 name_1, bool is_
 
	this->name_1 = name_1;
 
	this->location_of_HQ = INVALID_TILE;
 
	this->is_ai = is_ai;
 
	this->terraform_limit = (uint32)_settings_game.construction.terraform_frame_burst << 16;
 
	this->clear_limit     = (uint32)_settings_game.construction.clear_frame_burst << 16;
 
	this->tree_limit      = (uint32)_settings_game.construction.tree_frame_burst << 16;
 
	this->terraform_limit    = (uint32)_settings_game.construction.terraform_frame_burst << 16;
 
	this->clear_limit        = (uint32)_settings_game.construction.clear_frame_burst << 16;
 
	this->tree_limit         = (uint32)_settings_game.construction.tree_frame_burst << 16;
 
	this->build_object_limit = (uint32)_settings_game.construction.build_object_frame_burst << 16;
 

	
 
	std::fill(this->share_owners.begin(), this->share_owners.end(), INVALID_OWNER);
 
	InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, INVALID_COMPANY);
 
@@ -267,9 +268,10 @@ void SubtractMoneyFromCompanyFract(Compa
 
void UpdateLandscapingLimits()
 
{
 
	for (Company *c : Company::Iterate()) {
 
		c->terraform_limit = std::min<uint64>((uint64)c->terraform_limit + _settings_game.construction.terraform_per_64k_frames, (uint64)_settings_game.construction.terraform_frame_burst << 16);
 
		c->clear_limit     = std::min<uint64>((uint64)c->clear_limit     + _settings_game.construction.clear_per_64k_frames,     (uint64)_settings_game.construction.clear_frame_burst << 16);
 
		c->tree_limit      = std::min<uint64>((uint64)c->tree_limit      + _settings_game.construction.tree_per_64k_frames,      (uint64)_settings_game.construction.tree_frame_burst << 16);
 
		c->terraform_limit    = std::min<uint64>((uint64)c->terraform_limit    + _settings_game.construction.terraform_per_64k_frames,    (uint64)_settings_game.construction.terraform_frame_burst << 16);
 
		c->clear_limit        = std::min<uint64>((uint64)c->clear_limit        + _settings_game.construction.clear_per_64k_frames,        (uint64)_settings_game.construction.clear_frame_burst << 16);
 
		c->tree_limit         = std::min<uint64>((uint64)c->tree_limit         + _settings_game.construction.tree_per_64k_frames,         (uint64)_settings_game.construction.tree_frame_burst << 16);
 
		c->build_object_limit = std::min<uint64>((uint64)c->build_object_limit + _settings_game.construction.build_object_per_64k_frames, (uint64)_settings_game.construction.build_object_frame_burst << 16);
 
	}
 
}
 

	
src/lang/english.txt
Show inline comments
 
@@ -378,7 +378,7 @@ STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION  
 
STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION                          :{BLACK}Tramway construction
 
STR_SCENEDIT_TOOLBAR_PLANT_TREES                                :{BLACK}Plant trees. Shift toggles building/showing cost estimate
 
STR_SCENEDIT_TOOLBAR_PLACE_SIGN                                 :{BLACK}Place sign
 
STR_SCENEDIT_TOOLBAR_PLACE_OBJECT                               :{BLACK}Place object. Shift toggles building/showing cost estimate
 
STR_SCENEDIT_TOOLBAR_PLACE_OBJECT                               :{BLACK}Place object. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate
 

	
 
# Scenario editor file menu
 
###length 7
 
@@ -2816,7 +2816,7 @@ STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND   
 

	
 
# Object construction window
 
STR_OBJECT_BUILD_CAPTION                                        :{WHITE}Object Selection
 
STR_OBJECT_BUILD_TOOLTIP                                        :{BLACK}Select object to build. Shift toggles building/showing cost estimate
 
STR_OBJECT_BUILD_TOOLTIP                                        :{BLACK}Select object to build. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate
 
STR_OBJECT_BUILD_CLASS_TOOLTIP                                  :{BLACK}Select class of the object to build
 
STR_OBJECT_BUILD_PREVIEW_TOOLTIP                                :{BLACK}Preview of the object
 
STR_OBJECT_BUILD_SIZE                                           :{BLACK}Size: {GOLD}{NUM} x {NUM} tiles
 
@@ -4925,6 +4925,7 @@ STR_ERROR_OBJECT_IN_THE_WAY             
 
STR_ERROR_COMPANY_HEADQUARTERS_IN                               :{WHITE}... company headquarters in the way
 
STR_ERROR_CAN_T_PURCHASE_THIS_LAND                              :{WHITE}Can't purchase this land area...
 
STR_ERROR_YOU_ALREADY_OWN_IT                                    :{WHITE}... you already own it!
 
STR_ERROR_BUILD_OBJECT_LIMIT_REACHED                            :{WHITE}... object construction limit reached
 

	
 
# Group related errors
 
STR_ERROR_GROUP_CAN_T_CREATE                                    :{WHITE}Can't create group...
src/object_cmd.cpp
Show inline comments
 
@@ -311,6 +311,7 @@ CommandCost CmdBuildObject(DoCommandFlag
 
	}
 

	
 
	int hq_score = 0;
 
	uint build_object_size = 1;
 
	switch (type) {
 
		case OBJECT_TRANSMITTER:
 
		case OBJECT_LIGHTHOUSE:
 
@@ -349,20 +350,85 @@ CommandCost CmdBuildObject(DoCommandFlag
 
			return CMD_ERROR;
 

	
 
		default: // i.e. NewGRF provided.
 
			build_object_size = size_x * size_y;
 
			break;
 
	}
 

	
 
	/* Don't allow building more objects if the company has reached its limit. */
 
	Company *c = Company::GetIfValid(_current_company);
 
	if (c != nullptr && GB(c->build_object_limit, 16, 16) < build_object_size) {
 
		return_cmd_error(STR_ERROR_BUILD_OBJECT_LIMIT_REACHED);
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		BuildObject(type, tile, _current_company == OWNER_DEITY ? OWNER_NONE : _current_company, nullptr, view);
 

	
 
		/* Make sure the HQ starts at the right size. */
 
		if (type == OBJECT_HQ) UpdateCompanyHQ(tile, hq_score);
 

	
 
		/* Subtract the tile from the build limit. */
 
		if (c != nullptr) c->build_object_limit -= build_object_size << 16;
 
	}
 

	
 
	cost.AddCost(ObjectSpec::Get(type)->GetBuildCost() * size_x * size_y);
 
	cost.AddCost(spec->GetBuildCost() * build_object_size);
 
	return cost;
 
}
 

	
 
/**
 
 * Construct multiple objects in an area
 
 * @param flags of operation to conduct
 
 * @param tile end tile of area dragging
 
 * @param start_tile start tile of area dragging
 
 * @param type the object type to build
 
 * @param view the view for the object
 
 * @param diagonal Whether to use the Orthogonal (0) or Diagonal (1) iterator.
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdBuildObjectArea(DoCommandFlag flags, TileIndex tile, TileIndex start_tile, ObjectType type, uint8 view, bool diagonal)
 
{
 
	if (start_tile >= MapSize()) return CMD_ERROR;
 

	
 
	if (type >= NUM_OBJECTS) return CMD_ERROR;
 
	const ObjectSpec *spec = ObjectSpec::Get(type);
 
	if (view >= spec->views) return CMD_ERROR;
 

	
 
	if (spec->size != OBJECT_SIZE_1X1) 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 = diagonal ? (TileIterator *)new DiagonalTileIterator(tile, start_tile) : new OrthogonalTileIterator(tile, start_tile);
 
	for (; *iter != INVALID_TILE; ++(*iter)) {
 
		TileIndex t = *iter;
 
		CommandCost ret = Command<CMD_BUILD_OBJECT>::Do(flags & ~DC_EXEC, t, type, view);
 

	
 
		/* If we've reached the limit, stop building (or testing). */
 
		if (c != nullptr && --limit <= 0) break;
 

	
 
		if (ret.Failed()) {
 
			last_error = ret;
 
			continue;
 
		}
 

	
 
		had_success = true;
 
		if (flags & DC_EXEC) {
 
			money -= ret.GetCost();
 

	
 
			/* If we run out of money, stop building. */
 
			if (ret.GetCost() > 0 && money < 0) break;
 
			Command<CMD_BUILD_OBJECT>::Do(flags, t, type, view);
 
		}
 
		cost.AddCost(ret);
 
	}
 

	
 
	delete iter;
 
	return had_success ? cost : last_error;
 
}
 

	
 
static Foundation GetFoundation_Object(TileIndex tile, Slope tileh);
 

	
src/object_cmd.h
Show inline comments
 
@@ -14,7 +14,9 @@
 
#include "object_type.h"
 

	
 
CommandCost CmdBuildObject(DoCommandFlag flags, TileIndex tile, ObjectType type, uint8 view);
 
CommandCost CmdBuildObjectArea(DoCommandFlag flags, TileIndex tile, TileIndex start_tile, ObjectType type, uint8 view, bool diagonal);
 

	
 
DEF_CMD_TRAIT(CMD_BUILD_OBJECT, CmdBuildObject, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION)
 
DEF_CMD_TRAIT(CMD_BUILD_OBJECT_AREA, CmdBuildObjectArea, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION)
 

	
 
#endif /* OBJECT_CMD_H */
src/object_gui.cpp
Show inline comments
 
@@ -458,7 +458,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);
 
@@ -543,9 +543,38 @@ public:
 

	
 
	void OnPlaceObject(Point pt, TileIndex tile) override
 
	{
 
		ObjectClass *objclass = ObjectClass::Get(_selected_object_class);
 
		Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_BUILD_OBJECT, CcPlaySound_CONSTRUCTION_OTHER,
 
				tile, objclass->GetSpec(_selected_object_index)->Index(), _selected_object_view);
 
		const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
 

	
 
		if (spec->size == OBJECT_SIZE_1X1) {
 
			VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_BUILD_OBJECT);
 
		} else {
 
			Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_BUILD_OBJECT, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), _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) return;
 

	
 
		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);
 
				}
 
				const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
 
				Command<CMD_BUILD_OBJECT_AREA>::Post(STR_ERROR_CAN_T_BUILD_OBJECT, CcPlaySound_CONSTRUCTION_OTHER,
 
					end_tile, start_tile, spec->Index(), _selected_object_view, (_ctrl_pressed ? true : false));
 
				break;
 
		}
 
	}
 

	
 
	void OnPlaceObjectAbort() override
src/settings_type.h
Show inline comments
 
@@ -355,6 +355,8 @@ struct ConstructionSettings {
 
	uint16 clear_frame_burst;                ///< how many tiles may, over a short period, be cleared?
 
	uint32 tree_per_64k_frames;              ///< how many trees may, over a long period, be planted per 65536 frames?
 
	uint16 tree_frame_burst;                 ///< how many trees may, over a short period, be planted?
 
	uint32 build_object_per_64k_frames;      ///< how many tiles may, over a long period, have objects built on them per 65536 frames?
 
	uint16 build_object_frame_burst;         ///< how many tiles may, over a short period, have objects built on them?
 
};
 

	
 
/** Settings related to the AI. */
src/table/settings/world_settings.ini
Show inline comments
 
@@ -415,6 +415,24 @@ max      = 1 << 15
 
interval = 1
 
cat      = SC_EXPERT
 

	
 
[SDT_VAR]
 
var      = construction.build_object_per_64k_frames
 
type     = SLE_UINT32
 
def      = 32 << 16
 
min      = 0
 
max      = 1 << 30
 
interval = 1
 
cat      = SC_EXPERT
 

	
 
[SDT_VAR]
 
var      = construction.build_object_frame_burst
 
type     = SLE_UINT16
 
def      = 2048
 
min      = 0
 
max      = 1 << 15
 
interval = 1
 
cat      = SC_EXPERT
 

	
 
[SDT_BOOL]
 
var      = construction.autoslope
 
from     = SLV_75
src/viewport_type.h
Show inline comments
 
@@ -123,6 +123,7 @@ enum ViewportDragDropSelectionProcess {
 
	DDSP_CREATE_RIVER,         ///< Create rivers
 
	DDSP_PLANT_TREES,          ///< Plant trees
 
	DDSP_BUILD_BRIDGE,         ///< Bridge placement
 
	DDSP_BUILD_OBJECT,         ///< Build an object
 

	
 
	/* Rail specific actions */
 
	DDSP_PLACE_RAIL,           ///< Rail placement
0 comments (0 inline, 0 general)