~ubuntu-branches/ubuntu/raring/scummvm/raring

« back to all changes in this revision

Viewing changes to engines/saga/script.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Moritz Muehlenhoff
  • Date: 2011-05-25 19:02:23 UTC
  • mto: (21.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: james.westby@ubuntu.com-20110525190223-fiqm0oaec714xk31
Tags: upstream-1.3.0
ImportĀ upstreamĀ versionĀ 1.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * along with this program; if not, write to the Free Software
19
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
 *
21
 
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-2-1/engines/saga/script.cpp $
22
 
 * $Id: script.cpp 50951 2010-07-16 23:23:30Z eriktorbjorn $
 
21
 * $URL$
 
22
 * $Id$
23
23
 *
24
24
 */
25
25
 
46
46
 
47
47
SAGA1Script::SAGA1Script(SagaEngine *vm) : Script(vm) {
48
48
        ResourceContext *resourceContext;
49
 
        byte *resourcePointer;
50
 
        size_t resourceLength;
 
49
        ByteArray resourceData;
51
50
        int prevTell;
52
 
        int i, j;
53
 
        byte *stringsPointer;
54
 
        size_t stringsLength;
 
51
        uint ui;
 
52
        int j;
 
53
        ByteArray stringsData;
55
54
 
56
55
        //initialize member variables
57
56
        _abortEnabled = true;
67
66
        _pointerObject = ID_NOTHING;
68
67
 
69
68
        _staticSize = 0;
70
 
        _commonBufferSize = COMMON_BUFFER_SIZE;
71
 
        _commonBuffer = (byte*)malloc(_commonBufferSize);
72
 
        memset(_commonBuffer, 0, _commonBufferSize);
 
69
        _commonBuffer.resize(COMMON_BUFFER_SIZE);
73
70
 
74
71
        debug(8, "Initializing scripting subsystem");
75
72
        // Load script resource file context
86
83
        uint32 scriptResourceId = 0;
87
84
        scriptResourceId = _vm->getResourceDescription()->moduleLUTResourceId;
88
85
        debug(3, "Loading module LUT from resource %i", scriptResourceId);
89
 
        _vm->_resource->loadResource(resourceContext, scriptResourceId, resourcePointer, resourceLength);
 
86
        _vm->_resource->loadResource(resourceContext, scriptResourceId, resourceData);
90
87
 
91
88
        // Create logical script LUT from resource
92
 
        if (resourceLength % 22 == 0) {                 // ITE CD
 
89
        if (resourceData.size() % 22 == 0) {                    // ITE CD
93
90
                _modulesLUTEntryLen = 22;
94
 
        } else if (resourceLength % 16 == 0) {  // ITE disk, IHNM
 
91
        } else if (resourceData.size() % 16 == 0) {     // ITE disk, IHNM
95
92
                _modulesLUTEntryLen = 16;
96
93
        } else {
97
 
                error("Script::Script() Invalid script lookup table length (%i)", (int)resourceLength);
 
94
                error("Script::Script() Invalid script lookup table length (%i)", (int)resourceData.size());
98
95
        }
99
96
 
100
97
        // Calculate number of entries
101
 
        _modulesCount = resourceLength / _modulesLUTEntryLen;
 
98
        int modulesCount = resourceData.size() / _modulesLUTEntryLen;
102
99
 
103
 
        debug(3, "LUT has %i entries", _modulesCount);
 
100
        debug(3, "LUT has %i entries", modulesCount);
104
101
 
105
102
        // Allocate space for logical LUT
106
 
        _modules = (ModuleData *)malloc(_modulesCount * sizeof(*_modules));
107
 
        if (_modules == NULL) {
108
 
                memoryError("Script::Script()");
109
 
        }
 
103
        _modules.resize(modulesCount);
110
104
 
111
105
        // Convert LUT resource to logical LUT
112
 
        MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, resourceContext->isBigEndian());
113
 
        for (i = 0; i < _modulesCount; i++) {
114
 
                memset(&_modules[i], 0, sizeof(ModuleData));
 
106
        ByteArrayReadStreamEndian scriptS(resourceData, resourceContext->isBigEndian());
 
107
        for (ui = 0; ui < _modules.size(); ui++) {
115
108
 
116
109
                prevTell = scriptS.pos();
117
 
                _modules[i].scriptResourceId = scriptS.readUint16();
118
 
                _modules[i].stringsResourceId = scriptS.readUint16();
119
 
                _modules[i].voicesResourceId = scriptS.readUint16();
 
110
                _modules[ui].scriptResourceId = scriptS.readUint16();
 
111
                _modules[ui].stringsResourceId = scriptS.readUint16();
 
112
                _modules[ui].voicesResourceId = scriptS.readUint16();
120
113
 
121
114
                // Skip the unused portion of the structure
122
115
                for (j = scriptS.pos(); j < prevTell + _modulesLUTEntryLen; j++) {
123
116
                        if (scriptS.readByte() != 0)
124
 
                                warning("Unused scriptLUT part isn't really unused for LUT %d (pos: %d)", i, j);
 
117
                                warning("Unused scriptLUT part isn't really unused for LUT %d (pos: %d)", ui, j);
125
118
                }
126
119
        }
127
120
 
128
 
        free(resourcePointer);
129
 
 
130
121
        // TODO
131
122
        //
132
123
        // In ITE, the "main strings" resource contains both the verb strings
135
126
        // In IHNM, the "main strings" contains the verb strings, but not the
136
127
        // object names. At least, I think that's the case.
137
128
 
138
 
        _vm->_resource->loadResource(resourceContext, _vm->getResourceDescription()->mainStringsResourceId, stringsPointer, stringsLength);
 
129
        _vm->_resource->loadResource(resourceContext, _vm->getResourceDescription()->mainStringsResourceId, stringsData);
139
130
 
140
 
        _vm->loadStrings(_mainStrings, stringsPointer, stringsLength);
141
 
        free(stringsPointer);
 
131
        _vm->loadStrings(_mainStrings, stringsData);
142
132
 
143
133
        setupScriptOpcodeList();
144
134
 
157
147
 
158
148
SAGA1Script::~SAGA1Script() {
159
149
        debug(8, "Shutting down scripting subsystem.");
160
 
 
161
 
        _mainStrings.freeMem();
162
 
        _globalVoiceLUT.freeMem();
163
 
 
164
 
        freeModules();
165
 
        free(_modules);
166
 
 
167
 
        free(_commonBuffer);
168
150
}
169
151
 
170
152
SAGA2Script::SAGA2Script(SagaEngine *vm) : Script(vm) {
171
 
        byte *resourcePointer;
172
 
        size_t resourceLength;
 
153
        ByteArray resourceData;
173
154
 
174
155
        debug(8, "Initializing scripting subsystem");
175
156
        // Load script resource file context
179
160
        }
180
161
 
181
162
        // Script export segment (lookup table)
182
 
        uint32 saga2ExportSegId = MKID_BE('_EXP');
 
163
        uint32 saga2ExportSegId = MKTAG('_','E','X','P');
183
164
        int32 entryNum = _scriptContext->getEntryNum(saga2ExportSegId);
184
165
        if (entryNum < 0)
185
166
                error("Unable to locate the script's export segment");
186
167
        debug(3, "Loading module LUT from resource %i", entryNum);
187
 
        _vm->_resource->loadResource(_scriptContext, (uint32)entryNum, resourcePointer, resourceLength);
 
168
        _vm->_resource->loadResource(_scriptContext, (uint32)entryNum, resourceData);
188
169
 
189
170
        _modulesLUTEntryLen = sizeof(uint32);
190
171
 
191
172
        // Calculate number of entries
192
 
        _modulesCount = resourceLength / _modulesLUTEntryLen + 1;
 
173
        int modulesCount = resourceData.size() / _modulesLUTEntryLen + 1;
193
174
 
194
 
        debug(3, "LUT has %i entries", _modulesCount);
 
175
        debug(3, "LUT has %i entries", modulesCount);
195
176
 
196
177
        // Script data segment
197
178
        /*
198
 
        uint32 saga2DataSegId = MKID_BE('__DA');
 
179
        uint32 saga2DataSegId = MKTAG('_','_','D','A');
199
180
        entryNum = _scriptContext->getEntryNum(saga2DataSegId);
200
181
        if (entryNum < 0)
201
182
                error("Unable to locate the script's data segment");
994
975
                }
995
976
        } else {
996
977
#endif
997
 
                if (thread->_voiceLUT->voicesCount > first)
998
 
                        sampleResourceId = thread->_voiceLUT->voices[first];
 
978
                if (thread->_voiceLUT->size() > uint16(first))
 
979
                        sampleResourceId = (*thread->_voiceLUT)[uint16(first)];
999
980
#if 0
1000
981
        }
1001
982
#endif
1067
1048
        warning("opJmpSeedRandom");
1068
1049
}
1069
1050
 
1070
 
void Script::loadModule(int scriptModuleNumber) {
1071
 
        byte *resourcePointer;
1072
 
        size_t resourceLength;
 
1051
void Script::loadModule(uint scriptModuleNumber) {
 
1052
        ByteArray resourceData;
1073
1053
 
1074
1054
        // Validate script number
1075
 
        if ((scriptModuleNumber < 0) || (scriptModuleNumber >= _modulesCount)) {
 
1055
        if (scriptModuleNumber >= _modules.size()) {
1076
1056
                error("Script::loadScript() Invalid script module number");
1077
1057
        }
1078
1058
 
1083
1063
        // Initialize script data structure
1084
1064
        debug(3, "Loading script module #%d", scriptModuleNumber);
1085
1065
 
1086
 
        _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].scriptResourceId, resourcePointer, resourceLength);
1087
 
 
1088
 
        loadModuleBase(_modules[scriptModuleNumber], resourcePointer, resourceLength);
1089
 
        free(resourcePointer);
1090
 
 
1091
 
        _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].stringsResourceId, resourcePointer, resourceLength);
1092
 
 
1093
 
        _vm->loadStrings(_modules[scriptModuleNumber].strings, resourcePointer, resourceLength);
1094
 
        free(resourcePointer);
 
1066
        _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].scriptResourceId, resourceData);
 
1067
 
 
1068
        loadModuleBase(_modules[scriptModuleNumber], resourceData);
 
1069
 
 
1070
        _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].stringsResourceId, resourceData);
 
1071
 
 
1072
        _vm->loadStrings(_modules[scriptModuleNumber].strings, resourceData);
1095
1073
 
1096
1074
        if (_modules[scriptModuleNumber].voicesResourceId > 0) {
1097
 
                _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].voicesResourceId, resourcePointer, resourceLength);
 
1075
                _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].voicesResourceId, resourceData);
1098
1076
 
1099
 
                loadVoiceLUT(_modules[scriptModuleNumber].voiceLUT, resourcePointer, resourceLength);
1100
 
                free(resourcePointer);
 
1077
                loadVoiceLUT(_modules[scriptModuleNumber].voiceLUT, resourceData);
1101
1078
        }
1102
1079
 
1103
1080
        _modules[scriptModuleNumber].staticOffset = _staticSize;
1104
1081
        _staticSize += _modules[scriptModuleNumber].staticSize;
1105
 
        if (_staticSize > _commonBufferSize) {
1106
 
                error("Script::loadModule() _staticSize > _commonBufferSize");
 
1082
        if (_staticSize > _commonBuffer.size()) {
 
1083
                error("Script::loadModule() _staticSize > _commonBuffer.size()");
1107
1084
        }
1108
1085
        _modules[scriptModuleNumber].loaded = true;
1109
1086
}
1110
1087
 
1111
 
void Script::freeModules() {
1112
 
        int i;
1113
 
        for (i = 0; i < _modulesCount; i++) {
 
1088
void Script::clearModules() {
 
1089
        uint i;
 
1090
        for (i = 0; i < _modules.size(); i++) {
1114
1091
                if (_modules[i].loaded) {
1115
 
                        _modules[i].freeMem();
1116
 
                        _modules[i].loaded = false;
 
1092
                        _modules[i].clear();
1117
1093
                }
1118
1094
        }
1119
1095
        _staticSize = 0;
1120
1096
}
1121
1097
 
1122
 
void Script::loadModuleBase(ModuleData &module, const byte *resourcePointer, size_t resourceLength) {
1123
 
        int i;
 
1098
void Script::loadModuleBase(ModuleData &module, const ByteArray &resourceData) {
 
1099
        uint i;
1124
1100
 
1125
1101
        debug(3, "Loading module base...");
1126
1102
 
1127
 
        module.moduleBase = (byte*)malloc(resourceLength);
1128
 
        module.moduleBaseSize = resourceLength;
1129
 
 
1130
 
        memcpy(module.moduleBase, resourcePointer, resourceLength);
1131
 
 
1132
 
        MemoryReadStreamEndian scriptS(module.moduleBase, module.moduleBaseSize, _scriptContext->isBigEndian());
1133
 
 
1134
 
        module.entryPointsCount = scriptS.readUint16();
1135
 
        scriptS.readUint16(); //skip
1136
 
        module.entryPointsTableOffset = scriptS.readUint16();
1137
 
        scriptS.readUint16(); //skip
1138
 
 
1139
 
        if ((module.moduleBaseSize - module.entryPointsTableOffset) < (module.entryPointsCount * SCRIPT_TBLENTRY_LEN)) {
 
1103
        module.moduleBase.assign(resourceData);
 
1104
 
 
1105
        ByteArrayReadStreamEndian scriptS(module.moduleBase, _scriptContext->isBigEndian());
 
1106
 
 
1107
        uint entryPointsCount = scriptS.readUint16();
 
1108
        scriptS.readUint16(); //skip
 
1109
        uint16 entryPointsTableOffset;  // offset of entrypoint table in moduleBase
 
1110
        entryPointsTableOffset = scriptS.readUint16();
 
1111
        scriptS.readUint16(); //skip
 
1112
 
 
1113
        if ((module.moduleBase.size() - entryPointsTableOffset) < (entryPointsCount * SCRIPT_TBLENTRY_LEN)) {
1140
1114
                error("Script::loadModuleBase() Invalid table offset");
1141
1115
        }
1142
1116
 
1143
 
        if (module.entryPointsCount > SCRIPT_MAX) {
 
1117
        if (entryPointsCount > SCRIPT_MAX) {
1144
1118
                error("Script::loadModuleBase()Script limit exceeded");
1145
1119
        }
1146
1120
 
1147
 
        module.entryPoints = (EntryPoint *)malloc(module.entryPointsCount * sizeof(*module.entryPoints));
1148
 
        if (module.entryPoints == NULL) {
1149
 
                memoryError("Script::loadModuleBase");
1150
 
        }
 
1121
        module.entryPoints.resize(entryPointsCount);
1151
1122
 
1152
1123
        // Read in the entrypoint table
1153
1124
 
1154
1125
        module.staticSize = scriptS.readUint16();
1155
 
        while (scriptS.pos() < module.entryPointsTableOffset)
 
1126
        while (scriptS.pos() < entryPointsTableOffset)
1156
1127
                scriptS.readByte();
1157
1128
 
1158
 
        for (i = 0; i < module.entryPointsCount; i++) {
 
1129
        for (i = 0; i < module.entryPoints.size(); i++) {
1159
1130
                // First uint16 is the offset of the entrypoint name from the start
1160
1131
                // of the bytecode resource, second uint16 is the offset of the
1161
1132
                // bytecode itself for said entrypoint
1163
1134
                module.entryPoints[i].offset = scriptS.readUint16();
1164
1135
 
1165
1136
                // Perform a simple range check on offset values
1166
 
                if ((module.entryPoints[i].nameOffset >= module.moduleBaseSize) || (module.entryPoints[i].offset >= module.moduleBaseSize)) {
 
1137
                if ((module.entryPoints[i].nameOffset >= module.moduleBase.size()) || (module.entryPoints[i].offset >= module.moduleBase.size())) {
1167
1138
                        error("Script::loadModuleBase() Invalid offset encountered in script entrypoint table");
1168
1139
                }
1169
1140
        }
1170
1141
}
1171
1142
 
1172
 
void Script::loadVoiceLUT(VoiceLUT &voiceLUT, const byte *resourcePointer, size_t resourceLength) {
 
1143
void Script::loadVoiceLUT(VoiceLUT &voiceLUT, const ByteArray &resourceData) {
1173
1144
        uint16 i;
1174
1145
 
1175
 
        voiceLUT.voicesCount = resourceLength / 2;
1176
 
 
1177
 
        voiceLUT.voices = (uint16 *)malloc(voiceLUT.voicesCount * sizeof(*voiceLUT.voices));
1178
 
        if (voiceLUT.voices == NULL) {
1179
 
                error("Script::loadVoiceLUT() not enough memory");
1180
 
        }
1181
 
 
1182
 
        MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, _scriptContext->isBigEndian());
1183
 
 
1184
 
        for (i = 0; i < voiceLUT.voicesCount; i++) {
1185
 
                voiceLUT.voices[i] = scriptS.readUint16();
 
1146
        voiceLUT.resize(resourceData.size() / 2);
 
1147
 
 
1148
        ByteArrayReadStreamEndian scriptS(resourceData, _scriptContext->isBigEndian());
 
1149
 
 
1150
        for (i = 0; i < voiceLUT.size(); i++) {
 
1151
                voiceLUT[i] = scriptS.readUint16();
1186
1152
        }
1187
1153
}
1188
1154
 
1315
1281
        // engine did it, but it appears to work.
1316
1282
        _pointerObject = ID_NOTHING;
1317
1283
 
1318
 
        setLeftButtonVerb( verb );
 
1284
        setLeftButtonVerb(verb);
1319
1285
        showVerb();
1320
1286
}
1321
1287
 
1442
1408
                event.param4 = _pendingObject[0];       // Object
1443
1409
                event.param5 = _pendingObject[1];       // With Object
1444
1410
                event.param6 = (objectType == kGameObjectActor) ? _pendingObject[0] : ID_PROTAG;                // Actor
1445
 
                _vm->_events->queue(&event);
 
1411
                _vm->_events->queue(event);
1446
1412
 
1447
1413
        } else {
1448
1414
                // Show excuse text in ITE CD Versions
1549
1515
        }
1550
1516
 
1551
1517
        if (_pointerObject != ID_NOTHING) {
1552
 
                hitObject( leftButton );
 
1518
                hitObject(leftButton);
1553
1519
        } else {
1554
1520
                _pendingObject[0] = ID_NOTHING;
1555
1521
                _pendingObject[1] = ID_NOTHING;
1618
1584
                                _vm->_actor->actorWalkTo(ID_PROTAG, pickLocation);
1619
1585
                } else {
1620
1586
                        if (_pendingVerb == getVerbType(kVerbLookAt)) {
1621
 
                                if (objectTypeId(_pendingObject[0]) != kGameObjectActor ) {
 
1587
                                if (objectTypeId(_pendingObject[0]) != kGameObjectActor) {
1622
1588
                                        _vm->_actor->actorWalkTo(ID_PROTAG, pickLocation);
1623
1589
                                } else {
1624
1590
                                        doVerb();