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