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_error.hpp Everything to query errors. */
9 
10 #ifndef SCRIPT_ERROR_HPP
11 #define SCRIPT_ERROR_HPP
12 
13 #include "script_object.hpp"
14 #include <map>
15 
16 /**
17  * Helper to write precondition enforcers for the script API in an abbreviated manner.
18  * @param returnval The value to return on failure.
19  * @param condition The condition that must be obeyed.
20  */
21 #define EnforcePrecondition(returnval, condition)               \
22 	if (!(condition)) {                                           \
23 		ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED);   \
24 		return returnval;                                           \
25 	}
26 
27 /**
28  * Helper to write precondition enforcers for the script API in an abbreviated manner.
29  * @param returnval The value to return on failure.
30  * @param condition The condition that must be obeyed.
31  * @param error_code The error code passed to ScriptObject::SetLastError.
32  */
33 #define EnforcePreconditionCustomError(returnval, condition, error_code)   \
34 	if (!(condition)) {                                                      \
35 		ScriptObject::SetLastError(error_code);                                    \
36 		return returnval;                                                      \
37 	}
38 
39 /**
40  * Helper to write precondition enforcers for the script API in an abbreviated manner for encoded texts.
41  * @param returnval The value to return on failure.
42  * @param string The string that is checked.
43  */
44 #define EnforcePreconditionEncodedText(returnval, string)   \
45 	if ((string) == nullptr) { \
46 		ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_TOO_MANY_PARAMETERS); \
47 		return returnval; \
48 	} \
49 	if (StrEmpty(string)) { \
50 		ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED); \
51 		return returnval; \
52 	}
53 
54 /**
55  * Class that handles all error related functions.
56  * @api ai game
57  */
58 class ScriptError : public ScriptObject {
59 public:
60 	/**
61 	 * All categories errors can be divided in.
62 	 */
63 	enum ErrorCategories {
64 		ERR_CAT_NONE = 0, ///< Error messages not related to any category.
65 		ERR_CAT_GENERAL,  ///< Error messages related to general things.
66 		ERR_CAT_VEHICLE,  ///< Error messages related to building / maintaining vehicles.
67 		ERR_CAT_STATION,  ///< Error messages related to building / maintaining stations.
68 		ERR_CAT_BRIDGE,   ///< Error messages related to building / removing bridges.
69 		ERR_CAT_TUNNEL,   ///< Error messages related to building / removing tunnels.
70 		ERR_CAT_TILE,     ///< Error messages related to raising / lowering and demolishing tiles.
71 		ERR_CAT_SIGN,     ///< Error messages related to building / removing signs.
72 		ERR_CAT_RAIL,     ///< Error messages related to building / maintaining rails.
73 		ERR_CAT_ROAD,     ///< Error messages related to building / maintaining roads.
74 		ERR_CAT_ORDER,    ///< Error messages related to managing orders.
75 		ERR_CAT_MARINE,   ///< Error messages related to building / removing ships, docks and channels.
76 		ERR_CAT_WAYPOINT, ///< Error messages related to building / maintaining waypoints.
77 
78 		/**
79 		 * DO NOT USE! The error bitsize determines how many errors can be stored in
80 		 *  a category and what the offsets are of all categories.
81 		 */
82 		ERR_CAT_BIT_SIZE = 8,
83 	};
84 
85 	/**
86 	 * All general related error messages.
87 	 */
88 	enum ErrorMessages {
89 		/** Initial error value */
90 		ERR_NONE = ERR_CAT_NONE << ERR_CAT_BIT_SIZE,  // []
91 		/** If an error occurred and the error wasn't mapped */
92 		ERR_UNKNOWN,                                  // []
93 		/** If a precondition is not met */
94 		ERR_PRECONDITION_FAILED,                      // []
95 		/** A string supplied was too long */
96 		ERR_PRECONDITION_STRING_TOO_LONG,             // []
97 		/** A string had too many parameters */
98 		ERR_PRECONDITION_TOO_MANY_PARAMETERS,         // []
99 		/** The company you use is invalid */
100 		ERR_PRECONDITION_INVALID_COMPANY,             // []
101 		/** An error returned by a NewGRF. No possibility to get the exact error in an script readable format */
102 		ERR_NEWGRF_SUPPLIED_ERROR,                    // []
103 
104 		/** Base for general errors */
105 		ERR_GENERAL_BASE = ERR_CAT_GENERAL << ERR_CAT_BIT_SIZE,
106 
107 		/** Not enough cash to perform the previous action */
108 		ERR_NOT_ENOUGH_CASH,                          // [STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY]
109 
110 		/** Local authority won't allow the previous action */
111 		ERR_LOCAL_AUTHORITY_REFUSES,                  // [STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE]
112 
113 		/** The piece of infrastructure you tried to build is already in place */
114 		ERR_ALREADY_BUILT,                            // [STR_ERROR_ALREADY_BUILT, STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, STR_ERROR_TREE_ALREADY_HERE]
115 
116 		/** Area isn't clear, try to demolish the building on it */
117 		ERR_AREA_NOT_CLEAR,                           // [STR_ERROR_BUILDING_MUST_BE_DEMOLISHED, STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, STR_ERROR_MUST_DEMOLISH_RAILROAD, STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST, STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST, STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST, STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST, STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST, STR_ERROR_BUOY_IN_THE_WAY, STR_ERROR_MUST_DEMOLISH_DOCK_FIRST, STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, STR_ERROR_COMPANY_HEADQUARTERS_IN, STR_ERROR_OBJECT_IN_THE_WAY, STR_ERROR_MUST_REMOVE_ROAD_FIRST, STR_ERROR_MUST_REMOVE_RAILROAD_TRACK, STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST, STR_ERROR_EXCAVATION_WOULD_DAMAGE]
118 
119 		/** Area / property is owned by another company */
120 		ERR_OWNED_BY_ANOTHER_COMPANY,                 // [STR_ERROR_AREA_IS_OWNED_BY_ANOTHER, STR_ERROR_OWNED_BY]
121 
122 		/** The name given is not unique for the object type */
123 		ERR_NAME_IS_NOT_UNIQUE,                       // [STR_ERROR_NAME_MUST_BE_UNIQUE]
124 
125 		/** The building you want to build requires flat land */
126 		ERR_FLAT_LAND_REQUIRED,                       // [STR_ERROR_FLAT_LAND_REQUIRED]
127 
128 		/** Land is sloped in the wrong direction for this build action */
129 		ERR_LAND_SLOPED_WRONG,                        // [STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION]
130 
131 		/** A vehicle is in the way */
132 		ERR_VEHICLE_IN_THE_WAY,                       // [STR_ERROR_TRAIN_IN_THE_WAY, STR_ERROR_ROAD_VEHICLE_IN_THE_WAY, STR_ERROR_SHIP_IN_THE_WAY, STR_ERROR_AIRCRAFT_IN_THE_WAY]
133 
134 		/** Site is unsuitable */
135 		ERR_SITE_UNSUITABLE,                          // [STR_ERROR_SITE_UNSUITABLE, STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE]
136 
137 		/** Too close to the edge of the map */
138 		ERR_TOO_CLOSE_TO_EDGE,                        // [STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP]
139 
140 		/** Station is too spread out */
141 		ERR_STATION_TOO_SPREAD_OUT,                   // [STR_ERROR_STATION_TOO_SPREAD_OUT]
142 	};
143 
144 	/**
145 	 * Check the membership of the last thrown error.
146 	 * @return The category the error belongs to.
147 	 * @note The last throw error can be acquired by calling GetLastError().
148 	 */
149 	static ErrorCategories GetErrorCategory();
150 
151 	/**
152 	 * Get the last error.
153 	 * @return An ErrorMessages enum value.
154 	 */
155 	static ScriptErrorType GetLastError();
156 
157 	/**
158 	 * Get the last error in string format (for human readability).
159 	 * @return An ErrorMessage enum item, as string.
160 	 */
161 	static char *GetLastErrorString();
162 
163 	/**
164 	 * Get the error based on the OpenTTD StringID.
165 	 * @api -all
166 	 * @param internal_string_id The string to convert.
167 	 * @return The script equivalent error message.
168 	 */
169 	static ScriptErrorType StringToError(StringID internal_string_id);
170 
171 	/**
172 	 * Map an internal OpenTTD error message to its script equivalent.
173 	 * @api -all
174 	 * @param internal_string_id The OpenTTD StringID used for an error.
175 	 * @param ai_error_msg The script equivalent error message.
176 	 */
177 	static void RegisterErrorMap(StringID internal_string_id, ScriptErrorType ai_error_msg);
178 
179 	/**
180 	 * Map an internal OpenTTD error message to its script equivalent.
181 	 * @api -all
182 	 * @param ai_error_msg The script error message representation.
183 	 * @param message The string representation of this error message, used for debug purposes.
184 	 */
185 	static void RegisterErrorMapString(ScriptErrorType ai_error_msg, const char *message);
186 
187 private:
188 	typedef std::map<StringID, ScriptErrorType> ScriptErrorMap;           ///< The type for mapping between error (internal OpenTTD) StringID to the script error type.
189 	typedef std::map<ScriptErrorType, const char *> ScriptErrorMapString; ///< The type for mapping between error type and textual representation.
190 
191 	static ScriptErrorMap error_map;              ///< The mapping between error (internal OpenTTD) StringID to the script error type.
192 	static ScriptErrorMapString error_map_string; ///< The mapping between error type and textual representation.
193 };
194 
195 #endif /* SCRIPT_ERROR_HPP */
196