2001-10-09 14:30:12 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
|
|
|
* Copyright (C) 2001 Ludvig Strigeus
|
2003-03-06 21:46:56 +00:00
|
|
|
* Copyright (C) 2001-2003 The ScummVM project
|
2001-10-09 14:30:12 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
2001-11-06 20:00:47 +00:00
|
|
|
* $Header$
|
2001-10-09 14:30:12 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "scumm.h"
|
2002-05-14 23:32:34 +00:00
|
|
|
#include "actor.h"
|
2002-07-16 17:59:28 +00:00
|
|
|
#include "costume.h"
|
2002-08-29 23:45:15 +00:00
|
|
|
#include "scumm/sound.h"
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
const byte revBitMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
|
2001-10-09 14:30:12 +00:00
|
|
|
|
|
|
|
const byte cost_scaleTable[256] = {
|
2002-04-11 17:19:16 +00:00
|
|
|
255, 253, 125, 189, 61, 221, 93, 157, 29, 237,
|
|
|
|
109, 173, 45, 205, 77, 141, 13, 245, 117, 181,
|
|
|
|
53, 213, 85, 149, 21, 229, 101, 165, 37, 197, 69,
|
|
|
|
133, 5, 249, 121, 185, 57, 217, 89, 153, 25, 233,
|
|
|
|
105, 169, 41, 201, 73, 137, 9, 241, 113, 177, 49,
|
|
|
|
209, 81, 145, 17, 225, 97, 161, 33, 193, 65, 129,
|
|
|
|
1, 251, 123, 187, 59, 219, 91, 155, 27, 235, 107,
|
|
|
|
171, 43, 203, 75, 139, 11, 243, 115, 179, 51, 211,
|
|
|
|
83, 147, 19, 227, 99, 163, 35, 195, 67, 131, 3,
|
|
|
|
247, 119, 183, 55, 215, 87, 151, 23, 231, 103,
|
|
|
|
167, 39, 199, 71, 135, 7, 239, 111, 175, 47, 207,
|
|
|
|
79, 143, 15, 223, 95, 159, 31, 191, 63, 127, 0,
|
|
|
|
128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208,
|
|
|
|
48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104,
|
|
|
|
232, 24, 152, 88, 216, 56, 184, 120, 248, 4, 132,
|
|
|
|
68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52,
|
|
|
|
180, 116, 244, 12, 140, 76, 204, 44, 172, 108,
|
|
|
|
236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130,
|
|
|
|
66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50,
|
|
|
|
178, 114, 242, 10, 138, 74, 202, 42, 170, 106,
|
|
|
|
234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134,
|
|
|
|
70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54,
|
|
|
|
182, 118, 246, 14, 142, 78, 206, 46, 174, 110,
|
|
|
|
238, 30, 158, 94, 222, 62, 190, 126, 254
|
2001-10-09 14:30:12 +00:00
|
|
|
};
|
|
|
|
|
2003-05-29 10:31:05 +00:00
|
|
|
byte CostumeRenderer::mainRoutine(int xmoveCur, int ymoveCur) {
|
|
|
|
int i, skip;
|
2003-05-28 21:08:56 +00:00
|
|
|
byte drawFlag = 1;
|
2001-10-09 14:30:12 +00:00
|
|
|
uint scal;
|
2003-05-28 21:08:56 +00:00
|
|
|
bool use_scaling;
|
2003-04-23 08:26:28 +00:00
|
|
|
byte startScaleIndexX;
|
2002-04-11 17:19:16 +00:00
|
|
|
int ex1, ex2;
|
2003-05-29 02:14:31 +00:00
|
|
|
int y_top, y_bottom;
|
|
|
|
int x_left, x_right;
|
2003-05-29 02:46:06 +00:00
|
|
|
int step;
|
2002-07-18 18:42:51 +00:00
|
|
|
|
2003-01-05 23:53:16 +00:00
|
|
|
CHECK_HEAP
|
2003-05-29 02:14:31 +00:00
|
|
|
v1.mask = 0xF;
|
|
|
|
v1.shr = 4;
|
2001-12-27 17:51:58 +00:00
|
|
|
if (_loaded._numColors == 32) {
|
2003-05-29 02:14:31 +00:00
|
|
|
v1.mask = 7;
|
|
|
|
v1.shr = 3;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
|
|
|
|
switch (_loaded._ptr[7] & 0x7F) {
|
|
|
|
case 0x60:
|
|
|
|
case 0x61:
|
2001-10-16 10:01:48 +00:00
|
|
|
ex1 = _srcptr[0];
|
|
|
|
ex2 = _srcptr[1];
|
|
|
|
_srcptr += 2;
|
2002-04-11 17:19:16 +00:00
|
|
|
if (ex1 != 0xFF || ex2 != 0xFF) {
|
|
|
|
ex1 = READ_LE_UINT16(_loaded._ptr + _loaded._numColors + 10 + ex1 * 2);
|
2003-04-22 20:48:53 +00:00
|
|
|
_srcptr = _loaded._baseptr + READ_LE_UINT16(_loaded._ptr + ex1 + ex2 * 2) + 14;
|
2001-10-16 10:01:48 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
}
|
2001-10-16 10:01:48 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
v1.x = _actorX;
|
|
|
|
v1.y = _actorY;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-05-28 21:08:56 +00:00
|
|
|
use_scaling = (_scaleX != 0xFF) || (_scaleY != 0xFF);
|
|
|
|
|
2003-05-29 02:46:06 +00:00
|
|
|
skip = 0;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-28 21:08:56 +00:00
|
|
|
if (use_scaling) {
|
2003-05-29 02:46:06 +00:00
|
|
|
v1.scaleXstep = -1;
|
2003-05-29 10:16:00 +00:00
|
|
|
if (xmoveCur < 0) {
|
|
|
|
xmoveCur = -xmoveCur;
|
2003-05-29 02:46:06 +00:00
|
|
|
v1.scaleXstep = 1;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
if (_mirror) {
|
2003-05-29 10:16:00 +00:00
|
|
|
startScaleIndexX = _scaleIndexX = 128 - xmoveCur;
|
|
|
|
for (i = 0; i < xmoveCur; i++) {
|
2003-05-28 21:08:56 +00:00
|
|
|
if (cost_scaleTable[_scaleIndexX++] < _scaleX)
|
2003-05-29 02:46:06 +00:00
|
|
|
v1.x -= v1.scaleXstep;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2003-05-29 02:14:31 +00:00
|
|
|
x_right = x_left = v1.x;
|
2003-04-23 08:26:28 +00:00
|
|
|
_scaleIndexX = startScaleIndexX;
|
2002-04-11 17:19:16 +00:00
|
|
|
for (i = 0; i < _width; i++) {
|
2003-05-29 02:14:31 +00:00
|
|
|
if (x_right < 0) {
|
2003-05-29 02:46:06 +00:00
|
|
|
skip++;
|
2003-04-23 08:26:28 +00:00
|
|
|
startScaleIndexX = _scaleIndexX;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
scal = cost_scaleTable[_scaleIndexX++];
|
|
|
|
if (scal < _scaleX)
|
2003-05-29 02:14:31 +00:00
|
|
|
x_right++;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
} else {
|
2003-05-29 10:16:00 +00:00
|
|
|
startScaleIndexX = _scaleIndexX = xmoveCur + 128;
|
|
|
|
for (i = 0; i < xmoveCur; i++) {
|
2001-10-09 14:30:12 +00:00
|
|
|
scal = cost_scaleTable[_scaleIndexX--];
|
|
|
|
if (scal < _scaleX)
|
2003-05-29 02:46:06 +00:00
|
|
|
v1.x += v1.scaleXstep;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2003-05-29 02:14:31 +00:00
|
|
|
x_right = x_left = v1.x;
|
2003-04-23 08:26:28 +00:00
|
|
|
_scaleIndexX = startScaleIndexX;
|
2002-04-11 17:19:16 +00:00
|
|
|
for (i = 0; i < _width; i++) {
|
2003-05-29 02:14:31 +00:00
|
|
|
if (x_left > (_vm->_screenWidth - 1)) {
|
2003-05-29 02:46:06 +00:00
|
|
|
skip++;
|
2003-04-23 08:26:28 +00:00
|
|
|
startScaleIndexX = _scaleIndexX;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
scal = cost_scaleTable[_scaleIndexX--];
|
2002-04-11 17:19:16 +00:00
|
|
|
if (scal < _scaleX)
|
2003-05-29 02:14:31 +00:00
|
|
|
x_left--;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
}
|
2003-04-23 08:26:28 +00:00
|
|
|
_scaleIndexX = startScaleIndexX;
|
2003-05-29 02:46:06 +00:00
|
|
|
if (skip)
|
|
|
|
skip--;
|
|
|
|
|
|
|
|
step = -1;
|
2003-05-29 10:16:00 +00:00
|
|
|
if (ymoveCur < 0) {
|
|
|
|
ymoveCur = -ymoveCur;
|
2003-05-29 02:46:06 +00:00
|
|
|
step = 1;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2003-05-29 10:16:00 +00:00
|
|
|
_scaleIndexY = 128 - ymoveCur;
|
|
|
|
for (i = 0; i < ymoveCur; i++) {
|
2001-10-09 14:30:12 +00:00
|
|
|
scal = cost_scaleTable[_scaleIndexY++];
|
|
|
|
if (scal < _scaleY)
|
2003-05-29 02:46:06 +00:00
|
|
|
v1.y -= step;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2003-05-29 02:14:31 +00:00
|
|
|
y_top = y_bottom = v1.y;
|
2003-05-29 10:16:00 +00:00
|
|
|
_scaleIndexY = 128 - ymoveCur;
|
2002-04-11 17:19:16 +00:00
|
|
|
for (i = 0; i < _height; i++) {
|
2001-10-09 14:30:12 +00:00
|
|
|
scal = cost_scaleTable[_scaleIndexY++];
|
2002-04-11 17:19:16 +00:00
|
|
|
if (scal < _scaleY)
|
2003-05-29 02:14:31 +00:00
|
|
|
y_bottom++;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2003-05-29 10:16:00 +00:00
|
|
|
_scaleIndexY = _scaleIndexYTop = 128 - ymoveCur;
|
2001-10-09 14:30:12 +00:00
|
|
|
} else {
|
2003-05-29 02:14:31 +00:00
|
|
|
if (!_mirror)
|
2003-05-29 10:16:00 +00:00
|
|
|
xmoveCur = -xmoveCur;
|
|
|
|
v1.x += xmoveCur;
|
|
|
|
v1.y += ymoveCur;
|
2001-10-09 14:30:12 +00:00
|
|
|
if (_mirror) {
|
2003-05-29 02:14:31 +00:00
|
|
|
x_left = v1.x;
|
|
|
|
x_right = v1.x + _width;
|
2001-10-09 14:30:12 +00:00
|
|
|
} else {
|
2003-05-29 02:14:31 +00:00
|
|
|
x_left = v1.x - _width;
|
|
|
|
x_right = v1.x;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2003-05-29 02:14:31 +00:00
|
|
|
y_top = v1.y;
|
|
|
|
y_bottom = y_top + _height;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-05-29 02:46:06 +00:00
|
|
|
v1.scaleXstep = -1;
|
2001-10-09 14:30:12 +00:00
|
|
|
if (_mirror)
|
2003-05-29 02:46:06 +00:00
|
|
|
v1.scaleXstep = 1;
|
2001-12-27 17:51:58 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
_vm->updateDirtyRect(0, x_left, x_right + 1, y_top, y_bottom, _dirty_id);
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if (y_top >= (int)_outheight || y_bottom <= 0)
|
2001-10-09 14:30:12 +00:00
|
|
|
return 0;
|
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if (x_left >= _vm->_screenWidth || x_right <= 0)
|
2001-12-27 17:51:58 +00:00
|
|
|
return 1;
|
2003-05-28 21:08:56 +00:00
|
|
|
|
2003-05-29 10:46:07 +00:00
|
|
|
v1.replen = 0;
|
|
|
|
|
2001-10-09 14:30:12 +00:00
|
|
|
if (_mirror) {
|
2003-05-29 02:14:31 +00:00
|
|
|
if (!use_scaling)
|
2003-05-29 02:46:06 +00:00
|
|
|
skip = -v1.x;
|
|
|
|
if (skip > 0) {
|
|
|
|
_width2 -= skip;
|
2003-05-29 10:31:05 +00:00
|
|
|
codec1_ignorePakCols(skip);
|
2003-05-29 02:14:31 +00:00
|
|
|
v1.x = 0;
|
2001-10-09 14:30:12 +00:00
|
|
|
} else {
|
2003-05-29 02:46:06 +00:00
|
|
|
skip = x_right - _vm->_screenWidth;
|
|
|
|
if (skip <= 0) {
|
2003-05-28 21:08:56 +00:00
|
|
|
drawFlag = 2;
|
2001-10-09 14:30:12 +00:00
|
|
|
} else {
|
2003-05-29 02:46:06 +00:00
|
|
|
_width2 -= skip;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2003-05-29 02:14:31 +00:00
|
|
|
if (!use_scaling)
|
2003-05-29 02:46:06 +00:00
|
|
|
skip = x_right - _vm->_screenWidth;
|
|
|
|
if (skip > 0) {
|
|
|
|
_width2 -= skip;
|
2003-05-29 10:31:05 +00:00
|
|
|
codec1_ignorePakCols(skip);
|
2003-05-29 02:14:31 +00:00
|
|
|
v1.x = _vm->_screenWidth - 1;
|
2001-10-09 14:30:12 +00:00
|
|
|
} else {
|
2003-05-29 02:46:06 +00:00
|
|
|
skip = -1 - x_left;
|
|
|
|
if (skip <= 0)
|
2003-05-28 21:08:56 +00:00
|
|
|
drawFlag = 2;
|
2001-10-09 14:30:12 +00:00
|
|
|
else
|
2003-05-29 02:46:06 +00:00
|
|
|
_width2 -= skip;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
if (_width2 == 0)
|
2001-10-16 10:01:48 +00:00
|
|
|
return 0;
|
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if ((uint) y_top > (uint) _outheight)
|
|
|
|
y_top = 0;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if (x_left < 0)
|
|
|
|
x_left = 0;
|
2001-11-05 19:21:49 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if ((uint) y_bottom > _outheight)
|
|
|
|
y_bottom = _outheight;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if (_draw_top > y_top)
|
|
|
|
_draw_top = y_top;
|
|
|
|
if (_draw_bottom < y_bottom)
|
|
|
|
_draw_bottom = y_bottom;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if (_height + y_top >= 256) {
|
2003-01-05 23:53:16 +00:00
|
|
|
CHECK_HEAP
|
|
|
|
return 2;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
v1.destptr = _outptr + v1.y * _vm->_screenWidth + v1.x;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
v1.mask_ptr = _vm->getResourceAddress(rtBuffer, 9) + v1.y * _numStrips + _vm->_screenStartStrip;
|
|
|
|
v1.imgbufoffs = _vm->gdi._imgBufOffs[_zbuf];
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-18 18:36:14 +00:00
|
|
|
// FIXME: Masking used to be conditional. Will it cause regressions
|
|
|
|
// to always do it? I don't think so, since the behaviour used to be
|
|
|
|
// to mask if there was a mask to apply, unless _zbuf is 0.
|
|
|
|
//
|
|
|
|
// However, when _zbuf is 0 masking and charset masking are the same
|
|
|
|
// thing. I believe the only thing that is ever written to the
|
|
|
|
// frontmost mask buffer is the charset mask, except in Sam & Max
|
|
|
|
// where it's also used for the inventory box and conversation icons.
|
2001-11-11 16:54:45 +00:00
|
|
|
|
2003-05-18 18:36:14 +00:00
|
|
|
_use_mask = true;
|
|
|
|
_use_charset_mask = true;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-01-05 23:53:16 +00:00
|
|
|
CHECK_HEAP
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-18 18:36:14 +00:00
|
|
|
if (_vm->_features & GF_AMIGA)
|
|
|
|
proc3_ami();
|
|
|
|
else
|
|
|
|
proc3();
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-05-18 18:36:14 +00:00
|
|
|
CHECK_HEAP
|
2003-05-28 21:08:56 +00:00
|
|
|
return drawFlag;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
void CostumeRenderer::proc3() {
|
2003-05-29 02:14:31 +00:00
|
|
|
const byte *mask, *src;
|
|
|
|
byte *dst;
|
2002-04-11 17:19:16 +00:00
|
|
|
byte maskbit, len, height, pcolor, width;
|
2003-05-29 02:46:06 +00:00
|
|
|
int color;
|
2001-10-16 20:31:27 +00:00
|
|
|
uint y;
|
2003-05-18 18:36:14 +00:00
|
|
|
bool masked;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
mask = v1.mask_ptr + (v1.x >> 3);
|
|
|
|
maskbit = revBitMask[v1.x & 7];
|
|
|
|
y = v1.y;
|
2002-08-04 00:04:50 +00:00
|
|
|
src = _srcptr;
|
2003-05-29 02:14:31 +00:00
|
|
|
dst = v1.destptr;
|
2003-05-29 10:46:07 +00:00
|
|
|
len = v1.replen;
|
2003-05-29 02:14:31 +00:00
|
|
|
color = v1.repcolor;
|
|
|
|
height = _height;
|
2002-08-04 00:04:50 +00:00
|
|
|
width = _width2;
|
2001-10-16 20:31:27 +00:00
|
|
|
|
2003-05-29 10:46:07 +00:00
|
|
|
if (v1.replen)
|
2002-04-11 17:19:16 +00:00
|
|
|
goto StartPos;
|
2001-10-16 20:31:27 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
len = *src++;
|
2003-05-29 02:14:31 +00:00
|
|
|
color = len >> v1.shr;
|
|
|
|
len &= v1.mask;
|
2002-04-11 17:19:16 +00:00
|
|
|
if (!len)
|
|
|
|
len = *src++;
|
2002-08-04 00:04:50 +00:00
|
|
|
|
2001-10-16 20:31:27 +00:00
|
|
|
do {
|
2003-05-18 18:36:14 +00:00
|
|
|
if (_scaleY == 255 || cost_scaleTable[_scaleIndexY++] < _scaleY) {
|
2003-05-29 02:14:31 +00:00
|
|
|
masked = (_use_mask && (mask[v1.imgbufoffs] & maskbit)) || (_use_charset_mask && (mask[0] & maskbit));
|
2003-05-18 18:36:14 +00:00
|
|
|
|
|
|
|
if (color && y < _outheight && !masked) {
|
|
|
|
// FIXME: Fully implement _shadow_mode.
|
|
|
|
// For now, it's enough for Sam & Max
|
|
|
|
// transparency.
|
|
|
|
if (_shadow_mode & 0x20) {
|
|
|
|
pcolor = _vm->_proc_special_palette[*dst];
|
|
|
|
} else {
|
|
|
|
pcolor = _palette[color];
|
|
|
|
if (pcolor == 13 && _shadow_table)
|
|
|
|
pcolor = _shadow_table[*dst];
|
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
*dst = pcolor;
|
|
|
|
}
|
2003-05-10 21:49:59 +00:00
|
|
|
dst += _vm->_screenWidth;
|
2002-10-24 06:28:54 +00:00
|
|
|
mask += _numStrips;
|
2001-10-09 14:30:12 +00:00
|
|
|
y++;
|
|
|
|
}
|
|
|
|
if (!--height) {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (!--width)
|
2001-10-09 14:30:12 +00:00
|
|
|
return;
|
|
|
|
height = _height;
|
2003-05-29 02:46:06 +00:00
|
|
|
y = v1.y;
|
|
|
|
|
2001-10-09 14:30:12 +00:00
|
|
|
_scaleIndexY = _scaleIndexYTop;
|
2003-05-29 02:46:06 +00:00
|
|
|
if (_scaleX == 255 || cost_scaleTable[_scaleIndexX] < _scaleX) {
|
|
|
|
v1.x += v1.scaleXstep;
|
2003-05-29 02:14:31 +00:00
|
|
|
if (v1.x < 0 || v1.x >= _vm->_screenWidth)
|
2001-10-09 14:30:12 +00:00
|
|
|
return;
|
2003-05-29 02:14:31 +00:00
|
|
|
maskbit = revBitMask[v1.x & 7];
|
2003-05-29 02:46:06 +00:00
|
|
|
v1.destptr += v1.scaleXstep;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2003-05-29 02:46:06 +00:00
|
|
|
_scaleIndexX += v1.scaleXstep;
|
2003-05-29 02:14:31 +00:00
|
|
|
dst = v1.destptr;
|
|
|
|
mask = v1.mask_ptr + (v1.x >> 3);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
StartPos:;
|
2001-10-09 14:30:12 +00:00
|
|
|
} while (--len);
|
2002-04-11 17:19:16 +00:00
|
|
|
} while (1);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
void CostumeRenderer::proc3_ami() {
|
2003-05-29 02:14:31 +00:00
|
|
|
const byte *mask, *src;
|
|
|
|
byte *dst;
|
2003-05-18 18:36:14 +00:00
|
|
|
byte maskbit, len, height, width;
|
2003-05-29 02:46:06 +00:00
|
|
|
int color;
|
2002-07-18 18:42:51 +00:00
|
|
|
uint y;
|
2003-05-18 18:36:14 +00:00
|
|
|
bool masked;
|
2002-08-24 13:06:44 +00:00
|
|
|
int oldXpos, oldScaleIndexX;
|
2002-07-18 18:42:51 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
mask = v1.mask_ptr + (v1.x >> 3);
|
|
|
|
dst = v1.destptr;
|
|
|
|
height = _height;
|
2002-07-18 18:42:51 +00:00
|
|
|
width = _width;
|
|
|
|
src = _srcptr;
|
2003-05-29 02:14:31 +00:00
|
|
|
maskbit = revBitMask[v1.x & 7];
|
|
|
|
y = v1.y;
|
|
|
|
oldXpos = v1.x;
|
2002-07-18 18:42:51 +00:00
|
|
|
oldScaleIndexX = _scaleIndexX;
|
|
|
|
|
|
|
|
do {
|
|
|
|
len = *src++;
|
2003-05-29 02:14:31 +00:00
|
|
|
color = len >> v1.shr;
|
|
|
|
len &= v1.mask;
|
2002-07-18 18:42:51 +00:00
|
|
|
if (!len)
|
|
|
|
len = *src++;
|
|
|
|
do {
|
2003-05-18 18:36:14 +00:00
|
|
|
if (_scaleY == 255 || cost_scaleTable[_scaleIndexY] < _scaleY) {
|
2003-05-29 02:14:31 +00:00
|
|
|
masked = (_use_mask && (mask[v1.imgbufoffs] & maskbit)) || (_use_charset_mask && (mask[0] & maskbit));
|
2003-05-18 18:36:14 +00:00
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if (color && v1.x >= 0 && v1.x < _vm->_screenWidth && !masked) {
|
2003-05-18 18:36:14 +00:00
|
|
|
*dst = _palette[color];
|
2002-07-18 18:42:51 +00:00
|
|
|
}
|
|
|
|
|
2003-05-29 02:46:06 +00:00
|
|
|
if (_scaleX == 255 || cost_scaleTable[_scaleIndexX] < _scaleX) {
|
|
|
|
v1.x += v1.scaleXstep;
|
|
|
|
dst += v1.scaleXstep;
|
2003-05-29 02:14:31 +00:00
|
|
|
maskbit = revBitMask[v1.x & 7];
|
2002-07-18 18:42:51 +00:00
|
|
|
}
|
2003-05-29 02:46:06 +00:00
|
|
|
_scaleIndexX += v1.scaleXstep;
|
2003-05-29 02:14:31 +00:00
|
|
|
mask = v1.mask_ptr + (v1.x >> 3);
|
2002-07-18 18:42:51 +00:00
|
|
|
}
|
|
|
|
if (!--width) {
|
|
|
|
if (!--height)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (y >= _outheight)
|
|
|
|
return;
|
|
|
|
|
2003-05-29 02:14:31 +00:00
|
|
|
if (v1.x != oldXpos) {
|
|
|
|
dst += _vm->_screenWidth - (v1.x - oldXpos);
|
|
|
|
v1.mask_ptr += _numStrips;
|
|
|
|
mask = v1.mask_ptr;
|
2002-07-18 18:42:51 +00:00
|
|
|
y++;
|
|
|
|
}
|
|
|
|
width = _width;
|
2003-05-29 02:14:31 +00:00
|
|
|
v1.x = oldXpos;
|
2002-07-18 18:42:51 +00:00
|
|
|
_scaleIndexX = oldScaleIndexX;
|
|
|
|
_scaleIndexY++;
|
|
|
|
}
|
|
|
|
} while (--len);
|
|
|
|
} while (1);
|
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
void LoadedCostume::loadCostume(int id) {
|
2001-11-14 20:09:39 +00:00
|
|
|
_ptr = _vm->getResourceAddress(rtCostume, id);
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-04-12 19:51:14 +00:00
|
|
|
if (_vm->_features & GF_AFTER_V6)
|
2001-10-23 19:51:50 +00:00
|
|
|
_ptr += 8;
|
2003-04-12 19:51:14 +00:00
|
|
|
else if (_vm->_features & GF_OLD_BUNDLE)
|
|
|
|
_ptr += -2;
|
|
|
|
else if (_vm->_features & GF_SMALL_HEADER)
|
|
|
|
_ptr += 0;
|
|
|
|
else
|
2001-10-23 19:51:50 +00:00
|
|
|
_ptr += 2;
|
|
|
|
|
2003-04-22 20:48:53 +00:00
|
|
|
_baseptr = _ptr;
|
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
switch (_ptr[7] & 0x7F) {
|
2001-10-09 14:30:12 +00:00
|
|
|
case 0x58:
|
|
|
|
_numColors = 16;
|
|
|
|
break;
|
|
|
|
case 0x59:
|
|
|
|
_numColors = 32;
|
|
|
|
break;
|
2002-04-11 17:19:16 +00:00
|
|
|
case 0x60: /* New since version 6 */
|
2001-10-16 10:01:48 +00:00
|
|
|
_numColors = 16;
|
|
|
|
break;
|
2002-04-11 17:19:16 +00:00
|
|
|
case 0x61: /* New since version 6 */
|
2001-10-16 10:01:48 +00:00
|
|
|
_numColors = 32;
|
|
|
|
break;
|
2001-10-09 14:30:12 +00:00
|
|
|
default:
|
|
|
|
error("Costume %d is invalid", id);
|
|
|
|
}
|
2003-04-22 18:57:10 +00:00
|
|
|
|
|
|
|
// In GF_OLD_BUNDLE games, there is no actual palette, just a single color byte.
|
|
|
|
// Don't forget, these games were designed around a fixed 16 color HW palette :-)
|
2003-04-22 20:48:53 +00:00
|
|
|
// In addition, all offsets are shifted by 2; we accomodate that via a seperate
|
|
|
|
// _baseptr value (instead of adding tons of if's throughout the code).
|
|
|
|
if (_vm->_features & GF_OLD_BUNDLE) {
|
2003-04-22 18:57:10 +00:00
|
|
|
_numColors = 1;
|
2003-04-22 20:48:53 +00:00
|
|
|
_baseptr += 2;
|
|
|
|
}
|
|
|
|
_dataptr = _baseptr + READ_LE_UINT16(_ptr + _numColors + 8);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
byte CostumeRenderer::drawLimb(const CostumeData &cost, int limb) {
|
2003-01-05 23:53:16 +00:00
|
|
|
int i;
|
|
|
|
int code;
|
2003-05-29 02:46:06 +00:00
|
|
|
const byte *frameptr;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-05-29 02:46:06 +00:00
|
|
|
// If the specified limb is stopped or not existing, do nothing.
|
2003-01-05 23:53:16 +00:00
|
|
|
if (cost.curpos[limb] == 0xFFFF || cost.stopped & (1 << limb))
|
|
|
|
return 0;
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2003-05-29 02:46:06 +00:00
|
|
|
// Determine the position the limb is at
|
2003-01-05 23:53:16 +00:00
|
|
|
i = cost.curpos[limb] & 0x7FFF;
|
2003-04-13 19:53:39 +00:00
|
|
|
|
2003-05-29 02:46:06 +00:00
|
|
|
// Get the base pointer for that limb
|
|
|
|
frameptr = _loaded._baseptr + READ_LE_UINT16(_loaded._ptr + _loaded._numColors + limb * 2 + 10);
|
|
|
|
|
|
|
|
// Determine the offset to the costume data for the limb at position i
|
|
|
|
code = _loaded._dataptr[i] & 0x7F;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-05-29 02:46:06 +00:00
|
|
|
// Code 0x7B indicates a limb for which there is nothing to draw
|
2003-01-05 23:53:16 +00:00
|
|
|
if (code != 0x7B) {
|
2003-05-29 02:46:06 +00:00
|
|
|
_srcptr = _loaded._baseptr + READ_LE_UINT16(frameptr + code * 2);
|
2003-05-29 10:31:05 +00:00
|
|
|
if (!(_vm->_features & GF_OLD256) || code < 0x79) {
|
|
|
|
const CostumeInfo *costumeInfo;
|
|
|
|
int xmoveCur, ymoveCur;
|
|
|
|
|
|
|
|
// FIXME: those are here just in case... you never now...
|
|
|
|
assert(_srcptr[1] == 0);
|
|
|
|
assert(_srcptr[3] == 0);
|
|
|
|
|
|
|
|
costumeInfo = (const CostumeInfo *)_srcptr;
|
|
|
|
_width = _width2 = READ_LE_UINT16(&costumeInfo->width);
|
|
|
|
_height = READ_LE_UINT16(&costumeInfo->height);
|
|
|
|
xmoveCur = _xmove + (int16)READ_LE_UINT16(&costumeInfo->rel_x);
|
|
|
|
ymoveCur = _ymove + (int16)READ_LE_UINT16(&costumeInfo->rel_y);
|
|
|
|
_xmove += (int16)READ_LE_UINT16(&costumeInfo->move_x);
|
|
|
|
_ymove -= (int16)READ_LE_UINT16(&costumeInfo->move_y);
|
|
|
|
_srcptr += 12;
|
|
|
|
|
|
|
|
return mainRoutine(xmoveCur, ymoveCur);
|
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
int Scumm::cost_frameToAnim(Actor *a, int frame) {
|
2001-12-27 17:51:58 +00:00
|
|
|
return newDirToOldDir(a->facing) + frame * 4;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
void Scumm::cost_decodeData(Actor *a, int frame, uint usemask) {
|
2003-05-29 02:46:06 +00:00
|
|
|
const byte *r;
|
2002-04-11 17:19:16 +00:00
|
|
|
uint mask, j;
|
2001-11-26 19:57:57 +00:00
|
|
|
int i;
|
2002-04-11 17:19:16 +00:00
|
|
|
byte extra, cmd;
|
2003-05-29 02:46:06 +00:00
|
|
|
const byte *dataptr;
|
2001-11-26 19:57:57 +00:00
|
|
|
int anim;
|
2002-07-15 22:56:24 +00:00
|
|
|
LoadedCostume lc(this);
|
2001-12-27 17:51:58 +00:00
|
|
|
|
2002-07-15 22:56:24 +00:00
|
|
|
lc.loadCostume(a->costume);
|
2001-11-26 19:57:57 +00:00
|
|
|
|
|
|
|
anim = cost_frameToAnim(a, frame);
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-04-22 20:48:53 +00:00
|
|
|
if (anim > lc._ptr[6]) {
|
2003-04-14 07:02:07 +00:00
|
|
|
return;
|
2003-04-13 19:53:39 +00:00
|
|
|
}
|
|
|
|
|
2003-04-22 20:48:53 +00:00
|
|
|
r = lc._baseptr + READ_LE_UINT16(lc._ptr + anim * 2 + lc._numColors + 42);
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2003-04-22 20:48:53 +00:00
|
|
|
if (r == lc._baseptr) {
|
2001-11-26 19:57:57 +00:00
|
|
|
return;
|
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-04-22 18:57:10 +00:00
|
|
|
dataptr = lc._dataptr;
|
2001-11-26 19:57:57 +00:00
|
|
|
mask = READ_LE_UINT16(r);
|
2002-04-11 17:19:16 +00:00
|
|
|
r += 2;
|
2001-11-26 19:57:57 +00:00
|
|
|
i = 0;
|
|
|
|
do {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (mask & 0x8000) {
|
2003-05-03 16:46:47 +00:00
|
|
|
if ((_features & GF_AFTER_V3) || (_features & GF_AFTER_V2)) {
|
2003-04-22 18:57:10 +00:00
|
|
|
j = *r++;
|
2003-04-22 20:48:53 +00:00
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
if (j == 0xFF)
|
|
|
|
j = 0xFFFF;
|
2002-02-21 22:48:13 +00:00
|
|
|
} else {
|
|
|
|
j = READ_LE_UINT16(r);
|
2002-04-11 17:19:16 +00:00
|
|
|
r += 2;
|
2002-02-21 22:48:13 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
if (usemask & 0x8000) {
|
|
|
|
if (j == 0xFFFF) {
|
2001-11-26 19:57:57 +00:00
|
|
|
a->cost.curpos[i] = 0xFFFF;
|
|
|
|
a->cost.start[i] = 0;
|
|
|
|
a->cost.frame[i] = frame;
|
|
|
|
} else {
|
|
|
|
extra = *r++;
|
|
|
|
cmd = dataptr[j];
|
2002-04-11 17:19:16 +00:00
|
|
|
if (cmd == 0x7A) {
|
|
|
|
a->cost.stopped &= ~(1 << i);
|
|
|
|
} else if (cmd == 0x79) {
|
|
|
|
a->cost.stopped |= (1 << i);
|
2001-11-26 19:57:57 +00:00
|
|
|
} else {
|
|
|
|
a->cost.curpos[i] = a->cost.start[i] = j;
|
2002-04-11 17:19:16 +00:00
|
|
|
a->cost.end[i] = j + (extra & 0x7F);
|
|
|
|
if (extra & 0x80)
|
2001-11-26 19:57:57 +00:00
|
|
|
a->cost.curpos[i] |= 0x8000;
|
|
|
|
a->cost.frame[i] = frame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (j != 0xFFFF)
|
2001-11-26 19:57:57 +00:00
|
|
|
r++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
usemask <<= 1;
|
|
|
|
mask <<= 1;
|
|
|
|
} while ((uint16)mask);
|
|
|
|
}
|
2001-12-27 17:51:58 +00:00
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
void CostumeRenderer::setPalette(byte *palette) {
|
2001-12-27 17:51:58 +00:00
|
|
|
int i;
|
|
|
|
byte color;
|
|
|
|
|
2003-04-22 18:57:10 +00:00
|
|
|
if (_vm->_features & GF_OLD_BUNDLE) {
|
2003-05-08 15:48:50 +00:00
|
|
|
if ((_vm->VAR(_vm->VAR_CURRENT_LIGHTS) & LIGHTMODE_actor_color)) {
|
2003-04-22 20:48:53 +00:00
|
|
|
memcpy(_palette, palette, 16);
|
2002-08-19 17:23:48 +00:00
|
|
|
} else {
|
2003-04-22 20:48:53 +00:00
|
|
|
memset(_palette, 8, 16);
|
2003-04-22 19:59:30 +00:00
|
|
|
_palette[12] = 0;
|
|
|
|
}
|
2003-04-22 20:48:53 +00:00
|
|
|
_palette[_loaded._ptr[8]] = _palette[0];
|
2003-04-22 19:59:30 +00:00
|
|
|
} else {
|
2003-05-13 23:03:18 +00:00
|
|
|
if ((_vm->_features & GF_AFTER_V6) || (_vm->VAR(_vm->VAR_CURRENT_LIGHTS) & LIGHTMODE_actor_color)) {
|
|
|
|
for (i = 0; i < _loaded._numColors; i++) {
|
2003-04-22 19:59:30 +00:00
|
|
|
color = palette[i];
|
|
|
|
if (color == 255)
|
|
|
|
color = _loaded._ptr[8 + i];
|
2003-05-13 23:03:18 +00:00
|
|
|
_palette[i] = color;
|
2003-04-22 19:59:30 +00:00
|
|
|
}
|
2003-05-13 23:03:18 +00:00
|
|
|
} else {
|
|
|
|
memset(_palette, 8, _loaded._numColors);
|
|
|
|
_palette[12] = 0;
|
2002-08-19 17:23:48 +00:00
|
|
|
}
|
2001-12-27 17:51:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
void CostumeRenderer::setFacing(Actor *a) {
|
2003-01-07 17:35:20 +00:00
|
|
|
_mirror = newDirToOldDir(a->facing) != 0 || (_loaded._ptr[7] & 0x80);
|
2001-12-27 17:51:58 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
void CostumeRenderer::setCostume(int costume) {
|
2002-07-15 22:56:24 +00:00
|
|
|
_loaded.loadCostume(costume);
|
2001-12-27 17:51:58 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
byte LoadedCostume::increaseAnims(Actor *a) {
|
2001-12-27 17:51:58 +00:00
|
|
|
int i;
|
|
|
|
byte r = 0;
|
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
for (i = 0; i != 16; i++) {
|
|
|
|
if (a->cost.curpos[i] != 0xFFFF)
|
2002-07-15 22:56:24 +00:00
|
|
|
r += increaseAnim(a, i);
|
2001-12-27 17:51:58 +00:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
byte LoadedCostume::increaseAnim(Actor *a, int slot) {
|
2001-12-27 17:51:58 +00:00
|
|
|
int highflag;
|
2002-04-11 17:19:16 +00:00
|
|
|
int i, end;
|
|
|
|
byte code, nc;
|
2001-12-27 17:51:58 +00:00
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
if (a->cost.curpos[slot] == 0xFFFF)
|
2001-12-27 17:51:58 +00:00
|
|
|
return 0;
|
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
highflag = a->cost.curpos[slot] & 0x8000;
|
|
|
|
i = a->cost.curpos[slot] & 0x7FFF;
|
2001-12-27 17:51:58 +00:00
|
|
|
end = a->cost.end[slot];
|
2002-07-15 22:56:24 +00:00
|
|
|
code = _dataptr[i] & 0x7F;
|
2001-12-27 17:51:58 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
if (!highflag) {
|
|
|
|
if (i++ >= end)
|
|
|
|
i = a->cost.start[slot];
|
|
|
|
} else {
|
|
|
|
if (i != end)
|
|
|
|
i++;
|
|
|
|
}
|
2002-07-15 22:56:24 +00:00
|
|
|
nc = _dataptr[i];
|
2001-12-27 17:51:58 +00:00
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
if (nc == 0x7C) {
|
2001-12-27 17:51:58 +00:00
|
|
|
a->cost.animCounter1++;
|
2002-04-11 17:19:16 +00:00
|
|
|
if (a->cost.start[slot] != end)
|
2001-12-27 17:51:58 +00:00
|
|
|
continue;
|
|
|
|
} else {
|
2002-07-15 22:56:24 +00:00
|
|
|
if (_vm->_features & GF_AFTER_V6) {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (nc >= 0x71 && nc <= 0x78) {
|
2002-08-14 20:43:56 +00:00
|
|
|
_vm->_sound->addSoundToQueue2(a->sound[nc - 0x71]);
|
2002-04-11 17:19:16 +00:00
|
|
|
if (a->cost.start[slot] != end)
|
2001-12-27 17:51:58 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (nc == 0x78) {
|
2001-12-27 17:51:58 +00:00
|
|
|
a->cost.animCounter2++;
|
2002-04-11 17:19:16 +00:00
|
|
|
if (a->cost.start[slot] != end)
|
2001-12-27 17:51:58 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
a->cost.curpos[slot] = i | highflag;
|
2002-07-15 22:56:24 +00:00
|
|
|
return (_dataptr[i] & 0x7F) != code;
|
2002-04-11 17:19:16 +00:00
|
|
|
} while (1);
|
2001-12-27 17:51:58 +00:00
|
|
|
}
|
2002-05-20 14:41:47 +00:00
|
|
|
|
2003-03-06 17:58:13 +00:00
|
|
|
bool Scumm::isCostumeInUse(int cost) {
|
2002-05-20 14:41:47 +00:00
|
|
|
int i;
|
|
|
|
Actor *a;
|
|
|
|
|
|
|
|
if (_roomResource != 0)
|
2003-05-13 23:42:41 +00:00
|
|
|
for (i = 1; i < _numActors; i++) {
|
2002-05-20 14:41:47 +00:00
|
|
|
a = derefActor(i);
|
|
|
|
if (a->isInCurrentRoom() && a->costume == cost)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|