TWINE: added a few lba2 stubs and converted some code from lba2-classic

This commit is contained in:
Martin Gerhardy 2024-04-29 00:18:20 +02:00
parent de891e4729
commit d46820d565
23 changed files with 1306 additions and 117 deletions

View File

@ -100,9 +100,8 @@ public:
* @param z sound generating entity z position
* @param actorIdx
*/
// HQ_MixSample
void playSample(int32 index, int32 repeat = 1, int32 x = 128, int32 y = 128, int32 z = 128, int32 actorIdx = -1);
void playSample(int32 index, int32 repeat, const IVec3 &pos, int32 actorIdx = -1) {
void playSample(int32 index, int32 repeat = 1, int32 x = 128, int32 y = 128, int32 z = 128, int32 actorIdx = -1); // HQ_3D_MixSample
void playSample(int32 index, int32 repeat, const IVec3 &pos, int32 actorIdx = -1) { // HQ_MixSample
playSample(index, repeat, pos.x, pos.y, pos.z, actorIdx);
}
@ -121,10 +120,10 @@ public:
int32 getActorChannel(int32 index);
/** Stops a specific sample */
void stopSample(int32 index);
void stopSample(int32 index); // HQ_StopOneSample
/** Check if a sample is playing */
int32 isSamplePlaying(int32 index);
int32 isSamplePlaying(int32 index); // IsSamplePlaying
/** Play VOX sample */
bool playVoxSample(const TextEntry *text);

View File

@ -30,11 +30,14 @@ MODULE_OBJS := \
scene/animations.o \
scene/buggy.o \
scene/collision.o \
scene/dart.o \
scene/extra.o \
scene/gamestate.o \
scene/grid.o \
scene/movements.o \
scene/rain.o \
scene/scene.o \
scene/wagon.o \
\
script/script_life.o \
script/script_move.o \

View File

@ -28,21 +28,25 @@
namespace TwinE {
// MAX_INCRUST_DISP
#define OVERLAY_MAX_ENTRIES 10
enum class OverlayType {
koSprite = 0,
koNumber = 1,
koNumberRange = 2,
koInventoryItem = 3,
koText = 4,
koInventory = 5, // lba2
koSysText = 6, // lba2
koFlash = 7, //lba2
koRain = 8, //lba2
koSprite = 0, // INCRUST_SPRITE
koNumber = 1, // INCRUST_NUM
koNumberRange = 2, // INCRUST_CMPT
koInventoryItem = 3, // INCRUST_OBJ
koText = 4, // INCRUST_TEXT
koInventory = 5, // lba2 (INCRUST_INVENTORY)
koSysText = 6, // lba2 (INCRUST_SYS_TEXT)
koFlash = 7, // lba2 (INCRUST_ECLAIR)
koRain = 8, // lba2 (INCRUST_PLUIE)
koMax
};
// lba2
#define INCRUST_YCLIP (1 << 8)
enum class OverlayPosType {
koNormal = 0,
koFollowActor = 1

View File

@ -116,6 +116,8 @@ void Actor::setBehaviour(HeroBehaviourType behaviour) {
_heroBehaviour = behaviour;
sceneHero->_entityDataPtr = &_heroEntityPROTOPACK;
break;
case HeroBehaviourType::kMax:
break;
}
const BodyType bodyIdx = sceneHero->_genBody;
@ -368,6 +370,56 @@ void Actor::giveExtraBonus(int32 actorIdx) {
}
}
// Lba2
#define START_AROUND_BETA 1024
#define END_AROUND_BETA 3072
#define STEP_AROUND_BETA 128 // 16 pos testees
#define GetAngle2D(x0, z0, x1, z1) GetAngleVector2D((x1) - (x0), (z1) - (z0))
void Actor::posObjectAroundAnother(uint8 numsrc, uint8 numtopos) {
#if 0
ActorStruct *objsrc;
ActorStruct *objtopos;
int32 beta, dist, dist2;
int32 step;
objsrc = _engine->_scene->getActor(numsrc);
objtopos = _engine->_scene->getActor(numtopos);
int32 xb = objsrc->Obj.X;
int32 zb = objsrc->Obj.Z;
objtopos->Obj.Y = objsrc->Obj.Y;
dist = MAX(objsrc->XMin, objsrc->XMax);
dist = MAX(dist, objsrc->ZMin);
dist = MAX(dist, objsrc->ZMax);
dist2 = MAX(objtopos->XMin, objtopos->XMax);
dist2 = MAX(dist2, objtopos->ZMin);
dist2 = MAX(dist2, objtopos->ZMax);
dist += dist / 2 + dist2 + dist2 / 2;
beta = ClampAngle(objsrc->Obj.Beta + START_AROUND_BETA);
for (step = 0; step < (4096 / STEP_AROUND_BETA); step++, beta += STEP_AROUND_BETA) {
beta &= 4095;
_engine->_renderer->rotate(0, dist, beta);
objtopos->Obj.X = xb + X0;
objtopos->Obj.Z = zb + Z0;
if (_engine->_collision->checkValidObjPos(numtopos, numsrc)) {
// accepte position
break;
}
}
objtopos->Obj.Beta = ClampAngle(GetAngle2D(xb, zb, objtopos->Obj.X, objtopos->Obj.Z));
#endif
}
void ActorStruct::loadModel(int32 modelIndex, bool lba1) {
_body = modelIndex;
if (!_staticFlags.bIsSpriteActor) {

View File

@ -77,7 +77,7 @@ struct StaticFlagsStruct {
// take smaller value for bound, or if not set take average for bound
uint32 bUseMiniZv : 1; // 0x008000 MINI_ZV - square on smaller dimension (if 3D object)
uint32 bHasInvalidPosition : 1; // 0x010000
uint32 bNoElectricShock : 1; // 0x020000
uint32 bNoElectricShock : 1; // 0x020000 NO_CHOC
uint32 bHasSpriteAnim3D : 1; // 0x040000
uint32 bNoPreClipping : 1; // 0x080000
uint32 bHasZBuffer : 1; // 0x100000
@ -142,7 +142,7 @@ struct BonusParameter {
*
* Such as characters, doors, moving plataforms, invisible actors, ...
*/
class ActorStruct {
class ActorStruct { // T_OBJET
private:
ShapeType _col = ShapeType::kNone; // collision
bool _brickCausesDamage = false;
@ -150,8 +150,8 @@ private:
EntityData _entityData;
public:
StaticFlagsStruct _staticFlags;
DynamicFlagsStruct _workFlags;
StaticFlagsStruct _staticFlags; // Flags
DynamicFlagsStruct _workFlags; // WorkFlags
inline ShapeType brickShape() const { return _col; }
inline void setCollision(ShapeType shapeType) {
@ -188,7 +188,7 @@ public:
BonusParameter _bonusParameter;
int32 _beta = 0; // facing angle of actor. Minumum is 0 (SW). Going counter clock wise (BETA in original sources)
int32 _speed = 40; // SRot - speed of movement
ControlMode _controlMode = ControlMode::kNoMove;
ControlMode _controlMode = ControlMode::kNoMove; // Move
int32 _delayInMillis = 0;
int32 _cropLeft = 0; // Info
int32 _cropTop = 0; // Info1
@ -235,6 +235,8 @@ public:
AnimType _flagAnim = AnimType::kAnimationTypeRepeat;
int32 _spriteActorRotation = 0;
uint8 _brickSound = 0U; // CodeJeu
int32 SampleAlways = 0; // lba2
uint8 SampleVolume = 0; // lba2
BoundingBox _boundingBox; // Xmin, YMin, Zmin, Xmax, Ymax, Zmax
ActorMoveStruct realAngle;
@ -326,7 +328,7 @@ public:
* Set hero behaviour
* @param behaviour behaviour value to set
*/
void setBehaviour(HeroBehaviourType behaviour);
void setBehaviour(HeroBehaviourType behaviour); // SetComportement
/**
* Initialize 3D actor
@ -357,10 +359,13 @@ public:
void hitObj(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle);
/** Process actor carrier */
void processActorCarrier(int32 actorIdx);
void processActorCarrier(int32 actorIdx); // CheckCarrier
/** Process actor extra bonus */
void giveExtraBonus(int32 actorIdx);
// Lba2
void posObjectAroundAnother(uint8 numsrc, uint8 numtopos); // PosObjetAroundAnother
};
} // namespace TwinE

View File

@ -104,7 +104,7 @@ public:
* @param animExtra animation actions extra data
* @param actorIdx actor index
*/
bool initAnim(AnimationTypes newAnim, AnimType animType, AnimationTypes animExtra, int32 actorIdx);
bool initAnim(AnimationTypes newAnim, AnimType animType, AnimationTypes animExtra, int32 actorIdx); // InitAnim
/**
* Process acotr animation actions

View File

@ -20,25 +20,593 @@
*/
#include "twine/scene/buggy.h"
#include "twine/audio/sound.h"
#include "twine/scene/actor.h"
#include "twine/scene/animations.h"
#include "twine/scene/collision.h"
#include "twine/scene/movements.h"
#include "twine/scene/scene.h"
#include "twine/shared.h"
#include "twine/twine.h"
#define MAX_SAMPLE_PITCH 11000
#define MIN_SAMPLE_PITCH2 5000
#define MAX_SAMPLE_PITCH2 8500
#define MAX_SPEED 3800
#define TEMPO_GEAR 1200 // speed change
#define SAMPLE_BUGGY 109
namespace TwinE {
void Buggy::initBuggy(uint8 numobj, uint32 flaginit) {
S_BUGGY *ptb = &ListBuggy[0];
ActorStruct *ptrobj = _engine->_scene->getActor(numobj);
// So that the objects follow their tracks without being interrupted
// by the buggy (too bad, it will be pushed)
ptrobj->_staticFlags.bCanBePushed = true;
ptrobj->_staticFlags.bCanDrown = true;
if (flaginit == 2 // we force the repositioning of the buggy
|| (flaginit && !NumBuggy)) // first initialization
// because the empty buggy cannot be Twinsen
{
ptb->Cube = _engine->_scene->_currentSceneIdx; // Port-Ludo (Desert)
ptb->X = ptrobj->_pos.x;
ptb->Y = ptrobj->_pos.y;
ptb->Z = ptrobj->_pos.z;
ptb->Beta = ptrobj->_beta;
_engine->_actor->initBody(BodyType::btNormal, numobj);
NumBuggy = (uint8)(numobj | BUGGY_PRESENT);
} else if (NumBuggy) {
if (_engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_controlMode != ControlMode::kBuggyManual && _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_controlMode != ControlMode::kBuggy) {
int32 x, y;
if (_engine->_scene->_currentSceneIdx == ptb->Cube) {
ptrobj->_pos.x = ptb->X;
ptrobj->_pos.y = ptb->Y;
ptrobj->_pos.z = ptb->Z;
ptrobj->_beta = ptb->Beta;
_engine->_actor->initBody(BodyType::btNormal, numobj);
} else if (_engine->_scene->loadSceneCubeXY(ptb->Cube, &x, &y)) {
x -= _engine->_scene->_currentCubeX;
y -= _engine->_scene->_currentCubeY;
ptrobj->_pos.x = ptb->X + x * 32768;
ptrobj->_pos.y = ptb->Y;
ptrobj->_pos.z = ptb->Z + y * 32768;
ptrobj->_beta = ptb->Beta;
ptrobj->_staticFlags.bDoesntCastShadow = 1;
ptrobj->_staticFlags.bIsBackgrounded = 1;
ptrobj->_staticFlags.bNoElectricShock = 1;
ptrobj->_staticFlags.bHasZBuffer = 1;
_engine->_actor->initBody(BodyType::btNormal, numobj);
} else {
_engine->_actor->initBody(BodyType::btNone, numobj);
}
_engine->_movements->clearRealAngle(ptrobj);
} else {
_engine->_actor->initBody(BodyType::btNone, numobj);
}
NumBuggy = (uint8)(numobj | BUGGY_PRESENT);
} else {
_engine->_actor->initBody(BodyType::btNone, numobj);
}
}
void Buggy::resetBuggy() {
S_BUGGY *ptb = &ListBuggy[0];
NumBuggy = 0;
ptb->Cube = 0;
}
void Buggy::takeBuggy() {
#if 0
int32 sample;
ActorStruct *ptrobj = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX);
S_BUGGY *ptb = &ListBuggy[0];
ptb->SpeedRot = 1024;
ptb->LastTimer = TimerRefHR;
// TODO: ObjectClear(&ptrobj);
// Shielding in case the Buggy moved (being pushed, for example).
ptb->X = _engine->_scene->getActor(NUM_BUGGY)->_pos.x;
ptb->Y = _engine->_scene->getActor(NUM_BUGGY)->_pos.y;
ptb->Z = _engine->_scene->getActor(NUM_BUGGY)->_pos.z;
ptrobj->_pos.x = ptb->X;
ptrobj->_pos.y = ptb->Y;
ptrobj->_pos.z = ptb->Z;
ptrobj->_beta = ptb->Beta;
_engine->_movements->clearRealAngle(ptrobj); // To avoid crushing the beta.
ptrobj->_workFlags.bMANUAL_INTER_FRAME = true;
ptrobj->_staticFlags.bHasZBuffer = true;
_engine->_actor->setBehaviour(HeroBehaviourType::kBUGGY);
// Switch Buggy Scenario to NoBody.
_engine->_actor->initBody(BodyType::btNone, NUM_BUGGY);
if (ptrobj->SampleAlways) {
_engine->_sound->stopSample(ptrobj->SampleAlways);
ptrobj->SampleAlways = 0;
}
sample = SAMPLE_BUGGY;
if (_engine->_sound->isSamplePlaying(sample)) {
_engine->_sound->stopSample(sample);
}
ptrobj->SampleVolume = 20;
ParmSampleVolume = ptrobj->SampleVolume;
Gear = 0;
TimerGear = 0;
ptrobj->SampleAlways = _engine->_sound->playSample(SAMPLE_BUGGY, 4096, 0, 0,
ptrobj->_pos.x, ptrobj->_pos.y, ptrobj->_pos.z);
#endif
}
void Buggy::leaveBuggy(uint8 newcomportement) {
#if 0
static void ObjectClear(T_OBJ *ptb3d) {
memset(ptb3d, 0, sizeof(T_OBJ));
ptb3d.OBJ_3D.Body, -1
ptb3d.OBJ_3D.NextBody, -1
ptb3d.OBJ_3D.Texture, -1
ptb3d.OBJ_3D.NextTexture, -1
ptb3d.OBJ_3D.Anim, -1
}
#endif
void Buggy::leaveBuggy(HeroBehaviourType behaviour) {
int32 sample;
ActorStruct *ptrobj = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX);
S_BUGGY *ptb = &ListBuggy[0];
sample = SAMPLE_BUGGY;
if (_engine->_sound->isSamplePlaying(sample)) {
_engine->_sound->stopSample(sample);
ptrobj->SampleAlways = 0;
}
ptb->X = ptrobj->_pos.x;
ptb->Y = ptrobj->_pos.y;
ptb->Z = ptrobj->_pos.z;
ptb->Beta = ptrobj->_beta;
ptb->Cube = _engine->_scene->_currentSceneIdx;
// TODO: ObjectClear(ptrobj);
ptrobj->_workFlags.bMANUAL_INTER_FRAME = 0;
ptrobj->_staticFlags.bHasZBuffer = 0;
_engine->_actor->initBody(BodyType::btTunic, OWN_ACTOR_SCENE_INDEX);
_engine->_actor->setBehaviour(behaviour);
// Restore scenario buggy.
ptrobj = _engine->_scene->getActor(NUM_BUGGY);
ptrobj->_pos.x = ptb->X;
ptrobj->_pos.y = ptb->Y;
ptrobj->_pos.z = ptb->Z;
ptrobj->_beta = ptb->Beta;
ptrobj->_brickSound = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_brickSound;
_engine->_movements->clearRealAngle(ptrobj); // To avoid crushing the beta
_engine->_actor->initBody(BodyType::btNormal, NUM_BUGGY);
// Search for a free position for Twinsen nearby.
_engine->_actor->posObjectAroundAnother(NUM_BUGGY, OWN_ACTOR_SCENE_INDEX);
}
void Buggy::doAnimBuggy(ActorStruct *ptrobj) {
#if 0
int32 x1, y1, z1, yw;
S_BUGGY *ptb = &ListBuggy[0];
T_OBJ_3D *ptb3d = &ptrobj->Obj;
// wheels rot
int32 c, d;
int32 x, y, z;
// Trick to avoid crushing the groups in AffOneObject().
ObjectSetInterFrame(ptb3d);
if (ptrobj->_workFlags.bIsFalling || ptrobj->_workFlags.bUnk1000) {
return;
}
LongRotate(0, ptb->SpeedInc * 1024, ptb3d->Beta);
Nxw = ptb3d->X + X0 / 1024;
Nzw = ptb3d->Z + Z0 / 1024;
// Ideal altitude
yw = CalculAltitudeObjet(Nxw, Nzw, -1); // Ground Y for XZ
// test altitude #2: Forbidden triangles
// Front left wheel direction
ptb3d->CurrentFrame[3].Beta = (int16)ptb->BetaWheel;
// Front right wheel direction
ptb3d->CurrentFrame[6].Beta = (int16)ptb->BetaWheel;
// Management of 4 separate wheels.
// front right wheel
LongRotate(-400, 400, ptb3d->Beta);
x = Nxw + X0;
z = Nzw + Z0;
y = yw;
if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
y += CalculAltitudeObjet(x, z, -1);
}
c = (260 * 31415) / 1000; // Circumference * 10
d = Distance3D(ptb->Wheel[0].X, ptb->Wheel[0].Y, ptb->Wheel[0].Z, x, y, z);
if (ptb->Speed >= 0) {
ptb->Wheel[0].Angle += (4096 * 10 * d) / c;
} else {
ptb->Wheel[0].Angle -= (4096 * 10 * d) / c;
}
ptb->Wheel[0].X = x;
ptb->Wheel[0].Y = y;
ptb->Wheel[0].Z = z;
// front left wheel
LongRotate(400, 400, ptb3d->Beta);
x = Nxw + X0;
z = Nzw + Z0;
y = yw;
if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
y += CalculAltitudeObjet(x, z, -1);
}
c = (260 * 31415) / 1000; // Circumference * 10
d = Distance3D(ptb->Wheel[1].X, ptb->Wheel[1].Y, ptb->Wheel[1].Z, x, y, z);
if (ptb->Speed >= 0) {
ptb->Wheel[1].Angle += (4096 * 10 * d) / c;
} else {
ptb->Wheel[1].Angle -= (4096 * 10 * d) / c;
}
ptb->Wheel[1].X = x;
ptb->Wheel[1].Y = y;
ptb->Wheel[1].Z = z;
// back left wheel
LongRotate(400, -350, ptb3d->Beta);
x = Nxw + X0;
z = Nzw + Z0;
y = yw;
if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
y += CalculAltitudeObjet(x, z, -1);
}
c = (360 * 31415) / 1000; // Circumference * 10
d = Distance3D(ptb->Wheel[2].X, ptb->Wheel[2].Y, ptb->Wheel[2].Z, x, y, z);
if (ptb->Speed >= 0) {
ptb->Wheel[2].Angle += (4096 * 10 * d) / c;
} else {
ptb->Wheel[2].Angle -= (4096 * 10 * d) / c;
}
ptb->Wheel[2].X = x;
ptb->Wheel[2].Y = y;
ptb->Wheel[2].Z = z;
// back right wheel
LongRotate(-400, -350, ptb3d->Beta);
x = Nxw + X0;
z = Nzw + Z0;
y = yw;
if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
y += CalculAltitudeObjet(x, z, -1);
}
c = (360 * 31415) / 1000; // Circumference * 10
d = Distance3D(ptb->Wheel[3].X, ptb->Wheel[3].Y, ptb->Wheel[3].Z, x, y, z);
if (ptb->Speed >= 0) {
ptb->Wheel[3].Angle += (4096 * 10 * d) / c;
} else {
ptb->Wheel[3].Angle -= (4096 * 10 * d) / c;
}
ptb->Wheel[3].X = x;
ptb->Wheel[3].Y = y;
ptb->Wheel[3].Z = z;
// front right wheel
ptb3d->CurrentFrame[4].Alpha = (int16)ptb->Wheel[1].Angle;
// front left wheel
ptb3d->CurrentFrame[7].Alpha = (int16)ptb->Wheel[0].Angle;
// back left wheel
ptb3d->CurrentFrame[11].Alpha = (int16)ptb->Wheel[2].Angle;
// back right wheel
ptb3d->CurrentFrame[9].Alpha = (int16)ptb->Wheel[3].Angle;
// Car inclination (pitch)
ptb3d->CurrentFrame[1].Type = 0;
LongRotate(0, 400, ptb3d->Beta);
x1 = X0;
z1 = Z0;
LongRotate(0, -400, ptb3d->Beta);
if (Nxw + x1 >= 0 && Nxw + x1 < 32768 && Nzw + z1 >= 0 && Nzw + z1 < 32768) {
y = CalculAltitudeObjet(Nxw + x1, Nzw + z1, -1);
} else {
y = yw;
}
if (Nxw + X0 >= 0 && Nxw + X0 < 32768 && Nzw + Z0 >= 0 && Nzw + Z0 < 32768) {
y1 = CalculAltitudeObjet(Nxw + X0, Nzw + Z0, -1);
} else {
y1 = yw;
}
ptb3d->CurrentFrame[1].Alpha = (int16)(1024 - GetAngle2D(0, y, 800, y1));
ptb->Alpha = ptb3d->CurrentFrame[1].Alpha;
// Car inclination (roll)
LongRotate(400, 0, ptb3d->Beta);
x1 = X0;
z1 = Z0;
LongRotate(-400, 0, ptb3d->Beta);
if (Nxw + X0 >= 0 && Nxw + X0 < 32768 && Nzw + Z0 >= 0 && Nzw + Z0 < 32768) {
y = CalculAltitudeObjet(Nxw + X0, Nzw + Z0, -1);
} else {
y = yw;
}
if (Nxw + x1 >= 0 && Nxw + x1 < 32768 && Nzw + z1 >= 0 && Nzw + z1 < 32768) {
y1 = CalculAltitudeObjet(Nxw + x1, Nzw + z1, -1);
} else {
y1 = yw;
}
ptb3d->CurrentFrame[1].Gamma = (int16)GetAngle2D(y, 0, y1, 800);
// Steering wheel
ptb3d->CurrentFrame[12].Gamma = (int16)-ptb->BetaWheel;
// Twinsen's head
ptb3d->CurrentFrame[14].Beta = (int16)ptb->BetaWheel;
#endif
}
void Buggy::moveBuggy(ActorStruct *ptrobj) {
#if 0
S_BUGGY *ptb = &ListBuggy[0];
T_OBJ_3D *ptb3d = &ptrobj->Obj;
int32 pitch = 0;
int32 flagattack = false;
int32 speedinc;
int32 rotlevel;
int32 timerhr, deltatimer;
timerhr = TimerRefHR;
deltatimer = timerhr - ptb->LastTimer;
if ((Input & I_THROW) && (PtrComportement->Flags & CF_WEAPON)) {
// Are we in mage?
if (TabInv[FLAG_TUNIQUE].IdObj3D == 0) {
_engine->_actor->initBody(BodyType::btTunicTir, OWN_ACTOR_SCENE_INDEX);
} else {
_engine->_actor->initBody(BodyType::btMageTir, OWN_ACTOR_SCENE_INDEX);
}
_engine->_animations->initAnim(GEN_ANIM_LANCE, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
/* control direction pendant Aiming */
if (!ptrobj->_workFlags.bIsRotationByAnim) {
ptb3d->Beta += GetDeltaMove(&ptrobj->BoundAngle.Move);
ptb3d->Beta &= 4095;
_engine->_movements->initRealAngleConst(ptrobj);
}
_engine->_movements->_lastJoyFlag = true;
flagattack = true;
} else {
if (LastInput & I_THROW) {
// We finished shooting with the buggy,
// we close the hood
_engine->_actor->initBody(BodyType::btTunic, OWN_ACTOR_SCENE_INDEX);
_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
}
}
if (!flagattack && !ptrobj->_workFlags.bIsFalling && !ptrobj->_workFlags.bUnk1000) {
_engine->_movements->clearRealAngle(ptrobj);
if (_engine->_movements->_lastJoyFlag && (((Input & I_JOY) != LastMyJoy) || ((Input & I_FIRE) != LastMyFire))) {
_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
Pushing = false;
}
_engine->_movements->_lastJoyFlag = false;
// Pushing contains the number of the object being pushed
// So 1000 is an impossible value used as an initialization flag
// no animation
if (Pushing == 1000) {
_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
Pushing = false;
}
if (Input & I_UP) {
if (Pushing) {
_engine->_animations->initAnim(AnimationTypes::kPush, ANIM_TEMPO, OWN_ACTOR_SCENE_INDEX);
_engine->_movements->_lastJoyFlag = true;
} else {
_engine->_animations->initAnim(AnimationTypes::kForward, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
_engine->_movements->_lastJoyFlag = true;
}
} else if (Input & I_DOWN) {
_engine->_animations->initAnim(AnimationTypes::kBackward, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
_engine->_movements->_lastJoyFlag = true;
}
}
if (!ptrobj->_workFlags.bIsFalling && !ptrobj->_workFlags.bUnk1000) {
// check speed command
if ((Input & I_UP) // accelerating
&& !flagattack) {
ptb->Speed += deltatimer * 4;
if (!TimerGear)
TimerGear = TimerRefHR + TEMPO_GEAR;
else {
if (Gear < 0)
Gear = 0;
if (TimerRefHR > TimerGear && Gear < 2) {
Gear++;
TimerGear = TimerRefHR + TEMPO_GEAR;
}
}
} else if ((Input & I_DOWN) // brake / reverse
&& !flagattack) {
ptb->Speed -= deltatimer * 12;
Gear = -1;
TimerGear = 0;
} else // slow down
{
if (ptb->Speed > 0) {
ptb->Speed -= deltatimer * 7;
if (ptb->Speed < 0) {
ptb->Speed = 0;
}
}
if (ptb->Speed < 0) {
ptb->Speed += deltatimer * 7;
if (ptb->Speed > 0) {
ptb->Speed = 0;
}
}
Gear = 0;
TimerGear = 0;
}
if (ptb->Speed < -2000)
ptb->Speed = -2000;
if (ptb->Speed > MAX_SPEED)
ptb->Speed = MAX_SPEED;
speedinc = ptb->Speed * deltatimer / 1000;
} else {
speedinc = 0;
}
// check dir
if (!flagattack) {
if (Input & I_RIGHT) {
ptb->BetaWheel = -300;
if (ptb->Speed) {
rotlevel = -ptb->SpeedRot * speedinc / ptb->Speed;
} else {
rotlevel = 0;
}
} else if (Input & I_LEFT) {
ptb->BetaWheel = 300;
if (ptb->Speed) {
rotlevel = ptb->SpeedRot * speedinc / ptb->Speed;
} else {
rotlevel = 0;
}
} else {
ptb->BetaWheel = 0;
rotlevel = 0;
}
if (ptrobj->_staticFlags & SKATING) {
ptb->Speed = 3000;
speedinc = ptb->Speed * deltatimer / 1000;
} else {
if (ptb->Speed >= 0) {
ptb3d->Beta += rotlevel;
} else {
ptb3d->Beta -= rotlevel;
}
ptb3d->Beta = ClampAngle(ptb3d->Beta);
}
} else {
ptb->BetaWheel = 0;
}
LastMyJoy = Input & I_JOY;
LastMyFire = Input & I_FIRE;
LastInput = Input;
ptb->LastTimer = timerhr;
ptb->SpeedInc = speedinc;
if (ptrobj->SampleAlways && _engine->_sound->isSamplePlaying(ptrobj->SampleAlways)) {
int32 pitch;
switch (Gear) {
case -1:
pitch = _engine->_collision->boundRuleThree(3000, MAX_SAMPLE_PITCH2, MAX_SPEED, ABS(ptb->Speed));
break;
case 0:
pitch = _engine->_collision->boundRuleThree(3000, MAX_SAMPLE_PITCH, MAX_SPEED, ABS(ptb->Speed));
if (pitch >= MAX_SAMPLE_PITCH)
TimerGear = 1;
break;
case 1:
pitch = _engine->_collision->boundRuleThree(MAX_SAMPLE_PITCH2, MIN_SAMPLE_PITCH2, TEMPO_GEAR, TimerGear - TimerRefHR);
break;
default:
pitch = MAX_SAMPLE_PITCH2;
}
_engine->_sound->ChangePitchbendSample(ptrobj->SampleAlways, pitch);
}
#endif
}
} // namespace TwinE

View File

@ -26,18 +26,52 @@
#include "twine/input.h"
#include "twine/scene/actor.h"
#define BUGGY_PRESENT 0x80
#define NUM_BUGGY ((uint8)(NumBuggy & ~(BUGGY_PRESENT)))
#define IsBuggyPresent() (NumBuggy & BUGGY_PRESENT)
namespace TwinE {
class Buggy {
private:
TwinEEngine *_engine;
int32 Gear = 0;
int32 TimerGear;
public:
#define MAX_BUGGYS 2
struct S_ONE_WHEEL {
int32 Angle;
int32 X;
int32 Y;
int32 Z;
};
typedef struct {
int32 X;
int32 Y;
int32 Z;
int32 Cube;
int32 Beta;
int32 Alpha;
int32 Gamma;
S_ONE_WHEEL Wheel[4];
int32 BetaWheel;
int32 SpeedInc;
int32 SpeedRot;
int32 Speed;
int32 LastTimer;
} S_BUGGY;
// TODO: rename and hide
S_BUGGY ListBuggy[MAX_BUGGYS];
uint8 NumBuggy;
Buggy(TwinEEngine *engine) : _engine(engine) {}
void initBuggy(uint8 numobj, uint32 flaginit);
void resetBuggy();
void takeBuggy();
void leaveBuggy(uint8 newcomportement);
void leaveBuggy(HeroBehaviourType behaviour);
void doAnimBuggy(ActorStruct *ptrobj);
void moveBuggy(ActorStruct *ptrobj);
};

View File

@ -0,0 +1,150 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "twine/scene/dart.h"
#include "twine/audio/sound.h"
#include "twine/renderer/redraw.h"
#include "twine/scene/gamestate.h"
#include "twine/scene/scene.h"
namespace TwinE {
void Dart::InitDarts() {
#if 0
T_DART *ptrd;
uint8 *ptrbody;
uint32 t;
int32 x0, x1, y0, y1, z0, z1;
int32 size;
T_BODY_HEADER *ptr;
ptrbody = (uint8 *)GivePtrObjFix(BODY_3D_DART);
if (!ptrbody) {
char tmpFilePath[ADELINE_MAX_PATH];
GetResPath(tmpFilePath, ADELINE_MAX_PATH, OBJFIX_HQR_NAME);
TheEndCheckFile(tmpFilePath);
}
// Calcule ZV des flechettes
ptr = (T_BODY_HEADER *)ptrbody;
x0 = ptr->XMin;
x1 = ptr->XMax;
y0 = ptr->YMin;
y1 = ptr->YMax;
z0 = ptr->ZMin;
z1 = ptr->ZMax;
// Average
size = ((x1 - x0) + (z1 - z0)) / 4;
ptrd = ListDart;
for (t = 0; t < MAX_DARTS; t++, ptrd++) {
ptrd->Body = BODY_3D_DART;
ptrd->XMin = -size;
ptrd->XMax = size;
ptrd->YMin = y0;
ptrd->YMax = y1;
ptrd->ZMin = -size;
ptrd->ZMax = size;
ptrd->Flags = 0;
ptrd->NumCube = -1;
}
#endif
}
int32 Dart::GetDart() {
T_DART *ptrd;
int32 t;
ptrd = ListDart;
for (t = 0; t < MAX_DARTS; t++, ptrd++) {
if (ptrd->Flags & DART_TAKEN) {
return t;
}
}
return -1;
}
void Dart::TakeAllDarts() {
T_DART *ptrd;
int32 n;
ptrd = ListDart;
for (n = 0; n < MAX_DARTS; n++, ptrd++) {
ptrd->Flags |= DART_TAKEN;
}
_engine->_gameState->setDarts(MAX_DARTS);
}
void Dart::CheckDartCol(ActorStruct *ptrobj) {
int32 n;
T_DART *ptrd;
int32 x0, y0, z0, x1, y1, z1;
int32 xt0, yt0, zt0, xt1, yt1, zt1;
if (ptrobj->_staticFlags.bIsHidden)
return;
x0 = ptrobj->_pos.x + ptrobj->_boundingBox.mins.x;
x1 = ptrobj->_pos.x + ptrobj->_boundingBox.maxs.x;
y0 = ptrobj->_pos.y + ptrobj->_boundingBox.mins.y;
y1 = ptrobj->_pos.y + ptrobj->_boundingBox.maxs.y;
z0 = ptrobj->_pos.z + ptrobj->_boundingBox.mins.z;
z1 = ptrobj->_pos.z + ptrobj->_boundingBox.maxs.z;
ptrd = ListDart;
for (n = 0; n < MAX_DARTS; n++, ptrd++) {
if (ptrd->NumCube == _engine->_scene->_currentSceneIdx && !(ptrd->Flags & DART_TAKEN)) {
xt0 = ptrd->PosX + ptrd->XMin;
xt1 = ptrd->PosX + ptrd->XMax;
yt0 = ptrd->PosY + ptrd->YMin;
yt1 = ptrd->PosY + ptrd->YMax;
zt0 = ptrd->PosZ + ptrd->ZMin;
zt1 = ptrd->PosZ + ptrd->ZMax;
if (x0 < xt1 && x1 > xt0 && y0 < yt1 && y1 > yt0 && z0 < zt1 && z1 > zt0) {
ptrd->Flags |= DART_TAKEN;
_engine->_gameState->addDart();
#if 0
_engine->_sound->playSample(SAMPLE_BONUS_TROUVE, 0x1000, 0, 1,
ptrd->PosX, ptrd->PosY, ptrd->PosZ);
_engine->_redraw->addOverlay(OverlayType::koSprite | INCRUST_YCLIP,
SPRITE_DART,
15, 30,
0, 0, 2);
#endif
}
}
}
}
} // namespace TwinE

View File

@ -0,0 +1,69 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCENE_DART_H
#define TWINE_SCENE_DART_H
#include "twine/scene/actor.h"
#include "twine/twine.h"
#define MAX_DARTS 3
#define BODY_3D_DART 61
// dart flags
#define DART_TAKEN (1 << 0)
namespace TwinE {
class Dart {
private:
TwinEEngine *_engine;
public:
struct T_DART {
int32 PosX;
int32 PosY;
int32 PosZ;
int32 Alpha;
int32 Beta;
int32 Body;
int32 NumCube; // Number of the cube in which the dart is located
uint32 Flags;
int32 XMin; // ZV of the darts
int32 YMin;
int32 ZMin;
int32 XMax;
int32 YMax;
int32 ZMax;
};
T_DART ListDart[MAX_DARTS];
Dart(TwinEEngine *engine) : _engine(engine) {}
void InitDarts();
int32 GetDart();
void TakeAllDarts();
void CheckDartCol(ActorStruct *ptrobj);
};
} // namespace TwinE
#endif

View File

@ -229,6 +229,10 @@ bool GameState::loadGame(Common::SeekableReadStream *file) {
bool GameState::saveGame(Common::WriteStream *file) {
debug(2, "Save game");
if (!_engine->isLBA1()) {
warning("Saving not implemented for lba2");
return false;
}
if (_engine->_menuOptions->_saveGameName[0] == '\0') {
Common::strlcpy(_engine->_menuOptions->_saveGameName, "TwinEngineSave", sizeof(_engine->_menuOptions->_saveGameName));
}
@ -296,7 +300,7 @@ int16 GameState::getChapter() const {
return _listFlagGame[253];
}
void GameState::setGameFlag(uint8 index, uint8 value) {
void GameState::setGameFlag(uint8 index, int16 value) {
if (_listFlagGame[index] == value) {
return;
}

View File

@ -25,6 +25,7 @@
#include "common/savefile.h"
#include "common/scummsys.h"
#include "twine/menu/menu.h"
#include "twine/shared.h"
namespace TwinE {
@ -68,7 +69,7 @@ private:
* 107: Set to 1 after Twinsen kills yellow groboclone in the Citadel Island Tavern (after the Tavern has
* been closed down). Makes the Tavern open again and groboclone not appear any more.
*/
uint8 _listFlagGame[NUM_GAME_FLAGS];
int16 _listFlagGame[NUM_GAME_FLAGS];
// only lba1 - lba2 uses 253 gameflag
int16 _gameChapter = 0;
@ -138,6 +139,16 @@ public:
int32 _numChoices = 0; // numOfOptionsInChoice
TextId _choiceAnswer = TextId::kNone; // inGameMenuAnswer
void setDarts(int16 value) {
setGameFlag(InventoryItems::kiDart, value);
}
void addDart() {
int16 old = _listFlagGame[InventoryItems::kiDart];
++old;
setGameFlag(InventoryItems::kiDart, old);
}
inline bool inventoryDisabled() const {
return hasGameFlag(GAMEFLAG_INVENTORY_DISABLED) != 0;
}
@ -167,7 +178,7 @@ public:
uint8 hasGameFlag(uint8 index) const;
void setGameFlag(uint8 index, uint8 value);
void setGameFlag(uint8 index, int16 value);
int16 setKeys(int16 value);
int16 setGas(int16 value);

View File

@ -292,6 +292,7 @@ bool Movements::processBehaviourExecution(int actorIdx) {
_engine->_animations->initAnim(AnimationTypes::kHide, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
break;
case HeroBehaviourType::kProtoPack:
case HeroBehaviourType::kMax:
break;
}
return executeAction;

View File

@ -0,0 +1,41 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "twine/scene/rain.h"
namespace TwinE {
void Rain::InitOneRain(T_RAIN *pt) {
}
void Rain::InitRain() {
}
void Rain::GereRain() {
}
void Rain::ClearImpactRain() {
}
void Rain::AffRain() {
}
} // namespace TwinE

View File

@ -0,0 +1,53 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCENE_RAIN_H
#define TWINE_SCENE_RAIN_H
#include "twine/scene/actor.h"
#include "twine/twine.h"
namespace TwinE {
class Rain {
private:
TwinEEngine *_engine;
public:
struct T_RAIN {
int32 XRain;
int32 YRain;
int32 ZRain;
int32 Timer;
};
Rain(TwinEEngine *engine) : _engine(engine) {}
void InitOneRain(T_RAIN *pt);
void InitRain();
void GereRain();
void ClearImpactRain();
void AffRain();
};
} // namespace TwinE
#endif

View File

@ -148,13 +148,45 @@ void Scene::setBonusParameterFlags(ActorStruct *act, uint16 bonusFlags) {
}
}
bool Scene::loadSceneCubeXY(int numcube, int *cubex, int *cubey) {
uint8 *scene = nullptr;
// numcube+1 because at 0 is SizeCube.MAX (size of the largest .SCC)
const int32 sceneSize = HQR::getAllocEntry(&scene, Resources::HQR_SCENE_FILE, numcube + 1);
if (sceneSize <= 0) {
return false;
}
Common::MemoryReadStream stream(scene, sceneSize, DisposeAfterUse::YES);
*cubex = *cubey = 0;
// World info: INFO_WORLD
const uint8 island = stream.readByte();
// Used only for 3DExt
const int32 x = stream.readByte();
const int32 y = stream.readByte();
/*uint8 shadowlvl =*/stream.readByte();
/*uint8 modelaby =*/stream.readByte();
const uint8 cubemode = stream.readByte();
if (cubemode == CUBE_EXTERIEUR && island == _island && ABS(x - _currentCubeX) <= 1 && ABS(y - _currentCubeY) <= 1) {
*cubex = x;
*cubey = y;
return true;
}
return false;
}
bool Scene::loadSceneLBA2() {
Common::MemoryReadStream stream(_currentScene, _currentSceneSize);
_sceneTextBank = (TextBankId)stream.readByte();
/*int8 currentCubeX =*/ stream.readSByte();
/*int8 currentCubeY =*/ stream.readSByte();
/*int8 shadowLevel =*/ stream.readSByte();
/*int8 modeLabyrinthe =*/ stream.readSByte();
_island = stream.readByte();
_sceneTextBank = (TextBankId)_island;
_currentCubeX = stream.readByte();
_currentCubeY = stream.readByte();
_shadowLevel = stream.readByte();
_modeLabyrinthe = stream.readByte();
_isOutsideScene = stream.readByte();
/*uint8 n =*/ stream.readByte();

View File

@ -172,6 +172,12 @@ public:
int32 _alphaLight = 0;
int32 _betaLight = 0;
uint8 _island = 0;
uint8 _shadowLevel = 0; // lba2
uint8 _modeLabyrinthe = 0; // lba2
uint8 _currentCubeX = 0; // lba2
uint8 _currentCubeY = 0; // lba2
IVec3 _newHeroPos;
/** Hero Y coordinate before fall */
@ -208,7 +214,7 @@ public:
int32 _sceneNumZones = 0;
ZoneStruct _sceneZones[NUM_MAX_ZONES];
ActorStruct *getActor(int32 actorIdx);
ActorStruct *getActor(int32 actorIdx); // ListObjet
void playSceneMusic();
@ -217,6 +223,9 @@ public:
/** Change to another scene */
void changeScene();
/** For the buggy to get the 2D coordinates of an exterior cube in the map */
bool loadSceneCubeXY(int sceneNum, int *cubeX, int *cubeY);
/** Process scene environment sound */
void processEnvironmentSound();
void initSceneVars();

View File

@ -0,0 +1,42 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "twine/scene/wagon.h"
namespace TwinE {
void Wagon::DoAnimWagon() {
}
void Wagon::DoDirWagon(ActorStruct *ptrobj) {
}
int32 Wagon::GetNumBrickWagon(int32 brick) {
return -1;
}
void Wagon::AdjustEssieuWagonAvant(int32 brickw) {
}
void Wagon::AdjustEssieuWagonArriere(int32 brickw) {
}
} // namespace TwinE

View File

@ -0,0 +1,46 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCENE_WAGON_H
#define TWINE_SCENE_WAGON_H
#include "twine/scene/actor.h"
#include "twine/twine.h"
namespace TwinE {
class Wagon {
private:
TwinEEngine *_engine;
public:
Wagon(TwinEEngine *engine) : _engine(engine) {}
void DoAnimWagon();
void DoDirWagon(ActorStruct *ptrobj);
int32 GetNumBrickWagon(int32 brick);
void AdjustEssieuWagonAvant(int32 brickw);
void AdjustEssieuWagonArriere(int32 brickw);
};
} // namespace TwinE
#endif

View File

@ -20,14 +20,16 @@
*/
#include "twine/script/script_life_v2.h"
#include "twine/renderer/redraw.h"
#include "twine/renderer/screens.h"
#include "twine/audio/sound.h"
#include "twine/movies.h"
#include "twine/renderer/redraw.h"
#include "twine/renderer/renderer.h"
#include "twine/renderer/screens.h"
#include "twine/resources/resources.h"
#include "twine/scene/actor.h"
#include "twine/movies.h"
#include "twine/scene/buggy.h"
#include "twine/scene/movements.h"
#include "twine/scene/wagon.h"
#include "twine/script/script_move_v2.h"
#include "twine/shared.h"
#include "twine/twine.h"
@ -784,6 +786,25 @@ int32 ScriptLifeV2::lSET_RAIL(TwinEEngine *engine, LifeScriptContext &ctx) {
}
int32 ScriptLifeV2::lINVERSE_BETA(TwinEEngine *engine, LifeScriptContext &ctx) {
ctx.actor->_beta = ClampAngle(ctx.actor->_beta + LBAAngles::ANGLE_180);
if (ctx.actor->_controlMode == ControlMode::kWagon) {
#if 0
ctx.actor->Info1 = 1; // reinit speed wagon
// to be clean
APtObj = ctx.actor;
// SizeSHit contains the number of the brick under the wagon
// test front axle position
engine->_wagon->AdjustEssieuWagonAvant(ctx.actor->SizeSHit);
// test rear axle position
engine->_wagon->AdjustEssieuWagonArriere(ctx.actor->SizeSHit);
#endif
}
// To tell an object that it is no longer being carried by me
engine->_actor->processActorCarrier(ctx.actorIdx);
return -1;
}

View File

@ -254,30 +254,31 @@ enum class ShapeType {
/** Control mode types */
enum class ControlMode {
kNoMove = 0,
kManual = 1,
kFollow = 2,
kTrack = 3,
kFollow2 = 4,
kTrackAttack = 5,
kSameXZ = 6,
kRandom = 7, // kPinguin in lba2
kNoMove = 0, // NO_MOVE
kManual = 1, // MOVE_MANUAL
kFollow = 2, // MOVE_FOLLOW
kTrack = 3, // MOVE_TRACK
kFollow2 = 4, // MOVE_FOLLOW_2
kTrackAttack = 5, // MOVE_TRACK_ATTACK
kSameXZ = 6, // MOVE_SAME_XZ
kRandom = 7, //
kPinguin = 7, // MOVE_PINGOUIN kRandom doesn't exist in lba2 ()
// lba2
kWagon = 8,
kCircle = 9, // Beta = Tangent lines to circles
kCircle2 = 10,
kSameXYBeta = 11,
kBuggy = 12,
kBuggyManual = 13
kWagon = 8, // MOVE_WAGON
kCircle = 9, // MOVE_CIRCLE Beta = Tangent lines to circles
kCircle2 = 10, // MOVE_CIRCLE2 Beta = Facing the flag
kSameXYBeta = 11, // MOVE_SAME_XZ_BETA
kBuggy = 12, // MOVE_BUGGY
kBuggyManual = 13 // MOVE_BUGGY_MANUAL
};
enum class AnimationTypes {
kAnimNone = -1,
kStanding = 0,
kForward = 1,
kBackward = 2,
kTurnLeft = 3,
kTurnRight = 4,
kStanding = 0, // GEN_ANIM_RIEN
kForward = 1, // GEN_ANIM_MARCHE
kBackward = 2, // GEN_ANIM_RECULE
kTurnLeft = 3, // GEN_ANIM_GAUCHE
kTurnRight = 4, // GEN_ANIM_DROITE
kHit = 5,
kBigHit = 6,
kFall = 7,
@ -297,6 +298,7 @@ enum class AnimationTypes {
kDrawn = 21,
kHit2 = 22,
kSabreAttack = 23,
kPush = 27, // GEN_ANIM_POUSSE
kSabreUnknown = 24,
kCarStarting = 303,
kCarDriving = 304,
@ -307,7 +309,7 @@ enum class AnimationTypes {
};
enum class AnimType {
kAnimationTypeRepeat = 0,
kAnimationTypeRepeat = 0, // ANIM_REPEAT
kAnimationThen = 1,
// play animation and let animExtra follow as next animation
// if there is already a next animation set - replace the value
@ -332,13 +334,29 @@ enum class AnimType {
* @note The values must match the @c TextId indices
*/
enum class HeroBehaviourType {
kNormal = 0,
kAthletic = 1,
kAggressive = 2,
kDiscrete = 3,
kProtoPack = 4
kNormal = 0, // C_NORMAL
kAthletic = 1, // C_SPORTIF
kAggressive = 2, // C_AGRESSIF
kDiscrete = 3, // C_DISCRET
kProtoPack = 4, // C_PROTOPACK
#if 0
kDOUBLE = 5, // C_DOUBLE Twinsen + Zoé
kCONQUE = 6, // C_CONQUE Conque
kSCAPH_INT_NORM = 7, // C_SCAPH_INT_NORM Scaphandre Interieur Normal
kJETPACK = 8, // C_JETPACK SuperJetPack
kSCAPH_INT_SPOR = 9, // C_SCAPH_INT_SPOR Scaphandre Interieur Sportif
kSCAPH_EXT_NORM = 10, // C_SCAPH_EXT_NORM Scaphandre Exterieur Normal
kSCAPH_EXT_SPOR = 11, // C_SCAPH_EXT_SPOR Scaphandre Exterieur Sportif
kBUGGY = 12, // C_BUGGY Conduite du buggy
kSKELETON = 13, // C_SKELETON Squelette Electrique
#endif
kMax
};
// lba2
#define CUBE_INTERIEUR 0
#define CUBE_EXTERIEUR 1
/**
* 0: tunic + medallion
* 1: tunic
@ -349,14 +367,27 @@ enum class HeroBehaviourType {
* 6: snowboard (WARNING, this can crash the game when you change behavior)
*/
enum class BodyType {
btNone = -1,
btNormal = 0,
btTunic = 1,
btSabre = 2,
btPrisonSuit = 3,
btNurseSuit = 4,
btHorn = 5,
btSnowboard = 6
btNone = -1, // Lba1/Lba2 NO_BODY (255)
btNormal = 0, // Lba1/Lba2 GEN_BODY_NORMAL
btTunic = 1, // Lba1/Lba2 GEN_BODY_TUNIQUE
btSabre = 2, // Lba1/Lba2 GEN_BODY_SABRE
btPrisonSuit = 3, // Lba1
btNurseSuit = 4, // Lba1
btHorn = 5, // Lba1
btSnowboard = 6, // Lba1
btBlowTube = 3, // Lba2 GEN_BODY_SARBACANE
btSarbatron = 4, // Lba2 GEN_BODY_SARBATRON
btGlove = 5, // Lba2 GEN_BODY_GANT
btLaserPistole = 6, // Lba2 GEN_BODY_PISTOLASER
btMage = 7, // Lba2 GEN_BODY_MAGE
btMageBlowtube = 8, // Lba2 GEN_BODY_MAGE_SARBACANE
btBodyFire = 9, // Lba2 GEN_BODY_FEU
btTunicTir = 10, // Lba2 GEN_BODY_TUNIQUE_TIR
btMageTir = 11, // Lba2 GEN_BODY_MAGE_TIR
btLabyrinth = 12 // Lba2 GEN_BODY_LABYRINTHE
};
enum class ExtraSpecialType {
@ -603,35 +634,37 @@ enum class TextId : int16 {
};
enum InventoryItems {
kiHolomap = 0,
kiMagicBall = 1,
kiUseSabre = 2,
kiGawleysHorn = 3,
kiTunic = 4,
kiBookOfBu = 5,
kSendellsMedallion = 6,
kFlaskOfClearWater = 7,
kRedCard = 8,
kBlueCard = 9,
kIDCard = 10,
kMrMiesPass = 11,
kiProtoPack = 12,
kSnowboard = 13,
kiPenguin = 14,
kGasItem = 15,
kPirateFlag = 16,
kMagicFlute = 17,
kSpaceGuitar = 18,
kHairDryer = 19,
kAncesteralKey = 20,
kBottleOfSyrup = 21,
kEmptyBottle = 22,
kFerryTicket = 23,
kKeypad = 24,
kCoffeeCan = 25,
kiBonusList = 26,
kiCloverLeaf = 27,
MaxInventoryItems = 28
kiHolomap = 0, // lba1/lba2
kiMagicBall = 1, // lba1/lba2
kiUseSabre = 2, // lba1
kiDart = 2, // lba2
kiGawleysHorn = 3, // lba1
kiTunic = 4, // lba1/lba2
kiBookOfBu = 5, // lba1
kSendellsMedallion = 6, // lba1
kFlaskOfClearWater = 7, // lba1
kRedCard = 8, // lba1
kBlueCard = 9, // lba1
kIDCard = 10, // lba1
kMrMiesPass = 11, // lba1
kiProtoPack = 12, // lba1/lba2
kSnowboard = 13, // lba1
kiPenguin = 14, // lba1/lba2
kGasItem = 15, // lba1/lba2 (GazoGem)
kPirateFlag = 16, // lba1
kMagicFlute = 17, // lba1
kSpaceGuitar = 18, // lba1
kHairDryer = 19, // lba1
kAncesteralKey = 20, // lba1
kBottleOfSyrup = 21, // lba1
kEmptyBottle = 22, // lba1
kFerryTicket = 23, // lba1
kKeypad = 24, // lba1
kCoffeeCan = 25, // lba1
kiBonusList = 26, // lba1
kiCloverLeaf = 27, // lba1
MaxInventoryItems = 28, // lba1
MaxInventoryItemsLba2 = 40 // lba2
};
struct TwineResource {

View File

@ -28,8 +28,8 @@
#include "common/str.h"
#include "common/stream.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "common/text-to-speech.h"
#include "common/textconsole.h"
#include "engines/metaengine.h"
#include "engines/util.h"
#include "graphics/cursorman.h"
@ -45,12 +45,12 @@
#include "twine/debugger/debug_grid.h"
#include "twine/debugger/debug_scene.h"
#include "twine/detection.h"
#include "twine/movies.h"
#include "twine/holomap.h"
#include "twine/input.h"
#include "twine/menu/interface.h"
#include "twine/menu/menu.h"
#include "twine/menu/menuoptions.h"
#include "twine/movies.h"
#include "twine/renderer/redraw.h"
#include "twine/renderer/renderer.h"
#include "twine/renderer/screens.h"
@ -60,11 +60,14 @@
#include "twine/scene/animations.h"
#include "twine/scene/buggy.h"
#include "twine/scene/collision.h"
#include "twine/scene/dart.h"
#include "twine/scene/extra.h"
#include "twine/scene/gamestate.h"
#include "twine/scene/grid.h"
#include "twine/scene/movements.h"
#include "twine/scene/rain.h"
#include "twine/scene/scene.h"
#include "twine/scene/wagon.h"
#include "twine/script/script_life_v1.h"
#include "twine/script/script_life_v2.h"
#include "twine/script/script_move_v1.h"
@ -129,7 +132,7 @@ void TwineScreen::update() {
const int left = CLIP<int>(_engine->_redraw->_sceneryViewX - maxW / 4, 0, maxW / 2);
const int top = CLIP<int>(_engine->_redraw->_sceneryViewY - maxH / 4, 0, maxH / 2);
const Common::Rect srcRect(left, top, left + maxW / 2, top + maxH / 2);
const Common::Rect& destRect = zoomWorkVideoBuffer.getBounds();
const Common::Rect &destRect = zoomWorkVideoBuffer.getBounds();
zoomWorkVideoBuffer.blitFrom(*this, srcRect, destRect);
blitFrom(zoomWorkVideoBuffer);
// TODO: we need to redraw everything because we just modified the screen buffer itself
@ -209,6 +212,9 @@ TwinEEngine::TwinEEngine(OSystem *system, Common::Language language, uint32 flag
_scriptLife = new ScriptLifeV2(this);
_scriptMove = new ScriptMoveV2(this);
_buggy = new Buggy(this);
_dart = new Dart(this);
_rain = new Rain(this);
_wagon = new Wagon(this);
}
_holomap = new Holomap(this);
_sound = new Sound(this);
@ -356,7 +362,7 @@ Common::Error TwinEEngine::run() {
_state = EngineState::Menu;
break;
case EngineState::Menu:
#if 0
#if 0
// this will enter the game and execute the commands in the file "debug"
_gameState->initEngineVars();
_text->textClipSmall();
@ -366,9 +372,9 @@ Common::Error TwinEEngine::run() {
debug("Failed to execute debug file before entering the scene");
}
gameEngineLoop();
#else
#else
_state = _menu->run();
#endif
#endif
break;
}
}
@ -569,7 +575,7 @@ void TwinEEngine::playIntro() {
bool abort = false;
if (isLBA2()) {
//abort |= _screens->loadImageDelay(_resources->activisionLogo(), 7);
// abort |= _screens->loadImageDelay(_resources->activisionLogo(), 7);
abort |= _screens->loadImageDelay(_resources->eaLogo(), 7);
}
@ -851,9 +857,7 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
if (_scene->_needChangeScene > -1) {
if (!isMod() && isDemo() && isLBA1()) {
// the demo only has these scenes
if (_scene->_needChangeScene != LBA1SceneId::Citadel_Island_Prison
&& _scene->_needChangeScene != LBA1SceneId::Citadel_Island_outside_the_citadel
&& _scene->_needChangeScene != LBA1SceneId::Citadel_Island_near_the_tavern) {
if (_scene->_needChangeScene != LBA1SceneId::Citadel_Island_Prison && _scene->_needChangeScene != LBA1SceneId::Citadel_Island_outside_the_citadel && _scene->_needChangeScene != LBA1SceneId::Citadel_Island_near_the_tavern) {
// TODO: PlayMidiFile(6);
return true;
}
@ -910,11 +914,11 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
// Process behaviour menu
const bool behaviourMenu = _input->isActionActive(TwinEActionType::BehaviourMenu, false);
if ((behaviourMenu ||
_input->isActionActive(TwinEActionType::QuickBehaviourNormal, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourAggressive, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourDiscreet, false)) &&
_scene->_sceneHero->_body != -1 && _scene->_sceneHero->_controlMode == ControlMode::kManual) {
_input->isActionActive(TwinEActionType::QuickBehaviourNormal, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourAggressive, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourDiscreet, false)) &&
_scene->_sceneHero->_body != -1 && _scene->_sceneHero->_controlMode == ControlMode::kManual) {
if (_input->isActionActive(TwinEActionType::QuickBehaviourNormal, false)) {
_actor->_heroBehaviour = HeroBehaviourType::kNormal;
} else if (_input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false)) {
@ -1266,9 +1270,9 @@ void TwinEEngine::drawText(int32 x, int32 y, const Common::String &text, bool ce
return;
}
font->drawString(&_frontVideoBuffer, text,
x, y, width,
_frontVideoBuffer.format.RGBToColor(255, 255, 255),
center ? Graphics::kTextAlignCenter : Graphics::kTextAlignLeft, 0, true);
x, y, width,
_frontVideoBuffer.format.RGBToColor(255, 255, 255),
center ? Graphics::kTextAlignCenter : Graphics::kTextAlignLeft, 0, true);
}
Common::Language TwinEEngine::getGameLang() const {

View File

@ -37,7 +37,6 @@
#include "twine/detection.h"
#include "twine/input.h"
#include "twine/scene/actor.h"
#include "twine/scene/buggy.h"
#include "twine/script/script_life.h"
#include "twine/script/script_move.h"
#include "twine/shared.h"
@ -150,6 +149,12 @@ struct Keyboard;
class Debug;
class DebugScene;
// lba2
class Buggy;
class Dart;
class Rain;
class Wagon;
enum class EngineState {
Menu,
GameLoop,
@ -296,6 +301,9 @@ public:
Input *_input;
Debug *_debug;
Buggy *_buggy; // lba2
Dart *_dart; // lba2
Rain *_rain; // lba2
Wagon *_wagon; // lba2
DebugScene *_debugScene;
/** Configuration file structure