aboutsummaryrefslogtreecommitdiff
path: root/scumm
diff options
context:
space:
mode:
Diffstat (limited to 'scumm')
-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