1 /*
2  * Copyright (C) 2004 Ivo Danihelka (ivo@danihelka.net)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  */
9 #include "game-script.h"
10 
11 #include "Log.h"
12 #include "KeyControl.h"
13 #include "Path.h"
14 #include "V2.h"
15 #include "Anim.h"
16 #include "Shape.h"
17 #include "Cube.h"
18 #include "Rules.h"
19 #include "LevelScript.h"
20 #include "ModelFactory.h"
21 #include "Room.h"
22 #include "RopeDecor.h"
23 #include "ShapeBuilder.h"
24 
25 #include "def-script.h"
26 
27 //-----------------------------------------------------------------
28     inline LevelScript *
getLevelScript(lua_State * L)29 getLevelScript(lua_State *L)
30 {
31     return dynamic_cast<LevelScript*>(script_getLeader(L));
32 }
33 //-----------------------------------------------------------------
34     inline Cube *
getModel(lua_State * L,int model_index)35 getModel(lua_State *L, int model_index)
36 {
37     return getLevelScript(L)->getModel(model_index);
38 }
39 
40 //-----------------------------------------------------------------
41 /**
42  * void game_setRoomWaves(amplitude, periode, speed)
43  */
44     int
script_game_setRoomWaves(lua_State * L)45 script_game_setRoomWaves(lua_State *L) throw()
46 {
47     BEGIN_NOEXCEPTION;
48     float amp = luaL_checknumber(L, 1);
49     float periode = luaL_checknumber(L, 2);
50     float speed = luaL_checknumber(L, 3);
51 
52     getLevelScript(L)->room()->setWaves(amp, periode, speed);
53     END_NOEXCEPTION;
54     return 0;
55 }
56 //-----------------------------------------------------------------
57 /**
58  * int game_addModel(kind, x, y, shape)
59  * Return model index.
60  *
61  *  table = addModel("light", 10, 30,
62  *  [[
63  *  XXXXX
64  *  ..X
65  *  ..X
66  *  ]])
67  */
68     int
script_game_addModel(lua_State * L)69 script_game_addModel(lua_State *L) throw()
70 {
71     BEGIN_NOEXCEPTION;
72     const char *kind = luaL_checkstring(L, 1);
73     int x = luaL_checkint(L, 2);
74     int y = luaL_checkint(L, 3);
75     const char *shape = luaL_checkstring(L, 4);
76 
77     Cube *model = ModelFactory::createModel(kind, V2(x, y), shape);
78     Unit *unit = ModelFactory::createUnit(kind);
79     int model_index = getLevelScript(L)->addModel(model, unit);
80     lua_pushnumber(L, model_index);
81     END_NOEXCEPTION;
82     //NOTE: return model_index
83     return 1;
84 }
85 //-----------------------------------------------------------------
86 /**
87  * int game_getCycles()
88  */
89     int
script_game_getCycles(lua_State * L)90 script_game_getCycles(lua_State *L) throw()
91 {
92     BEGIN_NOEXCEPTION;
93     int cycles = getLevelScript(L)->room()->getCycles();
94     lua_pushnumber(L, cycles);
95     END_NOEXCEPTION;
96     //NOTE: return cycles
97     return 1;
98 }
99 //-----------------------------------------------------------------
100 /**
101  * void game_addDecor(decor_name, params...)
102  *
103  * decor_name:
104  * "rope" ... draw rope between models
105  *          params = (model_index1, model_index2,
106  *              shift_x1, shift_y1, shift_x2, shift_y2)
107  */
108     int
script_game_addDecor(lua_State * L)109 script_game_addDecor(lua_State *L) throw()
110 {
111     BEGIN_NOEXCEPTION;
112     std::string decor_name = luaL_checkstring(L, 1);
113     if ("rope" == decor_name) {
114         int model_index1 = luaL_checkint(L, 2);
115         int model_index2 = luaL_checkint(L, 3);
116         int shift_x1 = luaL_checkint(L, 4);
117         int shift_y1 = luaL_checkint(L, 5);
118         int shift_x2 = luaL_checkint(L, 6);
119         int shift_y2 = luaL_checkint(L, 7);
120 
121         Cube *model1 = getModel(L, model_index1);
122         Cube *model2 = getModel(L, model_index2);
123         getLevelScript(L)->room()->addDecor(new RopeDecor(model1, model2,
124                     V2(shift_x1, shift_y1), V2(shift_x2, shift_y2)));
125     }
126     else {
127         LOG_WARNING(ExInfo("unknown decor")
128                 .addInfo("decor_name", decor_name));
129     }
130 
131     END_NOEXCEPTION;
132     return 0;
133 }
134 //-----------------------------------------------------------------
135 /**
136  * void game_setScreenShift(x, y)
137  */
138     int
script_game_setScreenShift(lua_State * L)139 script_game_setScreenShift(lua_State *L) throw()
140 {
141     BEGIN_NOEXCEPTION;
142     int x = luaL_checkint(L, 1);
143     int y = luaL_checkint(L, 2);
144     getLevelScript(L)->room()->setScreenShift(V2(x, y));
145     END_NOEXCEPTION;
146     return 0;
147 }
148 //-----------------------------------------------------------------
149 /**
150  * void game_changeBg(picture)
151  */
152     int
script_game_changeBg(lua_State * L)153 script_game_changeBg(lua_State *L) throw()
154 {
155     BEGIN_NOEXCEPTION;
156     const char *picture = luaL_checkstring(L, 1);
157     getLevelScript(L)->room()->changeBg(picture);
158     END_NOEXCEPTION;
159     return 0;
160 }
161 //-----------------------------------------------------------------
162 /**
163  * string game_getBg()
164  * Return the name of the currently used bg picture.
165  */
166     int
script_game_getBg(lua_State * L)167 script_game_getBg(lua_State *L) throw()
168 {
169     BEGIN_NOEXCEPTION;
170     lua_pushstring(L, getLevelScript(L)->room()->getBg().c_str());
171     END_NOEXCEPTION;
172     //NOTE: return bg
173     return 1;
174 }
175 //-----------------------------------------------------------------
176 /**
177  * void game_checkActive()
178  * Check active fish, switch to non busy alive fish.
179  */
180     int
script_game_checkActive(lua_State * L)181 script_game_checkActive(lua_State *L) throw()
182 {
183     BEGIN_NOEXCEPTION;
184     getLevelScript(L)->room()->checkActive();
185     END_NOEXCEPTION;
186     return 0;
187 }
188 //-----------------------------------------------------------------
189 /**
190  * void game_setFastFalling(value)
191  * Value==true sets fast falling for all objets.
192  */
193     int
script_game_setFastFalling(lua_State * L)194 script_game_setFastFalling(lua_State *L) throw()
195 {
196     BEGIN_NOEXCEPTION;
197     bool value = lua_toboolean(L, 1);
198     getLevelScript(L)->room()->setFastFalling(value);
199     END_NOEXCEPTION;
200     return 0;
201 }
202 
203 //-----------------------------------------------------------------
204 /**
205  * void model_addAnim(model_index, anim_name, picture, lookDir)
206  * Sides:
207  * LOOK_LEFT = 0
208  * LOOK_RIGHT = 1
209  */
210     int
script_model_addAnim(lua_State * L)211 script_model_addAnim(lua_State *L) throw()
212 {
213     BEGIN_NOEXCEPTION;
214     int model_index = luaL_checkint(L, 1);
215     const char *anim_name = luaL_checkstring(L, 2);
216     const char *picture = luaL_checkstring(L, 3);
217     Anim::eSide lookDir = static_cast<Anim::eSide>(
218             luaL_optint(L, 4, Anim::SIDE_LEFT));
219 
220     Cube *model = getModel(L, model_index);
221     if (picture[0] == '\0') {
222         model->anim()->addAnim(anim_name,
223                 ShapeBuilder::createImage(model->shape(), model->getWeight()),
224                 lookDir);
225     } else {
226         model->anim()->addAnim(anim_name, Path::dataReadPath(picture), lookDir);
227     }
228     END_NOEXCEPTION;
229     return 0;
230 }
231 //-----------------------------------------------------------------
232 /**
233  * void model_runAnim(model_index, anim_name, phase=0)
234  */
235     int
script_model_runAnim(lua_State * L)236 script_model_runAnim(lua_State *L) throw()
237 {
238     BEGIN_NOEXCEPTION;
239     int model_index = luaL_checkint(L, 1);
240     const char *anim_name = luaL_checkstring(L, 2);
241     int phase = luaL_optint(L, 3, 0);
242 
243     Cube *model = getModel(L, model_index);
244     model->anim()->runAnim(anim_name, phase);
245     END_NOEXCEPTION;
246     return 0;
247 }
248 //-----------------------------------------------------------------
249 /**
250  * void model_setAnim(model_index, anim_name, phase)
251  */
252     int
script_model_setAnim(lua_State * L)253 script_model_setAnim(lua_State *L) throw()
254 {
255     BEGIN_NOEXCEPTION;
256     int model_index = luaL_checkint(L, 1);
257     const char *anim_name = luaL_checkstring(L, 2);
258     int phase = luaL_checkint(L, 3);
259 
260     Cube *model = getModel(L, model_index);
261     model->anim()->setAnim(anim_name, phase);
262     END_NOEXCEPTION;
263     return 0;
264 }
265 //-----------------------------------------------------------------
266 /**
267  * void model_useSpecialAnim(model_index, anim_name, phase)
268  *
269  * Set special anim for one phase.
270  */
271     int
script_model_useSpecialAnim(lua_State * L)272 script_model_useSpecialAnim(lua_State *L) throw()
273 {
274     BEGIN_NOEXCEPTION;
275     int model_index = luaL_checkint(L, 1);
276     const char *anim_name = luaL_checkstring(L, 2);
277     int phase = luaL_checkint(L, 3);
278 
279     Cube *model = getModel(L, model_index);
280     model->anim()->useSpecialAnim(anim_name, phase);
281     END_NOEXCEPTION;
282     return 0;
283 }
284 //-----------------------------------------------------------------
285 /**
286  * int model_countAnims(model_index, anim_name)
287  */
288     int
script_model_countAnims(lua_State * L)289 script_model_countAnims(lua_State *L) throw()
290 {
291     BEGIN_NOEXCEPTION;
292     int model_index = luaL_checkint(L, 1);
293     const char *anim_name = luaL_checkstring(L, 2);
294 
295     Cube *model = getModel(L, model_index);
296     int anims = model->anim()->countAnimPhases(anim_name);
297     lua_pushnumber(L, anims);
298     END_NOEXCEPTION;
299     //NOTE: return anims
300     return 1;
301 }
302 //-----------------------------------------------------------------
303 /**
304  * void model_setEffect(model_index, effect_name)
305  *
306  * Set special view effect.
307  * available effects: "none", "mirror", "invisible", "reverse", "zx"
308  */
309     int
script_model_setEffect(lua_State * L)310 script_model_setEffect(lua_State *L) throw()
311 {
312     BEGIN_NOEXCEPTION;
313     int model_index = luaL_checkint(L, 1);
314     std::string effectName = luaL_checkstring(L, 2);
315     Cube *model = getModel(L, model_index);
316     model->anim()->setEffect(effectName);
317 
318     END_NOEXCEPTION;
319     return 0;
320 }
321 //-----------------------------------------------------------------
322 /**
323  * (x, y) model_getLoc(model_index)
324  */
325     int
script_model_getLoc(lua_State * L)326 script_model_getLoc(lua_State *L) throw()
327 {
328     BEGIN_NOEXCEPTION;
329     int model_index = luaL_checkint(L, 1);
330 
331     Cube *model = getModel(L, model_index);
332     V2 loc = model->getLocation();
333 
334     lua_pushnumber(L, loc.getX());
335     lua_pushnumber(L, loc.getY());
336     END_NOEXCEPTION;
337     //NOTE: return (x, y)
338     return 2;
339 }
340 
341 //-----------------------------------------------------------------
342 /**
343  * string model_getAction(model_index)
344  */
345     int
script_model_getAction(lua_State * L)346 script_model_getAction(lua_State *L) throw()
347 {
348     BEGIN_NOEXCEPTION;
349     int model_index = luaL_checkint(L, 1);
350     Cube *model = getModel(L, model_index);
351     std::string action = model->rules()->getAction();
352 
353     lua_pushlstring(L, action.c_str(), action.size());
354     END_NOEXCEPTION;
355     //NOTE: return action
356     return 1;
357 }
358 //-----------------------------------------------------------------
359 /**
360  * string model_getState(model_index)
361  */
362     int
script_model_getState(lua_State * L)363 script_model_getState(lua_State *L) throw()
364 {
365     BEGIN_NOEXCEPTION;
366     int model_index = luaL_checkint(L, 1);
367     Cube *model = getModel(L, model_index);
368     std::string state = model->rules()->getState();
369 
370     lua_pushlstring(L, state.c_str(), state.size());
371     END_NOEXCEPTION;
372     //NOTE: return state
373     return 1;
374 }
375 //-----------------------------------------------------------------
376 /**
377  * Dir::eDir model_getDir(model_index)
378  */
379     int
script_model_getDir(lua_State * L)380 script_model_getDir(lua_State *L) throw()
381 {
382     BEGIN_NOEXCEPTION;
383     int model_index = luaL_checkint(L, 1);
384     Cube *model = getModel(L, model_index);
385     Dir::eDir dir = model->getLastMoveDir();
386 
387     lua_pushnumber(L, dir);
388     END_NOEXCEPTION;
389     //NOTE: return dir
390     return 1;
391 }
392 //-----------------------------------------------------------------
393 /**
394  * Dir::eDir model_getTouchDir(model_index)
395  */
396     int
script_model_getTouchDir(lua_State * L)397 script_model_getTouchDir(lua_State *L) throw()
398 {
399     BEGIN_NOEXCEPTION;
400     int model_index = luaL_checkint(L, 1);
401     Cube *model = getModel(L, model_index);
402     Dir::eDir dir = model->rules()->getTouchDir();
403 
404     lua_pushnumber(L, dir);
405     END_NOEXCEPTION;
406     //NOTE: return dir
407     return 1;
408 }
409 //-----------------------------------------------------------------
410 /**
411  * bool model_isAlive(model_index)
412  */
413     int
script_model_isAlive(lua_State * L)414 script_model_isAlive(lua_State *L) throw()
415 {
416     BEGIN_NOEXCEPTION;
417     int model_index = luaL_checkint(L, 1);
418     Cube *model = getModel(L, model_index);
419     bool alive = model->isAlive();
420 
421     lua_pushboolean(L, alive);
422     END_NOEXCEPTION;
423     //NOTE: return alive
424     return 1;
425 }
426 //-----------------------------------------------------------------
427 /**
428  * bool model_isOut(model_index)
429  *
430  * Returns true when model is out of room.
431  */
432     int
script_model_isOut(lua_State * L)433 script_model_isOut(lua_State *L) throw()
434 {
435     BEGIN_NOEXCEPTION;
436     int model_index = luaL_checkint(L, 1);
437     Cube *model = getModel(L, model_index);
438     bool out = model->isOut();
439 
440     lua_pushboolean(L, out);
441     END_NOEXCEPTION;
442     //NOTE: return out
443     return 1;
444 }
445 //-----------------------------------------------------------------
446 /**
447  * bool model_isLeft(model_index)
448  *
449  * Returns true when model is looking to the left.
450  */
451     int
script_model_isLeft(lua_State * L)452 script_model_isLeft(lua_State *L) throw()
453 {
454     BEGIN_NOEXCEPTION;
455     int model_index = luaL_checkint(L, 1);
456     Cube *model = getModel(L, model_index);
457     bool left = model->isLeft();
458 
459     lua_pushboolean(L, left);
460     END_NOEXCEPTION;
461     //NOTE: return left
462     return 1;
463 }
464 //-----------------------------------------------------------------
465 /**
466  * bool model_isAtBorder(model_index)
467  *
468  * Returns true when model is at room border.
469  */
470     int
script_model_isAtBorder(lua_State * L)471 script_model_isAtBorder(lua_State *L) throw()
472 {
473     BEGIN_NOEXCEPTION;
474     int model_index = luaL_checkint(L, 1);
475     Cube *model = getModel(L, model_index);
476     bool atBorder = model->rules()->isAtBorder();
477 
478     lua_pushboolean(L, atBorder);
479     END_NOEXCEPTION;
480     //NOTE: return atBorder
481     return 1;
482 }
483 //-----------------------------------------------------------------
484 /**
485  * int model_getW(model_index)
486  *
487  * Returns model width.
488  */
489     int
script_model_getW(lua_State * L)490 script_model_getW(lua_State *L) throw()
491 {
492     BEGIN_NOEXCEPTION;
493     int model_index = luaL_checkint(L, 1);
494     Cube *model = getModel(L, model_index);
495     int width = model->shape()->getW();
496 
497     lua_pushnumber(L, width);
498     END_NOEXCEPTION;
499     //NOTE: return width
500     return 1;
501 }
502 //-----------------------------------------------------------------
503 /**
504  * int model_getH(model_index)
505  *
506  * Returns model height.
507  */
508     int
script_model_getH(lua_State * L)509 script_model_getH(lua_State *L) throw()
510 {
511     BEGIN_NOEXCEPTION;
512     int model_index = luaL_checkint(L, 1);
513     Cube *model = getModel(L, model_index);
514     int height = model->shape()->getH();
515 
516     lua_pushnumber(L, height);
517     END_NOEXCEPTION;
518     //NOTE: return height
519     return 1;
520 }
521 //-----------------------------------------------------------------
522 /**
523  * void model_setGoal(model_index, goalname)
524  * Choose:
525  * - "goal_no" .. no goal
526  * - "goal_out" ... go out
527  * - "goal_escape" ... go alive out
528  */
529     int
script_model_setGoal(lua_State * L)530 script_model_setGoal(lua_State *L) throw()
531 {
532     //NOTE: (const char*)== does not compare string equality
533     BEGIN_NOEXCEPTION;
534     int model_index = luaL_checkint(L, 1);
535     std::string goalname = luaL_checkstring(L, 2);
536 
537     Cube *model = getModel(L, model_index);
538     Goal goal = Goal::noGoal();
539     if ("goal_no" == goalname) {
540         goal = Goal::noGoal();
541     }
542     else if ("goal_out" == goalname) {
543         goal = Goal::outGoal();
544     }
545     else if ("goal_escape" == goalname) {
546         goal = Goal::escapeGoal();
547     }
548     else if ("goal_alive" == goalname) {
549         goal = Goal::aliveGoal();
550     }
551     else {
552         ExInfo error = ExInfo("unknown goal")
553             .addInfo("goal", goalname);
554         LOG_WARNING(error);
555         luaL_error(L, error.what());
556     }
557 
558     model->setGoal(goal);
559 
560     END_NOEXCEPTION;
561     return 0;
562 }
563 //-----------------------------------------------------------------
564 /**
565  * void model_change_turnSide(model_index)
566  *
567  * Change look side.
568  */
569     int
script_model_change_turnSide(lua_State * L)570 script_model_change_turnSide(lua_State *L) throw()
571 {
572     BEGIN_NOEXCEPTION;
573     int model_index = luaL_checkint(L, 1);
574     Cube *model = getModel(L, model_index);
575     model->change_turnSide();
576 
577     END_NOEXCEPTION;
578     return 0;
579 }
580 //-----------------------------------------------------------------
581 /**
582  * void model_change_setLocation(model_index, x, y)
583  * Change model position (used to load undo).
584  */
585     int
script_model_change_setLocation(lua_State * L)586 script_model_change_setLocation(lua_State *L) throw()
587 {
588     BEGIN_NOEXCEPTION;
589     int model_index = luaL_checkint(L, 1);
590     int x = luaL_checkint(L, 2);
591     int y = luaL_checkint(L, 3);
592     Cube *model = getModel(L, model_index);
593     model->rules()->change_setLocation(V2(x, y));
594 
595     END_NOEXCEPTION;
596     return 0;
597 }
598 //-----------------------------------------------------------------
599 /**
600  * void model_setViewShift(model_index, shift_x, shift_y)
601  * Shift view (used for obsolete animation effects).
602  */
603     int
script_model_setViewShift(lua_State * L)604 script_model_setViewShift(lua_State *L) throw()
605 {
606     BEGIN_NOEXCEPTION;
607     int model_index = luaL_checkint(L, 1);
608     int shift_x = luaL_checkint(L, 2);
609     int shift_y = luaL_checkint(L, 3);
610     Cube *model = getModel(L, model_index);
611     model->anim()->setViewShift(V2(shift_x, shift_y));
612 
613     END_NOEXCEPTION;
614     return 0;
615 }
616 //-----------------------------------------------------------------
617 /**
618  * shift_x, shift_y model_getViewShift(model_index)
619  */
620     int
script_model_getViewShift(lua_State * L)621 script_model_getViewShift(lua_State *L) throw()
622 {
623     BEGIN_NOEXCEPTION;
624     int model_index = luaL_checkint(L, 1);
625     Cube *model = getModel(L, model_index);
626     V2 shift = model->anim()->getViewShift();
627 
628     lua_pushnumber(L, shift.getX());
629     lua_pushnumber(L, shift.getY());
630     END_NOEXCEPTION;
631     //NOTE: return shift_x, shift_y
632     return 2;
633 }
634 //-----------------------------------------------------------------
635 /**
636  * void model_setBusy(model_index, value)
637  */
638     int
script_model_setBusy(lua_State * L)639 script_model_setBusy(lua_State *L) throw()
640 {
641     BEGIN_NOEXCEPTION;
642     int model_index = luaL_checkint(L, 1);
643     bool busy = lua_toboolean(L, 2);
644     Cube *model = getModel(L, model_index);
645     model->setBusy(busy);
646 
647     END_NOEXCEPTION;
648     return 0;
649 }
650 //-----------------------------------------------------------------
651 /**
652  * table model_getExtraParams(model_index)
653  *
654  * Returns extra parameters needed to restore after undo.
655  */
656     int
script_model_getExtraParams(lua_State * L)657 script_model_getExtraParams(lua_State *L) throw()
658 {
659     BEGIN_NOEXCEPTION;
660     int model_index = luaL_checkint(L, 1);
661     Cube *model = getModel(L, model_index);
662 
663     lua_newtable(L);
664     lua_pushstring(L, "outDir");
665     lua_pushnumber(L, model->getOutDir());
666     lua_settable(L, -3);
667 
668     lua_pushstring(L, "outCapacity");
669     lua_pushnumber(L, model->getOutCapacity());
670     lua_settable(L, -3);
671 
672     lua_pushstring(L, "weight");
673     lua_pushnumber(L, model->getWeight());
674     lua_settable(L, -3);
675 
676     lua_pushstring(L, "anim");
677     lua_pushstring(L, model->anim()->getState().c_str());
678     lua_settable(L, -3);
679 
680     END_NOEXCEPTION;
681     return 1;
682 }
683 //-----------------------------------------------------------------
684 /**
685  * void model_change_setExtraParams(model_index, table)
686  *
687  * Restores extra parameters after undo.
688  */
689     int
script_model_change_setExtraParams(lua_State * L)690 script_model_change_setExtraParams(lua_State *L) throw()
691 {
692     BEGIN_NOEXCEPTION;
693     int model_index = luaL_checkint(L, 1);
694 
695     lua_pushstring(L, "outDir");
696     lua_gettable(L, 2);
697     int outDir = luaL_checkint(L, -1);
698 
699     lua_pushstring(L, "outCapacity");
700     lua_gettable(L, 2);
701     int outCapacity = luaL_checkint(L, -1);
702 
703     lua_pushstring(L, "weight");
704     lua_gettable(L, 2);
705     int weight = luaL_checkint(L, -1);
706 
707     lua_pushstring(L, "anim");
708     lua_gettable(L, 2);
709     std::string animState = luaL_checkstring(L, -1);
710 
711     Cube *model = getModel(L, model_index);
712     model->setOutDir((Dir::eDir)outDir, outCapacity, (Cube::eWeight)weight);
713     model->setExtraParams();
714     model->anim()->restoreState(animState);
715 
716     END_NOEXCEPTION;
717     return 0;
718 }
719 
720 //-----------------------------------------------------------------
721 /**
722  * void model_equals(model_index, x, y)
723  *
724  * Returns whether object at location(x, y) is equal.
725  * NOTE: model_index can be -1 for empty water.
726  * NOTE: boder is as wall (even thought border.index == -1)
727  */
728     int
script_model_equals(lua_State * L)729 script_model_equals(lua_State *L) throw()
730 {
731     BEGIN_NOEXCEPTION;
732     int model_index = luaL_checkint(L, 1);
733     int x = luaL_checkint(L, 2);
734     int y = luaL_checkint(L, 3);
735     Cube *other = getLevelScript(L)->askField(V2(x, y));
736 
737     bool equals = false;
738     if (other) {
739         if (model_index == -1) {
740             equals = false;
741         }
742         else {
743             equals = (model_index == other->getIndex());
744         }
745     }
746     else {
747         if (model_index == -1) {
748             equals = true;
749         }
750     }
751 
752     lua_pushboolean(L, equals);
753     END_NOEXCEPTION;
754     //NOTE: return equals
755     return 1;
756 }
757 
758 
759 //-----------------------------------------------------------------
760 /**
761  * void sound_addSound(name, file)
762  *
763  * Store this sound resource under this name.
764  */
765     int
script_sound_addSound(lua_State * L)766 script_sound_addSound(lua_State *L) throw()
767 {
768     BEGIN_NOEXCEPTION;
769     const char *name = luaL_checkstring(L, 1);
770     const char *file = luaL_checkstring(L, 2);
771 
772     getLevelScript(L)->addSound(name, Path::dataReadPath(file));
773     END_NOEXCEPTION;
774     return 0;
775 }
776 //-----------------------------------------------------------------
777 /**
778  * void sound_playSound(name, volume)
779  */
780     int
script_sound_playSound(lua_State * L)781 script_sound_playSound(lua_State *L) throw()
782 {
783     BEGIN_NOEXCEPTION;
784     const char *name = luaL_checkstring(L, 1);
785     int volume = luaL_optint(L, 2, 100);
786 
787     getLevelScript(L)->playSound(name, volume);
788     END_NOEXCEPTION;
789     return 0;
790 }
791 
792