TWINE: initial import

This commit is contained in:
Martin Gerhardy 2020-10-14 14:20:38 +02:00 committed by Eugene Sandulenko
parent cff369a14b
commit bc35611293
74 changed files with 24235 additions and 0 deletions

540
engines/twine/actor.cpp Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

147
engines/twine/animations.h Normal file
View 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
View 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
View 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

View 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
View 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

View 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
}
}

View 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
View 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

View 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);
}
}
}
}

View 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

View 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
View 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
View 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
View 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
View 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
View 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

View 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);
}

View 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
View 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
View 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
View 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, &currentSceneIdx, 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
View 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
View 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(&currentGrid, HQR_LBA_GRI_FILE, index);
// load layouts from file
hqrGetallocEntry(&currentBll, 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
View 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
View 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
View 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
View 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
View 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
View 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 (CohenSutherland 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

86
engines/twine/menu.h Normal file
View 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

View 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);
}
}

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

78
engines/twine/renderer.h Normal file
View 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
View 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
View 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
View 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(&currentScene, 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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

View 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);
}

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

295
engines/twine/sound.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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