1 #include "api_param.h"
2 #include "api_class.h"
3
4 #include "../simcity.h"
5 #include "../simfab.h"
6 #include "../bauer/goods_manager.h"
7 #include "../dataobj/schedule.h"
8 #include "../dataobj/loadsave.h"
9 #include "../dataobj/scenario.h"
10 #include "../player/simplay.h"
11 #include "../utils/plainstring.h"
12 #include "api/api_command.h" // script_api::my_tool_t
13 #include "api/api_simple.h" // my_ribi_t
14
15
clamp(T v,T l,T u)16 template<typename T> T clamp(T v, T l, T u) { return v < l ? l : (v > u ? u :v); }
17
18 namespace script_api {
19
20 karte_ptr_t welt;
21
22 // rotation handling
rotate90()23 void rotate90() { coordinate_transform_t::rotate90(); }
new_world()24 void new_world() { coordinate_transform_t::new_world(); }
25
26 uint8 coordinate_transform_t::rotation = 4;
27
initialize()28 void coordinate_transform_t::initialize()
29 {
30 if (rotation == 4) {
31 rotation = welt->get_settings().get_rotation();
32 }
33 }
34
rdwr(loadsave_t * file)35 void coordinate_transform_t::rdwr(loadsave_t *file)
36 {
37 file->rdwr_byte(rotation);
38 }
39
koord_w2sq(koord & k)40 void coordinate_transform_t::koord_w2sq(koord &k)
41 {
42 // do not transform koord::invalid
43 if (k.x == -1 && k.y == -1) {
44 return;
45 }
46 switch( rotation ) {
47 // 0: do nothing
48 case 1: k = koord(k.y, welt->get_size().x-1 - k.x); break;
49 case 2: k = koord(welt->get_size().x-1 - k.x, welt->get_size().y-1 - k.y); break;
50 case 3: k = koord(welt->get_size().y-1 - k.y, k.x); break;
51 default: break;
52 }
53 }
54
koord_sq2w(koord & k)55 void coordinate_transform_t::koord_sq2w(koord &k)
56 {
57 // do not transform koord::invalid
58 if (k.x == -1 && k.y == -1) {
59 return;
60 }
61 switch( rotation ) {
62 // 0: do nothing
63 case 1: k = koord(welt->get_size().x-1 - k.y, k.x); break;
64 case 2: k = koord(welt->get_size().x-1 - k.x, welt->get_size().y-1 - k.y); break;
65 case 3: k = koord(k.y, welt->get_size().y-1 - k.x); break;
66 default: break;
67 }
68 }
69
ribi_w2sq(ribi_t::ribi & r)70 void coordinate_transform_t::ribi_w2sq(ribi_t::ribi &r)
71 {
72 if (rotation) {
73 r = ( ( (r << 4) | r) >> rotation) & 15;
74 }
75 }
76
ribi_sq2w(ribi_t::ribi & r)77 void coordinate_transform_t::ribi_sq2w(ribi_t::ribi &r)
78 {
79 if (rotation) {
80 r = ( ( (r << 4) | r) << rotation) >> 4 & 15;
81 }
82 }
83
slope_w2sq(slope_t::type & s)84 void coordinate_transform_t::slope_w2sq(slope_t::type &s)
85 {
86 if (s < slope_t::raised) {
87 for(uint8 i=1; i <= 4-rotation; i++) {
88 s = slope_t::rotate90(s);
89 }
90 }
91 }
92
slope_sq2w(slope_t::type & s)93 void coordinate_transform_t::slope_sq2w(slope_t::type &s)
94 {
95 if (s < slope_t::raised) {
96 for(uint8 i=1; i <= rotation; i++) {
97 s = slope_t::rotate90(s);
98 }
99 }
100 }
101
102 // void parameter
push(HSQUIRRELVM,void_t const &)103 SQInteger param<void_t>::push(HSQUIRRELVM, void_t const&)
104 {
105 return 0;
106 }
107
get(HSQUIRRELVM,SQInteger)108 void_t param<void_t>::get(HSQUIRRELVM, SQInteger)
109 {
110 return void_t();
111 }
112
113 // integer arguments
get(HSQUIRRELVM vm,SQInteger index)114 uint8 param<uint8>::get(HSQUIRRELVM vm, SQInteger index)
115 {
116 SQInteger i = 0;
117 sq_getinteger(vm, index, &i);
118 return clamp<uint8>(i, 0, 255);
119 }
push(HSQUIRRELVM vm,uint8 const & v)120 SQInteger param<uint8>::push(HSQUIRRELVM vm, uint8 const& v)
121 {
122 sq_pushinteger(vm, v);
123 return 1;
124 }
125
get(HSQUIRRELVM vm,SQInteger index)126 sint8 param<sint8>::get(HSQUIRRELVM vm, SQInteger index)
127 {
128 SQInteger i = 0;
129 sq_getinteger(vm, index, &i);
130 return clamp<sint8>(i, -128, 127);
131 }
push(HSQUIRRELVM vm,sint8 const & v)132 SQInteger param<sint8>::push(HSQUIRRELVM vm, sint8 const& v)
133 {
134 sq_pushinteger(vm, v);
135 return 1;
136 }
137
get(HSQUIRRELVM vm,SQInteger index)138 uint16 param<uint16>::get(HSQUIRRELVM vm, SQInteger index)
139 {
140 SQInteger i = 0;
141 sq_getinteger(vm, index, &i);
142 return clamp<uint16>(i, 0, 0xffff);
143 }
push(HSQUIRRELVM vm,uint16 const & v)144 SQInteger param<uint16>::push(HSQUIRRELVM vm, uint16 const& v)
145 {
146 sq_pushinteger(vm, v);
147 return 1;
148 }
149
get(HSQUIRRELVM vm,SQInteger index)150 sint16 param<sint16>::get(HSQUIRRELVM vm, SQInteger index)
151 {
152 SQInteger i = 0;
153 sq_getinteger(vm, index, &i);
154 return clamp<sint16>(i, -32768, 0x7fff);
155 }
push(HSQUIRRELVM vm,sint16 const & v)156 SQInteger param<sint16>::push(HSQUIRRELVM vm, sint16 const& v)
157 {
158 sq_pushinteger(vm, v);
159 return 1;
160 }
161
get(HSQUIRRELVM vm,SQInteger index)162 uint32 param<uint32>::get(HSQUIRRELVM vm, SQInteger index)
163 {
164 SQInteger i = 0;
165 sq_getinteger(vm, index, &i);
166 return i>=0 ? i : 0;
167 }
push(HSQUIRRELVM vm,uint32 const & v)168 SQInteger param<uint32>::push(HSQUIRRELVM vm, uint32 const& v)
169 {
170 sq_pushinteger(vm, v);
171 return 1;
172 }
173
get(HSQUIRRELVM vm,SQInteger index)174 sint32 param<sint32>::get(HSQUIRRELVM vm, SQInteger index)
175 {
176 SQInteger i = 0;
177 sq_getinteger(vm, index, &i);
178 return i;
179 }
push(HSQUIRRELVM vm,sint32 const & v)180 SQInteger param<sint32>::push(HSQUIRRELVM vm, sint32 const& v)
181 {
182 sq_pushinteger(vm, v);
183 return 1;
184 }
185
get(HSQUIRRELVM vm,SQInteger index)186 uint64 param<uint64>::get(HSQUIRRELVM vm, SQInteger index)
187 {
188 SQInteger i = 0;
189 sq_getinteger(vm, index, &i);
190 return i>=0 ? i : 0;
191 }
push(HSQUIRRELVM vm,uint64 const & v)192 SQInteger param<uint64>::push(HSQUIRRELVM vm, uint64 const& v)
193 {
194 sq_pushinteger(vm, (SQInteger)v);
195 return 1;
196 }
197
get(HSQUIRRELVM vm,SQInteger index)198 sint64 param<sint64>::get(HSQUIRRELVM vm, SQInteger index)
199 {
200 SQInteger i = 0;
201 sq_getinteger(vm, index, &i);
202 return i;
203 }
push(HSQUIRRELVM vm,sint64 const & v)204 SQInteger param<sint64>::push(HSQUIRRELVM vm, sint64 const& v)
205 {
206 sq_pushinteger(vm, (SQInteger)v);
207 return 1;
208 }
209
210 // floats
get(HSQUIRRELVM vm,SQInteger index)211 double param<double>::get(HSQUIRRELVM vm, SQInteger index)
212 {
213 SQFloat d = 0.0;
214 sq_getfloat(vm, index, &d);
215 return d;
216 }
push(HSQUIRRELVM vm,double const & v)217 SQInteger param<double>::push(HSQUIRRELVM vm, double const& v)
218 {
219 sq_pushfloat(vm, (SQFloat)v);
220 return 1;
221 }
222
223 // strings
get(HSQUIRRELVM vm,SQInteger index)224 const char* param<const char*>::get(HSQUIRRELVM vm, SQInteger index)
225 {
226 const char* str = NULL;
227 if (!SQ_SUCCEEDED(sq_getstring(vm, index, &str))) {
228 sq_raise_error(vm, "Supplied string parameter is null");
229 return NULL;
230 }
231 return str;
232 }
push(HSQUIRRELVM vm,const char * const & v)233 SQInteger param<const char*>::push(HSQUIRRELVM vm, const char* const& v)
234 {
235 if (v) {
236 sq_pushstring(vm, v, -1);
237 }
238 else {
239 sq_pushnull(vm);
240 }
241 return 1;
242 }
243
get(HSQUIRRELVM vm,SQInteger index)244 plainstring param<plainstring>::get(HSQUIRRELVM vm, SQInteger index)
245 {
246 if (sq_gettype(vm, index) == OT_NULL) {
247 return NULL;
248 }
249 plainstring ret;
250 const char* str = NULL;
251 if (!SQ_SUCCEEDED(sq_getstring(vm, index, &str))) {
252 // try tostring
253 if (SQ_SUCCEEDED(sq_tostring(vm, index))) {
254 sq_getstring(vm, -1, &str);
255 ret = str;
256 sq_pop(vm, 1);
257 }
258 }
259 else {
260 ret = str;
261 }
262 return ret;
263 }
264
push(HSQUIRRELVM vm,plainstring const & v)265 SQInteger param<plainstring>::push(HSQUIRRELVM vm, plainstring const& v)
266 {
267 return param<const char*>::push(vm, v.c_str());
268 }
269
270 // bool
get(HSQUIRRELVM vm,SQInteger index)271 bool param<bool>::get(HSQUIRRELVM vm, SQInteger index)
272 {
273 SQBool b = false;
274 sq_tobool(vm, index, &b);
275 return b;
276 }
push(HSQUIRRELVM vm,bool const & v)277 SQInteger param<bool>::push(HSQUIRRELVM vm, bool const& v)
278 {
279 sq_pushbool(vm, v);
280 return 1;
281 }
282
283 // coordinates
get(HSQUIRRELVM vm,SQInteger index)284 koord param<koord>::get(HSQUIRRELVM vm, SQInteger index)
285 {
286 sint16 x=-1, y=-1;
287 get_slot(vm, "x", x, index);
288 get_slot(vm, "y", y, index);
289 koord k(x,y);
290 if (k.x != -1 && k.y != -1) {
291 // transform coordinates
292 coordinate_transform_t::koord_sq2w(k);
293 }
294 else {
295 k = koord::invalid;
296 }
297 return k;
298 }
299
push(HSQUIRRELVM vm,koord const & v)300 SQInteger param<koord>::push(HSQUIRRELVM vm, koord const& v)
301 {
302 koord k(v);
303 if (k.x != -1 && k.y != -1) {
304 // transform coordinates
305 coordinate_transform_t::koord_w2sq(k);
306 }
307 else {
308 k = koord::invalid;
309 }
310 return push_instance(vm, "coord", k.x, k.y);
311 }
312
get(HSQUIRRELVM vm,SQInteger index)313 koord3d param<koord3d>::get(HSQUIRRELVM vm, SQInteger index)
314 {
315 sint8 z = -1;
316 if (!SQ_SUCCEEDED(get_slot(vm, "z", z, index))) {
317 return koord3d::invalid;
318 }
319 koord k = param<koord>::get(vm, index);
320 return koord3d(k, z);
321 }
322
323
push(HSQUIRRELVM vm,koord3d const & v)324 SQInteger param<koord3d>::push(HSQUIRRELVM vm, koord3d const& v)
325 {
326 koord k(v.get_2d());
327 if (k.x != -1 && k.y != -1) {
328 // transform coordinates
329 coordinate_transform_t::koord_w2sq(k);
330 }
331 else {
332 k = koord::invalid;
333 }
334 return push_instance(vm, "coord3d", k.x, k.y, v.z);
335 }
336 // directions / ribis
push(HSQUIRRELVM vm,my_ribi_t const & v)337 SQInteger param<my_ribi_t>::push(HSQUIRRELVM vm, my_ribi_t const& v)
338 {
339 ribi_t::ribi ribi = v;
340 coordinate_transform_t::ribi_w2sq(ribi);
341 return param<uint8>::push(vm, ribi);
342 }
343
get(HSQUIRRELVM vm,SQInteger index)344 my_ribi_t param<my_ribi_t>::get(HSQUIRRELVM vm, SQInteger index)
345 {
346 ribi_t::ribi ribi = param<uint8>::get(vm, index) & ribi_t::all;
347 coordinate_transform_t::ribi_sq2w(ribi);
348 return ribi;
349 }
350 // slopes
push(HSQUIRRELVM vm,my_slope_t const & v)351 SQInteger param<my_slope_t>::push(HSQUIRRELVM vm, my_slope_t const& v)
352 {
353 slope_t::type slope = v;
354 coordinate_transform_t::slope_w2sq(slope);
355 return param<uint8>::push(vm, slope);
356 }
357
get(HSQUIRRELVM vm,SQInteger index)358 my_slope_t param<my_slope_t>::get(HSQUIRRELVM vm, SQInteger index)
359 {
360 slope_t::type slope = param<uint8>::get(vm, index);
361 coordinate_transform_t::slope_sq2w(slope);
362 return slope;
363 }
364
365 // pointers to classes
366
get(HSQUIRRELVM vm,SQInteger index)367 convoi_t* param<convoi_t*>::get(HSQUIRRELVM vm, SQInteger index)
368 {
369 convoihandle_t cnv = param<convoihandle_t>::get(vm, index);
370 if (!cnv.is_bound()) {
371 sq_raise_error(vm, "Invalid convoi id %d", cnv.get_id());
372 }
373 return cnv.get_rep();
374 }
375
get(HSQUIRRELVM vm,SQInteger index)376 fabrik_t* param<fabrik_t*>::get(HSQUIRRELVM vm, SQInteger index)
377 {
378 koord pos = param<koord>::get(vm, index);
379 fabrik_t* fab = fabrik_t::get_fab(pos);
380 if (fab==NULL) {
381 sq_raise_error(vm, "no factory at position (%s)", pos.get_str());
382 }
383 return fab;
384 }
385
push(HSQUIRRELVM vm,fabrik_t * const & fab)386 SQInteger param<fabrik_t*>::push(HSQUIRRELVM vm, fabrik_t* const& fab)
387 {
388 if (fab == NULL) {
389 sq_pushnull(vm); return 1;
390 }
391 koord pos(fab->get_pos().get_2d());
392 coordinate_transform_t::koord_w2sq(pos);
393 return push_instance(vm, "factory_x", pos.x, pos.y);
394 }
395
get(HSQUIRRELVM vm,SQInteger index)396 const ware_production_t* param<const ware_production_t*>::get(HSQUIRRELVM vm, SQInteger index)
397 {
398 fabrik_t* fab = param<fabrik_t*>::get(vm, index);
399 if (fab == NULL) {
400 return NULL;
401 }
402 // obtain index into wareproduction_t arrays
403 SQInteger i = -1;
404 if (SQ_SUCCEEDED(get_slot(vm, "index", i, index))) {
405 if (i>=0) {
406 if ( (uint32)i<fab->get_input().get_count()) {
407 return &fab->get_input()[i];
408 }
409 else {
410 i -= fab->get_input().get_count();
411 if ( (uint32)i<fab->get_output().get_count()) {
412 return &fab->get_output()[i];
413 }
414 }
415 }
416 }
417 sq_raise_error(vm, "No production slot [%d] in factory at (%s)", i, fab->get_pos().get_str());
418 return NULL;
419 }
420
get(HSQUIRRELVM vm,SQInteger index)421 const factory_supplier_desc_t* param<const factory_supplier_desc_t*>::get(HSQUIRRELVM vm, SQInteger index)
422 {
423 fabrik_t* fab = param<fabrik_t*>::get(vm, index);
424 if (fab == NULL) {
425 return NULL;
426 }
427 // obtain index into wareproduction_t arrays
428 SQInteger i = -1;
429 if (SQ_SUCCEEDED(get_slot(vm, "index", i, index))) {
430 if (i>=0 && (uint32)i<fab->get_input().get_count()) {
431 const ware_production_t& in = fab->get_input()[i];
432 const factory_supplier_desc_t* desc = fab->get_desc()->get_supplier(i);
433 // sanity check
434 if (desc && desc->get_input_type() == in.get_typ()) {
435 return desc;
436 }
437 }
438 }
439 sq_raise_error(vm, "No input slot [%d] in factory at (%s)", i, fab->get_pos().get_str());
440 return NULL;
441 }
442
get(HSQUIRRELVM vm,SQInteger index)443 const factory_product_desc_t* param<const factory_product_desc_t*>::get(HSQUIRRELVM vm, SQInteger index)
444 {
445 fabrik_t* fab = param<fabrik_t*>::get(vm, index);
446 if (fab == NULL) {
447 return NULL;
448 }
449 // obtain index into wareproduction_t arrays
450 SQInteger i = -1;
451 if (SQ_SUCCEEDED(get_slot(vm, "index", i, index))) {
452 i -= fab->get_input().get_count();
453 if (i>=0 && (uint32)i<fab->get_output().get_count()) {
454 const ware_production_t& out = fab->get_output()[i];
455 const factory_product_desc_t* desc = fab->get_desc()->get_product(i);
456 // sanity check
457 if (desc && desc->get_output_type() == out.get_typ()) {
458 return desc;
459 }
460 }
461 }
462 sq_raise_error(vm, "No output slot [%d] in factory at (%s)", i, fab->get_pos().get_str());
463 return NULL;
464 }
465
get(HSQUIRRELVM vm,SQInteger index)466 player_t* param<player_t*>::get(HSQUIRRELVM vm, SQInteger index)
467 {
468 uint8 plnr = 0;
469 get_slot(vm, "nr", plnr, index);
470 if(plnr < 15) {
471 return welt->get_player(plnr);
472 }
473 else {
474 sq_raise_error(vm, "Invalid player index %d", plnr);
475 return NULL;
476 }
477 }
478
479
push(HSQUIRRELVM vm,player_t * const & player)480 SQInteger param<player_t*>::push(HSQUIRRELVM vm, player_t* const& player)
481 {
482 return push_instance(vm, "player_x", player ? player->get_player_nr() : 16);
483 }
484
485
get_my_player(HSQUIRRELVM vm)486 player_t* get_my_player(HSQUIRRELVM vm)
487 {
488 sq_pushregistrytable(vm);
489 uint8 player_nr = PLAYER_UNOWNED;
490 player_t *pl = NULL;
491 if (SQ_SUCCEEDED(get_slot<uint8>(vm, "my_player_nr", player_nr)) && player_nr < 15) {
492 pl = welt->get_player(player_nr);
493 }
494 sq_poptop(vm);
495 return pl;
496 }
497
498
get(HSQUIRRELVM vm,SQInteger index)499 const haltestelle_t* param<const haltestelle_t*>::get(HSQUIRRELVM vm, SQInteger index)
500 {
501 halthandle_t halt = param<halthandle_t>::get(vm, index);
502 if (!halt.is_bound()) {
503 sq_raise_error(vm, "Invalid halt id %d", halt.get_id());
504 }
505 return halt.get_rep();
506 }
507
508
get(HSQUIRRELVM vm,SQInteger index)509 planquadrat_t* param<planquadrat_t*>::get(HSQUIRRELVM vm, SQInteger index)
510 {
511 koord pos = param<koord>::get(vm, index);
512 planquadrat_t *plan = welt->access(pos);
513 if (plan==NULL) {
514 sq_raise_error(vm, "Coordinate out of range (%s)", pos.get_str());
515 }
516 return plan;
517 }
518
519
get(HSQUIRRELVM vm,SQInteger index)520 grund_t* param<grund_t*>::get(HSQUIRRELVM vm, SQInteger index)
521 {
522 koord3d pos = param<koord3d>::get(vm, index);
523 grund_t *gr = welt->lookup(pos);
524 if (gr==NULL) {
525 gr = welt->lookup_kartenboden(pos.get_2d());
526 }
527 if (gr==NULL) {
528 sq_raise_error(vm, "Coordinate out of range (%s)", pos.get_str());
529 }
530 return gr;
531 }
532
533
push(HSQUIRRELVM vm,grund_t * const & v)534 SQInteger param<grund_t*>::push(HSQUIRRELVM vm, grund_t* const& v)
535 {
536 if (v) {
537 koord k = v->get_pos().get_2d();
538 // transform coordinates
539 coordinate_transform_t::koord_w2sq(k);
540 return push_instance(vm, "tile_x", k.x, k.y, v->get_pos().z);
541 }
542 else {
543 sq_pushnull(vm); return 1;
544 }
545 }
546
547
get(HSQUIRRELVM,SQInteger)548 scenario_t* param<scenario_t*>::get(HSQUIRRELVM, SQInteger)
549 {
550 return welt->get_scenario();
551 }
552
553
push(HSQUIRRELVM vm,schedule_entry_t const & v)554 SQInteger param<schedule_entry_t>::push(HSQUIRRELVM vm, schedule_entry_t const& v)
555 {
556 return push_instance(vm, "schedule_entry_x", v.pos, v.minimum_loading, v.waiting_time_shift);
557 }
558
559
push(HSQUIRRELVM vm,schedule_t * const & v)560 SQInteger param<schedule_t*>::push(HSQUIRRELVM vm, schedule_t* const& v)
561 {
562 return param<const schedule_t*>::push(vm, v);
563 }
564
565
push(HSQUIRRELVM vm,const schedule_t * const & v)566 SQInteger param<const schedule_t*>::push(HSQUIRRELVM vm, const schedule_t* const& v)
567 {
568 if (v) {
569 return push_instance(vm, "schedule_x", v->get_waytype(), v->entries);
570 }
571 else {
572 sq_pushnull(vm); return 1;
573 }
574 }
575
576
get(HSQUIRRELVM,SQInteger)577 settings_t* param<settings_t*>::get(HSQUIRRELVM, SQInteger)
578 {
579 return &welt->get_settings();
580 }
581
582
get(HSQUIRRELVM vm,SQInteger index)583 simline_t* param<simline_t*>::get(HSQUIRRELVM vm, SQInteger index)
584 {
585 linehandle_t line = param<linehandle_t>::get(vm, index);
586 if (!line.is_bound()) {
587 sq_raise_error(vm, "Invalid line id %d", line.get_id());
588 }
589 return line.get_rep();
590 }
591
592
get(HSQUIRRELVM vm,SQInteger index)593 stadt_t* param<stadt_t*>::get(HSQUIRRELVM vm, SQInteger index)
594 {
595 koord pos = param<koord>::get(vm, index);
596 return welt->find_nearest_city(pos);
597 }
598
push(HSQUIRRELVM vm,stadt_t * const & v)599 SQInteger param<stadt_t*>::push(HSQUIRRELVM vm, stadt_t* const& v)
600 {
601 if (v) {
602 koord k = v->get_pos();
603 // transform coordinates
604 coordinate_transform_t::koord_w2sq(k);
605 return push_instance(vm, "city_x", k.x, k.y);
606 }
607 else {
608 sq_pushnull(vm); return 1;
609 }
610 }
611
get(HSQUIRRELVM,SQInteger)612 karte_t* param<karte_t*>::get(HSQUIRRELVM, SQInteger)
613 {
614 return welt;
615 }
616
push(HSQUIRRELVM vm,karte_t * const &)617 SQInteger param<karte_t*>::push(HSQUIRRELVM vm, karte_t* const&)
618 {
619 sq_pushnull(vm); return 1;
620 }
621
get(HSQUIRRELVM vm,SQInteger index)622 tool_t* param<tool_t*>::get(HSQUIRRELVM vm, SQInteger index)
623 {
624 my_tool_t *mtool = get_attached_instance<my_tool_t>(vm, index, param<tool_t*>::tag());
625 if (mtool) {
626 return mtool->tool;
627 }
628 return NULL;
629 }
630 };
631