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