1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM 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 "lastexpress/entities/entity.h"
24 
25 #include "lastexpress/data/sequence.h"
26 
27 #include "lastexpress/game/action.h"
28 #include "lastexpress/game/entities.h"
29 #include "lastexpress/game/logic.h"
30 #include "lastexpress/game/object.h"
31 #include "lastexpress/game/savegame.h"
32 #include "lastexpress/game/savepoint.h"
33 #include "lastexpress/game/state.h"
34 #include "lastexpress/game/scenes.h"
35 
36 #include "lastexpress/lastexpress.h"
37 
38 namespace LastExpress {
39 
40 //////////////////////////////////////////////////////////////////////////
41 // EntityData
42 //////////////////////////////////////////////////////////////////////////
43 
~EntityCallData()44 EntityData::EntityCallData::~EntityCallData() {
45 	SAFE_DELETE(frame);
46 	SAFE_DELETE(frame1);
47 
48 	SAFE_DELETE(sequence);
49 	SAFE_DELETE(sequence2);
50 	SAFE_DELETE(sequence3);
51 }
52 
syncString(Common::Serializer & s,Common::String & string,uint length) const53 void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, uint length) const {
54 	assert(length <= 13);
55 	assert(string.size() <= 13);
56 
57 	char seqName[13];
58 	memset(&seqName, 0, length);
59 
60 	if (s.isSaving())
61 		strcpy((char *)&seqName, string.c_str());
62 
63 	s.syncBytes((byte *)&seqName, length);
64 
65 	if (s.isLoading())
66 		string = seqName;
67 }
68 
saveLoadWithSerializer(Common::Serializer & s)69 void EntityData::EntityCallData::saveLoadWithSerializer(Common::Serializer &s) {
70 	for (uint i = 0; i < ARRAYSIZE(callbacks); i++)
71 		s.syncAsByte(callbacks[i]);
72 
73 	s.syncAsByte(currentCall);
74 	s.syncAsUint16LE(entityPosition);
75 	s.syncAsUint16LE(location);
76 	s.syncAsUint16LE(car);
77 	s.syncAsByte(field_497);
78 	s.syncAsByte(entity);
79 	s.syncAsByte(inventoryItem);
80 	s.syncAsByte(direction);
81 	s.syncAsUint16LE(field_49B);
82 	s.syncAsUint16LE(currentFrame);
83 	s.syncAsUint16LE(currentFrame2);
84 	s.syncAsUint16LE(field_4A1);
85 	s.syncAsUint16LE(field_4A3);
86 	s.syncAsByte(clothes);
87 	s.syncAsByte(position);
88 	s.syncAsByte(car2);
89 	s.syncAsByte(doProcessEntity);
90 	s.syncAsByte(field_4A9);
91 	s.syncAsByte(field_4AA);
92 	s.syncAsByte(directionSwitch);
93 
94 	// Sync strings
95 	syncString(s, sequenceName, 13);
96 	syncString(s, sequenceName2, 13);
97 	syncString(s, sequenceNamePrefix, 7);
98 	syncString(s, sequenceNameCopy, 13);
99 
100 	// Skip pointers to frame & sequences
101 	// (we are using a compressed stream, so we cannot seek on load)
102 	if (s.isLoading()) {
103 		byte empty[5 * 4];
104 		s.syncBytes(empty, 5 * 4);
105 	} else {
106 		s.skip(5 * 4);
107 	}
108 }
109 
110 //////////////////////////////////////////////////////////////////////////
111 // EntityData
112 //////////////////////////////////////////////////////////////////////////
getParameters(uint callback,byte index) const113 EntityData::EntityParameters *EntityData::getParameters(uint callback, byte index) const {
114 	if (callback >= 9)
115 		error("[EntityData::getParameters] Invalid callback value (was: %d, max: 9)", callback);
116 
117 	if (index >= 4)
118 		error("[EntityData::getParameters] Invalid index value (was: %d, max: 4)", index);
119 
120 	return _parameters[callback].parameters[index];
121 }
122 
getCallback(uint callback) const123 byte EntityData::getCallback(uint callback) const {
124 	if (callback >= 16)
125 		error("[EntityData::getCallback] Invalid callback value (was: %d, max: 16)", callback);
126 
127 	return _data.callbacks[callback];
128 }
129 
setCallback(uint callback,byte index)130 void EntityData::setCallback(uint callback, byte index) {
131 	if (callback >= 16)
132 		error("[EntityData::setCallback] Invalid callback value (was: %d, max: 16)", callback);
133 
134 	_data.callbacks[callback] = index;
135 }
136 
updateParameters(uint32 index) const137 void EntityData::updateParameters(uint32 index) const {
138 	if (index < 8)
139 		getParameters(8, 0)->update(index);
140 	else if (index < 16)
141 		getParameters(8, 1)->update(index - 8);
142 	else if (index < 24)
143 		getParameters(8, 2)->update(index - 16);
144 	else if (index < 32)
145 		getParameters(8, 3)->update(index - 24);
146 	else
147 		error("[EntityData::updateParameters] Invalid param index to update (was:%d, max:32)", index);
148 }
149 
saveLoadWithSerializer(Common::Serializer & s,const Common::Array<TypeSetter> * paramsTypeSetters)150 void EntityData::saveLoadWithSerializer(Common::Serializer &s, const Common::Array<TypeSetter>* paramsTypeSetters) {
151 	if (s.isSaving()) {
152 		for (uint i = 0; i < ARRAYSIZE(_parameters); i++)
153 			_parameters[i].saveLoadWithSerializer(s);
154 
155 		_data.saveLoadWithSerializer(s);
156 	} else {
157 		// to correctly deserialize parameters, we need to know their runtime type
158 		// but we don't know it until callbacks[] array will be deserialized
159 		// all types of parameters are serialized to 32*4 bytes
160 		// (the original game has same-size-PODs and just memcpy-s them.
161 		// *sigh* Why does this implementation even need the extra byte in strings?
162 		// Well, big-endian vs little-endian is also a thing...)
163 		byte buf[ARRAYSIZE(_parameters) * 32 * 4];
164 		s.syncBytes(buf, sizeof(buf));
165 
166 		_data.saveLoadWithSerializer(s);
167 
168 		for (uint i = 0; i < 8; i++) {
169 			if (!paramsTypeSetters || _data.callbacks[i] >= paramsTypeSetters->size())
170 				resetParametersType<EntityParametersIIII, EntityParametersIIII, EntityParametersIIII>(&_parameters[i]);
171 			else
172 				(*paramsTypeSetters)[_data.callbacks[i]](&_parameters[i]);
173 		}
174 		Common::MemoryReadStream paramsStream(buf, sizeof(buf));
175 		Common::Serializer paramsSerializer(&paramsStream, NULL);
176 		for (uint i = 0; i < ARRAYSIZE(_parameters); i++)
177 			_parameters[i].saveLoadWithSerializer(paramsSerializer);
178 	}
179 }
180 
181 //////////////////////////////////////////////////////////////////////////
182 // Entity
183 //////////////////////////////////////////////////////////////////////////
Entity(LastExpressEngine * engine,EntityIndex index)184 Entity::Entity(LastExpressEngine *engine, EntityIndex index) : _engine(engine), _entityIndex(index) {
185 	_data = new EntityData();
186 
187 	// Add first empty entry to callbacks array
188 	_callbacks.push_back(NULL);
189 	_paramsTypeSetters.push_back(&EntityData::resetParametersType<EntityData::EntityParametersIIII, EntityData::EntityParametersIIII, EntityData::EntityParametersIIII>);
190 }
191 
~Entity()192 Entity::~Entity() {
193 	for (uint i = 0; i < _callbacks.size(); i++)
194 		SAFE_DELETE(_callbacks[i]);
195 
196 	_callbacks.clear();
197 
198 	SAFE_DELETE(_data);
199 
200 	// Zero-out passed pointers
201 	_engine = NULL;
202 }
203 
setup(ChapterIndex index)204 void Entity::setup(ChapterIndex index) {
205 	switch(index) {
206 	case kChapterAll:
207 		getSavePoints()->setCallback(_entityIndex, _callbacks[_data->getCurrentCallback()]);
208 		break;
209 
210 	case kChapter1:
211 		setup_chapter1();
212 		break;
213 
214 	case kChapter2:
215 		setup_chapter2();
216 		break;
217 
218 	case kChapter3:
219 		setup_chapter3();
220 		break;
221 
222 	case kChapter4:
223 		setup_chapter4();
224 		break;
225 
226 	case kChapter5:
227 		setup_chapter5();
228 		break;
229 
230 	default:
231 		break;
232 	}
233 }
234 
235 //////////////////////////////////////////////////////////////////////////
236 // Shared functions
237 //////////////////////////////////////////////////////////////////////////
238 
reset(const SavePoint & savepoint,ClothesIndex maxClothes,bool resetItem)239 void Entity::reset(const SavePoint &savepoint, ClothesIndex maxClothes, bool resetItem) {
240 	EXPOSE_PARAMS(EntityData::EntityParametersIIII)
241 
242 	switch (savepoint.action) {
243 	default:
244 		break;
245 
246 	case kAction1:
247 		if (maxClothes != kClothesDefault) {
248 			// Select next available clothes
249 			getData()->clothes = (ClothesIndex)(getData()->clothes + 1);
250 			if (getData()->clothes > maxClothes)
251 				getData()->clothes = kClothesDefault;
252 		}
253 		break;
254 
255 	case kActionNone:
256 		if (getEntities()->updateEntity(_entityIndex, kCarGreenSleeping, (EntityPosition)params->param1))
257 			params->param1 = (params->param1 == 10000) ? 0 : 10000;
258 		break;
259 
260 	case kActionDefault:
261 		getData()->entityPosition = kPositionNone;
262 		getData()->location = kLocationOutsideCompartment;
263 		getData()->car = kCarGreenSleeping;
264 
265 		if (resetItem)
266 			getData()->inventoryItem = kItemInvalid;
267 
268 		params->param1 = 10000;
269 		break;
270 	}
271 }
272 
savegame(const SavePoint & savepoint)273 void Entity::savegame(const SavePoint &savepoint) {
274 	EXPOSE_PARAMS(EntityData::EntityParametersIIII)
275 
276 	switch (savepoint.action) {
277 	default:
278 		break;
279 
280 	case kActionNone:
281 		callbackAction();
282 		break;
283 
284 	case kActionDefault:
285 		getSaveLoad()->saveGame((SavegameType)params->param1, _entityIndex, (EventIndex)params->param2);
286 		callbackAction();
287 		break;
288 	}
289 }
290 
savegameBloodJacket(byte callback)291 bool Entity::savegameBloodJacket(byte callback) {
292 	if (getProgress().jacket == kJacketBlood
293 	 && getEntities()->isDistanceBetweenEntities(_entityIndex, kEntityPlayer, 1000)
294 	 && !getEntities()->isInsideCompartments(kEntityPlayer)
295 	 && !getEntities()->checkFields10(kEntityPlayer)) {
296 		setCallback(callback);
297 		setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
298 		return true;
299 	}
300 	return false;
301 }
302 
playSound(const SavePoint & savepoint,bool resetItem,SoundFlag flag)303 void Entity::playSound(const SavePoint &savepoint, bool resetItem, SoundFlag flag) {
304 	EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
305 
306 	switch (savepoint.action) {
307 	default:
308 		break;
309 
310 	case kActionEndSound:
311 		callbackAction();
312 		break;
313 
314 	case kActionDefault:
315 		if (resetItem)
316 			getData()->inventoryItem = kItemNone;
317 
318 		getSound()->playSound(_entityIndex, (char *)&params->seq1, flag);
319 		break;
320 	}
321 }
322 
draw(const SavePoint & savepoint,bool handleExcuseMe)323 void Entity::draw(const SavePoint &savepoint, bool handleExcuseMe) {
324 	EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
325 
326 	switch (savepoint.action) {
327 	default:
328 		break;
329 
330 	case kActionExitCompartment:
331 		callbackAction();
332 		break;
333 
334 	case kActionExcuseMeCath:
335 		if (handleExcuseMe && !params->param4) {
336 			getSound()->excuseMe(_entityIndex);
337 			params->param4 = 1;
338 		}
339 		break;
340 
341 	case kActionDefault:
342 		getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq1);
343 		break;
344 	}
345 }
346 
draw2(const SavePoint & savepoint)347 void Entity::draw2(const SavePoint &savepoint) {
348 	EXPOSE_PARAMS(EntityData::EntityParametersSSII)
349 
350 	switch (savepoint.action) {
351 	default:
352 		break;
353 
354 	case kActionExitCompartment:
355 		callbackAction();
356 		break;
357 
358 	case kActionDefault:
359 		getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq1);
360 		getEntities()->drawSequenceRight((EntityIndex)params->param7, (char *)&params->seq2);
361 		break;
362 	}
363 }
364 
updateFromTicks(const SavePoint & savepoint)365 void Entity::updateFromTicks(const SavePoint &savepoint) {
366 	EXPOSE_PARAMS(EntityData::EntityParametersIIII)
367 
368 	switch (savepoint.action) {
369 	default:
370 		break;
371 
372 	case kActionNone:
373 		if (!Entity::updateParameter(params->param2, getState()->timeTicks, params->param1))
374 			break;
375 
376 		callbackAction();
377 		break;
378 	}
379 }
380 
updateFromTime(const SavePoint & savepoint)381 void Entity::updateFromTime(const SavePoint &savepoint) {
382 	EXPOSE_PARAMS(EntityData::EntityParametersIIII)
383 
384 	switch (savepoint.action) {
385 	default:
386 		break;
387 
388 	case kActionNone:
389 		if (!Entity::updateParameter(params->param2, getState()->time, params->param1))
390 			break;
391 
392 		callbackAction();
393 		break;
394 	}
395 }
396 
callbackActionOnDirection(const SavePoint & savepoint)397 void Entity::callbackActionOnDirection(const SavePoint &savepoint) {
398 	switch (savepoint.action) {
399 	default:
400 		break;
401 
402 	case kActionExitCompartment:
403 		callbackAction();
404 		break;
405 
406 	case kActionNone:
407 		if (getData()->direction != kDirectionRight)
408 			callbackAction();
409 		break;
410 	}
411 }
412 
callbackActionRestaurantOrSalon(const SavePoint & savepoint)413 void Entity::callbackActionRestaurantOrSalon(const SavePoint &savepoint) {
414 	switch (savepoint.action) {
415 	default:
416 		break;
417 
418 	case kActionNone:
419 	case kActionDefault:
420 		if (getEntities()->isSomebodyInsideRestaurantOrSalon())
421 			callbackAction();
422 		break;
423 	}
424 }
425 
updateEntity(const SavePoint & savepoint,bool handleExcuseMe)426 void Entity::updateEntity(const SavePoint &savepoint, bool handleExcuseMe) {
427 	EXPOSE_PARAMS(EntityData::EntityParametersIIII)
428 
429 	switch (savepoint.action) {
430 	default:
431 		break;
432 
433 	case kActionExcuseMeCath:
434 		if (handleExcuseMe)
435 			getSound()->excuseMeCath();
436 		break;
437 
438 	case kActionExcuseMe:
439 		if (handleExcuseMe)
440 			getSound()->excuseMe(_entityIndex);
441 		break;
442 
443 	case kActionNone:
444 	case kActionDefault:
445 		if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
446 			callbackAction();
447 		break;
448 	}
449 }
450 
callSavepoint(const SavePoint & savepoint,bool handleExcuseMe)451 void Entity::callSavepoint(const SavePoint &savepoint, bool handleExcuseMe) {
452 	EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
453 
454 	switch (savepoint.action) {
455 	default:
456 		break;
457 
458 	case kActionExitCompartment:
459 		if (!CURRENT_PARAM(1, 1))
460 			getSavePoints()->call(_entityIndex, (EntityIndex)params->param4, (ActionIndex)params->param5, (char *)&params->seq2);
461 		callbackAction();
462 		break;
463 
464 	case kActionExcuseMeCath:
465 		if (handleExcuseMe && !CURRENT_PARAM(1, 2)) {
466 			getSound()->excuseMe(_entityIndex);
467 			CURRENT_PARAM(1, 2) = 1;
468 		}
469 		break;
470 
471 	case kAction10:
472 		if (!CURRENT_PARAM(1, 1)) {
473 			getSavePoints()->call(_entityIndex, (EntityIndex)params->param4, (ActionIndex)params->param5, (char *)&params->seq2);
474 			CURRENT_PARAM(1, 1) = 1;
475 		}
476 		break;
477 
478 	case kActionDefault:
479 		getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq1);
480 		break;
481 	}
482 }
483 
enterExitCompartment(const SavePoint & savepoint,EntityPosition position1,EntityPosition position2,CarIndex car,ObjectIndex compartment,bool alternate,bool updateLocation)484 void Entity::enterExitCompartment(const SavePoint &savepoint, EntityPosition position1, EntityPosition position2, CarIndex car, ObjectIndex compartment, bool alternate, bool updateLocation) {
485 	EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
486 
487 	switch (savepoint.action) {
488 	default:
489 		break;
490 
491 	case kActionExitCompartment:
492 		getEntities()->exitCompartment(_entityIndex, (ObjectIndex)params->param4);
493 		if (position1)
494 			getData()->entityPosition = position1;
495 
496 		if (updateLocation)
497 			getData()->location = kLocationInsideCompartment;
498 
499 		callbackAction();
500 		break;
501 
502 	case kActionDefault:
503 		getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq1);
504 		getEntities()->enterCompartment(_entityIndex, (ObjectIndex)params->param4);
505 
506 		if (position1) {
507 			getData()->location = kLocationInsideCompartment;
508 
509 			if (getEntities()->isInsideCompartment(kEntityPlayer, car, position1) || getEntities()->isInsideCompartment(kEntityPlayer, car, position2)) {
510 				getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
511 				getSound()->playSound(kEntityPlayer, "BUMP");
512 				getScenes()->loadSceneFromObject(compartment, alternate);
513 			}
514 		}
515 		break;
516 	}
517 }
518 
goToCompartment(const SavePoint & savepoint,ObjectIndex compartmentFrom,EntityPosition positionFrom,Common::String sequenceFrom,Common::String sequenceTo)519 void Entity::goToCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, Common::String sequenceTo) {
520 	switch (savepoint.action) {
521 	default:
522 		break;
523 
524 	case kActionDefault:
525 		getData()->entityPosition = positionFrom;
526 		setCallback(1);
527 		setup_enterExitCompartment(sequenceFrom.c_str(), compartmentFrom);
528 		break;
529 
530 	case kActionCallback:
531 		switch (getCallback()) {
532 		default:
533 			break;
534 
535 		case 1:
536 			setCallback(2);
537 			setup_enterExitCompartment(sequenceTo.c_str(), compartmentFrom);
538 			break;
539 
540 		case 2:
541 			getData()->entityPosition = positionFrom;
542 			getEntities()->clearSequences(_entityIndex);
543 			callbackAction();
544 			break;
545 		}
546 		break;
547 	}
548 }
549 
goToCompartmentFromCompartment(const SavePoint & savepoint,ObjectIndex compartmentFrom,EntityPosition positionFrom,Common::String sequenceFrom,ObjectIndex compartmentTo,EntityPosition positionTo,Common::String sequenceTo)550 void Entity::goToCompartmentFromCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, ObjectIndex compartmentTo, EntityPosition positionTo, Common::String sequenceTo) {
551 	switch (savepoint.action) {
552 	default:
553 		break;
554 
555 	case kActionDefault:
556 		getData()->entityPosition = positionFrom;
557 		getData()->location = kLocationOutsideCompartment;
558 		setCallback(1);
559 		setup_enterExitCompartment(sequenceFrom.c_str(), compartmentFrom);
560 		break;
561 
562 	case kActionCallback:
563 		switch (getCallback()) {
564 		default:
565 			break;
566 
567 		case 1:
568 			setCallback(2);
569 			setup_updateEntity(kCarGreenSleeping, positionTo);
570 			break;
571 
572 		case 2:
573 			setCallback(3);
574 			setup_enterExitCompartment(sequenceTo.c_str(), compartmentTo);
575 			break;
576 
577 		case 3:
578 			getData()->location = kLocationInsideCompartment;
579 			getEntities()->clearSequences(_entityIndex);
580 			callbackAction();
581 			break;
582 		}
583 		break;
584 	}
585 }
586 
updatePosition(const SavePoint & savepoint,bool handleExcuseMe)587 void Entity::updatePosition(const SavePoint &savepoint, bool handleExcuseMe) {
588 	EXPOSE_PARAMS(EntityData::EntityParametersSIII)
589 
590 	switch (savepoint.action) {
591 	default:
592 		break;
593 
594 	case kActionExitCompartment:
595 		getEntities()->updatePositionExit(_entityIndex, (CarIndex)params->param4, (Position)params->param5);
596 		callbackAction();
597 		break;
598 
599 	case kActionExcuseMeCath:
600 		if (handleExcuseMe && !params->param6) {
601 			getSound()->excuseMe(_entityIndex);
602 			params->param6 = 1;
603 		}
604 		break;
605 
606 	case kActionDefault:
607 		getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq);
608 		getEntities()->updatePositionEnter(_entityIndex, (CarIndex)params->param4, (Position)params->param5);
609 		break;
610 	}
611 }
612 
callbackAction()613 void Entity::callbackAction() {
614 	if (getData()->currentCall == 0)
615 		error("[Entity::callbackAction] currentCall is already 0, cannot proceed");
616 
617 	getData()->currentCall--;
618 
619 	getSavePoints()->setCallback(_entityIndex, _callbacks[_data->getCurrentCallback()]);
620 
621 	getSavePoints()->call(_entityIndex, _entityIndex, kActionCallback);
622 }
623 
624 //////////////////////////////////////////////////////////////////////////
625 // Setup functions
626 //////////////////////////////////////////////////////////////////////////
setup(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter)627 void Entity::setup(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter) {
628 	debugC(6, kLastExpressDebugLogic, "Entity: %s()", name);
629 
630 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
631 	_data->setCurrentCallback(index);
632 	paramsTypeSetter(_data->getCurrentCallParameters());
633 
634 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
635 }
636 
setupI(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,uint param1)637 void Entity::setupI(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, uint param1) {
638 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%u)", name, param1);
639 
640 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
641 	_data->setCurrentCallback(index);
642 	paramsTypeSetter(_data->getCurrentCallParameters());
643 
644 	EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters();
645 	params->param1 = (unsigned int)param1;
646 
647 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
648 }
649 
setupII(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,uint param1,uint param2)650 void Entity::setupII(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, uint param1, uint param2) {
651 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u)", name, param1, param2);
652 
653 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
654 	_data->setCurrentCallback(index);
655 	paramsTypeSetter(_data->getCurrentCallParameters());
656 
657 	EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters();
658 	params->param1 = param1;
659 	params->param2 = param2;
660 
661 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
662 }
663 
setupIII(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,uint param1,uint param2,uint param3)664 void Entity::setupIII(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, uint param1, uint param2, uint param3) {
665 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %u)", name, param1, param2, param3);
666 
667 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
668 	_data->setCurrentCallback(index);
669 	paramsTypeSetter(_data->getCurrentCallParameters());
670 
671 	EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters();
672 	params->param1 = param1;
673 	params->param2 = param2;
674 	params->param3 = param3;
675 
676 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
677 }
678 
setupS(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,const char * seq1)679 void Entity::setupS(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, const char *seq1) {
680 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%s)", name, seq1);
681 
682 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
683 	_data->setCurrentCallback(index);
684 	paramsTypeSetter(_data->getCurrentCallParameters());
685 
686 	EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters();
687 	strncpy(params->seq1, seq1, 12);
688 
689 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
690 }
691 
setupSS(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,const char * seq1,const char * seq2)692 void Entity::setupSS(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, const char *seq1, const char *seq2) {
693 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %s)", name, seq1, seq2);
694 
695 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
696 	_data->setCurrentCallback(index);
697 	paramsTypeSetter(_data->getCurrentCallParameters());
698 
699 	EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII*)_data->getCurrentParameters();
700 	strncpy(params->seq1, seq1, 12);
701 	strncpy(params->seq2, seq2, 12);
702 
703 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
704 }
705 
setupSI(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,const char * seq1,uint param4)706 void Entity::setupSI(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, const char *seq1, uint param4) {
707 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u)", name, seq1, param4);
708 
709 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
710 	_data->setCurrentCallback(index);
711 	paramsTypeSetter(_data->getCurrentCallParameters());
712 
713 	EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS *)_data->getCurrentParameters();
714 	strncpy(params->seq1, seq1, 12);
715 	params->param4 = param4;
716 
717 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
718 }
719 
setupSII(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,const char * seq1,uint param4,uint param5)720 void Entity::setupSII(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, const char *seq1, uint param4, uint param5) {
721 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u)", name, seq1, param4, param5);
722 
723 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
724 	_data->setCurrentCallback(index);
725 	paramsTypeSetter(_data->getCurrentCallParameters());
726 
727 	EntityData::EntityParametersSIII *params = (EntityData::EntityParametersSIII *)_data->getCurrentParameters();
728 	strncpy(params->seq, seq1, 12);
729 	params->param4 = param4;
730 	params->param5 = param5;
731 
732 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
733 }
734 
setupSIII(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,const char * seq,uint param4,uint param5,uint param6)735 void Entity::setupSIII(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, const char *seq, uint param4, uint param5, uint param6) {
736 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u, %u)", name, seq, param4, param5, param6);
737 
738 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
739 	_data->setCurrentCallback(index);
740 	paramsTypeSetter(_data->getCurrentCallParameters());
741 
742 	EntityData::EntityParametersSIII *params = (EntityData::EntityParametersSIII *)_data->getCurrentParameters();
743 	strncpy(params->seq, seq, 12);
744 	params->param4 = param4;
745 	params->param5 = param5;
746 	params->param6 = param6;
747 
748 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
749 }
750 
setupSIIS(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,const char * seq1,uint param4,uint param5,const char * seq2)751 void Entity::setupSIIS(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, const char *seq1, uint param4, uint param5, const char *seq2) {
752 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u, %s)", name, seq1, param4, param5, seq2);
753 
754 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
755 	_data->setCurrentCallback(index);
756 	paramsTypeSetter(_data->getCurrentCallParameters());
757 
758 	EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS *)_data->getCurrentParameters();
759 	strncpy(params->seq1, seq1, 12);
760 	params->param4 = param4;
761 	params->param5 = param5;
762 	strncpy(params->seq2, seq2, 12);
763 
764 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
765 }
766 
setupSSI(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,const char * seq1,const char * seq2,uint param7)767 void Entity::setupSSI(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, const char *seq1, const char *seq2, uint param7) {
768 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %s, %u)", name, seq1, seq2, param7);
769 
770 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
771 	_data->setCurrentCallback(index);
772 	paramsTypeSetter(_data->getCurrentCallParameters());
773 
774 	EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII *)_data->getCurrentParameters();
775 	strncpy(params->seq1, seq1, 12);
776 	strncpy(params->seq2, seq2, 12);
777 	params->param7 = param7;
778 
779 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
780 }
781 
setupIS(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,uint param1,const char * seq)782 void Entity::setupIS(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, uint param1, const char *seq) {
783 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %s)", name, param1, seq);
784 
785 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
786 	_data->setCurrentCallback(index);
787 	paramsTypeSetter(_data->getCurrentCallParameters());
788 
789 	EntityData::EntityParametersISII *params = (EntityData::EntityParametersISII *)_data->getCurrentParameters();
790 	params->param1 = (unsigned int)param1;
791 	strncpy(params->seq, seq, 12);
792 
793 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
794 }
795 
setupISS(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,uint param1,const char * seq1,const char * seq2)796 void Entity::setupISS(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, uint param1, const char *seq1, const char *seq2) {
797 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %s, %s)", name, param1, seq1, seq2);
798 
799 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
800 	_data->setCurrentCallback(index);
801 	paramsTypeSetter(_data->getCurrentCallParameters());
802 
803 	EntityData::EntityParametersISSI *params = (EntityData::EntityParametersISSI *)_data->getCurrentParameters();
804 	params->param1 = param1;
805 	strncpy(params->seq1, seq1, 12);
806 	strncpy(params->seq2, seq2, 12);
807 
808 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
809 }
810 
setupIIS(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,uint param1,uint param2,const char * seq)811 void Entity::setupIIS(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, uint param1, uint param2, const char *seq) {
812 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %s)", name, param1, param2, seq);
813 
814 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
815 	_data->setCurrentCallback(index);
816 	paramsTypeSetter(_data->getCurrentCallParameters());
817 
818 	EntityData::EntityParametersIISI *params = (EntityData::EntityParametersIISI *)_data->getCurrentParameters();
819 	params->param1 = param1;
820 	params->param2 = param2;
821 	strncpy(params->seq, seq, 12);
822 
823 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
824 }
825 
setupIISS(const char * name,uint index,EntityData::TypeSetter paramsTypeSetter,uint param1,uint param2,const char * seq1,const char * seq2)826 void Entity::setupIISS(const char *name, uint index, EntityData::TypeSetter paramsTypeSetter, uint param1, uint param2, const char *seq1, const char *seq2) {
827 	debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %s, %s)", name, param1, param2, seq1, seq2);
828 
829 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
830 	_data->setCurrentCallback(index);
831 	paramsTypeSetter(_data->getCurrentCallParameters());
832 
833 	EntityData::EntityParametersIISS *params = (EntityData::EntityParametersIISS *)_data->getCurrentParameters();
834 	params->param1 = param1;
835 	params->param2 = param2;
836 	strncpy(params->seq1, seq1, 12);
837 	strncpy(params->seq2, seq2, 12);
838 
839 	_engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
840 }
841 
842 //////////////////////////////////////////////////////////////////////////
843 // Helper functions
844 //////////////////////////////////////////////////////////////////////////
845 
updateParameter(uint & parameter,uint timeType,uint delta) const846 bool Entity::updateParameter(uint &parameter, uint timeType, uint delta) const {
847 	if (!parameter)
848 		parameter = (uint)(timeType + delta);
849 
850 	if (parameter >= timeType)
851 		return false;
852 
853 	parameter = kTimeInvalid;
854 
855 	return true;
856 }
857 
updateParameterTime(TimeValue timeValue,bool check,uint & parameter,uint delta) const858 bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint &parameter, uint delta) const {
859 	if (getState()->time <= timeValue) {
860 		if (check || !parameter)
861 			parameter = (uint)(getState()->time + delta);
862 	}
863 
864 	if (parameter >= getState()->time && getState()->time <= timeValue)
865 		return false;
866 
867 	parameter = kTimeInvalid;
868 
869 	return true;
870 }
871 
updateParameterCheck(uint & parameter,uint timeType,uint delta) const872 bool Entity::updateParameterCheck(uint &parameter, uint timeType, uint delta) const {
873 	if (!parameter)
874 		parameter = (uint)(timeType + delta);
875 
876 	if (parameter && parameter >= timeType)
877 		return false;
878 
879 	return true;
880 }
881 
timeCheck(TimeValue timeValue,uint & parameter,Common::Functor0<void> * function) const882 bool Entity::timeCheck(TimeValue timeValue, uint &parameter, Common::Functor0<void> *function) const {
883 	if (getState()->time > timeValue && !parameter) {
884 		parameter = 1;
885 		(*function)();
886 
887 		return true;
888 	}
889 
890 	return false;
891 }
892 
timeCheckCallback(TimeValue timeValue,uint & parameter,byte callback,Common::Functor0<void> * function)893 bool Entity::timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *function) {
894 	if (getState()->time > timeValue && !parameter) {
895 		parameter = 1;
896 		setCallback(callback);
897 		(*function)();
898 
899 		return true;
900 	}
901 
902 	return false;
903 }
904 
timeCheckCallback(TimeValue timeValue,uint & parameter,byte callback,const char * str,Common::Functor1<const char *,void> * function)905 bool Entity::timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, const char *str, Common::Functor1<const char *, void> *function) {
906 	if (getState()->time > timeValue && !parameter) {
907 		parameter = 1;
908 		setCallback(callback);
909 		(*function)(str);
910 
911 		return true;
912 	}
913 
914 	return false;
915 }
916 
timeCheckCallback(TimeValue timeValue,uint & parameter,byte callback,bool check,Common::Functor1<bool,void> * function)917 bool Entity::timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, bool check, Common::Functor1<bool, void> *function) {
918 	if (getState()->time > timeValue && !parameter) {
919 		parameter = 1;
920 		setCallback(callback);
921 		(*function)(check);
922 
923 		return true;
924 	}
925 
926 	return false;
927 }
928 
timeCheckCallbackInventory(TimeValue timeValue,uint & parameter,byte callback,Common::Functor0<void> * function)929 bool Entity::timeCheckCallbackInventory(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *function) {
930 	if (getState()->time > timeValue && !parameter) {
931 		parameter = 1;
932 		getData()->inventoryItem = kItemNone;
933 		setCallback(callback);
934 		(*function)();
935 
936 		return true;
937 	}
938 
939 	return false;
940 }
941 
timeCheckCar(TimeValue timeValue,uint & parameter,byte callback,Common::Functor0<void> * function)942 bool Entity::timeCheckCar(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *function) {
943 	if ((getState()->time <= timeValue && !getEntities()->isPlayerInCar(kCarGreenSleeping)) || !parameter)
944 		parameter = (uint)getState()->time + 75;
945 
946 	if (getState()->time > timeValue || parameter < getState()->time) {
947 		parameter = kTimeInvalid;
948 		setCallback(callback);
949 		(*function)();
950 
951 		return true;
952 	}
953 
954 	return false;
955 }
956 
timeCheckSavepoint(TimeValue timeValue,uint & parameter,EntityIndex entity1,EntityIndex entity2,ActionIndex action) const957 void Entity::timeCheckSavepoint(TimeValue timeValue, uint &parameter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) const {
958 	if (getState()->time > timeValue && !parameter) {
959 		parameter = 1;
960 		getSavePoints()->push(entity1, entity2, action);
961 	}
962 }
963 
timeCheckObject(TimeValue timeValue,uint & parameter,ObjectIndex object,ObjectModel model) const964 void Entity::timeCheckObject(TimeValue timeValue, uint &parameter, ObjectIndex object, ObjectModel model) const {
965 	if (getState()->time > timeValue && !parameter) {
966 		parameter = 1;
967 		getObjects()->updateModel(object, model);
968 	}
969 }
970 
timeCheckCallbackAction(TimeValue timeValue,uint & parameter)971 bool Entity::timeCheckCallbackAction(TimeValue timeValue, uint &parameter) {
972 	if (getState()->time > timeValue && !parameter) {
973 		parameter = 1;
974 		callbackAction();
975 		return true;
976 	}
977 
978 	return false;
979 }
980 
timeCheckPlaySoundUpdatePosition(TimeValue timeValue,uint & parameter,byte callback,const char * sound,EntityPosition position)981 bool Entity::timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint &parameter, byte callback, const char* sound, EntityPosition position) {
982 	if (getState()->time > timeValue && !parameter) {
983 		parameter = 1;
984 		getData()->entityPosition = position;
985 		setCallback(callback);
986 		setup_playSound(sound);
987 		return true;
988 	}
989 
990 	return false;
991 }
992 
993 } // End of namespace LastExpress
994