aboutsummaryrefslogtreecommitdiff
path: root/engines/pegasus/ai
diff options
context:
space:
mode:
Diffstat (limited to 'engines/pegasus/ai')
-rw-r--r--engines/pegasus/ai/ai_action.cpp78
-rw-r--r--engines/pegasus/ai/ai_action.h136
-rw-r--r--engines/pegasus/ai/ai_area.cpp613
-rw-r--r--engines/pegasus/ai/ai_area.h172
-rw-r--r--engines/pegasus/ai/ai_condition.cpp290
-rw-r--r--engines/pegasus/ai/ai_condition.h287
-rw-r--r--engines/pegasus/ai/ai_rule.cpp78
-rw-r--r--engines/pegasus/ai/ai_rule.h86
8 files changed, 1740 insertions, 0 deletions
diff --git a/engines/pegasus/ai/ai_action.cpp b/engines/pegasus/ai/ai_action.cpp
new file mode 100644
index 0000000000..38d639038f
--- /dev/null
+++ b/engines/pegasus/ai/ai_action.cpp
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/ai/ai_action.h"
+#include "pegasus/ai/ai_area.h"
+
+namespace Pegasus {
+
+AICompoundAction::~AICompoundAction() {
+ for (AIActionList::iterator it = _compoundActions.begin(); it != _compoundActions.end(); it++)
+ delete *it;
+}
+
+void AICompoundAction::performAIAction(AIRule *rule) {
+ for (AIActionList::iterator it = _compoundActions.begin(); it != _compoundActions.end(); it++)
+ (*it)->performAIAction(rule);
+}
+
+AIPlayMessageAction::AIPlayMessageAction(const Common::String &movieName, bool keepLastFrame, const InputBits interruptionFilter) {
+ _movieName = movieName;
+ _keepLastFrame = keepLastFrame;
+ _interruptionFilter = interruptionFilter;
+}
+
+void AIPlayMessageAction::performAIAction(AIRule *) {
+ if (g_AIArea) {
+ g_AIArea->checkMiddleArea();
+ g_AIArea->playAIMovie(kRightAreaSignature, _movieName, _keepLastFrame, _interruptionFilter);
+ }
+}
+
+AIStartTimerAction::AIStartTimerAction(AITimerCondition *timerCondition) {
+ _timerCondition = timerCondition;
+}
+
+void AIStartTimerAction::performAIAction(AIRule *) {
+ _timerCondition->startTimer();
+}
+
+AIActivateRuleAction::AIActivateRuleAction(AIRule *rule) {
+ _rule = rule;
+}
+
+void AIActivateRuleAction::performAIAction(AIRule *) {
+ _rule->activateRule();
+}
+
+AIDeactivateRuleAction::AIDeactivateRuleAction(AIRule *rule) {
+ _rule = rule;
+}
+
+void AIDeactivateRuleAction::performAIAction(AIRule *) {
+ _rule->deactivateRule();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/ai/ai_action.h b/engines/pegasus/ai/ai_action.h
new file mode 100644
index 0000000000..6eac976f9c
--- /dev/null
+++ b/engines/pegasus/ai/ai_action.h
@@ -0,0 +1,136 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_AI_AIACTION_H
+#define PEGASUS_AI_AIACTION_H
+
+#include "common/list.h"
+
+#include "pegasus/input.h"
+#include "pegasus/types.h"
+
+namespace Pegasus {
+
+class AIRule;
+class AITimerCondition;
+
+/////////////////////////////////////////////
+//
+// AIAction
+
+class AIAction {
+friend class AIRule;
+public:
+ AIAction() { _actionCount = 1; }
+ virtual ~AIAction() {}
+
+ virtual void performAIAction(AIRule *) = 0;
+
+ void setActionCount(const uint32 count) { _actionCount = count; }
+
+protected:
+ uint32 _actionCount;
+};
+
+typedef Common::List<AIAction *> AIActionList;
+
+/////////////////////////////////////////////
+//
+// AICompoundAction
+
+class AICompoundAction : public AIAction {
+public:
+ AICompoundAction() {}
+ virtual ~AICompoundAction();
+
+ void addAction(AIAction *action) { _compoundActions.push_back(action); }
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ AIActionList _compoundActions;
+};
+
+/////////////////////////////////////////////
+//
+// AIPlayMessageAction
+
+class AIPlayMessageAction : public AIAction {
+public:
+ AIPlayMessageAction(const Common::String &movieName, bool keepLastFrame, const InputBits = kWarningInterruption);
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ Common::String _movieName;
+ InputBits _interruptionFilter;
+ bool _keepLastFrame;
+};
+
+/////////////////////////////////////////////
+//
+// AIStartTimerAction
+
+class AIStartTimerAction : public AIAction {
+public:
+ AIStartTimerAction(AITimerCondition *);
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ AITimerCondition *_timerCondition;
+};
+
+/////////////////////////////////////////////
+//
+// AIActivateRuleAction
+
+class AIActivateRuleAction : public AIAction {
+public:
+ AIActivateRuleAction(AIRule *);
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ AIRule *_rule;
+};
+
+/////////////////////////////////////////////
+//
+// AIDeactivateRuleAction
+
+class AIDeactivateRuleAction : public AIAction {
+public:
+ AIDeactivateRuleAction(AIRule *rule);
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ AIRule *_rule;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/ai/ai_area.cpp b/engines/pegasus/ai/ai_area.cpp
new file mode 100644
index 0000000000..e4d31049f2
--- /dev/null
+++ b/engines/pegasus/ai/ai_area.cpp
@@ -0,0 +1,613 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/memstream.h"
+
+#include "pegasus/cursor.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/biochips/opticalchip.h"
+#include "pegasus/items/biochips/pegasuschip.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+AIArea *g_AIArea = 0;
+
+AIArea::AIArea(InputHandler *nextHandler) : InputHandler(nextHandler), _leftAreaMovie(kAILeftAreaID),
+ _middleAreaMovie(kAIMiddleAreaID), _rightAreaMovie(kAIRightAreaID), _AIMovie(kAIMovieID) {
+ g_AIArea = this;
+ _leftAreaOwner = kNoClientSignature;
+ _middleAreaOwner = kNoClientSignature;
+ _rightAreaOwner = kNoClientSignature;
+ _leftInventoryTime = 0xffffffff;
+ _middleInventoryTime = 0xffffffff;
+ _middleBiochipTime = 0xffffffff;
+ _rightBiochipTime = 0xffffffff;
+ _lockCount = 0;
+ startIdling();
+}
+
+AIArea::~AIArea() {
+ if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ if (currentBiochip && currentBiochip->isSelected())
+ currentBiochip->giveUpSharedArea();
+ } else if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ if (currentItem && currentItem->isSelected())
+ currentItem->giveUpSharedArea();
+ }
+
+ stopIdling();
+
+ for (AIRuleList::iterator it = _AIRules.begin(); it != _AIRules.end(); it++)
+ delete *it;
+
+ g_AIArea = 0;
+}
+
+// Save last state of AI rules...
+void AIArea::saveAIState() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ delete vm->_aiSaveStream;
+
+ Common::MemoryWriteStreamDynamic out;
+ writeAIRules(&out);
+
+ vm->_aiSaveStream = new Common::MemoryReadStream(out.getData(), out.size(), DisposeAfterUse::YES);
+}
+
+void AIArea::restoreAIState() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (vm->_aiSaveStream)
+ readAIRules(vm->_aiSaveStream);
+}
+
+void AIArea::writeAIRules(Common::WriteStream *stream) {
+ _AIRules.writeAIRules(stream);
+}
+
+void AIArea::readAIRules(Common::ReadStream *stream) {
+ _AIRules.readAIRules(stream);
+}
+
+void AIArea::initAIArea() {
+ allocateSurface(Common::Rect(0, 0, 384, 96));
+
+ _leftAreaMovie.shareSurface(this);
+ _leftAreaMovie.initFromMovieFile("Images/Items/Left Area Movie");
+ _leftAreaMovie.moveElementTo(kAILeftAreaLeft, kAILeftAreaTop);
+ _leftAreaMovie.setDisplayOrder(kAILeftAreaOrder);
+ _leftAreaMovie.startDisplaying();
+ _leftAreaMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+
+ _middleAreaMovie.shareSurface(this);
+ _middleAreaMovie.initFromMovieFile("Images/Items/Middle Area Movie");
+ _middleAreaMovie.moveElementTo(kAIMiddleAreaLeft, kAIMiddleAreaTop);
+ _middleAreaMovie.moveMovieBoxTo(kAIMiddleAreaLeft - kAILeftAreaLeft, 0);
+ _middleAreaMovie.setDisplayOrder(kAIMiddleAreaOrder);
+ _middleAreaMovie.startDisplaying();
+ _middleAreaMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+
+ _rightAreaMovie.shareSurface(this);
+ _rightAreaMovie.initFromMovieFile("Images/Items/Right Area Movie");
+ _rightAreaMovie.moveElementTo(kAIRightAreaLeft, kAIRightAreaTop);
+ _rightAreaMovie.moveMovieBoxTo(kAIRightAreaLeft - kAILeftAreaLeft, 0);
+ _rightAreaMovie.setDisplayOrder(kAIRightAreaOrder);
+ _rightAreaMovie.startDisplaying();
+ _rightAreaMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+
+ _AIMovie.setDisplayOrder(kAIMovieOrder);
+}
+
+void AIArea::setAIVolume(const uint16 volume) {
+ _leftAreaMovie.setVolume(volume);
+ _middleAreaMovie.setVolume(volume);
+ _rightAreaMovie.setVolume(volume);
+}
+
+// There are only so many legal combinations of client/area.
+// Here is the list of supported pairs:
+// kInventorySignature kLeftAreaSignature
+// kInventorySignature kMiddleAreaSignature
+// kBiochipSignature kMiddleAreaSignature
+// kBiochipSignature kRightAreaSignature
+// kAISignature kLeftAreaSignature
+// Further, the kAISignature never sets a static frame time in the left area,
+// but only plays a sequence.
+
+// If this function is called while a sequence is playing, it will just "remember"
+// the time value, so that when the sequence finishes, the new time is asserted.
+
+void AIArea::setAIAreaToTime(const LowerClientSignature client, const LowerAreaSignature area, const TimeValue time) {
+ switch (area) {
+ case kLeftAreaSignature:
+ // Only support kInventorySignature client, since AI never calls SetAIAreaToTime.
+ _leftAreaMovie.setSegment(0, _leftAreaMovie.getDuration());
+
+ if (time == 0xffffffff) {
+ _leftAreaMovie.hide();
+ _leftAreaOwner = kNoClientSignature;
+ } else {
+ setLeftMovieTime(time);
+ }
+ break;
+ case kMiddleAreaSignature:
+ // Only support kInventorySignature and kBiochipSignature clients.
+ _middleAreaMovie.stop();
+ _middleAreaMovie.setFlags(0);
+ _middleAreaMovie.setSegment(0, _middleAreaMovie.getDuration());
+
+ if (time == 0xffffffff) {
+ if (client == kInventorySignature) {
+ if (_middleBiochipTime != 0xffffffff) {
+ setMiddleMovieTime(kBiochipSignature, _middleBiochipTime);
+ } else {
+ _middleAreaMovie.hide();
+ _middleAreaOwner = kNoClientSignature;
+ }
+ } else { // client == kBiochipSignature
+ if (_middleInventoryTime != 0xffffffff) {
+ setMiddleMovieTime(kInventorySignature, _middleInventoryTime);
+ } else {
+ _middleAreaMovie.hide();
+ _middleAreaOwner = kNoClientSignature;
+ }
+ }
+ } else {
+ setMiddleMovieTime(client, time);
+ }
+ break;
+ case kRightAreaSignature:
+ // Only support kBiochipSignature client.
+ _rightAreaMovie.setSegment(0, _rightAreaMovie.getDuration());
+
+ if (time == 0xffffffff) {
+ _rightAreaMovie.hide();
+ _rightAreaOwner = kNoClientSignature;
+ } else {
+ setRightMovieTime(time);
+ }
+ break;
+ }
+}
+
+// Plays a sequence on an area. When the sequence ends, the previous image
+// is restored.
+// Also, is input disabled or not?
+// Easy answer: yes.
+
+// There are only so many legal combinations of client/area.
+// Here is the list of supported pairs:
+// kBiochipSignature kMiddleAreaSignature
+// kBiochipSignature kRightAreaSignature
+// kInventorySignature kMiddleAreaSignature
+
+void AIArea::playAIAreaSequence(const LowerClientSignature, const LowerAreaSignature area, const TimeValue start, const TimeValue stop) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ lockAIOut();
+
+ switch (area) {
+ case kLeftAreaSignature:
+ break;
+ case kMiddleAreaSignature:
+ if (_middleAreaOwner == kInventorySignature)
+ _middleInventoryTime = _middleAreaMovie.getTime();
+ else if (_middleAreaOwner == kBiochipSignature)
+ _middleBiochipTime = _middleAreaMovie.getTime();
+
+ _middleAreaMovie.stop();
+ _middleAreaMovie.setFlags(0);
+ _middleAreaMovie.setSegment(start, stop);
+ _middleAreaMovie.setTime(start);
+ _middleAreaMovie.show();
+ _middleAreaMovie.start();
+ vm->_cursor->hide();
+
+ while (_middleAreaMovie.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ _middleAreaMovie.stop();
+ vm->_cursor->hideUntilMoved();
+
+ if (_middleAreaOwner == kInventorySignature)
+ setAIAreaToTime(_middleAreaOwner, kMiddleAreaSignature, _middleInventoryTime);
+ else if (_middleAreaOwner == kBiochipSignature)
+ setAIAreaToTime(_middleAreaOwner, kMiddleAreaSignature, _middleBiochipTime);
+ else
+ setAIAreaToTime(_middleAreaOwner, kMiddleAreaSignature, 0xffffffff);
+ break;
+ case kRightAreaSignature:
+ _rightBiochipTime = _rightAreaMovie.getTime();
+ _rightAreaMovie.setSegment(start, stop);
+ _rightAreaMovie.setTime(start);
+ _rightAreaMovie.show();
+ _rightAreaMovie.start();
+ vm->_cursor->hide();
+
+ while (_rightAreaMovie.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ _rightAreaMovie.stop();
+ vm->_cursor->hideUntilMoved();
+ setAIAreaToTime(_rightAreaOwner, kRightAreaSignature, _rightBiochipTime);
+ break;
+ }
+
+ unlockAI();
+}
+
+bool AIArea::playAIMovie(const LowerAreaSignature area, const Common::String &movieName, bool keepLastFrame, const InputBits interruptFilter) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ lockAIOut();
+
+ InputDevice.waitInput(interruptFilter);
+ if (_AIMovie.isMovieValid())
+ _AIMovie.releaseMovie();
+
+ _AIMovie.shareSurface(this);
+ _AIMovie.initFromMovieFile(movieName);
+
+ if (area == kLeftAreaSignature) {
+ _AIMovie.moveElementTo(kAILeftAreaLeft, kAILeftAreaTop);
+ _leftAreaMovie.hide();
+ } else {
+ _AIMovie.moveElementTo(kAIRightAreaLeft, kAIRightAreaTop);
+ _AIMovie.moveMovieBoxTo(kAIRightAreaLeft - kAILeftAreaLeft, 0);
+ _rightAreaMovie.hide();
+ }
+
+ _AIMovie.setTime(0);
+ _AIMovie.startDisplaying();
+ _AIMovie.show();
+ _AIMovie.redrawMovieWorld();
+ _AIMovie.setVolume(vm->getSoundFXLevel());
+ _AIMovie.start();
+ vm->_cursor->hide();
+
+ bool result = true;
+ bool saveAllowed = vm->swapSaveAllowed(false);
+ bool openAllowed = vm->swapLoadAllowed(false);
+
+ while (_AIMovie.isRunning()) {
+ Input input;
+ InputDevice.getInput(input, interruptFilter);
+
+ if (input.anyInput() || vm->shouldQuit() || vm->saveRequested() || vm->loadRequested()) {
+ result = false;
+ break;
+ }
+
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ _AIMovie.stop();
+
+ vm->swapSaveAllowed(saveAllowed);
+ vm->swapLoadAllowed(openAllowed);
+
+ // This used to keep the last frame up even if the movie was interrupted.
+ // However, this only occurs in the recalibration, where interruption means skip the
+ // whole thing, so skipping causes the AI to go away even when keepLastFrame is true.
+
+ if (!(result && keepLastFrame)) {
+ _AIMovie.stopDisplaying();
+ _AIMovie.releaseMovie();
+
+ if (area == kLeftAreaSignature) {
+ _leftAreaMovie.setTime(_leftInventoryTime);
+ _leftAreaMovie.show();
+ _leftAreaMovie.redrawMovieWorld();
+ } else {
+ _rightAreaMovie.setTime(_rightBiochipTime);
+ _rightAreaMovie.show();
+ _rightAreaMovie.redrawMovieWorld();
+ }
+ }
+
+ vm->_cursor->hideUntilMoved();
+ unlockAI();
+ return result;
+}
+
+// Only implemented for kMiddleAreaSignature, kInventorySignature
+void AIArea::loopAIAreaSequence(const LowerClientSignature owner, const LowerAreaSignature area, const TimeValue start, const TimeValue stop) {
+ if (area == kMiddleAreaSignature && owner == kInventorySignature && owner == _middleAreaOwner) {
+ _middleAreaMovie.stop();
+ _middleAreaMovie.setFlags(0);
+ _middleAreaMovie.setSegment(start, stop);
+ _middleAreaMovie.setFlags(kLoopTimeBase);
+ _middleAreaMovie.setTime(start);
+ _middleAreaMovie.show();
+ _middleAreaMovie.start();
+ }
+}
+
+// Only called by kInventorySignature.
+void AIArea::setLeftMovieTime(const TimeValue time) {
+ if (!_AIMovie.isSurfaceValid()) {
+ _leftAreaMovie.setTime(time);
+ _leftAreaMovie.show();
+ _leftAreaMovie.redrawMovieWorld();
+ }
+
+ _leftAreaOwner = kInventorySignature;
+ _leftInventoryTime = time;
+}
+
+void AIArea::setMiddleMovieTime(const LowerClientSignature client, const TimeValue time) {
+ if (client == kInventorySignature) {
+ _middleInventoryTime = time;
+ if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ if (currentBiochip && currentBiochip->isSelected())
+ currentBiochip->giveUpSharedArea();
+ }
+ } else {
+ _middleBiochipTime = time;
+ if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ if (currentItem && currentItem->isSelected())
+ currentItem->giveUpSharedArea();
+ }
+ }
+
+ _middleAreaMovie.setSegment(0, _middleAreaMovie.getDuration());
+ _middleAreaMovie.stop();
+ _middleAreaMovie.setFlags(0);
+ _middleAreaMovie.setTime(time);
+ _middleAreaMovie.show();
+ _middleAreaMovie.redrawMovieWorld();
+ _middleAreaOwner = client;
+}
+
+// Only called by kBiochipSignature.
+void AIArea::setRightMovieTime(const TimeValue time) {
+ if (!_AIMovie.isSurfaceValid()) {
+ // Can't do it when the AI movie is up...
+ _rightAreaMovie.setTime(time);
+ _rightAreaMovie.show();
+ _rightAreaMovie.redrawMovieWorld();
+ }
+
+ _rightAreaOwner = kBiochipSignature;
+ _rightBiochipTime = time;
+}
+
+void AIArea::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (JMPPPInput::isToggleAIMiddleInput(input))
+ toggleMiddleAreaOwner();
+ else
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+void AIArea::toggleMiddleAreaOwner() {
+ if (_middleAreaOwner == kInventorySignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ if (currentBiochip) {
+ setMiddleMovieTime(kBiochipSignature, currentBiochip->getSharedAreaTime());
+ currentBiochip->takeSharedArea();
+ }
+ } else if (_middleAreaOwner == kBiochipSignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ if (currentItem) {
+ setMiddleMovieTime(kInventorySignature, currentItem->getSharedAreaTime());
+ currentItem->takeSharedArea();
+ }
+ }
+}
+
+void AIArea::activateHotspots() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ if (currentBiochip)
+ switch (currentBiochip->getObjectID()) {
+ case kAIBiochip:
+ ((AIChip *)currentBiochip)->activateAIHotspots();
+ break;
+ case kPegasusBiochip:
+ if (!vm->isDemo())
+ ((PegasusChip *)currentBiochip)->activatePegasusHotspots();
+ break;
+ case kOpticalBiochip:
+ ((OpticalChip *)currentBiochip)->activateOpticalHotspots();
+ break;
+ }
+ } else if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ if (currentItem && currentItem->getObjectID() == kAirMask)
+ ((AirMask *)currentItem)->activateAirMaskHotspots();
+ }
+
+ InputHandler::activateHotspots();
+}
+
+void AIArea::clickInHotspot(const Input &input, const Hotspot *hotspot) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ bool handled = false;
+
+ if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+
+ if (currentBiochip) {
+ switch (currentBiochip->getObjectID()) {
+ case kAIBiochip:
+ if ((hotspot->getHotspotFlags() & kAIBiochipSpotFlag) != 0) {
+ ((AIChip *)currentBiochip)->clickInAIHotspot(hotspot->getObjectID());
+ handled = true;
+ }
+ break;
+ case kPegasusBiochip:
+ if (!vm->isDemo() && ((hotspot->getHotspotFlags() & kPegasusBiochipSpotFlag) != 0)) {
+ ((PegasusChip *)currentBiochip)->clickInPegasusHotspot();
+ handled = true;
+ }
+ break;
+ case kOpticalBiochip:
+ if ((hotspot->getHotspotFlags() & kOpticalBiochipSpotFlag) != 0) {
+ ((OpticalChip *)currentBiochip)->clickInOpticalHotspot(hotspot->getObjectID());
+ handled = true;
+ }
+ break;
+ }
+ }
+ } else if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+
+ if (currentItem) {
+ switch (currentItem->getObjectID()) {
+ case kAirMask:
+ if ((hotspot->getHotspotFlags() & kAirMaskSpotFlag) != 0) {
+ ((AirMask *)currentItem)->clickInAirMaskHotspot();
+ handled = true;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!handled)
+ InputHandler::clickInHotspot(input, hotspot);
+}
+
+void AIArea::lockAIOut() {
+ if (_lockCount == 0)
+ stopIdling();
+
+ _lockCount++;
+}
+
+void AIArea::unlockAI() {
+ if (_lockCount > 0) {
+ _lockCount--;
+ if (_lockCount == 0)
+ startIdling();
+ }
+}
+
+void AIArea::forceAIUnlocked() {
+ if (_lockCount > 0) {
+ _lockCount = 1;
+ unlockAI();
+ }
+}
+
+void AIArea::checkRules() {
+ if (_lockCount == 0 && ((PegasusEngine *)g_engine)->playerAlive())
+ for (AIRuleList::iterator it = _AIRules.begin(); it != _AIRules.end(); it++)
+ if ((*it)->fireRule())
+ break;
+}
+
+void AIArea::useIdleTime() {
+ checkRules();
+}
+
+void AIArea::addAIRule(AIRule *rule) {
+ _AIRules.push_back(rule);
+}
+
+void AIArea::removeAllRules() {
+ for (AIRuleList::iterator it = _AIRules.begin(); it != _AIRules.end(); it++)
+ delete *it;
+
+ _AIRules.clear();
+}
+
+void AIArea::checkMiddleArea() {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+
+ if (currentBiochip) {
+ if (_middleAreaOwner == kBiochipSignature) {
+ switch (currentBiochip->getObjectID()) {
+ case kAIBiochip:
+ ((AIChip *)currentBiochip)->setUpAIChip();
+ break;
+ case kPegasusBiochip:
+ ((PegasusChip *)currentBiochip)->setUpPegasusChip();
+ break;
+ }
+ } else {
+ switch (currentBiochip->getObjectID()) {
+ case kAIBiochip:
+ ((AIChip *)currentBiochip)->setUpAIChipRude();
+ break;
+ case kPegasusBiochip:
+ ((PegasusChip *)currentBiochip)->setUpPegasusChipRude();
+ break;
+ }
+ }
+ }
+}
+
+TimeValue AIArea::getBigInfoTime() {
+ if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ return currentItem->getInfoLeftTime();
+ } else if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ return currentBiochip->getInfoLeftTime();
+ }
+
+ return 0xffffffff;
+}
+
+void AIArea::getSmallInfoSegment(TimeValue &start, TimeValue &stop) {
+ if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ currentItem->getInfoRightTimes(start, stop);
+ } else if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ currentBiochip->getInfoRightTimes(start, stop);
+ } else {
+ start = 0xffffffff;
+ stop = 0xffffffff;
+ }
+}
+
+LowerClientSignature AIArea::getMiddleAreaOwner() {
+ return _middleAreaOwner;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/ai/ai_area.h b/engines/pegasus/ai/ai_area.h
new file mode 100644
index 0000000000..10bfc933a1
--- /dev/null
+++ b/engines/pegasus/ai/ai_area.h
@@ -0,0 +1,172 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_AI_AIAREA_H
+#define PEGASUS_AI_AIAREA_H
+
+#include "pegasus/input.h"
+#include "pegasus/movie.h"
+#include "pegasus/timers.h"
+#include "pegasus/ai/ai_rule.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+/*
+
+ The AI area is the area at the bottom of the screen. There are three areas within
+ the AI area:
+ 1) the inventory/AI help area
+ 2) the middle area
+ 3) the biochip display area
+
+ Area 1 is used for displaying the current inventory item. When the player changes the
+ current item, either by selecting a new one in the inventory list or by picking
+ up a new item, area 1 updates to show the new item.
+
+ If the AI decides to give a message, the AI's head temporarily takes over area 1
+ for the duration of the message, then goes away, returning the area to the current
+ inventory item.
+
+ Area 2 is used to display the current inventory item's state, the current biochip's
+ state, and any extra information from the AI. The contention for this area is
+ resolved as follows:
+ -- If the AI needs to use the area while giving a message in area 1, it takes over
+ area 2 for the duration of its message.
+*** This is not true.
+ -- If the player selects a new inventory item, the inventory item's state gets
+ displayed immediately.
+ -- If the player selects a new biochip, the biochip's state info gets displayed
+ immediately.
+ -- If any auto drawing is to occur, it seizes the area as soon as the drawing is
+ to occur. For example, the mapping biochip does auto drawing every time the
+ player takes a step. The only exception to this rule is if the AI is presenting
+ a warning. When the AI seizes areas 1 and 2, it preempts all other uses.
+ Some inventory items and biochips can cause arbitrary drawing to occur in this area
+ at arbitrary times. The map biochip is one example which causes drawing when the
+ player takes a step. Another example is the poison gas canister, which flashes in
+ this area to indicate a dangerous compound.
+
+ Area 3 is used to display the current biochip. When the player changes the current
+ biochip, either by selecting a new one from the biochip list or by picking up a
+ new one, area 3 updates to show the new item. In addition, some biochips can play
+ animation in this area.
+
+*/
+
+namespace Pegasus {
+
+class AIArea : public Surface, public Idler, public InputHandler {
+public:
+ AIArea(InputHandler *);
+ virtual ~AIArea();
+
+ void writeAIRules(Common::WriteStream *stream);
+ void readAIRules(Common::ReadStream *stream);
+
+ void initAIArea();
+
+ void saveAIState();
+ void restoreAIState();
+
+ void handleInput(const Input &, const Hotspot *);
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+
+ void setAIVolume(const uint16);
+
+ // There are only so many legal combinations of client/area.
+ // Here is the list of supported pairs:
+ // kInventorySignature kLeftAreaSignature
+ // kInventorySignature kMiddleAreaSignature
+ // kBiochipSignature kMiddleAreaSignature
+ // kBiochipSignature kRightAreaSignature
+ // kAISignature kLeftAreaSignature
+ // Further, the kAISignature never sets a static frame time in the left area,
+ // but only plays a sequence from the AI movie.
+ void setAIAreaToTime(const LowerClientSignature, const LowerAreaSignature, const TimeValue);
+
+ // The "Play" functions play the requested sequence synchronously.
+ void playAIAreaSequence(const LowerClientSignature, const LowerAreaSignature, const TimeValue, const TimeValue);
+
+ // For PlayAIMovie, it is assumed that the client is the AI itself.
+ // This is used to play AI messages as well as Optical Memory video.
+ // Returns true if the movie played all the way through, false if it was interrupted.
+ bool playAIMovie(const LowerAreaSignature, const Common::String &movieName, bool keepLastFrame, const InputBits);
+
+ // Loop the requested sequence indefinitely.
+ void loopAIAreaSequence(const LowerClientSignature, const LowerAreaSignature, const TimeValue, const TimeValue);
+
+ void addAIRule(AIRule *);
+
+ // Remove and delete all rules.
+ void removeAllRules();
+
+ void lockAIOut();
+ void unlockAI();
+ void forceAIUnlocked();
+
+ void checkMiddleArea();
+ void checkRules();
+
+ LowerClientSignature getMiddleAreaOwner();
+ void toggleMiddleAreaOwner();
+
+ TimeValue getBigInfoTime();
+ void getSmallInfoSegment(TimeValue &, TimeValue &);
+
+protected:
+ void useIdleTime();
+
+ void setLeftMovieTime(const TimeValue);
+ void setMiddleMovieTime(const LowerClientSignature, const TimeValue);
+ void setRightMovieTime(const TimeValue);
+
+ Movie _leftAreaMovie;
+ Movie _middleAreaMovie;
+ Movie _rightAreaMovie;
+ Movie _AIMovie;
+
+ LowerClientSignature _leftAreaOwner;
+ LowerClientSignature _middleAreaOwner;
+ LowerClientSignature _rightAreaOwner;
+
+ TimeValue _leftInventoryTime;
+ TimeValue _middleInventoryTime;
+ TimeValue _middleBiochipTime;
+ TimeValue _rightBiochipTime;
+
+ AIRuleList _AIRules;
+
+ uint _lockCount;
+};
+
+extern AIArea *g_AIArea;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/ai/ai_condition.cpp b/engines/pegasus/ai/ai_condition.cpp
new file mode 100644
index 0000000000..df6d3227e5
--- /dev/null
+++ b/engines/pegasus/ai/ai_condition.cpp
@@ -0,0 +1,290 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_condition.h"
+#include "pegasus/items/itemlist.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+AIOneChildCondition::AIOneChildCondition(AICondition *child) {
+ _child = child;
+}
+
+AIOneChildCondition::~AIOneChildCondition() {
+ delete _child;
+}
+
+void AIOneChildCondition::writeAICondition(Common::WriteStream *stream) {
+ if (_child)
+ _child->writeAICondition(stream);
+}
+
+void AIOneChildCondition::readAICondition(Common::ReadStream *stream) {
+ if (_child)
+ _child->readAICondition(stream);
+}
+
+AITwoChildrenCondition::AITwoChildrenCondition(AICondition *leftChild, AICondition *rightChild) {
+ _leftChild = leftChild;
+ _rightChild = rightChild;
+}
+
+AITwoChildrenCondition::~AITwoChildrenCondition() {
+ delete _leftChild;
+ delete _rightChild;
+}
+
+void AITwoChildrenCondition::writeAICondition(Common::WriteStream *stream) {
+ if (_leftChild)
+ _leftChild->writeAICondition(stream);
+
+ if (_rightChild)
+ _rightChild->writeAICondition(stream);
+}
+
+void AITwoChildrenCondition::readAICondition(Common::ReadStream *stream) {
+ if (_leftChild)
+ _leftChild->readAICondition(stream);
+
+ if (_rightChild)
+ _rightChild->readAICondition(stream);
+}
+
+AINotCondition::AINotCondition(AICondition* child) : AIOneChildCondition(child) {
+}
+
+bool AINotCondition::fireCondition() {
+ return _child && !_child->fireCondition();
+}
+
+AIAndCondition::AIAndCondition(AICondition *leftChild, AICondition *rightChild) : AITwoChildrenCondition(leftChild, rightChild) {
+}
+
+bool AIAndCondition::fireCondition() {
+ return _leftChild && _leftChild->fireCondition() && _rightChild && _rightChild->fireCondition();
+}
+
+AIOrCondition::AIOrCondition(AICondition *leftChild, AICondition *rightChild) : AITwoChildrenCondition(leftChild, rightChild) {
+}
+
+bool AIOrCondition::fireCondition() {
+ return (_leftChild && _leftChild->fireCondition()) || (_rightChild && _rightChild->fireCondition());
+}
+
+AITimerCondition::AITimerCondition(const TimeValue time, const TimeScale scale, const bool shouldStartTimer) {
+ _timerFuse.primeFuse(time, scale);
+ _timerFuse.setFunctionPtr((tFunctionPtr)&AITimerFunction, (void *)this);
+ _fired = false;
+
+ if (shouldStartTimer)
+ startTimer();
+}
+
+void AITimerCondition::startTimer() {
+ _fired = false;
+ _timerFuse.lightFuse();
+}
+
+void AITimerCondition::stopTimer() {
+ _timerFuse.stopFuse();
+}
+
+void AITimerCondition::writeAICondition(Common::WriteStream *stream) {
+ stream->writeByte(_timerFuse.isFuseLit());
+ stream->writeByte(_fired);
+ stream->writeUint32BE(_timerFuse.getTimeRemaining());
+ stream->writeUint32BE(_timerFuse.getFuseScale());
+}
+
+void AITimerCondition::readAICondition(Common::ReadStream *stream) {
+ bool running = stream->readByte();
+ _fired = stream->readByte();
+ TimeValue time = stream->readUint32BE();
+ TimeScale scale = stream->readUint32BE();
+
+ _timerFuse.stopFuse();
+ _timerFuse.primeFuse(time, scale);
+
+ if (running)
+ _timerFuse.lightFuse();
+}
+
+void AITimerCondition::AITimerFunction(FunctionPtr *, AITimerCondition *condition) {
+ condition->_fired = true;
+}
+
+bool AITimerCondition::fireCondition() {
+ return _fired;
+}
+
+AILocationCondition::AILocationCondition(uint32 maxLocations) {
+ _numLocations = 0;
+ _maxLocations = maxLocations;
+ _locations = new RoomViewID[maxLocations];
+}
+
+AILocationCondition::~AILocationCondition() {
+ delete[] _locations;
+}
+
+void AILocationCondition::addLocation(const RoomViewID location) {
+ if (_numLocations < _maxLocations)
+ _locations[_numLocations++] = location;
+}
+
+bool AILocationCondition::fireCondition() {
+ RoomViewID test = GameState.getCurrentRoomAndView(), *p;
+ uint32 i;
+
+ for (i = 0, p = _locations; i < _numLocations; i++, p++) {
+ if (test == *p) {
+ *p = MakeRoomView(kNoRoomID, kNoDirection);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AILocationCondition::writeAICondition(Common::WriteStream *stream) {
+ stream->writeUint32BE(_maxLocations);
+ stream->writeUint32BE(_numLocations);
+
+ uint32 i;
+ RoomViewID *p;
+ for (i = 0, p = _locations; i < _numLocations; i++, p++)
+ stream->writeUint32BE(*p);
+}
+
+void AILocationCondition::readAICondition(Common::ReadStream *stream) {
+ uint32 maxLocations = stream->readUint32BE();
+
+ if (_maxLocations != maxLocations) {
+ delete[] _locations;
+ _locations = new RoomViewID[maxLocations];
+ _maxLocations = maxLocations;
+ }
+
+ _numLocations = stream->readUint32BE();
+
+ uint32 i;
+ RoomViewID *p;
+ for (i = 0, p = _locations; i < _numLocations; i++, p++)
+ *p = stream->readUint32BE();
+}
+
+AIDoorOpenedCondition::AIDoorOpenedCondition(RoomViewID doorLocation) {
+ _doorLocation = doorLocation;
+}
+
+bool AIDoorOpenedCondition::fireCondition() {
+ return GameState.getCurrentRoomAndView() == _doorLocation && GameState.isCurrentDoorOpen();
+}
+
+AIHasItemCondition::AIHasItemCondition(const ItemID item) {
+ _item = item;
+}
+
+bool AIHasItemCondition::fireCondition() {
+ return _item == kNoItemID || GameState.isTakenItemID(_item);
+}
+
+AIDoesntHaveItemCondition::AIDoesntHaveItemCondition(const ItemID item) {
+ _item = item;
+}
+
+bool AIDoesntHaveItemCondition::fireCondition() {
+ return _item == kNoItemID || !GameState.isTakenItemID(_item);
+}
+
+AICurrentItemCondition::AICurrentItemCondition(const ItemID item) {
+ _item = item;
+}
+
+bool AICurrentItemCondition::fireCondition() {
+ InventoryItem *item = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+
+ if (_item == kNoItemID)
+ return item == 0;
+
+ return item != 0 && item->getObjectID() == _item;
+}
+
+AICurrentBiochipCondition::AICurrentBiochipCondition(const ItemID biochip) {
+ _biochip = biochip;
+}
+
+bool AICurrentBiochipCondition::fireCondition() {
+ BiochipItem *biochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+
+ if (_biochip == kNoItemID)
+ return biochip == 0;
+
+ return biochip != 0 && biochip->getObjectID() == _biochip;
+}
+
+AIItemStateCondition::AIItemStateCondition(const ItemID item, const ItemState state) {
+ _item = item;
+ _state = state;
+}
+
+bool AIItemStateCondition::fireCondition() {
+ Item *item = g_allItems.findItemByID(_item);
+ return item != 0 && item->getItemState() == _state;
+}
+
+AIEnergyMonitorCondition::AIEnergyMonitorCondition(const int32 energyThreshold) {
+ _energyThreshold = energyThreshold;
+}
+
+bool AIEnergyMonitorCondition::fireCondition() {
+ return g_energyMonitor != 0 && g_energyMonitor->getCurrentEnergy() < _energyThreshold;
+}
+
+AILastExtraCondition::AILastExtraCondition(const ExtraID lastExtra) {
+ _lastExtra = lastExtra;
+}
+
+bool AILastExtraCondition::fireCondition() {
+ return g_neighborhood && (ExtraID)g_neighborhood->getLastExtra() == _lastExtra;
+}
+
+AICondition *makeLocationAndDoesntHaveItemCondition(const RoomID room, const DirectionConstant direction, const ItemID item) {
+ AILocationCondition *location = new AILocationCondition(1);
+ location->addLocation(MakeRoomView(room, direction));
+
+ AIDoesntHaveItemCondition *doesntHaveItem = new AIDoesntHaveItemCondition(item);
+
+ return new AIAndCondition(location, doesntHaveItem);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/ai/ai_condition.h b/engines/pegasus/ai/ai_condition.h
new file mode 100644
index 0000000000..2d93a52eab
--- /dev/null
+++ b/engines/pegasus/ai/ai_condition.h
@@ -0,0 +1,287 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_AI_AICONDITION_H
+#define PEGASUS_AI_AICONDITION_H
+
+#include "pegasus/timers.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+namespace Pegasus {
+
+/////////////////////////////////////////////
+//
+// AICondition
+
+class AICondition {
+public:
+ AICondition() {}
+ virtual ~AICondition() {}
+
+ virtual bool fireCondition() = 0;
+
+ // Only need these for conditions that are dynamic, like timer conditions...
+ // other conditions, like item related conditions, which don't change during
+ // the run of an environment, are completely initted when the environment
+ // is created.
+ virtual void writeAICondition(Common::WriteStream *) {}
+ virtual void readAICondition(Common::ReadStream *) {}
+};
+
+/////////////////////////////////////////////
+//
+// AIOneChildCondition
+
+class AIOneChildCondition : public AICondition {
+public:
+ AIOneChildCondition(AICondition *);
+ virtual ~AIOneChildCondition();
+
+ virtual void writeAICondition(Common::WriteStream *);
+ virtual void readAICondition(Common::ReadStream *);
+
+protected:
+ AICondition *_child;
+};
+
+/////////////////////////////////////////////
+//
+// AITwoChildrenCondition
+
+class AITwoChildrenCondition : public AICondition {
+public:
+ AITwoChildrenCondition(AICondition *, AICondition *);
+ virtual ~AITwoChildrenCondition();
+
+ virtual void writeAICondition(Common::WriteStream *);
+ virtual void readAICondition(Common::ReadStream *);
+
+protected:
+ AICondition *_leftChild, *_rightChild;
+};
+
+/////////////////////////////////////////////
+//
+// AINotCondition
+
+class AINotCondition : public AIOneChildCondition {
+public:
+ AINotCondition(AICondition *);
+
+ virtual bool fireCondition();
+};
+
+/////////////////////////////////////////////
+//
+// AIAndCondition
+
+class AIAndCondition : public AITwoChildrenCondition {
+public:
+ AIAndCondition(AICondition *, AICondition *);
+
+ virtual bool fireCondition();
+};
+
+/////////////////////////////////////////////
+//
+// AIOrCondition
+
+class AIOrCondition : public AITwoChildrenCondition {
+public:
+ AIOrCondition(AICondition *, AICondition *);
+
+ virtual bool fireCondition();
+};
+
+/////////////////////////////////////////////
+//
+// AITimerCondition
+
+class AITimerCondition : public AICondition {
+public:
+ AITimerCondition(const TimeValue, const TimeScale, const bool);
+
+ void startTimer();
+ void stopTimer();
+
+ virtual bool fireCondition();
+
+ virtual void writeAICondition(Common::WriteStream *);
+ virtual void readAICondition(Common::ReadStream *);
+
+protected:
+ static void AITimerFunction(FunctionPtr *, AITimerCondition *);
+
+ FuseFunction _timerFuse;
+ bool _fired;
+};
+
+/////////////////////////////////////////////
+//
+// AILocationCondition
+
+class AILocationCondition : public AICondition {
+public:
+ AILocationCondition(uint32);
+ virtual ~AILocationCondition();
+
+ void addLocation(RoomViewID);
+ virtual bool fireCondition();
+
+ virtual void writeAICondition(Common::WriteStream *);
+ virtual void readAICondition(Common::ReadStream *);
+
+protected:
+ uint32 _numLocations, _maxLocations;
+ RoomViewID *_locations;
+};
+
+/////////////////////////////////////////////
+//
+// AIDoorOpenedCondition
+
+class AIDoorOpenedCondition : public AICondition {
+public:
+ AIDoorOpenedCondition(RoomViewID);
+ virtual ~AIDoorOpenedCondition() {}
+
+ virtual bool fireCondition();
+
+protected:
+ RoomViewID _doorLocation;
+};
+
+/////////////////////////////////////////////
+//
+// AIHasItemCondition
+
+class AIHasItemCondition : public AICondition {
+public:
+ AIHasItemCondition(const ItemID);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _item;
+};
+
+/////////////////////////////////////////////
+//
+// AIDoesntHaveItemCondition
+
+class AIDoesntHaveItemCondition : public AICondition {
+public:
+ AIDoesntHaveItemCondition(const ItemID);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _item;
+};
+
+/////////////////////////////////////////////
+//
+// AICurrentItemCondition
+
+class AICurrentItemCondition : public AICondition {
+public:
+ AICurrentItemCondition(const ItemID);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _item;
+};
+
+/////////////////////////////////////////////
+//
+// AICurrentBiochipCondition
+
+class AICurrentBiochipCondition : public AICondition {
+public:
+ AICurrentBiochipCondition(const ItemID);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _biochip;
+};
+
+/////////////////////////////////////////////
+//
+// AIItemStateCondition
+
+class AIItemStateCondition : public AICondition {
+public:
+ AIItemStateCondition(const ItemID, const ItemState);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _item;
+ ItemState _state;
+};
+
+/////////////////////////////////////////////
+//
+// AIEnergyMonitorCondition
+
+class AIEnergyMonitorCondition : public AICondition {
+public:
+ AIEnergyMonitorCondition(const int32);
+
+ virtual bool fireCondition();
+
+protected:
+ int32 _energyThreshold;
+};
+
+/////////////////////////////////////////////
+//
+// AILastExtraCondition
+
+class AILastExtraCondition : public AICondition {
+public:
+ AILastExtraCondition(const ExtraID);
+
+ virtual bool fireCondition();
+
+protected:
+ ExtraID _lastExtra;
+};
+
+/////////////////////////////////////////////
+//
+// Helper functions
+
+AICondition *makeLocationAndDoesntHaveItemCondition(const RoomID room, const DirectionConstant direction, const ItemID item);
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/ai/ai_rule.cpp b/engines/pegasus/ai/ai_rule.cpp
new file mode 100644
index 0000000000..3aaa530a4a
--- /dev/null
+++ b/engines/pegasus/ai/ai_rule.cpp
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "pegasus/ai/ai_action.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/ai/ai_condition.h"
+#include "pegasus/ai/ai_rule.h"
+
+namespace Pegasus {
+
+bool AIRule::fireRule() {
+ if (_ruleActive && _ruleCondition && _ruleAction && _ruleCondition->fireCondition()) {
+ if (g_AIArea)
+ g_AIArea->lockAIOut();
+
+ _ruleAction->performAIAction(this);
+
+ if (--_ruleAction->_actionCount <= 0)
+ deactivateRule();
+
+ if (g_AIArea)
+ g_AIArea->unlockAI();
+
+ return true;
+ }
+
+ return false;
+}
+
+void AIRule::writeAIRule(Common::WriteStream *stream) {
+ stream->writeByte(_ruleActive);
+
+ if (_ruleCondition)
+ _ruleCondition->writeAICondition(stream);
+}
+
+void AIRule::readAIRule(Common::ReadStream *stream) {
+ _ruleActive = stream->readByte();
+
+ if (_ruleCondition)
+ _ruleCondition->readAICondition(stream);
+}
+
+void AIRuleList::writeAIRules(Common::WriteStream *stream) {
+ for (AIRuleList::iterator it = begin(); it != end(); it++)
+ (*it)->writeAIRule(stream);
+}
+
+void AIRuleList::readAIRules(Common::ReadStream *stream) {
+ for (AIRuleList::iterator it = begin(); it != end(); it++)
+ (*it)->readAIRule(stream);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/ai/ai_rule.h b/engines/pegasus/ai/ai_rule.h
new file mode 100644
index 0000000000..bccd4ecb06
--- /dev/null
+++ b/engines/pegasus/ai/ai_rule.h
@@ -0,0 +1,86 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_AI_AIRULE_H
+#define PEGASUS_AI_AIRULE_H
+
+#include "common/list.h"
+
+#include "pegasus/ai/ai_action.h"
+#include "pegasus/ai/ai_condition.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+namespace Pegasus {
+
+class AICondition;
+class AIAction;
+
+class AIRule {
+public:
+ AIRule(AICondition *condition, AIAction *rule) {
+ _ruleCondition = condition;
+ _ruleAction = rule;
+ _ruleActive = true;
+ }
+
+ ~AIRule() {
+ if (_ruleCondition)
+ delete _ruleCondition;
+
+ if (_ruleAction)
+ delete _ruleAction;
+ }
+
+ bool fireRule();
+
+ void activateRule() { _ruleActive = true; }
+ void deactivateRule() { _ruleActive = false; }
+ bool isRuleActive() { return _ruleActive; }
+
+ void writeAIRule(Common::WriteStream *);
+ void readAIRule(Common::ReadStream *);
+
+protected:
+ AICondition *_ruleCondition;
+ AIAction *_ruleAction;
+ bool _ruleActive;
+};
+
+class AIRuleList : public Common::List<AIRule *> {
+public:
+ AIRuleList() {}
+ ~AIRuleList() {}
+
+ void writeAIRules(Common::WriteStream *);
+ void readAIRules(Common::ReadStream *);
+};
+
+} // End of namespace Pegasus
+
+#endif