mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-20 19:21:46 +00:00
TWINE: initial import
This commit is contained in:
parent
cff369a14b
commit
bc35611293
540
engines/twine/actor.cpp
Normal file
540
engines/twine/actor.cpp
Normal file
@ -0,0 +1,540 @@
|
||||
/** @file actor.cpp
|
||||
@brief
|
||||
This file contains scene actor routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "actor.h"
|
||||
#include "lbaengine.h"
|
||||
#include "scene.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "resources.h"
|
||||
#include "renderer.h"
|
||||
#include "grid.h"
|
||||
#include "animations.h"
|
||||
#include "renderer.h"
|
||||
#include "movements.h"
|
||||
#include "gamestate.h"
|
||||
#include "sound.h"
|
||||
#include "extra.h"
|
||||
|
||||
/** Actors 3D body table - size of NUM_BODIES */
|
||||
uint8 *bodyTable[NUM_BODIES];
|
||||
|
||||
/** Restart hero variables while opening new scenes */
|
||||
void restartHeroScene() {
|
||||
sceneHero->controlMode = 1;
|
||||
memset(&sceneHero->dynamicFlags, 0, 2);
|
||||
memset(&sceneHero->staticFlags, 0, 2);
|
||||
|
||||
sceneHero->staticFlags.bComputeCollisionWithObj = 1;
|
||||
sceneHero->staticFlags.bComputeCollisionWithBricks = 1;
|
||||
sceneHero->staticFlags.bIsZonable = 1;
|
||||
sceneHero->staticFlags.bCanDrown = 1;
|
||||
sceneHero->staticFlags.bCanFall = 1;
|
||||
|
||||
sceneHero->armor = 1;
|
||||
sceneHero->positionInMoveScript = -1;
|
||||
sceneHero->labelIdx = -1;
|
||||
sceneHero->positionInLifeScript = 0;
|
||||
sceneHero->zone = -1;
|
||||
sceneHero->angle = previousHeroAngle;
|
||||
|
||||
setActorAngleSafe(sceneHero->angle, sceneHero->angle, 0, &sceneHero->move);
|
||||
setBehaviour(previousHeroBehaviour);
|
||||
|
||||
cropBottomScreen = 0;
|
||||
}
|
||||
|
||||
/** Load hero 3D body and animations */
|
||||
void loadHeroEntities() {
|
||||
hqrGetallocEntry(&heroEntityATHLETIC, HQR_FILE3D_FILE, FILE3DHQR_HEROATHLETIC);
|
||||
sceneHero->entityDataPtr = heroEntityATHLETIC;
|
||||
heroAnimIdxATHLETIC = getBodyAnimIndex(0, 0);
|
||||
|
||||
hqrGetallocEntry(&heroEntityAGGRESSIVE, HQR_FILE3D_FILE, FILE3DHQR_HEROAGGRESSIVE);
|
||||
sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
|
||||
heroAnimIdxAGGRESSIVE = getBodyAnimIndex(0, 0);
|
||||
|
||||
hqrGetallocEntry(&heroEntityDISCRETE, HQR_FILE3D_FILE, FILE3DHQR_HERODISCRETE);
|
||||
sceneHero->entityDataPtr = heroEntityDISCRETE;
|
||||
heroAnimIdxDISCRETE = getBodyAnimIndex(0, 0);
|
||||
|
||||
hqrGetallocEntry(&heroEntityPROTOPACK, HQR_FILE3D_FILE, FILE3DHQR_HEROPROTOPACK);
|
||||
sceneHero->entityDataPtr = heroEntityPROTOPACK;
|
||||
heroAnimIdxPROTOPACK = getBodyAnimIndex(0, 0);
|
||||
|
||||
hqrGetallocEntry(&heroEntityNORMAL, HQR_FILE3D_FILE, FILE3DHQR_HERONORMAL);
|
||||
sceneHero->entityDataPtr = heroEntityNORMAL;
|
||||
heroAnimIdxNORMAL = getBodyAnimIndex(0, 0);
|
||||
|
||||
sceneHero->animExtraPtr = currentActorAnimExtraPtr;
|
||||
}
|
||||
|
||||
/** Set hero behaviour
|
||||
@param behaviour behaviour value to set */
|
||||
void setBehaviour(int32 behaviour) {
|
||||
int32 bodyIdx;
|
||||
|
||||
switch (behaviour) {
|
||||
case kNormal:
|
||||
heroBehaviour = kNormal;
|
||||
sceneHero->entityDataPtr = heroEntityNORMAL;
|
||||
break;
|
||||
case kAthletic:
|
||||
heroBehaviour = kAthletic;
|
||||
sceneHero->entityDataPtr = heroEntityATHLETIC;
|
||||
break;
|
||||
case kAggressive:
|
||||
heroBehaviour = kAggressive;
|
||||
sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
|
||||
break;
|
||||
case kDiscrete:
|
||||
heroBehaviour = kDiscrete;
|
||||
sceneHero->entityDataPtr = heroEntityDISCRETE;
|
||||
break;
|
||||
case kProtoPack:
|
||||
heroBehaviour = kProtoPack;
|
||||
sceneHero->entityDataPtr = heroEntityPROTOPACK;
|
||||
break;
|
||||
};
|
||||
|
||||
bodyIdx = sceneHero->body;
|
||||
|
||||
sceneHero->entity = -1;
|
||||
sceneHero->body = -1;
|
||||
|
||||
initModelActor(bodyIdx, 0);
|
||||
|
||||
sceneHero->anim = -1;
|
||||
sceneHero->animType = 0;
|
||||
|
||||
initAnim(kStanding, 0, 255, 0);
|
||||
}
|
||||
|
||||
/** Initialize sprite actor
|
||||
@param actorIdx sprite actor index */
|
||||
void initSpriteActor(int32 actorIdx) {
|
||||
ActorStruct *localActor = &sceneActors[actorIdx];
|
||||
|
||||
if (localActor->staticFlags.bIsSpriteActor && localActor->sprite != -1 && localActor->entity != localActor->sprite) {
|
||||
int16 *ptr = (int16 *)(spriteBoundingBoxPtr + localActor->sprite * 16 + 4);
|
||||
|
||||
localActor->entity = localActor->sprite;
|
||||
localActor->boudingBox.X.bottomLeft = *(ptr++);
|
||||
localActor->boudingBox.X.topRight = *(ptr++);
|
||||
localActor->boudingBox.Y.bottomLeft = *(ptr++);
|
||||
localActor->boudingBox.Y.topRight = *(ptr++);
|
||||
localActor->boudingBox.Z.bottomLeft = *(ptr++);
|
||||
localActor->boudingBox.Z.topRight = *(ptr++);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize 3D actor body
|
||||
@param bodyIdx 3D actor body index
|
||||
@param actorIdx 3D actor index */
|
||||
int32 initBody(int32 bodyIdx, int32 actorIdx) {
|
||||
ActorStruct *localActor;
|
||||
uint8 *bodyPtr;
|
||||
uint8 var1;
|
||||
uint8 var2;
|
||||
uint8 *bodyPtr2;
|
||||
uint8 *bodyPtr3;
|
||||
uint8 *bodyPtr4;
|
||||
// int16 *bodyPtr5;
|
||||
int16 flag;
|
||||
int32 index;
|
||||
|
||||
localActor = &sceneActors[actorIdx];
|
||||
bodyPtr = localActor->entityDataPtr;
|
||||
|
||||
do {
|
||||
var1 = *(bodyPtr++);
|
||||
|
||||
if (var1 == 0xFF)
|
||||
return (-1);
|
||||
|
||||
bodyPtr2 = bodyPtr + 1;
|
||||
|
||||
if (var1 == 1) {
|
||||
var2 = *(bodyPtr);
|
||||
|
||||
if (var2 == bodyIdx) {
|
||||
bodyPtr3 = bodyPtr2 + 1;
|
||||
flag = *((uint16*)bodyPtr3);
|
||||
|
||||
if (!(flag & 0x8000)) {
|
||||
hqrGetallocEntry(&bodyTable[currentPositionInBodyPtrTab], HQR_BODY_FILE, flag & 0xFFFF);
|
||||
|
||||
if (!bodyTable[currentPositionInBodyPtrTab]) {
|
||||
printf("HQR ERROR: Loading body entities\n");
|
||||
exit(1);
|
||||
}
|
||||
prepareIsoModel(bodyTable[currentPositionInBodyPtrTab]);
|
||||
*((uint16*)bodyPtr3) = currentPositionInBodyPtrTab + 0x8000;
|
||||
index = currentPositionInBodyPtrTab;
|
||||
currentPositionInBodyPtrTab++;
|
||||
} else {
|
||||
flag &= 0x7FFF;
|
||||
index = flag;
|
||||
}
|
||||
|
||||
bodyPtr3 += 2;
|
||||
bottomLeftX = -32000;
|
||||
|
||||
bodyPtr4 = bodyPtr3;
|
||||
bodyPtr3++;
|
||||
|
||||
if (!*bodyPtr4)
|
||||
return (index);
|
||||
|
||||
bodyPtr4 = bodyPtr3;
|
||||
bodyPtr3++;
|
||||
|
||||
if (*bodyPtr4 != 14)
|
||||
return (index);
|
||||
|
||||
// bodyPtr5 = (int16 *) bodyPtr3;
|
||||
|
||||
bottomLeftX = *((uint16*)bodyPtr3);
|
||||
bodyPtr3 += 2;
|
||||
bottomLeftY = *((uint16*)bodyPtr3);
|
||||
bodyPtr3 += 2;
|
||||
bottomLeftZ = *((uint16*)bodyPtr3);
|
||||
bodyPtr3 += 2;
|
||||
|
||||
topRightX = *((uint16*)bodyPtr3);
|
||||
bodyPtr3 += 2;
|
||||
topRightY = *((uint16*)bodyPtr3);
|
||||
bodyPtr3 += 2;
|
||||
topRightZ = *((uint16*)bodyPtr3);
|
||||
bodyPtr3 += 2;
|
||||
|
||||
return (index);
|
||||
}
|
||||
}
|
||||
|
||||
bodyPtr = *bodyPtr2 + bodyPtr2;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/** Initialize 3D actor
|
||||
@param bodyIdx 3D actor body index
|
||||
@param actorIdx 3D actor index */
|
||||
void initModelActor(int32 bodyIdx, int16 actorIdx) {
|
||||
ActorStruct *localActor;
|
||||
int32 entityIdx;
|
||||
int currentIndex;
|
||||
uint16 *ptr;
|
||||
int16 var1, var2, var3, var4;
|
||||
|
||||
int32 result, result1, result2;
|
||||
|
||||
result = 0;
|
||||
|
||||
localActor = &sceneActors[actorIdx];
|
||||
|
||||
if (localActor->staticFlags.bIsSpriteActor)
|
||||
return;
|
||||
|
||||
if (actorIdx == 0 && heroBehaviour == kProtoPack && localActor->armor != 0 && localActor->armor != 1) { // if hero
|
||||
setBehaviour(kNormal);
|
||||
}
|
||||
|
||||
if (bodyIdx != -1) {
|
||||
entityIdx = initBody(bodyIdx, actorIdx);
|
||||
} else {
|
||||
entityIdx = -1;
|
||||
}
|
||||
|
||||
if (entityIdx != -1) {
|
||||
if (localActor->entity == entityIdx)
|
||||
return;
|
||||
|
||||
localActor->entity = entityIdx;
|
||||
localActor->body = bodyIdx;
|
||||
currentIndex = localActor->entity;
|
||||
|
||||
if (bottomLeftX == -32000) {
|
||||
ptr = (uint16 *) bodyTable[localActor->entity];
|
||||
ptr++;
|
||||
|
||||
var1 = *((int16 *)ptr++);
|
||||
var2 = *((int16 *)ptr++);
|
||||
localActor->boudingBox.Y.bottomLeft = *((int16 *)ptr++);
|
||||
localActor->boudingBox.Y.topRight = *((int16 *)ptr++);
|
||||
var3 = *((int16 *)ptr++);
|
||||
var4 = *((int16 *)ptr++);
|
||||
|
||||
if (localActor->staticFlags.bUseMiniZv) {
|
||||
result1 = var2 - var1; // take smaller for bound
|
||||
result2 = var4 - var3;
|
||||
|
||||
if (result1 < result2)
|
||||
result = result1;
|
||||
else
|
||||
result = result2;
|
||||
|
||||
result = abs(result);
|
||||
result >>= 1;
|
||||
} else {
|
||||
result1 = var2 - var1; // take average for bound
|
||||
result2 = var4 - var3;
|
||||
|
||||
result = result2 + result1;
|
||||
result = abs(result);
|
||||
result >>= 2;
|
||||
}
|
||||
|
||||
localActor->boudingBox.X.bottomLeft = -result;
|
||||
localActor->boudingBox.X.topRight = result;
|
||||
localActor->boudingBox.Z.bottomLeft = -result;
|
||||
localActor->boudingBox.Z.topRight = result;
|
||||
} else {
|
||||
localActor->boudingBox.X.bottomLeft = bottomLeftX;
|
||||
localActor->boudingBox.X.topRight = topRightX;
|
||||
localActor->boudingBox.Y.bottomLeft = bottomLeftY;
|
||||
localActor->boudingBox.Y.topRight = topRightY;
|
||||
localActor->boudingBox.Z.bottomLeft = bottomLeftZ;
|
||||
localActor->boudingBox.Z.topRight = topRightZ;
|
||||
}
|
||||
|
||||
if (currentIndex == -1)
|
||||
return;
|
||||
|
||||
if (localActor->previousAnimIdx == -1)
|
||||
return;
|
||||
|
||||
copyActorInternAnim(bodyTable[currentIndex], bodyTable[localActor->entity]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
localActor->body = -1;
|
||||
localActor->entity = -1;
|
||||
|
||||
localActor->boudingBox.X.bottomLeft = 0;
|
||||
localActor->boudingBox.X.topRight = 0;
|
||||
localActor->boudingBox.Y.bottomLeft = 0;
|
||||
localActor->boudingBox.Y.topRight = 0;
|
||||
localActor->boudingBox.Z.bottomLeft = 0;
|
||||
localActor->boudingBox.Z.topRight = 0;
|
||||
}
|
||||
|
||||
/** Initialize actors
|
||||
@param actorIdx actor index to init */
|
||||
void initActor(int16 actorIdx) {
|
||||
ActorStruct *actor = &sceneActors[actorIdx];
|
||||
|
||||
if (actor->staticFlags.bIsSpriteActor) { // if sprite actor
|
||||
if (actor->strengthOfHit != 0) {
|
||||
actor->dynamicFlags.bIsHitting = 1;
|
||||
}
|
||||
|
||||
actor->entity = -1;
|
||||
|
||||
initSpriteActor(actorIdx);
|
||||
|
||||
setActorAngleSafe(0, 0, 0, &actor->move);
|
||||
|
||||
if (actor->staticFlags.bUsesClipping) {
|
||||
actor->lastX = actor->X;
|
||||
actor->lastY = actor->Y;
|
||||
actor->lastZ = actor->Z;
|
||||
}
|
||||
|
||||
} else {
|
||||
actor->entity = -1;
|
||||
|
||||
initModelActor(actor->body, actorIdx);
|
||||
|
||||
actor->previousAnimIdx = -1;
|
||||
actor->animType = 0;
|
||||
|
||||
if (actor->entity != -1) {
|
||||
initAnim(actor->anim, 0, 255, actorIdx);
|
||||
}
|
||||
|
||||
setActorAngleSafe(actor->angle, actor->angle, 0, &actor->move);
|
||||
}
|
||||
|
||||
actor->positionInMoveScript = -1;
|
||||
actor->labelIdx = -1;
|
||||
actor->positionInLifeScript = 0;
|
||||
}
|
||||
|
||||
/** Reset actor
|
||||
@param actorIdx actor index to init */
|
||||
void resetActor(int16 actorIdx) {
|
||||
ActorStruct *actor = &sceneActors[actorIdx];
|
||||
|
||||
actor->body = 0;
|
||||
actor->anim = 0;
|
||||
actor->X = 0;
|
||||
actor->Y = -1;
|
||||
actor->Z = 0;
|
||||
|
||||
actor->boudingBox.X.bottomLeft = 0;
|
||||
actor->boudingBox.X.topRight = 0;
|
||||
actor->boudingBox.Y.bottomLeft = 0;
|
||||
actor->boudingBox.Y.topRight = 0;
|
||||
actor->boudingBox.Z.bottomLeft = 0;
|
||||
actor->boudingBox.Z.topRight = 0;
|
||||
|
||||
actor->angle = 0;
|
||||
actor->speed = 40;
|
||||
actor->controlMode = 0;
|
||||
|
||||
actor->info0 = 0;
|
||||
actor->info1 = 0;
|
||||
actor->info2 = 0;
|
||||
actor->info3 = 0;
|
||||
|
||||
actor->brickShape = 0;
|
||||
actor->collision = -1;
|
||||
actor->standOn = -1;
|
||||
actor->zone = -1;
|
||||
|
||||
memset(&actor->staticFlags,0,2);
|
||||
memset(&actor->dynamicFlags,0,2);
|
||||
|
||||
actor->life = 50;
|
||||
actor->armor = 1;
|
||||
actor->hitBy = -1;
|
||||
actor->lastRotationAngle = 0;
|
||||
actor->lastX = 0;
|
||||
actor->lastY = 0;
|
||||
actor->lastZ = 0;
|
||||
actor->entity = -1;
|
||||
actor->previousAnimIdx = -1;
|
||||
actor->animType = 0;
|
||||
actor->animPosition = 0;
|
||||
|
||||
setActorAngleSafe(0, 0, 0, &actor->move);
|
||||
|
||||
actor->positionInMoveScript = -1;
|
||||
actor->positionInLifeScript = 0;
|
||||
}
|
||||
|
||||
/** Process hit actor
|
||||
@param actorIdx actor hitting index
|
||||
@param actorIdxAttacked actor attacked index
|
||||
@param strengthOfHit actor hitting strength of hit
|
||||
@param angle angle of actor hitting */
|
||||
void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle) {
|
||||
ActorStruct *actor = &sceneActors[actorIdxAttacked];
|
||||
|
||||
if (actor->life <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
actor->hitBy = actorIdx;
|
||||
|
||||
if (actor->armor <= strengthOfHit) {
|
||||
if (actor->anim == kBigHit || actor->anim == kHit2) {
|
||||
int32 tmpAnimPos;
|
||||
tmpAnimPos = actor->animPosition;
|
||||
if (actor->animExtra) {
|
||||
processAnimActions(actorIdxAttacked);
|
||||
}
|
||||
|
||||
actor->animPosition = tmpAnimPos;
|
||||
} else {
|
||||
if (angle != -1) {
|
||||
setActorAngleSafe(angle, angle, 0, &actor->move);
|
||||
}
|
||||
|
||||
if (rand() & 1) {
|
||||
initAnim(kHit2, 3, 255, actorIdxAttacked);
|
||||
} else {
|
||||
initAnim(kBigHit, 3, 255, actorIdxAttacked);
|
||||
}
|
||||
}
|
||||
|
||||
addExtraSpecial(actor->X, actor->Y + 1000, actor->Z, kHitStars);
|
||||
|
||||
if (!actorIdxAttacked) {
|
||||
heroMoved = 1;
|
||||
}
|
||||
|
||||
actor->life -= strengthOfHit;
|
||||
|
||||
if (actor->life < 0) {
|
||||
actor->life = 0;
|
||||
}
|
||||
} else {
|
||||
initAnim(kHit, 3, 255, actorIdxAttacked);
|
||||
}
|
||||
}
|
||||
|
||||
/** Process actor carrier */
|
||||
void processActorCarrier(int32 actorIdx) { // CheckCarrier
|
||||
int32 a;
|
||||
ActorStruct *actor = &sceneActors[actorIdx];
|
||||
|
||||
if (actor->staticFlags.bIsCarrierActor) {
|
||||
for (a = 0; a < sceneNumActors; a++) {
|
||||
if (actor->standOn == actorIdx) {
|
||||
actor->standOn = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Process actor extra bonus */
|
||||
void processActorExtraBonus(int32 actorIdx) { // GiveExtraBonus
|
||||
int32 a, numBonus;
|
||||
int8 bonusTable[8], currentBonus;
|
||||
ActorStruct *actor = &sceneActors[actorIdx];
|
||||
|
||||
numBonus = 0;
|
||||
|
||||
for (a = 0; a < 5; a++) {
|
||||
if (actor->bonusParameter & (1 << (a + 4))) {
|
||||
bonusTable[numBonus++] = a;
|
||||
}
|
||||
}
|
||||
|
||||
if (numBonus) {
|
||||
currentBonus = bonusTable[Rnd(numBonus)];
|
||||
// if bonus is magic an no magic level yet, then give life points
|
||||
if (!magicLevelIdx && currentBonus == 2) {
|
||||
currentBonus = 1;
|
||||
}
|
||||
currentBonus += 3;
|
||||
|
||||
if (actor->dynamicFlags.bIsDead) {
|
||||
addExtraBonus(actor->X, actor->Y, actor->Z, 0x100, 0, currentBonus, actor->bonusAmount);
|
||||
// FIXME add constant for sample index
|
||||
playSample(11, 0x1000, 1, actor->X, actor->Y, actor->Z, actorIdx);
|
||||
} else {
|
||||
int32 angle = getAngleAndSetTargetActorDistance(actor->X, actor->Z, sceneHero->X, sceneHero->Z);
|
||||
addExtraBonus(actor->X, actor->Y + actor->boudingBox.Y.topRight, actor->Z, 200, angle, currentBonus, actor->bonusAmount);
|
||||
// FIXME add constant for sample index
|
||||
playSample(11, 0x1000, 1, actor->X, actor->Y + actor->boudingBox.Y.topRight, actor->Z, actorIdx);
|
||||
}
|
||||
}
|
||||
}
|
294
engines/twine/actor.h
Normal file
294
engines/twine/actor.h
Normal file
@ -0,0 +1,294 @@
|
||||
/** @file actor.h
|
||||
@brief
|
||||
This file contains scene actor routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef ACTOR_H
|
||||
#define ACTOR_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/** Total number of sprites allowed in the game */
|
||||
#define NUM_SPRITES 200
|
||||
|
||||
/** Total number of bodies allowed in the game */
|
||||
#define NUM_BODIES 200
|
||||
|
||||
enum HeroBehaviourType {
|
||||
kNormal = 0,
|
||||
kAthletic = 1,
|
||||
kAggressive = 2,
|
||||
kDiscrete = 3,
|
||||
kProtoPack = 4
|
||||
};
|
||||
|
||||
|
||||
/** Table with all loaded sprites */
|
||||
uint8* spriteTable[NUM_SPRITES];
|
||||
/** Table with all loaded sprite sizes */
|
||||
uint32 spriteSizeTable[NUM_SPRITES];
|
||||
|
||||
/** Actors move structure */
|
||||
typedef struct ActorMoveStruct {
|
||||
int16 from;
|
||||
int16 to;
|
||||
int16 numOfStep;
|
||||
int32 timeOfChange;
|
||||
} ActorMoveStruct;
|
||||
|
||||
/** Actors zone volumique points structure */
|
||||
typedef struct ZVPoint {
|
||||
int16 bottomLeft;
|
||||
int16 topRight;
|
||||
} ZVPoint;
|
||||
|
||||
/** Actors zone volumique box structure */
|
||||
typedef struct ZVBox {
|
||||
ZVPoint X;
|
||||
ZVPoint Y;
|
||||
ZVPoint Z;
|
||||
} ZVBox;
|
||||
|
||||
/** Actors animation timer structure */
|
||||
typedef struct AnimTimerDataStruct {
|
||||
uint8* ptr;
|
||||
int32 time;
|
||||
} AnimTimerDataStruct;
|
||||
|
||||
/** Actors static flags structure */
|
||||
typedef struct StaticFlagsStruct {
|
||||
uint16 bComputeCollisionWithObj : 1; // 0x0001
|
||||
uint16 bComputeCollisionWithBricks : 1; // 0x0002
|
||||
uint16 bIsZonable : 1; // 0x0004
|
||||
uint16 bUsesClipping : 1; // 0x0008
|
||||
uint16 bCanBePushed : 1; // 0x0010
|
||||
uint16 bComputeLowCollision : 1; // 0x0020
|
||||
uint16 bCanDrown : 1; // 0x0040
|
||||
uint16 bUnk80 : 1; // 0x0080
|
||||
uint16 bUnk0100 : 1; // 0x0100
|
||||
uint16 bIsHidden : 1; // 0x0200
|
||||
uint16 bIsSpriteActor : 1; // 0x0400
|
||||
uint16 bCanFall : 1; // 0x0800
|
||||
uint16 bDoesntCastShadow : 1; // 0x1000
|
||||
uint16 bIsBackgrounded : 1; // 0x2000
|
||||
uint16 bIsCarrierActor : 1; // 0x4000
|
||||
uint16 bUseMiniZv : 1; // 0x8000
|
||||
} StaticFlagsStruct;
|
||||
|
||||
/** Actors dynamic flags structure */
|
||||
typedef struct DynamicFlagsStruct {
|
||||
uint16 bWaitHitFrame : 1; // 0x0001 wait for hit frame
|
||||
uint16 bIsHitting : 1; // 0x0002 hit frame anim
|
||||
uint16 bAnimEnded : 1; // 0x0004 anim ended in the current loop (will be looped in the next engine loop)
|
||||
uint16 bAnimFrameReached : 1; // 0x0008 new frame anim reached
|
||||
uint16 bIsVisible : 1; // 0x0010 actor has been drawn in this loop
|
||||
uint16 bIsDead : 1; // 0x0020 is dead
|
||||
uint16 bIsSpriteMoving : 1; // 0x0040 door is opening or closing (wait to reach the destination position)
|
||||
uint16 bIsRotationByAnim : 1; // 0x0080 actor rotation is managed by its animaation not by the engine
|
||||
uint16 bIsFalling : 1; // 0x0100 is falling on scene
|
||||
uint16 bUnk0200 : 1; // 0x0200 unused
|
||||
uint16 bUnk0400 : 1; // 0x0400 unused
|
||||
uint16 bUnk0800 : 1; // 0x0800 unused
|
||||
uint16 bUnk1000 : 1; // 0x1000 unused
|
||||
uint16 bUnk2000 : 1; // 0x2000 unused
|
||||
uint16 bUnk4000 : 1; // 0x4000 unused
|
||||
uint16 bUnk8000 : 1; // 0x8000 unused
|
||||
} DynamicFlagsStruct;
|
||||
|
||||
/** Actors structure */
|
||||
typedef struct ActorStruct {
|
||||
StaticFlagsStruct staticFlags;
|
||||
DynamicFlagsStruct dynamicFlags;
|
||||
|
||||
int32 entity; // costumeIndex
|
||||
int32 body;
|
||||
int32 anim;
|
||||
int32 animExtra; //field_2
|
||||
int32 brickShape; // field_3
|
||||
uint8 *animExtraPtr;
|
||||
int32 sprite; // field_8
|
||||
uint8 *entityDataPtr;
|
||||
|
||||
int32 X;
|
||||
int32 Y;
|
||||
int32 Z;
|
||||
int32 strengthOfHit; // field_66
|
||||
int32 hitBy;
|
||||
int32 bonusParameter; // field_10
|
||||
int32 angle;
|
||||
int32 speed;
|
||||
int32 controlMode;
|
||||
int32 info0; // cropLeft
|
||||
int32 info1; // cropTop
|
||||
int32 info2; // cropRight
|
||||
int32 info3; // cropBottom
|
||||
int32 followedActor; // same as info3
|
||||
int32 bonusAmount; // field_12
|
||||
int32 talkColor;
|
||||
int32 armor; // field_14
|
||||
int32 life;
|
||||
|
||||
int32 collisionX; // field_20
|
||||
int32 collisionY; // field_22
|
||||
int32 collisionZ; // field_24
|
||||
|
||||
int32 positionInMoveScript;
|
||||
uint8 *moveScript;
|
||||
|
||||
int32 positionInLifeScript;
|
||||
uint8 *lifeScript;
|
||||
|
||||
int32 labelIdx; // script label index
|
||||
int32 currentLabelPtr; // pointer to LABEL offset
|
||||
int32 pausedTrackPtr;
|
||||
|
||||
//int costumeIndex;
|
||||
int32 collision;
|
||||
int32 standPosition;
|
||||
int32 standOn;
|
||||
int32 zone;
|
||||
|
||||
int32 lastRotationAngle;
|
||||
int32 lastX;
|
||||
int32 lastZ;
|
||||
int32 lastY;
|
||||
int32 previousAnimIdx;
|
||||
int32 doorStatus;
|
||||
int32 animPosition;
|
||||
int32 animType; // field_78
|
||||
int32 brickSound; // field_7A
|
||||
|
||||
ZVBox boudingBox;
|
||||
ActorMoveStruct move;
|
||||
AnimTimerDataStruct animTimerData;
|
||||
} ActorStruct;
|
||||
|
||||
/** Actor shadow X coordinate */
|
||||
int32 shadowX;
|
||||
/** Actor shadow Y coordinate */
|
||||
int32 shadowY;
|
||||
/** Actor shadow Z coordinate */
|
||||
int32 shadowZ;
|
||||
/** Actor shadow collition type */
|
||||
int8 shadowCollisionType; // shadowVar
|
||||
|
||||
/** Hero behaviour */
|
||||
int16 heroBehaviour;
|
||||
/** Hero auto agressive mode */
|
||||
int16 autoAgressive;
|
||||
/** Previous Hero behaviour */
|
||||
int16 previousHeroBehaviour;
|
||||
/** Previous Hero angle */
|
||||
int16 previousHeroAngle;
|
||||
|
||||
int16 cropBottomScreen;
|
||||
|
||||
/** Hero 3D entity for normal behaviour */
|
||||
uint8 *heroEntityNORMAL; // file3D0
|
||||
/** Hero 3D entity for athletic behaviour */
|
||||
uint8 *heroEntityATHLETIC; // file3D1
|
||||
/** Hero 3D entity for aggressive behaviour */
|
||||
uint8 *heroEntityAGGRESSIVE; // file3D2
|
||||
/** Hero 3D entity for discrete behaviour */
|
||||
uint8 *heroEntityDISCRETE; // file3D3
|
||||
/** Hero 3D entity for protopack behaviour */
|
||||
uint8 *heroEntityPROTOPACK; // file3D4
|
||||
|
||||
/** Hero current anim for normal behaviour */
|
||||
int16 heroAnimIdxNORMAL; // TCos0Init
|
||||
/** Hero current anim for athletic behaviour */
|
||||
int16 heroAnimIdxATHLETIC; // TCos1Init
|
||||
/** Hero current anim for aggressive behaviour */
|
||||
int16 heroAnimIdxAGGRESSIVE; // TCos2Init
|
||||
/** Hero current anim for discrete behaviour */
|
||||
int16 heroAnimIdxDISCRETE; // TCos3Init
|
||||
/** Hero current anim for protopack behaviour */
|
||||
int16 heroAnimIdxPROTOPACK; // TCos4Init
|
||||
|
||||
/** Hero anim for behaviour menu */
|
||||
int16 heroAnimIdx[4]; // TCOS
|
||||
|
||||
/** Actors 3D body table - size of NUM_BODIES */
|
||||
extern uint8 *bodyTable[NUM_BODIES];
|
||||
|
||||
/** Current position in body table */
|
||||
int32 currentPositionInBodyPtrTab;
|
||||
|
||||
/** Actor bounding box bottom left X coordinate */
|
||||
int16 bottomLeftX; // loadCostumeVar
|
||||
/** Actor bounding box bottom left Y coordinate */
|
||||
int16 bottomLeftY; // loadCostumeVar2
|
||||
/** Actor bounding box bottom left Z coordinate */
|
||||
int16 bottomLeftZ; // loadCostumeVar3
|
||||
/** Actor bounding box top left X coordinate */
|
||||
int16 topRightX; // loadCostumeVar4
|
||||
/** Actor bounding box top left Y coordinate */
|
||||
int16 topRightY; // loadCostumeVar5
|
||||
/** Actor bounding box top left Z coordinate */
|
||||
int16 topRightZ; // loadCostumeVar6
|
||||
|
||||
/** Restart hero variables while opening new scenes */
|
||||
void restartHeroScene();
|
||||
|
||||
/** Load hero 3D body and animations */
|
||||
void loadHeroEntities();
|
||||
|
||||
/** Set hero behaviour
|
||||
@param behaviour behaviour value to set */
|
||||
void setBehaviour(int32 behaviour);
|
||||
|
||||
/** Initialize 3D actor body
|
||||
@param bodyIdx 3D actor body index
|
||||
@param actorIdx 3D actor index */
|
||||
int32 initBody(int32 bodyIdx, int32 actorIdx);
|
||||
|
||||
/** Preload all sprites */
|
||||
void preloadSprites();
|
||||
|
||||
/** Initialize 3D actor
|
||||
@param bodyIdx 3D actor body index
|
||||
@param actorIdx 3D actor index */
|
||||
void initModelActor(int32 bodyIdx, int16 actorIdx);
|
||||
|
||||
/** Initialize actors
|
||||
@param actorIdx actor index to init */
|
||||
void initActor(int16 actorIdx);
|
||||
|
||||
/** Reset actor
|
||||
@param actorIdx actor index to init */
|
||||
void resetActor(int16 actorIdx);
|
||||
|
||||
/** Process hit actor
|
||||
@param actorIdx actor hitting index
|
||||
@param actorIdxAttacked actor attacked index
|
||||
@param strengthOfHit actor hitting strength of hit
|
||||
@param angle angle of actor hitting */
|
||||
void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle);
|
||||
|
||||
/** Process actor carrier */
|
||||
void processActorCarrier(int32 actorIdx);
|
||||
|
||||
/** Process actor extra bonus */
|
||||
void processActorExtraBonus(int32 actorIdx);
|
||||
|
||||
#endif
|
1282
engines/twine/animations.cpp
Normal file
1282
engines/twine/animations.cpp
Normal file
File diff suppressed because it is too large
Load Diff
147
engines/twine/animations.h
Normal file
147
engines/twine/animations.h
Normal file
@ -0,0 +1,147 @@
|
||||
/** @file animations.h
|
||||
@brief
|
||||
This file contains 3D actors animations routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef ANIMATIONS_H
|
||||
#define ANIMATIONS_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "actor.h"
|
||||
|
||||
/** Total number of animations allowed in the game */
|
||||
#define NUM_ANIMS 600
|
||||
|
||||
enum AnimationTypes {
|
||||
kStanding = 0,
|
||||
kForward = 1,
|
||||
kBackward = 2,
|
||||
kTurnLeft = 3,
|
||||
kTurnRight = 4,
|
||||
kHit = 5,
|
||||
kBigHit = 6,
|
||||
kFall = 7,
|
||||
kLanding = 8,
|
||||
kLandingHit = 9,
|
||||
kLandDeath = 10,
|
||||
kAction = 11,
|
||||
kClimbLadder = 12,
|
||||
kTopLadder = 13,
|
||||
kJump = 14,
|
||||
kThrowBall = 15,
|
||||
kHide = 16,
|
||||
kKick = 17,
|
||||
kRightPunch = 18,
|
||||
kLeftPunch = 19,
|
||||
kFoundItem = 20,
|
||||
kDrawn = 21,
|
||||
kHit2 = 22,
|
||||
kSabreAttack = 23
|
||||
};
|
||||
|
||||
|
||||
/** Table with all loaded animations */
|
||||
uint8* animTable[NUM_ANIMS];
|
||||
/** Table with all loaded animations sizes */
|
||||
uint32 animSizeTable[NUM_ANIMS];
|
||||
|
||||
/** Rotation by anim and not by engine */
|
||||
int16 processRotationByAnim; // processActorVar5
|
||||
/** Last rotation angle */
|
||||
int16 processLastRotationAngle; // processActorVar6
|
||||
/** Current process actor index */
|
||||
int16 currentlyProcessedActorIdx;
|
||||
|
||||
/** Current step X coornidate */
|
||||
int16 currentStepX;
|
||||
/** Current step Y coornidate */
|
||||
int16 currentStepY;
|
||||
/** Current step Z coornidate */
|
||||
int16 currentStepZ;
|
||||
/** Current actor anim extra pointer */
|
||||
uint8 *currentActorAnimExtraPtr;
|
||||
|
||||
/** Pointer to current animation keyframe */
|
||||
uint8 *keyFramePtr;
|
||||
/** Pointer to last animation keyframe */
|
||||
uint8 *lastKeyFramePtr;
|
||||
|
||||
uint8 *animBuffer1;
|
||||
uint8 *animBuffer2;
|
||||
|
||||
/** Set animation keyframe
|
||||
@param keyframIdx Animation keyframe index
|
||||
@param animPtr Pointer to animation
|
||||
@param bodyPtr Body model poitner
|
||||
@param animTimerDataPtr Animation time data */
|
||||
int32 setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
|
||||
|
||||
/** Get total number of keyframes in animation
|
||||
@param animPtr Pointer to animation */
|
||||
int32 getNumKeyframes(uint8 *animPtr);
|
||||
|
||||
/** Get first keyframes in animation
|
||||
@param animPtr Pointer to animation */
|
||||
int32 getStartKeyframe(uint8 *animPtr);
|
||||
|
||||
/** Set new body animation
|
||||
@param animIdx Animation index
|
||||
@param animPtr Animation pointer
|
||||
@param bodyPtr Body model poitner
|
||||
@param animTimerDataPtr Animation time data */
|
||||
int32 setModelAnimation(int32 animIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
|
||||
|
||||
/** Get entity anim index (This is taken from File3D entities)
|
||||
@param animIdx Entity animation index
|
||||
@param actorIdx Actor index */
|
||||
int32 getBodyAnimIndex(int32 animIdx, int32 actorIdx);
|
||||
|
||||
/** Stock animation - copy the next keyFrame from a different buffer
|
||||
@param animPtr Animation pointer
|
||||
@param bodyPtr Body model poitner
|
||||
@param animTimerDataPtr Animation time data */
|
||||
int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
|
||||
|
||||
/** Verify animation at keyframe
|
||||
@param animIdx Animation index
|
||||
@param animPtr Animation pointer
|
||||
@param bodyPtr Body model poitner
|
||||
@param animTimerDataPtr Animation time data */
|
||||
int32 verifyAnimAtKeyframe(int32 animPos, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
|
||||
|
||||
/** Initialize animation
|
||||
@param newAnim animation to init
|
||||
@param animType animation type
|
||||
@param animExtra animation actions extra data
|
||||
@param actorIdx actor index */
|
||||
int32 initAnim(int32 newAnim, int16 animType, uint8 animExtra, int32 actorIdx);
|
||||
|
||||
/** Process acotr animation actions
|
||||
@param actorIdx Actor index */
|
||||
void processAnimActions(int32 actorIdx);
|
||||
|
||||
/** Process main loop actor animations
|
||||
@param actorIdx Actor index */
|
||||
void processActorAnimations(int32 actorIdx);
|
||||
|
||||
#endif
|
624
engines/twine/collision.cpp
Normal file
624
engines/twine/collision.cpp
Normal file
@ -0,0 +1,624 @@
|
||||
/** @file collision.cpp
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "collision.h"
|
||||
#include "scene.h"
|
||||
#include "actor.h"
|
||||
#include "movements.h"
|
||||
#include "grid.h"
|
||||
#include "main.h"
|
||||
#include "animations.h"
|
||||
#include "renderer.h"
|
||||
#include "extra.h"
|
||||
|
||||
/** Check if actor 1 is standing in actor2
|
||||
@param actorIdx1 Actor 1 index
|
||||
@param actorIdx2 Actor 2 index */
|
||||
int32 standingOnActor(int32 actorIdx1, int32 actorIdx2) { // CheckZvOnZv
|
||||
int32 x1Left, y1Left, z1Left, x1Right, y1Right, z1Right;
|
||||
int32 x2Left, y2Left, z2Left, x2Right, y2Right, z2Right;
|
||||
ActorStruct *actor1;
|
||||
ActorStruct *actor2;
|
||||
|
||||
actor1 = &sceneActors[actorIdx1];
|
||||
actor2 = &sceneActors[actorIdx2];
|
||||
|
||||
// Current actor (actor 1)
|
||||
x1Left = processActorX + actor1->boudingBox.X.bottomLeft;
|
||||
x1Right = processActorX + actor1->boudingBox.X.topRight;
|
||||
|
||||
y1Left = processActorY + actor1->boudingBox.Y.bottomLeft;
|
||||
y1Right = processActorY + actor1->boudingBox.Y.topRight;
|
||||
|
||||
z1Left = processActorZ + actor1->boudingBox.Z.bottomLeft;
|
||||
z1Right = processActorZ + actor1->boudingBox.Z.topRight;
|
||||
|
||||
// Actor 2
|
||||
x2Left = actor2->X + actor2->boudingBox.X.bottomLeft;
|
||||
x2Right = actor2->X + actor2->boudingBox.X.topRight;
|
||||
|
||||
y2Left = actor2->Y + actor2->boudingBox.Y.bottomLeft;
|
||||
y2Right = actor2->Y + actor2->boudingBox.Y.topRight;
|
||||
|
||||
z2Left = actor2->Z + actor2->boudingBox.Z.bottomLeft;
|
||||
z2Right = actor2->Z + actor2->boudingBox.Z.topRight;
|
||||
|
||||
if (x1Left >= x2Right)
|
||||
return 0; // not standing
|
||||
|
||||
if (x1Right <= x2Left)
|
||||
return 0;
|
||||
|
||||
if (y1Left > (y2Right + 1))
|
||||
return 0;
|
||||
|
||||
if (y1Left <= (y2Right - 0x100))
|
||||
return 0;
|
||||
|
||||
if (y1Right <= y2Left)
|
||||
return 0;
|
||||
|
||||
if (z1Left >= z2Right)
|
||||
return 0;
|
||||
|
||||
if (z1Right <= z2Left)
|
||||
return 0;
|
||||
|
||||
return 1; // standing
|
||||
}
|
||||
|
||||
int32 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);
|
||||
}
|
||||
|
||||
/** Reajust actor position in scene according with brick shape bellow actor
|
||||
@param brickShape Shape of brick bellow the actor */
|
||||
void reajustActorPosition(int32 brickShape) {
|
||||
int32 brkX, brkY, brkZ;
|
||||
|
||||
if (!brickShape) {
|
||||
return;
|
||||
}
|
||||
|
||||
brkX = (collisionX << 9) - 0x100;
|
||||
brkY = collisionY << 8;
|
||||
brkZ = (collisionZ << 9) - 0x100;
|
||||
|
||||
// double-side stairs
|
||||
if (brickShape >= kDoubleSideStairsTop1 && brickShape <= kDoubleSideStairsRight2) {
|
||||
switch (brickShape) {
|
||||
case kDoubleSideStairsTop1:
|
||||
if (processActorZ - collisionZ <= processActorX - collisionX) {
|
||||
brickShape = kStairsTopLeft;
|
||||
} else {
|
||||
brickShape = kStairsTopRight;
|
||||
}
|
||||
break;
|
||||
case kDoubleSideStairsBottom1:
|
||||
if (processActorZ - collisionZ <= processActorX - collisionX) {
|
||||
brickShape = kStairsBottomLeft;
|
||||
} else {
|
||||
brickShape = kStairsBottomRight;
|
||||
}
|
||||
break;
|
||||
case kDoubleSideStairsLeft1:
|
||||
if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
|
||||
brickShape = kStairsTopLeft;
|
||||
} else {
|
||||
brickShape = kStairsBottomLeft;
|
||||
}
|
||||
break;
|
||||
case kDoubleSideStairsRight1:
|
||||
if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
|
||||
brickShape = kStairsTopRight;
|
||||
} else {
|
||||
brickShape = kStairsBottomRight;
|
||||
}
|
||||
break;
|
||||
case kDoubleSideStairsTop2:
|
||||
if (processActorX - collisionX >= processActorZ - collisionZ) {
|
||||
brickShape = kStairsTopRight;
|
||||
} else {
|
||||
brickShape = kStairsTopLeft;
|
||||
}
|
||||
break;
|
||||
case kDoubleSideStairsBottom2:
|
||||
if (processActorZ - collisionZ <= processActorX - collisionX) {
|
||||
brickShape = kStairsBottomRight;
|
||||
} else {
|
||||
brickShape = kStairsBottomLeft;
|
||||
}
|
||||
break;
|
||||
case kDoubleSideStairsLeft2:
|
||||
if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
|
||||
brickShape = kStairsBottomLeft;
|
||||
} else {
|
||||
brickShape = kStairsTopLeft;
|
||||
}
|
||||
break;
|
||||
case kDoubleSideStairsRight2:
|
||||
if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
|
||||
brickShape = kStairsBottomRight;
|
||||
} else {
|
||||
brickShape = kStairsTopRight;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (cfgfile.Debug == 1) {
|
||||
printf("Brick Shape %d unsupported\n", brickShape);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (brickShape >= kStairsTopLeft && brickShape <= kStairsBottomRight) {
|
||||
switch (brickShape) {
|
||||
case kStairsTopLeft:
|
||||
processActorY = brkY + getAverageValue(0, 0x100, 0x200, processActorX - brkX);
|
||||
break;
|
||||
case kStairsTopRight:
|
||||
processActorY = brkY + getAverageValue(0, 0x100, 0x200, processActorZ - brkZ);
|
||||
break;
|
||||
case kStairsBottomLeft:
|
||||
processActorY = brkY + getAverageValue(0x100, 0, 0x200, processActorZ - brkZ);
|
||||
break;
|
||||
case kStairsBottomRight:
|
||||
processActorY = brkY + getAverageValue(0x100, 0, 0x200, processActorX - brkX);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Check collision with actors
|
||||
@param actorIx Current process actor index */
|
||||
int32 checkCollisionWithActors(int32 actorIdx) {
|
||||
int32 a, xLeft, xRight, yLeft, yRight, zLeft, zRight;
|
||||
ActorStruct *actor, *actorTest;
|
||||
|
||||
actor = &sceneActors[actorIdx];
|
||||
|
||||
xLeft = processActorX + actor->boudingBox.X.bottomLeft;
|
||||
xRight = processActorX + actor->boudingBox.X.topRight;
|
||||
|
||||
yLeft = processActorY + actor->boudingBox.Y.bottomLeft;
|
||||
yRight = processActorY + actor->boudingBox.Y.topRight;
|
||||
|
||||
zLeft = processActorZ + actor->boudingBox.Z.bottomLeft;
|
||||
zRight = processActorZ + actor->boudingBox.Z.topRight;
|
||||
|
||||
actor->collision = -1;
|
||||
|
||||
for (a = 0; a < sceneNumActors; a++) {
|
||||
actorTest = &sceneActors[a];
|
||||
|
||||
// aviod current processed actor
|
||||
if (a != actorIdx && actorTest->entity != -1 && !actor->staticFlags.bComputeLowCollision && actorTest->standOn != actorIdx) {
|
||||
int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
|
||||
|
||||
xLeftTest = actorTest->X + actorTest->boudingBox.X.bottomLeft;
|
||||
xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
|
||||
|
||||
yLeftTest = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
|
||||
yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
|
||||
|
||||
zLeftTest = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
|
||||
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) {
|
||||
processActorY = yRightTest - actor->boudingBox.Y.bottomLeft + 1;
|
||||
actor->standOn = a;
|
||||
} else {
|
||||
if (standingOnActor(actorIdx, a)) {
|
||||
processActorY = yRightTest - actor->boudingBox.Y.bottomLeft + 1;
|
||||
actor->standOn = a;
|
||||
} else {
|
||||
int32 newAngle;
|
||||
|
||||
newAngle = getAngleAndSetTargetActorDistance(processActorX, 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 = processActorX - actor->collisionX;
|
||||
actorTest->lastZ = 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) {
|
||||
processActorX = xLeftTest - actor->boudingBox.X.topRight;
|
||||
}
|
||||
if (newAngle >= 0x180 && newAngle < 0x280) {
|
||||
processActorZ = zRightTest - actor->boudingBox.Z.bottomLeft;
|
||||
}
|
||||
if (newAngle >= 0x280 && newAngle < 0x380) {
|
||||
processActorX = xRightTest - actor->boudingBox.X.bottomLeft;
|
||||
}
|
||||
if (newAngle >= 0x380 || (newAngle < 0x380 && newAngle < 0x80)) {
|
||||
processActorZ = zLeftTest - actor->boudingBox.Z.topRight;
|
||||
}
|
||||
} else {
|
||||
if (!actor->dynamicFlags.bIsFalling) {
|
||||
processActorX = previousActorX;
|
||||
processActorY = previousActorY;
|
||||
processActorZ = previousActorZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int32 newAngle;
|
||||
|
||||
if (standingOnActor(actorIdx, a)) {
|
||||
hitActor(actorIdx, a, 1, -1);
|
||||
}
|
||||
|
||||
newAngle = getAngleAndSetTargetActorDistance(processActorX, 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 = processActorX - actor->collisionX;
|
||||
actorTest->lastZ = 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) {
|
||||
processActorX = xLeftTest - actor->boudingBox.X.topRight;
|
||||
}
|
||||
if (newAngle >= 0x180 && newAngle < 0x280) {
|
||||
processActorZ = zRightTest - actor->boudingBox.Z.bottomLeft;
|
||||
}
|
||||
if (newAngle >= 0x280 && newAngle < 0x380) {
|
||||
processActorX = xRightTest - actor->boudingBox.X.bottomLeft;
|
||||
}
|
||||
if (newAngle >= 0x380 || (newAngle < 0x380 && newAngle < 0x80)) {
|
||||
processActorZ = zLeftTest - actor->boudingBox.Z.topRight;
|
||||
}
|
||||
} else {
|
||||
if (!actor->dynamicFlags.bIsFalling) {
|
||||
processActorX = previousActorX;
|
||||
processActorY = previousActorY;
|
||||
processActorZ = previousActorZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (actor->dynamicFlags.bIsHitting) {
|
||||
rotateActor(0, 200, actor->angle);
|
||||
|
||||
xLeft = destX + processActorX + actor->boudingBox.X.bottomLeft;
|
||||
xRight = destX + processActorX + actor->boudingBox.X.topRight;
|
||||
|
||||
yLeft = processActorY + actor->boudingBox.Y.bottomLeft;
|
||||
yRight = processActorY + actor->boudingBox.Y.topRight;
|
||||
|
||||
zLeft = destZ + processActorZ + actor->boudingBox.Z.bottomLeft;
|
||||
zRight = destZ + processActorZ + actor->boudingBox.Z.topRight;
|
||||
|
||||
for (a = 0; a < sceneNumActors; a++) {
|
||||
actorTest = &sceneActors[a];
|
||||
|
||||
// aviod current processed actor
|
||||
if (a != actorIdx && actorTest->entity != -1 && !actorTest->staticFlags.bIsHidden && actorTest->standOn != actorIdx) {
|
||||
int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
|
||||
|
||||
xLeftTest = actorTest->X + actorTest->boudingBox.X.bottomLeft;
|
||||
xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
|
||||
|
||||
yLeftTest = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
|
||||
yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
|
||||
|
||||
zLeftTest = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
|
||||
zRightTest = actorTest->Z + actorTest->boudingBox.Z.topRight;
|
||||
|
||||
if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
|
||||
hitActor(actorIdx, a, actor->strengthOfHit, actor->angle + 0x200);
|
||||
actor->dynamicFlags.bIsHitting = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return actor->collision;
|
||||
}
|
||||
|
||||
/** Check Hero collision with bricks
|
||||
@param X Hero X coordinate
|
||||
@param Y Hero Y coordinate
|
||||
@param Z Hero Z coordinate
|
||||
@param damageMask Cause damage mask */
|
||||
void checkHeroCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask) {
|
||||
int32 brickShape;
|
||||
|
||||
brickShape = getBrickShape(processActorX, processActorY, processActorZ);
|
||||
|
||||
processActorX += X;
|
||||
processActorY += Y;
|
||||
processActorZ += Z;
|
||||
|
||||
if (processActorX >= 0 && processActorZ >= 0 && processActorX <= 0x7E00 && processActorZ <= 0x7E00) {
|
||||
reajustActorPosition(brickShape);
|
||||
brickShape = getBrickShapeFull(processActorX, processActorY, processActorZ, processActorPtr->boudingBox.Y.topRight);
|
||||
|
||||
if (brickShape == kSolid) {
|
||||
causeActorDamage |= damageMask;
|
||||
brickShape = getBrickShapeFull(processActorX, processActorY, previousActorZ + Z, processActorPtr->boudingBox.Y.topRight);
|
||||
|
||||
if (brickShape == kSolid) {
|
||||
brickShape = getBrickShapeFull(X + previousActorX, processActorY, processActorZ, processActorPtr->boudingBox.Y.topRight);
|
||||
|
||||
if (brickShape != kSolid) {
|
||||
processCollisionX = previousActorX;
|
||||
}
|
||||
} else {
|
||||
processCollisionZ = previousActorZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processActorX = processCollisionX;
|
||||
processActorY = processCollisionY;
|
||||
processActorZ = processCollisionZ;
|
||||
}
|
||||
|
||||
/** Check other actor collision with bricks
|
||||
@param X Actor X coordinate
|
||||
@param Y Actor Y coordinate
|
||||
@param Z Actor Z coordinate
|
||||
@param damageMask Cause damage mask */
|
||||
void checkActorCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask) {
|
||||
int32 brickShape;
|
||||
|
||||
brickShape = getBrickShape(processActorX, processActorY, processActorZ);
|
||||
|
||||
processActorX += X;
|
||||
processActorY += Y;
|
||||
processActorZ += Z;
|
||||
|
||||
if (processActorX >= 0 && processActorZ >= 0 && processActorX <= 0x7E00 && processActorZ <= 0x7E00) {
|
||||
reajustActorPosition(brickShape);
|
||||
brickShape = getBrickShape(processActorX, processActorY, processActorZ);
|
||||
|
||||
if (brickShape == kSolid) {
|
||||
causeActorDamage |= damageMask;
|
||||
brickShape = getBrickShape(processActorX, processActorY, previousActorZ + Z);
|
||||
|
||||
if (brickShape == kSolid) {
|
||||
brickShape = getBrickShape(X + previousActorX, processActorY, processActorZ);
|
||||
|
||||
if (brickShape != kSolid) {
|
||||
processCollisionX = previousActorX;
|
||||
}
|
||||
} else {
|
||||
processCollisionZ = previousActorZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processActorX = processCollisionX;
|
||||
processActorY = processCollisionY;
|
||||
processActorZ = processCollisionZ;
|
||||
}
|
||||
|
||||
/** Make actor to stop falling */
|
||||
void stopFalling() { // ReceptionObj()
|
||||
int32 fall;
|
||||
|
||||
if (currentlyProcessedActorIdx == 0) {
|
||||
fall = heroYBeforeFall - processActorY;
|
||||
|
||||
if (fall >= 0x1000) {
|
||||
addExtraSpecial(processActorPtr->X, processActorPtr->Y + 1000, processActorPtr->Z, kHitStars);
|
||||
processActorPtr->life--;
|
||||
initAnim(kLandingHit, 2, 0, currentlyProcessedActorIdx);
|
||||
} else if (fall >= 0x800) {
|
||||
addExtraSpecial(processActorPtr->X, processActorPtr->Y + 1000, processActorPtr->Z, kHitStars);
|
||||
processActorPtr->life--;
|
||||
initAnim(kLandingHit, 2, 0, currentlyProcessedActorIdx);
|
||||
} else if (fall > 10) {
|
||||
initAnim(kLanding, 2, 0, currentlyProcessedActorIdx);
|
||||
} else {
|
||||
initAnim(kStanding, 0, 0, currentlyProcessedActorIdx);
|
||||
}
|
||||
|
||||
heroYBeforeFall = 0;
|
||||
} else {
|
||||
initAnim(kLanding, 2, processActorPtr->animExtra, currentlyProcessedActorIdx);
|
||||
}
|
||||
|
||||
processActorPtr->dynamicFlags.bIsFalling = 0;
|
||||
}
|
||||
|
||||
/** Check extra collision with actors
|
||||
@param extra to process
|
||||
@param actorIdx actor to check collision */
|
||||
int32 checkExtraCollisionWithActors(ExtraListStruct* extra, int32 actorIdx) {
|
||||
int32 a;
|
||||
int32 xLeft, xRight, yLeft, yRight, zLeft, zRight;
|
||||
int16 * spriteBounding;
|
||||
ActorStruct *actorTest;
|
||||
|
||||
spriteBounding = (int16*)(spriteBoundingBoxPtr + extra->info0 * 16 + 4);
|
||||
|
||||
xLeft = *(spriteBounding++) + extra->X;
|
||||
xRight = *(spriteBounding++) + extra->X;
|
||||
|
||||
yLeft = *(spriteBounding++) + extra->Y;
|
||||
yRight = *(spriteBounding++) + extra->Y;
|
||||
|
||||
zLeft = *(spriteBounding++) + extra->Z;
|
||||
zRight = *(spriteBounding++) + extra->Z;
|
||||
|
||||
for (a = 0; a < sceneNumActors; a++) {
|
||||
actorTest = &sceneActors[a];
|
||||
|
||||
if (a != actorIdx && actorTest->entity != -1) {
|
||||
int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
|
||||
|
||||
xLeftTest = actorTest->X + actorTest->boudingBox.X.bottomLeft;
|
||||
xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
|
||||
|
||||
yLeftTest = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
|
||||
yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
|
||||
|
||||
zLeftTest = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
|
||||
zRightTest = actorTest->Z + actorTest->boudingBox.Z.topRight;
|
||||
|
||||
if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
|
||||
if (extra->strengthOfHit != 0) {
|
||||
hitActor(actorIdx, a, extra->strengthOfHit, -1);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Check extra collision with bricks */
|
||||
int32 checkExtraCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 oldX, int32 oldY, int32 oldZ) {
|
||||
int32 averageX, averageY, averageZ;
|
||||
|
||||
if (getBrickShape(oldX, oldY, oldZ)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
averageX = Abs(X + oldX)/2;
|
||||
averageY = Abs(Y + oldY)/2;
|
||||
averageZ = Abs(Z + oldZ)/2;
|
||||
|
||||
if (getBrickShape(averageX, averageY, averageZ)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getBrickShape(Abs(oldX + averageX)/2, Abs(oldY + averageY)/2, Abs(oldZ + averageZ)/2)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getBrickShape(Abs(X + averageX)/2, Abs(Y + averageY)/2, Abs(Z + averageZ)/2)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Check extra collision with another extra
|
||||
@param extra to process
|
||||
@param extraIdx extra index to check collision */
|
||||
int32 checkExtraCollisionWithExtra(ExtraListStruct* extra, int32 extraIdx) {
|
||||
int32 i;
|
||||
int32 xLeft, xRight, yLeft, yRight, zLeft, zRight;
|
||||
int16 * spriteBounding;
|
||||
|
||||
spriteBounding = (int16*)(spriteBoundingBoxPtr + extra->info0 * 16 + 4);
|
||||
|
||||
xLeft = *(spriteBounding++) + extra->X;
|
||||
xRight = *(spriteBounding++) + extra->X;
|
||||
|
||||
yLeft = *(spriteBounding++) + extra->Y;
|
||||
yRight = *(spriteBounding++) + extra->Y;
|
||||
|
||||
zLeft = *(spriteBounding++) + extra->Z;
|
||||
zRight = *(spriteBounding++) + extra->Z;
|
||||
|
||||
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
||||
ExtraListStruct *extraTest = &extraList[i];
|
||||
if ( i != extraIdx && extraTest->info0 != -1) {
|
||||
int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
|
||||
// int16 * spriteBoundingTest;
|
||||
// spriteBoundingTest = (int16*)(spriteBoundingBoxPtr + extraTest->info0 * 16 + 4);
|
||||
|
||||
xLeftTest = *(spriteBounding++) + extraTest->X;
|
||||
xRightTest = *(spriteBounding++) + extraTest->X;
|
||||
|
||||
yLeftTest = *(spriteBounding++) + extraTest->Y;
|
||||
yRightTest = *(spriteBounding++) + extraTest->Y;
|
||||
|
||||
zLeftTest = *(spriteBounding++) + extraTest->Z;
|
||||
zRightTest = *(spriteBounding++) + extraTest->Z;
|
||||
|
||||
if (xLeft < xLeftTest) {
|
||||
if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
94
engines/twine/collision.h
Normal file
94
engines/twine/collision.h
Normal file
@ -0,0 +1,94 @@
|
||||
/** @file collision.h
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef COLLISION_H
|
||||
#define COLLISION_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "extra.h"
|
||||
|
||||
/** Actor collition X coordinate */
|
||||
int32 collisionX; // getPosVar1
|
||||
/** Actor collition Y coordinate */
|
||||
int32 collisionY; // getPosVar2
|
||||
/** Actor collition Z coordinate */
|
||||
int32 collisionZ; // getPosVar3
|
||||
|
||||
/** Actor collition X coordinate */
|
||||
int32 processCollisionX; // processActorVar11
|
||||
/** Actor collition Y coordinate */
|
||||
int32 processCollisionY; // processActorVar12
|
||||
/** Actor collition Z coordinate */
|
||||
int32 processCollisionZ; // processActorVar13
|
||||
|
||||
/** Cause damage in current processed actor */
|
||||
int32 causeActorDamage; //fieldCauseDamage
|
||||
|
||||
/** Check if actor 1 is standing in actor2
|
||||
@param actorIdx1 Actor 1 index
|
||||
@param actorIdx2 Actor 2 index */
|
||||
int32 standingOnActor(int32 actorIdx1, int32 actorIdx2);
|
||||
|
||||
int32 getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3);
|
||||
|
||||
/** Reajust actor position in scene according with brick shape bellow actor
|
||||
@param brickShape Shape of brick bellow the actor */
|
||||
void reajustActorPosition(int32 brickShape);
|
||||
|
||||
/** Check collision with actors
|
||||
@param actorIx Current process actor index */
|
||||
int32 checkCollisionWithActors(int32 actorIdx);
|
||||
|
||||
/** Check Hero collision with bricks
|
||||
@param X Hero X coordinate
|
||||
@param Y Hero Y coordinate
|
||||
@param Z Hero Z coordinate
|
||||
@param damageMask Cause damage mask */
|
||||
void checkHeroCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask);
|
||||
|
||||
/** Check other actor collision with bricks
|
||||
@param X Actor X coordinate
|
||||
@param Y Actor Y coordinate
|
||||
@param Z Actor Z coordinate
|
||||
@param damageMask Cause damage mask */
|
||||
void checkActorCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask);
|
||||
|
||||
/** Make actor to stop falling */
|
||||
void stopFalling();
|
||||
|
||||
/** Check extra collision with actors
|
||||
@param extra to process
|
||||
@param actorIdx actor to check collision */
|
||||
int32 checkExtraCollisionWithActors(ExtraListStruct* extra, int32 actorIdx);
|
||||
|
||||
/** Check extra collision with bricks */
|
||||
int32 checkExtraCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 oldX, int32 oldY, int32 oldZ);
|
||||
|
||||
/** Check extra collision with another extra
|
||||
@param extra to process
|
||||
@param extraIdx extra index to check collision */
|
||||
int32 checkExtraCollisionWithExtra(ExtraListStruct* extra, int32 extraIdx);
|
||||
|
||||
#endif
|
3
engines/twine/configure.engine
Normal file
3
engines/twine/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]
|
||||
add_engine twine "Little Big Adventure" no
|
556
engines/twine/debug.cpp
Normal file
556
engines/twine/debug.cpp
Normal file
@ -0,0 +1,556 @@
|
||||
/** @file debug.cpp
|
||||
@brief
|
||||
This file contains the main game debug window routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef GAMEMOD
|
||||
#include "debug.scene.h"
|
||||
#include "debug.grid.h"
|
||||
#include "scene.h"
|
||||
#include "sdlengine.h"
|
||||
#include "menu.h"
|
||||
#include "interface.h"
|
||||
#include "text.h"
|
||||
#include "lbaengine.h"
|
||||
#include "screens.h"
|
||||
#include "redraw.h"
|
||||
|
||||
enum ButtonType {
|
||||
NO_ACTION,
|
||||
FREE_CAMERA,
|
||||
CHANGE_SCENE,
|
||||
SHOW_CELLING_GRID,
|
||||
SHOW_ZONES,
|
||||
SHOW_ZONE_CUBE,
|
||||
SHOW_ZONE_CAMERA,
|
||||
SHOW_ZONE_SCENARIC,
|
||||
SHOW_ZONE_CELLINGGRID,
|
||||
SHOW_ZONE_OBJECT,
|
||||
SHOW_ZONE_TEXT,
|
||||
SHOW_ZONE_LADDER
|
||||
};
|
||||
|
||||
enum WindowType {
|
||||
NO_MENU,
|
||||
FREE_CAMERA_INFO_MENU,
|
||||
CHANGE_SCENE_INFO_MENU,
|
||||
ZONES_MENU
|
||||
};
|
||||
|
||||
typedef struct DebugButtonStruct {
|
||||
int32 left;
|
||||
int32 top;
|
||||
int32 right;
|
||||
int32 bottom;
|
||||
int8 *text;
|
||||
int32 textLeft;
|
||||
int32 textTop;
|
||||
int32 isActive;
|
||||
int32 color;
|
||||
int32 activeColor;
|
||||
int32 submenu;
|
||||
int32 type;
|
||||
} DebugButtonStruct;
|
||||
|
||||
typedef struct DebugWindowStruct {
|
||||
int32 left;
|
||||
int32 top;
|
||||
int32 right;
|
||||
int32 bottom;
|
||||
int32 alpha;
|
||||
int32 isActive;
|
||||
int32 numLines;
|
||||
int8 *text[20];
|
||||
int32 numButtons;
|
||||
DebugButtonStruct debugButtons[50];
|
||||
} DebugWindowStruct;
|
||||
|
||||
DebugWindowStruct debugWindows[10];
|
||||
int32 numDebugWindows = 0;
|
||||
|
||||
|
||||
void debugFillButton(int32 X, int32 Y, int32 width, int32 height, int8 color) {
|
||||
int32 i, j;
|
||||
uint8 *ptr;
|
||||
int32 offset;
|
||||
|
||||
ptr = frontVideoBuffer + screenLookupTable[Y] + X;
|
||||
offset = 640 - (width);
|
||||
|
||||
for (i = 0; i < height; i++) {
|
||||
for (j = 0; j < width; j++) {
|
||||
*(ptr++) = color;
|
||||
}
|
||||
ptr += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void debugDrawButton(int32 left, int32 top, int32 right, int32 bottom, int8 *text, int32 textLeft, int32 textRight, int32 isActive, int8 color) {
|
||||
debugFillButton(left + 1, top + 1, right - left - 1, bottom - top - 1, color);
|
||||
drawBox(left, top, right, bottom);
|
||||
ttfDrawText(textLeft, textRight, text, 0);
|
||||
copyBlockPhys(left, top, right, bottom);
|
||||
}
|
||||
|
||||
void debugDrawWindowBox(int32 left, int32 top, int32 right, int32 bottom, int32 alpha) {
|
||||
drawTransparentBox(left, top, right, bottom, alpha);
|
||||
drawBox(left, top, right, bottom);
|
||||
//copyBlockPhys(left,top,right,bottom);
|
||||
}
|
||||
|
||||
void debugDrawWindowButtons(int32 w) {
|
||||
int32 b;
|
||||
|
||||
for (b = 0; b < debugWindows[w].numButtons; b++) {
|
||||
int32 left = debugWindows[w].debugButtons[b].left;
|
||||
int32 top = debugWindows[w].debugButtons[b].top;
|
||||
int32 right = debugWindows[w].debugButtons[b].right;
|
||||
int32 bottom = debugWindows[w].debugButtons[b].bottom;
|
||||
int8 *text = debugWindows[w].debugButtons[b].text;
|
||||
int32 textLeft = debugWindows[w].debugButtons[b].textLeft;
|
||||
int32 textTop = debugWindows[w].debugButtons[b].textTop;
|
||||
int32 isActive = debugWindows[w].debugButtons[b].isActive;
|
||||
int8 color = debugWindows[w].debugButtons[b].color;
|
||||
if (isActive > 0)
|
||||
color = debugWindows[w].debugButtons[b].activeColor;
|
||||
|
||||
debugDrawButton(left, top, right, bottom, text, textLeft, textTop, isActive, color);
|
||||
}
|
||||
}
|
||||
|
||||
void debugDrawWindow(int32 w) {
|
||||
int32 left = debugWindows[w].left;
|
||||
int32 top = debugWindows[w].top;
|
||||
int32 right = debugWindows[w].right;
|
||||
int32 bottom = debugWindows[w].bottom;
|
||||
int32 alpha = debugWindows[w].alpha;
|
||||
|
||||
debugDrawWindowBox(left, top, right, bottom, alpha);
|
||||
|
||||
if (debugWindows[w].numLines > 0) {
|
||||
int32 l;
|
||||
|
||||
for (l = 0; l < debugWindows[w].numLines; l++) {
|
||||
ttfDrawText(left + 10, top + l*20 + 5, debugWindows[w].text[l], 0);
|
||||
}
|
||||
}
|
||||
|
||||
copyBlockPhys(left, top, right, bottom);
|
||||
|
||||
debugDrawWindowButtons(w);
|
||||
}
|
||||
|
||||
int32 debugTypeUseMenu(int32 type) {
|
||||
int32 w, b;
|
||||
|
||||
for (w = 0; w < numDebugWindows; w++) {
|
||||
if (debugWindows[w].isActive > 0) {
|
||||
for (b = 0; b < debugWindows[w].numButtons; b++) {
|
||||
if (debugWindows[w].debugButtons[b].type == type) {
|
||||
int submenu = debugWindows[w].debugButtons[b].submenu;
|
||||
if (submenu > 0)
|
||||
debugWindows[submenu].isActive = !debugWindows[submenu].isActive;
|
||||
return submenu;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void debugResetButtonsState() {
|
||||
int w, b;
|
||||
for (w = 0; w < numDebugWindows; w++) {
|
||||
if (debugWindows[w].isActive > 0) {
|
||||
for (b = 0; b < debugWindows[w].numButtons; b++) {
|
||||
if (debugWindows[w].debugButtons[b].type <= -1)
|
||||
debugWindows[w].debugButtons[b].isActive = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debugRefreshButtons(int32 type) {
|
||||
int32 w, b;
|
||||
|
||||
for (w = 0; w < numDebugWindows; w++) {
|
||||
if (debugWindows[w].isActive > 0) {
|
||||
for (b = 0; b < debugWindows[w].numButtons; b++) {
|
||||
if (debugWindows[w].debugButtons[b].type == type) {
|
||||
int32 left = debugWindows[w].debugButtons[b].left;
|
||||
int32 top = debugWindows[w].debugButtons[b].top;
|
||||
int32 right = debugWindows[w].debugButtons[b].right;
|
||||
int32 bottom = debugWindows[w].debugButtons[b].bottom;
|
||||
int8 *text = debugWindows[w].debugButtons[b].text;
|
||||
int32 textLeft = debugWindows[w].debugButtons[b].textLeft;
|
||||
int32 textTop = debugWindows[w].debugButtons[b].textTop;
|
||||
int8 color = debugWindows[w].debugButtons[b].color;
|
||||
int32 isActive = debugWindows[w].debugButtons[b].isActive = !debugWindows[w].debugButtons[b].isActive;
|
||||
|
||||
if (isActive > 0)
|
||||
color = debugWindows[w].debugButtons[b].activeColor;
|
||||
|
||||
debugDrawButton(left, top, right, bottom, text, textLeft, textTop, isActive, color);
|
||||
|
||||
if (debugWindows[w].debugButtons[b].submenu && isActive > 0)
|
||||
debugDrawWindow(debugWindows[w].debugButtons[b].submenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debugDrawWindows() {
|
||||
int32 w;
|
||||
|
||||
for (w = 0; w < numDebugWindows; w++) {
|
||||
if (debugWindows[w].isActive > 0) {
|
||||
debugDrawWindow(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debugResetButton(int32 type) {
|
||||
int32 w, b;
|
||||
|
||||
for (w = 0; w < numDebugWindows; w++) {
|
||||
if (debugWindows[w].isActive > 0) {
|
||||
for (b = 0; b < debugWindows[w].numButtons; b++) {
|
||||
if (debugWindows[w].debugButtons[b].type == type) {
|
||||
int submenu = debugWindows[w].debugButtons[b].submenu;
|
||||
debugWindows[w].debugButtons[b].isActive = 0;
|
||||
if (submenu > 0) {
|
||||
debugWindows[submenu].debugButtons[b].isActive = !debugWindows[submenu].debugButtons[b].isActive;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debugRedrawScreen() {
|
||||
redrawEngineActions(1);
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
debugDrawWindows();
|
||||
}
|
||||
|
||||
int32 debugGetActionsState(int32 type) {
|
||||
int32 state = 0;
|
||||
|
||||
switch (type) {
|
||||
case FREE_CAMERA:
|
||||
state = useFreeCamera;
|
||||
break;
|
||||
case CHANGE_SCENE:
|
||||
state = canChangeScenes;
|
||||
break;
|
||||
case SHOW_ZONES:
|
||||
state = showingZones;
|
||||
break;
|
||||
case SHOW_ZONE_CUBE:
|
||||
case SHOW_ZONE_CAMERA:
|
||||
case SHOW_ZONE_SCENARIC:
|
||||
case SHOW_ZONE_CELLINGGRID:
|
||||
case SHOW_ZONE_OBJECT:
|
||||
case SHOW_ZONE_TEXT:
|
||||
case SHOW_ZONE_LADDER:
|
||||
state = typeZones;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void debugSetActions(int32 type) {
|
||||
switch (type) {
|
||||
case FREE_CAMERA:
|
||||
useFreeCamera = !useFreeCamera;
|
||||
break;
|
||||
|
||||
case CHANGE_SCENE:
|
||||
canChangeScenes = !canChangeScenes;
|
||||
break;
|
||||
|
||||
case SHOW_ZONES:
|
||||
showingZones = !showingZones;
|
||||
debugResetButton(-1);
|
||||
debugResetButton(-2);
|
||||
debugRedrawScreen();
|
||||
break;
|
||||
case SHOW_ZONE_CUBE:
|
||||
if (showingZones) {
|
||||
if (typeZones & 0x01)
|
||||
typeZones &= ~0x01;
|
||||
else
|
||||
typeZones |= 0x01;
|
||||
debugRedrawScreen();
|
||||
}
|
||||
break;
|
||||
case SHOW_ZONE_CAMERA:
|
||||
if (showingZones) {
|
||||
if (typeZones & 0x02)
|
||||
typeZones &= ~0x02;
|
||||
else
|
||||
typeZones |= 0x02;
|
||||
debugRedrawScreen();
|
||||
}
|
||||
break;
|
||||
case SHOW_ZONE_SCENARIC:
|
||||
if (showingZones) {
|
||||
if (typeZones & 0x04)
|
||||
typeZones &= ~0x04;
|
||||
else
|
||||
typeZones |= 0x04;
|
||||
debugRedrawScreen();
|
||||
}
|
||||
break;
|
||||
case SHOW_ZONE_CELLINGGRID:
|
||||
if (showingZones) {
|
||||
if (typeZones & 0x08)
|
||||
typeZones &= ~0x08;
|
||||
else
|
||||
typeZones |= 0x08;
|
||||
debugRedrawScreen();
|
||||
debugRedrawScreen();
|
||||
}
|
||||
break;
|
||||
case SHOW_ZONE_OBJECT:
|
||||
if (showingZones) {
|
||||
if (typeZones & 0x10)
|
||||
typeZones &= ~0x10;
|
||||
else
|
||||
typeZones |= 0x10;
|
||||
debugRedrawScreen();
|
||||
debugRedrawScreen();
|
||||
}
|
||||
break;
|
||||
case SHOW_ZONE_TEXT:
|
||||
if (showingZones) {
|
||||
if (typeZones & 0x20)
|
||||
typeZones &= ~0x20;
|
||||
else
|
||||
typeZones |= 0x20;
|
||||
debugRedrawScreen();
|
||||
}
|
||||
break;
|
||||
case SHOW_ZONE_LADDER:
|
||||
if (showingZones) {
|
||||
if (typeZones & 0x40)
|
||||
typeZones &= ~0x40;
|
||||
else
|
||||
typeZones |= 0x40;
|
||||
debugRedrawScreen();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case -1:
|
||||
debugResetButton(-2);
|
||||
debugRedrawScreen();
|
||||
break;
|
||||
case -2:
|
||||
debugResetButton(-1);
|
||||
debugRedrawScreen();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void debugAddButton(int32 window, int32 left, int32 top, int32 right, int32 bottom, int8 *text, int32 textLeft, int32 textTop, int32 isActive, int32 color, int32 activeColor, int32 submenu, int32 type) {
|
||||
int32 button = debugWindows[window].numButtons;
|
||||
debugWindows[window].debugButtons[button].left = left;
|
||||
debugWindows[window].debugButtons[button].top = top;
|
||||
debugWindows[window].debugButtons[button].right = right;
|
||||
debugWindows[window].debugButtons[button].bottom = bottom;
|
||||
debugWindows[window].debugButtons[button].text = text;
|
||||
debugWindows[window].debugButtons[button].textLeft = textLeft;
|
||||
debugWindows[window].debugButtons[button].textTop = textTop;
|
||||
debugWindows[window].debugButtons[button].isActive = debugGetActionsState(type);
|
||||
debugWindows[window].debugButtons[button].color = color;
|
||||
debugWindows[window].debugButtons[button].activeColor = activeColor;
|
||||
debugWindows[window].debugButtons[button].submenu = submenu;
|
||||
debugWindows[window].debugButtons[button].type = type;
|
||||
debugWindows[window].numButtons++;
|
||||
}
|
||||
|
||||
void debugAddWindowText(int32 window, int8 *text) {
|
||||
int32 line = debugWindows[window].numLines;
|
||||
debugWindows[window].text[line] = text;
|
||||
debugWindows[window].numLines++;
|
||||
}
|
||||
|
||||
void debugAddWindow(int32 left, int32 top, int32 right, int32 bottom, int32 alpha, int32 isActive) {
|
||||
debugWindows[numDebugWindows].left = left;
|
||||
debugWindows[numDebugWindows].top = top;
|
||||
debugWindows[numDebugWindows].right = right;
|
||||
debugWindows[numDebugWindows].bottom = bottom;
|
||||
debugWindows[numDebugWindows].alpha = alpha;
|
||||
debugWindows[numDebugWindows].numButtons = 0;
|
||||
debugWindows[numDebugWindows].isActive = isActive;
|
||||
numDebugWindows++;
|
||||
}
|
||||
|
||||
void debugLeftMenu() {
|
||||
// left menu window
|
||||
debugAddWindow(5, 60, 200, 474, 4, 1);
|
||||
debugAddButton(0, 5, 55, 160, 75, (int8*) "Use free camera", 30, 60, 0, 87, 119, NO_MENU, FREE_CAMERA);
|
||||
debugAddButton(0, 161, 55, 200, 75, (int8*) "info", 171, 60, 0, 87, 119, FREE_CAMERA_INFO_MENU, -1);
|
||||
debugAddButton(0, 5, 76, 160, 96, (int8*) "Change scenes", 30, 81, 0, 87, 119, NO_MENU, CHANGE_SCENE);
|
||||
debugAddButton(0, 161, 76, 200, 96, (int8*) "info", 171, 81, 0, 87, 119, CHANGE_SCENE_INFO_MENU, -2);
|
||||
debugAddButton(0, 5, 97, 200, 117, (int8*) "Show celling grids", 30, 102, 0, 87, 119, NO_MENU, 3);
|
||||
debugAddButton(0, 5, 118, 200, 138, (int8*) "Show zones", 30, 123, 0, 87, 119, ZONES_MENU, SHOW_ZONES);
|
||||
|
||||
// add submenu windows
|
||||
// - free camera window
|
||||
debugAddWindow(205, 55, 634, 160, 4, 0);
|
||||
debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "When enable, use the following keys to browse through the scenes:");
|
||||
debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) " - S to go North");
|
||||
debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) " - X to go South");
|
||||
debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) " - Z to go West");
|
||||
debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) " - C to go East");
|
||||
|
||||
// - change scene window
|
||||
debugAddWindow(205, 55, 634, 137, 4, 0);
|
||||
debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) "When enable, use the following keys to change to another scene:");
|
||||
debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) " - R to go Next Scene");
|
||||
debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) " - F to go Previous Scene");
|
||||
|
||||
// - zones window
|
||||
debugAddWindow(205, 55, 634, 97, 4, 0);
|
||||
debugAddWindowText(ZONES_MENU, (int8*) "You can enable or disable each zone type:");
|
||||
debugAddButton(ZONES_MENU, 205, 118, 350, 138, (int8*) "Cube Zones", 215, 123, 1, 87, 119, 0, SHOW_ZONE_CUBE);
|
||||
debugAddButton(ZONES_MENU, 205, 139, 350, 159, (int8*) "Camera Zones", 215, 144, 2, 87, 119, 0, SHOW_ZONE_CAMERA);
|
||||
debugAddButton(ZONES_MENU, 205, 160, 350, 180, (int8*) "Scenaric Zones", 215, 165, 3, 87, 119, 0, SHOW_ZONE_SCENARIC);
|
||||
debugAddButton(ZONES_MENU, 205, 181, 350, 201, (int8*) "Celling Grid Zones", 215, 186, 4, 87, 119, 0, SHOW_ZONE_CELLINGGRID);
|
||||
debugAddButton(ZONES_MENU, 205, 202, 350, 222, (int8*) "Object Zones", 215, 207, 5, 87, 119, 0, SHOW_ZONE_OBJECT);
|
||||
debugAddButton(ZONES_MENU, 205, 223, 350, 243, (int8*) "Text Zones", 215, 228, 6, 87, 119, 0, SHOW_ZONE_TEXT);
|
||||
debugAddButton(ZONES_MENU, 205, 244, 350, 264, (int8*) "Ladder Zones", 215, 249, 7, 87, 119, 0, SHOW_ZONE_LADDER);
|
||||
}
|
||||
|
||||
int32 debugProcessButton(int32 X, int32 Y) {
|
||||
int32 i;
|
||||
int32 j;
|
||||
|
||||
for (i = 0; i < numDebugWindows; i++) {
|
||||
for (j = 0; j < debugWindows[i].numButtons; j++) {
|
||||
if (X > (debugWindows[i].debugButtons[j].left)
|
||||
&& X < (debugWindows[i].debugButtons[j].right)
|
||||
&& Y > (debugWindows[i].debugButtons[j].top)
|
||||
&& Y < (debugWindows[i].debugButtons[j].bottom)) {
|
||||
return (debugWindows[i].debugButtons[j].type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void debugPlasmaWindow(int8 *text, int32 color) {
|
||||
int32 textSize;
|
||||
processPlasmaEffect(5, color);
|
||||
if (!(rand() % 5)) {
|
||||
plasmaEffectPtr[rand() % 320 * 10 + 6400] = 255;
|
||||
}
|
||||
textSize = getTextSize(text);
|
||||
drawText((SCREEN_WIDTH / 2) - (textSize / 2), 10, text);
|
||||
drawBox(5, 5, 634, 50);
|
||||
copyBlockPhys(5, 5, 634, 50);
|
||||
}
|
||||
|
||||
void debugProcessWindow() {
|
||||
if (rightMouse) {
|
||||
int32 quit = 0;
|
||||
int8* text = (int8*) "Game Debug Window";
|
||||
int32 color = 64;
|
||||
int32 colorIdx = 4;
|
||||
int32 count = 0;
|
||||
MouseStatusStruct mouseData;
|
||||
rightMouse = 0;
|
||||
leftMouse = 0;
|
||||
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
|
||||
debugResetButtonsState();
|
||||
if (numDebugWindows == 0)
|
||||
debugLeftMenu();
|
||||
debugDrawWindows();
|
||||
|
||||
do {
|
||||
readKeys();
|
||||
getMousePositions(&mouseData);
|
||||
|
||||
if (mouseData.left) {
|
||||
int type = 0;
|
||||
if ((type = debugProcessButton(mouseData.X, mouseData.Y)) != NO_ACTION) { // process menu item
|
||||
if (debugTypeUseMenu(type)) {
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
copyBlockPhys(205, 55, 634, 474);
|
||||
}
|
||||
|
||||
debugRefreshButtons(type);
|
||||
debugSetActions(type);
|
||||
}
|
||||
mouseData.left = 0;
|
||||
}
|
||||
|
||||
// draw window plasma effect
|
||||
if (count == 256) {
|
||||
colorIdx++;
|
||||
count = 0;
|
||||
}
|
||||
color = colorIdx * 16;
|
||||
if (color >= 240) {
|
||||
color = 64;
|
||||
colorIdx = 4;
|
||||
}
|
||||
debugPlasmaWindow(text, color);
|
||||
|
||||
// quit
|
||||
if (mouseData.right)
|
||||
quit = 1;
|
||||
|
||||
fpsCycles(25); // rest
|
||||
|
||||
count++;
|
||||
} while (!quit);
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void processDebug(int16 pKey) {
|
||||
debugProcessWindow();
|
||||
|
||||
changeGrid(pKey);
|
||||
changeGridCamera(pKey);
|
||||
if (needChangeScene == 0);
|
||||
applyCellingGrid(pKey);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
131
engines/twine/debug.grid.cpp
Normal file
131
engines/twine/debug.grid.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/** @file debug.grid.cpp
|
||||
@brief
|
||||
This file contains grid debug routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.grid.h"
|
||||
#include "grid.h"
|
||||
#include "lbaengine.h"
|
||||
#include "scene.h"
|
||||
#include "main.h"
|
||||
#include "redraw.h"
|
||||
|
||||
int32 useFreeCamera = 0;
|
||||
#ifdef _DEBUG
|
||||
int32 canChangeScenes = 1;
|
||||
#else
|
||||
int32 canChangeScenes = 0;
|
||||
#endif
|
||||
|
||||
/** Change scenario camera positions */
|
||||
void changeGridCamera(int16 pKey) {
|
||||
if (useFreeCamera) {
|
||||
// Press up - more X positions
|
||||
if (pKey == 0x2E) {
|
||||
newCameraZ--;
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
|
||||
// Press down - less X positions
|
||||
if (pKey == 0x2C) {
|
||||
newCameraZ++;
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
|
||||
// Press left - less Z positions
|
||||
if (pKey == 0x1F) {
|
||||
newCameraX--;
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
|
||||
// Press right - more Z positions
|
||||
if (pKey == 0x2D) {
|
||||
newCameraX++;
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Change grid index */
|
||||
void changeGrid(int16 pKey) {
|
||||
if (canChangeScenes) {
|
||||
// Press up - more X positions
|
||||
if (pKey == 0x13) {
|
||||
currentSceneIdx++;
|
||||
if (currentSceneIdx > NUM_SCENES)
|
||||
currentSceneIdx = 0;
|
||||
needChangeScene = currentSceneIdx;
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
|
||||
// Press down - less X positions
|
||||
if (pKey == 0x21) {
|
||||
currentSceneIdx--;
|
||||
if (currentSceneIdx < 0)
|
||||
currentSceneIdx = NUM_SCENES;
|
||||
needChangeScene = currentSceneIdx;
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
|
||||
if (cfgfile.Debug && (pKey == 'f' || pKey == 'r'))
|
||||
printf("\nGrid index changed: %d\n", needChangeScene);
|
||||
}
|
||||
}
|
||||
|
||||
/** Apply and change disappear celling grid */
|
||||
void applyCellingGrid(int16 pKey) {
|
||||
// Increase celling grid index
|
||||
if (pKey == 0x22) {
|
||||
cellingGridIdx++;
|
||||
if (cellingGridIdx > 133)
|
||||
cellingGridIdx = 133;
|
||||
}
|
||||
// Decrease celling grid index
|
||||
if (pKey == 0x30) {
|
||||
cellingGridIdx--;
|
||||
if (cellingGridIdx < 0)
|
||||
cellingGridIdx = 0;
|
||||
}
|
||||
|
||||
// Enable/disable celling grid
|
||||
if (pKey == 0x14 && useCellingGrid == -1) {
|
||||
useCellingGrid = 1;
|
||||
//createGridMap();
|
||||
initCellingGrid(cellingGridIdx);
|
||||
if (cfgfile.Debug && pKey == 0x14)
|
||||
printf("\nEnable Celling Grid index: %d\n", cellingGridIdx);
|
||||
needChangeScene = -2; // tricky to make the fade
|
||||
} else if (pKey == 0x14 && useCellingGrid == 1) {
|
||||
useCellingGrid = -1;
|
||||
createGridMap();
|
||||
reqBgRedraw = 1;
|
||||
if (cfgfile.Debug && pKey == 0x14)
|
||||
printf("\nDisable Celling Grid index: %d\n", cellingGridIdx);
|
||||
needChangeScene = -2; // tricky to make the fade
|
||||
}
|
||||
}
|
||||
|
41
engines/twine/debug.grid.h
Normal file
41
engines/twine/debug.grid.h
Normal file
@ -0,0 +1,41 @@
|
||||
/** @file debug.grid.h
|
||||
@brief
|
||||
This file contains grid debug routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef GRIDDEBUG_H
|
||||
#define GRIDDEBUG_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
extern int32 useFreeCamera;
|
||||
extern int32 canChangeScenes;
|
||||
|
||||
/** Change scenario camera positions */
|
||||
void changeGridCamera(int16 pKey);
|
||||
/** Change grid index */
|
||||
void changeGrid(int16 pKey);
|
||||
/** Apply and change disappear celling grid */
|
||||
void applyCellingGrid(int16 pKey);
|
||||
|
||||
#endif
|
41
engines/twine/debug.h
Normal file
41
engines/twine/debug.h
Normal file
@ -0,0 +1,41 @@
|
||||
/** @file debug.h
|
||||
@brief
|
||||
This file contains the main game debug window routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
typedef struct MouseStatusStruct {
|
||||
int32 left;
|
||||
int32 right;
|
||||
int32 X;
|
||||
int32 Y;
|
||||
} MouseStatusStruct;
|
||||
|
||||
|
||||
void processDebug(int16 pKey);
|
||||
|
||||
#endif
|
203
engines/twine/debug.scene.cpp
Normal file
203
engines/twine/debug.scene.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
/** @file debug.scene.cpp
|
||||
@brief
|
||||
This file contains scenario debug routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "debug.scene.h"
|
||||
#include "scene.h"
|
||||
#include "grid.h"
|
||||
#include "lbaengine.h"
|
||||
#include "redraw.h"
|
||||
#include "interface.h"
|
||||
#include "renderer.h"
|
||||
|
||||
int32 showingZones = 0;
|
||||
int32 typeZones = 127; // all zones on as default
|
||||
|
||||
void drawBoundingBoxProjectPoints(ScenePoint* pPoint3d, ScenePoint* pPoint3dProjected) {
|
||||
projectPositionOnScreen(pPoint3d->X, pPoint3d->Y, pPoint3d->Z);
|
||||
|
||||
pPoint3dProjected->X = projPosX;
|
||||
pPoint3dProjected->Y = projPosY;
|
||||
pPoint3dProjected->Z = projPosZ;
|
||||
|
||||
if (renderLeft > projPosX)
|
||||
renderLeft = projPosX;
|
||||
|
||||
if (renderRight < projPosX)
|
||||
renderRight = projPosX;
|
||||
|
||||
if (renderTop > projPosY)
|
||||
renderTop = projPosY;
|
||||
|
||||
if (renderBottom < projPosY)
|
||||
renderBottom = projPosY;
|
||||
}
|
||||
|
||||
int32 checkZoneType(int32 type) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
if (typeZones & 0x01)
|
||||
return 1;
|
||||
break;
|
||||
case 1:
|
||||
if (typeZones & 0x02)
|
||||
return 1;
|
||||
break;
|
||||
case 2:
|
||||
if (typeZones & 0x04)
|
||||
return 1;
|
||||
break;
|
||||
case 3:
|
||||
if (typeZones & 0x08)
|
||||
return 1;
|
||||
break;
|
||||
case 4:
|
||||
if (typeZones & 0x10)
|
||||
return 1;
|
||||
break;
|
||||
case 5:
|
||||
if (typeZones & 0x20)
|
||||
return 1;
|
||||
break;
|
||||
case 6:
|
||||
if (typeZones & 0x40)
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void displayZones(int16 pKey) {
|
||||
if (showingZones == 1) {
|
||||
int z;
|
||||
ZoneStruct *zonePtr = sceneZones;
|
||||
for (z = 0; z < sceneNumZones; z++) {
|
||||
zonePtr = &sceneZones[z];
|
||||
|
||||
if (checkZoneType(zonePtr->type)) {
|
||||
ScenePoint frontBottomLeftPoint;
|
||||
ScenePoint frontBottomRightPoint;
|
||||
|
||||
ScenePoint frontTopLeftPoint;
|
||||
ScenePoint frontTopRightPoint;
|
||||
|
||||
ScenePoint backBottomLeftPoint;
|
||||
ScenePoint backBottomRightPoint;
|
||||
|
||||
ScenePoint backTopLeftPoint;
|
||||
ScenePoint backTopRightPoint;
|
||||
|
||||
ScenePoint frontBottomLeftPoint2D;
|
||||
ScenePoint frontBottomRightPoint2D;
|
||||
|
||||
ScenePoint frontTopLeftPoint2D;
|
||||
ScenePoint frontTopRightPoint2D;
|
||||
|
||||
ScenePoint backBottomLeftPoint2D;
|
||||
ScenePoint backBottomRightPoint2D;
|
||||
|
||||
ScenePoint backTopLeftPoint2D;
|
||||
ScenePoint backTopRightPoint2D;
|
||||
|
||||
uint8 color;
|
||||
|
||||
// compute the points in 3D
|
||||
|
||||
frontBottomLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
|
||||
frontBottomLeftPoint.Y = zonePtr->bottomLeft.Y - cameraY;
|
||||
frontBottomLeftPoint.Z = zonePtr->topRight.Z - cameraZ;
|
||||
|
||||
frontBottomRightPoint.X = zonePtr->topRight.X - cameraX;
|
||||
frontBottomRightPoint.Y = zonePtr->bottomLeft.Y - cameraY;
|
||||
frontBottomRightPoint.Z = zonePtr->topRight.Z - cameraZ;
|
||||
|
||||
frontTopLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
|
||||
frontTopLeftPoint.Y = zonePtr->topRight.Y - cameraY;
|
||||
frontTopLeftPoint.Z = zonePtr->topRight.Z - cameraZ;
|
||||
|
||||
frontTopRightPoint.X = zonePtr->topRight.X - cameraX;
|
||||
frontTopRightPoint.Y = zonePtr->topRight.Y - cameraY;
|
||||
frontTopRightPoint.Z = zonePtr->topRight.Z - cameraZ;
|
||||
|
||||
backBottomLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
|
||||
backBottomLeftPoint.Y = zonePtr->bottomLeft.Y - cameraY;
|
||||
backBottomLeftPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
|
||||
|
||||
backBottomRightPoint.X = zonePtr->topRight.X - cameraX;
|
||||
backBottomRightPoint.Y = zonePtr->bottomLeft.Y - cameraY;
|
||||
backBottomRightPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
|
||||
|
||||
backTopLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
|
||||
backTopLeftPoint.Y = zonePtr->topRight.Y - cameraY;
|
||||
backTopLeftPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
|
||||
|
||||
backTopRightPoint.X = zonePtr->topRight.X - cameraX;
|
||||
backTopRightPoint.Y = zonePtr->topRight.Y - cameraY;
|
||||
backTopRightPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
|
||||
|
||||
// project all points
|
||||
|
||||
drawBoundingBoxProjectPoints(&frontBottomLeftPoint, &frontBottomLeftPoint2D);
|
||||
drawBoundingBoxProjectPoints(&frontBottomRightPoint, &frontBottomRightPoint2D);
|
||||
drawBoundingBoxProjectPoints(&frontTopLeftPoint, &frontTopLeftPoint2D);
|
||||
drawBoundingBoxProjectPoints(&frontTopRightPoint, &frontTopRightPoint2D);
|
||||
drawBoundingBoxProjectPoints(&backBottomLeftPoint, &backBottomLeftPoint2D);
|
||||
drawBoundingBoxProjectPoints(&backBottomRightPoint, &backBottomRightPoint2D);
|
||||
drawBoundingBoxProjectPoints(&backTopLeftPoint, &backTopLeftPoint2D);
|
||||
drawBoundingBoxProjectPoints(&backTopRightPoint, &backTopRightPoint2D);
|
||||
|
||||
// draw all lines
|
||||
|
||||
color = 15 * 3 + zonePtr->type * 16;
|
||||
|
||||
// draw front part
|
||||
drawLine(frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, color);
|
||||
drawLine(frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, frontTopRightPoint2D.X, frontTopRightPoint2D.Y, color);
|
||||
drawLine(frontTopRightPoint2D.X, frontTopRightPoint2D.Y, frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, color);
|
||||
drawLine(frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, color);
|
||||
|
||||
// draw top part
|
||||
drawLine(frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, backTopLeftPoint2D.X, backTopLeftPoint2D.Y, color);
|
||||
drawLine(backTopLeftPoint2D.X, backTopLeftPoint2D.Y, backTopRightPoint2D.X, backTopRightPoint2D.Y, color);
|
||||
drawLine(backTopRightPoint2D.X, backTopRightPoint2D.Y, frontTopRightPoint2D.X, frontTopRightPoint2D.Y, color);
|
||||
drawLine(frontTopRightPoint2D.X, frontTopRightPoint2D.Y, frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, color);
|
||||
|
||||
// draw back part
|
||||
drawLine(backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, backTopLeftPoint2D.X, backTopLeftPoint2D.Y, color);
|
||||
drawLine(backTopLeftPoint2D.X, backTopLeftPoint2D.Y, backTopRightPoint2D.X, backTopRightPoint2D.Y, color);
|
||||
drawLine(backTopRightPoint2D.X, backTopRightPoint2D.Y, backBottomRightPoint2D.X, backBottomRightPoint2D.Y, color);
|
||||
drawLine(backBottomRightPoint2D.X, backBottomRightPoint2D.Y, backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, color);
|
||||
|
||||
// draw bottom part
|
||||
drawLine(frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, color);
|
||||
drawLine(backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, backBottomRightPoint2D.X, backBottomRightPoint2D.Y, color);
|
||||
drawLine(backBottomRightPoint2D.X, backBottomRightPoint2D.Y, frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, color);
|
||||
drawLine(frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
engines/twine/debug.scene.h
Normal file
36
engines/twine/debug.scene.h
Normal file
@ -0,0 +1,36 @@
|
||||
/** @file debug.scene.h
|
||||
@brief
|
||||
This file contains scenario debug routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SCENE_DEBUG_H
|
||||
#define SCENE_DEBUG_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
extern int32 showingZones;
|
||||
extern int32 typeZones;
|
||||
|
||||
void displayZones(int16 pKey);
|
||||
|
||||
#endif
|
65
engines/twine/detection.cpp
Normal file
65
engines/twine/detection.cpp
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.
|
||||
*
|
||||
* 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/config-manager.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "base/plugins.h"
|
||||
#include "twine/detection.h"
|
||||
|
||||
static const PlainGameDescriptor twineGames[] = {
|
||||
{ "twine", "Little Big Adventure" },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const ADGameDescription twineGameDescriptions[] = {
|
||||
{
|
||||
"twine",
|
||||
"",
|
||||
AD_ENTRY1s("infobar.txt", "f1e42a95972643462b9c3c2ea79d6683", 543),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
TwinE::kGameFlagNoSubtitles,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
class TwinEMetaEngineDetection : public AdvancedMetaEngineDetection {
|
||||
public:
|
||||
TwinEMetaEngineDetection() : AdvancedMetaEngineDetection(twineGameDescriptions, sizeof(ADGameDescription), twineGames) {
|
||||
_md5Bytes = 512;
|
||||
}
|
||||
|
||||
const char *getEngineId() const override {
|
||||
return "twine";
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "Little Big Adventure";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Little Big Adventure (C) Adeline Software International";
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(TWINE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, TwinEMetaEngineDetection);
|
37
engines/twine/detection.h
Normal file
37
engines/twine/detection.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_DETECTION_H
|
||||
#define TWINE_DETECTION_H
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
enum GameFlag {
|
||||
kGameFlagDemo = 1 << 0,
|
||||
kGameFlagEncodedData = 1 << 1,
|
||||
kGameFlagNoSubtitles = 1 << 2,
|
||||
kGameFlagIntroOnly = 1 << 3
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif // TWINE_DETECTION_H
|
925
engines/twine/extra.cpp
Normal file
925
engines/twine/extra.cpp
Normal file
@ -0,0 +1,925 @@
|
||||
/** @file extra.cpp
|
||||
@brief
|
||||
This file contains extra (bonus, projectils, keys, etc.) routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "extra.h"
|
||||
#include "lbaengine.h"
|
||||
#include "collision.h"
|
||||
#include "resources.h"
|
||||
#include "gamestate.h"
|
||||
#include "scene.h"
|
||||
#include "movements.h"
|
||||
#include "renderer.h"
|
||||
#include "grid.h"
|
||||
#include "sound.h"
|
||||
#include "redraw.h"
|
||||
#include "interface.h"
|
||||
|
||||
/** Hit Stars shape info */
|
||||
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 */
|
||||
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
|
||||
};
|
||||
|
||||
int32 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;
|
||||
|
||||
setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
|
||||
extra->angle = getAngleAndSetTargetActorDistance(X, Z, sceneActors[targetActor].X, sceneActors[targetActor].Z);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Add extra explosion
|
||||
@param X Explostion X coordinate
|
||||
@param Y Explostion Y coordinate
|
||||
@param Z Explostion Z coordinate */
|
||||
int32 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 = lbaTime;
|
||||
extra->strengthOfHit = 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Reset all used extras */
|
||||
void resetExtras() {
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
||||
ExtraListStruct *extra = &extraList[i];
|
||||
extra->info0 = -1;
|
||||
extra->info1 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void 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;
|
||||
|
||||
rotateActor(var3, 0, var1);
|
||||
|
||||
extra->destY = -destZ;
|
||||
|
||||
rotateActor(0, destX, var2);
|
||||
|
||||
extra->destX = destX;
|
||||
extra->destZ = destZ;
|
||||
|
||||
extra->angle = var4;
|
||||
extra->lifeTime = lbaTime;
|
||||
}
|
||||
|
||||
void 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, Rnd(0x100) + 0x80, Rnd(0x400), 50, 20);
|
||||
|
||||
extra->strengthOfHit = 0;
|
||||
extra->lifeTime = lbaTime;
|
||||
extra->actorIdx = 100;
|
||||
|
||||
return;
|
||||
} else if (type == kExplodeCloud) {
|
||||
extra->type = 1;
|
||||
|
||||
extra->X = X;
|
||||
extra->Y = Y;
|
||||
extra->Z = Z;
|
||||
|
||||
extra->strengthOfHit = 0;
|
||||
extra->lifeTime = lbaTime;
|
||||
extra->actorIdx = 5;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 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 = lbaTime;
|
||||
extra->actorIdx = 1000;
|
||||
extra->info1 = bonusAmount;
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 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 = lbaTime;
|
||||
extra->actorIdx = actorIdx;
|
||||
extra->info1 = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 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;
|
||||
setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
|
||||
extra->angle = getAngleAndSetTargetActorDistance(X, Z, sceneActors[targetActorIdx].X, sceneActors[targetActorIdx].Z);
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// cseg01:00018168
|
||||
int32 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 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;
|
||||
setActorAngle(0, 0x0FA0, 50, &extra->trackActorMove);
|
||||
extra->angle = getAngleAndSetTargetActorDistance(X, Z, extraList[extraIdx].X, extraList[extraIdx].Z);
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void 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 (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;
|
||||
}
|
||||
|
||||
magicBallNumBounce = ((inventoryMagicPoints - 1) / 20) + 1;
|
||||
if (inventoryMagicPoints == 0) {
|
||||
magicBallNumBounce = 0;
|
||||
}
|
||||
|
||||
extraIdx = findExtraKey();
|
||||
if (extraIdx != -1) { // there is a key to aim
|
||||
magicBallNumBounce = 5;
|
||||
}
|
||||
|
||||
switch (magicBallNumBounce) {
|
||||
case 0:
|
||||
magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
|
||||
break;
|
||||
case 1:
|
||||
magicBallAuxBounce = 4;
|
||||
magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
magicBallNumBounce = 1;
|
||||
magicBallAuxBounce = 4;
|
||||
magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
|
||||
break;
|
||||
case 5:
|
||||
magicBallIdx = addExtraAimingAtKey(0, X, Y, Z, ballSprite, extraIdx);
|
||||
break;
|
||||
}
|
||||
|
||||
if (inventoryMagicPoints > 0) {
|
||||
inventoryMagicPoints--;
|
||||
}
|
||||
}
|
||||
|
||||
void drawSpecialShape(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;
|
||||
|
||||
renderLeft = 0x7D00;
|
||||
renderRight = -0x7D00;
|
||||
renderTop = 0x7D00;
|
||||
renderBottom = -0x7D00;
|
||||
|
||||
rotateActor(var_8, temp1, angle);
|
||||
|
||||
computedX = destX + X;
|
||||
computedY = destZ + Y;
|
||||
|
||||
if (computedX < renderLeft)
|
||||
renderLeft = computedX;
|
||||
|
||||
if (computedX > renderRight)
|
||||
renderRight = computedX;
|
||||
|
||||
if (computedY < renderTop)
|
||||
renderTop = computedY;
|
||||
|
||||
if (computedY > renderBottom)
|
||||
renderBottom = computedY;
|
||||
|
||||
numEntries = 1;
|
||||
|
||||
currentX = computedX;
|
||||
currentY = computedY;
|
||||
|
||||
while (numEntries < currentShapeTable) {
|
||||
var_8 = ((*(shapeTable++)) * size) >> 4;
|
||||
temp1 = ((*(shapeTable++)) * size) >> 4;
|
||||
|
||||
oldComputedX = currentX;
|
||||
oldComputedY = currentY;
|
||||
|
||||
projPosX = currentX;
|
||||
projPosY = currentY;
|
||||
|
||||
rotateActor(var_8, temp1, angle);
|
||||
|
||||
currentX = destX + X;
|
||||
currentY = destZ + Y;
|
||||
|
||||
if (currentX < renderLeft)
|
||||
renderLeft = currentX;
|
||||
|
||||
if (currentX > renderRight)
|
||||
renderRight = currentX;
|
||||
|
||||
if (currentY < renderTop)
|
||||
renderTop = currentY;
|
||||
|
||||
if (currentY > renderBottom)
|
||||
renderBottom = currentY;
|
||||
|
||||
projPosX = currentX;
|
||||
projPosY = currentY;
|
||||
|
||||
drawLine(oldComputedX, oldComputedY, currentX, currentY, color);
|
||||
|
||||
numEntries++;
|
||||
|
||||
currentX = projPosX;
|
||||
currentY = projPosY;
|
||||
|
||||
}
|
||||
|
||||
projPosX = currentX;
|
||||
projPosY = currentY;
|
||||
drawLine(currentX, currentY, computedX, computedY, color);
|
||||
}
|
||||
|
||||
void 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, (lbaTime << 5) & 0x300, 4);
|
||||
break;
|
||||
case kExplodeCloud: {
|
||||
int32 cloudTime = 1 + lbaTime - extra->lifeTime;
|
||||
|
||||
if (cloudTime > 32) {
|
||||
cloudTime = 32;
|
||||
}
|
||||
|
||||
drawSpecialShape(explodeCloudShapeTable, X, Y, 15, 0, cloudTime);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void processMagicballBounce(ExtraListStruct *extra, int32 X, int32 Y, int32 Z) {
|
||||
if (getBrickShape(X, extra->Y, Z)) {
|
||||
extra->destY = -extra->destY;
|
||||
}
|
||||
if (getBrickShape(extra->X, Y, Z)) {
|
||||
extra->destX = -extra->destX;
|
||||
}
|
||||
if (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 = lbaTime;
|
||||
}
|
||||
|
||||
/** Process extras */
|
||||
void 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 <= lbaTime) {
|
||||
extra->info0 = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// reset extra
|
||||
if (extra->type & 0x800) {
|
||||
extra->info0 = -1;
|
||||
continue;
|
||||
}
|
||||
//
|
||||
if (extra->type & 0x1000) {
|
||||
extra->info0 = getAverageValue(97, 100, 30, lbaTime - extra->lifeTime);
|
||||
continue;
|
||||
}
|
||||
// process extra moving
|
||||
if (extra->type & 0x2) {
|
||||
currentExtraX = extra->X;
|
||||
currentExtraY = extra->Y;
|
||||
currentExtraZ = extra->Z;
|
||||
|
||||
currentExtraSpeedX = extra->destX * (lbaTime - extra->lifeTime);
|
||||
extra->X = currentExtraSpeedX + extra->lastX;
|
||||
|
||||
currentExtraSpeedY = extra->destY * (lbaTime - extra->lifeTime);
|
||||
currentExtraSpeedY += extra->lastY;
|
||||
extra->Y = currentExtraSpeedY - Abs(((extra->angle * (lbaTime - extra->lifeTime))* (lbaTime - extra->lifeTime)) >> 4);
|
||||
|
||||
extra->Z = extra->destZ * (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 == 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;
|
||||
}
|
||||
|
||||
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 (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 = sceneActors[actorIdxAttacked].X;
|
||||
currentExtraY = sceneActors[actorIdxAttacked].Y + 1000;
|
||||
currentExtraZ = sceneActors[actorIdxAttacked].Z;
|
||||
|
||||
tmpAngle = getAngleAndSetTargetActorDistance(extra->X, extra->Z, currentExtraX, currentExtraZ);
|
||||
angle = (tmpAngle - extra->angle) & 0x3FF;
|
||||
|
||||
if (angle > 400 && angle < 600) {
|
||||
if (extra->strengthOfHit) {
|
||||
hitActor(actorIdx, actorIdxAttacked, extra->strengthOfHit, -1);
|
||||
}
|
||||
|
||||
if (i == magicBallIdx) {
|
||||
magicBallIdx = -1;
|
||||
}
|
||||
|
||||
extra->info0 = -1;
|
||||
continue;
|
||||
} else {
|
||||
int32 angle, pos;
|
||||
|
||||
angle = getAngleAndSetTargetActorDistance(extra->Y, 0, currentExtraY, targetActorDistance);
|
||||
|
||||
pos = getRealAngle(&extra->trackActorMove);
|
||||
|
||||
if (!pos) {
|
||||
pos = 1;
|
||||
}
|
||||
|
||||
rotateActor(pos, 0, angle);
|
||||
extra->Y -= destZ;
|
||||
|
||||
rotateActor(0, destX, tmpAngle);
|
||||
extra->X += destX;
|
||||
extra->Z += destZ;
|
||||
|
||||
setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
|
||||
|
||||
if (actorIdxAttacked == checkExtraCollisionWithActors(extra, actorIdx)) {
|
||||
if (i == magicBallIdx) {
|
||||
magicBallIdx = -1;
|
||||
}
|
||||
|
||||
extra->info0 = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// process magic ball extra aiming for key
|
||||
if (extra->type & 0x200) {
|
||||
int32 actorIdx, tmpAngle, angle;
|
||||
// int32 actorIdxAttacked = extra->lifeTime;
|
||||
ExtraListStruct *extraKey = &extraList[extra->actorIdx];
|
||||
actorIdx = extra->actorIdx;
|
||||
|
||||
tmpAngle = getAngleAndSetTargetActorDistance(extra->X, extra->Z, extraKey->X, extraKey->Z);
|
||||
angle = (tmpAngle - extra->angle) & 0x3FF;
|
||||
|
||||
if (angle > 400 && angle < 600) {
|
||||
playSample(97, 0x1000, 1, sceneHero->X, sceneHero->Y, sceneHero->Z, 0);
|
||||
|
||||
if (extraKey->info1 > 1) {
|
||||
projectPositionOnScreen(extraKey->X - cameraX, extraKey->Y - cameraY, extraKey->Z - cameraZ);
|
||||
addOverlay(koNumber, extraKey->info1, projPosX, projPosY, koNormal, 0, 2);
|
||||
}
|
||||
|
||||
addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
|
||||
|
||||
inventoryNumKeys += extraKey->info1;
|
||||
extraKey->info0 = -1;
|
||||
|
||||
extra->info0 = -1;
|
||||
magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, SPRITEHQR_KEY, 0, 8000, 0);
|
||||
continue;
|
||||
} else {
|
||||
int32 angle, pos;
|
||||
|
||||
angle = getAngleAndSetTargetActorDistance(extra->Y, 0, extraKey->Y, targetActorDistance);
|
||||
pos = getRealAngle(&extra->trackActorMove);
|
||||
|
||||
if (!pos) {
|
||||
pos = 1;
|
||||
}
|
||||
|
||||
rotateActor(pos, 0, angle);
|
||||
extra->Y -= destZ;
|
||||
|
||||
rotateActor(0, destX, tmpAngle);
|
||||
extra->X += destX;
|
||||
extra->Z += destZ;
|
||||
|
||||
setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
|
||||
|
||||
if (actorIdx == checkExtraCollisionWithExtra(extra, magicBallIdx)) {
|
||||
playSample(97, 0x1000, 1, sceneHero->X, sceneHero->Y, sceneHero->Z, 0);
|
||||
|
||||
if (extraKey->info1 > 1) {
|
||||
projectPositionOnScreen(extraKey->X - cameraX, extraKey->Y - cameraY, extraKey->Z - cameraZ);
|
||||
addOverlay(koNumber, extraKey->info1, projPosX, projPosY, koNormal, 0, 2);
|
||||
}
|
||||
|
||||
addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
|
||||
|
||||
inventoryNumKeys += extraKey->info1;
|
||||
extraKey->info0 = -1;
|
||||
|
||||
extra->info0 = -1;
|
||||
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;
|
||||
magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 8000, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// process extra collision with actors
|
||||
if (extra->type & 0x4) {
|
||||
if (checkExtraCollisionWithActors(extra, extra->actorIdx) != -1) {
|
||||
// if extra is Magic Ball
|
||||
if (i == 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;
|
||||
}
|
||||
|
||||
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 (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 == magicBallIdx) {
|
||||
// FIXME: add constant for sample index
|
||||
playSample(86, Rnd(300) + 3946, 1, extra->X, extra->Y, extra->Z, -1);
|
||||
|
||||
// cant bounce with not magic points
|
||||
if (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;
|
||||
}
|
||||
|
||||
magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
|
||||
|
||||
extra->info0 = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if has magic points
|
||||
if (magicBallNumBounce == 1) {
|
||||
if (!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;
|
||||
}
|
||||
|
||||
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 (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 *)(spriteBoundingBoxPtr + extra->info0 * 16 + 8);
|
||||
extra->Y = (collisionY << 8) + 0x100 - *(spriteBounds);
|
||||
extra->type &= 0xFFED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// get extras on ground
|
||||
if ((extra->type & 0x20) && !(extra->type & 0x2)) {
|
||||
// if hero touch extra
|
||||
if (checkExtraCollisionWithActors(extra, -1) == 0) {
|
||||
// FIXME: add constant for sample index
|
||||
playSample(97, 0x1000, 1, extra->X, extra->Y, extra->Z, -1);
|
||||
|
||||
if (extra->info1 > 1 && !(loopPressedKey & 2)) {
|
||||
projectPositionOnScreen(extra->X - cameraX, extra->Y - cameraY, extra->Z - cameraZ);
|
||||
addOverlay(koNumber, extra->info1, projPosX, projPosY, 158, koNormal, 2);
|
||||
}
|
||||
|
||||
addOverlay(koSprite, extra->info0, 10, 30, 0, koNormal, 2);
|
||||
|
||||
if (extra->info0 == SPRITEHQR_KASHES) {
|
||||
inventoryNumKashes += extra->info1;
|
||||
if (inventoryNumKashes > 999) {
|
||||
inventoryNumKashes = 999;
|
||||
}
|
||||
}
|
||||
|
||||
if (extra->info0 == SPRITEHQR_LIFEPOINTS) {
|
||||
sceneHero->life += extra->info1;
|
||||
if (sceneHero->life > 50) {
|
||||
sceneHero->life = 50;
|
||||
}
|
||||
}
|
||||
|
||||
if (extra->info0 == SPRITEHQR_MAGICPOINTS && magicLevelIdx) {
|
||||
inventoryMagicPoints += extra->info1 * 2;
|
||||
if (inventoryMagicPoints > magicLevelIdx * 20) {
|
||||
inventoryMagicPoints = magicLevelIdx * 20;
|
||||
}
|
||||
}
|
||||
|
||||
if (extra->info0 == SPRITEHQR_KEY) {
|
||||
inventoryNumKeys += extra->info1;
|
||||
}
|
||||
|
||||
if (extra->info0 == SPRITEHQR_CLOVERLEAF) {
|
||||
inventoryNumLeafs += extra->info1;
|
||||
if (inventoryNumLeafs > inventoryNumLeafsBox) {
|
||||
inventoryNumLeafs = inventoryNumLeafsBox;
|
||||
}
|
||||
}
|
||||
|
||||
extra->info0 = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
89
engines/twine/extra.h
Normal file
89
engines/twine/extra.h
Normal file
@ -0,0 +1,89 @@
|
||||
/** @file extra.h
|
||||
@brief
|
||||
This file contains extra (bonus, projectils, keys, etc.) routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
#include "actor.h"
|
||||
|
||||
#ifndef EXTRA_H
|
||||
#define EXTRA_H
|
||||
|
||||
#define EXTRA_MAX_ENTRIES 50
|
||||
|
||||
typedef struct ExtraListStruct
|
||||
{
|
||||
int16 info0; // field_0
|
||||
int16 X;
|
||||
int16 Y;
|
||||
int16 Z;
|
||||
|
||||
int16 lastX; // field_8
|
||||
int16 lastY; // field_A
|
||||
int16 lastZ; // field_C
|
||||
|
||||
ActorMoveStruct trackActorMove;
|
||||
|
||||
int16 destX; // field_E
|
||||
int16 destY; // field_10
|
||||
int16 destZ; // field_12
|
||||
int16 type; // field_14
|
||||
int16 angle; // field_16
|
||||
int32 lifeTime;
|
||||
int16 actorIdx; // field_ 1C
|
||||
int16 strengthOfHit; // field_1E
|
||||
int16 info1; // field_20
|
||||
} ExtraListStruct;
|
||||
|
||||
ExtraListStruct extraList[EXTRA_MAX_ENTRIES];
|
||||
|
||||
enum ExtraSpecialType {
|
||||
kHitStars = 0,
|
||||
kExplodeCloud = 1
|
||||
};
|
||||
|
||||
int32 addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 targetActor, int32 maxSpeed, int32 strengthOfHit);
|
||||
|
||||
/** Add extra explosion
|
||||
@param X Explostion X coordinate
|
||||
@param Y Explostion Y coordinate
|
||||
@param Z Explostion Z coordinate */
|
||||
int32 addExtraExplode(int32 X, int32 Y, int32 Z);
|
||||
|
||||
/** Reset all used extras */
|
||||
void resetExtras();
|
||||
|
||||
void addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type);
|
||||
int32 addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 type, int32 bonusAmount);
|
||||
int32 addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int32 var2, int32 var3, int32 var4, int32 var5, int32 strengthOfHit);
|
||||
int32 addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 targetActorIdx, int32 maxSpeed, int32 strengthOfHit);
|
||||
void addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle, int32 param2, int32 param3);
|
||||
|
||||
void drawExtraSpecial(int32 extraIdx, int32 X, int32 Y);
|
||||
|
||||
/** Process extras */
|
||||
void processExtras();
|
||||
|
||||
|
||||
#endif
|
||||
|
142
engines/twine/fcaseopen.cpp
Normal file
142
engines/twine/fcaseopen.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Keith Bauer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "fcaseopen.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
// r must have strlen(path) + 2 bytes
|
||||
static int casepath(char const *path, char *r)
|
||||
{
|
||||
size_t l = strlen(path);
|
||||
char *p = alloca(l + 1);
|
||||
strcpy(p, path);
|
||||
size_t rl = 0;
|
||||
|
||||
DIR *d;
|
||||
if (p[0] == '/')
|
||||
{
|
||||
d = opendir("/");
|
||||
p = p + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = opendir(".");
|
||||
r[0] = '.';
|
||||
r[1] = 0;
|
||||
rl = 1;
|
||||
}
|
||||
|
||||
int last = 0;
|
||||
char *c = strsep(&p, "/");
|
||||
while (c)
|
||||
{
|
||||
if (!d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (last)
|
||||
{
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r[rl] = '/';
|
||||
rl += 1;
|
||||
r[rl] = 0;
|
||||
|
||||
struct dirent *e = readdir(d);
|
||||
while (e)
|
||||
{
|
||||
if (strcasecmp(c, e->d_name) == 0)
|
||||
{
|
||||
strcpy(r + rl, e->d_name);
|
||||
rl += strlen(e->d_name);
|
||||
|
||||
closedir(d);
|
||||
d = opendir(r);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
e = readdir(d);
|
||||
}
|
||||
|
||||
if (!e)
|
||||
{
|
||||
strcpy(r + rl, c);
|
||||
rl += strlen(c);
|
||||
last = 1;
|
||||
}
|
||||
|
||||
c = strsep(&p, "/");
|
||||
}
|
||||
|
||||
if (d) closedir(d);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
FILE *fcaseopen(char const *path, char const *mode)
|
||||
{
|
||||
FILE *f = fopen(path, mode);
|
||||
#ifndef WIN32
|
||||
if (!f)
|
||||
{
|
||||
char *r = alloca(strlen(path) + 2);
|
||||
if (casepath(path, r))
|
||||
{
|
||||
f = fopen(r, mode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return f;
|
||||
}
|
||||
|
||||
void casechdir(char const *path)
|
||||
{
|
||||
#ifndef WIN32
|
||||
char *r = alloca(strlen(path) + 2);
|
||||
if (casepath(path, r))
|
||||
{
|
||||
chdir(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENOENT;
|
||||
}
|
||||
#else
|
||||
_chdir(path);
|
||||
#endif
|
||||
}
|
40
engines/twine/fcaseopen.h
Normal file
40
engines/twine/fcaseopen.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Keith Bauer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef fcaseopen_h
|
||||
#define fcaseopen_h
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern FILE *fcaseopen(char const *path, char const *mode);
|
||||
|
||||
extern void casechdir(char const *path);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
112
engines/twine/filereader.cpp
Normal file
112
engines/twine/filereader.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
/** @file filereader.cpp
|
||||
@brief
|
||||
This file contains file read routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "filereader.h"
|
||||
#include "fcaseopen.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/** Feed buffer from file
|
||||
@param fr FileReader pointer */
|
||||
void frfeed(FileReader* fr) {
|
||||
fread(fr->buffer, BUFFER_SIZE, 1, fr->fd);
|
||||
fr->bufferPos = 0;
|
||||
}
|
||||
|
||||
/** Read file
|
||||
@param fr FileReader pointer
|
||||
@param destPtr content destination pointer
|
||||
@param size size of read characters */
|
||||
void frread(FileReader* fr, void* destPtr, uint32 size) {
|
||||
if (BUFFER_SIZE - fr->bufferPos >= size) {
|
||||
memcpy(destPtr, &fr->buffer[fr->bufferPos], size);
|
||||
fr->bufferPos += size;
|
||||
} else {
|
||||
// feed what we can
|
||||
int8* tempPtr = (int8*)destPtr;
|
||||
memcpy(tempPtr, &fr->buffer[fr->bufferPos], BUFFER_SIZE - fr->bufferPos);
|
||||
tempPtr += BUFFER_SIZE - fr->bufferPos;
|
||||
size -= BUFFER_SIZE - fr->bufferPos;
|
||||
|
||||
// feed the rest
|
||||
do {
|
||||
fr->currSector++;
|
||||
frfeed(fr);
|
||||
if (size >= BUFFER_SIZE) {
|
||||
memcpy(tempPtr, fr->buffer, BUFFER_SIZE);
|
||||
tempPtr += BUFFER_SIZE;
|
||||
size -= BUFFER_SIZE;
|
||||
} else {
|
||||
memcpy(tempPtr, fr->buffer, size);
|
||||
fr->bufferPos += size;
|
||||
size = 0;
|
||||
}
|
||||
} while (size > 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Seek file
|
||||
@param fr FileReader pointer
|
||||
@param seekPosition position to seek */
|
||||
void frseek(FileReader* fr, uint32 seekPosition) {
|
||||
uint32 sectorToSeek;
|
||||
|
||||
sectorToSeek = seekPosition / 2048;
|
||||
|
||||
fseek(fr->fd, sectorToSeek * 2048, SEEK_SET);
|
||||
|
||||
fr->currSector = sectorToSeek;
|
||||
frfeed(fr);
|
||||
fr->bufferPos = (seekPosition - (sectorToSeek * 2048));
|
||||
}
|
||||
|
||||
/** Open file
|
||||
@param fr FileReader pointer
|
||||
@param filename file path
|
||||
@return true if file open and false if error occurred */
|
||||
int32 fropen2(FileReader* fr, char* filename, const char* mode) {
|
||||
fr->fd = fcaseopen(filename, mode);
|
||||
|
||||
if (fr->fd) {
|
||||
fr->currSector = 0;
|
||||
frfeed(fr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Write file
|
||||
@param fr FileReader pointer
|
||||
@param destPtr content destination pointer
|
||||
@param size size of read characters */
|
||||
void frwrite(FileReader* fr, void* destPtr, uint32 size, uint32 count) {
|
||||
fwrite(destPtr, size, count, fr->fd);
|
||||
}
|
||||
|
||||
/** Close file
|
||||
@param fr FileReader pointer */
|
||||
void frclose(FileReader* fr) {
|
||||
fclose(fr->fd);
|
||||
}
|
83
engines/twine/filereader.h
Normal file
83
engines/twine/filereader.h
Normal file
@ -0,0 +1,83 @@
|
||||
/** @file filereader.h
|
||||
@brief
|
||||
This file contains file read routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef FILEREADER_H
|
||||
#define FILEREADER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/** Number of sector in the buffer */
|
||||
#define SECTORS_IN_BUFFER (3)
|
||||
/** Buffer size */
|
||||
#define BUFFER_SIZE (2048*SECTORS_IN_BUFFER)
|
||||
|
||||
/** File reader structure */
|
||||
typedef struct FileReader {
|
||||
/** File descriptor */
|
||||
FILE* fd;
|
||||
/** Content buffer */
|
||||
uint8 buffer[BUFFER_SIZE];
|
||||
/** Current position in the buffer */
|
||||
uint32 bufferPos;
|
||||
/** Current sector in the buffer */
|
||||
uint32 currSector;
|
||||
} FileReader;
|
||||
|
||||
/** Feed buffer from file
|
||||
@param fr FileReader pointer */
|
||||
void frfeed(FileReader* fr);
|
||||
|
||||
/** Read file
|
||||
@param fr FileReader pointer
|
||||
@param destPtr content destination pointer
|
||||
@param size size of read characters */
|
||||
void frread(FileReader* fr, void* destPtr, uint32 size);
|
||||
|
||||
/** Seek file
|
||||
@param fr FileReader pointer
|
||||
@param seekPosition position to seek */
|
||||
void frseek(FileReader* fr, uint32 seekPosition);
|
||||
|
||||
/** Open file
|
||||
@param fr FileReader pointer
|
||||
@param filename file path
|
||||
@return true if file open and false if error occurred */
|
||||
int32 fropen2(FileReader* fr, char* filename, const char* mode);
|
||||
|
||||
/** Write file
|
||||
@param fr FileReader pointer
|
||||
@param destPtr content destination pointer
|
||||
@param size size of read characters */
|
||||
void frwrite(FileReader* fr, void* destPtr, uint32 size, uint32 count);
|
||||
|
||||
/** Close file
|
||||
@param fr FileReader pointer */
|
||||
void frclose(FileReader* fr);
|
||||
|
||||
#endif
|
492
engines/twine/flamovies.cpp
Normal file
492
engines/twine/flamovies.cpp
Normal file
@ -0,0 +1,492 @@
|
||||
/** @file movies.cpp
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "flamovies.h"
|
||||
#include "screens.h"
|
||||
#include "sdlengine.h"
|
||||
#include "main.h"
|
||||
#include "sound.h"
|
||||
#include "music.h"
|
||||
#include "filereader.h"
|
||||
#include "lbaengine.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
/** Config movie types */
|
||||
#define CONF_MOVIE_NONE 0
|
||||
#define CONF_MOVIE_FLA 1
|
||||
#define CONF_MOVIE_FLAWIDE 2
|
||||
#define CONF_MOVIE_FLAPCX 3
|
||||
|
||||
/** FLA movie extension */
|
||||
#define FLA_EXT ".fla"
|
||||
|
||||
/** FLA Frame Opcode types */
|
||||
enum FlaFrameOpcode {
|
||||
kLoadPalette = 0,
|
||||
kFade = 1,
|
||||
kPlaySample = 2,
|
||||
kStopSample = 4,
|
||||
kDeltaFrame = 5,
|
||||
kKeyFrame = 7
|
||||
};
|
||||
|
||||
/** Auxiliar FLA fade out variable */
|
||||
int32 _fadeOut;
|
||||
/** Auxiliar FLA fade out variable to count frames between the fade */
|
||||
int32 fadeOutFrames;
|
||||
|
||||
/** FLA movie sample auxiliar table */
|
||||
int32 flaSampleTable[100];
|
||||
/** Number of samples in FLA movie */
|
||||
int32 samplesInFla;
|
||||
/** Auxiliar work video buffer */
|
||||
uint8* workVideoBufferCopy;
|
||||
/** FLA movie header data */
|
||||
FLAHeaderStruct flaHeaderData;
|
||||
/** FLA movie header data */
|
||||
FLAFrameDataStruct frameData;
|
||||
|
||||
FileReader frFla;
|
||||
|
||||
/** FLA movie draw key frame
|
||||
@param ptr FLA frame buffer pointer
|
||||
@param width FLA movie width
|
||||
@param height FLA movie height */
|
||||
void drawKeyFrame(uint8 * ptr, int32 width, int32 height) {
|
||||
int32 a, b;
|
||||
uint8 * destPtr = (uint8 *)flaBuffer;
|
||||
uint8 * startOfLine = destPtr;
|
||||
int8 flag1;
|
||||
int8 flag2;
|
||||
|
||||
do {
|
||||
flag1 = *(ptr++);
|
||||
|
||||
for (a = 0; a < flag1; a++) {
|
||||
flag2 = *(ptr++);
|
||||
|
||||
if (flag2 < 0) {
|
||||
flag2 = - flag2;
|
||||
for (b = 0; b < flag2; b++) {
|
||||
*(destPtr++) = *(ptr++);
|
||||
}
|
||||
} else {
|
||||
char colorFill;
|
||||
|
||||
colorFill = *(ptr++);
|
||||
|
||||
for (b = 0; b < flag2; b++) {
|
||||
*(destPtr++) = colorFill;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startOfLine = destPtr = startOfLine + width;
|
||||
} while (--height);
|
||||
}
|
||||
|
||||
/** FLA movie draw delta frame
|
||||
@param ptr FLA frame buffer pointer
|
||||
@param width FLA movie width */
|
||||
void drawDeltaFrame(uint8 * ptr, int32 width) {
|
||||
int32 a, b;
|
||||
uint16 skip;
|
||||
uint8 * destPtr;
|
||||
uint8 * startOfLine;
|
||||
int32 height;
|
||||
|
||||
int8 flag1;
|
||||
int8 flag2;
|
||||
|
||||
skip = *((uint16*)ptr);
|
||||
ptr += 2;
|
||||
skip *= width;
|
||||
startOfLine = destPtr = (uint8 *)flaBuffer + skip;
|
||||
height = *((int16*)ptr);
|
||||
ptr += 2;
|
||||
|
||||
do {
|
||||
flag1 = *(ptr++);
|
||||
|
||||
for (a = 0; a < flag1; a++) {
|
||||
destPtr += (unsigned char) * (ptr++);
|
||||
flag2 = *(ptr++);
|
||||
|
||||
if (flag2 > 0) {
|
||||
for (b = 0; b < flag2; b++) {
|
||||
*(destPtr++) = *(ptr++);
|
||||
}
|
||||
} else {
|
||||
char colorFill;
|
||||
flag2 = - flag2;
|
||||
|
||||
colorFill = *(ptr++);
|
||||
|
||||
for (b = 0; b < flag2; b++) {
|
||||
*(destPtr++) = colorFill;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startOfLine = destPtr = startOfLine + width;
|
||||
} while (--height);
|
||||
}
|
||||
|
||||
/** Scale FLA movie 2 times
|
||||
|
||||
According with the settins we can put the original aspect radio stretch
|
||||
to fullscreen or preserve it and use top and button black bars */
|
||||
void scaleFla2x() {
|
||||
int32 i, j;
|
||||
uint8* source = (uint8*)flaBuffer;
|
||||
uint8* dest = (uint8*)workVideoBuffer;
|
||||
|
||||
if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
|
||||
for (i = 0; i < SCREEN_WIDTH / SCALE*40; i++) {
|
||||
*(dest++) = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < FLASCREEN_HEIGHT; i++) {
|
||||
for (j = 0; j < FLASCREEN_WIDTH; j++) {
|
||||
*(dest++) = *(source);
|
||||
*(dest++) = *(source++);
|
||||
}
|
||||
if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) { // include wide bars
|
||||
memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
|
||||
dest += FLASCREEN_WIDTH * 2;
|
||||
} else { // stretch the movie like original game.
|
||||
if (i % (2)) {
|
||||
memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
|
||||
dest += FLASCREEN_WIDTH * 2;
|
||||
}
|
||||
if (i % 10) {
|
||||
memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
|
||||
dest += FLASCREEN_WIDTH * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
|
||||
for (i = 0; i < SCREEN_WIDTH / SCALE*40; i++) {
|
||||
*(dest++) = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** FLA movie process frame */
|
||||
void processFrame() {
|
||||
FLASampleStruct sample;
|
||||
uint32 opcodeBlockSize;
|
||||
uint8 opcode;
|
||||
int32 aux = 0;
|
||||
uint8 * ptr;
|
||||
|
||||
frread(&frFla, &frameData.videoSize, 1);
|
||||
frread(&frFla, &frameData.dummy, 1);
|
||||
frread(&frFla, &frameData.frameVar0, 4);
|
||||
|
||||
frread(&frFla, workVideoBufferCopy, frameData.frameVar0);
|
||||
|
||||
if ((int32)frameData.videoSize <= 0)
|
||||
return;
|
||||
|
||||
ptr = workVideoBufferCopy;
|
||||
|
||||
do {
|
||||
opcode = *((uint8*)ptr);
|
||||
ptr += 2;
|
||||
opcodeBlockSize = *((uint16*)ptr);
|
||||
ptr += 2;
|
||||
|
||||
switch (opcode - 1) {
|
||||
case kLoadPalette: {
|
||||
int16 numOfColor = *((int16*)ptr);
|
||||
int16 startColor = *((int16*)(ptr + 2));
|
||||
memcpy((palette + (startColor*3)), (ptr + 4), numOfColor*3);
|
||||
break;
|
||||
}
|
||||
case kFade: {
|
||||
// FLA movies don't use cross fade
|
||||
// fade out tricky
|
||||
if (_fadeOut != 1) {
|
||||
convertPalToRGBA(palette, paletteRGBACustom);
|
||||
fadeToBlack(paletteRGBACustom);
|
||||
_fadeOut = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kPlaySample: {
|
||||
memcpy(&sample, ptr, sizeof(FLASampleStruct));
|
||||
playFlaSample(sample.sampleNum, sample.freq, sample.repeat, sample.x, sample.y);
|
||||
break;
|
||||
}
|
||||
case kStopSample: {
|
||||
stopSample(sample.sampleNum);
|
||||
break;
|
||||
}
|
||||
case kDeltaFrame: {
|
||||
drawDeltaFrame(ptr, FLASCREEN_WIDTH);
|
||||
if (_fadeOut == 1)
|
||||
fadeOutFrames++;
|
||||
break;
|
||||
}
|
||||
case kKeyFrame: {
|
||||
drawKeyFrame(ptr, FLASCREEN_WIDTH, FLASCREEN_HEIGHT);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aux++;
|
||||
ptr += opcodeBlockSize;
|
||||
|
||||
} while (aux < (int32)frameData.videoSize);
|
||||
//free(workVideoBufferCopy);
|
||||
}
|
||||
|
||||
/** Play FLA PCX Screens
|
||||
@param flaName FLA movie name */
|
||||
void fla_pcxList(int8 *flaName) {
|
||||
// TODO if is using FLA PCX than show the images instead
|
||||
}
|
||||
|
||||
/** Play FLA movies
|
||||
@param flaName FLA movie name */
|
||||
void playFlaMovie(int8 *flaName) {
|
||||
int32 i;
|
||||
int32 quit = 0;
|
||||
int32 currentFrame;
|
||||
int16 tmpValue;
|
||||
int8 fileNamePath[256];
|
||||
|
||||
stopSamples();
|
||||
|
||||
// Play FLA PCX instead of movies
|
||||
if (cfgfile.Movie == CONF_MOVIE_FLAPCX) {
|
||||
fla_pcxList(flaName);
|
||||
return;
|
||||
}
|
||||
|
||||
stopMusic();
|
||||
|
||||
// take extension if movie name has it
|
||||
for (i = 0; i < (int32)strlen(flaName); i++) {
|
||||
if(flaName[i] == '.') {
|
||||
flaName[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(fileNamePath, FLA_DIR);
|
||||
strcat(fileNamePath, flaName);
|
||||
strcat(fileNamePath, FLA_EXT);
|
||||
|
||||
_fadeOut = -1;
|
||||
fadeOutFrames = 0;
|
||||
|
||||
if (!fropen2(&frFla, fileNamePath, "rb"))
|
||||
return;
|
||||
|
||||
workVideoBufferCopy = workVideoBuffer;
|
||||
|
||||
frread(&frFla, &flaHeaderData.version, 6);
|
||||
frread(&frFla, &flaHeaderData.numOfFrames, 4);
|
||||
frread(&frFla, &flaHeaderData.speed, 1);
|
||||
frread(&frFla, &flaHeaderData.var1, 1);
|
||||
frread(&frFla, &flaHeaderData.xsize, 2);
|
||||
frread(&frFla, &flaHeaderData.ysize, 2);
|
||||
|
||||
frread(&frFla, &samplesInFla, 2);
|
||||
frread(&frFla, &tmpValue, 2);
|
||||
|
||||
for (i = 0; i < samplesInFla; i++) {
|
||||
int16 var0;
|
||||
int16 var1;
|
||||
frread(&frFla, &var0, 2);
|
||||
frread(&frFla, &var1, 2);
|
||||
flaSampleTable[i] = var0;
|
||||
}
|
||||
|
||||
if (!strcmp(flaHeaderData.version, "V1.3")) {
|
||||
currentFrame = 0;
|
||||
|
||||
if (!quit) {
|
||||
do {
|
||||
if (currentFrame == flaHeaderData.numOfFrames)
|
||||
quit = 1;
|
||||
else {
|
||||
processFrame();
|
||||
scaleFla2x();
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
|
||||
// Only blit to screen if isn't a fade
|
||||
if (_fadeOut == -1) {
|
||||
convertPalToRGBA(palette, paletteRGBACustom);
|
||||
if (!currentFrame) // fade in the first frame
|
||||
fadeIn(paletteRGBACustom);
|
||||
else
|
||||
setPalette(paletteRGBACustom);
|
||||
}
|
||||
|
||||
// TRICKY: fade in tricky
|
||||
if (fadeOutFrames >= 2) {
|
||||
flip();
|
||||
convertPalToRGBA(palette, paletteRGBACustom);
|
||||
fadeToPal(paletteRGBACustom);
|
||||
_fadeOut = -1;
|
||||
fadeOutFrames = 0;
|
||||
}
|
||||
|
||||
currentFrame++;
|
||||
|
||||
fpsCycles(flaHeaderData.speed + 1);
|
||||
|
||||
readKeys();
|
||||
|
||||
if (skipIntro)
|
||||
break;
|
||||
}
|
||||
} while (!quit);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfgfile.CrossFade) {
|
||||
crossFade(frontVideoBuffer, paletteRGBACustom);
|
||||
} else {
|
||||
fadeToBlack(paletteRGBACustom);
|
||||
}
|
||||
|
||||
stopSamples();
|
||||
}
|
||||
|
||||
/*
|
||||
void fla_pcxList(char *flaName)
|
||||
{
|
||||
// check if FLAPCX file exist
|
||||
// if(!checkIfFileExist("FLA_PCX.HQR") || !checkIfFileExist("FLA_GIF.HQR")){
|
||||
// printf("FLA_PCX file doesn't exist!");
|
||||
//return;
|
||||
//}
|
||||
|
||||
// TODO: done this with the HQR 23th entry (movies informations)
|
||||
if(!strcmp(flaName,"INTROD"))
|
||||
{
|
||||
prepareFlaPCX(1);
|
||||
WaitTime(5000);
|
||||
prepareFlaPCX(2);
|
||||
WaitTime(5000);
|
||||
prepareFlaPCX(3);
|
||||
WaitTime(5000);
|
||||
prepareFlaPCX(4);
|
||||
WaitTime(5000);
|
||||
prepareFlaPCX(5);
|
||||
WaitTime(5000);
|
||||
|
||||
}
|
||||
else if(!strcmp(flaName,"BAFFE") || !strcmp(flaName,"BAFFE2") || !strcmp(flaName,"BAFFE3") || !strcmp(flaName,"BAFFE4"))
|
||||
{
|
||||
prepareFlaPCX(6);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"bateau") || !strcmp(flaName,"bateau2"))
|
||||
{
|
||||
prepareFlaPCX(7);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"flute2"))
|
||||
{
|
||||
prepareFlaPCX(8);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"navette"))
|
||||
{
|
||||
prepareFlaPCX(15);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"templebu"))
|
||||
{
|
||||
prepareFlaPCX(12);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"glass2"))
|
||||
{
|
||||
prepareFlaPCX(8);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"surf"))
|
||||
{
|
||||
prepareFlaPCX(9);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"verser") || !strcmp(flaName,"verser2"))
|
||||
{
|
||||
prepareFlaPCX(10);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"capture"))
|
||||
{
|
||||
prepareFlaPCX(14);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"neige2"))
|
||||
{
|
||||
prepareFlaPCX(11);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"sendel"))
|
||||
{
|
||||
prepareFlaPCX(14);
|
||||
WaitTime(5000);
|
||||
}
|
||||
else if(!strcmp(flaName,"sendel2"))
|
||||
{
|
||||
prepareFlaPCX(17);
|
||||
WaitTime(5000);
|
||||
}
|
||||
}
|
||||
|
||||
void prepareFlaPCX(int index)
|
||||
{
|
||||
int i;
|
||||
SDL_Surface *image;
|
||||
|
||||
// TODO: Done this without SDL_Image Library
|
||||
if(checkIfFileExist("FLA_PCX.HQR"))
|
||||
image = IMG_LoadPCX_RW(SDL_RWFromMem(HQR_Get(HQR_FlaPCX,index), Size_HQR("FLA_PCX.HQR", index))); // rwop
|
||||
else if(checkIfFileExist("FLA_GIF.HQR"))
|
||||
image = IMG_LoadGIF_RW(SDL_RWFromMem(HQR_Get(HQR_FlaGIF,index), Size_HQR("fla_gif.hqr", index))); // rwop
|
||||
|
||||
if(!image) {
|
||||
printf("Can't load FLA PCX: %s\n", IMG_GetError());
|
||||
}
|
||||
|
||||
osystem_FlaPCXCrossFade(image);
|
||||
}*/
|
83
engines/twine/flamovies.h
Normal file
83
engines/twine/flamovies.h
Normal file
@ -0,0 +1,83 @@
|
||||
/** @file movies.h
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef FLAMOVIES_H
|
||||
#define FLAMOVIES_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
/** FLA movie directory */
|
||||
#define FLA_DIR "fla/"
|
||||
|
||||
/** FLA movie header structure */
|
||||
typedef struct FLAHeaderStruct {
|
||||
/** FLA version */
|
||||
int8 version[6];
|
||||
/** Number of frames */
|
||||
int32 numOfFrames;
|
||||
/** Frames per second */
|
||||
int8 speed;
|
||||
/** Unknown var1 */
|
||||
int8 var1;
|
||||
/** Frame width */
|
||||
int16 xsize;
|
||||
/** Frame height */
|
||||
int16 ysize;
|
||||
} FLAHeaderStruct;
|
||||
|
||||
/** FLA movie frame structure */
|
||||
typedef struct FLAFrameDataStruct {
|
||||
/** Current frame size */
|
||||
int8 videoSize;
|
||||
/** Dummy variable */
|
||||
int8 dummy;
|
||||
/** Unknown frameVar0 */
|
||||
int32 frameVar0;
|
||||
} FLAFrameDataStruct;
|
||||
|
||||
/** FLA movie sample structure */
|
||||
typedef struct FLASampleStruct {
|
||||
/** Number os samples */
|
||||
int16 sampleNum;
|
||||
/** Sample frequency */
|
||||
int16 freq;
|
||||
/** Numbers of time to repeat */
|
||||
int16 repeat;
|
||||
/** Dummy variable */
|
||||
int8 dummy;
|
||||
/** Unknown x */
|
||||
uint8 x;
|
||||
/** Unknown y */
|
||||
uint8 y;
|
||||
} FLASampleStruct;
|
||||
|
||||
/** FLA movie file buffer */
|
||||
unsigned char flaBuffer[FLASCREEN_WIDTH*FLASCREEN_HEIGHT];
|
||||
|
||||
/** Play FLA movies
|
||||
@param flaName FLA movie name */
|
||||
void playFlaMovie(int8 *flaName);
|
||||
|
||||
#endif
|
531
engines/twine/gamestate.cpp
Normal file
531
engines/twine/gamestate.cpp
Normal file
@ -0,0 +1,531 @@
|
||||
/** @file gamestate.cpp
|
||||
@brief
|
||||
This file contains game state routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "gamestate.h"
|
||||
#include "scene.h"
|
||||
#include "redraw.h"
|
||||
#include "text.h"
|
||||
#include "menu.h"
|
||||
#include "renderer.h"
|
||||
#include "grid.h"
|
||||
#include "lbaengine.h"
|
||||
#include "interface.h"
|
||||
#include "animations.h"
|
||||
#include "keyboard.h"
|
||||
#include "resources.h"
|
||||
#include "extra.h"
|
||||
#include "sound.h"
|
||||
#include "screens.h"
|
||||
#include "music.h"
|
||||
#include "filereader.h"
|
||||
#include "menuoptions.h"
|
||||
#include "collision.h"
|
||||
|
||||
#define SAVE_DIR "save/"
|
||||
|
||||
int32 magicLevelStrengthOfHit[] = {
|
||||
kNoBallStrenght,
|
||||
kYellowBallStrenght,
|
||||
kGreenBallStrenght,
|
||||
kRedBallStrenght,
|
||||
kFireBallStrength,
|
||||
0
|
||||
};
|
||||
|
||||
/** Initialize engine 3D projections */
|
||||
void initEngineProjections() { // reinitAll1
|
||||
setOrthoProjection(311, 240, 512);
|
||||
setBaseTranslation(0, 0, 0);
|
||||
setBaseRotation(0, 0, 0);
|
||||
setLightVector(alphaLight, betaLight, 0);
|
||||
}
|
||||
|
||||
/** Initialize variables */
|
||||
void initSceneVars() {
|
||||
int32 i;
|
||||
|
||||
resetExtras();
|
||||
|
||||
for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
|
||||
overlayList[i].info0 = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_SCENES_FLAGS; i++) {
|
||||
sceneFlags[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_GAME_FLAGS; i++) {
|
||||
gameFlags[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_INVENTORY_ITEMS; i++) {
|
||||
inventoryFlags[i] = 0;
|
||||
}
|
||||
|
||||
sampleAmbiance[0] = -1;
|
||||
sampleAmbiance[1] = -1;
|
||||
sampleAmbiance[2] = -1;
|
||||
sampleAmbiance[3] = -1;
|
||||
|
||||
sampleRepeat[0] = 0;
|
||||
sampleRepeat[1] = 0;
|
||||
sampleRepeat[2] = 0;
|
||||
sampleRepeat[3] = 0;
|
||||
|
||||
sampleRound[0] = 0;
|
||||
sampleRound[1] = 0;
|
||||
sampleRound[2] = 0;
|
||||
sampleRound[3] = 0;
|
||||
|
||||
for (i = 0; i < 150; i++) {
|
||||
holomapFlags[i] = 0;
|
||||
}
|
||||
|
||||
sceneNumActors = 0;
|
||||
sceneNumZones = 0;
|
||||
sceneNumTracks = 0;
|
||||
|
||||
currentPositionInBodyPtrTab = 0;
|
||||
}
|
||||
|
||||
void initHeroVars() { // reinitAll3
|
||||
resetActor(0); // reset Hero
|
||||
|
||||
magicBallIdx = -1;
|
||||
|
||||
inventoryNumLeafsBox = 2;
|
||||
inventoryNumLeafs = 2;
|
||||
inventoryNumKashes = 0;
|
||||
inventoryNumKeys = 0;
|
||||
inventoryMagicPoints = 0;
|
||||
|
||||
usingSabre = 0;
|
||||
|
||||
sceneHero->body = 0;
|
||||
sceneHero->life = 50;
|
||||
sceneHero->talkColor = 4;
|
||||
}
|
||||
|
||||
/** Initialize all engine variables */
|
||||
void initEngineVars(int32 save) { // reinitAll
|
||||
resetClip();
|
||||
|
||||
alphaLight = 896;
|
||||
betaLight = 950;
|
||||
initEngineProjections();
|
||||
initSceneVars();
|
||||
initHeroVars();
|
||||
|
||||
newHeroX = 0x2000;
|
||||
newHeroY = 0x1800;
|
||||
newHeroZ = 0x2000;
|
||||
|
||||
currentSceneIdx = -1;
|
||||
needChangeScene = 0;
|
||||
quitGame = -1;
|
||||
mecaPinguinIdx = -1;
|
||||
canShowCredits = 0;
|
||||
|
||||
inventoryNumLeafs = 0;
|
||||
inventoryNumLeafsBox = 2;
|
||||
inventoryMagicPoints = 0;
|
||||
inventoryNumKashes = 0;
|
||||
inventoryNumKeys = 0;
|
||||
inventoryNumGas = 0;
|
||||
|
||||
cropBottomScreen = 0;
|
||||
|
||||
magicLevelIdx = 0;
|
||||
usingSabre = 0;
|
||||
|
||||
gameChapter = 0;
|
||||
|
||||
currentTextBank = 0;
|
||||
currentlyFollowedActor = 0;
|
||||
heroBehaviour = 0;
|
||||
previousHeroAngle = 0;
|
||||
previousHeroBehaviour = 0;
|
||||
|
||||
if (save == -1) {
|
||||
loadGame();
|
||||
if (newHeroX == -1) {
|
||||
heroPositionType = kNoPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadGame() {
|
||||
FileReader fr;
|
||||
uint8 data;
|
||||
int8* namePtr;
|
||||
|
||||
if (!fropen2(&fr, SAVE_DIR "S9999.LBA", "rb")) {
|
||||
printf("Can't load S9999.LBA saved game!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
namePtr = savePlayerName;
|
||||
|
||||
frread(&fr, &data, 1); // save game id
|
||||
|
||||
do {
|
||||
frread(&fr, &data, 1); // get save player name characters
|
||||
*(namePtr++) = data;
|
||||
} while (data);
|
||||
|
||||
frread(&fr, &data, 1); // number of game flags, always 0xFF
|
||||
frread(&fr, gameFlags, data);
|
||||
frread(&fr, &needChangeScene, 1); // scene index
|
||||
frread(&fr, &gameChapter, 1);
|
||||
|
||||
frread(&fr, &heroBehaviour, 1);
|
||||
previousHeroBehaviour = heroBehaviour;
|
||||
frread(&fr, &sceneHero->life, 1);
|
||||
frread(&fr, &inventoryNumKashes, 2);
|
||||
frread(&fr, &magicLevelIdx, 1);
|
||||
frread(&fr, &inventoryMagicPoints, 1);
|
||||
frread(&fr, &inventoryNumLeafsBox, 1);
|
||||
frread(&fr, &newHeroX, 2);
|
||||
frread(&fr, &newHeroY, 2);
|
||||
frread(&fr, &newHeroZ, 2);
|
||||
frread(&fr, &sceneHero->angle, 2);
|
||||
previousHeroAngle = sceneHero->angle;
|
||||
frread(&fr, &sceneHero->body, 1);
|
||||
|
||||
frread(&fr, &data, 1); // number of holomap locations, always 0x96
|
||||
frread(&fr, holomapFlags, data);
|
||||
|
||||
frread(&fr, &inventoryNumGas, 1);
|
||||
|
||||
frread(&fr, &data, 1); // number of used inventory items, always 0x1C
|
||||
frread(&fr, inventoryFlags, data);
|
||||
|
||||
frread(&fr, &inventoryNumLeafs, 1);
|
||||
frread(&fr, &usingSabre, 1);
|
||||
|
||||
frclose(&fr);
|
||||
|
||||
currentSceneIdx = -1;
|
||||
heroPositionType = kReborn;
|
||||
}
|
||||
|
||||
void saveGame() {
|
||||
FileReader fr;
|
||||
int8 data;
|
||||
|
||||
if (!fropen2(&fr, SAVE_DIR "S9999.LBA", "wb+")) {
|
||||
printf("Can't save S9999.LBA saved game!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
data = 0x03;
|
||||
frwrite(&fr, &data, 1, 1);
|
||||
|
||||
data = 0x00;
|
||||
frwrite(&fr, "TwinEngineSave", 15, 1);
|
||||
|
||||
data = 0xFF; // number of game flags
|
||||
frwrite(&fr, &data, 1, 1);
|
||||
frwrite(&fr, gameFlags, 255, 1);
|
||||
|
||||
frwrite(&fr, ¤tSceneIdx, 1, 1);
|
||||
frwrite(&fr, &gameChapter, 1, 1);
|
||||
frwrite(&fr, &heroBehaviour, 1, 1);
|
||||
frwrite(&fr, &sceneHero->life, 1, 1);
|
||||
frwrite(&fr, &inventoryNumKashes, 2, 1);
|
||||
frwrite(&fr, &magicLevelIdx, 1, 1);
|
||||
frwrite(&fr, &inventoryMagicPoints, 1, 1);
|
||||
frwrite(&fr, &inventoryNumLeafsBox, 1, 1);
|
||||
frwrite(&fr, &newHeroX, 2, 1);
|
||||
frwrite(&fr, &newHeroY, 2, 1);
|
||||
frwrite(&fr, &newHeroZ, 2, 1);
|
||||
frwrite(&fr, &sceneHero->angle, 2, 1);
|
||||
frwrite(&fr, &sceneHero->body, 1, 1);
|
||||
|
||||
data = 0x96; // number of holomap locations
|
||||
frwrite(&fr, &data, 1, 1);
|
||||
frwrite(&fr, holomapFlags, 150, 1);
|
||||
|
||||
frwrite(&fr, &inventoryNumGas, 1, 1);
|
||||
|
||||
data = 0x1C; // number of inventory items
|
||||
frwrite(&fr, &data, 1, 1);
|
||||
frwrite(&fr, inventoryFlags, 28, 1);
|
||||
|
||||
frwrite(&fr, &inventoryNumLeafs, 1, 1);
|
||||
frwrite(&fr, &usingSabre, 1, 1);
|
||||
|
||||
frclose(&fr);
|
||||
}
|
||||
|
||||
void processFoundItem(int32 item) {
|
||||
int32 itemCameraX, itemCameraY, itemCameraZ; // objectXYZ
|
||||
int32 itemX, itemY, itemZ; // object2XYZ
|
||||
int32 boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY;
|
||||
int32 textState, quitItem, currentAnimState;
|
||||
uint8 *currentAnim;
|
||||
AnimTimerDataStruct tmpAnimTimer;
|
||||
|
||||
newCameraX = (sceneHero->X + 0x100) >> 9;
|
||||
newCameraY = (sceneHero->Y + 0x100) >> 8;
|
||||
newCameraZ = (sceneHero->Z + 0x100) >> 9;
|
||||
|
||||
// Hide hero in scene
|
||||
sceneHero->staticFlags.bIsHidden = 1;
|
||||
redrawEngineActions(1);
|
||||
sceneHero->staticFlags.bIsHidden = 0;
|
||||
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
|
||||
itemCameraX = newCameraX << 9;
|
||||
itemCameraY = newCameraY << 8;
|
||||
itemCameraZ = newCameraZ << 9;
|
||||
|
||||
renderIsoModel(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ, 0, 0x80, 0, bodyTable[sceneHero->entity]);
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
itemX = (sceneHero->X + 0x100) >> 9;
|
||||
itemY = sceneHero->Y >> 8;
|
||||
if (sceneHero->brickShape & 0x7F) {
|
||||
itemY++;
|
||||
}
|
||||
itemZ = (sceneHero->Z + 0x100) >> 9;
|
||||
|
||||
drawOverModelActor(itemX, itemY, itemZ);
|
||||
flip();
|
||||
|
||||
projectPositionOnScreen(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ);
|
||||
projPosY -= 150;
|
||||
|
||||
boxTopLeftX = projPosX - 65;
|
||||
boxTopLeftY = projPosY - 65;
|
||||
|
||||
boxBottomRightX = projPosX + 65;
|
||||
boxBottomRightY = projPosY + 65;
|
||||
|
||||
playSample(41, 0x1000, 1, 0x80, 0x80, 0x80, -1);
|
||||
|
||||
// process vox play
|
||||
{
|
||||
int32 tmpLanguageCDId;
|
||||
stopMusic();
|
||||
tmpLanguageCDId = cfgfile.LanguageCDId;
|
||||
//cfgfile.LanguageCDId = 0; // comented so we can init vox bank
|
||||
initTextBank(2);
|
||||
cfgfile.LanguageCDId = tmpLanguageCDId;
|
||||
}
|
||||
|
||||
resetClip();
|
||||
initText(item);
|
||||
initDialogueBox();
|
||||
|
||||
textState = 1;
|
||||
quitItem = 0;
|
||||
|
||||
if (cfgfile.LanguageCDId) {
|
||||
initVoxToPlay(item);
|
||||
}
|
||||
|
||||
currentAnim = animTable[getBodyAnimIndex(kFoundItem, 0)];
|
||||
|
||||
tmpAnimTimer = sceneHero->animTimerData;
|
||||
|
||||
animBuffer2 += stockAnimation(animBuffer2, bodyTable[sceneHero->entity], &sceneHero->animTimerData);
|
||||
if (animBuffer1 + 4488 < animBuffer2) {
|
||||
animBuffer2 = animBuffer1;
|
||||
}
|
||||
|
||||
currentAnimState = 0;
|
||||
|
||||
prepareIsoModel(inventoryTable[item]);
|
||||
numOfRedrawBox = 0;
|
||||
|
||||
while (!quitItem) {
|
||||
resetClip();
|
||||
currNumOfRedrawBox = 0;
|
||||
blitBackgroundAreas();
|
||||
drawTransparentBox(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY, 4);
|
||||
|
||||
setClip(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
|
||||
|
||||
itemAngle[item] += 8;
|
||||
|
||||
renderInventoryItem(projPosX, projPosY, inventoryTable[item], itemAngle[item], 10000);
|
||||
|
||||
drawBox(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
|
||||
addRedrawArea(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
|
||||
resetClip();
|
||||
initEngineProjections();
|
||||
|
||||
if (setModelAnimation(currentAnimState, currentAnim, bodyTable[sceneHero->entity], &sceneHero->animTimerData)) {
|
||||
currentAnimState++; // keyframe
|
||||
if (currentAnimState >= getNumKeyframes(currentAnim)) {
|
||||
currentAnimState = getStartKeyframe(currentAnim);
|
||||
}
|
||||
}
|
||||
|
||||
renderIsoModel(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ, 0, 0x80, 0, bodyTable[sceneHero->entity]);
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
drawOverModelActor(itemX, itemY, itemZ);
|
||||
addRedrawArea(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
if (textState) {
|
||||
resetClip();
|
||||
textState = printText10();
|
||||
}
|
||||
|
||||
if (textState == 0 || textState == 2) {
|
||||
sdldelay(15);
|
||||
}
|
||||
|
||||
flipRedrawAreas();
|
||||
|
||||
readKeys();
|
||||
if (skippedKey) {
|
||||
if (!textState) {
|
||||
quitItem = 1;
|
||||
}
|
||||
|
||||
if (textState == 2) {
|
||||
textState = 1;
|
||||
}
|
||||
}
|
||||
|
||||
lbaTime++;
|
||||
}
|
||||
|
||||
while (playVoxSimple(currDialTextEntry)) {
|
||||
readKeys();
|
||||
if (skipIntro == 1) {
|
||||
break;
|
||||
}
|
||||
delaySkip(1);
|
||||
}
|
||||
|
||||
initEngineProjections();
|
||||
initTextBank(currentTextBank + 3);
|
||||
|
||||
/*do {
|
||||
readKeys();
|
||||
delaySkip(1);
|
||||
} while (!skipIntro);*/
|
||||
|
||||
if (cfgfile.LanguageCDId && isSamplePlaying(currDialTextEntry)) {
|
||||
stopVox(currDialTextEntry);
|
||||
}
|
||||
|
||||
sceneHero->animTimerData = tmpAnimTimer;
|
||||
}
|
||||
|
||||
void processGameChoices(int32 choiceIdx) {
|
||||
int32 i;
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
|
||||
gameChoicesSettings[0] = 0; // Current loaded button (button number)
|
||||
gameChoicesSettings[1] = numChoices; // Num of buttons
|
||||
gameChoicesSettings[2] = 0; // Buttons box height
|
||||
gameChoicesSettings[3] = currentTextBank + 3;
|
||||
|
||||
if (numChoices > 0) {
|
||||
for(i = 0; i < numChoices; i++) {
|
||||
gameChoicesSettings[i * 2 + 4] = 0;
|
||||
gameChoicesSettings[i * 2 + 5] = gameChoices[i];
|
||||
}
|
||||
}
|
||||
|
||||
drawAskQuestion(choiceIdx);
|
||||
|
||||
processMenu(gameChoicesSettings);
|
||||
choiceAnswer = gameChoices[gameChoicesSettings[0]];
|
||||
|
||||
// get right VOX entry index
|
||||
if (cfgfile.LanguageCDId) {
|
||||
initVoxToPlay(choiceAnswer);
|
||||
while(playVoxSimple(currDialTextEntry));
|
||||
stopVox(currDialTextEntry);
|
||||
|
||||
hasHiddenVox = 0;
|
||||
voxHiddenIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void processGameoverAnimation() { // makeGameOver
|
||||
int32 tmpLbaTime, startLbaTime;
|
||||
uint8 *gameOverPtr;
|
||||
|
||||
tmpLbaTime = lbaTime;
|
||||
|
||||
// workaround to fix hero redraw after drowning
|
||||
sceneHero->staticFlags.bIsHidden = 1;
|
||||
redrawEngineActions(1);
|
||||
sceneHero->staticFlags.bIsHidden = 0;
|
||||
|
||||
// TODO: drawInGameTransBox
|
||||
setPalette(paletteRGBA);
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
gameOverPtr = malloc(hqrEntrySize(HQR_RESS_FILE, RESSHQR_GAMEOVERMDL));
|
||||
hqrGetEntry(gameOverPtr, HQR_RESS_FILE, RESSHQR_GAMEOVERMDL);
|
||||
|
||||
if (gameOverPtr) {
|
||||
int32 avg, cdot;
|
||||
|
||||
prepareIsoModel(gameOverPtr);
|
||||
stopSamples();
|
||||
stopMidiMusic(); // stop fade music
|
||||
setCameraPosition(320, 240, 128, 200, 200);
|
||||
startLbaTime = lbaTime;
|
||||
setClip(120, 120, 519, 359);
|
||||
|
||||
while(skipIntro != 1 && (lbaTime - startLbaTime) <= 0x1F4) {
|
||||
readKeys();
|
||||
|
||||
avg = getAverageValue(40000, 3200, 500, lbaTime - startLbaTime);
|
||||
cdot = crossDot(1, 1024, 100, (lbaTime - startLbaTime) % 0x64);
|
||||
blitBox(120, 120, 519, 359, (int8*) workVideoBuffer, 120, 120, (int8*) frontVideoBuffer);
|
||||
setCameraAngle(0, 0, 0, 0, -cdot, 0, avg);
|
||||
renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
|
||||
copyBlockPhys(120, 120, 519, 359);
|
||||
|
||||
lbaTime++;
|
||||
sdldelay(15);
|
||||
}
|
||||
|
||||
playSample(37, Rnd(2000) + 3096, 1, 0x80, 0x80, 0x80, -1);
|
||||
blitBox(120, 120, 519, 359, (int8*) workVideoBuffer, 120, 120, (int8*) frontVideoBuffer);
|
||||
setCameraAngle(0, 0, 0, 0, 0, 0, 3200);
|
||||
renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
|
||||
copyBlockPhys(120, 120, 519, 359);
|
||||
|
||||
delaySkip(2000);
|
||||
|
||||
resetClip();
|
||||
free(gameOverPtr);
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
flip();
|
||||
initEngineProjections();
|
||||
|
||||
lbaTime = tmpLbaTime;
|
||||
}
|
||||
}
|
114
engines/twine/gamestate.h
Normal file
114
engines/twine/gamestate.h
Normal file
@ -0,0 +1,114 @@
|
||||
/** @file gamestate.h
|
||||
@brief
|
||||
This file contains game state routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef GAMESTATE_H
|
||||
#define GAMESTATE_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
#define NUM_GAME_FLAGS 255
|
||||
#define NUM_INVENTORY_ITEMS 28
|
||||
|
||||
#define GAMEFLAG_HAS_HOLOMAP 0
|
||||
#define GAMEFLAG_HAS_MAGICBALL 1
|
||||
#define GAMEFLAG_HAS_SABRE 2
|
||||
#define GAMEFLAG_TUNIC 4
|
||||
#define GAMEFLAG_BOOKOFBU 6
|
||||
#define GAMEFLAG_PROTOPACK 12
|
||||
#define GAMEFLAG_MECA_PINGUIN 14
|
||||
#define GAMEFLAG_HAS_CLOVER_LEAF 27
|
||||
#define GAMEFLAG_INVENTORY_DISABLED 70
|
||||
|
||||
/** Magicball strength*/
|
||||
enum MagicballStrengthType {
|
||||
kNoBallStrenght = 2,
|
||||
kYellowBallStrenght = 3,
|
||||
kGreenBallStrenght = 4,
|
||||
kRedBallStrenght = 6,
|
||||
kFireBallStrength = 8
|
||||
};
|
||||
|
||||
/** LBA engine game flags to save quest states */
|
||||
uint8 gameFlags[256];
|
||||
|
||||
/** LBA engine chapter */
|
||||
int16 gameChapter;
|
||||
|
||||
/** Magic ball type index */
|
||||
int16 magicBallIdx;
|
||||
/** Magic ball num bounce */
|
||||
int16 magicBallNumBounce;
|
||||
/** Magic ball auxiliar bounce number */
|
||||
int16 magicBallAuxBounce; // magicBallParam
|
||||
/** Magic level index */
|
||||
int16 magicLevelIdx;
|
||||
|
||||
/** Store the number of inventory keys */
|
||||
int16 inventoryNumKeys;
|
||||
/** Store the number of inventory kashes */
|
||||
int16 inventoryNumKashes;
|
||||
/** Store the number of inventory clover leafs boxes */
|
||||
int16 inventoryNumLeafsBox;
|
||||
/** Store the number of inventory clover leafs */
|
||||
int16 inventoryNumLeafs;
|
||||
/** Store the number of inventory magic points */
|
||||
int16 inventoryMagicPoints;
|
||||
/** Store the number of gas */
|
||||
int16 inventoryNumGas;
|
||||
|
||||
/** Its using FunFrock Sabre */
|
||||
int16 usingSabre;
|
||||
|
||||
/** Inventory used flags */
|
||||
uint8 inventoryFlags[NUM_INVENTORY_ITEMS];
|
||||
|
||||
/** Inventory used flags */
|
||||
uint8 holomapFlags[150]; // GV14
|
||||
|
||||
int8 savePlayerName[30]; // playerName
|
||||
|
||||
int32 gameChoices[10]; // inGameMenuData
|
||||
int32 numChoices; // numOfOptionsInChoice
|
||||
int16 gameChoicesSettings[18]; // choiceTab - same structure as menu settings
|
||||
int32 choiceAnswer; // inGameMenuAnswer
|
||||
|
||||
extern int32 magicLevelStrengthOfHit[];
|
||||
|
||||
/** Initialize all engine variables */
|
||||
void initEngineVars(int32 save);
|
||||
|
||||
/** Initialize engine 3D projections */
|
||||
void initEngineProjections();
|
||||
|
||||
void processFoundItem(int32 item);
|
||||
|
||||
void loadGame();
|
||||
void saveGame();
|
||||
|
||||
void processGameChoices(int32 choiceIdx);
|
||||
|
||||
void processGameoverAnimation();
|
||||
|
||||
#endif
|
984
engines/twine/grid.cpp
Normal file
984
engines/twine/grid.cpp
Normal file
@ -0,0 +1,984 @@
|
||||
/** @file grid.cpp
|
||||
@brief
|
||||
This file contains grid manipulation routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "grid.h"
|
||||
#include "resources.h"
|
||||
#include "lbaengine.h"
|
||||
#include "scene.h"
|
||||
#include "sdlengine.h"
|
||||
#include "interface.h"
|
||||
#include "screens.h"
|
||||
#include "actor.h"
|
||||
#include "renderer.h"
|
||||
#include "redraw.h"
|
||||
#include "collision.h"
|
||||
|
||||
/** Grip X size */
|
||||
#define GRID_SIZE_X 64
|
||||
/** Grip Y size */
|
||||
#define GRID_SIZE_Y 25
|
||||
/** Grip Z size */
|
||||
#define GRID_SIZE_Z GRID_SIZE_X
|
||||
|
||||
/** Total number of bricks allowed in the game */
|
||||
#define NUM_BRICKS 9000
|
||||
|
||||
/** Total number of bricks allowed in the game */
|
||||
#define CELLING_GRIDS_START_INDEX 120
|
||||
|
||||
/** Table with all loaded bricks */
|
||||
uint8* brickTable[NUM_BRICKS];
|
||||
/** Table with all loaded bricks masks */
|
||||
uint8* brickMaskTable[NUM_BRICKS];
|
||||
/** Table with all loaded bricks sizes */
|
||||
uint32 brickSizeTable[NUM_BRICKS];
|
||||
/** Table with all loaded bricks usage */
|
||||
uint8 brickUsageTable[NUM_BRICKS];
|
||||
|
||||
/** Current grid pointer */
|
||||
uint8 *currentGrid;
|
||||
/** Current block library pointer */
|
||||
uint8 *currentBll;
|
||||
/** Number of block libraries */
|
||||
int32 numberOfBll;
|
||||
|
||||
/** Block fragment entry */
|
||||
struct BlockEntry {
|
||||
/** Block library index */
|
||||
uint8 blockIdx;
|
||||
/** Brick index inside the block library */
|
||||
uint8 brickBlockIdx;
|
||||
};
|
||||
/** Grid block entry types */
|
||||
typedef struct BlockEntry blockMap[64][64][25];
|
||||
|
||||
/** Brick entry data */
|
||||
typedef struct BrickEntry {
|
||||
/** Brick X position in screen */
|
||||
int16 x; //z
|
||||
/** Brick Y position in screen */
|
||||
int16 y;
|
||||
/** Brick Z position in screen */
|
||||
int16 z; // x
|
||||
/** Brick pixel X position */
|
||||
int16 posX;
|
||||
/** Brick pixel Y position */
|
||||
int16 posY;
|
||||
/** Brick index */
|
||||
int16 index;
|
||||
/** Brick shape type */
|
||||
uint8 shape;
|
||||
/** Brick sound type */
|
||||
uint8 sound;
|
||||
} BrickEntry;
|
||||
|
||||
/** Brick data buffer */
|
||||
BrickEntry bricksDataBuffer[28][150];
|
||||
/** Brick info buffer */
|
||||
int16 brickInfoBuffer[28];
|
||||
|
||||
/** Current brick pixel X position */
|
||||
int32 brickPixelPosX;
|
||||
/** Current brick pixel Y position */
|
||||
int32 brickPixelPosY;
|
||||
|
||||
/** Copy grid mask to allow actors to display over the bricks
|
||||
@param index current brick index
|
||||
@param x grid X coordinate
|
||||
@param y grid Y coordinate
|
||||
@param buffer work video buffer */
|
||||
void copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
|
||||
uint8 *ptr;
|
||||
int32 top;
|
||||
int32 bottom;
|
||||
int32 left;
|
||||
int32 right;
|
||||
uint8 *outPtr;
|
||||
uint8 *inPtr;
|
||||
int32 offset;
|
||||
int32 vc3;
|
||||
|
||||
int32 temp;
|
||||
int32 j;
|
||||
|
||||
int32 absX;
|
||||
int32 absY;
|
||||
|
||||
int32 vSize;
|
||||
|
||||
ptr = brickMaskTable[index];
|
||||
|
||||
left = x + *(ptr + 2);
|
||||
top = y + *(ptr + 3);
|
||||
right = *ptr + left - 1;
|
||||
bottom = *(ptr + 1) + top - 1;
|
||||
|
||||
if (left > textWindowRight || right < textWindowLeft || bottom < textWindowTop || top > textWindowBottom)
|
||||
return;
|
||||
|
||||
ptr += 4;
|
||||
|
||||
absX = left;
|
||||
absY = top;
|
||||
|
||||
vSize = (bottom - top) + 1;
|
||||
|
||||
if (vSize <= 0)
|
||||
return;
|
||||
|
||||
offset = -((right - left) - SCREEN_WIDTH) - 1;
|
||||
|
||||
right++;
|
||||
bottom++;
|
||||
|
||||
// if line on top aren't in the blitting area...
|
||||
if (absY < textWindowTop) {
|
||||
int numOfLineToRemove;
|
||||
|
||||
numOfLineToRemove = textWindowTop - absY;
|
||||
|
||||
vSize -= numOfLineToRemove;
|
||||
if (vSize <= 0)
|
||||
return;
|
||||
|
||||
absY += numOfLineToRemove;
|
||||
|
||||
do {
|
||||
int lineDataSize;
|
||||
|
||||
lineDataSize = *(ptr++);
|
||||
ptr += lineDataSize;
|
||||
} while (--numOfLineToRemove);
|
||||
}
|
||||
|
||||
// reduce the vSize to remove lines on bottom
|
||||
if (absY + vSize - 1 > textWindowBottom) {
|
||||
vSize = textWindowBottom - absY + 1;
|
||||
if (vSize <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
outPtr = frontVideoBuffer + screenLookupTable[absY] + left;
|
||||
inPtr = buffer + screenLookupTable[absY] + left;
|
||||
|
||||
do {
|
||||
vc3 = *(ptr++);
|
||||
|
||||
do {
|
||||
temp = *(ptr++); // skip size
|
||||
outPtr += temp;
|
||||
inPtr += temp;
|
||||
|
||||
absX += temp;
|
||||
|
||||
vc3--;
|
||||
if (!vc3)
|
||||
break;
|
||||
|
||||
temp = *(ptr++); // copy size
|
||||
|
||||
for (j = 0; j < temp; j++) {
|
||||
if (absX >= textWindowLeft && absX <= textWindowRight)
|
||||
*outPtr = *inPtr;
|
||||
|
||||
absX++;
|
||||
outPtr++;
|
||||
inPtr++;
|
||||
}
|
||||
} while (--vc3);
|
||||
|
||||
absX = left;
|
||||
|
||||
outPtr += offset;
|
||||
inPtr += offset;
|
||||
} while (--vSize);
|
||||
}
|
||||
|
||||
/** Draw 3D actor over bricks
|
||||
@param X actor X coordinate
|
||||
@param Y actor Y coordinate
|
||||
@param Z actor Z coordinate */
|
||||
void drawOverModelActor(int32 X, int32 Y, int32 Z) {
|
||||
int32 CopyBlockPhysLeft;
|
||||
int32 CopyBlockPhysRight;
|
||||
int32 i;
|
||||
int32 j;
|
||||
BrickEntry *currBrickEntry;
|
||||
|
||||
CopyBlockPhysLeft = ((textWindowLeft + 24) / 24) - 1;
|
||||
CopyBlockPhysRight = ((textWindowRight + 24) / 24);
|
||||
|
||||
for (j = CopyBlockPhysLeft; j <= CopyBlockPhysRight; j++) {
|
||||
for (i = 0; i < brickInfoBuffer[j]; i++) {
|
||||
currBrickEntry = &bricksDataBuffer[j][i];
|
||||
|
||||
if (currBrickEntry->posY + 38 > textWindowTop && currBrickEntry->posY <= textWindowBottom && currBrickEntry->y >= Y) {
|
||||
if (currBrickEntry->x + currBrickEntry->z > Z + X) {
|
||||
copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw sprite actor over bricks
|
||||
@param X actor X coordinate
|
||||
@param Y actor Y coordinate
|
||||
@param Z actor Z coordinate */
|
||||
void drawOverSpriteActor(int32 X, int32 Y, int32 Z) {
|
||||
int32 CopyBlockPhysLeft;
|
||||
int32 CopyBlockPhysRight;
|
||||
int32 i;
|
||||
int32 j;
|
||||
BrickEntry *currBrickEntry;
|
||||
|
||||
CopyBlockPhysLeft = ((textWindowLeft + 24) / 24) - 1;
|
||||
CopyBlockPhysRight = (textWindowRight + 24) / 24;
|
||||
|
||||
for (j = CopyBlockPhysLeft; j <= CopyBlockPhysRight; j++) {
|
||||
for (i = 0; i < brickInfoBuffer[j]; i++) {
|
||||
currBrickEntry = &bricksDataBuffer[j][i];
|
||||
|
||||
if (currBrickEntry->posY + 38 > textWindowTop && currBrickEntry->posY <= textWindowBottom && currBrickEntry->y >= Y) {
|
||||
if ((currBrickEntry->x == X) && (currBrickEntry->z == Z)) {
|
||||
copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
|
||||
}
|
||||
|
||||
if ((currBrickEntry->x > X) || (currBrickEntry->z > Z)) {
|
||||
copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Process brick masks to allow actors to display over the bricks
|
||||
@param buffer brick pointer buffer
|
||||
@param ptr brick mask pointer buffer */
|
||||
int processGridMask(uint8 *buffer, uint8 *ptr) {
|
||||
uint32 *ptrSave = (uint32 *)ptr;
|
||||
uint8 *ptr2;
|
||||
uint8 *esi;
|
||||
uint8 *edi;
|
||||
uint8 iteration, numOfBlock, ah, bl, al, bh;
|
||||
int32 ebx;
|
||||
|
||||
ebx = *((uint32 *)buffer); // brick flag
|
||||
buffer += 4;
|
||||
*((uint32 *)ptr) = ebx;
|
||||
ptr += 4;
|
||||
|
||||
bh = (ebx & 0x0000FF00) >> 8;
|
||||
|
||||
esi = (uint8 *) buffer;
|
||||
edi = (uint8 *) ptr;
|
||||
|
||||
iteration = 0;
|
||||
|
||||
do {
|
||||
numOfBlock = 0;
|
||||
ah = 0;
|
||||
ptr2 = edi;
|
||||
|
||||
edi++;
|
||||
|
||||
bl = *(esi++);
|
||||
|
||||
if (*(esi) & 0xC0) { // the first time isn't skip. the skip size is 0 in that case
|
||||
*edi++ = 0;
|
||||
numOfBlock++;
|
||||
}
|
||||
|
||||
do {
|
||||
al = *esi++;
|
||||
iteration = al;
|
||||
iteration &= 0x3F;
|
||||
iteration++;
|
||||
|
||||
if (al & 0x80) {
|
||||
ah += iteration;
|
||||
esi++;
|
||||
} else if (al & 0x40) {
|
||||
ah += iteration;
|
||||
esi += iteration;
|
||||
} else { // skip
|
||||
if (ah) {
|
||||
*edi++ = ah; // write down the number of pixel passed so far
|
||||
numOfBlock++;
|
||||
ah = 0;
|
||||
}
|
||||
*(edi++) = iteration; //write skip
|
||||
numOfBlock++;
|
||||
}
|
||||
} while (--bl > 0);
|
||||
|
||||
if (ah) {
|
||||
*edi++ = ah;
|
||||
numOfBlock++;
|
||||
|
||||
ah = 0;
|
||||
}
|
||||
|
||||
*ptr2 = numOfBlock;
|
||||
} while (--bh > 0);
|
||||
|
||||
return ((int)((uint8 *) edi - (uint8 *) ptrSave));
|
||||
}
|
||||
|
||||
/** Create grid masks to allow display actors over the bricks */
|
||||
void createGridMask() {
|
||||
int32 b;
|
||||
|
||||
for (b = 0; b < NUM_BRICKS; b++) {
|
||||
if (brickUsageTable[b]) {
|
||||
if (brickMaskTable[b])
|
||||
free(brickMaskTable[b]);
|
||||
brickMaskTable[b] = (uint8*)malloc(brickSizeTable[b]);
|
||||
processGridMask(brickTable[b], brickMaskTable[b]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get sprite width and height sizes
|
||||
@param offset sprite pointer offset
|
||||
@param width sprite width size
|
||||
@param height sprite height size
|
||||
@param spritePtr sprite buffer pointer */
|
||||
void getSpriteSize(int32 offset, int32 *width, int32 *height, uint8 *spritePtr) {
|
||||
spritePtr += *((int32 *)(spritePtr + offset * 4));
|
||||
|
||||
*width = *spritePtr;
|
||||
*height = *(spritePtr + 1);
|
||||
}
|
||||
|
||||
/** Load grid bricks according with block librarie usage
|
||||
@param gridSize size of the current grid
|
||||
@return true if everything went ok*/
|
||||
int32 loadGridBricks(int32 gridSize) {
|
||||
uint32 firstBrick = 60000;
|
||||
uint32 lastBrick = 0;
|
||||
uint8* ptrToBllBits;
|
||||
uint32 i;
|
||||
uint32 j;
|
||||
uint32 currentBllEntryIdx = 0;
|
||||
|
||||
memset(brickTable, 0, sizeof(brickTable));
|
||||
memset(brickSizeTable, 0, sizeof(brickSizeTable));
|
||||
memset(brickUsageTable, 0, sizeof(brickUsageTable));
|
||||
|
||||
// get block librarie usage bits
|
||||
ptrToBllBits = currentGrid + (gridSize - 32);
|
||||
|
||||
// for all bits under the 32bytes (256bits)
|
||||
for (i = 1; i < 256; i++) {
|
||||
uint8 currentBitByte = *(ptrToBllBits + (i / 8));
|
||||
uint8 currentBitMask = 1 << (7 - (i & 7));
|
||||
|
||||
if (currentBitByte & currentBitMask) {
|
||||
uint32 currentBllOffset = *((uint32 *)(currentBll + currentBllEntryIdx));
|
||||
uint8* currentBllPtr = currentBll + currentBllOffset;
|
||||
|
||||
uint32 bllSizeX = currentBllPtr[0];
|
||||
uint32 bllSizeY = currentBllPtr[1];
|
||||
uint32 bllSizeZ = currentBllPtr[2];
|
||||
|
||||
uint32 bllSize = bllSizeX * bllSizeY * bllSizeZ;
|
||||
|
||||
uint8* bllDataPtr = currentBllPtr + 5;
|
||||
|
||||
for (j = 0; j < bllSize; j++) {
|
||||
uint32 brickIdx = *((int16*)(bllDataPtr));
|
||||
|
||||
if (brickIdx) {
|
||||
brickIdx--;
|
||||
|
||||
if (brickIdx <= firstBrick)
|
||||
firstBrick = brickIdx;
|
||||
|
||||
if (brickIdx > lastBrick)
|
||||
lastBrick = brickIdx;
|
||||
|
||||
brickUsageTable[brickIdx] = 1;
|
||||
}
|
||||
bllDataPtr += 4;
|
||||
}
|
||||
}
|
||||
currentBllEntryIdx += 4;
|
||||
}
|
||||
|
||||
for (i = firstBrick; i <= lastBrick; i++) {
|
||||
if (brickUsageTable[i]) {
|
||||
brickSizeTable[i] = hqrGetallocEntry(&brickTable[i], HQR_LBA_BRK_FILE, i);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Create grid Y column in block buffer
|
||||
@param gridEntry current grid index
|
||||
@param dest destination block buffer */
|
||||
void createGridColumn(uint8 *gridEntry, uint8 *dest) {
|
||||
int32 blockCount;
|
||||
int32 brickCount;
|
||||
int32 flag;
|
||||
int32 gridIdx;
|
||||
int32 i;
|
||||
uint16 *gridBuffer;
|
||||
uint16 *blockByffer;
|
||||
|
||||
brickCount = *(gridEntry++);
|
||||
|
||||
do {
|
||||
flag = *(gridEntry++);
|
||||
|
||||
blockCount = (flag & 0x3F) + 1;
|
||||
|
||||
gridBuffer = (uint16 *) gridEntry;
|
||||
blockByffer = (uint16 *) dest;
|
||||
|
||||
if (!(flag & 0xC0)) {
|
||||
for (i = 0; i < blockCount; i++)
|
||||
*(blockByffer++) = 0;
|
||||
} else if (flag & 0x40) {
|
||||
for (i = 0; i < blockCount; i++)
|
||||
*(blockByffer++) = *(gridBuffer++);
|
||||
} else {
|
||||
gridIdx = *(gridBuffer++);
|
||||
for (i = 0; i < blockCount; i++)
|
||||
*(blockByffer++) = gridIdx;
|
||||
}
|
||||
|
||||
gridEntry = (uint8 *) gridBuffer;
|
||||
dest = (uint8 *) blockByffer;
|
||||
|
||||
} while (--brickCount);
|
||||
}
|
||||
|
||||
/** Create grid Y column in block buffer
|
||||
@param gridEntry current grid index
|
||||
@param dest destination block buffer */
|
||||
void createCellingGridColumn(uint8 *gridEntry, uint8 *dest) {
|
||||
int32 blockCount;
|
||||
int32 brickCount;
|
||||
int32 flag;
|
||||
int32 gridIdx;
|
||||
int32 i;
|
||||
uint16 *gridBuffer;
|
||||
uint16 *blockByffer;
|
||||
|
||||
brickCount = *(gridEntry++);
|
||||
|
||||
do {
|
||||
flag = *(gridEntry++);
|
||||
|
||||
blockCount = (flag & 0x3F) + 1;
|
||||
|
||||
gridBuffer = (uint16*) gridEntry;
|
||||
blockByffer = (uint16 *) dest;
|
||||
|
||||
if (!(flag & 0xC0)) {
|
||||
for (i = 0; i < blockCount; i++)
|
||||
blockByffer++;
|
||||
} else if (flag & 0x40) {
|
||||
for (i = 0; i < blockCount; i++)
|
||||
*(blockByffer++) = *(gridBuffer++);
|
||||
} else {
|
||||
gridIdx = *(gridBuffer++);
|
||||
for (i = 0; i < blockCount; i++)
|
||||
*(blockByffer++) = gridIdx;
|
||||
}
|
||||
|
||||
gridEntry = (uint8 *) gridBuffer;
|
||||
dest = (uint8 *) blockByffer;
|
||||
|
||||
} while (--brickCount);
|
||||
}
|
||||
|
||||
/** Create grid map from current grid to block library buffer */
|
||||
void createGridMap() {
|
||||
int32 currOffset = 0;
|
||||
int32 blockOffset;
|
||||
int32 gridIdx;
|
||||
int32 x, z;
|
||||
|
||||
for (z = 0; z < GRID_SIZE_Z; z++) {
|
||||
blockOffset = currOffset;
|
||||
gridIdx = z << 6;
|
||||
|
||||
for (x = 0; x < GRID_SIZE_X; x++) {
|
||||
int32 gridOffset = *((uint16 *)(currentGrid + 2 * (x + gridIdx)));
|
||||
createGridColumn(currentGrid + gridOffset, blockBuffer + blockOffset);
|
||||
blockOffset += 50;
|
||||
}
|
||||
currOffset += 3200;
|
||||
}
|
||||
}
|
||||
|
||||
/** Create celling grid map from celling grid to block library buffer
|
||||
@param gridPtr celling grid buffer pointer */
|
||||
void createCellingGridMap(uint8* gridPtr) {
|
||||
int32 currGridOffset = 0;
|
||||
int32 currOffset = 0;
|
||||
int32 blockOffset;
|
||||
int32 z, x;
|
||||
uint8* tempGridPtr;
|
||||
|
||||
for (z = 0; z < GRID_SIZE_Z; z++) {
|
||||
blockOffset = currOffset;
|
||||
tempGridPtr = gridPtr + currGridOffset;
|
||||
|
||||
for (x = 0; x < GRID_SIZE_X; x++) {
|
||||
int gridOffset = *((uint16 *)tempGridPtr);
|
||||
tempGridPtr += 2;
|
||||
createCellingGridColumn(gridPtr + gridOffset, blockBuffer + blockOffset);
|
||||
blockOffset += 50;
|
||||
}
|
||||
currGridOffset += 128;
|
||||
currOffset += 3200;
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize grid (background scenearios)
|
||||
@param index grid index number */
|
||||
int32 initGrid(int32 index) {
|
||||
|
||||
// load grids from file
|
||||
int32 gridSize = hqrGetallocEntry(¤tGrid, HQR_LBA_GRI_FILE, index);
|
||||
|
||||
// load layouts from file
|
||||
hqrGetallocEntry(¤tBll, HQR_LBA_BLL_FILE, index);
|
||||
|
||||
loadGridBricks(gridSize);
|
||||
|
||||
createGridMask();
|
||||
|
||||
numberOfBll = (*((uint32 *)currentBll) >> 2);
|
||||
|
||||
createGridMap();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Initialize celling grid (background scenearios)
|
||||
@param index grid index number */
|
||||
int32 initCellingGrid(int32 index) {
|
||||
uint8* gridPtr;
|
||||
|
||||
// load grids from file
|
||||
hqrGetallocEntry(&gridPtr, HQR_LBA_GRI_FILE, index + CELLING_GRIDS_START_INDEX);
|
||||
|
||||
createCellingGridMap(gridPtr);
|
||||
|
||||
if (gridPtr)
|
||||
free(gridPtr);
|
||||
|
||||
reqBgRedraw = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Draw brick sprite in the screen
|
||||
@param index brick index to draw
|
||||
@param posX brick X position to draw
|
||||
@param posY brick Y position to draw */
|
||||
void drawBrick(int32 index, int32 posX, int32 posY) {
|
||||
drawBrickSprite(index, posX, posY, brickTable[index], 0);
|
||||
}
|
||||
|
||||
/** Draw sprite in the screen
|
||||
@param index sprite index to draw
|
||||
@param posX sprite X position to draw
|
||||
@param posY sprite Y position to draw
|
||||
@param ptr sprite buffer pointer to draw */
|
||||
void drawSprite(int32 index, int32 posX, int32 posY, uint8 *ptr) {
|
||||
drawBrickSprite(index, posX, posY, ptr, 1);
|
||||
}
|
||||
|
||||
// WARNING: Rewrite this function to have better performance
|
||||
/** Draw sprite or bricks in the screen according with the type
|
||||
@param index sprite index to draw
|
||||
@param posX sprite X position to draw
|
||||
@param posY sprite Y position to draw
|
||||
@param ptr sprite buffer pointer to draw
|
||||
@param isSprite allows to identify if the sprite to display is brick or a single sprite */
|
||||
void drawBrickSprite(int32 index, int32 posX, int32 posY, uint8 *ptr, int32 isSprite) {
|
||||
//unsigned char *ptr;
|
||||
int32 top;
|
||||
int32 bottom;
|
||||
int32 left;
|
||||
int32 right;
|
||||
uint8 *outPtr;
|
||||
int32 offset;
|
||||
int32 c1;
|
||||
int32 c2;
|
||||
int32 vc3;
|
||||
|
||||
int32 temp;
|
||||
int32 iteration;
|
||||
int32 i;
|
||||
|
||||
int32 x;
|
||||
int32 y;
|
||||
|
||||
if (isSprite == 1)
|
||||
ptr = ptr + *((uint32 *)(ptr + index * 4));
|
||||
|
||||
left = posX + *(ptr + 2);
|
||||
top = posY + *(ptr + 3);
|
||||
right = *ptr + left - 1;
|
||||
bottom = *(ptr + 1) + top - 1;
|
||||
|
||||
ptr += 4;
|
||||
|
||||
x = left;
|
||||
y = top;
|
||||
|
||||
//if (left >= textWindowLeft-2 && top >= textWindowTop-2 && right <= textWindowRight-2 && bottom <= textWindowBottom-2) // crop
|
||||
{
|
||||
right++;
|
||||
bottom++;
|
||||
|
||||
outPtr = frontVideoBuffer + screenLookupTable[top] + left;
|
||||
|
||||
offset = -((right - left) - SCREEN_WIDTH);
|
||||
|
||||
for (c1 = 0; c1 < bottom - top; c1++) {
|
||||
vc3 = *(ptr++);
|
||||
for (c2 = 0; c2 < vc3; c2++) {
|
||||
temp = *(ptr++);
|
||||
iteration = temp & 0x3F;
|
||||
if (temp & 0xC0) {
|
||||
iteration++;
|
||||
if (!(temp & 0x40)) {
|
||||
temp = *(ptr++);
|
||||
for (i = 0; i < iteration; i++) {
|
||||
if (x >= textWindowLeft && x<textWindowRight && y >= textWindowTop && y < textWindowBottom)
|
||||
frontVideoBuffer[y*SCREEN_WIDTH+x] = temp;
|
||||
|
||||
x++;
|
||||
outPtr++;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < iteration; i++) {
|
||||
if (x >= textWindowLeft && x<textWindowRight && y >= textWindowTop && y < textWindowBottom)
|
||||
frontVideoBuffer[y*SCREEN_WIDTH+x] = *ptr;
|
||||
|
||||
x++;
|
||||
ptr++;
|
||||
outPtr++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outPtr += iteration + 1;
|
||||
x += iteration + 1;
|
||||
}
|
||||
}
|
||||
outPtr += offset;
|
||||
x = left;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get block library
|
||||
@param index block library index
|
||||
@return pointer to the current block index */
|
||||
uint8* getBlockLibrary(int32 index) {
|
||||
int32 offset = *((uint32 *)(currentBll + 4 * index));
|
||||
return (uint8 *)(currentBll + offset);
|
||||
}
|
||||
|
||||
/** Get brick position in the screen
|
||||
@param x column x position in the current camera
|
||||
@param y column y position in the current camera
|
||||
@param z column z position in the current camera */
|
||||
void getBrickPos(int32 x, int32 y, int32 z) {
|
||||
brickPixelPosX = (x - z) * 24 + 288; // x pos
|
||||
brickPixelPosY = ((x + z) * 12) - (y * 15) + 215; // y pos
|
||||
}
|
||||
|
||||
/** Draw a specific brick in the grid column according with the block index
|
||||
@param blockIdx block library index
|
||||
@param brickBlockIdx brick index inside the block
|
||||
@param x column x position
|
||||
@param y column y position
|
||||
@param z column z position */
|
||||
void drawColumnGrid(int32 blockIdx, int32 brickBlockIdx, int32 x, int32 y, int32 z) {
|
||||
uint8 *blockPtr;
|
||||
uint16 brickIdx;
|
||||
uint8 brickShape;
|
||||
uint8 brickSound;
|
||||
int32 brickBuffIdx;
|
||||
BrickEntry *currBrickEntry;
|
||||
|
||||
blockPtr = getBlockLibrary(blockIdx) + 3 + brickBlockIdx * 4;
|
||||
|
||||
brickShape = *((uint8 *)(blockPtr));
|
||||
brickSound = *((uint8 *)(blockPtr + 1));
|
||||
brickIdx = *((uint16 *)(blockPtr + 2));
|
||||
|
||||
if (!brickIdx)
|
||||
return;
|
||||
|
||||
getBrickPos(x - newCameraX, y - newCameraY, z - newCameraZ);
|
||||
|
||||
if (brickPixelPosX < -24)
|
||||
return;
|
||||
if (brickPixelPosX >= SCREEN_WIDTH)
|
||||
return;
|
||||
if (brickPixelPosY < -38)
|
||||
return;
|
||||
if (brickPixelPosY >= SCREEN_HEIGHT)
|
||||
return;
|
||||
|
||||
// draw the background brick
|
||||
drawBrick(brickIdx - 1, brickPixelPosX, brickPixelPosY);
|
||||
|
||||
brickBuffIdx = (brickPixelPosX + 24) / 24;
|
||||
|
||||
if (brickInfoBuffer[brickBuffIdx] >= 150) {
|
||||
printf("\nGRID WARNING: brick buffer exceeded! \n");
|
||||
return;
|
||||
}
|
||||
|
||||
currBrickEntry = &bricksDataBuffer[brickBuffIdx][brickInfoBuffer[brickBuffIdx]];
|
||||
|
||||
currBrickEntry->x = x;
|
||||
currBrickEntry->y = y;
|
||||
currBrickEntry->z = z;
|
||||
currBrickEntry->posX = brickPixelPosX;
|
||||
currBrickEntry->posY = brickPixelPosY;
|
||||
currBrickEntry->index = brickIdx - 1;
|
||||
currBrickEntry->shape = brickShape;
|
||||
currBrickEntry->sound = brickSound;
|
||||
|
||||
brickInfoBuffer[brickBuffIdx]++;
|
||||
}
|
||||
|
||||
/** Redraw grid background */
|
||||
void redrawGrid() {
|
||||
int32 i, x, y, z;
|
||||
uint8 blockIdx;
|
||||
blockMap* map = (blockMap*)blockBuffer;
|
||||
|
||||
cameraX = newCameraX << 9;
|
||||
cameraY = newCameraY << 8;
|
||||
cameraZ = newCameraZ << 9;
|
||||
|
||||
projectPositionOnScreen(-cameraX, -cameraY, -cameraZ);
|
||||
|
||||
projPosXScreen = projPosX;
|
||||
projPosYScreen = projPosY;
|
||||
|
||||
for (i = 0; i < 28; i++) {
|
||||
brickInfoBuffer[i] = 0;
|
||||
}
|
||||
|
||||
if (changeRoomVar10 == 0)
|
||||
return;
|
||||
|
||||
for (z = 0; z < GRID_SIZE_Z; z++) {
|
||||
for (x = 0; x < GRID_SIZE_X; x++) {
|
||||
for (y = 0; y < GRID_SIZE_Y; y++) {
|
||||
blockIdx = (*map)[z][x][y].blockIdx;
|
||||
if (blockIdx) {
|
||||
drawColumnGrid(blockIdx - 1, (*map)[z][x][y].brickBlockIdx, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 getBrickShape(int32 x, int32 y, int32 z) { // WorldColBrick
|
||||
uint8 blockIdx;
|
||||
uint8 *blockBufferPtr;
|
||||
|
||||
blockBufferPtr = blockBuffer;
|
||||
|
||||
collisionX = (x + 0x100) >> 9;
|
||||
collisionY = y >> 8;
|
||||
collisionZ = (z + 0x100) >> 9;
|
||||
|
||||
if (collisionX < 0 || collisionX >= 64)
|
||||
return 0;
|
||||
|
||||
if (collisionY <= -1)
|
||||
return 1;
|
||||
|
||||
if (collisionY < 0 || collisionY > 24 || collisionZ < 0 || collisionZ >= 64)
|
||||
return 0;
|
||||
|
||||
blockBufferPtr += collisionX * 50;
|
||||
blockBufferPtr += collisionY * 2;
|
||||
blockBufferPtr += (collisionZ << 7) * 25;
|
||||
|
||||
blockIdx = *blockBufferPtr;
|
||||
|
||||
if (blockIdx) {
|
||||
uint8 *blockPtr;
|
||||
uint8 tmpBrickIdx;
|
||||
|
||||
blockPtr = currentBll;
|
||||
|
||||
blockPtr += *(uint32 *)(blockPtr + blockIdx * 4 - 4);
|
||||
blockPtr += 3;
|
||||
|
||||
tmpBrickIdx = *(blockBufferPtr + 1);
|
||||
blockPtr = blockPtr + tmpBrickIdx * 4;
|
||||
|
||||
return *blockPtr;
|
||||
} else {
|
||||
return *(blockBufferPtr + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int32 getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2) {
|
||||
int32 newY, currY, i;
|
||||
uint8 blockIdx, brickShape;
|
||||
uint8 *blockBufferPtr;
|
||||
|
||||
blockBufferPtr = blockBuffer;
|
||||
|
||||
collisionX = (x + 0x100) >> 9;
|
||||
collisionY = y >> 8;
|
||||
collisionZ = (z + 0x100) >> 9;
|
||||
|
||||
if (collisionX < 0 || collisionX >= 64)
|
||||
return 0;
|
||||
|
||||
if (collisionY <= -1)
|
||||
return 1;
|
||||
|
||||
if (collisionY < 0 || collisionY > 24 || collisionZ < 0 || collisionZ >= 64)
|
||||
return 0;
|
||||
|
||||
blockBufferPtr += collisionX * 50;
|
||||
blockBufferPtr += collisionY * 2;
|
||||
blockBufferPtr += (collisionZ << 7) * 25;
|
||||
|
||||
blockIdx = *blockBufferPtr;
|
||||
|
||||
if (blockIdx) {
|
||||
uint8 *blockPtr;
|
||||
uint8 tmpBrickIdx;
|
||||
|
||||
blockPtr = currentBll;
|
||||
|
||||
blockPtr += *(uint32 *)(blockPtr + blockIdx * 4 - 4);
|
||||
blockPtr += 3;
|
||||
|
||||
tmpBrickIdx = *(blockBufferPtr + 1);
|
||||
blockPtr = blockPtr + tmpBrickIdx * 4;
|
||||
|
||||
brickShape = *blockPtr;
|
||||
|
||||
newY = (y2 + 255) >> 8;
|
||||
currY = collisionY;
|
||||
|
||||
for (i = 0; i < newY; i++) {
|
||||
if (currY > 24) {
|
||||
return brickShape;
|
||||
}
|
||||
|
||||
blockBufferPtr += 2;
|
||||
currY++;
|
||||
|
||||
if (*(int16 *)(blockBufferPtr) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return brickShape;
|
||||
} else {
|
||||
brickShape = *(blockBufferPtr + 1);
|
||||
|
||||
newY = (y2 + 255) >> 8;
|
||||
currY = collisionY;
|
||||
|
||||
for (i = 0; i < newY; i++) {
|
||||
if (currY > 24) {
|
||||
return brickShape;
|
||||
}
|
||||
|
||||
blockBufferPtr += 2;
|
||||
currY++;
|
||||
|
||||
if (*(int16 *)(blockBufferPtr) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 getBrickSoundType(int32 x, int32 y, int32 z) { // getPos2
|
||||
uint8 blockIdx;
|
||||
uint8 *blockBufferPtr;
|
||||
|
||||
blockBufferPtr = blockBuffer;
|
||||
|
||||
collisionX = (x + 0x100) >> 9;
|
||||
collisionY = y >> 8;
|
||||
collisionZ = (z + 0x100) >> 9;
|
||||
|
||||
if (collisionX < 0 || collisionX >= 64)
|
||||
return 0;
|
||||
|
||||
if (collisionY <= -1)
|
||||
return 1;
|
||||
|
||||
if (collisionY < 0 || collisionY > 24 || collisionZ < 0 || collisionZ >= 64)
|
||||
return 0;
|
||||
|
||||
blockBufferPtr += collisionX * 50;
|
||||
blockBufferPtr += collisionY * 2;
|
||||
blockBufferPtr += (collisionZ << 7) * 25;
|
||||
|
||||
blockIdx = *blockBufferPtr;
|
||||
|
||||
if (blockIdx) {
|
||||
uint8 *blockPtr;
|
||||
uint8 tmpBrickIdx;
|
||||
|
||||
blockPtr = currentBll;
|
||||
|
||||
blockPtr += *(uint32 *)(blockPtr + blockIdx * 4 - 4);
|
||||
blockPtr += 3;
|
||||
|
||||
tmpBrickIdx = *(blockBufferPtr + 1);
|
||||
blockPtr = blockPtr + tmpBrickIdx * 4;
|
||||
blockPtr++;
|
||||
|
||||
return *((int16 *)blockPtr);
|
||||
}
|
||||
|
||||
return 0xF0;
|
||||
}
|
139
engines/twine/grid.h
Normal file
139
engines/twine/grid.h
Normal file
@ -0,0 +1,139 @@
|
||||
/** @file grid.h
|
||||
@brief
|
||||
This file contains grid manipulation routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef GRID_H
|
||||
#define GRID_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
enum ShapeType {
|
||||
kNone = 0,
|
||||
kSolid = 1,
|
||||
kStairsTopLeft = 2,
|
||||
kStairsTopRight = 3,
|
||||
kStairsBottomLeft = 4,
|
||||
kStairsBottomRight = 5,
|
||||
kDoubleSideStairsTop1 = 6,
|
||||
kDoubleSideStairsBottom1 = 7,
|
||||
kDoubleSideStairsLeft1 = 8,
|
||||
kDoubleSideStairsRight1 = 9,
|
||||
kDoubleSideStairsTop2 = 10,
|
||||
kDoubleSideStairsBottom2 = 11,
|
||||
kDoubleSideStairsLeft2 = 12,
|
||||
kDoubleSideStairsRight2 = 13,
|
||||
kFlatBottom1 = 14,
|
||||
kFlatBottom2 = 15
|
||||
};
|
||||
|
||||
/** New grid camera X coordinates */
|
||||
int32 newCameraX;
|
||||
/** New grid camera Y coordinates */
|
||||
int32 newCameraY;
|
||||
/** New grid camera Z coordinates */
|
||||
int32 newCameraZ;
|
||||
|
||||
/** Current grid camera X coordinates */
|
||||
int32 cameraX;
|
||||
/** Current grid camera Y coordinates */
|
||||
int32 cameraY;
|
||||
/** Current grid camera Z coordinates */
|
||||
int32 cameraZ;
|
||||
|
||||
/** Celling grid brick block buffer */
|
||||
uint8 *blockBuffer;
|
||||
|
||||
|
||||
/** Flag to know if the engine is using celling grids */
|
||||
int16 useCellingGrid; // useAnotherGrm
|
||||
/** Current celling grid index */
|
||||
int16 cellingGridIdx; // currentGrid2
|
||||
|
||||
|
||||
/** Draw 3D actor over bricks
|
||||
@param X actor X coordinate
|
||||
@param Y actor Y coordinate
|
||||
@param Z actor Z coordinate */
|
||||
void drawOverModelActor(int32 X, int32 Y, int32 Z);
|
||||
|
||||
/** Draw sprite actor over bricks
|
||||
@param X actor X coordinate
|
||||
@param Y actor Y coordinate
|
||||
@param Z actor Z coordinate */
|
||||
void drawOverSpriteActor(int32 X, int32 Y, int32 Z);
|
||||
|
||||
/** Get sprite width and height sizes
|
||||
@param offset sprite pointer offset
|
||||
@param width sprite width size
|
||||
@param height sprite height size
|
||||
@param spritePtr sprite buffer pointer */
|
||||
void getSpriteSize(int32 offset, int32 *width, int32 *height, uint8 *spritePtr);
|
||||
|
||||
/** Draw brick sprite in the screen
|
||||
@param index brick index to draw
|
||||
@param posX brick X position to draw
|
||||
@param posY brick Y position to draw */
|
||||
void drawBrick(int32 index, int32 posX, int32 posY);
|
||||
|
||||
/** Draw sprite in the screen
|
||||
@param index sprite index to draw
|
||||
@param posX sprite X position to draw
|
||||
@param posY sprite Y position to draw
|
||||
@param ptr sprite buffer pointer to draw */
|
||||
void drawSprite(int32 index, int32 posX, int32 posY, uint8 *spritePtr);
|
||||
|
||||
/** Draw sprite or bricks in the screen according with the type
|
||||
@param index sprite index to draw
|
||||
@param posX sprite X position to draw
|
||||
@param posY sprite Y position to draw
|
||||
@param ptr sprite buffer pointer to draw
|
||||
@param isSprite allows to identify if the sprite to display is brick or a single sprite */
|
||||
void drawBrickSprite(int32 index, int32 posX, int32 posY, uint8 *spritePtr, int32 isSprite);
|
||||
|
||||
/** Get block library
|
||||
@param index block library index
|
||||
@return pointer to the current block index */
|
||||
uint8* getBlockLibrary(int32 index);
|
||||
|
||||
/** Create grid map from current grid to block library buffer */
|
||||
void createGridMap();
|
||||
|
||||
/** Initialize grid (background scenearios)
|
||||
@param index grid index number */
|
||||
int32 initGrid(int32 index);
|
||||
|
||||
/** Initialize celling grid (background scenearios)
|
||||
@param index grid index number */
|
||||
int32 initCellingGrid(int32 index);
|
||||
|
||||
/** Redraw grid background */
|
||||
void redrawGrid();
|
||||
|
||||
int32 getBrickShape(int32 x, int32 y, int32 z);
|
||||
|
||||
int32 getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2);
|
||||
|
||||
int32 getBrickSoundType(int32 x, int32 y, int32 z);
|
||||
|
||||
#endif
|
40
engines/twine/holomap.cpp
Normal file
40
engines/twine/holomap.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/** @file holomap.cpp
|
||||
@brief
|
||||
This file contains holomap routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "holomap.h"
|
||||
#include "gamestate.h"
|
||||
|
||||
/** Set Holomap location position
|
||||
@location Scene where position must be set */
|
||||
void setHolomapPosition(int32 location) {
|
||||
holomapFlags[location] = 0x81;
|
||||
}
|
||||
|
||||
/** Clear Holomap location position
|
||||
@location Scene where position must be cleared */
|
||||
void clearHolomapPosition(int32 location) {
|
||||
holomapFlags[location] &= 0x7E;
|
||||
holomapFlags[location] |= 0x40;
|
||||
}
|
40
engines/twine/holomap.h
Normal file
40
engines/twine/holomap.h
Normal file
@ -0,0 +1,40 @@
|
||||
/** @file holomap.h
|
||||
@brief
|
||||
This file contains holomap routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef HOLOMAP_H
|
||||
#define HOLOMAP_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/** Set Holomap location position
|
||||
@location Scene where position must be set */
|
||||
void setHolomapPosition(int32 location);
|
||||
|
||||
/** Clear Holomap location position
|
||||
@location Scene where position must be cleared */
|
||||
void clearHolomapPosition(int32 location);
|
||||
|
||||
|
||||
#endif
|
386
engines/twine/hqrdepack.cpp
Normal file
386
engines/twine/hqrdepack.cpp
Normal file
@ -0,0 +1,386 @@
|
||||
/** @file hqrdepack.cpp
|
||||
@brief
|
||||
This file contains High Quality Resource (HQR) decompress routines.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hqrdepack.h"
|
||||
#include "filereader.h"
|
||||
|
||||
FileReader fr;
|
||||
|
||||
/** Decompress entry based in Yaz0r and Zink decompression code
|
||||
@param dst destination pointer where will be the decompressed entry
|
||||
@param src compressed data pointer
|
||||
@decompsize real file size after decompression
|
||||
@mode compression mode used */
|
||||
void hqrDecompressEntry(uint8 * dst, uint8 * src, int32 decompsize, int32 mode) {
|
||||
uint8 b;
|
||||
int32 lenght, d, i;
|
||||
uint16 offset;
|
||||
uint8 *ptr;
|
||||
|
||||
do {
|
||||
b = *(src++);
|
||||
for (d = 0; d < 8; d++) {
|
||||
if (!(b & (1 << d))) {
|
||||
offset = *(uint16*)(src);
|
||||
src += 2;
|
||||
lenght = (offset & 0x0F) + (mode + 1);
|
||||
ptr = dst - (offset >> 4) - 1;
|
||||
for (i = 0; i < lenght; i++)
|
||||
*(dst++) = *(ptr++);
|
||||
} else {
|
||||
lenght = 1;
|
||||
*(dst++) = *(src++);
|
||||
}
|
||||
decompsize -= lenght;
|
||||
if (decompsize <= 0)
|
||||
return;
|
||||
}
|
||||
} while (decompsize);
|
||||
}
|
||||
|
||||
/** Decompress entry based in the original expand lzss lba code
|
||||
@param dst destination pointer where will be the decompressed entry
|
||||
@param src compressed data pointer
|
||||
@decompsize real file size after decompression
|
||||
@mode compression mode used */
|
||||
void hqrDecompressLZEntry(uint8 * dst, uint8 * src, int32 decompsize, int32 mode) {
|
||||
uint16 offset;
|
||||
int32 lenght;
|
||||
uint8 *ptr;
|
||||
|
||||
while (decompsize > 0) {
|
||||
uint8 bits;
|
||||
uint8 type = *(src++);
|
||||
for (bits = 1; bits != 0; bits <<= 1) {
|
||||
if (!(type&bits)) {
|
||||
offset = *(uint16*)(src);
|
||||
src += 2;
|
||||
lenght = (offset & 0x0F) + (mode + 1);
|
||||
ptr = dst - (offset >> 4) - 1;
|
||||
if (offset == 0) {
|
||||
memset(dst, *ptr, lenght);
|
||||
} else {
|
||||
if ((ptr + lenght) >= dst) {
|
||||
int32 n;
|
||||
uint8 *tmp = dst;
|
||||
for (n = 0; n < lenght; n++)
|
||||
*tmp++ = *ptr++;
|
||||
} else {
|
||||
memcpy(dst, ptr, lenght);
|
||||
}
|
||||
}
|
||||
dst += lenght;
|
||||
} else {
|
||||
lenght = 1;
|
||||
*(dst++) = *(src++);
|
||||
}
|
||||
decompsize -= lenght;
|
||||
if (decompsize <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get a HQR entry pointer
|
||||
@param ptr pointer to save the entry
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size*/
|
||||
int32 hqrGetEntry(uint8 * ptr, int8 *filename, int32 index) {
|
||||
uint32 headerSize;
|
||||
uint32 offsetToData;
|
||||
uint32 realSize;
|
||||
uint32 compSize;
|
||||
uint16 mode;
|
||||
|
||||
if (!filename)
|
||||
return 0;
|
||||
|
||||
if (!fropen2(&fr, (char*)filename, "rb"))
|
||||
printf("HQR: %s can't be found !\n", filename);
|
||||
|
||||
frread(&fr, &headerSize, 4);
|
||||
|
||||
if ((uint32)index >= headerSize / 4) {
|
||||
printf("\nHQR WARNING: Invalid entry index!!\n");
|
||||
frclose(&fr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
frseek(&fr, index*4);
|
||||
frread(&fr, &offsetToData, 4);
|
||||
|
||||
frseek(&fr, offsetToData);
|
||||
frread(&fr, &realSize, 4);
|
||||
frread(&fr, &compSize, 4);
|
||||
frread(&fr, &mode, 2);
|
||||
|
||||
if (!ptr)
|
||||
ptr = (uint8*)malloc(realSize);
|
||||
|
||||
if (!ptr) {
|
||||
printf("\nHQR WARNING: Unable to allocate memory!!\n");
|
||||
frclose(&fr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// uncompressed
|
||||
if (mode == 0) {
|
||||
frread(&fr, ptr, realSize);
|
||||
}
|
||||
// compressed: modes (1 & 2)
|
||||
else if (mode == 1 || mode == 2) {
|
||||
uint8* compDataPtr = 0;
|
||||
compDataPtr = (uint8*)malloc(compSize);
|
||||
frread(&fr, compDataPtr, compSize);
|
||||
hqrDecompressEntry(ptr, compDataPtr, realSize, mode);
|
||||
free(compDataPtr);
|
||||
}
|
||||
|
||||
frclose(&fr);
|
||||
|
||||
return realSize;
|
||||
}
|
||||
|
||||
/** Get a HQR entry pointer
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size */
|
||||
int hqrEntrySize(int8 *filename, int32 index) {
|
||||
uint32 headerSize;
|
||||
uint32 offsetToData;
|
||||
uint32 realSize;
|
||||
|
||||
if (!filename)
|
||||
return 0;
|
||||
|
||||
if (!fropen2(&fr, (char*)filename, "rb")) {
|
||||
printf("HQR: %s can't be found !\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frread(&fr, &headerSize, 4);
|
||||
|
||||
if ((uint32)index >= headerSize / 4) {
|
||||
printf("\nHQR WARNING: Invalid entry index!!\n");
|
||||
frclose(&fr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
frseek(&fr, index*4);
|
||||
frread(&fr, &offsetToData, 4);
|
||||
|
||||
frseek(&fr, offsetToData);
|
||||
frread(&fr, &realSize, 4);
|
||||
|
||||
frclose(&fr);
|
||||
|
||||
return realSize;
|
||||
}
|
||||
|
||||
/** Get a HQR total number of entries
|
||||
@param filename HQR file name
|
||||
@return total number of entries */
|
||||
int hqrNumEntries(int8 *filename) {
|
||||
uint32 headerSize;
|
||||
|
||||
if (!filename)
|
||||
return 0;
|
||||
|
||||
if (!fropen2(&fr, (char*)filename, "rb")) {
|
||||
printf("HQR: %s can't be found !\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frread(&fr, &headerSize, 4);
|
||||
|
||||
return headerSize / 4;
|
||||
}
|
||||
|
||||
/** Get a HQR entry pointer with memory allocation
|
||||
@param ptr pointer to save the entry
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size */
|
||||
int32 hqrGetallocEntry(uint8 ** ptr, int8 *filename, int32 index) {
|
||||
int32 size;
|
||||
size = hqrEntrySize(filename, index);
|
||||
|
||||
*ptr = (uint8*)malloc(size * sizeof(uint8));
|
||||
if (!*ptr) {
|
||||
printf("HQR WARNING: unable to allocate entry memory!!\n");
|
||||
return 0;
|
||||
}
|
||||
hqrGetEntry(*ptr, filename, index);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/** Get a HQR entry pointer
|
||||
@param ptr pointer to save the entry
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size*/
|
||||
int32 hqrGetVoxEntry(uint8 * ptr, int8 *filename, int32 index, int32 hiddenIndex) {
|
||||
uint32 headerSize;
|
||||
uint32 offsetToData;
|
||||
uint32 realSize;
|
||||
uint32 compSize;
|
||||
uint16 mode;
|
||||
|
||||
if (!filename)
|
||||
return 0;
|
||||
|
||||
if (!fropen2(&fr, (char*)filename, "rb"))
|
||||
printf("HQR: %s can't be found !\n", filename);
|
||||
|
||||
frread(&fr, &headerSize, 4);
|
||||
|
||||
if ((uint32)index >= headerSize / 4) {
|
||||
printf("\nHQR WARNING: Invalid entry index!!\n");
|
||||
frclose(&fr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
frseek(&fr, index*4);
|
||||
frread(&fr, &offsetToData, 4);
|
||||
|
||||
frseek(&fr, offsetToData);
|
||||
frread(&fr, &realSize, 4);
|
||||
frread(&fr, &compSize, 4);
|
||||
frread(&fr, &mode, 2);
|
||||
|
||||
// exist hidden entries
|
||||
if (hiddenIndex > 0) {
|
||||
int32 i = 0;
|
||||
for (i = 0; i < hiddenIndex; i++) {
|
||||
frseek(&fr, offsetToData + compSize + 10); // hidden entry
|
||||
offsetToData = offsetToData + compSize + 10; // current hidden offset
|
||||
|
||||
frread(&fr, &realSize, 4);
|
||||
frread(&fr, &compSize, 4);
|
||||
frread(&fr, &mode, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ptr)
|
||||
ptr = (uint8*)malloc(realSize);
|
||||
|
||||
if (!ptr) {
|
||||
printf("\nHQR WARNING: Unable to allocate memory!!\n");
|
||||
frclose(&fr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// uncompressed
|
||||
if (mode == 0) {
|
||||
frread(&fr, ptr, realSize);
|
||||
}
|
||||
// compressed: modes (1 & 2)
|
||||
else if (mode == 1 || mode == 2) {
|
||||
uint8* compDataPtr = 0;
|
||||
compDataPtr = (uint8*)malloc(compSize);
|
||||
frread(&fr, compDataPtr, compSize);
|
||||
hqrDecompressEntry(ptr, compDataPtr, realSize, mode);
|
||||
free(compDataPtr);
|
||||
}
|
||||
|
||||
frclose(&fr);
|
||||
|
||||
return realSize;
|
||||
}
|
||||
|
||||
/** Get a HQR entry pointer
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size */
|
||||
int hqrVoxEntrySize(int8 *filename, int32 index, int32 hiddenIndex) {
|
||||
uint32 headerSize;
|
||||
uint32 offsetToData;
|
||||
uint32 realSize;
|
||||
uint32 compSize;
|
||||
|
||||
if (!filename)
|
||||
return 0;
|
||||
|
||||
if (!fropen2(&fr, (char*)filename, "rb")) {
|
||||
printf("HQR: %s can't be found !\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frread(&fr, &headerSize, 4);
|
||||
|
||||
if ((uint32)index >= headerSize / 4) {
|
||||
printf("\nHQR WARNING: Invalid entry index!!\n");
|
||||
frclose(&fr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
frseek(&fr, index*4);
|
||||
frread(&fr, &offsetToData, 4);
|
||||
|
||||
frseek(&fr, offsetToData);
|
||||
frread(&fr, &realSize, 4);
|
||||
frread(&fr, &compSize, 4);
|
||||
|
||||
// exist hidden entries
|
||||
if (hiddenIndex > 0) {
|
||||
int32 i = 0;
|
||||
for (i = 0; i < hiddenIndex; i++) {
|
||||
frseek(&fr, offsetToData + compSize + 10); // hidden entry
|
||||
offsetToData = offsetToData + compSize + 10; // current hidden offset
|
||||
|
||||
frread(&fr, &realSize, 4);
|
||||
frread(&fr, &compSize, 4);
|
||||
}
|
||||
}
|
||||
|
||||
frclose(&fr);
|
||||
|
||||
return realSize;
|
||||
}
|
||||
|
||||
/** Get a HQR entry pointer with memory allocation
|
||||
@param ptr pointer to save the entry
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size */
|
||||
int32 hqrGetallocVoxEntry(uint8 ** ptr, int8 *filename, int32 index, int32 hiddenIndex) {
|
||||
int32 size;
|
||||
size = hqrVoxEntrySize(filename, index, hiddenIndex);
|
||||
|
||||
*ptr = (uint8*)malloc(size * sizeof(uint8));
|
||||
if (!*ptr) {
|
||||
printf("HQR WARNING: unable to allocate entry memory!!\n");
|
||||
return 0;
|
||||
}
|
||||
hqrGetVoxEntry(*ptr, filename, index, hiddenIndex);
|
||||
|
||||
return size;
|
||||
}
|
59
engines/twine/hqrdepack.h
Normal file
59
engines/twine/hqrdepack.h
Normal file
@ -0,0 +1,59 @@
|
||||
/** @file hqrdepack.h
|
||||
@brief
|
||||
This file contains High Quality Resource (HQR) decompress routines.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef HQRDEPACK_H
|
||||
#define HQRDEPACK_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/** Get a HQR entry pointer
|
||||
@param ptr pointer to save the entry
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size */
|
||||
int32 hqrGetEntry(uint8 * ptr, int8 *filename, int32 index);
|
||||
|
||||
/** Get a HQR entry pointer
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size */
|
||||
int32 hqrEntrySize(int8 *filename, int32 index);
|
||||
|
||||
/** Get a HQR total number of entries
|
||||
@param filename HQR file name
|
||||
@return total number of entries */
|
||||
int32 hqrNumEntries(int8 *filename);
|
||||
|
||||
/** Get a HQR entry pointer with memory allocation
|
||||
@param ptr pointer to save the entry
|
||||
@param filename HQR file name
|
||||
@param index entry index to extract
|
||||
@return entry real size */
|
||||
int32 hqrGetallocEntry(uint8 ** ptr, int8 *filename, int32 index);
|
||||
|
||||
int32 hqrGetVoxEntry(uint8 * ptr, int8 *filename, int32 index, int32 hiddenIndex);
|
||||
int32 hqrGetallocVoxEntry(uint8 ** ptr, int8 *filename, int32 index, int32 hiddenIndex);
|
||||
|
||||
#endif
|
328
engines/twine/interface.cpp
Normal file
328
engines/twine/interface.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
/** @file interface.cpp
|
||||
@brief
|
||||
This file contains in-game interface routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "interface.h"
|
||||
#include "sdlengine.h"
|
||||
#include "main.h"
|
||||
#include "lbaengine.h"
|
||||
const int32 INSIDE = 0; // 0000
|
||||
const int32 LEFT = 1; // 0001
|
||||
const int32 RIGHT = 2; // 0010
|
||||
const int32 TOP = 4; // 0100
|
||||
const int32 BOTTOM = 8; // 1000
|
||||
|
||||
int32 checkClipping(int32 x, int32 y)
|
||||
{
|
||||
int32 code = INSIDE;
|
||||
if (x < textWindowLeft) code |= LEFT;
|
||||
else if (x > textWindowRight) code |= RIGHT;
|
||||
if (y < textWindowTop) code |= TOP;
|
||||
else if (y > textWindowBottom) code |= BOTTOM;
|
||||
return code;
|
||||
}
|
||||
|
||||
/** Draw button line
|
||||
@param startWidth width value where the line starts
|
||||
@param startHeight height value where the line starts
|
||||
@param endWidth width value where the line ends
|
||||
@param endHeight height value where the line ends
|
||||
@param lineColor line color in the current palette */
|
||||
void drawLine(int32 startWidth, int32 startHeight, int32 endWidth, int32 endHeight, int32 lineColor) {
|
||||
int32 temp;
|
||||
int32 flag2;
|
||||
uint8 *out;
|
||||
int16 color;
|
||||
int16 var2;
|
||||
int16 xchg;
|
||||
int32 outcode0, outcode1;
|
||||
int32 x, y, outcodeOut;
|
||||
int32 currentLineColor = lineColor;
|
||||
|
||||
// draw line from left to right
|
||||
if (startWidth > endWidth) {
|
||||
temp = endWidth;
|
||||
endWidth = startWidth;
|
||||
startWidth = temp;
|
||||
|
||||
temp = endHeight;
|
||||
endHeight = startHeight;
|
||||
startHeight = temp;
|
||||
}
|
||||
|
||||
// Perform proper clipping (Cohen–Sutherland algorithm)
|
||||
outcode0 = checkClipping(startWidth, startHeight);
|
||||
outcode1 = checkClipping(endWidth, endHeight);
|
||||
|
||||
while ((outcode0 | outcode1) != 0) {
|
||||
if (((outcode0 & outcode1) != 0) && (outcode0 != INSIDE)) return; // Reject lines which are behind one clipping plane
|
||||
|
||||
// At least one endpoint is outside the clip rectangle; pick it.
|
||||
outcodeOut = outcode0 ? outcode0 : outcode1;
|
||||
|
||||
if (outcodeOut & TOP) { // point is above the clip rectangle
|
||||
x = startWidth + (int)((endWidth - startWidth) * (float)(textWindowTop - startHeight) / (float)(endHeight - startHeight));
|
||||
y = textWindowTop;
|
||||
} else if (outcodeOut & BOTTOM) { // point is below the clip rectangle
|
||||
x = startWidth + (int)((endWidth - startWidth) * (float)(textWindowBottom - startHeight) / (float)(endHeight - startHeight));
|
||||
y = textWindowBottom;
|
||||
} else if (outcodeOut & RIGHT) { // point is to the right of clip rectangle
|
||||
y = startHeight + (int)((endHeight - startHeight) * (float)(textWindowRight - startWidth) / (float)(endWidth - startWidth));
|
||||
x = textWindowRight;
|
||||
} else if (outcodeOut & LEFT) { // point is to the left of clip rectangle
|
||||
y = startHeight + (int)((endHeight - startHeight) * (float)(textWindowLeft - startWidth) / (float)(endWidth - startWidth));
|
||||
x = textWindowLeft;
|
||||
}
|
||||
|
||||
// Clip the point
|
||||
if (outcodeOut == outcode0) {
|
||||
startWidth = x;
|
||||
startHeight = y;
|
||||
outcode0 = checkClipping(startWidth, startHeight);
|
||||
} else {
|
||||
endWidth = x;
|
||||
endHeight = y;
|
||||
outcode1 = checkClipping(endWidth, endHeight);
|
||||
}
|
||||
}
|
||||
|
||||
flag2 = 640;//SCREEN_WIDTH;
|
||||
endWidth -= startWidth;
|
||||
endHeight -= startHeight;
|
||||
if (endHeight < 0) {
|
||||
flag2 = -flag2;
|
||||
endHeight = -endHeight;
|
||||
}
|
||||
|
||||
out = frontVideoBuffer + screenLookupTable[startHeight] + startWidth;
|
||||
|
||||
color = currentLineColor;
|
||||
if (endWidth < endHeight) { // significant slope
|
||||
xchg = endWidth;
|
||||
endWidth = endHeight;
|
||||
endHeight = xchg;
|
||||
var2 = endWidth;
|
||||
var2 <<= 1;
|
||||
startHeight = endWidth;
|
||||
endHeight <<= 1;
|
||||
endWidth++;
|
||||
do {
|
||||
*out = (uint8) color;
|
||||
startHeight -= endHeight;
|
||||
if (startHeight > 0) {
|
||||
out += flag2;
|
||||
} else {
|
||||
startHeight += var2;
|
||||
out += flag2 + 1;
|
||||
}
|
||||
} while (--endWidth);
|
||||
} else { // reduced slope
|
||||
var2 = endWidth;
|
||||
var2 <<= 1;
|
||||
startHeight = endWidth;
|
||||
endHeight <<= 1;
|
||||
endWidth++;
|
||||
do {
|
||||
*out = (uint8) color;
|
||||
out++;
|
||||
startHeight -= endHeight;
|
||||
if (startHeight < 0) {
|
||||
startHeight += var2;
|
||||
out += flag2;
|
||||
}
|
||||
} while (--endWidth);
|
||||
}
|
||||
}
|
||||
|
||||
/** Blit button box from working buffer to front buffer
|
||||
@param left start width to draw the button
|
||||
@param top start height to draw the button
|
||||
@param right end width to draw the button
|
||||
@param bottom end height to draw the button
|
||||
@source source screen buffer, in this case working buffer
|
||||
@param leftDest start width to draw the button in destination buffer
|
||||
@param topDest start height to draw the button in destination buffer
|
||||
@dest destination screen buffer, in this case front buffer */
|
||||
void blitBox(int32 left, int32 top, int32 right, int32 bottom, int8 *source, int32 leftDest, int32 topDest, int8 *dest) {
|
||||
int32 width;
|
||||
int32 height;
|
||||
int8 *s;
|
||||
int8 *d;
|
||||
int32 insideLine;
|
||||
int32 temp3;
|
||||
int32 i;
|
||||
int32 j;
|
||||
|
||||
s = screenLookupTable[top] + source + left;
|
||||
d = screenLookupTable[topDest] + dest + leftDest;
|
||||
|
||||
width = right - left + 1;
|
||||
height = bottom - top + 1;
|
||||
|
||||
insideLine = SCREEN_WIDTH - width;
|
||||
temp3 = left;
|
||||
|
||||
left >>= 2;
|
||||
temp3 &= 3;
|
||||
|
||||
for (j = 0; j < height; j++) {
|
||||
for (i = 0; i < width; i++) {
|
||||
*(d++) = *(s++);
|
||||
}
|
||||
|
||||
d += insideLine;
|
||||
s += insideLine;
|
||||
}
|
||||
}
|
||||
|
||||
/** Draws inside buttons transparent area
|
||||
@param left start width to draw the button
|
||||
@param top start height to draw the button
|
||||
@param right end width to draw the button
|
||||
@param bottom end height to draw the button
|
||||
@param colorAdj index to adjust the transparent box color */
|
||||
void drawTransparentBox(int32 left, int32 top, int32 right, int32 bottom, int32 colorAdj) {
|
||||
uint8 *pos;
|
||||
int32 width;
|
||||
int32 height;
|
||||
int32 height2;
|
||||
int32 temp;
|
||||
int32 localMode;
|
||||
int32 var1;
|
||||
int8 color;
|
||||
int8 color2;
|
||||
|
||||
if (left > SCREEN_TEXTLIMIT_RIGHT)
|
||||
return;
|
||||
if (right < SCREEN_TEXTLIMIT_LEFT)
|
||||
return;
|
||||
if (top > SCREEN_TEXTLIMIT_BOTTOM)
|
||||
return;
|
||||
if (bottom < SCREEN_TEXTLIMIT_TOP)
|
||||
return;
|
||||
|
||||
if (left < SCREEN_TEXTLIMIT_LEFT)
|
||||
left = SCREEN_TEXTLIMIT_LEFT;
|
||||
if (right > SCREEN_TEXTLIMIT_RIGHT)
|
||||
right = SCREEN_TEXTLIMIT_RIGHT;
|
||||
if (top < SCREEN_TEXTLIMIT_TOP)
|
||||
top = SCREEN_TEXTLIMIT_TOP;
|
||||
if (bottom > SCREEN_TEXTLIMIT_BOTTOM)
|
||||
bottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
|
||||
pos = screenLookupTable[top] + frontVideoBuffer + left;
|
||||
height2 = height = bottom - top;
|
||||
height2++;
|
||||
|
||||
width = right - left + 1;
|
||||
|
||||
temp = 640 - width; // SCREEN_WIDTH
|
||||
localMode = colorAdj;
|
||||
|
||||
do {
|
||||
var1 = width;
|
||||
do {
|
||||
color2 = color = *pos;
|
||||
color2 &= 0xF0;
|
||||
color &= 0x0F;
|
||||
color -= localMode;
|
||||
if (color < 0)
|
||||
color = color2;
|
||||
else
|
||||
color += color2;
|
||||
*pos++ = color;
|
||||
var1--;
|
||||
} while (var1 > 0);
|
||||
pos += temp;
|
||||
height2--;
|
||||
} while (height2 > 0);
|
||||
}
|
||||
|
||||
void drawSplittedBox(int32 left, int32 top, int32 right, int32 bottom, uint8 e) { // Box
|
||||
uint8 *ptr;
|
||||
|
||||
int32 offset;
|
||||
|
||||
int32 x;
|
||||
int32 y;
|
||||
|
||||
if (left > SCREEN_TEXTLIMIT_RIGHT)
|
||||
return;
|
||||
if (right < SCREEN_TEXTLIMIT_LEFT)
|
||||
return;
|
||||
if (top > SCREEN_TEXTLIMIT_BOTTOM)
|
||||
return;
|
||||
if (bottom < SCREEN_TEXTLIMIT_TOP)
|
||||
return;
|
||||
|
||||
// cropping
|
||||
offset = -((right - left) - SCREEN_WIDTH);
|
||||
|
||||
ptr = frontVideoBuffer + screenLookupTable[top] + left;
|
||||
|
||||
for (x = top; x < bottom; x++) {
|
||||
for (y = left; y < right; y++) {
|
||||
*(ptr++) = e;
|
||||
}
|
||||
ptr += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void setClip(int32 left, int32 top, int32 right, int32 bottom) {
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
textWindowLeft = left;
|
||||
|
||||
if (top < 0)
|
||||
top = 0;
|
||||
textWindowTop = top;
|
||||
|
||||
if (right >= SCREEN_WIDTH)
|
||||
right = SCREEN_TEXTLIMIT_RIGHT;
|
||||
textWindowRight = right;
|
||||
|
||||
if (bottom >= SCREEN_HEIGHT)
|
||||
bottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
textWindowBottom = bottom;
|
||||
}
|
||||
|
||||
void saveClip() { // saveTextWindow
|
||||
textWindowLeftSave = textWindowLeft;
|
||||
textWindowTopSave = textWindowTop;
|
||||
textWindowRightSave = textWindowRight;
|
||||
textWindowBottomSave = textWindowBottom;
|
||||
}
|
||||
|
||||
void loadClip() { // loadSavedTextWindow
|
||||
textWindowLeft = textWindowLeftSave;
|
||||
textWindowTop = textWindowTopSave;
|
||||
textWindowRight = textWindowRightSave;
|
||||
textWindowBottom = textWindowBottomSave;
|
||||
}
|
||||
|
||||
void resetClip() {
|
||||
textWindowTop = textWindowLeft = SCREEN_TEXTLIMIT_TOP;
|
||||
textWindowRight = SCREEN_TEXTLIMIT_RIGHT;
|
||||
textWindowBottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
}
|
84
engines/twine/interface.h
Normal file
84
engines/twine/interface.h
Normal file
@ -0,0 +1,84 @@
|
||||
/** @file interface.h
|
||||
@brief
|
||||
This file contains in-game interface routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef INTERFACE_H
|
||||
#define INTERFACE_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "main.h"
|
||||
|
||||
/** Screen top limit to display the texts */
|
||||
#define SCREEN_TEXTLIMIT_TOP 0
|
||||
/** Screen left limit to display the texts */
|
||||
#define SCREEN_TEXTLIMIT_LEFT 0
|
||||
/** Screen right limit to display the texts */
|
||||
#define SCREEN_TEXTLIMIT_RIGHT SCREEN_WIDTH-1
|
||||
/** Screen bottom limit to display the texts */
|
||||
#define SCREEN_TEXTLIMIT_BOTTOM SCREEN_HEIGHT-1
|
||||
|
||||
int32 textWindowTop;
|
||||
int32 textWindowTopSave;
|
||||
int32 textWindowLeft;
|
||||
int32 textWindowLeftSave;
|
||||
int32 textWindowRight;
|
||||
int32 textWindowRightSave;
|
||||
int32 textWindowBottom;
|
||||
int32 textWindowBottomSave;
|
||||
|
||||
/** Draw button line
|
||||
@param startWidth width value where the line starts
|
||||
@param startHeight height value where the line starts
|
||||
@param endWidth width value where the line ends
|
||||
@param endHeight height value where the line ends
|
||||
@param lineColor line color in the current palette */
|
||||
void drawLine(int32 startWidth, int32 startHeight, int32 endWidth, int32 endHeight, int32 lineColor);
|
||||
|
||||
/** Blit button box from working buffer to front buffer
|
||||
@param left start width to draw the button
|
||||
@param top start height to draw the button
|
||||
@param right end width to draw the button
|
||||
@param bottom end height to draw the button
|
||||
@source source screen buffer, in this case working buffer
|
||||
@param leftDest start width to draw the button in destination buffer
|
||||
@param topDest start height to draw the button in destination buffer
|
||||
@dest destination screen buffer, in this case front buffer */
|
||||
void blitBox(int32 left, int32 top, int32 right, int32 bottom, int8 *source, int32 leftDest, int32 topDest, int8 *dest);
|
||||
|
||||
/** Draws inside buttons transparent area
|
||||
@param left start width to draw the button
|
||||
@param top start height to draw the button
|
||||
@param right end width to draw the button
|
||||
@param bottom end height to draw the button
|
||||
@param colorAdj index to adjust the transparent box color */
|
||||
void drawTransparentBox(int32 left, int32 top, int32 right, int32 bottom, int32 colorAdj);
|
||||
|
||||
void drawSplittedBox(int32 left, int32 top, int32 right, int32 bottom, uint8 e);
|
||||
|
||||
void setClip(int32 left, int32 top, int32 right, int32 bottom);
|
||||
void saveClip(); // saveTextWindow
|
||||
void loadClip(); // loadSavedTextWindow
|
||||
void resetClip();
|
||||
|
||||
#endif
|
98
engines/twine/keyboard.cpp
Normal file
98
engines/twine/keyboard.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/** @file keyboard.cpp
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "keyboard.h"
|
||||
|
||||
/** Initialize engine auxiliar keymap */
|
||||
uint8 pressedKeyMap[29] = {
|
||||
0x48, // 0
|
||||
0x50,
|
||||
0x4B,
|
||||
0x4D,
|
||||
0x47,
|
||||
0x49,
|
||||
0x51,
|
||||
0x4F, // 7
|
||||
|
||||
0x39, // 8
|
||||
0x1C,
|
||||
0x1D,
|
||||
0x38,
|
||||
0x53,
|
||||
0x2A,
|
||||
0x36, // 14
|
||||
|
||||
0x3B, // 15
|
||||
0x3C,
|
||||
0x3D,
|
||||
0x3E,
|
||||
0x3F,
|
||||
0x40, // LBAKEY_F6
|
||||
0x41,
|
||||
0x42,
|
||||
0x43,
|
||||
0x44,
|
||||
0x57,
|
||||
0x58,
|
||||
0x2A,
|
||||
0x0, // 28
|
||||
};
|
||||
|
||||
uint16 pressedKeyCharMap[31] = {
|
||||
0x0100, // up
|
||||
0x0200, // down
|
||||
0x0400, // left
|
||||
0x0800, // right
|
||||
0x0500, // home
|
||||
0x0900, // pageup
|
||||
0x0A00, // pagedown
|
||||
0x0600, // end
|
||||
|
||||
0x0101, // space bar
|
||||
0x0201, // enter
|
||||
0x0401, // ctrl
|
||||
0x0801, // alt
|
||||
0x1001, // del
|
||||
0x2001, // left shift
|
||||
0x2001, // right shift
|
||||
|
||||
0x0102, // F1
|
||||
0x0202, // F2
|
||||
0x0402, // F3
|
||||
0x0802, // F4
|
||||
0x1002, // F5
|
||||
0x2002, // F6
|
||||
0x4002, // F7
|
||||
0x8002, // F8
|
||||
|
||||
0x0103, // F9
|
||||
0x0203, // F10
|
||||
0x0403, // ?
|
||||
0x0803, // ?
|
||||
0x00FF, // left shift
|
||||
0x00FF,
|
||||
0x0,
|
||||
0x0,
|
||||
};
|
51
engines/twine/keyboard.h
Normal file
51
engines/twine/keyboard.h
Normal file
@ -0,0 +1,51 @@
|
||||
/** @file keyboard.h
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef KEYBOARD_H
|
||||
#define KEYBOARD_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/** Pressed key map - scanCodeTab1 */
|
||||
extern uint8 pressedKeyMap[29];
|
||||
/** Pressed key char map - scanCodeTab2 */
|
||||
extern uint16 pressedKeyCharMap[31];
|
||||
|
||||
/** Skipped key - key1 */
|
||||
int16 skippedKey;
|
||||
/** Pressed key - printTextVar12 */
|
||||
int16 pressedKey;
|
||||
//int printTextVar13;
|
||||
/** Skip intro variable */
|
||||
int16 skipIntro;
|
||||
/** Current key value */
|
||||
int16 currentKey;
|
||||
/** Auxiliar key value */
|
||||
int16 key;
|
||||
|
||||
int32 heroPressedKey;
|
||||
int32 heroPressedKey2;
|
||||
|
||||
#endif
|
538
engines/twine/lbaengine.cpp
Normal file
538
engines/twine/lbaengine.cpp
Normal file
@ -0,0 +1,538 @@
|
||||
/** @file lbaengine.cpp
|
||||
@brief
|
||||
This file contains the main game engine routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "lbaengine.h"
|
||||
#include "main.h"
|
||||
#include "sdlengine.h"
|
||||
#include "screens.h"
|
||||
#include "grid.h"
|
||||
#include "debug.grid.h"
|
||||
#include "scene.h"
|
||||
#include "menu.h"
|
||||
#include "interface.h"
|
||||
#include "text.h"
|
||||
#include "redraw.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "resources.h"
|
||||
#include "renderer.h"
|
||||
#include "animations.h"
|
||||
#include "movements.h"
|
||||
#include "keyboard.h"
|
||||
#include "gamestate.h"
|
||||
#include "sound.h"
|
||||
#include "script.life.h"
|
||||
#include "script.move.h"
|
||||
#include "extra.h"
|
||||
#include "menuoptions.h"
|
||||
#include "collision.h"
|
||||
|
||||
#ifdef GAMEMOD
|
||||
#include "debug.h"
|
||||
#endif
|
||||
|
||||
int32 isTimeFreezed = 0;
|
||||
int32 saveFreezedTime = 0;
|
||||
|
||||
enum InventoryItems {
|
||||
kiHolomap = 0,
|
||||
kiMagicBall = 1,
|
||||
kiUseSabre = 2,
|
||||
kiBookOfBu = 5,
|
||||
kiProtoPack = 12,
|
||||
kiPinguin = 14,
|
||||
kiBonusList = 26,
|
||||
kiCloverLeaf = 27
|
||||
};
|
||||
|
||||
void freezeTime() {
|
||||
if (!isTimeFreezed)
|
||||
saveFreezedTime = lbaTime;
|
||||
isTimeFreezed++;
|
||||
}
|
||||
|
||||
void unfreezeTime() {
|
||||
--isTimeFreezed;
|
||||
if (isTimeFreezed == 0)
|
||||
lbaTime = saveFreezedTime;
|
||||
}
|
||||
|
||||
void processActorSamplePosition(int32 actorIdx) {
|
||||
int32 channelIdx;
|
||||
ActorStruct *actor = &sceneActors[actorIdx];
|
||||
channelIdx = getActorChannel(actorIdx);
|
||||
setSamplePosition(channelIdx, actor->X, actor->Y, actor->Z);
|
||||
}
|
||||
|
||||
/** Game engine main loop
|
||||
@return true if we want to show credit sequence */
|
||||
int32 runGameEngine() { // mainLoopInteration
|
||||
int32 a;
|
||||
readKeys();
|
||||
|
||||
if (needChangeScene > -1) {
|
||||
changeScene();
|
||||
}
|
||||
|
||||
previousLoopPressedKey = loopPressedKey;
|
||||
key = pressedKey;
|
||||
loopPressedKey = skippedKey;
|
||||
loopCurrentKey = skipIntro;
|
||||
|
||||
#ifdef GAMEMOD
|
||||
processDebug(loopCurrentKey);
|
||||
#endif
|
||||
|
||||
if(canShowCredits != 0) {
|
||||
// TODO: if current music playing != 8, than play_track(8);
|
||||
if (skipIntro != 0) {
|
||||
return 0;
|
||||
}
|
||||
if (pressedKey != 0) {
|
||||
return 0;
|
||||
}
|
||||
if (skippedKey != 0) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Process give up menu - Press ESC
|
||||
if (skipIntro == 1 && sceneHero->life > 0 && sceneHero->entity != -1 && !sceneHero->staticFlags.bIsHidden) {
|
||||
freezeTime();
|
||||
if (giveupMenu()) {
|
||||
unfreezeTime();
|
||||
redrawEngineActions(1);
|
||||
freezeTime();
|
||||
saveGame(); // auto save game
|
||||
quitGame = 0;
|
||||
cfgfile.Quit = 0;
|
||||
unfreezeTime();
|
||||
return 0;
|
||||
} else {
|
||||
unfreezeTime();
|
||||
redrawEngineActions(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Process options menu - Press F6
|
||||
if (loopCurrentKey == 0x40) {
|
||||
int tmpLangCD = cfgfile.LanguageCDId;
|
||||
freezeTime();
|
||||
pauseSamples();
|
||||
OptionsMenuSettings[5] = 15;
|
||||
cfgfile.LanguageCDId = 0;
|
||||
initTextBank(0);
|
||||
optionsMenu();
|
||||
cfgfile.LanguageCDId = tmpLangCD;
|
||||
initTextBank(currentTextBank + 3);
|
||||
//TODO: play music
|
||||
resumeSamples();
|
||||
unfreezeTime();
|
||||
redrawEngineActions(1);
|
||||
}
|
||||
|
||||
// inventory menu
|
||||
loopInventoryItem = -1;
|
||||
if (loopCurrentKey == 0x36 && sceneHero->entity != -1 && sceneHero->controlMode == kManual) {
|
||||
freezeTime();
|
||||
processInventoryMenu();
|
||||
|
||||
switch (loopInventoryItem) {
|
||||
case kiHolomap:
|
||||
printf("Use Inventory [kiHolomap] not implemented!\n");
|
||||
break;
|
||||
case kiMagicBall:
|
||||
if (usingSabre == 1) {
|
||||
initModelActor(0, 0);
|
||||
}
|
||||
usingSabre = 0;
|
||||
break;
|
||||
case kiUseSabre:
|
||||
if (sceneHero->body != GAMEFLAG_HAS_SABRE) {
|
||||
if (heroBehaviour == kProtoPack) {
|
||||
setBehaviour(kNormal);
|
||||
}
|
||||
initModelActor(GAMEFLAG_HAS_SABRE, 0);
|
||||
initAnim(24, 1, 0, 0);
|
||||
|
||||
usingSabre = 1;
|
||||
}
|
||||
break;
|
||||
case kiBookOfBu: {
|
||||
int32 tmpFlagDisplayText;
|
||||
|
||||
fadeToBlack(paletteRGBA);
|
||||
loadImage(RESSHQR_INTROSCREEN1IMG, 1);
|
||||
initTextBank(2);
|
||||
newGameVar4 = 0;
|
||||
textClipFull();
|
||||
setFontCrossColor(15);
|
||||
tmpFlagDisplayText = cfgfile.FlagDisplayText;
|
||||
cfgfile.FlagDisplayText = 1;
|
||||
drawTextFullscreen(161);
|
||||
cfgfile.FlagDisplayText = tmpFlagDisplayText;
|
||||
textClipSmall();
|
||||
newGameVar4 = 1;
|
||||
initTextBank(currentTextBank + 3);
|
||||
fadeToBlack(paletteRGBACustom);
|
||||
clearScreen();
|
||||
flip();
|
||||
setPalette(paletteRGBA);
|
||||
lockPalette = 1;
|
||||
}
|
||||
break;
|
||||
case kiProtoPack:
|
||||
if (gameFlags[GAMEFLAG_BOOKOFBU]) {
|
||||
sceneHero->body = 0;
|
||||
} else {
|
||||
sceneHero->body = 1;
|
||||
}
|
||||
|
||||
if (heroBehaviour == kProtoPack) {
|
||||
setBehaviour(kNormal);
|
||||
} else {
|
||||
setBehaviour(kProtoPack);
|
||||
}
|
||||
break;
|
||||
case kiPinguin: {
|
||||
ActorStruct *pinguin = &sceneActors[mecaPinguinIdx];
|
||||
|
||||
pinguin->X = destX + sceneHero->X;
|
||||
pinguin->Y = sceneHero->Y;
|
||||
pinguin->Z = destZ + sceneHero->Z;
|
||||
pinguin->angle = sceneHero->angle;
|
||||
|
||||
rotateActor(0, 800, pinguin->angle);
|
||||
|
||||
if (!checkCollisionWithActors(mecaPinguinIdx)) {
|
||||
pinguin->life = 50;
|
||||
pinguin->body = -1;
|
||||
initModelActor(0, mecaPinguinIdx);
|
||||
pinguin->dynamicFlags.bIsDead = 0; // &= 0xDF
|
||||
pinguin->brickShape = 0;
|
||||
moveActor(pinguin->angle, pinguin->angle, pinguin->speed, &pinguin->move);
|
||||
gameFlags[GAMEFLAG_MECA_PINGUIN] = 0; // byte_50D89 = 0;
|
||||
pinguin->info0 = lbaTime + 1500;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kiBonusList: {
|
||||
int32 tmpLanguageCDIdx;
|
||||
tmpLanguageCDIdx = cfgfile.LanguageCDId;
|
||||
unfreezeTime();
|
||||
redrawEngineActions(1);
|
||||
freezeTime();
|
||||
cfgfile.LanguageCDId = 0;
|
||||
initTextBank(2);
|
||||
textClipFull();
|
||||
setFontCrossColor(15);
|
||||
drawTextFullscreen(162);
|
||||
textClipSmall();
|
||||
cfgfile.LanguageCDId = tmpLanguageCDIdx;
|
||||
initTextBank(currentTextBank + 3);
|
||||
}
|
||||
break;
|
||||
case kiCloverLeaf:
|
||||
if (sceneHero->life < 50) {
|
||||
if (inventoryNumLeafs > 0) {
|
||||
sceneHero->life = 50;
|
||||
inventoryMagicPoints = magicLevelIdx * 20;
|
||||
inventoryNumLeafs--;
|
||||
addOverlay(koInventoryItem, 27, 0, 0, 0, koNormal, 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
unfreezeTime();
|
||||
redrawEngineActions(1);
|
||||
}
|
||||
|
||||
// Process behaviour menu - Press CTRL and F1..F4 Keys
|
||||
if ((loopCurrentKey == 0x1D || loopCurrentKey == 0x3B || loopCurrentKey == 0x3C || loopCurrentKey == 0x3D || loopCurrentKey == 0x3E) && sceneHero->entity != -1 && sceneHero->controlMode == kManual) {
|
||||
if (loopCurrentKey != 0x1D) {
|
||||
heroBehaviour = loopCurrentKey - 0x3B;
|
||||
}
|
||||
freezeTime();
|
||||
processBehaviourMenu();
|
||||
unfreezeTime();
|
||||
redrawEngineActions(1);
|
||||
}
|
||||
|
||||
// use Proto-Pack
|
||||
if (loopCurrentKey == 0x24 && gameFlags[GAMEFLAG_PROTOPACK] == 1) {
|
||||
if (gameFlags[GAMEFLAG_BOOKOFBU]) {
|
||||
sceneHero->body = 0;
|
||||
} else {
|
||||
sceneHero->body = 1;
|
||||
}
|
||||
|
||||
if (heroBehaviour == kProtoPack) {
|
||||
setBehaviour(kNormal);
|
||||
} else {
|
||||
setBehaviour(kProtoPack);
|
||||
}
|
||||
}
|
||||
|
||||
// Press Enter to Recenter Screen
|
||||
if ((loopPressedKey & 2) && !disableScreenRecenter) {
|
||||
newCameraX = sceneActors[currentlyFollowedActor].X >> 9;
|
||||
newCameraY = sceneActors[currentlyFollowedActor].Y >> 8;
|
||||
newCameraZ = sceneActors[currentlyFollowedActor].Z >> 9;
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
|
||||
// TODO: draw holomap
|
||||
|
||||
// Process Pause - Press P
|
||||
if (loopCurrentKey == 0x19) {
|
||||
freezeTime();
|
||||
setFontColor(15);
|
||||
drawText(5, 446, (int8*)"Pause"); // no key for pause in Text Bank
|
||||
copyBlockPhys(5, 446, 100, 479);
|
||||
do {
|
||||
readKeys();
|
||||
SDL_Delay(10);
|
||||
} while (skipIntro != 0x19 && !pressedKey);
|
||||
unfreezeTime();
|
||||
redrawEngineActions(1);
|
||||
}
|
||||
}
|
||||
|
||||
loopActorStep = getRealValue(&loopMovePtr);
|
||||
if (!loopActorStep) {
|
||||
loopActorStep = 1;
|
||||
}
|
||||
|
||||
setActorAngle(0, -256, 5, &loopMovePtr);
|
||||
disableScreenRecenter = 0;
|
||||
|
||||
processEnvironmentSound();
|
||||
|
||||
// Reset HitBy state
|
||||
for (a = 0; a < sceneNumActors; a++)
|
||||
{
|
||||
sceneActors[a].hitBy = -1;
|
||||
}
|
||||
|
||||
processExtras();
|
||||
|
||||
for (a = 0; a < sceneNumActors; a++) {
|
||||
ActorStruct *actor = &sceneActors[a];
|
||||
|
||||
if (!actor->dynamicFlags.bIsDead) {
|
||||
if (actor->life == 0) {
|
||||
if (a == 0) { // if its hero who died
|
||||
initAnim(kLandDeath, 4, 0, 0);
|
||||
actor->controlMode = 0;
|
||||
} else {
|
||||
playSample(37, Rnd(2000) + 3096, 1, actor->X, actor->Y, actor->Z, a);
|
||||
|
||||
if (a == mecaPinguinIdx) {
|
||||
addExtraExplode(actor->X, actor->Y, actor->Z);
|
||||
}
|
||||
}
|
||||
|
||||
if (actor->bonusParameter & 0x1F0 && !(actor->bonusParameter & 1)) {
|
||||
processActorExtraBonus(a);
|
||||
}
|
||||
}
|
||||
|
||||
processActorMovements(a);
|
||||
|
||||
actor->collisionX = actor->X;
|
||||
actor->collisionY = actor->Y;
|
||||
actor->collisionZ = actor->Z;
|
||||
|
||||
if (actor->positionInMoveScript != -1) {
|
||||
processMoveScript(a);
|
||||
}
|
||||
|
||||
processActorAnimations(a);
|
||||
|
||||
if (actor->staticFlags.bIsZonable) {
|
||||
processActorZones(a);
|
||||
}
|
||||
|
||||
if (actor->positionInLifeScript != -1) {
|
||||
processLifeScript(a);
|
||||
}
|
||||
|
||||
processActorSamplePosition(a);
|
||||
|
||||
if (quitGame != -1) {
|
||||
return quitGame;
|
||||
}
|
||||
|
||||
if (actor->staticFlags.bCanDrown) {
|
||||
int32 brickSound;
|
||||
brickSound = getBrickSoundType(actor->X, actor->Y - 1, actor->Z);
|
||||
actor->brickSound = brickSound;
|
||||
|
||||
if ((brickSound & 0xF0) == 0xF0) {
|
||||
if ((brickSound & 0xF) == 1) {
|
||||
if (a) { // all other actors
|
||||
int32 rnd = Rnd(2000) + 3096;
|
||||
playSample(0x25, rnd, 1, actor->X, actor->Y, actor->Z, a);
|
||||
if (actor->bonusParameter & 0x1F0) {
|
||||
if (!(actor->bonusParameter & 1)) {
|
||||
processActorExtraBonus(a);
|
||||
}
|
||||
actor->life = 0;
|
||||
}
|
||||
} else { // if Hero
|
||||
if (heroBehaviour != 4 || (brickSound & 0x0F) != actor->anim) {
|
||||
if (!cropBottomScreen)
|
||||
{
|
||||
initAnim(kDrawn, 4, 0, 0);
|
||||
projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
|
||||
cropBottomScreen = projPosY;
|
||||
}
|
||||
projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
|
||||
actor->controlMode = 0;
|
||||
actor->life = -1;
|
||||
cropBottomScreen = projPosY;
|
||||
actor->staticFlags.bCanDrown |= 0x10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (actor->life <= 0) {
|
||||
if (!a) { // if its Hero
|
||||
if (actor->dynamicFlags.bAnimEnded) {
|
||||
if (inventoryNumLeafs > 0) { // use clover leaf automaticaly
|
||||
sceneHero->X = newHeroX;
|
||||
sceneHero->Y = newHeroY;
|
||||
sceneHero->Z = newHeroZ;
|
||||
|
||||
needChangeScene = currentSceneIdx;
|
||||
inventoryMagicPoints = magicLevelIdx * 20;
|
||||
|
||||
newCameraX = (sceneHero->X >> 9);
|
||||
newCameraY = (sceneHero->Y >> 8);
|
||||
newCameraZ = (sceneHero->Z >> 9);
|
||||
|
||||
heroPositionType = kReborn;
|
||||
|
||||
sceneHero->life = 50;
|
||||
reqBgRedraw = 1;
|
||||
lockPalette = 1;
|
||||
inventoryNumLeafs--;
|
||||
cropBottomScreen = 0;
|
||||
} else { // game over
|
||||
inventoryNumLeafsBox = 2;
|
||||
inventoryNumLeafs = 1;
|
||||
inventoryMagicPoints = magicLevelIdx * 20;
|
||||
heroBehaviour = previousHeroBehaviour;
|
||||
actor->angle = previousHeroAngle;
|
||||
actor->life = 50;
|
||||
|
||||
if (previousSceneIdx != currentSceneIdx) {
|
||||
newHeroX = -1;
|
||||
newHeroY = -1;
|
||||
newHeroZ = -1;
|
||||
currentSceneIdx = previousSceneIdx;
|
||||
}
|
||||
|
||||
saveGame();
|
||||
processGameoverAnimation();
|
||||
quitGame = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
processActorCarrier(a);
|
||||
actor->dynamicFlags.bIsDead = 1;
|
||||
actor->entity = -1;
|
||||
actor->zone = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (needChangeScene != -1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recenter screen automatically
|
||||
if (!disableScreenRecenter && !useFreeCamera) {
|
||||
ActorStruct *actor = &sceneActors[currentlyFollowedActor];
|
||||
projectPositionOnScreen(actor->X - (newCameraX << 9),
|
||||
actor->Y - (newCameraY << 8),
|
||||
actor->Z - (newCameraZ << 9));
|
||||
if (projPosX < 80 || projPosX > 539 || projPosY < 80 || projPosY > 429) {
|
||||
newCameraX = ((actor->X + 0x100) >> 9) + (((actor->X + 0x100) >> 9) - newCameraX) / 2;
|
||||
newCameraY = actor->Y >> 8;
|
||||
newCameraZ = ((actor->Z + 0x100) >> 9) + (((actor->Z + 0x100) >> 9) - newCameraZ) / 2;
|
||||
|
||||
if(newCameraX >= 64) {
|
||||
newCameraX = 63;
|
||||
}
|
||||
|
||||
if(newCameraZ >= 64) {
|
||||
newCameraZ = 63;
|
||||
}
|
||||
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
}
|
||||
|
||||
redrawEngineActions(reqBgRedraw);
|
||||
|
||||
// workaround to fix hero redraw after drowning
|
||||
if(cropBottomScreen && reqBgRedraw == 1) {
|
||||
sceneHero->staticFlags.bIsHidden = 1;
|
||||
redrawEngineActions(1);
|
||||
sceneHero->staticFlags.bIsHidden = 0;
|
||||
}
|
||||
|
||||
needChangeScene = -1;
|
||||
reqBgRedraw = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Game engine main loop
|
||||
@return true if we want to show credit sequence */
|
||||
int32 gameEngineLoop() { // mainLoop
|
||||
uint32 start;
|
||||
|
||||
reqBgRedraw = 1;
|
||||
lockPalette = 1;
|
||||
setActorAngle(0, -256, 5, &loopMovePtr);
|
||||
|
||||
while (quitGame == -1) {
|
||||
start = SDL_GetTicks();
|
||||
|
||||
while (SDL_GetTicks() < start + cfgfile.Fps) {
|
||||
if (runGameEngine())
|
||||
return 1;
|
||||
SDL_Delay(1);
|
||||
}
|
||||
lbaTime++;
|
||||
}
|
||||
return 0;
|
||||
}
|
67
engines/twine/lbaengine.h
Normal file
67
engines/twine/lbaengine.h
Normal file
@ -0,0 +1,67 @@
|
||||
/** @file lbaengine.h
|
||||
@brief
|
||||
This file contains the main game engine routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef GAMEENGINE_H
|
||||
#define GAMEENGINE_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "actor.h"
|
||||
|
||||
int32 quitGame;
|
||||
volatile int32 lbaTime;
|
||||
|
||||
int16 leftMouse;
|
||||
int16 rightMouse;
|
||||
|
||||
/** Work video buffer */
|
||||
uint8 *workVideoBuffer;
|
||||
/** Main game video buffer */
|
||||
uint8 *frontVideoBuffer;
|
||||
/** Auxiliar game video buffer */
|
||||
uint8 *frontVideoBufferbis;
|
||||
|
||||
/** temporary screen table */
|
||||
int32 screenLookupTable[2000];
|
||||
|
||||
ActorMoveStruct loopMovePtr; // mainLoopVar1
|
||||
|
||||
int32 loopPressedKey; // mainLoopVar5
|
||||
int32 previousLoopPressedKey; // mainLoopVar6
|
||||
int32 loopCurrentKey; // mainLoopVar7
|
||||
int32 loopInventoryItem; // mainLoopVar9
|
||||
|
||||
int32 loopActorStep; // mainLoopVar17
|
||||
|
||||
/** Disable screen recenter */
|
||||
int16 disableScreenRecenter;
|
||||
|
||||
int32 zoomScreen;
|
||||
|
||||
void freezeTime();
|
||||
void unfreezeTime();
|
||||
|
||||
int32 gameEngineLoop();
|
||||
|
||||
#endif
|
498
engines/twine/main.cpp
Normal file
498
engines/twine/main.cpp
Normal file
@ -0,0 +1,498 @@
|
||||
/** @file main.cpp
|
||||
@brief
|
||||
This file contains the main engine functions.
|
||||
It also contains configurations file definitions.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "resources.h"
|
||||
#include "sdlengine.h"
|
||||
#include "screens.h"
|
||||
#include "music.h"
|
||||
#include "menu.h"
|
||||
#include "interface.h"
|
||||
#include "flamovies.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "scene.h"
|
||||
#include "grid.h"
|
||||
#include "lbaengine.h"
|
||||
#include "redraw.h"
|
||||
#include "text.h"
|
||||
#include "renderer.h"
|
||||
#include "animations.h"
|
||||
#include "gamestate.h"
|
||||
#include "keyboard.h"
|
||||
#include "actor.h"
|
||||
#include "sound.h"
|
||||
#include "fcaseopen.h"
|
||||
|
||||
/** Engine current version */
|
||||
const int8* ENGINE_VERSION = (int8*) "0.2.0";
|
||||
|
||||
/** Engine configuration filename */
|
||||
const int8* CONFIG_FILENAME = (int8*) "lba.cfg";
|
||||
|
||||
/** Engine install setup filename
|
||||
|
||||
This file contains informations about the game version.
|
||||
This is only used for original games. For mod games project you can
|
||||
used \a lba.cfg file \b Version tag. If this tag is set for original game
|
||||
it will be used instead of \a setup.lst file. */
|
||||
const int8* SETUP_FILENAME = (int8*) "setup.lst";
|
||||
|
||||
/** Configuration types at \a lba.cfg file
|
||||
|
||||
Fill this with all needed configurations at \a lba.cfg file.
|
||||
This engine version allows new type of configurations.
|
||||
Check new config lines at \a lba.cfg file after the first game execution */
|
||||
int8 CFGList[][22] = {
|
||||
"Language:",
|
||||
"LanguageCD:",
|
||||
"FlagDisplayText:",
|
||||
"FlagKeepVoice:",
|
||||
"SvgaDriver:",
|
||||
"MidiDriver:",
|
||||
"MidiExec:",
|
||||
"MidiBase:",
|
||||
"MidiType:",
|
||||
"MidiIRQ:",
|
||||
"MidiDMA:", // 10
|
||||
"WaveDriver:",
|
||||
"WaveExec:",
|
||||
"WaveBase:",
|
||||
"WaveIRQ:",
|
||||
"WaveDMA:",
|
||||
"WaveRate:",
|
||||
"MixerDriver:",
|
||||
"MixerBase:",
|
||||
"WaveVolume:",
|
||||
"VoiceVolume:", // 20
|
||||
"MusicVolume:",
|
||||
"CDVolume:",
|
||||
"LineVolume:",
|
||||
"MasterVolume:",
|
||||
"Version:",
|
||||
"FullScreen:",
|
||||
"UseCD:",
|
||||
"Sound:",
|
||||
"Movie:",
|
||||
"CrossFade:", // 30
|
||||
"Fps:",
|
||||
"Debug:",
|
||||
"UseAutoSaving:",
|
||||
"CombatAuto:",
|
||||
"Shadow:",
|
||||
"SceZoom:",
|
||||
"FillDetails:",
|
||||
"InterfaceStyle",
|
||||
"WallCollision" // 39
|
||||
};
|
||||
|
||||
int8 LanguageTypes[][10] = {
|
||||
"English",
|
||||
"Français",
|
||||
"Deutsch",
|
||||
"Español",
|
||||
"Italiano",
|
||||
"Português"
|
||||
};
|
||||
ConfigFile cfgfile;
|
||||
|
||||
/** Allocate video memory, both front and back buffers */
|
||||
void allocVideoMemory() {
|
||||
int32 i, j, k;
|
||||
|
||||
workVideoBuffer = (uint8 *) malloc((SCREEN_WIDTH * SCREEN_HEIGHT) * sizeof(uint8));
|
||||
frontVideoBuffer = frontVideoBufferbis = (uint8 *) malloc(sizeof(uint8) * SCREEN_WIDTH * SCREEN_HEIGHT);
|
||||
initScreenBuffer(frontVideoBuffer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
j = 0;
|
||||
k = 0;
|
||||
for (i = SCREEN_HEIGHT; i > 0; i--) {
|
||||
screenLookupTable[j] = k;
|
||||
j++;
|
||||
k += SCREEN_WIDTH;
|
||||
}
|
||||
|
||||
// initVideoVar1 = -1;
|
||||
}
|
||||
|
||||
/** Gets configuration type index from lba.cfg config file
|
||||
@param lineBuffer buffer with config line
|
||||
@return config type index */
|
||||
int getConfigTypeIndex(int8* lineBuffer) {
|
||||
int32 i;
|
||||
char buffer[256];
|
||||
char* ptr;
|
||||
|
||||
strcpy(buffer, lineBuffer);
|
||||
|
||||
ptr = strchr(buffer, ' ');
|
||||
|
||||
if (ptr) {
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < (sizeof(CFGList) / 22); i++) {
|
||||
if (strlen(CFGList[i])) {
|
||||
if (!strcmp(CFGList[i], buffer)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Gets configuration type index from lba.cfg config file
|
||||
@param lineBuffer buffer with config line
|
||||
@return config type index */
|
||||
int getLanguageTypeIndex(int8* language) {
|
||||
int32 i;
|
||||
char buffer[256];
|
||||
char* ptr;
|
||||
|
||||
strcpy(buffer, language);
|
||||
|
||||
ptr = strchr(buffer, ' ');
|
||||
|
||||
if (ptr) {
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < (sizeof(LanguageTypes) / 10); i++) {
|
||||
if (strlen(LanguageTypes[i])) {
|
||||
if (!strcmp(LanguageTypes[i], buffer)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // English
|
||||
}
|
||||
|
||||
/** Init configuration file \a lba.cfg */
|
||||
void initConfigurations() {
|
||||
FILE *fd, *fd_test;
|
||||
int8 buffer[256], tmp[16];
|
||||
int32 cfgtype = -1;
|
||||
|
||||
fd = fcaseopen(CONFIG_FILENAME, "rb");
|
||||
if (!fd)
|
||||
printf("Error: Can't find config file %s\n", CONFIG_FILENAME);
|
||||
|
||||
// make sure it quit when it reaches the end of file
|
||||
while (fgets(buffer, 256, fd) != NULL) {
|
||||
*strchr(buffer, 0x0D0A) = 0;
|
||||
cfgtype = getConfigTypeIndex(buffer);
|
||||
if (cfgtype != -1) {
|
||||
switch (cfgtype) {
|
||||
case 0:
|
||||
sscanf(buffer, "Language: %s", cfgfile.Language);
|
||||
cfgfile.LanguageId = getLanguageTypeIndex(cfgfile.Language);
|
||||
break;
|
||||
case 1:
|
||||
sscanf(buffer, "LanguageCD: %s", cfgfile.LanguageCD);
|
||||
cfgfile.LanguageCDId = getLanguageTypeIndex(cfgfile.Language) + 1;
|
||||
break;
|
||||
case 2:
|
||||
sscanf(buffer, "FlagDisplayText: %s", cfgfile.FlagDisplayTextStr);
|
||||
if (!strcmp(cfgfile.FlagDisplayTextStr,"ON")) {
|
||||
cfgfile.FlagDisplayText = 1;
|
||||
} else {
|
||||
cfgfile.FlagDisplayText = 0;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
sscanf(buffer, "FlagKeepVoice: %s", cfgfile.FlagKeepVoiceStr);
|
||||
break;
|
||||
case 8:
|
||||
sscanf(buffer, "MidiType: %s", tmp);
|
||||
if (strcmp(tmp, "auto") == 0) {
|
||||
fd_test = fcaseopen(HQR_MIDI_MI_WIN_FILE, "rb");
|
||||
if (fd_test) {
|
||||
fclose(fd_test);
|
||||
cfgfile.MidiType = 1;
|
||||
}
|
||||
else
|
||||
cfgfile.MidiType = 0;
|
||||
}
|
||||
else if (strcmp(tmp, "midi") == 0)
|
||||
cfgfile.MidiType = 1;
|
||||
else
|
||||
cfgfile.MidiType = 0;
|
||||
break;
|
||||
case 19:
|
||||
sscanf(buffer, "WaveVolume: %d", &cfgfile.WaveVolume);
|
||||
cfgfile.VoiceVolume = cfgfile.WaveVolume;
|
||||
break;
|
||||
case 20:
|
||||
sscanf(buffer, "VoiceVolume: %d", &cfgfile.VoiceVolume);
|
||||
break;
|
||||
case 21:
|
||||
sscanf(buffer, "MusicVolume: %d", &cfgfile.MusicVolume);
|
||||
break;
|
||||
case 22:
|
||||
sscanf(buffer, "CDVolume: %d", &cfgfile.CDVolume);
|
||||
break;
|
||||
case 23:
|
||||
sscanf(buffer, "LineVolume: %d", &cfgfile.LineVolume);
|
||||
break;
|
||||
case 24:
|
||||
sscanf(buffer, "MasterVolume: %d", &cfgfile.MasterVolume);
|
||||
break;
|
||||
case 25:
|
||||
sscanf(buffer, "Version: %d", &cfgfile.Version);
|
||||
break;
|
||||
case 26:
|
||||
sscanf(buffer, "FullScreen: %d", &cfgfile.FullScreen);
|
||||
break;
|
||||
case 27:
|
||||
sscanf(buffer, "UseCD: %d", &cfgfile.UseCD);
|
||||
break;
|
||||
case 28:
|
||||
sscanf(buffer, "Sound: %d", &cfgfile.Sound);
|
||||
break;
|
||||
case 29:
|
||||
sscanf(buffer, "Movie: %d", &cfgfile.Movie);
|
||||
break;
|
||||
case 30:
|
||||
sscanf(buffer, "CrossFade: %d", &cfgfile.CrossFade);
|
||||
break;
|
||||
case 31:
|
||||
sscanf(buffer, "Fps: %d", &cfgfile.Fps);
|
||||
break;
|
||||
case 32:
|
||||
sscanf(buffer, "Debug: %d", &cfgfile.Debug);
|
||||
break;
|
||||
case 33:
|
||||
sscanf(buffer, "UseAutoSaving: %d", &cfgfile.UseAutoSaving);
|
||||
break;
|
||||
case 34:
|
||||
sscanf(buffer, "CombatAuto: %d", &cfgfile.AutoAgressive);
|
||||
break;
|
||||
case 35:
|
||||
sscanf(buffer, "Shadow: %d", &cfgfile.ShadowMode);
|
||||
break;
|
||||
case 36:
|
||||
sscanf(buffer, "SceZoom: %d", &cfgfile.SceZoom);
|
||||
break;
|
||||
case 37:
|
||||
sscanf(buffer, "FillDetails: %d", &cfgfile.FillDetails);
|
||||
break;
|
||||
case 38:
|
||||
sscanf(buffer, "InterfaceStyle: %d", &cfgfile.InterfaceStyle);
|
||||
break;
|
||||
case 39:
|
||||
sscanf(buffer, "WallCollision: %d", &cfgfile.WallCollision);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfgfile.Fps)
|
||||
cfgfile.Fps = DEFAULT_FRAMES_PER_SECOND;
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
/** Initialize LBA engine */
|
||||
void initEngine() {
|
||||
// getting configuration file
|
||||
initConfigurations();
|
||||
|
||||
// Show engine information
|
||||
printf("TwinEngine v%s\n\n", ENGINE_VERSION);
|
||||
printf("(c)2002 The TwinEngine team. Refer to AUTHORS file for further details.\n");
|
||||
printf("Released under the terms of the GNU GPL license version 2 (or, at your opinion, any later). See COPYING file.\n\n");
|
||||
printf("The original Little Big Adventure game is:\n\t(c)1994 by Adeline Software International, All Rights Reserved.\n\n");
|
||||
|
||||
if (cfgfile.Debug)
|
||||
printf("Compiled the %s at %s\n", __DATE__, __TIME__);
|
||||
|
||||
sdlInitialize();
|
||||
|
||||
srand(SDL_GetTicks()); // always get a different seed while starting the game
|
||||
|
||||
allocVideoMemory();
|
||||
clearScreen();
|
||||
|
||||
// Toggle fullscreen if Fullscreen flag is set
|
||||
toggleFullscreen();
|
||||
|
||||
// Check if LBA CD-Rom is on drive
|
||||
initCdrom();
|
||||
|
||||
#ifndef _DEBUG
|
||||
|
||||
// Display company logo
|
||||
adelineLogo();
|
||||
|
||||
// verify game version screens
|
||||
if (cfgfile.Version == EUROPE_VERSION) {
|
||||
// Little Big Adventure screen
|
||||
loadImageDelay(RESSHQR_LBAIMG, 3);
|
||||
// Electronic Arts Logo
|
||||
loadImageDelay(RESSHQR_EAIMG, 2);
|
||||
} else if (cfgfile.Version == USA_VERSION) {
|
||||
// Relentless screen
|
||||
loadImageDelay(RESSHQR_RELLENTIMG, 3);
|
||||
// Electronic Arts Logo
|
||||
loadImageDelay(RESSHQR_EAIMG, 2);
|
||||
} else if (cfgfile.Version == MODIFICATION_VERSION) {
|
||||
// Modification screen
|
||||
loadImageDelay(RESSHQR_RELLENTIMG, 2);
|
||||
}
|
||||
|
||||
playFlaMovie(FLA_DRAGON3);
|
||||
|
||||
#endif
|
||||
|
||||
loadMenuImage(1);
|
||||
|
||||
mainMenu();
|
||||
}
|
||||
|
||||
void initMCGA() {
|
||||
drawInGameTransBox = 1;
|
||||
}
|
||||
|
||||
void initSVGA() {
|
||||
drawInGameTransBox = 0;
|
||||
}
|
||||
|
||||
/** Initialize all needed stuffs at first time running engine */
|
||||
void initAll() {
|
||||
blockBuffer = (uint8 *) malloc(64*64*25*2 * sizeof(uint8));
|
||||
animBuffer1 = animBuffer2 = (uint8 *) malloc(5000 * sizeof(uint8));
|
||||
memset(samplesPlaying, -1, sizeof(int32) * NUM_CHANNELS);
|
||||
memset(itemAngle, 256, sizeof(itemAngle)); // reset inventory items angles
|
||||
|
||||
bubbleSpriteIndex = SPRITEHQR_DIAG_BUBBLE_LEFT;
|
||||
bubbleActor = -1;
|
||||
showDialogueBubble = 1;
|
||||
|
||||
currentTextBank = -1;
|
||||
currMenuTextIndex = -1;
|
||||
currMenuTextBank = -1;
|
||||
autoAgressive = 1;
|
||||
|
||||
sceneHero = &sceneActors[0];
|
||||
|
||||
renderLeft = 0;
|
||||
renderTop = 0;
|
||||
renderRight = SCREEN_TEXTLIMIT_RIGHT;
|
||||
renderBottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
// Set clip to fullscreen by default, allows main menu to render properly after load
|
||||
resetClip();
|
||||
|
||||
rightMouse = 0;
|
||||
leftMouse = 0;
|
||||
|
||||
initResources();
|
||||
|
||||
initSVGA();
|
||||
}
|
||||
|
||||
/** Main engine function
|
||||
@param argc numner of arguments
|
||||
@param argv array with all arguments strings */
|
||||
int main(int argc, char *argv[]) {
|
||||
initAll();
|
||||
initEngine();
|
||||
sdlClose();
|
||||
printf("\n\nLBA/Relentless < %s / %s >\n\nOK.\n\n", __DATE__, __TIME__);
|
||||
printf("TwinEngine v%s closed\n", ENGINE_VERSION);
|
||||
if (cfgfile.Debug) {
|
||||
printf("\nPress <ENTER> to quit debug mode\n");
|
||||
getchar();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// AUX FUNC
|
||||
|
||||
int8* ITOA(int32 number) {
|
||||
int32 numDigits = 1;
|
||||
int8* text;
|
||||
|
||||
if (number >=10 && number <= 99) {
|
||||
numDigits = 2;
|
||||
} else if (number >=100 && number <= 999) {
|
||||
numDigits = 3;
|
||||
}
|
||||
|
||||
text = (int8 *)malloc(sizeof(int8) * (numDigits + 1));
|
||||
sprintf(text, "%d", number);
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
/** \mainpage Twinsen's Engine Doxxy Documentation
|
||||
|
||||
\section intro_sec Introduction
|
||||
|
||||
TwinEngine is a reimplementation project upon the popular
|
||||
Little Big Adventure games released respectively in
|
||||
1994 (Relentless in North America) and 1997 (Twinsen's Odyssey).
|
||||
|
||||
\section doc_sec Documentation
|
||||
|
||||
This document, allows you to easily search for particulary things among
|
||||
the code. We plan to comment as best as we can and with the most necessary
|
||||
informations. The source code is also shared in this document and you can
|
||||
use it in the terms of the license.
|
||||
|
||||
Feel free to contact us if you wanna help improving this documentation and
|
||||
the engine itself.
|
||||
|
||||
\section copy_sec Copyright
|
||||
|
||||
Copyright (c) Adeline Software International 1994, All Rights Reserved.\n
|
||||
Copyright (c) 2002-2007 The TwinEngine team.\n
|
||||
Copyright (c) 2008-2013 Prequengine team \n
|
||||
Copyright (c) 2013 The TwinEngine team
|
||||
|
||||
\section licenc_sec License
|
||||
|
||||
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.
|
||||
|
||||
For a full license, check the license file in source code.
|
||||
*/
|
144
engines/twine/main.h
Normal file
144
engines/twine/main.h
Normal file
@ -0,0 +1,144 @@
|
||||
/** @file main.h
|
||||
@brief
|
||||
This file contains the main engine functions. It also contains
|
||||
configurations file definitions.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/** Definition for European version */
|
||||
#define EUROPE_VERSION 0
|
||||
/** Definition for American version */
|
||||
#define USA_VERSION 1
|
||||
/** Definition for Modification version */
|
||||
#define MODIFICATION_VERSION 2
|
||||
|
||||
/** Original screen width */
|
||||
#define DEFAULT_SCREEN_WIDTH 640
|
||||
/** Original screen height */
|
||||
#define DEFAULT_SCREEN_HEIGHT 480
|
||||
/** Scale screen to double size */
|
||||
#define SCALE 1
|
||||
/** Original screen width */
|
||||
#define SCREEN_WIDTH DEFAULT_SCREEN_WIDTH * SCALE
|
||||
/** Original screen height */
|
||||
#define SCREEN_HEIGHT DEFAULT_SCREEN_HEIGHT * SCALE
|
||||
/** Original FLA screen width */
|
||||
#define FLASCREEN_WIDTH 320
|
||||
/** Original FLA screen height */
|
||||
#define FLASCREEN_HEIGHT 200
|
||||
/** Default frames per second */
|
||||
#define DEFAULT_FRAMES_PER_SECOND 19
|
||||
|
||||
/** Number of colors used in the game */
|
||||
#define NUMOFCOLORS 256
|
||||
|
||||
|
||||
/** Configuration file structure
|
||||
|
||||
Used in the engine to load/use certain parts of code according with
|
||||
this settings. Check \a lba.cfg file for valid values for each settings.\n
|
||||
All the settings with (*) means they are new and only exist in this engine. */
|
||||
typedef struct ConfigFile {
|
||||
/** Language name */
|
||||
int8 Language[10];
|
||||
/** Language CD name */
|
||||
int8 LanguageCD[10];
|
||||
/** Language Identification according with Language setting. */
|
||||
int32 LanguageId;
|
||||
/** Language Identification according with Language setting. */
|
||||
int32 LanguageCDId;
|
||||
/** Enable/Disable game dialogues */
|
||||
int8 FlagDisplayTextStr[3];
|
||||
/** Enable/Disable game dialogues */
|
||||
int32 FlagDisplayText;
|
||||
/** Save voice files on hard disk */
|
||||
int8 FlagKeepVoiceStr[3];
|
||||
/** Save voice files on hard disk */
|
||||
int32 FlagKeepVoice;
|
||||
/** Type of music file to be used */
|
||||
int8 MidiType;
|
||||
/** Wave volume */
|
||||
int32 WaveVolume;
|
||||
/** Chacters voices volume */
|
||||
int32 VoiceVolume;
|
||||
/** Music volume */
|
||||
int32 MusicVolume;
|
||||
/** CD volume */
|
||||
int32 CDVolume;
|
||||
/** Line-In volume */
|
||||
int32 LineVolume;
|
||||
/** Main volume controller */
|
||||
int32 MasterVolume;
|
||||
/** *Game version */
|
||||
int32 Version;
|
||||
/** To allow fullscreen or window mode. */
|
||||
int32 FullScreen;
|
||||
/** If you want to use the LBA CD or not */
|
||||
int32 UseCD;
|
||||
/** Allow various sound types */
|
||||
int32 Sound;
|
||||
/** Allow various movie types */
|
||||
int32 Movie;
|
||||
/** Use cross fade effect while changing images, or be as the original */
|
||||
int32 CrossFade;
|
||||
/** Flag used to keep the game frames per second */
|
||||
int32 Fps;
|
||||
/** Flag to display game debug */
|
||||
int32 Debug;
|
||||
/** Use original autosaving system or save when you want */
|
||||
int32 UseAutoSaving;
|
||||
/** Shadow mode type */
|
||||
int32 ShadowMode;
|
||||
/** AutoAgressive mode type */
|
||||
int32 AutoAgressive;
|
||||
/** SceZoom mode type */
|
||||
int32 SceZoom;
|
||||
/** FillDetails mode type */
|
||||
int32 FillDetails;
|
||||
/** Flag to quit the game */
|
||||
int32 Quit;
|
||||
/** Flag to change interface style */
|
||||
int32 InterfaceStyle;
|
||||
/** Flag to toggle Wall Collision */
|
||||
int32 WallCollision;
|
||||
} ConfigFile;
|
||||
|
||||
/** Configuration file structure
|
||||
|
||||
Contains all the data used in the engine to configurated the game in particulary ways.\n
|
||||
A detailled information of all types are in \a main.h header file. */
|
||||
extern ConfigFile cfgfile;
|
||||
|
||||
/** CD Game directory */
|
||||
int8 * cdDir;
|
||||
|
||||
void initMCGA();
|
||||
void initSVGA();
|
||||
|
||||
int8* ITOA(int32 number);
|
||||
|
||||
#endif
|
1268
engines/twine/menu.cpp
Normal file
1268
engines/twine/menu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
86
engines/twine/menu.h
Normal file
86
engines/twine/menu.h
Normal file
@ -0,0 +1,86 @@
|
||||
/** @file menu.h
|
||||
@brief
|
||||
This file contains main menu create and processing routines.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MENU_H
|
||||
#define MENU_H
|
||||
|
||||
#include "sdlengine.h"
|
||||
#include "actor.h"
|
||||
|
||||
int32 currMenuTextIndex;
|
||||
int32 currMenuTextBank;
|
||||
int8 currMenuTextBuffer[256];
|
||||
|
||||
int16 itemAngle[255]; // objectRotation
|
||||
|
||||
extern int16 OptionsMenuSettings[];
|
||||
|
||||
/** Behaviour menu move pointer */
|
||||
ActorMoveStruct moveMenu;
|
||||
|
||||
/** Plasma Effect pointer to file content: RESS.HQR:51 */
|
||||
extern uint8 *plasmaEffectPtr;
|
||||
|
||||
/** Process the plasma effect
|
||||
@param top top height where the effect will be draw in the front buffer
|
||||
@param color plasma effect start color */
|
||||
void processPlasmaEffect(int32 top, int32 color);
|
||||
|
||||
/** Draw the entire button box
|
||||
@param left start width to draw the button
|
||||
@param top start height to draw the button
|
||||
@param right end width to draw the button
|
||||
@param bottom end height to draw the button */
|
||||
void drawBox(int32 left, int32 top, int32 right, int32 bottom);
|
||||
|
||||
/** Draws inside buttons transparent area
|
||||
@param left start width to draw the button
|
||||
@param top start height to draw the button
|
||||
@param right end width to draw the button
|
||||
@param bottom end height to draw the button
|
||||
@param colorAdj index to adjust the transparent box color */
|
||||
void drawTransparentBox(int32 left, int32 top, int32 right, int32 bottom, int32 colorAdj);
|
||||
|
||||
/** Where the main menu options are processed
|
||||
@param menuSettings menu settings array with the information to build the menu options
|
||||
@return pressed menu button identification */
|
||||
int32 processMenu(int16 * menuSettings);
|
||||
|
||||
/** Used to run the main menu */
|
||||
void mainMenu();
|
||||
|
||||
/** Used to run the in-game give-up menu */
|
||||
int32 giveupMenu();
|
||||
|
||||
/** Used to run the options menu */
|
||||
int32 optionsMenu();
|
||||
|
||||
/** Process hero behaviour menu */
|
||||
void processBehaviourMenu();
|
||||
|
||||
/** Process in-game inventory menu */
|
||||
void processInventoryMenu();
|
||||
|
||||
#endif
|
313
engines/twine/menuoptions.cpp
Normal file
313
engines/twine/menuoptions.cpp
Normal file
@ -0,0 +1,313 @@
|
||||
/** @file menuoptions.cpp
|
||||
@brief
|
||||
This file contains menu routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "menuoptions.h"
|
||||
#include "lbaengine.h"
|
||||
#include "main.h"
|
||||
#include "screens.h"
|
||||
#include "resources.h"
|
||||
#include "sdlengine.h"
|
||||
#include "text.h"
|
||||
#include "gamestate.h"
|
||||
#include "music.h"
|
||||
#include "keyboard.h"
|
||||
#include "flamovies.h"
|
||||
#include "scene.h"
|
||||
#include "interface.h"
|
||||
#include "menu.h"
|
||||
#include "text.h"
|
||||
|
||||
/** Main menu continue game option key */
|
||||
#define MAINMENU_CONTINUEGAME 21
|
||||
/** Main menu enter players name */
|
||||
#define MAINMENU_ENTERPLAYERNAME 42
|
||||
|
||||
int8 allowedCharIndex[] = " ABCDEFGHIJKLM.NOPQRSTUVWXYZ-abcdefghijklm?nopqrstuvwxyz!0123456789\040\b\r\0";
|
||||
|
||||
|
||||
void newGame() {
|
||||
int32 tmpFlagDisplayText;
|
||||
|
||||
stopMusic();
|
||||
|
||||
tmpFlagDisplayText = cfgfile.FlagDisplayText;
|
||||
cfgfile.FlagDisplayText = 1;
|
||||
|
||||
// intro screen 1 - twinsun
|
||||
loadImage(RESSHQR_INTROSCREEN1IMG, 1);
|
||||
|
||||
newGameVar4 = 0;
|
||||
newGameVar5 = 1;
|
||||
|
||||
initTextBank(2);
|
||||
textClipFull();
|
||||
setFontCrossColor(15);
|
||||
|
||||
drawTextFullscreen(150);
|
||||
readKeys();
|
||||
|
||||
if (skipIntro != 1) {
|
||||
// intro screen 1 - twinsun
|
||||
loadImage(RESSHQR_INTROSCREEN2IMG, 1);
|
||||
drawTextFullscreen(151);
|
||||
readKeys();
|
||||
|
||||
if (skipIntro != 1) {
|
||||
loadImage(RESSHQR_INTROSCREEN3IMG, 1);
|
||||
drawTextFullscreen(152);
|
||||
}
|
||||
}
|
||||
|
||||
newGameVar5 = 0;
|
||||
textClipSmall();
|
||||
newGameVar4 = 1;
|
||||
|
||||
fadeToBlack(paletteRGBACustom);
|
||||
clearScreen();
|
||||
flip();
|
||||
|
||||
playMidiMusic(1, 0);
|
||||
playFlaMovie(FLA_INTROD);
|
||||
|
||||
clearScreen();
|
||||
flip();
|
||||
|
||||
// set main palette back
|
||||
setPalette(paletteRGBA);
|
||||
|
||||
cfgfile.FlagDisplayText = tmpFlagDisplayText;
|
||||
}
|
||||
|
||||
void showCredits() {
|
||||
int32 tmpShadowMode, tmpLanguageCDIdx;
|
||||
|
||||
canShowCredits = 1;
|
||||
tmpShadowMode = cfgfile.ShadowMode;
|
||||
tmpLanguageCDIdx = cfgfile.LanguageCDId;
|
||||
cfgfile.ShadowMode = 0;
|
||||
cfgfile.LanguageCDId = 0;
|
||||
initEngineVars(1);
|
||||
currentSceneIdx = 119;
|
||||
needChangeScene = 119;
|
||||
|
||||
gameEngineLoop();
|
||||
|
||||
canShowCredits = 0;
|
||||
cfgfile.ShadowMode = tmpShadowMode;
|
||||
cfgfile.LanguageCDId = tmpLanguageCDIdx;
|
||||
|
||||
clearScreen();
|
||||
flip();
|
||||
|
||||
playFlaMovie(FLA_THEEND);
|
||||
|
||||
clearScreen();
|
||||
flip();
|
||||
setPalette(paletteRGBA);
|
||||
}
|
||||
|
||||
void drawSelectableCharacter(int32 x, int32 y, int32 arg) {
|
||||
int8 buffer[256];
|
||||
int32 centerX, left, top, centerY, bottom, right, right2;
|
||||
|
||||
buffer[0] = allowedCharIndex[y + x * 14];
|
||||
|
||||
centerX = y * 45 + 25;
|
||||
left = centerX - 20;
|
||||
right = centerX + 20;
|
||||
top = x * 56 + 200 - 25;
|
||||
buffer[1] = 0;
|
||||
centerY = x * 56 + 200;
|
||||
bottom = x * 56 + 200 + 25;
|
||||
|
||||
if (arg != 0) {
|
||||
drawSplittedBox(left, top, right, bottom, 91);
|
||||
} else {
|
||||
blitBox(left, top, right, bottom, (int8 *) workVideoBuffer, left, top, (int8 *)frontVideoBuffer);
|
||||
right2 = right;
|
||||
drawTransparentBox(left, top, right2, bottom, 4);
|
||||
}
|
||||
|
||||
drawBox(left, top, right, bottom);
|
||||
right2 = right;
|
||||
|
||||
setFontColor(15);
|
||||
drawText(centerX - getTextSize(buffer) / 2, centerY - 18, buffer);
|
||||
|
||||
copyBlockPhys(left, top, right2, bottom);
|
||||
}
|
||||
|
||||
void drawSelectableCharacters(void) {
|
||||
int8 x, y;
|
||||
|
||||
for (x = 0; x < 5; x++) {
|
||||
for (y = 0; y < 14; y++) {
|
||||
drawSelectableCharacter(x, y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0001F18C
|
||||
void drawPlayerName(int32 centerx, int32 top, int8* playerName, int32 type) {
|
||||
/*
|
||||
int v4; // ebp@0
|
||||
int v6; // [sp+0h] [bp-14h]@0
|
||||
int v7; // [sp+0h] [bp-14h]@4
|
||||
int v8; // [sp+4h] [bp-10h]@0
|
||||
int v9; // [sp+4h] [bp-10h]@4
|
||||
|
||||
LOWORD(v8) = a1 - buttonDrawVar1 / 2;
|
||||
if ( !a4 )
|
||||
{
|
||||
v6 = (signed __int16)(a2 + 25);
|
||||
blitRectangle(v4);
|
||||
drawBoxInsideTrans(v4);
|
||||
}
|
||||
if ( a4 == 1 )
|
||||
{
|
||||
makeFireEffect(v4);
|
||||
if ( !(rand(v6, v8) % 5) )
|
||||
*(_BYTE *)(10 * rand(v7, v9) % 320 + bufSpeak + 6400) = -1;
|
||||
}
|
||||
if ( a4 == 2 )
|
||||
Box(v4);
|
||||
DrawCadre();
|
||||
CoulFont(0xFu);
|
||||
SizeFont(a3);
|
||||
Font(v4);
|
||||
return CopyBlockPhys(v4);
|
||||
*/
|
||||
|
||||
// TODO: implement the other types (don't seam to be used)
|
||||
/*if (type == 1) {
|
||||
processPlasmaEffect(top, 1);
|
||||
}
|
||||
|
||||
drawBox(x, top, dialTextBoxRight, dialTextBoxBottom);
|
||||
drawTransparentBox(dialTextBoxLeft + 1, dialTextBoxTop + 1, dialTextBoxRight - 1, dialTextBoxBottom - 1, 3);
|
||||
|
||||
setFontColor(15);
|
||||
drawText(centerX - getTextSize(playerName) / 2, top, playerName);
|
||||
|
||||
copyBlockPhys(x, y, x + 320, y + 25);*/
|
||||
}
|
||||
|
||||
int32 enterPlayerName(int32 textIdx) {
|
||||
int8 buffer[256];
|
||||
|
||||
while(1) {
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
flip(); //frontVideoBuffer
|
||||
initTextBank(0);
|
||||
getMenuText(textIdx, buffer);
|
||||
setFontColor(15);
|
||||
drawText(320 - (getTextSize(buffer) / 2), 20, buffer);
|
||||
copyBlockPhys(0, 0, 639, 99);
|
||||
playerName[0] = enterPlayerNameVar1;
|
||||
drawPlayerName(320, 100, playerName, 1);
|
||||
drawSelectableCharacters();
|
||||
|
||||
do {
|
||||
readKeys();
|
||||
do {
|
||||
readKeys();
|
||||
} while(skipIntro);
|
||||
} while(skippedKey);
|
||||
|
||||
enterPlayerNameVar2 = 1;
|
||||
|
||||
do {
|
||||
readKeys();
|
||||
} while(pressedKey);
|
||||
|
||||
while (!skipIntro) {
|
||||
readKeys();
|
||||
// TODO
|
||||
drawPlayerName(320, 100, playerName, 1);
|
||||
}
|
||||
|
||||
// FIXME: remove this lines after implementing everything
|
||||
if (skipIntro)
|
||||
break;
|
||||
}
|
||||
|
||||
enterPlayerNameVar2 = 0;
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
flip(); // frontVideoBuffer
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Main menu new game options */
|
||||
void newGameMenu() {
|
||||
//TODO: process players name
|
||||
if(enterPlayerName(MAINMENU_ENTERPLAYERNAME))
|
||||
{
|
||||
initEngineVars(1);
|
||||
newGame();
|
||||
|
||||
if (gameEngineLoop()) {
|
||||
showCredits();
|
||||
}
|
||||
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
// TODO: recheck this
|
||||
do {
|
||||
readKeys();
|
||||
do {
|
||||
readKeys();
|
||||
} while(skippedKey != 0);
|
||||
} while(skipIntro != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Main menu continue game options */
|
||||
void continueGameMenu() {
|
||||
//TODO: get list of saved games
|
||||
//if(chooseSave(MAINMENU_CONTINUEGAME))
|
||||
{
|
||||
initEngineVars(-1); // will load game
|
||||
if (gameChapter == 0 && currentSceneIdx == 0) {
|
||||
newGame();
|
||||
} else {
|
||||
newGameVar5 = 0;
|
||||
textClipSmall();
|
||||
newGameVar4 = 1;
|
||||
}
|
||||
|
||||
if (gameEngineLoop()) {
|
||||
showCredits();
|
||||
}
|
||||
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
// TODO: recheck this
|
||||
do {
|
||||
readKeys();
|
||||
do {
|
||||
readKeys();
|
||||
} while(skippedKey != 0);
|
||||
} while(skipIntro != 0);
|
||||
}
|
||||
}
|
43
engines/twine/menuoptions.h
Normal file
43
engines/twine/menuoptions.h
Normal file
@ -0,0 +1,43 @@
|
||||
/** @file menuoptions.h
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MENUOPTIONS_H
|
||||
#define MENUOPTIONS_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
int32 canShowCredits;
|
||||
|
||||
int8 playerName[256];
|
||||
int8 enterPlayerNameVar1;
|
||||
int32 enterPlayerNameVar2;
|
||||
|
||||
/** Main menu new game options */
|
||||
void newGameMenu();
|
||||
|
||||
/** Main menu continue game options */
|
||||
void continueGameMenu();
|
||||
|
||||
#endif
|
156
engines/twine/metaengine.cpp
Normal file
156
engines/twine/metaengine.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
/* 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/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "common/fs.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "base/plugins.h"
|
||||
#include "graphics/thumbnail.h"
|
||||
|
||||
#include "tucker/tucker.h"
|
||||
|
||||
class TwinEMetaEngine : public AdvancedMetaEngine {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "TwinE";
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override {
|
||||
switch (f) {
|
||||
case kSupportsListSaves:
|
||||
case kSupportsLoadingDuringStartup:
|
||||
case kSupportsDeleteSave:
|
||||
case kSavesSupportMetaInfo:
|
||||
case kSavesSupportThumbnail:
|
||||
case kSavesSupportCreationDate:
|
||||
case kSavesSupportPlayTime:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override {
|
||||
if (desc) {
|
||||
*engine = new TwinE::TwinEEngine(syst, desc->language, desc->flags);
|
||||
}
|
||||
return desc != nullptr;
|
||||
}
|
||||
|
||||
SaveStateList listSaves(const char *target) const override {
|
||||
Common::String pattern = TwinE::generateGameStateFileName(target, 0, true);
|
||||
Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
|
||||
TwinE::TwinEEngine::SavegameHeader header;
|
||||
SaveStateList saveList;
|
||||
|
||||
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
|
||||
int slot;
|
||||
const char *ext = strrchr(file->c_str(), '.');
|
||||
if (ext && (slot = atoi(ext + 1)) >= 0 && slot <= TwinE::kLastSaveSlot) {
|
||||
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
|
||||
if (in) {
|
||||
if (TwinE::TwinEEngine::readSavegameHeader(in, header) == TwinE::TwinEEngine::kSavegameNoError) {
|
||||
saveList.push_back(SaveStateDescriptor(slot, header.description));
|
||||
}
|
||||
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort saves based on slot number.
|
||||
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
|
||||
return saveList;
|
||||
}
|
||||
|
||||
int getMaximumSaveSlot() const override {
|
||||
return TwinE::kLastSaveSlot;
|
||||
}
|
||||
|
||||
virtual int getAutosaveSlot() const override {
|
||||
return TwinE::kAutoSaveSlot;
|
||||
}
|
||||
|
||||
void removeSaveState(const char *target, int slot) const override {
|
||||
Common::String filename = TwinE::generateGameStateFileName(target, slot);
|
||||
g_system->getSavefileManager()->removeSavefile(filename);
|
||||
}
|
||||
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override {
|
||||
Common::String fileName = Common::String::format("%s.%d", target, slot);
|
||||
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
|
||||
|
||||
if (!file) {
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
TwinE::TwinEEngine::SavegameHeader header;
|
||||
TwinE::TwinEEngine::SavegameError savegameError = TwinE::TwinEEngine::readSavegameHeader(file, header, false);
|
||||
if (savegameError) {
|
||||
delete file;
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
SaveStateDescriptor desc(slot, header.description);
|
||||
|
||||
if (slot == TwinE::kAutoSaveSlot) {
|
||||
bool autosaveAllowed = TwinE::TwinEEngine::isAutosaveAllowed(target);
|
||||
desc.setDeletableFlag(!autosaveAllowed);
|
||||
desc.setWriteProtectedFlag(autosaveAllowed);
|
||||
}
|
||||
|
||||
if (header.version >= 2) {
|
||||
// creation/play time
|
||||
if (header.saveDate) {
|
||||
int day = (header.saveDate >> 24) & 0xFF;
|
||||
int month = (header.saveDate >> 16) & 0xFF;
|
||||
int year = header.saveDate & 0xFFFF;
|
||||
desc.setSaveDate(year, month, day);
|
||||
}
|
||||
|
||||
if (header.saveTime) {
|
||||
int hour = (header.saveTime >> 16) & 0xFF;
|
||||
int minutes = (header.saveTime >> 8) & 0xFF;
|
||||
desc.setSaveTime(hour, minutes);
|
||||
}
|
||||
|
||||
if (header.playTime) {
|
||||
desc.setPlayTime(header.playTime * 1000);
|
||||
}
|
||||
|
||||
// thumbnail
|
||||
if (header.thumbnail) {
|
||||
desc.setThumbnail(header.thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
delete file;
|
||||
return desc;
|
||||
}
|
||||
};
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(TwinE)
|
||||
REGISTER_PLUGIN_DYNAMIC(TwinE, PLUGIN_TYPE_ENGINE, TwinEMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(TwinE, PLUGIN_TYPE_ENGINE, TwinEMetaEngine);
|
||||
#endif
|
50
engines/twine/module.mk
Normal file
50
engines/twine/module.mk
Normal file
@ -0,0 +1,50 @@
|
||||
MODULE := engines/twine
|
||||
|
||||
MODULE_OBJS := \
|
||||
actor.o \
|
||||
animations.o \
|
||||
collision.o \
|
||||
debug.o \
|
||||
debug.grid.o \
|
||||
debug.scene.o \
|
||||
detection.o \
|
||||
extra.o \
|
||||
fcaseopen.o \
|
||||
filereader.o \
|
||||
flamovies.o \
|
||||
gamestate.o \
|
||||
grid.o \
|
||||
holomap.o \
|
||||
hqrdepack.o \
|
||||
interface.o \
|
||||
keyboard.o \
|
||||
lbaengine.o \
|
||||
main.o \
|
||||
menu.o \
|
||||
menuoptions.o \
|
||||
metaengine.o \
|
||||
movements.o \
|
||||
music.o \
|
||||
redraw.o \
|
||||
renderer.o \
|
||||
resources.o \
|
||||
scene.o \
|
||||
screens.o \
|
||||
script.life.o \
|
||||
script.move.o \
|
||||
sdlengine.o \
|
||||
sound.o \
|
||||
sys.o \
|
||||
text.o \
|
||||
xmidi.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_TWINE), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
539
engines/twine/movements.cpp
Normal file
539
engines/twine/movements.cpp
Normal file
@ -0,0 +1,539 @@
|
||||
/** @file movements.cpp
|
||||
@brief
|
||||
This file contains 3d actor movement rendering routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "movements.h"
|
||||
#include "actor.h"
|
||||
#include "lbaengine.h"
|
||||
#include "renderer.h"
|
||||
#include "grid.h"
|
||||
#include "scene.h"
|
||||
#include "keyboard.h"
|
||||
#include "animations.h"
|
||||
#include "collision.h"
|
||||
#include "gamestate.h"
|
||||
|
||||
/** Get shadow position
|
||||
@param X Shadow X coordinate
|
||||
@param Y Shadow Y coordinate
|
||||
@param Z Shadow Z coordinate */
|
||||
void getShadowPosition(int32 X, int32 Y, int32 Z) {
|
||||
int32 tempX;
|
||||
int32 tempY;
|
||||
int32 tempZ;
|
||||
uint8* ptr;
|
||||
|
||||
tempX = (X + 0x100) >> 9;
|
||||
tempY = Y >> 8;
|
||||
tempZ = (Z + 0x100) >> 9;
|
||||
|
||||
ptr = blockBuffer + tempY * 2 + tempX * 25 * 2 + (tempZ << 6) * 25 * 2;
|
||||
|
||||
while (tempY) { // search down until either ground is found or lower border of the cube is reached
|
||||
if (*(int16*)ptr) // found the ground
|
||||
break;
|
||||
|
||||
tempY--;
|
||||
ptr -= 2;
|
||||
}
|
||||
|
||||
shadowCollisionType = 0;
|
||||
|
||||
collisionX = tempX;
|
||||
collisionY = tempY;
|
||||
collisionZ = tempZ;
|
||||
|
||||
processActorX = X;
|
||||
processActorY = (tempY + 1) << 8;
|
||||
processActorZ = Z;
|
||||
|
||||
if (*ptr) { //*((uint8 *)(blockPtr))
|
||||
uint8 *blockPtr;
|
||||
uint8 brickShape;
|
||||
|
||||
blockPtr = getBlockLibrary(*(ptr) - 1) + 3 + *(ptr + 1) * 4;
|
||||
brickShape = *((uint8 *)(blockPtr));
|
||||
|
||||
shadowCollisionType = brickShape;
|
||||
reajustActorPosition(shadowCollisionType);
|
||||
}
|
||||
|
||||
shadowX = processActorX;
|
||||
shadowY = processActorY;
|
||||
shadowZ = processActorZ;
|
||||
}
|
||||
|
||||
/** Set actor safe angle
|
||||
@param startAngle start angle
|
||||
@param endAngle end angle
|
||||
@param stepAngle number of steps
|
||||
@param movePtr Pointer to process movements */
|
||||
void setActorAngleSafe(int16 startAngle, int16 endAngle, int16 stepAngle, ActorMoveStruct * movePtr) {
|
||||
movePtr->from = startAngle & 0x3FF;
|
||||
movePtr->to = endAngle & 0x3FF;
|
||||
movePtr->numOfStep = stepAngle & 0x3FF;
|
||||
movePtr->timeOfChange = lbaTime;
|
||||
}
|
||||
|
||||
/** Clear actors safe angle
|
||||
@param actorPtr actor pointer */
|
||||
void clearRealAngle(ActorStruct * actorPtr) {
|
||||
setActorAngleSafe(actorPtr->angle, actorPtr->angle, 0, &actorPtr->move);
|
||||
}
|
||||
|
||||
/** Set actor safe angle
|
||||
@param startAngle start angle
|
||||
@param endAngle end angle
|
||||
@param stepAngle number of steps
|
||||
@param movePtr Pointer to process movements */
|
||||
void setActorAngle(int16 startAngle, int16 endAngle, int16 stepAngle, ActorMoveStruct * movePtr) {
|
||||
movePtr->from = startAngle;
|
||||
movePtr->to = endAngle;
|
||||
movePtr->numOfStep = stepAngle;
|
||||
movePtr->timeOfChange = lbaTime;
|
||||
}
|
||||
|
||||
/** Get actor angle
|
||||
@param x1 Actor 1 X
|
||||
@param z1 Actor 1 Z
|
||||
@param x2 Actor 2 X
|
||||
@param z2 Actor 2 Z */
|
||||
#define PI 3.14159265
|
||||
int32 getAngleAndSetTargetActorDistance(int32 x1, int32 z1, int32 x2, int32 z2) {
|
||||
/*
|
||||
//Pythagoras
|
||||
targetActorDistance = (int32)sqrt((int64)(((z2 - z1)*(z2 - z1) + (x2 - x1)*(x2 - x1))));
|
||||
|
||||
if (targetActorDistance == 0)
|
||||
return 0;
|
||||
|
||||
//given two points, we calculate its arc-tangent in radians
|
||||
//Then we convert from radians (360 degrees == 2*PI) to a 10bit value (360 degrees == 1024) and invert the rotation direction
|
||||
//Then we add an offset of 90 degrees (256) and limit it to the 10bit value range.
|
||||
return (256 + ((int32)floor((-1024 * atan2((int64)(z2-z1), (int32)(x2-x1))) / (2*PI)))) % 1024;
|
||||
*/
|
||||
|
||||
int32 newX, newZ, difX, difZ, tmpX, tmpZ, tmpEx, flag, destAngle, startAngle, finalAngle;
|
||||
|
||||
difZ = tmpZ = z2 - z1;
|
||||
newZ = tmpZ * tmpZ;
|
||||
|
||||
difX = tmpX = x2 - x1;
|
||||
newX = tmpX * tmpX;
|
||||
|
||||
// Exchange X and Z
|
||||
if (newX < newZ) {
|
||||
tmpEx = difX;
|
||||
difX = difZ;
|
||||
difZ = tmpEx;
|
||||
|
||||
flag = 1;
|
||||
} else {
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
targetActorDistance = (int32)sqrt((int64)(newX + newZ));
|
||||
|
||||
if (!targetActorDistance) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
destAngle = (difZ << 14) / targetActorDistance;
|
||||
|
||||
startAngle = 0;
|
||||
// stopAngle = 0x100;
|
||||
|
||||
while (shadeAngleTab3[startAngle] > destAngle) {
|
||||
startAngle++;
|
||||
}
|
||||
|
||||
if (shadeAngleTab3[startAngle] != destAngle) {
|
||||
if ((shadeAngleTab3[startAngle - 1] + shadeAngleTab3[startAngle]) / 2 <= destAngle) {
|
||||
startAngle--;
|
||||
}
|
||||
}
|
||||
|
||||
finalAngle = 128 + startAngle;
|
||||
|
||||
if (difX <= 0) {
|
||||
finalAngle = -finalAngle;
|
||||
}
|
||||
|
||||
if (flag & 1) {
|
||||
finalAngle = -finalAngle + 0x100;
|
||||
}
|
||||
|
||||
return finalAngle & 0x3FF;
|
||||
}
|
||||
|
||||
/** Get actor real angle
|
||||
@param movePtr Pointer to process movements */
|
||||
int32 getRealAngle(ActorMoveStruct * movePtr) {
|
||||
int32 timePassed;
|
||||
int32 remainingAngle;
|
||||
|
||||
if (movePtr->numOfStep) {
|
||||
timePassed = lbaTime - movePtr->timeOfChange;
|
||||
|
||||
if (timePassed >= movePtr->numOfStep) { // rotation is finished
|
||||
movePtr->numOfStep = 0;
|
||||
return movePtr->to;
|
||||
}
|
||||
|
||||
remainingAngle = movePtr->to - movePtr->from;
|
||||
|
||||
if (remainingAngle < -0x200) {
|
||||
remainingAngle += 0x400;
|
||||
} else if (remainingAngle > 0x200) {
|
||||
remainingAngle -= 0x400;
|
||||
}
|
||||
|
||||
remainingAngle *= timePassed;
|
||||
remainingAngle /= movePtr->numOfStep;
|
||||
remainingAngle += movePtr->from;
|
||||
|
||||
return (remainingAngle);
|
||||
}
|
||||
|
||||
return movePtr->to;
|
||||
}
|
||||
|
||||
/** Get actor step
|
||||
@param movePtr Pointer to process movements */
|
||||
int32 getRealValue(ActorMoveStruct * movePtr) {
|
||||
int32 tempStep;
|
||||
|
||||
if (!movePtr->numOfStep)
|
||||
return movePtr->to;
|
||||
|
||||
if (!(lbaTime - movePtr->timeOfChange < movePtr->numOfStep)) {
|
||||
movePtr->numOfStep = 0;
|
||||
return movePtr->to;
|
||||
}
|
||||
|
||||
tempStep = movePtr->to - movePtr->from;
|
||||
tempStep *= lbaTime - movePtr->timeOfChange;
|
||||
tempStep /= movePtr->numOfStep;
|
||||
|
||||
return tempStep + movePtr->from;
|
||||
}
|
||||
|
||||
/** Rotate actor with a given angle
|
||||
@param X Actor current X coordinate
|
||||
@param Z Actor current Z coordinate
|
||||
@param angle Actor angle to rotate */
|
||||
void rotateActor(int32 X, int32 Z, int32 angle) {
|
||||
double radians = 2*PI*angle/0x400;
|
||||
destX = (int32)(X*cos(radians) + Z*sin(radians));
|
||||
destZ = (int32)(-X*sin(radians) + Z*cos(radians));
|
||||
}
|
||||
|
||||
/** Get distance value in 2D
|
||||
@param x1 Actor 1 X coordinate
|
||||
@param z1 Actor 1 Z coordinate
|
||||
@param x2 Actor 2 X coordinate
|
||||
@param z2 Actor 2 Z coordinate */
|
||||
int32 getDistance2D(int32 x1, int32 z1, int32 x2, int32 z2) {
|
||||
return (int32)sqrt((int64)((x2-x1)*(x2-x1) + (z2-z1)*(z2-z1)));
|
||||
}
|
||||
|
||||
/** Get distance value in 3D
|
||||
@param x1 Actor 1 X coordinate
|
||||
@param y1 Actor 1 Y coordinate
|
||||
@param z1 Actor 1 Z coordinate
|
||||
@param x2 Actor 2 X coordinate
|
||||
@param y2 Actor 2 Y coordinate
|
||||
@param z2 Actor 2 Z coordinate */
|
||||
int32 getDistance3D(int32 x1, int32 y1, int32 z1, int32 x2, int32 y2, int32 z2) {
|
||||
return (int32)sqrt((int64)((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1)));
|
||||
}
|
||||
|
||||
/** Move actor around the scene
|
||||
@param angleFrom Current actor angle
|
||||
@param angleTo Angle to rotate
|
||||
@param speed Rotate speed
|
||||
@param movePtr Pointer to process movements */
|
||||
void moveActor(int32 angleFrom, int32 angleTo, int32 speed, ActorMoveStruct *movePtr) { // ManualRealAngle
|
||||
int32 numOfStepInt;
|
||||
int16 numOfStep;
|
||||
int16 from;
|
||||
int16 to;
|
||||
|
||||
from = angleFrom & 0x3FF;
|
||||
to = angleTo & 0x3FF;
|
||||
|
||||
movePtr->from = from;
|
||||
movePtr->to = to;
|
||||
|
||||
numOfStep = (from - to) << 6;
|
||||
|
||||
if (numOfStep < 0) {
|
||||
numOfStepInt = -numOfStep;
|
||||
} else {
|
||||
numOfStepInt = numOfStep;
|
||||
}
|
||||
|
||||
numOfStepInt >>= 6;
|
||||
|
||||
numOfStepInt *= speed;
|
||||
numOfStepInt >>= 8;
|
||||
|
||||
movePtr->numOfStep = (int16)numOfStepInt;
|
||||
movePtr->timeOfChange = lbaTime;
|
||||
}
|
||||
|
||||
void processActorMovements(int32 actorIdx) {
|
||||
ActorStruct *actor = &sceneActors[actorIdx];
|
||||
|
||||
if (actor->entity == -1)
|
||||
return;
|
||||
|
||||
if (actor->dynamicFlags.bIsFalling) {
|
||||
int16 tempAngle = 0;
|
||||
|
||||
if (actor->controlMode != 1)
|
||||
return;
|
||||
|
||||
if (key & 4)
|
||||
tempAngle = 0x100;
|
||||
|
||||
if (key & 8)
|
||||
tempAngle = -0x100;
|
||||
|
||||
moveActor(actor->angle, actor->angle + tempAngle, actor->speed, &actor->move);
|
||||
|
||||
heroPressedKey = key;
|
||||
} else {
|
||||
int16 tempAngle;
|
||||
|
||||
if (!actor->staticFlags.bIsSpriteActor) {
|
||||
if (actor->controlMode != kManual) {
|
||||
actor->angle = getRealAngle(&actor->move);
|
||||
}
|
||||
}
|
||||
|
||||
switch (actor->controlMode) {
|
||||
case kNoMove:
|
||||
break;
|
||||
case kManual:
|
||||
if (!actorIdx) { // take this out when we want to give manual movements to other characters than Hero
|
||||
heroAction = 0;
|
||||
|
||||
// If press W for action
|
||||
if (skipIntro == 0x11) {
|
||||
heroAction = 1;
|
||||
}
|
||||
|
||||
// Process hero actions
|
||||
switch (heroBehaviour) {
|
||||
case kNormal:
|
||||
if (loopPressedKey & 1) {
|
||||
heroAction = 1;
|
||||
}
|
||||
break;
|
||||
case kAthletic:
|
||||
if (loopPressedKey & 1) {
|
||||
initAnim(kJump, 1, 0, actorIdx);
|
||||
}
|
||||
break;
|
||||
case kAggressive:
|
||||
if (loopPressedKey & 1) {
|
||||
if (autoAgressive) {
|
||||
heroMoved = 1;
|
||||
actor->angle = getRealAngle(&actor->move);
|
||||
if (!(previousLoopPressedKey & 1) || !actor->anim) {
|
||||
int32 aggresiveMode = Rnd(3);
|
||||
|
||||
switch (aggresiveMode) {
|
||||
case 0:
|
||||
initAnim(kKick, 1, 0, actorIdx);
|
||||
break;
|
||||
case 1:
|
||||
initAnim(kRightPunch, 1, 0, actorIdx);
|
||||
break;
|
||||
case 2:
|
||||
initAnim(kLeftPunch, 1, 0, actorIdx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (key & 8) {
|
||||
initAnim(kRightPunch, 1, 0, actorIdx);
|
||||
}
|
||||
|
||||
if (key & 4) {
|
||||
initAnim(kLeftPunch, 1, 0, actorIdx);
|
||||
}
|
||||
|
||||
if (key & 1) {
|
||||
initAnim(kKick, 1, 0, actorIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kDiscrete:
|
||||
if (loopPressedKey & 1) {
|
||||
initAnim(kHide, 0, 255, actorIdx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((loopPressedKey & 8) && !gameFlags[GAMEFLAG_INVENTORY_DISABLED]) {
|
||||
if (usingSabre == 0) { // Use Magic Ball
|
||||
if (gameFlags[GAMEFLAG_HAS_MAGICBALL]) {
|
||||
if (magicBallIdx == -1) {
|
||||
initAnim(kThrowBall, 1, 0, actorIdx);
|
||||
}
|
||||
|
||||
heroMoved = 1;
|
||||
actor->angle = getRealAngle(&actor->move);
|
||||
}
|
||||
} else {
|
||||
if (gameFlags[GAMEFLAG_HAS_SABRE]) {
|
||||
if (actor->body != GAMEFLAG_HAS_SABRE) {
|
||||
initModelActor(GAMEFLAG_HAS_SABRE, actorIdx);
|
||||
}
|
||||
|
||||
initAnim(kSabreAttack, 1, 0, actorIdx);
|
||||
|
||||
heroMoved = 1;
|
||||
actor->angle = getRealAngle(&actor->move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loopPressedKey || heroAction) {
|
||||
|
||||
if (key & 3) { // if continue walking
|
||||
heroMoved = 0; // don't break animation
|
||||
}
|
||||
|
||||
if (key != heroPressedKey || loopPressedKey != heroPressedKey2) {
|
||||
if (heroMoved) {
|
||||
initAnim(kStanding, 0, 255, actorIdx);
|
||||
}
|
||||
}
|
||||
|
||||
heroMoved = 0;
|
||||
|
||||
if (key & 1) { // walk forward
|
||||
if (!currentActorInZone) {
|
||||
initAnim(kForward, 0, 255, actorIdx);
|
||||
}
|
||||
heroMoved = 1;
|
||||
}
|
||||
|
||||
if (key & 2 && !(key & 1)) { // walk backward
|
||||
initAnim(kBackward, 0, 255, actorIdx);
|
||||
heroMoved = 1;
|
||||
}
|
||||
|
||||
if (key & 4) { // turn left
|
||||
heroMoved = 1;
|
||||
if (actor->anim == 0) {
|
||||
initAnim(kTurnLeft, 0, 255, actorIdx);
|
||||
} else {
|
||||
if (!actor->dynamicFlags.bIsRotationByAnim) {
|
||||
actor->angle = getRealAngle(&actor->move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key & 8) { // turn right
|
||||
heroMoved = 1;
|
||||
if (actor->anim == 0) {
|
||||
initAnim(kTurnRight, 0, 255, actorIdx);
|
||||
} else {
|
||||
if (!actor->dynamicFlags.bIsRotationByAnim) {
|
||||
actor->angle = getRealAngle(&actor->move);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tempAngle = 0;
|
||||
|
||||
if (key & 4) {
|
||||
tempAngle = 0x100;
|
||||
}
|
||||
|
||||
if (key & 8) {
|
||||
tempAngle = -0x100;
|
||||
}
|
||||
|
||||
moveActor(actor->angle, actor->angle + tempAngle, actor->speed, &actor->move);
|
||||
|
||||
heroPressedKey = key;
|
||||
heroPressedKey2 = loopPressedKey;
|
||||
|
||||
break;
|
||||
case kFollow: {
|
||||
int32 newAngle = getAngleAndSetTargetActorDistance(actor->X, actor->Z, sceneActors[actor->followedActor].X, sceneActors[actor->followedActor].Z);
|
||||
if (actor->staticFlags.bIsSpriteActor) {
|
||||
actor->angle = newAngle;
|
||||
} else {
|
||||
moveActor(actor->angle, newAngle, actor->speed, &actor->move);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kTrack:
|
||||
if (actor->positionInMoveScript == -1) {
|
||||
actor->positionInMoveScript = 0;
|
||||
}
|
||||
break;
|
||||
case kFollow2: // unused
|
||||
case kTrackAttack: // unused
|
||||
break;
|
||||
case kSameXZ:
|
||||
actor->X = sceneActors[actor->followedActor].X;
|
||||
actor->Z = sceneActors[actor->followedActor].Z;
|
||||
break;
|
||||
case kRandom: {
|
||||
if (!actor->dynamicFlags.bIsRotationByAnim) {
|
||||
if (actor->brickShape & 0x80) {
|
||||
moveActor(actor->angle, (((rand() & 0x100) + (actor->angle - 0x100)) & 0x3FF ), actor->speed, &actor->move);
|
||||
actor->info0 = Rnd(300) + lbaTime + 300;
|
||||
initAnim(0, 0, 255, actorIdx);
|
||||
}
|
||||
|
||||
if (!actor->move.numOfStep) {
|
||||
initAnim(1, 0, 255, actorIdx);
|
||||
if(lbaTime > actor->info0) {
|
||||
moveActor(actor->angle, (((rand() & 0x100) + (actor->angle - 0x100)) & 0x3FF), actor->speed, &actor->move);
|
||||
actor->info0 = Rnd(300) + lbaTime + 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("Unknown Control mode %d\n", actor->controlMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
138
engines/twine/movements.h
Normal file
138
engines/twine/movements.h
Normal file
@ -0,0 +1,138 @@
|
||||
/** @file movements.h
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MOVEMENTS_H
|
||||
#define MOVEMENTS_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "actor.h"
|
||||
|
||||
/** Control mode types */
|
||||
enum ControlMode {
|
||||
kNoMove = 0,
|
||||
kManual = 1,
|
||||
kFollow = 2,
|
||||
kTrack = 3,
|
||||
kFollow2 = 4,
|
||||
kTrackAttack = 5,
|
||||
kSameXZ = 6,
|
||||
kRandom = 7
|
||||
};
|
||||
|
||||
/** Hero moved */
|
||||
int16 heroMoved; // twinsenMove
|
||||
/** Hero Action */
|
||||
int16 heroAction; // action
|
||||
|
||||
/** Process actor X coordinate */
|
||||
int16 processActorX;
|
||||
/** Process actor Y coordinate */
|
||||
int16 processActorY;
|
||||
/** Process actor Z coordinate */
|
||||
int16 processActorZ;
|
||||
|
||||
ActorStruct *processActorPtr; // processActorVar1
|
||||
|
||||
/** Previous process actor X coordinate */
|
||||
int16 previousActorX; // processActorVar2
|
||||
/** Previous process actor Y coordinate */
|
||||
int16 previousActorY; // processActorVar3
|
||||
/** Previous process actor Z coordinate */
|
||||
int16 previousActorZ; // processActorVar4
|
||||
|
||||
int32 targetActorDistance; // DoTrackVar1
|
||||
|
||||
|
||||
/** Get shadow position
|
||||
@param X Shadow X coordinate
|
||||
@param Y Shadow Y coordinate
|
||||
@param Z Shadow Z coordinate */
|
||||
void getShadowPosition(int32 X, int32 Y, int32 Z);
|
||||
|
||||
/** Set actor safe angle
|
||||
@param startAngle start angle
|
||||
@param endAngle end angle
|
||||
@param stepAngle number of steps
|
||||
@param movePtr time pointer to update */
|
||||
void setActorAngleSafe(int16 startAngle, int16 endAngle, int16 stepAngle, ActorMoveStruct * movePtr);
|
||||
|
||||
/** Clear actors safe angle
|
||||
@param actorPtr actor pointer */
|
||||
void clearRealAngle(ActorStruct * actorPtr);
|
||||
|
||||
/** Set actor safe angle
|
||||
@param startAngle start angle
|
||||
@param endAngle end angle
|
||||
@param stepAngle number of steps
|
||||
@param movePtr time pointer to update */
|
||||
void setActorAngle(int16 startAngle, int16 endAngle, int16 stepAngle, ActorMoveStruct * movePtr);
|
||||
|
||||
/** Get actor angle
|
||||
@param x1 Actor 1 X
|
||||
@param z1 Actor 1 Z
|
||||
@param x2 Actor 2 X
|
||||
@param z2 Actor 2 Z */
|
||||
int32 getAngleAndSetTargetActorDistance(int32 x1, int32 z1, int32 x2, int32 z2);
|
||||
|
||||
/** Get actor real angle
|
||||
@param movePtr time pointer to process */
|
||||
int32 getRealAngle(ActorMoveStruct * movePtr);
|
||||
|
||||
/** Get actor step
|
||||
@param movePtr time pointer to process */
|
||||
int32 getRealValue(ActorMoveStruct * movePtr);
|
||||
|
||||
/** Rotate actor with a given angle
|
||||
@param X Actor current X coordinate
|
||||
@param Z Actor current Z coordinate
|
||||
@param angle Actor angle to rotate */
|
||||
void rotateActor(int32 X, int32 Z, int32 angle);
|
||||
|
||||
/** Get distance value in 2D
|
||||
@param x1 Actor 1 X coordinate
|
||||
@param z1 Actor 1 Z coordinate
|
||||
@param x2 Actor 2 X coordinate
|
||||
@param z2 Actor 2 Z coordinate */
|
||||
int32 getDistance2D(int32 x1, int32 z1, int32 x2, int32 z2);
|
||||
|
||||
/** Get distance value in 3D
|
||||
@param x1 Actor 1 X coordinate
|
||||
@param y1 Actor 1 Y coordinate
|
||||
@param z1 Actor 1 Z coordinate
|
||||
@param x2 Actor 2 X coordinate
|
||||
@param y2 Actor 2 Y coordinate
|
||||
@param z2 Actor 2 Z coordinate */
|
||||
int32 getDistance3D(int32 x1, int32 y1, int32 z1, int32 x2, int32 y2, int32 z2);
|
||||
|
||||
/** Move actor around the scene
|
||||
@param angleFrom Current actor angle
|
||||
@param angleTo Angle to rotate
|
||||
@param speed Rotate speed
|
||||
@param movePtr Pointer to process movements */
|
||||
void moveActor(int32 angleFrom, int32 angleTo, int32 speed, ActorMoveStruct *movePtr);
|
||||
|
||||
void processActorMovements(int32 actorIdx);
|
||||
|
||||
#endif
|
253
engines/twine/music.cpp
Normal file
253
engines/twine/music.cpp
Normal file
@ -0,0 +1,253 @@
|
||||
/** @file music.cpp
|
||||
@brief
|
||||
This file contains music playing routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
#ifndef MACOSX
|
||||
#include <SDL/SDL_mixer.h>
|
||||
#else
|
||||
#include <SDL_mixer/SDL_mixer.h>
|
||||
#endif
|
||||
|
||||
#include "music.h"
|
||||
#include "main.h"
|
||||
#include "sdlengine.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "resources.h"
|
||||
#include "xmidi.h"
|
||||
|
||||
/** MP3 music folder */
|
||||
#define MUSIC_FOLDER "music"
|
||||
/** LBA1 default number of tracks */
|
||||
#define NUM_CD_TRACKS 10
|
||||
/** Number of miliseconds to fade music */
|
||||
#define FADE_MS 500
|
||||
|
||||
/** SDL CD variable interface */
|
||||
SDL_CD *cdrom;
|
||||
/** CD drive letter */
|
||||
const int8 *cdname;
|
||||
|
||||
/** SDL_Mixer track variable interface */
|
||||
Mix_Music *current_track;
|
||||
|
||||
/** Auxiliar midi pointer to */
|
||||
uint8 * midiPtr;
|
||||
|
||||
|
||||
/** Music volume
|
||||
@param current volume number */
|
||||
void musicVolume(int32 volume) {
|
||||
// div 2 because LBA use 255 range and SDL_mixer use 128 range
|
||||
Mix_VolumeMusic(volume / 2);
|
||||
}
|
||||
|
||||
/** Fade music in
|
||||
@param loops number of*/
|
||||
void musicFadeIn(int32 loops, int32 ms) {
|
||||
Mix_FadeInMusic(current_track, loops, ms);
|
||||
musicVolume(cfgfile.MusicVolume);
|
||||
}
|
||||
|
||||
/** Fade music out
|
||||
@param ms number of miliseconds to fade*/
|
||||
void musicFadeOut(int32 ms) {
|
||||
while (!Mix_FadeOutMusic(ms) && Mix_PlayingMusic()) {
|
||||
SDL_Delay(100);
|
||||
}
|
||||
Mix_HaltMusic();
|
||||
Mix_RewindMusic();
|
||||
musicVolume(cfgfile.MusicVolume);
|
||||
}
|
||||
|
||||
|
||||
/** Play CD music
|
||||
@param track track number to play */
|
||||
void playTrackMusicCd(int32 track) {
|
||||
if (!cfgfile.UseCD) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cdrom->numtracks == 10) {
|
||||
if (CD_INDRIVE(SDL_CDStatus(cdrom)))
|
||||
SDL_CDPlayTracks(cdrom, track, 0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop CD music */
|
||||
void stopTrackMusicCd() {
|
||||
if (!cfgfile.UseCD) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cdrom != NULL) {
|
||||
SDL_CDStop(cdrom);
|
||||
}
|
||||
}
|
||||
|
||||
/** Generic play music, according with settings it plays CD or MP3 instead
|
||||
@param track track number to play */
|
||||
void playTrackMusic(int32 track) {
|
||||
if (!cfgfile.Sound) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (track == currentMusic)
|
||||
return;
|
||||
currentMusic = track;
|
||||
|
||||
stopMusic();
|
||||
playTrackMusicCd(track);
|
||||
}
|
||||
|
||||
/** Generic stop music according with settings */
|
||||
void stopTrackMusic() {
|
||||
if (!cfgfile.Sound) {
|
||||
return;
|
||||
}
|
||||
|
||||
musicFadeOut(FADE_MS);
|
||||
stopTrackMusicCd();
|
||||
}
|
||||
|
||||
/** Play MIDI music
|
||||
@param midiIdx music index under mini_mi_win.hqr*/
|
||||
void playMidiMusic(int32 midiIdx, int32 loop) {
|
||||
uint8* dos_midi_ptr;
|
||||
int32 midiSize;
|
||||
int8 filename[256];
|
||||
SDL_RWops *rw;
|
||||
|
||||
if (!cfgfile.Sound) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (midiIdx == currentMusic) {
|
||||
return;
|
||||
}
|
||||
|
||||
stopMusic();
|
||||
currentMusic = midiIdx;
|
||||
|
||||
if (cfgfile.MidiType == 0)
|
||||
sprintf(filename, "%s", HQR_MIDI_MI_DOS_FILE);
|
||||
else
|
||||
sprintf(filename, "%s", HQR_MIDI_MI_WIN_FILE);
|
||||
|
||||
if (midiPtr) {
|
||||
musicFadeOut(FADE_MS / 2);
|
||||
stopMidiMusic();
|
||||
}
|
||||
|
||||
midiSize = hqrGetallocEntry(&midiPtr, filename, midiIdx);
|
||||
|
||||
if (cfgfile.Sound == 1 && cfgfile.MidiType == 0) {
|
||||
midiSize = convert_to_midi(midiPtr, midiSize, &dos_midi_ptr);
|
||||
free(midiPtr);
|
||||
midiPtr = dos_midi_ptr;
|
||||
}
|
||||
|
||||
rw = SDL_RWFromMem(midiPtr, midiSize);
|
||||
|
||||
current_track = Mix_LoadMUS_RW(rw);
|
||||
|
||||
musicFadeIn(1, FADE_MS);
|
||||
|
||||
musicVolume(cfgfile.MusicVolume);
|
||||
|
||||
if (Mix_PlayMusic(current_track, loop) == -1)
|
||||
printf("Error while playing music: %d \n", midiIdx);
|
||||
}
|
||||
|
||||
/** Stop MIDI music */
|
||||
void stopMidiMusic() {
|
||||
if (!cfgfile.Sound) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_track != NULL) {
|
||||
Mix_FreeMusic(current_track);
|
||||
current_track = NULL;
|
||||
if (midiPtr != NULL)
|
||||
free(midiPtr);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize CD-Rom */
|
||||
int initCdrom() {
|
||||
int32 numOfCDROM;
|
||||
int32 cdNum;
|
||||
|
||||
if (!cfgfile.Sound) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
numOfCDROM = SDL_CDNumDrives();
|
||||
|
||||
if (cfgfile.Debug)
|
||||
printf("Found %d CDROM devices\n", numOfCDROM);
|
||||
|
||||
if (!numOfCDROM) {
|
||||
fprintf(stderr, "No CDROM devices available\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cdNum = 0; cdNum < numOfCDROM; cdNum++) {
|
||||
cdname = SDL_CDName(cdNum);
|
||||
if (cfgfile.Debug)
|
||||
printf("Testing drive %s\n", cdname);
|
||||
cdrom = SDL_CDOpen(cdNum);
|
||||
if (!cdrom) {
|
||||
if (cfgfile.Debug)
|
||||
fprintf(stderr, "Couldn't open CD drive: %s\n\n", SDL_GetError());
|
||||
} else {
|
||||
SDL_CDStatus(cdrom);
|
||||
if (cdrom->numtracks == NUM_CD_TRACKS) {
|
||||
printf("Assuming that it is LBA cd... %s\n\n", cdname);
|
||||
cdDir = "LBA";
|
||||
cfgfile.UseCD = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// not found the right CD
|
||||
cfgfile.UseCD = 0;
|
||||
SDL_CDClose(cdrom);
|
||||
}
|
||||
|
||||
cdrom = NULL;
|
||||
|
||||
printf("Can't find LBA CD!\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Stop MIDI and Track music */
|
||||
void stopMusic() {
|
||||
stopTrackMusic();
|
||||
stopMidiMusic();
|
||||
}
|
64
engines/twine/music.h
Normal file
64
engines/twine/music.h
Normal file
@ -0,0 +1,64 @@
|
||||
/** @file music.h
|
||||
@brief
|
||||
This file contains music playing routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MUSIC_H
|
||||
#define MUSIC_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/** Track number of the current playing music */
|
||||
int32 currentMusic;
|
||||
|
||||
/** Music volume
|
||||
@param current volume number */
|
||||
void musicVolume(int32 volume);
|
||||
/** Play CD music
|
||||
@param track track number to play */
|
||||
void playTrackMusicCd(int32 track);
|
||||
/** Stop CD music */
|
||||
void stopTrackMusicCd();
|
||||
/** Play MP3 music
|
||||
@param track track number to play */
|
||||
void playTrackMusicMp3(int32 track);
|
||||
/** Stop MP3 music */
|
||||
void stopTrackMusicMp3();
|
||||
/** Generic play music, according with settings it plays CD or high quality sounds instead
|
||||
@param track track number to play*/
|
||||
void playTrackMusic(int32 track);
|
||||
/** Generic stop music according with settings */
|
||||
void stopTrackMusic();
|
||||
/** Play MIDI music
|
||||
@param midiIdx music index under mini_mi_win.hqr*/
|
||||
void playMidiMusic(int32 midiIdx, int32 loop);
|
||||
/** Stop MIDI music */
|
||||
void stopMidiMusic();
|
||||
|
||||
/** Initialize CD-Rom */
|
||||
int32 initCdrom();
|
||||
|
||||
/** Stop MIDI and Track music */
|
||||
void stopMusic();
|
||||
|
||||
#endif
|
861
engines/twine/redraw.cpp
Normal file
861
engines/twine/redraw.cpp
Normal file
@ -0,0 +1,861 @@
|
||||
/** @file redraw.cpp
|
||||
@brief
|
||||
This file contains engine redraw actions routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "redraw.h"
|
||||
#include "sdlengine.h"
|
||||
#include "lbaengine.h"
|
||||
#include "renderer.h"
|
||||
#include "interface.h"
|
||||
#include "screens.h"
|
||||
#include "grid.h"
|
||||
#include "scene.h"
|
||||
#include "actor.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "resources.h"
|
||||
#include "menu.h"
|
||||
#include "animations.h"
|
||||
#include "keyboard.h"
|
||||
#include "movements.h"
|
||||
#include "text.h"
|
||||
#include "collision.h"
|
||||
#include "sound.h"
|
||||
|
||||
#ifdef GAMEMOD
|
||||
#include "debug.scene.h"
|
||||
#endif
|
||||
|
||||
typedef struct RedrawStruct {
|
||||
uint16 left;
|
||||
uint16 top;
|
||||
uint16 right;
|
||||
uint16 bottom;
|
||||
} RedrawStruct;
|
||||
|
||||
RedrawStruct currentRedrawList[300];
|
||||
RedrawStruct nextRedrawList[300];
|
||||
|
||||
typedef struct DrawListStruct {
|
||||
int16 posValue;
|
||||
uint16 index; // field_2
|
||||
uint16 X;
|
||||
uint16 Y;
|
||||
uint16 Z;
|
||||
uint16 field_A;
|
||||
uint16 field_C;
|
||||
uint16 field_E;
|
||||
uint16 field_10;
|
||||
} DrawListStruct;
|
||||
|
||||
/** Draw list array to grab the necessary */
|
||||
DrawListStruct drawList[150];
|
||||
|
||||
int16 overlayRotation = 0;
|
||||
|
||||
/** Add a certain region to the current redraw list array
|
||||
@param left start width to redraw the region
|
||||
@param top start height to redraw the region
|
||||
@param right end width to redraw the region
|
||||
@param bottom end height to redraw the region */
|
||||
void addRedrawCurrentArea(int32 left, int32 top, int32 right, int32 bottom) {
|
||||
int32 area;
|
||||
int32 i = 0;
|
||||
int32 leftValue;
|
||||
int32 rightValue;
|
||||
int32 topValue;
|
||||
int32 bottomValue;
|
||||
|
||||
area = (right - left) * (bottom - top);
|
||||
|
||||
while (i < numOfRedrawBox) {
|
||||
if (currentRedrawList[i].left >= left)
|
||||
leftValue = left;
|
||||
else
|
||||
leftValue = currentRedrawList[i].left;
|
||||
|
||||
if (currentRedrawList[i].right <= right)
|
||||
rightValue = right;
|
||||
else
|
||||
rightValue = currentRedrawList[i].right;
|
||||
|
||||
if (currentRedrawList[i].top >= top)
|
||||
topValue = top;
|
||||
else
|
||||
topValue = currentRedrawList[i].top;
|
||||
|
||||
if (currentRedrawList[i].bottom <= bottom)
|
||||
bottomValue = bottom;
|
||||
else
|
||||
bottomValue = currentRedrawList[i].bottom;
|
||||
|
||||
if ((rightValue - leftValue) *(bottomValue - topValue) < ((currentRedrawList[i].bottom - currentRedrawList[i].top) *(currentRedrawList[i].right - currentRedrawList[i].left) + area)) {
|
||||
currentRedrawList[i].left = leftValue;
|
||||
currentRedrawList[i].top = topValue;
|
||||
currentRedrawList[i].right = rightValue;
|
||||
currentRedrawList[i].bottom = bottomValue;
|
||||
|
||||
if (currentRedrawList[i].bottom >= SCREEN_WIDTH)
|
||||
currentRedrawList[i].bottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
return;
|
||||
}
|
||||
|
||||
i++;
|
||||
};
|
||||
|
||||
currentRedrawList[i].left = left;
|
||||
currentRedrawList[i].top = top;
|
||||
currentRedrawList[i].right = right;
|
||||
currentRedrawList[i].bottom = bottom;
|
||||
|
||||
if (currentRedrawList[i].bottom >= SCREEN_WIDTH)
|
||||
currentRedrawList[i].bottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
|
||||
numOfRedrawBox++;
|
||||
}
|
||||
|
||||
/** Add a certain region to redraw list array
|
||||
@param left start width to redraw the region
|
||||
@param top start height to redraw the region
|
||||
@param right end width to redraw the region
|
||||
@param bottom end height to redraw the region */
|
||||
void addRedrawArea(int32 left, int32 top, int32 right, int32 bottom) {
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
if (top < 0)
|
||||
top = 0;
|
||||
if (right >= SCREEN_WIDTH)
|
||||
right = SCREEN_TEXTLIMIT_RIGHT;
|
||||
if (bottom >= SCREEN_HEIGHT)
|
||||
bottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
|
||||
if (left > right || top > bottom)
|
||||
return;
|
||||
|
||||
nextRedrawList[currNumOfRedrawBox].left = left;
|
||||
nextRedrawList[currNumOfRedrawBox].top = top;
|
||||
nextRedrawList[currNumOfRedrawBox].right = right;
|
||||
nextRedrawList[currNumOfRedrawBox].bottom = bottom;
|
||||
|
||||
currNumOfRedrawBox++;
|
||||
|
||||
addRedrawCurrentArea(left, top, right, bottom);
|
||||
}
|
||||
|
||||
/** Move next regions to the current redraw list */
|
||||
void moveNextAreas() {
|
||||
int32 i;
|
||||
|
||||
numOfRedrawBox = 0;
|
||||
|
||||
for (i = 0; i < currNumOfRedrawBox; i++) {
|
||||
addRedrawCurrentArea(nextRedrawList[i].left, nextRedrawList[i].top, nextRedrawList[i].right, nextRedrawList[i].bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/** Flip currentRedrawList regions in the screen
|
||||
|
||||
This only updates small areas in the screen so few CPU processor is used */
|
||||
void flipRedrawAreas() {
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < numOfRedrawBox; i++) { // redraw areas on screen
|
||||
copyBlockPhys(currentRedrawList[i].left, currentRedrawList[i].top, currentRedrawList[i].right, currentRedrawList[i].bottom);
|
||||
}
|
||||
|
||||
numOfRedrawBox = 0;
|
||||
|
||||
for (i = 0; i < currNumOfRedrawBox; i++) { //setup the redraw areas for next display
|
||||
addRedrawCurrentArea(nextRedrawList[i].left, nextRedrawList[i].top, nextRedrawList[i].right, nextRedrawList[i].bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/** Blit/Update all screen regions in the currentRedrawList */
|
||||
void blitBackgroundAreas() {
|
||||
int32 i;
|
||||
RedrawStruct* currentArea;
|
||||
currentArea = currentRedrawList;
|
||||
|
||||
for (i = 0; i < numOfRedrawBox; i++) {
|
||||
blitBox(currentArea->left, currentArea->top, currentArea->right, currentArea->bottom, (int8 *) workVideoBuffer, currentArea->left, currentArea->top, (int8 *) frontVideoBuffer);
|
||||
currentArea++;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sort drawing list struct ordered as the first objects appear in the top left corner of the screen
|
||||
@param list drawing list variable which contains information of the drawing objects
|
||||
@param listSize number of drawing objects in the list */
|
||||
void sortDrawingList(DrawListStruct *list, int32 listSize) {
|
||||
int32 i;
|
||||
int32 j;
|
||||
|
||||
DrawListStruct tempStruct;
|
||||
|
||||
for (i = 0; i < listSize - 1; i++) {
|
||||
for (j = 0; j < listSize - 1 - i; j++) {
|
||||
if (list[j+1].posValue < list[j].posValue) {
|
||||
memcpy(&tempStruct, &list[j+1], sizeof(DrawListStruct));
|
||||
memcpy(&list[j+1], &list[j], sizeof(DrawListStruct));
|
||||
memcpy(&list[j], &tempStruct, sizeof(DrawListStruct));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** */
|
||||
void addOverlay(int16 type, int16 info0, int16 X, int16 Y, int16 info1, int16 posType, int16 lifeTime) {
|
||||
int32 i;
|
||||
for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
|
||||
OverlayListStruct *overlay = &overlayList[i];
|
||||
if (overlay->info0 == -1) {
|
||||
overlay->type = type;
|
||||
overlay->info0 = info0;
|
||||
overlay->X = X;
|
||||
overlay->Y = Y;
|
||||
overlay->info1 = info1;
|
||||
overlay->posType = posType;
|
||||
overlay->lifeTime = lbaTime + lifeTime * 50;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** */
|
||||
void updateOverlayTypePosition(int16 X1, int16 Y1, int16 X2, int16 Y2) {
|
||||
int32 i;
|
||||
int16 newX, newY;
|
||||
|
||||
newX = X2 - X1;
|
||||
newY = Y2 - Y1;
|
||||
|
||||
for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
|
||||
OverlayListStruct *overlay = &overlayList[i];
|
||||
if (overlay->type == koFollowActor) {
|
||||
overlay->X = newX;
|
||||
overlay->Y = newY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** This is responsible for the entire game screen redraw
|
||||
@param bgRedraw true if we want to redraw background grid, false if we want to update certain screen areas */
|
||||
void redrawEngineActions(int32 bgRedraw) { // fullRedraw
|
||||
int16 tmpProjPosX;
|
||||
int16 tmpProjPosY;
|
||||
int32 i;
|
||||
int32 tmpVal;
|
||||
int32 modelActorPos; // arg_1A
|
||||
int32 spriteActorPos; // top6
|
||||
int32 shadowActorPos; // top2
|
||||
int32 drawListPos; // a12
|
||||
ActorStruct *actor;
|
||||
|
||||
tmpProjPosX = projPosXScreen;
|
||||
tmpProjPosY = projPosYScreen;
|
||||
|
||||
resetClip();
|
||||
|
||||
if (bgRedraw) {
|
||||
freezeTime();
|
||||
if (needChangeScene != -1 && needChangeScene != -2)
|
||||
fadeOut(paletteRGBA);
|
||||
clearScreen();
|
||||
redrawGrid();
|
||||
updateOverlayTypePosition(tmpProjPosX, tmpProjPosY, projPosXScreen, projPosYScreen);
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
|
||||
if (needChangeScene != -1 && needChangeScene != -2) {
|
||||
fadeIn(paletteRGBA);
|
||||
setPalette(paletteRGBA);
|
||||
}
|
||||
} else {
|
||||
blitBackgroundAreas();
|
||||
}
|
||||
|
||||
// first loop
|
||||
|
||||
modelActorPos = 0;
|
||||
drawListPos = 0;
|
||||
spriteActorPos = 0x1000;
|
||||
shadowActorPos = 0x0C00;
|
||||
|
||||
// Process actors drawing list
|
||||
for (modelActorPos = 0; modelActorPos < sceneNumActors; modelActorPos++, spriteActorPos++, shadowActorPos++) {
|
||||
actor = &sceneActors[modelActorPos];
|
||||
actor->dynamicFlags.bIsVisible = 0; // reset visible state
|
||||
|
||||
if ((useCellingGrid == -1) || actor->Y <= (*(int16 *)(cellingGridIdx*24 + (int8 *)sceneZones + 8))) {
|
||||
// no redraw required
|
||||
if (actor->staticFlags.bIsBackgrounded && bgRedraw == 0) {
|
||||
// get actor position on screen
|
||||
projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
|
||||
|
||||
// check if actor is visible on screen, otherwise don't display it
|
||||
if (projPosX > -50 && projPosX < 680 && projPosY > -30 && projPosY < 580) {
|
||||
actor->dynamicFlags.bIsVisible = 1;
|
||||
}
|
||||
} else {
|
||||
// if the actor isn't set as hidden
|
||||
if (actor->entity != -1 && !(actor->staticFlags.bIsHidden)) {
|
||||
// get actor position on screen
|
||||
projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
|
||||
|
||||
if ((actor->staticFlags.bUsesClipping && projPosX > -112 && projPosX < 752 && projPosY > -50 && projPosY < 651) ||
|
||||
((!actor->staticFlags.bUsesClipping) && projPosX > -50 && projPosX < 680 && projPosY > -30 && projPosY < 580)) {
|
||||
|
||||
tmpVal = actor->Z + actor->X - cameraX - cameraZ;
|
||||
|
||||
// if actor is above another actor
|
||||
if (actor->standOn != -1) {
|
||||
tmpVal = sceneActors[actor->standOn].X - cameraX + sceneActors[actor->standOn].Z - cameraZ + 2;
|
||||
}
|
||||
|
||||
if (actor->staticFlags.bIsSpriteActor) {
|
||||
drawList[drawListPos].index = spriteActorPos; // > 0x1000
|
||||
if (actor->staticFlags.bUsesClipping) {
|
||||
tmpVal = actor->lastX - cameraX + actor->lastZ - cameraZ;
|
||||
}
|
||||
} else {
|
||||
drawList[drawListPos].index = modelActorPos;
|
||||
}
|
||||
|
||||
drawList[drawListPos].posValue = tmpVal;
|
||||
|
||||
drawListPos++;
|
||||
|
||||
// if use shadows
|
||||
if (cfgfile.ShadowMode != 0 && !(actor->staticFlags.bDoesntCastShadow)) {
|
||||
if (actor->standOn != -1) {
|
||||
shadowX = actor->X;
|
||||
shadowY = actor->Y - 1;
|
||||
shadowZ = actor->Z;
|
||||
} else {
|
||||
getShadowPosition(actor->X, actor->Y, actor->Z);
|
||||
}
|
||||
|
||||
tmpVal--;
|
||||
drawList[drawListPos].posValue = tmpVal; // save the shadow entry in the drawList
|
||||
drawList[drawListPos].index = 0xC00; // shadowActorPos
|
||||
drawList[drawListPos].X = shadowX;
|
||||
drawList[drawListPos].Y = shadowY;
|
||||
drawList[drawListPos].Z = shadowZ;
|
||||
drawList[drawListPos].field_A = 2;
|
||||
drawListPos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// second loop
|
||||
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
|
||||
ExtraListStruct *extra = &extraList[i];
|
||||
if (extra->info0 != -1) {
|
||||
if (extra->type & 0x400) {
|
||||
if (lbaTime - extra->lifeTime > 35) {
|
||||
extra->lifeTime = lbaTime;
|
||||
extra->type &= 0xFBFF;
|
||||
// FIXME make constant for sample index
|
||||
playSample(11, 0x1000, 1, extra->X, extra->Y, extra->Z, -1);
|
||||
}
|
||||
} else {
|
||||
if ((extra->type & 1) || (extra->type & 0x40) || (extra->actorIdx + extra->lifeTime - 150 < lbaTime) || (!((lbaTime + extra->lifeTime) & 8))) {
|
||||
projectPositionOnScreen(extra->X - cameraX, extra->Y - cameraY, extra->Z - cameraZ);
|
||||
|
||||
if (projPosX > -50 && projPosX < 680 && projPosY > -30 && projPosY < 580) {
|
||||
drawList[drawListPos].posValue = extra->X - cameraX + extra->Z - cameraZ;
|
||||
drawList[drawListPos].index = 0x1800 + i;
|
||||
drawListPos++;
|
||||
|
||||
if (cfgfile.ShadowMode == 2 && !(extra->info0 & 0x8000)) {
|
||||
getShadowPosition(extra->X, extra->Y, extra->Z);
|
||||
|
||||
drawList[drawListPos].posValue = extra->X - cameraX + extra->Z - cameraZ - 1;
|
||||
drawList[drawListPos].index = 0xC00;
|
||||
drawList[drawListPos].X = shadowX;
|
||||
drawList[drawListPos].Y = shadowY;
|
||||
drawList[drawListPos].Z = shadowZ;
|
||||
drawList[drawListPos].field_A = 0;
|
||||
drawListPos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sortDrawingList(drawList, drawListPos);
|
||||
|
||||
currNumOfRedrawBox = 0;
|
||||
// if has something to draw
|
||||
if (drawListPos > 0) {
|
||||
int32 pos = 0;
|
||||
uint32 flags;
|
||||
int32 actorIdx;
|
||||
ActorStruct *actor;
|
||||
|
||||
do {
|
||||
actorIdx = drawList[pos].index & 0x3FF;
|
||||
actor = &sceneActors[actorIdx];
|
||||
flags = ((uint32) drawList[pos].index) & 0xFC00;
|
||||
|
||||
// Drawing actors
|
||||
if (flags < 0xC00) {
|
||||
if (!flags) {
|
||||
setModelAnimation(actor->animPosition, animTable[actor->previousAnimIdx], bodyTable[actor->entity], &actor->animTimerData);
|
||||
|
||||
if (!renderIsoModel(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ, 0, actor->angle, 0, bodyTable[actor->entity])) {
|
||||
if (renderLeft < 0)
|
||||
renderLeft = SCREEN_TEXTLIMIT_LEFT;
|
||||
|
||||
if (renderTop < 0)
|
||||
renderTop = SCREEN_TEXTLIMIT_TOP;
|
||||
|
||||
if (renderRight >= SCREEN_WIDTH)
|
||||
renderRight = SCREEN_TEXTLIMIT_RIGHT;
|
||||
|
||||
if (renderBottom >= SCREEN_HEIGHT)
|
||||
renderBottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
int32 tempX;
|
||||
int32 tempY;
|
||||
int32 tempZ;
|
||||
|
||||
actor->dynamicFlags.bIsVisible = 1;
|
||||
|
||||
tempX = (actor->X + 0x100) >> 9;
|
||||
tempY = actor->Y >> 8;
|
||||
|
||||
if (actor->brickShape & 0x7F)
|
||||
tempY++;
|
||||
|
||||
tempZ = (actor->Z + 0x100) >> 9;
|
||||
|
||||
drawOverModelActor(tempX, tempY, tempZ);
|
||||
|
||||
if(cropBottomScreen) {
|
||||
renderBottom = textWindowBottom = cropBottomScreen + 10;
|
||||
}
|
||||
|
||||
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
|
||||
|
||||
if (actor->staticFlags.bIsBackgrounded && bgRedraw == 1) {
|
||||
blitBox(textWindowLeft, textWindowTop, renderRight, renderBottom, (int8 *) frontVideoBuffer, textWindowLeft, textWindowTop, (int8 *) workVideoBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Drawing shadows
|
||||
else if (flags == 0xC00 && !cropBottomScreen) {
|
||||
int32 spriteWidth, spriteHeight, tmpX, tmpY, tmpZ;
|
||||
DrawListStruct shadow = drawList[pos];
|
||||
|
||||
// get actor position on screen
|
||||
projectPositionOnScreen(shadow.X - cameraX, shadow.Y - cameraY, shadow.Z - cameraZ);
|
||||
|
||||
getSpriteSize(shadow.field_A, &spriteWidth, &spriteHeight, spriteShadowPtr);
|
||||
|
||||
// calculate sprite size and position on screen
|
||||
renderLeft = projPosX - (spriteWidth / 2);
|
||||
renderTop = projPosY - (spriteHeight / 2);
|
||||
renderRight = projPosX + (spriteWidth / 2);
|
||||
renderBottom = projPosY + (spriteHeight / 2);
|
||||
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
drawSprite(shadow.field_A, renderLeft, renderTop, spriteShadowPtr);
|
||||
}
|
||||
|
||||
tmpX = (shadow.X + 0x100) >> 9;
|
||||
tmpY = shadow.Y >> 8;
|
||||
tmpZ = (shadow.Z + 0x100) >> 9;
|
||||
|
||||
drawOverModelActor(tmpX, tmpY, tmpZ);
|
||||
|
||||
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
|
||||
|
||||
// show clipping area
|
||||
//drawBox(renderLeft, renderTop, renderRight, renderBottom);
|
||||
}
|
||||
// Drawing unknown
|
||||
else if (flags < 0x1000) {
|
||||
// TODO reverse this part of the code
|
||||
}
|
||||
// Drawing sprite actors
|
||||
else if (flags == 0x1000) {
|
||||
int32 spriteWidth, spriteHeight;
|
||||
uint8 *spritePtr = spriteTable[actor->entity];
|
||||
|
||||
// get actor position on screen
|
||||
projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
|
||||
|
||||
getSpriteSize(0, &spriteWidth, &spriteHeight, spritePtr);
|
||||
|
||||
// calculate sprite position on screen
|
||||
renderLeft = projPosX + *((int16 *)(spriteBoundingBoxPtr + (actor->entity * 16)));
|
||||
renderTop = projPosY + *((int16 *)(spriteBoundingBoxPtr + (actor->entity * 16) + 2));
|
||||
renderRight = renderLeft + spriteWidth;
|
||||
renderBottom = renderTop + spriteHeight;
|
||||
|
||||
if (actor->staticFlags.bUsesClipping) {
|
||||
setClip(projPosXScreen + actor->info0, projPosYScreen + actor->info1, projPosXScreen + actor->info2, projPosYScreen + actor->info3);
|
||||
} else {
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
}
|
||||
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
drawSprite(0, renderLeft, renderTop, spritePtr);
|
||||
|
||||
actor->dynamicFlags.bIsVisible = 1;
|
||||
|
||||
if (actor->staticFlags.bUsesClipping) {
|
||||
drawOverSpriteActor((actor->lastX + 0x100) >> 9, actor->lastY >> 8, (actor->lastZ + 0x100) >> 9);
|
||||
} else {
|
||||
int32 tmpX, tmpY, tmpZ;
|
||||
|
||||
tmpX = (actor->X + actor->boudingBox.X.topRight + 0x100) >> 9;
|
||||
tmpY = actor->Y >> 8;
|
||||
if (actor->brickShape & 0x7F) {
|
||||
tmpY++;
|
||||
}
|
||||
tmpZ = (actor->Z + actor->boudingBox.Z.topRight + 0x100) >> 9;
|
||||
|
||||
drawOverSpriteActor(tmpX, tmpY, tmpZ);
|
||||
}
|
||||
|
||||
addRedrawArea(textWindowLeft, textWindowTop, textWindowRight, textWindowBottom);
|
||||
|
||||
if (actor->staticFlags.bIsBackgrounded && bgRedraw == 1) {
|
||||
blitBox(textWindowLeft, textWindowTop, textWindowRight, textWindowBottom, (int8 *) frontVideoBuffer, textWindowLeft, textWindowTop, (int8 *) workVideoBuffer);
|
||||
}
|
||||
|
||||
// show clipping area
|
||||
//drawBox(renderLeft, renderTop, renderRight, renderBottom);
|
||||
}
|
||||
}
|
||||
// Drawing extras
|
||||
else if (flags == 0x1800) {
|
||||
ExtraListStruct *extra = &extraList[actorIdx];
|
||||
|
||||
projectPositionOnScreen(extra->X - cameraX, extra->Y - cameraY, extra->Z - cameraZ);
|
||||
|
||||
if (extra->info0 & 0x8000) {
|
||||
drawExtraSpecial(actorIdx, projPosX, projPosY);
|
||||
} else {
|
||||
int32 spriteWidth, spriteHeight;
|
||||
|
||||
getSpriteSize(0, &spriteWidth, &spriteHeight, spriteTable[extra->info0]);
|
||||
|
||||
// calculate sprite position on screen
|
||||
renderLeft = projPosX + *(int16 *)(spriteBoundingBoxPtr + extra->info0 * 16);
|
||||
renderTop = projPosY + *(int16 *)(spriteBoundingBoxPtr + extra->info0 * 16 + 2);
|
||||
renderRight = renderLeft + spriteWidth;
|
||||
renderBottom = renderTop + spriteHeight;
|
||||
|
||||
drawSprite(0, renderLeft, renderTop, spriteTable[extra->info0]);
|
||||
}
|
||||
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
int32 tmpX, tmpY, tmpZ;
|
||||
|
||||
tmpX = (drawList[pos].X + 0x100) >> 9;
|
||||
tmpY = drawList[pos].Y >> 8;
|
||||
tmpZ = (drawList[pos].Z + 0x100) >> 9;
|
||||
|
||||
drawOverModelActor(tmpX, tmpY, tmpZ);
|
||||
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
|
||||
|
||||
// show clipping area
|
||||
//drawBox(renderLeft, renderTop, renderRight, renderBottom);
|
||||
}
|
||||
}
|
||||
|
||||
resetClip();
|
||||
pos++;
|
||||
} while (pos < drawListPos);
|
||||
}
|
||||
|
||||
#ifdef GAMEMOD
|
||||
displayZones(skipIntro);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
|
||||
OverlayListStruct *overlay = &overlayList[i];
|
||||
if (overlay->info0 != -1) {
|
||||
// process position overlay
|
||||
switch(overlay->posType) {
|
||||
case koNormal:
|
||||
if (lbaTime >= overlay->lifeTime) {
|
||||
overlay->info0 = -1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case koFollowActor: {
|
||||
ActorStruct *actor = &sceneActors[overlay->info1];
|
||||
|
||||
projectPositionOnScreen(actor->X - cameraX, actor->Y + actor->boudingBox.Y.topRight - cameraY, actor->Z - cameraZ);
|
||||
|
||||
overlay->X = projPosX;
|
||||
overlay->Y = projPosY;
|
||||
|
||||
if (lbaTime >= overlay->lifeTime) {
|
||||
overlay->info0 = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// process overlay type
|
||||
switch(overlay->type) {
|
||||
case koSprite: {
|
||||
int16 offsetX, offsetY;
|
||||
int32 spriteWidth, spriteHeight;
|
||||
uint8 *spritePtr = spriteTable[overlay->info0];
|
||||
|
||||
getSpriteSize(0, &spriteWidth, &spriteHeight, spritePtr);
|
||||
|
||||
offsetX = *((int16 *)(spriteBoundingBoxPtr + (overlay->info0 * 16)));
|
||||
offsetY = *((int16 *)(spriteBoundingBoxPtr + (overlay->info0 * 16) + 2));
|
||||
|
||||
renderLeft = offsetX + overlay->X;
|
||||
renderTop = offsetY + overlay->Y;
|
||||
renderRight = renderLeft + spriteWidth;
|
||||
renderBottom = renderTop + spriteHeight;
|
||||
|
||||
drawSprite(0, renderLeft, renderTop, spritePtr);
|
||||
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case koNumber: {
|
||||
int32 textLength, textHeight;
|
||||
int8 text[10];
|
||||
sprintf(text, "%d", overlay->info0);
|
||||
|
||||
textLength = getTextSize(text);
|
||||
textHeight = 48;
|
||||
|
||||
renderLeft = overlay->X - (textLength/2);
|
||||
renderTop = overlay->Y - 24;
|
||||
renderRight = overlay->X + (textLength/2);
|
||||
renderBottom = overlay->Y + textHeight;
|
||||
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
setFontColor(overlay->info1);
|
||||
|
||||
drawText(renderLeft, renderTop, text);
|
||||
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case koNumberRange: {
|
||||
int32 textLength, textHeight, range;
|
||||
int8 text[10];
|
||||
|
||||
range = getAverageValue(overlay->info1, overlay->info0, 100, overlay->lifeTime - lbaTime - 50);
|
||||
|
||||
sprintf(text, "%d", range);
|
||||
|
||||
textLength = getTextSize(text);
|
||||
textHeight = 48;
|
||||
|
||||
renderLeft = overlay->X - (textLength/2);
|
||||
renderTop = overlay->Y - 24;
|
||||
renderRight = overlay->X + (textLength/2);
|
||||
renderBottom = overlay->Y + textHeight;
|
||||
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
setFontColor(155);
|
||||
|
||||
drawText(renderLeft, renderTop, text);
|
||||
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case koInventoryItem: {
|
||||
int32 item = overlay->info0;
|
||||
|
||||
drawSplittedBox(10, 10, 69, 69, 0);
|
||||
setClip(10, 10, 69, 69);
|
||||
|
||||
prepareIsoModel(inventoryTable[item]);
|
||||
setCameraPosition(40, 40, 128, 200, 200);
|
||||
setCameraAngle(0, 0, 0, 60, 0, 0, 16000);
|
||||
|
||||
overlayRotation += 1; // overlayRotation += 8;
|
||||
|
||||
renderIsoModel(0, 0, 0, 0, overlayRotation, 0, inventoryTable[item]);
|
||||
drawBox(10, 10, 69, 69);
|
||||
addRedrawArea(10, 10, 69, 69);
|
||||
initEngineProjections();
|
||||
}
|
||||
break;
|
||||
case koText: {
|
||||
int32 textLength, textHeight;
|
||||
int8 text[256];
|
||||
|
||||
getMenuText(overlay->info0, text);
|
||||
|
||||
textLength = getTextSize(text);
|
||||
textHeight = 48;
|
||||
|
||||
renderLeft = overlay->X - (textLength/2);
|
||||
renderTop = overlay->Y - 24;
|
||||
renderRight = overlay->X + (textLength/2);
|
||||
renderBottom = overlay->Y + textHeight;
|
||||
|
||||
if(renderLeft < 0) {
|
||||
renderLeft = 0;
|
||||
}
|
||||
|
||||
if(renderTop < 0) {
|
||||
renderTop = 0;
|
||||
}
|
||||
|
||||
if(renderRight > SCREEN_TEXTLIMIT_RIGHT) {
|
||||
renderRight = SCREEN_TEXTLIMIT_RIGHT;
|
||||
}
|
||||
|
||||
if(renderBottom > SCREEN_TEXTLIMIT_BOTTOM) {
|
||||
renderBottom = SCREEN_TEXTLIMIT_BOTTOM;
|
||||
}
|
||||
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
setFontColor(sceneActors[overlay->info1].talkColor);
|
||||
|
||||
drawText(renderLeft, renderTop, text);
|
||||
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetClip();
|
||||
|
||||
// make celling grid fade
|
||||
// need to be here to fade after drawing all actors in scene
|
||||
if (needChangeScene == -2) {
|
||||
crossFade(frontVideoBuffer, paletteRGBA);
|
||||
needChangeScene = -1;
|
||||
}
|
||||
|
||||
if (bgRedraw) {
|
||||
flip();
|
||||
moveNextAreas();
|
||||
unfreezeTime();
|
||||
} else {
|
||||
flipRedrawAreas();
|
||||
}
|
||||
|
||||
if (lockPalette) {
|
||||
if (useAlternatePalette) {
|
||||
fadeToPal(paletteRGBA);
|
||||
} else {
|
||||
fadeToPal(mainPaletteRGBA);
|
||||
}
|
||||
lockPalette = 0;
|
||||
}
|
||||
|
||||
if (zoomScreen) {
|
||||
//zoomScreenScale();
|
||||
}
|
||||
}
|
||||
|
||||
void drawBubble(int32 actorIdx) {
|
||||
int32 spriteWidth, spriteHeight;
|
||||
uint8 *spritePtr;
|
||||
ActorStruct *actor = &sceneActors[actorIdx];
|
||||
|
||||
// get actor position on screen
|
||||
projectPositionOnScreen(actor->X - cameraX, actor->Y + actor->boudingBox.Y.topRight - cameraY, actor->Z - cameraZ);
|
||||
|
||||
if (actorIdx != bubbleActor) {
|
||||
bubbleSpriteIndex = bubbleSpriteIndex ^ 1;
|
||||
bubbleActor = actorIdx;
|
||||
}
|
||||
|
||||
spritePtr = spriteTable[bubbleSpriteIndex];
|
||||
getSpriteSize(0, &spriteWidth, &spriteHeight, spritePtr);
|
||||
|
||||
// calculate sprite position on screen
|
||||
if (bubbleSpriteIndex == SPRITEHQR_DIAG_BUBBLE_RIGHT) {
|
||||
renderLeft = projPosX + 10;
|
||||
} else {
|
||||
renderLeft = projPosX - 10 - spriteWidth;
|
||||
}
|
||||
renderTop = projPosY - 20;
|
||||
renderRight = spriteWidth + renderLeft - 1;
|
||||
renderBottom = spriteHeight + renderTop - 1;
|
||||
|
||||
setClip(renderLeft, renderTop, renderRight, renderBottom);
|
||||
|
||||
drawSprite(0, renderLeft, renderTop, spritePtr);
|
||||
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
|
||||
copyBlockPhys(renderLeft, renderTop, renderRight, renderBottom);
|
||||
}
|
||||
|
||||
resetClip();
|
||||
}
|
||||
|
||||
void zoomScreenScale() {
|
||||
int h, w;
|
||||
uint8 * dest;
|
||||
uint8 * zoomWorkVideoBuffer = (uint8 *) malloc((SCREEN_WIDTH * SCREEN_HEIGHT) * sizeof(uint8));
|
||||
memcpy(zoomWorkVideoBuffer, workVideoBuffer, SCREEN_WIDTH*SCREEN_HEIGHT);
|
||||
|
||||
dest = workVideoBuffer;
|
||||
|
||||
for (h = 0; h < SCREEN_HEIGHT; h++) {
|
||||
for (w = 0; w < SCREEN_WIDTH; w++) {
|
||||
*dest++ = *zoomWorkVideoBuffer;
|
||||
*dest++ = *zoomWorkVideoBuffer++;
|
||||
}
|
||||
//memcpy(dest, dest - SCREEN_WIDTH, SCREEN_WIDTH);
|
||||
//dest += SCREEN_WIDTH;
|
||||
}
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
//free(zoomWorkVideoBuffer);
|
||||
}
|
108
engines/twine/redraw.h
Normal file
108
engines/twine/redraw.h
Normal file
@ -0,0 +1,108 @@
|
||||
/** @file redraw.h
|
||||
@brief
|
||||
This file contains engine redraw actions routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef REDRAW_H
|
||||
#define REDRAW_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
#define OVERLAY_MAX_ENTRIES 10
|
||||
|
||||
/** Auxiliar object render left position on screen */
|
||||
int32 renderLeft;
|
||||
/** Auxiliar object render right position on screen */
|
||||
int32 renderRight;
|
||||
/** Auxiliar object render top position on screen */
|
||||
int32 renderTop;
|
||||
/** Auxiliar object render bottom position on screen */
|
||||
int32 renderBottom;
|
||||
|
||||
int16 drawInGameTransBox;
|
||||
|
||||
/** Request background redraw */
|
||||
int16 reqBgRedraw;
|
||||
|
||||
/** Current number of redraw regions in the screen */
|
||||
int32 currNumOfRedrawBox; // fullRedrawVar8
|
||||
/** Number of redraw regions in the screen */
|
||||
int32 numOfRedrawBox;
|
||||
|
||||
/** Save last actor that bubble dialog icon */
|
||||
int32 bubbleActor;
|
||||
int32 bubbleSpriteIndex;
|
||||
|
||||
enum OverlayType {
|
||||
koSprite = 0,
|
||||
koNumber = 1,
|
||||
koNumberRange = 2,
|
||||
koInventoryItem = 3,
|
||||
koText = 4
|
||||
};
|
||||
|
||||
enum OverlayPosType {
|
||||
koNormal = 0,
|
||||
koFollowActor = 1
|
||||
};
|
||||
|
||||
/** Overlay list structure */
|
||||
typedef struct OverlayListStruct {
|
||||
int16 type;
|
||||
int16 info0; // sprite/3d model entry | number | number range
|
||||
int16 X;
|
||||
int16 Y;
|
||||
int16 info1; // followed actor | total coins
|
||||
int16 posType;
|
||||
int16 lifeTime;
|
||||
} OverlayListStruct;
|
||||
|
||||
OverlayListStruct overlayList[OVERLAY_MAX_ENTRIES];
|
||||
|
||||
void addOverlay(int16 type, int16 info0, int16 X, int16 Y, int16 info1, int16 posType, int16 lifeTime);
|
||||
|
||||
/** Add a certain region to redraw list array
|
||||
@param left start width to redraw the region
|
||||
@param top start height to redraw the region
|
||||
@param right end width to redraw the region
|
||||
@param bottom end height to redraw the region */
|
||||
void addRedrawArea(int32 left, int32 top, int32 right, int32 bottom);
|
||||
|
||||
/** Flip currentRedrawList regions in the screen
|
||||
|
||||
This only updates small areas in the screen so few CPU processor is used */
|
||||
void flipRedrawAreas();
|
||||
|
||||
/** Blit/Update all screen regions in the currentRedrawList */
|
||||
void blitBackgroundAreas();
|
||||
|
||||
/** This is responsible for the entire game screen redraw
|
||||
@param bgRedraw true if we want to redraw background grid, false if we want to update certain screen areas */
|
||||
void redrawEngineActions(int32 bgRedraw);
|
||||
|
||||
/** Draw dialogue sprite image */
|
||||
void drawBubble(int32 actorIdx);
|
||||
|
||||
void zoomScreenScale();
|
||||
|
||||
#endif
|
2024
engines/twine/renderer.cpp
Normal file
2024
engines/twine/renderer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
78
engines/twine/renderer.h
Normal file
78
engines/twine/renderer.h
Normal file
@ -0,0 +1,78 @@
|
||||
/** @file renderer.h
|
||||
@brief
|
||||
This file contains 3d models render routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef RENDERER_H
|
||||
#define RENDERER_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
int32 isUsingOrhoProjection;
|
||||
|
||||
int16 projPosXScreen; // fullRedrawVar1
|
||||
int16 projPosYScreen; // fullRedrawVar2
|
||||
int16 projPosZScreen; // fullRedrawVar3
|
||||
int16 projPosX;
|
||||
int16 projPosY;
|
||||
int16 projPosZ;
|
||||
|
||||
int32 orthoProjX; // setSomethingVar1
|
||||
int32 orthoProjY; // setSomethingVar2
|
||||
int32 orthoProjZ; // setSomethingVar2
|
||||
|
||||
int32 destX;
|
||||
int32 destY;
|
||||
int32 destZ;
|
||||
|
||||
int16 *shadeAngleTab3; // tab3
|
||||
|
||||
|
||||
int16 polyRenderType; //FillVertic_AType;
|
||||
int32 numOfVertex;
|
||||
int16 vertexCoordinates[193];
|
||||
int16 *pRenderV1;
|
||||
|
||||
void setLightVector(int32 angleX, int32 angleY, int32 angleZ);
|
||||
|
||||
int32 computePolygons();
|
||||
void renderPolygons(int32 ecx, int32 edi);
|
||||
|
||||
void prepareIsoModel(uint8 *bodyPtr); // loadGfxSub
|
||||
|
||||
int32 projectPositionOnScreen(int32 cX, int32 cY, int32 cZ);
|
||||
void setCameraPosition(int32 X, int32 Y, int32 cX, int32 cY, int32 cZ);
|
||||
void setCameraAngle(int32 transPosX, int32 transPosY, int32 transPosZ, int32 rotPosX, int32 rotPosY, int32 rotPosZ, int32 param6);
|
||||
void setBaseTranslation(int32 X, int32 Y, int32 Z);
|
||||
void setBaseRotation(int32 X, int32 Y, int32 Z);
|
||||
void setOrthoProjection(int32 X, int32 Y, int32 Z);
|
||||
|
||||
int32 renderIsoModel(int32 X, int32 Y, int32 Z, int32 angleX, int32 angleY, int32 angleZ, uint8 *bodyPtr);
|
||||
|
||||
void copyActorInternAnim(uint8 *bodyPtrSrc, uint8 *bodyPtrDest);
|
||||
|
||||
void renderBehaviourModel(int32 boxLeft, int32 boxTop, int32 boxRight, int32 boxBottom, int32 Y, int32 angle, uint8 *entityPtr);
|
||||
|
||||
void renderInventoryItem(int32 X, int32 Y, uint8* itemBodyPtr, int32 angle, int32 param);
|
||||
|
||||
#endif
|
128
engines/twine/resources.cpp
Normal file
128
engines/twine/resources.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/** @file resources.cpp
|
||||
@brief
|
||||
This file contains the definitions of most used game resources.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "resources.h"
|
||||
#include "text.h"
|
||||
#include "scene.h"
|
||||
#include "animations.h"
|
||||
#include "screens.h"
|
||||
#include "sdlengine.h"
|
||||
#include "sound.h"
|
||||
|
||||
int8 * HQR_RESS_FILE = "ress.hqr";
|
||||
int8 * HQR_TEXT_FILE = "text.hqr";
|
||||
int8 * HQR_FLASAMP_FILE = "flasamp.hqr";
|
||||
int8 * HQR_MIDI_MI_DOS_FILE = "midi_mi.hqr";
|
||||
int8 * HQR_MIDI_MI_WIN_FILE = "midi_mi_win.hqr";
|
||||
int8 * HQR_MIDI_MI_WIN_MP3_FILE = "midi_mi_win_mp3.hqr";
|
||||
int8 * HQR_MIDI_MI_WIN_OGG_FILE = "midi_mi_win_ogg.hqr";
|
||||
int8 * HQR_SAMPLES_FILE = "samples.hqr";
|
||||
int8 * HQR_LBA_GRI_FILE = "lba_gri.hqr";
|
||||
int8 * HQR_LBA_BLL_FILE = "lba_bll.hqr";
|
||||
int8 * HQR_LBA_BRK_FILE = "lba_brk.hqr";
|
||||
int8 * HQR_SCENE_FILE = "scene.hqr";
|
||||
int8 * HQR_SPRITES_FILE = "sprites.hqr";
|
||||
int8 * HQR_FILE3D_FILE = "file3d.hqr";
|
||||
int8 * HQR_BODY_FILE = "body.hqr";
|
||||
int8 * HQR_ANIM_FILE = "anim.hqr";
|
||||
int8 * HQR_INVOBJ_FILE = "invobj.hqr";
|
||||
|
||||
/** Init palettes */
|
||||
void initPalettes() {
|
||||
// Init standard palette
|
||||
hqrGetallocEntry(&mainPalette, HQR_RESS_FILE, RESSHQR_MAINPAL);
|
||||
convertPalToRGBA(mainPalette, mainPaletteRGBA);
|
||||
|
||||
memcpy(palette, mainPalette, NUMOFCOLORS * 3);
|
||||
|
||||
convertPalToRGBA(palette, paletteRGBA);
|
||||
setPalette(paletteRGBA);
|
||||
|
||||
// We use it now
|
||||
palCustom = 0;
|
||||
}
|
||||
|
||||
/** Preload all sprites */
|
||||
void preloadSprites() {
|
||||
int32 i;
|
||||
int32 numEntries = hqrNumEntries(HQR_SPRITES_FILE) - 1;
|
||||
|
||||
for (i = 0; i < numEntries; i++) {
|
||||
spriteSizeTable[i] = hqrGetallocEntry(&spriteTable[i], HQR_SPRITES_FILE, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Preload all animations */
|
||||
void preloadAnimations() {
|
||||
int32 i;
|
||||
int32 numEntries = hqrNumEntries(HQR_ANIM_FILE) - 1;
|
||||
|
||||
for (i = 0; i < numEntries; i++) {
|
||||
animSizeTable[i] = hqrGetallocEntry(&animTable[i], HQR_ANIM_FILE, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Preload all animations */
|
||||
void preloadSamples() {
|
||||
int32 i;
|
||||
int32 numEntries = hqrNumEntries(HQR_SAMPLES_FILE) - 1;
|
||||
|
||||
for (i = 0; i < numEntries; i++) {
|
||||
samplesSizeTable[i] = hqrGetallocEntry(&samplesTable[i], HQR_SAMPLES_FILE, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Preload all animations */
|
||||
void preloadInventoryItems() {
|
||||
int32 i;
|
||||
int32 numEntries = hqrNumEntries(HQR_INVOBJ_FILE) - 1;
|
||||
|
||||
for (i = 0; i < numEntries; i++) {
|
||||
inventorySizeTable[i] = hqrGetallocEntry(&inventoryTable[i], HQR_INVOBJ_FILE, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize resource pointers */
|
||||
void initResources() {
|
||||
// Menu and in-game palette
|
||||
initPalettes();
|
||||
|
||||
// load LBA font
|
||||
hqrGetallocEntry(&fontPtr, HQR_RESS_FILE, RESSHQR_LBAFONT);
|
||||
|
||||
setFontParameters(2, 8);
|
||||
setFontColor(14);
|
||||
setTextCrossColor(136, 143, 2);
|
||||
|
||||
hqrGetallocEntry(&spriteShadowPtr, HQR_RESS_FILE, RESSHQR_SPRITESHADOW);
|
||||
|
||||
// load sprite actors bounding box data
|
||||
hqrGetallocEntry(&spriteBoundingBoxPtr, HQR_RESS_FILE, RESSHQR_SPRITEBOXDATA);
|
||||
|
||||
preloadSprites();
|
||||
preloadAnimations();
|
||||
//preloadSamples();
|
||||
preloadInventoryItems();
|
||||
}
|
122
engines/twine/resources.h
Normal file
122
engines/twine/resources.h
Normal file
@ -0,0 +1,122 @@
|
||||
/** @file resources.h
|
||||
@brief
|
||||
This file contains the definitions of most used game resources.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef RESOURCES_H
|
||||
#define RESOURCES_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "gamestate.h"
|
||||
|
||||
/** RESS.HQR FILE */
|
||||
#define RESSHQR_MAINPAL 0
|
||||
#define RESSHQR_LBAFONT 1
|
||||
#define RESSHQR_BLANK 2
|
||||
#define RESSHQR_SPRITEBOXDATA 3
|
||||
#define RESSHQR_SPRITESHADOW 4
|
||||
#define RESSHQR_HOLOPAL 5
|
||||
#define RESSHQR_HOLOSURFACE 6
|
||||
#define RESSHQR_HOLOIMG 7
|
||||
#define RESSHQR_HOLOARROWINFO 8
|
||||
#define RESSHQR_HOLOTWINMDL 9
|
||||
#define RESSHQR_HOLOARROWMDL 10
|
||||
#define RESSHQR_HOLOTWINARROWMDL 11
|
||||
#define RESSHQR_RELLENTIMG 12
|
||||
#define RESSHQR_RELLENTPAL 13
|
||||
#define RESSHQR_MENUIMG 14
|
||||
#define RESSHQR_INTROSCREEN1IMG 15
|
||||
#define RESSHQR_INTROSCREEN1PAL 16
|
||||
#define RESSHQR_INTROSCREEN2IMG 17
|
||||
#define RESSHQR_INTROSCREEN2PAL 18
|
||||
#define RESSHQR_INTROSCREEN3IMG 19
|
||||
#define RESSHQR_INTROSCREEN3PAL 20
|
||||
#define RESSHQR_GAMEOVERMDL 21
|
||||
|
||||
#define RESSHQR_ALARMREDPAL 22
|
||||
#define RESSHQR_DARKPAL 24
|
||||
|
||||
#define RESSHQR_ADELINEIMG 27
|
||||
#define RESSHQR_ADELINEPAL 28
|
||||
|
||||
#define RESSHQR_LBAIMG 49
|
||||
#define RESSHQR_LBAPAL 50
|
||||
#define RESSHQR_PLASMAEFFECT 51
|
||||
#define RESSHQR_EAIMG 52
|
||||
#define RESSHQR_EAPAL 53
|
||||
|
||||
#define FLA_DRAGON3 "dragon3"
|
||||
#define FLA_INTROD "introd"
|
||||
#define FLA_THEEND "the_end"
|
||||
|
||||
#define FILE3DHQR_HERONORMAL 0
|
||||
#define FILE3DHQR_HEROATHLETIC 1
|
||||
#define FILE3DHQR_HEROAGGRESSIVE 2
|
||||
#define FILE3DHQR_HERODISCRETE 3
|
||||
#define FILE3DHQR_HEROPROTOPACK 4
|
||||
|
||||
/** Behaviour menu sprite values */
|
||||
#define SPRITEHQR_KASHES 3
|
||||
#define SPRITEHQR_LIFEPOINTS 4
|
||||
#define SPRITEHQR_MAGICPOINTS 5
|
||||
#define SPRITEHQR_KEY 6
|
||||
#define SPRITEHQR_CLOVERLEAF 7
|
||||
#define SPRITEHQR_CLOVERLEAFBOX 41
|
||||
|
||||
#define SPRITEHQR_MAGICBALL_GREEN 42
|
||||
#define SPRITEHQR_MAGICBALL_RED 43
|
||||
#define SPRITEHQR_MAGICBALL_YELLOW_TRANS 44
|
||||
#define SPRITEHQR_MAGICBALL_GREEN_TRANS 109
|
||||
#define SPRITEHQR_MAGICBALL_RED_TRANS 110
|
||||
|
||||
#define SPRITEHQR_DIAG_BUBBLE_RIGHT 90
|
||||
#define SPRITEHQR_DIAG_BUBBLE_LEFT 91
|
||||
|
||||
extern int8 * HQR_RESS_FILE;
|
||||
extern int8 * HQR_TEXT_FILE;
|
||||
extern int8 * HQR_FLASAMP_FILE;
|
||||
extern int8 * HQR_MIDI_MI_DOS_FILE;
|
||||
extern int8 * HQR_MIDI_MI_WIN_FILE;
|
||||
extern int8 * HQR_MIDI_MI_WIN_MP3_FILE;
|
||||
extern int8 * HQR_MIDI_MI_WIN_OGG_FILE;
|
||||
extern int8 * HQR_SAMPLES_FILE;
|
||||
extern int8 * HQR_LBA_GRI_FILE;
|
||||
extern int8 * HQR_LBA_BLL_FILE;
|
||||
extern int8 * HQR_LBA_BRK_FILE;
|
||||
extern int8 * HQR_SCENE_FILE;
|
||||
extern int8 * HQR_SPRITES_FILE;
|
||||
extern int8 * HQR_FILE3D_FILE;
|
||||
extern int8 * HQR_BODY_FILE;
|
||||
extern int8 * HQR_ANIM_FILE;
|
||||
extern int8 * HQR_INVOBJ_FILE;
|
||||
|
||||
/** Table with all loaded samples */
|
||||
uint8* inventoryTable[NUM_INVENTORY_ITEMS];
|
||||
/** Table with all loaded samples sizes */
|
||||
uint32 inventorySizeTable[NUM_INVENTORY_ITEMS];
|
||||
|
||||
/** Initialize resource pointers */
|
||||
void initResources();
|
||||
|
||||
#endif
|
588
engines/twine/scene.cpp
Normal file
588
engines/twine/scene.cpp
Normal file
@ -0,0 +1,588 @@
|
||||
/** @file scene.cpp
|
||||
@brief
|
||||
This file contains main scenario routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "scene.h"
|
||||
#include "actor.h"
|
||||
#include "grid.h"
|
||||
#include "main.h"
|
||||
#include "lbaengine.h"
|
||||
#include "text.h"
|
||||
#include "resources.h"
|
||||
#include "music.h"
|
||||
#include "renderer.h"
|
||||
#include "gamestate.h"
|
||||
#include "redraw.h"
|
||||
#include "movements.h"
|
||||
#include "sound.h"
|
||||
#include "animations.h"
|
||||
#include "extra.h"
|
||||
#include "screens.h"
|
||||
|
||||
uint8* currentScene;
|
||||
|
||||
|
||||
void setActorStaticFlags(int32 actorIdx, uint16 staticFlags) {
|
||||
if (staticFlags & 0x1) {
|
||||
sceneActors[actorIdx].staticFlags.bComputeCollisionWithObj = 1;
|
||||
}
|
||||
if (staticFlags & 0x2) {
|
||||
sceneActors[actorIdx].staticFlags.bComputeCollisionWithBricks = 1;
|
||||
}
|
||||
if (staticFlags & 0x4) {
|
||||
sceneActors[actorIdx].staticFlags.bIsZonable = 1;
|
||||
}
|
||||
if (staticFlags & 0x8) {
|
||||
sceneActors[actorIdx].staticFlags.bUsesClipping = 1;
|
||||
}
|
||||
if (staticFlags & 0x10) {
|
||||
sceneActors[actorIdx].staticFlags.bCanBePushed = 1;
|
||||
}
|
||||
if (staticFlags & 0x20) {
|
||||
sceneActors[actorIdx].staticFlags.bComputeLowCollision = 1;
|
||||
}
|
||||
if (staticFlags & 0x40) {
|
||||
sceneActors[actorIdx].staticFlags.bCanDrown = 1;
|
||||
}
|
||||
if (staticFlags & 0x80) {
|
||||
sceneActors[actorIdx].staticFlags.bUnk80 = 1;
|
||||
}
|
||||
|
||||
if (staticFlags & 0x100) {
|
||||
sceneActors[actorIdx].staticFlags.bUnk0100 = 1;
|
||||
}
|
||||
if (staticFlags & 0x200) {
|
||||
sceneActors[actorIdx].staticFlags.bIsHidden = 1;
|
||||
}
|
||||
if (staticFlags & 0x400) {
|
||||
sceneActors[actorIdx].staticFlags.bIsSpriteActor = 1;
|
||||
}
|
||||
if (staticFlags & 0x800) {
|
||||
sceneActors[actorIdx].staticFlags.bCanFall = 1;
|
||||
}
|
||||
if (staticFlags & 0x1000) {
|
||||
sceneActors[actorIdx].staticFlags.bDoesntCastShadow = 1;
|
||||
}
|
||||
if (staticFlags & 0x2000) {
|
||||
//sceneActors[actorIdx].staticFlags.bIsBackgrounded = 1;
|
||||
}
|
||||
if (staticFlags & 0x4000) {
|
||||
sceneActors[actorIdx].staticFlags.bIsCarrierActor = 1;
|
||||
}
|
||||
if (staticFlags & 0x8000) {
|
||||
sceneActors[actorIdx].staticFlags.bUseMiniZv = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void loadScene() {
|
||||
int32 i;
|
||||
int32 scriptSize = 0;
|
||||
uint8* localScene = currentScene;
|
||||
|
||||
// load scene ambience properties
|
||||
currentTextBank = *(localScene++);
|
||||
currentGameOverScene = *(localScene++);
|
||||
localScene += 4;
|
||||
|
||||
alphaLight = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
betaLight = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
// FIXME: Workaround to fix lighting issue - not using proper dark light
|
||||
alphaLight = 896;
|
||||
betaLight = 950;
|
||||
|
||||
sampleAmbiance[0] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleRepeat[0] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleRound[0] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sampleAmbiance[1] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleRepeat[1] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleRound[1] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sampleAmbiance[2] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleRepeat[2] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleRound[2] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sampleAmbiance[3] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleRepeat[3] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleRound[3] = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sampleMinDelay = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sampleMinDelayRnd = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sceneMusic = *(localScene++);
|
||||
|
||||
// load hero properties
|
||||
sceneHeroX = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneHeroY = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneHeroZ = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
scriptSize = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneHero->moveScript = localScene;
|
||||
localScene += scriptSize;
|
||||
|
||||
scriptSize = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneHero->lifeScript = localScene;
|
||||
localScene += scriptSize;
|
||||
|
||||
sceneNumActors = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
for (i = 1; i < sceneNumActors; i++) {
|
||||
uint16 staticFlags;
|
||||
|
||||
resetActor(i);
|
||||
|
||||
staticFlags = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
setActorStaticFlags(i, staticFlags);
|
||||
|
||||
sceneActors[i].entity = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
if (!sceneActors[i].staticFlags.bIsSpriteActor) {
|
||||
hqrGetallocEntry(&sceneActors[i].entityDataPtr, HQR_FILE3D_FILE, sceneActors[i].entity);
|
||||
}
|
||||
|
||||
sceneActors[i].body = *(localScene++);
|
||||
sceneActors[i].anim = *(localScene++);
|
||||
sceneActors[i].sprite = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].X = *((uint16*)localScene);
|
||||
sceneActors[i].collisionX = sceneActors[i].X;
|
||||
localScene += 2;
|
||||
sceneActors[i].Y = *((uint16*)localScene);
|
||||
sceneActors[i].collisionY = sceneActors[i].Y;
|
||||
localScene += 2;
|
||||
sceneActors[i].Z = *((uint16*)localScene);
|
||||
sceneActors[i].collisionZ = sceneActors[i].Z;
|
||||
localScene += 2;
|
||||
sceneActors[i].strengthOfHit = *(localScene++);
|
||||
sceneActors[i].bonusParameter = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].bonusParameter &= 0xFE;
|
||||
sceneActors[i].angle = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].speed = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].controlMode = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].info0 = *((int16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].info1 = *((int16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].info2 = *((int16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].info3 = *((int16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].followedActor = sceneActors[i].info3;
|
||||
sceneActors[i].bonusAmount = *(localScene++);
|
||||
sceneActors[i].talkColor = *(localScene++);
|
||||
sceneActors[i].armor = *(localScene++);
|
||||
sceneActors[i].life = *(localScene++);
|
||||
|
||||
scriptSize = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].moveScript = localScene;
|
||||
localScene += scriptSize;
|
||||
|
||||
scriptSize = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneActors[i].lifeScript = localScene;
|
||||
localScene += scriptSize;
|
||||
}
|
||||
|
||||
sceneNumZones = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
for (i = 0; i < sceneNumZones; i++) {
|
||||
sceneZones[i].bottomLeft.X = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneZones[i].bottomLeft.Y = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneZones[i].bottomLeft.Z = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sceneZones[i].topRight.X = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneZones[i].topRight.Y = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneZones[i].topRight.Z = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sceneZones[i].type = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sceneZones[i].infoData.generic.info0 = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneZones[i].infoData.generic.info1 = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneZones[i].infoData.generic.info2 = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneZones[i].infoData.generic.info3 = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
sceneZones[i].snap = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
}
|
||||
|
||||
sceneNumTracks = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
|
||||
for (i = 0; i < sceneNumTracks; i++) {
|
||||
sceneTracks[i].X = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneTracks[i].Y = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
sceneTracks[i].Z = *((uint16*)localScene);
|
||||
localScene += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize new scene */
|
||||
int32 initScene(int32 index) {
|
||||
// load scene from file
|
||||
hqrGetallocEntry(¤tScene, HQR_SCENE_FILE, index);
|
||||
|
||||
loadScene();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** Reset scene */
|
||||
void resetScene() {
|
||||
int32 i;
|
||||
|
||||
resetExtras();
|
||||
|
||||
for (i = 0; i < NUM_SCENES_FLAGS; i++) {
|
||||
sceneFlags[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
|
||||
overlayList[i].info0 = -1;
|
||||
}
|
||||
|
||||
currentPositionInBodyPtrTab = 0;
|
||||
useAlternatePalette = 0;
|
||||
}
|
||||
|
||||
/** Change to another scene */
|
||||
void changeScene() {
|
||||
int32 a;
|
||||
|
||||
// change twinsen house destroyed hard-coded
|
||||
if (needChangeScene == 4 && gameFlags[30] != 0)
|
||||
needChangeScene = 118;
|
||||
|
||||
// local backup previous scene
|
||||
previousSceneIdx = currentSceneIdx;
|
||||
currentSceneIdx = needChangeScene;
|
||||
|
||||
stopSamples();
|
||||
|
||||
resetScene();
|
||||
loadHeroEntities();
|
||||
|
||||
sceneHero->controlMode = 1;
|
||||
sceneHero->zone = -1;
|
||||
sceneHero->positionInLifeScript = 0;
|
||||
sceneHero->positionInMoveScript = -1;
|
||||
sceneHero->labelIdx = -1;
|
||||
|
||||
initScene(needChangeScene);
|
||||
|
||||
//TODO: treat holomap trajectories
|
||||
|
||||
if (needChangeScene == 116 || needChangeScene == 117)
|
||||
currentTextBank = 10;
|
||||
|
||||
initTextBank(currentTextBank + 3);
|
||||
initGrid(needChangeScene);
|
||||
|
||||
if (heroPositionType == kZone) {
|
||||
newHeroX = zoneHeroX;
|
||||
newHeroY = zoneHeroY;
|
||||
newHeroZ = zoneHeroZ;
|
||||
}
|
||||
|
||||
if (heroPositionType == kScene || heroPositionType == kNoPosition) {
|
||||
newHeroX = sceneHeroX;
|
||||
newHeroY = sceneHeroY;
|
||||
newHeroZ = sceneHeroZ;
|
||||
}
|
||||
|
||||
sceneHero->X = newHeroX;
|
||||
sceneHero->Y = heroYBeforeFall = newHeroY;
|
||||
sceneHero->Z = newHeroZ;
|
||||
|
||||
setLightVector(alphaLight, betaLight, 0);
|
||||
|
||||
if (previousSceneIdx != needChangeScene) {
|
||||
previousHeroBehaviour = heroBehaviour;
|
||||
previousHeroAngle = sceneHero->angle;
|
||||
saveGame();
|
||||
}
|
||||
|
||||
restartHeroScene();
|
||||
|
||||
for (a = 1; a < sceneNumActors; a++) {
|
||||
initActor(a);
|
||||
}
|
||||
|
||||
inventoryNumKeys = 0;
|
||||
disableScreenRecenter = 0;
|
||||
heroPositionType = kNoPosition;
|
||||
sampleAmbienceTime = 0;
|
||||
|
||||
newCameraX = sceneActors[currentlyFollowedActor].X >> 9;
|
||||
newCameraY = sceneActors[currentlyFollowedActor].Y >> 8;
|
||||
newCameraZ = sceneActors[currentlyFollowedActor].Z >> 9;
|
||||
|
||||
magicBallIdx = -1;
|
||||
heroMoved = 1;
|
||||
useCellingGrid = -1;
|
||||
cellingGridIdx = -1;
|
||||
reqBgRedraw = 1;
|
||||
lockPalette = 0;
|
||||
|
||||
needChangeScene = -1;
|
||||
changeRoomVar10 = 1;
|
||||
changeRoomVar11 = 14;
|
||||
|
||||
setLightVector(alphaLight, betaLight, 0);
|
||||
|
||||
if (sceneMusic != -1) {
|
||||
playMidiMusic(sceneMusic, 0); // TODO this should play midi or cd tracks
|
||||
}
|
||||
}
|
||||
|
||||
/** Process scene environment sound */
|
||||
void processEnvironmentSound() {
|
||||
int16 s, currentAmb, decal, repeat;
|
||||
int16 sampleIdx = -1;
|
||||
|
||||
if (lbaTime >= sampleAmbienceTime) {
|
||||
currentAmb = Rnd(4); // random ambiance
|
||||
|
||||
for(s = 0; s < 4; s++) {
|
||||
if(!(samplePlayed & (1 << currentAmb))) { // if not already played
|
||||
samplePlayed |= (1 << currentAmb); // make sample played
|
||||
|
||||
if(samplePlayed == 15) { // reset if all samples played
|
||||
samplePlayed = 0;
|
||||
}
|
||||
|
||||
sampleIdx = sampleAmbiance[currentAmb];
|
||||
if(sampleIdx != -1) {
|
||||
decal = sampleRound[currentAmb];
|
||||
repeat = sampleRepeat[currentAmb];
|
||||
|
||||
playSample(sampleIdx, (0x1000+Rnd(decal)-(decal/2)), repeat, 110, -1, 110, -1);
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
currentAmb++; // try next ambiance
|
||||
currentAmb &= 3; // loop in all 4 ambiances
|
||||
}
|
||||
|
||||
// compute next ambiance timer
|
||||
sampleAmbienceTime = lbaTime + (Rnd(sampleMinDelayRnd) + sampleMinDelay) * 50;
|
||||
}
|
||||
}
|
||||
|
||||
/** Process zone extra bonus */
|
||||
void processZoneExtraBonus(ZoneStruct *zone) {
|
||||
int32 a, numBonus;
|
||||
int8 bonusTable[8], currentBonus;
|
||||
|
||||
numBonus = 0;
|
||||
|
||||
// bonus not used yet
|
||||
if (!zone->infoData.generic.info3) {
|
||||
for (a = 0; a < 5; a++) {
|
||||
if (zone->infoData.generic.info1 & (1 << (a + 4))) {
|
||||
bonusTable[numBonus++] = a;
|
||||
}
|
||||
}
|
||||
|
||||
if (numBonus) {
|
||||
int32 angle, index;
|
||||
currentBonus = bonusTable[Rnd(numBonus)];
|
||||
|
||||
// if bonus is magic an no magic level yet, then give life points
|
||||
if (!magicLevelIdx && currentBonus == 2) {
|
||||
currentBonus = 1;
|
||||
}
|
||||
|
||||
angle = getAngleAndSetTargetActorDistance(Abs(zone->topRight.X + zone->bottomLeft.X)/2, Abs(zone->topRight.Z + zone->bottomLeft.Z)/2, sceneHero->X, sceneHero->Z);
|
||||
index = addExtraBonus(Abs(zone->topRight.X + zone->bottomLeft.X)/2, zone->topRight.Y, Abs(zone->topRight.Z + zone->bottomLeft.Z)/2, 180, angle, currentBonus + 3, zone->infoData.generic.info2);
|
||||
|
||||
if (index != -1) {
|
||||
extraList[index].type |= 0x400;
|
||||
zone->infoData.generic.info3 = 1; // set as used
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Process actor zones
|
||||
@param actorIdx Process actor index */
|
||||
void processActorZones(int32 actorIdx) {
|
||||
int32 currentX, currentY, currentZ, z, tmpCellingGrid;
|
||||
ActorStruct *actor;
|
||||
|
||||
actor = &sceneActors[actorIdx];
|
||||
|
||||
currentX = actor->X;
|
||||
currentY = actor->Y;
|
||||
currentZ = actor->Z;
|
||||
|
||||
actor->zone = -1;
|
||||
tmpCellingGrid = 0;
|
||||
|
||||
if (!actorIdx) {
|
||||
currentActorInZone = actorIdx;
|
||||
}
|
||||
|
||||
for (z = 0; z < sceneNumZones; z++) {
|
||||
ZoneStruct *zone = &sceneZones[z];
|
||||
|
||||
// check if actor is in zone
|
||||
if ((currentX >= zone->bottomLeft.X && currentX <= zone->topRight.X) &&
|
||||
(currentY >= zone->bottomLeft.Y && currentY <= zone->topRight.Y) &&
|
||||
(currentZ >= zone->bottomLeft.Z && currentZ <= zone->topRight.Z)) {
|
||||
switch (zone->type) {
|
||||
case kCube:
|
||||
if (!actorIdx && actor->life > 0) {
|
||||
needChangeScene = zone->infoData.ChangeScene.newSceneIdx;
|
||||
zoneHeroX = actor->X - zone->bottomLeft.X + zone->infoData.ChangeScene.X;
|
||||
zoneHeroY = actor->Y - zone->bottomLeft.Y + zone->infoData.ChangeScene.Y;
|
||||
zoneHeroZ = actor->Z - zone->bottomLeft.Z + zone->infoData.ChangeScene.Z;
|
||||
heroPositionType = kZone;
|
||||
}
|
||||
break;
|
||||
case kCamera:
|
||||
if (currentlyFollowedActor == actorIdx) {
|
||||
disableScreenRecenter = 1;
|
||||
if (newCameraX != zone->infoData.CameraView.X || newCameraY != zone->infoData.CameraView.Y || newCameraZ != zone->infoData.CameraView.Z) {
|
||||
newCameraX = zone->infoData.CameraView.X;
|
||||
newCameraY = zone->infoData.CameraView.Y;
|
||||
newCameraZ = zone->infoData.CameraView.Z;
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kSceneric:
|
||||
actor->zone = zone->infoData.Sceneric.zoneIdx;
|
||||
break;
|
||||
case kGrid:
|
||||
if (currentlyFollowedActor == actorIdx) {
|
||||
tmpCellingGrid = 1;
|
||||
if (useCellingGrid != zone->infoData.CeillingGrid.newGrid) {
|
||||
if (zone->infoData.CeillingGrid.newGrid != -1) {
|
||||
createGridMap();
|
||||
}
|
||||
|
||||
useCellingGrid = zone->infoData.CeillingGrid.newGrid;
|
||||
cellingGridIdx = z;
|
||||
freezeTime();
|
||||
initCellingGrid(useCellingGrid);
|
||||
unfreezeTime();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kObject:
|
||||
if (!actorIdx && heroAction != 0) {
|
||||
initAnim(kAction, 1, 0, 0);
|
||||
processZoneExtraBonus(zone);
|
||||
}
|
||||
break;
|
||||
case kText:
|
||||
if (!actorIdx && heroAction != 0) {
|
||||
freezeTime();
|
||||
setFontCrossColor(zone->infoData.DisplayText.textColor);
|
||||
talkingActor = actorIdx;
|
||||
drawTextFullscreen(zone->infoData.DisplayText.textIdx);
|
||||
unfreezeTime();
|
||||
redrawEngineActions(1);
|
||||
}
|
||||
break;
|
||||
case kLadder:
|
||||
if (!actorIdx && heroBehaviour != kProtoPack && (actor->anim == kForward || actor->anim == kTopLadder || actor->anim == kClimbLadder)) {
|
||||
rotateActor(actor->boudingBox.X.bottomLeft, actor->boudingBox.Z.bottomLeft, actor->angle + 0x580);
|
||||
destX += processActorX;
|
||||
destZ += processActorZ;
|
||||
|
||||
if (destX >= 0 && destZ >= 0 && destX <= 0x7E00 && destZ <= 0x7E00) {
|
||||
if (getBrickShape(destX, actor->Y + 0x100, destZ)) {
|
||||
currentActorInZone = 1;
|
||||
if (actor->Y >= Abs(zone->bottomLeft.Y + zone->topRight.Y) / 2) {
|
||||
initAnim(kTopLadder, 2, 0, actorIdx); // reached end of ladder
|
||||
} else {
|
||||
initAnim(kClimbLadder, 0, 255, actorIdx); // go up in ladder
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tmpCellingGrid && actorIdx == currentlyFollowedActor && useCellingGrid != -1) {
|
||||
useCellingGrid = -1;
|
||||
cellingGridIdx = -1;
|
||||
createGridMap();
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
}
|
188
engines/twine/scene.h
Normal file
188
engines/twine/scene.h
Normal file
@ -0,0 +1,188 @@
|
||||
/** @file scene.h
|
||||
@brief
|
||||
This file contains main scenario routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SCENE_H
|
||||
#define SCENE_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "actor.h"
|
||||
|
||||
#define NUM_SCENES_FLAGS 80
|
||||
|
||||
#define NUM_SCENES_ENTRIES 120
|
||||
#define NUM_SCENES NUM_SCENES_ENTRIES-1
|
||||
|
||||
#define NUM_MAX_ACTORS 100
|
||||
#define NUM_MAX_ZONES 100
|
||||
#define NUM_MAX_TRACKS 200
|
||||
|
||||
enum ScenePositionType {
|
||||
kNoPosition = 0,
|
||||
kZone = 1,
|
||||
kScene = 2,
|
||||
kReborn = 3
|
||||
};
|
||||
|
||||
|
||||
int32 needChangeScene;
|
||||
int32 currentSceneIdx;
|
||||
int32 previousSceneIdx;
|
||||
|
||||
uint8 *spriteShadowPtr;
|
||||
uint8 *spriteBoundingBoxPtr;
|
||||
|
||||
int32 currentGameOverScene;
|
||||
int32 alphaLight;
|
||||
int32 betaLight;
|
||||
|
||||
/** Timer for the next sample ambience in scene */
|
||||
int32 sampleAmbienceTime;
|
||||
|
||||
int16 sampleAmbiance[4];
|
||||
int16 sampleRepeat[4];
|
||||
int16 sampleRound[4];
|
||||
int16 sampleMinDelay;
|
||||
int16 sampleMinDelayRnd;
|
||||
|
||||
int16 samplePlayed;
|
||||
|
||||
int16 sceneMusic;
|
||||
|
||||
int16 sceneHeroX; // newTwinsenXByScene
|
||||
int16 sceneHeroY; // newTwinsenYByScene
|
||||
int16 sceneHeroZ; // newTwinsenZByScene
|
||||
|
||||
int16 newHeroX; // newTwinsenX
|
||||
int16 newHeroY; // newTwinsenY
|
||||
int16 newHeroZ; // newTwinsenZ
|
||||
|
||||
int16 zoneHeroX; // newTwinsenXByZone
|
||||
int16 zoneHeroY; // newTwinsenYByZone
|
||||
int16 zoneHeroZ; // newTwinsenZByZone
|
||||
|
||||
/** Hero Y coordinate before fall */
|
||||
int16 heroYBeforeFall;
|
||||
|
||||
/** Hero type of position in scene */
|
||||
int16 heroPositionType; // twinsenPositionModeInNewCube
|
||||
|
||||
// ACTORS
|
||||
int32 sceneNumActors;
|
||||
ActorStruct sceneActors[NUM_MAX_ACTORS];
|
||||
ActorStruct *sceneHero;
|
||||
|
||||
/** Meca pinguin actor index */
|
||||
int16 mecaPinguinIdx; // currentPingouin
|
||||
|
||||
/** Current followed actor in scene */
|
||||
int16 currentlyFollowedActor;
|
||||
/** Current actor in zone */
|
||||
int16 currentActorInZone; // currentActorInZoneProcess
|
||||
/** Current actor manipulated in scripts */
|
||||
int16 currentScriptValue; // manipActorResult
|
||||
|
||||
int16 talkingActor;
|
||||
|
||||
// ZONES
|
||||
|
||||
typedef struct ScenePoint {
|
||||
int16 X;
|
||||
int16 Y;
|
||||
int16 Z;
|
||||
} ScenePoint;
|
||||
|
||||
typedef struct ZoneStruct {
|
||||
ScenePoint bottomLeft;
|
||||
ScenePoint topRight;
|
||||
int16 type;
|
||||
union {
|
||||
struct {
|
||||
int16 newSceneIdx;
|
||||
int16 X;
|
||||
int16 Y;
|
||||
int16 Z;
|
||||
} ChangeScene;
|
||||
struct {
|
||||
int16 dummy;
|
||||
int16 X;
|
||||
int16 Y;
|
||||
int16 Z;
|
||||
} CameraView;
|
||||
struct {
|
||||
int16 zoneIdx;
|
||||
} Sceneric;
|
||||
struct {
|
||||
int16 newGrid;
|
||||
} CeillingGrid;
|
||||
struct {
|
||||
int16 textIdx;
|
||||
int16 textColor;
|
||||
} DisplayText;
|
||||
struct {
|
||||
int16 info0;
|
||||
int16 info1;
|
||||
int16 info2;
|
||||
int16 info3;
|
||||
} generic;
|
||||
} infoData;
|
||||
int16 snap;
|
||||
} ZoneStruct;
|
||||
|
||||
int32 sceneNumZones;
|
||||
ZoneStruct sceneZones[NUM_MAX_ZONES];
|
||||
|
||||
enum ZoneType {
|
||||
kCube = 0, // Change to another scene
|
||||
kCamera = 1, // Binds camera view
|
||||
kSceneric = 2, // For use in Life Script
|
||||
kGrid = 3, // Set disappearing Grid fragment
|
||||
kObject = 4, // Give bonus
|
||||
kText = 5, // Displays text message
|
||||
kLadder = 6 // Hero can climb on it
|
||||
};
|
||||
|
||||
|
||||
// TRACKS
|
||||
|
||||
int32 sceneNumTracks;
|
||||
ScenePoint sceneTracks[NUM_MAX_TRACKS];
|
||||
|
||||
// TODO: check what is this
|
||||
int16 changeRoomVar10;
|
||||
int16 changeRoomVar11;
|
||||
|
||||
uint8 sceneFlags[80]; // cubeFlags
|
||||
|
||||
/** Change to another scene */
|
||||
void changeScene();
|
||||
|
||||
/** Process scene environment sound */
|
||||
void processEnvironmentSound();
|
||||
|
||||
/** Process actor zones
|
||||
@param actorIdx Process actor index */
|
||||
void processActorZones(int32 actorIdx);
|
||||
|
||||
#endif
|
326
engines/twine/screens.cpp
Normal file
326
engines/twine/screens.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
/** @file images.cpp
|
||||
@brief
|
||||
This file contains image processing.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "screens.h"
|
||||
#include "resources.h"
|
||||
#include "main.h"
|
||||
#include "sdlengine.h"
|
||||
#include "music.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "lbaengine.h"
|
||||
|
||||
|
||||
/** Load and display Adeline Logo */
|
||||
void adelineLogo() {
|
||||
playMidiMusic(31, 0);
|
||||
|
||||
loadImage(RESSHQR_ADELINEIMG, 1);
|
||||
delaySkip(7000);
|
||||
fadeOut(paletteRGBACustom);
|
||||
palCustom = 1;
|
||||
}
|
||||
|
||||
/** Load and display Main Menu image */
|
||||
void loadMenuImage(int16 fade_in) {
|
||||
hqrGetEntry(workVideoBuffer, HQR_RESS_FILE, RESSHQR_MENUIMG);
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
if (fade_in) {
|
||||
fadeToPal(paletteRGBA);
|
||||
} else {
|
||||
setPalette(paletteRGBA);
|
||||
}
|
||||
|
||||
palCustom = 0;
|
||||
}
|
||||
|
||||
/** Load a custom palette */
|
||||
void loadCustomPalette(int32 index) {
|
||||
hqrGetEntry(palette, HQR_RESS_FILE, index);
|
||||
convertPalToRGBA(palette, paletteRGBACustom);
|
||||
}
|
||||
|
||||
/** Load and display a particulary image on \a RESS.HQR file with cross fade effect
|
||||
@param index \a RESS.HQR entry index (starting from 0) */
|
||||
void loadImage(int32 index, int16 fade_in) {
|
||||
hqrGetEntry(workVideoBuffer, HQR_RESS_FILE, index);
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
loadCustomPalette(index + 1);
|
||||
if (fade_in) {
|
||||
fadeToPal(paletteRGBACustom);
|
||||
} else {
|
||||
setPalette(paletteRGBACustom);
|
||||
}
|
||||
|
||||
palCustom = 1;
|
||||
}
|
||||
|
||||
/** Load and display a particulary image on \a RESS.HQR file with cross fade effect and delay
|
||||
@param index \a RESS.HQR entry index (starting from 0)
|
||||
@param time number of seconds to delay */
|
||||
void loadImageDelay(int32 index, int32 time) {
|
||||
loadImage(index, 1);
|
||||
delaySkip(1000*time);
|
||||
fadeOut(paletteRGBACustom);
|
||||
}
|
||||
|
||||
/** Converts in-game palette to SDL palette
|
||||
@param palSource palette source with RGB
|
||||
@param palDest palette destination with RGBA */
|
||||
void convertPalToRGBA(uint8 * palSource, uint8 * palDest) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUMOFCOLORS; i++) {
|
||||
palDest[0] = palSource[0];
|
||||
palDest[1] = palSource[1];
|
||||
palDest[2] = palSource[2];
|
||||
palDest += 4;
|
||||
palSource += 3;
|
||||
}
|
||||
}
|
||||
|
||||
/** Fade image in
|
||||
@param palette current palette to fade in */
|
||||
void fadeIn(uint8 * palette) {
|
||||
if (cfgfile.CrossFade)
|
||||
crossFade(frontVideoBuffer, palette);
|
||||
else
|
||||
fadeToPal(palette);
|
||||
|
||||
setPalette(palette);
|
||||
}
|
||||
|
||||
/** Fade image out
|
||||
@param palette current palette to fade out */
|
||||
void fadeOut(uint8 * palette) {
|
||||
/*if(cfgfile.CrossFade)
|
||||
crossFade(frontVideoBuffer, palette);
|
||||
else
|
||||
fadeToBlack(palette);*/
|
||||
if (!cfgfile.CrossFade)
|
||||
fadeToBlack(palette);
|
||||
}
|
||||
|
||||
/** Calculate a new color component according with an intensity
|
||||
@param modifier color compenent
|
||||
@param color color value
|
||||
@param param unknown
|
||||
@param intensity intensity value to adjust
|
||||
@return new color component*/
|
||||
int32 crossDot(int32 modifier, int32 color, int32 param, int32 intensity) {
|
||||
if (!param)
|
||||
return (color);
|
||||
return (((color - modifier) * intensity) / param) + modifier;
|
||||
}
|
||||
|
||||
/** Adjust palette intensity
|
||||
@param R red component of color
|
||||
@param G green component of color
|
||||
@param B blue component of color
|
||||
@param palette palette to adjust
|
||||
@param intensity intensity value to adjust */
|
||||
void adjustPalette(uint8 R, uint8 G, uint8 B, uint8 * palette, int32 intensity) {
|
||||
uint8 localPalette[NUMOFCOLORS*4];
|
||||
uint8 *newR;
|
||||
uint8 *newG;
|
||||
uint8 *newB;
|
||||
uint8 *newA;
|
||||
|
||||
int32 local;
|
||||
int32 counter = 0;
|
||||
int32 i;
|
||||
|
||||
local = intensity;
|
||||
|
||||
newR = &localPalette[0];
|
||||
newG = &localPalette[1];
|
||||
newB = &localPalette[2];
|
||||
newA = &localPalette[3];
|
||||
|
||||
for (i = 0; i < NUMOFCOLORS; i++) {
|
||||
*newR = crossDot(R, palette[counter], 100, local);
|
||||
*newG = crossDot(G, palette[counter + 1], 100, local);
|
||||
*newB = crossDot(B, palette[counter + 2], 100, local);
|
||||
*newA = 0;
|
||||
|
||||
newR += 4;
|
||||
newG += 4;
|
||||
newB += 4;
|
||||
newA += 4;
|
||||
|
||||
counter += 4;
|
||||
}
|
||||
|
||||
setPalette(localPalette);
|
||||
}
|
||||
|
||||
/** Adjust between two palettes
|
||||
@param pal1 palette from adjust
|
||||
@param pal2 palette to adjust */
|
||||
void adjustCrossPalette(uint8 * pal1, uint8 * pal2) {
|
||||
uint8 localPalette[NUMOFCOLORS*4];
|
||||
|
||||
uint8 *newR;
|
||||
uint8 *newG;
|
||||
uint8 *newB;
|
||||
uint8 *newA;
|
||||
|
||||
int32 i;
|
||||
int32 counter = 0;
|
||||
int32 intensity = 0;
|
||||
|
||||
do
|
||||
{
|
||||
counter = 0;
|
||||
|
||||
newR = &localPalette[counter];
|
||||
newG = &localPalette[counter + 1];
|
||||
newB = &localPalette[counter + 2];
|
||||
newA = &localPalette[counter + 3];
|
||||
|
||||
for (i = 0; i < NUMOFCOLORS; i++) {
|
||||
*newR = crossDot(pal1[counter], pal2[counter], 100, intensity);
|
||||
*newG = crossDot(pal1[counter + 1], pal2[counter + 1], 100, intensity);
|
||||
*newB = crossDot(pal1[counter + 2], pal2[counter + 2], 100, intensity);
|
||||
*newA = 0;
|
||||
|
||||
newR += 4;
|
||||
newG += 4;
|
||||
newB += 4;
|
||||
newA += 4;
|
||||
|
||||
counter += 4;
|
||||
}
|
||||
|
||||
setPalette(localPalette);
|
||||
fpsCycles(50);
|
||||
|
||||
intensity++;
|
||||
} while(intensity <= 100);
|
||||
}
|
||||
|
||||
/** Fade image to black
|
||||
@param palette current palette to fade */
|
||||
void fadeToBlack(uint8 *palette) {
|
||||
int32 i = 0;
|
||||
|
||||
if (palReseted == 0) {
|
||||
for (i = 100; i >= 0; i -= 3) {
|
||||
adjustPalette(0, 0, 0, (uint8 *) palette, i);
|
||||
fpsCycles(50);
|
||||
}
|
||||
}
|
||||
|
||||
palReseted = 1;
|
||||
}
|
||||
|
||||
/** Fade image with another palette source
|
||||
@param palette current palette to fade */
|
||||
void fadeToPal(uint8 *palette) {
|
||||
int32 i = 100;
|
||||
|
||||
for (i = 0; i <= 100; i += 3) {
|
||||
adjustPalette(0, 0, 0, (uint8 *) palette, i);
|
||||
fpsCycles(50);
|
||||
}
|
||||
|
||||
setPalette((uint8*)palette);
|
||||
|
||||
palReseted = 0;
|
||||
}
|
||||
|
||||
/** Fade black palette to with palette */
|
||||
void blackToWhite() {
|
||||
uint8 palette[NUMOFCOLORS*4];
|
||||
int32 i;
|
||||
|
||||
i = 256;
|
||||
for (i = 0; i < NUMOFCOLORS; i += 3) {
|
||||
memset(palette, i, 1024);
|
||||
|
||||
setPalette(palette);
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets both in-game and sdl palettes */
|
||||
void setBackPal() {
|
||||
memset(palette, 0, NUMOFCOLORS*3);
|
||||
memset(paletteRGBA, 0, NUMOFCOLORS*4);
|
||||
|
||||
setPalette(paletteRGBA);
|
||||
|
||||
palReseted = 1;
|
||||
}
|
||||
|
||||
/** Fade palette to red palette
|
||||
@param palette current palette to fade */
|
||||
void fadePalRed(uint8 *palette) {
|
||||
int32 i = 100;
|
||||
|
||||
for (i = 100; i >= 0; i -= 2) {
|
||||
adjustPalette(0xFF, 0, 0, (uint8 *) palette, i);
|
||||
fpsCycles(50);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Fade red to palette
|
||||
@param palette current palette to fade */
|
||||
void fadeRedPal(uint8 *palette) {
|
||||
int32 i = 0;
|
||||
|
||||
for (i = 0; i <= 100; i += 2) {
|
||||
adjustPalette(0xFF, 0, 0, (uint8 *) palette, i);
|
||||
fpsCycles(50);
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy a determinate screen buffer to another
|
||||
@param source screen buffer
|
||||
@param destination screen buffer */
|
||||
void copyScreen(uint8 * source, uint8 * destination) {
|
||||
int32 w, h;
|
||||
|
||||
if (SCALE == 1)
|
||||
memcpy(destination, source, SCREEN_WIDTH*SCREEN_HEIGHT);
|
||||
else if (SCALE == 2)
|
||||
for (h = 0; h < SCREEN_HEIGHT / SCALE; h++) {
|
||||
for (w = 0; w < SCREEN_WIDTH / SCALE; w++) {
|
||||
*destination++ = *source;
|
||||
*destination++ = *source++;
|
||||
}
|
||||
memcpy(destination, destination - SCREEN_WIDTH, SCREEN_WIDTH);
|
||||
destination += SCREEN_WIDTH;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Clear front buffer screen */
|
||||
void clearScreen() {
|
||||
memset(frontVideoBuffer, 0, SCREEN_WIDTH*SCREEN_HEIGHT);
|
||||
}
|
146
engines/twine/screens.h
Normal file
146
engines/twine/screens.h
Normal file
@ -0,0 +1,146 @@
|
||||
/** @file images.h
|
||||
@brief
|
||||
This file contains image processing.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SCREENS_H
|
||||
#define SCREENS_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "main.h"
|
||||
|
||||
/** In-game palette (should not be used, except in special case. otherwise use other images functions instead) */
|
||||
uint8 palette[NUMOFCOLORS * 3];
|
||||
|
||||
/** SDL converted in-game palette */
|
||||
uint8 paletteRGBA[NUMOFCOLORS * 4];
|
||||
|
||||
/** SDL converted custom palette */
|
||||
uint8 paletteRGBACustom[NUMOFCOLORS * 4];
|
||||
|
||||
/** flag to check if a custom palette is in use */
|
||||
int16 palCustom;
|
||||
|
||||
/** flag to check in the game palette was changed */
|
||||
int16 palReseted;
|
||||
|
||||
/** flag to check if the main flag is locked */
|
||||
int16 lockPalette;
|
||||
|
||||
/** flag to check if we are using a different palette than the main one */
|
||||
int16 useAlternatePalette;
|
||||
|
||||
/** main game palette */
|
||||
uint8* mainPalette;
|
||||
|
||||
/** SDL converted in-game palette */
|
||||
uint8 mainPaletteRGBA[NUMOFCOLORS * 4];
|
||||
|
||||
/** Load and display Adeline Logo */
|
||||
void adelineLogo();
|
||||
|
||||
/** Load a custom palette
|
||||
@param index \a RESS.HQR entry index (starting from 0) */
|
||||
void loadCustomPalette(int32 index);
|
||||
|
||||
/** Load and display Main Menu image */
|
||||
void loadMenuImage(int16 fade_in);
|
||||
|
||||
/** Load and display a particulary image on \a RESS.HQR file with cross fade effect
|
||||
@param index \a RESS.HQR entry index (starting from 0)
|
||||
@param fade_in if we fade in before using the palette */
|
||||
void loadImage(int32 index, int16 fade_in);
|
||||
|
||||
/** Load and display a particulary image on \a RESS.HQR file with cross fade effect and delay
|
||||
@param index \a RESS.HQR entry index (starting from 0)
|
||||
@param time number of seconds to delay */
|
||||
void loadImageDelay(int32 index, int32 time);
|
||||
|
||||
/** Converts in-game palette to SDL palette
|
||||
@param palSource palette source with RGB
|
||||
@param palDest palette destination with RGBA */
|
||||
void convertPalToRGBA(uint8 * palSource, uint8 * palDest);
|
||||
|
||||
/** Fade image in
|
||||
@param palette current palette to fade in */
|
||||
void fadeIn(uint8 * palette);
|
||||
|
||||
/** Fade image out
|
||||
@param palette current palette to fade out */
|
||||
void fadeOut(uint8 * palette);
|
||||
|
||||
/** Calculate a new color component according with an intensity
|
||||
@param modifier color compenent
|
||||
@param color color value
|
||||
@param param unknown
|
||||
@param intensity intensity value to adjust
|
||||
@return new color component*/
|
||||
int32 crossDot(int32 modifier, int32 color, int32 param, int32 intensity);
|
||||
|
||||
/** Adjust palette intensity
|
||||
@param R red component of color
|
||||
@param G green component of color
|
||||
@param B blue component of color
|
||||
@param palette palette to adjust
|
||||
@param intensity intensity value to adjust */
|
||||
void adjustPalette(uint8 R, uint8 G, uint8 B, uint8 * palette, int32 intensity);
|
||||
|
||||
/** Adjust between two palettes
|
||||
@param pal1 palette from adjust
|
||||
@param pal2 palette to adjust */
|
||||
void adjustCrossPalette(uint8 * pal1, uint8 * pal2);
|
||||
|
||||
/** Fade image to black
|
||||
@param palette current palette to fade */
|
||||
void fadeToBlack(uint8 *palette);
|
||||
|
||||
/** Fade image with another palette source
|
||||
@param palette current palette to fade */
|
||||
void fadeToPal(uint8 *palette);
|
||||
|
||||
/** Fade black palette to white palette */
|
||||
void blackToWhite();
|
||||
|
||||
/** Resets both in-game and sdl palettes */
|
||||
void setBackPal();
|
||||
|
||||
/** Fade palette to red palette
|
||||
@param palette current palette to fade */
|
||||
void fadePalRed(uint8 *palette);
|
||||
|
||||
/** Fade red to palette
|
||||
@param palette current palette to fade */
|
||||
void fadeRedPal(uint8 *palette);
|
||||
|
||||
/** Copy a determinate screen buffer to another
|
||||
@param source screen buffer
|
||||
@param destination screen buffer */
|
||||
void copyScreen(uint8 * source, uint8 * destination);
|
||||
|
||||
/** Clear front buffer screen */
|
||||
void clearScreen();
|
||||
|
||||
/** Init palettes */
|
||||
void initPalettes();
|
||||
|
||||
#endif
|
1648
engines/twine/script.life.cpp
Normal file
1648
engines/twine/script.life.cpp
Normal file
File diff suppressed because it is too large
Load Diff
37
engines/twine/script.life.h
Normal file
37
engines/twine/script.life.h
Normal file
@ -0,0 +1,37 @@
|
||||
/** @file script.life.h
|
||||
@brief
|
||||
This file contains life-related routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTLIFE_H
|
||||
#define SCRIPTLIFE_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
#define MAX_TARGET_ACTOR_DISTANCE 0x7D00
|
||||
|
||||
/** Process actor life script
|
||||
@param actorIdx Current processed actor index */
|
||||
void processLifeScript(int32 actorIdx);
|
||||
|
||||
#endif
|
598
engines/twine/script.move.cpp
Normal file
598
engines/twine/script.move.cpp
Normal file
@ -0,0 +1,598 @@
|
||||
/** @file script.move.cpp
|
||||
@brief
|
||||
This file contains movies routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "script.move.h"
|
||||
#include "scene.h"
|
||||
#include "actor.h"
|
||||
#include "movements.h"
|
||||
#include "animations.h"
|
||||
#include "scene.h"
|
||||
#include "renderer.h"
|
||||
#include "sound.h"
|
||||
#include "redraw.h"
|
||||
#include "lbaengine.h"
|
||||
|
||||
uint8 *scriptPtr;
|
||||
int32 continueMove;
|
||||
int32 scriptPosition;
|
||||
ActorMoveStruct *move;
|
||||
int32 numRepeatSample = 1;
|
||||
|
||||
typedef int32 ScriptMoveFunc(int32 actorIdx, ActorStruct *actor);
|
||||
|
||||
typedef struct ScriptMoveFunction {
|
||||
const uint8 *name;
|
||||
ScriptMoveFunc *function;
|
||||
} ScriptMoveFunction;
|
||||
|
||||
#define MAPFUNC(name, func) {(uint8*)name, func}
|
||||
|
||||
|
||||
/*0x00*/
|
||||
int32 mEND(int32 actorIdx, ActorStruct *actor) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x01*/
|
||||
int32 mNOP(int32 actorIdx, ActorStruct *actor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x02*/
|
||||
int32 mBODY(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 bodyIdx = *(scriptPtr);
|
||||
initModelActor(bodyIdx, actorIdx);
|
||||
actor->positionInMoveScript++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x03*/
|
||||
int32 mANIM(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 animIdx = *(scriptPtr++);
|
||||
if (initAnim(animIdx, 0, 0, actorIdx)) {
|
||||
actor->positionInMoveScript++;
|
||||
} else {
|
||||
actor->positionInMoveScript = scriptPosition;
|
||||
continueMove = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x04*/
|
||||
int32 mGOTO_POINT(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 newAngle;
|
||||
|
||||
actor->positionInMoveScript++;
|
||||
currentScriptValue = *(scriptPtr);
|
||||
|
||||
destX = sceneTracks[currentScriptValue].X;
|
||||
destY = sceneTracks[currentScriptValue].Y;
|
||||
destZ = sceneTracks[currentScriptValue].Z;
|
||||
|
||||
newAngle = getAngleAndSetTargetActorDistance(actor->X, actor->Z, destX, destZ);
|
||||
|
||||
if (actor->staticFlags.bIsSpriteActor) {
|
||||
actor->angle = newAngle;
|
||||
} else {
|
||||
moveActor(actor->angle, newAngle, actor->speed, &actor->move);
|
||||
}
|
||||
|
||||
if (targetActorDistance > 500) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript -= 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x05*/
|
||||
int32 mWAIT_ANIM(int32 actorIdx, ActorStruct *actor) {
|
||||
if (!actor->dynamicFlags.bAnimEnded) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript--;
|
||||
} else {
|
||||
continueMove = 0;
|
||||
clearRealAngle(actor);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x06*/
|
||||
int32 mLOOP(int32 actorIdx, ActorStruct *actor) {
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*0x07*/
|
||||
int32 mANGLE(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript += 2;
|
||||
if (!actor->staticFlags.bIsSpriteActor) {
|
||||
currentScriptValue = *((int16 *)scriptPtr);
|
||||
if (actor->move.numOfStep == 0) {
|
||||
moveActor(actor->angle, currentScriptValue, actor->speed, move);
|
||||
}
|
||||
if (actor->angle == currentScriptValue) {
|
||||
clearRealAngle(actor);
|
||||
return 0;
|
||||
}
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript -= 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x08*/
|
||||
int32 mPOS_POINT(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript++;
|
||||
currentScriptValue = *(scriptPtr);
|
||||
|
||||
destX = sceneTracks[currentScriptValue].X;
|
||||
destY = sceneTracks[currentScriptValue].Y;
|
||||
destZ = sceneTracks[currentScriptValue].Z;
|
||||
|
||||
if (actor->staticFlags.bIsSpriteActor) {
|
||||
actor->speed = 0;
|
||||
}
|
||||
|
||||
actor->X = destX;
|
||||
actor->Y = destY;
|
||||
actor->Z = destZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x09*/
|
||||
int32 mLABEL(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->labelIdx = *(scriptPtr);
|
||||
actor->positionInMoveScript++;
|
||||
actor->currentLabelPtr = actor->positionInMoveScript - 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x0A*/
|
||||
int32 mGOTO(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript = *((int16 *)scriptPtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x0B*/
|
||||
int32 mSTOP(int32 actorIdx, ActorStruct *actor) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x0C*/
|
||||
int32 mGOTO_SYM_POINT(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 newAngle;
|
||||
|
||||
actor->positionInMoveScript++;
|
||||
currentScriptValue = *(scriptPtr);
|
||||
|
||||
destX = sceneTracks[currentScriptValue].X;
|
||||
destY = sceneTracks[currentScriptValue].Y;
|
||||
destZ = sceneTracks[currentScriptValue].Z;
|
||||
|
||||
newAngle = 0x200 + getAngleAndSetTargetActorDistance(actor->X, actor->Z, destX, destZ);
|
||||
|
||||
if (actor->staticFlags.bIsSpriteActor) {
|
||||
actor->angle = newAngle;
|
||||
} else {
|
||||
moveActor(actor->angle, newAngle, actor->speed, &actor->move);
|
||||
}
|
||||
|
||||
if (targetActorDistance > 500) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript -= 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x0D*/
|
||||
int32 mWAIT_NUM_ANIM(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript += 2;
|
||||
|
||||
if (actor->dynamicFlags.bAnimEnded) {
|
||||
int32 animPos, animRepeats;
|
||||
|
||||
animRepeats = *(scriptPtr);
|
||||
animPos = *(scriptPtr + 1);
|
||||
|
||||
animPos++;
|
||||
|
||||
if (animPos == animRepeats) {
|
||||
animPos = 0;
|
||||
} else {
|
||||
continueMove = 0;
|
||||
}
|
||||
|
||||
*(scriptPtr + 1) = animPos;
|
||||
} else {
|
||||
continueMove = 0;
|
||||
}
|
||||
|
||||
if (continueMove == 0) {
|
||||
actor->positionInMoveScript -= 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x0E*/
|
||||
int32 mSAMPLE(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 sampleIdx = *((int16 *)scriptPtr);
|
||||
playSample(sampleIdx, 0x1000, 1, actor->X, actor->Y, actor->Z, actorIdx);
|
||||
actor->positionInMoveScript += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x0F*/
|
||||
int32 mGOTO_POINT_3D(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript++;
|
||||
|
||||
if (actor->staticFlags.bIsSpriteActor) {
|
||||
currentScriptValue = *(scriptPtr);
|
||||
|
||||
destX = sceneTracks[currentScriptValue].X;
|
||||
destY = sceneTracks[currentScriptValue].Y;
|
||||
destZ = sceneTracks[currentScriptValue].Z;
|
||||
|
||||
actor->angle = getAngleAndSetTargetActorDistance(actor->X, actor->Z, destX, destZ);
|
||||
actor->animType = getAngleAndSetTargetActorDistance(actor->Y, 0, destY, targetActorDistance);
|
||||
|
||||
if (targetActorDistance > 100) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript -= 2;
|
||||
} else {
|
||||
actor->X = destX;
|
||||
actor->Y = destY;
|
||||
actor->Z = destZ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x10*/
|
||||
int32 mSPEED(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript += 2;
|
||||
actor->speed = *((int16 *)scriptPtr);
|
||||
|
||||
if (actor->staticFlags.bIsSpriteActor) {
|
||||
setActorAngle(0, actor->speed, 50, move);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x11*/
|
||||
int32 mBACKGROUND(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript++;
|
||||
|
||||
if (*(scriptPtr) != 0) {
|
||||
if (!actor->staticFlags.bIsBackgrounded) {
|
||||
actor->staticFlags.bIsBackgrounded = 1;
|
||||
if (actor->dynamicFlags.bIsVisible) {
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (actor->staticFlags.bIsBackgrounded) {
|
||||
actor->staticFlags.bIsBackgrounded = 0;
|
||||
if (actor->dynamicFlags.bIsVisible) {
|
||||
reqBgRedraw = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x12*/
|
||||
int32 mWAIT_NUM_SECOND(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 numSeconds, currentTime;
|
||||
actor->positionInMoveScript += 5;
|
||||
|
||||
numSeconds = *(scriptPtr++);
|
||||
currentTime = *((int32 *)scriptPtr);
|
||||
|
||||
if (currentTime == 0) {
|
||||
currentTime = lbaTime + numSeconds * 50;
|
||||
*((int32 *)scriptPtr) = currentTime;
|
||||
}
|
||||
|
||||
if (lbaTime < currentTime) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript -= 6;
|
||||
} else {
|
||||
*((int32 *)scriptPtr) = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x13*/
|
||||
int32 mNO_BODY(int32 actorIdx, ActorStruct *actor) {
|
||||
initModelActor(-1, actorIdx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x14*/
|
||||
int32 mBETA(int32 actorIdx, ActorStruct *actor) {
|
||||
int16 beta;
|
||||
|
||||
beta = *((int16 *)scriptPtr);
|
||||
actor->positionInMoveScript += 2;
|
||||
|
||||
actor->angle = beta;
|
||||
|
||||
if (actor->staticFlags.bIsSpriteActor) {
|
||||
clearRealAngle(actor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x15*/
|
||||
int32 mOPEN_LEFT(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript += 2;
|
||||
if (actor->staticFlags.bIsSpriteActor && actor->staticFlags.bUsesClipping) {
|
||||
actor->angle = 0x300;
|
||||
actor->doorStatus = *((int16 *)scriptPtr);
|
||||
actor->dynamicFlags.bIsSpriteMoving = 1;
|
||||
actor->speed = 1000;
|
||||
setActorAngle(0, 1000, 50, move);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x16*/
|
||||
int32 mOPEN_RIGHT(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript += 2;
|
||||
if (actor->staticFlags.bIsSpriteActor && actor->staticFlags.bUsesClipping) {
|
||||
actor->angle = 0x100;
|
||||
actor->doorStatus = *((int16 *)scriptPtr);
|
||||
actor->dynamicFlags.bIsSpriteMoving = 1;
|
||||
actor->speed = 1000;
|
||||
setActorAngle(0, 1000, 50, move);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x17*/
|
||||
int32 mOPEN_UP(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript += 2;
|
||||
if (actor->staticFlags.bIsSpriteActor && actor->staticFlags.bUsesClipping) {
|
||||
actor->angle = 0x200;
|
||||
actor->doorStatus = *((int16 *)scriptPtr);
|
||||
actor->dynamicFlags.bIsSpriteMoving = 1;
|
||||
actor->speed = 1000;
|
||||
setActorAngle(0, 1000, 50, move);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x18*/
|
||||
int32 mOPEN_DOWN(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript += 2;
|
||||
if (actor->staticFlags.bIsSpriteActor && actor->staticFlags.bUsesClipping) {
|
||||
actor->angle = 0;
|
||||
actor->doorStatus = *((int16 *)scriptPtr);
|
||||
actor->dynamicFlags.bIsSpriteMoving = 1;
|
||||
actor->speed = 1000;
|
||||
setActorAngle(0, 1000, 50, move);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x19*/
|
||||
int32 mCLOSE(int32 actorIdx, ActorStruct *actor) {
|
||||
if (actor->staticFlags.bIsSpriteActor && actor->staticFlags.bUsesClipping) {
|
||||
actor->doorStatus = 0;
|
||||
actor->dynamicFlags.bIsSpriteMoving = 1;
|
||||
actor->speed = -1000;
|
||||
setActorAngle(0, -1000, 50, move);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x1A*/
|
||||
int32 mWAIT_DOOR(int32 actorIdx, ActorStruct *actor) {
|
||||
if (actor->staticFlags.bIsSpriteActor && actor->staticFlags.bUsesClipping) {
|
||||
if (actor->speed) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x1B*/
|
||||
int32 mSAMPLE_RND(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 freq = Rnd(2048) + 2048;
|
||||
int32 sampleIdx = *((int16 *)scriptPtr);
|
||||
playSample(sampleIdx, freq, 1, actor->X, actor->Y, actor->Z, actorIdx);
|
||||
actor->positionInMoveScript += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x1C*/
|
||||
int32 mSAMPLE_ALWAYS(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 sampleIdx = *((int16 *)scriptPtr);
|
||||
if (getSampleChannel(sampleIdx) == -1) { // if its not playing
|
||||
playSample(sampleIdx, 0x1000, -1, actor->X, actor->Y, actor->Z, actorIdx);
|
||||
}
|
||||
actor->positionInMoveScript += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x1D*/
|
||||
int32 mSAMPLE_STOP(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 sampleIdx = *((int16 *)scriptPtr);
|
||||
stopSample(sampleIdx);
|
||||
actor->positionInMoveScript += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x1E*/
|
||||
int32 mPLAY_FLA(int32 actorIdx, ActorStruct *actor) {
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*0x1F*/
|
||||
int32 mREPEAT_SAMPLE(int32 actorIdx, ActorStruct *actor) {
|
||||
numRepeatSample = *((int16 *)scriptPtr);
|
||||
actor->positionInMoveScript += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x20*/
|
||||
int32 mSIMPLE_SAMPLE(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 sampleIdx = *((int16 *)scriptPtr);
|
||||
playSample(sampleIdx, 0x1000, numRepeatSample, actor->X, actor->Y, actor->Z, actorIdx);
|
||||
numRepeatSample = 1;
|
||||
actor->positionInMoveScript += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x21*/
|
||||
int32 mFACE_HERO(int32 actorIdx, ActorStruct *actor) {
|
||||
actor->positionInMoveScript += 2;
|
||||
if (!actor->staticFlags.bIsSpriteActor) {
|
||||
currentScriptValue = *((int16 *)scriptPtr);
|
||||
if (currentScriptValue == -1 && actor->move.numOfStep == 0) {
|
||||
currentScriptValue = getAngleAndSetTargetActorDistance(actor->X, actor->Z, sceneHero->X, sceneHero->Z);
|
||||
moveActor(actor->angle, currentScriptValue, actor->speed, &actor->move);
|
||||
*((int16 *)scriptPtr) = currentScriptValue;
|
||||
}
|
||||
|
||||
if (actor->angle != currentScriptValue) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript -= 3;
|
||||
} else {
|
||||
clearRealAngle(actor);
|
||||
*((int16 *)scriptPtr) = -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*0x22*/
|
||||
int32 mANGLE_RND(int32 actorIdx, ActorStruct *actor) {
|
||||
int32 newAngle;
|
||||
|
||||
actor->positionInMoveScript += 4;
|
||||
if (!actor->staticFlags.bIsSpriteActor) {
|
||||
currentScriptValue = *((int16 *)scriptPtr + 2);
|
||||
|
||||
if (currentScriptValue == -1 && actor->move.numOfStep == 0) {
|
||||
if (rand() & 1) {
|
||||
currentScriptValue = *((int16 *)scriptPtr);
|
||||
newAngle = actor->angle + 0x100 + (Abs(currentScriptValue) >> 1);
|
||||
currentScriptValue = (newAngle - Rnd(currentScriptValue)) & 0x3FF;
|
||||
} else {
|
||||
currentScriptValue = *((int16 *)scriptPtr);
|
||||
newAngle = actor->angle - 0x100 + (Abs(currentScriptValue) >> 1);
|
||||
currentScriptValue = (newAngle - Rnd(currentScriptValue)) & 0x3FF;
|
||||
}
|
||||
|
||||
moveActor(actor->angle, currentScriptValue, actor->speed, &actor->move);
|
||||
*((int16 *)scriptPtr + 2) = currentScriptValue;
|
||||
}
|
||||
|
||||
if (actor->angle != currentScriptValue) {
|
||||
continueMove = 0;
|
||||
actor->positionInMoveScript -= 5;
|
||||
} else {
|
||||
clearRealAngle(actor);
|
||||
*((int16 *)scriptPtr + 2) = -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const ScriptMoveFunction function_map[] = {
|
||||
/*0x00*/ MAPFUNC("END", mEND),
|
||||
/*0x01*/ MAPFUNC("NOP", mNOP),
|
||||
/*0x02*/ MAPFUNC("BODY", mBODY),
|
||||
/*0x03*/ MAPFUNC("ANIM", mANIM),
|
||||
/*0x04*/ MAPFUNC("GOTO_POINT", mGOTO_POINT),
|
||||
/*0x05*/ MAPFUNC("WAIT_ANIM", mWAIT_ANIM),
|
||||
/*0x06*/ MAPFUNC("LOOP", mLOOP),
|
||||
/*0x07*/ MAPFUNC("ANGLE", mANGLE),
|
||||
/*0x08*/ MAPFUNC("POS_POINT", mPOS_POINT),
|
||||
/*0x09*/ MAPFUNC("LABEL", mLABEL),
|
||||
/*0x0A*/ MAPFUNC("GOTO", mGOTO),
|
||||
/*0x0B*/ MAPFUNC("STOP", mSTOP),
|
||||
/*0x0C*/ MAPFUNC("GOTO_SYM_POINT", mGOTO_SYM_POINT),
|
||||
/*0x0D*/ MAPFUNC("WAIT_NUM_ANIM", mWAIT_NUM_ANIM),
|
||||
/*0x0E*/ MAPFUNC("SAMPLE", mSAMPLE),
|
||||
/*0x0F*/ MAPFUNC("GOTO_POINT_3D", mGOTO_POINT_3D),
|
||||
/*0x10*/ MAPFUNC("SPEED", mSPEED),
|
||||
/*0x11*/ MAPFUNC("BACKGROUND", mBACKGROUND),
|
||||
/*0x12*/ MAPFUNC("WAIT_NUM_SECOND", mWAIT_NUM_SECOND),
|
||||
/*0x13*/ MAPFUNC("NO_BODY", mNO_BODY),
|
||||
/*0x14*/ MAPFUNC("BETA", mBETA),
|
||||
/*0x15*/ MAPFUNC("OPEN_LEFT", mOPEN_LEFT),
|
||||
/*0x16*/ MAPFUNC("OPEN_RIGHT", mOPEN_RIGHT),
|
||||
/*0x17*/ MAPFUNC("OPEN_UP", mOPEN_UP),
|
||||
/*0x18*/ MAPFUNC("OPEN_DOWN", mOPEN_DOWN),
|
||||
/*0x19*/ MAPFUNC("CLOSE", mCLOSE),
|
||||
/*0x1A*/ MAPFUNC("WAIT_DOOR", mWAIT_DOOR),
|
||||
/*0x1B*/ MAPFUNC("SAMPLE_RND", mSAMPLE_RND),
|
||||
/*0x1C*/ MAPFUNC("SAMPLE_ALWAYS", mSAMPLE_ALWAYS),
|
||||
/*0x1D*/ MAPFUNC("SAMPLE_STOP", mSAMPLE_STOP),
|
||||
/*0x1E*/ MAPFUNC("PLAY_FLA", mPLAY_FLA),
|
||||
/*0x1F*/ MAPFUNC("REPEAT_SAMPLE", mREPEAT_SAMPLE),
|
||||
/*0x20*/ MAPFUNC("SIMPLE_SAMPLE", mSIMPLE_SAMPLE),
|
||||
/*0x21*/ MAPFUNC("FACE_HERO", mFACE_HERO),
|
||||
/*0x22*/ MAPFUNC("ANGLE_RND", mANGLE_RND)
|
||||
};
|
||||
|
||||
/** Process actor move script
|
||||
@param actorIdx Current processed actor index */
|
||||
void processMoveScript(int32 actorIdx) {
|
||||
int32 scriptOpcode;
|
||||
ActorStruct *actor;
|
||||
|
||||
continueMove = 1;
|
||||
actor = &sceneActors[actorIdx];
|
||||
move = &actor->move;
|
||||
|
||||
do {
|
||||
scriptPosition = actor->positionInMoveScript;
|
||||
scriptPtr = actor->moveScript + scriptPosition;
|
||||
scriptOpcode = *(scriptPtr++);
|
||||
|
||||
actor->positionInMoveScript++;
|
||||
|
||||
function_map[scriptOpcode].function(actorIdx, actor);
|
||||
} while(continueMove);
|
||||
}
|
35
engines/twine/script.move.h
Normal file
35
engines/twine/script.move.h
Normal file
@ -0,0 +1,35 @@
|
||||
/** @file script.move.h
|
||||
@brief
|
||||
This file contains movements routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTMOVE_H
|
||||
#define SCRIPTMOVE_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/** Process actor move script
|
||||
@param actorIdx Current processed actor index */
|
||||
void processMoveScript(int32 actorIdx);
|
||||
|
||||
#endif
|
601
engines/twine/sdlengine.cpp
Normal file
601
engines/twine/sdlengine.cpp
Normal file
@ -0,0 +1,601 @@
|
||||
/** @file sdlengine.cpp
|
||||
@brief
|
||||
This file contains SDL engine routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_thread.h>
|
||||
#ifndef MACOSX
|
||||
#include <SDL/SDL_mixer.h>
|
||||
#else
|
||||
#include <SDL_mixer/SDL_mixer.h>
|
||||
#endif
|
||||
|
||||
#ifdef GAMEMOD
|
||||
#ifndef MACOSX
|
||||
#include <SDL/SDL_ttf.h>
|
||||
#else
|
||||
#include <SDL_ttf/SDL_ttf.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "sdlengine.h"
|
||||
#include "main.h"
|
||||
#include "screens.h"
|
||||
#include "music.h"
|
||||
#include "lbaengine.h"
|
||||
#include "debug.h"
|
||||
#include "keyboard.h"
|
||||
#include "redraw.h"
|
||||
|
||||
/** SDL exit callback */
|
||||
//static void atexit_callback(void);
|
||||
|
||||
/** Original audio frequency */
|
||||
#define ORIGINAL_GAME_FREQUENCY 11025
|
||||
/** High quality audio frequency */
|
||||
#define HIGH_QUALITY_FREQUENCY 44100
|
||||
|
||||
/** Main SDL screen surface buffer */
|
||||
SDL_Surface *screen = NULL;
|
||||
/** Auxiliar SDL screen surface buffer */
|
||||
SDL_Surface *screenBuffer = NULL;
|
||||
/** SDL screen color */
|
||||
SDL_Color screenColors[256];
|
||||
/** Auxiliar surface table */
|
||||
SDL_Surface *surfaceTable[16];
|
||||
|
||||
#ifdef GAMEMOD
|
||||
TTF_Font *font;
|
||||
#endif
|
||||
|
||||
/** SDL exit callback */
|
||||
//static void atexit_callback(void) {
|
||||
// sdlClose();
|
||||
//}
|
||||
|
||||
void sdlClose() {
|
||||
stopTrackMusic();
|
||||
stopMidiMusic();
|
||||
Mix_CloseAudio();
|
||||
#ifdef GAMEMOD
|
||||
TTF_Quit();
|
||||
#endif
|
||||
SDL_Quit();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/** SDL initializer
|
||||
@return SDL init state */
|
||||
int sdlInitialize() {
|
||||
uint8 *keyboard;
|
||||
int32 size;
|
||||
int32 i;
|
||||
int32 freq;
|
||||
//SDL_Surface* icon;
|
||||
|
||||
Uint32 rmask, gmask, bmask;
|
||||
// Uint32 amask;
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
rmask = 0xff000000;
|
||||
gmask = 0x00ff0000;
|
||||
bmask = 0x0000ff00;
|
||||
#else
|
||||
rmask = 0x000000ff;
|
||||
gmask = 0x0000ff00;
|
||||
bmask = 0x00ff0000;
|
||||
#endif
|
||||
|
||||
printf("Initialising SDL device. Please wait...\n");
|
||||
|
||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
|
||||
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef GAMEMOD
|
||||
if (TTF_Init() < 0) {
|
||||
fprintf(stderr, "Couldn't initialize TTF: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
font = TTF_OpenFont("FreeMono.ttf", 12);
|
||||
|
||||
if (font == NULL) {
|
||||
fprintf(stderr, "Couldn't load %d pt font from %s: %s\n", 12, "FreeMono.ttf", SDL_GetError());
|
||||
exit(2);
|
||||
}
|
||||
|
||||
TTF_SetFontStyle(font, 0);
|
||||
#endif
|
||||
|
||||
|
||||
/*icon = SDL_LoadBMP("icon.bmp");
|
||||
SDL_WM_SetIcon(icon, NULL);*/
|
||||
|
||||
if (cfgfile.Debug) {
|
||||
SDL_version compile_version;
|
||||
const SDL_version *link_version;
|
||||
SDL_VERSION(&compile_version);
|
||||
printf("Compiled with SDL version: %d.%d.%d\n", compile_version.major, compile_version.minor, compile_version.patch);
|
||||
link_version = SDL_Linked_Version();
|
||||
printf("Running with SDL version: %d.%d.%d\n\n", link_version->major, link_version->minor, link_version->patch);
|
||||
}
|
||||
|
||||
printf("Initialising Sound device. Please wait...\n\n");
|
||||
|
||||
// Verify if we want to use high quality sounds
|
||||
if (cfgfile.Sound > 1)
|
||||
freq = HIGH_QUALITY_FREQUENCY;
|
||||
else
|
||||
freq = ORIGINAL_GAME_FREQUENCY;
|
||||
|
||||
if (Mix_OpenAudio(freq, AUDIO_S16, 2, 256) < 0) {
|
||||
printf("Mix_OpenAudio: %s\n", Mix_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Mix_AllocateChannels(32);
|
||||
|
||||
SDL_WM_SetCaption("Little Big Adventure: TwinEngine", "twin-e");
|
||||
SDL_PumpEvents();
|
||||
|
||||
keyboard = SDL_GetKeyState(&size);
|
||||
|
||||
keyboard[SDLK_RETURN] = 0;
|
||||
|
||||
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
|
||||
|
||||
if (screen == NULL) {
|
||||
fprintf(stderr, "Couldn't set 640x480x8 video mode: %s\n\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
surfaceTable[i] = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 32, rmask, gmask, bmask, 0);
|
||||
}
|
||||
|
||||
atexit(SDL_Quit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Frames per second sdl delay
|
||||
@param fps frames per second */
|
||||
void fpsCycles(int32 fps) {
|
||||
SDL_Delay(1000 / (fps));
|
||||
}
|
||||
|
||||
/** Deplay certain seconds till proceed
|
||||
@param time time in seconds to delay */
|
||||
void sdldelay(uint32 time) {
|
||||
SDL_Delay(time);
|
||||
}
|
||||
|
||||
/** Deplay certain seconds till proceed - Can skip delay
|
||||
@param time time in seconds to delay */
|
||||
void delaySkip(uint32 time) {
|
||||
uint32 startTicks = SDL_GetTicks();
|
||||
uint32 stopTicks = 0;
|
||||
skipIntro = 0;
|
||||
do {
|
||||
readKeys();
|
||||
if (skipIntro == 1)
|
||||
break;
|
||||
stopTicks = SDL_GetTicks() - startTicks;
|
||||
SDL_Delay(1);
|
||||
//lbaTime++;
|
||||
} while (stopTicks <= time);
|
||||
}
|
||||
|
||||
/** Set a new palette in the SDL screen buffer
|
||||
@param palette palette to set */
|
||||
void setPalette(uint8 * palette) {
|
||||
SDL_Color *screenColorsTemp = (SDL_Color *) palette;
|
||||
|
||||
SDL_SetColors(screenBuffer, screenColorsTemp, 0, 256);
|
||||
SDL_BlitSurface(screenBuffer, NULL, screen, NULL);
|
||||
SDL_UpdateRect(screen, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/** Fade screen from black to white */
|
||||
void fadeBlackToWhite() {
|
||||
int32 i;
|
||||
|
||||
SDL_Color colorPtr[256];
|
||||
|
||||
SDL_UpdateRect(screen, 0, 0, 0, 0);
|
||||
|
||||
for (i = 0; i < 256; i += 3) {
|
||||
memset(colorPtr, i, 1024);
|
||||
SDL_SetPalette(screen, SDL_PHYSPAL, colorPtr, 0, 256);
|
||||
}
|
||||
}
|
||||
|
||||
/** Blit surface in the screen */
|
||||
void flip() {
|
||||
SDL_BlitSurface(screenBuffer, NULL, screen, NULL);
|
||||
SDL_UpdateRect(screen, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/** Blit surface in the screen in a determinate area
|
||||
@param left left position to start copy
|
||||
@param top top position to start copy
|
||||
@param right right position to start copy
|
||||
@param bottom bottom position to start copy */
|
||||
void copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom) {
|
||||
SDL_Rect rectangle;
|
||||
|
||||
rectangle.x = left;
|
||||
rectangle.y = top;
|
||||
rectangle.w = right - left + 1 ;
|
||||
rectangle.h = bottom - top + 1 ;
|
||||
|
||||
SDL_BlitSurface(screenBuffer, &rectangle, screen, &rectangle);
|
||||
SDL_UpdateRect(screen, left, top, right - left + 1, bottom - top + 1);
|
||||
}
|
||||
|
||||
/** Create SDL screen surface
|
||||
@param buffer screen buffer to blit surface
|
||||
@param width screen width size
|
||||
@param height screen height size */
|
||||
void initScreenBuffer(uint8 *buffer, int32 width, int32 height) {
|
||||
screenBuffer = SDL_CreateRGBSurfaceFrom(buffer, width, height, 8, SCREEN_WIDTH, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/** Cross fade feature
|
||||
@param buffer screen buffer
|
||||
@param palette new palette to cross fade */
|
||||
void crossFade(uint8 *buffer, uint8 *palette) {
|
||||
int32 i;
|
||||
SDL_Surface *backupSurface;
|
||||
SDL_Surface *newSurface;
|
||||
SDL_Surface *tempSurface;
|
||||
Uint32 rmask, gmask, bmask;
|
||||
// Uint32 amask;
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
rmask = 0xff000000;
|
||||
gmask = 0x00ff0000;
|
||||
bmask = 0x0000ff00;
|
||||
#else
|
||||
rmask = 0x000000ff;
|
||||
gmask = 0x0000ff00;
|
||||
bmask = 0x00ff0000;
|
||||
#endif
|
||||
|
||||
backupSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 32, rmask, gmask, bmask, 0);
|
||||
newSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, SCREEN_WIDTH, SCREEN_HEIGHT, 32, rmask, gmask, bmask, 0);
|
||||
|
||||
tempSurface = SDL_CreateRGBSurfaceFrom(buffer, SCREEN_WIDTH, SCREEN_HEIGHT, 8, SCREEN_WIDTH, 0, 0, 0, 0);
|
||||
SDL_SetColors(tempSurface, (SDL_Color *) palette, 0, 256);
|
||||
|
||||
SDL_BlitSurface(screen, NULL, backupSurface, NULL);
|
||||
SDL_BlitSurface(tempSurface, NULL, newSurface, NULL);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
SDL_BlitSurface(backupSurface, NULL, surfaceTable[i], NULL);
|
||||
SDL_SetAlpha(newSurface, SDL_SRCALPHA | SDL_RLEACCEL, i * 32);
|
||||
SDL_BlitSurface(newSurface, NULL, surfaceTable[i], NULL);
|
||||
SDL_BlitSurface(surfaceTable[i], NULL, screen, NULL);
|
||||
SDL_UpdateRect(screen, 0, 0, 0, 0);
|
||||
delaySkip(50);
|
||||
}
|
||||
|
||||
SDL_BlitSurface(newSurface, NULL, screen, NULL);
|
||||
SDL_UpdateRect(screen, 0, 0, 0, 0);
|
||||
|
||||
SDL_FreeSurface(backupSurface);
|
||||
SDL_FreeSurface(newSurface);
|
||||
SDL_FreeSurface(tempSurface);
|
||||
}
|
||||
|
||||
/** Switch between window and fullscreen modes */
|
||||
void toggleFullscreen() {
|
||||
cfgfile.FullScreen = 1 - cfgfile.FullScreen;
|
||||
SDL_FreeSurface(screen);
|
||||
|
||||
reqBgRedraw = 1;
|
||||
|
||||
if (cfgfile.FullScreen) {
|
||||
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
SDL_ShowCursor(1);
|
||||
} else {
|
||||
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE | SDL_FULLSCREEN);
|
||||
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||||
|
||||
#ifdef _DEBUG
|
||||
SDL_ShowCursor(1);
|
||||
#else
|
||||
SDL_ShowCursor(0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle keyboard pressed keys */
|
||||
void readKeys() {
|
||||
SDL_Event event;
|
||||
int32 localKey;
|
||||
int32 i, j, size;
|
||||
int32 find = 0;
|
||||
int16 temp;
|
||||
uint8 temp2;
|
||||
int8 found = 0;
|
||||
uint8 *keyboard;
|
||||
|
||||
localKey = 0;
|
||||
skippedKey = 0;
|
||||
skipIntro = 0;
|
||||
|
||||
SDL_PumpEvents();
|
||||
|
||||
keyboard = SDL_GetKeyState(&size);
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
sdlClose();
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
switch (event.button.button) {
|
||||
case SDL_BUTTON_RIGHT:
|
||||
rightMouse = 1;
|
||||
break;
|
||||
case SDL_BUTTON_LEFT:
|
||||
leftMouse = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
pressedKey = 0;
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
localKey = 0x1;
|
||||
break;
|
||||
case SDLK_SPACE:
|
||||
localKey = 0x39;
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
case SDLK_KP_ENTER:
|
||||
localKey = 0x1C;
|
||||
break;
|
||||
case SDLK_LSHIFT:
|
||||
case SDLK_RSHIFT:
|
||||
localKey = 0x36;
|
||||
break;
|
||||
case SDLK_LALT:
|
||||
case SDLK_RALT:
|
||||
localKey = 0x38;
|
||||
break;
|
||||
case SDLK_LCTRL:
|
||||
case SDLK_RCTRL:
|
||||
localKey = 0x1D;
|
||||
break;
|
||||
case SDLK_PAGEUP:
|
||||
localKey = 0x49;
|
||||
break;
|
||||
case SDLK_p: // pause
|
||||
localKey = 0x19;
|
||||
break;
|
||||
case SDLK_h: // holomap
|
||||
localKey = 0x23;
|
||||
break;
|
||||
case SDLK_j:
|
||||
localKey = 0x24;
|
||||
break;
|
||||
case SDLK_w: // Especial key to do the action
|
||||
localKey = 0x11;
|
||||
break;
|
||||
case SDLK_F1:
|
||||
localKey = 0x3B;
|
||||
break;
|
||||
case SDLK_F2:
|
||||
localKey = 0x3C;
|
||||
break;
|
||||
case SDLK_F3:
|
||||
localKey = 0x3D;
|
||||
break;
|
||||
case SDLK_F4:
|
||||
localKey = 0x3E;
|
||||
break;
|
||||
case SDLK_F6:
|
||||
localKey = 0x40;
|
||||
break;
|
||||
case SDLK_F12:
|
||||
toggleFullscreen();
|
||||
break;
|
||||
#ifdef GAMEMOD
|
||||
case SDLK_r: // next room
|
||||
localKey = 0x13;
|
||||
break;
|
||||
case SDLK_f: // previous room
|
||||
localKey = 0x21;
|
||||
break;
|
||||
case SDLK_t: // apply celling grid
|
||||
localKey = 0x14;
|
||||
break;
|
||||
case SDLK_g: // increase celling grid index
|
||||
localKey = 0x22;
|
||||
break;
|
||||
case SDLK_b: // decrease celling grid index
|
||||
localKey = 0x30;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < size; j++) {
|
||||
if (keyboard[j]) {
|
||||
switch (j) {
|
||||
case SDLK_RETURN:
|
||||
case SDLK_KP_ENTER:
|
||||
localKey = 0x1C;
|
||||
break;
|
||||
case SDLK_SPACE:
|
||||
localKey = 0x39;
|
||||
break;
|
||||
case SDLK_UP:
|
||||
case SDLK_KP8:
|
||||
localKey = 0x48;
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
case SDLK_KP2:
|
||||
localKey = 0x50;
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
case SDLK_KP4:
|
||||
localKey = 0x4B;
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
case SDLK_KP6:
|
||||
localKey = 0x4D;
|
||||
break;
|
||||
case SDLK_LCTRL:
|
||||
case SDLK_RCTRL:
|
||||
localKey = 0x1D;
|
||||
break;
|
||||
/*case SDLK_LSHIFT:
|
||||
case SDLK_RSHIFT:
|
||||
localKey = 0x36;
|
||||
break;*/
|
||||
case SDLK_LALT:
|
||||
case SDLK_RALT:
|
||||
localKey = 0x38;
|
||||
break;
|
||||
case SDLK_F1:
|
||||
localKey = 0x3B;
|
||||
break;
|
||||
case SDLK_F2:
|
||||
localKey = 0x3C;
|
||||
break;
|
||||
case SDLK_F3:
|
||||
localKey = 0x3D;
|
||||
break;
|
||||
case SDLK_F4:
|
||||
localKey = 0x3E;
|
||||
break;
|
||||
#ifdef GAMEMOD
|
||||
// change grid camera
|
||||
case SDLK_s:
|
||||
localKey = 0x1F;
|
||||
break;
|
||||
case SDLK_x:
|
||||
localKey = 0x2D;
|
||||
break;
|
||||
case SDLK_z:
|
||||
localKey = 0x2C;
|
||||
break;
|
||||
case SDLK_c:
|
||||
localKey = 0x2E;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 28; i++) {
|
||||
if (pressedKeyMap[i] == localKey) {
|
||||
find = i;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != 0) {
|
||||
temp = pressedKeyCharMap[find];
|
||||
temp2 = temp & 0x00FF;
|
||||
|
||||
if (temp2 == 0) {
|
||||
// pressed valid keys
|
||||
if (!(localKey & 0x80)) {
|
||||
pressedKey |= (temp & 0xFF00) >> 8;
|
||||
} else {
|
||||
pressedKey &= -((temp & 0xFF00) >> 8);
|
||||
}
|
||||
}
|
||||
// pressed inactive keys
|
||||
else {
|
||||
skippedKey |= (temp & 0xFF00) >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
//if (found==0) {
|
||||
skipIntro = localKey;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GAMEMOD
|
||||
|
||||
/** Display SDL text in screen
|
||||
@param X X coordinate in screen
|
||||
@param Y Y coordinate in screen
|
||||
@param string text to display
|
||||
@param center if the text should be centered accoding with the giving positions */
|
||||
void ttfDrawText(int32 X, int32 Y, int8 *string, int32 center) {
|
||||
SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 };
|
||||
SDL_Color *forecol = &white;
|
||||
SDL_Rect rectangle;
|
||||
|
||||
SDL_Surface *text;
|
||||
|
||||
text = TTF_RenderText_Solid(font, string, *forecol);
|
||||
|
||||
if (center)
|
||||
rectangle.x = X - (text->w / 2);
|
||||
else
|
||||
rectangle.x = X;
|
||||
rectangle.y = Y - 2;
|
||||
rectangle.w = text->w;
|
||||
rectangle.h = text->h;
|
||||
|
||||
SDL_BlitSurface(text, NULL, screenBuffer, &rectangle);
|
||||
SDL_FreeSurface(text);
|
||||
}
|
||||
|
||||
/** Gets SDL mouse positions
|
||||
@param mouseData structure that contains mouse position info */
|
||||
void getMousePositions(MouseStatusStruct *mouseData) {
|
||||
SDL_GetMouseState(&mouseData->X, &mouseData->Y);
|
||||
|
||||
mouseData->left = leftMouse;
|
||||
mouseData->right = rightMouse;
|
||||
|
||||
leftMouse = 0;
|
||||
rightMouse = 0;
|
||||
}
|
||||
|
||||
#endif
|
100
engines/twine/sdlengine.h
Normal file
100
engines/twine/sdlengine.h
Normal file
@ -0,0 +1,100 @@
|
||||
/** @file sdlengine.h
|
||||
@brief
|
||||
This file contains SDL engine routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SCREEN_H
|
||||
#define SCREEN_H
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include "sys.h"
|
||||
#include "debug.h"
|
||||
|
||||
/** Main SDL screen surface buffer */
|
||||
extern SDL_Surface *screen;
|
||||
|
||||
/** Close everything in the game */
|
||||
void sdlClose();
|
||||
|
||||
/** SDL initializer
|
||||
@return SDL init state */
|
||||
int sdlInitialize();
|
||||
|
||||
/** Frames per second sdl delay */
|
||||
void fpsCycles(int32 fps);
|
||||
|
||||
/** Deplay certain seconds till proceed
|
||||
@param time time in seconds to delay */
|
||||
void sdldelay(uint32 time);
|
||||
|
||||
/** Deplay certain seconds till proceed - Can also Skip this delay
|
||||
@param time time in seconds to delay */
|
||||
void delaySkip(uint32 time);
|
||||
|
||||
/** Set a new palette in the SDL screen buffer
|
||||
@param palette palette to set */
|
||||
void setPalette(uint8 * palette);
|
||||
|
||||
/** Fade screen from black to white */
|
||||
void fadeBlackToWhite();
|
||||
|
||||
/** Blit surface in the screen */
|
||||
void flip();
|
||||
|
||||
/** Blit surface in the screen in a determinate area
|
||||
@param left left position to start copy
|
||||
@param top top position to start copy
|
||||
@param right right position to start copy
|
||||
@param bottom bottom position to start copy */
|
||||
void copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom);
|
||||
|
||||
/** Create SDL screen surface
|
||||
@param buffer screen buffer to blit surface
|
||||
@param width screen width size
|
||||
@param height screen height size */
|
||||
void initScreenBuffer(uint8 *buffer, int32 width, int32 height);
|
||||
|
||||
/** Cross fade feature
|
||||
@param buffer screen buffer
|
||||
@param palette new palette to cross fade*/
|
||||
void crossFade(uint8 *buffer, uint8 *palette);
|
||||
|
||||
/** Switch between window and fullscreen modes */
|
||||
void toggleFullscreen();
|
||||
|
||||
/** Handle keyboard pressed keys */
|
||||
void readKeys();
|
||||
|
||||
/** Display SDL text in screen
|
||||
@param X X coordinate in screen
|
||||
@param Y Y coordinate in screen
|
||||
@param string text to display
|
||||
@param center if the text should be centered accoding with the giving positions */
|
||||
void ttfDrawText(int32 X, int32 Y, int8 *string, int32 center);
|
||||
|
||||
/** Gets SDL mouse positions
|
||||
@param mouseData structure that contains mouse position info */
|
||||
void getMousePositions(MouseStatusStruct *mouseData);
|
||||
|
||||
#endif
|
1057
engines/twine/shadeangletab.h
Normal file
1057
engines/twine/shadeangletab.h
Normal file
File diff suppressed because it is too large
Load Diff
295
engines/twine/sound.cpp
Normal file
295
engines/twine/sound.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
/** @file sound.cpp
|
||||
@brief
|
||||
This file contains music playing routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
#ifndef MACOSX
|
||||
#include <SDL/SDL_mixer.h>
|
||||
#else
|
||||
#include <SDL_mixer/SDL_mixer.h>
|
||||
#endif
|
||||
|
||||
#include "sound.h"
|
||||
#include "flamovies.h"
|
||||
#include "main.h"
|
||||
#include "resources.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "movements.h"
|
||||
#include "grid.h"
|
||||
#include "collision.h"
|
||||
#include "text.h"
|
||||
|
||||
/** SDL_Mixer channels */
|
||||
int32 channel;
|
||||
/** Samples chunk variable */
|
||||
Mix_Chunk *sample;
|
||||
|
||||
int32 channelIdx = -1;
|
||||
|
||||
/** Sample volume
|
||||
@param channel sample channel
|
||||
@param volume sample volume number */
|
||||
void sampleVolume(int32 channel, int32 volume) {
|
||||
Mix_Volume(channel, volume / 2);
|
||||
}
|
||||
|
||||
/** Play FLA movie samples
|
||||
@param index sample index under flasamp.hqr file
|
||||
@param frequency frequency used to play the sample
|
||||
@param repeat number of times to repeat the sample
|
||||
@param x unknown x variable
|
||||
@param y unknown y variable */
|
||||
void playFlaSample(int32 index, int32 frequency, int32 repeat, int32 x, int32 y) {
|
||||
if (cfgfile.Sound) {
|
||||
int32 sampSize = 0;
|
||||
int8 sampfile[256];
|
||||
SDL_RWops *rw;
|
||||
uint8* sampPtr;
|
||||
|
||||
sprintf(sampfile, FLA_DIR "%s",HQR_FLASAMP_FILE);
|
||||
|
||||
sampSize = hqrGetallocEntry(&sampPtr, sampfile, index);
|
||||
|
||||
// Fix incorrect sample files first byte
|
||||
if (*sampPtr != 'C')
|
||||
*sampPtr = 'C';
|
||||
|
||||
rw = SDL_RWFromMem(sampPtr, sampSize);
|
||||
sample = Mix_LoadWAV_RW(rw, 1);
|
||||
|
||||
channelIdx = getFreeSampleChannelIndex();
|
||||
if (channelIdx != -1) {
|
||||
samplesPlaying[channelIdx] = index;
|
||||
}
|
||||
|
||||
sampleVolume(channelIdx, cfgfile.WaveVolume);
|
||||
|
||||
if (Mix_PlayChannel(channelIdx, sample, repeat - 1) == -1)
|
||||
printf("Error while playing VOC: Sample %d \n", index);
|
||||
|
||||
/*if (cfgfile.Debug)
|
||||
printf("Playing VOC: Sample %d\n", index);*/
|
||||
|
||||
free(sampPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void setSamplePosition(int32 channelIdx, int32 x, int32 y, int32 z) {
|
||||
int32 distance;
|
||||
distance = Abs(getDistance3D(newCameraX << 9, newCameraY << 8, newCameraZ << 9, x, y, z));
|
||||
distance = getAverageValue(0, distance, 10000, 255);
|
||||
if (distance > 255) { // don't play it if its to far away
|
||||
distance = 255;
|
||||
}
|
||||
|
||||
Mix_SetDistance(channelIdx, distance);
|
||||
}
|
||||
|
||||
/** Play samples
|
||||
@param index sample index under flasamp.hqr file
|
||||
@param frequency frequency used to play the sample
|
||||
@param repeat number of times to repeat the sample
|
||||
@param x unknown x variable
|
||||
@param y unknown y variable
|
||||
@param z unknown z variable */
|
||||
void playSample(int32 index, int32 frequency, int32 repeat, int32 x, int32 y, int32 z, int32 actorIdx) {
|
||||
if (cfgfile.Sound) {
|
||||
int32 sampSize = 0;
|
||||
SDL_RWops *rw;
|
||||
uint8* sampPtr;
|
||||
|
||||
sampSize = hqrGetallocEntry(&sampPtr, HQR_SAMPLES_FILE, index);
|
||||
|
||||
// Fix incorrect sample files first byte
|
||||
if (*sampPtr != 'C')
|
||||
*sampPtr = 'C';
|
||||
|
||||
rw = SDL_RWFromMem(sampPtr, sampSize);
|
||||
sample = Mix_LoadWAV_RW(rw, 1);
|
||||
|
||||
channelIdx = getFreeSampleChannelIndex();
|
||||
|
||||
// only play if we have a free channel, otherwise we won't be able to control the sample
|
||||
if (channelIdx != -1) {
|
||||
samplesPlaying[channelIdx] = index;
|
||||
sampleVolume(channelIdx, cfgfile.WaveVolume);
|
||||
|
||||
if (actorIdx != -1) {
|
||||
setSamplePosition(channelIdx, x, y, z);
|
||||
|
||||
// save the actor index for the channel so we can check the position
|
||||
samplesPlayingActors[channelIdx] = actorIdx;
|
||||
}
|
||||
|
||||
if (Mix_PlayChannel(channelIdx, sample, repeat - 1) == -1)
|
||||
printf("Error while playing VOC: Sample %d \n", index);
|
||||
|
||||
/*if (cfgfile.Debug)
|
||||
printf("Playing VOC: Sample %d\n", index);*/
|
||||
}
|
||||
|
||||
free(sampPtr);
|
||||
}
|
||||
}
|
||||
|
||||
/** Resume samples */
|
||||
void resumeSamples() {
|
||||
if (cfgfile.Sound) {
|
||||
Mix_Resume(-1);
|
||||
/*if (cfgfile.Debug)
|
||||
printf("Resume VOC samples\n");*/
|
||||
}
|
||||
}
|
||||
|
||||
/** Pause samples */
|
||||
void pauseSamples() {
|
||||
if (cfgfile.Sound) {
|
||||
Mix_HaltChannel(-1);
|
||||
/*if (cfgfile.Debug)
|
||||
printf("Pause VOC samples\n");*/
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop samples */
|
||||
void stopSamples() {
|
||||
if (cfgfile.Sound) {
|
||||
memset(samplesPlaying, -1, sizeof(int32) * NUM_CHANNELS);
|
||||
Mix_HaltChannel(-1);
|
||||
//clean up
|
||||
Mix_FreeChunk(sample);
|
||||
sample = NULL; //make sure we free it
|
||||
/*if (cfgfile.Debug)
|
||||
printf("Stop VOC samples\n");*/
|
||||
}
|
||||
}
|
||||
|
||||
int32 getActorChannel(int32 index) {
|
||||
int32 c = 0;
|
||||
for (c = 0; c < NUM_CHANNELS; c++) {
|
||||
if (samplesPlayingActors[c] == index) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 getSampleChannel(int32 index) {
|
||||
int32 c = 0;
|
||||
for (c = 0; c < NUM_CHANNELS; c++) {
|
||||
if (samplesPlaying[c] == index) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void removeSampleChannel(int32 c) {
|
||||
samplesPlaying[c] = -1;
|
||||
samplesPlayingActors[c] = -1;
|
||||
}
|
||||
|
||||
/** Stop samples */
|
||||
void stopSample(int32 index) {
|
||||
if (cfgfile.Sound) {
|
||||
int32 stopChannel = getSampleChannel(index);
|
||||
if (stopChannel != -1) {
|
||||
removeSampleChannel(stopChannel);
|
||||
Mix_HaltChannel(stopChannel);
|
||||
//clean up
|
||||
Mix_FreeChunk(sample);
|
||||
sample = NULL; //make sure we free it
|
||||
/*if (cfgfile.Debug)
|
||||
printf("Stop VOC samples\n");*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 isChannelPlaying(int32 channel) {
|
||||
if (channel != -1) {
|
||||
if(Mix_Playing(channel)) {
|
||||
return 1;
|
||||
} else {
|
||||
removeSampleChannel(channel);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 isSamplePlaying(int32 index) {
|
||||
int32 channel = getSampleChannel(index);
|
||||
return isChannelPlaying(channel);
|
||||
}
|
||||
|
||||
int32 getFreeSampleChannelIndex() {
|
||||
int i = 0;
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
if (samplesPlaying[i] == -1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
//FIXME if didn't find any, lets free what is not in use
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
if (samplesPlaying[i] != -1) {
|
||||
isChannelPlaying(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void playVoxSample(int32 index) {
|
||||
if (cfgfile.Sound) {
|
||||
int32 sampSize = 0;
|
||||
SDL_RWops *rw;
|
||||
uint8* sampPtr = 0;
|
||||
|
||||
sampSize = hqrGetallocVoxEntry(&sampPtr, currentVoxBankFile, index, voxHiddenIndex);
|
||||
|
||||
// Fix incorrect sample files first byte
|
||||
if (*sampPtr != 'C') {
|
||||
hasHiddenVox = *sampPtr;
|
||||
voxHiddenIndex++;
|
||||
*sampPtr = 'C';
|
||||
}
|
||||
|
||||
rw = SDL_RWFromMem(sampPtr, sampSize);
|
||||
sample = Mix_LoadWAV_RW(rw, 1);
|
||||
|
||||
channelIdx = getFreeSampleChannelIndex();
|
||||
|
||||
// only play if we have a free channel, otherwise we won't be able to control the sample
|
||||
if (channelIdx != -1) {
|
||||
samplesPlaying[channelIdx] = index;
|
||||
|
||||
sampleVolume(channelIdx, cfgfile.VoiceVolume - 1);
|
||||
|
||||
if (Mix_PlayChannel(channelIdx, sample, 0) == -1)
|
||||
printf("Error while playing VOC: Sample %d \n", index);
|
||||
|
||||
/*if (cfgfile.Debug)
|
||||
printf("Playing VOC: Sample %d\n", index);*/
|
||||
}
|
||||
|
||||
free(sampPtr);
|
||||
}
|
||||
}
|
101
engines/twine/sound.h
Normal file
101
engines/twine/sound.h
Normal file
@ -0,0 +1,101 @@
|
||||
/** @file sound.h
|
||||
@brief
|
||||
This file contains music playing routines
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SOUND_H
|
||||
#define SOUND_H
|
||||
|
||||
#include "sys.h"
|
||||
#include "sys.h"
|
||||
|
||||
/** Total number of sprites allowed in the game */
|
||||
#define NUM_SAMPLES 243
|
||||
#define NUM_CHANNELS 32
|
||||
|
||||
/** Table with all loaded samples */
|
||||
uint8* samplesTable[NUM_SAMPLES];
|
||||
/** Table with all loaded samples sizes */
|
||||
uint32 samplesSizeTable[NUM_SAMPLES];
|
||||
|
||||
/** Samples playing at the same time */
|
||||
int32 samplesPlaying[NUM_CHANNELS];
|
||||
|
||||
/** Samples playing at a actors position */
|
||||
int32 samplesPlayingActors[NUM_CHANNELS];
|
||||
|
||||
/** Sample volume
|
||||
@param channel sample channel
|
||||
@param volume sample volume number */
|
||||
void sampleVolume(int32 channel, int32 volume);
|
||||
|
||||
/** Play FLA movie samples
|
||||
@param index sample index under flasamp.hqr file
|
||||
@param frequency frequency used to play the sample
|
||||
@param repeat number of times to repeat the sample
|
||||
@param x unknown x variable
|
||||
@param y unknown y variable */
|
||||
void playFlaSample(int32 index, int32 frequency, int32 repeat, int32 x, int32 y);
|
||||
|
||||
/** Update sample position in channel */
|
||||
void setSamplePosition(int32 channelIdx, int32 x, int32 y, int32 z);
|
||||
|
||||
/** Play samples
|
||||
@param index sample index under flasamp.hqr file
|
||||
@param frequency frequency used to play the sample
|
||||
@param repeat number of times to repeat the sample
|
||||
@param x unknown x variable
|
||||
@param y unknown y variable
|
||||
@param z unknown z variable */
|
||||
void playSample(int32 index, int32 frequency, int32 repeat, int32 x, int32 y, int32 z, int32 actorIdx);
|
||||
|
||||
/** Pause samples */
|
||||
void pauseSamples();
|
||||
|
||||
void resumeSamples();
|
||||
|
||||
/** Stop samples */
|
||||
void stopSamples();
|
||||
|
||||
/** Get the channel where the actor sample is playing */
|
||||
int32 getActorChannel(int32 index);
|
||||
|
||||
/** Get the channel where the sample is playing */
|
||||
int32 getSampleChannel(int32 index);
|
||||
|
||||
/** Stops a specific sample */
|
||||
void stopSample(int32 index);
|
||||
|
||||
/** Find a free channel slot to use */
|
||||
int32 getFreeSampleChannelIndex();
|
||||
|
||||
/** Remove a sample from the channel usage list */
|
||||
void removeSampleChannel(int32 index);
|
||||
|
||||
/** Check if a sample is playing */
|
||||
int32 isSamplePlaying(int32 index);
|
||||
|
||||
/** Play VOX sample */
|
||||
void playVoxSample(int32 index);
|
||||
|
||||
#endif
|
108
engines/twine/sys.cpp
Normal file
108
engines/twine/sys.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/** @file sys.cpp
|
||||
@brief
|
||||
This file contains system types definitions
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
// Little endian
|
||||
|
||||
FORCEINLINE uint16 READ_LE_UINT16(const void *ptr) {
|
||||
const uint8 *b = (const uint8 *)ptr;
|
||||
return (b[1] << 8) | b[0];
|
||||
}
|
||||
|
||||
FORCEINLINE int16 READ_LE_INT16(const void *ptr) {
|
||||
return (int16)READ_LE_UINT16(ptr);
|
||||
}
|
||||
|
||||
FORCEINLINE uint32 READ_LE_UINT32(const void *ptr) {
|
||||
const uint8 *b = (const uint8 *)ptr;
|
||||
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0]);
|
||||
}
|
||||
|
||||
FORCEINLINE int32 READ_LE_INT32(const void *ptr) {
|
||||
return (int32)READ_LE_UINT32(ptr);
|
||||
}
|
||||
|
||||
FORCEINLINE void WRITE_LE_UINT16(void *ptr, uint16 value) {
|
||||
uint8 *b = (uint8 *)ptr;
|
||||
b[0] = (uint8)(value >> 0);
|
||||
b[1] = (uint8)(value >> 8);
|
||||
}
|
||||
|
||||
FORCEINLINE void WRITE_LE_INT16(void *ptr, int16 value) {
|
||||
WRITE_LE_UINT16(ptr, (uint16)value);
|
||||
}
|
||||
|
||||
FORCEINLINE void WRITE_LE_UINT32(void *ptr, uint32 value) {
|
||||
uint8 *b = (uint8 *)ptr;
|
||||
b[0] = (uint8)(value >> 0);
|
||||
b[1] = (uint8)(value >> 8);
|
||||
b[2] = (uint8)(value >> 16);
|
||||
b[3] = (uint8)(value >> 24);
|
||||
}
|
||||
|
||||
FORCEINLINE void WRITE_LE_INT32(void *ptr, int32 value) {
|
||||
WRITE_LE_UINT32(ptr, (uint32)value);
|
||||
}
|
||||
|
||||
// TODO: big endian
|
||||
|
||||
// Main endian functions
|
||||
|
||||
FORCEINLINE uint8 READ_BYTE(const void *ptr) {
|
||||
return *((const uint8 *)ptr);
|
||||
}
|
||||
|
||||
FORCEINLINE uint16 READ_UINT16(const void *ptr) {
|
||||
return READ_LE_UINT16(ptr);
|
||||
}
|
||||
|
||||
FORCEINLINE int16 READ_INT16(const void *ptr) {
|
||||
return READ_LE_INT16(ptr);
|
||||
}
|
||||
|
||||
FORCEINLINE uint32 READ_UINT32(const void *ptr) {
|
||||
return READ_LE_UINT32(ptr);
|
||||
}
|
||||
|
||||
FORCEINLINE int32 READ_INT32(const void *ptr) {
|
||||
return READ_LE_INT32(ptr);
|
||||
}
|
||||
|
||||
FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
|
||||
WRITE_LE_UINT16(ptr, value);
|
||||
}
|
||||
|
||||
FORCEINLINE void WRITE_INT16(void *ptr, int16 value) {
|
||||
WRITE_LE_INT16(ptr, value);
|
||||
}
|
||||
|
||||
FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
|
||||
WRITE_LE_UINT32(ptr, value);
|
||||
}
|
||||
|
||||
FORCEINLINE void WRITE_INT32(void *ptr, int32 value) {
|
||||
WRITE_LE_INT32(ptr, value);
|
||||
}
|
60
engines/twine/sys.h
Normal file
60
engines/twine/sys.h
Normal file
@ -0,0 +1,60 @@
|
||||
/** @file sys.h
|
||||
@brief
|
||||
This file contains system types definitions
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SYS_H
|
||||
#define SYS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define Rnd(x) rand()%x
|
||||
#define Abs(x) abs(x)
|
||||
|
||||
// TYPES
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef char int8;
|
||||
|
||||
typedef unsigned short uint16;
|
||||
typedef short int16;
|
||||
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32;
|
||||
|
||||
typedef float int64;
|
||||
|
||||
// ENDIAN
|
||||
|
||||
#ifdef UNIX
|
||||
#define FORCEINLINE static __inline__
|
||||
#elif MINGW32
|
||||
#define FORCEINLINE inline
|
||||
#else
|
||||
#define FORCEINLINE __forceinline
|
||||
#endif
|
||||
|
||||
#endif
|
959
engines/twine/text.cpp
Normal file
959
engines/twine/text.cpp
Normal file
@ -0,0 +1,959 @@
|
||||
/** @file text.cpp
|
||||
@brief
|
||||
This file contains dialogues processing.
|
||||
It contains text and font functions.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "text.h"
|
||||
#include "main.h"
|
||||
#include "hqrdepack.h"
|
||||
#include "resources.h"
|
||||
#include "sdlengine.h"
|
||||
#include "menu.h"
|
||||
#include "interface.h"
|
||||
#include "lbaengine.h"
|
||||
#include "keyboard.h"
|
||||
#include "screens.h"
|
||||
#include "renderer.h"
|
||||
#include "sound.h"
|
||||
|
||||
// RECHECK THIS LATER
|
||||
int32 currentBankIdx = -1; // textVar1
|
||||
uint8 textVar2[256];
|
||||
uint8 textVar3;
|
||||
|
||||
/** Dialogue text pointer */
|
||||
uint8 *dialTextPtr; // bufText
|
||||
/** Dialogue entry order pointer */
|
||||
uint8 *dialOrderPtr; // bufOrder
|
||||
/** Number of dialogues text entries */
|
||||
int16 numDialTextEntries;
|
||||
|
||||
// TODO: refactor this
|
||||
int32 wordSizeChar;
|
||||
int32 wordSizePixel;
|
||||
|
||||
int16 spaceChar = 0x20;
|
||||
|
||||
/** FLA movie extension */
|
||||
#define VOX_EXT ".vox"
|
||||
/** Common movie directory */
|
||||
#define VOX_DIR "vox/"
|
||||
|
||||
int8 * LanguagePrefixTypes[] = {
|
||||
"EN_",
|
||||
"FR_",
|
||||
"DE_",
|
||||
"SP_",
|
||||
"IT_"
|
||||
};
|
||||
|
||||
int8 * LanguageSufixTypes[] = {
|
||||
"sys",
|
||||
"cre",
|
||||
"gam",
|
||||
"000",
|
||||
"001",
|
||||
"002",
|
||||
"003",
|
||||
"004",
|
||||
"005",
|
||||
"006",
|
||||
"007",
|
||||
"008",
|
||||
"009",
|
||||
"010",
|
||||
"011"
|
||||
};
|
||||
|
||||
|
||||
void initVoxBank(int32 bankIdx) {
|
||||
// get the correct vox hqr file
|
||||
memset(currentVoxBankFile, 0, sizeof(int8));
|
||||
sprintf(currentVoxBankFile, VOX_DIR);
|
||||
strcat(currentVoxBankFile, LanguagePrefixTypes[cfgfile.LanguageId]);
|
||||
strcat(currentVoxBankFile, LanguageSufixTypes[bankIdx]);
|
||||
strcat(currentVoxBankFile, VOX_EXT);
|
||||
|
||||
// TODO check the rest to reverse
|
||||
}
|
||||
|
||||
|
||||
int32 initVoxToPlay(int32 index) { // setVoxFileAtDigit
|
||||
int32 i = 0;
|
||||
int32 currIdx = 0;
|
||||
int32 orderIdx = 0;
|
||||
|
||||
int16 *localOrderBuf = (int16 *) dialOrderPtr;
|
||||
|
||||
voxHiddenIndex = 0;
|
||||
hasHiddenVox = 0;
|
||||
|
||||
// choose right text from order index
|
||||
for (i = 0; i < numDialTextEntries; i++) {
|
||||
orderIdx = *(localOrderBuf++);
|
||||
if (orderIdx == index) {
|
||||
currIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
currDialTextEntry = currIdx;
|
||||
|
||||
playVoxSample(currDialTextEntry);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32 playVox(int32 index) {
|
||||
if (cfgfile.LanguageCDId && index) {
|
||||
if (hasHiddenVox && !isSamplePlaying(index)) {
|
||||
playVoxSample(index);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 playVoxSimple(int32 index) {
|
||||
if (cfgfile.LanguageCDId && index) {
|
||||
playVox(index);
|
||||
|
||||
if (isSamplePlaying(index)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stopVox(int32 index) {
|
||||
hasHiddenVox = 0;
|
||||
stopSample(index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Initialize dialogue
|
||||
@param bankIdx Text bank index*/
|
||||
void initTextBank(int32 bankIdx) { // InitDial
|
||||
int32 langIdx;
|
||||
int32 hqrSize;
|
||||
|
||||
// don't load if we already have the dialogue text bank loaded
|
||||
if (bankIdx == currentBankIdx)
|
||||
return;
|
||||
|
||||
currentBankIdx = bankIdx;
|
||||
// RECHECK THIS LATER
|
||||
textVar2[0] = textVar3;
|
||||
|
||||
// get index according with language
|
||||
langIdx = (cfgfile.LanguageId * 14) * 2 + bankIdx * 2;
|
||||
|
||||
hqrSize = hqrGetallocEntry(&dialOrderPtr, HQR_TEXT_FILE, langIdx);
|
||||
|
||||
numDialTextEntries = hqrSize / 2;
|
||||
|
||||
hqrSize = hqrGetallocEntry(&dialTextPtr, HQR_TEXT_FILE, ++langIdx);
|
||||
|
||||
if (cfgfile.LanguageCDId) {
|
||||
initVoxBank(bankIdx);
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw a certain character in the screen
|
||||
@param x X coordinate in screen
|
||||
@param y Y coordinate in screen
|
||||
@param character ascii character to display */
|
||||
void drawCharacter(int32 x, int32 y, uint8 character) { // drawCharacter
|
||||
uint8 sizeX;
|
||||
uint8 sizeY;
|
||||
uint8 param1;
|
||||
uint8 param2;
|
||||
uint8 *data;
|
||||
uint8 *screen;
|
||||
|
||||
// int temp=0;
|
||||
int32 toNextLine;
|
||||
uint8 index;
|
||||
|
||||
// char color;
|
||||
uint8 usedColor;
|
||||
uint8 number;
|
||||
uint8 jump;
|
||||
|
||||
int32 i;
|
||||
|
||||
int32 tempX;
|
||||
int32 tempY;
|
||||
|
||||
data = fontPtr + *((int16 *)(fontPtr + character * 4));
|
||||
|
||||
dialTextSize = sizeX = *(data++);
|
||||
sizeY = *(data++);
|
||||
|
||||
param1 = *(data++);
|
||||
param2 = *(data++);
|
||||
|
||||
x += param1;
|
||||
y += param2;
|
||||
|
||||
usedColor = dialTextColor;
|
||||
|
||||
screen = frontVideoBuffer + screenLookupTable[y] + x;
|
||||
|
||||
tempX = x;
|
||||
tempY = y;
|
||||
|
||||
toNextLine = SCREEN_WIDTH - sizeX;
|
||||
|
||||
do {
|
||||
index = *(data++);
|
||||
do {
|
||||
jump = *(data++);
|
||||
screen += jump;
|
||||
tempX += jump;
|
||||
if (--index == 0) {
|
||||
screen += toNextLine;
|
||||
tempY++;
|
||||
tempX = x;
|
||||
sizeY--;
|
||||
if (sizeY <= 0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
number = *(data++);
|
||||
for (i = 0; i < number; i++) {
|
||||
if (tempX >= SCREEN_TEXTLIMIT_LEFT && tempX < SCREEN_TEXTLIMIT_RIGHT && tempY >= SCREEN_TEXTLIMIT_TOP && tempY < SCREEN_TEXTLIMIT_BOTTOM)
|
||||
frontVideoBuffer[SCREEN_WIDTH*tempY + tempX] = usedColor;
|
||||
|
||||
screen++;
|
||||
tempX++;
|
||||
}
|
||||
|
||||
if (--index == 0) {
|
||||
screen += toNextLine;
|
||||
tempY++;
|
||||
tempX = x;
|
||||
|
||||
sizeY--;
|
||||
if (sizeY <= 0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (1);
|
||||
} while (1);
|
||||
|
||||
}
|
||||
|
||||
/** Draw character with shadow
|
||||
@param x X coordinate in screen
|
||||
@param y Y coordinate in screen
|
||||
@param character ascii character to display
|
||||
@param color character color */
|
||||
void drawCharacterShadow(int32 x, int32 y, uint8 character, int32 color) { // drawDoubleLetter
|
||||
int32 left, top, right, bottom;
|
||||
|
||||
if (character != 0x20)
|
||||
{
|
||||
// shadow color
|
||||
setFontColor(0);
|
||||
drawCharacter(x + 2, y + 4, character);
|
||||
|
||||
// text color
|
||||
setFontColor(color);
|
||||
drawCharacter(x, y, character);
|
||||
|
||||
left = x;
|
||||
top = y;
|
||||
// FIXME: get right font size
|
||||
right = x + 32;
|
||||
bottom = y + 38;
|
||||
|
||||
copyBlockPhys(left, top, right, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/** Display a certain dialogue text in the screen
|
||||
@param x X coordinate in screen
|
||||
@param y Y coordinate in screen
|
||||
@param dialogue ascii text to display */
|
||||
void drawText(int32 x, int32 y, int8 *dialogue) { // Font
|
||||
uint8 currChar;
|
||||
|
||||
if (fontPtr == 0) // if the font is not defined
|
||||
return;
|
||||
|
||||
do {
|
||||
currChar = (uint8) * (dialogue++); // read the next char from the string
|
||||
|
||||
if (currChar == 0) // if the char is 0x0, -> end of string
|
||||
break;
|
||||
|
||||
if (currChar == 0x20) // if it's a space char
|
||||
x += dialCharSpace;
|
||||
else {
|
||||
dialTextSize = *(fontPtr + (*((int16 *)(fontPtr + currChar * 4)))); // get the length of the character
|
||||
drawCharacter(x, y, currChar); // draw the character on screen
|
||||
// add the length of the space between 2 characters
|
||||
x += dialSpaceBetween;
|
||||
// add the length of the current character
|
||||
x += dialTextSize;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/** Gets dialogue text width size
|
||||
@param dialogue ascii text to display */
|
||||
int32 getTextSize(int8 *dialogue) { // SizeFont
|
||||
uint8 currChar;
|
||||
dialTextSize = 0;
|
||||
|
||||
do {
|
||||
currChar = (uint8) * (dialogue++);
|
||||
|
||||
if (currChar == 0)
|
||||
break;
|
||||
|
||||
if (currChar == 0x20) {
|
||||
dialTextSize += dialCharSpace;
|
||||
} else {
|
||||
dialTextSize += dialSpaceBetween;
|
||||
dialTextSize += *(fontPtr + *((int16 *)(fontPtr + currChar * 4)));
|
||||
}
|
||||
} while (1);
|
||||
|
||||
return (dialTextSize);
|
||||
}
|
||||
|
||||
void initDialogueBox() { // InitDialWindow
|
||||
blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (int8*)workVideoBuffer, dialTextBoxLeft, dialTextBoxTop, (int8*)frontVideoBuffer);
|
||||
|
||||
if (newGameVar4 != 0) {
|
||||
drawBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom);
|
||||
drawTransparentBox(dialTextBoxLeft + 1, dialTextBoxTop + 1, dialTextBoxRight - 1, dialTextBoxBottom - 1, 3);
|
||||
}
|
||||
|
||||
copyBlockPhys(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom);
|
||||
printText8Var3 = 0;
|
||||
blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (int8*)frontVideoBuffer, dialTextBoxLeft, dialTextBoxTop, (int8*)workVideoBuffer);
|
||||
}
|
||||
|
||||
void initInventoryDialogueBox() { // SecondInitDialWindow
|
||||
blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (int8*)workVideoBuffer, dialTextBoxLeft, dialTextBoxTop, (int8*)frontVideoBuffer);
|
||||
copyBlockPhys(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom);
|
||||
printText8Var3 = 0;
|
||||
}
|
||||
|
||||
// TODO: refactor this code
|
||||
void initText(int32 index) { // initText
|
||||
printTextVar13 = 0;
|
||||
|
||||
if (!getText(index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
printText8Ptr1 = buf1;
|
||||
printText8Ptr2 = buf2;
|
||||
|
||||
printTextVar13 = 1;
|
||||
|
||||
printText8Var1 = 0;
|
||||
buf1[0] = 0;
|
||||
buf2[0] = 0;
|
||||
printText8Var2 = index;
|
||||
printText8Var3 = 0;
|
||||
TEXT_CurrentLetterX = dialTextBoxLeft + 8;
|
||||
printText8Var5 = 0;
|
||||
printText8Var6 = 0;
|
||||
TEXT_CurrentLetterY = dialTextBoxTop + 8;
|
||||
printText8Var8 = currDialTextPtr;
|
||||
|
||||
// lba font is get while engine start
|
||||
setFontParameters(2, 7);
|
||||
}
|
||||
|
||||
void initProgressiveTextBuffer() {
|
||||
int32 i = 0;
|
||||
|
||||
buf2[0] = 0;
|
||||
|
||||
while (i < dialTextBufferSize) {
|
||||
strcat((char*)buf2, " ");
|
||||
i++;
|
||||
};
|
||||
|
||||
printText8Ptr2 = buf2;
|
||||
addLineBreakX = 16;
|
||||
printText8Var1 = 0;
|
||||
}
|
||||
|
||||
void printText8Sub4(int16 a, int16 b, int16 c) {
|
||||
int32 temp;
|
||||
int32 counter2 = 0;
|
||||
int32 var1;
|
||||
int32 var2;
|
||||
|
||||
if (printText8Var3 < 32) {
|
||||
temp = printText8Var3 * 3;
|
||||
pt8s4[temp] = c;
|
||||
pt8s4[temp+1] = a;
|
||||
pt8s4[temp+2] = b;
|
||||
|
||||
printText8Var3++;
|
||||
} else {
|
||||
while (counter2 < 31) {
|
||||
var1 = (counter2 + 1) * 3;
|
||||
var2 = counter2 * 3;
|
||||
pt8s4[var2] = pt8s4[var1];
|
||||
pt8s4[var2+1] = pt8s4[var1+1];
|
||||
pt8s4[var2+2] = pt8s4[var1+2];
|
||||
counter2++;
|
||||
};
|
||||
pt8s4[93] = c;
|
||||
pt8s4[94] = a;
|
||||
pt8s4[95] = b;
|
||||
}
|
||||
}
|
||||
|
||||
void getWordSize(uint8 *arg1, uint8 *arg2) {
|
||||
int32 temp = 0;
|
||||
uint8 *arg2Save = arg2;
|
||||
|
||||
while (*arg1 != 0 && *arg1 != 1 && *arg1 != 0x20) {
|
||||
temp++;
|
||||
*arg2++ = *arg1++;
|
||||
}
|
||||
|
||||
wordSizeChar = temp;
|
||||
*arg2 = 0;
|
||||
wordSizePixel = getTextSize((int8*)arg2Save);
|
||||
}
|
||||
|
||||
void processTextLine() {
|
||||
int16 var4;
|
||||
uint8 *buffer;
|
||||
uint8 *temp;
|
||||
|
||||
buffer = printText8Var8;
|
||||
dialCharSpace = 7;
|
||||
var4 = 1;
|
||||
|
||||
addLineBreakX = 0;
|
||||
printText8PrepareBufferVar2 = 0;
|
||||
buf2[0] = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (*buffer == 0x20) {
|
||||
buffer++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*buffer != 0) {
|
||||
printText8Var8 = buffer;
|
||||
getWordSize(buffer, buf1);
|
||||
if (addLineBreakX + dialCharSpace + wordSizePixel < dialTextBoxParam2) {
|
||||
temp = buffer + 1;
|
||||
if (*buffer == 1) {
|
||||
var4 = 0;
|
||||
buffer = temp;
|
||||
} else {
|
||||
if (*buf1 == 0x40) {
|
||||
var4 = 0;
|
||||
buffer = temp;
|
||||
if (addLineBreakX == 0) {
|
||||
addLineBreakX = 7;
|
||||
*((int16 *)buf2) = spaceChar;
|
||||
}
|
||||
if (buf1[1] == 0x50) {
|
||||
printText8Var1 = dialTextBoxParam1;
|
||||
buffer++;
|
||||
}
|
||||
} else {
|
||||
buffer += wordSizeChar;
|
||||
printText8Var8 = buffer;
|
||||
strcat((char*)buf2, (char*)buf1);
|
||||
strcat((char*)buf2, " "); // not 100% accurate
|
||||
printText8PrepareBufferVar2++;
|
||||
|
||||
addLineBreakX += wordSizePixel + dialCharSpace;
|
||||
if (*printText8Var8 != 0) {
|
||||
printText8Var8++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (printText8PrepareBufferVar2 != 0)
|
||||
printText8PrepareBufferVar2--;
|
||||
|
||||
if (*printText8Var8 != 0 && var4 == 1) {
|
||||
dialCharSpace += (dialTextBoxParam2 - addLineBreakX) / printText8PrepareBufferVar2;
|
||||
printText10Var1 = dialTextBoxParam2 - addLineBreakX - dialTextBoxParam2 - addLineBreakX; // stupid... recheck
|
||||
}
|
||||
|
||||
printText8Var8 = buffer;
|
||||
|
||||
printText8Ptr2 = buf2;
|
||||
|
||||
}
|
||||
|
||||
// draw next page arrow polygon
|
||||
void printText10Sub() { // printText10Sub()
|
||||
vertexCoordinates[0] = dialTextStopColor;
|
||||
vertexCoordinates[1] = dialTextBoxRight - 3;
|
||||
vertexCoordinates[2] = dialTextBoxBottom - 24;
|
||||
vertexCoordinates[3] = dialTextStopColor;
|
||||
vertexCoordinates[4] = dialTextBoxRight - 24;
|
||||
vertexCoordinates[5] = dialTextBoxBottom - 3;
|
||||
vertexCoordinates[6] = dialTextStartColor;
|
||||
vertexCoordinates[7] = vertexCoordinates[1];
|
||||
vertexCoordinates[8] = vertexCoordinates[5];
|
||||
|
||||
polyRenderType = 0; // POLYGONTYPE_FLAT
|
||||
numOfVertex = 3;
|
||||
|
||||
if (computePolygons())
|
||||
{
|
||||
renderPolygons(polyRenderType, dialTextStopColor);
|
||||
}
|
||||
|
||||
copyBlockPhys(dialTextBoxRight - 24, dialTextBoxBottom - 24, dialTextBoxRight - 3, dialTextBoxBottom - 3);
|
||||
}
|
||||
|
||||
void printText10Sub2() { // printText10Sub2()
|
||||
int32 currentLetter;
|
||||
int32 currentIndex;
|
||||
int32 counter;
|
||||
int32 counter2;
|
||||
int16 *ptr;
|
||||
|
||||
currentLetter = printText8Var3;
|
||||
currentLetter--;
|
||||
|
||||
currentIndex = currentLetter * 3;
|
||||
|
||||
ptr = pt8s4 + currentIndex;
|
||||
|
||||
sdldelay(15);
|
||||
|
||||
counter = printText8Var3;
|
||||
counter2 = dialTextStartColor;
|
||||
|
||||
while (--counter >= 0) {
|
||||
setFontColor(counter2);
|
||||
drawCharacterShadow(*(ptr + 1), *(ptr + 2), (uint8)*ptr, counter2);
|
||||
counter2 -= dialTextStepSize;
|
||||
if (counter2 > dialTextStopColor)
|
||||
counter2 = dialTextStopColor;
|
||||
ptr -= 3;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void TEXT_GetLetterSize(uint8 character, int32 *pLetterWidth, int32 *pLetterHeight, uint8 * pFont) { // TEXT_GetLetterSize
|
||||
uint8 *temp;
|
||||
|
||||
temp = (uint8*) (pFont + *((int16 *)(pFont + character * 4)));
|
||||
*pLetterWidth = *(temp);
|
||||
*pLetterHeight = *(temp + 1);
|
||||
}
|
||||
|
||||
// TODO: refactor this code
|
||||
int printText10() { // printText10()
|
||||
int32 charWidth, charHeight; // a, b
|
||||
|
||||
if (printTextVar13 == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*(printText8Ptr2) == 0) {
|
||||
if (printText8Var5 != 0) {
|
||||
if (newGameVar5 != 0) {
|
||||
printText10Sub();
|
||||
}
|
||||
printTextVar13 = 0;
|
||||
return 0;
|
||||
}
|
||||
if (printText8Var6 != 0) {
|
||||
blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (int8*)workVideoBuffer, dialTextBoxLeft, dialTextBoxTop, (int8*)frontVideoBuffer);
|
||||
copyBlockPhys(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom);
|
||||
printText8Var3 = 0;
|
||||
printText8Var6 = 0;
|
||||
TEXT_CurrentLetterX = dialTextBoxLeft + 8;
|
||||
TEXT_CurrentLetterY = dialTextBoxTop + 8;
|
||||
}
|
||||
if (*(printText8Var8) == 0) {
|
||||
initProgressiveTextBuffer();
|
||||
printText8Var5 = 1;
|
||||
return 1;
|
||||
}
|
||||
processTextLine();
|
||||
}
|
||||
|
||||
// RECHECK this later
|
||||
if (*(printText8Ptr2) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printText8Sub4(TEXT_CurrentLetterX, TEXT_CurrentLetterY, *printText8Ptr2);
|
||||
printText10Sub2();
|
||||
TEXT_GetLetterSize(*printText8Ptr2, &charWidth, &charHeight, (uint8*)fontPtr);
|
||||
|
||||
if (*(printText8Ptr2) != 0x20) {
|
||||
TEXT_CurrentLetterX += charWidth + 2;
|
||||
} else {
|
||||
if (printText10Var1 != 0) {
|
||||
TEXT_CurrentLetterX++;
|
||||
printText10Var1--;
|
||||
}
|
||||
TEXT_CurrentLetterX += dialCharSpace;
|
||||
}
|
||||
|
||||
// next character
|
||||
printText8Ptr2++;
|
||||
|
||||
if (*(printText8Ptr2) != 0)
|
||||
return 1;
|
||||
|
||||
TEXT_CurrentLetterY += 38;
|
||||
TEXT_CurrentLetterX = dialTextBoxLeft + 8;
|
||||
|
||||
if (printText8Var6 == 1 && printText8Var5 == 0) {
|
||||
printText10Sub();
|
||||
return 2;
|
||||
}
|
||||
|
||||
printText8Var1++;
|
||||
if (printText8Var1 < dialTextBoxParam1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
initProgressiveTextBuffer();
|
||||
printText8Var6 = 1;
|
||||
|
||||
if (*(printText8Var8) == 0) {
|
||||
printText8Var5 = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO: refactor this code
|
||||
void drawTextFullscreen(int32 index) { // printTextFullScreen
|
||||
int32 printedText;
|
||||
int32 skipText = 0;
|
||||
|
||||
saveClip();
|
||||
resetClip();
|
||||
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||||
|
||||
// get right VOX entry index
|
||||
if (cfgfile.LanguageCDId) {
|
||||
initVoxToPlay(index);
|
||||
}
|
||||
|
||||
// if we don't display text, than still plays vox file
|
||||
if (cfgfile.FlagDisplayText) {
|
||||
initText(index);
|
||||
initDialogueBox();
|
||||
|
||||
do {
|
||||
readKeys();
|
||||
printedText = printText10();
|
||||
playVox(currDialTextEntry);
|
||||
|
||||
if (printedText == 2) {
|
||||
do {
|
||||
readKeys();
|
||||
if (skipIntro == 0 && skippedKey == 0 && pressedKey == 0) {
|
||||
break;
|
||||
}
|
||||
playVox(currDialTextEntry);
|
||||
sdldelay(1);
|
||||
} while(1);
|
||||
|
||||
do {
|
||||
readKeys();
|
||||
if (skipIntro != 0 || skippedKey != 0 || pressedKey != 0) {
|
||||
break;
|
||||
}
|
||||
playVox(currDialTextEntry);
|
||||
sdldelay(1);
|
||||
} while(1);
|
||||
}
|
||||
|
||||
if (skipIntro == 1) {
|
||||
skipText = 1;
|
||||
}
|
||||
|
||||
if (!printedText && !isSamplePlaying(currDialTextEntry)) {
|
||||
break;
|
||||
}
|
||||
|
||||
sdldelay(1);
|
||||
} while(!skipText);
|
||||
|
||||
hasHiddenVox = 0;
|
||||
|
||||
if (cfgfile.LanguageCDId && isSamplePlaying(currDialTextEntry)) {
|
||||
stopVox(currDialTextEntry);
|
||||
}
|
||||
|
||||
printTextVar13 = 0;
|
||||
|
||||
if (printedText != 0) {
|
||||
loadClip();
|
||||
return;
|
||||
}
|
||||
|
||||
if (skipText != 0) {
|
||||
loadClip();
|
||||
return;
|
||||
}
|
||||
|
||||
// RECHECK this later
|
||||
// wait displaying text
|
||||
do {
|
||||
readKeys();
|
||||
sdldelay(1);
|
||||
} while(skipIntro || skippedKey || pressedKey);
|
||||
|
||||
// RECHECK this later
|
||||
// wait key to display next text
|
||||
do {
|
||||
readKeys();
|
||||
if (skipIntro != 0) {
|
||||
loadClip();
|
||||
return;
|
||||
}
|
||||
if (skippedKey != 0) {
|
||||
loadClip();
|
||||
return;
|
||||
}
|
||||
sdldelay(1);
|
||||
} while(!pressedKey);
|
||||
} else { // RECHECK THIS
|
||||
while (playVox(currDialTextEntry) && skipIntro != 1 );
|
||||
hasHiddenVox = 0;
|
||||
voxHiddenIndex = 0;
|
||||
}
|
||||
|
||||
if (cfgfile.LanguageCDId && isSamplePlaying(currDialTextEntry)) {
|
||||
stopVox(currDialTextEntry);
|
||||
}
|
||||
|
||||
loadClip();
|
||||
}
|
||||
|
||||
void setFont(uint8 *font, int32 spaceBetween, int32 charSpace) {
|
||||
fontPtr = font;
|
||||
dialCharSpace = charSpace;
|
||||
dialSpaceBetween = spaceBetween;
|
||||
}
|
||||
|
||||
/** Set font type parameters
|
||||
@param spaceBetween number in pixels of space between characters
|
||||
@param charSpace number in pixels of the character space */
|
||||
void setFontParameters(int32 spaceBetween, int32 charSpace) {
|
||||
dialSpaceBetween = spaceBetween;
|
||||
dialCharSpace = charSpace;
|
||||
}
|
||||
|
||||
/** Set the font cross color
|
||||
@param color color number to choose */
|
||||
void setFontCrossColor(int32 color) { // TestCoulDial
|
||||
dialTextStepSize = -1;
|
||||
dialTextBufferSize = 14;
|
||||
dialTextStartColor = color << 4;
|
||||
dialTextStopColor = (color << 4) + 12;
|
||||
}
|
||||
|
||||
/** Set the font color
|
||||
@param color color number to choose */
|
||||
void setFontColor(int32 color) {
|
||||
dialTextColor = color;
|
||||
}
|
||||
|
||||
/** Set font color parameters to process cross color display
|
||||
@param stopColor color number to stop
|
||||
@param startColor color number to start
|
||||
@param stepSize step size to change between those colors */
|
||||
void setTextCrossColor(int32 stopColor, int32 startColor, int32 stepSize) {
|
||||
dialTextStartColor = startColor;
|
||||
dialTextStopColor = stopColor;
|
||||
dialTextStepSize = stepSize;
|
||||
dialTextBufferSize = ((startColor - stopColor) + 1) / stepSize;
|
||||
}
|
||||
|
||||
/** Get dialogue text into text buffer
|
||||
@param index dialogue index */
|
||||
int32 getText(int32 index) { // findString
|
||||
int32 currIdx = 0;
|
||||
int32 orderIdx = 0;
|
||||
int32 numEntries;
|
||||
int32 ptrCurrentEntry;
|
||||
int32 ptrNextEntry;
|
||||
|
||||
int16 *localTextBuf = (int16 *) dialTextPtr;
|
||||
int16 *localOrderBuf = (int16 *) dialOrderPtr;
|
||||
|
||||
numEntries = numDialTextEntries;
|
||||
|
||||
// choose right text from order index
|
||||
do {
|
||||
orderIdx = *(localOrderBuf++);
|
||||
if (orderIdx == index)
|
||||
break;
|
||||
currIdx++;
|
||||
} while (currIdx < numDialTextEntries);
|
||||
|
||||
if (currIdx >= numEntries)
|
||||
return 0;
|
||||
|
||||
ptrCurrentEntry = localTextBuf[currIdx];
|
||||
ptrNextEntry = localTextBuf[currIdx + 1];
|
||||
|
||||
currDialTextPtr = (dialTextPtr + ptrCurrentEntry);
|
||||
currDialTextSize = ptrNextEntry - ptrCurrentEntry;
|
||||
numDialTextEntries = numEntries;
|
||||
|
||||
// RECHECK: this was added for vox playback
|
||||
currDialTextEntry = currIdx;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Copy dialogue text
|
||||
@param src source text buffer
|
||||
@param dst destination text buffer
|
||||
@param size text size */
|
||||
void copyText(int8 *src, int8 *dst, int32 size) { // copyStringToString
|
||||
int32 i;
|
||||
for (i = 0; i < size; i++)
|
||||
*(dst++) = *(src++);
|
||||
}
|
||||
|
||||
/** Gets menu dialogue text
|
||||
@param index text index to display
|
||||
@param dialogue dialogue text buffer to display */
|
||||
void getMenuText(int32 index, int8 *text) { // GetMultiText
|
||||
if (index == currMenuTextIndex) {
|
||||
if (currMenuTextBank == currentTextBank) {
|
||||
strcpy(text, currMenuTextBuffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!getText(index)) {
|
||||
// if doesn't have text
|
||||
text[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((currDialTextSize - 1) > 0xFF)
|
||||
currDialTextSize = 0xFF;
|
||||
|
||||
copyText((int8 *) currDialTextPtr, text, currDialTextSize);
|
||||
currDialTextSize++;
|
||||
copyText(text, currMenuTextBuffer, currDialTextSize);
|
||||
|
||||
currMenuTextIndex = index;
|
||||
currMenuTextBank = currentTextBank;
|
||||
}
|
||||
|
||||
void textClipFull() { // newGame2
|
||||
dialTextBoxLeft = 8;
|
||||
dialTextBoxTop = 8;
|
||||
dialTextBoxRight = 631;
|
||||
|
||||
dialTextBoxBottom = 471;
|
||||
dialTextBoxParam1 = 11;
|
||||
dialTextBoxParam2 = 607;
|
||||
}
|
||||
|
||||
void textClipSmall() { // newGame4
|
||||
dialTextBoxLeft = 16;
|
||||
dialTextBoxTop = 334;
|
||||
dialTextBoxRight = 623;
|
||||
dialTextBoxBottom = 463;
|
||||
dialTextBoxParam1 = 3;
|
||||
dialTextBoxParam2 = 591;
|
||||
}
|
||||
|
||||
void drawAskQuestion(int32 index) { // MyDial
|
||||
int32 textStatus = 1;
|
||||
|
||||
// get right VOX entry index
|
||||
if (cfgfile.LanguageCDId) {
|
||||
initVoxToPlay(index);
|
||||
}
|
||||
|
||||
initText(index);
|
||||
initDialogueBox();
|
||||
|
||||
do {
|
||||
readKeys();
|
||||
textStatus = printText10();
|
||||
|
||||
if (textStatus == 2) {
|
||||
do {
|
||||
readKeys();
|
||||
playVox(currDialTextEntry);
|
||||
sdldelay(1);
|
||||
} while(skipIntro || skippedKey || pressedKey);
|
||||
|
||||
do {
|
||||
readKeys();
|
||||
playVox(currDialTextEntry);
|
||||
sdldelay(1);
|
||||
} while(!skipIntro && !skippedKey && !pressedKey);
|
||||
}
|
||||
|
||||
sdldelay(1);
|
||||
} while(textStatus);
|
||||
|
||||
if (cfgfile.LanguageCDId) {
|
||||
while(playVoxSimple(currDialTextEntry));
|
||||
|
||||
hasHiddenVox = 0;
|
||||
voxHiddenIndex = 0;
|
||||
|
||||
if(isSamplePlaying(currDialTextEntry)) {
|
||||
stopVox(currDialTextEntry);
|
||||
}
|
||||
}
|
||||
|
||||
printTextVar13 = 0;
|
||||
}
|
163
engines/twine/text.h
Normal file
163
engines/twine/text.h
Normal file
@ -0,0 +1,163 @@
|
||||
/** @file text.h
|
||||
@brief
|
||||
This file contains dialogues processing. It contains text and font functions.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2008-2013 Prequengine team
|
||||
Copyright (C) 2002-2007 The TwinEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef DIALOGUES_H
|
||||
#define DIALOGUES_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
//TODO: add all 14 colors here for future use
|
||||
/** White color value */
|
||||
#define WHITE_COLOR_0 0
|
||||
|
||||
/** Current text bank */
|
||||
int32 currentTextBank;
|
||||
/** Current dialogue text size */
|
||||
int32 currDialTextSize;
|
||||
/** Current dialogue text pointer */
|
||||
uint8 *currDialTextPtr;
|
||||
|
||||
/** Font buffer pointer */
|
||||
uint8 * fontPtr;
|
||||
|
||||
/** Dialogue text size */
|
||||
int32 dialTextSize;
|
||||
/** Pixel size between dialogue text */
|
||||
int32 dialSpaceBetween;
|
||||
/** Pixel size of the space character */
|
||||
int32 dialCharSpace;
|
||||
/** Dialogue text color */
|
||||
int32 dialTextColor;
|
||||
|
||||
/** Dialogue text start color for cross coloring dialogues */
|
||||
int32 dialTextStartColor;
|
||||
/** Dialogue text stop color for cross coloring dialogues */
|
||||
int32 dialTextStopColor;
|
||||
/** Dialogue text step size for cross coloring dialogues */
|
||||
int32 dialTextStepSize;
|
||||
/** Dialogue text buffer size for cross coloring dialogues */
|
||||
int32 dialTextBufferSize;
|
||||
|
||||
int32 dialTextBoxLeft; // dialogueBoxLeft
|
||||
int32 dialTextBoxTop; // dialogueBoxTop
|
||||
int32 dialTextBoxRight; // dialogueBoxRight
|
||||
int32 dialTextBoxBottom; // dialogueBoxBottom
|
||||
|
||||
int32 dialTextBoxParam1; // dialogueBoxParam1
|
||||
int32 dialTextBoxParam2; // dialogueBoxParam2
|
||||
|
||||
// TODO: refactor all this variables and related functions
|
||||
int32 printTextVar13;
|
||||
uint8 buf1[256];
|
||||
uint8 buf2[256];
|
||||
uint8 *printText8Ptr1;
|
||||
uint8 *printText8Ptr2;
|
||||
int32 printText8Var1;
|
||||
int32 printText8Var2;
|
||||
int32 printText8Var3;
|
||||
int32 TEXT_CurrentLetterX;
|
||||
int32 printText8Var5;
|
||||
int32 printText8Var6;
|
||||
int32 TEXT_CurrentLetterY;
|
||||
uint8 *printText8Var8;
|
||||
int32 newGameVar4;
|
||||
int32 newGameVar5;
|
||||
int32 hasHiddenVox; // printTextVar5
|
||||
int32 voxHiddenIndex;
|
||||
int32 printText10Var1;
|
||||
int32 addLineBreakX;
|
||||
int16 pt8s4[96];
|
||||
int32 printText8PrepareBufferVar2;
|
||||
|
||||
int32 currDialTextEntry; // ordered entry
|
||||
int32 nextDialTextEntry; // ordered entry
|
||||
int8 currentVoxBankFile[256];
|
||||
|
||||
int32 showDialogueBubble;
|
||||
|
||||
|
||||
/** Initialize dialogue
|
||||
@param bankIdx Text bank index*/
|
||||
void initTextBank(int32 bankIdx);
|
||||
|
||||
/** Display a certain dialogue text in the screen
|
||||
@param x X coordinate in screen
|
||||
@param y Y coordinate in screen
|
||||
@param dialogue ascii text to display */
|
||||
void drawText(int32 x, int32 y, int8 *dialogue);
|
||||
|
||||
void drawTextFullscreen(int32 index);
|
||||
|
||||
/** Gets dialogue text width size
|
||||
@param dialogue ascii text to display */
|
||||
int32 getTextSize(int8 *dialogue);
|
||||
|
||||
void initDialogueBox();
|
||||
void initInventoryDialogueBox();
|
||||
|
||||
void initText(int32 index);
|
||||
int printText10();
|
||||
|
||||
void setFont(uint8 *font, int32 spaceBetween, int32 charSpace);
|
||||
|
||||
/** Set font type parameters
|
||||
@param spaceBetween number in pixels of space between characters
|
||||
@param charSpace number in pixels of the character space */
|
||||
void setFontParameters(int32 spaceBetween, int32 charSpace);
|
||||
|
||||
/** Set the font cross color
|
||||
@param color color number to choose */
|
||||
void setFontCrossColor(int32 color);
|
||||
|
||||
/** Set the font color
|
||||
@param color color number to choose */
|
||||
void setFontColor(int32 color);
|
||||
|
||||
/** Set font color parameters to precess cross color display
|
||||
@param stopColor color number to stop
|
||||
@param startColor color number to start
|
||||
@param stepSize step size to change between those colors */
|
||||
void setTextCrossColor(int32 stopColor, int32 startColor, int32 stepSize);
|
||||
|
||||
/** Get dialogue text into text buffer
|
||||
@param index dialogue index */
|
||||
int32 getText(int32 index);
|
||||
|
||||
/** Gets menu dialogue text
|
||||
@param index text index to display
|
||||
@param dialogue dialogue text buffer to display */
|
||||
void getMenuText(int32 index, int8 *text);
|
||||
|
||||
void textClipFull();
|
||||
void textClipSmall();
|
||||
|
||||
void drawAskQuestion(int32 index);
|
||||
|
||||
int32 playVox(int32 index);
|
||||
int32 playVoxSimple(int32 index);
|
||||
void stopVox(int32 index);
|
||||
int32 initVoxToPlay(int32 index);
|
||||
|
||||
#endif
|
788
engines/twine/xmidi.cpp
Normal file
788
engines/twine/xmidi.cpp
Normal file
@ -0,0 +1,788 @@
|
||||
/** @file xmidi.cpp
|
||||
@brief
|
||||
This file contains MIDI-related routines.
|
||||
These routines were adapted from ScrummVM/Exult engine source code.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2013 The ScrummVM/ExultEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "xmidi.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define warning(...) if (cfgfile.Debug) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
|
||||
//#define info(...) if (cfgfile.Debug) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
|
||||
#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
|
||||
|
||||
/**
|
||||
* Provides comprehensive information on the next event in the MIDI stream.
|
||||
* An EventInfo struct is instantiated by format-specific implementations
|
||||
* of MidiParser::parseNextEvent() each time another event is needed.
|
||||
*
|
||||
* Adapted from the ScummVM project
|
||||
*/
|
||||
struct EventInfo {
|
||||
uint8 * start; ///< Position in the MIDI stream where the event starts.
|
||||
///< For delta-based MIDI streams (e.g. SMF and XMIDI), this points to the delta.
|
||||
uint32 delta; ///< The number of ticks after the previous event that this event should occur.
|
||||
uint8 event; ///< Upper 4 bits are the command code, lower 4 bits are the MIDI channel.
|
||||
///< For META, event == 0xFF. For SysEx, event == 0xF0.
|
||||
union {
|
||||
struct {
|
||||
uint8 param1; ///< The first parameter in a simple MIDI message.
|
||||
uint8 param2; ///< The second parameter in a simple MIDI message.
|
||||
} basic;
|
||||
struct {
|
||||
uint8 type; ///< For META events, this indicates the META type.
|
||||
uint8 * data; ///< For META and SysEx events, this points to the start of the data.
|
||||
} ext;
|
||||
};
|
||||
uint32 length; ///< For META and SysEx blocks, this indicates the length of the data.
|
||||
///< For Note On events, a non-zero value indicates that no Note Off event
|
||||
///< will occur, and the MidiParser will have to generate one itself.
|
||||
///< For all other events, this value should always be zero.
|
||||
};
|
||||
|
||||
// Adapted from the ScummVM project
|
||||
struct XMIDI_info {
|
||||
uint8 num_tracks;
|
||||
uint8* tracks[120]; // Maximum 120 tracks
|
||||
};
|
||||
|
||||
/* Linked list of saved note offs to be injected in the midi stream at a later
|
||||
* time. */
|
||||
struct CachedEvent {
|
||||
struct EventInfo* eventInfo;
|
||||
uint32 time;
|
||||
struct CachedEvent* next;
|
||||
};
|
||||
static struct CachedEvent* cached_events = NULL;
|
||||
|
||||
/*
|
||||
* Forward declarations
|
||||
*/
|
||||
static uint16 read2low(uint8** data);
|
||||
static uint32 read4high(uint8** data);
|
||||
static void write4high(uint8** data, uint32 val);
|
||||
static void write2high(uint8** data, uint16 val);
|
||||
static uint32 readVLQ2(uint8** data);
|
||||
static uint32 readVLQ(uint8** data);
|
||||
static int32 putVLQ(uint8* dest, uint32 value);
|
||||
|
||||
/* Returns an EventInfo struct if there is a cached event that should be
|
||||
* played between current_time and current_time + delta. The cached event
|
||||
* is removed from the internal list of cached events! */
|
||||
static struct EventInfo* pop_cached_event(uint32 current_time, uint32 delta);
|
||||
static void save_event(struct EventInfo* info, uint32 current_time);
|
||||
|
||||
static int32 read_event_info(uint8* data, struct EventInfo* info, uint32 current_time);
|
||||
static int32 put_event(uint8* dest, struct EventInfo* info);
|
||||
static int32 convert_to_mtrk(uint8* data, uint32 size, uint8* dest);
|
||||
static int32 read_XMIDI_header(uint8* data, uint32 size, struct XMIDI_info* info);
|
||||
|
||||
// Adapted from the ScummVM project
|
||||
static uint16 read2low(uint8** data)
|
||||
{
|
||||
uint8* d = *data;
|
||||
uint16 value = (d[1] << 8) | d[0];
|
||||
*data = (d + 2);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Adapted from the ScummVM project
|
||||
static uint32 read4high(uint8** data)
|
||||
{
|
||||
uint8* d = *data;
|
||||
uint16 value = (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | (d[3]);
|
||||
*data = (d + 4);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Adapted from the ScummVM project
|
||||
static void write4high(uint8** data, uint32 val)
|
||||
{
|
||||
uint8* d = *data;
|
||||
*d++ = (val >> 24) & 0xff;
|
||||
*d++ = (val >> 16) & 0xff;
|
||||
*d++ = (val >> 8) & 0xff;
|
||||
*d++ = val & 0xff;
|
||||
*data = d;
|
||||
}
|
||||
|
||||
// Adapted from the ScummVM project
|
||||
static void write2high(uint8** data, uint16 val)
|
||||
{
|
||||
uint8* d = *data;
|
||||
*d++ = (val >> 8) & 0xff;
|
||||
*d++ = val & 0xff;
|
||||
*data = d;
|
||||
}
|
||||
|
||||
// This is a special XMIDI variable length quantity
|
||||
//
|
||||
// Adapted from the ScummVM project
|
||||
static uint32 readVLQ2(uint8** data)
|
||||
{
|
||||
uint8* pos = *data;
|
||||
uint32 value = 0;
|
||||
while (!(pos[0] & 0x80)) {
|
||||
value += *pos++;
|
||||
}
|
||||
*data = pos;
|
||||
return value;
|
||||
}
|
||||
|
||||
// This is the conventional (i.e. SMF) variable length quantity
|
||||
//
|
||||
// Adapted from the ScummVM project
|
||||
static uint32 readVLQ(uint8** data) {
|
||||
uint8* d = *data;
|
||||
uint8 str;
|
||||
uint32 value = 0;
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
str = *d++;
|
||||
value = (value << 7) | (str & 0x7F);
|
||||
if (!(str & 0x80))
|
||||
break;
|
||||
}
|
||||
*data = d;
|
||||
return value;
|
||||
}
|
||||
|
||||
// PutVLQ
|
||||
//
|
||||
// Write a Conventional Variable Length Quantity
|
||||
//
|
||||
// Code adapted from the Exult engine
|
||||
static int32 putVLQ(uint8* dest, uint32 value)
|
||||
{
|
||||
int32 buffer;
|
||||
int32 j, i = 1;
|
||||
|
||||
buffer = value & 0x7F;
|
||||
while (value >>= 7)
|
||||
{
|
||||
buffer <<= 8;
|
||||
buffer |= ((value & 0x7F) | 0x80);
|
||||
i++;
|
||||
}
|
||||
if (!dest) return i;
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
*dest++ = buffer & 0xFF;
|
||||
buffer >>= 8;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void save_event(struct EventInfo* info, uint32 current_time)
|
||||
{
|
||||
uint32 delta = info->length;
|
||||
struct CachedEvent *prev, *next, *temp;
|
||||
|
||||
temp = malloc(sizeof(struct CachedEvent));
|
||||
temp->eventInfo = info;
|
||||
temp->time = current_time + delta;
|
||||
temp->next = NULL;
|
||||
|
||||
//info("Saving event to be stopped at %2X", temp->time);
|
||||
|
||||
if (!cached_events) {
|
||||
cached_events = temp;
|
||||
}
|
||||
else {
|
||||
prev = NULL;
|
||||
next = cached_events;
|
||||
|
||||
/* Find the proper time slot */
|
||||
while (next && next->time < current_time + delta) {
|
||||
prev = next;
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
prev->next = temp;
|
||||
}
|
||||
else {
|
||||
if (prev) {
|
||||
temp->next = prev->next;
|
||||
prev->next = temp;
|
||||
}
|
||||
else {
|
||||
temp->next = cached_events;
|
||||
cached_events = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct EventInfo* pop_cached_event(uint32 current_time, uint32 delta)
|
||||
{
|
||||
struct EventInfo* info = NULL;
|
||||
struct CachedEvent* old;
|
||||
|
||||
if (cached_events && cached_events->time < current_time + delta) {
|
||||
info = cached_events->eventInfo;
|
||||
info->delta = cached_events->time - current_time;
|
||||
old = cached_events;
|
||||
cached_events = cached_events->next;
|
||||
free(old);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// Adapted from the ScummVM project
|
||||
static int32 read_event_info(uint8* data, struct EventInfo* info, uint32 current_time)
|
||||
{
|
||||
struct EventInfo* injectedEvent;
|
||||
info->start = data;
|
||||
info->delta = readVLQ2(&data);
|
||||
info->event = *data++;
|
||||
|
||||
/* Advance current time here, but not yet in the main conversion loop.
|
||||
* This is so that cached events can still be injected correctly */
|
||||
current_time += info->delta;
|
||||
|
||||
//info("%02X: Parsing event %02X", current_time, info->event);
|
||||
switch (info->event >> 4) {
|
||||
case 0x9: // Note On
|
||||
info->basic.param1 = *(data++);
|
||||
info->basic.param2 = *(data++);
|
||||
info->length = readVLQ(&data);
|
||||
if (info->basic.param2 == 0) {
|
||||
info->event = (info->event & 0x0F) | 0x80;
|
||||
info->length = 0;
|
||||
}
|
||||
else {
|
||||
//info("Found Note On with duration %X. Saving a Note Off for later", info->length);
|
||||
injectedEvent = malloc(sizeof(struct EventInfo));
|
||||
injectedEvent->event = 0x80 | (info->event & 0x0f);
|
||||
injectedEvent->basic.param1 = info->basic.param1;
|
||||
injectedEvent->basic.param2 = info->basic.param2;
|
||||
injectedEvent->length = info->length;
|
||||
save_event(injectedEvent, current_time);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
case 0xD:
|
||||
info->basic.param1 = *(data++);
|
||||
info->basic.param2 = 0;
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
case 0xA:
|
||||
case 0xE:
|
||||
info->basic.param1 = *(data++);
|
||||
info->basic.param2 = *(data++);
|
||||
break;
|
||||
|
||||
case 0xB:
|
||||
info->basic.param1 = *(data++);
|
||||
info->basic.param2 = *(data++);
|
||||
|
||||
// This isn't a full XMIDI implementation, but it should
|
||||
// hopefully be "good enough" for most things.
|
||||
|
||||
switch (info->basic.param1) {
|
||||
// Simplified XMIDI looping.
|
||||
case 0x74: { // XMIDI_CONTROLLER_FOR_LOOP
|
||||
#if 0 // TODO
|
||||
uint8 *pos = data;
|
||||
if (_loopCount < ARRAYSIZE(_loop) - 1)
|
||||
_loopCount++;
|
||||
/*else
|
||||
warning("XMIDI: Exceeding maximum loop count %d", ARRAYSIZE(_loop));*/
|
||||
|
||||
_loop[_loopCount].pos = pos;
|
||||
_loop[_loopCount].repeat = info->basic.param2;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x75: // XMIDI_CONTORLLER_NEXT_BREAK
|
||||
#if 0 // TODO
|
||||
if (_loopCount >= 0) {
|
||||
if (info->basic.param2 < 64) {
|
||||
// End the current loop.
|
||||
_loopCount--;
|
||||
} else {
|
||||
// Repeat 0 means "loop forever".
|
||||
if (_loop[_loopCount].repeat) {
|
||||
if (--_loop[_loopCount].repeat == 0)
|
||||
_loopCount--;
|
||||
else
|
||||
data = _loop[_loopCount].pos;
|
||||
} else {
|
||||
data = _loop[_loopCount].pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x77: // XMIDI_CONTROLLER_CALLBACK_TRIG
|
||||
#if 0 // TODO
|
||||
if (_callbackProc)
|
||||
_callbackProc(info->basic.param2, _callbackData);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x6e: // XMIDI_CONTROLLER_CHAN_LOCK
|
||||
case 0x6f: // XMIDI_CONTROLLER_CHAN_LOCK_PROT
|
||||
case 0x70: // XMIDI_CONTROLLER_VOICE_PROT
|
||||
case 0x71: // XMIDI_CONTROLLER_TIMBRE_PROT
|
||||
case 0x72: // XMIDI_CONTROLLER_BANK_CHANGE
|
||||
case 0x73: // XMIDI_CONTROLLER_IND_CTRL_PREFIX
|
||||
case 0x76: // XMIDI_CONTROLLER_CLEAR_BB_COUNT
|
||||
case 0x78: // XMIDI_CONTROLLER_SEQ_BRANCH_INDEX
|
||||
default:
|
||||
if (info->basic.param1 >= 0x6e && info->basic.param1 <= 0x78) {
|
||||
/*warning("Unsupported XMIDI controller %d (0x%2x)",
|
||||
info->basic.param1, info->basic.param1);*/
|
||||
}
|
||||
}
|
||||
|
||||
// Should we really keep passing the XMIDI controller events to
|
||||
// the MIDI driver, or should we turn them into some kind of
|
||||
// NOP events? (Dummy meta events, perhaps?) Ah well, it has
|
||||
// worked so far, so it shouldn't cause any damage...
|
||||
|
||||
break;
|
||||
|
||||
case 0xF: // Meta or SysEx event
|
||||
switch (info->event & 0x0F) {
|
||||
case 0x2: // Song Position Pointer
|
||||
info->basic.param1 = *(data++);
|
||||
info->basic.param2 = *(data++);
|
||||
break;
|
||||
|
||||
case 0x3: // Song Select
|
||||
info->basic.param1 = *(data++);
|
||||
info->basic.param2 = 0;
|
||||
break;
|
||||
|
||||
case 0x6:
|
||||
case 0x8:
|
||||
case 0xA:
|
||||
case 0xB:
|
||||
case 0xC:
|
||||
case 0xE:
|
||||
info->basic.param1 = info->basic.param2 = 0;
|
||||
break;
|
||||
|
||||
case 0x0: // SysEx
|
||||
info->length = readVLQ(&data);
|
||||
info->ext.data = data;
|
||||
data += info->length;
|
||||
break;
|
||||
|
||||
case 0xF: // META event
|
||||
info->ext.type = *(data++);
|
||||
info->length = readVLQ(&data);
|
||||
info->ext.data = data;
|
||||
data += info->length;
|
||||
if (info->ext.type == 0x51 && info->length == 3) {
|
||||
// Tempo event. We want to make these constant 500,000.
|
||||
info->ext.data[0] = 0x07;
|
||||
info->ext.data[1] = 0xA1;
|
||||
info->ext.data[2] = 0x20;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//warning("MidiParser_XMIDI::parseNextEvent: Unsupported event code %x (delta: %X)", info->event, info->delta);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (data - info->start);
|
||||
}
|
||||
|
||||
// Code adapted from the Exult engine
|
||||
static int32 put_event(uint8* dest, struct EventInfo* info)
|
||||
{
|
||||
int32 i = 0,j;
|
||||
int32 rc = 0;
|
||||
static uint8 last_event = 0;
|
||||
|
||||
rc = putVLQ (dest, info->delta);
|
||||
if (dest) dest += rc;
|
||||
i += rc;
|
||||
|
||||
if ((info->event != last_event) || (info->event >= 0xF0))
|
||||
{
|
||||
if (dest) *dest++ = (info->event);
|
||||
i++;
|
||||
}
|
||||
|
||||
last_event = info->event;
|
||||
|
||||
switch (info->event >> 4)
|
||||
{
|
||||
// 2 bytes data
|
||||
// Note off, Note on, Aftertouch, Controller and Pitch Wheel
|
||||
case 0x8: case 0x9: case 0xA: case 0xB: case 0xE:
|
||||
if (dest)
|
||||
{
|
||||
*dest++ = (info->basic.param1);
|
||||
*dest++ = (info->basic.param2);
|
||||
}
|
||||
i += 2;
|
||||
break;
|
||||
|
||||
|
||||
// 1 bytes data
|
||||
// Program Change and Channel Pressure
|
||||
case 0xC: case 0xD:
|
||||
if (dest) *dest++ = (info->basic.param1);
|
||||
i++;
|
||||
break;
|
||||
|
||||
|
||||
// Variable length
|
||||
// SysEx
|
||||
case 0xF:
|
||||
if (info->event == 0xFF)
|
||||
{
|
||||
if (dest) *dest++ = (info->basic.param1);
|
||||
i++;
|
||||
}
|
||||
|
||||
rc = putVLQ (dest, info->length);
|
||||
if (dest) dest += rc;
|
||||
i += rc;
|
||||
|
||||
if (info->length)
|
||||
{
|
||||
for (j = 0; j < (int)info->length; j++)
|
||||
{
|
||||
if (dest) *dest++ = (info->ext.data[j]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
// Never occur
|
||||
default:
|
||||
//warning("Not supposed to see this");
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Code adapted from the Exult engine
|
||||
static int32 convert_to_mtrk(uint8* data, uint32 size, uint8* dest)
|
||||
{
|
||||
int32 time = 0;
|
||||
int32 lasttime = 0;
|
||||
int32 rc;
|
||||
uint32 i = 8;
|
||||
uint8* size_pos = NULL;
|
||||
uint8* data_end = data + size;
|
||||
struct XMIDI_info xmidi_info;
|
||||
struct EventInfo info;
|
||||
struct EventInfo* cached_info;
|
||||
|
||||
if (dest)
|
||||
{
|
||||
*dest++ =('M');
|
||||
*dest++ =('T');
|
||||
*dest++ =('r');
|
||||
*dest++ =('k');
|
||||
|
||||
size_pos = dest;
|
||||
dest += 4;
|
||||
}
|
||||
|
||||
rc = read_XMIDI_header(data, size, &xmidi_info);
|
||||
if (!rc) {
|
||||
//warning("Failed to read XMIDI header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
data = xmidi_info.tracks[0];
|
||||
|
||||
while (data < data_end)
|
||||
{
|
||||
//info("=======================================================================");
|
||||
// We don't write the end of stream marker here, we'll do it later
|
||||
if (data[0] == 0xFF && data[1] == 0x2f) {
|
||||
//info("Got EOX");
|
||||
// lasttime = event->time;
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = read_event_info(data, &info, time);
|
||||
if (!rc) {
|
||||
//warning("Failed to read event info %ld bytes from the end!", data_end - data);
|
||||
return 0;
|
||||
}
|
||||
data += rc;
|
||||
|
||||
cached_info = pop_cached_event(time, info.delta);
|
||||
while (cached_info) {
|
||||
//info("Injecting event %2X at time %2X", cached_info->event, time);
|
||||
rc = put_event(dest, cached_info);
|
||||
if (!rc) {
|
||||
//warning("Failed to save injected event!");
|
||||
return 0;
|
||||
}
|
||||
if (dest) dest += rc;
|
||||
i += rc;
|
||||
time += cached_info->delta;
|
||||
info.delta -= cached_info->delta;
|
||||
free(cached_info);
|
||||
cached_info = pop_cached_event(time, info.delta);
|
||||
}
|
||||
|
||||
//info("Saving event %02X", info.event);
|
||||
rc = put_event(dest, &info);
|
||||
if (!rc) {
|
||||
//warning("Failed to save event!");
|
||||
return 0;
|
||||
}
|
||||
if (dest) dest += rc;
|
||||
i += rc;
|
||||
time += info.delta;
|
||||
if (info.event == 0xFF && info.ext.type == 0x2F) {
|
||||
//info("GOT EOX");
|
||||
data = data_end;
|
||||
}
|
||||
}
|
||||
|
||||
// Write out end of stream marker
|
||||
if (lasttime > time) {
|
||||
rc = putVLQ (dest, lasttime-time);
|
||||
if (dest) dest += rc;
|
||||
i += rc;
|
||||
}
|
||||
else {
|
||||
rc = putVLQ (dest, 0);
|
||||
if (dest) dest += rc;
|
||||
i += rc;
|
||||
}
|
||||
if (dest) {
|
||||
*dest++ = (0xFF);
|
||||
*dest++ = (0x2F);
|
||||
}
|
||||
rc = putVLQ (dest, 0);
|
||||
i += 2+rc;
|
||||
|
||||
if (dest)
|
||||
{
|
||||
dest += rc;
|
||||
write4high(&size_pos, i-8);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Code adapted from the ScummVM project, which originally adapted it from the
|
||||
* Exult engine */
|
||||
static int32 read_XMIDI_header(uint8* data, uint32 size, struct XMIDI_info* info)
|
||||
{
|
||||
uint32 i = 0;
|
||||
uint8 *start;
|
||||
uint32 len;
|
||||
uint32 chunkLen;
|
||||
char buf[32];
|
||||
uint8 *pos = data;
|
||||
int32 tracksRead = 0;
|
||||
|
||||
if (!memcmp(pos, "FORM", 4)) {
|
||||
pos += 4;
|
||||
|
||||
// Read length of
|
||||
len = read4high(&pos);
|
||||
start = pos;
|
||||
|
||||
// XDIRless XMIDI, we can handle them here.
|
||||
if (!memcmp(pos, "XMID", 4)) {
|
||||
//warning("XMIDI doesn't have XDIR");
|
||||
pos += 4;
|
||||
info->num_tracks = 1;
|
||||
} else if (memcmp(pos, "XDIR", 4)) {
|
||||
// Not an XMIDI that we recognize
|
||||
//warning("Expected 'XDIR' but found '%c%c%c%c'", pos[0], pos[1], pos[2], pos[3]);
|
||||
return 0;
|
||||
} else {
|
||||
// Seems Valid
|
||||
pos += 4;
|
||||
info->num_tracks = 0;
|
||||
|
||||
for (i = 4; i < len; i++) {
|
||||
// Read 4 bytes of type
|
||||
memcpy(buf, pos, 4);
|
||||
pos += 4;
|
||||
|
||||
// Read length of chunk
|
||||
chunkLen = read4high(&pos);
|
||||
|
||||
// Add eight bytes
|
||||
i += 8;
|
||||
|
||||
if (memcmp(buf, "INFO", 4) == 0) {
|
||||
// Must be at least 2 bytes long
|
||||
if (chunkLen < 2) {
|
||||
//warning("Invalid chunk length %d for 'INFO' block", (int)chunkLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
info->num_tracks = (uint8)read2low(&pos);
|
||||
pos += 2;
|
||||
|
||||
if (chunkLen > 2) {
|
||||
//warning("Chunk length %d is greater than 2", (int)chunkLen);
|
||||
//pos += chunkLen - 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Must align
|
||||
pos += (chunkLen + 1) & ~1;
|
||||
i += (chunkLen + 1) & ~1;
|
||||
}
|
||||
|
||||
// Didn't get to fill the header
|
||||
if (info->num_tracks == 0) {
|
||||
//warning("Didn't find a valid track count");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ok now to start part 2
|
||||
// Goto the right place
|
||||
pos = start + ((len + 1) & ~1);
|
||||
|
||||
if (memcmp(pos, "CAT ", 4)) {
|
||||
// Not an XMID
|
||||
//warning("Expected 'CAT ' but found '%c%c%c%c'", pos[0], pos[1], pos[2], pos[3]);
|
||||
return 0;
|
||||
}
|
||||
pos += 4;
|
||||
|
||||
// Now read length of this track
|
||||
len = read4high(&pos);
|
||||
|
||||
if (memcmp(pos, "XMID", 4)) {
|
||||
// Not an XMID
|
||||
//warning("Expected 'XMID' but found '%c%c%c%c'", pos[0], pos[1], pos[2], pos[3]);
|
||||
return 0;
|
||||
}
|
||||
pos += 4;
|
||||
|
||||
}
|
||||
|
||||
// Ok it's an XMIDI.
|
||||
// We're going to identify and store the location for each track.
|
||||
if (info->num_tracks > ARRAYSIZE(info->tracks)) {
|
||||
//warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(info->tracks), (int)info->num_tracks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (tracksRead < info->num_tracks) {
|
||||
if (!memcmp(pos, "FORM", 4)) {
|
||||
// Skip this plus the 4 bytes after it.
|
||||
pos += 8;
|
||||
} else if (!memcmp(pos, "XMID", 4)) {
|
||||
// Skip this.
|
||||
pos += 4;
|
||||
} else if (!memcmp(pos, "TIMB", 4)) {
|
||||
// Custom timbres?
|
||||
// We don't support them.
|
||||
// Read the length, skip it, and hope there was nothing there.
|
||||
pos += 4;
|
||||
len = read4high(&pos);
|
||||
pos += (len + 1) & ~1;
|
||||
} else if (!memcmp(pos, "EVNT", 4)) {
|
||||
// Ahh! What we're looking for at last.
|
||||
info->tracks[tracksRead] = pos + 8; // Skip the EVNT and length bytes
|
||||
pos += 4;
|
||||
len = read4high(&pos);
|
||||
pos += (len + 1) & ~1;
|
||||
++tracksRead;
|
||||
} else {
|
||||
//warning("Hit invalid block '%c%c%c%c' while scanning for track locations", pos[0], pos[1], pos[2], pos[3]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************* Public API *********************************/
|
||||
// Code adapted from the Exult engine
|
||||
uint32 convert_to_midi(uint8* data, uint32 size, uint8** dest)
|
||||
{
|
||||
int32 len;
|
||||
uint8* d,* start;
|
||||
|
||||
if (!dest)
|
||||
return 0;
|
||||
|
||||
/* Do a dry run first so we know how much memory to allocate */
|
||||
len = convert_to_mtrk (data, size, NULL);
|
||||
if (!len) {
|
||||
//warning("Failed dummy conversion!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//info("Allocating %d bytes of memory", len);
|
||||
d = malloc(len + 14);
|
||||
if (!d) {
|
||||
perror("Could not allocate memory");
|
||||
return 0;
|
||||
}
|
||||
start = d;
|
||||
|
||||
*d++ = ('M');
|
||||
*d++ = ('T');
|
||||
*d++ = ('h');
|
||||
*d++ = ('d');
|
||||
|
||||
write4high (&d, 6);
|
||||
|
||||
write2high (&d, 0);
|
||||
write2high (&d, 1);
|
||||
write2high (&d, 60); // The PPQN
|
||||
|
||||
len = convert_to_mtrk(data, size, d);
|
||||
if (!len) {
|
||||
//warning("Failed to convert");
|
||||
free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*dest = start;
|
||||
|
||||
return len + 14;
|
||||
}
|
||||
|
45
engines/twine/xmidi.h
Normal file
45
engines/twine/xmidi.h
Normal file
@ -0,0 +1,45 @@
|
||||
/** @file xmidi.h
|
||||
@brief
|
||||
This file contains MIDI-related routines.
|
||||
These routines were adapted from ScrummVM/Exult engine source code.
|
||||
|
||||
TwinEngine: a Little Big Adventure engine
|
||||
|
||||
Copyright (C) 2013 The TwinEngine team
|
||||
Copyright (C) 2013 The ScrummVM/ExultEngine team
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef XMIDI_H
|
||||
#define XMIDI_H
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
/**
|
||||
* Credit where credit is due:
|
||||
* Most of code to convert XMIDI to MIDI is adapted from either the ScummVM
|
||||
* project or the Exult game engine.
|
||||
* //risca
|
||||
*/
|
||||
|
||||
/*
|
||||
* Takes a pointer to XMIDI data of size 'size' and converts it to MIDI. The
|
||||
* result is allocated dynamically and saved to the 'dest' pointer. Returns
|
||||
* the size of the MIDI data or 0 on error.
|
||||
*/
|
||||
uint32 convert_to_midi(uint8* data, uint32 size, uint8** dest);
|
||||
|
||||
#endif // XMIDI_H
|
Loading…
x
Reference in New Issue
Block a user