mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-09 19:32:11 +00:00
37bbfc168b
also converted the code to the coding guidelines of the scummvm team
913 lines
26 KiB
C++
913 lines
26 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 "twine/extra.h"
|
|
#include "common/util.h"
|
|
#include "twine/collision.h"
|
|
#include "twine/gamestate.h"
|
|
#include "twine/grid.h"
|
|
#include "twine/interface.h"
|
|
#include "twine/movements.h"
|
|
#include "twine/redraw.h"
|
|
#include "twine/renderer.h"
|
|
#include "twine/resources.h"
|
|
#include "twine/scene.h"
|
|
#include "twine/sound.h"
|
|
#include "twine/twine.h"
|
|
|
|
namespace TwinE {
|
|
|
|
/** Hit Stars shape info */
|
|
static const int16 hitStarsShapeTable[] = {
|
|
10,
|
|
0,
|
|
-20,
|
|
4,
|
|
-6,
|
|
19,
|
|
-6,
|
|
7,
|
|
2,
|
|
12,
|
|
16,
|
|
0,
|
|
7,
|
|
-12,
|
|
16,
|
|
-7,
|
|
2,
|
|
-19,
|
|
-6,
|
|
-4,
|
|
-6};
|
|
|
|
/** Explode Cloud shape info */
|
|
static const int16 explodeCloudShapeTable[] = {
|
|
18,
|
|
0,
|
|
-20,
|
|
6,
|
|
-16,
|
|
8,
|
|
-10,
|
|
14,
|
|
-12,
|
|
20,
|
|
-4,
|
|
18,
|
|
4,
|
|
12,
|
|
4,
|
|
16,
|
|
8,
|
|
8,
|
|
16,
|
|
2,
|
|
12,
|
|
-4,
|
|
18,
|
|
-10,
|
|
16,
|
|
-12,
|
|
8,
|
|
-16,
|
|
10,
|
|
-20,
|
|
4,
|
|
-12,
|
|
-8,
|
|
-6,
|
|
-6,
|
|
-10,
|
|
-12};
|
|
|
|
Extra::Extra(TwinEEngine *engine) : _engine(engine) {}
|
|
|
|
int32 Extra::addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 targetActor, int32 maxSpeed, int32 strengthOfHit) {
|
|
int32 i;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 == -1) {
|
|
extra->info0 = info0;
|
|
extra->type = 0x80;
|
|
extra->info1 = 0;
|
|
extra->x = X;
|
|
extra->y = Y;
|
|
extra->z = Z;
|
|
extra->actorIdx = actorIdx;
|
|
extra->lifeTime = targetActor;
|
|
extra->destZ = maxSpeed;
|
|
extra->strengthOfHit = strengthOfHit;
|
|
|
|
_engine->_movements->setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
|
|
extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(X, Z, _engine->_scene->sceneActors[targetActor].x, _engine->_scene->sceneActors[targetActor].z);
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int32 Extra::addExtraExplode(int32 X, int32 Y, int32 Z) {
|
|
int32 i;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 == -1) {
|
|
extra->info0 = 0x61;
|
|
extra->type = 0x1001;
|
|
extra->info1 = 0;
|
|
extra->x = X;
|
|
extra->y = Y;
|
|
extra->z = Z;
|
|
extra->actorIdx = 0x28;
|
|
extra->lifeTime = _engine->lbaTime;
|
|
extra->strengthOfHit = 0;
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void Extra::resetExtras() {
|
|
int32 i;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
extra->info0 = -1;
|
|
extra->info1 = 1;
|
|
}
|
|
}
|
|
|
|
void Extra::throwExtra(ExtraListStruct *extra, int32 var1, int32 var2, int32 var3, int32 var4) { // InitFly
|
|
extra->type |= 2;
|
|
|
|
extra->lastX = extra->x;
|
|
extra->lastY = extra->y;
|
|
extra->lastZ = extra->z;
|
|
|
|
_engine->_movements->rotateActor(var3, 0, var1);
|
|
|
|
extra->destY = -_engine->_renderer->destZ;
|
|
|
|
_engine->_movements->rotateActor(0, _engine->_renderer->destX, var2);
|
|
|
|
extra->destX = _engine->_renderer->destX;
|
|
extra->destZ = _engine->_renderer->destZ;
|
|
|
|
extra->angle = var4;
|
|
extra->lifeTime = _engine->lbaTime;
|
|
}
|
|
|
|
void Extra::addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type) { // InitSpecial
|
|
int32 i;
|
|
int16 flag = 0x8000 + type;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 == -1) {
|
|
extra->info0 = flag;
|
|
extra->info1 = 0;
|
|
|
|
if (type == kHitStars) {
|
|
extra->type = 9;
|
|
|
|
extra->x = X;
|
|
extra->y = Y;
|
|
extra->z = Z;
|
|
|
|
// same as InitFly
|
|
throwExtra(extra, _engine->getRandomNumber(0x100) + 0x80, _engine->getRandomNumber(0x400), 50, 20);
|
|
|
|
extra->strengthOfHit = 0;
|
|
extra->lifeTime = _engine->lbaTime;
|
|
extra->actorIdx = 100;
|
|
|
|
return;
|
|
}
|
|
if (type == kExplodeCloud) {
|
|
extra->type = 1;
|
|
|
|
extra->x = X;
|
|
extra->y = Y;
|
|
extra->z = Z;
|
|
|
|
extra->strengthOfHit = 0;
|
|
extra->lifeTime = _engine->lbaTime;
|
|
extra->actorIdx = 5;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 Extra::addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 type, int32 bonusAmount) { // ExtraBonus
|
|
int32 i;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 == -1) {
|
|
extra->info0 = type;
|
|
extra->type = 0x4071;
|
|
|
|
/*if(type == SPRITEHQR_KEY) {
|
|
extra->type = 0x4030;
|
|
}*/
|
|
|
|
extra->x = X;
|
|
extra->y = Y;
|
|
extra->z = Z;
|
|
|
|
// same as InitFly
|
|
throwExtra(extra, param, angle, 40, 15);
|
|
|
|
extra->strengthOfHit = 0;
|
|
extra->lifeTime = _engine->lbaTime;
|
|
extra->actorIdx = 1000;
|
|
extra->info1 = bonusAmount;
|
|
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int32 Extra::addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int32 var2, int32 var3, int32 var4, int32 var5, int32 strengthOfHit) { // ThrowExtra
|
|
int32 i;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 == -1) {
|
|
extra->info0 = sprite;
|
|
extra->type = 0x210C;
|
|
extra->x = X;
|
|
extra->y = Y;
|
|
extra->z = Z;
|
|
|
|
// same as InitFly
|
|
throwExtra(extra, var2, var3, var4, var5);
|
|
|
|
extra->strengthOfHit = strengthOfHit;
|
|
extra->lifeTime = _engine->lbaTime;
|
|
extra->actorIdx = actorIdx;
|
|
extra->info1 = 0;
|
|
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int32 Extra::addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 targetActorIdx, int32 maxSpeed, int32 strengthOfHit) { // ExtraSearch
|
|
int32 i;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 == -1) {
|
|
extra->info0 = spriteIdx;
|
|
extra->type = 0x80;
|
|
extra->info1 = 0;
|
|
extra->x = X;
|
|
extra->y = Y;
|
|
extra->z = Z;
|
|
extra->actorIdx = actorIdx;
|
|
extra->lifeTime = targetActorIdx;
|
|
extra->destZ = maxSpeed;
|
|
extra->strengthOfHit = strengthOfHit;
|
|
_engine->_movements->setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
|
|
extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(X, Z, _engine->_scene->sceneActors[targetActorIdx].x, _engine->_scene->sceneActors[targetActorIdx].z);
|
|
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// cseg01:00018168
|
|
int32 Extra::findExtraKey() {
|
|
int32 i;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 == SPRITEHQR_KEY) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// cseg01:00018250
|
|
int32 Extra::addExtraAimingAtKey(int32 actorIdx, int32 x, int32 y, int32 z, int32 spriteIdx, int32 extraIdx) { // addMagicBallAimingAtKey
|
|
int32 i;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 == -1) {
|
|
extra->info0 = spriteIdx;
|
|
extra->type = 0x200;
|
|
extra->info1 = 0;
|
|
extra->x = x;
|
|
extra->y = y;
|
|
extra->z = z;
|
|
extra->actorIdx = extraIdx;
|
|
extra->destZ = 0x0FA0;
|
|
extra->strengthOfHit = 0;
|
|
_engine->_movements->setActorAngle(0, 0x0FA0, 50, &extra->trackActorMove);
|
|
extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(x, z, extraList[extraIdx].x, extraList[extraIdx].z);
|
|
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void Extra::addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle, int32 param2, int32 param3) { // ThrowMagicBall
|
|
int32 ballSprite = -1;
|
|
int32 ballStrength = 0;
|
|
int32 extraIdx = -1;
|
|
|
|
switch (_engine->_gameState->magicLevelIdx) {
|
|
case 0:
|
|
case 1:
|
|
ballSprite = 1;
|
|
ballStrength = 4;
|
|
break;
|
|
case 2:
|
|
ballSprite = 42;
|
|
ballStrength = 6;
|
|
break;
|
|
case 3:
|
|
ballSprite = 43;
|
|
ballStrength = 8;
|
|
break;
|
|
case 4:
|
|
ballSprite = 13;
|
|
ballStrength = 10;
|
|
break;
|
|
}
|
|
|
|
_engine->_gameState->magicBallNumBounce = ((_engine->_gameState->inventoryMagicPoints - 1) / 20) + 1;
|
|
if (_engine->_gameState->inventoryMagicPoints == 0) {
|
|
_engine->_gameState->magicBallNumBounce = 0;
|
|
}
|
|
|
|
extraIdx = findExtraKey();
|
|
if (extraIdx != -1) { // there is a key to aim
|
|
_engine->_gameState->magicBallNumBounce = 5;
|
|
}
|
|
|
|
switch (_engine->_gameState->magicBallNumBounce) {
|
|
case 0:
|
|
_engine->_gameState->magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
|
|
break;
|
|
case 1:
|
|
_engine->_gameState->magicBallAuxBounce = 4;
|
|
_engine->_gameState->magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
_engine->_gameState->magicBallNumBounce = 1;
|
|
_engine->_gameState->magicBallAuxBounce = 4;
|
|
_engine->_gameState->magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
|
|
break;
|
|
case 5:
|
|
_engine->_gameState->magicBallIdx = addExtraAimingAtKey(0, X, Y, Z, ballSprite, extraIdx);
|
|
break;
|
|
}
|
|
|
|
if (_engine->_gameState->inventoryMagicPoints > 0) {
|
|
_engine->_gameState->inventoryMagicPoints--;
|
|
}
|
|
}
|
|
|
|
void Extra::drawSpecialShape(const int16 *shapeTable, int32 X, int32 Y, int32 color, int32 angle, int32 size) {
|
|
int16 currentShapeTable;
|
|
int16 var_8;
|
|
int16 temp1;
|
|
int32 computedX;
|
|
int32 computedY;
|
|
int32 oldComputedX;
|
|
int32 oldComputedY;
|
|
int32 numEntries;
|
|
int32 currentX;
|
|
int32 currentY;
|
|
|
|
currentShapeTable = *(shapeTable++);
|
|
|
|
var_8 = ((*(shapeTable++)) * size) >> 4;
|
|
temp1 = ((*(shapeTable++)) * size) >> 4;
|
|
|
|
_engine->_redraw->renderLeft = 0x7D00;
|
|
_engine->_redraw->renderRight = -0x7D00;
|
|
_engine->_redraw->renderTop = 0x7D00;
|
|
_engine->_redraw->renderBottom = -0x7D00;
|
|
|
|
_engine->_movements->rotateActor(var_8, temp1, angle);
|
|
|
|
computedX = _engine->_renderer->destX + X;
|
|
computedY = _engine->_renderer->destZ + Y;
|
|
|
|
if (computedX < _engine->_redraw->renderLeft)
|
|
_engine->_redraw->renderLeft = computedX;
|
|
|
|
if (computedX > _engine->_redraw->renderRight)
|
|
_engine->_redraw->renderRight = computedX;
|
|
|
|
if (computedY < _engine->_redraw->renderTop)
|
|
_engine->_redraw->renderTop = computedY;
|
|
|
|
if (computedY > _engine->_redraw->renderBottom)
|
|
_engine->_redraw->renderBottom = computedY;
|
|
|
|
numEntries = 1;
|
|
|
|
currentX = computedX;
|
|
currentY = computedY;
|
|
|
|
while (numEntries < currentShapeTable) {
|
|
var_8 = ((*(shapeTable++)) * size) >> 4;
|
|
temp1 = ((*(shapeTable++)) * size) >> 4;
|
|
|
|
oldComputedX = currentX;
|
|
oldComputedY = currentY;
|
|
|
|
_engine->_renderer->projPosX = currentX;
|
|
_engine->_renderer->projPosY = currentY;
|
|
|
|
_engine->_movements->rotateActor(var_8, temp1, angle);
|
|
|
|
currentX = _engine->_renderer->destX + X;
|
|
currentY = _engine->_renderer->destZ + Y;
|
|
|
|
if (currentX < _engine->_redraw->renderLeft)
|
|
_engine->_redraw->renderLeft = currentX;
|
|
|
|
if (currentX > _engine->_redraw->renderRight)
|
|
_engine->_redraw->renderRight = currentX;
|
|
|
|
if (currentY < _engine->_redraw->renderTop)
|
|
_engine->_redraw->renderTop = currentY;
|
|
|
|
if (currentY > _engine->_redraw->renderBottom)
|
|
_engine->_redraw->renderBottom = currentY;
|
|
|
|
_engine->_renderer->projPosX = currentX;
|
|
_engine->_renderer->projPosY = currentY;
|
|
|
|
_engine->_interface->drawLine(oldComputedX, oldComputedY, currentX, currentY, color);
|
|
|
|
numEntries++;
|
|
|
|
currentX = _engine->_renderer->projPosX;
|
|
currentY = _engine->_renderer->projPosY;
|
|
}
|
|
|
|
_engine->_renderer->projPosX = currentX;
|
|
_engine->_renderer->projPosY = currentY;
|
|
_engine->_interface->drawLine(currentX, currentY, computedX, computedY, color);
|
|
}
|
|
|
|
void Extra::drawExtraSpecial(int32 extraIdx, int32 X, int32 Y) {
|
|
int32 specialType;
|
|
ExtraListStruct *extra = &extraList[extraIdx];
|
|
|
|
specialType = extra->info0 & 0x7FFF;
|
|
|
|
switch (specialType) {
|
|
case kHitStars:
|
|
drawSpecialShape(hitStarsShapeTable, X, Y, 15, (_engine->lbaTime << 5) & 0x300, 4);
|
|
break;
|
|
case kExplodeCloud: {
|
|
int32 cloudTime = 1 + _engine->lbaTime - extra->lifeTime;
|
|
|
|
if (cloudTime > 32) {
|
|
cloudTime = 32;
|
|
}
|
|
|
|
drawSpecialShape(explodeCloudShapeTable, X, Y, 15, 0, cloudTime);
|
|
} break;
|
|
}
|
|
}
|
|
|
|
void Extra::processMagicballBounce(ExtraListStruct *extra, int32 X, int32 Y, int32 Z) {
|
|
if (_engine->_grid->getBrickShape(X, extra->y, Z)) {
|
|
extra->destY = -extra->destY;
|
|
}
|
|
if (_engine->_grid->getBrickShape(extra->x, Y, Z)) {
|
|
extra->destX = -extra->destX;
|
|
}
|
|
if (_engine->_grid->getBrickShape(X, Y, extra->z)) {
|
|
extra->destZ = -extra->destZ;
|
|
}
|
|
|
|
extra->x = X;
|
|
extra->lastX = X;
|
|
extra->y = Y;
|
|
extra->lastY = Y;
|
|
extra->z = Z;
|
|
extra->lastZ = Z;
|
|
|
|
extra->lifeTime = _engine->lbaTime;
|
|
}
|
|
|
|
/** Process extras */
|
|
void Extra::processExtras() {
|
|
int32 i;
|
|
|
|
int32 currentExtraX = 0;
|
|
int32 currentExtraY = 0;
|
|
int32 currentExtraZ = 0;
|
|
int32 currentExtraSpeedX = 0;
|
|
int32 currentExtraSpeedY = 0;
|
|
|
|
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
|
ExtraListStruct *extra = &extraList[i];
|
|
if (extra->info0 != -1) {
|
|
// process extra life time
|
|
if (extra->type & 0x1) {
|
|
if (extra->actorIdx + extra->lifeTime <= _engine->lbaTime) {
|
|
extra->info0 = -1;
|
|
continue;
|
|
}
|
|
}
|
|
// reset extra
|
|
if (extra->type & 0x800) {
|
|
extra->info0 = -1;
|
|
continue;
|
|
}
|
|
//
|
|
if (extra->type & 0x1000) {
|
|
extra->info0 = _engine->_collision->getAverageValue(97, 100, 30, _engine->lbaTime - extra->lifeTime);
|
|
continue;
|
|
}
|
|
// process extra moving
|
|
if (extra->type & 0x2) {
|
|
currentExtraX = extra->x;
|
|
currentExtraY = extra->y;
|
|
currentExtraZ = extra->z;
|
|
|
|
currentExtraSpeedX = extra->destX * (_engine->lbaTime - extra->lifeTime);
|
|
extra->x = currentExtraSpeedX + extra->lastX;
|
|
|
|
currentExtraSpeedY = extra->destY * (_engine->lbaTime - extra->lifeTime);
|
|
currentExtraSpeedY += extra->lastY;
|
|
extra->y = currentExtraSpeedY - ABS(((extra->angle * (_engine->lbaTime - extra->lifeTime)) * (_engine->lbaTime - extra->lifeTime)) >> 4);
|
|
|
|
extra->z = extra->destZ * (_engine->lbaTime - extra->lifeTime) + extra->lastZ;
|
|
|
|
// check if extra is out of scene
|
|
if (extra->y < 0 || extra->x < 0 || extra->x > 0x7E00 || extra->z < 0 || extra->z > 0x7E00) {
|
|
// if extra is Magic Ball
|
|
if (i == _engine->_gameState->magicBallIdx) {
|
|
int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
|
|
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
|
|
}
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
|
|
}
|
|
|
|
_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 10000, 0);
|
|
}
|
|
|
|
// if can take extra on ground
|
|
if (extra->type & 0x20) {
|
|
extra->type &= 0xFFED;
|
|
} else {
|
|
extra->info0 = -1;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
//
|
|
if (extra->type & 0x4000) {
|
|
if (_engine->lbaTime - extra->lifeTime > 40) {
|
|
extra->type &= 0xBFFF;
|
|
}
|
|
continue;
|
|
}
|
|
// process actor target hit
|
|
if (extra->type & 0x80) {
|
|
int32 actorIdx, actorIdxAttacked, tmpAngle, angle;
|
|
|
|
actorIdxAttacked = extra->lifeTime;
|
|
actorIdx = extra->actorIdx;
|
|
|
|
currentExtraX = _engine->_scene->sceneActors[actorIdxAttacked].x;
|
|
currentExtraY = _engine->_scene->sceneActors[actorIdxAttacked].y + 1000;
|
|
currentExtraZ = _engine->_scene->sceneActors[actorIdxAttacked].z;
|
|
|
|
tmpAngle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->x, extra->z, currentExtraX, currentExtraZ);
|
|
angle = (tmpAngle - extra->angle) & 0x3FF;
|
|
|
|
if (angle > 400 && angle < 600) {
|
|
if (extra->strengthOfHit) {
|
|
_engine->_actor->hitActor(actorIdx, actorIdxAttacked, extra->strengthOfHit, -1);
|
|
}
|
|
|
|
if (i == _engine->_gameState->magicBallIdx) {
|
|
_engine->_gameState->magicBallIdx = -1;
|
|
}
|
|
|
|
extra->info0 = -1;
|
|
continue;
|
|
} else {
|
|
const int32 angle2 = _engine->_movements->getAngleAndSetTargetActorDistance(extra->y, 0, currentExtraY, _engine->_movements->targetActorDistance);
|
|
|
|
int32 pos = _engine->_movements->getRealAngle(&extra->trackActorMove);
|
|
|
|
if (!pos) {
|
|
pos = 1;
|
|
}
|
|
|
|
_engine->_movements->rotateActor(pos, 0, angle2);
|
|
extra->y -= _engine->_renderer->destZ;
|
|
|
|
_engine->_movements->rotateActor(0, _engine->_renderer->destX, tmpAngle);
|
|
extra->x += _engine->_renderer->destX;
|
|
extra->z += _engine->_renderer->destZ;
|
|
|
|
_engine->_movements->setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
|
|
|
|
if (actorIdxAttacked == _engine->_collision->checkExtraCollisionWithActors(extra, actorIdx)) {
|
|
if (i == _engine->_gameState->magicBallIdx) {
|
|
_engine->_gameState->magicBallIdx = -1;
|
|
}
|
|
|
|
extra->info0 = -1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
// process magic ball extra aiming for key
|
|
if (extra->type & 0x200) {
|
|
// int32 actorIdxAttacked = extra->lifeTime;
|
|
ExtraListStruct *extraKey = &extraList[extra->actorIdx];
|
|
int32 actorIdx = extra->actorIdx;
|
|
|
|
int32 tmpAngle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->x, extra->z, extraKey->x, extraKey->z);
|
|
int32 angle = (tmpAngle - extra->angle) & 0x3FF;
|
|
|
|
if (angle > 400 && angle < 600) {
|
|
_engine->_sound->playSample(97, 0x1000, 1, _engine->_scene->sceneHero->x, _engine->_scene->sceneHero->y, _engine->_scene->sceneHero->z, 0);
|
|
|
|
if (extraKey->info1 > 1) {
|
|
_engine->_renderer->projectPositionOnScreen(extraKey->x - _engine->_grid->cameraX, extraKey->y - _engine->_grid->cameraY, extraKey->z - _engine->_grid->cameraZ);
|
|
_engine->_redraw->addOverlay(koNumber, extraKey->info1, _engine->_renderer->projPosX, _engine->_renderer->projPosY, koNormal, 0, 2);
|
|
}
|
|
|
|
_engine->_redraw->addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
|
|
|
|
_engine->_gameState->inventoryNumKeys += extraKey->info1;
|
|
extraKey->info0 = -1;
|
|
|
|
extra->info0 = -1;
|
|
_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, SPRITEHQR_KEY, 0, 8000, 0);
|
|
continue;
|
|
}
|
|
int32 angle2 = _engine->_movements->getAngleAndSetTargetActorDistance(extra->y, 0, extraKey->y, _engine->_movements->targetActorDistance);
|
|
int32 pos = _engine->_movements->getRealAngle(&extra->trackActorMove);
|
|
|
|
if (!pos) {
|
|
pos = 1;
|
|
}
|
|
|
|
_engine->_movements->rotateActor(pos, 0, angle2);
|
|
extra->y -= _engine->_renderer->destZ;
|
|
|
|
_engine->_movements->rotateActor(0, _engine->_renderer->destX, tmpAngle);
|
|
extra->x += _engine->_renderer->destX;
|
|
extra->z += _engine->_renderer->destZ;
|
|
|
|
_engine->_movements->setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
|
|
|
|
if (actorIdx == _engine->_collision->checkExtraCollisionWithExtra(extra, _engine->_gameState->magicBallIdx)) {
|
|
_engine->_sound->playSample(97, 0x1000, 1, _engine->_scene->sceneHero->x, _engine->_scene->sceneHero->y, _engine->_scene->sceneHero->z, 0);
|
|
|
|
if (extraKey->info1 > 1) {
|
|
_engine->_renderer->projectPositionOnScreen(extraKey->x - _engine->_grid->cameraX, extraKey->y - _engine->_grid->cameraY, extraKey->z - _engine->_grid->cameraZ);
|
|
_engine->_redraw->addOverlay(koNumber, extraKey->info1, _engine->_renderer->projPosX, _engine->_renderer->projPosY, koNormal, 0, 2);
|
|
}
|
|
|
|
_engine->_redraw->addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
|
|
|
|
_engine->_gameState->inventoryNumKeys += extraKey->info1;
|
|
extraKey->info0 = -1;
|
|
|
|
extra->info0 = -1;
|
|
_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, SPRITEHQR_KEY, 0, 8000, 0);
|
|
continue;
|
|
}
|
|
if (extraKey->info0 == -1) {
|
|
int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
|
|
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
|
|
}
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
|
|
}
|
|
|
|
extra->info0 = -1;
|
|
_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 8000, 0);
|
|
continue;
|
|
}
|
|
}
|
|
// process extra collision with actors
|
|
if (extra->type & 0x4) {
|
|
if (_engine->_collision->checkExtraCollisionWithActors(extra, extra->actorIdx) != -1) {
|
|
// if extra is Magic Ball
|
|
if (i == _engine->_gameState->magicBallIdx) {
|
|
int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
|
|
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
|
|
}
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
|
|
}
|
|
|
|
_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 10000, 0);
|
|
}
|
|
|
|
extra->info0 = -1;
|
|
continue;
|
|
}
|
|
}
|
|
// process extra collision with scene ground
|
|
if (extra->type & 0x8) {
|
|
int32 process = 0;
|
|
|
|
if (_engine->_collision->checkExtraCollisionWithBricks(currentExtraX, currentExtraY, currentExtraZ, extra->x, extra->y, extra->z)) {
|
|
// if not touch the ground
|
|
if (!(extra->type & 0x2000)) {
|
|
process = 1;
|
|
}
|
|
} else {
|
|
// if touch the ground
|
|
if (extra->type & 0x2000) {
|
|
extra->type &= 0xDFFF; // set flag out of ground
|
|
}
|
|
}
|
|
|
|
if (process) {
|
|
// show explode cloud
|
|
if (extra->type & 0x100) {
|
|
addExtraSpecial(currentExtraX, currentExtraY, currentExtraZ, kExplodeCloud);
|
|
}
|
|
// if extra is magic ball
|
|
if (i == _engine->_gameState->magicBallIdx) {
|
|
// FIXME: add constant for sample index
|
|
_engine->_sound->playSample(86, _engine->getRandomNumber(300) + 3946, 1, extra->x, extra->y, extra->z, -1);
|
|
|
|
// cant bounce with not magic points
|
|
if (_engine->_gameState->magicBallNumBounce <= 0) {
|
|
int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
|
|
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
|
|
}
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
|
|
}
|
|
|
|
_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 10000, 0);
|
|
|
|
extra->info0 = -1;
|
|
continue;
|
|
}
|
|
|
|
// if has magic points
|
|
if (_engine->_gameState->magicBallNumBounce == 1) {
|
|
if (!_engine->_gameState->magicBallAuxBounce--) {
|
|
int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
|
|
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
|
|
}
|
|
if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
|
|
spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
|
|
}
|
|
|
|
_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 10000, 0);
|
|
|
|
extra->info0 = -1;
|
|
continue;
|
|
} else {
|
|
processMagicballBounce(extra, currentExtraX, currentExtraY, currentExtraZ);
|
|
}
|
|
}
|
|
} else {
|
|
extra->info0 = -1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
// extra stop moving while collision with bricks
|
|
if (extra->type & 0x10) {
|
|
int32 process = 0;
|
|
|
|
if (_engine->_collision->checkExtraCollisionWithBricks(currentExtraX, currentExtraY, currentExtraZ, extra->x, extra->y, extra->z)) {
|
|
// if not touch the ground
|
|
if (!(extra->type & 0x2000)) {
|
|
process = 1;
|
|
}
|
|
} else {
|
|
// if touch the ground
|
|
if (extra->type & 0x2000) {
|
|
extra->type &= 0xDFFF; // set flag out of ground
|
|
}
|
|
}
|
|
|
|
if (process) {
|
|
int16 *spriteBounds;
|
|
|
|
spriteBounds = (int16 *)(_engine->_scene->spriteBoundingBoxPtr + extra->info0 * 16 + 8);
|
|
extra->y = (_engine->_collision->collisionY << 8) + 0x100 - *(spriteBounds);
|
|
extra->type &= 0xFFED;
|
|
continue;
|
|
}
|
|
}
|
|
// get extras on ground
|
|
if ((extra->type & 0x20) && !(extra->type & 0x2)) {
|
|
// if hero touch extra
|
|
if (_engine->_collision->checkExtraCollisionWithActors(extra, -1) == 0) {
|
|
// FIXME: add constant for sample index
|
|
_engine->_sound->playSample(97, 0x1000, 1, extra->x, extra->y, extra->z, -1);
|
|
|
|
if (extra->info1 > 1 && !(_engine->loopPressedKey & 2)) {
|
|
_engine->_renderer->projectPositionOnScreen(extra->x - _engine->_grid->cameraX, extra->y - _engine->_grid->cameraY, extra->z - _engine->_grid->cameraZ);
|
|
_engine->_redraw->addOverlay(koNumber, extra->info1, _engine->_renderer->projPosX, _engine->_renderer->projPosY, 158, koNormal, 2);
|
|
}
|
|
|
|
_engine->_redraw->addOverlay(koSprite, extra->info0, 10, 30, 0, koNormal, 2);
|
|
|
|
if (extra->info0 == SPRITEHQR_KASHES) {
|
|
_engine->_gameState->inventoryNumKashes += extra->info1;
|
|
if (_engine->_gameState->inventoryNumKashes > 999) {
|
|
_engine->_gameState->inventoryNumKashes = 999;
|
|
}
|
|
}
|
|
|
|
if (extra->info0 == SPRITEHQR_LIFEPOINTS) {
|
|
_engine->_scene->sceneHero->life += extra->info1;
|
|
if (_engine->_scene->sceneHero->life > 50) {
|
|
_engine->_scene->sceneHero->life = 50;
|
|
}
|
|
}
|
|
|
|
if (extra->info0 == SPRITEHQR_MAGICPOINTS && _engine->_gameState->magicLevelIdx) {
|
|
_engine->_gameState->inventoryMagicPoints += extra->info1 * 2;
|
|
if (_engine->_gameState->inventoryMagicPoints > _engine->_gameState->magicLevelIdx * 20) {
|
|
_engine->_gameState->inventoryMagicPoints = _engine->_gameState->magicLevelIdx * 20;
|
|
}
|
|
}
|
|
|
|
if (extra->info0 == SPRITEHQR_KEY) {
|
|
_engine->_gameState->inventoryNumKeys += extra->info1;
|
|
}
|
|
|
|
if (extra->info0 == SPRITEHQR_CLOVERLEAF) {
|
|
_engine->_gameState->inventoryNumLeafs += extra->info1;
|
|
if (_engine->_gameState->inventoryNumLeafs > _engine->_gameState->inventoryNumLeafsBox) {
|
|
_engine->_gameState->inventoryNumLeafs = _engine->_gameState->inventoryNumLeafsBox;
|
|
}
|
|
}
|
|
|
|
extra->info0 = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace TwinE
|