/* 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 .
*
*/
#ifndef PRINCE_PRINCE_H
#define PRINCE_PRINCE_H
#include "common/random.h"
#include "common/system.h"
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/textconsole.h"
#include "common/text-to-speech.h"
#include "common/rect.h"
#include "common/events.h"
#include "common/endian.h"
#include "common/savefile.h"
#include "common/serializer.h"
#include "image/bmp.h"
#include "gui/debugger.h"
#include "engines/engine.h"
#include "engines/util.h"
#include "audio/mixer.h"
#include "video/flic_decoder.h"
#include "prince/mob.h"
#include "prince/object.h"
#include "prince/pscr.h"
#include "prince/detection.h"
namespace Prince {
enum PRINCEActions {
kActionNone,
kActionSave,
kActionLoad,
kActionZ,
kActionX,
kActionSkip,
};
struct SavegameHeader;
class PrinceEngine;
class GraphicsMan;
class Script;
class Interpreter;
class InterpreterFlags;
class Debugger;
class MusicPlayer;
class VariaTxt;
class Cursor;
class MhwanhDecoder;
class Font;
class Hero;
class Animation;
class Room;
class Pscr;
struct SavegameHeader {
uint8 version;
Common::String saveName;
Graphics::Surface *thumbnail;
int16 saveYear, saveMonth, saveDay;
int16 saveHour, saveMinutes;
uint32 playTime;
};
#define kSavegameStrSize 14
#define kSavegameStr "SCUMMVM_PRINCE"
struct Text {
const char *_str;
uint16 _x, _y;
uint16 _time;
uint32 _color;
Text() {
clear();
}
void clear() {
_str = nullptr;
_x = 0;
_y = 0;
_time = 0;
_color = 255;
}
};
struct AnimListItem {
uint16 _type; // type of animation - for background anims RND of frame
uint16 _fileNumber;
uint16 _startPhase; // first phase number
uint16 _endPhase;
uint16 _loopPhase;
int16 _x;
int16 _y;
uint16 _loopType;
uint16 _nextAnim; // number of animation to do for loop = 3
uint16 _flags; // byte 0 - draw masks, byte 1 - draw in front of mask, byte 2 - load but turn off drawing
bool loadFromStream(Common::SeekableReadStream &stream);
};
struct BAS {
int32 _type; // type of sequence
int32 _data; // additional data
int32 _anims; // number of animations
int32 _current; // actual number of animation
int32 _counter; // time counter for animation
int32 _currRelative; //actual relative number for animation
int32 _data2; // additional data for measurements
};
const int kStructSizeBAS = 28;
struct BASA {
int16 _num; // animation number
int16 _start; // initial frame
int16 _end; // final frame
//int16 _pad; // fulfilment to 8 bytes
};
const int kStructSizeBASA = 8;
// background and normal animation
struct Anim {
BASA _basaData;
int32 _addr; // animation address
int16 _usage;
int16 _state; // state of animation: 0 - turning on, 1 - turning off
int16 _flags;
int16 _frame; // number of phase to show
int16 _lastFrame; // last phase
int16 _loopFrame; // first frame of loop
int16 _showFrame; // actual visible frame of animation
int16 _loopType; // type of loop (0 - last frame; 1 - normal loop (begin from _loopFrame); 2 - no loop; 3 - load new animation)
int16 _nextAnim; // number of next animation to load after actual
int16 _x;
int16 _y;
int32 _currFrame;
int16 _currX;
int16 _currY;
int16 _currW;
int16 _currH;
int16 _packFlag;
int32 _currShadowFrame;
int16 _packShadowFlag;
int32 _shadowBack;
int16 _relX;
int16 _relY;
Animation *_animData;
Animation *_shadowData;
enum AnimOffsets {
kAnimState = 10,
kAnimFrame = 14,
kAnimLastFrame = 16,
kAnimX = 26
};
int16 getAnimData(Anim::AnimOffsets offset) {
switch (offset) {
case kAnimState:
return _state;
case kAnimFrame:
return _frame + 1; // fix for location 30 - man with a dog animation
case kAnimX:
return _x;
default:
error("getAnimData() - Wrong offset type: %d", (int)offset);
}
}
void setAnimData(Anim::AnimOffsets offset, int16 value) {
if (offset == kAnimX) {
_x = value;
} else {
error("setAnimData() - Wrong offset: %d, value: %d", (int)offset, value);
}
}
};
struct BackgroundAnim {
BAS _seq;
Common::Array backAnims;
};
enum AnimType {
kBackgroundAnimation,
kNormalAnimation
};
// Nak (PL - Nakladka)
struct Mask {
uint16 _state; // visible / invisible
int16 _flags; // turning on / turning off of a mask
int16 _x1;
int16 _y1;
int16 _x2;
int16 _y2;
int16 _z;
int16 _number; // number of mask for background recreating
int16 _width;
int16 _height;
byte *_data;
int16 getX() const {
return READ_LE_UINT16(_data);
}
int16 getY() const {
return READ_LE_UINT16(_data + 2);
}
int16 getWidth() const {
return READ_LE_UINT16(_data + 4);
}
int16 getHeight() const {
return READ_LE_UINT16(_data + 6);
}
byte *getMask() const {
return (byte *)(_data + 8);
}
};
struct InvItem {
int _x;
int _y;
Graphics::Surface *_surface;
Graphics::Surface *getSurface() const { return _surface; }
};
struct DrawNode {
int posX;
int posY;
int posZ;
int32 width;
int32 height;
int32 scaleValue;
Graphics::Surface *s;
Graphics::Surface *originalRoomSurface;
void *data;
void (*drawFunction)(Graphics::Surface *, DrawNode *);
};
struct DebugChannel {
enum Type {
kScript = 1 << 0,
kEngine = 1 << 1
};
};
static const uint8 kHeroTextColor = 220;
class PrinceEngine : public Engine {
protected:
Common::Error run() override;
public:
PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc);
~PrinceEngine() override;
bool scummVMSaveLoadDialog(bool isSave);
bool hasFeature(EngineFeature f) const override;
void pauseEngineIntern(bool pause) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
Common::Error loadGameState(int slot) override;
void playVideo(const Common::Path &videoFilename);
WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true);
void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream);
bool loadGame(int slotNumber);
void resetGame();
int32 _creditsDataSize;
byte *_creditsData;
void scrollCredits();
int getGameType() const;
const char *getGameId() const;
uint32 getFeatures() const;
Common::Language getLanguage() const;
const PrinceGameDescription *_gameDescription;
Video::FlicDecoder _flicPlayer;
const Graphics::Surface *_flcFrameSurface;
VariaTxt *_variaTxt;
uint32 _talkTxtSize;
byte *_talkTxt;
uint32 _mobTranslationSize;
byte *_mobTranslationData;
bool _missingVoice;
bool loadLocation(uint16 locationNr);
bool loadAnim(uint16 animNr, bool loop);
bool loadVoice(uint32 textSlot, uint32 sampleSlot, const Common::String &name);
bool loadSample(uint32 sampleSlot, const Common::String &name);
bool loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName);
bool loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2);
bool loadTrans(byte *transTable, const char *resourceName);
bool loadMobPriority(const char *resourceName);
void loadMobTranslationTexts();
void setMobTranslationTexts();
bool loadMusic(int musNumber);
void stopMusic();
void playSample(uint16 sampleId, uint16 loopType);
void stopSample(uint16 sampleId);
void stopAllSamples();
void freeSample(uint16 sampleId);
void freeAllSamples();
void setVoice(uint16 slot, uint32 sampleSlot, uint16 flag);
void changeCursor(uint16 curId);
void printAt(uint32 slot, uint8 color, char *s, uint16 x, uint16 y);
int calcTextLines(const char *s);
int calcTextTime(int numberOfLines);
void correctStringDEU(char *s);
void sayText(const Common::String &text, bool isSpeech, Common::TextToSpeechManager::Action action = Common::TextToSpeechManager::INTERRUPT);
#ifdef USE_TTS
Common::U32String convertText(const Common::String &text) const;
bool checkConversionTable(const byte *character, int &index, byte *convertedBytes, const uint16 *table) const;
#endif
void setTTSVoice(uint8 textColor) const;
void stopTextToSpeech() const;
static const uint8 kMaxTexts = 32;
Text _textSlots[kMaxTexts];
Hero *_mainHero;
Hero *_secondHero;
enum HeroId {
kMainHero,
kSecondHero
};
int _mouseFlag;
uint32 _currentTime;
uint16 _locationNr;
uint16 _sceneWidth;
int32 _picWindowX;
int32 _picWindowY;
bool _printMapNotification;
bool _intro;
bool _credits;
Image::BitmapDecoder *_roomBmp;
MhwanhDecoder *_suitcaseBmp;
Room *_room;
Script *_script;
InterpreterFlags *_flags;
Interpreter *_interpreter;
GraphicsMan *_graph;
uint8 _currentMidi;
byte *_zoomBitmap;
byte *_shadowBitmap;
byte *_transTable;
int16 _scaleValue; // scale for hero or special shadow animation
int16 _lightX; // for hero shadow
int16 _lightY;
int32 _shadScaleValue;
int32 _shadLineLen;
byte *_shadowLine;
void setShadowScale(int32 shadowScale);
static const int16 kFPS = 15;
static const int32 kIntMax = 2147483647;
static const int16 kMaxPicWidth = 1280;
static const int16 kMaxPicHeight = 480;
static const int16 kZoomStep = 4;
static const int32 kZoomBitmapLen = kMaxPicHeight / kZoomStep * kMaxPicWidth / kZoomStep;
static const int32 kShadowBitmapSize = kMaxPicWidth * kMaxPicHeight / 8;
static const int16 kShadowLineArraySize = 2 * 1280 * 4;
static const int16 kZoomBitmapWidth = kMaxPicWidth / kZoomStep;
static const int16 kZoomBitmapHeight = kMaxPicHeight / kZoomStep;
static const int16 kNormalWidth = 640;
static const int16 kNormalHeight = 480;
static const uint32 kTransTableSize = 256 * 256;
static const int kMaxNormAnims = 64;
static const int kMaxBackAnims = 64;
static const int kMaxObjects = 64;
static const int kMaxMobs = 64;
Common::Array _drawNodeList;
Common::Array _animList;
Common::Array _backAnimList;
Common::Array _normAnimList;
Common::Array _mobList;
Common::Array _mobPriorityList;
Common::Array _maskList;
Common::Array