mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-20 00:41:12 +00:00
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
This commit is contained in:
parent
45d8b3b002
commit
d3727e1c2a
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -36,7 +36,8 @@ enum ArrayType {
|
||||
kNibbleArray = 2,
|
||||
kByteArray = 3,
|
||||
kStringArray = 4,
|
||||
kIntArray = 5
|
||||
kIntArray = 5,
|
||||
kDwordArray = 6
|
||||
};
|
||||
|
||||
struct ArrayHeader {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user