scummvm/engines/twine/collision.cpp
Martin Gerhardy 699c8225c6 TWINE: replaced magic numbers with constants
and started to mark the angles - to be able to refacto them easier later on
2020-11-20 18:34:50 +01:00

566 lines
23 KiB
C++

/* 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/memstream.h"
#include "twine/actor.h"
#include "twine/animations.h"
#include "twine/collision.h"
#include "common/debug.h"
#include "common/util.h"
#include "twine/extra.h"
#include "twine/grid.h"
#include "twine/movements.h"
#include "twine/renderer.h"
#include "twine/resources.h"
#include "twine/scene.h"
#include "twine/twine.h"
namespace TwinE {
Collision::Collision(TwinEEngine *engine) : _engine(engine) {
}
bool Collision::standingOnActor(int32 actorIdx1, int32 actorIdx2) {
const ActorStruct *actor1 = _engine->_scene->getActor(actorIdx1);
const ActorStruct *actor2 = _engine->_scene->getActor(actorIdx2);
// Current actor (actor 1)
const int32 x1Left = _engine->_movements->processActorX + actor1->boudingBox.x.bottomLeft;
const int32 x1Right = _engine->_movements->processActorX + actor1->boudingBox.x.topRight;
const int32 y1Left = _engine->_movements->processActorY + actor1->boudingBox.y.bottomLeft;
const int32 y1Right = _engine->_movements->processActorY + actor1->boudingBox.y.topRight;
const int32 z1Left = _engine->_movements->processActorZ + actor1->boudingBox.z.bottomLeft;
const int32 z1Right = _engine->_movements->processActorZ + actor1->boudingBox.z.topRight;
// Actor 2
const int32 x2Left = actor2->x + actor2->boudingBox.x.bottomLeft;
const int32 x2Right = actor2->x + actor2->boudingBox.x.topRight;
const int32 y2Left = actor2->y + actor2->boudingBox.y.bottomLeft;
const int32 y2Right = actor2->y + actor2->boudingBox.y.topRight;
const int32 z2Left = actor2->z + actor2->boudingBox.z.bottomLeft;
const int32 z2Right = actor2->z + actor2->boudingBox.z.topRight;
if (x1Left >= x2Right) {
return false; // not standing
}
if (x1Right <= x2Left) {
return false;
}
if (y1Left > (y2Right + 1)) {
return false;
}
if (y1Left <= (y2Right - 0x100)) {
return false;
}
if (y1Right <= y2Left) {
return false;
}
if (z1Left >= z2Right) {
return false;
}
if (z1Right <= z2Left) {
return false;
}
return true; // standing
}
int32 Collision::getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3) {
if (var3 <= 0) {
return var0;
}
if (var3 >= var2) {
return var1;
}
return (((var1 - var0) * var3) / var2) + var0;
}
void Collision::reajustActorPosition(ShapeType brickShape) {
if (brickShape == ShapeType::kNone) {
return;
}
const int32 brkX = (collisionX << 9) - 0x100;
const int32 brkY = collisionY << 8;
const int32 brkZ = (collisionZ << 9) - 0x100;
// double-side stairs
if (brickShape >= ShapeType::kDoubleSideStairsTop1 && brickShape <= ShapeType::kDoubleSideStairsRight2) {
switch (brickShape) {
case ShapeType::kDoubleSideStairsTop1:
if (_engine->_movements->processActorZ - collisionZ <= _engine->_movements->processActorX - collisionX) {
brickShape = ShapeType::kStairsTopLeft;
} else {
brickShape = ShapeType::kStairsTopRight;
}
break;
case ShapeType::kDoubleSideStairsBottom1:
if (_engine->_movements->processActorZ - collisionZ <= _engine->_movements->processActorX - collisionX) {
brickShape = ShapeType::kStairsBottomLeft;
} else {
brickShape = ShapeType::kStairsBottomRight;
}
break;
case ShapeType::kDoubleSideStairsLeft1:
if (512 - _engine->_movements->processActorX - collisionX <= _engine->_movements->processActorZ - collisionZ) {
brickShape = ShapeType::kStairsTopLeft;
} else {
brickShape = ShapeType::kStairsBottomLeft;
}
break;
case ShapeType::kDoubleSideStairsRight1:
if (512 - _engine->_movements->processActorX - collisionX <= _engine->_movements->processActorZ - collisionZ) {
brickShape = ShapeType::kStairsTopRight;
} else {
brickShape = ShapeType::kStairsBottomRight;
}
break;
case ShapeType::kDoubleSideStairsTop2:
if (_engine->_movements->processActorX - collisionX >= _engine->_movements->processActorZ - collisionZ) {
brickShape = ShapeType::kStairsTopRight;
} else {
brickShape = ShapeType::kStairsTopLeft;
}
break;
case ShapeType::kDoubleSideStairsBottom2:
if (_engine->_movements->processActorZ - collisionZ <= _engine->_movements->processActorX - collisionX) {
brickShape = ShapeType::kStairsBottomRight;
} else {
brickShape = ShapeType::kStairsBottomLeft;
}
break;
case ShapeType::kDoubleSideStairsLeft2:
if (512 - _engine->_movements->processActorX - collisionX <= _engine->_movements->processActorZ - collisionZ) {
brickShape = ShapeType::kStairsBottomLeft;
} else {
brickShape = ShapeType::kStairsTopLeft;
}
break;
case ShapeType::kDoubleSideStairsRight2:
if (512 - _engine->_movements->processActorX - collisionX <= _engine->_movements->processActorZ - collisionZ) {
brickShape = ShapeType::kStairsBottomRight;
} else {
brickShape = ShapeType::kStairsTopRight;
}
break;
default:
if (_engine->cfgfile.Debug) {
debug("Brick Shape %d unsupported", (int)brickShape);
}
break;
}
}
if (brickShape >= ShapeType::kStairsTopLeft && brickShape <= ShapeType::kStairsBottomRight) {
switch (brickShape) {
case ShapeType::kStairsTopLeft:
_engine->_movements->processActorY = brkY + getAverageValue(0, 256, 512, _engine->_movements->processActorX - brkX);
break;
case ShapeType::kStairsTopRight:
_engine->_movements->processActorY = brkY + getAverageValue(0, 256, 512, _engine->_movements->processActorZ - brkZ);
break;
case ShapeType::kStairsBottomLeft:
_engine->_movements->processActorY = brkY + getAverageValue(256, 0, 512, _engine->_movements->processActorZ - brkZ);
break;
case ShapeType::kStairsBottomRight:
_engine->_movements->processActorY = brkY + getAverageValue(256, 0, 512, _engine->_movements->processActorX - brkX);
break;
default:
break;
}
}
}
int32 Collision::checkCollisionWithActors(int32 actorIdx) {
ActorStruct *actor = _engine->_scene->getActor(actorIdx);
int32 xLeft = _engine->_movements->processActorX + actor->boudingBox.x.bottomLeft;
int32 xRight = _engine->_movements->processActorX + actor->boudingBox.x.topRight;
int32 yLeft = _engine->_movements->processActorY + actor->boudingBox.y.bottomLeft;
int32 yRight = _engine->_movements->processActorY + actor->boudingBox.y.topRight;
int32 zLeft = _engine->_movements->processActorZ + actor->boudingBox.z.bottomLeft;
int32 zRight = _engine->_movements->processActorZ + actor->boudingBox.z.topRight;
actor->collision = -1;
for (int32 a = 0; a < _engine->_scene->sceneNumActors; a++) {
ActorStruct *actorTest = _engine->_scene->getActor(a);
// aviod current processed actor
if (a != actorIdx && actorTest->entity != -1 && !actor->staticFlags.bComputeLowCollision && actorTest->standOn != actorIdx) {
const int32 xLeftTest = actorTest->x + actorTest->boudingBox.x.bottomLeft;
const int32 xRightTest = actorTest->x + actorTest->boudingBox.x.topRight;
const int32 yLeftTest = actorTest->y + actorTest->boudingBox.y.bottomLeft;
const int32 yRightTest = actorTest->y + actorTest->boudingBox.y.topRight;
const int32 zLeftTest = actorTest->z + actorTest->boudingBox.z.bottomLeft;
const int32 zRightTest = actorTest->z + actorTest->boudingBox.z.topRight;
if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
actor->collision = a; // mark as collision with actor a
if (actorTest->staticFlags.bIsCarrierActor) {
if (actor->dynamicFlags.bIsFalling) {
_engine->_movements->processActorY = yRightTest - actor->boudingBox.y.bottomLeft + 1;
actor->standOn = a;
} else {
if (standingOnActor(actorIdx, a)) {
_engine->_movements->processActorY = yRightTest - actor->boudingBox.y.bottomLeft + 1;
actor->standOn = a;
} else {
int32 newAngle = _engine->_movements->getAngleAndSetTargetActorDistance(_engine->_movements->processActorX, _engine->_movements->processActorZ, actorTest->x, actorTest->z);
if (actorTest->staticFlags.bCanBePushed && !actor->staticFlags.bCanBePushed) {
actorTest->lastY = 0;
if (actorTest->staticFlags.bUseMiniZv) {
if (newAngle >= 0x80 && newAngle < 0x180 && actor->angle > 0x80 && actor->angle < 0x180) {
actorTest->lastX = 192;
}
if (newAngle >= 0x180 && newAngle < 0x280 && actor->angle > 0x180 && actor->angle < 0x280) {
actorTest->lastZ = -64;
}
if (newAngle >= 0x280 && newAngle < 0x380 && actor->angle > 0x280 && actor->angle < 0x380) {
actorTest->lastX = -64;
}
if ((newAngle >= 0x380 || newAngle < 0x80) && (actor->angle > 0x380 || actor->angle < 0x80)) {
actorTest->lastX = 192;
}
} else {
actorTest->lastX = _engine->_movements->processActorX - actor->collisionX;
actorTest->lastZ = _engine->_movements->processActorZ - actor->collisionZ;
}
}
if ((actorTest->boudingBox.x.topRight - actorTest->boudingBox.x.bottomLeft == actorTest->boudingBox.z.topRight - actorTest->boudingBox.z.bottomLeft) &&
(actor->boudingBox.x.topRight - actor->boudingBox.x.bottomLeft == actor->boudingBox.z.topRight - actor->boudingBox.z.bottomLeft)) {
if (newAngle < 0x180) {
_engine->_movements->processActorX = xLeftTest - actor->boudingBox.x.topRight;
}
if (newAngle >= 0x180 && newAngle < 0x280) {
_engine->_movements->processActorZ = zRightTest - actor->boudingBox.z.bottomLeft;
}
if (newAngle >= 0x280 && newAngle < 0x380) {
_engine->_movements->processActorX = xRightTest - actor->boudingBox.x.bottomLeft;
}
if (newAngle >= 0x380 || (newAngle < 0x380 && newAngle < 0x80)) {
_engine->_movements->processActorZ = zLeftTest - actor->boudingBox.z.topRight;
}
} else {
if (!actor->dynamicFlags.bIsFalling) {
_engine->_movements->processActorX = _engine->_movements->previousActorX;
_engine->_movements->processActorY = _engine->_movements->previousActorY;
_engine->_movements->processActorZ = _engine->_movements->previousActorZ;
}
}
}
}
} else {
if (standingOnActor(actorIdx, a)) {
_engine->_actor->hitActor(actorIdx, a, 1, -1);
}
int32 newAngle = _engine->_movements->getAngleAndSetTargetActorDistance(_engine->_movements->processActorX, _engine->_movements->processActorZ, actorTest->x, actorTest->z);
if (actorTest->staticFlags.bCanBePushed && !actor->staticFlags.bCanBePushed) {
actorTest->lastY = 0;
if (actorTest->staticFlags.bUseMiniZv) {
if (newAngle >= 0x80 && newAngle < 0x180 && actor->angle > 0x80 && actor->angle < 0x180) {
actorTest->lastX = 192;
}
if (newAngle >= 0x180 && newAngle < 0x280 && actor->angle > 0x180 && actor->angle < 0x280) {
actorTest->lastZ = -64;
}
if (newAngle >= 0x280 && newAngle < 0x380 && actor->angle > 0x280 && actor->angle < 0x380) {
actorTest->lastX = -64;
}
if ((newAngle >= 0x380 || newAngle < 0x80) && (actor->angle > 0x380 || actor->angle < 0x80)) {
actorTest->lastX = 192;
}
} else {
actorTest->lastX = _engine->_movements->processActorX - actor->collisionX;
actorTest->lastZ = _engine->_movements->processActorZ - actor->collisionZ;
}
}
if ((actorTest->boudingBox.x.topRight - actorTest->boudingBox.x.bottomLeft == actorTest->boudingBox.z.topRight - actorTest->boudingBox.z.bottomLeft) &&
(actor->boudingBox.x.topRight - actor->boudingBox.x.bottomLeft == actor->boudingBox.z.topRight - actor->boudingBox.z.bottomLeft)) {
if (newAngle < 0x180) {
_engine->_movements->processActorX = xLeftTest - actor->boudingBox.x.topRight;
}
if (newAngle >= 0x180 && newAngle < 0x280) {
_engine->_movements->processActorZ = zRightTest - actor->boudingBox.z.bottomLeft;
}
if (newAngle >= 0x280 && newAngle < 0x380) {
_engine->_movements->processActorX = xRightTest - actor->boudingBox.x.bottomLeft;
}
if (newAngle >= 0x380 || (newAngle < 0x380 && newAngle < 0x80)) {
_engine->_movements->processActorZ = zLeftTest - actor->boudingBox.z.topRight;
}
} else {
if (!actor->dynamicFlags.bIsFalling) {
_engine->_movements->processActorX = _engine->_movements->previousActorX;
_engine->_movements->processActorY = _engine->_movements->previousActorY;
_engine->_movements->processActorZ = _engine->_movements->previousActorZ;
}
}
}
}
}
}
if (actor->dynamicFlags.bIsHitting) {
_engine->_movements->rotateActor(0, 200, actor->angle);
xLeft = _engine->_renderer->destX + _engine->_movements->processActorX + actor->boudingBox.x.bottomLeft;
xRight = _engine->_renderer->destX + _engine->_movements->processActorX + actor->boudingBox.x.topRight;
yLeft = _engine->_movements->processActorY + actor->boudingBox.y.bottomLeft;
yRight = _engine->_movements->processActorY + actor->boudingBox.y.topRight;
zLeft = _engine->_renderer->destZ + _engine->_movements->processActorZ + actor->boudingBox.z.bottomLeft;
zRight = _engine->_renderer->destZ + _engine->_movements->processActorZ + actor->boudingBox.z.topRight;
for (int32 a = 0; a < _engine->_scene->sceneNumActors; a++) {
const ActorStruct *actorTest = _engine->_scene->getActor(a);
// aviod current processed actor
if (a != actorIdx && actorTest->entity != -1 && !actorTest->staticFlags.bIsHidden && actorTest->standOn != actorIdx) {
const int32 xLeftTest = actorTest->x + actorTest->boudingBox.x.bottomLeft;
const int32 xRightTest = actorTest->x + actorTest->boudingBox.x.topRight;
const int32 yLeftTest = actorTest->y + actorTest->boudingBox.y.bottomLeft;
const int32 yRightTest = actorTest->y + actorTest->boudingBox.y.topRight;
const int32 zLeftTest = actorTest->z + actorTest->boudingBox.z.bottomLeft;
const int32 zRightTest = actorTest->z + actorTest->boudingBox.z.topRight;
if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
_engine->_actor->hitActor(actorIdx, a, actor->strengthOfHit, actor->angle + ANGLE_90);
actor->dynamicFlags.bIsHitting = 0;
}
}
}
}
return actor->collision;
}
void Collision::checkHeroCollisionWithBricks(int32 x, int32 y, int32 z, int32 damageMask) {
ShapeType brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
_engine->_movements->processActorX += x;
_engine->_movements->processActorY += y;
_engine->_movements->processActorZ += z;
if (_engine->_movements->processActorX >= 0 && _engine->_movements->processActorZ >= 0 && _engine->_movements->processActorX <= 0x7E00 && _engine->_movements->processActorZ <= 0x7E00) {
reajustActorPosition(brickShape);
brickShape = _engine->_grid->getBrickShapeFull(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ, _engine->_actor->processActorPtr->boudingBox.y.topRight);
if (brickShape == ShapeType::kSolid) {
causeActorDamage |= damageMask;
brickShape = _engine->_grid->getBrickShapeFull(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->previousActorZ + z, _engine->_actor->processActorPtr->boudingBox.y.topRight);
if (brickShape == ShapeType::kSolid) {
brickShape = _engine->_grid->getBrickShapeFull(x + _engine->_movements->previousActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ, _engine->_actor->processActorPtr->boudingBox.y.topRight);
if (brickShape != ShapeType::kSolid) {
processCollisionX = _engine->_movements->previousActorX;
}
} else {
processCollisionZ = _engine->_movements->previousActorZ;
}
}
}
_engine->_movements->processActorX = processCollisionX;
_engine->_movements->processActorY = processCollisionY;
_engine->_movements->processActorZ = processCollisionZ;
}
void Collision::checkActorCollisionWithBricks(int32 x, int32 y, int32 z, int32 damageMask) {
ShapeType brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
_engine->_movements->processActorX += x;
_engine->_movements->processActorY += y;
_engine->_movements->processActorZ += z;
if (_engine->_movements->processActorX >= 0 && _engine->_movements->processActorZ >= 0 && _engine->_movements->processActorX <= 0x7E00 && _engine->_movements->processActorZ <= 0x7E00) {
reajustActorPosition(brickShape);
brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
if (brickShape == ShapeType::kSolid) {
causeActorDamage |= damageMask;
brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->previousActorZ + z);
if (brickShape == ShapeType::kSolid) {
brickShape = _engine->_grid->getBrickShape(x + _engine->_movements->previousActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
if (brickShape != ShapeType::kSolid) {
processCollisionX = _engine->_movements->previousActorX;
}
} else {
processCollisionZ = _engine->_movements->previousActorZ;
}
}
}
_engine->_movements->processActorX = processCollisionX;
_engine->_movements->processActorY = processCollisionY;
_engine->_movements->processActorZ = processCollisionZ;
}
void Collision::stopFalling() { // ReceptionObj()
if (IS_HERO(_engine->_animations->currentlyProcessedActorIdx)) {
const int32 fall = _engine->_scene->heroYBeforeFall - _engine->_movements->processActorY;
if (fall >= 2048) {
_engine->_extra->addExtraSpecial(_engine->_actor->processActorPtr->x, _engine->_actor->processActorPtr->y + 1000, _engine->_actor->processActorPtr->z, ExtraSpecialType::kHitStars);
_engine->_actor->processActorPtr->life--;
_engine->_animations->initAnim(AnimationTypes::kLandingHit, 2, AnimationTypes::kStanding, _engine->_animations->currentlyProcessedActorIdx);
} else if (fall > 10) {
_engine->_animations->initAnim(AnimationTypes::kLanding, 2, AnimationTypes::kStanding, _engine->_animations->currentlyProcessedActorIdx);
} else {
_engine->_animations->initAnim(AnimationTypes::kStanding, 0, AnimationTypes::kStanding, _engine->_animations->currentlyProcessedActorIdx);
}
_engine->_scene->heroYBeforeFall = 0;
} else {
_engine->_animations->initAnim(AnimationTypes::kLanding, 2, _engine->_actor->processActorPtr->animExtra, _engine->_animations->currentlyProcessedActorIdx);
}
_engine->_actor->processActorPtr->dynamicFlags.bIsFalling = 0;
}
int32 Collision::checkExtraCollisionWithActors(ExtraListStruct *extra, int32 actorIdx) {
Common::MemoryReadStream stream(_engine->_resources->spriteBoundingBoxPtr, _engine->_resources->spriteBoundingBoxSize);
stream.seek(extra->info0 * 16);
stream.skip(4);
const int32 xLeft = stream.readSint16LE() + extra->x;
const int32 xRight = stream.readSint16LE() + extra->x;
const int32 yLeft = stream.readSint16LE() + extra->y;
const int32 yRight = stream.readSint16LE() + extra->y;
const int32 zLeft = stream.readSint16LE() + extra->z;
const int32 zRight = stream.readSint16LE() + extra->z;
for (int32 a = 0; a < _engine->_scene->sceneNumActors; a++) {
const ActorStruct *actorTest = _engine->_scene->getActor(a);
if (a != actorIdx && actorTest->entity != -1) {
const int32 xLeftTest = actorTest->x + actorTest->boudingBox.x.bottomLeft;
const int32 xRightTest = actorTest->x + actorTest->boudingBox.x.topRight;
const int32 yLeftTest = actorTest->y + actorTest->boudingBox.y.bottomLeft;
const int32 yRightTest = actorTest->y + actorTest->boudingBox.y.topRight;
const int32 zLeftTest = actorTest->z + actorTest->boudingBox.z.bottomLeft;
const int32 zRightTest = actorTest->z + actorTest->boudingBox.z.topRight;
if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
if (extra->strengthOfHit != 0) {
_engine->_actor->hitActor(actorIdx, a, extra->strengthOfHit, -1);
}
return a;
}
}
}
return -1;
}
bool Collision::checkExtraCollisionWithBricks(int32 x, int32 y, int32 z, int32 oldX, int32 oldY, int32 oldZ) {
if (_engine->_grid->getBrickShape(oldX, oldY, oldZ) != ShapeType::kNone) {
return true;
}
const int32 averageX = ABS(x + oldX) / 2;
const int32 averageY = ABS(y + oldY) / 2;
const int32 averageZ = ABS(z + oldZ) / 2;
if (_engine->_grid->getBrickShape(averageX, averageY, averageZ) != ShapeType::kNone) {
return true;
}
if (_engine->_grid->getBrickShape(ABS(oldX + averageX) / 2, ABS(oldY + averageY) / 2, ABS(oldZ + averageZ) / 2) != ShapeType::kNone) {
return true;
}
if (_engine->_grid->getBrickShape(ABS(x + averageX) / 2, ABS(y + averageY) / 2, ABS(z + averageZ) / 2) != ShapeType::kNone) {
return true;
}
return false;
}
int32 Collision::checkExtraCollisionWithExtra(ExtraListStruct *extra, int32 extraIdx) {
Common::MemoryReadStream stream(_engine->_resources->spriteBoundingBoxPtr, _engine->_resources->spriteBoundingBoxSize);
stream.seek(extra->info0 * 16);
stream.skip(4);
const int32 xLeft = stream.readSint16LE() + extra->x;
const int32 xRight = stream.readSint16LE() + extra->x;
const int32 yLeft = stream.readSint16LE() + extra->y;
const int32 yRight = stream.readSint16LE() + extra->y;
const int32 zLeft = stream.readSint16LE() + extra->z;
const int32 zRight = stream.readSint16LE() + extra->z;
for (int32 i = 0; i < EXTRA_MAX_ENTRIES; i++) {
const ExtraListStruct *extraTest = &_engine->_extra->extraList[i];
if (i != extraIdx && extraTest->info0 != -1) {
// const int16 * spriteBoundingTest;
// spriteBoundingTest = (const int16*)(_engine->_resources->spriteBoundingBoxPtr + extraTest->info0 * 16 + 4);
const int32 xLeftTest = stream.readSint16LE() + extraTest->x;
const int32 xRightTest = stream.readSint16LE() + extraTest->x;
const int32 yLeftTest = stream.readSint16LE() + extraTest->y;
const int32 yRightTest = stream.readSint16LE() + extraTest->y;
const int32 zLeftTest = stream.readSint16LE() + extraTest->z;
const int32 zRightTest = stream.readSint16LE() + extraTest->z;
if (xLeft < xLeftTest) {
if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
return i;
}
}
}
}
return -1;
}
} // namespace TwinE