scummvm/gob/map.cpp
Torbjörn Andersson d6fb5517ed This should fix the negative frequency bug that caused some sound effects
to not be played, and probably fixes wrong frequency on some that were
played. It's all guesswork, though. I don't know if this is what the
original did.

svn-id: r17882
2005-05-01 10:15:30 +00:00

757 lines
16 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 Ivan Dubrov
* Copyright (C) 2004-2005 The ScummVM project
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include "gob/gob.h"
#include "gob/map.h"
#include "gob/video.h"
#include "gob/util.h"
#include "gob/dataio.h"
#include "gob/inter.h"
#include "gob/goblin.h"
#include "gob/sound.h"
#include "gob/scenery.h"
namespace Gob {
char map_passMap[28][26]; // [y][x]
int16 map_itemsMap[28][26]; // [y][x]
Map_Point map_wayPoints[40];
int16 map_nearestWayPoint = 0;
int16 map_nearestDest = 0;
int16 map_curGoblinX;
int16 map_curGoblinY;
int16 map_destX;
int16 map_destY;
Map_ItemPos map_itemPoses[40];
char map_loadFromAvo;
char map_sourceFile[15];
static char *map_avoDataPtr;
void map_placeItem(int16 x, int16 y, int16 id) {
if ((map_itemsMap[y][x] & 0xff00) != 0)
map_itemsMap[y][x] = (map_itemsMap[y][x] & 0xff00) | id;
else
map_itemsMap[y][x] = (map_itemsMap[y][x] & 0x00ff) | (id << 8);
}
int16 map_getDirection(int16 x0, int16 y0, int16 x1, int16 y1) {
int16 dir;
dir = 0;
if (x0 == x1 && y0 == y1)
return 0;
if (x1 < 0 || x1 > 25 || y1 < 0 || y1 > 27)
return 0;
if (y1 > y0)
dir = 8;
else if (y1 < y0)
dir = 2;
if (x1 > x0)
dir += 4;
else if (x1 < x0)
dir += 1;
if (map_passMap[y0][x0] == 3 && (dir == 3 || dir == 6 || dir == 2)) {
if (map_passMap[y0 - 1][x0] != 0)
return 0x4800;
}
if (map_passMap[y0][x0] == 3 && (dir == 9 || dir == 12 || dir == 8)) {
if (map_passMap[y0 + 1][x0] != 0)
return 0x5000;
}
if (map_passMap[y0][x0] == 6 && (dir == 3 || dir == 6 || dir == 2)) {
if (map_passMap[y0 - 1][x0] != 0)
return 0x4800;
}
if (map_passMap[y0][x0] == 6 && (dir == 9 || dir == 12 || dir == 8)) {
if (map_passMap[y0 + 1][x0] != 0)
return 0x5000;
}
if (dir == 1) {
if (x0 - 1 >= 0 && map_passMap[y0][x0 - 1] != 0)
return 0x4b00;
return 0;
}
if (dir == 4) {
if (x0 + 1 < 26 && map_passMap[y0][x0 + 1] != 0)
return 0x4d00;
return 0;
}
if (dir == 2) {
if (y0 - 1 >= 0 && map_passMap[y0 - 1][x0] != 0)
return 0x4800;
if (y0 - 1 >= 0 && x0 - 1 >= 0
&& map_passMap[y0 - 1][x0 - 1] != 0)
return 0x4700;
if (y0 - 1 >= 0 && x0 + 1 < 26
&& map_passMap[y0 - 1][x0 + 1] != 0)
return 0x4900;
return 0;
}
if (dir == 8) {
if (y0 + 1 < 28 && map_passMap[y0 + 1][x0] != 0)
return 0x5000;
if (y0 + 1 < 28 && x0 - 1 >= 0
&& map_passMap[y0 + 1][x0 - 1] != 0)
return 0x4f00;
if (y0 + 1 < 28 && x0 + 1 < 26
&& map_passMap[y0 + 1][x0 + 1] != 0)
return 0x5100;
return 0;
}
if (dir == 6) {
if (y0 - 1 >= 0 && x0 + 1 < 26
&& map_passMap[y0 - 1][x0 + 1] != 0)
return 0x4900;
if (y0 - 1 >= 0 && map_passMap[y0 - 1][x0] != 0)
return 0x4800;
if (x0 + 1 < 26 && map_passMap[y0][x0 + 1] != 0)
return 0x4d00;
return 0;
}
if (dir == 12) {
if (x0 + 1 < 26 && y0 + 1 < 28
&& map_passMap[y0 + 1][x0 + 1] != 0)
return 0x5100;
if (y0 + 1 < 28 && map_passMap[y0 + 1][x0] != 0)
return 0x5000;
if (x0 + 1 < 26 && map_passMap[y0][x0 + 1] != 0)
return 0x4d00;
return 0;
}
if (dir == 3) {
if (x0 - 1 >= 0 && y0 - 1 >= 0
&& map_passMap[y0 - 1][x0 - 1] != 0)
return 0x4700;
if (y0 - 1 >= 0 && map_passMap[y0 - 1][x0] != 0)
return 0x4800;
if (x0 - 1 >= 0 && map_passMap[y0][x0 - 1] != 0)
return 0x4b00;
return 0;
}
if (dir == 9) {
if (x0 - 1 >= 0 && y0 + 1 < 28
&& map_passMap[y0 + 1][x0 - 1] != 0)
return 0x4f00;
if (y0 + 1 < 28 && map_passMap[y0 + 1][x0] != 0)
return 0x5000;
if (x0 - 1 >= 0 && map_passMap[y0][x0 - 1] != 0)
return 0x4b00;
return 0;
}
return -1;
}
void map_findNearestToGob(void) {
int16 length;
int16 i;
int16 tmp;
length = 30000;
for (i = 0; i < 40; i++) {
if (map_wayPoints[i].x < 0 ||
map_wayPoints[i].x > 25 ||
map_wayPoints[i].y < 0 || map_wayPoints[i].y > 27)
return;
tmp = ABS(map_curGoblinX - map_wayPoints[i].x) +
ABS(map_curGoblinY - map_wayPoints[i].y);
if (tmp <= length) {
map_nearestWayPoint = i;
length = tmp;
}
}
}
void map_findNearestToDest(void) {
int16 length;
int16 tmp;
int16 i;
length = 30000;
for (i = 0; i < 40; i++) {
if (map_wayPoints[i].x < 0 ||
map_wayPoints[i].x > 25 ||
map_wayPoints[i].y < 0 || map_wayPoints[i].y > 27)
return;
tmp = ABS(map_destX - map_wayPoints[i].x) +
ABS(map_destY - map_wayPoints[i].y);
if (tmp <= length) {
map_nearestDest = i;
length = tmp;
}
}
}
int16 map_checkDirectPath(int16 x0, int16 y0, int16 x1, int16 y1) {
uint16 dir;
while (1) {
dir = map_getDirection(x0, y0, x1, y1);
if (x0 == x1 && y0 == y1)
return 1;
if (dir == 0)
return 3;
switch (dir) {
case 0x4700:
x0--;
y0--;
break;
case 0x4800:
y0--;
break;
case 0x4900:
x0++;
y0--;
break;
case 0x4b00:
x0--;
break;
case 0x4d00:
x0++;
break;
case 0x4f00:
x0--;
y0++;
break;
case 0x5000:
y0++;
break;
case 0x5100:
x0++;
y0++;
break;
}
}
}
int16 map_checkLongPath(int16 x0, int16 y0, int16 x1, int16 y1, int16 i0, int16 i1) {
uint16 dir;
int16 curX;
int16 curY;
int16 nextLink;
curX = x0;
curY = y0;
dir = 0;
nextLink = 1;
while (1) {
if (x0 == curX && y0 == curY)
nextLink = 1;
if (nextLink != 0) {
if (map_checkDirectPath(x0, y0, x1, y1) == 1)
return 1;
nextLink = 0;
if (i0 > i1) {
curX = map_wayPoints[i0].x;
curY = map_wayPoints[i0].y;
i0--;
} else if (i0 < i1) {
curX = map_wayPoints[i0].x;
curY = map_wayPoints[i0].y;
i0++;
} else if (i0 == i1) {
curX = map_wayPoints[i0].x;
curY = map_wayPoints[i0].y;
}
}
if (i0 == i1 && map_wayPoints[i0].x == x0
&& map_wayPoints[i0].y == y0) {
if (map_checkDirectPath(x0, y0, x1, y1) == 1)
return 1;
return 0;
}
dir = map_getDirection(x0, y0, curX, curY);
switch (dir) {
case 0:
return 0;
case 0x4700:
x0--;
y0--;
break;
case 0x4800:
y0--;
break;
case 0x4900:
x0++;
y0--;
break;
case 0x4b00:
x0--;
break;
case 0x4d00:
x0++;
break;
case 0x4f00:
x0--;
y0++;
break;
case 0x5000:
y0++;
break;
case 0x5100:
x0++;
y0++;
break;
}
}
}
int16 map_optimizePoints(int16 xPos, int16 yPos) {
int16 i;
if (map_nearestWayPoint < map_nearestDest) {
for (i = map_nearestWayPoint; i <= map_nearestDest; i++) {
if (map_checkDirectPath(xPos, yPos,
map_wayPoints[i].x, map_wayPoints[i].y) == 1)
map_nearestWayPoint = i;
}
} else if (map_nearestWayPoint > map_nearestDest) {
for (i = map_nearestWayPoint; i >= map_nearestDest; i--) {
if (map_checkDirectPath(xPos, yPos,
map_wayPoints[i].x, map_wayPoints[i].y) == 1)
map_nearestWayPoint = i;
}
}
return map_nearestWayPoint;
}
void map_loadDataFromAvo(char *dest, int16 size) {
memcpy(dest, map_avoDataPtr, size);
map_avoDataPtr += size;
}
uint16 map_loadFromAvo_LE_UINT16() {
uint16 tmp = READ_LE_UINT16(map_avoDataPtr);
map_avoDataPtr += 2;
return tmp;
}
void map_loadItemToObject(void) {
int16 flag;
int16 count;
int16 i;
flag = map_loadFromAvo_LE_UINT16();
if (flag == 0)
return;
map_avoDataPtr += 1456;
count = map_loadFromAvo_LE_UINT16();
for (i = 0; i < count; i++) {
map_avoDataPtr += 20;
gob_itemToObject[i] = map_loadFromAvo_LE_UINT16();
map_avoDataPtr += 5;
}
}
void map_loadMapObjects(char *avjFile) {
int16 i;
char avoName[128];
int16 handle;
char item;
int16 soundCount;
int16 tmp;
char *savedPtr;
char *savedPtr2;
char *savedPtr3;
int16 state;
int16 col;
int32 flag;
Gob_State *pState;
char buf[128];
char sndNames[20][14];
char *dataBuf;
int16 x;
int16 y;
int16 count2;
int16 count3;
strcpy(avoName, map_sourceFile);
strcat(avoName, ".avo");
handle = data_openData(avoName);
if (handle >= 0) {
map_loadFromAvo = 1;
data_closeData(handle);
map_avoDataPtr = data_getSmallData(avoName);
dataBuf = map_avoDataPtr;
map_loadDataFromAvo((char *)map_passMap, 28 * 26);
for (y = 0; y < 28; y++) {
for (x = 0; x < 26; x++) {
map_loadDataFromAvo(&item, 1);
map_itemsMap[y][x] = item;
}
}
for (i = 0; i < 40; i++) {
map_wayPoints[i].x = map_loadFromAvo_LE_UINT16();
map_wayPoints[i].y = map_loadFromAvo_LE_UINT16();
}
map_loadDataFromAvo((char *)map_itemPoses, szMap_ItemPos * 20);
} else {
map_loadFromAvo = 0;
map_avoDataPtr = data_getSmallData(avjFile);
dataBuf = map_avoDataPtr;
}
map_avoDataPtr += 32;
map_avoDataPtr += 76;
map_avoDataPtr += 4;
map_avoDataPtr += 20;
for (i = 0; i < 3; i++) {
tmp = map_loadFromAvo_LE_UINT16();
map_avoDataPtr += tmp * 14;
}
soundCount = map_loadFromAvo_LE_UINT16();
savedPtr = map_avoDataPtr;
map_avoDataPtr += 14 * soundCount;
map_avoDataPtr += 4;
map_avoDataPtr += 24;
count2 = map_loadFromAvo_LE_UINT16();
count3 = map_loadFromAvo_LE_UINT16();
savedPtr2 = map_avoDataPtr;
map_avoDataPtr += count2 * 8;
savedPtr3 = map_avoDataPtr;
map_avoDataPtr += count3 * 8;
gob_gobsCount = map_loadFromAvo_LE_UINT16();
for (i = 0; i < gob_gobsCount; i++) {
gob_goblins[i] = (Gob_Object *)malloc(sizeof(Gob_Object));
gob_goblins[i]->xPos = READ_LE_UINT16(savedPtr2);
savedPtr2 += 2;
gob_goblins[i]->yPos = READ_LE_UINT16(savedPtr2);
savedPtr2 += 2;
gob_goblins[i]->order = READ_LE_UINT16(savedPtr2);
savedPtr2 += 2;
gob_goblins[i]->state = READ_LE_UINT16(savedPtr2);
savedPtr2 += 2;
if (i == 3)
gob_goblins[i]->stateMach = (Gob_StateLine *)malloc(szGob_StateLine * 70);
else
gob_goblins[i]->stateMach = (Gob_StateLine *)malloc(szGob_StateLine * 40);
// FIXME: All is wrong further. We should unwind calls to map_loadDataFromAvo()
map_loadDataFromAvo((char *)gob_goblins[i]->stateMach, 40 * szGob_StateLine);
map_avoDataPtr += 160;
gob_goblins[i]->multObjIndex = *map_avoDataPtr;
map_avoDataPtr += 2;
gob_goblins[i]->realStateMach = gob_goblins[i]->stateMach;
for (state = 0; state < 40; state++) {
for (col = 0; col < 6; col++) {
if (gob_goblins[i]->stateMach[state][col] == 0)
continue;
Gob_State *tmpState = (Gob_State *)malloc(sizeof(Gob_State));
gob_goblins[i]->stateMach[state][col] = tmpState;
tmpState->animation = map_loadFromAvo_LE_UINT16();
tmpState->layer = map_loadFromAvo_LE_UINT16();
map_avoDataPtr += 8;
tmpState->unk0 = map_loadFromAvo_LE_UINT16();
tmpState->unk1 = map_loadFromAvo_LE_UINT16();
map_avoDataPtr += 2;
if (READ_LE_UINT32(map_avoDataPtr) != 0) {
map_avoDataPtr += 4;
tmpState->sndItem = map_loadFromAvo_LE_UINT16();
} else {
map_avoDataPtr += 6;
tmpState->sndItem = -1;
}
tmpState->freq = map_loadFromAvo_LE_UINT16();
tmpState->repCount = map_loadFromAvo_LE_UINT16();
tmpState->sndFrame = map_loadFromAvo_LE_UINT16();
}
}
}
pState = (Gob_State *)malloc(sizeof(Gob_State));
gob_goblins[0]->stateMach[39][0] = pState;
pState->animation = 0;
pState->layer = 98;
pState->unk0 = 0;
pState->unk1 = 0;
pState->sndItem = -1;
pState = (Gob_State *) malloc(sizeof(Gob_State));
gob_goblins[1]->stateMach[39][0] = pState;
pState->animation = 0;
pState->layer = 99;
pState->unk0 = 0;
pState->unk1 = 0;
pState->sndItem = -1;
pState = (Gob_State *) malloc(sizeof(Gob_State));
gob_goblins[2]->stateMach[39][0] = pState;
pState->animation = 0;
pState->layer = 100;
pState->unk0 = 0;
pState->unk1 = 0;
pState->sndItem = -1;
gob_goblins[2]->stateMach[10][0]->sndFrame = 13;
gob_goblins[2]->stateMach[11][0]->sndFrame = 13;
gob_goblins[2]->stateMach[28][0]->sndFrame = 13;
gob_goblins[2]->stateMach[29][0]->sndFrame = 13;
gob_goblins[1]->stateMach[10][0]->sndFrame = 13;
gob_goblins[1]->stateMach[11][0]->sndFrame = 13;
for (state = 40; state < 70; state++) {
pState = (Gob_State *)malloc(sizeof(Gob_State));
gob_goblins[3]->stateMach[state][0] = pState;
gob_goblins[3]->stateMach[state][1] = 0;
pState->animation = 9;
pState->layer = state - 40;
pState->sndItem = -1;
pState->sndFrame = 0;
}
gob_objCount = map_loadFromAvo_LE_UINT16();
for (i = 0; i < gob_objCount; i++) {
gob_objects[i] =
(Gob_Object *) malloc(sizeof(Gob_Object));
gob_objects[i]->xPos = READ_LE_UINT16(savedPtr3);
savedPtr3 += 2;
gob_objects[i]->yPos = READ_LE_UINT16(savedPtr3);
savedPtr3 += 2;
gob_objects[i]->order = READ_LE_UINT16(savedPtr3);
savedPtr3 += 2;
gob_objects[i]->state = READ_LE_UINT16(savedPtr3);
savedPtr3 += 2;
gob_objects[i]->stateMach = (Gob_StateLine *)malloc(szGob_StateLine * 40);
map_loadDataFromAvo((char *)gob_objects[i]->stateMach, 40 * szGob_StateLine);
map_avoDataPtr += 160;
gob_objects[i]->multObjIndex = *map_avoDataPtr;
map_avoDataPtr += 2;
gob_objects[i]->realStateMach = gob_objects[i]->stateMach;
for (state = 0; state < 40; state++) {
for (col = 0; col < 6; col++) {
if (gob_objects[i]->stateMach[state][col] == 0)
continue;
Gob_State *tmpState = (Gob_State *)malloc(sizeof(Gob_State));
gob_objects[i]->stateMach[state][col] = tmpState;
tmpState->animation = map_loadFromAvo_LE_UINT16();
tmpState->layer = map_loadFromAvo_LE_UINT16();
map_avoDataPtr += 8;
tmpState->unk0 = map_loadFromAvo_LE_UINT16();
tmpState->unk1 = map_loadFromAvo_LE_UINT16();
map_avoDataPtr += 2;
if (READ_LE_UINT32(map_avoDataPtr) != 0) {
map_avoDataPtr += 4;
tmpState->sndItem = map_loadFromAvo_LE_UINT16();
} else {
map_avoDataPtr += 6;
tmpState->sndItem = -1;
}
tmpState->freq = map_loadFromAvo_LE_UINT16();
tmpState->repCount = map_loadFromAvo_LE_UINT16();
tmpState->sndFrame = map_loadFromAvo_LE_UINT16();
}
}
}
gob_objects[10] = (Gob_Object *)malloc(sizeof(Gob_Object));
memset(gob_objects[10], 0, sizeof(Gob_Object));
gob_objects[10]->stateMach = (Gob_StateLine *)malloc(szGob_StateLine * 40);
memset(gob_objects[10]->stateMach, 0, szGob_StateLine * 40);
pState = (Gob_State *)malloc(sizeof(Gob_State));
gob_objects[10]->stateMach[0][0] = pState;
memset(pState, 0, sizeof(Gob_State));
pState->animation = 9;
pState->layer = 27;
pState->unk0 = 0;
pState->unk1 = 0;
pState->sndItem = -1;
pState->sndFrame = 0;
gob_placeObject(gob_objects[10], 1);
gob_objects[10]->realStateMach = gob_objects[10]->stateMach;
gob_objects[10]->type = 1;
gob_objects[10]->unk14 = 1;
state = map_loadFromAvo_LE_UINT16();
for (i = 0; i < state; i++) {
map_avoDataPtr += 30;
map_loadDataFromAvo((char *)&flag, 4);
map_avoDataPtr += 56;
if (flag != 0)
map_avoDataPtr += 30;
}
map_loadDataFromAvo((char *)&tmp, 2);
map_avoDataPtr += 48;
map_loadItemToObject();
map_avoDataPtr = savedPtr;
for (i = 0; i < soundCount; i++) {
map_loadDataFromAvo(buf, 14);
strcat(buf, ".SND");
strcpy(sndNames[i], buf);
}
free(dataBuf);
gob_soundData[14] = snd_loadSoundData("diamant1.snd");
for (i = 0; i < soundCount; i++) {
handle = data_openData(sndNames[i]);
if (handle < 0)
continue;
data_closeData(handle);
gob_soundData[i] = snd_loadSoundData(sndNames[i]);
}
}
void map_loadMapsInitGobs(void) {
int16 layer;
int16 i;
if (map_loadFromAvo == 0)
error("map_load: Loading .pas/.pos files is not supported!");
for (i = 0; i < 3; i++) {
gob_nextLayer(gob_goblins[i]);
}
for (i = 0; i < 3; i++) {
layer =
gob_goblins[i]->stateMach[gob_goblins[i]->state][0]->layer;
scen_updateAnim(layer, 0, gob_goblins[i]->animation, 0,
gob_goblins[i]->xPos, gob_goblins[i]->yPos, 0);
gob_goblins[i]->yPos = (gob_gobPositions[i].y + 1) * 6 -
(scen_toRedrawBottom - scen_animTop);
gob_goblins[i]->xPos = gob_gobPositions[i].x * 12 -
(scen_toRedrawLeft - scen_animLeft);
gob_goblins[i]->order = scen_toRedrawBottom / 24 + 3;
}
gob_currentGoblin = 0;
gob_pressedMapX = gob_gobPositions[0].x;
gob_pressedMapY = gob_gobPositions[0].y;
gob_pathExistence = 0;
gob_goblins[0]->doAnim = 0;
gob_goblins[1]->doAnim = 1;
gob_goblins[2]->doAnim = 1;
}
} // End of namespace Gob