Initial commit
This commit is contained in:
1
engines/icb/POTFILES
Normal file
1
engines/icb/POTFILES
Normal file
@@ -0,0 +1 @@
|
||||
engines/icb/icb.cpp
|
||||
145
engines/icb/actor.cpp
Normal file
145
engines/icb/actor.cpp
Normal 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
38
engines/icb/actor.h
Normal 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
644
engines/icb/actor_fx_pc.cpp
Normal 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
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
59
engines/icb/actor_pc.h
Normal 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
|
||||
686
engines/icb/actor_view_pc.cpp
Normal file
686
engines/icb/actor_view_pc.cpp
Normal 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
|
||||
59
engines/icb/actor_view_pc.h
Normal file
59
engines/icb/actor_view_pc.h
Normal 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
443
engines/icb/animation.cpp
Normal 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
|
||||
503
engines/icb/animation_mega_set.cpp
Normal file
503
engines/icb/animation_mega_set.cpp
Normal 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
|
||||
143
engines/icb/animation_mega_set.h
Normal file
143
engines/icb/animation_mega_set.h
Normal 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
|
||||
52
engines/icb/async_generic.cpp
Normal file
52
engines/icb/async_generic.cpp
Normal 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
1468
engines/icb/barriers.cpp
Normal file
File diff suppressed because it is too large
Load Diff
150
engines/icb/barriers.h
Normal file
150
engines/icb/barriers.h
Normal 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
613
engines/icb/bone.cpp
Normal 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
46
engines/icb/bone.h
Normal 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
181
engines/icb/breath.cpp
Normal 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
61
engines/icb/breath.h
Normal 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
598
engines/icb/camera.cpp
Normal 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
855
engines/icb/chi.cpp
Normal 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
|
||||
407
engines/icb/cluster_manager_pc.cpp
Normal file
407
engines/icb/cluster_manager_pc.cpp
Normal 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
|
||||
146
engines/icb/cluster_manager_pc.h
Normal file
146
engines/icb/cluster_manager_pc.h
Normal 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
|
||||
309
engines/icb/common/datapacker.cpp
Normal file
309
engines/icb/common/datapacker.cpp
Normal 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
|
||||
89
engines/icb/common/datapacker.h
Normal file
89
engines/icb/common/datapacker.h
Normal 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
|
||||
347
engines/icb/common/pc_props.h
Normal file
347
engines/icb/common/pc_props.h
Normal 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
|
||||
90
engines/icb/common/ptr_util.cpp
Normal file
90
engines/icb/common/ptr_util.cpp
Normal 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
|
||||
53
engines/icb/common/ptr_util.h
Normal file
53
engines/icb/common/ptr_util.h
Normal 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
|
||||
133
engines/icb/common/px_2drealline.cpp
Normal file
133
engines/icb/common/px_2drealline.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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
|
||||
97
engines/icb/common/px_2drealline.h
Normal file
97
engines/icb/common/px_2drealline.h
Normal 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
|
||||
69
engines/icb/common/px_2drealpoint.h
Normal file
69
engines/icb/common/px_2drealpoint.h
Normal 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
|
||||
95
engines/icb/common/px_3drealpoint.h
Normal file
95
engines/icb/common/px_3drealpoint.h
Normal 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
|
||||
172
engines/icb/common/px_anims.h
Normal file
172
engines/icb/common/px_anims.h
Normal 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_
|
||||
367
engines/icb/common/px_array.h
Normal file
367
engines/icb/common/px_array.h
Normal 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
|
||||
42
engines/icb/common/px_bitmap.h
Normal file
42
engines/icb/common/px_bitmap.h
Normal 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
|
||||
63
engines/icb/common/px_bitmap_pc.h
Normal file
63
engines/icb/common/px_bitmap_pc.h
Normal 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
|
||||
53
engines/icb/common/px_bones.cpp
Normal file
53
engines/icb/common/px_bones.cpp
Normal 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
|
||||
62
engines/icb/common/px_bones.h
Normal file
62
engines/icb/common/px_bones.h
Normal 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
|
||||
49
engines/icb/common/px_camera.h
Normal file
49
engines/icb/common/px_camera.h
Normal 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__
|
||||
63
engines/icb/common/px_camera_cube.h
Normal file
63
engines/icb/common/px_camera_cube.h
Normal 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
|
||||
44
engines/icb/common/px_capri_maths.cpp
Normal file
44
engines/icb/common/px_capri_maths.cpp
Normal 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
|
||||
408
engines/icb/common/px_capri_maths.h
Normal file
408
engines/icb/common/px_capri_maths.h
Normal 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
|
||||
44
engines/icb/common/px_capri_maths_pc.cpp
Normal file
44
engines/icb/common/px_capri_maths_pc.cpp
Normal 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
|
||||
537
engines/icb/common/px_capri_maths_pc.h
Normal file
537
engines/icb/common/px_capri_maths_pc.h
Normal 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
|
||||
82
engines/icb/common/px_clu_api.cpp
Normal file
82
engines/icb/common/px_clu_api.cpp
Normal 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
|
||||
99
engines/icb/common/px_clu_api.h
Normal file
99
engines/icb/common/px_clu_api.h
Normal 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
|
||||
237
engines/icb/common/px_common.h
Normal file
237
engines/icb/common/px_common.h
Normal 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
|
||||
49
engines/icb/common/px_definitions.h
Normal file
49
engines/icb/common/px_definitions.h
Normal 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
|
||||
63
engines/icb/common/px_features.h
Normal file
63
engines/icb/common/px_features.h
Normal 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
|
||||
97
engines/icb/common/px_floor_map.h
Normal file
97
engines/icb/common/px_floor_map.h
Normal 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
|
||||
211
engines/icb/common/px_game_object.h
Normal file
211
engines/icb/common/px_game_object.h
Normal 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
|
||||
202
engines/icb/common/px_globalvariables.cpp
Normal file
202
engines/icb/common/px_globalvariables.cpp
Normal 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
|
||||
88
engines/icb/common/px_globalvariables.h
Normal file
88
engines/icb/common/px_globalvariables.h
Normal 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
|
||||
88
engines/icb/common/px_lights.h
Normal file
88
engines/icb/common/px_lights.h
Normal 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
|
||||
63
engines/icb/common/px_linkeddatafile.cpp
Normal file
63
engines/icb/common/px_linkeddatafile.cpp
Normal 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
|
||||
180
engines/icb/common/px_linkeddatafile.h
Normal file
180
engines/icb/common/px_linkeddatafile.h
Normal 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
|
||||
184
engines/icb/common/px_list.h
Normal file
184
engines/icb/common/px_list.h
Normal 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
|
||||
163
engines/icb/common/px_mapfile.h
Normal file
163
engines/icb/common/px_mapfile.h
Normal 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)
|
||||
74
engines/icb/common/px_prop_anims.h
Normal file
74
engines/icb/common/px_prop_anims.h
Normal 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
|
||||
45
engines/icb/common/px_rcutypes.h
Normal file
45
engines/icb/common/px_rcutypes.h
Normal 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
|
||||
215
engines/icb/common/px_route_barriers.h
Normal file
215
engines/icb/common/px_route_barriers.h
Normal 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
|
||||
534
engines/icb/common/px_scriptengine.cpp
Normal file
534
engines/icb/common/px_scriptengine.cpp
Normal 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
|
||||
143
engines/icb/common/px_scriptengine.h
Normal file
143
engines/icb/common/px_scriptengine.h
Normal 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
|
||||
97
engines/icb/common/px_sfx_description.h
Normal file
97
engines/icb/common/px_sfx_description.h
Normal 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
|
||||
58
engines/icb/common/px_sound_constants.h
Normal file
58
engines/icb/common/px_sound_constants.h
Normal 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
|
||||
71
engines/icb/common/px_staticlayers.h
Normal file
71
engines/icb/common/px_staticlayers.h
Normal 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
|
||||
336
engines/icb/common/px_string.cpp
Normal file
336
engines/icb/common/px_string.cpp
Normal 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
|
||||
195
engines/icb/common/px_string.h
Normal file
195
engines/icb/common/px_string.h
Normal 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
|
||||
41
engines/icb/common/px_types.h
Normal file
41
engines/icb/common/px_types.h
Normal 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
|
||||
150
engines/icb/common/px_walkarea_integer.h
Normal file
150
engines/icb/common/px_walkarea_integer.h
Normal 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
|
||||
73
engines/icb/common/revtex_api.h
Normal file
73
engines/icb/common/revtex_api.h
Normal 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
|
||||
69
engines/icb/configfile.cpp
Normal file
69
engines/icb/configfile.cpp
Normal 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 §ion, 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 §ion, 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
49
engines/icb/configfile.h
Normal 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 §ion, const Common::String &key, const Common::String &value) {}
|
||||
Common::String readSetting(const Common::String §ion, const Common::String &key, const Common::String &defaultValue) const;
|
||||
int32 readIntSetting(const Common::String §ion, const Common::String &key, int32 defaultValue) const;
|
||||
|
||||
void readFile(const char *filename);
|
||||
};
|
||||
|
||||
} // End of namespace ICB
|
||||
|
||||
#endif
|
||||
3
engines/icb/configure.engine
Normal file
3
engines/icb/configure.engine
Normal 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"
|
||||
44
engines/icb/console_pc.cpp
Normal file
44
engines/icb/console_pc.cpp
Normal 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
5
engines/icb/credits.pl
Normal file
@@ -0,0 +1,5 @@
|
||||
begin_section("ICB");
|
||||
add_person("Paweł Kołodziejski", "aquadran", "");
|
||||
add_person("Joost Peters", "joostp", "");
|
||||
add_person("Einar Johan T. Sømåen", "somaen", "");
|
||||
end_section();
|
||||
441
engines/icb/custom_logics.cpp
Normal file
441
engines/icb/custom_logics.cpp
Normal 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, ¶ms);
|
||||
|
||||
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
|
||||
63
engines/icb/custom_logics.h
Normal file
63
engines/icb/custom_logics.h
Normal 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
220
engines/icb/debug.cpp
Normal 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
57
engines/icb/debug.h
Normal 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
67
engines/icb/debug_pc.cpp
Normal 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
65
engines/icb/debug_pc.h
Normal 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
356
engines/icb/detection.cpp
Normal 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
43
engines/icb/detection.h
Normal 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
|
||||
133
engines/icb/direct_input.cpp
Normal file
133
engines/icb/direct_input.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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
|
||||
50
engines/icb/direct_input.h
Normal file
50
engines/icb/direct_input.h
Normal 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
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
98
engines/icb/drawpoly_pc.h
Normal 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
283
engines/icb/event_list.cpp
Normal 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
176
engines/icb/event_list.h
Normal file
@@ -0,0 +1,176 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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
|
||||
297
engines/icb/event_manager.cpp
Normal file
297
engines/icb/event_manager.cpp
Normal 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
102
engines/icb/event_manager.h
Normal 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
132
engines/icb/event_timer.h
Normal 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
445
engines/icb/floors.cpp
Normal 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
117
engines/icb/floors.h
Normal 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
1512
engines/icb/fn_animation.cpp
Normal file
File diff suppressed because it is too large
Load Diff
843
engines/icb/fn_event_functions.cpp
Normal file
843
engines/icb/fn_event_functions.cpp
Normal 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
79
engines/icb/fn_fx.cpp
Normal 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
222
engines/icb/fn_fx_pc.cpp
Normal 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
|
||||
324
engines/icb/fn_icon_functions.cpp
Normal file
324
engines/icb/fn_icon_functions.cpp
Normal 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
573
engines/icb/fn_interact.cpp
Normal 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
Reference in New Issue
Block a user