[Scummvm-git-logs] scummvm master -> 10a54c2696126a81ee2b2f7f10b1a8be90ed7711
sev-
noreply at scummvm.org
Mon Aug 24 23:05:06 UTC 2026
This automated email contains information about 17 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
38bc73531c AVALANCHE: Restore screen resolution in Outro::run to fix crash on exit
34520412fd AVALANCHE: Support returning to launcher on game exit
2dd01922b8 AVALANCHE: Fix toolbar not rendering in game
91ef88814c AVALANCHE: Handle Alt keyboard shortcuts for Boss key, quit, and easter egg
285e72a0d4 AVALANCHE: Add bounds checking for character IDs to prevent out-of-bounds array access
c020475724 AVALANCHE: Fix Spludwick presence in laboratory and dynamic room calculation
ae737c7161 AVALANCHE: Fix password character matching out-of-bounds crash in parser
f179e1dade AVALANCHE: Implement Golden Slumbers cutscene when giving lute to Geida
7f8982f98c AVALANCHE: Add playMod and stopMod methods to SoundHandler for MOD audio playback
2c6a22a7e5 AVALANCHE: Create TitleScreen class
4e457efa90 AVALANCHE: Implement EGA title screen with scrolling credits banner
4ef76e75e0 AVALANCHE: Refactor intro music playback to use SoundHandler methods
1c7d1154aa AVALANCHE: Use local variable in TitleScreen font loading to prevent in-game font corruption
969ccbd937 AVALANCHE: Implement MainMenu Option 3 teaser preview
5cd66a540e AVALANCHE: Implement MainMenu Option 5 documentation reader for avalot.doc
5390f634f0 AVALANCHE: Implement MainMenu Option 4: documentation index and section jumping
10a54c2696 AVALANCHE: Remove stray arrow character from documentation viewer status text
Commit: 38bc73531cf703e5014150ec85c68ab34225da7a
https://github.com/scummvm/scummvm/commit/38bc73531cf703e5014150ec85c68ab34225da7a
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Restore screen resolution in Outro::run to fix crash on exit
Changed paths:
engines/avalanche/outro.cpp
diff --git a/engines/avalanche/outro.cpp b/engines/avalanche/outro.cpp
index 14634f65fb1..905ba7e6aef 100644
--- a/engines/avalanche/outro.cpp
+++ b/engines/avalanche/outro.cpp
@@ -38,6 +38,7 @@ namespace Avalanche {
}
void Outro::run() {
+ _vm->_graphics->menuRestoreScreen();
CursorMan.showMouse(false);
_vm->_graphics->blackOutScreen();
_vm->_graphics->drawQuittingPic();
Commit: 34520412fdf40f7b1eadc498d5d986d43773c670
https://github.com/scummvm/scummvm/commit/34520412fdf40f7b1eadc498d5d986d43773c670
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Support returning to launcher on game exit
Changed paths:
engines/avalanche/avalanche.cpp
diff --git a/engines/avalanche/avalanche.cpp b/engines/avalanche/avalanche.cpp
index eaf022f5df2..bc835fd2e71 100644
--- a/engines/avalanche/avalanche.cpp
+++ b/engines/avalanche/avalanche.cpp
@@ -181,7 +181,7 @@ Common::ErrorCode AvalancheEngine::initialize() {
}
bool AvalancheEngine::hasFeature(EngineFeature f) const {
- return (f == kSupportsSavingDuringRuntime) || (f == kSupportsLoadingDuringRuntime);
+ return (f == kSupportsSavingDuringRuntime) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsReturnToLauncher);
}
const char *AvalancheEngine::getCopyrightString() const {
Commit: 2dd01922b8be5234605255b8c455e2e6d2a3626b
https://github.com/scummvm/scummvm/commit/2dd01922b8be5234605255b8c455e2e6d2a3626b
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Fix toolbar not rendering in game
Changed paths:
engines/avalanche/avalanche.cpp
engines/avalanche/avalot.cpp
diff --git a/engines/avalanche/avalanche.cpp b/engines/avalanche/avalanche.cpp
index bc835fd2e71..2028fc3d824 100644
--- a/engines/avalanche/avalanche.cpp
+++ b/engines/avalanche/avalanche.cpp
@@ -440,7 +440,7 @@ bool AvalancheEngine::loadGame(const int16 slot) {
_alive = true;
refreshObjectList();
_animation->updateSpeed();
- drawDirection();
+ drawToolbar();
_animation->animLink();
_background->update();
diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp
index d5977df067f..6dc4dd94d1d 100644
--- a/engines/avalanche/avalot.cpp
+++ b/engines/avalanche/avalot.cpp
@@ -1466,6 +1466,7 @@ void AvalancheEngine::newGame() {
enterRoom(kRoomYours, 1);
avvy->_visible = false;
drawScore();
+ drawToolbar();
_dropdown->setup();
_clock->update();
spriteRun();
Commit: 91ef88814c8e72e67c7080984f9166462515b8d4
https://github.com/scummvm/scummvm/commit/91ef88814c8e72e67c7080984f9166462515b8d4
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Handle Alt keyboard shortcuts for Boss key, quit, and easter egg
Changed paths:
engines/avalanche/avalot.cpp
diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp
index 6dc4dd94d1d..4d0f6f33ad5 100644
--- a/engines/avalanche/avalot.cpp
+++ b/engines/avalanche/avalot.cpp
@@ -117,6 +117,22 @@ Room AvalancheEngine::_whereIs[29] = {
void AvalancheEngine::handleKeyDown(Common::Event &event) {
_sound->click();
+ if (event.kbd.flags & Common::KBD_ALT) {
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_b:
+ callVerb(kVerbCodeBoss);
+ return;
+ case Common::KEYCODE_x:
+ callVerb(kVerbCodeQuit);
+ return;
+ case Common::KEYCODE_d:
+ _dialogs->displayText("Wrong game!");
+ return;
+ default:
+ break;
+ }
+ }
+
if ((Common::KEYCODE_F1 <= event.kbd.keycode) && (event.kbd.keycode <= Common::KEYCODE_F15))
_parser->handleFunctionKey(event);
else if ((32 <= event.kbd.ascii) && (event.kbd.ascii <= 128) && (event.kbd.ascii != 47))
Commit: 285e72a0d465dc340d8527c7ad552714d4b451d8
https://github.com/scummvm/scummvm/commit/285e72a0d465dc340d8527c7ad552714d4b451d8
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Add bounds checking for character IDs to prevent out-of-bounds array access
Changed paths:
engines/avalanche/avalot.cpp
diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp
index 4d0f6f33ad5..6f47476e2c0 100644
--- a/engines/avalanche/avalot.cpp
+++ b/engines/avalanche/avalot.cpp
@@ -1698,10 +1698,14 @@ void AvalancheEngine::openDoor(Room whither, byte ped, byte magicnum) {
}
void AvalancheEngine::setRoom(People persId, Room roomId) {
+ if (persId < kPeopleAvalot || persId > kPeopleWisewoman)
+ return;
_whereIs[persId - kPeopleAvalot] = roomId;
}
Room AvalancheEngine::getRoom(People persId) {
+ if (persId < kPeopleAvalot || persId > kPeopleWisewoman)
+ return kRoomNowhere;
return _whereIs[persId - kPeopleAvalot];
}
} // End of namespace Avalanche
Commit: c0204757248342f39c5616113a6de5548e1343ea
https://github.com/scummvm/scummvm/commit/c0204757248342f39c5616113a6de5548e1343ea
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Fix Spludwick presence in laboratory and dynamic room calculation
Initialized _spludwickAtHome to true in resetVariables() to match original game source, so that by default Spludwick is at the laboratory
Changed paths:
engines/avalanche/avalot.cpp
diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp
index 6f47476e2c0..21bc7ced4af 100644
--- a/engines/avalanche/avalot.cpp
+++ b/engines/avalanche/avalot.cpp
@@ -626,6 +626,11 @@ void AvalancheEngine::enterRoom(Room roomId, byte ped) {
break;
case kRoomSpludwicks:
+ if (!_talkedToCrapulus || _lustieIsAsleep)
+ _spludwickAtHome = true;
+ else
+ _spludwickAtHome = !((_roomCount[kRoomWiseWomans] % 3) == 1);
+
if (_spludwickAtHome) {
AnimationType *spr1 = _animation->_sprites[1];
if (ped > 0) {
@@ -1399,7 +1404,7 @@ void AvalancheEngine::resetVariables() {
_totalTime = 0;
_jumpStatus = 0;
_mushroomGrowing = false;
- _spludwickAtHome = false;
+ _spludwickAtHome = true;
_lastRoom = kRoomDummy;
_lastRoomNotMap = kRoomDummy;
_crapulusWillTell = false;
Commit: ae737c7161378b517577b46ddcd76e4b8b29d9d8
https://github.com/scummvm/scummvm/commit/ae737c7161378b517577b46ddcd76e4b8b29d9d8
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Fix password character matching out-of-bounds crash in parser
Changed paths:
engines/avalanche/parser.cpp
diff --git a/engines/avalanche/parser.cpp b/engines/avalanche/parser.cpp
index ba89fb46e47..2ac014fb6c5 100644
--- a/engines/avalanche/parser.cpp
+++ b/engines/avalanche/parser.cpp
@@ -2304,7 +2304,7 @@ void Parser::doThat() {
temp.toUppercase();
int pwdId = _vm->_passwordNum + kFirstPassword;
for (uint j = 0; j < _vocabulary[pwdId]._word.size(); j++) {
- if (_vocabulary[pwdId]._word[j] != temp[j])
+ if (_vocabulary[pwdId]._word[j] != ((j < temp.size()) ? temp[j] : '\0'))
ok = false;
}
}
Commit: f179e1dadeaba87706fd66d7f6e2ee9eac4dc11b
https://github.com/scummvm/scummvm/commit/f179e1dadeaba87706fd66d7f6e2ee9eac4dc11b
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Implement Golden Slumbers cutscene when giving lute to Geida
Changed paths:
engines/avalanche/avalot.cpp
engines/avalanche/parser.cpp
diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp
index 21bc7ced4af..108ad71ff21 100644
--- a/engines/avalanche/avalot.cpp
+++ b/engines/avalanche/avalot.cpp
@@ -1316,6 +1316,7 @@ void AvalancheEngine::minorRedraw() {
for (int i = 0; i < 3; i++)
_scoreToDisplay[i] = -1; // impossible digits
drawScore();
+ drawToolbar();
fadeIn();
}
diff --git a/engines/avalanche/parser.cpp b/engines/avalanche/parser.cpp
index 2ac014fb6c5..9b692d3d13b 100644
--- a/engines/avalanche/parser.cpp
+++ b/engines/avalanche/parser.cpp
@@ -1676,8 +1676,54 @@ void Parser::giveGeidaTheLute() {
// She plays it.
_vm->_dialogs->displayScrollChain('Q', 64);
+ // Golden Slumbers cutscene
+ _vm->_graphics->saveScreen();
+
+ for (int gd = 0; gd <= 320; gd += 32) {
+ _vm->_graphics->drawFilledRectangle(Common::Rect(320 - gd, 100 - gd / 2, 320 + gd, 100 + gd / 2), kColorLightblue);
+ _vm->_graphics->refreshScreen();
+ g_system->delayMillis(15);
+ }
+ _vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 640, 200), kColorLightblue);
+ _vm->_graphics->refreshScreen();
+
+ static const char *const lullabyLines[] = {
+ "Golden slumbers kiss your eyes",
+ "Smiles awake you when you rise",
+ "Sleep, pretty Baron, do not cry",
+ "And I will sing a lullaby.",
+ "",
+ "Care you know not, therefore sleep",
+ "While I o'er you watch do keep;",
+ "Sleep now, du Lustie, do not cry",
+ "And I will leave the castle. Bye!"
+ };
+
+ int curY = 20;
+ for (int i = 0; i < 9; i++) {
+ if (lullabyLines[i][0] != '\0') {
+ _vm->_graphics->drawNormalText(lullabyLines[i], _vm->_font, 8, 80, curY, kColorWhite);
+ _vm->_graphics->refreshScreen();
+ g_system->delayMillis(1200);
+ } else {
+ g_system->delayMillis(600);
+ }
+ curY += 15;
+ }
+
+ g_system->delayMillis(1500);
+
+ for (int gd = 320; gd >= 0; gd -= 32) {
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->drawFilledRectangle(Common::Rect(320 - gd, 100 - gd / 2, 320 + gd, 100 + gd / 2), kColorLightblue);
+ _vm->_graphics->refreshScreen();
+ g_system->delayMillis(15);
+ }
+
+ _vm->minorRedraw();
+ _vm->_graphics->refreshScreen();
+
_vm->_timer->addTimer(1, Timer::kProcGiveLuteToGeida, Timer::kReasonGeidaSings);
- //_vm->_enid->backToBootstrap(4); TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then!
}
void Parser::playHarp() {
Commit: 7f8982f98c70599653f9b5d35a0d15f31ca22129
https://github.com/scummvm/scummvm/commit/7f8982f98c70599653f9b5d35a0d15f31ca22129
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Add playMod and stopMod methods to SoundHandler for MOD audio playback
Changed paths:
engines/avalanche/sound.cpp
engines/avalanche/sound.h
diff --git a/engines/avalanche/sound.cpp b/engines/avalanche/sound.cpp
index 13edf49b030..59dbbbdf10f 100644
--- a/engines/avalanche/sound.cpp
+++ b/engines/avalanche/sound.cpp
@@ -23,6 +23,7 @@
#include "avalanche/sound.h"
#include "audio/softsynth/pcspk.h"
+#include "audio/mods/protracker.h"
#include "common/config-manager.h"
namespace Avalanche {
@@ -84,4 +85,26 @@ void SoundHandler::blip() {
playNote(177, 77);
}
+void SoundHandler::playMod(const Common::Path &filename) {
+ if (!_soundFl)
+ return;
+
+ Common::File *file = new Common::File();
+ if (!file->open(filename)) {
+ warning("AVALANCHE: SoundHandler: Music file not found: %s", filename.toString(Common::Path::kNativeSeparator).c_str());
+ delete file;
+ return;
+ }
+
+ Audio::AudioStream *stream = Audio::makeProtrackerStream(file);
+ if (stream)
+ _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, nullptr, stream);
+ else
+ delete file;
+}
+
+void SoundHandler::stopMod() {
+ _vm->_mixer->stopAll();
+}
+
} // End of namespace Avalanche
diff --git a/engines/avalanche/sound.h b/engines/avalanche/sound.h
index 848beff8b6a..1bea77cc643 100644
--- a/engines/avalanche/sound.h
+++ b/engines/avalanche/sound.h
@@ -43,6 +43,8 @@ public:
void blip();
void syncVolume();
void stopSound();
+ void playMod(const Common::Path &filename);
+ void stopMod();
private:
AvalancheEngine *_vm;
Commit: 2c6a22a7e5934610e279dd16e400ab54476a6059
https://github.com/scummvm/scummvm/commit/2c6a22a7e5934610e279dd16e400ab54476a6059
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Create TitleScreen class
Changed paths:
A engines/avalanche/titlescreen.cpp
A engines/avalanche/titlescreen.h
engines/avalanche/avalanche.cpp
engines/avalanche/avalanche.h
engines/avalanche/module.mk
diff --git a/engines/avalanche/avalanche.cpp b/engines/avalanche/avalanche.cpp
index 2028fc3d824..1f3009fa3fd 100644
--- a/engines/avalanche/avalanche.cpp
+++ b/engines/avalanche/avalanche.cpp
@@ -33,6 +33,7 @@
#include "avalanche/avalanche.h"
#include "avalanche/intro.h"
+#include "avalanche/titlescreen.h"
namespace Avalanche {
@@ -59,6 +60,7 @@ AvalancheEngine::AvalancheEngine(OSystem *syst, const AvalancheGameDescription *
_highscore = nullptr;
_intro = nullptr;
_outro = nullptr;
+ _titleScreen = nullptr;
initVariables();
}
@@ -84,6 +86,7 @@ AvalancheEngine::~AvalancheEngine() {
delete _highscore;
delete _intro;
delete _outro;
+ delete _titleScreen;
for (int i = 0; i < 31; i++) {
for (int j = 0; j < 2; j++) {
@@ -171,6 +174,7 @@ Common::ErrorCode AvalancheEngine::initialize() {
_highscore = new HighScore(this);
_intro = new Intro(this);
_outro = new Outro(this);
+ _titleScreen = new TitleScreen(this);
_graphics->init();
_dialogs->init();
diff --git a/engines/avalanche/avalanche.h b/engines/avalanche/avalanche.h
index bd07eeaef11..937365f09ab 100644
--- a/engines/avalanche/avalanche.h
+++ b/engines/avalanche/avalanche.h
@@ -61,6 +61,7 @@ class RandomSource;
namespace Avalanche {
struct AvalancheGameDescription;
+class TitleScreen;
class Intro;
class Outro;
@@ -95,6 +96,7 @@ public:
HighScore *_highscore;
Intro *_intro;
Outro *_outro;
+ TitleScreen *_titleScreen;
AvalancheEngine(OSystem *syst, const AvalancheGameDescription *gd);
~AvalancheEngine() override;
diff --git a/engines/avalanche/module.mk b/engines/avalanche/module.mk
index 3a1c8259bcc..cdd98b2003d 100644
--- a/engines/avalanche/module.mk
+++ b/engines/avalanche/module.mk
@@ -24,6 +24,7 @@ MODULE_OBJS = \
shootemup.o \
sound.o \
timer.o \
+ titlescreen.o \
# This module can be built as a plugin
ifeq ($(ENABLE_AVALANCHE), DYNAMIC_PLUGIN)
diff --git a/engines/avalanche/titlescreen.cpp b/engines/avalanche/titlescreen.cpp
new file mode 100644
index 00000000000..11c60b99a4d
--- /dev/null
+++ b/engines/avalanche/titlescreen.cpp
@@ -0,0 +1,37 @@
+/* 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/>.
+ *
+ */
+
+#include "avalanche/avalanche.h"
+#include "avalanche/titlescreen.h"
+
+namespace Avalanche {
+
+TitleScreen::TitleScreen(AvalancheEngine *vm) : _vm(vm) {
+}
+
+TitleScreen::~TitleScreen() {
+}
+
+void TitleScreen::run() {
+ (void)_vm;
+}
+
+} // End of namespace Avalanche
diff --git a/engines/avalanche/titlescreen.h b/engines/avalanche/titlescreen.h
new file mode 100644
index 00000000000..4231e9cd848
--- /dev/null
+++ b/engines/avalanche/titlescreen.h
@@ -0,0 +1,41 @@
+/* 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 AVALANCHE_TITLESCREEN_H
+#define AVALANCHE_TITLESCREEN_H
+
+namespace Avalanche {
+
+class AvalancheEngine;
+
+class TitleScreen {
+public:
+ TitleScreen(AvalancheEngine *vm);
+ ~TitleScreen();
+ void run();
+
+private:
+ AvalancheEngine *_vm;
+};
+
+} // End of namespace Avalanche
+
+#endif // AVALANCHE_TITLESCREEN_H
Commit: 4e457efa90555d60b3244b0e4be78462d01784cc
https://github.com/scummvm/scummvm/commit/4e457efa90555d60b3244b0e4be78462d01784cc
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Implement EGA title screen with scrolling credits banner
1) Fix drawArc to draw on passed surface instead of Graphics::Surface _scrolls.
2) drawArc was using 361 degrees instead of 360, which caused 361° to wrap down to 0° and swap start and end angles into full closed circles instead of 1° arc.
Changed paths:
engines/avalanche/graphics.cpp
engines/avalanche/graphics.h
engines/avalanche/mainmenu.cpp
engines/avalanche/titlescreen.cpp
engines/avalanche/titlescreen.h
diff --git a/engines/avalanche/graphics.cpp b/engines/avalanche/graphics.cpp
index a485e73f95a..5b2fc73fd62 100644
--- a/engines/avalanche/graphics.cpp
+++ b/engines/avalanche/graphics.cpp
@@ -217,16 +217,11 @@ Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16
return endPoint;
}
- // Check if valid angles.
- stAngle = stAngle % 361;
- endAngle = endAngle % 361;
-
- // If impossible angles, then swap them!
- if (endAngle < stAngle) {
- uint16 tmpAngle=endAngle;
- endAngle=stAngle;
- stAngle=tmpAngle;
- }
+ // Normalize angles modulo 360
+ stAngle = stAngle % 360;
+ endAngle = endAngle % 360;
+ if (endAngle == 0 && stAngle > 0)
+ endAngle = 360;
// Approximate the number of pixels required by using the circumference equation of an ellipse.
uint16 numOfPixels = (uint16)floor(sqrt(3.0) * sqrt(pow(double(xRadius), 2) + pow(double(yRadius), 2)) + 0.5);
@@ -264,17 +259,25 @@ Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16
int16 yp = y + yTemp;
int16 ym = y - yTemp;
- if ((j >= stAngle) && (j <= endAngle))
- *(byte *)_scrolls.getBasePtr(xp, yp) = color;
+ if ((j >= stAngle) && (j <= endAngle)) {
+ if ((xp >= 0) && (xp < surface.w) && (yp >= 0) && (yp < surface.h))
+ *(byte *)surface.getBasePtr(xp, yp) = color;
+ }
- if (((180 - j) >= stAngle) && ((180 - j) <= endAngle))
- *(byte *)_scrolls.getBasePtr(xm, yp) = color;
+ if (((180 - j) >= stAngle) && ((180 - j) <= endAngle)) {
+ if ((xm >= 0) && (xm < surface.w) && (yp >= 0) && (yp < surface.h))
+ *(byte *)surface.getBasePtr(xm, yp) = color;
+ }
- if (((j + 180) >= stAngle) && ((j + 180) <= endAngle))
- *(byte *)_scrolls.getBasePtr(xm, ym) = color;
+ if (((j + 180) >= stAngle) && ((j + 180) <= endAngle)) {
+ if ((xm >= 0) && (xm < surface.w) && (ym >= 0) && (ym < surface.h))
+ *(byte *)surface.getBasePtr(xm, ym) = color;
+ }
- if (((360 - j) >= stAngle) && ((360 - j) <= endAngle))
- *(byte *)_scrolls.getBasePtr(xp, ym) = color;
+ if (((360 - j) >= stAngle) && ((360 - j) <= endAngle)) {
+ if ((xp >= 0) && (xp < surface.w) && (ym >= 0) && (ym < surface.h))
+ *(byte *)surface.getBasePtr(xp, ym) = color;
+ }
j += delta;
} while (j <= deltaEnd);
@@ -283,7 +286,8 @@ Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16
}
void GraphicManager::drawDot(int x, int y, Color color) {
- *(byte *)_surface.getBasePtr(x, y) = color;
+ if ((x >= 0) && (x < _surface.w) && (y >= 0) && (y < _surface.h))
+ *(byte *)_surface.getBasePtr(x, y) = color;
}
void GraphicManager::drawLine(int x1, int y1, int x2, int y2, int penX, int penY, Color color) {
@@ -342,8 +346,12 @@ void GraphicManager::drawText(Graphics::Surface &surface, const Common::String &
byte pixel = font[(byte)text[i]][j];
for (int bit = 0; bit < 8; bit++) {
byte pixelBit = (pixel >> bit) & 1;
- if (pixelBit)
- *(byte *)surface.getBasePtr(x + i * 8 + 7 - bit, y + j) = color;
+ if (pixelBit) {
+ int px = x + i * 8 + 7 - bit;
+ int py = y + j;
+ if (px >= 0 && px < surface.w && py >= 0 && py < surface.h)
+ *(byte *)surface.getBasePtr(px, py) = color;
+ }
}
}
}
diff --git a/engines/avalanche/graphics.h b/engines/avalanche/graphics.h
index e7c68c81976..05d57e5f863 100644
--- a/engines/avalanche/graphics.h
+++ b/engines/avalanche/graphics.h
@@ -166,7 +166,15 @@ public:
void restoreScreen();
void removeBackup();
+ Graphics::Surface loadPictureGraphic(Common::File &file); // Reads Graphic-planar EGA data.
+ void drawPicture(Graphics::Surface &target, const Graphics::Surface &picture, uint16 destX, uint16 destY);
+ // Taken from Free Pascal's Procedure InternalEllipseDefault. Used to replace Pascal's procedure arc.
+ // Returns the end point of the arc. (Needed in Clock.)
+ Common::Point drawArc(Graphics::Surface &surface, int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color);
+ void drawText(Graphics::Surface &surface, const Common::String &text, FontType font, byte fontHeight, int16 x, int16 y, Color color);
+
Graphics::Surface &getSurface() { return _surface; }
+ Graphics::Surface &getMenuSurface() { return _menu; }
private:
static const int16 kMouseSize = 134;
@@ -201,16 +209,9 @@ private:
void skipDifference(int size, const Graphics::Surface &picture, Common::File &file);
// Further information about these two: https://moddingwiki.shikadi.net/wiki/Raw_EGA_data
- Graphics::Surface loadPictureGraphic(Common::File &file); // Reads Graphic-planar EGA data.
Graphics::Surface loadPictureSign(Common::File &file, uint16 width, uint16 height); // Reads a tricky type of picture used for the "game over"/"about" scrolls and in the mini-game Nim.
- void drawText(Graphics::Surface &surface, const Common::String &text, FontType font, byte fontHeight, int16 x, int16 y, Color color);
void drawBigText(Graphics::Surface &surface, const Common::String &text, FontType font, byte fontHeight, int16 x, int16 y, Color color);
- void drawPicture(Graphics::Surface &target, const Graphics::Surface &picture, uint16 destX, uint16 destY);
-
- // Taken from Free Pascal's Procedure InternalEllipseDefault. Used to replace Pascal's procedure arc.
- // Returns the end point of the arc. (Needed in Clock.)
- Common::Point drawArc(Graphics::Surface &surface, int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color);
};
} // End of namespace Avalanche
diff --git a/engines/avalanche/mainmenu.cpp b/engines/avalanche/mainmenu.cpp
index ce1eafc1d75..fa02db9701d 100644
--- a/engines/avalanche/mainmenu.cpp
+++ b/engines/avalanche/mainmenu.cpp
@@ -29,6 +29,7 @@
#include "avalanche/avalanche.h"
#include "avalanche/mainmenu.h"
#include "avalanche/intro.h"
+#include "titlescreen.h"
namespace Avalanche {
@@ -39,7 +40,7 @@ MainMenu::MainMenu(AvalancheEngine *vm) {
}
void MainMenu::run() {
- _vm->_intro->run();
+ _vm->_titleScreen->run();
_vm->_graphics->menuInitialize();
_vm->_graphics->menuLoadPictures();
loadRegiInfo();
diff --git a/engines/avalanche/titlescreen.cpp b/engines/avalanche/titlescreen.cpp
index 11c60b99a4d..b3003309e0d 100644
--- a/engines/avalanche/titlescreen.cpp
+++ b/engines/avalanche/titlescreen.cpp
@@ -30,8 +30,168 @@ TitleScreen::TitleScreen(AvalancheEngine *vm) : _vm(vm) {
TitleScreen::~TitleScreen() {
}
+void TitleScreen::loadCredits(Common::Array<Common::String> &lines) {
+ Common::File f;
+ if (!f.open("credits.dat")) {
+ warning("AVALANCHE: TitleScreen: File not found: credits.dat");
+ return;
+ }
+
+ while (!f.eos()) {
+ Common::String line;
+ while (!f.eos()) {
+ char ch = f.readByte();
+ if (ch == '\n')
+ break;
+ if (ch != '\r')
+ line += ch;
+ }
+
+ Common::String str;
+ for (uint i = 0; i < line.size(); i++) {
+ char c = line[i];
+ if (c == '%')
+ break;
+ if (c == '@' || c == '^' || c == '>' || c == '*')
+ continue;
+ str += c;
+ }
+ str.trim();
+ if (!str.empty())
+ lines.push_back(str);
+ }
+ f.close();
+}
+
void TitleScreen::run() {
- (void)_vm;
+ _vm->_sound->playMod("avalot2.mod");
+
+ Common::File fontFile;
+ if (fontFile.open("avalot.fnt")) {
+ for (int i = 0; i < 256; i++)
+ fontFile.read(_vm->_font[i], 16);
+ fontFile.close();
+ }
+
+ _vm->_graphics->menuInitialize();
+ Graphics::Surface &menu = _vm->_graphics->getMenuSurface();
+ menu.fillRect(Common::Rect(0, 0, 640, 350), kColorBlack);
+
+ CursorMan.showMouse(false);
+
+ // Draw star arcs
+ static const Color arcColors[5] = { kColorBlue, kColorLightblue, kColorCyan, kColorLightcyan, kColorWhite };
+ byte c = 0;
+ for (int gd = 1; gd <= 64; gd++) {
+ for (int gm = 0; gm <= 60; gm++) {
+ c = (c % 12) + 1;
+ if (c > 5)
+ continue;
+ _vm->_graphics->drawArc(menu, 320, 175, gm * 6, gm * 6 + 1, gd * 6, arcColors[c - 1]);
+ }
+ }
+
+ // Load logo.avd â 1bpp monochrome (each bit = white/black, written to all EGA planes simultaneously)
+ // OR-paste at (112, 0): only white pixels land on screen, black are transparent
+ Common::File logoFile;
+ if (logoFile.open("logo.avd")) {
+ Graphics::Surface logo;
+ logo.create(53 * 8, 194 - 7 + 1, Graphics::PixelFormat::createFormatCLUT8());
+ for (int y = 0; y < 194 - 7 + 1; y++) {
+ for (int x = 0; x < 424; x += 8) {
+ byte pixel = logoFile.readByte();
+ for (int bit = 0; bit < 8; bit++) {
+ byte pixelBit = (pixel >> (7 - bit)) & 1;
+ *(byte *)logo.getBasePtr(x + bit, y) = pixelBit ? kColorWhite : kColorBlack;
+ }
+ }
+ }
+ logoFile.close();
+ for (int y = 0; y < logo.h && y < menu.h; y++) {
+ for (int x = 0; x < logo.w && (x + 112) < menu.w; x++) {
+ byte color = *(byte *)logo.getBasePtr(x, y);
+ // White pixels (logo) overwrite background (stars)
+ if (color != kColorBlack)
+ *(byte *)menu.getBasePtr(x + 112, y) = color;
+ }
+ }
+ logo.free();
+ }
+
+ Common::Array<Common::String> credits;
+ loadCredits(credits);
+
+ Common::String scrollStr;
+ for (uint i = 0; i < credits.size(); i++) {
+ if (!scrollStr.empty())
+ scrollStr += " * ";
+ scrollStr += credits[i];
+ }
+ scrollStr += " ";
+
+ const int kBandCenterY = 315;
+ const int kBandHalfH = (110 - 50) / 3 ;
+ const int kBandTop = kBandCenterY - kBandHalfH;
+ const int kBandBottom = kBandCenterY + kBandHalfH;
+
+ // Phase 1: Gold/magenta band opening animation
+ for (int spinnum = 50; spinnum <= 110 && !_vm->shouldQuit(); spinnum++) {
+ int expand = (spinnum - 50) / 3;
+ menu.fillRect(Common::Rect(0, kBandCenterY - expand, 640, kBandCenterY + expand + 1), kColorYellow);
+ if (spinnum > 56) {
+ int inner = (spinnum - 56) / 3;
+ menu.fillRect(Common::Rect(0, kBandCenterY - inner, 640, kBandCenterY + inner + 1), kColorLightmagenta);
+ }
+ _vm->_graphics->menuRefreshScreen();
+ g_system->delayMillis(3);
+
+ Common::Event event;
+ while (_vm->getEvent(event)) {
+ if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
+ _vm->_sound->stopMod();
+ CursorMan.showMouse(true);
+ return;
+ }
+ }
+ }
+
+ // Phase 2: Scroll credits text left across the band
+ int scrollX = 640;
+ uint32 lastTick = g_system->getMillis();
+
+ while (!_vm->shouldQuit()) {
+ // Draw settled band: gold & green borders + black center
+ menu.fillRect(Common::Rect(0, kBandTop + 2, 640, kBandBottom - 1), kColorBlack);
+ menu.fillRect(Common::Rect(0, kBandTop, 640, kBandTop + 2), kColorYellow);
+ menu.fillRect(Common::Rect(0, kBandBottom - 1, 640, kBandBottom + 1), kColorYellow);
+ menu.fillRect(Common::Rect(0, kBandTop + 2, 640, kBandTop + 4), kColorGreen);
+ menu.fillRect(Common::Rect(0, kBandBottom - 3, 640, kBandBottom - 1), kColorGreen);
+
+ int textY = kBandTop + (kBandHalfH * 2 - 16) / 2;
+ _vm->_graphics->drawText(menu, scrollStr, _vm->_font, 16, scrollX, textY, kColorWhite);
+ _vm->_graphics->menuRefreshScreen();
+
+ uint32 now = g_system->getMillis();
+ if (now - lastTick >= 32) {
+ scrollX -= 8;
+ lastTick = now;
+ if (scrollX < -(int)(scrollStr.size() * 8))
+ break;
+ }
+
+ Common::Event event;
+ while (_vm->getEvent(event)) {
+ if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
+ _vm->_sound->stopMod();
+ CursorMan.showMouse(true);
+ return;
+ }
+ }
+ g_system->delayMillis(5);
+ }
+
+ _vm->_sound->stopMod();
+ CursorMan.showMouse(true);
}
} // End of namespace Avalanche
diff --git a/engines/avalanche/titlescreen.h b/engines/avalanche/titlescreen.h
index 4231e9cd848..66bf1f5d699 100644
--- a/engines/avalanche/titlescreen.h
+++ b/engines/avalanche/titlescreen.h
@@ -22,6 +22,9 @@
#ifndef AVALANCHE_TITLESCREEN_H
#define AVALANCHE_TITLESCREEN_H
+#include "common/array.h"
+#include "common/str.h"
+
namespace Avalanche {
class AvalancheEngine;
@@ -34,6 +37,7 @@ public:
private:
AvalancheEngine *_vm;
+ void loadCredits(Common::Array<Common::String> &lines);
};
} // End of namespace Avalanche
Commit: 4ef76e75e01c91a2e92caa6c54c5fbde6d393c86
https://github.com/scummvm/scummvm/commit/4ef76e75e01c91a2e92caa6c54c5fbde6d393c86
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Refactor intro music playback to use SoundHandler methods
Changed paths:
engines/avalanche/intro.cpp
diff --git a/engines/avalanche/intro.cpp b/engines/avalanche/intro.cpp
index 0600377324b..e8eac64bc29 100644
--- a/engines/avalanche/intro.cpp
+++ b/engines/avalanche/intro.cpp
@@ -258,13 +258,7 @@ void Intro::run() {
_vm->_graphics->menuRestoreScreen();
// Load and play music (glover.mod)
- Common::File musicFile;
- if (musicFile.open("glover.mod")) {
- Audio::AudioStream *stream = Audio::makeProtrackerStream(&musicFile);
- if (stream) {
- _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, _musicHandle, stream);
- }
- }
+ _vm->_sound->playMod("glover.mod");
loadText();
resetPlanes();
@@ -340,7 +334,7 @@ void Intro::run() {
Common::Event event;
while (_vm->getEvent(event)) {
if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
- _vm->_mixer->stopHandle(*_musicHandle);
+ _vm->_sound->stopMod();
CursorMan.showMouse(true);
return;
}
@@ -351,7 +345,7 @@ void Intro::run() {
g_system->delayMillis(55 - delay);
}
- _vm->_mixer->stopHandle(*_musicHandle);
+ _vm->_sound->stopMod();
CursorMan.showMouse(true);
}
Commit: 1c7d1154aa3466c5e998449738faa177fd56fadb
https://github.com/scummvm/scummvm/commit/1c7d1154aa3466c5e998449738faa177fd56fadb
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Use local variable in TitleScreen font loading to prevent in-game font corruption
Changed paths:
engines/avalanche/titlescreen.cpp
diff --git a/engines/avalanche/titlescreen.cpp b/engines/avalanche/titlescreen.cpp
index b3003309e0d..44787d4ed99 100644
--- a/engines/avalanche/titlescreen.cpp
+++ b/engines/avalanche/titlescreen.cpp
@@ -66,10 +66,11 @@ void TitleScreen::loadCredits(Common::Array<Common::String> &lines) {
void TitleScreen::run() {
_vm->_sound->playMod("avalot2.mod");
+ FontType avalotFont;
Common::File fontFile;
if (fontFile.open("avalot.fnt")) {
for (int i = 0; i < 256; i++)
- fontFile.read(_vm->_font[i], 16);
+ fontFile.read(avalotFont[i], 16);
fontFile.close();
}
@@ -168,7 +169,7 @@ void TitleScreen::run() {
menu.fillRect(Common::Rect(0, kBandBottom - 3, 640, kBandBottom - 1), kColorGreen);
int textY = kBandTop + (kBandHalfH * 2 - 16) / 2;
- _vm->_graphics->drawText(menu, scrollStr, _vm->_font, 16, scrollX, textY, kColorWhite);
+ _vm->_graphics->drawText(menu, scrollStr, avalotFont, 16, scrollX, textY, kColorWhite);
_vm->_graphics->menuRefreshScreen();
uint32 now = g_system->getMillis();
Commit: 969ccbd937ae4000f4571fb33c86e5d76e5acab6
https://github.com/scummvm/scummvm/commit/969ccbd937ae4000f4571fb33c86e5d76e5acab6
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Implement MainMenu Option 3 teaser preview
Changed paths:
engines/avalanche/mainmenu.cpp
engines/avalanche/mainmenu.h
diff --git a/engines/avalanche/mainmenu.cpp b/engines/avalanche/mainmenu.cpp
index fa02db9701d..46b377ff331 100644
--- a/engines/avalanche/mainmenu.cpp
+++ b/engines/avalanche/mainmenu.cpp
@@ -111,6 +111,12 @@ void MainMenu::wait() {
_vm->_graphics->menuLoadPictures();
drawMenu();
break;
+ case Common::KEYCODE_3:
+ showPreview();
+ _vm->_graphics->menuInitialize();
+ _vm->_graphics->menuLoadPictures();
+ drawMenu();
+ break;
case Common::KEYCODE_ESCAPE:
case Common::KEYCODE_6: // Falltroughs are inteded.
// Exit back to DOS
@@ -124,4 +130,66 @@ void MainMenu::wait() {
}
}
+void MainMenu::showPreview() {
+ Common::File file;
+ if (!file.open("preview2.avd")) {
+ warning("AVALANCHE: File not found: preview2.avd");
+ return;
+ }
+
+ _vm->_graphics->menuInitialize();
+ Graphics::Surface &preview = _vm->_graphics->getMenuSurface();
+ preview.fillRect(Common::Rect(0, 0, 640, 350), kColorBlack);
+
+ file.seek(177);
+
+ byte planes[4][151 * 80];
+ for (int plane = 0; plane < 4; plane++)
+ file.read(planes[plane], 151 * 80);
+ file.close();
+
+ for (int y = 0; y < 151; y++) {
+ int destY1 = 10 + (y * 4) / 3;
+ int destY2 = 10 + ((y + 1) * 4) / 3;
+ for (int x = 0; x < 640; x++) {
+ int byteIdx = y * 80 + (x / 8);
+ int bitIdx = 7 - (x % 8);
+
+ byte color = 0;
+ for (int plane = 0; plane < 4; plane++) {
+ byte bit = (planes[plane][byteIdx] >> bitIdx) & 1;
+ color |= (bit << plane);
+ }
+ for (int dy = destY1; dy < destY2 && dy < preview.h; dy++)
+ *(byte *)preview.getBasePtr(x, dy) = color;
+ }
+ }
+
+ _vm->_graphics->drawText(preview, "...This is a preview of things to come...", _font, 16, 320 - 20 * 8, 225, kColorCyan);
+ _vm->_graphics->drawText(preview, "AVAROID", _font, 16, 320 - 4 * 8, 245, kColorYellow);
+ _vm->_graphics->drawText(preview, "(a space so dizzy)", _font, 16, 320 - 9 * 8, 263, kColorYellow);
+ _vm->_graphics->drawText(preview, "the next Avvy adventure-- in 256 colours.", _font, 16, 320 - 20 * 8, 283, kColorLightblue);
+ _vm->_graphics->drawText(preview, "Any key...", _font, 16, 540, 318, kColorLightgray);
+
+ _vm->_graphics->menuRefreshScreen();
+ CursorMan.showMouse(false);
+
+ uint32 startTime = g_system->getMillis();
+ while (!_vm->shouldQuit()) {
+ if (g_system->getMillis() - startTime >= 15000)
+ break;
+
+ Common::Event event;
+ while (_vm->getEvent(event)) {
+ if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
+ CursorMan.showMouse(true);
+ return;
+ }
+ }
+ g_system->delayMillis(10);
+ }
+
+ CursorMan.showMouse(true);
+}
+
} // End of namespace Avalanche
diff --git a/engines/avalanche/mainmenu.h b/engines/avalanche/mainmenu.h
index 1b76dbc5b0e..2738c75a85e 100644
--- a/engines/avalanche/mainmenu.h
+++ b/engines/avalanche/mainmenu.h
@@ -48,6 +48,7 @@ private:
void drawMenu();
void centre(int16 y, Common::String text);
void wait();
+ void showPreview();
};
} // End of namespace Avalanche
Commit: 5cd66a540e1df743637e0dff18e005aa0b047afa
https://github.com/scummvm/scummvm/commit/5cd66a540e1df743637e0dff18e005aa0b047afa
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Implement MainMenu Option 5 documentation reader for avalot.doc
Changed paths:
engines/avalanche/mainmenu.cpp
engines/avalanche/mainmenu.h
diff --git a/engines/avalanche/mainmenu.cpp b/engines/avalanche/mainmenu.cpp
index 46b377ff331..7880ac32288 100644
--- a/engines/avalanche/mainmenu.cpp
+++ b/engines/avalanche/mainmenu.cpp
@@ -117,6 +117,12 @@ void MainMenu::wait() {
_vm->_graphics->menuLoadPictures();
drawMenu();
break;
+ case Common::KEYCODE_5:
+ showDoc("avalot.doc", 1094);
+ _vm->_graphics->menuInitialize();
+ _vm->_graphics->menuLoadPictures();
+ drawMenu();
+ break;
case Common::KEYCODE_ESCAPE:
case Common::KEYCODE_6: // Falltroughs are inteded.
// Exit back to DOS
@@ -130,6 +136,121 @@ void MainMenu::wait() {
}
}
+void MainMenu::showDoc(const Common::String &filename, int startLine) {
+ Common::File file;
+ if (!file.open(filename.c_str())) {
+ warning("AVALANCHE: File not found: %s", filename.c_str());
+ return;
+ }
+
+ Common::Array<Common::String> lines;
+ while (!file.eos()) {
+ Common::String line;
+ while (!file.eos()) {
+ char ch = file.readByte();
+ if (ch == '\n')
+ break;
+ if (ch == '\t') {
+ int spaces = 8 - (line.size() % 8);
+ for (int s = 0; s < spaces; s++)
+ line += ' ';
+ } else if ((byte)ch >= 32 && (byte)ch <= 126) {
+ line += ch;
+ }
+ }
+ lines.push_back(line);
+ }
+ file.close();
+
+ if (lines.empty())
+ return;
+
+ int currentLine = startLine;
+ if (currentLine >= (int)lines.size())
+ currentLine = (int)lines.size() - 1;
+ if (currentLine < 0)
+ currentLine = 0;
+
+ _vm->_graphics->menuInitialize();
+ Graphics::Surface &menu = _vm->_graphics->getMenuSurface();
+ CursorMan.showMouse(false);
+
+ const int linesPerPage = 23;
+
+ while (!_vm->shouldQuit()) {
+ menu.fillRect(Common::Rect(0, 0, 640, 332), kColorBlue);
+
+ for (int i = 0; i < linesPerPage; i++) {
+ int lineIdx = currentLine + i;
+ if (lineIdx >= (int)lines.size())
+ break;
+
+ Common::String line = lines[lineIdx];
+ if (line.size() > 78)
+ line = Common::String(line.c_str(), 78);
+
+ _vm->_graphics->drawText(menu, line, _font, 14, 8, 4 + i * 14, kColorLightgray);
+ }
+
+ int pct = (currentLine + linesPerPage) * 100 / lines.size();
+ if (pct > 100)
+ pct = 100;
+ else if (pct <= 1)
+ pct = 0;
+ Common::String statusStr = Common::String::format("Doc lister: PgUp, PgDn, Home & End to move. Esc exits to main menu.|%d%% through", pct);
+ menu.fillRect(Common::Rect(0, 332, 640, 350), kColorLightgray);
+ _vm->_graphics->drawText(menu, statusStr, _vm->_font, 8, 4, 336, kColorBlack);
+
+ _vm->_graphics->menuRefreshScreen();
+
+ Common::Event event;
+ bool redraw = false;
+ while (_vm->getEvent(event)) {
+ if (event.type == Common::EVENT_KEYDOWN) {
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_ESCAPE:
+ CursorMan.showMouse(true);
+ return;
+ case Common::KEYCODE_PAGEUP:
+ case Common::KEYCODE_UP:
+ currentLine -= linesPerPage;
+ if (currentLine < 0)
+ currentLine = 0;
+ redraw = true;
+ break;
+ case Common::KEYCODE_PAGEDOWN:
+ case Common::KEYCODE_DOWN:
+ case Common::KEYCODE_SPACE:
+ if (currentLine + linesPerPage < (int)lines.size())
+ currentLine += linesPerPage;
+ redraw = true;
+ break;
+ case Common::KEYCODE_HOME:
+ currentLine = 0;
+ redraw = true;
+ break;
+ case Common::KEYCODE_END:
+ currentLine = (int)lines.size() - linesPerPage;
+ if (currentLine < 0)
+ currentLine = 0;
+ redraw = true;
+ break;
+ default:
+ break;
+ }
+ } else if (event.type == Common::EVENT_LBUTTONDOWN) {
+ CursorMan.showMouse(true);
+ return;
+ }
+ }
+
+ if (!redraw)
+ g_system->delayMillis(15);
+ }
+
+ CursorMan.showMouse(true);
+}
+
void MainMenu::showPreview() {
Common::File file;
if (!file.open("preview2.avd")) {
diff --git a/engines/avalanche/mainmenu.h b/engines/avalanche/mainmenu.h
index 2738c75a85e..fbedcb36c86 100644
--- a/engines/avalanche/mainmenu.h
+++ b/engines/avalanche/mainmenu.h
@@ -49,6 +49,7 @@ private:
void centre(int16 y, Common::String text);
void wait();
void showPreview();
+ void showDoc(const Common::String &filename, int startLine);
};
} // End of namespace Avalanche
Commit: 5390f634f0665442dd4c3fcc53114cbadcf43669
https://github.com/scummvm/scummvm/commit/5390f634f0665442dd4c3fcc53114cbadcf43669
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Implement MainMenu Option 4: documentation index and section jumping
Changed paths:
engines/avalanche/mainmenu.cpp
engines/avalanche/mainmenu.h
diff --git a/engines/avalanche/mainmenu.cpp b/engines/avalanche/mainmenu.cpp
index 7880ac32288..eb1847f28a9 100644
--- a/engines/avalanche/mainmenu.cpp
+++ b/engines/avalanche/mainmenu.cpp
@@ -117,8 +117,14 @@ void MainMenu::wait() {
_vm->_graphics->menuLoadPictures();
drawMenu();
break;
+ case Common::KEYCODE_4:
+ showDoc("avalot.doc", 0, false);
+ _vm->_graphics->menuInitialize();
+ _vm->_graphics->menuLoadPictures();
+ drawMenu();
+ break;
case Common::KEYCODE_5:
- showDoc("avalot.doc", 1094);
+ showDoc("avalot.doc", 1094, true);
_vm->_graphics->menuInitialize();
_vm->_graphics->menuLoadPictures();
drawMenu();
@@ -136,7 +142,7 @@ void MainMenu::wait() {
}
}
-void MainMenu::showDoc(const Common::String &filename, int startLine) {
+void MainMenu::showDoc(const Common::String &filename, int startLine, bool isRegi) {
Common::File file;
if (!file.open(filename.c_str())) {
warning("AVALANCHE: File not found: %s", filename.c_str());
@@ -165,16 +171,39 @@ void MainMenu::showDoc(const Common::String &filename, int startLine) {
if (lines.empty())
return;
- int currentLine = startLine;
- if (currentLine >= (int)lines.size())
- currentLine = (int)lines.size() - 1;
- if (currentLine < 0)
- currentLine = 0;
+ Common::Array<DocSection> sections;
+ DocSection startSec;
+ startSec.name = "Start of documentation";
+ startSec.line = 0;
+ sections.push_back(startSec);
+
+ for (int i = 1; i < (int)lines.size(); i++) {
+ Common::String trimmed = lines[i];
+ trimmed.trim();
+ if (trimmed.size() >= 3 && trimmed[0] == '"' && trimmed[1] == '"' && trimmed[2] == '"') {
+ Common::String headerStr = lines[i - 1];
+ headerStr.trim();
+ if (!headerStr.empty()) {
+ DocSection sec;
+ sec.name = headerStr;
+ sec.line = i - 1;
+ sections.push_back(sec);
+ }
+ }
+ }
+ int currentLine = startLine;
_vm->_graphics->menuInitialize();
Graphics::Surface &menu = _vm->_graphics->getMenuSurface();
CursorMan.showMouse(false);
+ if (!isRegi && startLine == 0) {
+ // Show Table of Contents index screen
+ int tocLine = showDocTOC(lines, sections);
+ if (tocLine >= 0)
+ currentLine = tocLine;
+ }
+
const int linesPerPage = 23;
while (!_vm->shouldQuit()) {
@@ -189,7 +218,7 @@ void MainMenu::showDoc(const Common::String &filename, int startLine) {
if (line.size() > 78)
line = Common::String(line.c_str(), 78);
- _vm->_graphics->drawText(menu, line, _font, 14, 8, 4 + i * 14, kColorLightgray);
+ _vm->_graphics->drawText(menu, line, _font, 14, 8, 4 + i * 14, kColorCyan);
}
int pct = (currentLine + linesPerPage) * 100 / lines.size();
@@ -197,7 +226,13 @@ void MainMenu::showDoc(const Common::String &filename, int startLine) {
pct = 100;
else if (pct <= 1)
pct = 0;
- Common::String statusStr = Common::String::format("Doc lister: PgUp, PgDn, Home & End to move. Esc exits to main menu.|%d%% through", pct);
+
+ Common::String statusStr;
+ if (isRegi)
+ statusStr = Common::String::format("Doc lister: PgUp, PgDn, Home & End to move. Esc exits to main menu. | %d %% through", pct);
+ else
+ statusStr = Common::String::format("Doc lister: PgUp, PgDn, Home & End to move. Esc exits. C=âcontents |%d %% through", pct);
+
menu.fillRect(Common::Rect(0, 332, 640, 350), kColorLightgray);
_vm->_graphics->drawText(menu, statusStr, _vm->_font, 8, 4, 336, kColorBlack);
@@ -211,6 +246,14 @@ void MainMenu::showDoc(const Common::String &filename, int startLine) {
case Common::KEYCODE_ESCAPE:
CursorMan.showMouse(true);
return;
+ case Common::KEYCODE_c:
+ if (!isRegi) {
+ int tocLine = showDocTOC(lines, sections);
+ if (tocLine >= 0)
+ currentLine = tocLine;
+ redraw = true;
+ }
+ break;
case Common::KEYCODE_PAGEUP:
case Common::KEYCODE_UP:
currentLine -= linesPerPage;
@@ -251,6 +294,54 @@ void MainMenu::showDoc(const Common::String &filename, int startLine) {
CursorMan.showMouse(true);
}
+int MainMenu::showDocTOC(const Common::Array<Common::String> &lines, const Common::Array<DocSection> §ions) {
+ Graphics::Surface &menu = _vm->_graphics->getMenuSurface();
+ menu.fillRect(Common::Rect(0, 0, 640, 332), kColorBlue);
+
+ Common::String header = "-=- The contents of the Lord AVALOT D'Argent (version 1.3) documentation -=-";
+ _vm->_graphics->drawText(menu, header, _font, 14, 320 - (header.size() * 4), 4, kColorCyan);
+
+ for (int i = 0; i < (int)sections.size() && i < 26; i++) {
+ char keyChar = (i < 9) ? ('1' + i) : ('A' + (i - 9));
+ Common::String itemStr = Common::String::format("%c. %s", keyChar, sections[i].name.c_str());
+ if (itemStr.size() > 76)
+ itemStr = Common::String(itemStr.c_str(), 76);
+
+ int x = 12;
+ int y = 20 + i * 11;
+
+ _vm->_graphics->drawText(menu, itemStr, _vm->_font, 8, x, y, kColorCyan);
+ }
+
+ Common::String tocStatus = "Esc=to doc lister | Press the key listed next to the section you wish to jump to";
+ menu.fillRect(Common::Rect(0, 332, 640, 350), kColorLightgray);
+ _vm->_graphics->drawText(menu, tocStatus, _vm->_font, 8, 4, 338, kColorBlack);
+
+ _vm->_graphics->menuRefreshScreen();
+
+ while (!_vm->shouldQuit()) {
+ Common::Event event;
+ while (_vm->getEvent(event)) {
+ if (event.type == Common::EVENT_KEYDOWN) {
+ if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
+ return -1;
+
+ char c = toupper(event.kbd.ascii);
+ int targetSec = -1;
+ if (c >= '1' && c <= '9')
+ targetSec = c - '1';
+ else if (c >= 'A' && c <= 'Z')
+ targetSec = 9 + (c - 'A');
+
+ if (targetSec >= 0 && targetSec < (int)sections.size())
+ return sections[targetSec].line;
+ }
+ }
+ g_system->delayMillis(15);
+ }
+ return -1;
+}
+
void MainMenu::showPreview() {
Common::File file;
if (!file.open("preview2.avd")) {
diff --git a/engines/avalanche/mainmenu.h b/engines/avalanche/mainmenu.h
index fbedcb36c86..5ef2dff08f3 100644
--- a/engines/avalanche/mainmenu.h
+++ b/engines/avalanche/mainmenu.h
@@ -46,10 +46,16 @@ private:
void loadRegiInfo();
void option(byte which, Common::String what);
void drawMenu();
+ struct DocSection {
+ Common::String name;
+ int line;
+ };
+
void centre(int16 y, Common::String text);
void wait();
void showPreview();
- void showDoc(const Common::String &filename, int startLine);
+ void showDoc(const Common::String &filename, int startLine, bool isRegi = false);
+ int showDocTOC(const Common::Array<Common::String> &lines, const Common::Array<DocSection> §ions);
};
} // End of namespace Avalanche
Commit: 10a54c2696126a81ee2b2f7f10b1a8be90ed7711
https://github.com/scummvm/scummvm/commit/10a54c2696126a81ee2b2f7f10b1a8be90ed7711
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-08-25T01:04:54+02:00
Commit Message:
AVALANCHE: Remove stray arrow character from documentation viewer status text
Changed paths:
engines/avalanche/mainmenu.cpp
diff --git a/engines/avalanche/mainmenu.cpp b/engines/avalanche/mainmenu.cpp
index eb1847f28a9..555f6d70140 100644
--- a/engines/avalanche/mainmenu.cpp
+++ b/engines/avalanche/mainmenu.cpp
@@ -231,7 +231,7 @@ void MainMenu::showDoc(const Common::String &filename, int startLine, bool isReg
if (isRegi)
statusStr = Common::String::format("Doc lister: PgUp, PgDn, Home & End to move. Esc exits to main menu. | %d %% through", pct);
else
- statusStr = Common::String::format("Doc lister: PgUp, PgDn, Home & End to move. Esc exits. C=âcontents |%d %% through", pct);
+ statusStr = Common::String::format("Doc lister: PgUp, PgDn, Home & End to move. Esc exits. C=contents |%d %% through", pct);
menu.fillRect(Common::Rect(0, 332, 640, 350), kColorLightgray);
_vm->_graphics->drawText(menu, statusStr, _vm->_font, 8, 4, 336, kColorBlack);
More information about the Scummvm-git-logs
mailing list