1 #ifndef _API_PARAM_H_
2 #define _API_PARAM_H_
3 
4 /** @file api_param.h templates for transfer of function call parameters */
5 
6 #include "../squirrel/squirrel.h"
7 #include "../simobj.h"
8 #include "../simtypes.h"
9 #include "../tpl/quickstone_tpl.h"
10 #include "../utils/cbuffer_t.h"
11 
12 class baum_t;
13 class convoi_t;
14 class fabrik_t;
15 class factory_supplier_desc_t;
16 class factory_product_desc_t;
17 class gebaeude_t;
18 class grund_t;
19 class haltestelle_t;
20 class karte_t;
21 class karte_ptr_t;
22 class koord;
23 class koord3d;
24 class label_t;
25 class loadsave_t;
26 struct schedule_entry_t;
27 struct my_ribi_t;
28 struct my_slope_t;
29 class planquadrat_t;
30 class plainstring;
31 class scenario_t;
32 class schedule_t;
33 class settings_t;
34 class simline_t;
35 class player_t;
36 class stadt_t;
37 class tool_t;
38 class ware_production_t;
39 class weg_t;
40 class way_builder_t;
41 
42 /**
43  * @namespace script_api The namespace contains all functions necessary to communicate
44  * between simutrans and squirrel: transfer parameters, export classes and functions.
45  *
46  * @brief API simutrans <-> squirrel
47  */
48 namespace script_api {
49 	/// pointer to the world
50 	extern karte_ptr_t welt;
51 
52 	// forward declaration
53 	struct mytime_t;
54 	struct mytime_ticks_t;
55 
56 	/**
57 	 * Cannot specialize templates by void, so use own void type
58 	 */
59 	struct void_t {};
60 
61 	/**
62 	 * Templated interface to transfer variables from / to squirrel.
63 	 */
64 	template<class T> struct param {
65 		/**
66 		 * Gets parameters for calls to c++ functions from stack.
67 		 * @param index on stack
68 		 * @return value of parameter
69 		 */
70 #ifdef DOXYGEN
71 		static T get(HSQUIRRELVM vm, SQInteger index);
72 #endif
73 
74 		/**
75 		 * Pushes parameters for calls to squirrel functions on stack.
76 		 * @return positive value for success, negative for failure
77 		 */
78 #ifdef DOXYGEN
79 		static SQInteger push(HSQUIRRELVM vm, T const& v);
80 #endif
81 		/// typemask: this squirrel type needs to be provided when calling c++ function
typemaskparam82 		static const char* typemask() { return "."; }
83 
84 		/// squirrel_type corresponding to the c++ type/class
squirrel_typeparam85 		static const char* squirrel_type() { return "any_x"; }
86 	};
87 
88 	/**
89 	 * Create slots in table/class on the stack:
90 	 * it has the same effect as 'table.name <- value'.
91 	 * @tparam type of the new value
92 	 * @param name name of the slot to be created
93 	 * @param value value to be set
94 	 * @param static_ true if this should be a static class member
95 	 * @param index of table/instance/etc on the stack
96 	 * @returns positive value on success, negative on failure
97 	 */
98 	template<class T>
99 	SQInteger create_slot(HSQUIRRELVM vm, const char* name, T const& value, bool static_ = false, SQInteger index = -1)
100 	{
101 		sq_pushstring(vm, name, -1);
102 		if (SQ_SUCCEEDED(param<T>::push(vm, value))) {
103 			SQInteger new_index = index > 0 ? index : index-2;
104 			return sq_newslot(vm, new_index, static_);
105 		}
106 		else {
107 			sq_pop(vm, 1); /* pop name */
108 			return SQ_ERROR;
109 		}
110 	}
111 
112 	/**
113 	 * Sets value to existing variable in table, instance etc at index @p index.
114 	 * @tparam type of the new value
115 	 * @param name name of the slot to be created
116 	 * @param value value to be set
117 	 * @param index of table/instance/etc on the stack
118 	 * @returns positive value on success, negative on failure
119 	 */
120 	template<class T>
121 	SQInteger set_slot(HSQUIRRELVM vm, const char* name, T const& value, SQInteger index = -1)
122 	{
123 		sq_pushstring(vm, name, -1);
124 		if (SQ_SUCCEEDED(param<T>::push(vm, value))) {
125 			SQInteger new_index = index > 0 ? index : index-2;
126 			return sq_set(vm, new_index);
127 		}
128 		else {
129 			sq_pop(vm, 1); /* pop name */
130 			return SQ_ERROR;
131 		}
132 	}
133 
134 	/**
135 	 * Gets value to existing variable in table, instance etc at index @p index.
136 	 * @tparam type of the new value
137 	 * @param name name of the slot to be created
138 	 * @param value will be set upon success
139 	 * @param index of table/instance/etc on the stack
140 	 * @returns positive value on success, negative on failure
141 	 */
142 	template<class T>
143 	SQInteger get_slot(HSQUIRRELVM vm, const char* name, T& value, SQInteger index = -1)
144 	{
145 		sq_pushstring(vm, name, -1);
146 		SQInteger new_index = index > 0 ? index : index-1;
147 		if (SQ_SUCCEEDED(sq_get(vm, new_index))) {
148 			value = param<T>::get(vm, -1);
149 			sq_pop(vm, 1);
150 			return SQ_OK;
151 		}
152 		return SQ_ERROR;
153 	}
154 
155 	/**
156 	 * partial specialization for 'const T*' types
157 	 */
158 	template<class T> struct param<const T*> {
159 		/**
160 		 * Gets parameters for calls to c++ functions from stack.
161 		 * @param index on stack
162 		 * @return value of parameter
163 		 */
164 		static const T* get(HSQUIRRELVM vm, SQInteger index)
165 		{
166 			return param<T*>::get(vm, index);
167 		}
168 		/**
169 		 * Pushes parameters for calls to squirrel functions on stack.
170 		 * @return positive value for success, negative for failure
171 		 */
172 		static SQInteger push(HSQUIRRELVM vm, const T* const& v)
173 		{
174 			return param<T*>::push(vm, v);
175 		}
176 
177 		/// typemask: this squirrel type needs to be provided when calling c++ function
178 		static const char* typemask()
179 		{
180 			return param<T*>::typemask();
181 		}
182 		/// squirrel_type corresponding to the c++ type/class
183 		static const char* squirrel_type()
184 		{
185 			return param<T*>::squirrel_type();
186 		}
187 	};
188 
189 	/**
190 	 * partial specialization for 'const T' types
191 	 */
192 	template<class T> struct param<const T> {
193 		/**
194 		 * Gets parameters for calls to c++ functions from stack.
195 		 * @param index on stack
196 		 * @return value of parameter
197 		 */
198 		static const T get(HSQUIRRELVM vm, SQInteger index)
199 		{
200 			return param<T>::get(vm, index);
201 		}
202 		/**
203 		 * Pushes parameters for calls to squirrel functions on stack.
204 		 * @return positive value for success, negative for failure
205 		 */
206 		static SQInteger push(HSQUIRRELVM vm, T const& v)
207 		{
208 			return param<T>::push(vm, v);
209 		}
210 
211 		/// typemask: this squirrel type needs to be provided when calling c++ function
212 		static const char* typemask()
213 		{
214 			return param<T>::typemask();
215 		}
216 		/// squirrel_type corresponding to the c++ type/class
217 		static const char* squirrel_type()
218 		{
219 			return param<T>::squirrel_type();
220 		}
221 	};
222 
223 	/**
224 	 * partial specialization for 'const T&' types
225 	 */
226 	template<class T> struct param<const T&> {
227 		/**
228 		 * Pushes parameters for calls to squirrel functions on stack.
229 		 * @return positive value for success, negative for failure
230 		 */
231 		static SQInteger push(HSQUIRRELVM vm, const T& v)
232 		{
233 			return param<T>::push(vm, v);
234 		}
235 
236 		/// typemask: this squirrel type needs to be provided when calling c++ function
237 		static const char* typemask()
238 		{
239 			return param<T>::typemask();
240 		}
241 		/// squirrel_type corresponding to the c++ type/class
242 		static const char* squirrel_type()
243 		{
244 			return param<T>::squirrel_type();
245 		}
246 	};
247 
248 	/**
249 	 * partial specialization for container types
250 	 */
251 	template< template<class> class vector, class T> struct param< vector<T> > {
252 		/**
253 		 * Pushes parameters for calls to squirrel functions on stack.
254 		 * @return positive value for success, negative for failure
255 		 */
256 		static SQInteger push(HSQUIRRELVM vm, vector<T> const& v)
257 		{
258 			sq_newarray(vm, 0);
259 
260 			FORT(const vector<T>, const&i, v) {
261 				param<T>::push(vm, i);
262 				sq_arrayappend(vm, -2);
263 			}
264 			return 1;
265 		}
266 		/// squirrel_type corresponding to the c++ type/class
267 		static const char* squirrel_type()
268 		{
269 			static cbuffer_t buf;
270 			buf.clear();
271 			buf.printf("array<%s>", param<T>::squirrel_type() );
272 			return buf;
273 		}
274 	};
275 
276 	/**
277 	 * partial specialization for *handle_t types
278 	 */
279 	// declared here, implementation in api_class.h,
280 	// which has to be included if necessary
281 	template<class T> struct param< quickstone_tpl<T> >;
282 
283 
284 #define declare_types(mask, sqtype) \
285 	static const char* typemask() { return mask; } \
286 	static const char* squirrel_type() \
287 	{ \
288 		return sqtype; \
289 	}
290 
291 	/// macro to declare specialized param template
292 #define declare_specialized_param(T, mask, sqtype) \
293 	template<> struct param<T> { \
294 		static T get(HSQUIRRELVM vm, SQInteger index); \
295 		static SQInteger push(HSQUIRRELVM vm, T const& v);\
296 		static void* tag(); \
297 		declare_types(mask, sqtype); \
298 	};
299 	/// macro to only define typemask for specialized param template
300 	/// if only 'const class*' is defined then parameter mask must be defined for 'class *' too.
301 #define declare_param_mask(T, mask, sqtype) \
302 	template<> struct param<T> { \
303 		declare_types(mask, sqtype) \
304 	};
305 	/// macro to declare fake types, inherited from void_t,
306 	/// for documentation purposes
307 #define declare_fake_param(T, sqtype) \
308 	class T { public: T(void_t) {};  operator void_t() const { return void_t();} };  \
309 	template<> struct param<T> { \
310 		static T get(HSQUIRRELVM vm, SQInteger index) { return param<void_t>::get(vm, index); } \
311 		static SQInteger push(HSQUIRRELVM vm, T const& v) { return param<void_t>::push(vm, v); } \
312 		declare_types(".", sqtype); \
313 	};
314 	// macro to declare enums
315 #define declare_enum_param(T, inttype, sqtype) \
316 	template<> struct param<T> { \
317 		static T get(HSQUIRRELVM vm, SQInteger index) { return (T)param<inttype>::get(vm, index); } \
318 		static SQInteger push(HSQUIRRELVM vm, T const& v) { return param<inttype>::push(vm, v); } \
319 		declare_types("i", sqtype); \
320 	};
321 
322 
323 
324 	declare_specialized_param(void_t, ".", "void");
325 	// no typemask, as we call to_bool
326 	declare_specialized_param(bool, ".", "bool");
327 
328 	declare_specialized_param(uint8, "i", "integer");
329 	declare_specialized_param(sint8, "i", "integer");
330 	declare_specialized_param(uint16, "i", "integer");
331 	declare_specialized_param(sint16, "i", "integer");
332 	declare_specialized_param(uint32, "i", "integer");
333 	declare_specialized_param(sint32, "i", "integer");
334 	declare_specialized_param(uint64, "i", "integer");
335 	declare_specialized_param(sint64, "i", "integer");
336 	declare_enum_param(waytype_t, sint16, "way_types");
337 	declare_enum_param(systemtype_t, uint8, "way_system_types");
338 	declare_enum_param(obj_t::typ, uint8, "map_objects");
339 	declare_enum_param(climate, uint8, "climates");
340 	declare_specialized_param(my_ribi_t, "i", "dir");
341 	declare_specialized_param(my_slope_t, "i", "slope");
342 
343 	declare_specialized_param(double, "i|f", "float");
344 
345 	declare_specialized_param(const char*, ".", "string");
346 	// no string typemask, as we call to_string
347 	declare_specialized_param(plainstring, ".", "string");
348 
349 	declare_specialized_param(koord, "t|x|y", "coord");
350 	declare_specialized_param(koord3d, "t|x|y", "coord3d");
351 
352 	declare_specialized_param(convoi_t*, "t|x|y", "convoy_x");
353 	declare_specialized_param(fabrik_t*, "t|x|y", "factory_x");
354 	declare_specialized_param(grund_t*, "t|x|y", "tile_x");
355 	declare_specialized_param(const haltestelle_t*, "t|x|y", "halt_x");
356 	declare_param_mask(haltestelle_t*, "t|x|y", "halt_x");
357 	declare_specialized_param(karte_t*, ".", "world");
358 	declare_specialized_param(planquadrat_t*, "t|x|y", "square_x");
359 	declare_specialized_param(settings_t*, "t|x|y", "settings");
360 	declare_specialized_param(schedule_t*, "t|x|y", "schedule_x");
361 	declare_specialized_param(const schedule_t*, "t|x|y", "schedule_x");
362 	declare_specialized_param(schedule_entry_t, "t|x|y", "schedule_entry_x");
363 	declare_specialized_param(mytime_t, "i|t|x|y", "time_x");
364 	declare_specialized_param(mytime_ticks_t, "i|t|x|y", "time_ticks_x");
365 	declare_specialized_param(scenario_t*, "t|x|y", "");
366 	declare_specialized_param(simline_t*, "t|x|y", "line_x");
367 	declare_specialized_param(player_t*, "t|x|y", "player_x");
368 	declare_specialized_param(stadt_t*, "t|x|y", "city_x");
369 	declare_specialized_param(const ware_production_t*, "t|x|y", "factory_production_x");
370 	declare_specialized_param(const factory_supplier_desc_t*, "t|x|y", "factory_production_x");
371 	declare_specialized_param(const factory_product_desc_t*, "t|x|y", "factory_production_x");
372 	declare_param_mask(ware_production_t*, "t|x|y", "factory_production_x");
373 	declare_specialized_param(tool_t*, "x", "command_x");
374 	declare_specialized_param(way_builder_t*, "t|x|y", "way_planner_x");
375 
376 	// export of obj_t derived classes in api/map_objects.cc
377 	declare_specialized_param(obj_t*, "t|x|y", "map_object_x");
378 	declare_specialized_param(baum_t*, "t|x|y", "tree_x");
379 	declare_specialized_param(gebaeude_t*, "t|x|y", "building_x");
380 	declare_specialized_param(label_t*, "t|x|y", "label_x");
381 	declare_specialized_param(weg_t*, "t|x|y", "way_x");
382 
383 	/**
384 	 * Returns the player associated to the script
385 	 * (or NULL for scenarios)
386 	 */
387 	player_t* get_my_player(HSQUIRRELVM vm);
388 
389 	/**
390 	 * Templated interface to declare free variables for
391 	 * c++ function calls
392 	 */
393 	template<class A1> struct freevariable {
394 		A1 arg1;
395 		freevariable(A1 const& a1) : arg1(a1) {}
396 
397 		/**
398 		 * Pushes the free variables
399 		 * @returns number of pushed parameters
400 		 */
401 		SQInteger push(HSQUIRRELVM vm) const {
402 			SQInteger count = 0;
403 			if (SQ_SUCCEEDED( param<A1>::push(vm, arg1) ) ) count++;
404 			return count;
405 		}
406 	};
407 
408 	/**
409 	 * Templated interface to declare free variables for
410 	 * c++ function calls
411 	 */
412 	template<class A1,class A2> struct freevariable2 : public freevariable<A1> {
413 		A2 arg2;
414 		freevariable2(A1 const& a1, A2 const& a2) : freevariable<A1>(a1), arg2(a2) {}
415 
416 		/**
417 		 * Pushes the free variables
418 		 * @returns number of pushed parameters
419 		 */
420 		SQInteger push(HSQUIRRELVM vm) const {
421 			SQInteger count = 0;
422 			if (SQ_SUCCEEDED( param<A2>::push(vm, arg2) ) ) count++;
423 			count += freevariable<A1>::push(vm);
424 			return count;
425 		}
426 	};
427 
428 	template<class A1,class A2,class A3> struct freevariable3 : public freevariable2<A1,A2> {
429 		A3 arg3;
430 		freevariable3(A1 const& a1, A2 const& a2, A3 const& a3) : freevariable2<A1,A2>(a1,a2), arg3(a3) {}
431 
432 		/**
433 		 * Pushes the free variables
434 		 * @returns number of pushed parameters
435 		 */
436 		SQInteger push(HSQUIRRELVM vm) const {
437 			SQInteger count = 0;
438 			if (SQ_SUCCEEDED( param<A3>::push(vm, arg3) ) ) count++;
439 			count += freevariable2<A1,A2>::push(vm);
440 			return count;
441 		}
442 	};
443 
444 
445 	/**
446 	 * Static class to handle the translation of world coordinates (which are sensible to rotation)
447 	 * to script coordinates (that are independent of rotation).
448 	 */
449 	class coordinate_transform_t {
450 	private:
451 		/// Stores how many times initial map was rotated.
452 		/// Scripts do not take care of rotated maps.
453 		/// Coordinates will be translated between in-game coordinates and script coordinates.
454 		/// First v.m. to be started sets this value
455 		static uint8 rotation;
456 	public:
457 		/// called if a new world is initialized
458 		static void new_world() { rotation=4; /*invalid*/ }
459 
460 		/// inits rotation from karte_t::settings
461 		static void initialize();
462 
463 		/// keep track of rotation
464 		static void rotate90()  { if (rotation<4) rotation = (rotation+1)&3; }
465 
466 		/// read/save rotation to stay consistent after saving & loading
467 		static void rdwr(loadsave_t*);
468 
469 		/**
470 		 * rotate actual world coordinates back,
471 		 * coordinates after transform are like in the
472 		 * scenario's original savegame
473 		 */
474 		static void koord_w2sq(koord &);
475 
476 		/**
477 		 * rotate original coordinates to actual world coordinates
478 		 */
479 		static void koord_sq2w(koord &);
480 
481 		/**
482 		 * rotate actual world coordinates direction to original direction
483 		 */
484 		static void ribi_w2sq(ribi_t::ribi &r);
485 
486 		/**
487 		 * rotate original direction to actual world coordinates direction
488 		 */
489 		static void ribi_sq2w(ribi_t::ribi &r);
490 
491 		/**
492 		 * rotate actual slope to original slope
493 		 */
494 		static void slope_w2sq(slope_t::type &s);
495 
496 		/**
497 		 * rotate original slope to actual slope
498 		 */
499 		static void slope_sq2w(slope_t::type &s);
500 
501 		static uint8 get_rotation() { return rotation; }
502 	};
503 
504 	/// called by karte_t directly
505 	void rotate90();
506 	/// called by karte_t directly
507 	void new_world();
508 
509 }; // end of namespace
510 #endif
511