aboutsummaryrefslogtreecommitdiff
path: root/engines/m4
diff options
context:
space:
mode:
Diffstat (limited to 'engines/m4')
-rw-r--r--engines/m4/font.h6
-rw-r--r--engines/m4/mads_logic.cpp5
-rw-r--r--engines/m4/mads_scene.cpp42
-rw-r--r--engines/m4/mads_scene.h21
-rw-r--r--engines/m4/mads_views.cpp215
-rw-r--r--engines/m4/mads_views.h71
6 files changed, 248 insertions, 112 deletions
diff --git a/engines/m4/font.h b/engines/m4/font.h
index d675cb6d47..e64f80b70d 100644
--- a/engines/m4/font.h
+++ b/engines/m4/font.h
@@ -61,6 +61,12 @@ class Font {
public:
Font(MadsM4Engine *vm);
~Font();
+
+ Font *getFont(const char *filename) {
+ // TODO: Proper separation of font instances
+ setFont(filename);
+ return this;
+ }
void setFont(const char *filename);
void setColor(uint8 color);
void setColors(uint8 alt1, uint8 alt2, uint8 foreground);
diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp
index 24d225a2a6..9d6c4e169b 100644
--- a/engines/m4/mads_logic.cpp
+++ b/engines/m4/mads_logic.cpp
@@ -164,7 +164,8 @@ void MadsSceneLogic::selectScene(int sceneNum) {
void MadsSceneLogic::setupScene() {
// FIXME: This is the hardcoded logic for Rex scene 101 only
- //const char *animName = formAnimName('A', -1);
+ const char *animName = formAnimName('A', -1);
+ warning("anim - %s", animName);
// sub_1e754(animName, 3);
@@ -187,7 +188,7 @@ void MadsSceneLogic::enterScene() {
_spriteIndexes[16] = startSpriteSequence(_spriteIndexes[1], 0, 4, 0, 1, 0);
_spriteIndexes[17] = startSpriteSequence(_spriteIndexes[2], 0, 4, 0, 1, 0);
- _madsVm->scene()->_sequenceList.unk2(0, 2, 7, 0x46);
+ _madsVm->scene()->_sequenceList.addSubEntry(0, SM_FRAME_INDEX, 7, 70);
_spriteIndexes[18] = startCycledSpriteSequence(_spriteIndexes[3], 0, 10, 0, 0, 60);
_spriteIndexes[19] = startSpriteSequence(_spriteIndexes[4], 0, 5, 0, 1, 0);
diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp
index 39279573de..efb495e823 100644
--- a/engines/m4/mads_scene.cpp
+++ b/engines/m4/mads_scene.cpp
@@ -57,6 +57,12 @@ MadsScene::~MadsScene() {
* Secondary scene loading code
*/
void MadsScene::loadScene2(const char *aaName) {
+ // TODO: Completely finish
+
+ _spriteSlots.clear();
+ _sequenceList.clear();
+ _kernelMessages.clear();
+
// Load up the properties for the scene
_sceneResources.load(_currentScene);
@@ -652,42 +658,6 @@ void MadsSceneResources::load(int sId) {
* Adds a new entry to the timed on-screen text display list
*/
/*
-int MadsScreenText::addTimed(const Common::Point &destPos, uint fontColours, uint flags, int vUnknown, uint32 timeout, const char *message) {
- // Find a free slot
- int idx = 0;
- while ((idx < TIMED_TEXT_SIZE) && ((_timedText[idx].flags & TEXTFLAG_ACTIVE) != 0))
- ++idx;
- if (idx == TIMED_TEXT_SIZE) {
- if (vUnknown == 0)
- return -1;
-
- error("Ran out of timed text display slots");
- }
-
- // Set up the entry values
- _timedText[idx].flags = flags | TEXTFLAG_ACTIVE;
- strcpy(_timedText[idx].message, message);
- _timedText[idx].colour1 = fontColours & 0xff;
- _timedText[idx].colour2 = fontColours >> 8;
- _timedText[idx].position.x = destPos.x;
- _timedText[idx].position.y = destPos.y;
- _timedText[idx].textDisplayIndex = -1;
- _timedText[idx].timeout = timeout;
- _timedText[idx].frameTimer = g_system->getMillis();
- _timedText[idx].field_1C = vUnknown;
- _timedText[idx].field_1D = 0; // word_84206
-
- // Copy the current action noun list
- for (int i = 0; i < 3; ++i)
- _timedText[idx].actionNouns[i] = _madsVm->scene()->actionNouns[i];
-
- if (flags & TEXTFLAG_2) {
- warning("word_844b8 and dword_845a0 not yet implemented");
- }
-
- return idx;
-}
-
void MadsScreenText::draw(M4Surface *surface) {
}
diff --git a/engines/m4/mads_scene.h b/engines/m4/mads_scene.h
index 43a90b621f..f7625bb761 100644
--- a/engines/m4/mads_scene.h
+++ b/engines/m4/mads_scene.h
@@ -66,27 +66,6 @@ public:
void load(int sceneId);
};
-#define TIMED_TEXT_SIZE 10
-#define TEXT_4A_SIZE 30
-
-enum TalkTextFlags {TEXTFLAG_2 = 2, TEXTFLAG_4 = 4, TEXTFLAG_8 = 8, TEXTFLAG_40 = 0x40,
- TEXTFLAG_ACTIVE = 0x80};
-
-struct TimedText {
- uint8 flags;
- int colour1;
- int colour2;
- Common::Point position;
- int textDisplayIndex;
- int timerIndex;
- uint32 timeout;
- uint32 frameTimer;
- bool field_1C;
- uint8 field_1D;
- uint16 actionNouns[3];
- char message[100];
-};
-
enum MadsActionMode {ACTMODE_NONE = 0, ACTMODE_VERB = 1, ACTMODE_OBJECT = 3, ACTMODE_TALK = 6};
enum MAdsActionMode2 {ACTMODE2_0 = 0, ACTMODE2_2 = 2, ACTMODE2_5 = 5};
diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp
index 57dd3523d4..a99976338b 100644
--- a/engines/m4/mads_views.cpp
+++ b/engines/m4/mads_views.cpp
@@ -240,6 +240,108 @@ void MadsTextDisplay::cleanUp() {
//--------------------------------------------------------------------------
+MadsKernelMessageList::MadsKernelMessageList(MadsView &owner): _owner(owner) {
+ for (int i = 0; i < TIMED_TEXT_SIZE; ++i) {
+ MadsKernelMessageListEntry rec;
+ _entries.push_back(rec);
+ }
+
+ _owner._textSpacing = -1;
+ _talkFont = _vm->_font->getFont(FONT_CONVERSATION_MADS);
+}
+
+void MadsKernelMessageList::clear() {
+ for (uint i = 0; i < _entries.size(); ++i)
+ _entries[i].flags = 0;
+
+ _owner._textSpacing = -1;
+ _talkFont = _vm->_font->getFont(FONT_CONVERSATION_MADS);
+}
+
+int MadsKernelMessageList::add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 v2, uint32 timeout, char *msg) {
+ // Find a free slot
+ uint idx = 0;
+ while ((idx < _entries.size()) && ((_entries[idx].flags & KMSG_ACTIVE) != 0))
+ ++idx;
+ if (idx == _entries.size()) {
+ if (v2 == 0)
+ return -1;
+
+ error("MadsKernelList overflow");
+ }
+
+ MadsKernelMessageListEntry &rec = _entries[idx];
+ rec.msg = msg;
+ rec.flags = flags | KMSG_ACTIVE;
+ rec.colour1 = fontColour & 0xff;
+ rec.colour2 = fontColour >> 8;
+ rec.position = pt;
+ rec.textDisplayIndex = -1;
+ rec.timeout = timeout;
+ rec.frameTimer = _madsVm->_currentTimer;
+ rec.field_1C = v2;
+ rec.abortMode = _owner._abortTimersMode2;
+
+ for (int i = 0; i < 3; ++i)
+ rec.actionNouns[i] = _madsVm->scene()->actionNouns[i];
+
+ if (flags & KMSG_2)
+ rec.frameTimer = _owner._ticksAmount + _owner._newTimeout;
+
+ return idx;
+}
+
+void MadsKernelMessageList::unk1(int msgIndex, int v1, int v2) {
+ if (msgIndex < 0)
+ return;
+
+ _entries[msgIndex].flags |= (v2 == 0) ? KMSG_8 : (KMSG_8 | KMSG_1);
+ _entries[msgIndex].msgOffset = 0;
+ _entries[msgIndex].field_E = v1;
+ _entries[msgIndex].frameTimer2 = _madsVm->_currentTimer;
+
+ const char *msgP = _entries[msgIndex].msg;
+ _entries[msgIndex].asciiChar = *msgP;
+ _entries[msgIndex].asciiChar2 = *(msgP + 1);
+
+ if (_entries[msgIndex].flags & KMSG_2)
+ _entries[msgIndex].frameTimer2 = _owner._ticksAmount + _owner._newTimeout;
+
+ _entries[msgIndex].frameTimer = _entries[msgIndex].frameTimer2;
+}
+
+void MadsKernelMessageList::setSeqIndex(int msgIndex, int seqIndex) {
+ if (msgIndex >= 0) {
+ _entries[msgIndex].flags |= KMSG_4;
+ _entries[msgIndex].sequenceIndex = seqIndex;
+ }
+}
+
+void MadsKernelMessageList::remove(int msgIndex) {
+ MadsKernelMessageListEntry &rec = _entries[msgIndex];
+
+ if (rec.flags & KMSG_ACTIVE) {
+ if (rec.flags & KMSG_8) {
+ *(rec.msg + rec.msgOffset) = rec.asciiChar;
+ *(rec.msg + rec.msgOffset + 1) = rec.asciiChar2;
+ }
+
+ if (rec.textDisplayIndex >= 0)
+ _owner._textDisplay.expire(rec.textDisplayIndex);
+
+ rec.flags &= ~KMSG_ACTIVE;
+ }
+}
+
+void MadsKernelMessageList::reset() {
+ for (uint i = 0; i < _entries.size(); ++i)
+ remove(i);
+
+ // sub_20454
+}
+
+//--------------------------------------------------------------------------
+
/**
* Clears the entries list
*/
@@ -375,14 +477,21 @@ MadsSequenceList::MadsSequenceList(MadsView &owner): _owner(owner) {
}
}
-bool MadsSequenceList::unk2(int index, int v1, int v2, int v3) {
- if (_entries[index].len27 >= TIMER_ENTRY_SUBSET_MAX)
+void MadsSequenceList::clear() {
+ for (uint i = 0; i < _entries.size(); ++i) {
+ _entries[i].active = 0;
+ _entries[i].dynamicHotspotIndex = -1;
+ }
+}
+
+bool MadsSequenceList::addSubEntry(int index, SequenceSubEntryMode mode, int frameIndex, int abortVal) {
+ if (_entries[index].entries.count >= TIMER_ENTRY_SUBSET_MAX)
return true;
- int subIndex = _entries[index].len27++;
- _entries[index].fld27[subIndex] = v1;
- _entries[index].fld2C[subIndex] = v2;
- _entries[index].fld36[subIndex] = v3;
+ int subIndex = _entries[index].entries.count++;
+ _entries[index].entries.mode[subIndex] = mode;
+ _entries[index].entries.frameIndex[subIndex] = frameIndex;
+ _entries[index].entries.abortVal[subIndex] = abortVal;
return false;
}
@@ -428,8 +537,8 @@ int MadsSequenceList::add(int spriteListIndex, int v0, int frameIndex, char fiel
_entries[timerIndex].field_25 = 0;
_entries[timerIndex].field_13 = 0;
_entries[timerIndex].dynamicHotspotIndex = -1;
- _entries[timerIndex].len27 = 0;
- _entries[timerIndex].field_3B = 0; //word_84206
+ _entries[timerIndex].entries.count = 0;
+ _entries[timerIndex].abortMode = _owner._abortTimersMode2;
for (int i = 0; i < 3; ++i)
_entries[timerIndex].actionNouns[i] = _madsVm->scene()->actionNouns[i];
@@ -469,37 +578,37 @@ void MadsSequenceList::setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot)
}
bool MadsSequenceList::loadSprites(int timerIndex) {
- MadsSequenceEntry &timerEntry = _entries[timerIndex];
+ MadsSequenceEntry &seqEntry = _entries[timerIndex];
int slotIndex;
bool result = false;
int idx = -1;
_owner._spriteSlots.deleteTimer(timerIndex);
- if (timerEntry.field_25 != 0) {
+ if (seqEntry.field_25 != 0) {
remove(timerIndex);
return false;
}
- if (timerEntry.spriteListIndex == -1) {
- timerEntry.field_25 = -1;
+ if (seqEntry.spriteListIndex == -1) {
+ seqEntry.field_25 = -1;
} else if ((slotIndex = _owner._spriteSlots.getIndex()) >= 0) {
MadsSpriteSlot &spriteSlot = _owner._spriteSlots[slotIndex];
setSpriteSlot(timerIndex, spriteSlot);
int x2 = 0, y2 = 0;
- if ((timerEntry.field_13 != 0) || (timerEntry.dynamicHotspotIndex >= 0)) {
- SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(timerEntry.spriteListIndex);
- M4Sprite *frame = spriteSet.getFrame(timerEntry.frameIndex - 1);
- int width = frame->width() * timerEntry.scale / 200;
- int height = frame->height() * timerEntry.scale / 100;
+ if ((seqEntry.field_13 != 0) || (seqEntry.dynamicHotspotIndex >= 0)) {
+ SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(seqEntry.spriteListIndex);
+ M4Sprite *frame = spriteSet.getFrame(seqEntry.frameIndex - 1);
+ int width = frame->width() * seqEntry.scale / 200;
+ int height = frame->height() * seqEntry.scale / 100;
warning("frame size %d x %d", width, height);
// TODO: Missing stuff here, and I'm not certain about the dynamic hotspot stuff below
- if (timerEntry.dynamicHotspotIndex >= 0) {
- DynamicHotspot &dynHotspot = _owner._dynamicHotspots[timerEntry.dynamicHotspotIndex];
+ if (seqEntry.dynamicHotspotIndex >= 0) {
+ DynamicHotspot &dynHotspot = _owner._dynamicHotspots[seqEntry.dynamicHotspotIndex];
dynHotspot.bounds.left = MAX(x2 - width, 0);
dynHotspot.bounds.right = MAX(x2 - width, 319) - dynHotspot.bounds.left + 1;
@@ -511,62 +620,70 @@ bool MadsSequenceList::loadSprites(int timerIndex) {
}
// Frame adjustments
- if (timerEntry.frameStart != timerEntry.numSprites)
- timerEntry.frameIndex += timerEntry.frameInc;
+ if (seqEntry.frameStart != seqEntry.numSprites)
+ seqEntry.frameIndex += seqEntry.frameInc;
- if (timerEntry.frameIndex >= timerEntry.frameStart) {
- if (timerEntry.frameIndex > timerEntry.numSprites) {
+ if (seqEntry.frameIndex >= seqEntry.frameStart) {
+ if (seqEntry.frameIndex > seqEntry.numSprites) {
result = true;
- if (timerEntry.animType != ANIMTYPE_CYCLED) {
+ if (seqEntry.animType != ANIMTYPE_CYCLED) {
// Keep index from exceeding maximum allowed
- timerEntry.frameIndex = timerEntry.frameStart;
+ seqEntry.frameIndex = seqEntry.frameStart;
} else {
// Switch into reverse
- timerEntry.frameIndex = timerEntry.numSprites - 1;
- timerEntry.frameInc = -1;
+ seqEntry.frameIndex = seqEntry.numSprites - 1;
+ seqEntry.frameInc = -1;
}
}
} else {
// Currently in reverse mode
result = true;
- if (timerEntry.animType == ANIMTYPE_CYCLED)
+ if (seqEntry.animType == ANIMTYPE_CYCLED)
{
// Switch back to forward direction again
- timerEntry.frameIndex = timerEntry.frameStart + 1;
- timerEntry.frameInc = 1;
+ seqEntry.frameIndex = seqEntry.frameStart + 1;
+ seqEntry.frameInc = 1;
} else {
// Otherwise reset back to last sprite for further reverse animating
- timerEntry.frameIndex = timerEntry.numSprites;
+ seqEntry.frameIndex = seqEntry.numSprites;
}
}
- if (result && (timerEntry.field_24 != 0)) {
- if (--timerEntry.field_24 != 0)
- timerEntry.field_25 = -1;
+ if (result && (seqEntry.field_24 != 0)) {
+ if (--seqEntry.field_24 != 0)
+ seqEntry.field_25 = -1;
}
} else {
// Out of sprite slots
- timerEntry.field_25 = -1;
+ seqEntry.field_25 = -1;
}
- if (timerEntry.len27 > 0) {
- for (int i = 0; i <= timerEntry.len27; ++i) {
- if ((!timerEntry.fld27[i] && (timerEntry.field_25 != 0)) ||
- ((timerEntry.fld27[i] == 1) && result)) {
+ if (seqEntry.entries.count > 0) {
+ for (int i = 0; i <= seqEntry.entries.count; ++i) {
+ switch (seqEntry.entries.mode[i]) {
+ case SM_0:
+ case SM_1:
+ if (((seqEntry.entries.mode[i] == SM_0) && (seqEntry.field_25 != 0)) ||
+ ((seqEntry.entries.mode[i] == SM_1) && result))
idx = i;
- } else if (timerEntry.fld27[i] > 1) {
- int v = timerEntry.fld2C[i];
- if ((v == timerEntry.frameIndex) || (v == 0))
+ break;
+
+ case SM_FRAME_INDEX: {
+ int v = seqEntry.entries.frameIndex[i];
+ if ((v == seqEntry.frameIndex) || (v == 0))
idx = i;
}
+
+ default:
+ break;
+ }
}
}
if (idx >= 0) {
- //_owner._abortTimers = timerEntry.fld36[idx];
-
- // TODO: Figure out word_84208, timerEntry.field_3B[]
+ _owner._abortTimers = seqEntry.entries.abortVal[idx];
+ _owner._abortTimersMode = seqEntry.abortMode;
}
return result;
@@ -606,9 +723,15 @@ void MadsSequenceList::delay(uint32 v1, uint32 v2) {
//--------------------------------------------------------------------------
-MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this) {
+MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this),
+ _kernelMessages(*this) {
+ _textSpacing = -1;
+ _ticksAmount = 3;
+ _newTimeout = 0;
_abortTimers = 0;
_abortTimers2 = 0;
+ _abortTimersMode = ABORTMODE_0;
+ _abortTimersMode2 = ABORTMODE_0;
}
void MadsView::refresh() {
diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h
index 50ce9e1aab..37c797b931 100644
--- a/engines/m4/mads_views.h
+++ b/engines/m4/mads_views.h
@@ -40,6 +40,8 @@ namespace M4 {
class MadsView;
+enum AbortTimerMode {ABORTMODE_0 = 0, ABORTMODE_1 = 1, ABORTMODE_2 = 2};
+
class MadsSpriteSlot {
public:
int spriteId;
@@ -126,6 +128,48 @@ public:
void cleanUp();
};
+#define TIMED_TEXT_SIZE 10
+#define TEXT_4A_SIZE 30
+
+enum KernelMessageFlags {KMSG_1 = 1, KMSG_2 = 2, KMSG_4 = 4, KMSG_8 = 8, KMSG_40 = 0x40, KMSG_ACTIVE = 0x80};
+
+class MadsKernelMessageListEntry {
+public:
+ uint8 flags;
+ int sequenceIndex;
+ char asciiChar;
+ char asciiChar2;
+ int colour1;
+ int colour2;
+ Common::Point position;
+ int textDisplayIndex;
+ int msgOffset;
+ int field_E;
+ uint32 frameTimer2;
+ uint32 frameTimer;
+ uint32 timeout;
+ bool field_1C;
+ AbortTimerMode abortMode;
+ uint16 actionNouns[3];
+ char *msg;
+};
+
+class MadsKernelMessageList {
+private:
+ MadsView &_owner;
+ Common::Array<MadsKernelMessageListEntry> _entries;
+ Font *_talkFont;
+public:
+ MadsKernelMessageList(MadsView &owner);
+
+ void clear();
+ int add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 v2, uint32 timeout, char *msg);
+ void unk1(int msgIndex, int v1, int v2);
+ void setSeqIndex(int msgIndex, int seqIndex);
+ void remove(int msgIndex);
+ void reset();
+};
+
class ScreenObjectEntry {
public:
Common::Rect bounds;
@@ -191,9 +235,18 @@ public:
void reset();
};
+enum SpriteAnimType {ANIMTYPE_SINGLE_DIRECTION = 1, ANIMTYPE_CYCLED = 2};
+
+enum SequenceSubEntryMode {SM_0 = 0, SM_1 = 1, SM_FRAME_INDEX = 2};
+
#define TIMER_ENTRY_SUBSET_MAX 5
-enum SpriteAnimType {ANIMTYPE_SINGLE_DIRECTION = 1, ANIMTYPE_CYCLED = 2};
+struct MadsSequenceSubEntries {
+ int count;
+ SequenceSubEntryMode mode[TIMER_ENTRY_SUBSET_MAX];
+ int16 frameIndex[TIMER_ENTRY_SUBSET_MAX];
+ int8 abortVal[TIMER_ENTRY_SUBSET_MAX];
+};
struct MadsSequenceEntry {
int8 active;
@@ -220,11 +273,8 @@ struct MadsSequenceEntry {
int field_24;
int field_25;
- int len27;
- int8 fld27[TIMER_ENTRY_SUBSET_MAX];
- int16 fld2C[TIMER_ENTRY_SUBSET_MAX];
- int8 fld36[TIMER_ENTRY_SUBSET_MAX];
- int field_3B;
+ MadsSequenceSubEntries entries;
+ AbortTimerMode abortMode;
uint16 actionNouns[3];
int numTicks;
@@ -242,7 +292,8 @@ public:
MadsSequenceList(MadsView &owner);
MadsSequenceEntry &operator[](int index) { return _entries[index]; }
- bool unk2(int index, int v1, int v2, int v3);
+ void clear();
+ bool addSubEntry(int index, SequenceSubEntryMode mode, int frameIndex, int abortVal);
int add(int spriteListIndex, int v0, int v1, char field_24, int timeoutTicks, int extraTicks, int numTicks,
int height, int width, char field_12, char scale, char depth, int frameInc, SpriteAnimType animType,
int numSprites, int frameStart);
@@ -259,12 +310,18 @@ private:
public:
MadsSpriteSlots _spriteSlots;
MadsTextDisplay _textDisplay;
+ MadsKernelMessageList _kernelMessages;
ScreenObjects _screenObjects;
MadsDynamicHotspots _dynamicHotspots;
MadsSequenceList _sequenceList;
+ int _textSpacing;
+ int _ticksAmount;
+ uint32 _newTimeout;
int _abortTimers;
int8 _abortTimers2;
+ AbortTimerMode _abortTimersMode;
+ AbortTimerMode _abortTimersMode2;
public:
MadsView(View *view);