mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 14:50:17 +00:00
GLK: MAGNETIC: Added subengine files
This commit is contained in:
parent
aff46219ef
commit
1c67621047
471
engines/glk/magnetic/defs.h
Normal file
471
engines/glk/magnetic/defs.h
Normal file
@ -0,0 +1,471 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAGNETIC_DEFS_H
|
||||
#define MAGNETIC_DEFS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "glk/magnetic/magnetic_types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Magnetic {
|
||||
|
||||
/*****************************************************************************\
|
||||
* Type definitions for Magnetic
|
||||
*
|
||||
* Note: When running into trouble please ensure that these types have the
|
||||
* correct number of bits on your system !!!
|
||||
\*****************************************************************************/
|
||||
|
||||
typedef byte type8;
|
||||
typedef int8 type8s;
|
||||
typedef uint16 type16;
|
||||
typedef int16 type16s;
|
||||
typedef uint32 type32;
|
||||
typedef int32 type32s;
|
||||
|
||||
/****************************************************************************\
|
||||
* Compile time switches
|
||||
\****************************************************************************/
|
||||
|
||||
/* Switch: SAVEMEM
|
||||
Purpose: Magnetic loads a complete graphics file into memory by default.
|
||||
Setting this switch you tell Magnetic to load images on request
|
||||
(saving memory, wasting load time)
|
||||
|
||||
#define SAVEMEM
|
||||
*/
|
||||
|
||||
/* Switch: NO_ANIMATION
|
||||
Purpose: By default Magnetic plays animated graphics.
|
||||
Setting this switch to ignore animations, Magnetic shows the
|
||||
static parts of the images anyway!
|
||||
|
||||
#define NO_ANIMATION
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
* Abstract functions
|
||||
*
|
||||
* Note: These functions MUST be implemented by each port of Magnetic!
|
||||
\****************************************************************************/
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_load_file
|
||||
*
|
||||
* Purpose: Load a save game file and restore game
|
||||
*
|
||||
* Parameters: type8s* name zero terminated string of filename
|
||||
* typed by player
|
||||
* type8* ptr pointer to data to save
|
||||
* type16 size number of bytes to save
|
||||
*
|
||||
* Result: 0 is successful
|
||||
*
|
||||
* Note: You probably want to put in a file requester!
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_load_file(const char *name, type8 *ptr, type16 size);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_save_file
|
||||
*
|
||||
* Purpose: Save the current game to file
|
||||
*
|
||||
* Parameters: type8s* name zero terminated string of filename
|
||||
* typed by player
|
||||
* type8* ptr pointer to data to save
|
||||
* type16 size number of bytes to save
|
||||
*
|
||||
* Result: 0 is successful
|
||||
*
|
||||
* Note: You probably want to put in a file requester!
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_save_file(const char *name, type8 *ptr, type16 size);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_statuschar
|
||||
*
|
||||
* Purpose: Output a single character to the status bar
|
||||
*
|
||||
* Parameters: type8 c character to be printed
|
||||
*
|
||||
* Note: All characters are printed as provided except for:
|
||||
* 0x0A resets the x position to zero
|
||||
* 0x09 moves the cursor to the right half of the bar, ie 'width-11'
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_statuschar(type8 c);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_putchar
|
||||
*
|
||||
* Purpose: Output a single character to the game/text windows
|
||||
*
|
||||
* Parameters: type8 c character to be printed
|
||||
*
|
||||
* Note: It is highly recommended to buffer the output, see also ms_flush()
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_putchar(type8 c);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_flush
|
||||
*
|
||||
* Purpose: Flush the output buffer (if applicable)
|
||||
*
|
||||
* Note: see also ms_putchar
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_flush(void);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_getchar
|
||||
*
|
||||
* Purpose: Read user input, buffered
|
||||
*
|
||||
* Parameters: type8 trans if not 0, translate any #undo
|
||||
* input to a return code of 0
|
||||
*
|
||||
* Return: One character
|
||||
*
|
||||
* Note: The first time it is called a string should be read and then given
|
||||
* back one byte at a time (ie. one for each call) until a '\n' is
|
||||
* reached (which will be the last byte sent back before it all restarts)
|
||||
* Returning a zero means 'undo' and the rest of the line must then be
|
||||
* ignored.
|
||||
* Returning 1 means that the opcode should return immediately. This is
|
||||
* needed to prevent possible corruption of the game's memory in
|
||||
* interpreters which allow a new game to be loaded without restarting.
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_getchar(type8 trans);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_showpic
|
||||
*
|
||||
* Purpose: Displays or hides a picture
|
||||
*
|
||||
* Parameter: type32 c number of image to be displayed
|
||||
* type8 mode mode == 0 means gfx off,
|
||||
* mode == 1 gfx on thumbnails,
|
||||
* mode == 2 gfx on normal.
|
||||
*
|
||||
* Note: For retrieving the raw data of a picture call ms_extract (see below)
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_showpic(type32 c, type8 mode);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_fatal
|
||||
*
|
||||
* Purpose: Handle fatal interpreter error
|
||||
*
|
||||
* Parameter: type8s* txt message
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_fatal(const char *txt);
|
||||
|
||||
/****************************************************************************\
|
||||
* Magnetic core functions
|
||||
*
|
||||
* Note: These functions SHOULD be used somewhere in your port!
|
||||
\****************************************************************************/
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_extract
|
||||
*
|
||||
* Purpose: Extract a picture and return a pointer to a raw bitmap
|
||||
*
|
||||
* Parameters: type32 c number of the picture
|
||||
* type16* w width of picture
|
||||
* type16* h height pf picture
|
||||
* type16* pal array for the palette (16 colours)
|
||||
* type8* is_anim 1 if animated picture, otherwise 0
|
||||
* OR null (!)
|
||||
*
|
||||
* Return: Pointer to bitmap data if successful, otherwise null (also if gfx
|
||||
* are disabled!)
|
||||
*
|
||||
* Note: All pictures have 16 colours and the palette entries use 3-bit RGB
|
||||
* encoded as 00000RRR0GGG0BBB, that is, bits 0-2 give the blue
|
||||
* component, bits 4-6 the green and bits 8-10 the red. The bitmap is
|
||||
* one byte per pixel, with each byte giving the pixel's index into the
|
||||
* palette. The data is given starting from the upper left corner. The
|
||||
* image buffer is reused when the next picture is requested, so take
|
||||
* care! More information on animated pictures are below!
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 *ms_extract(type32 c, type16 *w, type16 *h, type16 *pal, type8 *is_anim);
|
||||
|
||||
/****************************************************************************\
|
||||
* Magnetic animated pictures support
|
||||
*
|
||||
* Note: Some of the pictures for Wonderland and the Collection Volume 1 games
|
||||
* are animations. To detect these, pass a pointer to a type8 as the is_anim
|
||||
* argument to ms_extract().
|
||||
*
|
||||
* There are two types of animated images, however almost all images are type1.
|
||||
* A type1 image consists of four main elements:
|
||||
* 1) A static picture which is loaded straight at the beginning
|
||||
* 2) A set of frames with a mask. These frames are just "small pictures", which
|
||||
* are coded like the normal static pictures. The image mask determines
|
||||
* how the frame is removed after it has been displayed. A mask is exactly
|
||||
* 1/8 the size of the image and holds 1 bit per pixel, saying "remove pixel"
|
||||
* or leave pixel set when frame gets removed. It might be a good idea to check
|
||||
* your system documentation for masking operations as your system might be
|
||||
* able to use this mask data directly.
|
||||
* 3) Positioning tables. These hold animation sequences consisting of commands
|
||||
* like "Draw frame 12 at (123,456)"
|
||||
* 4) A playback script, which determines how to use the positioning tables.
|
||||
* These scripts are handled inside Magnetic, so no need to worry about.
|
||||
* However, details can be found in the ms_animate() function.
|
||||
*
|
||||
* A type2 image is like a type1 image, but it does not have a static
|
||||
* picture, nor does it have frame masking. It just consists of frames.
|
||||
*
|
||||
* How to support animations?
|
||||
* After getting is_anim == 1 you should call ms_animate() immediately, and at
|
||||
* regular intervals until ms_animate() returns 0. An appropriate interval
|
||||
* between calls is about 100 milliseconds.
|
||||
* Each call to ms_animate() will fill in the arguments with the address
|
||||
* and size of an array of ms_position structures (see below), each of
|
||||
* which holds an an animation frame number and x and y co-ordinates. To
|
||||
* display the animation, decode all the animation frames (discussed below)
|
||||
* from a single call to ms_animate() and display each one over the main picture.
|
||||
* If your port does not support animations, define NO_ANIMATION.
|
||||
\****************************************************************************/
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_animate
|
||||
*
|
||||
* Purpose: Generate the next frame of an animation
|
||||
*
|
||||
* Parameters: ms_position** positions array of ms_position structs
|
||||
* type16* count size of array
|
||||
*
|
||||
* Return: 1 if animation continues, 0 if animation is finfished
|
||||
*
|
||||
* Note: The positions array holds size ms_positions structures. BEFORE calling
|
||||
* ms_animate again, retrieve the frames for all the ms_positions
|
||||
* structures with ms_get_anim_frame and display each one on the static
|
||||
* main picture.
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_animate(struct ms_position **positions, type16 *count);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_get_anim_frame
|
||||
*
|
||||
* Purpose: Extracts the bitmap data of a single animation frame
|
||||
*
|
||||
* Parameters: type16s number number of frame (see ms_position struct)
|
||||
* type16* width width of frame
|
||||
* type16* height height of frame
|
||||
* type8** mask pointer to masking data, might be NULL
|
||||
*
|
||||
* Return: 1 if animation continues, 0 if animation is finfished
|
||||
*
|
||||
* Note: The format of the frame is identical to the main pictures' returned by
|
||||
* ms_extract. The mask has one-bit-per-pixel, determing how to handle the
|
||||
* removal of the frame.
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 *ms_get_anim_frame(type16s number, type16 *width, type16 *height, type8 **mask);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_anim_is_repeating
|
||||
*
|
||||
* Purpose: Detects whether an animation is repeating
|
||||
*
|
||||
* Return: True if repeating
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_anim_is_repeating(void);
|
||||
|
||||
/****************************************************************************\
|
||||
* Magnetic Windows hint support
|
||||
*
|
||||
* The windowed Magnetic Scolls games included online hints. To add support
|
||||
* for the hints to your magnetic port, you should implement the ms_showhints
|
||||
* function. It retrieves a pointer to an array of ms_hint structs
|
||||
* The root element is always hints[0]. The elcount determines the number
|
||||
* of items in this topic. You probably want to display those in some kind
|
||||
* of list interface. The content pointer points to the actual description of
|
||||
* the items, separated by '\0' terminators. The nodetype is 1 if the items are
|
||||
* "folders" and 2 if the items are hints. Hints should be displayed one after
|
||||
* another. For "folder" items, the links array holds the index of the hint in
|
||||
* the array which is to be displayed on selection. One hint block has exactly
|
||||
* one type. The parent element determines the "back" target.
|
||||
\****************************************************************************/
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_showhints
|
||||
* Purpose: Show the player a hint
|
||||
*
|
||||
* Parameters: ms_hint* hints pointer to array of ms_hint structs
|
||||
*
|
||||
* Return: 0 on error, 1 on success
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_showhints(struct ms_hint *hints);
|
||||
|
||||
/****************************************************************************\
|
||||
* Magnetic Windows sound support
|
||||
*
|
||||
* Wonderland contains music scores that are played when entering specific
|
||||
* locations in the game. The music data are actually MIDI events and can be
|
||||
* played through normal MIDI devices. The original game plays the MIDI score
|
||||
* until the end, even if the location is changed while playing. The playback
|
||||
* tempo is not included with the MIDI data. The ms_sndextract function
|
||||
* returns a recommended tempo, however depending on the MIDI implementation
|
||||
* and operating system, you might need to adapt it.
|
||||
\****************************************************************************/
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_playmusic
|
||||
*
|
||||
* Purpose: Plays (or stops playing) a MIDI music score.
|
||||
*
|
||||
* Parameter: type8 * midi_data the MIDI data to play
|
||||
* type32 length the length of the MIDI data
|
||||
* type16 tempo the suggested tempo for playing
|
||||
*
|
||||
* Note: If midi_data is NULL, all that should happen is that any currently
|
||||
* playing music is stopped.
|
||||
* Note: The data returned contain a complete MIDI file header, so if pure
|
||||
* memory processing is not applicable you can write the data to a
|
||||
* temporary file and use external players or libraries.
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_playmusic(type8 *midi_data, type32 length, type16 tempo);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_init
|
||||
*
|
||||
* Purpose: Loads the interpreter with a game
|
||||
*
|
||||
* Parameters: type8s* name filename of story file
|
||||
* type8s* gfxname filename of graphics file (optional)
|
||||
* type8s* hntname filename of hints file (optional)
|
||||
* type8s* sndname filename of music file (optional)
|
||||
*
|
||||
* Return: 0 = failure
|
||||
* 1 = success (without graphics or graphics failed)
|
||||
* 2 = success (with graphics)
|
||||
*
|
||||
* Note: You must call this function before starting the ms_rungame loop
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_init(const char *name, const char *gfxname, const char *hntname, const char *sndname);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_rungame
|
||||
*
|
||||
* Purpose: Executes an interpreter instruction
|
||||
*
|
||||
* Return: True if successful
|
||||
*
|
||||
* Note: You must call this function in a loop like this:
|
||||
* while (running) {running=ms_rungame();}
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_rungame(void);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_freemen
|
||||
*
|
||||
* Purpose: Frees all allocated ressources
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_freemem(void);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_seed
|
||||
*
|
||||
* Purpose: Initializes the interpreter's random number generator with
|
||||
* the given seed
|
||||
*
|
||||
* Parameter: type32 seed seed
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_seed(type32 seed);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_is_running
|
||||
*
|
||||
* Purpose: Detects if game is running
|
||||
*
|
||||
* Return: True, if game is currently running
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_is_running(void);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_is_magwin
|
||||
*
|
||||
* Purpose: Detects Magnetic Windows games (Wonderland, Collection)
|
||||
*
|
||||
* Return: True, if Magnetic Windows game
|
||||
\****************************************************************************/
|
||||
|
||||
extern type8 ms_is_magwin(void);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_stop
|
||||
*
|
||||
* Purpose: Stops further processing of opcodes
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_stop(void);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_status
|
||||
*
|
||||
* Purpose: Dumps interperetr state to stderr, ie. registers
|
||||
\****************************************************************************/
|
||||
|
||||
extern void ms_status(void);
|
||||
|
||||
/****************************************************************************\
|
||||
* Function: ms_count
|
||||
*
|
||||
* Purpose: Returns the number of executed intructions
|
||||
*
|
||||
* Return: Instruction count
|
||||
\****************************************************************************/
|
||||
|
||||
extern type32 ms_count(void);
|
||||
|
||||
extern void write(const char *fmt, ...);
|
||||
|
||||
extern void writeChar(char c);
|
||||
|
||||
extern int gms_startup_code(int argc, char *argv[]);
|
||||
|
||||
extern void gms_main();
|
||||
|
||||
} // End of namespace Magnetic
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
5393
engines/glk/magnetic/glk.cpp
Normal file
5393
engines/glk/magnetic/glk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,507 +0,0 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/magnetic/magnetic.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Magnetic {
|
||||
|
||||
byte Magnetic::init_gfx1(size_t size) {
|
||||
if (!(gfx_buf = new byte[MAX_PICTURE_SIZE]))
|
||||
return 1;
|
||||
|
||||
if (!(gfx_data = new byte[size])) {
|
||||
delete[] gfx_buf;
|
||||
gfx_buf = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_gfxFile.read(gfx_data, size) != size) {
|
||||
delete[] gfx_data;
|
||||
delete[] gfx_buf;
|
||||
gfx_data = gfx_buf = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
gfx_ver = 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
byte Magnetic::init_gfx2(size_t size) {
|
||||
if (!(gfx_buf = new byte[MAX_PICTURE_SIZE])) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
gfx2_hsize = size;
|
||||
if (!(gfx2_hdr = new byte[gfx2_hsize])) {
|
||||
delete[] gfx_buf;
|
||||
gfx_buf = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_gfxFile.read(gfx2_hdr, gfx2_hsize) != gfx2_hsize) {
|
||||
delete[] gfx_buf;
|
||||
delete[] gfx2_hdr;
|
||||
gfx_buf = nullptr;
|
||||
gfx2_hdr = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
gfx_ver = 2;
|
||||
return 2;
|
||||
}
|
||||
|
||||
void Magnetic::ms_showpic(int c, byte mode) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
bool Magnetic::is_blank(uint16 line, uint16 width) const {
|
||||
int i;
|
||||
|
||||
for (i = line * width; i < (line + 1) * width; i++)
|
||||
if (gfx_buf[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
byte *Magnetic::ms_extract1(byte pic, uint16 * w, uint16 * h, uint16 * pal) {
|
||||
byte *table, *data, bit, val, *buffer;
|
||||
uint16 tablesize, count;
|
||||
uint32 i, j, upsize, offset;
|
||||
//uint32 datasize;
|
||||
|
||||
offset = READ_LE_UINT32(gfx_data + 4 * pic);
|
||||
buffer = gfx_data + offset - 8;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
pal[i] = READ_LE_UINT16(buffer + 0x1c + 2 * i);
|
||||
w[0] = (uint16)(READ_LE_UINT16(buffer + 4) - READ_LE_UINT16(buffer + 2));
|
||||
h[0] = READ_LE_UINT16(buffer + 6);
|
||||
|
||||
tablesize = READ_LE_UINT16(buffer + 0x3c);
|
||||
//datasize = READ_LE_UINT32(buffer + 0x3e);
|
||||
table = buffer + 0x42;
|
||||
data = table + tablesize * 2 + 2;
|
||||
upsize = h[0] * w[0];
|
||||
|
||||
for (i = 0, j = 0, count = 0, val = 0, bit = 7; i < upsize; i++, count--) {
|
||||
if (!count) {
|
||||
count = tablesize;
|
||||
while (count < 0x80) {
|
||||
if (data[j] & (1 << bit))
|
||||
count = table[2 * count];
|
||||
else
|
||||
count = table[2 * count + 1];
|
||||
if (!bit)
|
||||
j++;
|
||||
bit = (byte)(bit ? bit - 1 : 7);
|
||||
}
|
||||
count &= 0x7f;
|
||||
if (count >= 0x10)
|
||||
count -= 0x10;
|
||||
else
|
||||
{
|
||||
val = (byte)count;
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
gfx_buf[i] = val;
|
||||
}
|
||||
for (j = w[0]; j < upsize; j++)
|
||||
gfx_buf[j] ^= gfx_buf[j - w[0]];
|
||||
|
||||
for (; h[0] > 0 && is_blank((uint16)(h[0] - 1), w[0]); h[0]--);
|
||||
for (i = 0; h[0] > 0 && is_blank((uint16)i, w[0]); h[0]--, i++);
|
||||
return gfx_buf + i * w[0];
|
||||
}
|
||||
|
||||
|
||||
byte *Magnetic::ms_extract2(const char *name, uint16 *w, uint16 *h, uint16 *pal, byte *is_anim) {
|
||||
struct picture main_pic;
|
||||
uint32 offset = 0, length = 0, i;
|
||||
int16 header_pos = -1;
|
||||
byte* anim_data;
|
||||
uint32 j;
|
||||
|
||||
if (is_anim != 0)
|
||||
*is_anim = 0;
|
||||
gfx2_name = name;
|
||||
|
||||
pos_table_size = 0;
|
||||
|
||||
// Find the uppercase (no animation) version of the picture first
|
||||
header_pos = find_name_in_header(name, 1);
|
||||
|
||||
if (header_pos < 0)
|
||||
header_pos = find_name_in_header(name, 0);
|
||||
if (header_pos < 0)
|
||||
return 0;
|
||||
|
||||
offset = READ_LE_UINT32(gfx2_hdr + header_pos + 8);
|
||||
length = READ_LE_UINT32(gfx2_hdr + header_pos + 12);
|
||||
|
||||
if (offset != 0) {
|
||||
if (gfx2_buf) {
|
||||
delete[] gfx2_buf;
|
||||
gfx2_buf = nullptr;
|
||||
}
|
||||
|
||||
gfx2_buf = new byte[length];
|
||||
if (!gfx2_buf)
|
||||
return 0;
|
||||
|
||||
if (!_gfxFile.seek(offset) || _gfxFile.read(gfx2_buf, length) != length) {
|
||||
delete[] gfx2_buf;
|
||||
gfx2_buf = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
pal[i] = READ_LE_UINT16(gfx2_buf + 4 + (2 * i));
|
||||
|
||||
main_pic.data = gfx2_buf + 48;
|
||||
main_pic.data_size = READ_LE_UINT32(gfx2_buf + 38);
|
||||
main_pic.width = READ_LE_UINT16(gfx2_buf + 42);
|
||||
main_pic.height = READ_LE_UINT16(gfx2_buf + 44);
|
||||
main_pic.wbytes = (uint16)(main_pic.data_size / main_pic.height);
|
||||
main_pic.plane_step = (uint16)(main_pic.wbytes / 4);
|
||||
main_pic.mask = (byte*)0;
|
||||
extract_frame(&main_pic);
|
||||
|
||||
*w = main_pic.width;
|
||||
*h = main_pic.height;
|
||||
|
||||
// Check for an animation
|
||||
anim_data = gfx2_buf + 48 + main_pic.data_size;
|
||||
if ((anim_data[0] != 0xD0) || (anim_data[1] != 0x5E)) {
|
||||
byte *current;
|
||||
uint16 frame_count;
|
||||
uint16 value1, value2;
|
||||
//uint16 command_count;
|
||||
|
||||
if (is_anim != 0)
|
||||
*is_anim = 1;
|
||||
|
||||
current = anim_data + 6;
|
||||
frame_count = READ_LE_UINT16(anim_data + 2);
|
||||
if (frame_count > MAX_ANIMS)
|
||||
{
|
||||
error("animation frame array too short");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Loop through each animation frame */
|
||||
for (i = 0; i < frame_count; i++)
|
||||
{
|
||||
anim_frame_table[i].data = current + 10;
|
||||
anim_frame_table[i].data_size = READ_LE_UINT32(current);
|
||||
anim_frame_table[i].width = READ_LE_UINT16(current + 4);
|
||||
anim_frame_table[i].height = READ_LE_UINT16(current + 6);
|
||||
anim_frame_table[i].wbytes = (uint16)(anim_frame_table[i].data_size / anim_frame_table[i].height);
|
||||
anim_frame_table[i].plane_step = (uint16)(anim_frame_table[i].wbytes / 4);
|
||||
anim_frame_table[i].mask = (byte*)0;
|
||||
|
||||
current += anim_frame_table[i].data_size + 12;
|
||||
value1 = READ_LE_UINT16(current - 2);
|
||||
value2 = READ_LE_UINT16(current);
|
||||
|
||||
/* Get the mask */
|
||||
if ((value1 == anim_frame_table[i].width) && (value2 == anim_frame_table[i].height))
|
||||
{
|
||||
uint16 skip;
|
||||
|
||||
anim_frame_table[i].mask = (byte*)(current + 4);
|
||||
skip = READ_LE_UINT16(current + 2);
|
||||
current += skip + 6;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the positioning tables */
|
||||
pos_table_size = READ_LE_UINT16(current - 2);
|
||||
if (pos_table_size > MAX_POSITIONS)
|
||||
{
|
||||
error("animation position array too short");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < pos_table_size; i++) {
|
||||
pos_table_count[i] = READ_LE_UINT16(current + 2);
|
||||
current += 4;
|
||||
|
||||
if (pos_table_count[i] > MAX_ANIMS)
|
||||
{
|
||||
error("animation position array too short");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < pos_table_count[i]; j++)
|
||||
{
|
||||
pos_table[i][j].x = READ_LE_UINT16(current);
|
||||
pos_table[i][j].y = READ_LE_UINT16(current + 2);
|
||||
pos_table[i][j].number = READ_LE_UINT16(current + 4) - 1;
|
||||
current += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the command sequence table
|
||||
//command_count = READ_LE_UINT16(current);
|
||||
command_table = current + 2;
|
||||
|
||||
for (i = 0; i < MAX_POSITIONS; i++)
|
||||
{
|
||||
anim_table[i].flag = -1;
|
||||
anim_table[i].count = -1;
|
||||
}
|
||||
command_index = 0;
|
||||
anim_repeat = 0;
|
||||
pos_table_index = -1;
|
||||
pos_table_max = -1;
|
||||
}
|
||||
|
||||
return gfx_buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int16 Magnetic::find_name_in_header(const Common::String &name, bool upper) {
|
||||
int16 header_pos = 0;
|
||||
Common::String pic_name(name.c_str(), name.c_str() + 6);
|
||||
|
||||
if (upper)
|
||||
pic_name.toUppercase();
|
||||
|
||||
while (header_pos < gfx2_hsize) {
|
||||
const char *hname = (const char *)(gfx2_hdr + header_pos);
|
||||
if (strncmp(hname, pic_name.c_str(), 6) == 0)
|
||||
return header_pos;
|
||||
header_pos += 16;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Magnetic::extract_frame(const picture *pic) {
|
||||
uint32 i, x, y, bit_x, mask, ywb, yw, value, values[4];
|
||||
values[0] = values[1] = values[2] = values[3] = 0;
|
||||
|
||||
if (pic->width * pic->height > MAX_PICTURE_SIZE) {
|
||||
error("picture too large");
|
||||
return;
|
||||
}
|
||||
|
||||
for (y = 0; y < pic->height; y++) {
|
||||
ywb = y * pic->wbytes;
|
||||
yw = y * pic->width;
|
||||
|
||||
for (x = 0; x < pic->width; x++) {
|
||||
if ((x % 8) == 0) {
|
||||
for (i = 0; i < 4; i++)
|
||||
values[i] = pic->data[ywb + (x / 8) + (pic->plane_step * i)];
|
||||
}
|
||||
|
||||
bit_x = 7 - (x & 7);
|
||||
mask = 1 << bit_x;
|
||||
value = ((values[0] & mask) >> bit_x) << 0 |
|
||||
((values[1] & mask) >> bit_x) << 1 |
|
||||
((values[2] & mask) >> bit_x) << 2 |
|
||||
((values[3] & mask) >> bit_x) << 3;
|
||||
value &= 15;
|
||||
|
||||
gfx_buf[yw + x] = (byte)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte *Magnetic::ms_extract(uint32 pic, uint16 *w, uint16 *h, uint16 *pal, byte *is_anim) {
|
||||
if (is_anim)
|
||||
*is_anim = 0;
|
||||
|
||||
if (gfx_buf) {
|
||||
switch (gfx_ver) {
|
||||
case 1:
|
||||
return ms_extract1((byte)pic, w, h, pal);
|
||||
case 2:
|
||||
return ms_extract2((const char *)(code + pic), w, h, pal, is_anim);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
byte Magnetic::ms_animate(ms_position **positions, uint16 *count) {
|
||||
byte got_anim = 0;
|
||||
uint16 i, j, ttable;
|
||||
|
||||
if ((gfx_buf == 0) || (gfx2_buf == 0) || (gfx_ver != 2))
|
||||
return 0;
|
||||
if ((pos_table_size == 0) || (command_index < 0))
|
||||
return 0;
|
||||
|
||||
*count = 0;
|
||||
*positions = (struct ms_position*)0;
|
||||
|
||||
while (got_anim == 0)
|
||||
{
|
||||
if (pos_table_max >= 0)
|
||||
{
|
||||
if (pos_table_index < pos_table_max)
|
||||
{
|
||||
for (i = 0; i < pos_table_size; i++)
|
||||
{
|
||||
if (anim_table[i].flag > -1)
|
||||
{
|
||||
if (*count >= MAX_FRAMES)
|
||||
{
|
||||
error("returned animation array too short");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos_array[*count] = pos_table[i][anim_table[i].flag];
|
||||
|
||||
(*count)++;
|
||||
|
||||
if (anim_table[i].flag < (pos_table_count[i] - 1))
|
||||
anim_table[i].flag++;
|
||||
if (anim_table[i].count > 0)
|
||||
anim_table[i].count--;
|
||||
else
|
||||
anim_table[i].flag = -1;
|
||||
}
|
||||
}
|
||||
if (*count > 0)
|
||||
{
|
||||
*positions = pos_array;
|
||||
got_anim = 1;
|
||||
}
|
||||
pos_table_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (got_anim == 0)
|
||||
{
|
||||
byte command = command_table[command_index];
|
||||
command_index++;
|
||||
|
||||
pos_table_max = -1;
|
||||
pos_table_index = -1;
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case 0x00:
|
||||
command_index = -1;
|
||||
return 0;
|
||||
case 0x01:
|
||||
ttable = command_table[command_index];
|
||||
command_index++;
|
||||
|
||||
if (ttable - 1 >= MAX_POSITIONS)
|
||||
{
|
||||
error("animation table too short");
|
||||
return 0;
|
||||
}
|
||||
|
||||
anim_table[ttable - 1].flag = (int16)(command_table[command_index] - 1);
|
||||
command_index++;
|
||||
anim_table[ttable - 1].count = (int16)(command_table[command_index] - 1);
|
||||
command_index++;
|
||||
|
||||
/* Workaround for Wonderland "catter" animation */
|
||||
if (v4_id == 0)
|
||||
{
|
||||
if (gfx2_name == "catter") {
|
||||
if (command_index == 96)
|
||||
anim_table[ttable - 1].count = 9;
|
||||
if (command_index == 108)
|
||||
anim_table[ttable - 1].flag = -1;
|
||||
if (command_index == 156)
|
||||
anim_table[ttable - 1].flag = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
pos_table_max = command_table[command_index];
|
||||
pos_table_index = 0;
|
||||
command_index++;
|
||||
break;
|
||||
case 0x03:
|
||||
if (v4_id == 0)
|
||||
{
|
||||
command_index = -1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
command_index = 0;
|
||||
anim_repeat = 1;
|
||||
pos_table_index = -1;
|
||||
pos_table_max = -1;
|
||||
for (j = 0; j < MAX_POSITIONS; j++)
|
||||
{
|
||||
anim_table[j].flag = -1;
|
||||
anim_table[j].count = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
command_index += 3;
|
||||
return 0;
|
||||
case 0x05:
|
||||
ttable = next_table;
|
||||
command_index++;
|
||||
|
||||
anim_table[ttable - 1].flag = 0;
|
||||
anim_table[ttable - 1].count = command_table[command_index];
|
||||
|
||||
pos_table_max = command_table[command_index];
|
||||
pos_table_index = 0;
|
||||
command_index++;
|
||||
command_index++;
|
||||
next_table++;
|
||||
break;
|
||||
default:
|
||||
error("unknown animation command");
|
||||
command_index = -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return got_anim;
|
||||
}
|
||||
|
||||
byte *Magnetic::ms_get_anim_frame(int16 number, uint16 *width, uint16 *height, byte **mask) {
|
||||
if (number >= 0)
|
||||
{
|
||||
extract_frame(anim_frame_table + number);
|
||||
*width = anim_frame_table[number].width;
|
||||
*height = anim_frame_table[number].height;
|
||||
*mask = anim_frame_table[number].mask;
|
||||
return gfx_buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Magnetic
|
||||
} // End of namespace Glk
|
@ -21,41 +21,20 @@
|
||||
*/
|
||||
|
||||
#include "glk/magnetic/magnetic.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/translation.h"
|
||||
#include "glk/magnetic/defs.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Magnetic {
|
||||
|
||||
Magnetic::Magnetic(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
|
||||
|
||||
vm_exited_cleanly(false), dlimit(0xffffffff), slimit(0xffffffff), log_on(0),
|
||||
i_count(0), string_size(0), rseed(0), pc(0), arg1i(0), mem_size(0), properties(0), fl_sub(0),
|
||||
fl_tab(0), fl_size(0), fp_tab(0), fp_size(0), zflag(0), nflag(0), cflag(0), vflag(0), byte1(0),
|
||||
byte2(0), regnr(0), admode(0), opsize(0), arg1(nullptr), arg2(nullptr), is_reversible(0),
|
||||
lastchar(0), version(0), sd(0), decode_table(nullptr), restart(nullptr), code(nullptr),
|
||||
string(nullptr), string2(nullptr), string3(nullptr), dict(nullptr), quick_flag(0), gfx_ver(0),
|
||||
gfx_buf(nullptr), gfx_data(nullptr), gfx2_hdr(0), gfx2_buf(nullptr), gfx2_hsize(0),
|
||||
snd_buf(nullptr), snd_hdr(nullptr), snd_hsize(0), undo_pc(0), undo_size(0),
|
||||
gfxtable(0), table_dist(0), v4_id(0), next_table(1), pos_table_size(0),
|
||||
command_table(nullptr), command_index(-1), pos_table_index(-1), pos_table_max(-1),
|
||||
anim_repeat(0) {
|
||||
Magnetic *g_vm;
|
||||
|
||||
// Emu fields
|
||||
undo[0] = undo[1] = nullptr;
|
||||
undo_stat[0] = undo_stat[1] = 0;
|
||||
Common::fill(&dreg[0], &dreg[8], 0);
|
||||
Common::fill(&areg[0], &areg[8], 0);
|
||||
Common::fill(&tmparg[0], &tmparg[4], 0);
|
||||
Common::fill(&undo_regs[0][0], &undo_regs[2][18], 0),
|
||||
Common::fill(&pos_table_count[0], &pos_table_count[MAX_POSITIONS], 0);
|
||||
Magnetic::Magnetic(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc) {
|
||||
g_vm = this;
|
||||
}
|
||||
|
||||
void Magnetic::runGame() {
|
||||
if (!is_gamefile_valid())
|
||||
return;
|
||||
|
||||
// TODO
|
||||
gms_startup_code(0, nullptr);
|
||||
gms_main();
|
||||
}
|
||||
|
||||
Common::Error Magnetic::readSaveData(Common::SeekableReadStream *rs) {
|
||||
@ -68,30 +47,5 @@ Common::Error Magnetic::writeGameData(Common::WriteStream *ws) {
|
||||
return Common::kWritingFailed;
|
||||
}
|
||||
|
||||
bool Magnetic::is_gamefile_valid() {
|
||||
if (_gameFile.size() < 8) {
|
||||
GUIErrorMessage(_("This is too short to be a valid Glulx file."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_gameFile.readUint32BE() != MKTAG('G', 'l', 'u', 'l')) {
|
||||
GUIErrorMessage(_("This is not a valid Glulx file."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// We support version 2.0 through 3.1.*
|
||||
uint32 vers = _gameFile.readUint32BE();
|
||||
if (vers < 0x20000) {
|
||||
GUIErrorMessage(_("This Glulx file is too old a version to execute."));
|
||||
return false;
|
||||
}
|
||||
if (vers >= 0x30200) {
|
||||
GUIErrorMessage(_("This Glulx file is too new a version to execute."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Magnetic
|
||||
} // End of namespace Glk
|
||||
|
@ -20,6 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* Based on Magnetic interpreter version 2.3 */
|
||||
|
||||
#ifndef GLK_MAGNETIC_MAGNETIC
|
||||
#define GLK_MAGNETIC_MAGNETIC
|
||||
|
||||
@ -34,146 +36,6 @@ namespace Magnetic {
|
||||
* Magnetic game interpreter
|
||||
*/
|
||||
class Magnetic : public GlkAPI {
|
||||
public:
|
||||
Common::File _hintFile;
|
||||
Common::File _gfxFile;
|
||||
Common::File _sndFile;
|
||||
bool vm_exited_cleanly;
|
||||
uint dlimit, slimit;
|
||||
int log_on;
|
||||
|
||||
// Emu fields
|
||||
uint32 dreg[8], areg[8], i_count, string_size, rseed, pc, arg1i, mem_size;
|
||||
uint16 properties, fl_sub, fl_tab, fl_size, fp_tab, fp_size;
|
||||
byte zflag, nflag, cflag, vflag, byte1, byte2, regnr, admode, opsize;
|
||||
byte *arg1, *arg2, is_reversible, running, tmparg[4];
|
||||
byte lastchar, version, sd;
|
||||
byte *decode_table, *restart, *code, *string, *string2;
|
||||
byte *string3, *dict;
|
||||
byte quick_flag, gfx_ver, *gfx_buf, *gfx_data;
|
||||
byte *gfx2_hdr, *gfx2_buf;
|
||||
Common::String gfx2_name;
|
||||
uint16 gfx2_hsize;
|
||||
byte *snd_buf, *snd_hdr;
|
||||
uint16 snd_hsize;
|
||||
Common::File gfx_fp;
|
||||
uint32 undo_regs[2][18], undo_pc, undo_size;
|
||||
byte *undo[2], undo_stat[2];
|
||||
uint16 gfxtable, table_dist;
|
||||
uint16 v4_id, next_table;
|
||||
|
||||
ms_hint *hints;
|
||||
byte *hint_contents;
|
||||
picture anim_frame_table[MAX_ANIMS];
|
||||
uint16 pos_table_size;
|
||||
uint16 pos_table_count[MAX_POSITIONS];
|
||||
ms_position pos_table[MAX_POSITIONS][MAX_ANIMS];
|
||||
byte *command_table;
|
||||
int command_index;
|
||||
lookup anim_table[MAX_POSITIONS];
|
||||
int pos_table_index;
|
||||
int pos_table_max;
|
||||
ms_position pos_array[MAX_FRAMES];
|
||||
byte anim_repeat;
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* Validates the game file, and if it's invalid, displays an error dialog
|
||||
*/
|
||||
bool is_gamefile_valid();
|
||||
|
||||
/**
|
||||
* \defgroup Emu
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Loads the interpreter with a game
|
||||
* @return 0 = failure, 1 = success(without graphics or graphics failed),
|
||||
* 2 = success(with graphics)
|
||||
*/
|
||||
int ms_init(bool restarting = false);
|
||||
|
||||
/**
|
||||
* Stops further processing of opcodes
|
||||
*/
|
||||
void ms_stop() { running = false; }
|
||||
|
||||
/**
|
||||
* Detects if game is running
|
||||
*/
|
||||
bool ms_is_running() const { return running; }
|
||||
|
||||
/**
|
||||
* Returns true if running a Magnetic Windows game
|
||||
*/
|
||||
bool ms_is_magwin() const { return version == 4; }
|
||||
|
||||
/**
|
||||
* Frees all allocated ressources
|
||||
*/
|
||||
void ms_freemem();
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* \defgroup Graphics support methods
|
||||
* @{
|
||||
*/
|
||||
|
||||
byte init_gfx1(size_t size);
|
||||
|
||||
byte init_gfx2(size_t size);
|
||||
|
||||
/**
|
||||
* Displays or hides a picture
|
||||
* @param c number of image to be displayed
|
||||
* @param mode 0 = means gfx off, 1 gfx on thumbnails, 2 gfx on normal
|
||||
*
|
||||
* @remarks For retrieving the raw data of a picture call ms_extract
|
||||
*/
|
||||
void ms_showpic(int c, byte mode);
|
||||
|
||||
/**
|
||||
* Returns true if a given line is blank
|
||||
*/
|
||||
bool is_blank(uint16 line, uint16 width) const;
|
||||
|
||||
byte *ms_extract1(byte pic, uint16 *w, uint16 *h, uint16 *pal);
|
||||
|
||||
int16 find_name_in_header(const Common::String &name, bool upper);
|
||||
|
||||
void extract_frame(const picture *pic);
|
||||
|
||||
byte *ms_extract2(const char *name, uint16 *w, uint16 *h, uint16 *pal, byte *is_anim);
|
||||
|
||||
byte *ms_extract(uint32 pic, uint16 *w, uint16 *h, uint16 *pal, byte *is_anim);
|
||||
|
||||
byte ms_animate(ms_position **positions, uint16 *count);
|
||||
|
||||
byte *ms_get_anim_frame(int16 number, uint16 *width, uint16 *height, byte **mask);
|
||||
|
||||
bool ms_anim_is_repeating() const { return anim_repeat; }
|
||||
|
||||
void write_reg(int i, int s, uint32 val) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* \defgroup Sound support methods
|
||||
* @{
|
||||
*/
|
||||
|
||||
byte init_snd(size_t size);
|
||||
|
||||
int16 find_name_in_sndheader(const Common::String &name);
|
||||
|
||||
byte *sound_extract(const Common::String &name, uint32 *length, uint16 *tempo);
|
||||
|
||||
/**@}*/
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
@ -188,7 +50,9 @@ public:
|
||||
/**
|
||||
* Returns the running interpreter type
|
||||
*/
|
||||
virtual InterpreterType getInterpreterType() const override { return INTERPRETER_MAGNETIC; }
|
||||
virtual InterpreterType getInterpreterType() const override {
|
||||
return INTERPRETER_MAGNETIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a savegame from the passed Quetzal file chunk stream
|
||||
@ -202,6 +66,8 @@ public:
|
||||
virtual Common::Error writeGameData(Common::WriteStream *ws) override;
|
||||
};
|
||||
|
||||
extern Magnetic *g_vm;
|
||||
|
||||
} // End of namespace Magnetic
|
||||
} // End of namespace Glk
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define GLK_MAGNETIC_TYPES
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/algorithm.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Magnetic {
|
||||
@ -47,7 +48,7 @@ struct lookup {
|
||||
};
|
||||
|
||||
struct picture {
|
||||
byte * data;
|
||||
byte *data;
|
||||
uint32 data_size;
|
||||
uint16 width;
|
||||
uint16 height;
|
||||
@ -121,7 +122,7 @@ struct ms_position {
|
||||
struct ms_hint {
|
||||
uint16 elcount;
|
||||
uint16 nodetype;
|
||||
byte *content;
|
||||
const char *content;
|
||||
uint16 links[MAX_HITEMS];
|
||||
uint16 parent;
|
||||
|
||||
|
176
engines/glk/magnetic/main.cpp
Normal file
176
engines/glk/magnetic/main.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/magnetic/defs.h"
|
||||
#include "common/file.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Magnetic {
|
||||
|
||||
#define WIDTH 78
|
||||
|
||||
static type8 buffer[80], xpos = 0, bufpos = 0, log_on = 0, ms_gfx_enabled, filename[256];
|
||||
static Common::DumpFile *log1 = 0, *log2 = 0;
|
||||
|
||||
type8 ms_load_file(const char *name, type8 *ptr, type16 size) {
|
||||
assert(name);
|
||||
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(name);
|
||||
if (!file)
|
||||
return 1;
|
||||
|
||||
if (file->read(ptr, size) != size) {
|
||||
delete file;
|
||||
return 1;
|
||||
}
|
||||
|
||||
delete file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
type8 ms_save_file(const char *name, type8 *ptr, type16 size) {
|
||||
assert(name);
|
||||
Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(name);
|
||||
if (!file)
|
||||
return 1;
|
||||
|
||||
if (file->write(ptr, size) != size) {
|
||||
delete file;
|
||||
return 1;
|
||||
}
|
||||
|
||||
file->finalize();
|
||||
delete file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void script_write(type8 c) {
|
||||
if (log_on == 2)
|
||||
log1->writeByte(c);
|
||||
}
|
||||
|
||||
void transcript_write(type8 c) {
|
||||
if (log2)
|
||||
log2->writeByte(c);
|
||||
}
|
||||
|
||||
void ms_fatal(const char *txt) {
|
||||
error("Fatal error: %s", txt);
|
||||
}
|
||||
|
||||
#if 0
|
||||
main(int argc, char **argv) {
|
||||
type8 running, i, *gamename = 0, *gfxname = 0, *hintname = 0;
|
||||
type32 dlimit, slimit;
|
||||
|
||||
if (sizeof(type8) != 1 || sizeof(type16) != 2 || sizeof(type32) != 4) {
|
||||
fprintf(stderr,
|
||||
"You have incorrect typesizes, please edit the typedefs and recompile\n"
|
||||
"or proceed on your own risk...\n");
|
||||
exit(1);
|
||||
}
|
||||
dlimit = slimit = 0xffffffff;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
switch (tolower(argv[i][1])) {
|
||||
case 'd':
|
||||
if (strlen(argv[i]) > 2)
|
||||
dlimit = atoi(&argv[i][2]);
|
||||
else
|
||||
dlimit = 0;
|
||||
break;
|
||||
case 's':
|
||||
if (strlen(argv[i]) > 2)
|
||||
slimit = atoi(&argv[i][2]);
|
||||
else
|
||||
slimit = 655360;
|
||||
break;
|
||||
case 't':
|
||||
if (!(log2 = fopen(&argv[i][2], "w")))
|
||||
printf("Failed to open \"%s\" for writing.\n", &argv[i][2]);
|
||||
break;
|
||||
case 'r':
|
||||
if (log1 = fopen(&argv[i][2], "r"))
|
||||
log_on = 1;
|
||||
else
|
||||
printf("Failed to open \"%s\" for reading.\n", &argv[i][2]);
|
||||
break;
|
||||
case 'w':
|
||||
if (log1 = fopen(&argv[i][2], "w"))
|
||||
log_on = 2;
|
||||
else
|
||||
printf("Failed to open \"%s\" for writing.\n", &argv[i][2]);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown option -%c, ignoring.\n", argv[i][1]);
|
||||
break;
|
||||
}
|
||||
} else if (!gamename)
|
||||
gamename = argv[i];
|
||||
else if (!gfxname)
|
||||
gfxname = argv[i];
|
||||
else if (!hintname)
|
||||
hintname = argv[i];
|
||||
}
|
||||
if (!gamename) {
|
||||
printf("Magnetic 2.3 - a Magnetic Scrolls interpreter\n\n");
|
||||
printf("Usage: %s [options] game [gfxfile] [hintfile]\n\n"
|
||||
"Where the options are:\n"
|
||||
" -dn activate register dump (after n instructions)\n"
|
||||
" -rname read script file\n"
|
||||
" -sn safety mode, exits automatically (after n instructions)\n"
|
||||
" -tname write transcript file\n"
|
||||
" -wname write script file\n\n"
|
||||
"The interpreter commands are:\n"
|
||||
" #undo undo - don't use it near are_you_sure prompts\n"
|
||||
" #logoff turn off script writing\n\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!(ms_gfx_enabled = ms_init(gamename, gfxname, hintname, 0))) {
|
||||
printf("Couldn't start up game \"%s\".\n", gamename);
|
||||
exit(1);
|
||||
}
|
||||
ms_gfx_enabled--;
|
||||
running = 1;
|
||||
while ((ms_count() < slimit) && running) {
|
||||
if (ms_count() >= dlimit)
|
||||
ms_status();
|
||||
running = ms_rungame();
|
||||
}
|
||||
if (ms_count() == slimit) {
|
||||
printf("\n\nSafety limit (%d) reached.\n", slimit);
|
||||
ms_status();
|
||||
}
|
||||
ms_freemem();
|
||||
if (log_on)
|
||||
fclose(log1);
|
||||
if (log2)
|
||||
fclose(log2);
|
||||
printf("\nExiting.\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // End of namespace Magnetic
|
||||
} // End of namespace Glk
|
133
engines/glk/magnetic/myth.cpp
Normal file
133
engines/glk/magnetic/myth.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Patches Myth C64 disk image
|
||||
* Written by David Kinder, based on code by Niclas Karlsson
|
||||
*/
|
||||
|
||||
#define D64_SIZE (174848L)
|
||||
unsigned char image[D64_SIZE];
|
||||
|
||||
void ungarble(unsigned char *block, signed long key) {
|
||||
unsigned char d;
|
||||
int i, j;
|
||||
|
||||
d = (unsigned char)((key & 0x07) ^ 0xFF);
|
||||
if (d < 0xFF) {
|
||||
i = d;
|
||||
j = d + 1;
|
||||
while (j < 0x100)
|
||||
block[j++] ^= block[i];
|
||||
}
|
||||
|
||||
i = 0xFF;
|
||||
j = d - 1;
|
||||
while (j >= 0)
|
||||
block[j--] ^= block[i--];
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
d = block[i];
|
||||
block[i] = block[255 - i];
|
||||
block[255 - i] = d;
|
||||
}
|
||||
}
|
||||
|
||||
void garble(unsigned char *block, int i1, int j1, int i2) {
|
||||
unsigned char d;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
d = block[i];
|
||||
block[i] = block[255 - i];
|
||||
block[255 - i] = d;
|
||||
}
|
||||
|
||||
i = i1;
|
||||
j = -1;
|
||||
while (j < j1)
|
||||
block[++j] ^= block[++i];
|
||||
|
||||
i = i2;
|
||||
j = 0x100;
|
||||
while (j > i2 + 1)
|
||||
block[--j] ^= block[i];
|
||||
}
|
||||
|
||||
/* This routine does the patching. */
|
||||
void fixDiskImage(int code) {
|
||||
unsigned char *block = NULL;
|
||||
|
||||
switch (code) {
|
||||
case 0:
|
||||
/* code[0x3056] = 0x60 */
|
||||
block = image + 0x1600;
|
||||
ungarble(block, 0x27L);
|
||||
block[0x56] = 0x60;
|
||||
garble(block, 0x07, 0xF7, 0xF8);
|
||||
break;
|
||||
case 1:
|
||||
/* code[0x3148] = 0x60 */
|
||||
/* code[0x314D] = 0x11 */
|
||||
block = image + 0x1700;
|
||||
ungarble(block, 0x28L);
|
||||
block[0x48] = 0x60;
|
||||
block[0x4D] = 0x11;
|
||||
garble(block, 0x00, 0xFE, 0xFF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void readDiskImage(const char *filename) {
|
||||
FILE *file = fopen(filename, "r+b");
|
||||
if (file == NULL)
|
||||
exit(1);
|
||||
fread(image, 1, D64_SIZE, file);
|
||||
}
|
||||
|
||||
void writeDiskImage(const char *filename) {
|
||||
FILE *file = fopen(filename, "w+b");
|
||||
if (file == NULL)
|
||||
exit(1);
|
||||
fwrite(image, 1, D64_SIZE, file);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 4) {
|
||||
int code = -1;
|
||||
if (sscanf(argv[3], "%d", &code) == 1) {
|
||||
if ((code >= 0) && (code <= 1)) {
|
||||
readDiskImage(argv[1]);
|
||||
fixDiskImage(code);
|
||||
writeDiskImage(argv[2]);
|
||||
printf("Myth patched.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Removes password protection from Magnetic Scrolls' Myth.\n");
|
||||
printf("Use: myth input.d64 output.d64 code\n");
|
||||
printf("If code is 0, the password protection is completely removed.\n");
|
||||
printf("If code is 1, any user name and password will be accepted.\n");
|
||||
return 0;
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/magnetic/magnetic.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Magnetic {
|
||||
|
||||
byte Magnetic::init_snd(size_t size) {
|
||||
if (!(snd_buf = new byte[MAX_MUSIC_SIZE])) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
snd_hsize = _sndFile.readUint16LE();
|
||||
if (!(snd_hdr = new byte[snd_hsize])) {
|
||||
delete[] snd_buf;
|
||||
snd_buf = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_sndFile.read(snd_hdr, snd_hsize) != snd_hsize) {
|
||||
delete[] snd_buf;
|
||||
delete[] snd_hdr;
|
||||
snd_buf = nullptr;
|
||||
snd_hdr = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
int16 Magnetic::find_name_in_sndheader(const Common::String &name) {
|
||||
int16 header_pos = 0;
|
||||
|
||||
while (header_pos < snd_hsize) {
|
||||
const char *hname = (const char *)(snd_hdr + header_pos);
|
||||
if (name == hname)
|
||||
return header_pos;
|
||||
header_pos += 18;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
byte *Magnetic::sound_extract(const Common::String &name, uint32 *length, uint16 *tempo) {
|
||||
uint32 offset = 0;
|
||||
int16 header_pos = -1;
|
||||
|
||||
if (header_pos < 0)
|
||||
header_pos = find_name_in_sndheader(name);
|
||||
if (header_pos < 0)
|
||||
return 0;
|
||||
|
||||
*tempo = READ_BE_UINT16(snd_hdr + header_pos + 8);
|
||||
offset = READ_BE_UINT32(snd_hdr + header_pos + 10);
|
||||
*length = READ_BE_UINT32(snd_hdr + header_pos + 14);
|
||||
|
||||
if (offset != 0) {
|
||||
if (!snd_buf)
|
||||
return nullptr;
|
||||
if (!_sndFile.seek(offset))
|
||||
return nullptr;
|
||||
if (_sndFile.read(snd_buf, *length) != *length)
|
||||
return nullptr;
|
||||
|
||||
return snd_buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Magnetic
|
||||
} // End of namespace Glk
|
@ -262,9 +262,9 @@ ifdef ENABLE_GLK_MAGNETIC
|
||||
MODULE_OBJS += \
|
||||
magnetic/detection.o \
|
||||
magnetic/emu.o \
|
||||
magnetic/graphics.o \
|
||||
magnetic/glk.o \
|
||||
magnetic/magnetic.o \
|
||||
magnetic/sound.o
|
||||
magnetic/main.o
|
||||
endif
|
||||
|
||||
ifdef ENABLE_GLK_QUEST
|
||||
|
Loading…
Reference in New Issue
Block a user