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  * aint32 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  * Based on the original sources
23  *   Faery Tale II -- The Halls of the Dead
24  *   (c) 1993-1996 The Wyrmkeep Entertainment Co.
25  */
26 
27 #include "saga2/saga2.h"
28 #include "saga2/objects.h"
29 #include "saga2/sensor.h"
30 #include "saga2/player.h"
31 #include "saga2/tile.h"
32 
33 namespace Saga2 {
34 
35 /* ===================================================================== *
36    SensorList management functions
37  * ===================================================================== */
38 
39 //----------------------------------------------------------------------
40 //	Allocate a new SensorList
41 
newSensorList(SensorList * s)42 void newSensorList(SensorList *s) {
43 	g_vm->_sensorListList.push_back(s);
44 }
45 
46 //----------------------------------------------------------------------
47 //	Deallocate an SensorList
48 
deleteSensorList(SensorList * s)49 void deleteSensorList(SensorList *s) {
50 	g_vm->_sensorListList.remove(s);
51 }
52 
53 /* ===================================================================== *
54    Sensor management functions
55  * ===================================================================== */
56 
57 //----------------------------------------------------------------------
58 //	Allocate a new Sensor
59 
newSensor(Sensor * s)60 void newSensor(Sensor *s) {
61 	g_vm->_sensorList.push_back(s);
62 
63 	s->checkCtr = sensorCheckRate;
64 }
65 
66 //----------------------------------------------------------------------
67 //	Allocate a new Sensor with a specified starting check counter
68 
newSensor(Sensor * s,int16 ctr)69 void newSensor(Sensor *s, int16 ctr) {
70 	newSensor(s);
71 
72 	s->checkCtr = ctr;
73 }
74 
75 //----------------------------------------------------------------------
76 //	Deallocate a Sensor
77 
deleteSensor(Sensor * p)78 void deleteSensor(Sensor *p) {
79 	g_vm->_sensorList.remove(p);
80 }
81 
readSensor(int16 ctr,Common::InSaveFile * in)82 void readSensor(int16 ctr, Common::InSaveFile *in) {
83 	int16 type;
84 	Sensor *sensor = nullptr;
85 	SensorList *sl;
86 
87 	//  Get the sensor type
88 	type = in->readSint16LE();
89 	debugC(3, kDebugSaveload, "type = %d", type);
90 
91 	switch (type) {
92 	case protaganistSensor:
93 		sensor = new ProtaganistSensor(in, ctr);
94 		break;
95 
96 	case specificObjectSensor:
97 		sensor = new SpecificObjectSensor(in, ctr);
98 		break;
99 
100 	case objectPropertySensor:
101 		sensor = new ObjectPropertySensor(in, ctr);
102 		break;
103 
104 	case specificActorSensor:
105 		sensor = new SpecificActorSensor(in, ctr);
106 		break;
107 
108 	case actorPropertySensor:
109 		sensor = new ActorPropertySensor(in, ctr);
110 		break;
111 
112 	case eventSensor:
113 		sensor = new EventSensor(in, ctr);
114 		break;
115 	}
116 
117 	assert(sensor != nullptr);
118 
119 	//  Get the sensor list
120 	sl = fetchSensorList(sensor->getObject());
121 
122 	assert(sl != nullptr);
123 
124 	//  Append this Sensor to the sensor list
125 	sl->_list.push_back(sensor);
126 }
127 
writeSensor(Sensor * sensor,Common::MemoryWriteStreamDynamic * out)128 void writeSensor(Sensor *sensor, Common::MemoryWriteStreamDynamic *out) {
129 	assert(sensor != NULL);
130 
131 	//  Store the sensor type
132 	out->writeSint16LE(sensor->getType());
133 	debugC(3, kDebugSaveload, "type = %d", sensor->getType());
134 
135 	//  Let the sensor store its data in the buffer
136 	sensor->write(out);
137 }
138 
139 //----------------------------------------------------------------------
140 
checkSensors(void)141 void checkSensors(void) {
142 	Common::Array<Sensor *> deadSensors;
143 
144 	for (Common::List<Sensor *>::iterator it = g_vm->_sensorList.begin(); it != g_vm->_sensorList.end(); ++it) {
145 		Sensor *sensor = *it;
146 
147 		if (sensor->_active == false) {
148 			deadSensors.push_back(sensor);
149 			continue;
150 		}
151 
152 		if (--sensor->checkCtr <= 0) {
153 			assert(sensor->checkCtr == 0);
154 
155 			SenseInfo   info;
156 			GameObject  *senseobj = sensor->getObject();
157 			uint32      sFlags = nonActorSenseFlags;
158 			if (isActor(senseobj)) {
159 				Actor *a = (Actor *)senseobj;
160 				sFlags = a->_enchantmentFlags;
161 			}
162 
163 			if (sensor->check(info, sFlags)) {
164 				assert(info.sensedObject != NULL);
165 				assert(isObject(info.sensedObject) || isActor(info.sensedObject));
166 
167 				sensor->getObject()->senseObject(sensor->thisID(), info.sensedObject->thisID());
168 			}
169 
170 			sensor->checkCtr = sensorCheckRate;
171 		}
172 	}
173 
174 	for (uint i = 0; i < deadSensors.size(); ++i)
175 		delete deadSensors[i];
176 }
177 
178 //----------------------------------------------------------------------
179 
assertEvent(const GameEvent & ev)180 void assertEvent(const GameEvent &ev) {
181 	assert(ev.directObject != NULL);
182 	assert(isObject(ev.directObject) || isActor(ev.directObject));
183 
184 	for (Common::List<Sensor *>::iterator it = g_vm->_sensorList.begin(); it != g_vm->_sensorList.end(); ++it) {
185 		Sensor *sensor = *it;
186 
187 		if (sensor->evaluateEvent(ev)) {
188 			sensor->getObject()->senseEvent(
189 			    sensor->thisID(),
190 			    ev.type,
191 			    ev.directObject->thisID(),
192 			    ev.indirectObject != NULL
193 			    ?   ev.indirectObject->thisID()
194 			    :   Nothing);
195 		}
196 	}
197 }
198 
199 //----------------------------------------------------------------------
200 //	Initialize the sensors
201 
initSensors(void)202 void initSensors(void) {
203 	//  Nothing to do
204 	assert(sizeof(ProtaganistSensor) <= maxSensorSize);
205 	assert(sizeof(SpecificObjectSensor) <= maxSensorSize);
206 	assert(sizeof(ObjectPropertySensor) <= maxSensorSize);
207 	assert(sizeof(SpecificActorSensor) <= maxSensorSize);
208 	assert(sizeof(ActorPropertySensor) <= maxSensorSize);
209 	assert(sizeof(EventSensor) <= maxSensorSize);
210 }
211 
getSensorListID(SensorList * t)212 static int getSensorListID(SensorList *t) {
213 	int i = 0;
214 	for (Common::List<SensorList *>::iterator it = g_vm->_sensorListList.begin(); it != g_vm->_sensorListList.end(); it++, i++) {
215 		if ((*it) == t)
216 			return i;
217 	}
218 	return -1;
219 }
220 
getSensorID(Sensor * t)221 static int getSensorID(Sensor *t) {
222 	int i = 0;
223 	for (Common::List<Sensor *>::iterator it = g_vm->_sensorList.begin(); it != g_vm->_sensorList.end(); it++, i++) {
224 		if ((*it) == t)
225 			return i;
226 	}
227 	return -1;
228 }
229 
230 
saveSensors(Common::OutSaveFile * outS)231 void saveSensors(Common::OutSaveFile *outS) {
232 	debugC(2, kDebugSaveload, "Saving Sensors");
233 
234 	int16 sensorListCount = 0,
235 	      sensorCount = 0;
236 
237 	//  Tally the sensor lists
238 	sensorListCount = g_vm->_sensorListList.size();
239 
240 	//  Tally the sensors and add the archive size of each
241 	sensorCount = g_vm->_sensorList.size();
242 
243 	outS->write("SENS", 4);
244 	CHUNK_BEGIN;
245 	//  Store the sensor list count and sensor count
246 	out->writeSint16LE(sensorListCount);
247 	out->writeSint16LE(sensorCount);
248 
249 	debugC(3, kDebugSaveload, "... sensorListCount = %d", sensorListCount);
250 	debugC(3, kDebugSaveload, "... sensorCount = %d", sensorCount);
251 
252 	//  Archive all sensor lists
253 	for (Common::List<SensorList *>::iterator it = g_vm->_sensorListList.begin(); it != g_vm->_sensorListList.end(); ++it) {
254 		debugC(3, kDebugSaveload, "Saving SensorList %d", getSensorListID(*it));
255 		(*it)->write(out);
256 	}
257 
258 	//  Archive all sensors
259 	for (Common::List<Sensor *>::iterator it = g_vm->_sensorList.begin(); it != g_vm->_sensorList.end(); ++it) {
260 		if ((*it)->_active == false)
261 			continue;
262 
263 		debugC(3, kDebugSaveload, "Saving Sensor %d", getSensorID(*it));
264 		out->writeSint16LE((*it)->checkCtr);
265 		debugC(3, kDebugSaveload, "... ctr = %d", (*it)->checkCtr);
266 
267 		writeSensor(*it, out);
268 	}
269 	CHUNK_END;
270 }
271 
loadSensors(Common::InSaveFile * in)272 void loadSensors(Common::InSaveFile *in) {
273 	debugC(2, kDebugSaveload, "Loading Sensors");
274 
275 	int16 sensorListCount,
276 	      sensorCount;
277 
278 	//  Get the sensor list count and sensor count
279 	sensorListCount = in->readSint16LE();
280 	sensorCount = in->readSint16LE();
281 	debugC(3, kDebugSaveload, "... sensorListCount = %d", sensorListCount);
282 	debugC(3, kDebugSaveload, "... sensorCount = %d", sensorCount);
283 
284 	//  Restore all sensor lists
285 	for (int i = 0; i < sensorListCount; i++) {
286 		debugC(3, kDebugSaveload, "Loading SensorList %d", i);
287 		new SensorList(in);
288 	}
289 
290 	//  Restore all sensors
291 	for (int i = 0; i < sensorCount; i++) {
292 		int16 ctr;
293 
294 		debugC(3, kDebugSaveload, "Loading Sensor %d", i);
295 		ctr = in->readSint16LE();
296 		debugC(3, kDebugSaveload, "... ctr = %d", ctr);
297 
298 		readSensor(ctr, in);
299 	}
300 }
301 
302 //----------------------------------------------------------------------
303 //	Cleanup the active sensors
304 
cleanupSensors(void)305 void cleanupSensors(void) {
306 	Common::List<SensorList *>::iterator sensorListNextIt;
307 	for (Common::List<SensorList *>::iterator it = g_vm->_sensorListList.begin(); it != g_vm->_sensorListList.end(); it = sensorListNextIt) {
308 		sensorListNextIt = it;
309 		sensorListNextIt++;
310 		delete *it;
311 	}
312 
313 	Common::List<Sensor *>::iterator sensorNextIt;
314 	for (Common::List<Sensor *>::iterator it = g_vm->_sensorList.begin(); it != g_vm->_sensorList.end(); it = sensorNextIt) {
315 		sensorNextIt = it;
316 		sensorNextIt++;
317 		delete *it;
318 	}
319 }
320 
321 //----------------------------------------------------------------------
322 //	Fetch a specified object's SensorList
323 
fetchSensorList(GameObject * obj)324 SensorList *fetchSensorList(GameObject *obj) {
325 	for (Common::List<SensorList *>::iterator it = g_vm->_sensorListList.begin(); it != g_vm->_sensorListList.end(); ++it) {
326 		if ((*it)->getObject() == obj)
327 			return *it;
328 	}
329 
330 	return NULL;
331 }
332 
333 /* ===================================================================== *
334    SensorList member functions
335  * ===================================================================== */
336 
SensorList(Common::InSaveFile * in)337 SensorList::SensorList(Common::InSaveFile *in) {
338 	ObjectID id = in->readUint16LE();
339 
340 	assert(isObject(id) || isActor(id));
341 
342 	obj = GameObject::objectAddress(id);
343 
344 	newSensorList(this);
345 
346 	debugC(4, kDebugSaveload, "... objID = %d", id);
347 }
348 
write(Common::MemoryWriteStreamDynamic * out)349 void SensorList::write(Common::MemoryWriteStreamDynamic *out) {
350 	out->writeUint16LE(obj->thisID());
351 
352 	debugC(4, kDebugSaveload, "... objID = %d", obj->thisID());
353 }
354 
355 /* ===================================================================== *
356    Sensor member functions
357  * ===================================================================== */
358 
Sensor(Common::InSaveFile * in,int16 ctr)359 Sensor::Sensor(Common::InSaveFile *in, int16 ctr) {
360 	ObjectID objID = in->readUint16LE();
361 
362 	assert(isObject(objID) || isActor(objID));
363 
364 	//  Restore the object pointer
365 	obj = GameObject::objectAddress(objID);
366 
367 	//  Restore the ID
368 	id = in->readSint16LE();
369 
370 	//  Restore the range
371 	range = in->readSint16LE();
372 
373 	_active = true;
374 
375 	newSensor(this, ctr);
376 
377 	debugC(4, kDebugSaveload, "... objID = %d", objID);
378 	debugC(4, kDebugSaveload, "... id = %d", id);
379 	debugC(4, kDebugSaveload, "... range = %d", range);
380 }
381 
382 //----------------------------------------------------------------------
383 //	Return the number of bytes needed to archive this object in a buffer
384 
write(Common::MemoryWriteStreamDynamic * out)385 void Sensor::write(Common::MemoryWriteStreamDynamic *out) {
386 	//  Store the object's ID
387 	out->writeUint16LE(obj->thisID());
388 
389 	//  Store the sensor ID
390 	out->writeSint16LE(id);
391 
392 	//  Store the range
393 	out->writeSint16LE(range);
394 
395 	debugC(4, kDebugSaveload, "... objID = %d", obj->thisID());
396 	debugC(4, kDebugSaveload, "... id = %d", id);
397 	debugC(4, kDebugSaveload, "... range = %d", range);
398 }
399 
400 /* ===================================================================== *
401    ProtaganistSensor member functions
402  * ===================================================================== */
403 
404 //----------------------------------------------------------------------
405 //	Return an integer representing the type of this sensor
406 
getType(void)407 int16 ProtaganistSensor::getType(void) {
408 	return protaganistSensor;
409 }
410 
411 //----------------------------------------------------------------------
412 //	Determine if the object can sense what it's looking for
413 
check(SenseInfo & info,uint32 senseFlags)414 bool ProtaganistSensor::check(SenseInfo &info, uint32 senseFlags) {
415 	static PlayerActorID    playerActorIDs[] = {
416 		FTA_JULIAN,
417 		FTA_PHILIP,
418 		FTA_KEVIN,
419 	};
420 
421 	int16       i;
422 	bool        objIsActor = isActor(getObject());
423 
424 	for (i = 0; i < (long)ARRAYSIZE(playerActorIDs); i++) {
425 		Actor   *protag =
426 		    getPlayerActorAddress(playerActorIDs[i])->getActor();
427 
428 		assert(isActor(protag));
429 
430 		//  Skip this protaganist if they're dead
431 		if (protag->isDead())
432 			continue;
433 
434 		if (senseFlags & (1 << actorBlind))
435 			continue;
436 
437 		//  This extra test is a HACK to ensure that the center actor
438 		//  will be able to sense a protaganist even if the protaganist
439 		//  is invisible.
440 		if (!objIsActor || getObject() != getCenterActor()) {
441 			if (!(senseFlags & actorSeeInvis)
442 			        &&  protag->hasEffect(actorInvisible))
443 				continue;
444 		}
445 
446 		//  Skip if out of range
447 		if (getRange() != 0
448 		        &&  !getObject()->inRange(protag->getLocation(), getRange()))
449 			continue;
450 
451 		//  Skip if we're checking for an actor and the protaganist is
452 		//  not in sight or not under the same roof
453 		if (objIsActor
454 		        && (!underSameRoof(getObject(), protag)
455 		            ||  !lineOfSight(getObject(), protag, terrainTransparent)))
456 			continue;
457 
458 		info.sensedObject = protag;
459 		return true;
460 	}
461 
462 	return false;
463 }
464 
465 //----------------------------------------------------------------------
466 //	Evaluate an event to determine if the object is waiting for it
467 
evaluateEvent(const GameEvent &)468 bool ProtaganistSensor::evaluateEvent(const GameEvent &) {
469 	return false;
470 }
471 
472 /* ===================================================================== *
473    ObjectSensor member functions
474  * ===================================================================== */
475 
476 //----------------------------------------------------------------------
477 //	Determine if the object can sense what it's looking for
478 
check(SenseInfo & info,uint32 senseFlags)479 bool ObjectSensor::check(SenseInfo &info, uint32 senseFlags) {
480 	bool                    objIsActor = isActor(getObject());
481 	CircularObjectIterator  iter(
482 	    getObject()->world(),
483 	    getObject()->getLocation(),
484 	    getRange() != 0 ? getRange() : kTileUVSize * kPlatformWidth * 8);
485 	GameObject              *objToTest = nullptr;
486 	iter.first(&objToTest);
487 
488 	for (iter.first(&objToTest);
489 	        objToTest != NULL;
490 	        iter.next(&objToTest)) {
491 		if (senseFlags & (1 << actorBlind))
492 			continue;
493 		bool objToTestIsActor = isActor(objToTest);
494 
495 		//  This extra test is a HACK to ensure that the center actor
496 		//  will be able to sense a protaganist even if the protaganist
497 		//  is invisible.
498 		if (objToTestIsActor
499 		        && (!objIsActor
500 		            ||  getObject() != getCenterActor()
501 		            ||  !isPlayerActor((Actor *)objToTest))) {
502 			Actor *a = (Actor *) objToTest;
503 			if (!(senseFlags & actorSeeInvis) && a->hasEffect(actorInvisible))
504 				continue;
505 		}
506 		//  Skip if object is out of range
507 		if (getRange() != 0
508 		        &&  !getObject()->inRange(objToTest->getLocation(), getRange()))
509 			continue;
510 
511 		//  Skip if object is not what we're looking for
512 		if (!isObjectSought(objToTest))
513 			continue;
514 
515 		//  Skip if we're checking for an actor and the protaganist is
516 		//  not in sight or not under the same roof
517 		if (objIsActor
518 		        && (!underSameRoof(getObject(), objToTest)
519 		            ||  !lineOfSight(getObject(), objToTest, terrainTransparent)))
520 			continue;
521 
522 		info.sensedObject = objToTest;
523 		return true;
524 	}
525 
526 	return false;
527 }
528 
529 //----------------------------------------------------------------------
530 //	Evaluate an event to determine if the object is waiting for it
531 
evaluateEvent(const GameEvent &)532 bool ObjectSensor::evaluateEvent(const GameEvent &) {
533 	return false;
534 }
535 
536 /* ===================================================================== *
537    SpecificObjectSensor member functions
538  * ===================================================================== */
539 
SpecificObjectSensor(Common::InSaveFile * in,int16 ctr)540 SpecificObjectSensor::SpecificObjectSensor(Common::InSaveFile *in, int16 ctr) :
541 	ObjectSensor(in, ctr) {
542 	debugC(3, kDebugSaveload, "Loading SpecificObjectSensor");
543 
544 	//  Restore the sought object's ID
545 	soughtObjID = in->readUint16LE();
546 }
547 
write(Common::MemoryWriteStreamDynamic * out)548 void SpecificObjectSensor::write(Common::MemoryWriteStreamDynamic *out) {
549 	debugC(3, kDebugSaveload, "Saving SpecificObjectSensor");
550 
551 	//  Let the base class archive its data
552 	ObjectSensor::write(out);
553 
554 	//  Store the sought object's ID
555 	out->writeUint16LE(soughtObjID);
556 }
557 
558 //----------------------------------------------------------------------
559 //	Return an integer representing the type of this sensor
560 
getType(void)561 int16 SpecificObjectSensor::getType(void) {
562 	return specificObjectSensor;
563 }
564 
565 //----------------------------------------------------------------------
566 //	Determine if the object can sense what it's looking for
567 
check(SenseInfo & info,uint32 senseFlags)568 bool SpecificObjectSensor::check(SenseInfo &info, uint32 senseFlags) {
569 	assert(soughtObjID != Nothing);
570 	assert(isObject(soughtObjID) || isActor(soughtObjID));
571 
572 	GameObject      *soughtObject = GameObject::objectAddress(soughtObjID);
573 	bool            objIsActor = isActor(getObject());
574 
575 	if (senseFlags & (1 << actorBlind))
576 		return false;
577 
578 	//  This extra test is a HACK to ensure that the center actor
579 	//  will be able to sense a protaganist even if the protaganist
580 	//  is invisible.
581 	if (isActor(soughtObject)
582 	        && (!objIsActor
583 	            ||  getObject() != getCenterActor()
584 	            ||  !isPlayerActor((Actor *)soughtObject))) {
585 		Actor *a = (Actor *) soughtObject;
586 		if (!(senseFlags & actorSeeInvis) && a->hasEffect(actorInvisible))
587 			return false;
588 	}
589 
590 	if (getRange() != 0
591 	        &&  !getObject()->inRange(soughtObject->getLocation(),  getRange()))
592 		return false;
593 
594 	if (objIsActor
595 	        && (!underSameRoof(getObject(), soughtObject)
596 	            ||  !lineOfSight(getObject(), soughtObject, terrainTransparent)))
597 		return false;
598 
599 	info.sensedObject = soughtObject;
600 	return true;
601 }
602 
603 //----------------------------------------------------------------------
604 //	Determine if an object meets the search criteria
605 
isObjectSought(GameObject * obj_)606 bool SpecificObjectSensor::isObjectSought(GameObject *obj_) {
607 	assert(isObject(obj_) || isActor(obj_));
608 	assert(soughtObjID != Nothing);
609 	assert(isObject(soughtObjID) || isActor(soughtObjID));
610 
611 	return obj_ == GameObject::objectAddress(soughtObjID);
612 }
613 
614 /* ===================================================================== *
615    ObjectPropertySensor member functions
616  * ===================================================================== */
617 
ObjectPropertySensor(Common::InSaveFile * in,int16 ctr)618 ObjectPropertySensor::ObjectPropertySensor(Common::InSaveFile *in, int16 ctr) :
619 	ObjectSensor(in, ctr) {
620 	debugC(3, kDebugSaveload, "Loading ObjectPropertySensor");
621 
622 	//  Restore the object property ID
623 	objectProperty = in->readSint16LE();;
624 }
625 
write(Common::MemoryWriteStreamDynamic * out)626 void ObjectPropertySensor::write(Common::MemoryWriteStreamDynamic *out) {
627 	debugC(3, kDebugSaveload, "Saving ObjectPropertySensor");
628 
629 	//  Let the base class archive its data
630 	ObjectSensor::write(out);
631 
632 	//  Store the object property's ID
633 	out->writeSint16LE(objectProperty);
634 }
635 
636 //----------------------------------------------------------------------
637 //	Return an integer representing the type of this sensor
638 
getType(void)639 int16 ObjectPropertySensor::getType(void) {
640 	return objectPropertySensor;
641 }
642 
643 //----------------------------------------------------------------------
644 //	Determine if an object meets the search criteria
645 
isObjectSought(GameObject * obj_)646 bool ObjectPropertySensor::isObjectSought(GameObject *obj_) {
647 	assert(isObject(obj_) || isActor(obj_));
648 
649 	return obj_->hasProperty(*g_vm->_properties->getObjProp(objectProperty));
650 }
651 
652 /* ===================================================================== *
653    ActorSensor member functions
654  * ===================================================================== */
655 
656 //----------------------------------------------------------------------
657 //	Determine if an object meets the search criteria
658 
isObjectSought(GameObject * obj_)659 bool ActorSensor::isObjectSought(GameObject *obj_) {
660 	assert(isObject(obj_) || isActor(obj_));
661 
662 	//  Only actors need apply
663 	return isActor(obj_) && isActorSought((Actor *)obj_);
664 }
665 
666 /* ===================================================================== *
667    SpecificActorSensor member functions
668  * ===================================================================== */
669 
SpecificActorSensor(Common::InSaveFile * in,int16 ctr)670 SpecificActorSensor::SpecificActorSensor(Common::InSaveFile *in, int16 ctr) : ActorSensor(in, ctr) {
671 	debugC(3, kDebugSaveload, "Loading SpecificActorSensor");
672 	ObjectID actorID = in->readUint16LE();
673 
674 	assert(isActor(actorID));
675 
676 	//  Restore the sought actor pointer
677 	soughtActor = (Actor *)GameObject::objectAddress(actorID);
678 }
679 
write(Common::MemoryWriteStreamDynamic * out)680 void SpecificActorSensor::write(Common::MemoryWriteStreamDynamic *out) {
681 	debugC(3, kDebugSaveload, "Saving SpecificActorSensor");
682 
683 	//  Let the base class archive its data
684 	ActorSensor::write(out);
685 
686 	//  Store the sought actor's ID
687 	out->writeUint16LE(soughtActor->thisID());
688 }
689 
690 //----------------------------------------------------------------------
691 //	Return an integer representing the type of this sensor
692 
getType(void)693 int16 SpecificActorSensor::getType(void) {
694 	return specificActorSensor;
695 }
696 
697 //----------------------------------------------------------------------
698 //	Determine if the object can sense what it's looking for
699 
check(SenseInfo & info,uint32 senseFlags)700 bool SpecificActorSensor::check(SenseInfo &info, uint32 senseFlags) {
701 	assert(isActor(soughtActor));
702 	bool        objIsActor = isActor(getObject());
703 
704 	if (senseFlags & (1 << actorBlind))
705 		return false;
706 
707 	//  This extra test is a HACK to ensure that the center actor
708 	//  will be able to sense a protaganist even if the protaganist
709 	//  is invisible.
710 	if (!objIsActor
711 	        ||  getObject() != getCenterActor()
712 	        ||  !isPlayerActor(soughtActor)) {
713 		if (!(senseFlags & actorSeeInvis) && soughtActor->hasEffect(actorInvisible))
714 			return false;
715 	}
716 
717 	if (getRange() != 0
718 	        &&  !getObject()->inRange(soughtActor->getLocation(), getRange()))
719 		return false;
720 
721 	if (objIsActor
722 	        && (!underSameRoof(getObject(), soughtActor)
723 	            ||  !lineOfSight(getObject(), soughtActor, terrainTransparent)))
724 		return false;
725 
726 	info.sensedObject = soughtActor;
727 	return true;
728 }
729 
730 //----------------------------------------------------------------------
731 //	Determine if an actor meets the search criteria
732 
isActorSought(Actor * a)733 bool SpecificActorSensor::isActorSought(Actor *a) {
734 	return a == soughtActor;
735 }
736 
737 /* ===================================================================== *
738    ActorPropertySensor member functions
739  * ===================================================================== */
740 
ActorPropertySensor(Common::InSaveFile * in,int16 ctr)741 ActorPropertySensor::ActorPropertySensor(Common::InSaveFile *in, int16 ctr) : ActorSensor(in, ctr) {
742 	debugC(3, kDebugSaveload, "Loading ActorPropertySensor");
743 	//  Restore the actor property's ID
744 	actorProperty = in->readSint16LE();
745 }
746 
write(Common::MemoryWriteStreamDynamic * out)747 void ActorPropertySensor::write(Common::MemoryWriteStreamDynamic *out) {
748 	debugC(3, kDebugSaveload, "Saving ActorPropertySensor");
749 
750 	//  Let the base class archive its data
751 	ActorSensor::write(out);
752 
753 	//  Store the actor property's ID
754 	out->writeSint16LE(actorProperty);
755 }
756 
757 //----------------------------------------------------------------------
758 //	Return an integer representing the type of this sensor
759 
getType(void)760 int16 ActorPropertySensor::getType(void) {
761 	return actorPropertySensor;
762 }
763 
764 //----------------------------------------------------------------------
765 //	Determine if an actor meets the search criteria
766 
isActorSought(Actor * a)767 bool ActorPropertySensor::isActorSought(Actor *a) {
768 	return a->hasProperty(*g_vm->_properties->getActorProp(actorProperty));
769 }
770 
771 /* ===================================================================== *
772    EventSensor member functions
773  * ===================================================================== */
774 
775 //----------------------------------------------------------------------
776 //	Constructor -- initial construction
777 
EventSensor(GameObject * o,SensorID sensorID,int16 rng,int16 type)778 EventSensor::EventSensor(
779     GameObject      *o,
780     SensorID        sensorID,
781     int16           rng,
782     int16           type) :
783 	Sensor(o, sensorID, rng),
784 	eventType(type) {
785 }
786 
EventSensor(Common::InSaveFile * in,int16 ctr)787 EventSensor::EventSensor(Common::InSaveFile *in, int16 ctr) : Sensor(in, ctr) {
788 	debugC(3, kDebugSaveload, "Loading EventSensor");
789 	//  Restore the event type
790 	eventType = in->readSint16LE();
791 }
792 
793 //----------------------------------------------------------------------
794 //	Return the number of bytes needed to archive this object in a buffer
795 
write(Common::MemoryWriteStreamDynamic * out)796 void EventSensor::write(Common::MemoryWriteStreamDynamic *out) {
797 	debugC(3, kDebugSaveload, "Saving EventSensor");
798 
799 	//  Let the base class archive its data
800 	Sensor::write(out);
801 
802 	//  Store the event type
803 	out->writeSint16LE(eventType);
804 }
805 
806 //----------------------------------------------------------------------
807 //	Return an integer representing the type of this sensor
808 
getType(void)809 int16 EventSensor::getType(void) {
810 	return eventSensor;
811 }
812 
813 //----------------------------------------------------------------------
814 //	Determine if the object can sense what it's looking for
815 
check(SenseInfo &,uint32)816 bool EventSensor::check(SenseInfo &, uint32) {
817 	return false;
818 }
819 
820 //----------------------------------------------------------------------
821 //	Evaluate an event to determine if the object is waiting for it
822 
evaluateEvent(const GameEvent & event)823 bool EventSensor::evaluateEvent(const GameEvent &event) {
824 	return      event.type == eventType
825 	            &&  getObject()->world() == event.directObject->world()
826 	            && (getRange() != 0
827 	                ?   getObject()->inRange(
828 	                    event.directObject->getLocation(),
829 	                    getRange())
830 	                :   true)
831 	            && (!isActor(getObject())
832 	                || (underSameRoof(getObject(), event.directObject)
833 	                    &&  lineOfSight(
834 	                        getObject(),
835 	                        event.directObject,
836 	                        terrainTransparent)));
837 }
838 
839 } // end of namespace Saga2
840