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/events.h" // for USER_EVENT
|
||||
#include "tinsel/events.h" // for TINSEL_EVENT
|
||||
#include "tinsel/palette.h" // for COLORREF
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
struct FREEL;
|
||||
struct INT_CONTEXT;
|
||||
struct MACTOR;
|
||||
struct MOVER;
|
||||
struct OBJECT;
|
||||
|
||||
#define ACTORTAG_KEY 0x1000000
|
||||
|
||||
#define OTH_RELATEDACTOR 0x00000fff
|
||||
#define OTH_RELATIVE 0x00001000
|
||||
#define OTH_ABSOLUTE 0x00002000
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void RegisterActors(int num);
|
||||
void FreeActors(void);
|
||||
void setleadid(int rid);
|
||||
int LeadId(void);
|
||||
void StartActors(SCNHANDLE ah, int numActors, bool bRunScript);
|
||||
void SetLeadId(int rid);
|
||||
int GetLeadId(void);
|
||||
bool ActorIsGhost(int actor);
|
||||
void StartTaggedActors(SCNHANDLE ah, int numActors, bool bRunScript);
|
||||
void DropActors(void); // No actor reels running
|
||||
void DisableActor(int actor);
|
||||
void EnableActor(int actor);
|
||||
|
@ -63,60 +69,110 @@ int GetActorLeft(int ano);
|
|||
int GetActorRight(int ano);
|
||||
int GetActorTop(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);
|
||||
void unHideMovingActor(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);
|
||||
SCNHANDLE actorFilm(int ano);
|
||||
|
||||
void setActorPlayFilm(int ano, SCNHANDLE film);
|
||||
SCNHANDLE getActorPlayFilm(int ano);
|
||||
void setActorTalkFilm(int ano, SCNHANDLE film);
|
||||
SCNHANDLE getActorTalkFilm(int ano);
|
||||
void setActorTalking(int ano, bool tf);
|
||||
bool isActorTalking(int ano);
|
||||
void setActorLatestFilm(int ano, SCNHANDLE film);
|
||||
SCNHANDLE getActorLatestFilm(int ano);
|
||||
void SetActorPlayFilm(int ano, SCNHANDLE hFilm);
|
||||
SCNHANDLE GetActorPlayFilm(int ano);
|
||||
void SetActorTalkFilm(int ano, SCNHANDLE hFilm);
|
||||
SCNHANDLE GetActorTalkFilm(int ano);
|
||||
void SetActorTalking(int ano, bool tf);
|
||||
bool ActorIsTalking(int ano);
|
||||
void SetActorLatestFilm(int ano, SCNHANDLE hFilm);
|
||||
SCNHANDLE GetActorLatestFilm(int ano);
|
||||
|
||||
void updateActorEsc(int ano, bool escOn, int escEv);
|
||||
bool actorEsc(int ano);
|
||||
int actorEev(int ano);
|
||||
void storeActorPos(int ano, int x, int y);
|
||||
void storeActorSteps(int ano, int steps);
|
||||
int getActorSteps(int ano);
|
||||
void storeActorZpos(int ano, int z);
|
||||
void UpdateActorEsc(int ano, bool escOn, int escEvent);
|
||||
void UpdateActorEsc(int ano, int escEvent);
|
||||
bool ActorEsc(int ano);
|
||||
int ActorEev(int ano);
|
||||
void StoreActorPos(int ano, int x, int y);
|
||||
void StoreActorSteps(int ano, int steps);
|
||||
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);
|
||||
void FirstTaggedActor(void);
|
||||
int NextTaggedActor(void);
|
||||
int NextTaggedActor(int previous);
|
||||
int AsetZPos(OBJECT *pObj, int y, int32 zFactor);
|
||||
void MAsetZPos(MACTOR *pActor, int y, int32 zFactor);
|
||||
void actorEvent(int ano, USER_EVENT event, BUTEVENT be);
|
||||
void SetMoverZ(MOVER *pMover, int y, int32 zFactor);
|
||||
void ActorEvent(int ano, TINSEL_EVENT event, PLR_EVENT be);
|
||||
|
||||
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 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 {
|
||||
short actorID;
|
||||
short z;
|
||||
short zFactor;
|
||||
bool bAlive;
|
||||
bool bHidden;
|
||||
SCNHANDLE presFilm; //!< the film that reel belongs to
|
||||
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);
|
||||
|
||||
|
||||
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/object.h"
|
||||
#include "tinsel/sched.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
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.
|
||||
* @param pAnim Animation data structure
|
||||
|
@ -64,6 +44,9 @@ SCRIPTSTATE DoNextFrame(ANIM *pAnim) {
|
|||
const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);
|
||||
|
||||
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)) {
|
||||
case ANI_END: // end of animation script
|
||||
|
@ -104,7 +87,6 @@ SCRIPTSTATE DoNextFrame(ANIM *pAnim) {
|
|||
|
||||
// go fetch a real image
|
||||
break;
|
||||
|
||||
case ANI_HVFLIP: // flip animated object in both directions
|
||||
|
||||
// next opcode
|
||||
|
@ -230,6 +212,12 @@ SCRIPTSTATE DoNextFrame(ANIM *pAnim) {
|
|||
void InitStepAnimScript(ANIM *pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int aniSpeed) {
|
||||
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->pObject = pAniObj; // set object to animate
|
||||
pAnim->hScript = hNewScript; // set animation script
|
||||
|
@ -254,9 +242,13 @@ SCRIPTSTATE StepAnimScript(ANIM *pAnim) {
|
|||
// re-init animation delta counter
|
||||
pAnim->aniDelta = pAnim->aniRate;
|
||||
|
||||
if (TinselV2)
|
||||
state = DoNextFrame(pAnim);
|
||||
else {
|
||||
// move to next frame
|
||||
while ((state = DoNextFrame(pAnim)) == ScriptNoSleep)
|
||||
;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
@ -274,7 +266,7 @@ void SkipFrames(ANIM *pAnim, int numFrames) {
|
|||
// get a pointer to the script
|
||||
const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);
|
||||
|
||||
if (numFrames <= 0)
|
||||
if (!TinselV2 && (numFrames <= 0))
|
||||
// do nothing
|
||||
return;
|
||||
|
||||
|
@ -282,9 +274,10 @@ void SkipFrames(ANIM *pAnim, int numFrames) {
|
|||
|
||||
switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
|
||||
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)!'");
|
||||
break;
|
||||
return;
|
||||
|
||||
case ANI_JUMP: // do animation jump
|
||||
|
||||
|
@ -293,6 +286,10 @@ void SkipFrames(ANIM *pAnim, int numFrames) {
|
|||
|
||||
// jump to new frame position
|
||||
pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);
|
||||
|
||||
if (TinselV2)
|
||||
// Done if skip to jump
|
||||
return;
|
||||
break;
|
||||
|
||||
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
|
||||
|
||||
// one less frame
|
||||
if (numFrames-- > 0) {
|
||||
if (numFrames == 0)
|
||||
return;
|
||||
|
||||
if (numFrames == -1 || numFrames-- > 0) {
|
||||
// next opcode
|
||||
pAnim->scriptIndex++;
|
||||
} 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
|
||||
|
|
|
@ -41,6 +41,32 @@ struct ANIM {
|
|||
uint32 hScript; //!< animation script handle
|
||||
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
|
||||
int numFrames); // number of frames to skip
|
||||
|
||||
bool AboutToJumpOrEnd(PANIM pAnim);
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
||||
#endif // TINSEL_ANIM_H
|
||||
|
|
|
@ -37,6 +37,9 @@ namespace Tinsel {
|
|||
// current background
|
||||
BACKGND *pCurBgnd = NULL;
|
||||
|
||||
// FIXME: Not yet used
|
||||
static bool bEntireRedraw;
|
||||
|
||||
/**
|
||||
* Called to initialise a 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param which Which playfield
|
||||
|
@ -229,4 +253,9 @@ void DrawBackgnd(void) {
|
|||
ResetClipRect();
|
||||
}
|
||||
|
||||
void ForceEntireRedraw(void) {
|
||||
bEntireRedraw = true;
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
|
|
@ -27,10 +27,11 @@
|
|||
#ifndef TINSEL_BACKGND_H // prevent multiple includes
|
||||
#define TINSEL_BACKGND_H
|
||||
|
||||
#include "tinsel/dw.h" // for SCNHANDLE
|
||||
#include "tinsel/palette.h" // palette definitions
|
||||
#include "common/frac.h"
|
||||
#include "common/rect.h"
|
||||
#include "tinsel/coroutine.h"
|
||||
#include "tinsel/dw.h" // for SCNHANDLE
|
||||
#include "tinsel/palette.h" // palette definitions
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
|
@ -78,6 +79,8 @@ struct BACKGND {
|
|||
void InitBackground( // called to initialise a 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 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 *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
|
||||
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
|
||||
|
||||
SCNHANDLE BackPal(void);
|
||||
OBJECT *GetBgObject();
|
||||
|
||||
SCNHANDLE BgPal(void);
|
||||
|
||||
void ForceEntireRedraw(void);
|
||||
|
||||
int BgWidth(void);
|
||||
|
||||
int BgHeight(void);
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
#include "tinsel/pid.h"
|
||||
#include "tinsel/sched.h"
|
||||
#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"
|
||||
|
||||
|
@ -45,49 +46,61 @@ namespace Tinsel {
|
|||
|
||||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
||||
static SCNHANDLE BackPalette = 0; // Background's palette
|
||||
static OBJECT *pBG = 0; // The main picture's object.
|
||||
#define MAX_BG 10
|
||||
|
||||
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 SCNHANDLE BgroundHandle = 0; // Current scene handle - stored in case of Save_Scene()
|
||||
static bool DoFadeIn = false;
|
||||
static ANIM thisAnim; // used by BGmainProcess()
|
||||
static SCNHANDLE hBackground = 0; // Current scene handle - stored in case of Save_Scene()
|
||||
static bool bDoFadeIn = false;
|
||||
static int bgReels;
|
||||
|
||||
/**
|
||||
* GetBgObject
|
||||
*/
|
||||
OBJECT *GetBgObject() {
|
||||
return pBG[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* BackPal
|
||||
*/
|
||||
SCNHANDLE BackPal(void) {
|
||||
return BackPalette;
|
||||
SCNHANDLE BgPal(void) {
|
||||
return hBgPal;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetDoFadeIn
|
||||
*/
|
||||
void SetDoFadeIn(bool tf) {
|
||||
DoFadeIn = tf;
|
||||
bDoFadeIn = tf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before scene change.
|
||||
*/
|
||||
void DropBackground(void) {
|
||||
pBG = NULL; // No background
|
||||
BackPalette = 0; // No background palette
|
||||
pBG[0] = NULL; // No background
|
||||
|
||||
if (!TinselV2)
|
||||
hBgPal = 0; // No background palette
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the width of the current background.
|
||||
*/
|
||||
int BackgroundWidth(void) {
|
||||
assert(pBG);
|
||||
return MultiRightmost(pBG) + 1;
|
||||
int BgWidth(void) {
|
||||
assert(pBG[0]);
|
||||
return MultiRightmost(pBG[0]) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the height of the current background.
|
||||
*/
|
||||
int BackgroundHeight(void) {
|
||||
assert(pBG);
|
||||
return MultiLowest(pBG) + 1;
|
||||
int BgHeight(void) {
|
||||
assert(pBG[0]);
|
||||
return MultiLowest(pBG[0]) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,90 +113,137 @@ static void BGmainProcess(CORO_PARAM, const void *param) {
|
|||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
const FREEL *pfr;
|
||||
const FILM *pFilm;
|
||||
const FREEL *pReel;
|
||||
const MULTI_INIT *pmi;
|
||||
|
||||
// get the stuff copied to process when it was created
|
||||
pfr = (const FREEL *)param;
|
||||
|
||||
if (pBG == NULL) {
|
||||
if (pBG[0] == NULL) {
|
||||
/*** At start of scene ***/
|
||||
|
||||
if (!TinselV2) {
|
||||
pReel = (const FREEL *)param;
|
||||
|
||||
// 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.
|
||||
pBG = MultiInitObject(pmi);
|
||||
MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG);
|
||||
InitStepAnimScript(&thisAnim, pBG, FROM_LE_32(pfr->script), BGspeed);
|
||||
pBG[0] = MultiInitObject(pmi);
|
||||
MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[0]);
|
||||
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) {
|
||||
FadeInFast(NULL);
|
||||
DoFadeIn = false;
|
||||
int i;
|
||||
for (i = 0; i < bgReels; i++) {
|
||||
// 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)
|
||||
CORO_SLEEP(1);
|
||||
if (bDoFadeIn) {
|
||||
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!");
|
||||
}
|
||||
|
||||
CORO_SLEEP(1);
|
||||
}
|
||||
} else {
|
||||
// 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.
|
||||
InitStepAnimScript(&thisAnim, pBG, FROM_LE_32(pfr->script), BGspeed);
|
||||
StepAnimScript(&thisAnim);
|
||||
// Just re-initialise the scripts.
|
||||
for (int i = 0; i < bgReels; i++) {
|
||||
InitStepAnimScript(&thisAnim[i], pBG[i], pFilm->reels[i].script, BGspeed);
|
||||
StepAnimScript(&thisAnim[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* setBackPal()
|
||||
* AetBgPal()
|
||||
*/
|
||||
void setBackPal(SCNHANDLE hPal) {
|
||||
BackPalette = hPal;
|
||||
void SetBackPal(SCNHANDLE hPal) {
|
||||
hBgPal = hPal;
|
||||
|
||||
fettleFontPal(BackPalette);
|
||||
CreateTranslucentPalette(BackPalette);
|
||||
FettleFontPal(hBgPal);
|
||||
CreateTranslucentPalette(hBgPal);
|
||||
}
|
||||
|
||||
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
|
||||
* everything else's use, then starts a display process for each reel
|
||||
* 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;
|
||||
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);
|
||||
setBackPal(FROM_LE_32(pim->hImgPal));
|
||||
pim = GetImageFromFilm(hFilm, 0, NULL, NULL, &pfilm);
|
||||
SetBackPal(FROM_LE_32(pim->hImgPal));
|
||||
|
||||
// Extract the film speed
|
||||
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
|
||||
assert(FROM_LE_32(pfilm->numreels) == 1); // Multi-reeled backgrounds withdrawn
|
||||
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.
|
||||
*/
|
||||
SCNHANDLE GetBgroundHandle(void) {
|
||||
return BgroundHandle;
|
||||
return hBackground;
|
||||
}
|
||||
|
||||
} // 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
|
||||
*/
|
||||
|
||||
//#define USE_3FLAGS 1
|
||||
|
||||
#include "tinsel/config.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/sound.h"
|
||||
|
@ -39,7 +41,7 @@ namespace Tinsel {
|
|||
//----------------- GLOBAL GLOBAL DATA --------------------
|
||||
|
||||
int dclickSpeed = DOUBLE_CLICK_TIME;
|
||||
int volMidi = Audio::Mixer::kMaxChannelVolume;
|
||||
int volMusic = Audio::Mixer::kMaxChannelVolume;
|
||||
int volSound = Audio::Mixer::kMaxChannelVolume;
|
||||
int volVoice = Audio::Mixer::kMaxChannelVolume;
|
||||
int speedText = DEFTEXTSPEED;
|
||||
|
@ -49,21 +51,18 @@ LANGUAGE g_language = TXT_ENGLISH;
|
|||
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.
|
||||
*/
|
||||
void WriteConfig(void) {
|
||||
ConfMan.setInt("dclick_speed", dclickSpeed);
|
||||
ConfMan.setInt("music_volume", volMidi);
|
||||
ConfMan.setInt("music_volume", volMusic);
|
||||
ConfMan.setInt("sfx_volume", volSound);
|
||||
ConfMan.setInt("speech_volume", volVoice);
|
||||
ConfMan.setInt("talkspeed", (speedText * 255) / 100);
|
||||
ConfMan.setBool("subtitles", bSubtitles);
|
||||
//ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0);
|
||||
//ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB
|
||||
|
||||
// Store language for multilingual versions
|
||||
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();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*\
|
||||
| ReadConfig() |
|
||||
|-----------------------------------------------------------------------|
|
||||
|
|
||||
\*---------------------------------------------------------------------*/
|
||||
/**
|
||||
* Read configuration settings from the config file into memory
|
||||
*/
|
||||
void ReadConfig(void) {
|
||||
if (ConfMan.hasKey("dclick_speed"))
|
||||
dclickSpeed = ConfMan.getInt("dclick_speed");
|
||||
|
||||
volMidi = ConfMan.getInt("music_volume");
|
||||
volMusic = ConfMan.getInt("music_volume");
|
||||
volSound = ConfMan.getInt("sfx_volume");
|
||||
volVoice = ConfMan.getInt("speech_volume");
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ enum {
|
|||
};
|
||||
|
||||
extern int dclickSpeed;
|
||||
extern int volMidi;
|
||||
extern int volMusic;
|
||||
extern int volSound;
|
||||
extern int volVoice;
|
||||
extern int speedText;
|
||||
|
@ -51,10 +51,6 @@ void ReadConfig(void);
|
|||
|
||||
extern bool isJapanMode();
|
||||
|
||||
|
||||
// Shouldn't really be here, but time is short...
|
||||
extern bool bNoBlocking;
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,6 +70,7 @@ struct CoroBaseContext {
|
|||
|
||||
typedef CoroBaseContext *CoroContext;
|
||||
|
||||
extern CoroContext nullContext;
|
||||
|
||||
/**
|
||||
* 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_BEGIN_CODE(x) \
|
||||
if (&coroParam == &nullContext) assert(!nullContext);\
|
||||
if (!x) {coroParam = x = new CoroContextTag();}\
|
||||
assert(coroParam);\
|
||||
assert(coroParam->_sleep >= 0);\
|
||||
|
@ -109,17 +111,22 @@ public:
|
|||
switch(coroParam->_line) { case 0:;
|
||||
|
||||
#define CORO_END_CODE \
|
||||
if (&coroParam == &nullContext) nullContext = NULL; \
|
||||
}
|
||||
|
||||
#define CORO_SLEEP(delay) \
|
||||
do {\
|
||||
#define CORO_SLEEP(delay) do {\
|
||||
coroParam->_line = __LINE__;\
|
||||
coroParam->_sleep = delay;\
|
||||
assert(&coroParam != &nullContext);\
|
||||
return; case __LINE__:;\
|
||||
} 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 */
|
||||
#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 */
|
||||
#define CORO_INVOKE_ARGS(subCoro, ARGS) \
|
||||
|
@ -130,9 +137,22 @@ public:
|
|||
subCoro ARGS;\
|
||||
if (!coroParam->_subctx) break;\
|
||||
coroParam->_sleep = coroParam->_subctx->_sleep;\
|
||||
assert(&coroParam != &nullContext);\
|
||||
return; case __LINE__:;\
|
||||
} while(1);\
|
||||
} 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) \
|
||||
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX))
|
||||
|
@ -140,6 +160,8 @@ public:
|
|||
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0))
|
||||
#define CORO_INVOKE_2(subCoroutine, 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
|
||||
|
|
|
@ -34,11 +34,14 @@
|
|||
#include "tinsel/film.h"
|
||||
#include "tinsel/graphics.h"
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/inventory.h"
|
||||
#include "tinsel/dialogs.h"
|
||||
#include "tinsel/multiobj.h" // multi-part object defintions etc.
|
||||
#include "tinsel/object.h"
|
||||
#include "tinsel/pid.h"
|
||||
#include "tinsel/play.h"
|
||||
#include "tinsel/sched.h"
|
||||
#include "tinsel/sysvar.h"
|
||||
#include "tinsel/text.h"
|
||||
#include "tinsel/timers.h" // For ONE_SECOND constant
|
||||
#include "tinsel/tinlib.h" // resetidletime()
|
||||
#include "tinsel/tinsel.h" // For engine access
|
||||
|
@ -54,20 +57,21 @@ namespace Tinsel {
|
|||
|
||||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
||||
static OBJECT *McurObj = 0; // Main cursor object
|
||||
static OBJECT *AcurObj = 0; // Auxiliary cursor object
|
||||
static OBJECT *McurObj = NULL; // Main cursor object
|
||||
static OBJECT *AcurObj = NULL; // Auxiliary cursor object
|
||||
|
||||
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 bool bHiddenCursor = false; // Set when cursor is 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 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 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
|
||||
// Reset when main cursor has re-initialised
|
||||
|
||||
static bool restart = false; // When main cursor has been bWhoa-ed, it waits
|
||||
// for this to be set to true.
|
||||
static uint16 restart = 0; // When main cursor has been bWhoa-ed, it waits
|
||||
// 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
|
||||
|
||||
|
@ -97,7 +104,7 @@ static int lastCursorX = 0, lastCursorY = 0;
|
|||
|
||||
//----------------- FORWARD REFERENCES --------------------
|
||||
|
||||
static void MoveCursor(void);
|
||||
static void DoCursorMove(void);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
|
||||
|
||||
pim = GetImageFromFilm(CursorHandle, i+1, &pfr, &pmi, &pfilm);// Get pointer to image
|
||||
assert(BackPal()); // No background palette
|
||||
pim->hImgPal = TO_LE_32(BackPal());
|
||||
pim = GetImageFromFilm(hCursorFilm, i+1, &pfr, &pmi, &pfilm);// Get pointer to image
|
||||
assert(BgPal()); // No background palette
|
||||
pim->hImgPal = TO_LE_32(BgPal());
|
||||
|
||||
// Initialise and insert the object, set its Z-pos, and hide it
|
||||
ntrailData[i].trailObj = MultiInitObject(pmi);
|
||||
|
@ -140,8 +147,8 @@ static bool GetDriverPosition(int *x, int *y) {
|
|||
*x = ptMouse.x;
|
||||
*y = ptMouse.y;
|
||||
|
||||
return(*x >= 0 && *x <= SCREEN_WIDTH-1 &&
|
||||
*y >= 0 && *y <= SCREEN_HEIGHT-1);
|
||||
return(*x >= 0 && *x <= SCREEN_WIDTH - 1 &&
|
||||
*y >= 0 && *y <= SCREEN_HEIGHT - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,7 +161,7 @@ void AdjustCursorXY(int deltaX, int deltaY) {
|
|||
if (GetDriverPosition(&x, &y))
|
||||
_vm->setMousePosition(Common::Point(x + deltaX, y + deltaY));
|
||||
}
|
||||
MoveCursor();
|
||||
DoCursorMove();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,7 +177,7 @@ void SetCursorXY(int newx, int newy) {
|
|||
|
||||
if (GetDriverPosition(&x, &y))
|
||||
_vm->setMousePosition(Common::Point(newx, newy));
|
||||
MoveCursor();
|
||||
DoCursorMove();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,7 +188,7 @@ void SetCursorScreenXY(int newx, int newy) {
|
|||
|
||||
if (GetDriverPosition(&x, &y))
|
||||
_vm->setMousePosition(Common::Point(newx, newy));
|
||||
MoveCursor();
|
||||
DoCursorMove();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,7 +236,7 @@ void RestoreMainCursor(void) {
|
|||
const FILM *pfilm;
|
||||
|
||||
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));
|
||||
StepAnimScript(&McurAnim);
|
||||
|
@ -281,6 +288,13 @@ void FreezeCursor(void) {
|
|||
bFrozenCursor = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Freeze the cursor, or not.
|
||||
*/
|
||||
void DoFreezeCursor(bool bFreeze) {
|
||||
bFrozenCursor = bFreeze;
|
||||
}
|
||||
|
||||
/**
|
||||
* HideCursorTrails
|
||||
*/
|
||||
|
@ -365,11 +379,12 @@ void SetAuxCursor(SCNHANDLE hFilm) {
|
|||
GetCursorXY(&x, &y, false); // Note: also waits for cursor to appear
|
||||
|
||||
pim = GetImageFromFilm(hFilm, 0, &pfr, &pmi, &pfilm);// Get pointer to image
|
||||
assert(BackPal()); // no background palette
|
||||
pim->hImgPal = TO_LE_32(BackPal()); // Poke in the background palette
|
||||
assert(BgPal()); // no 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)));
|
||||
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
|
||||
AcurObj = MultiInitObject(pmi);
|
||||
|
@ -387,7 +402,7 @@ void SetAuxCursor(SCNHANDLE hFilm) {
|
|||
/**
|
||||
* MoveCursor
|
||||
*/
|
||||
static void MoveCursor(void) {
|
||||
static void DoCursorMove(void) {
|
||||
int startX, startY;
|
||||
Common::Point ptMouse;
|
||||
frac_t newX, newY;
|
||||
|
@ -459,22 +474,30 @@ static void MoveCursor(void) {
|
|||
* Initialise cursor object.
|
||||
*/
|
||||
static void InitCurObj(void) {
|
||||
const FILM *pfilm;
|
||||
const FILM *pFilm;
|
||||
const FREEL *pfr;
|
||||
const MULTI_INIT *pmi;
|
||||
IMAGE *pim;
|
||||
|
||||
pim = GetImageFromFilm(CursorHandle, 0, &pfr, &pmi, &pfilm);// Get pointer to image
|
||||
assert(BackPal()); // no background palette
|
||||
pim->hImgPal = TO_LE_32(BackPal());
|
||||
//---
|
||||
if (TinselV2) {
|
||||
pFilm = (const FILM *)LockMem(hCursorFilm);
|
||||
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
|
||||
}
|
||||
|
||||
McurObj = MultiInitObject(pmi);
|
||||
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;
|
||||
|
||||
MultiSetZPosition(McurObj, Z_CURSOR);
|
||||
MoveCursor();
|
||||
DoCursorMove();
|
||||
MultiHideObject(McurObj);
|
||||
|
||||
IterationSize = ITERATION_BASE;
|
||||
|
@ -505,16 +528,16 @@ static void CursorStoppedCheck(CORO_PARAM) {
|
|||
// If scene is closing down
|
||||
if (bWhoa) {
|
||||
// ...wait for next scene start-up
|
||||
while (!restart)
|
||||
while (restart != 0x8000)
|
||||
CORO_SLEEP(1);
|
||||
|
||||
// Re-initialise
|
||||
InitCurObj();
|
||||
InitCurPos();
|
||||
InventoryIconCursor(); // May be holding something
|
||||
InventoryIconCursor(false); // May be holding something
|
||||
|
||||
// Re-start the cursor trails
|
||||
restart = false; // set all bits
|
||||
restart = (uint16)-1; // set all bits
|
||||
bWhoa = false;
|
||||
}
|
||||
CORO_END_CODE;
|
||||
|
@ -530,15 +553,15 @@ void CursorProcess(CORO_PARAM, const void *) {
|
|||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
while (!CursorHandle || !BackPal())
|
||||
while (!hCursorFilm || !BgPal())
|
||||
CORO_SLEEP(1);
|
||||
|
||||
InitCurObj();
|
||||
InitCurPos();
|
||||
InventoryIconCursor(); // May be holding something
|
||||
InventoryIconCursor(false); // May be holding something
|
||||
|
||||
bWhoa = false;
|
||||
restart = false;
|
||||
restart = 0;
|
||||
|
||||
while (1) {
|
||||
// allow rescheduling
|
||||
|
@ -562,10 +585,10 @@ void CursorProcess(CORO_PARAM, const void *) {
|
|||
|
||||
// Move the cursor as appropriate
|
||||
if (!bFrozenCursor)
|
||||
MoveCursor();
|
||||
DoCursorMove();
|
||||
|
||||
// If the cursor should be hidden...
|
||||
if (bHiddenCursor) {
|
||||
if (bHiddenCursor || bTempHide) {
|
||||
// ...hide the cursor object(s)
|
||||
MultiHideObject(McurObj);
|
||||
if (AcurObj)
|
||||
|
@ -595,9 +618,9 @@ void CursorProcess(CORO_PARAM, const void *) {
|
|||
void DwInitCursor(SCNHANDLE bfilm) {
|
||||
const FILM *pfilm;
|
||||
|
||||
CursorHandle = bfilm;
|
||||
hCursorFilm = bfilm;
|
||||
|
||||
pfilm = (const FILM *)LockMem(CursorHandle);
|
||||
pfilm = (const FILM *)LockMem(hCursorFilm);
|
||||
numTrails = FROM_LE_32(pfilm->numreels) - 1;
|
||||
|
||||
assert(numTrails <= MAX_TRAILERS);
|
||||
|
@ -607,6 +630,15 @@ void DwInitCursor(SCNHANDLE bfilm) {
|
|||
* DropCursor is called when a scene is closing down.
|
||||
*/
|
||||
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
|
||||
McurObj = NULL; // No cursor object (imminently deleted elsewhere)
|
||||
bHiddenCursor = false; // Not hidden in next scene
|
||||
|
@ -625,7 +657,7 @@ void DropCursor(void) {
|
|||
* RestartCursor is called when a new scene is starting up.
|
||||
*/
|
||||
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;
|
||||
|
||||
CursorHandle = 0;
|
||||
hCursorFilm = 0;
|
||||
|
||||
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
|
||||
|
|
|
@ -42,6 +42,7 @@ void SetTempCursor(SCNHANDLE pScript);
|
|||
void DwHideCursor(void);
|
||||
void UnHideCursor(void);
|
||||
void FreezeCursor(void);
|
||||
void DoFreezeCursor(bool bFreeze);
|
||||
void HideCursorTrails(void);
|
||||
void UnHideCursorTrails(void);
|
||||
void DelAuxCursor(void);
|
||||
|
@ -50,6 +51,8 @@ void DwInitCursor(SCNHANDLE bfilm);
|
|||
void DropCursor(void);
|
||||
void RestartCursor(void);
|
||||
void RebootCursor(void);
|
||||
void StartCursorFollowed(void);
|
||||
void EndCursorFollowed(void);
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include "tinsel/tinsel.h"
|
||||
#include "tinsel/debugger.h"
|
||||
#include "tinsel/inventory.h"
|
||||
#include "tinsel/dialogs.h"
|
||||
#include "tinsel/pcode.h"
|
||||
#include "tinsel/scene.h"
|
||||
#include "tinsel/sound.h"
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "tinsel/tinsel.h"
|
||||
#include "tinsel/savescn.h" // needed by TinselMetaEngine::listSaves
|
||||
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
struct TinselGameDescription {
|
||||
|
@ -68,7 +67,7 @@ uint16 TinselEngine::getVersion() const {
|
|||
static const PlainGameDescriptor tinselGames[] = {
|
||||
{"tinsel", "Tinsel engine game"},
|
||||
{"dw", "Discworld"},
|
||||
{"dw2", "Discworld 2: Mortality Bytes!"},
|
||||
{"dw2", "Discworld 2: Missing Presumed ...!?"},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
|
@ -77,25 +76,15 @@ namespace Tinsel {
|
|||
|
||||
static const TinselGameDescription gameDescriptions[] = {
|
||||
|
||||
// The DW1 demo was based on an older revision of the Tinsel engine
|
||||
// than the one used in the released game. We call it Tinsel v0 as
|
||||
// opposed to v1 which was used in the full retail version of DW.
|
||||
|
||||
{ // 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,
|
||||
},
|
||||
// Note: The following is the (hopefully) definitive list of version details:
|
||||
// TINSEL_V0: Used only by the Discworld 1 demo - this used a more primitive version
|
||||
// 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
|
||||
// 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,
|
||||
// as both game versions work equally well with the newer code.
|
||||
// TINSEL_V2: The Discworld 2 game used this updated version of the Tinsel 1 engine,
|
||||
// and as far as we know there aren't any variations of this engine.
|
||||
|
||||
{
|
||||
{ // This version has *.gra files
|
||||
|
@ -112,49 +101,6 @@ static const TinselGameDescription gameDescriptions[] = {
|
|||
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.
|
||||
// Note: It contains no english subtitles.
|
||||
{
|
||||
|
@ -245,7 +191,7 @@ static const TinselGameDescription gameDescriptions[] = {
|
|||
TINSEL_V1,
|
||||
},
|
||||
|
||||
{ // English CD with SCN files
|
||||
{ // English CD v2
|
||||
{
|
||||
"dw",
|
||||
"CD",
|
||||
|
@ -265,7 +211,7 @@ static const TinselGameDescription gameDescriptions[] = {
|
|||
},
|
||||
|
||||
#if 0
|
||||
{ // English Saturn CD. Not (yet?) supported
|
||||
{ // English Saturn CD
|
||||
{
|
||||
"dw",
|
||||
"CD",
|
||||
|
@ -285,6 +231,25 @@ static const TinselGameDescription gameDescriptions[] = {
|
|||
},
|
||||
#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"
|
||||
// Note: This release has ENGLISH.TXT (with german content) instead of GERMAN.TXT
|
||||
{
|
||||
|
@ -301,6 +266,44 @@ static const TinselGameDescription gameDescriptions[] = {
|
|||
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 }
|
||||
};
|
||||
|
||||
|
@ -334,25 +337,23 @@ public:
|
|||
}
|
||||
|
||||
virtual const char *getCopyright() const {
|
||||
// FIXME: Bad copyright string.
|
||||
// Should be something like "Tinsel (C) Psygnosis" or so... ???
|
||||
return "Tinsel Engine";
|
||||
return "Tinsel (C) Psygnosis";
|
||||
}
|
||||
|
||||
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
|
||||
|
||||
virtual bool hasFeature(MetaEngineFeature f) const;
|
||||
virtual SaveStateList listSaves(const char *target) const;
|
||||
virtual int getMaximumSaveSlot() const;
|
||||
};
|
||||
|
||||
bool TinselMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves);
|
||||
return (f == kSupportsListSaves);
|
||||
}
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
extern int getList(Common::SaveFileManager *saveFileMan, const Common::String &target);
|
||||
|
||||
}
|
||||
|
||||
SaveStateList TinselMetaEngine::listSaves(const char *target) const {
|
||||
|
@ -368,8 +369,6 @@ SaveStateList TinselMetaEngine::listSaves(const char *target) const {
|
|||
return saveList;
|
||||
}
|
||||
|
||||
int TinselMetaEngine::getMaximumSaveSlot() const { return 999; }
|
||||
|
||||
bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
|
||||
const Tinsel::TinselGameDescription *gd = (const Tinsel::TinselGameDescription *)desc;
|
||||
if (gd) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,52 +29,67 @@
|
|||
#define TINSEL_INVENTORY_H
|
||||
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/events.h" // for KEYEVENT, BUTEVENT
|
||||
#include "tinsel/events.h" // for PLR_EVENT, PLR_EVENT
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
class Serializer;
|
||||
|
||||
enum {
|
||||
INV_OPEN = -1,
|
||||
INV_OPEN = -1, // DW1 only
|
||||
INV_CONV = 0,
|
||||
INV_1 = 1,
|
||||
INV_2 = 2,
|
||||
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 */
|
||||
struct INV_OBJECT {
|
||||
int32 id; // inventory objects id
|
||||
SCNHANDLE hFilm; // inventory objects animation film
|
||||
SCNHANDLE hIconFilm; // inventory objects animation film
|
||||
SCNHANDLE hScript; // inventory objects event handling script
|
||||
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);
|
||||
|
||||
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 Ymovement(int y);
|
||||
|
||||
void ButtonToInventory(BUTEVENT be);
|
||||
|
||||
void KeyToInventory(KEYEVENT ke);
|
||||
void EventToInventory(PLR_EVENT pEvent, const Common::Point &coOrds);
|
||||
void ButtonToInventory(PLR_EVENT be);
|
||||
void KeyToInventory(PLR_EVENT ke);
|
||||
|
||||
|
||||
int WhichItemHeld(void);
|
||||
|
||||
void HoldItem(int item);
|
||||
void HoldItem(int item, bool bKeepFilm = false);
|
||||
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);
|
||||
|
||||
|
||||
|
@ -89,25 +104,34 @@ void idec_inv2(SCNHANDLE text, int MaxContents, int MinWidth, int MinHeight,
|
|||
|
||||
bool InventoryActive(void);
|
||||
|
||||
void AddIconToPermanentDefaultList(int icon);
|
||||
void PermaConvIcon(int icon, bool bEnd = false);
|
||||
|
||||
void convPos(int bpos);
|
||||
void ConvPoly(HPOLYGON hp);
|
||||
int convIcon(void);
|
||||
int GetIcon(void);
|
||||
void CloseDownConv(void);
|
||||
void convHide(bool hide);
|
||||
bool convHid(void);
|
||||
void HideConversation(bool hide);
|
||||
bool ConvIsHidden(void);
|
||||
|
||||
enum {
|
||||
NOOBJECT = -1,
|
||||
INV_NOICON = -1,
|
||||
INV_CLOSEICON = -2,
|
||||
INV_OPENICON = -3,
|
||||
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 setFlagFilms(SCNHANDLE hf);
|
||||
|
@ -122,8 +146,6 @@ bool IsInInventory(int object, int invnum);
|
|||
|
||||
void KillInventory(void);
|
||||
|
||||
void invObjectFilm(int object, SCNHANDLE hFilm);
|
||||
|
||||
void syncInvInfo(Serializer &s);
|
||||
|
||||
int InvGetLimit(int invno);
|
||||
|
@ -134,9 +156,13 @@ void InvSetSize(int invno, int MinWidth, int MinHeight,
|
|||
int WhichInventoryOpen(void);
|
||||
|
||||
bool IsTopWindow(void);
|
||||
bool IsConfWindow(void);
|
||||
bool MenuActive(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
|
||||
|
||||
#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 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 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
|
||||
#define MIN_INT (1 << (8*sizeof(int) - 1))
|
||||
|
@ -70,8 +69,7 @@ typedef int HPOLYGON;
|
|||
#define FIELD_WORLD 0
|
||||
#define FIELD_STATUS 1
|
||||
|
||||
|
||||
|
||||
#define ZSHIFT 10
|
||||
|
||||
// We don't set the Z position for print and talk text
|
||||
// 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_SAVED_ACTORS 32 // Saved 'Normal' actors
|
||||
#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()
|
||||
#define NO_ENTRY_NUM (-3458) // Magic unlikely number
|
||||
|
@ -110,13 +109,19 @@ typedef int HPOLYGON;
|
|||
|
||||
// Language for the resource strings
|
||||
enum LANGUAGE {
|
||||
TXT_ENGLISH,
|
||||
TXT_FRENCH,
|
||||
TXT_GERMAN,
|
||||
TXT_ITALIAN,
|
||||
TXT_SPANISH
|
||||
TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN, TXT_ITALIAN, TXT_SPANISH,
|
||||
TXT_HEBREW, TXT_HUNGARIAN, TXT_JAPANESE, TXT_US,
|
||||
NUM_LANGUAGES
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
#endif // TINSEL_DW_H
|
||||
|
|
|
@ -41,13 +41,14 @@
|
|||
#include "tinsel/polygons.h"
|
||||
#include "tinsel/rince.h"
|
||||
#include "tinsel/sched.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
struct EP_INIT {
|
||||
HPOLYGON hEpoly;
|
||||
PMACTOR pActor;
|
||||
PMOVER pMover;
|
||||
int index;
|
||||
};
|
||||
|
||||
|
@ -61,24 +62,32 @@ static void EffectProcess(CORO_PARAM, const void *param) {
|
|||
CORO_BEGIN_CONTEXT;
|
||||
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);
|
||||
|
||||
int x, y; // Lead actor position
|
||||
|
||||
// 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 {
|
||||
CORO_SLEEP(1);
|
||||
GetMActorPosition(to->pActor, &x, &y);
|
||||
GetMoverPosition(to->pMover, &x, &y);
|
||||
} while (InPolygon(x, y, EFFECT) == to->hEpoly);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
@ -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
|
||||
* 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;
|
||||
EP_INIT epi;
|
||||
|
||||
|
@ -97,10 +106,10 @@ static void FettleEffectPolys(int x, int y, int index, PMACTOR pActor) {
|
|||
hPoly = InPolygon(x, y, EFFECT);
|
||||
if (hPoly != NOPOLY) {
|
||||
//Just entered effect polygon
|
||||
SetMAinEffectPoly(index, true);
|
||||
SetMoverInEffect(index, true);
|
||||
|
||||
epi.hEpoly = hPoly;
|
||||
epi.pActor = pActor;
|
||||
epi.pMover = pActor;
|
||||
epi.index = index;
|
||||
g_scheduler->createProcess(PID_TCODE, EffectProcess, &epi, sizeof(epi));
|
||||
}
|
||||
|
@ -118,10 +127,10 @@ void EffectPolyProcess(CORO_PARAM, const void *param) {
|
|||
CORO_BEGIN_CODE(_ctx);
|
||||
while (1) {
|
||||
for (int i = 0; i < MAX_MOVERS; i++) {
|
||||
PMACTOR pActor = GetLiveMover(i);
|
||||
PMOVER pActor = GetLiveMover(i);
|
||||
if (pActor != NULL) {
|
||||
int x, y;
|
||||
GetMActorPosition(pActor, &x, &y);
|
||||
GetMoverPosition(pActor, &x, &y);
|
||||
FettleEffectPolys(x, y, i, pActor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,14 +26,17 @@
|
|||
*/
|
||||
|
||||
#include "tinsel/actors.h"
|
||||
#include "tinsel/background.h"
|
||||
#include "tinsel/config.h"
|
||||
#include "tinsel/coroutine.h"
|
||||
#include "tinsel/cursor.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/events.h"
|
||||
#include "tinsel/handle.h" // For LockMem()
|
||||
#include "tinsel/inventory.h"
|
||||
#include "tinsel/dialogs.h"
|
||||
#include "tinsel/move.h" // For walking lead actor
|
||||
#include "tinsel/pcode.h" // For Interpret()
|
||||
#include "tinsel/pdisplay.h"
|
||||
#include "tinsel/pid.h"
|
||||
#include "tinsel/polygons.h"
|
||||
#include "tinsel/rince.h" // For walking lead actor
|
||||
|
@ -41,6 +44,7 @@
|
|||
#include "tinsel/scroll.h" // For DontScrollCursor()
|
||||
#include "tinsel/timers.h" // DwGetCurrentTime()
|
||||
#include "tinsel/tinlib.h" // For control()
|
||||
#include "tinsel/tinsel.h"
|
||||
#include "tinsel/token.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
@ -51,22 +55,25 @@ namespace Tinsel {
|
|||
extern int GetTaggedActor(void);
|
||||
extern HPOLYGON GetTaggedPoly(void);
|
||||
|
||||
|
||||
//----------------- EXTERNAL GLOBAL DATA ---------------------
|
||||
|
||||
extern bool bEnableF1;
|
||||
|
||||
extern bool bEnableMenu;
|
||||
|
||||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
||||
static int userEvents = 0; // Whenever a button or a key comes in
|
||||
static uint32 lastUserEvent = 0; // Time it hapenned
|
||||
static int butEvents = 0; // Single or double, left or right. Or escape key.
|
||||
static int escEvents = 0; // Escape key
|
||||
|
||||
static int leftEvents = 0; // Single or double, left or right. Or 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 controlState;
|
||||
static bool bStartOff;
|
||||
|
||||
static int controlX, controlY;
|
||||
static bool bProvNotProcessed = false;
|
||||
|
||||
/**
|
||||
* Gets called before each schedule, only 1 user action per schedule
|
||||
* is allowed.
|
||||
|
@ -87,12 +94,12 @@ void IncUserEvents(void) {
|
|||
* If this is a double click, the process from the waiting single click
|
||||
* gets killed.
|
||||
*/
|
||||
void AllowDclick(CORO_PARAM, BUTEVENT be) {
|
||||
void AllowDclick(CORO_PARAM, PLR_EVENT be) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
if (be == BE_SLEFT) {
|
||||
if (be == PLR_SLEFT) {
|
||||
GetToken(TOKEN_LEFT_BUT);
|
||||
CORO_SLEEP(dclickSpeed+1);
|
||||
FreeToken(TOKEN_LEFT_BUT);
|
||||
|
@ -103,94 +110,120 @@ void AllowDclick(CORO_PARAM, BUTEVENT be) {
|
|||
|
||||
break;
|
||||
|
||||
} else if (be == BE_DLEFT) {
|
||||
} else if (be == PLR_DLEFT) {
|
||||
GetToken(TOKEN_LEFT_BUT);
|
||||
FreeToken(TOKEN_LEFT_BUT);
|
||||
}
|
||||
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.
|
||||
* Return TRUE if control taken, FALSE if not.
|
||||
*/
|
||||
|
||||
bool GetControl(int param) {
|
||||
if (TestToken(TOKEN_CONTROL)) {
|
||||
control(param);
|
||||
if (TinselV2)
|
||||
return GetControl();
|
||||
|
||||
else if (TestToken(TOKEN_CONTROL)) {
|
||||
Control(param);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
struct TP_INIT {
|
||||
HPOLYGON hPoly; // Polygon
|
||||
USER_EVENT event; // Trigerring event
|
||||
BUTEVENT bev; // To allow for double clicks
|
||||
bool take_control; // Set if control should be taken
|
||||
// while code is running.
|
||||
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 GetControl(void) {
|
||||
if (controlState == CONTROL_ON) {
|
||||
ControlOff();
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs glitter code associated with a polygon.
|
||||
*/
|
||||
void RunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, BUTEVENT be, bool tc) {
|
||||
TP_INIT to = { hPoly, event, be, tc, 0 };
|
||||
bool ControlIsOn(void) {
|
||||
if (TinselV2)
|
||||
return (controlState == CONTROL_ON);
|
||||
|
||||
g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
|
||||
}
|
||||
|
||||
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));
|
||||
return TestToken(TOKEN_CONTROL);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -206,22 +239,33 @@ struct WP_INIT {
|
|||
static void WalkProcess(CORO_PARAM, const void *param) {
|
||||
// COROUTINE
|
||||
CORO_BEGIN_CONTEXT;
|
||||
PMACTOR pActor;
|
||||
PMOVER pMover;
|
||||
int thisWalk;
|
||||
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);
|
||||
|
||||
_ctx->pActor = GetMover(LEAD_ACTOR);
|
||||
if (_ctx->pActor->MActorState == NORM_MACTOR) {
|
||||
assert(_ctx->pActor->hCpath != NOPOLY); // Lead actor is not in a path
|
||||
_ctx->pMover = GetMover(LEAD_ACTOR);
|
||||
|
||||
GetToken(TOKEN_LEAD);
|
||||
SetActorDest(_ctx->pActor, to->x, to->y, false, 0);
|
||||
if (TinselV2 && MoverIs(_ctx->pMover) && !MoverIsSWalking(_ctx->pMover)) {
|
||||
assert(_ctx->pMover->hCpath != NOPOLY); // Lead actor is not in a path
|
||||
|
||||
_ctx->thisWalk = SetActorDest(_ctx->pMover, to->x, to->y, false, 0);
|
||||
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);
|
||||
|
||||
FreeToken(TOKEN_LEAD);
|
||||
|
@ -230,7 +274,7 @@ static void WalkProcess(CORO_PARAM, const void *param) {
|
|||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void walkto(int x, int y) {
|
||||
void WalkTo(int x, int y) {
|
||||
WP_INIT to = { x, y };
|
||||
|
||||
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.
|
||||
* 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 aniX, aniY;
|
||||
HPOLYGON hPoly;
|
||||
|
@ -249,19 +293,34 @@ static void User_Event(USER_EVENT uEvent, BUTEVENT be) {
|
|||
if (++eCount != 1)
|
||||
return;
|
||||
|
||||
if ((actor = GetTaggedActor()) != 0)
|
||||
actorEvent(actor, uEvent, be);
|
||||
else if ((hPoly = GetTaggedPoly()) != NOPOLY)
|
||||
if ((actor = GetTaggedActor()) != 0) {
|
||||
// Event for a tagged actor
|
||||
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);
|
||||
else {
|
||||
else if (uEvent != PROV_WALKTO)
|
||||
PolygonEvent(nullContext, hPoly, uEvent, 0, false, 0);
|
||||
|
||||
} else {
|
||||
GetCursorXY(&aniX, &aniY, true);
|
||||
|
||||
// There could be a poly involved which has no tag.
|
||||
if ((hPoly = InPolygon(aniX, aniY, TAG)) != NOPOLY
|
||||
|| (hPoly = InPolygon(aniX, aniY, EXIT)) != NOPOLY) {
|
||||
if ((hPoly = InPolygon(aniX, aniY, TAG)) != 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);
|
||||
} else if (uEvent == WALKTO)
|
||||
walkto(aniX, aniY);
|
||||
} else if ((uEvent == PROV_WALKTO) || (uEvent == WALKTO)) {
|
||||
if (TinselV2)
|
||||
ProcessedProvisional();
|
||||
WalkTo(aniX, aniY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,137 +328,155 @@ static void User_Event(USER_EVENT uEvent, BUTEVENT be) {
|
|||
/**
|
||||
* ProcessButEvent
|
||||
*/
|
||||
void ProcessButEvent(BUTEVENT be) {
|
||||
IncUserEvents();
|
||||
|
||||
void ProcessButEvent(PLR_EVENT be) {
|
||||
if (bSwapButtons) {
|
||||
switch (be) {
|
||||
case BE_SLEFT:
|
||||
be = BE_SRIGHT;
|
||||
case PLR_SLEFT:
|
||||
be = PLR_SRIGHT;
|
||||
break;
|
||||
case BE_DLEFT:
|
||||
be = BE_DRIGHT;
|
||||
case PLR_DLEFT:
|
||||
be = PLR_DRIGHT;
|
||||
break;
|
||||
case BE_SRIGHT:
|
||||
be = BE_SLEFT;
|
||||
case PLR_SRIGHT:
|
||||
be = PLR_SLEFT;
|
||||
break;
|
||||
case BE_DRIGHT:
|
||||
be = BE_DLEFT;
|
||||
case PLR_DRIGHT:
|
||||
be = PLR_DLEFT;
|
||||
break;
|
||||
case BE_LDSTART:
|
||||
be = BE_RDSTART;
|
||||
case PLR_DRAG1_START:
|
||||
be = PLR_DRAG2_START;
|
||||
break;
|
||||
case BE_LDEND:
|
||||
be = BE_RDEND;
|
||||
case PLR_DRAG1_END:
|
||||
be = PLR_DRAG2_END;
|
||||
break;
|
||||
case BE_RDSTART:
|
||||
be = BE_LDSTART;
|
||||
case PLR_DRAG2_START:
|
||||
be = PLR_DRAG1_START;
|
||||
break;
|
||||
case BE_RDEND:
|
||||
be = BE_LDEND;
|
||||
case PLR_DRAG2_END:
|
||||
be = PLR_DRAG1_END;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if (be == BE_SLEFT || be == BE_DLEFT || be == BE_SRIGHT || be == BE_DRIGHT)
|
||||
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;
|
||||
}
|
||||
}
|
||||
PlayerEvent(be, _vm->getMousePosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
if (bEnableF1 && ke == OPTION_KEY)
|
||||
control(CONTROL_ON);
|
||||
if (bEnableMenu && pEvent == PLR_MENU)
|
||||
Control(CONTROL_ON);
|
||||
else
|
||||
IncUserEvents();
|
||||
|
||||
if (ke == ESC_KEY) {
|
||||
escEvents++;
|
||||
butEvents++; // Yes, I do mean this
|
||||
if (pEvent == PLR_ESCAPE) {
|
||||
++escEvents;
|
||||
++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
|
||||
if (!TestToken(TOKEN_CONTROL) && (BUTEVENT)ke != BE_LDEND)
|
||||
// Only allow events if player control is on
|
||||
if (!ControlIsOn() && (pEvent != PLR_DRAG1_END))
|
||||
return;
|
||||
|
||||
switch (ke) {
|
||||
case QUIT_KEY:
|
||||
PopUpConf(QUIT);
|
||||
if (TinselV2 && InventoryActive()) {
|
||||
int x, y;
|
||||
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;
|
||||
|
||||
case OPTION_KEY:
|
||||
PopUpConf(OPTION);
|
||||
case PLR_MENU:
|
||||
OpenMenu(MAIN_MENU);
|
||||
break;
|
||||
|
||||
case SAVE_KEY:
|
||||
PopUpConf(SAVE);
|
||||
case PLR_JUMP:
|
||||
OpenMenu(HOPPER_MENU1);
|
||||
break;
|
||||
|
||||
case LOAD_KEY:
|
||||
PopUpConf(LOAD);
|
||||
case PLR_SAVE:
|
||||
OpenMenu(SAVE_MENU);
|
||||
break;
|
||||
|
||||
case WALKTO_KEY:
|
||||
if (InventoryActive())
|
||||
ButtonToInventory(BE_SLEFT);
|
||||
case PLR_LOAD:
|
||||
OpenMenu(LOAD_MENU);
|
||||
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
|
||||
User_Event(WALKTO, BE_NONE);
|
||||
EventToInventory(PLR_SLEFT, coOrds);
|
||||
break;
|
||||
|
||||
case ACTION_KEY:
|
||||
if (InventoryActive())
|
||||
ButtonToInventory(BE_DLEFT);
|
||||
case PLR_ACTION:
|
||||
REAL_ACTION_CHECK;
|
||||
|
||||
if (TinselV2 || !InventoryActive())
|
||||
ProcessUserEvent(ACTION, coOrds, PLR_DLEFT);
|
||||
else
|
||||
User_Event(ACTION, BE_NONE);
|
||||
EventToInventory(PLR_DLEFT, coOrds);
|
||||
break;
|
||||
|
||||
case LOOK_KEY:
|
||||
if (InventoryActive())
|
||||
ButtonToInventory(BE_SRIGHT);
|
||||
case PLR_LOOK:
|
||||
REAL_ACTION_CHECK;
|
||||
|
||||
if (TinselV2 || !InventoryActive())
|
||||
ProcessUserEvent(LOOK, coOrds, PLR_SRIGHT);
|
||||
else
|
||||
User_Event(LOOK, BE_NONE);
|
||||
break;
|
||||
|
||||
case ESC_KEY:
|
||||
case PGUP_KEY:
|
||||
case PGDN_KEY:
|
||||
case HOME_KEY:
|
||||
case END_KEY:
|
||||
if (InventoryActive())
|
||||
KeyToInventory(ke);
|
||||
EventToInventory(PLR_SRIGHT, coOrds);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (InventoryActive())
|
||||
EventToInventory(pEvent, coOrds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +484,6 @@ void ProcessKeyEvent(KEYEVENT ke) {
|
|||
/**
|
||||
* For ESCapable Glitter sequences
|
||||
*/
|
||||
|
||||
int GetEscEvents(void) {
|
||||
return escEvents;
|
||||
}
|
||||
|
@ -415,15 +491,21 @@ int GetEscEvents(void) {
|
|||
/**
|
||||
* For cutting short talk()s etc.
|
||||
*/
|
||||
|
||||
int GetLeftEvents(void) {
|
||||
return butEvents;
|
||||
return leftEvents;
|
||||
}
|
||||
|
||||
bool LeftEventChange(int myleftEvent) {
|
||||
if (leftEvents != myleftEvent) {
|
||||
ProcessedProvisional();
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* For waitkey() Glitter function
|
||||
*/
|
||||
|
||||
int getUserEvents(void) {
|
||||
return userEvents;
|
||||
}
|
||||
|
@ -436,4 +518,154 @@ void resetUserEventTime(void) {
|
|||
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
|
||||
|
|
|
@ -29,49 +29,99 @@
|
|||
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/coroutine.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
/*
|
||||
enum BUTEVENT {
|
||||
BE_NONE, BE_SLEFT, BE_DLEFT, BE_SRIGHT, BE_DRIGHT,
|
||||
BE_LDSTART, BE_LDEND, BE_RDSTART, BE_RDEND,
|
||||
BE_UNKNOWN
|
||||
PLR_NOEVENT, PLR_SLEFT, PLR_DLEFT, PLR_SRIGHT, PLR_DRIGHT,
|
||||
PLR_DRAG1_START, PLR_DRAG1_END, PLR_DRAG2_START, PLR_DRAG2_END,
|
||||
PLR_UNKNOWN
|
||||
};
|
||||
|
||||
|
||||
enum KEYEVENT {
|
||||
ESC_KEY, QUIT_KEY, SAVE_KEY, LOAD_KEY, OPTION_KEY,
|
||||
PGUP_KEY, PGDN_KEY, HOME_KEY, END_KEY,
|
||||
WALKTO_KEY, ACTION_KEY, LOOK_KEY,
|
||||
PLR_ESCAPE, PLR_QUIT, PLR_SAVE, PLR_LOAD, PLR_MENU,
|
||||
PLR_PGUP, PLR_PGDN, PLR_HOME, PLR_END,
|
||||
PLR_WALKTO, PLR_ACTION, PLR_LOOK,
|
||||
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.
|
||||
* Do not re-order these as equivalent CONSTs are defined in the master
|
||||
* 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 {
|
||||
POINTED, WALKTO, ACTION, LOOK,
|
||||
ENTER, LEAVE, STARTUP, CONVERSE,
|
||||
UNPOINT, PUTDOWN,
|
||||
NOEVENT
|
||||
enum TINSEL_EVENT {
|
||||
NOEVENT, STARTUP, CLOSEDOWN, POINTED, UNPOINT, WALKIN, WALKOUT,
|
||||
PICKUP, PUTDOWN, WALKTO, LOOK, ACTION, CONVERSE, SHOWEVENT,
|
||||
HIDEEVENT, TALKING, ENDTALK, LEAVE_T2, RESTORE, PROV_WALKTO
|
||||
};
|
||||
|
||||
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(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 effRunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, int actor);
|
||||
void RunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, PLR_EVENT be, bool tc);
|
||||
void effRunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, int actor);
|
||||
|
||||
void ProcessButEvent(BUTEVENT be);
|
||||
void ProcessKeyEvent(KEYEVENT ke);
|
||||
void ProcessButEvent(PLR_EVENT be);
|
||||
void ProcessKeyEvent(PLR_EVENT ke);
|
||||
|
||||
|
||||
int GetEscEvents(void);
|
||||
int GetLeftEvents(void);
|
||||
bool LeftEventChange(int myleftEvent);
|
||||
|
||||
int getUserEvents(void);
|
||||
|
||||
uint32 getUserEventTime(void);
|
||||
|
@ -79,6 +129,16 @@ void resetUserEventTime(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
|
||||
|
||||
#endif /* TINSEL_EVENTS_H */
|
||||
|
|
|
@ -24,11 +24,14 @@
|
|||
* Palette Fader and Flasher processes.
|
||||
*/
|
||||
|
||||
#include "tinsel/pid.h" // list of all process IDs
|
||||
#include "tinsel/sched.h" // scheduler defs
|
||||
#include "tinsel/actors.h"
|
||||
#include "tinsel/faders.h" // fader defs
|
||||
#include "tinsel/handle.h"
|
||||
#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 {
|
||||
|
||||
|
@ -40,9 +43,7 @@ struct FADE {
|
|||
|
||||
// fixed point fade multiplier tables
|
||||
//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, 0x4000, 0x7000, 0xa000, 0xd000, 0x10000L, -1};
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
for (int i = 0; i < numColours; i++, pNew++, pOrig++) {
|
||||
if (!TinselV2)
|
||||
// apply multiplier to RGB components
|
||||
*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);
|
||||
|
||||
// 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);
|
||||
|
||||
if (TinselV2)
|
||||
// Note that this palette is being faded
|
||||
FadingPalette(pFade->pPalQ, true);
|
||||
|
||||
// get pointer to palette - reduce pointer indirection a bit
|
||||
_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
|
||||
|
||||
// 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,
|
||||
FROM_LE_32(_ctx->pPalette->numColours), (uint32) *_ctx->pColMult);
|
||||
|
||||
|
@ -110,6 +129,10 @@ static void FadeProcess(CORO_PARAM, const void *param) {
|
|||
CORO_SLEEP(1);
|
||||
}
|
||||
|
||||
if (TinselV2)
|
||||
// Note that this palette is being faded
|
||||
FadingPalette(pFade->pPalQ, false);
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
|
@ -122,6 +145,13 @@ static void FadeProcess(CORO_PARAM, const void *param) {
|
|||
static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) {
|
||||
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
|
||||
for (pPal = GetNextPalette(NULL); pPal != NULL; pPal = GetNextPalette(pPal)) {
|
||||
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.
|
||||
* @param noFadeTable A NULL terminated list of palettes not to fade.
|
||||
*/
|
||||
void FadeOutFast(SCNHANDLE noFadeTable[]) {
|
||||
// Fixed point fade multiplier table
|
||||
static const long fadeout[] = {0xd000, 0xa000, 0x7000, 0x4000, 0x1000, 0, -1};
|
||||
|
||||
// call generic fader
|
||||
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.
|
||||
* @param noFadeTable A NULL terminated list of palettes not to fade.
|
||||
*/
|
||||
void FadeInFast(SCNHANDLE noFadeTable[]) {
|
||||
// Fade multiplier table
|
||||
static const long fadein[] = {0, 0x1000, 0x4000, 0x7000, 0xa000, 0xd000, 0x10000L, -1};
|
||||
|
||||
// call generic fader
|
||||
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
|
||||
|
|
|
@ -28,16 +28,15 @@
|
|||
#define TINSEL_FADERS_H
|
||||
|
||||
#include "tinsel/dw.h" // for SCNHANDLE
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
enum {
|
||||
/**
|
||||
/**
|
||||
* 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 *|
|
||||
|
@ -47,8 +46,11 @@ enum {
|
|||
// should not be faded. This parameter can be
|
||||
// NULL - fade all palettes.
|
||||
|
||||
void FadeOutMedium(SCNHANDLE noFadeTable[]);
|
||||
void FadeOutFast(SCNHANDLE noFadeTable[]);
|
||||
void FadeInMedium(SCNHANDLE noFadeTable[]);
|
||||
void FadeInFast(SCNHANDLE noFadeTable[]);
|
||||
void PokeInTagColour(void);
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
||||
|
|
|
@ -22,11 +22,14 @@
|
|||
* $Id$
|
||||
*/
|
||||
|
||||
#include "tinsel/actors.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/font.h"
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/object.h"
|
||||
#include "tinsel/sysvar.h"
|
||||
#include "tinsel/text.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
|
@ -35,48 +38,63 @@ namespace Tinsel {
|
|||
static char tBuffer[TBUFSZ];
|
||||
|
||||
static SCNHANDLE hTagFont = 0, hTalkFont = 0;
|
||||
static SCNHANDLE hRegularTalkFont = 0, hRegularTagFont = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Return address of tBuffer
|
||||
*/
|
||||
char *tBufferAddr() {
|
||||
char *TextBufferAddr() {
|
||||
return tBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return hTagFont handle.
|
||||
*/
|
||||
SCNHANDLE hTagFontHandle() {
|
||||
SCNHANDLE GetTagFontHandle() {
|
||||
return hTagFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return hTalkFont handle.
|
||||
*/
|
||||
SCNHANDLE hTalkFontHandle() {
|
||||
SCNHANDLE GetTalkFontHandle() {
|
||||
return hTalkFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from dec_tagfont() Glitter function. Store the tag font handle.
|
||||
*/
|
||||
void TagFontHandle(SCNHANDLE hf) {
|
||||
hTagFont = hf; // Store the font handle
|
||||
void SetTagFontHandle(SCNHANDLE hFont) {
|
||||
hTagFont = hRegularTagFont = hFont; // Store the font handle
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from dec_talkfont() Glitter function.
|
||||
* Store the talk font handle.
|
||||
*/
|
||||
void TalkFontHandle(SCNHANDLE hf) {
|
||||
hTalkFont = hf; // Store the font handle
|
||||
void SetTalkFontHandle(SCNHANDLE hFont) {
|
||||
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.
|
||||
*/
|
||||
void fettleFontPal(SCNHANDLE fontPal) {
|
||||
void FettleFontPal(SCNHANDLE fontPal) {
|
||||
const FONT *pFont;
|
||||
IMAGE *pImg;
|
||||
|
||||
|
@ -86,11 +104,23 @@ void fettleFontPal(SCNHANDLE fontPal) {
|
|||
|
||||
pFont = (const FONT *)LockMem(hTagFont);
|
||||
pImg = (IMAGE *)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0
|
||||
if (!TinselV2)
|
||||
pImg->hImgPal = TO_LE_32(fontPal);
|
||||
else
|
||||
pImg->hImgPal = 0;
|
||||
|
||||
pFont = (const FONT *)LockMem(hTalkFont);
|
||||
pImg = (IMAGE *)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0
|
||||
if (!TinselV2)
|
||||
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
|
||||
|
|
|
@ -31,17 +31,27 @@
|
|||
namespace Tinsel {
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
char *tBufferAddr(void);
|
||||
SCNHANDLE hTagFontHandle(void);
|
||||
SCNHANDLE hTalkFontHandle(void);
|
||||
char *TextBufferAddr(void);
|
||||
|
||||
void TagFontHandle(SCNHANDLE hf);
|
||||
void TalkFontHandle(SCNHANDLE hf);
|
||||
void fettleFontPal(SCNHANDLE fontPal);
|
||||
SCNHANDLE GetTagFontHandle(void);
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "tinsel/handle.h" // LockMem()
|
||||
#include "tinsel/object.h"
|
||||
#include "tinsel/palette.h"
|
||||
#include "tinsel/scene.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
@ -46,7 +47,6 @@ extern uint8 transPalette[MAX_COLOURS];
|
|||
/**
|
||||
* Straight rendering with transparency support
|
||||
*/
|
||||
|
||||
static void WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping) {
|
||||
// Set up the offset between destination blocks
|
||||
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
|
||||
*/
|
||||
|
||||
static void WrtConst(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
||||
if (applyClipping) {
|
||||
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
|
||||
* lookup table from transpal.cpp (the contents of which have been moved into palette.cpp)
|
||||
*/
|
||||
|
||||
static void WrtTrans(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
||||
if (applyClipping) {
|
||||
pObj->height -= pObj->topClip + pObj->botClip;
|
||||
|
@ -204,165 +284,135 @@ static void WrtTrans(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// This commented out code is the untested original WrtNonZero/ClpWrtNonZero combo method
|
||||
// from the v1 source. It may be needed to be included later on to support v1 gfx files
|
||||
|
||||
/**
|
||||
* Straight rendering with transparency support
|
||||
* Possibly only used in the Discworld Demo
|
||||
* 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;
|
||||
|
||||
static void DemoWrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping) {
|
||||
// FIXME: If this method is used for the demo, it still needs to be made Endian safe
|
||||
if (applyClipping) {
|
||||
srcP += (pObj->topClip * pObj->width) + pObj->leftClip;
|
||||
|
||||
// Set up the offset between destination lines
|
||||
pObj->lineoffset = SCREEN_WIDTH - pObj->width - (applyClipping ? pObj->leftClip - pObj->rightClip : 0);
|
||||
pObj->height -= pObj->topClip + pObj->botClip;
|
||||
pObj->width -= pObj->leftClip + pObj->rightClip;
|
||||
|
||||
// Top clipped line handling
|
||||
while (applyClipping && (pObj->topClip > 0)) {
|
||||
// Loop through discarding the data for the line
|
||||
int width = pObj->width;
|
||||
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;
|
||||
}
|
||||
if (pObj->width <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
--pObj->height;
|
||||
--pObj->topClip;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (width < pObj->rightClip)
|
||||
width = 0;
|
||||
}
|
||||
|
||||
// Handling for the visible part of the line
|
||||
int endWidth = applyClipping ? pObj->rightClip : 0;
|
||||
while (width > endWidth) {
|
||||
int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP);
|
||||
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;
|
||||
for (int y = 0; y < pObj->height; ++y) {
|
||||
Common::copy(srcP, srcP + pObj->width, destP);
|
||||
srcP += objWidth;
|
||||
destP += SCREEN_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a packed data stream with a variable sized palette
|
||||
*/
|
||||
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;
|
||||
|
||||
if (applyClipping) {
|
||||
pObj->height -= pObj->botClip;
|
||||
topClip = pObj->topClip;
|
||||
}
|
||||
|
||||
if (packingType == 3) {
|
||||
// Variable colours
|
||||
numColours = *srcP++;
|
||||
colourTable = srcP;
|
||||
srcP += numColours;
|
||||
}
|
||||
|
||||
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);
|
||||
bool eolFlag = false;
|
||||
|
||||
// Get offset for first pixels in next line
|
||||
xOffset = *srcP++;
|
||||
|
||||
int x = 0;
|
||||
while (x < pObj->width) {
|
||||
// Get next run size and colour to use
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (eolFlag)
|
||||
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;
|
||||
}
|
||||
}
|
||||
assert(x <= pObj->width);
|
||||
|
||||
if (!eolFlag) {
|
||||
// Assert that the next bytes signal a line end
|
||||
assert((*srcP++ & 0xf) == 0);
|
||||
assert(*srcP++ == 0);
|
||||
}
|
||||
|
||||
if (topClip > 0)
|
||||
--topClip;
|
||||
else
|
||||
destP += SCREEN_WIDTH;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------- MAIN FUNCTIONS ---------------------
|
||||
|
||||
|
@ -380,8 +430,10 @@ void ClearScreen() {
|
|||
* Updates the screen surface within the following rectangle
|
||||
*/
|
||||
void UpdateScreenRect(const Common::Rect &pClip) {
|
||||
byte *pDest = (byte *)_vm->screen().getBasePtr(pClip.left, pClip.top);
|
||||
g_system->copyRectToScreen(pDest, _vm->screen().pitch, pClip.left, pClip.top, pClip.width(), pClip.height());
|
||||
int yOffset = (g_system->getHeight() - SCREEN_HEIGHT) / 2;
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -398,18 +450,76 @@ void DrawObject(DRAWOBJECT *pObj) {
|
|||
|
||||
// If writing constant data, don't bother locking the data pointer and reading src details
|
||||
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->transOffset = READ_LE_UINT32(p + 0x14);
|
||||
}
|
||||
}
|
||||
|
||||
// Get destination starting point
|
||||
destPtr = (byte *)_vm->screen().getBasePtr(pObj->xPos, pObj->yPos);
|
||||
|
||||
// Handle various draw types
|
||||
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) {
|
||||
case 0x01:
|
||||
case 0x08:
|
||||
|
@ -420,7 +530,7 @@ void DrawObject(DRAWOBJECT *pObj) {
|
|||
|
||||
case 0x04:
|
||||
case 0x44:
|
||||
// ClpWrtConst with/without clipping
|
||||
// WrtConst with/without clipping
|
||||
WrtConst(pObj,destPtr, typeId == 0x44);
|
||||
break;
|
||||
|
||||
|
@ -435,6 +545,7 @@ void DrawObject(DRAWOBJECT *pObj) {
|
|||
error("Unknown drawing type %d", typeId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Tinsel
|
||||
|
|
|
@ -37,12 +37,6 @@ namespace Tinsel {
|
|||
|
||||
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 */
|
||||
struct DRAWOBJECT {
|
||||
char *charBase; // character set base address
|
||||
|
@ -60,6 +54,7 @@ struct DRAWOBJECT {
|
|||
int botClip; // amount to clip off object bottom
|
||||
short xPos; // x position of object
|
||||
short yPos; // y position of object
|
||||
uint32 baseCol; // For 4-bit stuff
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "tinsel/drives.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/scn.h" // name of "index" file
|
||||
#include "tinsel/handle.h"
|
||||
|
@ -41,6 +42,8 @@
|
|||
#include "tinsel/object.h"
|
||||
#include "tinsel/palette.h"
|
||||
#include "tinsel/text.h"
|
||||
#include "tinsel/timers.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
#include "tinsel/scene.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
@ -58,6 +61,7 @@ struct MEMHANDLE {
|
|||
char szName[12]; //!< 00 - file name of graphics file
|
||||
int32 filesize; //!< 12 - file size and flags
|
||||
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 MALLOC_MASK 0xFF000000L //!< mask to isolate the memory allocation flags
|
||||
#define OFFSETMASK 0x007fffffL //!< get offset of address
|
||||
//#define HANDLEMASK 0xFF800000L //!< get handle of address
|
||||
|
||||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
@ -83,6 +86,13 @@ static MEMHANDLE *handleTable = 0;
|
|||
// number of handles in the handle table
|
||||
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 --------------------
|
||||
|
||||
|
@ -94,7 +104,8 @@ static void LoadFile(MEMHANDLE *pH, bool bWarn); // load a memory block as a fil
|
|||
* permanent graphics etc.
|
||||
*/
|
||||
void SetupHandleTable(void) {
|
||||
enum { RECORD_SIZE = 20 };
|
||||
bool t2Flag = (TinselVersion == TINSEL_V2);
|
||||
int RECORD_SIZE = t2Flag ? 24 : 20;
|
||||
|
||||
int len;
|
||||
uint i;
|
||||
|
@ -108,7 +119,7 @@ void SetupHandleTable(void) {
|
|||
if (len > 0) {
|
||||
if ((len % RECORD_SIZE) != 0) {
|
||||
// index file is corrupt
|
||||
error("File %s is corrupt", INDEX_FILENAME);
|
||||
error(FILE_IS_CORRUPT, INDEX_FILENAME);
|
||||
}
|
||||
|
||||
// calc number of handles
|
||||
|
@ -128,31 +139,36 @@ void SetupHandleTable(void) {
|
|||
// need to read that from the file.
|
||||
handleTable[i].pNode = NULL;
|
||||
f.seek(4, SEEK_CUR);
|
||||
// For Discworld 2, read in the flags2 field
|
||||
handleTable[i].flags2 = t2Flag ? f.readUint32LE() : 0;
|
||||
}
|
||||
|
||||
if (f.ioFailed()) {
|
||||
// index file is corrupt
|
||||
error("File %s is corrupt", INDEX_FILENAME);
|
||||
error(FILE_IS_CORRUPT, INDEX_FILENAME);
|
||||
}
|
||||
|
||||
// close the file
|
||||
f.close();
|
||||
} else { // index file is corrupt
|
||||
error("File %s is corrupt", INDEX_FILENAME);
|
||||
error(FILE_IS_CORRUPT, INDEX_FILENAME);
|
||||
}
|
||||
} 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
|
||||
for (i = 0, pH = handleTable; i < numHandles; i++, pH++) {
|
||||
if (pH->filesize & fPreload) {
|
||||
// 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
|
||||
assert(pH->pNode);
|
||||
|
||||
// Initialise the MEM_NODE structure
|
||||
memset(pH->pNode, 0, sizeof(MEM_NODE));
|
||||
|
||||
// load the data
|
||||
LoadFile(pH, true);
|
||||
}
|
||||
|
@ -178,8 +194,101 @@ void FreeHandleTable(void) {
|
|||
free(handleTable);
|
||||
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.
|
||||
* @param pH Memory block pointer
|
||||
|
@ -204,7 +313,7 @@ void LoadFile(MEMHANDLE *pH, bool bWarn) {
|
|||
|
||||
if (pH->filesize & fPreload)
|
||||
// preload - no need to lock the memory
|
||||
addr = (uint8 *)pH->pNode;
|
||||
addr = (uint8 *)pH->pNode + sizeof(MEM_NODE);
|
||||
else {
|
||||
// discardable - lock the memory
|
||||
addr = (uint8 *)MemoryLock(pH->pNode);
|
||||
|
@ -243,12 +352,12 @@ void LoadFile(MEMHANDLE *pH, bool bWarn) {
|
|||
|
||||
if (bWarn)
|
||||
// file is corrupt
|
||||
error("File %s is corrupt", szFilename);
|
||||
error(FILE_IS_CORRUPT, szFilename);
|
||||
}
|
||||
|
||||
if (bWarn)
|
||||
// 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;
|
||||
|
||||
if (pH->filesize & fPreload) {
|
||||
if (TinselV2)
|
||||
// update the LRU time (new in this file)
|
||||
pH->pNode->lruTime = DwGetCurrentTime();
|
||||
|
||||
// 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 {
|
||||
if (pH->pNode->pBaseAddr && (pH->filesize & fLoaded))
|
||||
// already allocated and loaded
|
||||
|
@ -312,7 +452,10 @@ void LockScene(SCNHANDLE offset) {
|
|||
|
||||
if ((pH->filesize & fPreload) == 0) {
|
||||
// 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
|
||||
bLockedScene = true;
|
||||
#endif
|
||||
|
@ -363,4 +506,50 @@ bool ValidHandle(SCNHANDLE offset) {
|
|||
}
|
||||
#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
|
||||
|
|
|
@ -48,6 +48,23 @@ void LockScene( // Called to make the current scene non-discardable
|
|||
void UnlockScene( // Called to make the current scene discardable again
|
||||
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
|
||||
|
||||
#endif // TINSEL_HANDLE_H
|
||||
|
|
|
@ -26,11 +26,13 @@
|
|||
|
||||
#include "tinsel/heapmem.h"
|
||||
#include "tinsel/timers.h" // For DwGetCurrentTime
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
// minimum memory required for MS-DOS version of game
|
||||
#define MIN_MEM 2506752L
|
||||
// Specifies the total amount of memory required for DW1 demo, DW1, or DW2 respectively.
|
||||
// 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
|
||||
MEM_NODE mnodeList[NUM_MNODES];
|
||||
|
@ -73,8 +75,10 @@ void MemoryInit(void) {
|
|||
// null the last mnode
|
||||
mnodeList[NUM_MNODES - 1].pNext = NULL;
|
||||
|
||||
// allocatea big chunk of memory
|
||||
const uint32 size = 2*MIN_MEM+655360L;
|
||||
// allocates a big chunk of memory
|
||||
uint32 size = MemoryPoolSize[0];
|
||||
if (TinselVersion == TINSEL_V1) size = MemoryPoolSize[1];
|
||||
else if (TinselVersion == TINSEL_V2) size = MemoryPoolSize[2];
|
||||
uint8 *mem = (uint8 *)malloc(size);
|
||||
assert(mem);
|
||||
|
||||
|
@ -274,8 +278,9 @@ MEM_NODE *MemoryAlloc(int flags, long size) {
|
|||
bool bCompacted = true; // set when heap has been compacted
|
||||
|
||||
// compact the heap if we are allocating fixed memory
|
||||
if (flags & DWM_FIXED)
|
||||
if (flags & DWM_FIXED) {
|
||||
HeapCompact(MAX_INT, false);
|
||||
}
|
||||
|
||||
while ((flags & DWM_NOALLOC) == 0 && bCompacted) {
|
||||
// search the heap for a free block
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* Functions to set up moving actors' reels.
|
||||
*/
|
||||
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/pcode.h" // For D_UP, D_DOWN
|
||||
#include "tinsel/rince.h"
|
||||
|
||||
|
@ -34,7 +35,7 @@ namespace Tinsel {
|
|||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
||||
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
|
||||
MAX_SCRENTRIES = NUM_INTERVALS*2*3
|
||||
|
@ -51,36 +52,80 @@ static SCIdataStruct SCIdata[MAX_SCRENTRIES];
|
|||
|
||||
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.
|
||||
*/
|
||||
SCNHANDLE GetMactorTalkReel(PMACTOR pActor, TFTYPE dirn) {
|
||||
SCNHANDLE GetMoverTalkReel(PMOVER pActor, TFTYPE dirn) {
|
||||
assert(1 <= pActor->scale && pActor->scale <= TOTAL_SCALES);
|
||||
switch (dirn) {
|
||||
case TF_NONE:
|
||||
return pActor->TalkReels[pActor->scale-1][pActor->dirn];
|
||||
return pActor->talkReels[pActor->scale-1][pActor->direction];
|
||||
|
||||
case TF_UP:
|
||||
return pActor->TalkReels[pActor->scale-1][AWAY];
|
||||
return pActor->talkReels[pActor->scale-1][AWAY];
|
||||
|
||||
case TF_DOWN:
|
||||
return pActor->TalkReels[pActor->scale-1][FORWARD];
|
||||
return pActor->talkReels[pActor->scale-1][FORWARD];
|
||||
|
||||
case TF_LEFT:
|
||||
return pActor->TalkReels[pActor->scale-1][LEFTREEL];
|
||||
return pActor->talkReels[pActor->scale-1][LEFTREEL];
|
||||
|
||||
case TF_RIGHT:
|
||||
return pActor->TalkReels[pActor->scale-1][RIGHTREEL];
|
||||
return pActor->talkReels[pActor->scale-1][RIGHTREEL];
|
||||
|
||||
default:
|
||||
error("GetMactorTalkReel() - illegal direction!");
|
||||
error("GetMoverTalkReel() - illegal direction!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
assert(scale >= 1 && scale <= NUM_MAINSCALES); // invalid scale
|
||||
assert(!(scale == 1 && direction == D_UP) &&
|
||||
|
@ -101,7 +146,7 @@ void setscalingreels(int actor, int scale, int direction,
|
|||
/**
|
||||
* ScalingReel
|
||||
*/
|
||||
SCNHANDLE ScalingReel(int ano, int scale1, int scale2, DIRREEL reel) {
|
||||
SCNHANDLE ScalingReel(int ano, int scale1, int scale2, DIRECTION reel) {
|
||||
int d; // Direction
|
||||
|
||||
// The smaller the number, the bigger the scale
|
||||
|
@ -129,4 +174,20 @@ void RebootScalingReels(void) {
|
|||
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
|
||||
|
|
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 \
|
||||
background.o \
|
||||
bg.o \
|
||||
bmv.o \
|
||||
cliprect.o \
|
||||
config.o \
|
||||
cursor.o \
|
||||
debugger.o \
|
||||
detection.o \
|
||||
dialogs.o \
|
||||
drives.o \
|
||||
effect.o \
|
||||
events.o \
|
||||
faders.o \
|
||||
|
@ -17,7 +20,6 @@ MODULE_OBJS = \
|
|||
graphics.o \
|
||||
handle.o \
|
||||
heapmem.o \
|
||||
inventory.o \
|
||||
mareels.o \
|
||||
move.o \
|
||||
multiobj.o \
|
||||
|
@ -37,6 +39,7 @@ MODULE_OBJS = \
|
|||
scroll.o \
|
||||
sound.o \
|
||||
strres.o \
|
||||
sysvar.o \
|
||||
text.o \
|
||||
timers.o \
|
||||
tinlib.o \
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,17 +27,24 @@
|
|||
#define TINSEL_MOVE_H
|
||||
|
||||
#include "tinsel/dw.h" // for SCNHANDLE
|
||||
#include "tinsel/rince.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
struct MACTOR;
|
||||
struct MOVER;
|
||||
|
||||
void SetActorDest(MACTOR *pActor, int x, int y, bool igPath, SCNHANDLE film);
|
||||
void SSetActorDest(MACTOR *pActor);
|
||||
void DoMoveActor(MACTOR *pActor);
|
||||
typedef enum { YB_X2, YB_X1_5 } YBIAS;
|
||||
|
||||
int SetActorDest(MOVER *pMover, int x, int y, bool igPath, SCNHANDLE film);
|
||||
void SSetActorDest(MOVER *pActor);
|
||||
void DoMoveActor(MOVER *pMover);
|
||||
|
||||
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
|
||||
|
||||
#endif /* TINSEL_MOVE_H */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "tinsel/multiobj.h"
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/object.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
|
@ -204,6 +205,8 @@ void MultiAdjustXY(OBJECT *pMultiObj, int deltaX, int deltaY) {
|
|||
if (deltaX == 0 && deltaY == 0)
|
||||
return; // ignore no change
|
||||
|
||||
if (!TinselV2) {
|
||||
// *** This may be wrong!!!
|
||||
if (pMultiObj->flags & DMA_FLIPH) {
|
||||
// image is flipped horizontally - flip the x direction
|
||||
deltaX = -deltaX;
|
||||
|
@ -213,6 +216,7 @@ void MultiAdjustXY(OBJECT *pMultiObj, int deltaX, int deltaY) {
|
|||
// image is flipped vertically - flip the y direction
|
||||
deltaY = -deltaY;
|
||||
}
|
||||
}
|
||||
|
||||
// for all the objects that make up this multi-part
|
||||
do {
|
||||
|
@ -530,4 +534,32 @@ int MultiLowest(OBJECT *pMulti) {
|
|||
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
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define TINSEL_MULTIOBJ_H
|
||||
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/object.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
|
@ -45,7 +46,9 @@ struct MULTI_INIT {
|
|||
int32 mulX; //!< multi-objects initial x ani position
|
||||
int32 mulY; //!< multi-objects initial y ani position
|
||||
int32 mulZ; //!< multi-objects initial z position
|
||||
uint32 otherFlags; //!< multi-objects Tinsel 2 - other flags
|
||||
} PACKED_STRUCT;
|
||||
typedef MULTI_INIT *PMULTI_INIT;
|
||||
|
||||
#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
|
||||
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
|
||||
|
||||
#endif // TINSEL_MULTIOBJ_H
|
||||
|
|
|
@ -31,12 +31,21 @@
|
|||
#include "sound/mididrv.h"
|
||||
#include "sound/midiparser.h"
|
||||
#include "sound/audiocd.h"
|
||||
#include "sound/adpcm.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/file.h"
|
||||
|
||||
#include "tinsel/config.h"
|
||||
#include "tinsel/sound.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 {
|
||||
|
||||
|
@ -153,8 +162,8 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
|||
currentMidi = dwFileOffset;
|
||||
currentLoop = bLoop;
|
||||
|
||||
if (volMidi != 0) {
|
||||
SetMidiVolume(volMidi);
|
||||
if (volMusic != 0) {
|
||||
SetMidiVolume(volMusic);
|
||||
// Support for compressed music from the music enhancement project
|
||||
AudioCD.stop();
|
||||
|
||||
|
@ -191,7 +200,7 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
|||
|
||||
// open MIDI sequence file in binary mode
|
||||
if (!midiStream.open(MIDI_FILE))
|
||||
error("Cannot find file %s", MIDI_FILE);
|
||||
error(CANNOT_FIND_FILE, MIDI_FILE);
|
||||
|
||||
// update index of last tune loaded
|
||||
dwLastMidiIndex = dwMidiIndex;
|
||||
|
@ -206,22 +215,22 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
|||
assert(dwSeqLen > 0 && dwSeqLen <= midiBuffer.size);
|
||||
|
||||
// stop any currently playing tune
|
||||
_vm->_music->stop();
|
||||
_vm->_midiMusic->stop();
|
||||
|
||||
// read the sequence
|
||||
if (midiStream.read(midiBuffer.pDat, dwSeqLen) != dwSeqLen)
|
||||
error("File %s is corrupt", MIDI_FILE);
|
||||
error(FILE_IS_CORRUPT, MIDI_FILE);
|
||||
|
||||
midiStream.close();
|
||||
|
||||
_vm->_music->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
||||
_vm->_midiMusic->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
||||
|
||||
// Store the length
|
||||
dwLastSeqLen = dwSeqLen;
|
||||
} else {
|
||||
// dwMidiIndex == dwLastMidiIndex
|
||||
_vm->_music->stop();
|
||||
_vm->_music->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
||||
_vm->_midiMusic->stop();
|
||||
_vm->_midiMusic->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
||||
}
|
||||
|
||||
// allow another sequence to play
|
||||
|
@ -235,7 +244,7 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
|||
*/
|
||||
bool MidiPlaying(void) {
|
||||
if (AudioCD.isPlaying()) return true;
|
||||
return _vm->_music->isPlaying();
|
||||
return _vm->_midiMusic->isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -246,7 +255,7 @@ bool StopMidi(void) {
|
|||
currentLoop = false;
|
||||
|
||||
AudioCD.stop();
|
||||
_vm->_music->stop();
|
||||
_vm->_midiMusic->stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -255,7 +264,7 @@ bool StopMidi(void) {
|
|||
* Gets the volume of the MIDI music.
|
||||
*/
|
||||
int GetMidiVolume() {
|
||||
return volMidi;
|
||||
return volMusic;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -265,24 +274,24 @@ int GetMidiVolume() {
|
|||
void SetMidiVolume(int vol) {
|
||||
assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume);
|
||||
|
||||
if (vol == 0 && volMidi == 0) {
|
||||
if (vol == 0 && volMusic == 0) {
|
||||
// Nothing to do
|
||||
} else if (vol == 0 && volMidi != 0) {
|
||||
} else if (vol == 0 && volMusic != 0) {
|
||||
// Stop current midi sequence
|
||||
AudioCD.stop();
|
||||
StopMidi();
|
||||
} else if (vol != 0 && volMidi == 0) {
|
||||
} else if (vol != 0 && volMusic == 0) {
|
||||
// Perhaps restart last midi sequence
|
||||
if (currentLoop) {
|
||||
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
|
||||
_vm->_music->setVolume(vol);
|
||||
_vm->_midiMusic->setVolume(vol);
|
||||
}
|
||||
|
||||
volMidi = vol;
|
||||
volMusic = vol;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -292,7 +301,7 @@ void OpenMidiFiles(void) {
|
|||
Common::File midiStream;
|
||||
|
||||
// Demo version has no midi file
|
||||
if (_vm->getFeatures() & GF_DEMO)
|
||||
if ((_vm->getFeatures() & GF_DEMO) || (TinselVersion == TINSEL_V2))
|
||||
return;
|
||||
|
||||
if (midiBuffer.pDat)
|
||||
|
@ -301,12 +310,12 @@ void OpenMidiFiles(void) {
|
|||
|
||||
// open MIDI sequence file in binary mode
|
||||
if (!midiStream.open(MIDI_FILE))
|
||||
error("Cannot find file %s", MIDI_FILE);
|
||||
error(CANNOT_FIND_FILE, MIDI_FILE);
|
||||
|
||||
// gen length of the largest sequence
|
||||
midiBuffer.size = midiStream.readUint32LE();
|
||||
if (midiStream.ioFailed())
|
||||
error("File %s is corrupt", MIDI_FILE);
|
||||
error(FILE_IS_CORRUPT, MIDI_FILE);
|
||||
|
||||
if (midiBuffer.size) {
|
||||
// allocate a buffer big enough for the largest MIDI sequence
|
||||
|
@ -327,14 +336,14 @@ void DeleteMidiBuffer() {
|
|||
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));
|
||||
_masterVolume = 0;
|
||||
this->open();
|
||||
_xmidiParser = MidiParser::createParser_XMIDI();
|
||||
}
|
||||
|
||||
MusicPlayer::~MusicPlayer() {
|
||||
MidiMusicPlayer::~MidiMusicPlayer() {
|
||||
_driver->setTimerCallback(NULL, NULL);
|
||||
stop();
|
||||
this->close();
|
||||
|
@ -342,7 +351,7 @@ MusicPlayer::~MusicPlayer() {
|
|||
delete _xmidiParser;
|
||||
}
|
||||
|
||||
void MusicPlayer::setVolume(int volume) {
|
||||
void MidiMusicPlayer::setVolume(int volume) {
|
||||
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, 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!
|
||||
if (!_driver)
|
||||
return 255;
|
||||
|
@ -372,14 +381,14 @@ int MusicPlayer::open() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void MusicPlayer::close() {
|
||||
void MidiMusicPlayer::close() {
|
||||
stop();
|
||||
if (_driver)
|
||||
_driver->close();
|
||||
_driver = 0;
|
||||
}
|
||||
|
||||
void MusicPlayer::send(uint32 b) {
|
||||
void MidiMusicPlayer::send(uint32 b) {
|
||||
byte channel = (byte)(b & 0x0F);
|
||||
if ((b & 0xFFF0) == 0x07B0) {
|
||||
// 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) {
|
||||
case 0x2F: // End of Track
|
||||
if (_looping)
|
||||
|
@ -423,15 +432,15 @@ void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
|
|||
}
|
||||
}
|
||||
|
||||
void MusicPlayer::onTimer(void *refCon) {
|
||||
MusicPlayer *music = (MusicPlayer *)refCon;
|
||||
void MidiMusicPlayer::onTimer(void *refCon) {
|
||||
MidiMusicPlayer *music = (MidiMusicPlayer *)refCon;
|
||||
Common::StackLock lock(music->_mutex);
|
||||
|
||||
if (music->_isPlaying)
|
||||
music->_parser->onTimer();
|
||||
}
|
||||
|
||||
void MusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
|
||||
void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
|
||||
if (_isPlaying)
|
||||
return;
|
||||
|
||||
|
@ -463,7 +472,7 @@ void MusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
|
|||
}
|
||||
}
|
||||
|
||||
void MusicPlayer::stop() {
|
||||
void MidiMusicPlayer::stop() {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
_isPlaying = false;
|
||||
|
@ -473,16 +482,414 @@ void MusicPlayer::stop() {
|
|||
}
|
||||
}
|
||||
|
||||
void MusicPlayer::pause() {
|
||||
void MidiMusicPlayer::pause() {
|
||||
setVolume(-1);
|
||||
_isPlaying = false;
|
||||
}
|
||||
|
||||
void MusicPlayer::resume() {
|
||||
void MidiMusicPlayer::resume() {
|
||||
setVolume(GetMidiVolume());
|
||||
_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) {
|
||||
*pMidi = currentMidi;
|
||||
*pLoop = currentLoop;
|
||||
|
@ -495,9 +902,9 @@ void RestoreMidiFacts(SCNHANDLE Midi, bool Loop) {
|
|||
currentMidi = Midi;
|
||||
currentLoop = Loop;
|
||||
|
||||
if (volMidi != 0 && Loop) {
|
||||
if (volMusic != 0 && Loop) {
|
||||
PlayMidiSequence(currentMidi, true);
|
||||
SetMidiVolume(volMidi);
|
||||
SetMidiVolume(volMusic);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,4 +953,4 @@ void dumpMusic() {
|
|||
}
|
||||
#endif
|
||||
|
||||
} // End of namespace Made
|
||||
} // End of namespace Tinsel
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "sound/mididrv.h"
|
||||
#include "sound/midiparser.h"
|
||||
#include "sound/audiostream.h"
|
||||
#include "sound/mixer.h"
|
||||
#include "common/mutex.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
@ -58,11 +60,10 @@ SCNHANDLE GetTrackOffset(int trackNumber);
|
|||
|
||||
void dumpMusic();
|
||||
|
||||
|
||||
class MusicPlayer : public MidiDriver {
|
||||
class MidiMusicPlayer : public MidiDriver {
|
||||
public:
|
||||
MusicPlayer(MidiDriver *driver);
|
||||
~MusicPlayer();
|
||||
MidiMusicPlayer(MidiDriver *driver);
|
||||
~MidiMusicPlayer();
|
||||
|
||||
bool isPlaying() { return _isPlaying; }
|
||||
void setPlaying(bool playing) { _isPlaying = playing; }
|
||||
|
@ -71,6 +72,7 @@ public:
|
|||
int getVolume() { return _masterVolume; }
|
||||
|
||||
void playXMIDI(byte *midiData, uint32 size, bool loop);
|
||||
|
||||
void stop();
|
||||
void pause();
|
||||
void resume();
|
||||
|
@ -111,6 +113,93 @@ protected:
|
|||
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
|
||||
|
|
|
@ -29,14 +29,13 @@
|
|||
#include "tinsel/cliprect.h" // object clip rect defs
|
||||
#include "tinsel/graphics.h" // low level interface
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/text.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
#define OID_EFFECTS 0x2000 // generic special effects object id
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
/** screen clipping rectangle */
|
||||
static const Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
// list of all objects
|
||||
OBJECT *objectList = 0;
|
||||
|
||||
|
@ -194,6 +193,7 @@ void InsertObject(OBJECT *pObjList, OBJECT *pInsObj) {
|
|||
*/
|
||||
void DelObject(OBJECT *pObjList, OBJECT *pDelObj) {
|
||||
OBJECT *pPrev, *pObj; // object list traversal pointers
|
||||
const Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
// validate object pointer
|
||||
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
|
||||
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
|
||||
|
||||
// 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
|
||||
// null image
|
||||
|
@ -365,21 +367,25 @@ OBJECT *InitObject(const OBJ_INIT *pInitTbl) {
|
|||
// get pointer to image
|
||||
if (pInitTbl->hObjImg) {
|
||||
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
|
||||
|
||||
if (pImg->hImgPal) {
|
||||
// allocate a palette for this object
|
||||
pPalQ = AllocPalette(FROM_LE_32(pImg->hImgPal));
|
||||
|
||||
// make sure palette allocated
|
||||
assert(pPalQ != NULL);
|
||||
}
|
||||
|
||||
// assign palette to object
|
||||
pObj->pPal = pPalQ;
|
||||
|
||||
// set objects size
|
||||
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
|
||||
pObj->hBits = FROM_LE_32(pImg->hImgBits);
|
||||
|
@ -434,7 +440,9 @@ void AnimateObjectFlags(OBJECT *pAniObj, int newflags, SCNHANDLE hNewImg) {
|
|||
|
||||
// setup new shape
|
||||
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
|
||||
pAniObj->hBits = FROM_LE_32(pNewImg->hImgBits);
|
||||
|
|
|
@ -51,21 +51,24 @@ enum {
|
|||
DMA_ABS = 0x0100, //!< position of object is absolute
|
||||
DMA_CHANGED = 0x0200, //!< object has changed in some way since the last frame
|
||||
DMA_USERDEF = 0x0400, //!< user defined flags start here
|
||||
DMA_GHOST = 0x0080,
|
||||
|
||||
|
||||
/** flags that effect an objects appearance */
|
||||
DMA_HARDFLAGS = (DMA_WNZ | DMA_CNZ | DMA_CONST | DMA_WA | DMA_FLIPH | DMA_FLIPV | DMA_TRANS)
|
||||
};
|
||||
|
||||
/** structure for image */
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
struct IMAGE {
|
||||
short imgWidth; //!< image width
|
||||
short imgHeight; //!< image height
|
||||
unsigned short imgHeight; //!< image height
|
||||
short anioffX; //!< image x animation offset
|
||||
short anioffY; //!< image y animation offset
|
||||
SCNHANDLE hImgBits; //!< image bitmap 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 */
|
||||
typedef uint32 FRAME;
|
||||
|
@ -93,6 +96,7 @@ struct OBJECT {
|
|||
SCNHANDLE hMirror; //!< objects previous animation frame
|
||||
int oid; //!< object identifier
|
||||
};
|
||||
typedef OBJECT *POBJECT;
|
||||
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "tinsel/graphics.h"
|
||||
#include "tinsel/handle.h" // LockMem definition
|
||||
#include "tinsel/palette.h" // palette allocator structures etc.
|
||||
#include "tinsel/sysvar.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
@ -72,6 +73,17 @@ static VIDEO_DAC_Q *pDAChead;
|
|||
/** the translucent palette lookup table */
|
||||
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
|
||||
// diagnostic palette counters
|
||||
static int numPals = 0;
|
||||
|
@ -243,6 +255,10 @@ PALQ *AllocPalette(SCNHANDLE hNewPal) {
|
|||
p->hPal = hNewPal; // set hardware palette data
|
||||
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
|
||||
// one more palette in use
|
||||
if (++numPals > maxPals)
|
||||
|
@ -250,6 +266,9 @@ PALQ *AllocPalette(SCNHANDLE hNewPal) {
|
|||
#endif
|
||||
|
||||
// Q the change to the video DAC
|
||||
if (TinselV2)
|
||||
UpdateDACqueue(p->posInDAC, pNewPal->numColours, p->palRGB);
|
||||
else
|
||||
UpdateDACqueueHandle(p->posInDAC, p->numColours, p->hPal);
|
||||
|
||||
// move all palettes after this one down (if necessary)
|
||||
|
@ -265,9 +284,14 @@ PALQ *AllocPalette(SCNHANDLE hNewPal) {
|
|||
+ pPrev->numColours | PALETTE_MOVED;
|
||||
|
||||
// Q the palette change in position to the video DAC
|
||||
if (!TinselV2)
|
||||
UpdateDACqueueHandle(pNxtPal->posInDAC,
|
||||
pNxtPal->numColours,
|
||||
pNxtPal->hPal);
|
||||
else if (!pNxtPal->bFading)
|
||||
UpdateDACqueue(pNxtPal->posInDAC,
|
||||
pNxtPal->numColours,
|
||||
pNxtPal->palRGB);
|
||||
|
||||
// update previous palette to current palette
|
||||
pPrev = pNxtPal;
|
||||
|
@ -347,10 +371,22 @@ void SwapPalette(PALQ *pPalQ, SCNHANDLE hNewPal) {
|
|||
// install new palette
|
||||
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
|
||||
UpdateDACqueueHandle(pPalQ->posInDAC, FROM_LE_32(pNewPal->numColours), hNewPal);
|
||||
}
|
||||
} else {
|
||||
// # colours are different - will have to update all following palette entries
|
||||
assert(!TinselV2); // Fatal error for Tinsel 2
|
||||
|
||||
PALQ *pNxtPalQ; // next palette queue position
|
||||
|
||||
|
@ -410,6 +446,33 @@ void SetBgndColour(COLORREF colour) {
|
|||
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.
|
||||
* @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
|
||||
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
|
||||
|
|
|
@ -43,7 +43,7 @@ enum {
|
|||
MAX_COLOURS = 256, //!< maximum number of colours - 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
|
||||
NUM_PALETTES = 3, //!< number of palettes
|
||||
NUM_PALETTES = 32, //!< number of palettes
|
||||
|
||||
// Discworld has some fixed apportioned bits in the palette.
|
||||
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 posInDAC; //!< palette position in the video DAC
|
||||
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"
|
||||
// field - the palette entry has moved
|
||||
|
@ -137,8 +140,41 @@ COLORREF GetBgndColour(void); // returns current background colour
|
|||
void SetBgndColour( // sets current background colour
|
||||
COLORREF colour); // colour to set the background to
|
||||
|
||||
void FadingPalette(PPALQ pPalQ, bool bFading);
|
||||
|
||||
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
|
||||
|
||||
#endif // TINSEL_PALETTE_H
|
||||
|
|
|
@ -25,13 +25,16 @@
|
|||
*/
|
||||
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/drives.h"
|
||||
#include "tinsel/events.h" // 'POINTED' etc.
|
||||
#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/scn.h" // FindChunk()
|
||||
#include "tinsel/serializer.h"
|
||||
#include "tinsel/timers.h"
|
||||
#include "tinsel/tinlib.h" // Library routines
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
|
@ -97,7 +100,7 @@ enum OPCODE {
|
|||
|
||||
#define OPMASK 0x3F //!< mask to isolate the opcode
|
||||
|
||||
|
||||
bool bNoPause = false;
|
||||
|
||||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
||||
|
@ -107,13 +110,19 @@ static int numGlobals = 0; // How many global variables to save/restore
|
|||
|
||||
static INT_CONTEXT *icList = 0;
|
||||
|
||||
static uint32 hMasterScript;
|
||||
|
||||
/**
|
||||
* Keeps the code array pointer up to date.
|
||||
*/
|
||||
void LockCode(INT_CONTEXT *ic) {
|
||||
if (ic->GSort == GS_MASTER)
|
||||
ic->code = (byte *)FindChunk(MASTER_SCNHANDLE, CHUNK_PCODE);
|
||||
if (ic->GSort == GS_MASTER) {
|
||||
if (TinselV2)
|
||||
// Get the srcipt handle from a specific global chunk
|
||||
ic->code = (byte *)LockMem(hMasterScript);
|
||||
else
|
||||
ic->code = (byte *)FindChunk(MASTER_SCNHANDLE, CHUNK_PCODE);
|
||||
} else
|
||||
ic->code = (byte *)LockMem(ic->hCode);
|
||||
}
|
||||
|
||||
|
@ -124,7 +133,7 @@ static INT_CONTEXT *AllocateInterpretContext(GSORT gsort) {
|
|||
INT_CONTEXT *pic;
|
||||
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 = g_scheduler->getCurrentProcess();
|
||||
pic->GSort = gsort;
|
||||
|
@ -141,11 +150,41 @@ static INT_CONTEXT *AllocateInterpretContext(GSORT gsort) {
|
|||
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.
|
||||
* Called from the end of Interpret().
|
||||
*/
|
||||
static void FreeInterpretContextPi(INT_CONTEXT *pic) {
|
||||
FreeWaitCheck(pic, true);
|
||||
if (TinselV2)
|
||||
memset(pic, 0, sizeof(INT_CONTEXT));
|
||||
pic->GSort = GS_NONE;
|
||||
}
|
||||
|
||||
|
@ -158,8 +197,11 @@ void FreeInterpretContextPr(PROCESS *pProc) {
|
|||
INT_CONTEXT *pic;
|
||||
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) {
|
||||
FreeWaitCheck(pic, false);
|
||||
if (TinselV2)
|
||||
memset(pic, 0, sizeof(INT_CONTEXT));
|
||||
pic->GSort = GS_NONE;
|
||||
break;
|
||||
}
|
||||
|
@ -173,8 +215,9 @@ void FreeMostInterpretContexts(void) {
|
|||
INT_CONTEXT *pic;
|
||||
int i;
|
||||
|
||||
for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) {
|
||||
if (pic->GSort != GS_MASTER) {
|
||||
for (i = 0, pic = icList; i < NUM_INTERPRET; i++, pic++) {
|
||||
if ((pic->GSort != GS_MASTER) && (pic->GSort != GS_GPROCESS)) {
|
||||
memset(pic, 0, sizeof(INT_CONTEXT));
|
||||
pic->GSort = GS_NONE;
|
||||
}
|
||||
}
|
||||
|
@ -187,8 +230,9 @@ void FreeMasterInterpretContext(void) {
|
|||
INT_CONTEXT *pic;
|
||||
int i;
|
||||
|
||||
for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) {
|
||||
if (pic->GSort == GS_MASTER) {
|
||||
for (i = 0, pic = icList; i < NUM_INTERPRET; i++, pic++) {
|
||||
if ((pic->GSort == GS_MASTER) || (pic->GSort == GS_GPROCESS)) {
|
||||
memset(pic, 0, sizeof(INT_CONTEXT));
|
||||
pic->GSort = GS_NONE;
|
||||
return;
|
||||
}
|
||||
|
@ -205,8 +249,8 @@ void FreeMasterInterpretContext(void) {
|
|||
* @param actorId Associated actor (if any)
|
||||
* @param pinvo Associated inventory object
|
||||
*/
|
||||
INT_CONTEXT *InitInterpretContext(GSORT gsort, SCNHANDLE hCode, USER_EVENT event,
|
||||
HPOLYGON hpoly, int actorid, INV_OBJECT *pinvo) {
|
||||
INT_CONTEXT *InitInterpretContext(GSORT gsort, SCNHANDLE hCode, TINSEL_EVENT event,
|
||||
HPOLYGON hpoly, int actorid, INV_OBJECT *pinvo, int myEscape) {
|
||||
INT_CONTEXT *ic;
|
||||
|
||||
ic = AllocateInterpretContext(gsort);
|
||||
|
@ -215,14 +259,14 @@ INT_CONTEXT *InitInterpretContext(GSORT gsort, SCNHANDLE hCode, USER_EVENT event
|
|||
ic->hCode = hCode;
|
||||
LockCode(ic);
|
||||
ic->event = event;
|
||||
ic->hpoly = hpoly;
|
||||
ic->actorid = actorid;
|
||||
ic->hPoly = hpoly;
|
||||
ic->idActor = actorid;
|
||||
ic->pinvo = pinvo;
|
||||
|
||||
// Previously local variables in Interpret()
|
||||
ic->bHalt = false; // set to exit interpeter
|
||||
ic->escOn = false;
|
||||
ic->myescEvent = 0; // only initialised to prevent compiler warning!
|
||||
ic->escOn = myEscape > 0;
|
||||
ic->myEscape = myEscape;
|
||||
ic->sp = 0;
|
||||
ic->bp = ic->sp + 1;
|
||||
ic->ip = 0; // start of code
|
||||
|
@ -256,6 +300,9 @@ void RegisterGlobals(int num) {
|
|||
if (pGlobals == NULL) {
|
||||
numGlobals = num;
|
||||
|
||||
hMasterScript = !TinselV2 ? 0 :
|
||||
READ_LE_UINT32(FindChunk(MASTER_SCNHANDLE, CHUNK_MASTER_SCRIPT));
|
||||
|
||||
// Allocate RAM for pGlobals and make sure it's allocated
|
||||
pGlobals = (int32 *)calloc(numGlobals, sizeof(int32));
|
||||
if (pGlobals == NULL) {
|
||||
|
@ -263,18 +310,38 @@ void RegisterGlobals(int num) {
|
|||
}
|
||||
|
||||
// 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) {
|
||||
error("Cannot allocate memory for interpret contexts");
|
||||
}
|
||||
|
||||
g_scheduler->setResourceCallback(FreeInterpretContextPr);
|
||||
} else {
|
||||
// Check size is still the same
|
||||
assert(numGlobals == num);
|
||||
|
||||
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(hCode);
|
||||
s.syncAsUint32LE(event);
|
||||
s.syncAsSint32LE(hpoly);
|
||||
s.syncAsSint32LE(actorid);
|
||||
s.syncAsSint32LE(hPoly);
|
||||
s.syncAsSint32LE(idActor);
|
||||
|
||||
for (int i = 0; i < PCODE_STACK_SIZE; ++i)
|
||||
s.syncAsSint32LE(stack[i]);
|
||||
|
@ -320,14 +387,14 @@ void INT_CONTEXT::syncWithSerializer(Serializer &s) {
|
|||
s.syncAsSint32LE(ip);
|
||||
s.syncAsUint32LE(bHalt);
|
||||
s.syncAsUint32LE(escOn);
|
||||
s.syncAsSint32LE(myescEvent);
|
||||
s.syncAsSint32LE(myEscape);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return pointer to and size of global data for save/restore game.
|
||||
*/
|
||||
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;
|
||||
ic->sp += tmp2;
|
||||
LockCode(ic);
|
||||
if (TinselV2 && (ic->resumeState == RES_1))
|
||||
ic->resumeState = RES_NOT;
|
||||
break;
|
||||
|
||||
case OP_RET: // procedure return
|
||||
|
@ -567,12 +636,14 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
|
|||
break;
|
||||
|
||||
case OP_ESCON:
|
||||
bNoPause = true;
|
||||
ic->escOn = true;
|
||||
ic->myescEvent = GetEscEvents();
|
||||
ic->myEscape = GetEscEvents();
|
||||
break;
|
||||
|
||||
case OP_ESCOFF:
|
||||
ic->escOn = false;
|
||||
ic->myEscape = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -590,4 +661,128 @@ void Interpret(CORO_PARAM, INT_CONTEXT *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
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#ifndef TINSEL_PCODE_H // prevent multiple includes
|
||||
#define TINSEL_PCODE_H
|
||||
|
||||
#include "tinsel/events.h" // for USER_EVENT
|
||||
#include "tinsel/events.h" // for TINSEL_EVENT
|
||||
#include "tinsel/sched.h" // for PROCESS
|
||||
|
||||
namespace Tinsel {
|
||||
|
@ -45,9 +45,12 @@ enum {
|
|||
};
|
||||
|
||||
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 {
|
||||
|
||||
// Elements for interpret context management
|
||||
|
@ -57,9 +60,9 @@ struct INT_CONTEXT {
|
|||
// Previously parameters to Interpret()
|
||||
SCNHANDLE hCode; //!< scene handle of the code to execute
|
||||
byte *code; //!< pointer to the code to execute
|
||||
USER_EVENT event; //!< causal event
|
||||
HPOLYGON hpoly; //!< associated polygon (if any)
|
||||
int actorid; //!< associated actor (if any)
|
||||
TINSEL_EVENT event; //!< causal event
|
||||
HPOLYGON hPoly; //!< associated polygon (if any)
|
||||
int idActor; //!< associated actor (if any)
|
||||
INV_OBJECT *pinvo; //!< associated inventory object
|
||||
|
||||
// Previously local variables in Interpret()
|
||||
|
@ -69,27 +72,32 @@ struct INT_CONTEXT {
|
|||
int ip; //!< instruction pointer
|
||||
bool bHalt; //!< set to exit interpeter
|
||||
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;
|
||||
|
||||
void syncWithSerializer(Serializer &s);
|
||||
};
|
||||
|
||||
typedef INT_CONTEXT *PINT_CONTEXT;
|
||||
|
||||
/*----------------------------------------------------------------------*\
|
||||
|* 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(
|
||||
GSORT gsort,
|
||||
SCNHANDLE hCode, // code to execute
|
||||
USER_EVENT event, // causal event
|
||||
TINSEL_EVENT event, // causal event
|
||||
HPOLYGON hpoly, // associated polygon (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);
|
||||
|
||||
|
@ -101,8 +109,12 @@ void SaveInterpretContexts(INT_CONTEXT *sICInfo);
|
|||
void RegisterGlobals(int num);
|
||||
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 *|
|
||||
|
@ -137,10 +149,6 @@ void FreeGlobals(void);
|
|||
#define MIDI_DEF 0
|
||||
#define MIDI_LOOP 1
|
||||
|
||||
#define TRANS_DEF 0
|
||||
#define TRANS_CUT 1
|
||||
#define TRANS_FADE 2
|
||||
|
||||
#define FM_IN 0 //
|
||||
#define FM_OUT 1 // fademidi()
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "tinsel/actors.h"
|
||||
#include "tinsel/background.h"
|
||||
#include "tinsel/coroutine.h"
|
||||
#include "tinsel/cursor.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/events.h"
|
||||
|
@ -41,6 +42,7 @@
|
|||
#include "tinsel/sched.h"
|
||||
#include "tinsel/strres.h"
|
||||
#include "tinsel/text.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
|
@ -56,8 +58,8 @@ extern int newestString; // The overrun counter, in STRRES.C
|
|||
//----------------- EXTERNAL FUNCTIONS ---------------------
|
||||
|
||||
// in BG.C
|
||||
extern int BackgroundWidth(void);
|
||||
extern int BackgroundHeight(void);
|
||||
extern int BgWidth(void);
|
||||
extern int BgHeight(void);
|
||||
|
||||
|
||||
|
||||
|
@ -84,8 +86,11 @@ static bool bShowString = false;
|
|||
static int TaggedActor = 0;
|
||||
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
|
||||
/**
|
||||
|
@ -134,7 +139,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
|||
|
||||
char PositionString[64]; // sprintf() things into here
|
||||
|
||||
PMACTOR pActor; // Lead actor
|
||||
PMOVER pActor; // Lead actor
|
||||
|
||||
while (1) {
|
||||
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
|
||||
|
@ -159,7 +164,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
|||
// New text objects
|
||||
sprintf(PositionString, "%d %d", aniX + Loffset, aniY + Toffset);
|
||||
_ctx->cpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||
0, CPOSX, POSY, hTagFontHandle(), TXT_CENTRE);
|
||||
0, CPOSX, POSY, GetTagFontHandle(), TXT_CENTRE);
|
||||
if (DispPath) {
|
||||
HPOLYGON hp = InPolygon(aniX + Loffset, aniY + Toffset, PATH);
|
||||
if (hp == NOPOLY)
|
||||
|
@ -171,7 +176,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
|||
PolyCornerX(hp, 2), PolyCornerY(hp, 2),
|
||||
PolyCornerX(hp, 3), PolyCornerY(hp, 3));
|
||||
_ctx->cpathText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||
0, 4, POSY+ 10, hTagFontHandle(), 0);
|
||||
0, 4, POSY+ 10, GetTagFontHandle(), 0);
|
||||
}
|
||||
|
||||
// update previous position
|
||||
|
@ -191,7 +196,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
|||
|
||||
sprintf(PositionString, "%d", Overrun);
|
||||
_ctx->opText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||
0, OPOSX, POSY, hTagFontHandle(), TXT_CENTRE);
|
||||
0, OPOSX, POSY, GetTagFontHandle(), TXT_CENTRE);
|
||||
|
||||
// update previous value
|
||||
_ctx->prevOver = Overrun;
|
||||
|
@ -202,7 +207,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
|||
| Lead actor's position. |
|
||||
\*----------------------*/
|
||||
pActor = GetMover(LEAD_ACTOR);
|
||||
if (pActor && pActor->MActorState == NORM_MACTOR) {
|
||||
if (pActor && pActor->MActorState == NORM_MOVER) {
|
||||
// get lead's animation position
|
||||
GetActorPos(LEAD_ACTOR, &aniX, &aniY);
|
||||
|
||||
|
@ -217,7 +222,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
|||
// create new text object list
|
||||
sprintf(PositionString, "%d %d", aniX, aniY);
|
||||
_ctx->rpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||
0, LPOSX, POSY, hTagFontHandle(), TXT_CENTRE);
|
||||
0, LPOSX, POSY, GetTagFontHandle(), TXT_CENTRE);
|
||||
|
||||
// update previous position
|
||||
_ctx->prevlX = aniX;
|
||||
|
@ -236,7 +241,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
|||
|
||||
sprintf(PositionString, "String: %d", newestString);
|
||||
_ctx->spText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
|
||||
0, SPOSX, POSY+10, hTalkFontHandle(), TXT_CENTRE);
|
||||
0, SPOSX, POSY+10, GetTalkFontHandle(), TXT_CENTRE);
|
||||
|
||||
// update previous value
|
||||
_ctx->prevString = newestString;
|
||||
|
@ -252,9 +257,52 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
|
|||
}
|
||||
#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
|
||||
* (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) {
|
||||
TaggedActor = ano;
|
||||
|
@ -262,7 +310,7 @@ static void SaveTaggedActor(int ano) {
|
|||
|
||||
/**
|
||||
* 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) {
|
||||
return TaggedActor;
|
||||
|
@ -270,7 +318,7 @@ int GetTaggedActor(void) {
|
|||
|
||||
/**
|
||||
* 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) {
|
||||
hTaggedPolygon = hp;
|
||||
|
@ -341,12 +389,59 @@ static bool InHotSpot(int ano, int aniX, int aniY, int *pxtext, int *pytext) {
|
|||
* the screen.
|
||||
*/
|
||||
static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) {
|
||||
static int Loffset = 0, Toffset = 0; // Values when tag was displayed
|
||||
int nLoff, nToff; // new values, to keep tag in place
|
||||
static int tagX = 0, tagY = 0; // Values when tag was displayed
|
||||
int newX, newY; // new values, to keep tag in place
|
||||
int ano;
|
||||
int xtext, ytext;
|
||||
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....
|
||||
FirstTaggedActor();
|
||||
while ((ano = NextTaggedActor()) != 0) {
|
||||
|
@ -369,20 +464,20 @@ static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) {
|
|||
SaveTaggedActor(ano); // This actor tagged
|
||||
SaveTaggedPoly(NOPOLY); // No tagged polygon
|
||||
|
||||
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
|
||||
LoadStringRes(GetActorTag(ano), tBufferAddr(), TBUFSZ);
|
||||
*ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(),
|
||||
0, xtext - Loffset, ytext - Toffset, hTagFontHandle(), TXT_CENTRE);
|
||||
PlayfieldGetPos(FIELD_WORLD, &tagX, &tagY);
|
||||
LoadStringRes(GetActorTag(ano), TextBufferAddr(), TBUFSZ);
|
||||
*ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
|
||||
0, xtext - tagX, ytext - tagY, GetTagFontHandle(), TXT_CENTRE);
|
||||
assert(*ppText); // Actor tag string produced NULL text
|
||||
MultiSetZPosition(*ppText, Z_TAG_TEXT);
|
||||
} else {
|
||||
// Maintain actor tag's position
|
||||
|
||||
PlayfieldGetPos(FIELD_WORLD, &nLoff, &nToff);
|
||||
if (nLoff != Loffset || nToff != Toffset) {
|
||||
MultiMoveRelXY(*ppText, Loffset - nLoff, Toffset - nToff);
|
||||
Loffset = nLoff;
|
||||
Toffset = nToff;
|
||||
PlayfieldGetPos(FIELD_WORLD, &newX, &newY);
|
||||
if (newX != tagX || newY != tagY) {
|
||||
MultiMoveRelXY(*ppText, tagX - newX, tagY - newY);
|
||||
tagX = newX;
|
||||
tagY = newY;
|
||||
}
|
||||
}
|
||||
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 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
|
||||
HPOLYGON hp;
|
||||
bool newPoly;
|
||||
|
@ -418,8 +514,11 @@ static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
|
|||
for (int i = 0; i < MAX_POLY; i++) {
|
||||
hp = GetPolyHandle(i);
|
||||
|
||||
if (TinselV2 && (hp == NOPOLY))
|
||||
continue;
|
||||
|
||||
// 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
|
||||
if (hp != GetTaggedPoly()) {
|
||||
if (*ppText) {
|
||||
|
@ -431,58 +530,99 @@ static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
|
|||
SaveTaggedPoly(hp); // This polygon tagged
|
||||
}
|
||||
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
|
||||
newPoly = false;
|
||||
if (TinselV2) {
|
||||
if (hp != GetTaggedPoly())
|
||||
newPoly = true; // Different polygon
|
||||
} else {
|
||||
if (*pTag != POLY_HOTSPOT_TAG)
|
||||
newPoly = true; // A new polygon (no current)
|
||||
else if (hp != GetTaggedPoly())
|
||||
newPoly = true; // Different polygon
|
||||
else
|
||||
newPoly = false; // Same polygon
|
||||
}
|
||||
|
||||
if (newPoly) {
|
||||
if (*ppText)
|
||||
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText);
|
||||
|
||||
if (!TinselV2)
|
||||
*pTag = POLY_HOTSPOT_TAG;
|
||||
SaveTaggedActor(0); // No tagged actor
|
||||
SaveTaggedPoly(hp); // This polygon tagged
|
||||
|
||||
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
|
||||
getPolyTagInfo(hp, &hTagtext, &tagx, &tagy);
|
||||
GetTagTag(hp, &hTagtext, &tagx, &tagy);
|
||||
|
||||
int strLen;
|
||||
if (PolyTagHandle(hp) != 0)
|
||||
strLen = LoadStringRes(PolyTagHandle(hp), tBufferAddr(), TBUFSZ);
|
||||
if (GetPolyTagHandle(hp) != 0)
|
||||
strLen = LoadStringRes(GetPolyTagHandle(hp), TextBufferAddr(), TBUFSZ);
|
||||
else
|
||||
strLen = LoadStringRes(hTagtext, tBufferAddr(), TBUFSZ);
|
||||
strLen = LoadStringRes(hTagtext, TextBufferAddr(), TBUFSZ);
|
||||
|
||||
if (strLen == 0)
|
||||
// No valid string returned, so leave ppText as NULL
|
||||
ppText = NULL;
|
||||
else {
|
||||
// Handle displaying the tag text on-screen
|
||||
*ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(),
|
||||
0, tagx - Loffset, tagy - Toffset,
|
||||
hTagFontHandle(), TXT_CENTRE);
|
||||
assert(*ppText); // Polygon tag string produced NULL text
|
||||
MultiSetZPosition(*ppText, Z_TAG_TEXT);
|
||||
else if (TinselV2 && !PolyTagFollowsCursor(hp)) {
|
||||
// May have buggered cursor
|
||||
EndCursorFollowed();
|
||||
|
||||
*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
|
||||
*/
|
||||
shift = MultiRightmost(*ppText) + Loffset + 2;
|
||||
if (shift >= BackgroundWidth()) // Not off right
|
||||
MultiMoveRelXY(*ppText, BackgroundWidth() - shift, 0);
|
||||
if (shift >= BgWidth()) // Not off right
|
||||
MultiMoveRelXY(*ppText, BgWidth() - shift, 0);
|
||||
shift = MultiLeftmost(*ppText) + Loffset - 1;
|
||||
if (shift <= 0) // Not off left
|
||||
MultiMoveRelXY(*ppText, -shift, 0);
|
||||
shift = MultiLowest(*ppText) + Toffset;
|
||||
if (shift > BackgroundHeight()) // Not off bottom
|
||||
MultiMoveRelXY(*ppText, 0, BackgroundHeight() - shift);
|
||||
if (shift > BgHeight()) // Not off bottom
|
||||
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 {
|
||||
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);
|
||||
if (nLoff != Loffset || nToff != Toffset) {
|
||||
MultiMoveRelXY(*ppText, Loffset - nLoff, Toffset - nToff);
|
||||
|
@ -495,7 +635,9 @@ static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
|
|||
}
|
||||
|
||||
// No tagged polygon
|
||||
if (*pTag == POLY_HOTSPOT_TAG) {
|
||||
if (TinselV2)
|
||||
SaveTaggedPoly(NOPOLY);
|
||||
else if (*pTag == POLY_HOTSPOT_TAG) {
|
||||
*pTag = NO_HOTSPOT_TAG;
|
||||
SaveTaggedPoly(NOPOLY);
|
||||
}
|
||||
|
@ -522,7 +664,7 @@ void TagProcess(CORO_PARAM, const void *) {
|
|||
SaveTaggedPoly(NOPOLY); // No tagged polygon yet
|
||||
|
||||
while (1) {
|
||||
if (TagsActive == TAGS_ON) {
|
||||
if (bTagsActive) {
|
||||
int curX, curY; // cursor position
|
||||
while (!GetCursorXYNoWait(&curX, &curY, true))
|
||||
CORO_SLEEP(1);
|
||||
|
@ -533,6 +675,10 @@ void TagProcess(CORO_PARAM, const void *) {
|
|||
if (_ctx->pText) {
|
||||
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText);
|
||||
_ctx->pText = NULL;
|
||||
|
||||
if (TinselV2)
|
||||
// May have buggered cursor
|
||||
EndCursorFollowed();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -557,22 +703,43 @@ void TagProcess(CORO_PARAM, const void *) {
|
|||
/**
|
||||
* Called from PointProcess() as appropriate.
|
||||
*/
|
||||
static void enteringpoly(HPOLYGON hp) {
|
||||
SetPolyPointState(hp, POINTING);
|
||||
static void enteringpoly(CORO_PARAM, HPOLYGON hp) {
|
||||
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.
|
||||
*/
|
||||
static void leavingpoly(HPOLYGON hp) {
|
||||
SetPolyPointState(hp, NOT_POINTING);
|
||||
static void leavingpoly(CORO_PARAM, HPOLYGON hp) {
|
||||
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
|
||||
SetPolyTagState(hp, TAG_OFF);
|
||||
}
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -583,56 +750,95 @@ static void leavingpoly(HPOLYGON hp) {
|
|||
void PointProcess(CORO_PARAM, const void *) {
|
||||
// COROUTINE
|
||||
CORO_BEGIN_CONTEXT;
|
||||
HPOLYGON hPoly;
|
||||
int i;
|
||||
int curX, curY; // cursor/tagged actor position
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
if (TinselV2)
|
||||
EnablePointing();
|
||||
|
||||
while (1) {
|
||||
int aniX, aniY; // cursor/tagged actor position
|
||||
while (!GetCursorXYNoWait(&aniX, &aniY, true))
|
||||
while (!GetCursorXYNoWait(&_ctx->curX, &_ctx->curY, true))
|
||||
CORO_SLEEP(1);
|
||||
|
||||
/*----------------------------------*\
|
||||
| For polygons of type TAG and EXIT. |
|
||||
\*----------------------------------*/
|
||||
for (int i = 0; i < MAX_POLY; i++) {
|
||||
HPOLYGON hp = GetPolyHandle(i);
|
||||
for (_ctx->i = 0; _ctx->i < MAX_POLY; _ctx->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 (PolyPointState(hp) == NOT_POINTING) {
|
||||
if (IsInPolygon(aniX, aniY, hp)) {
|
||||
enteringpoly(hp);
|
||||
if (!PolyIsPointedTo(_ctx->hPoly)) {
|
||||
if (IsInPolygon(_ctx->curX, _ctx->curY, _ctx->hPoly)) {
|
||||
if (TinselV2) {
|
||||
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
|
||||
do {
|
||||
CORO_SLEEP(1);
|
||||
} while (!bPointingActive);
|
||||
} else {
|
||||
// allow re-scheduling
|
||||
CORO_SLEEP(1);
|
||||
}
|
||||
}
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void DisableTags(void) {
|
||||
TagsActive = TAGS_OFF;
|
||||
bTagsActive = false;
|
||||
}
|
||||
|
||||
void EnableTags(void) {
|
||||
TagsActive = TAGS_ON;
|
||||
bTagsActive = true;
|
||||
}
|
||||
|
||||
bool DisableTagsIfEnabled(void) {
|
||||
if (TagsActive == TAGS_OFF)
|
||||
return false;
|
||||
else {
|
||||
TagsActive = TAGS_OFF;
|
||||
if (bTagsActive) {
|
||||
DisableTags();
|
||||
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_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_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
|
||||
|
||||
#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
|
||||
enum PTYPE {
|
||||
TEST, PATH, EXIT, BLOCKING,
|
||||
EFFECT, REFER, TAG, EX_TAG, EX_EXIT, EX_BLOCK
|
||||
// Tinsel 2 Polygon type list
|
||||
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
|
||||
|
@ -45,6 +49,13 @@ enum {
|
|||
NODE = 1 // For paths
|
||||
};
|
||||
|
||||
// tagFlags
|
||||
enum {
|
||||
POINTING = 0x01,
|
||||
TAGWANTED = 0x02,
|
||||
FOLLOWCURSOR = 0x04
|
||||
};
|
||||
|
||||
// tagState
|
||||
enum TSTATE {
|
||||
TAG_OFF, TAG_ON
|
||||
|
@ -52,7 +63,7 @@ enum TSTATE {
|
|||
|
||||
// pointState
|
||||
enum PSTATE {
|
||||
NO_POINT, NOT_POINTING, POINTING
|
||||
PS_NO_POINT, PS_NOT_POINTING, PS_POINTING
|
||||
};
|
||||
|
||||
|
||||
|
@ -60,7 +71,10 @@ enum {
|
|||
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 FindBestPoint(HPOLYGON path, int *x, int *y, int *line);
|
||||
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 NearEndNode(HPOLYGON spath, HPOLYGON dpath);
|
||||
int NearestNodeWithin(HPOLYGON npath, int x, int y);
|
||||
void NearestCorner(int *x, int *y, HPOLYGON spath, HPOLYGON dpath);
|
||||
bool IsPolyCorner(HPOLYGON hPath, int x, 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 getPolyTagInfo(HPOLYGON p, SCNHANDLE *hTagText, int *tagx, int *tagy);
|
||||
SCNHANDLE getPolyFilm(HPOLYGON p);
|
||||
void getPolyNode(HPOLYGON p, int *px, int *py);
|
||||
SCNHANDLE getPolyScript(HPOLYGON p);
|
||||
REEL getPolyReelType(HPOLYGON p);
|
||||
int32 getPolyZfactor(HPOLYGON p);
|
||||
void GetTagTag(HPOLYGON p, SCNHANDLE *hTagText, int *tagx, int *tagy);
|
||||
SCNHANDLE GetPolyFilm(HPOLYGON p);
|
||||
void GetPolyNode(HPOLYGON hp, int *pNodeX, int *pNodeY);
|
||||
SCNHANDLE GetPolyScript(HPOLYGON p);
|
||||
REEL GetPolyReelType(HPOLYGON p);
|
||||
int32 GetPolyZfactor(HPOLYGON p);
|
||||
int numNodes(HPOLYGON pp);
|
||||
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 EnableBlock(int blockno);
|
||||
void DisableTag(int tagno);
|
||||
void EnableTag(int tagno);
|
||||
HPOLYGON GetTagHandle(int tagno);
|
||||
void DisableTag(CORO_PARAM, int tag);
|
||||
void EnableTag(CORO_PARAM, int tag);
|
||||
void DisableExit(int exitno);
|
||||
void EnableExit(int exitno);
|
||||
HPOLYGON FirstPathPoly(void);
|
||||
|
@ -99,6 +123,8 @@ void DropPolygons(void);
|
|||
|
||||
void SaveDeadPolys(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]
|
||||
PSTATE PolyPointState(HPOLYGON hp); // ->pointState
|
||||
TSTATE PolyTagState(HPOLYGON hp); // ->tagState
|
||||
SCNHANDLE PolyTagHandle(HPOLYGON hp); // ->oTagHandle
|
||||
|
||||
void SetPolyPointState(HPOLYGON hp, PSTATE ps); // ->pointState
|
||||
void SetPolyTagState(HPOLYGON hp, TSTATE ts); // ->tagState
|
||||
|
@ -118,6 +143,21 @@ void SetPolyTagHandle(HPOLYGON hp, SCNHANDLE th);// ->oTagHandle
|
|||
|
||||
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
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "tinsel/anim.h" // for ANIM
|
||||
#include "tinsel/scene.h" // for TFTYPE
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
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 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 {
|
||||
NUM_MAINSCALES = 5,
|
||||
NUM_AUXSCALES = 5,
|
||||
TOTAL_SCALES = NUM_MAINSCALES + NUM_AUXSCALES
|
||||
};
|
||||
#define BOGUS_BRIGHTNESS -1
|
||||
|
||||
struct MACTOR {
|
||||
struct MOVER {
|
||||
|
||||
int objx; /* Co-ordinates object */
|
||||
int objy;
|
||||
int objX, objY; /* Co-ordinates object */
|
||||
|
||||
int targetX, targetY;
|
||||
int ItargetX, ItargetY; /* Intermediate destination */
|
||||
HPOLYGON hIpath;
|
||||
int UtargetX, UtargetY; /* Ultimate destination */
|
||||
HPOLYGON hUpath;
|
||||
|
||||
HPOLYGON hIpath;
|
||||
HPOLYGON hUpath;
|
||||
HPOLYGON hCpath;
|
||||
|
||||
bool over;
|
||||
int ticket;
|
||||
int walkNumber;
|
||||
|
||||
IND InDifficulty;
|
||||
|
||||
|
@ -74,129 +74,147 @@ struct MACTOR {
|
|||
|
||||
int Tline; // NEW
|
||||
|
||||
bool TagReelRunning;
|
||||
|
||||
// TODO: TagReelRunning may be the same as bSpecReel
|
||||
bool bSpecReel;
|
||||
|
||||
/* Used internally */
|
||||
DIRREEL dirn; // Current reel
|
||||
DIRECTION direction; // Current reel
|
||||
int scale; // Current scale
|
||||
int scount; // Step count for walking reel synchronisation
|
||||
|
||||
unsigned fromx;
|
||||
unsigned fromy;
|
||||
int stepCount; // Step count for walking reel synchronisation
|
||||
|
||||
int walkedFromX, walkedFromY;
|
||||
|
||||
bool bMoving; // Set this to TRUE during a walk
|
||||
|
||||
bool bNoPath;
|
||||
bool bIgPath;
|
||||
bool walkReel;
|
||||
bool bWalkReel;
|
||||
|
||||
OBJECT *actorObj; // Actor's object
|
||||
ANIM actorAnim; // Actor's animation script
|
||||
|
||||
SCNHANDLE lastfilm; // } Used by AlterActor()
|
||||
SCNHANDLE pushedfilm; // }
|
||||
SCNHANDLE hLastFilm; // } Used by AlterMover()
|
||||
SCNHANDLE hPushedFilm; // }
|
||||
|
||||
int actorID;
|
||||
int actorToken;
|
||||
|
||||
SCNHANDLE WalkReels[TOTAL_SCALES][4];
|
||||
SCNHANDLE StandReels[TOTAL_SCALES][4];
|
||||
SCNHANDLE TalkReels[TOTAL_SCALES][4];
|
||||
SCNHANDLE walkReels[REQ_TOTAL_SCALES][4];
|
||||
SCNHANDLE standReels[REQ_TOTAL_SCALES][4];
|
||||
SCNHANDLE talkReels[REQ_TOTAL_SCALES][4];
|
||||
|
||||
MAS MActorState;
|
||||
bool bActive;
|
||||
|
||||
bool aHidden;
|
||||
int SlowFactor; // Slow down movement while hidden
|
||||
|
||||
bool stop;
|
||||
bool bStop;
|
||||
|
||||
/* NOTE: If effect polys can overlap, this needs improving */
|
||||
bool InEffect;
|
||||
bool bInEffect;
|
||||
|
||||
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 };
|
||||
|
||||
void StoreMoverPalette(PMOVER pMover, int startColour, int length);
|
||||
|
||||
MACTOR *GetMover(int ano);
|
||||
MACTOR *SetMover(int ano);
|
||||
void KillMActor(MACTOR *pActor);
|
||||
MACTOR *GetLiveMover(int index);
|
||||
void MoverBrightness(PMOVER pMover, int brightness);
|
||||
|
||||
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 getMActorHideState(MACTOR *pActor);
|
||||
void unhideMActor(MACTOR *pActor);
|
||||
void DropMActors(void);
|
||||
void MoveMActor(MACTOR *pActor, int x, int y);
|
||||
bool getMActorState(MOVER *psActor);
|
||||
int GetMoverId(PMOVER pMover);
|
||||
void SetMoverZ(PMOVER pMover, int y, uint32 zFactor);
|
||||
void SetMoverZoverride(PMOVER pMover, uint32 zFactor);
|
||||
|
||||
void GetMActorPosition(MACTOR *pActor, int *aniX, int *aniY);
|
||||
void GetMActorMidTopPosition(MACTOR *pActor, int *aniX, int *aniY);
|
||||
int GetMActorLeft(MACTOR *pActor);
|
||||
int GetMActorRight(MACTOR *pActor);
|
||||
void HideMover(PMOVER pMover, int sf = 0);
|
||||
bool MoverHidden(PMOVER pMover);
|
||||
bool MoverIs(PMOVER pMover);
|
||||
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 AlterMActor(MACTOR *actor, SCNHANDLE film, AR_FUNCTION fn);
|
||||
DIRREEL GetMActorDirection(MACTOR *pActor);
|
||||
int GetMActorScale(MACTOR *pActor);
|
||||
void SetMActorDirection(MACTOR *pActor, DIRREEL dirn);
|
||||
void SetMActorStanding(MACTOR *actor);
|
||||
void SetMActorWalkReel(MACTOR *actor, DIRREEL reel, int scale, bool force);
|
||||
void GetMoverPosition(PMOVER pMover, int *aniX, int *aniY);
|
||||
void GetMoverMidTop(PMOVER pMover, int *aniX, int *aniY);
|
||||
int GetMoverLeft(PMOVER pMover);
|
||||
int GetMoverRight(PMOVER pMover);
|
||||
int GetMoverTop(PMOVER pMover);
|
||||
int GetMoverBottom(PMOVER pMover);
|
||||
|
||||
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);
|
||||
|
||||
bool IsMAinEffectPoly(int index);
|
||||
void SetMAinEffectPoly(int index, bool tf);
|
||||
void SetMoverInEffect(int index, bool tf);
|
||||
|
||||
bool MAmoving(MACTOR *pActor);
|
||||
|
||||
int GetActorTicket(MACTOR *pActor);
|
||||
void StopMover(PMOVER pMover);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
struct SAVED_MOVER {
|
||||
|
||||
MAS MActorState;
|
||||
int actorID;
|
||||
int objx;
|
||||
int objy;
|
||||
SCNHANDLE lastfilm;
|
||||
int objX;
|
||||
int objY;
|
||||
SCNHANDLE hLastfilm;
|
||||
|
||||
SCNHANDLE WalkReels[TOTAL_SCALES][4];
|
||||
SCNHANDLE StandReels[TOTAL_SCALES][4];
|
||||
SCNHANDLE TalkReels[TOTAL_SCALES][4];
|
||||
SCNHANDLE walkReels[REQ_TOTAL_SCALES][4];
|
||||
SCNHANDLE standReels[REQ_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 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 {
|
||||
MAGICX = -101,
|
||||
MAGICY = -102
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
*/
|
||||
|
||||
#include "tinsel/actors.h"
|
||||
#include "tinsel/dialogs.h"
|
||||
#include "tinsel/drives.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/inventory.h"
|
||||
#include "tinsel/rince.h"
|
||||
#include "tinsel/savescn.h"
|
||||
#include "tinsel/serializer.h"
|
||||
|
@ -63,7 +64,11 @@ namespace Tinsel {
|
|||
#define VER(x) x
|
||||
|
||||
|
||||
//----------------- GLOBAL GLOBAL DATA --------------------
|
||||
|
||||
int thingHeld = 0;
|
||||
int restoreCD = 0;
|
||||
SRSTATE SRstate = SR_IDLE;
|
||||
|
||||
//----------------- EXTERN FUNCTIONS --------------------
|
||||
|
||||
|
@ -79,9 +84,6 @@ extern void syncGlobInfo(Serializer &s);
|
|||
// in POLYGONS.C
|
||||
extern void syncPolyInfo(Serializer &s);
|
||||
|
||||
// in SAVESCN.CPP
|
||||
extern void RestoreScene(SAVED_DATA *sd, bool bFadeOut);
|
||||
|
||||
//----------------- LOCAL DEFINES --------------------
|
||||
|
||||
struct SaveGameHeader {
|
||||
|
@ -93,15 +95,17 @@ struct SaveGameHeader {
|
|||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
#define SAVEGAME_ID (TinselV2 ? (uint32)DW2_SAVEGAME_ID : (uint32)DW1_SAVEGAME_ID)
|
||||
|
||||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
||||
static int numSfiles = 0;
|
||||
static SFILES savedFiles[MAX_SFILES];
|
||||
static SFILES savedFiles[MAX_SAVED_FILES];
|
||||
|
||||
static bool NeedLoad = true;
|
||||
|
||||
|
@ -112,8 +116,6 @@ static const char *SaveSceneDesc = 0;
|
|||
static int *SaveSceneSsCount = 0;
|
||||
static char *SaveSceneSsData = 0; // points to 'SAVED_DATA ssdata[MAX_NEST]'
|
||||
|
||||
static SRSTATE SRstate = SR_IDLE;
|
||||
|
||||
//------------- SAVE/LOAD SUPPORT METHODS ----------------
|
||||
|
||||
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) {
|
||||
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.objx);
|
||||
s.syncAsSint32LE(sm.objy);
|
||||
s.syncAsUint32LE(sm.lastfilm);
|
||||
s.syncAsSint32LE(sm.objX);
|
||||
s.syncAsSint32LE(sm.objY);
|
||||
s.syncAsUint32LE(sm.hLastfilm);
|
||||
|
||||
for (int pIndex = 0; pIndex < 3; ++pIndex) {
|
||||
SCNHANDLE *p = pList[pIndex];
|
||||
for (int i = 0; i < TOTAL_SCALES * 4; ++i)
|
||||
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) {
|
||||
s.syncAsUint16LE(sa.actorID);
|
||||
s.syncAsUint16LE(sa.z);
|
||||
s.syncAsUint16LE(sa.zFactor);
|
||||
s.syncAsUint32LE(sa.bAlive);
|
||||
s.syncAsUint32LE(sa.presFilm);
|
||||
s.syncAsUint16LE(sa.presRnum);
|
||||
s.syncAsUint16LE(sa.presX);
|
||||
s.syncAsUint16LE(sa.presY);
|
||||
s.syncAsUint16LE(sa.presPlayX);
|
||||
s.syncAsUint16LE(sa.presPlayY);
|
||||
}
|
||||
|
||||
extern void syncAllActorsAlive(Serializer &s);
|
||||
|
@ -186,6 +197,24 @@ static void syncNoScrollB(Serializer &s, NOSCROLLB &ns) {
|
|||
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) {
|
||||
s.syncAsUint32LE(sd.SavedSceneHandle);
|
||||
s.syncAsUint32LE(sd.SavedBgroundHandle);
|
||||
|
@ -197,7 +226,7 @@ static void syncSavedData(Serializer &s, SAVED_DATA &sd) {
|
|||
s.syncAsSint32LE(sd.NumSavedActors);
|
||||
s.syncAsSint32LE(sd.SavedLoffset);
|
||||
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);
|
||||
for (int i = 0; i < MAX_POLY; ++i)
|
||||
s.syncAsUint32LE(sd.SavedDeadPolys[i]);
|
||||
|
@ -213,6 +242,32 @@ static void syncSavedData(Serializer &s, SAVED_DATA &sd) {
|
|||
syncNoScrollB(s, sd.SavedNoScrollData.NoHScroll[i]);
|
||||
s.syncAsUint32LE(sd.SavedNoScrollData.NumNoV);
|
||||
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).
|
||||
*/
|
||||
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;
|
||||
|
||||
const Common::String pattern = target + ".???";
|
||||
|
@ -255,7 +315,7 @@ int getList(Common::SaveFileManager *saveFileMan, const Common::String &target)
|
|||
numSfiles = 0;
|
||||
|
||||
for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) {
|
||||
if (numSfiles >= MAX_SFILES)
|
||||
if (numSfiles >= MAX_SAVED_FILES)
|
||||
break;
|
||||
|
||||
const Common::String &fname = *file;
|
||||
|
@ -308,7 +368,6 @@ int getList(void) {
|
|||
return getList(_vm->getSaveFileMan(), _vm->getTargetName());
|
||||
}
|
||||
|
||||
|
||||
char *ListEntry(int i, letype which) {
|
||||
if (i == -1)
|
||||
i = numSfiles;
|
||||
|
@ -322,7 +381,16 @@ char *ListEntry(int i, letype which) {
|
|||
}
|
||||
|
||||
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);
|
||||
syncGlobInfo(s); // Glitter globals
|
||||
|
@ -332,10 +400,15 @@ static void DoSync(Serializer &s) {
|
|||
if (s.isSaving())
|
||||
sg = WhichItemHeld();
|
||||
s.syncAsSint32LE(sg);
|
||||
if (s.isLoading())
|
||||
if (s.isLoading()) {
|
||||
if (TinselV2)
|
||||
thingHeld = sg;
|
||||
else
|
||||
HoldItem(sg);
|
||||
}
|
||||
|
||||
syncTimerInfo(s); // Timer data
|
||||
if (!TinselV2)
|
||||
syncPolyInfo(s); // Dead polygon data
|
||||
syncSCdata(s); // Hook Scene and delayed scene
|
||||
|
||||
|
@ -347,6 +420,7 @@ static void DoSync(Serializer &s) {
|
|||
syncSavedData(s, *sdPtr);
|
||||
}
|
||||
|
||||
if (!TinselV2)
|
||||
syncAllActorsAlive(s);
|
||||
}
|
||||
|
||||
|
@ -440,7 +514,7 @@ void ProcessSRQueue(void) {
|
|||
switch (SRstate) {
|
||||
case SR_DORESTORE:
|
||||
if (DoRestore()) {
|
||||
RestoreScene(srsd, false);
|
||||
DoRestoreScene(srsd, false);
|
||||
}
|
||||
SRstate = SR_IDLE;
|
||||
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) {
|
||||
if (TinselV2) {
|
||||
if (num == -1)
|
||||
return;
|
||||
else if (num == -2) {
|
||||
// From CD change for restore
|
||||
num = RestoreGameNumber;
|
||||
}
|
||||
}
|
||||
|
||||
assert(num >= 0);
|
||||
|
||||
RestoreGameNumber = num;
|
||||
|
@ -476,4 +559,14 @@ void RequestRestoreGame(int num, SAVED_DATA *sd, int *pSsCount, SAVED_DATA *pSsD
|
|||
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
|
||||
|
|
|
@ -28,19 +28,24 @@
|
|||
#include "tinsel/actors.h"
|
||||
#include "tinsel/background.h"
|
||||
#include "tinsel/config.h"
|
||||
#include "tinsel/drives.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/faders.h" // FadeOutFast()
|
||||
#include "tinsel/graphics.h" // ClearScreen()
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/inventory.h"
|
||||
#include "tinsel/heapmem.h"
|
||||
#include "tinsel/dialogs.h"
|
||||
#include "tinsel/music.h"
|
||||
#include "tinsel/pid.h"
|
||||
#include "tinsel/play.h"
|
||||
#include "tinsel/polygons.h"
|
||||
#include "tinsel/rince.h"
|
||||
#include "tinsel/savescn.h"
|
||||
#include "tinsel/scene.h"
|
||||
#include "tinsel/sched.h"
|
||||
#include "tinsel/scroll.h"
|
||||
#include "tinsel/sound.h"
|
||||
#include "tinsel/sysvar.h"
|
||||
#include "tinsel/tinlib.h"
|
||||
#include "tinsel/token.h"
|
||||
|
||||
|
@ -49,7 +54,6 @@ namespace Tinsel {
|
|||
//----------------- EXTERN FUNCTIONS --------------------
|
||||
|
||||
// in BG.C
|
||||
extern void startupBackground(SCNHANDLE bfilm);
|
||||
extern SCNHANDLE GetBgroundHandle(void);
|
||||
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)
|
||||
void RestoreProcess(INT_CONTEXT *pic);
|
||||
|
||||
// in PLAY.C
|
||||
extern void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y);
|
||||
|
||||
// in SCENE.C
|
||||
extern SCNHANDLE GetSceneHandle(void);
|
||||
extern void NewScene(SCNHANDLE scene, int entry);
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------- LOCAL DEFINES --------------------
|
||||
|
@ -77,6 +75,11 @@ enum {
|
|||
MAX_NEST = 4
|
||||
};
|
||||
|
||||
//----------------- EXTERNAL GLOBAL DATA --------------------
|
||||
|
||||
extern int thingHeld;
|
||||
extern int restoreCD;
|
||||
extern SRSTATE SRstate;
|
||||
|
||||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
||||
|
@ -84,54 +87,52 @@ static bool ASceneIsSaved = false;
|
|||
|
||||
static int savedSceneCount = 0;
|
||||
|
||||
//static SAVED_DATA s_ssData[MAX_NEST];
|
||||
static SAVED_DATA *s_ssData = 0;
|
||||
static bool bNotDoneYet = false;
|
||||
|
||||
//static SAVED_DATA ssData[MAX_NEST];
|
||||
static SAVED_DATA *ssData = NULL;
|
||||
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;
|
||||
|
||||
//----------------- 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.
|
||||
* @param sd Pointer to the scene data
|
||||
*/
|
||||
void SaveScene(SAVED_DATA *sd) {
|
||||
void DoSaveScene(SAVED_DATA *sd) {
|
||||
sd->SavedSceneHandle = GetSceneHandle();
|
||||
sd->SavedBgroundHandle = GetBgroundHandle();
|
||||
SaveMovers(sd->SavedMoverInfo);
|
||||
sd->NumSavedActors = SaveActors(sd->SavedActorInfo);
|
||||
PlayfieldGetPos(FIELD_WORLD, &sd->SavedLoffset, &sd->SavedToffset);
|
||||
SaveInterpretContexts(sd->SavedICInfo);
|
||||
SaveDeadPolys(sd->SavedDeadPolys);
|
||||
sd->SavedControl = TestToken(TOKEN_CONTROL);
|
||||
CurrentMidiFacts(&sd->SavedMidi, &sd->SavedLoop);
|
||||
sd->SavedNoBlocking = bNoBlocking;
|
||||
sd->SavedControl = ControlIsOn();
|
||||
sd->SavedNoBlocking = GetNoBlocking();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -140,13 +141,32 @@ void SaveScene(SAVED_DATA *sd) {
|
|||
* @param sd Pointer to the scene data
|
||||
* @param bFadeOut Flag to perform a fade out
|
||||
*/
|
||||
void RestoreScene(SAVED_DATA *sd, bool bFadeOut) {
|
||||
s_rsd = sd;
|
||||
void DoRestoreScene(SAVED_DATA *sd, bool bFadeOut) {
|
||||
rsd = sd;
|
||||
|
||||
if (bFadeOut)
|
||||
s_restoreSceneCount = RS_COUNT + COUNTOUT_COUNT; // Set restore scene count
|
||||
RestoreSceneCount = RS_COUNT + COUNTOUT_COUNT; // Set restore scene count
|
||||
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.
|
||||
* Also 'stand' all the moving actors at their saved positions.
|
||||
*/
|
||||
void sortActors(SAVED_DATA *rsd) {
|
||||
for (int i = 0; i < rsd->NumSavedActors; i++) {
|
||||
ActorsLife(rsd->SavedActorInfo[i].actorID, rsd->SavedActorInfo[i].bAlive);
|
||||
void sortActors(SAVED_DATA *sd) {
|
||||
assert(!TinselV2);
|
||||
for (int i = 0; i < sd->NumSavedActors; i++) {
|
||||
ActorsLife(sd->SavedActorInfo[i].actorID, sd->SavedActorInfo[i].bAlive);
|
||||
|
||||
// Should be playing the same reel.
|
||||
if (rsd->SavedActorInfo[i].presFilm != 0) {
|
||||
if (!actorAlive(rsd->SavedActorInfo[i].actorID))
|
||||
if (sd->SavedActorInfo[i].presFilm != 0) {
|
||||
if (!actorAlive(sd->SavedActorInfo[i].actorID))
|
||||
continue;
|
||||
|
||||
playThisReel(rsd->SavedActorInfo[i].presFilm, rsd->SavedActorInfo[i].presRnum, rsd->SavedActorInfo[i].z,
|
||||
rsd->SavedActorInfo[i].presX, rsd->SavedActorInfo[i].presY);
|
||||
RestoreActorReels(sd->SavedActorInfo[i].presFilm, sd->SavedActorInfo[i].presRnum, sd->SavedActorInfo[i].zFactor,
|
||||
sd->SavedActorInfo[i].presPlayX, sd->SavedActorInfo[i].presPlayY);
|
||||
}
|
||||
}
|
||||
|
||||
RestoreAuxScales(rsd->SavedMoverInfo);
|
||||
RestoreAuxScales(sd->SavedMoverInfo);
|
||||
for (int i = 0; i < MAX_MOVERS; i++) {
|
||||
if (rsd->SavedMoverInfo[i].MActorState == NORM_MACTOR)
|
||||
stand(rsd->SavedMoverInfo[i].actorID, rsd->SavedMoverInfo[i].objx,
|
||||
rsd->SavedMoverInfo[i].objy, rsd->SavedMoverInfo[i].lastfilm);
|
||||
if (sd->SavedMoverInfo[i].bActive)
|
||||
Stand(nullContext, sd->SavedMoverInfo[i].actorID, sd->SavedMoverInfo[i].objX,
|
||||
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
|
||||
if (rsd == &sgData) {
|
||||
if (!TinselV2 && (rsd == &sgData)) {
|
||||
g_scheduler->killMatchingProcess(PID_MASTER_SCR, -1);
|
||||
FreeMasterInterpretContext();
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_INTERPRET; i++) {
|
||||
for (int i = 0; i < NUM_INTERPRET; i++) {
|
||||
switch (rsd->SavedICInfo[i].GSort) {
|
||||
case GS_NONE:
|
||||
break;
|
||||
|
@ -203,14 +268,31 @@ void ResumeInterprets(SAVED_DATA *rsd) {
|
|||
RestoreMasterProcess(&rsd->SavedICInfo[i]);
|
||||
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:
|
||||
RestoreActorProcess(rsd->SavedICInfo[i].actorid, &rsd->SavedICInfo[i]);
|
||||
if (TinselV2)
|
||||
RestoreProcess(&rsd->SavedICInfo[i]);
|
||||
else
|
||||
RestoreActorProcess(rsd->SavedICInfo[i].idActor, &rsd->SavedICInfo[i]);
|
||||
break;
|
||||
|
||||
case GS_POLYGON:
|
||||
case GS_SCENE:
|
||||
RestoreProcess(&rsd->SavedICInfo[i]);
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("Unhandled GSort in ResumeInterprets");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +301,7 @@ void ResumeInterprets(SAVED_DATA *rsd) {
|
|||
* Do restore scene
|
||||
* @param n Id
|
||||
*/
|
||||
static int DoRestoreScene(SAVED_DATA *rsd, int n) {
|
||||
static int DoRestoreSceneFrame(SAVED_DATA *sd, int n) {
|
||||
switch (n) {
|
||||
case RS_COUNT + COUNTOUT_COUNT:
|
||||
// Trigger pre-load and fade and start countdown
|
||||
|
@ -229,31 +311,90 @@ static int DoRestoreScene(SAVED_DATA *rsd, int n) {
|
|||
case RS_COUNT:
|
||||
_vm->_sound->stopAllSamples();
|
||||
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);
|
||||
bNoFade = false;
|
||||
startupBackground(rsd->SavedBgroundHandle);
|
||||
KillScroll();
|
||||
PlayfieldSetPos(FIELD_WORLD, rsd->SavedLoffset, rsd->SavedToffset);
|
||||
bNoBlocking = rsd->SavedNoBlocking;
|
||||
RestoreNoScrollData(&rsd->SavedNoScrollData);
|
||||
/*
|
||||
break;
|
||||
StartupBackground(nullContext, sd->SavedBgroundHandle);
|
||||
|
||||
case RS_COUNT - 1:
|
||||
*/
|
||||
sortActors(rsd);
|
||||
if (TinselV2) {
|
||||
Offset(EX_USEXY, sd->SavedLoffset, sd->SavedToffset);
|
||||
} 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;
|
||||
|
||||
case 2:
|
||||
break;
|
||||
|
||||
case 1:
|
||||
RestoreMidiFacts(rsd->SavedMidi, rsd->SavedLoop);
|
||||
if (rsd->SavedControl)
|
||||
control(CONTROL_ON); // TOKEN_CONTROL was free
|
||||
ResumeInterprets(rsd);
|
||||
if (TinselV2) {
|
||||
if (bNotDoneYet)
|
||||
return n;
|
||||
|
||||
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;
|
||||
|
@ -266,7 +407,7 @@ static int DoRestoreScene(SAVED_DATA *rsd, int n) {
|
|||
void RestoreGame(int num) {
|
||||
KillInventory();
|
||||
|
||||
RequestRestoreGame(num, &sgData, &savedSceneCount, s_ssData);
|
||||
RequestRestoreGame(num, &sgData, &savedSceneCount, ssData);
|
||||
|
||||
// Actual restoring is performed by ProcessSRQueue
|
||||
}
|
||||
|
@ -278,9 +419,9 @@ void RestoreGame(int num) {
|
|||
*/
|
||||
void SaveGame(char *name, char *desc) {
|
||||
// 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
|
||||
}
|
||||
|
@ -289,23 +430,23 @@ void SaveGame(char *name, char *desc) {
|
|||
//---------------------------------------------------------------------------------
|
||||
|
||||
bool IsRestoringScene() {
|
||||
if (s_restoreSceneCount) {
|
||||
s_restoreSceneCount = DoRestoreScene(s_rsd, s_restoreSceneCount);
|
||||
if (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
|
||||
if (s_restoreSceneCount == 0) {
|
||||
if (RestoreSceneCount == 0) {
|
||||
assert(savedSceneCount >= 1); // No saved scene to restore
|
||||
|
||||
if (ASceneIsSaved)
|
||||
RestoreScene(&s_ssData[--savedSceneCount], bFade);
|
||||
DoRestoreScene(&ssData[--savedSceneCount], bFade);
|
||||
if (!bFade)
|
||||
bNoFade = true;
|
||||
}
|
||||
|
@ -314,7 +455,7 @@ void PleaseRestoreScene(bool bFade) {
|
|||
/**
|
||||
* Please Save Scene
|
||||
*/
|
||||
void PleaseSaveScene(CORO_PARAM) {
|
||||
void TinselSaveScene(CORO_PARAM) {
|
||||
// only called by save_scene PCODE
|
||||
CORO_BEGIN_CONTEXT;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
@ -325,10 +466,10 @@ void PleaseSaveScene(CORO_PARAM) {
|
|||
|
||||
// Don't save the same thing multiple times!
|
||||
// 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();
|
||||
|
||||
SaveScene(&s_ssData[savedSceneCount++]);
|
||||
DoSaveScene(&ssData[savedSceneCount++]);
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,16 @@
|
|||
#include "tinsel/dw.h" // SCNHANDLE
|
||||
#include "tinsel/rince.h" // SAVED_MOVER
|
||||
#include "tinsel/pcode.h" // INT_CONTEXT
|
||||
#include "tinsel/play.h"
|
||||
#include "tinsel/polygons.h"
|
||||
#include "tinsel/scroll.h" // SCROLLDATA
|
||||
#include "tinsel/sysvar.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
enum {
|
||||
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
|
||||
// name field in savedFiles. Raising it to 256 as a preliminary fix.
|
||||
|
@ -66,6 +69,16 @@ struct SAVED_DATA {
|
|||
bool SavedLoop; // } Midi
|
||||
bool SavedNoBlocking;
|
||||
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
|
||||
};
|
||||
|
||||
void PleaseRestoreScene(bool bFade);
|
||||
void PleaseSaveScene(CORO_PARAM);
|
||||
void TinselRestoreScene(bool bFade);
|
||||
void TinselSaveScene(CORO_PARAM);
|
||||
void DoRestoreScene(SAVED_DATA *sd, bool bFadeOut);
|
||||
void DoSaveScene(SAVED_DATA *sd);
|
||||
|
||||
bool IsRestoringScene();
|
||||
|
||||
|
@ -95,8 +110,8 @@ void ProcessSRQueue(void);
|
|||
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 InitialiseSs(void);
|
||||
void FreeSs(void);
|
||||
void InitialiseSaveScenes(void);
|
||||
void FreeSaveScenes(void);
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
||||
|
|
|
@ -29,21 +29,26 @@
|
|||
#include "tinsel/background.h"
|
||||
#include "tinsel/config.h"
|
||||
#include "tinsel/cursor.h"
|
||||
#include "tinsel/dialogs.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/graphics.h"
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/inventory.h"
|
||||
#include "tinsel/film.h"
|
||||
#include "tinsel/font.h"
|
||||
#include "tinsel/mareels.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/sched.h"
|
||||
#include "tinsel/scn.h"
|
||||
#include "tinsel/scroll.h"
|
||||
#include "tinsel/sound.h" // stopAllSamples()
|
||||
#include "tinsel/object.h"
|
||||
#include "tinsel/pcode.h"
|
||||
#include "tinsel/pid.h" // process IDs
|
||||
#include "tinsel/polygons.h"
|
||||
#include "tinsel/sysvar.h"
|
||||
#include "tinsel/token.h"
|
||||
|
||||
|
||||
|
@ -72,20 +77,28 @@ extern void EnableTags(void);
|
|||
|
||||
/** scene structure - one per scene */
|
||||
struct SCENE_STRUC {
|
||||
int32 numEntrance; //!< number of entrances in this scene
|
||||
int32 numPoly; //!< number of various polygons in this scene
|
||||
int32 numActor; //!< number of actors in this scene
|
||||
int32 defRefer; //!< Default refer direction
|
||||
SCNHANDLE hSceneScript; //!< handle to scene script
|
||||
SCNHANDLE hEntrance; //!< handle to table of entrances
|
||||
SCNHANDLE hPoly; //!< handle to table of polygons
|
||||
SCNHANDLE hActor; //!< handle to table of actors
|
||||
int32 defRefer; // Default refer direction (REFTYPE)
|
||||
SCNHANDLE hSceneScript; // handle to scene script
|
||||
SCNHANDLE hSceneDesc; // handle to scene description
|
||||
int32 numEntrance; // number of entrances in this scene
|
||||
SCNHANDLE hEntrance; // handle to table of entrances
|
||||
int32 numPoly; // number of various polygons in this scene
|
||||
SCNHANDLE hPoly; // handle to table of polygons
|
||||
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;
|
||||
|
||||
/** entrance structure - one per entrance */
|
||||
struct ENTRANCE_STRUC {
|
||||
int32 eNumber; //!< entrance number
|
||||
SCNHANDLE hScript; //!< handle to entrance script
|
||||
// Tinsel 2 fields
|
||||
SCNHANDLE hEntDesc; // handle to entrance description
|
||||
uint32 flags;
|
||||
} PACKED_STRUCT;
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
SCNHANDLE newestScene = 0;
|
||||
|
||||
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.
|
||||
|
@ -107,20 +151,59 @@ static void SceneTinselProcess(CORO_PARAM, const void *param) {
|
|||
// COROUTINE
|
||||
CORO_BEGIN_CONTEXT;
|
||||
INT_CONTEXT *pic;
|
||||
const TP_INIT *pInit;
|
||||
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);
|
||||
|
||||
_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);
|
||||
|
||||
if (_ctx->pInit->event == CLOSEDOWN || _ctx->pInit->event == LEAVE_T2)
|
||||
bWatchingOut = false;
|
||||
|
||||
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
|
||||
* Initialise polygons for the scene
|
||||
|
@ -128,47 +211,103 @@ static void SceneTinselProcess(CORO_PARAM, const void *param) {
|
|||
* Run the appropriate entrance code (if any)
|
||||
* Get the default refer type
|
||||
*/
|
||||
|
||||
static void LoadScene(SCNHANDLE scene, int entry) {
|
||||
uint i;
|
||||
TP_INIT init;
|
||||
const SCENE_STRUC *ss;
|
||||
const ENTRANCE_STRUC *es;
|
||||
uint i;
|
||||
|
||||
// Scene structure
|
||||
// Scene handle
|
||||
SceneHandle = scene; // Save scene handle in case of Save_Scene()
|
||||
|
||||
LockMem(SceneHandle); // Make sure scene is loaded
|
||||
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);
|
||||
|
||||
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
|
||||
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
|
||||
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)
|
||||
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 (es->hScript)
|
||||
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &es->hScript, sizeof(es->hScript));
|
||||
if (es->hScript) {
|
||||
init.event = STARTUP;
|
||||
init.hTinselCode = es->hScript;
|
||||
|
||||
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Move to next entrance
|
||||
if (TinselV2)
|
||||
++es;
|
||||
else
|
||||
es = (const ENTRANCE_STRUC *)((const byte *)es + 8);
|
||||
|
||||
}
|
||||
|
||||
if (i == FROM_LE_32(ss->numEntrance))
|
||||
error("Non-existant scene entry number");
|
||||
|
||||
if (ss->hSceneScript)
|
||||
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &ss->hSceneScript, sizeof(ss->hSceneScript));
|
||||
if (ss->hSceneScript) {
|
||||
init.event = STARTUP;
|
||||
init.hTinselCode = ss->hSceneScript;
|
||||
|
||||
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
|
||||
}
|
||||
}
|
||||
|
||||
// Default refer type
|
||||
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
|
||||
|
||||
DropPolygons(); // No polygons
|
||||
DropNoScrolls(); // No no-scrolls
|
||||
DropScroll(); // No no-scrolls
|
||||
DropBackground(); // No background
|
||||
DropMActors(); // No moving actors
|
||||
DropMovers(); // No moving actors
|
||||
DropCursor(); // No cursor
|
||||
DropActors(); // No actor reels running
|
||||
FreeAllTokens(); // No-one has tokens
|
||||
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->_mixer->stopAll();
|
||||
|
||||
// init the palette manager
|
||||
ResetPalAllocator();
|
||||
|
@ -251,10 +402,11 @@ void PrimeBackground(void) {
|
|||
*/
|
||||
|
||||
void PrimeScene(void) {
|
||||
|
||||
bNoBlocking = false;
|
||||
SetNoBlocking(false);
|
||||
SetSysVar(SYS_SceneFxDimFactor, SysVar(SYS_DefaultFxDimFactor));
|
||||
|
||||
RestartCursor(); // Restart the cursor
|
||||
if (!TinselV2)
|
||||
EnableTags(); // Next scene with tags enabled
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
void NewScene(SCNHANDLE scene, int entry) {
|
||||
void StartNewScene(SCNHANDLE scene, int entry) {
|
||||
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.
|
||||
|
||||
LoadScene(scene, entry);
|
||||
|
@ -303,4 +461,29 @@ SCNHANDLE GetSceneHandle(void) {
|
|||
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
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define TINSEL_SCENE_H
|
||||
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/events.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
|
@ -39,13 +40,19 @@ enum {
|
|||
MAX_ACTOR = 32 //!< maximum number of actors in a scene
|
||||
};
|
||||
|
||||
// ENTRANCE_STRUC bitflags
|
||||
enum ENTRANCE_FLAGS {
|
||||
fCall = 0x00000001L,
|
||||
fHook = 0x00000002L
|
||||
};
|
||||
|
||||
/** reference direction */
|
||||
enum REFTYPE {
|
||||
REF_DEFAULT, REF_UP, REF_DOWN, REF_LEFT, REF_RIGHT, REF_POINT
|
||||
};
|
||||
|
||||
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 */
|
||||
|
@ -68,6 +75,23 @@ enum REEL {
|
|||
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
|
||||
|
||||
#endif // TINSEL_SCENE_H
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
* Process scheduler.
|
||||
*/
|
||||
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/pcode.h"
|
||||
#include "tinsel/pid.h"
|
||||
#include "tinsel/polygons.h"
|
||||
#include "tinsel/sched.h"
|
||||
|
||||
#include "common/util.h"
|
||||
|
@ -32,18 +36,26 @@ namespace Tinsel {
|
|||
|
||||
Scheduler *g_scheduler = 0;
|
||||
|
||||
/** process structure */
|
||||
struct PROCESS {
|
||||
PROCESS *pNext; //!< pointer to next process in active or free list
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
|
||||
CoroContext state; //!< the state of the coroutine
|
||||
CORO_ADDR coroAddr; //!< the entry point of the coroutine
|
||||
struct PROCESS_STRUC {
|
||||
uint32 processId; // ID of process
|
||||
SCNHANDLE hProcessCode; // handle to actor script
|
||||
} PACKED_STRUCT;
|
||||
|
||||
int sleepTime; //!< number of scheduler cycles to sleep
|
||||
int pid; //!< process ID
|
||||
char param[PARAM_SIZE]; //!< process specific info
|
||||
};
|
||||
#include "common/pack-end.h" // END STRUCT PACKING
|
||||
|
||||
CoroContext nullContext = NULL;
|
||||
|
||||
//----------------- LOCAL GLOBAL DATA --------------------
|
||||
|
||||
static uint32 numSceneProcess;
|
||||
static SCNHANDLE hSceneProcess;
|
||||
|
||||
static uint32 numGlobalProcess;
|
||||
static PROCESS_STRUC *pGlobalProcess;
|
||||
|
||||
//--------------------- FUNCTIONS ------------------------
|
||||
|
||||
Scheduler::Scheduler() {
|
||||
processList = 0;
|
||||
|
@ -59,6 +71,7 @@ Scheduler::Scheduler() {
|
|||
pRCfunction = 0;
|
||||
|
||||
active = new PROCESS;
|
||||
active->pPrevious = NULL;
|
||||
|
||||
g_scheduler = this; // FIXME HACK
|
||||
}
|
||||
|
@ -83,7 +96,7 @@ void Scheduler::reset() {
|
|||
|
||||
if (processList == NULL) {
|
||||
// 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
|
||||
if (processList == NULL) {
|
||||
|
@ -91,7 +104,7 @@ void Scheduler::reset() {
|
|||
}
|
||||
|
||||
// fill with garbage
|
||||
memset(processList, 'S', NUM_PROCESS * sizeof(PROCESS));
|
||||
memset(processList, 'S', MAX_PROCESSES * sizeof(PROCESS));
|
||||
}
|
||||
|
||||
// no active processes
|
||||
|
@ -101,12 +114,10 @@ void Scheduler::reset() {
|
|||
pFreeProcesses = processList;
|
||||
|
||||
// link all other processes after first
|
||||
for (int i = 1; i < NUM_PROCESS; i++) {
|
||||
processList[i - 1].pNext = processList + i;
|
||||
for (int i = 1; i <= NUM_PROCESS; 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
|
||||
|
||||
#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
|
||||
*/
|
||||
void Scheduler::schedule(void) {
|
||||
// start dispatching active process list
|
||||
PROCESS *pPrevProc = active;
|
||||
PROCESS *pNext;
|
||||
PROCESS *pProc = active->pNext;
|
||||
while (pProc != NULL) {
|
||||
pNext = pProc->pNext;
|
||||
|
||||
if (--pProc->sleepTime <= 0) {
|
||||
// process is ready for dispatch, activate it
|
||||
pCurrent = pProc;
|
||||
pProc->coroAddr(pProc->state, pProc->param);
|
||||
pCurrent = NULL;
|
||||
|
||||
if (!pProc->state || pProc->state->_sleep <= 0) {
|
||||
// Coroutine finished
|
||||
pCurrent = pCurrent->pPrevious;
|
||||
killProcess(pProc);
|
||||
pProc = pPrevProc;
|
||||
} else {
|
||||
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.
|
||||
|
@ -172,16 +322,27 @@ PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pPara
|
|||
|
||||
// get link to next free process
|
||||
pFreeProcesses = pProc->pNext;
|
||||
if (pFreeProcesses)
|
||||
pFreeProcesses->pPrevious = NULL;
|
||||
|
||||
if (pCurrent != NULL) {
|
||||
// place new process before the next active process
|
||||
pProc->pNext = pCurrent->pNext;
|
||||
if (pProc->pNext)
|
||||
pProc->pNext->pPrevious = pProc;
|
||||
|
||||
// make this new process the next active process
|
||||
pCurrent->pNext = pProc;
|
||||
pProc->pPrevious = pCurrent;
|
||||
|
||||
} else { // no active processes, place process at head of list
|
||||
pProc->pNext = active->pNext;
|
||||
pProc->pPrevious = active;
|
||||
|
||||
if (pProc->pNext)
|
||||
pProc->pNext->pPrevious = pProc;
|
||||
active->pNext = pProc;
|
||||
|
||||
}
|
||||
|
||||
// set coroutine entry point
|
||||
|
@ -204,7 +365,6 @@ PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pPara
|
|||
memcpy(pProc->param, pParam, sizeParam);
|
||||
}
|
||||
|
||||
|
||||
// return created process
|
||||
return pProc;
|
||||
}
|
||||
|
@ -215,8 +375,6 @@ PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pPara
|
|||
* @param pKillProc which process to kill
|
||||
*/
|
||||
void Scheduler::killProcess(PROCESS *pKillProc) {
|
||||
PROCESS *pProc, *pPrev; // process list pointers
|
||||
|
||||
// make sure a valid process pointer
|
||||
assert(pKillProc >= processList && pKillProc <= processList + NUM_PROCESS - 1);
|
||||
|
||||
|
@ -229,32 +387,25 @@ void Scheduler::killProcess(PROCESS *pKillProc) {
|
|||
assert(numProcs >= 0);
|
||||
#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
|
||||
if (pRCfunction != NULL)
|
||||
(pRCfunction)(pProc);
|
||||
(pRCfunction)(pKillProc);
|
||||
|
||||
delete pProc->state;
|
||||
delete pKillProc->state;
|
||||
|
||||
// make prev point to next to unlink pProc
|
||||
pPrev->pNext = pProc->pNext;
|
||||
// Take the process out of the active chain list
|
||||
pKillProc->pPrevious->pNext = pKillProc->pNext;
|
||||
if (pKillProc->pNext)
|
||||
pKillProc->pNext->pPrevious = pKillProc->pPrevious;
|
||||
|
||||
// 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
|
||||
pFreeProcesses = pProc;
|
||||
|
||||
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");
|
||||
// make pKillProc the first free process
|
||||
pFreeProcesses = pKillProc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -302,11 +453,21 @@ int Scheduler::killMatchingProcess(int pidKill, int pidMask) {
|
|||
// kill this process
|
||||
numKilled++;
|
||||
|
||||
// Free the process' resources
|
||||
if (pRCfunction != NULL)
|
||||
(pRCfunction)(pProc);
|
||||
|
||||
delete pProc->state;
|
||||
|
||||
// make prev point to next to unlink pProc
|
||||
pPrev->pNext = pProc->pNext;
|
||||
if (pProc->pNext)
|
||||
pPrev->pNext->pPrevious = pPrev;
|
||||
|
||||
// link first free process after pProc
|
||||
pProc->pNext = pFreeProcesses;
|
||||
pProc->pPrevious = NULL;
|
||||
pFreeProcesses->pPrevious = pProc;
|
||||
|
||||
// make pProc the first free process
|
||||
pFreeProcesses = pProc;
|
||||
|
@ -327,8 +488,6 @@ int Scheduler::killMatchingProcess(int pidKill, int pidMask) {
|
|||
return numKilled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set pointer to a function to be called by killProcess().
|
||||
*
|
||||
|
@ -342,4 +501,262 @@ void Scheduler::setResourceCallback(VFPTRPP 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
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
#include "tinsel/dw.h" // new data types
|
||||
#include "tinsel/coroutine.h"
|
||||
#include "tinsel/events.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
|
@ -36,12 +38,26 @@ namespace Tinsel {
|
|||
#define PARAM_SIZE 32
|
||||
|
||||
// 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 *);
|
||||
|
||||
/** 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).
|
||||
|
@ -69,6 +85,8 @@ private:
|
|||
// diagnostic process counters
|
||||
int numProcs;
|
||||
int maxProcs;
|
||||
|
||||
void CheckStack();
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -90,13 +108,16 @@ public:
|
|||
#endif
|
||||
|
||||
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);
|
||||
void killProcess(PROCESS *pKillProc);
|
||||
|
||||
PROCESS *getCurrentProcess();
|
||||
int getCurrentPID() const;
|
||||
int killMatchingProcess(int pidKill, int pidMask);
|
||||
int killMatchingProcess(int pidKill, int pidMask = -1);
|
||||
|
||||
|
||||
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
|
||||
|
||||
//----------------- 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
|
||||
|
||||
#endif // TINSEL_SCHED_H
|
||||
|
|
|
@ -47,10 +47,15 @@ byte *FindChunk(SCNHANDLE handle, uint32 chunk) {
|
|||
uint32 *lptr = (uint32 *)bptr;
|
||||
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
|
||||
// the same in V1 and V2
|
||||
if (_vm->getVersion() == TINSEL_V0 &&
|
||||
// the same in V0 and V1
|
||||
if (TinselVersion == TINSEL_V0 &&
|
||||
chunk != CHUNK_STRING && chunk != CHUNK_BITMAP)
|
||||
chunk -= 0x2L;
|
||||
|
||||
|
@ -70,10 +75,10 @@ byte *FindChunk(SCNHANDLE handle, uint32 chunk) {
|
|||
/**
|
||||
* Get the actor id from a film (column 0)
|
||||
*/
|
||||
int extractActor(SCNHANDLE film) {
|
||||
const FILM *pfilm = (const FILM *)LockMem(film);
|
||||
const FREEL *preel = &pfilm->reels[0];
|
||||
const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(preel->mobj));
|
||||
int ExtractActor(SCNHANDLE hFilm) {
|
||||
const FILM *pFilm = (const FILM *)LockMem(hFilm);
|
||||
const FREEL *pReel = &pFilm->reels[0];
|
||||
const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj));
|
||||
return (int)FROM_LE_32(pmi->mulID);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,14 @@
|
|||
|
||||
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
|
||||
|
||||
|
@ -48,20 +56,42 @@ namespace Tinsel {
|
|||
#define CHUNK_ENTRANCE 0x3334000BL // not used!
|
||||
#define CHUNK_POLYGONS 0x3334000CL // not used!
|
||||
#define CHUNK_ACTORS 0x3334000DL // not used!
|
||||
#define CHUNK_SCENE 0x3334000EL
|
||||
#define CHUNK_TOTAL_ACTORS 0x3334000FL
|
||||
#define CHUNK_TOTAL_GLOBALS 0x33340010L
|
||||
#define CHUNK_TOTAL_OBJECTS 0x33340011L
|
||||
#define CHUNK_OBJECTS 0x33340012L
|
||||
#define CHUNK_MIDI 0x33340013L // not used!
|
||||
#define CHUNK_SAMPLE 0x33340014L // not used!
|
||||
#define CHUNK_TOTAL_POLY 0x33340015L
|
||||
#define CHUNK_MBSTRING 0x33340022L // Multi-byte characters
|
||||
|
||||
#define CHUNK_PROCESSES 0x3334000EL // Tinsel 2 only
|
||||
|
||||
// Following chunk Ids should be decremented by 1 for Tinsel 1
|
||||
#define CHUNK_SCENE 0x3334000FL
|
||||
#define CHUNK_TOTAL_ACTORS 0x33340010L
|
||||
#define CHUNK_TOTAL_GLOBALS 0x33340011L
|
||||
#define CHUNK_TOTAL_OBJECTS 0x33340012L
|
||||
#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
|
||||
|
||||
byte *FindChunk(SCNHANDLE handle, uint32 chunk);
|
||||
int extractActor(SCNHANDLE film);
|
||||
int ExtractActor(SCNHANDLE hFilm);
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
||||
|
|
|
@ -33,17 +33,11 @@
|
|||
#include "tinsel/rince.h"
|
||||
#include "tinsel/scroll.h"
|
||||
#include "tinsel/sched.h"
|
||||
#include "tinsel/sysvar.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
//----------------- EXTERNAL FUNCTIONS ---------------------
|
||||
|
||||
// in BG.C
|
||||
extern int BackgroundWidth(void);
|
||||
extern int BackgroundHeight(void);
|
||||
|
||||
|
||||
|
||||
//----------------- LOCAL DEFINES --------------------
|
||||
|
||||
#define LEFT 'L'
|
||||
|
@ -58,7 +52,7 @@ extern int BackgroundHeight(void);
|
|||
static int LeftScroll = 0, DownScroll = 0; // Number of iterations outstanding
|
||||
|
||||
static int scrollActor = 0;
|
||||
static PMACTOR psActor = 0;
|
||||
static PMOVER pScrollMover = 0;
|
||||
static int oldx = 0, oldy = 0;
|
||||
|
||||
/** 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,
|
||||
// DW2 fields
|
||||
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
|
||||
// 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.
|
||||
* Checks for no-scroll boundaries and sets off a scroll if allowed.
|
||||
|
@ -157,9 +153,14 @@ static void NeedScroll(int direction) {
|
|||
}
|
||||
|
||||
if (LeftScroll <= 0) {
|
||||
scrollPixels = SCROLLPIXELS;
|
||||
if (TinselV2) {
|
||||
scrollPixelsX = sd.xSpeed;
|
||||
LeftScroll += sd.xDistance;
|
||||
} else {
|
||||
scrollPixelsX = SCROLLPIXELS;
|
||||
LeftScroll = RLSCROLL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RIGHT: /* Picture will go right, 'camera' left */
|
||||
|
@ -175,9 +176,14 @@ static void NeedScroll(int direction) {
|
|||
}
|
||||
|
||||
if (LeftScroll >= 0) {
|
||||
scrollPixels = SCROLLPIXELS;
|
||||
if (TinselV2) {
|
||||
scrollPixelsX = sd.xSpeed;
|
||||
LeftScroll -= sd.xDistance;
|
||||
} else {
|
||||
scrollPixelsX = SCROLLPIXELS;
|
||||
LeftScroll = -RLSCROLL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case UP: /* Picture will go upwards, 'camera' downwards */
|
||||
|
@ -194,9 +200,14 @@ static void NeedScroll(int direction) {
|
|||
}
|
||||
|
||||
if (DownScroll <= 0) {
|
||||
scrollPixels = SCROLLPIXELS;
|
||||
if (TinselV2) {
|
||||
scrollPixelsY = sd.ySpeed;
|
||||
DownScroll += sd.yDistance;
|
||||
} else {
|
||||
scrollPixelsY = SCROLLPIXELS;
|
||||
DownScroll = UDSCROLL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DOWN: /* Picture will go downwards, 'camera' upwards */
|
||||
|
@ -212,9 +223,14 @@ static void NeedScroll(int direction) {
|
|||
}
|
||||
|
||||
if (DownScroll >= 0) {
|
||||
scrollPixels = SCROLLPIXELS;
|
||||
if (TinselV2) {
|
||||
scrollPixelsY = sd.ySpeed;
|
||||
DownScroll -= sd.yDistance;
|
||||
} else {
|
||||
scrollPixelsY = SCROLLPIXELS;
|
||||
DownScroll = -UDSCROLL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +250,7 @@ static void ScrollImage(void) {
|
|||
* Keeping cursor on a tag?
|
||||
*/
|
||||
if (ScrollCursor) {
|
||||
GetCursorXY(&curX, &curY, true);
|
||||
GetCursorXYNoWait(&curX, &curY, true);
|
||||
if (InPolygon(curX, curY, TAG) != NOPOLY || InPolygon(curX, curY, EXIT) != NOPOLY) {
|
||||
OldLoffset = Loffset;
|
||||
OldToffset = Toffset;
|
||||
|
@ -246,49 +262,66 @@ static void ScrollImage(void) {
|
|||
* Horizontal scrolling
|
||||
*/
|
||||
if (LeftScroll > 0) {
|
||||
LeftScroll -= scrollPixels;
|
||||
LeftScroll -= scrollPixelsX;
|
||||
if (LeftScroll < 0) {
|
||||
Loffset += LeftScroll;
|
||||
LeftScroll = 0;
|
||||
}
|
||||
Loffset += scrollPixels; // Move right
|
||||
Loffset += scrollPixelsX; // Move right
|
||||
if (Loffset > ImageW - SCREEN_WIDTH)
|
||||
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) {
|
||||
LeftScroll += scrollPixels;
|
||||
LeftScroll += scrollPixelsX;
|
||||
if (LeftScroll > 0) {
|
||||
Loffset += LeftScroll;
|
||||
LeftScroll = 0;
|
||||
}
|
||||
Loffset -= scrollPixels; // Move left
|
||||
Loffset -= scrollPixelsX; // Move left
|
||||
if (Loffset < 0)
|
||||
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
|
||||
*/
|
||||
if (DownScroll > 0) {
|
||||
DownScroll -= scrollPixels;
|
||||
DownScroll -= scrollPixelsY;
|
||||
if (DownScroll < 0) {
|
||||
Toffset += DownScroll;
|
||||
DownScroll = 0;
|
||||
}
|
||||
Toffset += scrollPixels; // Move down
|
||||
Toffset += scrollPixelsY; // Move down
|
||||
|
||||
if (Toffset > ImageH - SCREEN_HEIGHT)
|
||||
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) {
|
||||
DownScroll += scrollPixels;
|
||||
DownScroll += scrollPixelsY;
|
||||
if (DownScroll > 0) {
|
||||
Toffset += DownScroll;
|
||||
DownScroll = 0;
|
||||
}
|
||||
Toffset -= scrollPixels; // Move up
|
||||
Toffset -= scrollPixelsY; // Move up
|
||||
|
||||
if (Toffset < 0)
|
||||
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
|
||||
*/
|
||||
if (!psActor || getMActorHideState(psActor)
|
||||
|| getMActorState(psActor) == NO_MACTOR)
|
||||
if (!pScrollMover || MoverHidden(pScrollMover) || !MoverIs(pScrollMover))
|
||||
return;
|
||||
|
||||
GetActorPos(scrollActor, &newx, &newy);
|
||||
|
@ -326,7 +358,7 @@ static void MonitorScroll(void) {
|
|||
/*
|
||||
* Approaching right side or left side of the screen?
|
||||
*/
|
||||
if (newx > Loffset+SCREEN_WIDTH-RLDISTANCE && Loffset < ImageW-SCREEN_WIDTH) {
|
||||
if (newx > Loffset+SCREEN_WIDTH - RLDISTANCE && Loffset < ImageW - SCREEN_WIDTH) {
|
||||
if (newx > oldx)
|
||||
NeedScroll(LEFT);
|
||||
} else if (newx < Loffset + RLDISTANCE && Loffset) {
|
||||
|
@ -337,10 +369,10 @@ static void MonitorScroll(void) {
|
|||
/*
|
||||
* 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)
|
||||
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)
|
||||
NeedScroll(DOWN);
|
||||
}
|
||||
|
@ -349,6 +381,30 @@ static void MonitorScroll(void) {
|
|||
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.
|
||||
*/
|
||||
|
@ -359,21 +415,28 @@ void ScrollProcess(CORO_PARAM, const void *) {
|
|||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
ImageH = BackgroundHeight(); // Dimensions
|
||||
ImageW = BackgroundWidth(); // of this scene.
|
||||
// In Tinsel v2, scenes may play movies, so the background may not always
|
||||
// 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
|
||||
if (ImageW == SCREEN_WIDTH && ImageH == SCREEN_HEIGHT)
|
||||
CORO_KILL_SELF();
|
||||
|
||||
if (!TinselV2) {
|
||||
LeftScroll = DownScroll = 0; // No iterations outstanding
|
||||
oldx = oldy = 0;
|
||||
scrollPixels = SCROLLPIXELS;
|
||||
scrollPixelsX = scrollPixelsY = SCROLLPIXELS;
|
||||
}
|
||||
|
||||
if (!scrollActor)
|
||||
scrollActor = LeadId();
|
||||
scrollActor = GetLeadId();
|
||||
|
||||
psActor = GetMover(scrollActor);
|
||||
pScrollMover = GetMover(scrollActor);
|
||||
|
||||
while (1) {
|
||||
MonitorScroll(); // Set scroll requirement
|
||||
|
@ -395,17 +458,26 @@ void ScrollFocus(int ano) {
|
|||
oldx = oldy = 0;
|
||||
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.
|
||||
*/
|
||||
void ScrollTo(int x, int y, int iter) {
|
||||
void ScrollTo(int x, int y, int xIter, int yIter) {
|
||||
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
|
||||
|
||||
|
@ -429,4 +501,35 @@ void RestoreNoScrollData(SCROLLDATA *ssd) {
|
|||
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
|
||||
|
|
|
@ -30,8 +30,10 @@ namespace Tinsel {
|
|||
|
||||
#define SCROLLPIXELS 8 // Number of pixels to scroll per iteration
|
||||
|
||||
#define RLDISTANCE 50 // Distance from edge that triggers a scroll
|
||||
#define UDDISTANCE 20
|
||||
// Distance from edge that triggers a scroll
|
||||
#define RLDISTANCE (TinselV2 ? sd.xTrigger : 50)
|
||||
#define UDISTANCE (TinselV2 ? sd.yTriggerTop : 20)
|
||||
#define DDISTANCE (TinselV2 ? sd.yTriggerBottom : 20)
|
||||
|
||||
// Number of iterations to make
|
||||
#define RLSCROLL 160 // 20*8 = 160 = half a screen
|
||||
|
@ -52,26 +54,39 @@ struct SCROLLDATA{
|
|||
NOSCROLLB NoVScroll[MAX_VNOSCROLL]; // Vertical no-scroll boundaries
|
||||
NOSCROLLB NoHScroll[MAX_HNOSCROLL]; // Horizontal 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 DoScrollCursor(void);
|
||||
|
||||
void SetNoScroll(int x1, int y1, int x2, int y2);
|
||||
void DropNoScrolls(void);
|
||||
void DropScroll(void);
|
||||
|
||||
void ScrollProcess(CORO_PARAM, const void *);
|
||||
|
||||
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 GetNoScrollData(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
|
||||
|
||||
#endif /* TINSEL_SCROLL_H */
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "tinsel/music.h"
|
||||
#include "tinsel/strres.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
#include "tinsel/sysvar.h"
|
||||
#include "tinsel/background.h"
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/file.h"
|
||||
|
@ -38,14 +40,20 @@
|
|||
|
||||
#include "sound/mixer.h"
|
||||
#include "sound/audiocd.h"
|
||||
#include "sound/adpcm.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
extern LANGUAGE sampleLanguage;
|
||||
|
||||
//--------------------------- General data ----------------------------------
|
||||
|
||||
SoundManager::SoundManager(TinselEngine *vm) :
|
||||
//_vm(vm), // TODO: Enable this once global _vm var is gone
|
||||
_sampleIndex(0), _sampleIndexLen(0) {
|
||||
|
||||
for (int i = 0; i < kNumChannels; i++)
|
||||
_channels[i].sampleNum = _channels[i].subSample = -1;
|
||||
}
|
||||
|
||||
SoundManager::~SoundManager() {
|
||||
|
@ -67,24 +75,29 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
|
|||
if (!_vm->_mixer->isReady())
|
||||
return false;
|
||||
|
||||
Channel &curChan = _channels[kChannelTinsel1];
|
||||
|
||||
// stop any currently playing sample
|
||||
_vm->_mixer->stopHandle(_handle);
|
||||
_vm->_mixer->stopHandle(curChan.handle);
|
||||
|
||||
// make sure id is in range
|
||||
assert(id > 0 && id < _sampleIndexLen);
|
||||
|
||||
curChan.sampleNum = id;
|
||||
curChan.subSample = 0;
|
||||
|
||||
// get file offset for this sample
|
||||
int32 dwSampleIndex = _sampleIndex[id];
|
||||
uint32 dwSampleIndex = _sampleIndex[id];
|
||||
|
||||
// move to correct position in the sample file
|
||||
_sampleStream.seek(dwSampleIndex);
|
||||
if (_sampleStream.ioFailed() || _sampleStream.pos() != dwSampleIndex)
|
||||
error("File %s is corrupt", SAMPLE_FILE);
|
||||
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 %s is corrupt", SAMPLE_FILE);
|
||||
error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage));
|
||||
|
||||
// allocate a buffer
|
||||
void *sampleBuf = malloc(sampleLen);
|
||||
|
@ -92,7 +105,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
|
|||
|
||||
// read all of the sample
|
||||
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 ;)
|
||||
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volSound);
|
||||
|
@ -101,15 +114,211 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
|
|||
|
||||
|
||||
// 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);
|
||||
|
||||
if (handle)
|
||||
*handle = _handle;
|
||||
*handle = curChan.handle;
|
||||
|
||||
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.
|
||||
* @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.
|
||||
*/
|
||||
bool SoundManager::sampleIsPlaying(void) {
|
||||
return _vm->_mixer->isSoundHandleActive(_handle);
|
||||
bool SoundManager::sampleIsPlaying(int id) {
|
||||
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) {
|
||||
// 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;
|
||||
|
||||
// open sample index file in binary mode
|
||||
if (f.open(SAMPLE_INDEX)) {
|
||||
if (f.open(_vm->getSampleIndex(sampleLanguage))) {
|
||||
// get length of index file
|
||||
f.seek(0, SEEK_END); // move to end of file
|
||||
_sampleIndexLen = f.pos(); // get file pointer
|
||||
|
@ -166,7 +413,7 @@ void SoundManager::openSampleFiles(void) {
|
|||
|
||||
if (_sampleIndex == NULL) {
|
||||
// allocate a buffer for the indices
|
||||
_sampleIndex = (int32 *)malloc(_sampleIndexLen);
|
||||
_sampleIndex = (uint32 *)malloc(_sampleIndexLen);
|
||||
|
||||
// make sure memory allocated
|
||||
if (_sampleIndex == NULL) {
|
||||
|
@ -179,7 +426,7 @@ void SoundManager::openSampleFiles(void) {
|
|||
// load data
|
||||
if (f.read(_sampleIndex, _sampleIndexLen) != (uint32)_sampleIndexLen)
|
||||
// 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
|
||||
// Convert all ids from LE to native format
|
||||
|
@ -194,18 +441,25 @@ void SoundManager::openSampleFiles(void) {
|
|||
// convert file size to size in DWORDs
|
||||
_sampleIndexLen /= sizeof(uint32);
|
||||
} else
|
||||
error("Cannot find file %s", SAMPLE_INDEX);
|
||||
error(CANNOT_FIND_FILE, _vm->getSampleIndex(sampleLanguage));
|
||||
|
||||
// open sample file in binary mode
|
||||
if (!_sampleStream.open(SAMPLE_FILE))
|
||||
error("Cannot find file %s", SAMPLE_FILE);
|
||||
if (!_sampleStream.open(_vm->getSampleFile(sampleLanguage)))
|
||||
error(CANNOT_FIND_FILE, _vm->getSampleFile(sampleLanguage));
|
||||
|
||||
/*
|
||||
// gen length of the largest sample
|
||||
sampleBuffer.size = _sampleStream.readUint32LE();
|
||||
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
|
||||
|
|
|
@ -37,6 +37,11 @@
|
|||
|
||||
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 *|
|
||||
|
@ -44,14 +49,39 @@ namespace Tinsel {
|
|||
|
||||
class SoundManager {
|
||||
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
|
||||
|
||||
/** Sample handle */
|
||||
Audio::SoundHandle _handle;
|
||||
|
||||
/** Sample index buffer and number of entries */
|
||||
int32 *_sampleIndex;
|
||||
uint32 *_sampleIndex;
|
||||
|
||||
/** Number of entries in the sample index */
|
||||
long _sampleIndexLen;
|
||||
|
@ -59,19 +89,29 @@ protected:
|
|||
/** file stream for sample file */
|
||||
Common::File _sampleStream;
|
||||
|
||||
bool offscreenChecks(int x, int &y);
|
||||
int8 getPan(int x);
|
||||
|
||||
public:
|
||||
|
||||
SoundManager(TinselEngine *vm);
|
||||
~SoundManager();
|
||||
|
||||
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 stopSpecSample(int id, int sub = 0); // Stops a specific sample
|
||||
|
||||
void setSFXVolumes(uint8 volume);
|
||||
|
||||
bool sampleExists(int id);
|
||||
bool sampleIsPlaying(void);
|
||||
bool sampleIsPlaying(int id = -1);
|
||||
|
||||
// TODO: Internal method, make this protected?
|
||||
void openSampleFiles(void);
|
||||
void closeSampleStream(void);
|
||||
};
|
||||
|
||||
} // end of namespace Tinsel
|
||||
|
|
|
@ -40,18 +40,39 @@ int newestString;
|
|||
// buffer for resource strings
|
||||
static uint8 *textBuffer = 0;
|
||||
|
||||
// language resource string filenames
|
||||
static const char *languageFiles[] = {
|
||||
"english.txt",
|
||||
"french.txt",
|
||||
"german.txt",
|
||||
"italian.txt",
|
||||
"spanish.txt"
|
||||
static struct {
|
||||
bool bPresent;
|
||||
const char *szStem;
|
||||
SCNHANDLE hDescription;
|
||||
SCNHANDLE hFlagFilm;
|
||||
|
||||
} 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.
|
||||
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
|
||||
* @param newLang The new language
|
||||
|
@ -60,6 +81,9 @@ void ChangeLanguage(LANGUAGE newLang) {
|
|||
Common::File f;
|
||||
uint32 textLen = 0; // length of buffer
|
||||
|
||||
textLanguage = newLang;
|
||||
sampleLanguage = newLang;
|
||||
|
||||
if (textBuffer) {
|
||||
// free the previous buffer
|
||||
free(textBuffer);
|
||||
|
@ -69,9 +93,9 @@ void ChangeLanguage(LANGUAGE newLang) {
|
|||
// 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
|
||||
// language versions reused it rather than their proper filename
|
||||
if (!f.open(languageFiles[newLang])) {
|
||||
if ((newLang == TXT_ENGLISH) || !f.open(languageFiles[TXT_ENGLISH]))
|
||||
error("Cannot find file %s", languageFiles[newLang]);
|
||||
if (!f.open(_vm->getTextFile(newLang))) {
|
||||
if ((newLang == TXT_ENGLISH) || !f.open(_vm->getTextFile(TXT_ENGLISH)))
|
||||
error(CANNOT_FIND_FILE, _vm->getTextFile(newLang));
|
||||
}
|
||||
|
||||
// Check whether the file is compressed or not - for compressed files the
|
||||
|
@ -79,7 +103,7 @@ void ChangeLanguage(LANGUAGE newLang) {
|
|||
// identifier
|
||||
textLen = f.readUint32LE();
|
||||
if (f.ioFailed())
|
||||
error("File %s is corrupt", languageFiles[newLang]);
|
||||
error(FILE_IS_CORRUPT, _vm->getTextFile(newLang));
|
||||
|
||||
if (textLen == CHUNK_STRING || textLen == CHUNK_MBSTRING) {
|
||||
// the file is uncompressed
|
||||
|
@ -101,7 +125,7 @@ void ChangeLanguage(LANGUAGE newLang) {
|
|||
// load data
|
||||
if (f.read(textBuffer, textLen) != textLen)
|
||||
// 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
|
||||
f.close();
|
||||
|
@ -111,19 +135,11 @@ void ChangeLanguage(LANGUAGE newLang) {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* FindStringBase
|
||||
*/
|
||||
int LoadStringRes(int id, char *pBuffer, int bufferMax) {
|
||||
#ifdef DEBUG
|
||||
// For diagnostics
|
||||
newestString = id;
|
||||
#endif
|
||||
|
||||
static byte *FindStringBase(int id) {
|
||||
// base of string resource table
|
||||
uint8 *pText = textBuffer;
|
||||
byte *pText = textBuffer;
|
||||
|
||||
// index into text resource file
|
||||
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
|
||||
int strSkip = id % STRINGS_PER_CHUNK;
|
||||
|
||||
// length of string
|
||||
int len;
|
||||
|
||||
// skip to the correct chunk
|
||||
while (chunkSkip-- != 0) {
|
||||
// make sure chunk id is correct
|
||||
assert(READ_LE_UINT32(pText + index) == CHUNK_STRING || READ_LE_UINT32(pText + index) == CHUNK_MBSTRING);
|
||||
|
||||
if (READ_LE_UINT32(pText + index + sizeof(uint32)) == 0) {
|
||||
// TEMPORARY DIRTY BODGE
|
||||
strcpy(pBuffer, "!! HIGH STRING !!");
|
||||
|
||||
// string does not exist
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get index to next chunk
|
||||
|
@ -163,17 +173,114 @@ int LoadStringRes(int id, char *pBuffer, int bufferMax) {
|
|||
// skip to the correct string
|
||||
while (strSkip-- != 0) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
// copy the string to the buffer
|
||||
if (len < bufferMax) {
|
||||
if (len < bufferMax)
|
||||
{
|
||||
memcpy(pBuffer, pText + 1, len);
|
||||
|
||||
// null terminate
|
||||
|
@ -199,6 +306,42 @@ int LoadStringRes(int id, char *pBuffer, int bufferMax) {
|
|||
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() {
|
||||
if (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
|
||||
|
|
|
@ -58,11 +58,44 @@ void ChangeLanguage(LANGUAGE newLang);
|
|||
*/
|
||||
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()
|
||||
*/
|
||||
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
|
||||
|
||||
#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 hFont Which font to use
|
||||
* @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,
|
||||
SCNHANDLE hFont, int mode) {
|
||||
OBJECT *ObjectTextOut(CORO_PARAM, OBJECT *pList, char *szStr, int colour,
|
||||
int xPos, int yPos, SCNHANDLE hFont, int mode, int sleepTime) {
|
||||
int xJustify; // x position of text after justification
|
||||
int yOffset; // offset to next line of text
|
||||
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']));
|
||||
|
||||
// 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) {
|
||||
// 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
|
||||
pChar->hImg = hImg; // image def
|
||||
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
|
||||
|
||||
// check for absolute positioning
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#ifndef TINSEL_TEXT_H // prevent multiple includes
|
||||
#define TINSEL_TEXT_H
|
||||
|
||||
#include "tinsel/coroutine.h"
|
||||
#include "tinsel/object.h" // object manager defines
|
||||
|
||||
namespace Tinsel {
|
||||
|
@ -42,6 +43,10 @@ enum {
|
|||
/** maximum number of characters in a font */
|
||||
#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
|
||||
|
||||
|
@ -80,14 +85,21 @@ struct TEXTOUT {
|
|||
|* Text Function Prototypes *|
|
||||
\*----------------------------------------------------------------------*/
|
||||
|
||||
OBJECT *ObjectTextOut( // output a string of text
|
||||
OBJECT *pList, // object list to add text to
|
||||
char *szStr, // string to output
|
||||
int colour, // colour for monochrome text
|
||||
int xPos, // x position of string
|
||||
int yPos, // y position of string
|
||||
SCNHANDLE hFont, // which font to use
|
||||
int mode); // mode flags for the string
|
||||
/**
|
||||
* Main text outputting routine. If a object list is specified a
|
||||
* multi-object is created for the whole text and a pointer to the head
|
||||
* of the list is returned.
|
||||
* @param pList object list to add text to
|
||||
* @param szStr string to output
|
||||
* @param colour colour for monochrome text
|
||||
* @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
|
||||
TEXTOUT *pText); // pointer to TextOut struct with all parameters
|
||||
|
|
|
@ -151,7 +151,7 @@ void FettleTimers(void) {
|
|||
/**
|
||||
* 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;
|
||||
|
||||
assert(num); // zero is not allowed as a timer number
|
||||
|
|
|
@ -44,7 +44,7 @@ void syncTimerInfo(Serializer &s);
|
|||
|
||||
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);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,13 +28,40 @@
|
|||
#define TINSEL_TINLIB_H
|
||||
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/object.h"
|
||||
#include "tinsel/palette.h"
|
||||
|
||||
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
|
||||
|
||||
void control(int param);
|
||||
void stand(int actor, int x, int y, SCNHANDLE film);
|
||||
void ActorBrightness(int actor, int brightness);
|
||||
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
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/error.h"
|
||||
#include "common/events.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/file.h"
|
||||
|
@ -44,13 +45,15 @@
|
|||
#include "tinsel/background.h"
|
||||
#include "tinsel/config.h"
|
||||
#include "tinsel/cursor.h"
|
||||
#include "tinsel/drives.h"
|
||||
#include "tinsel/dw.h"
|
||||
#include "tinsel/events.h"
|
||||
#include "tinsel/faders.h"
|
||||
#include "tinsel/film.h"
|
||||
#include "tinsel/handle.h"
|
||||
#include "tinsel/heapmem.h" // MemoryInit
|
||||
#include "tinsel/inventory.h"
|
||||
#include "tinsel/dialogs.h"
|
||||
#include "tinsel/mareels.h"
|
||||
#include "tinsel/music.h"
|
||||
#include "tinsel/object.h"
|
||||
#include "tinsel/pid.h"
|
||||
|
@ -60,6 +63,7 @@
|
|||
#include "tinsel/serializer.h"
|
||||
#include "tinsel/sound.h"
|
||||
#include "tinsel/strres.h"
|
||||
#include "tinsel/sysvar.h"
|
||||
#include "tinsel/timers.h"
|
||||
#include "tinsel/tinsel.h"
|
||||
|
||||
|
@ -71,6 +75,14 @@ namespace Tinsel {
|
|||
extern void SetDoFadeIn(bool tf);
|
||||
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
|
||||
extern void CursorProcess(CORO_PARAM, const void *);
|
||||
|
||||
|
@ -79,7 +91,6 @@ extern void InventoryProcess(CORO_PARAM, const void *);
|
|||
|
||||
// In SCENE.CPP
|
||||
extern void PrimeBackground();
|
||||
extern void NewScene(SCNHANDLE scene, int entry);
|
||||
extern SCNHANDLE GetSceneHandle(void);
|
||||
|
||||
// In TIMER.CPP
|
||||
|
@ -94,6 +105,12 @@ void SetNewScene(SCNHANDLE scene, int entrance, int transition);
|
|||
bool bRestart = false;
|
||||
bool bHasRestarted = false;
|
||||
|
||||
static bool bCuttingScene = false;
|
||||
|
||||
static bool bChangingForRestore = false;
|
||||
|
||||
static Common::Point clickPos;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool bFast; // set to make it go ludicrously fast
|
||||
#endif
|
||||
|
@ -110,11 +127,11 @@ static Scene NextScene = { 0, 0, 0 };
|
|||
static Scene HookScene = { 0, 0, 0 };
|
||||
static Scene DelayedScene = { 0, 0, 0 };
|
||||
|
||||
static bool bHookSuspend = false;
|
||||
|
||||
static PROCESS *pMouseProcess = 0;
|
||||
static PROCESS *pKeyboardProcess = 0;
|
||||
|
||||
static SCNHANDLE hCdChangeScene;
|
||||
|
||||
// Stack of pending mouse button events
|
||||
Common::List<Common::EventType> mouseButtons;
|
||||
|
||||
|
@ -142,6 +159,7 @@ void KeyboardProcess(CORO_PARAM, const void *) {
|
|||
// Get the next keyboard event off the stack
|
||||
Common::Event evt = *keypresses.begin();
|
||||
keypresses.erase(keypresses.begin());
|
||||
const Common::Point mousePos = _vm->getMousePosition();
|
||||
|
||||
// Switch for special keys
|
||||
switch (evt.kbd.keycode) {
|
||||
|
@ -150,21 +168,21 @@ void KeyboardProcess(CORO_PARAM, const void *) {
|
|||
case Common::KEYCODE_RALT:
|
||||
if (evt.type == Common::EVENT_KEYDOWN) {
|
||||
if (!bSwapButtons)
|
||||
ProcessButEvent(BE_RDSTART);
|
||||
ProcessButEvent(PLR_DRAG2_START);
|
||||
else
|
||||
ProcessButEvent(BE_LDSTART);
|
||||
ProcessButEvent(PLR_DRAG1_START);
|
||||
} else {
|
||||
if (!bSwapButtons)
|
||||
ProcessButEvent(BE_LDEND);
|
||||
ProcessButEvent(PLR_DRAG1_END);
|
||||
else
|
||||
ProcessButEvent(BE_RDEND);
|
||||
ProcessButEvent(PLR_DRAG2_END);
|
||||
}
|
||||
continue;
|
||||
|
||||
case Common::KEYCODE_LCTRL:
|
||||
case Common::KEYCODE_RCTRL:
|
||||
if (evt.type == Common::EVENT_KEYDOWN) {
|
||||
ProcessKeyEvent(LOOK_KEY);
|
||||
ProcessKeyEvent(PLR_LOOK);
|
||||
} else {
|
||||
// Control key release
|
||||
}
|
||||
|
@ -186,42 +204,42 @@ void KeyboardProcess(CORO_PARAM, const void *) {
|
|||
switch (evt.kbd.keycode) {
|
||||
/*** SPACE = WALKTO ***/
|
||||
case Common::KEYCODE_SPACE:
|
||||
ProcessKeyEvent(WALKTO_KEY);
|
||||
ProcessKeyEvent(PLR_WALKTO);
|
||||
continue;
|
||||
|
||||
/*** RETURN = ACTION ***/
|
||||
case Common::KEYCODE_RETURN:
|
||||
case Common::KEYCODE_KP_ENTER:
|
||||
ProcessKeyEvent(ACTION_KEY);
|
||||
ProcessKeyEvent(PLR_ACTION);
|
||||
continue;
|
||||
|
||||
/*** l = LOOK ***/
|
||||
case Common::KEYCODE_l: // LOOK
|
||||
ProcessKeyEvent(LOOK_KEY);
|
||||
ProcessKeyEvent(PLR_LOOK);
|
||||
continue;
|
||||
|
||||
case Common::KEYCODE_ESCAPE:
|
||||
// WORKAROUND: Check if any of the starting logo screens are active, and if so
|
||||
// manually skip to the title screen, allowing them to be bypassed
|
||||
{
|
||||
if (!TinselV2) {
|
||||
// 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 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) &&
|
||||
((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) {
|
||||
// Skip to title screen
|
||||
// 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
|
||||
SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);
|
||||
} else
|
||||
#endif
|
||||
if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) {
|
||||
} else if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) {
|
||||
// Skip to title screen
|
||||
SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);
|
||||
} else {
|
||||
// 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;
|
||||
|
||||
|
@ -236,48 +254,79 @@ void KeyboardProcess(CORO_PARAM, const void *) {
|
|||
|
||||
case Common::KEYCODE_F1:
|
||||
// Options dialog
|
||||
ProcessKeyEvent(OPTION_KEY);
|
||||
ProcessKeyEvent(PLR_MENU);
|
||||
continue;
|
||||
case Common::KEYCODE_F5:
|
||||
// Save game
|
||||
ProcessKeyEvent(SAVE_KEY);
|
||||
ProcessKeyEvent(PLR_SAVE);
|
||||
continue;
|
||||
case Common::KEYCODE_F7:
|
||||
// Load game
|
||||
ProcessKeyEvent(LOAD_KEY);
|
||||
ProcessKeyEvent(PLR_LOAD);
|
||||
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:
|
||||
if ((evt.kbd.flags == Common::KBD_CTRL) || (evt.kbd.flags == Common::KBD_ALT))
|
||||
ProcessKeyEvent(QUIT_KEY);
|
||||
ProcessKeyEvent(PLR_QUIT);
|
||||
continue;
|
||||
case Common::KEYCODE_PAGEUP:
|
||||
case Common::KEYCODE_KP9:
|
||||
ProcessKeyEvent(PGUP_KEY);
|
||||
ProcessKeyEvent(PLR_PGUP);
|
||||
continue;
|
||||
case Common::KEYCODE_PAGEDOWN:
|
||||
case Common::KEYCODE_KP3:
|
||||
ProcessKeyEvent(PGDN_KEY);
|
||||
ProcessKeyEvent(PLR_PGDN);
|
||||
continue;
|
||||
case Common::KEYCODE_HOME:
|
||||
case Common::KEYCODE_KP7:
|
||||
ProcessKeyEvent(HOME_KEY);
|
||||
ProcessKeyEvent(PLR_HOME);
|
||||
continue;
|
||||
case Common::KEYCODE_END:
|
||||
case Common::KEYCODE_KP1:
|
||||
ProcessKeyEvent(END_KEY);
|
||||
ProcessKeyEvent(PLR_END);
|
||||
continue;
|
||||
default:
|
||||
ProcessKeyEvent(NOEVENT_KEY);
|
||||
ProcessKeyEvent(PLR_NOEVENT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
void MouseProcess(CORO_PARAM, const void *) {
|
||||
static void MouseProcess(CORO_PARAM, const void *) {
|
||||
// COROUTINE
|
||||
CORO_BEGIN_CONTEXT;
|
||||
bool lastLWasDouble;
|
||||
|
@ -292,9 +341,6 @@ void MouseProcess(CORO_PARAM, const void *) {
|
|||
_ctx->lastLeftClick = _ctx->lastRightClick = DwGetCurrentTime();
|
||||
|
||||
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()) {
|
||||
// allow scheduling
|
||||
|
@ -306,23 +352,46 @@ void MouseProcess(CORO_PARAM, const void *) {
|
|||
Common::EventType type = *mouseButtons.begin();
|
||||
mouseButtons.erase(mouseButtons.begin());
|
||||
|
||||
int xp, yp;
|
||||
GetCursorXYNoWait(&xp, &yp, true);
|
||||
const Common::Point mousePos(xp, yp);
|
||||
|
||||
switch (type) {
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
// left button press
|
||||
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
|
||||
ProcessButEvent(BE_LDSTART);
|
||||
ProcessButEvent(PLR_DRAG1_START);
|
||||
|
||||
// signal left double click event
|
||||
ProcessButEvent(BE_DLEFT);
|
||||
ProcessButEvent(PLR_DLEFT);
|
||||
}
|
||||
|
||||
_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 {
|
||||
// signal left drag start
|
||||
ProcessButEvent(BE_LDSTART);
|
||||
ProcessButEvent(PLR_DRAG1_START);
|
||||
|
||||
// signal left single click event
|
||||
ProcessButEvent(BE_SLEFT);
|
||||
ProcessButEvent(PLR_SLEFT);
|
||||
}
|
||||
|
||||
_ctx->lastLWasDouble = false;
|
||||
}
|
||||
|
@ -332,32 +401,53 @@ void MouseProcess(CORO_PARAM, const void *) {
|
|||
// left button release
|
||||
|
||||
// update click timer
|
||||
if (_ctx->lastLWasDouble == false)
|
||||
if (_ctx->lastLWasDouble == false) {
|
||||
_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;
|
||||
|
||||
if (TinselV2)
|
||||
// Signal left drag end
|
||||
PlayerEvent(PLR_DRAG1_END, mousePos);
|
||||
else
|
||||
// signal left drag end
|
||||
ProcessButEvent(BE_LDEND);
|
||||
ProcessButEvent(PLR_DRAG1_END);
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
// right button press
|
||||
|
||||
if (DwGetCurrentTime() - _ctx->lastRightClick < (uint32)dclickSpeed) {
|
||||
// Right button double-click
|
||||
if (TinselV2) {
|
||||
PlayerEvent(PLR_NOEVENT, clickPos);
|
||||
} else {
|
||||
// signal right drag start
|
||||
ProcessButEvent(BE_RDSTART);
|
||||
ProcessButEvent(PLR_DRAG2_START);
|
||||
|
||||
// signal right double click event
|
||||
ProcessButEvent(BE_DRIGHT);
|
||||
ProcessButEvent(PLR_DRIGHT);
|
||||
}
|
||||
|
||||
_ctx->lastRWasDouble = true;
|
||||
} else {
|
||||
if (TinselV2) {
|
||||
PlayerEvent(PLR_DRAG2_START, mousePos);
|
||||
PlayerEvent(PLR_LOOK, mousePos);
|
||||
} else {
|
||||
// signal right drag start
|
||||
ProcessButEvent(BE_RDSTART);
|
||||
ProcessButEvent(PLR_DRAG2_START);
|
||||
|
||||
// signal right single click event
|
||||
ProcessButEvent(BE_SRIGHT);
|
||||
ProcessButEvent(PLR_SRIGHT);
|
||||
}
|
||||
|
||||
_ctx->lastRWasDouble = false;
|
||||
}
|
||||
|
@ -372,8 +462,12 @@ void MouseProcess(CORO_PARAM, const void *) {
|
|||
else
|
||||
_ctx->lastRightClick -= dclickSpeed;
|
||||
|
||||
if (TinselV2)
|
||||
// Signal left drag end
|
||||
PlayerEvent(PLR_DRAG2_END, mousePos);
|
||||
else
|
||||
// signal right drag end
|
||||
ProcessButEvent(BE_RDEND);
|
||||
ProcessButEvent(PLR_DRAG2_END);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -402,9 +496,24 @@ static void MasterScriptProcess(CORO_PARAM, const void *) {
|
|||
/**
|
||||
* Store the facts pertaining to a scene change.
|
||||
*/
|
||||
|
||||
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
|
||||
NextScene.scene = scene;
|
||||
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) {
|
||||
assert(HookScene.scene == 0); // scene already hooked
|
||||
|
||||
|
@ -432,6 +544,9 @@ void SetHookScene(SCNHANDLE scene, int entrance, int transition) {
|
|||
HookScene.trans = transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooked scene is over, trigger a change to the delayed scene
|
||||
*/
|
||||
void UnHookScene(void) {
|
||||
assert(DelayedScene.scene != 0); // no scene delayed
|
||||
|
||||
|
@ -444,11 +559,40 @@ void UnHookScene(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) {
|
||||
bHookSuspend = false;
|
||||
bCuttingScene = false;
|
||||
}
|
||||
|
||||
void syncSCdata(Serializer &s) {
|
||||
|
@ -468,16 +612,23 @@ static void RestoredProcess(CORO_PARAM, const void *param) {
|
|||
// COROUTINE
|
||||
CORO_BEGIN_CONTEXT;
|
||||
INT_CONTEXT *pic;
|
||||
bool bConverse;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
// 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->bConverse = TinselV2 && (_ctx->pic->event == CONVERSE);
|
||||
|
||||
CORO_INVOKE_1(Interpret, _ctx->pic);
|
||||
|
||||
// Restore control after CallScene() from a conversation icon
|
||||
if (_ctx->bConverse)
|
||||
ControlOn();
|
||||
|
||||
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 |
|
||||
* 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())
|
||||
return;
|
||||
return true;
|
||||
|
||||
if (NextScene.scene != 0) {
|
||||
if (!CountOut) {
|
||||
|
@ -517,12 +675,15 @@ void ChangeScene() {
|
|||
// Trigger pre-load and fade and start countdown
|
||||
CountOut = COUNTOUT_COUNT;
|
||||
FadeOutFast(NULL);
|
||||
if (TinselV2)
|
||||
_vm->_pcmMusic->startFadeOut(COUNTOUT_COUNT);
|
||||
break;
|
||||
}
|
||||
} else if (--CountOut == 0) {
|
||||
if (!TinselV2)
|
||||
ClearScreen();
|
||||
|
||||
NewScene(NextScene.scene, NextScene.entry);
|
||||
StartNewScene(NextScene.scene, NextScene.entry);
|
||||
NextScene.scene = 0;
|
||||
|
||||
switch (NextScene.trans) {
|
||||
|
@ -535,20 +696,32 @@ void ChangeScene() {
|
|||
SetDoFadeIn(true);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
_vm->_pcmMusic->fadeOutIteration();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* CuttingScene
|
||||
*/
|
||||
void CuttingScene(bool bCutting) {
|
||||
bCuttingScene = bCutting;
|
||||
|
||||
if (!bCutting)
|
||||
WrapScene();
|
||||
}
|
||||
|
||||
/**
|
||||
* LoadBasicChunks
|
||||
*/
|
||||
|
||||
void LoadBasicChunks(void) {
|
||||
byte *cptr;
|
||||
int numObjects;
|
||||
|
||||
// Allocate RAM for savescene data
|
||||
InitialiseSs();
|
||||
InitialiseSaveScenes();
|
||||
|
||||
// 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
|
||||
|
@ -581,6 +754,23 @@ void LoadBasicChunks(void) {
|
|||
cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_POLY);
|
||||
if (cptr != NULL)
|
||||
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 --------------------
|
||||
|
@ -602,10 +792,39 @@ static const GameSettings tinselSettings[] = {
|
|||
{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) :
|
||||
Engine(syst), _gameDescription(gameDesc) {
|
||||
_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
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
|
||||
|
@ -629,9 +848,10 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
|
|||
if (native_mt32)
|
||||
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
|
||||
|
||||
_music = new MusicPlayer(_driver);
|
||||
//_music->setNativeMT32(native_mt32);
|
||||
//_music->setAdlib(adlib);
|
||||
_midiMusic = new MidiMusicPlayer(_driver);
|
||||
_pcmMusic = new PCMMusicPlayer();
|
||||
//_midiMusic->setNativeMT32(native_mt32);
|
||||
//_midiMusic->setAdlib(adlib);
|
||||
|
||||
_musicVolume = ConfMan.getInt("music_volume");
|
||||
|
||||
|
@ -644,25 +864,38 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
|
|||
}
|
||||
|
||||
TinselEngine::~TinselEngine() {
|
||||
if (MoviePlaying())
|
||||
FinishBMV();
|
||||
|
||||
delete _sound;
|
||||
delete _music;
|
||||
delete _midiMusic;
|
||||
delete _pcmMusic;
|
||||
delete _console;
|
||||
delete _driver;
|
||||
_screenSurface.free();
|
||||
FreeSs();
|
||||
FreeSaveScenes();
|
||||
FreeTextBuffer();
|
||||
FreeHandleTable();
|
||||
FreeActors();
|
||||
FreeObjectList();
|
||||
FreeGlobalProcesses();
|
||||
FreeGlobals();
|
||||
delete _scheduler;
|
||||
}
|
||||
|
||||
Common::Error TinselEngine::init() {
|
||||
// Initialize backend
|
||||
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, false);
|
||||
|
||||
_screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, 1);
|
||||
if (getGameID() == GID_DW2) {
|
||||
#ifndef DW2_EXACT_SIZE
|
||||
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");
|
||||
|
||||
|
@ -670,6 +903,8 @@ Common::Error TinselEngine::init() {
|
|||
|
||||
_scheduler = new Scheduler();
|
||||
|
||||
InitSysVars();
|
||||
|
||||
// init memory manager
|
||||
MemoryInit();
|
||||
|
||||
|
@ -684,20 +919,19 @@ Common::Error TinselEngine::init() {
|
|||
RebootCursor();
|
||||
RebootDeadTags();
|
||||
RebootMovers();
|
||||
resetUserEventTime();
|
||||
RebootTimers();
|
||||
RebootScalingReels();
|
||||
|
||||
DelayedScene.scene = HookScene.scene = 0;
|
||||
#endif
|
||||
|
||||
// Load in text strings
|
||||
ChangeLanguage(g_language);
|
||||
|
||||
// Init palette and object managers, scheduler, keyboard and mouse
|
||||
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
|
||||
SetupHandleTable();
|
||||
|
||||
|
@ -707,14 +941,23 @@ Common::Error TinselEngine::init() {
|
|||
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 {
|
||||
char filename[256];
|
||||
snprintf(filename, 256, "%s.%03d", getTargetName().c_str(), saveNum);
|
||||
return filename;
|
||||
}
|
||||
|
||||
#define GAME_FRAME_DELAY (1000 / ONE_SECOND)
|
||||
|
||||
Common::Error TinselEngine::go() {
|
||||
uint32 timerVal = 0;
|
||||
|
||||
|
@ -758,6 +1001,9 @@ Common::Error TinselEngine::go() {
|
|||
// Save/Restore scene file transfers
|
||||
ProcessSRQueue();
|
||||
|
||||
// Handle any playing movie
|
||||
FettleBMV();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (bFast)
|
||||
continue; // run flat-out
|
||||
|
@ -765,6 +1011,11 @@ Common::Error TinselEngine::go() {
|
|||
// Loop processing events while there are any pending
|
||||
while (pollEvent());
|
||||
|
||||
DoCdChange();
|
||||
|
||||
if (MoviePlaying() && NextMovieTime())
|
||||
g_system->delayMillis(MAX<int>(NextMovieTime() - g_system->getMillis() + MovieAudioLag(), 0));
|
||||
else
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
|
@ -776,8 +1027,11 @@ Common::Error TinselEngine::go() {
|
|||
|
||||
|
||||
void TinselEngine::NextGameCycle(void) {
|
||||
//
|
||||
ChangeScene();
|
||||
// Dim Music
|
||||
_pcmMusic->dimIteration();
|
||||
|
||||
// Check for scene change
|
||||
ChangeScene(false);
|
||||
|
||||
// Allow a user event for this schedule
|
||||
ResetEcount();
|
||||
|
@ -785,6 +1039,9 @@ void TinselEngine::NextGameCycle(void) {
|
|||
// schedule process
|
||||
_scheduler->schedule();
|
||||
|
||||
if (MoviePlaying())
|
||||
CopyMovieToScreen();
|
||||
else
|
||||
// redraw background
|
||||
DrawBackgnd();
|
||||
|
||||
|
@ -810,7 +1067,13 @@ bool TinselEngine::pollEvent() {
|
|||
break;
|
||||
|
||||
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;
|
||||
|
||||
case Common::EVENT_KEYDOWN:
|
||||
|
@ -828,7 +1091,6 @@ bool TinselEngine::pollEvent() {
|
|||
/**
|
||||
* Start the processes that continue between scenes.
|
||||
*/
|
||||
|
||||
void TinselEngine::CreateConstProcesses(void) {
|
||||
// Process to run the master script
|
||||
_scheduler->createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0);
|
||||
|
@ -841,7 +1103,6 @@ void TinselEngine::CreateConstProcesses(void) {
|
|||
/**
|
||||
* Restart the game
|
||||
*/
|
||||
|
||||
void TinselEngine::RestartGame(void) {
|
||||
HoldItem(INV_NOICON); // Holding nothing
|
||||
|
||||
|
@ -878,7 +1139,6 @@ void TinselEngine::RestartGame(void) {
|
|||
/**
|
||||
* Init palette and object managers, scheduler, keyboard and mouse.
|
||||
*/
|
||||
|
||||
void TinselEngine::RestartDrivers(void) {
|
||||
// init the palette manager
|
||||
ResetPalAllocator();
|
||||
|
@ -902,13 +1162,12 @@ void TinselEngine::RestartDrivers(void) {
|
|||
}
|
||||
|
||||
// Set midi volume
|
||||
SetMidiVolume(volMidi);
|
||||
SetMidiVolume(volMusic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove keyboard, mouse and joystick drivers.
|
||||
*/
|
||||
|
||||
void TinselEngine::ChopDrivers(void) {
|
||||
// remove sound driver
|
||||
StopMidi();
|
||||
|
@ -923,7 +1182,6 @@ void TinselEngine::ChopDrivers(void) {
|
|||
/**
|
||||
* Process a keyboard event
|
||||
*/
|
||||
|
||||
void TinselEngine::ProcessKeyEvent(const Common::Event &event) {
|
||||
|
||||
// Handle any special keys immediately
|
||||
|
@ -974,4 +1232,48 @@ void TinselEngine::ProcessKeyEvent(const Common::Event &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
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
#include "common/error.h"
|
||||
#include "common/events.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/util.h"
|
||||
|
@ -39,10 +40,12 @@
|
|||
#include "tinsel/debugger.h"
|
||||
#include "tinsel/graphics.h"
|
||||
#include "tinsel/sound.h"
|
||||
#include "tinsel/dw.h"
|
||||
|
||||
namespace Tinsel {
|
||||
|
||||
class MusicPlayer;
|
||||
class MidiMusicPlayer;
|
||||
class PCMMusicPlayer;
|
||||
class Scheduler;
|
||||
class SoundManager;
|
||||
|
||||
|
@ -65,11 +68,34 @@ enum TinselGameFeatures {
|
|||
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 {
|
||||
TINSEL_V0 = 0, // Used in the DW1 demo only
|
||||
TINSEL_V1 = 1
|
||||
TINSEL_V0 = 0,
|
||||
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;
|
||||
|
||||
enum TinselKeyDirection {
|
||||
|
@ -79,6 +105,22 @@ enum TinselKeyDirection {
|
|||
|
||||
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 {
|
||||
int _gameId;
|
||||
Common::KeyState _keyPressed;
|
||||
|
@ -89,11 +131,16 @@ class TinselEngine : public Engine {
|
|||
Console *_console;
|
||||
Scheduler *_scheduler;
|
||||
|
||||
static const char *_sampleIndices[][3];
|
||||
static const char *_sampleFiles[][3];
|
||||
static const char *_textFiles[][3];
|
||||
|
||||
protected:
|
||||
|
||||
// Engine APIs
|
||||
virtual Common::Error init();
|
||||
virtual Common::Error go();
|
||||
virtual void syncSoundSettings();
|
||||
|
||||
public:
|
||||
TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc);
|
||||
|
@ -109,13 +156,18 @@ public:
|
|||
uint16 getVersion() const;
|
||||
Common::Platform getPlatform() const;
|
||||
|
||||
const char *getSampleIndex(LANGUAGE lang);
|
||||
const char *getSampleFile(LANGUAGE lang);
|
||||
const char *getTextFile(LANGUAGE lang);
|
||||
|
||||
MidiDriver *_driver;
|
||||
SoundManager *_sound;
|
||||
MusicPlayer *_music;
|
||||
MidiMusicPlayer *_midiMusic;
|
||||
PCMMusicPlayer *_pcmMusic;
|
||||
|
||||
KEYFPTR _keyHandler;
|
||||
private:
|
||||
//MusicPlayer *_music;
|
||||
//MidiMusicPlayer *_midiMusic;
|
||||
int _musicVolume;
|
||||
|
||||
void NextGameCycle(void);
|
||||
|
@ -134,7 +186,8 @@ public:
|
|||
|
||||
Common::Point getMousePosition() const { return _mousePos; }
|
||||
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;
|
||||
}
|
||||
void divertKeyInput(KEYFPTR fptr) { _keyHandler = fptr; }
|
||||
|
@ -145,6 +198,11 @@ public:
|
|||
// Global reference to the TinselEngine object
|
||||
extern TinselEngine *_vm;
|
||||
|
||||
// Externally available methods
|
||||
void CuttingScene(bool bCutting);
|
||||
void CDChangeForRestore(int cdNumber);
|
||||
void CdHasChanged(void);
|
||||
|
||||
} // End of namespace Tinsel
|
||||
|
||||
#endif /* TINSEL_H */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue