1 #ifndef scenario_h
2 #define scenario_h
3 
4 /** @file scenario.h declarations for scenario interface */
5 
6 #include "koord3d.h"
7 #include "../utils/plainstring.h"
8 #include "../script/dynamic_string.h"
9 #include "../dataobj/ribi.h"
10 #include "../convoihandle_t.h"
11 
12 class loadsave_t;
13 class stadt_t;
14 class fabrik_t;
15 class karte_t;
16 class schedule_t;
17 class depot_t;
18 
19 /**
20  * @class scenario_t
21  * Controls scenarios in connection to a simutrans world.
22  *
23  * Scenarios are scripted. In network games, only the server has access to the script,
24  * clients will be sent some results of the script.
25  *
26  * Each instance of karte_t carries a non-NULL pointer to a scenario_t
27  * thus also the need for inactive scenarios.
28  */
29 class scenario_t
30 {
31 private:
32 	/// possible states of scenario
33 	enum scenario_state_t {
34 		INACTIVE = 0,         ///< scenario inactive
35 		SCRIPTED = 7,         ///< scenario active (non-network game or at server)
36 		SCRIPTED_NETWORK = 8  ///< scenario active, network game at client
37 	};
38 
39 	/// state of the current scenario @see scenario_state_t
40 	uint16 what_scenario;
41 
42 	/// the world we are scripting in
43 	karte_t *welt;
44 
45 	/// name of scenario, files are searched in scenario_path/scenario_name/...
46 	/// e.g. my_scenario
47 	plainstring scenario_name;
48 
49 	/// path to scenario directory (relative to env_t::user_dir)
50 	/// e.g. pak/scenario/my_scenario/
51 	plainstring scenario_path;
52 
53 
54 	/**
55 	 * loads scenario file with the given name
56 	 * @param filename name scenario script file (including .nut extension)
57 	 */
58 	bool load_script(const char* filename);
59 
60 	/**
61 	 * loads necessary compatibility scripts
62 	 */
63 	void load_compatibility_script();
64 
65 	/// is set, if an error occurred during loading of savegame
66 	/// e.g. re-starting of scenario failed due to script error
67 	bool rdwr_error;
68 
69 
70 	/// pointer to virtual machine
71 	script_vm_t *script;
72 
73 	/// @{
74 	/// @name Interface to forbid tools in-game
75 	/**
76 	 * Struct to store information about forbidden tools
77 	 *
78 	 * Necessary in network games: there, the list of forbidden tools
79 	 * is transferred to clients. Needed to apply conditions to e.g. way-building
80 	 * tools or to have toolbars reflect allowed tools.
81 	 */
82 	struct forbidden_t {
83 		enum forbid_type { forbid_tool = 1, forbid_tool_rect = 2};
84 		forbid_type type;
85 		uint8 player_nr;
86 		/// id of tool to be forbidden, as set by constructors of classes derived from
87 		/// tool_t, @see simtool.h
88 		uint16 toolnr;
89 		/// waytype of tool, @see waytype_t
90 		sint16 waytype;
91 		koord pos_nw, pos_se;
92 		sint8 hmin, hmax;
93 		/// error message to be displayed if user tries to work with the tool
94 		plainstring error;
95 
96 		/// constructor: forbid tool/etc for a certain player
97 		forbidden_t(forbid_type type_=forbid_tool, uint8 player_nr_=255, uint16 toolnr_=0, sint16 waytype_=invalid_wt) :
typeforbidden_t98 			type(type_), player_nr(player_nr_), toolnr(toolnr_), waytype(waytype_),
99 			pos_nw(koord::invalid), pos_se(koord::invalid), hmin(-128), hmax(127), error() {};
100 
101 		/// constructor: forbid tool for a certain player at certain locations (and heights)
102 		forbidden_t(uint8 player_nr_, uint16 toolnr_, sint16 waytype_, koord nw, koord se, sint8 hmin_=-128, sint8 hmax_=127) :
typeforbidden_t103 			type(forbid_tool_rect), player_nr(player_nr_), toolnr(toolnr_), waytype(waytype_),
104 			pos_nw(nw), pos_se(se), hmin(hmin_), hmax(hmax_), error() {};
105 
106 		// copy constructor
107 		forbidden_t(const forbidden_t&);
108 
109 		/**
110 		 * @returns if this < other, compares: type, playernr, tool, wt
111 		 * DIRTY: (a <= b)  &&  (b <= a)  DOES NOT imply  a == b
112 		 */
113 		bool operator <(const forbidden_t &) const;
114 
115 		bool operator <=(const forbidden_t &other) const { return !(other < *this); }
116 
compareforbidden_t117 		static bool compare(const forbidden_t *a, const forbidden_t *b)
118 		{
119 			return *a < *b;
120 		}
121 
122 		/**
123 		 * compares everything (including coordinates)
124 		 * DIRTY: (a <= b)  &&  (b <= a)  DOES NOT imply  a == b
125 		 */
126 		bool operator ==(const forbidden_t &other) const;
127 
128 		/**
129 		 * templated load/save support
130 		 */
rdwrforbidden_t131 		template<class T> void rdwr(T *file)
132 		{
133 			uint8 t = (uint8)type;
134 			file->rdwr_byte(t);
135 			type= (forbid_type)t;
136 			file->rdwr_byte(player_nr);
137 			file->rdwr_short(toolnr);
138 			file->rdwr_short(waytype);
139 			file->rdwr_short(pos_nw.x); file->rdwr_short(pos_nw.y);
140 			file->rdwr_short(pos_se.x); file->rdwr_short(pos_se.y);
141 			file->rdwr_byte(hmin);
142 			file->rdwr_byte(hmax);
143 			file->rdwr_str(error);
144 		}
145 
146 		void rotate90(const sint16 y_size);
147 
148 	private:
149 		const forbidden_t& operator=(const forbidden_t&);
150 	};
151 
152 	/// list of forbidden tools
153 	vector_tpl<forbidden_t*>forbidden_tools;
154 
155 	/// set to true if rules changed to update toolbars,
156 	/// toolbars will be updated in next call to step()
157 	bool need_toolbar_update;
158 
159 	/**
160 	 * helper function:
161 	 * @param other given record
162 	 * @returns first index i such that
163 	 *          forbidden_tools[i-1] < other <= forbidden_tools[i] <= other
164 	 *          or returns  forbidden_tools.get_count() if no such index is found
165 	 */
166 	uint32 find_first(const forbidden_t &other) const;
167 
168 	/**
169 	 * Helper function:
170 	 * Puts/removes new record into/from forbidden_tools list, checks for identical entries.
171 	 * Only call this method from call_forbid_tool(forbidden_t *,bool)
172 	 * @param test must be pointer to allocated memory, will be invalid after call
173 	 * @param forbid if true puts, if false removes into/from list
174 	 */
175 	void intern_forbid(forbidden_t *test, bool forbid);
176 
177 	/**
178 	 * Helper function: works on forbidden_tools directly (if not in network-mode)
179 	 * or sends information over network (if at server)
180 	 * @param test must be pointer to allocated memory, will be invalid after call
181 	 * @param forbid if true forbids, if false allows the record
182 	 */
183 	void call_forbid_tool(forbidden_t *test, bool forbid);
184 	/// @}
185 
186 	/// bit set if player has won / lost
187 	uint16 won;
188 	uint16 lost;
189 
190 	/// function to update the won / lost bitset
191 	/// called if this information changes for some players
192 	void update_won_lost(uint16 new_won, uint16 new_lost);
193 
194 public:
195 
196 	scenario_t(karte_t *w);
197 	~scenario_t();
198 
199 	/**
200 	 * Initializes scripted scenario
201 	 */
202 	const char* init( const char *scenario_base, const char *scenario_name, karte_t *welt );
203 
204 	/**
205 	 * Load file with translations. Tries to load files in the following order
206 	 * (1) script_addon_path/iso/filename
207 	 * (2) script_addon_path/en/filename
208 	 * (3) script_path/iso/filename
209 	 *
210 	 * Here, iso refers to iso-abbreviation of currently active language
211 	 * @return content of loaded file
212 	 */
213 	plainstring load_language_file(const char* filename);
214 
215 	/// Load/save support
216 	void rdwr(loadsave_t *file);
217 
218 	/// @returns true if loading succeed, false if script failed during loading
rdwr_ok()219 	bool rdwr_ok() const { return !rdwr_error; }
220 
221 	/**
222 	 * Stop scenario
223 	 */
stop()224 	void stop() { what_scenario = INACTIVE; }
225 
226 	/// @return true if a scenario is present
active()227 	bool active() const { return what_scenario != INACTIVE; }
228 
229 	/// @return true if scenario is scripted
is_scripted()230 	bool is_scripted() const { return what_scenario == SCRIPTED  ||  what_scenario == SCRIPTED_NETWORK; }
231 
232 	/**
233 	 * compiles and executes given string
234 	 * @returns error msg (or NULL if succeeded)
235 	 */
236 	const char* eval_string(const char* squirrel_string) const;
237 
238 	/**
239 	 * Get percentage of scenario completion. Does not call script to update this value.
240 	 * On clients: call server for update via dynamic_string logic.
241 	 * Returns percentage of scenario completion.
242 	 * @param player_nr player
243 	 * @returns percentage of scenario completion:
244 	 * if >= 100 then scenario is won
245 	 * if < 0 then scenario is lost
246 	 */
247 	sint32 get_completion(int player_nr);
248 
249 	/**
250 	 * Sets percentage of scenario completion. Used as callback if script call got suspended.
251 	 * @param player_nr player
252 	 * @returns dummy return value
253 	 */
254 	bool set_completion(sint32 player_nr, sint32 percentage);
255 
256 	void rotate90(const sint16 y_size);
257 
258 	/**
259 	 * rotate original coordinates to actual world coordinates
260 	 * uses the methods in script_api
261 	 */
262 	void koord_sq2w(koord &) const;
263 
264 	/**
265 	 * Text to be displayed in the finance info window
266 	 * i.e. short description of scenario
267 	 */
268 	dynamic_string description_text;
269 
270 	/// @{
271 	/// @name Text to be displayed in the scenario info window
272 	dynamic_string info_text;
273 	dynamic_string goal_text;
274 	dynamic_string rule_text;
275 	dynamic_string result_text;
276 	dynamic_string about_text;
277 	dynamic_string debug_text;
278 	/// @}
279 
280 	/**
281 	 * Called to update the scenario texts
282 	 * @see dynamic_string::update
283 	 */
284 	void update_scenario_texts();
285 
286 	/**
287 	 * opens scenario info window at tab @p tab.
288 	 */
289 	bool open_info_win(const char* tab = "result") const;
290 
291 
292 	/**
293 	 * Last error of script
294 	 */
295 	const char* get_error_text();
296 
297 
298 	/**
299 	 * Calls scripted is_scenario_completed. Caches this value in statistics of player_t.
300 	 * Server sends update of won/lost if necessary.
301 	 */
302 	void step();
303 
304 	/**
305 	 * Called upon month change: at 0:00 of the first day of the new month.
306 	 */
307 	void new_month();
308 
309 	/**
310 	 * Called upon new year: at 0:00 January 1st.
311 	 */
312 	void new_year();
313 
314 	/// @{
315 	/// @name Interface to forbid tools in-game
316 	/**
317 	 * Forbid tool
318 	 * @ingroup squirrel-api
319 	 *
320 	 * @param player_nr number of player this rule applies to,
321 	 *                  if this is set to MAX_PLAYER_COUNT then this acts for all players except public player
322 	 * @param tool_id id of tool
323 	 */
324 	void forbid_tool(uint8 player_nr, uint16 tool_id);
325 
326 	/**
327 	 * @ingroup squirrel-api
328 	 * @see forbid_tool
329 	 */
330 	void allow_tool(uint8 player_nr, uint16 tool_id);
331 
332 	/**
333 	 * Forbid tool with certain waytype
334 	 * @ingroup squirrel-api
335 	 *
336 	 * @param player_nr number of player this rule applies to,
337 	 *                  if this is set to MAX_PLAYER_COUNT then this acts for all players except public player
338 	 * @param tool_id id of tool
339 	 * @param wt waytype
340 	 */
341 	void forbid_way_tool(uint8 player_nr, uint16 tool_id, waytype_t wt);
342 
343 	/**
344 	 * @ingroup squirrel-api
345 	 * @see forbid_way_tool
346 	 */
347 	void allow_way_tool(uint8 player_nr, uint16 tool_id, waytype_t wt);
348 
349 	/**
350 	 * Forbid tool with certain waytype within rectangular region on the map
351 	 * @ingroup squirrel-api
352 	 *
353 	 * @param player_nr number of player this rule applies to,
354 	 *                  if this is set to MAX_PLAYER_COUNT then this acts for all players except public player
355 	 * @param tool_id id of tool
356 	 * @param wt waytype
357 	 * @param pos_nw coordinate of north-western corner of rectangle
358 	 * @param pos_se coordinate of south-eastern corner of rectangle
359 	 * @param err error message presented to user when trying to apply this tool
360 	 */
361 	void forbid_way_tool_rect(uint8 player_nr, uint16 tool_id, waytype_t wt, koord pos_nw, koord pos_se, plainstring err);
362 
363 	/**
364 	 * @ingroup squirrel-api
365 	 * @see forbid_way_tool_rect
366 	 */
367 	void allow_way_tool_rect(uint8 player_nr, uint16 tool_id, waytype_t wt, koord pos_nw, koord pos_se);
368 
369 	/**
370 	 * Forbid tool with certain waytype within cubic region on the map.
371 	 * @ingroup squirrel-api
372 	 *
373 	 * @param player_nr number of player this rule applies to,
374 	 *                  if this is set to MAX_PLAYER_COUNT then this acts for all players except public player
375 	 * @param tool_id id of tool
376 	 * @param wt waytype
377 	 * @param pos_nw coordinate of north-western corner of cube
378 	 * @param pos_se coordinate of south-eastern corner of cube
379 	 * @param err error message presented to user when trying to apply this tool
380 	 */
381 	void forbid_way_tool_cube(uint8 player_nr, uint16 tool_id, waytype_t wt, koord3d pos_nw, koord3d pos_se, plainstring err);
382 
383 	/**
384 	 * @ingroup squirrel-api
385 	 * @see forbid_way_tool_cube
386 	 */
387 	void allow_way_tool_cube(uint8 player_nr, uint16 tool_id, waytype_t wt, koord3d pos_nw, koord3d pos_se);
388 
389 	/**
390 	 * Clears all rules.
391 	 * @ingroup squirrel-api
392 	 */
393 	void clear_rules();
394 
395 	/**
396 	 * Checks if player can use this tool at all.
397 	 * Called for instance in karte_t::local_set_tool to change active tool or when filling toolbars.
398 	 * @return true if player can use this tool.
399 	 */
400 	bool is_tool_allowed(const player_t* player, uint16 tool_id, sint16 wt = invalid_wt);
401 
402 	/**
403 	 * Checks if player can use the tool at this position.
404 	 * @return NULL if allowed otherwise error message
405 	 */
406 	const char* is_work_allowed_here(const player_t* player, uint16 tool_id, sint16 wt, koord3d pos);
407 
408 	/**
409 	 * Checks if player can use this schedule.
410 	 *
411 	 * @param player player
412 	 * @param schedule the schedule
413 	 *
414 	 * @return null if allowed, an error message otherwise
415 	 */
416 	const char* is_schedule_allowed(const player_t* player, const schedule_t* schedule);
417 
418 	/**
419 	 * Checks if player can use this convoy.
420 	 * Called when player wants to start convoy at depot.
421 	 *
422 	 * @param player player
423 	 * @param cnv convoy
424 	 * @param depot depot
425 	 *
426 	 * @return null if allowed, an error message otherwise
427 	 */
428 	const char* is_convoy_allowed(const player_t* player, convoihandle_t cnv, depot_t* depot);
429 
430 	/// @return debug dump of forbidden tools
431 	const char* get_forbidden_text();
432 	/// @}
433 
434 	friend class nwc_scenario_t; ///< to access vm, update_won_lost()
435 	friend class nwc_scenario_rules_t; ///< to access forbidden_tool stuff
436 };
437 
438 #endif
439