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 #ifndef DIRECTOR_LINGO_LINGO_H 24 #define DIRECTOR_LINGO_LINGO_H 25 26 #include "common/hash-ptr.h" 27 #include "common/hash-str.h" 28 #include "common/str-array.h" 29 #include "common/queue.h" 30 #include "common/rect.h" 31 32 #include "director/types.h" 33 34 namespace Audio { 35 class AudioStream; 36 } 37 namespace Common { 38 class SeekableReadStreamEndian; 39 } 40 41 namespace Director { 42 43 struct ChunkReference; 44 struct TheEntity; 45 struct TheEntityField; 46 struct LingoArchive; 47 struct LingoV4Bytecode; 48 struct LingoV4TheEntity; 49 struct Node; 50 class AbstractObject; 51 class Cast; 52 class ScriptContext; 53 class DirectorEngine; 54 class Frame; 55 class LingoCompiler; 56 57 typedef void (*inst)(void); 58 #define STOP (inst)0 59 #define ENTITY_INDEX(t,id) ((t) * 100000 + (id)) 60 61 int calcStringAlignment(const char *s); 62 int calcCodeAlignment(int l); 63 64 typedef Common::Array<inst> ScriptData; 65 66 struct FuncDesc { 67 Common::String name; 68 const char *proto; 69 FuncDescFuncDesc70 FuncDesc(Common::String n, const char *p) { name = n; proto = p; } 71 }; 72 73 typedef Common::HashMap<void *, FuncDesc *> FuncHash; 74 75 struct BuiltinProto { 76 const char *name; 77 void (*func)(int); 78 int minArgs; // -1 -- arglist 79 int maxArgs; 80 int version; 81 SymbolType type; 82 }; 83 84 struct Symbol { /* symbol table entry */ 85 Common::String *name; 86 SymbolType type; 87 union { 88 ScriptData *defn; /* HANDLER */ 89 void (*func)(); /* OPCODE */ 90 void (*bltin)(int); /* BUILTIN */ 91 Common::String *s; /* STRING */ 92 } u; 93 94 int *refCount; 95 96 int nargs; /* number of arguments */ 97 int maxArgs; /* maximal number of arguments, for builtins */ 98 int targetType; /* valid target objects, for method builtins */ 99 100 Common::Array<Common::String> *argNames; 101 Common::Array<Common::String> *varNames; 102 ScriptContext *ctx; /* optional script context to execute with */ 103 AbstractObject *target; /* optional method target */ 104 bool anonymous; 105 106 Symbol(); 107 Symbol(const Symbol &s); 108 Symbol& operator=(const Symbol &s); 109 void reset(); 110 ~Symbol(); 111 }; 112 113 struct PArray { 114 bool _sorted; 115 PropertyArray arr; 116 PArrayPArray117 PArray() : _sorted(false) {} 118 PArrayPArray119 PArray(int size) : _sorted(false), arr(size) {} 120 }; 121 122 struct FArray { 123 bool _sorted; 124 DatumArray arr; 125 FArrayFArray126 FArray() : _sorted(false) {} 127 FArrayFArray128 FArray(int size) : _sorted(false), arr(size) {} 129 }; 130 131 132 struct Datum { /* interpreter stack type */ 133 DatumType type; 134 135 union { 136 int i; /* INT, ARGC, ARGCNORET */ 137 double f; /* FLOAT */ 138 Common::String *s; /* STRING, VARREF, OBJECT */ 139 FArray *farr; /* ARRAY, POINT, RECT */ 140 PArray *parr; /* PARRAY */ 141 AbstractObject *obj; /* OBJECT */ 142 ChunkReference *cref; /* CHUNKREF */ 143 CastMemberID *cast; /* CASTREF, FIELDREF */ 144 } u; 145 146 int *refCount; 147 148 Datum(); 149 Datum(const Datum &d); 150 Datum& operator=(const Datum &d); 151 Datum(int val); 152 Datum(double val); 153 Datum(const Common::String &val); 154 Datum(AbstractObject *val); 155 Datum(const CastMemberID &val); 156 Datum(const Common::Rect &rect); 157 void reset(); 158 ~DatumDatum159 ~Datum() { 160 reset(); 161 } 162 163 Datum eval() const; 164 double asFloat() const; 165 int asInt() const; 166 Common::String asString(bool printonly = false) const; 167 CastMemberID asMemberID() const; 168 Common::Point asPoint() const; 169 170 bool isRef() const; 171 bool isVarRef() const; 172 bool isCastRef() const; 173 174 const char *type2str(bool isk = false) const; 175 176 int equalTo(Datum &d, bool ignoreCase = false) const; 177 int compareTo(Datum &d) const; 178 }; 179 180 struct ChunkReference { 181 Datum source; 182 ChunkType type; 183 int startChunk; 184 int endChunk; 185 int start; 186 int end; 187 ChunkReferenceChunkReference188 ChunkReference(const Datum &src, ChunkType t, int sc, int ec, int s, int e) 189 : source(src), type(t), startChunk(sc), endChunk(ec), start(s), end(e) {} 190 }; 191 192 struct PCell { 193 Datum p; 194 Datum v; 195 196 PCell(); 197 PCell(const Datum &prop, const Datum &val); 198 }; 199 200 struct Builtin { 201 void (*func)(void); 202 int nargs; 203 BuiltinBuiltin204 Builtin(void (*func1)(void), int nargs1) : func(func1), nargs(nargs1) {} 205 }; 206 207 typedef Common::HashMap<int32, ScriptContext *> ScriptContextHash; 208 typedef Common::Array<Datum> StackData; 209 typedef Common::HashMap<Common::String, Symbol, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SymbolHash; 210 typedef Common::HashMap<Common::String, Datum, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> DatumHash; 211 typedef Common::HashMap<Common::String, Builtin *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> BuiltinHash; 212 typedef Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> VarTypeHash; 213 typedef void (*XLibFunc)(int); 214 typedef Common::HashMap<Common::String, XLibFunc, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> XLibFuncHash; 215 typedef Common::HashMap<Common::String, ObjectType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> OpenXLibsHash; 216 217 typedef Common::HashMap<Common::String, TheEntity *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> TheEntityHash; 218 typedef Common::HashMap<Common::String, TheEntityField *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> TheEntityFieldHash; 219 220 struct CFrame { /* proc/func call stack frame */ 221 Symbol sp; /* symbol table entry */ 222 int retPC; /* where to resume after return */ 223 ScriptData *retScript; /* which script to resume after return */ 224 ScriptContext *retContext; /* which script context to use after return */ 225 bool retFreezeContext; /* whether the context should be frozen after return */ 226 DatumHash *retLocalVars; 227 Datum retMe; /* which me obj to use after return */ 228 uint stackSizeBefore; 229 bool allowRetVal; /* whether to allow a return value */ 230 Datum defaultRetVal; /* default return value */ 231 }; 232 233 struct LingoEvent { 234 LEvent event; 235 int eventId; 236 ScriptType scriptType; 237 CastMemberID scriptId; 238 bool passByDefault; 239 int channelId; 240 241 LingoEvent (LEvent e, int ei, ScriptType st, CastMemberID si, bool pass, int ci = -1) { 242 event = e; 243 eventId = ei; 244 scriptType = st; 245 scriptId = si; 246 passByDefault = pass; 247 channelId = ci; 248 } 249 }; 250 251 252 struct LingoArchive { LingoArchiveLingoArchive253 LingoArchive(Cast *c) : cast(c) {}; 254 ~LingoArchive(); 255 256 Cast *cast; 257 ScriptContextHash lctxContexts; 258 ScriptContextHash scriptContexts[kMaxScriptType + 1]; 259 Common::Array<Common::String> names; 260 Common::HashMap<uint32, Common::String> primaryEventHandlers; 261 SymbolHash functionHandlers; 262 263 ScriptContext *getScriptContext(ScriptType type, uint16 id); 264 Common::String getName(uint16 id); 265 266 void addCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName = nullptr); 267 void removeCode(ScriptType type, uint16 id); 268 void replaceCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName = nullptr); 269 void addCodeV4(Common::SeekableReadStreamEndian &stream, uint16 lctxIndex, const Common::String &archName, uint16 version); 270 void addNamesV4(Common::SeekableReadStreamEndian &stream); 271 }; 272 273 class Lingo { 274 275 public: 276 Lingo(DirectorEngine *vm); 277 ~Lingo(); 278 279 void resetLingo(); 280 281 void executeHandler(const Common::String &name); 282 void executeScript(ScriptType type, CastMemberID id); 283 void printStack(const char *s, uint pc); 284 void printCallStack(uint pc); 285 Common::String decodeInstruction(ScriptData *sd, uint pc, uint *newPC = NULL); 286 287 void reloadBuiltIns(); 288 void initBuiltIns(); 289 void initBuiltIns(BuiltinProto protos[]); 290 void cleanupBuiltIns(); 291 void cleanupBuiltIns(BuiltinProto protos[]); 292 void initFuncs(); 293 void cleanupFuncs(); 294 void initBytecode(); 295 void initMethods(); 296 void cleanupMethods(); 297 void initXLibs(); 298 void cleanupXLibs(); 299 300 Common::String normalizeXLibName(Common::String name); 301 void openXLib(Common::String name, ObjectType type); 302 void closeXLib(Common::String name); 303 void reloadOpenXLibs(); 304 305 void runTests(); 306 307 // lingo-events.cpp 308 private: 309 void initEventHandlerTypes(); 310 void processEvent(LEvent event, ScriptType st, CastMemberID scriptId, int channelId = -1); 311 312 public: 313 ScriptType event2script(LEvent ev); 314 Symbol getHandler(const Common::String &name); 315 316 void processEvents(Common::Queue<LingoEvent> &queue); 317 318 public: 319 void execute(); 320 void loadStateFromWindow(); 321 void saveStateToWindow(); 322 void pushContext(const Symbol funcSym, bool allowRetVal, Datum defaultRetVal); 323 void popContext(bool aborting = false); 324 bool hasFrozenContext(); 325 void cleanLocalVars(); 326 void varAssign(const Datum &var, const Datum &value); 327 Datum varFetch(const Datum &var, bool silent = false); 328 Common::U32String evalChunkRef(const Datum &var); 329 Datum findVarV4(int varType, const Datum &id); 330 CastMemberID resolveCastMember(const Datum &memberID, const Datum &castLib); 331 332 int getAlignedType(const Datum &d1, const Datum &d2, bool numsOnly); 333 334 void printAllVars(); 335 readInst()336 inst readInst() { return getInst(_pc++); } getInst(uint pc)337 inst getInst(uint pc) { return (*_currentScript)[pc]; } readInt()338 int readInt() { return getInt(_pc++); } 339 int getInt(uint pc); readFloat()340 double readFloat() { double d = getFloat(_pc); _pc += calcCodeAlignment(sizeof(double)); return d; } getFloat(uint pc)341 double getFloat(uint pc) { return *(double *)(&((*_currentScript)[pc])); } readString()342 char *readString() { char *s = getString(_pc); _pc += calcStringAlignment(s); return s; } getString(uint pc)343 char *getString(uint pc) { return (char *)(&((*_currentScript)[pc])); } 344 345 void pushVoid(); 346 347 void printSTUBWithArglist(const char *funcname, int nargs, const char *prefix = "STUB:"); 348 void convertVOIDtoString(int arg, int nargs); 349 void dropStack(int nargs); 350 void drop(uint num); 351 352 void lingoError(const char *s, ...); 353 354 void func_mci(const Common::String &name); 355 void func_mciwait(const Common::String &name); 356 void func_beep(int repeats); 357 void func_goto(Datum &frame, Datum &movie); 358 void func_gotoloop(); 359 void func_gotonext(); 360 void func_gotoprevious(); 361 void func_play(Datum &frame, Datum &movie); 362 void func_playdone(); 363 void func_cursor(Datum cursorDatum); 364 int func_marker(int m); 365 uint16 func_label(Datum &label); 366 367 // lingo-the.cpp 368 public: 369 void initTheEntities(); 370 void cleanUpTheEntities(); 371 const char *entity2str(int id); 372 const char *field2str(int id); 373 374 // global kTheEntity 375 Common::u32char_type_t _itemDelimiter; 376 377 Datum getTheEntity(int entity, Datum &id, int field); 378 void setTheEntity(int entity, Datum &id, int field, Datum &d); 379 Datum getTheMenuItemEntity(int entity, Datum &menuId, int field, Datum &menuItemId); 380 void setTheMenuItemEntity(int entity, Datum &menuId, int field, Datum &menuItemId, Datum &d); 381 Datum getTheSprite(Datum &id, int field); 382 void setTheSprite(Datum &id, int field, Datum &d); 383 Datum getTheCast(Datum &id, int field); 384 void setTheCast(Datum &id, int field, Datum &d); 385 Datum getTheField(Datum &id1, int field); 386 void setTheField(Datum &id1, int field, Datum &d); 387 Datum getTheChunk(Datum &chunk, int field); 388 void setTheChunk(Datum &chunk, int field, Datum &d); 389 void getObjectProp(Datum &obj, Common::String &propName); 390 void setObjectProp(Datum &obj, Common::String &propName, Datum &d); 391 Datum getTheDate(int field); 392 Datum getTheTime(int field); 393 394 private: 395 Common::StringArray _entityNames; 396 Common::StringArray _fieldNames; 397 398 public: 399 LingoCompiler *_compiler; 400 401 int _currentChannelId; 402 ScriptContext *_currentScriptContext; 403 ScriptData *_currentScript; 404 Datum _currentMe; 405 406 bool _freezeContext; 407 bool _abort; 408 bool _expectError; 409 bool _caughtError; 410 411 TheEntityHash _theEntities; 412 TheEntityFieldHash _theEntityFields; 413 414 int _objectEntityId; 415 416 SymbolHash _builtinCmds; 417 SymbolHash _builtinFuncs; 418 SymbolHash _builtinConsts; 419 SymbolHash _methods; 420 XLibFuncHash _xlibOpeners; 421 XLibFuncHash _xlibClosers; 422 423 OpenXLibsHash _openXLibs; 424 425 Common::String _floatPrecisionFormat; 426 427 public: 428 void push(Datum d); 429 Datum pop(); 430 Datum peek(uint offset); 431 432 public: 433 Common::HashMap<uint32, const char *> _eventHandlerTypes; 434 Common::HashMap<Common::String, uint32, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _eventHandlerTypeIds; 435 Common::HashMap<Common::String, Audio::AudioStream *> _audioAliases; 436 437 DatumHash _globalvars; 438 DatumHash *_localvars; 439 440 FuncHash _functions; 441 442 Common::HashMap<int, LingoV4Bytecode *> _lingoV4; 443 Common::HashMap<int, LingoV4TheEntity *> _lingoV4TheEntity; 444 445 uint _globalCounter; 446 uint _pc; 447 448 StackData _stack; 449 450 DirectorEngine *_vm; 451 452 int _floatPrecision; 453 454 Datum _theResult; 455 456 // events 457 bool _passEvent; 458 Datum _perFrameHook; 459 460 Datum _windowList; 461 462 public: 463 void executeImmediateScripts(Frame *frame); 464 void executePerFrameHook(int frame, int subframe); 465 466 // lingo-utils.cpp 467 private: 468 Common::HashMap<uint32, Common::U32String> _charNormalizations; 469 void initCharNormalizations(); 470 471 public: 472 Common::String normalizeString(const Common::String &str); 473 }; 474 475 extern Lingo *g_lingo; 476 477 } // End of namespace Director 478 479 #endif 480