update copyright date, some formating stuff

This commit is contained in:
Pawel Kolodziejski 2004-02-25 08:21:31 +00:00
parent 362f2dfa1f
commit 10e7e539b7
22 changed files with 925 additions and 922 deletions

View File

@ -1,16 +1,31 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <math.h>
#include "matrix3.h"
void Matrix3::setAsIdentity( void )
{
void Matrix3::setAsIdentity( void ) {
right_.set(1.f, 0.f, 0.f);
up_.set(0.f, 1.f, 0.f);
at_.set(0.f, 0.f, 0.f);
}
void Matrix3::buildFromPitchYawRoll( float pitch, float yaw, float roll )
{
Matrix3 temp1, temp2;
void Matrix3::buildFromPitchYawRoll( float pitch, float yaw, float roll ) {
Matrix3 temp1, temp2;
temp1.constructAroundPitch( pitch );
constructAroundRoll( roll );
@ -22,23 +37,20 @@ void Matrix3::buildFromPitchYawRoll( float pitch, float yaw, float roll )
(*this) *= temp2;
}
#define MYPI 3.141592654
#define DEGTORAD(a) (a*MYPI/180.0)
#define RADTODEG(a) (a*180.0/MYPI)
#define MYPI 3.141592654
#define DEGTORAD(a) (a*MYPI/180.0)
#define RADTODEG(a) (a*180.0/MYPI)
float RadianToDegree( float rad )
{
float RadianToDegree( float rad ) {
return RADTODEG(rad);
}
float DegreeToRadian( float degrees )
{
float DegreeToRadian( float degrees ) {
return DEGTORAD(degrees);
}
// right
void Matrix3::constructAroundPitch( float pitch )
{
void Matrix3::constructAroundPitch( float pitch ) {
float cosa;
float sina;
@ -51,8 +63,7 @@ void Matrix3::constructAroundPitch( float pitch )
}
// up
void Matrix3::constructAroundYaw( float yaw )
{
void Matrix3::constructAroundYaw( float yaw ) {
float cosa;
float sina;
@ -65,8 +76,7 @@ void Matrix3::constructAroundYaw( float yaw )
}
// at
void Matrix3::constructAroundRoll( float roll )
{
void Matrix3::constructAroundRoll( float roll ) {
float cosa;
float sina;
@ -85,8 +95,7 @@ void Matrix3::constructAroundRoll( float roll )
*/
// WARNING: Still buggy in some occasions.
void Matrix3::getPitchYawRoll( float* pPitch, float* pYaw, float* pRoll )
{
void Matrix3::getPitchYawRoll( float* pPitch, float* pYaw, float* pRoll ) {
float D;
float C;
float ftrx;
@ -95,49 +104,45 @@ void Matrix3::getPitchYawRoll( float* pPitch, float* pYaw, float* pRoll )
float angle_y;
float angle_z;
angle_y = D = asin( right_.z() ); /* Calculate Y-axis angle */
C = cos( angle_y );
angle_y = RadianToDegree( angle_y );
angle_y = D = asin( right_.z() ); /* Calculate Y-axis angle */
C = cos( angle_y );
angle_y = RadianToDegree( angle_y );
if ( fabs( C ) > 0.005 ) /* Gimball lock? */
{
ftrx = at_.z() / C; /* No, so get X-axis angle */
ftry = -up_.z() / C;
if ( fabs( C ) > 0.005 ) { /* Gimball lock? */
ftrx = at_.z() / C; /* No, so get X-axis angle */
ftry = -up_.z() / C;
angle_x = RadianToDegree(atan2( ftry, ftrx ));
angle_x = RadianToDegree(atan2( ftry, ftrx ));
ftrx = right_.x() / C; /* Get Z-axis angle */
ftry = -right_.y() / C;
ftrx = right_.x() / C; /* Get Z-axis angle */
ftry = -right_.y() / C;
angle_z = RadianToDegree(atan2( ftry, ftrx ));
}
else /* Gimball lock has occurred */
{
angle_x = 0; /* Set X-axis angle to zqero */
angle_z = RadianToDegree(atan2( ftry, ftrx ));
} else { /* Gimball lock has occurred */
angle_x = 0; /* Set X-axis angle to zqero */
ftrx = up_.y(); /* And calculate Z-axis angle */
ftry = up_.x();
ftrx = up_.y(); /* And calculate Z-axis angle */
ftry = up_.x();
angle_z = RadianToDegree(atan2( ftry, ftrx ));
}
angle_z = RadianToDegree(atan2( ftry, ftrx ));
}
/* return only positive angles in [0,360] */
if (angle_x < 0) angle_x += 360;
if (angle_y < 0) angle_y += 360;
if (angle_z < 0) angle_z += 360;
/* return only positive angles in [0,360] */
if (angle_x < 0) angle_x += 360;
if (angle_y < 0) angle_y += 360;
if (angle_z < 0) angle_z += 360;
if( pPitch)
*pPitch = angle_x;
if( pYaw )
*pYaw = angle_y;
*pYaw = angle_y;
if( pRoll )
*pRoll = angle_z;
}
float Matrix3::getPitch()
{
float Matrix3::getPitch() {
float pitch;
getPitchYawRoll( &pitch, 0, 0);
@ -145,8 +150,7 @@ float Matrix3::getPitch()
return pitch;
}
float Matrix3::getYaw()
{
float Matrix3::getYaw() {
float yaw;
getPitchYawRoll( 0, &yaw, 0);
@ -154,8 +158,7 @@ float Matrix3::getYaw()
return yaw;
}
float Matrix3::getRoll()
{
float Matrix3::getRoll() {
float roll;
getPitchYawRoll( 0, 0, &roll);
@ -163,8 +166,7 @@ float Matrix3::getRoll()
return roll;
}
void Matrix3::transform( Vector3d* v )
{
void Matrix3::transform( Vector3d* v ) {
float x;
float y;
float z;

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -24,8 +24,8 @@
class Matrix3{
public:
Vector3d right_;
Vector3d up_;
Vector3d at_;
Vector3d up_;
Vector3d at_;
void buildFromPitchYawRoll( float pitch, float yaw, float roll );
void setAsIdentity(void);
@ -43,8 +43,7 @@ public:
void transform( Vector3d* v );
// operators
Matrix3& operator *=(const Matrix3& s)
{
Matrix3& operator *=(const Matrix3& s) {
float x, y, z;
x = right_.dotProduct( s.right_.x(), s.up_.x(), s.at_.x() );
@ -67,8 +66,7 @@ public:
return *this;
}
Matrix3& operator =(const Matrix3& s)
{
Matrix3& operator =(const Matrix3& s) {
right_ = s.right_;
up_ = s.up_;
at_ = s.at_;

View File

@ -1,13 +1,28 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "matrix4.h"
Matrix4::Matrix4( void )
{
Matrix4::Matrix4( void ) {
pos_.set( 0.f, 0.f, 0.f );
rot_.setAsIdentity();
}
void Matrix4::translate( float x, float y, float z )
{
void Matrix4::translate( float x, float y, float z ) {
Vector3d v;
v.set( x, y, z );

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -24,21 +24,19 @@
// matrix 4 is a rotation matrix + position
class Matrix4{
public:
Matrix3 rot_;
Matrix3 rot_;
Vector3d pos_;
Matrix4( void );
Matrix4& operator =(const Matrix4& s)
{
Matrix4& operator =(const Matrix4& s) {
pos_ = s.pos_;
rot_ = s.rot_;
return *this;
}
Matrix4& operator *=(const Matrix4& s)
{
Matrix4& operator *=(const Matrix4& s) {
Vector3d v;
v = s.pos_;

View File

@ -63,7 +63,7 @@ public:
return &sectors_[id];
else
return NULL;
}
}
private:
struct Setup { // Camera setup data

View File

@ -1,110 +1,112 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "screen.h"
#include <string.h>
unsigned short int dataTemp[640*480];
unsigned short int dataTemp[640 * 480];
screenBlockDataStruct screenBlockData[NUM_SCREEN_BLOCK_WIDTH][NUM_SCREEN_BLOCK_HEIGHT];
void screenBlocksReset()
{
void screenBlocksReset() {
int i;
int j;
for( i = 0; i < NUM_SCREEN_BLOCK_WIDTH; i++ )
{
for( j = 0; j < NUM_SCREEN_BLOCK_HEIGHT; j++ )
{
for(i = 0; i < NUM_SCREEN_BLOCK_WIDTH; i++) {
for(j = 0; j < NUM_SCREEN_BLOCK_HEIGHT; j++) {
screenBlockData[i][j].isDirty = false;
}
}
}
float getZbufferBlockDepth( char* zbuffer, int x, int y )
{
float getZbufferBlockDepth(char *zbuffer, int x, int y) {
unsigned short int buffer[SCREEN_BLOCK_WIDTH * SCREEN_BLOCK_HEIGHT];
char* readPtr;
char* writePtr;
char *readPtr;
char *writePtr;
int i;
int j;
writePtr = (char*)buffer;
writePtr = (char *)buffer;
for( i = 0; i <16; i++)
{
readPtr = zbuffer + (y*16+i) * 640 + (x*16);
for(j=0; j<16; j++)
{
for(i = 0; i < 16; i++) {
readPtr = zbuffer + (y*16+i) * 640 + (x * 16);
for(j = 0; j < 16; j++) {
*(writePtr++) = *(readPtr++);
*(writePtr++) = *(readPtr++);
}
}
unsigned short int bDepth = 0xFFFF;
for( i = 0; i<SCREEN_BLOCK_SIZE; i++ )
{
for(i = 0; i < SCREEN_BLOCK_SIZE; i++ ) {
if(bDepth > buffer[i])
bDepth = buffer[i];
}
return ((float)bDepth/65535);
return ((float)bDepth / 65535);
}
void screenBlocksInit(char* zbuffer)
{
void screenBlocksInit(char* zbuffer) {
int i;
int j;
memcpy( dataTemp, zbuffer, 640*480*2);
memcpy(dataTemp, zbuffer, 640 * 480 * 2);
for( i = 0; i < NUM_SCREEN_BLOCK_WIDTH; i++ )
{
for( j = 0; j < NUM_SCREEN_BLOCK_HEIGHT; j++ )
{
for(i = 0; i < NUM_SCREEN_BLOCK_WIDTH; i++) {
for(j = 0; j < NUM_SCREEN_BLOCK_HEIGHT; j++) {
screenBlockData[i][j].isDirty = false;
screenBlockData[i][j].depth = getZbufferBlockDepth( zbuffer, i, j );
screenBlockData[i][j].depth = getZbufferBlockDepth(zbuffer, i, j);
}
}
}
void screenBlocksInitEmpty()
{
void screenBlocksInitEmpty() {
int i;
int j;
for( i = 0; i < NUM_SCREEN_BLOCK_WIDTH; i++ )
{
for( j = 0; j < NUM_SCREEN_BLOCK_HEIGHT; j++ )
{
for(i = 0; i < NUM_SCREEN_BLOCK_WIDTH; i++ ) {
for( j = 0; j < NUM_SCREEN_BLOCK_HEIGHT; j++ ) {
screenBlockData[i][j].isDirty = false;
screenBlockData[i][j].depth = 1.f;
}
}
}
void screenBlocksAddRectangle( int top, int right, int left, int bottom, float depth )
{
void screenBlocksAddRectangle( int top, int right, int left, int bottom, float depth) {
// clip the rectange to the screen size
int tempHeight = bottom-top;
top = 480-bottom;
top = 480 - bottom;
bottom = top + tempHeight;
if(top<0)
if(top < 0)
top = 0;
if(top>=SCREEN_HEIGHT)
top = SCREEN_HEIGHT-1;
if(top > =SCREEN_HEIGHT)
top = SCREEN_HEIGHT - 1;
if(bottom<0)
if(bottom < 0)
bottom = 0;
if(bottom>=SCREEN_HEIGHT)
bottom = SCREEN_HEIGHT-1;
if(bottom >= SCREEN_HEIGHT)
bottom = SCREEN_HEIGHT - 1;
if(left<0)
if(left < 0)
left = 0;
if(left>=SCREEN_WIDTH)
left = SCREEN_WIDTH-1;
left = SCREEN_WIDTH - 1;
if(right<0)
right = 0;
@ -138,18 +140,15 @@ void screenBlocksAddRectangle( int top, int right, int left, int bottom, float d
int i;
int j;
for(i=firstLeft; i<firstLeft+width; i++)
{
for(j=firstTop; j<firstTop+height; j++)
{
for(i = firstLeft; i < firstLeft + width; i++) {
for(j = firstTop; j < firstTop + height; j++) {
if(screenBlockData[i][j].depth < depth)
screenBlockData[i][j].isDirty = true;
}
}
}
void screenBlocksDrawDebug()
{
void screenBlocksDrawDebug() {
int i;
int j;
@ -166,12 +165,9 @@ void screenBlocksDrawDebug()
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for(i=0;i<40;i++)
{
for(j=0;j<30;j++)
{
if(screenBlockData[i][j].isDirty)
{
for(i = 0; i< 40; i++) {
for(j = 0;j < 30; j++) {
if(screenBlockData[i][j].isDirty) {
glBegin(GL_QUADS);
glVertex2i(i*16,j*16);
glVertex2i((i+1)*16,j*16);
@ -186,8 +182,7 @@ void screenBlocksDrawDebug()
glDisable(GL_BLEND);
}
void screenBlocksBlitDirtyBlocks()
{
void screenBlocksBlitDirtyBlocks() {
int i;
int j;
@ -202,22 +197,17 @@ void screenBlocksBlitDirtyBlocks()
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_TRUE);
for(j=0;j<30;j++)
{
for(i=0;i<40;i++)
{
for(j = 0;j < 30;j++) {
for(i=0;i<40;i++) {
if (screenBlockData[i][j].isDirty) {
int width = 1;
int start = i++;
// find the largest possible line
while ((screenBlockData[i][j].isDirty) && (i < 40))
{
while ((screenBlockData[i][j].isDirty) && (i < 40)) {
i++;
width++;
}
for (int y = 0; y < 16; y++)
{
for (int y = 0; y < 16; y++) {
glRasterPos2i(start*16, j*16 + y + 1);
glDrawPixels(16*width, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, dataTemp+((j*16 +y) * 640)+(start*16));
}

View File

@ -1,3 +1,20 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#ifndef _SCREEN_H_
#define _SCREEN_H_
@ -18,8 +35,7 @@
#define NUM_SCREEN_BLOCKS (NUM_SCREEN_BLOCK_WIDTH * NUM_SCREEN_BLOCK_HEIGHT)
struct screenBlockDataStruct
{
struct screenBlockDataStruct {
bool isDirty;
float depth;
};

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -166,7 +166,7 @@ bool Smush::setupAnim(const char *file, int x, int y) {
uint32 tag;
int32 size;
tag = _file.readUint32BE();
assert(tag == MKID_BE('SANM'));
size = _file.readUint32BE();
@ -208,7 +208,7 @@ bool Smush::play(const char *filename, int x, int y) {
FILE *tmp = ResourceLoader::instance()->openNewStream(filename);
FILE *outFile = NULL;
sprintf(tmpOut, "smush.temp");
if (tmp != NULL) {
z_stream z;
char inBuf[1024], outBuf[1024], flags;
@ -221,7 +221,7 @@ bool Smush::play(const char *filename, int x, int y) {
if (((flags & 0x04) != 0) || ((flags & 0x10) != 0)) // Misc
error("Unsupported header flag");
if ((flags & 0x08) != 0) { // Name
printf("Decompressing ");
do {
@ -568,33 +568,33 @@ bool zlibFile::open(const char *filename) {
if (filename == NULL || *filename == 0)
return false;
_handle = ResourceLoader::instance()->openNewStream(filename);
if (!_handle) {
warning("zlibFile %s not found", filename);
return false;
return false;
}
warning("zlibFile %s opening...", filename);
// Read in the GZ header
fread(inBuf, 4, sizeof(char), _handle); // Header, Method, Flags
fread(inBuf, 4, sizeof(char), _handle); // Header, Method, Flags
flags = inBuf[3];
fread(inBuf, 6, sizeof(char), _handle); // XFlags
fread(inBuf, 6, sizeof(char), _handle); // XFlags
if (((flags & 0x04) != 0) || ((flags & 0x10) != 0)) // Misc
if (((flags & 0x04) != 0) || ((flags & 0x10) != 0)) // Misc
error("Unsupported header flag");
if ((flags & 0x08) != 0) { // Name
if ((flags & 0x08) != 0) { // Name
printf("Decompressing ");
do {
fread(inBuf, 1, sizeof(char), _handle);
printf("%c", inBuf[0]);
} while(inBuf[0] != 0);
printf("\n");
}
}
if ((flags & 0x02) != 0) // CRC
if ((flags & 0x02) != 0) // CRC
fread(inBuf, 2, sizeof(char), _handle);
stream.zalloc = NULL;
@ -650,17 +650,17 @@ void zlibFile::seek(int32 offs, int whence) {
uint32 zlibFile::read(void *ptr, uint32 len) {
byte *ptr2 = (byte *)ptr;
if (_handle == NULL) {
error("File is not open!");
return 0;
}
if (_handle == NULL) {
error("File is not open!");
return 0;
}
if (len == 0)
return 0;
return 0;
int bufferLeft = sizeof(outBuf) - usedBuffer;
printf("zlibFile::read(%d). usedBuffer: %d. bufferLeft: %d\n", len, usedBuffer, bufferLeft);
// Do we need to get more than one buffer-read to complete this request?
if (len > bufferLeft) {
int maxBuffer = sizeof(outBuf);
@ -687,25 +687,25 @@ uint32 zlibFile::read(void *ptr, uint32 len) {
} else {
memcpy(ptr2, outBuf + usedBuffer, len);
usedBuffer+=len;
}
}
return len;
}
bool zlibFile::fillZlibBuffer() {
int status = 0;
if (stream.avail_in == 0) {
stream.next_in = (Bytef*)inBuf;
stream.avail_in = fread(inBuf, 1, sizeof(inBuf), _handle);
}
status = inflate(&stream, Z_NO_FLUSH);
}
status = inflate(&stream, Z_NO_FLUSH);
if (status == Z_STREAM_END) {
if (sizeof(outBuf) - stream.avail_out)
warning("fillZlibBuffer: End of buffer");
return true;
}
}
if (status != Z_OK) {
warning("Smush::play() - Error inflating stream (%d) [-3 means bad data]", status);
return false;

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -125,13 +125,12 @@ public:
void pause(bool pause) { _videoPause = pause; }
bool isPlaying() { return !_videoFinished; }
bool isUpdateNeeded() { return _updateNeeded; }
void clearUpdateNeeded() {_updateNeeded = false; }
byte *getDstPtr() { return _buf; }
int getX() { return _x; }
int getY() { return _y; }
int getWidth() {return _width; }
int getHeight() { return _height; }
void setUpdateNeeded() { _updateNeeded = true; }
void clearUpdateNeeded() { _updateNeeded = false; }
private:
static void timerCallback(void *ptr);

806
sound.cpp
View File

@ -24,406 +24,399 @@
#include <SDL_endian.h>
struct imuseTableEntry {
int stateNum;
const char *filename;
int stateNum;
const char *filename;
};
static const imuseTableEntry grimMusicTable[] = {
{ 1001, "1001 - Manny's Office.IMC" },
{ 1002, "1002 - Mr. Frustration.IMC" },
{ 1003, "1002 - Mr. Frustration.IMC" },
{ 1004, "1002 - Mr. Frustration.IMC" },
{ 1005, "1002 - Mr. Frustration.IMC" },
{ 1006, "1002 - Mr. Frustration.IMC" },
{ 1007, "1002 - Mr. Frustration.IMC" },
{ 1008, "1008 - Domino's Office.IMC" },
{ 1009, "1009 - Copal's Office.IMC" },
{ 1010, "1010 - Ledge.IMC" },
{ 1011, "1011 - Roof.IMC" },
{ 1020, "1020 - Tube Room.IMC" },
{ 1021, "1021 - Brennis.IMC" },
{ 1022, "1022 - Lobby.IMC" },
{ 1023, "1023 - Packing Room.IMC" },
{ 1030, "1030 - Garage.IMC" },
{ 1031, "1031 - Glottis' Shop.IMC" },
{ 1032, "1030 - Garage.IMC" },
{ 1040, "1040 - Festival Wet.IMC" },
{ 1041, "1041 - Festival Dry.IMC" },
{ 1042, "1041 - Festival Dry.IMC" },
{ 1043, "1041 - Festival Dry.IMC" },
{ 1044, "1040 - Festival Wet.IMC" },
{ 1050, "1050 - Headquarters.IMC" },
{ 1060, "1060 - Real World.IMC" },
{ 1070, "1070 - Stump Room.IMC" },
{ 1071, "1071 - Signpost Room.IMC" },
{ 1072, "1072 - Navigation.IMC" },
{ 1073, "1071 - Signpost Room.IMC" },
{ 1074, "1074 - Bone Wagon.IMC" },
{ 1075, "1075 - Spider's Eye.IMC" },
{ 1076, "1076 - Spider Room.IMC" },
{ 1077, "1077 - Tree Pump Amb.IMC" },
{ 1078, "1078 - Tree Pump.IMC" },
{ 1079, "1071 - Signpost Room.IMC" },
{ 1080, "1080 - Beaver Room Lobby.IMC" },
{ 1081, "1081 - Beaver Dam.IMC" },
{ 1082, "1083 - Beaver Room.IMC" },
{ 1083, "1083 - Beaver Room.IMC" },
{ 1084, "1084 - Foggy Cactus.IMC" },
{ 1085, "1085 - Rubamat Exterior.IMC" },
{ 1086, "1086 - Blue Hector.IMC" },
{ 1100, "1109 - Cafe Exterior.IMC" },
{ 1101, "1101 - Cafe Office.IMC" },
{ 1102, "1102 - Cafe Intercom.IMC" },
{ 1103, "1103 - Coat Check.IMC" },
{ 1104, "1104 - Lupe.IMC" },
{ 1105, "1106 - Glottis Noodle.IMC" },
{ 1106, "1106 - Glottis Noodle.IMC" },
{ 1107, "1101 - Cafe Office.IMC" },
{ 1108, "1108 - Casino Interior.IMC" },
{ 1109, "1109 - Cafe Exterior.IMC" },
{ 1110, "1110 - Cafe Ledge.IMC" },
{ 1111, "1108 - Casino Interior.IMC" },
{ 1112, "1112 - Rusty Sans Vox.IMC" },
{ 1120, "1120 - Elevator Station.IMC" },
{ 1121, "1122 - Blue Exterior.IMC" },
{ 1122, "1122 - Blue Exterior.IMC" },
{ 1123, "1123 - Blue Casket Ins.IMC" },
{ 1124, "1124 - Blue Casket Amb.IMC" },
{ 1125, "1125 - Smooth Hector.IMC" },
{ 1126, "1122 - Blue Exterior.IMC" },
{ 1127, "1127 - Limbo Dock.IMC" },
{ 1128, "1128 - Limbo Talk.IMC" },
{ 1129, "1129 - Limbo Poem.IMC" },
{ 1130, "1130 - Dry Dock.IMC" },
{ 1131, "1131 - Dry Dock Strike.IMC" },
{ 1132, "1132 - Lighthouse Ext.IMC" },
{ 1133, "1133 - Lola's Last.IMC" },
{ 1140, "1140 - Police Station.IMC" },
{ 1141, "1141 - Police Interior.IMC" },
{ 1142, "1141 - Police Interior.IMC" },
{ 1143, "1143 - Morgue.IMC" },
{ 1144, "1140 - Police Station.IMC" },
{ 1145, "1145 - Bridge Blimp.IMC" },
{ 1146, "1146 - LOL Security Ext.IMC" },
{ 1147, "1147 - LOL Security Int.IMC" },
{ 1148, "1148 - Carla's Life.IMC" },
{ 1149, "1149 - Bomb.IMC" },
{ 1150, "1150 - Track Stairs.IMC" },
{ 1151, "1151 - Track Stairs.IMC" },
{ 1152, "1152 - Track Stairs.IMC" },
{ 1153, "1153 - Track Base.IMC" },
{ 1154, "1154 - Kitty Hall.IMC" },
{ 1155, "1155 - Sanspoof.IMC" },
{ 1156, "1156 - Kitty Stables.IMC" },
{ 1160, "1160 - High Roller Hall.IMC" },
{ 1161, "1161 - High Roller Lnge.IMC" },
{ 1162, "1162 - Glottis Gambling.IMC" },
{ 1163, "1163 - Max's Office.IMC" },
{ 1164, "1125 - Hector Steps Out.IMC" },
{ 1165, "1125 - Hector Steps Out.IMC" },
{ 1166, "1125 - Hector Steps Out.IMC" },
{ 1167, "1167 - Dillopede Elev.IMC" },
{ 1168, "1168 - Dillopede Elev.IMC" },
{ 1169, "1169 - Dillopede Elev.IMC" },
{ 1170, "1170 - Extendo Bridge.IMC" },
{ 1171, "1170 - Extendo Bridge.IMC" },
{ 1172, "1170 - Extendo Bridge.IMC" },
{ 1173, "1173 - Scrimshaw Int.IMC" },
{ 1174, "1174 - Scrim Sleep.IMC" },
{ 1180, "1180 - Note to Manny.IMC" },
{ 1181, "1155 - Sanspoof.IMC" },
{ 1190, "1106 - Glottis Noodle.IMC" },
{ 1191, "1106 - Glottis Noodle.IMC" },
{ 1201, "1201 - Lola Zapata.IMC" },
{ 1202, "1202 - Inside the Lola.IMC" },
{ 1203, "1203 - Engine Room.IMC" },
{ 1204, "1204 - Porthole.IMC" },
{ 1205, "1204 - Porthole.IMC" },
{ 1210, "1210 - Sunken Lola.IMC" },
{ 1211, "1211 - Pearl Crater Sub.IMC" },
{ 1220, "1220 - Miner's Room.IMC" },
{ 1221, "1221 - Miner's Room.IMC" },
{ 1222, "1222 - Exterior Airlock.IMC" },
{ 1223, "1223 - Factory Hub.IMC" },
{ 1224, "1224 - Foreman's Office.IMC" },
{ 1230, "1230 - Vault Door.IMC" },
{ 1231, "1231 - Outer Vault.IMC" },
{ 1232, "1232 - Inner Vault.IMC" },
{ 1233, "1233 - Ashtray Room.IMC" },
{ 1234, "1234 - Ashtray Scary.IMC" },
{ 1235, "1235 - Ashtray Pensive.IMC" },
{ 1236, "1236 - Domino's Room.IMC" },
{ 1240, "1240 - Conveyor Under.IMC" },
{ 1241, "1240 - Conveyor Under.IMC" },
{ 1242, "1241 - Crane Intro.IMC" },
{ 1243, "1243 - Anchor Room.IMC" },
{ 1244, "1244 - Glottis Hanging.IMC" },
{ 1245, "1245 - End of the World.IMC" },
{ 1246, "1246 - End World Later.IMC" },
{ 1247, "1241 - Crane Intro.IMC" },
{ 1250, "1250 - Upper Beach.IMC" },
{ 1251, "1250 - Upper Beach.IMC" },
{ 1252, "1252 - Lower Beach Boat.IMC" },
{ 1253, "1253 - Lamancha Sub.IMC" },
{ 1254, "1254 - Crane Later.IMC" },
{ 1301, "1301 - Temple Gate.IMC" },
{ 1302, "1301 - Temple Gate.IMC" },
{ 1303, "1303 - Truck Depot.IMC" },
{ 1304, "1304 - Mayan Train Sta.IMC" },
{ 1305, "1305 - Mayan Workshop.IMC" },
{ 1306, "1306 - Mayan Train Pad.IMC" },
{ 1307, "1307 - Mechanic's Kitch.IMC" },
{ 1310, "1310 - Jello Bomb.IMC" },
{ 1311, "1310 - Jello Bomb.IMC" },
{ 1312, "1125 - Smooth Hector.IMC" },
{ 1313, "1125 - Smooth Hector.IMC" },
{ 1314, "1125 - Smooth Hector.IMC" },
{ 1315, "1122 - Blue Exterior.IMC" },
{ 1316, "1122 - Blue Exterior.IMC" },
{ 1317, "1122 - Blue Exterior.IMC" },
{ 1318, "1332 - Hector's Foyer.IMC" },
{ 1319, "1319 - Florist Video.IMC" },
{ 1320, "1320 - New LSA HQ.IMC" },
{ 1321, "1321 - LSA Sewer.IMC" },
{ 1322, "1321 - LSA Sewer.IMC" },
{ 1323, "1323 - Sewer Maze.IMC" },
{ 1324, "1324 - Albinozod.IMC" },
{ 1325, "1325 - Florist Shop.IMC" },
{ 1326, "1326 - Florist Shop Int.IMC" },
{ 1327, "1327 - Florist OK.IMC" },
{ 1328, "1323 - Sewer Maze.IMC" },
{ 1329, "1329 - Theater Backstag.IMC" },
{ 1330, "1330 - Lemans Lobby.IMC" },
{ 1331, "1330 - Lemans Lobby.IMC" },
{ 1332, "1332 - Hector's Foyer.IMC" },
{ 1333, "1333 - Brennis Talk.IMC" },
{ 1334, "1334 - Albino Trap.IMC" },
{ 1340, "1342 - Neon Ledge.IMC" },
{ 1350, "1350 - Meadow Flowers.IMC" },
{ 1351, "1351 - Meadow.IMC" },
{ 1352, "1352 - Car Head.IMC" },
{ 1353, "1353 - Greenhouse Appr.IMC" },
{ 1354, "1354 - Game Ending.IMC" },
{ 1355, "1355 - Shootout.IMC" },
{ 1400, "1400 - Start Credits.IMC" },
{ 1401, "1401 - Smooth Hector.IMC" },
{ 2001, "2001 - Climb Rope.IMC" },
{ 2010, "2010 - Glottis OK.IMC" },
{ 2020, "2020 - Reap Bruno.IMC" },
{ 2030, "2030 - Ledgepeckers.IMC" },
{ 2050, "2050 - Glottis Heart.IMC" },
{ 2055, "2055 - Slingshot Bone.IMC" },
{ 2060, "2060 - Glott Tree Fall.IMC" },
{ 2070, "2070 - Beaver Fly.IMC" },
{ 2071, "2071 - Beaver Sink.IMC" },
{ 2080, "2080 - Meet Velasco.IMC" },
{ 2140, "2140 - Ooo Bonewagon.IMC" },
{ 2141, "2141 - Ooo Meche.IMC" },
{ 2155, "2155 - Find Detector.IMC" },
{ 2156, "2156 - Glott Drink Wine.IMC" },
{ 2157, "2157 - Glott No Wine.IMC" },
{ 2161, "2161 - Raoul Appears.IMC" },
{ 2162, "2162 - Raoul KO.IMC" },
{ 2163, "2163 - Raoul Dissed.IMC" },
{ 2165, "2165 - Fake Tix.IMC" },
{ 2180, "2180 - Befriend Commies.IMC" },
{ 2186, "2186 - Nick Punchout.IMC" },
{ 2200, "2200 - Year 3 Iris.IMC" },
{ 2210, "2210 - Hit Men.IMC" },
{ 2230, "2230 - Open Vault.IMC" },
{ 2235, "2235 - Dead Tix.IMC" },
{ 2240, "2240 - Sprinkler.IMC" },
{ 2250, "2250 - Crane Track.IMC" },
{ 2255, "2255 - Crane Fall.IMC" },
{ 2300, "2300 - Yr 4 Iris.IMC" },
{ 2301, "2301 - Pop Bruno Casket.IMC" },
{ 2310, "2310 - Rocket Idea.IMC" },
{ 2320, "2320 - Jello Suspense.IMC" },
{ 2325, "2325 - Lumbago Lemo.IMC" },
{ 2327, "2327 - Breath Mint.IMC" },
{ 2330, "2330 - Pigeon Fly.IMC" },
{ 2340, "2340 - Coffee On Boys.IMC" },
{ 2350, "2350 - Sprout Aha.IMC" },
{ 2360, "2360 - Chowchilla Bye.IMC" },
{ 2370, "2370 - Salvador Death.IMC" },
{ 2399, "2399 - End Credits.IMC" }
{ 1001, "1001 - Manny's Office.IMC" },
{ 1002, "1002 - Mr. Frustration.IMC" },
{ 1003, "1002 - Mr. Frustration.IMC" },
{ 1004, "1002 - Mr. Frustration.IMC" },
{ 1005, "1002 - Mr. Frustration.IMC" },
{ 1006, "1002 - Mr. Frustration.IMC" },
{ 1007, "1002 - Mr. Frustration.IMC" },
{ 1008, "1008 - Domino's Office.IMC" },
{ 1009, "1009 - Copal's Office.IMC" },
{ 1010, "1010 - Ledge.IMC" },
{ 1011, "1011 - Roof.IMC" },
{ 1020, "1020 - Tube Room.IMC" },
{ 1021, "1021 - Brennis.IMC" },
{ 1022, "1022 - Lobby.IMC" },
{ 1023, "1023 - Packing Room.IMC" },
{ 1030, "1030 - Garage.IMC" },
{ 1031, "1031 - Glottis' Shop.IMC" },
{ 1032, "1030 - Garage.IMC" },
{ 1040, "1040 - Festival Wet.IMC" },
{ 1041, "1041 - Festival Dry.IMC" },
{ 1042, "1041 - Festival Dry.IMC" },
{ 1043, "1041 - Festival Dry.IMC" },
{ 1044, "1040 - Festival Wet.IMC" },
{ 1050, "1050 - Headquarters.IMC" },
{ 1060, "1060 - Real World.IMC" },
{ 1070, "1070 - Stump Room.IMC" },
{ 1071, "1071 - Signpost Room.IMC" },
{ 1072, "1072 - Navigation.IMC" },
{ 1073, "1071 - Signpost Room.IMC" },
{ 1074, "1074 - Bone Wagon.IMC" },
{ 1075, "1075 - Spider's Eye.IMC" },
{ 1076, "1076 - Spider Room.IMC" },
{ 1077, "1077 - Tree Pump Amb.IMC" },
{ 1078, "1078 - Tree Pump.IMC" },
{ 1079, "1071 - Signpost Room.IMC" },
{ 1080, "1080 - Beaver Room Lobby.IMC" },
{ 1081, "1081 - Beaver Dam.IMC" },
{ 1082, "1083 - Beaver Room.IMC" },
{ 1083, "1083 - Beaver Room.IMC" },
{ 1084, "1084 - Foggy Cactus.IMC" },
{ 1085, "1085 - Rubamat Exterior.IMC" },
{ 1086, "1086 - Blue Hector.IMC" },
{ 1100, "1109 - Cafe Exterior.IMC" },
{ 1101, "1101 - Cafe Office.IMC" },
{ 1102, "1102 - Cafe Intercom.IMC" },
{ 1103, "1103 - Coat Check.IMC" },
{ 1104, "1104 - Lupe.IMC" },
{ 1105, "1106 - Glottis Noodle.IMC" },
{ 1106, "1106 - Glottis Noodle.IMC" },
{ 1107, "1101 - Cafe Office.IMC" },
{ 1108, "1108 - Casino Interior.IMC" },
{ 1109, "1109 - Cafe Exterior.IMC" },
{ 1110, "1110 - Cafe Ledge.IMC" },
{ 1111, "1108 - Casino Interior.IMC" },
{ 1112, "1112 - Rusty Sans Vox.IMC" },
{ 1120, "1120 - Elevator Station.IMC" },
{ 1121, "1122 - Blue Exterior.IMC" },
{ 1122, "1122 - Blue Exterior.IMC" },
{ 1123, "1123 - Blue Casket Ins.IMC" },
{ 1124, "1124 - Blue Casket Amb.IMC" },
{ 1125, "1125 - Smooth Hector.IMC" },
{ 1126, "1122 - Blue Exterior.IMC" },
{ 1127, "1127 - Limbo Dock.IMC" },
{ 1128, "1128 - Limbo Talk.IMC" },
{ 1129, "1129 - Limbo Poem.IMC" },
{ 1130, "1130 - Dry Dock.IMC" },
{ 1131, "1131 - Dry Dock Strike.IMC" },
{ 1132, "1132 - Lighthouse Ext.IMC" },
{ 1133, "1133 - Lola's Last.IMC" },
{ 1140, "1140 - Police Station.IMC" },
{ 1141, "1141 - Police Interior.IMC" },
{ 1142, "1141 - Police Interior.IMC" },
{ 1143, "1143 - Morgue.IMC" },
{ 1144, "1140 - Police Station.IMC" },
{ 1145, "1145 - Bridge Blimp.IMC" },
{ 1146, "1146 - LOL Security Ext.IMC" },
{ 1147, "1147 - LOL Security Int.IMC" },
{ 1148, "1148 - Carla's Life.IMC" },
{ 1149, "1149 - Bomb.IMC" },
{ 1150, "1150 - Track Stairs.IMC" },
{ 1151, "1151 - Track Stairs.IMC" },
{ 1152, "1152 - Track Stairs.IMC" },
{ 1153, "1153 - Track Base.IMC" },
{ 1154, "1154 - Kitty Hall.IMC" },
{ 1155, "1155 - Sanspoof.IMC" },
{ 1156, "1156 - Kitty Stables.IMC" },
{ 1160, "1160 - High Roller Hall.IMC" },
{ 1161, "1161 - High Roller Lnge.IMC" },
{ 1162, "1162 - Glottis Gambling.IMC" },
{ 1163, "1163 - Max's Office.IMC" },
{ 1164, "1125 - Hector Steps Out.IMC" },
{ 1165, "1125 - Hector Steps Out.IMC" },
{ 1166, "1125 - Hector Steps Out.IMC" },
{ 1167, "1167 - Dillopede Elev.IMC" },
{ 1168, "1168 - Dillopede Elev.IMC" },
{ 1169, "1169 - Dillopede Elev.IMC" },
{ 1170, "1170 - Extendo Bridge.IMC" },
{ 1171, "1170 - Extendo Bridge.IMC" },
{ 1172, "1170 - Extendo Bridge.IMC" },
{ 1173, "1173 - Scrimshaw Int.IMC" },
{ 1174, "1174 - Scrim Sleep.IMC" },
{ 1180, "1180 - Note to Manny.IMC" },
{ 1181, "1155 - Sanspoof.IMC" },
{ 1190, "1106 - Glottis Noodle.IMC" },
{ 1191, "1106 - Glottis Noodle.IMC" },
{ 1201, "1201 - Lola Zapata.IMC" },
{ 1202, "1202 - Inside the Lola.IMC" },
{ 1203, "1203 - Engine Room.IMC" },
{ 1204, "1204 - Porthole.IMC" },
{ 1205, "1204 - Porthole.IMC" },
{ 1210, "1210 - Sunken Lola.IMC" },
{ 1211, "1211 - Pearl Crater Sub.IMC" },
{ 1220, "1220 - Miner's Room.IMC" },
{ 1221, "1221 - Miner's Room.IMC" },
{ 1222, "1222 - Exterior Airlock.IMC" },
{ 1223, "1223 - Factory Hub.IMC" },
{ 1224, "1224 - Foreman's Office.IMC" },
{ 1230, "1230 - Vault Door.IMC" },
{ 1231, "1231 - Outer Vault.IMC" },
{ 1232, "1232 - Inner Vault.IMC" },
{ 1233, "1233 - Ashtray Room.IMC" },
{ 1234, "1234 - Ashtray Scary.IMC" },
{ 1235, "1235 - Ashtray Pensive.IMC" },
{ 1236, "1236 - Domino's Room.IMC" },
{ 1240, "1240 - Conveyor Under.IMC" },
{ 1241, "1240 - Conveyor Under.IMC" },
{ 1242, "1241 - Crane Intro.IMC" },
{ 1243, "1243 - Anchor Room.IMC" },
{ 1244, "1244 - Glottis Hanging.IMC" },
{ 1245, "1245 - End of the World.IMC" },
{ 1246, "1246 - End World Later.IMC" },
{ 1247, "1241 - Crane Intro.IMC" },
{ 1250, "1250 - Upper Beach.IMC" },
{ 1251, "1250 - Upper Beach.IMC" },
{ 1252, "1252 - Lower Beach Boat.IMC" },
{ 1253, "1253 - Lamancha Sub.IMC" },
{ 1254, "1254 - Crane Later.IMC" },
{ 1301, "1301 - Temple Gate.IMC" },
{ 1302, "1301 - Temple Gate.IMC" },
{ 1303, "1303 - Truck Depot.IMC" },
{ 1304, "1304 - Mayan Train Sta.IMC" },
{ 1305, "1305 - Mayan Workshop.IMC" },
{ 1306, "1306 - Mayan Train Pad.IMC" },
{ 1307, "1307 - Mechanic's Kitch.IMC" },
{ 1310, "1310 - Jello Bomb.IMC" },
{ 1311, "1310 - Jello Bomb.IMC" },
{ 1312, "1125 - Smooth Hector.IMC" },
{ 1313, "1125 - Smooth Hector.IMC" },
{ 1314, "1125 - Smooth Hector.IMC" },
{ 1315, "1122 - Blue Exterior.IMC" },
{ 1316, "1122 - Blue Exterior.IMC" },
{ 1317, "1122 - Blue Exterior.IMC" },
{ 1318, "1332 - Hector's Foyer.IMC" },
{ 1319, "1319 - Florist Video.IMC" },
{ 1320, "1320 - New LSA HQ.IMC" },
{ 1321, "1321 - LSA Sewer.IMC" },
{ 1322, "1321 - LSA Sewer.IMC" },
{ 1323, "1323 - Sewer Maze.IMC" },
{ 1324, "1324 - Albinozod.IMC" },
{ 1325, "1325 - Florist Shop.IMC" },
{ 1326, "1326 - Florist Shop Int.IMC" },
{ 1327, "1327 - Florist OK.IMC" },
{ 1328, "1323 - Sewer Maze.IMC" },
{ 1329, "1329 - Theater Backstag.IMC" },
{ 1330, "1330 - Lemans Lobby.IMC" },
{ 1331, "1330 - Lemans Lobby.IMC" },
{ 1332, "1332 - Hector's Foyer.IMC" },
{ 1333, "1333 - Brennis Talk.IMC" },
{ 1334, "1334 - Albino Trap.IMC" },
{ 1340, "1342 - Neon Ledge.IMC" },
{ 1350, "1350 - Meadow Flowers.IMC" },
{ 1351, "1351 - Meadow.IMC" },
{ 1352, "1352 - Car Head.IMC" },
{ 1353, "1353 - Greenhouse Appr.IMC" },
{ 1354, "1354 - Game Ending.IMC" },
{ 1355, "1355 - Shootout.IMC" },
{ 1400, "1400 - Start Credits.IMC" },
{ 1401, "1401 - Smooth Hector.IMC" },
{ 2001, "2001 - Climb Rope.IMC" },
{ 2010, "2010 - Glottis OK.IMC" },
{ 2020, "2020 - Reap Bruno.IMC" },
{ 2030, "2030 - Ledgepeckers.IMC" },
{ 2050, "2050 - Glottis Heart.IMC" },
{ 2055, "2055 - Slingshot Bone.IMC" },
{ 2060, "2060 - Glott Tree Fall.IMC" },
{ 2070, "2070 - Beaver Fly.IMC" },
{ 2071, "2071 - Beaver Sink.IMC" },
{ 2080, "2080 - Meet Velasco.IMC" },
{ 2140, "2140 - Ooo Bonewagon.IMC" },
{ 2141, "2141 - Ooo Meche.IMC" },
{ 2155, "2155 - Find Detector.IMC" },
{ 2156, "2156 - Glott Drink Wine.IMC" },
{ 2157, "2157 - Glott No Wine.IMC" },
{ 2161, "2161 - Raoul Appears.IMC" },
{ 2162, "2162 - Raoul KO.IMC" },
{ 2163, "2163 - Raoul Dissed.IMC" },
{ 2165, "2165 - Fake Tix.IMC" },
{ 2180, "2180 - Befriend Commies.IMC" },
{ 2186, "2186 - Nick Punchout.IMC" },
{ 2200, "2200 - Year 3 Iris.IMC" },
{ 2210, "2210 - Hit Men.IMC" },
{ 2230, "2230 - Open Vault.IMC" },
{ 2235, "2235 - Dead Tix.IMC" },
{ 2240, "2240 - Sprinkler.IMC" },
{ 2250, "2250 - Crane Track.IMC" },
{ 2255, "2255 - Crane Fall.IMC" },
{ 2300, "2300 - Yr 4 Iris.IMC" },
{ 2301, "2301 - Pop Bruno Casket.IMC" },
{ 2310, "2310 - Rocket Idea.IMC" },
{ 2320, "2320 - Jello Suspense.IMC" },
{ 2325, "2325 - Lumbago Lemo.IMC" },
{ 2327, "2327 - Breath Mint.IMC" },
{ 2330, "2330 - Pigeon Fly.IMC" },
{ 2340, "2340 - Coffee On Boys.IMC" },
{ 2350, "2350 - Sprout Aha.IMC" },
{ 2360, "2360 - Chowchilla Bye.IMC" },
{ 2370, "2370 - Salvador Death.IMC" },
{ 2399, "2399 - End Credits.IMC" }
};
Mixer *Mixer::instance_ = NULL;
Mixer *Mixer::instance() {
if (instance_ == NULL)
instance_ = new Mixer;
return instance_;
if (instance_ == NULL)
instance_ = new Mixer;
return instance_;
}
void mixerCallback(void *userdata, int16 *stream, uint len) {
Mixer *m = static_cast<Mixer *>(userdata);
m->getAudio(stream, len * 2);
Mixer *m = static_cast<Mixer *>(userdata);
m->getAudio(stream, len * 2);
}
extern SoundMixer *g_mixer;
Mixer::Mixer() :
musicSound_(NULL), seqSound_(NULL)
{
musicSound_(NULL), seqSound_(NULL){
}
void Mixer::start() {
Sound::init();
g_mixer->setupPremix(mixerCallback, this);
g_mixer->setVolume(100);
Sound::init();
g_mixer->setupPremix(mixerCallback, this);
g_mixer->setVolume(100);
}
void Mixer::playVoice(Sound *s) {
s->reset();
voiceSounds_.push_back(s);
s->reset();
voiceSounds_.push_back(s);
}
void Mixer::playSfx(Sound *s) {
s->reset();
sfxSounds_.push_back(s);
s->reset();
sfxSounds_.push_back(s);
}
void Mixer::stopSfx(Sound *s) {
for (sound_list::iterator i = sfxSounds_.begin();
i != sfxSounds_.end(); ) {
if (*i == s)
i = sfxSounds_.erase(i);
else
i++;
}
for (sound_list::iterator i = sfxSounds_.begin(); i != sfxSounds_.end(); ) {
if (*i == s)
i = sfxSounds_.erase(i);
else
i++;
}
}
void Mixer::stopVoice(Sound *s) {
for (sound_list::iterator i = voiceSounds_.begin();
i != voiceSounds_.end(); ) {
if (*i == s)
i = voiceSounds_.erase(i);
else
i++;
}
for (sound_list::iterator i = voiceSounds_.begin(); i != voiceSounds_.end(); ) {
if (*i == s)
i = voiceSounds_.erase(i);
else
i++;
}
}
static int compareStates(const void *p1, const void *p2) {
const imuseTableEntry *e1 = static_cast<const imuseTableEntry *>(p1);
const imuseTableEntry *e2 = static_cast<const imuseTableEntry *>(p2);
return e1->stateNum - e2->stateNum;
const imuseTableEntry *e1 = static_cast<const imuseTableEntry *>(p1);
const imuseTableEntry *e2 = static_cast<const imuseTableEntry *>(p2);
return e1->stateNum - e2->stateNum;
}
void Mixer::setImuseState(int state) {
Sound *newSound = NULL;
Sound *newSound = NULL;
if (state != 1000) {
imuseTableEntry key;
key.stateNum = state;
const imuseTableEntry *e = static_cast<imuseTableEntry *>
(std::bsearch(&key, grimMusicTable,
sizeof(grimMusicTable) / sizeof(grimMusicTable[0]),
sizeof(grimMusicTable[0]), compareStates));
if (e == NULL) {
warning("Unknown IMuse state %d\n", state);
return;
}
if (state != 1000) {
imuseTableEntry key;
key.stateNum = state;
const imuseTableEntry *e = static_cast<imuseTableEntry *>
(std::bsearch(&key, grimMusicTable,
sizeof(grimMusicTable) / sizeof(grimMusicTable[0]),
sizeof(grimMusicTable[0]), compareStates));
if (e == NULL) {
warning("Unknown IMuse state %d\n", state);
return;
}
newSound = ResourceLoader::instance()->loadSound(e->filename);
if (newSound == NULL) {
warning("Could not find music file %s\n", e->filename);
return;
}
}
newSound = ResourceLoader::instance()->loadSound(e->filename);
if (newSound == NULL) {
warning("Could not find music file %s\n", e->filename);
return;
}
}
if (newSound != musicSound_) {
if (newSound != NULL)
newSound->reset();
musicSound_ = newSound;
}
if (newSound != musicSound_) {
if (newSound != NULL)
newSound->reset();
musicSound_ = newSound;
}
}
void Mixer::setImuseSeq(int state) {
Sound *newSound = NULL;
Sound *newSound = NULL;
if (state != 2000) {
imuseTableEntry key;
key.stateNum = state;
const imuseTableEntry *e = static_cast<imuseTableEntry *>
(std::bsearch(&key, grimMusicTable,
sizeof(grimMusicTable) / sizeof(grimMusicTable[0]),
sizeof(grimMusicTable[0]), compareStates));
if (e == NULL) {
warning("Unknown IMuse state %d\n", state);
return;
}
if (state != 2000) {
imuseTableEntry key;
key.stateNum = state;
const imuseTableEntry *e = static_cast<imuseTableEntry *>
(std::bsearch(&key, grimMusicTable,
sizeof(grimMusicTable) / sizeof(grimMusicTable[0]),
sizeof(grimMusicTable[0]), compareStates));
if (e == NULL) {
warning("Unknown IMuse state %d\n", state);
return;
}
Sound *newSound = ResourceLoader::instance()->loadSound(e->filename);
if (newSound == NULL) {
warning("Could not find music file %s\n", e->filename);
return;
}
}
Sound *newSound = ResourceLoader::instance()->loadSound(e->filename);
if (newSound == NULL) {
warning("Could not find music file %s\n", e->filename);
return;
}
}
if (newSound != seqSound_) {
if (newSound != NULL)
newSound->reset();
seqSound_ = newSound;
}
if (newSound != seqSound_) {
if (newSound != NULL)
newSound->reset();
seqSound_ = newSound;
}
}
Sound *Mixer::findSfx(const char *filename) {
for (sound_list::iterator i = sfxSounds_.begin();
i != sfxSounds_.end(); i++) {
if (std::strcmp((*i)->filename(), filename) == 0)
return *i;
}
return NULL;
for (sound_list::iterator i = sfxSounds_.begin(); i != sfxSounds_.end(); i++) {
if (std::strcmp((*i)->filename(), filename) == 0)
return *i;
}
return NULL;
}
bool Mixer::voicePlaying() const {
return ! voiceSounds_.empty();
return ! voiceSounds_.empty();
}
void Mixer::getAudio(int16 *data, int numSamples) {
memset(data, 0, numSamples * 2);
for (sound_list::iterator i = voiceSounds_.begin();
i != voiceSounds_.end(); ) {
(*i)->mix(data, numSamples);
if ((*i)->done())
i = voiceSounds_.erase(i);
else
i++;
}
for (sound_list::iterator i = sfxSounds_.begin();
i != sfxSounds_.end(); ) {
(*i)->mix(data, numSamples);
if ((*i)->done())
i = sfxSounds_.erase(i);
else
i++;
}
if (seqSound_ != NULL) {
seqSound_->mix(data, numSamples);
if (seqSound_->done())
seqSound_ = NULL;
}
else if (musicSound_ != NULL) {
musicSound_->mix(data, numSamples);
if (musicSound_->done())
musicSound_->reset();
}
memset(data, 0, numSamples * 2);
for (sound_list::iterator i = voiceSounds_.begin(); i != voiceSounds_.end(); ) {
(*i)->mix(data, numSamples);
if ((*i)->done())
i = voiceSounds_.erase(i);
else
i++;
}
for (sound_list::iterator i = sfxSounds_.begin(); i != sfxSounds_.end(); ) {
(*i)->mix(data, numSamples);
if ((*i)->done())
i = sfxSounds_.erase(i);
else
i++;
}
if (seqSound_ != NULL) {
seqSound_->mix(data, numSamples);
if (seqSound_->done())
seqSound_ = NULL;
} else if (musicSound_ != NULL) {
musicSound_->mix(data, numSamples);
if (musicSound_->done())
musicSound_->reset();
}
}
#define ST_SAMPLE_MAX 0x7fffL
#define ST_SAMPLE_MIN (-ST_SAMPLE_MAX - 1L)
static inline void clampedAdd(int16& a, int b) {
register int val = a + b;
register int val = a + b;
if (val > ST_SAMPLE_MAX)
val = ST_SAMPLE_MAX;
else if (val < ST_SAMPLE_MIN)
val = ST_SAMPLE_MIN;
if (val > ST_SAMPLE_MAX)
val = ST_SAMPLE_MAX;
else if (val < ST_SAMPLE_MIN)
val = ST_SAMPLE_MIN;
a = val;
a = val;
}
static uint16 destTable[5786];
@ -434,93 +427,86 @@ void Sound::init() {
vimaInit(destTable);
}
Sound::Sound(const char *filename, const char *data, int /* len */) :
Resource(filename)
{
const char *extension = filename + std::strlen(filename) - 3;
const char *dataStart;
int numBlocks, codecsLen;
const char *codecsStart;
const char *headerPos = data;
int dataSize;
Sound::Sound(const char *filename, const char *data, int /* len */) : Resource(filename) {
const char *extension = filename + std::strlen(filename) - 3;
const char *dataStart;
int numBlocks, codecsLen;
const char *codecsStart;
const char *headerPos = data;
int dataSize;
if (strcasecmp(extension, "wav") == 0 || strcasecmp(extension, "imc") == 0) {
// Read MCMP info
if (std::memcmp(data, "MCMP", 4) != 0)
error("Invalid file format in %s\n", filename);
if (strcasecmp(extension, "wav") == 0 || strcasecmp(extension, "imc") == 0) {
// Read MCMP info
if (std::memcmp(data, "MCMP", 4) != 0)
error("Invalid file format in %s\n", filename);
// The first block is the WAVE or IMUS header
numBlocks = READ_BE_UINT16(data + 4);
codecsStart = data + 8 + numBlocks * 9;
codecsLen = READ_BE_UINT16(codecsStart - 2);
headerPos = codecsStart + codecsLen;
}
// The first block is the WAVE or IMUS header
numBlocks = READ_BE_UINT16(data + 4);
codecsStart = data + 8 + numBlocks * 9;
codecsLen = READ_BE_UINT16(codecsStart - 2);
headerPos = codecsStart + codecsLen;
}
if (strcasecmp(extension, "wav") == 0) {
numChannels_ = READ_LE_UINT16(headerPos + 22);
dataStart = headerPos + 28 + READ_LE_UINT32(headerPos + 16);
dataSize = READ_LE_UINT32(dataStart - 4);
}
else if (strcasecmp(extension, "imc") == 0 ||
strcasecmp(extension, "imu") == 0) {
// Ignore MAP info for now...
if (memcmp(headerPos + 16, "FRMT", 4) != 0)
error("FRMT block not where it was expected\n");
numChannels_ = READ_BE_UINT32(headerPos + 40);
dataStart = headerPos + 24 + READ_BE_UINT32(headerPos + 12);
dataSize = READ_BE_UINT32(dataStart - 4);
}
else {
error("Unrecognized extension for sound file %s\n", filename);
}
if (strcasecmp(extension, "wav") == 0) {
numChannels_ = READ_LE_UINT16(headerPos + 22);
dataStart = headerPos + 28 + READ_LE_UINT32(headerPos + 16);
dataSize = READ_LE_UINT32(dataStart - 4);
} else if (strcasecmp(extension, "imc") == 0 || strcasecmp(extension, "imu") == 0) {
// Ignore MAP info for now...
if (memcmp(headerPos + 16, "FRMT", 4) != 0)
error("FRMT block not where it was expected\n");
numChannels_ = READ_BE_UINT32(headerPos + 40);
dataStart = headerPos + 24 + READ_BE_UINT32(headerPos + 12);
dataSize = READ_BE_UINT32(dataStart - 4);
} else {
error("Unrecognized extension for sound file %s\n", filename);
}
if (strcasecmp(extension, "wav") == 0 || strcasecmp(extension, "imc") == 0) {
// Uncompress the samples
numSamples_ = dataSize / 2;
samples_ = new int16[dataSize / 2];
int16 *destPos = samples_;
const char *srcPos = dataStart;
for (int i = 1; i < numBlocks; i++) { // Skip header block
if (std::strcmp(codecsStart + 5 * *(uint8 *)(data + 6 + i * 9),
"VIMA") != 0)
error("Unsupported codec %s\n",
codecsStart + 5 * *(uint8 *)(data + 6 + i * 9));
decompressVima(srcPos, destPos, READ_BE_UINT32(data + 7 + i * 9), destTable);
srcPos += READ_BE_UINT32(data + 11 + i * 9);
destPos += READ_BE_UINT32(data + 7 + i * 9) / 2;
}
}
else {
numSamples_ = dataSize / 2;
samples_ = new int16[dataSize / 2];
std::memcpy(samples_, dataStart, dataSize);
if (strcasecmp(extension, "wav") == 0 || strcasecmp(extension, "imc") == 0) {
// Uncompress the samples
numSamples_ = dataSize / 2;
samples_ = new int16[dataSize / 2];
int16 *destPos = samples_;
const char *srcPos = dataStart;
for (int i = 1; i < numBlocks; i++) { // Skip header block
if (std::strcmp(codecsStart + 5 * *(uint8 *)(data + 6 + i * 9), "VIMA") != 0)
error("Unsupported codec %s\n",
codecsStart + 5 * *(uint8 *)(data + 6 + i * 9));
decompressVima(srcPos, destPos, READ_BE_UINT32(data + 7 + i * 9), destTable);
srcPos += READ_BE_UINT32(data + 11 + i * 9);
destPos += READ_BE_UINT32(data + 7 + i * 9) / 2;
}
} else {
numSamples_ = dataSize / 2;
samples_ = new int16[dataSize / 2];
std::memcpy(samples_, dataStart, dataSize);
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
for (int i = 0; i < numSamples_; i++)
samples_[i] = SDL_Swap16(samples_[i]);
for (int i = 0; i < numSamples_; i++)
samples_[i] = SDL_Swap16(samples_[i]);
#endif
}
}
currPos_ = 0;
currPos_ = 0;
}
void Sound::reset() {
currPos_ = 0;
currPos_ = 0;
}
void Sound::mix(int16 *data, int samples) {
while (samples > 0 && currPos_ < numSamples_) {
clampedAdd(*data, samples_[currPos_]);
data++;
if (numChannels_ == 1) {
*data += samples_[currPos_];
samples--;
data++;
}
currPos_++;
samples--;
}
while (samples > 0 && currPos_ < numSamples_) {
clampedAdd(*data, samples_[currPos_]);
data++;
if (numChannels_ == 1) {
*data += samples_[currPos_];
samples--;
data++;
}
currPos_++;
samples--;
}
}
Sound::~Sound() {
delete[] samples_;
delete[] samples_;
}

56
sound.h
View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -24,51 +24,51 @@
class Sound : public Resource {
public:
Sound(const char *filename, const char *data, int len);
~Sound();
Sound(const char *filename, const char *data, int len);
~Sound();
bool done() const { return currPos_ >= numSamples_; }
bool done() const { return currPos_ >= numSamples_; }
private:
int numSamples_, numChannels_, currPos_;
int16 *samples_;
int numSamples_, numChannels_, currPos_;
int16 *samples_;
static void init();
static void init();
void reset();
void mix(int16 *data, int samples);
void reset();
void mix(int16 *data, int samples);
friend class Mixer;
friend class Mixer;
};
class Mixer {
public:
static Mixer *instance();
static Mixer *instance();
void start();
void start();
void playVoice(Sound *s);
void playSfx(Sound *s);
void stopSfx(Sound *s);
void stopVoice(Sound *s);
void setImuseState(int state);
void setImuseSeq(int seq);
void playVoice(Sound *s);
void playSfx(Sound *s);
void stopSfx(Sound *s);
void stopVoice(Sound *s);
void setImuseState(int state);
void setImuseSeq(int seq);
Sound *findSfx(const char *filename);
bool voicePlaying() const;
Sound *findSfx(const char *filename);
bool voicePlaying() const;
void getAudio(int16 *data, int numSamples);
void getAudio(int16 *data, int numSamples);
private:
Mixer();
~Mixer();
Mixer();
~Mixer();
static Mixer *instance_;
typedef std::list<ResPtr<Sound> > sound_list;
sound_list voiceSounds_, sfxSounds_;
ResPtr<Sound> musicSound_, seqSound_;
static Mixer *instance_;
typedef std::list<ResPtr<Sound> > sound_list;
sound_list voiceSounds_, sfxSounds_;
ResPtr<Sound> musicSound_, seqSound_;
friend void mixerCallback(void *userdata, uint8 *stream, int len);
friend void mixerCallback(void *userdata, uint8 *stream, int len);
};
#endif

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -22,9 +22,9 @@
#include "driver_gl.h"
TextObject::TextObject(const char *text, const int x, const int y, const Color& fgColor) :
fgColor_(fgColor), x_(x), y_(y) {
strcpy(textID_, text);
Engine::instance()->registerTextObject(this);
fgColor_(fgColor), x_(x), y_(y) {
strcpy(textID_, text);
Engine::instance()->registerTextObject(this);
}
void TextObject::setX(int x) {x_ = x;}
@ -32,9 +32,9 @@ void TextObject::setY(int y) {y_ = y;}
void TextObject::setColor(Color *newcolor) {fgColor_ = newcolor;}
void TextObject::draw() {
const char *localString = Localizer::instance()->localize(textID_).c_str();
const char *localString = Localizer::instance()->localize(textID_).c_str();
//warning("Drawing text object %s at (%d,%d): %s", textID_, x_, y_, localString);
g_driver->drawHackFont(x_, y_, localString, fgColor_);
//warning("Drawing text object %s at (%d,%d): %s", textID_, x_, y_, localString);
g_driver->drawHackFont(x_, y_, localString, fgColor_);
}

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -25,18 +25,18 @@
#include <string>
class TextObject {
public:
TextObject(const char *text, const int x, const int y, const Color& fgColor);
void setX(int x);
void setY(int y);
void setColor(Color *newColor);
public:
TextObject(const char *text, const int x, const int y, const Color& fgColor);
void setX(int x);
void setY(int y);
void setColor(Color *newColor);
const char *name() const { return textID_; }
void draw();
const char *name() const { return textID_; }
void draw();
protected:
char textID_[10];
Color fgColor_;
int x_, y_;
protected:
char textID_[10];
Color fgColor_;
int x_, y_;
};
#endif

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -26,92 +26,92 @@
// FIXME: Replace this with a proper parser (this is just too dodgy :)
int residual_vsscanf(const char *str, int field_count, const char *format, va_list ap) {
unsigned int f01 = va_arg(ap, long);
unsigned int f02 = va_arg(ap, long);
unsigned int f03 = va_arg(ap, long);
unsigned int f04 = va_arg(ap, long);
unsigned int f05 = va_arg(ap, long);
unsigned int f06 = va_arg(ap, long);
unsigned int f07 = va_arg(ap, long);
unsigned int f08 = va_arg(ap, long);
unsigned int f09 = va_arg(ap, long);
unsigned int f10 = va_arg(ap, long);
unsigned int f01 = va_arg(ap, long);
unsigned int f02 = va_arg(ap, long);
unsigned int f03 = va_arg(ap, long);
unsigned int f04 = va_arg(ap, long);
unsigned int f05 = va_arg(ap, long);
unsigned int f06 = va_arg(ap, long);
unsigned int f07 = va_arg(ap, long);
unsigned int f08 = va_arg(ap, long);
unsigned int f09 = va_arg(ap, long);
unsigned int f10 = va_arg(ap, long);
if (field_count > 10)
error("Too many fields requested of residual_vsscanf (%d)", field_count);
if (field_count > 10)
error("Too many fields requested of residual_vsscanf (%d)", field_count);
return sscanf(str, format, f01, f02, f03, f04, f05, f06, f07, f08, f09, f10);
return sscanf(str, format, f01, f02, f03, f04, f05, f06, f07, f08, f09, f10);
}
TextSplitter::TextSplitter(const char *data, int len) {
data_ = new char[len + 1];
std::memcpy(data_, data, len);
data_[len] = '\0';
curr_line_ = data_;
processLine();
data_ = new char[len + 1];
std::memcpy(data_, data, len);
data_[len] = '\0';
curr_line_ = data_;
processLine();
}
bool TextSplitter::checkString(const char *needle) {
if (std::strstr(currentLine(), needle))
return true;
else
return false;
if (std::strstr(currentLine(), needle))
return true;
else
return false;
}
void TextSplitter::expectString(const char *expected) {
if (eof())
error("Expected `%s', got EOF\n", expected);
if (std::strcmp(currentLine(), expected) != 0)
error("Expected `%s', got `%s'\n", expected, currentLine());
nextLine();
if (eof())
error("Expected `%s', got EOF\n", expected);
if (std::strcmp(currentLine(), expected) != 0)
error("Expected `%s', got `%s'\n", expected, currentLine());
nextLine();
}
void TextSplitter::scanString(const char *fmt, int field_count, ...) {
if (eof())
error("Expected line of format `%s', got EOF\n", fmt);
if (eof())
error("Expected line of format `%s', got EOF\n", fmt);
std::va_list va;
std::va_list va;
va_start(va, field_count);
#ifdef WIN32
if (residual_vsscanf(currentLine(), field_count, fmt, va) < field_count)
#else
if (vsscanf(currentLine(), fmt, va) < field_count)
#endif
error("Expected line of format `%s', got `%s'\n", fmt, currentLine());
va_end(va);
va_start(va, field_count);
nextLine();
}
#ifdef WIN32
if (residual_vsscanf(currentLine(), field_count, fmt, va) < field_count)
#else
if (vsscanf(currentLine(), fmt, va) < field_count)
#endif
error("Expected line of format `%s', got `%s'\n", fmt, currentLine());
va_end(va);
nextLine();
}
void TextSplitter::processLine() {
if (eof())
return;
if (eof())
return;
next_line_ = std::strchr(curr_line_, '\n');
if (next_line_ != NULL) {
*next_line_ = '\0';
next_line_++;
}
next_line_ = std::strchr(curr_line_, '\n');
if (next_line_ != NULL) {
*next_line_ = '\0';
next_line_++;
}
// Cut off comments
char *comment_start = std::strchr(curr_line_, '#');
if (comment_start != NULL)
*comment_start = '\0';
// Cut off comments
char *comment_start = std::strchr(curr_line_, '#');
if (comment_start != NULL)
*comment_start = '\0';
// Cut off trailing whitespace (including '\r')
char *strend = std::strchr(curr_line_, '\0');
while (strend > curr_line_ && std::isspace(strend[-1]))
strend--;
*strend = '\0';
// Cut off trailing whitespace (including '\r')
char *strend = std::strchr(curr_line_, '\0');
while (strend > curr_line_ && std::isspace(strend[-1]))
strend--;
*strend = '\0';
// Skip blank lines
if (*curr_line_ == '\0')
nextLine();
// Skip blank lines
if (*curr_line_ == '\0')
nextLine();
// Convert to lower case
if (! eof())
for (char *s = curr_line_; *s != '\0'; s++)
*s = std::tolower(*s);
// Convert to lower case
if (! eof())
for (char *s = curr_line_; *s != '\0'; s++)
*s = std::tolower(*s);
}

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -26,40 +26,40 @@
class TextSplitter {
public:
TextSplitter(const char *data, int len);
TextSplitter(const char *data, int len);
char *nextLine() {
curr_line_ = next_line_;
processLine();
return curr_line_;
}
char *nextLine() {
curr_line_ = next_line_;
processLine();
return curr_line_;
}
char *currentLine() { return curr_line_; }
const char *currentLine() const { return curr_line_; }
bool eof() const { return curr_line_ == NULL; }
char *currentLine() { return curr_line_; }
const char *currentLine() const { return curr_line_; }
bool eof() const { return curr_line_ == NULL; }
// Check if the current line contains 'needle'
bool TextSplitter::checkString(const char *needle);
// Check if the current line contains 'needle'
bool TextSplitter::checkString(const char *needle);
// Expect a certain fixed string; bail out with an error if not
// found. Advance to the next line.
void expectString(const char *expected);
// Expect a certain fixed string; bail out with an error if not
// found. Advance to the next line.
void expectString(const char *expected);
// Scan a line according to the given format (compatible with
// scanf); if not all fields are read (according to the field_count
// argument), bail out with an error. Advance to the next line.
void scanString(const char *fmt, int field_count, ...)
// Scan a line according to the given format (compatible with
// scanf); if not all fields are read (according to the field_count
// argument), bail out with an error. Advance to the next line.
void scanString(const char *fmt, int field_count, ...)
#ifdef __GNUC__
__attribute__((format (scanf, 2, 4)))
__attribute__((format (scanf, 2, 4)))
#endif
;
;
~TextSplitter() { delete[] data_; }
~TextSplitter() { delete[] data_; }
private:
char *data_, *curr_line_, *next_line_;
char *data_, *curr_line_, *next_line_;
void processLine();
void processLine();
};
#endif

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -22,120 +22,120 @@
class Vector3d {
public:
float coords_[3]; // Make sure this stays as an array so
// it can be passed to GL functions
float coords_[3]; // Make sure this stays as an array so
// it can be passed to GL functions
float& x() { return coords_[0]; }
float x() const { return coords_[0]; }
float& y() { return coords_[1]; }
float y() const { return coords_[1]; }
float& z() { return coords_[2]; }
float z() const { return coords_[2]; }
float& x() { return coords_[0]; }
float x() const { return coords_[0]; }
float& y() { return coords_[1]; }
float y() const { return coords_[1]; }
float& z() { return coords_[2]; }
float z() const { return coords_[2]; }
Vector3d() {this->x() = 0; this->y() = 0; this->z() = 0;}
Vector3d(float x, float y, float z) {
this->x() = x; this->y() = y; this->z() = z;
}
Vector3d(const Vector3d &v) {
x() = v.x(); y() = v.y(); z() = v.z();
}
Vector3d() {this->x() = 0; this->y() = 0; this->z() = 0;}
Vector3d(float x, float y, float z) {
this->x() = x; this->y() = y; this->z() = z;
}
Vector3d(const Vector3d &v) {
x() = v.x(); y() = v.y(); z() = v.z();
}
void set(float x, float y, float z) {
this->x() = x; this->y() = y; this->z() = z;
}
void set(float x, float y, float z) {
this->x() = x; this->y() = y; this->z() = z;
}
Vector3d& operator =(const Vector3d &v) {
x() = v.x(); y() = v.y(); z() = v.z();
return *this;
}
Vector3d& operator =(const Vector3d &v) {
x() = v.x(); y() = v.y(); z() = v.z();
return *this;
}
bool operator ==(const Vector3d &v) {
return ( (x() == v.x()) && (y() == v.y()) && (z() == v.z()) );
}
bool operator ==(const Vector3d &v) {
return ( (x() == v.x()) && (y() == v.y()) && (z() == v.z()) );
}
bool operator !=(const Vector3d &v) {
return ( (x() != v.x()) || (y() != v.y()) || (z() != v.z()) );
}
bool operator !=(const Vector3d &v) {
return ( (x() != v.x()) || (y() != v.y()) || (z() != v.z()) );
}
Vector3d& operator +=(const Vector3d &v) {
x() += v.x(); y() += v.y(); z() += v.z();
return *this;
}
Vector3d& operator +=(const Vector3d &v) {
x() += v.x(); y() += v.y(); z() += v.z();
return *this;
}
Vector3d& operator -=(const Vector3d &v) {
x() -= v.x(); y() -= v.y(); z() -= v.z();
return *this;
}
Vector3d& operator -=(const Vector3d &v) {
x() -= v.x(); y() -= v.y(); z() -= v.z();
return *this;
}
Vector3d& operator *=(float s) {
x() *= s; y() *= s; z() *= s;
return *this;
}
Vector3d& operator *=(float s) {
x() *= s; y() *= s; z() *= s;
return *this;
}
Vector3d& operator /=(float s) {
x() /= s; y() /= s; z() /= s;
return *this;
}
Vector3d& operator /=(float s) {
x() /= s; y() /= s; z() /= s;
return *this;
}
float magnitude() const {
return std::sqrt(x() * x() + y() * y() + z() * z());
}
float magnitude() const {
return std::sqrt(x() * x() + y() * y() + z() * z());
}
float dotProduct( float sx, float sy, float sz ) {
return x()*sx + y()*sy + z()*sz;
}
float dotProduct( float sx, float sy, float sz ) {
return x()*sx + y()*sy + z()*sz;
}
bool isZero() {
if(x() == 0.f && y() == 0.f && z() == 0.f)
return true;
return false;
}
bool isZero() {
if(x() == 0.f && y() == 0.f && z() == 0.f)
return true;
return false;
}
};
inline float dot(const Vector3d& v1, const Vector3d& v2) {
return v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
return v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
}
inline Vector3d cross(const Vector3d& v1, const Vector3d& v2) {
return Vector3d(v1.y() * v2.z() - v1.z() * v2.y(),
v1.z() * v2.x() - v1.x() * v2.z(),
v1.x() * v2.y() - v1.y() * v2.x());
return Vector3d(v1.y() * v2.z() - v1.z() * v2.y(),
v1.z() * v2.x() - v1.x() * v2.z(),
v1.x() * v2.y() - v1.y() * v2.x());
}
inline float angle(const Vector3d& v1, const Vector3d& v2) {
return std::acos(dot(v1, v2) / (v1.magnitude() * v2.magnitude()));
return std::acos(dot(v1, v2) / (v1.magnitude() * v2.magnitude()));
}
inline Vector3d operator +(const Vector3d& v1, const Vector3d& v2) {
Vector3d result = v1;
result += v2;
return result;
Vector3d result = v1;
result += v2;
return result;
}
inline Vector3d operator -(const Vector3d& v1, const Vector3d& v2) {
Vector3d result = v1;
result -= v2;
return result;
Vector3d result = v1;
result -= v2;
return result;
}
inline Vector3d operator *(float s, const Vector3d& v) {
Vector3d result = v;
result *= s;
return result;
Vector3d result = v;
result *= s;
return result;
}
inline Vector3d operator *(const Vector3d& v, float s) {
return s * v;
return s * v;
}
inline Vector3d operator /(const Vector3d& v, float s) {
Vector3d result = v;
result /= s;
return result;
Vector3d result = v;
result /= s;
return result;
}
inline bool operator ==(const Vector3d& v1, const Vector3d& v2) {
return v1.x() == v2.x() && v1.y() == v2.y() && v1.z() == v2.z();
return v1.x() == v2.x() && v1.y() == v2.y() && v1.z() == v2.z();
}
#endif

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -20,73 +20,73 @@
#include "debug.h"
static int16 imcTable1[] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
static int8 imcTable2[] = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
static int8 imcOtherTable1[] = {
-1, 4, -1, 4
-1, 4, -1, 4
};
static int8 imcOtherTable2[] = {
-1, -1, 2, 6, -1, -1, 2, 6
-1, -1, 2, 6, -1, -1, 2, 6
};
static int8 imcOtherTable3[] = {
-1, -1, -1, -1, 1, 2, 4, 6,
-1, -1, -1, -1, 1, 2, 4, 6
-1, -1, -1, -1, 1, 2, 4, 6,
-1, -1, -1, -1, 1, 2, 4, 6
};
static int8 imcOtherTable4[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 2, 2, 4, 5, 6,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 2, 2, 4, 5, 6
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 2, 2, 4, 5, 6,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 2, 2, 4, 5, 6
};
static int8 imcOtherTable5[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 2, 2, 2,
2, 4, 4, 4, 5, 5, 6, 6,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 2, 2, 2,
2, 4, 4, 4, 5, 5, 6, 6
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 2, 2, 2,
2, 4, 4, 4, 5, 5, 6, 6,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 2, 2, 2,
2, 4, 4, 4, 5, 5, 6, 6
};
static int8 imcOtherTable6[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 6, 6, 6, 6,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 6, 6, 6, 6
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 6, 6, 6, 6,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 6, 6, 6, 6
};
static int8 *offsets[] = {

View File

@ -1,6 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -21,86 +20,86 @@
#include "textsplit.h"
void Sector::load(TextSplitter &ts) {
char buf[256];
int id = 0;
char buf[256];
int id = 0;
// Sector NAMES can be null, but ts isn't flexible enough
if (strlen(ts.currentLine()) > strlen(" sector"))
ts.scanString(" sector %256s", 1, buf);
else {
ts.nextLine();
strcpy(buf, "");
}
// Sector NAMES can be null, but ts isn't flexible enough
if (strlen(ts.currentLine()) > strlen(" sector"))
ts.scanString(" sector %256s", 1, buf);
else {
ts.nextLine();
strcpy(buf, "");
}
ts.scanString(" id %d", 1, &id);
load0(ts, buf, id);
ts.scanString(" id %d", 1, &id);
load0(ts, buf, id);
}
void Sector::load0(TextSplitter &ts, char *name, int id) {
char buf[256];
int i = 0;
float height = 12345.f; // Yaz: this is in the original code...
Vector3d tempVert;
char buf[256];
int i = 0;
float height = 12345.f; // Yaz: this is in the original code...
Vector3d tempVert;
name_ = name;
id_ = id;
ts.scanString(" type %256s", 1, buf);
name_ = name;
id_ = id;
ts.scanString(" type %256s", 1, buf);
// Flags used in function at 4A66C0 (buildWalkPlane)
// Flags used in function at 4A66C0 (buildWalkPlane)
if (strstr(buf, "walk"))
type_ = 0x1000;
if (strstr(buf, "walk"))
type_ = 0x1000;
else if (strstr(buf, "funnel"))
type_ = 0x1100;
else if (strstr(buf, "camera"))
type_ = 0x2000;
else if (strstr(buf, "special"))
type_ = 0x4000;
else if (strstr(buf, "chernobyl"))
type_ = 0x8000;
else
error("Unknown sector type '%s' in room setup", buf);
else if (strstr(buf, "funnel"))
type_ = 0x1100;
else if (strstr(buf, "camera"))
type_ = 0x2000;
else if (strstr(buf, "special"))
type_ = 0x4000;
else if (strstr(buf, "chernobyl"))
type_ = 0x8000;
else
error("Unknown sector type '%s' in room setup", buf);
ts.scanString(" default visibility %256s", 1, buf);
if (strcmp(buf, "visible") == 0)
visible_ = true;
else if (strcmp(buf, "invisible") == 0)
visible_ = false;
else
error("Invalid visibility spec: %s\n", buf);
ts.scanString(" height %f", 1, &height_);
ts.scanString(" numvertices %d", 1, &numVertices_);
vertices_ = new Vector3d[numVertices_ + 1];
ts.scanString(" default visibility %256s", 1, buf);
if (strcmp(buf, "visible") == 0)
visible_ = true;
else if (strcmp(buf, "invisible") == 0)
visible_ = false;
else
error("Invalid visibility spec: %s\n", buf);
ts.scanString(" height %f", 1, &height_);
ts.scanString(" numvertices %d", 1, &numVertices_);
vertices_ = new Vector3d[numVertices_ + 1];
ts.scanString(" vertices: %f %f %f", 3, &vertices_[0].x(), &vertices_[0].y(),
&vertices_[0].z());
for (i=1;i<numVertices_;i++)
ts.scanString(" %f %f %f", 3, &vertices_[i].x(), &vertices_[i].y(), &vertices_[i].z());
ts.scanString(" vertices: %f %f %f", 3, &vertices_[0].x(), &vertices_[0].y(),
&vertices_[0].z());
for (i=1;i<numVertices_;i++)
ts.scanString(" %f %f %f", 3, &vertices_[i].x(), &vertices_[i].y(), &vertices_[i].z());
// Repeat the last vertex for convenience
vertices_[numVertices_] = vertices_[0];
// Repeat the last vertex for convenience
vertices_[numVertices_] = vertices_[0];
}
void Sector::setVisible(bool visible) {
visible_ = visible;
visible_ = visible;
}
bool Sector::isPointInSector(Vector3d point) const {
// The algorithm: for each edge A->B, check whether the z-component
// of (B-A) x (P-A) is >= 0. Then the point is at least in the
// cylinder above&below the polygon. (This works because the polygons'
// vertices are always given in counterclockwise order, and the
// polygons are always convex.)
//
// (I don't know whether the box height actually has to be considered;
// if not then this will be fine as is.)
// The algorithm: for each edge A->B, check whether the z-component
// of (B-A) x (P-A) is >= 0. Then the point is at least in the
// cylinder above&below the polygon. (This works because the polygons'
// vertices are always given in counterclockwise order, and the
// polygons are always convex.)
//
// (I don't know whether the box height actually has to be considered;
// if not then this will be fine as is.)
for (int i = 0; i < numVertices_; i++) {
Vector3d edge = vertices_[i+1] - vertices_[i];
Vector3d delta = point - vertices_[i];
if (edge.x() * delta.y() < edge.y() * delta.x())
return false;
}
return true;
for (int i = 0; i < numVertices_; i++) {
Vector3d edge = vertices_[i+1] - vertices_[i];
Vector3d delta = point - vertices_[i];
if (edge.x() * delta.y() < edge.y() * delta.x())
return false;
}
return true;
}

View File

@ -1,5 +1,5 @@
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -28,24 +28,24 @@ class TextSplitter;
class Sector {
public:
void load(TextSplitter &ts);
void load0(TextSplitter &ts, char *name, int id);
void load(TextSplitter &ts);
void load0(TextSplitter &ts, char *name, int id);
void setVisible(bool visible);
void setVisible(bool visible);
const char *name() const { return name_.c_str(); }
const int id() const { return id_; }
const int type() const { return type_; } // FIXME: Implement type de-masking
bool visible() const { return visible_; }
bool isPointInSector(Vector3d point) const;
const char *name() const { return name_.c_str(); }
const int id() const { return id_; }
const int type() const { return type_; } // FIXME: Implement type de-masking
bool visible() const { return visible_; }
bool isPointInSector(Vector3d point) const;
private:
int numVertices_, id_;
int numVertices_, id_;
std::string name_;
int type_;
bool visible_;
Vector3d *vertices_;
float height_;
std::string name_;
int type_;
bool visible_;
Vector3d *vertices_;
float height_;
};
#endif