mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-20 16:59:06 +00:00
bd50e9f3d7
svn-id: r10224
895 lines
33 KiB
C++
895 lines
33 KiB
C++
/* Copyright (C) 1994-2003 Revolution Software Ltd
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* $Header$
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
// A more intelligent version of the old ANIMS.C
|
|
// All this stuff by James
|
|
// DON'T TOUCH!
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
|
|
//#include <io.h> // for access()
|
|
#include <stdio.h> // for sprintf
|
|
#include <string.h>
|
|
|
|
#include "stdafx.h"
|
|
#include "common/scummsys.h"
|
|
#include "driver/driver96.h"
|
|
#include "anims.h"
|
|
#include "build_display.h" // for DisplayMsg()
|
|
#include "console.h"
|
|
#include "controls.h" // for 'speechSelected' & 'subtitles'
|
|
#include "debug.h"
|
|
#include "defs.h"
|
|
#include "header.h"
|
|
#include "interpreter.h"
|
|
#include "layers.h" // for 'this_screen' structure - for restoring palette in FN_play_sequence
|
|
#include "maketext.h" // for MakeTextSprite used by FN_play_sequence ultimately
|
|
#include "object.h"
|
|
#include "protocol.h"
|
|
#include "resman.h"
|
|
#include "sword2.h" // for Close_game()
|
|
#include "sync.h"
|
|
#include "sound.h" // for Speech stuff.
|
|
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
uint32 smackerLeadOut=0; // stores resource id of wav to use as lead-out from smacker
|
|
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
// local function prototypes
|
|
|
|
int32 Animate(int32 *params, uint8 reverse_flag);
|
|
int32 Mega_table_animate(int32 *params, uint8 reverse_flag);
|
|
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
int32 FN_anim(int32 *params)
|
|
{
|
|
// params: 0 pointer to object's logic structure
|
|
// 1 pointer to object's graphic structure
|
|
// 2 resource id of animation file
|
|
|
|
return Animate(params,0); // 0 means normal forward anim
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
int32 FN_reverse_anim(int32 *params)
|
|
{
|
|
// params: 0 pointer to object's logic structure
|
|
// 1 pointer to object's graphic structure
|
|
// 2 resource id of animation file
|
|
|
|
return Animate(params,1); // 1 means reverse anim
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
int32 FN_mega_table_anim(int32 *params)
|
|
{
|
|
// params: 0 pointer to object's logic structure
|
|
// 1 pointer to object's graphic structure
|
|
// 2 pointer to object's mega structure
|
|
// 3 pointer to animation table
|
|
|
|
return Mega_table_animate(params,0); // 0 means normal forward anim
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
int32 FN_reverse_mega_table_anim(int32 *params)
|
|
{
|
|
// params: 0 pointer to object's logic structure
|
|
// 1 pointer to object's graphic structure
|
|
// 2 pointer to object's mega structure
|
|
// 3 pointer to animation table
|
|
|
|
return Mega_table_animate(params,1); // 1 means reverse anim
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
int32 Animate(int32 *params, uint8 reverse_flag)
|
|
{
|
|
// params: 0 pointer to object's logic structure
|
|
// 1 pointer to object's graphic structure
|
|
// 2 resource id of animation file
|
|
|
|
Object_logic *ob_logic;
|
|
Object_graphic *ob_graphic;
|
|
uint8 *anim_file;
|
|
_animHeader *anim_head;
|
|
int32 res = params[2];
|
|
|
|
#ifdef _SWORD2_DEBUG
|
|
_standardHeader *head; // for animation testing & checking for correct file type
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// read the main parameters
|
|
|
|
ob_logic = (Object_logic *) params[0]; // param 0 is pointer to normal structure
|
|
ob_graphic = (Object_graphic *) params[1]; // param 1 is pointer to graphic structure
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// if this is the start of the anim, set up the first frame
|
|
|
|
if (ob_logic->looping==0)
|
|
{
|
|
//-----------------------------------------------------------
|
|
#ifdef _SWORD2_DEBUG
|
|
// For testing all anims! (James18apr97)
|
|
// A script loop can send every resource number to the anim function
|
|
// & it will only run the valid ones
|
|
// See 'testing_routines' object in George's Player Character section of linc
|
|
if (SYSTEM_TESTING_ANIMS)
|
|
{
|
|
if (res_man.Res_check_valid(res)) // if the resource number is within range & it's not a null resource
|
|
{
|
|
head = (_standardHeader*) res_man.Res_open(res); // open the resource
|
|
res_man.Res_close(res); // can close immediately - we've got a pointer to the header
|
|
|
|
if (head->fileType!=ANIMATION_FILE) // if it's not an animation file
|
|
{
|
|
FN_no_sprite(params+1); // switch off the sprite
|
|
return(IR_STOP); // don't animate - just continue script next cycle
|
|
}
|
|
}
|
|
else
|
|
{ // not a valid resource number
|
|
FN_no_sprite(params+1); // switch off the sprite
|
|
return(IR_STOP); // don't animate - just continue script next cycle
|
|
}
|
|
|
|
FN_sort_sprite(params+1); // switch on the sprite
|
|
}
|
|
#endif
|
|
//-----------------------------------------------------------
|
|
|
|
//---------------------
|
|
#ifdef _SWORD2_DEBUG
|
|
// check that we haven't been passed a zero resource number
|
|
if (res==0)
|
|
Con_fatal_error("Animate: %s (id %d) passed zero anim resource (%s line %u)", FetchObjectName(ID), ID, __FILE__, __LINE__);
|
|
#endif
|
|
//---------------------
|
|
|
|
anim_file = res_man.Res_open(res); // open anim file
|
|
|
|
//---------------------
|
|
#ifdef _SWORD2_DEBUG
|
|
// check this this resource is actually an animation file!
|
|
head = (_standardHeader*) anim_file;
|
|
if (head->fileType!=ANIMATION_FILE) // if it's not an animation file
|
|
Con_fatal_error("Animate: %s (%d) is not an anim! (%s line %u)", FetchObjectName(res), res, __FILE__, __LINE__);
|
|
#endif
|
|
//---------------------
|
|
|
|
anim_head = FetchAnimHeader( anim_file ); // point to anim header
|
|
|
|
//---------------------
|
|
/*
|
|
#ifdef _SWORD2_DEBUG
|
|
// check there's at least one frame
|
|
if (anim_head->noAnimFrames==0)
|
|
Con_fatal_error("Animate: %s (%d) has zero frame count! (%s line %u)", FetchObjectName(res), res, __FILE__, __LINE__);
|
|
#endif
|
|
*/
|
|
//---------------------
|
|
|
|
ob_logic->looping = 1; // now running an anim, looping back to this 'FN' call again
|
|
ob_graphic->anim_resource = res; // param 2 is id of animation resource
|
|
|
|
if (reverse_flag) // if a reverse anim
|
|
ob_graphic->anim_pc = anim_head->noAnimFrames-1; // start on last frame
|
|
else // forward anim
|
|
ob_graphic->anim_pc = 0; // start on first frame
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// otherwise, if we've received a sync, return to script immediately
|
|
|
|
else if (Get_sync()) // returns sync value if one has been sent to current 'id', otherwise 0
|
|
{
|
|
// Zdebug("**sync stopped %d**", ID);
|
|
ob_logic->looping = 0; // if sync received, anim finishes right now (remaining on last frame)
|
|
return(IR_CONT); // quit anim but continue script
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// otherwise (not first frame & not received a sync), set up the next frame of the anim
|
|
else
|
|
{
|
|
anim_file = res_man.Res_open(ob_graphic->anim_resource); // open anim file
|
|
anim_head = FetchAnimHeader( anim_file ); // point to anim header
|
|
|
|
if (reverse_flag) // if a reverse anim
|
|
ob_graphic->anim_pc--; // decrement the anim frame number
|
|
else // normal forward anim
|
|
ob_graphic->anim_pc++; // increment the anim frame number
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// check for end of anim
|
|
|
|
if (reverse_flag) // if a reverse anim
|
|
{
|
|
if (ob_graphic->anim_pc == 0) // reached the first frame of the anim
|
|
ob_logic->looping = 0; // anim finishes on this frame
|
|
}
|
|
else // normal forward anim
|
|
{
|
|
if (ob_graphic->anim_pc == (int32)(anim_head->noAnimFrames-1)) // reached the last frame of the anim
|
|
ob_logic->looping = 0; // anim finishes on this frame
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// close the anim file
|
|
|
|
res_man.Res_close(ob_graphic->anim_resource); // close anim file
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// check if we want the script to loop back & call this function again
|
|
|
|
if (ob_logic->looping)
|
|
return(IR_REPEAT); // drop out of script, but call this function again next cycle
|
|
else
|
|
return(IR_STOP); // drop out of script
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
int32 Mega_table_animate(int32 *params, uint8 reverse_flag)
|
|
{
|
|
// params: 0 pointer to object's logic structure
|
|
// 1 pointer to object's graphic structure
|
|
// 2 pointer to object's mega structure
|
|
// 3 pointer to animation table
|
|
|
|
Object_logic *ob_logic;
|
|
Object_mega *ob_mega;
|
|
uint32 *anim_table;
|
|
int32 pars[5];
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// if this is the start of the anim, read the anim table to get the appropriate anim resource
|
|
|
|
ob_logic = (Object_logic *) params[0]; // param 0 is pointer to logic structure
|
|
|
|
if (ob_logic->looping==0)
|
|
{
|
|
ob_mega = (Object_mega *) params[2]; // param 2 is pointer to mega structure
|
|
|
|
anim_table = (uint32*)params[3];
|
|
pars[2] = anim_table[ob_mega->current_dir]; // appropriate anim resource is in 'table[direction]'
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// set up the rest of the parameters for FN_anim()
|
|
|
|
pars[0] = params[0];
|
|
pars[1] = params[1];
|
|
// pars[2] only needed setting at the start of the anim
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
|
|
return Animate(pars, reverse_flag); // call Animate() with these params
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
int32 FN_set_frame(int32 *params)
|
|
{
|
|
// params: 0 pointer to object's graphic structure
|
|
// 1 resource id of animation file
|
|
// 2 frame flag (0=first 1=last)
|
|
|
|
Object_graphic *ob_graphic;
|
|
uint8 *anim_file;
|
|
_animHeader *anim_head;
|
|
int32 res = params[1];
|
|
|
|
#ifdef _SWORD2_DEBUG
|
|
_standardHeader *head; // for checking for correct file type
|
|
#endif
|
|
|
|
//---------------------
|
|
#ifdef _SWORD2_DEBUG
|
|
// check that we haven't been passed a zero resource number
|
|
if (res==0)
|
|
Con_fatal_error("FN_set_frame: %s (id %d) passed zero anim resource (%s line %u)", FetchObjectName(ID), ID, __FILE__, __LINE__);
|
|
#endif
|
|
//---------------------
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// open the resource (& check it's valid)
|
|
|
|
anim_file = res_man.Res_open(res); // open anim file
|
|
|
|
//---------------------
|
|
#ifdef _SWORD2_DEBUG
|
|
// check this this resource is actually an animation file!
|
|
head = (_standardHeader*) anim_file;
|
|
if (head->fileType!=ANIMATION_FILE) // if it's not an animation file
|
|
Con_fatal_error("FN_set_frame: %s (%d) is not an anim! (%s line %u)", FetchObjectName(res), res, __FILE__, __LINE__);
|
|
#endif
|
|
//---------------------
|
|
|
|
anim_head = FetchAnimHeader( anim_file ); // set up pointer to the animation header
|
|
|
|
//---------------------
|
|
/*
|
|
#ifdef _SWORD2_DEBUG
|
|
// check there's at least one frame
|
|
if (anim_head->noAnimFrames==0)
|
|
Con_fatal_error("FN_set_frame: %s (%d) has zero frame count! (%s line %u)", FetchObjectName(res), res, __FILE__, __LINE__);
|
|
#endif
|
|
*/
|
|
//---------------------
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// set up anim resource in graphic object
|
|
|
|
ob_graphic = (Object_graphic *) params[0]; // param 0 is pointer to the object's graphic structure
|
|
|
|
ob_graphic->anim_resource = res; // param 2 is id of animation resource
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
if (params[2]) // frame flag is non-zero
|
|
ob_graphic->anim_pc = anim_head->noAnimFrames-1; // last frame
|
|
else // frame flag is 0
|
|
ob_graphic->anim_pc = 0; // first frame
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// close the anim file
|
|
|
|
res_man.Res_close(ob_graphic->anim_resource); // close anim file
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
|
|
return(IR_CONT); // drop out of script
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_no_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0xffff0000; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= NO_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_back_par0_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0xffff0000; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= BGP0_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_back_par1_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0xffff0000; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= BGP1_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_back_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0xffff0000; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= BACK_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_sort_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0xffff0000; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= SORT_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_fore_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0xffff0000; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= FORE_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_fore_par0_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0xffff0000; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= FGP0_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_fore_par1_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0xffff0000; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= FGP1_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_shaded_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0x0000ffff; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= SHADED_SPRITE;
|
|
|
|
// note that drivers may still shade mega frames automatically, even when not sent 'RDSPR_SHADOW'
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_unshaded_sprite(int32 *params)
|
|
{
|
|
// params 0 pointer to object's graphic structure
|
|
|
|
Object_graphic *ob_graphic = (Object_graphic *) params[0];
|
|
|
|
ob_graphic->type &= 0x0000ffff; // remove previous status (but don't affect the shading upper-word)
|
|
ob_graphic->type |= UNSHADED_SPRITE;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// Notes on PlaySmacker()
|
|
|
|
// 1st param is filename of sequence file
|
|
// 2nd param is a pointer to a null-terminated array of pointers to _movieTextObject structures
|
|
|
|
|
|
//int32 PlaySmacker(char *filename, _movieTextObject *textObjects[]);
|
|
|
|
// typedef struct
|
|
// {
|
|
// uint16 startFrame;
|
|
// uint16 endFrame;
|
|
// _spriteInfo *textSprite;
|
|
// _wavHeader *speech;
|
|
// } _movieTextObject;
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// FOR TEXT LINES IN SEQUENCE PLAYER (James22may97)
|
|
|
|
#define MAX_SEQUENCE_TEXT_LINES 15
|
|
|
|
typedef struct
|
|
{
|
|
uint32 textNumber;
|
|
uint16 startFrame;
|
|
uint16 endFrame;
|
|
mem *text_mem;
|
|
mem *speech_mem;
|
|
} _sequenceTextInfo;
|
|
|
|
static _sequenceTextInfo sequence_text_list[MAX_SEQUENCE_TEXT_LINES];
|
|
uint32 sequenceTextLines=0; // keeps count of number of text lines to disaply during the sequence
|
|
|
|
//-------------------------------------------------------------------------------------------------------------
|
|
|
|
int32 FN_add_sequence_text(int32 *params) // (James22may97)
|
|
{
|
|
// params 0 text number
|
|
// 1 frame number to start the text displaying
|
|
// 2 frame number to stop the text dispalying
|
|
|
|
#ifdef _SWORD2_DEBUG
|
|
if (sequenceTextLines == MAX_SEQUENCE_TEXT_LINES)
|
|
Con_fatal_error("FN_add_sequence_text ran out of lines (%s line %u)",__FILE__,__LINE__);
|
|
#endif
|
|
|
|
sequence_text_list[sequenceTextLines].textNumber = params[0];
|
|
sequence_text_list[sequenceTextLines].startFrame = params[1];
|
|
sequence_text_list[sequenceTextLines].endFrame = (uint16) params[2];
|
|
sequenceTextLines++;
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
// speech sample code added by James on 16july97
|
|
void CreateSequenceSpeech(_movieTextObject *sequenceText[]) // (James23may97)
|
|
{
|
|
uint32 line;
|
|
_frameHeader *frame;
|
|
uint32 local_text;
|
|
uint32 text_res;
|
|
uint8 *text;
|
|
int16 wavId; // ie. offical text number (actor text number)
|
|
uint8 speechRunning;
|
|
char speechFile[256];
|
|
int32 wavSize;
|
|
|
|
|
|
for (line=0; line < sequenceTextLines; line++) // for each sequence text line that's been logged
|
|
{
|
|
sequenceText[line] = new _movieTextObject; // allocate this structure
|
|
|
|
sequenceText[line]->startFrame = sequence_text_list[line].startFrame;
|
|
sequenceText[line]->endFrame = sequence_text_list[line].endFrame;
|
|
|
|
//-----------------------------------------------------------
|
|
// pull out the text line to get the official text number (for wav id)
|
|
|
|
text_res = sequence_text_list[line].textNumber/SIZE;
|
|
local_text = sequence_text_list[line].textNumber&0xffff;
|
|
|
|
text = FetchTextLine( res_man.Res_open(text_res), local_text ); // open text resource & get the line
|
|
wavId = (int32)READ_LE_UINT16(text);
|
|
|
|
res_man.Res_close(text_res); // now ok to close the text file
|
|
|
|
//--------------------------------------
|
|
// Write to walkthrough file (zebug0.txt)
|
|
#ifdef _SWORD2_DEBUG
|
|
Zdebug(0,"(%d) SEQUENCE TEXT: %s", *(uint16*)text, text+2); // 1st word of text line is the official line number
|
|
#endif
|
|
//--------------------------------------
|
|
// is it to be speech or subtitles or both?
|
|
|
|
speechRunning=0; // assume not running until know otherwise
|
|
sequence_text_list[line].speech_mem = NULL;
|
|
sequenceText[line]->speech = NULL;
|
|
|
|
if (speechSelected) // speech is selected, so try that first
|
|
{
|
|
//------------------------------
|
|
// set up path to speech cluster
|
|
// first checking if we have speech1.clu or speech2.clu in current directory (for translators to test)
|
|
|
|
File fp;
|
|
|
|
sprintf(speechFile, "speech%d.clu", res_man.WhichCd());
|
|
if (fp.open(speechFile, g_sword2->getGameDataPath()))
|
|
fp.close();
|
|
else
|
|
strcpy(speechFile, "speech.clu");
|
|
|
|
wavSize = g_sword2->_sound->GetCompSpeechSize(speechFile, wavId); // returns size of decompressed wav, or 0 if wav not found
|
|
if (wavSize) // if we've got the wav
|
|
{
|
|
// allocate memory for speech buffer
|
|
sequence_text_list[line].speech_mem = Twalloc( wavSize, MEM_locked, UID_temp ); // last param is an optional id for type of mem block
|
|
|
|
if (sequence_text_list[line].speech_mem) // if mem allocated ok (should be fine, but worth checking)
|
|
{
|
|
if (g_sword2->_sound->PreFetchCompSpeech(speechFile, wavId, sequence_text_list[line].speech_mem->ad) == RD_OK) // Load speech & decompress to our buffer
|
|
{
|
|
Float_mem (sequence_text_list[line].speech_mem); // now float this buffer so we can make space for the next text sprites and/or speech samples
|
|
speechRunning=1; // ok, we've got speech!
|
|
}
|
|
else // whoops, sample didn't load & decompress for some reason...
|
|
{
|
|
Free_mem (sequence_text_list[line].speech_mem); // may as well free up this speech buffer now, rather than in ClearSequenceSpeech();
|
|
sequence_text_list[line].speech_mem = NULL; // so we know that it's free'd
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (subtitles || (speechRunning==0)) // if we want subtitles, or speech failed to load
|
|
{
|
|
text = FetchTextLine( res_man.Res_open(text_res), local_text ); // open text resource & get the line
|
|
// mem* MakeTextSprite( uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes );
|
|
sequence_text_list[line].text_mem = MakeTextSprite( text+2, 600, 255, speech_font_id ); // make the sprite
|
|
// 'text+2' to skip the first 2 bytes which form the line reference number
|
|
// NB. The mem block containing the text sprite is currently FLOATING!
|
|
|
|
res_man.Res_close(text_res); // ok to close the text resource now
|
|
}
|
|
else
|
|
{
|
|
sequence_text_list[line].text_mem = NULL;
|
|
sequenceText[line]->textSprite = NULL;
|
|
}
|
|
//--------------------------------------
|
|
}
|
|
|
|
sequenceText[sequenceTextLines] = NULL; // for drivers: NULL-terminate the array of pointers to _movieTextObject's
|
|
|
|
//---------------------------------------
|
|
// now lock all the memory blocks containing text sprites & speech samples
|
|
// and set up the pointers to them, etc, for the drivers
|
|
|
|
for (line=0; line < sequenceTextLines; line++)
|
|
{
|
|
// text sprites:
|
|
if (sequence_text_list[line].text_mem) // if we've made a text sprite for this line...
|
|
{
|
|
Lock_mem (sequence_text_list[line].text_mem);
|
|
// now fill out the _spriteInfo structure in the _movieTextObjectStructure
|
|
|
|
frame = (_frameHeader*) sequence_text_list[line].text_mem->ad;
|
|
|
|
sequenceText[line]->textSprite = new _spriteInfo;
|
|
|
|
sequenceText[line]->textSprite->x = 320 - frame->width/2; // centred
|
|
sequenceText[line]->textSprite->y = 440 - frame->height; // at bottom of screen
|
|
sequenceText[line]->textSprite->w = frame->width;
|
|
sequenceText[line]->textSprite->h = frame->height;
|
|
sequenceText[line]->textSprite->scale = 0;
|
|
sequenceText[line]->textSprite->scaledWidth = 0;
|
|
sequenceText[line]->textSprite->scaledHeight= 0;
|
|
sequenceText[line]->textSprite->type = RDSPR_DISPLAYALIGN+RDSPR_TRANS+RDSPR_NOCOMPRESSION;
|
|
sequenceText[line]->textSprite->blend = 0;
|
|
sequenceText[line]->textSprite->data = sequence_text_list[line].text_mem->ad+sizeof(_frameHeader);
|
|
sequenceText[line]->textSprite->colourTable = 0;
|
|
}
|
|
|
|
// speech samples:
|
|
if (sequence_text_list[line].speech_mem) // if we've loaded a speech sample for this line...
|
|
{
|
|
Lock_mem (sequence_text_list[line].speech_mem);
|
|
sequenceText[line]->speech = (_wavHeader *)sequence_text_list[line].speech_mem->ad; // for drivers: set up pointer to decompressed wav in memory
|
|
}
|
|
}
|
|
//---------------------------------------
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
// speech sample code added by James on 16july97
|
|
void ClearSequenceSpeech(_movieTextObject *textSprites[]) // (James27may97)
|
|
{
|
|
uint32 line;
|
|
|
|
for (line=0; line < sequenceTextLines; line++)
|
|
{
|
|
delete (textSprites[line]); // free up the memory used by this _movieTextObject
|
|
|
|
if (sequence_text_list[line].text_mem)
|
|
Free_mem (sequence_text_list[line].text_mem); // free up the mem block containing this text sprite
|
|
|
|
if (sequence_text_list[line].speech_mem)
|
|
Free_mem (sequence_text_list[line].speech_mem); // free up the mem block containing this speech sample
|
|
}
|
|
|
|
sequenceTextLines=0; // IMPORTANT! Reset the line count ready for the next sequence!
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_smacker_lead_in(int32 *params) // James(21july97)
|
|
{
|
|
uint8 *leadIn;
|
|
uint32 rv;
|
|
#ifdef _SWORD2_DEBUG
|
|
_standardHeader *header;
|
|
#endif
|
|
|
|
|
|
leadIn = res_man.Res_open(params[0]);
|
|
|
|
//-----------------------------------------
|
|
#ifdef _SWORD2_DEBUG
|
|
header = (_standardHeader*)leadIn;
|
|
if (header->fileType != WAV_FILE)
|
|
Con_fatal_error("FN_smacker_lead_in() given invalid resource (%s line %u)",__FILE__,__LINE__);
|
|
#endif
|
|
//-----------------------------------------
|
|
|
|
leadIn += sizeof(_standardHeader);
|
|
rv = g_sword2->_sound->PlayFx( 0, leadIn, 0, 0, RDSE_FXLEADIN ); // wav data gets copied to sound memory
|
|
|
|
//-----------------------------------------
|
|
#ifdef _SWORD2_DEBUG
|
|
if (rv)
|
|
Zdebug("SFX ERROR: PlayFx() returned %.8x (%s line %u)", rv, __FILE__, __LINE__);
|
|
#endif
|
|
//-----------------------------------------
|
|
|
|
res_man.Res_close(params[0]);
|
|
|
|
FN_stop_music(NULL); // fade out any music that is currently playing (James22july97)
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
int32 FN_smacker_lead_out(int32 *params) // James(21july97)
|
|
{
|
|
smackerLeadOut = params[0]; // ready for use in FN_play_sequence
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
int32 FN_play_sequence(int32 *params) // James(09apr97)
|
|
{
|
|
// params 0 pointer to null-terminated ascii filename
|
|
// params 1 number of frames in the sequence, used for PSX.
|
|
|
|
char filename[30];
|
|
uint32 rv; // drivers return value
|
|
_movieTextObject *sequenceSpeechArray[MAX_SEQUENCE_TEXT_LINES+1];
|
|
uint8 *leadOut = NULL;
|
|
#ifdef _SWORD2_DEBUG
|
|
_standardHeader *header;
|
|
#endif
|
|
|
|
#ifdef _MUTE_SMACKERS
|
|
uint32 musicMuteStatus;
|
|
#endif
|
|
|
|
//----------------------------------
|
|
// In the case where smackers are crashing but the rest of the game is fine,
|
|
// the "Skip Smackers" executable will display a message giving the smacker
|
|
// file name rather than actually playing it.
|
|
// Then the user can switch tasks & view the smacker using the stand-alone player!
|
|
// This has got to be the biggest fudge in the history of computer games.
|
|
|
|
#ifdef _SKIP_SMACKERS
|
|
uint8 message[30];
|
|
|
|
sprintf((char*)message,"SKIPPING SMACKER: \"%s.smk\"", (char *)params[0]);
|
|
DisplayMsg(message, 3); // 3 is duration in seconds
|
|
RemoveMsg();
|
|
sequenceTextLines=0; // IMPORTANT - clear this so it doesn't overflow!
|
|
return(IR_CONT); // continue script now; don't play smacker!
|
|
#endif
|
|
//----------------------------------
|
|
// Another attempt to prevent the smacker crash
|
|
// This time muting the music during the smacker
|
|
// - in case that's what's causing the crash
|
|
|
|
#ifdef _MUTE_SMACKERS
|
|
musicMuteStatus = IsMusicMute(); // keep note of what mute status was to start with
|
|
MuteMusic(1); // mute the music - we'll set it back to 'musicMuteStatus' later
|
|
#endif
|
|
//----------------------------------
|
|
|
|
Zdebug("FN_play_sequence(\"%s\");", params[0]);
|
|
|
|
//--------------------------------------------------
|
|
// check that the name paseed from script is 8 chars or less
|
|
#ifdef _SWORD2_DEBUG
|
|
if (strlen((char *)params[0]) > 8)
|
|
Con_fatal_error("Sequence filename too long (%s line %u)",__FILE__,__LINE__);
|
|
#endif
|
|
//--------------------------------------------------
|
|
// add the appropriate file extension & play it
|
|
|
|
if (g_sword2->_gameId == GID_SWORD2_DEMO)
|
|
sprintf(filename,"%s.smk", (char *)params[0]);
|
|
else
|
|
sprintf(filename,"%sSMACKS\\%s.smk", res_man.GetCdPath(), (char *)params[0]);
|
|
|
|
//--------------------------------------
|
|
// Write to walkthrough file (zebug0.txt)
|
|
|
|
#ifdef _SWORD2_DEBUG
|
|
Zdebug(0,"PLAYING SEQUENCE \"%s\"", filename);
|
|
#endif
|
|
//--------------------------------------
|
|
// now create the text sprites, if any (James27may97)
|
|
|
|
if (sequenceTextLines) // if we have some text to accompany this sequence
|
|
CreateSequenceSpeech(sequenceSpeechArray);
|
|
|
|
//--------------------------------------
|
|
// open the lead-out music resource, if there is one
|
|
|
|
if (smackerLeadOut)
|
|
{
|
|
leadOut = res_man.Res_open(smackerLeadOut);
|
|
|
|
//---------------------------
|
|
#ifdef _SWORD2_DEBUG
|
|
header = (_standardHeader*)leadOut;
|
|
if (header->fileType != WAV_FILE)
|
|
Con_fatal_error("FN_smacker_lead_out() given invalid resource (%s line %u)",__FILE__,__LINE__);
|
|
#endif
|
|
//---------------------------
|
|
|
|
leadOut += sizeof(_standardHeader);
|
|
}
|
|
|
|
//--------------------------------------
|
|
// play the smacker
|
|
|
|
FN_stop_music(NULL); // don't want to carry on streaming game music when smacker starts!
|
|
g_sword2->_sound->PauseFxForSequence(); // pause sfx during sequence, except the one used for lead-in music
|
|
|
|
if (sequenceTextLines && g_sword2->_gameId == GID_SWORD2) // if we have some text to accompany this sequence
|
|
rv = PlaySmacker(filename, sequenceSpeechArray, leadOut);
|
|
else
|
|
rv = PlaySmacker(filename, NULL, leadOut);
|
|
|
|
/* we don't have this call - khalek
|
|
if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q during the smacker
|
|
{
|
|
Close_game(); //close engine systems down
|
|
CloseAppWindow();
|
|
exit(0); //quit the game
|
|
}
|
|
*/
|
|
|
|
g_sword2->_sound->UnpauseFx(); // unpause sound fx again, in case we're staying in same location
|
|
|
|
//--------------------------------------
|
|
// close the lead-out music resource
|
|
|
|
if (smackerLeadOut)
|
|
{
|
|
res_man.Res_close(smackerLeadOut);
|
|
smackerLeadOut=0;
|
|
}
|
|
//--------------------------
|
|
// check the error return-value
|
|
#ifdef _SWORD2_DEBUG
|
|
if (rv)
|
|
Zdebug("PlaySmacker(\"%s\") returned 0x%.8x", filename, rv);
|
|
#endif
|
|
//--------------------------
|
|
// now clear the text sprites, if any (James27may97)
|
|
|
|
if (sequenceTextLines) // if we have some text/speech to accompany this sequence
|
|
ClearSequenceSpeech(sequenceSpeechArray);
|
|
|
|
//--------------------------
|
|
// now clear the screen in case the Sequence was quitted (using ESC) rather than fading down to black
|
|
|
|
EraseBackBuffer(); // for hardware rendering
|
|
EraseSoftwareScreenBuffer(); // for software rendering
|
|
|
|
//--------------------------------------------------
|
|
// zero the entire palette in case we're about to fade up!
|
|
|
|
_palEntry pal[256];
|
|
|
|
memset(pal, 0, 256*sizeof(_palEntry));
|
|
BS2_SetPalette(0, 256, (uint8 *) pal, RDPAL_INSTANT);
|
|
//--------------------------------------------------
|
|
|
|
Zdebug("FN_play_sequence FINISHED");
|
|
|
|
//--------------------------------------------------
|
|
#ifdef _MUTE_SMACKERS
|
|
MuteMusic(musicMuteStatus); // set mute status back to what it was before the sequence
|
|
#endif
|
|
//----------------------------------
|
|
|
|
|
|
return(IR_CONT); // continue script
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------------------------------------------------
|