MADS: Implement loading logic for UI background animations

This commit is contained in:
Paul Gilbert 2014-04-07 22:37:22 -04:00
parent f6a6ea9741
commit 7e13f488ab
13 changed files with 206 additions and 40 deletions

View File

@ -108,15 +108,24 @@ void AnimMessage::load(Common::SeekableReadStream *f) {
f->skip(2);
}
void AnimFrameEntry::load(Common::SeekableReadStream *f) {
_frameNumber = f->readUint16LE();
_seqIndex = f->readByte();
_spriteSlot._spritesIndex = f->readByte();
_spriteSlot._frameNumber = f->readUint16LE();
_spriteSlot._position.x = f->readSint16LE();
_spriteSlot._position.y = f->readSint16LE();
_spriteSlot._depth = f->readSByte();
_spriteSlot._scale = (int8)f->readByte();
void AnimFrameEntry::load(Common::SeekableReadStream *f, bool uiFlag) {
if (uiFlag) {
f->skip(2);
_seqIndex = f->readByte();
_spriteSlot._spritesIndex = f->readByte();
_spriteSlot._frameNumber = f->readUint16LE();
_spriteSlot._position.x = f->readSint16LE();
_spriteSlot._position.y = f->readSint16LE();
} else {
_frameNumber = f->readUint16LE();
_seqIndex = f->readByte();
_spriteSlot._spritesIndex = f->readByte();
_spriteSlot._frameNumber = f->readUint16LE();
_spriteSlot._position.x = f->readSint16LE();
_spriteSlot._position.y = f->readSint16LE();
_spriteSlot._depth = f->readSByte();
_spriteSlot._scale = (int8)f->readByte();
}
}
/*------------------------------------------------------------------------*/
@ -132,6 +141,22 @@ void AnimMiscEntry::load(Common::SeekableReadStream *f) {
/*------------------------------------------------------------------------*/
void AnimUIEntry::load(Common::SeekableReadStream *f) {
_probability = f->readUint16LE();
_imageCount = f->readUint16LE();
_firstImage = f->readUint16LE();
_lastImage = f->readUint16LE();
_counter = f->readSint16LE();
for (int i = 0; i < ANIM_SPAWN_COUNT; ++i)
_spawn[i] = f->readByte();
for (int i = 0; i < ANIM_SPAWN_COUNT; ++i)
_spawnFrame[i] = f->readUint16LE();
_sound = f->readUint16LE() & 0xFF;
_soundFrame = f->readUint16LE();
}
/*------------------------------------------------------------------------*/
Animation *Animation::init(MADSEngine *vm, Scene *scene) {
return new Animation(vm, scene);
}
@ -149,7 +174,7 @@ Animation::~Animation() {
if (_header._manualFlag)
scene._sprites.remove(_spriteListIndexes[_header._spritesIndex]);
for (uint idx = 0; idx < _header._spriteSetsCount; ++idx) {
for (int idx = 0; idx < _header._spriteSetsCount; ++idx) {
if (!_header._manualFlag || _header._spritesIndex != idx)
scene._sprites.remove(_spriteListIndexes[idx]);
}
@ -195,12 +220,12 @@ void Animation::load(UserInterface &interfaceSurface, MSurface &depthSurface,
delete stream;
if (_header._animMode == 4)
flags |= 0x4000;
flags |= PALFLAG_RESERVED;
if (flags & 0x100) {
if (flags & ANIMFLAG_LOAD_BACKGROUND) {
loadInterface(interfaceSurface, depthSurface, _header, flags, palAnimData, sceneInfo);
}
if (flags & 0x200) {
if (flags & ANIMFLAG_LOAD_BACKGROUND_ONLY) {
// No data
_header._messagesCount = 0;
_header._frameEntriesCount = 0;
@ -234,7 +259,7 @@ void Animation::load(UserInterface &interfaceSurface, MSurface &depthSurface,
for (int i = 0; i < _header._frameEntriesCount; i++) {
AnimFrameEntry rec;
rec.load(frameStream);
rec.load(frameStream, flags & ANIMFLAG_LOAD_BACKGROUND);
_frameEntries.push_back(rec);
}
@ -242,14 +267,23 @@ void Animation::load(UserInterface &interfaceSurface, MSurface &depthSurface,
}
_miscEntries.clear();
_uiEntries.clear();
if (_header._miscEntriesCount > 0) {
// Chunk 4: Misc Data
Common::SeekableReadStream *miscStream = madsPack.getItemStream(streamIndex++);
for (int i = 0; i < _header._miscEntriesCount; ++i) {
AnimMiscEntry rec;
rec.load(miscStream);
_miscEntries.push_back(rec);
if (flags & ANIMFLAG_LOAD_BACKGROUND) {
for (int i = 0; i < _header._miscEntriesCount; ++i) {
AnimUIEntry rec;
rec.load(miscStream);
_uiEntries.push_back(rec);
}
} else {
for (int i = 0; i < _header._miscEntriesCount; ++i) {
AnimMiscEntry rec;
rec.load(miscStream);
_miscEntries.push_back(rec);
}
}
delete miscStream;
@ -257,7 +291,7 @@ void Animation::load(UserInterface &interfaceSurface, MSurface &depthSurface,
// If the animation specifies a font, then load it for access
delete _font;
if (_header._flags & ANIM_CUSTOM_FONT) {
if (_header._flags & ANIMFLAG_CUSTOM_FONT) {
Common::String fontName = "*" + _header._fontResource;
_font = _vm->_font->getFont(fontName.c_str());
} else {

View File

@ -33,7 +33,12 @@
namespace MADS {
enum AnimFlag { ANIM_CUSTOM_FONT = 0x20 };
enum AnimFlag {
ANIMFLAG_DITHER = 0x0001, // Dither to 16 colors
ANIMFLAG_CUSTOM_FONT = 0x0020, // Load ccustom font
ANIMFLAG_LOAD_BACKGROUND = 0x0100, // Load background
ANIMFLAG_LOAD_BACKGROUND_ONLY = 0x0200 // Load background only
};
class MADSEngine;
class Scene;
@ -63,7 +68,7 @@ public:
/**
* Loads data for the record
*/
void load(Common::SeekableReadStream *f);
void load(Common::SeekableReadStream *f, bool uiFlag);
};
class AnimMiscEntry {
@ -80,6 +85,26 @@ public:
void load(Common::SeekableReadStream *f);
};
#define ANIM_SPAWN_COUNT 2
class AnimUIEntry {
public:
int _probability;
int _imageCount;
int _firstImage;
int _lastImage;
int _counter;
int _spawn[ANIM_SPAWN_COUNT];
int _spawnFrame[ANIM_SPAWN_COUNT];
int _sound;
int _soundFrame;
/**
* Loads the data for the record
*/
void load(Common::SeekableReadStream *f);
};
class AAHeader {
public:
int _spriteSetsCount;
@ -115,7 +140,6 @@ private:
Common::Array<int> _spriteListIndexes;
Common::Array<AnimMessage> _messages;
Common::Array<AnimFrameEntry> _frameEntries;
Common::Array<AnimMiscEntry> _miscEntries;
Common::Array<SpriteAsset *> _spriteSets;
Font *_font;
@ -153,6 +177,8 @@ private:
protected:
Animation(MADSEngine *vm, Scene *scene);
public:
Common::Array<AnimFrameEntry> _frameEntries;
Common::Array<AnimUIEntry> _uiEntries;
bool _resetFlag;
static Animation *init(MADSEngine *vm, Scene *scene);

View File

@ -52,7 +52,6 @@ Game::Game(MADSEngine *vm): _vm(vm), _surface(nullptr), _objects(vm),
_priorSectionNumber = 0;
_currentSectionNumber = -1;
_kernelMode = KERNEL_GAME_LOAD;
_v2 = 0;
_quoteEmergency = false;
_vocabEmergency = false;
_aaName = "*I0.AA";

View File

@ -131,7 +131,6 @@ public:
VisitedScenes _visitedScenes;
Scene _scene;
KernelMode _kernelMode;
int _v2;
int _trigger;
ScreenTransition _fx;
TriggerMode _triggerMode;

View File

@ -43,6 +43,7 @@ MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
_textWindowStill = false;
_screenFade = SCREEN_FADE_SMOOTH;
_musicFlag = false;
_dithering = false;
_debugger = nullptr;
_dialogs = nullptr;

View File

@ -104,6 +104,7 @@ public:
bool _textWindowStill;
ScreenFade _screenFade;
bool _musicFlag;
bool _dithering;
public:
MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc);
virtual ~MADSEngine();

View File

@ -32,6 +32,19 @@ class MADSEngine;
#define PALETTE_USAGE_COUNT 4
/**
* Palette mapping options
*/
enum {
PALFLAG_BACKGROUND = 0x8000, // Loading initial background
PALFLAG_RESERVED = 0x4000, // Enable mapping reserved colors
PALFLAG_ANY_TO_CLOSEST = 0x2000, // Any color can map to closest
PALFLAG_ALL_TO_CLOSEST = 0x1000, // Any colors that can map must map
PALFLAG_TOP_COLORS = 0x0800, // Allow mapping to high four colors
PALFLAG_DEFINE_RESERVED = 0x0400, // Define initial reserved color
PALFLAG_MASK = 0xfc00 // Mask for all the palette flags
};
struct RGB4 {
byte r;
byte g;

View File

@ -123,8 +123,12 @@ void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) {
_kernelMessages.clear();
// TODO: palletteUsage reset? setPalette(_nullPalette);
int flags = SCENEFLAG_LOAD_SHADOW;
if (_vm->_dithering)
flags |= SCENEFLAG_DITHER;
_sceneInfo = SceneInfo::init(_vm);
_sceneInfo->load(_currentSceneId, _variant, Common::String(), _vm->_game->_v2 ? 17 : 16,
_sceneInfo->load(_currentSceneId, _variant, Common::String(), flags,
_depthSurface, _backgroundSurface);
// Initialise palette animation for the scene
@ -143,10 +147,12 @@ void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) {
_vm->_palette->_paletteUsage.load(1, 0xF);
// Load interface
int flags = _vm->_game->_v2 ? 0x4101 : 0x4100;
if (!_vm->_textWindowStill)
flags |= 0x200;
flags = PALFLAG_RESERVED | ANIMFLAG_LOAD_BACKGROUND;
if (_vm->_dithering)
flags |= ANIMFLAG_DITHER;
if (_vm->_textWindowStill)
flags |= ANIMFLAG_LOAD_BACKGROUND_ONLY;
_animationData = Animation::init(_vm, this);
MSurface depthSurface;
_animationData->load(_userInterface, depthSurface, prefix, flags, nullptr, nullptr);
@ -513,7 +519,7 @@ void Scene::loadAnimation(const Common::String &resName, int abortTimers) {
_activeAnimation = Animation::init(_vm, this);
_activeAnimation->load(interfaceSurface, depthSurface, resName,
_vm->_game->_v2 ? 1 : 0, nullptr, nullptr);
_vm->_dithering ? ANIMFLAG_DITHER : 0, nullptr, nullptr);
_activeAnimation->startAnimation(abortTimers);
}
@ -585,8 +591,4 @@ void Scene::resetScene() {
_sequences.clear();
}
void Scene::backgroundAnimation() {
warning("TODO: Scene::backgroundAnimation");
}
} // End of namespace MADS

View File

@ -213,8 +213,6 @@ public:
void resetScene();
void backgroundAnimation();
/**
* Removes all the scene specific sprites fromt the sprites list,
* leaving any player sprites list in place at the start of the list.

View File

@ -52,6 +52,11 @@ class SpriteSlot;
#define TEXT_DISPLAY_MAX_SIZE 40
#define DIRTY_AREAS_SIZE (SPRITE_SLOTS_MAX_SIZE + TEXT_DISPLAY_MAX_SIZE)
enum {
SCENEFLAG_DITHER = 0x01, // Dither to 16 colors
SCENEFLAG_LOAD_SHADOW = 0x10 // Load hard shadows
};
class VerbInit {
public:
int _id;

View File

@ -354,10 +354,10 @@ void ScreenObjects::check(bool scanFlag) {
slot._flags = IMG_ERASE;
}
// Any background animation
scene.backgroundAnimation();
// Any background animation in the user interface
userInterface.doBackgroundAnimation();
// Handle animating the selected inventory animation
// Handle animating the selected inventory item
userInterface.inventoryAnim();
// Set the base time

View File

@ -48,7 +48,7 @@ void UISlots::add(const Common::Point &pt, int frameNumber, int spritesIndex) {
assert(size() < 50);
UISlot ie;
ie._flags = -3;
ie._flags = IMG_OVERPRINT;
ie._segmentId = IMG_TEXT_UPDATE;
ie._position = pt;
ie._frameNumber = frameNumber;
@ -57,6 +57,20 @@ void UISlots::add(const Common::Point &pt, int frameNumber, int spritesIndex) {
push_back(ie);
}
void UISlots::add(const AnimFrameEntry &frameEntry) {
assert(size() < 50);
UISlot ie;
ie._flags = IMG_UPDATE;
ie._segmentId = frameEntry._seqIndex;
ie._spritesIndex = frameEntry._spriteSlot._spritesIndex;
ie._frameNumber = frameEntry._frameNumber;
ie._position = frameEntry._spriteSlot._position;
push_back(ie);
}
void UISlots::draw(bool updateFlag, bool delFlag) {
Scene &scene = _vm->_game->_scene;
UserInterface &userInterface = scene._userInterface;
@ -633,6 +647,66 @@ void UserInterface::inventoryAnim() {
_uiSlots.push_back(slot);
}
void UserInterface::doBackgroundAnimation() {
Scene &scene = _vm->_game->_scene;
Common::Array<AnimUIEntry> &uiEntries = scene._animationData->_uiEntries;
Common::Array<AnimFrameEntry> &frameEntries = scene._animationData->_frameEntries;
_noSegmentsActive = !_someSegmentsActive;
_someSegmentsActive = false;
for (int idx = 0; idx < uiEntries.size(); ++idx) {
AnimUIEntry &uiEntry = uiEntries[idx];
if (uiEntry._counter < 0) {
if (uiEntry._counter == -1) {
int probabilityRandom = _vm->getRandomNumber(1, 30000);
int probability = uiEntry._probability;
if (uiEntry._probability > 30000) {
if (_noSegmentsActive) {
probability -= 30000;
} else {
probability = -1;
}
}
if (probabilityRandom <= probability) {
uiEntry._counter = uiEntry._firstImage;
_someSegmentsActive = true;
}
} else {
uiEntry._counter = uiEntry._firstImage;
_someSegmentsActive = true;
}
} else {
for (int idx2 = 0; idx2 < ANIM_SPAWN_COUNT; idx2++) {
if (uiEntry._spawnFrame[idx2] == (uiEntry._counter - uiEntry._firstImage)) {
int tempIndex = uiEntry._spawn[idx2];
if (idx >= tempIndex) {
uiEntries[tempIndex]._counter = uiEntries[tempIndex]._firstImage;
} else {
uiEntries[tempIndex]._counter = -2;
}
_someSegmentsActive = true;
}
}
++uiEntry._counter;
if (uiEntry._counter > uiEntry._lastImage) {
uiEntry._counter = -1;
} else {
_someSegmentsActive = true;
}
}
}
for (int idx = 0; idx < uiEntries.size(); ++idx) {
int imgScan = uiEntries[idx]._counter;
if (imgScan >= 0) {
_uiSlots.add(frameEntries[imgScan]);
}
}
}
void UserInterface::categoryChanged() {
_highlightedItemIndex = -1;
_vm->_events->initVars();

View File

@ -33,6 +33,8 @@ namespace MADS {
enum { IMG_SPINNING_OBJECT = 200, IMG_TEXT_UPDATE = 201 };
class AnimFrameEntry;
class UISlot {
public:
int _flags;
@ -61,6 +63,11 @@ public:
*/
void add(const Common::Point &pt, int frameNumber, int spritesIndex);
/**
* Loads the data from an aimation frame entry
*/
void add(const AnimFrameEntry &frameEntry);
/**
* Adds a special entry for full refresh of the user interface
*/
@ -83,6 +90,8 @@ private:
int _invFrameNumber;
uint32 _scrollMilli;
bool _scrollFlag;
int _noSegmentsActive;
int _someSegmentsActive;
/**
* Loads the elements of the user interface
@ -182,6 +191,11 @@ public:
*/
void noInventoryAnim();
/**
* Handles any animation that occurs in the background of the user interface
*/
void doBackgroundAnimation();
/**
* Handles queuing a new frame of an inventory animation for drawing
*/