1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
8 /** @file script_industry.cpp Implementation of ScriptIndustry. */
9 
10 #include "../../stdafx.h"
11 #include "script_industry.hpp"
12 #include "script_cargo.hpp"
13 #include "script_company.hpp"
14 #include "script_error.hpp"
15 #include "script_map.hpp"
16 #include "../../company_base.h"
17 #include "../../industry.h"
18 #include "../../string_func.h"
19 #include "../../strings_func.h"
20 #include "../../station_base.h"
21 #include "../../newgrf_industries.h"
22 #include "table/strings.h"
23 #include <numeric>
24 
25 #include "../../safeguards.h"
26 
GetIndustryCount()27 /* static */ int32 ScriptIndustry::GetIndustryCount()
28 {
29 	return (int32)::Industry::GetNumItems();
30 }
31 
IsValidIndustry(IndustryID industry_id)32 /* static */ bool ScriptIndustry::IsValidIndustry(IndustryID industry_id)
33 {
34 	return ::Industry::IsValidID(industry_id);
35 }
36 
GetIndustryID(TileIndex tile)37 /* static */ IndustryID ScriptIndustry::GetIndustryID(TileIndex tile)
38 {
39 	if (!::IsValidTile(tile) || !::IsTileType(tile, MP_INDUSTRY)) return INVALID_INDUSTRY;
40 	return ::GetIndustryIndex(tile);
41 }
42 
GetName(IndustryID industry_id)43 /* static */ char *ScriptIndustry::GetName(IndustryID industry_id)
44 {
45 	if (!IsValidIndustry(industry_id)) return nullptr;
46 
47 	::SetDParam(0, industry_id);
48 	return GetString(STR_INDUSTRY_NAME);
49 }
50 
SetText(IndustryID industry_id,Text * text)51 /* static */ bool ScriptIndustry::SetText(IndustryID industry_id, Text *text)
52 {
53 	CCountedPtr<Text> counter(text);
54 
55 	const char *encoded_text = nullptr;
56 	if (text != nullptr) {
57 		encoded_text = text->GetEncodedText();
58 		EnforcePreconditionEncodedText(false, encoded_text);
59 	}
60 	EnforcePrecondition(false, IsValidIndustry(industry_id));
61 
62 	return ScriptObject::DoCommand(0, industry_id, static_cast<uint32>(IndustryAction::SetText), CMD_INDUSTRY_CTRL, encoded_text);
63 }
64 
IsCargoAccepted(IndustryID industry_id,CargoID cargo_id)65 /* static */ ScriptIndustry::CargoAcceptState ScriptIndustry::IsCargoAccepted(IndustryID industry_id, CargoID cargo_id)
66 {
67 	if (!IsValidIndustry(industry_id)) return CAS_NOT_ACCEPTED;
68 	if (!ScriptCargo::IsValidCargo(cargo_id)) return CAS_NOT_ACCEPTED;
69 
70 	Industry *i = ::Industry::Get(industry_id);
71 
72 	for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
73 		if (i->accepts_cargo[j] == cargo_id) {
74 			if (IndustryTemporarilyRefusesCargo(i, cargo_id)) return CAS_TEMP_REFUSED;
75 			return CAS_ACCEPTED;
76 		}
77 	}
78 
79 	return CAS_NOT_ACCEPTED;
80 }
81 
GetStockpiledCargo(IndustryID industry_id,CargoID cargo_id)82 /* static */ int32 ScriptIndustry::GetStockpiledCargo(IndustryID industry_id, CargoID cargo_id)
83 {
84 	if (!IsValidIndustry(industry_id)) return -1;
85 	if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
86 
87 	Industry *ind = ::Industry::Get(industry_id);
88 	for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
89 		CargoID cid = ind->accepts_cargo[i];
90 		if (cid == cargo_id) {
91 			return ind->incoming_cargo_waiting[i];
92 		}
93 	}
94 
95 	return -1;
96 }
97 
GetLastMonthProduction(IndustryID industry_id,CargoID cargo_id)98 /* static */ int32 ScriptIndustry::GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id)
99 {
100 	if (!IsValidIndustry(industry_id)) return -1;
101 	if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
102 
103 	const Industry *i = ::Industry::Get(industry_id);
104 
105 	for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
106 		if (i->produced_cargo[j] == cargo_id) return i->last_month_production[j];
107 	}
108 
109 	return -1;
110 }
111 
GetLastMonthTransported(IndustryID industry_id,CargoID cargo_id)112 /* static */ int32 ScriptIndustry::GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id)
113 {
114 	if (!IsValidIndustry(industry_id)) return -1;
115 	if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
116 
117 	const Industry *i = ::Industry::Get(industry_id);
118 
119 	for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
120 		if (i->produced_cargo[j] == cargo_id) return i->last_month_transported[j];
121 	}
122 
123 	return -1;
124 }
125 
GetLastMonthTransportedPercentage(IndustryID industry_id,CargoID cargo_id)126 /* static */ int32 ScriptIndustry::GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id)
127 {
128 	if (!IsValidIndustry(industry_id)) return -1;
129 	if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
130 
131 	const Industry *i = ::Industry::Get(industry_id);
132 
133 	for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
134 		if (i->produced_cargo[j] == cargo_id) return ::ToPercent8(i->last_month_pct_transported[j]);
135 	}
136 
137 	return -1;
138 }
139 
GetLocation(IndustryID industry_id)140 /* static */ TileIndex ScriptIndustry::GetLocation(IndustryID industry_id)
141 {
142 	if (!IsValidIndustry(industry_id)) return INVALID_TILE;
143 
144 	return ::Industry::Get(industry_id)->location.tile;
145 }
146 
GetAmountOfStationsAround(IndustryID industry_id)147 /* static */ int32 ScriptIndustry::GetAmountOfStationsAround(IndustryID industry_id)
148 {
149 	if (!IsValidIndustry(industry_id)) return -1;
150 
151 	Industry *ind = ::Industry::Get(industry_id);
152 	return (int32)ind->stations_near.size();
153 }
154 
GetDistanceManhattanToTile(IndustryID industry_id,TileIndex tile)155 /* static */ int32 ScriptIndustry::GetDistanceManhattanToTile(IndustryID industry_id, TileIndex tile)
156 {
157 	if (!IsValidIndustry(industry_id)) return -1;
158 
159 	return ScriptMap::DistanceManhattan(tile, GetLocation(industry_id));
160 }
161 
GetDistanceSquareToTile(IndustryID industry_id,TileIndex tile)162 /* static */ int32 ScriptIndustry::GetDistanceSquareToTile(IndustryID industry_id, TileIndex tile)
163 {
164 	if (!IsValidIndustry(industry_id)) return -1;
165 
166 	return ScriptMap::DistanceSquare(tile, GetLocation(industry_id));
167 }
168 
IsBuiltOnWater(IndustryID industry_id)169 /* static */ bool ScriptIndustry::IsBuiltOnWater(IndustryID industry_id)
170 {
171 	if (!IsValidIndustry(industry_id)) return false;
172 
173 	return (::GetIndustrySpec(::Industry::Get(industry_id)->type)->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0;
174 }
175 
HasHeliport(IndustryID industry_id)176 /* static */ bool ScriptIndustry::HasHeliport(IndustryID industry_id)
177 {
178 	if (!IsValidIndustry(industry_id)) return false;
179 
180 	return (::GetIndustrySpec(::Industry::Get(industry_id)->type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0;
181 }
182 
GetHeliportLocation(IndustryID industry_id)183 /* static */ TileIndex ScriptIndustry::GetHeliportLocation(IndustryID industry_id)
184 {
185 	if (!IsValidIndustry(industry_id)) return INVALID_TILE;
186 	if (!HasHeliport(industry_id)) return INVALID_TILE;
187 
188 	const Industry *ind = ::Industry::Get(industry_id);
189 	for (TileIndex tile_cur : ind->location) {
190 		if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
191 			return tile_cur;
192 		}
193 	}
194 
195 	return INVALID_TILE;
196 }
197 
HasDock(IndustryID industry_id)198 /* static */ bool ScriptIndustry::HasDock(IndustryID industry_id)
199 {
200 	if (!IsValidIndustry(industry_id)) return false;
201 
202 	return (::GetIndustrySpec(::Industry::Get(industry_id)->type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0;
203 }
204 
GetDockLocation(IndustryID industry_id)205 /* static */ TileIndex ScriptIndustry::GetDockLocation(IndustryID industry_id)
206 {
207 	if (!IsValidIndustry(industry_id)) return INVALID_TILE;
208 	if (!HasDock(industry_id)) return INVALID_TILE;
209 
210 	const Industry *ind = ::Industry::Get(industry_id);
211 	for (TileIndex tile_cur : ind->location) {
212 		if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
213 			return tile_cur;
214 		}
215 	}
216 
217 	return INVALID_TILE;
218 }
219 
GetIndustryType(IndustryID industry_id)220 /* static */ IndustryType ScriptIndustry::GetIndustryType(IndustryID industry_id)
221 {
222 	if (!IsValidIndustry(industry_id)) return INVALID_INDUSTRYTYPE;
223 
224 	return ::Industry::Get(industry_id)->type;
225 }
226 
GetLastProductionYear(IndustryID industry_id)227 int32 ScriptIndustry::GetLastProductionYear(IndustryID industry_id)
228 {
229 	Industry *i = Industry::GetIfValid(industry_id);
230 	if (i == nullptr) return 0;
231 	return i->last_prod_year;
232 }
233 
GetCargoLastAcceptedDate(IndustryID industry_id,CargoID cargo_type)234 ScriptDate::Date ScriptIndustry::GetCargoLastAcceptedDate(IndustryID industry_id, CargoID cargo_type)
235 {
236 	Industry *i = Industry::GetIfValid(industry_id);
237 	if (i == nullptr) return ScriptDate::DATE_INVALID;
238 
239 	if (cargo_type == CT_INVALID) {
240 		return (ScriptDate::Date)std::accumulate(std::begin(i->last_cargo_accepted_at), std::end(i->last_cargo_accepted_at), 0, [](Date a, Date b) { return std::max(a, b); });
241 	} else {
242 		int index = i->GetCargoAcceptedIndex(cargo_type);
243 		if (index < 0) return ScriptDate::DATE_INVALID;
244 		return (ScriptDate::Date)i->last_cargo_accepted_at[index];
245 	}
246 }
247 
GetControlFlags(IndustryID industry_id)248 uint32 ScriptIndustry::GetControlFlags(IndustryID industry_id)
249 {
250 	Industry *i = Industry::GetIfValid(industry_id);
251 	if (i == nullptr) return 0;
252 	return i->ctlflags;
253 }
254 
SetControlFlags(IndustryID industry_id,uint32 control_flags)255 bool ScriptIndustry::SetControlFlags(IndustryID industry_id, uint32 control_flags)
256 {
257 	if (ScriptObject::GetCompany() != OWNER_DEITY) return false;
258 	if (!IsValidIndustry(industry_id)) return false;
259 
260 	return ScriptObject::DoCommand(0, industry_id, 0 | ((control_flags & ::INDCTL_MASK) << 8), CMD_INDUSTRY_CTRL);
261 }
262 
GetExclusiveSupplier(IndustryID industry_id)263 /* static */ ScriptCompany::CompanyID ScriptIndustry::GetExclusiveSupplier(IndustryID industry_id)
264 {
265 	if (!IsValidIndustry(industry_id)) return ScriptCompany::COMPANY_INVALID;
266 
267 	auto company_id = ::Industry::Get(industry_id)->exclusive_supplier;
268 	if (!::Company::IsValidID(company_id)) return ScriptCompany::COMPANY_INVALID;
269 
270 	return (ScriptCompany::CompanyID)((byte)company_id);
271 }
272 
SetExclusiveSupplier(IndustryID industry_id,ScriptCompany::CompanyID company_id)273 /* static */ bool ScriptIndustry::SetExclusiveSupplier(IndustryID industry_id, ScriptCompany::CompanyID company_id)
274 {
275 	EnforcePrecondition(false, IsValidIndustry(industry_id));
276 
277 	auto company = ScriptCompany::ResolveCompanyID(company_id);
278 	::Owner owner = (company == ScriptCompany::COMPANY_INVALID ? ::INVALID_OWNER : (::Owner)company);
279 	return ScriptObject::DoCommand(0, industry_id, 1 | (((uint8)owner) << 16), CMD_INDUSTRY_CTRL);
280 }
281 
GetExclusiveConsumer(IndustryID industry_id)282 /* static */ ScriptCompany::CompanyID ScriptIndustry::GetExclusiveConsumer(IndustryID industry_id)
283 {
284 	if (!IsValidIndustry(industry_id)) return ScriptCompany::COMPANY_INVALID;
285 
286 	auto company_id = ::Industry::Get(industry_id)->exclusive_consumer;
287 	if (!::Company::IsValidID(company_id)) return ScriptCompany::COMPANY_INVALID;
288 
289 	return (ScriptCompany::CompanyID)((byte)company_id);
290 }
291 
SetExclusiveConsumer(IndustryID industry_id,ScriptCompany::CompanyID company_id)292 /* static */ bool ScriptIndustry::SetExclusiveConsumer(IndustryID industry_id, ScriptCompany::CompanyID company_id)
293 {
294 	EnforcePrecondition(false, IsValidIndustry(industry_id));
295 
296 	auto company = ScriptCompany::ResolveCompanyID(company_id);
297 	::Owner owner = (company == ScriptCompany::COMPANY_INVALID ? ::INVALID_OWNER : (::Owner)company);
298 	return ScriptObject::DoCommand(0, industry_id, 2 | (((uint8)owner) << 16), CMD_INDUSTRY_CTRL);
299 }
300