27 |
#include "oxyd.hh" |
#include "oxyd.hh" |
28 |
#include "enigma.hh" |
#include "enigma.hh" |
29 |
#include "sound.hh" |
#include "sound.hh" |
30 |
|
#include "objects.hh" |
31 |
|
#include "world.hh" |
32 |
|
#include "display.hh" |
33 |
|
|
34 |
#include "oxydlib/DatFile.h" |
#include "oxydlib/DatFile.h" |
|
#include "oxydlib/VecUtils.h" |
|
35 |
#include "oxydlib/FileUtils.h" |
#include "oxydlib/FileUtils.h" |
36 |
|
#include "oxydlib/Level.h" |
37 |
|
|
38 |
#include <string> |
#include <string> |
39 |
#include <cstdio> |
#include <cstdio> |
45 |
using namespace enigma; |
using namespace enigma; |
46 |
using namespace enigma::oxyd; |
using namespace enigma::oxyd; |
47 |
|
|
48 |
|
//---------------------------------------- |
49 |
|
// Oxyd level packs |
50 |
|
//---------------------------------------- |
51 |
|
namespace |
52 |
|
{ |
53 |
|
class LevelPack_Oxyd : public LevelPack { |
54 |
|
public: |
55 |
|
LevelPack_Oxyd (OxydVersion ver, DatFile *dat, bool twoplayers) |
56 |
|
: m_version(ver), m_datfile(dat), m_twoplayers(twoplayers) |
57 |
|
{ |
58 |
|
} |
59 |
|
|
60 |
|
// LevelPack interface |
61 |
|
string name() const; |
62 |
|
size_t size() const { return 100; } |
63 |
|
|
64 |
|
bool load_level (size_t index); |
65 |
|
|
66 |
|
LevelInfo *get_info (size_t index); |
67 |
|
private: |
68 |
|
// Private methods |
69 |
|
void load_floor (const Level &level); |
70 |
|
void load_stones (const Level &level); |
71 |
|
void load_actors (const Level &level); |
72 |
|
|
73 |
|
// Variables |
74 |
|
OxydVersion m_version; |
75 |
|
DatFile *m_datfile; |
76 |
|
bool m_twoplayers; |
77 |
|
|
78 |
|
static char *floor_map[256]; |
79 |
|
static char *item_map[256]; |
80 |
|
static char *stone_map[256]; |
81 |
|
}; |
82 |
|
} |
83 |
|
|
84 |
|
char *LevelPack_Oxyd::floor_map[256] = { |
85 |
|
"fl-abyss", // 0x00 |
86 |
|
"fl-gray", // 0x01 |
87 |
|
"fl-metal", // 0x02 |
88 |
|
"fl-metal", // 0x03 |
89 |
|
"fl-metal", // 0x04 |
90 |
|
"fl-metal", // 0x05 |
91 |
|
"fl-metal", // 0x06 |
92 |
|
"fl-metal", // 0x07 |
93 |
|
"fl-rough", // 0x08 |
94 |
|
"fl-normal", // 0x09 |
95 |
|
"fl-normal", // 0x0a |
96 |
|
"fl-stone", // 0x0b |
97 |
|
"fl-inverse", // 0x0c |
98 |
|
0, // 0x0d black tile |
99 |
|
0, // 0x0e white tile |
100 |
|
0, // 0x0f swamp |
101 |
|
0, // 0x10 swamp |
102 |
|
0, // 0x11 swamp |
103 |
|
0, // 0x12 swamp |
104 |
|
"fl-water", // 0x13 |
105 |
|
"fl-water", // 0x14 |
106 |
|
"fl-water", // 0x15 |
107 |
|
"fl-water", // 0x16 |
108 |
|
"fl-ice_001", // 0x17 |
109 |
|
"fl-ice_001", // 0x18 |
110 |
|
"fl-ice_001", // 0x19 |
111 |
|
"fl-ice_001", // 0x1a |
112 |
|
"fl-ice_001", // 0x1b |
113 |
|
"fl-space", // 0x1c |
114 |
|
"fl-space", // 0x1d |
115 |
|
"fl-space", // 0x1e |
116 |
|
"fl-space", // 0x1f |
117 |
|
"fl-space", // 0x20 |
118 |
|
"fl-space", // 0x21 space force down |
119 |
|
"fl-space", // 0x22 space force down |
120 |
|
"fl-gradient1", // 0x23 |
121 |
|
"fl-gradient2", // 0x24 |
122 |
|
"fl-gradient3", // 0x25 |
123 |
|
"fl-gradient4", // 0x26 |
124 |
|
"fl-gradient5", // 0x27 |
125 |
|
"fl-gradient6", // 0x28 |
126 |
|
"fl-gradient7", // 0x29 |
127 |
|
"fl-gradient8", // 0x2a |
128 |
|
"fl-gradient9", // 0x2b |
129 |
|
"fl-gradient10", // 0x2c |
130 |
|
"fl-gradient11", // 0x2d |
131 |
|
"fl-gradient12", // 0x2e |
132 |
|
"fl-gradient13", // 0x2f |
133 |
|
"fl-gradient14", // 0x30 |
134 |
|
"fl-gradient15", // 0x31 |
135 |
|
"fl-gradient16", // 0x32 |
136 |
|
}; |
137 |
|
|
138 |
|
char *LevelPack_Oxyd::item_map[256] = { |
139 |
|
|
140 |
|
}; |
141 |
|
|
142 |
|
char *LevelPack_Oxyd::stone_map[256] = { |
143 |
|
0, |
144 |
|
"st-oxyd", // 0x01 |
145 |
|
"st-oxyd", // 0x02 |
146 |
|
"st-oxyd", // 0x03 |
147 |
|
"st-oxyd", // 0x04 |
148 |
|
"st-oxyd", // 0x05 |
149 |
|
"st-oxyd", // 0x06 |
150 |
|
"st-oxyd", // 0x07 |
151 |
|
"st-oxyd", // 0x08 |
152 |
|
"st-oxyd", // 0x09 |
153 |
|
"st-oxyd", // 0x0a |
154 |
|
"st-oxyd", // 0x0b |
155 |
|
"st-oxyd", // 0x0c |
156 |
|
"st-oxyd", // 0x0d |
157 |
|
"st-oxyd", // 0x0e |
158 |
|
"st-oxyd", // 0x0f |
159 |
|
"st-oxyd", // 0x10 |
160 |
|
"st-fakeoxyd", // 0x11 |
161 |
|
0, // 0x12 |
162 |
|
0, // 0x13 |
163 |
|
0, // 0x14 |
164 |
|
0, // 0x15 |
165 |
|
0, // 0x16 |
166 |
|
0, // 0x17 |
167 |
|
"st-grate1", // 0x18 |
168 |
|
0, // 0x19 |
169 |
|
0, // 0x1a |
170 |
|
0, // 0x1b |
171 |
|
0, // 0x1c |
172 |
|
0, // 0x1d |
173 |
|
0, // 0x1e |
174 |
|
0, // 0x1f |
175 |
|
0, // 0x20 |
176 |
|
0, // 0x21 |
177 |
|
0, // 0x22 |
178 |
|
0, // 0x23 |
179 |
|
0, // 0x24 |
180 |
|
0, // 0x25 |
181 |
|
0, // 0x26 |
182 |
|
"st-wood", // 0x27 |
183 |
|
0, // 0x28 |
184 |
|
0, // 0x29 |
185 |
|
0, // 0x2a |
186 |
|
0, // 0x2b |
187 |
|
0, // 0x2c |
188 |
|
0, // 0x2d |
189 |
|
0, // 0x2e |
190 |
|
"st-death", // 0x2f |
191 |
|
"st-death_invisible", // 0x30 |
192 |
|
0, // 0x31 |
193 |
|
0, // 0x32 |
194 |
|
0, // 0x33 |
195 |
|
0, // 0x34 |
196 |
|
0, // 0x35 |
197 |
|
0, // 0x36 |
198 |
|
0, // 0x37 |
199 |
|
0, // 0x38 |
200 |
|
0, // 0x39 |
201 |
|
0, // 0x3a |
202 |
|
0, // 0x3b |
203 |
|
0, // 0x3c |
204 |
|
0, // 0x3d |
205 |
|
0, // 0x3e |
206 |
|
0, // 0x3f |
207 |
|
|
208 |
|
}; |
209 |
|
|
210 |
|
|
211 |
|
string |
212 |
|
LevelPack_Oxyd::name() const |
213 |
|
{ |
214 |
|
static char *names1p[] = { |
215 |
|
"Oxyd 1", "Oxyd magnum", "Per.Oxyd", "Oxyd extra" |
216 |
|
}; |
217 |
|
static char *names2p[] = { |
218 |
|
"Oxyd 1 (2p)", "Oxyd magnum (2p)", "Per.Oxyd (2p)", "Oxyd extra (2p)" |
219 |
|
}; |
220 |
|
return m_twoplayers ? names2p[m_version] : names1p[m_version]; |
221 |
|
} |
222 |
|
|
223 |
|
void |
224 |
|
LevelPack_Oxyd::load_floor (const Level &level) |
225 |
|
{ |
226 |
|
using namespace world; |
227 |
|
|
228 |
|
const Grid &grid = level.getGrid (GridType_Surfaces); |
229 |
|
for (unsigned y=0; y<grid.getHeight(); ++y) { |
230 |
|
for (unsigned x=0; x<grid.getWidth(); ++x) { |
231 |
|
const char *name = floor_map[grid.get(x,y)]; |
232 |
|
Floor *fl = MakeFloor(name ? name : "fl-hay"); |
233 |
|
SetFloor (GridPos(x, y), fl); |
234 |
|
} |
235 |
|
} |
236 |
|
} |
237 |
|
|
238 |
|
void |
239 |
|
LevelPack_Oxyd::load_stones (const Level &level) |
240 |
|
{ |
241 |
|
using namespace world; |
242 |
|
|
243 |
|
const Grid &grid = level.getGrid (GridType_Pieces); |
244 |
|
for (unsigned y=0; y<grid.getHeight(); ++y) { |
245 |
|
for (unsigned x=0; x<grid.getWidth(); ++x) { |
246 |
|
int val = grid.get(x,y); |
247 |
|
if (!val) continue; |
248 |
|
const char *name = stone_map[val]; |
249 |
|
Stone *st = MakeStone(name ? name : "st-brownie"); |
250 |
|
SetStone (GridPos(x, y), st); |
251 |
|
} |
252 |
|
} |
253 |
|
} |
254 |
|
|
255 |
|
void |
256 |
|
LevelPack_Oxyd::load_actors (const Level &level) |
257 |
|
{ |
258 |
|
using namespace world; |
259 |
|
|
260 |
|
int nmarbles = level.getNumMarbles(); |
261 |
|
|
262 |
|
for (int i=0; i<nmarbles; ++i) { |
263 |
|
const Marble &marble = level.getMarble(i); |
264 |
|
double x = marble.getX()/32.0; |
265 |
|
double y = marble.getY()/32.0; |
266 |
|
Actor *ac = 0; |
267 |
|
|
268 |
|
switch (marble.getMarbleType()) { |
269 |
|
case MarbleType_Black: |
270 |
|
ac = MakeActor ("ac-blackball"); |
271 |
|
ac->set_attrib ("player", Value(0.0)); |
272 |
|
AddActor (x, y, ac); |
273 |
|
break; |
274 |
|
case MarbleType_White: |
275 |
|
ac = MakeActor ("ac-whiteball"); |
276 |
|
ac->set_attrib ("player", Value(1.0)); |
277 |
|
AddActor (x, y, ac); |
278 |
|
break; |
279 |
|
case MarbleType_Meditation: |
280 |
|
ac = MakeActor ("ac-whiteball-small"); |
281 |
|
ac->set_attrib ("player", Value(0.0)); |
282 |
|
ac->set_attrib ("mouseforce", Value(1.0)); |
283 |
|
AddActor (x, y, ac); |
284 |
|
break; |
285 |
|
case MarbleType_Horse: |
286 |
|
case MarbleType_Jack: |
287 |
|
case MarbleType_LifeSpitter: |
288 |
|
case MarbleType_DynamiteHolder: |
289 |
|
break; |
290 |
|
default: |
291 |
|
break; |
292 |
|
} |
293 |
|
} |
294 |
|
|
295 |
|
} |
296 |
|
|
297 |
|
bool |
298 |
|
LevelPack_Oxyd::load_level (size_t index) |
299 |
|
{ |
300 |
|
assert (0 <= index && index < size()); |
301 |
|
string msg; |
302 |
|
Level level; |
303 |
|
|
304 |
|
if (m_twoplayers) |
305 |
|
index += 100; |
306 |
|
|
307 |
|
if (!parseLevel (m_datfile->getLevel(index), &level, &msg)) { |
308 |
|
Log << "Could not load " << name() << " level #" << index+1 |
309 |
|
<< ":\n " << msg; |
310 |
|
return false; |
311 |
|
} |
312 |
|
|
313 |
|
world::Create (level.getWidth(), level.getHeight()); |
314 |
|
|
315 |
|
load_floor (level); |
316 |
|
load_stones (level); |
317 |
|
load_actors (level); |
318 |
|
|
319 |
|
world::InitWorld(); |
320 |
|
SetFollowMode (display::FOLLOW_SCREEN); |
321 |
|
|
322 |
|
return true; |
323 |
|
} |
324 |
|
|
325 |
|
LevelInfo * |
326 |
|
LevelPack_Oxyd::get_info (size_t index) |
327 |
|
{ |
328 |
|
static LevelInfo info ("oxyd", "Oxyd", "Dongleware"); |
329 |
|
|
330 |
|
char name[200]; |
331 |
|
sprintf (name, "%s #%d", this->name().c_str(), index); |
332 |
|
info.name = name; |
333 |
|
return &info; |
334 |
|
} |
335 |
|
|
336 |
namespace |
namespace |
337 |
{ |
{ |
338 |
struct GameInfo { |
struct GameInfo { |
345 |
bool is_present; |
bool is_present; |
346 |
string datfile_path; |
string datfile_path; |
347 |
}; |
}; |
|
|
|
|
map <string,string> soundfx_map; |
|
348 |
} |
} |
349 |
|
|
350 |
GameInfo::GameInfo() |
GameInfo::GameInfo() |
351 |
: is_present(false) |
: is_present(false) |
352 |
{} |
{} |
353 |
|
|
354 |
|
|
355 |
GameInfo::GameInfo (const string &game_, const string &datfile_) |
GameInfo::GameInfo (const string &game_, const string &datfile_) |
356 |
: game(game_), datfile(datfile_), is_present(false) |
: game(game_), datfile(datfile_), is_present(false) |
357 |
{ |
{ |
358 |
string fname; |
string fname; |
359 |
if (FindFile (datfile, datfile_path)) { |
if (FindFile (datfile, datfile_path)) { |
370 |
{ |
{ |
371 |
vector<GameInfo> games; |
vector<GameInfo> games; |
372 |
DatFile *datfile = 0; |
DatFile *datfile = 0; |
373 |
|
OxydVersion oxyd_version; |
374 |
|
|
375 |
|
map <string,string> soundfx_map; |
376 |
} |
} |
377 |
|
|
378 |
void enigma::oxyd::Init() |
void |
379 |
|
enigma::oxyd::Init() |
380 |
{ |
{ |
381 |
games.clear(); |
games.clear(); |
382 |
games.resize(OxydVersion_Count); |
games.resize(OxydVersion_Count); |
384 |
games[OxydVersion_Oxyd1] = GameInfo("Oxyd 1", "oxyd1ibm.dat"); |
games[OxydVersion_Oxyd1] = GameInfo("Oxyd 1", "oxyd1ibm.dat"); |
385 |
games[OxydVersion_OxydMagnum] = GameInfo("Oxyd magnum", "oxydmibm.dat"); |
games[OxydVersion_OxydMagnum] = GameInfo("Oxyd magnum", "oxydmibm.dat"); |
386 |
games[OxydVersion_OxydExtra] = GameInfo("Oxyd extra", "oxydex.dat"); |
games[OxydVersion_OxydExtra] = GameInfo("Oxyd extra", "oxydex.dat"); |
387 |
|
|
388 |
|
oxyd_version = OxydVersion_Invalid; |
389 |
} |
} |
390 |
|
|
391 |
bool |
bool |
409 |
if (!parseDatFile (data, ver, datfile, &errmsg)) { |
if (!parseDatFile (data, ver, datfile, &errmsg)) { |
410 |
enigma::Log << "Error loading " << fname << ": " << errmsg << endl; |
enigma::Log << "Error loading " << fname << ": " << errmsg << endl; |
411 |
delete datfile; |
delete datfile; |
412 |
|
datfile = 0; |
413 |
} else { |
} else { |
414 |
enigma::Log << "Loaded "<< fname << endl; |
enigma::Log << "Loaded "<< fname << endl; |
415 |
} |
} |
416 |
} |
} |
417 |
|
if (datfile) |
418 |
|
oxyd_version = ver; |
419 |
return false; |
return false; |
420 |
} |
} |
421 |
|
|
422 |
|
LevelPack * |
423 |
|
enigma::oxyd::MakeLevelPack (bool twoplayers) |
424 |
|
{ |
425 |
|
if (datfile == 0 || oxyd_version == OxydVersion_Invalid) |
426 |
|
return 0; |
427 |
|
|
428 |
|
if (twoplayers && oxyd_version == OxydVersion_OxydExtra) |
429 |
|
return 0; |
430 |
|
else |
431 |
|
return new LevelPack_Oxyd (oxyd_version, datfile, twoplayers); |
432 |
|
} |
433 |
|
|
434 |
|
|
435 |
void |
void |
436 |
enigma::oxyd::UseOxydSounds (bool ok) |
enigma::oxyd::UseOxydSounds (bool ok) |
437 |
{ |
{ |