scummvm/engines/freescape/freescape.h

505 lines
17 KiB
C++

/* 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.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef FREESCAPE_H
#define FREESCAPE_H
#include "common/bitarray.h"
#include "common/events.h"
#include "engines/advancedDetector.h"
#include "graphics/managed_surface.h"
#include "graphics/surface.h"
#include "audio/decoders/wave.h"
#include "audio/mixer.h"
#include "audio/softsynth/pcspk.h"
#include "graphics/framelimiter.h"
#include "freescape/area.h"
#include "freescape/gfx.h"
#include "freescape/objects/entrance.h"
#include "freescape/objects/geometricobject.h"
#include "freescape/objects/sensor.h"
#include "freescape/sound.h"
namespace Common {
class RandomSource;
}
namespace Freescape {
class Renderer;
#define FREESCAPE_DATA_BUNDLE "freescape.dat"
enum CameraMovement {
kForwardMovement,
kBackwardMovement,
kLeftMovement,
kRightMovement
};
typedef Common::HashMap<uint16, Area *> AreaMap;
typedef Common::Array<byte *> ColorMap;
typedef Common::HashMap<uint16, int32> StateVars;
enum {
kFreescapeDebugMove = 1 << 0,
kFreescapeDebugParser = 1 << 1,
kFreescapeDebugCode = 1 << 2,
kFreescapeDebugMedia = 1 << 4,
};
enum GameStateControl {
kFreescapeGameStateStart,
kFreescapeGameStatePlaying,
kFreescapeGameStateDemo,
kFreescapeGameStateEnd,
kFreescapeGameStateRestart,
};
struct CGAPaletteEntry {
int areaId;
byte *palette;
};
class EventManagerWrapper {
public:
EventManagerWrapper(Common::EventManager *delegate);
// EventManager API
bool pollEvent(Common::Event &event);
void purgeKeyboardEvents();
void purgeMouseEvents();
void pushEvent(Common::Event &event);
void clearExitEvents();
private:
// for continuous events (keyDown)
enum {
kKeyRepeatInitialDelay = 400,
kKeyRepeatSustainDelay = 100
};
Common::EventManager *_delegate;
Common::KeyState _currentKeyDown;
uint32 _keyRepeatTime;
};
class FreescapeEngine : public Engine {
public:
FreescapeEngine(OSystem *syst, const ADGameDescription *gd);
~FreescapeEngine();
const ADGameDescription *_gameDescription;
GameStateControl _gameStateControl;
bool isDemo() const;
// Game selection
uint32 _variant;
Common::Language _language;
bool isSpaceStationOblivion() { return _targetName.hasPrefix("spacestationoblivion"); }
bool isDriller() { return _targetName.hasPrefix("driller") || _targetName.hasPrefix("spacestationoblivion"); }
bool isDark() { return _targetName.hasPrefix("darkside"); }
bool isEclipse() { return _targetName.hasPrefix("totaleclipse"); } // This will match Total Eclipse 1 and 2.
bool isEclipse2() { return _targetName.hasPrefix("totaleclipse2"); }
bool isCastle() { return _targetName.hasPrefix("castle"); }
bool isAmiga() { return _gameDescription->platform == Common::kPlatformAmiga; }
bool isAtariST() { return _gameDescription->platform == Common::kPlatformAtariST; }
bool isDOS() { return _gameDescription->platform == Common::kPlatformDOS; }
bool isSpectrum() { return _gameDescription->platform == Common::kPlatformZX; }
bool isCPC() { return _gameDescription->platform == Common::kPlatformAmstradCPC; }
bool isC64() { return _gameDescription->platform == Common::kPlatformC64; }
Common::Error run() override;
// UI
Common::Rect _viewArea;
Common::Rect _fullscreenViewArea;
void centerCrossair();
virtual void borderScreen();
virtual void titleScreen();
void drawFullscreenSurface(Graphics::Surface *surface);
virtual void loadBorder();
virtual void processBorder();
void drawBorder();
void drawTitle();
virtual void drawBackground();
void clearBackground();
virtual void drawUI();
virtual void drawInfoMenu();
void drawBorderScreenAndWait(Graphics::Surface *surface);
virtual void drawCrossair(Graphics::Surface *surface);
Graphics::ManagedSurface *_border;
Graphics::ManagedSurface *_title;
Graphics::Surface *_background;
Texture *_borderTexture;
Texture *_titleTexture;
Texture *_uiTexture;
Texture *_skyTexture;
Common::Array<Graphics::Surface *>_indicators;
Common::HashMap<uint16, Texture *> _borderCGAByArea;
Common::HashMap<uint16, byte *> _paletteCGAByArea;
// Parsing assets
uint8 _binaryBits;
virtual void loadAssets();
virtual void loadAssetsDemo();
virtual void loadAssetsFullGame();
virtual void loadAssetsAtariFullGame();
virtual void loadAssetsAtariDemo();
virtual void loadAssetsAmigaFullGame();
virtual void loadAssetsAmigaDemo();
virtual void loadAssetsDOSFullGame();
virtual void loadAssetsDOSDemo();
virtual void loadAssetsZXFullGame();
virtual void loadAssetsZXDemo();
virtual void loadAssetsCPCFullGame();
virtual void loadAssetsCPCDemo();
virtual void loadAssetsC64FullGame();
virtual void loadAssetsC64Demo();
virtual void drawDOSUI(Graphics::Surface *surface);
virtual void drawZXUI(Graphics::Surface *surface);
virtual void drawCPCUI(Graphics::Surface *surface);
virtual void drawC64UI(Graphics::Surface *surface);
virtual void drawAmigaAtariSTUI(Graphics::Surface *surface);
Common::Archive *_dataBundle;
void loadDataBundle();
Graphics::Surface *loadBundledImage(const Common::String &name);
byte *getPaletteFromNeoImage(Common::SeekableReadStream *stream, int offset);
Graphics::ManagedSurface *loadAndConvertNeoImage(Common::SeekableReadStream *stream, int offset, byte *palette = nullptr);
Graphics::ManagedSurface *loadAndCenterScrImage(Common::SeekableReadStream *stream);
void loadPalettes(Common::SeekableReadStream *file, int offset);
void swapPalette(uint16 areaID);
virtual byte *findCGAPalette(uint16 levelID);
const CGAPaletteEntry *_rawCGAPaletteByArea;
Common::HashMap<uint16, byte *> _paletteByArea;
void loadColorPalette();
// Demo
Common::Array<byte> _demoData;
int _demoIndex;
int _currentDemoInputCode;
int _currentDemoInputRepetition;
Common::Array<Common::Event> _demoEvents;
Common::Point _currentDemoMousePosition;
void loadDemoData(Common::SeekableReadStream *file, int offset, int size);
int decodeAmigaAtariKey(int code);
int decodeDOSKey(int code);
Common::Event decodeDOSMouseEvent(int code, int repetition);
uint16 readField(Common::SeekableReadStream *file, int nbits);
uint16 readPtr(Common::SeekableReadStream *file);
Common::Array<uint16> readArray(Common::SeekableReadStream *file, int size);
// 8-bit
void load8bitBinary(Common::SeekableReadStream *file, int offset, int ncolors);
Area *load8bitArea(Common::SeekableReadStream *file, uint16 ncolors);
Object *load8bitObject(Common::SeekableReadStream *file);
Group *load8bitGroup(Common::SeekableReadStream *file, byte rawFlagsAndType);
Group *load8bitGroupV1(Common::SeekableReadStream *file, byte rawFlagsAndType);
Group *load8bitGroupV2(Common::SeekableReadStream *file, byte rawFlagsAndType);
void loadGlobalObjects(Common::SeekableReadStream *file, int offset, int size);
void renderPixels8bitBinImage(Graphics::ManagedSurface *surface, int row, int column, int bit, int count);
void renderPixels8bitBinCGAImage(Graphics::ManagedSurface *surface, int &i, int &j, uint8 pixels, int color);
void renderPixels8bitBinEGAImage(Graphics::ManagedSurface *surface, int &i, int &j, uint8 pixels, int color);
Graphics::ManagedSurface *load8bitBinImage(Common::SeekableReadStream *file, int offset);
void load8bitBinImageRow(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int row);
void load8bitBinImageRowIteration(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int row, int bit);
int execute8bitBinImageCommand(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int row, int pixels, int bit);
int execute8bitBinImageSingleCommand(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int row, int pixels, int bit, int count);
int execute8bitBinImageMultiCommand(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int row, int pixels, int bit, int count);
// Areas
uint16 _startArea;
uint16 _endArea;
AreaMap _areaMap;
Area *_currentArea;
bool _gotoExecuted;
Math::Vector3d _scale;
virtual void gotoArea(uint16 areaID, int entranceID);
// Entrance
uint16 _startEntrance;
uint16 _endEntrance;
Common::HashMap<int, const struct entrancesTableEntry *> _entranceTable;
// Input
bool _demoMode;
bool _disableDemoMode;
bool _flyMode;
bool _shootMode;
bool _noClipMode;
bool _invertY;
virtual void initKeymaps(Common::Keymap *engineKeyMap, const char *target);
EventManagerWrapper *_eventManager;
void processInput();
void resetInput();
void generateDemoInput();
virtual void pressedKey(const int keycode);
virtual void releasedKey(const int keycode);
virtual bool onScreenControls(Common::Point mouse);
void move(CameraMovement direction, uint8 scale, float deltaTime);
void resolveCollisions(Math::Vector3d newPosition);
virtual void checkIfStillInArea();
void changePlayerHeight(int index);
void increaseStepSize();
void decreaseStepSize();
void rise();
void lower();
bool checkFloor(Math::Vector3d currentPosition);
bool tryStepUp(Math::Vector3d currentPosition);
bool tryStepDown(Math::Vector3d currentPosition);
bool _hasFallen;
int _maxFallingDistance;
int _maxShield;
int _maxEnergy;
void rotate(float xoffset, float yoffset);
// Input state
float _lastFrame;
// Interaction
void activate();
void shoot();
void traverseEntrance(uint16 entranceID);
// Euler Angles
float _yaw;
float _pitch;
int _angleRotationIndex;
Common::Array<float> _angleRotations;
Math::Vector3d directionToVector(float pitch, float heading);
void updateCamera();
// Camera options
Common::Point _crossairPosition;
float _mouseSensitivity;
Math::Vector3d _upVector; // const
Math::Vector3d _cameraFront, _cameraRight;
// Spacial attributes
Math::Vector3d _position, _rotation, _velocity;
Math::Vector3d _lastPosition;
int _playerHeightNumber;
Common::Array<int> _playerHeights;
uint16 _playerHeight;
uint16 _playerWidth;
uint16 _playerDepth;
uint16 _stepUpDistance;
int _playerStepIndex;
Common::Array<int> _playerSteps;
// Effects
Common::Array<Common::String> _conditionSources;
Common::Array<FCLInstructionVector> _conditions;
bool runCollisionConditions(Math::Vector3d const lastPosition, Math::Vector3d const newPosition);
Math::Vector3d _objExecutingCodeSize;
virtual void executeMovementConditions();
bool executeObjectConditions(GeometricObject *obj, bool shot, bool collided, bool activated);
void executeLocalGlobalConditions(bool shot, bool collided, bool timer);
void executeCode(FCLInstructionVector &code, bool shot, bool collided, bool timer, bool activated);
// Instructions
bool checkConditional(FCLInstruction &instruction, bool shot, bool collided, bool timer, bool activated);
bool checkIfGreaterOrEqual(FCLInstruction &instruction);
void executeExecute(FCLInstruction &instruction);
void executeIncrementVariable(FCLInstruction &instruction);
void executeDecrementVariable(FCLInstruction &instruction);
void executeSetVariable(FCLInstruction &instruction);
void executeGoto(FCLInstruction &instruction);
void executeIfThenElse(FCLInstruction &instruction);
void executeMakeInvisible(FCLInstruction &instruction);
void executeMakeVisible(FCLInstruction &instruction);
void executeToggleVisibility(FCLInstruction &instruction);
void executeDestroy(FCLInstruction &instruction);
void executeRedraw(FCLInstruction &instruction);
void executeSound(FCLInstruction &instruction);
void executeDelay(FCLInstruction &instruction);
bool executeEndIfNotEqual(FCLInstruction &instruction);
void executeSetBit(FCLInstruction &instruction);
void executeClearBit(FCLInstruction &instruction);
void executeToggleBit(FCLInstruction &instruction);
bool executeEndIfBitNotEqual(FCLInstruction &instruction);
bool executeEndIfVisibilityIsEqual(FCLInstruction &instruction);
void executeSwapJet(FCLInstruction &instruction);
virtual void executePrint(FCLInstruction &instruction);
void executeSPFX(FCLInstruction &instruction);
void executeStartAnim(FCLInstruction &instruction);
// Sound
Audio::SoundHandle _soundFxHandle;
Audio::SoundHandle _musicHandle;
Freescape::SizedPCSpeaker *_speaker;
bool _syncSound;
bool _firstSound;
bool _usePrerecordedSounds;
void waitForSounds();
void stopAllSounds();
bool isPlayingSound();
void playSound(int index, bool sync);
void playWav(const Common::Path &filename);
void playMusic(const Common::Path &filename);
void queueSoundConst(double hzFreq, int duration);
void playSilence(int duration, bool sync);
void playSoundConst(double hzFreq, int duration, bool sync);
void playSoundSweepIncWL(double hzFreq1, double hzFreq2, double wlStepPerMS, int resolution, bool sync);
uint16 playSoundDOSSpeaker(uint16 startFrequency, soundSpeakerFx *speakerFxInfo);
void playSoundDOS(soundSpeakerFx *speakerFxInfo, bool sync);
virtual void playSoundFx(int index, bool sync);
virtual void loadSoundsFx(Common::SeekableReadStream *file, int offset, int number);
Common::HashMap<uint16, soundFx *> _soundsFx;
void loadSpeakerFxDOS(Common::SeekableReadStream *file, int offsetFreq, int offsetDuration);
void loadSpeakerFxZX(Common::SeekableReadStream *file, int sfxTable, int sfxData);
Common::HashMap<uint16, soundSpeakerFx *> _soundsSpeakerFx;
void playSoundZX(Common::Array<soundUnitZX> *data);
Common::HashMap<uint16, Common::Array<soundUnitZX>*> _soundsSpeakerFxZX;
int _nextSoundToPlay = 1;
// Rendering
int _screenW, _screenH;
Renderer *_gfx;
Graphics::FrameLimiter *_frameLimiter;
bool _vsyncEnabled;
Common::RenderMode _renderMode;
ColorMap _colorMap;
int _underFireFrames;
int _avoidRenderingFrames;
int _shootingFrames;
GeometricObject *_delayedShootObject;
void drawFrame();
void flashScreen(int backgroundColor);
uint8 _colorNumber;
Math::Vector3d _scaleVector;
float _nearClipPlane;
float _farClipPlane;
// Text messages and Fonts
void insertTemporaryMessage(const Common::String message, int deadline);
void getLatestMessages(Common::String &message, int &deadline);
void clearTemporalMessages();
Common::StringArray _temporaryMessages;
Common::Array<int> _temporaryMessageDeadlines;
Common::StringArray _messagesList;
Common::String _noShieldMessage;
Common::String _noEnergyMessage;
Common::String _fallenMessage;
Common::String _timeoutMessage;
Common::String _forceEndGameMessage;
Common::String _crushedMessage;
void loadMessagesFixedSize(Common::SeekableReadStream *file, int offset, int size, int number);
virtual void loadMessagesVariableSize(Common::SeekableReadStream *file, int offset, int number);
void drawFullscreenMessageAndWait(Common::String message);
void drawFullscreenMessage(Common::String message, uint32 front, Graphics::Surface *surface);
void loadFonts(Common::SeekableReadStream *file, int offset);
void loadFonts(byte *font, int charNumber);
Common::StringArray _currentAreaMessages;
Common::StringArray _currentEphymeralMessages;
Common::BitArray _font;
bool _fontLoaded;
void drawStringInSurface(const Common::String &str, int x, int y, uint32 fontColor, uint32 backColor, Graphics::Surface *surface, int offset = 0);
Graphics::Surface *drawStringsInSurface(const Common::Array<Common::String> &lines);
// Game state
virtual void initGameState();
void setGameBit(int index);
void clearGameBit(int index);
void toggleGameBit(int index);
uint16 getGameBit(int index);
StateVars _gameStateVars;
uint32 _gameStateBits;
virtual bool checkIfGameEnded();
virtual void endGame();
bool _endGameKeyPressed;
bool _endGamePlayerEndArea;
bool _forceEndGame;
bool _playerWasCrushed;
ObjectArray _sensors;
virtual void checkSensors();
virtual void drawSensorShoot(Sensor *sensor);
void takeDamageFromSensor();
bool hasFeature(EngineFeature f) const override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override { return true; }
bool canSaveAutosaveCurrently() override { return false; }
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override { return true; }
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
virtual Common::Error saveGameStreamExtended(Common::WriteStream *stream, bool isAutosave = false);
virtual Common::Error loadGameStreamExtended(Common::SeekableReadStream *stream);
Graphics::Surface *_savedScreen;
void pauseEngineIntern(bool pause) override;
// Timers
bool startCountdown(uint32 delay);
void removeTimers();
bool _timerStarted;
int _initialCountdown;
int _countdown;
int _ticks;
int _ticksFromEnd;
int _lastTick;
int _lastMinute;
void getTimeFromCountdown(int &seconds, int &minutes, int &hours);
virtual void updateTimeVariables();
// Cheats
bool _useExtendedTimer;
bool _disableSensors;
bool _disableFalling;
// Random
Common::RandomSource *_rnd;
};
extern FreescapeEngine *g_freescape;
} // namespace Freescape
#endif // FREESCAPE_H