void Interpreter::ReadLiteral(int typeId, int id, char *object, const Literal &literal) {
        switch (literal.GetType()) {
                case Literal::ARRAY_VALUES:
-                       throw Error("named value arrays are not supported, sorry");
-                       break;
                case Literal::ARRAY_PROPS:
-                       throw Error("named property list arrays are not supported, sorry");
+               case Literal::ARRAY_IDENTS:
+                       throw Error("named arrays are not supported, sorry");
                        break;
                case Literal::BOOLEAN:
                        new (object) bool(literal.GetBoolean());
                        int typeId(0), id(0);
                        switch (v.GetLiteral().GetType()) {
                                case Literal::ARRAY_VALUES:
-                                       throw Error("cannot copy value arrays, sorry");
-                                       break;
                                case Literal::ARRAY_PROPS:
-                                       throw Error("cannot copy property list arrays, sorry");
+                               case Literal::ARRAY_IDENTS:
+                                       throw Error("cannot copy arrays, sorry");
                                        break;
                                case Literal::BOOLEAN:
                                        {
                        char *dest(object + fd.Offset());
                        if (fd.IsAggregate()) {
                                int arraySize(i->second->GetLiteral().ArraySize());
-                               char *aggregate(alloc.Alloc(fieldType.Size() * arraySize));
-                               char *iter(aggregate);
+                               char *aggregate;
                                if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) {
+                                       aggregate = alloc.Alloc(fieldType.Size() * arraySize);
+                                       char *iter = aggregate;
                                        const vector<PropertyList *> &list(i->second->GetLiteral().GetPropertyLists());
                                        for (vector<PropertyList *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
                                                fieldType.Construct(iter);
                                                ReadObject(fieldType.TypeId(), -1, iter, **j);
                                        }
-                               } else {
+                               } else if (i->second->GetLiteral().GetType() == Literal::ARRAY_VALUES) {
+                                       aggregate = alloc.Alloc(fieldType.Size() * arraySize);
+                                       char *iter = aggregate;
                                        const vector<Value *> &list(i->second->GetLiteral().GetValues());
                                        for (vector<Value *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
                                                fieldType.Construct(iter);
                                                ReadLiteral(fieldType.TypeId(), -1, iter, (*j)->GetLiteral());
                                        }
+                               } else {
+                                       aggregate = alloc.Alloc(sizeof(char *) * arraySize);
+                                       char *iter = aggregate;
+                                       const vector<string> &list(i->second->GetLiteral().GetIdentifiers());
+                                       for (vector<string>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += sizeof(void *)) {
+                                               if (source.IsDefined(*j)) {
+                                                       *reinterpret_cast<void **>(iter)
+                                                                       = GetObject(fd.TypeId(), *j);
+                                               } else {
+                                                       Postpone(typeId, id, fd.Offset() + (iter - aggregate), *j, fd.TypeId(), false);
+                                               }
+                                       }
                                }
                                if (fd.IsReferenced()) {
                                        std::memcpy(dest, &aggregate, sizeof(char *));
 
 
 }
 
+Literal::Literal(const string &typeName, const vector<string> &ids)
+: props(0)
+, typeName(typeName)
+, identifiers(ids)
+, i1(0), i2(0)
+, i3(0), i4(0)
+, b(false)
+, type(ARRAY_IDENTS) {
+
+}
+
 Literal::Literal(bool b)
 : props(0)
 , typeName("Boolean")
        }
 }
 
+const vector<string> &Literal::GetIdentifiers() const {
+       if (type == ARRAY_IDENTS) {
+               return identifiers;
+       } else {
+               throw runtime_error("tried to access identifiers of non-array literal");
+       }
+}
+
 bool Literal::GetBoolean() const {
        if (type == BOOLEAN) {
                return b;
                case loader::Literal::ARRAY_PROPS:
                        out << "array of property lists";
                        break;
+               case loader::Literal::ARRAY_IDENTS:
+                       out << "array of identifiers";
+                       break;
                case loader::Literal::BOOLEAN:
                        out << "boolean, " << (l.GetBoolean() ? "true" : "false");
                        break;
 
        enum Type {
                ARRAY_VALUES,
                ARRAY_PROPS,
+               ARRAY_IDENTS,
                BOOLEAN,
                COLOR,
                NUMBER,
        };
 
 public:
+       /// array of values
        explicit Literal(const std::vector<Value *> &);
+       /// array of objects
        Literal(const std::string &, const std::vector<PropertyList *> &);
+       /// array of identifiers
+       Literal(const std::string &, const std::vector<std::string> &);
+       /// boolean
        explicit Literal(bool);
+       /// color
        Literal(int r, int g, int b, int a = 255);
+       /// number
        explicit Literal(int number);
+       /// path string
        Literal(const std::string &dir, const std::string &path);
+       /// string
        Literal(const std::string &);
+       /// vector
        Literal(int x, int y);
+       /// object
        Literal(const std::string &typeName, PropertyList *properties);
+       /// script
        explicit Literal(const std::vector<ScriptToken *> &);
        ~Literal();
 private:
 
 public:
        Type GetType() const { return type; }
-       bool IsArray() const { return GetType() == ARRAY_VALUES || GetType() == ARRAY_PROPS; }
+       bool IsArray() const { return GetType() == ARRAY_VALUES || GetType() == ARRAY_PROPS || GetType() == ARRAY_IDENTS; }
        bool IsObject() const { return GetType() == OBJECT; }
-       int ArraySize() const { return GetType() == ARRAY_VALUES ? GetValues().size() : GetPropertyLists().size(); }
+       int ArraySize() const { return GetType() == ARRAY_VALUES ? GetValues().size()
+                       : (GetType() == ARRAY_PROPS ? GetPropertyLists().size() : GetIdentifiers().size()); }
 
        const std::vector<Value *> &GetValues() const;
        const std::vector<PropertyList *> &GetPropertyLists() const;
+       const std::vector<std::string> &GetIdentifiers() const;
        bool GetBoolean() const;
        int GetRed() const;
        int GetGreen() const;
        std::string typeName, str;
        std::vector<Value *> values;
        std::vector<PropertyList *> propertyLists;
+       std::vector<std::string> identifiers;
        std::vector<ScriptToken *> script;
        int i1, i2, i3, i4;
        bool b;
 
        Token probe(GetToken());
 
        if (probe.type == Token::TYPE_NAME) {
-               vector<PropertyList *> values;
-               while (t.type != Token::BRACKET_CLOSE) {
-                       PropertyList *value(ParsePropertyList());
-                       values.push_back(value);
+               t = GetToken();
+               tok.Putback(t);
+               if (t.type == Token::ANGLE_BRACKET_OPEN) {
+                       vector<PropertyList *> values;
+                       while (t.type != Token::BRACKET_CLOSE) {
+                               PropertyList *value(ParsePropertyList());
+                               values.push_back(value);
 
-                       t = GetToken();
-                       if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
-                               throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
+                               t = GetToken();
+                               if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
+                                       throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
+                               }
+                       }
+                       return new Literal(probe.str, values);
+               } else {
+                       vector<string> values;
+                       while (t.type != Token::BRACKET_CLOSE) {
+                               string value(ParseIdentifier());
+                               values.push_back(value);
+
+                               t = GetToken();
+                               if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
+                                       throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
+                               }
                        }
+                       return new Literal(probe.str, values);
                }
-               return new Literal(probe.str, values);
        } else {
                tok.Putback(probe);
 
 
 
        /// Add monsters. This will cause the entity to be Hostile() and result in a
        /// battle scene with given monsters when touched.
-       void SetMonsters(battle::Monster *m, int num) { monsters = m; numMonsters = num; }
-       battle::Monster *MonstersBegin() { return monsters; }
-       battle::Monster *MonstersEnd() { return monsters + numMonsters; }
+       void SetMonsters(battle::Monster **m, int num) { monsters = m; numMonsters = num; }
+       battle::Monster **MonstersBegin() { return monsters; }
+       battle::Monster **MonstersEnd() { return monsters + numMonsters; }
 
        /// Get an entity that should follow in this one's steps or 0 if none.
        Entity *Follower() { return follower; }
        const graphics::Animation *animation;
        const graphics::Sprite *sprite;
        battle::PartyLayout *partyLayout;
-       battle::Monster *monsters;
+       battle::Monster **monsters;
        int numMonsters;
        graphics::AnimationRunner runner;
        geometry::Vector<int> spriteOffset;
 
                                                battleState->AddHero(*game->state->party[i]);
                                        }
                                }
-                               for (battle::Monster *monster((*e)->MonstersBegin()); monster != (*e)->MonstersEnd(); ++monster) {
-                                       battleState->AddMonster(*monster);
+                               for (battle::Monster **monster((*e)->MonstersBegin()); monster != (*e)->MonstersEnd(); ++monster) {
+                                       battleState->AddMonster(**monster);
                                }
 
                                ColorFade *fadeIn(new ColorFade(this, 0, 500, true));
 
                                repeat: true
                        },
                        position: <2, 1>,
-                       partyLayout: monstersLayout
-                       // TODO: monsters
+                       partyLayout: monstersLayout,
+                       monsters: [ Monster
+                               lizard,
+                               lizard
+                       ]
                },
                {
                        sprite: Sprite {