1 #include "Interpreter.h"
3 #include "ParsedSource.h"
4 #include "../battle/Hero.h"
5 #include "../battle/Monster.h"
6 #include "../battle/PartyLayout.h"
7 #include "../battle/Resources.h"
8 #include "../common/Ikari.h"
9 #include "../common/Item.h"
10 #include "../common/Script.h"
11 #include "../common/Spell.h"
12 #include "../common/Stats.h"
13 #include "../common/TargetingMode.h"
14 #include "../graphics/ComplexAnimation.h"
15 #include "../graphics/Font.h"
16 #include "../graphics/Frame.h"
17 #include "../graphics/Gauge.h"
18 #include "../graphics/Menu.h"
19 #include "../graphics/SimpleAnimation.h"
20 #include "../graphics/Sprite.h"
24 #include <SDL_image.h>
27 using battle::Monster;
28 using battle::PartyLayout;
34 using common::TargetingMode;
35 using graphics::Animation;
36 using graphics::Color;
38 using graphics::Frame;
39 using graphics::Gauge;
40 using graphics::ComplexAnimation;
41 using graphics::SimpleAnimation;
42 using graphics::Sprite;
43 using geometry::Vector;
51 Interpreter::~Interpreter() {
52 for (std::map<string, SDL_Surface *>::const_iterator i(imageCache.begin()), end(imageCache.end()); i != end; ++i) {
53 SDL_FreeSurface(i->second);
58 const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &identifier) {
59 std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(identifier));
60 if (i != parsedDefinitions.end()) {
62 } else if (source.IsDefined(identifier)) {
63 ReadDefinition(source.GetDefinition(identifier));
64 return parsedDefinitions.at(identifier);
66 throw Error("access to undefined object " + identifier);
71 void *Interpreter::GetObject(int typeId, const std::string &name) {
72 std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
73 if (i != parsedDefinitions.end()) {
74 const TypeDescription &requested(TypeDescription::Get(typeId));
75 const TypeDescription &actual(TypeDescription::Get(i->second.type));
76 if (requested.TypeId() == actual.TypeId()) {
77 return values[actual.TypeId()][i->second.id];
78 } else if (actual.IsSubtypeOf(requested)) {
79 char *sub(reinterpret_cast<char *>(values[actual.TypeId()][i->second.id]));
80 std::ptrdiff_t offset(actual.SupertypeOffset(requested));
83 throw Error("cannot cast " + actual.TypeName() + " to " + requested.TypeName());
86 throw Error("access to undefined object " + name);
91 void Interpreter::ReadSource() {
92 for (set<string>::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) {
93 ReadDefinition(source.GetDefinition(*i));
97 void Interpreter::ReadDefinition(const Definition &dfn) {
98 if (parsedDefinitions.find(dfn.Identifier()) != parsedDefinitions.end()) {
101 if (dfn.HasLiteralValue()) {
108 void Interpreter::ReadLiteral(const Definition &dfn) {
109 const string &typeName(dfn.GetLiteral()->IsArray() ? "Array" : dfn.GetLiteral()->GetTypeName());
110 int typeId(TypeDescription::GetTypeId(typeName));
111 int id(values[typeId].size());
112 const TypeDescription &td(TypeDescription::Get(typeId));
114 (dfn.GetLiteral()->GetType() == Literal::PATH
115 || dfn.GetLiteral()->GetType() == Literal::STRING)
116 ? dfn.GetLiteral()->GetString().size() : td.Size());
117 char *object(alloc.Alloc(size));
118 values[typeId].push_back(object);
119 parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
120 if (dfn.GetLiteral()->GetType() == Literal::OBJECT) {
121 ReadObject(typeId, id, object, *dfn.GetLiteral()->GetProperties());
123 ReadLiteral(typeId, id, object, *dfn.GetLiteral());
127 void Interpreter::ReadLiteral(int typeId, int id, char *object, const Literal &literal) {
128 switch (literal.GetType()) {
129 case Literal::ARRAY_VALUES:
130 throw Error("named value arrays are not supported, sorry");
132 case Literal::ARRAY_PROPS:
133 throw Error("named property list arrays are not supported, sorry");
135 case Literal::BOOLEAN:
136 new (object) bool(literal.GetBoolean());
139 new (object) Color(literal.GetRed(), literal.GetGreen(), literal.GetBlue(), literal.GetAlpha());
141 case Literal::NUMBER:
142 new (object) int(literal.GetNumber());
145 std::memcpy(object, literal.GetString().c_str(), literal.GetString().size());
146 object[literal.GetString().size()] = '\0';
148 case Literal::SCRIPT:
150 ReadScript(literal.GetScript(), reinterpret_cast<Script *>(object));
152 case Literal::STRING:
153 std::memcpy(object, literal.GetString().c_str(), literal.GetString().size());
154 object[literal.GetString().size()] = '\0';
156 case Literal::VECTOR:
157 new (object) Vector<int>(literal.GetX(), literal.GetY());
159 case Literal::OBJECT:
160 throw Error("illogical branch: read literal object as non-object literal");
165 void *Interpreter::GetObject(int typeId, const Value &v) {
167 if (v.GetLiteral().IsObject()) {
168 int typeId(TypeDescription::GetTypeId(v.GetLiteral().GetTypeName()));
169 const TypeDescription &td(TypeDescription::Get(typeId));
170 char *object(alloc.Alloc(td.Size()));
171 td.Construct(object);
172 int id(values[typeId].size());
173 values[typeId].push_back(object);
174 ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
177 int typeId(0), id(0);
178 switch (v.GetLiteral().GetType()) {
179 case Literal::ARRAY_VALUES:
180 throw Error("cannot copy value arrays, sorry");
182 case Literal::ARRAY_PROPS:
183 throw Error("cannot copy property list arrays, sorry");
185 case Literal::BOOLEAN:
187 typeId = TypeDescription::GetTypeId("Boolean");
188 id = values[typeId].size();
189 const TypeDescription &td(TypeDescription::Get(typeId));
190 char *object(alloc.Alloc(td.Size()));
191 values[typeId].push_back(new (object) bool(v.GetLiteral().GetBoolean()));
196 typeId = TypeDescription::GetTypeId("Color");
197 id = values[typeId].size();
198 const TypeDescription &td(TypeDescription::Get(typeId));
199 char *object(alloc.Alloc(td.Size()));
200 values[typeId].push_back(new (object) Color(v.GetLiteral().GetRed(), v.GetLiteral().GetGreen(), v.GetLiteral().GetBlue(), v.GetLiteral().GetAlpha()));
203 case Literal::NUMBER:
205 typeId = TypeDescription::GetTypeId("Number");
206 id = values[typeId].size();
207 const TypeDescription &td(TypeDescription::Get(typeId));
208 char *object(alloc.Alloc(td.Size()));
209 values[typeId].push_back(new (object) int(v.GetLiteral().GetNumber()));
214 typeId = TypeDescription::GetTypeId("Path");
215 id = values[typeId].size();
216 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
217 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
218 str[v.GetLiteral().GetString().size()] = '\0';
219 values[typeId].push_back(str);
222 case Literal::SCRIPT:
224 typeId = TypeDescription::GetTypeId("Script");
225 char *script(ReadScript(v.GetLiteral().GetScript()));
226 id = values[typeId].size();
227 values[typeId].push_back(script);
230 case Literal::STRING:
232 typeId = TypeDescription::GetTypeId("String");
233 id = values[typeId].size();
234 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
235 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
236 str[v.GetLiteral().GetString().size()] = '\0';
237 values[typeId].push_back(str);
240 case Literal::VECTOR:
242 typeId = TypeDescription::GetTypeId("Vector");
243 id = values[typeId].size();
244 const TypeDescription &td(TypeDescription::Get(typeId));
245 char *object(alloc.Alloc(td.Size()));
246 values[typeId].push_back(new (object) Vector<int>(v.GetLiteral().GetX(), v.GetLiteral().GetY()));
249 case Literal::OBJECT:
251 typeId = TypeDescription::GetTypeId(v.GetLiteral().GetTypeName());
252 const TypeDescription &td(TypeDescription::Get(typeId));
253 id = values[typeId].size();
254 char *object(alloc.Alloc(td.Size()));
255 td.Construct(object);
256 ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
260 return values[typeId][id];
263 ReadDefinition(source.GetDefinition(v.GetIdentifier()));
264 return GetObject(typeId, v.GetIdentifier());
269 void Interpreter::ReadObject(const Definition &dfn) {
270 int typeId(TypeDescription::GetTypeId(dfn.TypeName()));
271 const TypeDescription &td(TypeDescription::Get(typeId));
272 int id(values[typeId].size());
273 char *object(alloc.Alloc(td.Size()));
274 td.Construct(object);
275 values[typeId].push_back(object);
276 parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
277 ReadObject(typeId, id, object, *dfn.GetProperties());
281 void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyList &props) {
282 const TypeDescription &td(TypeDescription::Get(typeId));
283 for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) {
284 const FieldDescription &fd(td.GetField(i->first));
285 const TypeDescription &fieldType(TypeDescription::Get(fd.TypeId()));
286 if (CanLink(*i->second)) {
287 char *dest(object + fd.Offset());
288 if (fd.IsAggregate()) {
289 int arraySize(i->second->GetLiteral().ArraySize());
290 char *aggregate(alloc.Alloc(fieldType.Size() * arraySize));
291 char *iter(aggregate);
292 if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) {
293 const vector<PropertyList *> &list(i->second->GetLiteral().GetPropertyLists());
294 for (vector<PropertyList *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
295 fieldType.Construct(iter);
296 ReadObject(fieldType.TypeId(), -1, iter, **j);
299 const vector<Value *> &list(i->second->GetLiteral().GetValues());
300 for (vector<Value *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
301 fieldType.Construct(iter);
302 ReadLiteral(fieldType.TypeId(), -1, iter, (*j)->GetLiteral());
305 if (fd.IsReferenced()) {
306 std::memcpy(dest, &aggregate, sizeof(char *));
307 dest += sizeof(char *);
308 std::memcpy(dest, &arraySize, sizeof(int));
310 throw Error("aggregate type fields must be referenced");
312 } else if (i->second->IsLiteral() && !fd.IsReferenced()) {
314 if (i->second->GetLiteral().IsObject()) {
315 ReadObject(fd.TypeId(), -1, dest, *i->second->GetLiteral().GetProperties());
317 ReadLiteral(fd.TypeId(), -1, dest, i->second->GetLiteral());
320 char *src(reinterpret_cast<char *>(GetObject(fd.TypeId(), *i->second)));
321 if (fd.TypeId() == TypeDescription::GetTypeId("Image")) {
322 src = reinterpret_cast<char *>(GetImage(src));
324 if (fd.IsReferenced()) {
325 std::memcpy(dest, &src, sizeof(char *));
327 std::memcpy(dest, src, fieldType.Size());
331 Postpone(typeId, id, fd.Offset(), i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced());
338 void Interpreter::ReadScript(const std::vector<ScriptToken *> &s, Script *script) {
339 std::map<string, int> labels;
341 for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
342 if ((*i)->GetType() == ScriptToken::LABEL) {
343 if (labels.count((*i)->Label())) {
344 throw Error("duplicate label " + (*i)->Label());
346 labels[(*i)->Label()] = size;
348 } else if ((*i)->GetType() != ScriptToken::COMMAND) {
349 throw Error("unexpected script token");
351 size += sizeof(Script::Code);
352 const string &cmd((*i)->CommandName());
356 throw Error("unexpected script end after move");
358 const string ®((*i)->RegisterName());
359 if (reg.size() != 2) {
360 throw Error("invalid register name " + reg);
364 throw Error("unexpected script end after move");
366 if ((*i)->GetType() != ScriptToken::REGISTER) {
369 size += sizeof(void *);
375 size += sizeof(Vector<int>);
378 throw Error("unknown register " + reg);
381 } else if (cmd == "add") {
384 throw Error("unexpected script end after add");
386 const string ®((*i)->RegisterName());
387 if (reg.size() != 2) {
388 throw Error("invalid register name " + reg);
392 throw Error("unexpected script end after add");
394 if ((*i)->GetType() != ScriptToken::REGISTER) {
400 size += sizeof(Vector<int>);
403 throw Error("expected register after add " + reg);
406 } else if (cmd == "mod") {
409 throw Error("unexpected script end after mod");
413 throw Error("unexpected script end after mod");
415 if ((*i)->GetType() != ScriptToken::REGISTER) {
418 } else if (cmd == "rand") {
421 throw Error("unexpected script end after rand");
423 } else if (cmd == "cmp") {
426 throw Error("unexpected script end after cmp");
428 if ((*i)->GetType() != ScriptToken::REGISTER) {
433 throw Error("unexpected script end after cmp");
435 if ((*i)->GetType() != ScriptToken::REGISTER) {
438 } else if (cmd == "jmp") {
442 throw Error("unexpected script end after cmp");
444 } else if (cmd == "jeq") {
448 throw Error("unexpected script end after cmp");
450 } else if (cmd == "jne") {
454 throw Error("unexpected script end after cmp");
456 } else if (cmd == "jl") {
460 throw Error("unexpected script end after cmp");
462 } else if (cmd == "jle") {
466 throw Error("unexpected script end after cmp");
468 } else if (cmd == "jg") {
472 throw Error("unexpected script end after cmp");
474 } else if (cmd == "jge") {
478 throw Error("unexpected script end after cmp");
480 } else if (cmd == "sysc") {
483 throw Error("unknown command " + cmd);
487 char *text(alloc.Alloc(size));
489 for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
490 if ((*i)->GetType() == ScriptToken::LABEL) {
493 if ((*i)->GetType() != ScriptToken::COMMAND) {
494 throw Error("unexpected script token");
496 const string &cmd((*i)->CommandName());
498 Script::Code &code(CreateScriptCode(Script::COMMAND_MOVE, text + cursor));
499 cursor += sizeof(Script::Code);
502 const string ®((*i)->RegisterName());
505 code.type = Script::TYPE_ADDRESS;
508 code.type = Script::TYPE_INTEGER;
511 code.type = Script::TYPE_VECTOR;
514 throw Error("invalid register " + reg);
516 int regnum(reg[1] - '0');
517 if (regnum < 0 || regnum > 6) {
518 throw Error("invalid register " + reg);
523 if ((*i)->GetType() == ScriptToken::REGISTER) {
524 string reg2((*i)->RegisterName());
525 if (reg[0] != reg2[0]) {
526 throw Error("mixed-type commands not allowed");
528 int reg2num(reg[1] - '0');
529 if (reg2num < 0 || reg2num > 6) {
530 throw Error("invalid register " + reg2);
536 case Script::TYPE_ADDRESS:
537 ReadScriptAddress(**i, text + cursor);
538 cursor += sizeof(void *);
540 case Script::TYPE_INTEGER:
541 ReadScriptInteger(**i, text + cursor);
542 cursor += sizeof(int);
544 case Script::TYPE_VECTOR:
545 ReadScriptVector(**i, text + cursor);
546 cursor += sizeof(Vector<int>);
550 } else if (cmd == "add") {
551 Script::Code &code(CreateScriptCode(Script::COMMAND_ADD, text + cursor));
552 cursor += sizeof(Script::Code);
555 const string ®((*i)->RegisterName());
558 code.type = Script::TYPE_INTEGER;
561 code.type = Script::TYPE_VECTOR;
564 throw Error("invalid register " + reg);
566 int regnum(reg[1] - '0');
567 if (regnum < 0 || regnum > 6) {
568 throw Error("invalid register " + reg);
573 if ((*i)->GetType() == ScriptToken::REGISTER) {
574 string reg2((*i)->RegisterName());
575 if (reg[0] != reg2[0]) {
576 throw Error("mixed-type commands not allowed");
578 int reg2num(reg[1] - '0');
579 if (reg2num < 0 || reg2num > 6) {
580 throw Error("invalid register name " + reg2);
586 case Script::TYPE_INTEGER:
587 ReadScriptInteger(**i, text + cursor);
588 cursor += sizeof(int);
590 case Script::TYPE_VECTOR:
591 ReadScriptVector(**i, text + cursor);
592 cursor += sizeof(Vector<int>);
596 } else if (cmd == "mod") {
597 Script::Code &code(CreateScriptCode(Script::COMMAND_MOD, text + cursor));
598 cursor += sizeof(Script::Code);
601 const string ®((*i)->RegisterName());
603 throw Error("invalid register " + reg);
605 code.type = Script::TYPE_INTEGER;
606 int regnum(reg[1] - '0');
607 if (regnum < 0 || regnum > 6) {
608 throw Error("invalid register " + reg);
613 if ((*i)->GetType() == ScriptToken::REGISTER) {
614 string reg2((*i)->RegisterName());
615 if (reg[0] != reg2[0]) {
616 throw Error("mixed-type commands not allowed");
618 int reg2num(reg[1] - '0');
619 if (reg2num < 0 || reg2num > 6) {
620 throw Error("invalid register name " + reg2);
625 ReadScriptInteger(**i, text + cursor);
626 cursor += sizeof(int);
628 } else if (cmd == "rand") {
629 Script::Code &code(CreateScriptCode(Script::COMMAND_RAND, text + cursor));
630 cursor += sizeof(Script::Code);
633 const string ®((*i)->RegisterName());
635 throw Error("invalid register " + reg);
637 code.type = Script::TYPE_INTEGER;
638 int regnum(reg[1] - '0');
639 if (regnum < 0 || regnum > 6) {
640 throw Error("invalid register " + reg);
643 } else if (cmd == "cmp") {
644 Script::Code &code(CreateScriptCode(Script::COMMAND_CMP, text + cursor));
645 cursor += sizeof(Script::Code);
648 const string ®((*i)->RegisterName());
650 throw Error("invalid register " + reg);
652 code.type = Script::TYPE_INTEGER;
653 int regnum(reg[1] - '0');
654 if (regnum < 0 || regnum > 6) {
655 throw Error("invalid register " + reg);
660 if ((*i)->GetType() == ScriptToken::REGISTER) {
661 string reg2((*i)->RegisterName());
662 if (reg[0] != reg2[0]) {
663 throw Error("mixed-type commands not allowed");
665 int reg2num(reg[1] - '0');
666 if (reg2num < 0 || reg2num > 6) {
667 throw Error("invalid register name " + reg2);
672 ReadScriptInteger(**i, text + cursor);
673 cursor += sizeof(int);
675 } else if (cmd == "jmp") {
676 Script::Code &code(CreateScriptCode(Script::COMMAND_JMP, text + cursor));
677 cursor += sizeof(Script::Code);
680 if (!labels.count((*i)->Identifier())) {
681 throw Error("use of undefined label " + (*i)->Identifier());
683 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
684 cursor += sizeof(int);
685 } else if (cmd == "jeq") {
686 Script::Code &code(CreateScriptCode(Script::COMMAND_JEQ, text + cursor));
687 cursor += sizeof(Script::Code);
690 if (!labels.count((*i)->Identifier())) {
691 throw Error("use of undefined label " + (*i)->Identifier());
693 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
694 cursor += sizeof(int);
695 } else if (cmd == "jne") {
696 Script::Code &code(CreateScriptCode(Script::COMMAND_JNE, text + cursor));
697 cursor += sizeof(Script::Code);
700 if (!labels.count((*i)->Identifier())) {
701 throw Error("use of undefined label " + (*i)->Identifier());
703 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
704 cursor += sizeof(int);
705 } else if (cmd == "jl") {
706 Script::Code &code(CreateScriptCode(Script::COMMAND_JL, text + cursor));
707 cursor += sizeof(Script::Code);
710 if (!labels.count((*i)->Identifier())) {
711 throw Error("use of undefined label " + (*i)->Identifier());
713 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
714 cursor += sizeof(int);
715 } else if (cmd == "jle") {
716 Script::Code &code(CreateScriptCode(Script::COMMAND_JLE, text + cursor));
717 cursor += sizeof(Script::Code);
720 if (!labels.count((*i)->Identifier())) {
721 throw Error("use of undefined label " + (*i)->Identifier());
723 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
724 cursor += sizeof(int);
725 } else if (cmd == "jg") {
726 Script::Code &code(CreateScriptCode(Script::COMMAND_JG, text + cursor));
727 cursor += sizeof(Script::Code);
730 if (!labels.count((*i)->Identifier())) {
731 throw Error("use of undefined label " + (*i)->Identifier());
733 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
734 cursor += sizeof(int);
735 } else if (cmd == "jge") {
736 Script::Code &code(CreateScriptCode(Script::COMMAND_JGE, text + cursor));
737 cursor += sizeof(Script::Code);
740 if (!labels.count((*i)->Identifier())) {
741 throw Error("use of undefined label " + (*i)->Identifier());
743 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
744 cursor += sizeof(int);
745 } else if (cmd == "sysc") {
746 Script::Code &code(CreateScriptCode(Script::COMMAND_SYSC, text + cursor));
747 cursor += sizeof(Script::Code);
750 throw Error("unknown command " + cmd);
755 script->textlen = size;
758 char *Interpreter::ReadScript(const vector<ScriptToken *> &s) {
759 char *mem(alloc.Alloc(sizeof(Script)));
761 Script *script(reinterpret_cast<Script *>(mem));
762 ReadScript(s, script);
766 Script::Code &Interpreter::CreateScriptCode(Script::Command c, char *dest) {
767 Script::Code &code(*reinterpret_cast<Script::Code *>(dest));
770 code.type = Script::TYPE_NONE;
776 void Interpreter::ReadScriptAddress(const ScriptToken &t, char *dest) {
777 if (t.GetType() != ScriptToken::IDENTIFIER) {
778 throw Error("expected identifier for address");
780 if (source.IsDefined(t.Identifier())) {
781 const ParsedDefinition &def(GetDefinition(t.Identifier()));
782 void *addr(GetObject(def.type, t.Identifier()));
783 *reinterpret_cast<void **>(dest) = addr;
785 throw Error("postponing values in scripts not implemented");
789 void Interpreter::ReadScriptInteger(const ScriptToken &t, char *dest) {
790 if (t.GetType() == ScriptToken::IDENTIFIER) {
791 if (source.IsDefined(t.Identifier())) {
792 void *num(GetObject(TypeDescription::GetTypeId("Number"), t.Identifier()));
793 *reinterpret_cast<int *>(dest) = *reinterpret_cast<int *>(num);
795 throw Error("postponing values in scripts not implemented");
797 } else if (t.GetType() == ScriptToken::LITERAL) {
798 *reinterpret_cast<int *>(dest) = t.GetLiteral()->GetNumber();
800 throw Error("expected identifier or integer literal");
804 void Interpreter::ReadScriptVector(const ScriptToken &t, char *dest) {
805 if (t.GetType() == ScriptToken::IDENTIFIER) {
806 if (source.IsDefined(t.Identifier())) {
807 void *vec(GetObject(TypeDescription::GetTypeId("Vector"), t.Identifier()));
808 *reinterpret_cast<Vector<int> *>(dest) = *reinterpret_cast<Vector<int> *>(vec);
810 throw Error("postponing values in scripts not implemented");
812 } else if (t.GetType() == ScriptToken::LITERAL) {
813 *reinterpret_cast<Vector<int> *>(dest) = Vector<int>(t.GetLiteral()->GetX(), t.GetLiteral()->GetY());
815 throw Error("expected identifier or vector literal");
820 SDL_Surface *Interpreter::GetImage(const string &path) {
821 std::map<string, SDL_Surface *>::const_iterator result(imageCache.find(path));
822 if (result != imageCache.end()) {
823 return result->second;
825 SDL_Surface *image(IMG_Load(path.c_str()));
826 imageCache.insert(make_pair(path, image));
832 bool Interpreter::CanLink(const Value &v) const {
833 return v.IsLiteral() || source.IsDefined(v.GetIdentifier());
836 void Interpreter::Postpone(int type, int id, std::ptrdiff_t offset, const std::string &identifier, int linkedType, bool inlined) {
837 char *str(alloc.Alloc(identifier.size() + 1));
838 std::memcpy(str, identifier.c_str(), identifier.size());
839 str[identifier.size()] = '\0';
840 postponedDefinitions.push_back(PostponedDefinition(type, id, offset, str, linkedType, inlined));
844 void Interpreter::CreateTypeDescriptions() {
846 TypeDescription &td(TypeDescription::Create(BOOLEAN_ID, "Boolean"));
847 td.SetDescription("Logical value which can be either true or false.");
848 td.SetSize(sizeof(bool));
851 TypeDescription &td(TypeDescription::Create(COLOR_ID, "Color"));
853 "A color in RGB format with an optional alpha channel.\n"
854 "Components range from 0 to 255.\n"
855 "Alpha defaults to 255 if omitted.");
856 td.SetSize(sizeof(Color));
859 TypeDescription &td(TypeDescription::Create(IMAGE_ID, "Image"));
860 td.SetDescription("Path to a PNG file with image data.");
861 td.SetSize(sizeof(SDL_Surface));
864 TypeDescription &td(TypeDescription::Create(NUMBER_ID, "Number"));
865 td.SetDescription("A signed integer.");
866 td.SetSize(sizeof(int));
869 TypeDescription &td(TypeDescription::Create(PATH_ID, "Path"));
870 td.SetDescription("A path in the filesystem which is interpreted relative to the source file's location.");
872 td.AddSupertype(STRING_ID, 0);
875 TypeDescription &td(TypeDescription::Create(SCRIPT_ID, "Script"));
876 td.SetDescription("Collection of commands that define a behaviour.");
877 td.SetSize(sizeof(Script));
880 TypeDescription &td(TypeDescription::Create(STRING_ID, "String"));
881 td.SetDescription("Some characters.");
885 TypeDescription &td(TypeDescription::Create(VECTOR_ID, "Vector"));
886 td.SetDescription("A pair of numbers usually describing a 2D translation or offset.");
887 td.SetSize(sizeof(Vector<int>));