]> git.localhorst.tv Git - l2e.git/blob - src/loader/Interpreter.cpp
0fd2d883fba0a8129b3a896dd56d37f35e4af96f
[l2e.git] / src / loader / Interpreter.cpp
1 /*
2  * Interpreter.cpp
3  *
4  *  Created on: Aug 26, 2012
5  *      Author: holy
6  */
7
8 #include "Interpreter.h"
9
10 #include "ParsedSource.h"
11 #include "../battle/Hero.h"
12 #include "../battle/Monster.h"
13 #include "../battle/PartyLayout.h"
14 #include "../battle/Resources.h"
15 #include "../common/Ikari.h"
16 #include "../common/Item.h"
17 #include "../common/Script.h"
18 #include "../common/Spell.h"
19 #include "../common/Stats.h"
20 #include "../common/TargetingMode.h"
21 #include "../graphics/ComplexAnimation.h"
22 #include "../graphics/Font.h"
23 #include "../graphics/Frame.h"
24 #include "../graphics/Gauge.h"
25 #include "../graphics/Menu.h"
26 #include "../graphics/SimpleAnimation.h"
27 #include "../graphics/Sprite.h"
28
29 #include <algorithm>
30 #include <cstring>
31 #include <SDL_image.h>
32
33 using battle::Hero;
34 using battle::Monster;
35 using battle::PartyLayout;
36 using common::Ikari;
37 using common::Item;
38 using common::Script;
39 using common::Spell;
40 using common::Stats;
41 using common::TargetingMode;
42 using graphics::Animation;
43 using graphics::Color;
44 using graphics::Font;
45 using graphics::Frame;
46 using graphics::Gauge;
47 using graphics::ComplexAnimation;
48 using graphics::SimpleAnimation;
49 using graphics::Sprite;
50 using geometry::Vector;
51 using std::make_pair;
52 using std::set;
53 using std::string;
54 using std::vector;
55
56 namespace loader {
57
58 Interpreter::~Interpreter() {
59         for (std::map<string, SDL_Surface *>::const_iterator i(imageCache.begin()), end(imageCache.end()); i != end; ++i) {
60                 SDL_FreeSurface(i->second);
61         }
62 }
63
64
65 const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &identifier) {
66         std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(identifier));
67         if (i != parsedDefinitions.end()) {
68                 return i->second;
69         } else if (source.IsDefined(identifier)) {
70                 ReadDefinition(source.GetDefinition(identifier));
71                 return parsedDefinitions.at(identifier);
72         } else {
73                 throw Error("access to undefined object " + identifier);
74         }
75 }
76
77
78 void *Interpreter::GetObject(int typeId, const std::string &name) {
79         std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
80         if (i != parsedDefinitions.end()) {
81                 const TypeDescription &requested(TypeDescription::Get(typeId));
82                 const TypeDescription &actual(TypeDescription::Get(i->second.type));
83                 if (requested.TypeId() == actual.TypeId()) {
84                         return values[actual.TypeId()][i->second.id];
85                 } else if (actual.IsSubtypeOf(requested)) {
86                         char *sub(reinterpret_cast<char *>(values[actual.TypeId()][i->second.id]));
87                         std::ptrdiff_t offset(actual.SupertypeOffset(requested));
88                         return sub - offset;
89                 } else {
90                         throw Error("cannot cast " + actual.TypeName() + " to " + requested.TypeName());
91                 }
92         } else {
93                 throw Error("access to undefined object " + name);
94         }
95 }
96
97
98 void Interpreter::ReadSource() {
99         for (set<string>::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) {
100                 ReadDefinition(source.GetDefinition(*i));
101         }
102 }
103
104 void Interpreter::ReadDefinition(const Definition &dfn) {
105         if (parsedDefinitions.find(dfn.Identifier()) != parsedDefinitions.end()) {
106                 return;
107         }
108         if (dfn.HasLiteralValue()) {
109                 ReadLiteral(dfn);
110         } else {
111                 ReadObject(dfn);
112         }
113 }
114
115 void Interpreter::ReadLiteral(const Definition &dfn) {
116         const string &typeName(dfn.GetLiteral()->IsArray() ? "Array" : dfn.GetLiteral()->GetTypeName());
117         int typeId(TypeDescription::GetTypeId(typeName));
118         int id(values[typeId].size());
119         const TypeDescription &td(TypeDescription::Get(typeId));
120         int size(
121                         (dfn.GetLiteral()->GetType() == Literal::PATH
122                                         || dfn.GetLiteral()->GetType() == Literal::STRING)
123                         ? dfn.GetLiteral()->GetString().size() : td.Size());
124         char *object(alloc.Alloc(size));
125         values[typeId].push_back(object);
126         parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
127         if (dfn.GetLiteral()->GetType() == Literal::OBJECT) {
128                 ReadObject(typeId, id, object, *dfn.GetLiteral()->GetProperties());
129         } else {
130                 ReadLiteral(typeId, id, object, *dfn.GetLiteral());
131         }
132 }
133
134 void Interpreter::ReadLiteral(int typeId, int id, char *object, const Literal &literal) {
135         switch (literal.GetType()) {
136                 case Literal::ARRAY_VALUES:
137                         throw Error("named value arrays are not supported, sorry");
138                         break;
139                 case Literal::ARRAY_PROPS:
140                         throw Error("named property list arrays are not supported, sorry");
141                         break;
142                 case Literal::BOOLEAN:
143                         new (object) bool(literal.GetBoolean());
144                         break;
145                 case Literal::COLOR:
146                         new (object) Color(literal.GetRed(), literal.GetGreen(), literal.GetBlue(), literal.GetAlpha());
147                         break;
148                 case Literal::NUMBER:
149                         new (object) int(literal.GetNumber());
150                         break;
151                 case Literal::PATH:
152                         std::memcpy(object, literal.GetString().c_str(), literal.GetString().size());
153                         object[literal.GetString().size()] = '\0';
154                         break;
155                 case Literal::SCRIPT:
156                         new (object) Script;
157                         ReadScript(literal.GetScript(), reinterpret_cast<Script *>(object));
158                         break;
159                 case Literal::STRING:
160                         std::memcpy(object, literal.GetString().c_str(), literal.GetString().size());
161                         object[literal.GetString().size()] = '\0';
162                         break;
163                 case Literal::VECTOR:
164                         new (object) Vector<int>(literal.GetX(), literal.GetY());
165                         break;
166                 case Literal::OBJECT:
167                         throw Error("illogical branch: read literal object as non-object literal");
168         }
169 }
170
171
172 void *Interpreter::GetObject(int typeId, const Value &v) {
173         if (v.IsLiteral()) {
174                 if (v.GetLiteral().IsObject()) {
175                         int typeId(TypeDescription::GetTypeId(v.GetLiteral().GetTypeName()));
176                         const TypeDescription &td(TypeDescription::Get(typeId));
177                         char *object(alloc.Alloc(td.Size()));
178                         td.Construct(object);
179                         int id(values[typeId].size());
180                         values[typeId].push_back(object);
181                         ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
182                         return object;
183                 } else {
184                         int typeId(0), id(0);
185                         switch (v.GetLiteral().GetType()) {
186                                 case Literal::ARRAY_VALUES:
187                                         throw Error("cannot copy value arrays, sorry");
188                                         break;
189                                 case Literal::ARRAY_PROPS:
190                                         throw Error("cannot copy property list arrays, sorry");
191                                         break;
192                                 case Literal::BOOLEAN:
193                                         {
194                                                 typeId = TypeDescription::GetTypeId("Boolean");
195                                                 id = values[typeId].size();
196                                                 const TypeDescription &td(TypeDescription::Get(typeId));
197                                                 char *object(alloc.Alloc(td.Size()));
198                                                 values[typeId].push_back(new (object) bool(v.GetLiteral().GetBoolean()));
199                                         }
200                                         break;
201                                 case Literal::COLOR:
202                                         {
203                                                 typeId = TypeDescription::GetTypeId("Color");
204                                                 id = values[typeId].size();
205                                                 const TypeDescription &td(TypeDescription::Get(typeId));
206                                                 char *object(alloc.Alloc(td.Size()));
207                                                 values[typeId].push_back(new (object) Color(v.GetLiteral().GetRed(), v.GetLiteral().GetGreen(), v.GetLiteral().GetBlue(), v.GetLiteral().GetAlpha()));
208                                         }
209                                         break;
210                                 case Literal::NUMBER:
211                                         {
212                                                 typeId = TypeDescription::GetTypeId("Number");
213                                                 id = values[typeId].size();
214                                                 const TypeDescription &td(TypeDescription::Get(typeId));
215                                                 char *object(alloc.Alloc(td.Size()));
216                                                 values[typeId].push_back(new (object) int(v.GetLiteral().GetNumber()));
217                                         }
218                                         break;
219                                 case Literal::PATH:
220                                         {
221                                                 typeId = TypeDescription::GetTypeId("Path");
222                                                 id = values[typeId].size();
223                                                 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
224                                                 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
225                                                 str[v.GetLiteral().GetString().size()] = '\0';
226                                                 values[typeId].push_back(str);
227                                         }
228                                         break;
229                                 case Literal::SCRIPT:
230                                         {
231                                                 typeId = TypeDescription::GetTypeId("Script");
232                                                 char *script(ReadScript(v.GetLiteral().GetScript()));
233                                                 id = values[typeId].size();
234                                                 values[typeId].push_back(script);
235                                         }
236                                         break;
237                                 case Literal::STRING:
238                                         {
239                                                 typeId = TypeDescription::GetTypeId("String");
240                                                 id = values[typeId].size();
241                                                 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
242                                                 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
243                                                 str[v.GetLiteral().GetString().size()] = '\0';
244                                                 values[typeId].push_back(str);
245                                         }
246                                         break;
247                                 case Literal::VECTOR:
248                                         {
249                                                 typeId = TypeDescription::GetTypeId("Vector");
250                                                 id = values[typeId].size();
251                                                 const TypeDescription &td(TypeDescription::Get(typeId));
252                                                 char *object(alloc.Alloc(td.Size()));
253                                                 values[typeId].push_back(new (object) Vector<int>(v.GetLiteral().GetX(), v.GetLiteral().GetY()));
254                                         }
255                                         break;
256                                 case Literal::OBJECT:
257                                         {
258                                                 typeId = TypeDescription::GetTypeId(v.GetLiteral().GetTypeName());
259                                                 const TypeDescription &td(TypeDescription::Get(typeId));
260                                                 id = values[typeId].size();
261                                                 char *object(alloc.Alloc(td.Size()));
262                                                 td.Construct(object);
263                                                 ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
264                                         }
265                                         break;
266                         }
267                         return values[typeId][id];
268                 }
269         } else {
270                 ReadDefinition(source.GetDefinition(v.GetIdentifier()));
271                 return GetObject(typeId, v.GetIdentifier());
272         }
273 }
274
275
276 void Interpreter::ReadObject(const Definition &dfn) {
277         int typeId(TypeDescription::GetTypeId(dfn.TypeName()));
278         const TypeDescription &td(TypeDescription::Get(typeId));
279         int id(values[typeId].size());
280         char *object(alloc.Alloc(td.Size()));
281         td.Construct(object);
282         values[typeId].push_back(object);
283         parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
284         ReadObject(typeId, id, object, *dfn.GetProperties());
285 }
286
287
288 void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyList &props) {
289         const TypeDescription &td(TypeDescription::Get(typeId));
290         for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) {
291                 const FieldDescription &fd(td.GetField(i->first));
292                 const TypeDescription &fieldType(TypeDescription::Get(fd.TypeId()));
293                 if (CanLink(*i->second)) {
294                         char *dest(object + fd.Offset());
295                         if (fd.IsAggregate()) {
296                                 int arraySize(i->second->GetLiteral().ArraySize());
297                                 char *aggregate(alloc.Alloc(fieldType.Size() * arraySize));
298                                 char *iter(aggregate);
299                                 if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) {
300                                         const vector<PropertyList *> &list(i->second->GetLiteral().GetPropertyLists());
301                                         for (vector<PropertyList *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
302                                                 fieldType.Construct(iter);
303                                                 ReadObject(fieldType.TypeId(), -1, iter, **j);
304                                         }
305                                 } else {
306                                         const vector<Value *> &list(i->second->GetLiteral().GetValues());
307                                         for (vector<Value *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
308                                                 fieldType.Construct(iter);
309                                                 ReadLiteral(fieldType.TypeId(), -1, iter, (*j)->GetLiteral());
310                                         }
311                                 }
312                                 if (fd.IsReferenced()) {
313                                         std::memcpy(dest, &aggregate, sizeof(char *));
314                                         dest += sizeof(char *);
315                                         std::memcpy(dest, &arraySize, sizeof(int));
316                                 } else {
317                                         throw Error("aggregate type fields must be referenced");
318                                 }
319                         } else if (i->second->IsLiteral() && !fd.IsReferenced()) {
320                                 // inline literals
321                                 if (i->second->GetLiteral().IsObject()) {
322                                         ReadObject(fd.TypeId(), -1, dest, *i->second->GetLiteral().GetProperties());
323                                 } else {
324                                         ReadLiteral(fd.TypeId(), -1, dest, i->second->GetLiteral());
325                                 }
326                         } else {
327                                 char *src(reinterpret_cast<char *>(GetObject(fd.TypeId(), *i->second)));
328                                 if (fd.TypeId() == TypeDescription::GetTypeId("Image")) {
329                                         src = reinterpret_cast<char *>(GetImage(src));
330                                 }
331                                 if (fd.IsReferenced()) {
332                                         std::memcpy(dest, &src, sizeof(char *));
333                                 } else {
334                                         std::memcpy(dest, src, fieldType.Size());
335                                 }
336                         }
337                 } else {
338                         Postpone(typeId, id, fd.Offset(), i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced());
339                 }
340         }
341         td.Load(object);
342 }
343
344
345 void Interpreter::ReadScript(const std::vector<ScriptToken *> &s, Script *script) {
346         int size(0);
347         for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
348                 if ((*i)->GetType() != ScriptToken::COMMAND) {
349                         throw Error("unexpected script token");
350                 }
351                 ++size;
352                 const string &cmd((*i)->CommandName());
353                 if (cmd == "move") {
354                         ++i;
355                         if (i == end) {
356                                 throw Error("unexpected script end after move");
357                         }
358                         const string &reg((*i)->RegisterName());
359                         switch (reg[0]) {
360                                 case 'a':
361                                         size += sizeof(void *);
362                                         break;
363                                 case 'i':
364                                         size += sizeof(int);
365                                         break;
366                                 case 'v':
367                                         size += sizeof(Vector<int>);
368                                         break;
369                                 default:
370                                         throw Error("unknown register " + reg);
371                         }
372                         ++i;
373                         if (i == end) {
374                                 throw Error("unexpected script end after move");
375                         }
376                 } else if (cmd == "add") {
377                         ++i;
378                         if (i == end) {
379                                 throw Error("unexpected script end after add");
380                         }
381                         const string &reg((*i)->RegisterName());
382                         switch (reg[0]) {
383                                 case 'i':
384                                         size += sizeof(int);
385                                         break;
386                                 case 'v':
387                                         size += sizeof(Vector<int>);
388                                         break;
389                                 default:
390                                         throw Error("expected register after add " + reg);
391                         }
392                         ++i;
393                         if (i == end) {
394                                 throw Error("unexpected script end after add");
395                         }
396                 } else if (cmd == "mod") {
397                         ++i;
398                         if (i == end) {
399                                 throw Error("unexpected script end after mod");
400                         }
401                         size += sizeof(int);
402                         ++i;
403                         if (i == end) {
404                                 throw Error("unexpected script end after mod");
405                         }
406                 } else if (cmd == "rand") {
407                         ++i;
408                         if (i == end) {
409                                 throw Error("unexpected script end after rand");
410                         }
411                         size += sizeof(int);
412                         ++i;
413                         if (i == end) {
414                                 throw Error("unexpected script end after rand");
415                         }
416                 } else if (cmd == "sysc") {
417
418                 } else {
419                         throw Error("unknown command " + cmd);
420                 }
421         }
422
423         unsigned char *text(reinterpret_cast<unsigned char *>(alloc.Alloc(size)));
424         int cursor(0);
425         for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
426                 if ((*i)->GetType() != ScriptToken::COMMAND) {
427                         throw Error("unexpected script token");
428                 }
429                 const string &cmd((*i)->CommandName());
430                 if (cmd == "move") {
431                         ++i;
432                         const string &reg((*i)->RegisterName());
433                         ++i;
434                         if (reg == "a0") {
435                                 text[cursor] = Script::CODE_MOVE_A0;
436                                 ++cursor;
437                                 ReadScriptAddress(**i, text + cursor);
438                                 cursor += sizeof(void *);
439                         } else if (reg == "a1") {
440                                 text[cursor] = Script::CODE_MOVE_A1;
441                                 ++cursor;
442                                 ReadScriptAddress(**i, text + cursor);
443                                 cursor += sizeof(void *);
444                         } else if (reg == "i0") {
445                                 text[cursor] = Script::CODE_MOVE_I0;
446                                 ++cursor;
447                                 ReadScriptInteger(**i, text + cursor);
448                                 cursor += sizeof(int);
449                         } else if (reg == "i1") {
450                                 text[cursor] = Script::CODE_MOVE_I1;
451                                 ++cursor;
452                                 ReadScriptInteger(**i, text + cursor);
453                                 cursor += sizeof(int);
454                         } else if (reg == "v0") {
455                                 text[cursor] = Script::CODE_MOVE_V0;
456                                 ++cursor;
457                                 ReadScriptVector(**i, text + cursor);
458                                 cursor += sizeof(Vector<int>);
459                         } else if (reg == "v1") {
460                                 text[cursor] = Script::CODE_MOVE_V1;
461                                 ++cursor;
462                                 ReadScriptVector(**i, text + cursor);
463                                 cursor += sizeof(Vector<int>);
464                         } else {
465                                 throw Error("unknown register " + reg);
466                         }
467                 } else if (cmd == "add") {
468                         ++i;
469                         const string &reg((*i)->RegisterName());
470                         ++i;
471                         if (reg == "i0") {
472                                 text[cursor] = Script::CODE_ADD_I0;
473                                 ++cursor;
474                                 ReadScriptInteger(**i, text + cursor);
475                                 cursor += sizeof(int);
476                         } else if (reg == "i1") {
477                                 text[cursor] = Script::CODE_ADD_I1;
478                                 ++cursor;
479                                 ReadScriptInteger(**i, text + cursor);
480                                 cursor += sizeof(int);
481                         } else if (reg == "v0") {
482                                 text[cursor] = Script::CODE_ADD_V0;
483                                 ++cursor;
484                                 ReadScriptVector(**i, text + cursor);
485                                 cursor += sizeof(Vector<int>);
486                         } else if (reg == "v1") {
487                                 text[cursor] = Script::CODE_ADD_V1;
488                                 ++cursor;
489                                 ReadScriptVector(**i, text + cursor);
490                                 cursor += sizeof(Vector<int>);
491                         } else {
492                                 throw Error("unexpected register " + reg);
493                         }
494                 } else if (cmd == "mod") {
495                         ++i;
496                         const string &reg((*i)->RegisterName());
497                         ++i;
498                         if (reg == "i0") {
499                                 text[cursor] = Script::CODE_MOD_I0;
500                                 ++cursor;
501                                 ReadScriptInteger(**i, text + cursor);
502                                 cursor += sizeof(int);
503                         } else if (reg == "i1") {
504                                 text[cursor] = Script::CODE_MOD_I1;
505                                 ++cursor;
506                                 ReadScriptInteger(**i, text + cursor);
507                                 cursor += sizeof(int);
508                         } else {
509                                 throw Error("unexpected register " + reg);
510                         }
511                 } else if (cmd == "rand") {
512                         ++i;
513                         const string &reg((*i)->RegisterName());
514                         if (reg == "i0") {
515                                 text[cursor] = Script::CODE_RAND_I0;
516                                 ++cursor;
517                         } else if (reg == "i1") {
518                                 text[cursor] = Script::CODE_RAND_I1;
519                                 ++cursor;
520                         } else {
521                                 throw Error("unexpected register " + reg);
522                         }
523                 } else if (cmd == "sysc") {
524                         text[cursor] = Script::CODE_SYSCALL;
525                         ++cursor;
526                 } else {
527                         throw Error("unknown command " + cmd);
528                 }
529         }
530
531         script->text = text;
532         script->textlen = size;
533 }
534
535 char *Interpreter::ReadScript(const vector<ScriptToken *> &s) {
536         char *mem(alloc.Alloc(sizeof(Script)));
537         new (mem) Script;
538         Script *script(reinterpret_cast<Script *>(mem));
539         ReadScript(s, script);
540         return mem;
541 }
542
543 void Interpreter::ReadScriptAddress(const ScriptToken &t, unsigned char *dest) {
544         if (t.GetType() != ScriptToken::IDENTIFIER) {
545                 throw Error("expected identifier for address");
546         }
547         if (source.IsDefined(t.GetIdentifier())) {
548                 const ParsedDefinition &def(GetDefinition(t.GetIdentifier()));
549                 void *addr(GetObject(def.type, t.GetIdentifier()));
550                 *reinterpret_cast<void **>(dest) = addr;
551         } else {
552                 throw Error("postponing values in scripts not implemented");
553         }
554 }
555
556 void Interpreter::ReadScriptInteger(const ScriptToken &t, unsigned char *dest) {
557         if (t.GetType() == ScriptToken::IDENTIFIER) {
558                 if (source.IsDefined(t.GetIdentifier())) {
559                         void *num(GetObject(TypeDescription::GetTypeId("Number"), t.GetIdentifier()));
560                         *reinterpret_cast<int *>(dest) = *reinterpret_cast<int *>(num);
561                 } else {
562                         throw Error("postponing values in scripts not implemented");
563                 }
564         } else if (t.GetType() == ScriptToken::LITERAL) {
565                 *reinterpret_cast<int *>(dest) = t.GetLiteral()->GetNumber();
566         } else {
567                 throw Error("expected identifier or integer literal");
568         }
569 }
570
571 void Interpreter::ReadScriptVector(const ScriptToken &t, unsigned char *dest) {
572         if (t.GetType() == ScriptToken::IDENTIFIER) {
573                 if (source.IsDefined(t.GetIdentifier())) {
574                         void *vec(GetObject(TypeDescription::GetTypeId("Vector"), t.GetIdentifier()));
575                         *reinterpret_cast<Vector<int> *>(dest) = *reinterpret_cast<Vector<int> *>(vec);
576                 } else {
577                         throw Error("postponing values in scripts not implemented");
578                 }
579         } else if (t.GetType() == ScriptToken::LITERAL) {
580                 *reinterpret_cast<Vector<int> *>(dest) = Vector<int>(t.GetLiteral()->GetX(), t.GetLiteral()->GetY());
581         } else {
582                 throw Error("expected identifier or vector literal");
583         }
584 }
585
586
587 SDL_Surface *Interpreter::GetImage(const string &path) {
588         std::map<string, SDL_Surface *>::const_iterator result(imageCache.find(path));
589         if (result != imageCache.end()) {
590                 return result->second;
591         } else {
592                 SDL_Surface *image(IMG_Load(path.c_str()));
593                 imageCache.insert(make_pair(path, image));
594                 return image;
595         }
596 }
597
598
599 bool Interpreter::CanLink(const Value &v) const {
600         return v.IsLiteral() || source.IsDefined(v.GetIdentifier());
601 }
602
603 void Interpreter::Postpone(int type, int id, std::ptrdiff_t offset, const std::string &identifier, int linkedType, bool inlined) {
604         char *str(alloc.Alloc(identifier.size() + 1));
605         std::memcpy(str, identifier.c_str(), identifier.size());
606         str[identifier.size()] = '\0';
607         postponedDefinitions.push_back(PostponedDefinition(type, id, offset, str, linkedType, inlined));
608 }
609
610
611 void Interpreter::CreateTypeDescriptions() {
612         {
613                 TypeDescription &td(TypeDescription::CreateOrGet("Boolean"));
614                 td.SetDescription("Logical value which can be either true or false.");
615                 td.SetSize(sizeof(bool));
616         }
617         {
618                 TypeDescription &td(TypeDescription::CreateOrGet("Color"));
619                 td.SetDescription(
620                                 "A color in RGB format with an optional alpha channel.\n"
621                                 "Components range from 0 to 255.\n"
622                                 "Alpha defaults to 255 if omitted.");
623                 td.SetSize(sizeof(Color));
624         }
625         {
626                 TypeDescription &td(TypeDescription::CreateOrGet("Image"));
627                 td.SetDescription("Path to a PNG file with image data.");
628                 td.SetSize(sizeof(SDL_Surface));
629         }
630         {
631                 TypeDescription &td(TypeDescription::CreateOrGet("Number"));
632                 td.SetDescription("A signed integer.");
633                 td.SetSize(sizeof(int));
634         }
635         {
636                 int stringId(TypeDescription::GetTypeId("String"));
637                 TypeDescription &td(TypeDescription::CreateOrGet("Path"));
638                 td.SetDescription("A path in the filesystem which is interpreted relative to the source file's location.");
639                 td.SetSize(1);
640                 td.AddSupertype(stringId, 0);
641         }
642         {
643                 TypeDescription &td(TypeDescription::CreateOrGet("Script"));
644                 td.SetDescription("Collection of commands that define a behaviour.");
645                 td.SetSize(sizeof(Script));
646         }
647         {
648                 TypeDescription &td(TypeDescription::CreateOrGet("String"));
649                 td.SetDescription("Some characters.");
650                 td.SetSize(1);
651         }
652         {
653                 TypeDescription &td(TypeDescription::CreateOrGet("Vector"));
654                 td.SetDescription("A pair of numbers usually describing a 2D translation or offset.");
655                 td.SetSize(sizeof(Vector<int>));
656         }
657 }
658
659 }