1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "sci/sci.h"
24 #include "sci/engine/features.h"
25 #include "sci/engine/kernel.h"
26 #include "sci/engine/scriptdebug.h"
27 #include "sci/engine/state.h"
28 #include "sci/engine/selector.h"
29 
30 namespace Sci {
31 
32 #if 1
33 
34 #define FIND_SELECTOR(_slc_) _selectorCache._slc_ = findSelector(#_slc_)
35 #define FIND_SELECTOR2(_slc_, _slcstr_) _selectorCache._slc_ = findSelector(_slcstr_)
36 
37 #else
38 
39 // The defines below can be used to construct static selector tables for games which don't have
40 // a vocab.997 resource, by dumping the selector table from other similar versions or games
41 #define FIND_SELECTOR(_slc_) _selectorCache._slc_ = findSelector(#_slc_); \
42 	debugN("\t{ \"%s\", %d },\n", #_slc_, _selectorCache._slc_)
43 
44 #define FIND_SELECTOR2(_slc_, _slcstr_) _selectorCache._slc_ = findSelector(_slcstr_); \
45 	debugN("\t{ \"%s\", %d },\n", _slcstr_, _selectorCache._slc_)
46 
47 #endif
48 
mapSelectors()49 void Kernel::mapSelectors() {
50 	// species
51 	// superClass
52 	FIND_SELECTOR2(_info_, "-info-");
53 	FIND_SELECTOR(y);
54 	FIND_SELECTOR(x);
55 	FIND_SELECTOR(view);
56 	FIND_SELECTOR(loop);
57 	FIND_SELECTOR(cel);
58 	FIND_SELECTOR(underBits);
59 	FIND_SELECTOR(nsTop);
60 	FIND_SELECTOR(nsLeft);
61 	FIND_SELECTOR(nsBottom);
62 	FIND_SELECTOR(nsRight);
63 	FIND_SELECTOR(lsTop);
64 	FIND_SELECTOR(lsLeft);
65 	FIND_SELECTOR(lsBottom);
66 	FIND_SELECTOR(lsRight);
67 	FIND_SELECTOR(signal);
68 	FIND_SELECTOR(illegalBits);
69 	FIND_SELECTOR(brTop);
70 	FIND_SELECTOR(brLeft);
71 	FIND_SELECTOR(brBottom);
72 	FIND_SELECTOR(brRight);
73 	// name
74 	// key
75 	// time
76 	FIND_SELECTOR(text);
77 	FIND_SELECTOR(elements);
78 	// color
79 	// back
80 	FIND_SELECTOR(mode);
81 	// style
82 	FIND_SELECTOR(state);
83 	FIND_SELECTOR(font);
84 	FIND_SELECTOR(type);
85 	// window
86 	FIND_SELECTOR(cursor);
87 	FIND_SELECTOR(max);
88 	FIND_SELECTOR(mark);
89 	FIND_SELECTOR(sort);
90 	// who
91 	FIND_SELECTOR(message);
92 	// edit
93 	FIND_SELECTOR(play);
94 	FIND_SELECTOR(restore);
95 	FIND_SELECTOR(number);
96 	FIND_SELECTOR(handle);	// nodePtr
97 	FIND_SELECTOR(client);
98 	FIND_SELECTOR(dx);
99 	FIND_SELECTOR(dy);
100 	FIND_SELECTOR2(b_movCnt, "b-moveCnt");
101 	FIND_SELECTOR2(b_i1, "b-i1");
102 	FIND_SELECTOR2(b_i2, "b-i2");
103 	FIND_SELECTOR2(b_di, "b-di");
104 	FIND_SELECTOR2(b_xAxis, "b-xAxis");
105 	FIND_SELECTOR2(b_incr, "b-incr");
106 	FIND_SELECTOR(xStep);
107 	FIND_SELECTOR(yStep);
108 	FIND_SELECTOR(xLast);
109 	FIND_SELECTOR(yLast);
110 	FIND_SELECTOR(moveSpeed);
111 	FIND_SELECTOR(canBeHere);	// cantBeHere
112 	FIND_SELECTOR(heading);
113 	FIND_SELECTOR(mover);
114 	FIND_SELECTOR(doit);
115 	FIND_SELECTOR(isBlocked);
116 	FIND_SELECTOR(looper);
117 	FIND_SELECTOR(priority);
118 	FIND_SELECTOR(modifiers);
119 	FIND_SELECTOR(replay);
120 	// setPri
121 	// at
122 	// next
123 	// done
124 	// width
125 	FIND_SELECTOR(wordFail);
126 	FIND_SELECTOR(syntaxFail);
127 	// semanticFail
128 	// pragmaFail
129 	// said
130 	FIND_SELECTOR(claimed);
131 	// value
132 	// save
133 	// restore
134 	// title
135 	// button
136 	// icon
137 	// draw
138 	FIND_SELECTOR2(delete_, "delete");
139 	FIND_SELECTOR(z);
140 	// -----------------------------
141 	FIND_SELECTOR(size);
142 	FIND_SELECTOR(moveDone);
143 	FIND_SELECTOR(vol);
144 	FIND_SELECTOR(pri);
145 	FIND_SELECTOR(min);
146 	FIND_SELECTOR(sec);
147 	FIND_SELECTOR(frame);
148 	FIND_SELECTOR(dataInc);
149 	FIND_SELECTOR(palette);
150 	FIND_SELECTOR(cantBeHere);
151 	FIND_SELECTOR(nodePtr);
152 	FIND_SELECTOR(flags);
153 	FIND_SELECTOR(points);
154 	FIND_SELECTOR(syncCue);
155 	FIND_SELECTOR(syncTime);
156 	FIND_SELECTOR(printLang);
157 	FIND_SELECTOR(subtitleLang);
158 	FIND_SELECTOR(parseLang);
159 	FIND_SELECTOR(overlay);
160 	FIND_SELECTOR(topString);
161 	FIND_SELECTOR(scaleSignal);
162 	FIND_SELECTOR(scaleX);
163 	FIND_SELECTOR(scaleY);
164 	FIND_SELECTOR(maxScale);
165 	FIND_SELECTOR(vanishingX);
166 	FIND_SELECTOR(vanishingY);
167 	FIND_SELECTOR(iconIndex);
168 	FIND_SELECTOR(select);
169 	FIND_SELECTOR(handsOff);
170 	FIND_SELECTOR(setStep);
171 	FIND_SELECTOR(setMotion);
172 	FIND_SELECTOR(cycleSpeed);
173 	FIND_SELECTOR(owner);
174 	FIND_SELECTOR(curPos);
175 	FIND_SELECTOR(update);
176 
177 #ifdef ENABLE_SCI32
178 	FIND_SELECTOR(data);
179 	FIND_SELECTOR(picture);
180 	FIND_SELECTOR(bitmap);
181 	FIND_SELECTOR(plane);
182 	FIND_SELECTOR(top);
183 	FIND_SELECTOR(left);
184 	FIND_SELECTOR(bottom);
185 	FIND_SELECTOR(right);
186 	FIND_SELECTOR(seenRect);
187 	FIND_SELECTOR(resY);
188 	FIND_SELECTOR(resX);
189 	FIND_SELECTOR(dimmed);
190 	FIND_SELECTOR(fore);
191 	FIND_SELECTOR(back);
192 	FIND_SELECTOR(skip);
193 	FIND_SELECTOR(borderColor);
194 	FIND_SELECTOR(width);
195 	FIND_SELECTOR(fixPriority);
196 	FIND_SELECTOR(mirrored);
197 	FIND_SELECTOR(visible);
198 	FIND_SELECTOR(useInsetRect);
199 	FIND_SELECTOR(inTop);
200 	FIND_SELECTOR(inLeft);
201 	FIND_SELECTOR(inBottom);
202 	FIND_SELECTOR(inRight);
203 	FIND_SELECTOR(textTop);
204 	FIND_SELECTOR(textLeft);
205 	FIND_SELECTOR(textBottom);
206 	FIND_SELECTOR(textRight);
207 	FIND_SELECTOR(title);
208 	FIND_SELECTOR(titleFont);
209 	FIND_SELECTOR(titleFore);
210 	FIND_SELECTOR(titleBack);
211 	FIND_SELECTOR(magnifier);
212 	FIND_SELECTOR(frameOut);
213 	FIND_SELECTOR(casts);
214 	FIND_SELECTOR(setVol);
215 	FIND_SELECTOR(reSyncVol);
216 	FIND_SELECTOR(set);
217 	FIND_SELECTOR(clear);
218 	FIND_SELECTOR(show);
219 	FIND_SELECTOR(position);
220 	FIND_SELECTOR(musicVolume);
221 	FIND_SELECTOR(soundVolume);
222 	FIND_SELECTOR(initialOff);
223 	FIND_SELECTOR(setPos);
224 	FIND_SELECTOR(setSize);
225 	FIND_SELECTOR(displayValue);
226 	FIND_SELECTOR2(new_, "new");
227 	FIND_SELECTOR(mainCel);
228 	FIND_SELECTOR(move);
229 	FIND_SELECTOR(eachElementDo);
230 	FIND_SELECTOR(physicalBar);
231 	FIND_SELECTOR(init);
232 	FIND_SELECTOR(scratch);
233 	FIND_SELECTOR(num);
234 	FIND_SELECTOR(reallyRestore);
235 	FIND_SELECTOR(canInput);
236 	FIND_SELECTOR(bookMark);
237 	FIND_SELECTOR(fileNumber);
238 	FIND_SELECTOR(description);
239 	FIND_SELECTOR(dispose);
240 	FIND_SELECTOR(masterVolume);
241 	FIND_SELECTOR(setCel);
242 	FIND_SELECTOR(value);
243 #endif
244 }
245 
readSelector(SegManager * segMan,reg_t object,Selector selectorId)246 reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId) {
247 	ObjVarRef address;
248 
249 	if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
250 		return NULL_REG;
251 
252 	if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORREAD) {
253 		reg_t curValue = *address.getPointer(segMan);
254 		debugPropertyAccess(segMan->getObject(object), object, 0, selectorId,
255 			                curValue, NULL_REG, segMan, BREAK_SELECTORREAD);
256 	}
257 
258 	return *address.getPointer(segMan);
259 }
260 
261 #ifdef ENABLE_SCI32
updateInfoFlagViewVisible(Object * obj,int index,bool fromPropertyOp)262 void updateInfoFlagViewVisible(Object *obj, int index, bool fromPropertyOp) {
263 	if (getSciVersion() >= SCI_VERSION_2 && obj->mustSetViewVisible(index, fromPropertyOp)) {
264 		obj->setInfoSelectorFlag(kInfoFlagViewVisible);
265 	}
266 }
267 #endif
268 
writeSelector(SegManager * segMan,reg_t object,Selector selectorId,reg_t value)269 void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value) {
270 	ObjVarRef address;
271 
272 	if ((selectorId < 0) || (selectorId > (int)g_sci->getKernel()->getSelectorNamesSize())) {
273 		const SciCallOrigin origin = g_sci->getEngineState()->getCurrentCallOrigin();
274 		error("Attempt to write to invalid selector %d. Address %04x:%04x, %s", selectorId, PRINT_REG(object), origin.toString().c_str());
275 	}
276 
277 	if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable) {
278 		const SciCallOrigin origin = g_sci->getEngineState()->getCurrentCallOrigin();
279 		error("Selector '%s' of object could not be written to. Address %04x:%04x, %s", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object), origin.toString().c_str());
280 	}
281 
282 	if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORWRITE) {
283 		reg_t curValue = *address.getPointer(segMan);
284 		debugPropertyAccess(segMan->getObject(object), object, 0, selectorId,
285 			                curValue, value, segMan, BREAK_SELECTORWRITE);
286 	}
287 
288 	*address.getPointer(segMan) = value;
289 #ifdef ENABLE_SCI32
290 	updateInfoFlagViewVisible(segMan->getObject(object), address.varindex);
291 #endif
292 }
293 
invokeSelector(EngineState * s,reg_t object,int selectorId,int k_argc,StackPtr k_argp,int argc,const reg_t * argv)294 void invokeSelector(EngineState *s, reg_t object, int selectorId,
295 	int k_argc, StackPtr k_argp, int argc, const reg_t *argv) {
296 	int i;
297 	int framesize = 2 + 1 * argc;
298 	int slc_type;
299 	StackPtr stackframe = k_argp + k_argc;
300 
301 	stackframe[0] = make_reg(0, selectorId);  // The selector we want to call
302 	stackframe[1] = make_reg(0, argc); // Argument count
303 
304 	slc_type = lookupSelector(s->_segMan, object, selectorId, NULL, NULL);
305 
306 	if (slc_type == kSelectorNone) {
307 		const SciCallOrigin origin = g_sci->getEngineState()->getCurrentCallOrigin();
308 		error("invokeSelector: Selector '%s' could not be invoked. Address %04x:%04x, %s", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object), origin.toString().c_str());
309 	}
310 	if (slc_type == kSelectorVariable) {
311 		const SciCallOrigin origin = g_sci->getEngineState()->getCurrentCallOrigin();
312 		error("invokeSelector: Attempting to invoke variable selector %s. Address %04x:%04x, %s", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object), origin.toString().c_str());
313 	}
314 
315 	for (i = 0; i < argc; i++)
316 		stackframe[2 + i] = argv[i]; // Write each argument
317 
318 	ExecStack *xstack;
319 
320 	// Now commit the actual function:
321 	xstack = send_selector(s, object, object, stackframe, framesize, stackframe);
322 
323 	xstack->sp += argc + 2;
324 	xstack->fp += argc + 2;
325 
326 	run_vm(s); // Start a new vm
327 }
328 
lookupSelector(SegManager * segMan,reg_t obj_location,Selector selectorId,ObjVarRef * varp,reg_t * fptr)329 SelectorType lookupSelector(SegManager *segMan, reg_t obj_location, Selector selectorId, ObjVarRef *varp, reg_t *fptr) {
330 	const Object *obj = segMan->getObject(obj_location);
331 	int index;
332 	bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
333 
334 	// Early SCI versions used the LSB in the selector ID as a read/write
335 	// toggle, meaning that we must remove it for selector lookup.
336 	if (oldScriptHeader)
337 		selectorId &= ~1;
338 
339 	if (!obj) {
340 		const SciCallOrigin origin = g_sci->getEngineState()->getCurrentCallOrigin();
341 		error("lookupSelector: Attempt to send to non-object or invalid script. Address %04x:%04x, %s", PRINT_REG(obj_location), origin.toString().c_str());
342 	}
343 
344 	index = obj->locateVarSelector(segMan, selectorId);
345 
346 	if (index >= 0) {
347 		// Found it as a variable
348 		if (varp) {
349 			varp->obj = obj_location;
350 			varp->varindex = index;
351 		}
352 		return kSelectorVariable;
353 	} else {
354 		// Check if it's a method, with recursive lookup in superclasses
355 		while (obj) {
356 			index = obj->funcSelectorPosition(selectorId);
357 			if (index >= 0) {
358 				if (fptr)
359 					*fptr = obj->getFunction(index);
360 
361 				return kSelectorMethod;
362 			} else {
363 				obj = segMan->getObject(obj->getSuperClassSelector());
364 			}
365 		}
366 
367 		return kSelectorNone;
368 	}
369 
370 
371 //	return _lookupSelector_function(segMan, obj, selectorId, fptr);
372 }
373 
374 } // End of namespace Sci
375