Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

1
engines/icb/POTFILES Normal file
View File

@@ -0,0 +1 @@
engines/icb/icb.cpp

145
engines/icb/actor.cpp Normal file
View File

@@ -0,0 +1,145 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/global_objects.h"
#include "engines/icb/actor.h"
#include "engines/icb/gfx/psx_scrn.h"
#include "engines/icb/gfx/psx_poly.h"
#include "engines/icb/common/px_capri_maths.h"
namespace ICB {
// return 0 if on screen
// return 1 if off screen
int32 QuickActorCull(psxCamera *camera, VECTOR *pos, SVECTOR *orient) {
MATRIX lw, ls;
// Set the focal length in the GTE
gte_SetGeomScreen(camera->focLen);
// Now make a "true" local-world matrix i.e. without render correction
RotMatrix_gte(orient, &lw);
lw.t[0] = pos->vx;
lw.t[1] = pos->vy;
lw.t[2] = pos->vz;
// Make the equivalent local-screen matrix
// Should inline this
makeLSmatrix(&camera->view, &lw, &ls);
// Do a high level check to see if the actor and a very large bounding box are on the screen or not
int16 xminLocal = -100; // -1m
int16 yminLocal = 0; // on the ground
int16 zminLocal = -100; // +1m
int16 xmaxLocal = +100; // +1m
int16 ymaxLocal = +200; // +2m high people
int16 zmaxLocal = +100; // +1m
SVECTOR bboxLocal[8];
bboxLocal[0].vx = xminLocal;
bboxLocal[0].vy = yminLocal;
bboxLocal[0].vz = zminLocal;
bboxLocal[1].vx = xminLocal;
bboxLocal[1].vy = yminLocal;
bboxLocal[1].vz = zmaxLocal;
bboxLocal[2].vx = xmaxLocal;
bboxLocal[2].vy = yminLocal;
bboxLocal[2].vz = zminLocal;
bboxLocal[3].vx = xmaxLocal;
bboxLocal[3].vy = yminLocal;
bboxLocal[3].vz = zmaxLocal;
bboxLocal[4].vx = xmaxLocal;
bboxLocal[4].vy = ymaxLocal;
bboxLocal[4].vz = zminLocal;
bboxLocal[5].vx = xmaxLocal;
bboxLocal[5].vy = ymaxLocal;
bboxLocal[5].vz = zmaxLocal;
bboxLocal[6].vx = xminLocal;
bboxLocal[6].vy = ymaxLocal;
bboxLocal[6].vz = zminLocal;
bboxLocal[7].vx = xminLocal;
bboxLocal[7].vy = ymaxLocal;
bboxLocal[7].vz = zmaxLocal;
SVECTOR *local = bboxLocal;
SVECTOR bboxScrn[8];
SVECTOR *scrn = bboxScrn;
int32 z0;
int32 p, flag;
int32 i;
// Set the local-screen matrix in the GTE
gte_SetRotMatrix(&ls);
gte_SetTransMatrix(&ls);
for (i = 0; i < 8; i++, local++, scrn++) {
gte_RotTransPers(local, (int32 *)&(scrn->vx), &p, &flag, &z0);
scrn->vz = (int16)z0;
}
// Find the minimum and maximum screen positions (plus z)
scrn = bboxScrn;
SVECTOR scrnMin, scrnMax;
copyVector(&scrnMin, scrn);
copyVector(&scrnMax, scrn);
scrn++;
for (i = 1; i < 8; i++, scrn++) {
if (scrn->vx < scrnMin.vx)
scrnMin.vx = scrn->vx;
if (scrn->vy < scrnMin.vy)
scrnMin.vy = scrn->vy;
if (scrn->vz < scrnMin.vz)
scrnMin.vz = scrn->vz;
if (scrn->vx > scrnMax.vx)
scrnMax.vx = scrn->vx;
if (scrn->vy > scrnMax.vy)
scrnMax.vy = scrn->vy;
if (scrn->vz > scrnMax.vz)
scrnMax.vz = scrn->vz;
}
// Reject the actor if the gross bounding box isn't on the screen yet
if ((scrnMin.vx > (SCREEN_W / 2)) || // min x off right of the screen
(scrnMin.vy > (SCREEN_H / 2)) || // min y off top of the screen
(scrnMax.vx < (-SCREEN_W / 2)) || // max x off left of the screen
(scrnMax.vy < (-SCREEN_H / 2)) || // max y off bottom of the screen
(scrnMax.vz < g_actor_hither_plane) || // max z infront of the hither plane
(scrnMin.vz > g_actor_far_clip_plane)) { // min z behind the max z plane
return 1;
}
return 0;
}
} // End of namespace ICB

38
engines/icb/actor.h Normal file
View File

@@ -0,0 +1,38 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_ACTOR_H
#define ICB_ACTOR_H
#include "engines/icb/gfx/psx_camera.h"
namespace ICB {
int32 QuickActorCull(psxCamera *camera, VECTOR *pos, SVECTOR *orient);
} // End of namespace ICB
#endif // #ifndef ACTOR_H

644
engines/icb/actor_fx_pc.cpp Normal file
View File

@@ -0,0 +1,644 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/debug.h"
#include "engines/icb/gfx/psx_pcdefines.h"
#include "engines/icb/actor_pc.h"
#include "engines/icb/gfx/psx_scrn.h"
#include "engines/icb/gfx/psx_poly.h"
#include "engines/icb/global_objects_psx.h"
#include "engines/icb/drawpoly_pc.h"
#include "engines/icb/icb.h"
#include "engines/icb/common/px_capri_maths.h"
namespace ICB {
void DrawMuzzleFlashPC(SVECTOR *mfpos, int32 mfh, int32 mfw);
void DrawCartridgeCasePC(SVECTOR *bulletOffset, int32 col);
void DrawBreathingPC(Breath *breath); // test function
#if _PSX_ON_PC == 1
extern int32 minX, maxX, minY, maxY, minZ, maxZ;
#else // #if _PSX_ON_PC == 1
int32 minX, maxX, minY, maxY, minZ, maxZ;
#endif // #if _PSX_ON_PC == 1
#define VERY_BRIGHT 9000
#define NOT_VERY_BRIGHT 3000
// draw the special effects
int32 DrawActorSpecialEffectsPC(int32 mflash, SVECTOR *mfpos, int32 mfh, int32 mfw, int32 bullet, SVECTOR *bulletPos, int32 bulletCol, Breath *breath, MATRIXPC *local2screen, int32 brightness,
SVECTOR *minBBox, SVECTOR *maxBBox) {
// Put the correct rot and trans matrix in place
// transform model from world space to screen space
gte_SetRotMatrix_pc(local2screen);
gte_SetTransMatrix_pc(local2screen);
minX = SCREEN_WIDTH / 2;
maxX = -SCREEN_WIDTH / 2;
minY = SCREEN_DEPTH / 2;
maxY = -SCREEN_DEPTH / 2;
minZ = 0x7fff;
maxZ = 0;
// Draw muzzle flash if need be
if (mflash) {
DrawMuzzleFlashPC(mfpos, mfh, mfw);
}
if (bullet) {
int32 b;
// get difference between actual brightness and the min level
b = brightness - NOT_VERY_BRIGHT;
// limit it, no point having negative, anything below min is clamped
if (b < 0)
b = 0;
// also limit at top range, anything above is clamped to full
else if (b > (VERY_BRIGHT - NOT_VERY_BRIGHT))
b = (VERY_BRIGHT - NOT_VERY_BRIGHT);
DrawCartridgeCasePC(bulletPos, bulletCol);
}
if ((breath) && (breath->on)) {
DrawBreathingPC(breath);
}
if ((minBBox) && (maxBBox)) {
minBBox->vx = (int16)minX;
minBBox->vy = (int16)minY;
minBBox->vz = (int16)minZ;
maxBBox->vx = (int16)maxX;
maxBBox->vy = (int16)maxY;
maxBBox->vz = (int16)maxZ;
}
if ((minX < maxX) && (minY < maxY))
return 1;
return 0;
}
#define CIRCLE_SEGMENTS 12
void DrawBreathParticlePC(short x, short y, int32 z, uint8 col, short w, short h, int32 *rands) {
int32 angle = 0;
int32 da = 4096 / CIRCLE_SEGMENTS;
int32 cx, cy;
int32 nx, ny;
int32 i;
TPOLY_G3 *poly;
#define getCircleX(ang) ((int32)(PXcos((float)ang / 4096.0f) * w))
#define getCircleY(ang) ((int32)(PXsin((float)ang / 4096.0f) * h))
// get top point
nx = (int32)getCircleX(angle);
ny = (int32)getCircleY(angle);
int32 randPointer = (x & 7); // 0-7
// for every other point
for (i = 0; i < CIRCLE_SEGMENTS; i++) {
cx = nx;
cy = ny;
angle = (angle + da) & 4095;
nx = (int32)(getCircleX(angle) + rands[randPointer]);
randPointer = (randPointer + 1) & 7;
ny = (int32)(getCircleY(angle) + rands[randPointer]);
randPointer = (randPointer + 1) & 7;
poly = (TPOLY_G3 *)drawpacket;
setTPolyG3(poly);
setTSemiTrans(poly, 1);
setTABRMode(poly, 1);
setXY3(poly, (int16)x, (int16)y, (int16)(cx + x), (int16)(cy + y), (int16)(nx + x), (int16)(ny + y));
setRGB0(poly, col, col, col);
setRGB1(poly, col, col, col);
setRGB2(poly, col, col, col);
myAddPacket(sizeof(TPOLY_G3));
myAddPrimClip(z, poly);
}
}
#define MAX_DRAW_BREATH 4
#define MAX_DRAW_SMOKE 8
// breathing test....
void DrawBreathingPC(Breath *breath) {
int32 i;
uint8 col;
// to get z value etc
SVECTORPC local;
// unused
SVECTORPC out;
int32 p, flag;
int32 z0;
int32 size;
int32 max;
// set maximum number of polys...
if (breath->on == BREATH_SMOKE)
max = MAX_DRAW_SMOKE;
else
max = MAX_DRAW_BREATH;
int32 rands[8];
for (i = 0; i < 8; i++)
rands[i] = g_icb->getRandomSource()->getRandomNumber(5 - 1) - 2;
// draw the polys
for (i = 0; i < max; i++) {
if ((int32)(breath->breathColour[i]) > 0) {
local.vx = breath->position.vx;
local.vy = (int16)(breath->position.vy + breath->breathY[i]);
local.vz = (int16)(breath->position.vz + breath->breathZ[i]);
gte_RotTransPers_pc(&local, &out, &p, &flag, &z0);
size = (128 * breath->breathSize[i]) / z0;
if (size) {
short x, y;
x = (int16)(out.vx);
y = (int16)(out.vy);
col = (uint8)(2 * breath->breathColour[i]);
short w, h;
w = (int16)((size * 3) >> 1);
h = (int16)size;
DrawBreathParticlePC(x, y, z0, col, w, h, rands);
// check bounding box...
if (x < minX)
minX = x;
if (y < minY)
minY = y;
if (x + w > maxX)
maxX = (int16)(x + w);
if (y + h > maxY)
maxY = (int16)(y + h);
if (z0 < minZ)
minZ = (int16)z0;
if (z0 > maxZ)
maxZ = (int16)z0;
}
}
}
}
// number of points (8 for cube) and number of faces (6 for cube)...
#define BULLET_POINTS 8
#define BULLET_QUADS 6
// dimensions of bullet
#define BULLET_LENGTH 4
#define BULLET_RADIUS 1
// 8 points on cubic shape, length by 2*radius (width) by 2*radius (height)...
const short bulletOffsets[BULLET_POINTS][3] = {{-BULLET_RADIUS, BULLET_RADIUS, 0},
{BULLET_RADIUS, BULLET_RADIUS, 0},
{BULLET_RADIUS, -BULLET_RADIUS, 0},
{-BULLET_RADIUS, -BULLET_RADIUS, 0},
{-BULLET_RADIUS, BULLET_RADIUS, BULLET_LENGTH},
{BULLET_RADIUS, BULLET_RADIUS, BULLET_LENGTH},
{BULLET_RADIUS, -BULLET_RADIUS, BULLET_LENGTH},
{-BULLET_RADIUS, -BULLET_RADIUS, BULLET_LENGTH}};
// 6 sides for cube....
const int32 bulletQuads[BULLET_QUADS][4] = {{1, 0, 2, 3}, {0, 1, 4, 5}, {1, 2, 5, 6}, {2, 3, 6, 7}, {3, 0, 7, 4}, {4, 5, 7, 6}};
#define BULLET_RED_1 255
#define BULLET_GREEN_1 255
#define BULLET_BLUE_1 255
#define BULLET_RED_2 100
#define BULLET_GREEN_2 100
#define BULLET_BLUE_2 100
void DrawCartridgeCasePC(SVECTOR *bulletOffset, int32 col) {
SVECTORPC sxy[BULLET_POINTS];
int32 p, flag, z = 0;
SVECTORPC pos;
int32 i;
for (i = 0; i < BULLET_POINTS; i++) {
pos.vx = (int16)(bulletOffset->vx + bulletOffsets[i][0]);
pos.vy = (int16)(bulletOffset->vy + bulletOffsets[i][1]);
pos.vz = (int16)(bulletOffset->vz + bulletOffsets[i][2]);
gte_RotTransPers_pc(&pos, &sxy[i], &p, &flag, &z);
}
// draw polygon...
for (i = 0; i < BULLET_QUADS; i++) {
POLY_G4 *poly;
poly = (POLY_G4 *)drawpacket;
setPolyG4(poly);
poly->x0 = sxy[bulletQuads[i][0]].vx;
poly->y0 = sxy[bulletQuads[i][0]].vy;
poly->x1 = sxy[bulletQuads[i][1]].vx;
poly->y1 = sxy[bulletQuads[i][1]].vy;
poly->x2 = sxy[bulletQuads[i][2]].vx;
poly->y2 = sxy[bulletQuads[i][2]].vy;
poly->x3 = sxy[bulletQuads[i][3]].vx;
poly->y3 = sxy[bulletQuads[i][3]].vy;
// check bounding box...
// minX
if (poly->x0 < minX)
minX = poly->x0;
if (poly->x1 < minX)
minX = poly->x1;
if (poly->x2 < minX)
minX = poly->x2;
if (poly->x3 < minX)
minX = poly->x3;
// minY
if (poly->y0 < minY)
minY = poly->y0;
if (poly->y1 < minY)
minY = poly->y1;
if (poly->y2 < minY)
minY = poly->y2;
if (poly->y3 < minY)
minY = poly->y3;
// minX
if (poly->x0 > maxX)
maxX = poly->x0;
if (poly->x1 > maxX)
maxX = poly->x1;
if (poly->x2 > maxX)
maxX = poly->x2;
if (poly->x3 > maxX)
maxX = poly->x3;
// minY
if (poly->y0 > maxY)
maxY = poly->y0;
if (poly->y1 > maxY)
maxY = poly->y1;
if (poly->y2 > maxY)
maxY = poly->y2;
if (poly->y3 > maxY)
maxY = poly->y3;
// z
if (z < minZ)
minZ = (int16)z;
if (z > maxZ)
maxZ = (int16)z;
// set colours (remember dark at back and light at front
if (bulletQuads[i][0] < 4)
setRGB0(poly, (uint8)((col * BULLET_RED_1) / 256), (uint8)((col * BULLET_GREEN_1) / 256), (uint8)((col * BULLET_BLUE_1) / 256));
else
setRGB0(poly, (uint8)((col * BULLET_RED_2) / 256), (uint8)((col * BULLET_GREEN_2) / 256), (uint8)((col * BULLET_BLUE_2) / 256));
if (bulletQuads[i][1] < 4)
setRGB1(poly, (uint8)((col * BULLET_RED_1) / 256), (uint8)((col * BULLET_GREEN_1) / 256), (uint8)((col * BULLET_BLUE_1) / 256));
else
setRGB1(poly, (uint8)((col * BULLET_RED_2) / 256), (uint8)((col * BULLET_GREEN_2) / 256), (uint8)((col * BULLET_BLUE_2) / 256));
if (bulletQuads[i][2] < 4)
setRGB2(poly, (uint8)((col * BULLET_RED_1) / 256), (uint8)((col * BULLET_GREEN_1) / 256), (uint8)((col * BULLET_BLUE_1) / 256));
else
setRGB2(poly, (uint8)((col * BULLET_RED_2) / 256), (uint8)((col * BULLET_GREEN_2) / 256), (uint8)((col * BULLET_BLUE_2) / 256));
if (bulletQuads[i][3] < 4)
setRGB3(poly, (uint8)((col * BULLET_RED_1) / 256), (uint8)((col * BULLET_GREEN_1) / 256), (uint8)((col * BULLET_BLUE_1) / 256));
else
setRGB3(poly, (uint8)((col * BULLET_RED_2) / 256), (uint8)((col * BULLET_GREEN_2) / 256), (uint8)((col * BULLET_BLUE_2) / 256));
// draw it
myAddPrimClip(z, poly);
myAddPacket(sizeof(POLY_G4));
}
}
#define MUZZLE_COLOUR_0 0x201008
#define MUZZLE_COLOUR_1 0xc08020
#define setRGB0Colour(prim, col) setRGB0(prim, (col >> 16) & 255, (col >> 8) & 255, col & 255)
#define setRGB1Colour(prim, col) setRGB1(prim, (col >> 16) & 255, (col >> 8) & 255, col & 255)
#define setRGB2Colour(prim, col) setRGB2(prim, (col >> 16) & 255, (col >> 8) & 255, col & 255)
void DrawMuzzleFlashPC(SVECTOR *mfpos, int32 mfh, int32 mfw) {
// X left of character
// Y upwards
// Z forwards
int32 h = mfh;
int32 w = mfw;
int32 mz = 20;
int32 p, flag, z;
SVECTORPC origin;
SVECTORPC points[18];
SVECTORPC sxy0;
int32 z0;
SVECTORPC spoints[18];
int32 i;
// The centre point
short mfx = mfpos->vx;
short mfy = mfpos->vy;
short mfz = mfpos->vz;
origin.vx = mfx;
origin.vy = mfy;
origin.vz = mfz;
gte_RotTransPers_pc(&origin, &sxy0, &p, &flag, &z0);
i = 0;
// slightly out... (OUT MORE FOR TRIS)
points[i].vx = (int16)(mfx + 0);
points[i].vy = (int16)(mfy + w);
points[i].vz = (int16)(mfz + 2 * mz);
// far...
i++;
points[i].vx = (int16)(mfx + 0);
points[i].vy = (int16)(mfy + 0);
points[i].vz = (int16)(mfz + 2 * mz);
// slightly out... (OUT MORE FOR TRIS)
i++;
points[i].vx = (int16)(mfx + 0);
points[i].vy = (int16)(mfy - w);
points[i].vz = (int16)(mfz + 2 * mz);
// slightly out... (OUT MORE FOR TRIS)
i++;
points[i].vx = (int16)(mfx + w);
points[i].vy = (int16)(mfy + 0);
points[i].vz = (int16)(mfz + 2 * mz);
// far...
i++;
points[i].vx = (int16)(mfx + 0);
points[i].vy = (int16)(mfy + 0);
points[i].vz = (int16)(mfz + 2 * mz);
// slightly out... (OUT MORE FOR TRIS)
i++;
points[i].vx = (int16)(mfx - w);
points[i].vy = (int16)(mfy + 0);
points[i].vz = (int16)(mfz + 2 * mz);
// The top-left corner
i++;
points[i].vx = (int16)(mfx - w);
points[i].vy = (int16)(mfy + h);
points[i].vz = (int16)(mfz + mz);
// The top-middle corner
i++;
points[i].vx = (int16)(mfx + 0);
points[i].vy = (int16)(mfy + h + w);
points[i].vz = (int16)(mfz + mz);
// The top-right corner
i++;
points[i].vx = (int16)(mfx + w);
points[i].vy = (int16)(mfy + h);
points[i].vz = (int16)(mfz + mz);
// The left-bottom corner
i++;
points[i].vx = (int16)(mfx - h);
points[i].vy = (int16)(mfy - w);
points[i].vz = (int16)(mfz + mz);
// The left-middle corner
i++;
points[i].vx = (int16)(mfx - h - w);
points[i].vy = (int16)(mfy + 0);
points[i].vz = (int16)(mfz + mz);
// The left-top corner
i++;
points[i].vx = (int16)(mfx - h);
points[i].vy = (int16)(mfy + w);
points[i].vz = (int16)(mfz + mz);
// The bottom-left corner
i++;
points[i].vx = (int16)(mfx - w);
points[i].vy = (int16)(mfy - h);
points[i].vz = (int16)(mfz + mz);
// The bottom-middle corner
i++;
points[i].vx = (int16)(mfx + 0);
points[i].vy = (int16)(mfy - h - w);
points[i].vz = (int16)(mfz + mz);
// The bottom-right corner
i++;
points[i].vx = (int16)(mfx + w);
points[i].vy = (int16)(mfy - h);
points[i].vz = (int16)(mfz + mz);
// The right-top corner
i++;
points[i].vx = (int16)(mfx + h);
points[i].vy = (int16)(mfy + w);
points[i].vz = (int16)(mfz + mz);
// The right-middle corner
i++;
points[i].vx = (int16)(mfx + h + w);
points[i].vy = (int16)(mfy - 0);
points[i].vz = (int16)(mfz + mz);
// The right-bottom corner
i++;
points[i].vx = (int16)(mfx + h);
points[i].vy = (int16)(mfy - w);
points[i].vz = (int16)(mfz + mz);
SVECTORPC *ppoints = points;
SVECTORPC *pspoints = spoints;
for (i = 0; i < 18; i++) {
gte_RotTransPers_pc(ppoints, pspoints, &p, &flag, &z);
ppoints++;
pspoints++;
}
TPOLY_G3 *poly;
// Draw the four polygons
int32 j = 0;
for (i = 0; i < 6; i++) {
poly = (TPOLY_G3 *)drawpacket;
setTPolyG3(poly);
setTABRMode(poly, 1);
setTSemiTrans(poly, 1);
SVECTORPC sxy1 = spoints[j];
SVECTORPC sxy2 = spoints[j + 1];
SVECTORPC sxy3 = spoints[j + 2];
j += 3;
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
setRGB0Colour(poly, MUZZLE_COLOUR_1);
gte_NormalClip_pc(&sxy1, &sxy2, &sxy0, &flag);
// Back facing
if (flag < 0) {
poly->x1 = sxy3.vx;
poly->y1 = sxy3.vy;
poly->x2 = sxy1.vx;
poly->y2 = sxy1.vy;
// *(int32*)&(poly->x3) = sxy3;
setRGB1Colour(poly, MUZZLE_COLOUR_0);
setRGB2Colour(poly, MUZZLE_COLOUR_0);
} else {
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy3.vx;
poly->y2 = sxy3.vy;
// *(int32*)&(poly->x3) = sxy3;
setRGB1Colour(poly, MUZZLE_COLOUR_0);
setRGB2Colour(poly, MUZZLE_COLOUR_0);
}
// check bounding box...
// minX
if (poly->x0 < minX)
minX = poly->x0;
if (poly->x1 < minX)
minX = poly->x1;
if (poly->x2 < minX)
minX = poly->x2;
// minY
if (poly->y0 < minY)
minY = poly->y0;
if (poly->y1 < minY)
minY = poly->y1;
if (poly->y2 < minY)
minY = poly->y2;
// minX
if (poly->x0 > maxX)
maxX = poly->x0;
if (poly->x1 > maxX)
maxX = poly->x1;
if (poly->x2 > maxX)
maxX = poly->x2;
// minY
if (poly->y0 > maxY)
maxY = poly->y0;
if (poly->y1 > maxY)
maxY = poly->y1;
if (poly->y2 > maxY)
maxY = poly->y2;
// z
if (z0 < minZ)
minZ = (int16)z0;
if (z0 > maxZ)
maxZ = (int16)z0;
// draw it
myAddPrimClip(z0, poly);
myAddPacket(sizeof(TPOLY_G3));
}
}
} // End of namespace ICB

1009
engines/icb/actor_pc.cpp Normal file

File diff suppressed because it is too large Load Diff

59
engines/icb/actor_pc.h Normal file
View File

@@ -0,0 +1,59 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_ACTOR_PC_H
#define ICB_ACTOR_PC_H
#include "engines/icb/gfx/psx_pcdefines.h"
#include "engines/icb/gfx/psx_pcgpu.h"
#include "engines/icb/light_pc.h"
#include "engines/icb/gfx/psx_camera.h"
#include "engines/icb/gfx/psx_pxactor.h"
#include "engines/icb/gfx/psx_tman.h"
#include "engines/icb/gfx/rap_api.h"
#include "engines/icb/gfx/rab_api.h"
#include "engines/icb/gfx/rlp_api.h"
#include "engines/icb/common/px_bones.h"
#include "engines/icb/breath.h"
namespace ICB {
void ConvertToScreenCoords(SVECTORPC *local, SVECTORPC *screen, int32 nVertices);
void ConvertToScreenCoords(SVECTOR *local, SVECTOR *screen, int32 nVertices);
void DrawActor4PC(psxActor *actor, psxCamera *camera, Bone_Frame *frame, RapAPI *mesh, RapAPI *pose, RapAPI *smesh, PSXrgb *ambient, PSXLampList *lamplist,
PSXShadeList *shadelist, int32 nShadows, SVECTORPC *p_n, int32 *p_d, uint32 debug, int32 uvframe, BoneDeformation **boneDeforms, int32 *brightness,
MATRIXPC *local2screen);
void DrawActorTiePC(psxCamera *camera, SVECTORPC *pos, uint32 size, CVECTOR *colour);
// return 1 if something drawn, else return 0
int32 DrawActorSpecialEffectsPC(int32 mflash, SVECTOR *mfpos, int32 mfh, int32 mfw, int32 bullet, SVECTOR *bulletPos, int32 bulletCol, Breath *breath, MATRIXPC *local2screen, int32 brightness,
SVECTOR *minBBox, SVECTOR *maxBBox);
} // End of namespace ICB
#endif // #ifndef ACTOR_PC_H

View File

@@ -0,0 +1,686 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/p4.h"
#include "engines/icb/p4_generic.h"
#include "engines/icb/debug.h"
#include "engines/icb/mission.h"
#include "engines/icb/direct_input.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/global_objects_psx.h"
#include "engines/icb/p4.h"
#include "engines/icb/actor.h"
#include "engines/icb/actor_pc.h"
#include "engines/icb/drawpoly_pc.h"
#include "engines/icb/common/px_capri_maths.h"
#include "engines/icb/gfx/gfxstub.h"
#include "engines/icb/gfx/gfxstub_dutch.h"
#include "engines/icb/gfx/gfxstub_rev_dutch.h"
#include "engines/icb/actor_view_pc.h"
#include "engines/icb/res_man.h"
#include "common/keyboard.h"
namespace ICB {
// Cute little puppies
extern char *pRGB;
extern char *pZa;
extern int32 RGBWidth;
extern int32 RGBHeight;
extern int32 RGBPitch;
extern int32 RGBBytesPerPixel;
RevRenderDevice renderingDevice;
extern int32 texturesUsedThisCycle;
// This controls autoanimation (0 = None, 1 = Backward, 2 = Forward)
uint32 auto_anim = 2;
// Camera and animation structures
PXanim *pxanim;
SVECTOR rot; // Actor rotation
SVECTOR _crot; // Camera rotation
int32 uvframe = 0;
// Global filename stuff
char cluster_name[32];
uint32 cluster_name_hash;
char raj_name[128];
uint32 raj_name_hash;
// Pointers to useful strings for the current actor
char *character_name;
char *anim_name;
const char *weapon_name;
char *outfit_name;
int32 framenum;
int32 g_repeats;
// Do we allow keyboard input to affect the actor viewing
bool8 g_av_userControlled = FALSE8;
// Lighting structure and coordinates, colour components
int16 av_LightX;
int16 av_LightY;
int16 av_LightZ;
int32 av_LightR;
int32 av_LightG;
int32 av_LightB;
int32 av_LightA;
bool8 av_LightDir;
bool8 av_autoR;
bool8 av_autoG;
bool8 av_autoB;
// Render coordinates
int16 av_x, av_y, av_z;
// Prototypes for functions used in this module
TextureHandle *GetRegisteredTexture(const char *, uint32, const char *, uint32, const char *, uint32);
void DrawFrame(const int32 frame);
void MakeCameraView();
void ResetCamera();
void ResetActor();
void InitLight();
void SetLight(int32 falloff);
void AutoCycleLight();
#define LIGHT_DISTANCE_FROM_ACTOR 100
#define LIGHT_HEIGHT_LIMIT 200
void InitActorView(const char *name, const char *outfit, const char *weapon, const char *anim, int16 ix, int16 iy, int16 iz) {
// Store initial offset coordinates
av_x = ix;
av_y = iy;
av_z = iz;
// Make hash filename of the character
char h_character[8];
HashFile(name, h_character);
// Make hash filename of the outfit
char h_outfit[8];
HashFile(outfit, h_outfit);
// Make the cluster name
Common::sprintf_s(cluster_name, "\\C\\%s\\%s.OFT", h_character, h_outfit);
// Hash value for this cluster name
cluster_name_hash = NULL_HASH;
ResetCamera();
ResetActor();
raj_name_hash = NULL_HASH;
Common::sprintf_s(raj_name, "%s\\%s.raj", weapon, anim);
anim_name = const_cast<char *>(anim);
weapon_name = const_cast<char *>(weapon);
outfit_name = const_cast<char *>(outfit);
character_name = const_cast<char *>(name);
// Animate the shape from frame to frame, looping
framenum = 0;
g_repeats = 0;
auto_anim = 2;
// Initialise a light to use
InitLight();
// Start the psx poly drawing ganky bit
InitDrawing();
// Load and select the appropriate texture
char texture_name[128];
uint32 texture_name_hash = NULL_HASH;
Common::sprintf_s(texture_name, "material.revtex");
TextureHandle *texHan = GetRegisteredTexture(texture_name, texture_name_hash, texture_name, texture_name_hash, cluster_name, cluster_name_hash);
ChooseTexture(texHan);
}
void ChangeAnimPlaying(const char *pose, const char *anim, bool8 forwards, int32 repeats, int16 ix, int16 iy, int16 iz) {
// Set pose
if (pose) {
// New pose
weapon_name = const_cast<char *>(pose);
} else {
// Default is unarmed
weapon_name = "unarmed";
}
// Require anim parameter
if (anim == nullptr)
Fatal_error("ChangeAnimPlaying() cannot set active animation to NULL!");
// Remake raj filename
raj_name_hash = NULL_HASH;
Common::sprintf_s(raj_name, "%s\\%s.raj", weapon_name, anim);
// Change animation to use
anim_name = const_cast<char *>(anim);
// Set direction to run the anim
if (forwards)
auto_anim = 2;
else
auto_anim = 1;
pxanim = (PXanim *)rs_anims->Res_open(raj_name, raj_name_hash, cluster_name, cluster_name_hash);
// Set to the starting frame of this anim
if (forwards)
framenum = 0;
else
framenum = pxanim->frame_qty - 2;
g_repeats = repeats;
// Store initial offset coordinates
av_x = ix;
av_y = iy;
av_z = iz;
ResetCamera();
}
int32 ActorViewDraw() {
// Return value
int32 returnStatus = MID_ANIMATION;
// Alters the light nicely
AutoCycleLight();
// Call this each cycle to update our light
SetLight(500);
// This does most of the work
DrawFrame(framenum);
// This code acts upon user input to alter the actor's rotation and anim frame
// from the initialised defaults.
if (g_av_userControlled) {
// Increment in degrees
int32 dang = 5;
// Actor rotation
if (Read_DI_keys(Common::KEYCODE_LEFT)) {
rot.vy = (int16)(rot.vy + 4096 * dang / 360);
}
if (Read_DI_keys(Common::KEYCODE_DOWN)) {
rot.vy = (int16)(rot.vy - 4096 * dang / 360);
}
if (Read_DI_keys(Common::KEYCODE_UP)) {
rot.vx = (int16)(rot.vx + 4096 * dang / 360);
}
if (Read_DI_keys(Common::KEYCODE_DOWN)) {
rot.vx = (int16)(rot.vx - 4096 * dang / 360);
}
if (Read_DI_keys(Common::KEYCODE_PAGEUP)) {
rot.vz = (int16)(rot.vz + 4096 * dang / 360);
}
if (Read_DI_keys(Common::KEYCODE_PAGEDOWN)) {
rot.vz = (int16)(rot.vz - 4096 * dang / 360);
}
if (rot.vx > 4096)
rot.vx -= 4096;
if (rot.vy > 4096)
rot.vy -= 4096;
if (rot.vz > 4096)
rot.vz -= 4096;
if (rot.vx < -4096)
rot.vx += 4096;
if (rot.vy < -4096)
rot.vy += 4096;
if (rot.vz < -4096)
rot.vz += 4096;
// Set animation playing forwards
if (Read_DI_keys(Common::KEYCODE_1)) {
auto_anim = 2;
}
// Set animation playing backwards
if (Read_DI_keys(Common::KEYCODE_2)) {
auto_anim = 1;
}
// Previous frame
if (Read_DI_once_keys(Common::KEYCODE_MINUS)) {
auto_anim = 0;
framenum--;
}
// Next frame
if (Read_DI_once_keys(Common::KEYCODE_EQUALS)) {
auto_anim = 0;
framenum++;
}
}
// Auto animating backward
if (auto_anim == 1) {
framenum--;
}
// Auto forwards
else if (auto_anim) {
framenum++;
}
// Catch the loop for doing -1 in unsigned decimal
if (framenum > pxanim->frame_qty)
framenum = pxanim->frame_qty - 2;
if (framenum < 0) {
if (g_repeats > 0) {
g_repeats--;
} else {
if (auto_anim == 1)
returnStatus = ANIMATION_END;
}
framenum = pxanim->frame_qty - 2;
}
// Catch the loop for going past end of the animation
if (framenum > (pxanim->frame_qty - 2)) {
if (g_repeats > 0) {
g_repeats--;
} else {
if (auto_anim == 2)
returnStatus = ANIMATION_END;
}
framenum = 0;
}
// Catch illegal animations
if (framenum < 0)
framenum = 0;
// Draw the display list
drawOTList();
// Now copy the sucker to the screen
uint32 *address = (uint32 *)surface_manager->Lock_surface(working_buffer_id);
uint32 pitch = surface_manager->Get_pitch(working_buffer_id);
uint32 *source = (uint32 *)pRGB;
uint16 *zActor = (uint16 *)pZa;
uint32 *safe_ad = address;
for (int32 y = SCREEN_DEPTH; y; y--) {
uint32 *ad = safe_ad;
for (int32 x = SCREEN_WIDTH; x; x--) {
// If the z-map for this pixel is FFFF then this pixel doesn't contain actor
if (*zActor != 0xFFFF) {
*ad = *source;
*zActor = 0xFFFF;
}
++zActor;
++ad;
++source;
}
safe_ad += pitch / 4;
}
// Unlock the surface
surface_manager->Unlock_surface(working_buffer_id);
return returnStatus;
}
void DrawFrame(const int32 frame) {
// These structures are needed for the drawing code to accept our light
PSXLampList the_lights;
PSXShadeList the_shades;
the_lights.n = 1;
the_lights.states[0] = 0;
the_lights.lamps[0] = g_av_Light;
the_shades.n = 0;
// Open the animation file
char bone_name[128];
char pose_name[128];
char mesh_name[128];
char smesh_name[128];
PSXrgb ambient;
ambient.r = 128;
ambient.g = 128;
ambient.b = 128;
pxanim = (PXanim *)rs_anims->Res_open(raj_name, raj_name_hash, cluster_name, cluster_name_hash);
PXFrameEnOfAnim(framenum, pxanim);
// Make the actors orientation matrix
g_av_actor->rot = rot;
g_av_actor->rot.vy = (int16)(g_av_actor->rot.vy);
// Make the root local-world matrix
RotMatrix_gte(&g_av_actor->rot, &g_av_actor->lw);
// Need to use marker to get correct actor height (making crouch look correct)
PXframe *frm = PXFrameEnOfAnim(framenum, pxanim);
PXmarker &marker = frm->markers[ORG_POS];
float mposx, mposy, mposz;
PXmarker_PSX_Object::GetXYZ(&marker, &mposx, &mposy, &mposz);
int32 dy = (int32)mposy;
g_av_actor->lw.t[0] = 0;
g_av_actor->lw.t[1] = dy - 112;
g_av_actor->lw.t[2] = 0;
// Set the true rotation & position values from the ORG marker
g_av_actor->truePos.x = 0;
g_av_actor->truePos.y = dy - 112;
g_av_actor->truePos.z = 0;
g_av_actor->trueRot = g_av_actor->rot;
Common::sprintf_s(pose_name, "%s\\pose.rap", weapon_name);
Common::sprintf_s(bone_name, "%s\\%s.rab", weapon_name, anim_name);
Common::sprintf_s(mesh_name, "mesh.rap");
Common::sprintf_s(smesh_name, "mesh_shadow.rap");
uint32 mesh_hash = HashString(mesh_name);
RapAPI *mesh = (RapAPI *)rs_anims->Res_open(mesh_name, mesh_hash, cluster_name, cluster_name_hash);
uint32 smesh_hash = HashString(smesh_name);
RapAPI *smesh = (RapAPI *)rs_anims->Res_open(smesh_name, smesh_hash, cluster_name, cluster_name_hash);
uint32 pose_hash = HashString(pose_name);
RapAPI *pose = (RapAPI *)rs_anims->Res_open(pose_name, pose_hash, cluster_name, cluster_name_hash);
uint32 bone_hash = HashString(bone_name);
RabAPI *rab = (RabAPI *)rs_anims->Res_open(bone_name, bone_hash, cluster_name, cluster_name_hash);
ConvertRAP(pose);
ConvertRAP(smesh);
ConvertRAP(mesh);
// Some error checking
if (READ_LE_INT32((int32 *)mesh->id) != *(int32 *)const_cast<char *>(RAP_API_ID)) {
Fatal_error("Wrong rap id value file %d api %d file:%s", mesh->id, RAP_API_ID, mesh_name);
}
if (FROM_LE_32(mesh->schema) != RAP_API_SCHEMA) {
Fatal_error("Wrong rap schema value file %d rap_api %d file:%s", mesh->schema, RAP_API_SCHEMA, mesh_name);
}
if (READ_LE_INT32((int32 *)pose->id) != *(int32 *)const_cast<char *>(RAP_API_ID)) {
Fatal_error("Wrong rap id value file %d api %d file:%s", pose->id, RAP_API_ID, pose_name);
}
if (FROM_LE_32(pose->schema) != RAP_API_SCHEMA) {
Fatal_error("Wrong rap schema value file %d rap_api %d file:%s", pose->schema, RAP_API_SCHEMA, pose_name);
}
if (READ_LE_INT32((int32 *)rab->id) != *(int32 *)const_cast<char *>(RAB_API_ID)) {
Fatal_error("Wrong rab id value file %d rab_api %d file:%s", rab->id, RAB_API_ID, bone_name);
}
if (FROM_LE_32(rab->schema) != RAB_API_SCHEMA) {
Fatal_error("Wrong rab schema value file %d rab_api %d file:%s", rab->schema, RAB_API_SCHEMA, bone_name);
}
if (FROM_LE_16(mesh->nBones) != rab->nBones) {
Fatal_error("mesh nBones != animation nBones %d != %d", mesh->nBones, rab->nBones);
}
// Pass in the linkage file and the bones file
Bone_Frame *bone_frame = RabAPIObject::GetFrame(rab, frame);
int32 brightness;
int32 debug = 1;
BoneDeformation *myBones[MAX_DEFORMABLE_BONES];
for (int32 i = 0; i < MAX_DEFORMABLE_BONES; i++) {
myBones[i] = nullptr;
}
// Shadow stuff to play with
int32 nShadows = 0;
SVECTORPC p_n[3];
int32 p_d[3];
p_n[0].vx = 0;
p_n[0].vy = -1;
p_n[0].vz = 0;
p_d[0] = -118;
MATRIXPC local2screen; // not really bothered about this...
// Drawing finally
DrawActor4PC(g_av_actor, g_camera, bone_frame, mesh, pose, smesh, &ambient, &the_lights, &the_shades, nShadows, p_n, p_d, debug, uvframe, myBones, &brightness,
&local2screen);
uvframe++;
}
void MakeCameraView() {
RotMatrix_gte(&_crot, &g_camera->view);
// Include the x,y,z scalings
g_camera->view.m[0][0] = (int16)(g_camera->view.m[0][0] * 1);
g_camera->view.m[0][1] = (int16)(g_camera->view.m[0][1] * 1);
g_camera->view.m[0][2] = (int16)(g_camera->view.m[0][2] * 1);
g_camera->view.m[1][0] = (int16)(g_camera->view.m[1][0] * 1);
g_camera->view.m[1][1] = (int16)(g_camera->view.m[1][1] * 1);
g_camera->view.m[1][2] = (int16)(g_camera->view.m[1][2] * 1);
g_camera->view.m[2][0] = (int16)(g_camera->view.m[2][0] * 4);
g_camera->view.m[2][1] = (int16)(g_camera->view.m[2][1] * 4);
g_camera->view.m[2][2] = (int16)(g_camera->view.m[2][2] * 4);
}
void ResetCamera() {
_crot.vx = (4096 * 180) / 360;
_crot.vy = (4096 * -30) / 360;
_crot.vz = 0;
g_camera->view.t[0] = 170 + av_x;
g_camera->view.t[1] = 0 + av_y;
g_camera->view.t[2] = 1800 + av_z;
g_camera->focLen = 619 * 4;
MakeCameraView();
}
void ResetActor() {
// Set up av_actor rotation
rot.vx = 0;
rot.vy = 0;
rot.vz = 0;
}
void InitLight() {
g_av_Light->nStates = 1; // One state
g_av_Light->w = 0; // Zero width
g_av_Light->b = 0; // Zero bounce
g_av_Light->anu = 0; // Don't use it
g_av_Light->type = OMNI_LIGHT; // OMNI
g_av_Light->ba = 0; // Means nothing for an OMNI
g_av_Light->bs = 0; // Means nothing for an OMNI
// Don't think these things are used...
g_av_Light->states[0].ans2 = 0;
g_av_Light->states[0].ane2 = (100 * 1) * (100 * 1);
// No shade...
g_av_Light->states[0].m = 128;
// Direction doesn't matter; it's an OMNI light
g_av_Light->states[0].vx = 4096; // Ignored for an OMNI light
g_av_Light->states[0].vy = 0; // Ignored for an OMNI light
g_av_Light->states[0].vz = 0; // Ignored for an OMNI light
// Initial angle
av_LightA = 0;
av_LightDir = TRUE8;
// Initial position
av_LightX = 0;
av_LightY = 0;
av_LightZ = LIGHT_DISTANCE_FROM_ACTOR;
// Initial colour (RED)
av_LightR = 255;
av_LightG = 0;
av_LightB = 0;
// Auto flags
av_autoR = FALSE8;
av_autoG = FALSE8;
av_autoB = FALSE8;
}
void AutoCycleLight() {
// Increase angle by 10 degrees
av_LightA += 10;
if (av_LightA >= 360)
av_LightA = 0;
// Convert to radians
double radians = (av_LightA * M_PI) / 180.0f;
// Now calculate z and x coordinates from this angle
av_LightX = (int16)(sin(radians) * LIGHT_DISTANCE_FROM_ACTOR);
av_LightZ = (int16)(cos(radians) * LIGHT_DISTANCE_FROM_ACTOR);
// Now bouce the light height between two fixed limits
if (av_LightDir) {
av_LightY = (int16)(av_LightY + 10);
if (av_LightY > LIGHT_HEIGHT_LIMIT) {
av_LightY = LIGHT_HEIGHT_LIMIT;
av_LightDir = FALSE8;
}
} else {
av_LightY = (int16)(av_LightY - 10);
if (av_LightY < -LIGHT_HEIGHT_LIMIT) {
av_LightY = -LIGHT_HEIGHT_LIMIT;
av_LightDir = TRUE8;
}
}
// Red component
if (av_autoR) {
av_LightR += 3;
if (av_LightR > 255) {
av_LightR = 255;
av_autoR = FALSE8;
}
} else {
av_LightR -= 2;
if (av_LightR < 0) {
av_LightR = 0;
av_autoR = TRUE8;
}
}
// Green component
if (av_autoG) {
av_LightG += 2;
if (av_LightG > 255) {
av_LightG = 255;
av_autoG = FALSE8;
}
} else {
av_LightG -= 3;
if (av_LightG < 0) {
av_LightG = 0;
av_autoG = TRUE8;
}
}
// Blue component
if (av_autoB) {
av_LightB += 7;
if (av_LightB > 255) {
av_LightB = 255;
av_autoB = FALSE8;
}
} else {
av_LightB -= 5;
if (av_LightB < 0) {
av_LightB = 0;
av_autoB = TRUE8;
}
}
}
void SetLight(int32 falloff) {
// Check colours are 0-255
if ((av_LightR > 255) || (av_LightR < 0) || (av_LightG > 255) || (av_LightG < 0) || (av_LightB > 255) || (av_LightB < 0))
Fatal_error("ActorView light rgb %d,%d,%d out of range (0-255)", av_LightR, av_LightG, av_LightB);
// Set colours (scale 0-255 to 0-4095)
g_av_Light->states[0].c.r = (int16)((av_LightR * 4096) / 256);
g_av_Light->states[0].c.g = (int16)((av_LightG * 4096) / 256);
g_av_Light->states[0].c.b = (int16)((av_LightB * 4096) / 256);
// Set the v field of colour to be the maximum of r,g,b
g_av_Light->states[0].c.v = g_av_Light->states[0].c.r; // Start at red
if (g_av_Light->states[0].c.g > g_av_Light->states[0].c.v) // If green bigger
g_av_Light->states[0].c.v = g_av_Light->states[0].c.g; // Set to green
if (g_av_Light->states[0].c.b > g_av_Light->states[0].c.v) // If blue bigger
g_av_Light->states[0].c.v = g_av_Light->states[0].c.b; // Set to blue
g_av_Light->states[0].pos.vx = (int32)av_LightX;
g_av_Light->states[0].pos.vy = (int32)av_LightY;
g_av_Light->states[0].pos.vz = (int32)av_LightZ;
// And add the players position
g_av_Light->states[0].pos.vx += (int32)g_av_actor->truePos.x;
g_av_Light->states[0].pos.vy += (int32)g_av_actor->truePos.y;
g_av_Light->states[0].pos.vz += (int32)g_av_actor->truePos.z;
// Falloff
if (falloff == 0) {
g_av_Light->afu = 0; // Don't use it
} else {
g_av_Light->states[0].afs2 = (falloff * falloff) / 100; // (d/10)^2 = (d*d)/100
g_av_Light->states[0].afe2 = falloff * falloff; // d^2 = (d*d)
g_av_Light->afu = 1; // Use it
}
}
int32 my_sprintf(char *buf, const char *format...) {
char lbuf[256];
// Process the variable arguments
va_list arglist;
va_start(arglist, format);
int32 slen = vsnprintf(lbuf, 256, const_cast<char *>(format), arglist);
strncpy(buf, lbuf, slen);
buf[slen] = '\0';
va_end(arglist);
return slen;
}
} // End of namespace ICB

View File

@@ -0,0 +1,59 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_ACTOR_VIEW_PC_H_INCLUDED
#define ICB_ACTOR_VIEW_PC_H_INCLUDED
namespace ICB {
// Set this to true if the actor view (character profiles) should act as voxview
extern bool8 g_av_userControlled;
// Return values for ActorViewDraw
#define MID_ANIMATION 0x00
#define ANIMATION_END 0x01
void InitActorView(const char *name, // Character to draw (ie "cord")
const char *outfit, // Characters outfit (ie "casual_wear")
const char *weapon, // Character pose (ie "unarmed")
const char *anim, // Character anim (ie "walk")
int16 ix, // Initial render x coord
int16 iy, // Initial render y coord
int16 iz); // Initial render z coord
int32 ActorViewDraw(); // Call each cycle to draw
void ChangeAnimPlaying(const char *pose, // Pose to swap to NULL if keep the same
const char *anim, // Anim to change to
bool8 forwards, // Play anim forwards or backwards
int32 repeats, // Number of times to play this anim before ActorViewDraw() returns ANIMATION_END
int16 ix, // New render x coordinate
int16 iy, // New render y coordinate
int16 iz); // New render z coordinate
} // End of namespace ICB
#endif

443
engines/icb/animation.cpp Normal file
View File

@@ -0,0 +1,443 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/debug.h"
#include "engines/icb/res_man.h"
#include "engines/icb/common/px_scriptengine.h"
#include "engines/icb/common/px_linkeddatafile.h"
#include "engines/icb/common/px_prop_anims.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/session.h"
#include "engines/icb/mission.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/global_objects.h"
namespace ICB {
mcodeFunctionReturnCodes fn_prop_animate(int32 &result, int32 *params) { return (MS->fn_prop_animate(result, params)); }
mcodeFunctionReturnCodes fn_prop_set_to_last_frame(int32 &result, int32 *params) { return (MS->fn_prop_set_to_last_frame(result, params)); }
mcodeFunctionReturnCodes fn_prop_set_to_first_frame(int32 &result, int32 *params) { return (MS->fn_prop_set_to_first_frame(result, params)); }
mcodeFunctionReturnCodes fn_test_prop_anim(int32 &result, int32 *params) { return (MS->fn_test_prop_anim(result, params)); }
mcodeFunctionReturnCodes fn_inherit_prop_anim_height(int32 &result, int32 *params) { return (MS->fn_inherit_prop_anim_height(result, params)); }
mcodeFunctionReturnCodes fn_inherit_prop_anim_height_id(int32 &result, int32 *params) { return (MS->fn_inherit_prop_anim_height_id(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_prop_animate(int32 &, int32 *params) {
// runs forward through a prop animation until it finishes
// bungs a frame in first time called - lets last frame have a whole cycle then quits next go
// note - this is for props only not actors
// in
// param 0 anim name
// out
// IR_CONT anim finished
// IR_REPEAT anim not finished yet - more frames remain to be played
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)LinkedDataObject::Try_fetch_item_by_name(prop_anims, CGameObject::GetName(object));
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
// is this the first time in?
if (!L->looping) {
// first time so set up the anim
// set first frame
prop_state_table[cur_id] = anim->frames[0];
// current pc
L->anim_pc = 0;
// now looping
L->looping = 1;
// come back again next cycle
return (IR_REPEAT);
} else {
// just running through the animation
// is it the end? - i.e. was the frame set up last cycle the last in the sequence - if so then continue with
// the script
if ((uint8)L->anim_pc == (anim->num_frames - 1)) {
// not looping
logic_structs[cur_id]->looping = 0;
// last frame has been displayed so now continue with script
return (IR_CONT);
}
// advance current pc
++L->anim_pc;
// set next frame
prop_state_table[cur_id] = anim->frames[L->anim_pc];
// come back again next cycle
return (IR_REPEAT);
}
}
}
// didn't find the named anim so that's it
Tdebug("objects_that_died.txt", "_game_session::fn_prop_animate object %s can't find anim %s", CGameObject::GetName(object), anim_name);
Shut_down_object("by fn_prop_animate");
return (IR_STOP);
}
mcodeFunctionReturnCodes _game_session::fn_prop_set_to_last_frame(int32 &, int32 *params) {
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)LinkedDataObject::Try_fetch_item_by_name(prop_anims, CGameObject::GetName(object));
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
// set to last frame in sequence
prop_state_table[cur_id] = anim->frames[anim->num_frames - 1];
return (IR_CONT);
}
}
// didn't find the named anim so that's it
Tdebug("objects_that_died.txt", "fn_prop_set_to_last_frame object %s can't find anim %s", CGameObject::GetName(object), anim_name);
Shut_down_object("by fn_prop_set_to_last_frame");
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_prop_set_to_first_frame(int32 &, int32 *params) {
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)LinkedDataObject::Try_fetch_item_by_name(prop_anims, CGameObject::GetName(object));
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
// set to last frame in sequence
prop_state_table[cur_id] = anim->frames[0];
return (IR_CONT);
}
}
// didn't find the named anim so that's it
Tdebug("objects_that_died.txt", "fn_prop_set_to_first_frame object %s can't find anim %s", CGameObject::GetName(object), anim_name);
Message_box("fn_prop_set_to_first_frame object %s can't find anim %s", CGameObject::GetName(object), anim_name);
Shut_down_object("by fn_prop_set_to_first_frame");
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_test_prop_anim(int32 &result, int32 *params) {
// confirm that a prop anim actually exists
// this is useful for objects that may be using custom engine logic
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)LinkedDataObject::Try_fetch_item_by_name(prop_anims, CGameObject::GetName(object));
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// final check to see if there are actual frames in there
if (anim->num_frames) {
result = 1;
return (IR_CONT);
}
Message_box("fn_test_prop_anim object [%s] has anim [%s] but it has no frames", CGameObject::GetName(object), anim_name);
result = 0;
return IR_CONT;
}
}
Message_box("fn_test_prop_anim didn't find anim [%s] for object [%s]", anim_name, CGameObject::GetName(object));
result = 0;
return IR_CONT;
}
uint32 _game_session::Validate_prop_anim(const char *anim_name) {
// confirm that a prop anim actually exists
// this is useful for objects that may be using custom engine logic
// return the anim number
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)LinkedDataObject::Try_fetch_item_by_name(prop_anims, CGameObject::GetName(object));
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// final check to see if there are actual frames in there
if (anim->num_frames)
return (j);
Fatal_error("Validate_prop_anim object [%s] has anim [%s] but it has no frames", CGameObject::GetName(object), anim_name);
}
}
Fatal_error("Validate_prop_anim didn't find anim [%s] for object [%s]", anim_name, CGameObject::GetName(object));
return (FALSE8);
}
mcodeFunctionReturnCodes _game_session::fn_inherit_prop_anim_height_id(int32 &, int32 *params) {
// runs forward through a props animation until it finishes passing the height to the mega
// so instead of playing the anim we're just gettings the y height each frame instead
// the prop should therefore be playing the anim at the same time
// param 0 prop id
// 1 anim name
// out
// IR_CONT anim finished
// IR_REPEAT anim not finished yet - more frames remain to be played
_animating_prop *index;
_animation_entry *anim;
uint32 j;
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[1]);
Zdebug("fn_inherit_prop_anim_height_id");
// find entry for this object via its name, which we find via its number :(
index = (_animating_prop *)LinkedDataObject::Fetch_item_by_name(prop_anims, (const char *)LinkedDataObject::Fetch_items_name_by_number(objects, params[0]));
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
Zdebug(" found anim");
// is this the first time in?
if (!L->looping) {
// first time so set up the anim
if (!anim->offset_heights)
return IR_CONT;
// current pc
L->list[0] = 0; // our prop pc!
// now looping
L->looping = 1;
// protect the mega
L->do_not_disturb = 1;
// get first height
int16 *heights = (int16 *)(((char *)index) + anim->offset_heights);
PXreal one_height = (PXreal)(heights[0]);
M->actor_xyz.y = one_height;
// come back again next cycle
return (IR_REPEAT);
} else {
// just running through the animation
// is it the end? - i.e. was the frame set up last cycle the last in the sequence - if so then continue with
// the script
if (L->list[0] > (uint8)(anim->num_frames - 1))
Fatal_error("%s corrupted in fn_inherit_prop_anim_height_id", CGameObject::GetName(object));
if ((uint8)L->list[0] == (anim->num_frames - 1)) {
// not looping
logic_structs[cur_id]->looping = 0;
// unprotect the mega
L->do_not_disturb = 0;
// last frame has been displayed so now continue with script
return (IR_CONT);
}
// advance current pc
L->list[0]++;
Zdebug("pc = %d", L->list[0]);
// get height
int16 *heights = (int16 *)(((char *)index) + anim->offset_heights);
PXreal one_height = (PXreal)(heights[L->list[0]]);
M->actor_xyz.y = one_height;
Zdebug("new height %3.1f", M->actor_xyz.y);
// come back again next cycle
return (IR_REPEAT);
}
}
}
// didn't find the named anim so that's it
Fatal_error("fn_inherit_prop_anim_height_id object [%s] prop [%s] can't find anim [%s]", CGameObject::GetName(object), LinkedDataObject::Fetch_items_name_by_number(objects, params[0]), anim_name);
return (IR_STOP);
}
mcodeFunctionReturnCodes _game_session::fn_inherit_prop_anim_height(int32 &, int32 *params) {
// runs forward through a props animation until it finishes passing the height to the mega
// so instead of playing the anim we're just gettings the y height each frame instead
// the prop should therefore be playing the anim at the same time
// param 0 prop name
// 1 anim name
// out
// IR_CONT anim finished
// IR_REPEAT anim not finished yet - more frames remain to be played
_animating_prop *index;
_animation_entry *anim;
uint32 j;
const char *prop_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[1]);
Zdebug("fn_inherit_prop_anim_height");
Zdebug("ob %s", CGameObject::GetName(object));
Zdebug("prop %s anim %s", prop_name, anim_name);
// find entry for this object via its name, which we find via its number :(
index = (_animating_prop *)LinkedDataObject::Fetch_item_by_name(prop_anims, prop_name);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
Zdebug(" found anim");
// is this the first time in?
if (!L->looping) {
// first time so set up the anim
// current pc
L->list[0] = 0; // our prop pc!
// now looping
L->looping = 1;
// protect the mega
L->do_not_disturb = 1;
// get first height
int16 *heights = (int16 *)(((char *)index) + anim->offset_heights);
PXreal one_height = (PXreal)(heights[0]);
M->actor_xyz.y = one_height;
// come back again next cycle
return (IR_REPEAT);
} else {
// just running through the animation
// is it the end? - i.e. was the frame set up last cycle the last in the sequence - if so then continue with
// the script
if ((uint8)L->list[0] == (anim->num_frames - 1)) {
// not looping
logic_structs[cur_id]->looping = 0;
// unprotect the mega
L->do_not_disturb = 0;
// last frame has been displayed so now continue with script
return (IR_CONT);
}
// advance current pc
L->list[0]++;
// get height
int16 *heights = (int16 *)(((char *)index) + anim->offset_heights);
PXreal one_height = (PXreal)(heights[L->list[0]]);
M->actor_xyz.y = one_height;
// come back again next cycle
return (IR_REPEAT);
}
}
}
// didn't find the named anim so that's it
Fatal_error("fn_inherit_prop_anim_height object [%s] prop [%s] can't find anim [%s]", CGameObject::GetName(object), prop_name, anim_name);
return (IR_STOP); //
}
} // End of namespace ICB

View File

@@ -0,0 +1,503 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/global_switches.h"
#include "engines/icb/session.h"
#include "engines/icb/animation_mega_set.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/debug.h"
#include "engines/icb/p4_generic.h"
#include "engines/icb/mission.h"
#include "engines/icb/p4.h"
#include "engines/icb/player.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/floors.h"
#include "engines/icb/common/px_scriptengine.h"
#include "engines/icb/common/px_floor_map.h"
#include "engines/icb/common/px_features.h"
#include "engines/icb/res_man.h"
#include "common/str.h"
#include "common/util.h"
namespace ICB {
// this is the master animation declaration table.
_an_anim_entry master_anim_name_table[__TOTAL_ANIMS] = {
{"walk", __WALK},
{"walk_to_stand", __WALK_TO_STAND},
{"walk_to_other_stand_(left_leg)", __WALK_TO_OTHER_STAND_LEFT_LEG},
{"walk_to_pull_out_weapon", __WALK_TO_PULL_OUT_WEAPON},
{"stand", __STAND},
{"stand_to_walk", __STAND_TO_WALK},
{"stand_to_walk_upstairs_right", __STAND_TO_WALK_UP_STAIRS_RIGHT},
{"stand_to_walk_downstairs_right", __STAND_TO_WALK_DOWN_STAIRS_RIGHT},
{"stand_to_run", __STAND_TO_RUN},
{"stand_to_step_backward", __STAND_TO_STEP_BACKWARD},
{"stand_crouch_to_stand", __STAND_CROUCHED_TO_STAND},
{"stand_crouch_to_walk_crouched", __STAND_CROUCHED_TO_WALK_CROUCHED},
{"run", __RUN},
{"run_to_stand", __RUN_TO_STAND},
{"run_to_pull_out_weapon", __RUN_TO_PULL_OUT_WEAPON},
{"use_card_on_slot", __USE_CARD_ON_SLOT},
{"pick_up_object_from_floor", __PICK_UP_OBJECT_FROM_FLOOR},
{"push_button", __PUSH_BUTTON},
{"being_shot", __BEING_SHOT},
{"being_shot_dead", __BEING_SHOT_DEAD},
{"sidestep_left", __SIDESTEP_LEFT},
{"step_backward", __STEP_BACKWARD},
{"step_forward", __STEP_FORWARD},
{"step_backward_to_stand", __STEP_BACKWARD_TO_STAND},
{"step_backward_to_other_stand_(left_leg)", __STEP_BACKWARD_TO_OTHER_STAND_LEFT},
{"stand_and_aim", __STAND_AND_AIM},
{"stand_and_shoot", __STAND_AND_SHOOT},
{"pull_out_weapon", __PULL_OUT_WEAPON},
{"cord_strike", __STRIKE},
{"low_strike", __LOW_STRIKE},
{"hit_from_behind", __HIT_FROM_BEHIND},
{"turn_on_the_spot_cw", __TURN_ON_THE_SPOT_CLOCKWISE},
{"walk_upstairs_left", __WALK_UPSTAIRS_LEFT},
{"walk_upstairs_right", __WALK_UPSTAIRS_RIGHT},
{"walk_downstairs_left", __WALK_DOWNSTAIRS_LEFT},
{"walk_downstairs_right", __WALK_DOWNSTAIRS_RIGHT},
{"walk_upstairs_left_to_stood_on_stairs_facing_up", __WALK_UPSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_UP},
{"walk_upstairs_right_to_stood_on_stairs_facing_up", __WALK_UPSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_UP},
{"walk_downstairs_left_to_stood_on_stairs_facing_down", __WALK_DOWNSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_DOWN},
{"walk_downstairs_right_to_stood_on_stairs_facing_down", __WALK_DOWNSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_DOWN},
{"walk_upstairs_left_to_walk_downstairs_right", __WALK_UPSTAIRS_LEFT_TO_WALK_DOWNSTAIRS_RIGHT},
{"walk_upstairs_right_to_walk_downstairs_left", __WALK_UPSTAIRS_RIGHT_TO_WALK_DOWNSTAIRS_LEFT},
{"walk_downstairs_left_to_walk_upstairs_right", __WALK_DOWNSTAIRS_LEFT_TO_WALK_UPSTAIRS_RIGHT},
{"walk_downstairs_right_to_walk_upstairs_left", __WALK_DOWNSTAIRS_RIGHT_TO_WALK_UPSTAIRS_LEFT},
{"run_up_stairs_left", __RUN_UPSTAIRS_LEFT},
{"run_up_stairs_right", __RUN_UPSTAIRS_RIGHT},
{"run_down_stairs_left", __RUN_DOWNSTAIRS_LEFT},
{"run_down_stairs_right", __RUN_DOWNSTAIRS_RIGHT},
{"climb_up_ladder_left", __CLIMB_UP_LADDER_LEFT},
{"climb_up_ladder_right", __CLIMB_UP_LADDER_RIGHT},
{"climb_down_ladder_left", __CLIMB_DOWN_LADDER_LEFT},
{"climb_down_ladder_right", __CLIMB_DOWN_LADDER_RIGHT},
{"climb_up_ladder_right_to_stand", __CLIMB_UP_LADDER_RIGHT_TO_STAND},
{"climb_down_ladder_right_to_stand", __CLIMB_DOWN_LADDER_RIGHT_TO_STAND},
{"cord_stand_to_climb_up_ladder", __CORD_STAND_TO_CLIMB_UP_LADDER},
{"stand_to_climb_up_ladder_right", __STAND_TO_CLIMB_UP_LADDER_RIGHT},
{"stand_to_climb_down_ladder_right", __STAND_TO_CLIMB_DOWN_LADDER_RIGHT},
{"climb_down_ladder_left_to_slide_down_ladder", __CLIMB_DOWN_LADDER_LEFT_TO_SLIDE_DOWN_LADDER},
{"slide_down_ladder", __SLIDE_DOWN_LADDER},
{"slide_down_ladder_to_stand", __SLIDE_DOWN_LADDER_TO_STAND},
{"load_gun", __LOAD_GUN},
{"load_gun_2", __LOAD_GUN_2},
{"load_gun2", __LOAD_GUN_CROUCH_2},
{"cowering", __COWER},
{"cowering_to_stand", __COWER_TO_STAND},
{"run_hand_through_hair", __HAND_HAIR},
{"shrug", __SHRUG},
{"look_at_watch", __LOOK_AT_WATCH},
{"stretch", __STRETCH},
{"scratching_backside", __SCRATCH},
};
// these names must be in same order as __weapon
char weapon_text[__TOTAL_WEAPONS][MAX_WEAPON_NAME_LENGTH] = {"unarmed", "gun", "crouched", "crouched_gun"};
bool8 armed_state_table[__TOTAL_WEAPONS] = {FALSE8, TRUE8, FALSE8, TRUE8};
_player_stat player_stat_table[__TOTAL_WEAPONS] = {STOOD, NEW_AIM, CROUCHING, CROUCH_AIM};
bool8 crouch_state_table[__TOTAL_WEAPONS] = {FALSE8, FALSE8, TRUE8, TRUE8};
void _vox_image::___init(const char *chr, const char *set, __weapon weapon) {
// Clear the override pose hash value
Cancel_override_pose();
// store these things temporarily so we can recall this function when swapping voxel -> polygon and vice verse...
Common::strcpy_s(temp_chr, chr);
Common::strcpy_s(temp_set, set);
temp_weapon = weapon;
// constructor for mega-set-caps class
// resolve the path of the voxel image directory
// we are passed the character name AND the graphic set
// for example, cord, wetsuit
// this object is created by _game_session::fn_set_voxel_image_path
// where chr='cord'
// set='casual_wear'
int32 k, len;
// check for no weapon being set
if (weapon == __NOT_SET)
Fatal_error("WARNING %s does not have a weapon type", MS->Fetch_object_name(MS->Fetch_cur_id()));
palette_hash = NULL_HASH;
// get base path
// Make hash filename of the character
char chr_hash[8];
HashFile(chr, chr_hash);
// Make hash filename of the outfit
char set_hash[8];
HashFile(set, set_hash);
// Make the cluster name "\c\<#character>\<#outfit>\outfit.clu"
len = Common::sprintf_s(base_path, CHR_PATH, chr_hash, set_hash);
if (len > BASE_PATH_STR_LEN)
Fatal_error("_vox_image::___init base_path string too long");
base_path_hash = NULL_HASH;
Zdebug("make base path == %s from %s %s\n", (const char *)base_path, chr, set);
// In the clustered version the image path is the path inside the cluster
len = Common::sprintf_s(image_path, "%s\\", weapon_text[weapon]);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::___init image_path [%s] string too long", image_path);
len = Common::sprintf_s(shadow_mesh_name, "%s", "mesh_shadow.rap");
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::___init shadow_mesh_name [%s] string too long", shadow_mesh_name);
len = Common::sprintf_s(pose_name, "%s\\pose.rap", weapon_text[weapon]);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::___init pose_name [%s] string too long", pose_name);
pose_hash = HashString(pose_name);
shadow_mesh_hash = HashString(shadow_mesh_name);
// Make the hash value for this cluster name
base_path_hash = HashString(base_path);
// Make the hash value for this cluster name
base_path_hash = HashString(base_path);
Zdebug("image path == %s\n", (const char *)image_path);
Zdebug("base path == %s\n", (const char *)base_path);
for (k = 0; k < __NON_GENERIC; k++) {
anim_table[k] = (int8)-1;
}
if (((g_mission) && (g_mission->session)) && (MS->Fetch_cur_id() != 999)) {
MS->logic_structs[MS->Fetch_cur_id()]->cur_anim_type = __STAND;
MS->logic_structs[MS->Fetch_cur_id()]->anim_pc = 0;
}
has_custom_path_built = FALSE8; // no custom animation exists
Zdebug("\n-------------------------------------------------------------------------------\n");
}
void _vox_image::MakeAnimEntry(int32 i) {
Common::String strName;
strName = Common::String::format("%s%s.rab", (const char *)image_path, (const char *)master_anim_name_table[i].name);
if (strName.size() > ANIM_NAME_STR_LEN) {
Fatal_error("_vox_image::___init [%s] string too long", strName.c_str());
}
Common::strcpy_s(anim_name[i], strName.c_str());
anim_name_hash[i] = HashString(anim_name[i]);
strName = Common::String::format("%s%s.raj", (const char *)image_path, (const char *)master_anim_name_table[i].name);
if (strName.size() > ANIM_NAME_STR_LEN) {
Fatal_error("_vox_image::___init [%s] string too long", strName.c_str());
}
Common::strcpy_s(info_name[i], strName.c_str());
info_name_hash[i] = HashString(info_name[i]);
// do the test file
anim_table[i] = (int8)(rs_anims->Test_file(get_anim_name(i), anim_name_hash[i], base_path, base_path_hash));
}
bool8 _vox_image::Init_custom_animation(const char *anim) {
// init a non generic animation in its special __NON_GENERIC slot
// this does not ensure the anim exists
bool8 custom;
char custom_image_path_rav[128];
char custom_image_path_rai[128];
uint32 len;
len = strlen(anim);
uint32 j;
for (j = 0; j < len; j++)
if (Common::isUpper(*(anim + j)))
Fatal_error("Init_custom_animation finds [%s] has upper case letters - implementor must edit the script", anim);
// has anyone been and built the path before?
if (has_custom_path_built) {
has_custom_path_built = FALSE8; // remove it
return (TRUE8); // carry on
}
custom = MS->Fetch_custom();
// check for no weapon being set
if (custom == FALSE8 /*__NONE*/) {
// custom must be in the current weapon set - bah, shouldn't have done it like this - it's daft
// rav (or equivalent) always come from pcp directory...
len = Common::sprintf_s(custom_image_path_rav, "%s\\", weapon_text[MS->Fetch_cur_megas_pose()]);
// rai (or equivalent) always come from base path...
len = Common::sprintf_s(custom_image_path_rai, "%s\\", weapon_text[MS->Fetch_cur_megas_pose()]);
// pose mesh name
len = Common::sprintf_s(custom_pose_name, "%s\\pose.rap", weapon_text[MS->Fetch_cur_megas_pose()]);
custom_pose_hash = HashString(custom_pose_name);
} else {
// we have specified a custom type - i.e. the anim is not part of the current weapon set, but
// instead sits parallel to weapon directory
len = Common::sprintf_s(custom_image_path_rav, "%s\\", MS->Fetch_cur_megas_custom_text());
len = Common::sprintf_s(custom_image_path_rai, "%s\\", MS->Fetch_cur_megas_custom_text());
len = Common::sprintf_s(custom_pose_name, "%s\\pose.rap", MS->Fetch_cur_megas_custom_text());
if (len > 128)
Fatal_error("Init_custom_animation string error");
custom_pose_hash = HashString(custom_pose_name);
}
len = Common::sprintf_s(anim_name[__NON_GENERIC], "%s%s.rab", (const char *)custom_image_path_rav, (const char *)anim);
if (len > ANIM_NAME_STR_LEN)
Fatal_error("Init_custom_animation string error");
anim_name_hash[__NON_GENERIC] = HashString(anim_name[__NON_GENERIC]);
len = Common::sprintf_s(info_name[__NON_GENERIC], "%s%s.raj", (const char *)custom_image_path_rai, (const char *)anim);
if (len > ANIM_NAME_STR_LEN)
Fatal_error("Init_custom_animation string error");
info_name_hash[__NON_GENERIC] = HashString(info_name[__NON_GENERIC]);
anim_table[__NON_GENERIC] = 1;
if (!rs_anims->Test_file(get_anim_name(__NON_GENERIC), anim_name_hash[__NON_GENERIC], base_path, base_path_hash)) {
Fatal_error("custom anim [%s,%08x] not found in cluster %s", (const char *)anim_name[__NON_GENERIC], anim_name_hash[__NON_GENERIC], base_path);
}
Zdebug(" created [%s]", (const char *)anim_name[__NON_GENERIC]);
return (TRUE8);
}
void _vox_image::Promote_non_generic() {
// copy non-generic path to safe __PROMOTED_NON_GENERIC slot
// this is all for psx asyncing
memcpy(&anim_name[__PROMOTED_NON_GENERIC], &anim_name[__NON_GENERIC], ANIM_NAME_STR_LEN);
memcpy(&info_name[__PROMOTED_NON_GENERIC], &info_name[__NON_GENERIC], ANIM_NAME_STR_LEN);
info_name_hash[__PROMOTED_NON_GENERIC] = info_name_hash[__NON_GENERIC];
anim_name_hash[__PROMOTED_NON_GENERIC] = anim_name_hash[__NON_GENERIC];
anim_table[__PROMOTED_NON_GENERIC] = 1; // hack this
}
bool8 _vox_image::Find_anim_type(__mega_set_names *anim, const char *name) {
uint32 k;
for (k = 0; k < __TOTAL_ANIMS; k++) {
// we must search the table
if (!strcmp(name, master_anim_name_table[k].name)) {
*(anim) = master_anim_name_table[k].ref;
return (TRUE8);
}
}
return (FALSE8);
}
bool8 _game_session::Start_generic_ascii_anim(const char *ascii_name) {
// search for named anim and setup if found
uint32 k;
// search for the named generic anim - can't use __ANIM_NAME from script unfortunately
for (k = 0; k < __TOTAL_ANIMS; k++) {
// we must search the table
if (!strcmp(const_cast<char *>(ascii_name), master_anim_name_table[k].name)) {
Zdebug(" Start_generic_ascii_anim found [%s]", ascii_name);
L->cur_anim_type = master_anim_name_table[k].ref;
L->anim_pc = 0;
// Check to see if this anim exists on the hard drive
// Note this will also make the name entry correctly if the name hasn't already
// been made
if (I->IsAnimTable(L->cur_anim_type) == (int8)-1)
return (FALSE8);
return (TRUE8);
}
}
Zdebug("nightmare!");
return (FALSE8);
}
__mega_set_names _game_session::Fetch_generic_anim_from_ascii(const char *ascii_name) {
// pass name of a generic anim and return the type
uint32 k;
// search for the named generic anim - can't use __ANIM_NAME from script unfortunately
for (k = 0; k < __TOTAL_ANIMS; k++) {
if (!strcmp(const_cast<char *>(ascii_name), master_anim_name_table[k].name)) {
// found!
if (I->IsAnimTable(L->cur_anim_type) == (int8)-1)
Fatal_error("Fetch_generic_anim_from_ascii can't find on drive %s", ascii_name);
return (master_anim_name_table[k].ref);
}
}
Fatal_error("Fetch_generic_anim_from_ascii can't find %s", ascii_name);
return __NON_GENERIC;
}
void PreRegisterTexture(const char *, uint32, const char *, uint32, const char *, uint32);
bool8 _vox_image::Set_texture(const char *tex_name) {
int32 len;
len = Common::sprintf_s(texture_name, "%s.revtex", tex_name);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::Set_texture [%s] string too long", tex_name);
texture_hash = HashString(texture_name);
// set palette to be same as texture
Common::strcpy_s(palette_name, texture_name);
palette_hash = texture_hash;
// okay preload the texture/palette combo
PreRegisterTexture(texture_name, texture_hash, palette_name, palette_hash, base_path, base_path_hash);
return TRUE8;
}
bool8 _vox_image::Set_mesh(const char *m_name) {
char name[32];
int32 len;
Common::strcpy_s(name, m_name);
Common::strcat_s(name, ".rap");
len = Common::sprintf_s(mesh_name, "%s", name);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::___init mesh_name [%s] string too long", mesh_name);
mesh_hash = HashString(mesh_name);
return TRUE8;
}
bool8 _vox_image::Set_palette(const char *pal_name) {
// Ignore the default_palette : this is yucky and hacky but it is the end of the project so tough luck
if (strcmp(pal_name, "default") == 0) {
palette_hash = NULL_HASH;
return TRUE8;
}
int32 len;
len = Common::sprintf_s(palette_name, "%s.revtex", pal_name);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::Set_palette [%s] string too long", pal_name);
palette_hash = HashString(palette_name);
// okay preload the texture/palette combo
PreRegisterTexture(texture_name, texture_hash, palette_name, palette_hash, base_path, base_path_hash);
return TRUE8;
}
bool8 _vox_image::Set_override_pose(const char *p_name) {
int len = Common::sprintf_s(override_pose_name, "%s\\pose.rap", p_name);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::Set_override_pose [%s] string too long", override_pose_name);
override_pose_hash = HashString(override_pose_name);
return TRUE8;
}
bool8 _vox_image::Cancel_override_pose() {
override_pose_hash = NULL_HASH;
override_pose_name[0] = '\0';
return TRUE8;
}
// Async load a file from a character cluster into rs_anims
// Return 0 - file is not in memory
// Return 1 - file is in memory
int _vox_image::Preload_file(const char *file) {
char file_name[ENGINE_STRING_LEN];
int len = Common::sprintf_s(file_name, "%s", file);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::Preload_file [%s] string too long", file_name);
uint32 fileHash = NULL_HASH;
// The PC version does not use async loading
if (rs_anims->Res_open(file_name, fileHash, base_path, base_path_hash))
return 1;
return 0;
}
} // End of namespace ICB

View File

@@ -0,0 +1,143 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_ANIMATION_MEGA_SET
#define ICB_ANIMATION_MEGA_SET
#include "engines/icb/common/px_string.h"
namespace ICB {
#define MAX_ANIM_NAME_LENGTH 64
enum __mega_set_names {
__WALK,
__WALK_TO_STAND,
__WALK_TO_OTHER_STAND_LEFT_LEG,
__WALK_TO_PULL_OUT_WEAPON,
__STAND,
__STAND_TO_WALK,
__STAND_TO_WALK_UP_STAIRS_RIGHT,
__STAND_TO_WALK_DOWN_STAIRS_RIGHT,
__STAND_TO_RUN,
__STAND_TO_STEP_BACKWARD,
__STAND_CROUCHED_TO_STAND,
__STAND_CROUCHED_TO_WALK_CROUCHED,
__RUN,
__RUN_TO_STAND,
__RUN_TO_PULL_OUT_WEAPON,
__USE_CARD_ON_SLOT,
__PICK_UP_OBJECT_FROM_FLOOR,
__PUSH_BUTTON,
__BEING_SHOT,
__BEING_SHOT_DEAD,
__SIDESTEP_LEFT,
__STEP_BACKWARD,
__STEP_FORWARD,
__STEP_BACKWARD_TO_STAND,
__STEP_BACKWARD_TO_OTHER_STAND_LEFT,
__STAND_AND_AIM,
__STAND_AND_SHOOT,
__PULL_OUT_WEAPON,
__STRIKE,
__LOW_STRIKE,
__HIT_FROM_BEHIND,
__TURN_ON_THE_SPOT_CLOCKWISE,
__WALK_UPSTAIRS_LEFT,
__WALK_UPSTAIRS_RIGHT,
__WALK_DOWNSTAIRS_LEFT,
__WALK_DOWNSTAIRS_RIGHT,
__WALK_UPSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_UP,
__WALK_UPSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_UP,
__WALK_DOWNSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_DOWN,
__WALK_DOWNSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_DOWN,
__WALK_UPSTAIRS_LEFT_TO_WALK_DOWNSTAIRS_RIGHT,
__WALK_UPSTAIRS_RIGHT_TO_WALK_DOWNSTAIRS_LEFT,
__WALK_DOWNSTAIRS_LEFT_TO_WALK_UPSTAIRS_RIGHT,
__WALK_DOWNSTAIRS_RIGHT_TO_WALK_UPSTAIRS_LEFT,
__RUN_UPSTAIRS_LEFT,
__RUN_UPSTAIRS_RIGHT,
__RUN_DOWNSTAIRS_LEFT,
__RUN_DOWNSTAIRS_RIGHT,
__CLIMB_UP_LADDER_LEFT,
__CLIMB_UP_LADDER_RIGHT,
__CLIMB_DOWN_LADDER_LEFT,
__CLIMB_DOWN_LADDER_RIGHT,
__CLIMB_UP_LADDER_RIGHT_TO_STAND,
__CLIMB_DOWN_LADDER_RIGHT_TO_STAND,
__CORD_STAND_TO_CLIMB_UP_LADDER,
__STAND_TO_CLIMB_UP_LADDER_RIGHT,
__STAND_TO_CLIMB_DOWN_LADDER_RIGHT,
__CLIMB_DOWN_LADDER_LEFT_TO_SLIDE_DOWN_LADDER,
__SLIDE_DOWN_LADDER,
__SLIDE_DOWN_LADDER_TO_STAND,
__LOAD_GUN,
__LOAD_GUN_2,
__LOAD_GUN_CROUCH_2,
__COWER,
__COWER_TO_STAND,
__HAND_HAIR,
__SHRUG,
__LOOK_AT_WATCH,
__STRETCH,
__SCRATCH,
__NON_GENERIC, // a non generic specific - initialised at run time
__PROMOTED_NON_GENERIC, // a generic gets promoted here where it wilk be safe from new generic paths being formed - done for psx
// asyncing
__NO_LINK, // can be used by _player::Start_new_mode
__NO_ANIM,
__TOTAL_ANIMS
};
typedef struct {
char name[MAX_ANIM_NAME_LENGTH]; // the name minus .RAV & .RAI
__mega_set_names ref;
} _an_anim_entry;
extern _an_anim_entry master_anim_name_table[__TOTAL_ANIMS];
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,52 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/debug.h"
#include "engines/icb/session.h"
#include "engines/icb/actor.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/res_man.h"
#include "engines/icb/mission.h"
namespace ICB {
mcodeFunctionReturnCodes fn_preload_basics(int32 &result, int32 *params) { return (MS->fn_preload_basics(result, params)); }
// function loads some standard anim and marker files in, designed to be used at session
// init. this function run for a few megas (ie the ones that are on screen)
// should ease off the preloader slightly and create less chug on psx...!
mcodeFunctionReturnCodes _game_session::fn_preload_basics(int32 &, int32 *) {
// if this is init script, then I is not set yet, so do so now...
I = L->voxel_info;
rs_anims->Res_open_mini_cluster(I->base_path, I->base_path_hash, I->base_path, I->base_path_hash);
// okay
return (IR_CONT);
}
} // End of namespace ICB

1468
engines/icb/barriers.cpp Normal file

File diff suppressed because it is too large Load Diff

150
engines/icb/barriers.h Normal file
View File

@@ -0,0 +1,150 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_BARRIERS_H
#define ICB_BARRIERS_H
#include "engines/icb/common/px_rcutypes.h"
#include "engines/icb/common/px_linkeddatafile.h"
#include "engines/icb/common/px_route_barriers.h"
namespace ICB {
#define MAX_slices 10
//+1 for dummy top floor ceiling
#define MAX_heights (MAX_slices + 1)
#define MAX_floors 48
// this is the master number of objects -
// The +3 & ~3 - means it is rounded up to be a multiple of 4
#define MAX_props ((116 + 3) & ~3)
#define MAX_parents_per_anim_slice 24
//#define MAX_bars_per_parent 96
#define MAX_props_per_parent 16
#define MAX_animating_props 24
#define MAX_bars_per_prop 60
#define MAX_child_groups_per_parent 16
#define MAX_prop_abars (MAX_animating_props * MAX_bars_per_prop)
//--------------------------------------------------------------------------------------
class _animating_parent { // contains all of the abarriers that lie within this parent space - for each we record its associated prop and
// state so we know when each is in scope
public:
uint8 num_props;
uint8 prop_number[MAX_props_per_parent];
};
class _animating_barrier_slice { // contains a list of parents that lie within the slice
// and a list of props within the slice
public:
_animating_parent *anim_parents[MAX_parents_per_anim_slice];
uint8 num_props_in_slice;
uint8 prop_list[MAX_props];
};
class _anim_prop_info { // contains a list of all the abars for the prop
public:
uint8 barriers_per_state;
uint8 total_states; // temp - could be removed
uint16 *barrier_list; // pointer into 'prop_abar_table'
};
class _barrier_handler {
public:
void ___init();
void Form_route_barrier_list(PXreal x, PXreal y, PXreal z, PXreal x2, PXreal z2);
void Form_parent_barrier_list(PXreal x, PXreal y, PXreal z);
ParentBox *Fetch_parent_box_for_xyz(PXreal x, PXreal y, PXreal z, uint32 &par_num, uint32 &slice_num);
ParentBox *Fetch_parent_num_on_slice_y(uint32 requested_parent, PXreal y);
uint32 Fetch_number_of_child_boxes(ParentBox *parent);
ChildGroup *Fetch_child_box(ParentBox *parent, uint32 child);
RouteBarrier *Fetch_barrier(uint32 num);
uint32 Fetch_total_barriers();
LinkedDataFile *Get_barrier_pointer() const { return raw_barriers; }
void Prepare_animating_barriers();
uint32 Get_anim_barriers(uint32 n, uint32 *oThisCubesBarriers, uint32 slice);
void Set_route_barrier_mask(int32 left, int32 right, int32 top, int32 bottom);
void Clear_route_barrier_mask();
_animating_barrier_slice anim_slices[MAX_slices];
_anim_prop_info anim_prop_info[MAX_props];
uint16 prop_abar_table[MAX_animating_props * MAX_bars_per_prop];
uint8 parents_used; // count how many of table are used
_animating_parent anim_parent_table[MAX_floors]; // storage
// raw barriers
LinkedDataFile *raw_barriers; // raw route barriers used for routing/line of sight and maybe shadow geometry
uint32 total_barriers;
// route barrier wrapper file
LinkedDataFile *route_wrapper;
uint32 total_slices; // useful out of file
bool8 barrier_mask;
DXrect mask;
};
inline void _barrier_handler::Set_route_barrier_mask(int32 left, int32 right, int32 top, int32 bottom) {
// certain route building will provide an inner rect that barriers must lie within
barrier_mask = TRUE8;
mask.left = left;
mask.right = right;
mask.top = top;
mask.bottom = bottom;
}
inline void _barrier_handler::Clear_route_barrier_mask() {
// cancel inner route barrier mask
barrier_mask = FALSE8;
}
inline uint32 _barrier_handler::Fetch_number_of_child_boxes(ParentBox *parent) { return (parent->num_childgroups); }
inline ChildGroup *_barrier_handler::Fetch_child_box(ParentBox *parent, uint32 child) { return ((ChildGroup *)(((uint8 *)parent) + parent->childgroups[child])); }
inline uint32 _barrier_handler::Fetch_total_barriers() { return (total_barriers); }
} // End of namespace ICB
#endif

613
engines/icb/bone.cpp Normal file
View File

@@ -0,0 +1,613 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/debug.h"
#include "engines/icb/mission.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/bone.h"
#include "engines/icb/sound.h"
#include "engines/icb/icb.h"
#include "common/textconsole.h"
namespace ICB {
#define NECK_PERCENT 16
#define NECK_RANGE 96
#define NECK_SPEED 8
#define JAW_PERCENT 40
#define JAW_MAX 256
#define JAW_SPEED 32
#define STANDARD_LOOK_SPEED 128
// useful function to cap a short value at min-max range
void LimitShort(short &v, short min, short max) {
if (v < min)
v = min;
else if (v > max)
v = max;
}
#define BULLET_COL 200
#define BULLET_DC -8
#define BULLET_G -8 // dy+=g
#define BULLET_DX 4 // initial dy
#define BULLET_DY 16 // initial dy
void _mega::InitCartridgeCase(SVECTOR *initPos, short initialHeight) {
bulletInitialHeight = initialHeight;
bulletOn = TRUE8;
bulletPos = *initPos;
bulletDX = BULLET_DX;
bulletDY = BULLET_DY;
bulletColour = (uint8)BULLET_COL;
bulletBounced = (uint8)0;
}
void _game_session::UpdateCartridgeCase() {
if (M->bulletOn) {
// gravity acceleration
M->bulletDY = (int16)(M->bulletDY + BULLET_G);
// movement
M->bulletPos.vx = (int16)(M->bulletPos.vx + M->bulletDX);
M->bulletPos.vy = (int16)(M->bulletPos.vy + M->bulletDY);
// only reduce colour if >0
if (M->bulletColour)
M->bulletColour = (uint8)(M->bulletColour + BULLET_DC);
if ((M->bulletPos.vy < -M->bulletInitialHeight) && (M->bulletBounced >= 1)) { // we are at ground height and have already bounced enough (1) times, turn us off
M->bulletOn = FALSE8;
} else if (M->bulletPos.vy < -M->bulletInitialHeight) { // otherwise if we are at floor height then bounce us back up...
M->bulletPos.vy = (int16)(-M->bulletInitialHeight); // clip
M->bulletDY = (int16)(-M->bulletDY / 2);
M->bulletDX = (int16)(M->bulletDX / 2);
M->bulletBounced++;
// this is where we make the bouncing sound...
RegisterSound(cur_id, CGameObject::GetStringValueOrDefault(object, tinkleSfxVar, defaultTinkleSfx), tinkleDesc);
}
}
}
// update talking character log
// using there rap file to get bones
// for jaw and neck. This sets random
// movement on neck (x,y,z) and random
// movement for jaw (just in x)
void UpdateTalking(_logic *log, RapAPI *rap) {
// check for -1 in rap
if (rap->jawBone == (int8)-1)
Tdebug("bones.txt", "mega %s speaking but has no jaw bone!", log->mega->chr_name);
if (rap->neckBone == (int8)-1)
Tdebug("bones.txt", "mega %s speaking but has no neck bone!", log->mega->chr_name);
// set deformations....
BoneDeformation *neckBone = &(log->voxel_info->neckBone);
BoneDeformation *jawBone = &(log->voxel_info->jawBone);
// set speed
neckBone->boneSpeed = NECK_SPEED;
jawBone->boneSpeed = JAW_SPEED;
// set number of bone from rap file
jawBone->boneNumber = (int16)(rap->jawBone);
neckBone->boneNumber = (int16)(rap->neckBone);
// unless it's -1 (no bone) we want the bone above this...
if (neckBone->boneNumber != (int16)-1) {
neckBone->boneNumber++; // add one to the value
}
// random neck movement (all three planes)
if ((g_icb->getRandomSource()->getRandomNumber(100 - 1)) < NECK_PERCENT) {
neckBone->boneTarget.vx = (int16)((g_icb->getRandomSource()->getRandomNumber(2 * NECK_RANGE - 1)) - NECK_RANGE);
neckBone->boneTarget.vz = (int16)((g_icb->getRandomSource()->getRandomNumber(2 * NECK_RANGE - 1)) - NECK_RANGE);
neckBone->boneTarget.vy = (int16)((g_icb->getRandomSource()->getRandomNumber(2 * NECK_RANGE - 1)) - NECK_RANGE);
}
// random jaw movement (just the v moves)
if ((g_icb->getRandomSource()->getRandomNumber(100 - 1)) < JAW_PERCENT) {
jawBone->boneTarget.vx = (int16)(g_icb->getRandomSource()->getRandomNumber(JAW_MAX - 1));
jawBone->boneTarget.vz = (int16)0;
jawBone->boneTarget.vy = (int16)0;
}
}
// player was shot by obj
// needs some work to get right
void SetPlayerShotBone(int32 obj_id) {
_logic *player_log = MS->player.log;
_logic *obj_log = MS->logic_structs[obj_id];
PXfloat px, py, pz, ox, oy, oz;
// get locations (only really interested in x and z
player_log->GetPosition(px, py, pz);
obj_log->GetPosition(ox, oy, oz);
PXfloat dx, dz;
dx = ox - px;
dz = oz - pz;
// get player facing direction...
PXfloat player_pan;
if (MS->player.log->auto_panning == FALSE8)
player_pan = MS->player.log->pan;
else
player_pan = MS->player.log->auto_display_pan;
int32 direction;
// get direction got shot from...
direction = (int32)(4096.0 * (PXAngleOfVector(-dz, -dx) - player_pan));
// make sure it is -2048 - 2048
if (direction > 2047)
direction -= 4096;
if (direction < -2048)
direction += 4096;
// bone number 2 set to (512,0,512)
if (abs(direction) < 1024) // shot from somewhere behind...
MS->player.shotDeformation.boneValue.vx = 256; // front
else
MS->player.shotDeformation.boneValue.vx = -256; // back
if ((g_icb->getRandomSource()->getRandomNumber(100 - 1)) < 50) { // 50% chance of going either way left or right
MS->player.shotDeformation.boneValue.vy = 32; // turn a bit just for variation
MS->player.shotDeformation.boneValue.vz = 32; // turn a bit just for variation
} else {
MS->player.shotDeformation.boneValue.vy = -32; // turn
MS->player.shotDeformation.boneValue.vz = -32; // turn a bit just for variation
}
MS->player.shotDeformation.Target0();
MS->player.shotDeformation.boneNumber = 1;
MS->player.shotDeformation.boneSpeed = 128;
}
#define STATUS_NONE 0
#define STATUS_BODY 1
#define STATUS_HEAD 2
#define PLAYER_STOOD_EYE 180
#define PLAYER_CROUCH_EYE 65
#define MEGA_STOOD_EYE 170
#define MEGA_CROUCH_EYE 55
#define MEGA_DEAD_EYE 0
#define ROBOT_EYE 40
#define STANDARD_MARKER_HEIGHT 170
void ResetPlayerLook() {
_logic *log = MS->player.log;
BoneDeformation *b = &(log->voxel_info->lookBone);
b->boneTarget.vx = b->boneTarget.vy = b->boneTarget.vz = 0;
}
// update the neck bone
// should only be called with player as logic
void UpdatePlayerLook() {
static int32 status = STATUS_NONE;
_logic *log = MS->player.log;
BoneDeformation *b = &(log->voxel_info->lookBone);
// start off with manually set values
b->boneTarget = log->voxel_info->scriptedLookBoneTarget;
// interact object, or look at object if we don't have an interact one
bool8 has_interact = MS->player.interact_selected;
uint32 sel_id = MS->player.cur_interact_id;
// we have no interact so try getting a look at...
if (!has_interact) {
has_interact = MS->player.look_at_selected;
sel_id = MS->player.look_at_id;
}
// if we have a specific look set then we set bone number to 23
if ((b->boneTarget.vx != 0) || (b->boneTarget.vy != 0) || (b->boneTarget.vz != 0)) {
status = STATUS_NONE;
b->boneNumber = 23;
b->boneSpeed = STANDARD_LOOK_SPEED;
}
// we only override these things if we do not have a bone target set (ie bone target is <0,0,0>)
// also we only do this if the player is looking at something... (otherwise the targets are <0,0,0>
// also we only do this when not playing a custom anim...
if ((b->boneTarget.vx == 0) && (b->boneTarget.vy == 0) && (b->boneTarget.vz == 0) && // bone override not set
(has_interact) && // are looking at something
(log->cur_anim_type != __PROMOTED_NON_GENERIC) && // we are not on a special non-generic (custom)
(log->cur_anim_type != __NON_GENERIC) // we are not on a non-generic (custom)
) {
_logic *target;
PXfloat player_pan;
PXreal ox, oy, oz, px, py, pz;
PXreal dx, dy, dz;
int32 playerEye;
// get position of players head
// raw position (foot)
log->GetPosition(px, py, pz);
if (log->mega->Is_crouched())
playerEye = PLAYER_CROUCH_EYE; // crouch
else
playerEye = PLAYER_STOOD_EYE; // stand
// height increases to eye...
py += playerEye;
// get position of targeting object
target = MS->logic_structs[sel_id];
// raw position
target->GetPosition(ox, oy, oz);
// target is an actor so need adjustment for eye height...
if (target->image_type == VOXEL) {
CGame *pGameObject = (CGame *)LinkedDataObject::Fetch_item_by_number(MS->objects, sel_id);
int32 dead = CGameObject::GetIntegerVariable(pGameObject, CGameObject::GetVariable(pGameObject, "state"));
if (target->object_type == __NON_ORGANIC_MEGA) { // robot (look down)
oy += ROBOT_EYE;
} else if (dead) { // dead
oy += MEGA_DEAD_EYE;
} else if (target->mega->Is_crouched()) { // crouch
oy += MEGA_CROUCH_EYE;
} else {
oy += MEGA_STOOD_EYE; // standing
}
// difference in x,y,z
dx = (px - ox);
dy = (py - oy);
dz = (pz - oz);
}
// is an interact object, check for height.
else {
int32 height = STANDARD_MARKER_HEIGHT; // standard prop height
// if look_height set for this marker set
if (target->look_height != -1)
height = target->look_height;
dx = (px - ox);
// difference between player eye and marker height
dy = (PXreal)(playerEye - height);
dz = (pz - oz);
}
// get player pan (for calculating how far round the head moves)
if (MS->player.log->auto_panning == FALSE8)
player_pan = MS->player.log->pan;
else
player_pan = MS->player.log->auto_display_pan;
// Now find angles for neck bone...
b->boneTarget.vz = (int16)(4096.0 * (PXAngleOfVector(-dz, -dx) - player_pan));
b->boneTarget.vx = (int16)(4096.0 * PXAngleOfVector((PXfloat)PXsqrt(dx * dx + dz * dz), dy));
// make sure vz is in range -2048 - 2048... this might not be because of subtracting off player_pan
while (b->boneTarget.vz > 2048)
b->boneTarget.vz -= 4096;
while (b->boneTarget.vz < -2048)
b->boneTarget.vz += 4096;
if (b->boneTarget.vz > 1024)
b->boneTarget.vz = 1024;
if (b->boneTarget.vz < -1024)
b->boneTarget.vz = -1024;
// armed unarmed
int32 armed = MS->player.log->mega->Fetch_armed_status();
// from NONE to a status
// if status is none and we are armed and we have returned to central then start looking with upper body...
if ((status == STATUS_NONE) && (armed) && (b->boneValue.vz == 0) && (b->boneValue.vx == 0))
status = STATUS_BODY;
// if status is none and we are not armed and we have returned to central then start looking with head...
if ((status == STATUS_NONE) && (!armed) && (b->boneValue.vz == 0) && (b->boneValue.vx == 0))
status = STATUS_HEAD;
// from wrong status to NONE
// if aiming with body but not armed then status is none (in prep of going to status_body)
if ((status == STATUS_BODY) && (!armed))
status = STATUS_NONE;
// if looking with head but armed then status is none (in preparation for going to STATUS_HEAD)
if ((status == STATUS_HEAD) && (armed))
status = STATUS_NONE;
// now what to do in each status...
// no status, target nothing...
if (status == STATUS_NONE) {
b->boneTarget.vx = 0;
b->boneTarget.vy = 0;
b->boneTarget.vz = 0;
b->boneSpeed = STANDARD_LOOK_SPEED * 2;
}
// look with head...
else if (status == STATUS_HEAD) {
// limit pan and pitch
LimitShort(b->boneTarget.vz, -512, 384);
LimitShort(b->boneTarget.vx, -256, 256);
// for turning it looks better if you look up slightly (vx=vx-abs(vz)/2)
b->boneTarget.vx = (int16)(b->boneTarget.vx - (abs(b->boneTarget.vz) / 3));
// we need to set the speed to be STANDARD_LOOK_SPEED
b->boneSpeed = STANDARD_LOOK_SPEED;
// should not be hard coded, neck bone
b->boneNumber = 23;
}
// look with body...
else if (status == STATUS_BODY) {
// no bend when aimed
b->boneTarget.vy = 0;
// limit pitch (pan can be any value so gun is always pointing at target...)
LimitShort(b->boneTarget.vx, -256, 256);
b->boneTarget.vy = (int16)((b->boneTarget.vx * b->boneTarget.vz) / 1024);
// we need to set the speed to be STANDARD_LOOK_SPEED
b->boneSpeed = STANDARD_LOOK_SPEED * 2;
// should not be hard coded, body bone
b->boneNumber = 1;
}
} else {
// if still in body mode and we have gone back to straight then set mode to none and bone goes to 23 (neck) for specific
// looks...
if ((b->boneTarget.vx == 0) && (b->boneValue.vz == 0) && (status == STATUS_BODY)) {
status = STATUS_NONE;
b->boneNumber = 23;
b->boneSpeed = STANDARD_LOOK_SPEED;
}
}
// don't do an update here...
}
mcodeFunctionReturnCodes fn_set_neck_bone(int32 &result, int32 *params) { return (MS->fn_set_neck_bone(result, params)); }
mcodeFunctionReturnCodes fn_set_neck_vector(int32 &result, int32 *params) { return (MS->fn_set_neck_vector(result, params)); }
mcodeFunctionReturnCodes speak_set_neck_vector(int32 &result, int32 *params) { return (MS->speak_set_neck_vector(result, params)); }
mcodeFunctionReturnCodes fn_simple_look(int32 &result, int32 *params) { return (MS->fn_simple_look(result, params)); }
mcodeFunctionReturnCodes speak_simple_look(int32 &result, int32 *params) { return (MS->speak_simple_look(result, params)); }
mcodeFunctionReturnCodes fn_set_mega_height(int32 &result, int32 *params) { return (MS->fn_set_mega_height(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_set_mega_height(int32 &, int32 *params) {
if (!L->mega)
Fatal_error("fn_set_mega_height called for %s which is not a mega!", L->GetName());
L->mega->height = params[0];
return IR_CONT;
}
// the array of standard look coords
#define LOOK_RIGHT (int16)(-384)
#define LOOK_UP (int16)(-196)
#define LOOK_LEFT (int16)(-LOOK_RIGHT)
#define LOOK_DOWN (int16)(-LOOK_UP)
const short looks[9][3] = {
{0, 0, 0}, // ahead
{0, 0, LOOK_UP}, // up
{LOOK_RIGHT, 0, LOOK_UP}, // up/right
{LOOK_RIGHT, 0, 0}, // right
{LOOK_RIGHT, 0, LOOK_DOWN}, // down/right
{0, 0, LOOK_DOWN}, // down
{LOOK_LEFT, 0, LOOK_DOWN}, // down/left
{LOOK_LEFT, 0, 0}, // left
{LOOK_LEFT, 0, LOOK_UP} // up/left
};
// look
// 0 - Ahead
// 1 - Up
// 2 - Up/Right
// 3 - Right
// 4 - Right/Down
// 5 - Down
// 6 - Down/Left
// 7 - Left
// 8 - Left/Up
// simple look
mcodeFunctionReturnCodes _game_session::fn_simple_look(int32 &, int32 *params) {
int32 l = params[0]; // which direction
if (!logic_structs[cur_id]->mega)
Fatal_error("fn_simple_look called by non mega %s", L->GetName());
int32 callingParams[2];
callingParams[0] = MemoryUtil::encodePtr((uint8 *)const_cast<char *>(L->GetName()));
callingParams[1] = l;
int32 ret;
return speak_simple_look(ret, callingParams);
}
// simple look from speech scripts...
mcodeFunctionReturnCodes _game_session::speak_simple_look(int32 &, int32 *params) {
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// object
int32 object_id = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
// direction
int32 l = params[1];
if (!logic_structs[object_id]->mega)
Fatal_error("speak_simple_look called by non mega %s", logic_structs[object_id]->GetName());
if (logic_structs[object_id]->voxel_info->lookBone.boneNumber == (int8)-1)
Fatal_error("speak_simple_look called but no fn_set_neck_bone() has been called for object %s", logic_structs[object_id]->GetName());
Tdebug("bones.txt", "%s: Simple look %d <%d,%d,%d> at speed %d", object_name, l, looks[l][2], looks[l][1], looks[l][0], STANDARD_LOOK_SPEED);
// sorry looks is wrong way round! (z,y,x)
logic_structs[object_id]->voxel_info->scriptedLookBoneTarget.vx = looks[l][2];
logic_structs[object_id]->voxel_info->scriptedLookBoneTarget.vy = looks[l][1];
logic_structs[object_id]->voxel_info->scriptedLookBoneTarget.vz = looks[l][0];
logic_structs[object_id]->voxel_info->lookBone.boneSpeed = STANDARD_LOOK_SPEED;
warning("doing a look direction: %d bone: %d", l, logic_structs[object_id]->voxel_info->lookBone.boneNumber);
return IR_CONT;
}
// set neck bone of current object
mcodeFunctionReturnCodes _game_session::fn_set_neck_bone(int32 &, int32 *params) {
int32 bone = params[0];
if (!logic_structs[cur_id]->mega)
Fatal_error("fn_set_neck_bone called by non mega %s", L->GetName());
Tdebug("bones.txt", "%s: Neck bone is %d", L->GetName(), bone);
logic_structs[cur_id]->voxel_info->lookBone.boneNumber = (int8)bone;
logic_structs[cur_id]->voxel_info->neckBone.boneNumber = (int8)bone;
return IR_CONT;
}
// set neck vector
// params
// 0 - x
// 1 - y
// 2 - z
// 3 - speed
// equiverlant to speech_set_neck_vector(NAME,x,y,z,speed)
// where NAME is object name...
//
mcodeFunctionReturnCodes _game_session::fn_set_neck_vector(int32 &, int32 *params) {
int32 x, y, z, speed;
x = params[0];
y = params[1];
z = params[2];
speed = params[3];
if (!logic_structs[cur_id]->mega)
Fatal_error("fn_set_neck_vector called by non mega %s", L->GetName());
int32 callingParams[5];
callingParams[0] = MemoryUtil::encodePtr((uint8 *)const_cast<char *>(L->GetName()));
callingParams[1] = x;
callingParams[2] = y;
callingParams[3] = z;
callingParams[4] = speed;
int32 ret;
return speak_set_neck_vector(ret, callingParams);
}
// set neck vector
// params
// 0 - "object"
// 1 - x
// 2 - y
// 3 - z
// 4 - speed
//
mcodeFunctionReturnCodes _game_session::speak_set_neck_vector(int32 &, int32 *params) {
int32 object_id;
int32 x, y, z, speed;
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
object_id = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
x = params[1];
y = params[2];
z = params[3];
speed = params[4];
if (L == player.log) {
warning("player set neck vector...");
logic_structs[object_id]->voxel_info->lookBone.boneNumber = 23;
}
if (!logic_structs[object_id]->mega)
Fatal_error("fn_set_neck_vector called by non mega %s", logic_structs[object_id]->GetName());
if (logic_structs[object_id]->voxel_info->lookBone.boneNumber == (int8)-1)
Fatal_error("fn_set_neck_vector called but no fn_set_neck_bone() has been called for object %s", logic_structs[object_id]->GetName());
Tdebug("bones.txt", "%s: Setting bone <%d,%d,%d> at speed %d", object_name, x, y, z, speed);
logic_structs[object_id]->voxel_info->scriptedLookBoneTarget.vx = (int16)x;
logic_structs[object_id]->voxel_info->scriptedLookBoneTarget.vy = (int16)y;
logic_structs[object_id]->voxel_info->scriptedLookBoneTarget.vz = (int16)z;
logic_structs[object_id]->voxel_info->lookBone.boneSpeed = (int16)speed;
return IR_CONT;
}
} // End of namespace ICB

46
engines/icb/bone.h Normal file
View File

@@ -0,0 +1,46 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_BONE_H
#define ICB_BONE_H
#include "engines/icb/common/px_bones.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/gfx/rap_api.h"
namespace ICB {
void UpdateTalking(_logic *log, RapAPI *rap);
void SetPlayerShotBone(int32 obj_id);
void ResetPlayerLook();
void UpdatePlayerLook();
} // End of namespace ICB
#endif // _BONE_H

181
engines/icb/breath.cpp Normal file
View File

@@ -0,0 +1,181 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/debug.h"
#include "engines/icb/mission.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/icb.h"
#include "engines/icb/breath.h"
namespace ICB {
mcodeFunctionReturnCodes fn_breath(int32 &result, int32 *params) { return (MS->fn_breath(result, params)); }
// fn_breath(on/off,x,y,z);
mcodeFunctionReturnCodes _game_session::fn_breath(int32 &, int32 *params) {
M->breath.on = (uint8)params[0];
M->breath.Init();
// location is not used at the moment
M->breath.position.vx = (int16)params[1];
M->breath.position.vy = (int16)params[2];
M->breath.position.vz = (int16)params[3];
return IR_CONT;
}
// init the breath, so we get a stream of breath....
Breath::Breath() {
on = BREATH_OFF; // off as default...
}
// smoke
// var /dt
// y (height) +rand
// z (out) +rand
// c (colour) -const
// s (size) +const
//
#define SMOKE_DY (6)
#define SMOKE_DZ (2)
#define SMOKE_DC (-2)
#define SMOKE_DS (4)
#define SMOKE_IY (0)
#define SMOKE_IZ (0)
#define SMOKE_IC (32)
#define SMOKE_IS (4)
#define BREATH_DY (-static_cast<int>(g_icb->getRandomSource()->getRandomNumber(2 - 1)))
#define BREATH_DZ (g_icb->getRandomSource()->getRandomNumber(4 - 1))
#define BREATH_DC (-4)
#define BREATH_DS (2)
#define BREATH_IY (0)
#define BREATH_IZ (0)
#define BREATH_IC (32)
#define BREATH_IS (2)
#define BREATH_WAIT_SECONDS 2
#define BREATH_WAIT (12 * BREATH_WAIT_SECONDS * BREATH_DC + BREATH_IC) // between breaths
void Breath::Init() {
breathEnd = (int16)(BREATH_WAIT);
int32 i;
for (i = 0; i < MAX_BREATH; i++) {
breathStarted[i] = 0;
if (on == BREATH_ON) {
breathColour[i] = (int16)(breathEnd - (BREATH_DC * i));
} else { // smoke...
breathColour[i] = (int16)(breathEnd - (SMOKE_DC * i));
}
}
// reset cycles count (smoke uses this to turn off)
allStarted = 0;
}
// update the breath every cycle
void Breath::Update() {
if (on) {
int32 i;
int32 numberStarted;
numberStarted = 0;
// update each particle
for (i = 0; i < MAX_BREATH; i++) {
// update
if (on == BREATH_ON) {
breathZ[i] = (int8)(breathZ[i] + BREATH_DZ);
breathY[i] = (int8)(breathY[i] + BREATH_DY);
breathSize[i] += BREATH_DS;
breathColour[i] += BREATH_DC;
} else { // smoking
breathZ[i] += SMOKE_DZ;
breathY[i] += SMOKE_DY;
breathSize[i] += SMOKE_DS;
breathColour[i] += SMOKE_DC;
}
// turn off
// if we have all started and we are ending and we are smoking then reset...
if ((breathColour[i] <= breathEnd) && (allStarted) && (on == BREATH_SMOKE)) {
breathStarted[i] = 1;
}
// otherwise reset it
else if (breathColour[i] <= breathEnd) {
// set values
if (on == BREATH_ON) {
breathZ[i] = BREATH_IZ;
breathY[i] = BREATH_IY;
breathSize[i] = BREATH_IS;
breathColour[i] = BREATH_IC;
} else { // smoke
breathZ[i] = SMOKE_IZ;
breathY[i] = SMOKE_IY;
breathSize[i] = SMOKE_IS;
breathColour[i] = SMOKE_IC;
}
// we have definitely started now!
breathStarted[i] = 1;
}
// for testing if all on (for smoke)
// to see if all have started
if (breathStarted[i])
numberStarted++;
}
if (on == BREATH_SMOKE) {
// if all have stopped and we are smoking then time to turn off
if ((numberStarted == MAX_BREATH) && (allStarted)) {
on = BREATH_OFF;
}
// if all started set it
else if (numberStarted == MAX_BREATH) {
allStarted = 1;
// reset this field (when they are all set again we can turn off)
for (i = 0; i < MAX_BREATH; i++)
breathStarted[i] = 0;
}
}
}
}
} // End of namespace ICB

61
engines/icb/breath.h Normal file
View File

@@ -0,0 +1,61 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_BREATH_H
#define ICB_BREATH_H
#include "engines/icb/common/px_common.h"
namespace ICB {
#define MAX_BREATH 8 // number of particles
#define BREATH_OFF 0
#define BREATH_ON 1
#define BREATH_SMOKE 2
class Breath {
public:
SVECTOR position; // 8 bytes?
int16 breathColour[MAX_BREATH]; // 8 bytes
int8 breathZ[MAX_BREATH]; // 4 bytes
int8 breathY[MAX_BREATH]; // 4 bytes
int8 breathSize[MAX_BREATH]; // 4 bytes
int8 breathStarted[MAX_BREATH]; // 4 bytes
int16 breathEnd; // 2 bytes
uint8 on; // 1 byte
int8 allStarted; // 1 byte (how many times reset)
Breath();
void Update();
void Init();
};
} // End of namespace ICB
#endif

598
engines/icb/camera.cpp Normal file
View File

@@ -0,0 +1,598 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/p4.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_game_object.h"
#include "engines/icb/common/px_scriptengine.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/session.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/debug.h"
#include "engines/icb/player.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/res_man.h"
#include "engines/icb/floors.h"
#include "engines/icb/mission.h"
namespace ICB {
#define RUBBER 30
#define REAL_RUBBER (30 * REAL_ONE)
PXvector *posi;
uint32 this_rect;
_floor *obfloor;
mcodeFunctionReturnCodes fn_floor_and_floor_camera_linked(int32 &result, int32 *params) { return (MS->fn_floor_and_floor_camera_linked(result, params)); }
mcodeFunctionReturnCodes fn_switch_to_manual_camera(int32 &result, int32 *params) { return (MS->fn_switch_to_manual_camera(result, params)); }
mcodeFunctionReturnCodes fn_cancel_manual_camera(int32 &result, int32 *params) { return (MS->fn_cancel_manual_camera(result, params)); }
mcodeFunctionReturnCodes fn_is_current_camera(int32 &result, int32 *params) { return (MS->fn_is_current_camera(result, params)); }
mcodeFunctionReturnCodes fn_is_current_location(int32 &result, int32 *params) { return (MS->fn_is_current_location(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_floor_and_floor_camera_linked(int32 &, int32 *params) {
// params 0 ascii name of home floor
// 1 ascii name of viewable floor name
// search for a camera of this name
// confirm floor exists
// add floor number to cameras extra floor list
uint32 home_floor_num;
uint32 floor_num;
const char *home_floor_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *floor_name = (const char *)MemoryUtil::resolvePtr(params[1]);
home_floor_num = floor_def->Fetch_floor_number_by_name(home_floor_name);
if (home_floor_num == PX_LINKED_DATA_FILE_ERROR)
Fatal_error("fn_floor_and_floor_camera_linked can't find floor [%s]", home_floor_name);
floor_num = floor_def->Fetch_floor_number_by_name(floor_name);
if (floor_num == PX_LINKED_DATA_FILE_ERROR)
Fatal_error("fn_floor_and_floor_camera_linked can't find floor [%s]", floor_name);
if (home_floor_num == floor_num)
Fatal_error("fn_floor_and_floor_camera_linked finds [%s] and [%s] are same floor!", home_floor_name, floor_name);
// add viewable floor number to the camera that displays our primary home floor
uint32 index1 = floor_to_camera_index[home_floor_num];
uint32 index2 = floor_to_camera_index[floor_num];
cam_floor_list[index1].extra_floors[cam_floor_list[index1].num_extra_floors++] = floor_num;
cam_floor_list[index2].extra_floors[cam_floor_list[index2].num_extra_floors++] = home_floor_num;
if (cam_floor_list[index1].num_extra_floors == MAX_extra_floors)
Fatal_error("fn_floor_and_floor_camera_linked too many extra floors");
return IR_CONT;
}
void _game_session::Build_camera_table() {
// read each floor to note the name of the camera
// each new camera name is put into a list of names
// the floor number gets the numer of that camerea in the list
uint32 j, k;
_floor *floor;
uint32 tot;
Zdebug("\n***********building camera table**************");
num_cameras = 0; // reset
// reset extra cams table
for (j = 0; j < MAX_floors; j++)
cam_floor_list[j].num_extra_floors = 0;
tot = floor_def->Fetch_total_floors();
if (!tot)
Fatal_error("Build_camera_table finds no floors?");
for (j = 0; j < tot; j++) {
floor = (_floor *)floor_def->Fetch_floor_number(j);
if (floor->camera_name_offset) {
// is this camera name already been assigned a slot?
k = 0;
while ((k < num_cameras) && (strcmp(camera_name_list[k], (((char *)floor) + floor->camera_name_offset))))
++k;
if (k == num_cameras) { // didn't find this camera
Zdebug(" new camera %d [%s] [%s]", num_cameras, (((char *)floor) + floor->camera_name_offset), floor->camera_cluster);
camera_name_list[num_cameras] = (((char *)floor) + floor->camera_name_offset); // add camera name to list of names
camera_cluster_list[num_cameras] = floor->camera_cluster;
floor_to_camera_index[j] = num_cameras; // set this floors camera number
num_cameras++;
} else {
floor_to_camera_index[j] = k; // set this floors camera number
}
Zdebug(" floor %d gets camera number %d", j, floor_to_camera_index[j]);
} else {
// camera name is missing
floor_to_camera_index[j] = NO_CAMERA_CHOSEN;
Zdebug("floor %d camera missing!!!!!!!!!!!", j);
}
}
Zdebug("***********building camera table**************\n");
}
bool8 _game_session::Object_visible_to_camera(uint32 id) {
// is id visible to current camera
uint32 j, num_extra;
#define FLOOR_NO logic_structs[id]->owner_floor_rect
#define MM logic_structs[id]->mega
// Don't want to see held objects
if (logic_structs[id]->ob_status == OB_STATUS_HELD)
return (FALSE8);
// high level user clip
if ((MM) && (!MM->display_me))
return FALSE8;
// check for no camera chosen - 1st cycle
if (cur_camera_number == NO_CAMERA_CHOSEN)
return (FALSE8);
// if following the player then always TRUE8 - need this because of rubber band
if ((!g_mission->camera_follow_id_overide) && (id == player.Fetch_player_id()))
return TRUE8;
if (floor_to_camera_index[FLOOR_NO] == cur_camera_number)
return (TRUE8);
// now check if the current floor is registered as an extra floor viewable from current camera
num_extra = cam_floor_list[cur_camera_number].num_extra_floors;
for (j = 0; j < num_extra; j++)
if (cam_floor_list[cur_camera_number].extra_floors[j] == FLOOR_NO)
return (TRUE8);
// definitely not on screen
return (FALSE8);
}
void _game_session::Reset_camera_director() {
// by masking this off we force a new camera to be initialised in current view mode
cur_camera_number = NO_CAMERA_CHOSEN;
manual_camera = FALSE8;
wa_camera = FALSE8;
wa_tied_to_pin = FALSE8;
wa_tied_to_exit_pin = FALSE8;
this_rect = 0; // will be legal floor which is all that matters
}
int32 Contains(int32 x1, int32 y1, int32 x2, int32 y2, int32 mx, int32 my) {
int32 tmp, x3;
x1 = x1 << 1;
y1 = y1 << 1;
x2 = x2 << 1;
y2 = y2 << 1;
mx = (mx << 1) + 1;
my = (my << 1) + 1;
if (((y1 < my) && (y2 > my)) || ((y1 > my) && (y2 < my))) {
if (x1 > x2) {
tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
}
if (y1 < y2)
x3 = x1 + (my - y1) * (x2 - x1) / (y2 - y1);
else
x3 = x2 - (my - y2) * (x2 - x1) / (y1 - y2);
if (x3 < mx)
return 1;
}
return 0;
}
void _game_session::Camera_director() {
// check which object the camera is linked to
// check which floor rect that object is on
// if no camera run a script
// else if new camera switch it in
const __aWalkArea *wa;
uint32 k;
uint32 hit;
PXreal sub1, sub2, len, y;
Prepare_camera_floors();
// a manual script camera completely overides the floor and WA system cameras
if ((manual_camera) || (camera_lock))
return;
// do walkarea stuff first
// are we currently on one?
// if so are we still on it
// if not are we on one in the list
// if so start it
// else go through normal floor system
if (wa_camera) {
// we are currently using a WA camera
wa = MS->wa_list[wa_number];
y = floor_def->Return_true_y((PXreal)wa->y);
if ((y >= obfloor->base_height) && (y < (floor_def->Fetch_floors_volume_height(this_rect)))) {
if (wa_tied_to_pin) {
// we are still tied to the pin point
// if we are within the stretch distance from the pin then we remain on the wa camera - even if we are now
// actually outside of it
sub1 = (PXreal)posi->x - wa_pin_x;
sub2 = (PXreal)posi->z - wa_pin_z;
// dist
len = (PXreal)((sub1 * sub1) + (sub2 * sub2));
Tdebug("rubber.txt", "len %3.2f pos %3.2f, %3.2f pin %3.2f, %3.2f", len, posi->x, posi->z, wa_pin_x, wa_pin_z);
if (len < (PXreal)(REAL_RUBBER * REAL_RUBBER))
return; // still constrained by the band
// band is broken
wa_tied_to_pin = FALSE8; // release
}
if ((posi->x > wa->x) && (posi->x < (wa->x + wa->w)) && (posi->z > wa->z) && (posi->z < (wa->z + wa->h))) {
// we're inside the rectangle
// are we within the polygon
hit = 0; // result is 0, miss
for (k = 0; k < (wa->noPoints - 1); k++) {
if (Contains(wa->points[k].x, wa->points[k].z, wa->points[k + 1].x, wa->points[k + 1].z, (uint32)posi->x, (uint32)posi->z))
hit = 1 - hit;
}
if (hit) { // hurrah - still hitting
cur_camera_number = floor_to_camera_index[this_rect];
return;
}
}
}
// only stick an off pin in if we're not wandering straight onto another
if (!Process_wa_list()) {
// not hitting anymore
if (!g_mission->camera_follow_id_overide)
this_rect = floor_def->Return_non_rubber_floor_no(logic_structs[player.Fetch_player_id()], this_rect);
else
this_rect = floor_def->Return_non_rubber_floor_no(logic_structs[g_mission->camera_follow_id_overide], this_rect);
// stick a pin in that we must leave before hitting a wa again
wa_pin_x = posi->x;
wa_pin_y = posi->y;
wa_pin_z = posi->z;
wa_tied_to_exit_pin = TRUE8;
cur_camera_number = NO_CAMERA_CHOSEN; // force a choose
wa_camera = FALSE8; // not any more
}
}
// not on one so check em all to see if we are
// but first check to see if we are tied to a get-off-wa pin
if (wa_tied_to_exit_pin) {
if (wa_pin_y != posi->y) { // as soon as we change y the pin breaks
wa_tied_to_exit_pin = FALSE8; // off
} else {
sub1 = (PXreal)posi->x - wa_pin_x;
sub2 = (PXreal)posi->z - wa_pin_z;
// dist
len = (PXreal)((sub1 * sub1) + (sub2 * sub2));
if (len > (PXreal)(REAL_RUBBER * REAL_RUBBER)) {
// band is broken
wa_tied_to_exit_pin = FALSE8; // release
}
}
} else {
Process_wa_list();
}
// not on a WA camera so check via the floor rects
if (this_rect == PXNULL) { // object not on a rect??
// we can't pick a camera set view
// if a set is set up then that will continue to be used
// if there isn't a set at all (this is first cycle) then engine will switch to nethack mode
return;
}
// has player changed camera - work this out from primary camera
if (cur_camera_number != floor_to_camera_index[this_rect]) {
// we are now on a floor with a different camera
// BUT
// we allow some elastic on the old one before switching
// get floor that we last changed camera on
// if we are within its bounds then remain
if (cur_camera_number != NO_CAMERA_CHOSEN) {
_floor *floor;
floor = (_floor *)floor_def->Fetch_floor_number(anchor_floor);
if ((posi->y == (PXreal)(floor->base_height)) && (posi->x >= (PXreal)(floor->rect.x1 - RUBBER)) && (posi->x <= (PXreal)(floor->rect.x2 + RUBBER)) &&
(posi->z >= (PXreal)(floor->rect.z1 - RUBBER)) && (posi->z <= (PXreal)(floor->rect.z2 + RUBBER)))
return; // still within the rubber banded camera
}
if (floor_to_camera_index[this_rect] == 0xffffffff) { // no named camera so its a more complex logic switch
// ok, lets assume that there was no special camera!
g_px->display_mode = TEMP_NETHACK; // stick us into temporary nethack mode which will bounce out again if it can
Zdebug("no named camera! - entering TEMP_NETHACK");
} else { // ok, there is a named camera! and we know its different from current
// different from current
Zdebug(" make cam=%s %s", camera_name_list[floor_to_camera_index[this_rect]], camera_cluster_list[floor_to_camera_index[this_rect]]);
// set camera number
cur_camera_number = floor_to_camera_index[this_rect];
anchor_floor = this_rect;
// if we're not in NETHACK mode then switch in the set
if (g_px->display_mode != NETHACK) {
g_px->display_mode = THREED; // force back in-case we were in TEMP_NETHACK
// init the new set - Initialise_set will record the name of the new camera
// it will also handle missing set files and bung us into TEMP_NETHACK mode if it has to
Initialise_set(camera_name_list[floor_to_camera_index[this_rect]], camera_cluster_list[floor_to_camera_index[this_rect]]); // name);
// force in the anims of megas not playing stand - techs and the like
MS->One_logic_cycle();
}
}
}
}
void _game_session::Prepare_camera_floors() {
// get floor numbers from followed object
// get a mega class objects world position - can be player or other mega
if (!g_mission->camera_follow_id_overide) {
if (!player.Player_exists())
Fatal_error("camera director can't choose a scene as player object has been shut down");
if (logic_structs[player.Fetch_player_id()]->ob_status == OB_STATUS_HELD)
Fatal_error("camera director can't choose a scene as player object has been shut down");
posi = (PXvector *)&logic_structs[player.Fetch_player_id()]->mega->actor_xyz;
this_rect = logic_structs[player.Fetch_player_id()]->owner_floor_rect;
} else {
// following another mega character
posi = (PXvector *)&logic_structs[g_mission->camera_follow_id_overide]->mega->actor_xyz;
this_rect = logic_structs[g_mission->camera_follow_id_overide]->owner_floor_rect;
}
// fetch the floor
obfloor = (_floor *)floor_def->Fetch_floor_number(this_rect);
}
bool8 _game_session::Process_wa_list() {
const __aWalkArea *wa;
uint32 j, k;
uint32 hit;
char *name;
PXreal y;
for (j = 0; j < MS->total_was; j++) {
wa = MS->wa_list[j];
y = floor_def->Return_true_y((PXreal)wa->y);
if ((y >= obfloor->base_height) && (y < (floor_def->Fetch_floors_volume_height(this_rect)))) {
if ((posi->x > wa->x) && (posi->x < (wa->x + wa->w)) && (posi->z > wa->z) && (posi->z < (wa->z + wa->h))) {
// we're inside the rectangle
// are we within the polygon
hit = 0; // result is 0, miss
for (k = 0; k < (wa->noPoints - 1); k++) {
if (Contains(wa->points[k].x, wa->points[k].z, wa->points[k + 1].x, wa->points[k + 1].z, (uint32)posi->x, (uint32)posi->z))
hit = 1 - hit;
}
if (hit) { // hey we hit the closed poly
name = (char *)const_cast<ICB::__point *>(&wa->points[wa->noPoints]);
Tdebug("cam_changes.txt", " WA camera name %s cluster %s", name, wa->cameraCluster);
Initialise_set(name, wa->cameraCluster); // name, clusterVersion of the name
wa_camera = TRUE8;
wa_number = j;
wa_pin_x = posi->x;
wa_pin_z = posi->z;
wa_tied_to_pin = TRUE8;
// in case we are coming here afresh - from a reset camera director - i.e. from nethack mode
// find the floor and set the current camera
// in other words we fake the system to think that the floor camera is chosen - that's how we decide
// who is on camera.
if (!g_mission->camera_follow_id_overide) {
this_rect = floor_def->Return_floor_rect(posi->x, posi->z, posi->y, 0);
} else {
this_rect = floor_def->Return_non_rubber_floor_no(logic_structs[g_mission->camera_follow_id_overide], this_rect);
}
// set camera number
cur_camera_number = floor_to_camera_index[this_rect];
Tdebug("cam_changes.txt", " floor %d", cur_camera_number);
return TRUE8;
}
}
}
}
return FALSE8;
}
mcodeFunctionReturnCodes _game_session::fn_switch_to_manual_camera(int32 &, int32 *params) {
// switch in a manual camera
// params 0 stub name of room - CORRIDOR\pc\camera
// 1 stub name of camera - corridor\pc\CAMERA
// 2 name of primary floor
uint32 floor_num;
uint32 len;
char h_buf[8];
const char *room_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *camera_name = (const char *)MemoryUtil::resolvePtr(params[1]);
const char *floor_name = (const char *)MemoryUtil::resolvePtr(params[2]);
// get primary floor number
floor_num = floor_def->Fetch_floor_number_by_name(floor_name);
// set camera number
cur_camera_number = floor_to_camera_index[floor_num];
manual_camera = TRUE8;
len = Common::sprintf_s(manual_camera_name, "%s\\pc\\%s", room_name, camera_name);
if (len > ENGINE_STRING_LEN)
Fatal_error("fn_switch_to_manual_camera string len error");
HashFile(manual_camera_name, h_buf);
Tdebug("cam_changes.txt", " built name %s %s", (const char *)temp_buf, h_buf);
Initialise_set(manual_camera_name, h_buf); // name);
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_is_current_camera(int32 &result, int32 *params) {
// check passed string against current camera
// params 0 ascii name
const char *camera_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// check for not set initialised yet - 1st game cycle
if (!set.OK()) {
result = 0;
return IR_CONT;
}
if (!strstr(set.GetSetName(), camera_name))
result = 0; // no
else
result = 1;
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_is_current_location(int32 &result, int32 *params) {
char h_buf[8];
uint32 len;
const char *location_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// First we need to know which location the player is in, because the information level
// for this is automatically at full.
//uint32 nPlayerFloorIndex = MS->logic_structs[MS->player.Fetch_player_id()]->owner_floor_rect;
Message_box("is %s current location?", location_name);
len = Common::sprintf_s(manual_camera_name, "%s\\pc\\%s", location_name, set.GetSetName());
if (len > ENGINE_STRING_LEN)
Fatal_error("fn_is_current_location string len error");
HashFile(manual_camera_name, h_buf);
result = 1;
// continue script
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_cancel_manual_camera(int32 &, int32 *) {
// cancel the manual camera
Tdebug("cam_changes.txt", "Releasing manual camera");
if (!manual_camera)
return IR_CONT;
Reset_camera_director();
return (IR_CONT);
}
// Compute if mega's are on or off current camera and send events to them to say "ON_CAMERA" / "OFF_CAMERA"
void _game_session::UpdateOnOffCamera() {
PXcamera &camera = GetCamera();
_logic *log;
for (uint32 j = 0; j < number_of_voxel_ids; j++) {
// fetch the logic structure for the game object that has a voxel image to render
log = logic_structs[voxel_id_list[j]];
// shift the this cycle camera flag to last cycle camera flag
log->mega->ShiftViewState();
// person owned by current camera floor? TEMP check
if (Object_visible_to_camera(voxel_id_list[j])) {
bool8 result = TRUE8;
PXvector filmPosition;
PXWorldToFilm(log->mega->actor_xyz, camera, result, filmPosition);
// i.e. his feet are visible !
if (result && (filmPosition.z < -g_actor_hither_plane))
log->mega->SetThisViewState(ON_CAMERA);
}
// Now test the view state flags and send an appropriate event
// Just walked on camera
if (log->mega->viewState == OFF_ON_CAMERA) {
g_oEventManager->PostNamedEvent(EVENT_ON_CAMERA, voxel_id_list[j]);
}
// Just walked off camera
else if (log->mega->viewState == ON_OFF_CAMERA) {
g_oEventManager->PostNamedEvent(EVENT_OFF_CAMERA, voxel_id_list[j]);
}
}
}
} // End of namespace ICB

855
engines/icb/chi.cpp Normal file
View File

@@ -0,0 +1,855 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/icb.h"
#include "engines/icb/session.h"
#include "engines/icb/mission.h"
#include "engines/icb/p4.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/sound.h"
#include "engines/icb/res_man.h"
namespace ICB {
mcodeFunctionReturnCodes fn_simple_chi(int32 &result, int32 *params) { return (MS->fn_simple_chi(result, params)); }
mcodeFunctionReturnCodes fn_chi(int32 &result, int32 *params) { return (MS->fn_chi(result, params)); }
mcodeFunctionReturnCodes fn_start_chi_following(int32 &result, int32 *params) { return (MS->fn_start_chi_following(result, params)); }
mcodeFunctionReturnCodes fn_record_player_interaction(int32 &result, int32 *params) { return (MS->fn_record_player_interaction(result, params)); }
mcodeFunctionReturnCodes fn_fetch_chi_mode(int32 &result, int32 *params) { return (MS->fn_fetch_chi_mode(result, params)); }
mcodeFunctionReturnCodes fn_check_for_chi(int32 &result, int32 *params) { return (MS->fn_check_for_chi(result, params)); }
mcodeFunctionReturnCodes fn_wait_for_chi(int32 &result, int32 *params) { return (MS->fn_wait_for_chi(result, params)); }
mcodeFunctionReturnCodes fn_send_chi_to_this_object(int32 &result, int32 *params) { return (MS->fn_send_chi_to_this_object(result, params)); }
mcodeFunctionReturnCodes fn_chi_wait_for_player_to_move(int32 &result, int32 *params) { return (MS->fn_chi_wait_for_player_to_move(result, params)); }
mcodeFunctionReturnCodes fn_stop_chi_following(int32 &result, int32 *params) { return (MS->fn_stop_chi_following(result, params)); }
mcodeFunctionReturnCodes fn_register_chi(int32 &result, int32 *params) { return (MS->fn_register_chi(result, params)); }
mcodeFunctionReturnCodes fn_send_chi_to_named_object(int32 &result, int32 *params) { return (MS->fn_send_chi_to_named_object(result, params)); }
mcodeFunctionReturnCodes fn_chi_heard_gunshot(int32 &result, int32 *params) { return (MS->fn_chi_heard_gunshot(result, params)); }
mcodeFunctionReturnCodes fn_calibrate_chi(int32 &result, int32 *params) { return (MS->fn_calibrate_chi(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_simple_chi(int32 &, int32 *) {
// simple chi that teleports around
Fatal_error("fn_simple_chi not supported");
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_start_chi_following(int32 &, int32 *) {
// the real chi
g_mission->chi_following = TRUE8;
chi_history = cur_history; // chi gets same point as cord
chi_think_mode = __FOLLOWING; // set mode
chi_do_mode = __THINKING; // thinking about following :)
chi_next_move = 100; // 100 cycles
Tdebug("chi.txt", "-+fn_start_chi_following - history=%d +-", chi_history);
permission_to_fire = FALSE8; // reset
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_stop_chi_following(int32 &, int32 *) {
// stop her
// do this before changing her to custom logics
g_mission->chi_following = FALSE8;
chi_think_mode = __NOTHING; // nowt
Tdebug("chi.txt", "-+fn_stop_chi_following");
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_record_player_interaction(int32 &, int32 *) {
// write the id of interact object to player history list
// advance history
cur_history++;
if (cur_history == MAX_player_history)
cur_history = 0; // wrap
// record it
history[cur_history].interaction = TRUE8;
history[cur_history].id = M->target_id;
Tdebug("history.txt", "-> [%s] %d", LinkedDataObject::Fetch_items_name_by_number(objects, M->target_id), M->target_id);
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_send_chi_to_named_object(int32 &, int32 *params) {
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
uint32 id;
id = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
if (id == 0xffffffff)
Fatal_error("fn_send_chi_to_named_object - illegal object [%s]", object_name);
// advance history
cur_history++;
if (cur_history == MAX_player_history)
cur_history = 0; // wrap
// record it
history[cur_history].interaction = TRUE8;
history[cur_history].id = id;
Tdebug("history.txt", ">> [%s] %d", CGameObject::GetName(object), cur_id);
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_send_chi_to_this_object(int32 &, int32 *) {
// write the id of calling object to player history list
// advance history
cur_history++;
if (cur_history == MAX_player_history)
cur_history = 0; // wrap
// record it
history[cur_history].interaction = TRUE8;
history[cur_history].id = cur_id;
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_fetch_chi_mode(int32 &result, int32 *) {
// returns the chi mode (__chi_think_mode) to script
result = (int32)chi_think_mode;
return IR_CONT;
}
__chi_think_mode _game_session::fn_fetch_chi_mode() {
// returns the chi mode (__chi_think_mode) to engine
return chi_think_mode;
}
mcodeFunctionReturnCodes _game_session::fn_chi_heard_gunshot(int32 &, int32 *) {
// called when chi hears a gunshot
// if we can see the player and same history - or, we're already in armed mode
if (((chi_history == cur_history) && (g_oLineOfSight->LineOfSight(cur_id, player.Fetch_player_id()))) || (chi_do_mode == __FIGHT_HELP)) {
permission_to_fire = 1; // chi can start fighting
}
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_calibrate_chi(int32 &, int32 *params) {
// set chi's near and far distances
// params 0 catch up distance
// 1 lost player distance
chi_catch_up_dist = (PXreal)(params[0] * params[0]);
chi_lost_dist = (PXreal)(params[1] * params[1]);
return IR_CONT;
}
void _game_session::Set_chi_permission() {
// called by players gunshot code
permission_to_fire = 1; // chi can start fighting
}
bool8 _game_session::Find_a_chi_target() {
// find an ememy for chi
uint32 j;
for (j = 0; j < number_of_voxel_ids; j++) {
if ((!logic_structs[voxel_id_list[j]]->mega->dead) && // alive
(logic_structs[voxel_id_list[j]]->ob_status != OB_STATUS_HELD) && // not held
(logic_structs[voxel_id_list[j]]->mega->is_evil) && // is evil
(Object_visible_to_camera(voxel_id_list[j])) && // on screen
(g_oLineOfSight->ObjectToObject(cur_id, voxel_id_list[j], LIGHT, 0, _line_of_sight::USE_OBJECT_VALUE,
TRUE8))) { // can see
chi_target_id = voxel_id_list[j];
chi_has_target = TRUE8;
Tdebug("chi_targets.txt", "chi selects [%s] as target", logic_structs[chi_target_id]->GetName());
return TRUE8;
}
}
chi_has_target = FALSE8;
// no
return FALSE8;
}
void _game_session::Chi_leaves_fight_mode() {
// set animation
L->cur_anim_type = __PULL_OUT_WEAPON;
I->IsAnimTable(L->cur_anim_type);
// get animation
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
// set to last frame
L->anim_pc = anim->frame_qty - 2; // if 10 frames then 10+1 (looper) == 11 meaning 9 is last displayable frame number
M->next_anim_type = __NO_ANIM;
chi_do_mode = __DISARM_TO_THINK; // back to thinking next cycle
}
mcodeFunctionReturnCodes _game_session::fn_chi(int32 &, int32 *) {
// the real chi
while (!Process_chi()) {
};
return IR_REPEAT;
}
bool8 _game_session::Process_chi() {
uint32 next_room;
PXreal x, z;
int32 result;
bool8 res;
PXreal sub1, sub2, cord_dist;
bool8 route_res;
switch (chi_do_mode) {
case __ANIMATE_TO_THINK:
if (Play_anim()) {
chi_do_mode = __THINKING;
}
return TRUE8;
break;
case __DISARM_TO_THINK:
if (Play_reverse_anim()) {
chi_do_mode = __THINKING;
Set_pose(__NOT_ARMED);
Change_pose_in_current_anim_set();
L->cur_anim_type = __STAND;
I->IsAnimTable(L->cur_anim_type);
}
return TRUE8;
break;
case __GET_WEAPON_OUT:
if (fight_pause)
fight_pause--;
else {
Set_pose(__GUN);
Change_pose_in_current_anim_set();
L->anim_pc = 0; // start here
L->cur_anim_type = __PULL_OUT_WEAPON;
M->next_anim_type = __STAND;
I->IsAnimTable(L->cur_anim_type);
Find_a_chi_target(); // select a target if there is one available
chi_do_mode = __ANIMATE_TO_FIGHT_HELP;
}
return TRUE8;
break;
case __ANIMATE_TO_FIGHT_HELP:
if (Play_anim()) {
chi_do_mode = __FIGHT_HELP;
}
return TRUE8;
break;
case __TURN_RND:
if (fast_face_rnd(2))
chi_do_mode = __FIGHT_HELP;
return TRUE8;
break;
case __TURN_TO_FACE_OBJECT:
if (fast_face_object(chi_target_id, 3)) {
chi_do_mode = __FIGHT_HELP;
}
return TRUE8;
break;
case __INTERACT_FOLLOW: // return from interact with ladder, stair, etc., here
// we then move the position on and think again
// arrived
chi_do_mode = __THINKING;
// move on to next position
chi_history += 1;
if (chi_history == MAX_player_history)
chi_history = 0; // wrap
chi_history += 1;
if (chi_history == MAX_player_history)
chi_history = 0; // wrap
chi_next_move = 12;
return TRUE8;
break;
case __ROUTING:
// first do a check to see if players wandered back onto our floor
// if we're on same floor as we started AND we meet player then stop
if ((history[chi_history].id == L->owner_floor_rect) && (L->owner_floor_rect == logic_structs[player.Fetch_player_id()]->owner_floor_rect)) {
chi_do_mode = __ANIMATE_TO_THINK;
chi_history = cur_history; // chi gets same point as cord
L->anim_pc = 0; // start here
L->cur_anim_type = __WALK_TO_STAND;
M->next_anim_type = __STAND;
return TRUE8;
}
// animate the route
if (Process_route()) {
// arrived
chi_do_mode = __THINKING;
// in-case last move pick a time to next move
chi_next_move = g_icb->getRandomSource()->getRandomNumber(200 - 1);
chi_next_move += 50;
// move on to next position
chi_history += 1;
if (chi_history == MAX_player_history)
chi_history = 0; // wrap
// cancel looping flag from the routing
L->looping = 0;
return TRUE8;
}
break;
case __CHASING:
// running after cord but on same floor
cord_dist = Cord_dist();
// animate the route
if ((Process_route()) || (chi_history != cur_history) ||
(cord_dist < (PXreal)(chi_catch_up_dist))) { // check for route done or player moved on in which case we quit the route and get following
// cancel looping flag from the routing
L->looping = 0;
if (chi_history == cur_history) {
// still on same floor - route has just finished naturally
// if we are within the zone then we come to a stand
if (cord_dist < (PXreal)(chi_lost_dist)) {
// within distance - so come to a stand
chi_do_mode = __ANIMATE_TO_THINK;
L->anim_pc = 0; // start here
L->cur_anim_type = __WALK_TO_STAND;
M->next_anim_type = __STAND;
chi_next_move = g_icb->getRandomSource()->getRandomNumber(200 - 1);
chi_next_move += 50;
return TRUE8;
}
}
// players gone or we're going to keep running
chi_do_mode = __THINKING;
chi_next_move = 1;
return FALSE8;
}
break;
case __BUMBLING:
// just ambling about the current room
cord_dist = Cord_dist();
// animate the route
if ((Process_route()) || ((chi_history != cur_history)) ||
(cord_dist < (PXreal)(chi_catch_up_dist / 2))) { // check for route done or player moved on in which case we quit the route and get following
// arrived
chi_do_mode = __THINKING;
// in-case last move pick a time to next move
chi_next_move = g_icb->getRandomSource()->getRandomNumber(200 - 1);
chi_next_move += 50;
// cancel looping flag from the routing
L->looping = 0;
if (chi_history == cur_history) {
// still on same floor - route has just finished naturally
// if we are within the zone then we come to a stand
if (cord_dist < (PXreal)(chi_catch_up_dist)) {
// within distance - so come to a stand
chi_do_mode = __ANIMATE_TO_THINK;
L->anim_pc = 0; // start here
L->cur_anim_type = __WALK_TO_STAND;
M->next_anim_type = __STAND;
return TRUE8;
}
}
return TRUE8;
}
break;
case __GO_CORD_GO:
// wait for player to moveout of a lift
sub1 = logic_structs[player.Fetch_player_id()]->mega->actor_xyz.x - M->actor_xyz.x;
sub2 = logic_structs[player.Fetch_player_id()]->mega->actor_xyz.z - M->actor_xyz.z;
// dist
if (((chi_history != cur_history)) || (((sub1 * sub1) + (sub2 * sub2)) > (PXreal)(100 * 100))) {
// players moved
Message_box("bye then");
chi_next_move = 1;
chi_do_mode = __THINKING;
}
return TRUE8;
break;
case __PAUSING:
break;
case __FIGHT_HELP: // help the player in a fight
// first see if players gone
if (chi_history != cur_history) {
Chi_leaves_fight_mode();
return TRUE8;
} else {
if (!fight_pause) {
// not got permission, can see player and player not armed - exit armed mode
if ((!permission_to_fire) && (!MS->logic_structs[player.Fetch_player_id()]->mega->Fetch_armed_status()) &&
(g_oLineOfSight->ObjectToObject(cur_id, player.Fetch_player_id(), LIGHT, 0, _line_of_sight::USE_OBJECT_VALUE, TRUE8))) {
// exit this mode
Chi_leaves_fight_mode();
return TRUE8;
}
// not on camera - then quit fight mode and catch up with player
if (!Object_visible_to_camera(chi_id)) {
// exit this mode
Chi_leaves_fight_mode();
return TRUE8;
}
// if can't see the player but would expect to (he's moved) then forget this and catch him up
if (!g_oLineOfSight->ObjectToObject(cur_id, player.Fetch_player_id(), LIGHT, 0, _line_of_sight::USE_OBJECT_VALUE, TRUE8)) {
// exit this mode
PXreal x2 = logic_structs[player.Fetch_player_id()]->mega->actor_xyz.x;
PXreal z2 = logic_structs[player.Fetch_player_id()]->mega->actor_xyz.z;
PXreal vect = PXAngleOfVector(z2 - M->actor_xyz.z, x2 - M->actor_xyz.x); // work out vector
if (PXfabs(L->pan - vect) < (FULL_TURN / 5)) {
Chi_leaves_fight_mode();
return TRUE8;
}
}
// got target but target is dead or not seeable - set no target
if (chi_has_target) {
if (logic_structs[chi_target_id]->mega->dead)
chi_has_target = 0; // dead so no target
if (!Object_visible_to_camera(chi_target_id))
chi_has_target = 0; // target is now off camera so forget it
}
// do something!
if ((chi_has_target) && (permission_to_fire)) {
// if right angle, shoot
// else turn to face
if (Need_to_turn_to_face_object(chi_target_id))
chi_do_mode = __TURN_TO_FACE_OBJECT;
else {
// shoot!
// play gun sound
if (MS->logic_structs[cur_id]->sfxVars[GUNSHOT_SFX_VAR] != 0)
RegisterSound(cur_id, nullptr, MS->logic_structs[cur_id]->sfxVars[GUNSHOT_SFX_VAR], gunDesc,
(int8)127); // have to use full version so we can give hash instead of string
else
RegisterSound(cur_id, defaultGunSfx, gunDesc); // use small version as we have string not hash
// dynamic light
M->SetDynamicLight(1, 255, 255, 255, 0, 150, 100, 200);
// Hey we are shooting
M->is_shooting = TRUE8;
L->anim_pc = 0; // start here
L->cur_anim_type = __STAND_AND_SHOOT;
M->next_anim_type = __STAND;
I->IsAnimTable(L->cur_anim_type);
chi_do_mode = __ANIMATE_TO_FIGHT_HELP;
fight_pause = (uint8)(1 + g_icb->getRandomSource()->getRandomNumber(10 - 1));
Call_socket(chi_target_id, "gun_shot", &result);
return TRUE8;
}
} else if (chi_has_target) {
// can't shoot
chi_do_mode = __TURN_TO_FACE_OBJECT;
} else {
// no target
// try to find new target
// yes, then set to turn
// no, turn to player
if (!Find_a_chi_target()) {
if (!fast_face_rnd(2))
chi_do_mode = __TURN_RND;
// cancel permission
permission_to_fire = 0;
} else { // found a new target
chi_do_mode = __TURN_TO_FACE_OBJECT; // turns to face new target
}
}
fight_pause = (uint8)(6 + g_icb->getRandomSource()->getRandomNumber(10 - 1));
} else {
fight_pause--;
}
}
break;
case __THINKING:
switch (chi_think_mode) {
case __FOLLOWING:
if (M->reverse_route)
Message_box("chi in reverse");
if (chi_history != cur_history) {
// player must have moved on one or more rooms but we can be certain the rooms are properly adjacent
// get next room
next_room = chi_history + 1;
if (next_room == MAX_player_history)
next_room = 0; // wrap
// is next entry a new floor or an object to interact with
if (history[next_room].interaction == TRUE8) {
// players interacted with something - a floor, lift, stairway, etc.
if (L->looping) {
L->looping = 0;
}
Set_motion(__MOTION_RUN);
res = chi_interacts(history[next_room].id, "chi");
if (!res)
res = chi_interacts(history[next_room].id, "interact");
if (!res) { // no interaction portal for chi - actually not possible now she can use the normal
// 'interact' script
chi_think_mode = __LOST; // oh dear, we must be lost. Not legal but lets handle it for now
Tdebug("chi.txt", "chi can't follow player via %d", history[next_room].id);
return TRUE8;
} else {
// ok, back to script
// script interpreter shouldn't write a pc back
chi_do_mode = __INTERACT_FOLLOW;
return (IR_GOSUB);
}
} else { // players gone to an adjacent floor
x = history[next_room].first_x;
z = history[next_room].first_z;
// if player is running then chi should run
// if chi is more than one behind chi should run
bool8 run = TRUE8;
if (Cord_dist() < (400 * 400))
run = FALSE8; // walk if near
// 0 result
// 1 x
// 2 z
// 3 0='walk', else 'run'
// 4 0=no turn-on-spot 1=yes
// 5 end on stand
if (!Setup_route(result, (int32)x, (int32)z, run, __ENDB, TRUE8)) {
// route failed or was no route required which in theory can't happen - so we take it as
// route failed to build
Tdebug("chi.txt", " route failed");
Setup_route(result, (int32)x, (int32)z, 1, __LASER, TRUE8);
}
Tdebug("chi.txt", " route made");
chi_do_mode = __ROUTING;
return TRUE8;
}
} else {
// same room - unless we started incorrectly, which we'll notice when we move
// decide on something to do then?
if (!chi_next_move) {
// create a coordinate to route to
bool8 ret = Make_floor_coordinate(&x, &z);
if (!ret) {
chi_next_move = 36; // try again in a second
return TRUE8; // make another next cycle and try again
}
session_barriers->Set_route_barrier_mask((int32)x - 300, (int32)x + 300, (int32)z - 300, (int32)z + 300);
route_res = Setup_route(result, (int32)x, (int32)z, 0, __FULL, 1); // walk
session_barriers->Clear_route_barrier_mask();
if (!route_res) {
// route failed or was no route required which in theory can't happen - so we take it as
// route failed to build
Tdebug("chi.txt", " bumble route failed");
chi_next_move = 36; // try again in a second
return TRUE8; // make another next cycle and try again
} else {
if (M->reverse_route)
Message_box("chi is reversing! do it - do it now");
chi_do_mode = __BUMBLING;
return TRUE8;
}
} else {
chi_next_move--; // reduce time to next
// see if we should fight help
// either we just heard player gunshot or we can see him and he's armed
if ((Object_visible_to_camera(chi_id)) && (Cord_dist() < (PXreal)(chi_lost_dist)) &&
(logic_structs[player.Fetch_player_id()]->mega->actor_xyz.y == M->actor_xyz.y))
if ((permission_to_fire) || ((g_oLineOfSight->LineOfSight(cur_id, player.Fetch_player_id())) &&
(MS->logic_structs[player.Fetch_player_id()]->mega->Fetch_armed_status()))) {
// has he got gun out?
chi_do_mode = __GET_WEAPON_OUT;
if (!permission_to_fire)
fight_pause = 3; // shes seen player arming - wait a bit
else
fight_pause = 0; // heard a shot - arm straight away
permission_to_fire = 0; // when armed - must see player shoot someone before she will shoot
return TRUE8;
}
// move if player a distance away
if ((Cord_dist() > (PXreal)(chi_lost_dist)) && (logic_structs[player.Fetch_player_id()]->mega->actor_xyz.y == M->actor_xyz.y) &&
(prev_save_state)) {
// 0 result
// 1 x
// 2 z
// 3 0='walk', else 'run'
// 4 0=no turn-on-spot 1=yes
// 5 end on stand
x = logic_structs[player.Fetch_player_id()]->mega->actor_xyz.x;
z = logic_structs[player.Fetch_player_id()]->mega->actor_xyz.z;
bool8 run = TRUE8;
bool8 eos = FALSE8;
if (Cord_dist() < (400 * 400)) {
run = FALSE8; // walk if near
eos = TRUE8; // end on stand
}
// set a barrier mask :(
session_barriers->Set_route_barrier_mask((int32)x - 450, (int32)x + 450, (int32)z - 450, (int32)z + 450);
route_res = Setup_route(result, (int32)x, (int32)z, run, __FULL, eos);
session_barriers->Clear_route_barrier_mask();
if (!route_res) {
// route failed or was no route required which in theory can't happen - so we take it
// as route failed to build
if (result == FALSE8)
Setup_route(result, (int32)x, (int32)z, run, __LASER, eos);
else
return TRUE8; // make another next cycle and try again
} else {
Tdebug("chi.txt", " route made");
if (M->reverse_route)
Message_box("chi is reversing! do it - do it now");
chi_do_mode = __CHASING;
return FALSE8;
}
}
// cancel permission - so we catch player gunshots immediately
permission_to_fire = 0;
}
}
break;
case __LOST:
// we're lost - but if the player turns up then we can restart
if (logic_structs[player.Fetch_player_id()]->owner_floor_rect == L->owner_floor_rect) {
chi_history = cur_history; // chi gets same point as cord
chi_think_mode = __FOLLOWING; // set mode
Tdebug("chi.txt", "chi is finds cord again - chi=%d, player=%d", chi_history, cur_history);
}
/* fall through */
case __NOTHING:
// dummy mode for when switched to custom logics
L->cur_anim_type = __STAND;
L->anim_pc = 0;
return (TRUE8);
break;
default:
Fatal_error("ilegal chi mode");
break;
}
break;
}
return (TRUE8);
}
PXreal _game_session::Cord_dist() {
// return cords distance from chi (or other mega depending upon where called)
PXreal sub1,
sub2;
sub1 = logic_structs[player.Fetch_player_id()]->mega->actor_xyz.x - M->actor_xyz.x;
sub2 = logic_structs[player.Fetch_player_id()]->mega->actor_xyz.z - M->actor_xyz.z;
// dist
return ((sub1 * sub1) + (sub2 * sub2));
}
mcodeFunctionReturnCodes _game_session::fn_check_for_chi(int32 &result, int32 *) {
// player wants to go down a lift so we must check to see if we need to tell chi to come over
// returns 0 no need to wait for chi
// 1 need to wait for chi
// default to no
result = 0;
// check there is a following chi
if (!is_there_a_chi)
return IR_CONT;
// not if held
if (logic_structs[chi_id]->ob_status == OB_STATUS_HELD)
return IR_CONT;
if (g_mission->chi_following) {
if (logic_structs[chi_id]->mega->dead) {
// chi is dead
result = 0;
return IR_CONT;
}
result = 1;
return IR_CONT;
// chi's got to come over and onto the platform
}
// not in follow mode
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_wait_for_chi(int32 &, int32 *) {
// waits for chi to register as having arrived
// this happens when she resets her following variables
if (chi_history == cur_history) {
// she's arrived
return IR_CONT;
}
return IR_REPEAT;
}
mcodeFunctionReturnCodes _game_session::fn_chi_wait_for_player_to_move(int32 &, int32 *) {
// set to go-cord-go wait mode
// used after lift movement
chi_history = cur_history; // chi gets same point as cord
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_register_chi(int32 &, int32 *) {
// tell engine there is a chi object
if (is_there_a_chi)
Fatal_error("double call to fn_register_chi");
Tdebug("chi.txt", "%s registers as chi", CGameObject::GetName(object));
is_there_a_chi = TRUE8;
chi_id = cur_id;
return IR_CONT;
}
bool8 _game_session::Make_floor_coordinate(PXreal *x, PXreal *z) {
// make a coordinate for the floor
if (!local_history_count)
return FALSE8;
int32 choice = g_icb->getRandomSource()->getRandomNumber(local_history_count - 1);
*x = local_history[choice].x;
*z = local_history[choice].z;
return TRUE8;
}
} // End of namespace ICB

View File

@@ -0,0 +1,407 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_string.h"
#include "engines/icb/res_man_pc.h"
#include "engines/icb/debug_pc.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/cluster_manager_pc.h"
#include "engines/icb/options_manager_pc.h"
#include "engines/icb/movie_pc.h"
#include "common/textconsole.h"
#include "common/file.h"
namespace ICB {
// Global ClusterManger instance
ClusterManager *g_theClusterManager;
// Function prototypes
void RecursivelyDeleteDirectory(const char *path);
void ValidateDirectoryToDelete(const char *path);
uint32 GetFileSize(const char *path);
void MakeDirectoryTree(MISSION_ID mission);
// Number of bytes to read from CD and write to hard disk per cycle
#define CHUNKSIZE 25600 // ((300 * 1024) / 12) based on 12fps for 2xCD drive
// This is the number of attempts we check the cd drive on the prompt screen
#define CD_SEARCH_DELAY 1000
// Private for the title background movie handling
MovieManager *g_while_u_wait_SequenceManager;
// Colours used by progress display
uint32 g_progressColourMap[7] = {
0x3C3C3C, // OFF 60 60 60
0xFEFEFE, // | 254 254 254
0xCAD5E4, // | 202 213 228
0xA6B8D4, // | 166 184 212
0x89A1C7, // | 137 161 199
0x587AB0, // V 88 122 176
0x2E579C // ON 46 87 156
};
// Controls the decay on the progress bit colouring
#define PROGRESS_BIT_DELAY 6
ClusterManager::ClusterManager() {
memset(m_cdroot1, 0, 1024);
memset(m_cdroot2, 0, 1024);
m_multipleCDDrives = FALSE8;
m_activeCDDrive = 1;
memset(m_missionDir, 0, 8);
m_bytesFreeOnInstalledDrive = 0;
m_minimumInstall = FALSE8;
memset(m_theList, 0, MAX_BYTESIZE_OF_A_FILELIST);
m_filelistTotalBytes = 0;
m_filelistCursor = -1;
m_filelistSize = 0;
m_src_fp = nullptr;
m_dst_fp = nullptr;
m_currentFileSize = 0;
m_chunkCounter = 0;
m_bytesDone = 0;
m_movieMemoryPointer = nullptr;
m_installDone = FALSE8;
memset(m_progressBits, 0, sizeof(PROGRESS_BIT) * NUMBER_OF_PROGRESS_BITS);
m_bitsDone = 0;
m_frameCounter = 0;
m_currentLanguage = T_ENGLISH;
}
ClusterManager::~ClusterManager() {}
void ClusterManager::Initialise() {
// First we need to discover what install method has been employed.
MinimumInstallCheck();
// Obtain drive information (CD path(s) and free space)
InterrogateDrives();
// Starting with an empty mission directory covers against the game
// crashing out or data being modified between executes.
CleanHardDisk();
// Require a disc on startup
CheckAnyDiscInserted();
// Line number 7398
const char *testline = g_theOptionsManager->GetTextFromReference(HashString("opt_missingdisc"));
if (strcmp(testline, "Please insert disc %d") == 0)
m_currentLanguage = T_ENGLISH;
else if (strcmp(testline, "Veuillez ins\xE9rer le disque %d") == 0)
m_currentLanguage = T_FRENCH;
else if (strcmp(testline, "Inserisci il disco %d") == 0)
m_currentLanguage = T_ITALIAN;
else if (strcmp(testline, "Bitte CD %d einlegen") == 0)
m_currentLanguage = T_GERMAN;
else if (strcmp(testline, "Por favor, inserta el disco %d") == 0)
m_currentLanguage = T_SPANISH;
else if (strcmp(testline, "\xC2\xF1\xF2\xE0\xE2\xFC\xF2\xE5 \xE4\xE8\xF1\xEA %d") == 0)
m_currentLanguage = T_RUSSIAN;
else
// Must be polish by default
m_currentLanguage = T_POLISH;
}
void ClusterManager::CheckDiscInserted(MISSION_ID /*mission*/) {
}
bool8 ClusterManager::CheckDiscInsertedWithCancel(MISSION_ID mission) {
// No user cancel
return FALSE8;
}
void ClusterManager::CheckAnyDiscInserted() {
}
bool8 ClusterManager::StartMissionInstall(MISSION_ID /*mission*/) {
return FALSE8;
}
bool8 ClusterManager::InstallMission() {
// Nothing to do on a full install
if (m_minimumInstall == FALSE8)
return FALSE8;
return FALSE8;
}
void ClusterManager::InterrogateDrives() {
}
void ClusterManager::CalculateFreeDiskSpace(void) {
m_bytesFreeOnInstalledDrive = 256 * 1024 * 1024;
}
char *ClusterManager::GetCDRoot(void) {
if (m_activeCDDrive == 1)
return m_cdroot1;
else
return m_cdroot2;
}
int32 ClusterManager::WhichCD(MISSION_ID mission) {
// All demos exist on one CD only
int32 demo = g_globalScriptVariables->GetVariable("demo");
if (demo != 0)
return 1;
if (mission >= MISSION1 && mission <= MISSION3)
return 1;
else if (mission >= MISSION4 && mission <= MISSION7)
return 2;
else if (mission >= MISSION8 && mission <= MISSION10)
return 3;
else
Fatal_error("ClusterManager::WhichCD() can't resolve unknown mission parameter");
// Never gonna get here are we
return 0;
}
bool8 ClusterManager::CheckForCD(int32 /*number*/) {
m_cdroot1[0] = '\0';
m_cdroot2[0] = '\0';
return TRUE8;
}
void ClusterManager::MinimumInstallCheck() {
m_minimumInstall = FALSE8;
}
bool8 ClusterManager::IsMissionDataInstalled(MISSION_ID &m) {
for (uint32 i = 0; i < NUMBER_OF_MISSIONS; i++) {
// Make the mission directories one by one and see if any exist
char h_mission[8];
HashFile(g_mission_names[i], h_mission);
pxString missionDirectory;
missionDirectory.Format("m\\%s\\", h_mission);
if (checkFileExists(missionDirectory)) {
m = (MISSION_ID)i;
return TRUE8;
}
}
// No mission directories on the hard disk
return FALSE8;
}
void ClusterManager::CleanHardDisk() {
// Can't be letting that happen now can we
if (m_minimumInstall == FALSE8)
return;
}
void ClusterManager::MissingCD(int32 /*number*/) {
}
bool8 ClusterManager::MissingCDWithCancel(int32 /*number*/) {
return FALSE8;
}
void ClusterManager::LoadFileList(MISSION_ID /*mission*/) {
if (m_minimumInstall == FALSE8)
return;
}
char *ClusterManager::GetFileListEntry() {
if (m_filelistCursor == -1)
Fatal_error("Can't retrieve filelist entry without loading a filelist first!");
char *line = nullptr;
// End of file check
if (m_filelistCursor < m_filelistSize) {
line = &(m_theList[m_filelistCursor]);
// Move to next line
m_filelistCursor += strlen((const char *)&(m_theList[m_filelistCursor]));
// Skip any terminators to get to the start of the next line
while (m_theList[m_filelistCursor] == 0)
m_filelistCursor++;
}
return line;
}
bool8 ClusterManager::DrawCoverFrame(void) {
// Draw a frame of the torture movie
g_while_u_wait_SequenceManager->drawFrame(working_buffer_id);
// Have we finished both movie playback and mission install
if (m_installDone) {
// Release bink from playing the movie
g_while_u_wait_SequenceManager->kill();
// Free up resources
delete[] m_movieMemoryPointer;
// Quit only when movie has finished
return FALSE8;
}
DrawProgressBits();
// Update screen manually
surface_manager->Flip();
return TRUE8;
}
void ClusterManager::InitialiseProgressBits() {
// Tweakable
int32 width = 5;
int32 height = 15;
int32 spacing = 2;
int32 initialY = SCREEN_DEPTH - height - 30;
// Calculate entire width so we can centre things
int32 length = (NUMBER_OF_PROGRESS_BITS * (width + spacing)) - spacing;
int32 initialX = (SCREEN_WIDTH / 2) - (length / 2);
for (int32 i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
m_progressBits[i].r.left = initialX;
m_progressBits[i].r.top = initialY;
m_progressBits[i].r.right = initialX + width;
m_progressBits[i].r.bottom = initialY + height;
m_progressBits[i].state = 0;
// Now increment
initialX += width + spacing;
}
m_bitsDone = 0;
}
void ClusterManager::UpdateProgressBits() {
if (m_frameCounter % PROGRESS_BIT_DELAY == 0) {
// Update the state of all bits
for (int32 i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
if (m_progressBits[i].state > 0 && m_progressBits[i].state != 6) {
m_progressBits[i].state = m_progressBits[i].state + 1;
}
}
}
// Bytes per progress bit
float progress_inc = (float)(m_filelistTotalBytes / NUMBER_OF_PROGRESS_BITS);
// The number of bits that should bit switched on
uint32 bitsOn = (int32)((float)m_bytesDone / progress_inc);
// Do we need to switch on a new bit
if (bitsOn > m_bitsDone) {
m_progressBits[m_bitsDone].state = 1;
m_bitsDone++;
}
}
void ClusterManager::DrawProgressBits() {
for (int32 i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
Fill_rect(m_progressBits[i].r.left, m_progressBits[i].r.top, m_progressBits[i].r.right, m_progressBits[i].r.bottom, g_progressColourMap[m_progressBits[i].state]);
}
}
void ClusterManager::Shutdown(void) {
}
void RecursivelyDeleteDirectory(const char * /*path*/) {
}
void ValidateDirectoryToDelete(const char *path) {
if (strcmp(path, pxVString("m\\FP3YNHA\\")) == 0)
return;
else if (strcmp(path, pxVString("m\\HWYIPVA\\")) == 0)
return;
else if (strcmp(path, pxVString("m\\TPQUB4D\\")) == 0)
return;
else if (strcmp(path, pxVString("m\\RIGABTB\\")) == 0)
return;
else if (strcmp(path, pxVString("m\\GAIYO3A\\")) == 0)
return;
else if (strcmp(path, pxVString("m\\NMUFF0B\\")) == 0)
return;
else if (strcmp(path, pxVString("m\\1QYUOAA\\")) == 0)
return;
else if (strcmp(path, pxVString("m\\TT3WADD\\")) == 0)
return;
else
Fatal_error(pxVString("ValidateDirectoryToDelete() failed on: %s", path));
}
uint32 GetFileSize(const char *path) {
Common::File file;
if (!file.open(path)) {
return 0;
}
return (uint32)file.size();
}
const char *MissionIdToName(MISSION_ID mission) {
switch (mission) {
case MISSION1:
return g_m01;
case MISSION2:
return g_m02;
case MISSION3:
return g_m03;
case MISSION4:
return g_m04;
case MISSION5:
return g_m05;
case MISSION7:
return g_m07;
case MISSION8:
return g_m08;
case MISSION9:
return g_m08;
case MISSION10:
return g_m10;
}
Fatal_error("MissionIdToName() should never get here - smack AndyB");
return nullptr;
}
void MakeDirectoryTree(MISSION_ID /*mission*/) {
}
} // End of namespace ICB

View File

@@ -0,0 +1,146 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_CLUSTER_MANAGER_PC_H_INCLUDED
#define ICB_CLUSTER_MANAGER_PC_H_INCLUDED
namespace ICB {
// Global cluster controller declaration
class ClusterManager;
class MovieManager;
extern ClusterManager *g_theClusterManager;
extern MovieManager *g_while_u_wait_SequenceManager;
// Byte limit of filelists
#define MAX_BYTESIZE_OF_A_FILELIST (4 * 1024)
enum MISSION_ID { MISSION1 = 0, MISSION2 = 1, MISSION3 = 2, MISSION4 = 3, MISSION5 = 4, MISSION7 = 5, MISSION8 = 6, MISSION9 = 7, MISSION10 = 8 };
#define NUMBER_OF_PROGRESS_BITS 32
typedef struct {
LRECT r;
int32 state;
} PROGRESS_BIT;
enum TLANGUAGE { T_ENGLISH, T_FRENCH, T_ITALIAN, T_GERMAN, T_SPANISH, T_RUSSIAN, T_POLISH };
class ClusterManager {
private:
// Drive path of CD drives on installed system
char m_cdroot1[1024];
char m_cdroot2[1024];
bool8 m_multipleCDDrives;
int32 m_activeCDDrive;
// Working mission directory name (hashed)
char m_missionDir[8];
// You guessed it
uint32 m_bytesFreeOnInstalledDrive;
// As cluster management is only necessary on minimum installs this
// acts as an on\off switch (state determined via VISE installer)
bool8 m_minimumInstall;
// Filelist handling
char m_theList[MAX_BYTESIZE_OF_A_FILELIST];
uint32 m_filelistTotalBytes;
int32 m_filelistCursor;
int32 m_filelistSize;
// These are to handle the chunk copying
Common::SeekableReadStream *m_src_fp;
Common::WriteStream *m_dst_fp;
uint32 m_currentFileSize;
uint32 m_chunkCounter;
uint32 m_bytesDone;
bool8 m_installDone;
// Pointer to memory resident bink file
char *m_movieMemoryPointer;
// Progress bar structures and counter
PROGRESS_BIT m_progressBits[NUMBER_OF_PROGRESS_BITS];
uint32 m_bitsDone;
// Used to control decay on progress bar
uint32 m_frameCounter;
TLANGUAGE m_currentLanguage;
public:
ClusterManager();
~ClusterManager();
// Startup
void Initialise();
// Useful methods for external modules
bool8 AreWeRunningAMinimumInstall() { return m_minimumInstall; }
char *GetCDRoot();
void CheckDiscInserted(MISSION_ID mission);
bool8 CheckDiscInsertedWithCancel(MISSION_ID mission);
void CheckAnyDiscInserted();
// These handle the mission swapping
bool8 StartMissionInstall(MISSION_ID mission);
bool8 InstallMission();
// Shutdown
void Shutdown();
// Language enquirer (set in Initialise() function called at startup)
TLANGUAGE GetLanguage() { return m_currentLanguage; }
private:
// Administration functions
void InterrogateDrives();
void CalculateFreeDiskSpace();
void MinimumInstallCheck();
bool8 IsMissionDataInstalled(MISSION_ID &m);
void CleanHardDisk();
int32 WhichCD(MISSION_ID mission);
bool8 CheckForCD(int32 number);
void MissingCD(int32 number);
bool8 MissingCDWithCancel(int32 number);
// Filelist handling
void LoadFileList(MISSION_ID mission);
char *GetFileListEntry();
// Visual update
bool8 DrawCoverFrame();
// Progress bar management
void InitialiseProgressBits();
void UpdateProgressBits();
void DrawProgressBits();
};
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,309 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/datapacker.h"
#include "common/stream.h"
#include "common/textconsole.h"
namespace ICB {
// Just initialise the buffer position and the min, max values
// used for packing and error detection
DataPacker::DataPacker() {
readMode = false;
iMode = NO_MODE;
iPackMode = NO_PACKMODE;
pos = 0;
packMin = -(1 << (PACK_BIT_SIZE - 1));
packMax = +((1 << PACK_BIT_SIZE) - 1);
// clear out the data buffer
ClearBuffer();
}
// Could do something here - but not sure what !
// Could error check on pos = 0 : but might lead to trouble
DataPacker::~DataPacker() {}
// Start the bit-packing process : say if we are in READ or WRITE mode
DataPacker::ReturnCodes DataPacker::open(const ModeEnum mode, const PackModeEnum packMode) {
if (pos != 0) {
return BAD_POS;
}
if ((mode != READ) && (mode != WRITE)) {
return BAD_MODE;
}
if ((packMode != PACK) && (packMode != DONT_PACK)) {
return BAD_PACKMODE;
}
if (mode == READ) {
readMode = true;
pos = PACK_CHUNK_SIZE;
}
if (mode == WRITE) {
readMode = false;
pos = 0;
}
// clear out the data buffer
ClearBuffer();
iMode = mode;
iPackMode = packMode;
return OK;
}
// Put a value into the bit-stream
DataPacker::ReturnCodes DataPacker::put(const int32 value, Common::WriteStream *stream) {
if (iMode != WRITE) {
return BAD_MODE;
}
if ((iPackMode != PACK) && (iPackMode != DONT_PACK)) {
return BAD_PACKMODE;
}
if ((pos < 0) || (pos >= PACK_CHUNK_SIZE)) {
return BAD_POS;
}
// For DONT_PACK mode just write the data straight out
if (iPackMode == DONT_PACK) {
// Check it is a legal value : 16-bits
int32 lvarMin = -(1 << 15);
int32 lvarMax = +((1 << 15) - 1);
if ((value < lvarMin) || (value > lvarMax)) {
return BAD_VALUE;
}
int32 nItems = 2;
int16 v16 = (int16)value;
int32 ret = stream->write((const void *)&v16, nItems);
if (ret != nItems) {
return WRITE_ERROR;
}
return OK;
}
// Convert the value to be within limits
int32 v = value - packMin;
// Check the value is within range
if ((v < 0) || (v > packMax)) {
return BAD_VALUE;
}
// Add the value in
if (pos == 0) {
buffer[0] = (uint8)((v >> 6) & 0xFF); // v's top 8-bits
buffer[1] = (uint8)((v & 0x3F) << 2); // v's bottom 6-bits into top 6-bits
} else if (pos == 1) {
buffer[1] |= ((v >> 12) & 0x03); // v's top 2-bits into bottom 2
buffer[2] = (uint8)((v >> 4) & 0xFF); // v's middle 8-bits
buffer[3] = (uint8)((v & 0x0F) << 4); // v's bottom 4-bits into top 4
} else if (pos == 2) {
buffer[3] |= ((v >> 10) & 0x0F); // v's top 4-bits into bottom 4
buffer[4] = (uint8)((v >> 2) & 0xFF); // v's middle 8-bits
buffer[5] = (uint8)((v & 0x03) << 6); // v's bottom 2-bits into top 2
} else if (pos == 3) {
buffer[5] |= ((v >> 8) & 0x3F); // v's top 6-bits into bottom 6
buffer[6] = (uint8)(v & 0xFF); // v's bottom 8-bits
}
// Put data into the next position !
pos++;
// Do we need to output the current buffer ?
if (pos == PACK_CHUNK_SIZE) {
#if 0
printf("WRITE %X %X %X %X %X %X %X",
buffer[0], buffer[1], buffer[2], buffer[3],
buffer[4], buffer[5], buffer[6]);
#endif // #if 0
// Write out the buffer
int32 nItems = BUFFER_BYTE_SIZE;
int32 ret = stream->write((const void *)buffer, nItems);
if (ret != nItems) {
return WRITE_ERROR;
}
pos = 0;
ClearBuffer();
}
return OK;
}
// Get a value from the bit-stream
DataPacker::ReturnCodes DataPacker::Get(int32 &value, Common::SeekableReadStream *stream) {
if (iMode != READ) {
return BAD_MODE;
}
if ((iPackMode != PACK) && (iPackMode != DONT_PACK)) {
return BAD_PACKMODE;
}
if ((pos < 0) || (pos > PACK_CHUNK_SIZE)) {
return BAD_POS;
}
// For DONT_PACK mode just read the data straight in
if (iPackMode == DONT_PACK) {
int32 nItems = 2;
int16 v16;
int32 ret = stream->read((void *)&v16, nItems);
value = v16;
if (ret != nItems) {
return READ_ERROR;
}
return OK;
}
// Do we need to fill up the current buffer ?
if (pos == PACK_CHUNK_SIZE) {
// Read into the buffer
int32 nItems = BUFFER_BYTE_SIZE;
int32 ret = stream->read((void *)buffer, nItems);
if (ret != nItems) {
return READ_ERROR;
}
#if 0
printf("READ %X %X %X %X %X %X %X",
buffer[0], buffer[1], buffer[2], buffer[3],
buffer[4], buffer[5], buffer[6]);
#endif
pos = 0;
}
int32 v = 0;
// Get the value out of the buffer
if (pos == 0) {
v = (buffer[0] << 6); // v's top 8-bits
v |= (buffer[1] >> 2); // v's bottom 6-bits into top 6-bits
} else if (pos == 1) {
v = ((buffer[1] & 0x03) << 12); // v's top 2-bits into bottom 2
v |= (buffer[2] << 4); // v's middle 8-bits
v |= (buffer[3] >> 4); // v's bottom 4-bits into top 4
} else if (pos == 2) {
v = ((buffer[3] & 0x0F) << 10); // v's top 4-bits into bottom 4
v |= (buffer[4] << 2); // v's middle 8-bits
v |= (buffer[5] >> 6); // v's bottom 2-bits into top 2
} else if (pos == 3) {
v = (buffer[5] & 0x3F) << 8; // v's top 6-bits into bottom 6
v |= buffer[6]; // v's bottom 8-bits
}
// Get data from the next position !
pos++;
// Check the value is within range
// This should just not be possible !
if ((v < 0) || (v > packMax)) {
return BAD_VALUE;
}
// Convert the extracted value to be in normal signed/unsigned limits
value = v + packMin;
return OK;
}
// Stop the bit-packing process : will output any remaining data
DataPacker::ReturnCodes DataPacker::close(Common::WriteStream *stream) {
if ((iMode == WRITE) && (pos != 0)) {
// Write out the remaining data items
int32 nItems = BUFFER_BYTE_SIZE;
int32 ret = stream->write((const void *)buffer, nItems);
if (ret != nItems) {
return WRITE_ERROR;
}
} else {
error("Wrong close-function called, passed WriteStream without being in WRITE-mode");
}
iMode = NO_MODE;
iPackMode = NO_PACKMODE;
pos = 0;
ClearBuffer();
return OK;
}
DataPacker::ReturnCodes DataPacker::close(Common::SeekableReadStream *stream) {
// TODO: If write mode.
if ((iMode == WRITE) && (pos != 0)) {
error("Wrong close-function called, passed ReadStream in WRITE-mode");
}
iMode = NO_MODE;
iPackMode = NO_PACKMODE;
pos = 0;
ClearBuffer();
return OK;
}
// Copy constructor
DataPacker::DataPacker(DataPacker &src) { *this = src; }
// Assignment operator
DataPacker &DataPacker::operator=(DataPacker &b) {
readMode = b.readMode;
iMode = b.iMode;
iPackMode = b.iPackMode;
pos = b.pos;
packMin = b.packMin;
packMax = b.packMax;
for (int32 i = 0; i < BUFFER_BYTE_SIZE; i++) {
buffer[i] = b.buffer[i];
}
return *this;
}
// Clear out the data buffer
void DataPacker::ClearBuffer() {
for (int32 i = 0; i < BUFFER_BYTE_SIZE; i++) {
buffer[i] = 0x00;
}
}
} // End of namespace ICB

View File

@@ -0,0 +1,89 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_DATAPACKER_HH
#define ICB_DATAPACKER_HH
#include "common/stream.h"
namespace ICB {
// Pack: 4 values into 4*14 bits = 56-bits = 7 bytes
#define BUFFER_BYTE_SIZE (7)
#define PACK_BIT_SIZE (14)
#define PACK_CHUNK_SIZE (4)
class DataPacker {
public:
DataPacker();
~DataPacker();
// Copy constructor
DataPacker(DataPacker &src);
// Assignment operator
DataPacker &operator=(DataPacker &b);
enum ModeEnum { NO_MODE, READ, WRITE };
enum PackModeEnum { NO_PACKMODE, PACK, DONT_PACK };
enum ReturnCodes { OK, BAD_POS, BAD_MODE, BAD_PACKMODE, READ_ERROR, WRITE_ERROR, BAD_READFUNC, BAD_WRITEFUNC, BAD_VALUE };
// Start the bit-packing process : say if we are in READ or WRITE mode
ReturnCodes open(const ModeEnum mode, const PackModeEnum packMode);
// Put a value into the bit-stream
ReturnCodes put(const int32 value, Common::WriteStream *fh);
// Get a value from the bit-stream
ReturnCodes Get(int32 &value, Common::SeekableReadStream *stream);
// Stop the bit-packing process : will output any remaining data
ReturnCodes close(Common::WriteStream *stream);
ReturnCodes close(Common::SeekableReadStream *stream);
// Simple inspectors
int32 Pos() const { return pos; }
int32 PackMin() const { return packMin; }
int32 PackMax() const { return packMax; }
private:
void ClearBuffer();
bool readMode;
ModeEnum iMode;
PackModeEnum iPackMode;
int32 pos;
int32 packMin;
int32 packMax;
uint8 buffer[BUFFER_BYTE_SIZE];
};
} // End of namespace ICB
#endif // #ifndef DATAPACKER_HH

View File

@@ -0,0 +1,347 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PC_PROPS_H
#define ICB_PC_PROPS_H
#include "engines/icb/common/px_staticlayers.h" // for types + defines
#include "engines/icb/common/px_types.h"
namespace ICB {
#define PCPROP_SCHEMA 3
#define PCPROP_ID MKTAG('p', 'o', 'r', 'P')
#define PCINTERACTIBLE_SCHEMA 2
#define PCINTERACTIBLE_ID MKTAG('k', 'c', 'a', 'T')
#define PCSETFILE_ID_ICB MKTAG('t', 'n', 'i', 'm')
#define PCSETFILE_ID_ELDORADO MKTAG('t', 'n', 'i', 'p')
typedef struct _pcSetHeader {
uint32 id;
uint32 cameraOffset;
uint32 lightOffset;
uint32 propOffset;
uint32 layerOffset;
uint32 backgroundOffset;
uint32 interactiblesOffset;
} _pcSetHeader;
class pcInteractible {
private:
char name[32];
int32 width;
int32 height;
int32 x;
int32 y;
uint8 *mask;
public:
pcInteractible(uint8 *interactiblePtr) {
uint8 *ptr = interactiblePtr;
memcpy(name, ptr, 32);
ptr += 32;
width = (int32)READ_LE_U32(ptr);
ptr += 4;
height = (int32)READ_LE_U32(ptr);
ptr += 4;
x = (int32)READ_LE_U32(ptr);
ptr += 4;
y = (int32)READ_LE_U32(ptr);
ptr += 4;
mask = ptr;
}
};
class pcInteractibleFile {
private:
uint32 id;
uint32 schema;
uint32 mapping;
uint32 quantity;
pcInteractible **interactibles;
public:
pcInteractibleFile() : id(PCINTERACTIBLE_ID), schema(PCINTERACTIBLE_SCHEMA), mapping(0), quantity(0), interactibles(nullptr) {}
pcInteractibleFile(uint8 *interactibleData) {
uint8 *ptr = interactibleData;
id = READ_LE_U32(ptr);
ptr += 4;
schema = READ_LE_U32(ptr);
ptr += 4;
mapping = READ_LE_U32(ptr);
ptr += 4;
quantity = READ_LE_U32(ptr);
ptr += 4;
interactibles = new pcInteractible *[quantity];
for (uint32 i = 0; i < quantity; i++) {
interactibles[i] = new pcInteractible(interactibleData + READ_LE_U32(ptr));
ptr += 4;
}
}
~pcInteractibleFile() {
for (uint32 i = 0; i < quantity; i++) {
delete interactibles[i];
}
delete[] interactibles;
interactibles = 0;
}
uint32 GetID() { return id; }
void SetId(uint32 i) { id = i; }
uint32 GetQty() { return quantity; }
void SetQty(uint32 q) { quantity = q; }
pcInteractible *GetInt(uint32 i) { return interactibles[i]; }
void SetSchema(uint32 s) { schema = s; }
uint32 GetSchema() const {
if (id != PCINTERACTIBLE_ID)
return 0;
else
return schema;
}
};
class pcPropRGBState {
private:
uint16 *zPtrs[TILE_COUNT];
uint16 *semiPtrs[TILE_COUNT];
uint16 nLRBgTiles;
uint16 nLRFgTiles;
uint16 nHRBgTiles;
uint16 nHRFgTiles;
uint32 *palettePtr;
uint16 bgLRSurfaceWidth;
uint16 bgLRSurfaceHeight;
uint16 fgLRSurfaceWidth;
uint16 fgLRSurfaceHeight;
uint16 bgHRSurfaceWidth;
uint16 bgHRSurfaceHeight;
uint16 fgHRSurfaceWidth;
uint16 fgHRSurfaceHeight;
uint8 *bgLRRleDataPtr;
uint8 *fgLRRleDataPtr;
uint8 *bgHRRleDataPtr;
uint8 *fgHRRleDataPtr;
LRECT *tileRects;
public:
pcPropRGBState(uint8 *propBasePtr, uint32 dataOffset) {
uint8 *ptr = propBasePtr + dataOffset;
for (int32 i = 0; i < TILE_COUNT; i++) {
zPtrs[i] = 0;
if (uint32 offset = READ_LE_U32(ptr)) {
zPtrs[i] = (uint16 *)(propBasePtr + offset);
}
ptr += 4;
}
for (int32 i = 0; i < TILE_COUNT; i++) {
semiPtrs[i] = 0;
if (uint32 offset = READ_LE_U32(ptr)) {
semiPtrs[i] = (uint16 *)(propBasePtr + offset);
}
ptr += 4;
}
nLRBgTiles = READ_LE_U16(ptr);
ptr += 2;
nLRFgTiles = READ_LE_U16(ptr);
ptr += 2;
nHRBgTiles = READ_LE_U16(ptr);
ptr += 2;
nHRFgTiles = READ_LE_U16(ptr);
ptr += 2;
palettePtr = (uint32 *)(propBasePtr + READ_LE_U32(ptr));
ptr += 4;
bgLRSurfaceWidth = READ_LE_U16(ptr);
ptr += 2;
bgLRSurfaceHeight = READ_LE_U16(ptr);
ptr += 2;
fgLRSurfaceWidth = READ_LE_U16(ptr);
ptr += 2;
fgLRSurfaceHeight = READ_LE_U16(ptr);
ptr += 2;
bgHRSurfaceWidth = READ_LE_U16(ptr);
ptr += 2;
bgHRSurfaceHeight = READ_LE_U16(ptr);
ptr += 2;
fgHRSurfaceWidth = READ_LE_U16(ptr);
ptr += 2;
fgHRSurfaceHeight = READ_LE_U16(ptr);
ptr += 2;
bgLRRleDataPtr = propBasePtr + READ_LE_U32(ptr);
ptr += 4;
fgLRRleDataPtr = propBasePtr + READ_LE_U32(ptr);
ptr += 4;
bgHRRleDataPtr = propBasePtr + READ_LE_U32(ptr);
ptr += 4;
fgHRRleDataPtr = propBasePtr + READ_LE_U32(ptr);
ptr += 4;
tileRects = (LRECT *)ptr;
}
uint16 *GetZTileTable(int32 t) { return zPtrs[t]; }
uint16 *GetSemiTileTable(int32 t) { return semiPtrs[t]; }
uint16 GetLRBgTileQty() { return nLRBgTiles; }
uint16 GetLRFgTileQty() { return nLRFgTiles; }
uint16 GetHRBgTileQty() { return nHRBgTiles; }
uint16 GetHRFgTileQty() { return nHRFgTiles; }
uint32 *GetPalette() { return palettePtr; }
uint16 GetLRBgSurfaceWidth() { return bgLRSurfaceWidth; }
uint16 GetLRBgSurfaceHeight() { return bgLRSurfaceHeight; }
uint16 GetLRFgSurfaceWidth() { return fgLRSurfaceWidth; }
uint16 GetLRFgSurfaceHeight() { return fgLRSurfaceHeight; }
uint16 GetHRBgSurfaceWidth() { return bgHRSurfaceWidth; }
uint16 GetHRBgSurfaceHeight() { return bgHRSurfaceHeight; }
uint16 GetHRFgSurfaceWidth() { return fgHRSurfaceWidth; }
uint16 GetHRFgSurfaceHeight() { return fgHRSurfaceHeight; }
uint8 *GetLRBgRlePtr() { return bgLRRleDataPtr; }
uint8 *GetLRFgRlePtr() { return fgLRRleDataPtr; }
uint8 *GetHRBgRlePtr() { return bgHRRleDataPtr; }
uint8 *GetHRFgRlePtr() { return fgHRRleDataPtr; }
LRECT *GetTileRects() { return tileRects; }
};
class pcPropRGB {
private:
char name[32];
uint32 stateQty;
pcPropRGBState **states;
public:
pcPropRGB(uint8 *propBasePtr, uint32 dataOffset) {
uint8 *ptr = propBasePtr + dataOffset;
memcpy(name, ptr, 32);
ptr += 32;
stateQty = READ_LE_U32(ptr);
ptr += 4;
states = new pcPropRGBState *[stateQty];
for (uint32 i = 0; i < stateQty; i++) {
states[i] = new pcPropRGBState(propBasePtr, READ_LE_U32(ptr));
ptr += 4;
}
}
~pcPropRGB() {
for (uint32 i = 0; i < stateQty; i++) {
delete states[i];
}
delete[] states;
states = 0;
}
const char *GetName() const { return name; }
uint32 GetStateQty() const { return stateQty; }
pcPropRGBState *GetState(uint32 s) { return states[s]; }
};
class pcPropFile {
private:
uint32 id;
uint32 schema;
uint32 mapping;
uint32 propQty;
pcPropRGB **props;
public:
pcPropFile(uint8 *propData) {
uint8 *ptr = propData;
id = READ_LE_U32(ptr);
ptr += 4;
schema = READ_LE_U32(ptr);
ptr += 4;
mapping = READ_LE_U32(ptr);
ptr += 4;
propQty = READ_LE_U32(ptr);
ptr += 4;
props = new pcPropRGB *[propQty];
for (uint32 i = 0; i < propQty; i++) {
props[i] = new pcPropRGB(propData, READ_LE_U32(ptr));
ptr += 4;
}
}
~pcPropFile() {
for (uint32 i = 0; i < propQty; i++) {
delete props[i];
}
delete[] props;
props = 0;
}
uint32 GetId() const { return id; }
uint32 GetPropQty() const { return propQty; }
pcPropRGB *GetProp(uint32 p) { return props[p]; }
uint32 GetSchema() const {
if (id != PCPROP_ID)
return 0;
else
return schema;
}
};
} // End of namespace ICB
#endif // #ifndef PC_PROPS_H

View File

@@ -0,0 +1,90 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/ptr_util.h"
#include "common/array.h"
namespace ICB {
Common::Array<PointerReference> *g_ptrArray;
namespace MemoryUtil {
const int32 PTR_ARRAY_MAX(1024);
uint32 encodePtr(uint8 *ptr) {
PointerReference ptrRef;
ptrdiff_t diff = ptr - (uint8 *)nullptr;
ptrRef.ref = (uint32)(diff & 0xFFFFFFFF);
ptrRef.ptr = ptr;
// find free slot
for (Common::Array<PointerReference>::iterator it = g_ptrArray->begin(); it < g_ptrArray->end(); it++) {
if (it->ref == 0) {
*it = ptrRef; // store
return ptrRef.ref;
}
}
// append
g_ptrArray->push_back(ptrRef);
if (g_ptrArray->size() >= (uint)PTR_ARRAY_MAX) {
error("MemoryUtil::encodePtr(): too many pointers (MAX = %u)\n", PTR_ARRAY_MAX);
}
return ptrRef.ref;
}
uint8 *resolvePtr(uint32 ref) {
if (ref == 0)
return nullptr;
// do a linear search
for (Common::Array<PointerReference>::iterator it = g_ptrArray->begin(); it < g_ptrArray->end(); it++) {
if (it->ref == ref) {
uint8 *ptr = it->ptr;
// purge
it->ref = 0;
it->ptr = nullptr;
return ptr;
}
}
error("MemoryUtil::resolvePtr(%08x) COULD NOT RESOLVE POINTER!\n", ref);
return nullptr;
}
void clearAllPtrs(void) { g_ptrArray->clear(); }
}
} // End of namespace ICB

View File

@@ -0,0 +1,53 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PTR_UTIL_H
#define ICB_PTR_UTIL_H
#include "engines/icb/common/px_common.h"
#include "common/array.h"
namespace ICB {
// map pointers to 32-bit references (bottom 32-bits of address)
struct PointerReference {
uint32 ref;
uint8 *ptr;
};
extern Common::Array<PointerReference> *g_ptrArray;
namespace MemoryUtil {
uint32 encodePtr(uint8 *ptr);
uint8 *resolvePtr(uint32 ptrRef);
void clearAllPtrs();
}
#endif // PTR_UTIL_H
} // End of namespace ICB

View 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_2drealline.h"
#include "math/utils.h"
namespace ICB {
typedef float PXfloat;
typedef float PXreal;
#define REAL_ZERO 0.0f
#define REAL_TWO 2.0f
#define REAL_MAX FLT_MAX
px2DRealLine::IntersectionLogicVal px2DRealLine::Intersects(const px2DRealLine &oLineB, px2DRealPoint &oIntersection) const {
PXfloat fAX, fBX, fCX, fAY, fBY, fCY;
PXfloat fX1Low, fX1High, fY1Low, fY1High;
PXfloat fD, fE, fF;
// Initialize return value (costs little and tidies up code no end).
oIntersection.SetX(REAL_MAX);
oIntersection.SetY(REAL_MAX);
// Work out some commonly used terms.
fAX = m_fX2 - m_fX1;
fBX = oLineB.m_fX1 - oLineB.m_fX2;
// X bounding box test.
if (fAX < REAL_ZERO) {
fX1Low = m_fX2;
fX1High = m_fX1;
} else {
fX1High = m_fX2;
fX1Low = m_fX1;
}
if (fBX > REAL_ZERO) {
if ((fX1High < oLineB.m_fX2) || oLineB.m_fX1 < fX1Low)
return DONT_INTERSECT;
} else {
if ((fX1High < oLineB.m_fX1) || oLineB.m_fX2 < fX1Low)
return DONT_INTERSECT;
}
// More common terms.
fAY = m_fY2 - m_fY1;
fBY = oLineB.m_fY1 - oLineB.m_fY2;
// Y bounding box test.
if (fAY < REAL_ZERO) {
fY1Low = m_fY2;
fY1High = m_fY1;
} else {
fY1High = m_fY2;
fY1Low = m_fY1;
}
if (fBY > REAL_ZERO) {
if ((fY1High < oLineB.m_fY2) || oLineB.m_fY1 < fY1Low)
return DONT_INTERSECT;
} else {
if ((fY1High < oLineB.m_fY1) || oLineB.m_fY2 < fY1Low)
return DONT_INTERSECT;
}
// Couldn't dismiss the lines on their bounding rectangles, so do a proper intersection.
fCX = m_fX1 - oLineB.m_fX1;
fCY = m_fY1 - oLineB.m_fY1;
fD = (fBY * fCX) - (fBX * fCY);
fF = (fAY * fBX) - (fAX * fBY);
if (fF > REAL_ZERO) {
if ((fD < REAL_ZERO) || (fD > fF))
return DONT_INTERSECT;
} else {
if ((fD > REAL_ZERO) || (fD < fF))
return DONT_INTERSECT;
}
fE = (fAX * fCY) - (fAY * fCX);
if (fF > REAL_ZERO) {
if ((fE < REAL_ZERO) || (fE > fF))
return DONT_INTERSECT;
} else {
if ((fE > REAL_ZERO) || (fE < fF))
return DONT_INTERSECT;
}
// At this point, we can say that the lines do intersect as int32 as they are not
// colinear (colinear is indicated by fF == 0.0).
if (fabs(fF - REAL_ZERO) < (FLT_MIN * 10.0f))
return COLLINEAR;
// Right, lines do intersect, so calculate where.
PXfloat fNum, fOffset;
fNum = fD * fAX;
fOffset = SameSigns(fNum, fF) ? fF / REAL_TWO : -fF / REAL_TWO;
oIntersection.SetX(m_fX1 + (fNum + fOffset) / fF);
fNum = fD * fAY;
fOffset = SameSigns(fNum, fF) ? fF / REAL_TWO : -fF / REAL_TWO;
oIntersection.SetY(m_fY1 + (fNum + fOffset) / fF);
return DO_INTERSECT;
}
} // End of namespace ICB

View File

@@ -0,0 +1,97 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX2DLINE_H_INCLUDED
#define ICB_PX2DLINE_H_INCLUDED
#include "engines/icb/common/px_array.h"
#include "engines/icb/common/px_2drealpoint.h"
namespace ICB {
// Note, this header file needs somethings :
// e.g. PXreal, REAL_ZERO
#ifndef REAL_ZERO
#error "REAL_ZERO not defined in px2drealline.h"
#endif // #ifndef REAL_ZERO
// Here I define an array type for the class. This neatens syntax and also allows pxArrays of pxArrays to be declared.
class px2DRealLine;
typedef rcActArray<px2DRealLine> px2DRealLineArray;
// Holds a line on a plane as a pair of integer endpoints, and provides functions for working with them.
class px2DRealLine {
public:
// Definitions for this class.
enum IntersectionLogicVal { DONT_INTERSECT, DO_INTERSECT, COLLINEAR };
// Default constructor and destructor.
inline px2DRealLine() {
m_fX1 = REAL_ZERO;
m_fY1 = REAL_ZERO;
m_fX2 = REAL_ZERO;
m_fY2 = REAL_ZERO;
}
inline ~px2DRealLine() { ; }
// Gets and sets.
PXreal GetX1() const { return m_fX1; }
PXreal GetY1() const { return m_fY1; }
PXreal GetX2() const { return m_fX2; }
PXreal GetY2() const { return m_fY2; }
void SetX1(PXreal fX1) { m_fX1 = fX1; }
void SetY1(PXreal fY1) { m_fY1 = fY1; }
void SetX2(PXreal fX2) { m_fX2 = fX2; }
void SetY2(PXreal fY2) { m_fY2 = fY2; }
// This determines whether this-> line intersects another.
IntersectionLogicVal Intersects(const px2DRealLine &oLineB, px2DRealPoint &oIntersection) const;
private:
PXreal m_fX1, m_fY1, m_fX2, m_fY2; // The line's endpoints.
// Functions used only by this class.
inline bool8 SameSigns(PXreal dA, PXreal dB) const;
};
inline bool8 px2DRealLine::SameSigns(PXreal fA, PXreal fB) const {
if (fA < REAL_ZERO) {
if (fB < REAL_ZERO)
return TRUE8;
else
return FALSE8;
} else {
if (fB < REAL_ZERO)
return FALSE8;
else
return TRUE8;
}
}
} // End of namespace ICB
#endif // #ifndef PX2DLINE_H_INCLUDED

View File

@@ -0,0 +1,69 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_2DREALPOINT_H_INCLUDED
#define ICB_PX_2DREALPOINT_H_INCLUDED
#include "engines/icb/common/px_rcutypes.h"
#include "engines/icb/common/px_common.h"
namespace ICB {
// A 2D point on a plane with endpoints stored as floating point.
class px2DRealPoint {
public:
// Default constructor and destructor.
px2DRealPoint() {
m_fX = REAL_ZERO;
m_fY = REAL_ZERO;
}
~px2DRealPoint() { ; }
// Alternative constructor that allows the point to be initialized.
px2DRealPoint(PXreal fX, PXreal fY) {
m_fX = fX;
m_fY = fY;
}
// Gets and sets.
void SetX(PXreal fX) { m_fX = fX; }
void SetY(PXreal fY) { m_fY = fY; }
PXreal GetX() const { return m_fX; }
PXreal GetY() const { return m_fY; }
// This allows the values of a point to be set after it has been created.
void Set(PXreal fX, PXreal fY) {
m_fX = fX;
m_fY = fY;
}
private:
PXreal m_fX, m_fY; // The point.
};
} // End of namespace ICB
#endif // #ifndef PX_2DREALPOINT_H_INCLUDED

View File

@@ -0,0 +1,95 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_3DREALPOINT_H_INCLUDED
#define ICB_PX_3DREALPOINT_H_INCLUDED
// Include the header files needed by this class.
#include "engines/icb/common/px_rcutypes.h"
namespace ICB {
// Note, this needs pre-definitions / typedef's of :
// PXreal, REAL_ZERO
// For PC PXreal = float, REAL_ZERO = 0.0f
// For PSX PXreal = int, REAL_ZERO = 0
#ifndef REAL_ZERO
#error "REAL_ZERO not defined"
#endif // #ifndef REAL_ZERO
// A 2D point on a plane with endpoints stored as floating point.
class px3DRealPoint {
public:
// Default constructor and destructor.
px3DRealPoint() {
m_fX = REAL_ZERO;
m_fY = REAL_ZERO;
m_fZ = REAL_ZERO;
}
~px3DRealPoint() { ; }
// Alternative constructor that allows the point to be initialized.
px3DRealPoint(PXreal fX, PXreal fY, PXreal fZ) {
m_fX = fX;
m_fY = fY;
m_fZ = fZ;
}
// Gets and sets.
void SetX(PXreal fX) { m_fX = fX; }
void SetY(PXreal fY) { m_fY = fY; }
void SetZ(PXreal fZ) { m_fZ = fZ; }
PXreal GetX() const { return m_fX; }
PXreal GetY() const { return m_fY; }
PXreal GetZ() const { return m_fZ; }
// This allows the values of a point to be set after it has been created.
void Set(PXreal fX, PXreal fY, PXreal fZ) {
m_fX = fX;
m_fY = fY;
m_fZ = fZ;
}
private:
PXreal m_fX, m_fY, m_fZ; // The point.
};
#if 0
inline bool8 px3DRealPoint::operator == (const px3DRealPoint &obOpB) const {
if ((PXfabs(m_fX - obOpB.m_fX) < (FLT_MIN * 5.0f)) &&
(PXfabs(m_fY - obOpB.m_fY) < (FLT_MIN * 5.0f)) &&
(PXfabs(m_fZ - obOpB.m_fZ) < (FLT_MIN * 5.0f)))
return TRUE8;
else
return FALSE8;
}
#endif
} // End of namespace ICB
#endif // #ifndef PX_3DREALPOINT_H_INCLUDED

View File

@@ -0,0 +1,172 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_ANIMS_H_
#define ICB_PX_ANIMS_H_
#include "engines/icb/common/px_common.h"
#include "common/endian.h"
namespace ICB {
#define PXANIM_SCHEMA 5
#define PXANIM_TAG "Peas"
#define ORG_POS 0
#define ORG_STRING "ORG"
#define INT_POS 1
#define INT_STRING "INT"
#define OBJ_STRING "OBJ"
#define ORG_TYPE 0
#define INT_TYPE 1
#define INT0_TYPE 2 // Forced export of INT marker on frame 0 of anim
#define TRI_TYPE 3
#define OBJ_TYPE 4
// PXmarker_PC : the PC version
typedef struct {
uint32 m_type;
float m_x, m_y, m_z;
float m_pan;
} PXmarker_PC;
// PXmarker_PC : the PC version
class PXmarker_PC_Object {
public:
static uint32 GetType(PXmarker_PC *marker) { return FROM_LE_32(marker->m_type); }
static void GetPan(PXmarker_PC *marker, float *pan) { *pan = FROM_LE_32(marker->m_pan); }
static void GetXYZ(PXmarker_PC *marker, float *x, float *y, float *z);
};
// PXframe_PC : the PC version //
typedef struct {
int16 left_foot_distance;
int16 right_foot_distance;
uint8 marker_qty;
uint8 leftFootStep;
uint8 rightFootStep;
uint8 pad3;
PXmarker_PC markers[1];
} PXframe_PC;
// PXmarker_PSX : the PSX version
typedef struct {
uint8 m_type;
uint8 x8;
uint16 x7y9;
uint32 y6z15pan11;
} PXmarker_PSX;
// PXmarker_PSX : the PSX version
class PXmarker_PSX_Object {
public:
static uint8 GetType(PXmarker_PSX *marker) { return marker->m_type; }
static void GetPan(PXmarker_PSX *marker, float *pan);
static void GetXYZ(PXmarker_PSX *marker, float *x, float *y, float *z);
};
inline void PXmarker_PSX_Object::GetPan(PXmarker_PSX *marker, float *pan) {
*pan = (float)(((FROM_LE_32(marker->y6z15pan11) & 0x7FF) << 1)) / 4096.0f;
}
inline void PXmarker_PSX_Object::GetXYZ(PXmarker_PSX *marker, float *x, float *y, float *z) {
int32 ix, iy, iz;
ix = ((marker->x8 << 7) | (FROM_LE_16(marker->x7y9) >> 9));
if (ix >= 16384)
ix = ix - 32768;
iy = (((FROM_LE_16(marker->x7y9) & 0x1FF) << 6) | (FROM_LE_32(marker->y6z15pan11) >> 26));
if (iy >= 16384)
iy = iy - 32768;
iz = ((FROM_LE_32(marker->y6z15pan11) >> 11) & 0x7FFF);
if (iz >= 16384)
iz = iz - 32768;
*x = (float)ix;
*y = (float)iy;
*z = (float)iz;
}
// PXframe_PSX : the PSX version //
typedef struct {
int16 left_foot_distance;
int16 right_foot_distance;
uint8 marker_qty;
uint8 leftFootStep;
uint8 rightFootStep;
uint8 pad3;
PXmarker_PSX markers[1];
} PXframe_PSX;
// PXanim //
typedef struct {
char tag[4];
int32 schema;
uint8 frame_qty;
uint8 speed;
uint16 offsets[1];
} PXanim_PSX;
typedef struct {
char tag[4];
int32 schema;
uint8 frame_qty;
uint8 speed;
uint16 offsets[1];
} PXanim_PC;
inline void ConvertPXanim(PXanim_PSX *anim) {
// Support old schema type files
if (FROM_LE_32(anim->schema) == PXANIM_SCHEMA - 1) {
int32 nFrames = anim->frame_qty;
anim->frame_qty = (uint8)nFrames;
anim->speed = 1;
anim->schema = TO_LE_32(PXANIM_SCHEMA);
}
}
inline void ConvertPXanim(PXanim_PC *anim) {
// Support old schema type files
if (FROM_LE_32(anim->schema) == PXANIM_SCHEMA - 1) {
int32 nFrames = anim->frame_qty;
anim->frame_qty = (uint8)nFrames;
anim->speed = 1;
anim->schema = TO_LE_32(PXANIM_SCHEMA);
}
}
// The animation, frame, marker
typedef PXframe_PSX PXframe;
typedef PXmarker_PSX PXmarker;
} // End of namespace ICB
#endif // _library__PX_ANIMS_H_

View File

@@ -0,0 +1,367 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_LIBRARY_CMYACTARRAY
#define ICB_LIBRARY_CMYACTARRAY
#include "engines/icb/common/px_rcutypes.h"
namespace ICB {
#define MY_TEMPLATE template <class Type>
#define T_MYACTARRAY rcActArray<Type>
#define T_MYPTRARRAY rcAutoPtrArray<Type>
MY_TEMPLATE class rcActArray {
public:
rcActArray() { // Construct an empty array
m_userPosition = m_allocatedSize = 0;
}
rcActArray(rcActArray &a) {
m_userPosition = m_allocatedSize = 0;
(*this) = a;
}
~rcActArray(); // Destruct the array
void operator=(const rcActArray &);
// Member access functions
uint32 GetNoItems() const { return (m_userPosition); }
uint32 Add(const Type &f); // Add an item.
Type &operator[](uint32); // Give access to an entry
const Type &operator[](uint32 i) const;
void SetSize(uint32 n) { ResizeArray(n); }
void Reset();
private:
uint32 m_userPosition; // Next place to add an item to
uint32 m_allocatedSize; // How many items have been allocated
Type **m_contents; // A pointer to pointers to the objects
void ResizeArray(uint32); // Change the size of the array
};
MY_TEMPLATE
void T_MYACTARRAY::operator=(const rcActArray &a) {
if (m_allocatedSize)
delete[] m_contents;
m_userPosition = a.m_userPosition;
m_allocatedSize = a.m_allocatedSize;
if (m_allocatedSize)
{
m_contents = new Type *[m_allocatedSize];
for (uint32 count = 0; count < m_allocatedSize; count++)
m_contents[count] = new Type(*(a.m_contents[count]));
}
}
MY_TEMPLATE
Type &T_MYACTARRAY::operator[](uint32 n) {
if (n >= m_userPosition) {
ResizeArray(n);
m_userPosition = n + 1;
}
return (*(m_contents[n]));
}
MY_TEMPLATE
const Type &T_MYACTARRAY::operator[](uint32 n) const {
// It is permissible to look at an element that has not been defined, as the constructor assures
// that the contents are valid
if (n >= m_userPosition) {
// Remove any 'constness' for a resize
(const_cast<rcActArray<Type> *>(this))->ResizeArray(n);
(const_cast<rcActArray<Type> *>(this))->m_userPosition = n + 1;
}
return (*(m_contents[n]));
}
MY_TEMPLATE T_MYACTARRAY::~rcActArray() { Reset(); }
MY_TEMPLATE void T_MYACTARRAY::Reset() {
for (uint32 count = 0; count < m_allocatedSize; count++)
delete m_contents[count];
if (m_allocatedSize)
delete[] m_contents;
m_allocatedSize = 0;
m_userPosition = 0;
}
MY_TEMPLATE void T_MYACTARRAY::ResizeArray(uint32 n2) {
// if n is still within the allocated area then just set the last position
if (n2 >= m_allocatedSize) {
// Make sure we are going to make the thing big enough
uint32 nextSize = m_allocatedSize ? m_allocatedSize + m_allocatedSize : 1; // Double, or 1 if now 0
while (nextSize <= n2)
nextSize += nextSize;
// Get a New pointer array of the correct size
Type **newArray = new Type *[nextSize];
if (m_allocatedSize > 0) {
// Copy in the old stuff
memcpy((unsigned char *)newArray, (unsigned char *)m_contents, m_allocatedSize * sizeof(Type *));
}
// Put empty objects in the newly allocated space
for (uint32 newObjects = m_allocatedSize; newObjects < nextSize; newObjects++)
newArray[newObjects] = new Type;
// Remove any old stuff
if (m_allocatedSize)
delete[] m_contents;
m_contents = newArray;
m_allocatedSize = nextSize;
}
}
MY_TEMPLATE uint32 T_MYACTARRAY::Add(const Type &f) {
operator[](m_userPosition) = f;
return (m_userPosition - 1);
}
MY_TEMPLATE class rcAutoPtrArray {
uint32 m_noContents; // How many entries have been allocated
uint32 m_userPosition; // Next position for the Add command
Type **m_contents; // A pointer to pointers to the objects
void ResizeArray(uint32); // Change the size of the array
public:
explicit rcAutoPtrArray() { // Construct an empty array
m_noContents = m_userPosition = 0;
}
~rcAutoPtrArray(); // Destruct the array
// Member access functions
uint32 GetNoItems() const { return (m_userPosition); }
uint32 Add(Type *f) {
operator[](m_userPosition) = f;
return (m_userPosition - 1);
}
Type *&operator[](uint32); // Give access to an entry
const Type *&operator[](uint32) const; // Give access to an entry
void Reset();
void RemoveAndShuffle(uint32); // Remove an object from the array
void SetSize(uint32 n) { ResizeArray(n); }
// Super dangerous, but faster, access to the array
Type *GetRawArray() { return (*m_contents); }
private: // Prevent use of the PtrArray copy constructor
// The default copy constructor should never be called
rcAutoPtrArray(const rcAutoPtrArray &) {}
void operator=(const rcAutoPtrArray &) {}
};
MY_TEMPLATE
Type *&T_MYPTRARRAY::operator[](uint32 n) {
if (n >= m_userPosition) {
ResizeArray(n);
m_userPosition = n + 1;
}
return (m_contents[n]);
}
MY_TEMPLATE
const Type *&T_MYPTRARRAY::operator[](uint32 n) const {
// It is permissible to look at an element that has not been defined, as it will be defined as NULL
if (n >= m_userPosition) {
(const_cast<rcAutoPtrArray<Type> *>(this))->ResizeArray(n);
(const_cast<rcAutoPtrArray<Type> *>(this))->m_userPosition = n + 1;
}
return const_cast<const Type *&>(m_contents[n]);
}
MY_TEMPLATE T_MYPTRARRAY::~rcAutoPtrArray() { Reset(); }
MY_TEMPLATE void T_MYPTRARRAY::Reset() {
// The pointer array maintains responsibility for deleting any contents
for (uint32 count = 0; count < m_userPosition; count++)
if (m_contents[count])
delete m_contents[count];
if (m_noContents)
delete[] m_contents;
m_noContents = m_userPosition = 0;
}
MY_TEMPLATE void T_MYPTRARRAY::ResizeArray(uint32 n2) {
if (n2 >= m_noContents) {
// Double the allocation value
uint32 nextSize = m_noContents > 0 ? m_noContents + m_noContents : 1;
while (n2 >= nextSize)
nextSize = nextSize + nextSize;
// Get a New pointer array of the correct size
Type **newArray = new Type *[nextSize];
// Copy in the old stuff, if there is any
if (m_noContents > 0)
memcpy((unsigned char *)newArray, (unsigned char *)m_contents, m_noContents * sizeof(Type *));
// Reset the New entries
memset((unsigned char *)(newArray + m_noContents), 0, (nextSize - m_noContents) * sizeof(Type *));
// Remove any old stuff
if (m_noContents)
delete[] m_contents;
m_contents = newArray;
m_noContents = nextSize;
}
}
MY_TEMPLATE void T_MYPTRARRAY::RemoveAndShuffle(uint32 n) {
// Remove an object from the array
// First delete it
if (m_contents[n])
delete m_contents[n];
// and shuffle the array
memcpy(m_contents + n, m_contents + n + 1, (m_noContents - n - 1) * sizeof(Type *));
}
template <class Type> class rcIntArray {
uint32 m_noContents; // How many entries there are
uint32 m_userPosition; // Where the next add position goes
Type *m_contents;
void ResizeArray(uint32); // Change the size of the array
public:
explicit rcIntArray() { // Construct an empty array
m_noContents = m_userPosition = 0;
}
~rcIntArray() { // Destruct the array
if (m_noContents)
delete[] m_contents;
}
// Copy constructor
rcIntArray(const rcIntArray &a) {
m_noContents = m_userPosition = 0;
(*this) = a;
}
// Constructor with an initial size
rcIntArray(uint32 initialSize) { ResizeArray(initialSize); }
const rcIntArray &operator=(const rcIntArray &);
// Member access functions
uint32 GetNoItems() const { return (m_userPosition); }
uint32 Add(Type f); // Add an integer. Only makes sense if the resize step is one
Type &operator[](uint32); // Give access to an entry
const Type operator[](uint32) const; // Give access to an entry
void Reset();
void SetSize(uint32 n) { ResizeArray(n); }
Type *GetRawArray() { return (m_contents); }
};
template <class Type> Type &rcIntArray<Type>::operator[](uint32 index) {
if (index >= m_userPosition) {
ResizeArray(index);
m_userPosition = index + 1;
}
return m_contents[index];
}
// This version of [] allows the array to be part of a const function
template <class Type> const Type rcIntArray<Type>::operator[](uint32 index) const {
// It is permissible to look at an element that has not been defined, as it will have been set to 0
if (index >= m_userPosition) {
// Remove any 'constness' for a resize
(const_cast<rcIntArray<Type> *>(this))->ResizeArray(index);
(const_cast<rcIntArray<Type> *>(this))->m_userPosition = index + 1;
}
return m_contents[index];
}
template <class IntType> void rcIntArray<IntType>::ResizeArray(uint32 accessedSize) {
// Check if we need to do any reallocating
if (accessedSize >= m_noContents) {
uint32 newSize = m_noContents > 0 ? m_noContents * 2 : 1;
while (newSize <= accessedSize)
newSize = newSize + newSize;
IntType *newArray = new IntType[newSize];
if (m_noContents)
memcpy(newArray, m_contents, m_noContents * sizeof(IntType));
// Call me a fool, but I like my integers initialised to 0
memset(newArray + m_noContents, 0, (newSize - m_noContents) * sizeof(IntType));
if (m_noContents)
delete[] m_contents;
m_contents = newArray;
m_noContents = newSize;
}
}
template <class IntType> const rcIntArray<IntType> &rcIntArray<IntType>::operator=(const rcIntArray<IntType> &obOpB) {
uint32 nCount;
if (m_noContents)
delete[] m_contents;
m_userPosition = obOpB.m_userPosition;
m_noContents = obOpB.m_noContents;
if (m_noContents) {
m_contents = new IntType[m_noContents];
for (nCount = 0; nCount < m_noContents; nCount++)
m_contents[nCount] = obOpB.m_contents[nCount];
}
return *this;
}
template <class Type> void rcIntArray<Type>::Reset() {
// CLear out the array
if (m_noContents) {
delete[] m_contents;
m_noContents = m_userPosition = 0;
}
}
template <class Type> uint32 rcIntArray<Type>::Add(Type f) {
// Add an integer. Only makes sense if the resize step is one
operator[](m_userPosition) = f;
return (m_userPosition - 1);
}
} // End of namespace ICB
#endif // ndef _LIBRARY_CMYACTARRAY

View File

@@ -0,0 +1,42 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_BITMAP_H_INCLUDED
#define ICB_PX_BITMAP_H_INCLUDED
#include "engines/icb/common/px_bitmap_pc.h"
namespace ICB {
typedef _pxPCBitmap _pxBitmap;
typedef _pxPCSprite _pxSprite;
#define PX_BITMAP_EXT PX_BITMAP_PC_EXT
#define PX_BITMAP_SCHEMA PC_BITMAP_SCHEMA
#define PX_BITMAP_ID PC_BITMAP_ID
} // End of namespace ICB
#endif // #ifndef _PX_BITMAP_H_INCLUDED

View File

@@ -0,0 +1,63 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_BITMAP_PC_H_INCLUDED
#define ICB_PX_BITMAP_PC_H_INCLUDED
#include "engines/icb/common/px_common.h"
namespace ICB {
// These define the extension for the finding the bitmap files
#ifndef PX_BITMAP_PC_EXT
#define PX_BITMAP_PC_EXT "bitmap_pc"
#endif
// Replaced pxHeader with id and added schema control to datafiles
#define PC_BITMAP_SCHEMA 1
#define PC_BITMAP_ID "PCB"
// Data structure to overlay the sprite data.
typedef struct {
uint32 x, y; // X and Y position of sprite.
uint32 width, height; // Width and height of the sprite in pixels.
uint8 data[1]; // Sprite data.
} _pxPCSprite;
typedef struct _pxPCBitmap {
char id[4]; // "PCB" Pc bitmap
uint32 schema; // The current schema number
uint8 palette[4 * 256]; // RGB but padded with 0 to 32-bits.
uint32 num_sprites; // Number of sprites in this file.
uint32 sprite_offsets[1]; // Offsets to sprite data for each sprite.
} _pxPCBitmap;
} // End of namespace ICB
#endif // #ifndef _PX_BITMAP_PC_H_INCLUDED

View File

@@ -0,0 +1,53 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/gfx/psx_pcdefines.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_bones.h"
namespace ICB {
void BoneDeformation::UpdateBoneValue(short &v, short t) {
if (v < t) {
v = (int16)(v + boneSpeed);
if (v > t)
v = t;
} else if (v > t) {
v = (int16)(v - boneSpeed);
if (v < t)
v = t;
}
}
void BoneDeformation::Target0() { boneTarget.vx = boneTarget.vy = boneTarget.vz = 0; }
void BoneDeformation::Update() {
UpdateBoneValue(boneValue.vx, boneTarget.vx);
UpdateBoneValue(boneValue.vy, boneTarget.vy);
UpdateBoneValue(boneValue.vz, boneTarget.vz);
}
} // End of namespace ICB

View File

@@ -0,0 +1,62 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_BONES_H
#define ICB_PX_BONES_H
#include "engines/icb/common/px_common.h"
namespace ICB {
// maximum number of deformations
#define MAX_DEFORMABLE_BONES 4
// the deformations being used (so standard across tools/engine...
#define JAW_DEFORMATION 0
#define NECK_DEFORMATION 1
#define LOOK_DEFORMATION 2
#define SPARE_DEFORMATION 3
class BoneDeformation {
public:
BoneDeformation() {
boneTarget.vx = boneTarget.vy = boneTarget.vz = boneValue.vx = boneValue.vy = boneValue.vz = 0;
boneNumber = -1;
}
int16 boneNumber;
int16 boneSpeed;
SVECTOR boneValue;
SVECTOR boneTarget;
void UpdateBoneValue(int16 &v, int16 t);
void Target0();
void Update();
};
} // End of namespace ICB
#endif // _PX_BONES_H

View File

@@ -0,0 +1,49 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_CAMERA_H
#define ICB_PX_CAMERA_H
#include "engines/icb/common/px_common.h"
namespace ICB {
typedef struct PXmatrix_PC {
PXreal m[3][3]; /* 3x3 rotation matrix */
PXreal t[3]; /* transfer vector */
} PXmatrix_PC;
struct PCcamera {
char id[4];
int32 schema;
PXmatrix_PC view;
float pan;
float focLen;
};
} // End of namespace ICB
#endif // __px_camera_h__included__

View File

@@ -0,0 +1,63 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_CAMERA_CUBE
#define ICB_PX_CAMERA_CUBE
#include "engines/icb/common/px_common.h"
namespace ICB {
typedef struct {
/*
(y)height
|
|
|
|
|
x1,y1,z1 |----------| y
\ \ |
\ \ |
\___________ (x)width \---x
(z)depth \ parallel to max model axis
z
*/
PXreal x1;
PXreal y1;
PXreal z1; // top left bottom corner point
PXreal width;
PXreal depth;
PXreal height;
uint32 script_name_offset; // IF this is set then we call a script
uint32 camera_name_offset; // ELSE offset from start of this file to ascii
// name of camera - and therefore set
} _camera_cube;
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,44 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/psx_config.h"
#include "engines/icb/gfx/psx_pcdefines.h"
#if _PSX_ON_PC == 1
#include "engines/icb/common/px_capri_maths.h"
#endif
namespace ICB {
MATRIX *gterot;
MATRIX *gtetrans;
MATRIX *gtecolour;
MATRIX *gtelight;
short gteback[3];
int32 gtegeomscrn;
uint8 dcache[1024];
} // End of namespace ICB

View File

@@ -0,0 +1,408 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PC_CAPRI_MATHS_H
#define ICB_PC_CAPRI_MATHS_H
#include "engines/icb/psx_config.h"
#include "engines/icb/common/px_capri_maths_pc.h"
namespace ICB {
#if (_PSX_ON_PC == 0) && !defined ICB_PSX_PCDEFINES_H
// make our own equivalents
typedef struct MATRIX {
int16 m[3][3]; /* 3x3 rotation matrix */
int16 pad;
int32 t[3]; /* transfer vector */
MATRIX() { pad = 0; }
} MATRIX;
/* int32 word type 3D vector */
typedef struct VECTOR {
int32 vx, vy;
int32 vz, pad;
VECTOR() { pad = 0; }
} VECTOR;
/* short word type 3D vector */
typedef struct SVECTOR {
int16 vx, vy;
int16 vz, pad;
SVECTOR() { pad = 0; }
bool operator==(const SVECTOR &v) { return ((v.vx == vx) && (v.vy == vy) && (v.vz == vz)); }
} SVECTOR;
/* short word type 3D vector */
typedef struct CVECTOR {
uint8 r, g;
int16 b, pad;
CVECTOR() { pad = 0; }
bool operator==(const CVECTOR &v) { return ((v.r == r) && (v.g == g) && (v.b == b)); }
} CVECTOR;
#endif // #if (_PSX_ON_PC==0)
#define ONE 4096
#define myPI (3.141592654f)
inline int32 myNINT(float f) {
if (f >= 0.0f)
return int(f + 0.5f);
else
return int(f - 0.5f);
}
#define VectorNormal myVectorNormal
#define ApplyMatrixLV myApplyMatrixLV
#define ApplyMatrixSV myApplyMatrixSV
#define RotMatrix_gte myRotMatrix_gte
#define gte_MulMatrix0 mygte_MulMatrix0
#define gte_RotTrans mygte_RotTrans
#define gte_RotTransPers mygte_RotTransPers
#define gte_RotTransPers3 mygte_RotTransPers3
#define gte_SetRotMatrix mygte_SetRotMatrix
#define gte_SetTransMatrix mygte_SetTransMatrix
#define gte_ApplyRotMatrix mygte_ApplyRotMatrix
#define gte_SetGeomScreen mygte_SetGeomScreen
#define gte_SetBackColor mygte_SetBackColor
#define gte_SetColorMatrix mygte_SetColorMatrix
#define gte_SetLightMatrix mygte_SetLightMatrix
#define gte_NormalColorCol mygte_NormalColorCol
#define gte_NormalColorCol3 mygte_NormalColorCol3
#define gte_NormalClip mygte_NormalClip
#define gte_AverageZ3 mygte_AverageZ3
extern MATRIX *gterot;
extern MATRIX *gtetrans;
extern MATRIX *gtecolour;
extern MATRIX *gtelight;
extern int16 gteback[3];
extern int32 gtegeomscrn;
extern uint8 dcache[1024];
#define getScratchAddr(x) ((uint32 *)(dcache + x))
inline void myApplyMatrixLV(MATRIX *m, VECTOR *invec, VECTOR *outvec);
inline void myApplyMatrixSV(MATRIX *m, SVECTOR *invec, SVECTOR *outvec);
inline int32 myVectorNormal(VECTOR *in0, VECTOR *out0);
inline void mygte_MulMatrix0(MATRIX *m1, MATRIX *m2, MATRIX *out);
inline void mygte_RotTrans(SVECTOR *in0, VECTOR *out0, int32 *flag);
inline void mygte_RotTransPers(SVECTOR *in0, int32 *sxy0, int32 *p, int32 *flag, int32 *z);
inline void mygte_RotTransPers3(SVECTOR *in0, SVECTOR *in1, SVECTOR *in2, int32 *sxy0, int32 *sxy1, int32 *sxy2, int32 *p, int32 *flag, int32 *z);
inline void mygte_SetRotMatrix(MATRIX *m);
inline void mygte_SetTransMatrix(MATRIX *m);
inline void mygte_ApplyRotMatrix(SVECTOR *invec, VECTOR *outvec);
inline void myRotMatrix_gte(SVECTOR *rot, MATRIX *m);
inline void mygte_SetColorMatrix(MATRIX *m);
inline void mygte_SetLightMatrix(MATRIX *m);
inline void mygte_SetGeomScreen(int32 h);
inline void mygte_SetBackColor(int32 r, int32 g, int32 b);
inline void mygte_NormalColorCol(SVECTOR *v0, CVECTOR *in0, CVECTOR *out0);
inline void mygte_NormalColorCol3(SVECTOR *v0, SVECTOR *v1, SVECTOR *v2, CVECTOR *in0, CVECTOR *out0, CVECTOR *out1, CVECTOR *out2);
inline void mygte_NormalClip(int32 sxy0, int32 sxy1, int32 sxy2, int32 *flag);
inline void mygte_AverageZ3(int32 z0, int32 z1, int32 z2, int32 *sz);
inline void myApplyMatrixLV(MATRIX *m, VECTOR *invec, VECTOR *outvec) {
outvec->vx = ((int)m->m[0][0] * invec->vx + (int)m->m[0][1] * invec->vy + (int)m->m[0][2] * invec->vz) / 4096;
outvec->vy = ((int)m->m[1][0] * invec->vx + (int)m->m[1][1] * invec->vy + (int)m->m[1][2] * invec->vz) / 4096;
outvec->vz = ((int)m->m[2][0] * invec->vx + (int)m->m[2][1] * invec->vy + (int)m->m[2][2] * invec->vz) / 4096;
}
inline void myApplyMatrixSV(MATRIX *m, SVECTOR *invec, SVECTOR *outvec) {
outvec->vx = (int16)(((int)m->m[0][0] * invec->vx + (int)m->m[0][1] * invec->vy + (int)m->m[0][2] * invec->vz) / 4096);
outvec->vy = (int16)(((int)m->m[1][0] * invec->vx + (int)m->m[1][1] * invec->vy + (int)m->m[1][2] * invec->vz) / 4096);
outvec->vz = (int16)(((int)m->m[2][0] * invec->vx + (int)m->m[2][1] * invec->vy + (int)m->m[2][2] * invec->vz) / 4096);
}
inline void mygte_MulMatrix0(MATRIX *m1, MATRIX *m2, MATRIX *out) {
MATRIX local;
MATRIX *work;
if ((out == m1) || (out == m2))
work = &local;
else
work = out;
work->m[0][0] = (int16)(((int)m1->m[0][0] * (int)m2->m[0][0] + (int)m1->m[0][1] * (int)m2->m[1][0] + (int)m1->m[0][2] * (int)m2->m[2][0]) / 4096);
work->m[0][1] = (int16)(((int)m1->m[0][0] * (int)m2->m[0][1] + (int)m1->m[0][1] * (int)m2->m[1][1] + (int)m1->m[0][2] * (int)m2->m[2][1]) / 4096);
work->m[0][2] = (int16)(((int)m1->m[0][0] * (int)m2->m[0][2] + (int)m1->m[0][1] * (int)m2->m[1][2] + (int)m1->m[0][2] * (int)m2->m[2][2]) / 4096);
work->m[1][0] = (int16)(((int)m1->m[1][0] * (int)m2->m[0][0] + (int)m1->m[1][1] * (int)m2->m[1][0] + (int)m1->m[1][2] * (int)m2->m[2][0]) / 4096);
work->m[1][1] = (int16)(((int)m1->m[1][0] * (int)m2->m[0][1] + (int)m1->m[1][1] * (int)m2->m[1][1] + (int)m1->m[1][2] * (int)m2->m[2][1]) / 4096);
work->m[1][2] = (int16)(((int)m1->m[1][0] * (int)m2->m[0][2] + (int)m1->m[1][1] * (int)m2->m[1][2] + (int)m1->m[1][2] * (int)m2->m[2][2]) / 4096);
work->m[2][0] = (int16)(((int)m1->m[2][0] * (int)m2->m[0][0] + (int)m1->m[2][1] * (int)m2->m[1][0] + (int)m1->m[2][2] * (int)m2->m[2][0]) / 4096);
work->m[2][1] = (int16)(((int)m1->m[2][0] * (int)m2->m[0][1] + (int)m1->m[2][1] * (int)m2->m[1][1] + (int)m1->m[2][2] * (int)m2->m[2][1]) / 4096);
work->m[2][2] = (int16)(((int)m1->m[2][0] * (int)m2->m[0][2] + (int)m1->m[2][1] * (int)m2->m[1][2] + (int)m1->m[2][2] * (int)m2->m[2][2]) / 4096);
if (work != out) {
out->m[0][0] = work->m[0][0];
out->m[0][1] = work->m[0][1];
out->m[0][2] = work->m[0][2];
out->m[1][0] = work->m[1][0];
out->m[1][1] = work->m[1][1];
out->m[1][2] = work->m[1][2];
out->m[2][0] = work->m[2][0];
out->m[2][1] = work->m[2][1];
out->m[2][2] = work->m[2][2];
}
}
inline void mygte_SetRotMatrix(MATRIX *m) { *gterot = *m; }
inline void mygte_SetTransMatrix(MATRIX *m) { *gtetrans = *m; }
inline void mygte_ApplyRotMatrix(SVECTOR *invec, VECTOR *outvec) {
outvec->vx = (((int)gterot->m[0][0] * (int)invec->vx + (int)gterot->m[0][1] * (int)invec->vy + (int)gterot->m[0][2] * (int)invec->vz) / 4096);
outvec->vy = (((int)gterot->m[1][0] * (int)invec->vx + (int)gterot->m[1][1] * (int)invec->vy + (int)gterot->m[1][2] * (int)invec->vz) / 4096);
outvec->vz = (((int)gterot->m[2][0] * (int)invec->vx + (int)gterot->m[2][1] * (int)invec->vy + (int)gterot->m[2][2] * (int)invec->vz) / 4096);
}
inline void mygte_RotTrans(SVECTOR *in0, VECTOR *out0, int32 *flag) {
mygte_ApplyRotMatrix(in0, out0);
out0->vx += gtetrans->t[0];
out0->vy += gtetrans->t[1];
out0->vz += gtetrans->t[2];
// What GTE flags should we set ?
*flag = 0;
}
inline void mygte_RotTransPers(SVECTOR *in0, int32 *sxy0, int32 * /* p */, int32 *flag, int32 *z) {
VECTOR cam;
SVECTOR *scrn = (SVECTOR *)sxy0;
gte_RotTrans(in0, &cam, flag);
*flag = 0;
if (cam.vz != 0) {
scrn->vx = (int16)((cam.vx * gtegeomscrn) / cam.vz);
scrn->vy = (int16)((cam.vy * gtegeomscrn) / cam.vz);
} else {
// To force an error and hence an illegal polygon
scrn->vx = 2048;
scrn->vy = 2048;
}
*z = cam.vz / 4;
if (abs(scrn->vx) > 1024)
*flag |= 0x80000000;
if (abs(scrn->vy) > 1024)
*flag |= 0x80000000;
// set the value of flag : closer than h/2
if (cam.vz < 0)
*flag |= 0x80000000;
}
inline void mygte_RotTransPers3(SVECTOR *in0, SVECTOR *in1, SVECTOR *in2, int32 *sxy0, int32 *sxy1, int32 *sxy2, int32 *p, int32 *flag, int32 *z) {
int32 z0, z1, z2;
int32 p0, p1, p2;
int32 flag0, flag1, flag2;
mygte_RotTransPers(in0, sxy0, &p0, &flag0, &z0);
mygte_RotTransPers(in1, sxy1, &p1, &flag1, &z1);
mygte_RotTransPers(in2, sxy2, &p2, &flag2, &z2);
// What GTE flags should we set ?
*flag = flag0 | flag1 | flag2;
*p = p2;
*z = z2;
}
inline void myRotMatrix_gte(SVECTOR *rot, MATRIX *m) {
const int32 one = (1 << 12);
float ang0 = (float)rot->vx * 2.0f * myPI / one;
MATRIX m0;
int32 c0 = myNINT(one * (float)cos(ang0));
int32 s0 = myNINT(one * (float)sin(ang0));
m0.m[0][0] = one;
m0.m[0][1] = 0;
m0.m[0][2] = 0;
m0.m[1][0] = 0;
m0.m[1][1] = (int16)c0;
m0.m[1][2] = (int16)-s0;
m0.m[2][0] = 0;
m0.m[2][1] = (int16)s0;
m0.m[2][2] = (int16)c0;
float ang1 = (float)rot->vy * 2.0f * myPI / one;
int32 c1 = myNINT(one * (float)cos(ang1));
int32 s1 = myNINT(one * (float)sin(ang1));
MATRIX m1;
m1.m[0][0] = (int16)c1;
m1.m[0][1] = 0;
m1.m[0][2] = (int16)s1;
m1.m[1][0] = 0;
m1.m[1][1] = one;
m1.m[1][2] = 0;
m1.m[2][0] = (int16)-s1;
m1.m[2][1] = 0;
m1.m[2][2] = (int16)c1;
float ang2 = (float)rot->vz * 2.0f * myPI / one;
int32 c2 = myNINT(one * (float)cos(ang2));
int32 s2 = myNINT(one * (float)sin(ang2));
MATRIX m2;
m2.m[0][0] = (int16)c2;
m2.m[0][1] = (int16)-s2;
m2.m[0][2] = 0;
m2.m[1][0] = (int16)s2;
m2.m[1][1] = (int16)c2;
m2.m[1][2] = 0;
m2.m[2][0] = 0;
m2.m[2][1] = 0;
m2.m[2][2] = one;
mygte_MulMatrix0(&m0, &m1, m);
mygte_MulMatrix0(m, &m2, m);
}
inline void mygte_SetBackColor(int32 r, int32 g, int32 b) {
gteback[0] = (int16)r;
gteback[1] = (int16)g;
gteback[2] = (int16)b;
}
inline void mygte_SetColorMatrix(MATRIX *m) { *gtecolour = *m; }
inline void mygte_SetLightMatrix(MATRIX *m) { *gtelight = *m; }
inline void mygte_SetGeomScreen(int32 h) { gtegeomscrn = h; }
inline void mygte_NormalColorCol(SVECTOR *v0, CVECTOR *in0, CVECTOR *out0) {
SVECTOR lightEffect;
// Normal line vector(local) -> light source effect
ApplyMatrixSV(gtelight, v0, &lightEffect);
if (lightEffect.vx < 0)
lightEffect.vx = 0;
if (lightEffect.vy < 0)
lightEffect.vy = 0;
if (lightEffect.vz < 0)
lightEffect.vz = 0;
// Light source effect -> Colour effect(local colour matrix+back colour)
SVECTOR colourEffect;
ApplyMatrixSV(gtecolour, &lightEffect, &colourEffect);
if (colourEffect.vx < 0)
colourEffect.vx = 0;
if (colourEffect.vy < 0)
colourEffect.vy = 0;
if (colourEffect.vz < 0)
colourEffect.vz = 0;
// colourEffect is 0-4095 (2^12)
// gteback is 0-255 (2^8)
colourEffect.vx = (int16)((colourEffect.vx >> 4) + gteback[0]);
colourEffect.vy = (int16)((colourEffect.vy >> 4) + gteback[1]);
colourEffect.vz = (int16)((colourEffect.vz >> 4) + gteback[2]);
// 256 = 1.0 in colourEffect
// 128 = 1.0 in in0
int32 red = ((in0->r * colourEffect.vx) >> 8);
int32 green = ((in0->g * colourEffect.vy) >> 8);
int32 blue = ((in0->b * colourEffect.vz) >> 8);
if (red > 255)
red = 255;
if (green > 255)
green = 255;
if (blue > 255)
blue = 255;
out0->r = (uint8)(red);
out0->g = (uint8)(green);
out0->b = (uint8)(blue);
}
inline void mygte_NormalColorCol3(SVECTOR *v0, SVECTOR *v1, SVECTOR *v2, CVECTOR *in0, CVECTOR *out0, CVECTOR *out1, CVECTOR *out2) {
gte_NormalColorCol(v0, in0, out0);
gte_NormalColorCol(v1, in0, out1);
gte_NormalColorCol(v2, in0, out2);
}
inline int32 myVectorNormal(VECTOR *in0, VECTOR *out0) {
int32 r2 = (in0->vx * in0->vx + in0->vy * in0->vy + in0->vz * in0->vz);
float r = (float)sqrt((float)r2) / 4096.0f;
if (fabs(r) < 1.0e-6)
return 0;
out0->vx = (int32)((float)in0->vx / r);
out0->vy = (int32)((float)in0->vy / r);
out0->vz = (int32)((float)in0->vz / r);
return r2;
}
inline void mygte_NormalClip(int32 sxy0, int32 sxy1, int32 sxy2, int32 *flag) {
SVECTOR *v0 = (SVECTOR *)&sxy0;
SVECTOR *v1 = (SVECTOR *)&sxy1;
SVECTOR *v2 = (SVECTOR *)&sxy2;
// compute the cross-product of (v1-v0) x (v2-v0)
int32 l0x = v1->vx - v0->vx;
int32 l0y = v1->vy - v0->vy;
int32 l1x = v2->vx - v0->vx;
int32 l1y = v2->vy - v0->vy;
*flag = ((l0x * l1y) - (l0y * l1x));
}
inline void mygte_AverageZ3(int32 z0, int32 z1, int32 z2, int32 *sz) {
*sz = (z0 + z1 + z2) / 3;
*sz /= 4;
}
} // End of namespace ICB
#endif // #ifndef __PC_CAPRI_MATHS_H

View File

@@ -0,0 +1,44 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/psx_config.h"
#include "engines/icb/gfx/psx_pcdefines.h"
#if _PSX_ON_PC == 1
#include "engines/icb/common/px_capri_maths_pc.h"
#endif
namespace ICB {
MATRIXPC *gterot_pc;
MATRIXPC *gtetrans_pc;
MATRIXPC *gtecolour_pc;
MATRIXPC *gtelight_pc;
int32 gteback_pc[3];
int32 gtegeomscrn_pc;
int32 gtescreenscaleshift_pc = 0;
} // End of namespace ICB

View File

@@ -0,0 +1,537 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_CAPRI_MATHS_PC_H
#define ICB_PX_CAPRI_MATHS_PC_H
#include "common/util.h"
namespace ICB {
#if (_PSX_ON_PC == 0) && !defined ICB_PX_CAPRI_MATHS_PC_H
// make our own equivalents
typedef struct MATRIXPC {
int32 m[3][3]; /* 3x3 rotation matrix */
int32 pad;
int32 t[3]; /* transfer vector */
MATRIXPC() { pad = 0; }
} MATRIXPC;
/* int32 word type 3D vector */
typedef struct VECTOR {
int32 vx, vy;
int32 vz, pad;
VECTOR() { pad = 0; }
} VECTOR;
/* short word type 3D vector */
typedef struct SVECTORPC {
int32 vx, vy;
int32 vz, pad;
SVECTORPC() { pad = 0; }
bool operator==(const SVECTORPC &v) { return ((v.vx == vx) && (v.vy == vy) && (v.vz == vz)); }
} SVECTORPC;
/* short word type 3D vector */
typedef struct CVECTOR {
uint8 r, g;
int16 b, pad;
CVECTOR() { pad = 0; }
bool operator==(const CVECTOR &v) { return ((v.r == r) && (v.g == g) && (v.b == b)); }
} CVECTOR;
#endif // #if (_PSX_ON_PC==0)
//-=- Definitions -=-//
const int32 ONE_PC_SCALE = 12;
const int32 ONE_PC = 1 << ONE_PC_SCALE;
const float myPI_PC = 3.141592654f;
const int32 ZSCALE = 1;
inline int32 myNINT_PC(float f) {
if (f >= 0.0f)
return int(f + 0.5f);
else
return int(f - 0.5f);
}
//------------------------------------------------------------------------
#define VectorNormal_pc myVectorNormal_pc
#define ApplyMatrixLV_pc myApplyMatrixLV_pc
#define ApplyMatrixSV_pc myApplyMatrixSV_pc
#define RotMatrix_gte_pc myRotMatrix_gte_pc
#define gte_MulMatrix0_pc mygte_MulMatrix0_pc
#define gte_RotTrans_pc mygte_RotTrans_pc
#define gte_RotTransPers_pc mygte_RotTransPers_pc
#define gte_RotTransPers3_pc mygte_RotTransPers3_pc
#define gte_SetRotMatrix_pc mygte_SetRotMatrix_pc
#define gte_SetTransMatrix_pc mygte_SetTransMatrix_pc
#define gte_ApplyRotMatrix_pc mygte_ApplyRotMatrix_pc
#define gte_SetGeomScreen_pc mygte_SetGeomScreen_pc
#define gte_SetBackColor_pc mygte_SetBackColor_pc
#define gte_SetColorMatrix_pc mygte_SetColorMatrix_pc
#define gte_SetLightMatrix_pc mygte_SetLightMatrix_pc
#define gte_NormalColorCol_pc mygte_NormalColorCol_pc
#define gte_NormalColorCol3_pc mygte_NormalColorCol3_pc
#define gte_NormalClip_pc mygte_NormalClip_pc
#define gte_AverageZ3_pc mygte_AverageZ3_pc
#define gte_SetScreenScaleShift_pc mygte_SetScreenScaleShift_pc
//------------------------------------------------------------------------
extern MATRIXPC *gterot_pc;
extern MATRIXPC *gtetrans_pc;
extern MATRIXPC *gtecolour_pc;
extern MATRIXPC *gtelight_pc;
extern int32 gteback_pc[3];
extern int32 gtegeomscrn_pc;
extern int32 gtescreenscaleshift_pc;
//------------------------------------------------------------------------
inline void myApplyMatrixLV_pc(MATRIXPC *m, VECTOR *invec, VECTOR *outvec);
inline void myApplyMatrixSV_pc(MATRIXPC *m, SVECTORPC *invec, SVECTORPC *outvec);
inline void myApplyMatrixSV_pc(MATRIXPC *m, SVECTOR *invec, SVECTORPC *outvec);
inline int32 myVectorNormal_pc(VECTOR *in0, VECTOR *out0);
inline void mygte_MulMatrix0_pc(MATRIXPC *m1, MATRIXPC *m2, MATRIXPC *out);
inline void mygte_RotTrans_pc(SVECTORPC *in0, VECTOR *out0, int32 *flag);
inline void mygte_RotTrans_pc(SVECTOR *in0, VECTOR *out0, int32 *flag);
inline void mygte_RotTransPers_pc(SVECTORPC *in0, SVECTORPC *sxy0, int32 *p, int32 *flag, int32 *z);
inline void mygte_RotTransPers_pc(SVECTOR *in0, SVECTORPC *sxy0, int32 *p, int32 *flag, int32 *z);
inline void mygte_RotTransPers3_pc(SVECTORPC *in0, SVECTORPC *in1, SVECTORPC *in2, SVECTORPC *sxy0, SVECTORPC *sxy1, SVECTORPC *sxy2, int32 *p, int32 *flag, int32 *z);
inline void mygte_SetRotMatrix_pc(MATRIXPC *m);
inline void mygte_SetTransMatrix_pc(MATRIXPC *m);
inline void mygte_ApplyRotMatrix_pc(SVECTORPC *invec, VECTOR *outvec);
inline void myRotMatrix_gte_pc(SVECTOR *rot, MATRIXPC *m);
inline void mygte_SetColorMatrix_pc(MATRIXPC *m);
inline void mygte_SetLightMatrix_pc(MATRIXPC *m);
inline void mygte_SetGeomScreen_pc(int32 h);
inline void mygte_SetBackColor_pc(int32 r, int32 g, int32 b);
inline void mygte_SetScreenScaleShift_pc(int32 shift);
inline void mygte_NormalColorCol_pc(SVECTOR *v0, CVECTOR *in0, CVECTOR *out0);
inline void mygte_NormalColorCol3_pc(SVECTOR *v0, SVECTOR *v1, SVECTOR *v2, CVECTOR *in0, CVECTOR *out0, CVECTOR *out1, CVECTOR *out2);
inline void mygte_NormalClip_pc(SVECTORPC *sxy0, SVECTORPC *sxy1, SVECTORPC *sxy2, int32 *flag);
inline void mygte_NormalClip_pc(SVECTOR *sxy0, SVECTOR *sxy1, SVECTOR *sxy2, int32 *flag);
inline void mygte_AverageZ3_pc(int32 z0, int32 z1, int32 z2, int32 *sz);
//------------------------------------------------------------------------
inline void myApplyMatrixLV_pc(MATRIXPC *m, VECTOR *invec, VECTOR *outvec) {
outvec->vx = (m->m[0][0] * invec->vx + m->m[0][1] * invec->vy + m->m[0][2] * invec->vz) / ONE_PC;
outvec->vy = (m->m[1][0] * invec->vx + m->m[1][1] * invec->vy + m->m[1][2] * invec->vz) / ONE_PC;
outvec->vz = (m->m[2][0] * invec->vx + m->m[2][1] * invec->vy + m->m[2][2] * invec->vz) / ONE_PC;
}
//------------------------------------------------------------------------
inline void myApplyMatrixSV_pc(MATRIXPC *m, SVECTORPC *invec, SVECTORPC *outvec) {
outvec->vx = (int)((m->m[0][0] * invec->vx + m->m[0][1] * invec->vy + m->m[0][2] * invec->vz) / ONE_PC);
outvec->vy = (int)((m->m[1][0] * invec->vx + m->m[1][1] * invec->vy + m->m[1][2] * invec->vz) / ONE_PC);
outvec->vz = (int)((m->m[2][0] * invec->vx + m->m[2][1] * invec->vy + m->m[2][2] * invec->vz) / ONE_PC);
}
//------------------------------------------------------------------------
inline void myApplyMatrixSV_pc(MATRIXPC *m, SVECTOR *invec, SVECTORPC *outvec) {
outvec->vx = (int)((m->m[0][0] * (int)invec->vx + m->m[0][1] * (int)invec->vy + m->m[0][2] * (int)invec->vz) / ONE_PC);
outvec->vy = (int)((m->m[1][0] * (int)invec->vx + m->m[1][1] * (int)invec->vy + m->m[1][2] * (int)invec->vz) / ONE_PC);
outvec->vz = (int)((m->m[2][0] * (int)invec->vx + m->m[2][1] * (int)invec->vy + m->m[2][2] * (int)invec->vz) / ONE_PC);
}
//------------------------------------------------------------------------
inline void mygte_MulMatrix0_pc(MATRIXPC *m1, MATRIXPC *m2, MATRIXPC *out) {
MATRIXPC local;
MATRIXPC *work;
if ((out == m1) || (out == m2))
work = &local;
else
work = out;
work->m[0][0] = (int)((m1->m[0][0] * m2->m[0][0] + m1->m[0][1] * m2->m[1][0] + m1->m[0][2] * m2->m[2][0]) / ONE_PC);
work->m[0][1] = (int)((m1->m[0][0] * m2->m[0][1] + m1->m[0][1] * m2->m[1][1] + m1->m[0][2] * m2->m[2][1]) / ONE_PC);
work->m[0][2] = (int)((m1->m[0][0] * m2->m[0][2] + m1->m[0][1] * m2->m[1][2] + m1->m[0][2] * m2->m[2][2]) / ONE_PC);
work->m[1][0] = (int)((m1->m[1][0] * m2->m[0][0] + m1->m[1][1] * m2->m[1][0] + m1->m[1][2] * m2->m[2][0]) / ONE_PC);
work->m[1][1] = (int)((m1->m[1][0] * m2->m[0][1] + m1->m[1][1] * m2->m[1][1] + m1->m[1][2] * m2->m[2][1]) / ONE_PC);
work->m[1][2] = (int)((m1->m[1][0] * m2->m[0][2] + m1->m[1][1] * m2->m[1][2] + m1->m[1][2] * m2->m[2][2]) / ONE_PC);
work->m[2][0] = (int)((m1->m[2][0] * m2->m[0][0] + m1->m[2][1] * m2->m[1][0] + m1->m[2][2] * m2->m[2][0]) / ONE_PC);
work->m[2][1] = (int)((m1->m[2][0] * m2->m[0][1] + m1->m[2][1] * m2->m[1][1] + m1->m[2][2] * m2->m[2][1]) / ONE_PC);
work->m[2][2] = (int)((m1->m[2][0] * m2->m[0][2] + m1->m[2][1] * m2->m[1][2] + m1->m[2][2] * m2->m[2][2]) / ONE_PC);
if (work != out) {
out->m[0][0] = work->m[0][0];
out->m[0][1] = work->m[0][1];
out->m[0][2] = work->m[0][2];
out->m[1][0] = work->m[1][0];
out->m[1][1] = work->m[1][1];
out->m[1][2] = work->m[1][2];
out->m[2][0] = work->m[2][0];
out->m[2][1] = work->m[2][1];
out->m[2][2] = work->m[2][2];
}
}
//------------------------------------------------------------------------
inline void mygte_SetRotMatrix_pc(MATRIXPC *m) { *gterot_pc = *m; }
//------------------------------------------------------------------------
inline void mygte_SetTransMatrix_pc(MATRIXPC *m) { *gtetrans_pc = *m; }
//------------------------------------------------------------------------
inline void mygte_ApplyRotMatrix_pc(SVECTORPC *invec, VECTOR *outvec) {
outvec->vx = ((gterot_pc->m[0][0] * invec->vx + gterot_pc->m[0][1] * invec->vy + gterot_pc->m[0][2] * invec->vz) / ONE_PC);
outvec->vy = ((gterot_pc->m[1][0] * invec->vx + gterot_pc->m[1][1] * invec->vy + gterot_pc->m[1][2] * invec->vz) / ONE_PC);
outvec->vz = ((gterot_pc->m[2][0] * invec->vx + gterot_pc->m[2][1] * invec->vy + gterot_pc->m[2][2] * invec->vz) / ONE_PC);
}
//------------------------------------------------------------------------
inline void mygte_RotTrans_pc(SVECTORPC *in0, VECTOR *out0, int32 *flag) {
mygte_ApplyRotMatrix_pc(in0, out0);
out0->vx += gtetrans_pc->t[0];
out0->vy += gtetrans_pc->t[1];
out0->vz += gtetrans_pc->t[2];
// What GTE flags should we set ?
*flag = 0;
}
//------------------------------------------------------------------------
inline void mygte_RotTrans_pc(SVECTOR *in0, VECTOR *out0, int32 *flag) {
SVECTORPC sv_pc;
sv_pc.vx = in0->vx;
sv_pc.vy = in0->vy;
sv_pc.vz = in0->vz;
mygte_ApplyRotMatrix_pc(&sv_pc, out0);
out0->vx += gtetrans_pc->t[0];
out0->vy += gtetrans_pc->t[1];
out0->vz += gtetrans_pc->t[2];
// What GTE flags should we set ?
*flag = 0;
}
//------------------------------------------------------------------------
inline void mygte_RotTransPers_pc(SVECTORPC *in0, SVECTORPC *sxy0, int32 * /* p */, int32 *flag, int32 *z) {
VECTOR cam;
cam.vx = ((gterot_pc->m[0][0] * in0->vx + gterot_pc->m[0][1] * in0->vy + gterot_pc->m[0][2] * in0->vz) / ONE_PC);
cam.vy = ((gterot_pc->m[1][0] * in0->vx + gterot_pc->m[1][1] * in0->vy + gterot_pc->m[1][2] * in0->vz) / ONE_PC);
cam.vz = ((gterot_pc->m[2][0] * in0->vx + gterot_pc->m[2][1] * in0->vy + gterot_pc->m[2][2] * in0->vz) / ONE_PC);
cam.vx += (gtetrans_pc->t[0] << gtescreenscaleshift_pc);
cam.vy += (gtetrans_pc->t[1] << gtescreenscaleshift_pc);
cam.vz += (gtetrans_pc->t[2] << gtescreenscaleshift_pc);
*flag = 0;
if (cam.vz != 0) {
sxy0->vx = (int)((cam.vx * gtegeomscrn_pc) / cam.vz);
sxy0->vy = (int)((cam.vy * gtegeomscrn_pc) / cam.vz);
} else {
// To force an error and hence an illegal polygon
sxy0->vx = 2048;
sxy0->vy = 2048;
}
cam.vz >>= gtescreenscaleshift_pc;
*z = cam.vz / 4;
if (abs(sxy0->vx) > 1024)
*flag |= 0x80000000;
if (abs(sxy0->vy) > 1024)
*flag |= 0x80000000;
// set the value of flag : closer than h/2
if (cam.vz < 0)
*flag |= 0x80000000;
}
//------------------------------------------------------------------------
inline void mygte_RotTransPers_pc(SVECTOR *in0, SVECTORPC *sxy0, int32 * /* p */, int32 *flag, int32 *z) {
VECTOR cam;
cam.vx = ((gterot_pc->m[0][0] * (int)in0->vx + gterot_pc->m[0][1] * (int)in0->vy + gterot_pc->m[0][2] * (int)in0->vz) / ONE_PC);
cam.vy = ((gterot_pc->m[1][0] * (int)in0->vx + gterot_pc->m[1][1] * (int)in0->vy + gterot_pc->m[1][2] * (int)in0->vz) / ONE_PC);
cam.vz = ((gterot_pc->m[2][0] * (int)in0->vx + gterot_pc->m[2][1] * (int)in0->vy + gterot_pc->m[2][2] * (int)in0->vz) / ONE_PC);
cam.vx += (gtetrans_pc->t[0] << gtescreenscaleshift_pc);
cam.vy += (gtetrans_pc->t[1] << gtescreenscaleshift_pc);
cam.vz += (gtetrans_pc->t[2] << gtescreenscaleshift_pc);
*flag = 0;
if (cam.vz != 0) {
sxy0->vx = (int)((cam.vx * gtegeomscrn_pc) / cam.vz);
sxy0->vy = (int)((cam.vy * gtegeomscrn_pc) / cam.vz);
} else {
// To force an error and hence an illegal polygon
sxy0->vx = 2048;
sxy0->vy = 2048;
}
cam.vz >>= gtescreenscaleshift_pc;
*z = cam.vz / 4;
if (abs(sxy0->vx) > 1024)
*flag |= 0x80000000;
if (abs(sxy0->vy) > 1024)
*flag |= 0x80000000;
// set the value of flag : closer than h/2
if (cam.vz < 0)
*flag |= 0x80000000;
}
//------------------------------------------------------------------------
inline void mygte_RotTransPers3_pc(SVECTORPC *in0, SVECTORPC *in1, SVECTORPC *in2, SVECTORPC *sxy0, SVECTORPC *sxy1, SVECTORPC *sxy2, int32 *p, int32 *flag, int32 *z) {
int32 z0, z1, z2;
int32 p0, p1, p2;
int32 flag0, flag1, flag2;
mygte_RotTransPers_pc(in0, sxy0, &p0, &flag0, &z0);
mygte_RotTransPers_pc(in1, sxy1, &p1, &flag1, &z1);
mygte_RotTransPers_pc(in2, sxy2, &p2, &flag2, &z2);
// What GTE flags should we set ?
*flag = flag0 | flag1 | flag2;
*p = p2;
*z = z2;
}
//------------------------------------------------------------------------
inline void myRotMatrix_gte_pc(SVECTOR *rot, MATRIXPC *m) {
float ang0 = (float)rot->vx * 2.0f * myPI_PC / 4096;
MATRIXPC m0;
int32 c0 = myNINT_PC(ONE_PC * (float)cos(ang0));
int32 s0 = myNINT_PC(ONE_PC * (float)sin(ang0));
m0.m[0][0] = ONE_PC;
m0.m[0][1] = 0;
m0.m[0][2] = 0;
m0.m[1][0] = 0;
m0.m[1][1] = c0;
m0.m[1][2] = -s0;
m0.m[2][0] = 0;
m0.m[2][1] = s0;
m0.m[2][2] = c0;
float ang1 = (float)rot->vy * 2.0f * myPI_PC / 4096;
int32 c1 = myNINT_PC(ONE_PC * (float)cos(ang1));
int32 s1 = myNINT_PC(ONE_PC * (float)sin(ang1));
MATRIXPC m1;
m1.m[0][0] = c1;
m1.m[0][1] = 0;
m1.m[0][2] = s1;
m1.m[1][0] = 0;
m1.m[1][1] = ONE_PC;
m1.m[1][2] = 0;
m1.m[2][0] = -s1;
m1.m[2][1] = 0;
m1.m[2][2] = c1;
float ang2 = (float)rot->vz * 2.0f * myPI_PC / 4096;
int32 c2 = myNINT_PC(ONE_PC * (float)cos(ang2));
int32 s2 = myNINT_PC(ONE_PC * (float)sin(ang2));
MATRIXPC m2;
m2.m[0][0] = c2;
m2.m[0][1] = -s2;
m2.m[0][2] = 0;
m2.m[1][0] = s2;
m2.m[1][1] = c2;
m2.m[1][2] = 0;
m2.m[2][0] = 0;
m2.m[2][1] = 0;
m2.m[2][2] = ONE_PC;
mygte_MulMatrix0_pc(&m0, &m1, m);
mygte_MulMatrix0_pc(m, &m2, m);
}
//------------------------------------------------------------------------
inline void mygte_SetBackColor_pc(int32 r, int32 g, int32 b) {
gteback_pc[0] = r;
gteback_pc[1] = g;
gteback_pc[2] = b;
}
//------------------------------------------------------------------------
inline void mygte_SetColorMatrix_pc(MATRIXPC *m) { *gtecolour_pc = *m; }
//------------------------------------------------------------------------
inline void mygte_SetLightMatrix_pc(MATRIXPC *m) { *gtelight_pc = *m; }
//------------------------------------------------------------------------
inline void mygte_SetGeomScreen_pc(int32 h) { gtegeomscrn_pc = h; }
//------------------------------------------------------------------------
inline void mygte_NormalColorCol_pc(SVECTOR *v0, CVECTOR *in0, CVECTOR *out0) {
SVECTORPC lightEffect;
// Normal line vector(local) -> light source effect
ApplyMatrixSV_pc(gtelight_pc, v0, &lightEffect);
if (lightEffect.vx < 0)
lightEffect.vx = 0;
if (lightEffect.vy < 0)
lightEffect.vy = 0;
if (lightEffect.vz < 0)
lightEffect.vz = 0;
// Light source effect -> Colour effect(local colour matrix+back colour)
SVECTORPC colourEffect;
ApplyMatrixSV_pc(gtecolour_pc, &lightEffect, &colourEffect);
if (colourEffect.vx < 0)
colourEffect.vx = 0;
if (colourEffect.vy < 0)
colourEffect.vy = 0;
if (colourEffect.vz < 0)
colourEffect.vz = 0;
// colourEffect is 0-ONE_PC (2^ONE_PC_SCALE)
// gteback is 0-255 (2^8)
colourEffect.vx = ((colourEffect.vx >> (ONE_PC_SCALE - 8)) + gteback_pc[0]);
colourEffect.vy = ((colourEffect.vy >> (ONE_PC_SCALE - 8)) + gteback_pc[1]);
colourEffect.vz = ((colourEffect.vz >> (ONE_PC_SCALE - 8)) + gteback_pc[2]);
// 256 = 1.0 in colourEffect
// 128 = 1.0 in in0
int32 red = ((in0->r * colourEffect.vx) >> 8);
int32 green = ((in0->g * colourEffect.vy) >> 8);
int32 blue = ((in0->b * colourEffect.vz) >> 8);
if (red > 255)
red = 255;
if (green > 255)
green = 255;
if (blue > 255)
blue = 255;
out0->r = (uint8)(red);
out0->g = (uint8)(green);
out0->b = (uint8)(blue);
}
//------------------------------------------------------------------------
inline void mygte_NormalColorCol3_pc(SVECTOR *v0, SVECTOR *v1, SVECTOR *v2, CVECTOR *in0, CVECTOR *out0, CVECTOR *out1, CVECTOR *out2) {
gte_NormalColorCol_pc(v0, in0, out0);
gte_NormalColorCol_pc(v1, in0, out1);
gte_NormalColorCol_pc(v2, in0, out2);
}
//------------------------------------------------------------------------
inline int32 myVectorNormal_pc(VECTOR *in0, VECTOR *out0) {
int32 r2 = (in0->vx * in0->vx + in0->vy * in0->vy + in0->vz * in0->vz);
float r = (float)sqrt((float)r2) / (float)ONE_PC;
if (fabs(r) < 1.0e-6)
return 0;
out0->vx = (int32)((float)in0->vx / r);
out0->vy = (int32)((float)in0->vy / r);
out0->vz = (int32)((float)in0->vz / r);
return r2;
}
//////////////////////////////////////////////////////////////////////
inline void mygte_NormalClip_pc(SVECTORPC *sxy0, SVECTORPC *sxy1, SVECTORPC *sxy2, int32 *flag) {
// compute the cross-product of (v1-v0) x (v2-v0)
int32 l0x = sxy1->vx - sxy0->vx;
int32 l0y = sxy1->vy - sxy0->vy;
int32 l1x = sxy2->vx - sxy0->vx;
int32 l1y = sxy2->vy - sxy0->vy;
*flag = ((l0x * l1y) - (l0y * l1x));
}
//------------------------------------------------------------------------
inline void mygte_NormalClip_pc(SVECTOR *sxy0, SVECTOR *sxy1, SVECTOR *sxy2, int32 *flag) {
// compute the cross-product of (v1-v0) x (v2-v0)
int32 l0x = sxy1->vx - sxy0->vx;
int32 l0y = sxy1->vy - sxy0->vy;
int32 l1x = sxy2->vx - sxy0->vx;
int32 l1y = sxy2->vy - sxy0->vy;
*flag = ((l0x * l1y) - (l0y * l1x));
}
//------------------------------------------------------------------------
inline void mygte_AverageZ3_pc(int32 z0, int32 z1, int32 z2, int32 *sz) {
*sz = (z0 + z1 + z2) / 3;
*sz /= 4;
}
//------------------------------------------------------------------------
inline void mygte_SetScreenScaleShift_pc(int32 shift) { gtescreenscaleshift_pc = shift; }
//------------------------------------------------------------------------
} // End of namespace ICB
#endif // #ifndef __PC_CAPRI_MATHS_PC_H

View File

@@ -0,0 +1,82 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "common/system.h"
namespace ICB {
const char *hashTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
uint32 EngineHashString(const char *fn) {
if (fn == nullptr)
return 0;
char *f;
char c;
uint32 n;
n = 0;
f = const_cast<char *>(fn);
while ((c = *f) != 0) {
n = (n << 7) + (n << 1) + n + c; // n=128n+2n+n+c -> n=131n+c
// n=131*n+c; // n=131n+c
f++;
}
return n;
}
// Take a filename, path whatever,
// convert to hash value, then convert that hash value to
// 7 character filename
uint32 EngineHashFile(const char *fn, char *output) {
uint32 hash = EngineHashString(fn);
output[0] = hashTable[(hash >> 27) & 0x1F];
output[1] = hashTable[(hash >> 22) & 0x1F];
output[2] = hashTable[(hash >> 17) & 0x1F];
output[3] = hashTable[(hash >> 12) & 0x1F];
output[4] = hashTable[(hash >> 7) & 0x1F];
output[5] = hashTable[(hash >> 2) & 0x1F];
output[6] = hashTable[hash & 0x3];
output[7] = '\0';
return hash;
}
// Take a hash
// convert that hash value to
// 7 character filename
uint32 EngineHashToFile(uint32 hash, char *output) {
output[0] = hashTable[(hash >> 27) & 0x1F];
output[1] = hashTable[(hash >> 22) & 0x1F];
output[2] = hashTable[(hash >> 17) & 0x1F];
output[3] = hashTable[(hash >> 12) & 0x1F];
output[4] = hashTable[(hash >> 7) & 0x1F];
output[5] = hashTable[(hash >> 2) & 0x1F];
output[6] = hashTable[hash & 0x3];
output[7] = '\0';
return hash;
}
} // End of namespace ICB

View File

@@ -0,0 +1,99 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_CLU_API_H
#define ICB_CLU_API_H
namespace ICB {
#define MAX_DESCRIPTION_SIZE 60
#define MAX_FILENAME_SIZE 128
#define NON_KOSHA_FILE "ZZT_666_BUGGERED_666_ZZT"
#define NON_KOSHA_HASH 0xFFFFFFFF
#define CLUSTER_API_SCHEMA 2
#define CLUSTER_API_ID "CLU"
#define NULL_HASH 0x0
#define FOLDER_FILE_ID "ZZT"
// moved actual function to clu_api.cpp to save some memory maybe (testing)
uint32 EngineHashString(const char *fn);
uint32 EngineHashFile(const char *fn, char *output);
uint32 EngineHashToFile(uint32 hash, char *output); // Take a hash convert that hash value to 7 character filename
// To let the engine use the old version of HashString & HashFile
#define HashString EngineHashString
#define HashFile EngineHashFile
// File Layout is:
// HEADER_OPEN
// HEADER_NORMAL[n]
// filename1
// filename2
// ...
// filenamen
// file1
// file2
// ...
// filen
//
// The filenames are padded to multiple of 4 bytes
// The files are padded to multiple of 8 bytes
typedef struct HEADER_OPEN {
uint32 header_size;
uint32 noFiles;
uint32 cluster_hash;
int32 cdpos;
char description[MAX_DESCRIPTION_SIZE];
} HEADER_OPEN;
typedef struct HEADER_NORMAL {
uint32 fnOffset; // WAS: char* fn;
uint32 size;
uint32 offset;
uint32 hash;
} HEADER_NORMAL;
typedef struct Cluster_API {
char ID[4];
uint32 schema;
HEADER_OPEN ho;
HEADER_NORMAL hn[1]; // hn[n]
// string data
// file data
} Cluster_API;
#define FILE_NAME(a) (sizeof(uint) + sizeof(uint32) + sizeof(HEADER_OPEN) + (sizeof(HEADER_NORMAL) * (a)))
#define FILE_SIZE(a) (FILE_NAME(a) + sizeof(uint32))
#define FILE_OFFSET(a) (FILE_SIZE(a) + sizeof(uint32))
#define FILE_HASH(a) (FILE_OFFSET(a) + sizeof(uint32))
} // End of namespace ICB
#endif // #ifndef CLU_API_H

View File

@@ -0,0 +1,237 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_COMMON_H
#define ICB_PX_COMMON_H
#include "common/scummsys.h"
#include "engines/icb/common/px_rcutypes.h"
namespace ICB {
#define PXNULL (0xffffffff)
// This defines the scale value for converting PC floats to PSX fixed-point representation. Not
// sure if this is the right place for this.
#define PSX_FIXED_POINT_SCALE 4096
#define PSX_FLOAT_POINT_SHIFT 12
#define PSX_FLOAT_POINT_SCALE (1 << PSX_FLOAT_POINT_SHIFT)
#define PSX_ANGLE_POINT_SCALE 4096
#define PSX_DOUBLE_POINT_SCALE 4096
// Rather than using integer values beginning at 0 it would be more descriptive to use
// four ascii characters, so the type can be guessed from a hex dump.
// Use the FT macro to turn four characters into an enum _file_type
#define FT_MACRO(a, b, c, d) (a | (b << 8) | (c << 16) | (d << 24))
enum _file_type {
FT_UNDEFINED,
unusedFT_COMPILED_GAME_OBJECT, // A compiled game object
FT_FONT, // debug console & head-up font
FT_VOX_ANIM, // voxel anim file (see voxel anim file format doc)
FT_GAME_OBJECT, // A game engine game object
FT_BITMAP_ANIM, // 2D anim file (from bitmap converter) (see 2D bitmaps doc)
FT_BITMAP_FONT, // font file (from bitmap converter) (see 2D bitmaps doc)
unusedFT_FN_ROUTINES_DAT, // fn routine data for the script compiler
unusedFT_OBJECTS_SCRIPTS_DAT, // Compiled scripts for a single object
unusedFT_LINKED_SCRIPTS, // File containing scripts linked together
unusedFT_LINKED_OBJECTS, // File containing objects in session linked together
FT_PROP_LIST, // File containing a list of prop names and there program counters
FT_PROP_ANIM_LIST, // File containing prop animation lists
FT_FLOOR_MAP, // File containing the floors for a session [PS 06/04/98].
FT_BARRIERS, // File containing the index into the barriers file for the line-of-sight stuff [PS 06/04/98].
FT_CAMERAS, // File containing the camera 'cubes' for a session [PS 06/04/98].
FT_BARRIERLIST, // File containing the actual raw walkgrid barriers for a session [PS 01/06/98].
FT_OBJECT_POSITIONS, // File listing props occurring on a given floor [PS 06/04/98].
FT_PROP_ANIMATIONS, // File containing information about prop animations [PS 11/08/98].
FT_VOICE_OVER_TEXT, // Compiled voice-over text file (for Remora etc.).
// add more here!
/***IMPORTANT***
DO NOT DELETE ENTRIES FROM THIS LIST OR SUBSEQUENT RESOURCE TYPES WILL BE RENUMBERED
RENAME ENTRIES NO LONGER IN USE AND REUSE THEM LATER
*/
// The following entries can go in any order, but should not be changed
FT_COMPILED_SCRIPTS = FT_MACRO('C', 'S', 'C', 'R'), // Compiled script object format (.scrobj)
FT_LINKED_SCRIPTS = FT_MACRO('L', 'S', 'C', 'R'), // File containing scripts linked together
FT_LINKED_OBJECTS = FT_MACRO('L', 'O', 'B', 'J'), // File containing objects in session linked together
FT_COMPILED_GAME_OBJECT = FT_MACRO('C', 'O', 'B', 'J'), // A compiled game object
FT_FN_ROUTINES_DAT = FT_MACRO('F', 'N', 'D', 'T'), // fn routine data for the script compiler
FT_COMBINED_OBJECT = FT_MACRO('C', 'M', 'B', 'O'), // Combined object and script data
FT_COMPILED_TEXT = FT_MACRO('C', 'M', 'P', 'T'), // Compressed text
FT_LINKED_TEXT = FT_MACRO('L', 'N', 'K', 'T'), // Linked text
FT_COMPILED_SFX = FT_MACRO('S', 'F', 'X', ' '), // compiled SFX file
FT_LINKED_SFX = FT_MACRO('S', 'F', 'X', 'L'), // linked SFX files file
FT_REMORA_MAP = FT_MACRO('R', 'M', 'A', 'P') // Remora map file.
};
#define STANDARD_HEADER_NAME_LENGTH 32 // Max length of the header name
typedef struct {
int32 version; // This is incremented every time the object is updated
_file_type type; // enumerated value for every type of object in the game
int32 owner; // Who is responsible for producing this object
int32 unused; // For future expansion
int32 unused2; // For future expansion
char name[STANDARD_HEADER_NAME_LENGTH]; // 32 bytes worth of ascii name information
} px_standard_header;
typedef struct {
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
} _rgb;
typedef float PXreal;
typedef float PXfloat;
typedef double PXdouble;
#define REAL_ZERO 0.0f
#define REAL_ONE 1.0f
#define REAL_TWO 2.0f
#define REAL_MIN FLT_MIN
#define REAL_MAX FLT_MAX
#define REAL_LARGE 100000.0f
#define FLOAT_ZERO 0.0f
#define FLOAT_QUARTER 0.25f
#define FLOAT_HALF 0.5f
#define FLOAT_ONE 1.0f
#define FLOAT_TWO 2.0f
#define FLOAT_MIN FLT_MIN
#define FLOAT_MAX FLT_MAX
#define FLOAT_LARGE 100000.0f
#define ZERO_TURN 0.0f
#define QUARTER_TURN 0.25f
#define HALF_TURN 0.5f
#define FULL_TURN 1.0f
#define TWO_PI (2.0f * M_PI)
// For converting pan values when the game is saved/loaded
// For PC this is equal to the PSX fixed point scaling used to represent angles
#define PAN_SCALE_FACTOR PSX_ANGLE_POINT_SCALE
// #define DEGREES_TO_RADIANS 0.01745329f
#define DEGREES_TO_RADIANS(x) ((x * TWO_PI) / 360.0f)
#define RADIANS_TO_DEGREES(x) (x * (180.0f / PI))
// How to make a PXdouble from a PXreal
#define PXreal2PXdouble(x) (double)(x)
// How to make a PXreal from a PXdouble
#define PXdouble2PXreal(x) (float)(x)
// How to make a PXfloat from a PXreal
#define PXreal2PXfloat(x) (x)
// How to make a PXreal from a PXfloat
#define PXfloat2PXreal(x) (x)
typedef struct PXsvector_PC {
float x;
float y;
float z;
} PXsvector_PC;
typedef struct PXvector_PC {
float x;
float y;
float z;
} PXvector_PC;
typedef struct PXsvector_PSX {
int16 x;
int16 y;
int16 z;
int16 pad;
} PXsvector_PSX;
typedef struct PXvector_PSX {
int32 x;
int32 y;
int32 z;
} PXvector_PSX;
#ifdef _PSX_VECTOR
typedef PXvector_PSX PXvector;
typedef PXsvector_PSX PXsvector;
#else
typedef PXvector_PC PXvector;
typedef PXsvector_PC PXsvector;
#endif
typedef struct PXorient_PSX {
int16 pan;
int16 tilt;
int16 cant;
int16 pad;
} PXorient_PSX;
typedef struct PXorient_PC {
float pan;
float tilt;
float cant;
} PXorient_PC;
#ifdef _PSX_ORIENT
typedef PXorient_PSX PXorient;
#else
typedef PXorient_PC PXorient;
#endif
// Endian safe read functions
inline uint16 READ_LE_U16(const void *p) {
const uint8 *data = (const uint8 *)p;
return (uint16)((data[1] << 8) | data[0]);
}
inline uint32 READ_LE_U32(const void *p) {
const uint8 *data = (const uint8 *)p;
return (uint32)(((uint32)data[3] << 24) | ((uint32)data[2] << 16) | ((uint32)data[1] << 8) | (uint32)data[0]);
}
#if defined(SCUMM_LITTLE_ENDIAN)
#define FROM_LE_FLOAT32(a) ((float)(a))
#else
#define FROM_LE_FLOAT32(a) ((float)(SWAP_BYTES_32(a)))
#endif
#define MKTAG(a0, a1, a2, a3) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24)))
} // End of namespace ICB
#endif // #ifndef _PX_INC_PROJECT_X_COMMON_H

View File

@@ -0,0 +1,49 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
namespace ICB {
#define BUILD_OUTPUT_EXTENSION "build" // Extension for the file containing the build results
#define OBJECT_DEFINITION_EXTENSION "objdef" // Extension for an object definition
#define COMPILED_OBJECT_EXTENSION "compobj" // Extension for a compiled object
#define COMPILED_SCRIPT_EXTENSION "scrobj" // Extension for a compiled script
#define COMBINED_OBJECT_EXTENSION "cbdobj" // Extension for a combined object
#define COMPILED_FN_ROUTINES_EXTENSION "fn_dat" // Extension for the compiled fn routine data
#define COMPILED_SPEECH_SCRIPT_EXTENSION "spchscrobj" // Compiled speech script
// Makefile macro names
#define NMAKE_LOCAL_ROOT_MACRO "$(LOCALROOT)"
#define NMAKE_COMMON_ROOT_MACRO "$(COMMONROOT)"
// Resource gauge definitions
#define RESOURCE_VARIABLE_SEARCH_PATTERN "Resource Value:"
#define RESOURCE_VARIABLE_SEARCH_PATTERN_LEN 15
// Converter program versions
#define PXVER_FN_ROUTINES 1 // fn_routines converter version.
#define PXVER_SCRIPTCOMPILER 1 // fn_routines converter version.
} // End of namespace ICB

View File

@@ -0,0 +1,63 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_FEATURES_H_INCLUDED
#define ICB_PX_FEATURES_H_INCLUDED
#include "engines/icb/common/px_common.h"
namespace ICB {
// These define the filenames for files containing floor maps.
#define PX_FILENAME_FEATURES_INFO "pxwgfeatures"
#ifndef PX_EXT_LINKED
#define PX_EXT_LINKED "linked"
#endif
#ifndef PSX_EXT_LINKED
#define PSX_EXT_LINKED "PSXlinked"
#endif
// This is the version for these files. The engine checks this runtime to know that it is running with
// the correct version of file.
#define VERSION_PXWGFEATURES 200
// enum _feature_type
// Not entirely sure what these will be yet. But here are a couple of suggestions.
enum _feature_type { ANIMATING = 0, FEATURE, OTHER };
// struct _feature_info
// This holds information about one prop.
typedef struct {
PXreal x, y, z; // Reference point for the prop.
PXreal floor_y; // Y projected down to the floor the prop is on.
_feature_type type; // The type of the prop.
PXfloat direction; // 0 - 99 (maybe use -1 to indicate no direction).
} _feature_info;
} // End of namespace ICB
#endif // #ifndef _PX_FEATURES_H_INCLUDED

View File

@@ -0,0 +1,97 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_FLOOR_MAP_H_INCLUDED
#define ICB_PX_FLOOR_MAP_H_INCLUDED
#include "engines/icb/common/px_common.h"
namespace ICB {
// Should put this in a nice header file somewhere
typedef float PXreal;
typedef float PXfloat;
// This defines the length of the hashed camera name on the PSX.
#define HASH_CAMERA_LEN 8
// These define the filenames for files containing floor maps.
#define PX_FILENAME_FLOOR_MAP "pxwgfloors"
#ifndef PC_EXT_LINKED
#define PC_EXT_LINKED "linked"
#endif
#ifndef PSX_EXT_LINKED
#define PSX_EXT_LINKED "PSXlinked"
#endif
// Update this whenever the format of the data changes, so engine can check it is in sync with data.
#define VERSION_PXWGFLOORS 300
// This holds one of the rectangles making up the floor. The coordinates are held looking DOWN on the floor, and the
// coordinate system used is our system (y is up/down, x and z axes are in the horizontal plane).
typedef struct {
PXreal x1, z1; // X, Z of top-left of the floor rectangle (looking DOWN on the floor).
PXreal x2, z2; // Ditto for bottom-right corner.
} _rect;
// struct _neighbour_map_entry
// This holds one of the entries in the exit map.
typedef struct {
uint32 neighbour; // Index of neighbour (can be passed directly into _linked_data_file.Fetch_item_by_number()).
uint32 offset_exit_descriptor; // File position of the exit descriptor for this.
} _neighbour_map_entry;
// struct _floor
// This is the top structure in a floor entry. All the other structures hang off this one.
typedef struct {
PXreal base_height;
_rect rect;
char camera_cluster[HASH_CAMERA_LEN];
uint32 camera_name_offset;
uint32 map_location_hash;
uint32 num_neighbours;
_neighbour_map_entry neighbour_map[1];
} _floor;
// struct _exit_descriptor
// This holds an exit descriptor would you believe?
typedef struct {
uint32 num_waypoints; // Number of waypoints for the exit.
uint32 offset_waypoints; // File offset of the list of waypoints for this exit.
uint32 offset_propname; // File offset of the ASCII name of a prop associated with this exit.
} _exit_descriptor;
// struct _floor_waypoint
// This holds a waypoint for an exit.
typedef struct {
PXreal x, z; // Physical position of waypoint on floor.
PXfloat direction; // A direction (0-360?) for the waypoint. Might be used to face a mega a certain way.
} _floor_waypoint;
} // End of namespace ICB
#endif // #ifndef _PX_FLOOR_MAP_H_INCLUDED

View File

@@ -0,0 +1,211 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_GAME_OBJECT_H
#define ICB_GAME_OBJECT_H
#include "engines/icb/common/px_rcutypes.h"
namespace ICB {
// object run-time status values
enum _object_status { // possible values of object status field
OB_STATUS_NOT_HELD, // 0
OB_STATUS_HELD // 1 (when an object is held it does not get processed or drawn - it is excluded from the game)
};
#define OB_INIT_SCRIPT 0
#define OB_LOGIC_CONTEXT 1
#define OB_ACTION_CONTEXT 2
typedef struct {
uint32 m_size; // The size of the total data structure
uint32 m_var_table_offset;
uint32 ob_status; // low level internal stuff - see enum _object_status
// The offsets to the blocks of data. All offsets
// are from the start of the object
uint32 m_script_name_hash_table_offset; // Offset to the script name table
uint32 m_lvars_offset; // Offset to the local variable data
uint32 m_name_offset; // Offset to the object name
// Variable and script count
uint32 m_noLvars; // How many lvars this object has
uint32 m_noScripts; // The number of scripts associated with this object
/* This data is then followed by:
Null terminated object name
Object variable information block
Script names information block
*/
} CGame;
class CGameObject {
// Only ob_status is made public. To access the other elements use
// the access functions. This is so that further changes to the structure
// can be catered for through the access functions, and not needed where
// any element is specifically referenced
public:
// Main access functions
static const char *GetName(CGame *game); // Get a pointer to the object name
static uint32 GetNoLvars(CGame *game) ; // Get the number of local variables
static uint32 GetNoScripts(CGame *game); // Get the number of scripts
static uint32 GetSize(CGame *game) { return FROM_LE_32(game->m_size); }
// Using the hash system you cannot get names, only hashes
static uint32 GetScriptNameFullHash(CGame *game, uint32);
static uint32 GetScriptNamePartHash(CGame *game, uint32);
static const char *GetScriptVariableName(CGame *game, uint32); // gets name
static int32 GetVariable(CGame *game, const char *name); // get's number of named variable
static int32 IsVariableString(CGame *game, uint32); // is variable a string (1=string, 0=int)
static void SetIntegerVariable(CGame *game, uint32, int32); // Sets the value of an integer variable
static int32 GetIntegerVariable(CGame *game, uint32); // Get the value of an integer variable
static int32 *GetIntegerVariablePtr(CGame *game, uint32); // Get the value of an integer variable
static const char *GetStringVariable(CGame *game, uint32); // Get the value of a string variable
static const char *GetStringValueOrDefault(CGame *game, const char *varName, const char *defaultStr) {
int32 var;
var = GetVariable(game, varName);
if (var == -1)
return defaultStr;
else
return GetStringVariable(game, var);
}
static int32 GetIntegerValueOrDefault(CGame *game, const char *varName, int32 defaultInt) {
int32 var;
var = GetVariable(game, varName);
if (var == -1)
return defaultInt;
else
return GetIntegerVariable(game, var);
}
};
inline const char *CGameObject::GetName(CGame *game) {
// Get a pointer to the object name
return ((const char *)(((const char *)game) + game->m_name_offset));
}
inline uint32 CGameObject::GetNoLvars(CGame *game) {
// Get the number of local variables
return FROM_LE_32(game->m_noLvars);
}
inline uint32 CGameObject::GetNoScripts(CGame *game) {
// Get the number of scripts
return FROM_LE_32(game->m_noScripts);
}
inline uint32 CGameObject::GetScriptNameFullHash(CGame *game, uint32 scriptNo) {
assert(scriptNo < FROM_LE_32(game->m_noScripts));
return FROM_LE_32(((const int32 *)(((const char *)game) + FROM_LE_32(game->m_script_name_hash_table_offset)))[scriptNo * 2]);
}
inline uint32 CGameObject::GetScriptNamePartHash(CGame *game, uint32 scriptNo) {
assert(scriptNo < FROM_LE_32(game->m_noScripts));
return FROM_LE_32(((const int32 *)(((const char *)game) + FROM_LE_32(game->m_script_name_hash_table_offset)))[scriptNo * 2 + 1]);
}
inline const char *CGameObject::GetScriptVariableName(CGame *game, uint32 varNo) {
const char *currentPos;
const uint32 *table;
currentPos = (((const char *)game) + FROM_LE_32(game->m_var_table_offset));
table = (const uint32 *)currentPos;
return ((const char *)game) + FROM_LE_32(table[varNo * 2]);
}
inline int32 CGameObject::IsVariableString(CGame *game, uint32 varNo) {
const char *currentPos;
const uint32 *table;
currentPos = (((const char *)game) + FROM_LE_32(game->m_var_table_offset));
table = (const uint32 *)currentPos;
return FROM_LE_32(table[varNo * 2 + 1]);
}
inline int32 CGameObject::GetVariable(CGame *game, const char *name) {
const char *currentPos;
const uint32 *table;
int32 retValue;
uint32 whichVar;
currentPos = (((const char *)game) + FROM_LE_32(game->m_var_table_offset));
table = (const uint32 *)currentPos;
retValue = -1;
for (whichVar = 0; whichVar < FROM_LE_32(game->m_noLvars); whichVar++) {
if (strcmp(name, ((const char *)game) + FROM_LE_32(table[whichVar * 2])) == 0) {
retValue = whichVar;
whichVar = (int32)FROM_LE_32(game->m_noLvars);
}
}
return retValue;
}
inline void CGameObject::SetIntegerVariable(CGame *game, uint32 lvar, int32 val) {
assert(lvar < FROM_LE_32(game->m_noLvars));
uint32 *lvars = (uint32 *)((byte *)game + FROM_LE_32(game->m_lvars_offset));
WRITE_LE_UINT32(lvars + lvar, (uint32)val);
}
inline int32 CGameObject::GetIntegerVariable(CGame *game, uint32 lvar) {
// Get an lvar value
assert(lvar < FROM_LE_32(game->m_noLvars));
uint32 *lvars = (uint32 *)((byte *)game + FROM_LE_32(game->m_lvars_offset));
return (int32)READ_LE_UINT32(lvars + lvar);
}
inline int32 *CGameObject::GetIntegerVariablePtr(CGame *game, uint32 lvar) {
// Get an lvar value
assert(lvar < FROM_LE_32(game->m_noLvars));
uint32 *lvars = (uint32 *)((byte *)game + FROM_LE_32(game->m_lvars_offset));
return (int32 *)(lvars + lvar);
}
inline const char *CGameObject::GetStringVariable(CGame *game, uint32 lvar) {
// Get an lvar value
assert(lvar < FROM_LE_32(game->m_noLvars));
uint32 *lvars = (uint32 *)((byte *)game + FROM_LE_32(game->m_lvars_offset));
return (const char *)game + (int32)READ_LE_UINT32(lvars + lvar);
}
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,202 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/p4.h"
#include "engines/icb/debug_pc.h"
#include "engines/icb/common/px_globalvariables.h"
namespace ICB {
CpxGlobalScriptVariables::CpxGlobalScriptVariables() {
m_no_vars = 0;
m_sorted = 0;
int32 i;
for (i = 0; i < MAX_global_vars; i++) {
m_vars[i].hash = 666;
m_vars[i].value = 666;
m_varInit[i] = GLOBAL_VAR_NOT_SET;
}
}
int32 CpxGlobalScriptVariables::FindVariable(uint32 hash) {
int32 index = -1;
if (m_sorted == 0) {
SortVariables();
} else {
// Use binary search system to find the variables
// The variables are stored in ascending hash sorted order
int32 min = 0;
int32 max = m_no_vars;
index = ((max - min) >> 1);
CpxVariable *pvar = m_vars + index;
// Start at the middle of the list
while (pvar->hash != hash) {
// Not found
if ((index == min) || (index == max)) {
index = -1;
break;
}
// Is it further up the table ?
if (hash > pvar->hash) {
min = index;
// Go down from min so we creep towards maximum
index = max - ((max - min) >> 1);
} else {
max = index;
// Go up from min so we creep towards minimum
index = min + ((max - min) >> 1);
}
pvar = m_vars + index;
if (max == min)
Fatal_error("GlobalVars Binary search failed max==min %d number %d", max, m_no_vars);
}
//#define CHECK_BINARY_SEARCH
#ifdef CHECK_BINARY_SEARCH
uint32 i;
int32 oldi = 0;
// Check the binarry search worked
for (i = 0; i < m_no_vars; i++) {
if (m_vars[i].hash == hash) {
oldi = i;
break;
}
}
if (oldi != index) {
Fatal_error("Binary search failed");
}
#endif
}
return index;
}
void CpxGlobalScriptVariables::InitVariable(uint32 hash, int32 value, const char *name) {
// If the variable exists then it has already been initialised
int32 i = FindVariable(hash);
if (i == -1) {
m_vars[m_no_vars].hash = hash;
m_vars[m_no_vars].value = value;
if (name) {
Tdebug("gtable.txt", "%s , %d , 0x%X", name, value, hash);
}
m_no_vars++;
// The list is no int32er sorted !
m_sorted = 0;
} else {
// The variable has been set, so initing it is an error
// Fatal_error( "Global variable with hash 0x%08x has already been initialised",hash); // Game engine error
m_vars[i].value = value;
}
}
void CpxGlobalScriptVariables::SetVariable(uint32 hash, int32 value) {
// Set a variable
// You can't set a variable that has not been initialised
// Has the variable been defined already
int32 i = FindVariable(hash);
if (i != -1) {
// Once a variable is set then flag it as such
m_varInit[i] = GLOBAL_VAR_SET;
// Ok, just return the value
m_vars[i].value = value;
} else {
// The variable hasn't been set, so accessing it is an error
Fatal_error("SetVariable::Global variable with hash 0x%08x has been accessed before it was initialised", hash); // Game engine error
}
}
// warn = 1
// Give a warning if someone Get's the value before Setting it
// i.e. they are relying on the initialisation code which is bad
// warn = 0
// Don't give the warning - this is needed for save games which Get all global's !
int32 CpxGlobalScriptVariables::GetVariable(uint32 hash, const char *name, int32 warn) {
// Has the variable been defined already
int32 i = FindVariable(hash);
if (i != -1) {
if (warn == 1) {
// Give a warning if someone Get's the value before Setting it
// i.e. they are relying on the initialisation code which is bad
// Once a variable is set then flag it as such
if (m_varInit[i] == GLOBAL_VAR_NOT_SET) {
// Only give the warning once
m_varInit[i] = GLOBAL_VAR_SET;
if (name) {
{ Message_box("GetVariable::Global variable '%s' hash 0x%08X value %d accessed before it was set", name, hash, m_vars[i].value); }
} else {
{ Message_box("GetVariable::Global variable hash 0x%08X value %d accessed before it was set", hash, m_vars[i].value); }
}
}
}
// Ok, just return the value
return m_vars[i].value;
} else {
// The variable hasn't been set, so accessing it is an error
Fatal_error("GetVariable::Global variable with hash 0x%08X has been accessed before it was initialised", hash); // Game engine error
return 0;
}
}
//
// Sort the variables so searching for them is quicker !
// The search method can then use a binary chop system
//
void CpxGlobalScriptVariables::SortVariables() {
uint32 i;
uint32 j;
CpxVariable temp;
uint8 temp8;
// Sort the variable in ascending order
// e.g. lowest -> highest
for (i = 0; i < m_no_vars; i++) {
for (j = i + 1; j < m_no_vars; j++) {
if (m_vars[i].hash > m_vars[j].hash) {
temp = m_vars[i];
m_vars[i] = m_vars[j];
m_vars[j] = temp;
temp8 = m_varInit[i];
m_varInit[i] = m_varInit[j];
m_varInit[j] = temp8;
}
}
}
// The list is now sorted
m_sorted = 1;
}
} // End of namespace ICB

View File

@@ -0,0 +1,88 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PXGLOBALVARIABLES
#define ICB_PXGLOBALVARIABLES
#include "common/noncopyable.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_clu_api.h"
namespace ICB {
#define MAX_global_vars 256
#define GLOBAL_VAR_NOT_SET (0)
#define GLOBAL_VAR_SET (1)
class CpxVariable {
public:
uint32 hash;
int32 value;
};
class CpxGlobalScriptVariables : Common::NonCopyable {
private:
CpxVariable m_vars[MAX_global_vars];
// This is not part of the CpxVariable class - because of memory packing reasons
uint8 m_varInit[MAX_global_vars];
uint32 m_no_vars;
uint32 m_sorted;
public:
CpxGlobalScriptVariables();
void SortVariables();
int32 GetVariable(uint32 hash, const char *name = NULL, int32 warn = 1); // Get a variable by hash
int32 GetVariable(const char *n) { // Get a variable
return GetVariable(EngineHashString(n), n);
}
void SetVariable(uint32, int32); // Set a variable by hash
void SetVariable(const char *n, int32 i) { // Set a variable
SetVariable(EngineHashString(n), i);
}
void InitVariable(uint32, int32, const char *name = NULL); // First time initialise a variable by hash
void InitVariable(const char *n, int32 i) { // First time initialise a variable
InitVariable(EngineHashString(n), i, n);
}
int32 FindVariable(uint32); // is this variable taken
int32 FindVariable(const char *n) { // is this variable taken
return FindVariable(EngineHashString(n));
}
uint32 GetNoItems() { return (m_no_vars); }
const CpxVariable &operator[](uint32 n) { return (m_vars[n]); } // Return reference to variable itself (const)
};
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,88 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/gfx/psx_pcdefines.h"
namespace ICB {
enum pxLightType { OMNI_PX_LIGHT, FREE_SPOT_PX_LIGHT, TARGET_SPOT_PX_LIGHT, FREE_DIRECT_PX_LIGHT, TARGET_DIRECT_PX_LIGHT, GLOBAL_PX_LIGHT };
typedef struct {
char name[16]; // String for user's name
uint32 type; // 0-5 enumerated, see above
MATRIX PSX_matrix; // Standard PSX type, 32 bytes
SVECTOR direction; // Standard PSX type, 8 bytes
int32 pan; // Fixed point angle
int32 cant; // Fixed point angle
int32 tilt; // Fixed point angle
uint32 red; // Fixed point integer
uint32 green; // Fixed point integer
uint32 blue; // Fixed point integer
uint32 intensity; // Fixed point integer
uint32 hspot_size; // Fixed point angle
uint32 falloff_size; // Fixed point angle
uint32 use_nearAtten; // 0 false, 1 true
uint32 nearAtten_start; // Nearest integer
uint32 nearAtten_end; // Nearest integer
uint32 use_farAtten; // 0 false, 1 true
uint32 farAtten_start; // Nearest integer
uint32 farAtten_end; // Nearest integer
uint32 shape; // 0 rectangular, 1 circlular
uint32 aspect; // Fixed point integer
uint32 overshoot; // 0 false, 1 true
uint32 shadow; // 0 false, 1 true
uint32 affect_diffuse; // 0 false, 1 true
uint32 affect_specular; // 0 false, 1 true
} _pxLightState; // Size 144 bytes in total
class _pxLights {
public:
_pxLights() { ; }
~_pxLights() { ; }
uint32 Fetch_number_of_items() const { return num_of_lights; }
inline const _pxLightState *Fetch_item_by_number(uint32 number) const;
private:
uint32 num_of_lights;
};
// All lights are of the same size to skip to the start of whichever is wanted
inline const _pxLightState *_pxLights::Fetch_item_by_number(uint32 number) const {
if (number < num_of_lights) {
return ((_pxLightState *)(((char *)this) + (4 + (number * 144))));
} else
return NULL;
}
} // End of namespace ICB

View File

@@ -0,0 +1,63 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_rcutypes.h"
#include "engines/icb/common/px_string.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_clu_api.h"
#include "engines/icb/common/px_linkeddatafile.h"
namespace ICB {
// get NUMBER given HASH (does the search) - hashs must be ordered for this binary search to succeed.
uint32 LinkedDataObject::Fetch_item_number_by_hash(LinkedDataFile *file, const uint32 hash) {
int32 top, bottom;
int32 i;
uint32 current;
if (!FROM_LE_32(file->number_of_items))
return PX_LINKED_DATA_FILE_ERROR;
top = FROM_LE_32(file->number_of_items) - 1;
i = top >> 1;
bottom = 0;
for (;;) {
current = FROM_LE_32(file->list[i].name_hash_value);
if (hash == current)
return i;
else if (top == bottom)
return PX_LINKED_DATA_FILE_ERROR;
else if (hash > current) {
bottom = i + 1;
i = (top + bottom) >> 1;
} else {
top = i;
i = (top + bottom) >> 1;
}
}
}
} // End of namespace ICB

View File

@@ -0,0 +1,180 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_LINKED_DATA_FILE_H
#define ICB_PX_LINKED_DATA_FILE_H
#include "engines/icb/common/px_rcutypes.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_clu_api.h"
#include "engines/icb/debug.h"
#include "common/endian.h"
namespace ICB {
// This value is returned as an error condition.
#define PX_LINKED_DATA_FILE_ERROR (0xffffffff)
#define ORDER_PRESERVED_FLAG 1
#define NO_NAMES_FLAG 2
#define SUPPRESS_OUTPUT 4 // Suppress printing of output
typedef struct {
int32 name_offset; // offset to Null terminated name of the item
int32 data_offset; // Offset to the item
int32 data_size; // Size of the items data
uint32 name_hash_value; // hash value of name item...
} LinkedDataFileEntry;
typedef struct {
px_standard_header header;
uint32 number_of_items;
uint32 flags;
LinkedDataFileEntry list[1]; // 1 used to prevent 0 sized array warnings
// This structure is a variable size and so should never
// be a parameter to sizeof anyway
} LinkedDataFile;
class LinkedDataObject { // Should be CObjectFile
public:
static inline uint32 Fetch_number_of_items(LinkedDataFile *file) { // how many
return (FROM_LE_32(file->number_of_items));
}
static inline uint32 GetHeaderVersion(LinkedDataFile *file) { return (FROM_LE_32(file->header.version)); }
static inline int32 OrderPreserved(LinkedDataFile *file) { return (FROM_LE_32(file->flags) & (ORDER_PRESERVED_FLAG)); }
static inline int32 NameSearchable(LinkedDataFile *file) { return (!OrderPreserved(file)); }
static uint32 Fetch_item_number_by_hash(LinkedDataFile *file, const uint32 hash);
static uint32 Fetch_item_number_by_name(LinkedDataFile *file, const char *name); // reference a number by its ascii name
static void *Fetch_item_by_number(LinkedDataFile *file, uint32 number); // reference a resource by number
static void *Fetch_item_by_name(LinkedDataFile *file, const char *name); // reference a resource by its ascii name
static void *Fetch_items_name_by_number(LinkedDataFile *file, uint32 number); // return pointer to name of item number n
static void *Try_fetch_item_by_name(LinkedDataFile *file, const char *); // reference a resource by name
static void *Try_fetch_item_by_hash(LinkedDataFile *file, uint32); // reference a resource by hash
static void *Try_fetch_item_by_script_name(LinkedDataFile *file, const char *name);
};
// get DATA given NUMBER
inline void *LinkedDataObject::Fetch_item_by_number(LinkedDataFile *file, uint32 number) {
// illegal reference number
assert(number < FROM_LE_32(file->number_of_items));
// return address of resource
return (((uint8 *)&file->header) + FROM_LE_32(file->list[number].data_offset));
}
// get NAME given NUMBER
inline void *LinkedDataObject::Fetch_items_name_by_number(LinkedDataFile *file, uint32 number) {
// illegal reference number
assert(number < FROM_LE_32(file->number_of_items));
// return name
return (((uint8 *)&file->header) + FROM_LE_32(file->list[number].name_offset));
}
// this is the one that does the search...
// get NUMBER given NAME (does search)
inline uint32 LinkedDataObject::Fetch_item_number_by_name(LinkedDataFile *file, const char *name) {
uint32 hash;
if (!NameSearchable(file)) {
Fatal_error("This file is not searchable by name and was created as such (name %s)", name);
}
hash = EngineHashString(name);
return Fetch_item_number_by_hash(file, hash);
}
// get ITEM given NAME (uses Try_fetch_item_by_name, fatal error if can't find)
inline void *LinkedDataObject::Fetch_item_by_name(LinkedDataFile *file, const char *name) {
void *search;
search = Try_fetch_item_by_name(file, name);
if (search == 0) {
Fatal_error("pxLinked_data_file::Fetch_item_by_name Object %s not found", name);
// Note, for not the engine then the error is not caught which is a bad thing
// but we need a generic Fatal_error type thing that converters & the engine can call
// i.e. the converters need a Fatal_error function
return (NULL);
} else
return search;
}
// get DATA given NAME (uses get NUMBER given NAME and returns 0 if not found or uses get DATA given NUMBER to return DATA)
inline void *LinkedDataObject::Try_fetch_item_by_name(LinkedDataFile *file, const char *name) {
// as Fetch_item_with_name but will return 0 if entry could not be found as opposed to an assert
uint32 search = 0;
search = Fetch_item_number_by_name(file, name);
if (search == PX_LINKED_DATA_FILE_ERROR)
return 0; // not found (legal)
else
return Fetch_item_by_number(file, search);
}
// get DATA given HASH (uses get NUMBER given HASH and returns 0 if not found or uses get DATA given NUMBER to return DATA)
inline void *LinkedDataObject::Try_fetch_item_by_hash(LinkedDataFile *file, uint32 hash) {
// as Fetch_item_with_name but will return 0 if entry could not be found as opposed to an assert
uint32 search = 0;
search = Fetch_item_number_by_hash(file, hash);
if (search == PX_LINKED_DATA_FILE_ERROR)
return 0; // not found (legal)
else
return Fetch_item_by_number(file, search);
}
inline void *LinkedDataObject::Try_fetch_item_by_script_name(LinkedDataFile *file, const char *name) {
uint32 search = 0;
do {
if (strstr((const char *)((uint8 *)&file->header) + FROM_LE_32(file->list[search].name_offset), (const char *)name))
return (((uint8 *)&file->header) + FROM_LE_32(file->list[search].data_offset));
search++;
} while (search < FROM_LE_32(file->number_of_items));
// not found at all
return (0);
}
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,184 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_LIBRARY_LIST_TEMPLATE
#define ICB_PX_LIBRARY_LIST_TEMPLATE
namespace ICB {
template <class Type> class pxList {
protected:
Type m_item; // The item at this node
pxList<Type> *m_tail; // The tail of the list
public:
pxList() {
m_tail = NULL; // Construct an empty list
}
~pxList() {
if (!IsEmpty())
delete Tail(); // Destruct the array
}
Type &Head() {
return m_item; // The lists' head
}
pxList<Type> *Tail() {
return m_tail; // The lists' tail
}
bool IsEmpty() {
return (m_tail == NULL); // Is the list empty ?
}
void Append(const Type &); // Append item to the end of the list
void Insert(const Type &); // Inserts an item after the current item
pxList<Type> *Find(const Type &); // Returns the list whose head == entry (NULL if not found)
int32 Length(); // Returns the length of the list
};
template <class Type> class rcSortedList {
protected:
Type m_item; // The item at this node
rcSortedList<Type> *m_tail; // The tail of the list
public:
rcSortedList() {
m_tail = NULL; // Construct an empty list
}
~rcSortedList() {
if (!IsEmpty())
delete Tail(); // Destruct the array
}
public:
Type &Head(); // The lists' head
rcSortedList<Type> *Tail(); // The lists' tail
bool IsEmpty(); // Is the list empty ?
int32 Length(); // Returns the length of the list
public:
rcSortedList<Type> *Insert(const Type &); // Inserts an item in the correct place
rcSortedList<Type> *Find(const Type &); // Returns the list whose head == entry (NULL if not found)
};
template <class Type> void pxList<Type>::Append(const Type &entry) {
if (IsEmpty()) {
m_item = entry;
m_tail = new pxList<Type>;
} else {
Tail()->Append(entry);
}
}
template <class Type> void pxList<Type>::Insert(const Type &entry) {
pxList<Type> *newNode = new pxList<Type>;
if (IsEmpty()) { // Is the list is empty, insert the item at the start of the list
m_item = entry;
} else { // Else put the item before this node
newNode->m_item = m_item;
m_item = entry;
newNode->m_tail = Tail();
}
m_tail = newNode;
}
template <class Type> pxList<Type> *pxList<Type>::Find(const Type &entry) {
// If this is the end of list marker we haven't found it
if (IsEmpty())
return NULL;
if (Head() == entry)
return this;
return (Tail()->Find(entry));
}
template <class Type> int32 pxList<Type>::Length() {
if (IsEmpty())
return 0;
return (1 + Tail()->Length());
}
template <class Type> Type &rcSortedList<Type>::Head() { // The lists' head
return m_item;
}
template <class Type> rcSortedList<Type> *rcSortedList<Type>::Tail() { // The lists' tail
return m_tail;
}
template <class Type> bool rcSortedList<Type>::IsEmpty() { // Is the list empty ?
return (m_tail == NULL);
}
template <class Type> rcSortedList<Type> *rcSortedList<Type>::Insert(const Type &entry) {
if (IsEmpty()) {
// End of the list so add the entry here
m_item = entry;
m_tail = new rcSortedList<Type>;
return this;
}
// The class being listed must have a '>' Operator defined
else if (m_item > entry) {
// The new item comes before the current one
rcSortedList<Type> *newNode = new rcSortedList<Type>;
newNode->m_tail = m_tail;
newNode->m_item = m_item;
m_item = entry;
m_tail = newNode;
return this;
} else {
// Keep going
return Tail()->Insert(entry);
}
}
template <class Type> rcSortedList<Type> *rcSortedList<Type>::Find(const Type &entry) {
// If this is the end of list marker we haven't found it
if (IsEmpty())
return NULL;
// this list is sorted, so we can stop when we have a higher value than entry
if (Head() > entry)
return NULL;
if (Head() == entry)
return this;
return (Tail()->Find(entry));
}
template <class Type> int32 rcSortedList<Type>::Length() {
if (IsEmpty())
return 0;
return (1 + Tail()->Length());
}
} // End of namespace ICB
#endif // #ifndef _PX_LIBRARY_LIST_TEMPLATE

View File

@@ -0,0 +1,163 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
// NOTES
// 1. A session has a number of maps. These maps may, though don't have to, correspond to the
// slices in the walkgrid data. Each map is one item in a px_linkeddatafile. The data structures
// below describe the internal structure of this.
// 2. Each entry in the px_linkeddatafile is simply a uint32 count of the number of objects in
// this level, followed by the objects themselves, which are all one of the types listed below.
// 3. All x,y,z coordinates are divided by two before storage, so we can fit them in a byte. Thus
// the map is stored half-scale.
// Make sure this header gets included only once.
#ifndef ICB_PX_MAPFILE_H_INCLUDED
#define ICB_PX_MAPFILE_H_INCLUDED
// Include headers needed by this file.
#include "engines/icb/common/px_common.h"
namespace ICB {
// This defines a schema version number for the data. If the format is changed then this number should
// be changed to prevent the engine running with out-of-date data.
#define REMORA_MAP_FILE_VERSION 100
// These define extensions and names for these files.
#if !defined(REMORA_MAP_FILENAME)
#define REMORA_MAP_FILENAME "remora_map"
#endif
#if !defined(REMORA_MAP_PC_EXT)
#define REMORA_MAP_PC_EXT "rmf_pc"
#endif
#if !defined(REMORA_MAP_PSX_EXT)
#define REMORA_MAP_PSX_EXT "rmf_psx"
#endif
#if !defined(PX_MAP_EXT)
#if defined(_PSX)
#define PX_MAP_EXT REMORA_MAP_PSX_EXT
#else
#define PX_MAP_EXT REMORA_MAP_PC_EXT
#endif
#endif
// This defines the 'knowledge levels' that items can have. Basically, the idea is that an object
// will only get drawn in the game if the knowledge level for the player is greater than or equal
// to the level stored for the object.
#define REMORA_MAP_MAX_KNOWLEDGE_LEVEL 3
// These are definitions for the object types. These are packed in with the 'level' indicator. So
// if you had a line that should be displayed only when the player's knowledge is at level 4 (i.e. the
// player is currently in a location), then it would have the following code:
// 0x40 | 0x02 = 0x42.
enum MapObjectType { REMORA_MAP_RECTANGLE = 0, REMORA_MAP_FILLED_RECTANGLE, REMORA_MAP_LINE, REMORA_MAP_TEXT, REMORA_MAP_POLYGON, REMORA_MAP_NUM_OBJECTS };
// These macros allow access to the two halves of the packed field mentioned previously.
#define GET_KNOWLEDGE_LEVEL(x) ((uint32)((x & 0xf0) >> 4))
#define GET_OBJECT_TYPE(x) ((MapObjectType)(x & 0x0f))
// type _map_colour_point
// This holds a point with a colour. This is not used in the objects that have a fixed number
// of points because we lose 3 padding bytes per point.
typedef struct {
uint8 nX, nY;
uint8 nR, nG, nB;
uint8 nPad1;
uint8 nPad2;
uint8 nPad3;
} _map_colour_point;
// type _map_rectangle
// An outline rectangle - object type 0.
typedef struct {
uint32 nLocationNameHash; // Hash of the location this object is part of.
uint8 nLevelAndType; // See note above for how to construct this field.
uint8 nX1, nY1; // Top-left corner of the rectangle.
uint8 nR1, nG1, nB1; // Colour for top-left corner.
uint8 nX2, nY2; // Bottom-right corner of the rectangle.
uint8 nR2, nG2, nB2; // Colour for bottom-right corner.
uint8 nWidth; // Width to draw rectangle line.
} _map_rectangle;
// type _map_filled_rectangle
// A filled rectangle - object type 1.
typedef struct {
uint32 nLocationNameHash; // Hash of the location this object is part of.
uint8 nLevelAndType; // See note above for how to construct this field.
uint8 nX1, nY1; // Top-left corner of the rectangle.
uint8 nR1, nG1, nB1; // Colour for top-left corner.
uint8 nX2, nY2; // Bottom-right corner of the rectangle.
uint8 nR2, nG2, nB2; // Colour for bottom-right corner.
uint8 nPad1;
} _map_filled_rectangle;
// type _map_line
// A line - object type 2.
typedef struct {
uint32 nLocationNameHash; // Hash of the location this object is part of.
uint8 nLevelAndType; // See note above for how to construct this field.
uint8 nX1, nY1; // Top-left corner of the rectangle.
uint8 nR1, nG1, nB1; // Colour for top-left corner.
uint8 nX2, nY2; // Bottom-right corner of the rectangle.
uint8 nR2, nG2, nB2; // Colour for bottom-right corner.
uint8 nWidth; // Width to draw rectangle line.
} _map_line;
// type _map_text
// Some text to be displayed - object type 3.
typedef struct {
uint32 nLocationNameHash; // Hash of the location this object is part of.
uint8 nLevelAndType; // See note above for how to construct this field.
uint8 nX, nY; // Bottom-left point to start drawing text.
uint8 nR, nG, nB; // Colour.
uint8 nPad1;
uint8 nPad2;
uint32 nTextHash; // Hash of the text.
} _map_text;
// type _map_polygon
// A filled rectangle - object type 4.
typedef struct {
uint32 nLocationNameHash; // Hash of the location this object is part of.
uint8 nLevelAndType; // See note above for how to construct this field.
uint8 nNumPoints; // How many points it has.
uint8 m_nPad1;
uint8 m_nPad2;
_map_colour_point pPoints[1]; // The points for the polygon.
} _map_polygon;
// This function works out the size of a polygon structure in the file because there are variable.
inline uint32 _map_polygon_sizeof(const _map_polygon *pPoly) { return (sizeof(_map_polygon) + (pPoly->nNumPoints - 1) * sizeof(_map_colour_point)); }
} // End of namespace ICB
#endif // #if !defined(_PX_MAPFILE_H_INCLUDED)

View File

@@ -0,0 +1,74 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_PROP_ANIMS_H_INCLUDED
#define ICB_PX_PROP_ANIMS_H_INCLUDED
// Include headers needed by this file.
#include "engines/icb/common/px_common.h"
namespace ICB {
// These define the filenames for files containing prop animations.
// The PSX definition is in engine\p4_psx.h
#define PX_FILENAME_PROPANIMS "pxwgpropanims"
#ifndef PC_EXT_LINKED
#define PC_EXT_LINKED "linked"
#endif
#ifndef PSX_EXT_LINKED
#define PSX_EXT_LINKED "PSXlinked"
#endif
#ifdef PX_EXT_LINKED
#undef PX_EXT_LINKED
#endif
#define PX_EXT_LINKED PC_EXT_LINKED
#define VERSION_PXWGPROPANIMS 300
// This the animations for one prop.
typedef struct {
uint16 num_anims; // The number of animations this prop has.
uint16 anims[1]; // Array of file offsets to the entries for the animations.
} _animating_prop;
// This holds one animation and any associated barriers. Note that the offsets are relative to the
// start of this _animation_entry.
typedef struct {
uint16 name; // File offset of the name of the animation.
uint16 offset_barriers; // Offset to an array of barrier indices (NULL if none).
uint16 offset_heights; // Offset to an array of PxReal height values (0 means there isn't one).
uint8 num_frames; // Number of frames in the animation.
uint8 num_barriers_per_frame; // The number of barriers per frame (same for each frame and very often 1).
uint8 frames[1]; // The frames for the animation.
} _animation_entry;
} // End of namespace ICB
#endif // #ifndef _PX_PROP_ANIMS_H_INCLUDED

View File

@@ -0,0 +1,45 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_RCUTYPES_H
#define ICB_RCUTYPES_H
#include "common/scummsys.h"
namespace ICB {
// Definition of a boolean value that can be used across the PC and PSX. I stopped true being 0xff because
// C++ weak typing allows you to assign a bool8 to an int8 without warning, whereupon '==' fails for TRUE8 because
// one is signed and one isn't.
typedef uint8 bool8;
#define TRUE8 ((uint8)0x01)
#define FALSE8 ((uint8)0x00)
// end of file
} // End of namespace ICB
#endif //_px_rcUTYPES_H

View File

@@ -0,0 +1,215 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_ROUTE_BARRIERS_H_INCLUDED
#define ICB_PX_ROUTE_BARRIERS_H_INCLUDED
// Include headers needed by this file.
#include "engines/icb/common/px_common.h"
namespace ICB {
// These define the filenames for files containing barrier maps and routing maps.
#define PX_FILENAME_LINEOFSIGHT "pxwglineofsight"
#define PX_FILENAME_ROUTING "pxwgrouting"
#define PX_FILENAME_BARRIERLIST "pxwgbarrierlist"
#ifndef PC_EXT_LINKED
#define PC_EXT_LINKED "linked"
#endif
#ifndef PSX_EXT_LINKED
#define PSX_EXT_LINKED "PSXlinked"
#endif
#ifdef PX_EXT_LINKED
#undef PX_EXT_LINKED
#endif
#define PX_EXT_LINKED PC_EXT_LINKED
// This is the version for these files. The engine checks this runtime to know that it is running with
// the correct version of file.
#define VERSION_PXWGLINEOFSIGHT 200
#define VERSION_PXWGROUTING 200
#define VERSION_PXWGBARRIERLIST 200
// This is the size of the sides of the cubes that each floor is divided into in centimetres.
#define FLOOR_CUBE_SIZE 1000 // 10-metre sides.
#define ABOVE_ALL_MODELS 10000 // Set this to be higher than any model point ever.
// This is an enumerated type for the barrier (the types listed are just illustrations - they may well be changed).
// BRICK - can't walk through it, see through it or shoot through it.
// GLASS - can't walk through it; can see through it; not sure about shooting (glass would need to break).
// BULLET_PROOF_GLASS - can't walk through it or shoot through it, but can see through it.
// THIN_STEEL - can't see through it or walk through it, but can shoot through it.
// WIRE_FENCE - can't walk through it, but can see through it; can shoot through it with random success.
// UNIT_HEIGHT - special one for stopping characters walking off the edge of ledges etc.
// VIEW_FIELD - stops characters walking out of camera field-of-view.
// LEFT_NUDGE - use to assist player control going through doors.
// RIGHT_NUDGE - ditto last one.
enum eBarrierType { BRICK = 0, GLASS, BULLET_PROOF_GLASS, THIN_STEEL, WIRE_FENCE, UNIT_HEIGHT, VIEW_FIELD, LEFT_NUDGE, RIGHT_NUDGE };
#define BARRIER_TYPE_CARDINALITY 9 // Must match number of enums in previous type (because C++
// doesn't provide a way to get this).
// This is an enumerated type for the things that might try to pass through a barrier. Note: the TEST_RAY
// is blocked by all types of barrier.
enum eBarrierRayType { TEST_RAY, LIGHT, BULLET };
#define RAY_TYPE_CARDINALITY 3
// Defines a multi-state logic value for use with the barriers.
enum eBarrierLogicValue { NO_IMPACT = 0, BLOCKS, ALLOWS, MAYBE, SPECIAL };
// This is the truth table that states what kind of ray passes through what
// type of barrier.
static enum eBarrierLogicValue barrierLogicTable[BARRIER_TYPE_CARDINALITY][RAY_TYPE_CARDINALITY] = {
{BLOCKS, BLOCKS, BLOCKS}, {BLOCKS, ALLOWS, SPECIAL}, {BLOCKS, ALLOWS, BLOCKS}, {BLOCKS, BLOCKS, ALLOWS}, {BLOCKS, ALLOWS, MAYBE},
{BLOCKS, ALLOWS, ALLOWS}, {BLOCKS, ALLOWS, ALLOWS}, {BLOCKS, ALLOWS, ALLOWS}, {BLOCKS, ALLOWS, ALLOWS}};
typedef struct {
// these are in both versions
PXfloat m_linedist, m_alinedist, m_blinedist;
PXfloat m_lpx, m_lpz; // Main barrier
PXfloat m_alpx, m_alpz; // End A.
PXfloat m_blpx, m_blpz; // End B.
} BarrierCollisionMaths;
class BarrierCollisionMathsObject {
public:
static inline PXfloat alpx(BarrierCollisionMaths *bmath) {
// return m_alpx;
return -bmath->m_lpz;
}
static inline PXfloat alpz(BarrierCollisionMaths *bmath) {
// return m_alpz;
return bmath->m_lpx;
}
static inline PXfloat blpx(BarrierCollisionMaths *bmath) {
// return m_blpx;
return bmath->m_lpz;
}
static inline PXfloat blpz(BarrierCollisionMaths *bmath) {
// return m_blpz;
return -bmath->m_lpx;
}
static void Generate(BarrierCollisionMaths *bmath, PXreal x1, PXreal z1, PXreal x2, PXreal z2) {
PXreal dx = x1 - x2;
PXreal dz = z1 - z2;
int32 nLength = (int32)PXsqrt((PXdouble)(dx * dx + dz * dz));
PXfloat xunit = PXreal2PXfloat(dx) / nLength;
PXfloat zunit = PXreal2PXfloat(dz) / nLength;
bmath->m_lpx = -zunit;
bmath->m_lpz = xunit;
bmath->m_linedist = (x1 * bmath->m_lpx) + (z1 * bmath->m_lpz);
bmath->m_alinedist = (x1 * alpx(bmath)) + (z1 * alpz(bmath));
bmath->m_blinedist = (x2 * blpx(bmath)) + (z2 * blpz(bmath));
}
};
typedef struct {
PXreal m_x1, m_z1; // Looking down on the model, the position of the first vertical edge of the barrier.
PXreal m_x2, m_z2; // Looking down on the model, the position of the second vertical edge.
PXreal m_bottom; // The bottom of the barrier.
PXreal m_top; // The top of the barrier.
eBarrierType m_material; // The material the barrier is made of.
PXfloat m_pan; // The barrier's pan value.
BarrierCollisionMaths m_bcm; // Some extra figures to speed up barrier collision detection.
} RouteBarrier;
inline void routeBarrierCreatePan(RouteBarrier *barrier) { barrier->m_pan = PXAngleOfVector(barrier->m_z1 - barrier->m_z2, barrier->m_x1 - barrier->m_x2); }
// This holds several barriers. These barriers all at least partly occupy a given cube in space. If one barrier passes
// through more than one cube, it will have a duplicate entry in each cube.
typedef struct {
int32 num_barriers; // The number of barriers referenced in this cube.
uint32 barriers; // Offset to an array of barrier indices.
} BarrierCube;
// This is a horizontal slice through the Max model, containing all the route barriers that pass through this level. The
// extremeties of the whole cuboid are given first so that a quick initial check can be done to see if there might be
// route barriers in the way.
typedef struct {
PXreal bottom; // The bottom of the slice.
PXreal top; // The top of the slice.
PXreal left_edge; // Leftmost edge of the cube of space occupied by this floor slice.
PXreal right_edge; // Ditto right edge.
PXreal back_edge; // Back edge.
PXreal front_edge; // Ditto front edge.
uint32 num_cubes; // Number of _route_cubes in this floor (could be calculated by dividing overall cube size by FLOOR_CUBE_SIZE).
uint32 row_length; // Size of the rows in the array (eg. 6 cubes could be 1X6, 2X3, 3X2 or 6X1).
uint32 offset_cubes[1]; // An array of offsets to cubes (2D array of size row_length * (num_cubes / row_length) ).
} BarrierSlice;
// This is used in the following definition of _parent_box, and holds one group of barriers.
typedef struct {
PXreal back, left; // Back/left of the bounding box holding this group of barriers (looking down into the model).
PXreal front, right; // Ditto front/right.
uint32 num_barriers; // Number of barriers in this group.
uint32 barriers[1]; // Array of barrier indices.
} ChildGroup;
// This holds one parent box entry.
typedef struct {
PXreal back, left; // Top/left of the parent box (looking down into the model).
PXreal front, right; // Ditto bottom/right.
uint32 num_barriers; // Number of barriers in the parent (not its children).
uint32 barriers; // Offset to an array of barrier indices.
uint32 num_specials; // Number of special barriers (eg. field-of-view).
uint32 specials; // Offset of the array of special barrier indices.
uint32 num_childgroups; // Number of child groups owned by this parent box.
uint32 childgroups[1]; // Array of offsets to the child groups.
} ParentBox;
// This is also a slice through the model, but the data is grouped in a different way which is more suited to routing.
typedef struct {
PXreal bottom; // The bottom of the slice.
PXreal top; // The top of the slice.
uint32 num_parent_boxes; // The number of parent boxes in this slice (same as the number of floor rectangles at this height).
uint32 parent_boxes[1]; // An array of offsets to parent boxes.
} RoutingSlice;
inline eBarrierLogicValue IsBarrierTo(eBarrierType eMaterial, eBarrierRayType eRay) { return barrierLogicTable[eMaterial][eRay]; }
} // End of namespace ICB
#endif // #ifndef _PX_ROUTE_BARRIERS_H_INCLUDED

View File

@@ -0,0 +1,534 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/p4.h"
#include "engines/icb/debug_pc.h"
#include "engines/icb/common/px_scriptengine.h"
#include "engines/icb/common/px_common.h" // common defs for tools & engine
#include "engines/icb/common/px_globalvariables.h" // The global variable class
#include "engines/icb/fn_routines.h"
#include "engines/icb/icb.h"
namespace ICB {
const char *playerString = "player";
CpxGlobalScriptVariables *g_globalScriptVariables;
// Information for the script program stack
#define STACK_SIZE 10 // The size of the stack
int32 stack[STACK_SIZE]; // The current stack
int32 stackPointer = 0; // Position within stack
#define _SCRIPT_ENGINE_ERROR(mess) Fatal_error("Script engine error\nObject %s\nScript %s\nMessage %s", CGameObject::GetName(object), scriptSourceName, mess)
// Check the stack pointer is within bounds
#define CheckStackPointer \
if (!((stackPointer >= 0) && (stackPointer < STACK_SIZE))) \
_SCRIPT_ENGINE_ERROR("Out of stack")
// Push a value on to the stack
#define PushOnStack(x) \
{ \
stack[stackPointer] = (x); \
stackPointer++; \
CheckStackPointer; \
}
// Pop a value from the stack
#define PopOffStack(x) \
{ \
x = stack[stackPointer - 1]; \
stackPointer--; \
CheckStackPointer; \
}
// Do a stack based two operator operation
#define DoBinaryOperation(x) \
{ \
stack[stackPointer - 2] = (x); \
stackPointer--; \
CheckStackPointer; \
}
// Do a stack based single operator operation
#define DoUnaryOperation(x) \
{ stack[stackPointer - 1] = (x); }
// Report an operation to the log file
#define TraceOperation(x, y) ScriptTrace("%d %s %d -> %d", stack[stackPointer - 2], x, stack[stackPointer - 1], stack[stackPointer - 2] y stack[stackPointer - 1]);
#define TraceUnaryOperation(x, y) ScriptTrace("%s %d -> %d", x, stack[stackPointer - 1], y stack[stackPointer - 1]);
// Macros for fetching data from the script file
#define Fetch8(var) \
{ \
var = *((char *)const_cast<char *>(actualScript)); \
actualScript += sizeof(char); \
}
#define Fetch32(param) \
{ \
param = *((int32 *)const_cast<char *>(actualScript)); \
actualScript += sizeof(int32); \
}
#define Read32ipLeaveip(var) \
{ var = *((int32 *)const_cast<char *>(actualScript)); }
#define Fetch16(param) \
{ \
param = *((int16 *)const_cast<char *>(actualScript)); \
actualScript += sizeof(int16); \
}
#define Read16ipLeaveip(var) \
{ var = *((int16 *)const_cast<char *>(actualScript)); }
#define UpdatePC \
{ scriptData = actualScript; }
#define ScriptTrace Zdebug
void SetScriptDebugging(bool8) {}
extern mcodeFunctionReturnCodes fn_context_chosen_logic(int32 &, int32 *);
extern mcodeFunctionReturnCodes fn_start_player_interaction(int32 &, int32 *);
scriptInterpreterReturnCodes RunScript(const char *&scriptData, // A pointer to the script data that can be modified
CGame *object, // A pointer to the object that owns this object
int32 *engineReturnValue2,
const char *scriptSourceName) { // A value to return to the game engine
// Run a script
ScriptTrace("Run script");
// Default return value is 0
if (engineReturnValue2)
*engineReturnValue2 = 0;
// Check if the script data begins with the check text, and skip it if it does
if (strncmp(scriptData, SCRIPT_CHECK_TEXT, SCRIPT_CHECK_TEXT_LEN) == 0)
scriptData += SCRIPT_CHECK_TEXT_LEN;
const char *actualScript = scriptData;
// Some variables to hold parameters and values
int32 parameter1, parameter2, value;
bool8 isInExpression = FALSE8;
// Variable to prevent infinite loops
uint32 infiniteLoopCounter = 0;
while (*actualScript) {
// Quick check for infinite loops
infiniteLoopCounter++;
if (infiniteLoopCounter > 10000) {
// Oh dear, what do we do now.
Fatal_error("Internal script loop in object %s", CGameObject::GetName(object));
}
int32 command = *(actualScript++);
// so that call_mcode and call_mcode_expr can share code...
isInExpression = FALSE8;
switch (command) {
case CP_PUSH_INT32: { // 1: Push a 32 bit integer
Fetch32(parameter1);
ScriptTrace("Push number(32 bit) %d", parameter1);
PushOnStack(parameter1);
} break;
case CP_PUSH_INT16: { // 1: Push a 16 bit integer
int16 sixteenBit;
Fetch16(sixteenBit);
ScriptTrace("Push number(16 bit) %d", sixteenBit);
PushOnStack((int32)sixteenBit);
} break;
case CP_PUSH_INT8: { // 1: Push an 8 bit integer
int8 eightBit;
Fetch8(eightBit);
ScriptTrace("Push number(8 bit) %d", eightBit);
PushOnStack((int32)eightBit);
} break;
case CP_PUSH_ADDRESS_LOCAL_VAR32: {
Fetch8(value); // Get the local variable number
if (!((value >= 0) && (value < (int32)CGameObject::GetNoLvars(object))))
_SCRIPT_ENGINE_ERROR("Local variable out of range");
ScriptTrace("Push address of local integer variable %d = %d", value, CGameObject::GetIntegerVariable(object, value));
PushOnStack(MemoryUtil::encodePtr((uint8 *)CGameObject::GetIntegerVariablePtr(object, value)));
} break;
case CP_SKIPONFALSE: { // 4 : Skip a chunk if a result if false
Read32ipLeaveip(parameter1) PopOffStack(value);
ScriptTrace("Skip %d if %d is false", parameter1, value);
if (value)
actualScript += sizeof(int32);
else
actualScript += parameter1;
} break;
case CP_SKIPALLWAYS: { // 5 : Skip a chunk
Read32ipLeaveip(parameter1) ScriptTrace("Skip %d", parameter1);
actualScript += parameter1;
} break;
case CP_SKIPONTRUE: { // 6 : Skip a chunk if a result if true
Read32ipLeaveip(parameter1) PopOffStack(value);
ScriptTrace("Skip %d if %d is true", parameter1, value);
if (value)
actualScript -= parameter1;
else
actualScript += sizeof(int32);
} break;
case CP_RETURN: { // po value off stack and return it to the game engine
if (!engineReturnValue2)
_SCRIPT_ENGINE_ERROR("No return value");
PopOffStack(*engineReturnValue2);
ScriptTrace("Return %d to game engine", *engineReturnValue2);
return (IR_RET_END_THE_CYCLE);
} break;
case CP_PUSH_GLOBAL_VAR32: {
Fetch32(parameter1); // hash of global
parameter2 = g_globalScriptVariables->GetVariable(parameter1); // value of global
PushOnStack(parameter2); // push on stack
// printf("push global 0x%08x = %d",parameter1,parameter2);
} break;
case CP_POP_GLOBAL_VAR32: {
Fetch32(parameter1); // hash of global
PopOffStack(parameter2); // value from stack
g_globalScriptVariables->SetVariable(parameter1, parameter2); // set value
// printf("pop global 0x%08x = %d",parameter1,parameter2);
} break;
// isInExpression starts off at false as it is set every loop of the while...
case CP_CALL_MCODE_EXPR:
isInExpression = TRUE8; // set to true and carry on running this code...
// falls through
case CP_CALL_MCODE: { // 10: Call an mcode routine
// Get the mcode number
int16 fnNumber;
Fetch16(fnNumber);
const int16 numApiRoutines = (g_icb->getGameType() == GType_ELDORADO) ? NO_API_ROUTINES_ELDORADO : NO_API_ROUTINES_ICB;
if (!((fnNumber >= 0) && (fnNumber < numApiRoutines)))
_SCRIPT_ENGINE_ERROR("fnNumber out of range?");
// Get the number of parameters
Fetch8(value); // amount to adjust stack by (no of parameters)
ScriptTrace("Call mcode %d (%sin expression)", fnNumber, isInExpression ? "" : "not ");
int32 routineReturnParameter = 0; // The value returned by the mcode routine
mcodeFunctionReturnCodes mcodeRetVal;
if (g_icb->getGameType() == GType_ICB) {
mcodeRetVal = McodeTableICB[fnNumber](routineReturnParameter, stack + (stackPointer - value));
} else if (g_icb->getGameType() == GType_ELDORADO) {
mcodeRetVal = McodeTableED[fnNumber](routineReturnParameter, stack + (stackPointer - value));
} else {
error("unknown game type");
}
ScriptTrace("api returned %d(%d)", mcodeRetVal, routineReturnParameter);
// Correct the stack for the parameters pushed on
stackPointer -= value;
// If this is part of an expression then we want to
// push the return value on to the stack
// Otherwise we may want to pause the script here
if (isInExpression) {
// Push the fn_routine return value
PushOnStack(routineReturnParameter);
// save the mcode return value
} else {
// Check return value in case we want to pause the script
switch (mcodeRetVal) {
case IR_STOP:
UpdatePC;
ScriptTrace("Script returns IR_RET_END_THE_CYCLE");
return (IR_RET_END_THE_CYCLE);
case IR_CONT:
// Continue the script
break;
case IR_TERMINATE:
ScriptTrace("Script returns IR_RET_CONT_THIS_CYCLE");
return (IR_RET_CONT_THIS_CYCLE);
case IR_REPEAT:
ScriptTrace("Script returns IR_RET_END_THE_CYCLE");
return (IR_RET_END_THE_CYCLE);
case IR_GOSUB:
UpdatePC;
ScriptTrace("Script returns IR_RET_END_THE_CYCLE");
return (IR_RET_END_THE_CYCLE);
}
}
} break;
case CP_QUIT: {
// Quit for a cycle
UpdatePC;
return (IR_RET_END_THE_CYCLE);
} break;
case CP_PUSH_STRING:
Fetch8(value); // the length of the string
ScriptTrace("Push string \"%s\"", actualScript);
// printf("push \"%s\"\n",actualScript);
PushOnStack(MemoryUtil::encodePtr((uint8 *)const_cast<char *>(actualScript))); // The pointer to the string
actualScript += value;
break;
case CP_PUSH_STRING_REFERENCE:
Fetch32(parameter1); // lookup (backwards)
ScriptTrace("Push string reference \"%s\"", actualScript + parameter1 - 4);
// printf("push reference \"%s\"\n",actualScript+parameter1-4);
PushOnStack(MemoryUtil::encodePtr((uint8 *)const_cast<char *>(actualScript + parameter1 - 4)));
break;
case CP_PUSH_STRING_PLAYER:
ScriptTrace("Push special string \"player\"");
// printf("push special \"player\"\n");
PushOnStack(MemoryUtil::encodePtr((uint8 *)const_cast<char *>(playerString)));
break;
case CP_CALL_VSCRIPT_ON_TRUE: { // 14: Call a virtual script if a result is true
// Get the value to check
PopOffStack(value);
// Get the script index
Fetch32(parameter1);
if (!((parameter1 >= 0) && (parameter1 < (int32)CGameObject::GetNoScripts(object))))
_SCRIPT_ENGINE_ERROR("Virtual script call out of range");
// Get the type
Fetch8(parameter2);
ScriptTrace("if (%d) call virtual script %d (%d)", value, parameter1, CGameObject::GetScriptNameFullHash(object, parameter1));
if (value) {
parameter1 &= 0xffff;
int32 dummyReturnValue;
ScriptTrace("param2 = %d", parameter2);
int32 scriptHash = CGameObject::GetScriptNameFullHash(object, parameter1);
if (parameter2) {
ScriptTrace("interact");
fn_start_player_interaction(dummyReturnValue, &scriptHash);
} else {
ScriptTrace("chosen logic");
fn_context_chosen_logic(dummyReturnValue, &scriptHash);
}
// Update and finish
UpdatePC;
return (IR_RET_CONT_THIS_CYCLE);
}
} break;
case CP_SAVE_MCODE_START: // 15: Update the script pc, usually before doing an mcode routine
UpdatePC;
ScriptTrace("Update pc");
break;
case CP_PUSH_LOCAL_VAR32: // 16: Push a local variable on to the stack
Fetch8(value); // Get the local variable number
if (!((value >= 0) && (value < (int32)CGameObject::GetNoLvars(object))))
_SCRIPT_ENGINE_ERROR("Unknown variable??");
ScriptTrace("Push local integer variable %d = %d", value, CGameObject::GetIntegerVariable(object, value));
PushOnStack(CGameObject::GetIntegerVariable(object, value));
break;
case CP_POP_LOCAL_VAR32: // 17 // Pop a local variable from the stack
Fetch8(value); // Get the local variable number
if (!(value >= 0) && (value < (int32)CGameObject::GetNoLvars(object)))
_SCRIPT_ENGINE_ERROR("Unknown variable??");
ScriptTrace("Pop local variable %d", value);
{
int32 varValue;
PopOffStack(varValue);
CGameObject::SetIntegerVariable(object, value, varValue);
}
break;
case CP_PUSH_LOCAL_VARSTRING: // 18: Push a local string variable on to the stack
Fetch8(value); // Get the local variable number
if (!((value >= 0) && (value < (int32)CGameObject::GetNoLvars(object))))
_SCRIPT_ENGINE_ERROR("Unknown variable (string)??");
ScriptTrace("Push local string variable %d = \"%s\"", value, CGameObject::GetStringVariable(object, value));
PushOnStack(MemoryUtil::encodePtr((uint8 *)const_cast<char *>(CGameObject::GetStringVariable(object, value))));
break;
case CP_DEBUG: { // 19: Debug options
Fetch8(value); // Get the debug type
} break;
case CP_INITIALISEGLOBAL: {
// Initialise a global
_SCRIPT_ENGINE_ERROR("Can't initialise a variable here anymore");
} break;
case CP_SWITCH: {
int32 i, size, found;
PopOffStack(parameter1); // value
Fetch32(parameter2); // 4 byte offset to table
ScriptTrace("Start of switch statement - value: %d", parameter1);
actualScript += parameter2 - sizeof(int32);
Fetch8(size); // 1 byte number of cases
i = 0;
found = 0;
while (!found) {
Fetch32(value); // case value (or offset if default case)
if (i == (size - 1)) { // default case
actualScript += value - sizeof(int32);
found = 1;
} else {
Fetch32(parameter2); // case code offset
if (value == parameter1) { // if switch value = this case value
actualScript += parameter2 - sizeof(int32); // do the jump
found = 1;
}
}
i++;
}
} break;
case CP_PUSH_0: {
ScriptTrace("Push 0");
PushOnStack(0);
} break;
case CP_PUSH_1: {
ScriptTrace("Push 1");
PushOnStack(1);
} break;
case OP_TIMES: { // 32 // '*'
ScriptTrace("*");
TraceOperation("*", *)DoBinaryOperation((stack[stackPointer - 2] * stack[stackPointer - 1]));
} break;
case OP_DIVIDE: { // 34 // '/'
ScriptTrace("/");
TraceOperation("/", / ) DoBinaryOperation((stack[stackPointer - 2] / stack[stackPointer - 1]));
} break;
case OP_PLUS: { // 31 // '+'
ScriptTrace("+");
TraceOperation("+", +) DoBinaryOperation((stack[stackPointer - 2] + stack[stackPointer - 1]));
} break;
case OP_MINUS: { // 33 // '-'
ScriptTrace("-");
TraceOperation("-", -) DoBinaryOperation((stack[stackPointer - 2] - stack[stackPointer - 1]));
} break;
case OP_LSTHAN: { // 35 // '<'
ScriptTrace("<");
TraceOperation("<", < ) DoBinaryOperation((stack[stackPointer - 2] < stack[stackPointer - 1]));
} break;
case OP_GTTHAN: { // 39 // '>'
ScriptTrace(">");
TraceOperation(">", > ) DoBinaryOperation((stack[stackPointer - 2] > stack[stackPointer - 1]));
} break;
case OP_LSTHANE: { // 42 // '<='
ScriptTrace("<=");
TraceOperation("<=", <= ) DoBinaryOperation((stack[stackPointer - 2] <= stack[stackPointer - 1]));
} break;
case OP_GTTHANE: { // 41 // '>='
ScriptTrace(">=");
TraceOperation(">=", >= ) DoBinaryOperation((stack[stackPointer - 2] >= stack[stackPointer - 1]));
} break;
case OP_ISEQUAL: { // 30: '=='
ScriptTrace("==");
TraceOperation("==", == ) DoBinaryOperation((stack[stackPointer - 2] == stack[stackPointer - 1]));
} break;
case OP_NOTEQUAL: { // 36: '!='
ScriptTrace("!=");
TraceOperation("!=", != ) DoBinaryOperation((stack[stackPointer - 2] != stack[stackPointer - 1]));
} break;
case OP_ANDAND: { // 37 // '&&'
ScriptTrace("&&");
TraceOperation("&&", &&) DoBinaryOperation((stack[stackPointer - 2] && stack[stackPointer - 1]));
} break;
case OP_OROR: { // 38 // '||'
ScriptTrace("||");
TraceOperation("||", || ) DoBinaryOperation((stack[stackPointer - 2] || stack[stackPointer - 1]));
} break;
case TK_UNARY_NOT: { // 50 // '!'
// _SCRIPT_ENGINE_ERROR("I aint doing that!");
ScriptTrace("!");
TraceUnaryOperation("!", !) DoUnaryOperation(!stack[stackPointer - 1]);
} break;
case TK_UNARY_MINUS: { // 51 // '-'
ScriptTrace("-");
TraceUnaryOperation("-", -) DoUnaryOperation(-stack[stackPointer - 1]);
} break;
default: { _SCRIPT_ENGINE_ERROR(pxVString("Invalid script token %d", command)); }
}
}
ScriptTrace("Script Done");
return (IR_RET_SCRIPT_FINISHED);
}
} // End of namespace ICB

View File

@@ -0,0 +1,143 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_GAME_ENGINE_SCRIPTENGINE_H
#define ICB_GAME_ENGINE_SCRIPTENGINE_H
#include "engines/icb/common/px_string.h"
#include "engines/icb/common/px_game_object.h"
#include "engines/icb/common/px_globalvariables.h"
namespace ICB {
#define SCRIPT_CHECK_TEXT "SDS>"
#define SCRIPT_CHECK_TEXT_LEN 4
enum scriptInterpreterReturnCodes {
IR_RET_END_THE_CYCLE = 0, // done enough this cycle
IR_RET_SCRIPT_FINISHED = 1, // current script has finished and hit closing brace
IR_RET_CONT_THIS_CYCLE = 2 // FN_ returned an IR_TERMINATE to interpreter so we just go around - new script or gosub
};
scriptInterpreterReturnCodes RunScript(const char *&scriptData, // A pointer to the script data that can be modified
CGame *object, // A pointer to the object that owns this object
int32 *engineReturnValue = NULL,
const char *scriptSourceName = NULL); // A value to return to the game engine
void SetScriptDebugging(bool8 f); // Set script debugging flag
extern CpxGlobalScriptVariables *g_globalScriptVariables;
#define CP_END_SCRIPT 0 // Terminate a script
#define CP_PUSH_INT32 1 // Push a number on to the stack
#define CP_PUSH_ADDRESS_LOCAL_VAR32 2 // Push the address of a local variable
//#define CP_CALL_SCRIPT_ON_TRUE 3 // Call a script if the expression result is true
// Not sure where this is used
#define CP_SKIPONFALSE 4 // Skip if the bottom value on the stack is false
#define CP_SKIPALLWAYS 5 // Skip a block of code
#define CP_SKIPONTRUE 6 // Skip if the bottom value on the stack is true
#define CP_RETURN 7 // return the value on the stack to the game engine
#define CP_PUSH_GLOBAL_VAR32 8 // Set a variable to 1
#define CP_POP_GLOBAL_VAR32 9 // Pop a global variable
#define CP_CALL_MCODE 10 // Call a machine code function
#define CP_QUIT 11 // Quit for a cycle
#define CP_PUSH_STRING 12 // Push a pointer to a string
//#define CP_LINE_NUMBER 13 // Notify a change of script line number
#define CP_CALL_VSCRIPT_ON_TRUE 14 // Call a virtual script if the expression result is true
// The script name is taken from the object virtual
// script table
#define CP_SAVE_MCODE_START 15 // Save the mcode code start for restarting when necessary
#define CP_PUSH_LOCAL_VAR32 16 // Push a local variable on to the stack
#define CP_POP_LOCAL_VAR32 17 // Pop a local variable from the stack
#define CP_PUSH_LOCAL_VARSTRING 18 // Push a local variable on to the stack
#define CP_DEBUG 19 // A debug command
#define CP_INITIALISEGLOBAL 20 // Initialise a global variable
#define CP_SWITCH 21 // takes value of the stack and uses with switch table...
#define CP_PUSH_0 22 // push 0 on the stack (a slight speed advantage and a space saving)
#define CP_PUSH_1 23 // push 1 on the stack (a slight speed advantage and a space saving)
// It was decided that the following fix to the return code of fn routines
// in expressions was not to be applied, but the code has been kept just in
// case
// special push variations to save space
#define CP_PUSH_INT16 26
#define CP_PUSH_INT8 27
#define CP_PUSH_STRING_REFERENCE 28
// An invalid token
#define CP_INVALID_TOKEN 29 // For functions where a token is required, but not appropriate
// Binary Operators
#define OP_ISEQUAL 30 // '=='
#define OP_PLUS 31 // '+'
#define OP_TIMES 32 // '*'
#define OP_MINUS 33 // '-'
#define OP_DIVIDE 34 // '/'
#define OP_LSTHAN 35 // <
#define OP_NOTEQUAL 36 // '!='
#define OP_ANDAND 37 // &&
#define OP_OROR 38 // || or OR
#define OP_GTTHAN 39 // >
#define OP_GTTHANE 41 // >=
#define OP_LSTHANE 42 // <=
// Unary Operators
#define TK_UNARY_NOT 50 // ! Invert a boolean
#define TK_UNARY_MINUS 51 // - Negate a number
// a special op which pushes the string "player" onto the stack
#define CP_PUSH_STRING_PLAYER 52
// a new version of call_mcode which sets inside expression to true (saves 1 byte per fn_call)
#define CP_CALL_MCODE_EXPR 53
// Command tokens, only ever used internally
#define CT_IF 100 // An if statement
#define CT_CLOSEBRACKET 101 // )
#define CT_SEMICOLON 102 // ;
#define CT_ONCE 103 // the 'once' command
#define CT_CLOSEBRACE 104 // }
#define CT_DOUBLECLOSEBRACE 105 // Two tab indent reduction
#define CT_DO 106 // the 'do' command
#define CT_RETURN 107 // return a value to the engine
#define CT_SWITCH 108 // Switch
#define CT_QUIT 109 // Quit for a cycle
#define CT_COMMA 110 // ,
#define CT_OPENBRACE 111 // {
#define CT_DEBUG 112 // Debug commands
#define CT_INITIALISEGLOBAL 113 // Initialise a global variable
#define CT_WHILE 114 // the 'while' command
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,97 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_SFX_DESCRIPTION_H
#define ICB_PX_SFX_DESCRIPTION_H
namespace ICB {
// versions...
// 100 initial
// 101 rearanged
// 105 added also to sfxdesc files to be checked by converter
//
#define SFX_VERSION 105
#define NO_LOOPING 0x00
#define WAV_LOOPING_FLAG 0x01
#define SFX_LOOPING_FLAG 0x02
// this class contains an envelope of the form y=ax^3+bx^2+cx+d
class CEnvelope {
public:
int32 a;
int32 b;
int32 c;
int32 d;
int8 div; // dividing value on the time scale
CEnvelope() { Reset(); }
void Reset() {
a = b = c = d = 0;
div = 1;
}
};
// this class contains a single sfx ready to be saved out. This will go in it's own file eventually...
class CSfx {
public:
CSfx() { Reset(); }
CEnvelope m_volume; // volume where v<=0 => none >=128 => max
CEnvelope m_pitch; // pitch addition to base pitch (in PSX pitch units where 0x1000=44100hz, etc)
int32 m_duration; // duration in 128th of second
int32 m_rand_pitch; // random value to add to pitch at start (in PSX pitch units where 0x1000=44100hz, etc)
int32 m_min_distance; // in cm
int32 m_max_distance; // in cm
int8 m_sampleNameOffset; // offset into structure of sampleName...
int8 m_descOffset; // generally this will be 0 when outputing for the engine since the engine will not need descriptions
int8 m_looping; // BIT 0 is hardware flag, bit 1 is software flag.
int8 m_rand_mode; // mode=0 is normal, choose a random value at startup, mode>0 is some divider of the envelope
void Reset() {
m_volume.Reset();
m_pitch.Reset();
m_duration = 0;
m_looping = 0;
m_rand_pitch = 0;
m_rand_mode = 0;
m_sampleNameOffset = 0;
m_descOffset = 0;
m_min_distance = 0;
m_max_distance = 0;
}
const char *GetSampleName() { return (const char *) this + m_sampleNameOffset; }
};
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,58 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
namespace ICB {
#define PITCH_MULT \
{ \
128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 142, 142, 143, \
143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 150, 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, 156, 156, 157, 157, 158, 158, 159, 160, \
160, 161, 161, 162, 163, 163, 164, 164, 165, 165, 166, 167, 167, 168, 169, 169, 170, 170, 171, 172, 172, 173, 173, 174, 175, 175, 176, 177, 177, 178, 179, \
179, 180, 181, 181, 182, 182, 183, 184, 184, 185, 186, 186, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 197, 198, 198, 199, 200, \
200, 201, 202, 203, 203, 204, 205, 206, 206, 207, 208, 209, 209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 219, 219, 220, 221, 222, 223, 223, \
224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 233, 233, 234, 235, 236, 237, 238, 239, 239, 240, 241, 242, 243, 244, 245, 246, 246, 247, 248, 249, 250, \
251, 252, 253, 254, 255 \
}
#define PITCH_DIV \
{ \
128, 127, 127, 126, 126, 125, 125, 124, 124, 123, 123, 123, 122, 122, 121, 121, 120, 120, 119, 119, 119, 118, 118, 117, 117, 116, 116, 116, 115, 115, 114, 114, \
114, 113, 113, 112, 112, 111, 111, 111, 110, 110, 109, 109, 109, 108, 108, 108, 107, 107, 106, 106, 106, 105, 105, 104, 104, 104, 103, 103, 103, 102, 102, \
101, 101, 101, 100, 100, 100, 99, 99, 99, 98, 98, 97, 97, 97, 96, 96, 96, 95, 95, 95, 94, 94, 94, 93, 93, 93, 92, 92, 92, 91, 91, 91, 90, 90, 90, 89, 89, 89, \
88, 88, 88, 87, 87, 87, 86, 86, 86, 86, 85, 85, 85, 84, 84, 84, 83, 83, 83, 82, 82, 82, 82, 81, 81, 81, 80, 80, 80, 80, 79, 79, 79, 78, 78, 78, 78, 77, 77, \
77, 76, 76, 76, 76, 75, 75, 75, 75, 74, 74, 74, 73, 73, 73, 73, 72, 72, 72, 72, 71, 71, 71, 71, 70, 70, 70, 70, 69, 69, 69, 69, 68, 68, 68, 68, 67, 67, 67, \
67, 66, 66, 66, 66, 65, 65, 65, 65, 64, 64, 64, 64 \
}
#define VOL_FUNCTION \
{ \
0, 11, 16, 19, 22, 25, 27, 29, 32, 33, 35, 37, 39, 40, 42, 43, 45, 46, 47, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 64, 65, 66, 67, 68, 69, 70, 71, \
72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89, 89, 90, 91, 91, 92, 93, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99, 100, \
101, 101, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108, 109, 109, 110, 110, 111, 111, 112, 113, 113, 114, 114, 115, 115, 116, 117, 117, 118, 118, \
119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127 \
}
} // End of namespace ICB

View File

@@ -0,0 +1,71 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_STATIC_LAYERS_H
#define ICB_PX_STATIC_LAYERS_H
#include "engines/icb/common/px_common.h"
namespace ICB {
#define PCLAYER_SCHEMA 1
#define PCLAYER_ID MKTAG('r', 'y', 'a', 'L')
#define TILE_WIDTH 64
#define TILE_HEIGHT 48
#define TILES_WIDE (640 / TILE_WIDTH)
#define TILES_HIGH (480 / TILE_HEIGHT)
#define TILE_COUNT (TILES_WIDE * TILES_HIGH)
class pcStaticLayers {
private:
char id[4];
uint32 schema;
uint32 mapping;
uint32 tilePtrs[TILE_COUNT]; // 10 x 10 array of tiles (null means an empty tile)
uint32 semiPtrs[TILE_COUNT]; // 10 x 10 array of tiles (null means an empty tile)
uint8 *DataStart() { return (uint8 *)id; }
public:
uint16 *GetSemiTileTable(int32 idx) { return semiPtrs[idx] ? (uint16 *)(DataStart() + semiPtrs[idx]) : 0; }
uint16 *GetTileTable(int32 idx) { return tilePtrs[idx] ? (uint16 *)(DataStart() + tilePtrs[idx]) : 0; }
uint32 GetSchema() {
if (READ_LE_U32(id) != PCLAYER_ID)
return 0;
else
return schema;
}
pcStaticLayers () {
(void)mapping; // shutup warning
}
};
} // End of namespace ICB
#endif // _PX_STATIC_LAYERS_H

View File

@@ -0,0 +1,336 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_string.h"
#include "common/textconsole.h"
namespace ICB {
#define SLEN_CHECK (slen < 0)
const char *pxString::operator=(const char *str) {
// Assign a value
// If we are assigning the string to ourself, then no assignment is necessary
if (str == s)
return (s);
if (s)
delete[] s;
if (str) {
// We are not assigning a null string
uint32 len = strlen(const_cast<char *>(str)) + 1;
s = new char[len];
memcpy((unsigned char *)s, (unsigned char *)const_cast<char *>(str), len);
} else
s = nullptr; // Just the null string
return (s);
}
void pxString::operator=(const pxString &str) {
// Assign a value
if (s)
delete[] s;
if (str.s) {
// We are not assigning a null string
uint32 len = strlen((char *)(str.s)) + 1;
s = new char[len];
memcpy((unsigned char *)s, (unsigned char *)str.s, len);
} else
s = nullptr; // Null string
}
const char *pxString::operator+=(const char *adder) {
// Add a string
if (adder) {
uint32 slen = s ? strlen(s) : 0; // Get original string length
uint32 adderlen = strlen(const_cast<char *>(adder)); // Get additional string length
char *buf = new char[slen + adderlen + 1]; // Create a buffer
if (s)
memcpy((unsigned char *)buf, (unsigned char *)s, slen); // Move the original string in
memcpy((unsigned char *)buf + slen, (unsigned char *)const_cast<char *>(adder), adderlen + 1); // And put the additional string in
// Tidy up
delete[] s;
s = buf;
}
return (s);
}
const pxString pxString::operator+(const char *adder) const {
// Produce a string addition without affecting this object
pxString temp(s);
temp += adder;
return (temp);
}
bool pxString::operator==(const char *string) const {
// Do a character by character comparison
if (s == nullptr)
return ((bool)(string == nullptr));
if (string == nullptr)
return (false);
return ((bool)(strcmp(s, const_cast<char *>(string)) == 0));
}
void pxString::SetString(const char *data, uint32 len) {
// Get the first len characters from another string
// Lose any string we currently hold
if (s)
delete[] s;
// If the data is NULL then we become NULL
if (data) {
// Copy in the data
s = new char[len + 1];
memcpy((unsigned char *)s, (unsigned char *)const_cast<char *>(data), len);
// And null terminate it
s[len] = 0;
} else
s = nullptr;
}
void pxString::Substr(pxString &rsStr, uint32 nStart, uint32 nNum) const {
char *pNewString;
uint32 slen = strlen(s); // ds: No need to calculate this several times
// Do some range checking.
if (nStart > (slen - 1)) {
rsStr = "";
return;
}
// If the requested substring goes past the end of the existing string, simply clip it
// after the last character in the existing one.
if (nStart + nNum > slen)
nNum -= (nStart + nNum) - slen;
// Create a buffer the correct size to hold the new substring
pNewString = new char[nNum + 1];
// Copy in the substring.
memcpy((unsigned char *)pNewString, (unsigned char *)&s[nStart], nNum);
// Put the terminator on.
pNewString[nNum] = '\0';
// Make the new pxString from the buffer.
rsStr = pNewString;
// ds: Deallocate the temporary buffer
delete[] pNewString;
}
uint32 pxString::StrChr(char cToFind, uint32 nStartPos) const {
char *pcPositionOfFirst;
uint32 nStringLength = strlen(s);
// Check if the start position is outside the string.
if (nStartPos >= nStringLength)
return nStringLength;
// I use strchr, which relies on the pxString being implemented as a character array,
// but it is OK to do it in here, 'cos if the internal representation changed, presumably
// every function in this class would need looking at anyway.
pcPositionOfFirst = strchr(s + nStartPos, static_cast<uint>(cToFind));
if (pcPositionOfFirst) {
// Character was found. Work out its index from the address.
return (pcPositionOfFirst - s);
} else {
// I use the length of the string as a rogue value to indicate the character wasn't found.
return nStringLength;
}
}
void pxString::ToUpper() {
if (s) {
char *sp = s;
while (*sp) {
*sp = (char)toupper(*sp);
sp++;
}
}
}
void pxString::ToLower() {
if (s) {
char *sp = s;
while (*sp) {
*sp = (char)tolower(*sp);
sp++;
}
}
}
void pxString::ConvertPath() {
if (s) {
char *sp = s;
while (*sp) {
*sp = (*sp == '\\' ? '/' : *sp);
sp++;
}
// trim '/'
if (*s == '/') {
uint32 len = strlen((char *)s);
sp = new char[len];
memcpy((unsigned char *)sp, (unsigned char *)(s + 1), len);
delete[] s;
s = sp;
}
}
}
const pxString &pxString::Format(const char *format, ...) {
if (s)
delete[] s;
s = nullptr;
// Check for a null parameter
if (format == nullptr)
return (*this);
// The data could be any size. Rather than incrementally allocating memory until
// it fits a large buffer multiple is used that should cover 99.9% of all strings
// but will still cope with unfeasably large ones
uint32 startBufferSize = 1024;
// Allocate a start buffer
s = new char[startBufferSize + 2];
if (s == nullptr)
return (*this);
// Process the variable arguments
va_list arglist;
int32 slen;
// Keep doubling the size of the buffer until it fits
while (va_start(arglist, format), slen = vsnprintf(s, startBufferSize, const_cast<char *>(format), arglist), SLEN_CHECK) {
delete[] s;
startBufferSize += startBufferSize;
s = new char[startBufferSize + 2];
// According to VC5 release mode this code is unreachable
// I can't see why, so I shall turn the warning off for this bit of code
// If the sllocation failed return an empty string
if (s == nullptr)
return (*this);
}
// Tidy up and finish
va_end(arglist);
// At this point the buffer in s is much larger than it needs to be
// In the interest of saving space, it will now be reduced
assert(slen == (int32)strlen(s));
char *tempBuffer = new char[slen + 1];
// If this allocation fails leave the string as it is
if (tempBuffer) {
memcpy((unsigned char *)tempBuffer, (unsigned char *)s, slen + 1);
delete[] s;
s = tempBuffer;
}
return (*this);
}
// build a temporary string
const char *pxVString(const char *format, ...) {
#define PXV_BUF_SIZE 1024
static char buf[PXV_BUF_SIZE];
va_list va;
va_start(va, format);
vsnprintf(buf, PXV_BUF_SIZE, format, va);
va_end(va);
#undef PXV_BUF_SIZE
return buf;
}
pxFixedCharBuffer::pxFixedCharBuffer(uint32 len) {
// Construct the object with the appropriate amount of data
m_data = new char[len];
// Check for an error
if (m_data == nullptr) {
error("pxFixedCharBuffer memory allocation error");
}
}
pxFlexiCharBuffer::pxFlexiCharBuffer(uint32 initLen) {
m_bufLen = initLen;
m_buffer = new char[initLen]; // The buffer itself
}
pxFlexiCharBuffer::~pxFlexiCharBuffer() { delete[] m_buffer; }
char &pxFlexiCharBuffer::operator[](uint32 offset) {
CheckSize(offset);
return (m_buffer[offset]);
}
void pxFlexiCharBuffer::CheckSize(uint32 size) {
// Make sure we have enough room
if (size >= m_bufLen) {
uint32 newLen = size + 1;
char *newb = new char[newLen];
assert(newb);
memcpy((unsigned char *)newb, (unsigned char *)m_buffer, m_bufLen);
delete[] m_buffer;
m_buffer = newb;
m_bufLen = newLen;
}
}
void pxFlexiCharBuffer::StrCpy(uint32 offset, const char *string) {
// Add a string
uint32 slen = strlen(const_cast<char *>(string));
CheckSize(offset + slen);
memcpy((unsigned char *)(m_buffer + offset), (unsigned char *)const_cast<char *>(string), slen);
}
void pxFlexiCharBuffer::StrnCpy(uint32 offset, const char *string, uint32 len) {
// Copy a number of characters to the buffer
CheckSize(offset + len);
memcpy((unsigned char *)(m_buffer + offset), (unsigned char *)const_cast<char *>(string), len);
}
} // End of namespace ICB

View File

@@ -0,0 +1,195 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PX_STRING_H
#define ICB_PX_STRING_H
#include "engines/icb/common/px_rcutypes.h"
namespace ICB {
class pxString {
protected:
char *s; // The actual string
public:
pxString(); // Empty creator
pxString(const char *); // Copy constructor
pxString(const pxString &); // Copy constructor
~pxString(); // Destructor
operator const char *() const {
return (s); // Return a pointer to the string
}
const char *operator=(const char *); // Assign a value
void operator=(const pxString &); // Assign a value
const char *operator+=(const char *); // Add a string
char &operator[](uint32 n) {
return (s[n]); // Get a character (no reason not to allow it to change)
}
char &operator[](int32 n) {
return (s[n]); // Get a character (no reason not to allow it to change)
}
bool IsNull() const {
return ((bool)(s == NULL)); // Check for a null value
}
bool IsEmpty() const; // Check for an empty string
uint32 GetLen() const; // Returns the length of the string.
void ToUpper(); // Make contents of string uppercase
void ToLower(); // Make contents of string lowercase
void ConvertPath(); // Converts a path to native format
const char *c_str() { return s; }
const pxString &Format(const char *, ...); // Use variable arguments to set the string
const pxString operator+(const char *) const;
inline pxString Substr(uint32 nStart, uint32 nLen) const; // Return a part of this string
void Substr(pxString &rsStr, uint32 nStart, uint32 nLen) const; // A faster substring.
void SetString(const char *data, uint32 len); // Get the first len characters from another string
uint32 StrChr(char cToFind, uint32 nStartPos = 0) const; // Find position of a character in a string [PS 17/08/98]
// char * comparisons
bool operator==(const char *string) const; // Do a character by character comparison
bool operator!=(const char *string) const; // Do a character by character uncomparison
};
inline pxString::pxString(const pxString &str) {
if (str.s) {
// There is some data to copy
uint32 len = strlen((char *)str.s) + 1;
s = new char[len];
memcpy((unsigned char *)s, (unsigned char *)str.s, len);
} else
// No data for this string
s = NULL;
}
inline pxString::~pxString() {
// Destructor
if (s)
delete[] s;
}
const char *pxVString(MSVC_PRINTF const char *format, ...) GCC_PRINTF(1, 2);
class pxFlexiCharBuffer {
char *m_buffer; // The buffer itself
uint32 m_bufLen; // The buffer length
public:
// explicit
pxFlexiCharBuffer(uint32 len = 40);
~pxFlexiCharBuffer();
char &operator[](uint32); // Allow array access
void CheckSize(uint32); // Make sure we have enough room
char *GetBuffer() {
return (m_buffer); // Make it a little more difficult to pass the pointer
}
// Pointer access was originally const char *, but for use as a buffer for reading in from
// files this needs to be changeable, and needs a void * operator
operator char *() {
return (m_buffer); // Treat as a char *
}
operator void *() {
return (m_buffer); // Treat as a void *
}
void StrCpy(uint32 offset, const char *text); // Copy a string to the buffer
void StrnCpy(uint32 offset, const char *text, uint32 len); // Copy a number of characters to the buffer
// Prevent copy or assignment
private:
pxFlexiCharBuffer(const pxFlexiCharBuffer &) {}
void operator=(const pxFlexiCharBuffer &) {}
};
class pxFixedCharBuffer {
char *m_data;
public:
pxFixedCharBuffer(uint32 len);
~pxFixedCharBuffer() { delete[] m_data; }
operator void *() { return (m_data); }
operator char *() { return (m_data); }
// Prevent copy or assignment
private:
pxFixedCharBuffer(const pxFixedCharBuffer &) {}
void operator=(const pxFixedCharBuffer &) {}
};
inline pxString::pxString() {
// Empty creator
s = NULL;
}
inline pxString::pxString(const char *str) {
// Copy constructor
if (str) {
uint32 len = strlen(str) + 1;
s = new char[len];
memcpy(s, str, len);
} else
s = NULL;
}
inline bool pxString::IsEmpty() const {
// Check for an empty string
if ((s == NULL) || (*s == 0))
return (true);
return (false);
}
inline uint32 pxString::GetLen() const {
if ((s == NULL))
return (0);
return (strlen(s));
}
inline pxString pxString::Substr(uint32 nStart, uint32 nNum) const {
pxString rsRetVal;
Substr(rsRetVal, nStart, nNum);
return rsRetVal;
}
inline bool pxString::operator!=(const char *string) const {
// Do a character by character uncomparison
// Simply return the opposit of the == function
return ((bool)!((*this) == string));
}
} // End of namespace ICB
#endif // #ifndef _PX_pxString_H

View File

@@ -0,0 +1,41 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_PXTYPES_H
#define ICB_PXTYPES_H
namespace ICB {
typedef struct {
int32 left;
int32 top;
int32 right;
int32 bottom;
} LRECT;
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,150 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef WALKAREA_H
#define WALKAREA_H
#include "engines/icb/common/px_rcutypes.h"
namespace ICB {
#define INTEGER_WALKAREA_API_SCHEMA 1
struct __point { // 3D integer coordinate representation
__point(void) : x(0), y(0), z(0) { ; }
__point(int32 X, int32 Y, int32 Z) : x(X), y(Y), z(Z) { ; }
int32 x;
int32 y;
int32 z;
};
struct __aWalkArea{
char name[32]; // Name of the walkarea
char cameraCluster[8]; // Hashed cameraName value
// Bounding box dimensions
int32 x; // Top-left corner x coordinate (Revolution space)
int32 y; // Top-left corner y coordinate (Revolution space)
int32 z; // Top-left corner z coordinate (Revolution space)
int32 w; // Width
int32 h; // Height
// THE AREA DEFINITION (All in Revolution space)
uint32 noPoints; // Number of verteces\knots in 2D spline
__point points[1]; // The points themselves (spline is always closed)
char cameraName[1]; // Name of associated camera (DWORD aligned)
};
class INTEGER_WalkAreaFile {
public:
uint32 schema; // The format version
char ID[4]; // ID "WGA"
// Class methods
INTEGER_WalkAreaFile() { ; }
~INTEGER_WalkAreaFile() { ; }
uint32 GetSchema(void) const { return schema; }
uint32 GetNoAreas(void) const { return noAreas; }
// Get pointer to a specific WalkArea
inline const __aWalkArea *GetWalkArea(uint32 number) const;
inline uint32 GetNoPoints(uint32 number) const;
inline int32 GetBox_X(uint32 number) const;
inline int32 GetBox_Y(uint32 number) const;
inline int32 GetBox_Z(uint32 number) const;
inline int32 GetBox_W(uint32 number) const;
inline int32 GetBox_H(uint32 number) const;
bool8 GetAreaName(uint32 number, const char *&name) const;
bool8 GetCluster(uint32 number, const char *&cluster) const;
bool8 GetPoint(uint32 area, uint32 number, __point &point) const;
bool8 GetCameraName(uint32 number, const char *&name) const;
private:
uint32 noAreas;
uint32 offsetTable[1];
};
inline const __aWalkArea *INTEGER_WalkAreaFile::GetWalkArea(uint32 number) const { return ((const __aWalkArea *)(((const char *)this) + offsetTable[number])); }
inline uint32 INTEGER_WalkAreaFile::GetNoPoints(uint32 number) const { return (GetWalkArea(number)->noPoints); }
inline int32 INTEGER_WalkAreaFile::GetBox_X(uint32 number) const { return (GetWalkArea(number)->x); }
inline int32 INTEGER_WalkAreaFile::GetBox_Y(uint32 number) const { return (GetWalkArea(number)->y); }
inline int32 INTEGER_WalkAreaFile::GetBox_Z(uint32 number) const { return (GetWalkArea(number)->z); }
inline int32 INTEGER_WalkAreaFile::GetBox_W(uint32 number) const { return (GetWalkArea(number)->w); }
inline int32 INTEGER_WalkAreaFile::GetBox_H(uint32 number) const { return (GetWalkArea(number)->h); }
inline bool8 INTEGER_WalkAreaFile::GetAreaName(uint32 number, const char *&name) const {
if (number >= noAreas)
return FALSE8;
name = GetWalkArea(number)->name;
return TRUE8;
}
inline bool8 INTEGER_WalkAreaFile::GetCluster(uint32 number, const char *&cluster) const {
if (number >= noAreas)
return FALSE8;
cluster = GetWalkArea(number)->cameraCluster;
return TRUE8;
}
inline bool8 INTEGER_WalkAreaFile::GetPoint(uint32 area, uint32 number, __point &point) const {
if (area >= noAreas)
return FALSE8;
point.x = GetWalkArea(area)->points[number].x;
point.y = GetWalkArea(area)->points[number].y;
point.z = GetWalkArea(area)->points[number].z;
return TRUE8;
}
inline bool8 INTEGER_WalkAreaFile::GetCameraName(uint32 number, const char *&name) const {
if (number >= noAreas)
return FALSE8;
// Get the address of the start of the cameraName (by asking for a point that isn't there
name = (const char *)&GetWalkArea(number)->points[GetNoPoints(number)];
return TRUE8;
}
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,73 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_REVTEX_API_H
#define ICB_REVTEX_API_H
namespace ICB {
#define REVTEX_API_ID "RTX"
#define REVTEX_API_SCHEMA_ICB 1
#define REVTEX_API_SCHEMA_ELDORADO 2
#define MAX_PAL_ENTRIES (256)
typedef struct revtex_API_header {
char id[4];
uint32 schema;
} revtex_API_header;
// The level pointers within the RevTexture structure in this structure
// are relative addresses which get converted to absolute pointer by
// calling the Map function
typedef struct revtex_API_v1 {
char id[4];
uint32 schema;
// RevTexture revtex;
uint32 palette[256]; // windows 32-bit RGB with 1 byte of padding
uint32 width; // must be power of 2
uint32 height; // must be power of 2
uint32 levelOffset[9]; // width/1 * height/1 -> width/256 * height/256
} revtex_API_v1;
typedef struct revtex_API_v2 {
char id[4];
uint32 schema;
uint32 transparent;
// RevTexture revtex;
uint32 palette[256]; // windows 32-bit RGB with 1 byte of padding
uint32 width; // must be power of 2
uint32 height; // must be power of 2
uint32 levelOffset[9]; // width/1 * height/1 -> width/256 * height/256
} revtex_API_v2;
} // End of namespace ICB
#endif // #ifndef REVTEX_API_H

View File

@@ -0,0 +1,69 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/configfile.h"
#include "common/path.h"
#include "common/textconsole.h"
#include "common/formats/ini-file.h"
namespace ICB {
ConfigFile::ConfigFile() {}
void ConfigFile::readFile(const char *filename) {
Common::INIFile file;
if (!file.loadFromFile(Common::Path(filename, '/'))) {
error("Opening file '%s' failed'", filename);
return;
}
Common::INIFile::SectionList sections = file.getSections();
for (auto &i : sections) {
Common::INIFile::SectionKeyList kList = i.getKeys();
for (auto &j : kList) {
_dataSet[i.name][j.key] = j.value;
}
}
}
Common::String ConfigFile::readSetting(const Common::String &section, const Common::String &key, const Common::String &defaultValue) const {
Common::HashMap<Common::String, Common::HashMap<Common::String, Common::String> >::const_iterator sectionIt;
sectionIt = _dataSet.find(section);
if (sectionIt != _dataSet.end()) {
Common::HashMap<Common::String, Common::String>::const_iterator keyIt = sectionIt->_value.find(key);
if (keyIt != sectionIt->_value.end()) {
return keyIt->_value;
}
}
return defaultValue;
}
int32 ConfigFile::readIntSetting(const Common::String &section, const Common::String &key, int32 defaultValue) const {
return atoi(readSetting(section, key, Common::String().format("%d", defaultValue)).c_str());
}
} // End of namespace ICB

49
engines/icb/configfile.h Normal file
View File

@@ -0,0 +1,49 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_CONFIGFILE_H
#define ICB_CONFIGFILE_H
#include "common/str.h"
#include "common/hash-str.h"
namespace ICB {
class ConfigFile {
Common::HashMap<Common::String, Common::HashMap<Common::String, Common::String> > _dataSet;
public:
ConfigFile();
void writeSetting(const Common::String &section, const Common::String &key, const Common::String &value) {}
Common::String readSetting(const Common::String &section, const Common::String &key, const Common::String &defaultValue) const;
int32 readIntSetting(const Common::String &section, const Common::String &key, int32 defaultValue) const;
void readFile(const char *filename);
};
} // End of namespace ICB
#endif

View File

@@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
add_engine icb "In Cold Blood" no "" "" "16bit highres bink"

View File

@@ -0,0 +1,44 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/p4.h"
namespace ICB {
// version & owner details
// So version string is 18 bytes long :
// Version String = <8 byte header,5 character version, \0, INT32 time>
#define HEAD_LEN 8
uint8 version_string[HEAD_LEN + 10] = {1, 255, 37, 22, 45, 128, 34, 67};
uint8 unencoded_name[HEAD_LEN + 48] = {9, 11, 73, 18, 120, 209, 211, 237, 'R', 'e', 'v', 'o', 'l', 'u', 't', 'i',
'o', 'n', ' ', 'S', 'o', 'f', 't', 'w', 'a', 'r', 'e', ' ', 'L', 't', 'd', 0};
uint8 encoded_name[HEAD_LEN + 48] = {24, 52, 90, 122, 223, 165, 33, 199, 179, 209, 225, 157, 222, 238, 219, 209, 143, 224, 133, 190, 232, 209, 162, 177, 198, 228, 202, 146,
180, 232, 214, 65, 65, 65, 116, 104, 116, 114, 107, 104, 32, 49, 64, 35, 123, 125, 61, 45, 41, 40, 163, 36, 49, 123, 125, 10};
} // End of namespace ICB

5
engines/icb/credits.pl Normal file
View File

@@ -0,0 +1,5 @@
begin_section("ICB");
add_person("Pawe&#322; Ko&#322;odziejski", "aquadran", "");
add_person("Joost Peters", "joostp", "");
add_person("Einar Johan T. S&oslash;m&aring;en", "somaen", "");
end_section();

View File

@@ -0,0 +1,441 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/session.h"
#include "engines/icb/mission.h"
#include "engines/icb/p4.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/custom_logics.h"
#include "engines/icb/common/px_scriptengine.h"
#include "engines/icb/common/px_linkeddatafile.h"
#include "engines/icb/common/px_prop_anims.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/sound.h"
namespace ICB {
mcodeFunctionReturnCodes fn_set_custom_simple_animator(int32 &result, int32 *params) { return (MS->fn_set_custom_simple_animator(result, params)); }
mcodeFunctionReturnCodes fn_set_custom_button_operated_door(int32 &result, int32 *params) { return (MS->fn_set_custom_button_operated_door(result, params)); }
mcodeFunctionReturnCodes fn_set_custom_auto_door(int32 &result, int32 *params) { return (MS->fn_set_custom_auto_door(result, params)); }
mcodeFunctionReturnCodes fn_set_cad_lock_status(int32 &result, int32 *params) { return (MS->fn_set_cad_lock_status(result, params)); }
mcodeFunctionReturnCodes fn_get_cad_state_flag(int32 &result, int32 *params) { return (MS->fn_get_cad_state_flag(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_set_custom_simple_animator(int32 &, int32 *) {
// chnage the object to be a special simple animator type where all scripts are circumvented
// we need to check here, first, for legality - i.e. we clear the way for run-time assumptions to be made
_animating_prop *index;
_animation_entry *anim;
// find entry for this object via its name
index = (_animating_prop *)LinkedDataObject::Try_fetch_item_by_name(prop_anims, CGameObject::GetName(object));
// get anim
anim = (_animation_entry *)(((char *)index) + index->anims[0]);
// check for no frame
if (!anim->num_frames) {
Tdebug("objects_that_died.txt", "fn_set_custom_simple_animator [%s] loop anim has 0 frames", CGameObject::GetName(object));
Shut_down_object("by fn_set_custom_simple_animator");
return (IR_STOP);
}
// start at frame 0
L->anim_pc = 0;
L->big_mode = __CUSTOM_SIMPLE_ANIMATE;
SA_INDEX = LinkedDataObject::Fetch_item_number_by_name(prop_anims, CGameObject::GetName(object));
// object will pause when off screen
L->hold_mode = prop_camera_hold;
Tdebug("logic_modes.txt", "fn_set_custom_simple_animator switching [%s]", CGameObject::GetName(object));
return (IR_CONT);
}
void _game_session::Custom_simple_animator() {
// this special _big_mode logic replaces the logic script of a lib_simple_animator object
// this is a rationalisation designed to aid speed up on psx
_animating_prop *index;
_animation_entry *anim;
// get index for object
index = (_animating_prop *)LinkedDataObject::Fetch_item_by_number(prop_anims, SA_INDEX);
// now then, lets make the assumption that anim 0 will be the 'looping' one
anim = (_animation_entry *)(((char *)index) + index->anims[0]);
if ((uint8)L->anim_pc == (anim->num_frames - 1))
L->anim_pc = 0;
else
L->anim_pc++; // advance current pc
// set frame
prop_state_table[cur_id] = anim->frames[L->anim_pc];
}
mcodeFunctionReturnCodes _game_session::fn_set_custom_button_operated_door(int32 &, int32 *params) {
// set to special custom door logic
// params 0 initial state value
// prime
BOD_STATE = params[0];
// starts non animating
BOD_CONTROL = 0; // not opening or closing
// switch out of script mode
L->big_mode = __CUSTOM_BUTTON_OPERATED_DOOR;
BOD_INDEX = LinkedDataObject::Fetch_item_number_by_name(prop_anims, CGameObject::GetName(object));
BOD_OPEN_NO = Validate_prop_anim("opening");
BOD_CLOSE_NO = Validate_prop_anim("closing");
Tdebug("logic_modes.txt", "fn_set_custom_button_operated_door switching [%s]", CGameObject::GetName(object));
// Set a symbol type so the Remora knows what to draw.
L->object_type = __BUTTON_OPERATED_DOOR;
// push the y up for Cord to look at
L->prop_xyz.y += 179;
return IR_CONT;
}
void _game_session::Custom_button_operated_door() {
// this special _big_mode logic replaces the logic script of a lib_simple_animator object
// this is a rationalisation designed to aid speed up on psx
_animating_prop *index;
_animation_entry *anim;
uint32 var_num;
int32 params, result;
do { // do while because when we switch in to new anim we need to do an anim
if (BOD_CONTROL == BOD_WAITING) {
// we've opened, now we wait until no one in the list is near to us
if (!BOD_WAIT_COUNT) {
params = 300;
fn_near_list(result, &params);
if (result == TRUE8) {
BOD_WAIT_COUNT = 36; // count again
return;
}
// else, close
L->anim_pc = 0;
BOD_CONTROL = BOD_CLOSING;
BOD_STATE = 1; // closed
// set state flag to 1
var_num = CGameObject::GetVariable(object, "state");
CGameObject::SetIntegerVariable(object, var_num, 1);
} else {
BOD_WAIT_COUNT--;
return;
}
}
if (BOD_CONTROL == BOD_OPENING) {
// get index for object
index = (_animating_prop *)LinkedDataObject::Fetch_item_by_number(prop_anims, BOD_INDEX);
anim = (_animation_entry *)(((char *)index) + index->anims[BOD_OPEN_NO]);
prop_state_table[cur_id] = anim->frames[L->anim_pc];
if ((uint8)L->anim_pc == (anim->num_frames - 1)) {
BOD_CONTROL = BOD_WAITING; // just opened - set to wait for list of people to not be here
BOD_WAIT_COUNT = 36;
BOD_STATE = 0; // open
// set state flag to 0
var_num = CGameObject::GetVariable(object, "state");
CGameObject::SetIntegerVariable(object, var_num, 0);
} else
L->anim_pc++; // frame on
return;
} else if (BOD_CONTROL == BOD_CLOSING) {
// get index for object
index = (_animating_prop *)LinkedDataObject::Try_fetch_item_by_name(prop_anims, CGameObject::GetName(object));
anim = (_animation_entry *)(((char *)index) + index->anims[BOD_CLOSE_NO]);
// set frame
prop_state_table[cur_id] = anim->frames[L->anim_pc];
if ((uint8)L->anim_pc == (anim->num_frames - 1))
BOD_CONTROL = 0; // cancel mode
else
L->anim_pc++; // frame on
return;
}
// ok, we're not animating so just check state
// what state are we in?
if (!BOD_STATE) { // open
// ok, check to see if opened
// get state variable number
var_num = CGameObject::GetVariable(object, "state");
// get value
if (!CGameObject::GetIntegerVariable(object, var_num)) {
BOD_CONTROL = BOD_WAITING; // just opened - set to wait for list of people to not be here
BOD_WAIT_COUNT = 36;
return; // zero so still open
}
L->anim_pc = 0;
BOD_CONTROL = BOD_CLOSING;
BOD_STATE = 1; // closed
// close sound
if (logic_structs[cur_id]->sfxVars[CLOSE_SFX_VAR] != 0)
RegisterSound(cur_id, nullptr, logic_structs[cur_id]->sfxVars[CLOSE_SFX_VAR], closeDesc,
(int8)127); // have to use full version so we can give hash instead of string
else
RegisterSound(cur_id, defaultCloseSfx, closeDesc); // use small version as we have string not hash
} else { // closed
// check for
// a. someone pressing button
// b. chi off screen being near
bool8 open = FALSE8;
if (is_there_a_chi) {
// if chi is on a different floor from player then assume she is following and so auto open the door for her
// - sneaky
if (logic_structs[chi_id]->owner_floor_rect != logic_structs[player.Fetch_player_id()]->owner_floor_rect) {
PXreal sub1, sub2;
sub1 = logic_structs[chi_id]->mega->actor_xyz.x - L->prop_xyz.x;
sub2 = logic_structs[chi_id]->mega->actor_xyz.z - L->prop_xyz.z;
// dist
if (((sub1 * sub1) + (sub2 * sub2)) < (200 * 200)) {
open = TRUE8;
}
}
}
// get state variable number
var_num = CGameObject::GetVariable(object, "state");
// get value
if (!CGameObject::GetIntegerVariable(object, var_num)) {
open = TRUE8; // now 0 so start opening
}
if (open) {
L->anim_pc = 0;
BOD_CONTROL = BOD_OPENING;
BOD_STATE = 0; // open
// open sound
if (logic_structs[cur_id]->sfxVars[OPEN_SFX_VAR] != 0)
RegisterSound(cur_id, nullptr, logic_structs[cur_id]->sfxVars[OPEN_SFX_VAR], openDesc,
(int8)127); // have to use full version so we can give hash instead of string
else
RegisterSound(cur_id, defaultOpenSfx, openDesc); // use small version as we have string not hash
} else { // still closed - see if we can go to sleep
if (!L->prop_on_this_screen) {
// closed and no on screen
L->camera_held = TRUE8; // not on screen
L->cycle_time = 0; // accurate for displays
}
return;
}
}
} while (1);
}
mcodeFunctionReturnCodes _game_session::fn_set_custom_auto_door(int32 &, int32 *params) {
// set to special custom door logic
// params 0 initial state value
// params 1 dist for detection
// params 2 locked or not
CAD_STATE = params[0];
CAD_DIST = params[1];
CAD_LOCKED = params[2]; // starts not locked
L->list[9] = params[1];
// switch out of script mode
L->big_mode = __CUSTOM_AUTO_DOOR;
// anim presets
CAD_INDEX = LinkedDataObject::Fetch_item_number_by_name(prop_anims, CGameObject::GetName(object));
CAD_OPEN_NO = Validate_prop_anim("opening");
CAD_CLOSE_NO = Validate_prop_anim("closing");
Tdebug("logic_modes.txt", "fn_set_custom_auto_door switching [%s]", CGameObject::GetName(object));
// Set a symbol type so the Remora knows what to draw.
L->object_type = __AUTO_DOOR;
return (IR_CONT);
}
void _game_session::Custom_auto_door() {
// this special _big_mode logic replaces the logic script of a lib_auto_slide_door object
// this is a rationalisation designed to aid speed up on psx
_animating_prop *index;
_animation_entry *anim;
uint32 j, id;
bool8 sensed = FALSE8;
L->list[8] = 0;
// check if someone is here or not
j = 0;
while ((j < number_of_voxel_ids) && (!sensed)) { // object 0 is used
id = voxel_id_list[j++];
if ((!logic_structs[id]->mega->dead) && (logic_structs[id]->ob_status != OB_STATUS_HELD)) { // still alive
if (PXfabs(L->prop_xyz.y - logic_structs[id]->mega->actor_xyz.y) < (200 * REAL_ONE)) { // slack for height calc
if ((PXfabs(L->prop_xyz.x - logic_structs[id]->mega->actor_xyz.x) < (PXreal)CAD_DIST) &&
(PXfabs(L->prop_xyz.z - logic_structs[id]->mega->actor_xyz.z) < (PXreal)CAD_DIST)) {
// yes
sensed = TRUE8;
L->list[8]++;
}
}
}
}
if (CAD_STATE == CAD_OPENING) { // doors opening
// get index for object
index = (_animating_prop *)LinkedDataObject::Fetch_item_by_number(prop_anims, CAD_INDEX);
anim = (_animation_entry *)(((char *)index) + index->anims[CAD_OPEN_NO]);
prop_state_table[cur_id] = anim->frames[L->anim_pc];
if ((uint8)L->anim_pc == (anim->num_frames - 1)) {
CAD_STATE = CAD_OPEN; // cancel mode
CAD_WAIT = CAD_TIMER; // when we sense somewhat we reset the timer
} else
L->anim_pc++; // frame on
return;
} else if (CAD_STATE == CAD_OPEN) {
if ((!CAD_LOCKED) && (!sensed)) { // no one here anymore so switch modes
if (CAD_WAIT) { // now wait for time up
CAD_WAIT--; // 1 less
return;
}
CAD_STATE = CAD_CLOSING;
// close sound
if (logic_structs[cur_id]->sfxVars[CLOSE_SFX_VAR] != 0)
RegisterSound(cur_id, nullptr, logic_structs[cur_id]->sfxVars[CLOSE_SFX_VAR], closeDesc,
(int8)127); // have to use full version so we can give hash instead of string
else
RegisterSound(cur_id, defaultCloseSfx, closeDesc); // use small version as we have string not hash
}
CAD_WAIT = CAD_TIMER; // when we sense somewhat we reset the timer
return;
} else if (CAD_STATE == CAD_CLOSING) { // doors closing
if (sensed) { // sensed someone so switch modes
CAD_STATE = CAD_OPENING;
return;
}
// get index for object
index = (_animating_prop *)LinkedDataObject::Fetch_item_by_number(prop_anims, CAD_INDEX);
// when closing we reverse the opening anim - until the done when we set to last frame of closing
anim = (_animation_entry *)(((char *)index) + index->anims[CAD_OPEN_NO]);
prop_state_table[cur_id] = anim->frames[L->anim_pc];
if (!L->anim_pc) {
CAD_STATE = CAD_CLOSED; // cancel mode
anim = (_animation_entry *)(((char *)index) + index->anims[CAD_CLOSE_NO]);
prop_state_table[cur_id] = anim->frames[anim->num_frames - 1];
} else
L->anim_pc--; // frame on
return;
} else if (CAD_STATE == CAD_CLOSED) {
if ((!CAD_LOCKED) && (sensed)) { // sensed someone so switch modes
CAD_STATE = CAD_OPENING;
L->anim_pc = 0;
// open sound
if (logic_structs[cur_id]->sfxVars[OPEN_SFX_VAR] != 0)
RegisterSound(cur_id, nullptr, logic_structs[cur_id]->sfxVars[OPEN_SFX_VAR], openDesc,
(int8)127); // have to use full version so we can give hash instead of string
else
RegisterSound(cur_id, defaultOpenSfx, openDesc); // use small version as we have string not hash
}
if (!L->prop_on_this_screen) {
// closed and no on screen
L->camera_held = TRUE8; // not on screen
L->cycle_time = 0; // accurate for displays
}
return;
}
}
mcodeFunctionReturnCodes _game_session::fn_set_cad_lock_status(int32 &, int32 *params) {
// set the locked status of an auto slide door
// only the object should call this
// params 0 0 name of door
// params 0 0 or non zero
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
uint32 id;
id = (uint32)LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
logic_structs[id]->list[5] = params[1];
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_get_cad_state_flag(int32 &result, int32 *params) {
// return custom auto door state to button
// params 0 name of door
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
uint32 id;
id = (uint32)LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
if (logic_structs[id]->EXT_CAD_STATE == CAD_OPEN)
result = 1;
else
result = 0;
return IR_CONT;
}
} // End of namespace ICB

View File

@@ -0,0 +1,63 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
namespace ICB {
#define SA_INDEX L->list[0]
#define BOD_OPENING 1
#define BOD_CLOSING 2
#define BOD_WAITING 3
#define BOD_WAIT_COUNT L->list[4]
#define BOD_STATE L->list[5]
#define BOD_STATE_INDEX 5
#define BOD_CONTROL L->list[6]
// animation index
#define BOD_INDEX L->list[7]
#define BOD_OPEN_NO L->list[8]
#define BOD_CLOSE_NO L->list[9]
#define CAD_OPEN 0
#define CAD_CLOSED 1
#define CAD_OPENING 2
#define CAD_CLOSING 3
#define EXT_CAD_STATE list[0]
#define CAD_STATE L->list[0]
#define CAD_STATE_INDEX 0
#define CAD_DIST L->list[1]
// animation index
#define CAD_INDEX L->list[2]
#define CAD_OPEN_NO L->list[3]
#define CAD_CLOSE_NO L->list[4]
#define CAD_LOCKED L->list[5]
#define CAD_WAIT L->list[6]
#define CAD_TIMER 48
} // End of namespace ICB

220
engines/icb/debug.cpp Normal file
View File

@@ -0,0 +1,220 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/p4.h"
#include "engines/icb/p4_generic.h"
#include "engines/icb/direct_input.h"
#include "engines/icb/keyboard.h"
#include "engines/icb/debug.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/session.h"
#include "engines/icb/p4_generic.h"
#include "engines/icb/mouse.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_string.h"
#include "engines/icb/common/px_array.h"
#include "engines/icb/text.h"
namespace ICB {
#define LIGHT_RECT_WIDTH (16)
#define LIGHT_RECT_HEIGHT (16)
#define LIGHT_TIE_WIDTH (10)
#define LIGHT_TIE_HEIGHT (10)
// Pink
#define LIGHT_TIE_PEN (0xFF7080)
// 2m below the light source
#define LIGHT_TIE_Y_OFFSET (-200)
// PSX specifics are in "debug_psx.cpp"
// PC specifics are in "debug_pc.cpp"
// zdebug logging on or off
bool8 terminate_debugging = FALSE8;
// This flag indicates whether or not the debug simulated feature is activated or not.
bool8 debug_auto_save = FALSE8;
void _game_session::Show_lit_unlit_diagnostics() {
uint32 j;
uint32 pitch; // backbuffer pitch
uint8 *ad;
_rgb pen = {// rgb
255, 0, 0, 0};
// cross hair is now a development option
if (g_px->cross_hair == FALSE8)
return;
ad = surface_manager->Lock_surface(working_buffer_id);
pitch = surface_manager->Get_pitch(working_buffer_id);
// setup camera
PXcamera &camera = GetCamera();
// set up nico world coords
PXvector pos;
for (j = 0; j < number_of_voxel_ids; j++) {
pos.x = logic_structs[voxel_id_list[j]]->mega->actor_xyz.x;
pos.y = logic_structs[voxel_id_list[j]]->mega->actor_xyz.y;
pos.z = logic_structs[voxel_id_list[j]]->mega->actor_xyz.z;
// screen pos
PXvector filmpos;
// yesno
bool8 result = FALSE8;
// compute screen coord
PXWorldToFilm(pos, camera, result, filmpos);
// print name if on screen
if (result) {
if (!logic_structs[voxel_id_list[j]]->mega->in_shade)
Clip_text_print(&pen, (int32)(filmpos.x + (SCREEN_WIDTH / 2)), (int32)((SCREEN_DEPTH / 2) - filmpos.y), ad, pitch, ">");
}
}
// Unlock to use Fill_rect !
surface_manager->Unlock_surface(working_buffer_id);
_rgb tiecolour = {0xFF, 0x70, 0x80, 0};
_rgb dcolour = {0x00, 0x00, 0xFF, 0};
_rgb tcol = {0xFF, 0xFF, 0xFF, 0};
_rgb lcol = {0xFF, 0x70, 0x80, 0};
// Draw the lights at their screen positions and with their base colours
if (SetOK()) {
rlp_API *lights = set.GetPRig();
if (lights != nullptr) {
for (j = 0; j < lights->nLamps; j++) {
PSXLamp *pLamp = (PSXLamp *)lights->GetLamp(j);
uint32 state = pLamp->nStates - 1;
if (state > 0) {
state = Fetch_prop_state(pLamp->prop_name);
}
// Really shoud write a PSXLamp::GetState( uint32 n ) !
PSXLampState *plampstate = pLamp->states + state;
int32 r = plampstate->c.r;
int32 g = plampstate->c.g;
int32 b = plampstate->c.b;
int32 m = plampstate->m;
r = (r * m) >> 7; // m has 1.0 = 128
g = (g * m) >> 7; // m has 1.0 = 128
b = (b * m) >> 7; // m has 1.0 = 128
// Convert from 0-4096 -> 0-256
r >>= 4;
g >>= 4;
b >>= 4;
// Clamp the colours
if (r > 255)
r = 255;
if (g > 255)
g = 255;
if (b > 255)
b = 255;
pos.x = (PXfloat)plampstate->pos.vx;
pos.y = (PXfloat)plampstate->pos.vy;
pos.z = (PXfloat)plampstate->pos.vz;
// screen pos
PXvector lightpos, tiepos;
// yesno
bool8 result = FALSE8;
// compute screen coord
PXWorldToFilm(pos, camera, result, lightpos);
// draw rectangle of the correct colour
int32 x0 = (int32)(lightpos.x + (SCREEN_WIDTH / 2));
int32 y0 = (int32)(SCREEN_DEPTH / 2 - lightpos.y);
uint32 penrgb = (r << 16) | (g << 8) | (b << 0);
Fill_rect(x0 - LIGHT_RECT_WIDTH / 2, y0 - LIGHT_RECT_HEIGHT / 2, x0 + LIGHT_RECT_WIDTH / 2, y0 + LIGHT_RECT_HEIGHT / 2, penrgb, (int32)-lightpos.z);
// Draw a 'shadow' away from light ! - to try and guess z-distance
pos.y += LIGHT_TIE_Y_OFFSET;
PXWorldToFilm(pos, camera, result, tiepos);
int32 x1 = (int32)(tiepos.x + (SCREEN_WIDTH / 2));
int32 y1 = (int32)(SCREEN_DEPTH / 2 - tiepos.y);
penrgb = LIGHT_TIE_PEN;
Fill_rect(x1 - LIGHT_TIE_WIDTH / 2, y1 - LIGHT_TIE_HEIGHT / 2, x1 + LIGHT_TIE_WIDTH / 2, y1 + LIGHT_TIE_HEIGHT / 2, penrgb, (int32)-tiepos.z);
// Lock to use General_draw_line !
ad = surface_manager->Lock_surface(working_buffer_id);
// Draw a pink line from light to its tie !
General_draw_line_24_32((int16)x0, (int16)y0, (int16)x1, (int16)y1, &tiecolour, ad, pitch);
// Print the name of the light at the light pos and the tie pos
Clip_text_print(&tcol, x0, y0, ad, pitch, "%s", pLamp->lamp_name);
Clip_text_print(&tcol, x1, y1, ad, pitch, "%s", pLamp->lamp_name);
// Draw a line to show the light direction
if ((pLamp->type == DIRECT_LIGHT) || (pLamp->type == SPOT_LIGHT)) {
// plampstate direciton is normalised to be 4096 int32
// Take that down to 128cm int32 (>>5)
int32 dx = plampstate->vx >> 5;
int32 dy = plampstate->vy >> 5;
int32 dz = plampstate->vz >> 5;
// Remove the tie position offset
pos.y -= LIGHT_TIE_Y_OFFSET;
pos.x += dx;
pos.y += dy;
pos.z += dz;
PXWorldToFilm(pos, camera, result, tiepos);
// Draw a line to show the direction of the light
x1 = (int32)(tiepos.x + (SCREEN_WIDTH / 2));
y1 = (int32)(SCREEN_DEPTH / 2 - tiepos.y);
General_draw_line_24_32((int16)x0, (int16)y0, (int16)x1, (int16)y1, &dcolour, ad, pitch);
}
// Unlock to use Fill_rect !
surface_manager->Unlock_surface(working_buffer_id);
}
// Lock to use Clip_text_print !
ad = surface_manager->Lock_surface(working_buffer_id);
Clip_text_print(&lcol, 0, 12, ad, pitch, "%d Lamps", lights->nLamps);
// Unlock to use Fill_rect !
surface_manager->Unlock_surface(working_buffer_id);
}
}
}
} // End of namespace ICB

57
engines/icb/debug.h Normal file
View File

@@ -0,0 +1,57 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_D_DEBUG
#define ICB_D_DEBUG
#include "engines/icb/p4_generic.h"
#include "engines/icb/common/px_string.h"
#include "engines/icb/common/px_array.h"
#include "engines/icb/debug_pc.h"
namespace ICB {
extern bool8 terminate_debugging;
// This flag indicates whether or not the debug simulated feature is activated or not.
extern bool8 debug_auto_save;
// And this controls how frequently the autosave gets done.
#define DEBUG_AUTO_SAVE_SKIP_CYCLES 10
#define EXCEPTION_LOG "exception_log.txt"
#define PXTRY
#define PXCATCH if (0) {
#define PXENDCATCH }
// headup switch stub mode
void Headup_debug_switcher();
void Reset_headup_switcher();
} // End of namespace ICB
#endif // #ifndef D_DEBUG

67
engines/icb/debug_pc.cpp Normal file
View File

@@ -0,0 +1,67 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/p4_generic.h"
#include "engines/icb/direct_input.h"
#include "engines/icb/keyboard.h"
#include "engines/icb/debug.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/session.h"
#include "engines/icb/p4_generic.h"
#include "engines/icb/mouse.h"
#include "engines/icb/p4.h"
#include "common/textconsole.h"
namespace ICB {
bool8 zdebug = false;
// For the overloads of new & delete
extern uint32 newMemAlloc;
extern uint32 newMemUsed;
extern uint32 newNptrs;
void Fatal_error(const char *format...) {
char buf[256];
va_list args;
va_start(args, format);
vsnprintf(buf, 256, const_cast<char *>(format), args);
error("%s", buf);
}
void Message_box(const char *, ...) { ; }
void Zdebug(const char *, ...) { ; }
void Zdebug(uint32, const char *, ...) { ; }
void Tdebug(const char *, const char *, ...) { ; }
void Whap_test() { ; }
void Display_prop_stats() { ; }
void Headup_debug_switcher() { ; }
void Reset_headup_switcher() { ; }
void _game_session::Display_mega_times() { ; }
} // End of namespace ICB

65
engines/icb/debug_pc.h Normal file
View File

@@ -0,0 +1,65 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_DEBUG_PC_H
#define ICB_DEBUG_PC_H
#include "common/system.h"
namespace ICB {
extern bool8 zdebug;
void NORETURN_PRE Fatal_error(const char *format, ...) NORETURN_POST;
void Message_box(const char *text, ...);
void ExitWithReport(char *format, ...);
void Zdebug(const char *, ...);
void Zdebug(uint32 stream, const char *format, ...);
void Tdebug(const char *file, const char *format, ...);
#define Real_Fatal_error Fatal_error
#define Real_Message_box Message_box
// XXX: FIXME: This function stores the number of elapsed microseconds in an unsigned 32-bit int, which will overflow in just over an
// hour...
// We should make sure all the client code deals with this properly!
inline uint32 GetMicroTimer(void) {
static int32 first = 1;
static TimeDate startTime;
if (first) {
g_system->getTimeAndDate(startTime);
first = 0;
}
TimeDate curTime;
g_system->getTimeAndDate(curTime);
return (uint32)(((curTime.tm_sec - startTime.tm_sec) * 1000000));// + (curTime.tv_usec - startTime.tv_usec)); // TODO: Fix micro-second-precision.
}
} // End of namespace ICB
#endif // #ifndef DEBUG_PC_H

356
engines/icb/detection.cpp Normal file
View File

@@ -0,0 +1,356 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/advancedDetector.h"
#include "engines/icb/detection.h"
namespace ICB {
static const PlainGameDescriptor icbGames[] = {
{ "icb", "In Cold Blood" },
{ "eldorado", "The Road to El Dorado" },
{ nullptr, nullptr }
};
static const IcbGameDescription gameDescriptions[] = {
{
{
// In Cold Blood
// English GOG Version
"icb",
"GOG.com",
AD_ENTRY2s("g/speech.clu", "ced60009bdffa9a1055863bf10d2e79e", 7683040, "g/g", "ebe9e5377ee9d231e7a7e33666eb517b", 63892),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ICB
},
{
{
// In Cold Blood
// English 3 CD version
"icb",
"",
AD_ENTRY2s("g/speech.clu", "ced60009bdffa9a1055863bf10d2e79e", 7683040, "g/g", "af8281173d34b64088e173d791d1c27f", 63000),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ICB
},
{
{
// In Cold Blood
// Spanish (Revolution 25th Anniversary Collection)
"icb",
"",
AD_ENTRY2s("g/speech.clu", "84444660e4fd6104c88bc13b9db74b98", 7432352, "g/g", "3ee009f3319ec3148fb2861043794235", 67356),
Common::ES_ESP,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ICB
},
{
{
// In Cold Blood (De Sang Froid)
// French 3 CD version
"icb",
"",
AD_ENTRY2s("g/speech.clu", "5dfeb58bd1974e8a36d532c7c0002a49", 7872320, "g/g", "167c680f29d3ac160fd2e9f4a2591bf7", 67060),
Common::FR_FRA,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ICB
},
{
{
// In Cold Blood
// German GOG version
"icb",
"",
AD_ENTRY2s("g/speech.clu", "c880a89fe4a46b5c068acc06cf1dbf2b", 8785336, "g/g", "4ef623595db724fa33a127227b31acec", 65828),
Common::DE_DEU,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ICB
},
{
{
// In Cold Blood
// English Demo
"icb",
"Demo",
AD_ENTRY2s("g/speech.clu", "ced60009bdffa9a1055863bf10d2e79e", 7683040, "g/g", "f8e1a762cc25554846f6e45d59f55159", 54560),
Common::EN_GRB,
Common::kPlatformWindows,
ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ICB
},
{
{
// In Cold Blood
// English Demo
"icb",
"Demo",
AD_ENTRY2s("g/speech.clu", "ced60009bdffa9a1055863bf10d2e79e", 7683040, "g/g", "2b9a8ca8d7a1bd91701708535b171aa8", 62080),
Common::EN_USA,
Common::kPlatformWindows,
ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ICB
},
{
{
// In Cold Blood
// English PS1 Demo from Official UK PlayStation Magazine CD Disk 64 (SCED-02638)
"icb",
"Demo",
AD_ENTRY2s("g/speech.clu", "4e58eafc80b734ad177bdb7e2b2a3794", 735688, "g/havenota.clu", "87bacf73f340c879484fbcff93e4fd74", 44432),
Common::EN_GRB,
Common::kPlatformPSX,
ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ICB
},
{
{
// The Road to El Dorado
// English
"eldorado",
"",
AD_ENTRY2s("g/speech.clu", "65acb862dcdef2a7a69b961760bd565e", 1927072, "g/g", "ed36c6fb807a3ececba1bbda94172842", 17704),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// Spanish
"eldorado",
"",
AD_ENTRY2s("g/speech.clu", "81a0aedb57e78b22d1f434c2f3e09b08", 1948952, "g/g", "a3a396cce6e30040bd16f6dbdd724d49", 19560),
Common::ES_ESP,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// Italian
"eldorado",
"",
AD_ENTRY2s("g/speech.clu", "1220c9bef92e30a5faa033a15cb6788d", 1609464, "g/g", "52fbb4ab3247360d005e5c04a60d7196", 18920),
Common::IT_ITA,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// Polish
"eldorado",
"",
AD_ENTRY2s("g/speech.clu", "b063eee3ae6e327c37149a8342700004", 2009640, "g/g", "1427ecf118fc37da4ebb2f29d16d3d9b", 18520),
Common::PL_POL,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// Brazilian Portuguese
"eldorado",
"",
AD_ENTRY2s("g/speech.clu", "f69efab57478cd9b1792880298eada8d", 1927072, "g/g", "ed4e6fed9c3c5b2cbccec30484eef434", 19280),
Common::PT_BRA,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// English demo from CyberMycha 02/2001
"eldorado",
"Demo",
AD_ENTRY2s("g/speech.clu", "93905d81f6e11f8c1b9c6a1dcd303e68", 1970016, "g/g", "7e8aabc6fe481317de92fd18bdf328df", 17040),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// English US PS1
"eldorado",
0,
AD_ENTRY2s("g/speech.clu", "641adcc7b812dcd99a09e78bce22f2ce", 349480, "g/havenota.clu", "0a51dd4f3f49e8d0b209ea410ed42853", 17064),
Common::EN_USA,
Common::kPlatformPSX,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// English EU PS1
"eldorado",
0,
AD_ENTRY2s("g/speech.clu", "641adcc7b812dcd99a09e78bce22f2ce", 349480, "g/havenota.clu", "7276ce48dcb2ff87181292f9c6889f19", 17064),
Common::EN_GRB,
Common::kPlatformPSX,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// German PS1
"eldorado",
0,
AD_ENTRY2s("g/speech.clu", "4314272e910bfc72aa9224c179ea90ba", 328600, "g/havenota.clu", "0fb92797c62e1f5fd35a08292c681cd1", 18176),
Common::DE_DEU,
Common::kPlatformPSX,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// French PS1
"eldorado",
0,
AD_ENTRY2s("g/speech.clu", "2c0095ac493d847a60a9c395282bfe9b", 287032, "g/havenota.clu", "195c71302b79b3be2b60e11a2b49bae0", 18032),
Common::FR_FRA,
Common::kPlatformPSX,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// Spanish PS1
"eldorado",
0,
AD_ENTRY2s("g/speech.clu", "3862579927ef45bd603a6e19ee1bbaff", 353656, "g/havenota.clu", "c053da010d3aeb3d242f7f7d6f222669", 18112),
Common::ES_ESP,
Common::kPlatformPSX,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{
{
// The Road to El Dorado
// Italian PS1
"eldorado",
0,
AD_ENTRY2s("g/speech.clu", "c28ccf1def3fbf6de597f900b9c8d4e4", 288984, "g/havenota.clu", "fec13ff938c9f7ed054124b0bba10528", 17944),
Common::IT_ITA,
Common::kPlatformPSX,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_ELDORADO
},
{ AD_TABLE_END_MARKER, GType_ICB }
};
class IcbMetaEngineDetection : public AdvancedMetaEngineDetection<IcbGameDescription> {
public:
IcbMetaEngineDetection() : AdvancedMetaEngineDetection(gameDescriptions, icbGames) {
_guiOptions = GUIO_NOMIDI;
_flags = kADFlagMatchFullPaths;
}
const char *getEngineName() const override { return "In Cold Blood Engine"; }
const char *getName() const override {
return "icb";
}
const char *getOriginalCopyright() const override { return "(C) 2000 Revolution Software Ltd"; }
};
} // End of namespace ICB
REGISTER_PLUGIN_STATIC(ICB_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, ICB::IcbMetaEngineDetection);

43
engines/icb/detection.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_DETECTION_H
#define ICB_DETECTION_H
#include "engines/advancedDetector.h"
namespace ICB {
enum IcbGameType {
GType_ICB,
GType_ELDORADO
};
struct IcbGameDescription {
AD_GAME_DESCRIPTION_HELPERS(desc);
ADGameDescription desc;
IcbGameType gameType;
};
} // End of namespace ICB
#endif // ICB_DETECTION_H

View 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/p4_generic.h"
#include "engines/icb/debug.h"
#include "engines/icb/p4.h"
#include "engines/icb/player.h"
#include "engines/icb/direct_input.h"
#include "engines/icb/cluster_manager_pc.h"
#include "common/textconsole.h"
#include "common/events.h"
#include "common/keyboard.h"
namespace ICB {
bool8 keyboard_buf_scancodes[Common::KEYCODE_LAST];
bool8 repeats_scancodes[Common::KEYCODE_LAST];
void Init_direct_input() {
SetDefaultKeys();
}
void setKeyState(Common::KeyCode key, bool pressed) {
if (key >= Common::KEYCODE_LAST)
return;
keyboard_buf_scancodes[key] = pressed;
}
uint32 Get_DI_key_press() {
for (uint32 i = 0; i < Common::KEYCODE_LAST; i++) {
if (Read_DI_once_keys(i)) {
return i;
}
}
return 0;
}
void Clear_DI_key_buffer() {
for (uint32 i = 0; i < Common::KEYCODE_LAST; i++) {
repeats_scancodes[i] = FALSE8;
keyboard_buf_scancodes[i] = FALSE8;
}
}
bool8 Read_DI_once_keys(uint32 key) {
// in
// key = keycode
// out
// 0 not pressed down currently
// 1 pressed down
if (key >= Common::KEYCODE_LAST)
return FALSE8;
// set repeat
if (keyboard_buf_scancodes[key] && (repeats_scancodes[key]))
return (0); // key is still pressed so return 0
repeats_scancodes[key] = keyboard_buf_scancodes[key];
return (repeats_scancodes[key]);
}
bool8 Read_DI_keys(uint32 key) {
// in
// key = keycode
// out
// 0 not pressed down currently
// 1 pressed down
if (key >= Common::KEYCODE_LAST)
return FALSE8;
// set repeat
repeats_scancodes[key] = keyboard_buf_scancodes[key];
return (repeats_scancodes[key]);
}
bool8 DI_key_waiting() {
for (uint32 i = 0; i < Common::KEYCODE_LAST; i++) {
if (keyboard_buf_scancodes[i])
return TRUE8;
}
return FALSE8;
}
void SetDefaultKeys() {
fire_key = Common::KEYCODE_SPACE;
interact_key = Common::KEYCODE_LCTRL;
inventory_key = Common::KEYCODE_RETURN;
arm_key = Common::KEYCODE_LALT;
remora_key = Common::KEYCODE_r;
crouch_key = Common::KEYCODE_x;
sidestep_key = Common::KEYCODE_LSHIFT;
run_key = Common::KEYCODE_z;
up_key = Common::KEYCODE_UP;
down_key = Common::KEYCODE_DOWN;
left_key = Common::KEYCODE_LEFT;
right_key = Common::KEYCODE_RIGHT;
pause_key = Common::KEYCODE_ESCAPE;
}
} // End of namespace ICB

View File

@@ -0,0 +1,50 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_DINPUTH
#define ICB_DINPUTH
#include "common/keyboard.h"
namespace ICB {
extern bool8 keyboard_buf_scancodes[Common::KEYCODE_LAST];
extern bool8 repeats_scancodes[Common::KEYCODE_LAST];
void Init_direct_input();
void setKeyState(Common::KeyCode key, bool pressed);
bool8 Read_DI_keys(uint32 key);
bool8 Read_DI_once_keys(uint32 key);
bool8 DI_key_waiting();
uint32 Get_DI_key_press();
void Clear_DI_key_buffer();
void SetDefaultKeys();
const char *GetKeyName(uint32 key);
} // End of namespace ICB
#endif

3735
engines/icb/drawpoly_pc.cpp Normal file

File diff suppressed because it is too large Load Diff

98
engines/icb/drawpoly_pc.h Normal file
View File

@@ -0,0 +1,98 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_DRAWPOLY_PC_H
#define ICB_DRAWPOLY_PC_H
#include "engines/icb/gfx/psx_tman.h"
namespace ICB {
extern uint32 selFace;
extern CVECTOR unlitPoly;
extern uint32 _drawBface;
extern uint32 deadObject;
// Draw a cuboid
void drawSolidBboxPC(SVECTOR *scrn, CVECTOR *rgbIn);
// Debug : Flat, Un-Textured, Self-Luminous, triangles
void drawFUS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Debug : Gouraud, Un-Textured, Self-Luminous, triangles
void drawGUS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Debug : Flat, Textured, Self-Luminous Triangles
void drawFTS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Debug : Gouraud, Textured, Self-Luminous Triangles
void drawGTS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Debug : Flat, Un-Textured, Lit, triangles
void drawFUL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal);
// Debug : Gouraud, Un-Textured, Lit, triangles
void drawGUL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal);
// Debug : Flat, Textured, Lit Triangles
void drawFTL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal);
// Debug : Gouraud, Textured, Lit Triangles
void drawGTL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal);
// Debug : Simple Flat, Un-Textured triangles with no colour in them
void drawTRI3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Optimised : Flat, Un-Textured, Self-Luminous, triangles
void fastDrawFUS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Optimised : Gouraud, Un-Textured, Self-Luminous, triangles
void fastDrawGUS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Optimised : Flat, Textured, Self-Luminous Triangles
void fastDrawFTS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Optimised : Gouraud, Textured, Self-Luminous Triangles
void fastDrawGTS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
// Optimised : Flat, Un-Textured, Lit, triangles
void fastDrawFUL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal);
// Optimised : Gouraud, Un-Textured, Lit, triangles
void fastDrawGUL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal);
// Optimised : Flat, Textured, Lit Triangles
void fastDrawFTL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal);
// Optimised : Gouraud, Textured, Lit Triangles
void fastDrawGTL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal);
// Optimised : Simple Flat, Un-Textured triangles with no colour in them
void fastDrawTRI3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex);
} // End of namespace ICB
#endif // #ifndef DRAWPOLY_PC_H

283
engines/icb/event_list.cpp Normal file
View File

@@ -0,0 +1,283 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/event_list.h"
#include "engines/icb/debug.h"
namespace ICB {
// Use globals to save on rdata storage and having repeated strings therein
const char *global_event_deleted_placeholder = "**";
const char *global_event_generic = "generic";
const char *global_event_line_of_sight = "line_of_sight";
const char *global_event_sound = "sound";
const char *global_event_on_camera = "on_camera";
const char *global_event_off_camera = "off_camera";
const char *global_event_logic_rerun = "logic_rerun";
const char *global_event_out_of_sight = "out_of_sight";
const char *global_event_lift_ascend = "lift_ascend";
const char *global_event_lift_descend = "lift_descend";
_event_list::_event_list(const _event_list &oX) {
uint32 i;
m_pcObjectName = oX.m_pcObjectName;
m_nNumNamedEventsPending = oX.m_nNumNamedEventsPending;
m_nNumRegisteredEvents = oX.m_nNumRegisteredEvents;
m_bEventPending = oX.m_bEventPending;
m_nPad1 = 0;
for (i = 0; i < m_nNumRegisteredEvents; ++i)
m_pNamedEventList[i] = oX.m_pNamedEventList[i];
for (i = m_nNumRegisteredEvents; i < EVENT_MAX_EVENTS_REGISTERED; ++i)
m_pNamedEventList[i].s_pcEventName = EVENT_DELETED_PLACEHOLDER;
}
const _event_list &_event_list::operator=(const _event_list &oOpB) {
uint32 i;
m_pcObjectName = oOpB.m_pcObjectName;
m_nNumNamedEventsPending = oOpB.m_nNumNamedEventsPending;
m_nNumRegisteredEvents = oOpB.m_nNumRegisteredEvents;
m_bEventPending = oOpB.m_bEventPending;
for (i = 0; i < m_nNumRegisteredEvents; ++i)
m_pNamedEventList[i] = oOpB.m_pNamedEventList[i];
for (i = m_nNumRegisteredEvents; i < EVENT_MAX_EVENTS_REGISTERED; ++i)
m_pNamedEventList[i].s_pcEventName = EVENT_DELETED_PLACEHOLDER;
return (*this);
}
bool8 _event_list::IsEventInList(const char *pcEventName) const {
uint32 i;
// Look for the event in the list.
i = 0;
while ((i < m_nNumRegisteredEvents) && strcmp(m_pNamedEventList[i].s_pcEventName, pcEventName))
++i;
// See which loop condition failed.
if (i == m_nNumRegisteredEvents)
return (FALSE8);
else
return (TRUE8);
}
void _event_list::AddEventForObject(const char *pcEventName) {
uint32 i;
// Look for a blank slot or the event already being in the list.
i = 0;
while ((i < m_nNumRegisteredEvents) && strcmp(m_pNamedEventList[i].s_pcEventName, EVENT_DELETED_PLACEHOLDER) && strcmp(m_pNamedEventList[i].s_pcEventName, pcEventName))
++i;
// Our index is now pointing at the first placeholder for a removed event or one-past-the-end-of-the-array or at
// the event if it is already in the list. Make sure the pending flag is not set. However, we can't do this if
// the event is already in the list, as there may be events of this type outstanding.
if (i == m_nNumRegisteredEvents) {
// We are increasing the size of the list.
++m_nNumRegisteredEvents;
}
// If the event is already listed, don't overwrite it because we may destroy a pending event.
if (strcmp(m_pNamedEventList[i].s_pcEventName, pcEventName)) {
// Setting up a new event.
// Set_string( pcEventName, m_pNamedEventList[ i ].s_pcEventName, MAXLEN_EVENT_NAME );
m_pNamedEventList[i].s_pcEventName = const_cast<char *>(pcEventName);
m_pNamedEventList[i].s_bPending = FALSE8;
m_pNamedEventList[i].s_nLastSenderID = EVENT_INVALID_SENDER_ID;
}
}
void _event_list::RemoveEventForObject(const char *pcEventName) {
uint32 i;
// Look for the event in the list of named events.
i = 0;
while ((i < m_nNumRegisteredEvents) && strcmp(m_pNamedEventList[i].s_pcEventName, pcEventName))
++i;
// If we didn't get to the end of the array then we found the event OK.
if (i < m_nNumRegisteredEvents) {
// So delete the event.
m_pNamedEventList[i].s_pcEventName = EVENT_DELETED_PLACEHOLDER;
m_pNamedEventList[i].s_nLastSenderID = EVENT_INVALID_SENDER_ID;
// If the event was pending then we must remember to decrement the count of outstanding events
// because the event will no longer be able to be cleared by checking for it.
if (m_pNamedEventList[i].s_bPending) {
m_pNamedEventList[i].s_bPending = FALSE8;
--m_nNumNamedEventsPending;
}
// And return.
return;
}
}
void _event_list::ClearAllOutstandingEvents() {
uint32 i;
// Clear the generic event flag.
m_bEventPending = FALSE8;
// Now clear all the named events.
for (i = 0; i < m_nNumRegisteredEvents; ++i)
m_pNamedEventList[i].s_bPending = FALSE8;
// Object has no outstanding named events.
m_nNumNamedEventsPending = 0;
}
bool8 _event_list::PostNamedEvent(const char *pcEventName, int32 nSenderID) {
uint32 i;
// Look for the event in the list of events this object is interested in.
i = 0;
while ((i < m_nNumRegisteredEvents) && strcmp(m_pNamedEventList[i].s_pcEventName, pcEventName))
++i;
// If we didn't get to the end of the array then we found the event OK.
if (i < m_nNumRegisteredEvents) {
// Only one event of each type can be pending, so if the event is pending already, we are
// not adding a new one.
if (!m_pNamedEventList[i].s_bPending) {
++m_nNumNamedEventsPending;
m_pNamedEventList[i].s_bPending = TRUE8;
}
// Set the ID of the last sender of this event.
m_pNamedEventList[i].s_nLastSenderID = nSenderID;
// Also set the generic flag to trigger a rerun of context logic for the object.
m_bEventPending = TRUE8;
// Tell caller we added a new event.
return (TRUE8);
}
// We're not registering a new event.
return (FALSE8);
}
bool8 _event_list::CheckEventWaiting(const char *pcEventName) {
uint32 i;
// If we're not checking for line-of-sight events but there is one, we must clear it anyway.
if (strcmp(pcEventName, EVENT_LINE_OF_SIGHT) && (m_pNamedEventList[0].s_bPending)) {
m_pNamedEventList[0].s_bPending = FALSE8;
--m_nNumNamedEventsPending;
}
// Quick check: if there are no events pending then the named one can't be pending.
if (m_nNumNamedEventsPending == 0)
return (FALSE8);
// Look through the remaining named event list.
for (i = 0; i < m_nNumRegisteredEvents; ++i) {
if (!strcmp(m_pNamedEventList[i].s_pcEventName, pcEventName) && m_pNamedEventList[i].s_bPending) {
// Clear the pending flag on the named event.
m_pNamedEventList[i].s_bPending = FALSE8;
--m_nNumNamedEventsPending;
// Only clear the generic flag if we have just cleared the last named event. Otherwise, we have to turn
// it back on because HasEventsPending() always clears the flag regardless of whether or not there are
// still any named events pending.
if (m_nNumNamedEventsPending == 0)
m_bEventPending = FALSE8;
else
m_bEventPending = TRUE8;
// Tell caller that the named event was waiting for the object.
return (TRUE8);
}
}
// The object is either not registered for this event or the event is not pending.
return (FALSE8);
}
bool8 _event_list::DidObjectSendLastNamedEvent(uint32 nObjectID, const char *pcEventName) const {
uint32 i;
// Find the event in the list of events the object is registered for.
i = 0;
while ((i < m_nNumRegisteredEvents) && strcmp(m_pNamedEventList[i].s_pcEventName, pcEventName))
++i;
// If we ran off the end of that array, then just return false, but log a warning.
if (i == m_nNumRegisteredEvents) {
Zdebug("_event_list::DidObjectSendLastEvent( %d, %s ) - event not listed for object.", nObjectID, pcEventName);
return (FALSE8);
}
// Check if the object was the last sender of an event.
if ((uint32)m_pNamedEventList[i].s_nLastSenderID == nObjectID)
return (TRUE8);
else
return (FALSE8);
}
int32 _event_list::GetIDOfLastObjectToPostEvent(const char *pcEventName) const {
uint32 i;
// Find the event in the list of events the object is registered for.
i = 0;
while ((i < m_nNumRegisteredEvents) && strcmp(m_pNamedEventList[i].s_pcEventName, pcEventName))
++i;
// If we ran off the end of that array, then return EVENT_INVALID_SENDER_ID and log a warning.
if (i == m_nNumRegisteredEvents) {
Zdebug("_event_list::GetIDOfLastObjectToPostEvent( %s ) - event not listed for object.", pcEventName);
return (EVENT_INVALID_SENDER_ID);
}
// Return the last sender ID.
return (m_pNamedEventList[i].s_nLastSenderID);
}
void _event_list::Initialise() {
uint32 i;
// Initially, there are no pending events.
m_nNumNamedEventsPending = 0;
m_bEventPending = FALSE8;
// All objects get a line-of-sight slot by default.
m_pNamedEventList[0].s_pcEventName = EVENT_LINE_OF_SIGHT;
m_pNamedEventList[0].s_nLastSenderID = EVENT_INVALID_SENDER_ID;
m_pNamedEventList[0].s_bPending = FALSE8;
m_nNumRegisteredEvents = 1;
// Set all remaining slots to be empty.
for (i = 1; i < EVENT_MAX_EVENTS_REGISTERED; ++i)
m_pNamedEventList[i].s_pcEventName = EVENT_DELETED_PLACEHOLDER;
}
} // End of namespace ICB

176
engines/icb/event_list.h Normal file
View 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_EVENTLIST_H_INCLUDED
#define ICB_EVENTLIST_H_INCLUDED
#include "engines/icb/string_vest.h"
#include "engines/icb/common/px_string.h"
#include "engines/icb/string_vest.h"
namespace ICB {
// Use globals to save on rdata storage and having repeated strings therein
extern const char *global_event_deleted_placeholder;
extern const char *global_event_generic;
extern const char *global_event_line_of_sight;
extern const char *global_event_sound;
extern const char *global_event_on_camera;
extern const char *global_event_off_camera;
extern const char *global_event_logic_rerun;
extern const char *global_event_out_of_sight;
extern const char *global_event_lift_ascend;
extern const char *global_event_lift_descend;
// This is used to mark deleted objects to save reallocating all the time.
#define EVENT_DELETED_PLACEHOLDER global_event_deleted_placeholder
// This string is used to identify a generic, anonymous event, which all objects respond to all the time.
#define EVENT_LINE_OF_SIGHT global_event_line_of_sight
#define EVENT_OUT_OF_SIGHT global_event_out_of_sight
#define EVENT_ON_CAMERA global_event_on_camera
#define EVENT_OFF_CAMERA global_event_off_camera
#define EVENT_LIFT_ASCEND global_event_lift_ascend
#define EVENT_LIFT_DESCEND global_event_lift_descend
#define EVENT_LOGIC_RERUN global_event_logic_rerun
// Primarily for PSX speed variable data structures are history.
#define EVENT_MAX_EVENTS_REGISTERED 20
// This marks an invalid object ID as the sender of an event.
#define EVENT_INVALID_SENDER_ID (-1)
struct _event {
const char *s_pcEventName;
int32 s_nLastSenderID;
bool8 s_bPending;
uint8 s_nPadding[3];
// Initialisation.
_event() {
s_pcEventName = EVENT_DELETED_PLACEHOLDER;
s_nLastSenderID = EVENT_INVALID_SENDER_ID;
s_bPending = FALSE8;
}
// Copy constructor and assignment.
_event(const _event &oX) {
s_pcEventName = oX.s_pcEventName;
s_nLastSenderID = oX.s_nLastSenderID;
s_bPending = oX.s_bPending;
}
const _event &operator=(const _event &oOpB) {
s_pcEventName = oOpB.s_pcEventName;
s_nLastSenderID = oOpB.s_nLastSenderID;
s_bPending = oOpB.s_bPending;
return (*this);
}
};
// class _event_list
// Holds the list of events an object is currently interested in and counts of which ones are pending. Events
// with handlers are held in a separate list and take precedence over generic events, which simply cause the
// logic context for the object to be rerun.
class _event_list {
public:
// Default constructor and destructor.
inline _event_list();
~_event_list() {}
// Copy constructor.
_event_list(const _event_list &oX);
// Operator '='.
const _event_list &operator=(const _event_list &oOpB);
// This sets a new object name for the event list, and resets everything else.
void SetNewObjectName(const char *pcObjectName);
// This gets the name of the object that the event list is for.
const char *GetObjectName() const { return (m_pcObjectName); }
// This determines whether or not an object requires any event processing.
inline bool8 HasEventPending();
// Checks if the named event is waiting for the object.
bool8 CheckEventWaiting(const char *pcEventName);
// This determines whether or not the named event is in the list of registered events.
bool8 IsEventInList(const char *pcEventName) const;
// These functions have direct script equivalents, but may also get used directly from the engine.
void AddEventForObject(const char *pcEventName);
void RemoveEventForObject(const char *pcEventName);
inline void RemoveAllEventsForObject();
bool8 DidObjectSendLastNamedEvent(uint32 nObjectID, const char *pcEventName) const;
int32 GetIDOfLastObjectToPostEvent(const char *pcEventName) const;
bool8 PostNamedEvent(const char *pcEventName, int32 nSenderID);
void ClearAllOutstandingEvents();
private:
const char *m_pcObjectName; // Name of the object.
_event m_pNamedEventList[EVENT_MAX_EVENTS_REGISTERED]; // Named events this object is interested in.
uint8 m_nNumNamedEventsPending; // Number of named events pending.
uint8 m_nNumRegisteredEvents; // Number of events object is currently interested in.
bool8 m_bEventPending; // If true, at least one event is pending.
uint8 m_nPad1;
// Private functions used only inside this class.
void Initialise();
};
inline _event_list::_event_list() {
Initialise();
m_pcObjectName = EVENT_DELETED_PLACEHOLDER;
}
inline void _event_list::SetNewObjectName(const char *pcObjectName) {
Initialise();
m_pcObjectName = pcObjectName;
}
inline bool8 _event_list::HasEventPending() {
bool8 bRetVal;
// This function has no choice but to clear this flag, for two reasons: firstly, line-of-sight events don't
// get explicitly handled by a particular piece of code and so there is nowhere to clear the event if we
// don't do it here; secondly, even if named events are outstanding, I can't leave the event flag set because
// the script writer might not be making any calls to CheckEventWaiting(), in which case the event flag again
// would never get cleared.
bRetVal = m_bEventPending;
m_bEventPending = FALSE8;
return (bRetVal);
}
inline void _event_list::RemoveAllEventsForObject() { Initialise(); }
} // End of namespace ICB
#endif // #ifndef EVENTLIST_H_INCLUDED

View File

@@ -0,0 +1,297 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/event_manager.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/mission.h"
#include "common/stream.h"
namespace ICB {
bool8 _event_manager::HasEventPending(int32 nObjectID) {
// First check the ID is in range and the object is running.
if ((nObjectID < 0) || ((uint32)nObjectID >= m_nNumObjects))
Fatal_error("Object ID %d out of range in _event_manager::HasEventPending()", nObjectID);
// If the object is not running, simply return false.
if (!m_pbRunning[nObjectID] || m_pbSuspended[nObjectID])
return (FALSE8);
// Return the flag for the object.
return (m_pEventLists[nObjectID].HasEventPending());
}
bool8 _event_manager::CheckEventWaitingForObject(int32 nObjectID, const char *pcEventName) {
// First check the ID is in range and the object is running.
if ((nObjectID < 0) || ((uint32)nObjectID >= m_nNumObjects))
Fatal_error("Object ID %d out of range in _event_manager::CheckEventWaitingForObject()", nObjectID);
// If the object is not running, simply return false.
if (!m_pbRunning[nObjectID] || m_pbSuspended[nObjectID])
return (FALSE8);
// Check the object's event list.
return (m_pEventLists[nObjectID].CheckEventWaiting(pcEventName));
}
void _event_manager::ShutDownEventProcessingForObject(int32 nObjectID) {
// First check the ID is in range and the object is running.
if ((nObjectID < 0) || ((uint32)nObjectID >= m_nNumObjects))
Fatal_error("Object ID %d out of range in _event_manager::ShutDownEventProcessingForObject()", nObjectID);
// Mark it shut down.
m_pbRunning[nObjectID] = FALSE8;
}
void _event_manager::RegisterForEvent(int32 nObjectID, const char *pcEventName) {
// First check the ID is in range and the object is running.
if ((nObjectID < 0) || ((uint32)nObjectID >= m_nNumObjects))
Fatal_error("Object ID %d out of range in _event_manager::RegisterForEvent()", nObjectID);
// Add the event for the object.
if (m_pbRunning[nObjectID])
m_pEventLists[nObjectID].AddEventForObject(pcEventName);
}
void _event_manager::UnregisterForEvent(int32 nObjectID, const char *pcEventName) {
// First check the ID is in range and the object is running.
if ((nObjectID < 0) || ((uint32)nObjectID >= m_nNumObjects))
Fatal_error("Object ID %d out of range in _event_manager::UnregisterForEvent()", nObjectID);
// Make sure the object is running.
if (m_pbRunning[nObjectID]) {
// Remove event for the object.
m_pEventLists[nObjectID].RemoveEventForObject(pcEventName);
// This is a useful opportunity to do some cleaning up. Having worked with the implementers, it
// seems like desirable behaviour that all events get cleared when you unregister an object for one.
m_pEventLists[nObjectID].ClearAllOutstandingEvents();
}
}
void _event_manager::ClearAllEventsForObject(int32 nObjectID) {
// First check the ID is in range and the object is running.
if ((nObjectID < 0) || ((uint32)nObjectID >= m_nNumObjects))
Fatal_error("Object ID %d out of range in _event_manager::ClearAllEventsForObject()", nObjectID);
// Clear the object's events.
if (m_pbRunning[nObjectID])
m_pEventLists[nObjectID].ClearAllOutstandingEvents();
}
void _event_manager::SetSuspendFlagForObject(int32 nObjectID, bool8 bState) {
// First check the ID is in range and the object is running.
if ((nObjectID < 0) || ((uint32)nObjectID >= m_nNumObjects))
Fatal_error("Object ID %d out of range in _event_manager::SetSuspendFlagForObject()", nObjectID);
// Flag the object suspended or not.
m_pbSuspended[nObjectID] = bState;
}
bool8 _event_manager::DidObjectSendLastNamedEvent(int32 nCallerID, int32 nObjectID, const char *pcEventName) const {
if ((nCallerID < 0) || ((uint32)nCallerID >= m_nNumObjects))
Fatal_error("Caller ID %d out of range in _event_manager::DidObjectSendLastEvent()", nCallerID);
if ((nObjectID < 0) || ((uint32)nObjectID >= m_nNumObjects))
Fatal_error("Object ID %d out of range in _event_manager::DidObjectSendLastEvent()", nObjectID);
// Get the ID of last poster of named event.
if (!m_pbRunning[nCallerID] || m_pbSuspended[nCallerID])
return (FALSE8);
else
return (m_pEventLists[nCallerID].DidObjectSendLastNamedEvent(nObjectID, pcEventName));
}
int32 _event_manager::GetIDOfLastObjectToPostEvent(int32 nCallerID, const char *pcEventName) const {
if ((nCallerID < 0) || ((uint32)nCallerID >= m_nNumObjects))
Fatal_error("Caller ID %d out of range in _event_manager::GetIDOfLastObjectToPostEvent()", nCallerID);
// Get the ID of last poster of named event.
if (!m_pbRunning[nCallerID] || m_pbSuspended[nCallerID])
return (FALSE8);
else
return (m_pEventLists[nCallerID].GetIDOfLastObjectToPostEvent(pcEventName));
}
void _event_manager::PostNamedEventToObject(const char *pcEventName, int32 nTargetID, int32 nSenderID) {
if ((nSenderID < 0) || ((uint32)nSenderID >= m_nNumObjects))
Fatal_error("Sender ID %d out of range in _event_manager::PostNamedEventToObject()", nSenderID);
if ((nTargetID < 0) || ((uint32)nTargetID >= m_nNumObjects))
Fatal_error("Target ID %d out of range in _event_manager::PostNamedEventToObject()", nTargetID);
// Post the named event for one object only.
if (m_pbRunning[nTargetID] || m_pbSuspended[nTargetID])
m_pEventLists[nTargetID].PostNamedEvent(pcEventName, nSenderID);
}
bool8 _event_manager::IsObjectRegisteredForEvent(int32 nCallerID, const char *pcEventName) {
if ((nCallerID < 0) || ((uint32)nCallerID >= m_nNumObjects))
Fatal_error("Sender ID %d out of range in _event_manager::IsObjectRegisteredForEvent()", nCallerID);
if (m_pbRunning[nCallerID])
return (m_pEventLists[nCallerID].IsEventInList(pcEventName));
else
return (FALSE8);
}
void _event_manager::Initialise() {
uint32 i;
// Initialize the line-of-sight module.
g_oLineOfSight->Initialise();
// Add an entry for each of the objects in this session.
m_nNumObjects = (uint8)MS->total_objects;
memset(m_pbRunning, 0, MAX_session_objects * sizeof(bool8));
memset(m_pbSuspended, 0, MAX_session_objects * sizeof(bool8));
for (i = 0; i < m_nNumObjects; ++i) {
// Create an event list for the object.
m_pEventLists[i].SetNewObjectName(MS->logic_structs[i]->GetName());
// Flag it running or not.
if (MS->logic_structs[i]->ob_status == OB_STATUS_HELD)
m_pbRunning[i] = FALSE8;
else
m_pbRunning[i] = TRUE8;
}
// To start with, no event timers are running.
for (i = 0; i < EVENT_MANAGER_MAX_TIMERS; ++i)
m_pbActiveTimers[i] = FALSE8;
}
void _event_manager::PostNamedEvent(const char *pcEventName, int32 nSenderID) {
uint32 i;
// Loop through each object in the session.
for (i = 0; i < m_nNumObjects; ++i) {
// Post the event only if the object is marked as running.
if (m_pbRunning[i] && !m_pbSuspended[i])
m_pEventLists[i].PostNamedEvent(pcEventName, nSenderID);
}
}
void _event_manager::CycleEventManager() {
uint32 i;
uint32 nElapsed;
// Loop for each timer.
for (i = 0; i < EVENT_MANAGER_MAX_TIMERS; ++i) {
// Watch out for unused slots.
if (m_pbActiveTimers[i]) {
// Process the timer.
m_pEventTimers[i].SetEventTime(m_pEventTimers[i].GetEventTime() + 1);
// If it has gone past the end then it has expired and so needs removing.
if (m_pEventTimers[i].GetEventTime() > m_pEventTimers[i].GetEnd()) {
// Delete this expired timer.
m_pbActiveTimers[i] = FALSE8;
} else {
// Timer has not expired but might not even have started.
if (m_pEventTimers[i].GetEventTime() >= m_pEventTimers[i].GetEnd()) {
// Yes, it has started and has not expired. So check if it matches some multiple of
// the interval.
nElapsed = m_pEventTimers[i].GetEventTime() - m_pEventTimers[i].GetStart();
if ((m_pEventTimers[i].GetInterval() == 0) || ((nElapsed % m_pEventTimers[i].GetInterval()) == 0)) {
// We need to generate an event.
PostNamedEvent(m_pEventTimers[i].GetEventName(), m_pEventTimers[i].GetObjectID());
}
}
}
}
}
}
void _event_manager::PostRepeatingEvent(const char *pcEventName, uint32 nStart, uint32 nInterval, uint32 nEnd) {
uint32 i;
// Look for a vacant slot.
i = 0;
while ((i < EVENT_MANAGER_MAX_TIMERS) && m_pbActiveTimers[i])
++i;
// If we ran off the end, we failed to find a spare slot.
if (i == EVENT_MANAGER_MAX_TIMERS)
Fatal_error("Run out of event timer slots in _event_manager::PostRepeatingEvent()");
// Set up the timer.
m_pEventTimers[i].SetEventName(pcEventName);
m_pEventTimers[i].SetStart(nStart);
m_pEventTimers[i].SetEnd(nEnd);
m_pEventTimers[i].SetInterval(nInterval);
m_pEventTimers[i].SetEventTime(0);
// Flag it as running.
m_pbActiveTimers[i] = TRUE8;
}
void _event_manager::Save(Common::WriteStream *stream) const {
uint32 i;
uint32 nNumActiveTimers = 0;
// First, work out how many timers we are going to write.
for (i = 0; i < EVENT_MANAGER_MAX_TIMERS; ++i) {
if (m_pbActiveTimers[i])
++nNumActiveTimers;
}
// Write the number of active event timers in the file.
stream->writeUint32LE(nNumActiveTimers);
// Now write the actual active event timers.
for (i = 0; i < EVENT_MANAGER_MAX_TIMERS; ++i) {
if (m_pbActiveTimers[i])
m_pEventTimers[i].Save(stream);
}
}
void _event_manager::Restore(Common::SeekableReadStream *stream) {
uint32 i;
uint32 nNumActiveTimers;
_event_timer oEventTimer;
// Make sure all timers are currently deactivated. This is the same as overwriting them.
for (i = 0; i < EVENT_MANAGER_MAX_TIMERS; ++i)
m_pbActiveTimers[i] = FALSE8;
// Find out how many timers we are going to read in.
nNumActiveTimers = stream->readUint32LE();
// Read them in.
for (i = 0; i < nNumActiveTimers; ++i) {
oEventTimer.Restore(stream);
m_pEventTimers[i] = oEventTimer;
m_pbActiveTimers[i] = TRUE8;
}
if (stream->err())
Fatal_error("Error restoring event timers from save file");
}
} // End of namespace ICB

102
engines/icb/event_manager.h Normal file
View File

@@ -0,0 +1,102 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_EVENTMANAGER_H_INCLUDED
#define ICB_EVENTMANAGER_H_INCLUDED
// Include files with relative paths
#include "engines/icb/common/px_string.h"
#include "engines/icb/p4.h"
#include "engines/icb/event_timer.h"
#include "engines/icb/event_list.h"
#include "engines/icb/session.h"
namespace ICB {
#define EVENT_MANAGER_LOG "event_manager_log.txt"
// Maximum number of event timers active at one time.
#define EVENT_MANAGER_MAX_TIMERS 4
// Keeps track of which object is interested in hearing about events from which other objects and stores
// events which have occurred until they can be handled.
class _event_manager {
public:
// Default constructor and destructor.
_event_manager() {}
~_event_manager() {}
// This initializes the whole object and must be called at the start of each session.
void Initialise();
// This says whether a particular object has events pending.
bool8 HasEventPending(int32 nObjectID);
// This checks if an object has the named event waiting for it.
bool8 CheckEventWaitingForObject(int32 nObjectID, const char *pcEventName);
// This shuts down an object in the event manager.
void ShutDownEventProcessingForObject(int32 nObjectID);
// This processes the event timers if there are any, posting events as required.
void CycleEventManager();
// Determines whether or not the named object is registered for the named event.
bool8 IsObjectRegisteredForEvent(int32 nCallerID, const char *pcEventName);
// These functions save and restore necessary parts of the event manager.
void Save(Common::WriteStream *stream) const;
void Restore(Common::SeekableReadStream *stream);
// These functions will probably have direct script counterparts.
void RegisterForEvent(int32 nObjectID, const char *pcEventName);
void UnregisterForEvent(int32 nObjectID, const char *pcEventName);
void PostNamedEvent(const char *pcEventName, int32 nSenderID);
void PostNamedEventToObject(const char *pcEventName, int32 nTargetID, int32 nSenderID);
void PostRepeatingEvent(const char *pcEventName, uint32 nStart, uint32 nInterval, uint32 nEnd);
void ClearAllEventsForObject(int32 nObjectID);
bool8 DidObjectSendLastNamedEvent(int32 nCallerID, int32 nObjectID, const char *pcEventName) const;
int32 GetIDOfLastObjectToPostEvent(int32 nCallerID, const char *pcEventName) const;
void SetSuspendFlagForObject(int32 nObjectID, bool8 bState);
private:
_event_list m_pEventLists[MAX_session_objects]; // List of objects and the events they are currently interested in.
_event_timer m_pEventTimers[EVENT_MANAGER_MAX_TIMERS]; // Housekeeping for future and repeating events.
uint8 m_nNumObjects; // Number of objects in the event manager.
bool8 m_pbActiveTimers[EVENT_MANAGER_MAX_TIMERS]; // Housekeeping for future and repeating events.
bool8 m_pbRunning[MAX_session_objects]; // Set true for currently-running objects, false if they have been shut down.
bool8 m_pbSuspended[MAX_session_objects]; // Allows objects to be suspended then reinstated.
// Here I block the use of the default '='.
_event_manager(const _event_manager &) {}
void operator=(const _event_manager &) {}
};
extern _event_manager *g_oEventManager; // Instantiated in global_objects.cpp.
} // End of namespace ICB
#endif // #if !defined( EVENTMANAGER_H_INCLUDED )

132
engines/icb/event_timer.h Normal file
View File

@@ -0,0 +1,132 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_EVENTTIMER_H_INCLUDED
#define ICB_EVENTTIMER_H_INCLUDED
#include "common/stream.h"
#include "engines/icb/string_vest.h"
#include "engines/icb/common/px_string.h"
#include "engines/icb/event_list.h"
namespace ICB {
// class _event_timer
// This structure holds timing information for events that are posted into the future or have
// to happen repeatedly.
class _event_timer {
public:
// Default constructor and destructor.
inline _event_timer();
~_event_timer() {}
// Copy constructor.
inline _event_timer(const _event_timer &oX);
// Operator '='.
inline const _event_timer &operator=(const _event_timer &oOpB);
// Gets and sets.
void SetObjectID(int32 nObjectID) { m_nObjectID = nObjectID; }
void SetStart(uint32 nStart) { m_nStart = nStart; }
void SetEnd(uint32 nEnd) { m_nEnd = nEnd; }
void SetInterval(uint32 nInterval) { m_nInterval = nInterval; }
void SetEventTime(uint32 nTime) { m_nCurrentTime = nTime; }
inline void SetEventName(const char *pcEventName);
int32 GetObjectID() const { return (m_nObjectID); }
uint32 GetStart() const { return (m_nStart); }
uint32 GetEnd() const { return (m_nEnd); }
uint32 GetInterval() const { return (m_nInterval); }
uint32 GetEventTime() const { return (m_nCurrentTime); }
const char *GetEventName() const { return (m_pcEventName); }
void Save(Common::WriteStream *stream) const {
stream->writeSint32LE(m_nObjectID);
stream->writeUint32LE(m_nStart);
stream->writeUint32LE(m_nEnd);
stream->writeUint32LE(m_nInterval);
stream->writeUint32LE(m_nCurrentTime);
stream->write(m_pcEventName, MAXLEN_EVENT_NAME);
}
void Restore(Common::SeekableReadStream *stream) {
m_nObjectID = stream->readSint32LE();
m_nStart = stream->readUint32LE();
m_nEnd = stream->readUint32LE();
m_nInterval = stream->readUint32LE();
m_nCurrentTime = stream->readUint32LE();
stream->read(m_pcEventName, MAXLEN_EVENT_NAME);
}
private:
int32 m_nObjectID; // ID of object initiating this timer.
uint32 m_nStart; // When the event should start, relative to the time the event was placed.
uint32 m_nEnd; // When the event should end, relative to the time the event was placed.
uint32 m_nInterval; // Interval between occurrences of the event.
uint32 m_nCurrentTime; // Relative to the reference time.
char m_pcEventName[MAXLEN_EVENT_NAME]; // Name of the event.
};
inline _event_timer::_event_timer() {
m_nObjectID = EVENT_INVALID_SENDER_ID;
m_nStart = 0;
m_nEnd = 0;
m_nInterval = 0;
m_nCurrentTime = 0;
m_pcEventName[0] = '\0';
}
inline _event_timer::_event_timer(const _event_timer &oX) {
m_nObjectID = oX.m_nObjectID;
m_nStart = oX.m_nStart;
m_nEnd = oX.m_nEnd;
m_nInterval = oX.m_nInterval;
m_nCurrentTime = oX.m_nCurrentTime;
Common::strcpy_s(m_pcEventName, oX.m_pcEventName);
}
inline const _event_timer &_event_timer::operator=(const _event_timer &oOpB) {
m_nObjectID = oOpB.m_nObjectID;
m_nStart = oOpB.m_nStart;
m_nEnd = oOpB.m_nEnd;
m_nInterval = oOpB.m_nInterval;
m_nCurrentTime = oOpB.m_nCurrentTime;
Common::strcpy_s(m_pcEventName, oOpB.m_pcEventName);
return (*this);
}
inline void _event_timer::SetEventName(const char *pcEventName) {
if (strlen(pcEventName) >= MAXLEN_EVENT_NAME)
Fatal_error("Event name [%s] too long (max %d) in _event_timer::SetEventName()", pcEventName, MAXLEN_EVENT_NAME - 1);
Common::strcpy_s(m_pcEventName, pcEventName);
}
} // End of namespace ICB
#endif // #if !defined( EVENTTIMER_H_INCLUDED )

445
engines/icb/floors.cpp Normal file
View File

@@ -0,0 +1,445 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/p4.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_floor_map.h"
#include "engines/icb/common/px_linkeddatafile.h"
#include "engines/icb/mission.h"
#include "engines/icb/session.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/debug.h"
#include "engines/icb/floors.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/res_man.h"
namespace ICB {
_floor_world::_floor_world() {}
void _floor_world::___init() {
// init the floor and exit object
// works out how many floor levels are in the map and makes a list of them
// sets total_floors
// total_heights
// fills heights[]
uint32 buf_hash = NULL_HASH;
uint32 j, k, len;
PXreal temp;
_floor *floor;
// load the file for this session
// When clustered the session files have the base stripped
len = Common::sprintf_s(temp_buf, "%s", PX_FILENAME_FLOOR_MAP);
if (len > ENGINE_STRING_LEN)
Fatal_error("_floor_world::___init string len error");
uint32 cluster_hash = MS->Fetch_session_cluster_hash();
floors = (LinkedDataFile *)private_session_resman->Res_open(temp_buf, buf_hash, MS->Fetch_session_cluster(), cluster_hash);
// Check the file schema
if (LinkedDataObject::GetHeaderVersion(floors) != VERSION_PXWGFLOORS)
Fatal_error("Incorrect version number for floor data [%s] - file has %d, engine has %d", temp_buf, LinkedDataObject::GetHeaderVersion(floors), VERSION_PXWGFLOORS);
// set this for convenience
total_floors = LinkedDataObject::Fetch_number_of_items(floors);
Tdebug("floors.txt", "##total floors %d", total_floors);
// check for no floors
if (!total_floors) // no floors :O
Fatal_error("session has no floors - engine cannot proceed");
if (total_floors > MAX_floors) // general legality check to catch corrupt files
Fatal_error("engine stopping due to suspicious PxWGFloors file - has %d floors", total_floors);
// get some useful stats
total_heights = 0; // set to 0
int32 nMissing = 0;
for (j = 0; j < total_floors; j++) {
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, j);
if (total_heights) {
// see if this height is already defined
for (k = 0; k < total_heights; k++)
if (heights[k] == floor->base_height)
break; // already here
if (k == total_heights) {
// not found so register the new height
heights[total_heights++] = floor->base_height;
if (total_heights > MAX_slices)
Fatal_error("_floor_world::___init has run out of slices - %d found, %d allowed", total_heights, MAX_slices);
}
} else {
// register the first height
heights[0] = floor->base_height;
total_heights = 1;
}
}
if (nMissing > 0) {
Fatal_error("%d missing cameras : Game must terminate", nMissing);
}
// now sort the heights
if (total_heights > 1) {
for (j = 0; j < total_heights; j++) {
for (k = 0; k < total_heights - 1; k++) {
if (heights[k] > heights[k + 1]) {
temp = heights[k + 1];
heights[k + 1] = heights[k];
heights[k] = temp;
}
}
}
}
// create a dummy top floor figure for floor_y_volume creation
heights[total_heights] = REAL_LARGE;
Tdebug("floors.txt", "\n\n\n\n%d different heights", total_heights);
for (j = 0; j < total_heights; j++)
Tdebug("floors.txt", " %3.1f", heights[j]);
Tdebug("floors.txt", "\n\n\ncreating floor y volume table\n");
// in-case second time around
// create room height table
for (j = 0; j < total_floors; j++) {
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, j);
for (k = 0; k < total_heights; k++) {
if (floor->base_height == heights[k]) {
floor_y_volume[j] = (heights[k + 1] - REAL_ONE);
Tdebug("floors.txt", "floor %d, base %3.2f, top %3.2f", j, floor->base_height, floor_y_volume[j]);
}
}
}
}
bool8 _floor_world::On_a_floor(_mega *mega) {
// is a mega on a floor
// used to dismiss gunshots when on stairs, etc.
uint32 j;
for (j = 0; j < total_heights; j++)
if (mega->actor_xyz.y == heights[j])
return TRUE8;
return FALSE8;
}
void _floor_world::Align_with_floor(_mega *mega) {
uint32 j;
// check against actual heights
for (j = 0; j < total_heights; j++) {
if (mega->actor_xyz.y == heights[j])
return;
}
// not on one so align with one if we are pretty near
for (j = 0; j < total_heights; j++) {
if (PXfabs(mega->actor_xyz.y - heights[j]) < (REAL_ONE * 15)) {
mega->actor_xyz.y = heights[j];
return;
}
}
}
PXreal _floor_world::Return_true_y(PXreal y) {
// snap a y coordinate up or down to the floor it is meant to be
// used by walk area camera director
uint32 j;
// check against actual heights
for (j = 0; j < total_heights; j++)
if (y == heights[j])
return y;
// not on one so align with one if we are pretty near
for (j = 0; j < total_heights; j++)
if (PXfabs(y - heights[j]) < (REAL_ONE * 15)) {
y = heights[j];
return y;
}
return y;
}
_floor_world::~_floor_world() {
//_floor_world destructor
Zdebug("*_floor_world destructing*");
}
uint32 _floor_world::Fetch_floor_number_by_name(const char *name) {
// return a pointer to a named floor to an external routine - most likely a fn_function
return (LinkedDataObject::Fetch_item_number_by_name(floors, name));
}
uint32 _floor_world::Return_floor_rect(PXreal x, PXreal z, PXreal y, uint32 rubber) {
// find the floor LRECT that point x,y,z lies within
// returns rect number and pointer to _rect
// or PXNULL
uint32 j;
// search through all floors
for (j = 0; j < total_floors; j++) {
_floor *floor;
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, j);
if (floor->base_height == (int32)y) {
// this floor is in our view level
// check our x,z against all the rects
// if hit then return floor number
if ((x >= (PXreal)(floor->rect.x1 - rubber)) && (x <= (PXreal)(floor->rect.x2 + rubber)) && (z >= (PXreal)(floor->rect.z1 - rubber)) &&
(z <= (PXreal)(floor->rect.z2 + rubber)))
return (j);
}
}
// point is not on any floor rect
return (PXNULL);
}
bool8 _floor_world::Point_on_rubber_floor(PXreal x, PXreal z, PXreal y, uint32 rubber, uint32 rect_num) {
_floor *floor;
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, rect_num);
if (floor->base_height == (int32)y) {
// if hit then return floor number
if ((x >= (PXreal)(floor->rect.x1 - rubber)) && (x <= (PXreal)(floor->rect.x2 + rubber)) && (z >= (PXreal)(floor->rect.z1 - rubber)) &&
(z <= (PXreal)(floor->rect.z2 + rubber)))
return TRUE8;
}
// point is not on floor rect
return FALSE8;
}
uint32 _floor_world::Locate_floor_rect(PXreal x, PXreal z, PXreal y, _floor **rct) {
// find the floor RECT that point x,y,z lies within
// returns rect number and pointer to _rect
// or PXNULL
uint32 j;
for (j = 0; j < total_floors; j++) {
_floor *floor;
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, j);
if (floor->base_height == (int32)y) {
// this floor is in our view level
// check our x,z against all the rects
// if hit then return floor number
if ((x >= (PXreal)floor->rect.x1) && (x <= (PXreal)floor->rect.x2) && (z >= (PXreal)floor->rect.z1) && (z <= (PXreal)floor->rect.z2)) {
*rct = floor;
return (j);
}
}
}
// point is not on any floor rect
Message_box("no floor");
return (PXNULL);
}
void _floor_world::Set_floor_rect_flag(_logic *log) {
// find the floor RECT that character belongs to and fill in the owner_floor_rect flag
// note - there are ways to speed this up. We could record the rect and then only do a full search if the object
// moves outside the recorded rect again
uint32 j;
_floor *floor;
PXreal y;
#define FLOOR_RUBBER (20 * REAL_ONE)
// y locking
if (log->mega->y_locked)
y = log->mega->y_lock;
else
y = log->mega->actor_xyz.y;
// ylocking
// first see if we're one same one as last time
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, log->owner_floor_rect);
if ((y >= (floor->base_height - (0 * REAL_ONE))) && ((y <= (floor_y_volume[log->owner_floor_rect] - (0 * REAL_ONE))))) // this floor is in our view level
if ((log->mega->actor_xyz.x >= (floor->rect.x1 - FLOOR_RUBBER)) && (log->mega->actor_xyz.x <= (floor->rect.x2 + FLOOR_RUBBER)) &&
(log->mega->actor_xyz.z >= (floor->rect.z1 - FLOOR_RUBBER)) && (log->mega->actor_xyz.z <= (floor->rect.z2 + FLOOR_RUBBER))) {
Zdebug("[%s]still on %d", MS->Fetch_object_name(MS->Fetch_cur_id()), log->owner_floor_rect);
return; // yup, still hitting!
}
// search through all floors
for (j = 0; j < total_floors; j++) {
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, j);
if ((y >= (floor->base_height - (0 * REAL_ONE))) && ((y <= (floor_y_volume[j] - (0 * REAL_ONE))))) {
// this floor is in our view level
// if hit then return floor number
if ((log->mega->actor_xyz.x >= floor->rect.x1) && (log->mega->actor_xyz.x <= floor->rect.x2) && (log->mega->actor_xyz.z >= floor->rect.z1) &&
(log->mega->actor_xyz.z <= floor->rect.z2)) {
log->owner_floor_rect = j;
return;
}
}
}
// point is not on any floor rect
// hmmm, well, hold previous value i guess
Tdebug("warning.txt", "Set_floor_rect_flag; %s has no floor", MS->Fetch_object_name(MS->Fetch_cur_id()));
}
uint32 _floor_world::Return_non_rubber_floor_no(_logic *log, uint32 cur_rubber_floor) {
// return exact box
// used by camera director when leaving WA's
uint32 j;
_floor *floor;
// first see if we're one same one as last time
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, cur_rubber_floor);
if ((log->mega->actor_xyz.y >= floor->base_height) && ((log->mega->actor_xyz.y <= floor_y_volume[log->owner_floor_rect]))) // this floor is in our view level
if ((log->mega->actor_xyz.x >= (floor->rect.x1)) && (log->mega->actor_xyz.x <= (floor->rect.x2)) && (log->mega->actor_xyz.z >= (floor->rect.z1)) &&
(log->mega->actor_xyz.z <= (floor->rect.z2))) {
return cur_rubber_floor; // yup, still hitting!
}
// search through all floors
for (j = 0; j < total_floors; j++) {
floor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, j);
if ((log->mega->actor_xyz.y >= floor->base_height) && ((log->mega->actor_xyz.y <= floor_y_volume[j]))) {
// this floor is in our view level
// if hit then return floor number
if ((log->mega->actor_xyz.x >= floor->rect.x1) && (log->mega->actor_xyz.x <= floor->rect.x2) && (log->mega->actor_xyz.z >= floor->rect.z1) &&
(log->mega->actor_xyz.z <= floor->rect.z2)) {
return j;
}
}
}
// point is not on any floor rect
// hmmm, well, hold previous value i guess
return cur_rubber_floor;
}
PXreal _floor_world::Gravitise_y(PXreal y) {
// pull a y coordinate back to a floor height
int32 j;
for (j = total_heights - 1; j != -1; j--) { // 4 heights == j=3 == [0][1][2][3]
if (y >= heights[j]) {
return (heights[j]);
}
}
Zdebug("\n\nGravitise_y %3.2f", y);
for (j = 0; j < (int32)total_heights; j++)
Zdebug("%d [%3.2f]", j, heights[j]);
Fatal_error("Gravitise_y finds major height problem - %s", MS->Fetch_object_name(MS->Fetch_cur_id()));
return (y);
}
PXreal _floor_world::Floor_safe_gravitise_y(PXreal fY) {
int32 i;
// This function does the same as Gravitise_y() but does not Fatal_error if it
// falls out of the bottom of the game world. This is to correct faults in the
// art (surprise, surprise) that were causing megas on ladders to briefly have a
// y-coordinate lower than the floor the ladder bottom is on.
for (i = total_heights - 1; i != -1; --i) {
if (fY >= heights[i])
return (heights[i]);
}
// Simply return the lowest floor height.
return (heights[0]);
}
int32 _floor_world::Project_point_down_through_floors(int32 nX, int32 nY, int32 nZ) {
int32 nSliceIndex;
uint32 j;
_floor *pFloor;
// Do what the normal Gravitise_y() does to place the point on the slice height below it.
nSliceIndex = total_heights - 1;
while ((nSliceIndex > -1) && (nY < (int32)heights[nSliceIndex]))
--nSliceIndex;
// See which loop condition failed.
if (nSliceIndex == -1) {
// Fell out of the bottom of the floor world, but this is not an error in this function.
return (-1);
}
// Right, we have put the point on a slice. While there are slices still to go
// beneath the current point, we check if the point lies within a floor rectangle
// on that height.
while (nSliceIndex > -1) {
nY = (int32)heights[nSliceIndex];
for (j = 0; j < total_floors; ++j) {
pFloor = (_floor *)LinkedDataObject::Fetch_item_by_number(floors, j);
if (pFloor->base_height == nY) {
// Floor at this height, so check its position.
if ((nX >= pFloor->rect.x1) && (nX <= pFloor->rect.x2) && (nZ >= pFloor->rect.z1) && (nZ <= pFloor->rect.z2)) {
return (nSliceIndex);
}
}
}
// Right, the point hit nothing on that level. Move to the slice below.
--nSliceIndex;
}
// If we fell out, it is not an error. It simply means there is no floor beneath
// the point we are checking.
return (-1);
}
} // End of namespace ICB

117
engines/icb/floors.h Normal file
View File

@@ -0,0 +1,117 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ICB_FLOORS_H
#define ICB_FLOORS_H
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_linkeddatafile.h"
#include "engines/icb/prim_route_builder.h"
#include "engines/icb/common/px_floor_map.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/barriers.h"
namespace ICB {
class _floor_world {
public:
_floor_world();
~_floor_world();
void ___init();
uint32 Locate_floor_rect(PXreal x, PXreal z, PXreal y, _floor **rct);
uint32 Return_floor_rect(PXreal x, PXreal z, PXreal y, uint32 rubber);
bool8 Point_on_rubber_floor(PXreal x, PXreal z, PXreal y, uint32 rubber, uint32 rect_num);
void Set_floor_rect_flag(_logic *log);
uint32 Return_non_rubber_floor_no(_logic *log, uint32 cur_rubber_floor);
// floor router
void Pick_floor_route(uint32 start, uint32 dest);
void Find_shortest_floor_route(uint32 start, uint32 dest, uint32 x, uint32 z);
void Recurse_to_shortest(uint32 adjoining_floor, uint32 level, uint32 dest);
uint32 Calculate_floor_route_length(uint32 total_floors);
PXreal Fetch_height(uint32 height);
int32 Fetch_total_heights();
uint32 Fetch_total_floors();
PXreal Gravitise_y(PXreal y);
PXreal Floor_safe_gravitise_y(PXreal fY);
void Align_with_floor(_mega *mega);
PXreal Return_true_y(PXreal y);
bool8 On_a_floor(_mega *mega);
// for external routines such as fn_functions
_floor *Fetch_named_floor(const char *name);
_floor *Fetch_floor_number(uint32 num);
PXreal Fetch_floors_volume_height(uint32 num);
uint32 Fetch_floor_number_by_name(const char *name);
uint32 Fetch_number_of_floors() const { return total_floors; }
int32 Project_point_down_through_floors(int32 nX, int32 nY, int32 nZ);
LinkedDataFile *floors; // the floor definition file
private:
uint32 total_floors; // total number of individual floors
uint32 total_heights; // how many unique heights
PXreal heights[MAX_heights]; // list of actual heights
PXreal floor_y_volume[MAX_floors]; // table of depths for floors
};
inline PXreal _floor_world::Fetch_floors_volume_height(uint32 num) { return floor_y_volume[num]; }
inline PXreal _floor_world::Fetch_height(uint32 height) {
if (height >= total_heights) {
Fatal_error("can't get %d height of %d", height, total_heights);
}
return (heights[height]);
}
inline int32 _floor_world::Fetch_total_heights() { return (total_heights); }
inline uint32 _floor_world::Fetch_total_floors() { return (total_floors); }
inline _floor *_floor_world::Fetch_named_floor(const char *name) {
// return a pointer to a named floor to an external routine - most likely a fn_function
return ((_floor *)LinkedDataObject::Fetch_item_by_name(floors, name));
}
inline _floor *_floor_world::Fetch_floor_number(uint32 num) {
// return a pointer to a named floor to an external routine - most likely a fn_function
return ((_floor *)LinkedDataObject::Fetch_item_by_number(floors, num));
}
} // End of namespace ICB
#endif

1512
engines/icb/fn_animation.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,843 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/common/px_rcutypes.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/event_manager.h"
#include "engines/icb/line_of_sight.h"
#include "engines/icb/sound_logic.h"
#include "engines/icb/mission.h"
#define EVENT_FNS_LOG "event_functions_log.txt"
namespace ICB {
// These are to do with the normal events (i.e. not line-of-sight or sound events).
mcodeFunctionReturnCodes fn_register_for_event(int32 &result, int32 *params) { return (MS->fn_register_for_event(result, params)); }
mcodeFunctionReturnCodes fn_unregister_for_event(int32 &result, int32 *params) { return (MS->fn_unregister_for_event(result, params)); }
mcodeFunctionReturnCodes fn_register_object_for_event(int32 &result, int32 *params) { return (MS->fn_register_object_for_event(result, params)); }
mcodeFunctionReturnCodes fn_unregister_object_for_event(int32 &result, int32 *params) { return (MS->fn_unregister_object_for_event(result, params)); }
mcodeFunctionReturnCodes fn_post_event(int32 &result, int32 *params) { return (MS->fn_post_event(result, params)); }
mcodeFunctionReturnCodes fn_post_future_event(int32 &result, int32 *params) { return (MS->fn_post_future_event(result, params)); }
mcodeFunctionReturnCodes fn_post_repeating_event(int32 &result, int32 *params) { return (MS->fn_post_repeating_event(result, params)); }
mcodeFunctionReturnCodes fn_clear_all_events(int32 &result, int32 *params) { return (MS->fn_clear_all_events(result, params)); }
mcodeFunctionReturnCodes fn_check_event_waiting(int32 &result, int32 *params) { return (MS->fn_check_event_waiting(result, params)); }
mcodeFunctionReturnCodes fn_event_check_last_sender(int32 &result, int32 *params) { return (MS->fn_event_check_last_sender(result, params)); }
mcodeFunctionReturnCodes fn_get_last_event_sender_id(int32 &result, int32 *params) { return (MS->fn_get_last_event_sender_id(result, params)); }
mcodeFunctionReturnCodes fn_post_named_event_to_object(int32 &result, int32 *params) { return (MS->fn_post_named_event_to_object(result, params)); }
mcodeFunctionReturnCodes fn_post_named_event_to_object_id(int32 &result, int32 *params) { return (MS->fn_post_named_event_to_object_id(result, params)); }
mcodeFunctionReturnCodes fn_shut_down_event_processing(int32 &result, int32 *params) { return (MS->fn_shut_down_event_processing(result, params)); }
mcodeFunctionReturnCodes fn_is_registered_for_event(int32 &result, int32 *params) { return (MS->fn_is_registered_for_event(result, params)); }
mcodeFunctionReturnCodes fn_is_object_registered_for_event(int32 &result, int32 *params) { return (MS->fn_is_object_registered_for_event(result, params)); }
mcodeFunctionReturnCodes fn_suspend_events(int32 &result, int32 *params) { return (MS->fn_suspend_events(result, params)); }
mcodeFunctionReturnCodes fn_unsuspend_events(int32 &result, int32 *params) { return (MS->fn_unsuspend_events(result, params)); }
// These are to do with line-of-sight.
mcodeFunctionReturnCodes fn_register_for_line_of_sight(int32 &result, int32 *params) { return (MS->fn_register_for_line_of_sight(result, params)); }
mcodeFunctionReturnCodes fn_unregister_for_line_of_sight(int32 &result, int32 *params) { return (MS->fn_unregister_for_line_of_sight(result, params)); }
mcodeFunctionReturnCodes fn_register_object_for_line_of_sight(int32 &result, int32 *params) { return (MS->fn_register_object_for_line_of_sight(result, params)); }
mcodeFunctionReturnCodes fn_unregister_object_for_line_of_sight(int32 &result, int32 *params) { return (MS->fn_unregister_object_for_line_of_sight(result, params)); }
mcodeFunctionReturnCodes fn_can_see(int32 &result, int32 *params) { return (MS->fn_can_see(result, params)); }
mcodeFunctionReturnCodes fn_can_object_see(int32 &result, int32 *params) { return (MS->fn_can_object_see(result, params)); }
mcodeFunctionReturnCodes fn_set_mega_field_of_view(int32 &result, int32 *params) { return (MS->fn_set_mega_field_of_view(result, params)); }
mcodeFunctionReturnCodes fn_set_object_sight_range(int32 &result, int32 *params) { return (MS->fn_set_object_sight_range(result, params)); }
mcodeFunctionReturnCodes fn_set_object_sight_height(int32 &result, int32 *params) { return (MS->fn_set_object_sight_height(result, params)); }
mcodeFunctionReturnCodes fn_line_of_sight_suspend(int32 &result, int32 *params) { return (MS->fn_line_of_sight_suspend(result, params)); }
mcodeFunctionReturnCodes fn_line_of_sight_unsuspend(int32 &result, int32 *params) { return (MS->fn_line_of_sight_unsuspend(result, params)); }
mcodeFunctionReturnCodes fn_line_of_sight_now(int32 &result, int32 *params) { return (MS->fn_line_of_sight_now(result, params)); }
mcodeFunctionReturnCodes fn_can_see_in_dark(int32 &result, int32 *params) { return (MS->fn_can_see_in_dark(result, params)); }
mcodeFunctionReturnCodes fn_mega_never_in_shadow(int32 &result, int32 *params) { return (MS->fn_mega_never_in_shadow(result, params)); }
// These are to do with the logic sound engine.
mcodeFunctionReturnCodes fn_sound_set_hearing_sensitivity(int32 &result, int32 *params) { return (MS->fn_sound_set_hearing_sensitivity(result, params)); }
mcodeFunctionReturnCodes fn_sound_heard_this(int32 &result, int32 *params) { return (MS->fn_sound_heard_this(result, params)); }
mcodeFunctionReturnCodes fn_sound_heard_something(int32 &result, int32 *params) { return (MS->fn_sound_heard_something(result, params)); }
mcodeFunctionReturnCodes fn_sound_new_entry(int32 &result, int32 *params) { return (MS->fn_sound_new_entry(result, params)); }
mcodeFunctionReturnCodes fn_sound_remove_entry(int32 &result, int32 *params) { return (MS->fn_sound_remove_entry(result, params)); }
mcodeFunctionReturnCodes fn_sound_simulate(int32 &result, int32 *params) { return (MS->fn_sound_simulate(result, params)); }
mcodeFunctionReturnCodes fn_sound_get_x(int32 &result, int32 *params) { return (MS->fn_sound_get_x(result, params)); }
mcodeFunctionReturnCodes fn_sound_get_z(int32 &result, int32 *params) { return (MS->fn_sound_get_z(result, params)); }
mcodeFunctionReturnCodes fn_sound_fast_face(int32 &result, int32 *params) { return (MS->fn_sound_fast_face(result, params)); }
mcodeFunctionReturnCodes fn_sound_route_to_near(int32 &result, int32 *params) { return (MS->fn_sound_route_to_near(result, params)); }
mcodeFunctionReturnCodes fn_sound_suspend(int32 &result, int32 *params) { return (MS->fn_sound_suspend(result, params)); }
mcodeFunctionReturnCodes fn_sound_unsuspend(int32 &result, int32 *params) { return (MS->fn_sound_unsuspend(result, params)); }
mcodeFunctionReturnCodes fn_sound_link_floors(int32 &result, int32 *params) { return (MS->fn_sound_link_floors(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_register_for_event(int32 &, int32 *params) {
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work in the event manager.
g_oEventManager->RegisterForEvent(cur_id, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_unregister_for_event(int32 &, int32 *params) {
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work in the event manager.
g_oEventManager->UnregisterForEvent(cur_id, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_register_object_for_event(int32 &, int32 *params) {
uint32 nObjectID;
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Find the target object's ID.
nObjectID = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
// Call the function that does the work in the event manager.
g_oEventManager->RegisterForEvent(nObjectID, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_unregister_object_for_event(int32 &, int32 *params) {
uint32 nObjectID;
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Find the target object's ID.
nObjectID = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
// Call the function that does the work in the event manager.
g_oEventManager->UnregisterForEvent(nObjectID, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_post_event(int32 &, int32 *params) {
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work in the event manager.
g_oEventManager->PostNamedEvent(event_name, cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_post_future_event(int32 &, int32 *params) {
uint32 nTime;
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[0]);
nTime = (uint32)params[1];
g_oEventManager->PostRepeatingEvent(event_name, nTime, 0, nTime);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_post_repeating_event(int32 &, int32 *params) {
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work in the event manager.
g_oEventManager->PostRepeatingEvent(event_name, (uint32)params[1], (uint32)params[2], (uint32)params[3]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_clear_all_events(int32 &, int32 *) {
// Call the function that does the work in the event manager.
g_oEventManager->ClearAllEventsForObject(cur_id);
// Call the function that does the work in the event manager.
g_oSoundLogicEngine->ClearHeardFlag(cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_check_event_waiting(int32 &result, int32 *params) {
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work in the event manager.
result = g_oEventManager->CheckEventWaitingForObject(cur_id, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_event_check_last_sender(int32 &result, int32 *params) {
uint32 nObjectID;
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Find the target object's ID.
nObjectID = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
// Find the sender of the named event.
result = g_oEventManager->DidObjectSendLastNamedEvent(cur_id, nObjectID, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_get_last_event_sender_id(int32 &result, int32 *params) {
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Find the sender of the named event.
result = g_oEventManager->GetIDOfLastObjectToPostEvent(cur_id, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_post_named_event_to_object(int32 &, int32 *params) {
uint32 nTargetID;
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Get ID of target and make sure it is valid.
nTargetID = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
// Post the event.
g_oEventManager->PostNamedEventToObject(event_name, nTargetID, cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_post_named_event_to_object_id(int32 &, int32 *params) {
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Post the event.
g_oEventManager->PostNamedEventToObject(event_name, (uint32)(params[0]), cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_shut_down_event_processing(int32 &, int32 *) {
// Shut down event processing for the object.
g_oEventManager->ShutDownEventProcessingForObject(cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_is_registered_for_event(int32 &result, int32 *params) {
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Make the engine call.
result = g_oEventManager->IsObjectRegisteredForEvent(cur_id, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_is_object_registered_for_event(int32 &result, int32 *params) {
uint32 nObjectID;
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *event_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Get ID of object and make sure it is valid.
nObjectID = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
// Make the engine call.
result = g_oEventManager->IsObjectRegisteredForEvent(nObjectID, event_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_suspend_events(int32 &, int32 *) {
// Make the call to the event manager.
g_oEventManager->SetSuspendFlagForObject(cur_id, TRUE8);
// Must turn off sound events separately.
g_oSoundLogicEngine->SetSuspendedFlag(cur_id, TRUE8);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_unsuspend_events(int32 &, int32 *) {
// Make the call to the event manager.
g_oEventManager->SetSuspendFlagForObject(cur_id, FALSE8);
// Must turn off sound events separately.
g_oSoundLogicEngine->SetSuspendedFlag(cur_id, FALSE8);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_register_for_line_of_sight(int32 &, int32 *params) {
uint32 nObjectID;
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Find the target object's ID.
nObjectID = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
// Now we can make the actual call to the line-of-sight object.
PXTRY
g_oLineOfSight->Subscribe(cur_id, nObjectID);
PXCATCH
Fatal_error("Exception in _line_of_sight::Subscribe()");
PXENDCATCH
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_unregister_for_line_of_sight(int32 &, int32 *params) {
uint32 nObjectID;
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Find the target object's ID.
nObjectID = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
// Now we can make the actual call to the line-of-sight object.
PXTRY
g_oLineOfSight->UnSubscribe(cur_id, nObjectID);
PXCATCH
Fatal_error("Exception in _line_of_sight::UnSubscribe()");
PXENDCATCH
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_register_object_for_line_of_sight(int32 &, int32 *params) {
uint32 nObserverID;
uint32 nTargetID;
const char *observer_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *target_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Find the objects' IDs.
nObserverID = LinkedDataObject::Fetch_item_number_by_name(objects, observer_name);
nTargetID = LinkedDataObject::Fetch_item_number_by_name(objects, target_name);
// Now we can make the actual call to the line-of-sight object.
if ((nTargetID != PX_LINKED_DATA_FILE_ERROR) && (nObserverID != PX_LINKED_DATA_FILE_ERROR)) {
PXTRY
g_oLineOfSight->Subscribe(nObserverID, nTargetID);
PXCATCH
Fatal_error("Exception in _line_of_sight::Subscribe()");
PXENDCATCH
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_unregister_object_for_line_of_sight(int32 &, int32 *params) {
uint32 nObserverID;
uint32 nTargetID;
const char *observer_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *target_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Find the objects' IDs.
nObserverID = LinkedDataObject::Fetch_item_number_by_name(objects, observer_name);
nTargetID = LinkedDataObject::Fetch_item_number_by_name(objects, target_name);
// Now we can make the actual call to the line-of-sight object.
if ((nTargetID != PX_LINKED_DATA_FILE_ERROR) && (nObserverID != PX_LINKED_DATA_FILE_ERROR)) {
PXTRY
g_oLineOfSight->UnSubscribe(nObserverID, nTargetID);
PXCATCH
Fatal_error("Exception in _line_of_sight::UnSubscribe()");
PXENDCATCH
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_can_see(int32 &result, int32 *params) {
uint32 nTargetID;
const char *target_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Find ID of target object.
nTargetID = LinkedDataObject::Fetch_item_number_by_name(objects, target_name);
// Don't call line-of-sight for an invalid ID.
if (nTargetID != PX_LINKED_DATA_FILE_ERROR) {
PXTRY
result = g_oLineOfSight->LineOfSight(cur_id, nTargetID);
PXCATCH
Fatal_error("Exception in _line_of_sight::LineOfSight()");
PXENDCATCH
} else {
result = FALSE8;
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_can_object_see(int32 &result, int32 *params) {
uint32 nObserverID;
uint32 nTargetID;
const char *observer_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *target_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Find the objects' IDs.
nObserverID = LinkedDataObject::Fetch_item_number_by_name(objects, observer_name);
if (nObserverID == PX_LINKED_DATA_FILE_ERROR)
Fatal_error("Object %s not found in fn_can_object_see()", observer_name);
nTargetID = LinkedDataObject::Fetch_item_number_by_name(objects, target_name);
if (nTargetID == PX_LINKED_DATA_FILE_ERROR)
Fatal_error("Object %s not found in fn_can_object_see()", target_name);
// Don't call line-of-sight for invalid IDs.
if ((nTargetID != PX_LINKED_DATA_FILE_ERROR) && (nObserverID != PX_LINKED_DATA_FILE_ERROR)) {
PXTRY
result = g_oLineOfSight->LineOfSight(nObserverID, nTargetID);
PXCATCH
Fatal_error("Exception in _line_of_sight::LineOfSight()");
PXENDCATCH
} else {
result = FALSE8;
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_set_mega_field_of_view(int32 &, int32 *params) {
// Make the call to do the work.
PXTRY
g_oLineOfSight->SetFieldOfView(cur_id, (uint32)(params[0]));
PXCATCH
Fatal_error("Exception in _line_of_sight::SetFieldOfView()");
PXENDCATCH
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_set_object_sight_range(int32 &, int32 *params) {
// Make the call to do the work.
PXTRY
g_oLineOfSight->SetSightRange(cur_id, (uint32)(params[0]));
PXCATCH
Fatal_error("Exception in _line_of_sight::SetSightRange()");
PXENDCATCH
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_set_object_sight_height(int32 &, int32 *params) {
// Make the call to do the work.
PXTRY
g_oLineOfSight->SetSightHeight(cur_id, (uint32)(params[0]));
PXCATCH
Fatal_error("Exception in _line_of_sight::SetSightHeight()");
PXENDCATCH
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_line_of_sight_suspend(int32 &, int32 *) {
// Make the call to the line-of-sight object.
g_oLineOfSight->Suspend(cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_line_of_sight_unsuspend(int32 &, int32 *) {
// Make the call to the line-of-sight object.
g_oLineOfSight->Unsuspend(cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_line_of_sight_now(int32 &result, int32 *params) {
uint32 nTargetID;
const char *target_name = (const char *)MemoryUtil::resolvePtr(params[0]);
nTargetID = LinkedDataObject::Fetch_item_number_by_name(objects, target_name);
if (nTargetID == PX_LINKED_DATA_FILE_ERROR)
Fatal_error("Object %s not found in fn_line_of_sight_now()", target_name);
// Make the call to the line-of-sight object, overriding any height checks.
result = g_oLineOfSight->ObjectToObject(cur_id, nTargetID, LIGHT, 0, (_line_of_sight::ActorEyeMode)params[1], TRUE8);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_can_see_in_dark(int32 &, int32 *params) {
bool8 bOnOff;
// Make the call to the line-of-sight object.
bOnOff = ((int32)params[0] == 0) ? FALSE8 : TRUE8;
g_oLineOfSight->SetCanSeeInDarkFlag(cur_id, bOnOff);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_mega_never_in_shadow(int32 &, int32 *params) {
bool8 bOnOff;
// Make the call to the line-of-sight object.
bOnOff = ((int32)params[0] == 0) ? FALSE8 : TRUE8;
g_oLineOfSight->SetNeverInShadowFlag(cur_id, bOnOff);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_set_hearing_sensitivity(int32 &, int32 *params) {
// Pass call on to the sound logic engine.
g_oSoundLogicEngine->SetHearingSensitivity(cur_id, (int32)params[0]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_heard_something(int32 &result, int32 *) {
// Write the call in the debug file.
Zdebug("fn_sound_heard_something()");
// Get the value from the sound logic engine.
result = g_oSoundLogicEngine->MegaHeardSomething(cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_heard_this(int32 &result, int32 *params) {
const char *sound_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Write the call in the debug file.
Zdebug("fn_sound_heard_this(%s)", sound_name);
// Get the value from the sound logic engine.
result = g_oSoundLogicEngine->MegaHeardThis(cur_id, sound_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_new_entry(int32 &, int32 *params) {
const char *sound_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Write the call in the debug file.
Zdebug("fn_sound_new_entry(%s)", sound_name);
// Pass call on to the sound logic engine.
g_oSoundLogicEngine->AddSubscription(cur_id, sound_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_remove_entry(int32 &, int32 *params) {
const char *sound_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Write the call in the debug file.
Zdebug("fn_sound_remove_entry(%s)", sound_name);
// Pass call on to the sound logic engine.
g_oSoundLogicEngine->RemoveSubscription(cur_id, sound_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_suspend(int32 &, int32 *) {
// Write the call in the debug file.
Zdebug("fn_sound_suspend() called by mega %d", cur_id);
// Turn sound events off
g_oSoundLogicEngine->SetSuspendedFlag(cur_id, TRUE8);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_unsuspend(int32 &, int32 *) {
// Write the call in the debug file.
Zdebug("fn_sound_unsuspend() called by mega %d", cur_id);
// Turn sound events on.
g_oSoundLogicEngine->SetSuspendedFlag(cur_id, FALSE8);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_get_x(int32 &result, int32 *params) {
uint32 nHashedSoundID;
const char *sound_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Pass call on to the sound logic engine.
nHashedSoundID = HashString(sound_name);
result = g_oSoundLogicEngine->GetSoundX(nHashedSoundID);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_get_z(int32 &result, int32 *params) {
uint32 nHashedSoundID;
const char *sound_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Pass call on to the sound logic engine.
nHashedSoundID = HashString(sound_name);
result = g_oSoundLogicEngine->GetSoundZ(nHashedSoundID);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_fast_face(int32 &, int32 *params) {
uint32 nHashedSoundID;
int32 nX, nZ;
const char *sound_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// See if this is the first time this function has been called from script.
if (!L->looping) {
// Work out the hashed name of the sound.
nHashedSoundID = HashString(sound_name);
// Get the coordinates of the sound.
nX = g_oSoundLogicEngine->GetSoundX(nHashedSoundID);
nZ = g_oSoundLogicEngine->GetSoundZ(nHashedSoundID);
// Check that a valid coordinate was found.
if ((nX == SL_UNDEFINED_COORDINATE) || (nZ == SL_UNDEFINED_COORDINATE)) {
// Invalid coordinate, so ignore the script function.
return (IR_CONT);
}
if (Calc_target_pan((PXreal)nX, (PXreal)nZ, M->actor_xyz.x, M->actor_xyz.z)) {
// The mega needs to do a turn.
L->looping = TRUE8;
} else {
// No animated turn required.
return (IR_CONT);
}
}
// We are running an animation to face the sound.
if (M->target_pan) {
// Still animating the turn.
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, (uint32)params[1]);
return (IR_REPEAT);
} else {
// Finished the turn.
L->looping = FALSE8;
// Set back to stand.
L->cur_anim_type = __STAND;
L->anim_pc = 0;
// Calling script can continue.
return (IR_CONT);
}
// I think this is needed to stop PSX warning.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_route_to_near(int32 &result, int32 *params) {
int32 nDeltaX, nDeltaZ;
int32 nX, nZ;
int32 nSquaredDistance;
uint32 nHashedSoundID;
const char *sound_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Work out the hashed name of the sound.
nHashedSoundID = HashString(sound_name);
// Get the coordinates of the sound.
nX = g_oSoundLogicEngine->GetSoundX(nHashedSoundID);
nZ = g_oSoundLogicEngine->GetSoundZ(nHashedSoundID);
// Check that a valid coordinate was found.
if ((nX == SL_UNDEFINED_COORDINATE) || (nZ == SL_UNDEFINED_COORDINATE)) {
// Invalid coordinate, so ignore the script function.
return (IR_CONT);
}
// Work out squared difference between where we are and where we need to be.
nDeltaX = nX - (int32)logic_structs[cur_id]->mega->actor_xyz.x;
nDeltaZ = nZ - (int32)logic_structs[cur_id]->mega->actor_xyz.z;
nSquaredDistance = nDeltaX * nDeltaX + nDeltaZ * nDeltaZ;
if (!L->looping) {
// Don't build a route if mega is already within the required distance.
if (nSquaredDistance < ((int32)params[3] * (int32)params[3])) {
result = TRUE8;
return (IR_CONT);
}
// Not close enough, so we need to build a route.
if (!Setup_route(result, nX, nZ, (int32)params[1], __FULL, TRUE8)) {
return (IR_CONT);
}
}
// Run the route.
if (Process_route()) {
L->looping = 0;
result = TRUE8;
return (IR_CONT);
}
if (nSquaredDistance < ((int32)params[3] * (int32)params[3])) {
M->m_main_route.dist_left = FLOAT_ZERO;
M->m_main_route.current_position = (M->m_main_route.total_points - 1);
}
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_link_floors(int32 &, int32 *params) {
const char *sound_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *sound_name2 = (const char *)MemoryUtil::resolvePtr(params[1]);
Tdebug(EVENT_FNS_LOG, "fn_sound_link_floors( %s, %s )", sound_name, sound_name2);
// Make the call to the sound logic engine.
g_oSoundLogicEngine->LinkFloorsForSoundEvents(sound_name, sound_name2);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_sound_simulate(int32 &, int32 *) { return (IR_CONT); }
} // End of namespace ICB

79
engines/icb/fn_fx.cpp Normal file
View File

@@ -0,0 +1,79 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/debug.h"
#include "engines/icb/mission.h"
#include "engines/icb/global_objects.h"
namespace ICB {
#define DEFAULT_WIDESCREEN_SPEED_ON 6
#define DEFAULT_WIDESCREEN_MODE_ON 0
#define DEFAULT_WIDESCREEN_SPEED_OFF 6
#define DEFAULT_WIDESCREEN_MODE_OFF 0
mcodeFunctionReturnCodes fx_widescreen(int32 &, int32 *params) {
// fx_narrow_screen(mode,0,0,0,target,6
// where mode is 0 for on and 2 for off
// where target is 27% for on and 0% for off
int32 p[6] = {DEFAULT_WIDESCREEN_MODE_OFF, 0, 0, 0, 0, DEFAULT_WIDESCREEN_SPEED_OFF};
// if on alter arguments 0 (mode) and 4 (percent)
if (params[0]) {
p[0] = DEFAULT_WIDESCREEN_MODE_ON; // scroll on
p[4] = 27; // 27% is 32 pixels off top and bottom
p[5] = DEFAULT_WIDESCREEN_SPEED_ON; // speed
}
int32 ret;
return MS->fx_narrow_screen(ret, p);
}
mcodeFunctionReturnCodes _simple_fx(int32 mode, int32 toFrom, int32 fr, int32 fg, int32 fb, int32 r, int32 g, int32 b, int32 cycles) {
// fx_generic_fade(mode,onOff,0,0,0,r,g,b,cycles
// note from colour is always <0,0,0>
int32 p[9] = {mode, toFrom, fr, fg, fb, r, g, b, cycles};
int32 ret;
return MS->fx_generic_fade(ret, p);
}
// take <r,g,b> and cycles
mcodeFunctionReturnCodes fx_brighten_to(int32 &, int32 *p) { return _simple_fx(0, 1, 0, 0, 0, p[0], p[1], p[2], p[3]); }
mcodeFunctionReturnCodes fx_brighten_from(int32 &, int32 *p) { return _simple_fx(0, 0, 0, 0, 0, p[0], p[1], p[2], p[3]); }
mcodeFunctionReturnCodes fx_darken_to(int32 &, int32 *p) { return _simple_fx(1, 1, 0, 0, 0, p[0], p[1], p[2], p[3]); }
mcodeFunctionReturnCodes fx_darken_from(int32 &, int32 *p) { return _simple_fx(1, 0, 0, 0, 0, p[0], p[1], p[2], p[3]); }
mcodeFunctionReturnCodes fx_fade_to(int32 &, int32 *p) { return _simple_fx(2, 1, 0, 0, 0, p[0], p[1], p[2], p[3]); }
mcodeFunctionReturnCodes fx_fade_from(int32 &, int32 *p) { return _simple_fx(2, 0, 0, 0, 0, p[0], p[1], p[2], p[3]); }
// blend function takes <r,g,b> -> <r,g,b> and cycles
mcodeFunctionReturnCodes fx_blend(int32 &, int32 *p) { return _simple_fx(3, 1, p[0], p[1], p[2], p[3], p[4], p[5], p[6]); }
} // End of namespace ICB

222
engines/icb/fn_fx_pc.cpp Normal file
View File

@@ -0,0 +1,222 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/debug.h"
#include "engines/icb/mission.h"
#include "engines/icb/global_objects.h"
namespace ICB {
mcodeFunctionReturnCodes fx_narrow_screen(int32 &result, int32 *params) { return (MS->fx_narrow_screen(result, params)); }
mcodeFunctionReturnCodes fx_generic_fade(int32 &result, int32 *params) { return (MS->fx_generic_fade(result, params)); }
mcodeFunctionReturnCodes _game_session::fx_narrow_screen(int32 &, int32 *params) {
/* Parameters */
int32 mode = params[0]; // border mode
int32 red = params[1]; // red component of cover
int32 green = params[2]; // green component of cover
int32 blue = params[3]; // blue component of cover
int32 percent = params[4]; // 0 - 100 percentage screen to cover
int32 cycles = params[5]; // number of cycles to shirnk over
/* Function Storage */
static int32 heightStep = 0;
static int32 alphaStep = 0;
static int32 cycleCount = 0;
// Get access to the border rectangle
LRECT &border = surface_manager->BorderRect();
// Check if there is a set loaded. If not we want to ignore the cycles param
if (!MSS.OK())
cycles = 1;
// Calculate the fxtarget screen coverage
int32 fxtarget = (480 * percent) / 200;
if (cycleCount == 0) {
// First time through
// Set the border colour
surface_manager->BorderRed() = (uint8)red;
surface_manager->BorderGreen() = (uint8)green;
surface_manager->BorderBlue() = (uint8)blue;
// Semi-non-persistence(ish)... If percentage is not 0 make sure we start from 0
if (percent) {
border.top = 0;
border.bottom = SCREEN_DEPTH;
surface_manager->BorderAlpha() = 0;
} else
surface_manager->BorderAlpha() = 255;
// Calculate the per cycle height step
heightStep = (cycles) ? (fxtarget - border.top) / cycles : fxtarget;
// Calculate alpha step
alphaStep = (cycles) ? 255 / cycles : 255;
// Check if we are fading out
if (percent == 0)
alphaStep = 0 - alphaStep;
// Mode 0 has no fade so set alpha to solid
if (mode == 0) { // Solid Colour
alphaStep = 0;
surface_manager->BorderAlpha() = 255;
}
if (mode == 2) { // Just Fade no shrink so set height step to 0
heightStep = 0;
if (percent) {
border.top = fxtarget;
border.bottom = SCREEN_DEPTH - fxtarget;
}
}
// Set the mode
surface_manager->BorderMode() = mode;
// Check we actually need to move the borders or fade the screen
if (heightStep == 0 && alphaStep == 0)
return (IR_CONT);
}
// Check if we have reached the specified border size
if (cycleCount == cycles) {
cycleCount = 0;
if (percent) {
// We are leaving the screen with borders of one sort or another
// So stop blending and switch to solid borders
surface_manager->BorderMode() = 0;
} else {
// We were removing the borders, so stop drawing them now
border.top = 0;
border.bottom = SCREEN_DEPTH;
}
return (IR_CONT);
}
// Check we aren't going to over step the borders
if (abs(fxtarget - border.top) <= abs(heightStep)) {
border.bottom -= fxtarget - border.top;
border.top = fxtarget;
} else {
// Move the borders
border.top += heightStep;
border.bottom -= heightStep;
}
// Check the alpha isn't going to go too far
if ((alphaStep + surface_manager->BorderAlpha()) > 255) {
surface_manager->BorderAlpha() = (uint8)255;
} else if ((alphaStep + surface_manager->BorderAlpha()) < 0) {
surface_manager->BorderAlpha() = (uint8)0;
} else {
surface_manager->BorderAlpha() = (uint8)(alphaStep + surface_manager->BorderAlpha());
}
cycleCount++;
return (IR_REPEAT);
}
// the full monty effect, fx_generic_fade(mode (0,1,2), on/off, r, g, b, cycles)
// where mode is 0-brighten, 1-darken, 2-fade
// where on/off is equiverlant to to/from
mcodeFunctionReturnCodes _game_session::fx_generic_fade(int32 &, int32 *params) {
int32 mode = params[0];
int32 onOff = params[1];
int32 fromRed = params[2];
int32 fromGreen = params[3];
int32 fromBlue = params[4];
int32 toRed = params[5];
int32 toGreen = params[6];
int32 toBlue = params[7];
int32 cycles = params[8];
/* Function Storage */
static int32 alphaStep = 0;
// Is this the first time through ?
if (alphaStep == 0) {
// First time through
alphaStep = (cycles) ? 255 / cycles : 255;
// Set the colour components
surface_manager->FadeFromRed() = (uint8)fromRed;
surface_manager->FadeFromGreen() = (uint8)fromGreen;
surface_manager->FadeFromBlue() = (uint8)fromBlue;
surface_manager->FadeToRed() = (uint8)toRed;
surface_manager->FadeToGreen() = (uint8)toGreen;
surface_manager->FadeToBlue() = (uint8)toBlue;
// Set the initial alpha value
if (onOff)
surface_manager->FadeAlpha() = 0; // Fading in
else
surface_manager->FadeAlpha() = 255; // Fading out
// Set the fade mode
surface_manager->FadeMode() = mode + 1;
}
// Increment / Decrement the alpha value
int32 newAlpha = surface_manager->FadeAlpha();
if (onOff) {
// Fading in
newAlpha += alphaStep;
} else {
// Fading out
newAlpha -= alphaStep;
}
// Check the limits
if (newAlpha <= 0) {
// Finished fade out
surface_manager->FadeMode() = 0;
surface_manager->FadeAlpha() = 0;
alphaStep = 0;
return (IR_CONT);
}
if (newAlpha >= 255) {
// Finished fade in
surface_manager->FadeAlpha() = 255;
alphaStep = 0;
return (IR_CONT);
}
surface_manager->FadeAlpha() = (uint8)newAlpha;
return (IR_REPEAT);
}
} // End of namespace ICB

View File

@@ -0,0 +1,324 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/icb.h"
#include "engines/icb/common/px_rcutypes.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/mission.h"
#include "engines/icb/remora.h"
#include "engines/icb/text_sprites.h"
#include "engines/icb/icon_list_manager.h"
namespace ICB {
// These are general icon list functions.
mcodeFunctionReturnCodes fn_is_carrying(int32 &result, int32 *params) { return (MS->fn_is_carrying(result, params)); }
mcodeFunctionReturnCodes fn_carrying_how_many(int32 &result, int32 *params) { return (MS->fn_carrying_how_many(result, params)); }
mcodeFunctionReturnCodes fn_is_holding(int32 &result, int32 *params) { return (MS->fn_is_holding(result, params)); }
mcodeFunctionReturnCodes fn_item_held(int32 &result, int32 *params) { return (MS->fn_item_held(result, params)); }
mcodeFunctionReturnCodes fn_drop(int32 &result, int32 *params) { return (MS->fn_drop(result, params)); }
mcodeFunctionReturnCodes fn_reset_icon_list(int32 &result, int32 *params) { return (MS->fn_reset_icon_list(result, params)); }
mcodeFunctionReturnCodes fn_add_icon_to_icon_list(int32 &result, int32 *params) { return (MS->fn_add_icon_to_icon_list(result, params)); }
mcodeFunctionReturnCodes fn_remove_icon_from_icon_list(int32 &result, int32 *params) { return (MS->fn_remove_icon_from_icon_list(result, params)); }
mcodeFunctionReturnCodes fn_interact_choose(int32 &result, int32 *params) { return (MS->fn_interact_choose(result, params)); }
mcodeFunctionReturnCodes fn_destroy_icon_list(int32 &result, int32 *params) { return (MS->fn_destroy_icon_list(result, params)); }
// These two are wrappers for dealing with the inventory (save having to pass in the name of the inventory icon list).
mcodeFunctionReturnCodes fn_add_inventory_item(int32 &result, int32 *params) { return (MS->fn_add_inventory_item(result, params)); }
mcodeFunctionReturnCodes fn_remove_inventory_item(int32 &result, int32 *params) { return (MS->fn_remove_inventory_item(result, params)); }
// These are wrappers for handling functions to do with ammo and health packs.
mcodeFunctionReturnCodes fn_add_medipacks(int32 &result, int32 *params) { return (MS->fn_add_medipacks(result, params)); }
mcodeFunctionReturnCodes fn_use_medipacks(int32 &result, int32 *params) { return (MS->fn_use_medipacks(result, params)); }
mcodeFunctionReturnCodes fn_add_ammo_clips(int32 &result, int32 *params) { return (MS->fn_add_ammo_clips(result, params)); }
mcodeFunctionReturnCodes fn_use_ammo_clips(int32 &result, int32 *params) { return (MS->fn_use_ammo_clips(result, params)); }
mcodeFunctionReturnCodes fn_shutdown_inventory(int32 &result, int32 *params) { return (MS->fn_shutdown_inventory(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_is_carrying(int32 &result, int32 *params) {
const char *item_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work.
result = g_oIconListManager->Carrying(ICON_LIST_INVENTORY, item_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_carrying_how_many(int32 &result, int32 *params) {
const char *item_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work.
result = g_oIconListManager->CarryingHowMany(ICON_LIST_INVENTORY, item_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_item_held(int32 &result, int32 *) {
// Call the function that does the work.
result = g_oIconListManager->ItemHeld();
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_is_holding(int32 &result, int32 *params) {
const char *item_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work.
result = g_oIconListManager->Holding(item_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_drop(int32 &, int32 *) {
// Call the function that does the work.
g_oIconListManager->Drop();
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_add_inventory_item(int32 &, int32 *params) {
char pcIconPath[ENGINE_STRING_LEN];
const char *item_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work.
g_oIconListManager->AddIconToList(ICON_LIST_INVENTORY, item_name);
// Preload the icon for PSX smoothing.
Common::sprintf_s(pcIconPath, ICON_PATH);
g_oIconMenu->PreloadIcon(pcIconPath, item_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remove_inventory_item(int32 &, int32 *params) {
const char *item_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the function that does the work.
g_oIconListManager->RemoveIconFromList(ICON_LIST_INVENTORY, item_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_add_medipacks(int32 &result, int32 *params) {
if (g_icb->getGameType() == GType_ELDORADO) {
result = 0;
return IR_CONT;
}
char pcIconPath[ENGINE_STRING_LEN];
bool8 bFlashIcons;
// can only carry 2
if (g_mission->num_medi >= 2) {
result = 1; // not given
return IR_CONT;
}
// Type-safe convert the integer second parameter to a bool8.
bFlashIcons = ((int32)params[1] == 0) ? FALSE8 : TRUE8;
// Call the function that does the work.
player.AddMediPacks(1, bFlashIcons);
// Preload the icon for PSX smoothing.
Common::sprintf_s(pcIconPath, ICON_PATH);
g_oIconMenu->PreloadIcon(pcIconPath, ARMS_HEALTH_NAME);
// Calling script can continue.
result = 0; // given
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_use_medipacks(int32 &, int32 *params) {
// Remove the medipacks.
player.UseMediPacks((uint32)params[0]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_add_ammo_clips(int32 &result, int32 *params) {
if (g_icb->getGameType() == GType_ELDORADO) {
return IR_CONT;
}
char pcIconPath[ENGINE_STRING_LEN];
bool8 bFlashIcons;
// Type-safe convert the integer second parameter to a bool8.
bFlashIcons = ((int32)params[1] == 0) ? FALSE8 : TRUE8;
// how many we got already?
int32 clips = player.GetNoAmmoClips();
// work out max we can carry minus what we have
int32 can_take = player.GetMaxClips() - clips;
if (can_take >= params[0]) { // we have room for all we're being given
// Call the function that does the work.
player.AddAmmoClips((uint32)params[0], bFlashIcons);
result = 0;
} else { // can't take all that were offered
// Call the function that does the work.
player.AddAmmoClips(can_take, bFlashIcons); // take max we can take
result = params[0] - can_take; // leave behind those we can't take
}
// Preload the icon for PSX smoothing.
Common::sprintf_s(pcIconPath, ICON_PATH);
g_oIconMenu->PreloadIcon(pcIconPath, ARMS_AMMO_NAME);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_use_ammo_clips(int32 &, int32 *params) {
// Remove the medipacks.
player.UseAmmoClips((uint32)params[0]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_add_icon_to_icon_list(int32 &, int32 *params) {
char pcIconPath[ENGINE_STRING_LEN];
const char *list_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Call the engine function that does the work.
g_oIconListManager->AddIconToList(list_name, icon_name);
// Preload the icon for PSX smoothing.
Common::sprintf_s(pcIconPath, ICON_PATH);
g_oIconMenu->PreloadIcon(pcIconPath, icon_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remove_icon_from_icon_list(int32 &, int32 *params) {
const char *list_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Call the engine function that does the work.
g_oIconListManager->RemoveIconFromList(list_name, icon_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_reset_icon_list(int32 &, int32 *params) {
const char *list_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Make the call to the Remora object.
g_oIconListManager->ResetList(list_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_destroy_icon_list(int32 &, int32 *params) {
const char *list_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Call the engine function that does the work.
g_oIconListManager->DestroyList(list_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_interact_choose(int32 &, int32 *params) {
_input *psInputState;
const char *list_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Check to see if we are already looping
if (!L->looping) {
// There has to be a current interact object.
if (!MS->player.Fetch_player_interact_status())
Fatal_error("fn_interact_choose() can only be called from an interact script");
// Mark the fact that we are now looping.
L->looping = 1;
// Bring up the icon menu.
g_oIconListManager->ActivateIconMenu(list_name, TRUE8, FALSE8);
MS->player.Push_control_mode(ACTOR_RELATIVE);
// Must call this function again as long as this interface is active.
return (IR_REPEAT);
} else {
// This is a subsequent call to this function. Cycle the icon menu logic.
MS->player.Update_input_state();
psInputState = MS->player.Fetch_input_state();
if (g_oIconMenu->CycleIconMenu(*psInputState)) {
// Menu still active, so we must continue cycling its logic next time through.
return (IR_REPEAT);
} else {
// A selection has been made or the menu has been cancelled. Calling script can now continue.
MS->player.Pop_control_mode();
L->looping = 0;
return (IR_CONT);
}
}
// To fix a GCC compiler warning.
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_shutdown_inventory(int32 &, int32 *) {
g_oIconMenu->CloseDownIconMenu();
// Calling script can continue.
return IR_CONT;
}
} // End of namespace ICB

573
engines/icb/fn_interact.cpp Normal file
View File

@@ -0,0 +1,573 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/p4.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_linkeddatafile.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/mission.h"
#include "engines/icb/session.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/debug.h"
#include "engines/icb/player.h"
#include "engines/icb/direct_input.h"
#include "engines/icb/barriers.h"
#include "engines/icb/common/px_route_barriers.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/animation_mega_set.h"
#include "engines/icb/mission.h"
#include "engines/icb/common/px_scriptengine.h"
#include "engines/icb/session.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/res_man.h"
#include "engines/icb/floors.h"
namespace ICB {
mcodeFunctionReturnCodes fn_generic_prop_interact(int32 &result, int32 *params) { return (MS->fn_generic_prop_interact(result, params)); }
mcodeFunctionReturnCodes fn_custom_prop_interact(int32 &result, int32 *params) { return (MS->fn_custom_prop_interact(result, params)); }
mcodeFunctionReturnCodes fn_is_there_interact_object(int32 &result, int32 *params) { return (MS->fn_is_there_interact_object(result, params)); }
mcodeFunctionReturnCodes fn_get_interact_object_id(int32 &result, int32 *params) { return (MS->fn_get_interact_object_id(result, params)); }
mcodeFunctionReturnCodes fn_is_object_interact_object(int32 &result, int32 *params) { return (MS->fn_is_object_interact_object(result, params)); }
mcodeFunctionReturnCodes fn_register_for_auto_interaction(int32 &result, int32 *params) { return (MS->fn_register_for_auto_interaction(result, params)); }
mcodeFunctionReturnCodes fn_route_to_custom_prop_interact(int32 &result, int32 *params) { return (MS->fn_route_to_custom_prop_interact(result, params)); }
mcodeFunctionReturnCodes fn_route_to_generic_prop_interact(int32 &result, int32 *params) { return (MS->fn_route_to_generic_prop_interact(result, params)); }
mcodeFunctionReturnCodes fn_sony_door_interact(int32 &result, int32 *params) { return (MS->fn_sony_door_interact(result, params)); }
mcodeFunctionReturnCodes fn_unregister_for_auto_interaction(int32 &result, int32 *params) { return (MS->fn_unregister_for_auto_interaction(result, params)); }
mcodeFunctionReturnCodes fn_wandering_custom_prop_interact(int32 &result, int32 *params) { return (MS->fn_wandering_custom_prop_interact(result, params)); }
mcodeFunctionReturnCodes fn_wandering_generic_prop_interact(int32 &result, int32 *params) { return (MS->fn_wandering_generic_prop_interact(result, params)); }
#define SONY_DOOR_STEP_BACK_DIST ((50 * REAL_ONE) * (50 * REAL_ONE))
#define SONY_DOOR_PRESS_DIST ((100 * REAL_ONE) * (100 * REAL_ONE))
mcodeFunctionReturnCodes _game_session::fn_set_interacting(int32 &, int32 *params) {
// set interting and id of target
// so we can run prop interact type animation functions outside of an interaction
// params 0 name of target
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
uint32 id = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
if (id == 0xffffffff)
Fatal_error("fn_set_interacting - illegal object [%s]", object_name);
M->target_id = id;
M->interacting = TRUE8;
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_clear_interacting(int32 &, int32 *) {
M->interacting = FALSE8;
return (IR_STOP); // this is vital as currently the object will be
}
mcodeFunctionReturnCodes _game_session::fn_route_to_generic_prop_interact(int32 &result, int32 *params) {
// WALK-TO interact with a prop BUT DOESN'T play a generic animation
// will call a trigger script if finds marker and script
// params 0 name of generic animation
if (L->looping == 2) {
L->looping = FALSE8;
L->pan = logic_structs[M->target_id]->prop_interact_pan;
// force to stand, frame 0, restore pre anim coordinates
POST_INTERACTION // fix coords and set to stand
return (IR_CONT);
}
return (Core_prop_interact(result, params, FALSE8, FALSE8));
}
mcodeFunctionReturnCodes _game_session::fn_route_to_custom_prop_interact(int32 &result, int32 *params) {
// WALK-TO interact with a prop BUT DOESN'T play a custom non generic animation
// then return to script
// params 0 name of custom animation
if (L->looping == 2) {
L->looping = FALSE8;
L->pan = logic_structs[M->target_id]->prop_interact_pan;
// force to stand, frame 0, restore pre anim coordinates
POST_INTERACTION // fix coords and set to stand
Reset_cur_megas_custom_type();
return (IR_CONT);
}
return (Core_prop_interact(result, params, TRUE8, FALSE8));
}
mcodeFunctionReturnCodes _game_session::fn_sony_door_interact(int32 &result, int32 *params) {
// special door situation whereby we are passed the names of two buttons and we need to work out which one to interact with
// params 0 name of first button
// 1 name of second button
// 2 number of buttons
PXfloat new_pan, diff;
uint32 id;
uint32 but_floor;
const char *button1_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *button2_name = (const char *)MemoryUtil::resolvePtr(params[1]);
if ((!params[2]) || (params[2] > 2))
Fatal_error("fn_sony_door_interact - %d is illegal number of buttons, can be 1 or 2", params[2]);
result = FALSE8; // no button was pressed
if (!L->looping) {
// work out which button to interact with
id = LinkedDataObject::Fetch_item_number_by_name(objects, button1_name);
if (id == 0xffffffff)
Fatal_error("fn_sony_door_interact - illegal object [%s]", button1_name);
but_floor = floor_def->Return_floor_rect(logic_structs[id]->prop_xyz.x, logic_structs[id]->prop_xyz.z, M->actor_xyz.y, 0);
// angle
new_pan = logic_structs[id]->prop_interact_pan; // get targets pan
// get difference between the two
diff = L->pan - new_pan;
// correct
if (diff > HALF_TURN)
diff -= FULL_TURN;
else if (diff < -HALF_TURN)
diff += FULL_TURN;
if ((L->owner_floor_rect == but_floor) && (PXfabs(diff) < (FULL_TURN / 5))) { // 36 deg = +/- 18 deg
// facing the same so this must be the button
M->target_id = id; // change the target
if (prop_interact_dist < SONY_DOOR_STEP_BACK_DIST)
M->reverse_route = TRUE8;
result = TRUE8; // button 1
} else {
// wanst button 1 - so do nothing if that was only button
if (params[2] == 1) {
return IR_CONT;
}
// there is another button so lets take a look to see it is named correctly
id = LinkedDataObject::Fetch_item_number_by_name(objects, button2_name);
if (id == 0xffffffff)
Fatal_error("fn_sony_door_interact - illegal object [%s]", button2_name);
but_floor = floor_def->Return_floor_rect(logic_structs[id]->prop_xyz.x, logic_structs[id]->prop_xyz.z, M->actor_xyz.y, 0);
if (L->owner_floor_rect != but_floor)
return IR_CONT;
M->target_id = id; // change the target
if (prop_interact_dist < SONY_DOOR_STEP_BACK_DIST)
M->reverse_route = TRUE8;
result = TRUE8; // button 2
}
}
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_custom_prop_interact(int32 &result, int32 *params) {
// interact with a prop and play a custom non generic animation
return (Core_prop_interact(result, params, TRUE8, TRUE8));
}
mcodeFunctionReturnCodes _game_session::fn_generic_prop_interact(int32 &result, int32 *params) {
// interact with a prop and play a generic animation
// will call a trigger script if finds marker and script
// params 0 name of generic animation
return (Core_prop_interact(result, params, FALSE8, TRUE8));
}
mcodeFunctionReturnCodes _game_session::fn_wandering_custom_prop_interact(int32 &result, int32 *params) {
// interact with a prop and play a custom non generic animation
return (Core_prop_interact(result, params, TRUE8, FALSE8));
}
mcodeFunctionReturnCodes _game_session::fn_wandering_generic_prop_interact(int32 &result, int32 *params) {
// interact with a prop and play a generic animation
// will call a trigger script if finds marker and script
// params 0 name of generic animation
return (Core_prop_interact(result, params, FALSE8, FALSE8));
}
mcodeFunctionReturnCodes _game_session::Core_prop_interact(int32 & /*result*/, int32 *params, bool8 custom, bool8 coord_correction) {
//bool8 initial_turn;
bool8 res = FALSE8;
__mega_set_names anim;
PXreal destx, destz;
PXfloat diff;
int32 retval;
PXreal sub1, sub2, len, len2;
uint32 j;
// looping 0 init route
// 1 process route
// 2 init turn to pan
// 3 async wait
// 4 play target anim
// 5
const char *anim_name = nullptr;
if (params && params[0]) {
anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
}
// set up first time in
if (!L->looping) {
// setup autoroute to coordinate
if (!custom) {
Zdebug("calc *generic* target anim [%s]", anim_name);
// get anim type
res = I->Find_anim_type(&anim, anim_name);
if (!res)
Fatal_error("Core_prop_interact can't indentify animation %s", anim_name);
if (!I->IsAnimTable(anim))
Fatal_error("Core_prop_interact finds [%s] doesn't have a [%s] animation", CGameObject::GetName(object), params[0]);
} else {
Zdebug("calc *custom* target anim [%s]", anim_name);
I->Init_custom_animation(anim_name);
anim = __NON_GENERIC;
}
// start psx asyncing the anim - may already be doing so if scripts are written properly!
if (rs_anims->Res_open(I->get_info_name(anim), I->info_name_hash[anim], I->base_path, I->base_path_hash) == nullptr)
return IR_REPEAT;
// we are now looping, having done the init
L->looping = 1;
// calculate the coordinate
Compute_target_interaction_coordinate(anim, &destx, &destz); // uses target_id to derive initial target coord
// save target coord for later post animation correction
M->target_xyz.x = destx;
M->target_xyz.z = destz;
// first lets see if we are really quite close to the interact coordinate - if we are we'll snap
sub1 = (PXreal)(destx - L->mega->actor_xyz.x);
sub2 = (PXreal)(destz - L->mega->actor_xyz.z);
len = (PXreal)((sub1 * sub1) + (sub2 * sub2)); // dist
if (len < (35 * 35)) {
L->mega->actor_xyz.x = destx;
L->mega->actor_xyz.z = destz;
L->looping = 2;
return (IR_REPEAT);
}
// lets see if the interact coordinate is further away than we are - which is bad news
// first, our coordinate to the prop
sub1 = (PXreal)(logic_structs[M->target_id]->prop_xyz.x - L->mega->actor_xyz.x);
sub2 = (PXreal)(logic_structs[M->target_id]->prop_xyz.z - L->mega->actor_xyz.z);
len = (PXreal)((sub1 * sub1) + (sub2 * sub2)); // dist
// second, the interact point to the prop
sub1 = (PXreal)(destx - logic_structs[M->target_id]->prop_xyz.x);
sub2 = (PXreal)(destz - logic_structs[M->target_id]->prop_xyz.z);
len2 = (PXreal)((sub1 * sub1) + (sub2 * sub2)); // dist
M->m_main_route.___init();
// set motion type
if ((len2 > len) || (M->reverse_route == TRUE8)) { // if further away OR already set to reverse - must have been by fn-sony-door
M->m_main_route.request_form.anim_type = __STEP_BACKWARD;
M->reverse_route = TRUE8;
//initial_turn = FALSE8;
} else {
//initial_turn = TRUE8;
if (M->motion == __MOTION_WALK)
M->m_main_route.request_form.anim_type = __WALK;
else
M->m_main_route.request_form.anim_type = __RUN; // form.anim_type=__RUN;
}
// new route do prepare a route request form!
// initial x,z
M->m_main_route.request_form.initial_x = M->actor_xyz.x;
M->m_main_route.request_form.initial_z = M->actor_xyz.z;
// target x,z
M->m_main_route.request_form.dest_x = (PXreal)destx;
M->m_main_route.request_form.dest_z = (PXreal)destz;
Zdebug("PLAYER INTERACT to %3.2f,%3.2f from %3.2f,%3.2f", destx, destz, M->actor_xyz.x, M->actor_xyz.z);
// need characters y coordinate also
M->m_main_route.request_form.character_y = M->actor_xyz.y;
// this function attempts to finish on stand
M->m_main_route.request_form.finish_on_null_stand = TRUE8;
M->m_main_route.request_form.finish_on_stand = FALSE8;
// set type
M->m_main_route.request_form.rtype = ROUTE_points_only;
// now log and create the initial route
// set a barrier mask :(
session_barriers->Set_route_barrier_mask((int32)destx - 500, (int32)destx + 500, (int32)destz - 500, (int32)destz + 500);
Create_initial_route(__FULL);
session_barriers->Clear_route_barrier_mask();
// only one of these per cycle - we may have cheated and done a second route here but at least we can stop another if we
// were first
Set_router_busy();
// if the route could not be built
if (M->m_main_route.request_form.error == __ROUTE_REQUEST_PRIM_FAILED) {
Create_initial_route(__LASER); // lets get out of this the easy way!
}
// we may not actually need a route if we are very close
if (M->m_main_route.request_form.error == __RR_NO_ROUTE_REQUIRED) {
Zdebug("skipping route");
L->looping = 2; // bypass the route
return (IR_REPEAT);
}
}
// routing
if (L->looping == 1) {
if (Process_route()) {
// not looping any longer
// set to turn phase
L->looping = 2;
return (IR_REPEAT);
}
}
// set up auto turning ready for anim play
if (L->looping == 2) {
diff = logic_structs[M->target_id]->prop_interact_pan - L->pan;
// work out which way to turn
if (diff > HALF_TURN)
diff -= FULL_TURN;
else if (diff < -HALF_TURN)
diff += FULL_TURN;
// diff is now the distance to turn by and its sign denotes direction
if (diff < FLOAT_ZERO)
M->turn_dir = 0; // right
else
M->turn_dir = 1; // left
M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
M->auto_target_pan = logic_structs[M->target_id]->prop_interact_pan; // actual target which we may clip to
L->auto_display_pan = L->pan; // start where we currently are
L->auto_panning = TRUE8;
L->looping = 3; // go straight to play anim
return (IR_REPEAT);
}
// check anim in memory
if (L->looping == 3) {
if (custom)
anim = __NON_GENERIC;
else
anim = Fetch_generic_anim_from_ascii(anim_name);
// in memory yet?
if (rs_anims->Res_open(I->get_info_name(anim), I->info_name_hash[anim], I->base_path, I->base_path_hash)) {
L->cur_anim_type = anim;
L->anim_pc = 0;
L->looping = 4; // go straight to play anim
}
return IR_REPEAT;
}
// running target animation
if (L->looping == 4) {
// get animation
PXanim *pAnim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
// last frame is currently displayed?
if ((int32)(L->anim_pc + M->anim_speed) >= (pAnim->frame_qty - 1)) {
L->looping = FALSE8;
M->reverse_route = FALSE8;
// force to stand, frame 0
if (coord_correction) {
POST_INTERACTION // fix coords and set to stand
} else { // was a wandering finish-where-we-finish interaction
L->cur_anim_type = __STAND;
L->anim_pc = 0;
}
Reset_cur_megas_custom_type();
return (IR_CONT);
}
// shift character and frame forward by the amount appropriate
if (!MS->Easy_frame_and_motion(L->cur_anim_type, 0, M->anim_speed)) {
L->looping = FALSE8;
M->reverse_route = FALSE8;
// force to stand, frame 0, restore pre anim coordinates
if (coord_correction) {
POST_INTERACTION // fix coords and set to stand
} else {
L->cur_anim_type = __STAND;
L->anim_pc = 0;
}
Reset_cur_megas_custom_type();
return (IR_CONT);
}
// is the interact marker on this frame ?
for (j = 0; j < M->anim_speed; j++) {
PXframe *frame = PXFrameEnOfAnim(L->anim_pc + j, pAnim);
if ((frame->marker_qty > INT_POS) && (INT_TYPE == (PXmarker_PSX_Object::GetType(&frame->markers[INT_POS])))) {
// run the trigger anim
if (!MS->Call_socket(M->target_id, "trigger", &retval)) {
Message_box("[%s] interact marker but no trigger script", (const char *)L->GetName());
Message_box("anim %s Target ID %d [%s]", master_anim_name_table[L->cur_anim_type].name, M->target_id, Fetch_object_name(M->target_id));
}
break; // done it
}
}
}
// not finished, so see you next cycle
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_is_there_interact_object(int32 &result, int32 *) {
// return yes or no for whether or not an interact object exists
result = player.Fetch_player_interact_status();
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_get_interact_object_id(int32 &result, int32 *) {
// return yes or no for whether or not an interact object exists
result = player.Fetch_player_interact_id();
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_is_object_interact_object(int32 &result, int32 *params) {
// return yes or no for whether or not an interact object exists
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
uint32 id = LinkedDataObject::Fetch_item_number_by_name(objects, object_name);
if (id == 0xffffffff)
Fatal_error("fn_is_object_interact_object - object [%s] does not exist", object_name);
if (id == player.Fetch_player_interact_id())
result = TRUE8;
else
result = FALSE8;
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_unregister_for_auto_interaction(int32 &, int32 *) {
// as the name says - for stairs, session joins, etc.
uint32 j;
for (j = 0; j < MAX_auto_interact; j++) {
if (auto_interact_list[j] == (uint8)(cur_id + 1)) {
Tdebug("auto_interact.txt", "- [%s] %d", CGameObject::GetName(object), j);
auto_interact_list[j] = 0; // slot not empty
return IR_CONT;
}
}
Fatal_error("fn_unregister_for_auto_interaction can't unregister non registered object [%s]", CGameObject::GetName(object));
return IR_CONT;
}
mcodeFunctionReturnCodes _game_session::fn_register_for_auto_interaction(int32 &, int32 *) {
// as the name says - for stairs, session joins, etc.
uint32 j;
for (j = 0; j < MAX_auto_interact; j++) {
if (auto_interact_list[j] == (uint8)(cur_id + 1))
Fatal_error("fn_register_for_auto_interaction finds double registration of %s", CGameObject::GetName(object));
if (!auto_interact_list[j]) { // empty slot
auto_interact_list[j] = (uint8)(cur_id + 1);
Tdebug("auto_interact.txt", "+ [%s] %d", CGameObject::GetName(object), j);
return IR_CONT;
}
}
Fatal_error("fn_register_for_auto_interaction - list full - [%s]", CGameObject::GetName(object));
return IR_CONT;
}
} // End of namespace ICB

Some files were not shown because too many files have changed in this diff Show More