Merged the tinsel 2 engine with tinsel 1. Both Discworld 1 and Discworld 2 should be completable
svn-id: r35196
This commit is contained in:
parent
f10f151ff7
commit
af945ac788
81 changed files with 17331 additions and 4740 deletions
File diff suppressed because it is too large
Load diff
|
@ -29,24 +29,30 @@
|
||||||
|
|
||||||
|
|
||||||
#include "tinsel/dw.h" // for SCNHANDLE
|
#include "tinsel/dw.h" // for SCNHANDLE
|
||||||
#include "tinsel/events.h" // for USER_EVENT
|
#include "tinsel/events.h" // for TINSEL_EVENT
|
||||||
#include "tinsel/palette.h" // for COLORREF
|
#include "tinsel/palette.h" // for COLORREF
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
struct FREEL;
|
struct FREEL;
|
||||||
struct INT_CONTEXT;
|
struct INT_CONTEXT;
|
||||||
struct MACTOR;
|
struct MOVER;
|
||||||
struct OBJECT;
|
struct OBJECT;
|
||||||
|
|
||||||
|
#define ACTORTAG_KEY 0x1000000
|
||||||
|
|
||||||
|
#define OTH_RELATEDACTOR 0x00000fff
|
||||||
|
#define OTH_RELATIVE 0x00001000
|
||||||
|
#define OTH_ABSOLUTE 0x00002000
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
void RegisterActors(int num);
|
void RegisterActors(int num);
|
||||||
void FreeActors(void);
|
void FreeActors(void);
|
||||||
void setleadid(int rid);
|
void SetLeadId(int rid);
|
||||||
int LeadId(void);
|
int GetLeadId(void);
|
||||||
void StartActors(SCNHANDLE ah, int numActors, bool bRunScript);
|
bool ActorIsGhost(int actor);
|
||||||
|
void StartTaggedActors(SCNHANDLE ah, int numActors, bool bRunScript);
|
||||||
void DropActors(void); // No actor reels running
|
void DropActors(void); // No actor reels running
|
||||||
void DisableActor(int actor);
|
void DisableActor(int actor);
|
||||||
void EnableActor(int actor);
|
void EnableActor(int actor);
|
||||||
|
@ -63,60 +69,110 @@ int GetActorLeft(int ano);
|
||||||
int GetActorRight(int ano);
|
int GetActorRight(int ano);
|
||||||
int GetActorTop(int ano);
|
int GetActorTop(int ano);
|
||||||
int GetActorBottom(int ano);
|
int GetActorBottom(int ano);
|
||||||
void HideActor(int ano);
|
void ShowActor(CORO_PARAM, int ano);
|
||||||
|
void HideActor(CORO_PARAM, int ano);
|
||||||
|
bool ActorHidden(int ano);
|
||||||
bool HideMovingActor(int id, int sf);
|
bool HideMovingActor(int id, int sf);
|
||||||
void unHideMovingActor(int id);
|
void unHideMovingActor(int id);
|
||||||
void restoreMovement(int id);
|
void restoreMovement(int id);
|
||||||
void storeActorReel(int ano, const FREEL *reel, SCNHANDLE film, OBJECT *pobj, int reelnum, int x, int y);
|
void storeActorReel(int ano, const FREEL *reel, SCNHANDLE hFilm, OBJECT *pobj, int reelnum, int x, int y);
|
||||||
const FREEL *actorReel(int ano);
|
const FREEL *actorReel(int ano);
|
||||||
SCNHANDLE actorFilm(int ano);
|
SCNHANDLE actorFilm(int ano);
|
||||||
|
|
||||||
void setActorPlayFilm(int ano, SCNHANDLE film);
|
void SetActorPlayFilm(int ano, SCNHANDLE hFilm);
|
||||||
SCNHANDLE getActorPlayFilm(int ano);
|
SCNHANDLE GetActorPlayFilm(int ano);
|
||||||
void setActorTalkFilm(int ano, SCNHANDLE film);
|
void SetActorTalkFilm(int ano, SCNHANDLE hFilm);
|
||||||
SCNHANDLE getActorTalkFilm(int ano);
|
SCNHANDLE GetActorTalkFilm(int ano);
|
||||||
void setActorTalking(int ano, bool tf);
|
void SetActorTalking(int ano, bool tf);
|
||||||
bool isActorTalking(int ano);
|
bool ActorIsTalking(int ano);
|
||||||
void setActorLatestFilm(int ano, SCNHANDLE film);
|
void SetActorLatestFilm(int ano, SCNHANDLE hFilm);
|
||||||
SCNHANDLE getActorLatestFilm(int ano);
|
SCNHANDLE GetActorLatestFilm(int ano);
|
||||||
|
|
||||||
void updateActorEsc(int ano, bool escOn, int escEv);
|
void UpdateActorEsc(int ano, bool escOn, int escEvent);
|
||||||
bool actorEsc(int ano);
|
void UpdateActorEsc(int ano, int escEvent);
|
||||||
int actorEev(int ano);
|
bool ActorEsc(int ano);
|
||||||
void storeActorPos(int ano, int x, int y);
|
int ActorEev(int ano);
|
||||||
void storeActorSteps(int ano, int steps);
|
void StoreActorPos(int ano, int x, int y);
|
||||||
int getActorSteps(int ano);
|
void StoreActorSteps(int ano, int steps);
|
||||||
void storeActorZpos(int ano, int z);
|
int GetActorSteps(int ano);
|
||||||
|
void StoreActorZpos(int ano, int z, int column = -1);
|
||||||
|
int GetActorZpos(int ano, int column);
|
||||||
|
void IncLoopCount(int ano);
|
||||||
|
int GetLoopCount(int ano);
|
||||||
SCNHANDLE GetActorTag(int ano);
|
SCNHANDLE GetActorTag(int ano);
|
||||||
void FirstTaggedActor(void);
|
void FirstTaggedActor(void);
|
||||||
int NextTaggedActor(void);
|
int NextTaggedActor(void);
|
||||||
|
int NextTaggedActor(int previous);
|
||||||
int AsetZPos(OBJECT *pObj, int y, int32 zFactor);
|
int AsetZPos(OBJECT *pObj, int y, int32 zFactor);
|
||||||
void MAsetZPos(MACTOR *pActor, int y, int32 zFactor);
|
void SetMoverZ(MOVER *pMover, int y, int32 zFactor);
|
||||||
void actorEvent(int ano, USER_EVENT event, BUTEVENT be);
|
void ActorEvent(int ano, TINSEL_EVENT event, PLR_EVENT be);
|
||||||
|
|
||||||
void storeActorAttr(int ano, int r1, int g1, int b1);
|
void storeActorAttr(int ano, int r1, int g1, int b1);
|
||||||
COLORREF getActorTcol(int ano);
|
COLORREF GetActorRGB(int ano);
|
||||||
|
void SetActorRGB(int ano, COLORREF colour);
|
||||||
|
void SetActorZfactor(int ano, uint32 zFactor);
|
||||||
|
uint32 GetActorZfactor(int ano);
|
||||||
|
|
||||||
void setactorson(void);
|
void setactorson(void);
|
||||||
|
|
||||||
void ActorsLife(int id, bool bAlive);
|
void ActorsLife(int id, bool bAlive);
|
||||||
|
|
||||||
|
void dwEndActor(int ano);
|
||||||
|
|
||||||
|
void ActorEvent(CORO_PARAM, int ano, TINSEL_EVENT tEvent, bool bWait, int myEscape, bool *result = NULL);
|
||||||
|
|
||||||
|
void GetActorTagPortion(int ano, unsigned *top, unsigned *bottom, unsigned *left, unsigned *right);
|
||||||
|
SCNHANDLE GetActorTagHandle(int ano);
|
||||||
|
void SetActorPointedTo(int actor, bool bPointedTo);
|
||||||
|
bool ActorIsPointedTo(int actor);
|
||||||
|
void SetActorTagWanted(int actor, bool bTagWanted, bool bCursor, SCNHANDLE hOverrideTag);
|
||||||
|
bool ActorTagIsWanted(int actor);
|
||||||
|
bool InHotSpot(int ano, int curX, int curY);
|
||||||
|
int FrontTaggedActor(void);
|
||||||
|
void GetActorTagPos(int actor, int *pTagX, int *pTagY, bool bAbsolute);
|
||||||
|
bool IsTaggedActor(int actor);
|
||||||
|
void StoreActorPresFilm(int ano, SCNHANDLE hFilm, int x, int y);
|
||||||
|
SCNHANDLE GetActorPresFilm(int ano);
|
||||||
|
int GetActorFilmNumber(int ano);
|
||||||
|
void StoreActorReel(int actor, int column, OBJECT *pObj);
|
||||||
|
void NotPlayingReel(int actor, int filmNumber, int column);
|
||||||
|
bool ActorReelPlaying(int actor, int column);
|
||||||
|
void SetActorPlayFilm(int ano, SCNHANDLE hFilm);
|
||||||
|
SCNHANDLE GetActorPlayFilm(int ano);
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
struct SAVED_ACTOR {
|
struct SAVED_ACTOR {
|
||||||
short actorID;
|
short actorID;
|
||||||
short z;
|
short zFactor;
|
||||||
bool bAlive;
|
bool bAlive;
|
||||||
|
bool bHidden;
|
||||||
SCNHANDLE presFilm; //!< the film that reel belongs to
|
SCNHANDLE presFilm; //!< the film that reel belongs to
|
||||||
short presRnum; //!< the present reel number
|
short presRnum; //!< the present reel number
|
||||||
short presX, presY;
|
short presPlayX, presPlayY;
|
||||||
|
};
|
||||||
|
typedef SAVED_ACTOR *PSAVED_ACTOR;
|
||||||
|
|
||||||
|
#define NUM_ZPOSITIONS 200 // Reasonable-sounding number
|
||||||
|
|
||||||
|
struct Z_POSITIONS {
|
||||||
|
short actor;
|
||||||
|
short column;
|
||||||
|
int z;
|
||||||
};
|
};
|
||||||
|
|
||||||
int SaveActors(SAVED_ACTOR *sActorInfo);
|
int SaveActors(SAVED_ACTOR *sActorInfo);
|
||||||
|
|
||||||
|
|
||||||
void RestoreActorProcess(int id, INT_CONTEXT *pic);
|
void RestoreActorProcess(int id, INT_CONTEXT *pic);
|
||||||
|
|
||||||
|
int SaveActors(PSAVED_ACTOR sActorInfo);
|
||||||
|
void RestoreActors(int numActors, PSAVED_ACTOR sActorInfo);
|
||||||
|
|
||||||
|
void SaveZpositions(void *zpp);
|
||||||
|
void RestoreZpositions(void *zpp);
|
||||||
|
|
||||||
|
void SaveActorZ(byte *saveActorZ);
|
||||||
|
void RestoreActorZ(byte *saveActorZ);
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
|
@ -29,32 +29,12 @@
|
||||||
#include "tinsel/multiobj.h" // multi-part object defintions etc.
|
#include "tinsel/multiobj.h" // multi-part object defintions etc.
|
||||||
#include "tinsel/object.h"
|
#include "tinsel/object.h"
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
/** Animation script commands */
|
|
||||||
enum {
|
|
||||||
ANI_END = 0, //!< end of animation script
|
|
||||||
ANI_JUMP = 1, //!< animation script jump
|
|
||||||
ANI_HFLIP = 2, //!< flip animated object horizontally
|
|
||||||
ANI_VFLIP = 3, //!< flip animated object vertically
|
|
||||||
ANI_HVFLIP = 4, //!< flip animated object in both directions
|
|
||||||
ANI_ADJUSTX = 5, //!< adjust animated object x animation point
|
|
||||||
ANI_ADJUSTY = 6, //!< adjust animated object y animation point
|
|
||||||
ANI_ADJUSTXY = 7, //!< adjust animated object x & y animation points
|
|
||||||
ANI_NOSLEEP = 8, //!< do not sleep for this frame
|
|
||||||
ANI_CALL = 9, //!< call routine
|
|
||||||
ANI_HIDE = 10 //!< hide animated object
|
|
||||||
};
|
|
||||||
|
|
||||||
/** animation script command possibilities */
|
|
||||||
union ANI_SCRIPT {
|
|
||||||
int32 op; //!< treat as an opcode or operand
|
|
||||||
uint32 hFrame; //!< treat as a animation frame handle
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Advance to next frame routine.
|
* Advance to next frame routine.
|
||||||
* @param pAnim Animation data structure
|
* @param pAnim Animation data structure
|
||||||
|
@ -64,6 +44,9 @@ SCRIPTSTATE DoNextFrame(ANIM *pAnim) {
|
||||||
const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);
|
const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);
|
||||||
|
|
||||||
while (1) { // repeat until a real image
|
while (1) { // repeat until a real image
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugAnimations,
|
||||||
|
"DoNextFrame %ph index=%d, op=%xh", (byte *)pAnim, pAnim->scriptIndex,
|
||||||
|
FROM_LE_32(pAni[pAnim->scriptIndex].op));
|
||||||
|
|
||||||
switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
|
switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
|
||||||
case ANI_END: // end of animation script
|
case ANI_END: // end of animation script
|
||||||
|
@ -104,7 +87,6 @@ SCRIPTSTATE DoNextFrame(ANIM *pAnim) {
|
||||||
|
|
||||||
// go fetch a real image
|
// go fetch a real image
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ANI_HVFLIP: // flip animated object in both directions
|
case ANI_HVFLIP: // flip animated object in both directions
|
||||||
|
|
||||||
// next opcode
|
// next opcode
|
||||||
|
@ -230,6 +212,12 @@ SCRIPTSTATE DoNextFrame(ANIM *pAnim) {
|
||||||
void InitStepAnimScript(ANIM *pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int aniSpeed) {
|
void InitStepAnimScript(ANIM *pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int aniSpeed) {
|
||||||
OBJECT *pObj; // multi-object list iterator
|
OBJECT *pObj; // multi-object list iterator
|
||||||
|
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugAnimations,
|
||||||
|
"InitStepAnimScript Object=(%d,%d,%xh) script=%xh aniSpeed=%d rec=%ph",
|
||||||
|
!pAniObj ? 0 : fracToInt(pAniObj->xPos),
|
||||||
|
!pAniObj ? 0 : fracToInt(pAniObj->yPos),
|
||||||
|
!pAniObj ? 0 : pAniObj->hImg, hNewScript, aniSpeed, (byte *)pAnim);
|
||||||
|
|
||||||
pAnim->aniDelta = 1; // will animate on next call to NextAnimRate
|
pAnim->aniDelta = 1; // will animate on next call to NextAnimRate
|
||||||
pAnim->pObject = pAniObj; // set object to animate
|
pAnim->pObject = pAniObj; // set object to animate
|
||||||
pAnim->hScript = hNewScript; // set animation script
|
pAnim->hScript = hNewScript; // set animation script
|
||||||
|
@ -254,9 +242,13 @@ SCRIPTSTATE StepAnimScript(ANIM *pAnim) {
|
||||||
// re-init animation delta counter
|
// re-init animation delta counter
|
||||||
pAnim->aniDelta = pAnim->aniRate;
|
pAnim->aniDelta = pAnim->aniRate;
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
state = DoNextFrame(pAnim);
|
||||||
|
else {
|
||||||
// move to next frame
|
// move to next frame
|
||||||
while ((state = DoNextFrame(pAnim)) == ScriptNoSleep)
|
while ((state = DoNextFrame(pAnim)) == ScriptNoSleep)
|
||||||
;
|
;
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -274,7 +266,7 @@ void SkipFrames(ANIM *pAnim, int numFrames) {
|
||||||
// get a pointer to the script
|
// get a pointer to the script
|
||||||
const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);
|
const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);
|
||||||
|
|
||||||
if (numFrames <= 0)
|
if (!TinselV2 && (numFrames <= 0))
|
||||||
// do nothing
|
// do nothing
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -282,9 +274,10 @@ void SkipFrames(ANIM *pAnim, int numFrames) {
|
||||||
|
|
||||||
switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
|
switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
|
||||||
case ANI_END: // end of animation script
|
case ANI_END: // end of animation script
|
||||||
// going off the end is probably a error
|
// going off the end is probably a error, but only in Tinsel 1
|
||||||
|
if (!TinselV2)
|
||||||
error("SkipFrames(): formally 'assert(0)!'");
|
error("SkipFrames(): formally 'assert(0)!'");
|
||||||
break;
|
return;
|
||||||
|
|
||||||
case ANI_JUMP: // do animation jump
|
case ANI_JUMP: // do animation jump
|
||||||
|
|
||||||
|
@ -293,6 +286,10 @@ void SkipFrames(ANIM *pAnim, int numFrames) {
|
||||||
|
|
||||||
// jump to new frame position
|
// jump to new frame position
|
||||||
pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);
|
pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
// Done if skip to jump
|
||||||
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ANI_HFLIP: // flip animated object horizontally
|
case ANI_HFLIP: // flip animated object horizontally
|
||||||
|
@ -383,7 +380,10 @@ void SkipFrames(ANIM *pAnim, int numFrames) {
|
||||||
default: // must be an actual animation frame handle
|
default: // must be an actual animation frame handle
|
||||||
|
|
||||||
// one less frame
|
// one less frame
|
||||||
if (numFrames-- > 0) {
|
if (numFrames == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (numFrames == -1 || numFrames-- > 0) {
|
||||||
// next opcode
|
// next opcode
|
||||||
pAnim->scriptIndex++;
|
pAnim->scriptIndex++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -401,4 +401,48 @@ void SkipFrames(ANIM *pAnim, int numFrames) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* About to jump or end
|
||||||
|
* @param pAnim Animation data structure
|
||||||
|
*/
|
||||||
|
bool AboutToJumpOrEnd(PANIM pAnim) {
|
||||||
|
if (pAnim->aniDelta == 1) {
|
||||||
|
// get a pointer to the script
|
||||||
|
ANI_SCRIPT *pAni = (ANI_SCRIPT *)LockMem(pAnim->hScript);
|
||||||
|
int zzz = pAnim->scriptIndex;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// repeat until a real image
|
||||||
|
switch (FROM_LE_32(pAni[zzz].op)) {
|
||||||
|
case ANI_END: // end of animation script
|
||||||
|
case ANI_JUMP: // do animation jump
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case ANI_HFLIP: // flip animated object horizontally
|
||||||
|
case ANI_VFLIP: // flip animated object vertically
|
||||||
|
case ANI_HVFLIP: // flip animated object in both directions
|
||||||
|
zzz++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANI_ADJUSTX: // adjust animated object x animation point
|
||||||
|
case ANI_ADJUSTY: // adjust animated object y animation point
|
||||||
|
zzz += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANI_ADJUSTXY: // adjust animated object x & y animation points
|
||||||
|
zzz += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANI_HIDE: // hide animated object
|
||||||
|
default: // must be an actual animation frame handle
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -41,6 +41,32 @@ struct ANIM {
|
||||||
uint32 hScript; //!< animation script handle
|
uint32 hScript; //!< animation script handle
|
||||||
int scriptIndex; //!< current position in animation script
|
int scriptIndex; //!< current position in animation script
|
||||||
};
|
};
|
||||||
|
typedef ANIM *PANIM;
|
||||||
|
|
||||||
|
typedef void (*PANI_ADDR)(struct ANIM *);
|
||||||
|
|
||||||
|
/** Animation script commands */
|
||||||
|
enum {
|
||||||
|
ANI_END = 0, //!< end of animation script
|
||||||
|
ANI_JUMP = 1, //!< animation script jump
|
||||||
|
ANI_HFLIP = 2, //!< flip animated object horizontally
|
||||||
|
ANI_VFLIP = 3, //!< flip animated object vertically
|
||||||
|
ANI_HVFLIP = 4, //!< flip animated object in both directions
|
||||||
|
ANI_ADJUSTX = 5, //!< adjust animated object x animation point
|
||||||
|
ANI_ADJUSTY = 6, //!< adjust animated object y animation point
|
||||||
|
ANI_ADJUSTXY = 7, //!< adjust animated object x & y animation points
|
||||||
|
ANI_NOSLEEP = 8, //!< do not sleep for this frame
|
||||||
|
ANI_CALL = 9, //!< call routine
|
||||||
|
ANI_HIDE = 10, //!< hide animated object
|
||||||
|
ANI_STOP = 11 //!< stop sound
|
||||||
|
};
|
||||||
|
|
||||||
|
/** animation script command possibilities */
|
||||||
|
union ANI_SCRIPT {
|
||||||
|
int32 op; //!< treat as an opcode or operand
|
||||||
|
uint32 hFrame; //!< treat as a animation frame handle
|
||||||
|
// PANI_ADDR pFunc; //!< treat as a animation function call
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*\
|
/*----------------------------------------------------------------------*\
|
||||||
|
@ -66,6 +92,8 @@ void SkipFrames( // Skip the specified number of frames
|
||||||
ANIM *pAnim, // animation data structure
|
ANIM *pAnim, // animation data structure
|
||||||
int numFrames); // number of frames to skip
|
int numFrames); // number of frames to skip
|
||||||
|
|
||||||
|
bool AboutToJumpOrEnd(PANIM pAnim);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif // TINSEL_ANIM_H
|
#endif // TINSEL_ANIM_H
|
||||||
|
|
|
@ -37,6 +37,9 @@ namespace Tinsel {
|
||||||
// current background
|
// current background
|
||||||
BACKGND *pCurBgnd = NULL;
|
BACKGND *pCurBgnd = NULL;
|
||||||
|
|
||||||
|
// FIXME: Not yet used
|
||||||
|
static bool bEntireRedraw;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to initialise a background.
|
* Called to initialise a background.
|
||||||
* @param pBgnd Pointer to data struct for current background
|
* @param pBgnd Pointer to data struct for current background
|
||||||
|
@ -124,6 +127,27 @@ void PlayfieldGetPos(int which, int *pXpos, int *pYpos) {
|
||||||
*pYpos = fracToInt(pPlayfield->fieldY);
|
*pYpos = fracToInt(pPlayfield->fieldY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the x position of the centre of the specified playfield
|
||||||
|
* @param which Which playfield
|
||||||
|
*/
|
||||||
|
|
||||||
|
int PlayfieldGetCentreX(int which) {
|
||||||
|
PLAYFIELD *pPlayfield; // pointer to relavent playfield
|
||||||
|
|
||||||
|
// make sure there is a background
|
||||||
|
assert(pCurBgnd != NULL);
|
||||||
|
|
||||||
|
// make sure the playfield number is in range
|
||||||
|
assert(which >= 0 && which < pCurBgnd->numPlayfields);
|
||||||
|
|
||||||
|
// get playfield pointer
|
||||||
|
pPlayfield = pCurBgnd->fieldArray + which;
|
||||||
|
|
||||||
|
// get current integer position
|
||||||
|
return fracToInt(pPlayfield->fieldX) + SCREEN_WIDTH/2;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the display list for the specified playfield.
|
* Returns the display list for the specified playfield.
|
||||||
* @param which Which playfield
|
* @param which Which playfield
|
||||||
|
@ -229,4 +253,9 @@ void DrawBackgnd(void) {
|
||||||
ResetClipRect();
|
ResetClipRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ForceEntireRedraw(void) {
|
||||||
|
bEntireRedraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -27,10 +27,11 @@
|
||||||
#ifndef TINSEL_BACKGND_H // prevent multiple includes
|
#ifndef TINSEL_BACKGND_H // prevent multiple includes
|
||||||
#define TINSEL_BACKGND_H
|
#define TINSEL_BACKGND_H
|
||||||
|
|
||||||
#include "tinsel/dw.h" // for SCNHANDLE
|
|
||||||
#include "tinsel/palette.h" // palette definitions
|
|
||||||
#include "common/frac.h"
|
#include "common/frac.h"
|
||||||
#include "common/rect.h"
|
#include "common/rect.h"
|
||||||
|
#include "tinsel/coroutine.h"
|
||||||
|
#include "tinsel/dw.h" // for SCNHANDLE
|
||||||
|
#include "tinsel/palette.h" // palette definitions
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -78,6 +79,8 @@ struct BACKGND {
|
||||||
void InitBackground( // called to initialise a background
|
void InitBackground( // called to initialise a background
|
||||||
BACKGND *pBgnd); // pointer to data struct for current background
|
BACKGND *pBgnd); // pointer to data struct for current background
|
||||||
|
|
||||||
|
void StartupBackground(CORO_PARAM, SCNHANDLE hFilm);
|
||||||
|
|
||||||
void StopBgndScrolling(void); // Stops all background playfields from scrolling
|
void StopBgndScrolling(void); // Stops all background playfields from scrolling
|
||||||
|
|
||||||
void PlayfieldSetPos( // Sets the xy position of the specified playfield in the current background
|
void PlayfieldSetPos( // Sets the xy position of the specified playfield in the current background
|
||||||
|
@ -90,6 +93,9 @@ void PlayfieldGetPos( // Returns the xy position of the specified playfield in
|
||||||
int *pXpos, // returns current x position
|
int *pXpos, // returns current x position
|
||||||
int *pYpos); // returns current y position
|
int *pYpos); // returns current y position
|
||||||
|
|
||||||
|
int PlayfieldGetCentreX( // Returns the xy position of the specified playfield in the current background
|
||||||
|
int which); // which playfield
|
||||||
|
|
||||||
OBJECT *GetPlayfieldList( // Returns the display list for the specified playfield
|
OBJECT *GetPlayfieldList( // Returns the display list for the specified playfield
|
||||||
int which); // which playfield
|
int which); // which playfield
|
||||||
|
|
||||||
|
@ -100,7 +106,15 @@ void DrawBackgnd(void); // Draws all playfields for the current background
|
||||||
|
|
||||||
void RedrawBackgnd(void); // Completely redraws all the playfield object lists for the current background
|
void RedrawBackgnd(void); // Completely redraws all the playfield object lists for the current background
|
||||||
|
|
||||||
SCNHANDLE BackPal(void);
|
OBJECT *GetBgObject();
|
||||||
|
|
||||||
|
SCNHANDLE BgPal(void);
|
||||||
|
|
||||||
|
void ForceEntireRedraw(void);
|
||||||
|
|
||||||
|
int BgWidth(void);
|
||||||
|
|
||||||
|
int BgHeight(void);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
#include "tinsel/pid.h"
|
#include "tinsel/pid.h"
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
#include "tinsel/timers.h" // For ONE_SECOND constant
|
#include "tinsel/timers.h" // For ONE_SECOND constant
|
||||||
#include "tinsel/tinlib.h" // For control()
|
#include "tinsel/tinlib.h" // For Control()
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
|
||||||
|
@ -45,49 +46,61 @@ namespace Tinsel {
|
||||||
|
|
||||||
//----------------- LOCAL GLOBAL DATA --------------------
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
static SCNHANDLE BackPalette = 0; // Background's palette
|
#define MAX_BG 10
|
||||||
static OBJECT *pBG = 0; // The main picture's object.
|
|
||||||
|
static SCNHANDLE hBgPal = 0; // Background's palette
|
||||||
|
static POBJECT pBG[MAX_BG];
|
||||||
|
static ANIM thisAnim[MAX_BG]; // used by BGmainProcess()
|
||||||
static int BGspeed = 0;
|
static int BGspeed = 0;
|
||||||
static SCNHANDLE BgroundHandle = 0; // Current scene handle - stored in case of Save_Scene()
|
static SCNHANDLE hBackground = 0; // Current scene handle - stored in case of Save_Scene()
|
||||||
static bool DoFadeIn = false;
|
static bool bDoFadeIn = false;
|
||||||
static ANIM thisAnim; // used by BGmainProcess()
|
static int bgReels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetBgObject
|
||||||
|
*/
|
||||||
|
OBJECT *GetBgObject() {
|
||||||
|
return pBG[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BackPal
|
* BackPal
|
||||||
*/
|
*/
|
||||||
SCNHANDLE BackPal(void) {
|
SCNHANDLE BgPal(void) {
|
||||||
return BackPalette;
|
return hBgPal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SetDoFadeIn
|
* SetDoFadeIn
|
||||||
*/
|
*/
|
||||||
void SetDoFadeIn(bool tf) {
|
void SetDoFadeIn(bool tf) {
|
||||||
DoFadeIn = tf;
|
bDoFadeIn = tf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before scene change.
|
* Called before scene change.
|
||||||
*/
|
*/
|
||||||
void DropBackground(void) {
|
void DropBackground(void) {
|
||||||
pBG = NULL; // No background
|
pBG[0] = NULL; // No background
|
||||||
BackPalette = 0; // No background palette
|
|
||||||
|
if (!TinselV2)
|
||||||
|
hBgPal = 0; // No background palette
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the width of the current background.
|
* Return the width of the current background.
|
||||||
*/
|
*/
|
||||||
int BackgroundWidth(void) {
|
int BgWidth(void) {
|
||||||
assert(pBG);
|
assert(pBG[0]);
|
||||||
return MultiRightmost(pBG) + 1;
|
return MultiRightmost(pBG[0]) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the height of the current background.
|
* Return the height of the current background.
|
||||||
*/
|
*/
|
||||||
int BackgroundHeight(void) {
|
int BgHeight(void) {
|
||||||
assert(pBG);
|
assert(pBG[0]);
|
||||||
return MultiLowest(pBG) + 1;
|
return MultiLowest(pBG[0]) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,90 +113,137 @@ static void BGmainProcess(CORO_PARAM, const void *param) {
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
const FREEL *pfr;
|
const FILM *pFilm;
|
||||||
|
const FREEL *pReel;
|
||||||
const MULTI_INIT *pmi;
|
const MULTI_INIT *pmi;
|
||||||
|
|
||||||
// get the stuff copied to process when it was created
|
// get the stuff copied to process when it was created
|
||||||
pfr = (const FREEL *)param;
|
if (pBG[0] == NULL) {
|
||||||
|
|
||||||
if (pBG == NULL) {
|
|
||||||
/*** At start of scene ***/
|
/*** At start of scene ***/
|
||||||
|
|
||||||
|
if (!TinselV2) {
|
||||||
|
pReel = (const FREEL *)param;
|
||||||
|
|
||||||
// Get the MULTI_INIT structure
|
// Get the MULTI_INIT structure
|
||||||
pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pfr->mobj));
|
pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj));
|
||||||
|
|
||||||
// Initialise and insert the object, and initialise its script.
|
// Initialise and insert the object, and initialise its script.
|
||||||
pBG = MultiInitObject(pmi);
|
pBG[0] = MultiInitObject(pmi);
|
||||||
MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG);
|
MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[0]);
|
||||||
InitStepAnimScript(&thisAnim, pBG, FROM_LE_32(pfr->script), BGspeed);
|
InitStepAnimScript(&thisAnim[0], pBG[0], FROM_LE_32(pReel->script), BGspeed);
|
||||||
|
bgReels = 1;
|
||||||
|
} else {
|
||||||
|
/*** At start of scene ***/
|
||||||
|
pFilm = (const FILM *)LockMem(hBackground);
|
||||||
|
bgReels = pFilm->numreels;
|
||||||
|
|
||||||
if (DoFadeIn) {
|
int i;
|
||||||
FadeInFast(NULL);
|
for (i = 0; i < bgReels; i++) {
|
||||||
DoFadeIn = false;
|
// Get the MULTI_INIT structure
|
||||||
|
pmi = (PMULTI_INIT) LockMem(pFilm->reels[i].mobj);
|
||||||
|
|
||||||
|
// Initialise and insert the object, and initialise its script.
|
||||||
|
pBG[i] = MultiInitObject(pmi);
|
||||||
|
MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[i]);
|
||||||
|
MultiSetZPosition(pBG[i], 0);
|
||||||
|
InitStepAnimScript(&thisAnim[i], pBG[i], pFilm->reels[i].script, BGspeed);
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
pBG[i-1]->pSlave = pBG[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (StepAnimScript(&thisAnim) != ScriptFinished)
|
if (bDoFadeIn) {
|
||||||
CORO_SLEEP(1);
|
FadeInFast(NULL);
|
||||||
|
bDoFadeIn = false;
|
||||||
|
} else if (TinselV2)
|
||||||
|
PokeInTagColour();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
for (int i = 0; i < bgReels; i++) {
|
||||||
|
if (StepAnimScript(&thisAnim[i]) == ScriptFinished)
|
||||||
error("Background animation has finished!");
|
error("Background animation has finished!");
|
||||||
|
}
|
||||||
|
|
||||||
|
CORO_SLEEP(1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// New background during scene
|
// New background during scene
|
||||||
|
if (!TinselV2) {
|
||||||
|
pReel = (const FREEL *)param;
|
||||||
|
InitStepAnimScript(&thisAnim[0], pBG[0], FROM_LE_32(pReel->script), BGspeed);
|
||||||
|
StepAnimScript(&thisAnim[0]);
|
||||||
|
} else {
|
||||||
|
pFilm = (const FILM *)LockMem(hBackground);
|
||||||
|
assert(bgReels == pFilm->numreels);
|
||||||
|
|
||||||
// Just re-initialise the script.
|
// Just re-initialise the scripts.
|
||||||
InitStepAnimScript(&thisAnim, pBG, FROM_LE_32(pfr->script), BGspeed);
|
for (int i = 0; i < bgReels; i++) {
|
||||||
StepAnimScript(&thisAnim);
|
InitStepAnimScript(&thisAnim[i], pBG[i], pFilm->reels[i].script, BGspeed);
|
||||||
|
StepAnimScript(&thisAnim[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* setBackPal()
|
* AetBgPal()
|
||||||
*/
|
*/
|
||||||
void setBackPal(SCNHANDLE hPal) {
|
void SetBackPal(SCNHANDLE hPal) {
|
||||||
BackPalette = hPal;
|
hBgPal = hPal;
|
||||||
|
|
||||||
fettleFontPal(BackPalette);
|
FettleFontPal(hBgPal);
|
||||||
CreateTranslucentPalette(BackPalette);
|
CreateTranslucentPalette(hBgPal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangePalette(SCNHANDLE hPal) {
|
void ChangePalette(SCNHANDLE hPal) {
|
||||||
SwapPalette(FindPalette(BackPalette), hPal);
|
SwapPalette(FindPalette(hBgPal), hPal);
|
||||||
|
|
||||||
setBackPal(hPal);
|
SetBackPal(hPal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the scene background film, extracts the palette handle for
|
* Given the scene background film, extracts the palette handle for
|
||||||
* everything else's use, then starts a display process for each reel
|
* everything else's use, then starts a display process for each reel
|
||||||
* in the film.
|
* in the film.
|
||||||
* @param bfilm Scene background film
|
* @param hFilm Scene background film
|
||||||
*/
|
*/
|
||||||
void startupBackground(SCNHANDLE bfilm) {
|
void StartupBackground(CORO_PARAM, SCNHANDLE hFilm) {
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
const FILM *pfilm;
|
const FILM *pfilm;
|
||||||
IMAGE *pim;
|
IMAGE *pim;
|
||||||
|
|
||||||
BgroundHandle = bfilm; // Save handle in case of Save_Scene()
|
hBackground = hFilm; // Save handle in case of Save_Scene()
|
||||||
|
|
||||||
pim = GetImageFromFilm(bfilm, 0, NULL, NULL, &pfilm);
|
pim = GetImageFromFilm(hFilm, 0, NULL, NULL, &pfilm);
|
||||||
setBackPal(FROM_LE_32(pim->hImgPal));
|
SetBackPal(FROM_LE_32(pim->hImgPal));
|
||||||
|
|
||||||
// Extract the film speed
|
// Extract the film speed
|
||||||
BGspeed = ONE_SECOND / FROM_LE_32(pfilm->frate);
|
BGspeed = ONE_SECOND / FROM_LE_32(pfilm->frate);
|
||||||
|
|
||||||
if (pBG == NULL)
|
|
||||||
control(CONTROL_STARTOFF); // New feature - start scene with control off
|
|
||||||
|
|
||||||
// Start display process for each reel in the film
|
// Start display process for each reel in the film
|
||||||
assert(FROM_LE_32(pfilm->numreels) == 1); // Multi-reeled backgrounds withdrawn
|
|
||||||
g_scheduler->createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL));
|
g_scheduler->createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL));
|
||||||
|
|
||||||
|
if (pBG[0] == NULL)
|
||||||
|
ControlStartOff();
|
||||||
|
|
||||||
|
if (TinselV2 && (coroParam != nullContext))
|
||||||
|
CORO_GIVE_WAY;
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the current scene handle.
|
* Return the current scene handle.
|
||||||
*/
|
*/
|
||||||
SCNHANDLE GetBgroundHandle(void) {
|
SCNHANDLE GetBgroundHandle(void) {
|
||||||
return BgroundHandle;
|
return hBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
1272
engines/tinsel/bmv.cpp
Normal file
1272
engines/tinsel/bmv.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,8 @@
|
||||||
* This file contains configuration functionality
|
* This file contains configuration functionality
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//#define USE_3FLAGS 1
|
||||||
|
|
||||||
#include "tinsel/config.h"
|
#include "tinsel/config.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/sound.h"
|
#include "tinsel/sound.h"
|
||||||
|
@ -39,7 +41,7 @@ namespace Tinsel {
|
||||||
//----------------- GLOBAL GLOBAL DATA --------------------
|
//----------------- GLOBAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
int dclickSpeed = DOUBLE_CLICK_TIME;
|
int dclickSpeed = DOUBLE_CLICK_TIME;
|
||||||
int volMidi = Audio::Mixer::kMaxChannelVolume;
|
int volMusic = Audio::Mixer::kMaxChannelVolume;
|
||||||
int volSound = Audio::Mixer::kMaxChannelVolume;
|
int volSound = Audio::Mixer::kMaxChannelVolume;
|
||||||
int volVoice = Audio::Mixer::kMaxChannelVolume;
|
int volVoice = Audio::Mixer::kMaxChannelVolume;
|
||||||
int speedText = DEFTEXTSPEED;
|
int speedText = DEFTEXTSPEED;
|
||||||
|
@ -49,21 +51,18 @@ LANGUAGE g_language = TXT_ENGLISH;
|
||||||
int bAmerica = 0;
|
int bAmerica = 0;
|
||||||
|
|
||||||
|
|
||||||
// Shouldn't really be here, but time is short...
|
|
||||||
bool bNoBlocking;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write settings to config manager and flush the config file to disk.
|
* Write settings to config manager and flush the config file to disk.
|
||||||
*/
|
*/
|
||||||
void WriteConfig(void) {
|
void WriteConfig(void) {
|
||||||
ConfMan.setInt("dclick_speed", dclickSpeed);
|
ConfMan.setInt("dclick_speed", dclickSpeed);
|
||||||
ConfMan.setInt("music_volume", volMidi);
|
ConfMan.setInt("music_volume", volMusic);
|
||||||
ConfMan.setInt("sfx_volume", volSound);
|
ConfMan.setInt("sfx_volume", volSound);
|
||||||
ConfMan.setInt("speech_volume", volVoice);
|
ConfMan.setInt("speech_volume", volVoice);
|
||||||
ConfMan.setInt("talkspeed", (speedText * 255) / 100);
|
ConfMan.setInt("talkspeed", (speedText * 255) / 100);
|
||||||
ConfMan.setBool("subtitles", bSubtitles);
|
ConfMan.setBool("subtitles", bSubtitles);
|
||||||
//ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0);
|
//ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0);
|
||||||
//ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB
|
|
||||||
|
|
||||||
// Store language for multilingual versions
|
// Store language for multilingual versions
|
||||||
if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) {
|
if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) {
|
||||||
|
@ -92,16 +91,14 @@ void WriteConfig(void) {
|
||||||
ConfMan.flushToDisk();
|
ConfMan.flushToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*\
|
/**
|
||||||
| ReadConfig() |
|
* Read configuration settings from the config file into memory
|
||||||
|-----------------------------------------------------------------------|
|
*/
|
||||||
|
|
|
||||||
\*---------------------------------------------------------------------*/
|
|
||||||
void ReadConfig(void) {
|
void ReadConfig(void) {
|
||||||
if (ConfMan.hasKey("dclick_speed"))
|
if (ConfMan.hasKey("dclick_speed"))
|
||||||
dclickSpeed = ConfMan.getInt("dclick_speed");
|
dclickSpeed = ConfMan.getInt("dclick_speed");
|
||||||
|
|
||||||
volMidi = ConfMan.getInt("music_volume");
|
volMusic = ConfMan.getInt("music_volume");
|
||||||
volSound = ConfMan.getInt("sfx_volume");
|
volSound = ConfMan.getInt("sfx_volume");
|
||||||
volVoice = ConfMan.getInt("speech_volume");
|
volVoice = ConfMan.getInt("speech_volume");
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int dclickSpeed;
|
extern int dclickSpeed;
|
||||||
extern int volMidi;
|
extern int volMusic;
|
||||||
extern int volSound;
|
extern int volSound;
|
||||||
extern int volVoice;
|
extern int volVoice;
|
||||||
extern int speedText;
|
extern int speedText;
|
||||||
|
@ -51,10 +51,6 @@ void ReadConfig(void);
|
||||||
|
|
||||||
extern bool isJapanMode();
|
extern bool isJapanMode();
|
||||||
|
|
||||||
|
|
||||||
// Shouldn't really be here, but time is short...
|
|
||||||
extern bool bNoBlocking;
|
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,6 +70,7 @@ struct CoroBaseContext {
|
||||||
|
|
||||||
typedef CoroBaseContext *CoroContext;
|
typedef CoroBaseContext *CoroContext;
|
||||||
|
|
||||||
|
extern CoroContext nullContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class which holds a pointer to a pointer to a CoroBaseContext.
|
* Wrapper class which holds a pointer to a pointer to a CoroBaseContext.
|
||||||
|
@ -101,6 +102,7 @@ public:
|
||||||
#define CORO_END_CONTEXT(x) } *x = (CoroContextTag *)coroParam
|
#define CORO_END_CONTEXT(x) } *x = (CoroContextTag *)coroParam
|
||||||
|
|
||||||
#define CORO_BEGIN_CODE(x) \
|
#define CORO_BEGIN_CODE(x) \
|
||||||
|
if (&coroParam == &nullContext) assert(!nullContext);\
|
||||||
if (!x) {coroParam = x = new CoroContextTag();}\
|
if (!x) {coroParam = x = new CoroContextTag();}\
|
||||||
assert(coroParam);\
|
assert(coroParam);\
|
||||||
assert(coroParam->_sleep >= 0);\
|
assert(coroParam->_sleep >= 0);\
|
||||||
|
@ -109,17 +111,22 @@ public:
|
||||||
switch(coroParam->_line) { case 0:;
|
switch(coroParam->_line) { case 0:;
|
||||||
|
|
||||||
#define CORO_END_CODE \
|
#define CORO_END_CODE \
|
||||||
|
if (&coroParam == &nullContext) nullContext = NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CORO_SLEEP(delay) \
|
#define CORO_SLEEP(delay) do {\
|
||||||
do {\
|
|
||||||
coroParam->_line = __LINE__;\
|
coroParam->_line = __LINE__;\
|
||||||
coroParam->_sleep = delay;\
|
coroParam->_sleep = delay;\
|
||||||
|
assert(&coroParam != &nullContext);\
|
||||||
return; case __LINE__:;\
|
return; case __LINE__:;\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define CORO_GIVE_WAY do { g_scheduler->giveWay(); CORO_SLEEP(1); } while (0)
|
||||||
|
#define CORO_RESCHEDULE do { g_scheduler->reschedule(); CORO_SLEEP(1); } while (0)
|
||||||
|
|
||||||
/** Stop the currently running coroutine */
|
/** Stop the currently running coroutine */
|
||||||
#define CORO_KILL_SELF() do { coroParam->_sleep = -1; return; } while(0)
|
#define CORO_KILL_SELF() \
|
||||||
|
do { if (&coroParam != &nullContext) { coroParam->_sleep = -1; } return; } while(0)
|
||||||
|
|
||||||
/** Invoke another coroutine */
|
/** Invoke another coroutine */
|
||||||
#define CORO_INVOKE_ARGS(subCoro, ARGS) \
|
#define CORO_INVOKE_ARGS(subCoro, ARGS) \
|
||||||
|
@ -130,9 +137,22 @@ public:
|
||||||
subCoro ARGS;\
|
subCoro ARGS;\
|
||||||
if (!coroParam->_subctx) break;\
|
if (!coroParam->_subctx) break;\
|
||||||
coroParam->_sleep = coroParam->_subctx->_sleep;\
|
coroParam->_sleep = coroParam->_subctx->_sleep;\
|
||||||
|
assert(&coroParam != &nullContext);\
|
||||||
return; case __LINE__:;\
|
return; case __LINE__:;\
|
||||||
} while(1);\
|
} while(1);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
#define CORO_INVOKE_ARGS_V(subCoro, RESULT, ARGS) \
|
||||||
|
do {\
|
||||||
|
coroParam->_line = __LINE__;\
|
||||||
|
coroParam->_subctx = 0;\
|
||||||
|
do {\
|
||||||
|
subCoro ARGS;\
|
||||||
|
if (!coroParam->_subctx) break;\
|
||||||
|
coroParam->_sleep = coroParam->_subctx->_sleep;\
|
||||||
|
assert(&coroParam != &nullContext);\
|
||||||
|
return RESULT; case __LINE__:;\
|
||||||
|
} while(1);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define CORO_INVOKE_0(subCoroutine) \
|
#define CORO_INVOKE_0(subCoroutine) \
|
||||||
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX))
|
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX))
|
||||||
|
@ -140,6 +160,8 @@ public:
|
||||||
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0))
|
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0))
|
||||||
#define CORO_INVOKE_2(subCoroutine, a0,a1) \
|
#define CORO_INVOKE_2(subCoroutine, a0,a1) \
|
||||||
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1))
|
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1))
|
||||||
|
#define CORO_INVOKE_3(subCoroutine, a0,a1,a2) \
|
||||||
|
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2))
|
||||||
|
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -34,11 +34,14 @@
|
||||||
#include "tinsel/film.h"
|
#include "tinsel/film.h"
|
||||||
#include "tinsel/graphics.h"
|
#include "tinsel/graphics.h"
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
#include "tinsel/inventory.h"
|
#include "tinsel/dialogs.h"
|
||||||
#include "tinsel/multiobj.h" // multi-part object defintions etc.
|
#include "tinsel/multiobj.h" // multi-part object defintions etc.
|
||||||
#include "tinsel/object.h"
|
#include "tinsel/object.h"
|
||||||
#include "tinsel/pid.h"
|
#include "tinsel/pid.h"
|
||||||
|
#include "tinsel/play.h"
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
|
#include "tinsel/text.h"
|
||||||
#include "tinsel/timers.h" // For ONE_SECOND constant
|
#include "tinsel/timers.h" // For ONE_SECOND constant
|
||||||
#include "tinsel/tinlib.h" // resetidletime()
|
#include "tinsel/tinlib.h" // resetidletime()
|
||||||
#include "tinsel/tinsel.h" // For engine access
|
#include "tinsel/tinsel.h" // For engine access
|
||||||
|
@ -54,20 +57,21 @@ namespace Tinsel {
|
||||||
|
|
||||||
//----------------- LOCAL GLOBAL DATA --------------------
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
static OBJECT *McurObj = 0; // Main cursor object
|
static OBJECT *McurObj = NULL; // Main cursor object
|
||||||
static OBJECT *AcurObj = 0; // Auxiliary cursor object
|
static OBJECT *AcurObj = NULL; // Auxiliary cursor object
|
||||||
|
|
||||||
static ANIM McurAnim = {0,0,0,0,0}; // Main cursor animation structure
|
static ANIM McurAnim = {0,0,0,0,0}; // Main cursor animation structure
|
||||||
static ANIM AcurAnim = {0,0,0,0,0}; // Auxiliary cursor animation structure
|
static ANIM AcurAnim = {0,0,0,0,0}; // Auxiliary cursor animation structure
|
||||||
|
|
||||||
static bool bHiddenCursor = false; // Set when cursor is hidden
|
static bool bHiddenCursor = false; // Set when cursor is hidden
|
||||||
static bool bTempNoTrailers = false; // Set when cursor trails are hidden
|
static bool bTempNoTrailers = false; // Set when cursor trails are hidden
|
||||||
|
static bool bTempHide = false; // Set when cursor is hidden
|
||||||
|
|
||||||
static bool bFrozenCursor = false; // Set when cursor position is frozen
|
static bool bFrozenCursor = false; // Set when cursor position is frozen
|
||||||
|
|
||||||
static frac_t IterationSize = 0;
|
static frac_t IterationSize = 0;
|
||||||
|
|
||||||
static SCNHANDLE CursorHandle = 0; // Handle to cursor reel data
|
static SCNHANDLE hCursorFilm = 0; // Handle to cursor reel data
|
||||||
|
|
||||||
static int numTrails = 0;
|
static int numTrails = 0;
|
||||||
static int nextTrail = 0;
|
static int nextTrail = 0;
|
||||||
|
@ -76,8 +80,11 @@ static bool bWhoa = false; // Set by DropCursor() at the end of a scene
|
||||||
// - causes cursor processes to do nothing
|
// - causes cursor processes to do nothing
|
||||||
// Reset when main cursor has re-initialised
|
// Reset when main cursor has re-initialised
|
||||||
|
|
||||||
static bool restart = false; // When main cursor has been bWhoa-ed, it waits
|
static uint16 restart = 0; // When main cursor has been bWhoa-ed, it waits
|
||||||
// for this to be set to true.
|
// for this to be set to 0x8000.
|
||||||
|
// Main cursor sets all the bits after a re-start
|
||||||
|
// - each cursor trail examines it's own bit
|
||||||
|
// to trigger a trail restart.
|
||||||
|
|
||||||
static short ACoX = 0, ACoY = 0; // Auxillary cursor image's animation offsets
|
static short ACoX = 0, ACoY = 0; // Auxillary cursor image's animation offsets
|
||||||
|
|
||||||
|
@ -97,7 +104,7 @@ static int lastCursorX = 0, lastCursorY = 0;
|
||||||
|
|
||||||
//----------------- FORWARD REFERENCES --------------------
|
//----------------- FORWARD REFERENCES --------------------
|
||||||
|
|
||||||
static void MoveCursor(void);
|
static void DoCursorMove(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise and insert a cursor trail object, set its Z-pos, and hide
|
* Initialise and insert a cursor trail object, set its Z-pos, and hide
|
||||||
|
@ -117,9 +124,9 @@ static void InitCurTrailObj(int i, int x, int y) {
|
||||||
if (ntrailData[i].trailObj != NULL)
|
if (ntrailData[i].trailObj != NULL)
|
||||||
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
|
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
|
||||||
|
|
||||||
pim = GetImageFromFilm(CursorHandle, i+1, &pfr, &pmi, &pfilm);// Get pointer to image
|
pim = GetImageFromFilm(hCursorFilm, i+1, &pfr, &pmi, &pfilm);// Get pointer to image
|
||||||
assert(BackPal()); // No background palette
|
assert(BgPal()); // No background palette
|
||||||
pim->hImgPal = TO_LE_32(BackPal());
|
pim->hImgPal = TO_LE_32(BgPal());
|
||||||
|
|
||||||
// Initialise and insert the object, set its Z-pos, and hide it
|
// Initialise and insert the object, set its Z-pos, and hide it
|
||||||
ntrailData[i].trailObj = MultiInitObject(pmi);
|
ntrailData[i].trailObj = MultiInitObject(pmi);
|
||||||
|
@ -154,7 +161,7 @@ void AdjustCursorXY(int deltaX, int deltaY) {
|
||||||
if (GetDriverPosition(&x, &y))
|
if (GetDriverPosition(&x, &y))
|
||||||
_vm->setMousePosition(Common::Point(x + deltaX, y + deltaY));
|
_vm->setMousePosition(Common::Point(x + deltaX, y + deltaY));
|
||||||
}
|
}
|
||||||
MoveCursor();
|
DoCursorMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,7 +177,7 @@ void SetCursorXY(int newx, int newy) {
|
||||||
|
|
||||||
if (GetDriverPosition(&x, &y))
|
if (GetDriverPosition(&x, &y))
|
||||||
_vm->setMousePosition(Common::Point(newx, newy));
|
_vm->setMousePosition(Common::Point(newx, newy));
|
||||||
MoveCursor();
|
DoCursorMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,7 +188,7 @@ void SetCursorScreenXY(int newx, int newy) {
|
||||||
|
|
||||||
if (GetDriverPosition(&x, &y))
|
if (GetDriverPosition(&x, &y))
|
||||||
_vm->setMousePosition(Common::Point(newx, newy));
|
_vm->setMousePosition(Common::Point(newx, newy));
|
||||||
MoveCursor();
|
DoCursorMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,7 +236,7 @@ void RestoreMainCursor(void) {
|
||||||
const FILM *pfilm;
|
const FILM *pfilm;
|
||||||
|
|
||||||
if (McurObj != NULL) {
|
if (McurObj != NULL) {
|
||||||
pfilm = (const FILM *)LockMem(CursorHandle);
|
pfilm = (const FILM *)LockMem(hCursorFilm);
|
||||||
|
|
||||||
InitStepAnimScript(&McurAnim, McurObj, FROM_LE_32(pfilm->reels->script), ONE_SECOND / FROM_LE_32(pfilm->frate));
|
InitStepAnimScript(&McurAnim, McurObj, FROM_LE_32(pfilm->reels->script), ONE_SECOND / FROM_LE_32(pfilm->frate));
|
||||||
StepAnimScript(&McurAnim);
|
StepAnimScript(&McurAnim);
|
||||||
|
@ -281,6 +288,13 @@ void FreezeCursor(void) {
|
||||||
bFrozenCursor = true;
|
bFrozenCursor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Freeze the cursor, or not.
|
||||||
|
*/
|
||||||
|
void DoFreezeCursor(bool bFreeze) {
|
||||||
|
bFrozenCursor = bFreeze;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HideCursorTrails
|
* HideCursorTrails
|
||||||
*/
|
*/
|
||||||
|
@ -365,11 +379,12 @@ void SetAuxCursor(SCNHANDLE hFilm) {
|
||||||
GetCursorXY(&x, &y, false); // Note: also waits for cursor to appear
|
GetCursorXY(&x, &y, false); // Note: also waits for cursor to appear
|
||||||
|
|
||||||
pim = GetImageFromFilm(hFilm, 0, &pfr, &pmi, &pfilm);// Get pointer to image
|
pim = GetImageFromFilm(hFilm, 0, &pfr, &pmi, &pfilm);// Get pointer to image
|
||||||
assert(BackPal()); // no background palette
|
assert(BgPal()); // no background palette
|
||||||
pim->hImgPal = TO_LE_32(BackPal()); // Poke in the background palette
|
pim->hImgPal = TO_LE_32(BgPal()); // Poke in the background palette
|
||||||
|
|
||||||
ACoX = (short)(FROM_LE_16(pim->imgWidth)/2 - ((int16) FROM_LE_16(pim->anioffX)));
|
ACoX = (short)(FROM_LE_16(pim->imgWidth)/2 - ((int16) FROM_LE_16(pim->anioffX)));
|
||||||
ACoY = (short)(FROM_LE_16(pim->imgHeight)/2 - ((int16) FROM_LE_16(pim->anioffY)));
|
ACoY = (short)((FROM_LE_16(pim->imgHeight) & ~C16_FLAG_MASK)/2 -
|
||||||
|
((int16) FROM_LE_16(pim->anioffY)));
|
||||||
|
|
||||||
// Initialise and insert the auxillary cursor object
|
// Initialise and insert the auxillary cursor object
|
||||||
AcurObj = MultiInitObject(pmi);
|
AcurObj = MultiInitObject(pmi);
|
||||||
|
@ -387,7 +402,7 @@ void SetAuxCursor(SCNHANDLE hFilm) {
|
||||||
/**
|
/**
|
||||||
* MoveCursor
|
* MoveCursor
|
||||||
*/
|
*/
|
||||||
static void MoveCursor(void) {
|
static void DoCursorMove(void) {
|
||||||
int startX, startY;
|
int startX, startY;
|
||||||
Common::Point ptMouse;
|
Common::Point ptMouse;
|
||||||
frac_t newX, newY;
|
frac_t newX, newY;
|
||||||
|
@ -459,22 +474,30 @@ static void MoveCursor(void) {
|
||||||
* Initialise cursor object.
|
* Initialise cursor object.
|
||||||
*/
|
*/
|
||||||
static void InitCurObj(void) {
|
static void InitCurObj(void) {
|
||||||
const FILM *pfilm;
|
const FILM *pFilm;
|
||||||
const FREEL *pfr;
|
const FREEL *pfr;
|
||||||
const MULTI_INIT *pmi;
|
const MULTI_INIT *pmi;
|
||||||
IMAGE *pim;
|
IMAGE *pim;
|
||||||
|
|
||||||
pim = GetImageFromFilm(CursorHandle, 0, &pfr, &pmi, &pfilm);// Get pointer to image
|
if (TinselV2) {
|
||||||
assert(BackPal()); // no background palette
|
pFilm = (const FILM *)LockMem(hCursorFilm);
|
||||||
pim->hImgPal = TO_LE_32(BackPal());
|
pfr = (const FREEL *)&pFilm->reels[0];
|
||||||
//---
|
pmi = (MULTI_INIT *)LockMem(pfr->mobj);
|
||||||
|
|
||||||
|
PokeInPalette(pmi);
|
||||||
|
} else {
|
||||||
|
assert(BgPal()); // no background palette
|
||||||
|
|
||||||
|
pim = GetImageFromFilm(hCursorFilm, 0, &pfr, &pmi, &pFilm);// Get pointer to image
|
||||||
|
pim->hImgPal = TO_LE_32(BgPal());
|
||||||
|
|
||||||
AcurObj = NULL; // No auxillary cursor
|
AcurObj = NULL; // No auxillary cursor
|
||||||
|
}
|
||||||
|
|
||||||
McurObj = MultiInitObject(pmi);
|
McurObj = MultiInitObject(pmi);
|
||||||
MultiInsertObject(GetPlayfieldList(FIELD_STATUS), McurObj);
|
MultiInsertObject(GetPlayfieldList(FIELD_STATUS), McurObj);
|
||||||
|
|
||||||
InitStepAnimScript(&McurAnim, McurObj, FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pfilm->frate));
|
InitStepAnimScript(&McurAnim, McurObj, FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pFilm->frate));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -486,7 +509,7 @@ static void InitCurPos(void) {
|
||||||
lastCursorY = ptMouse.y;
|
lastCursorY = ptMouse.y;
|
||||||
|
|
||||||
MultiSetZPosition(McurObj, Z_CURSOR);
|
MultiSetZPosition(McurObj, Z_CURSOR);
|
||||||
MoveCursor();
|
DoCursorMove();
|
||||||
MultiHideObject(McurObj);
|
MultiHideObject(McurObj);
|
||||||
|
|
||||||
IterationSize = ITERATION_BASE;
|
IterationSize = ITERATION_BASE;
|
||||||
|
@ -505,16 +528,16 @@ static void CursorStoppedCheck(CORO_PARAM) {
|
||||||
// If scene is closing down
|
// If scene is closing down
|
||||||
if (bWhoa) {
|
if (bWhoa) {
|
||||||
// ...wait for next scene start-up
|
// ...wait for next scene start-up
|
||||||
while (!restart)
|
while (restart != 0x8000)
|
||||||
CORO_SLEEP(1);
|
CORO_SLEEP(1);
|
||||||
|
|
||||||
// Re-initialise
|
// Re-initialise
|
||||||
InitCurObj();
|
InitCurObj();
|
||||||
InitCurPos();
|
InitCurPos();
|
||||||
InventoryIconCursor(); // May be holding something
|
InventoryIconCursor(false); // May be holding something
|
||||||
|
|
||||||
// Re-start the cursor trails
|
// Re-start the cursor trails
|
||||||
restart = false; // set all bits
|
restart = (uint16)-1; // set all bits
|
||||||
bWhoa = false;
|
bWhoa = false;
|
||||||
}
|
}
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
|
@ -530,15 +553,15 @@ void CursorProcess(CORO_PARAM, const void *) {
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
while (!CursorHandle || !BackPal())
|
while (!hCursorFilm || !BgPal())
|
||||||
CORO_SLEEP(1);
|
CORO_SLEEP(1);
|
||||||
|
|
||||||
InitCurObj();
|
InitCurObj();
|
||||||
InitCurPos();
|
InitCurPos();
|
||||||
InventoryIconCursor(); // May be holding something
|
InventoryIconCursor(false); // May be holding something
|
||||||
|
|
||||||
bWhoa = false;
|
bWhoa = false;
|
||||||
restart = false;
|
restart = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
// allow rescheduling
|
// allow rescheduling
|
||||||
|
@ -562,10 +585,10 @@ void CursorProcess(CORO_PARAM, const void *) {
|
||||||
|
|
||||||
// Move the cursor as appropriate
|
// Move the cursor as appropriate
|
||||||
if (!bFrozenCursor)
|
if (!bFrozenCursor)
|
||||||
MoveCursor();
|
DoCursorMove();
|
||||||
|
|
||||||
// If the cursor should be hidden...
|
// If the cursor should be hidden...
|
||||||
if (bHiddenCursor) {
|
if (bHiddenCursor || bTempHide) {
|
||||||
// ...hide the cursor object(s)
|
// ...hide the cursor object(s)
|
||||||
MultiHideObject(McurObj);
|
MultiHideObject(McurObj);
|
||||||
if (AcurObj)
|
if (AcurObj)
|
||||||
|
@ -595,9 +618,9 @@ void CursorProcess(CORO_PARAM, const void *) {
|
||||||
void DwInitCursor(SCNHANDLE bfilm) {
|
void DwInitCursor(SCNHANDLE bfilm) {
|
||||||
const FILM *pfilm;
|
const FILM *pfilm;
|
||||||
|
|
||||||
CursorHandle = bfilm;
|
hCursorFilm = bfilm;
|
||||||
|
|
||||||
pfilm = (const FILM *)LockMem(CursorHandle);
|
pfilm = (const FILM *)LockMem(hCursorFilm);
|
||||||
numTrails = FROM_LE_32(pfilm->numreels) - 1;
|
numTrails = FROM_LE_32(pfilm->numreels) - 1;
|
||||||
|
|
||||||
assert(numTrails <= MAX_TRAILERS);
|
assert(numTrails <= MAX_TRAILERS);
|
||||||
|
@ -607,6 +630,15 @@ void DwInitCursor(SCNHANDLE bfilm) {
|
||||||
* DropCursor is called when a scene is closing down.
|
* DropCursor is called when a scene is closing down.
|
||||||
*/
|
*/
|
||||||
void DropCursor(void) {
|
void DropCursor(void) {
|
||||||
|
if (TinselV2) {
|
||||||
|
if (AcurObj)
|
||||||
|
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), AcurObj);
|
||||||
|
if (McurObj)
|
||||||
|
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), McurObj);
|
||||||
|
|
||||||
|
restart = 0;
|
||||||
|
}
|
||||||
|
|
||||||
AcurObj = NULL; // No auxillary cursor
|
AcurObj = NULL; // No auxillary cursor
|
||||||
McurObj = NULL; // No cursor object (imminently deleted elsewhere)
|
McurObj = NULL; // No cursor object (imminently deleted elsewhere)
|
||||||
bHiddenCursor = false; // Not hidden in next scene
|
bHiddenCursor = false; // Not hidden in next scene
|
||||||
|
@ -625,7 +657,7 @@ void DropCursor(void) {
|
||||||
* RestartCursor is called when a new scene is starting up.
|
* RestartCursor is called when a new scene is starting up.
|
||||||
*/
|
*/
|
||||||
void RestartCursor(void) {
|
void RestartCursor(void) {
|
||||||
restart = true; // Get the main cursor to re-initialise
|
restart = 0x8000; // Get the main cursor to re-initialise
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -639,10 +671,22 @@ void RebootCursor(void) {
|
||||||
|
|
||||||
bHiddenCursor = bTempNoTrailers = bFrozenCursor = false;
|
bHiddenCursor = bTempNoTrailers = bFrozenCursor = false;
|
||||||
|
|
||||||
CursorHandle = 0;
|
hCursorFilm = 0;
|
||||||
|
|
||||||
bWhoa = false;
|
bWhoa = false;
|
||||||
restart = false;
|
restart = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartCursorFollowed(void) {
|
||||||
|
DelAuxCursor();
|
||||||
|
|
||||||
|
if (!SysVar(SV_ENABLEPRINTCURSOR))
|
||||||
|
bTempHide = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndCursorFollowed(void) {
|
||||||
|
InventoryIconCursor(false); // May be holding something
|
||||||
|
bTempHide = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -42,6 +42,7 @@ void SetTempCursor(SCNHANDLE pScript);
|
||||||
void DwHideCursor(void);
|
void DwHideCursor(void);
|
||||||
void UnHideCursor(void);
|
void UnHideCursor(void);
|
||||||
void FreezeCursor(void);
|
void FreezeCursor(void);
|
||||||
|
void DoFreezeCursor(bool bFreeze);
|
||||||
void HideCursorTrails(void);
|
void HideCursorTrails(void);
|
||||||
void UnHideCursorTrails(void);
|
void UnHideCursorTrails(void);
|
||||||
void DelAuxCursor(void);
|
void DelAuxCursor(void);
|
||||||
|
@ -50,6 +51,8 @@ void DwInitCursor(SCNHANDLE bfilm);
|
||||||
void DropCursor(void);
|
void DropCursor(void);
|
||||||
void RestartCursor(void);
|
void RestartCursor(void);
|
||||||
void RebootCursor(void);
|
void RebootCursor(void);
|
||||||
|
void StartCursorFollowed(void);
|
||||||
|
void EndCursorFollowed(void);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include "tinsel/tinsel.h"
|
#include "tinsel/tinsel.h"
|
||||||
#include "tinsel/debugger.h"
|
#include "tinsel/debugger.h"
|
||||||
#include "tinsel/inventory.h"
|
#include "tinsel/dialogs.h"
|
||||||
#include "tinsel/pcode.h"
|
#include "tinsel/pcode.h"
|
||||||
#include "tinsel/scene.h"
|
#include "tinsel/scene.h"
|
||||||
#include "tinsel/sound.h"
|
#include "tinsel/sound.h"
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#include "tinsel/tinsel.h"
|
#include "tinsel/tinsel.h"
|
||||||
#include "tinsel/savescn.h" // needed by TinselMetaEngine::listSaves
|
#include "tinsel/savescn.h" // needed by TinselMetaEngine::listSaves
|
||||||
|
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
struct TinselGameDescription {
|
struct TinselGameDescription {
|
||||||
|
@ -68,7 +67,7 @@ uint16 TinselEngine::getVersion() const {
|
||||||
static const PlainGameDescriptor tinselGames[] = {
|
static const PlainGameDescriptor tinselGames[] = {
|
||||||
{"tinsel", "Tinsel engine game"},
|
{"tinsel", "Tinsel engine game"},
|
||||||
{"dw", "Discworld"},
|
{"dw", "Discworld"},
|
||||||
{"dw2", "Discworld 2: Mortality Bytes!"},
|
{"dw2", "Discworld 2: Missing Presumed ...!?"},
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,25 +76,15 @@ namespace Tinsel {
|
||||||
|
|
||||||
static const TinselGameDescription gameDescriptions[] = {
|
static const TinselGameDescription gameDescriptions[] = {
|
||||||
|
|
||||||
// The DW1 demo was based on an older revision of the Tinsel engine
|
// Note: The following is the (hopefully) definitive list of version details:
|
||||||
// than the one used in the released game. We call it Tinsel v0 as
|
// TINSEL_V0: Used only by the Discworld 1 demo - this used a more primitive version
|
||||||
// opposed to v1 which was used in the full retail version of DW.
|
// of the Tinsel engine and graphics compression, and isn't currently supported
|
||||||
|
// TINSEL_V1: There were two versions of the Discworld 1 game - the first used .GRA
|
||||||
{ // Demo from http://www.adventure-treff.de/specials/dl_demos.php
|
// files, and the second used .SCN files. The second also provided some fixes to
|
||||||
{
|
// various script bugs and coding errors, but is still considered TINSEL_V1,
|
||||||
"dw",
|
// as both game versions work equally well with the newer code.
|
||||||
"Demo",
|
// TINSEL_V2: The Discworld 2 game used this updated version of the Tinsel 1 engine,
|
||||||
AD_ENTRY1s("dw.gra", "ce1b57761ba705221bcf70955b827b97", 441192),
|
// and as far as we know there aren't any variations of this engine.
|
||||||
//AD_ENTRY1s("dw.scn", "ccd72f02183d0e96b6e7d8df9492cda8", 23308),
|
|
||||||
Common::EN_ANY,
|
|
||||||
Common::kPlatformPC,
|
|
||||||
Common::ADGF_DEMO
|
|
||||||
},
|
|
||||||
GID_DW1,
|
|
||||||
0,
|
|
||||||
GF_DEMO,
|
|
||||||
TINSEL_V0,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
{ // This version has *.gra files
|
{ // This version has *.gra files
|
||||||
|
@ -112,49 +101,6 @@ static const TinselGameDescription gameDescriptions[] = {
|
||||||
TINSEL_V1,
|
TINSEL_V1,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ // Multilingual floppy with *.gra files.
|
|
||||||
// Note: It contains no english subtitles.
|
|
||||||
// Reported on our forums.
|
|
||||||
{
|
|
||||||
"dw",
|
|
||||||
"Floppy",
|
|
||||||
{
|
|
||||||
{"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
|
|
||||||
{"french.txt", 0, NULL, -1},
|
|
||||||
{"german.txt", 0, NULL, -1},
|
|
||||||
{"italian.txt", 0, NULL, -1},
|
|
||||||
{"spanish.txt", 0, NULL, -1},
|
|
||||||
{NULL, 0, NULL, 0}
|
|
||||||
},
|
|
||||||
Common::FR_FRA,
|
|
||||||
Common::kPlatformPC,
|
|
||||||
Common::ADGF_DROPLANGUAGE
|
|
||||||
},
|
|
||||||
GID_DW1,
|
|
||||||
0,
|
|
||||||
GF_FLOPPY | GF_USE_4FLAGS,
|
|
||||||
TINSEL_V1,
|
|
||||||
},
|
|
||||||
|
|
||||||
{ // English CD. This version has *.gra files
|
|
||||||
{
|
|
||||||
"dw",
|
|
||||||
"CD",
|
|
||||||
{
|
|
||||||
{"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
|
|
||||||
{"english.smp", 0, NULL, -1},
|
|
||||||
{NULL, 0, NULL, 0}
|
|
||||||
},
|
|
||||||
Common::EN_ANY,
|
|
||||||
Common::kPlatformPC,
|
|
||||||
Common::ADGF_NO_FLAGS
|
|
||||||
},
|
|
||||||
GID_DW1,
|
|
||||||
0,
|
|
||||||
GF_CD,
|
|
||||||
TINSEL_V1,
|
|
||||||
},
|
|
||||||
|
|
||||||
{ // Multilingual CD with english speech and *.gra files.
|
{ // Multilingual CD with english speech and *.gra files.
|
||||||
// Note: It contains no english subtitles.
|
// Note: It contains no english subtitles.
|
||||||
{
|
{
|
||||||
|
@ -245,7 +191,7 @@ static const TinselGameDescription gameDescriptions[] = {
|
||||||
TINSEL_V1,
|
TINSEL_V1,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ // English CD with SCN files
|
{ // English CD v2
|
||||||
{
|
{
|
||||||
"dw",
|
"dw",
|
||||||
"CD",
|
"CD",
|
||||||
|
@ -265,7 +211,7 @@ static const TinselGameDescription gameDescriptions[] = {
|
||||||
},
|
},
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
{ // English Saturn CD. Not (yet?) supported
|
{ // English Saturn CD
|
||||||
{
|
{
|
||||||
"dw",
|
"dw",
|
||||||
"CD",
|
"CD",
|
||||||
|
@ -285,6 +231,25 @@ static const TinselGameDescription gameDescriptions[] = {
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Currently disabled since it isn't really supported
|
||||||
|
#if 0
|
||||||
|
{ // Demo from http://www.adventure-treff.de/specials/dl_demos.php
|
||||||
|
{
|
||||||
|
"dw",
|
||||||
|
"Demo",
|
||||||
|
AD_ENTRY1s("dw.gra", "ce1b57761ba705221bcf70955b827b97", 441192),
|
||||||
|
//AD_ENTRY1s("dw.scn", "ccd72f02183d0e96b6e7d8df9492cda8", 23308),
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformPC,
|
||||||
|
Common::ADGF_DEMO
|
||||||
|
},
|
||||||
|
GID_DW1,
|
||||||
|
0,
|
||||||
|
GF_DEMO,
|
||||||
|
TINSEL_V0,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
|
||||||
{ // German CD re-release "Neon Edition"
|
{ // German CD re-release "Neon Edition"
|
||||||
// Note: This release has ENGLISH.TXT (with german content) instead of GERMAN.TXT
|
// Note: This release has ENGLISH.TXT (with german content) instead of GERMAN.TXT
|
||||||
{
|
{
|
||||||
|
@ -301,6 +266,44 @@ static const TinselGameDescription gameDescriptions[] = {
|
||||||
TINSEL_V1,
|
TINSEL_V1,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ // Europen/Australian Discworld 2 release
|
||||||
|
{
|
||||||
|
"dw2",
|
||||||
|
"CD",
|
||||||
|
{
|
||||||
|
{"dw2.scn", 0, "c6d15ce9720a9d8fef06e6582dcf3f34", 103593},
|
||||||
|
{"english1.smp", 0, NULL, -1},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformPC,
|
||||||
|
Common::ADGF_NO_FLAGS
|
||||||
|
},
|
||||||
|
GID_DW2,
|
||||||
|
0,
|
||||||
|
GF_CD | GF_SCNFILES,
|
||||||
|
TINSEL_V2,
|
||||||
|
},
|
||||||
|
|
||||||
|
{ // German Discworld 2 re-release "Neon Edition"
|
||||||
|
{
|
||||||
|
"dw2",
|
||||||
|
"CD",
|
||||||
|
{
|
||||||
|
{"dw2.scn", 0, "c6d15ce9720a9d8fef06e6582dcf3f34", 103593},
|
||||||
|
{"german1.smp", 0, NULL, -1},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::DE_DEU,
|
||||||
|
Common::kPlatformPC,
|
||||||
|
Common::ADGF_NO_FLAGS
|
||||||
|
},
|
||||||
|
GID_DW2,
|
||||||
|
0,
|
||||||
|
GF_CD | GF_SCNFILES,
|
||||||
|
TINSEL_V2,
|
||||||
|
},
|
||||||
|
|
||||||
{ AD_TABLE_END_MARKER, 0, 0, 0, 0 }
|
{ AD_TABLE_END_MARKER, 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -334,25 +337,23 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const char *getCopyright() const {
|
virtual const char *getCopyright() const {
|
||||||
// FIXME: Bad copyright string.
|
return "Tinsel (C) Psygnosis";
|
||||||
// Should be something like "Tinsel (C) Psygnosis" or so... ???
|
|
||||||
return "Tinsel Engine";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
|
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
|
||||||
|
|
||||||
virtual bool hasFeature(MetaEngineFeature f) const;
|
virtual bool hasFeature(MetaEngineFeature f) const;
|
||||||
virtual SaveStateList listSaves(const char *target) const;
|
virtual SaveStateList listSaves(const char *target) const;
|
||||||
virtual int getMaximumSaveSlot() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool TinselMetaEngine::hasFeature(MetaEngineFeature f) const {
|
bool TinselMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||||
return
|
return (f == kSupportsListSaves);
|
||||||
(f == kSupportsListSaves);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
extern int getList(Common::SaveFileManager *saveFileMan, const Common::String &target);
|
extern int getList(Common::SaveFileManager *saveFileMan, const Common::String &target);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveStateList TinselMetaEngine::listSaves(const char *target) const {
|
SaveStateList TinselMetaEngine::listSaves(const char *target) const {
|
||||||
|
@ -368,8 +369,6 @@ SaveStateList TinselMetaEngine::listSaves(const char *target) const {
|
||||||
return saveList;
|
return saveList;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TinselMetaEngine::getMaximumSaveSlot() const { return 999; }
|
|
||||||
|
|
||||||
bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
|
bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
|
||||||
const Tinsel::TinselGameDescription *gd = (const Tinsel::TinselGameDescription *)desc;
|
const Tinsel::TinselGameDescription *gd = (const Tinsel::TinselGameDescription *)desc;
|
||||||
if (gd) {
|
if (gd) {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,52 +29,67 @@
|
||||||
#define TINSEL_INVENTORY_H
|
#define TINSEL_INVENTORY_H
|
||||||
|
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/events.h" // for KEYEVENT, BUTEVENT
|
#include "tinsel/events.h" // for PLR_EVENT, PLR_EVENT
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
class Serializer;
|
class Serializer;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
INV_OPEN = -1,
|
INV_OPEN = -1, // DW1 only
|
||||||
INV_CONV = 0,
|
INV_CONV = 0,
|
||||||
INV_1 = 1,
|
INV_1 = 1,
|
||||||
INV_2 = 2,
|
INV_2 = 2,
|
||||||
INV_CONF = 3,
|
INV_CONF = 3,
|
||||||
|
INV_MENU = 3, // DW2 constant
|
||||||
|
NUM_INV = 4,
|
||||||
|
|
||||||
NUM_INV = 4
|
// Discworld 2 constants
|
||||||
|
DW2_INV_OPEN = 5,
|
||||||
|
INV_DEFAULT = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
/** structure of each inventory object */
|
/** structure of each inventory object */
|
||||||
struct INV_OBJECT {
|
struct INV_OBJECT {
|
||||||
int32 id; // inventory objects id
|
int32 id; // inventory objects id
|
||||||
SCNHANDLE hFilm; // inventory objects animation film
|
SCNHANDLE hIconFilm; // inventory objects animation film
|
||||||
SCNHANDLE hScript; // inventory objects event handling script
|
SCNHANDLE hScript; // inventory objects event handling script
|
||||||
int32 attribute; // inventory object's attribute
|
int32 attribute; // inventory object's attribute
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// attribute values - not a bit bit field to prevent portability problems
|
||||||
|
#define DROPCODE 0x01
|
||||||
|
#define ONLYINV1 0x02
|
||||||
|
#define ONLYINV2 0x04
|
||||||
|
#define DEFINV1 0x08
|
||||||
|
#define DEFINV2 0x10
|
||||||
|
#define PERMACONV 0x20
|
||||||
|
#define CONVENDITEM 0x40
|
||||||
|
|
||||||
void PopUpInventory(int invno);
|
void PopUpInventory(int invno);
|
||||||
|
|
||||||
enum CONFTYPE {
|
enum CONFTYPE {
|
||||||
SAVE, LOAD, QUIT, OPTION, RESTART, SOUND, CONTROLS, SUBT, TOPWIN
|
MAIN_MENU, SAVE_MENU, LOAD_MENU, QUIT_MENU, RESTART_MENU, SOUND_MENU,
|
||||||
|
CONTROLS_MENU, SUBTITLES_MENU, HOPPER_MENU1, HOPPER_MENU2, TOP_WINDOW
|
||||||
};
|
};
|
||||||
|
|
||||||
void PopUpConf(CONFTYPE type);
|
void OpenMenu(CONFTYPE type);
|
||||||
|
|
||||||
|
|
||||||
void Xmovement(int x);
|
void Xmovement(int x);
|
||||||
void Ymovement(int y);
|
void Ymovement(int y);
|
||||||
|
|
||||||
void ButtonToInventory(BUTEVENT be);
|
void EventToInventory(PLR_EVENT pEvent, const Common::Point &coOrds);
|
||||||
|
void ButtonToInventory(PLR_EVENT be);
|
||||||
void KeyToInventory(KEYEVENT ke);
|
void KeyToInventory(PLR_EVENT ke);
|
||||||
|
|
||||||
|
|
||||||
int WhichItemHeld(void);
|
int WhichItemHeld(void);
|
||||||
|
|
||||||
void HoldItem(int item);
|
void HoldItem(int item, bool bKeepFilm = false);
|
||||||
void DropItem(int item);
|
void DropItem(int item);
|
||||||
void AddToInventory(int invno, int icon, bool hold);
|
void ClearInventory(int invno);
|
||||||
|
void AddToInventory(int invno, int icon, bool hold = false);
|
||||||
bool RemFromInventory(int invno, int icon);
|
bool RemFromInventory(int invno, int icon);
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,25 +104,34 @@ void idec_inv2(SCNHANDLE text, int MaxContents, int MinWidth, int MinHeight,
|
||||||
|
|
||||||
bool InventoryActive(void);
|
bool InventoryActive(void);
|
||||||
|
|
||||||
void AddIconToPermanentDefaultList(int icon);
|
void PermaConvIcon(int icon, bool bEnd = false);
|
||||||
|
|
||||||
void convPos(int bpos);
|
void convPos(int bpos);
|
||||||
void ConvPoly(HPOLYGON hp);
|
void ConvPoly(HPOLYGON hp);
|
||||||
int convIcon(void);
|
int GetIcon(void);
|
||||||
void CloseDownConv(void);
|
void CloseDownConv(void);
|
||||||
void convHide(bool hide);
|
void HideConversation(bool hide);
|
||||||
bool convHid(void);
|
bool ConvIsHidden(void);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
NOOBJECT = -1,
|
||||||
INV_NOICON = -1,
|
INV_NOICON = -1,
|
||||||
INV_CLOSEICON = -2,
|
INV_CLOSEICON = -2,
|
||||||
INV_OPENICON = -3,
|
INV_OPENICON = -3,
|
||||||
INV_HELDNOTIN = -4
|
INV_HELDNOTIN = -4
|
||||||
};
|
};
|
||||||
|
|
||||||
void ConvAction(int index);
|
enum CONV_PARAM {
|
||||||
|
CONV_DEF,
|
||||||
|
CONV_BOTTOM,
|
||||||
|
CONV_END,
|
||||||
|
CONV_TOP
|
||||||
|
};
|
||||||
|
|
||||||
void InventoryIconCursor(void);
|
|
||||||
|
void ConvAction(int index);
|
||||||
|
void SetConvDetails(CONV_PARAM fn, HPOLYGON hPoly, int ano);
|
||||||
|
void InventoryIconCursor(bool bNewItem);
|
||||||
|
|
||||||
void setInvWinParts(SCNHANDLE hf);
|
void setInvWinParts(SCNHANDLE hf);
|
||||||
void setFlagFilms(SCNHANDLE hf);
|
void setFlagFilms(SCNHANDLE hf);
|
||||||
|
@ -122,8 +146,6 @@ bool IsInInventory(int object, int invnum);
|
||||||
|
|
||||||
void KillInventory(void);
|
void KillInventory(void);
|
||||||
|
|
||||||
void invObjectFilm(int object, SCNHANDLE hFilm);
|
|
||||||
|
|
||||||
void syncInvInfo(Serializer &s);
|
void syncInvInfo(Serializer &s);
|
||||||
|
|
||||||
int InvGetLimit(int invno);
|
int InvGetLimit(int invno);
|
||||||
|
@ -134,9 +156,13 @@ void InvSetSize(int invno, int MinWidth, int MinHeight,
|
||||||
int WhichInventoryOpen(void);
|
int WhichInventoryOpen(void);
|
||||||
|
|
||||||
bool IsTopWindow(void);
|
bool IsTopWindow(void);
|
||||||
bool IsConfWindow(void);
|
bool MenuActive(void);
|
||||||
bool IsConvWindow(void);
|
bool IsConvWindow(void);
|
||||||
|
|
||||||
|
void SetObjectFilm(int object, SCNHANDLE hFilm);
|
||||||
|
|
||||||
|
void ObjectEvent(CORO_PARAM, int objId, TINSEL_EVENT event, bool bWait, int myEscape, bool *result = NULL);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif /* TINSEL_INVENTRY_H */
|
#endif /* TINSEL_INVENTRY_H */
|
129
engines/tinsel/drives.cpp
Normal file
129
engines/tinsel/drives.cpp
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* CD/drive handling functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tinsel/drives.h"
|
||||||
|
#include "tinsel/scene.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
#include "tinsel/sched.h"
|
||||||
|
#include "tinsel/strres.h"
|
||||||
|
|
||||||
|
namespace Tinsel {
|
||||||
|
|
||||||
|
static char currentCD = '1';
|
||||||
|
static uint32 cdFlags[] = { fCd1, fCd2, fCd3, fCd4, fCd5, fCd6, fCd7, fCd8 };
|
||||||
|
|
||||||
|
static bool bChangingCD = false;
|
||||||
|
static char nextCD = '\0';
|
||||||
|
|
||||||
|
|
||||||
|
void CdCD(CORO_PARAM) {
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
while (bChangingCD) {
|
||||||
|
if (g_scheduler->getCurrentProcess()) {
|
||||||
|
// FIXME: CdCD gets passed a nullContext in RegisterGlobals() and
|
||||||
|
// PrimeSceneHopper(), because I didn't know how to get a proper
|
||||||
|
// context without converting the whole calling stack to CORO'd
|
||||||
|
// functions. If these functions really get called while a CD
|
||||||
|
// change is requested, this needs to be resolved.
|
||||||
|
if (coroParam == nullContext)
|
||||||
|
error("CdCD needs context!");
|
||||||
|
CORO_SLEEP(1);
|
||||||
|
} else
|
||||||
|
error("No current process in CdCD()!");
|
||||||
|
}
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetCurrentCD(void) {
|
||||||
|
// count from 1
|
||||||
|
return (currentCD - '1' + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCD(int flags) {
|
||||||
|
if (flags & cdFlags[currentCD - '1'])
|
||||||
|
return;
|
||||||
|
|
||||||
|
error("SetCD() problem");
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetCD(int flags) {
|
||||||
|
int i;
|
||||||
|
char cd = '\0';
|
||||||
|
|
||||||
|
if (flags & cdFlags[currentCD - '1'])
|
||||||
|
return GetCurrentCD();
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if (flags & cdFlags[i]) {
|
||||||
|
cd = (char)(i + '1');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(i != 8);
|
||||||
|
|
||||||
|
nextCD = cd;
|
||||||
|
return cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoCdChange(void) {
|
||||||
|
if (bChangingCD) {
|
||||||
|
_vm->_sound->closeSampleStream();
|
||||||
|
_vm->_sound->openSampleFiles();
|
||||||
|
ChangeLanguage(TextLanguage());
|
||||||
|
bChangingCD = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetNextCD(int cdNumber) {
|
||||||
|
assert(cdNumber == 1 || cdNumber == 2);
|
||||||
|
|
||||||
|
nextCD = (char)(cdNumber + '1' - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GotoCD(void) {
|
||||||
|
// WORKAROUND: Somehow, CdDoChange() is called twice... Hopefully, this guard helps
|
||||||
|
if (currentCD == nextCD)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
currentCD = nextCD;
|
||||||
|
|
||||||
|
/* if (bNoCD) {
|
||||||
|
strcpy(cdDirectory, hdDirectory);
|
||||||
|
cdLastBit[3] = currentCD;
|
||||||
|
strcat(cdDirectory, cdLastBit);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
bChangingCD = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Tinsel
|
63
engines/tinsel/drives.h
Normal file
63
engines/tinsel/drives.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* CD/drive handling functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TINSEL_DRIVES_H
|
||||||
|
#define TINSEL_DRIVES_H
|
||||||
|
|
||||||
|
#include "tinsel/dw.h"
|
||||||
|
#include "tinsel/coroutine.h"
|
||||||
|
|
||||||
|
namespace Tinsel {
|
||||||
|
|
||||||
|
// flags2
|
||||||
|
#define fCd1 0x00000001L
|
||||||
|
#define fCd2 0x00000002L
|
||||||
|
#define fCd3 0x00000004L
|
||||||
|
#define fCd4 0x00000008L
|
||||||
|
#define fCd5 0x00000010L
|
||||||
|
#define fCd6 0x00000020L
|
||||||
|
#define fCd7 0x00000040L
|
||||||
|
#define fCd8 0x00000080L
|
||||||
|
|
||||||
|
#define fAllCds (fCd1|fCd2|fCd3|fCd4|fCd5|fCd6|fCd7|fCd8)
|
||||||
|
|
||||||
|
void DoCdChange(void);
|
||||||
|
|
||||||
|
void CdCD(CORO_PARAM);
|
||||||
|
|
||||||
|
int GetCurrentCD(void);
|
||||||
|
|
||||||
|
void SetCD(int flags);
|
||||||
|
|
||||||
|
int GetCD(int flags);
|
||||||
|
|
||||||
|
void SetNextCD(int cdNumber);
|
||||||
|
|
||||||
|
bool GotoCD(void);
|
||||||
|
|
||||||
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
#endif /* TINSEL_DRIVES_H */
|
|
@ -47,9 +47,8 @@ typedef int HPOLYGON;
|
||||||
#define MIDI_FILE "midi.dat" // all MIDI sequences
|
#define MIDI_FILE "midi.dat" // all MIDI sequences
|
||||||
#define INDEX_FILENAME "index" // name of index file
|
#define INDEX_FILENAME "index" // name of index file
|
||||||
|
|
||||||
#define SCNHANDLE_SHIFT 23 // amount to shift scene handles by
|
|
||||||
#define NO_SCNHANDLES 300 // number of memory handles for scenes
|
#define NO_SCNHANDLES 300 // number of memory handles for scenes
|
||||||
#define MASTER_SCNHANDLE (0 << SCNHANDLE_SHIFT) // master scene memory handle
|
#define MASTER_SCNHANDLE 0 // master scene memory handle
|
||||||
|
|
||||||
// the minimum value a integer number can have
|
// the minimum value a integer number can have
|
||||||
#define MIN_INT (1 << (8*sizeof(int) - 1))
|
#define MIN_INT (1 << (8*sizeof(int) - 1))
|
||||||
|
@ -70,8 +69,7 @@ typedef int HPOLYGON;
|
||||||
#define FIELD_WORLD 0
|
#define FIELD_WORLD 0
|
||||||
#define FIELD_STATUS 1
|
#define FIELD_STATUS 1
|
||||||
|
|
||||||
|
#define ZSHIFT 10
|
||||||
|
|
||||||
|
|
||||||
// We don't set the Z position for print and talk text
|
// We don't set the Z position for print and talk text
|
||||||
// i.e. it gets a Z position of 0
|
// i.e. it gets a Z position of 0
|
||||||
|
@ -101,6 +99,7 @@ typedef int HPOLYGON;
|
||||||
#define MAX_MOVERS 6 // Moving actors using path system
|
#define MAX_MOVERS 6 // Moving actors using path system
|
||||||
#define MAX_SAVED_ACTORS 32 // Saved 'Normal' actors
|
#define MAX_SAVED_ACTORS 32 // Saved 'Normal' actors
|
||||||
#define MAX_SAVED_ALIVES 512 // Saves actors'lives
|
#define MAX_SAVED_ALIVES 512 // Saves actors'lives
|
||||||
|
#define MAX_SAVED_ACTOR_Z 512 // Saves actors' Z-ness
|
||||||
|
|
||||||
// Legal non-existant entrance number for LoadScene()
|
// Legal non-existant entrance number for LoadScene()
|
||||||
#define NO_ENTRY_NUM (-3458) // Magic unlikely number
|
#define NO_ENTRY_NUM (-3458) // Magic unlikely number
|
||||||
|
@ -110,13 +109,19 @@ typedef int HPOLYGON;
|
||||||
|
|
||||||
// Language for the resource strings
|
// Language for the resource strings
|
||||||
enum LANGUAGE {
|
enum LANGUAGE {
|
||||||
TXT_ENGLISH,
|
TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN, TXT_ITALIAN, TXT_SPANISH,
|
||||||
TXT_FRENCH,
|
TXT_HEBREW, TXT_HUNGARIAN, TXT_JAPANESE, TXT_US,
|
||||||
TXT_GERMAN,
|
NUM_LANGUAGES
|
||||||
TXT_ITALIAN,
|
|
||||||
TXT_SPANISH
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX_READ_RETRIES 5
|
||||||
|
|
||||||
|
// Definitions used for error messages
|
||||||
|
#define FILE_IS_CORRUPT "File %s is corrupt"
|
||||||
|
#define FILE_READ_ERROR "Error reading file %s"
|
||||||
|
#define CANNOT_FIND_FILE "Cannot find file %s"
|
||||||
|
#define NO_MEM "Cannot allocate memory for %s!"
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif // TINSEL_DW_H
|
#endif // TINSEL_DW_H
|
||||||
|
|
|
@ -41,13 +41,14 @@
|
||||||
#include "tinsel/polygons.h"
|
#include "tinsel/polygons.h"
|
||||||
#include "tinsel/rince.h"
|
#include "tinsel/rince.h"
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
struct EP_INIT {
|
struct EP_INIT {
|
||||||
HPOLYGON hEpoly;
|
HPOLYGON hEpoly;
|
||||||
PMACTOR pActor;
|
PMOVER pMover;
|
||||||
int index;
|
int index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,24 +62,32 @@ static void EffectProcess(CORO_PARAM, const void *param) {
|
||||||
CORO_BEGIN_CONTEXT;
|
CORO_BEGIN_CONTEXT;
|
||||||
CORO_END_CONTEXT(_ctx);
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
EP_INIT *to = (EP_INIT *)param; // get the stuff copied to process when it was created
|
const EP_INIT *to = (const EP_INIT *)param; // get the stuff copied to process when it was created
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
int x, y; // Lead actor position
|
int x, y; // Lead actor position
|
||||||
|
|
||||||
// Run effect poly enter script
|
// Run effect poly enter script
|
||||||
effRunPolyTinselCode(to->hEpoly, ENTER, to->pActor->actorID);
|
if (TinselV2)
|
||||||
|
CORO_INVOKE_ARGS(PolygonEvent, (CORO_SUBCTX, to->hEpoly, WALKIN,
|
||||||
|
GetMoverId(to->pMover), false, 0));
|
||||||
|
else
|
||||||
|
effRunPolyTinselCode(to->hEpoly, WALKIN, to->pMover->actorID);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
CORO_SLEEP(1);
|
CORO_SLEEP(1);
|
||||||
GetMActorPosition(to->pActor, &x, &y);
|
GetMoverPosition(to->pMover, &x, &y);
|
||||||
} while (InPolygon(x, y, EFFECT) == to->hEpoly);
|
} while (InPolygon(x, y, EFFECT) == to->hEpoly);
|
||||||
|
|
||||||
// Run effect poly leave script
|
// Run effect poly leave script
|
||||||
effRunPolyTinselCode(to->hEpoly, LEAVE, to->pActor->actorID);
|
if (TinselV2)
|
||||||
|
CORO_INVOKE_ARGS(PolygonEvent, (CORO_SUBCTX, to->hEpoly, WALKOUT,
|
||||||
|
GetMoverId(to->pMover), false, 0));
|
||||||
|
else
|
||||||
|
effRunPolyTinselCode(to->hEpoly, WALKOUT, to->pMover->actorID);
|
||||||
|
|
||||||
SetMAinEffectPoly(to->index, false);
|
SetMoverInEffect(to->index, false);
|
||||||
|
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +97,7 @@ static void EffectProcess(CORO_PARAM, const void *param) {
|
||||||
* it has just entered one. If it has, a process is started up to run
|
* it has just entered one. If it has, a process is started up to run
|
||||||
* the polygon's Glitter code.
|
* the polygon's Glitter code.
|
||||||
*/
|
*/
|
||||||
static void FettleEffectPolys(int x, int y, int index, PMACTOR pActor) {
|
static void FettleEffectPolys(int x, int y, int index, PMOVER pActor) {
|
||||||
HPOLYGON hPoly;
|
HPOLYGON hPoly;
|
||||||
EP_INIT epi;
|
EP_INIT epi;
|
||||||
|
|
||||||
|
@ -97,10 +106,10 @@ static void FettleEffectPolys(int x, int y, int index, PMACTOR pActor) {
|
||||||
hPoly = InPolygon(x, y, EFFECT);
|
hPoly = InPolygon(x, y, EFFECT);
|
||||||
if (hPoly != NOPOLY) {
|
if (hPoly != NOPOLY) {
|
||||||
//Just entered effect polygon
|
//Just entered effect polygon
|
||||||
SetMAinEffectPoly(index, true);
|
SetMoverInEffect(index, true);
|
||||||
|
|
||||||
epi.hEpoly = hPoly;
|
epi.hEpoly = hPoly;
|
||||||
epi.pActor = pActor;
|
epi.pMover = pActor;
|
||||||
epi.index = index;
|
epi.index = index;
|
||||||
g_scheduler->createProcess(PID_TCODE, EffectProcess, &epi, sizeof(epi));
|
g_scheduler->createProcess(PID_TCODE, EffectProcess, &epi, sizeof(epi));
|
||||||
}
|
}
|
||||||
|
@ -118,10 +127,10 @@ void EffectPolyProcess(CORO_PARAM, const void *param) {
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
while (1) {
|
while (1) {
|
||||||
for (int i = 0; i < MAX_MOVERS; i++) {
|
for (int i = 0; i < MAX_MOVERS; i++) {
|
||||||
PMACTOR pActor = GetLiveMover(i);
|
PMOVER pActor = GetLiveMover(i);
|
||||||
if (pActor != NULL) {
|
if (pActor != NULL) {
|
||||||
int x, y;
|
int x, y;
|
||||||
GetMActorPosition(pActor, &x, &y);
|
GetMoverPosition(pActor, &x, &y);
|
||||||
FettleEffectPolys(x, y, i, pActor);
|
FettleEffectPolys(x, y, i, pActor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,14 +26,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tinsel/actors.h"
|
#include "tinsel/actors.h"
|
||||||
|
#include "tinsel/background.h"
|
||||||
#include "tinsel/config.h"
|
#include "tinsel/config.h"
|
||||||
|
#include "tinsel/coroutine.h"
|
||||||
#include "tinsel/cursor.h"
|
#include "tinsel/cursor.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/events.h"
|
#include "tinsel/events.h"
|
||||||
#include "tinsel/handle.h" // For LockMem()
|
#include "tinsel/handle.h" // For LockMem()
|
||||||
#include "tinsel/inventory.h"
|
#include "tinsel/dialogs.h"
|
||||||
#include "tinsel/move.h" // For walking lead actor
|
#include "tinsel/move.h" // For walking lead actor
|
||||||
#include "tinsel/pcode.h" // For Interpret()
|
#include "tinsel/pcode.h" // For Interpret()
|
||||||
|
#include "tinsel/pdisplay.h"
|
||||||
#include "tinsel/pid.h"
|
#include "tinsel/pid.h"
|
||||||
#include "tinsel/polygons.h"
|
#include "tinsel/polygons.h"
|
||||||
#include "tinsel/rince.h" // For walking lead actor
|
#include "tinsel/rince.h" // For walking lead actor
|
||||||
|
@ -41,6 +44,7 @@
|
||||||
#include "tinsel/scroll.h" // For DontScrollCursor()
|
#include "tinsel/scroll.h" // For DontScrollCursor()
|
||||||
#include "tinsel/timers.h" // DwGetCurrentTime()
|
#include "tinsel/timers.h" // DwGetCurrentTime()
|
||||||
#include "tinsel/tinlib.h" // For control()
|
#include "tinsel/tinlib.h" // For control()
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
#include "tinsel/token.h"
|
#include "tinsel/token.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
@ -51,22 +55,25 @@ namespace Tinsel {
|
||||||
extern int GetTaggedActor(void);
|
extern int GetTaggedActor(void);
|
||||||
extern HPOLYGON GetTaggedPoly(void);
|
extern HPOLYGON GetTaggedPoly(void);
|
||||||
|
|
||||||
|
|
||||||
//----------------- EXTERNAL GLOBAL DATA ---------------------
|
//----------------- EXTERNAL GLOBAL DATA ---------------------
|
||||||
|
|
||||||
extern bool bEnableF1;
|
extern bool bEnableMenu;
|
||||||
|
|
||||||
|
|
||||||
//----------------- LOCAL GLOBAL DATA --------------------
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
static int userEvents = 0; // Whenever a button or a key comes in
|
|
||||||
static uint32 lastUserEvent = 0; // Time it hapenned
|
static uint32 lastUserEvent = 0; // Time it hapenned
|
||||||
static int butEvents = 0; // Single or double, left or right. Or escape key.
|
static int leftEvents = 0; // Single or double, left or right. Or escape key.
|
||||||
static int escEvents = 0; // Escape key
|
static int escEvents = 1; // Escape key
|
||||||
|
static int userEvents = 0; // Whenever a button or a key comes in
|
||||||
|
|
||||||
static int eCount = 0;
|
static int eCount = 0;
|
||||||
|
|
||||||
|
static int controlState;
|
||||||
|
static bool bStartOff;
|
||||||
|
|
||||||
|
static int controlX, controlY;
|
||||||
|
static bool bProvNotProcessed = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets called before each schedule, only 1 user action per schedule
|
* Gets called before each schedule, only 1 user action per schedule
|
||||||
* is allowed.
|
* is allowed.
|
||||||
|
@ -87,12 +94,12 @@ void IncUserEvents(void) {
|
||||||
* If this is a double click, the process from the waiting single click
|
* If this is a double click, the process from the waiting single click
|
||||||
* gets killed.
|
* gets killed.
|
||||||
*/
|
*/
|
||||||
void AllowDclick(CORO_PARAM, BUTEVENT be) {
|
void AllowDclick(CORO_PARAM, PLR_EVENT be) {
|
||||||
CORO_BEGIN_CONTEXT;
|
CORO_BEGIN_CONTEXT;
|
||||||
CORO_END_CONTEXT(_ctx);
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
if (be == BE_SLEFT) {
|
if (be == PLR_SLEFT) {
|
||||||
GetToken(TOKEN_LEFT_BUT);
|
GetToken(TOKEN_LEFT_BUT);
|
||||||
CORO_SLEEP(dclickSpeed+1);
|
CORO_SLEEP(dclickSpeed+1);
|
||||||
FreeToken(TOKEN_LEFT_BUT);
|
FreeToken(TOKEN_LEFT_BUT);
|
||||||
|
@ -103,94 +110,120 @@ void AllowDclick(CORO_PARAM, BUTEVENT be) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} else if (be == BE_DLEFT) {
|
} else if (be == PLR_DLEFT) {
|
||||||
GetToken(TOKEN_LEFT_BUT);
|
GetToken(TOKEN_LEFT_BUT);
|
||||||
FreeToken(TOKEN_LEFT_BUT);
|
FreeToken(TOKEN_LEFT_BUT);
|
||||||
}
|
}
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-enables user control
|
||||||
|
*/
|
||||||
|
void ControlOn(void) {
|
||||||
|
if (!TinselV2) {
|
||||||
|
Control(CONTROL_ON);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bEnableMenu = false;
|
||||||
|
|
||||||
|
if (controlState == CONTROL_OFF) {
|
||||||
|
// Control is on
|
||||||
|
controlState = CONTROL_ON;
|
||||||
|
|
||||||
|
// Restore cursor to where it was
|
||||||
|
if (bStartOff == true)
|
||||||
|
bStartOff = false;
|
||||||
|
else
|
||||||
|
SetCursorXY(controlX, controlY);
|
||||||
|
|
||||||
|
// Re-instate cursor
|
||||||
|
UnHideCursor();
|
||||||
|
|
||||||
|
// Turn tags back on
|
||||||
|
if (!InventoryActive())
|
||||||
|
EnableTags();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes control from the user
|
||||||
|
*/
|
||||||
|
void ControlOff(void) {
|
||||||
|
if (!TinselV2) {
|
||||||
|
Control(CONTROL_ON);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bEnableMenu = false;
|
||||||
|
|
||||||
|
if (controlState == CONTROL_ON) {
|
||||||
|
// Control is off
|
||||||
|
controlState = CONTROL_OFF;
|
||||||
|
|
||||||
|
// Store cursor position
|
||||||
|
GetCursorXY(&controlX, &controlY, true);
|
||||||
|
|
||||||
|
// Blank out cursor
|
||||||
|
DwHideCursor();
|
||||||
|
|
||||||
|
// Switch off tags
|
||||||
|
DisableTags();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent tags and cursor re-appearing
|
||||||
|
*/
|
||||||
|
void ControlStartOff(void) {
|
||||||
|
if (!TinselV2) {
|
||||||
|
Control(CONTROL_STARTOFF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bEnableMenu = false;
|
||||||
|
|
||||||
|
// Control is off
|
||||||
|
controlState = CONTROL_OFF;
|
||||||
|
|
||||||
|
// Blank out cursor
|
||||||
|
DwHideCursor();
|
||||||
|
|
||||||
|
// Switch off tags
|
||||||
|
DisableTags();
|
||||||
|
|
||||||
|
bStartOff = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take control from player, if the player has it.
|
* Take control from player, if the player has it.
|
||||||
* Return TRUE if control taken, FALSE if not.
|
* Return TRUE if control taken, FALSE if not.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool GetControl(int param) {
|
bool GetControl(int param) {
|
||||||
if (TestToken(TOKEN_CONTROL)) {
|
if (TinselV2)
|
||||||
control(param);
|
return GetControl();
|
||||||
|
|
||||||
|
else if (TestToken(TOKEN_CONTROL)) {
|
||||||
|
Control(param);
|
||||||
return true;
|
return true;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TP_INIT {
|
bool GetControl(void) {
|
||||||
HPOLYGON hPoly; // Polygon
|
if (controlState == CONTROL_ON) {
|
||||||
USER_EVENT event; // Trigerring event
|
ControlOff();
|
||||||
BUTEVENT bev; // To allow for double clicks
|
return true;
|
||||||
bool take_control; // Set if control should be taken
|
} else
|
||||||
// while code is running.
|
return false;
|
||||||
int actor;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs glitter code associated with a polygon.
|
|
||||||
*/
|
|
||||||
static void PolyTinselProcess(CORO_PARAM, const void *param) {
|
|
||||||
// COROUTINE
|
|
||||||
CORO_BEGIN_CONTEXT;
|
|
||||||
INT_CONTEXT *pic;
|
|
||||||
bool took_control; // Set if this function takes control
|
|
||||||
CORO_END_CONTEXT(_ctx);
|
|
||||||
|
|
||||||
TP_INIT *to = (TP_INIT *)param; // get the stuff copied to process when it was created
|
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
|
||||||
|
|
||||||
CORO_INVOKE_1(AllowDclick, to->bev); // May kill us if single click
|
|
||||||
|
|
||||||
// Control may have gone off during AllowDclick()
|
|
||||||
if (!TestToken(TOKEN_CONTROL)
|
|
||||||
&& (to->event == WALKTO || to->event == ACTION || to->event == LOOK))
|
|
||||||
CORO_KILL_SELF();
|
|
||||||
|
|
||||||
// Take control, if requested
|
|
||||||
if (to->take_control)
|
|
||||||
_ctx->took_control = GetControl(CONTROL_OFF);
|
|
||||||
else
|
|
||||||
_ctx->took_control = false;
|
|
||||||
|
|
||||||
// Hide conversation if appropriate
|
|
||||||
if (to->event == CONVERSE)
|
|
||||||
convHide(true);
|
|
||||||
|
|
||||||
// Run the code
|
|
||||||
_ctx->pic = InitInterpretContext(GS_POLYGON, getPolyScript(to->hPoly), to->event, to->hPoly, to->actor, NULL);
|
|
||||||
CORO_INVOKE_1(Interpret, _ctx->pic);
|
|
||||||
|
|
||||||
// Free control if we took it
|
|
||||||
if (_ctx->took_control)
|
|
||||||
control(CONTROL_ON);
|
|
||||||
|
|
||||||
// Restore conv window if applicable
|
|
||||||
if (to->event == CONVERSE)
|
|
||||||
convHide(false);
|
|
||||||
|
|
||||||
CORO_END_CODE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool ControlIsOn(void) {
|
||||||
* Runs glitter code associated with a polygon.
|
if (TinselV2)
|
||||||
*/
|
return (controlState == CONTROL_ON);
|
||||||
void RunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, BUTEVENT be, bool tc) {
|
|
||||||
TP_INIT to = { hPoly, event, be, tc, 0 };
|
|
||||||
|
|
||||||
g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
|
return TestToken(TOKEN_CONTROL);
|
||||||
}
|
|
||||||
|
|
||||||
void effRunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, int actor) {
|
|
||||||
TP_INIT to = { hPoly, event, BE_NONE, false, actor };
|
|
||||||
|
|
||||||
g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
@ -206,22 +239,33 @@ struct WP_INIT {
|
||||||
static void WalkProcess(CORO_PARAM, const void *param) {
|
static void WalkProcess(CORO_PARAM, const void *param) {
|
||||||
// COROUTINE
|
// COROUTINE
|
||||||
CORO_BEGIN_CONTEXT;
|
CORO_BEGIN_CONTEXT;
|
||||||
PMACTOR pActor;
|
PMOVER pMover;
|
||||||
|
int thisWalk;
|
||||||
CORO_END_CONTEXT(_ctx);
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
WP_INIT *to = (WP_INIT *)param; // get the co-ordinates - copied to process when it was created
|
const WP_INIT *to = (const WP_INIT *)param; // get the co-ordinates - copied to process when it was created
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
_ctx->pActor = GetMover(LEAD_ACTOR);
|
_ctx->pMover = GetMover(LEAD_ACTOR);
|
||||||
if (_ctx->pActor->MActorState == NORM_MACTOR) {
|
|
||||||
assert(_ctx->pActor->hCpath != NOPOLY); // Lead actor is not in a path
|
|
||||||
|
|
||||||
GetToken(TOKEN_LEAD);
|
if (TinselV2 && MoverIs(_ctx->pMover) && !MoverIsSWalking(_ctx->pMover)) {
|
||||||
SetActorDest(_ctx->pActor, to->x, to->y, false, 0);
|
assert(_ctx->pMover->hCpath != NOPOLY); // Lead actor is not in a path
|
||||||
|
|
||||||
|
_ctx->thisWalk = SetActorDest(_ctx->pMover, to->x, to->y, false, 0);
|
||||||
DontScrollCursor();
|
DontScrollCursor();
|
||||||
|
|
||||||
while (MAmoving(_ctx->pActor))
|
while (MoverMoving(_ctx->pMover) && (_ctx->thisWalk == GetWalkNumber(_ctx->pMover)))
|
||||||
|
CORO_SLEEP(1);
|
||||||
|
|
||||||
|
} else if (!TinselV2 && _ctx->pMover->bActive) {
|
||||||
|
assert(_ctx->pMover->hCpath != NOPOLY); // Lead actor is not in a path
|
||||||
|
|
||||||
|
GetToken(TOKEN_LEAD);
|
||||||
|
SetActorDest(_ctx->pMover, to->x, to->y, false, 0);
|
||||||
|
DontScrollCursor();
|
||||||
|
|
||||||
|
while (MoverMoving(_ctx->pMover))
|
||||||
CORO_SLEEP(1);
|
CORO_SLEEP(1);
|
||||||
|
|
||||||
FreeToken(TOKEN_LEAD);
|
FreeToken(TOKEN_LEAD);
|
||||||
|
@ -230,7 +274,7 @@ static void WalkProcess(CORO_PARAM, const void *param) {
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void walkto(int x, int y) {
|
void WalkTo(int x, int y) {
|
||||||
WP_INIT to = { x, y };
|
WP_INIT to = { x, y };
|
||||||
|
|
||||||
g_scheduler->createProcess(PID_TCODE, WalkProcess, &to, sizeof(to));
|
g_scheduler->createProcess(PID_TCODE, WalkProcess, &to, sizeof(to));
|
||||||
|
@ -240,7 +284,7 @@ void walkto(int x, int y) {
|
||||||
* Run appropriate actor or polygon glitter code.
|
* Run appropriate actor or polygon glitter code.
|
||||||
* If none, and it's a WALKTO event, do a walk.
|
* If none, and it's a WALKTO event, do a walk.
|
||||||
*/
|
*/
|
||||||
static void User_Event(USER_EVENT uEvent, BUTEVENT be) {
|
static void ProcessUserEvent(TINSEL_EVENT uEvent, const Common::Point &coOrds, PLR_EVENT be = PLR_NOEVENT) {
|
||||||
int actor;
|
int actor;
|
||||||
int aniX, aniY;
|
int aniX, aniY;
|
||||||
HPOLYGON hPoly;
|
HPOLYGON hPoly;
|
||||||
|
@ -249,19 +293,34 @@ static void User_Event(USER_EVENT uEvent, BUTEVENT be) {
|
||||||
if (++eCount != 1)
|
if (++eCount != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((actor = GetTaggedActor()) != 0)
|
if ((actor = GetTaggedActor()) != 0) {
|
||||||
actorEvent(actor, uEvent, be);
|
// Event for a tagged actor
|
||||||
else if ((hPoly = GetTaggedPoly()) != NOPOLY)
|
if (TinselV2)
|
||||||
|
ActorEvent(nullContext, actor, uEvent, false, 0);
|
||||||
|
else
|
||||||
|
ActorEvent(actor, uEvent, be);
|
||||||
|
} else if ((hPoly = GetTaggedPoly()) != NOPOLY) {
|
||||||
|
// Event for active tagged polygon
|
||||||
|
if (!TinselV2)
|
||||||
RunPolyTinselCode(hPoly, uEvent, be, false);
|
RunPolyTinselCode(hPoly, uEvent, be, false);
|
||||||
else {
|
else if (uEvent != PROV_WALKTO)
|
||||||
|
PolygonEvent(nullContext, hPoly, uEvent, 0, false, 0);
|
||||||
|
|
||||||
|
} else {
|
||||||
GetCursorXY(&aniX, &aniY, true);
|
GetCursorXY(&aniX, &aniY, true);
|
||||||
|
|
||||||
// There could be a poly involved which has no tag.
|
// There could be a poly involved which has no tag.
|
||||||
if ((hPoly = InPolygon(aniX, aniY, TAG)) != NOPOLY
|
if ((hPoly = InPolygon(aniX, aniY, TAG)) != NOPOLY ||
|
||||||
|| (hPoly = InPolygon(aniX, aniY, EXIT)) != NOPOLY) {
|
(!TinselV2 && ((hPoly = InPolygon(aniX, aniY, EXIT)) != NOPOLY))) {
|
||||||
|
if (TinselV2 && (uEvent != PROV_WALKTO))
|
||||||
|
PolygonEvent(nullContext, hPoly, uEvent, 0, false, 0);
|
||||||
|
else if (!TinselV2)
|
||||||
RunPolyTinselCode(hPoly, uEvent, be, false);
|
RunPolyTinselCode(hPoly, uEvent, be, false);
|
||||||
} else if (uEvent == WALKTO)
|
} else if ((uEvent == PROV_WALKTO) || (uEvent == WALKTO)) {
|
||||||
walkto(aniX, aniY);
|
if (TinselV2)
|
||||||
|
ProcessedProvisional();
|
||||||
|
WalkTo(aniX, aniY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,137 +328,155 @@ static void User_Event(USER_EVENT uEvent, BUTEVENT be) {
|
||||||
/**
|
/**
|
||||||
* ProcessButEvent
|
* ProcessButEvent
|
||||||
*/
|
*/
|
||||||
void ProcessButEvent(BUTEVENT be) {
|
void ProcessButEvent(PLR_EVENT be) {
|
||||||
IncUserEvents();
|
|
||||||
|
|
||||||
if (bSwapButtons) {
|
if (bSwapButtons) {
|
||||||
switch (be) {
|
switch (be) {
|
||||||
case BE_SLEFT:
|
case PLR_SLEFT:
|
||||||
be = BE_SRIGHT;
|
be = PLR_SRIGHT;
|
||||||
break;
|
break;
|
||||||
case BE_DLEFT:
|
case PLR_DLEFT:
|
||||||
be = BE_DRIGHT;
|
be = PLR_DRIGHT;
|
||||||
break;
|
break;
|
||||||
case BE_SRIGHT:
|
case PLR_SRIGHT:
|
||||||
be = BE_SLEFT;
|
be = PLR_SLEFT;
|
||||||
break;
|
break;
|
||||||
case BE_DRIGHT:
|
case PLR_DRIGHT:
|
||||||
be = BE_DLEFT;
|
be = PLR_DLEFT;
|
||||||
break;
|
break;
|
||||||
case BE_LDSTART:
|
case PLR_DRAG1_START:
|
||||||
be = BE_RDSTART;
|
be = PLR_DRAG2_START;
|
||||||
break;
|
break;
|
||||||
case BE_LDEND:
|
case PLR_DRAG1_END:
|
||||||
be = BE_RDEND;
|
be = PLR_DRAG2_END;
|
||||||
break;
|
break;
|
||||||
case BE_RDSTART:
|
case PLR_DRAG2_START:
|
||||||
be = BE_LDSTART;
|
be = PLR_DRAG1_START;
|
||||||
break;
|
break;
|
||||||
case BE_RDEND:
|
case PLR_DRAG2_END:
|
||||||
be = BE_LDEND;
|
be = PLR_DRAG1_END;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (be == BE_SLEFT || be == BE_DLEFT || be == BE_SRIGHT || be == BE_DRIGHT)
|
PlayerEvent(be, _vm->getMousePosition());
|
||||||
if (be == BE_SLEFT || be == BE_SRIGHT)
|
|
||||||
butEvents++;
|
|
||||||
|
|
||||||
if (!TestToken(TOKEN_CONTROL) && be != BE_LDEND)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (InventoryActive()) {
|
|
||||||
ButtonToInventory(be);
|
|
||||||
} else {
|
|
||||||
switch (be) {
|
|
||||||
case BE_SLEFT:
|
|
||||||
User_Event(WALKTO, BE_SLEFT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BE_DLEFT:
|
|
||||||
User_Event(ACTION, BE_DLEFT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BE_SRIGHT:
|
|
||||||
User_Event(LOOK, BE_SRIGHT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProcessKeyEvent
|
* ProcessKeyEvent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ProcessKeyEvent(KEYEVENT ke) {
|
void ProcessKeyEvent(PLR_EVENT ke) {
|
||||||
|
// Pass the keyboard event to the player event handler
|
||||||
|
int xp, yp;
|
||||||
|
GetCursorXYNoWait(&xp, &yp, true);
|
||||||
|
const Common::Point mousePos(xp, yp);
|
||||||
|
|
||||||
|
PlayerEvent(ke, mousePos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define REAL_ACTION_CHECK if (TinselV2) { \
|
||||||
|
if (DwGetCurrentTime() - lastRealAction < 4) return; \
|
||||||
|
lastRealAction = DwGetCurrentTime(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main interface point for specifying player atcions
|
||||||
|
*/
|
||||||
|
void PlayerEvent(PLR_EVENT pEvent, const Common::Point &coOrds) {
|
||||||
|
// Logging of player actions
|
||||||
|
const char *actionList[] = {
|
||||||
|
"PLR_PROV_WALKTO", "PLR_WALKTO", "PLR_LOOK", "PLR_ACTION", "PLR_ESCAPE",
|
||||||
|
"PLR_MENU", "PLR_QUIT", "PLR_PGUP", "PLR_PGDN", "PLR_HOME", "PLR_END",
|
||||||
|
"PLR_DRAG1_START", "PLR_DRAG1_END", "PLR_DRAG2_START", "PLR_DRAG2_END",
|
||||||
|
"PLR_JUMP", "PLR_NOEVENT"};
|
||||||
|
debugC(DEBUG_BASIC, kTinselDebugActions, "%s - (%d,%d)",
|
||||||
|
actionList[pEvent], coOrds.x, coOrds.y);
|
||||||
|
static uint32 lastRealAction = 0;
|
||||||
|
|
||||||
// This stuff to allow F1 key during startup.
|
// This stuff to allow F1 key during startup.
|
||||||
if (bEnableF1 && ke == OPTION_KEY)
|
if (bEnableMenu && pEvent == PLR_MENU)
|
||||||
control(CONTROL_ON);
|
Control(CONTROL_ON);
|
||||||
else
|
else
|
||||||
IncUserEvents();
|
IncUserEvents();
|
||||||
|
|
||||||
if (ke == ESC_KEY) {
|
if (pEvent == PLR_ESCAPE) {
|
||||||
escEvents++;
|
++escEvents;
|
||||||
butEvents++; // Yes, I do mean this
|
++leftEvents; // Yes, I do mean this
|
||||||
|
} else if ((pEvent == PLR_PROV_WALKTO)
|
||||||
|
|| (pEvent == PLR_WALKTO)
|
||||||
|
|| (pEvent == PLR_LOOK)
|
||||||
|
|| (pEvent == PLR_ACTION)) {
|
||||||
|
++leftEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This comparison is weird - I added (BUTEVENT) cast for now to suppress warning
|
// Only allow events if player control is on
|
||||||
if (!TestToken(TOKEN_CONTROL) && (BUTEVENT)ke != BE_LDEND)
|
if (!ControlIsOn() && (pEvent != PLR_DRAG1_END))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (ke) {
|
if (TinselV2 && InventoryActive()) {
|
||||||
case QUIT_KEY:
|
int x, y;
|
||||||
PopUpConf(QUIT);
|
PlayfieldGetPos(FIELD_WORLD, &x, &y);
|
||||||
|
EventToInventory(pEvent, Common::Point(coOrds.x - x, coOrds.y - y));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pEvent) {
|
||||||
|
case PLR_QUIT:
|
||||||
|
OpenMenu(QUIT_MENU);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPTION_KEY:
|
case PLR_MENU:
|
||||||
PopUpConf(OPTION);
|
OpenMenu(MAIN_MENU);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAVE_KEY:
|
case PLR_JUMP:
|
||||||
PopUpConf(SAVE);
|
OpenMenu(HOPPER_MENU1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOAD_KEY:
|
case PLR_SAVE:
|
||||||
PopUpConf(LOAD);
|
OpenMenu(SAVE_MENU);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WALKTO_KEY:
|
case PLR_LOAD:
|
||||||
if (InventoryActive())
|
OpenMenu(LOAD_MENU);
|
||||||
ButtonToInventory(BE_SLEFT);
|
break;
|
||||||
|
|
||||||
|
case PLR_PROV_WALKTO: // Provisional WALKTO !
|
||||||
|
ProcessUserEvent(PROV_WALKTO, coOrds);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLR_WALKTO:
|
||||||
|
REAL_ACTION_CHECK;
|
||||||
|
|
||||||
|
if (TinselV2 || !InventoryActive())
|
||||||
|
ProcessUserEvent(WALKTO, coOrds, PLR_SLEFT);
|
||||||
else
|
else
|
||||||
User_Event(WALKTO, BE_NONE);
|
EventToInventory(PLR_SLEFT, coOrds);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_KEY:
|
case PLR_ACTION:
|
||||||
if (InventoryActive())
|
REAL_ACTION_CHECK;
|
||||||
ButtonToInventory(BE_DLEFT);
|
|
||||||
|
if (TinselV2 || !InventoryActive())
|
||||||
|
ProcessUserEvent(ACTION, coOrds, PLR_DLEFT);
|
||||||
else
|
else
|
||||||
User_Event(ACTION, BE_NONE);
|
EventToInventory(PLR_DLEFT, coOrds);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOK_KEY:
|
case PLR_LOOK:
|
||||||
if (InventoryActive())
|
REAL_ACTION_CHECK;
|
||||||
ButtonToInventory(BE_SRIGHT);
|
|
||||||
|
if (TinselV2 || !InventoryActive())
|
||||||
|
ProcessUserEvent(LOOK, coOrds, PLR_SRIGHT);
|
||||||
else
|
else
|
||||||
User_Event(LOOK, BE_NONE);
|
EventToInventory(PLR_SRIGHT, coOrds);
|
||||||
break;
|
|
||||||
|
|
||||||
case ESC_KEY:
|
|
||||||
case PGUP_KEY:
|
|
||||||
case PGDN_KEY:
|
|
||||||
case HOME_KEY:
|
|
||||||
case END_KEY:
|
|
||||||
if (InventoryActive())
|
|
||||||
KeyToInventory(ke);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (InventoryActive())
|
||||||
|
EventToInventory(pEvent, coOrds);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,7 +484,6 @@ void ProcessKeyEvent(KEYEVENT ke) {
|
||||||
/**
|
/**
|
||||||
* For ESCapable Glitter sequences
|
* For ESCapable Glitter sequences
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int GetEscEvents(void) {
|
int GetEscEvents(void) {
|
||||||
return escEvents;
|
return escEvents;
|
||||||
}
|
}
|
||||||
|
@ -415,15 +491,21 @@ int GetEscEvents(void) {
|
||||||
/**
|
/**
|
||||||
* For cutting short talk()s etc.
|
* For cutting short talk()s etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int GetLeftEvents(void) {
|
int GetLeftEvents(void) {
|
||||||
return butEvents;
|
return leftEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LeftEventChange(int myleftEvent) {
|
||||||
|
if (leftEvents != myleftEvent) {
|
||||||
|
ProcessedProvisional();
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For waitkey() Glitter function
|
* For waitkey() Glitter function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int getUserEvents(void) {
|
int getUserEvents(void) {
|
||||||
return userEvents;
|
return userEvents;
|
||||||
}
|
}
|
||||||
|
@ -436,4 +518,154 @@ void resetUserEventTime(void) {
|
||||||
lastUserEvent = DwGetCurrentTime();
|
lastUserEvent = DwGetCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PTP_INIT {
|
||||||
|
HPOLYGON hPoly; // Polygon
|
||||||
|
TINSEL_EVENT event; // Trigerring event
|
||||||
|
PLR_EVENT bev; // To allow for double clicks
|
||||||
|
bool take_control; // Set if control should be taken
|
||||||
|
// while code is running.
|
||||||
|
int actor;
|
||||||
|
|
||||||
|
PINT_CONTEXT pic;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs glitter code associated with a polygon.
|
||||||
|
*/
|
||||||
|
void PolyTinselProcess(CORO_PARAM, const void *param) {
|
||||||
|
// COROUTINE
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
INT_CONTEXT *pic;
|
||||||
|
bool bTookControl; // Set if this function takes control
|
||||||
|
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
const PTP_INIT *to = (const PTP_INIT *)param; // get the stuff copied to process when it was created
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
|
||||||
|
// Take control for CONVERSE events
|
||||||
|
if (to->event == CONVERSE) {
|
||||||
|
_ctx->bTookControl = GetControl();
|
||||||
|
HideConversation(true);
|
||||||
|
} else
|
||||||
|
_ctx->bTookControl = false;
|
||||||
|
|
||||||
|
CORO_INVOKE_1(Interpret, to->pic);
|
||||||
|
|
||||||
|
// Restore conv window if applicable
|
||||||
|
if (to->event == CONVERSE) {
|
||||||
|
// Free control if we took it
|
||||||
|
if (_ctx->bTookControl)
|
||||||
|
ControlOn();
|
||||||
|
|
||||||
|
HideConversation(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
CORO_INVOKE_1(AllowDclick, to->bev); // May kill us if single click
|
||||||
|
|
||||||
|
// Control may have gone off during AllowDclick()
|
||||||
|
if (!TestToken(TOKEN_CONTROL)
|
||||||
|
&& (to->event == WALKTO || to->event == ACTION || to->event == LOOK))
|
||||||
|
CORO_KILL_SELF();
|
||||||
|
|
||||||
|
// Take control, if requested
|
||||||
|
if (to->take_control)
|
||||||
|
_ctx->bTookControl = GetControl(CONTROL_OFF);
|
||||||
|
else
|
||||||
|
_ctx->bTookControl = false;
|
||||||
|
|
||||||
|
// Hide conversation if appropriate
|
||||||
|
if (to->event == CONVERSE)
|
||||||
|
HideConversation(true);
|
||||||
|
|
||||||
|
// Run the code
|
||||||
|
_ctx->pic = InitInterpretContext(GS_POLYGON, GetPolyScript(to->hPoly), to->event, to->hPoly, to->actor, NULL);
|
||||||
|
CORO_INVOKE_1(Interpret, _ctx->pic);
|
||||||
|
|
||||||
|
// Free control if we took it
|
||||||
|
if (_ctx->bTookControl)
|
||||||
|
Control(CONTROL_ON);
|
||||||
|
|
||||||
|
// Restore conv window if applicable
|
||||||
|
if (to->event == CONVERSE)
|
||||||
|
HideConversation(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the Polygon process with the given event
|
||||||
|
*/
|
||||||
|
void PolygonEvent(CORO_PARAM, HPOLYGON hPoly, TINSEL_EVENT tEvent, int actor, bool bWait,
|
||||||
|
int myEscape, bool *result) {
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
PTP_INIT to;
|
||||||
|
PPROCESS pProc;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
if (result) *result = false;
|
||||||
|
_ctx->to.hPoly = -1;
|
||||||
|
_ctx->to.event = tEvent;
|
||||||
|
_ctx->to.pic = InitInterpretContext(GS_POLYGON,
|
||||||
|
GetPolyScript(hPoly),
|
||||||
|
tEvent,
|
||||||
|
hPoly, // Polygon
|
||||||
|
actor, // Actor
|
||||||
|
NULL, // No Object
|
||||||
|
myEscape);
|
||||||
|
if (_ctx->to.pic != NULL) {
|
||||||
|
_ctx->pProc = g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &_ctx->to, sizeof(_ctx->to));
|
||||||
|
AttachInterpret(_ctx->to.pic, _ctx->pProc);
|
||||||
|
|
||||||
|
if (bWait)
|
||||||
|
CORO_INVOKE_2(WaitInterpret,_ctx->pProc, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs glitter code associated with a polygon.
|
||||||
|
*/
|
||||||
|
void RunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, PLR_EVENT be, bool tc) {
|
||||||
|
PTP_INIT to = { hPoly, event, be, tc, 0, NULL };
|
||||||
|
|
||||||
|
assert(!TinselV2);
|
||||||
|
g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
|
||||||
|
}
|
||||||
|
|
||||||
|
void effRunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, int actor) {
|
||||||
|
PTP_INIT to = { hPoly, event, PLR_NOEVENT, false, actor, NULL };
|
||||||
|
|
||||||
|
assert(!TinselV2);
|
||||||
|
g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If provisional event was processed, calling this prevents the
|
||||||
|
* subsequent 'real' event.
|
||||||
|
*/
|
||||||
|
void ProcessedProvisional(void) {
|
||||||
|
bProvNotProcessed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the bProvNotProcessed flag
|
||||||
|
*/
|
||||||
|
void ProvNotProcessed(void) {
|
||||||
|
bProvNotProcessed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetProvNotProcessed() {
|
||||||
|
return bProvNotProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -29,49 +29,99 @@
|
||||||
|
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/coroutine.h"
|
#include "tinsel/coroutine.h"
|
||||||
|
#include "common/rect.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
/*
|
||||||
enum BUTEVENT {
|
enum BUTEVENT {
|
||||||
BE_NONE, BE_SLEFT, BE_DLEFT, BE_SRIGHT, BE_DRIGHT,
|
PLR_NOEVENT, PLR_SLEFT, PLR_DLEFT, PLR_SRIGHT, PLR_DRIGHT,
|
||||||
BE_LDSTART, BE_LDEND, BE_RDSTART, BE_RDEND,
|
PLR_DRAG1_START, PLR_DRAG1_END, PLR_DRAG2_START, PLR_DRAG2_END,
|
||||||
BE_UNKNOWN
|
PLR_UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum KEYEVENT {
|
enum KEYEVENT {
|
||||||
ESC_KEY, QUIT_KEY, SAVE_KEY, LOAD_KEY, OPTION_KEY,
|
PLR_ESCAPE, PLR_QUIT, PLR_SAVE, PLR_LOAD, PLR_MENU,
|
||||||
PGUP_KEY, PGDN_KEY, HOME_KEY, END_KEY,
|
PLR_PGUP, PLR_PGDN, PLR_HOME, PLR_END,
|
||||||
WALKTO_KEY, ACTION_KEY, LOOK_KEY,
|
PLR_WALKTO, PLR_ACTION, PLR_LOOK,
|
||||||
NOEVENT_KEY
|
NOEVENT_KEY
|
||||||
|
};*/
|
||||||
|
|
||||||
|
enum PLR_EVENT {
|
||||||
|
// action list
|
||||||
|
PLR_PROV_WALKTO = 0, // Provisional WALKTO !
|
||||||
|
PLR_WALKTO = 1,
|
||||||
|
PLR_LOOK = 2,
|
||||||
|
PLR_ACTION = 3,
|
||||||
|
PLR_ESCAPE = 4,
|
||||||
|
PLR_MENU = 5,
|
||||||
|
PLR_QUIT = 6,
|
||||||
|
PLR_PGUP = 7,
|
||||||
|
PLR_PGDN = 8,
|
||||||
|
PLR_HOME = 9,
|
||||||
|
PLR_END = 10,
|
||||||
|
PLR_DRAG1_START = 11,
|
||||||
|
PLR_DRAG1_END = 12,
|
||||||
|
PLR_DRAG2_START = 13,
|
||||||
|
PLR_DRAG2_END = 14,
|
||||||
|
PLR_JUMP = 15, // Call up scene hopper
|
||||||
|
PLR_NOEVENT = 16,
|
||||||
|
PLR_SAVE = 17,
|
||||||
|
PLR_LOAD = 18,
|
||||||
|
|
||||||
|
// Aliases used for DW1 actions
|
||||||
|
PLR_SLEFT = PLR_WALKTO,
|
||||||
|
PLR_DLEFT = PLR_ACTION,
|
||||||
|
PLR_SRIGHT = PLR_LOOK,
|
||||||
|
PLR_DRIGHT = PLR_NOEVENT,
|
||||||
|
PLR_UNKNOWN = PLR_NOEVENT
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reasons for running Glitter code.
|
* Reasons for running Glitter code.
|
||||||
* Do not re-order these as equivalent CONSTs are defined in the master
|
* Do not re-order these as equivalent CONSTs are defined in the master
|
||||||
* scene Glitter source file for testing against the event() library function.
|
* scene Glitter source file for testing against the event() library function.
|
||||||
|
*
|
||||||
|
* Note: DW2 renames ENTER & LEAVE to WALKIN & WALKOUT, and has a new LEAVE event
|
||||||
*/
|
*/
|
||||||
enum USER_EVENT {
|
enum TINSEL_EVENT {
|
||||||
POINTED, WALKTO, ACTION, LOOK,
|
NOEVENT, STARTUP, CLOSEDOWN, POINTED, UNPOINT, WALKIN, WALKOUT,
|
||||||
ENTER, LEAVE, STARTUP, CONVERSE,
|
PICKUP, PUTDOWN, WALKTO, LOOK, ACTION, CONVERSE, SHOWEVENT,
|
||||||
UNPOINT, PUTDOWN,
|
HIDEEVENT, TALKING, ENDTALK, LEAVE_T2, RESTORE, PROV_WALKTO
|
||||||
NOEVENT
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum TINSEL1_EVENT {
|
||||||
|
T1_POINTED, T1_WALKTO, T1_ACTION, T1_LOOK, T1_ENTER, T1_LEAVE, T1_STARTUP, T1_CONVERSE,
|
||||||
|
T1_UNPOINT, T1_PUTDOWN, T1_NOEVENT
|
||||||
|
};
|
||||||
|
|
||||||
void AllowDclick(CORO_PARAM, BUTEVENT be);
|
const TINSEL1_EVENT TINSEL1_EVENT_MAP[] = {
|
||||||
|
T1_NOEVENT, T1_STARTUP, T1_NOEVENT, T1_POINTED, T1_UNPOINT, T1_ENTER, T1_LEAVE,
|
||||||
|
T1_NOEVENT, T1_PUTDOWN, T1_WALKTO, T1_LOOK, T1_ACTION, T1_CONVERSE, T1_NOEVENT,
|
||||||
|
T1_NOEVENT, T1_NOEVENT, T1_NOEVENT, T1_NOEVENT, T1_NOEVENT, T1_NOEVENT
|
||||||
|
};
|
||||||
|
|
||||||
|
void AllowDclick(CORO_PARAM, PLR_EVENT be);
|
||||||
bool GetControl(int param);
|
bool GetControl(int param);
|
||||||
|
bool GetControl(void);
|
||||||
|
bool ControlIsOn(void);
|
||||||
|
void ControlOn(void);
|
||||||
|
void ControlOff(void);
|
||||||
|
void ControlStartOff(void);
|
||||||
|
|
||||||
void RunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, BUTEVENT be, bool tc);
|
void RunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, PLR_EVENT be, bool tc);
|
||||||
void effRunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, int actor);
|
void effRunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, int actor);
|
||||||
|
|
||||||
void ProcessButEvent(BUTEVENT be);
|
void ProcessButEvent(PLR_EVENT be);
|
||||||
void ProcessKeyEvent(KEYEVENT ke);
|
void ProcessKeyEvent(PLR_EVENT ke);
|
||||||
|
|
||||||
|
|
||||||
int GetEscEvents(void);
|
int GetEscEvents(void);
|
||||||
int GetLeftEvents(void);
|
int GetLeftEvents(void);
|
||||||
|
bool LeftEventChange(int myleftEvent);
|
||||||
|
|
||||||
int getUserEvents(void);
|
int getUserEvents(void);
|
||||||
|
|
||||||
uint32 getUserEventTime(void);
|
uint32 getUserEventTime(void);
|
||||||
|
@ -79,6 +129,16 @@ void resetUserEventTime(void);
|
||||||
|
|
||||||
void ResetEcount(void);
|
void ResetEcount(void);
|
||||||
|
|
||||||
|
void PolygonEvent(CORO_PARAM, HPOLYGON hPoly, TINSEL_EVENT tEvent, int actor, bool bWait,
|
||||||
|
int myEscape, bool *result = NULL);
|
||||||
|
|
||||||
|
|
||||||
|
void PlayerEvent(PLR_EVENT pEvent, const Common::Point &coOrds);
|
||||||
|
|
||||||
|
void ProcessedProvisional(void);
|
||||||
|
void ProvNotProcessed(void);
|
||||||
|
bool GetProvNotProcessed();
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif /* TINSEL_EVENTS_H */
|
#endif /* TINSEL_EVENTS_H */
|
||||||
|
|
|
@ -24,11 +24,14 @@
|
||||||
* Palette Fader and Flasher processes.
|
* Palette Fader and Flasher processes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tinsel/pid.h" // list of all process IDs
|
#include "tinsel/actors.h"
|
||||||
#include "tinsel/sched.h" // scheduler defs
|
|
||||||
#include "tinsel/faders.h" // fader defs
|
#include "tinsel/faders.h" // fader defs
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
#include "tinsel/palette.h" // Palette Manager defs
|
#include "tinsel/palette.h" // Palette Manager defs
|
||||||
|
#include "tinsel/pid.h" // list of all process IDs
|
||||||
|
#include "tinsel/sched.h" // scheduler defs
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -40,9 +43,7 @@ struct FADE {
|
||||||
|
|
||||||
// fixed point fade multiplier tables
|
// fixed point fade multiplier tables
|
||||||
//const long fadeout[] = {0xf000, 0xd000, 0xb000, 0x9000, 0x7000, 0x5000, 0x3000, 0x1000, 0, -1};
|
//const long fadeout[] = {0xf000, 0xd000, 0xb000, 0x9000, 0x7000, 0x5000, 0x3000, 0x1000, 0, -1};
|
||||||
const long fadeout[] = {0xd000, 0xa000, 0x7000, 0x4000, 0x1000, 0, -1};
|
|
||||||
//const long fadein[] = {0, 0x1000, 0x3000, 0x5000, 0x7000, 0x9000, 0xb000, 0xd000, 0x10000L, -1};
|
//const long fadein[] = {0, 0x1000, 0x3000, 0x5000, 0x7000, 0x9000, 0xb000, 0xd000, 0x10000L, -1};
|
||||||
const long fadein[] = {0, 0x1000, 0x4000, 0x7000, 0xa000, 0xd000, 0x10000L, -1};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scale 'colour' by the fixed point colour multiplier 'colourMult'
|
* Scale 'colour' by the fixed point colour multiplier 'colourMult'
|
||||||
|
@ -70,8 +71,18 @@ static COLORREF ScaleColour(COLORREF colour, uint32 colourMult) {
|
||||||
*/
|
*/
|
||||||
static void FadePalette(COLORREF *pNew, COLORREF *pOrig, int numColours, uint32 mult) {
|
static void FadePalette(COLORREF *pNew, COLORREF *pOrig, int numColours, uint32 mult) {
|
||||||
for (int i = 0; i < numColours; i++, pNew++, pOrig++) {
|
for (int i = 0; i < numColours; i++, pNew++, pOrig++) {
|
||||||
|
if (!TinselV2)
|
||||||
// apply multiplier to RGB components
|
// apply multiplier to RGB components
|
||||||
*pNew = ScaleColour(*pOrig, mult);
|
*pNew = ScaleColour(*pOrig, mult);
|
||||||
|
else if (i == (TalkColour() - 1)) {
|
||||||
|
*pNew = GetTalkColourRef();
|
||||||
|
*pNew = ScaleColour(*pNew, mult);
|
||||||
|
} else if (SysVar(SV_TAGCOLOUR) && i == (SysVar(SV_TAGCOLOUR) - 1)) {
|
||||||
|
*pNew = GetTagColorRef();
|
||||||
|
*pNew = ScaleColour(*pNew, mult);
|
||||||
|
} else {
|
||||||
|
*pNew = ScaleColour(*pOrig, mult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +100,14 @@ static void FadeProcess(CORO_PARAM, const void *param) {
|
||||||
CORO_END_CONTEXT(_ctx);
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
// get the fade data structure - copied to process when it was created
|
// get the fade data structure - copied to process when it was created
|
||||||
FADE *pFade = (FADE *)param;
|
const FADE *pFade = (const FADE *)param;
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
// Note that this palette is being faded
|
||||||
|
FadingPalette(pFade->pPalQ, true);
|
||||||
|
|
||||||
// get pointer to palette - reduce pointer indirection a bit
|
// get pointer to palette - reduce pointer indirection a bit
|
||||||
_ctx->pPalette = (PALETTE *)LockMem(pFade->pPalQ->hPal);
|
_ctx->pPalette = (PALETTE *)LockMem(pFade->pPalQ->hPal);
|
||||||
|
|
||||||
|
@ -100,6 +115,10 @@ static void FadeProcess(CORO_PARAM, const void *param) {
|
||||||
// go through all multipliers in table - until a negative entry
|
// go through all multipliers in table - until a negative entry
|
||||||
|
|
||||||
// fade palette using next multiplier
|
// fade palette using next multiplier
|
||||||
|
if (TinselV2)
|
||||||
|
FadePalette(_ctx->fadeRGB, pFade->pPalQ->palRGB,
|
||||||
|
FROM_LE_32(pFade->pPalQ->numColours), (uint32) *_ctx->pColMult);
|
||||||
|
else
|
||||||
FadePalette(_ctx->fadeRGB, _ctx->pPalette->palRGB,
|
FadePalette(_ctx->fadeRGB, _ctx->pPalette->palRGB,
|
||||||
FROM_LE_32(_ctx->pPalette->numColours), (uint32) *_ctx->pColMult);
|
FROM_LE_32(_ctx->pPalette->numColours), (uint32) *_ctx->pColMult);
|
||||||
|
|
||||||
|
@ -110,6 +129,10 @@ static void FadeProcess(CORO_PARAM, const void *param) {
|
||||||
CORO_SLEEP(1);
|
CORO_SLEEP(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
// Note that this palette is being faded
|
||||||
|
FadingPalette(pFade->pPalQ, false);
|
||||||
|
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +145,13 @@ static void FadeProcess(CORO_PARAM, const void *param) {
|
||||||
static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) {
|
static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) {
|
||||||
PALQ *pPal; // palette manager iterator
|
PALQ *pPal; // palette manager iterator
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// The is only ever one cuncurrent fade
|
||||||
|
// But this could be a fade out and the fade in is still going!
|
||||||
|
g_scheduler->killMatchingProcess(PID_FADER);
|
||||||
|
NoFadingPalettes();
|
||||||
|
}
|
||||||
|
|
||||||
// create a process for each palette in the palette queue
|
// create a process for each palette in the palette queue
|
||||||
for (pPal = GetNextPalette(NULL); pPal != NULL; pPal = GetNextPalette(pPal)) {
|
for (pPal = GetNextPalette(NULL); pPal != NULL; pPal = GetNextPalette(pPal)) {
|
||||||
bool bFade = true;
|
bool bFade = true;
|
||||||
|
@ -154,22 +184,61 @@ static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades a list of palettes down to black.
|
||||||
|
* 'noFadeTable' is a NULL terminated list of palettes not to fade.
|
||||||
|
*/
|
||||||
|
void FadeOutMedium(SCNHANDLE noFadeTable[]) {
|
||||||
|
// Fixed point fade multiplier table
|
||||||
|
static const long fadeout[] = {0xea00, 0xd000, 0xb600, 0x9c00,
|
||||||
|
0x8200, 0x6800, 0x4e00, 0x3400, 0x1a00, 0, -1};
|
||||||
|
|
||||||
|
// call generic fader
|
||||||
|
Fader(fadeout, noFadeTable);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fades a list of palettes down to black.
|
* Fades a list of palettes down to black.
|
||||||
* @param noFadeTable A NULL terminated list of palettes not to fade.
|
* @param noFadeTable A NULL terminated list of palettes not to fade.
|
||||||
*/
|
*/
|
||||||
void FadeOutFast(SCNHANDLE noFadeTable[]) {
|
void FadeOutFast(SCNHANDLE noFadeTable[]) {
|
||||||
|
// Fixed point fade multiplier table
|
||||||
|
static const long fadeout[] = {0xd000, 0xa000, 0x7000, 0x4000, 0x1000, 0, -1};
|
||||||
|
|
||||||
// call generic fader
|
// call generic fader
|
||||||
Fader(fadeout, noFadeTable);
|
Fader(fadeout, noFadeTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades a list of palettes from black to their current colours.
|
||||||
|
* 'noFadeTable' is a NULL terminated list of palettes not to fade.
|
||||||
|
*/
|
||||||
|
void FadeInMedium(SCNHANDLE noFadeTable[]) {
|
||||||
|
// Fade multiplier table
|
||||||
|
static const long fadein[] = {0, 0x1a00, 0x3400, 0x4e00, 0x6800,
|
||||||
|
0x8200, 0x9c00, 0xb600, 0xd000, 0xea00, 0x10000L, -1};
|
||||||
|
|
||||||
|
// call generic fader
|
||||||
|
Fader(fadein, noFadeTable);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fades a list of palettes from black to their current colours.
|
* Fades a list of palettes from black to their current colours.
|
||||||
* @param noFadeTable A NULL terminated list of palettes not to fade.
|
* @param noFadeTable A NULL terminated list of palettes not to fade.
|
||||||
*/
|
*/
|
||||||
void FadeInFast(SCNHANDLE noFadeTable[]) {
|
void FadeInFast(SCNHANDLE noFadeTable[]) {
|
||||||
|
// Fade multiplier table
|
||||||
|
static const long fadein[] = {0, 0x1000, 0x4000, 0x7000, 0xa000, 0xd000, 0x10000L, -1};
|
||||||
|
|
||||||
// call generic fader
|
// call generic fader
|
||||||
Fader(fadein, noFadeTable);
|
Fader(fadein, noFadeTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PokeInTagColour(void) {
|
||||||
|
if (SysVar(SV_TAGCOLOUR)) {
|
||||||
|
static COLORREF c = GetActorRGB(-1);
|
||||||
|
UpdateDACqueue(SysVar(SV_TAGCOLOUR), 1, &c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -28,16 +28,15 @@
|
||||||
#define TINSEL_FADERS_H
|
#define TINSEL_FADERS_H
|
||||||
|
|
||||||
#include "tinsel/dw.h" // for SCNHANDLE
|
#include "tinsel/dw.h" // for SCNHANDLE
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
enum {
|
|
||||||
/**
|
/**
|
||||||
* Number of iterations in a fade out.
|
* Number of iterations in a fade out.
|
||||||
* Must match which FadeOut() is in use.
|
|
||||||
*/
|
*/
|
||||||
COUNTOUT_COUNT = 6
|
// FIXME: There seems to be some confusion in Tinsel 2 whether this should be 9 or 6
|
||||||
};
|
#define COUNTOUT_COUNT 6
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*\
|
/*----------------------------------------------------------------------*\
|
||||||
|* Fader Function Prototypes *|
|
|* Fader Function Prototypes *|
|
||||||
|
@ -47,8 +46,11 @@ enum {
|
||||||
// should not be faded. This parameter can be
|
// should not be faded. This parameter can be
|
||||||
// NULL - fade all palettes.
|
// NULL - fade all palettes.
|
||||||
|
|
||||||
|
void FadeOutMedium(SCNHANDLE noFadeTable[]);
|
||||||
void FadeOutFast(SCNHANDLE noFadeTable[]);
|
void FadeOutFast(SCNHANDLE noFadeTable[]);
|
||||||
|
void FadeInMedium(SCNHANDLE noFadeTable[]);
|
||||||
void FadeInFast(SCNHANDLE noFadeTable[]);
|
void FadeInFast(SCNHANDLE noFadeTable[]);
|
||||||
|
void PokeInTagColour(void);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,14 @@
|
||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "tinsel/actors.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/font.h"
|
#include "tinsel/font.h"
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
#include "tinsel/object.h"
|
#include "tinsel/object.h"
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
#include "tinsel/text.h"
|
#include "tinsel/text.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -35,48 +38,63 @@ namespace Tinsel {
|
||||||
static char tBuffer[TBUFSZ];
|
static char tBuffer[TBUFSZ];
|
||||||
|
|
||||||
static SCNHANDLE hTagFont = 0, hTalkFont = 0;
|
static SCNHANDLE hTagFont = 0, hTalkFont = 0;
|
||||||
|
static SCNHANDLE hRegularTalkFont = 0, hRegularTagFont = 0;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return address of tBuffer
|
* Return address of tBuffer
|
||||||
*/
|
*/
|
||||||
char *tBufferAddr() {
|
char *TextBufferAddr() {
|
||||||
return tBuffer;
|
return tBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return hTagFont handle.
|
* Return hTagFont handle.
|
||||||
*/
|
*/
|
||||||
SCNHANDLE hTagFontHandle() {
|
SCNHANDLE GetTagFontHandle() {
|
||||||
return hTagFont;
|
return hTagFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return hTalkFont handle.
|
* Return hTalkFont handle.
|
||||||
*/
|
*/
|
||||||
SCNHANDLE hTalkFontHandle() {
|
SCNHANDLE GetTalkFontHandle() {
|
||||||
return hTalkFont;
|
return hTalkFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from dec_tagfont() Glitter function. Store the tag font handle.
|
* Called from dec_tagfont() Glitter function. Store the tag font handle.
|
||||||
*/
|
*/
|
||||||
void TagFontHandle(SCNHANDLE hf) {
|
void SetTagFontHandle(SCNHANDLE hFont) {
|
||||||
hTagFont = hf; // Store the font handle
|
hTagFont = hRegularTagFont = hFont; // Store the font handle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from dec_talkfont() Glitter function.
|
* Called from dec_talkfont() Glitter function.
|
||||||
* Store the talk font handle.
|
* Store the talk font handle.
|
||||||
*/
|
*/
|
||||||
void TalkFontHandle(SCNHANDLE hf) {
|
void SetTalkFontHandle(SCNHANDLE hFont) {
|
||||||
hTalkFont = hf; // Store the font handle
|
hTalkFont = hRegularTalkFont = hFont; // Store the font handle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetTempTagFontHandle(SCNHANDLE hFont) {
|
||||||
|
hTagFont = hFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTempTalkFontHandle(SCNHANDLE hFont) {
|
||||||
|
hTalkFont = hFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetFontHandles(void) {
|
||||||
|
hTagFont = hRegularTagFont;
|
||||||
|
hTalkFont = hRegularTalkFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Poke the background palette into character 0's images.
|
* Poke the background palette into character 0's images.
|
||||||
*/
|
*/
|
||||||
void fettleFontPal(SCNHANDLE fontPal) {
|
void FettleFontPal(SCNHANDLE fontPal) {
|
||||||
const FONT *pFont;
|
const FONT *pFont;
|
||||||
IMAGE *pImg;
|
IMAGE *pImg;
|
||||||
|
|
||||||
|
@ -86,11 +104,23 @@ void fettleFontPal(SCNHANDLE fontPal) {
|
||||||
|
|
||||||
pFont = (const FONT *)LockMem(hTagFont);
|
pFont = (const FONT *)LockMem(hTagFont);
|
||||||
pImg = (IMAGE *)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0
|
pImg = (IMAGE *)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0
|
||||||
|
if (!TinselV2)
|
||||||
pImg->hImgPal = TO_LE_32(fontPal);
|
pImg->hImgPal = TO_LE_32(fontPal);
|
||||||
|
else
|
||||||
|
pImg->hImgPal = 0;
|
||||||
|
|
||||||
pFont = (const FONT *)LockMem(hTalkFont);
|
pFont = (const FONT *)LockMem(hTalkFont);
|
||||||
pImg = (IMAGE *)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0
|
pImg = (IMAGE *)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0
|
||||||
|
if (!TinselV2)
|
||||||
pImg->hImgPal = TO_LE_32(fontPal);
|
pImg->hImgPal = TO_LE_32(fontPal);
|
||||||
|
else
|
||||||
|
pImg->hImgPal = 0;
|
||||||
|
|
||||||
|
if (TinselV2 && SysVar(SV_TAGCOLOUR)) {
|
||||||
|
static COLORREF c = GetActorRGB(-1);
|
||||||
|
SetTagColorRef(c);
|
||||||
|
UpdateDACqueue(SysVar(SV_TAGCOLOUR), 1, &c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End of namespace Tinsel
|
} // End of namespace Tinsel
|
||||||
|
|
|
@ -31,17 +31,27 @@
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
// A temporary buffer for extracting text into is defined in font.c
|
// A temporary buffer for extracting text into is defined in font.c
|
||||||
// Accessed using tBufferAddr(), this is how big it is:
|
// Accessed using TextBufferAddr(), this is how big it is:
|
||||||
#define TBUFSZ 512
|
#define TBUFSZ 512
|
||||||
|
|
||||||
|
|
||||||
char *tBufferAddr(void);
|
char *TextBufferAddr(void);
|
||||||
SCNHANDLE hTagFontHandle(void);
|
|
||||||
SCNHANDLE hTalkFontHandle(void);
|
|
||||||
|
|
||||||
void TagFontHandle(SCNHANDLE hf);
|
SCNHANDLE GetTagFontHandle(void);
|
||||||
void TalkFontHandle(SCNHANDLE hf);
|
|
||||||
void fettleFontPal(SCNHANDLE fontPal);
|
SCNHANDLE GetTalkFontHandle(void);
|
||||||
|
|
||||||
|
void SetTagFontHandle(SCNHANDLE hFont);
|
||||||
|
|
||||||
|
void SetTalkFontHandle(SCNHANDLE hFont);
|
||||||
|
|
||||||
|
void SetTempTagFontHandle(SCNHANDLE hFont);
|
||||||
|
|
||||||
|
void SetTempTalkFontHandle(SCNHANDLE hFont);
|
||||||
|
|
||||||
|
void ResetFontHandles(void);
|
||||||
|
|
||||||
|
void FettleFontPal(SCNHANDLE fontPal);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "tinsel/handle.h" // LockMem()
|
#include "tinsel/handle.h" // LockMem()
|
||||||
#include "tinsel/object.h"
|
#include "tinsel/object.h"
|
||||||
#include "tinsel/palette.h"
|
#include "tinsel/palette.h"
|
||||||
|
#include "tinsel/scene.h"
|
||||||
#include "tinsel/tinsel.h"
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
@ -46,7 +47,6 @@ extern uint8 transPalette[MAX_COLOURS];
|
||||||
/**
|
/**
|
||||||
* Straight rendering with transparency support
|
* Straight rendering with transparency support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping) {
|
static void WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping) {
|
||||||
// Set up the offset between destination blocks
|
// Set up the offset between destination blocks
|
||||||
int rightClip = applyClipping ? pObj->rightClip : 0;
|
int rightClip = applyClipping ? pObj->rightClip : 0;
|
||||||
|
@ -155,10 +155,91 @@ static void WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyCl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tinsel 2 Straight rendering with transparency support
|
||||||
|
*/
|
||||||
|
static void t2WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping, bool horizFlipped) {
|
||||||
|
// Setup for correct clipping of object edges
|
||||||
|
int yClip = applyClipping ? pObj->topClip : 0;
|
||||||
|
if (applyClipping)
|
||||||
|
pObj->height -= pObj->botClip;
|
||||||
|
int numBytes;
|
||||||
|
int clipAmount;
|
||||||
|
|
||||||
|
for (int y = 0; y < pObj->height; ++y) {
|
||||||
|
// Get the position to start writing out from
|
||||||
|
uint8 *tempP = !horizFlipped ? destP :
|
||||||
|
destP + (pObj->width - pObj->leftClip - pObj->rightClip) - 1;
|
||||||
|
int leftClip = applyClipping ? pObj->leftClip : 0;
|
||||||
|
int rightClip = applyClipping ? pObj->rightClip : 0;
|
||||||
|
if (horizFlipped)
|
||||||
|
SWAP(leftClip, rightClip);
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
while (x < pObj->width) {
|
||||||
|
// Get the next opcode
|
||||||
|
numBytes = *srcP++;
|
||||||
|
if (numBytes & 0x80) {
|
||||||
|
// Run length following
|
||||||
|
numBytes &= 0x7f;
|
||||||
|
clipAmount = MIN(numBytes, leftClip);
|
||||||
|
leftClip -= clipAmount;
|
||||||
|
x+= clipAmount;
|
||||||
|
|
||||||
|
int runLength = numBytes - clipAmount;
|
||||||
|
uint8 colour = *srcP++;
|
||||||
|
|
||||||
|
if ((yClip == 0) && (runLength > 0) && (colour != 0)) {
|
||||||
|
runLength = MIN(runLength, pObj->width - rightClip - x);
|
||||||
|
|
||||||
|
if (runLength > 0) {
|
||||||
|
// Non-transparent run length
|
||||||
|
colour += pObj->constant;
|
||||||
|
if (horizFlipped)
|
||||||
|
Common::set_to(tempP - runLength + 1, tempP + 1, colour);
|
||||||
|
else
|
||||||
|
Common::set_to(tempP, tempP + runLength, colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (horizFlipped)
|
||||||
|
tempP -= runLength;
|
||||||
|
else
|
||||||
|
tempP += runLength;
|
||||||
|
|
||||||
|
x += numBytes - clipAmount;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Dump a length of pixels
|
||||||
|
clipAmount = MIN(numBytes, leftClip);
|
||||||
|
leftClip -= clipAmount;
|
||||||
|
srcP += clipAmount;
|
||||||
|
int runLength = numBytes - clipAmount;
|
||||||
|
x += numBytes - runLength;
|
||||||
|
|
||||||
|
for (int xp = 0; xp < runLength; ++xp) {
|
||||||
|
if ((yClip > 0) || (x >= (pObj->width - rightClip)))
|
||||||
|
++srcP;
|
||||||
|
else if (horizFlipped)
|
||||||
|
*tempP-- = pObj->constant + *srcP++;
|
||||||
|
else
|
||||||
|
*tempP++ = pObj->constant + *srcP++;
|
||||||
|
++x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(x == pObj->width);
|
||||||
|
|
||||||
|
if (yClip > 0)
|
||||||
|
--yClip;
|
||||||
|
else
|
||||||
|
destP += SCREEN_WIDTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill the destination area with a constant colour
|
* Fill the destination area with a constant colour
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void WrtConst(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
static void WrtConst(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
||||||
if (applyClipping) {
|
if (applyClipping) {
|
||||||
pObj->height -= pObj->topClip + pObj->botClip;
|
pObj->height -= pObj->topClip + pObj->botClip;
|
||||||
|
@ -181,7 +262,6 @@ static void WrtConst(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
||||||
* Translates the destination surface within the object's bounds using the transparency
|
* Translates the destination surface within the object's bounds using the transparency
|
||||||
* lookup table from transpal.cpp (the contents of which have been moved into palette.cpp)
|
* lookup table from transpal.cpp (the contents of which have been moved into palette.cpp)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void WrtTrans(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
static void WrtTrans(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
||||||
if (applyClipping) {
|
if (applyClipping) {
|
||||||
pObj->height -= pObj->topClip + pObj->botClip;
|
pObj->height -= pObj->topClip + pObj->botClip;
|
||||||
|
@ -204,166 +284,136 @@ static void WrtTrans(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies an uncompressed block of data straight to the screen
|
||||||
|
*/
|
||||||
|
static void WrtAll(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping) {
|
||||||
|
int objWidth = pObj->width;
|
||||||
|
|
||||||
#if 0
|
if (applyClipping) {
|
||||||
// This commented out code is the untested original WrtNonZero/ClpWrtNonZero combo method
|
srcP += (pObj->topClip * pObj->width) + pObj->leftClip;
|
||||||
// from the v1 source. It may be needed to be included later on to support v1 gfx files
|
|
||||||
|
pObj->height -= pObj->topClip + pObj->botClip;
|
||||||
|
pObj->width -= pObj->leftClip + pObj->rightClip;
|
||||||
|
|
||||||
|
if (pObj->width <= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < pObj->height; ++y) {
|
||||||
|
Common::copy(srcP, srcP + pObj->width, destP);
|
||||||
|
srcP += objWidth;
|
||||||
|
destP += SCREEN_WIDTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Straight rendering with transparency support
|
* Renders a packed data stream with a variable sized palette
|
||||||
* Possibly only used in the Discworld Demo
|
|
||||||
*/
|
*/
|
||||||
|
static void PackedWrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP,
|
||||||
|
bool applyClipping, bool horizFlipped, int packingType) {
|
||||||
|
uint8 numColours = 0;
|
||||||
|
uint8 *colourTable = NULL;
|
||||||
|
int topClip = 0;
|
||||||
|
int xOffset = 0;
|
||||||
|
int numBytes, colour;
|
||||||
|
int v;
|
||||||
|
|
||||||
static void DemoWrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping) {
|
if (applyClipping) {
|
||||||
// FIXME: If this method is used for the demo, it still needs to be made Endian safe
|
pObj->height -= pObj->botClip;
|
||||||
|
topClip = pObj->topClip;
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the offset between destination lines
|
if (packingType == 3) {
|
||||||
pObj->lineoffset = SCREEN_WIDTH - pObj->width - (applyClipping ? pObj->leftClip - pObj->rightClip : 0);
|
// Variable colours
|
||||||
|
numColours = *srcP++;
|
||||||
|
colourTable = srcP;
|
||||||
|
srcP += numColours;
|
||||||
|
}
|
||||||
|
|
||||||
// Top clipped line handling
|
for (int y = 0; y < pObj->height; ++y) {
|
||||||
while (applyClipping && (pObj->topClip > 0)) {
|
// Get the position to start writing out from
|
||||||
// Loop through discarding the data for the line
|
uint8 *tempP = !horizFlipped ? destP :
|
||||||
int width = pObj->width;
|
destP + (pObj->width - pObj->leftClip - pObj->rightClip) - 1;
|
||||||
while (width > 0) {
|
int leftClip = applyClipping ? pObj->leftClip : 0;
|
||||||
int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP);
|
int rightClip = applyClipping ? pObj->rightClip : 0;
|
||||||
srcP += sizeof(uint32);
|
if (horizFlipped)
|
||||||
|
SWAP(leftClip, rightClip);
|
||||||
|
bool eolFlag = false;
|
||||||
|
|
||||||
if (opcodeOrLen >= 0) {
|
// Get offset for first pixels in next line
|
||||||
// Dump the data
|
xOffset = *srcP++;
|
||||||
srcP += ((opcodeOrLen + 3) / 4) * 4;
|
|
||||||
width -= opcodeOrLen;
|
int x = 0;
|
||||||
} else {
|
while (x < pObj->width) {
|
||||||
// Dump the run-length opcode
|
// Get next run size and colour to use
|
||||||
width -= -opcodeOrLen;
|
for (;;) {
|
||||||
|
if (xOffset > 0) {
|
||||||
|
x += xOffset;
|
||||||
|
|
||||||
|
// Reduce offset amount by any remaining left clipping
|
||||||
|
v = MIN(xOffset, leftClip);
|
||||||
|
xOffset -= v;
|
||||||
|
leftClip -= v;
|
||||||
|
|
||||||
|
if (horizFlipped) tempP -= xOffset; else tempP += xOffset;
|
||||||
|
xOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = *srcP++;
|
||||||
|
numBytes = v & 0xf; // No. bytes 1-15
|
||||||
|
if (packingType == 3)
|
||||||
|
colour = colourTable[v >> 4];
|
||||||
|
else
|
||||||
|
colour = pObj->baseCol + (v >> 4);
|
||||||
|
|
||||||
|
if (numBytes != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
numBytes = *srcP++;
|
||||||
|
if (numBytes >= 16)
|
||||||
|
break;
|
||||||
|
|
||||||
|
xOffset = numBytes + v;
|
||||||
|
if (xOffset == 0) {
|
||||||
|
// End of line encountered
|
||||||
|
eolFlag = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
--pObj->height;
|
if (eolFlag)
|
||||||
--pObj->topClip;
|
break;
|
||||||
|
|
||||||
|
// Apply clipping on byte sequence
|
||||||
|
v = MIN(numBytes, leftClip);
|
||||||
|
leftClip -= v;
|
||||||
|
numBytes -= v;
|
||||||
|
x += v;
|
||||||
|
|
||||||
|
while (numBytes-- > 0) {
|
||||||
|
if ((topClip == 0) && (x < (pObj->width - rightClip))) {
|
||||||
|
*tempP = colour;
|
||||||
|
if (horizFlipped) --tempP; else ++tempP;
|
||||||
}
|
}
|
||||||
|
++x;
|
||||||
// Loop for the required number of rows
|
|
||||||
while (pObj->height > 0) {
|
|
||||||
|
|
||||||
int width = pObj->width;
|
|
||||||
|
|
||||||
// Handling for left edge clipping - this basically involves dumping data until we reach
|
|
||||||
// the part of the line to be displayed
|
|
||||||
int clipLeft = pObj->leftClip;
|
|
||||||
while (applyClipping && (clipLeft > 0)) {
|
|
||||||
int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP);
|
|
||||||
srcP += sizeof(uint32);
|
|
||||||
|
|
||||||
if (opcodeOrLen >= 0) {
|
|
||||||
// Copy a specified number of bytes
|
|
||||||
// Make adjustments for past the clipping width
|
|
||||||
int remainder = 4 - (opcodeOrLen % 4);
|
|
||||||
srcP += MIN(clipLeft, opcodeOrLen);
|
|
||||||
opcodeOrLen -= MIN(clipLeft, opcodeOrLen);
|
|
||||||
clipLeft -= MIN(clipLeft, opcodeOrLen);
|
|
||||||
width -= opcodeOrLen;
|
|
||||||
|
|
||||||
|
|
||||||
// Handle any right edge clipping (if run length covers entire width)
|
|
||||||
if (width < pObj->rightClip) {
|
|
||||||
remainder += (pObj->rightClip - width);
|
|
||||||
opcodeOrLen -= (pObj->rightClip - width);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opcodeOrLen > 0)
|
|
||||||
Common::copy(srcP, srcP + opcodeOrLen, destP);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Output a run length number of bytes
|
|
||||||
// Get data for byte value and run length
|
|
||||||
opcodeOrLen = -opcodeOrLen;
|
|
||||||
int runLength = opcodeOrLen & 0xff;
|
|
||||||
uint8 colourVal = (opcodeOrLen >> 8) & 0xff;
|
|
||||||
|
|
||||||
// Make adjustments for past the clipping width
|
|
||||||
runLength -= MIN(clipLeft, runLength);
|
|
||||||
clipLeft -= MIN(clipLeft, runLength);
|
|
||||||
width -= runLength;
|
|
||||||
|
|
||||||
// Handle any right edge clipping (if run length covers entire width)
|
|
||||||
if (width < pObj->rightClip)
|
|
||||||
runLength -= (pObj->rightClip - width);
|
|
||||||
|
|
||||||
if (runLength > 0) {
|
|
||||||
// Displayable part starts partway through the slice
|
|
||||||
if (colourVal != 0)
|
|
||||||
Common::set_to(destP, destP + runLength, colourVal);
|
|
||||||
destP += runLength;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert(x <= pObj->width);
|
||||||
|
|
||||||
if (width < pObj->rightClip)
|
if (!eolFlag) {
|
||||||
width = 0;
|
// Assert that the next bytes signal a line end
|
||||||
|
assert((*srcP++ & 0xf) == 0);
|
||||||
|
assert(*srcP++ == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling for the visible part of the line
|
if (topClip > 0)
|
||||||
int endWidth = applyClipping ? pObj->rightClip : 0;
|
--topClip;
|
||||||
while (width > endWidth) {
|
else
|
||||||
int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP);
|
destP += SCREEN_WIDTH;
|
||||||
srcP += sizeof(uint32);
|
|
||||||
|
|
||||||
if (opcodeOrLen >= 0) {
|
|
||||||
// Copy the specified number of bytes
|
|
||||||
int remainder = 4 - (opcodeOrLen % 4);
|
|
||||||
|
|
||||||
if (width < endWidth) {
|
|
||||||
// Shorten run length by right clipping
|
|
||||||
remainder += (pObj->rightClip - width);
|
|
||||||
opcodeOrLen -= (pObj->rightClip - width);
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::copy(srcP, srcP + opcodeOrLen, destP);
|
|
||||||
srcP += opcodeOrLen + remainder;
|
|
||||||
destP += opcodeOrLen;
|
|
||||||
width -= opcodeOrLen;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Handle a given run length
|
|
||||||
opcodeOrLen = -opcodeOrLen;
|
|
||||||
int runLength = opcodeOrLen & 0xff;
|
|
||||||
uint8 colourVal = (opcodeOrLen >> 8) & 0xff;
|
|
||||||
|
|
||||||
if (width < endWidth)
|
|
||||||
// Shorten run length by right clipping
|
|
||||||
runLength -= (pObj->rightClip - width);
|
|
||||||
|
|
||||||
// Only set pixels if colourVal non-zero (0 signifies transparency)
|
|
||||||
if (colourVal != 0)
|
|
||||||
// Fill out a run length of a specified colour
|
|
||||||
Common::set_to(destP, destP + runLength, colourVal);
|
|
||||||
|
|
||||||
destP += runLength;
|
|
||||||
width -= runLength;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If right edge clipping is being applied, then width may still be non-zero - in
|
|
||||||
// that case all remaining line data until the end of the line must be ignored
|
|
||||||
while (width > 0) {
|
|
||||||
int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP);
|
|
||||||
srcP += sizeof(uint32);
|
|
||||||
|
|
||||||
if (opcodeOrLen >= 0) {
|
|
||||||
// Dump the data
|
|
||||||
srcP += ((opcodeOrLen + 3) / 4) * 4;
|
|
||||||
width -= opcodeOrLen;
|
|
||||||
} else {
|
|
||||||
// Dump the run-length opcode
|
|
||||||
width -= -opcodeOrLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--pObj->height;
|
|
||||||
destP += pObj->lineoffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//----------------- MAIN FUNCTIONS ---------------------
|
//----------------- MAIN FUNCTIONS ---------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -380,8 +430,10 @@ void ClearScreen() {
|
||||||
* Updates the screen surface within the following rectangle
|
* Updates the screen surface within the following rectangle
|
||||||
*/
|
*/
|
||||||
void UpdateScreenRect(const Common::Rect &pClip) {
|
void UpdateScreenRect(const Common::Rect &pClip) {
|
||||||
byte *pDest = (byte *)_vm->screen().getBasePtr(pClip.left, pClip.top);
|
int yOffset = (g_system->getHeight() - SCREEN_HEIGHT) / 2;
|
||||||
g_system->copyRectToScreen(pDest, _vm->screen().pitch, pClip.left, pClip.top, pClip.width(), pClip.height());
|
byte *pSrc = (byte *)_vm->screen().getBasePtr(pClip.left, pClip.top);
|
||||||
|
g_system->copyRectToScreen(pSrc, _vm->screen().pitch, pClip.left, pClip.top + yOffset,
|
||||||
|
pClip.width(), pClip.height());
|
||||||
g_system->updateScreen();
|
g_system->updateScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,18 +450,76 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||||
|
|
||||||
// If writing constant data, don't bother locking the data pointer and reading src details
|
// If writing constant data, don't bother locking the data pointer and reading src details
|
||||||
if ((pObj->flags & DMA_CONST) == 0) {
|
if ((pObj->flags & DMA_CONST) == 0) {
|
||||||
byte *p = (byte *)LockMem(pObj->hBits & 0xFF800000);
|
if (TinselV2) {
|
||||||
|
srcPtr = (byte *)LockMem(pObj->hBits);
|
||||||
|
pObj->charBase = NULL;
|
||||||
|
pObj->transOffset = 0;
|
||||||
|
} else {
|
||||||
|
byte *p = (byte *)LockMem(pObj->hBits & HANDLEMASK);
|
||||||
|
|
||||||
srcPtr = p + (pObj->hBits & 0x7FFFFF);
|
srcPtr = p + (pObj->hBits & OFFSETMASK);
|
||||||
pObj->charBase = (char *)p + READ_LE_UINT32(p + 0x10);
|
pObj->charBase = (char *)p + READ_LE_UINT32(p + 0x10);
|
||||||
pObj->transOffset = READ_LE_UINT32(p + 0x14);
|
pObj->transOffset = READ_LE_UINT32(p + 0x14);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get destination starting point
|
// Get destination starting point
|
||||||
destPtr = (byte *)_vm->screen().getBasePtr(pObj->xPos, pObj->yPos);
|
destPtr = (byte *)_vm->screen().getBasePtr(pObj->xPos, pObj->yPos);
|
||||||
|
|
||||||
// Handle various draw types
|
// Handle various draw types
|
||||||
uint8 typeId = pObj->flags & 0xff;
|
uint8 typeId = pObj->flags & 0xff;
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// Tinsel v2 decoders
|
||||||
|
// Initial switch statement for the different bit packing types
|
||||||
|
int packType = pObj->flags >> 14;
|
||||||
|
|
||||||
|
if (packType == 0) {
|
||||||
|
// No colour packing
|
||||||
|
switch (typeId) {
|
||||||
|
case 0x01:
|
||||||
|
case 0x11:
|
||||||
|
case 0x41:
|
||||||
|
case 0x51:
|
||||||
|
case 0x81:
|
||||||
|
case 0xC1:
|
||||||
|
t2WrtNonZero(pObj, srcPtr, destPtr, typeId >= 0x40, (typeId & 0x10) != 0);
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
case 0x42:
|
||||||
|
// This renderer called 'RlWrtAll', but is the same as t2WrtNonZero
|
||||||
|
t2WrtNonZero(pObj, srcPtr, destPtr, typeId >= 0x40, false);
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
case 0x44:
|
||||||
|
// WrtConst with/without clipping
|
||||||
|
WrtConst(pObj, destPtr, typeId == 0x44);
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
case 0x48:
|
||||||
|
WrtAll(pObj, srcPtr, destPtr, typeId >= 0x40);
|
||||||
|
break;
|
||||||
|
case 0x84:
|
||||||
|
case 0xC4:
|
||||||
|
// WrtTrans with/without clipping
|
||||||
|
WrtTrans(pObj, destPtr, typeId == 0xC4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown drawing type %d", typeId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 1 = 16 from 240
|
||||||
|
// 2 = 16 from 224
|
||||||
|
// 3 = variable colour
|
||||||
|
if (packType == 1) pObj->baseCol = 0xF0;
|
||||||
|
else if (packType == 2) pObj->baseCol = 0xE0;
|
||||||
|
|
||||||
|
PackedWrtNonZero(pObj, srcPtr, destPtr, (pObj->flags & DMA_CLIP) != 0,
|
||||||
|
(pObj->flags & DMA_FLIPH), packType);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Tinsel v1 decoders
|
||||||
switch (typeId) {
|
switch (typeId) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
case 0x08:
|
case 0x08:
|
||||||
|
@ -420,7 +530,7 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||||
|
|
||||||
case 0x04:
|
case 0x04:
|
||||||
case 0x44:
|
case 0x44:
|
||||||
// ClpWrtConst with/without clipping
|
// WrtConst with/without clipping
|
||||||
WrtConst(pObj,destPtr, typeId == 0x44);
|
WrtConst(pObj,destPtr, typeId == 0x44);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -436,5 +546,6 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Tinsel
|
} // End of namespace Tinsel
|
||||||
|
|
|
@ -37,12 +37,6 @@ namespace Tinsel {
|
||||||
|
|
||||||
struct PALQ;
|
struct PALQ;
|
||||||
|
|
||||||
|
|
||||||
#define SCREEN_WIDTH 320 // PC screen dimensions
|
|
||||||
#define SCREEN_HEIGHT 200
|
|
||||||
#define SCRN_CENTRE_X ((SCREEN_WIDTH - 1) / 2) // screen centre x
|
|
||||||
#define SCRN_CENTRE_Y ((SCREEN_HEIGHT - 1) / 2) // screen centre y
|
|
||||||
|
|
||||||
/** draw object structure - only used when drawing objects */
|
/** draw object structure - only used when drawing objects */
|
||||||
struct DRAWOBJECT {
|
struct DRAWOBJECT {
|
||||||
char *charBase; // character set base address
|
char *charBase; // character set base address
|
||||||
|
@ -60,6 +54,7 @@ struct DRAWOBJECT {
|
||||||
int botClip; // amount to clip off object bottom
|
int botClip; // amount to clip off object bottom
|
||||||
short xPos; // x position of object
|
short xPos; // x position of object
|
||||||
short yPos; // y position of object
|
short yPos; // y position of object
|
||||||
|
uint32 baseCol; // For 4-bit stuff
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "common/file.h"
|
#include "common/file.h"
|
||||||
|
|
||||||
|
#include "tinsel/drives.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/scn.h" // name of "index" file
|
#include "tinsel/scn.h" // name of "index" file
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
|
@ -41,6 +42,8 @@
|
||||||
#include "tinsel/object.h"
|
#include "tinsel/object.h"
|
||||||
#include "tinsel/palette.h"
|
#include "tinsel/palette.h"
|
||||||
#include "tinsel/text.h"
|
#include "tinsel/text.h"
|
||||||
|
#include "tinsel/timers.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
#include "tinsel/scene.h"
|
#include "tinsel/scene.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
@ -58,6 +61,7 @@ struct MEMHANDLE {
|
||||||
char szName[12]; //!< 00 - file name of graphics file
|
char szName[12]; //!< 00 - file name of graphics file
|
||||||
int32 filesize; //!< 12 - file size and flags
|
int32 filesize; //!< 12 - file size and flags
|
||||||
MEM_NODE *pNode; //!< 16 - memory node for the graphics
|
MEM_NODE *pNode; //!< 16 - memory node for the graphics
|
||||||
|
uint32 flags2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +76,6 @@ enum {
|
||||||
};
|
};
|
||||||
#define FSIZE_MASK 0x00FFFFFFL //!< mask to isolate the filesize
|
#define FSIZE_MASK 0x00FFFFFFL //!< mask to isolate the filesize
|
||||||
#define MALLOC_MASK 0xFF000000L //!< mask to isolate the memory allocation flags
|
#define MALLOC_MASK 0xFF000000L //!< mask to isolate the memory allocation flags
|
||||||
#define OFFSETMASK 0x007fffffL //!< get offset of address
|
|
||||||
//#define HANDLEMASK 0xFF800000L //!< get handle of address
|
//#define HANDLEMASK 0xFF800000L //!< get handle of address
|
||||||
|
|
||||||
//----------------- LOCAL GLOBAL DATA --------------------
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
@ -83,6 +86,13 @@ static MEMHANDLE *handleTable = 0;
|
||||||
// number of handles in the handle table
|
// number of handles in the handle table
|
||||||
static uint numHandles = 0;
|
static uint numHandles = 0;
|
||||||
|
|
||||||
|
static uint32 cdPlayHandle = (uint32)-1;
|
||||||
|
|
||||||
|
static int cdPlayFileNum, cdPlaySceneNum;
|
||||||
|
static SCNHANDLE cdBaseHandle = 0, cdTopHandle = 0;
|
||||||
|
static Common::File cdGraphStream;
|
||||||
|
|
||||||
|
static char szCdPlayFile[100];
|
||||||
|
|
||||||
//----------------- FORWARD REFERENCES --------------------
|
//----------------- FORWARD REFERENCES --------------------
|
||||||
|
|
||||||
|
@ -94,7 +104,8 @@ static void LoadFile(MEMHANDLE *pH, bool bWarn); // load a memory block as a fil
|
||||||
* permanent graphics etc.
|
* permanent graphics etc.
|
||||||
*/
|
*/
|
||||||
void SetupHandleTable(void) {
|
void SetupHandleTable(void) {
|
||||||
enum { RECORD_SIZE = 20 };
|
bool t2Flag = (TinselVersion == TINSEL_V2);
|
||||||
|
int RECORD_SIZE = t2Flag ? 24 : 20;
|
||||||
|
|
||||||
int len;
|
int len;
|
||||||
uint i;
|
uint i;
|
||||||
|
@ -108,7 +119,7 @@ void SetupHandleTable(void) {
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
if ((len % RECORD_SIZE) != 0) {
|
if ((len % RECORD_SIZE) != 0) {
|
||||||
// index file is corrupt
|
// index file is corrupt
|
||||||
error("File %s is corrupt", INDEX_FILENAME);
|
error(FILE_IS_CORRUPT, INDEX_FILENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// calc number of handles
|
// calc number of handles
|
||||||
|
@ -128,31 +139,36 @@ void SetupHandleTable(void) {
|
||||||
// need to read that from the file.
|
// need to read that from the file.
|
||||||
handleTable[i].pNode = NULL;
|
handleTable[i].pNode = NULL;
|
||||||
f.seek(4, SEEK_CUR);
|
f.seek(4, SEEK_CUR);
|
||||||
|
// For Discworld 2, read in the flags2 field
|
||||||
|
handleTable[i].flags2 = t2Flag ? f.readUint32LE() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f.ioFailed()) {
|
if (f.ioFailed()) {
|
||||||
// index file is corrupt
|
// index file is corrupt
|
||||||
error("File %s is corrupt", INDEX_FILENAME);
|
error(FILE_IS_CORRUPT, INDEX_FILENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// close the file
|
// close the file
|
||||||
f.close();
|
f.close();
|
||||||
} else { // index file is corrupt
|
} else { // index file is corrupt
|
||||||
error("File %s is corrupt", INDEX_FILENAME);
|
error(FILE_IS_CORRUPT, INDEX_FILENAME);
|
||||||
}
|
}
|
||||||
} else { // cannot find the index file
|
} else { // cannot find the index file
|
||||||
error("Cannot find file %s", INDEX_FILENAME);
|
error(CANNOT_FIND_FILE, INDEX_FILENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate memory nodes and load all permanent graphics
|
// allocate memory nodes and load all permanent graphics
|
||||||
for (i = 0, pH = handleTable; i < numHandles; i++, pH++) {
|
for (i = 0, pH = handleTable; i < numHandles; i++, pH++) {
|
||||||
if (pH->filesize & fPreload) {
|
if (pH->filesize & fPreload) {
|
||||||
// allocate a fixed memory node for permanent files
|
// allocate a fixed memory node for permanent files
|
||||||
pH->pNode = MemoryAlloc(DWM_FIXED, pH->filesize & FSIZE_MASK);
|
pH->pNode = MemoryAlloc(DWM_FIXED, sizeof(MEM_NODE) + (pH->filesize & FSIZE_MASK));
|
||||||
|
|
||||||
// make sure memory allocated
|
// make sure memory allocated
|
||||||
assert(pH->pNode);
|
assert(pH->pNode);
|
||||||
|
|
||||||
|
// Initialise the MEM_NODE structure
|
||||||
|
memset(pH->pNode, 0, sizeof(MEM_NODE));
|
||||||
|
|
||||||
// load the data
|
// load the data
|
||||||
LoadFile(pH, true);
|
LoadFile(pH, true);
|
||||||
}
|
}
|
||||||
|
@ -178,8 +194,101 @@ void FreeHandleTable(void) {
|
||||||
free(handleTable);
|
free(handleTable);
|
||||||
handleTable = NULL;
|
handleTable = NULL;
|
||||||
}
|
}
|
||||||
|
if (cdGraphStream.isOpen())
|
||||||
|
cdGraphStream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a memory block as a file.
|
||||||
|
*/
|
||||||
|
void OpenCDGraphFile(void) {
|
||||||
|
if (cdGraphStream.isOpen())
|
||||||
|
cdGraphStream.close();
|
||||||
|
|
||||||
|
// As the theory goes, the right CD will be in there!
|
||||||
|
|
||||||
|
cdGraphStream.clearIOFailed();
|
||||||
|
cdGraphStream.open(szCdPlayFile);
|
||||||
|
if (cdGraphStream.ioFailed())
|
||||||
|
error(CANNOT_FIND_FILE, szCdPlayFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadCDGraphData(MEMHANDLE *pH) {
|
||||||
|
// read the data
|
||||||
|
uint bytes;
|
||||||
|
byte *addr;
|
||||||
|
int retries = 0;
|
||||||
|
|
||||||
|
assert(!(pH->filesize & fCompressed));
|
||||||
|
|
||||||
|
// Can't be preloaded
|
||||||
|
assert(!(pH->filesize & fPreload));
|
||||||
|
|
||||||
|
// discardable - lock the memory
|
||||||
|
addr = (byte *)MemoryLock(pH->pNode);
|
||||||
|
|
||||||
|
// make sure address is valid
|
||||||
|
assert(addr);
|
||||||
|
|
||||||
|
// Move to correct place in file and load the required data
|
||||||
|
cdGraphStream.seek(cdBaseHandle & OFFSETMASK, SEEK_SET);
|
||||||
|
bytes = cdGraphStream.read(addr, (cdTopHandle - cdBaseHandle) & OFFSETMASK);
|
||||||
|
|
||||||
|
// New code to try and handle CD read failures 24/2/97
|
||||||
|
while (bytes != ((cdTopHandle - cdBaseHandle) & OFFSETMASK) && retries++ < MAX_READ_RETRIES) {
|
||||||
|
// Try again
|
||||||
|
cdGraphStream.seek(cdBaseHandle & OFFSETMASK, SEEK_SET);
|
||||||
|
bytes = cdGraphStream.read(addr, (cdTopHandle - cdBaseHandle) & OFFSETMASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// discardable - unlock the memory
|
||||||
|
MemoryUnlock(pH->pNode);
|
||||||
|
|
||||||
|
// set the loaded flag
|
||||||
|
pH->filesize |= fLoaded;
|
||||||
|
|
||||||
|
// clear the loading flag
|
||||||
|
// pH->filesize &= ~fLoading;
|
||||||
|
|
||||||
|
if (bytes != ((cdTopHandle-cdBaseHandle) & OFFSETMASK))
|
||||||
|
// file is corrupt
|
||||||
|
error(FILE_READ_ERROR, "CD play file");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called immediatly preceding a CDplay().
|
||||||
|
* Prepares the ground so that when LockMem() is called, the
|
||||||
|
* appropriate section of the extra scene file is loaded.
|
||||||
|
* @param start Handle of start of range
|
||||||
|
* @param next Handle of end of range + 1
|
||||||
|
*/
|
||||||
|
void LoadExtraGraphData(SCNHANDLE start, SCNHANDLE next) {
|
||||||
|
if (cdPlayFileNum == cdPlaySceneNum && start == cdBaseHandle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OpenCDGraphFile();
|
||||||
|
|
||||||
|
if ((handleTable + cdPlayHandle)->pNode->pBaseAddr != NULL)
|
||||||
|
MemoryDiscard((handleTable + cdPlayHandle)->pNode); // Free it
|
||||||
|
|
||||||
|
// It must always be the same
|
||||||
|
assert(cdPlayHandle == (start >> SCNHANDLE_SHIFT));
|
||||||
|
assert(cdPlayHandle == (next >> SCNHANDLE_SHIFT));
|
||||||
|
|
||||||
|
cdBaseHandle = start;
|
||||||
|
cdTopHandle = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCdPlaySceneDetails(int fileNum, const char *fileName) {
|
||||||
|
cdPlaySceneNum = fileNum;
|
||||||
|
strcpy(szCdPlayFile, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCdPlayHandle(int fileNum) {
|
||||||
|
cdPlayHandle = fileNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a memory block as a file.
|
* Loads a memory block as a file.
|
||||||
* @param pH Memory block pointer
|
* @param pH Memory block pointer
|
||||||
|
@ -204,7 +313,7 @@ void LoadFile(MEMHANDLE *pH, bool bWarn) {
|
||||||
|
|
||||||
if (pH->filesize & fPreload)
|
if (pH->filesize & fPreload)
|
||||||
// preload - no need to lock the memory
|
// preload - no need to lock the memory
|
||||||
addr = (uint8 *)pH->pNode;
|
addr = (uint8 *)pH->pNode + sizeof(MEM_NODE);
|
||||||
else {
|
else {
|
||||||
// discardable - lock the memory
|
// discardable - lock the memory
|
||||||
addr = (uint8 *)MemoryLock(pH->pNode);
|
addr = (uint8 *)MemoryLock(pH->pNode);
|
||||||
|
@ -243,12 +352,12 @@ void LoadFile(MEMHANDLE *pH, bool bWarn) {
|
||||||
|
|
||||||
if (bWarn)
|
if (bWarn)
|
||||||
// file is corrupt
|
// file is corrupt
|
||||||
error("File %s is corrupt", szFilename);
|
error(FILE_IS_CORRUPT, szFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bWarn)
|
if (bWarn)
|
||||||
// cannot find file
|
// cannot find file
|
||||||
error("Cannot find file %s", szFilename);
|
error(CANNOT_FIND_FILE, szFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,8 +374,39 @@ uint8 *LockMem(SCNHANDLE offset) {
|
||||||
pH = handleTable + handle;
|
pH = handleTable + handle;
|
||||||
|
|
||||||
if (pH->filesize & fPreload) {
|
if (pH->filesize & fPreload) {
|
||||||
|
if (TinselV2)
|
||||||
|
// update the LRU time (new in this file)
|
||||||
|
pH->pNode->lruTime = DwGetCurrentTime();
|
||||||
|
|
||||||
// permanent files are already loaded
|
// permanent files are already loaded
|
||||||
return (uint8 *)pH->pNode + (offset & OFFSETMASK);
|
return (uint8 *)pH->pNode + sizeof(MEM_NODE) + (offset & OFFSETMASK);
|
||||||
|
} else if (handle == cdPlayHandle) {
|
||||||
|
// Must be in currently loaded/loadable range
|
||||||
|
if(offset < cdBaseHandle || offset >= cdTopHandle)
|
||||||
|
error("Overlapping (in time) CD-plays!");
|
||||||
|
|
||||||
|
if (pH->pNode->pBaseAddr && (pH->filesize & fLoaded))
|
||||||
|
// already allocated and loaded
|
||||||
|
return pH->pNode->pBaseAddr + ((offset - cdBaseHandle) & OFFSETMASK);
|
||||||
|
|
||||||
|
if (pH->pNode->pBaseAddr == NULL)
|
||||||
|
// must have been discarded - reallocate the memory
|
||||||
|
MemoryReAlloc(pH->pNode, cdTopHandle-cdBaseHandle,
|
||||||
|
DWM_MOVEABLE | DWM_DISCARDABLE);
|
||||||
|
|
||||||
|
if(pH->pNode->pBaseAddr == NULL)
|
||||||
|
error("Out of memory");
|
||||||
|
|
||||||
|
LoadCDGraphData(pH);
|
||||||
|
|
||||||
|
// make sure address is valid
|
||||||
|
assert(pH->pNode->pBaseAddr);
|
||||||
|
|
||||||
|
// update the LRU time (new in this file)
|
||||||
|
pH->pNode->lruTime = DwGetCurrentTime();
|
||||||
|
|
||||||
|
return pH->pNode->pBaseAddr + ((offset - cdBaseHandle) & OFFSETMASK);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (pH->pNode->pBaseAddr && (pH->filesize & fLoaded))
|
if (pH->pNode->pBaseAddr && (pH->filesize & fLoaded))
|
||||||
// already allocated and loaded
|
// already allocated and loaded
|
||||||
|
@ -312,7 +452,10 @@ void LockScene(SCNHANDLE offset) {
|
||||||
|
|
||||||
if ((pH->filesize & fPreload) == 0) {
|
if ((pH->filesize & fPreload) == 0) {
|
||||||
// change the flags for the node
|
// change the flags for the node
|
||||||
MemoryReAlloc(pH->pNode, pH->filesize & FSIZE_MASK, DWM_MOVEABLE);
|
// WORKAROUND: The original didn't include the DWM_LOCKED flag. It's being
|
||||||
|
// included because the method is 'LockScene' so it's presumed that the
|
||||||
|
// point of this was that the scene's memory block be locked
|
||||||
|
MemoryReAlloc(pH->pNode, pH->filesize & FSIZE_MASK, DWM_MOVEABLE | DWM_LOCKED);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bLockedScene = true;
|
bLockedScene = true;
|
||||||
#endif
|
#endif
|
||||||
|
@ -363,4 +506,50 @@ bool ValidHandle(SCNHANDLE offset) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TouchMem
|
||||||
|
* @param offset Handle and offset to data
|
||||||
|
*/
|
||||||
|
void TouchMem(SCNHANDLE offset) {
|
||||||
|
MEMHANDLE *pH; // points to table entry
|
||||||
|
uint32 handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use
|
||||||
|
|
||||||
|
if (offset != 0) {
|
||||||
|
pH = handleTable + handle;
|
||||||
|
|
||||||
|
// update the LRU time whether its loaded or not!
|
||||||
|
pH->pNode->lruTime = DwGetCurrentTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given handle is into the cd graph data
|
||||||
|
* @param offset Handle and offset to data
|
||||||
|
*/
|
||||||
|
bool IsCdPlayHandle(SCNHANDLE offset) {
|
||||||
|
uint32 handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use
|
||||||
|
|
||||||
|
// range check the memory handle
|
||||||
|
assert(handle < numHandles);
|
||||||
|
|
||||||
|
return (handle == cdPlayHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the CD for a given scene handle
|
||||||
|
*/
|
||||||
|
int CdNumber(SCNHANDLE offset) {
|
||||||
|
uint handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use
|
||||||
|
|
||||||
|
// range check the memory handle
|
||||||
|
assert(handle < numHandles);
|
||||||
|
|
||||||
|
MEMHANDLE *pH = handleTable + handle;
|
||||||
|
|
||||||
|
if (!TinselV2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return GetCD(pH->flags2 & fAllCds);
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -48,6 +48,23 @@ void LockScene( // Called to make the current scene non-discardable
|
||||||
void UnlockScene( // Called to make the current scene discardable again
|
void UnlockScene( // Called to make the current scene discardable again
|
||||||
SCNHANDLE offset); // handle and offset to data
|
SCNHANDLE offset); // handle and offset to data
|
||||||
|
|
||||||
|
bool IsCdPlayHandle(SCNHANDLE offset);
|
||||||
|
|
||||||
|
void TouchMem(SCNHANDLE offset);
|
||||||
|
|
||||||
|
void SetCdPlaySceneDetails( // Called at scene startup
|
||||||
|
int sceneNum,
|
||||||
|
const char *fileName);
|
||||||
|
|
||||||
|
void SetCdPlayHandle( // Called at game startup
|
||||||
|
int fileNum);
|
||||||
|
|
||||||
|
void LoadExtraGraphData(
|
||||||
|
SCNHANDLE start, // Handle of start of range
|
||||||
|
SCNHANDLE next); // Handle of end of range + 1
|
||||||
|
|
||||||
|
int CdNumber(SCNHANDLE offset);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif // TINSEL_HANDLE_H
|
#endif // TINSEL_HANDLE_H
|
||||||
|
|
|
@ -26,11 +26,13 @@
|
||||||
|
|
||||||
#include "tinsel/heapmem.h"
|
#include "tinsel/heapmem.h"
|
||||||
#include "tinsel/timers.h" // For DwGetCurrentTime
|
#include "tinsel/timers.h" // For DwGetCurrentTime
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
// minimum memory required for MS-DOS version of game
|
// Specifies the total amount of memory required for DW1 demo, DW1, or DW2 respectively.
|
||||||
#define MIN_MEM 2506752L
|
// Currently this is set at 10Mb for all three - this could probably be reduced somewhat
|
||||||
|
uint32 MemoryPoolSize[3] = {10 * 1024 * 1024, 10 * 1024 * 1024, 10 * 1024 * 1024};
|
||||||
|
|
||||||
// list of all memory nodes
|
// list of all memory nodes
|
||||||
MEM_NODE mnodeList[NUM_MNODES];
|
MEM_NODE mnodeList[NUM_MNODES];
|
||||||
|
@ -73,8 +75,10 @@ void MemoryInit(void) {
|
||||||
// null the last mnode
|
// null the last mnode
|
||||||
mnodeList[NUM_MNODES - 1].pNext = NULL;
|
mnodeList[NUM_MNODES - 1].pNext = NULL;
|
||||||
|
|
||||||
// allocatea big chunk of memory
|
// allocates a big chunk of memory
|
||||||
const uint32 size = 2*MIN_MEM+655360L;
|
uint32 size = MemoryPoolSize[0];
|
||||||
|
if (TinselVersion == TINSEL_V1) size = MemoryPoolSize[1];
|
||||||
|
else if (TinselVersion == TINSEL_V2) size = MemoryPoolSize[2];
|
||||||
uint8 *mem = (uint8 *)malloc(size);
|
uint8 *mem = (uint8 *)malloc(size);
|
||||||
assert(mem);
|
assert(mem);
|
||||||
|
|
||||||
|
@ -274,8 +278,9 @@ MEM_NODE *MemoryAlloc(int flags, long size) {
|
||||||
bool bCompacted = true; // set when heap has been compacted
|
bool bCompacted = true; // set when heap has been compacted
|
||||||
|
|
||||||
// compact the heap if we are allocating fixed memory
|
// compact the heap if we are allocating fixed memory
|
||||||
if (flags & DWM_FIXED)
|
if (flags & DWM_FIXED) {
|
||||||
HeapCompact(MAX_INT, false);
|
HeapCompact(MAX_INT, false);
|
||||||
|
}
|
||||||
|
|
||||||
while ((flags & DWM_NOALLOC) == 0 && bCompacted) {
|
while ((flags & DWM_NOALLOC) == 0 && bCompacted) {
|
||||||
// search the heap for a free block
|
// search the heap for a free block
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
* Functions to set up moving actors' reels.
|
* Functions to set up moving actors' reels.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "tinsel/handle.h"
|
||||||
#include "tinsel/pcode.h" // For D_UP, D_DOWN
|
#include "tinsel/pcode.h" // For D_UP, D_DOWN
|
||||||
#include "tinsel/rince.h"
|
#include "tinsel/rince.h"
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ namespace Tinsel {
|
||||||
//----------------- LOCAL GLOBAL DATA --------------------
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NUM_INTERVALS = NUM_MAINSCALES - 1,
|
NUM_INTERVALS = REQ_MAIN_SCALES - 1,
|
||||||
|
|
||||||
// 2 for up and down, 3 allow enough entries for 3 fully subscribed moving actors' worth
|
// 2 for up and down, 3 allow enough entries for 3 fully subscribed moving actors' worth
|
||||||
MAX_SCRENTRIES = NUM_INTERVALS*2*3
|
MAX_SCRENTRIES = NUM_INTERVALS*2*3
|
||||||
|
@ -51,36 +52,80 @@ static SCIdataStruct SCIdata[MAX_SCRENTRIES];
|
||||||
|
|
||||||
static int scrEntries = 0;
|
static int scrEntries = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an actor's walk reels
|
||||||
|
*/
|
||||||
|
|
||||||
|
void SetWalkReels(PMOVER pMover, int scale,
|
||||||
|
SCNHANDLE al, SCNHANDLE ar, SCNHANDLE af, SCNHANDLE aa) {
|
||||||
|
assert(scale > 0 && scale <= TOTAL_SCALES);
|
||||||
|
|
||||||
|
pMover->walkReels[scale-1][LEFTREEL] = al;
|
||||||
|
pMover->walkReels[scale-1][RIGHTREEL] = ar;
|
||||||
|
pMover->walkReels[scale-1][FORWARD] = af;
|
||||||
|
pMover->walkReels[scale-1][AWAY] = aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an actor's stand reels
|
||||||
|
*/
|
||||||
|
|
||||||
|
void SetStandReels(PMOVER pMover, int scale,
|
||||||
|
SCNHANDLE al, SCNHANDLE ar, SCNHANDLE af, SCNHANDLE aa) {
|
||||||
|
assert(scale > 0 && scale <= TOTAL_SCALES);
|
||||||
|
|
||||||
|
pMover->standReels[scale-1][LEFTREEL] = al;
|
||||||
|
pMover->standReels[scale-1][RIGHTREEL] = ar;
|
||||||
|
pMover->standReels[scale-1][FORWARD] = af;
|
||||||
|
pMover->standReels[scale-1][AWAY] = aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an actor's talk reels
|
||||||
|
*/
|
||||||
|
|
||||||
|
void SetTalkReels(PMOVER pMover, int scale,
|
||||||
|
SCNHANDLE al, SCNHANDLE ar, SCNHANDLE af, SCNHANDLE aa) {
|
||||||
|
assert(scale > 0 && scale <= TOTAL_SCALES);
|
||||||
|
|
||||||
|
pMover->talkReels[scale-1][LEFTREEL] = al;
|
||||||
|
pMover->talkReels[scale-1][RIGHTREEL] = ar;
|
||||||
|
pMover->talkReels[scale-1][FORWARD] = af;
|
||||||
|
pMover->talkReels[scale-1][AWAY] = aa;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return handle to actor's talk reel at present scale and direction.
|
* Return handle to actor's talk reel at present scale and direction.
|
||||||
*/
|
*/
|
||||||
SCNHANDLE GetMactorTalkReel(PMACTOR pActor, TFTYPE dirn) {
|
SCNHANDLE GetMoverTalkReel(PMOVER pActor, TFTYPE dirn) {
|
||||||
assert(1 <= pActor->scale && pActor->scale <= TOTAL_SCALES);
|
assert(1 <= pActor->scale && pActor->scale <= TOTAL_SCALES);
|
||||||
switch (dirn) {
|
switch (dirn) {
|
||||||
case TF_NONE:
|
case TF_NONE:
|
||||||
return pActor->TalkReels[pActor->scale-1][pActor->dirn];
|
return pActor->talkReels[pActor->scale-1][pActor->direction];
|
||||||
|
|
||||||
case TF_UP:
|
case TF_UP:
|
||||||
return pActor->TalkReels[pActor->scale-1][AWAY];
|
return pActor->talkReels[pActor->scale-1][AWAY];
|
||||||
|
|
||||||
case TF_DOWN:
|
case TF_DOWN:
|
||||||
return pActor->TalkReels[pActor->scale-1][FORWARD];
|
return pActor->talkReels[pActor->scale-1][FORWARD];
|
||||||
|
|
||||||
case TF_LEFT:
|
case TF_LEFT:
|
||||||
return pActor->TalkReels[pActor->scale-1][LEFTREEL];
|
return pActor->talkReels[pActor->scale-1][LEFTREEL];
|
||||||
|
|
||||||
case TF_RIGHT:
|
case TF_RIGHT:
|
||||||
return pActor->TalkReels[pActor->scale-1][RIGHTREEL];
|
return pActor->talkReels[pActor->scale-1][RIGHTREEL];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error("GetMactorTalkReel() - illegal direction!");
|
error("GetMoverTalkReel() - illegal direction!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scalingreels
|
* scalingreels
|
||||||
*/
|
*/
|
||||||
void setscalingreels(int actor, int scale, int direction,
|
void SetScalingReels(int actor, int scale, int direction,
|
||||||
SCNHANDLE left, SCNHANDLE right, SCNHANDLE forward, SCNHANDLE away) {
|
SCNHANDLE left, SCNHANDLE right, SCNHANDLE forward, SCNHANDLE away) {
|
||||||
assert(scale >= 1 && scale <= NUM_MAINSCALES); // invalid scale
|
assert(scale >= 1 && scale <= NUM_MAINSCALES); // invalid scale
|
||||||
assert(!(scale == 1 && direction == D_UP) &&
|
assert(!(scale == 1 && direction == D_UP) &&
|
||||||
|
@ -101,7 +146,7 @@ void setscalingreels(int actor, int scale, int direction,
|
||||||
/**
|
/**
|
||||||
* ScalingReel
|
* ScalingReel
|
||||||
*/
|
*/
|
||||||
SCNHANDLE ScalingReel(int ano, int scale1, int scale2, DIRREEL reel) {
|
SCNHANDLE ScalingReel(int ano, int scale1, int scale2, DIRECTION reel) {
|
||||||
int d; // Direction
|
int d; // Direction
|
||||||
|
|
||||||
// The smaller the number, the bigger the scale
|
// The smaller the number, the bigger the scale
|
||||||
|
@ -129,4 +174,20 @@ void RebootScalingReels(void) {
|
||||||
memset(SCIdata, 0, sizeof(SCIdata));
|
memset(SCIdata, 0, sizeof(SCIdata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discourage them from being ditched.
|
||||||
|
*/
|
||||||
|
void TouchMoverReels(void) {
|
||||||
|
PMOVER pMover;
|
||||||
|
int scale;
|
||||||
|
|
||||||
|
pMover = NextMover(NULL);
|
||||||
|
|
||||||
|
do {
|
||||||
|
for (scale = 0; scale < TOTAL_SCALES; scale++) {
|
||||||
|
TouchMem(pMover->walkReels[scale][LEFTREEL]);
|
||||||
|
}
|
||||||
|
} while ((pMover = NextMover(pMover)) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
56
engines/tinsel/mareels.h
Normal file
56
engines/tinsel/mareels.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TINSEL_MAREELS_H // prevent multiple includes
|
||||||
|
#define TINSEL_MAREELS_H
|
||||||
|
|
||||||
|
#include "tinsel/dw.h" // for SCNHANDLE
|
||||||
|
#include "tinsel/rince.h"
|
||||||
|
|
||||||
|
namespace Tinsel {
|
||||||
|
|
||||||
|
void SetWalkReels(PMOVER pMover, int scale,
|
||||||
|
SCNHANDLE al, SCNHANDLE ar, SCNHANDLE af, SCNHANDLE aa);
|
||||||
|
|
||||||
|
void SetStandReels(PMOVER pMover, int scale,
|
||||||
|
SCNHANDLE al, SCNHANDLE ar, SCNHANDLE af, SCNHANDLE aa);
|
||||||
|
|
||||||
|
void SetTalkReels(PMOVER pMover, int scale,
|
||||||
|
SCNHANDLE al, SCNHANDLE ar, SCNHANDLE af, SCNHANDLE aa);
|
||||||
|
|
||||||
|
SCNHANDLE GetMoverTalkReel(PMOVER pActor, TFTYPE dirn);
|
||||||
|
|
||||||
|
void SetScalingReels(int actor, int scale, int direction,
|
||||||
|
SCNHANDLE left, SCNHANDLE right, SCNHANDLE forward, SCNHANDLE away);
|
||||||
|
|
||||||
|
SCNHANDLE ScalingReel(int ano, int scale1, int scale2, DIRECTION reel);
|
||||||
|
|
||||||
|
void RebootScalingReels(void);
|
||||||
|
|
||||||
|
void TouchMoverReels(void);
|
||||||
|
|
||||||
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,11 +5,14 @@ MODULE_OBJS = \
|
||||||
anim.o \
|
anim.o \
|
||||||
background.o \
|
background.o \
|
||||||
bg.o \
|
bg.o \
|
||||||
|
bmv.o \
|
||||||
cliprect.o \
|
cliprect.o \
|
||||||
config.o \
|
config.o \
|
||||||
cursor.o \
|
cursor.o \
|
||||||
debugger.o \
|
debugger.o \
|
||||||
detection.o \
|
detection.o \
|
||||||
|
dialogs.o \
|
||||||
|
drives.o \
|
||||||
effect.o \
|
effect.o \
|
||||||
events.o \
|
events.o \
|
||||||
faders.o \
|
faders.o \
|
||||||
|
@ -17,7 +20,6 @@ MODULE_OBJS = \
|
||||||
graphics.o \
|
graphics.o \
|
||||||
handle.o \
|
handle.o \
|
||||||
heapmem.o \
|
heapmem.o \
|
||||||
inventory.o \
|
|
||||||
mareels.o \
|
mareels.o \
|
||||||
move.o \
|
move.o \
|
||||||
multiobj.o \
|
multiobj.o \
|
||||||
|
@ -37,6 +39,7 @@ MODULE_OBJS = \
|
||||||
scroll.o \
|
scroll.o \
|
||||||
sound.o \
|
sound.o \
|
||||||
strres.o \
|
strres.o \
|
||||||
|
sysvar.o \
|
||||||
text.o \
|
text.o \
|
||||||
timers.o \
|
timers.o \
|
||||||
tinlib.o \
|
tinlib.o \
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,17 +27,24 @@
|
||||||
#define TINSEL_MOVE_H
|
#define TINSEL_MOVE_H
|
||||||
|
|
||||||
#include "tinsel/dw.h" // for SCNHANDLE
|
#include "tinsel/dw.h" // for SCNHANDLE
|
||||||
|
#include "tinsel/rince.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
struct MACTOR;
|
struct MOVER;
|
||||||
|
|
||||||
void SetActorDest(MACTOR *pActor, int x, int y, bool igPath, SCNHANDLE film);
|
typedef enum { YB_X2, YB_X1_5 } YBIAS;
|
||||||
void SSetActorDest(MACTOR *pActor);
|
|
||||||
void DoMoveActor(MACTOR *pActor);
|
int SetActorDest(MOVER *pMover, int x, int y, bool igPath, SCNHANDLE film);
|
||||||
|
void SSetActorDest(MOVER *pActor);
|
||||||
|
void DoMoveActor(MOVER *pMover);
|
||||||
|
|
||||||
void SetDefaultRefer(int32 defRefer);
|
void SetDefaultRefer(int32 defRefer);
|
||||||
|
int GetLastLeadXdest(void);
|
||||||
|
int GetLastLeadYdest(void);
|
||||||
|
|
||||||
|
DIRECTION GetDirection(int fromx, int fromy, int tox, int toy, DIRECTION lastreel,
|
||||||
|
HPOLYGON hPath, YBIAS yBias = YB_X2);
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif /* TINSEL_MOVE_H */
|
#endif /* TINSEL_MOVE_H */
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "tinsel/multiobj.h"
|
#include "tinsel/multiobj.h"
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
#include "tinsel/object.h"
|
#include "tinsel/object.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -204,6 +205,8 @@ void MultiAdjustXY(OBJECT *pMultiObj, int deltaX, int deltaY) {
|
||||||
if (deltaX == 0 && deltaY == 0)
|
if (deltaX == 0 && deltaY == 0)
|
||||||
return; // ignore no change
|
return; // ignore no change
|
||||||
|
|
||||||
|
if (!TinselV2) {
|
||||||
|
// *** This may be wrong!!!
|
||||||
if (pMultiObj->flags & DMA_FLIPH) {
|
if (pMultiObj->flags & DMA_FLIPH) {
|
||||||
// image is flipped horizontally - flip the x direction
|
// image is flipped horizontally - flip the x direction
|
||||||
deltaX = -deltaX;
|
deltaX = -deltaX;
|
||||||
|
@ -213,6 +216,7 @@ void MultiAdjustXY(OBJECT *pMultiObj, int deltaX, int deltaY) {
|
||||||
// image is flipped vertically - flip the y direction
|
// image is flipped vertically - flip the y direction
|
||||||
deltaY = -deltaY;
|
deltaY = -deltaY;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// for all the objects that make up this multi-part
|
// for all the objects that make up this multi-part
|
||||||
do {
|
do {
|
||||||
|
@ -530,4 +534,32 @@ int MultiLowest(OBJECT *pMulti) {
|
||||||
return lowest - 1;
|
return lowest - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns TRUE if the object currently has an image.
|
||||||
|
* @param pMulti Multi-part object
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool MultiHasShape(POBJECT pMulti) {
|
||||||
|
return (pMulti->hShape != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bodge for text on movies. Makes sure it appears for it's lifetime.
|
||||||
|
* @param pMultiObj Multi-part object to be adjusted
|
||||||
|
*/
|
||||||
|
|
||||||
|
void MultiForceRedraw(POBJECT pMultiObj) {
|
||||||
|
// validate object pointer
|
||||||
|
assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1);
|
||||||
|
|
||||||
|
// for all the objects that make up this multi-part
|
||||||
|
do {
|
||||||
|
// signal a change in the object
|
||||||
|
pMultiObj->flags |= DMA_CHANGED;
|
||||||
|
|
||||||
|
// next obj in list
|
||||||
|
pMultiObj = pMultiObj->pSlave;
|
||||||
|
} while (pMultiObj != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define TINSEL_MULTIOBJ_H
|
#define TINSEL_MULTIOBJ_H
|
||||||
|
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
|
#include "tinsel/object.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -45,7 +46,9 @@ struct MULTI_INIT {
|
||||||
int32 mulX; //!< multi-objects initial x ani position
|
int32 mulX; //!< multi-objects initial x ani position
|
||||||
int32 mulY; //!< multi-objects initial y ani position
|
int32 mulY; //!< multi-objects initial y ani position
|
||||||
int32 mulZ; //!< multi-objects initial z position
|
int32 mulZ; //!< multi-objects initial z position
|
||||||
|
uint32 otherFlags; //!< multi-objects Tinsel 2 - other flags
|
||||||
} PACKED_STRUCT;
|
} PACKED_STRUCT;
|
||||||
|
typedef MULTI_INIT *PMULTI_INIT;
|
||||||
|
|
||||||
#include "common/pack-end.h" // END STRUCT PACKING
|
#include "common/pack-end.h" // END STRUCT PACKING
|
||||||
|
|
||||||
|
@ -119,6 +122,12 @@ int MultiHighest( // Returns the highest point of a multi-part object
|
||||||
int MultiLowest( // Returns the lowest point of a multi-part object
|
int MultiLowest( // Returns the lowest point of a multi-part object
|
||||||
OBJECT *pMulti); // multi-part object
|
OBJECT *pMulti); // multi-part object
|
||||||
|
|
||||||
|
bool MultiHasShape( // Returns TRUE if the object currently has an image
|
||||||
|
POBJECT pMulti); // multi-part object
|
||||||
|
|
||||||
|
void MultiForceRedraw(
|
||||||
|
POBJECT pMultiObj); // multi-part object to be forced
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif // TINSEL_MULTIOBJ_H
|
#endif // TINSEL_MULTIOBJ_H
|
||||||
|
|
|
@ -31,12 +31,21 @@
|
||||||
#include "sound/mididrv.h"
|
#include "sound/mididrv.h"
|
||||||
#include "sound/midiparser.h"
|
#include "sound/midiparser.h"
|
||||||
#include "sound/audiocd.h"
|
#include "sound/audiocd.h"
|
||||||
|
#include "sound/adpcm.h"
|
||||||
#include "common/config-manager.h"
|
#include "common/config-manager.h"
|
||||||
#include "common/file.h"
|
#include "common/file.h"
|
||||||
|
|
||||||
#include "tinsel/config.h"
|
#include "tinsel/config.h"
|
||||||
#include "tinsel/sound.h"
|
#include "tinsel/sound.h"
|
||||||
#include "tinsel/music.h"
|
#include "tinsel/music.h"
|
||||||
|
#include "tinsel/handle.h"
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
|
|
||||||
|
#define MUSIC_JUMP (-1)
|
||||||
|
#define MUSIC_END (-2)
|
||||||
|
#define BLMAGIC (-3458)
|
||||||
|
|
||||||
|
#define DIM_SPEED 8
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -153,8 +162,8 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
||||||
currentMidi = dwFileOffset;
|
currentMidi = dwFileOffset;
|
||||||
currentLoop = bLoop;
|
currentLoop = bLoop;
|
||||||
|
|
||||||
if (volMidi != 0) {
|
if (volMusic != 0) {
|
||||||
SetMidiVolume(volMidi);
|
SetMidiVolume(volMusic);
|
||||||
// Support for compressed music from the music enhancement project
|
// Support for compressed music from the music enhancement project
|
||||||
AudioCD.stop();
|
AudioCD.stop();
|
||||||
|
|
||||||
|
@ -191,7 +200,7 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
||||||
|
|
||||||
// open MIDI sequence file in binary mode
|
// open MIDI sequence file in binary mode
|
||||||
if (!midiStream.open(MIDI_FILE))
|
if (!midiStream.open(MIDI_FILE))
|
||||||
error("Cannot find file %s", MIDI_FILE);
|
error(CANNOT_FIND_FILE, MIDI_FILE);
|
||||||
|
|
||||||
// update index of last tune loaded
|
// update index of last tune loaded
|
||||||
dwLastMidiIndex = dwMidiIndex;
|
dwLastMidiIndex = dwMidiIndex;
|
||||||
|
@ -206,22 +215,22 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
||||||
assert(dwSeqLen > 0 && dwSeqLen <= midiBuffer.size);
|
assert(dwSeqLen > 0 && dwSeqLen <= midiBuffer.size);
|
||||||
|
|
||||||
// stop any currently playing tune
|
// stop any currently playing tune
|
||||||
_vm->_music->stop();
|
_vm->_midiMusic->stop();
|
||||||
|
|
||||||
// read the sequence
|
// read the sequence
|
||||||
if (midiStream.read(midiBuffer.pDat, dwSeqLen) != dwSeqLen)
|
if (midiStream.read(midiBuffer.pDat, dwSeqLen) != dwSeqLen)
|
||||||
error("File %s is corrupt", MIDI_FILE);
|
error(FILE_IS_CORRUPT, MIDI_FILE);
|
||||||
|
|
||||||
midiStream.close();
|
midiStream.close();
|
||||||
|
|
||||||
_vm->_music->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
_vm->_midiMusic->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
||||||
|
|
||||||
// Store the length
|
// Store the length
|
||||||
dwLastSeqLen = dwSeqLen;
|
dwLastSeqLen = dwSeqLen;
|
||||||
} else {
|
} else {
|
||||||
// dwMidiIndex == dwLastMidiIndex
|
// dwMidiIndex == dwLastMidiIndex
|
||||||
_vm->_music->stop();
|
_vm->_midiMusic->stop();
|
||||||
_vm->_music->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
_vm->_midiMusic->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow another sequence to play
|
// allow another sequence to play
|
||||||
|
@ -235,7 +244,7 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
||||||
*/
|
*/
|
||||||
bool MidiPlaying(void) {
|
bool MidiPlaying(void) {
|
||||||
if (AudioCD.isPlaying()) return true;
|
if (AudioCD.isPlaying()) return true;
|
||||||
return _vm->_music->isPlaying();
|
return _vm->_midiMusic->isPlaying();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,7 +255,7 @@ bool StopMidi(void) {
|
||||||
currentLoop = false;
|
currentLoop = false;
|
||||||
|
|
||||||
AudioCD.stop();
|
AudioCD.stop();
|
||||||
_vm->_music->stop();
|
_vm->_midiMusic->stop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +264,7 @@ bool StopMidi(void) {
|
||||||
* Gets the volume of the MIDI music.
|
* Gets the volume of the MIDI music.
|
||||||
*/
|
*/
|
||||||
int GetMidiVolume() {
|
int GetMidiVolume() {
|
||||||
return volMidi;
|
return volMusic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,24 +274,24 @@ int GetMidiVolume() {
|
||||||
void SetMidiVolume(int vol) {
|
void SetMidiVolume(int vol) {
|
||||||
assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume);
|
assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume);
|
||||||
|
|
||||||
if (vol == 0 && volMidi == 0) {
|
if (vol == 0 && volMusic == 0) {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
} else if (vol == 0 && volMidi != 0) {
|
} else if (vol == 0 && volMusic != 0) {
|
||||||
// Stop current midi sequence
|
// Stop current midi sequence
|
||||||
AudioCD.stop();
|
AudioCD.stop();
|
||||||
StopMidi();
|
StopMidi();
|
||||||
} else if (vol != 0 && volMidi == 0) {
|
} else if (vol != 0 && volMusic == 0) {
|
||||||
// Perhaps restart last midi sequence
|
// Perhaps restart last midi sequence
|
||||||
if (currentLoop) {
|
if (currentLoop) {
|
||||||
PlayMidiSequence(currentMidi, true);
|
PlayMidiSequence(currentMidi, true);
|
||||||
_vm->_music->setVolume(vol);
|
_vm->_midiMusic->setVolume(vol);
|
||||||
}
|
}
|
||||||
} else if (vol != 0 && volMidi != 0) {
|
} else if (vol != 0 && volMusic != 0) {
|
||||||
// Alter current volume
|
// Alter current volume
|
||||||
_vm->_music->setVolume(vol);
|
_vm->_midiMusic->setVolume(vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
volMidi = vol;
|
volMusic = vol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -292,7 +301,7 @@ void OpenMidiFiles(void) {
|
||||||
Common::File midiStream;
|
Common::File midiStream;
|
||||||
|
|
||||||
// Demo version has no midi file
|
// Demo version has no midi file
|
||||||
if (_vm->getFeatures() & GF_DEMO)
|
if ((_vm->getFeatures() & GF_DEMO) || (TinselVersion == TINSEL_V2))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (midiBuffer.pDat)
|
if (midiBuffer.pDat)
|
||||||
|
@ -301,12 +310,12 @@ void OpenMidiFiles(void) {
|
||||||
|
|
||||||
// open MIDI sequence file in binary mode
|
// open MIDI sequence file in binary mode
|
||||||
if (!midiStream.open(MIDI_FILE))
|
if (!midiStream.open(MIDI_FILE))
|
||||||
error("Cannot find file %s", MIDI_FILE);
|
error(CANNOT_FIND_FILE, MIDI_FILE);
|
||||||
|
|
||||||
// gen length of the largest sequence
|
// gen length of the largest sequence
|
||||||
midiBuffer.size = midiStream.readUint32LE();
|
midiBuffer.size = midiStream.readUint32LE();
|
||||||
if (midiStream.ioFailed())
|
if (midiStream.ioFailed())
|
||||||
error("File %s is corrupt", MIDI_FILE);
|
error(FILE_IS_CORRUPT, MIDI_FILE);
|
||||||
|
|
||||||
if (midiBuffer.size) {
|
if (midiBuffer.size) {
|
||||||
// allocate a buffer big enough for the largest MIDI sequence
|
// allocate a buffer big enough for the largest MIDI sequence
|
||||||
|
@ -327,14 +336,14 @@ void DeleteMidiBuffer() {
|
||||||
midiBuffer.pDat = NULL;
|
midiBuffer.pDat = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false) {
|
MidiMusicPlayer::MidiMusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false) {
|
||||||
memset(_channel, 0, sizeof(_channel));
|
memset(_channel, 0, sizeof(_channel));
|
||||||
_masterVolume = 0;
|
_masterVolume = 0;
|
||||||
this->open();
|
this->open();
|
||||||
_xmidiParser = MidiParser::createParser_XMIDI();
|
_xmidiParser = MidiParser::createParser_XMIDI();
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicPlayer::~MusicPlayer() {
|
MidiMusicPlayer::~MidiMusicPlayer() {
|
||||||
_driver->setTimerCallback(NULL, NULL);
|
_driver->setTimerCallback(NULL, NULL);
|
||||||
stop();
|
stop();
|
||||||
this->close();
|
this->close();
|
||||||
|
@ -342,7 +351,7 @@ MusicPlayer::~MusicPlayer() {
|
||||||
delete _xmidiParser;
|
delete _xmidiParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::setVolume(int volume) {
|
void MidiMusicPlayer::setVolume(int volume) {
|
||||||
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
|
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
|
||||||
|
|
||||||
if (_masterVolume == volume)
|
if (_masterVolume == volume)
|
||||||
|
@ -359,7 +368,7 @@ void MusicPlayer::setVolume(int volume) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int MusicPlayer::open() {
|
int MidiMusicPlayer::open() {
|
||||||
// Don't ever call open without first setting the output driver!
|
// Don't ever call open without first setting the output driver!
|
||||||
if (!_driver)
|
if (!_driver)
|
||||||
return 255;
|
return 255;
|
||||||
|
@ -372,14 +381,14 @@ int MusicPlayer::open() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::close() {
|
void MidiMusicPlayer::close() {
|
||||||
stop();
|
stop();
|
||||||
if (_driver)
|
if (_driver)
|
||||||
_driver->close();
|
_driver->close();
|
||||||
_driver = 0;
|
_driver = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::send(uint32 b) {
|
void MidiMusicPlayer::send(uint32 b) {
|
||||||
byte channel = (byte)(b & 0x0F);
|
byte channel = (byte)(b & 0x0F);
|
||||||
if ((b & 0xFFF0) == 0x07B0) {
|
if ((b & 0xFFF0) == 0x07B0) {
|
||||||
// Adjust volume changes by master volume
|
// Adjust volume changes by master volume
|
||||||
|
@ -409,7 +418,7 @@ void MusicPlayer::send(uint32 b) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
|
void MidiMusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0x2F: // End of Track
|
case 0x2F: // End of Track
|
||||||
if (_looping)
|
if (_looping)
|
||||||
|
@ -423,15 +432,15 @@ void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::onTimer(void *refCon) {
|
void MidiMusicPlayer::onTimer(void *refCon) {
|
||||||
MusicPlayer *music = (MusicPlayer *)refCon;
|
MidiMusicPlayer *music = (MidiMusicPlayer *)refCon;
|
||||||
Common::StackLock lock(music->_mutex);
|
Common::StackLock lock(music->_mutex);
|
||||||
|
|
||||||
if (music->_isPlaying)
|
if (music->_isPlaying)
|
||||||
music->_parser->onTimer();
|
music->_parser->onTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
|
void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
|
||||||
if (_isPlaying)
|
if (_isPlaying)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -463,7 +472,7 @@ void MusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::stop() {
|
void MidiMusicPlayer::stop() {
|
||||||
Common::StackLock lock(_mutex);
|
Common::StackLock lock(_mutex);
|
||||||
|
|
||||||
_isPlaying = false;
|
_isPlaying = false;
|
||||||
|
@ -473,16 +482,414 @@ void MusicPlayer::stop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::pause() {
|
void MidiMusicPlayer::pause() {
|
||||||
setVolume(-1);
|
setVolume(-1);
|
||||||
_isPlaying = false;
|
_isPlaying = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicPlayer::resume() {
|
void MidiMusicPlayer::resume() {
|
||||||
setVolume(GetMidiVolume());
|
setVolume(GetMidiVolume());
|
||||||
_isPlaying = true;
|
_isPlaying = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PCMMusicPlayer::PCMMusicPlayer() {
|
||||||
|
_silenceSamples = 0;
|
||||||
|
|
||||||
|
_curChunk = 0;
|
||||||
|
_fileName = 0;
|
||||||
|
_state = S_IDLE;
|
||||||
|
_mState = S_IDLE;
|
||||||
|
_scriptNum = -1;
|
||||||
|
_scriptIndex = 0;
|
||||||
|
_forcePlay = false;
|
||||||
|
|
||||||
|
_volume = 255;
|
||||||
|
_dimmed = false;
|
||||||
|
_dimmedTinsel = false;
|
||||||
|
_dimIteration = 0;
|
||||||
|
|
||||||
|
_fadeOutVolume = 0;
|
||||||
|
_fadeOutIteration = 0;
|
||||||
|
|
||||||
|
_end = true;
|
||||||
|
|
||||||
|
_vm->_mixer->playInputStream(Audio::Mixer::kMusicSoundType,
|
||||||
|
&_handle, this, -1, _volume, 0, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
PCMMusicPlayer::~PCMMusicPlayer() {
|
||||||
|
_vm->_mixer->stopHandle(_handle);
|
||||||
|
|
||||||
|
delete[] _fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::startPlay(int id) {
|
||||||
|
if (!_fileName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugMusic, "Playing PCM music %s, index %d", _fileName, id);
|
||||||
|
|
||||||
|
Common::StackLock slock(_mutex);
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
_scriptNum = id;
|
||||||
|
_scriptIndex = 1;
|
||||||
|
_state = S_NEW;
|
||||||
|
|
||||||
|
play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::stopPlay() {
|
||||||
|
Common::StackLock slock(_mutex);
|
||||||
|
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int PCMMusicPlayer::readBuffer(int16 *buffer, const int numSamples) {
|
||||||
|
Common::StackLock slock(_mutex);
|
||||||
|
|
||||||
|
if (!_curChunk && ((_state == S_IDLE) || (_state == S_STOP)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int samplesLeft = numSamples;
|
||||||
|
|
||||||
|
while (samplesLeft > 0) {
|
||||||
|
if (_silenceSamples > 0) {
|
||||||
|
int n = MIN(_silenceSamples, samplesLeft);
|
||||||
|
|
||||||
|
memset(buffer, 0, n);
|
||||||
|
|
||||||
|
buffer += n;
|
||||||
|
_silenceSamples -= n;
|
||||||
|
samplesLeft -= n;
|
||||||
|
|
||||||
|
} else if (_curChunk &&
|
||||||
|
((_state == S_MID) || (_state == S_NEXT) || (_state == S_NEW))) {
|
||||||
|
int n = _curChunk->readBuffer(buffer, samplesLeft);
|
||||||
|
|
||||||
|
buffer += n;
|
||||||
|
samplesLeft -= n;
|
||||||
|
|
||||||
|
if (_curChunk->endOfData()) {
|
||||||
|
_state = S_END1;
|
||||||
|
|
||||||
|
delete _curChunk;
|
||||||
|
_curChunk = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (!getNextChunk())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (numSamples - samplesLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PCMMusicPlayer::isPlaying() const {
|
||||||
|
return ((_state != S_IDLE) && (_state != S_STOP));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PCMMusicPlayer::isDimmed() const {
|
||||||
|
return _dimmed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::getTunePlaying(void *voidPtr, int length) {
|
||||||
|
Common::StackLock lock(_mutex);
|
||||||
|
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugMusic, "getTunePlaying");
|
||||||
|
|
||||||
|
assert(length == (3 * sizeof(int32)));
|
||||||
|
|
||||||
|
int32 *p = (int32 *) voidPtr;
|
||||||
|
|
||||||
|
_mState = _state;
|
||||||
|
|
||||||
|
p[0] = (int32) _mState;
|
||||||
|
p[1] = _scriptNum;
|
||||||
|
p[2] = _scriptIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::restoreThatTune(void *voidPtr) {
|
||||||
|
Common::StackLock lock(_mutex);
|
||||||
|
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugMusic, "restoreThatTune");
|
||||||
|
|
||||||
|
int32 *p = (int32 *) voidPtr;
|
||||||
|
|
||||||
|
_mState = (State) p[0];
|
||||||
|
_scriptNum = p[1];
|
||||||
|
_scriptIndex = p[2];
|
||||||
|
|
||||||
|
if (_mState != S_IDLE)
|
||||||
|
_state = S_NEW;
|
||||||
|
|
||||||
|
delete _curChunk;
|
||||||
|
_curChunk = 0;
|
||||||
|
|
||||||
|
_end = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::setMusicSceneDetails(SCNHANDLE hScript,
|
||||||
|
SCNHANDLE hSegment, const char *fileName) {
|
||||||
|
|
||||||
|
Common::StackLock lock(_mutex);
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
debugC(DEBUG_INTERMEDIATE, kTinselDebugMusic, "Setting music scene details: %s", fileName);
|
||||||
|
|
||||||
|
_hScript = hScript;
|
||||||
|
_hSegment = hSegment;
|
||||||
|
_fileName = new char[strlen(fileName) + 1];
|
||||||
|
strcpy(_fileName, fileName);
|
||||||
|
|
||||||
|
// Start scene with music not dimmed
|
||||||
|
_dimmed = false;
|
||||||
|
_dimmedTinsel = false;
|
||||||
|
_dimIteration = 0;
|
||||||
|
setVol(255);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::setVolume(int volume) {
|
||||||
|
assert((volume >= 0) && (volume <= 100));
|
||||||
|
|
||||||
|
_dimmed = false;
|
||||||
|
setVol((volume * 255) / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::setVol(uint8 volume) {
|
||||||
|
_volume = volume;
|
||||||
|
|
||||||
|
_vm->_mixer->setChannelVolume(_handle, _volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PCMMusicPlayer::getMusicTinselDimmed() const {
|
||||||
|
return _dimmedTinsel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::dim(bool bTinselDim) {
|
||||||
|
if (_dimmed || (_volume == 0) ||
|
||||||
|
(_state == S_IDLE) || !_curChunk || (SysVar(SV_MUSICDIMFACTOR) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_dimmed = true;
|
||||||
|
if (bTinselDim)
|
||||||
|
_dimmedTinsel = true;
|
||||||
|
|
||||||
|
_dimmedVolume = _volume - (_volume / SysVar(SV_MUSICDIMFACTOR));
|
||||||
|
|
||||||
|
// Iterate down, negative iteration
|
||||||
|
if (!_dimIteration)
|
||||||
|
_dimPosition = _volume;
|
||||||
|
_dimIteration = (_dimmedVolume - _volume)/DIM_SPEED;
|
||||||
|
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugMusic, "Dimming music from %d to %d, steps %d", _dimPosition, _dimmedVolume, _dimIteration);
|
||||||
|
|
||||||
|
// And SFX
|
||||||
|
if (SysVar(SYS_SceneFxDimFactor))
|
||||||
|
_vm->_sound->setSFXVolumes(255 - 255/SysVar(SYS_SceneFxDimFactor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::unDim(bool bTinselUnDim) {
|
||||||
|
if (!_dimmed || (_dimmedTinsel && !bTinselUnDim))
|
||||||
|
return; // not dimmed
|
||||||
|
|
||||||
|
_dimmed = _dimmedTinsel = false;
|
||||||
|
|
||||||
|
if ((_volume == 0) || (_state == S_IDLE) || !_curChunk)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Iterate up, positive iteration
|
||||||
|
if (!_dimIteration)
|
||||||
|
_dimPosition = _dimmedVolume;
|
||||||
|
_dimIteration = (_volume - _dimmedVolume)/DIM_SPEED;
|
||||||
|
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugMusic, "UnDimming music from %d to %d, steps %d", _dimPosition, _volume, _dimIteration);
|
||||||
|
|
||||||
|
// And SFX
|
||||||
|
_vm->_sound->setSFXVolumes(255);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::dimIteration() {
|
||||||
|
if (_dimIteration != 0)
|
||||||
|
{
|
||||||
|
_dimPosition += _dimIteration;
|
||||||
|
if (_dimPosition >= _volume)
|
||||||
|
{
|
||||||
|
_dimPosition = _volume;
|
||||||
|
_dimIteration = 0;
|
||||||
|
}
|
||||||
|
else if (_dimPosition <= _dimmedVolume)
|
||||||
|
{
|
||||||
|
_dimPosition = _dimmedVolume;
|
||||||
|
_dimIteration = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_vm->_mixer->setChannelVolume(_handle, _dimPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::startFadeOut(int ticks) {
|
||||||
|
if ((_volume == 0) || (_state == S_IDLE) || !_curChunk)
|
||||||
|
return;
|
||||||
|
|
||||||
|
debugC(DEBUG_INTERMEDIATE, kTinselDebugMusic, "Fading out music...");
|
||||||
|
|
||||||
|
if (_dimmed) {
|
||||||
|
// Start from dimmed volume and go from there
|
||||||
|
_dimmed = false;
|
||||||
|
_fadeOutVolume = _volume - _volume/SysVar(SV_MUSICDIMFACTOR);
|
||||||
|
} else
|
||||||
|
_fadeOutVolume = _volume;
|
||||||
|
|
||||||
|
assert(ticks != 0);
|
||||||
|
_fadeOutIteration = _fadeOutVolume / ticks;
|
||||||
|
|
||||||
|
fadeOutIteration();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::fadeOutIteration() {
|
||||||
|
if ((_volume == 0) || (_state == S_IDLE) || !_curChunk)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fadeOutVolume = CLIP<int>(_fadeOutVolume -= _fadeOutIteration, 0, 255);
|
||||||
|
|
||||||
|
_vm->_mixer->setChannelVolume(_handle, _fadeOutVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PCMMusicPlayer::getNextChunk() {
|
||||||
|
MusicSegment *musicSegments;
|
||||||
|
int32 *script, *scriptBuffer;
|
||||||
|
int id;
|
||||||
|
int snum;
|
||||||
|
uint32 sampleOffset, sampleLength, sampleCLength;
|
||||||
|
Common::File f;
|
||||||
|
byte *buffer;
|
||||||
|
Common::MemoryReadStream *sampleStream;
|
||||||
|
|
||||||
|
switch (_state) {
|
||||||
|
case S_NEW:
|
||||||
|
case S_NEXT:
|
||||||
|
_forcePlay = false;
|
||||||
|
|
||||||
|
script = scriptBuffer = (int32 *) LockMem(_hScript);
|
||||||
|
|
||||||
|
// Set parameters for this chunk of music
|
||||||
|
id = _scriptNum;
|
||||||
|
while(id--)
|
||||||
|
script = scriptBuffer + FROM_LE_32(*script);
|
||||||
|
snum = FROM_LE_32(script[_scriptIndex++]);
|
||||||
|
|
||||||
|
if (snum == MUSIC_JUMP || snum == MUSIC_END)
|
||||||
|
{
|
||||||
|
// Let usual code sort it out!
|
||||||
|
_scriptIndex--; // Undo increment
|
||||||
|
_forcePlay = true; // Force a Play
|
||||||
|
_state = S_END1; // 'Goto' S_END1
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
musicSegments = (MusicSegment *) LockMem(_hSegment);
|
||||||
|
|
||||||
|
assert(FROM_LE_32(musicSegments[snum].numChannels) == 1);
|
||||||
|
assert(FROM_LE_32(musicSegments[snum].bitsPerSample) == 16);
|
||||||
|
|
||||||
|
sampleOffset = FROM_LE_32(musicSegments[snum].sampleOffset);
|
||||||
|
sampleLength = FROM_LE_32(musicSegments[snum].sampleLength);
|
||||||
|
sampleCLength = (((sampleLength + 63) & ~63)*33)/64;
|
||||||
|
|
||||||
|
if (!f.open(_fileName))
|
||||||
|
error(CANNOT_FIND_FILE, _fileName);
|
||||||
|
|
||||||
|
f.seek(sampleOffset);
|
||||||
|
if (f.ioFailed() || (uint32)f.pos() != sampleOffset)
|
||||||
|
error(FILE_IS_CORRUPT, _fileName);
|
||||||
|
|
||||||
|
buffer = (byte *) malloc(sampleCLength);
|
||||||
|
assert(buffer);
|
||||||
|
|
||||||
|
// read all of the sample
|
||||||
|
if (f.read(buffer, sampleCLength) != sampleCLength)
|
||||||
|
error(FILE_IS_CORRUPT, _fileName);
|
||||||
|
|
||||||
|
sampleStream = new Common::MemoryReadStream(buffer, sampleCLength, true);
|
||||||
|
|
||||||
|
delete _curChunk;
|
||||||
|
_curChunk = makeADPCMStream(sampleStream, true, sampleCLength,
|
||||||
|
Audio::kADPCMTinsel8, 22050, 1, 32);
|
||||||
|
|
||||||
|
_state = S_MID;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case S_END1:
|
||||||
|
script = scriptBuffer = (int32 *) LockMem(_hScript);
|
||||||
|
|
||||||
|
id = _scriptNum;
|
||||||
|
while(id--)
|
||||||
|
script = scriptBuffer + FROM_LE_32(*script);
|
||||||
|
|
||||||
|
switch (script[_scriptIndex]) {
|
||||||
|
|
||||||
|
case MUSIC_END:
|
||||||
|
_state = S_END2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MUSIC_JUMP:
|
||||||
|
_scriptIndex = script[++_scriptIndex];
|
||||||
|
// Fall through
|
||||||
|
default:
|
||||||
|
if (_forcePlay)
|
||||||
|
_state = S_NEW;
|
||||||
|
else
|
||||||
|
_state = S_NEXT;
|
||||||
|
_forcePlay = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case S_END2:
|
||||||
|
_silenceSamples = 11025; // Half a second of silence
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case S_END3:
|
||||||
|
stop();
|
||||||
|
_state = S_IDLE;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case S_IDLE:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::play() {
|
||||||
|
if (_curChunk)
|
||||||
|
return;
|
||||||
|
if (_scriptNum == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_end = false;
|
||||||
|
|
||||||
|
getNextChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMMusicPlayer::stop() {
|
||||||
|
delete _curChunk;
|
||||||
|
_curChunk = 0;
|
||||||
|
_scriptNum = -1;
|
||||||
|
_state = S_IDLE;
|
||||||
|
_mState = S_IDLE;
|
||||||
|
|
||||||
|
_end = true;
|
||||||
|
}
|
||||||
|
|
||||||
void CurrentMidiFacts(SCNHANDLE *pMidi, bool *pLoop) {
|
void CurrentMidiFacts(SCNHANDLE *pMidi, bool *pLoop) {
|
||||||
*pMidi = currentMidi;
|
*pMidi = currentMidi;
|
||||||
*pLoop = currentLoop;
|
*pLoop = currentLoop;
|
||||||
|
@ -495,9 +902,9 @@ void RestoreMidiFacts(SCNHANDLE Midi, bool Loop) {
|
||||||
currentMidi = Midi;
|
currentMidi = Midi;
|
||||||
currentLoop = Loop;
|
currentLoop = Loop;
|
||||||
|
|
||||||
if (volMidi != 0 && Loop) {
|
if (volMusic != 0 && Loop) {
|
||||||
PlayMidiSequence(currentMidi, true);
|
PlayMidiSequence(currentMidi, true);
|
||||||
SetMidiVolume(volMidi);
|
SetMidiVolume(volMusic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,4 +953,4 @@ void dumpMusic() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // End of namespace Made
|
} // End of namespace Tinsel
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include "sound/mididrv.h"
|
#include "sound/mididrv.h"
|
||||||
#include "sound/midiparser.h"
|
#include "sound/midiparser.h"
|
||||||
|
#include "sound/audiostream.h"
|
||||||
|
#include "sound/mixer.h"
|
||||||
#include "common/mutex.h"
|
#include "common/mutex.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
@ -58,11 +60,10 @@ SCNHANDLE GetTrackOffset(int trackNumber);
|
||||||
|
|
||||||
void dumpMusic();
|
void dumpMusic();
|
||||||
|
|
||||||
|
class MidiMusicPlayer : public MidiDriver {
|
||||||
class MusicPlayer : public MidiDriver {
|
|
||||||
public:
|
public:
|
||||||
MusicPlayer(MidiDriver *driver);
|
MidiMusicPlayer(MidiDriver *driver);
|
||||||
~MusicPlayer();
|
~MidiMusicPlayer();
|
||||||
|
|
||||||
bool isPlaying() { return _isPlaying; }
|
bool isPlaying() { return _isPlaying; }
|
||||||
void setPlaying(bool playing) { _isPlaying = playing; }
|
void setPlaying(bool playing) { _isPlaying = playing; }
|
||||||
|
@ -71,6 +72,7 @@ public:
|
||||||
int getVolume() { return _masterVolume; }
|
int getVolume() { return _masterVolume; }
|
||||||
|
|
||||||
void playXMIDI(byte *midiData, uint32 size, bool loop);
|
void playXMIDI(byte *midiData, uint32 size, bool loop);
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
void pause();
|
void pause();
|
||||||
void resume();
|
void resume();
|
||||||
|
@ -111,6 +113,93 @@ protected:
|
||||||
byte _masterVolume;
|
byte _masterVolume;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Made
|
class PCMMusicPlayer : public Audio::AudioStream {
|
||||||
|
public:
|
||||||
|
PCMMusicPlayer();
|
||||||
|
~PCMMusicPlayer();
|
||||||
|
|
||||||
|
bool isPlaying() const;
|
||||||
|
|
||||||
|
bool isDimmed() const;
|
||||||
|
|
||||||
|
void getTunePlaying(void *voidPtr, int length);
|
||||||
|
void restoreThatTune(void *voidPtr);
|
||||||
|
|
||||||
|
void setMusicSceneDetails(SCNHANDLE hScript, SCNHANDLE hSegment, const char *fileName);
|
||||||
|
|
||||||
|
void setVolume(int volume);
|
||||||
|
|
||||||
|
void startPlay(int id);
|
||||||
|
void stopPlay();
|
||||||
|
|
||||||
|
bool getMusicTinselDimmed() const;
|
||||||
|
void dim(bool bTinselDim);
|
||||||
|
void unDim(bool bTinselUnDim);
|
||||||
|
void dimIteration();
|
||||||
|
|
||||||
|
void startFadeOut(int ticks);
|
||||||
|
void fadeOutIteration();
|
||||||
|
|
||||||
|
int readBuffer(int16 *buffer, const int numSamples);
|
||||||
|
bool isStereo() const { return false; }
|
||||||
|
bool endOfData() const { return _end; }
|
||||||
|
bool endOfStream() const { return false; }
|
||||||
|
int getRate() const { return 22050; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum State {
|
||||||
|
S_IDLE,
|
||||||
|
S_NEW,
|
||||||
|
S_MID,
|
||||||
|
S_END1,
|
||||||
|
S_END2,
|
||||||
|
S_END3,
|
||||||
|
S_NEXT,
|
||||||
|
S_STOP
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MusicSegment {
|
||||||
|
uint32 numChannels;
|
||||||
|
uint32 bitsPerSec;
|
||||||
|
uint32 bitsPerSample;
|
||||||
|
uint32 sampleLength;
|
||||||
|
uint32 sampleOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
Audio::SoundHandle _handle;
|
||||||
|
Audio::AudioStream *_curChunk;
|
||||||
|
Common::Mutex _mutex;
|
||||||
|
|
||||||
|
bool _end;
|
||||||
|
|
||||||
|
int _silenceSamples;
|
||||||
|
|
||||||
|
State _state, _mState;
|
||||||
|
bool _forcePlay;
|
||||||
|
int32 _scriptNum;
|
||||||
|
int32 _scriptIndex;
|
||||||
|
SCNHANDLE _hScript;
|
||||||
|
SCNHANDLE _hSegment;
|
||||||
|
char *_fileName;
|
||||||
|
|
||||||
|
uint8 _volume;
|
||||||
|
|
||||||
|
bool _dimmed;
|
||||||
|
bool _dimmedTinsel;
|
||||||
|
uint8 _dimmedVolume;
|
||||||
|
int _dimIteration;
|
||||||
|
int _dimPosition;
|
||||||
|
|
||||||
|
uint8 _fadeOutVolume;
|
||||||
|
int _fadeOutIteration;
|
||||||
|
|
||||||
|
void play();
|
||||||
|
void stop();
|
||||||
|
void setVol(uint8 volume);
|
||||||
|
|
||||||
|
bool getNextChunk();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Tinsel
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,14 +29,13 @@
|
||||||
#include "tinsel/cliprect.h" // object clip rect defs
|
#include "tinsel/cliprect.h" // object clip rect defs
|
||||||
#include "tinsel/graphics.h" // low level interface
|
#include "tinsel/graphics.h" // low level interface
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
|
#include "tinsel/text.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
#define OID_EFFECTS 0x2000 // generic special effects object id
|
#define OID_EFFECTS 0x2000 // generic special effects object id
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
/** screen clipping rectangle */
|
|
||||||
static const Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
||||||
|
|
||||||
// list of all objects
|
// list of all objects
|
||||||
OBJECT *objectList = 0;
|
OBJECT *objectList = 0;
|
||||||
|
|
||||||
|
@ -194,6 +193,7 @@ void InsertObject(OBJECT *pObjList, OBJECT *pInsObj) {
|
||||||
*/
|
*/
|
||||||
void DelObject(OBJECT *pObjList, OBJECT *pDelObj) {
|
void DelObject(OBJECT *pObjList, OBJECT *pDelObj) {
|
||||||
OBJECT *pPrev, *pObj; // object list traversal pointers
|
OBJECT *pPrev, *pObj; // object list traversal pointers
|
||||||
|
const Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
|
||||||
// validate object pointer
|
// validate object pointer
|
||||||
assert(pDelObj >= objectList && pDelObj <= objectList + NUM_OBJECTS - 1);
|
assert(pDelObj >= objectList && pDelObj <= objectList + NUM_OBJECTS - 1);
|
||||||
|
@ -232,7 +232,9 @@ void DelObject(OBJECT *pObjList, OBJECT *pDelObj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we get to here - object has not been found on the list
|
// if we get to here - object has not been found on the list
|
||||||
error("DelObject(): formally 'assert(0)!'");
|
// This can be triggered in Act 3 in DW1 while talking to the guard,
|
||||||
|
// so this has been turned to a warning instead of an error
|
||||||
|
warning("DelObject(): formally 'assert(0)!'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,7 +315,7 @@ void GetAniOffset(SCNHANDLE hImg, int flags, int *pAniX, int *pAniY) {
|
||||||
// we are flipped vertically
|
// we are flipped vertically
|
||||||
|
|
||||||
// set ani Y = -ani Y + height - 1
|
// set ani Y = -ani Y + height - 1
|
||||||
*pAniY = -*pAniY + FROM_LE_16(pImg->imgHeight) - 1;
|
*pAniY = -*pAniY + (FROM_LE_16(pImg->imgHeight) & ~C16_FLAG_MASK) - 1;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
// null image
|
// null image
|
||||||
|
@ -365,21 +367,25 @@ OBJECT *InitObject(const OBJ_INIT *pInitTbl) {
|
||||||
// get pointer to image
|
// get pointer to image
|
||||||
if (pInitTbl->hObjImg) {
|
if (pInitTbl->hObjImg) {
|
||||||
int aniX, aniY; // objects animation offsets
|
int aniX, aniY; // objects animation offsets
|
||||||
PALQ *pPalQ; // palette queue pointer
|
PALQ *pPalQ = NULL; // palette queue pointer
|
||||||
const IMAGE *pImg = (const IMAGE *)LockMem(pInitTbl->hObjImg); // handle to image
|
const IMAGE *pImg = (const IMAGE *)LockMem(pInitTbl->hObjImg); // handle to image
|
||||||
|
|
||||||
|
if (pImg->hImgPal) {
|
||||||
// allocate a palette for this object
|
// allocate a palette for this object
|
||||||
pPalQ = AllocPalette(FROM_LE_32(pImg->hImgPal));
|
pPalQ = AllocPalette(FROM_LE_32(pImg->hImgPal));
|
||||||
|
|
||||||
// make sure palette allocated
|
// make sure palette allocated
|
||||||
assert(pPalQ != NULL);
|
assert(pPalQ != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// assign palette to object
|
// assign palette to object
|
||||||
pObj->pPal = pPalQ;
|
pObj->pPal = pPalQ;
|
||||||
|
|
||||||
// set objects size
|
// set objects size
|
||||||
pObj->width = FROM_LE_16(pImg->imgWidth);
|
pObj->width = FROM_LE_16(pImg->imgWidth);
|
||||||
pObj->height = FROM_LE_16(pImg->imgHeight);
|
pObj->height = FROM_LE_16(pImg->imgHeight) & ~C16_FLAG_MASK;
|
||||||
|
pObj->flags &= ~C16_FLAG_MASK;
|
||||||
|
pObj->flags |= FROM_LE_16(pImg->imgHeight) & C16_FLAG_MASK;
|
||||||
|
|
||||||
// set objects bitmap definition
|
// set objects bitmap definition
|
||||||
pObj->hBits = FROM_LE_32(pImg->hImgBits);
|
pObj->hBits = FROM_LE_32(pImg->hImgBits);
|
||||||
|
@ -434,7 +440,9 @@ void AnimateObjectFlags(OBJECT *pAniObj, int newflags, SCNHANDLE hNewImg) {
|
||||||
|
|
||||||
// setup new shape
|
// setup new shape
|
||||||
pAniObj->width = FROM_LE_16(pNewImg->imgWidth);
|
pAniObj->width = FROM_LE_16(pNewImg->imgWidth);
|
||||||
pAniObj->height = FROM_LE_16(pNewImg->imgHeight);
|
pAniObj->height = FROM_LE_16(pNewImg->imgHeight) & ~C16_FLAG_MASK;
|
||||||
|
newflags &= ~C16_FLAG_MASK;
|
||||||
|
newflags |= pNewImg->imgHeight & C16_FLAG_MASK;
|
||||||
|
|
||||||
// set objects bitmap definition
|
// set objects bitmap definition
|
||||||
pAniObj->hBits = FROM_LE_32(pNewImg->hImgBits);
|
pAniObj->hBits = FROM_LE_32(pNewImg->hImgBits);
|
||||||
|
|
|
@ -51,21 +51,24 @@ enum {
|
||||||
DMA_ABS = 0x0100, //!< position of object is absolute
|
DMA_ABS = 0x0100, //!< position of object is absolute
|
||||||
DMA_CHANGED = 0x0200, //!< object has changed in some way since the last frame
|
DMA_CHANGED = 0x0200, //!< object has changed in some way since the last frame
|
||||||
DMA_USERDEF = 0x0400, //!< user defined flags start here
|
DMA_USERDEF = 0x0400, //!< user defined flags start here
|
||||||
|
DMA_GHOST = 0x0080,
|
||||||
|
|
||||||
|
|
||||||
/** flags that effect an objects appearance */
|
/** flags that effect an objects appearance */
|
||||||
DMA_HARDFLAGS = (DMA_WNZ | DMA_CNZ | DMA_CONST | DMA_WA | DMA_FLIPH | DMA_FLIPV | DMA_TRANS)
|
DMA_HARDFLAGS = (DMA_WNZ | DMA_CNZ | DMA_CONST | DMA_WA | DMA_FLIPH | DMA_FLIPV | DMA_TRANS)
|
||||||
};
|
};
|
||||||
|
|
||||||
/** structure for image */
|
/** structure for image */
|
||||||
|
#include "common/pack-start.h" // START STRUCT PACKING
|
||||||
struct IMAGE {
|
struct IMAGE {
|
||||||
short imgWidth; //!< image width
|
short imgWidth; //!< image width
|
||||||
short imgHeight; //!< image height
|
unsigned short imgHeight; //!< image height
|
||||||
short anioffX; //!< image x animation offset
|
short anioffX; //!< image x animation offset
|
||||||
short anioffY; //!< image y animation offset
|
short anioffY; //!< image y animation offset
|
||||||
SCNHANDLE hImgBits; //!< image bitmap handle
|
SCNHANDLE hImgBits; //!< image bitmap handle
|
||||||
SCNHANDLE hImgPal; //!< image palette handle
|
SCNHANDLE hImgPal; //!< image palette handle
|
||||||
};
|
} PACKED_STRUCT;
|
||||||
|
#include "common/pack-end.h" // END STRUCT PACKING
|
||||||
|
|
||||||
/** a multi-object animation frame is a list of multi-image handles */
|
/** a multi-object animation frame is a list of multi-image handles */
|
||||||
typedef uint32 FRAME;
|
typedef uint32 FRAME;
|
||||||
|
@ -93,6 +96,7 @@ struct OBJECT {
|
||||||
SCNHANDLE hMirror; //!< objects previous animation frame
|
SCNHANDLE hMirror; //!< objects previous animation frame
|
||||||
int oid; //!< object identifier
|
int oid; //!< object identifier
|
||||||
};
|
};
|
||||||
|
typedef OBJECT *POBJECT;
|
||||||
|
|
||||||
#include "common/pack-start.h" // START STRUCT PACKING
|
#include "common/pack-start.h" // START STRUCT PACKING
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "tinsel/graphics.h"
|
#include "tinsel/graphics.h"
|
||||||
#include "tinsel/handle.h" // LockMem definition
|
#include "tinsel/handle.h" // LockMem definition
|
||||||
#include "tinsel/palette.h" // palette allocator structures etc.
|
#include "tinsel/palette.h" // palette allocator structures etc.
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
#include "tinsel/tinsel.h"
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
|
@ -72,6 +73,17 @@ static VIDEO_DAC_Q *pDAChead;
|
||||||
/** the translucent palette lookup table */
|
/** the translucent palette lookup table */
|
||||||
uint8 transPalette[MAX_COLOURS]; // used in graphics.cpp
|
uint8 transPalette[MAX_COLOURS]; // used in graphics.cpp
|
||||||
|
|
||||||
|
uint8 ghostPalette[MAX_COLOURS];
|
||||||
|
|
||||||
|
static int translucentIndex = 228;
|
||||||
|
|
||||||
|
static int talkIndex = 233;
|
||||||
|
|
||||||
|
static COLORREF talkColRef;
|
||||||
|
|
||||||
|
static COLORREF tagColRef;
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// diagnostic palette counters
|
// diagnostic palette counters
|
||||||
static int numPals = 0;
|
static int numPals = 0;
|
||||||
|
@ -243,6 +255,10 @@ PALQ *AllocPalette(SCNHANDLE hNewPal) {
|
||||||
p->hPal = hNewPal; // set hardware palette data
|
p->hPal = hNewPal; // set hardware palette data
|
||||||
p->numColours = FROM_LE_32(pNewPal->numColours); // set number of colours in palette
|
p->numColours = FROM_LE_32(pNewPal->numColours); // set number of colours in palette
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
// Copy all the colours
|
||||||
|
memcpy(p->palRGB, pNewPal->palRGB, pNewPal->numColours * sizeof(COLORREF));
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// one more palette in use
|
// one more palette in use
|
||||||
if (++numPals > maxPals)
|
if (++numPals > maxPals)
|
||||||
|
@ -250,6 +266,9 @@ PALQ *AllocPalette(SCNHANDLE hNewPal) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Q the change to the video DAC
|
// Q the change to the video DAC
|
||||||
|
if (TinselV2)
|
||||||
|
UpdateDACqueue(p->posInDAC, pNewPal->numColours, p->palRGB);
|
||||||
|
else
|
||||||
UpdateDACqueueHandle(p->posInDAC, p->numColours, p->hPal);
|
UpdateDACqueueHandle(p->posInDAC, p->numColours, p->hPal);
|
||||||
|
|
||||||
// move all palettes after this one down (if necessary)
|
// move all palettes after this one down (if necessary)
|
||||||
|
@ -265,9 +284,14 @@ PALQ *AllocPalette(SCNHANDLE hNewPal) {
|
||||||
+ pPrev->numColours | PALETTE_MOVED;
|
+ pPrev->numColours | PALETTE_MOVED;
|
||||||
|
|
||||||
// Q the palette change in position to the video DAC
|
// Q the palette change in position to the video DAC
|
||||||
|
if (!TinselV2)
|
||||||
UpdateDACqueueHandle(pNxtPal->posInDAC,
|
UpdateDACqueueHandle(pNxtPal->posInDAC,
|
||||||
pNxtPal->numColours,
|
pNxtPal->numColours,
|
||||||
pNxtPal->hPal);
|
pNxtPal->hPal);
|
||||||
|
else if (!pNxtPal->bFading)
|
||||||
|
UpdateDACqueue(pNxtPal->posInDAC,
|
||||||
|
pNxtPal->numColours,
|
||||||
|
pNxtPal->palRGB);
|
||||||
|
|
||||||
// update previous palette to current palette
|
// update previous palette to current palette
|
||||||
pPrev = pNxtPal;
|
pPrev = pNxtPal;
|
||||||
|
@ -347,10 +371,22 @@ void SwapPalette(PALQ *pPalQ, SCNHANDLE hNewPal) {
|
||||||
// install new palette
|
// install new palette
|
||||||
pPalQ->hPal = hNewPal;
|
pPalQ->hPal = hNewPal;
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
pPalQ->numColours = pNewPal->numColours;
|
||||||
|
|
||||||
|
// Copy all the colours
|
||||||
|
memcpy(pPalQ->palRGB, pNewPal->palRGB, pNewPal->numColours * sizeof(COLORREF));
|
||||||
|
|
||||||
|
if (!pPalQ->bFading)
|
||||||
|
// Q the change to the video DAC
|
||||||
|
UpdateDACqueue(pPalQ->posInDAC, FROM_LE_32(pNewPal->numColours), pPalQ->palRGB);
|
||||||
|
} else {
|
||||||
// Q the change to the video DAC
|
// Q the change to the video DAC
|
||||||
UpdateDACqueueHandle(pPalQ->posInDAC, FROM_LE_32(pNewPal->numColours), hNewPal);
|
UpdateDACqueueHandle(pPalQ->posInDAC, FROM_LE_32(pNewPal->numColours), hNewPal);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// # colours are different - will have to update all following palette entries
|
// # colours are different - will have to update all following palette entries
|
||||||
|
assert(!TinselV2); // Fatal error for Tinsel 2
|
||||||
|
|
||||||
PALQ *pNxtPalQ; // next palette queue position
|
PALQ *pNxtPalQ; // next palette queue position
|
||||||
|
|
||||||
|
@ -410,6 +446,33 @@ void SetBgndColour(COLORREF colour) {
|
||||||
UpdateDACqueue(BGND_DAC_INDEX, 1, &bgndColour);
|
UpdateDACqueue(BGND_DAC_INDEX, 1, &bgndColour);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note whether a palette is being faded.
|
||||||
|
* @param pPalQ Palette queue position
|
||||||
|
* @param bFading Whether it is fading
|
||||||
|
*/
|
||||||
|
void FadingPalette(PPALQ pPalQ, bool bFading) {
|
||||||
|
// validate palette Q pointer
|
||||||
|
assert(pPalQ >= palAllocData && pPalQ <= palAllocData + NUM_PALETTES - 1);
|
||||||
|
|
||||||
|
// validate that this is a change
|
||||||
|
assert(pPalQ->bFading != bFading);
|
||||||
|
|
||||||
|
pPalQ->bFading = bFading;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All fading processes have just been killed, so none of the
|
||||||
|
* palettes are fading.
|
||||||
|
*/
|
||||||
|
void NoFadingPalettes(void) {
|
||||||
|
PPALQ pPalQ;
|
||||||
|
|
||||||
|
for (pPalQ = palAllocData; pPalQ <= palAllocData + NUM_PALETTES - 1; pPalQ++) {
|
||||||
|
pPalQ->bFading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the translucent palette from the current backgrounds palette.
|
* Builds the translucent palette from the current backgrounds palette.
|
||||||
* @param hPalette Handle to current background palette
|
* @param hPalette Handle to current background palette
|
||||||
|
@ -433,8 +496,134 @@ void CreateTranslucentPalette(SCNHANDLE hPalette) {
|
||||||
|
|
||||||
// map the Value field to one of the 4 colours reserved for the translucent palette
|
// map the Value field to one of the 4 colours reserved for the translucent palette
|
||||||
val /= 63;
|
val /= 63;
|
||||||
transPalette[i + 1] = (uint8)((val == 0) ? 0 : val + COL_HILIGHT - 1);
|
transPalette[i + 1] = (uint8)((val == 0) ? 0 : val +
|
||||||
|
(TinselV2 ? TranslucentColour() : COL_HILIGHT) - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the ghost palette
|
||||||
|
*/
|
||||||
|
void CreateGhostPalette(SCNHANDLE hPalette) {
|
||||||
|
// get a pointer to the palette
|
||||||
|
PALETTE *pPal = (PALETTE *)LockMem(hPalette);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// leave background colour alone
|
||||||
|
ghostPalette[0] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < pPal->numColours; i++) {
|
||||||
|
// get the RGB colour model values
|
||||||
|
uint8 red = GetRValue(pPal->palRGB[i]);
|
||||||
|
uint8 green = GetGValue(pPal->palRGB[i]);
|
||||||
|
uint8 blue = GetBValue(pPal->palRGB[i]);
|
||||||
|
|
||||||
|
// calculate the Value field of the HSV colour model
|
||||||
|
unsigned val = (red > green) ? red : green;
|
||||||
|
val = (val > blue) ? val : blue;
|
||||||
|
|
||||||
|
// map the Value field to one of the 4 colours reserved for the translucent palette
|
||||||
|
val /= 64;
|
||||||
|
assert(/*val >= 0 &&*/ val <= 3);
|
||||||
|
ghostPalette[i + 1] = (uint8)(val + SysVar(ISV_GHOST_BASE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an adjusted colour RGB
|
||||||
|
* @param colour Colour to scale
|
||||||
|
*/
|
||||||
|
static COLORREF DimColour(COLORREF colour, int factor) {
|
||||||
|
uint32 red, green, blue;
|
||||||
|
|
||||||
|
if (factor == 10) {
|
||||||
|
// No change
|
||||||
|
return colour;
|
||||||
|
} else if (factor == 0) {
|
||||||
|
// No brightness
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
// apply multiplier to RGB components
|
||||||
|
red = GetRValue(colour) * factor / 10;
|
||||||
|
green = GetGValue(colour) * factor / 10;
|
||||||
|
blue = GetBValue(colour) * factor / 10;
|
||||||
|
|
||||||
|
// return new colour
|
||||||
|
return RGB(red, green, blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DimPartPalette
|
||||||
|
*/
|
||||||
|
void DimPartPalette(SCNHANDLE hDimPal, int startColour, int length, int brightness) {
|
||||||
|
PALQ *pPalQ;
|
||||||
|
PALETTE *pDimPal;
|
||||||
|
int iColour;
|
||||||
|
|
||||||
|
pPalQ = FindPalette(hDimPal);
|
||||||
|
assert(pPalQ);
|
||||||
|
|
||||||
|
// get pointer to dim palette
|
||||||
|
pDimPal = (PALETTE *)LockMem(hDimPal);
|
||||||
|
|
||||||
|
// Adjust for the fact that palettes don't contain colour 0
|
||||||
|
startColour -= 1;
|
||||||
|
|
||||||
|
// Check some other things
|
||||||
|
if (startColour + length > pPalQ->numColours)
|
||||||
|
error("DimPartPalette(): colour overrun");
|
||||||
|
|
||||||
|
for (iColour = startColour ; iColour < startColour + length; iColour++) {
|
||||||
|
pPalQ->palRGB[iColour] = DimColour(pDimPal->palRGB[iColour], brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pPalQ->bFading) {
|
||||||
|
// Q the change to the video DAC
|
||||||
|
UpdateDACqueue(pPalQ->posInDAC + startColour, length, &pPalQ->palRGB[startColour]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TranslucentColour(void) {
|
||||||
|
return translucentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HighlightColour(void) {
|
||||||
|
static COLORREF cRef;
|
||||||
|
|
||||||
|
cRef = (COLORREF)SysVar(SYS_HighlightRGB);
|
||||||
|
UpdateDACqueue(talkIndex, 1, &cRef);
|
||||||
|
|
||||||
|
return talkIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TalkColour(void) {
|
||||||
|
return TinselV2 ? talkIndex : TALKFONT_COL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTalkColourRef(COLORREF colRef) {
|
||||||
|
talkColRef = colRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
COLORREF GetTalkColourRef(void) {
|
||||||
|
return talkColRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTagColorRef(COLORREF colRef) {
|
||||||
|
tagColRef = colRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
COLORREF GetTagColorRef(void) {
|
||||||
|
return tagColRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTranslucencyOffset(int offset) {
|
||||||
|
translucentIndex = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTalkTextOffset(int offset) {
|
||||||
|
talkIndex = offset;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -43,7 +43,7 @@ enum {
|
||||||
MAX_COLOURS = 256, //!< maximum number of colours - for VGA 256
|
MAX_COLOURS = 256, //!< maximum number of colours - for VGA 256
|
||||||
BITS_PER_PIXEL = 8, //!< number of bits per pixel for VGA 256
|
BITS_PER_PIXEL = 8, //!< number of bits per pixel for VGA 256
|
||||||
MAX_INTENSITY = 255, //!< the biggest value R, G or B can have
|
MAX_INTENSITY = 255, //!< the biggest value R, G or B can have
|
||||||
NUM_PALETTES = 3, //!< number of palettes
|
NUM_PALETTES = 32, //!< number of palettes
|
||||||
|
|
||||||
// Discworld has some fixed apportioned bits in the palette.
|
// Discworld has some fixed apportioned bits in the palette.
|
||||||
BGND_DAC_INDEX = 0, //!< index of background colour in Video DAC
|
BGND_DAC_INDEX = 0, //!< index of background colour in Video DAC
|
||||||
|
@ -84,8 +84,11 @@ struct PALQ {
|
||||||
int objCount; //!< number of objects using this palette
|
int objCount; //!< number of objects using this palette
|
||||||
int posInDAC; //!< palette position in the video DAC
|
int posInDAC; //!< palette position in the video DAC
|
||||||
int numColours; //!< number of colours in the palette
|
int numColours; //!< number of colours in the palette
|
||||||
|
// Discworld 2 fields
|
||||||
|
bool bFading; // Whether or not fading
|
||||||
|
COLORREF palRGB[MAX_COLOURS]; // actual palette colours
|
||||||
};
|
};
|
||||||
|
typedef PALQ *PPALQ;
|
||||||
|
|
||||||
#define PALETTE_MOVED 0x8000 // when this bit is set in the "posInDAC"
|
#define PALETTE_MOVED 0x8000 // when this bit is set in the "posInDAC"
|
||||||
// field - the palette entry has moved
|
// field - the palette entry has moved
|
||||||
|
@ -137,8 +140,41 @@ COLORREF GetBgndColour(void); // returns current background colour
|
||||||
void SetBgndColour( // sets current background colour
|
void SetBgndColour( // sets current background colour
|
||||||
COLORREF colour); // colour to set the background to
|
COLORREF colour); // colour to set the background to
|
||||||
|
|
||||||
|
void FadingPalette(PPALQ pPalQ, bool bFading);
|
||||||
|
|
||||||
void CreateTranslucentPalette(SCNHANDLE BackPal);
|
void CreateTranslucentPalette(SCNHANDLE BackPal);
|
||||||
|
|
||||||
|
void CreateGhostPalette(SCNHANDLE hPalette);
|
||||||
|
|
||||||
|
void NoFadingPalettes(void); // All fading processes have just been killed
|
||||||
|
|
||||||
|
void DimPartPalette(
|
||||||
|
SCNHANDLE hPal,
|
||||||
|
int startColour,
|
||||||
|
int length,
|
||||||
|
int brightness); // 0 = black, 10 == 100%
|
||||||
|
|
||||||
|
|
||||||
|
int TranslucentColour(void);
|
||||||
|
|
||||||
|
#define BoxColour TranslucentColour
|
||||||
|
|
||||||
|
int HighlightColour(void);
|
||||||
|
|
||||||
|
int TalkColour(void);
|
||||||
|
|
||||||
|
void SetTalkColourRef(COLORREF colRef);
|
||||||
|
|
||||||
|
COLORREF GetTalkColourRef(void);
|
||||||
|
|
||||||
|
void SetTagColorRef(COLORREF colRef);
|
||||||
|
|
||||||
|
COLORREF GetTagColorRef(void);
|
||||||
|
|
||||||
|
void SetTalkTextOffset(int offset);
|
||||||
|
|
||||||
|
void SetTranslucencyOffset(int offset);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif // TINSEL_PALETTE_H
|
#endif // TINSEL_PALETTE_H
|
||||||
|
|
|
@ -25,13 +25,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
|
#include "tinsel/drives.h"
|
||||||
#include "tinsel/events.h" // 'POINTED' etc.
|
#include "tinsel/events.h" // 'POINTED' etc.
|
||||||
#include "tinsel/handle.h" // LockMem()
|
#include "tinsel/handle.h" // LockMem()
|
||||||
#include "tinsel/inventory.h" // for inventory id's
|
#include "tinsel/dialogs.h" // for inventory id's
|
||||||
#include "tinsel/pcode.h" // opcodes etc.
|
#include "tinsel/pcode.h" // opcodes etc.
|
||||||
#include "tinsel/scn.h" // FindChunk()
|
#include "tinsel/scn.h" // FindChunk()
|
||||||
#include "tinsel/serializer.h"
|
#include "tinsel/serializer.h"
|
||||||
|
#include "tinsel/timers.h"
|
||||||
#include "tinsel/tinlib.h" // Library routines
|
#include "tinsel/tinlib.h" // Library routines
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
|
||||||
|
@ -97,7 +100,7 @@ enum OPCODE {
|
||||||
|
|
||||||
#define OPMASK 0x3F //!< mask to isolate the opcode
|
#define OPMASK 0x3F //!< mask to isolate the opcode
|
||||||
|
|
||||||
|
bool bNoPause = false;
|
||||||
|
|
||||||
//----------------- LOCAL GLOBAL DATA --------------------
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
|
@ -107,13 +110,19 @@ static int numGlobals = 0; // How many global variables to save/restore
|
||||||
|
|
||||||
static INT_CONTEXT *icList = 0;
|
static INT_CONTEXT *icList = 0;
|
||||||
|
|
||||||
|
static uint32 hMasterScript;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps the code array pointer up to date.
|
* Keeps the code array pointer up to date.
|
||||||
*/
|
*/
|
||||||
void LockCode(INT_CONTEXT *ic) {
|
void LockCode(INT_CONTEXT *ic) {
|
||||||
if (ic->GSort == GS_MASTER)
|
if (ic->GSort == GS_MASTER) {
|
||||||
ic->code = (byte *)FindChunk(MASTER_SCNHANDLE, CHUNK_PCODE);
|
if (TinselV2)
|
||||||
|
// Get the srcipt handle from a specific global chunk
|
||||||
|
ic->code = (byte *)LockMem(hMasterScript);
|
||||||
else
|
else
|
||||||
|
ic->code = (byte *)FindChunk(MASTER_SCNHANDLE, CHUNK_PCODE);
|
||||||
|
} else
|
||||||
ic->code = (byte *)LockMem(ic->hCode);
|
ic->code = (byte *)LockMem(ic->hCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +133,7 @@ static INT_CONTEXT *AllocateInterpretContext(GSORT gsort) {
|
||||||
INT_CONTEXT *pic;
|
INT_CONTEXT *pic;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) {
|
for (i = 0, pic = icList; i < NUM_INTERPRET; i++, pic++) {
|
||||||
if (pic->GSort == GS_NONE) {
|
if (pic->GSort == GS_NONE) {
|
||||||
pic->pProc = g_scheduler->getCurrentProcess();
|
pic->pProc = g_scheduler->getCurrentProcess();
|
||||||
pic->GSort = gsort;
|
pic->GSort = gsort;
|
||||||
|
@ -141,11 +150,41 @@ static INT_CONTEXT *AllocateInterpretContext(GSORT gsort) {
|
||||||
error("Out of interpret contexts");
|
error("Out of interpret contexts");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FreeWaitCheck(PINT_CONTEXT pic, bool bVoluntary) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Is this waiting for something?
|
||||||
|
if (pic->waitNumber1) {
|
||||||
|
for (i = 0; i < NUM_INTERPRET; i++) {
|
||||||
|
if ((icList + i)->waitNumber2 == pic->waitNumber1) {
|
||||||
|
(icList + i)->waitNumber2 = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is someone waiting for this?
|
||||||
|
if (pic->waitNumber2) {
|
||||||
|
for (i = 0; i < NUM_INTERPRET; i++) {
|
||||||
|
if ((icList + i)->waitNumber1 == pic->waitNumber2) {
|
||||||
|
(icList + i)->waitNumber1 = 0;
|
||||||
|
(icList + i)->resumeCode = bVoluntary ? RES_FINISHED : RES_CUTSHORT;
|
||||||
|
g_scheduler->reschedule((icList + i)->pProc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(i < NUM_INTERPRET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normal release of an interpret context.
|
* Normal release of an interpret context.
|
||||||
* Called from the end of Interpret().
|
* Called from the end of Interpret().
|
||||||
*/
|
*/
|
||||||
static void FreeInterpretContextPi(INT_CONTEXT *pic) {
|
static void FreeInterpretContextPi(INT_CONTEXT *pic) {
|
||||||
|
FreeWaitCheck(pic, true);
|
||||||
|
if (TinselV2)
|
||||||
|
memset(pic, 0, sizeof(INT_CONTEXT));
|
||||||
pic->GSort = GS_NONE;
|
pic->GSort = GS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,8 +197,11 @@ void FreeInterpretContextPr(PROCESS *pProc) {
|
||||||
INT_CONTEXT *pic;
|
INT_CONTEXT *pic;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) {
|
for (i = 0, pic = icList; i < NUM_INTERPRET; i++, pic++) {
|
||||||
if (pic->GSort != GS_NONE && pic->pProc == pProc) {
|
if (pic->GSort != GS_NONE && pic->pProc == pProc) {
|
||||||
|
FreeWaitCheck(pic, false);
|
||||||
|
if (TinselV2)
|
||||||
|
memset(pic, 0, sizeof(INT_CONTEXT));
|
||||||
pic->GSort = GS_NONE;
|
pic->GSort = GS_NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -173,8 +215,9 @@ void FreeMostInterpretContexts(void) {
|
||||||
INT_CONTEXT *pic;
|
INT_CONTEXT *pic;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) {
|
for (i = 0, pic = icList; i < NUM_INTERPRET; i++, pic++) {
|
||||||
if (pic->GSort != GS_MASTER) {
|
if ((pic->GSort != GS_MASTER) && (pic->GSort != GS_GPROCESS)) {
|
||||||
|
memset(pic, 0, sizeof(INT_CONTEXT));
|
||||||
pic->GSort = GS_NONE;
|
pic->GSort = GS_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,8 +230,9 @@ void FreeMasterInterpretContext(void) {
|
||||||
INT_CONTEXT *pic;
|
INT_CONTEXT *pic;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) {
|
for (i = 0, pic = icList; i < NUM_INTERPRET; i++, pic++) {
|
||||||
if (pic->GSort == GS_MASTER) {
|
if ((pic->GSort == GS_MASTER) || (pic->GSort == GS_GPROCESS)) {
|
||||||
|
memset(pic, 0, sizeof(INT_CONTEXT));
|
||||||
pic->GSort = GS_NONE;
|
pic->GSort = GS_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -205,8 +249,8 @@ void FreeMasterInterpretContext(void) {
|
||||||
* @param actorId Associated actor (if any)
|
* @param actorId Associated actor (if any)
|
||||||
* @param pinvo Associated inventory object
|
* @param pinvo Associated inventory object
|
||||||
*/
|
*/
|
||||||
INT_CONTEXT *InitInterpretContext(GSORT gsort, SCNHANDLE hCode, USER_EVENT event,
|
INT_CONTEXT *InitInterpretContext(GSORT gsort, SCNHANDLE hCode, TINSEL_EVENT event,
|
||||||
HPOLYGON hpoly, int actorid, INV_OBJECT *pinvo) {
|
HPOLYGON hpoly, int actorid, INV_OBJECT *pinvo, int myEscape) {
|
||||||
INT_CONTEXT *ic;
|
INT_CONTEXT *ic;
|
||||||
|
|
||||||
ic = AllocateInterpretContext(gsort);
|
ic = AllocateInterpretContext(gsort);
|
||||||
|
@ -215,14 +259,14 @@ INT_CONTEXT *InitInterpretContext(GSORT gsort, SCNHANDLE hCode, USER_EVENT event
|
||||||
ic->hCode = hCode;
|
ic->hCode = hCode;
|
||||||
LockCode(ic);
|
LockCode(ic);
|
||||||
ic->event = event;
|
ic->event = event;
|
||||||
ic->hpoly = hpoly;
|
ic->hPoly = hpoly;
|
||||||
ic->actorid = actorid;
|
ic->idActor = actorid;
|
||||||
ic->pinvo = pinvo;
|
ic->pinvo = pinvo;
|
||||||
|
|
||||||
// Previously local variables in Interpret()
|
// Previously local variables in Interpret()
|
||||||
ic->bHalt = false; // set to exit interpeter
|
ic->bHalt = false; // set to exit interpeter
|
||||||
ic->escOn = false;
|
ic->escOn = myEscape > 0;
|
||||||
ic->myescEvent = 0; // only initialised to prevent compiler warning!
|
ic->myEscape = myEscape;
|
||||||
ic->sp = 0;
|
ic->sp = 0;
|
||||||
ic->bp = ic->sp + 1;
|
ic->bp = ic->sp + 1;
|
||||||
ic->ip = 0; // start of code
|
ic->ip = 0; // start of code
|
||||||
|
@ -256,6 +300,9 @@ void RegisterGlobals(int num) {
|
||||||
if (pGlobals == NULL) {
|
if (pGlobals == NULL) {
|
||||||
numGlobals = num;
|
numGlobals = num;
|
||||||
|
|
||||||
|
hMasterScript = !TinselV2 ? 0 :
|
||||||
|
READ_LE_UINT32(FindChunk(MASTER_SCNHANDLE, CHUNK_MASTER_SCRIPT));
|
||||||
|
|
||||||
// Allocate RAM for pGlobals and make sure it's allocated
|
// Allocate RAM for pGlobals and make sure it's allocated
|
||||||
pGlobals = (int32 *)calloc(numGlobals, sizeof(int32));
|
pGlobals = (int32 *)calloc(numGlobals, sizeof(int32));
|
||||||
if (pGlobals == NULL) {
|
if (pGlobals == NULL) {
|
||||||
|
@ -263,18 +310,38 @@ void RegisterGlobals(int num) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate RAM for interpret contexts and make sure it's allocated
|
// Allocate RAM for interpret contexts and make sure it's allocated
|
||||||
icList = (INT_CONTEXT *)calloc(MAX_INTERPRET, sizeof(INT_CONTEXT));
|
icList = (INT_CONTEXT *)calloc(NUM_INTERPRET, sizeof(INT_CONTEXT));
|
||||||
if (icList == NULL) {
|
if (icList == NULL) {
|
||||||
error("Cannot allocate memory for interpret contexts");
|
error("Cannot allocate memory for interpret contexts");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_scheduler->setResourceCallback(FreeInterpretContextPr);
|
g_scheduler->setResourceCallback(FreeInterpretContextPr);
|
||||||
} else {
|
} else {
|
||||||
// Check size is still the same
|
// Check size is still the same
|
||||||
assert(numGlobals == num);
|
assert(numGlobals == num);
|
||||||
|
|
||||||
memset(pGlobals, 0, numGlobals * sizeof(int32));
|
memset(pGlobals, 0, numGlobals * sizeof(int32));
|
||||||
memset(icList, 0, MAX_INTERPRET * sizeof(INT_CONTEXT));
|
memset(icList, 0, NUM_INTERPRET * sizeof(INT_CONTEXT));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// read initial values
|
||||||
|
CdCD(nullContext);
|
||||||
|
|
||||||
|
Common::File f;
|
||||||
|
if (!f.open(GLOBALS_FILENAME))
|
||||||
|
error(CANNOT_FIND_FILE, GLOBALS_FILENAME);
|
||||||
|
|
||||||
|
int32 length = f.readSint32LE();
|
||||||
|
if (length != num)
|
||||||
|
error(FILE_IS_CORRUPT, GLOBALS_FILENAME);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; ++i)
|
||||||
|
pGlobals[i] = f.readSint32LE();
|
||||||
|
|
||||||
|
if (f.ioFailed())
|
||||||
|
error(FILE_IS_CORRUPT, GLOBALS_FILENAME);
|
||||||
|
|
||||||
|
f.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,8 +376,8 @@ void INT_CONTEXT::syncWithSerializer(Serializer &s) {
|
||||||
s.syncAsUint32LE(GSort);
|
s.syncAsUint32LE(GSort);
|
||||||
s.syncAsUint32LE(hCode);
|
s.syncAsUint32LE(hCode);
|
||||||
s.syncAsUint32LE(event);
|
s.syncAsUint32LE(event);
|
||||||
s.syncAsSint32LE(hpoly);
|
s.syncAsSint32LE(hPoly);
|
||||||
s.syncAsSint32LE(actorid);
|
s.syncAsSint32LE(idActor);
|
||||||
|
|
||||||
for (int i = 0; i < PCODE_STACK_SIZE; ++i)
|
for (int i = 0; i < PCODE_STACK_SIZE; ++i)
|
||||||
s.syncAsSint32LE(stack[i]);
|
s.syncAsSint32LE(stack[i]);
|
||||||
|
@ -320,14 +387,14 @@ void INT_CONTEXT::syncWithSerializer(Serializer &s) {
|
||||||
s.syncAsSint32LE(ip);
|
s.syncAsSint32LE(ip);
|
||||||
s.syncAsUint32LE(bHalt);
|
s.syncAsUint32LE(bHalt);
|
||||||
s.syncAsUint32LE(escOn);
|
s.syncAsUint32LE(escOn);
|
||||||
s.syncAsSint32LE(myescEvent);
|
s.syncAsSint32LE(myEscape);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return pointer to and size of global data for save/restore game.
|
* Return pointer to and size of global data for save/restore game.
|
||||||
*/
|
*/
|
||||||
void SaveInterpretContexts(INT_CONTEXT *sICInfo) {
|
void SaveInterpretContexts(INT_CONTEXT *sICInfo) {
|
||||||
memcpy(sICInfo, icList, MAX_INTERPRET * sizeof(INT_CONTEXT));
|
memcpy(sICInfo, icList, NUM_INTERPRET * sizeof(INT_CONTEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -451,6 +518,8 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
|
||||||
return;
|
return;
|
||||||
ic->sp += tmp2;
|
ic->sp += tmp2;
|
||||||
LockCode(ic);
|
LockCode(ic);
|
||||||
|
if (TinselV2 && (ic->resumeState == RES_1))
|
||||||
|
ic->resumeState = RES_NOT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_RET: // procedure return
|
case OP_RET: // procedure return
|
||||||
|
@ -567,12 +636,14 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_ESCON:
|
case OP_ESCON:
|
||||||
|
bNoPause = true;
|
||||||
ic->escOn = true;
|
ic->escOn = true;
|
||||||
ic->myescEvent = GetEscEvents();
|
ic->myEscape = GetEscEvents();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_ESCOFF:
|
case OP_ESCOFF:
|
||||||
ic->escOn = false;
|
ic->escOn = false;
|
||||||
|
ic->myEscape = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -590,4 +661,128 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
|
||||||
FreeInterpretContextPi(ic);
|
FreeInterpretContextPi(ic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates an interpret context with the
|
||||||
|
* process that will run it.
|
||||||
|
*/
|
||||||
|
void AttachInterpret(INT_CONTEXT *pic, PROCESS *pProc) {
|
||||||
|
// Attach the process which is using this context
|
||||||
|
pic->pProc = pProc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a number that isn't being used.
|
||||||
|
*/
|
||||||
|
static uint32 UniqueWaitNumber(void) {
|
||||||
|
uint32 retval;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (retval = DwGetCurrentTime(); 1; retval--) {
|
||||||
|
if (retval == 0)
|
||||||
|
retval = (uint32)-1;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_INTERPRET; i++) {
|
||||||
|
if ((icList+i)->waitNumber1 == retval
|
||||||
|
|| (icList+i)->waitNumber2 == retval)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == NUM_INTERPRET)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WaitInterpret
|
||||||
|
*/
|
||||||
|
void WaitInterpret(CORO_PARAM, PPROCESS pWaitProc, bool *result) {
|
||||||
|
int i;
|
||||||
|
PPROCESS currentProcess = g_scheduler->getCurrentProcess();
|
||||||
|
assert(currentProcess);
|
||||||
|
assert(currentProcess != pWaitProc);
|
||||||
|
if (result) *result = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calling process is the waiter, find its interpret context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
PINT_CONTEXT picWaiter, picWaitee;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
for (i = 0, _ctx->picWaiter = icList; i < NUM_INTERPRET; i++, _ctx->picWaiter++) {
|
||||||
|
if (_ctx->picWaiter->GSort != GS_NONE && _ctx->picWaiter->pProc == currentProcess) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the interpret context of the process we're waiting for
|
||||||
|
*/
|
||||||
|
for (i = 0, _ctx->picWaitee = icList; i < NUM_INTERPRET; i++, _ctx->picWaitee++) {
|
||||||
|
if (_ctx->picWaitee->GSort != GS_NONE && _ctx->picWaitee->pProc == pWaitProc) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the first as waiting for the second
|
||||||
|
*/
|
||||||
|
assert(_ctx->picWaitee->waitNumber2 == 0);
|
||||||
|
_ctx->picWaiter->waitNumber1 = _ctx->picWaitee->waitNumber2 = UniqueWaitNumber();
|
||||||
|
_ctx->picWaiter->resumeCode = RES_WAITING;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for it
|
||||||
|
*/
|
||||||
|
CORO_GIVE_WAY;
|
||||||
|
while (_ctx->picWaiter->resumeCode == RES_WAITING) {
|
||||||
|
CORO_SLEEP(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
*result = (_ctx->picWaiter->resumeCode == RES_FINISHED);
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CheckOutWaiters
|
||||||
|
*/
|
||||||
|
void CheckOutWaiters(void) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
// Check all waited for have someone waiting
|
||||||
|
for (i = 0; i < NUM_INTERPRET; i++) {
|
||||||
|
// If someone is supposedly waiting for this one
|
||||||
|
if ((icList + i)->GSort != GS_NONE && (icList + i)->waitNumber2) {
|
||||||
|
// Someone really must be waiting for this one
|
||||||
|
for (j = 0; j < NUM_INTERPRET; j++) {
|
||||||
|
if ((icList + j)->GSort != GS_NONE
|
||||||
|
&& (icList + j)->waitNumber1 == (icList + i)->waitNumber2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(j < NUM_INTERPRET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check waiting for someone to wait for
|
||||||
|
for (i = 0; i < NUM_INTERPRET; i++) {
|
||||||
|
// If someone is supposedly waiting for this one
|
||||||
|
if ((icList + i)->GSort != GS_NONE && (icList + i)->waitNumber1) {
|
||||||
|
// Someone really must be waiting for this one
|
||||||
|
for (j = 0; j < NUM_INTERPRET; j++) {
|
||||||
|
if ((icList + j)->GSort != GS_NONE
|
||||||
|
&& (icList + j)->waitNumber2 == (icList + i)->waitNumber1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(j < NUM_INTERPRET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#ifndef TINSEL_PCODE_H // prevent multiple includes
|
#ifndef TINSEL_PCODE_H // prevent multiple includes
|
||||||
#define TINSEL_PCODE_H
|
#define TINSEL_PCODE_H
|
||||||
|
|
||||||
#include "tinsel/events.h" // for USER_EVENT
|
#include "tinsel/events.h" // for TINSEL_EVENT
|
||||||
#include "tinsel/sched.h" // for PROCESS
|
#include "tinsel/sched.h" // for PROCESS
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
@ -45,9 +45,12 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GSORT {
|
enum GSORT {
|
||||||
GS_NONE, GS_ACTOR, GS_MASTER, GS_POLYGON, GS_INVENTORY, GS_SCENE
|
GS_NONE, GS_ACTOR, GS_MASTER, GS_POLYGON, GS_INVENTORY, GS_SCENE,
|
||||||
|
GS_PROCESS, GS_GPROCESS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RESCODE {RES_WAITING, RES_FINISHED, RES_CUTSHORT};
|
||||||
|
|
||||||
struct INT_CONTEXT {
|
struct INT_CONTEXT {
|
||||||
|
|
||||||
// Elements for interpret context management
|
// Elements for interpret context management
|
||||||
|
@ -57,9 +60,9 @@ struct INT_CONTEXT {
|
||||||
// Previously parameters to Interpret()
|
// Previously parameters to Interpret()
|
||||||
SCNHANDLE hCode; //!< scene handle of the code to execute
|
SCNHANDLE hCode; //!< scene handle of the code to execute
|
||||||
byte *code; //!< pointer to the code to execute
|
byte *code; //!< pointer to the code to execute
|
||||||
USER_EVENT event; //!< causal event
|
TINSEL_EVENT event; //!< causal event
|
||||||
HPOLYGON hpoly; //!< associated polygon (if any)
|
HPOLYGON hPoly; //!< associated polygon (if any)
|
||||||
int actorid; //!< associated actor (if any)
|
int idActor; //!< associated actor (if any)
|
||||||
INV_OBJECT *pinvo; //!< associated inventory object
|
INV_OBJECT *pinvo; //!< associated inventory object
|
||||||
|
|
||||||
// Previously local variables in Interpret()
|
// Previously local variables in Interpret()
|
||||||
|
@ -69,27 +72,32 @@ struct INT_CONTEXT {
|
||||||
int ip; //!< instruction pointer
|
int ip; //!< instruction pointer
|
||||||
bool bHalt; //!< set to exit interpeter
|
bool bHalt; //!< set to exit interpeter
|
||||||
bool escOn;
|
bool escOn;
|
||||||
int myescEvent; //!< only initialised to prevent compiler warning!
|
int myEscape; //!< only initialised to prevent compiler warning!
|
||||||
|
|
||||||
|
uint32 waitNumber1; // The waiting numbert
|
||||||
|
uint32 waitNumber2; // The wait for number
|
||||||
|
RESCODE resumeCode;
|
||||||
RESUME_STATE resumeState;
|
RESUME_STATE resumeState;
|
||||||
|
|
||||||
void syncWithSerializer(Serializer &s);
|
void syncWithSerializer(Serializer &s);
|
||||||
};
|
};
|
||||||
|
typedef INT_CONTEXT *PINT_CONTEXT;
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*\
|
/*----------------------------------------------------------------------*\
|
||||||
|* Interpreter Function Prototypes *|
|
|* Interpreter Function Prototypes *|
|
||||||
\*----------------------------------------------------------------------*/
|
\*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
void Interpret(CORO_PARAM, INT_CONTEXT *ic); // Interprets the PCODE instructions in the code array
|
// Interprets the PCODE instructions in the code array
|
||||||
|
void Interpret(CORO_PARAM, INT_CONTEXT *ic);
|
||||||
|
|
||||||
INT_CONTEXT *InitInterpretContext(
|
INT_CONTEXT *InitInterpretContext(
|
||||||
GSORT gsort,
|
GSORT gsort,
|
||||||
SCNHANDLE hCode, // code to execute
|
SCNHANDLE hCode, // code to execute
|
||||||
USER_EVENT event, // causal event
|
TINSEL_EVENT event, // causal event
|
||||||
HPOLYGON hpoly, // associated polygon (if any)
|
HPOLYGON hpoly, // associated polygon (if any)
|
||||||
int actorid, // associated actor (if any)
|
int actorid, // associated actor (if any)
|
||||||
INV_OBJECT *pinvo); // associated inventory object
|
INV_OBJECT *pinvo,
|
||||||
|
int myEscape = -1); // associated inventory object
|
||||||
|
|
||||||
INT_CONTEXT *RestoreInterpretContext(INT_CONTEXT *ric);
|
INT_CONTEXT *RestoreInterpretContext(INT_CONTEXT *ric);
|
||||||
|
|
||||||
|
@ -101,8 +109,12 @@ void SaveInterpretContexts(INT_CONTEXT *sICInfo);
|
||||||
void RegisterGlobals(int num);
|
void RegisterGlobals(int num);
|
||||||
void FreeGlobals(void);
|
void FreeGlobals(void);
|
||||||
|
|
||||||
|
void AttachInterpret(INT_CONTEXT *pic, PROCESS *pProc);
|
||||||
|
|
||||||
#define MAX_INTERPRET (NUM_PROCESS - 20)
|
void WaitInterpret(CORO_PARAM, PPROCESS pWaitProc, bool *result);
|
||||||
|
|
||||||
|
#define NUM_INTERPRET (NUM_PROCESS - 20)
|
||||||
|
#define MAX_INTERPRET (MAX_PROCESSES - 20)
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*\
|
/*----------------------------------------------------------------------*\
|
||||||
|* Library Procedure and Function codes parameter enums *|
|
|* Library Procedure and Function codes parameter enums *|
|
||||||
|
@ -137,10 +149,6 @@ void FreeGlobals(void);
|
||||||
#define MIDI_DEF 0
|
#define MIDI_DEF 0
|
||||||
#define MIDI_LOOP 1
|
#define MIDI_LOOP 1
|
||||||
|
|
||||||
#define TRANS_DEF 0
|
|
||||||
#define TRANS_CUT 1
|
|
||||||
#define TRANS_FADE 2
|
|
||||||
|
|
||||||
#define FM_IN 0 //
|
#define FM_IN 0 //
|
||||||
#define FM_OUT 1 // fademidi()
|
#define FM_OUT 1 // fademidi()
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "tinsel/actors.h"
|
#include "tinsel/actors.h"
|
||||||
#include "tinsel/background.h"
|
#include "tinsel/background.h"
|
||||||
|
#include "tinsel/coroutine.h"
|
||||||
#include "tinsel/cursor.h"
|
#include "tinsel/cursor.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/events.h"
|
#include "tinsel/events.h"
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
#include "tinsel/strres.h"
|
#include "tinsel/strres.h"
|
||||||
#include "tinsel/text.h"
|
#include "tinsel/text.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -56,8 +58,8 @@ extern int newestString; // The overrun counter, in STRRES.C
|
||||||
//----------------- EXTERNAL FUNCTIONS ---------------------
|
//----------------- EXTERNAL FUNCTIONS ---------------------
|
||||||
|
|
||||||
// in BG.C
|
// in BG.C
|
||||||
extern int BackgroundWidth(void);
|
extern int BgWidth(void);
|
||||||
extern int BackgroundHeight(void);
|
extern int BgHeight(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,8 +86,11 @@ static bool bShowString = false;
|
||||||
static int TaggedActor = 0;
|
static int TaggedActor = 0;
|
||||||
static HPOLYGON hTaggedPolygon = NOPOLY;
|
static HPOLYGON hTaggedPolygon = NOPOLY;
|
||||||
|
|
||||||
static enum { TAGS_OFF, TAGS_ON } TagsActive = TAGS_ON;
|
static bool bTagsActive = true;
|
||||||
|
|
||||||
|
static bool bPointingActive = true;
|
||||||
|
|
||||||
|
static char tagBuffer[64];
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/**
|
/**
|
||||||
|
@ -134,7 +139,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
||||||
|
|
||||||
char PositionString[64]; // sprintf() things into here
|
char PositionString[64]; // sprintf() things into here
|
||||||
|
|
||||||
PMACTOR pActor; // Lead actor
|
PMOVER pActor; // Lead actor
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
|
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
|
||||||
|
@ -159,7 +164,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
||||||
// New text objects
|
// New text objects
|
||||||
sprintf(PositionString, "%d %d", aniX + Loffset, aniY + Toffset);
|
sprintf(PositionString, "%d %d", aniX + Loffset, aniY + Toffset);
|
||||||
_ctx->cpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
_ctx->cpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||||
0, CPOSX, POSY, hTagFontHandle(), TXT_CENTRE);
|
0, CPOSX, POSY, GetTagFontHandle(), TXT_CENTRE);
|
||||||
if (DispPath) {
|
if (DispPath) {
|
||||||
HPOLYGON hp = InPolygon(aniX + Loffset, aniY + Toffset, PATH);
|
HPOLYGON hp = InPolygon(aniX + Loffset, aniY + Toffset, PATH);
|
||||||
if (hp == NOPOLY)
|
if (hp == NOPOLY)
|
||||||
|
@ -171,7 +176,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
||||||
PolyCornerX(hp, 2), PolyCornerY(hp, 2),
|
PolyCornerX(hp, 2), PolyCornerY(hp, 2),
|
||||||
PolyCornerX(hp, 3), PolyCornerY(hp, 3));
|
PolyCornerX(hp, 3), PolyCornerY(hp, 3));
|
||||||
_ctx->cpathText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
_ctx->cpathText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||||
0, 4, POSY+ 10, hTagFontHandle(), 0);
|
0, 4, POSY+ 10, GetTagFontHandle(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update previous position
|
// update previous position
|
||||||
|
@ -191,7 +196,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
||||||
|
|
||||||
sprintf(PositionString, "%d", Overrun);
|
sprintf(PositionString, "%d", Overrun);
|
||||||
_ctx->opText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
_ctx->opText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||||
0, OPOSX, POSY, hTagFontHandle(), TXT_CENTRE);
|
0, OPOSX, POSY, GetTagFontHandle(), TXT_CENTRE);
|
||||||
|
|
||||||
// update previous value
|
// update previous value
|
||||||
_ctx->prevOver = Overrun;
|
_ctx->prevOver = Overrun;
|
||||||
|
@ -202,7 +207,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
||||||
| Lead actor's position. |
|
| Lead actor's position. |
|
||||||
\*----------------------*/
|
\*----------------------*/
|
||||||
pActor = GetMover(LEAD_ACTOR);
|
pActor = GetMover(LEAD_ACTOR);
|
||||||
if (pActor && pActor->MActorState == NORM_MACTOR) {
|
if (pActor && pActor->MActorState == NORM_MOVER) {
|
||||||
// get lead's animation position
|
// get lead's animation position
|
||||||
GetActorPos(LEAD_ACTOR, &aniX, &aniY);
|
GetActorPos(LEAD_ACTOR, &aniX, &aniY);
|
||||||
|
|
||||||
|
@ -217,7 +222,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
||||||
// create new text object list
|
// create new text object list
|
||||||
sprintf(PositionString, "%d %d", aniX, aniY);
|
sprintf(PositionString, "%d %d", aniX, aniY);
|
||||||
_ctx->rpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
_ctx->rpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||||
0, LPOSX, POSY, hTagFontHandle(), TXT_CENTRE);
|
0, LPOSX, POSY, GetTagFontHandle(), TXT_CENTRE);
|
||||||
|
|
||||||
// update previous position
|
// update previous position
|
||||||
_ctx->prevlX = aniX;
|
_ctx->prevlX = aniX;
|
||||||
|
@ -236,7 +241,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
||||||
|
|
||||||
sprintf(PositionString, "String: %d", newestString);
|
sprintf(PositionString, "String: %d", newestString);
|
||||||
_ctx->spText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
_ctx->spText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||||
0, SPOSX, POSY+10, hTalkFontHandle(), TXT_CENTRE);
|
0, SPOSX, POSY+10, GetTalkFontHandle(), TXT_CENTRE);
|
||||||
|
|
||||||
// update previous value
|
// update previous value
|
||||||
_ctx->prevString = newestString;
|
_ctx->prevString = newestString;
|
||||||
|
@ -252,9 +257,52 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* While inventory/menu is open.
|
||||||
|
*/
|
||||||
|
void DisablePointing(CORO_PARAM) {
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
int i;
|
||||||
|
HPOLYGON hPoly; // Polygon handle
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
bPointingActive = false;
|
||||||
|
|
||||||
|
for (_ctx->i = 0; _ctx->i < MAX_POLY; _ctx->i++) {
|
||||||
|
_ctx->hPoly = GetPolyHandle(_ctx->i);
|
||||||
|
|
||||||
|
if (_ctx->hPoly != NOPOLY && PolyType(_ctx->hPoly) == TAG && PolyIsPointedTo(_ctx->hPoly)) {
|
||||||
|
SetPolyPointedTo(_ctx->hPoly, false);
|
||||||
|
SetPolyTagWanted(_ctx->hPoly, false, false, 0);
|
||||||
|
CORO_INVOKE_ARGS(PolygonEvent, (CORO_SUBCTX, _ctx->hPoly, UNPOINT, 0, false, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each tagged actor
|
||||||
|
for (_ctx->i = 0; (_ctx->i = NextTaggedActor(_ctx->i)) != 0; ) {
|
||||||
|
if (ActorIsPointedTo(_ctx->i)) {
|
||||||
|
SetActorPointedTo(_ctx->i, false);
|
||||||
|
SetActorTagWanted(_ctx->i, false, false, 0);
|
||||||
|
|
||||||
|
CORO_INVOKE_ARGS(ActorEvent, (CORO_SUBCTX, _ctx->i, UNPOINT, false, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EnablePointing()
|
||||||
|
*/
|
||||||
|
void EnablePointing(void) {
|
||||||
|
bPointingActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag process keeps us updated as to which tagged actor is currently tagged
|
* Tag process keeps us updated as to which tagged actor is currently tagged
|
||||||
* (if one is). Tag process asks us for this information, as does User_Event().
|
* (if one is). Tag process asks us for this information, as does ProcessUserEvent().
|
||||||
*/
|
*/
|
||||||
static void SaveTaggedActor(int ano) {
|
static void SaveTaggedActor(int ano) {
|
||||||
TaggedActor = ano;
|
TaggedActor = ano;
|
||||||
|
@ -262,7 +310,7 @@ static void SaveTaggedActor(int ano) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag process keeps us updated as to which tagged actor is currently tagged
|
* Tag process keeps us updated as to which tagged actor is currently tagged
|
||||||
* (if one is). Tag process asks us for this information, as does User_Event().
|
* (if one is). Tag process asks us for this information, as does ProcessUserEvent().
|
||||||
*/
|
*/
|
||||||
int GetTaggedActor(void) {
|
int GetTaggedActor(void) {
|
||||||
return TaggedActor;
|
return TaggedActor;
|
||||||
|
@ -270,7 +318,7 @@ int GetTaggedActor(void) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag process keeps us updated as to which polygon is currently tagged
|
* Tag process keeps us updated as to which polygon is currently tagged
|
||||||
* (if one is). Tag process asks us for this information, as does User_Event().
|
* (if one is). Tag process asks us for this information, as does ProcessUserEvent().
|
||||||
*/
|
*/
|
||||||
static void SaveTaggedPoly(HPOLYGON hp) {
|
static void SaveTaggedPoly(HPOLYGON hp) {
|
||||||
hTaggedPolygon = hp;
|
hTaggedPolygon = hp;
|
||||||
|
@ -341,12 +389,59 @@ static bool InHotSpot(int ano, int aniX, int aniY, int *pxtext, int *pytext) {
|
||||||
* the screen.
|
* the screen.
|
||||||
*/
|
*/
|
||||||
static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) {
|
static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) {
|
||||||
static int Loffset = 0, Toffset = 0; // Values when tag was displayed
|
static int tagX = 0, tagY = 0; // Values when tag was displayed
|
||||||
int nLoff, nToff; // new values, to keep tag in place
|
int newX, newY; // new values, to keep tag in place
|
||||||
int ano;
|
int ano;
|
||||||
int xtext, ytext;
|
int xtext, ytext;
|
||||||
bool newActor;
|
bool newActor;
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// Tinsel 2 version
|
||||||
|
// Get the foremost pointed to actor
|
||||||
|
int actor = FrontTaggedActor();
|
||||||
|
|
||||||
|
if (actor == 0) {
|
||||||
|
SaveTaggedActor(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If new actor
|
||||||
|
// or actor has suddenly decided it wants tagging...
|
||||||
|
if (actor != GetTaggedActor() || (ActorTagIsWanted(actor) && !*ppText)) {
|
||||||
|
// Put up actor tag
|
||||||
|
SaveTaggedActor(actor); // This actor tagged
|
||||||
|
SaveTaggedPoly(NOPOLY); // No tagged polygon
|
||||||
|
|
||||||
|
if (*ppText)
|
||||||
|
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText);
|
||||||
|
|
||||||
|
if (ActorTagIsWanted(actor)) {
|
||||||
|
GetActorTagPos(actor, &tagX, &tagY, false);
|
||||||
|
LoadStringRes(GetActorTagHandle(actor), tagBuffer, sizeof(tagBuffer));
|
||||||
|
|
||||||
|
// May have buggered cursor
|
||||||
|
EndCursorFollowed();
|
||||||
|
*ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), tagBuffer,
|
||||||
|
0, tagX, tagY, GetTagFontHandle(), TXT_CENTRE, 0);
|
||||||
|
assert(*ppText);
|
||||||
|
MultiSetZPosition(*ppText, Z_TAG_TEXT);
|
||||||
|
} else
|
||||||
|
*ppText = NULL;
|
||||||
|
} else if (*ppText) {
|
||||||
|
// Same actor, maintain tag position
|
||||||
|
GetActorTagPos(actor, &newX, &newY, false);
|
||||||
|
|
||||||
|
if (newX != tagX || newY != tagY) {
|
||||||
|
MultiMoveRelXY(*ppText, newX - tagX, newY - tagY);
|
||||||
|
tagX = newX;
|
||||||
|
tagY = newY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tinsel 1 version
|
||||||
// For each actor with a tag....
|
// For each actor with a tag....
|
||||||
FirstTaggedActor();
|
FirstTaggedActor();
|
||||||
while ((ano = NextTaggedActor()) != 0) {
|
while ((ano = NextTaggedActor()) != 0) {
|
||||||
|
@ -369,20 +464,20 @@ static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) {
|
||||||
SaveTaggedActor(ano); // This actor tagged
|
SaveTaggedActor(ano); // This actor tagged
|
||||||
SaveTaggedPoly(NOPOLY); // No tagged polygon
|
SaveTaggedPoly(NOPOLY); // No tagged polygon
|
||||||
|
|
||||||
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
|
PlayfieldGetPos(FIELD_WORLD, &tagX, &tagY);
|
||||||
LoadStringRes(GetActorTag(ano), tBufferAddr(), TBUFSZ);
|
LoadStringRes(GetActorTag(ano), TextBufferAddr(), TBUFSZ);
|
||||||
*ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(),
|
*ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
|
||||||
0, xtext - Loffset, ytext - Toffset, hTagFontHandle(), TXT_CENTRE);
|
0, xtext - tagX, ytext - tagY, GetTagFontHandle(), TXT_CENTRE);
|
||||||
assert(*ppText); // Actor tag string produced NULL text
|
assert(*ppText); // Actor tag string produced NULL text
|
||||||
MultiSetZPosition(*ppText, Z_TAG_TEXT);
|
MultiSetZPosition(*ppText, Z_TAG_TEXT);
|
||||||
} else {
|
} else {
|
||||||
// Maintain actor tag's position
|
// Maintain actor tag's position
|
||||||
|
|
||||||
PlayfieldGetPos(FIELD_WORLD, &nLoff, &nToff);
|
PlayfieldGetPos(FIELD_WORLD, &newX, &newY);
|
||||||
if (nLoff != Loffset || nToff != Toffset) {
|
if (newX != tagX || newY != tagY) {
|
||||||
MultiMoveRelXY(*ppText, Loffset - nLoff, Toffset - nToff);
|
MultiMoveRelXY(*ppText, tagX - newX, tagY - newY);
|
||||||
Loffset = nLoff;
|
tagX = newX;
|
||||||
Toffset = nToff;
|
tagY = newY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -406,6 +501,7 @@ static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) {
|
||||||
*/
|
*/
|
||||||
static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
|
static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
|
||||||
static int Loffset = 0, Toffset = 0; // Values when tag was displayed
|
static int Loffset = 0, Toffset = 0; // Values when tag was displayed
|
||||||
|
static int curX = 0, curY = 0;
|
||||||
int nLoff, nToff; // new values, to keep tag in place
|
int nLoff, nToff; // new values, to keep tag in place
|
||||||
HPOLYGON hp;
|
HPOLYGON hp;
|
||||||
bool newPoly;
|
bool newPoly;
|
||||||
|
@ -418,8 +514,11 @@ static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
|
||||||
for (int i = 0; i < MAX_POLY; i++) {
|
for (int i = 0; i < MAX_POLY; i++) {
|
||||||
hp = GetPolyHandle(i);
|
hp = GetPolyHandle(i);
|
||||||
|
|
||||||
|
if (TinselV2 && (hp == NOPOLY))
|
||||||
|
continue;
|
||||||
|
|
||||||
// Added code for un-tagged tags
|
// Added code for un-tagged tags
|
||||||
if (hp != NOPOLY && PolyPointState(hp) == POINTING && PolyTagState(hp) != TAG_ON) {
|
if ((hp != NOPOLY) && (PolyPointState(hp) == PS_POINTING) && (PolyTagState(hp) != TAG_ON)) {
|
||||||
// This poly is entitled to be tagged
|
// This poly is entitled to be tagged
|
||||||
if (hp != GetTaggedPoly()) {
|
if (hp != GetTaggedPoly()) {
|
||||||
if (*ppText) {
|
if (*ppText) {
|
||||||
|
@ -431,58 +530,99 @@ static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
|
||||||
SaveTaggedPoly(hp); // This polygon tagged
|
SaveTaggedPoly(hp); // This polygon tagged
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (hp != NOPOLY && PolyTagState(hp) == TAG_ON) {
|
} else if ((TinselV2 && PolyTagIsWanted(hp)) ||
|
||||||
|
(!TinselV2 && hp != NOPOLY && PolyTagState(hp) == TAG_ON)) {
|
||||||
// Put up or maintain polygon tag
|
// Put up or maintain polygon tag
|
||||||
|
newPoly = false;
|
||||||
|
if (TinselV2) {
|
||||||
|
if (hp != GetTaggedPoly())
|
||||||
|
newPoly = true; // Different polygon
|
||||||
|
} else {
|
||||||
if (*pTag != POLY_HOTSPOT_TAG)
|
if (*pTag != POLY_HOTSPOT_TAG)
|
||||||
newPoly = true; // A new polygon (no current)
|
newPoly = true; // A new polygon (no current)
|
||||||
else if (hp != GetTaggedPoly())
|
else if (hp != GetTaggedPoly())
|
||||||
newPoly = true; // Different polygon
|
newPoly = true; // Different polygon
|
||||||
else
|
}
|
||||||
newPoly = false; // Same polygon
|
|
||||||
|
|
||||||
if (newPoly) {
|
if (newPoly) {
|
||||||
if (*ppText)
|
if (*ppText)
|
||||||
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText);
|
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText);
|
||||||
|
|
||||||
|
if (!TinselV2)
|
||||||
*pTag = POLY_HOTSPOT_TAG;
|
*pTag = POLY_HOTSPOT_TAG;
|
||||||
SaveTaggedActor(0); // No tagged actor
|
SaveTaggedActor(0); // No tagged actor
|
||||||
SaveTaggedPoly(hp); // This polygon tagged
|
SaveTaggedPoly(hp); // This polygon tagged
|
||||||
|
|
||||||
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
|
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
|
||||||
getPolyTagInfo(hp, &hTagtext, &tagx, &tagy);
|
GetTagTag(hp, &hTagtext, &tagx, &tagy);
|
||||||
|
|
||||||
int strLen;
|
int strLen;
|
||||||
if (PolyTagHandle(hp) != 0)
|
if (GetPolyTagHandle(hp) != 0)
|
||||||
strLen = LoadStringRes(PolyTagHandle(hp), tBufferAddr(), TBUFSZ);
|
strLen = LoadStringRes(GetPolyTagHandle(hp), TextBufferAddr(), TBUFSZ);
|
||||||
else
|
else
|
||||||
strLen = LoadStringRes(hTagtext, tBufferAddr(), TBUFSZ);
|
strLen = LoadStringRes(hTagtext, TextBufferAddr(), TBUFSZ);
|
||||||
|
|
||||||
if (strLen == 0)
|
if (strLen == 0)
|
||||||
// No valid string returned, so leave ppText as NULL
|
// No valid string returned, so leave ppText as NULL
|
||||||
ppText = NULL;
|
ppText = NULL;
|
||||||
else {
|
else if (TinselV2 && !PolyTagFollowsCursor(hp)) {
|
||||||
// Handle displaying the tag text on-screen
|
// May have buggered cursor
|
||||||
*ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(),
|
EndCursorFollowed();
|
||||||
0, tagx - Loffset, tagy - Toffset,
|
|
||||||
hTagFontHandle(), TXT_CENTRE);
|
|
||||||
assert(*ppText); // Polygon tag string produced NULL text
|
|
||||||
MultiSetZPosition(*ppText, Z_TAG_TEXT);
|
|
||||||
|
|
||||||
|
*ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
|
||||||
|
TextBufferAddr(), 0, tagx - Loffset, tagy - Toffset,
|
||||||
|
GetTagFontHandle(), TXT_CENTRE, 0);
|
||||||
|
} else if (TinselV2) {
|
||||||
|
// Bugger cursor
|
||||||
|
const char *tagPtr = TextBufferAddr();
|
||||||
|
if (tagPtr[0] < ' ' && tagPtr[1] == EOS_CHAR)
|
||||||
|
StartCursorFollowed();
|
||||||
|
|
||||||
|
GetCursorXYNoWait(&curX, &curY, false);
|
||||||
|
*ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
|
||||||
|
0, curX, curY, GetTagFontHandle(), TXT_CENTRE, 0);
|
||||||
|
} else {
|
||||||
|
// Handle displaying the tag text on-screen
|
||||||
|
*ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
|
||||||
|
0, tagx - Loffset, tagy - Toffset,
|
||||||
|
GetTagFontHandle(), TXT_CENTRE);
|
||||||
|
assert(*ppText); // Polygon tag string produced NULL text
|
||||||
|
}
|
||||||
|
|
||||||
|
// DW1 has some tags without text, e.g. the "equals" button when talking to the guard in act 3
|
||||||
|
if (ppText) {
|
||||||
|
MultiSetZPosition(*ppText, Z_TAG_TEXT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* New feature: Don't go off the side of the background
|
* New feature: Don't go off the side of the background
|
||||||
*/
|
*/
|
||||||
shift = MultiRightmost(*ppText) + Loffset + 2;
|
shift = MultiRightmost(*ppText) + Loffset + 2;
|
||||||
if (shift >= BackgroundWidth()) // Not off right
|
if (shift >= BgWidth()) // Not off right
|
||||||
MultiMoveRelXY(*ppText, BackgroundWidth() - shift, 0);
|
MultiMoveRelXY(*ppText, BgWidth() - shift, 0);
|
||||||
shift = MultiLeftmost(*ppText) + Loffset - 1;
|
shift = MultiLeftmost(*ppText) + Loffset - 1;
|
||||||
if (shift <= 0) // Not off left
|
if (shift <= 0) // Not off left
|
||||||
MultiMoveRelXY(*ppText, -shift, 0);
|
MultiMoveRelXY(*ppText, -shift, 0);
|
||||||
shift = MultiLowest(*ppText) + Toffset;
|
shift = MultiLowest(*ppText) + Toffset;
|
||||||
if (shift > BackgroundHeight()) // Not off bottom
|
if (shift > BgHeight()) // Not off bottom
|
||||||
MultiMoveRelXY(*ppText, 0, BackgroundHeight() - shift);
|
MultiMoveRelXY(*ppText, 0, BgHeight() - shift);
|
||||||
|
}
|
||||||
|
} else if (TinselV2 && (*ppText)) {
|
||||||
|
if (!PolyTagFollowsCursor(hp)) {
|
||||||
|
PlayfieldGetPos(FIELD_WORLD, &nLoff, &nToff);
|
||||||
|
if (nLoff != Loffset || nToff != Toffset) {
|
||||||
|
MultiMoveRelXY(*ppText, Loffset - nLoff, Toffset - nToff);
|
||||||
|
Loffset = nLoff;
|
||||||
|
Toffset = nToff;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
GetCursorXY(&tagx, &tagy, false);
|
||||||
|
if (tagx != curX || tagy != curY) {
|
||||||
|
MultiMoveRelXY(*ppText, tagx - curX, tagy - curY);
|
||||||
|
curX = tagx;
|
||||||
|
curY = tagy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!TinselV2) {
|
||||||
PlayfieldGetPos(FIELD_WORLD, &nLoff, &nToff);
|
PlayfieldGetPos(FIELD_WORLD, &nLoff, &nToff);
|
||||||
if (nLoff != Loffset || nToff != Toffset) {
|
if (nLoff != Loffset || nToff != Toffset) {
|
||||||
MultiMoveRelXY(*ppText, Loffset - nLoff, Toffset - nToff);
|
MultiMoveRelXY(*ppText, Loffset - nLoff, Toffset - nToff);
|
||||||
|
@ -495,7 +635,9 @@ static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// No tagged polygon
|
// No tagged polygon
|
||||||
if (*pTag == POLY_HOTSPOT_TAG) {
|
if (TinselV2)
|
||||||
|
SaveTaggedPoly(NOPOLY);
|
||||||
|
else if (*pTag == POLY_HOTSPOT_TAG) {
|
||||||
*pTag = NO_HOTSPOT_TAG;
|
*pTag = NO_HOTSPOT_TAG;
|
||||||
SaveTaggedPoly(NOPOLY);
|
SaveTaggedPoly(NOPOLY);
|
||||||
}
|
}
|
||||||
|
@ -522,7 +664,7 @@ void TagProcess(CORO_PARAM, const void *) {
|
||||||
SaveTaggedPoly(NOPOLY); // No tagged polygon yet
|
SaveTaggedPoly(NOPOLY); // No tagged polygon yet
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (TagsActive == TAGS_ON) {
|
if (bTagsActive) {
|
||||||
int curX, curY; // cursor position
|
int curX, curY; // cursor position
|
||||||
while (!GetCursorXYNoWait(&curX, &curY, true))
|
while (!GetCursorXYNoWait(&curX, &curY, true))
|
||||||
CORO_SLEEP(1);
|
CORO_SLEEP(1);
|
||||||
|
@ -533,6 +675,10 @@ void TagProcess(CORO_PARAM, const void *) {
|
||||||
if (_ctx->pText) {
|
if (_ctx->pText) {
|
||||||
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText);
|
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText);
|
||||||
_ctx->pText = NULL;
|
_ctx->pText = NULL;
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
// May have buggered cursor
|
||||||
|
EndCursorFollowed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -557,22 +703,43 @@ void TagProcess(CORO_PARAM, const void *) {
|
||||||
/**
|
/**
|
||||||
* Called from PointProcess() as appropriate.
|
* Called from PointProcess() as appropriate.
|
||||||
*/
|
*/
|
||||||
static void enteringpoly(HPOLYGON hp) {
|
static void enteringpoly(CORO_PARAM, HPOLYGON hp) {
|
||||||
SetPolyPointState(hp, POINTING);
|
CORO_BEGIN_CONTEXT;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
RunPolyTinselCode(hp, POINTED, BE_NONE, false);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
SetPolyPointState(hp, PS_POINTING);
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
CORO_INVOKE_ARGS(PolygonEvent, (CORO_SUBCTX, hp, POINTED, 0, false, 0));
|
||||||
|
else
|
||||||
|
RunPolyTinselCode(hp, POINTED, PLR_NOEVENT, false);
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from PointProcess() as appropriate.
|
* Called from PointProcess() as appropriate.
|
||||||
*/
|
*/
|
||||||
static void leavingpoly(HPOLYGON hp) {
|
static void leavingpoly(CORO_PARAM, HPOLYGON hp) {
|
||||||
SetPolyPointState(hp, NOT_POINTING);
|
CORO_BEGIN_CONTEXT;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
if (PolyTagState(hp) == TAG_ON) {
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
SetPolyPointState(hp, PS_NOT_POINTING);
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
CORO_INVOKE_ARGS(PolygonEvent, (CORO_SUBCTX, hp, UNPOINT, 0, false, 0));
|
||||||
|
SetPolyTagWanted(hp, false, false, 0);
|
||||||
|
|
||||||
|
} else if (PolyTagState(hp) == TAG_ON) {
|
||||||
// Delete this tag entry
|
// Delete this tag entry
|
||||||
SetPolyTagState(hp, TAG_OFF);
|
SetPolyTagState(hp, TAG_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -583,56 +750,95 @@ static void leavingpoly(HPOLYGON hp) {
|
||||||
void PointProcess(CORO_PARAM, const void *) {
|
void PointProcess(CORO_PARAM, const void *) {
|
||||||
// COROUTINE
|
// COROUTINE
|
||||||
CORO_BEGIN_CONTEXT;
|
CORO_BEGIN_CONTEXT;
|
||||||
|
HPOLYGON hPoly;
|
||||||
|
int i;
|
||||||
|
int curX, curY; // cursor/tagged actor position
|
||||||
CORO_END_CONTEXT(_ctx);
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
EnablePointing();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int aniX, aniY; // cursor/tagged actor position
|
while (!GetCursorXYNoWait(&_ctx->curX, &_ctx->curY, true))
|
||||||
while (!GetCursorXYNoWait(&aniX, &aniY, true))
|
|
||||||
CORO_SLEEP(1);
|
CORO_SLEEP(1);
|
||||||
|
|
||||||
/*----------------------------------*\
|
/*----------------------------------*\
|
||||||
| For polygons of type TAG and EXIT. |
|
| For polygons of type TAG and EXIT. |
|
||||||
\*----------------------------------*/
|
\*----------------------------------*/
|
||||||
for (int i = 0; i < MAX_POLY; i++) {
|
for (_ctx->i = 0; _ctx->i < MAX_POLY; _ctx->i++) {
|
||||||
HPOLYGON hp = GetPolyHandle(i);
|
_ctx->hPoly = GetPolyHandle(_ctx->i);
|
||||||
|
if ((_ctx->hPoly == NOPOLY) || ((PolyType(_ctx->hPoly) != TAG) &&
|
||||||
|
(PolyType(_ctx->hPoly) != EXIT)))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (hp != NOPOLY && (PolyType(hp) == TAG || PolyType(hp) == EXIT)) {
|
if (!PolyIsPointedTo(_ctx->hPoly)) {
|
||||||
if (PolyPointState(hp) == NOT_POINTING) {
|
if (IsInPolygon(_ctx->curX, _ctx->curY, _ctx->hPoly)) {
|
||||||
if (IsInPolygon(aniX, aniY, hp)) {
|
if (TinselV2) {
|
||||||
enteringpoly(hp);
|
SetPolyPointedTo(_ctx->hPoly, true);
|
||||||
|
CORO_INVOKE_ARGS(PolygonEvent, (CORO_SUBCTX, _ctx->hPoly, POINTED, 0, false, 0));
|
||||||
|
} else {
|
||||||
|
CORO_INVOKE_1(enteringpoly, _ctx->hPoly);
|
||||||
}
|
}
|
||||||
} else if (PolyPointState(hp) == POINTING) {
|
|
||||||
if (!IsInPolygon(aniX, aniY, hp)) {
|
|
||||||
leavingpoly(hp);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (!IsInPolygon(_ctx->curX, _ctx->curY, _ctx->hPoly)) {
|
||||||
|
if (TinselV2) {
|
||||||
|
SetPolyPointedTo(_ctx->hPoly, false);
|
||||||
|
SetPolyTagWanted(_ctx->hPoly, false, false, 0);
|
||||||
|
CORO_INVOKE_ARGS(PolygonEvent, (CORO_SUBCTX, _ctx->hPoly, UNPOINT, 0, false, 0));
|
||||||
|
} else {
|
||||||
|
CORO_INVOKE_1(leavingpoly, _ctx->hPoly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// For each tagged actor
|
||||||
|
for (_ctx->i = 0; (_ctx->i = NextTaggedActor(_ctx->i)) != 0; ) {
|
||||||
|
if (!ActorIsPointedTo(_ctx->i)) {
|
||||||
|
if (InHotSpot(_ctx->i, _ctx->curX, _ctx->curY)) {
|
||||||
|
SetActorPointedTo(_ctx->i, true);
|
||||||
|
CORO_INVOKE_ARGS(ActorEvent, (CORO_SUBCTX, _ctx->i, POINTED, false, 0));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!InHotSpot(_ctx->i, _ctx->curX, _ctx->curY)) {
|
||||||
|
SetActorPointedTo(_ctx->i, false);
|
||||||
|
SetActorTagWanted(_ctx->i, false, false, 0);
|
||||||
|
CORO_INVOKE_ARGS(ActorEvent, (CORO_SUBCTX, _ctx->i, UNPOINT, false, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow re-scheduling
|
// allow re-scheduling
|
||||||
|
do {
|
||||||
CORO_SLEEP(1);
|
CORO_SLEEP(1);
|
||||||
|
} while (!bPointingActive);
|
||||||
|
} else {
|
||||||
|
// allow re-scheduling
|
||||||
|
CORO_SLEEP(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisableTags(void) {
|
void DisableTags(void) {
|
||||||
TagsActive = TAGS_OFF;
|
bTagsActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnableTags(void) {
|
void EnableTags(void) {
|
||||||
TagsActive = TAGS_ON;
|
bTagsActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DisableTagsIfEnabled(void) {
|
bool DisableTagsIfEnabled(void) {
|
||||||
if (TagsActive == TAGS_OFF)
|
if (bTagsActive) {
|
||||||
return false;
|
DisableTags();
|
||||||
else {
|
|
||||||
TagsActive = TAGS_OFF;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
} else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
37
engines/tinsel/pdisplay.h
Normal file
37
engines/tinsel/pdisplay.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Tag related methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TINSEL_PDISPLAY_H // prevent multiple includes
|
||||||
|
#define TINSEL_PDISPLAY_H
|
||||||
|
|
||||||
|
namespace Tinsel {
|
||||||
|
|
||||||
|
void EnableTags(void);
|
||||||
|
void DisableTags(void);
|
||||||
|
|
||||||
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
#endif /* TINSEL_PDISPLAY_H */
|
|
@ -61,12 +61,20 @@ namespace Tinsel {
|
||||||
|
|
||||||
#define PID_MASTER_SCR 0x00C0 // tinsel master script process
|
#define PID_MASTER_SCR 0x00C0 // tinsel master script process
|
||||||
|
|
||||||
#define PID_MACTOR (0x00D0 | PID_DESTROY) // moving actor process
|
#define PID_MOVER (0x00D0 | PID_DESTROY) // moving actor process
|
||||||
|
|
||||||
#define PID_REEL (0x00E0 | PID_DESTROY) // process for each film reel
|
#define PID_REEL (0x00E0 | PID_DESTROY) // process for each film reel
|
||||||
|
|
||||||
#define PID_MIDI (0x00F0 | PID_DESTROY) // process to poll MIDI sound driver
|
#define PID_MIDI (0x00F0 | PID_DESTROY) // process to poll MIDI sound driver
|
||||||
|
|
||||||
|
#define PID_BMV 0x0100 // Movie player process
|
||||||
|
|
||||||
|
#define PID_BTN_CLICK 0x110 // process to handle mouse button clicks
|
||||||
|
|
||||||
|
#define PID_PROCESS (0x0110 | PID_DESTROY) // Scene process base
|
||||||
|
|
||||||
|
#define PID_GPROCESS 0x0120 // Global process base
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif // TINSEL_PID_H
|
#endif // TINSEL_PID_H
|
||||||
|
|
File diff suppressed because it is too large
Load diff
64
engines/tinsel/play.h
Normal file
64
engines/tinsel/play.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Plays films within a scene, takes into account the actor in each 'column'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TINSEL_PLAY_H // prevent multiple includes
|
||||||
|
#define TINSEL_PLAY_H
|
||||||
|
|
||||||
|
#include "tinsel/coroutine.h"
|
||||||
|
#include "tinsel/dw.h"
|
||||||
|
#include "tinsel/multiobj.h"
|
||||||
|
|
||||||
|
namespace Tinsel {
|
||||||
|
|
||||||
|
#define MAX_SOUNDREELS 5
|
||||||
|
|
||||||
|
struct SOUNDREELS {
|
||||||
|
SCNHANDLE hFilm; // The 'film'
|
||||||
|
int column; // Column number
|
||||||
|
int actorCol;
|
||||||
|
};
|
||||||
|
typedef SOUNDREELS *PSOUNDREELS;
|
||||||
|
|
||||||
|
void PlayFilm(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay, bool sfact, bool escOn,
|
||||||
|
int myescEvent, bool bTop);
|
||||||
|
|
||||||
|
void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int myescEvent, bool bTop);
|
||||||
|
|
||||||
|
void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact,
|
||||||
|
bool escOn, int myescEvent, bool bTop);
|
||||||
|
|
||||||
|
void RestoreActorReels(SCNHANDLE hFilm, short reelnum, short z, int x, int y);
|
||||||
|
void RestoreActorReels(SCNHANDLE hFilm, int actor, int x, int y);
|
||||||
|
|
||||||
|
void PokeInPalette(const MULTI_INIT *pmi);
|
||||||
|
|
||||||
|
void NoSoundReels(void);
|
||||||
|
void SaveSoundReels(PSOUNDREELS psr);
|
||||||
|
void RestoreSoundReels(PSOUNDREELS psr);
|
||||||
|
|
||||||
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -35,8 +35,12 @@ namespace Tinsel {
|
||||||
|
|
||||||
// Polygon Types
|
// Polygon Types
|
||||||
enum PTYPE {
|
enum PTYPE {
|
||||||
TEST, PATH, EXIT, BLOCKING,
|
// Tinsel 2 Polygon type list
|
||||||
EFFECT, REFER, TAG, EX_TAG, EX_EXIT, EX_BLOCK
|
TEST,
|
||||||
|
BLOCK, EFFECT, PATH, REFER, TAG,
|
||||||
|
EX_BLOCK, EX_EFFECT, EX_PATH, EX_REFER, EX_TAG,
|
||||||
|
// Extra polygon types from Tinsel v1
|
||||||
|
EXIT, EX_EXIT
|
||||||
};
|
};
|
||||||
|
|
||||||
// subtype
|
// subtype
|
||||||
|
@ -45,6 +49,13 @@ enum {
|
||||||
NODE = 1 // For paths
|
NODE = 1 // For paths
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// tagFlags
|
||||||
|
enum {
|
||||||
|
POINTING = 0x01,
|
||||||
|
TAGWANTED = 0x02,
|
||||||
|
FOLLOWCURSOR = 0x04
|
||||||
|
};
|
||||||
|
|
||||||
// tagState
|
// tagState
|
||||||
enum TSTATE {
|
enum TSTATE {
|
||||||
TAG_OFF, TAG_ON
|
TAG_OFF, TAG_ON
|
||||||
|
@ -52,7 +63,7 @@ enum TSTATE {
|
||||||
|
|
||||||
// pointState
|
// pointState
|
||||||
enum PSTATE {
|
enum PSTATE {
|
||||||
NO_POINT, NOT_POINTING, POINTING
|
PS_NO_POINT, PS_NOT_POINTING, PS_POINTING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +71,10 @@ enum {
|
||||||
NOPOLY = -1
|
NOPOLY = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct POLY_VOLATILE {
|
||||||
|
bool bDead;
|
||||||
|
short xoff, yoff; // Polygon offset
|
||||||
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -69,26 +83,36 @@ HPOLYGON InPolygon(int xt, int yt, PTYPE type);
|
||||||
void BlockingCorner(HPOLYGON poly, int *x, int *y, int tarx, int tary);
|
void BlockingCorner(HPOLYGON poly, int *x, int *y, int tarx, int tary);
|
||||||
void FindBestPoint(HPOLYGON path, int *x, int *y, int *line);
|
void FindBestPoint(HPOLYGON path, int *x, int *y, int *line);
|
||||||
bool IsAdjacentPath(HPOLYGON path1, HPOLYGON path2);
|
bool IsAdjacentPath(HPOLYGON path1, HPOLYGON path2);
|
||||||
HPOLYGON getPathOnTheWay(HPOLYGON from, HPOLYGON to);
|
HPOLYGON GetPathOnTheWay(HPOLYGON from, HPOLYGON to);
|
||||||
int NearestEndNode(HPOLYGON path, int x, int y);
|
int NearestEndNode(HPOLYGON path, int x, int y);
|
||||||
int NearEndNode(HPOLYGON spath, HPOLYGON dpath);
|
int NearEndNode(HPOLYGON spath, HPOLYGON dpath);
|
||||||
int NearestNodeWithin(HPOLYGON npath, int x, int y);
|
int NearestNodeWithin(HPOLYGON npath, int x, int y);
|
||||||
void NearestCorner(int *x, int *y, HPOLYGON spath, HPOLYGON dpath);
|
void NearestCorner(int *x, int *y, HPOLYGON spath, HPOLYGON dpath);
|
||||||
bool IsPolyCorner(HPOLYGON hPath, int x, int y);
|
bool IsPolyCorner(HPOLYGON hPath, int x, int y);
|
||||||
int GetScale(HPOLYGON path, int y);
|
int GetScale(HPOLYGON path, int y);
|
||||||
|
int GetBrightness(HPOLYGON hPath, int y);
|
||||||
void getNpathNode(HPOLYGON npath, int node, int *px, int *py);
|
void getNpathNode(HPOLYGON npath, int node, int *px, int *py);
|
||||||
void getPolyTagInfo(HPOLYGON p, SCNHANDLE *hTagText, int *tagx, int *tagy);
|
void GetTagTag(HPOLYGON p, SCNHANDLE *hTagText, int *tagx, int *tagy);
|
||||||
SCNHANDLE getPolyFilm(HPOLYGON p);
|
SCNHANDLE GetPolyFilm(HPOLYGON p);
|
||||||
void getPolyNode(HPOLYGON p, int *px, int *py);
|
void GetPolyNode(HPOLYGON hp, int *pNodeX, int *pNodeY);
|
||||||
SCNHANDLE getPolyScript(HPOLYGON p);
|
SCNHANDLE GetPolyScript(HPOLYGON p);
|
||||||
REEL getPolyReelType(HPOLYGON p);
|
REEL GetPolyReelType(HPOLYGON p);
|
||||||
int32 getPolyZfactor(HPOLYGON p);
|
int32 GetPolyZfactor(HPOLYGON p);
|
||||||
int numNodes(HPOLYGON pp);
|
int numNodes(HPOLYGON pp);
|
||||||
void RebootDeadTags(void);
|
void RebootDeadTags(void);
|
||||||
|
void DisableBlock(int block);
|
||||||
|
void EnableBlock(int block);
|
||||||
|
void DisableEffect(int effect);
|
||||||
|
void EnableEffect(int effect);
|
||||||
|
void DisablePath(int path);
|
||||||
|
void EnablePath(int path);
|
||||||
|
void DisableRefer(int refer);
|
||||||
|
void EnableRefer(int refer);
|
||||||
void DisableBlock(int blockno);
|
void DisableBlock(int blockno);
|
||||||
void EnableBlock(int blockno);
|
void EnableBlock(int blockno);
|
||||||
void DisableTag(int tagno);
|
HPOLYGON GetTagHandle(int tagno);
|
||||||
void EnableTag(int tagno);
|
void DisableTag(CORO_PARAM, int tag);
|
||||||
|
void EnableTag(CORO_PARAM, int tag);
|
||||||
void DisableExit(int exitno);
|
void DisableExit(int exitno);
|
||||||
void EnableExit(int exitno);
|
void EnableExit(int exitno);
|
||||||
HPOLYGON FirstPathPoly(void);
|
HPOLYGON FirstPathPoly(void);
|
||||||
|
@ -99,6 +123,8 @@ void DropPolygons(void);
|
||||||
|
|
||||||
void SaveDeadPolys(bool *sdp);
|
void SaveDeadPolys(bool *sdp);
|
||||||
void RestoreDeadPolys(bool *sdp);
|
void RestoreDeadPolys(bool *sdp);
|
||||||
|
void SavePolygonStuff(POLY_VOLATILE *sps);
|
||||||
|
void RestorePolygonStuff(POLY_VOLATILE *sps);
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -110,7 +136,6 @@ int PolyCornerX(HPOLYGON hp, int n); // ->cx[n]
|
||||||
int PolyCornerY(HPOLYGON hp, int n); // ->cy[n]
|
int PolyCornerY(HPOLYGON hp, int n); // ->cy[n]
|
||||||
PSTATE PolyPointState(HPOLYGON hp); // ->pointState
|
PSTATE PolyPointState(HPOLYGON hp); // ->pointState
|
||||||
TSTATE PolyTagState(HPOLYGON hp); // ->tagState
|
TSTATE PolyTagState(HPOLYGON hp); // ->tagState
|
||||||
SCNHANDLE PolyTagHandle(HPOLYGON hp); // ->oTagHandle
|
|
||||||
|
|
||||||
void SetPolyPointState(HPOLYGON hp, PSTATE ps); // ->pointState
|
void SetPolyPointState(HPOLYGON hp, PSTATE ps); // ->pointState
|
||||||
void SetPolyTagState(HPOLYGON hp, TSTATE ts); // ->tagState
|
void SetPolyTagState(HPOLYGON hp, TSTATE ts); // ->tagState
|
||||||
|
@ -118,6 +143,21 @@ void SetPolyTagHandle(HPOLYGON hp, SCNHANDLE th);// ->oTagHandle
|
||||||
|
|
||||||
void MaxPolygons(int maxPolys);
|
void MaxPolygons(int maxPolys);
|
||||||
|
|
||||||
|
int GetTagPolyId(HPOLYGON hp);
|
||||||
|
void GetTagTag(HPOLYGON hp, SCNHANDLE *hTagText, int *tagX, int *tagY);
|
||||||
|
void SetPolyPointedTo(HPOLYGON hp, bool bPointedTo);
|
||||||
|
bool PolyIsPointedTo(HPOLYGON hp);
|
||||||
|
void SetPolyTagWanted(HPOLYGON hp, bool bTagWanted, bool bCursor, SCNHANDLE hOverrideTag);
|
||||||
|
bool PolyTagIsWanted(HPOLYGON hp);
|
||||||
|
bool PolyTagFollowsCursor(HPOLYGON hp);
|
||||||
|
SCNHANDLE GetPolyTagHandle(HPOLYGON hp);
|
||||||
|
bool IsTagPolygon(int tagno);
|
||||||
|
int GetTagPolyId(HPOLYGON hp);
|
||||||
|
void GetPolyMidBottom( HPOLYGON hp, int *pX, int *pY);
|
||||||
|
int PathCount(void);
|
||||||
|
void MovePolygon(PTYPE ptype, int id, int x, int y);
|
||||||
|
void MovePolygonTo(PTYPE ptype, int id, int x, int y);
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include "tinsel/anim.h" // for ANIM
|
#include "tinsel/anim.h" // for ANIM
|
||||||
#include "tinsel/scene.h" // for TFTYPE
|
#include "tinsel/scene.h" // for TFTYPE
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -39,31 +40,30 @@ enum NPS {NOT_IN, GOING_UP, GOING_DOWN, LEAVING, ENTERING};
|
||||||
|
|
||||||
enum IND {NO_PROB, TRY_CENTRE, TRY_CORNER, TRY_NEXTCORNER};
|
enum IND {NO_PROB, TRY_CENTRE, TRY_CORNER, TRY_NEXTCORNER};
|
||||||
|
|
||||||
enum MAS {NO_MACTOR, NORM_MACTOR};
|
enum DIRECTION { LEFTREEL, RIGHTREEL, FORWARD, AWAY };
|
||||||
|
|
||||||
enum DIRREEL{ LEFTREEL, RIGHTREEL, FORWARD, AWAY };
|
#define NUM_MAINSCALES (TinselV2 ? 10 : 5)
|
||||||
|
#define NUM_AUXSCALES 5
|
||||||
|
#define TOTAL_SCALES (NUM_MAINSCALES + NUM_AUXSCALES)
|
||||||
|
#define REQ_MAIN_SCALES 10
|
||||||
|
#define REQ_TOTAL_SCALES 15
|
||||||
|
|
||||||
enum {
|
#define BOGUS_BRIGHTNESS -1
|
||||||
NUM_MAINSCALES = 5,
|
|
||||||
NUM_AUXSCALES = 5,
|
|
||||||
TOTAL_SCALES = NUM_MAINSCALES + NUM_AUXSCALES
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MACTOR {
|
struct MOVER {
|
||||||
|
|
||||||
int objx; /* Co-ordinates object */
|
int objX, objY; /* Co-ordinates object */
|
||||||
int objy;
|
|
||||||
|
|
||||||
int targetX, targetY;
|
int targetX, targetY;
|
||||||
int ItargetX, ItargetY; /* Intermediate destination */
|
int ItargetX, ItargetY; /* Intermediate destination */
|
||||||
HPOLYGON hIpath;
|
|
||||||
int UtargetX, UtargetY; /* Ultimate destination */
|
int UtargetX, UtargetY; /* Ultimate destination */
|
||||||
HPOLYGON hUpath;
|
|
||||||
|
|
||||||
|
HPOLYGON hIpath;
|
||||||
|
HPOLYGON hUpath;
|
||||||
HPOLYGON hCpath;
|
HPOLYGON hCpath;
|
||||||
|
|
||||||
bool over;
|
bool over;
|
||||||
int ticket;
|
int walkNumber;
|
||||||
|
|
||||||
IND InDifficulty;
|
IND InDifficulty;
|
||||||
|
|
||||||
|
@ -74,129 +74,147 @@ struct MACTOR {
|
||||||
|
|
||||||
int Tline; // NEW
|
int Tline; // NEW
|
||||||
|
|
||||||
bool TagReelRunning;
|
// TODO: TagReelRunning may be the same as bSpecReel
|
||||||
|
bool bSpecReel;
|
||||||
|
|
||||||
/* Used internally */
|
/* Used internally */
|
||||||
DIRREEL dirn; // Current reel
|
DIRECTION direction; // Current reel
|
||||||
int scale; // Current scale
|
int scale; // Current scale
|
||||||
int scount; // Step count for walking reel synchronisation
|
|
||||||
|
|
||||||
unsigned fromx;
|
int stepCount; // Step count for walking reel synchronisation
|
||||||
unsigned fromy;
|
|
||||||
|
int walkedFromX, walkedFromY;
|
||||||
|
|
||||||
bool bMoving; // Set this to TRUE during a walk
|
bool bMoving; // Set this to TRUE during a walk
|
||||||
|
|
||||||
bool bNoPath;
|
bool bNoPath;
|
||||||
bool bIgPath;
|
bool bIgPath;
|
||||||
bool walkReel;
|
bool bWalkReel;
|
||||||
|
|
||||||
OBJECT *actorObj; // Actor's object
|
OBJECT *actorObj; // Actor's object
|
||||||
ANIM actorAnim; // Actor's animation script
|
ANIM actorAnim; // Actor's animation script
|
||||||
|
|
||||||
SCNHANDLE lastfilm; // } Used by AlterActor()
|
SCNHANDLE hLastFilm; // } Used by AlterMover()
|
||||||
SCNHANDLE pushedfilm; // }
|
SCNHANDLE hPushedFilm; // }
|
||||||
|
|
||||||
int actorID;
|
int actorID;
|
||||||
int actorToken;
|
int actorToken;
|
||||||
|
|
||||||
SCNHANDLE WalkReels[TOTAL_SCALES][4];
|
SCNHANDLE walkReels[REQ_TOTAL_SCALES][4];
|
||||||
SCNHANDLE StandReels[TOTAL_SCALES][4];
|
SCNHANDLE standReels[REQ_TOTAL_SCALES][4];
|
||||||
SCNHANDLE TalkReels[TOTAL_SCALES][4];
|
SCNHANDLE talkReels[REQ_TOTAL_SCALES][4];
|
||||||
|
|
||||||
MAS MActorState;
|
bool bActive;
|
||||||
|
|
||||||
bool aHidden;
|
|
||||||
int SlowFactor; // Slow down movement while hidden
|
int SlowFactor; // Slow down movement while hidden
|
||||||
|
|
||||||
bool stop;
|
bool bStop;
|
||||||
|
|
||||||
/* NOTE: If effect polys can overlap, this needs improving */
|
/* NOTE: If effect polys can overlap, this needs improving */
|
||||||
bool InEffect;
|
bool bInEffect;
|
||||||
|
|
||||||
PROCESS *pProc;
|
PROCESS *pProc;
|
||||||
|
|
||||||
|
// Discworld 2 specific fields
|
||||||
|
int32 zOverride;
|
||||||
|
bool bHidden;
|
||||||
|
int brightness; // Current brightness
|
||||||
|
int startColour;
|
||||||
|
int paletteLength;
|
||||||
|
HPOLYGON hRpath; // Recent path
|
||||||
};
|
};
|
||||||
typedef MACTOR *PMACTOR;
|
typedef MOVER *PMOVER;
|
||||||
|
|
||||||
|
struct MAINIT {
|
||||||
|
int X;
|
||||||
|
int Y;
|
||||||
|
PMOVER pMover;
|
||||||
|
};
|
||||||
|
typedef MAINIT *PMAINIT;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
void MActorProcessCreate(int X, int Y, int id, MACTOR *pActor);
|
void MoverProcessCreate(int X, int Y, int id, PMOVER pMover);
|
||||||
|
|
||||||
|
|
||||||
enum AR_FUNCTION { AR_NORMAL, AR_PUSHREEL, AR_POPREEL, AR_WALKREEL };
|
enum AR_FUNCTION { AR_NORMAL, AR_PUSHREEL, AR_POPREEL, AR_WALKREEL };
|
||||||
|
|
||||||
|
void StoreMoverPalette(PMOVER pMover, int startColour, int length);
|
||||||
|
|
||||||
MACTOR *GetMover(int ano);
|
void MoverBrightness(PMOVER pMover, int brightness);
|
||||||
MACTOR *SetMover(int ano);
|
|
||||||
void KillMActor(MACTOR *pActor);
|
|
||||||
MACTOR *GetLiveMover(int index);
|
|
||||||
|
|
||||||
MAS getMActorState(MACTOR *psActor);
|
MOVER *GetMover(int ano);
|
||||||
|
MOVER *RegisterMover(int ano);
|
||||||
|
void KillMover(PMOVER pMover);
|
||||||
|
MOVER *GetLiveMover(int index);
|
||||||
|
|
||||||
void hideMActor(MACTOR *pActor, int sf);
|
bool getMActorState(MOVER *psActor);
|
||||||
bool getMActorHideState(MACTOR *pActor);
|
int GetMoverId(PMOVER pMover);
|
||||||
void unhideMActor(MACTOR *pActor);
|
void SetMoverZ(PMOVER pMover, int y, uint32 zFactor);
|
||||||
void DropMActors(void);
|
void SetMoverZoverride(PMOVER pMover, uint32 zFactor);
|
||||||
void MoveMActor(MACTOR *pActor, int x, int y);
|
|
||||||
|
|
||||||
void GetMActorPosition(MACTOR *pActor, int *aniX, int *aniY);
|
void HideMover(PMOVER pMover, int sf = 0);
|
||||||
void GetMActorMidTopPosition(MACTOR *pActor, int *aniX, int *aniY);
|
bool MoverHidden(PMOVER pMover);
|
||||||
int GetMActorLeft(MACTOR *pActor);
|
bool MoverIs(PMOVER pMover);
|
||||||
int GetMActorRight(MACTOR *pActor);
|
bool MoverIsSWalking(PMOVER pMover);
|
||||||
|
bool MoverMoving(PMOVER pMover);
|
||||||
|
int GetWalkNumber(PMOVER pMover);
|
||||||
|
void UnHideMover(PMOVER pMover);
|
||||||
|
void DropMovers(void);
|
||||||
|
void PositionMover(PMOVER pMover, int x, int y);
|
||||||
|
|
||||||
bool MActorIsInPolygon(MACTOR *pActor, HPOLYGON hPoly);
|
void GetMoverPosition(PMOVER pMover, int *aniX, int *aniY);
|
||||||
void AlterMActor(MACTOR *actor, SCNHANDLE film, AR_FUNCTION fn);
|
void GetMoverMidTop(PMOVER pMover, int *aniX, int *aniY);
|
||||||
DIRREEL GetMActorDirection(MACTOR *pActor);
|
int GetMoverLeft(PMOVER pMover);
|
||||||
int GetMActorScale(MACTOR *pActor);
|
int GetMoverRight(PMOVER pMover);
|
||||||
void SetMActorDirection(MACTOR *pActor, DIRREEL dirn);
|
int GetMoverTop(PMOVER pMover);
|
||||||
void SetMActorStanding(MACTOR *actor);
|
int GetMoverBottom(PMOVER pMover);
|
||||||
void SetMActorWalkReel(MACTOR *actor, DIRREEL reel, int scale, bool force);
|
|
||||||
|
|
||||||
MACTOR *InMActorBlock(MACTOR *pActor, int x, int y);
|
bool MoverIsInPolygon(PMOVER pMover, HPOLYGON hPoly);
|
||||||
|
void AlterMover(PMOVER pMover, SCNHANDLE film, AR_FUNCTION fn);
|
||||||
|
DIRECTION GetMoverDirection(PMOVER pMover);
|
||||||
|
int GetMoverScale(PMOVER pMover);
|
||||||
|
void SetMoverDirection(PMOVER pMover, DIRECTION dirn);
|
||||||
|
void SetMoverStanding(PMOVER pMover);
|
||||||
|
void SetMoverWalkReel(PMOVER pMover, DIRECTION reel, int scale, bool force);
|
||||||
|
|
||||||
|
PMOVER InMoverBlock(PMOVER pMover, int x, int y);
|
||||||
|
|
||||||
void RebootMovers(void);
|
void RebootMovers(void);
|
||||||
|
|
||||||
bool IsMAinEffectPoly(int index);
|
bool IsMAinEffectPoly(int index);
|
||||||
void SetMAinEffectPoly(int index, bool tf);
|
void SetMoverInEffect(int index, bool tf);
|
||||||
|
|
||||||
bool MAmoving(MACTOR *pActor);
|
void StopMover(PMOVER pMover);
|
||||||
|
|
||||||
int GetActorTicket(MACTOR *pActor);
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
struct SAVED_MOVER {
|
struct SAVED_MOVER {
|
||||||
|
|
||||||
MAS MActorState;
|
|
||||||
int actorID;
|
int actorID;
|
||||||
int objx;
|
int objX;
|
||||||
int objy;
|
int objY;
|
||||||
SCNHANDLE lastfilm;
|
SCNHANDLE hLastfilm;
|
||||||
|
|
||||||
SCNHANDLE WalkReels[TOTAL_SCALES][4];
|
SCNHANDLE walkReels[REQ_TOTAL_SCALES][4];
|
||||||
SCNHANDLE StandReels[TOTAL_SCALES][4];
|
SCNHANDLE standReels[REQ_TOTAL_SCALES][4];
|
||||||
SCNHANDLE TalkReels[TOTAL_SCALES][4];
|
SCNHANDLE talkReels[REQ_TOTAL_SCALES][4];
|
||||||
|
|
||||||
|
bool bActive;
|
||||||
|
bool bHidden;
|
||||||
|
int brightness;
|
||||||
|
int startColour;
|
||||||
|
int paletteLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
void SaveMovers(SAVED_MOVER *sMoverInfo);
|
void SaveMovers(SAVED_MOVER *sMoverInfo);
|
||||||
void RestoreAuxScales(SAVED_MOVER *sMoverInfo);
|
void RestoreAuxScales(SAVED_MOVER *sMoverInfo);
|
||||||
|
|
||||||
|
PMOVER NextMover(PMOVER pMover);
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Dodgy bit...
|
|
||||||
* These functions are now in MAREELS.C, but I can't be bothered to
|
|
||||||
* create a new header file.
|
|
||||||
*/
|
|
||||||
SCNHANDLE GetMactorTalkReel(MACTOR *pAactor, TFTYPE dirn);
|
|
||||||
|
|
||||||
void setscalingreels(int actor, int scale, int direction,
|
|
||||||
SCNHANDLE left, SCNHANDLE right, SCNHANDLE forward, SCNHANDLE away);
|
|
||||||
SCNHANDLE ScalingReel(int ano, int scale1, int scale2, DIRREEL reel);
|
|
||||||
void RebootScalingReels(void);
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MAGICX = -101,
|
MAGICX = -101,
|
||||||
MAGICY = -102
|
MAGICY = -102
|
||||||
|
|
|
@ -25,8 +25,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tinsel/actors.h"
|
#include "tinsel/actors.h"
|
||||||
|
#include "tinsel/dialogs.h"
|
||||||
|
#include "tinsel/drives.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/inventory.h"
|
|
||||||
#include "tinsel/rince.h"
|
#include "tinsel/rince.h"
|
||||||
#include "tinsel/savescn.h"
|
#include "tinsel/savescn.h"
|
||||||
#include "tinsel/serializer.h"
|
#include "tinsel/serializer.h"
|
||||||
|
@ -63,7 +64,11 @@ namespace Tinsel {
|
||||||
#define VER(x) x
|
#define VER(x) x
|
||||||
|
|
||||||
|
|
||||||
|
//----------------- GLOBAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
|
int thingHeld = 0;
|
||||||
|
int restoreCD = 0;
|
||||||
|
SRSTATE SRstate = SR_IDLE;
|
||||||
|
|
||||||
//----------------- EXTERN FUNCTIONS --------------------
|
//----------------- EXTERN FUNCTIONS --------------------
|
||||||
|
|
||||||
|
@ -79,9 +84,6 @@ extern void syncGlobInfo(Serializer &s);
|
||||||
// in POLYGONS.C
|
// in POLYGONS.C
|
||||||
extern void syncPolyInfo(Serializer &s);
|
extern void syncPolyInfo(Serializer &s);
|
||||||
|
|
||||||
// in SAVESCN.CPP
|
|
||||||
extern void RestoreScene(SAVED_DATA *sd, bool bFadeOut);
|
|
||||||
|
|
||||||
//----------------- LOCAL DEFINES --------------------
|
//----------------- LOCAL DEFINES --------------------
|
||||||
|
|
||||||
struct SaveGameHeader {
|
struct SaveGameHeader {
|
||||||
|
@ -93,15 +95,17 @@ struct SaveGameHeader {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SAVEGAME_ID = 0x44575399, // = 'DWSc' = "DiscWorld ScummVM"
|
DW1_SAVEGAME_ID = 0x44575399, // = 'DWSc' = "DiscWorld 1 ScummVM"
|
||||||
|
DW2_SAVEGAME_ID = 0x44573253, // = 'DW2S' = "DiscWOrld 2 ScummVM"
|
||||||
SAVEGAME_HEADER_SIZE = 4 + 4 + 4 + SG_DESC_LEN + 7
|
SAVEGAME_HEADER_SIZE = 4 + 4 + 4 + SG_DESC_LEN + 7
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SAVEGAME_ID (TinselV2 ? (uint32)DW2_SAVEGAME_ID : (uint32)DW1_SAVEGAME_ID)
|
||||||
|
|
||||||
//----------------- LOCAL GLOBAL DATA --------------------
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
static int numSfiles = 0;
|
static int numSfiles = 0;
|
||||||
static SFILES savedFiles[MAX_SFILES];
|
static SFILES savedFiles[MAX_SAVED_FILES];
|
||||||
|
|
||||||
static bool NeedLoad = true;
|
static bool NeedLoad = true;
|
||||||
|
|
||||||
|
@ -112,8 +116,6 @@ static const char *SaveSceneDesc = 0;
|
||||||
static int *SaveSceneSsCount = 0;
|
static int *SaveSceneSsCount = 0;
|
||||||
static char *SaveSceneSsData = 0; // points to 'SAVED_DATA ssdata[MAX_NEST]'
|
static char *SaveSceneSsData = 0; // points to 'SAVED_DATA ssdata[MAX_NEST]'
|
||||||
|
|
||||||
static SRSTATE SRstate = SR_IDLE;
|
|
||||||
|
|
||||||
//------------- SAVE/LOAD SUPPORT METHODS ----------------
|
//------------- SAVE/LOAD SUPPORT METHODS ----------------
|
||||||
|
|
||||||
static void syncTime(Serializer &s, struct tm &t) {
|
static void syncTime(Serializer &s, struct tm &t) {
|
||||||
|
@ -153,29 +155,38 @@ static bool syncSaveGameHeader(Serializer &s, SaveGameHeader &hdr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syncSavedMover(Serializer &s, SAVED_MOVER &sm) {
|
static void syncSavedMover(Serializer &s, SAVED_MOVER &sm) {
|
||||||
SCNHANDLE *pList[3] = { (SCNHANDLE *)&sm.WalkReels, (SCNHANDLE *)&sm.StandReels, (SCNHANDLE *)&sm.TalkReels };
|
SCNHANDLE *pList[3] = { (SCNHANDLE *)&sm.walkReels,
|
||||||
|
(SCNHANDLE *)&sm.standReels, (SCNHANDLE *)&sm.talkReels };
|
||||||
|
|
||||||
s.syncAsUint32LE(sm.MActorState);
|
s.syncAsUint32LE(sm.bActive);
|
||||||
s.syncAsSint32LE(sm.actorID);
|
s.syncAsSint32LE(sm.actorID);
|
||||||
s.syncAsSint32LE(sm.objx);
|
s.syncAsSint32LE(sm.objX);
|
||||||
s.syncAsSint32LE(sm.objy);
|
s.syncAsSint32LE(sm.objY);
|
||||||
s.syncAsUint32LE(sm.lastfilm);
|
s.syncAsUint32LE(sm.hLastfilm);
|
||||||
|
|
||||||
for (int pIndex = 0; pIndex < 3; ++pIndex) {
|
for (int pIndex = 0; pIndex < 3; ++pIndex) {
|
||||||
SCNHANDLE *p = pList[pIndex];
|
SCNHANDLE *p = pList[pIndex];
|
||||||
for (int i = 0; i < TOTAL_SCALES * 4; ++i)
|
for (int i = 0; i < TOTAL_SCALES * 4; ++i)
|
||||||
s.syncAsUint32LE(*p++);
|
s.syncAsUint32LE(*p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
s.syncAsByte(sm.bHidden);
|
||||||
|
|
||||||
|
s.syncAsSint32LE(sm.brightness);
|
||||||
|
s.syncAsSint32LE(sm.startColour);
|
||||||
|
s.syncAsSint32LE(sm.paletteLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syncSavedActor(Serializer &s, SAVED_ACTOR &sa) {
|
static void syncSavedActor(Serializer &s, SAVED_ACTOR &sa) {
|
||||||
s.syncAsUint16LE(sa.actorID);
|
s.syncAsUint16LE(sa.actorID);
|
||||||
s.syncAsUint16LE(sa.z);
|
s.syncAsUint16LE(sa.zFactor);
|
||||||
s.syncAsUint32LE(sa.bAlive);
|
s.syncAsUint32LE(sa.bAlive);
|
||||||
s.syncAsUint32LE(sa.presFilm);
|
s.syncAsUint32LE(sa.presFilm);
|
||||||
s.syncAsUint16LE(sa.presRnum);
|
s.syncAsUint16LE(sa.presRnum);
|
||||||
s.syncAsUint16LE(sa.presX);
|
s.syncAsUint16LE(sa.presPlayX);
|
||||||
s.syncAsUint16LE(sa.presY);
|
s.syncAsUint16LE(sa.presPlayY);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void syncAllActorsAlive(Serializer &s);
|
extern void syncAllActorsAlive(Serializer &s);
|
||||||
|
@ -186,6 +197,24 @@ static void syncNoScrollB(Serializer &s, NOSCROLLB &ns) {
|
||||||
s.syncAsSint32LE(ns.c2);
|
s.syncAsSint32LE(ns.c2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void syncZPosition(Serializer &s, Z_POSITIONS &zp) {
|
||||||
|
s.syncAsSint16LE(zp.actor);
|
||||||
|
s.syncAsSint16LE(zp.column);
|
||||||
|
s.syncAsSint32LE(zp.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syncPolyVolatile(Serializer &s, POLY_VOLATILE &p) {
|
||||||
|
s.syncAsByte(p.bDead);
|
||||||
|
s.syncAsSint16LE(p.xoff);
|
||||||
|
s.syncAsSint16LE(p.yoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syncSoundReel(Serializer &s, SOUNDREELS &sr) {
|
||||||
|
s.syncAsUint32LE(sr.hFilm);
|
||||||
|
s.syncAsSint32LE(sr.column);
|
||||||
|
s.syncAsSint32LE(sr.actorCol);
|
||||||
|
}
|
||||||
|
|
||||||
static void syncSavedData(Serializer &s, SAVED_DATA &sd) {
|
static void syncSavedData(Serializer &s, SAVED_DATA &sd) {
|
||||||
s.syncAsUint32LE(sd.SavedSceneHandle);
|
s.syncAsUint32LE(sd.SavedSceneHandle);
|
||||||
s.syncAsUint32LE(sd.SavedBgroundHandle);
|
s.syncAsUint32LE(sd.SavedBgroundHandle);
|
||||||
|
@ -197,7 +226,7 @@ static void syncSavedData(Serializer &s, SAVED_DATA &sd) {
|
||||||
s.syncAsSint32LE(sd.NumSavedActors);
|
s.syncAsSint32LE(sd.NumSavedActors);
|
||||||
s.syncAsSint32LE(sd.SavedLoffset);
|
s.syncAsSint32LE(sd.SavedLoffset);
|
||||||
s.syncAsSint32LE(sd.SavedToffset);
|
s.syncAsSint32LE(sd.SavedToffset);
|
||||||
for (int i = 0; i < MAX_INTERPRET; ++i)
|
for (int i = 0; i < NUM_INTERPRET; ++i)
|
||||||
sd.SavedICInfo[i].syncWithSerializer(s);
|
sd.SavedICInfo[i].syncWithSerializer(s);
|
||||||
for (int i = 0; i < MAX_POLY; ++i)
|
for (int i = 0; i < MAX_POLY; ++i)
|
||||||
s.syncAsUint32LE(sd.SavedDeadPolys[i]);
|
s.syncAsUint32LE(sd.SavedDeadPolys[i]);
|
||||||
|
@ -213,6 +242,32 @@ static void syncSavedData(Serializer &s, SAVED_DATA &sd) {
|
||||||
syncNoScrollB(s, sd.SavedNoScrollData.NoHScroll[i]);
|
syncNoScrollB(s, sd.SavedNoScrollData.NoHScroll[i]);
|
||||||
s.syncAsUint32LE(sd.SavedNoScrollData.NumNoV);
|
s.syncAsUint32LE(sd.SavedNoScrollData.NumNoV);
|
||||||
s.syncAsUint32LE(sd.SavedNoScrollData.NumNoH);
|
s.syncAsUint32LE(sd.SavedNoScrollData.NumNoH);
|
||||||
|
|
||||||
|
// Tinsel 2 fields
|
||||||
|
if (TinselV2) {
|
||||||
|
// SavedNoScrollData
|
||||||
|
s.syncAsUint32LE(sd.SavedNoScrollData.xTrigger);
|
||||||
|
s.syncAsUint32LE(sd.SavedNoScrollData.xDistance);
|
||||||
|
s.syncAsUint32LE(sd.SavedNoScrollData.xSpeed);
|
||||||
|
s.syncAsUint32LE(sd.SavedNoScrollData.yTriggerTop);
|
||||||
|
s.syncAsUint32LE(sd.SavedNoScrollData.yTriggerBottom);
|
||||||
|
s.syncAsUint32LE(sd.SavedNoScrollData.yDistance);
|
||||||
|
s.syncAsUint32LE(sd.SavedNoScrollData.ySpeed);
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_ZPOSITIONS; ++i)
|
||||||
|
syncZPosition(s, sd.zPositions[i]);
|
||||||
|
s.syncBytes(sd.savedActorZ, MAX_SAVED_ACTOR_Z);
|
||||||
|
for (int i = 0; i < MAX_POLY; ++i)
|
||||||
|
syncPolyVolatile(s, sd.SavedPolygonStuff[i]);
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
s.syncAsUint32LE(sd.SavedTune[i]);
|
||||||
|
s.syncAsByte(sd.bTinselDim);
|
||||||
|
s.syncAsSint32LE(sd.SavedScrollFocus);
|
||||||
|
for (int i = 0; i < SV_TOPVALID; ++i)
|
||||||
|
s.syncAsSint32LE(sd.SavedSystemVars[i]);
|
||||||
|
for (int i = 0; i < MAX_SOUNDREELS; ++i)
|
||||||
|
syncSoundReel(s, sd.SavedSoundReels[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -247,6 +302,11 @@ static char *NewName(void) {
|
||||||
* the number of files found).
|
* the number of files found).
|
||||||
*/
|
*/
|
||||||
int getList(Common::SaveFileManager *saveFileMan, const Common::String &target) {
|
int getList(Common::SaveFileManager *saveFileMan, const Common::String &target) {
|
||||||
|
// No change since last call?
|
||||||
|
// TODO/FIXME: Just always reload this data? Be careful about slow downs!!!
|
||||||
|
if (!NeedLoad)
|
||||||
|
return numSfiles;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
const Common::String pattern = target + ".???";
|
const Common::String pattern = target + ".???";
|
||||||
|
@ -255,7 +315,7 @@ int getList(Common::SaveFileManager *saveFileMan, const Common::String &target)
|
||||||
numSfiles = 0;
|
numSfiles = 0;
|
||||||
|
|
||||||
for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) {
|
for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) {
|
||||||
if (numSfiles >= MAX_SFILES)
|
if (numSfiles >= MAX_SAVED_FILES)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const Common::String &fname = *file;
|
const Common::String &fname = *file;
|
||||||
|
@ -308,7 +368,6 @@ int getList(void) {
|
||||||
return getList(_vm->getSaveFileMan(), _vm->getTargetName());
|
return getList(_vm->getSaveFileMan(), _vm->getTargetName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char *ListEntry(int i, letype which) {
|
char *ListEntry(int i, letype which) {
|
||||||
if (i == -1)
|
if (i == -1)
|
||||||
i = numSfiles;
|
i = numSfiles;
|
||||||
|
@ -322,7 +381,16 @@ char *ListEntry(int i, letype which) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DoSync(Serializer &s) {
|
static void DoSync(Serializer &s) {
|
||||||
int sg = 0;
|
int sg;
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
if (s.isSaving())
|
||||||
|
restoreCD = GetCurrentCD();
|
||||||
|
s.syncAsSint16LE(restoreCD);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TinselV2 && s.isLoading())
|
||||||
|
HoldItem(INV_NOICON);
|
||||||
|
|
||||||
syncSavedData(s, *srsd);
|
syncSavedData(s, *srsd);
|
||||||
syncGlobInfo(s); // Glitter globals
|
syncGlobInfo(s); // Glitter globals
|
||||||
|
@ -332,10 +400,15 @@ static void DoSync(Serializer &s) {
|
||||||
if (s.isSaving())
|
if (s.isSaving())
|
||||||
sg = WhichItemHeld();
|
sg = WhichItemHeld();
|
||||||
s.syncAsSint32LE(sg);
|
s.syncAsSint32LE(sg);
|
||||||
if (s.isLoading())
|
if (s.isLoading()) {
|
||||||
|
if (TinselV2)
|
||||||
|
thingHeld = sg;
|
||||||
|
else
|
||||||
HoldItem(sg);
|
HoldItem(sg);
|
||||||
|
}
|
||||||
|
|
||||||
syncTimerInfo(s); // Timer data
|
syncTimerInfo(s); // Timer data
|
||||||
|
if (!TinselV2)
|
||||||
syncPolyInfo(s); // Dead polygon data
|
syncPolyInfo(s); // Dead polygon data
|
||||||
syncSCdata(s); // Hook Scene and delayed scene
|
syncSCdata(s); // Hook Scene and delayed scene
|
||||||
|
|
||||||
|
@ -347,6 +420,7 @@ static void DoSync(Serializer &s) {
|
||||||
syncSavedData(s, *sdPtr);
|
syncSavedData(s, *sdPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!TinselV2)
|
||||||
syncAllActorsAlive(s);
|
syncAllActorsAlive(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,7 +514,7 @@ void ProcessSRQueue(void) {
|
||||||
switch (SRstate) {
|
switch (SRstate) {
|
||||||
case SR_DORESTORE:
|
case SR_DORESTORE:
|
||||||
if (DoRestore()) {
|
if (DoRestore()) {
|
||||||
RestoreScene(srsd, false);
|
DoRestoreScene(srsd, false);
|
||||||
}
|
}
|
||||||
SRstate = SR_IDLE;
|
SRstate = SR_IDLE;
|
||||||
break;
|
break;
|
||||||
|
@ -467,6 +541,15 @@ void RequestSaveGame(char *name, char *desc, SAVED_DATA *sd, int *pSsCount, SAVE
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestRestoreGame(int num, SAVED_DATA *sd, int *pSsCount, SAVED_DATA *pSsData) {
|
void RequestRestoreGame(int num, SAVED_DATA *sd, int *pSsCount, SAVED_DATA *pSsData) {
|
||||||
|
if (TinselV2) {
|
||||||
|
if (num == -1)
|
||||||
|
return;
|
||||||
|
else if (num == -2) {
|
||||||
|
// From CD change for restore
|
||||||
|
num = RestoreGameNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(num >= 0);
|
assert(num >= 0);
|
||||||
|
|
||||||
RestoreGameNumber = num;
|
RestoreGameNumber = num;
|
||||||
|
@ -476,4 +559,14 @@ void RequestRestoreGame(int num, SAVED_DATA *sd, int *pSsCount, SAVED_DATA *pSsD
|
||||||
SRstate = SR_DORESTORE;
|
SRstate = SR_DORESTORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the most recently saved savegame. This will always be
|
||||||
|
* the file at the first index, since the list is sorted by date/time
|
||||||
|
*/
|
||||||
|
int NewestSavedGame(void) {
|
||||||
|
int numFiles = getList();
|
||||||
|
|
||||||
|
return (numFiles == 0) ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -28,19 +28,24 @@
|
||||||
#include "tinsel/actors.h"
|
#include "tinsel/actors.h"
|
||||||
#include "tinsel/background.h"
|
#include "tinsel/background.h"
|
||||||
#include "tinsel/config.h"
|
#include "tinsel/config.h"
|
||||||
|
#include "tinsel/drives.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/faders.h" // FadeOutFast()
|
#include "tinsel/faders.h" // FadeOutFast()
|
||||||
#include "tinsel/graphics.h" // ClearScreen()
|
#include "tinsel/graphics.h" // ClearScreen()
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
#include "tinsel/inventory.h"
|
#include "tinsel/heapmem.h"
|
||||||
|
#include "tinsel/dialogs.h"
|
||||||
#include "tinsel/music.h"
|
#include "tinsel/music.h"
|
||||||
#include "tinsel/pid.h"
|
#include "tinsel/pid.h"
|
||||||
|
#include "tinsel/play.h"
|
||||||
#include "tinsel/polygons.h"
|
#include "tinsel/polygons.h"
|
||||||
#include "tinsel/rince.h"
|
#include "tinsel/rince.h"
|
||||||
#include "tinsel/savescn.h"
|
#include "tinsel/savescn.h"
|
||||||
|
#include "tinsel/scene.h"
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
#include "tinsel/scroll.h"
|
#include "tinsel/scroll.h"
|
||||||
#include "tinsel/sound.h"
|
#include "tinsel/sound.h"
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
#include "tinsel/tinlib.h"
|
#include "tinsel/tinlib.h"
|
||||||
#include "tinsel/token.h"
|
#include "tinsel/token.h"
|
||||||
|
|
||||||
|
@ -49,7 +54,6 @@ namespace Tinsel {
|
||||||
//----------------- EXTERN FUNCTIONS --------------------
|
//----------------- EXTERN FUNCTIONS --------------------
|
||||||
|
|
||||||
// in BG.C
|
// in BG.C
|
||||||
extern void startupBackground(SCNHANDLE bfilm);
|
|
||||||
extern SCNHANDLE GetBgroundHandle(void);
|
extern SCNHANDLE GetBgroundHandle(void);
|
||||||
extern void SetDoFadeIn(bool tf);
|
extern void SetDoFadeIn(bool tf);
|
||||||
|
|
||||||
|
@ -59,14 +63,8 @@ void RestoreMasterProcess(INT_CONTEXT *pic);
|
||||||
// in EVENTS.C (declared here and not in events.h because of strange goings-on)
|
// in EVENTS.C (declared here and not in events.h because of strange goings-on)
|
||||||
void RestoreProcess(INT_CONTEXT *pic);
|
void RestoreProcess(INT_CONTEXT *pic);
|
||||||
|
|
||||||
// in PLAY.C
|
|
||||||
extern void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y);
|
|
||||||
|
|
||||||
// in SCENE.C
|
// in SCENE.C
|
||||||
extern SCNHANDLE GetSceneHandle(void);
|
extern SCNHANDLE GetSceneHandle(void);
|
||||||
extern void NewScene(SCNHANDLE scene, int entry);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//----------------- LOCAL DEFINES --------------------
|
//----------------- LOCAL DEFINES --------------------
|
||||||
|
@ -77,6 +75,11 @@ enum {
|
||||||
MAX_NEST = 4
|
MAX_NEST = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//----------------- EXTERNAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
|
extern int thingHeld;
|
||||||
|
extern int restoreCD;
|
||||||
|
extern SRSTATE SRstate;
|
||||||
|
|
||||||
//----------------- LOCAL GLOBAL DATA --------------------
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
|
@ -84,54 +87,52 @@ static bool ASceneIsSaved = false;
|
||||||
|
|
||||||
static int savedSceneCount = 0;
|
static int savedSceneCount = 0;
|
||||||
|
|
||||||
//static SAVED_DATA s_ssData[MAX_NEST];
|
static bool bNotDoneYet = false;
|
||||||
static SAVED_DATA *s_ssData = 0;
|
|
||||||
|
//static SAVED_DATA ssData[MAX_NEST];
|
||||||
|
static SAVED_DATA *ssData = NULL;
|
||||||
static SAVED_DATA sgData;
|
static SAVED_DATA sgData;
|
||||||
|
|
||||||
static SAVED_DATA *s_rsd = 0;
|
static SAVED_DATA *rsd = 0;
|
||||||
|
|
||||||
static int s_restoreSceneCount = 0;
|
static int RestoreSceneCount = 0;
|
||||||
|
|
||||||
static bool bNoFade = false;
|
static bool bNoFade = false;
|
||||||
|
|
||||||
//----------------- FORWARD REFERENCES --------------------
|
//----------------- FORWARD REFERENCES --------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void InitialiseSs(void) {
|
|
||||||
if (s_ssData == NULL) {
|
|
||||||
s_ssData = (SAVED_DATA *)calloc(MAX_NEST, sizeof(SAVED_DATA));
|
|
||||||
if (s_ssData == NULL) {
|
|
||||||
error("Cannot allocate memory for scene changes");
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
savedSceneCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreeSs(void) {
|
|
||||||
if (s_ssData) {
|
|
||||||
free(s_ssData);
|
|
||||||
s_ssData = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save current scene.
|
* Save current scene.
|
||||||
* @param sd Pointer to the scene data
|
* @param sd Pointer to the scene data
|
||||||
*/
|
*/
|
||||||
void SaveScene(SAVED_DATA *sd) {
|
void DoSaveScene(SAVED_DATA *sd) {
|
||||||
sd->SavedSceneHandle = GetSceneHandle();
|
sd->SavedSceneHandle = GetSceneHandle();
|
||||||
sd->SavedBgroundHandle = GetBgroundHandle();
|
sd->SavedBgroundHandle = GetBgroundHandle();
|
||||||
SaveMovers(sd->SavedMoverInfo);
|
SaveMovers(sd->SavedMoverInfo);
|
||||||
sd->NumSavedActors = SaveActors(sd->SavedActorInfo);
|
sd->NumSavedActors = SaveActors(sd->SavedActorInfo);
|
||||||
PlayfieldGetPos(FIELD_WORLD, &sd->SavedLoffset, &sd->SavedToffset);
|
PlayfieldGetPos(FIELD_WORLD, &sd->SavedLoffset, &sd->SavedToffset);
|
||||||
SaveInterpretContexts(sd->SavedICInfo);
|
SaveInterpretContexts(sd->SavedICInfo);
|
||||||
SaveDeadPolys(sd->SavedDeadPolys);
|
sd->SavedControl = ControlIsOn();
|
||||||
sd->SavedControl = TestToken(TOKEN_CONTROL);
|
sd->SavedNoBlocking = GetNoBlocking();
|
||||||
CurrentMidiFacts(&sd->SavedMidi, &sd->SavedLoop);
|
|
||||||
sd->SavedNoBlocking = bNoBlocking;
|
|
||||||
GetNoScrollData(&sd->SavedNoScrollData);
|
GetNoScrollData(&sd->SavedNoScrollData);
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// Tinsel 2 specific data save
|
||||||
|
SaveActorZ(sd->savedActorZ);
|
||||||
|
SaveZpositions(sd->zPositions);
|
||||||
|
SavePolygonStuff(sd->SavedPolygonStuff);
|
||||||
|
_vm->_pcmMusic->getTunePlaying(sd->SavedTune, sizeof(sd->SavedTune));
|
||||||
|
sd->bTinselDim = _vm->_pcmMusic->getMusicTinselDimmed();
|
||||||
|
sd->SavedScrollFocus = GetScrollFocus();
|
||||||
|
SaveSysVars(sd->SavedSystemVars);
|
||||||
|
SaveSoundReels(sd->SavedSoundReels);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Tinsel 1 specific data save
|
||||||
|
SaveDeadPolys(sd->SavedDeadPolys);
|
||||||
|
CurrentMidiFacts(&sd->SavedMidi, &sd->SavedLoop);
|
||||||
|
}
|
||||||
|
|
||||||
ASceneIsSaved = true;
|
ASceneIsSaved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,13 +141,32 @@ void SaveScene(SAVED_DATA *sd) {
|
||||||
* @param sd Pointer to the scene data
|
* @param sd Pointer to the scene data
|
||||||
* @param bFadeOut Flag to perform a fade out
|
* @param bFadeOut Flag to perform a fade out
|
||||||
*/
|
*/
|
||||||
void RestoreScene(SAVED_DATA *sd, bool bFadeOut) {
|
void DoRestoreScene(SAVED_DATA *sd, bool bFadeOut) {
|
||||||
s_rsd = sd;
|
rsd = sd;
|
||||||
|
|
||||||
if (bFadeOut)
|
if (bFadeOut)
|
||||||
s_restoreSceneCount = RS_COUNT + COUNTOUT_COUNT; // Set restore scene count
|
RestoreSceneCount = RS_COUNT + COUNTOUT_COUNT; // Set restore scene count
|
||||||
else
|
else
|
||||||
s_restoreSceneCount = RS_COUNT; // Set restore scene count
|
RestoreSceneCount = RS_COUNT; // Set restore scene count
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitialiseSaveScenes(void) {
|
||||||
|
if (ssData == NULL) {
|
||||||
|
ssData = (SAVED_DATA *)calloc(MAX_NEST, sizeof(SAVED_DATA));
|
||||||
|
if (ssData == NULL) {
|
||||||
|
error("Cannot allocate memory for scene changes");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Re-initialise - no scenes saved
|
||||||
|
savedSceneCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeSaveScenes(void) {
|
||||||
|
if (ssData) {
|
||||||
|
free(ssData);
|
||||||
|
ssData = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,39 +174,84 @@ void RestoreScene(SAVED_DATA *sd, bool bFadeOut) {
|
||||||
* the scene was saved.
|
* the scene was saved.
|
||||||
* Also 'stand' all the moving actors at their saved positions.
|
* Also 'stand' all the moving actors at their saved positions.
|
||||||
*/
|
*/
|
||||||
void sortActors(SAVED_DATA *rsd) {
|
void sortActors(SAVED_DATA *sd) {
|
||||||
for (int i = 0; i < rsd->NumSavedActors; i++) {
|
assert(!TinselV2);
|
||||||
ActorsLife(rsd->SavedActorInfo[i].actorID, rsd->SavedActorInfo[i].bAlive);
|
for (int i = 0; i < sd->NumSavedActors; i++) {
|
||||||
|
ActorsLife(sd->SavedActorInfo[i].actorID, sd->SavedActorInfo[i].bAlive);
|
||||||
|
|
||||||
// Should be playing the same reel.
|
// Should be playing the same reel.
|
||||||
if (rsd->SavedActorInfo[i].presFilm != 0) {
|
if (sd->SavedActorInfo[i].presFilm != 0) {
|
||||||
if (!actorAlive(rsd->SavedActorInfo[i].actorID))
|
if (!actorAlive(sd->SavedActorInfo[i].actorID))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
playThisReel(rsd->SavedActorInfo[i].presFilm, rsd->SavedActorInfo[i].presRnum, rsd->SavedActorInfo[i].z,
|
RestoreActorReels(sd->SavedActorInfo[i].presFilm, sd->SavedActorInfo[i].presRnum, sd->SavedActorInfo[i].zFactor,
|
||||||
rsd->SavedActorInfo[i].presX, rsd->SavedActorInfo[i].presY);
|
sd->SavedActorInfo[i].presPlayX, sd->SavedActorInfo[i].presPlayY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RestoreAuxScales(rsd->SavedMoverInfo);
|
RestoreAuxScales(sd->SavedMoverInfo);
|
||||||
for (int i = 0; i < MAX_MOVERS; i++) {
|
for (int i = 0; i < MAX_MOVERS; i++) {
|
||||||
if (rsd->SavedMoverInfo[i].MActorState == NORM_MACTOR)
|
if (sd->SavedMoverInfo[i].bActive)
|
||||||
stand(rsd->SavedMoverInfo[i].actorID, rsd->SavedMoverInfo[i].objx,
|
Stand(nullContext, sd->SavedMoverInfo[i].actorID, sd->SavedMoverInfo[i].objX,
|
||||||
rsd->SavedMoverInfo[i].objy, rsd->SavedMoverInfo[i].lastfilm);
|
sd->SavedMoverInfo[i].objY, sd->SavedMoverInfo[i].hLastfilm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stand all the moving actors at their saved positions.
|
||||||
|
* Not called from the foreground.
|
||||||
|
*/
|
||||||
|
static void SortMAProcess(CORO_PARAM, const void *) {
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
int i;
|
||||||
|
int viaActor;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
// Disable via actor for the stands
|
||||||
|
_ctx->viaActor = SysVar(ISV_DIVERT_ACTOR);
|
||||||
|
SetSysVar(ISV_DIVERT_ACTOR, 0);
|
||||||
|
|
||||||
|
RestoreAuxScales(rsd->SavedMoverInfo);
|
||||||
|
|
||||||
|
for (_ctx->i = 0; _ctx->i < MAX_MOVERS; _ctx->i++) {
|
||||||
|
if (rsd->SavedMoverInfo[_ctx->i].bActive) {
|
||||||
|
CORO_INVOKE_ARGS(Stand, (CORO_SUBCTX, rsd->SavedMoverInfo[_ctx->i].actorID,
|
||||||
|
rsd->SavedMoverInfo[_ctx->i].objX, rsd->SavedMoverInfo[_ctx->i].objY,
|
||||||
|
rsd->SavedMoverInfo[_ctx->i].hLastfilm));
|
||||||
|
|
||||||
|
if (rsd->SavedMoverInfo[_ctx->i].bHidden)
|
||||||
|
HideMover(GetMover(rsd->SavedMoverInfo[_ctx->i].actorID));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActorPalette(rsd->SavedMoverInfo[_ctx->i].actorID,
|
||||||
|
rsd->SavedMoverInfo[_ctx->i].startColour, rsd->SavedMoverInfo[_ctx->i].paletteLength);
|
||||||
|
|
||||||
|
if (rsd->SavedMoverInfo[_ctx->i].brightness != BOGUS_BRIGHTNESS)
|
||||||
|
ActorBrightness(rsd->SavedMoverInfo[_ctx->i].actorID, rsd->SavedMoverInfo[_ctx->i].brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore via actor
|
||||||
|
SetSysVar(ISV_DIVERT_ACTOR, _ctx->viaActor);
|
||||||
|
|
||||||
|
bNotDoneYet = false;
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
void ResumeInterprets(SAVED_DATA *rsd) {
|
void ResumeInterprets(void) {
|
||||||
// Master script only affected on restore game, not restore scene
|
// Master script only affected on restore game, not restore scene
|
||||||
if (rsd == &sgData) {
|
if (!TinselV2 && (rsd == &sgData)) {
|
||||||
g_scheduler->killMatchingProcess(PID_MASTER_SCR, -1);
|
g_scheduler->killMatchingProcess(PID_MASTER_SCR, -1);
|
||||||
FreeMasterInterpretContext();
|
FreeMasterInterpretContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAX_INTERPRET; i++) {
|
for (int i = 0; i < NUM_INTERPRET; i++) {
|
||||||
switch (rsd->SavedICInfo[i].GSort) {
|
switch (rsd->SavedICInfo[i].GSort) {
|
||||||
case GS_NONE:
|
case GS_NONE:
|
||||||
break;
|
break;
|
||||||
|
@ -203,14 +268,31 @@ void ResumeInterprets(SAVED_DATA *rsd) {
|
||||||
RestoreMasterProcess(&rsd->SavedICInfo[i]);
|
RestoreMasterProcess(&rsd->SavedICInfo[i]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GS_PROCESS:
|
||||||
|
// Tinsel 2 process
|
||||||
|
RestoreSceneProcess(&rsd->SavedICInfo[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_GPROCESS:
|
||||||
|
// Tinsel 2 Global processes only affected on restore game, not restore scene
|
||||||
|
if (rsd == &sgData)
|
||||||
|
RestoreGlobalProcess(&rsd->SavedICInfo[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
case GS_ACTOR:
|
case GS_ACTOR:
|
||||||
RestoreActorProcess(rsd->SavedICInfo[i].actorid, &rsd->SavedICInfo[i]);
|
if (TinselV2)
|
||||||
|
RestoreProcess(&rsd->SavedICInfo[i]);
|
||||||
|
else
|
||||||
|
RestoreActorProcess(rsd->SavedICInfo[i].idActor, &rsd->SavedICInfo[i]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GS_POLYGON:
|
case GS_POLYGON:
|
||||||
case GS_SCENE:
|
case GS_SCENE:
|
||||||
RestoreProcess(&rsd->SavedICInfo[i]);
|
RestoreProcess(&rsd->SavedICInfo[i]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
warning("Unhandled GSort in ResumeInterprets");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,7 +301,7 @@ void ResumeInterprets(SAVED_DATA *rsd) {
|
||||||
* Do restore scene
|
* Do restore scene
|
||||||
* @param n Id
|
* @param n Id
|
||||||
*/
|
*/
|
||||||
static int DoRestoreScene(SAVED_DATA *rsd, int n) {
|
static int DoRestoreSceneFrame(SAVED_DATA *sd, int n) {
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case RS_COUNT + COUNTOUT_COUNT:
|
case RS_COUNT + COUNTOUT_COUNT:
|
||||||
// Trigger pre-load and fade and start countdown
|
// Trigger pre-load and fade and start countdown
|
||||||
|
@ -229,31 +311,90 @@ static int DoRestoreScene(SAVED_DATA *rsd, int n) {
|
||||||
case RS_COUNT:
|
case RS_COUNT:
|
||||||
_vm->_sound->stopAllSamples();
|
_vm->_sound->stopAllSamples();
|
||||||
ClearScreen();
|
ClearScreen();
|
||||||
RestoreDeadPolys(rsd->SavedDeadPolys);
|
|
||||||
NewScene(rsd->SavedSceneHandle, NO_ENTRY_NUM);
|
// Master script only affected on restore game, not restore scene
|
||||||
|
if (TinselV2 && (sd == &sgData)) {
|
||||||
|
g_scheduler->killMatchingProcess(PID_MASTER_SCR);
|
||||||
|
KillGlobalProcesses();
|
||||||
|
FreeMasterInterpretContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
RestorePolygonStuff(sd->SavedPolygonStuff);
|
||||||
|
|
||||||
|
// Abandon temporarily if different CD
|
||||||
|
if (sd == &sgData && restoreCD != GetCurrentCD()) {
|
||||||
|
SRstate = SR_IDLE;
|
||||||
|
|
||||||
|
EndScene();
|
||||||
|
SetNextCD(restoreCD);
|
||||||
|
CDChangeForRestore(restoreCD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RestoreDeadPolys(sd->SavedDeadPolys);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start up the scene
|
||||||
|
StartNewScene(sd->SavedSceneHandle, NO_ENTRY_NUM);
|
||||||
|
|
||||||
SetDoFadeIn(!bNoFade);
|
SetDoFadeIn(!bNoFade);
|
||||||
bNoFade = false;
|
bNoFade = false;
|
||||||
startupBackground(rsd->SavedBgroundHandle);
|
StartupBackground(nullContext, sd->SavedBgroundHandle);
|
||||||
KillScroll();
|
|
||||||
PlayfieldSetPos(FIELD_WORLD, rsd->SavedLoffset, rsd->SavedToffset);
|
|
||||||
bNoBlocking = rsd->SavedNoBlocking;
|
|
||||||
RestoreNoScrollData(&rsd->SavedNoScrollData);
|
|
||||||
/*
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RS_COUNT - 1:
|
if (TinselV2) {
|
||||||
*/
|
Offset(EX_USEXY, sd->SavedLoffset, sd->SavedToffset);
|
||||||
sortActors(rsd);
|
} else {
|
||||||
|
KillScroll();
|
||||||
|
PlayfieldSetPos(FIELD_WORLD, sd->SavedLoffset, sd->SavedToffset);
|
||||||
|
SetNoBlocking(sd->SavedNoBlocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
RestoreNoScrollData(&sd->SavedNoScrollData);
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// create process to sort out the moving actors
|
||||||
|
g_scheduler->createProcess(PID_MOVER, SortMAProcess, NULL, 0);
|
||||||
|
bNotDoneYet = true;
|
||||||
|
|
||||||
|
RestoreActorZ(sd->savedActorZ);
|
||||||
|
RestoreZpositions(sd->zPositions);
|
||||||
|
RestoreSysVars(sd->SavedSystemVars);
|
||||||
|
CreateGhostPalette(BgPal());
|
||||||
|
RestoreActors(sd->NumSavedActors, sd->SavedActorInfo);
|
||||||
|
RestoreSoundReels(sd->SavedSoundReels);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sortActors(sd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
RestoreMidiFacts(rsd->SavedMidi, rsd->SavedLoop);
|
if (TinselV2) {
|
||||||
if (rsd->SavedControl)
|
if (bNotDoneYet)
|
||||||
control(CONTROL_ON); // TOKEN_CONTROL was free
|
return n;
|
||||||
ResumeInterprets(rsd);
|
|
||||||
|
if (sd == &sgData)
|
||||||
|
HoldItem(thingHeld, true);
|
||||||
|
if (sd->bTinselDim)
|
||||||
|
_vm->_pcmMusic->dim(true);
|
||||||
|
_vm->_pcmMusic->restoreThatTune(sd->SavedTune);
|
||||||
|
ScrollFocus(sd->SavedScrollFocus);
|
||||||
|
} else {
|
||||||
|
RestoreMidiFacts(sd->SavedMidi, sd->SavedLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sd->SavedControl)
|
||||||
|
ControlOn(); // Control was on
|
||||||
|
ResumeInterprets();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return n - 1;
|
return n - 1;
|
||||||
|
@ -266,7 +407,7 @@ static int DoRestoreScene(SAVED_DATA *rsd, int n) {
|
||||||
void RestoreGame(int num) {
|
void RestoreGame(int num) {
|
||||||
KillInventory();
|
KillInventory();
|
||||||
|
|
||||||
RequestRestoreGame(num, &sgData, &savedSceneCount, s_ssData);
|
RequestRestoreGame(num, &sgData, &savedSceneCount, ssData);
|
||||||
|
|
||||||
// Actual restoring is performed by ProcessSRQueue
|
// Actual restoring is performed by ProcessSRQueue
|
||||||
}
|
}
|
||||||
|
@ -278,9 +419,9 @@ void RestoreGame(int num) {
|
||||||
*/
|
*/
|
||||||
void SaveGame(char *name, char *desc) {
|
void SaveGame(char *name, char *desc) {
|
||||||
// Get current scene data
|
// Get current scene data
|
||||||
SaveScene(&sgData);
|
DoSaveScene(&sgData);
|
||||||
|
|
||||||
RequestSaveGame(name, desc, &sgData, &savedSceneCount, s_ssData);
|
RequestSaveGame(name, desc, &sgData, &savedSceneCount, ssData);
|
||||||
|
|
||||||
// Actual saving is performed by ProcessSRQueue
|
// Actual saving is performed by ProcessSRQueue
|
||||||
}
|
}
|
||||||
|
@ -289,23 +430,23 @@ void SaveGame(char *name, char *desc) {
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
|
|
||||||
bool IsRestoringScene() {
|
bool IsRestoringScene() {
|
||||||
if (s_restoreSceneCount) {
|
if (RestoreSceneCount) {
|
||||||
s_restoreSceneCount = DoRestoreScene(s_rsd, s_restoreSceneCount);
|
RestoreSceneCount = DoRestoreSceneFrame(rsd, RestoreSceneCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s_restoreSceneCount ? true : false;
|
return RestoreSceneCount ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Please Restore Scene
|
* Restores Scene
|
||||||
*/
|
*/
|
||||||
void PleaseRestoreScene(bool bFade) {
|
void TinselRestoreScene(bool bFade) {
|
||||||
// only called by restore_scene PCODE
|
// only called by restore_scene PCODE
|
||||||
if (s_restoreSceneCount == 0) {
|
if (RestoreSceneCount == 0) {
|
||||||
assert(savedSceneCount >= 1); // No saved scene to restore
|
assert(savedSceneCount >= 1); // No saved scene to restore
|
||||||
|
|
||||||
if (ASceneIsSaved)
|
if (ASceneIsSaved)
|
||||||
RestoreScene(&s_ssData[--savedSceneCount], bFade);
|
DoRestoreScene(&ssData[--savedSceneCount], bFade);
|
||||||
if (!bFade)
|
if (!bFade)
|
||||||
bNoFade = true;
|
bNoFade = true;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +455,7 @@ void PleaseRestoreScene(bool bFade) {
|
||||||
/**
|
/**
|
||||||
* Please Save Scene
|
* Please Save Scene
|
||||||
*/
|
*/
|
||||||
void PleaseSaveScene(CORO_PARAM) {
|
void TinselSaveScene(CORO_PARAM) {
|
||||||
// only called by save_scene PCODE
|
// only called by save_scene PCODE
|
||||||
CORO_BEGIN_CONTEXT;
|
CORO_BEGIN_CONTEXT;
|
||||||
CORO_END_CONTEXT(_ctx);
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
@ -325,10 +466,10 @@ void PleaseSaveScene(CORO_PARAM) {
|
||||||
|
|
||||||
// Don't save the same thing multiple times!
|
// Don't save the same thing multiple times!
|
||||||
// FIXME/TODO: Maybe this can be changed to an assert?
|
// FIXME/TODO: Maybe this can be changed to an assert?
|
||||||
if (savedSceneCount && s_ssData[savedSceneCount-1].SavedSceneHandle == GetSceneHandle())
|
if (savedSceneCount && ssData[savedSceneCount-1].SavedSceneHandle == GetSceneHandle())
|
||||||
CORO_KILL_SELF();
|
CORO_KILL_SELF();
|
||||||
|
|
||||||
SaveScene(&s_ssData[savedSceneCount++]);
|
DoSaveScene(&ssData[savedSceneCount++]);
|
||||||
|
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,16 @@
|
||||||
#include "tinsel/dw.h" // SCNHANDLE
|
#include "tinsel/dw.h" // SCNHANDLE
|
||||||
#include "tinsel/rince.h" // SAVED_MOVER
|
#include "tinsel/rince.h" // SAVED_MOVER
|
||||||
#include "tinsel/pcode.h" // INT_CONTEXT
|
#include "tinsel/pcode.h" // INT_CONTEXT
|
||||||
|
#include "tinsel/play.h"
|
||||||
|
#include "tinsel/polygons.h"
|
||||||
#include "tinsel/scroll.h" // SCROLLDATA
|
#include "tinsel/scroll.h" // SCROLLDATA
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SG_DESC_LEN = 40, // Max. saved game description length
|
SG_DESC_LEN = 40, // Max. saved game description length
|
||||||
MAX_SFILES = 30,
|
MAX_SAVED_FILES = 30,
|
||||||
|
|
||||||
// FIXME: Save file names in ScummVM can be longer than 8.3, overflowing the
|
// FIXME: Save file names in ScummVM can be longer than 8.3, overflowing the
|
||||||
// name field in savedFiles. Raising it to 256 as a preliminary fix.
|
// name field in savedFiles. Raising it to 256 as a preliminary fix.
|
||||||
|
@ -66,6 +69,16 @@ struct SAVED_DATA {
|
||||||
bool SavedLoop; // } Midi
|
bool SavedLoop; // } Midi
|
||||||
bool SavedNoBlocking;
|
bool SavedNoBlocking;
|
||||||
SCROLLDATA SavedNoScrollData;
|
SCROLLDATA SavedNoScrollData;
|
||||||
|
|
||||||
|
// Tinsel 2 fields
|
||||||
|
Z_POSITIONS zPositions[NUM_ZPOSITIONS];
|
||||||
|
byte savedActorZ[MAX_SAVED_ACTOR_Z];
|
||||||
|
POLY_VOLATILE SavedPolygonStuff[MAX_POLY];
|
||||||
|
uint32 SavedTune[3]; // Music
|
||||||
|
bool bTinselDim;
|
||||||
|
int SavedScrollFocus;
|
||||||
|
int SavedSystemVars[SV_TOPVALID];
|
||||||
|
SOUNDREELS SavedSoundReels[MAX_SOUNDREELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,8 +87,10 @@ enum SRSTATE {
|
||||||
SR_DOSAVE, SR_DONESAVE, SR_ABORTED
|
SR_DOSAVE, SR_DONESAVE, SR_ABORTED
|
||||||
};
|
};
|
||||||
|
|
||||||
void PleaseRestoreScene(bool bFade);
|
void TinselRestoreScene(bool bFade);
|
||||||
void PleaseSaveScene(CORO_PARAM);
|
void TinselSaveScene(CORO_PARAM);
|
||||||
|
void DoRestoreScene(SAVED_DATA *sd, bool bFadeOut);
|
||||||
|
void DoSaveScene(SAVED_DATA *sd);
|
||||||
|
|
||||||
bool IsRestoringScene();
|
bool IsRestoringScene();
|
||||||
|
|
||||||
|
@ -95,8 +110,8 @@ void ProcessSRQueue(void);
|
||||||
void RequestSaveGame(char *name, char *desc, SAVED_DATA *sd, int *ssCount, SAVED_DATA *ssData);
|
void RequestSaveGame(char *name, char *desc, SAVED_DATA *sd, int *ssCount, SAVED_DATA *ssData);
|
||||||
void RequestRestoreGame(int num, SAVED_DATA *sd, int *ssCount, SAVED_DATA *ssData);
|
void RequestRestoreGame(int num, SAVED_DATA *sd, int *ssCount, SAVED_DATA *ssData);
|
||||||
|
|
||||||
void InitialiseSs(void);
|
void InitialiseSaveScenes(void);
|
||||||
void FreeSs(void);
|
void FreeSaveScenes(void);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
|
|
@ -29,21 +29,26 @@
|
||||||
#include "tinsel/background.h"
|
#include "tinsel/background.h"
|
||||||
#include "tinsel/config.h"
|
#include "tinsel/config.h"
|
||||||
#include "tinsel/cursor.h"
|
#include "tinsel/cursor.h"
|
||||||
|
#include "tinsel/dialogs.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/graphics.h"
|
#include "tinsel/graphics.h"
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
#include "tinsel/inventory.h"
|
|
||||||
#include "tinsel/film.h"
|
#include "tinsel/film.h"
|
||||||
|
#include "tinsel/font.h"
|
||||||
|
#include "tinsel/mareels.h"
|
||||||
#include "tinsel/move.h"
|
#include "tinsel/move.h"
|
||||||
|
#include "tinsel/music.h"
|
||||||
|
#include "tinsel/object.h"
|
||||||
|
#include "tinsel/pcode.h"
|
||||||
|
#include "tinsel/pid.h" // process IDs
|
||||||
|
#include "tinsel/play.h"
|
||||||
|
#include "tinsel/polygons.h"
|
||||||
#include "tinsel/rince.h"
|
#include "tinsel/rince.h"
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
#include "tinsel/scn.h"
|
#include "tinsel/scn.h"
|
||||||
#include "tinsel/scroll.h"
|
#include "tinsel/scroll.h"
|
||||||
#include "tinsel/sound.h" // stopAllSamples()
|
#include "tinsel/sound.h" // stopAllSamples()
|
||||||
#include "tinsel/object.h"
|
#include "tinsel/sysvar.h"
|
||||||
#include "tinsel/pcode.h"
|
|
||||||
#include "tinsel/pid.h" // process IDs
|
|
||||||
#include "tinsel/polygons.h"
|
|
||||||
#include "tinsel/token.h"
|
#include "tinsel/token.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,20 +77,28 @@ extern void EnableTags(void);
|
||||||
|
|
||||||
/** scene structure - one per scene */
|
/** scene structure - one per scene */
|
||||||
struct SCENE_STRUC {
|
struct SCENE_STRUC {
|
||||||
int32 numEntrance; //!< number of entrances in this scene
|
int32 defRefer; // Default refer direction (REFTYPE)
|
||||||
int32 numPoly; //!< number of various polygons in this scene
|
SCNHANDLE hSceneScript; // handle to scene script
|
||||||
int32 numActor; //!< number of actors in this scene
|
SCNHANDLE hSceneDesc; // handle to scene description
|
||||||
int32 defRefer; //!< Default refer direction
|
int32 numEntrance; // number of entrances in this scene
|
||||||
SCNHANDLE hSceneScript; //!< handle to scene script
|
SCNHANDLE hEntrance; // handle to table of entrances
|
||||||
SCNHANDLE hEntrance; //!< handle to table of entrances
|
int32 numPoly; // number of various polygons in this scene
|
||||||
SCNHANDLE hPoly; //!< handle to table of polygons
|
SCNHANDLE hPoly; // handle to table of polygons
|
||||||
SCNHANDLE hActor; //!< handle to table of actors
|
int32 numTaggedActor; // number of tagged actors in this scene
|
||||||
|
SCNHANDLE hTaggedActor; // handle to table of tagged actors
|
||||||
|
int32 numProcess; // number of processes in this scene
|
||||||
|
SCNHANDLE hProcess; // handle to table of processes
|
||||||
|
SCNHANDLE hMusicScript; // handle to music script data
|
||||||
|
SCNHANDLE hMusicSegment;// handle to music segments
|
||||||
} PACKED_STRUCT;
|
} PACKED_STRUCT;
|
||||||
|
|
||||||
/** entrance structure - one per entrance */
|
/** entrance structure - one per entrance */
|
||||||
struct ENTRANCE_STRUC {
|
struct ENTRANCE_STRUC {
|
||||||
int32 eNumber; //!< entrance number
|
int32 eNumber; //!< entrance number
|
||||||
SCNHANDLE hScript; //!< handle to entrance script
|
SCNHANDLE hScript; //!< handle to entrance script
|
||||||
|
// Tinsel 2 fields
|
||||||
|
SCNHANDLE hEntDesc; // handle to entrance description
|
||||||
|
uint32 flags;
|
||||||
} PACKED_STRUCT;
|
} PACKED_STRUCT;
|
||||||
|
|
||||||
#include "common/pack-end.h" // END STRUCT PACKING
|
#include "common/pack-end.h" // END STRUCT PACKING
|
||||||
|
@ -97,8 +110,39 @@ struct ENTRANCE_STRUC {
|
||||||
static bool ShowPosition = false; // Set when showpos() has been called
|
static bool ShowPosition = false; // Set when showpos() has been called
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SCNHANDLE newestScene = 0;
|
||||||
|
|
||||||
static SCNHANDLE SceneHandle = 0; // Current scene handle - stored in case of Save_Scene()
|
static SCNHANDLE SceneHandle = 0; // Current scene handle - stored in case of Save_Scene()
|
||||||
|
|
||||||
|
static bool bWatchingOut = false;
|
||||||
|
|
||||||
|
SCENE_STRUC tempStruc;
|
||||||
|
|
||||||
|
struct TP_INIT {
|
||||||
|
SCNHANDLE hTinselCode; // Code
|
||||||
|
TINSEL_EVENT event; // Triggering event
|
||||||
|
};
|
||||||
|
|
||||||
|
const SCENE_STRUC *GetSceneStruc(const byte *pStruc) {
|
||||||
|
if (TinselVersion == TINSEL_V2)
|
||||||
|
return (const SCENE_STRUC *)pStruc;
|
||||||
|
|
||||||
|
// Copy appropriate fields into tempStruc, and return a pointer to it
|
||||||
|
const uint32 *p = (const uint32 *)pStruc;
|
||||||
|
memset(&tempStruc, sizeof(SCENE_STRUC), 0);
|
||||||
|
|
||||||
|
tempStruc.numEntrance = *p++;
|
||||||
|
tempStruc.numPoly = *p++;
|
||||||
|
tempStruc.numTaggedActor = *p++;
|
||||||
|
tempStruc.defRefer = *p++;
|
||||||
|
tempStruc.hSceneScript = *p++;
|
||||||
|
tempStruc.hEntrance = *p++;
|
||||||
|
tempStruc.hPoly = *p++;
|
||||||
|
tempStruc.hTaggedActor = *p++;
|
||||||
|
|
||||||
|
return &tempStruc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Started up for scene script and entrance script.
|
* Started up for scene script and entrance script.
|
||||||
|
@ -107,20 +151,59 @@ static void SceneTinselProcess(CORO_PARAM, const void *param) {
|
||||||
// COROUTINE
|
// COROUTINE
|
||||||
CORO_BEGIN_CONTEXT;
|
CORO_BEGIN_CONTEXT;
|
||||||
INT_CONTEXT *pic;
|
INT_CONTEXT *pic;
|
||||||
|
const TP_INIT *pInit;
|
||||||
CORO_END_CONTEXT(_ctx);
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
// get the stuff copied to process when it was created
|
|
||||||
SCNHANDLE *ss = (SCNHANDLE *)param;
|
|
||||||
assert(*ss); // Must have some code to run
|
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
_ctx->pic = InitInterpretContext(GS_SCENE, READ_LE_UINT32(ss), NOEVENT, NOPOLY, 0, NULL);
|
// get the stuff copied to process when it was created
|
||||||
|
_ctx->pInit = (const TP_INIT *)param;
|
||||||
|
assert(_ctx->pInit);
|
||||||
|
assert(_ctx->pInit->hTinselCode); // Must have some code to run
|
||||||
|
|
||||||
|
_ctx->pic = InitInterpretContext(GS_SCENE,
|
||||||
|
READ_LE_UINT32(&_ctx->pInit->hTinselCode),
|
||||||
|
TinselV2 ? _ctx->pInit->event : NOEVENT,
|
||||||
|
NOPOLY, // No polygon
|
||||||
|
0, // No actor
|
||||||
|
NULL, // No object
|
||||||
|
0);
|
||||||
CORO_INVOKE_1(Interpret, _ctx->pic);
|
CORO_INVOKE_1(Interpret, _ctx->pic);
|
||||||
|
|
||||||
|
if (_ctx->pInit->event == CLOSEDOWN || _ctx->pInit->event == LEAVE_T2)
|
||||||
|
bWatchingOut = false;
|
||||||
|
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start up a SceneTinselProcess() running the scene
|
||||||
|
* script for various events.
|
||||||
|
*/
|
||||||
|
void SendSceneTinselProcess(TINSEL_EVENT event) {
|
||||||
|
SCENE_STRUC *ss;
|
||||||
|
|
||||||
|
if (event == CLOSEDOWN || event == LEAVE_T2)
|
||||||
|
bWatchingOut = true;
|
||||||
|
|
||||||
|
if (SceneHandle != (SCNHANDLE)NULL) {
|
||||||
|
ss = (SCENE_STRUC *) FindChunk(SceneHandle, CHUNK_SCENE);
|
||||||
|
|
||||||
|
if (ss->hSceneScript) {
|
||||||
|
TP_INIT init;
|
||||||
|
|
||||||
|
init.event = event;
|
||||||
|
init.hTinselCode = ss->hSceneScript;
|
||||||
|
|
||||||
|
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
|
||||||
|
} else if (event == CLOSEDOWN)
|
||||||
|
bWatchingOut = false;
|
||||||
|
}
|
||||||
|
else if (event == CLOSEDOWN)
|
||||||
|
bWatchingOut = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the SCENE_STRUC
|
* Get the SCENE_STRUC
|
||||||
* Initialise polygons for the scene
|
* Initialise polygons for the scene
|
||||||
|
@ -128,47 +211,103 @@ static void SceneTinselProcess(CORO_PARAM, const void *param) {
|
||||||
* Run the appropriate entrance code (if any)
|
* Run the appropriate entrance code (if any)
|
||||||
* Get the default refer type
|
* Get the default refer type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void LoadScene(SCNHANDLE scene, int entry) {
|
static void LoadScene(SCNHANDLE scene, int entry) {
|
||||||
|
uint i;
|
||||||
|
TP_INIT init;
|
||||||
const SCENE_STRUC *ss;
|
const SCENE_STRUC *ss;
|
||||||
const ENTRANCE_STRUC *es;
|
const ENTRANCE_STRUC *es;
|
||||||
uint i;
|
|
||||||
|
|
||||||
// Scene structure
|
// Scene handle
|
||||||
SceneHandle = scene; // Save scene handle in case of Save_Scene()
|
SceneHandle = scene; // Save scene handle in case of Save_Scene()
|
||||||
|
|
||||||
LockMem(SceneHandle); // Make sure scene is loaded
|
LockMem(SceneHandle); // Make sure scene is loaded
|
||||||
LockScene(SceneHandle); // Prevent current scene from being discarded
|
LockScene(SceneHandle); // Prevent current scene from being discarded
|
||||||
|
|
||||||
ss = (const SCENE_STRUC *)FindChunk(scene, CHUNK_SCENE);
|
if (TinselV2) {
|
||||||
|
// CdPlay() stuff
|
||||||
|
byte *cptr = FindChunk(scene, CHUNK_CDPLAY_FILENUM);
|
||||||
|
assert(cptr);
|
||||||
|
i = READ_LE_UINT32(cptr);
|
||||||
|
assert(i < 512);
|
||||||
|
cptr = FindChunk(scene, CHUNK_CDPLAY_FILENAME);
|
||||||
|
assert(cptr);
|
||||||
|
SetCdPlaySceneDetails(i, (const char *)cptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find scene structure
|
||||||
|
ss = GetSceneStruc(FindChunk(scene, CHUNK_SCENE));
|
||||||
assert(ss != NULL);
|
assert(ss != NULL);
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// Handle to scene description
|
||||||
|
newestScene = FROM_LE_32(ss->hSceneDesc);
|
||||||
|
|
||||||
|
// Music stuff
|
||||||
|
char *cptr = (char *)FindChunk(scene, CHUNK_MUSIC_FILENAME);
|
||||||
|
assert(cptr);
|
||||||
|
_vm->_pcmMusic->setMusicSceneDetails(FROM_LE_32(ss->hMusicScript),
|
||||||
|
FROM_LE_32(ss->hMusicSegment), cptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == NO_ENTRY_NUM) {
|
||||||
|
// Restoring scene
|
||||||
|
|
||||||
// Initialise all the polygons for this scene
|
// Initialise all the polygons for this scene
|
||||||
InitPolygons(FROM_LE_32(ss->hPoly), FROM_LE_32(ss->numPoly), (entry == NO_ENTRY_NUM));
|
InitPolygons(FROM_LE_32(ss->hPoly), FROM_LE_32(ss->numPoly), true);
|
||||||
|
|
||||||
// Initialise the actors for this scene
|
// Initialise the actors for this scene
|
||||||
StartActors(FROM_LE_32(ss->hActor), FROM_LE_32(ss->numActor), (entry != NO_ENTRY_NUM));
|
StartTaggedActors(FROM_LE_32(ss->hTaggedActor), FROM_LE_32(ss->numTaggedActor), false);
|
||||||
|
|
||||||
if (entry != NO_ENTRY_NUM) {
|
if (TinselV2)
|
||||||
|
// Returning from cutscene
|
||||||
|
SendSceneTinselProcess(RESTORE);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Genuine new scene
|
||||||
|
|
||||||
|
// Initialise all the polygons for this scene
|
||||||
|
InitPolygons(FROM_LE_32(ss->hPoly), FROM_LE_32(ss->numPoly), false);
|
||||||
|
|
||||||
|
// Initialise the actors for this scene
|
||||||
|
StartTaggedActors(FROM_LE_32(ss->hTaggedActor), FROM_LE_32(ss->numTaggedActor), true);
|
||||||
|
|
||||||
// Run the appropriate entrance code (if any)
|
// Run the appropriate entrance code (if any)
|
||||||
es = (const ENTRANCE_STRUC *)LockMem(FROM_LE_32(ss->hEntrance));
|
es = (const ENTRANCE_STRUC *)LockMem(FROM_LE_32(ss->hEntrance));
|
||||||
for (i = 0; i < FROM_LE_32(ss->numEntrance); i++, es++) {
|
for (i = 0; i < FROM_LE_32(ss->numEntrance); i++) {
|
||||||
if (FROM_LE_32(es->eNumber) == (uint)entry) {
|
if (FROM_LE_32(es->eNumber) == (uint)entry) {
|
||||||
if (es->hScript)
|
if (es->hScript) {
|
||||||
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &es->hScript, sizeof(es->hScript));
|
init.event = STARTUP;
|
||||||
|
init.hTinselCode = es->hScript;
|
||||||
|
|
||||||
|
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move to next entrance
|
||||||
|
if (TinselV2)
|
||||||
|
++es;
|
||||||
|
else
|
||||||
|
es = (const ENTRANCE_STRUC *)((const byte *)es + 8);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == FROM_LE_32(ss->numEntrance))
|
if (i == FROM_LE_32(ss->numEntrance))
|
||||||
error("Non-existant scene entry number");
|
error("Non-existant scene entry number");
|
||||||
|
|
||||||
if (ss->hSceneScript)
|
if (ss->hSceneScript) {
|
||||||
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &ss->hSceneScript, sizeof(ss->hSceneScript));
|
init.event = STARTUP;
|
||||||
|
init.hTinselCode = ss->hSceneScript;
|
||||||
|
|
||||||
|
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default refer type
|
// Default refer type
|
||||||
SetDefaultRefer(FROM_LE_32(ss->defRefer));
|
SetDefaultRefer(FROM_LE_32(ss->defRefer));
|
||||||
|
|
||||||
|
// Scene's processes
|
||||||
|
SceneProcesses(FROM_LE_32(ss->numProcess), FROM_LE_32(ss->hProcess));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -184,15 +323,27 @@ void EndScene(void) {
|
||||||
KillInventory(); // Close down any open inventory
|
KillInventory(); // Close down any open inventory
|
||||||
|
|
||||||
DropPolygons(); // No polygons
|
DropPolygons(); // No polygons
|
||||||
DropNoScrolls(); // No no-scrolls
|
DropScroll(); // No no-scrolls
|
||||||
DropBackground(); // No background
|
DropBackground(); // No background
|
||||||
DropMActors(); // No moving actors
|
DropMovers(); // No moving actors
|
||||||
DropCursor(); // No cursor
|
DropCursor(); // No cursor
|
||||||
DropActors(); // No actor reels running
|
DropActors(); // No actor reels running
|
||||||
FreeAllTokens(); // No-one has tokens
|
FreeAllTokens(); // No-one has tokens
|
||||||
FreeMostInterpretContexts(); // Only master script still interpreting
|
FreeMostInterpretContexts(); // Only master script still interpreting
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
SetSysVar(ISV_DIVERT_ACTOR, 0);
|
||||||
|
SetSysVar(ISV_GHOST_ACTOR, 0);
|
||||||
|
SetSysVar(SV_MinimumXoffset, 0);
|
||||||
|
SetSysVar(SV_MaximumXoffset, 0);
|
||||||
|
SetSysVar(SV_MinimumYoffset, 0);
|
||||||
|
SetSysVar(SV_MaximumYoffset, 0);
|
||||||
|
ResetFontHandles();
|
||||||
|
NoSoundReels();
|
||||||
|
}
|
||||||
|
|
||||||
_vm->_sound->stopAllSamples(); // Kill off any still-running sample
|
_vm->_sound->stopAllSamples(); // Kill off any still-running sample
|
||||||
|
_vm->_mixer->stopAll();
|
||||||
|
|
||||||
// init the palette manager
|
// init the palette manager
|
||||||
ResetPalAllocator();
|
ResetPalAllocator();
|
||||||
|
@ -251,10 +402,11 @@ void PrimeBackground(void) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void PrimeScene(void) {
|
void PrimeScene(void) {
|
||||||
|
SetNoBlocking(false);
|
||||||
bNoBlocking = false;
|
SetSysVar(SYS_SceneFxDimFactor, SysVar(SYS_DefaultFxDimFactor));
|
||||||
|
|
||||||
RestartCursor(); // Restart the cursor
|
RestartCursor(); // Restart the cursor
|
||||||
|
if (!TinselV2)
|
||||||
EnableTags(); // Next scene with tags enabled
|
EnableTags(); // Next scene with tags enabled
|
||||||
|
|
||||||
g_scheduler->createProcess(PID_SCROLL, ScrollProcess, NULL, 0);
|
g_scheduler->createProcess(PID_SCROLL, ScrollProcess, NULL, 0);
|
||||||
|
@ -276,9 +428,15 @@ void PrimeScene(void) {
|
||||||
* Wrap up the last scene and start up the next scene.
|
* Wrap up the last scene and start up the next scene.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void NewScene(SCNHANDLE scene, int entry) {
|
void StartNewScene(SCNHANDLE scene, int entry) {
|
||||||
EndScene(); // Wrap up the last scene.
|
EndScene(); // Wrap up the last scene.
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
TouchMoverReels();
|
||||||
|
|
||||||
|
LockMem(scene); // Do CD change before PrimeScene
|
||||||
|
}
|
||||||
|
|
||||||
PrimeScene(); // Start up the standard stuff for the next scene.
|
PrimeScene(); // Start up the standard stuff for the next scene.
|
||||||
|
|
||||||
LoadScene(scene, entry);
|
LoadScene(scene, entry);
|
||||||
|
@ -303,4 +461,29 @@ SCNHANDLE GetSceneHandle(void) {
|
||||||
return SceneHandle;
|
return SceneHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DoHailScene
|
||||||
|
*/
|
||||||
|
|
||||||
|
void DoHailScene(SCNHANDLE scene) {
|
||||||
|
// Find scene structure
|
||||||
|
const SCENE_STRUC *ss = GetSceneStruc(FindChunk(scene, CHUNK_SCENE));
|
||||||
|
|
||||||
|
if (ss != NULL && ss->hSceneScript) {
|
||||||
|
TP_INIT init;
|
||||||
|
|
||||||
|
init.event = NOEVENT;
|
||||||
|
init.hTinselCode = ss->hSceneScript;
|
||||||
|
|
||||||
|
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WrapScene
|
||||||
|
*/
|
||||||
|
void WrapScene(void) {
|
||||||
|
SendSceneTinselProcess(CLOSEDOWN);
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define TINSEL_SCENE_H
|
#define TINSEL_SCENE_H
|
||||||
|
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
|
#include "tinsel/events.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -39,13 +40,19 @@ enum {
|
||||||
MAX_ACTOR = 32 //!< maximum number of actors in a scene
|
MAX_ACTOR = 32 //!< maximum number of actors in a scene
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ENTRANCE_STRUC bitflags
|
||||||
|
enum ENTRANCE_FLAGS {
|
||||||
|
fCall = 0x00000001L,
|
||||||
|
fHook = 0x00000002L
|
||||||
|
};
|
||||||
|
|
||||||
/** reference direction */
|
/** reference direction */
|
||||||
enum REFTYPE {
|
enum REFTYPE {
|
||||||
REF_DEFAULT, REF_UP, REF_DOWN, REF_LEFT, REF_RIGHT, REF_POINT
|
REF_DEFAULT, REF_UP, REF_DOWN, REF_LEFT, REF_RIGHT, REF_POINT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TFTYPE {
|
enum TFTYPE {
|
||||||
TF_NONE, TF_UP, TF_DOWN, TF_LEFT, TF_RIGHT, TF_BOGUS
|
TF_NONE, TF_UP, TF_DOWN, TF_LEFT, TF_RIGHT, TF_FILM
|
||||||
};
|
};
|
||||||
|
|
||||||
/** different actor masks */
|
/** different actor masks */
|
||||||
|
@ -68,6 +75,23 @@ enum REEL {
|
||||||
REEL_DEFAULT, REEL_ALL, REEL_HORIZ, REEL_VERT
|
REEL_DEFAULT, REEL_ALL, REEL_HORIZ, REEL_VERT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum { TRANS_DEF, TRANS_CUT, TRANS_FADE } TRANSITS;
|
||||||
|
|
||||||
|
// amount to shift scene handles by
|
||||||
|
#define SCNHANDLE_SHIFT (TinselV2 ? 25 : 23)
|
||||||
|
#define OFFSETMASK (TinselV2 ? 0x01ffffffL : 0x007fffffL)
|
||||||
|
#define HANDLEMASK (TinselV2 ? 0xFE000000L : 0xFF800000L)
|
||||||
|
|
||||||
|
void DoHailScene(SCNHANDLE scene);
|
||||||
|
|
||||||
|
void WrapScene(void);
|
||||||
|
|
||||||
|
void StartNewScene(SCNHANDLE scene, int entry);
|
||||||
|
|
||||||
|
void EndScene(void);
|
||||||
|
|
||||||
|
void SendSceneTinselProcess(TINSEL_EVENT event);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif // TINSEL_SCENE_H
|
#endif // TINSEL_SCENE_H
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
* Process scheduler.
|
* Process scheduler.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "tinsel/handle.h"
|
||||||
|
#include "tinsel/pcode.h"
|
||||||
|
#include "tinsel/pid.h"
|
||||||
|
#include "tinsel/polygons.h"
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
|
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
@ -32,18 +36,26 @@ namespace Tinsel {
|
||||||
|
|
||||||
Scheduler *g_scheduler = 0;
|
Scheduler *g_scheduler = 0;
|
||||||
|
|
||||||
/** process structure */
|
#include "common/pack-start.h" // START STRUCT PACKING
|
||||||
struct PROCESS {
|
|
||||||
PROCESS *pNext; //!< pointer to next process in active or free list
|
|
||||||
|
|
||||||
CoroContext state; //!< the state of the coroutine
|
struct PROCESS_STRUC {
|
||||||
CORO_ADDR coroAddr; //!< the entry point of the coroutine
|
uint32 processId; // ID of process
|
||||||
|
SCNHANDLE hProcessCode; // handle to actor script
|
||||||
|
} PACKED_STRUCT;
|
||||||
|
|
||||||
int sleepTime; //!< number of scheduler cycles to sleep
|
#include "common/pack-end.h" // END STRUCT PACKING
|
||||||
int pid; //!< process ID
|
|
||||||
char param[PARAM_SIZE]; //!< process specific info
|
|
||||||
};
|
|
||||||
|
|
||||||
|
CoroContext nullContext = NULL;
|
||||||
|
|
||||||
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
|
static uint32 numSceneProcess;
|
||||||
|
static SCNHANDLE hSceneProcess;
|
||||||
|
|
||||||
|
static uint32 numGlobalProcess;
|
||||||
|
static PROCESS_STRUC *pGlobalProcess;
|
||||||
|
|
||||||
|
//--------------------- FUNCTIONS ------------------------
|
||||||
|
|
||||||
Scheduler::Scheduler() {
|
Scheduler::Scheduler() {
|
||||||
processList = 0;
|
processList = 0;
|
||||||
|
@ -59,6 +71,7 @@ Scheduler::Scheduler() {
|
||||||
pRCfunction = 0;
|
pRCfunction = 0;
|
||||||
|
|
||||||
active = new PROCESS;
|
active = new PROCESS;
|
||||||
|
active->pPrevious = NULL;
|
||||||
|
|
||||||
g_scheduler = this; // FIXME HACK
|
g_scheduler = this; // FIXME HACK
|
||||||
}
|
}
|
||||||
|
@ -83,7 +96,7 @@ void Scheduler::reset() {
|
||||||
|
|
||||||
if (processList == NULL) {
|
if (processList == NULL) {
|
||||||
// first time - allocate memory for process list
|
// first time - allocate memory for process list
|
||||||
processList = (PROCESS *)calloc(NUM_PROCESS, sizeof(PROCESS));
|
processList = (PROCESS *)calloc(MAX_PROCESSES, sizeof(PROCESS));
|
||||||
|
|
||||||
// make sure memory allocated
|
// make sure memory allocated
|
||||||
if (processList == NULL) {
|
if (processList == NULL) {
|
||||||
|
@ -91,7 +104,7 @@ void Scheduler::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill with garbage
|
// fill with garbage
|
||||||
memset(processList, 'S', NUM_PROCESS * sizeof(PROCESS));
|
memset(processList, 'S', MAX_PROCESSES * sizeof(PROCESS));
|
||||||
}
|
}
|
||||||
|
|
||||||
// no active processes
|
// no active processes
|
||||||
|
@ -101,12 +114,10 @@ void Scheduler::reset() {
|
||||||
pFreeProcesses = processList;
|
pFreeProcesses = processList;
|
||||||
|
|
||||||
// link all other processes after first
|
// link all other processes after first
|
||||||
for (int i = 1; i < NUM_PROCESS; i++) {
|
for (int i = 1; i <= NUM_PROCESS; i++) {
|
||||||
processList[i - 1].pNext = processList + i;
|
processList[i - 1].pNext = (i == NUM_PROCESS) ? NULL : processList + i;
|
||||||
|
processList[i - 1].pPrevious = (i == 1) ? active : processList + (i - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// null the last process
|
|
||||||
processList[NUM_PROCESS - 1].pNext = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,33 +130,172 @@ void Scheduler::printStats(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
/**
|
||||||
|
* Checks both the active and free process list to insure all the links are valid,
|
||||||
|
* and that no processes have been lost
|
||||||
|
*/
|
||||||
|
void Scheduler::CheckStack() {
|
||||||
|
Common::List<PROCESS *> pList;
|
||||||
|
|
||||||
|
// Check both the active and free process lists
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
PROCESS *p = (i == 0) ? active : pFreeProcesses;
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
// Make sure the linkages are correct
|
||||||
|
while (p->pNext != NULL) {
|
||||||
|
assert(p->pNext->pPrevious == p);
|
||||||
|
pList.push_back(p);
|
||||||
|
p = p->pNext;
|
||||||
|
}
|
||||||
|
pList.push_back(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure all processes are accounted for
|
||||||
|
for (int idx = 0; idx < NUM_PROCESS; idx++) {
|
||||||
|
bool found = false;
|
||||||
|
for (Common::List<PROCESS *>::iterator i = pList.begin(); i != pList.end(); ++i) {
|
||||||
|
PROCESS *pTemp = *i;
|
||||||
|
if (*i == &processList[idx]) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Give all active processes a chance to run
|
* Give all active processes a chance to run
|
||||||
*/
|
*/
|
||||||
void Scheduler::schedule(void) {
|
void Scheduler::schedule(void) {
|
||||||
// start dispatching active process list
|
// start dispatching active process list
|
||||||
PROCESS *pPrevProc = active;
|
PROCESS *pNext;
|
||||||
PROCESS *pProc = active->pNext;
|
PROCESS *pProc = active->pNext;
|
||||||
while (pProc != NULL) {
|
while (pProc != NULL) {
|
||||||
|
pNext = pProc->pNext;
|
||||||
|
|
||||||
if (--pProc->sleepTime <= 0) {
|
if (--pProc->sleepTime <= 0) {
|
||||||
// process is ready for dispatch, activate it
|
// process is ready for dispatch, activate it
|
||||||
pCurrent = pProc;
|
pCurrent = pProc;
|
||||||
pProc->coroAddr(pProc->state, pProc->param);
|
pProc->coroAddr(pProc->state, pProc->param);
|
||||||
pCurrent = NULL;
|
|
||||||
if (!pProc->state || pProc->state->_sleep <= 0) {
|
if (!pProc->state || pProc->state->_sleep <= 0) {
|
||||||
// Coroutine finished
|
// Coroutine finished
|
||||||
|
pCurrent = pCurrent->pPrevious;
|
||||||
killProcess(pProc);
|
killProcess(pProc);
|
||||||
pProc = pPrevProc;
|
|
||||||
} else {
|
} else {
|
||||||
pProc->sleepTime = pProc->state->_sleep;
|
pProc->sleepTime = pProc->state->_sleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pCurrent may have been changed
|
||||||
|
pNext = pCurrent->pNext;
|
||||||
|
pCurrent = NULL;
|
||||||
}
|
}
|
||||||
pPrevProc = pProc;
|
|
||||||
pProc = pProc->pNext;
|
pProc = pNext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reschedules all the processes to run again this query
|
||||||
|
*/
|
||||||
|
void Scheduler::rescheduleAll() {
|
||||||
|
assert(pCurrent);
|
||||||
|
|
||||||
|
// Unlink current process
|
||||||
|
pCurrent->pPrevious->pNext = pCurrent->pNext;
|
||||||
|
if (pCurrent->pNext)
|
||||||
|
pCurrent->pNext->pPrevious = pCurrent->pPrevious;
|
||||||
|
|
||||||
|
// Add process to the start of the active list
|
||||||
|
pCurrent->pNext = active->pNext;
|
||||||
|
active->pNext->pPrevious = pCurrent;
|
||||||
|
active->pNext = pCurrent;
|
||||||
|
pCurrent->pPrevious = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the specified process has already run on this tick, make it run
|
||||||
|
* again on the current tick.
|
||||||
|
*/
|
||||||
|
void Scheduler::reschedule(PPROCESS pReSchedProc) {
|
||||||
|
// If not currently processing the schedule list, then no action is needed
|
||||||
|
if (!pCurrent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!pReSchedProc)
|
||||||
|
pReSchedProc = pCurrent;
|
||||||
|
|
||||||
|
PPROCESS pEnd;
|
||||||
|
|
||||||
|
// Find the last process in the list.
|
||||||
|
// But if the target process is down the list from here, do nothing
|
||||||
|
for (pEnd = pCurrent; pEnd->pNext != NULL; pEnd = pEnd->pNext) {
|
||||||
|
if (pEnd->pNext == pReSchedProc)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(pEnd->pNext == NULL);
|
||||||
|
|
||||||
|
// Could be in the middle of a KillProc()!
|
||||||
|
// Dying process was last and this process was penultimate
|
||||||
|
if (pReSchedProc->pNext == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If we're moving the current process, move it back by one, so that the next
|
||||||
|
// schedule() iteration moves to the now next one
|
||||||
|
if (pCurrent == pReSchedProc)
|
||||||
|
pCurrent = pCurrent->pPrevious;
|
||||||
|
|
||||||
|
// Unlink the process, and add it at the end
|
||||||
|
pReSchedProc->pPrevious->pNext = pReSchedProc->pNext;
|
||||||
|
pReSchedProc->pNext->pPrevious = pReSchedProc->pPrevious;
|
||||||
|
pEnd->pNext = pReSchedProc;
|
||||||
|
pReSchedProc->pPrevious = pEnd;
|
||||||
|
pReSchedProc->pNext = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the specified process to the end of the dispatch queue
|
||||||
|
* allowing it to run again within the current game cycle.
|
||||||
|
* @param pGiveProc Which process
|
||||||
|
*/
|
||||||
|
void Scheduler::giveWay(PPROCESS pReSchedProc) {
|
||||||
|
// If not currently processing the schedule list, then no action is needed
|
||||||
|
if (!pCurrent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!pReSchedProc)
|
||||||
|
pReSchedProc = pCurrent;
|
||||||
|
|
||||||
|
// If the process is already at the end of the queue, nothing has to be done
|
||||||
|
if (!pReSchedProc->pNext)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PPROCESS pEnd;
|
||||||
|
|
||||||
|
// Find the last process in the list.
|
||||||
|
for (pEnd = pCurrent; pEnd->pNext != NULL; pEnd = pEnd->pNext) ;
|
||||||
|
assert(pEnd->pNext == NULL);
|
||||||
|
|
||||||
|
|
||||||
|
// If we're moving the current process, move it back by one, so that the next
|
||||||
|
// schedule() iteration moves to the now next one
|
||||||
|
if (pCurrent == pReSchedProc)
|
||||||
|
pCurrent = pCurrent->pPrevious;
|
||||||
|
|
||||||
|
// Unlink the process, and add it at the end
|
||||||
|
pReSchedProc->pPrevious->pNext = pReSchedProc->pNext;
|
||||||
|
pReSchedProc->pNext->pPrevious = pReSchedProc->pPrevious;
|
||||||
|
pEnd->pNext = pReSchedProc;
|
||||||
|
pReSchedProc->pPrevious = pEnd;
|
||||||
|
pReSchedProc->pNext = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new process.
|
* Creates a new process.
|
||||||
|
@ -172,16 +322,27 @@ PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pPara
|
||||||
|
|
||||||
// get link to next free process
|
// get link to next free process
|
||||||
pFreeProcesses = pProc->pNext;
|
pFreeProcesses = pProc->pNext;
|
||||||
|
if (pFreeProcesses)
|
||||||
|
pFreeProcesses->pPrevious = NULL;
|
||||||
|
|
||||||
if (pCurrent != NULL) {
|
if (pCurrent != NULL) {
|
||||||
// place new process before the next active process
|
// place new process before the next active process
|
||||||
pProc->pNext = pCurrent->pNext;
|
pProc->pNext = pCurrent->pNext;
|
||||||
|
if (pProc->pNext)
|
||||||
|
pProc->pNext->pPrevious = pProc;
|
||||||
|
|
||||||
// make this new process the next active process
|
// make this new process the next active process
|
||||||
pCurrent->pNext = pProc;
|
pCurrent->pNext = pProc;
|
||||||
|
pProc->pPrevious = pCurrent;
|
||||||
|
|
||||||
} else { // no active processes, place process at head of list
|
} else { // no active processes, place process at head of list
|
||||||
pProc->pNext = active->pNext;
|
pProc->pNext = active->pNext;
|
||||||
|
pProc->pPrevious = active;
|
||||||
|
|
||||||
|
if (pProc->pNext)
|
||||||
|
pProc->pNext->pPrevious = pProc;
|
||||||
active->pNext = pProc;
|
active->pNext = pProc;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set coroutine entry point
|
// set coroutine entry point
|
||||||
|
@ -204,7 +365,6 @@ PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pPara
|
||||||
memcpy(pProc->param, pParam, sizeParam);
|
memcpy(pProc->param, pParam, sizeParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return created process
|
// return created process
|
||||||
return pProc;
|
return pProc;
|
||||||
}
|
}
|
||||||
|
@ -215,8 +375,6 @@ PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pPara
|
||||||
* @param pKillProc which process to kill
|
* @param pKillProc which process to kill
|
||||||
*/
|
*/
|
||||||
void Scheduler::killProcess(PROCESS *pKillProc) {
|
void Scheduler::killProcess(PROCESS *pKillProc) {
|
||||||
PROCESS *pProc, *pPrev; // process list pointers
|
|
||||||
|
|
||||||
// make sure a valid process pointer
|
// make sure a valid process pointer
|
||||||
assert(pKillProc >= processList && pKillProc <= processList + NUM_PROCESS - 1);
|
assert(pKillProc >= processList && pKillProc <= processList + NUM_PROCESS - 1);
|
||||||
|
|
||||||
|
@ -229,32 +387,25 @@ void Scheduler::killProcess(PROCESS *pKillProc) {
|
||||||
assert(numProcs >= 0);
|
assert(numProcs >= 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// search the active list for the process
|
|
||||||
for (pProc = active->pNext, pPrev = active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) {
|
|
||||||
if (pProc == pKillProc) {
|
|
||||||
// found process in active list
|
|
||||||
|
|
||||||
// Free process' resources
|
// Free process' resources
|
||||||
if (pRCfunction != NULL)
|
if (pRCfunction != NULL)
|
||||||
(pRCfunction)(pProc);
|
(pRCfunction)(pKillProc);
|
||||||
|
|
||||||
delete pProc->state;
|
delete pKillProc->state;
|
||||||
|
|
||||||
// make prev point to next to unlink pProc
|
// Take the process out of the active chain list
|
||||||
pPrev->pNext = pProc->pNext;
|
pKillProc->pPrevious->pNext = pKillProc->pNext;
|
||||||
|
if (pKillProc->pNext)
|
||||||
|
pKillProc->pNext->pPrevious = pKillProc->pPrevious;
|
||||||
|
|
||||||
// link first free process after pProc
|
// link first free process after pProc
|
||||||
pProc->pNext = pFreeProcesses;
|
pKillProc->pNext = pFreeProcesses;
|
||||||
|
if (pFreeProcesses)
|
||||||
|
pKillProc->pNext->pPrevious = pKillProc;
|
||||||
|
pKillProc->pPrevious = NULL;
|
||||||
|
|
||||||
// make pProc the first free process
|
// make pKillProc the first free process
|
||||||
pFreeProcesses = pProc;
|
pFreeProcesses = pKillProc;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process not found in active list if we get to here
|
|
||||||
error("killProcess(): tried to kill a process not in the list of active processes");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -302,11 +453,21 @@ int Scheduler::killMatchingProcess(int pidKill, int pidMask) {
|
||||||
// kill this process
|
// kill this process
|
||||||
numKilled++;
|
numKilled++;
|
||||||
|
|
||||||
|
// Free the process' resources
|
||||||
|
if (pRCfunction != NULL)
|
||||||
|
(pRCfunction)(pProc);
|
||||||
|
|
||||||
|
delete pProc->state;
|
||||||
|
|
||||||
// make prev point to next to unlink pProc
|
// make prev point to next to unlink pProc
|
||||||
pPrev->pNext = pProc->pNext;
|
pPrev->pNext = pProc->pNext;
|
||||||
|
if (pProc->pNext)
|
||||||
|
pPrev->pNext->pPrevious = pPrev;
|
||||||
|
|
||||||
// link first free process after pProc
|
// link first free process after pProc
|
||||||
pProc->pNext = pFreeProcesses;
|
pProc->pNext = pFreeProcesses;
|
||||||
|
pProc->pPrevious = NULL;
|
||||||
|
pFreeProcesses->pPrevious = pProc;
|
||||||
|
|
||||||
// make pProc the first free process
|
// make pProc the first free process
|
||||||
pFreeProcesses = pProc;
|
pFreeProcesses = pProc;
|
||||||
|
@ -327,8 +488,6 @@ int Scheduler::killMatchingProcess(int pidKill, int pidMask) {
|
||||||
return numKilled;
|
return numKilled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set pointer to a function to be called by killProcess().
|
* Set pointer to a function to be called by killProcess().
|
||||||
*
|
*
|
||||||
|
@ -342,4 +501,262 @@ void Scheduler::setResourceCallback(VFPTRPP pFunc) {
|
||||||
pRCfunction = pFunc;
|
pRCfunction = pFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************************************************\
|
||||||
|
|*********** Stuff to do with scene and global processes ************|
|
||||||
|
\**************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The code for for restored scene processes.
|
||||||
|
*/
|
||||||
|
static void RestoredProcessProcess(CORO_PARAM, const void *) {
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
INT_CONTEXT *pic;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
PROCESS *pProc; // this process pointer
|
||||||
|
|
||||||
|
// get the stuff copied to process when it was created
|
||||||
|
pProc = g_scheduler->getCurrentProcess();
|
||||||
|
_ctx->pic = *((INT_CONTEXT **) pProc->param);
|
||||||
|
|
||||||
|
_ctx->pic = RestoreInterpretContext(_ctx->pic);
|
||||||
|
AttachInterpret(_ctx->pic, pProc);
|
||||||
|
|
||||||
|
CORO_INVOKE_1(Interpret, _ctx->pic);
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process Tinsel Process
|
||||||
|
*/
|
||||||
|
static void ProcessTinselProcess(CORO_PARAM, const void *) {
|
||||||
|
PPROCESS pProc = g_scheduler->getCurrentProcess();
|
||||||
|
PINT_CONTEXT *pPic = (PINT_CONTEXT *) pProc->param;
|
||||||
|
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
// get the stuff copied to process when it was created
|
||||||
|
CORO_INVOKE_1(Interpret, *pPic);
|
||||||
|
|
||||||
|
CORO_KILL_SELF();
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************\
|
||||||
|
|***************** Stuff to do with scene processes *****************|
|
||||||
|
\**************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to restore a scene process.
|
||||||
|
*/
|
||||||
|
void RestoreSceneProcess(INT_CONTEXT *pic) {
|
||||||
|
uint32 i;
|
||||||
|
PROCESS_STRUC *pStruc;
|
||||||
|
|
||||||
|
pStruc = (PROCESS_STRUC *)LockMem(hSceneProcess);
|
||||||
|
for (i = 0; i < numSceneProcess; i++) {
|
||||||
|
if (pStruc[i].hProcessCode == pic->hCode) {
|
||||||
|
g_scheduler->createProcess(PID_PROCESS + i, RestoredProcessProcess,
|
||||||
|
&pic, sizeof(pic));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(i < numSceneProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a scene process with the given event.
|
||||||
|
*/
|
||||||
|
void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape,
|
||||||
|
bool *result) {
|
||||||
|
uint32 i; // Loop counter
|
||||||
|
if (result) *result = false;
|
||||||
|
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
PROCESS_STRUC *pStruc;
|
||||||
|
PPROCESS pProc;
|
||||||
|
PINT_CONTEXT pic;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
_ctx->pStruc = (PROCESS_STRUC *)LockMem(hSceneProcess);
|
||||||
|
for (i = 0; i < numSceneProcess; i++) {
|
||||||
|
if (_ctx->pStruc[i].processId == procID) {
|
||||||
|
assert(_ctx->pStruc[i].hProcessCode); // Must have some code to run
|
||||||
|
|
||||||
|
_ctx->pic = InitInterpretContext(GS_PROCESS,
|
||||||
|
_ctx->pStruc[i].hProcessCode,
|
||||||
|
event,
|
||||||
|
NOPOLY, // No polygon
|
||||||
|
0, // No actor
|
||||||
|
NULL, // No object
|
||||||
|
myEscape);
|
||||||
|
if (_ctx->pic == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_ctx->pProc = g_scheduler->createProcess(PID_PROCESS + i, ProcessTinselProcess,
|
||||||
|
&_ctx->pic, sizeof(_ctx->pic));
|
||||||
|
AttachInterpret(_ctx->pic, _ctx->pProc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == numSceneProcess)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bWait) {
|
||||||
|
CORO_INVOKE_2(WaitInterpret, _ctx->pProc, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kill all instances of a scene process.
|
||||||
|
*/
|
||||||
|
void KillSceneProcess(uint32 procID) {
|
||||||
|
uint32 i; // Loop counter
|
||||||
|
PROCESS_STRUC *pStruc;
|
||||||
|
|
||||||
|
pStruc = (PROCESS_STRUC *) LockMem(hSceneProcess);
|
||||||
|
for (i = 0; i < numSceneProcess; i++) {
|
||||||
|
if (pStruc[i].processId == procID) {
|
||||||
|
g_scheduler->killMatchingProcess(PID_PROCESS + i, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the scene processes in a scene.
|
||||||
|
*/
|
||||||
|
void SceneProcesses(uint32 numProcess, SCNHANDLE hProcess) {
|
||||||
|
numSceneProcess = numProcess;
|
||||||
|
hSceneProcess = hProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************\
|
||||||
|
|***************** Stuff to do with global processes ****************|
|
||||||
|
\**************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to restore a global process.
|
||||||
|
*/
|
||||||
|
void RestoreGlobalProcess(INT_CONTEXT *pic) {
|
||||||
|
uint32 i; // Loop counter
|
||||||
|
|
||||||
|
for (i = 0; i < numGlobalProcess; i++) {
|
||||||
|
if (pGlobalProcess[i].hProcessCode == pic->hCode) {
|
||||||
|
g_scheduler->createProcess(PID_GPROCESS + i, RestoredProcessProcess,
|
||||||
|
&pic, sizeof(pic));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(i < numGlobalProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kill them all (restore game).
|
||||||
|
*/
|
||||||
|
void KillGlobalProcesses(void) {
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < numGlobalProcess; ++i) {
|
||||||
|
g_scheduler->killMatchingProcess(PID_GPROCESS + i, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a global process with the given event.
|
||||||
|
*/
|
||||||
|
bool GlobalProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape) {
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
PINT_CONTEXT pic;
|
||||||
|
PPROCESS pProc;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
uint32 i; // Loop counter
|
||||||
|
_ctx->pProc = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < numGlobalProcess; ++i) {
|
||||||
|
if (pGlobalProcess[i].processId == procID) {
|
||||||
|
assert(pGlobalProcess[i].hProcessCode); // Must have some code to run
|
||||||
|
|
||||||
|
_ctx->pic = InitInterpretContext(GS_GPROCESS,
|
||||||
|
pGlobalProcess[i].hProcessCode,
|
||||||
|
event,
|
||||||
|
NOPOLY, // No polygon
|
||||||
|
0, // No actor
|
||||||
|
NULL, // No object
|
||||||
|
myEscape);
|
||||||
|
|
||||||
|
if (_ctx->pic != NULL) {
|
||||||
|
|
||||||
|
_ctx->pProc = g_scheduler->createProcess(PID_GPROCESS + i, ProcessTinselProcess,
|
||||||
|
&_ctx->pic, sizeof(_ctx->pic));
|
||||||
|
AttachInterpret(_ctx->pic, _ctx->pProc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i == numGlobalProcess) || (_ctx->pic == NULL))
|
||||||
|
result = false;
|
||||||
|
else if (bWait)
|
||||||
|
CORO_INVOKE_ARGS_V(WaitInterpret, false, (CORO_SUBCTX, _ctx->pProc, &result));
|
||||||
|
|
||||||
|
CORO_END_CODE;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kill all instances of a global process.
|
||||||
|
*/
|
||||||
|
void xKillGlobalProcess(uint32 procID) {
|
||||||
|
uint32 i; // Loop counter
|
||||||
|
|
||||||
|
for (i = 0; i < numGlobalProcess; ++i) {
|
||||||
|
if (pGlobalProcess[i].processId == procID) {
|
||||||
|
g_scheduler->killMatchingProcess(PID_GPROCESS + i, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the global processes list
|
||||||
|
*/
|
||||||
|
void GlobalProcesses(uint32 numProcess, byte *pProcess) {
|
||||||
|
pGlobalProcess = new PROCESS_STRUC[numProcess];
|
||||||
|
numGlobalProcess = numProcess;
|
||||||
|
byte *p = pProcess;
|
||||||
|
|
||||||
|
for (uint i = 0; i < numProcess; ++i, p += 8) {
|
||||||
|
pGlobalProcess[i].processId = READ_LE_UINT32(p);
|
||||||
|
pGlobalProcess[i].hProcessCode = READ_LE_UINT32(p + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the global processes list
|
||||||
|
*/
|
||||||
|
void FreeGlobalProcesses() {
|
||||||
|
delete[] pGlobalProcess;
|
||||||
|
numGlobalProcess = 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
#include "tinsel/dw.h" // new data types
|
#include "tinsel/dw.h" // new data types
|
||||||
#include "tinsel/coroutine.h"
|
#include "tinsel/coroutine.h"
|
||||||
|
#include "tinsel/events.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
@ -36,12 +38,26 @@ namespace Tinsel {
|
||||||
#define PARAM_SIZE 32
|
#define PARAM_SIZE 32
|
||||||
|
|
||||||
// the maximum number of processes
|
// the maximum number of processes
|
||||||
#define NUM_PROCESS 64
|
#define NUM_PROCESS (TinselV2 ? 70 : 64)
|
||||||
|
#define MAX_PROCESSES 70
|
||||||
|
|
||||||
typedef void (*CORO_ADDR)(CoroContext &, const void *);
|
typedef void (*CORO_ADDR)(CoroContext &, const void *);
|
||||||
|
|
||||||
|
/** process structure */
|
||||||
|
struct PROCESS {
|
||||||
|
PROCESS *pNext; //!< pointer to next process in active or free list
|
||||||
|
PROCESS *pPrevious; //!< pointer to previous process in active or free list
|
||||||
|
|
||||||
struct PROCESS;
|
CoroContext state; //!< the state of the coroutine
|
||||||
|
CORO_ADDR coroAddr; //!< the entry point of the coroutine
|
||||||
|
|
||||||
|
int sleepTime; //!< number of scheduler cycles to sleep
|
||||||
|
int pid; //!< process ID
|
||||||
|
char param[PARAM_SIZE]; //!< process specific info
|
||||||
|
};
|
||||||
|
typedef PROCESS *PPROCESS;
|
||||||
|
|
||||||
|
struct INT_CONTEXT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and manage "processes" (really coroutines).
|
* Create and manage "processes" (really coroutines).
|
||||||
|
@ -69,6 +85,8 @@ private:
|
||||||
// diagnostic process counters
|
// diagnostic process counters
|
||||||
int numProcs;
|
int numProcs;
|
||||||
int maxProcs;
|
int maxProcs;
|
||||||
|
|
||||||
|
void CheckStack();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,13 +108,16 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void schedule();
|
void schedule();
|
||||||
|
void rescheduleAll();
|
||||||
|
void reschedule(PPROCESS pReSchedProc = NULL);
|
||||||
|
void giveWay(PPROCESS pReSchedProc = NULL);
|
||||||
|
|
||||||
PROCESS *createProcess(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam);
|
PROCESS *createProcess(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam);
|
||||||
void killProcess(PROCESS *pKillProc);
|
void killProcess(PROCESS *pKillProc);
|
||||||
|
|
||||||
PROCESS *getCurrentProcess();
|
PROCESS *getCurrentProcess();
|
||||||
int getCurrentPID() const;
|
int getCurrentPID() const;
|
||||||
int killMatchingProcess(int pidKill, int pidMask);
|
int killMatchingProcess(int pidKill, int pidMask = -1);
|
||||||
|
|
||||||
|
|
||||||
void setResourceCallback(VFPTRPP pFunc);
|
void setResourceCallback(VFPTRPP pFunc);
|
||||||
|
@ -105,6 +126,23 @@ public:
|
||||||
|
|
||||||
extern Scheduler *g_scheduler; // FIXME: Temporary global var, to be used until everything has been OOifyied
|
extern Scheduler *g_scheduler; // FIXME: Temporary global var, to be used until everything has been OOifyied
|
||||||
|
|
||||||
|
//----------------- FUNCTION PROTOTYPES --------------------
|
||||||
|
|
||||||
|
void SceneProcesses(uint32 numProcess, SCNHANDLE hProcess);
|
||||||
|
void CallSceneProcess(uint32 procID);
|
||||||
|
void KillSceneProcess(uint32 procID);
|
||||||
|
void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait,
|
||||||
|
int myEscape, bool *result = NULL);
|
||||||
|
void RestoreSceneProcess(INT_CONTEXT *pic);
|
||||||
|
|
||||||
|
void GlobalProcesses(uint32 numProcess, byte *pProcess);
|
||||||
|
void xCallGlobalProcess(uint32 procID);
|
||||||
|
void xKillGlobalProcess(uint32 procID);
|
||||||
|
bool GlobalProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape);
|
||||||
|
void RestoreGlobalProcess(INT_CONTEXT *pic);
|
||||||
|
void KillGlobalProcesses(void);
|
||||||
|
void FreeGlobalProcesses();
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif // TINSEL_SCHED_H
|
#endif // TINSEL_SCHED_H
|
||||||
|
|
|
@ -47,10 +47,15 @@ byte *FindChunk(SCNHANDLE handle, uint32 chunk) {
|
||||||
uint32 *lptr = (uint32 *)bptr;
|
uint32 *lptr = (uint32 *)bptr;
|
||||||
uint32 add;
|
uint32 add;
|
||||||
|
|
||||||
// V1 chunk types can be found by substracting 2 from the
|
// Initial adjustmnet for Tinsel 1 chunk types
|
||||||
|
if ((TinselVersion != TINSEL_V2) && (chunk >= CHUNK_SCENE) &&
|
||||||
|
(chunk != CHUNK_MBSTRING))
|
||||||
|
--chunk;
|
||||||
|
|
||||||
|
// V0 chunk types can be found by substracting 2 from the
|
||||||
// chunk type. Note that CHUNK_STRING and CHUNK_BITMAP are
|
// chunk type. Note that CHUNK_STRING and CHUNK_BITMAP are
|
||||||
// the same in V1 and V2
|
// the same in V0 and V1
|
||||||
if (_vm->getVersion() == TINSEL_V0 &&
|
if (TinselVersion == TINSEL_V0 &&
|
||||||
chunk != CHUNK_STRING && chunk != CHUNK_BITMAP)
|
chunk != CHUNK_STRING && chunk != CHUNK_BITMAP)
|
||||||
chunk -= 0x2L;
|
chunk -= 0x2L;
|
||||||
|
|
||||||
|
@ -70,10 +75,10 @@ byte *FindChunk(SCNHANDLE handle, uint32 chunk) {
|
||||||
/**
|
/**
|
||||||
* Get the actor id from a film (column 0)
|
* Get the actor id from a film (column 0)
|
||||||
*/
|
*/
|
||||||
int extractActor(SCNHANDLE film) {
|
int ExtractActor(SCNHANDLE hFilm) {
|
||||||
const FILM *pfilm = (const FILM *)LockMem(film);
|
const FILM *pFilm = (const FILM *)LockMem(hFilm);
|
||||||
const FREEL *preel = &pfilm->reels[0];
|
const FREEL *pReel = &pFilm->reels[0];
|
||||||
const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(preel->mobj));
|
const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj));
|
||||||
return (int)FROM_LE_32(pmi->mulID);
|
return (int)FROM_LE_32(pmi->mulID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,14 @@
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
#define INDEX_FILENAME "index" // name of scene index file
|
||||||
|
#define INDEXFILE_LENGTH 12 // length of filenames in the MEMHANDLE structure
|
||||||
|
|
||||||
|
#define GLOBALS_FILENAME "gdata" // name of globals file
|
||||||
|
#define HOPPER_FILENAME "hopper"
|
||||||
|
#define CD_ID_FILENAME "volume"
|
||||||
|
|
||||||
|
#define BMOVIE_EXTENSION ".bmv"
|
||||||
|
|
||||||
// chunk identifier numbers
|
// chunk identifier numbers
|
||||||
|
|
||||||
|
@ -48,20 +56,42 @@ namespace Tinsel {
|
||||||
#define CHUNK_ENTRANCE 0x3334000BL // not used!
|
#define CHUNK_ENTRANCE 0x3334000BL // not used!
|
||||||
#define CHUNK_POLYGONS 0x3334000CL // not used!
|
#define CHUNK_POLYGONS 0x3334000CL // not used!
|
||||||
#define CHUNK_ACTORS 0x3334000DL // not used!
|
#define CHUNK_ACTORS 0x3334000DL // not used!
|
||||||
#define CHUNK_SCENE 0x3334000EL
|
|
||||||
#define CHUNK_TOTAL_ACTORS 0x3334000FL
|
#define CHUNK_PROCESSES 0x3334000EL // Tinsel 2 only
|
||||||
#define CHUNK_TOTAL_GLOBALS 0x33340010L
|
|
||||||
#define CHUNK_TOTAL_OBJECTS 0x33340011L
|
// Following chunk Ids should be decremented by 1 for Tinsel 1
|
||||||
#define CHUNK_OBJECTS 0x33340012L
|
#define CHUNK_SCENE 0x3334000FL
|
||||||
#define CHUNK_MIDI 0x33340013L // not used!
|
#define CHUNK_TOTAL_ACTORS 0x33340010L
|
||||||
#define CHUNK_SAMPLE 0x33340014L // not used!
|
#define CHUNK_TOTAL_GLOBALS 0x33340011L
|
||||||
#define CHUNK_TOTAL_POLY 0x33340015L
|
#define CHUNK_TOTAL_OBJECTS 0x33340012L
|
||||||
#define CHUNK_MBSTRING 0x33340022L // Multi-byte characters
|
#define CHUNK_OBJECTS 0x33340013L
|
||||||
|
#define CHUNK_MIDI 0x33340014L // not used!
|
||||||
|
#define CHUNK_SAMPLE 0x33340015L // not used!
|
||||||
|
#define CHUNK_TOTAL_POLY 0x33340016L
|
||||||
|
|
||||||
|
// Following chunks are Tinsel 2 only
|
||||||
|
#define CHUNK_NUM_PROCESSES 0x33340017L // Master scene only
|
||||||
|
#define CHUNK_MASTER_SCRIPT 0x33340018L
|
||||||
|
#define CHUNK_CDPLAY_FILENUM 0x33340019L
|
||||||
|
#define CHUNK_CDPLAY_HANDLE 0x3334001AL
|
||||||
|
#define CHUNK_CDPLAY_FILENAME 0x3334001BL
|
||||||
|
#define CHUNK_MUSIC_FILENAME 0x3334001CL
|
||||||
|
#define CHUNK_MUSIC_SCRIPT 0x3334001DL
|
||||||
|
#define CHUNK_MUSIC_SEGMENT 0x3334001EL
|
||||||
|
#define CHUNK_SCENE_HOPPER 0x3334001FL // Hopper file only
|
||||||
|
#define CHUNK_SCENE_HOPPER2 0x33340030L // Hopper file only
|
||||||
|
#define CHUNK_TIME_STAMPS 0x33340020L
|
||||||
|
|
||||||
|
// This single chunk is common to all Tinsel versions
|
||||||
|
#define CHUNK_MBSTRING 0x33340022L
|
||||||
|
|
||||||
|
// This is a base, subsequent numbers may also get used
|
||||||
|
#define CHUNK_GRAB_NAME 0x33340100L
|
||||||
|
|
||||||
#define INDEX_FILENAME "index" // name of index file
|
#define INDEX_FILENAME "index" // name of index file
|
||||||
|
|
||||||
byte *FindChunk(SCNHANDLE handle, uint32 chunk);
|
byte *FindChunk(SCNHANDLE handle, uint32 chunk);
|
||||||
int extractActor(SCNHANDLE film);
|
int ExtractActor(SCNHANDLE hFilm);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
|
|
@ -33,17 +33,11 @@
|
||||||
#include "tinsel/rince.h"
|
#include "tinsel/rince.h"
|
||||||
#include "tinsel/scroll.h"
|
#include "tinsel/scroll.h"
|
||||||
#include "tinsel/sched.h"
|
#include "tinsel/sched.h"
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
//----------------- EXTERNAL FUNCTIONS ---------------------
|
|
||||||
|
|
||||||
// in BG.C
|
|
||||||
extern int BackgroundWidth(void);
|
|
||||||
extern int BackgroundHeight(void);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//----------------- LOCAL DEFINES --------------------
|
//----------------- LOCAL DEFINES --------------------
|
||||||
|
|
||||||
#define LEFT 'L'
|
#define LEFT 'L'
|
||||||
|
@ -58,7 +52,7 @@ extern int BackgroundHeight(void);
|
||||||
static int LeftScroll = 0, DownScroll = 0; // Number of iterations outstanding
|
static int LeftScroll = 0, DownScroll = 0; // Number of iterations outstanding
|
||||||
|
|
||||||
static int scrollActor = 0;
|
static int scrollActor = 0;
|
||||||
static PMACTOR psActor = 0;
|
static PMOVER pScrollMover = 0;
|
||||||
static int oldx = 0, oldy = 0;
|
static int oldx = 0, oldy = 0;
|
||||||
|
|
||||||
/** Boundaries and numbers of boundaries */
|
/** Boundaries and numbers of boundaries */
|
||||||
|
@ -72,6 +66,14 @@ static SCROLLDATA sd = {
|
||||||
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
|
// DW2 fields
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,7 +83,8 @@ static bool ScrollCursor = 0; // If a TAG or EXIT polygon is clicked on,
|
||||||
// the cursor is kept over that polygon
|
// the cursor is kept over that polygon
|
||||||
// whilst scrolling
|
// whilst scrolling
|
||||||
|
|
||||||
static int scrollPixels = SCROLLPIXELS;
|
static int scrollPixelsX = SCROLLPIXELS;
|
||||||
|
static int scrollPixelsY = SCROLLPIXELS;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,13 +126,6 @@ void SetNoScroll(int x1, int y1, int x2, int y2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the obvious - called at the end of a scene.
|
|
||||||
*/
|
|
||||||
void DropNoScrolls(void) {
|
|
||||||
sd.NumNoH = sd.NumNoV = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from scroll process when it thinks that a scroll is in order.
|
* Called from scroll process when it thinks that a scroll is in order.
|
||||||
* Checks for no-scroll boundaries and sets off a scroll if allowed.
|
* Checks for no-scroll boundaries and sets off a scroll if allowed.
|
||||||
|
@ -157,9 +153,14 @@ static void NeedScroll(int direction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LeftScroll <= 0) {
|
if (LeftScroll <= 0) {
|
||||||
scrollPixels = SCROLLPIXELS;
|
if (TinselV2) {
|
||||||
|
scrollPixelsX = sd.xSpeed;
|
||||||
|
LeftScroll += sd.xDistance;
|
||||||
|
} else {
|
||||||
|
scrollPixelsX = SCROLLPIXELS;
|
||||||
LeftScroll = RLSCROLL;
|
LeftScroll = RLSCROLL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RIGHT: /* Picture will go right, 'camera' left */
|
case RIGHT: /* Picture will go right, 'camera' left */
|
||||||
|
@ -175,9 +176,14 @@ static void NeedScroll(int direction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LeftScroll >= 0) {
|
if (LeftScroll >= 0) {
|
||||||
scrollPixels = SCROLLPIXELS;
|
if (TinselV2) {
|
||||||
|
scrollPixelsX = sd.xSpeed;
|
||||||
|
LeftScroll -= sd.xDistance;
|
||||||
|
} else {
|
||||||
|
scrollPixelsX = SCROLLPIXELS;
|
||||||
LeftScroll = -RLSCROLL;
|
LeftScroll = -RLSCROLL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UP: /* Picture will go upwards, 'camera' downwards */
|
case UP: /* Picture will go upwards, 'camera' downwards */
|
||||||
|
@ -194,9 +200,14 @@ static void NeedScroll(int direction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DownScroll <= 0) {
|
if (DownScroll <= 0) {
|
||||||
scrollPixels = SCROLLPIXELS;
|
if (TinselV2) {
|
||||||
|
scrollPixelsY = sd.ySpeed;
|
||||||
|
DownScroll += sd.yDistance;
|
||||||
|
} else {
|
||||||
|
scrollPixelsY = SCROLLPIXELS;
|
||||||
DownScroll = UDSCROLL;
|
DownScroll = UDSCROLL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DOWN: /* Picture will go downwards, 'camera' upwards */
|
case DOWN: /* Picture will go downwards, 'camera' upwards */
|
||||||
|
@ -212,9 +223,14 @@ static void NeedScroll(int direction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DownScroll >= 0) {
|
if (DownScroll >= 0) {
|
||||||
scrollPixels = SCROLLPIXELS;
|
if (TinselV2) {
|
||||||
|
scrollPixelsY = sd.ySpeed;
|
||||||
|
DownScroll -= sd.yDistance;
|
||||||
|
} else {
|
||||||
|
scrollPixelsY = SCROLLPIXELS;
|
||||||
DownScroll = -UDSCROLL;
|
DownScroll = -UDSCROLL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +250,7 @@ static void ScrollImage(void) {
|
||||||
* Keeping cursor on a tag?
|
* Keeping cursor on a tag?
|
||||||
*/
|
*/
|
||||||
if (ScrollCursor) {
|
if (ScrollCursor) {
|
||||||
GetCursorXY(&curX, &curY, true);
|
GetCursorXYNoWait(&curX, &curY, true);
|
||||||
if (InPolygon(curX, curY, TAG) != NOPOLY || InPolygon(curX, curY, EXIT) != NOPOLY) {
|
if (InPolygon(curX, curY, TAG) != NOPOLY || InPolygon(curX, curY, EXIT) != NOPOLY) {
|
||||||
OldLoffset = Loffset;
|
OldLoffset = Loffset;
|
||||||
OldToffset = Toffset;
|
OldToffset = Toffset;
|
||||||
|
@ -246,49 +262,66 @@ static void ScrollImage(void) {
|
||||||
* Horizontal scrolling
|
* Horizontal scrolling
|
||||||
*/
|
*/
|
||||||
if (LeftScroll > 0) {
|
if (LeftScroll > 0) {
|
||||||
LeftScroll -= scrollPixels;
|
LeftScroll -= scrollPixelsX;
|
||||||
if (LeftScroll < 0) {
|
if (LeftScroll < 0) {
|
||||||
Loffset += LeftScroll;
|
Loffset += LeftScroll;
|
||||||
LeftScroll = 0;
|
LeftScroll = 0;
|
||||||
}
|
}
|
||||||
Loffset += scrollPixels; // Move right
|
Loffset += scrollPixelsX; // Move right
|
||||||
if (Loffset > ImageW - SCREEN_WIDTH)
|
if (Loffset > ImageW - SCREEN_WIDTH)
|
||||||
Loffset = ImageW - SCREEN_WIDTH;// Now at extreme right
|
Loffset = ImageW - SCREEN_WIDTH;// Now at extreme right
|
||||||
|
|
||||||
|
/*** New feature to prop up rickety scroll boundaries ***/
|
||||||
|
if (TinselV2 && SysVar(SV_MaximumXoffset) && (Loffset > SysVar(SV_MaximumXoffset)))
|
||||||
|
Loffset = SysVar(SV_MaximumXoffset);
|
||||||
|
|
||||||
} else if (LeftScroll < 0) {
|
} else if (LeftScroll < 0) {
|
||||||
LeftScroll += scrollPixels;
|
LeftScroll += scrollPixelsX;
|
||||||
if (LeftScroll > 0) {
|
if (LeftScroll > 0) {
|
||||||
Loffset += LeftScroll;
|
Loffset += LeftScroll;
|
||||||
LeftScroll = 0;
|
LeftScroll = 0;
|
||||||
}
|
}
|
||||||
Loffset -= scrollPixels; // Move left
|
Loffset -= scrollPixelsX; // Move left
|
||||||
if (Loffset < 0)
|
if (Loffset < 0)
|
||||||
Loffset = 0; // Now at extreme left
|
Loffset = 0; // Now at extreme left
|
||||||
|
|
||||||
|
/*** New feature to prop up rickety scroll boundaries ***/
|
||||||
|
if (TinselV2 && SysVar(SV_MinimumXoffset) && (Loffset < SysVar(SV_MinimumXoffset)))
|
||||||
|
Loffset = SysVar(SV_MinimumXoffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Vertical scrolling
|
* Vertical scrolling
|
||||||
*/
|
*/
|
||||||
if (DownScroll > 0) {
|
if (DownScroll > 0) {
|
||||||
DownScroll -= scrollPixels;
|
DownScroll -= scrollPixelsY;
|
||||||
if (DownScroll < 0) {
|
if (DownScroll < 0) {
|
||||||
Toffset += DownScroll;
|
Toffset += DownScroll;
|
||||||
DownScroll = 0;
|
DownScroll = 0;
|
||||||
}
|
}
|
||||||
Toffset += scrollPixels; // Move down
|
Toffset += scrollPixelsY; // Move down
|
||||||
|
|
||||||
if (Toffset > ImageH - SCREEN_HEIGHT)
|
if (Toffset > ImageH - SCREEN_HEIGHT)
|
||||||
Toffset = ImageH - SCREEN_HEIGHT;// Now at extreme bottom
|
Toffset = ImageH - SCREEN_HEIGHT;// Now at extreme bottom
|
||||||
|
|
||||||
|
/*** New feature to prop up rickety scroll boundaries ***/
|
||||||
|
if (TinselV2 && SysVar(SV_MaximumYoffset) && Toffset > SysVar(SV_MaximumYoffset))
|
||||||
|
Toffset = SysVar(SV_MaximumYoffset);
|
||||||
|
|
||||||
} else if (DownScroll < 0) {
|
} else if (DownScroll < 0) {
|
||||||
DownScroll += scrollPixels;
|
DownScroll += scrollPixelsY;
|
||||||
if (DownScroll > 0) {
|
if (DownScroll > 0) {
|
||||||
Toffset += DownScroll;
|
Toffset += DownScroll;
|
||||||
DownScroll = 0;
|
DownScroll = 0;
|
||||||
}
|
}
|
||||||
Toffset -= scrollPixels; // Move up
|
Toffset -= scrollPixelsY; // Move up
|
||||||
|
|
||||||
if (Toffset < 0)
|
if (Toffset < 0)
|
||||||
Toffset = 0; // Now at extreme top
|
Toffset = 0; // Now at extreme top
|
||||||
|
|
||||||
|
/*** New feature to prop up rickety scroll boundaries ***/
|
||||||
|
if (TinselV2 && SysVar(SV_MinimumYoffset) && Toffset < SysVar(SV_MinimumYoffset))
|
||||||
|
Toffset = SysVar(SV_MinimumYoffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -312,8 +345,7 @@ static void MonitorScroll(void) {
|
||||||
/*
|
/*
|
||||||
* Only do it if the actor is there and is visible
|
* Only do it if the actor is there and is visible
|
||||||
*/
|
*/
|
||||||
if (!psActor || getMActorHideState(psActor)
|
if (!pScrollMover || MoverHidden(pScrollMover) || !MoverIs(pScrollMover))
|
||||||
|| getMActorState(psActor) == NO_MACTOR)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GetActorPos(scrollActor, &newx, &newy);
|
GetActorPos(scrollActor, &newx, &newy);
|
||||||
|
@ -337,10 +369,10 @@ static void MonitorScroll(void) {
|
||||||
/*
|
/*
|
||||||
* Approaching bottom or top of the screen?
|
* Approaching bottom or top of the screen?
|
||||||
*/
|
*/
|
||||||
if (newy > Toffset+SCREEN_HEIGHT-UDDISTANCE && Toffset < ImageH-SCREEN_HEIGHT) {
|
if (newy > Toffset+SCREEN_HEIGHT-DDISTANCE && Toffset < ImageH-SCREEN_HEIGHT) {
|
||||||
if (newy > oldy)
|
if (newy > oldy)
|
||||||
NeedScroll(UP);
|
NeedScroll(UP);
|
||||||
} else if (Toffset && newy < Toffset + UDDISTANCE + GetActorBottom(scrollActor) - GetActorTop(scrollActor)) {
|
} else if (Toffset && newy < Toffset + UDISTANCE + GetActorBottom(scrollActor) - GetActorTop(scrollActor)) {
|
||||||
if (newy < oldy)
|
if (newy < oldy)
|
||||||
NeedScroll(DOWN);
|
NeedScroll(DOWN);
|
||||||
}
|
}
|
||||||
|
@ -349,6 +381,30 @@ static void MonitorScroll(void) {
|
||||||
oldy = newy;
|
oldy = newy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RestoreScrollDefaults(void) {
|
||||||
|
sd.xTrigger = SysVar(SV_SCROLL_XTRIGGER);
|
||||||
|
sd.xDistance = SysVar(SV_SCROLL_XDISTANCE);
|
||||||
|
sd.xSpeed = SysVar(SV_SCROLL_XSPEED);
|
||||||
|
sd.yTriggerTop = SysVar(SV_SCROLL_YTRIGGERTOP);
|
||||||
|
sd.yTriggerBottom= SysVar(SV_SCROLL_YTRIGGERBOT);
|
||||||
|
sd.yDistance = SysVar(SV_SCROLL_YDISTANCE);
|
||||||
|
sd.ySpeed = SysVar(SV_SCROLL_YSPEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the obvious - called at the end of a scene.
|
||||||
|
*/
|
||||||
|
void DropScroll(void) {
|
||||||
|
sd.NumNoH = sd.NumNoV = 0;
|
||||||
|
if (TinselV2) {
|
||||||
|
LeftScroll = DownScroll = 0; // No iterations outstanding
|
||||||
|
oldx = oldy = 0;
|
||||||
|
scrollPixelsX = sd.xSpeed;
|
||||||
|
scrollPixelsY = sd.ySpeed;
|
||||||
|
RestoreScrollDefaults();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decide when to scroll and scroll when decided to.
|
* Decide when to scroll and scroll when decided to.
|
||||||
*/
|
*/
|
||||||
|
@ -359,21 +415,28 @@ void ScrollProcess(CORO_PARAM, const void *) {
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
ImageH = BackgroundHeight(); // Dimensions
|
// In Tinsel v2, scenes may play movies, so the background may not always
|
||||||
ImageW = BackgroundWidth(); // of this scene.
|
// already be initialised like it is in v1
|
||||||
|
while (!GetBgObject())
|
||||||
|
CORO_SLEEP(1);
|
||||||
|
|
||||||
|
ImageH = BgHeight(); // Dimensions
|
||||||
|
ImageW = BgWidth(); // of this scene.
|
||||||
|
|
||||||
// Give up if there'll be no purpose in this process
|
// Give up if there'll be no purpose in this process
|
||||||
if (ImageW == SCREEN_WIDTH && ImageH == SCREEN_HEIGHT)
|
if (ImageW == SCREEN_WIDTH && ImageH == SCREEN_HEIGHT)
|
||||||
CORO_KILL_SELF();
|
CORO_KILL_SELF();
|
||||||
|
|
||||||
|
if (!TinselV2) {
|
||||||
LeftScroll = DownScroll = 0; // No iterations outstanding
|
LeftScroll = DownScroll = 0; // No iterations outstanding
|
||||||
oldx = oldy = 0;
|
oldx = oldy = 0;
|
||||||
scrollPixels = SCROLLPIXELS;
|
scrollPixelsX = scrollPixelsY = SCROLLPIXELS;
|
||||||
|
}
|
||||||
|
|
||||||
if (!scrollActor)
|
if (!scrollActor)
|
||||||
scrollActor = LeadId();
|
scrollActor = GetLeadId();
|
||||||
|
|
||||||
psActor = GetMover(scrollActor);
|
pScrollMover = GetMover(scrollActor);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
MonitorScroll(); // Set scroll requirement
|
MonitorScroll(); // Set scroll requirement
|
||||||
|
@ -395,17 +458,26 @@ void ScrollFocus(int ano) {
|
||||||
oldx = oldy = 0;
|
oldx = oldy = 0;
|
||||||
scrollActor = ano;
|
scrollActor = ano;
|
||||||
|
|
||||||
psActor = ano ? GetMover(scrollActor) : NULL;
|
pScrollMover = ano ? GetMover(scrollActor) : NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the actor which the camera is following
|
||||||
|
*/
|
||||||
|
int GetScrollFocus(void) {
|
||||||
|
return scrollActor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scroll to abslote position.
|
* Scroll to abslote position.
|
||||||
*/
|
*/
|
||||||
void ScrollTo(int x, int y, int iter) {
|
void ScrollTo(int x, int y, int xIter, int yIter) {
|
||||||
int Loffset, Toffset; // for background offsets
|
int Loffset, Toffset; // for background offsets
|
||||||
|
|
||||||
scrollPixels = iter != 0 ? iter : SCROLLPIXELS;
|
scrollPixelsX = xIter != 0 ? xIter : (TinselV2 ? sd.xSpeed : SCROLLPIXELS);
|
||||||
|
scrollPixelsY = yIter != 0 ? yIter : (TinselV2 ? sd.ySpeed : SCROLLPIXELS);
|
||||||
|
|
||||||
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); // get background offsets
|
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); // get background offsets
|
||||||
|
|
||||||
|
@ -429,4 +501,35 @@ void RestoreNoScrollData(SCROLLDATA *ssd) {
|
||||||
memcpy(&sd, ssd, sizeof(SCROLLDATA));
|
memcpy(&sd, ssd, sizeof(SCROLLDATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SetScrollParameters
|
||||||
|
*/
|
||||||
|
void SetScrollParameters(int xTrigger, int xDistance, int xSpeed, int yTriggerTop,
|
||||||
|
int yTriggerBottom, int yDistance, int ySpeed) {
|
||||||
|
if (xTrigger == 0 && xDistance == 0 && xSpeed == 0
|
||||||
|
&& yTriggerTop == 0 && yTriggerBottom && yDistance == 0 && ySpeed == 0) {
|
||||||
|
// Restore defaults
|
||||||
|
RestoreScrollDefaults();
|
||||||
|
} else {
|
||||||
|
if (xTrigger)
|
||||||
|
sd.xTrigger = xTrigger;
|
||||||
|
if (xDistance)
|
||||||
|
sd.xDistance = xDistance;
|
||||||
|
if (xSpeed)
|
||||||
|
sd.xSpeed = xSpeed;
|
||||||
|
if (yTriggerTop)
|
||||||
|
sd.yTriggerTop = yTriggerTop;
|
||||||
|
if (yTriggerBottom)
|
||||||
|
sd.yTriggerBottom = yTriggerBottom;
|
||||||
|
if (yDistance)
|
||||||
|
sd.yDistance = yDistance;
|
||||||
|
if (ySpeed)
|
||||||
|
sd.ySpeed = ySpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsScrolling(void) {
|
||||||
|
return (LeftScroll || DownScroll);
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -30,8 +30,10 @@ namespace Tinsel {
|
||||||
|
|
||||||
#define SCROLLPIXELS 8 // Number of pixels to scroll per iteration
|
#define SCROLLPIXELS 8 // Number of pixels to scroll per iteration
|
||||||
|
|
||||||
#define RLDISTANCE 50 // Distance from edge that triggers a scroll
|
// Distance from edge that triggers a scroll
|
||||||
#define UDDISTANCE 20
|
#define RLDISTANCE (TinselV2 ? sd.xTrigger : 50)
|
||||||
|
#define UDISTANCE (TinselV2 ? sd.yTriggerTop : 20)
|
||||||
|
#define DDISTANCE (TinselV2 ? sd.yTriggerBottom : 20)
|
||||||
|
|
||||||
// Number of iterations to make
|
// Number of iterations to make
|
||||||
#define RLSCROLL 160 // 20*8 = 160 = half a screen
|
#define RLSCROLL 160 // 20*8 = 160 = half a screen
|
||||||
|
@ -52,26 +54,39 @@ struct SCROLLDATA{
|
||||||
NOSCROLLB NoVScroll[MAX_VNOSCROLL]; // Vertical no-scroll boundaries
|
NOSCROLLB NoVScroll[MAX_VNOSCROLL]; // Vertical no-scroll boundaries
|
||||||
NOSCROLLB NoHScroll[MAX_HNOSCROLL]; // Horizontal no-scroll boundaries
|
NOSCROLLB NoHScroll[MAX_HNOSCROLL]; // Horizontal no-scroll boundaries
|
||||||
unsigned NumNoV, NumNoH; // Counts of no-scroll boundaries
|
unsigned NumNoV, NumNoH; // Counts of no-scroll boundaries
|
||||||
|
// DW2 fields
|
||||||
|
int xTrigger;
|
||||||
|
int xDistance;
|
||||||
|
int xSpeed;
|
||||||
|
int yTriggerTop;
|
||||||
|
int yTriggerBottom;
|
||||||
|
int yDistance;
|
||||||
|
int ySpeed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DontScrollCursor(void);
|
void DontScrollCursor(void);
|
||||||
void DoScrollCursor(void);
|
void DoScrollCursor(void);
|
||||||
|
|
||||||
void SetNoScroll(int x1, int y1, int x2, int y2);
|
void SetNoScroll(int x1, int y1, int x2, int y2);
|
||||||
void DropNoScrolls(void);
|
void DropScroll(void);
|
||||||
|
|
||||||
void ScrollProcess(CORO_PARAM, const void *);
|
void ScrollProcess(CORO_PARAM, const void *);
|
||||||
|
|
||||||
void ScrollFocus(int actor);
|
void ScrollFocus(int actor);
|
||||||
void ScrollTo(int x, int y, int iter);
|
int GetScrollFocus(void);
|
||||||
|
void ScrollTo(int x, int y, int xIter, int yIter);
|
||||||
|
|
||||||
void KillScroll(void);
|
void KillScroll(void);
|
||||||
|
|
||||||
void GetNoScrollData(SCROLLDATA *ssd);
|
void GetNoScrollData(SCROLLDATA *ssd);
|
||||||
void RestoreNoScrollData(SCROLLDATA *ssd);
|
void RestoreNoScrollData(SCROLLDATA *ssd);
|
||||||
|
|
||||||
|
void SetScrollParameters(int xTrigger, int xDistance, int xSpeed, int yTriggerTop,
|
||||||
|
int yTriggerBottom, int yDistance, int ySpeed);
|
||||||
|
|
||||||
|
bool IsScrolling(void);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif /* TINSEL_SCROLL_H */
|
#endif /* TINSEL_SCROLL_H */
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#include "tinsel/music.h"
|
#include "tinsel/music.h"
|
||||||
#include "tinsel/strres.h"
|
#include "tinsel/strres.h"
|
||||||
#include "tinsel/tinsel.h"
|
#include "tinsel/tinsel.h"
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
|
#include "tinsel/background.h"
|
||||||
|
|
||||||
#include "common/endian.h"
|
#include "common/endian.h"
|
||||||
#include "common/file.h"
|
#include "common/file.h"
|
||||||
|
@ -38,14 +40,20 @@
|
||||||
|
|
||||||
#include "sound/mixer.h"
|
#include "sound/mixer.h"
|
||||||
#include "sound/audiocd.h"
|
#include "sound/audiocd.h"
|
||||||
|
#include "sound/adpcm.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
extern LANGUAGE sampleLanguage;
|
||||||
|
|
||||||
//--------------------------- General data ----------------------------------
|
//--------------------------- General data ----------------------------------
|
||||||
|
|
||||||
SoundManager::SoundManager(TinselEngine *vm) :
|
SoundManager::SoundManager(TinselEngine *vm) :
|
||||||
//_vm(vm), // TODO: Enable this once global _vm var is gone
|
//_vm(vm), // TODO: Enable this once global _vm var is gone
|
||||||
_sampleIndex(0), _sampleIndexLen(0) {
|
_sampleIndex(0), _sampleIndexLen(0) {
|
||||||
|
|
||||||
|
for (int i = 0; i < kNumChannels; i++)
|
||||||
|
_channels[i].sampleNum = _channels[i].subSample = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundManager::~SoundManager() {
|
SoundManager::~SoundManager() {
|
||||||
|
@ -67,24 +75,29 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
|
||||||
if (!_vm->_mixer->isReady())
|
if (!_vm->_mixer->isReady())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
Channel &curChan = _channels[kChannelTinsel1];
|
||||||
|
|
||||||
// stop any currently playing sample
|
// stop any currently playing sample
|
||||||
_vm->_mixer->stopHandle(_handle);
|
_vm->_mixer->stopHandle(curChan.handle);
|
||||||
|
|
||||||
// make sure id is in range
|
// make sure id is in range
|
||||||
assert(id > 0 && id < _sampleIndexLen);
|
assert(id > 0 && id < _sampleIndexLen);
|
||||||
|
|
||||||
|
curChan.sampleNum = id;
|
||||||
|
curChan.subSample = 0;
|
||||||
|
|
||||||
// get file offset for this sample
|
// get file offset for this sample
|
||||||
int32 dwSampleIndex = _sampleIndex[id];
|
uint32 dwSampleIndex = _sampleIndex[id];
|
||||||
|
|
||||||
// move to correct position in the sample file
|
// move to correct position in the sample file
|
||||||
_sampleStream.seek(dwSampleIndex);
|
_sampleStream.seek(dwSampleIndex);
|
||||||
if (_sampleStream.ioFailed() || _sampleStream.pos() != dwSampleIndex)
|
if (_sampleStream.ioFailed() || (uint32)_sampleStream.pos() != dwSampleIndex)
|
||||||
error("File %s is corrupt", SAMPLE_FILE);
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
|
||||||
// read the length of the sample
|
// read the length of the sample
|
||||||
uint32 sampleLen = _sampleStream.readUint32LE();
|
uint32 sampleLen = _sampleStream.readUint32LE();
|
||||||
if (_sampleStream.ioFailed())
|
if (_sampleStream.ioFailed())
|
||||||
error("File %s is corrupt", SAMPLE_FILE);
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
|
||||||
// allocate a buffer
|
// allocate a buffer
|
||||||
void *sampleBuf = malloc(sampleLen);
|
void *sampleBuf = malloc(sampleLen);
|
||||||
|
@ -92,7 +105,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
|
||||||
|
|
||||||
// read all of the sample
|
// read all of the sample
|
||||||
if (_sampleStream.read(sampleBuf, sampleLen) != sampleLen)
|
if (_sampleStream.read(sampleBuf, sampleLen) != sampleLen)
|
||||||
error("File %s is corrupt", SAMPLE_FILE);
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
|
||||||
// FIXME: Should set this in a different place ;)
|
// FIXME: Should set this in a different place ;)
|
||||||
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volSound);
|
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volSound);
|
||||||
|
@ -101,15 +114,211 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
|
||||||
|
|
||||||
|
|
||||||
// play it
|
// play it
|
||||||
_vm->_mixer->playRaw(type, &_handle, sampleBuf, sampleLen, 22050,
|
_vm->_mixer->playRaw(type, &curChan.handle, sampleBuf, sampleLen, 22050,
|
||||||
Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED);
|
Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED);
|
||||||
|
|
||||||
if (handle)
|
if (handle)
|
||||||
*handle = _handle;
|
*handle = curChan.handle;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SoundManager::playSample(int id, int sub, bool bLooped, int x, int y, int priority,
|
||||||
|
Audio::Mixer::SoundType type, Audio::SoundHandle *handle) {
|
||||||
|
|
||||||
|
// Floppy version has no sample file
|
||||||
|
if (_vm->getFeatures() & GF_FLOPPY)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// no sample driver?
|
||||||
|
if (!_vm->_mixer->isReady())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Channel *curChan;
|
||||||
|
|
||||||
|
uint8 sndVol = 255;
|
||||||
|
|
||||||
|
// Sample on screen?
|
||||||
|
if (!offscreenChecks(x, y))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If that sample is already playing, stop it
|
||||||
|
stopSpecSample(id, sub);
|
||||||
|
|
||||||
|
if (type == Audio::Mixer::kSpeechSoundType) {
|
||||||
|
curChan = &_channels[kChannelTalk];
|
||||||
|
} else if (type == Audio::Mixer::kSFXSoundType) {
|
||||||
|
uint32 oldestTime = g_system->getMillis();
|
||||||
|
int oldestChan = kChannelSFX;
|
||||||
|
|
||||||
|
int chan;
|
||||||
|
for (chan = kChannelSFX; chan < kNumChannels; chan++) {
|
||||||
|
if (!_vm->_mixer->isSoundHandleActive(_channels[chan].handle))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((_channels[chan].lastStart < oldestTime) &&
|
||||||
|
(_channels[chan].priority <= priority)) {
|
||||||
|
|
||||||
|
oldestTime = _channels[chan].lastStart;
|
||||||
|
oldestChan = chan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan == kNumChannels) {
|
||||||
|
if (_channels[oldestChan].priority > priority) {
|
||||||
|
warning("playSample: No free channel");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
chan = oldestChan;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_vm->_pcmMusic->isDimmed() && SysVar(SYS_SceneFxDimFactor))
|
||||||
|
sndVol = 255 - 255/SysVar(SYS_SceneFxDimFactor);
|
||||||
|
|
||||||
|
curChan = &_channels[chan];
|
||||||
|
} else {
|
||||||
|
warning("playSample: Unknown SoundType");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop any currently playing sample
|
||||||
|
_vm->_mixer->stopHandle(curChan->handle);
|
||||||
|
|
||||||
|
// make sure id is in range
|
||||||
|
assert(id > 0 && id < _sampleIndexLen);
|
||||||
|
|
||||||
|
// get file offset for this sample
|
||||||
|
uint32 dwSampleIndex = _sampleIndex[id];
|
||||||
|
|
||||||
|
if (dwSampleIndex == 0) {
|
||||||
|
warning("Tinsel2 playSample, non-existant sample %d", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move to correct position in the sample file
|
||||||
|
_sampleStream.seek(dwSampleIndex);
|
||||||
|
if (_sampleStream.ioFailed() || (uint32)_sampleStream.pos() != dwSampleIndex)
|
||||||
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
|
||||||
|
// read the length of the sample
|
||||||
|
uint32 sampleLen = _sampleStream.readUint32LE();
|
||||||
|
if (_sampleStream.ioFailed())
|
||||||
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
|
||||||
|
if (sampleLen & 0x80000000) {
|
||||||
|
// Has sub samples
|
||||||
|
|
||||||
|
int32 numSubs = sampleLen & ~0x80000000;
|
||||||
|
|
||||||
|
assert(sub >= 0 && sub < numSubs);
|
||||||
|
|
||||||
|
// Skipping
|
||||||
|
for (int32 i = 0; i < sub; i++) {
|
||||||
|
sampleLen = _sampleStream.readUint32LE();
|
||||||
|
_sampleStream.skip(sampleLen);
|
||||||
|
if (_sampleStream.ioFailed())
|
||||||
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
}
|
||||||
|
sampleLen = _sampleStream.readUint32LE();
|
||||||
|
if (_sampleStream.ioFailed())
|
||||||
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
}
|
||||||
|
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugSound, "Playing sound %d.%d, %d bytes at %d (pan %d)", id, sub, sampleLen,
|
||||||
|
_sampleStream.pos(), getPan(x));
|
||||||
|
|
||||||
|
// allocate a buffer
|
||||||
|
byte *sampleBuf = (byte *) malloc(sampleLen);
|
||||||
|
assert(sampleBuf);
|
||||||
|
|
||||||
|
// read all of the sample
|
||||||
|
if (_sampleStream.read(sampleBuf, sampleLen) != sampleLen)
|
||||||
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
|
||||||
|
Common::MemoryReadStream *sampleStream =
|
||||||
|
new Common::MemoryReadStream(sampleBuf, sampleLen, true);
|
||||||
|
Audio::AudioStream *_stream =
|
||||||
|
makeADPCMStream(sampleStream, true, sampleLen, Audio::kADPCMTinsel6, 22050, 1, 24);
|
||||||
|
|
||||||
|
// FIXME: Should set this in a different place ;)
|
||||||
|
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volSound);
|
||||||
|
//_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
|
||||||
|
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volVoice);
|
||||||
|
|
||||||
|
curChan->sampleNum = id;
|
||||||
|
curChan->subSample = sub;
|
||||||
|
curChan->looped = bLooped;
|
||||||
|
curChan->x = x;
|
||||||
|
curChan->y = y;
|
||||||
|
curChan->priority = priority;
|
||||||
|
curChan->lastStart = g_system->getMillis();
|
||||||
|
// /---Compression----\ Milis BytesPerSecond
|
||||||
|
curChan->timeDuration = (((sampleLen * 64) / 25) * 1000) / (22050 * 2);
|
||||||
|
|
||||||
|
// Play it
|
||||||
|
_vm->_mixer->playInputStream(type, &curChan->handle, _stream);
|
||||||
|
_vm->_mixer->setChannelVolume(curChan->handle, sndVol);
|
||||||
|
_vm->_mixer->setChannelBalance(curChan->handle, getPan(x));
|
||||||
|
|
||||||
|
if (handle)
|
||||||
|
*handle = curChan->handle;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns FALSE if sample doesn't need playing
|
||||||
|
*/
|
||||||
|
bool SoundManager::offscreenChecks(int x, int &y)
|
||||||
|
{
|
||||||
|
// No action if no x specification
|
||||||
|
if (x == -1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// convert x to offset from screen centre
|
||||||
|
x -= PlayfieldGetCentreX(FIELD_WORLD);
|
||||||
|
|
||||||
|
if (x < -SCREEN_WIDTH || x > SCREEN_WIDTH) {
|
||||||
|
// A long way offscreen, ignore it
|
||||||
|
return false;
|
||||||
|
} else if (x < -SCREEN_WIDTH/2 || x > SCREEN_WIDTH/2) {
|
||||||
|
// Off-screen, attennuate it
|
||||||
|
|
||||||
|
y = (y > 0) ? (y / 2) : 50;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8 SoundManager::getPan(int x) {
|
||||||
|
|
||||||
|
if (x == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
x -= PlayfieldGetCentreX(FIELD_WORLD);
|
||||||
|
|
||||||
|
if (x == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (x < 0) {
|
||||||
|
if (x < (-SCREEN_WIDTH / 2))
|
||||||
|
return -127;
|
||||||
|
|
||||||
|
x = (-x * 127) / (SCREEN_WIDTH / 2);
|
||||||
|
|
||||||
|
return 0 - x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x > (SCREEN_WIDTH / 2))
|
||||||
|
return 127;
|
||||||
|
|
||||||
|
x = (x * 127) / (SCREEN_WIDTH / 2);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns TRUE if there is a sample for the specified sample identifier.
|
* Returns TRUE if there is a sample for the specified sample identifier.
|
||||||
* @param id Identifier of sample to be checked
|
* @param id Identifier of sample to be checked
|
||||||
|
@ -131,8 +340,16 @@ bool SoundManager::sampleExists(int id) {
|
||||||
/**
|
/**
|
||||||
* Returns true if a sample is currently playing.
|
* Returns true if a sample is currently playing.
|
||||||
*/
|
*/
|
||||||
bool SoundManager::sampleIsPlaying(void) {
|
bool SoundManager::sampleIsPlaying(int id) {
|
||||||
return _vm->_mixer->isSoundHandleActive(_handle);
|
if (!TinselV2)
|
||||||
|
return _vm->_mixer->isSoundHandleActive(_channels[kChannelTinsel1].handle);
|
||||||
|
|
||||||
|
for (int i = 0; i < kNumChannels; i++)
|
||||||
|
if (_channels[i].sampleNum == id)
|
||||||
|
if (_vm->_mixer->isSoundHandleActive(_channels[i].handle))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -140,7 +357,37 @@ bool SoundManager::sampleIsPlaying(void) {
|
||||||
*/
|
*/
|
||||||
void SoundManager::stopAllSamples(void) {
|
void SoundManager::stopAllSamples(void) {
|
||||||
// stop currently playing sample
|
// stop currently playing sample
|
||||||
_vm->_mixer->stopHandle(_handle);
|
|
||||||
|
if (!TinselV2) {
|
||||||
|
_vm->_mixer->stopHandle(_channels[kChannelTinsel1].handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < kNumChannels; i++)
|
||||||
|
_vm->_mixer->stopHandle(_channels[i].handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundManager::stopSpecSample(int id, int sub) {
|
||||||
|
debugC(DEBUG_DETAILED, kTinselDebugSound, "stopSpecSample(%d, %d)", id, sub);
|
||||||
|
|
||||||
|
if (!TinselV2) {
|
||||||
|
if (_channels[kChannelTinsel1].sampleNum == id)
|
||||||
|
_vm->_mixer->stopHandle(_channels[kChannelTinsel1].handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = kChannelTalk; i < kNumChannels; i++) {
|
||||||
|
if ((_channels[i].sampleNum == id) && (_channels[i].subSample == sub))
|
||||||
|
_vm->_mixer->stopHandle(_channels[i].handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundManager::setSFXVolumes(uint8 volume) {
|
||||||
|
if (!TinselV2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = kChannelSFX; i < kNumChannels; i++)
|
||||||
|
_vm->_mixer->setChannelVolume(_channels[i].handle, volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -158,7 +405,7 @@ void SoundManager::openSampleFiles(void) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// open sample index file in binary mode
|
// open sample index file in binary mode
|
||||||
if (f.open(SAMPLE_INDEX)) {
|
if (f.open(_vm->getSampleIndex(sampleLanguage))) {
|
||||||
// get length of index file
|
// get length of index file
|
||||||
f.seek(0, SEEK_END); // move to end of file
|
f.seek(0, SEEK_END); // move to end of file
|
||||||
_sampleIndexLen = f.pos(); // get file pointer
|
_sampleIndexLen = f.pos(); // get file pointer
|
||||||
|
@ -166,7 +413,7 @@ void SoundManager::openSampleFiles(void) {
|
||||||
|
|
||||||
if (_sampleIndex == NULL) {
|
if (_sampleIndex == NULL) {
|
||||||
// allocate a buffer for the indices
|
// allocate a buffer for the indices
|
||||||
_sampleIndex = (int32 *)malloc(_sampleIndexLen);
|
_sampleIndex = (uint32 *)malloc(_sampleIndexLen);
|
||||||
|
|
||||||
// make sure memory allocated
|
// make sure memory allocated
|
||||||
if (_sampleIndex == NULL) {
|
if (_sampleIndex == NULL) {
|
||||||
|
@ -179,7 +426,7 @@ void SoundManager::openSampleFiles(void) {
|
||||||
// load data
|
// load data
|
||||||
if (f.read(_sampleIndex, _sampleIndexLen) != (uint32)_sampleIndexLen)
|
if (f.read(_sampleIndex, _sampleIndexLen) != (uint32)_sampleIndexLen)
|
||||||
// file must be corrupt if we get to here
|
// file must be corrupt if we get to here
|
||||||
error("File %s is corrupt", SAMPLE_FILE);
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
|
|
||||||
#ifdef SCUMM_BIG_ENDIAN
|
#ifdef SCUMM_BIG_ENDIAN
|
||||||
// Convert all ids from LE to native format
|
// Convert all ids from LE to native format
|
||||||
|
@ -194,18 +441,25 @@ void SoundManager::openSampleFiles(void) {
|
||||||
// convert file size to size in DWORDs
|
// convert file size to size in DWORDs
|
||||||
_sampleIndexLen /= sizeof(uint32);
|
_sampleIndexLen /= sizeof(uint32);
|
||||||
} else
|
} else
|
||||||
error("Cannot find file %s", SAMPLE_INDEX);
|
error(CANNOT_FIND_FILE, _vm->getSampleIndex(sampleLanguage));
|
||||||
|
|
||||||
// open sample file in binary mode
|
// open sample file in binary mode
|
||||||
if (!_sampleStream.open(SAMPLE_FILE))
|
if (!_sampleStream.open(_vm->getSampleFile(sampleLanguage)))
|
||||||
error("Cannot find file %s", SAMPLE_FILE);
|
error(CANNOT_FIND_FILE, _vm->getSampleFile(sampleLanguage));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// gen length of the largest sample
|
// gen length of the largest sample
|
||||||
sampleBuffer.size = _sampleStream.readUint32LE();
|
sampleBuffer.size = _sampleStream.readUint32LE();
|
||||||
if (_sampleStream.ioFailed())
|
if (_sampleStream.ioFailed())
|
||||||
error("File %s is corrupt", SAMPLE_FILE);
|
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundManager::closeSampleStream(void) {
|
||||||
|
_sampleStream.close();
|
||||||
|
free(_sampleIndex);
|
||||||
|
_sampleIndex = 0;
|
||||||
|
_sampleIndexLen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -37,6 +37,11 @@
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
enum STYPE {FX, VOICE};
|
||||||
|
|
||||||
|
enum PlayPriority { PRIORITY_SCRIPT, PRIORITY_SPLAY1, PRIORITY_SPLAY2, PRIORITY_TALK };
|
||||||
|
|
||||||
|
enum SampleFlags {PS_COMPLETE = 0x01, PS_SUSTAIN = 0x02};
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*\
|
/*----------------------------------------------------------------------*\
|
||||||
|* Function Prototypes *|
|
|* Function Prototypes *|
|
||||||
|
@ -44,14 +49,39 @@ namespace Tinsel {
|
||||||
|
|
||||||
class SoundManager {
|
class SoundManager {
|
||||||
protected:
|
protected:
|
||||||
|
static const int kNumSFX = 3; // Number of SFX channels
|
||||||
|
enum {
|
||||||
|
kChannelTalk = 0,
|
||||||
|
kChannelTinsel1 = 0, // Always using this channel for DW1
|
||||||
|
kChannelSFX = 1
|
||||||
|
};
|
||||||
|
static const int kNumChannels = kChannelSFX + kNumSFX;
|
||||||
|
|
||||||
|
struct Channel {
|
||||||
|
// Sample handle
|
||||||
|
Audio::SoundHandle handle;
|
||||||
|
|
||||||
|
// Sample id
|
||||||
|
int sampleNum;
|
||||||
|
int subSample;
|
||||||
|
|
||||||
|
// Playing properties
|
||||||
|
bool looped;
|
||||||
|
int x, y;
|
||||||
|
int priority;
|
||||||
|
|
||||||
|
// Time properties
|
||||||
|
uint32 timeStarted;
|
||||||
|
uint32 timeDuration;
|
||||||
|
uint32 lastStart;
|
||||||
|
};
|
||||||
|
|
||||||
|
Channel _channels[kNumChannels];
|
||||||
|
|
||||||
//TinselEngine *_vm; // TODO: Enable this once global _vm var is gone
|
//TinselEngine *_vm; // TODO: Enable this once global _vm var is gone
|
||||||
|
|
||||||
/** Sample handle */
|
|
||||||
Audio::SoundHandle _handle;
|
|
||||||
|
|
||||||
/** Sample index buffer and number of entries */
|
/** Sample index buffer and number of entries */
|
||||||
int32 *_sampleIndex;
|
uint32 *_sampleIndex;
|
||||||
|
|
||||||
/** Number of entries in the sample index */
|
/** Number of entries in the sample index */
|
||||||
long _sampleIndexLen;
|
long _sampleIndexLen;
|
||||||
|
@ -59,19 +89,29 @@ protected:
|
||||||
/** file stream for sample file */
|
/** file stream for sample file */
|
||||||
Common::File _sampleStream;
|
Common::File _sampleStream;
|
||||||
|
|
||||||
|
bool offscreenChecks(int x, int &y);
|
||||||
|
int8 getPan(int x);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SoundManager(TinselEngine *vm);
|
SoundManager(TinselEngine *vm);
|
||||||
~SoundManager();
|
~SoundManager();
|
||||||
|
|
||||||
bool playSample(int id, Audio::Mixer::SoundType type, Audio::SoundHandle *handle = 0);
|
bool playSample(int id, Audio::Mixer::SoundType type, Audio::SoundHandle *handle = 0);
|
||||||
|
bool playSample(int id, int sub, bool bLooped, int x, int y, int priority,
|
||||||
|
Audio::Mixer::SoundType type, Audio::SoundHandle *handle = 0);
|
||||||
|
|
||||||
void stopAllSamples(void); // Stops any currently playing sample
|
void stopAllSamples(void); // Stops any currently playing sample
|
||||||
|
void stopSpecSample(int id, int sub = 0); // Stops a specific sample
|
||||||
|
|
||||||
|
void setSFXVolumes(uint8 volume);
|
||||||
|
|
||||||
bool sampleExists(int id);
|
bool sampleExists(int id);
|
||||||
bool sampleIsPlaying(void);
|
bool sampleIsPlaying(int id = -1);
|
||||||
|
|
||||||
// TODO: Internal method, make this protected?
|
// TODO: Internal method, make this protected?
|
||||||
void openSampleFiles(void);
|
void openSampleFiles(void);
|
||||||
|
void closeSampleStream(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -40,18 +40,39 @@ int newestString;
|
||||||
// buffer for resource strings
|
// buffer for resource strings
|
||||||
static uint8 *textBuffer = 0;
|
static uint8 *textBuffer = 0;
|
||||||
|
|
||||||
// language resource string filenames
|
static struct {
|
||||||
static const char *languageFiles[] = {
|
bool bPresent;
|
||||||
"english.txt",
|
const char *szStem;
|
||||||
"french.txt",
|
SCNHANDLE hDescription;
|
||||||
"german.txt",
|
SCNHANDLE hFlagFilm;
|
||||||
"italian.txt",
|
|
||||||
"spanish.txt"
|
} languages[NUM_LANGUAGES] = {
|
||||||
|
|
||||||
|
{ false, "English", 0, 0 },
|
||||||
|
{ false, "French", 0, 0 },
|
||||||
|
{ false, "German", 0, 0 },
|
||||||
|
{ false, "Italian", 0, 0 },
|
||||||
|
{ false, "Spanish", 0, 0 },
|
||||||
|
{ false, "Hebrew", 0, 0 },
|
||||||
|
{ false, "Magyar", 0, 0 },
|
||||||
|
{ false, "Japanese",0, 0 },
|
||||||
|
{ false, "US", 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Set if we're handling 2-byte characters.
|
// Set if we're handling 2-byte characters.
|
||||||
bool bMultiByte = false;
|
bool bMultiByte = false;
|
||||||
|
|
||||||
|
LANGUAGE textLanguage, sampleLanguage = TXT_ENGLISH;
|
||||||
|
|
||||||
|
//----------------- LOCAL DEFINES ----------------------------
|
||||||
|
|
||||||
|
#define languageExtension ".txt"
|
||||||
|
#define indexExtension ".idx"
|
||||||
|
#define sampleExtension ".smp"
|
||||||
|
|
||||||
|
//----------------- FUNCTIONS --------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to load a resource file for a different language
|
* Called to load a resource file for a different language
|
||||||
* @param newLang The new language
|
* @param newLang The new language
|
||||||
|
@ -60,6 +81,9 @@ void ChangeLanguage(LANGUAGE newLang) {
|
||||||
Common::File f;
|
Common::File f;
|
||||||
uint32 textLen = 0; // length of buffer
|
uint32 textLen = 0; // length of buffer
|
||||||
|
|
||||||
|
textLanguage = newLang;
|
||||||
|
sampleLanguage = newLang;
|
||||||
|
|
||||||
if (textBuffer) {
|
if (textBuffer) {
|
||||||
// free the previous buffer
|
// free the previous buffer
|
||||||
free(textBuffer);
|
free(textBuffer);
|
||||||
|
@ -69,9 +93,9 @@ void ChangeLanguage(LANGUAGE newLang) {
|
||||||
// Try and open the specified language file. If it fails, and the language
|
// Try and open the specified language file. If it fails, and the language
|
||||||
// isn't English, try falling back on opening 'english.txt' - some foreign
|
// isn't English, try falling back on opening 'english.txt' - some foreign
|
||||||
// language versions reused it rather than their proper filename
|
// language versions reused it rather than their proper filename
|
||||||
if (!f.open(languageFiles[newLang])) {
|
if (!f.open(_vm->getTextFile(newLang))) {
|
||||||
if ((newLang == TXT_ENGLISH) || !f.open(languageFiles[TXT_ENGLISH]))
|
if ((newLang == TXT_ENGLISH) || !f.open(_vm->getTextFile(TXT_ENGLISH)))
|
||||||
error("Cannot find file %s", languageFiles[newLang]);
|
error(CANNOT_FIND_FILE, _vm->getTextFile(newLang));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the file is compressed or not - for compressed files the
|
// Check whether the file is compressed or not - for compressed files the
|
||||||
|
@ -79,7 +103,7 @@ void ChangeLanguage(LANGUAGE newLang) {
|
||||||
// identifier
|
// identifier
|
||||||
textLen = f.readUint32LE();
|
textLen = f.readUint32LE();
|
||||||
if (f.ioFailed())
|
if (f.ioFailed())
|
||||||
error("File %s is corrupt", languageFiles[newLang]);
|
error(FILE_IS_CORRUPT, _vm->getTextFile(newLang));
|
||||||
|
|
||||||
if (textLen == CHUNK_STRING || textLen == CHUNK_MBSTRING) {
|
if (textLen == CHUNK_STRING || textLen == CHUNK_MBSTRING) {
|
||||||
// the file is uncompressed
|
// the file is uncompressed
|
||||||
|
@ -101,7 +125,7 @@ void ChangeLanguage(LANGUAGE newLang) {
|
||||||
// load data
|
// load data
|
||||||
if (f.read(textBuffer, textLen) != textLen)
|
if (f.read(textBuffer, textLen) != textLen)
|
||||||
// file must be corrupt if we get to here
|
// file must be corrupt if we get to here
|
||||||
error("File %s is corrupt", languageFiles[newLang]);
|
error(FILE_IS_CORRUPT, _vm->getTextFile(newLang));
|
||||||
|
|
||||||
// close the file
|
// close the file
|
||||||
f.close();
|
f.close();
|
||||||
|
@ -111,19 +135,11 @@ void ChangeLanguage(LANGUAGE newLang) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a string resource identified by id.
|
* FindStringBase
|
||||||
* @param id identifier of string to be loaded
|
|
||||||
* @param pBuffer points to buffer that receives the string
|
|
||||||
* @param bufferMax maximum number of chars to be copied to the buffer
|
|
||||||
*/
|
*/
|
||||||
int LoadStringRes(int id, char *pBuffer, int bufferMax) {
|
static byte *FindStringBase(int id) {
|
||||||
#ifdef DEBUG
|
|
||||||
// For diagnostics
|
|
||||||
newestString = id;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// base of string resource table
|
// base of string resource table
|
||||||
uint8 *pText = textBuffer;
|
byte *pText = textBuffer;
|
||||||
|
|
||||||
// index into text resource file
|
// index into text resource file
|
||||||
uint32 index = 0;
|
uint32 index = 0;
|
||||||
|
@ -134,20 +150,14 @@ int LoadStringRes(int id, char *pBuffer, int bufferMax) {
|
||||||
// number of strings to skip when in the correct chunk
|
// number of strings to skip when in the correct chunk
|
||||||
int strSkip = id % STRINGS_PER_CHUNK;
|
int strSkip = id % STRINGS_PER_CHUNK;
|
||||||
|
|
||||||
// length of string
|
|
||||||
int len;
|
|
||||||
|
|
||||||
// skip to the correct chunk
|
// skip to the correct chunk
|
||||||
while (chunkSkip-- != 0) {
|
while (chunkSkip-- != 0) {
|
||||||
// make sure chunk id is correct
|
// make sure chunk id is correct
|
||||||
assert(READ_LE_UINT32(pText + index) == CHUNK_STRING || READ_LE_UINT32(pText + index) == CHUNK_MBSTRING);
|
assert(READ_LE_UINT32(pText + index) == CHUNK_STRING || READ_LE_UINT32(pText + index) == CHUNK_MBSTRING);
|
||||||
|
|
||||||
if (READ_LE_UINT32(pText + index + sizeof(uint32)) == 0) {
|
if (READ_LE_UINT32(pText + index + sizeof(uint32)) == 0) {
|
||||||
// TEMPORARY DIRTY BODGE
|
|
||||||
strcpy(pBuffer, "!! HIGH STRING !!");
|
|
||||||
|
|
||||||
// string does not exist
|
// string does not exist
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get index to next chunk
|
// get index to next chunk
|
||||||
|
@ -163,17 +173,114 @@ int LoadStringRes(int id, char *pBuffer, int bufferMax) {
|
||||||
// skip to the correct string
|
// skip to the correct string
|
||||||
while (strSkip-- != 0) {
|
while (strSkip-- != 0) {
|
||||||
// skip to next string
|
// skip to next string
|
||||||
|
|
||||||
|
if (!TinselV2 || ((*pText & 0x80) == 0)) {
|
||||||
|
// Tinsel 1, or string of length < 128
|
||||||
|
pText += *pText + 1;
|
||||||
|
} else if (*pText == 0x80) {
|
||||||
|
// string of length 128 - 255
|
||||||
|
pText++; // skip control byte
|
||||||
|
pText += *pText + 1;
|
||||||
|
} else if (*pText == 0x90) {
|
||||||
|
// string of length 256 - 511
|
||||||
|
pText++; // skip control byte
|
||||||
|
pText += *pText + 1 + 256;
|
||||||
|
} else { // multiple string
|
||||||
|
int subCount;
|
||||||
|
|
||||||
|
subCount = *pText & ~0x80;
|
||||||
|
pText++; // skip control byte
|
||||||
|
|
||||||
|
// skip prior sub-strings
|
||||||
|
while (subCount--) {
|
||||||
|
// skip control byte, if there is one
|
||||||
|
if (*pText == 0x80) {
|
||||||
|
pText++;
|
||||||
|
pText += *pText + 1;
|
||||||
|
} else if (*pText == 0x90) {
|
||||||
|
pText++;
|
||||||
|
pText += *pText + 1 + 256;
|
||||||
|
} else
|
||||||
pText += *pText + 1;
|
pText += *pText + 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pText;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a string resource identified by id.
|
||||||
|
* @param id identifier of string to be loaded
|
||||||
|
* @param pBuffer points to buffer that receives the string
|
||||||
|
* @param bufferMax maximum number of chars to be copied to the buffer
|
||||||
|
*/
|
||||||
|
int LoadStringResource(int id, int sub, char *pBuffer, int bufferMax) {
|
||||||
|
int len; // length of string
|
||||||
|
|
||||||
|
byte *pText = FindStringBase(id);
|
||||||
|
|
||||||
|
if (pText == NULL) {
|
||||||
|
strcpy(pBuffer, "!! HIGH STRING !!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TinselV2 || ((*pText & 0x80) == 0)) {
|
||||||
|
// get length of string
|
||||||
|
len = *pText;
|
||||||
|
} else if (*pText == 0x80) {
|
||||||
|
// string of length 128 - 255
|
||||||
|
pText++; // skip control byte
|
||||||
|
|
||||||
// get length of string
|
// get length of string
|
||||||
len = *pText;
|
len = *pText;
|
||||||
|
} else if (*pText == 0x90) {
|
||||||
|
// string of length 128 - 255
|
||||||
|
pText++; // skip control byte
|
||||||
|
|
||||||
if (len) {
|
// get length of string
|
||||||
|
len = *pText + 256;
|
||||||
|
} else {
|
||||||
|
// multiple string
|
||||||
|
pText++; // skip control byte
|
||||||
|
|
||||||
|
// skip prior sub-strings
|
||||||
|
while (sub--) {
|
||||||
|
// skip control byte, if there is one
|
||||||
|
if (*pText == 0x80) {
|
||||||
|
pText++;
|
||||||
|
pText += *pText + 1;
|
||||||
|
} else if (*pText == 0x90) {
|
||||||
|
pText++;
|
||||||
|
pText += *pText + 1 + 256;
|
||||||
|
} else
|
||||||
|
pText += *pText + 1;
|
||||||
|
}
|
||||||
|
// skip control byte, if there is one
|
||||||
|
if (*pText == 0x80) {
|
||||||
|
pText++;
|
||||||
|
|
||||||
|
// get length of string
|
||||||
|
len = *pText;
|
||||||
|
} else if (*pText == 0x90) {
|
||||||
|
pText++;
|
||||||
|
|
||||||
|
// get length of string
|
||||||
|
len = *pText + 256;
|
||||||
|
} else {
|
||||||
|
// get length of string
|
||||||
|
len = *pText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
// the string exists
|
// the string exists
|
||||||
|
|
||||||
// copy the string to the buffer
|
// copy the string to the buffer
|
||||||
if (len < bufferMax) {
|
if (len < bufferMax)
|
||||||
|
{
|
||||||
memcpy(pBuffer, pText + 1, len);
|
memcpy(pBuffer, pText + 1, len);
|
||||||
|
|
||||||
// null terminate
|
// null terminate
|
||||||
|
@ -199,6 +306,42 @@ int LoadStringRes(int id, char *pBuffer, int bufferMax) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LoadStringRes(int id, char *pBuffer, int bufferMax) {
|
||||||
|
return LoadStringResource(id, 0, pBuffer, bufferMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a string resource identified by id
|
||||||
|
* @param id identifier of string to be loaded
|
||||||
|
* @param sub sub-string number
|
||||||
|
* @param pBuffer points to buffer that receives the string
|
||||||
|
* @param bufferMax maximum number of chars to be copied to the buffer
|
||||||
|
*/
|
||||||
|
int LoadSubString(int id, int sub, char *pBuffer, int bufferMax) {
|
||||||
|
return LoadStringResource(id, sub, pBuffer, bufferMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SubStringCount
|
||||||
|
* @param id Identifier of string to be tested
|
||||||
|
*/
|
||||||
|
int SubStringCount(int id) {
|
||||||
|
byte *pText;
|
||||||
|
|
||||||
|
pText = FindStringBase(id);
|
||||||
|
|
||||||
|
if (pText == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((*pText & 0x80) == 0 || *pText == 0x80 || *pText == 0x90) {
|
||||||
|
// string of length < 128 or string of length 128 - 255
|
||||||
|
// or of length 256 - 511
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
return (*pText & ~0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FreeTextBuffer() {
|
void FreeTextBuffer() {
|
||||||
if (textBuffer) {
|
if (textBuffer) {
|
||||||
free(textBuffer);
|
free(textBuffer);
|
||||||
|
@ -206,4 +349,81 @@ void FreeTextBuffer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from TINLIB.C from DeclareLanguage().
|
||||||
|
*/
|
||||||
|
|
||||||
|
void LanguageFacts(int language, SCNHANDLE hDescription, SCNHANDLE hFlagFilm) {
|
||||||
|
assert(language >= 0 && language < NUM_LANGUAGES);
|
||||||
|
|
||||||
|
languages[language].hDescription = hDescription;
|
||||||
|
languages[language].hFlagFilm = hFlagFilm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current subtitles language
|
||||||
|
*/
|
||||||
|
LANGUAGE TextLanguage(void) {
|
||||||
|
return textLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current voice language
|
||||||
|
*/
|
||||||
|
LANGUAGE SampleLanguage(void) {
|
||||||
|
return sampleLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NumberOfLanguages(void) {
|
||||||
|
int i, count;
|
||||||
|
|
||||||
|
for (i = 0, count = 0; i < NUM_LANGUAGES; i++) {
|
||||||
|
if (languages[i].bPresent)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
LANGUAGE NextLanguage(LANGUAGE thisOne) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = thisOne+1; i < NUM_LANGUAGES; i++) {
|
||||||
|
if (languages[i].bPresent)
|
||||||
|
return (LANGUAGE)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < thisOne; i++) {
|
||||||
|
if (languages[i].bPresent)
|
||||||
|
return (LANGUAGE)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No others!
|
||||||
|
return thisOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
LANGUAGE PrevLanguage(LANGUAGE thisOne) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = thisOne-1; i >= 0; i--) {
|
||||||
|
if (languages[i].bPresent)
|
||||||
|
return (LANGUAGE)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = NUM_LANGUAGES-1; i > thisOne; i--) {
|
||||||
|
if (languages[i].bPresent)
|
||||||
|
return (LANGUAGE)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No others!
|
||||||
|
return thisOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCNHANDLE LanguageDesc(LANGUAGE thisOne) {
|
||||||
|
return languages[thisOne].hDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCNHANDLE LanguageFlag(LANGUAGE thisOne) {
|
||||||
|
return languages[thisOne].hFlagFilm;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
|
@ -58,11 +58,44 @@ void ChangeLanguage(LANGUAGE newLang);
|
||||||
*/
|
*/
|
||||||
int LoadStringRes(int id, char *pBuffer, int bufferMax);
|
int LoadStringRes(int id, char *pBuffer, int bufferMax);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a string resource identified by id
|
||||||
|
* @param id identifier of string to be loaded
|
||||||
|
* @param sub sub-string number
|
||||||
|
* @param pBuffer points to buffer that receives the string
|
||||||
|
* @param bufferMax maximum number of chars to be copied to the buffer
|
||||||
|
*/
|
||||||
|
int LoadSubString(int id, int sub, char *pBuffer, int bufferMax);
|
||||||
|
|
||||||
|
int SubStringCount(int id); // identifier of string to be tested
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees the text buffer allocated from ChangeLanguage()
|
* Frees the text buffer allocated from ChangeLanguage()
|
||||||
*/
|
*/
|
||||||
void FreeTextBuffer();
|
void FreeTextBuffer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from TINLIB.C from DeclareLanguage().
|
||||||
|
*/
|
||||||
|
|
||||||
|
void LanguageFacts(int language, SCNHANDLE hDescription, SCNHANDLE hFlagFilm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current subtitles language
|
||||||
|
*/
|
||||||
|
LANGUAGE TextLanguage(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current voice language
|
||||||
|
*/
|
||||||
|
LANGUAGE SampleLanguage(void);
|
||||||
|
|
||||||
|
int NumberOfLanguages(void);
|
||||||
|
LANGUAGE NextLanguage(LANGUAGE thisOne);
|
||||||
|
LANGUAGE PrevLanguage(LANGUAGE thisOne);
|
||||||
|
SCNHANDLE LanguageDesc(LANGUAGE thisOne);
|
||||||
|
SCNHANDLE LanguageFlag(LANGUAGE thisOne);
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
218
engines/tinsel/sysvar.cpp
Normal file
218
engines/tinsel/sysvar.cpp
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* System variable handling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tinsel/dw.h"
|
||||||
|
#include "tinsel/graphics.h"
|
||||||
|
#include "tinsel/dialogs.h"
|
||||||
|
#include "tinsel/strres.h"
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
|
namespace Tinsel {
|
||||||
|
|
||||||
|
// Return for SYS_Platform
|
||||||
|
typedef enum { DOS_PC, WIN_PC, APPLE_MAC, SONY_PSX, SEGA_SATURN } platform;
|
||||||
|
|
||||||
|
//----------------- GLOBAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
|
// To prevent assembler from needing to call SysVar()
|
||||||
|
uint8 ghostColour;
|
||||||
|
|
||||||
|
extern int NewestSavedGame(void);
|
||||||
|
|
||||||
|
//----------------- LOCAL GLOBAL DATA --------------------
|
||||||
|
|
||||||
|
static int systemVars[SV_TOPVALID] = {
|
||||||
|
|
||||||
|
INV_1, // Default inventory
|
||||||
|
|
||||||
|
10, // Y-offset of Conversation(TOP)
|
||||||
|
320, // Y-offset of Conversation(BOT)
|
||||||
|
15, // Minimum distance from side
|
||||||
|
10, // Minimum distance from top
|
||||||
|
115, // Distance above actor
|
||||||
|
10, // Distance below actor
|
||||||
|
|
||||||
|
0, // Current language **READ ONLY**
|
||||||
|
0, // Sample language **READ ONLY**
|
||||||
|
0, // Current state **READ ONLY**
|
||||||
|
0, // Saved Game Exists **READ ONLY**
|
||||||
|
|
||||||
|
true, // Should Conversation() wait for scroll? [TRUE]
|
||||||
|
true, // Should Talk()/Say() wait for scroll? [TRUE]
|
||||||
|
|
||||||
|
true, // Enable PointTag()
|
||||||
|
true, // Enable cursor with PrintCursor()
|
||||||
|
|
||||||
|
100, // SV_SCROLL_XTRIGGER
|
||||||
|
0, // SV_SCROLL_XDISTANCE
|
||||||
|
16, // SV_SCROLL_XSPEED
|
||||||
|
40, // SV_SCROLL_YTRIGGERTOP
|
||||||
|
40, // SV_SCROLL_YTRIGGERBOT
|
||||||
|
0, // SV_SCROLL_YDISTANCE
|
||||||
|
16, // SV_SCROLL_YSPEED
|
||||||
|
|
||||||
|
2, // Speech Delay
|
||||||
|
2, // Music dim factor
|
||||||
|
|
||||||
|
0, // if set, default actor's text colour gets poked in here
|
||||||
|
|
||||||
|
0, // user 1
|
||||||
|
0, // user 2
|
||||||
|
0, // user 3
|
||||||
|
0, // user 4
|
||||||
|
0, // user 5
|
||||||
|
0, // user 6
|
||||||
|
|
||||||
|
0, // SYS_MinimumXoffset
|
||||||
|
0, // SYS_MaximumXoffset
|
||||||
|
0, // SYS_MinimumYoffset
|
||||||
|
0, // SYS_MaximumYoffset
|
||||||
|
|
||||||
|
0, // SYS_DefaultFxDimFactor
|
||||||
|
0, // SYS_SceneFxDimFactor
|
||||||
|
|
||||||
|
0x606060, // SYS_HighlightRGB
|
||||||
|
WIN_PC, // SYS_Platform,
|
||||||
|
0, // SYS_Debug
|
||||||
|
|
||||||
|
0, // ISV_DIVERT_ACTOR
|
||||||
|
false, // ISV_NO_BLOCKING
|
||||||
|
|
||||||
|
0, // ISV_GHOST_ACTOR
|
||||||
|
0, // ISV_GHOST_BASE
|
||||||
|
0 // ISV_GHOST_COLOUR
|
||||||
|
};
|
||||||
|
|
||||||
|
static SCNHANDLE systemStrings[SS_MAX_VALID];
|
||||||
|
|
||||||
|
//static bool bFlagNoBlocking = false;
|
||||||
|
|
||||||
|
//----------------- FUNCTIONS --------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the system variable list
|
||||||
|
*/
|
||||||
|
|
||||||
|
void InitSysVars() {
|
||||||
|
systemVars[SV_SCROLL_XDISTANCE] = SCREEN_WIDTH / 2;
|
||||||
|
systemVars[SV_SCROLL_YDISTANCE] = SCREEN_BOX_HEIGHT1 / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SetSysVar
|
||||||
|
*/
|
||||||
|
|
||||||
|
void SetSysVar(int varId, int newValue) {
|
||||||
|
if (varId < 0 || varId >= SV_TOPVALID)
|
||||||
|
error("SetSystemVar(): out of range identifier");
|
||||||
|
|
||||||
|
switch (varId) {
|
||||||
|
case SV_LANGUAGE:
|
||||||
|
case SV_SAMPLE_LANGUAGE:
|
||||||
|
case SV_SUBTITLES:
|
||||||
|
case SV_SAVED_GAME_EXISTS:
|
||||||
|
case SYS_Platform:
|
||||||
|
case SYS_Debug:
|
||||||
|
error("SetSystemVar(): read only identifier");
|
||||||
|
|
||||||
|
default:
|
||||||
|
systemVars[varId] = newValue;
|
||||||
|
|
||||||
|
if (varId == ISV_GHOST_COLOUR) {
|
||||||
|
ghostColour = (uint8)newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SysVar(int varId) {
|
||||||
|
if (varId < 0 || varId >= SV_TOPVALID)
|
||||||
|
error("SystemVar(): out of range identifier");
|
||||||
|
|
||||||
|
switch (varId) {
|
||||||
|
case SV_LANGUAGE:
|
||||||
|
return TextLanguage();
|
||||||
|
|
||||||
|
case SV_SAMPLE_LANGUAGE:
|
||||||
|
return SampleLanguage();
|
||||||
|
|
||||||
|
case SV_SUBTITLES:
|
||||||
|
// FIXME: This isn't currently defined
|
||||||
|
return false;
|
||||||
|
//return bSubtitles;
|
||||||
|
|
||||||
|
case SV_SAVED_GAME_EXISTS:
|
||||||
|
return NewestSavedGame() != -1;
|
||||||
|
|
||||||
|
case SYS_Debug:
|
||||||
|
// FIXME: This isn't currently defined
|
||||||
|
return false;
|
||||||
|
//return bDebuggingAllowed;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return systemVars[varId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveSysVars(int *pSv) {
|
||||||
|
memcpy(pSv, systemVars, sizeof(systemVars));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RestoreSysVars(int *pSv) {
|
||||||
|
memcpy(systemVars, pSv, sizeof(systemVars));
|
||||||
|
|
||||||
|
ghostColour = (uint8)SysVar(ISV_GHOST_COLOUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSysString(int number, SCNHANDLE hString) {
|
||||||
|
assert(number >= 0 && number < SS_MAX_VALID);
|
||||||
|
|
||||||
|
systemStrings[number] = hString;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCNHANDLE SysString(int number) {
|
||||||
|
assert(number >= 0 && number < SS_MAX_VALID);
|
||||||
|
|
||||||
|
return systemStrings[number];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the no blocking flag. Note that for convenience, the systemVars arrray entry is
|
||||||
|
* used even for Tinsel 1, which used a separate boolean variable
|
||||||
|
*/
|
||||||
|
bool GetNoBlocking(void) {
|
||||||
|
return SysVar(ISV_NO_BLOCKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the no blocking flag. Note that for convenience, the systemVars arrray entry is
|
||||||
|
* used even for Tinsel 1, which used a separate boolean variable
|
||||||
|
*/
|
||||||
|
void SetNoBlocking(bool flag) {
|
||||||
|
SetSysVar(ISV_NO_BLOCKING, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Tinsel
|
149
engines/tinsel/sysvar.h
Normal file
149
engines/tinsel/sysvar.h
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* System variable handling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TINSEL_SYSVAR_H // prevent multiple includes
|
||||||
|
#define TINSEL_SYSVAR_H
|
||||||
|
|
||||||
|
namespace Tinsel {
|
||||||
|
|
||||||
|
typedef enum { SV_DEFAULT_INV,
|
||||||
|
|
||||||
|
SV_CONV_TOPY, // Y-offset of Conversation(TOP)
|
||||||
|
SV_CONV_BOTY, // Y-offset of Conversation(BOT)
|
||||||
|
SV_CONV_MINX, // Minimum distance from side
|
||||||
|
SV_CONV_MINY, // Minimum distance from top
|
||||||
|
SV_CONV_ABOVE_Y, // Distance above actor
|
||||||
|
SV_CONV_BELOW_Y, // Distance below actor
|
||||||
|
|
||||||
|
SV_LANGUAGE,
|
||||||
|
SV_SAMPLE_LANGUAGE,
|
||||||
|
SV_SUBTITLES,
|
||||||
|
SV_SAVED_GAME_EXISTS,
|
||||||
|
|
||||||
|
SV_CONVERSATIONWAITS, // } Do they wait for
|
||||||
|
SV_SPEECHWAITS, // } scrolls to complete?
|
||||||
|
|
||||||
|
SV_ENABLEPOINTTAG, // Enable PointTag()
|
||||||
|
SV_ENABLEPRINTCURSOR, // Enable cursor with PrintCursor()
|
||||||
|
|
||||||
|
SV_SCROLL_XTRIGGER, // }
|
||||||
|
SV_SCROLL_XDISTANCE, // }
|
||||||
|
SV_SCROLL_XSPEED, // } Scroll parameters!
|
||||||
|
SV_SCROLL_YTRIGGERTOP, // }
|
||||||
|
SV_SCROLL_YTRIGGERBOT, // }
|
||||||
|
SV_SCROLL_YDISTANCE, // }
|
||||||
|
SV_SCROLL_YSPEED, // }
|
||||||
|
|
||||||
|
SV_SPEECHDELAY, // Delay 'twixt text/animation and sample
|
||||||
|
SV_MUSICDIMFACTOR, // dimVolume = volume - volume/SV_MDF
|
||||||
|
|
||||||
|
SV_TAGCOLOUR, // if set, default actor's text colour gets poked in here
|
||||||
|
|
||||||
|
SV_USER1,
|
||||||
|
SV_USER2,
|
||||||
|
SV_USER3,
|
||||||
|
SV_USER4,
|
||||||
|
SV_USER5,
|
||||||
|
SV_USER6,
|
||||||
|
|
||||||
|
SV_MinimumXoffset,
|
||||||
|
SV_MaximumXoffset,
|
||||||
|
SV_MinimumYoffset,
|
||||||
|
SV_MaximumYoffset,
|
||||||
|
// dimVolume = volume - volume/DF
|
||||||
|
SYS_DefaultFxDimFactor, // To this at start of scene
|
||||||
|
SYS_SceneFxDimFactor, // Alter within scene
|
||||||
|
|
||||||
|
SYS_HighlightRGB,
|
||||||
|
SYS_Platform, // Hardware platform **READ ONLY**
|
||||||
|
SYS_Debug, // TRUE for debug build/'cheat'**READ ONLY**
|
||||||
|
|
||||||
|
ISV_DIVERT_ACTOR,
|
||||||
|
ISV_NO_BLOCKING,
|
||||||
|
ISV_GHOST_ACTOR,
|
||||||
|
ISV_GHOST_BASE,
|
||||||
|
ISV_GHOST_COLOUR,
|
||||||
|
|
||||||
|
|
||||||
|
SV_TOPVALID } SYSVARS;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
// Main Menu
|
||||||
|
SS_LOAD_OPTION, //
|
||||||
|
SS_SAVE_OPTION, //
|
||||||
|
SS_RESTART_OPTION, //
|
||||||
|
SS_SOUND_OPTION, //
|
||||||
|
SS_CONTROL_OPTION, //
|
||||||
|
SS_SUBTITLES_OPTION, //
|
||||||
|
SS_QUIT_OPTION, //
|
||||||
|
SS_RESUME_OPTION, //
|
||||||
|
|
||||||
|
SS_LOAD_HEADING,
|
||||||
|
SS_SAVE_HEADING,
|
||||||
|
SS_RESTART_HEADING,
|
||||||
|
SS_QUIT_HEADING,
|
||||||
|
|
||||||
|
SS_MVOL_SLIDER,
|
||||||
|
SS_SVOL_SLIDER,
|
||||||
|
SS_VVOL_SLIDER,
|
||||||
|
|
||||||
|
SS_DCLICK_SLIDER,
|
||||||
|
SS_DCLICK_TEST,
|
||||||
|
SS_SWAP_TOGGLE,
|
||||||
|
|
||||||
|
SS_TSPEED_SLIDER,
|
||||||
|
SS_STITLE_TOGGLE,
|
||||||
|
|
||||||
|
SS_HOPPER1, // Hopper scene menu heading
|
||||||
|
|
||||||
|
SS_SOUND_HEADING,
|
||||||
|
SS_CONTROLS_HEADING,
|
||||||
|
SS_LANGUAGE_SELECT,
|
||||||
|
|
||||||
|
SS_MAX_VALID
|
||||||
|
} BOLLOX;
|
||||||
|
|
||||||
|
void InitSysVars();
|
||||||
|
|
||||||
|
void SetSysVar(int varId, int newValue);
|
||||||
|
|
||||||
|
int SysVar(int varId);
|
||||||
|
|
||||||
|
void SaveSysVars(int *pSv);
|
||||||
|
void RestoreSysVars(int *pSv);
|
||||||
|
|
||||||
|
void SetSysString(int number, SCNHANDLE hString);
|
||||||
|
|
||||||
|
SCNHANDLE SysString(int number);
|
||||||
|
|
||||||
|
bool GetNoBlocking(void);
|
||||||
|
|
||||||
|
void SetNoBlocking(bool flag);
|
||||||
|
|
||||||
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
#endif
|
|
@ -105,9 +105,10 @@ int JustifyText(char *szStr, int xPos, const FONT *pFont, int mode) {
|
||||||
* @param yPos Y position of string
|
* @param yPos Y position of string
|
||||||
* @param hFont Which font to use
|
* @param hFont Which font to use
|
||||||
* @param mode Mode flags for the string
|
* @param mode Mode flags for the string
|
||||||
|
* @param sleepTime Sleep time between each character (if non-zero)
|
||||||
*/
|
*/
|
||||||
OBJECT *ObjectTextOut(OBJECT *pList, char *szStr, int colour, int xPos, int yPos,
|
OBJECT *ObjectTextOut(CORO_PARAM, OBJECT *pList, char *szStr, int colour,
|
||||||
SCNHANDLE hFont, int mode) {
|
int xPos, int yPos, SCNHANDLE hFont, int mode, int sleepTime) {
|
||||||
int xJustify; // x position of text after justification
|
int xJustify; // x position of text after justification
|
||||||
int yOffset; // offset to next line of text
|
int yOffset; // offset to next line of text
|
||||||
OBJECT *pFirst; // head of multi-object text list
|
OBJECT *pFirst; // head of multi-object text list
|
||||||
|
@ -130,7 +131,7 @@ OBJECT *ObjectTextOut(OBJECT *pList, char *szStr, int colour, int xPos, int yPos
|
||||||
pImg = (const IMAGE *)LockMem(FROM_LE_32(pFont->fontDef[(int)'W']));
|
pImg = (const IMAGE *)LockMem(FROM_LE_32(pFont->fontDef[(int)'W']));
|
||||||
|
|
||||||
// get height of capital W for offset to next line
|
// get height of capital W for offset to next line
|
||||||
yOffset = FROM_LE_16(pImg->imgHeight);
|
yOffset = FROM_LE_16(pImg->imgHeight) & ~C16_FLAG_MASK;
|
||||||
|
|
||||||
while (*szStr) {
|
while (*szStr) {
|
||||||
// x justify the text according to the mode flags
|
// x justify the text according to the mode flags
|
||||||
|
@ -175,7 +176,7 @@ OBJECT *ObjectTextOut(OBJECT *pList, char *szStr, int colour, int xPos, int yPos
|
||||||
// fill in character object
|
// fill in character object
|
||||||
pChar->hImg = hImg; // image def
|
pChar->hImg = hImg; // image def
|
||||||
pChar->width = FROM_LE_16(pImg->imgWidth); // width of chars bitmap
|
pChar->width = FROM_LE_16(pImg->imgWidth); // width of chars bitmap
|
||||||
pChar->height = FROM_LE_16(pImg->imgHeight); // height of chars bitmap
|
pChar->height = FROM_LE_16(pImg->imgHeight) & ~C16_FLAG_MASK; // height of chars bitmap
|
||||||
pChar->hBits = FROM_LE_32(pImg->hImgBits); // bitmap
|
pChar->hBits = FROM_LE_32(pImg->hImgBits); // bitmap
|
||||||
|
|
||||||
// check for absolute positioning
|
// check for absolute positioning
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#ifndef TINSEL_TEXT_H // prevent multiple includes
|
#ifndef TINSEL_TEXT_H // prevent multiple includes
|
||||||
#define TINSEL_TEXT_H
|
#define TINSEL_TEXT_H
|
||||||
|
|
||||||
|
#include "tinsel/coroutine.h"
|
||||||
#include "tinsel/object.h" // object manager defines
|
#include "tinsel/object.h" // object manager defines
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
@ -42,6 +43,10 @@ enum {
|
||||||
/** maximum number of characters in a font */
|
/** maximum number of characters in a font */
|
||||||
#define MAX_FONT_CHARS 256
|
#define MAX_FONT_CHARS 256
|
||||||
|
|
||||||
|
#define C16_240 0x4000
|
||||||
|
#define C16_224 0x8000
|
||||||
|
#define C16_MAP 0xC000
|
||||||
|
#define C16_FLAG_MASK (C16_240 | C16_224 | C16_MAP)
|
||||||
|
|
||||||
#include "common/pack-start.h" // START STRUCT PACKING
|
#include "common/pack-start.h" // START STRUCT PACKING
|
||||||
|
|
||||||
|
@ -80,14 +85,21 @@ struct TEXTOUT {
|
||||||
|* Text Function Prototypes *|
|
|* Text Function Prototypes *|
|
||||||
\*----------------------------------------------------------------------*/
|
\*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
OBJECT *ObjectTextOut( // output a string of text
|
/**
|
||||||
OBJECT *pList, // object list to add text to
|
* Main text outputting routine. If a object list is specified a
|
||||||
char *szStr, // string to output
|
* multi-object is created for the whole text and a pointer to the head
|
||||||
int colour, // colour for monochrome text
|
* of the list is returned.
|
||||||
int xPos, // x position of string
|
* @param pList object list to add text to
|
||||||
int yPos, // y position of string
|
* @param szStr string to output
|
||||||
SCNHANDLE hFont, // which font to use
|
* @param colour colour for monochrome text
|
||||||
int mode); // mode flags for the string
|
* @param xPos x position of string
|
||||||
|
* @param yPos y position of string
|
||||||
|
* @param hFont which font to use
|
||||||
|
* @param mode mode flags for the string
|
||||||
|
* @param sleepTime Sleep time between each character (if non-zero)
|
||||||
|
*/
|
||||||
|
OBJECT *ObjectTextOut(CORO_PARAM, OBJECT *pList, char *szStr, int colour,
|
||||||
|
int xPos, int yPos, SCNHANDLE hFont, int mode, int sleepTime = 0);
|
||||||
|
|
||||||
OBJECT *ObjectTextOutIndirect( // output a string of text
|
OBJECT *ObjectTextOutIndirect( // output a string of text
|
||||||
TEXTOUT *pText); // pointer to TextOut struct with all parameters
|
TEXTOUT *pText); // pointer to TextOut struct with all parameters
|
||||||
|
|
|
@ -151,7 +151,7 @@ void FettleTimers(void) {
|
||||||
/**
|
/**
|
||||||
* Start a timer up.
|
* Start a timer up.
|
||||||
*/
|
*/
|
||||||
void DwSetTimer(int num, int sval, bool up, bool frame) {
|
void StartTimer(int num, int sval, bool up, bool frame) {
|
||||||
TIMER *pt;
|
TIMER *pt;
|
||||||
|
|
||||||
assert(num); // zero is not allowed as a timer number
|
assert(num); // zero is not allowed as a timer number
|
||||||
|
|
|
@ -44,7 +44,7 @@ void syncTimerInfo(Serializer &s);
|
||||||
|
|
||||||
void FettleTimers(void);
|
void FettleTimers(void);
|
||||||
|
|
||||||
void DwSetTimer(int num, int sval, bool up, bool frame);
|
void StartTimer(int num, int sval, bool up, bool frame);
|
||||||
|
|
||||||
int Timer(int num);
|
int Timer(int num);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,13 +28,40 @@
|
||||||
#define TINSEL_TINLIB_H
|
#define TINSEL_TINLIB_H
|
||||||
|
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
|
#include "tinsel/object.h"
|
||||||
|
#include "tinsel/palette.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
|
enum EXTREME {
|
||||||
|
EX_USEXY, EX_BOTTOM, EX_BOTTOMLEFT,
|
||||||
|
EX_BOTTOMRIGHT, EX_LEFT, EX_RIGHT,
|
||||||
|
EX_TOP, EX_TOPLEFT, EX_TOPRIGHT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WHICH_VER {VER_GLITTER, VER_COMPILE};
|
||||||
|
#define VER_LEN 10
|
||||||
|
|
||||||
|
// Support functions
|
||||||
|
void TinGetVersion(WHICH_VER which, char *buffer, int length);
|
||||||
|
|
||||||
// Library functions in TINLIB.C
|
// Library functions in TINLIB.C
|
||||||
|
|
||||||
void control(int param);
|
void ActorBrightness(int actor, int brightness);
|
||||||
void stand(int actor, int x, int y, SCNHANDLE film);
|
void ActorPalette(int actor, int startColour, int length);
|
||||||
|
void Control(int param);
|
||||||
|
void HookScene(SCNHANDLE scene, int entrance, int transition);
|
||||||
|
void NewScene(CORO_PARAM, SCNHANDLE scene, int entrance, int transition);
|
||||||
|
void Offset(EXTREME extreme, int x, int y);
|
||||||
|
void RestoreScene(void);
|
||||||
|
void ResumeLastGame(void);
|
||||||
|
void SaveScene(CORO_PARAM);
|
||||||
|
void Stand(CORO_PARAM, int actor, int x, int y, SCNHANDLE film);
|
||||||
|
void SetTextPal(COLORREF col);
|
||||||
|
|
||||||
|
void KeepOnScreen(OBJECT *pText, int *pTextX, int *pTextY);
|
||||||
|
|
||||||
|
enum SPEECH_TYPE { IS_SAY, IS_SAYAT, IS_TALK, IS_TALKAT };
|
||||||
|
|
||||||
} // end of namespace Tinsel
|
} // end of namespace Tinsel
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common/endian.h"
|
#include "common/endian.h"
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/events.h"
|
#include "common/events.h"
|
||||||
#include "common/keyboard.h"
|
#include "common/keyboard.h"
|
||||||
#include "common/file.h"
|
#include "common/file.h"
|
||||||
|
@ -44,13 +45,15 @@
|
||||||
#include "tinsel/background.h"
|
#include "tinsel/background.h"
|
||||||
#include "tinsel/config.h"
|
#include "tinsel/config.h"
|
||||||
#include "tinsel/cursor.h"
|
#include "tinsel/cursor.h"
|
||||||
|
#include "tinsel/drives.h"
|
||||||
#include "tinsel/dw.h"
|
#include "tinsel/dw.h"
|
||||||
#include "tinsel/events.h"
|
#include "tinsel/events.h"
|
||||||
#include "tinsel/faders.h"
|
#include "tinsel/faders.h"
|
||||||
#include "tinsel/film.h"
|
#include "tinsel/film.h"
|
||||||
#include "tinsel/handle.h"
|
#include "tinsel/handle.h"
|
||||||
#include "tinsel/heapmem.h" // MemoryInit
|
#include "tinsel/heapmem.h" // MemoryInit
|
||||||
#include "tinsel/inventory.h"
|
#include "tinsel/dialogs.h"
|
||||||
|
#include "tinsel/mareels.h"
|
||||||
#include "tinsel/music.h"
|
#include "tinsel/music.h"
|
||||||
#include "tinsel/object.h"
|
#include "tinsel/object.h"
|
||||||
#include "tinsel/pid.h"
|
#include "tinsel/pid.h"
|
||||||
|
@ -60,6 +63,7 @@
|
||||||
#include "tinsel/serializer.h"
|
#include "tinsel/serializer.h"
|
||||||
#include "tinsel/sound.h"
|
#include "tinsel/sound.h"
|
||||||
#include "tinsel/strres.h"
|
#include "tinsel/strres.h"
|
||||||
|
#include "tinsel/sysvar.h"
|
||||||
#include "tinsel/timers.h"
|
#include "tinsel/timers.h"
|
||||||
#include "tinsel/tinsel.h"
|
#include "tinsel/tinsel.h"
|
||||||
|
|
||||||
|
@ -71,6 +75,14 @@ namespace Tinsel {
|
||||||
extern void SetDoFadeIn(bool tf);
|
extern void SetDoFadeIn(bool tf);
|
||||||
extern void DropBackground(void);
|
extern void DropBackground(void);
|
||||||
|
|
||||||
|
// In BMV.CPP
|
||||||
|
extern void FettleBMV(void);
|
||||||
|
extern bool MoviePlaying(void);
|
||||||
|
extern void CopyMovieToScreen(void);
|
||||||
|
extern void FinishBMV();
|
||||||
|
extern int32 MovieAudioLag();
|
||||||
|
extern uint32 NextMovieTime();
|
||||||
|
|
||||||
// In CURSOR.CPP
|
// In CURSOR.CPP
|
||||||
extern void CursorProcess(CORO_PARAM, const void *);
|
extern void CursorProcess(CORO_PARAM, const void *);
|
||||||
|
|
||||||
|
@ -79,7 +91,6 @@ extern void InventoryProcess(CORO_PARAM, const void *);
|
||||||
|
|
||||||
// In SCENE.CPP
|
// In SCENE.CPP
|
||||||
extern void PrimeBackground();
|
extern void PrimeBackground();
|
||||||
extern void NewScene(SCNHANDLE scene, int entry);
|
|
||||||
extern SCNHANDLE GetSceneHandle(void);
|
extern SCNHANDLE GetSceneHandle(void);
|
||||||
|
|
||||||
// In TIMER.CPP
|
// In TIMER.CPP
|
||||||
|
@ -94,6 +105,12 @@ void SetNewScene(SCNHANDLE scene, int entrance, int transition);
|
||||||
bool bRestart = false;
|
bool bRestart = false;
|
||||||
bool bHasRestarted = false;
|
bool bHasRestarted = false;
|
||||||
|
|
||||||
|
static bool bCuttingScene = false;
|
||||||
|
|
||||||
|
static bool bChangingForRestore = false;
|
||||||
|
|
||||||
|
static Common::Point clickPos;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool bFast; // set to make it go ludicrously fast
|
bool bFast; // set to make it go ludicrously fast
|
||||||
#endif
|
#endif
|
||||||
|
@ -110,11 +127,11 @@ static Scene NextScene = { 0, 0, 0 };
|
||||||
static Scene HookScene = { 0, 0, 0 };
|
static Scene HookScene = { 0, 0, 0 };
|
||||||
static Scene DelayedScene = { 0, 0, 0 };
|
static Scene DelayedScene = { 0, 0, 0 };
|
||||||
|
|
||||||
static bool bHookSuspend = false;
|
|
||||||
|
|
||||||
static PROCESS *pMouseProcess = 0;
|
static PROCESS *pMouseProcess = 0;
|
||||||
static PROCESS *pKeyboardProcess = 0;
|
static PROCESS *pKeyboardProcess = 0;
|
||||||
|
|
||||||
|
static SCNHANDLE hCdChangeScene;
|
||||||
|
|
||||||
// Stack of pending mouse button events
|
// Stack of pending mouse button events
|
||||||
Common::List<Common::EventType> mouseButtons;
|
Common::List<Common::EventType> mouseButtons;
|
||||||
|
|
||||||
|
@ -142,6 +159,7 @@ void KeyboardProcess(CORO_PARAM, const void *) {
|
||||||
// Get the next keyboard event off the stack
|
// Get the next keyboard event off the stack
|
||||||
Common::Event evt = *keypresses.begin();
|
Common::Event evt = *keypresses.begin();
|
||||||
keypresses.erase(keypresses.begin());
|
keypresses.erase(keypresses.begin());
|
||||||
|
const Common::Point mousePos = _vm->getMousePosition();
|
||||||
|
|
||||||
// Switch for special keys
|
// Switch for special keys
|
||||||
switch (evt.kbd.keycode) {
|
switch (evt.kbd.keycode) {
|
||||||
|
@ -150,21 +168,21 @@ void KeyboardProcess(CORO_PARAM, const void *) {
|
||||||
case Common::KEYCODE_RALT:
|
case Common::KEYCODE_RALT:
|
||||||
if (evt.type == Common::EVENT_KEYDOWN) {
|
if (evt.type == Common::EVENT_KEYDOWN) {
|
||||||
if (!bSwapButtons)
|
if (!bSwapButtons)
|
||||||
ProcessButEvent(BE_RDSTART);
|
ProcessButEvent(PLR_DRAG2_START);
|
||||||
else
|
else
|
||||||
ProcessButEvent(BE_LDSTART);
|
ProcessButEvent(PLR_DRAG1_START);
|
||||||
} else {
|
} else {
|
||||||
if (!bSwapButtons)
|
if (!bSwapButtons)
|
||||||
ProcessButEvent(BE_LDEND);
|
ProcessButEvent(PLR_DRAG1_END);
|
||||||
else
|
else
|
||||||
ProcessButEvent(BE_RDEND);
|
ProcessButEvent(PLR_DRAG2_END);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case Common::KEYCODE_LCTRL:
|
case Common::KEYCODE_LCTRL:
|
||||||
case Common::KEYCODE_RCTRL:
|
case Common::KEYCODE_RCTRL:
|
||||||
if (evt.type == Common::EVENT_KEYDOWN) {
|
if (evt.type == Common::EVENT_KEYDOWN) {
|
||||||
ProcessKeyEvent(LOOK_KEY);
|
ProcessKeyEvent(PLR_LOOK);
|
||||||
} else {
|
} else {
|
||||||
// Control key release
|
// Control key release
|
||||||
}
|
}
|
||||||
|
@ -186,42 +204,42 @@ void KeyboardProcess(CORO_PARAM, const void *) {
|
||||||
switch (evt.kbd.keycode) {
|
switch (evt.kbd.keycode) {
|
||||||
/*** SPACE = WALKTO ***/
|
/*** SPACE = WALKTO ***/
|
||||||
case Common::KEYCODE_SPACE:
|
case Common::KEYCODE_SPACE:
|
||||||
ProcessKeyEvent(WALKTO_KEY);
|
ProcessKeyEvent(PLR_WALKTO);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*** RETURN = ACTION ***/
|
/*** RETURN = ACTION ***/
|
||||||
case Common::KEYCODE_RETURN:
|
case Common::KEYCODE_RETURN:
|
||||||
case Common::KEYCODE_KP_ENTER:
|
case Common::KEYCODE_KP_ENTER:
|
||||||
ProcessKeyEvent(ACTION_KEY);
|
ProcessKeyEvent(PLR_ACTION);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*** l = LOOK ***/
|
/*** l = LOOK ***/
|
||||||
case Common::KEYCODE_l: // LOOK
|
case Common::KEYCODE_l: // LOOK
|
||||||
ProcessKeyEvent(LOOK_KEY);
|
ProcessKeyEvent(PLR_LOOK);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case Common::KEYCODE_ESCAPE:
|
case Common::KEYCODE_ESCAPE:
|
||||||
// WORKAROUND: Check if any of the starting logo screens are active, and if so
|
if (!TinselV2) {
|
||||||
// manually skip to the title screen, allowing them to be bypassed
|
// WORKAROUND: For Discworld 1, check if any of the starting logo screens are
|
||||||
{
|
// active, and if so manually skip to the title screen, allowing them to be bypassed
|
||||||
int sceneOffset = (_vm->getFeatures() & GF_SCNFILES) ? 1 : 0;
|
int sceneOffset = (_vm->getFeatures() & GF_SCNFILES) ? 1 : 0;
|
||||||
int sceneNumber = (GetSceneHandle() >> SCNHANDLE_SHIFT) - sceneOffset;
|
int sceneNumber = (GetSceneHandle() >> SCNHANDLE_SHIFT) - sceneOffset;
|
||||||
#if 0 // FIXME: Disabled this code for now, as it doesn't work as it should (see bug #2078922).
|
|
||||||
if ((g_language == TXT_GERMAN) &&
|
if ((g_language == TXT_GERMAN) &&
|
||||||
((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) {
|
((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) {
|
||||||
// Skip to title screen
|
// Skip to title screen
|
||||||
// It seems the German CD version uses scenes 25,26,27,17 for the intro,
|
// It seems the German CD version uses scenes 25,26,27,17 for the intro,
|
||||||
// instead of 13,14,15,11; also, the title screen is 11 instead of 10
|
// instead of 13,14,15,11; also, the title screen is 11 instead of 10
|
||||||
SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);
|
SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);
|
||||||
} else
|
} else if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) {
|
||||||
#endif
|
|
||||||
if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) {
|
|
||||||
// Skip to title screen
|
// Skip to title screen
|
||||||
SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);
|
SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);
|
||||||
} else {
|
} else {
|
||||||
// Not on an intro screen, so process the key normally
|
// Not on an intro screen, so process the key normally
|
||||||
ProcessKeyEvent(ESC_KEY);
|
ProcessKeyEvent(PLR_ESCAPE);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Running Discworld 2, so process the key normally
|
||||||
|
ProcessKeyEvent(PLR_ESCAPE);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -236,48 +254,79 @@ void KeyboardProcess(CORO_PARAM, const void *) {
|
||||||
|
|
||||||
case Common::KEYCODE_F1:
|
case Common::KEYCODE_F1:
|
||||||
// Options dialog
|
// Options dialog
|
||||||
ProcessKeyEvent(OPTION_KEY);
|
ProcessKeyEvent(PLR_MENU);
|
||||||
continue;
|
continue;
|
||||||
case Common::KEYCODE_F5:
|
case Common::KEYCODE_F5:
|
||||||
// Save game
|
// Save game
|
||||||
ProcessKeyEvent(SAVE_KEY);
|
ProcessKeyEvent(PLR_SAVE);
|
||||||
continue;
|
continue;
|
||||||
case Common::KEYCODE_F7:
|
case Common::KEYCODE_F7:
|
||||||
// Load game
|
// Load game
|
||||||
ProcessKeyEvent(LOAD_KEY);
|
ProcessKeyEvent(PLR_LOAD);
|
||||||
continue;
|
continue;
|
||||||
|
case Common::KEYCODE_m:
|
||||||
|
// Debug facility - scene hopper
|
||||||
|
if (TinselV2 && (evt.kbd.flags == Common::KBD_ALT))
|
||||||
|
ProcessKeyEvent(PLR_JUMP);
|
||||||
|
break;
|
||||||
case Common::KEYCODE_q:
|
case Common::KEYCODE_q:
|
||||||
if ((evt.kbd.flags == Common::KBD_CTRL) || (evt.kbd.flags == Common::KBD_ALT))
|
if ((evt.kbd.flags == Common::KBD_CTRL) || (evt.kbd.flags == Common::KBD_ALT))
|
||||||
ProcessKeyEvent(QUIT_KEY);
|
ProcessKeyEvent(PLR_QUIT);
|
||||||
continue;
|
continue;
|
||||||
case Common::KEYCODE_PAGEUP:
|
case Common::KEYCODE_PAGEUP:
|
||||||
case Common::KEYCODE_KP9:
|
case Common::KEYCODE_KP9:
|
||||||
ProcessKeyEvent(PGUP_KEY);
|
ProcessKeyEvent(PLR_PGUP);
|
||||||
continue;
|
continue;
|
||||||
case Common::KEYCODE_PAGEDOWN:
|
case Common::KEYCODE_PAGEDOWN:
|
||||||
case Common::KEYCODE_KP3:
|
case Common::KEYCODE_KP3:
|
||||||
ProcessKeyEvent(PGDN_KEY);
|
ProcessKeyEvent(PLR_PGDN);
|
||||||
continue;
|
continue;
|
||||||
case Common::KEYCODE_HOME:
|
case Common::KEYCODE_HOME:
|
||||||
case Common::KEYCODE_KP7:
|
case Common::KEYCODE_KP7:
|
||||||
ProcessKeyEvent(HOME_KEY);
|
ProcessKeyEvent(PLR_HOME);
|
||||||
continue;
|
continue;
|
||||||
case Common::KEYCODE_END:
|
case Common::KEYCODE_END:
|
||||||
case Common::KEYCODE_KP1:
|
case Common::KEYCODE_KP1:
|
||||||
ProcessKeyEvent(END_KEY);
|
ProcessKeyEvent(PLR_END);
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
ProcessKeyEvent(NOEVENT_KEY);
|
ProcessKeyEvent(PLR_NOEVENT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles launching a single click action result if the timeout for a double-click
|
||||||
|
* expires
|
||||||
|
*/
|
||||||
|
static void SingleLeftProcess(CORO_PARAM, const void *) {
|
||||||
|
CORO_BEGIN_CONTEXT;
|
||||||
|
uint32 endTicks;
|
||||||
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
|
// Work out when to wait until
|
||||||
|
_ctx->endTicks = DwGetCurrentTime() + (uint32)dclickSpeed;
|
||||||
|
|
||||||
|
// Timeout a double click (may not work once every 49 days!)
|
||||||
|
do {
|
||||||
|
CORO_SLEEP(1);
|
||||||
|
} while(DwGetCurrentTime() < _ctx->endTicks);
|
||||||
|
|
||||||
|
if (GetProvNotProcessed())
|
||||||
|
PlayerEvent(PLR_WALKTO, clickPos);
|
||||||
|
|
||||||
|
CORO_KILL_SELF();
|
||||||
|
CORO_END_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process to handle changes in the mouse buttons.
|
* Process to handle changes in the mouse buttons.
|
||||||
*/
|
*/
|
||||||
void MouseProcess(CORO_PARAM, const void *) {
|
static void MouseProcess(CORO_PARAM, const void *) {
|
||||||
// COROUTINE
|
// COROUTINE
|
||||||
CORO_BEGIN_CONTEXT;
|
CORO_BEGIN_CONTEXT;
|
||||||
bool lastLWasDouble;
|
bool lastLWasDouble;
|
||||||
|
@ -292,9 +341,6 @@ void MouseProcess(CORO_PARAM, const void *) {
|
||||||
_ctx->lastLeftClick = _ctx->lastRightClick = DwGetCurrentTime();
|
_ctx->lastLeftClick = _ctx->lastRightClick = DwGetCurrentTime();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// FIXME: I'm still keeping the ctrl/Alt handling in the ProcessKeyEvent method.
|
|
||||||
// Need to make sure that this works correctly
|
|
||||||
//DragKeys();
|
|
||||||
|
|
||||||
if (mouseButtons.empty()) {
|
if (mouseButtons.empty()) {
|
||||||
// allow scheduling
|
// allow scheduling
|
||||||
|
@ -306,23 +352,46 @@ void MouseProcess(CORO_PARAM, const void *) {
|
||||||
Common::EventType type = *mouseButtons.begin();
|
Common::EventType type = *mouseButtons.begin();
|
||||||
mouseButtons.erase(mouseButtons.begin());
|
mouseButtons.erase(mouseButtons.begin());
|
||||||
|
|
||||||
|
int xp, yp;
|
||||||
|
GetCursorXYNoWait(&xp, &yp, true);
|
||||||
|
const Common::Point mousePos(xp, yp);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Common::EVENT_LBUTTONDOWN:
|
case Common::EVENT_LBUTTONDOWN:
|
||||||
// left button press
|
// left button press
|
||||||
if (DwGetCurrentTime() - _ctx->lastLeftClick < (uint32)dclickSpeed) {
|
if (DwGetCurrentTime() - _ctx->lastLeftClick < (uint32)dclickSpeed) {
|
||||||
|
// Left button double-click
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// Kill off the button process and fire off the action command
|
||||||
|
g_scheduler->killMatchingProcess(PID_BTN_CLICK, -1);
|
||||||
|
PlayerEvent(PLR_ACTION, clickPos);
|
||||||
|
} else {
|
||||||
// signal left drag start
|
// signal left drag start
|
||||||
ProcessButEvent(BE_LDSTART);
|
ProcessButEvent(PLR_DRAG1_START);
|
||||||
|
|
||||||
// signal left double click event
|
// signal left double click event
|
||||||
ProcessButEvent(BE_DLEFT);
|
ProcessButEvent(PLR_DLEFT);
|
||||||
|
}
|
||||||
|
|
||||||
_ctx->lastLWasDouble = true;
|
_ctx->lastLWasDouble = true;
|
||||||
|
} else {
|
||||||
|
// Initial mouse down - either for a single click, or potentially
|
||||||
|
// the start of a double-click action
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
PlayerEvent(PLR_DRAG1_START, mousePos);
|
||||||
|
|
||||||
|
ProvNotProcessed();
|
||||||
|
PlayerEvent(PLR_PROV_WALKTO, mousePos);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// signal left drag start
|
// signal left drag start
|
||||||
ProcessButEvent(BE_LDSTART);
|
ProcessButEvent(PLR_DRAG1_START);
|
||||||
|
|
||||||
// signal left single click event
|
// signal left single click event
|
||||||
ProcessButEvent(BE_SLEFT);
|
ProcessButEvent(PLR_SLEFT);
|
||||||
|
}
|
||||||
|
|
||||||
_ctx->lastLWasDouble = false;
|
_ctx->lastLWasDouble = false;
|
||||||
}
|
}
|
||||||
|
@ -332,32 +401,53 @@ void MouseProcess(CORO_PARAM, const void *) {
|
||||||
// left button release
|
// left button release
|
||||||
|
|
||||||
// update click timer
|
// update click timer
|
||||||
if (_ctx->lastLWasDouble == false)
|
if (_ctx->lastLWasDouble == false) {
|
||||||
_ctx->lastLeftClick = DwGetCurrentTime();
|
_ctx->lastLeftClick = DwGetCurrentTime();
|
||||||
else
|
|
||||||
|
// If player control is enabled, start a process which, if it times out,
|
||||||
|
// will activate a single button click
|
||||||
|
if (TinselV2 && ControlIsOn()) {
|
||||||
|
clickPos = mousePos;
|
||||||
|
g_scheduler->createProcess(PID_BTN_CLICK, SingleLeftProcess, NULL, 0);
|
||||||
|
}
|
||||||
|
} else
|
||||||
_ctx->lastLeftClick -= dclickSpeed;
|
_ctx->lastLeftClick -= dclickSpeed;
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
// Signal left drag end
|
||||||
|
PlayerEvent(PLR_DRAG1_END, mousePos);
|
||||||
|
else
|
||||||
// signal left drag end
|
// signal left drag end
|
||||||
ProcessButEvent(BE_LDEND);
|
ProcessButEvent(PLR_DRAG1_END);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Common::EVENT_RBUTTONDOWN:
|
case Common::EVENT_RBUTTONDOWN:
|
||||||
// right button press
|
// right button press
|
||||||
|
|
||||||
if (DwGetCurrentTime() - _ctx->lastRightClick < (uint32)dclickSpeed) {
|
if (DwGetCurrentTime() - _ctx->lastRightClick < (uint32)dclickSpeed) {
|
||||||
|
// Right button double-click
|
||||||
|
if (TinselV2) {
|
||||||
|
PlayerEvent(PLR_NOEVENT, clickPos);
|
||||||
|
} else {
|
||||||
// signal right drag start
|
// signal right drag start
|
||||||
ProcessButEvent(BE_RDSTART);
|
ProcessButEvent(PLR_DRAG2_START);
|
||||||
|
|
||||||
// signal right double click event
|
// signal right double click event
|
||||||
ProcessButEvent(BE_DRIGHT);
|
ProcessButEvent(PLR_DRIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
_ctx->lastRWasDouble = true;
|
_ctx->lastRWasDouble = true;
|
||||||
|
} else {
|
||||||
|
if (TinselV2) {
|
||||||
|
PlayerEvent(PLR_DRAG2_START, mousePos);
|
||||||
|
PlayerEvent(PLR_LOOK, mousePos);
|
||||||
} else {
|
} else {
|
||||||
// signal right drag start
|
// signal right drag start
|
||||||
ProcessButEvent(BE_RDSTART);
|
ProcessButEvent(PLR_DRAG2_START);
|
||||||
|
|
||||||
// signal right single click event
|
// signal right single click event
|
||||||
ProcessButEvent(BE_SRIGHT);
|
ProcessButEvent(PLR_SRIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
_ctx->lastRWasDouble = false;
|
_ctx->lastRWasDouble = false;
|
||||||
}
|
}
|
||||||
|
@ -372,8 +462,12 @@ void MouseProcess(CORO_PARAM, const void *) {
|
||||||
else
|
else
|
||||||
_ctx->lastRightClick -= dclickSpeed;
|
_ctx->lastRightClick -= dclickSpeed;
|
||||||
|
|
||||||
|
if (TinselV2)
|
||||||
|
// Signal left drag end
|
||||||
|
PlayerEvent(PLR_DRAG2_END, mousePos);
|
||||||
|
else
|
||||||
// signal right drag end
|
// signal right drag end
|
||||||
ProcessButEvent(BE_RDEND);
|
ProcessButEvent(PLR_DRAG2_END);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -402,9 +496,24 @@ static void MasterScriptProcess(CORO_PARAM, const void *) {
|
||||||
/**
|
/**
|
||||||
* Store the facts pertaining to a scene change.
|
* Store the facts pertaining to a scene change.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SetNewScene(SCNHANDLE scene, int entrance, int transition) {
|
void SetNewScene(SCNHANDLE scene, int entrance, int transition) {
|
||||||
if (HookScene.scene == 0 || bHookSuspend) {
|
if (!bCuttingScene && TinselV2)
|
||||||
|
WrapScene();
|
||||||
|
|
||||||
|
// If CD change will be required, stick in the scene change scene
|
||||||
|
if (CdNumber(scene) != GetCurrentCD()) {
|
||||||
|
// This scene gets delayed
|
||||||
|
DelayedScene.scene = scene;
|
||||||
|
DelayedScene.entry = entrance;
|
||||||
|
DelayedScene.trans = transition;
|
||||||
|
|
||||||
|
NextScene.scene = hCdChangeScene;
|
||||||
|
NextScene.entry = CdNumber(scene) - '0';
|
||||||
|
NextScene.trans = TRANS_FADE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HookScene.scene == 0 || bCuttingScene) {
|
||||||
// This scene comes next
|
// This scene comes next
|
||||||
NextScene.scene = scene;
|
NextScene.scene = scene;
|
||||||
NextScene.entry = entrance;
|
NextScene.entry = entrance;
|
||||||
|
@ -424,6 +533,9 @@ void SetNewScene(SCNHANDLE scene, int entrance, int transition) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a scene as hooked
|
||||||
|
*/
|
||||||
void SetHookScene(SCNHANDLE scene, int entrance, int transition) {
|
void SetHookScene(SCNHANDLE scene, int entrance, int transition) {
|
||||||
assert(HookScene.scene == 0); // scene already hooked
|
assert(HookScene.scene == 0); // scene already hooked
|
||||||
|
|
||||||
|
@ -432,6 +544,9 @@ void SetHookScene(SCNHANDLE scene, int entrance, int transition) {
|
||||||
HookScene.trans = transition;
|
HookScene.trans = transition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooked scene is over, trigger a change to the delayed scene
|
||||||
|
*/
|
||||||
void UnHookScene(void) {
|
void UnHookScene(void) {
|
||||||
assert(DelayedScene.scene != 0); // no scene delayed
|
assert(DelayedScene.scene != 0); // no scene delayed
|
||||||
|
|
||||||
|
@ -444,11 +559,40 @@ void UnHookScene(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuspendHook(void) {
|
void SuspendHook(void) {
|
||||||
bHookSuspend = true;
|
bCuttingScene = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CdHasChanged(void) {
|
||||||
|
if (bChangingForRestore) {
|
||||||
|
bChangingForRestore = false;
|
||||||
|
RestoreGame(-2);
|
||||||
|
} else {
|
||||||
|
assert(DelayedScene.scene != 0);
|
||||||
|
|
||||||
|
WrapScene();
|
||||||
|
|
||||||
|
// The delayed scene can go now
|
||||||
|
NextScene.scene = DelayedScene.scene;
|
||||||
|
NextScene.entry = DelayedScene.entry;
|
||||||
|
NextScene.trans = DelayedScene.trans;
|
||||||
|
|
||||||
|
DelayedScene.scene = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCdChangeScene(SCNHANDLE hScene) {
|
||||||
|
hCdChangeScene = hScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDChangeForRestore(int cdNumber) {
|
||||||
|
NextScene.scene = hCdChangeScene;
|
||||||
|
NextScene.entry = cdNumber;
|
||||||
|
NextScene.trans = TRANS_FADE;
|
||||||
|
bChangingForRestore = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnSuspendHook(void) {
|
void UnSuspendHook(void) {
|
||||||
bHookSuspend = false;
|
bCuttingScene = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syncSCdata(Serializer &s) {
|
void syncSCdata(Serializer &s) {
|
||||||
|
@ -468,16 +612,23 @@ static void RestoredProcess(CORO_PARAM, const void *param) {
|
||||||
// COROUTINE
|
// COROUTINE
|
||||||
CORO_BEGIN_CONTEXT;
|
CORO_BEGIN_CONTEXT;
|
||||||
INT_CONTEXT *pic;
|
INT_CONTEXT *pic;
|
||||||
|
bool bConverse;
|
||||||
CORO_END_CONTEXT(_ctx);
|
CORO_END_CONTEXT(_ctx);
|
||||||
|
|
||||||
CORO_BEGIN_CODE(_ctx);
|
CORO_BEGIN_CODE(_ctx);
|
||||||
|
|
||||||
// get the stuff copied to process when it was created
|
// get the stuff copied to process when it was created
|
||||||
_ctx->pic = *((INT_CONTEXT **)param);
|
_ctx->pic = *((INT_CONTEXT * const *)param);
|
||||||
|
|
||||||
_ctx->pic = RestoreInterpretContext(_ctx->pic);
|
_ctx->pic = RestoreInterpretContext(_ctx->pic);
|
||||||
|
_ctx->bConverse = TinselV2 && (_ctx->pic->event == CONVERSE);
|
||||||
|
|
||||||
CORO_INVOKE_1(Interpret, _ctx->pic);
|
CORO_INVOKE_1(Interpret, _ctx->pic);
|
||||||
|
|
||||||
|
// Restore control after CallScene() from a conversation icon
|
||||||
|
if (_ctx->bConverse)
|
||||||
|
ControlOn();
|
||||||
|
|
||||||
CORO_END_CODE;
|
CORO_END_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,10 +651,17 @@ static int CountOut = 1; // == 1 for immediate start of first scene
|
||||||
* When the count expires, the screen will have faded. Ensure the scene |
|
* When the count expires, the screen will have faded. Ensure the scene |
|
||||||
* is loaded, clear the screen, and start the new scene.
|
* is loaded, clear the screen, and start the new scene.
|
||||||
*/
|
*/
|
||||||
void ChangeScene() {
|
bool ChangeScene(bool bReset) {
|
||||||
|
|
||||||
|
// Prevent attempt to fade-out when restarting game
|
||||||
|
if (bReset) {
|
||||||
|
CountOut = 1; // immediate start of first scene again
|
||||||
|
DelayedScene.scene = HookScene.scene = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsRestoringScene())
|
if (IsRestoringScene())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
if (NextScene.scene != 0) {
|
if (NextScene.scene != 0) {
|
||||||
if (!CountOut) {
|
if (!CountOut) {
|
||||||
|
@ -517,12 +675,15 @@ void ChangeScene() {
|
||||||
// Trigger pre-load and fade and start countdown
|
// Trigger pre-load and fade and start countdown
|
||||||
CountOut = COUNTOUT_COUNT;
|
CountOut = COUNTOUT_COUNT;
|
||||||
FadeOutFast(NULL);
|
FadeOutFast(NULL);
|
||||||
|
if (TinselV2)
|
||||||
|
_vm->_pcmMusic->startFadeOut(COUNTOUT_COUNT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (--CountOut == 0) {
|
} else if (--CountOut == 0) {
|
||||||
|
if (!TinselV2)
|
||||||
ClearScreen();
|
ClearScreen();
|
||||||
|
|
||||||
NewScene(NextScene.scene, NextScene.entry);
|
StartNewScene(NextScene.scene, NextScene.entry);
|
||||||
NextScene.scene = 0;
|
NextScene.scene = 0;
|
||||||
|
|
||||||
switch (NextScene.trans) {
|
switch (NextScene.trans) {
|
||||||
|
@ -535,20 +696,32 @@ void ChangeScene() {
|
||||||
SetDoFadeIn(true);
|
SetDoFadeIn(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
_vm->_pcmMusic->fadeOutIteration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CuttingScene
|
||||||
|
*/
|
||||||
|
void CuttingScene(bool bCutting) {
|
||||||
|
bCuttingScene = bCutting;
|
||||||
|
|
||||||
|
if (!bCutting)
|
||||||
|
WrapScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LoadBasicChunks
|
* LoadBasicChunks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void LoadBasicChunks(void) {
|
void LoadBasicChunks(void) {
|
||||||
byte *cptr;
|
byte *cptr;
|
||||||
int numObjects;
|
int numObjects;
|
||||||
|
|
||||||
// Allocate RAM for savescene data
|
// Allocate RAM for savescene data
|
||||||
InitialiseSs();
|
InitialiseSaveScenes();
|
||||||
|
|
||||||
// CHUNK_TOTAL_ACTORS seems to be missing in the released version, hard coding a value
|
// CHUNK_TOTAL_ACTORS seems to be missing in the released version, hard coding a value
|
||||||
// TODO: Would be nice to just change 511 to MAX_SAVED_ALIVES
|
// TODO: Would be nice to just change 511 to MAX_SAVED_ALIVES
|
||||||
|
@ -581,6 +754,23 @@ void LoadBasicChunks(void) {
|
||||||
cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_POLY);
|
cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_POLY);
|
||||||
if (cptr != NULL)
|
if (cptr != NULL)
|
||||||
MaxPolygons(*cptr);
|
MaxPolygons(*cptr);
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
// Global processes
|
||||||
|
cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_NUM_PROCESSES);
|
||||||
|
assert(cptr && (*cptr < 100));
|
||||||
|
int num = *cptr;
|
||||||
|
cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_PROCESSES);
|
||||||
|
assert(!num || cptr);
|
||||||
|
GlobalProcesses(num, cptr);
|
||||||
|
|
||||||
|
// CdPlay() stuff
|
||||||
|
cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_CDPLAY_HANDLE);
|
||||||
|
assert(cptr);
|
||||||
|
uint32 playHandle = READ_LE_UINT32(cptr);
|
||||||
|
assert(playHandle < 512);
|
||||||
|
SetCdPlayHandle(playHandle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------- TinselEngine --------------------
|
//----------------- TinselEngine --------------------
|
||||||
|
@ -602,10 +792,39 @@ static const GameSettings tinselSettings[] = {
|
||||||
{NULL, NULL, 0, 0, NULL}
|
{NULL, NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *TinselEngine::_sampleIndices[][3] = {
|
||||||
|
{ "english.idx", "english1.idx", "english2.idx" },
|
||||||
|
{ "french.idx", "french1.idx", "french2.idx" },
|
||||||
|
{ "german.idx", "german1.idx", "german2.idx" },
|
||||||
|
{ "italian.idx", "italian1.idx", "italian2.idx" },
|
||||||
|
{ "spanish.idx", "spanish1.idx", "spanish2.idx" },
|
||||||
|
};
|
||||||
|
const char *TinselEngine::_sampleFiles[][3] = {
|
||||||
|
{ "english.smp", "english1.smp", "english2.smp" },
|
||||||
|
{ "french.smp", "french1.smp", "french2.smp" },
|
||||||
|
{ "german.smp", "german1.smp", "german2.smp" },
|
||||||
|
{ "italian.smp", "italian1.smp", "italian2.smp" },
|
||||||
|
{ "spanish.smp", "spanish1.smp", "spanish2.smp" },
|
||||||
|
};
|
||||||
|
const char *TinselEngine::_textFiles[][3] = {
|
||||||
|
{ "english.txt", "english1.txt", "english2.txt" },
|
||||||
|
{ "french.txt", "french1.txt", "french2.txt" },
|
||||||
|
{ "german.txt", "german1.txt", "german2.txt" },
|
||||||
|
{ "italian.txt", "italian1.txt", "italian2.txt" },
|
||||||
|
{ "spanish.txt", "spanish1.txt", "spanish2.txt" }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) :
|
TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) :
|
||||||
Engine(syst), _gameDescription(gameDesc) {
|
Engine(syst), _gameDescription(gameDesc) {
|
||||||
_vm = this;
|
_vm = this;
|
||||||
|
|
||||||
|
// Register debug flags
|
||||||
|
Common::addSpecialDebugLevel(kTinselDebugAnimations, "animations", "Animations debugging");
|
||||||
|
Common::addSpecialDebugLevel(kTinselDebugActions, "actions", "Actions debugging");
|
||||||
|
Common::addSpecialDebugLevel(kTinselDebugSound, "sound", "Sound debugging");
|
||||||
|
Common::addSpecialDebugLevel(kTinselDebugMusic, "music", "Music debugging");
|
||||||
|
|
||||||
// Setup mixer
|
// Setup mixer
|
||||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
|
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
|
||||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
|
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
|
||||||
|
@ -629,9 +848,10 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
|
||||||
if (native_mt32)
|
if (native_mt32)
|
||||||
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
|
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
|
||||||
|
|
||||||
_music = new MusicPlayer(_driver);
|
_midiMusic = new MidiMusicPlayer(_driver);
|
||||||
//_music->setNativeMT32(native_mt32);
|
_pcmMusic = new PCMMusicPlayer();
|
||||||
//_music->setAdlib(adlib);
|
//_midiMusic->setNativeMT32(native_mt32);
|
||||||
|
//_midiMusic->setAdlib(adlib);
|
||||||
|
|
||||||
_musicVolume = ConfMan.getInt("music_volume");
|
_musicVolume = ConfMan.getInt("music_volume");
|
||||||
|
|
||||||
|
@ -644,25 +864,38 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
TinselEngine::~TinselEngine() {
|
TinselEngine::~TinselEngine() {
|
||||||
|
if (MoviePlaying())
|
||||||
|
FinishBMV();
|
||||||
|
|
||||||
delete _sound;
|
delete _sound;
|
||||||
delete _music;
|
delete _midiMusic;
|
||||||
|
delete _pcmMusic;
|
||||||
delete _console;
|
delete _console;
|
||||||
delete _driver;
|
delete _driver;
|
||||||
_screenSurface.free();
|
_screenSurface.free();
|
||||||
FreeSs();
|
FreeSaveScenes();
|
||||||
FreeTextBuffer();
|
FreeTextBuffer();
|
||||||
FreeHandleTable();
|
FreeHandleTable();
|
||||||
FreeActors();
|
FreeActors();
|
||||||
FreeObjectList();
|
FreeObjectList();
|
||||||
|
FreeGlobalProcesses();
|
||||||
FreeGlobals();
|
FreeGlobals();
|
||||||
delete _scheduler;
|
delete _scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Error TinselEngine::init() {
|
Common::Error TinselEngine::init() {
|
||||||
// Initialize backend
|
// Initialize backend
|
||||||
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, false);
|
if (getGameID() == GID_DW2) {
|
||||||
|
#ifndef DW2_EXACT_SIZE
|
||||||
_screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, 1);
|
initGraphics(640, 480, true);
|
||||||
|
#else
|
||||||
|
initGraphics(640, 432, true);
|
||||||
|
#endif
|
||||||
|
_screenSurface.create(640, 432, 1);
|
||||||
|
} else {
|
||||||
|
initGraphics(320, 200, false);
|
||||||
|
_screenSurface.create(320, 200, 1);
|
||||||
|
}
|
||||||
|
|
||||||
g_system->getEventManager()->registerRandomSource(_random, "tinsel");
|
g_system->getEventManager()->registerRandomSource(_random, "tinsel");
|
||||||
|
|
||||||
|
@ -670,6 +903,8 @@ Common::Error TinselEngine::init() {
|
||||||
|
|
||||||
_scheduler = new Scheduler();
|
_scheduler = new Scheduler();
|
||||||
|
|
||||||
|
InitSysVars();
|
||||||
|
|
||||||
// init memory manager
|
// init memory manager
|
||||||
MemoryInit();
|
MemoryInit();
|
||||||
|
|
||||||
|
@ -684,20 +919,19 @@ Common::Error TinselEngine::init() {
|
||||||
RebootCursor();
|
RebootCursor();
|
||||||
RebootDeadTags();
|
RebootDeadTags();
|
||||||
RebootMovers();
|
RebootMovers();
|
||||||
|
resetUserEventTime();
|
||||||
RebootTimers();
|
RebootTimers();
|
||||||
RebootScalingReels();
|
RebootScalingReels();
|
||||||
|
|
||||||
DelayedScene.scene = HookScene.scene = 0;
|
DelayedScene.scene = HookScene.scene = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Load in text strings
|
||||||
|
ChangeLanguage(g_language);
|
||||||
|
|
||||||
// Init palette and object managers, scheduler, keyboard and mouse
|
// Init palette and object managers, scheduler, keyboard and mouse
|
||||||
RestartDrivers();
|
RestartDrivers();
|
||||||
|
|
||||||
// TODO: More stuff from dos_main.c may have to be added here
|
|
||||||
|
|
||||||
// load in text strings
|
|
||||||
ChangeLanguage(g_language);
|
|
||||||
|
|
||||||
// load in graphics info
|
// load in graphics info
|
||||||
SetupHandleTable();
|
SetupHandleTable();
|
||||||
|
|
||||||
|
@ -707,14 +941,23 @@ Common::Error TinselEngine::init() {
|
||||||
return Common::kNoError;
|
return Common::kNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TinselEngine::syncSoundSettings() {
|
||||||
|
// Sync the engine with the config manager
|
||||||
|
int soundVolumeMusic = ConfMan.getInt("music_volume");
|
||||||
|
int soundVolumeSFX = ConfMan.getInt("sfx_volume");
|
||||||
|
int soundVolumeSpeech = ConfMan.getInt("speech_volume");
|
||||||
|
|
||||||
|
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
|
||||||
|
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX);
|
||||||
|
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech);
|
||||||
|
}
|
||||||
|
|
||||||
Common::String TinselEngine::getSavegameFilename(int16 saveNum) const {
|
Common::String TinselEngine::getSavegameFilename(int16 saveNum) const {
|
||||||
char filename[256];
|
char filename[256];
|
||||||
snprintf(filename, 256, "%s.%03d", getTargetName().c_str(), saveNum);
|
snprintf(filename, 256, "%s.%03d", getTargetName().c_str(), saveNum);
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GAME_FRAME_DELAY (1000 / ONE_SECOND)
|
|
||||||
|
|
||||||
Common::Error TinselEngine::go() {
|
Common::Error TinselEngine::go() {
|
||||||
uint32 timerVal = 0;
|
uint32 timerVal = 0;
|
||||||
|
|
||||||
|
@ -758,6 +1001,9 @@ Common::Error TinselEngine::go() {
|
||||||
// Save/Restore scene file transfers
|
// Save/Restore scene file transfers
|
||||||
ProcessSRQueue();
|
ProcessSRQueue();
|
||||||
|
|
||||||
|
// Handle any playing movie
|
||||||
|
FettleBMV();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (bFast)
|
if (bFast)
|
||||||
continue; // run flat-out
|
continue; // run flat-out
|
||||||
|
@ -765,6 +1011,11 @@ Common::Error TinselEngine::go() {
|
||||||
// Loop processing events while there are any pending
|
// Loop processing events while there are any pending
|
||||||
while (pollEvent());
|
while (pollEvent());
|
||||||
|
|
||||||
|
DoCdChange();
|
||||||
|
|
||||||
|
if (MoviePlaying() && NextMovieTime())
|
||||||
|
g_system->delayMillis(MAX<int>(NextMovieTime() - g_system->getMillis() + MovieAudioLag(), 0));
|
||||||
|
else
|
||||||
g_system->delayMillis(10);
|
g_system->delayMillis(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -776,8 +1027,11 @@ Common::Error TinselEngine::go() {
|
||||||
|
|
||||||
|
|
||||||
void TinselEngine::NextGameCycle(void) {
|
void TinselEngine::NextGameCycle(void) {
|
||||||
//
|
// Dim Music
|
||||||
ChangeScene();
|
_pcmMusic->dimIteration();
|
||||||
|
|
||||||
|
// Check for scene change
|
||||||
|
ChangeScene(false);
|
||||||
|
|
||||||
// Allow a user event for this schedule
|
// Allow a user event for this schedule
|
||||||
ResetEcount();
|
ResetEcount();
|
||||||
|
@ -785,6 +1039,9 @@ void TinselEngine::NextGameCycle(void) {
|
||||||
// schedule process
|
// schedule process
|
||||||
_scheduler->schedule();
|
_scheduler->schedule();
|
||||||
|
|
||||||
|
if (MoviePlaying())
|
||||||
|
CopyMovieToScreen();
|
||||||
|
else
|
||||||
// redraw background
|
// redraw background
|
||||||
DrawBackgnd();
|
DrawBackgnd();
|
||||||
|
|
||||||
|
@ -810,7 +1067,13 @@ bool TinselEngine::pollEvent() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Common::EVENT_MOUSEMOVE:
|
case Common::EVENT_MOUSEMOVE:
|
||||||
_mousePos = event.mouse;
|
{
|
||||||
|
// This fragment takes care of Tinsel 2 when it's been compiled with
|
||||||
|
// blank areas at the top and bottom of thes creen
|
||||||
|
int ySize = (g_system->getHeight() - _vm->screen().h) / 2;
|
||||||
|
if ((event.mouse.y >= ySize) && (event.mouse.y < (g_system->getHeight() - ySize)))
|
||||||
|
_mousePos = Common::Point(event.mouse.x, event.mouse.y - ySize);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Common::EVENT_KEYDOWN:
|
case Common::EVENT_KEYDOWN:
|
||||||
|
@ -828,7 +1091,6 @@ bool TinselEngine::pollEvent() {
|
||||||
/**
|
/**
|
||||||
* Start the processes that continue between scenes.
|
* Start the processes that continue between scenes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void TinselEngine::CreateConstProcesses(void) {
|
void TinselEngine::CreateConstProcesses(void) {
|
||||||
// Process to run the master script
|
// Process to run the master script
|
||||||
_scheduler->createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0);
|
_scheduler->createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0);
|
||||||
|
@ -841,7 +1103,6 @@ void TinselEngine::CreateConstProcesses(void) {
|
||||||
/**
|
/**
|
||||||
* Restart the game
|
* Restart the game
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void TinselEngine::RestartGame(void) {
|
void TinselEngine::RestartGame(void) {
|
||||||
HoldItem(INV_NOICON); // Holding nothing
|
HoldItem(INV_NOICON); // Holding nothing
|
||||||
|
|
||||||
|
@ -878,7 +1139,6 @@ void TinselEngine::RestartGame(void) {
|
||||||
/**
|
/**
|
||||||
* Init palette and object managers, scheduler, keyboard and mouse.
|
* Init palette and object managers, scheduler, keyboard and mouse.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void TinselEngine::RestartDrivers(void) {
|
void TinselEngine::RestartDrivers(void) {
|
||||||
// init the palette manager
|
// init the palette manager
|
||||||
ResetPalAllocator();
|
ResetPalAllocator();
|
||||||
|
@ -902,13 +1162,12 @@ void TinselEngine::RestartDrivers(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set midi volume
|
// Set midi volume
|
||||||
SetMidiVolume(volMidi);
|
SetMidiVolume(volMusic);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove keyboard, mouse and joystick drivers.
|
* Remove keyboard, mouse and joystick drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void TinselEngine::ChopDrivers(void) {
|
void TinselEngine::ChopDrivers(void) {
|
||||||
// remove sound driver
|
// remove sound driver
|
||||||
StopMidi();
|
StopMidi();
|
||||||
|
@ -923,7 +1182,6 @@ void TinselEngine::ChopDrivers(void) {
|
||||||
/**
|
/**
|
||||||
* Process a keyboard event
|
* Process a keyboard event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void TinselEngine::ProcessKeyEvent(const Common::Event &event) {
|
void TinselEngine::ProcessKeyEvent(const Common::Event &event) {
|
||||||
|
|
||||||
// Handle any special keys immediately
|
// Handle any special keys immediately
|
||||||
|
@ -974,4 +1232,48 @@ void TinselEngine::ProcessKeyEvent(const Common::Event &event) {
|
||||||
keypresses.push_back(event);
|
keypresses.push_back(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *TinselEngine::getSampleIndex(LANGUAGE lang) {
|
||||||
|
int cd;
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
cd = GetCurrentCD();
|
||||||
|
assert((cd == 1) || (cd == 2));
|
||||||
|
assert(((unsigned int) lang) < 5);
|
||||||
|
} else {
|
||||||
|
cd = 0;
|
||||||
|
lang = TXT_ENGLISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _sampleIndices[lang][cd];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *TinselEngine::getSampleFile(LANGUAGE lang) {
|
||||||
|
int cd;
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
cd = GetCurrentCD();
|
||||||
|
assert((cd == 1) || (cd == 2));
|
||||||
|
assert(((unsigned int) lang) < 5);
|
||||||
|
} else {
|
||||||
|
cd = 0;
|
||||||
|
lang = TXT_ENGLISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _sampleFiles[lang][cd];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *TinselEngine::getTextFile(LANGUAGE lang) {
|
||||||
|
assert(((unsigned int) lang) < 5);
|
||||||
|
|
||||||
|
int cd;
|
||||||
|
|
||||||
|
if (TinselV2) {
|
||||||
|
cd = GetCurrentCD();
|
||||||
|
assert((cd == 1) || (cd == 2));
|
||||||
|
} else
|
||||||
|
cd = 0;
|
||||||
|
|
||||||
|
return _textFiles[lang][cd];
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Tinsel
|
} // End of namespace Tinsel
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "common/scummsys.h"
|
#include "common/scummsys.h"
|
||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/events.h"
|
#include "common/events.h"
|
||||||
#include "common/keyboard.h"
|
#include "common/keyboard.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
@ -39,10 +40,12 @@
|
||||||
#include "tinsel/debugger.h"
|
#include "tinsel/debugger.h"
|
||||||
#include "tinsel/graphics.h"
|
#include "tinsel/graphics.h"
|
||||||
#include "tinsel/sound.h"
|
#include "tinsel/sound.h"
|
||||||
|
#include "tinsel/dw.h"
|
||||||
|
|
||||||
namespace Tinsel {
|
namespace Tinsel {
|
||||||
|
|
||||||
class MusicPlayer;
|
class MidiMusicPlayer;
|
||||||
|
class PCMMusicPlayer;
|
||||||
class Scheduler;
|
class Scheduler;
|
||||||
class SoundManager;
|
class SoundManager;
|
||||||
|
|
||||||
|
@ -65,11 +68,34 @@ enum TinselGameFeatures {
|
||||||
GF_USE_5FLAGS = 1 << 6 // All 5 flags
|
GF_USE_5FLAGS = 1 << 6 // All 5 flags
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following is the ScummVM definitions of the various Tinsel versions:
|
||||||
|
* TINSEL_V0 - This was an early engine version that was only used in the Discworld 1
|
||||||
|
* demo. It is not currently supported.
|
||||||
|
* TINSEL_V1 - This was the engine version used by Discworld 1. Note that there were two
|
||||||
|
* major releases: an earlier version that used *.gra files, and a later one that
|
||||||
|
* used *.scn files, and contained certain script and engine bugfixes. In ScummVM,
|
||||||
|
* we treat both releases as 'Tinsel 1', since the engine fixes from the later
|
||||||
|
* version work equally well the earlier version data.
|
||||||
|
* TINSEL_V2 - This is the engine used for the Discworld 2 game.
|
||||||
|
*/
|
||||||
enum TinselEngineVersion {
|
enum TinselEngineVersion {
|
||||||
TINSEL_V0 = 0, // Used in the DW1 demo only
|
TINSEL_V0 = 0,
|
||||||
TINSEL_V1 = 1
|
TINSEL_V1 = 1,
|
||||||
|
TINSEL_V2 = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kTinselDebugAnimations = 1 << 0,
|
||||||
|
kTinselDebugActions = 1 << 1,
|
||||||
|
kTinselDebugSound = 1 << 2,
|
||||||
|
kTinselDebugMusic = 2 << 3
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEBUG_BASIC 1
|
||||||
|
#define DEBUG_INTERMEDIATE 2
|
||||||
|
#define DEBUG_DETAILED 3
|
||||||
|
|
||||||
struct TinselGameDescription;
|
struct TinselGameDescription;
|
||||||
|
|
||||||
enum TinselKeyDirection {
|
enum TinselKeyDirection {
|
||||||
|
@ -79,6 +105,22 @@ enum TinselKeyDirection {
|
||||||
|
|
||||||
typedef bool (*KEYFPTR)(const Common::KeyState &);
|
typedef bool (*KEYFPTR)(const Common::KeyState &);
|
||||||
|
|
||||||
|
#define SCREEN_WIDTH (_vm->screen().w) // PC screen dimensions
|
||||||
|
#define SCREEN_HEIGHT (_vm->screen().h)
|
||||||
|
#define SCRN_CENTRE_X ((SCREEN_WIDTH - 1) / 2) // screen centre x
|
||||||
|
#define SCRN_CENTRE_Y ((SCREEN_HEIGHT - 1) / 2) // screen centre y
|
||||||
|
#define UNUSED_LINES 48
|
||||||
|
#define EXTRA_UNUSED_LINES 3
|
||||||
|
//#define SCREEN_BOX_HEIGHT1 (SCREEN_HEIGHT - UNUSED_LINES)
|
||||||
|
//#define SCREEN_BOX_HEIGHT2 (SCREEN_BOX_HEIGHT1 - EXTRA_UNUSED_LINES)
|
||||||
|
#define SCREEN_BOX_HEIGHT1 SCREEN_HEIGHT
|
||||||
|
#define SCREEN_BOX_HEIGHT2 SCREEN_HEIGHT
|
||||||
|
|
||||||
|
#define GAME_FRAME_DELAY (1000 / ONE_SECOND)
|
||||||
|
|
||||||
|
#define TinselVersion (_vm->getVersion())
|
||||||
|
#define TinselV2 (TinselVersion == TINSEL_V2)
|
||||||
|
|
||||||
class TinselEngine : public Engine {
|
class TinselEngine : public Engine {
|
||||||
int _gameId;
|
int _gameId;
|
||||||
Common::KeyState _keyPressed;
|
Common::KeyState _keyPressed;
|
||||||
|
@ -89,11 +131,16 @@ class TinselEngine : public Engine {
|
||||||
Console *_console;
|
Console *_console;
|
||||||
Scheduler *_scheduler;
|
Scheduler *_scheduler;
|
||||||
|
|
||||||
|
static const char *_sampleIndices[][3];
|
||||||
|
static const char *_sampleFiles[][3];
|
||||||
|
static const char *_textFiles[][3];
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Engine APIs
|
// Engine APIs
|
||||||
virtual Common::Error init();
|
virtual Common::Error init();
|
||||||
virtual Common::Error go();
|
virtual Common::Error go();
|
||||||
|
virtual void syncSoundSettings();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc);
|
TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc);
|
||||||
|
@ -109,13 +156,18 @@ public:
|
||||||
uint16 getVersion() const;
|
uint16 getVersion() const;
|
||||||
Common::Platform getPlatform() const;
|
Common::Platform getPlatform() const;
|
||||||
|
|
||||||
|
const char *getSampleIndex(LANGUAGE lang);
|
||||||
|
const char *getSampleFile(LANGUAGE lang);
|
||||||
|
const char *getTextFile(LANGUAGE lang);
|
||||||
|
|
||||||
MidiDriver *_driver;
|
MidiDriver *_driver;
|
||||||
SoundManager *_sound;
|
SoundManager *_sound;
|
||||||
MusicPlayer *_music;
|
MidiMusicPlayer *_midiMusic;
|
||||||
|
PCMMusicPlayer *_pcmMusic;
|
||||||
|
|
||||||
KEYFPTR _keyHandler;
|
KEYFPTR _keyHandler;
|
||||||
private:
|
private:
|
||||||
//MusicPlayer *_music;
|
//MidiMusicPlayer *_midiMusic;
|
||||||
int _musicVolume;
|
int _musicVolume;
|
||||||
|
|
||||||
void NextGameCycle(void);
|
void NextGameCycle(void);
|
||||||
|
@ -134,7 +186,8 @@ public:
|
||||||
|
|
||||||
Common::Point getMousePosition() const { return _mousePos; }
|
Common::Point getMousePosition() const { return _mousePos; }
|
||||||
void setMousePosition(const Common::Point &pt) {
|
void setMousePosition(const Common::Point &pt) {
|
||||||
g_system->warpMouse(pt.x, pt.y);
|
int ySize = (g_system->getHeight() - _screenSurface.h) / 2;
|
||||||
|
g_system->warpMouse(pt.x, pt.y + ySize);
|
||||||
_mousePos = pt;
|
_mousePos = pt;
|
||||||
}
|
}
|
||||||
void divertKeyInput(KEYFPTR fptr) { _keyHandler = fptr; }
|
void divertKeyInput(KEYFPTR fptr) { _keyHandler = fptr; }
|
||||||
|
@ -145,6 +198,11 @@ public:
|
||||||
// Global reference to the TinselEngine object
|
// Global reference to the TinselEngine object
|
||||||
extern TinselEngine *_vm;
|
extern TinselEngine *_vm;
|
||||||
|
|
||||||
|
// Externally available methods
|
||||||
|
void CuttingScene(bool bCutting);
|
||||||
|
void CDChangeForRestore(int cdNumber);
|
||||||
|
void CdHasChanged(void);
|
||||||
|
|
||||||
} // End of namespace Tinsel
|
} // End of namespace Tinsel
|
||||||
|
|
||||||
#endif /* TINSEL_H */
|
#endif /* TINSEL_H */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue