[Scummvm-git-logs] scummvm branch-2-9 -> a8930572186fa7d9fef2fc48e983898912265fd6
mgerhardy
noreply at scummvm.org
Wed Apr 30 05:01:53 UTC 2025
This automated email contains information about 11 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
3eced3c6a4 TWINE: comments to mention the original source names
49e3fdf9e9 TWINE: added pitchbend values to playSample (they are still unused)
067722311f TWINE: fixed pitch handling for samples
9ca0e8ed64 TWINE: Fix compilation
1b16313b96 TWINE: the holomap rotation is slow and location interaction is weird
68e7353686 TWINE: The movement of the meca penguin is different from dos version
4ce8dbf73b TWINE: fixed memory leak in fla sample handling
f0fa6416ec TWINE: fixed Audio::makeVOCStream call and fixed memory leak in vox samples
6defd5c324 TWINE: fixed missing pitchbend parameter for environmental sounds
20d9634db0 TWINE: started to support mixer balance changing for some samples
a893057218 TWINE: Skipping the text intro with Escape also skips the subsequent FMV
Commit: 3eced3c6a422db3b124aa9e3b3878f9c00847d48
https://github.com/scummvm/scummvm/commit/3eced3c6a422db3b124aa9e3b3878f9c00847d48
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:39:43+02:00
Commit Message:
TWINE: comments to mention the original source names
Changed paths:
engines/twine/shared.h
diff --git a/engines/twine/shared.h b/engines/twine/shared.h
index ce4b5e7cf77..86c46c48aa4 100644
--- a/engines/twine/shared.h
+++ b/engines/twine/shared.h
@@ -287,38 +287,38 @@ enum class ControlMode {
enum class AnimationTypes {
kAnimNone = -1,
- kStanding = 0, // GEN_ANIM_RIEN
- kForward = 1, // GEN_ANIM_MARCHE
- kBackward = 2, // GEN_ANIM_RECULE
- kTurnLeft = 3, // GEN_ANIM_GAUCHE
- kTurnRight = 4, // GEN_ANIM_DROITE
- kHit = 5,
- kBigHit = 6,
- kFall = 7,
- kLanding = 8,
- kLandingHit = 9,
- kLandDeath = 10,
- kAction = 11,
- kClimbLadder = 12,
- kTopLadder = 13,
- kJump = 14,
- kThrowBall = 15,
- kHide = 16,
- kKick = 17,
- kRightPunch = 18,
- kLeftPunch = 19,
- kFoundItem = 20,
- kDrawn = 21,
- kHit2 = 22,
- kSabreAttack = 23,
- kPush = 27, // GEN_ANIM_POUSSE
- kSabreUnknown = 24,
+ kStanding = 0, // GEN_ANIM_RIEN
+ kForward = 1, // GEN_ANIM_MARCHE
+ kBackward = 2, // GEN_ANIM_RECULE
+ kTurnLeft = 3, // GEN_ANIM_GAUCHE
+ kTurnRight = 4, // GEN_ANIM_DROITE
+ kHit = 5, // GEN_ANIM_ENCAISSE
+ kBigHit = 6, // GEN_ANIM_CHOC
+ kFall = 7, // GEN_ANIM_TOMBE
+ kLanding = 8, // GEN_ANIM_RECEPTION
+ kLandingHit = 9, // GEN_ANIM_RECEPTION_2
+ kLandDeath = 10, // GEN_ANIM_MORT
+ kAction = 11, // GEN_ANIM_ACTION
+ kClimbLadder = 12, // GEN_ANIM_MONTE
+ kTopLadder = 13, // GEN_ANIM_ECHELLE
+ kJump = 14, // GEN_ANIM_SAUTE
+ kThrowBall = 15, // GEN_ANIM_LANCE
+ kHide = 16, // GEN_ANIM_CACHE
+ kKick = 17, // GEN_ANIM_COUP_1
+ kRightPunch = 18, // GEN_ANIM_COUP_2
+ kLeftPunch = 19, // GEN_ANIM_COUP_3
+ kFoundItem = 20, // GEN_ANIM_TROUVE
+ kDrawn = 21, // GEN_ANIM_NOYADE
+ kHit2 = 22, // GEN_ANIM_CHOC2
+ kSabreAttack = 23, // GEN_ANIM_SABRE
+ kSabreUnknown = 24, // GEN_ANIM_DEGAINE
+ kPush = 27, // GEN_ANIM_POUSSE
kCarStarting = 303,
kCarDriving = 304,
kCarDrivingBackwards = 305,
kCarStopping = 306,
kCarFrozen = 307,
- kAnimInvalid = 255
+ kAnimInvalid = 255 // NO_ANIM
};
enum class AnimType {
Commit: 49e3fdf9e9fae436bbe7232b756d91f16dfdea9c
https://github.com/scummvm/scummvm/commit/49e3fdf9e9fae436bbe7232b756d91f16dfdea9c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:39:43+02:00
Commit Message:
TWINE: added pitchbend values to playSample (they are still unused)
see issue https://bugs.scummvm.org/ticket/15735
Changed paths:
engines/twine/audio/sound.cpp
engines/twine/audio/sound.h
engines/twine/renderer/redraw.cpp
engines/twine/scene/actor.cpp
engines/twine/scene/animations.cpp
engines/twine/scene/extra.cpp
engines/twine/script/script_move.cpp
engines/twine/script/script_move.h
engines/twine/twine.cpp
diff --git a/engines/twine/audio/sound.cpp b/engines/twine/audio/sound.cpp
index b8d758e2cb1..19a72209cfb 100644
--- a/engines/twine/audio/sound.cpp
+++ b/engines/twine/audio/sound.cpp
@@ -112,7 +112,7 @@ void Sound::playFlaSample(int32 index, int32 repeat, uint8 balance, int32 volume
playSample(channelIdx, index, audioStream, repeat, Resources::HQR_FLASAMP_FILE);
}
-void Sound::playSample(int32 index, int32 repeat, int32 x, int32 y, int32 z, int32 actorIdx) {
+void Sound::playSample(int32 index, uint16 pitchbend, int32 repeat, int32 x, int32 y, int32 z, int32 actorIdx) {
if (!_engine->_cfgfile.Sound) {
return;
}
@@ -131,6 +131,9 @@ void Sound::playSample(int32 index, int32 repeat, int32 x, int32 y, int32 z, int
samplesPlayingActors[channelIdx] = -1;
}
+ // TODO: implement pitchbend - see https://bugs.scummvm.org/ticket/15735
+ // frequency would be 11025 + (pitchbend - 0x1000);
+
uint8 *sampPtr = _engine->_resources->_samplesTable[index];
uint32 sampSize = _engine->_resources->_samplesSizeTable[index];
Common::MemoryReadStream *stream = new Common::MemoryReadStream(sampPtr, sampSize, DisposeAfterUse::NO);
diff --git a/engines/twine/audio/sound.h b/engines/twine/audio/sound.h
index 08d73da772b..3db1bd056f2 100644
--- a/engines/twine/audio/sound.h
+++ b/engines/twine/audio/sound.h
@@ -44,7 +44,7 @@ enum _Samples {
TaskCompleted = 41,
Hit = 86,
ItemFound = 97,
- WalkFloorBegin = 126,
+ WalkFloorBegin = 126, // BASE_STEP_SOUND
WalkFloorRightBegin = 141
};
}
@@ -100,11 +100,10 @@ public:
* @param z sound generating entity z position
* @param actorIdx
*/
- void playSample(int32 index, int32 repeat = 1, int32 x = 128, int32 y = 128, int32 z = 128, int32 actorIdx = -1); // HQ_3D_MixSample
- void playSample(int32 index, int32 repeat, const IVec3 &pos, int32 actorIdx = -1) { // HQ_MixSample
- playSample(index, repeat, pos.x, pos.y, pos.z, actorIdx);
+ void playSample(int32 index, uint16 pitchbend = 0x1000, int32 repeat = 1, int32 x = 128, int32 y = 128, int32 z = 128, int32 actorIdx = -1); // HQ_3D_MixSample
+ void playSample(int32 index, uint16 pitchbend, int32 repeat, const IVec3 &pos, int32 actorIdx = -1) { // HQ_MixSample
+ playSample(index, pitchbend, repeat, pos.x, pos.y, pos.z, actorIdx);
}
-
/** Pause samples */
void pauseSamples();
diff --git a/engines/twine/renderer/redraw.cpp b/engines/twine/renderer/redraw.cpp
index 8c617f4b4e1..cfff95a7a80 100644
--- a/engines/twine/renderer/redraw.cpp
+++ b/engines/twine/renderer/redraw.cpp
@@ -332,7 +332,7 @@ int32 Redraw::fillExtraDrawingList(DrawListStruct *drawList, int32 drawListPos)
if (_engine->timerRef - extra->spawnTime > 35) {
extra->spawnTime = _engine->timerRef;
extra->type &= ~ExtraType::TIME_IN;
- _engine->_sound->playSample(Samples::ItemPopup, 1, extra->pos);
+ _engine->_sound->playSample(Samples::ItemPopup, 0x1000, 1, extra->pos);
}
continue;
}
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index 8c92373bc2c..ad3c67f46b6 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -436,13 +436,13 @@ void Actor::giveExtraBonus(int32 actorIdx) {
}
if (actor->_workFlags.bIsDead) {
_engine->_extra->addExtraBonus(actor->posObj(), LBAAngles::ANGLE_90, LBAAngles::ANGLE_0, bonusSprite, actor->_bonusAmount);
- _engine->_sound->playSample(Samples::ItemPopup, 1, actor->posObj(), actorIdx);
+ _engine->_sound->playSample(Samples::ItemPopup, 0x1000, 1, actor->posObj(), actorIdx);
} else {
const ActorStruct *sceneHero = _engine->_scene->_sceneHero;
const int32 angle = _engine->_movements->getAngle(actor->posObj(), sceneHero->posObj());
const IVec3 pos(actor->_posObj.x, actor->_posObj.y + actor->_boundingBox.maxs.y, actor->_posObj.z);
_engine->_extra->addExtraBonus(pos, LBAAngles::ANGLE_70, angle, bonusSprite, actor->_bonusAmount);
- _engine->_sound->playSample(Samples::ItemPopup, 1, pos, actorIdx);
+ _engine->_sound->playSample(Samples::ItemPopup, 0x1000, 1, pos, actorIdx);
}
}
diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 962592c8cff..e5ef81e0449 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -294,9 +294,14 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
}
break;
case ActionType::ACTION_SAMPLE:
+ if (action.animFrame == actor->_frame) {
+ _engine->_sound->playSample(action.sampleIndex, 0x1000, 1, actor->posObj(), actorIdx);
+ }
+ break;
case ActionType::ACTION_SAMPLE_FREQ:
if (action.animFrame == actor->_frame) {
- _engine->_sound->playSample(action.sampleIndex, 1, actor->posObj(), actorIdx);
+ const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(action.frequency) - (action.frequency / 2);
+ _engine->_sound->playSample(action.sampleIndex, pitchBend, 1, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_THROW_EXTRA_BONUS:
@@ -311,7 +316,7 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
break;
case ActionType::ACTION_SAMPLE_REPEAT:
if (action.animFrame == actor->_frame) {
- _engine->_sound->playSample(action.sampleIndex, action.repeat, actor->posObj(), actorIdx);
+ _engine->_sound->playSample(action.sampleIndex, 0x1000, action.repeat, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_THROW_SEARCH:
@@ -332,13 +337,15 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
case ActionType::ACTION_LEFT_STEP:
if (action.animFrame == actor->_frame && (actor->_brickSound & 0xF0U) != 0xF0U) {
const int16 sampleIdx = (actor->_brickSound & 0x0FU) + Samples::WalkFloorBegin;
- _engine->_sound->playSample(sampleIdx, 1, actor->posObj(), actorIdx);
+ const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(1000) - 500;
+ _engine->_sound->playSample(sampleIdx, pitchBend, 1, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_RIGHT_STEP:
if (action.animFrame == actor->_frame && (actor->_brickSound & 0xF0U) != 0xF0U) {
const int16 sampleIdx = (actor->_brickSound & 0x0FU) + Samples::WalkFloorRightBegin;
- _engine->_sound->playSample(sampleIdx, 1, actor->posObj(), actorIdx);
+ const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(1000) - 500;
+ _engine->_sound->playSample(sampleIdx, pitchBend, 1, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_HERO_HITTING:
@@ -400,7 +407,7 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
}
}
-bool Animations::initAnim(AnimationTypes newAnim, AnimType flag, AnimationTypes genNextAnim, int32 actorIdx) {
+bool Animations::initAnim(AnimationTypes genNewAnim, AnimType flag, AnimationTypes genNextAnim, int32 actorIdx) {
ActorStruct *actor = _engine->_scene->getActor(actorIdx);
if (actor->_body == -1) {
return false;
@@ -410,7 +417,7 @@ bool Animations::initAnim(AnimationTypes newAnim, AnimType flag, AnimationTypes
return false;
}
- if (newAnim == actor->_genAnim && actor->_anim != -1) {
+ if (genNewAnim == actor->_genAnim && actor->_anim != -1) {
return true;
}
@@ -418,7 +425,7 @@ bool Animations::initAnim(AnimationTypes newAnim, AnimType flag, AnimationTypes
genNextAnim = actor->_genAnim;
}
- int32 newanim = searchAnim(newAnim, actorIdx);
+ int32 newanim = searchAnim(genNewAnim, actorIdx);
if (newanim == -1) {
newanim = searchAnim(AnimationTypes::kStanding, actorIdx);
@@ -428,7 +435,7 @@ bool Animations::initAnim(AnimationTypes newAnim, AnimType flag, AnimationTypes
}
if (flag != AnimType::kAnimationSet && actor->_flagAnim == AnimType::kAnimationAllThen) {
- actor->_nextGenAnim = newAnim;
+ actor->_nextGenAnim = genNewAnim;
return false;
}
@@ -455,7 +462,7 @@ bool Animations::initAnim(AnimationTypes newAnim, AnimType flag, AnimationTypes
}
actor->_anim = newanim;
- actor->_genAnim = newAnim;
+ actor->_genAnim = genNewAnim;
actor->_nextGenAnim = genNextAnim;
actor->_ptrAnimAction = _currentActorAnimExtraPtr;
diff --git a/engines/twine/scene/extra.cpp b/engines/twine/scene/extra.cpp
index 258a9365fb7..32631a1cb52 100644
--- a/engines/twine/scene/extra.cpp
+++ b/engines/twine/scene/extra.cpp
@@ -610,7 +610,7 @@ void Extra::gereExtras() {
const int32 angle = ClampAngle(tmpAngle - extra->angle);
if (angle > LBAAngles::ANGLE_140 && angle < LBAAngles::ANGLE_210) {
- _engine->_sound->playSample(Samples::ItemFound, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
+ _engine->_sound->playSample(Samples::ItemFound, 0x1000, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
if (extraKey->info1 > 1) {
const IVec3 &projPos = _engine->_renderer->projectPoint(extraKey->pos - _engine->_grid->_worldCube);
@@ -643,7 +643,7 @@ void Extra::gereExtras() {
_engine->_movements->initRealValue(LBAAngles::ANGLE_0, extra->destPos.z, LBAAngles::ANGLE_17, &extra->trackActorMove);
if (extraIdx == _engine->_collision->extraCheckExtraCol(extra, _engine->_gameState->_magicBall)) {
- _engine->_sound->playSample(Samples::ItemFound, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
+ _engine->_sound->playSample(Samples::ItemFound, 0x1000, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
if (extraKey->info1 > 1) {
const IVec3 &projPos = _engine->_renderer->projectPoint(extraKey->pos - _engine->_grid->_worldCube);
@@ -720,7 +720,8 @@ void Extra::gereExtras() {
}
// if extra is magic ball
if (i == _engine->_gameState->_magicBall) {
- _engine->_sound->playSample(Samples::Hit, 1, extra->pos);
+ const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(300) - 150;
+ _engine->_sound->playSample(Samples::Hit, pitchBend, 1, extra->pos);
// can't bounce with not magic points
if (_engine->_gameState->_magicBallType <= 0) {
@@ -791,7 +792,7 @@ void Extra::gereExtras() {
if ((extra->type & ExtraType::TAKABLE) && !(extra->type & ExtraType::FLY)) {
// if hero touch extra
if (_engine->_collision->extraCheckObjCol(extra, -1) == 0) {
- _engine->_sound->playSample(Samples::ItemFound, 1, extra->pos);
+ _engine->_sound->playSample(Samples::ItemFound, 0x1000, 1, extra->pos);
if (extra->info1 > 1) {
const IVec3 &projPos = _engine->_renderer->projectPoint(extra->pos - _engine->_grid->_worldCube);
diff --git a/engines/twine/script/script_move.cpp b/engines/twine/script/script_move.cpp
index 1021b905bfa..8737bbb00d7 100644
--- a/engines/twine/script/script_move.cpp
+++ b/engines/twine/script/script_move.cpp
@@ -280,7 +280,7 @@ int32 ScriptMove::mWAIT_NUM_ANIM(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 ScriptMove::mSAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE(%i)", (int)sampleIdx);
- engine->_sound->playSample(sampleIdx, 1, ctx.actor->posObj(), ctx.actorIdx);
+ engine->_sound->playSample(sampleIdx, 0x1000, 1, ctx.actor->posObj(), ctx.actorIdx);
return 0;
}
@@ -491,7 +491,8 @@ int32 ScriptMove::mWAIT_DOOR(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 ScriptMove::mSAMPLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE_RND(%i)", (int)sampleIdx);
- engine->_sound->playSample(sampleIdx, 1, ctx.actor->posObj(), ctx.actorIdx);
+ const uint16 pitchbend = 0x800 + engine->getRandomNumber(0x800);
+ engine->_sound->playSample(sampleIdx, pitchbend, 1, ctx.actor->posObj(), ctx.actorIdx);
return 0;
}
@@ -503,7 +504,7 @@ int32 ScriptMove::mSAMPLE_ALWAYS(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE_ALWAYS(%i)", (int)sampleIdx);
if (!engine->_sound->isSamplePlaying(sampleIdx)) { // if its not playing
- engine->_sound->playSample(sampleIdx, -1, ctx.actor->posObj(), ctx.actorIdx);
+ engine->_sound->playSample(sampleIdx, 0x1000, 0, ctx.actor->posObj(), ctx.actorIdx);
}
return 0;
}
@@ -552,8 +553,8 @@ int32 ScriptMove::mPLAY_FLA(TwinEEngine *engine, MoveScriptContext &ctx) {
* @note Opcode @c 0x1F
*/
int32 ScriptMove::mREPEAT_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
- ctx.numRepeatSample = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::REPEAT_SAMPLE(%i)", (int)ctx.numRepeatSample);
+ ctx.bigSampleRepeat = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::REPEAT_SAMPLE(%i)", (int)ctx.bigSampleRepeat);
return 0;
}
@@ -564,8 +565,8 @@ int32 ScriptMove::mREPEAT_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 ScriptMove::mSIMPLE_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SIMPLE_SAMPLE(%i)", (int)sampleIdx);
- engine->_sound->playSample(sampleIdx, ctx.numRepeatSample, ctx.actor->posObj(), ctx.actorIdx);
- ctx.numRepeatSample = 1;
+ engine->_sound->playSample(sampleIdx, 0x1000, ctx.bigSampleRepeat, ctx.actor->posObj(), ctx.actorIdx);
+ ctx.bigSampleRepeat = 1;
return 0;
}
diff --git a/engines/twine/script/script_move.h b/engines/twine/script/script_move.h
index e77da56ab47..d52a35e2c5a 100644
--- a/engines/twine/script/script_move.h
+++ b/engines/twine/script/script_move.h
@@ -30,7 +30,7 @@ namespace TwinE {
struct MoveScriptContext {
int32 actorIdx;
ActorStruct *actor;
- int32 numRepeatSample = 1;
+ int32 bigSampleRepeat = 1;
Common::MemorySeekableReadWriteStream stream;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 78912b5e46c..06509cbb91e 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -1096,7 +1096,8 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
actor->_workFlags.bIsHitting = 0;
#endif
} else {
- _sound->playSample(Samples::Explode, 1, actor->posObj(), a);
+ const uint16 pitchBend = 0x1000 + getRandomNumber(2000) - (2000 / 2);
+ _sound->playSample(Samples::Explode, pitchBend, 1, actor->posObj(), a);
if (a == _scene->_mecaPenguinIdx) {
_extra->extraExplo(actor->posObj());
@@ -1160,7 +1161,8 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
actor->_flags.bNoShadow = 1;
}
} else {
- _sound->playSample(Samples::Explode, 1, actor->posObj(), a);
+ const uint16 pitchBend = 0x1000 + getRandomNumber(2000) - (2000 / 2);
+ _sound->playSample(Samples::Explode, pitchBend, 1, actor->posObj(), a);
if (actor->_bonusParameter.cloverleaf || actor->_bonusParameter.kashes || actor->_bonusParameter.key || actor->_bonusParameter.lifepoints || actor->_bonusParameter.magicpoints) {
if (!actor->_bonusParameter.givenNothing) {
_actor->giveExtraBonus(a);
Commit: 067722311fe248354ecbec5bfa60710463360b2f
https://github.com/scummvm/scummvm/commit/067722311fe248354ecbec5bfa60710463360b2f
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:39:48+02:00
Commit Message:
TWINE: fixed pitch handling for samples
see https://bugs.scummvm.org/ticket/15735
Changed paths:
engines/twine/audio/sound.cpp
diff --git a/engines/twine/audio/sound.cpp b/engines/twine/audio/sound.cpp
index 19a72209cfb..6dcf4d2e8a6 100644
--- a/engines/twine/audio/sound.cpp
+++ b/engines/twine/audio/sound.cpp
@@ -131,14 +131,13 @@ void Sound::playSample(int32 index, uint16 pitchbend, int32 repeat, int32 x, int
samplesPlayingActors[channelIdx] = -1;
}
- // TODO: implement pitchbend - see https://bugs.scummvm.org/ticket/15735
- // frequency would be 11025 + (pitchbend - 0x1000);
-
uint8 *sampPtr = _engine->_resources->_samplesTable[index];
uint32 sampSize = _engine->_resources->_samplesSizeTable[index];
Common::MemoryReadStream *stream = new Common::MemoryReadStream(sampPtr, sampSize, DisposeAfterUse::NO);
- Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, DisposeAfterUse::YES);
+ Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
playSample(channelIdx, index, audioStream, repeat, Resources::HQR_SAMPLES_FILE, Audio::Mixer::kSFXSoundType);
+ uint16 frequency = 11025 + (pitchbend - 0x1000);
+ _engine->_system->getMixer()->setChannelRate(samplesPlaying[channelIdx], frequency);
}
bool Sound::playVoxSample(const TextEntry *text) {
Commit: 9ca0e8ed64850059c902913bac8c244fee6a792b
https://github.com/scummvm/scummvm/commit/9ca0e8ed64850059c902913bac8c244fee6a792b
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2025-04-29T21:39:51+02:00
Commit Message:
TWINE: Fix compilation
Changed paths:
engines/twine/audio/sound.cpp
diff --git a/engines/twine/audio/sound.cpp b/engines/twine/audio/sound.cpp
index 6dcf4d2e8a6..cbac347ffb6 100644
--- a/engines/twine/audio/sound.cpp
+++ b/engines/twine/audio/sound.cpp
@@ -21,6 +21,7 @@
#include "twine/audio/sound.h"
#include "audio/audiostream.h"
+#include "audio/decoders/raw.h"
#include "audio/decoders/voc.h"
#include "common/config-manager.h"
#include "common/memstream.h"
Commit: 1b16313b96c9a5f5accf1852934c2780d1e18add
https://github.com/scummvm/scummvm/commit/1b16313b96c9a5f5accf1852934c2780d1e18add
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:40:55+02:00
Commit Message:
TWINE: the holomap rotation is slow and location interaction is weird
See issue https://bugs.scummvm.org/ticket/15409 and https://bugs.scummvm.org/ticket/12074
Changed paths:
engines/twine/holomap_v1.cpp
engines/twine/holomap_v1.h
engines/twine/text.h
diff --git a/engines/twine/holomap_v1.cpp b/engines/twine/holomap_v1.cpp
index 6daef4931ae..84ab8b9def6 100644
--- a/engines/twine/holomap_v1.cpp
+++ b/engines/twine/holomap_v1.cpp
@@ -690,10 +690,24 @@ void HolomapV1::holoMap() {
}
if (_dialstat) {
- _engine->_text->drawHolomapLocation(_listHoloPos[_current].mess);
+ _engine->_text->normalWinDial();
+ _engine->_text->setFontCrossColor(COLOR_WHITE);
+ _engine->_interface->box(_engine->_text->_dialTextBox, COLOR_BLACK);
+ _engine->saveFrontBuffer();
+ _engine->_text->commonOpenDial(_listHoloPos[_current].mess);
+ _engine->_text->initDialWindow();
+ _textState = ProgressiveTextState::ContinueRunning;
_dialstat = false;
}
+ if (_textState == ProgressiveTextState::ContinueRunning) {
+ _textState = _engine->_text->nextDialChar();
+ if (_textState != ProgressiveTextState::ContinueRunning) {
+ _engine->_text->fadeInRemainingChars();
+ _engine->_text->closeDial();
+ }
+ }
+
++_engine->timerRef;
debugC(3, kDebugLevels::kDebugTimers, "Holomap time: %i", _engine->timerRef);
diff --git a/engines/twine/holomap_v1.h b/engines/twine/holomap_v1.h
index 6c3f1671897..e003c6e59f8 100644
--- a/engines/twine/holomap_v1.h
+++ b/engines/twine/holomap_v1.h
@@ -24,6 +24,7 @@
#include "twine/holomap.h"
#include "twine/shared.h"
+#include "twine/text.h"
#define NUM_HOLOMAPCOLORS 32
#define HOLOMAP_PALETTE_INDEX (12*16)
@@ -111,6 +112,7 @@ public:
bool _flagredraw = false;
bool _dialstat = false;
bool _flagpal = false;
+ ProgressiveTextState _textState = ProgressiveTextState::End;
/**
* Set Holomap location position
diff --git a/engines/twine/text.h b/engines/twine/text.h
index 576ad826500..958efc69a2c 100644
--- a/engines/twine/text.h
+++ b/engines/twine/text.h
@@ -143,20 +143,20 @@ private:
/** Dialogue text buffer size for cross coloring dialogues */
int32 _nbDegrade = 0;
- // Dial_X1, Dial_Y1
- Common::Rect _dialTextBox { 0, 0, 0, 0};
-
int32 _maxLineDial = 0;
int32 _dialMaxSize = 0;
bool _isShiftJIS = false;
bool _isVisualRTL = false;
- bool displayText(TextId index, bool showText, bool playVox, bool loop); // MyDial
public:
Text(TwinEEngine *engine);
~Text();
+ // Dial_X1, Dial_Y1
+ Common::Rect _dialTextBox { 0, 0, 0, 0};
+ bool displayText(TextId index, bool showText, bool playVox, bool loop); // MyDial
+
static const int32 lineHeight = INTER_LINE;
bool _flagRunningDial = false;
Commit: 68e73536862950585ec5de17509f070890b73685
https://github.com/scummvm/scummvm/commit/68e73536862950585ec5de17509f070890b73685
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:44:22+02:00
Commit Message:
TWINE: The movement of the meca penguin is different from dos version
fixed issue 13731 (https://bugs.scummvm.org/ticket/13731)
Changed paths:
engines/twine/debugger/debugtools.cpp
engines/twine/parser/body.h
engines/twine/renderer/redraw.cpp
engines/twine/scene/actor.cpp
engines/twine/scene/actor.h
engines/twine/scene/animations.cpp
engines/twine/scene/collision.cpp
engines/twine/scene/gamestate.cpp
engines/twine/scene/movements.cpp
engines/twine/scene/scene.cpp
engines/twine/script/script_life.cpp
engines/twine/shared.h
diff --git a/engines/twine/debugger/debugtools.cpp b/engines/twine/debugger/debugtools.cpp
index b3ee08aafc6..4e7523e2b13 100644
--- a/engines/twine/debugger/debugtools.cpp
+++ b/engines/twine/debugger/debugtools.cpp
@@ -539,7 +539,7 @@ static void actorDetailsWindow(int &actorIdx, TwinEEngine *engine) {
ImGui::TableNextColumn();
ImGui::Text("Strength");
ImGui::TableNextColumn();
- ImGui::Text("%i", actor->_strengthOfHit);
+ ImGui::Text("%i", actor->_hitForce);
ImGui::TableNextColumn();
ImGui::Text("Hit by");
ImGui::TableNextColumn();
diff --git a/engines/twine/parser/body.h b/engines/twine/parser/body.h
index 76b10c7d49e..685d5eff664 100644
--- a/engines/twine/parser/body.h
+++ b/engines/twine/parser/body.h
@@ -32,6 +32,12 @@
namespace TwinE {
+/** Actors animation timer structure */
+struct AnimTimerDataStruct {
+ const KeyFrame *ptr = nullptr;
+ int32 time = 0; // keyframe time
+};
+
class BodyData : public Parser {
private:
void loadVertices(Common::SeekableReadStream &stream);
@@ -55,6 +61,7 @@ protected:
public:
bool animated = false;
+ AnimTimerDataStruct _animTimerData;
BoundingBox bbox;
int16 offsetToData = 0;
diff --git a/engines/twine/renderer/redraw.cpp b/engines/twine/renderer/redraw.cpp
index cfff95a7a80..084bb8f7bb3 100644
--- a/engines/twine/renderer/redraw.cpp
+++ b/engines/twine/renderer/redraw.cpp
@@ -30,6 +30,7 @@
#include "twine/input.h"
#include "twine/menu/interface.h"
#include "twine/menu/menu.h"
+#include "twine/parser/body.h"
#include "twine/parser/sprite.h"
#include "twine/renderer/renderer.h"
#include "twine/renderer/screens.h"
@@ -404,7 +405,8 @@ void Redraw::processDrawListActors(const DrawListStruct &drawCmd, bool flagflip)
ActorStruct *actor = _engine->_scene->getActor(actorIdx);
if (actor->_anim >= 0) {
const AnimData &animData = _engine->_resources->_animData[actor->_anim];
- _engine->_animations->setInterAnimObjet2(actor->_frame, animData, actor->_entityDataPtr->getBody(actor->_body), &actor->_animTimerData);
+ BodyData &bodyData = actor->_entityDataPtr->getBody(actor->_body);
+ _engine->_animations->setInterAnimObjet2(actor->_frame, animData, bodyData, &bodyData._animTimerData);
}
const IVec3 &delta = actor->posObj() - _engine->_grid->_worldCube;
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index ad3c67f46b6..61bc56a24ab 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -125,7 +125,7 @@ void Actor::setBehaviour(HeroBehaviourType behaviour) {
sceneHero->_genAnim = AnimationTypes::kAnimNone;
sceneHero->_flagAnim = AnimType::kAnimationTypeRepeat;
- _engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, OWN_ACTOR_SCENE_INDEX);
+ _engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, OWN_ACTOR_SCENE_INDEX);
}
void Actor::setFrame(int32 actorIdx, uint32 frame) {
@@ -207,7 +207,8 @@ void Actor::setFrame(int32 actorIdx, uint32 frame) {
void Actor::initSprite(int32 spriteNum, int32 actorIdx) {
ActorStruct *localActor = _engine->_scene->getActor(actorIdx);
- localActor->_sprite = spriteNum;
+ localActor->_sprite = spriteNum; // lba2
+
if (!localActor->_flags.bSprite3D) {
return;
}
@@ -240,25 +241,25 @@ int32 Actor::searchBody(BodyType bodyIdx, int32 actorIdx, ActorBoundingBox &acto
return (int)bodyIdx;
}
-void Actor::initBody(BodyType bodyIdx, int16 actorIdx) {
+void Actor::initBody(BodyType gennewbody, int16 actorIdx) {
ActorStruct *localActor = _engine->_scene->getActor(actorIdx);
if (localActor->_flags.bSprite3D) {
return;
}
- debug(1, "Load body %i for actor %i", (int)bodyIdx, actorIdx);
+ debug(1, "Load body %i for actor %i", (int)gennewbody, actorIdx);
- if (IS_HERO(actorIdx) && _heroBehaviour == HeroBehaviourType::kProtoPack && bodyIdx != BodyType::btTunic && bodyIdx != BodyType::btNormal) {
+ if (IS_HERO(actorIdx) && _heroBehaviour == HeroBehaviourType::kProtoPack && gennewbody != BodyType::btTunic && gennewbody != BodyType::btNormal) {
setBehaviour(HeroBehaviourType::kNormal);
}
ActorBoundingBox actorBoundingBox;
- const int32 newBody = searchBody(bodyIdx, actorIdx, actorBoundingBox);
+ const int32 newBody = searchBody(gennewbody, actorIdx, actorBoundingBox);
if (newBody == -1) {
localActor->_genBody = BodyType::btNone;
localActor->_body = -1;
localActor->_boundingBox = BoundingBox();
- debug("Failed to initialize body %i for actor %i", (int)bodyIdx, actorIdx);
+ debug("Failed to initialize body %i for actor %i", (int)gennewbody, actorIdx);
return;
}
@@ -268,7 +269,7 @@ void Actor::initBody(BodyType bodyIdx, int16 actorIdx) {
const int32 oldBody = localActor->_body;
localActor->_body = newBody;
- localActor->_genBody = bodyIdx;
+ localActor->_genBody = gennewbody;
if (actorBoundingBox.hasBoundingBox) {
localActor->_boundingBox = actorBoundingBox.bbox;
@@ -305,6 +306,8 @@ void Actor::copyInterAnim(const BodyData &src, BodyData &dest) {
return;
}
+ dest._animTimerData = src._animTimerData;
+
const int16 numBones = MIN<int16>((int16)src.getNumBones(), (int16)dest.getNumBones());
for (int16 i = 0; i < numBones; ++i) {
const BoneFrame *srcBoneFrame = src.getBoneState(i);
@@ -317,7 +320,7 @@ void Actor::startInitObj(int16 actorIdx) {
ActorStruct *actor = _engine->_scene->getActor(actorIdx);
if (actor->_flags.bSprite3D) {
- if (actor->_strengthOfHit != 0) {
+ if (actor->_hitForce != 0) {
actor->_workFlags.bIsHitting = 1;
}
@@ -340,7 +343,7 @@ void Actor::startInitObj(int16 actorIdx) {
actor->_flagAnim = AnimType::kAnimationTypeRepeat;
if (actor->_body != -1) {
- _engine->_animations->initAnim(actor->_genAnim, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(actor->_genAnim, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
}
_engine->_movements->initRealAngle(actor->_beta, actor->_beta, LBAAngles::ANGLE_0, &actor->realAngle);
@@ -393,9 +396,9 @@ void Actor::hitObj(int32 actorIdx, int32 actorIdxAttacked, int32 hitforce, int32
}
if (_engine->getRandomNumber() & 1) {
- _engine->_animations->initAnim(AnimationTypes::kHit2, AnimType::kAnimationInsert, AnimationTypes::kAnimInvalid, actorIdxAttacked);
+ _engine->_animations->initAnim(AnimationTypes::kHit2, AnimType::kAnimationInsert, AnimationTypes::kNoAnim, actorIdxAttacked);
} else {
- _engine->_animations->initAnim(AnimationTypes::kBigHit, AnimType::kAnimationInsert, AnimationTypes::kAnimInvalid, actorIdxAttacked);
+ _engine->_animations->initAnim(AnimationTypes::kBigHit, AnimType::kAnimationInsert, AnimationTypes::kNoAnim, actorIdxAttacked);
}
}
@@ -410,7 +413,7 @@ void Actor::hitObj(int32 actorIdx, int32 actorIdxAttacked, int32 hitforce, int32
actor->_lifePoint = 0;
}
} else {
- _engine->_animations->initAnim(AnimationTypes::kHit, AnimType::kAnimationInsert, AnimationTypes::kAnimInvalid, actorIdxAttacked);
+ _engine->_animations->initAnim(AnimationTypes::kHit, AnimType::kAnimationInsert, AnimationTypes::kNoAnim, actorIdxAttacked);
}
}
diff --git a/engines/twine/scene/actor.h b/engines/twine/scene/actor.h
index a806b4819e8..72e5d550dab 100644
--- a/engines/twine/scene/actor.h
+++ b/engines/twine/scene/actor.h
@@ -51,12 +51,6 @@ struct RealValue {
int16 getRealAngle(int32 time);
};
-/** Actors animation timer structure */
-struct AnimTimerDataStruct {
- const KeyFrame *ptr = nullptr;
- int32 time = 0;
-};
-
/** Actors static flags structure */
struct StaticFlagsStruct {
uint32 bComputeCollisionWithObj : 1; // 0x000001 CHECK_OBJ_COL
@@ -189,7 +183,7 @@ public:
int32 Fin;
} A3DS;
- int32 _strengthOfHit = 0;
+ int32 _hitForce = 0;
int32 _hitBy = -1;
BonusParameter _bonusParameter;
int32 _beta = 0; // facing angle of actor. Minumum is 0 (SW). Going counter clock wise
@@ -251,7 +245,6 @@ public:
BoundingBox _boundingBox; // Xmin, YMin, Zmin, Xmax, Ymax, Zmax
RealValue realAngle;
- AnimTimerDataStruct _animTimerData;
};
inline const IVec3 &ActorStruct::posObj() const {
diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index e5ef81e0449..44d335c7992 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -289,7 +289,7 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
switch (action.type) {
case ActionType::ACTION_HITTING:
if (action.animFrame - 1 == actor->_frame) {
- actor->_strengthOfHit = action.strength;
+ actor->_hitForce = action.strength;
actor->_workFlags.bIsHitting = 1;
}
break;
@@ -350,7 +350,7 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
break;
case ActionType::ACTION_HERO_HITTING:
if (action.animFrame - 1 == actor->_frame) {
- actor->_strengthOfHit = magicLevelStrengthOfHit[_engine->_gameState->_magicLevelIdx];
+ actor->_hitForce = magicLevelStrengthOfHit[_engine->_gameState->_magicLevelIdx];
actor->_workFlags.bIsHitting = 1;
}
break;
@@ -421,7 +421,7 @@ bool Animations::initAnim(AnimationTypes genNewAnim, AnimType flag, AnimationTyp
return true;
}
- if (genNextAnim == AnimationTypes::kAnimInvalid && actor->_flagAnim != AnimType::kAnimationAllThen) {
+ if (genNextAnim == AnimationTypes::kNoAnim && actor->_flagAnim != AnimType::kAnimationAllThen) {
genNextAnim = actor->_genAnim;
}
@@ -453,12 +453,13 @@ bool Animations::initAnim(AnimationTypes genNewAnim, AnimType flag, AnimationTyp
flag = AnimType::kAnimationAllThen;
}
+ BodyData &bodyData = actor->_entityDataPtr->getBody(actor->_body);
if (actor->_anim == -1) {
// if no previous animation
- setAnimObjet(0, _engine->_resources->_animData[newanim], actor->_entityDataPtr->getBody(actor->_body), &actor->_animTimerData);
+ setAnimObjet(0, _engine->_resources->_animData[newanim], bodyData, &bodyData._animTimerData);
} else {
// interpolation between animations
- stockInterAnim(actor->_entityDataPtr->getBody(actor->_body), &actor->_animTimerData);
+ stockInterAnim(bodyData, &bodyData._animTimerData);
}
actor->_anim = newanim;
@@ -494,7 +495,7 @@ void Animations::doAnim(int32 actorIdx) {
IVec3 &processActor = actor->_processActor;
if (actor->_flags.bSprite3D) {
- if (actor->_strengthOfHit) {
+ if (actor->_hitForce) {
actor->_workFlags.bIsHitting = 1;
}
@@ -585,8 +586,9 @@ void Animations::doAnim(int32 actorIdx) {
const AnimData &animData = _engine->_resources->_animData[actor->_anim];
bool keyFramePassed = false;
- if (actor->_entityDataPtr->getBody(actor->_body).isAnimated()) {
- keyFramePassed = setInterDepObjet(actor->_frame, animData, &actor->_animTimerData);
+ BodyData &bodyData = actor->_entityDataPtr->getBody(actor->_body);
+ if (bodyData.isAnimated()) {
+ keyFramePassed = setInterDepObjet(actor->_frame, animData, &bodyData._animTimerData);
}
if (_animMasterRot) {
@@ -636,7 +638,7 @@ void Animations::doAnim(int32 actorIdx) {
actor->_flagAnim = AnimType::kAnimationTypeRepeat;
actor->_frame = 0;
- actor->_strengthOfHit = 0;
+ actor->_hitForce = 0;
}
processAnimActions(actorIdx);
@@ -795,10 +797,10 @@ void Animations::doAnim(int32 actorIdx) {
if (fallHeight <= (2 * SIZE_BRICK_Y) && actor->_genAnim == AnimationTypes::kForward) {
actor->_workFlags.bWasWalkingBeforeFalling = 1;
} else {
- initAnim(AnimationTypes::kFall, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ initAnim(AnimationTypes::kFall, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
}
} else {
- initAnim(AnimationTypes::kFall, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ initAnim(AnimationTypes::kFall, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
}
}
}
diff --git a/engines/twine/scene/collision.cpp b/engines/twine/scene/collision.cpp
index 736205fc3a6..e12e7de8db9 100644
--- a/engines/twine/scene/collision.cpp
+++ b/engines/twine/scene/collision.cpp
@@ -328,7 +328,7 @@ int32 Collision::checkObjCol(int32 actorIdx) {
const IVec3 minsTest = actorTest->posObj() + actorTest->_boundingBox.mins;
const IVec3 maxsTest = actorTest->posObj() + actorTest->_boundingBox.maxs;
if (mins.x < maxsTest.x && maxs.x > minsTest.x && mins.y < maxsTest.y && maxs.y > minsTest.y && mins.z < maxsTest.z && maxs.z > minsTest.z) {
- _engine->_actor->hitObj(actorIdx, a, ptrobj->_strengthOfHit, ptrobj->_beta + LBAAngles::ANGLE_180);
+ _engine->_actor->hitObj(actorIdx, a, ptrobj->_hitForce, ptrobj->_beta + LBAAngles::ANGLE_180);
ptrobj->_workFlags.bIsHitting = 0;
}
}
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 3e61d50a99b..3dcb783f3f5 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -383,7 +383,7 @@ void GameState::doFoundObj(InventoryItems item) {
const int32 bodyAnimIdx = _engine->_animations->searchAnim(AnimationTypes::kFoundItem, OWN_ACTOR_SCENE_INDEX);
const AnimData &ptranim = _engine->_resources->_animData[bodyAnimIdx];
- _engine->_animations->stockInterAnim(bodyData, &_engine->_scene->_sceneHero->_animTimerData);
+ _engine->_animations->stockInterAnim(bodyData, &bodyData._animTimerData);
uint frameanim = 0;
diff --git a/engines/twine/scene/movements.cpp b/engines/twine/scene/movements.cpp
index 358d25852ab..40158bac237 100644
--- a/engines/twine/scene/movements.cpp
+++ b/engines/twine/scene/movements.cpp
@@ -285,7 +285,7 @@ void Movements::processBehaviourExecution(int actorIdx) {
}
break;
case HeroBehaviourType::kDiscrete:
- _engine->_animations->initAnim(AnimationTypes::kHide, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(AnimationTypes::kHide, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
break;
case HeroBehaviourType::kProtoPack:
case HeroBehaviourType::kMax:
@@ -333,7 +333,7 @@ void Movements::processManualMovementExecution(int actorIdx) {
// if walking should get stopped
if (!_engine->_input->isActionActive(TwinEActionType::MoveForward) && !_engine->_input->isActionActive(TwinEActionType::MoveBackward)) {
if (_lastJoyFlag && (_heroActionKey != _previousLoopActionKey || _changedCursorKeys != _previousChangedCursorKeys)) {
- _engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
}
}
@@ -341,17 +341,17 @@ void Movements::processManualMovementExecution(int actorIdx) {
if (_engine->_input->isActionActive(TwinEActionType::MoveForward)) {
if (!_engine->_scene->_flagClimbing) {
- _engine->_animations->initAnim(AnimationTypes::kForward, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(AnimationTypes::kForward, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
}
_lastJoyFlag = true;
} else if (_engine->_input->isActionActive(TwinEActionType::MoveBackward)) {
- _engine->_animations->initAnim(AnimationTypes::kBackward, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(AnimationTypes::kBackward, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
_lastJoyFlag = true;
}
if (_engine->_input->isActionActive(TwinEActionType::TurnLeft)) {
if (actor->_genAnim == AnimationTypes::kStanding) {
- _engine->_animations->initAnim(AnimationTypes::kTurnLeft, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(AnimationTypes::kTurnLeft, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
} else {
if (!actor->_workFlags.bIsRotationByAnim) {
actor->_beta = actor->realAngle.getRealAngle(_engine->timerRef);
@@ -360,7 +360,7 @@ void Movements::processManualMovementExecution(int actorIdx) {
_lastJoyFlag = true;
} else if (_engine->_input->isActionActive(TwinEActionType::TurnRight)) {
if (actor->_genAnim == AnimationTypes::kStanding) {
- _engine->_animations->initAnim(AnimationTypes::kTurnRight, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(AnimationTypes::kTurnRight, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
} else {
if (!actor->_workFlags.bIsRotationByAnim) {
actor->_beta = actor->realAngle.getRealAngle(_engine->timerRef);
@@ -433,11 +433,11 @@ void Movements::processRandomAction(int actorIdx) {
const int32 angle = ClampAngle(actor->_beta + (_engine->getRandomNumber() & (LBAAngles::ANGLE_180 - 1)) - LBAAngles::ANGLE_90 + LBAAngles::ANGLE_180);
initRealAngleConst(actor->_beta, angle, actor->_srot, &actor->realAngle);
actor->_delayInMillis = _engine->timerRef + _engine->getRandomNumber(_engine->toSeconds(6)) + _engine->toSeconds(6);
- _engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
}
if (!actor->realAngle.timeValue) {
- _engine->_animations->initAnim(AnimationTypes::kForward, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
+ _engine->_animations->initAnim(AnimationTypes::kForward, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx);
if (_engine->timerRef > actor->_delayInMillis) {
const int32 angle = ClampAngle(actor->_beta + (_engine->getRandomNumber() & (LBAAngles::ANGLE_180 - 1)) - LBAAngles::ANGLE_90);
initRealAngleConst(actor->_beta, angle, actor->_srot, &actor->realAngle);
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 018888eccc9..57009d82a5f 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -247,7 +247,7 @@ bool Scene::loadSceneLBA2() {
act->_posObj.y = (int16)stream.readUint16LE();
act->_posObj.z = (int16)stream.readUint16LE();
act->_oldPos = act->posObj();
- act->_strengthOfHit = stream.readByte();
+ act->_hitForce = stream.readByte();
setBonusParameterFlags(act, stream.readUint16LE());
act->_beta = (int16)stream.readUint16LE();
act->_srot = (int16)stream.readUint16LE();
@@ -381,7 +381,7 @@ bool Scene::loadSceneLBA1() {
act->_posObj.y = (int16)stream.readUint16LE();
act->_posObj.z = (int16)stream.readUint16LE();
act->_oldPos = act->posObj();
- act->_strengthOfHit = stream.readByte();
+ act->_hitForce = stream.readByte();
setBonusParameterFlags(act, stream.readUint16LE());
act->_bonusParameter.givenNothing = 0;
act->_beta = (int16)stream.readUint16LE();
@@ -866,7 +866,7 @@ void Scene::checkZoneSce(int32 actorIdx) {
if (actor->_posObj.y >= (zone->mins.y + zone->maxs.y) / 2) {
_engine->_animations->initAnim(AnimationTypes::kTopLadder, AnimType::kAnimationAllThen, AnimationTypes::kStanding, actorIdx); // reached end of ladder
} else {
- _engine->_animations->initAnim(AnimationTypes::kClimbLadder, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx); // go up in ladder
+ _engine->_animations->initAnim(AnimationTypes::kClimbLadder, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, actorIdx); // go up in ladder
}
}
}
diff --git a/engines/twine/script/script_life.cpp b/engines/twine/script/script_life.cpp
index f32db9c7a0a..4433ce8b733 100644
--- a/engines/twine/script/script_life.cpp
+++ b/engines/twine/script/script_life.cpp
@@ -926,7 +926,7 @@ int32 ScriptLife::lMESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
// if we are in sporty mode, we might have triggered a jump with the special action binding
// see https://bugs.scummvm.org/ticket/13676 for more details.
if (ctx.actor->isJumpAnimationActive()) {
- engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, OWN_ACTOR_SCENE_INDEX);
+ engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, OWN_ACTOR_SCENE_INDEX);
}
engine->_text->drawTextProgressive(textIdx);
@@ -1014,7 +1014,7 @@ int32 ScriptLife::lSET_BEHAVIOUR(TwinEEngine *engine, LifeScriptContext &ctx) {
const HeroBehaviourType behavior = (HeroBehaviourType)ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsLife, "LIFE::SET_BEHAVIOUR(%i)", (int)behavior);
- engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, OWN_ACTOR_SCENE_INDEX);
+ engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, AnimationTypes::kNoAnim, OWN_ACTOR_SCENE_INDEX);
engine->_actor->setBehaviour(behavior);
return 0;
diff --git a/engines/twine/shared.h b/engines/twine/shared.h
index 86c46c48aa4..cf67d9ed4e5 100644
--- a/engines/twine/shared.h
+++ b/engines/twine/shared.h
@@ -318,7 +318,7 @@ enum class AnimationTypes {
kCarDrivingBackwards = 305,
kCarStopping = 306,
kCarFrozen = 307,
- kAnimInvalid = 255 // NO_ANIM
+ kNoAnim = 255 // NO_ANIM
};
enum class AnimType {
Commit: 4ce8dbf73b91805b2ce437e1f5a199ea5f3ed807
https://github.com/scummvm/scummvm/commit/4ce8dbf73b91805b2ce437e1f5a199ea5f3ed807
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:44:27+02:00
Commit Message:
TWINE: fixed memory leak in fla sample handling
Changed paths:
engines/twine/audio/sound.cpp
diff --git a/engines/twine/audio/sound.cpp b/engines/twine/audio/sound.cpp
index cbac347ffb6..0119d177096 100644
--- a/engines/twine/audio/sound.cpp
+++ b/engines/twine/audio/sound.cpp
@@ -109,7 +109,7 @@ void Sound::playFlaSample(int32 index, int32 repeat, uint8 balance, int32 volume
}
Common::MemoryReadStream *stream = new Common::MemoryReadStream(sampPtr, sampSize, DisposeAfterUse::YES);
- Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, DisposeAfterUse::YES);
+ Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
playSample(channelIdx, index, audioStream, repeat, Resources::HQR_FLASAMP_FILE);
}
Commit: f0fa6416ec5968429c14471e99ddcc8a6c6a00ac
https://github.com/scummvm/scummvm/commit/f0fa6416ec5968429c14471e99ddcc8a6c6a00ac
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:44:31+02:00
Commit Message:
TWINE: fixed Audio::makeVOCStream call and fixed memory leak in vox samples
Changed paths:
engines/twine/audio/sound.cpp
diff --git a/engines/twine/audio/sound.cpp b/engines/twine/audio/sound.cpp
index 0119d177096..210d71ee1b2 100644
--- a/engines/twine/audio/sound.cpp
+++ b/engines/twine/audio/sound.cpp
@@ -183,7 +183,7 @@ bool Sound::playVoxSample(const TextEntry *text) {
*sampPtr = 'C';
}
Common::MemoryReadStream *stream = new Common::MemoryReadStream(sampPtr, sampSize, DisposeAfterUse::YES);
- Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, DisposeAfterUse::YES);
+ Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
return playSample(channelIdx, text->index, audioStream, 1, _engine->_text->_currentVoxBankFile.c_str(), Audio::Mixer::kSpeechSoundType);
}
Commit: 6defd5c324674e2306488d4ed9bf7122e8243226
https://github.com/scummvm/scummvm/commit/6defd5c324674e2306488d4ed9bf7122e8243226
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:44:35+02:00
Commit Message:
TWINE: fixed missing pitchbend parameter for environmental sounds
Changed paths:
engines/twine/audio/sound.cpp
engines/twine/scene/scene.cpp
diff --git a/engines/twine/audio/sound.cpp b/engines/twine/audio/sound.cpp
index 210d71ee1b2..09a6beaaf7b 100644
--- a/engines/twine/audio/sound.cpp
+++ b/engines/twine/audio/sound.cpp
@@ -192,6 +192,8 @@ bool Sound::playSample(int channelIdx, int index, Audio::SeekableAudioStream *au
warning("Failed to create audio stream for %s: %i", name, index);
return false;
}
+
+ // infinite loop
if (loop == -1) {
loop = 0;
}
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 57009d82a5f..7222c2db85b 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -736,10 +736,11 @@ void Scene::processEnvironmentSound() {
const int16 sampleIdx = _sampleAmbiance[currentAmb];
if (sampleIdx != -1) {
- /*int16 decal = _sampleRound[currentAmb];*/
+ int16 decal = _sampleRound[currentAmb];
int16 repeat = _sampleRepeat[currentAmb];
- _engine->_sound->playSample(sampleIdx, repeat, 110, -1, 110);
+ const uint16 pitchbend = 0x1000 + _engine->getRandomNumber(decal) - (decal / 2);
+ _engine->_sound->playSample(sampleIdx, pitchbend, repeat, 110, 110);
break;
}
}
Commit: 20d9634db0cda3ea3ad6536d294f366e9c7b38a6
https://github.com/scummvm/scummvm/commit/20d9634db0cda3ea3ad6536d294f366e9c7b38a6
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:45:18+02:00
Commit Message:
TWINE: started to support mixer balance changing for some samples
also renamed methods to match better the original sources
Changed paths:
engines/twine/audio/sound.cpp
engines/twine/audio/sound.h
engines/twine/movies.cpp
engines/twine/renderer/redraw.cpp
engines/twine/scene/actor.cpp
engines/twine/scene/animations.cpp
engines/twine/scene/extra.cpp
engines/twine/scene/gamestate.cpp
engines/twine/scene/scene.cpp
engines/twine/script/script_move.cpp
engines/twine/twine.cpp
diff --git a/engines/twine/audio/sound.cpp b/engines/twine/audio/sound.cpp
index 09a6beaaf7b..57f5b49c875 100644
--- a/engines/twine/audio/sound.cpp
+++ b/engines/twine/audio/sound.cpp
@@ -23,6 +23,7 @@
#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/voc.h"
+#include "audio/mixer.h"
#include "common/config-manager.h"
#include "common/memstream.h"
#include "common/system.h"
@@ -36,6 +37,7 @@
#include "twine/resources/hqr.h"
#include "twine/scene/movements.h"
#include "twine/resources/resources.h"
+#include "twine/shared.h"
#include "twine/text.h"
#include "twine/twine.h"
@@ -55,19 +57,37 @@ void Sound::startRainSample() {
#if 0
const int sample = SAMPLE_RAIN;
if (CubeMode == CUBE_EXTERIEUR && !TEMPETE_FINIE && !isSamplePlaying(sample)) {
- //const int frequency = 0x1000;
+ const int rate = 0x1000;
const int offset = 300;
const int repeat = 0;
const int panning = 64;
const int volumeRain = 70;
- // TODO: playSample(sample, /*frequency,*/ offset, repeat, panning, volumeRain);
+ // TODO: mixSample(sample, rate, offset, repeat, panning, volumeRain);
}
RestartRainSample = false;
#endif
}
-void Sound::setSamplePosition(int32 channelIdx, int32 x, int32 y, int32 z) {
+void Sound::setChannelRate(int32 channelIdx, uint32 rate) {
+ if (channelIdx < 0 || channelIdx >= NUM_CHANNELS) {
+ return;
+ }
+ _engine->_system->getMixer()->setChannelRate(_samplesPlaying[channelIdx], rate);
+}
+
+void Sound::setChannelBalance(int32 channelIdx, uint8 volumeLeft, uint8 volumeRight) {
+ if (channelIdx < 0 || channelIdx >= NUM_CHANNELS) {
+ return;
+ }
+ Audio::Mixer *mixer = _engine->_system->getMixer();
+ const Audio::SoundHandle &handle = _samplesPlaying[channelIdx];
+ // balance value ranges from -127 to 127
+ int8 balance = (int8)(((int16)volumeRight - (int16)volumeLeft) * 127 / 255);
+ mixer->setChannelBalance(handle, balance);
+}
+
+void Sound::setChannelPosition(int32 channelIdx, int32 x, int32 y, int32 z) {
if (channelIdx < 0 || channelIdx >= NUM_CHANNELS) {
return;
}
@@ -77,13 +97,13 @@ void Sound::setSamplePosition(int32 channelIdx, int32 x, int32 y, int32 z) {
int32 distance = getDistance3D(camX, camY, camZ, x, y, z);
distance = boundRuleThree(0, distance, 10000, 255);
byte targetVolume = 0;
- if (distance < 255) {
- targetVolume = 255 - distance;
+ if (distance < Audio::Mixer::kMaxChannelVolume) {
+ targetVolume = Audio::Mixer::kMaxChannelVolume - distance;
}
- _engine->_system->getMixer()->setChannelVolume(samplesPlaying[channelIdx], targetVolume);
+ _engine->_system->getMixer()->setChannelVolume(_samplesPlaying[channelIdx], targetVolume);
}
-void Sound::playFlaSample(int32 index, int32 repeat, uint8 balance, int32 volumeLeft, int32 volumeRight) {
+void Sound::playFlaSample(int32 index, int16 rate, int32 repeat, uint8 volumeLeft, uint8 volumeRight) {
if (!_engine->_cfgfile.Sound) {
return;
}
@@ -110,10 +130,19 @@ void Sound::playFlaSample(int32 index, int32 repeat, uint8 balance, int32 volume
Common::MemoryReadStream *stream = new Common::MemoryReadStream(sampPtr, sampSize, DisposeAfterUse::YES);
Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
- playSample(channelIdx, index, audioStream, repeat, Resources::HQR_FLASAMP_FILE);
+ if (playSample(channelIdx, index, audioStream, repeat, Resources::HQR_FLASAMP_FILE)) {
+ setChannelRate(channelIdx, rate);
+ setChannelBalance(channelIdx, volumeLeft, volumeRight);
+ }
+}
+
+void Sound::mixSample(int32 index, uint16 pitchbend, int32 repeat, uint8 volumeLeft, uint8 volumeRight) {
+ mixSample3D(index, pitchbend, repeat, {}, -1);
+ int channelIdx = getSampleChannel(index);
+ setChannelBalance(channelIdx, volumeLeft, volumeRight);
}
-void Sound::playSample(int32 index, uint16 pitchbend, int32 repeat, int32 x, int32 y, int32 z, int32 actorIdx) {
+void Sound::mixSample3D(int32 index, uint16 pitchbend, int32 repeat, const IVec3 &pos, int32 actorIdx) {
if (!_engine->_cfgfile.Sound) {
return;
}
@@ -125,11 +154,12 @@ void Sound::playSample(int32 index, uint16 pitchbend, int32 repeat, int32 x, int
}
if (actorIdx != -1) {
- setSamplePosition(channelIdx, x, y, z);
+ // TODO: implement balance
+ setChannelPosition(channelIdx, pos.x, pos.y, pos.z);
// save the actor index for the channel so we can check the position
- samplesPlayingActors[channelIdx] = actorIdx;
+ _samplesPlayingActors[channelIdx] = actorIdx;
} else {
- samplesPlayingActors[channelIdx] = -1;
+ _samplesPlayingActors[channelIdx] = -1;
}
uint8 *sampPtr = _engine->_resources->_samplesTable[index];
@@ -137,8 +167,8 @@ void Sound::playSample(int32 index, uint16 pitchbend, int32 repeat, int32 x, int
Common::MemoryReadStream *stream = new Common::MemoryReadStream(sampPtr, sampSize, DisposeAfterUse::NO);
Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
playSample(channelIdx, index, audioStream, repeat, Resources::HQR_SAMPLES_FILE, Audio::Mixer::kSFXSoundType);
- uint16 frequency = 11025 + (pitchbend - 0x1000);
- _engine->_system->getMixer()->setChannelRate(samplesPlaying[channelIdx], frequency);
+ uint32 rate = 11025 + (pitchbend - 0x1000);
+ setChannelRate(channelIdx, rate);
}
bool Sound::playVoxSample(const TextEntry *text) {
@@ -187,7 +217,7 @@ bool Sound::playVoxSample(const TextEntry *text) {
return playSample(channelIdx, text->index, audioStream, 1, _engine->_text->_currentVoxBankFile.c_str(), Audio::Mixer::kSpeechSoundType);
}
-bool Sound::playSample(int channelIdx, int index, Audio::SeekableAudioStream *audioStream, int32 loop, const char *name, Audio::Mixer::SoundType soundType) {
+bool Sound::playSample(int32 channelIdx, int32 index, Audio::SeekableAudioStream *audioStream, int32 loop, const char *name, Audio::Mixer::SoundType soundType) {
if (audioStream == nullptr) {
warning("Failed to create audio stream for %s: %i", name, index);
return false;
@@ -198,9 +228,8 @@ bool Sound::playSample(int channelIdx, int index, Audio::SeekableAudioStream *au
loop = 0;
}
Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(audioStream, loop);
- Audio::SoundHandle *handle = &samplesPlaying[channelIdx];
+ Audio::SoundHandle *handle = &_samplesPlaying[channelIdx];
const byte volume = Audio::Mixer::kMaxChannelVolume;
- // TODO: implement balance
_engine->_system->getMixer()->playStream(soundType, handle, loopStream, index, volume);
return true;
}
@@ -224,64 +253,64 @@ void Sound::stopSamples() { // HQ_StopSample
return;
}
- for (int i = 0; i < NUM_CHANNELS; i++) {
- _engine->_system->getMixer()->stopHandle(samplesPlaying[i]);
+ for (int channelIdx = 0; channelIdx < NUM_CHANNELS; channelIdx++) {
+ _engine->_system->getMixer()->stopHandle(_samplesPlaying[channelIdx]);
}
- memset(samplesPlayingActors, -1, sizeof(samplesPlayingActors));
+ memset(_samplesPlayingActors, -1, sizeof(_samplesPlayingActors));
}
-int32 Sound::getActorChannel(int32 index) {
- for (int32 c = 0; c < NUM_CHANNELS; c++) {
- if (samplesPlayingActors[c] == index) {
- return c;
+int32 Sound::getActorChannel(int32 actorIdx) {
+ for (int32 channelIdx = 0; channelIdx < NUM_CHANNELS; channelIdx++) {
+ if (_samplesPlayingActors[channelIdx] == actorIdx) {
+ return channelIdx;
}
}
return -1;
}
int32 Sound::getSampleChannel(int32 index) {
- for (int32 c = 0; c < NUM_CHANNELS; c++) {
- if (_engine->_system->getMixer()->getSoundID(samplesPlaying[c]) == index) {
- return c;
+ for (int32 channelIdx = 0; channelIdx < NUM_CHANNELS; channelIdx++) {
+ if (_engine->_system->getMixer()->getSoundID(_samplesPlaying[channelIdx]) == index) {
+ return channelIdx;
}
}
return -1;
}
-void Sound::removeSampleChannel(int32 c) {
- samplesPlayingActors[c] = -1;
+void Sound::removeChannelWatch(int32 channelIdx) {
+ _samplesPlayingActors[channelIdx] = -1;
}
void Sound::stopSample(int32 index) {
if (!_engine->_cfgfile.Sound) {
return;
}
- const int32 stopChannel = getSampleChannel(index);
- if (stopChannel != -1) {
+ const int32 channelIdx = getSampleChannel(index);
+ if (channelIdx != -1) {
_engine->_system->getMixer()->stopID(index);
- removeSampleChannel(stopChannel);
+ removeChannelWatch(channelIdx);
}
}
-bool Sound::isChannelPlaying(int32 chan) {
- if (chan >= 0 && chan < ARRAYSIZE(samplesPlaying)) {
- if (_engine->_system->getMixer()->isSoundHandleActive(samplesPlaying[chan])) {
+bool Sound::isChannelPlaying(int32 channelIdx) {
+ if (channelIdx >= 0 && channelIdx < ARRAYSIZE(_samplesPlaying)) {
+ if (_engine->_system->getMixer()->isSoundHandleActive(_samplesPlaying[channelIdx])) {
return true;
}
- removeSampleChannel(chan);
+ removeChannelWatch(channelIdx);
}
return false;
}
int32 Sound::isSamplePlaying(int32 index) {
- const int32 chan = getSampleChannel(index);
- return isChannelPlaying(chan);
+ const int32 channelIdx = getSampleChannel(index);
+ return isChannelPlaying(channelIdx);
}
int32 Sound::getFreeSampleChannelIndex() {
- for (int i = 0; i < NUM_CHANNELS; i++) {
- if (!_engine->_system->getMixer()->isSoundHandleActive(samplesPlaying[i])) {
- return i;
+ for (int channelIdx = 0; channelIdx < NUM_CHANNELS; channelIdx++) {
+ if (!_engine->_system->getMixer()->isSoundHandleActive(_samplesPlaying[channelIdx])) {
+ return channelIdx;
}
}
return -1;
diff --git a/engines/twine/audio/sound.h b/engines/twine/audio/sound.h
index 3db1bd056f2..21172090dc0 100644
--- a/engines/twine/audio/sound.h
+++ b/engines/twine/audio/sound.h
@@ -54,56 +54,57 @@ class Sound {
private:
TwinEEngine *_engine;
- /** Get the channel where the sample is playing */
- int32 getSampleChannel(int32 index);
-
/** Samples playing at the same time */
- Audio::SoundHandle samplesPlaying[NUM_CHANNELS];
+ Audio::SoundHandle _samplesPlaying[NUM_CHANNELS];
/** Samples playing at a actors position */
- int32 samplesPlayingActors[NUM_CHANNELS]{0};
+ int32 _samplesPlayingActors[NUM_CHANNELS]{0};
- bool playSample(int channelIdx, int index, Audio::SeekableAudioStream *audioStream, int32 loop, const char *name, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
+ bool playSample(int32 channelIdx, int32 index, Audio::SeekableAudioStream *audioStream, int32 loop, const char *name, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
- bool isChannelPlaying(int32 channel);
+ bool isChannelPlaying(int32 channelIdx);
/** Find a free channel slot to use */
int32 getFreeSampleChannelIndex();
/** Remove a sample from the channel usage list */
- void removeSampleChannel(int32 index);
-
+ void removeChannelWatch(int32 channelIdx);
public:
Sound(TwinEEngine *engine);
~Sound();
+ /** Get the channel where the sample is playing */
+ int32 getSampleChannel(int32 index);
+
/**
* Play FLA movie samples
* @param index sample index under flasamp.hqr file
* @param repeat number of times to repeat the sample
*/
- void playFlaSample(int32 index, int32 repeat, uint8 balance, int32 volumeLeft, int32 volumeRight);
+ void playFlaSample(int32 index, int16 rate, int32 repeat, uint8 volumeLeft, uint8 volumeRight);
+
+ void setChannelBalance(int32 channelIdx, uint8 volumeLeft, uint8 volumeRight);
+
+ void setChannelRate(int32 channelIdx, uint32 rate);
/** Update sample position in channel */
- void setSamplePosition(int32 channelIdx, int32 x, int32 y, int32 z);
+ void setChannelPosition(int32 channelIdx, int32 x, int32 y, int32 z);
- inline void setSamplePosition(int32 channelIdx, const IVec3 &pos) {
- setSamplePosition(channelIdx, pos.x, pos.y, pos.z);
+ inline void setChannelPosition(int32 channelIdx, const IVec3 &pos) {
+ setChannelPosition(channelIdx, pos.x, pos.y, pos.z);
}
/**
* Play samples
* @param index sample index under flasamp.hqr file
* @param repeat number of times to repeat the sample
- * @param x sound generating entity x position
- * @param y sound generating entity y position
- * @param z sound generating entity z position
+ * @param pos sound generating entity position
* @param actorIdx
*/
- void playSample(int32 index, uint16 pitchbend = 0x1000, int32 repeat = 1, int32 x = 128, int32 y = 128, int32 z = 128, int32 actorIdx = -1); // HQ_3D_MixSample
- void playSample(int32 index, uint16 pitchbend, int32 repeat, const IVec3 &pos, int32 actorIdx = -1) { // HQ_MixSample
- playSample(index, pitchbend, repeat, pos.x, pos.y, pos.z, actorIdx);
- }
+ void mixSample3D(int32 index, uint16 pitchbend, int32 repeat, const IVec3 &pos, int32 actorIdx); // HQ_3D_MixSample
+
+ void mixSample(int32 index, uint16 pitchbend, int32 repeat, uint8 volumeLeft, uint8 volumeRight); // HQ_MixSample
+
/** Pause samples */
void pauseSamples();
@@ -116,13 +117,13 @@ public:
void stopSamples();
/** Get the channel where the actor sample is playing */
- int32 getActorChannel(int32 index);
+ int32 getActorChannel(int32 actorIdx);
/** Stops a specific sample */
void stopSample(int32 index); // HQ_StopOneSample
/** Check if a sample is playing */
- int32 isSamplePlaying(int32 index); // IsSamplePlaying
+ int32 isSamplePlaying(int32 index);
/** Play VOX sample */
bool playVoxSample(const TextEntry *text);
diff --git a/engines/twine/movies.cpp b/engines/twine/movies.cpp
index 547e3b8c5bd..b566b923759 100644
--- a/engines/twine/movies.cpp
+++ b/engines/twine/movies.cpp
@@ -234,7 +234,7 @@ void Movies::drawNextFrameFla() {
sample.balance = stream.readByte();
sample.volumeLeft = stream.readByte();
sample.volumeRight = stream.readByte();
- _engine->_sound->playFlaSample(sample.sampleNum, sample.repeat, sample.balance, sample.volumeLeft, sample.volumeRight);
+ _engine->_sound->playFlaSample(sample.sampleNum, sample.freq, sample.repeat, sample.volumeLeft, sample.volumeRight);
break;
}
case kStopSample: {
@@ -276,13 +276,14 @@ void Movies::drawNextFrameFla() {
break;
}
case kSampleBalance: {
- /* int16 num = */ stream.readSint16LE();
- /* uint8 offset = */ stream.readByte();
+ const int16 sampleNum = stream.readSint16LE();
+ /* const uint8 offset = */ stream.readByte();
stream.skip(1); // padding
- /* int16 balance = */ stream.readSint16LE();
- /* uint8 volumeLeft = */ stream.readByte();
- /* uint8 volumeRight = */ stream.readByte();
- // TODO: change balance
+ /* const int16 balance = */ stream.readSint16LE();
+ const uint8 volumeLeft = stream.readByte();
+ const uint8 volumeRight = stream.readByte();
+ const int32 channelIdx = _engine->_sound->getSampleChannel(sampleNum);
+ _engine->_sound->setChannelBalance(channelIdx, volumeLeft, volumeRight);
break;
}
default: {
diff --git a/engines/twine/renderer/redraw.cpp b/engines/twine/renderer/redraw.cpp
index 084bb8f7bb3..39c172164da 100644
--- a/engines/twine/renderer/redraw.cpp
+++ b/engines/twine/renderer/redraw.cpp
@@ -333,7 +333,7 @@ int32 Redraw::fillExtraDrawingList(DrawListStruct *drawList, int32 drawListPos)
if (_engine->timerRef - extra->spawnTime > 35) {
extra->spawnTime = _engine->timerRef;
extra->type &= ~ExtraType::TIME_IN;
- _engine->_sound->playSample(Samples::ItemPopup, 0x1000, 1, extra->pos);
+ _engine->_sound->mixSample3D(Samples::ItemPopup, 0x1000, 1, extra->pos, -1);
}
continue;
}
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index 61bc56a24ab..f5a12edbac8 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -439,13 +439,13 @@ void Actor::giveExtraBonus(int32 actorIdx) {
}
if (actor->_workFlags.bIsDead) {
_engine->_extra->addExtraBonus(actor->posObj(), LBAAngles::ANGLE_90, LBAAngles::ANGLE_0, bonusSprite, actor->_bonusAmount);
- _engine->_sound->playSample(Samples::ItemPopup, 0x1000, 1, actor->posObj(), actorIdx);
+ _engine->_sound->mixSample3D(Samples::ItemPopup, 0x1000, 1, actor->posObj(), actorIdx);
} else {
const ActorStruct *sceneHero = _engine->_scene->_sceneHero;
const int32 angle = _engine->_movements->getAngle(actor->posObj(), sceneHero->posObj());
const IVec3 pos(actor->_posObj.x, actor->_posObj.y + actor->_boundingBox.maxs.y, actor->_posObj.z);
_engine->_extra->addExtraBonus(pos, LBAAngles::ANGLE_70, angle, bonusSprite, actor->_bonusAmount);
- _engine->_sound->playSample(Samples::ItemPopup, 0x1000, 1, pos, actorIdx);
+ _engine->_sound->mixSample3D(Samples::ItemPopup, 0x1000, 1, pos, actorIdx);
}
}
diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 44d335c7992..f8950a8483d 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -295,13 +295,13 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
break;
case ActionType::ACTION_SAMPLE:
if (action.animFrame == actor->_frame) {
- _engine->_sound->playSample(action.sampleIndex, 0x1000, 1, actor->posObj(), actorIdx);
+ _engine->_sound->mixSample3D(action.sampleIndex, 0x1000, 1, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_SAMPLE_FREQ:
if (action.animFrame == actor->_frame) {
const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(action.frequency) - (action.frequency / 2);
- _engine->_sound->playSample(action.sampleIndex, pitchBend, 1, actor->posObj(), actorIdx);
+ _engine->_sound->mixSample3D(action.sampleIndex, pitchBend, 1, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_THROW_EXTRA_BONUS:
@@ -316,7 +316,7 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
break;
case ActionType::ACTION_SAMPLE_REPEAT:
if (action.animFrame == actor->_frame) {
- _engine->_sound->playSample(action.sampleIndex, 0x1000, action.repeat, actor->posObj(), actorIdx);
+ _engine->_sound->mixSample3D(action.sampleIndex, 0x1000, action.repeat, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_THROW_SEARCH:
@@ -338,14 +338,14 @@ void Animations::processAnimActions(int32 actorIdx) { // GereAnimAction
if (action.animFrame == actor->_frame && (actor->_brickSound & 0xF0U) != 0xF0U) {
const int16 sampleIdx = (actor->_brickSound & 0x0FU) + Samples::WalkFloorBegin;
const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(1000) - 500;
- _engine->_sound->playSample(sampleIdx, pitchBend, 1, actor->posObj(), actorIdx);
+ _engine->_sound->mixSample3D(sampleIdx, pitchBend, 1, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_RIGHT_STEP:
if (action.animFrame == actor->_frame && (actor->_brickSound & 0xF0U) != 0xF0U) {
const int16 sampleIdx = (actor->_brickSound & 0x0FU) + Samples::WalkFloorRightBegin;
const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(1000) - 500;
- _engine->_sound->playSample(sampleIdx, pitchBend, 1, actor->posObj(), actorIdx);
+ _engine->_sound->mixSample3D(sampleIdx, pitchBend, 1, actor->posObj(), actorIdx);
}
break;
case ActionType::ACTION_HERO_HITTING:
diff --git a/engines/twine/scene/extra.cpp b/engines/twine/scene/extra.cpp
index 32631a1cb52..0b93bd2c3b4 100644
--- a/engines/twine/scene/extra.cpp
+++ b/engines/twine/scene/extra.cpp
@@ -610,7 +610,7 @@ void Extra::gereExtras() {
const int32 angle = ClampAngle(tmpAngle - extra->angle);
if (angle > LBAAngles::ANGLE_140 && angle < LBAAngles::ANGLE_210) {
- _engine->_sound->playSample(Samples::ItemFound, 0x1000, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
+ _engine->_sound->mixSample3D(Samples::ItemFound, 0x1000, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
if (extraKey->info1 > 1) {
const IVec3 &projPos = _engine->_renderer->projectPoint(extraKey->pos - _engine->_grid->_worldCube);
@@ -643,7 +643,7 @@ void Extra::gereExtras() {
_engine->_movements->initRealValue(LBAAngles::ANGLE_0, extra->destPos.z, LBAAngles::ANGLE_17, &extra->trackActorMove);
if (extraIdx == _engine->_collision->extraCheckExtraCol(extra, _engine->_gameState->_magicBall)) {
- _engine->_sound->playSample(Samples::ItemFound, 0x1000, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
+ _engine->_sound->mixSample3D(Samples::ItemFound, 0x1000, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
if (extraKey->info1 > 1) {
const IVec3 &projPos = _engine->_renderer->projectPoint(extraKey->pos - _engine->_grid->_worldCube);
@@ -721,7 +721,7 @@ void Extra::gereExtras() {
// if extra is magic ball
if (i == _engine->_gameState->_magicBall) {
const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(300) - 150;
- _engine->_sound->playSample(Samples::Hit, pitchBend, 1, extra->pos);
+ _engine->_sound->mixSample3D(Samples::Hit, pitchBend, 1, extra->pos, -1);
// can't bounce with not magic points
if (_engine->_gameState->_magicBallType <= 0) {
@@ -792,7 +792,7 @@ void Extra::gereExtras() {
if ((extra->type & ExtraType::TAKABLE) && !(extra->type & ExtraType::FLY)) {
// if hero touch extra
if (_engine->_collision->extraCheckObjCol(extra, -1) == 0) {
- _engine->_sound->playSample(Samples::ItemFound, 0x1000, 1, extra->pos);
+ _engine->_sound->mixSample3D(Samples::ItemFound, 0x1000, 1, extra->pos, -1);
if (extra->info1 > 1) {
const IVec3 &projPos = _engine->_renderer->projectPoint(extra->pos - _engine->_grid->_worldCube);
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 3dcb783f3f5..9d22bd4248a 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -366,7 +366,7 @@ void GameState::doFoundObj(InventoryItems item) {
const int32 boxBottomRightX = projPos.x + (SIZE_FOUND_OBJ / 2);
const int32 boxBottomRightY = projPos.y + (SIZE_FOUND_OBJ / 2);
const Common::Rect boxRect(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
- _engine->_sound->playSample(Samples::BigItemFound);
+ _engine->_sound->mixSample(Samples::BigItemFound, 0x1000, 1, 128, 128);
// process vox play
_engine->_music->stopMusic();
@@ -543,7 +543,8 @@ void GameState::processGameoverAnimation() {
debugC(3, kDebugLevels::kDebugTimers, "GameOver time: %i", _engine->timerRef);
}
- _engine->_sound->playSample(Samples::Explode);
+ const uint16 pitchBend = 0x1000 + _engine->getRandomNumber(2000) - (2000 / 2);
+ _engine->_sound->mixSample(Samples::Explode, pitchBend, 1, 128, 128);
_engine->blitWorkToFront(rect);
_engine->_renderer->setFollowCamera(0, 0, 0, 0, 0, 0, zoom);
_engine->_renderer->affObjetIso(0, 0, 0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, gameOverPtr, dummy);
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 7222c2db85b..768d1e55b0d 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -740,7 +740,7 @@ void Scene::processEnvironmentSound() {
int16 repeat = _sampleRepeat[currentAmb];
const uint16 pitchbend = 0x1000 + _engine->getRandomNumber(decal) - (decal / 2);
- _engine->_sound->playSample(sampleIdx, pitchbend, repeat, 110, 110);
+ _engine->_sound->mixSample(sampleIdx, pitchbend, repeat, 110, 110);
break;
}
}
diff --git a/engines/twine/script/script_move.cpp b/engines/twine/script/script_move.cpp
index 8737bbb00d7..d1a09a12f49 100644
--- a/engines/twine/script/script_move.cpp
+++ b/engines/twine/script/script_move.cpp
@@ -280,7 +280,7 @@ int32 ScriptMove::mWAIT_NUM_ANIM(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 ScriptMove::mSAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE(%i)", (int)sampleIdx);
- engine->_sound->playSample(sampleIdx, 0x1000, 1, ctx.actor->posObj(), ctx.actorIdx);
+ engine->_sound->mixSample3D(sampleIdx, 0x1000, 1, ctx.actor->posObj(), ctx.actorIdx);
return 0;
}
@@ -492,7 +492,7 @@ int32 ScriptMove::mSAMPLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE_RND(%i)", (int)sampleIdx);
const uint16 pitchbend = 0x800 + engine->getRandomNumber(0x800);
- engine->_sound->playSample(sampleIdx, pitchbend, 1, ctx.actor->posObj(), ctx.actorIdx);
+ engine->_sound->mixSample3D(sampleIdx, pitchbend, 1, ctx.actor->posObj(), ctx.actorIdx);
return 0;
}
@@ -504,7 +504,7 @@ int32 ScriptMove::mSAMPLE_ALWAYS(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE_ALWAYS(%i)", (int)sampleIdx);
if (!engine->_sound->isSamplePlaying(sampleIdx)) { // if its not playing
- engine->_sound->playSample(sampleIdx, 0x1000, 0, ctx.actor->posObj(), ctx.actorIdx);
+ engine->_sound->mixSample3D(sampleIdx, 0x1000, 0, ctx.actor->posObj(), ctx.actorIdx);
}
return 0;
}
@@ -565,7 +565,7 @@ int32 ScriptMove::mREPEAT_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 ScriptMove::mSIMPLE_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SIMPLE_SAMPLE(%i)", (int)sampleIdx);
- engine->_sound->playSample(sampleIdx, 0x1000, ctx.bigSampleRepeat, ctx.actor->posObj(), ctx.actorIdx);
+ engine->_sound->mixSample(sampleIdx, 0x1000, ctx.bigSampleRepeat, 128, 128);
ctx.bigSampleRepeat = 1;
return 0;
}
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 06509cbb91e..bbc2d3342c9 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -735,7 +735,7 @@ void TwinEEngine::restoreTimer() {
void TwinEEngine::processActorSamplePosition(int32 actorIdx) {
const ActorStruct *actor = _scene->getActor(actorIdx);
const int32 channelIdx = _sound->getActorChannel(actorIdx);
- _sound->setSamplePosition(channelIdx, actor->posObj());
+ _sound->setChannelPosition(channelIdx, actor->posObj());
}
void TwinEEngine::processBookOfBu() {
@@ -1097,7 +1097,7 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
#endif
} else {
const uint16 pitchBend = 0x1000 + getRandomNumber(2000) - (2000 / 2);
- _sound->playSample(Samples::Explode, pitchBend, 1, actor->posObj(), a);
+ _sound->mixSample3D(Samples::Explode, pitchBend, 1, actor->posObj(), a);
if (a == _scene->_mecaPenguinIdx) {
_extra->extraExplo(actor->posObj());
@@ -1162,7 +1162,7 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
}
} else {
const uint16 pitchBend = 0x1000 + getRandomNumber(2000) - (2000 / 2);
- _sound->playSample(Samples::Explode, pitchBend, 1, actor->posObj(), a);
+ _sound->mixSample3D(Samples::Explode, pitchBend, 1, actor->posObj(), a);
if (actor->_bonusParameter.cloverleaf || actor->_bonusParameter.kashes || actor->_bonusParameter.key || actor->_bonusParameter.lifepoints || actor->_bonusParameter.magicpoints) {
if (!actor->_bonusParameter.givenNothing) {
_actor->giveExtraBonus(a);
Commit: a8930572186fa7d9fef2fc48e983898912265fd6
https://github.com/scummvm/scummvm/commit/a8930572186fa7d9fef2fc48e983898912265fd6
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2025-04-29T21:45:49+02:00
Commit Message:
TWINE: Skipping the text intro with Escape also skips the subsequent FMV
fixes 15734 (https://bugs.scummvm.org/ticket/15734)
Changed paths:
engines/twine/twine.cpp
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index bbc2d3342c9..61bc2e1ae68 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -649,12 +649,10 @@ void TwinEEngine::introduction() {
}
}
- if (!abort) {
- if (isLBA1()) {
- _movie->playMovie(FLA_DRAGON3);
- } else {
- _movie->playMovie("INTRO");
- }
+ if (isLBA1()) {
+ _movie->playMovie(FLA_DRAGON3);
+ } else {
+ _movie->playMovie("INTRO");
}
}
More information about the Scummvm-git-logs
mailing list