File: libimport.xml

package info (click to toggle)
enigma 1.30%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 76,132 kB
  • sloc: xml: 162,251; cpp: 67,393; ansic: 28,606; makefile: 1,986; sh: 1,298; yacc: 288; perl: 84; sed: 16
file content (218 lines) | stat: -rw-r--r-- 9,181 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<el:level xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://enigma-game.org/schema/level/1 level.xsd" xmlns:el="http://enigma-game.org/schema/level/1">
  <el:protected>
    <el:info el:type="library">
      <el:identity el:title="" el:id="lib/libimport"/>
      <el:version el:score="1" el:release="1" el:revision="2" el:status="released"/>
      <el:author el:name="Enigma Team" el:email="" el:homepage=""/>
      <el:copyright>Copyright © 2009 Enigma Team</el:copyright>
      <el:license el:type="GPL v2.0 or above" el:open="true"/>
      <el:compatibility el:enigma="1.10">
        <el:dependency el:path="lib/libmap" el:id="lib/libmap" el:release="1" el:preload="true"/>
      </el:compatibility>
      <el:modes el:easy="false" el:single="false" el:network="false"/>
      <el:comments>
      </el:comments>
      <el:score el:easy="-" el:difficult="-"/>
    </el:info>
    <el:luamain><![CDATA[

-- libimport.xml is dedicated to parse level files of other
-- games or formats and typically returns libmap-maps.
-- In this context, the word "level" refers to a string,
-- representing a level of the other game. "multilevel"
-- is a string composed of one or more levels.
-- A "monolevel" is a string which holds a single level,
-- but also additional information, so it has to be handled
-- as multilevel to extract the level.
-- A map is a map in the libmap-sense, i.e. an Enigma level.

lib.import = {}
setmetatable(lib.import, getmetatable(lib))

lib.import.line_regexp = {}

-------------------
-- General tools --
-------------------

function lib.import.unpack_multilevel(multilevel, sublevel_number, format)
    assert_type(multilevel, "lib.import.unpack_multilevel first argument", 2, "string")
    assert_type(sublevel_number, "lib.import.unpack_multilevel second argument", 2, "nil", "positive integer")
    local current_level_number = 0
    local level = ""
    -- search the correct sublevel by pattern matching, line for line
    local in_level = false
    for line in string.gmatch(multilevel, "([^\r\n\|]*)[\r\n\|]+") do
        local start_match, end_match = string.find(line, lib.import.line_regexp[format])
        if (start_match == 1) and (end_match == string.len(line)) then
            if not in_level then
                -- we just entered a new level
                current_level_number = current_level_number + 1
                in_level = true
            end
            if current_level_number == (sublevel_number or 1) then
                level = level..line.."\n"
            end
        else
            in_level = false
        end
    end
    assert_bool(level ~= "", "lib.import.unpack_multilevel: Multilevel holds less than "..sublevel_number.." levels!", 2)
    return level
end

function lib.import.uncompress_rle(level, attribs)
    assert_type(level, "lib.import.uncompress_rle first argument", 2, "string")
    assert_type(attribs, "lib.import.uncompress_rle second argument", 2, "nil", "table")
    local uncompressed = ""
    local rle_counter = nil
    local error_on_multiple = (attribs or {}).error_on_multiple
    for j = 1, string.len(level) do
        local ch = string.sub(level, j, j)
        if tonumber(ch) then
            -- add number for runlength encoding
            rle_counter = 10 * (rle_counter or 0) + tonumber(ch)
        else
            if error_on_multiple and ((rle_counter or 1) > 1) then
                -- check whether character is allowed as multiple
                if string.find(ch, error_on_multiple) then
                    error("lib.import.uncompress_rle: Level uses rle-compression on an invalid character.", 2)
                end
            end
            uncompressed = uncompressed .. string.rep(ch, rle_counter or 1)
            rle_counter = nil
        end
    end
    return uncompressed
end

function lib.import.string_replace(level, old_string, new_string)
    return string.gsub(level, old_string, function(s) return new_string end)
end

function lib.import.string_remove_multiples(level, ch)
    local result = level
    while string.find(result, ch..ch) do
        result = lib.import.string_replace(result, ch..ch, ch)
    end
    return result
end

-- When using level_to_map, make sure in advance that the level ends
-- with a proper line ending, and only one line ending.
function lib.import.level_to_map(level, line_ending, default_key)
    assert_type(level, "lib.import.level_to_map first argument", 2, "string")
    assert_type(line_ending, "lib.import.level_to_map second argument", 2, "nil", "non-empty string")
    assert_type(default_key, "lib.import.level_to_map third argument", 2, "nil", "non-empty string")
    local premap = {}
    local reg_exp_line = "(.-)" .. (line_ending or "\n")
    string.gsub(level, reg_exp_line, function (s)
        table.insert(premap, s)
    end)
    return wo:newMap(default_key or " ", premap)
end

----------------------------------------
-- Specific import data and functions --
----------------------------------------

--------------------------
-- Sokoban level format --
--------------------------

-- Sokoban level files can be very different - they can use
-- runlength encoding and multilevel files. Sometimes, "|"
-- is used as line ending instead of or together with "\n".
-- " ", "_" and "-" can all represent space. Sometimes, the
-- outside is filled with " ", then again with "#" (what we
-- call "redundant walls"). Finally, line width can vary.
-- We use a slightly generalized version, to include
-- chessoban levels. Allowed characters are:
--    - _ space  space
--    #          wall
--    .          goal
--    $ *        box, box with goal
--    n N        st_chess, st_chess with goal
--    @ +        player, player with goal
-- The returned map will use " " for inside space, "-" for
-- outside space, default key is " ".

lib.import.line_regexp["sokoban"] =
      "[ \-\#\_\$\.@\*0-9Nn\+]*"  -- all allowed characters except line ending
   .. "[\#\$\.@\*Nn\+]+"          -- at least one non-space character
   .. "[ \-\#\_\$\.@\*0-9Nn\+]*"  -- again all allowed characters except line ending
   .. "[\r]?"                     -- maybe a carriage return from line ending

function lib.import.map_sokoban(multilevel, sublevel_number, keylength_one)
    assert_type(multilevel, "lib.import.map_sokoban first argument", 2, "non-empty string")
    assert_type(sublevel_number, "lib.import.map_sokoban second argument", 2, "nil", "positive integer")
    local level
    level = lib.import.unpack_multilevel(multilevel .. "\n", sublevel_number or 1, "sokoban")
    level = lib.import.uncompress_rle(level, {error_on_multiple = "|\n"})
    level = lib.import.string_replace(level, "\r\n", "\n")
    level = lib.import.string_replace(level, "|", "\n")
    level = lib.import.string_remove_multiples(level .. "\n", "\n")
    local map = lib.import.level_to_map(level, "\n", " ")
    map:replace("_")
    map:replace("-")
    map:replace_outside(" ", "-")
    -- Remove redundant walls by outside:
    -- A wall is redundant, if it is surrounded by "-" or "#".
    -- In this case, it can be replaced by "-".
    map.defaultkey = "-"
    map[map:match({{po(0,0), "#"}, {NEIGHBORS_8, "-", "#"}})] = "-"
    map = map:trim()
    map.defaultkey = " "
    -- MAP now is a ready-to-use keylength-one-map.
    -- If KEYLENGTH_ONE is true, we may return the map;
    -- otherwise, we resolve the characters "*", "N" and
    -- "+", which include triggers.
    if keylength_one then
        return map
    end
    twocharmap = map * wo:newMap(" ")
    twocharmap:replace(". ", " .")
    twocharmap:replace("* ", "$.")
    twocharmap:replace("N ", "n.")
    twocharmap:replace("+ ", "@.")
    return twocharmap
end

---------------------------
-- Wanderer level format --
---------------------------

-- Wanderer is a game originally created by Steven Shipway in 1988.
-- Wanderer level files are uncompressed monolevels with fixed
-- width. The level itself is followed by a short description
-- (title/author/email) in a single line or a line of "#"s. Last
-- line optionally is a number. A Wanderer level knows the
-- following characters (taken from Wanderer's editor):
--    : _ #      earth, rock, indestructible rock
--    * - space  treasure, alternative space, space
--    O < > ^    falling boulder, arrow from right, arrow from left, balloon
--    ! + B      landmine, cage, bomb
--    / \\       deflectors
--    T A X @    teleport, arrival, exit, start
--    M S C ~    big monster, baby monster, time capsule, thingy

lib.import.line_regexp["wanderer"] =
      "[ \:\_\#\*\-O\<\>\^\!\+B\/\\TAX@MSC\~]+" -- at least one character

function lib.import.map_wanderer(monolevel)
    assert_type(monolevel, "lib.import.map_wanderer first argument", 2, "non-empty string")
    -- strip level from text lines
    local level = lib.import.unpack_multilevel(monolevel, 1, "wanderer")
    local map = lib.import.level_to_map(level, "\n", " ")
    -- replace alternative space by space (i.e. default key)
    map:replace("-")
    return map
end

    ]]></el:luamain>
    <el:i18n>
    </el:i18n>
  </el:protected>
</el:level>