[Scummvm-git-logs] scummvm master -> ffb1dc3610960eb4cf7623ab8361a67395866cc4
Die4Ever
30947252+Die4Ever at users.noreply.github.com
Thu Oct 28 00:10:13 UTC 2021
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
ffb1dc3610 GROOVIE: T11H Pente AI puzzle
Commit: ffb1dc3610960eb4cf7623ab8361a67395866cc4
https://github.com/scummvm/scummvm/commit/ffb1dc3610960eb4cf7623ab8361a67395866cc4
Author: Die4Ever (die4ever2005 at gmail.com)
Date: 2021-10-27T19:09:49-05:00
Commit Message:
GROOVIE: T11H Pente AI puzzle
Changed paths:
engines/groovie/logic/cake.cpp
engines/groovie/logic/pente.cpp
engines/groovie/logic/pente.h
engines/groovie/logic/triangle.cpp
engines/groovie/script.cpp
engines/groovie/script.h
engines/groovie/video/roq.cpp
engines/groovie/video/roq.h
diff --git a/engines/groovie/logic/cake.cpp b/engines/groovie/logic/cake.cpp
index 3bef335066..d87642bb87 100644
--- a/engines/groovie/logic/cake.cpp
+++ b/engines/groovie/logic/cake.cpp
@@ -321,6 +321,7 @@ byte CakeGame::aiGetBestMove(int search_depth) {
void CakeGame::testCake() {
warning("starting CakeGame::testCake()");
+ uint32 oldSeed = _random.getSeed();
// test the draw condition, grouped by column
runCakeTestNoAi(/*move 1*/ "7777777" /*8*/ "6666666" /*15*/ "5555555" /*22*/ "34444444" /*30*/ "333333" /*36*/ "2222222" /*43*/ "01111111" /*51*/ "000000", false, true);
@@ -328,6 +329,7 @@ void CakeGame::testCake() {
runCakeTest(1, "232232432445", false);
runCakeTest(123, "4453766355133466", false);
+ _random.setSeed(oldSeed);
warning("finished CakeGame::testCake()");
}
diff --git a/engines/groovie/logic/pente.cpp b/engines/groovie/logic/pente.cpp
index f0fb6dbb4f..6ee7a7b6c5 100644
--- a/engines/groovie/logic/pente.cpp
+++ b/engines/groovie/logic/pente.cpp
@@ -20,17 +20,1009 @@
*
*/
+#include <limits.h>
#include "groovie/groovie.h"
#include "groovie/logic/pente.h"
+#include "common/stack.h"
namespace Groovie {
+const uint WIN_SCORE = 100000000;
+const uint CAPTURE_SCORE = 1000000;
+
+struct pentePlayerTable {
+ Common::FixedStack<int, 813> lines;
+};
+
+struct penteTable {
+ pentePlayerTable player;
+ pentePlayerTable stauf;
+ uint playerScore;
+ uint staufScore;
+ byte playerLines;
+ byte staufLines;
+ byte width;
+ byte height;
+ uint16 boardSize;
+ byte lineLength;
+ uint16 moveCounter;
+ byte boardState[20][15];
+ uint16 linesCounter;
+ uint16 linesTable[20][15][21];
+ byte numAdjacentPieces[20][15];
+ byte calcTouchingPieces;// the deepest level of AI recursion sets this to 0, and then sets it back to 1 when returning
+};
+
+
+void PenteGame::penteSub02Frees(penteTable *table)
+{
+ delete table;
+}
+
+
+void PenteGame::penteSub05BuildLookupTable(penteTable *table)
+{
+ uint16 *puVar1;
+ uint _width;
+ uint uVar4;
+ uint uVar5;
+ byte bVar6;
+ byte local_14;
+ byte local_13;
+ uint16 lines_counter;
+ byte height;
+ byte line_length;
+ byte width;
+
+ width = table->width;
+ height = table->height;
+ bVar6 = 0;
+ lines_counter = 0;
+ line_length = table->lineLength;
+ _width = (uint)width;
+
+ auto &lines_table = table->linesTable;
+ local_14 = 0;
+ if (height != 0) {
+ do {
+ local_13 = 0;
+ if (-1 < (int)(_width - line_length)) {
+ do {
+ bVar6 = 0;
+ if (line_length != 0) {
+ do {
+ uVar4 = (uint)bVar6;
+ bVar6 += 1;
+ puVar1 = lines_table[uVar4 + local_13][local_14];
+ *puVar1 = *puVar1 + 1;
+ puVar1 = lines_table[uVar4 + local_13][local_14];
+ puVar1[*puVar1] = lines_counter;
+ } while (bVar6 < line_length);
+ }
+ lines_counter += 1;
+ local_13 += 1;
+ } while ((int)(uint)local_13 <= (int)(_width - line_length));
+ }
+ local_14 += 1;
+ } while (local_14 < height);
+ }
+ local_13 = 0;
+ if (width != 0) {
+ do {
+ local_14 = 0;
+ if (-1 < (int)((uint)height - (uint)line_length)) {
+ do {
+ if (line_length != 0) {
+ uVar4 = 0;
+ do {
+ bVar6 = (char)uVar4 + 1;
+ puVar1 = lines_table[local_13][uVar4 + local_14];
+ *puVar1 = *puVar1 + 1;
+ puVar1 = lines_table[local_13][uVar4 + local_14];
+ puVar1[*puVar1] = lines_counter;
+ uVar4 = (uint)bVar6;
+ } while (bVar6 < line_length);
+ }
+ lines_counter += 1;
+ local_14 += 1;
+ } while ((int)(uint)local_14 <= (int)((uint)height - (uint)line_length));
+ }
+ local_13 += 1;
+ } while (local_13 < width);
+ }
+ local_14 = 0;
+ uVar4 = (uint)line_length;
+ if (-1 < (int)(height - uVar4)) {
+ do {
+ local_13 = 0;
+ if (-1 < (int)(_width - uVar4)) {
+ do {
+ if (line_length != 0) {
+ uVar5 = 0;
+ do {
+ width = (char)uVar5 + 1;
+ puVar1 = lines_table[local_13 + uVar5][uVar5 + local_14];
+ *puVar1 = *puVar1 + 1;
+ puVar1 = lines_table[local_13 + uVar5][uVar5 + local_14];
+ puVar1[*puVar1] = lines_counter;
+ uVar5 = (uint)width;
+ } while (width < line_length);
+ }
+ lines_counter += 1;
+ local_13 += 1;
+ } while ((int)(uint)local_13 <= (int)(_width - uVar4));
+ }
+ local_14 += 1;
+ } while ((int)(uint)local_14 <= (int)(height - uVar4));
+ }
+ local_14 = line_length - 1;
+ if (local_14 < height) {
+ do {
+ local_13 = 0;
+ if (-1 < (int)(_width - uVar4)) {
+ do {
+ if (line_length != 0) {
+ uVar5 = 0;
+ do {
+ width = (char)uVar5 + 1;
+ puVar1 = lines_table[local_13 + uVar5][local_14 - uVar5];
+ *puVar1 = *puVar1 + 1;
+ puVar1 = lines_table[local_13 + uVar5][local_14 - uVar5];
+ puVar1[*puVar1] = lines_counter;
+ uVar5 = (uint)width;
+ } while (width < line_length);
+ }
+ lines_counter += 1;
+ local_13 += 1;
+ } while ((int)(uint)local_13 <= (int)(_width - uVar4));
+ }
+ local_14 += 1;
+ } while (local_14 < height);
+ }
+ table->linesCounter = lines_counter;
+}
+
+
+
+
+penteTable *PenteGame::penteSub01Init(byte width, byte height, byte length)
+{
+ penteTable *table;
+ byte bVar5;
+ uint16 _height;
+
+ table = new penteTable();
+ table->width = width;
+ table->height = height;
+ _height = (uint16)height;
+ table->boardSize = _height * width;
+ bVar5 = 0;
+ table->lineLength = length;
+ memset(table->boardState, 0, sizeof(table->boardState));
+
+ penteSub05BuildLookupTable(table);
+ assert(table->linesCounter == 812);
+
+ bVar5 = 0;
+ table->staufScore = (uint)table->linesCounter;
+ table->playerScore = (uint)table->linesCounter;
+ memset(table->numAdjacentPieces, 0, sizeof(table->numAdjacentPieces));
+
+ table->calcTouchingPieces = 1;
+ return table;
+}
+
+
+uint &getPlayerTable(penteTable *table, bool staufTurn, pentePlayerTable *&pt) {
+ pt = staufTurn ? &table->stauf : &table->player;
+ return staufTurn ? table->staufScore : table->playerScore;
+}
+
+
+void penteScoringLine(penteTable *table, uint16 lineIndex, bool stauf_turn, bool revert) {
+ pentePlayerTable *playerTable;
+ uint &score = getPlayerTable(table, stauf_turn, playerTable);
+
+ int lineLength, mult;
+ if (revert) {
+ lineLength = --playerTable->lines[lineIndex];
+ mult = -1;
+ } else {
+ lineLength = playerTable->lines[lineIndex]++;
+ mult = 1;
+ }
+
+ if (table->lineLength - lineLength == 1) {
+ score = (int)score + (int)WIN_SCORE * mult;
+ } else {
+ pentePlayerTable *opponentTable;
+ uint &opponentScore = getPlayerTable(table, !stauf_turn, opponentTable);
+ int opponentLineLength = opponentTable->lines[lineIndex];
+ if (lineLength == 0) {
+ opponentScore += (-(1 << ((byte)opponentLineLength & 0x1f))) * mult;
+ if (table->lineLength - opponentLineLength == 1) {
+ if (stauf_turn)
+ table->playerLines -= mult;
+ else
+ table->staufLines -= mult;
+ }
+ }
+ if (opponentLineLength == 0) {
+ score += (1 << ((byte)lineLength & 0x1f)) * mult;
+ if (table->lineLength - lineLength == 2) {
+ byte b;
+ if (stauf_turn)
+ b = (table->staufLines += mult);
+ else
+ b = (table->playerLines += mult);
+
+ if (revert)
+ b -= mult;
+
+ if (1 < b) {
+ score = (int)score + (int)CAPTURE_SCORE * mult;
+ }
+ }
+ }
+ }
+}
+
+void penteTouchingPieces(penteTable *table, byte moveX, byte moveY, bool revert) {
+ byte endX, endY;
+
+ if (moveX + 1 < table->width) {
+ endX = moveX + 1;
+ } else {
+ endX = table->width - 1;
+ }
+
+ if (moveY + 1 < table->height) {
+ endY = moveY + 1;
+ } else {
+ endY = table->height - 1;
+ }
+
+ byte x = 0;
+ if (1 < moveX) {
+ x = moveX - 1;
+ }
+
+ for (; x <= endX; x++) {
+ byte y = 0;
+ if (1 < moveY) {
+ y = moveY - 1;
+ }
+
+ for (; y <= endY; y++) {
+ if(revert)
+ table->numAdjacentPieces[x][y]--;
+ else
+ table->numAdjacentPieces[x][y]++;
+ }
+ }
+}
+
+
+void PenteGame::penteSub03Scoring(penteTable *table, byte move_y, byte move_x, bool stauf_turn) {
+ table->boardState[move_x][move_y] = stauf_turn ? 88 : 79;
+ uint16 lines = table->linesTable[move_x][move_y][0];
+
+ for (int i = 1; i <= lines; i++) {
+ uint16 lineIndex = table->linesTable[move_x][move_y][i];
+ penteScoringLine(table, lineIndex, stauf_turn, false);
+ }
+
+ if (table->calcTouchingPieces != 0) {
+ penteTouchingPieces(table, move_x, move_y, false);
+ }
+
+ table->moveCounter++;
+}
+
+
+void PenteGame::penteSub07RevertScore(penteTable *table, byte y, byte x) {
+ bool stauf_turn = table->boardState[x][y] == 88;
+ table->boardState[x][y] = 0;
+ table->moveCounter--;
+ uint lines = table->linesTable[x][y][0];
+
+ for (uint i = 1; i <= lines; i++) {
+ uint16 lineIndex = table->linesTable[x][y][i];
+ penteScoringLine(table, lineIndex, stauf_turn, true);
+ }
+
+ if (table->calcTouchingPieces != 0) {
+ penteTouchingPieces(table, x, y, true);
+ }
+}
+
+
+byte PenteGame::penteScoreCaptureSingle(penteTable *table, byte x, byte y, int slopeX, int slopeY) {
+ byte x1 = x + slopeX;
+ byte y1 = y + slopeY;
+ byte x2 = x + slopeX * 2;
+ byte y2 = y + slopeY * 2;
+ byte endX = x + slopeX * 3;
+ byte endY = y + slopeY * 3;
+
+ // we don't need to check for below 0 when we have unsigned types
+ if (x >= table->width || y >= table->height)
+ return 0;
+ if (endX >= table->width || endY >= table->height)
+ return 0;
+
+ auto &boardState = table->boardState;
+ byte captor = boardState[x][y];
+ byte captive = captor == 88 ? 79 : 88;
+
+ // make sure the captor is at the start and end of the line
+ if (boardState[endX][endY] != captor)
+ return 0;
+
+ // check that the captive is both of the middle pieces
+ if (boardState[x1][y1] != captive || boardState[x2][y2] != captive)
+ return 0;
+
+ penteSub07RevertScore(table, y1, x1);
+ penteSub07RevertScore(table, y2, x2);
+ return 1;
+}
+
+struct Slope {
+ int x, y;
+};
+// the order of these is important because we return the bitMask
+Slope slopes[] = {{1, 0},
+ {1, 1},
+ {0, 1},
+ {-1, 1},
+ {-1, 0},
+ {-1, -1},
+ {0, -1},
+ {1, -1}};
+
+uint PenteGame::penteSub04ScoreCapture(penteTable *table, byte y, byte x)
+{
+ byte bitMask = 0;
+ bool isStauf = table->boardState[x][y] == 88;
+
+
+ for (const Slope &slope : slopes ) {
+ bitMask <<= 1;
+ bitMask |= penteScoreCaptureSingle(table, x, y, slope.x, slope.y);
+ }
+
+ for (int i = bitMask; i; i >>= 1) {
+ if ((i & 1) == 0)
+ continue;
+ pentePlayerTable *playerTable;
+ uint &score = getPlayerTable(table, isStauf, playerTable);
+
+ int lineLength = ++playerTable->lines[table->linesCounter];
+ if (table->lineLength == lineLength) {
+ score += WIN_SCORE;
+ } else {
+ score += 1 << (lineLength - 1U & 0x1f);
+ }
+ }
+ return bitMask;
+}
+
+
+
+
+void PenteGame::penteSub08MaybeAnimateCapture(short move, byte *bitMaskG, short *param_3, short *param_4)
+
+{
+ byte x;
+ byte y;
+
+ x = (byte)((int)move / 0xf);
+ y = 0xe - (char)((int)move % 0xf);
+
+ byte &bitMask = *bitMaskG;
+ byte bVar3 = 0;
+ for (bVar3 = 0; bVar3 < 8; bVar3++) {
+ if (bitMask >> bVar3 & 1) {
+ bitMask = '\x01' << (bVar3 & 0x1f) ^ bitMask;
+ break;
+ }
+ }
+
+ short sVar4;
+ switch (bVar3) {
+ case 0:
+ *param_3 = (x + 2) * 0xf - (uint16)y;
+ *param_4 = ((uint16)x * 0xf - (uint16)y) + 0x2e;
+ return;
+ case 1:
+ *param_3 = (x + 1) * 0xf - (uint16)y;
+ *param_4 = ((uint16)x * 0xf - (uint16)y) + 0x10;
+ return;
+ case 2:
+ sVar4 = (uint16)x * 0xf - (uint16)y;
+ *param_3 = sVar4;
+ *param_4 = sVar4 + -0xe;
+ return;
+ case 3:
+ sVar4 = (uint16)x * 0xf - (uint16)y;
+ *param_3 = sVar4 + -1;
+ *param_4 = sVar4 + -0x10;
+ return;
+ case 4:
+ sVar4 = (uint16)x * 0xf - (uint16)y;
+ *param_3 = sVar4 + -2;
+ *param_4 = sVar4 + -0x12;
+ return;
+ case 5:
+ sVar4 = (uint16)x * 0xf - (uint16)y;
+ *param_3 = sVar4 + 0xd;
+ *param_4 = sVar4 + 0xc;
+ return;
+ case 6:
+ sVar4 = (uint16)x * 0xf - (uint16)y;
+ *param_3 = sVar4 + 0x1c;
+ *param_4 = sVar4 + 0x2a;
+ return;
+ case 7:
+ sVar4 = (uint16)x * 0xf - (uint16)y;
+ *param_3 = sVar4 + 0x1d;
+ *param_4 = sVar4 + 0x2c;
+ }
+ return;
+}
+
+
+
+
+void PenteGame::penteSub11RevertCapture(penteTable *table, byte y, byte x, byte bitMask)
+{
+ bool isPlayer = table->boardState[x][y] == 79;
+ for (int i = bitMask; i; i >>= 1) {
+ if ((i & 1) == 0)
+ continue;
+
+ pentePlayerTable *playerTable;
+ uint &score = getPlayerTable(table, !isPlayer, playerTable);
+
+ int linesCounter = --playerTable->lines[table->linesCounter];
+
+ if (table->lineLength - linesCounter == 1) {
+ score -= WIN_SCORE;
+ } else {
+ score -= (1 << ((char)linesCounter & 0x1f));
+ }
+ }
+
+ for (int i = 0; i < 8; i++) {
+ if ((bitMask >> i & 1) == 0)
+ continue;
+
+ Slope &slope = slopes[7 - i];
+ penteSub03Scoring(table, y + slope.y * 2, x + slope.x * 2, isPlayer);
+ penteSub03Scoring(table, y + slope.y, x + slope.x, isPlayer);
+ }
+}
+
+
+
+
+int PenteGame::penteSub10AiRecurse(penteTable *table_1, char depth, int parent_score)
+{
+ int iVar2;
+ int iVar3;
+ int iVar4;
+ bool bVar5;
+ uint uVar7;
+ int iVar8;
+ uint uVar9;
+ short sVar10;
+ int iVar12;
+ uint16 local_970[2];
+ int best_score;
+ Common::FixedStack<int, 600> local_95c;
+
+ best_score = 0x7fffffff;
+ if (depth == 1) {
+ table_1->calcTouchingPieces = 0;
+ for (byte bVar1 = 0; bVar1 < table_1->width; bVar1++) {
+ for (byte bVar11 = 0; bVar11 < table_1->height; bVar11++) {
+ if ((table_1->boardState[bVar1][bVar11] != 0) ||
+ (table_1->numAdjacentPieces[bVar1][bVar11] == 0)) {
+ continue;
+ }
+
+ penteSub03Scoring(table_1, bVar11, bVar1, (bool)((byte)table_1->moveCounter & 1));
+ uVar7 = penteSub04ScoreCapture(table_1, bVar11, bVar1);
+ if ((*(byte *)&table_1->moveCounter & 1) == 0) {
+ iVar12 = table_1->playerScore - table_1->staufScore;
+ } else {
+ iVar12 = table_1->staufScore - table_1->playerScore;
+ }
+ if ((byte)uVar7 != 0) {
+ penteSub11RevertCapture(table_1, bVar11, bVar1, (byte)uVar7);
+ }
+ penteSub07RevertScore(table_1, bVar11, bVar1);
+ if (iVar12 < best_score) {
+ best_score = iVar12;
+ }
+ if (-parent_score != best_score && parent_score <= -best_score) {
+ table_1->calcTouchingPieces = 1;
+ return -best_score;
+ }
+ }
+ }
+ table_1->calcTouchingPieces = 1;
+ } else {
+ *(uint *)local_970 = 0;
+ for (byte bVar1 = 0; bVar1 < table_1->width; bVar1++) {
+ for (byte bVar11 = 0; bVar11 < table_1->height; bVar11++) {
+ if ((table_1->boardState[bVar1][bVar11] != 0) ||
+ (table_1->numAdjacentPieces[bVar1][bVar11] == 0)) {
+ continue;
+ }
+
+ penteSub03Scoring(table_1, bVar11, bVar1, (bool)((byte)table_1->moveCounter & 1));
+ uVar7 = penteSub04ScoreCapture(table_1, bVar11, bVar1);
+ if ((*(byte *)&table_1->moveCounter & 1) == 0) {
+ iVar12 = table_1->playerScore - table_1->staufScore;
+ } else {
+ iVar12 = table_1->staufScore - table_1->playerScore;
+ }
+ if ((byte)uVar7 != 0) {
+ penteSub11RevertCapture(table_1, bVar11, bVar1, (byte)uVar7);
+ }
+ penteSub07RevertScore(table_1, bVar11, bVar1);
+ iVar8 = (int)(short)local_970[1];
+ *(uint *)local_970 = (uint)(uint16)(local_970[1] + 1) << 0x10;
+ local_95c[iVar8 * 2 + 1] = iVar12;
+ *(byte *)&local_95c[iVar8 * 2] = bVar11;
+ *((byte *)&local_95c[iVar8 * 2] + 1) = bVar1;
+ }
+ }
+
+ uint16 uVar6;
+ for (uVar6 = 1; uVar6 < local_970[1]; uVar6 = uVar6 * 3 + 1) {}
+
+ while (2 < (short)uVar6) {
+ uVar6 = (short)uVar6 / 3;
+ uVar7 = *(uint *)local_970 & 0xffff0000;
+ *(uint *)local_970 = uVar7 | uVar6;
+ local_970[1] = (uint16)(uVar7 >> 0x10);
+ if ((short)uVar6 < (short)local_970[1]) {
+ do {
+ bVar5 = false;
+ sVar10 = local_970[0] - uVar6;
+ while ((-1 < sVar10 && (!bVar5))) {
+ iVar8 = (int)sVar10;
+ iVar12 = (short)uVar6 + iVar8;
+ if (local_95c[iVar12 * 2 + 1] < local_95c[iVar8 * 2 + 1]) {
+ sVar10 -= uVar6;
+ iVar2 = local_95c[iVar12 * 2 + 1];
+ iVar3 = local_95c[iVar12 * 2];
+ iVar4 = local_95c[iVar8 * 2 + 1];
+ local_95c[iVar12 * 2] = local_95c[iVar8 * 2];
+ local_95c[iVar12 * 2 + 1] = iVar4;
+ local_95c[iVar8 * 2] = iVar3;
+ local_95c[iVar8 * 2 + 1] = iVar2;
+ } else {
+ bVar5 = true;
+ }
+ }
+ uVar7 = *(uint *)local_970 & 0xffff0000;
+ *(uint *)local_970 = uVar7 | (uint16)(local_970[0] + 1);
+ local_970[1] = (uint16)(uVar7 >> 0x10);
+ } while ((short)(local_970[0] + 1) < (short)local_970[1]);
+ }
+ }
+
+ local_970[1] = (uint16)(*(uint *)local_970 >> 0x10);
+ for (sVar10 = 0; sVar10 < local_970[1]; sVar10++) {
+ byte bVar1 = *(byte *)&local_95c[sVar10 * 2];
+ byte bVar11 = *((byte *)&local_95c[sVar10 * 2] + 1);
+ *(uint *)local_970 &= 0xffffff00;
+ penteSub03Scoring(table_1, bVar1, bVar11, (bool)((byte)table_1->moveCounter & 1));
+ uVar9 = penteSub04ScoreCapture(table_1, bVar1, bVar11);
+ uVar7 = table_1->playerScore;
+ if ((((int)uVar7 < WIN_SCORE) && ((int)table_1->staufScore < WIN_SCORE)) &&
+ (table_1->boardSize != table_1->moveCounter)) {
+ iVar12 = penteSub10AiRecurse(table_1, depth + -1, best_score);
+ } else {
+ if ((*(byte *)&table_1->moveCounter & 1) == 0) {
+ iVar12 = uVar7 - table_1->staufScore;
+ } else {
+ iVar12 = table_1->staufScore - uVar7;
+ }
+ }
+ if ((byte)uVar9 != 0) {
+ penteSub11RevertCapture(table_1, bVar1, bVar11, (byte)uVar9);
+ }
+ penteSub07RevertScore(table_1, bVar1, bVar11);
+ if (iVar12 < best_score) {
+ best_score = iVar12;
+ }
+ if (-parent_score != best_score && parent_score <= -best_score)
+ break;
+ local_970[1] = (uint16)(*(uint *)local_970 >> 0x10);
+ }
+ }
+ return -best_score;
+}
+
+
+
+
+uint PenteGame::penteSub09Ai(uint y_1, int param_2, int param_3, penteTable *table_4, byte depth)
+{
+ bool bVar1;
+ uint uVar2;
+ int iVar3;
+ byte _y;
+ int best_score;
+ uint16 uVar5;
+ byte bStack18;
+ byte _x;
+ uint16 local_c;
+ short local_4;
+ uint _y2;
+
+ bStack18 = 1;
+ _x = 0;
+ uVar5 = 0xffff;
+ best_score = 0x7fffffff;
+ if (table_4->width != 0) {
+ do {
+ _y = 0;
+ if (table_4->height != 0) {
+ do {
+ y_1 = (uint)_y;
+ if ((table_4->boardState[_x][y_1] == 0) && (table_4->numAdjacentPieces[_x][y_1] != 0)) {
+ penteSub03Scoring(table_4, _y, _x, (bool)((byte)table_4->moveCounter & 1));
+ _y2 = penteSub04ScoreCapture(table_4, _y, _x);
+ if (((int)table_4->playerScore < WIN_SCORE) &&
+ ((int)table_4->staufScore < WIN_SCORE)) {
+ bVar1 = false;
+ } else {
+ bVar1 = true;
+ }
+ if ((byte)_y2 != 0) {
+ penteSub11RevertCapture(table_4, _y, _x, (byte)_y2);
+ }
+ penteSub07RevertScore(table_4, _y, _x);
+ if (bVar1) {
+ return y_1 & 0xffff0000 | (uint)(uint16)((uint16)_y + (uint16)_x * 100);
+ }
+ }
+ _y += 1;
+ } while (_y <= table_4->height && table_4->height != _y);
+ }
+ _x += 1;
+ y_1 &= 0xffffff00;
+ } while (_x <= table_4->width && table_4->width != _x);
+ }
+ do {
+ _x = 0;
+ if (table_4->width != 0) {
+ do {
+ _y2 = 0;
+ if (table_4->height != 0) {
+ do {
+ _y = (byte)_y2;
+ y_1 = 0;
+ if ((table_4->boardState[_x][_y2] == 0) && (table_4->numAdjacentPieces[_x][_y2] != 0)) {
+ penteSub03Scoring(table_4, _y, _x, (bool)((byte)table_4->moveCounter & 1));
+ uVar2 = penteSub04ScoreCapture(table_4, _y, _x);
+ iVar3 = penteSub10AiRecurse(table_4, depth - 1, best_score);
+ if ((byte)uVar2 != 0) {
+ penteSub11RevertCapture(table_4, _y, _x, (byte)uVar2);
+ }
+ penteSub07RevertScore(table_4, _y, _x);
+ local_c = (uint16)_x;
+ local_4 = (short)_y2;
+ if (iVar3 < best_score) {
+ bStack18 = 1;
+ uVar5 = local_c * 100 + local_4;
+ best_score = iVar3;
+ } else {
+ if (iVar3 == best_score) {
+ bStack18 += 1;
+ _y2 = _random.getRandomNumber(UINT_MAX);
+ y_1 = (uint)bStack18;
+ if ((_y2 % CAPTURE_SCORE) * y_1 < CAPTURE_SCORE) {
+ uVar5 = local_c * 100 + local_4;
+ }
+ }
+ }
+ }
+ _y += 1;
+ _y2 = (uint)_y;
+ } while (_y <= table_4->height && table_4->height != _y);
+ }
+ _x += 1;
+ y_1 &= 0xffffff00;
+ } while (_x <= table_4->width && table_4->width != _x);
+ }
+ } while ((99999999 < best_score) && (depth -= 1, 1 < depth));
+ return y_1 & 0xffff0000 | (uint)uVar5;
+}
+
+
+int varsMoveToXY(byte var0, byte var1, byte var2, byte &x, byte &y) {
+ int move = ((char)var0 * 10 + (short)(char)var1) * 10 + (short)(char)var2;
+ x = (byte)(move / 15);
+ y = 0xe - (char)((int)move % 15);
+ return move;
+}
+
+void aiMoveToXY(int move, byte &x, byte &y) {
+ x = move / 100;
+ y = move % 100;
+}
+
+void moveToVars(int move, byte &var0, byte &var1, byte &var2) {
+ var0 = (byte)(move / 100);
+ var1 = (byte)((move % 100) / 10);
+ var2 = (byte)(move % 10);
+}
+
+void moveXYToVars(uint x, uint y, byte &var0, byte &var1, byte &var2) {
+ int move = (x * 0xf - y) + 0xe;
+ moveToVars(move, var0, var1, var2);
+}
+
+void PenteGame::penteOp(byte *vars)
+{
+ uint16 uVar1;
+ int iVar2;
+ uint uVar3;
+ byte ai_depth;
+ short local_2;
+
+ if ((game_state_table == (penteTable *)0x0) && (vars[4] != 0)) {
+ game_state_table = penteSub01Init(0x14, 0xf, 5);
+ }
+ uVar3 = vars[4];
+ debugC(kDebugLogic, "penteOp vars[4]: %d", (int)vars[4]);
+
+ switch (uVar3) {
+ case 0:
+ if (game_state_table != (penteTable *)0x0) {
+ penteSub02Frees(game_state_table);
+ }
+ game_state_table = (penteTable *)0x0;
+ return;
+ case 1:
+ globalPlayerMove = varsMoveToXY(vars[0], vars[1], vars[2], globalX, globalY);
+ debugC(kDebugLogic, "player moved to %d, %d", (int)globalX, (int)globalY);
+ penteSub03Scoring(game_state_table, globalY, globalX,
+ (bool)((byte)game_state_table->moveCounter & 1));
+ uVar3 = penteSub04ScoreCapture(game_state_table, globalY, globalX);
+ global2 = (char)uVar3;
+ return;
+ case 2:
+ case 4:
+ if (global2 != '\0') {
+ if (global1 < 0) {
+ penteSub08MaybeAnimateCapture(globalPlayerMove, (byte *)&global2, &local_2, &global1);
+ vars[5] = 1;
+ moveToVars(local_2, vars[0], vars[1], vars[2]);
+ return;
+ }
+ LAB_00412da4:
+ vars[0] = (byte)((int)global1 / 100);
+ vars[1] = (byte)((int)(global1 % 100) / 10);
+ iVar2 = (int)global1;
+ vars[2] = (byte)(iVar2 % 10);
+ global1 = -1;
+ vars[5] = 1;
+ return;
+ }
+ if (-1 < global1)
+ goto LAB_00412da4;
+ if ((int)game_state_table->playerScore < WIN_SCORE) {
+ if (((int)game_state_table->staufScore < WIN_SCORE) &&
+ (uVar1 = game_state_table->moveCounter)) {
+ vars[5] = 0;
+ return;
+ }
+ if ((int)game_state_table->playerScore < WIN_SCORE) {
+ uVar3 = game_state_table->staufScore;
+ vars[5] = 2;// Stauf wins
+ if ((int)uVar3 < WIN_SCORE) {
+ vars[5] = 4;// player wins because the board is full?
+ }
+ goto DEALLOC;
+ }
+ }
+ vars[5] = 3;// player wins
+ DEALLOC:
+ penteSub02Frees(game_state_table);
+ game_state_table = (penteTable *)0x0;
+ return;
+ case 3:
+ break;
+ case 5:
+ // asking Samantha to make a move? this does a bunch of queries to check if pieces belong to stauf or the player?
+ byte x, y;
+ varsMoveToXY(vars[0], vars[1], vars[2], x, y);
+ ai_depth = game_state_table->boardState[x][y];
+ if (ai_depth == 0) {
+ vars[3] = 0;
+ return;
+ }
+ if (ai_depth == 0x4f) {
+ vars[3] = 2;
+ return;
+ }
+ if (ai_depth != 0x58) {
+ return;
+ }
+ vars[3] = 1;
+ default:
+ return;
+ }
+ ai_depth = vars[6];
+ if (ai_depth == 0) {
+ ai_depth = 3;
+ } else {
+ if (ai_depth == 1) {
+ ai_depth = 4;
+ } else {
+ if (ai_depth != 2)
+ goto LAB_00412e85;
+ ai_depth = 5;
+ }
+ }
+ globalPlayerMove = penteSub09Ai(0, 0, 0, game_state_table, ai_depth);
+LAB_00412e85:
+ aiMoveToXY(globalPlayerMove, globalX, globalY);
+ debugC(kDebugLogic, "Stauf moved to %d, %d", (int)globalX, (int)globalY);
+ penteSub03Scoring(game_state_table, globalY, globalX,
+ (bool)((byte)game_state_table->moveCounter & 1));
+ uVar3 = penteSub04ScoreCapture(game_state_table, globalY, globalX);
+ global2 = (char)uVar3;
+ globalPlayerMove = ((uint16)globalX * 0xf - (uint16)globalY) + 0xe;
+ moveXYToVars(globalX, globalY, vars[0], vars[1], vars[2]);
+}
+
+
PenteGame::PenteGame() : _random("PenteGame") {
+ global1 = -1;
+ game_state_table = NULL;
+ globalY = 0;
+ globalX = 0;
+ global2 = 0;
+ globalPlayerMove = 0;
+#if 0
+ test();
+#endif
}
void PenteGame::run(byte *scriptVariables) {
- // TODO
- scriptVariables[5] = 4; // Auto-solve the puzzle, so the player can continue
+ // TODO: don't need to copy these variables once this is cleaned up
+ byte tvars[1024];
+ memcpy(tvars, scriptVariables, sizeof(tvars));
+ penteOp(tvars);
+ for (int i = 0; i < sizeof(tvars); i++) {
+ if (tvars[i] != scriptVariables[i]) {
+ debugC(kDebugLogic, "PenteGame::run var %d changed from %d to %d", i, (int)scriptVariables[i], (int)tvars[i]);
+ }
+ }
+ memcpy(scriptVariables, tvars, sizeof(tvars));
+}
+
+void PenteGame::test() {
+ warning("starting PenteGame::test()");
+ uint32 oldSeed = _random.getSeed();
+
+ // 6 moves per line
+ testGame(3,
+ {
+ /*x=*/10, /*y=*/6, /*x=*/9, /*y=*/6, /*x=*/10, /*y=*/7, /*x=*/10, /*y=*/5, /*x=*/10, /*y=*/8, /*x=*/9, /*y=*/9,
+ /*x=*/10, /*y=*/9, /*x=*/10, /*y=*/10, /*x=*/9, /*y=*/8, /*x=*/8, /*y=*/7, /*x=*/8, /*y=*/8, /*x=*/7, /*y=*/8,
+ /*x=*/6, /*y=*/9, /*x=*/11, /*y=*/4,
+ }, false);
+
+ testGame(10,
+ {
+ /*x=*/10, /*y=*/6, /*x=*/11, /*y=*/7, /*x=*/10, /*y=*/5, /*x=*/10, /*y=*/7, /*x=*/9, /*y=*/7, /*x=*/12, /*y=*/7,
+ /*x=*/10, /*y=*/4, /*x=*/8, /*y=*/8, /*x=*/10, /*y=*/3, /*x=*/11, /*y=*/5, /*x=*/10, /*y=*/2, /*x=*/9, /*y=*/7,
+ /*x=*/10, /*y=*/6,
+ }, true);
+
+ // test bottom left corner
+ testGame(1993,
+ {
+ /*x=*/0, /*y=*/0, /*x=*/1, /*y=*/1, /*x=*/1, /*y=*/0, /*x=*/2, /*y=*/0, /*x=*/0, /*y=*/1, /*x=*/0, /*y=*/2,
+ /*x=*/2, /*y=*/1, /*x=*/3, /*y=*/2, /*x=*/1, /*y=*/2, /*x=*/2, /*y=*/3, /*x=*/4, /*y=*/1, /*x=*/1, /*y=*/4,
+ /*x=*/5, /*y=*/1, /*x=*/6, /*y=*/1, /*x=*/3, /*y=*/0, /*x=*/5, /*y=*/2, /*x=*/4, /*y=*/3, /*x=*/3, /*y=*/1,
+ /*x=*/3, /*y=*/3, /*x=*/5, /*y=*/3, /*x=*/4, /*y=*/1, /*x=*/4, /*y=*/3, /*x=*/3, /*y=*/3, /*x=*/3, /*y=*/4,
+ /*x=*/2, /*y=*/5, /*x=*/7, /*y=*/0
+ }, false);
+
+ // test bottom right corner
+ testGame(1995,
+ {
+ /*x=*/19, /*y=*/0, /*x=*/18, /*y=*/1, /*x=*/19, /*y=*/1, /*x=*/18, /*y=*/2, /*x=*/18, /*y=*/0, /*x=*/18, /*y=*/3,
+ /*x=*/18, /*y=*/4, /*x=*/17, /*y=*/5, /*x=*/17, /*y=*/0, /*x=*/16, /*y=*/5, /*x=*/17, /*y=*/4, /*x=*/16, /*y=*/4,
+ /*x=*/18, /*y=*/5, /*x=*/18, /*y=*/6, /*x=*/18, /*y=*/5, /*x=*/15, /*y=*/3, /*x=*/18, /*y=*/4, /*x=*/14, /*y=*/2,
+ }, false);
+
+ // test top left corner
+ testGame(1996,
+ {
+ /*x=*/0, /*y=*/14, /*x=*/1, /*y=*/13, /*x=*/1, /*y=*/14, /*x=*/2, /*y=*/14, /*x=*/0, /*y=*/13, /*x=*/0, /*y=*/12,
+ /*x=*/1, /*y=*/12, /*x=*/2, /*y=*/11, /*x=*/2, /*y=*/12, /*x=*/3, /*y=*/12, /*x=*/4, /*y=*/13, /*x=*/1, /*y=*/10,
+ /*x=*/0, /*y=*/9, /*x=*/3, /*y=*/10, /*x=*/1, /*y=*/12, /*x=*/4, /*y=*/9, /*x=*/5, /*y=*/8, /*x=*/6, /*y=*/9,
+ /*x=*/3, /*y=*/11, /*x=*/6, /*y=*/10, /*x=*/6, /*y=*/11, /*x=*/4, /*y=*/8, /*x=*/3, /*y=*/9, /*x=*/4, /*y=*/10,
+ /*x=*/4, /*y=*/11, /*x=*/2, /*y=*/10, /*x=*/0, /*y=*/10, /*x=*/5, /*y=*/10
+ }, false);
+
+ // test top right corner
+ testGame(2019,
+ {
+ /*x=*/19, /*y=*/14, /*x=*/18, /*y=*/13, /*x=*/19, /*y=*/12, /*x=*/18, /*y=*/12, /*x=*/18, /*y=*/11, /*x=*/17, /*y=*/10,
+ /*x=*/18, /*y=*/14, /*x=*/16, /*y=*/11, /*x=*/18, /*y=*/9, /*x=*/15, /*y=*/12, /*x=*/14, /*y=*/13, /*x=*/15, /*y=*/10,
+ /*x=*/15, /*y=*/11, /*x=*/14, /*y=*/10, /*x=*/17, /*y=*/12, /*x=*/16, /*y=*/10, /*x=*/13, /*y=*/10, /*x=*/18, /*y=*/10
+ }, false);
+
+ _random.setSeed(oldSeed);
+ warning("finished PenteGame::test()");
+}
+
+void PenteGame::testGame(uint32 seed, Common::Array<int> moves, bool playerWin) {
+ byte vars[1024];
+ byte &winner = vars[5];
+ byte &op = vars[4];
+
+ warning("starting PenteGame::testGame(%u, %u, %d)", seed, moves.size(), (int)playerWin);
+ memset(vars, 0, sizeof(vars));
+ _random.setSeed(seed);
+
+ op = 0;
+ penteOp(vars);
+
+ for (uint i = 0; i < moves.size(); i += 2) {
+ if (winner)
+ error("%u: early winner: %d", i, (int)winner);
+
+ int x = moves[i];
+ int y = moves[i + 1];
+
+ if (i % 4) {
+ // check Stauf's move
+ op = 3;
+ penteOp(vars);
+
+ byte sX, sY;
+ varsMoveToXY(vars[0], vars[1], vars[2], sX, sY);
+
+ if (sX != x || sY != y)
+ error("%u: Stauf, expected (%d, %d), got (%d, %d)", i, (int)x, (int)y, (int)sX, (int)sY);
+
+ do {
+ op = 4;
+ penteOp(vars);
+ } while (winner == 1);
+ continue;
+ }
+
+ moveXYToVars(x, y, vars[0], vars[1], vars[2]);
+ op = 1;
+ penteOp(vars);
+
+ do {
+ op = 2;
+ penteOp(vars);
+ } while (winner == 1);
+ }
+
+ if (playerWin && winner != 3)
+ error("player didn't win, winner: %d", (int)winner);
+ else if (playerWin == false && winner != 2)
+ error("Stauf didn't win, winner: %d", (int)winner);
+
+ warning("finished PenteGame::testGame(%u, %u, %d)", seed, moves.size(), (int)playerWin);
}
} // End of Groovie namespace
diff --git a/engines/groovie/logic/pente.h b/engines/groovie/logic/pente.h
index 1cc47541c5..457794ab53 100644
--- a/engines/groovie/logic/pente.h
+++ b/engines/groovie/logic/pente.h
@@ -31,13 +31,40 @@ namespace Groovie {
/*
* Pente puzzle at the end of the game.
*/
+
+struct pentePlayerTable;
+struct penteTable;
+
class PenteGame {
public:
PenteGame();
void run(byte *scriptVariables);
-
+
private:
+ int *allocs(int param_1, int param_2);
+ void penteSub02Frees(penteTable *param_1);
+ void penteSub05BuildLookupTable(penteTable *table);
+ penteTable *penteSub01Init(byte width, byte height, byte length);
+ void penteSub03Scoring(penteTable *table, byte move_y, byte move_x, bool whose_turn);
+ void penteSub07RevertScore(penteTable *table_1, byte y, byte x);
+ byte penteScoreCaptureSingle(penteTable *table, byte x, byte y, int slopeX, int slopeY);
+ uint penteSub04ScoreCapture(penteTable *table, byte y, byte x);
+ void penteSub08MaybeAnimateCapture(short param_1, byte *param_2, short *param_3, short *param_4);
+ void penteSub11RevertCapture(penteTable *table, byte y, byte x, byte y2);
+ int penteSub10AiRecurse(penteTable *table_1, char depth, int parent_score);
+ uint penteSub09Ai(uint y_1, int param_2, int param_3, penteTable *table_4, byte depth);
+ void penteOp(byte *vars);
+ void test();
+ void testGame(uint32 seed, Common::Array<int> moves, bool playerWin);
+
Common::RandomSource _random;
+
+ byte globalY;
+ byte globalX;
+ char global2;
+ short globalPlayerMove;
+ short global1;
+ penteTable *game_state_table;
};
} // End of Groovie namespace
diff --git a/engines/groovie/logic/triangle.cpp b/engines/groovie/logic/triangle.cpp
index e4ff554c16..2eac2b2fd5 100644
--- a/engines/groovie/logic/triangle.cpp
+++ b/engines/groovie/logic/triangle.cpp
@@ -824,6 +824,7 @@ void TriangleGame::ensureSamanthaWin(uint32 seed) {
void TriangleGame::test() {
warning("starting TriangleGame::test");
+ uint32 oldSeed = _random.getSeed();
// Samantha appears to not always win, but she usually does, and she wins these seeds
// haven't verified if she always wins in the original game
@@ -837,6 +838,7 @@ void TriangleGame::test() {
testGame(3, {24, 32, 17, 42, 23, 53, 16, 39, 11, 29, 10, 44, 6, 33, 7, 63, 12, 28, 18, 31, 13, 204, 8, 204, 4, 38, 3, 43}, false);
testGame(3, {6, 32, 10, 42, 11, 53, 7, 23, 3, 15, 12, 22, 18, 43, 13, 33, 8, 35, 4, 31, 1, 204, 17, 204, 16, 204, 19, 63 }, false);
+ _random.setSeed(oldSeed);
warning("finished TriangleGame::test");
}
diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp
index 8b71a825d9..a4e8591744 100644
--- a/engines/groovie/script.cpp
+++ b/engines/groovie/script.cpp
@@ -2181,6 +2181,26 @@ void Script::o2_playsound() {
playBackgroundSound(fileref, loops);
}
+void Script::o_wipemaskfromstring58() {
+ // used in pente when pieces are captured
+ Common::String vidName;
+ uint16 instStart = _currentInstruction;
+ uint32 fileref = getVideoRefString(vidName);
+ setBitFlag(10, true);
+
+ // Show the debug information just when starting the playback
+ if (fileref != _videoRef) {
+ debugC(0, kDebugScript, "Groovie::Script: WIPEMASKFROMSTRING58 %d ('%s')", fileref, vidName.c_str());
+ debugC(2, kDebugVideo, "\nGroovie::Script: @0x%04X: Playing mask video %d ('%s') via 0x58 (o_wipemaskfromstring58)", instStart - 1, fileref, vidName.c_str());
+ }
+
+ // Play the video
+ if (!playvideofromref(fileref)) {
+ // Move _currentInstruction back
+ _currentInstruction = instStart - 1;
+ }
+}
+
void Script::o2_check_sounds_overlays() {
uint16 val1 = readScript8or16bits();
uint8 val2 = readScript8bits();
@@ -2394,7 +2414,7 @@ Script::OpcodeFunc Script::_opcodesV2[NUM_OPCODES] = {
&Script::o2_setscriptend,
&Script::o2_playsound,
&Script::o_invalid,
- &Script::o_invalid, // 0x58
+ &Script::o_wipemaskfromstring58, // 0x58
&Script::o2_check_sounds_overlays,
&Script::o2_preview_loadgame
};
diff --git a/engines/groovie/script.h b/engines/groovie/script.h
index b9131d80c9..ac42f8c3fa 100644
--- a/engines/groovie/script.h
+++ b/engines/groovie/script.h
@@ -245,6 +245,7 @@ private:
void o_musicdelay();
void o_hotspot_outrect();
void o_stub56();
+ void o_wipemaskfromstring58();
void o_stub59();
void o2_bf0on();
diff --git a/engines/groovie/video/roq.cpp b/engines/groovie/video/roq.cpp
index 44c601b5dd..a81635c3f7 100644
--- a/engines/groovie/video/roq.cpp
+++ b/engines/groovie/video/roq.cpp
@@ -65,13 +65,20 @@ static inline void copyPixel(byte *dst, const byte *src) {
*(uint32 *)dst = *(const uint32 *)src;
}
-// Overwrites one pixel of destination regardless of the alpha value
+// Overwrites one pixel of destination if the src pixel is visible
static inline void copyPixelIfAlpha(byte *dst, const byte *src) {
if (src[kAIndex] > 0) {
copyPixel(dst, src);
}
}
+// Overwrites one pixel if it's part of the mask
+static inline void copyPixelIfMask(byte *dst, const byte *mask, const byte *src) {
+ if (mask[kAIndex] > 0) {
+ copyPixel(dst, src);
+ }
+}
+
// Copies one pixel to destination but respects the alpha value of the source
static inline void copyPixelWithA(byte *dst, const byte *src) {
if (src[kAIndex] == 255) {
@@ -142,6 +149,7 @@ uint16 ROQPlayer::loadInternal() {
_flagOne = ((_flags & (1 << 1)) != 0);
_flagTwo = ((_flags & (1 << 2)) != 0);
_altMotionDecoder = ((_flags & (1 << 14)) != 0);
+ _flagMasked = ((_flags & (1 << 10)) != 0);
// Read the file header
ROQBlockHeader blockHeader;
@@ -249,7 +257,13 @@ void ROQPlayer::buildShowBuf() {
// Select the destination buffer according to the given flags
int destOffset = 0;
- Graphics::Surface *destBuf;
+ Graphics::Surface *maskBuf = NULL;
+ Graphics::Surface *srcBuf = _currBuf;
+ Graphics::Surface *destBuf = NULL;
+ if (_flagMasked) {
+ srcBuf = _bg;
+ maskBuf = _currBuf;
+ }
if (_flagOne) {
if (_flagTwo) {
destBuf = _overBuf;
@@ -266,17 +280,24 @@ void ROQPlayer::buildShowBuf() {
int startX, startY, stopX, stopY;
calcStartStop(startX, stopX, _origX, _screen->w);
calcStartStop(startY, stopY, _origY, _screen->h);
- assert(destBuf->format == _currBuf->format);
+ assert(destBuf->format == srcBuf->format);
assert(destBuf->format == _overBuf->format);
assert(destBuf->format.bytesPerPixel == 4);
for (int line = startY; line < stopY; line++) {
- byte *in = (byte *)_currBuf->getBasePtr(MAX(0, -_origX) / _scaleX, (line - _origY) / _scaleY);
+ byte *in = (byte *)srcBuf->getBasePtr(MAX(0, -_origX) / _scaleX, (line - _origY) / _scaleY);
byte *inOvr = (byte *)_overBuf->getBasePtr(startX, line);
byte *out = (byte *)destBuf->getBasePtr(startX, line + destOffset);
+ byte *mask = NULL;
+ if (_flagMasked) {
+ mask = (byte *)maskBuf->getBasePtr(MAX(0, -_origX) / _scaleX, (line - _origY) / _scaleY);
+ }
+
for (int x = startX; x < stopX; x++) {
- if (destBuf == _overBuf) {
+ if (_flagMasked) {
+ copyPixelIfMask(out, mask, in);
+ } else if (destBuf == _overBuf) {
copyPixelIfAlpha(out, in);
} else {
copyPixelWithA(out, in);
@@ -296,6 +317,8 @@ void ROQPlayer::buildShowBuf() {
inOvr += _screen->format.bytesPerPixel;
if (!(x % _scaleX))
in += _screen->format.bytesPerPixel;
+ if (mask)
+ mask += _screen->format.bytesPerPixel;
}
}
diff --git a/engines/groovie/video/roq.h b/engines/groovie/video/roq.h
index 32e3964934..3bfd52fb1f 100644
--- a/engines/groovie/video/roq.h
+++ b/engines/groovie/video/roq.h
@@ -93,9 +93,10 @@ private:
byte _codebook4[256 * 4];
// Flags
- bool _flagOne; // Play only first frame and do not print the image to the screen
- bool _flagTwo; // If _flagOne is set. Copy frame to the foreground otherwise to the background
+ bool _flagOne; //!< Play only first frame and do not print the image to the screen
+ bool _flagTwo; //!< If _flagOne is set. Copy frame to the foreground otherwise to the background
bool _altMotionDecoder; // Some ROQ vids use a variation on the copy codeblock
+ bool _flagMasked; //!< Clear the video instead of play it, used in pente
// Buffers
void buildShowBuf();
More information about the Scummvm-git-logs
mailing list