aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2004-08-25 02:12:03 +0000
committerEugene Sandulenko2004-08-25 02:12:03 +0000
commitd3727e1c2a4ba7e262f415711ca8bb269a4e820c (patch)
tree2d827cd6570c584cfb05aafd19c90218bca3a4ca
parent45d8b3b00291b6dcdae4d4966021ded316c2cfae (diff)
downloadscummvm-rg350-d3727e1c2a4ba7e262f415711ca8bb269a4e820c.tar.gz
scummvm-rg350-d3727e1c2a4ba7e262f415711ca8bb269a4e820c.tar.bz2
scummvm-rg350-d3727e1c2a4ba7e262f415711ca8bb269a4e820c.zip
HE 7.2 uses different array headers. they introduced start indexes, so it
became in somewhat Pascal fashion, i.e. array[2..3][10..20]. So I had to override ArrayHeader function in ScummEngine_v72he. Also there is new array type kDwordArray. So that is implemented as well. Though, not everything yet transferred to use new ArrayHeader, so running HE 7.2 titles is risky now. Some opcodes were implemented along the way. svn-id: r14735
-rw-r--r--scumm/intern.h27
-rw-r--r--scumm/resource.cpp6
-rw-r--r--scumm/resource.h3
-rw-r--r--scumm/script_v72he.cpp308
4 files changed, 288 insertions, 56 deletions
diff --git a/scumm/intern.h b/scumm/intern.h
index 05dc3e1826..9c8fa821c0 100644
--- a/scumm/intern.h
+++ b/scumm/intern.h
@@ -640,6 +640,23 @@ protected:
const char *desc;
};
+#if !defined(__GNUC__)
+ #pragma START_PACK_STRUCTS
+#endif
+
+ struct ArrayHeader {
+ int32 type; //0
+ int32 dim1start; //4
+ int32 dim1end; //8
+ int32 dim2start; //0c
+ int32 dim2end; //10
+ byte data[1];
+ } GCC_PACK;
+
+#if !defined(__GNUC__)
+ #pragma END_PACK_STRUCTS
+#endif
+
const OpcodeEntryV72he *_opcodesV72he;
public:
@@ -652,6 +669,11 @@ protected:
virtual void setupOpcodes();
virtual void executeOpcode(byte i);
virtual const char *getOpcodeDesc(byte i);
+ ArrayHeader *defineArray(int array, int type, int dim2start, int dim2end, int dim1start, int dim1end);
+ int readArray(int array, int idx2, int idx1);
+ void writeArray(int array, int idx2, int idx1, int value);
+ void redimArray(int arrayId, int newDim2start, int newDim2end,
+ int newDim1start, int newDim1end, int type);
/* Version 7 script opcodes */
void o72_pushDWordVar();
@@ -663,12 +685,15 @@ protected:
void o72_startObject();
void o72_drawObject();
void o72_unknown62();
- void o72_unknown63();
+ void o72_getArrayDimSize();
void o72_arrayOps();
void o72_dimArray();
void o72_dim2dimArray();
void o72_jumpToScript();
+ void o72_findAllObjects();
void o72_getPixel();
+ void o72_pickVarRandom();
+ void o72_redimArray();
void o72_stringLen();
void o72_readINI();
void o72_unknownF4();
diff --git a/scumm/resource.cpp b/scumm/resource.cpp
index ebe6caa3ca..8ddeda8879 100644
--- a/scumm/resource.cpp
+++ b/scumm/resource.cpp
@@ -1968,6 +1968,9 @@ byte *ScummEngine::getStringAddress(int i) {
if (!b)
return NULL;
+ if (_heversion >= 72)
+ return (b + 0x14); // ArrayHeader->data
+
if (_features & GF_NEW_OPCODES)
return ((ArrayHeader *)b)->data;
return b;
@@ -1983,6 +1986,9 @@ byte *ScummEngine::getStringAddressVar(int i) {
// error("NULL string var %d slot %d", i, _scummVars[i]);
return NULL;
+ if (_heversion >= 72)
+ return (addr + 0x14); // ArrayHeader->data
+
if (_features & GF_NEW_OPCODES)
return ((ArrayHeader *)addr)->data;
diff --git a/scumm/resource.h b/scumm/resource.h
index 8a2c65ae38..d2f0f125db 100644
--- a/scumm/resource.h
+++ b/scumm/resource.h
@@ -36,7 +36,8 @@ enum ArrayType {
kNibbleArray = 2,
kByteArray = 3,
kStringArray = 4,
- kIntArray = 5
+ kIntArray = 5,
+ kDwordArray = 6
};
struct ArrayHeader {
diff --git a/scumm/script_v72he.cpp b/scumm/script_v72he.cpp
index a401bb2242..a52b0860bc 100644
--- a/scumm/script_v72he.cpp
+++ b/scumm/script_v72he.cpp
@@ -48,7 +48,7 @@ void ScummEngine_v72he::setupOpcodes() {
/* 00 */
OPCODE(o6_pushByte),
OPCODE(o6_pushWord),
- OPCODE(o72_pushDWordVar),
+ OPCODE(o6_pushByteVar),
OPCODE(o6_pushWordVar),
/* 04 */
OPCODE(o72_getString),
@@ -151,8 +151,8 @@ void ScummEngine_v72he::setupOpcodes() {
OPCODE(o6_invalid),
OPCODE(o6_wordArrayInc),
/* 54 */
- OPCODE(o72_objectX),
- OPCODE(o72_objectY),
+ OPCODE(o6_getObjectX),
+ OPCODE(o6_getObjectY),
OPCODE(o6_byteVarDec),
OPCODE(o6_wordVarDec),
/* 58 */
@@ -169,7 +169,7 @@ void ScummEngine_v72he::setupOpcodes() {
OPCODE(o72_startObject),
OPCODE(o72_drawObject),
OPCODE(o72_unknown62),
- OPCODE(o72_unknown63),
+ OPCODE(o72_getArrayDimSize),
/* 64 */
OPCODE(o6_invalid),
OPCODE(o6_stopObjectCode),
@@ -322,14 +322,14 @@ void ScummEngine_v72he::setupOpcodes() {
OPCODE(o6_readFile),
/* DC */
OPCODE(o6_writeFile),
- OPCODE(o6_findAllObjects),
+ OPCODE(o72_findAllObjects),
OPCODE(o6_deleteFile),
OPCODE(o6_rename),
/* E0 */
OPCODE(o6_soundOps),
OPCODE(o72_getPixel),
OPCODE(o6_localizeArray),
- OPCODE(o6_pickVarRandom),
+ OPCODE(o72_pickVarRandom),
/* E4 */
OPCODE(o6_setBoxSet),
OPCODE(o6_invalid),
@@ -338,7 +338,7 @@ void ScummEngine_v72he::setupOpcodes() {
/* E8 */
OPCODE(o6_invalid),
OPCODE(o6_seekFilePos),
- OPCODE(o6_redimArray),
+ OPCODE(o72_redimArray),
OPCODE(o6_readFilePos),
/* EC */
OPCODE(o6_invalid),
@@ -379,16 +379,113 @@ const char *ScummEngine_v72he::getOpcodeDesc(byte i) {
return _opcodesV72he[i].desc;
}
-void ScummEngine_v72he::o72_pushDWordVar() {
- int a;
- if (*_lastCodePtr + sizeof(MemBlkHeader) != _scriptOrgPointer) {
- uint32 oldoffs = _scriptPointer - _scriptOrgPointer;
- getScriptBaseAddress();
- _scriptPointer = _scriptOrgPointer + oldoffs;
+static int arrayDataSizes[] = {0, 1, 4, 8, 8, 16, 32};
+
+ScummEngine_v72he::ArrayHeader *ScummEngine_v72he::defineArray(int array, int type, int dim2start, int dim2end,
+ int dim1start, int dim1end) {
+ int id;
+ int size;
+ ArrayHeader *ah;
+
+ assert(dim2start >= 0 && dim2start <= dim2end);
+ assert(dim1start >= 0 && dim1start <= dim1end);
+ assert(0 <= type && type <= 5);
+
+
+ if (type == kBitArray || type == kNibbleArray)
+ type = kByteArray;
+
+ nukeArray(array);
+
+ id = findFreeArrayId();
+
+ if (array & 0x80000000) {
+ error("Can't define bit variable as array pointer");
+ }
+
+ size = arrayDataSizes[type];
+
+ writeVar(array, id);
+
+ size *= dim2end - dim2start + 1;
+ size *= dim1end - dim1start + 1;
+ size >>= 3;
+
+ ah = (ArrayHeader *)createResource(rtString, id, size + sizeof(ArrayHeader));
+
+ ah->type = TO_LE_32(type);
+ ah->dim1start = TO_LE_32(dim1start);
+ ah->dim1end = TO_LE_32(dim1end);
+ ah->dim2start = TO_LE_32(dim2start);
+ ah->dim2end = TO_LE_32(dim2end);
+
+ return ah;
+}
+
+int ScummEngine_v72he::readArray(int array, int idx2, int idx1) {
+ if (readVar(array) == 0)
+ error("readArray: Reference to zeroed array pointer");
+
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
+
+ if (ah == NULL || ah->data == NULL)
+ error("readArray: invalid array %d (%d)", array, readVar(array));
+
+ if (idx2 < FROM_LE_32(ah->dim2start) || idx2 >= FROM_LE_32(ah->dim2end) ||
+ idx1 < FROM_LE_32(ah->dim1start) || idx1 >= FROM_LE_32(ah->dim2end)) {
+ error("readArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]",
+ array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end),
+ FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end));
+ }
+
+ const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
+ (idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1;
+
+ switch (FROM_LE_32(ah->type)) {
+ case kByteArray:
+ case kStringArray:
+ return ah->data[offset];
+
+ case kIntArray:
+ return (int16)READ_LE_UINT16(ah->data + offset * 2);
+
+ case kDwordArray:
+ return (int32)READ_LE_UINT32(ah->data + offset * 4);
+ }
+
+ return 0;
+}
+
+void ScummEngine_v72he::writeArray(int array, int idx2, int idx1, int value) {
+ if (readVar(array) == 0)
+ error("writeArray: Reference to zeroed array pointer");
+
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
+
+ if (!ah)
+ error("writeArray: Invalid array (%d) reference", readVar(array));
+
+ if (idx2 < FROM_LE_32(ah->dim2start) || idx2 >= FROM_LE_32(ah->dim2end) ||
+ idx1 < FROM_LE_32(ah->dim1start) || idx1 >= FROM_LE_32(ah->dim2end)) {
+ error("writeArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]",
+ array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end),
+ FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end));
+ }
+
+ const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
+ (idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1;
+
+ switch (FROM_LE_32(ah->type)) {
+ case kByteArray:
+ case kStringArray:
+ ah->data[offset] = value;
+
+ case kIntArray:
+ WRITE_LE_UINT16(ah->data + offset * 2, value);
+
+ case kDwordArray:
+ WRITE_LE_UINT32(ah->data + offset * 4, value);
}
- a = READ_LE_UINT32(_scriptPointer);
- _scriptPointer += 4;
- push(a);
}
void ScummEngine_v72he::o72_getString() {
@@ -407,7 +504,7 @@ void ScummEngine_v72he::o72_compareStackList() {
int value = pop();
if (num) {
- for (i = 1; i < num; i++) {
+ for (i = 1; i < 128; i++) {
if (args[i] == value) {
push(1);
break;
@@ -418,31 +515,6 @@ void ScummEngine_v72he::o72_compareStackList() {
}
}
-void ScummEngine_v72he::o72_objectX() {
- int object = pop();
- int objnum = getObjectIndex(object);
-
- if (objnum == -1) {
- push(0);
- return;
- }
-
- push(_objs[objnum].x_pos);
-}
-
-
-void ScummEngine_v72he::o72_objectY() {
- int object = pop();
- int objnum = getObjectIndex(object);
-
- if (objnum == -1) {
- push(0);
- return;
- }
-
- push(_objs[objnum].y_pos);
-}
-
void ScummEngine_v72he::o72_startScript() {
int args[16];
int script, flags;
@@ -510,12 +582,26 @@ void ScummEngine_v72he::o72_unknown62() {
warning("o72_unknown62 stub (%d)", a);
}
-void ScummEngine_v72he::o72_unknown63() {
+void ScummEngine_v72he::o72_getArrayDimSize() {
int subOp = fetchScriptByte();
- //int arrayId = readVar(fetchScriptWord());
+ int32 val1, val2;
+ ArrayHeader *ah;
- warning("o72_unknown63 stub (%d)", subOp);
- push(0);
+ switch (subOp) {
+ case 1:
+ case 3:
+ ah = (ArrayHeader *)getResourceAddress(rtString, readVar(fetchScriptWord()));
+ val1 = FROM_LE_32(ah->dim1end);
+ val2 = FROM_LE_32(ah->dim1start);
+ push(val1 - val2 + 1);
+ break;
+ case 2:
+ ah = (ArrayHeader *)getResourceAddress(rtString, readVar(fetchScriptWord()));
+ val1 = FROM_LE_32(ah->dim2end);
+ val2 = FROM_LE_32(ah->dim2start);
+ push(val1 - val2 + 1);
+ break;
+ }
}
void ScummEngine_v72he::o72_arrayOps() {
@@ -528,13 +614,13 @@ void ScummEngine_v72he::o72_arrayOps() {
switch (subOp) {
case 7: // SO_ASSIGN_STRING
len = resStrLen(_scriptPointer);
- ah = defineArray(array, kStringArray, 0, len + 1);
+ ah = defineArray(array, kStringArray, 0, 0, 0, len + 1);
copyScriptString(ah->data);
break;
case 205: // SO_ASSIGN_STRING
b = pop();
len = resStrLen(_scriptPointer);
- ah = defineArray(array, kStringArray, 0, len + 1);
+ ah = defineArray(array, kStringArray, 0, 0, 0, len + 1);
copyScriptString(ah->data + b);
break;
case 208: // SO_ASSIGN_INT_LIST
@@ -542,7 +628,7 @@ void ScummEngine_v72he::o72_arrayOps() {
c = pop();
d = readVar(array);
if (d == 0) {
- defineArray(array, kIntArray, 0, b + c);
+ defineArray(array, kIntArray, 0, 0, 0, b + c);
}
while (c--) {
writeArray(array, 0, b + c, pop());
@@ -582,7 +668,7 @@ void ScummEngine_v72he::o72_dimArray() {
data = kByteArray;
break;
case 6:
- error("New array type");
+ data = kDwordArray;
break;
case 7: // SO_STRING_ARRAY
data = kStringArray;
@@ -594,7 +680,7 @@ void ScummEngine_v72he::o72_dimArray() {
error("o72_dimArray: default case %d", type);
}
- defineArray(fetchScriptWord(), data, 0, pop());
+ defineArray(fetchScriptWord(), data, 0, 0, 0, pop());
}
@@ -615,7 +701,7 @@ void ScummEngine_v72he::o72_dim2dimArray() {
data = kIntArray;
break;
case 6:
- error("New array type");
+ data = kDwordArray;
break;
case 7: // SO_STRING_ARRAY
data = kStringArray;
@@ -626,7 +712,7 @@ void ScummEngine_v72he::o72_dim2dimArray() {
b = pop();
a = pop();
- defineArray(fetchScriptWord(), data, a, b);
+ defineArray(fetchScriptWord(), data, 0, a, 0, b);
}
void ScummEngine_v72he::o72_jumpToScript() {
@@ -640,6 +726,24 @@ void ScummEngine_v72he::o72_jumpToScript() {
runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args);
}
+void ScummEngine_v72he::o72_findAllObjects() {
+ int a = pop();
+ int i = 1;
+
+ if (a != _currentRoom)
+ warning("o72_findAllObjects: current room is not %d", a);
+ writeVar(0, 0);
+ defineArray(0, kDwordArray, 0, 0, 0, _numLocalObjects + 1);
+ writeArray(0, 0, 0, _numLocalObjects);
+
+ while (i < _numLocalObjects) {
+ writeArray(0, 0, i, _objs[i].obj_nr);
+ i++;
+ }
+
+ push(readVar(0));
+}
+
void ScummEngine_v72he::o72_getPixel() {
byte area;
int x = pop();
@@ -662,6 +766,102 @@ void ScummEngine_v72he::o72_getPixel() {
push(area);
}
+void ScummEngine_v72he::o72_pickVarRandom() {
+ int num;
+ int args[100];
+ int32 var_A;
+
+ num = getStackList(args, ARRAYSIZE(args));
+ int value = fetchScriptWord();
+
+ if (readVar(value) == 0) {
+ defineArray(value, kDwordArray, 0, 0, 0, num + 1);
+ if (num > 0) {
+ int16 counter = 0;
+ do {
+ writeArray(value, 0, counter + 1, args[counter]);
+ } while (++counter < num);
+ }
+
+ shuffleArray(value, 1, num-1);
+ writeArray(value, 0, 0, 2);
+ push(readArray(value, 0, 1));
+ return;
+ }
+
+ num = readArray(value, 0, 0);
+
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, num);
+ var_A = FROM_LE_32(ah->dim1end);
+
+ if (var_A-1 <= num) {
+ int16 var_2 = readArray(value, 0, num - 1);
+ shuffleArray(value, 1, num - 1);
+ if (readArray(value, 0, 1) == var_2) {
+ num = 2;
+ } else {
+ num = 1;
+ }
+ }
+
+ writeArray(value, 0, 0, num + 1);
+ push(readArray(value, 0, num));
+}
+
+void ScummEngine_v72he::o72_redimArray() {
+ int subcode, newX, newY;
+ newY = pop();
+ newX = pop();
+
+ subcode = fetchScriptByte();
+ switch (subcode) {
+ case 5:
+ redimArray(fetchScriptWord(), 0, newX, 0, newY, kIntArray);
+ break;
+ case 4:
+ redimArray(fetchScriptWord(), 0, newX, 0, newY, kByteArray);
+ break;
+ case 6:
+ redimArray(fetchScriptWord(), 0, newX, 0, newY, kDwordArray);
+ break;
+ default:
+ break;
+ }
+}
+
+void ScummEngine_v72he::redimArray(int arrayId, int newDim2start, int newDim2end,
+ int newDim1start, int newDim1end, int type) {
+ int newSize, oldSize;
+
+ if (readVar(arrayId) == 0)
+ error("redimArray: Reference to zeroed array pointer");
+
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId));
+
+ if (!ah)
+ error("redimArray: Invalid array (%d) reference", readVar(arrayId));
+
+ newSize = arrayDataSizes[type];
+ oldSize = arrayDataSizes[FROM_LE_32(ah->type)];
+
+ newSize *= (newDim1end - newDim1start + 1) * (newDim2end - newDim2end + 1);
+ oldSize *= (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
+ (FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1);
+
+ newSize >>= 3;
+ oldSize >>= 3;
+
+ if (newSize != oldSize)
+ error("redimArray: array %d redim mismatch", readVar(arrayId));
+
+ ah->type = TO_LE_32(type);
+ ah->dim1start = TO_LE_32(newDim1start);
+ ah->dim1end = TO_LE_32(newDim1end);
+ ah->dim2start = TO_LE_32(newDim2start);
+ ah->dim2end = TO_LE_32(newDim2end);
+}
+
+
void ScummEngine_v72he::o72_stringLen() {
int a, len;
byte *addr;
@@ -691,7 +891,7 @@ void ScummEngine_v72he::o72_readINI() {
push(0);
break;
case 7: // string
- defineArray(0, kStringArray, 0, 0);
+ defineArray(0, kStringArray, 0, 0, 0, 0);
retval = readVar(0);
writeArray(0, 0, 0, 0);
push(retval); // var ID string