Fix some daylength issues, possible division by zero in main menu.
[openttd-joker.git] / src / script / api / script_town.cpp
blob9904efb9429c9a69f6128f14ab814bee8b7c9efe
1 /* $Id: script_town.cpp 26270 2014-01-20 22:34:22Z frosch $ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file script_town.cpp Implementation of ScriptTown. */
12 #include "../../stdafx.h"
13 #include "script_town.hpp"
14 #include "script_map.hpp"
15 #include "script_error.hpp"
16 #include "../../town.h"
17 #include "../../townname_func.h"
18 #include "../../string_func.h"
19 #include "../../strings_func.h"
20 #include "../../station_base.h"
21 #include "../../landscape.h"
22 #include "table/strings.h"
24 #include "../../safeguards.h"
26 /* static */ int32 ScriptTown::GetTownCount()
28 return (int32)::Town::GetNumItems();
31 /* static */ bool ScriptTown::IsValidTown(TownID town_id)
33 return ::Town::IsValidID(town_id);
36 /* static */ char *ScriptTown::GetName(TownID town_id)
38 if (!IsValidTown(town_id)) return NULL;
40 ::SetDParam(0, town_id);
41 return GetString(STR_TOWN_NAME);
44 /* static */ bool ScriptTown::SetName(TownID town_id, Text *name)
46 CCountedPtr<Text> counter(name);
48 const char *text = NULL;
49 if (name != NULL) {
50 text = name->GetDecodedText();
51 EnforcePreconditionEncodedText(false, text);
52 EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
54 EnforcePrecondition(false, IsValidTown(town_id));
56 return ScriptObject::DoCommand(0, town_id, 0, CMD_RENAME_TOWN, text);
59 /* static */ bool ScriptTown::SetText(TownID town_id, Text *text)
61 CCountedPtr<Text> counter(text);
63 EnforcePrecondition(false, text != NULL);
64 const char *encoded_text = text->GetEncodedText();
65 EnforcePreconditionEncodedText(false, encoded_text);
66 EnforcePrecondition(false, IsValidTown(town_id));
68 return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, 0, CMD_TOWN_SET_TEXT, encoded_text);
71 /* static */ int32 ScriptTown::GetPopulation(TownID town_id)
73 if (!IsValidTown(town_id)) return -1;
74 const Town *t = ::Town::Get(town_id);
75 return t->cache.population;
78 /* static */ int32 ScriptTown::GetHouseCount(TownID town_id)
80 if (!IsValidTown(town_id)) return -1;
81 const Town *t = ::Town::Get(town_id);
82 return t->cache.num_houses;
85 /* static */ TileIndex ScriptTown::GetLocation(TownID town_id)
87 if (!IsValidTown(town_id)) return INVALID_TILE;
88 const Town *t = ::Town::Get(town_id);
89 return t->xy;
92 /* static */ int32 ScriptTown::GetLastMonthProduction(TownID town_id, CargoID cargo_id)
94 if (!IsValidTown(town_id)) return -1;
95 if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
97 const Town *t = ::Town::Get(town_id);
99 return t->supplied[cargo_id].old_max;
102 /* static */ int32 ScriptTown::GetLastMonthSupplied(TownID town_id, CargoID cargo_id)
104 if (!IsValidTown(town_id)) return -1;
105 if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
107 const Town *t = ::Town::Get(town_id);
109 return t->supplied[cargo_id].old_act;
112 /* static */ int32 ScriptTown::GetLastMonthTransportedPercentage(TownID town_id, CargoID cargo_id)
114 if (!IsValidTown(town_id)) return -1;
115 if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
117 const Town *t = ::Town::Get(town_id);
118 return ::ToPercent8(t->GetPercentTransported(cargo_id));
121 /* static */ int32 ScriptTown::GetLastMonthReceived(TownID town_id, ScriptCargo::TownEffect towneffect_id)
123 if (!IsValidTown(town_id)) return -1;
124 if (!ScriptCargo::IsValidTownEffect(towneffect_id)) return -1;
126 const Town *t = ::Town::Get(town_id);
128 return t->received[towneffect_id].old_act;
131 /* static */ bool ScriptTown::SetCargoGoal(TownID town_id, ScriptCargo::TownEffect towneffect_id, uint32 goal)
133 EnforcePrecondition(false, IsValidTown(town_id));
134 EnforcePrecondition(false, ScriptCargo::IsValidTownEffect(towneffect_id));
136 return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id | (towneffect_id << 16), goal, CMD_TOWN_CARGO_GOAL);
139 /* static */ uint32 ScriptTown::GetCargoGoal(TownID town_id, ScriptCargo::TownEffect towneffect_id)
141 if (!IsValidTown(town_id)) return UINT32_MAX;
142 if (!ScriptCargo::IsValidTownEffect(towneffect_id)) return UINT32_MAX;
144 const Town *t = ::Town::Get(town_id);
146 switch (t->goal[towneffect_id]) {
147 case TOWN_GROWTH_WINTER:
148 if (TileHeight(t->xy) >= GetSnowLine() && t->cache.population > 90) return 1;
149 return 0;
151 case TOWN_GROWTH_DESERT:
152 if (GetTropicZone(t->xy) == TROPICZONE_DESERT && t->cache.population > 60) return 1;
153 return 0;
155 default: return t->goal[towneffect_id];
159 /* static */ bool ScriptTown::SetGrowthRate(TownID town_id, uint32 days_between_town_growth)
161 EnforcePrecondition(false, IsValidTown(town_id));
163 switch (days_between_town_growth) {
164 case TOWN_GROWTH_NORMAL:
165 days_between_town_growth = 0;
166 break;
168 case TOWN_GROWTH_NONE:
169 days_between_town_growth = TOWN_GROW_RATE_CUSTOM_NONE;
170 break;
172 default:
173 days_between_town_growth = days_between_town_growth * DAY_TICKS / TOWN_GROWTH_TICKS;
174 EnforcePrecondition(false, days_between_town_growth < TOWN_GROW_RATE_CUSTOM);
175 if (days_between_town_growth == 0) days_between_town_growth = 1; // as fast as possible
176 break;
179 return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, days_between_town_growth, CMD_TOWN_GROWTH_RATE);
182 /* static */ int32 ScriptTown::GetGrowthRate(TownID town_id)
184 if (!IsValidTown(town_id)) return -1;
186 const Town *t = ::Town::Get(town_id);
188 if (t->growth_rate == TOWN_GROW_RATE_CUSTOM_NONE) return TOWN_GROWTH_NONE;
190 return ((t->growth_rate & ~TOWN_GROW_RATE_CUSTOM) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS;
193 /* static */ int32 ScriptTown::GetDistanceManhattanToTile(TownID town_id, TileIndex tile)
195 return ScriptMap::DistanceManhattan(tile, GetLocation(town_id));
198 /* static */ int32 ScriptTown::GetDistanceSquareToTile(TownID town_id, TileIndex tile)
200 return ScriptMap::DistanceSquare(tile, GetLocation(town_id));
203 /* static */ bool ScriptTown::IsWithinTownInfluence(TownID town_id, TileIndex tile)
205 if (!IsValidTown(town_id)) return false;
207 const Town *t = ::Town::Get(town_id);
208 return ((uint32)GetDistanceSquareToTile(town_id, tile) <= t->cache.squared_town_zone_radius[0]);
211 /* static */ bool ScriptTown::HasStatue(TownID town_id)
213 if (ScriptObject::GetCompany() == OWNER_DEITY) return false;
214 if (!IsValidTown(town_id)) return false;
216 return ::HasBit(::Town::Get(town_id)->statues, ScriptObject::GetCompany());
219 /* static */ bool ScriptTown::IsCity(TownID town_id)
221 if (!IsValidTown(town_id)) return false;
223 return ::Town::Get(town_id)->larger_town;
226 /* static */ int ScriptTown::GetRoadReworkDuration(TownID town_id)
228 if (!IsValidTown(town_id)) return -1;
230 return ::Town::Get(town_id)->road_build_months;
233 /* static */ int ScriptTown::GetFundBuildingsDuration(TownID town_id)
235 if (!IsValidTown(town_id)) return -1;
237 return ::Town::Get(town_id)->fund_buildings_months;
240 /* static */ ScriptCompany::CompanyID ScriptTown::GetExclusiveRightsCompany(TownID town_id)
242 if (ScriptObject::GetCompany() == OWNER_DEITY) return ScriptCompany::COMPANY_INVALID;
243 if (!IsValidTown(town_id)) return ScriptCompany::COMPANY_INVALID;
245 return (ScriptCompany::CompanyID)(int8)::Town::Get(town_id)->exclusivity;
248 /* static */ int32 ScriptTown::GetExclusiveRightsDuration(TownID town_id)
250 if (!IsValidTown(town_id)) return -1;
252 return ::Town::Get(town_id)->exclusive_counter;
255 /* static */ bool ScriptTown::IsActionAvailable(TownID town_id, TownAction town_action)
257 if (ScriptObject::GetCompany() == OWNER_DEITY) return false;
258 if (!IsValidTown(town_id)) return false;
260 return HasBit(::GetMaskOfTownActions(NULL, ScriptObject::GetCompany(), ::Town::Get(town_id)), town_action);
263 /* static */ bool ScriptTown::PerformTownAction(TownID town_id, TownAction town_action)
265 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
266 EnforcePrecondition(false, IsValidTown(town_id));
267 EnforcePrecondition(false, IsActionAvailable(town_id, town_action));
269 return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, town_action, CMD_DO_TOWN_ACTION);
272 /* static */ bool ScriptTown::ExpandTown(TownID town_id, int houses)
274 EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
275 EnforcePrecondition(false, IsValidTown(town_id));
276 EnforcePrecondition(false, houses > 0);
278 return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, houses, CMD_EXPAND_TOWN);
281 /* static */ bool ScriptTown::FoundTown(TileIndex tile, TownSize size, bool city, RoadLayout layout, Text *name)
283 CCountedPtr<Text> counter(name);
285 EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY || _settings_game.economy.found_town != TF_FORBIDDEN);
286 EnforcePrecondition(false, ::IsValidTile(tile));
287 EnforcePrecondition(false, size == TOWN_SIZE_SMALL || size == TOWN_SIZE_MEDIUM || size == TOWN_SIZE_LARGE)
288 EnforcePrecondition(false, size != TOWN_SIZE_LARGE || ScriptObject::GetCompany() == OWNER_DEITY);
289 if (ScriptObject::GetCompany() == OWNER_DEITY || _settings_game.economy.found_town == TF_CUSTOM_LAYOUT) {
290 EnforcePrecondition(false, layout == ROAD_LAYOUT_ORIGINAL || layout == ROAD_LAYOUT_BETTER_ROADS || layout == ROAD_LAYOUT_2x2 || layout == ROAD_LAYOUT_3x3);
291 } else {
292 /* The layout parameter is ignored for AIs when custom layouts is disabled. */
293 layout = (RoadLayout) (byte)_settings_game.economy.town_layout;
296 const char *text = NULL;
297 if (name != NULL) {
298 text = name->GetDecodedText();
299 EnforcePreconditionEncodedText(false, text);
300 EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
302 uint32 townnameparts;
303 if (!GenerateTownName(&townnameparts)) {
304 ScriptObject::SetLastError(ScriptError::ERR_NAME_IS_NOT_UNIQUE);
305 return false;
308 return ScriptObject::DoCommand(tile, size | (city ? 1 << 2 : 0) | layout << 3, townnameparts, CMD_FOUND_TOWN, text);
311 /* static */ ScriptTown::TownRating ScriptTown::GetRating(TownID town_id, ScriptCompany::CompanyID company_id)
313 if (!IsValidTown(town_id)) return TOWN_RATING_INVALID;
314 ScriptCompany::CompanyID company = ScriptCompany::ResolveCompanyID(company_id);
315 if (company == ScriptCompany::COMPANY_INVALID) return TOWN_RATING_INVALID;
317 const Town *t = ::Town::Get(town_id);
318 if (!HasBit(t->have_ratings, company)) {
319 return TOWN_RATING_NONE;
320 } else if (t->ratings[company] <= RATING_APPALLING) {
321 return TOWN_RATING_APPALLING;
322 } else if (t->ratings[company] <= RATING_VERYPOOR) {
323 return TOWN_RATING_VERY_POOR;
324 } else if (t->ratings[company] <= RATING_POOR) {
325 return TOWN_RATING_POOR;
326 } else if (t->ratings[company] <= RATING_MEDIOCRE) {
327 return TOWN_RATING_MEDIOCRE;
328 } else if (t->ratings[company] <= RATING_GOOD) {
329 return TOWN_RATING_GOOD;
330 } else if (t->ratings[company] <= RATING_VERYGOOD) {
331 return TOWN_RATING_VERY_GOOD;
332 } else if (t->ratings[company] <= RATING_EXCELLENT) {
333 return TOWN_RATING_EXCELLENT;
334 } else {
335 return TOWN_RATING_OUTSTANDING;
339 /* static */ int ScriptTown::GetAllowedNoise(TownID town_id)
341 if (!IsValidTown(town_id)) return -1;
343 const Town *t = ::Town::Get(town_id);
344 if (_settings_game.economy.station_noise_level) {
345 return t->MaxTownNoise() - t->noise_reached;
348 int num = 0;
349 const Station *st;
350 FOR_ALL_STATIONS(st) {
351 if (st->town == t && (st->facilities & FACIL_AIRPORT) && st->airport.type != AT_OILRIG) num++;
353 return max(0, 2 - num);
356 /* static */ ScriptTown::RoadLayout ScriptTown::GetRoadLayout(TownID town_id)
358 if (!IsValidTown(town_id)) return ROAD_LAYOUT_INVALID;
360 return (ScriptTown::RoadLayout)((TownLayout)::Town::Get(town_id)->layout);