[Scummvm-git-logs] scummvm master -> b31124723e689dfdbd6242bac3cd6a66730fe626
alexbevi
noreply at scummvm.org
Fri Oct 16 00:22:25 UTC 2026
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
f2d9adcbba HARVESTER: add cursor handling to Other dialogue entry
e464552720 HARVESTER: handle back-to-front player turn when at room min depth
b31124723e HARVESTER: properly restore animated room elements on re-entry
Commit: f2d9adcbbac8b48ec5d0a90d3f1e0a80d25923c4
https://github.com/scummvm/scummvm/commit/f2d9adcbbac8b48ec5d0a90d3f1e0a80d25923c4
Author: Alex Bevilacqua (alex at alexbevi.com)
Date: 2026-10-15T20:22:11-04:00
Commit Message:
HARVESTER: add cursor handling to Other dialogue entry
Assisted-by: Codex:gpt-6.1-sol
Changed paths:
engines/harvester/cft_font.cpp
engines/harvester/cft_font.h
engines/harvester/dialogue.cpp
diff --git a/engines/harvester/cft_font.cpp b/engines/harvester/cft_font.cpp
index 7b3630aef2d..5f7743f5a12 100644
--- a/engines/harvester/cft_font.cpp
+++ b/engines/harvester/cft_font.cpp
@@ -121,6 +121,10 @@ HarvesterCftFont::HarvesterCftFont(const CftFontResource &resource) : _resource(
_spaceWidth = MAX<int>(1, _maxCharWidth);
}
+bool HarvesterCftFont::hasGlyph(uint32 chr) const {
+ return chr == ' ' || chr == '_' || findGlyph(chr) != nullptr;
+}
+
int HarvesterCftFont::getCharWidth(uint32 chr) const {
if (chr == ' ' || chr == '_')
return _spaceWidth;
diff --git a/engines/harvester/cft_font.h b/engines/harvester/cft_font.h
index a7cd0d34241..e6588c1a485 100644
--- a/engines/harvester/cft_font.h
+++ b/engines/harvester/cft_font.h
@@ -40,6 +40,7 @@ public:
Common::String getFontName() const override { return _resource.name; }
int getMaxCharWidth() const override { return _maxCharWidth; }
int getCharWidth(uint32 chr) const override;
+ bool hasGlyph(uint32 chr) const;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
private:
diff --git a/engines/harvester/dialogue.cpp b/engines/harvester/dialogue.cpp
index a343fe3d54d..8787db2c63b 100644
--- a/engines/harvester/dialogue.cpp
+++ b/engines/harvester/dialogue.cpp
@@ -133,6 +133,9 @@ static const int kDialogueOtherX = 171;
static const int kDialogueOtherY = 183;
static const int kDialogueTextEntryX = 208;
static const int kDialogueTextEntryY = 184;
+static const uint kDialogueTextEntryMaxLength = 26;
+static const int kDialogueTextEntryMaxWidth = 550;
+static const uint32 kDialogueTextEntryBlinkTicks = 0x30;
static const int kDialogueOtherWidth = 120;
static const int kDialogueTopicStartX = 168;
static const int kDialogueTopicEndX = 482;
@@ -766,6 +769,8 @@ public:
topics.push_back(_genericByeTopic);
debugC(1, kDebugDialogue, "Harvester: keyword menu default topic='%s'", _genericByeTopic.c_str());
bool editingOther = false;
+ bool textEntryCursorVisible = false;
+ uint32 textEntryBlinkTimestamp = 0;
Common::String typedTopic;
Common::Error releaseError = waitForPointerRelease();
if (releaseError.getCode() != Common::kNoError)
@@ -773,43 +778,66 @@ public:
Graphics::FrameLimiter limiter(g_system, 60);
for (;;) {
+ const uint32 now = getRuntimeClockTicks();
+ if (editingOther && now - textEntryBlinkTimestamp > kDialogueTextEntryBlinkTicks) {
+ textEntryCursorVisible = !textEntryCursorVisible;
+ textEntryBlinkTimestamp = now;
+ }
const int hoveredTopicIndex = editingOther ? -1 : getDialogueMenuItemAt(*_menuFont, topics.size(), _mousePos);
- const bool hoverOther = !editingOther && isDialogueOtherHit(_mousePos);
+ const bool hoverOther = editingOther || isDialogueOtherHit(_mousePos);
drawDialogueOverlay(&_keywordBitmap, nullptr, &topics, hoveredTopicIndex, hoverOther,
- editingOther ? &typedTopic : nullptr);
+ editingOther ? &typedTopic : nullptr, textEntryCursorVisible);
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
Common::Error result = Common::kNoError;
- if (DialogueFlowAccess::handleSystemEvent(_flow, event, result))
+ if (DialogueFlowAccess::handleSystemEvent(_flow, event, result)) {
+ if (editingOther && _entityManager)
+ _entityManager->showCursor();
return result;
+ }
if (editingOther) {
+ bool acceptInput = false;
+ bool cancelInput = false;
if (event.type == Common::EVENT_KEYDOWN) {
if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {
- typedTopic.clear();
- editingOther = false;
- debugC(1, kDebugDialogue, "Harvester: keyword menu cancelled Other input");
- if (_entityManager)
- _entityManager->showCursor();
- } else if (event.kbd.keycode == Common::KEYCODE_BACKSPACE) {
+ cancelInput = true;
+ } else if (event.kbd.keycode == Common::KEYCODE_BACKSPACE ||
+ event.kbd.keycode == Common::KEYCODE_LEFT) {
if (!typedTopic.empty())
typedTopic.deleteLastChar();
+ } else if (event.kbd.keycode == Common::KEYCODE_HOME) {
+ typedTopic.clear();
} else if (event.kbd.keycode == Common::KEYCODE_RETURN ||
event.kbd.keycode == Common::KEYCODE_KP_ENTER) {
- if (!typedTopic.empty()) {
- selectedTopic = typedTopic;
- selection.fromTypedInput = true;
- debugC(1, kDebugDialogue, "Harvester: keyword menu typed topic='%s'",
- selectedTopic.c_str());
- if (_entityManager)
- _entityManager->showCursor();
- return Common::kNoError;
- }
- } else if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7e &&
- typedTopic.size() < 79) {
+ acceptInput = true;
+ } else if (event.kbd.ascii >= 0x1f && event.kbd.ascii <= 0x80 &&
+ event.kbd.ascii != '~' && typedTopic.size() < kDialogueTextEntryMaxLength &&
+ (!_subtitleCftFont || _subtitleCftFont->hasGlyph(event.kbd.ascii))) {
typedTopic += (char)event.kbd.ascii;
+ if (_highlightFont->getStringWidth(typedTopic) > kDialogueTextEntryMaxWidth)
+ typedTopic.deleteLastChar();
+ }
+ } else if (event.type == Common::EVENT_LBUTTONDOWN) {
+ acceptInput = Common::Rect(3, 460, 318, 477).contains(event.mouse);
+ cancelInput = Common::Rect(321, 460, 636, 477).contains(event.mouse);
+ if (cancelInput)
+ g_system->delayMillis(400);
+ }
+ if (acceptInput || cancelInput) {
+ editingOther = false;
+ if (_entityManager)
+ _entityManager->showCursor();
+ if (acceptInput && !typedTopic.empty()) {
+ selectedTopic = typedTopic;
+ selection.fromTypedInput = true;
+ debugC(1, kDebugDialogue, "Harvester: keyword menu typed topic='%s'",
+ selectedTopic.c_str());
+ return Common::kNoError;
}
+ typedTopic.clear();
+ debugC(1, kDebugDialogue, "Harvester: keyword menu cancelled Other input");
}
continue;
}
@@ -838,6 +866,8 @@ public:
if (isDialogueOtherHit(_mousePos)) {
typedTopic.clear();
editingOther = true;
+ textEntryCursorVisible = false;
+ textEntryBlinkTimestamp = getRuntimeClockTicks();
debugC(1, kDebugDialogue, "Harvester: keyword menu entered Other input");
if (_entityManager)
_entityManager->hideCursor();
@@ -998,7 +1028,8 @@ private:
void drawDialogueOverlay(const IndexedBitmap *overlayBitmap,
const Common::Array<Common::String> *subtitleLines, const Common::Array<Common::String> *topics,
- int hoveredTopicIndex, bool hoverOther, const Common::String *textEntryValue) {
+ int hoveredTopicIndex, bool hoverOther, const Common::String *textEntryValue,
+ bool textEntryCursorVisible = false) {
Graphics::Screen *activeScreen = getActiveScreen();
if (!activeScreen)
return;
@@ -1057,8 +1088,9 @@ private:
if (textEntryValue) {
drawFontString(*_highlightFont, _highlightFontUsesCft,
- *textEntryValue + "_", kDialogueTextEntryX, kDialogueTextEntryY,
- kDialogueKeywordTextWidth - 30, kTextColorNormal);
+ *textEntryValue + (textEntryCursorVisible ? "~" : ""),
+ kDialogueTextEntryX, kDialogueTextEntryY, kDialogueTextEntryMaxWidth,
+ kTextColorNormal);
}
if (_entityManager)
Commit: e4645527209e4a956f1e18a9e55e5a7be392fe0b
https://github.com/scummvm/scummvm/commit/e4645527209e4a956f1e18a9e55e5a7be392fe0b
Author: Alex Bevilacqua (alex at alexbevi.com)
Date: 2026-10-15T20:22:11-04:00
Commit Message:
HARVESTER: handle back-to-front player turn when at room min depth
Fixes #17370
Assisted-by: Codex:gpt-6.1-sol
Changed paths:
engines/harvester/player.cpp
diff --git a/engines/harvester/player.cpp b/engines/harvester/player.cpp
index 8d838aa2f48..0136cc01933 100644
--- a/engines/harvester/player.cpp
+++ b/engines/harvester/player.cpp
@@ -1696,13 +1696,19 @@ bool Player::startTurnAnimation(RoomPlayerState &playerState, int targetFacing)
playerState.facing < 0 || playerState.facing == targetFacing)
return false;
- // update_actor_runtime_state (0x4d750) routes desired states 1/2 from the
- // opposite horizontal facing through front-facing state 0.
- const int nextFacing = (playerState.facing == 1 && targetFacing == 2) ||
- (playerState.facing == 2 && targetFacing == 1) ? 0 : targetFacing;
+ int nextFacing = targetFacing;
+ if ((playerState.facing == 1 && targetFacing == 2) ||
+ (playerState.facing == 2 && targetFacing == 1))
+ nextFacing = 0;
+ else if ((playerState.facing == 0 && targetFacing == 3) ||
+ (playerState.facing == 3 && targetFacing == 0))
+ nextFacing = 2;
PlayerTurnAnimationRange range;
- if (!resolvePlayerTurnAnimationRange(playerState.facing, nextFacing, range))
+ if (playerState.facing == 3 && targetFacing == 0) {
+ range = PlayerTurnAnimationRange{ 0x28, 0x28, false };
+ } else if (!resolvePlayerTurnAnimationRange(playerState.facing, nextFacing, range)) {
return false;
+ }
playerState.turnActive = true;
playerState.turnTargetFacing = nextFacing;
Commit: b31124723e689dfdbd6242bac3cd6a66730fe626
https://github.com/scummvm/scummvm/commit/b31124723e689dfdbd6242bac3cd6a66730fe626
Author: Alex Bevilacqua (alex at alexbevi.com)
Date: 2026-10-15T20:22:11-04:00
Commit Message:
HARVESTER: properly restore animated room elements on re-entry
Fixes #17360
Assisted-by: Codex:gpt-6.1-sol
Changed paths:
engines/harvester/entity.cpp
engines/harvester/entity.h
diff --git a/engines/harvester/entity.cpp b/engines/harvester/entity.cpp
index ebd3839a251..0a4a2e13de6 100644
--- a/engines/harvester/entity.cpp
+++ b/engines/harvester/entity.cpp
@@ -241,12 +241,13 @@ void Entity::setAnimationEnabled(bool enabled) {
}
}
-void Entity::setCurrentFrame(int frame) {
+void Entity::setCurrentFrame(int frame, bool preserveScreenBase) {
if (_frames.empty())
return;
advanceAnimationFrame(frame);
- updateScreenBaseFromCurrentFrame();
+ if (!preserveScreenBase)
+ updateScreenBaseFromCurrentFrame();
}
void Entity::setAnimationFrameRange(int firstFrame, int lastFrame, bool looping) {
@@ -900,10 +901,6 @@ Entity *EntityManager::spawnSceneAnimationEntity(const Common::String &name,
if (!entity)
return nullptr;
- // Native room ANIM entities center the initially shown frame on the record
- // x/y pivot, lower the render-list depth anchor by half z_extent, and then
- // keep that cached screen base while later frame ABM x/y offsets shift the
- // final draw rect.
entity->setAnchorMode(kEntityAnchorCentered);
entity->setZExtent(3.0f);
entity->setPosition(position.x, position.y, z - floorf(MAX<float>(entity->getZExtent(), 0.0f) * 0.5f));
@@ -913,7 +910,7 @@ Entity *EntityManager::spawnSceneAnimationEntity(const Common::String &name,
int startFrame = playBackwards ? entity->getLastFrame() : 0;
if (!playBackwards && initialFrame >= 0)
startFrame = CLIP<int>(initialFrame, 0, entity->getLastFrame());
- entity->setCurrentFrame(startFrame);
+ entity->setCurrentFrame(startFrame, true);
// Non-looping room ANIM records can be authored visible but are started by SET_ANIM.
const bool shouldAdvance = active && (looping || initialFrame >= 0);
entity->setAnimationEnabled(shouldAdvance);
diff --git a/engines/harvester/entity.h b/engines/harvester/entity.h
index b14011749a3..b561f15c02c 100644
--- a/engines/harvester/entity.h
+++ b/engines/harvester/entity.h
@@ -92,7 +92,7 @@ public:
int getAnimationRate() const { return _animationRate; }
void setAnimationEnabled(bool enabled);
bool isAnimationEnabled() const { return _animationEnabled; }
- void setCurrentFrame(int frame);
+ void setCurrentFrame(int frame, bool preserveScreenBase = false);
int getCurrentFrame() const { return _currentFrame; }
int getLastFrame() const { return _lastFrame; }
uint getFrameCount() const { return _frames.size(); }
More information about the Scummvm-git-logs
mailing list