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 case Literal::ARRAY_PROPS:
131 case Literal::ARRAY_IDENTS:
132 throw Error("named arrays are not supported, sorry");
134 case Literal::BOOLEAN:
135 new (object) bool(literal.GetBoolean());
138 new (object) Color(literal.GetRed(), literal.GetGreen(), literal.GetBlue(), literal.GetAlpha());
140 case Literal::NUMBER:
141 new (object) int(literal.GetNumber());
144 std::memcpy(object, literal.GetString().c_str(), literal.GetString().size());
145 object[literal.GetString().size()] = '\0';
147 case Literal::SCRIPT:
149 ReadScript(literal.GetScript(), reinterpret_cast<Script *>(object));
151 case Literal::STRING:
152 std::memcpy(object, literal.GetString().c_str(), literal.GetString().size());
153 object[literal.GetString().size()] = '\0';
155 case Literal::VECTOR:
156 new (object) Vector<int>(literal.GetX(), literal.GetY());
158 case Literal::OBJECT:
159 throw Error("illogical branch: read literal object as non-object literal");
164 void *Interpreter::GetObject(int typeId, const Value &v) {
166 if (v.GetLiteral().IsObject()) {
167 int typeId(TypeDescription::GetTypeId(v.GetLiteral().GetTypeName()));
168 const TypeDescription &td(TypeDescription::Get(typeId));
169 char *object(alloc.Alloc(td.Size()));
170 td.Construct(object);
171 int id(values[typeId].size());
172 values[typeId].push_back(object);
173 ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
176 int typeId(0), id(0);
177 switch (v.GetLiteral().GetType()) {
178 case Literal::ARRAY_VALUES:
179 case Literal::ARRAY_PROPS:
180 case Literal::ARRAY_IDENTS:
181 throw Error("cannot copy arrays, sorry");
183 case Literal::BOOLEAN:
185 typeId = TypeDescription::GetTypeId("Boolean");
186 id = values[typeId].size();
187 const TypeDescription &td(TypeDescription::Get(typeId));
188 char *object(alloc.Alloc(td.Size()));
189 values[typeId].push_back(new (object) bool(v.GetLiteral().GetBoolean()));
194 typeId = TypeDescription::GetTypeId("Color");
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) Color(v.GetLiteral().GetRed(), v.GetLiteral().GetGreen(), v.GetLiteral().GetBlue(), v.GetLiteral().GetAlpha()));
201 case Literal::NUMBER:
203 typeId = TypeDescription::GetTypeId("Number");
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) int(v.GetLiteral().GetNumber()));
212 typeId = TypeDescription::GetTypeId("Path");
213 id = values[typeId].size();
214 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
215 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
216 str[v.GetLiteral().GetString().size()] = '\0';
217 values[typeId].push_back(str);
220 case Literal::SCRIPT:
222 typeId = TypeDescription::GetTypeId("Script");
223 char *script(ReadScript(v.GetLiteral().GetScript()));
224 id = values[typeId].size();
225 values[typeId].push_back(script);
228 case Literal::STRING:
230 typeId = TypeDescription::GetTypeId("String");
231 id = values[typeId].size();
232 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
233 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
234 str[v.GetLiteral().GetString().size()] = '\0';
235 values[typeId].push_back(str);
238 case Literal::VECTOR:
240 typeId = TypeDescription::GetTypeId("Vector");
241 id = values[typeId].size();
242 const TypeDescription &td(TypeDescription::Get(typeId));
243 char *object(alloc.Alloc(td.Size()));
244 values[typeId].push_back(new (object) Vector<int>(v.GetLiteral().GetX(), v.GetLiteral().GetY()));
247 case Literal::OBJECT:
249 typeId = TypeDescription::GetTypeId(v.GetLiteral().GetTypeName());
250 const TypeDescription &td(TypeDescription::Get(typeId));
251 id = values[typeId].size();
252 char *object(alloc.Alloc(td.Size()));
253 td.Construct(object);
254 ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
258 return values[typeId][id];
261 ReadDefinition(source.GetDefinition(v.GetIdentifier()));
262 return GetObject(typeId, v.GetIdentifier());
267 void Interpreter::ReadObject(const Definition &dfn) {
268 int typeId(TypeDescription::GetTypeId(dfn.TypeName()));
269 const TypeDescription &td(TypeDescription::Get(typeId));
270 int id(values[typeId].size());
271 char *object(alloc.Alloc(td.Size()));
272 td.Construct(object);
273 values[typeId].push_back(object);
274 parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
275 ReadObject(typeId, id, object, *dfn.GetProperties());
279 void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyList &props) {
280 const TypeDescription &td(TypeDescription::Get(typeId));
281 for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) {
282 const FieldDescription &fd(td.GetField(i->first));
283 const TypeDescription &fieldType(TypeDescription::Get(fd.TypeId()));
284 if (CanLink(*i->second)) {
285 char *dest(object + fd.Offset());
286 if (fd.IsAggregate()) {
287 int arraySize(i->second->GetLiteral().ArraySize());
289 if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) {
290 aggregate = alloc.Alloc(fieldType.Size() * arraySize);
291 char *iter = aggregate;
292 const vector<PropertyList *> &list(i->second->GetLiteral().GetPropertyLists());
293 for (vector<PropertyList *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
294 fieldType.Construct(iter);
295 ReadObject(fieldType.TypeId(), -1, iter, **j);
297 } else if (i->second->GetLiteral().GetType() == Literal::ARRAY_VALUES) {
298 aggregate = alloc.Alloc(fieldType.Size() * arraySize);
299 char *iter = aggregate;
300 const vector<Value *> &list(i->second->GetLiteral().GetValues());
301 for (vector<Value *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
302 fieldType.Construct(iter);
303 ReadLiteral(fieldType.TypeId(), -1, iter, (*j)->GetLiteral());
306 aggregate = alloc.Alloc(sizeof(char *) * arraySize);
307 char *iter = aggregate;
308 const vector<string> &list(i->second->GetLiteral().GetIdentifiers());
309 for (vector<string>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += sizeof(void *)) {
310 if (source.IsDefined(*j)) {
311 *reinterpret_cast<void **>(iter)
312 = GetObject(fd.TypeId(), *j);
314 Postpone(typeId, id, fd.Offset() + (iter - aggregate), *j, fd.TypeId(), false);
318 if (fd.IsReferenced()) {
319 std::memcpy(dest, &aggregate, sizeof(char *));
320 dest += sizeof(char *);
321 std::memcpy(dest, &arraySize, sizeof(int));
323 throw Error("aggregate type fields must be referenced");
325 } else if (i->second->IsLiteral() && !fd.IsReferenced()) {
327 if (i->second->GetLiteral().IsObject()) {
328 ReadObject(fd.TypeId(), -1, dest, *i->second->GetLiteral().GetProperties());
330 ReadLiteral(fd.TypeId(), -1, dest, i->second->GetLiteral());
333 char *src(reinterpret_cast<char *>(GetObject(fd.TypeId(), *i->second)));
334 if (fd.TypeId() == TypeDescription::GetTypeId("Image")) {
335 src = reinterpret_cast<char *>(GetImage(src));
337 if (fd.IsReferenced()) {
338 std::memcpy(dest, &src, sizeof(char *));
340 std::memcpy(dest, src, fieldType.Size());
344 Postpone(typeId, id, fd.Offset(), i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced());
351 void Interpreter::ReadScript(const std::vector<ScriptToken *> &s, Script *script) {
352 std::map<string, int> labels;
354 for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
355 if ((*i)->GetType() == ScriptToken::LABEL) {
356 if (labels.count((*i)->Label())) {
357 throw Error("duplicate label " + (*i)->Label());
359 labels[(*i)->Label()] = size;
361 } else if ((*i)->GetType() != ScriptToken::COMMAND) {
362 throw Error("unexpected script token");
364 size += sizeof(Script::Code);
365 const string &cmd((*i)->CommandName());
369 throw Error("unexpected script end after move");
371 const string ®((*i)->RegisterName());
372 if (reg.size() != 2) {
373 throw Error("invalid register name " + reg);
377 throw Error("unexpected script end after move");
379 if ((*i)->GetType() != ScriptToken::REGISTER) {
382 size += sizeof(void *);
388 size += sizeof(Vector<int>);
391 throw Error("unknown register " + reg);
394 } else if (cmd == "add") {
397 throw Error("unexpected script end after add");
399 const string ®((*i)->RegisterName());
400 if (reg.size() != 2) {
401 throw Error("invalid register name " + reg);
405 throw Error("unexpected script end after add");
407 if ((*i)->GetType() != ScriptToken::REGISTER) {
413 size += sizeof(Vector<int>);
416 throw Error("expected register after add " + reg);
419 } else if (cmd == "mod") {
422 throw Error("unexpected script end after mod");
426 throw Error("unexpected script end after mod");
428 if ((*i)->GetType() != ScriptToken::REGISTER) {
431 } else if (cmd == "rand") {
434 throw Error("unexpected script end after rand");
436 } else if (cmd == "cmp") {
439 throw Error("unexpected script end after cmp");
441 if ((*i)->GetType() != ScriptToken::REGISTER) {
446 throw Error("unexpected script end after cmp");
448 if ((*i)->GetType() != ScriptToken::REGISTER) {
451 } else if (cmd == "jmp") {
455 throw Error("unexpected script end after cmp");
457 } else if (cmd == "jeq") {
461 throw Error("unexpected script end after cmp");
463 } else if (cmd == "jne") {
467 throw Error("unexpected script end after cmp");
469 } else if (cmd == "jl") {
473 throw Error("unexpected script end after cmp");
475 } else if (cmd == "jle") {
479 throw Error("unexpected script end after cmp");
481 } else if (cmd == "jg") {
485 throw Error("unexpected script end after cmp");
487 } else if (cmd == "jge") {
491 throw Error("unexpected script end after cmp");
493 } else if (cmd == "sysc") {
496 throw Error("unknown command " + cmd);
500 char *text(alloc.Alloc(size));
502 for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
503 if ((*i)->GetType() == ScriptToken::LABEL) {
506 if ((*i)->GetType() != ScriptToken::COMMAND) {
507 throw Error("unexpected script token");
509 const string &cmd((*i)->CommandName());
511 Script::Code &code(CreateScriptCode(Script::COMMAND_MOVE, text + cursor));
512 cursor += sizeof(Script::Code);
515 const string ®((*i)->RegisterName());
518 code.type = Script::TYPE_ADDRESS;
521 code.type = Script::TYPE_INTEGER;
524 code.type = Script::TYPE_VECTOR;
527 throw Error("invalid register " + reg);
529 int regnum(reg[1] - '0');
530 if (regnum < 0 || regnum > 6) {
531 throw Error("invalid register " + reg);
536 if ((*i)->GetType() == ScriptToken::REGISTER) {
537 string reg2((*i)->RegisterName());
538 if (reg[0] != reg2[0]) {
539 throw Error("mixed-type commands not allowed");
541 int reg2num(reg[1] - '0');
542 if (reg2num < 0 || reg2num > 6) {
543 throw Error("invalid register " + reg2);
549 case Script::TYPE_ADDRESS:
550 ReadScriptAddress(**i, text + cursor);
551 cursor += sizeof(void *);
553 case Script::TYPE_INTEGER:
554 ReadScriptInteger(**i, text + cursor);
555 cursor += sizeof(int);
557 case Script::TYPE_VECTOR:
558 ReadScriptVector(**i, text + cursor);
559 cursor += sizeof(Vector<int>);
563 } else if (cmd == "add") {
564 Script::Code &code(CreateScriptCode(Script::COMMAND_ADD, text + cursor));
565 cursor += sizeof(Script::Code);
568 const string ®((*i)->RegisterName());
571 code.type = Script::TYPE_INTEGER;
574 code.type = Script::TYPE_VECTOR;
577 throw Error("invalid register " + reg);
579 int regnum(reg[1] - '0');
580 if (regnum < 0 || regnum > 6) {
581 throw Error("invalid register " + reg);
586 if ((*i)->GetType() == ScriptToken::REGISTER) {
587 string reg2((*i)->RegisterName());
588 if (reg[0] != reg2[0]) {
589 throw Error("mixed-type commands not allowed");
591 int reg2num(reg[1] - '0');
592 if (reg2num < 0 || reg2num > 6) {
593 throw Error("invalid register name " + reg2);
599 case Script::TYPE_INTEGER:
600 ReadScriptInteger(**i, text + cursor);
601 cursor += sizeof(int);
603 case Script::TYPE_VECTOR:
604 ReadScriptVector(**i, text + cursor);
605 cursor += sizeof(Vector<int>);
609 } else if (cmd == "mod") {
610 Script::Code &code(CreateScriptCode(Script::COMMAND_MOD, text + cursor));
611 cursor += sizeof(Script::Code);
614 const string ®((*i)->RegisterName());
616 throw Error("invalid register " + reg);
618 code.type = Script::TYPE_INTEGER;
619 int regnum(reg[1] - '0');
620 if (regnum < 0 || regnum > 6) {
621 throw Error("invalid register " + reg);
626 if ((*i)->GetType() == ScriptToken::REGISTER) {
627 string reg2((*i)->RegisterName());
628 if (reg[0] != reg2[0]) {
629 throw Error("mixed-type commands not allowed");
631 int reg2num(reg[1] - '0');
632 if (reg2num < 0 || reg2num > 6) {
633 throw Error("invalid register name " + reg2);
638 ReadScriptInteger(**i, text + cursor);
639 cursor += sizeof(int);
641 } else if (cmd == "rand") {
642 Script::Code &code(CreateScriptCode(Script::COMMAND_RAND, text + cursor));
643 cursor += sizeof(Script::Code);
646 const string ®((*i)->RegisterName());
648 throw Error("invalid register " + reg);
650 code.type = Script::TYPE_INTEGER;
651 int regnum(reg[1] - '0');
652 if (regnum < 0 || regnum > 6) {
653 throw Error("invalid register " + reg);
656 } else if (cmd == "cmp") {
657 Script::Code &code(CreateScriptCode(Script::COMMAND_CMP, text + cursor));
658 cursor += sizeof(Script::Code);
661 const string ®((*i)->RegisterName());
663 throw Error("invalid register " + reg);
665 code.type = Script::TYPE_INTEGER;
666 int regnum(reg[1] - '0');
667 if (regnum < 0 || regnum > 6) {
668 throw Error("invalid register " + reg);
673 if ((*i)->GetType() == ScriptToken::REGISTER) {
674 string reg2((*i)->RegisterName());
675 if (reg[0] != reg2[0]) {
676 throw Error("mixed-type commands not allowed");
678 int reg2num(reg[1] - '0');
679 if (reg2num < 0 || reg2num > 6) {
680 throw Error("invalid register name " + reg2);
685 ReadScriptInteger(**i, text + cursor);
686 cursor += sizeof(int);
688 } else if (cmd == "jmp") {
689 Script::Code &code(CreateScriptCode(Script::COMMAND_JMP, text + cursor));
690 cursor += sizeof(Script::Code);
693 if (!labels.count((*i)->Identifier())) {
694 throw Error("use of undefined label " + (*i)->Identifier());
696 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
697 cursor += sizeof(int);
698 } else if (cmd == "jeq") {
699 Script::Code &code(CreateScriptCode(Script::COMMAND_JEQ, text + cursor));
700 cursor += sizeof(Script::Code);
703 if (!labels.count((*i)->Identifier())) {
704 throw Error("use of undefined label " + (*i)->Identifier());
706 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
707 cursor += sizeof(int);
708 } else if (cmd == "jne") {
709 Script::Code &code(CreateScriptCode(Script::COMMAND_JNE, text + cursor));
710 cursor += sizeof(Script::Code);
713 if (!labels.count((*i)->Identifier())) {
714 throw Error("use of undefined label " + (*i)->Identifier());
716 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
717 cursor += sizeof(int);
718 } else if (cmd == "jl") {
719 Script::Code &code(CreateScriptCode(Script::COMMAND_JL, text + cursor));
720 cursor += sizeof(Script::Code);
723 if (!labels.count((*i)->Identifier())) {
724 throw Error("use of undefined label " + (*i)->Identifier());
726 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
727 cursor += sizeof(int);
728 } else if (cmd == "jle") {
729 Script::Code &code(CreateScriptCode(Script::COMMAND_JLE, text + cursor));
730 cursor += sizeof(Script::Code);
733 if (!labels.count((*i)->Identifier())) {
734 throw Error("use of undefined label " + (*i)->Identifier());
736 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
737 cursor += sizeof(int);
738 } else if (cmd == "jg") {
739 Script::Code &code(CreateScriptCode(Script::COMMAND_JG, text + cursor));
740 cursor += sizeof(Script::Code);
743 if (!labels.count((*i)->Identifier())) {
744 throw Error("use of undefined label " + (*i)->Identifier());
746 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
747 cursor += sizeof(int);
748 } else if (cmd == "jge") {
749 Script::Code &code(CreateScriptCode(Script::COMMAND_JGE, text + cursor));
750 cursor += sizeof(Script::Code);
753 if (!labels.count((*i)->Identifier())) {
754 throw Error("use of undefined label " + (*i)->Identifier());
756 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
757 cursor += sizeof(int);
758 } else if (cmd == "sysc") {
759 Script::Code &code(CreateScriptCode(Script::COMMAND_SYSC, text + cursor));
760 cursor += sizeof(Script::Code);
763 throw Error("unknown command " + cmd);
768 script->textlen = size;
771 char *Interpreter::ReadScript(const vector<ScriptToken *> &s) {
772 char *mem(alloc.Alloc(sizeof(Script)));
774 Script *script(reinterpret_cast<Script *>(mem));
775 ReadScript(s, script);
779 Script::Code &Interpreter::CreateScriptCode(Script::Command c, char *dest) {
780 Script::Code &code(*reinterpret_cast<Script::Code *>(dest));
783 code.type = Script::TYPE_NONE;
789 void Interpreter::ReadScriptAddress(const ScriptToken &t, char *dest) {
790 if (t.GetType() != ScriptToken::IDENTIFIER) {
791 throw Error("expected identifier for address");
793 if (source.IsDefined(t.Identifier())) {
794 const ParsedDefinition &def(GetDefinition(t.Identifier()));
795 void *addr(GetObject(def.type, t.Identifier()));
796 *reinterpret_cast<void **>(dest) = addr;
798 throw Error("postponing values in scripts not implemented");
802 void Interpreter::ReadScriptInteger(const ScriptToken &t, char *dest) {
803 if (t.GetType() == ScriptToken::IDENTIFIER) {
804 if (source.IsDefined(t.Identifier())) {
805 void *num(GetObject(TypeDescription::GetTypeId("Number"), t.Identifier()));
806 *reinterpret_cast<int *>(dest) = *reinterpret_cast<int *>(num);
808 throw Error("postponing values in scripts not implemented");
810 } else if (t.GetType() == ScriptToken::LITERAL) {
811 *reinterpret_cast<int *>(dest) = t.GetLiteral()->GetNumber();
813 throw Error("expected identifier or integer literal");
817 void Interpreter::ReadScriptVector(const ScriptToken &t, char *dest) {
818 if (t.GetType() == ScriptToken::IDENTIFIER) {
819 if (source.IsDefined(t.Identifier())) {
820 void *vec(GetObject(TypeDescription::GetTypeId("Vector"), t.Identifier()));
821 *reinterpret_cast<Vector<int> *>(dest) = *reinterpret_cast<Vector<int> *>(vec);
823 throw Error("postponing values in scripts not implemented");
825 } else if (t.GetType() == ScriptToken::LITERAL) {
826 *reinterpret_cast<Vector<int> *>(dest) = Vector<int>(t.GetLiteral()->GetX(), t.GetLiteral()->GetY());
828 throw Error("expected identifier or vector literal");
833 SDL_Surface *Interpreter::GetImage(const string &path) {
834 std::map<string, SDL_Surface *>::const_iterator result(imageCache.find(path));
835 if (result != imageCache.end()) {
836 return result->second;
838 SDL_Surface *image(IMG_Load(path.c_str()));
839 imageCache.insert(make_pair(path, image));
845 bool Interpreter::CanLink(const Value &v) const {
846 return v.IsLiteral() || source.IsDefined(v.GetIdentifier());
849 void Interpreter::Postpone(int type, int id, std::ptrdiff_t offset, const std::string &identifier, int linkedType, bool inlined) {
850 char *str(alloc.Alloc(identifier.size() + 1));
851 std::memcpy(str, identifier.c_str(), identifier.size());
852 str[identifier.size()] = '\0';
853 postponedDefinitions.push_back(PostponedDefinition(type, id, offset, str, linkedType, inlined));
857 void Interpreter::CreateTypeDescriptions() {
859 TypeDescription &td(TypeDescription::Create(BOOLEAN_ID, "Boolean"));
860 td.SetDescription("Logical value which can be either true or false.");
861 td.SetSize(sizeof(bool));
864 TypeDescription &td(TypeDescription::Create(COLOR_ID, "Color"));
866 "A color in RGB format with an optional alpha channel.\n"
867 "Components range from 0 to 255.\n"
868 "Alpha defaults to 255 if omitted.");
869 td.SetSize(sizeof(Color));
872 TypeDescription &td(TypeDescription::Create(IMAGE_ID, "Image"));
873 td.SetDescription("Path to a PNG file with image data.");
874 td.SetSize(sizeof(SDL_Surface));
877 TypeDescription &td(TypeDescription::Create(NUMBER_ID, "Number"));
878 td.SetDescription("A signed integer.");
879 td.SetSize(sizeof(int));
882 TypeDescription &td(TypeDescription::Create(PATH_ID, "Path"));
883 td.SetDescription("A path in the filesystem which is interpreted relative to the source file's location.");
885 td.AddSupertype(STRING_ID, 0);
888 TypeDescription &td(TypeDescription::Create(SCRIPT_ID, "Script"));
889 td.SetDescription("Collection of commands that define a behaviour.");
890 td.SetSize(sizeof(Script));
893 TypeDescription &td(TypeDescription::Create(STRING_ID, "String"));
894 td.SetDescription("Some characters.");
898 TypeDescription &td(TypeDescription::Create(VECTOR_ID, "Vector"));
899 td.SetDescription("A pair of numbers usually describing a 2D translation or offset.");
900 td.SetSize(sizeof(Vector<int>));