1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/debug-channels.h"
24
25 #include "engines/grim/emi/lua_v2.h"
26 #include "engines/grim/lua/lua.h"
27
28 #include "engines/grim/actor.h"
29 #include "engines/grim/debug.h"
30 #include "engines/grim/grim.h"
31 #include "engines/grim/costume.h"
32 #include "engines/grim/set.h"
33
34 #include "engines/grim/emi/emi.h"
35 #include "engines/grim/emi/costumeemi.h"
36 #include "engines/grim/emi/skeleton.h"
37 #include "engines/grim/emi/costume/emichore.h"
38 #include "engines/grim/emi/costume/emiskel_component.h"
39
40 #include "engines/grim/lua/lauxlib.h"
41
42 namespace Grim {
43
SetActorLocalAlpha()44 void Lua_V2::SetActorLocalAlpha() {
45 lua_Object actorObj = lua_getparam(1);
46 lua_Object vertexObj= lua_getparam(2);
47 lua_Object alphaObj = lua_getparam(3);
48 // lua_Object unknownObj = lua_getparam(4);
49
50 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
51 return;
52
53 Actor *actor = getactor(actorObj);
54 if (!actor)
55 return;
56
57 if (!lua_isnumber(vertexObj))
58 return;
59
60 if (!lua_isnumber(alphaObj))
61 return;
62
63 int vertex = lua_getnumber(vertexObj);
64 float alpha = lua_getnumber(alphaObj);
65
66 Actor::AlphaMode mode = (Actor::AlphaMode)(int)alpha;
67
68 if (mode == Actor::AlphaOff || mode == Actor::AlphaReplace || mode == Actor::AlphaModulate) {
69 actor->setLocalAlphaMode(vertex, mode);
70 } else {
71 actor->setLocalAlpha(vertex, alpha);
72 }
73 }
74
75
SetActorGlobalAlpha()76 void Lua_V2::SetActorGlobalAlpha() {
77 lua_Object actorObj = lua_getparam(1);
78 lua_Object alphaObj = lua_getparam(2);
79 lua_Object meshObj = lua_getparam(3);
80
81 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
82 return;
83
84 Actor *actor = getactor(actorObj);
85 if (!actor)
86 return;
87
88 if (!lua_isnumber(alphaObj))
89 return;
90
91 const char *mesh = nullptr;
92 if (lua_isstring(meshObj)) {
93 mesh = lua_getstring(meshObj);
94 }
95 float alpha = lua_getnumber(alphaObj);
96 if (alpha == Actor::AlphaOff ||
97 alpha == Actor::AlphaReplace ||
98 alpha == Actor::AlphaModulate) {
99 actor->setAlphaMode((Actor::AlphaMode) (int) alpha, mesh);
100 } else {
101 actor->setGlobalAlpha(alpha, mesh);
102 }
103 }
104
PutActorInOverworld()105 void Lua_V2::PutActorInOverworld() {
106 lua_Object actorObj = lua_getparam(1);
107
108 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
109 return;
110
111 Actor *actor = getactor(actorObj);
112
113 actor->setInOverworld(true);
114 }
115
RemoveActorFromOverworld()116 void Lua_V2::RemoveActorFromOverworld() {
117 lua_Object actorObj = lua_getparam(1);
118
119 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
120 return;
121
122 Actor *actor = getactor(actorObj);
123 if (!actor)
124 return;
125
126 actor->setInOverworld(false);
127 }
128
UnloadActor()129 void Lua_V2::UnloadActor() {
130 lua_Object actorObj = lua_getparam(1);
131
132 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
133 return;
134
135 Actor *actor = getactor(actorObj);
136 if (!actor)
137 return;
138
139 g_grim->invalidateActiveActorsList();
140 g_grim->immediatelyRemoveActor(actor);
141 delete actor;
142 }
143
SetActorWalkRate()144 void Lua_V2::SetActorWalkRate() {
145 lua_Object actorObj = lua_getparam(1);
146 lua_Object rateObj = lua_getparam(2);
147
148 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
149 return;
150 if (!lua_isnumber(rateObj))
151 return;
152
153 Actor *actor = getactor(actorObj);
154 float rate = lua_getnumber(rateObj);
155 // const below only differ from grim
156 actor->setWalkRate(rate * 3.279999971389771);
157 }
158
GetActorWalkRate()159 void Lua_V2::GetActorWalkRate() {
160 lua_Object actorObj = lua_getparam(1);
161 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
162 return;
163
164 Actor *actor = getactor(actorObj);
165 // const below only differ from grim
166 lua_pushnumber(actor->getWalkRate() * 0.3048780560493469);
167 }
168
SetActorTurnRate()169 void Lua_V2::SetActorTurnRate() {
170 lua_Object actorObj = lua_getparam(1);
171 lua_Object rateObj = lua_getparam(2);
172
173 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
174 return;
175 if (!lua_isnumber(rateObj))
176 return;
177
178 Actor *actor = getactor(actorObj);
179 float rate = lua_getnumber(rateObj); // FIXME verify negate values of rate
180
181 // special handling of value 1 only used for voodoo chair
182 actor->setTurnRate((rate == 1) ? 100 : rate);
183 }
184
LockChoreSet()185 void Lua_V2::LockChoreSet() {
186 lua_Object choreObj = lua_getparam(1);
187
188 const char *choreName = lua_getstring(choreObj);
189 warning("Lua_V2::LockChoreSet: chore: %s", choreName);
190 }
191
UnlockChoreSet()192 void Lua_V2::UnlockChoreSet() {
193 lua_Object choreObj = lua_getparam(1);
194
195 const char *choreName = lua_getstring(choreObj);
196 warning("Lua_V2::UnlockChoreSet: chore: %s", choreName);
197 }
198
LockChore()199 void Lua_V2::LockChore() {
200 lua_Object nameObj = lua_getparam(1);
201 lua_Object filenameObj = lua_getparam(2);
202
203 if (!lua_isstring(nameObj) || !lua_isstring(filenameObj)) {
204 lua_pushnil();
205 return;
206 }
207
208 const char *name = lua_getstring(nameObj);
209 const char *filename = lua_getstring(filenameObj);
210 warning("Lua_V2::LockChore, name: %s, filename: %s", name, filename);
211 // FIXME: implement missing rest part of code
212 }
213
UnlockChore()214 void Lua_V2::UnlockChore() {
215 lua_Object nameObj = lua_getparam(1);
216 lua_Object filenameObj = lua_getparam(2);
217
218 if (!lua_isstring(nameObj) || !lua_isstring(filenameObj)) {
219 lua_pushnil();
220 return;
221 }
222
223 const char *name = lua_getstring(nameObj);
224 const char *filename = lua_getstring(filenameObj);
225 warning("Lua_V2::UnlockChore, name: %s, filename: %s", name, filename);
226 // FIXME: implement missing rest part of code
227 }
228
IsActorChoring()229 void Lua_V2::IsActorChoring() {
230 lua_Object actorObj = lua_getparam(1);
231 bool excludeLoop = getbool(2);
232
233 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
234 return;
235
236 Actor *actor = getactor(actorObj);
237 const Common::List<Costume *> &costumes = actor->getCostumes();
238
239 for (Common::List<Costume *>::const_iterator it = costumes.begin(); it != costumes.end(); ++it) {
240 Costume *costume = *it;
241 for (int i = 0; i < costume->getNumChores(); i++) {
242 int chore = costume->isChoring(i, excludeLoop);
243 if (chore != -1) {
244 // Ignore talk chores.
245 bool isTalk = false;
246 for (int j = 0; j < 10; j++) {
247 if (costume == actor->getTalkCostume(j) && actor->getTalkChore(j) == chore) {
248 isTalk = true;
249 break;
250 }
251 }
252 if (isTalk)
253 continue;
254
255 lua_pushnumber(chore);
256
257 pushbool(true);
258 return;
259 }
260 }
261 }
262
263 lua_pushnil();
264 }
265
IsChoreValid()266 void Lua_V2::IsChoreValid() {
267 lua_Object choreObj = lua_getparam(1);
268
269 if (!lua_isuserdata(choreObj) || lua_tag(choreObj) != MKTAG('C','H','O','R'))
270 return;
271
272 int chore = lua_getuserdata(choreObj);
273 Chore *c = EMIChore::getPool().getObject(chore);
274
275 if (c) {
276 pushbool(c != nullptr);
277 } else {
278 lua_pushnil();
279 }
280 }
281
IsChorePlaying()282 void Lua_V2::IsChorePlaying() {
283 lua_Object choreObj = lua_getparam(1);
284
285 if (!lua_isuserdata(choreObj) || lua_tag(choreObj) != MKTAG('C','H','O','R'))
286 return;
287
288 int chore = lua_getuserdata(choreObj);
289 Chore *c = EMIChore::getPool().getObject(chore);
290
291 if (c) {
292 pushbool(c->isPlaying() && !c->isPaused());
293 } else {
294 lua_pushnil();
295 }
296 }
297
IsChoreLooping()298 void Lua_V2::IsChoreLooping() {
299 lua_Object choreObj = lua_getparam(1);
300
301 if (!lua_isuserdata(choreObj) || lua_tag(choreObj) != MKTAG('C','H','O','R'))
302 return;
303
304 int chore = lua_getuserdata(choreObj);
305 Chore *c = EMIChore::getPool().getObject(chore);
306
307 if (c) {
308 pushbool(c->isLooping());
309 } else {
310 lua_pushnil();
311 }
312 }
313
SetChoreLooping()314 void Lua_V2::SetChoreLooping() {
315 lua_Object choreObj = lua_getparam(1);
316 if (!lua_isuserdata(choreObj) || lua_tag(choreObj) != MKTAG('C','H','O','R'))
317 return;
318
319 int chore = lua_getuserdata(choreObj);
320 Chore *c = EMIChore::getPool().getObject(chore);
321
322 if (c) {
323 c->setLooping(false);
324 }
325 lua_pushnil();
326 }
327
PlayChore()328 void Lua_V2::PlayChore() {
329 lua_Object choreObj = lua_getparam(1);
330
331 if (!lua_isuserdata(choreObj) || lua_tag(choreObj) != MKTAG('C','H','O','R'))
332 return;
333 int chore = lua_getuserdata(choreObj);
334
335 Chore *c = EMIChore::getPool().getObject(chore);
336 if (c) {
337 c->setPaused(false);
338 }
339 }
340
PauseChore()341 void Lua_V2::PauseChore() {
342 lua_Object choreObj = lua_getparam(1);
343
344 if (!lua_isuserdata(choreObj) || lua_tag(choreObj) != MKTAG('C','H','O','R'))
345 return;
346 int chore = lua_getuserdata(choreObj);
347
348 Chore *c = EMIChore::getPool().getObject(chore);
349 if (c) {
350 c->setPaused(true);
351 }
352 }
353
StopChore()354 void Lua_V2::StopChore() {
355 lua_Object choreObj = lua_getparam(1);
356 lua_Object fadeTimeObj = lua_getparam(2);
357
358 if (!lua_isuserdata(choreObj) || lua_tag(choreObj) != MKTAG('C','H','O','R'))
359 return;
360
361 int chore = lua_getuserdata(choreObj);
362 float fadeTime = 0.0f;
363
364 if (!lua_isnil(fadeTimeObj)) {
365 if (lua_isnumber(fadeTimeObj))
366 fadeTime = lua_getnumber(fadeTimeObj);
367 }
368
369 // There are a few cases in the scripts where StopChore is called with an excessively
370 // large fadeTime value. The original engine ignores fade times greater or equal
371 // to 0.6 seconds, so we replicate that behavior here.
372 if (fadeTime >= 0.6f) {
373 fadeTime = 0.0f;
374 }
375
376 Chore *c = EMIChore::getPool().getObject(chore);
377 if (c) {
378 c->stop((int)(fadeTime * 1000));
379 }
380 }
381
AdvanceChore()382 void Lua_V2::AdvanceChore() {
383 lua_Object choreObj = lua_getparam(1);
384 lua_Object timeObj = lua_getparam(2);
385
386 if (!lua_isuserdata(choreObj) || lua_tag(choreObj) != MKTAG('C','H','O','R') || !lua_isnumber(timeObj))
387 return;
388
389 int chore = lua_getuserdata(choreObj);
390 float time = lua_getnumber(timeObj);
391 Chore *c = EMIChore::getPool().getObject(chore);
392 if (c) {
393 if (!c->isPlaying()) {
394 warning("AdvanceChore() called on stopped chore %s (%s)",
395 c->getName(), c->getOwner()->getFilename().c_str());
396 if (c->isLooping()) {
397 c->getOwner()->playChoreLooping(c->getName());
398 } else {
399 c->getOwner()->playChore(c->getName());
400 }
401 }
402 c->advance(time * 1000);
403 }
404 }
405
406 // TODO: Implement, verify, and rename parameters
CompleteChore()407 void Lua_V2::CompleteChore() {
408 lua_Object param1 = lua_getparam(1);
409 lua_Object param2 = lua_getparam(2);
410
411 if (!lua_isuserdata(param1) || !lua_isnumber(param2))
412 error("Lua_V2::CompleteChore - Unknown params");
413
414 // Guesswork based on StopChore:
415 int chore = lua_getuserdata(param1);
416 float time = lua_getnumber(param2);
417
418 error("Lua_V2::CompleteChore(%d, %f) - TODO: Implement opcode", chore, time);
419 }
420
SetActorSortOrder()421 void Lua_V2::SetActorSortOrder() {
422 lua_Object actorObj = lua_getparam(1);
423 lua_Object orderObj = lua_getparam(2);
424
425 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
426 return;
427
428 if (!lua_isnumber(orderObj))
429 return;
430
431 Actor *actor = getactor(actorObj);
432 int order = (int)lua_getnumber(orderObj);
433 actor->setSortOrder(order);
434
435 g_emi->invalidateSortOrder();
436 }
437
GetActorSortOrder()438 void Lua_V2::GetActorSortOrder() {
439 lua_Object actorObj = lua_getparam(1);
440
441 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
442 return;
443
444 Actor *actor = getactor(actorObj);
445 lua_pushnumber(actor->getEffectiveSortOrder());
446 }
447
ActorActivateShadow()448 void Lua_V2::ActorActivateShadow() {
449 lua_Object actorObj = lua_getparam(1);
450 lua_Object activeObj = lua_getparam(2);
451 lua_Object planeObj = lua_getparam(3);
452
453 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
454 return;
455
456 Actor *actor = getactor(actorObj);
457 if (!actor)
458 return;
459 bool active = (int)lua_getnumber(activeObj) == 1;
460 const char *plane = nullptr;
461 if (lua_isstring(planeObj))
462 plane = lua_getstring(planeObj);
463 actor->activateShadow(active, plane);
464 }
465
ActorStopMoving()466 void Lua_V2::ActorStopMoving() {
467 lua_Object actorObj = lua_getparam(1);
468
469 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
470 return;
471
472 Actor *actor = getactor(actorObj);
473
474 actor->stopWalking();
475 actor->stopTurning();
476
477 warning("Lua_V2::ActorStopMoving, actor: %s", actor->getName().c_str());
478 // FIXME: Inspect the rest of the code to see if there's anything else missing
479 }
480
ActorLookAt()481 void Lua_V2::ActorLookAt() {
482 lua_Object actorObj = lua_getparam(1);
483 lua_Object xObj = lua_getparam(2);
484 lua_Object yObj = lua_getparam(3);
485 lua_Object zObj = lua_getparam(4);
486 lua_Object rateObj = lua_getparam(5);
487
488 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A', 'C', 'T', 'R'))
489 return;
490 Actor *actor = getactor(actorObj);
491 if (!actor->getCurrentCostume())
492 return;
493
494 if (lua_isnumber(rateObj))
495 actor->setLookAtRate(lua_getnumber(rateObj));
496
497 // Look at nothing
498 if (lua_isnil(xObj)) {
499 if (actor->isLookAtVectorZero())
500 return;
501
502 actor->setLookAtVectorZero();
503 actor->setLooking(false);
504 if (lua_isnumber(yObj) && lua_getnumber(yObj) > 0)
505 actor->setLookAtRate(lua_getnumber(yObj));
506 return;
507 } else if (lua_isnumber(xObj)) { // look at xyz
508 float fY;
509 float fZ;
510
511 float fX = lua_getnumber(xObj);
512
513 if (lua_isnumber(yObj))
514 fY = lua_getnumber(yObj);
515 else
516 fY = 0.0f;
517
518 if (lua_isnumber(zObj))
519 fZ = lua_getnumber(zObj);
520 else
521 fZ = 0.0f;
522
523 Math::Vector3d vector;
524 vector.set(fX, fY, fZ);
525 actor->setLookAtVector(vector);
526
527 if (lua_isnumber(rateObj))
528 actor->setLookAtRate(lua_getnumber(rateObj));
529 } else if (lua_isuserdata(xObj) && lua_tag(xObj) == MKTAG('A', 'C', 'T', 'R')) { // look at another actor
530 Actor *lookedAct = getactor(xObj);
531 actor->setLookAtActor(lookedAct);
532
533 if (lua_isnumber(yObj))
534 actor->setLookAtRate(lua_getnumber(yObj));
535 } else {
536 return;
537 }
538
539 actor->setLooking(true);
540 }
541
GetActorWorldPos()542 void Lua_V2::GetActorWorldPos() {
543 lua_Object actorObj = lua_getparam(1);
544
545 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
546 return;
547
548 Actor *actor = getactor(actorObj);
549 if (!actor)
550 return;
551
552 Math::Vector3d pos = actor->getWorldPos();
553 lua_pushnumber(pos.x());
554 lua_pushnumber(pos.y());
555 lua_pushnumber(pos.z());
556 }
557
PutActorInSet()558 void Lua_V2::PutActorInSet() {
559 lua_Object actorObj = lua_getparam(1);
560 lua_Object setObj = lua_getparam(2);
561
562 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
563 return;
564
565 Actor *actor = getactor(actorObj);
566
567 if (!lua_isstring(setObj) && !lua_isnil(setObj)) {
568 lua_pushnil();
569 return;
570 }
571
572 const char *set = lua_getstring(setObj);
573
574 // FIXME verify adding actor to set
575 if (!set) {
576 actor->putInSet("");
577 lua_pushnil();
578 } else {
579 if (!actor->isInSet(set)) {
580 actor->putInSet(set);
581 }
582 lua_pushnumber(1.0);
583 }
584 }
585
SetActorRestChore()586 void Lua_V2::SetActorRestChore() {
587 lua_Object actorObj = lua_getparam(1);
588 lua_Object choreObj = lua_getparam(2);
589 lua_Object costumeObj = lua_getparam(3);
590 Costume *costume = nullptr;
591 int chore = -1;
592
593 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R') ||
594 (!lua_isstring(choreObj) && !lua_isnil(choreObj))) {
595 return;
596 }
597
598 Actor *actor = getactor(actorObj);
599
600 setChoreAndCostume(choreObj, costumeObj, actor, costume, chore);
601
602 actor->setRestChore(chore, costume);
603 }
604
SetActorWalkChore()605 void Lua_V2::SetActorWalkChore() {
606 lua_Object actorObj = lua_getparam(1);
607 lua_Object choreObj = lua_getparam(2);
608 lua_Object costumeObj = lua_getparam(3);
609 Costume *costume = nullptr;
610 int chore = -1;
611
612 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R') ||
613 (!lua_isstring(choreObj) && !lua_isnil(choreObj))) {
614 return;
615 }
616
617 Actor *actor = getactor(actorObj);
618
619 setChoreAndCostume(choreObj, costumeObj, actor, costume, chore);
620
621 actor->setWalkChore(chore, costume);
622 }
623
SetActorTurnChores()624 void Lua_V2::SetActorTurnChores() {
625 lua_Object actorObj = lua_getparam(1);
626 lua_Object leftChoreObj = lua_getparam(2);
627 lua_Object rightChoreObj = lua_getparam(3);
628 lua_Object costumeObj = lua_getparam(4);
629 Costume *costume;
630
631 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R')) {
632 return;
633 } else if (!lua_isnil(leftChoreObj) && !lua_isstring(leftChoreObj)) {
634 return;
635 } else if (!lua_isnil(rightChoreObj) && !lua_isstring(rightChoreObj)) {
636 return;
637 }
638
639 Actor *actor = getactor(actorObj);
640
641 if (!findCostume(costumeObj, actor, &costume))
642 return;
643
644 int leftChore = costume->getChoreId(lua_getstring(leftChoreObj));
645 int rightChore = costume->getChoreId(lua_getstring(rightChoreObj));
646
647 actor->setTurnChores(leftChore, rightChore, costume);
648 }
649
650
651
SetActorTalkChore()652 void Lua_V2::SetActorTalkChore() {
653 lua_Object actorObj = lua_getparam(1);
654 lua_Object indexObj = lua_getparam(2);
655 lua_Object choreObj = lua_getparam(3);
656 lua_Object costumeObj = lua_getparam(4);
657 Costume *costume = nullptr;
658 int chore = -1;
659
660 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R') ||
661 !lua_isnumber(indexObj) ||
662 (!lua_isstring(choreObj) && !lua_isnil(choreObj))) {
663 return;
664 }
665
666 int index = (int)lua_getnumber(indexObj);
667 if (index < 0 || index >= 16)
668 return;
669
670 Actor *actor = getactor(actorObj);
671
672 setChoreAndCostume(choreObj, costumeObj, actor, costume, chore);
673
674 actor->setTalkChore(index + 1, chore, costume);
675 }
676
SetActorMumblechore()677 void Lua_V2::SetActorMumblechore() {
678 lua_Object actorObj = lua_getparam(1);
679 lua_Object choreObj = lua_getparam(2);
680 lua_Object costumeObj = lua_getparam(3);
681 Costume *costume = nullptr;
682 int chore = -1;
683
684 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R') ||
685 (!lua_isstring(choreObj) && !lua_isnil(choreObj))) {
686 return;
687 }
688
689 Actor *actor = getactor(actorObj);
690
691 setChoreAndCostume(choreObj, costumeObj, actor, costume, chore);
692
693 actor->setMumbleChore(chore, costume);
694 }
695
GetActorChores()696 void Lua_V2::GetActorChores() {
697 lua_Object actorObj = lua_getparam(1);
698 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
699 return;
700 Actor *actor = getactor(actorObj);
701 const Common::List<Costume *> &costumes = actor->getCostumes();
702
703 lua_Object result = lua_createtable();
704 int count = 0;
705 for (Common::List<Costume *>::const_iterator it = costumes.begin(); it != costumes.end(); ++it) {
706 const Common::List<Chore *> &playingChores = (*it)->getPlayingChores();
707 for (Common::List<Chore *>::const_iterator cit = playingChores.begin(); cit != playingChores.end(); ++cit) {
708 lua_pushobject(result);
709 lua_pushnumber(count++);
710 lua_pushusertag(((EMIChore *)*cit)->getId(), MKTAG('C', 'H', 'O', 'R'));
711 lua_settable();
712 }
713 }
714 lua_pushobject(result);
715 lua_pushstring("count");
716 lua_pushnumber(count);
717 lua_settable();
718
719 lua_pushobject(result);
720 }
721
722 // Helper function, not called from LUA directly
findCostume(lua_Object costumeObj,Actor * actor,Costume ** costume)723 bool Lua_V2::findCostume(lua_Object costumeObj, Actor *actor, Costume **costume) {
724 *costume = nullptr;
725 if (lua_isnil(costumeObj)) {
726 *costume = actor->getCurrentCostume();
727 } else {
728 if (lua_isstring(costumeObj)) {
729 const char *costumeName = lua_getstring(costumeObj);
730 *costume = actor->findCostume(costumeName);
731 if (*costume == nullptr) {
732 actor->pushCostume(costumeName);
733 *costume = actor->findCostume(costumeName);
734 }
735 }
736 }
737 return (*costume != nullptr);
738 }
739
PlayActorChore()740 void Lua_V2::PlayActorChore() {
741 lua_Object actorObj = lua_getparam(1);
742 lua_Object choreObj = lua_getparam(2);
743 lua_Object costumeObj = lua_getparam(3);
744 lua_Object modeObj = lua_getparam(4);
745 lua_Object fadeTimeObj = lua_getparam(5);
746
747 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
748 return;
749
750 Actor *actor = getactor(actorObj);
751
752 if (!lua_isstring(choreObj) || !lua_isstring(costumeObj))
753 lua_pushnil();
754
755 bool mode = false;
756 float fadeTime = 0.0f;
757
758 if (!lua_isnil(modeObj)) {
759 if (lua_getnumber(modeObj) != 0.0)
760 mode = true;
761 }
762
763 if (!lua_isnil(fadeTimeObj)) {
764 if (lua_isnumber(fadeTimeObj))
765 fadeTime = lua_getnumber(fadeTimeObj);
766 }
767
768 const char *choreName = lua_getstring(choreObj);
769
770 Costume *costume;
771 if (!findCostume(costumeObj, actor, &costume))
772 return;
773
774 EMIChore *chore = (EMIChore *)costume->getChore(choreName);
775 if (mode) {
776 costume->playChoreLooping(choreName, (int)(fadeTime * 1000));
777 } else {
778 costume->playChore(choreName, (int)(fadeTime * 1000));
779 }
780 if (chore) {
781 lua_pushusertag(chore->getId(), MKTAG('C','H','O','R'));
782 } else {
783 lua_pushnil();
784 }
785
786 }
787
StopActorChores()788 void Lua_V2::StopActorChores() {
789 lua_Object actorObj = lua_getparam(1);
790 // Guesswork for boolean parameter
791 bool ignoreLoopingChores = getbool(2);
792
793 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
794 return;
795
796 Actor *actor = getactor(actorObj);
797 if (!actor)
798 return;
799
800 actor->stopAllChores(ignoreLoopingChores);
801 }
802
SetActorLighting()803 void Lua_V2::SetActorLighting() {
804 lua_Object actorObj = lua_getparam(1);
805 lua_Object lightModeObj = lua_getparam(2);
806
807 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
808 return;
809
810 Actor *actor = getactor(actorObj);
811 if (!actor)
812 return;
813
814 if (lua_isnil(lightModeObj) || !lua_isnumber(lightModeObj))
815 return;
816
817 int lightMode = (int)lua_getnumber(lightModeObj);
818 actor->setLightMode((Actor::LightMode)lightMode);
819 }
820
SetActorCollisionMode()821 void Lua_V2::SetActorCollisionMode() {
822 lua_Object actorObj = lua_getparam(1);
823 lua_Object modeObj = lua_getparam(2);
824
825 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
826 return;
827
828 Actor *actor = getactor(actorObj);
829 assert(actor);
830 int mode = (int)lua_getnumber(modeObj);
831
832 Actor::CollisionMode m;
833 switch (mode) {
834 case Actor::CollisionOff:
835 m = Actor::CollisionOff;
836 break;
837 case Actor::CollisionBox:
838 m = Actor::CollisionBox;
839 break;
840 case Actor::CollisionSphere:
841 m = Actor::CollisionSphere;
842 break;
843 default:
844 warning("Lua_V2::SetActorCollisionMode(): wrong collisionmode: %d, using default 0", mode);
845 m = Actor::CollisionOff;
846 }
847 actor->setCollisionMode(m);
848 }
849
SetActorCollisionScale()850 void Lua_V2::SetActorCollisionScale() {
851 lua_Object actorObj = lua_getparam(1);
852 lua_Object scaleObj = lua_getparam(2);
853
854 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
855 return;
856
857 Actor *actor = getactor(actorObj);
858 assert(actor);
859
860 float scale = lua_getnumber(scaleObj);
861 actor->setCollisionScale(scale);
862 }
863
GetActorPuckVector()864 void Lua_V2::GetActorPuckVector() {
865 lua_Object actorObj = lua_getparam(1);
866 lua_Object addObj = lua_getparam(2);
867
868 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R')) {
869 lua_pushnil();
870 return;
871 }
872
873 Actor *actor = getactor(actorObj);
874 // Note: The wear chore of dumbshadow.cos is only started from Lua if
875 // GetActorPuckVector returns a non-nil value. The original engine seems
876 // to return nil for all actors that have never followed walkboxes.
877 if (!actor || !actor->hasFollowedBoxes()) {
878 lua_pushnil();
879 return;
880 }
881
882 Math::Vector3d result = actor->getPuckVector();
883 if (!lua_isnil(addObj))
884 result += actor->getPos();
885
886 lua_pushnumber(result.x());
887 lua_pushnumber(result.y());
888 lua_pushnumber(result.z());
889 }
890
SetActorHeadLimits()891 void Lua_V2::SetActorHeadLimits() {
892 lua_Object actorObj = lua_getparam(1);
893 lua_Object yawObj = lua_getparam(2);
894 lua_Object maxPitchObj = lua_getparam(3);
895 lua_Object minPitchObj = lua_getparam(4);
896
897 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
898 return;
899
900 Actor *actor = getactor(actorObj);
901 if (!actor)
902 return;
903
904 if (lua_isnumber(yawObj) && lua_isnumber(minPitchObj) && lua_isnumber(maxPitchObj)) {
905 float yaw = lua_getnumber(yawObj);
906 float maxPitch = lua_getnumber(maxPitchObj);
907 float minPitch = lua_getnumber(minPitchObj);
908 actor->setHeadLimits(yaw / 2, maxPitch, -minPitch);
909 }
910 }
911
SetActorHead()912 void Lua_V2::SetActorHead() {
913 lua_Object actorObj = lua_getparam(1);
914 lua_Object jointObj = lua_getparam(2);
915 lua_Object xObj = lua_getparam(3);
916 lua_Object yObj = lua_getparam(4);
917 lua_Object zObj = lua_getparam(5);
918
919 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A', 'C', 'T', 'R'))
920 return;
921
922 Actor *actor = getactor(actorObj);
923 if (!actor)
924 return;
925
926 if (lua_isstring(jointObj)) {
927 const char *joint = lua_getstring(jointObj);
928 Math::Vector3d offset;
929 offset.x() = lua_getnumber(xObj);
930 offset.y() = lua_getnumber(yObj);
931 offset.z() = lua_getnumber(zObj);
932 actor->setHead(joint, offset);
933 }
934 }
935
SetActorFOV()936 void Lua_V2::SetActorFOV() {
937 lua_Object actorObj = lua_getparam(1);
938 lua_Object fovObj = lua_getparam(2);
939
940 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
941 return;
942
943 Actor *actor = getactor(actorObj);
944 if (!actor)
945 return;
946
947 if (lua_isnumber(fovObj)) {
948 float fov = lua_getnumber(fovObj);
949 // FIXME: implement missing code
950 //actor->func(fov); // cos(fov * some tuntime val * 0.5)
951 warning("Lua_V2::SetActorFOV: implement opcode. actor: %s, param: %f", actor->getName().c_str(), fov);
952 }
953 }
954
AttachActor()955 void Lua_V2::AttachActor() {
956 // Missing lua parts
957 lua_Object attachedObj = lua_getparam(1);
958 lua_Object actorObj = lua_getparam(2);
959 lua_Object jointObj = lua_getparam(3);
960
961 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A', 'C', 'T', 'R'))
962 return;
963
964 Actor *actor = getactor(actorObj);
965 if (!actor)
966 return;
967
968 if (!lua_isuserdata(attachedObj) || lua_tag(attachedObj) != MKTAG('A', 'C', 'T', 'R'))
969 return;
970
971 Actor *attached = getactor(attachedObj);
972 if (!attached)
973 return;
974
975 const char *joint = nullptr;
976 if (!lua_isnil(jointObj)) {
977 joint = lua_getstring(jointObj);
978 }
979
980 attached->attachToActor(actor, joint);
981 Debug::debug(Debug::Actors | Debug::Scripts, "Lua_V2::AttachActor: attaching %s to %s (on %s)", attached->getName().c_str(), actor->getName().c_str(), joint ? joint : "(none)");
982
983 g_emi->invalidateSortOrder();
984 }
985
DetachActor()986 void Lua_V2::DetachActor() {
987 // Missing lua parts
988 lua_Object attachedObj = lua_getparam(1);
989
990 if (!lua_isuserdata(attachedObj) || lua_tag(attachedObj) != MKTAG('A','C','T','R'))
991 return;
992
993 Actor *attached = getactor(attachedObj);
994 if (!attached)
995 return;
996
997 Debug::debug(Debug::Actors | Debug::Scripts, "Lua_V2::DetachActor: detaching %s from parent actor", attached->getName().c_str());
998 attached->detach();
999
1000 g_emi->invalidateSortOrder();
1001 }
1002
WalkActorToAvoiding()1003 void Lua_V2::WalkActorToAvoiding() {
1004 lua_Object actorObj = lua_getparam(1);
1005 lua_Object actor2Obj = lua_getparam(2);
1006 lua_Object xObj = lua_getparam(3);
1007 lua_Object yObj = lua_getparam(4);
1008 lua_Object zObj = lua_getparam(5);
1009
1010 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
1011 return;
1012
1013 if (!lua_isuserdata(actor2Obj) || lua_tag(actor2Obj) != MKTAG('A','C','T','R'))
1014 return;
1015
1016 Math::Vector3d destVec;
1017 Actor *actor = getactor(actorObj);
1018 if (!lua_isnumber(xObj)) {
1019 if (!lua_isuserdata(xObj) || lua_tag(xObj) != MKTAG('A','C','T','R'))
1020 return;
1021 Actor *destActor = getactor(xObj);
1022 destVec = destActor->getPos();
1023 } else {
1024 float x = lua_getnumber(xObj);
1025 float y = lua_getnumber(yObj);
1026 float z = lua_getnumber(zObj);
1027 destVec.set(x, y, z);
1028 }
1029
1030 // TODO: Make this actually avoid the second actor
1031
1032 actor->walkTo(destVec);
1033 }
1034
WalkActorVector()1035 void Lua_V2::WalkActorVector() {
1036 lua_Object actorObj = lua_getparam(1);
1037 // lua_Object xObj = lua_getparam(3);
1038 // lua_Object yObj = lua_getparam(4);
1039 // lua_Object zObj = lua_getparam(5);
1040 // lua_Object param6Obj = lua_getparam(6);
1041
1042 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A', 'C', 'T', 'R'))
1043 return;
1044
1045 // Actor *actor = static_cast<Actor *>(lua_getuserdata(actorObj));
1046 Actor *actor2 = getactor(actorObj);
1047
1048 // TODO whole below part need rewrote to much original
1049 float moveHoriz, moveVert;
1050
1051 // Third option is the "left/right" movement
1052 moveHoriz = luaL_check_number(2);
1053 // Fourth Option is the "up/down" movement
1054 moveVert = luaL_check_number(4);
1055
1056 // Get the direction the camera is pointing
1057 Set::Setup *setup = g_grim->getCurrSet()->getCurrSetup();
1058 Math::Vector3d cameraVector(0, 0, 1);
1059
1060 setup->_rot.transform(&cameraVector, false);
1061
1062 // find the angle the camera direction is around the unit circle
1063 Math::Angle cameraYaw = Math::Angle::arcTangent2(cameraVector.x(), cameraVector.z());
1064
1065 // Handle the turning
1066 Math::Vector3d adjustVector(moveHoriz, 0, moveVert);
1067 // find the angle the adjust vector is around the unit circle
1068 Math::Angle adjustYaw = Math::Angle::arcTangent2(adjustVector.x(), adjustVector.z());
1069
1070 Math::Angle yaw = cameraYaw + adjustYaw;
1071
1072 // set the new direction or walk forward
1073 if (actor2->getYaw() != yaw)
1074 actor2->turnTo(0, yaw, 0, true);
1075 actor2->walkForward();
1076 }
1077
EnableActorPuck()1078 void Lua_V2::EnableActorPuck() {
1079 lua_Object actorObj = lua_getparam(1);
1080
1081 if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
1082 return;
1083
1084 Actor *actor = getactor(actorObj);
1085 if (!actor)
1086 return;
1087
1088 bool enable = getbool(2);
1089
1090 // FIXME: Implement.
1091 warning("Lua_V2::EnableActorPuck: stub, actor: %s enable: %s", actor->getName().c_str(), enable ? "TRUE" : "FALSE");
1092 }
1093
1094 // Helper function, not called from LUA directly
setChoreAndCostume(lua_Object choreObj,lua_Object costumeObj,Actor * actor,Costume * & costume,int & chore)1095 void Lua_V2::setChoreAndCostume(lua_Object choreObj, lua_Object costumeObj, Actor *actor, Costume *&costume, int &chore) {
1096 if (lua_isnil(choreObj)) {
1097 return;
1098 }
1099
1100 if (!findCostume(costumeObj, actor, &costume))
1101 return;
1102
1103 const char *choreStr = lua_getstring(choreObj);
1104 chore = costume->getChoreId(choreStr);
1105 }
1106
1107 } // end of namespace Grim
1108