1 #include "Interpreter.h"
3 #include "ParsedSource.h"
4 #include "TypeDescription.h"
5 #include "../battle/Hero.h"
6 #include "../battle/Monster.h"
7 #include "../battle/PartyLayout.h"
8 #include "../battle/Resources.h"
9 #include "../common/Ikari.h"
10 #include "../common/Item.h"
11 #include "../common/Script.h"
12 #include "../common/Spell.h"
13 #include "../common/Stats.h"
14 #include "../common/TargetingMode.h"
15 #include "../graphics/ComplexAnimation.h"
16 #include "../graphics/Font.h"
17 #include "../graphics/Frame.h"
18 #include "../graphics/Gauge.h"
19 #include "../graphics/Menu.h"
20 #include "../graphics/SimpleAnimation.h"
21 #include "../graphics/Sprite.h"
25 #include <SDL_image.h>
28 using battle::Monster;
29 using battle::PartyLayout;
35 using common::TargetingMode;
36 using graphics::Animation;
37 using graphics::Color;
39 using graphics::Frame;
40 using graphics::Gauge;
41 using graphics::ComplexAnimation;
42 using graphics::SimpleAnimation;
43 using graphics::Sprite;
52 Interpreter::~Interpreter() {
53 for (std::map<string, SDL_Surface *>::const_iterator i(imageCache.begin()), end(imageCache.end()); i != end; ++i) {
54 SDL_FreeSurface(i->second);
59 const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &identifier) {
60 std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(identifier));
61 if (i != parsedDefinitions.end()) {
63 } else if (source.IsDefined(identifier)) {
64 ReadDefinition(source.GetDefinition(identifier));
65 return parsedDefinitions.at(identifier);
67 throw Error("access to undefined object " + identifier);
72 void *Interpreter::GetObject(int typeId, const std::string &name) {
73 std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
74 if (i != parsedDefinitions.end()) {
75 const TypeDescription &requested(TypeDescription::Get(typeId));
76 const TypeDescription &actual(TypeDescription::Get(i->second.type));
77 if (requested.TypeId() == actual.TypeId()) {
78 return values[actual.TypeId()][i->second.id];
79 } else if (actual.IsSubtypeOf(requested)) {
80 char *sub(reinterpret_cast<char *>(values[actual.TypeId()][i->second.id]));
81 std::ptrdiff_t offset(actual.SupertypeOffset(requested));
84 throw Error("cannot cast " + actual.TypeName() + " to " + requested.TypeName());
87 throw Error("access to undefined object " + name);
92 void Interpreter::ReadSource() {
93 for (set<string>::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) {
94 ReadDefinition(source.GetDefinition(*i));
98 void Interpreter::ReadDefinition(const Definition &dfn) {
99 if (parsedDefinitions.find(dfn.Identifier()) != parsedDefinitions.end()) {
102 if (dfn.HasLiteralValue()) {
109 void Interpreter::ReadLiteral(const Definition &dfn) {
110 const string &typeName(dfn.GetLiteral()->IsArray() ? "Array" : dfn.GetLiteral()->GetTypeName());
111 int typeId(TypeDescription::GetTypeId(typeName));
112 int id(values[typeId].size());
113 const TypeDescription &td(TypeDescription::Get(typeId));
115 (dfn.GetLiteral()->GetType() == Literal::PATH
116 || dfn.GetLiteral()->GetType() == Literal::STRING)
117 ? dfn.GetLiteral()->GetString().size() : td.Size());
118 char *object(alloc.Alloc(size));
119 values[typeId].push_back(object);
120 parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
121 if (dfn.GetLiteral()->GetType() == Literal::OBJECT) {
122 ReadObject(typeId, id, object, *dfn.GetLiteral()->GetProperties());
124 ReadLiteral(typeId, id, object, *dfn.GetLiteral());
128 void Interpreter::ReadLiteral(int typeId, int id, char *object, const Literal &literal) {
129 switch (literal.GetType()) {
130 case Literal::ARRAY_VALUES:
131 case Literal::ARRAY_PROPS:
132 case Literal::ARRAY_IDENTS:
133 throw Error("named 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 case Literal::ARRAY_PROPS:
181 case Literal::ARRAY_IDENTS:
182 throw Error("cannot copy arrays, sorry");
184 case Literal::BOOLEAN:
186 typeId = TypeDescription::GetTypeId("Boolean");
187 id = values[typeId].size();
188 const TypeDescription &td(TypeDescription::Get(typeId));
189 char *object(alloc.Alloc(td.Size()));
190 values[typeId].push_back(new (object) bool(v.GetLiteral().GetBoolean()));
195 typeId = TypeDescription::GetTypeId("Color");
196 id = values[typeId].size();
197 const TypeDescription &td(TypeDescription::Get(typeId));
198 char *object(alloc.Alloc(td.Size()));
199 values[typeId].push_back(new (object) Color(v.GetLiteral().GetRed(), v.GetLiteral().GetGreen(), v.GetLiteral().GetBlue(), v.GetLiteral().GetAlpha()));
202 case Literal::NUMBER:
204 typeId = TypeDescription::GetTypeId("Number");
205 id = values[typeId].size();
206 const TypeDescription &td(TypeDescription::Get(typeId));
207 char *object(alloc.Alloc(td.Size()));
208 values[typeId].push_back(new (object) int(v.GetLiteral().GetNumber()));
213 typeId = TypeDescription::GetTypeId("Path");
214 id = values[typeId].size();
215 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
216 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
217 str[v.GetLiteral().GetString().size()] = '\0';
218 values[typeId].push_back(str);
221 case Literal::SCRIPT:
223 typeId = TypeDescription::GetTypeId("Script");
224 char *script(ReadScript(v.GetLiteral().GetScript()));
225 id = values[typeId].size();
226 values[typeId].push_back(script);
229 case Literal::STRING:
231 typeId = TypeDescription::GetTypeId("String");
232 id = values[typeId].size();
233 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
234 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
235 str[v.GetLiteral().GetString().size()] = '\0';
236 values[typeId].push_back(str);
239 case Literal::VECTOR:
241 typeId = TypeDescription::GetTypeId("Vector");
242 id = values[typeId].size();
243 const TypeDescription &td(TypeDescription::Get(typeId));
244 char *object(alloc.Alloc(td.Size()));
245 values[typeId].push_back(new (object) Vector<int>(v.GetLiteral().GetX(), v.GetLiteral().GetY()));
248 case Literal::OBJECT:
250 typeId = TypeDescription::GetTypeId(v.GetLiteral().GetTypeName());
251 const TypeDescription &td(TypeDescription::Get(typeId));
252 id = values[typeId].size();
253 char *object(alloc.Alloc(td.Size()));
254 td.Construct(object);
255 ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
259 return values[typeId][id];
262 ReadDefinition(source.GetDefinition(v.GetIdentifier()));
263 return GetObject(typeId, v.GetIdentifier());
268 void Interpreter::ReadObject(const Definition &dfn) {
269 int typeId(TypeDescription::GetTypeId(dfn.TypeName()));
270 const TypeDescription &td(TypeDescription::Get(typeId));
271 int id(values[typeId].size());
272 char *object(alloc.Alloc(td.Size()));
273 td.Construct(object);
274 values[typeId].push_back(object);
275 parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
276 ReadObject(typeId, id, object, *dfn.GetProperties());
280 void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyList &props) {
281 const TypeDescription &td(TypeDescription::Get(typeId));
282 for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) {
283 const FieldDescription &fd(td.GetField(i->first));
284 const TypeDescription &fieldType(TypeDescription::Get(fd.TypeId()));
285 if (CanLink(*i->second)) {
286 char *dest(object + fd.Offset());
287 if (fd.IsAggregate()) {
288 int arraySize(i->second->GetLiteral().ArraySize());
290 if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) {
291 aggregate = alloc.Alloc(fieldType.Size() * arraySize);
292 char *iter = aggregate;
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);
298 } else if (i->second->GetLiteral().GetType() == Literal::ARRAY_VALUES) {
299 aggregate = alloc.Alloc(fieldType.Size() * arraySize);
300 char *iter = aggregate;
301 const vector<Value *> &list(i->second->GetLiteral().GetValues());
302 for (vector<Value *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
303 fieldType.Construct(iter);
304 ReadLiteral(fieldType.TypeId(), -1, iter, (*j)->GetLiteral());
307 aggregate = alloc.Alloc(sizeof(char *) * arraySize);
308 char *iter = aggregate;
309 const vector<string> &list(i->second->GetLiteral().GetIdentifiers());
310 for (vector<string>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += sizeof(void *)) {
311 if (source.IsDefined(*j)) {
312 *reinterpret_cast<void **>(iter)
313 = GetObject(fd.TypeId(), *j);
315 Postpone(typeId, id, fd.Offset() + (iter - aggregate), *j, fd.TypeId(), false);
319 if (fd.IsReferenced()) {
320 std::memcpy(dest, &aggregate, sizeof(char *));
321 dest += sizeof(char *);
322 std::memcpy(dest, &arraySize, sizeof(int));
324 throw Error("aggregate type fields must be referenced");
326 } else if (i->second->IsLiteral() && !fd.IsReferenced()) {
328 if (i->second->GetLiteral().IsObject()) {
329 ReadObject(fd.TypeId(), -1, dest, *i->second->GetLiteral().GetProperties());
331 ReadLiteral(fd.TypeId(), -1, dest, i->second->GetLiteral());
334 char *src(reinterpret_cast<char *>(GetObject(fd.TypeId(), *i->second)));
335 if (fd.TypeId() == TypeDescription::GetTypeId("Image")) {
336 src = reinterpret_cast<char *>(GetImage(src));
338 if (fd.IsReferenced()) {
339 std::memcpy(dest, &src, sizeof(char *));
341 std::memcpy(dest, src, fieldType.Size());
345 Postpone(typeId, id, fd.Offset(), i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced());
352 void Interpreter::ReadScript(const std::vector<ScriptToken *> &s, Script *script) {
353 std::map<string, int> labels;
355 for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
356 if ((*i)->GetType() == ScriptToken::LABEL) {
357 if (labels.count((*i)->Label())) {
358 throw Error("duplicate label " + (*i)->Label());
360 labels[(*i)->Label()] = size;
362 } else if ((*i)->GetType() != ScriptToken::COMMAND) {
363 throw Error("unexpected script token");
365 size += sizeof(Script::Code);
366 const string &cmd((*i)->CommandName());
370 throw Error("unexpected script end after move");
372 const string ®((*i)->RegisterName());
373 if (reg.size() != 2) {
374 throw Error("invalid register name " + reg);
378 throw Error("unexpected script end after move");
380 if ((*i)->GetType() != ScriptToken::REGISTER) {
383 size += sizeof(void *);
389 size += sizeof(Vector<int>);
392 throw Error("unknown register " + reg);
395 } else if (cmd == "add") {
398 throw Error("unexpected script end after add");
400 const string ®((*i)->RegisterName());
401 if (reg.size() != 2) {
402 throw Error("invalid register name " + reg);
406 throw Error("unexpected script end after add");
408 if ((*i)->GetType() != ScriptToken::REGISTER) {
414 size += sizeof(Vector<int>);
417 throw Error("expected register after add " + reg);
420 } else if (cmd == "mod") {
423 throw Error("unexpected script end after mod");
427 throw Error("unexpected script end after mod");
429 if ((*i)->GetType() != ScriptToken::REGISTER) {
432 } else if (cmd == "rand") {
435 throw Error("unexpected script end after rand");
437 } else if (cmd == "cmp") {
440 throw Error("unexpected script end after cmp");
442 if ((*i)->GetType() != ScriptToken::REGISTER) {
447 throw Error("unexpected script end after cmp");
449 if ((*i)->GetType() != ScriptToken::REGISTER) {
452 } else if (cmd == "jmp") {
456 throw Error("unexpected script end after cmp");
458 } else if (cmd == "jeq") {
462 throw Error("unexpected script end after cmp");
464 } else if (cmd == "jne") {
468 throw Error("unexpected script end after cmp");
470 } else if (cmd == "jl") {
474 throw Error("unexpected script end after cmp");
476 } else if (cmd == "jle") {
480 throw Error("unexpected script end after cmp");
482 } else if (cmd == "jg") {
486 throw Error("unexpected script end after cmp");
488 } else if (cmd == "jge") {
492 throw Error("unexpected script end after cmp");
494 } else if (cmd == "sysc") {
497 throw Error("unknown command " + cmd);
501 char *text(alloc.Alloc(size));
503 for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
504 if ((*i)->GetType() == ScriptToken::LABEL) {
507 if ((*i)->GetType() != ScriptToken::COMMAND) {
508 throw Error("unexpected script token");
510 const string &cmd((*i)->CommandName());
512 Script::Code &code(CreateScriptCode(Script::COMMAND_MOVE, text + cursor));
513 cursor += sizeof(Script::Code);
516 const string ®((*i)->RegisterName());
519 code.type = Script::TYPE_ADDRESS;
522 code.type = Script::TYPE_INTEGER;
525 code.type = Script::TYPE_VECTOR;
528 throw Error("invalid register " + reg);
530 int regnum(reg[1] - '0');
531 if (regnum < 0 || regnum > 6) {
532 throw Error("invalid register " + reg);
537 if ((*i)->GetType() == ScriptToken::REGISTER) {
538 string reg2((*i)->RegisterName());
539 if (reg[0] != reg2[0]) {
540 throw Error("mixed-type commands not allowed");
542 int reg2num(reg[1] - '0');
543 if (reg2num < 0 || reg2num > 6) {
544 throw Error("invalid register " + reg2);
550 case Script::TYPE_ADDRESS:
551 ReadScriptAddress(**i, text + cursor);
552 cursor += sizeof(void *);
554 case Script::TYPE_INTEGER:
555 ReadScriptInteger(**i, text + cursor);
556 cursor += sizeof(int);
558 case Script::TYPE_VECTOR:
559 ReadScriptVector(**i, text + cursor);
560 cursor += sizeof(Vector<int>);
564 } else if (cmd == "add") {
565 Script::Code &code(CreateScriptCode(Script::COMMAND_ADD, text + cursor));
566 cursor += sizeof(Script::Code);
569 const string ®((*i)->RegisterName());
572 code.type = Script::TYPE_INTEGER;
575 code.type = Script::TYPE_VECTOR;
578 throw Error("invalid register " + reg);
580 int regnum(reg[1] - '0');
581 if (regnum < 0 || regnum > 6) {
582 throw Error("invalid register " + reg);
587 if ((*i)->GetType() == ScriptToken::REGISTER) {
588 string reg2((*i)->RegisterName());
589 if (reg[0] != reg2[0]) {
590 throw Error("mixed-type commands not allowed");
592 int reg2num(reg[1] - '0');
593 if (reg2num < 0 || reg2num > 6) {
594 throw Error("invalid register name " + reg2);
600 case Script::TYPE_INTEGER:
601 ReadScriptInteger(**i, text + cursor);
602 cursor += sizeof(int);
604 case Script::TYPE_VECTOR:
605 ReadScriptVector(**i, text + cursor);
606 cursor += sizeof(Vector<int>);
610 } else if (cmd == "mod") {
611 Script::Code &code(CreateScriptCode(Script::COMMAND_MOD, text + cursor));
612 cursor += sizeof(Script::Code);
615 const string ®((*i)->RegisterName());
617 throw Error("invalid register " + reg);
619 code.type = Script::TYPE_INTEGER;
620 int regnum(reg[1] - '0');
621 if (regnum < 0 || regnum > 6) {
622 throw Error("invalid register " + reg);
627 if ((*i)->GetType() == ScriptToken::REGISTER) {
628 string reg2((*i)->RegisterName());
629 if (reg[0] != reg2[0]) {
630 throw Error("mixed-type commands not allowed");
632 int reg2num(reg[1] - '0');
633 if (reg2num < 0 || reg2num > 6) {
634 throw Error("invalid register name " + reg2);
639 ReadScriptInteger(**i, text + cursor);
640 cursor += sizeof(int);
642 } else if (cmd == "rand") {
643 Script::Code &code(CreateScriptCode(Script::COMMAND_RAND, text + cursor));
644 cursor += sizeof(Script::Code);
647 const string ®((*i)->RegisterName());
649 throw Error("invalid register " + reg);
651 code.type = Script::TYPE_INTEGER;
652 int regnum(reg[1] - '0');
653 if (regnum < 0 || regnum > 6) {
654 throw Error("invalid register " + reg);
657 } else if (cmd == "cmp") {
658 Script::Code &code(CreateScriptCode(Script::COMMAND_CMP, text + cursor));
659 cursor += sizeof(Script::Code);
662 const string ®((*i)->RegisterName());
664 throw Error("invalid register " + reg);
666 code.type = Script::TYPE_INTEGER;
667 int regnum(reg[1] - '0');
668 if (regnum < 0 || regnum > 6) {
669 throw Error("invalid register " + reg);
674 if ((*i)->GetType() == ScriptToken::REGISTER) {
675 string reg2((*i)->RegisterName());
676 if (reg[0] != reg2[0]) {
677 throw Error("mixed-type commands not allowed");
679 int reg2num(reg[1] - '0');
680 if (reg2num < 0 || reg2num > 6) {
681 throw Error("invalid register name " + reg2);
686 ReadScriptInteger(**i, text + cursor);
687 cursor += sizeof(int);
689 } else if (cmd == "jmp") {
690 Script::Code &code(CreateScriptCode(Script::COMMAND_JMP, text + cursor));
691 cursor += sizeof(Script::Code);
694 if (!labels.count((*i)->Identifier())) {
695 throw Error("use of undefined label " + (*i)->Identifier());
697 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
698 cursor += sizeof(int);
699 } else if (cmd == "jeq") {
700 Script::Code &code(CreateScriptCode(Script::COMMAND_JEQ, text + cursor));
701 cursor += sizeof(Script::Code);
704 if (!labels.count((*i)->Identifier())) {
705 throw Error("use of undefined label " + (*i)->Identifier());
707 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
708 cursor += sizeof(int);
709 } else if (cmd == "jne") {
710 Script::Code &code(CreateScriptCode(Script::COMMAND_JNE, text + cursor));
711 cursor += sizeof(Script::Code);
714 if (!labels.count((*i)->Identifier())) {
715 throw Error("use of undefined label " + (*i)->Identifier());
717 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
718 cursor += sizeof(int);
719 } else if (cmd == "jl") {
720 Script::Code &code(CreateScriptCode(Script::COMMAND_JL, text + cursor));
721 cursor += sizeof(Script::Code);
724 if (!labels.count((*i)->Identifier())) {
725 throw Error("use of undefined label " + (*i)->Identifier());
727 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
728 cursor += sizeof(int);
729 } else if (cmd == "jle") {
730 Script::Code &code(CreateScriptCode(Script::COMMAND_JLE, text + cursor));
731 cursor += sizeof(Script::Code);
734 if (!labels.count((*i)->Identifier())) {
735 throw Error("use of undefined label " + (*i)->Identifier());
737 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
738 cursor += sizeof(int);
739 } else if (cmd == "jg") {
740 Script::Code &code(CreateScriptCode(Script::COMMAND_JG, text + cursor));
741 cursor += sizeof(Script::Code);
744 if (!labels.count((*i)->Identifier())) {
745 throw Error("use of undefined label " + (*i)->Identifier());
747 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
748 cursor += sizeof(int);
749 } else if (cmd == "jge") {
750 Script::Code &code(CreateScriptCode(Script::COMMAND_JGE, text + cursor));
751 cursor += sizeof(Script::Code);
754 if (!labels.count((*i)->Identifier())) {
755 throw Error("use of undefined label " + (*i)->Identifier());
757 *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
758 cursor += sizeof(int);
759 } else if (cmd == "sysc") {
760 Script::Code &code(CreateScriptCode(Script::COMMAND_SYSC, text + cursor));
761 cursor += sizeof(Script::Code);
764 throw Error("unknown command " + cmd);
769 script->textlen = size;
772 char *Interpreter::ReadScript(const vector<ScriptToken *> &s) {
773 char *mem(alloc.Alloc(sizeof(Script)));
775 Script *script(reinterpret_cast<Script *>(mem));
776 ReadScript(s, script);
780 Script::Code &Interpreter::CreateScriptCode(Script::Command c, char *dest) {
781 Script::Code &code(*reinterpret_cast<Script::Code *>(dest));
784 code.type = Script::TYPE_NONE;
790 void Interpreter::ReadScriptAddress(const ScriptToken &t, char *dest) {
791 if (t.GetType() != ScriptToken::IDENTIFIER) {
792 throw Error("expected identifier for address");
794 if (source.IsDefined(t.Identifier())) {
795 const ParsedDefinition &def(GetDefinition(t.Identifier()));
796 void *addr(GetObject(def.type, t.Identifier()));
797 *reinterpret_cast<void **>(dest) = addr;
799 throw Error("postponing values in scripts not implemented");
803 void Interpreter::ReadScriptInteger(const ScriptToken &t, char *dest) {
804 if (t.GetType() == ScriptToken::IDENTIFIER) {
805 if (source.IsDefined(t.Identifier())) {
806 void *num(GetObject(TypeDescription::GetTypeId("Number"), t.Identifier()));
807 *reinterpret_cast<int *>(dest) = *reinterpret_cast<int *>(num);
809 throw Error("postponing values in scripts not implemented");
811 } else if (t.GetType() == ScriptToken::LITERAL) {
812 *reinterpret_cast<int *>(dest) = t.GetLiteral()->GetNumber();
814 throw Error("expected identifier or integer literal");
818 void Interpreter::ReadScriptVector(const ScriptToken &t, char *dest) {
819 if (t.GetType() == ScriptToken::IDENTIFIER) {
820 if (source.IsDefined(t.Identifier())) {
821 void *vec(GetObject(TypeDescription::GetTypeId("Vector"), t.Identifier()));
822 *reinterpret_cast<Vector<int> *>(dest) = *reinterpret_cast<Vector<int> *>(vec);
824 throw Error("postponing values in scripts not implemented");
826 } else if (t.GetType() == ScriptToken::LITERAL) {
827 *reinterpret_cast<Vector<int> *>(dest) = Vector<int>(t.GetLiteral()->GetX(), t.GetLiteral()->GetY());
829 throw Error("expected identifier or vector literal");
834 SDL_Surface *Interpreter::GetImage(const string &path) {
835 std::map<string, SDL_Surface *>::const_iterator result(imageCache.find(path));
836 if (result != imageCache.end()) {
837 return result->second;
839 SDL_Surface *image(IMG_Load(path.c_str()));
840 imageCache.insert(make_pair(path, image));
846 bool Interpreter::CanLink(const Value &v) const {
847 return v.IsLiteral() || source.IsDefined(v.GetIdentifier());
850 void Interpreter::Postpone(int type, int id, std::ptrdiff_t offset, const std::string &identifier, int linkedType, bool inlined) {
851 char *str(alloc.Alloc(identifier.size() + 1));
852 std::memcpy(str, identifier.c_str(), identifier.size());
853 str[identifier.size()] = '\0';
854 postponedDefinitions.push_back(PostponedDefinition(type, id, offset, str, linkedType, inlined));
858 void Interpreter::CreateTypeDescriptions() {
860 TypeDescription &td(TypeDescription::Create(BOOLEAN_ID, "Boolean"));
861 td.SetDescription("Logical value which can be either true or false.");
862 td.SetSize(sizeof(bool));
865 TypeDescription &td(TypeDescription::Create(COLOR_ID, "Color"));
867 "A color in RGB format with an optional alpha channel.\n"
868 "Components range from 0 to 255.\n"
869 "Alpha defaults to 255 if omitted.");
870 td.SetSize(sizeof(Color));
873 TypeDescription &td(TypeDescription::Create(IMAGE_ID, "Image"));
874 td.SetDescription("Path to a PNG file with image data.");
875 td.SetSize(sizeof(SDL_Surface));
878 TypeDescription &td(TypeDescription::Create(NUMBER_ID, "Number"));
879 td.SetDescription("A signed integer.");
880 td.SetSize(sizeof(int));
883 TypeDescription &td(TypeDescription::Create(PATH_ID, "Path"));
884 td.SetDescription("A path in the filesystem which is interpreted relative to the source file's location.");
886 td.AddSupertype(STRING_ID, 0);
889 TypeDescription &td(TypeDescription::Create(SCRIPT_ID, "Script"));
890 td.SetDescription("Collection of commands that define a behaviour.");
891 td.SetSize(sizeof(Script));
894 TypeDescription &td(TypeDescription::Create(STRING_ID, "String"));
895 td.SetDescription("Some characters.");
899 TypeDescription &td(TypeDescription::Create(VECTOR_ID, "Vector"));
900 td.SetDescription("A pair of numbers usually describing a 2D translation or offset.");
901 td.SetSize(sizeof(Vector<int>));