svn-id: r9211
This commit is contained in:
Jonathan Gray 2003-07-28 01:44:38 +00:00
parent d592095fb9
commit f020d28b5e
60 changed files with 25143 additions and 0 deletions

1
sword2/.cvsignore Normal file
View file

@ -0,0 +1 @@
.deps

911
sword2/anims.cpp Normal file
View file

@ -0,0 +1,911 @@
/* 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 "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 _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 _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 _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 _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 _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 _DEBUG
_standardHeader *head; // for checking for correct file type
#endif
//---------------------
#ifdef _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 _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 _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 _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 = 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
memcpy(&wavId, text, 2); // this works on PSX & PC
res_man.Res_close(text_res); // now ok to close the text file
//--------------------------------------
// Write to walkthrough file (zebug0.txt)
#ifdef _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)
#ifdef _WEBDEMO // (James 03oct97)
strcpy(speechFile,"SPEECH.CLU");
#else
#ifdef _DEBUG
if ((res_man.WhichCd()==1) && (!access("speech1.clu",0))) // if 0 ie. if it's there
{
strcpy(speechFile,"speech1.clu");
}
else if ((res_man.WhichCd()==2) && (!access("speech2.clu",0))) // if 0 ie. if it's there
{
strcpy(speechFile,"speech2.clu");
}
else
#endif // _DEBUG
{
strcpy(speechFile,res_man.GetCdPath());
strcat(speechFile,"CLUSTERS\\SPEECH.CLU");
}
#endif // _WEBDEMO
//------------------------------
wavSize = 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 (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 _DEBUG
_standardHeader *header;
#endif
leadIn = res_man.Res_open(params[0]);
//-----------------------------------------
#ifdef _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 = PlayFx( 0, leadIn, 0, 0, RDSE_FXLEADIN ); // wav data gets copied to sound memory
//-----------------------------------------
#ifdef _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 _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 _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
#ifdef _WEBDEMO // (James 01oct97)
sprintf(filename,"%s.smk", (char *)params[0]);
#else
sprintf(filename,"%sSMACKS\\%s.smk", res_man.GetCdPath(), (char *)params[0]);
#endif // _WEBDEMO
//--------------------------------------
// Write to walkthrough file (zebug0.txt)
#ifdef _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 _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!
PauseFxForSequence(); // pause sfx during sequence, except the one used for lead-in music
if (sequenceTextLines) // 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
RestoreDisplay();
CloseAppWindow();
exit(0); //quit the game
}
*/
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 _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
FlipScreens(); // to get the new blank screen visible
//--------------------------------------------------
// zero the entire palette in case we're about to fade up!
_palEntry pal[256];
memset(pal, 0, 256*sizeof(_palEntry));
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
}
//---------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------

36
sword2/anims.h Normal file
View file

@ -0,0 +1,36 @@
/* 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$
*/
#ifndef _ANIM_S
#define _ANIM_S
#include "driver/driver96.h"
int32 FN_anim(int32 *params);
int32 FN_reverse_anim(int32 *params);
int32 FN_mega_table_anim(int32 *params);
int32 FN_reverse_mega_table_anim(int32 *params);
int32 FN_set_frame(int32 *params);
int32 FN_no_sprite(int32 *params);
int32 FN_back_sprite(int32 *params);
int32 FN_sort_sprite(int32 *params);
int32 FN_fore_sprite(int32 *params);
#endif

1255
sword2/build_display.cpp Normal file

File diff suppressed because it is too large Load diff

81
sword2/build_display.h Normal file
View file

@ -0,0 +1,81 @@
/* 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$
*/
#ifndef _BUILD_DISPLAY
#define _BUILD_DISPLAY
#include "driver/driver96.h"
typedef struct //structure filled out by each object to register its graphic printing requrements
{
int16 x;
int16 y;
uint16 scaled_width;
uint16 scaled_height;
int16 sort_y;
uint32 anim_resource;
uint16 anim_pc;
uint16 scale; //denotes a scaling sprite at print time - and holds the scaling value for the shrink routine
uint16 layer_number; //non zero means this item is a layer - retrieve from background layer and send to special renderer
uint8 shadingFlag; // non zero means we want this frame to be affected by the shading mask
// uint32 write_mouse_list; //if none zero the shrinker should write coordinates to this mouse_list number
} buildit;
// declared externally so that debug.cpp can display these in the info
#define MAX_bgp0_sprites 6
#define MAX_bgp1_sprites 6
#define MAX_back_sprites 30
#define MAX_sort_sprites 30
#define MAX_fore_sprites 30
#define MAX_fgp0_sprites 6
#define MAX_fgp1_sprites 6
// declared externally so that debug.cpp can display these in the info
extern uint32 cur_bgp0;
extern uint32 cur_bgp1;
extern uint32 cur_back;
extern uint32 cur_sort;
extern uint32 cur_fore;
extern uint32 cur_fgp0;
extern uint32 cur_fgp1;
#ifdef _DEBUG
extern char largest_layer_info[128];
extern char largest_sprite_info[128];
#endif
// the only build list needed externally - by layers.cpp - for adding layers to sort list
extern buildit sort_list[];
// function prototypes needed externally
void Reset_render_lists(void);
void Build_display(void); //Tony21Sept96
int32 FN_fade_down(int32 *params); //Tony5Dec96
int32 FN_fade_up(int32 *params); // Chris 15May97
void Process_image(buildit *build_unit); // (5nov96 JEL)
void DisplayMsg( uint8 *text, int time ); // (Chris 15May97)
void RemoveMsg(void);
void SetFullPalette(int32 palRes); // James17jun97
extern uint32 fps; // needed by debug.cpp for displaying as part of top-screen info
#endif

1341
sword2/console.cpp Normal file

File diff suppressed because it is too large Load diff

81
sword2/console.h Normal file
View file

@ -0,0 +1,81 @@
/* 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$
*/
#ifndef C_ONSOLE_H
#define C_ONSOLE_H
#include "driver/driver96.h"
#include "memory.h"
#ifdef _DEBUG
void Init_console(void); //Tony9Sept96
uint32 One_console(void); //Tony12Aug96
void StartConsole(void); //Tony12Aug96
void EndConsole(void); //Tony9Oct96
void Con_fatal_error(char *format,...);
void Print_to_console(char *format,...); //Tony13Aug96
void Temp_print_to_console(char *format,...); //Tony13Aug96
void Scroll_console(void); //Tony13Aug96
void Clear_console_line(void); //Tony13Aug96
extern mem *console_sprite;
extern uint32 con_y;
extern uint32 con_depth;
extern uint32 con_width;
extern uint8 grabbingSequences;
extern uint8 wantSfxDebug; // sfx debug file enabled/disabled from console
#else // _DEBUG
/*
#define Init_console NULL
#define One_console NULL
#define StartConsole NULL
#define EndConsole NULL
*/
void Init_console(void);
uint32 One_console(void);
void StartConsole(void);
void EndConsole(void);
// 'Con_fatal_error' commands map to ExitWithReport
// so we show errors in a window rather than our development game console
#define Con_fatal_error ExitWithReport
//#define Print_to_console NULL
//#define Temp_print_to_console NULL
//#define Clear_console_line NULL
//#define Scroll_console NULL
void Print_to_console(char *format,...);
void Temp_print_to_console(char *format,...);
void Clear_console_line(void);
void Scroll_console(void);
//#define Var_check NULL
//#define Var_set NULL
#endif // _DEBUG
extern uint32 console_status;
#endif

2917
sword2/controls.cpp Normal file

File diff suppressed because it is too large Load diff

38
sword2/controls.h Normal file
View file

@ -0,0 +1,38 @@
/* 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$
*/
#ifndef _CONTROL_S
#define _CONTROL_S
#include "common/scummsys.h"
//#include "src\driver96.h"
uint32 Restore_control(void); //Tony20Mar97
void Save_control(void); //Tony1Apr97
void Quit_control(void); //Tony2Apr97
void Restart_control(void); //Tony4Apr97
void Option_control(void); //Pete5Jun97
int32 ReadOptionSettings(void); //Pete10Jun97
void UpdateGraphicsLevel(uint8 oldLevel, uint8 newLevel); // (James13jun97)
extern uint8 subtitles; // text selected
extern uint8 speechSelected;
extern uint8 current_graphics_level;
#endif

28
sword2/credits.h Normal file
View file

@ -0,0 +1,28 @@
/* 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$
*/
#ifndef _Credits_h_
#define _Credits_h_
#include "driver/driver96.h"
// int32 __declspec( dllexport ) Credits(_drvDrawStatus *pDrawStatus, _drvSoundStatus *pSoundStatus, const char *cdPath, BOOL smoke, BOOL *pAppFocus, _drvKeyStatus *pKeyStatus);
int32 Credits(_drvDrawStatus *pDrawStatus, _drvSoundStatus *pSoundStatus, const char *cdPath, BOOL smoke, BOOL *pAppFocus, _drvKeyStatus *pKeyStatus);
#endif

553
sword2/debug.cpp Normal file
View file

@ -0,0 +1,553 @@
/* 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$
*/
//--------------------------------------------------------------------------------------
#include <stdarg.h> // for ExitWithReport, which stays in RELEASE version
#include <stdio.h>
#include "driver/driver96.h"
#include "debug.h"
//--------------------------------------------------------------------------------------
#if _DEBUG // this whole file (except ExitWithReport) only included on debug versions
#include <stdlib.h>
#include "build_display.h" // for 'fps' (frames-per-second counter)
#include "console.h"
#include "defs.h"
#include "events.h" // for CountEvents()
#include "layers.h"
#include "logic.h"
#include "maketext.h"
#include "mem_view.h"
#include "mouse.h"
#include "protocol.h"
#include "resman.h"
#include "router.h" // for PlotWalkGrid()
#include "speech.h" // for 'officialTextNumber' and 'speechScriptWaiting'
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// global variables
uint8 displayDebugText = 0; // "INFO" 0=off; 1=on
uint8 displayWalkGrid = 0; // "WALKGRID"
uint8 displayMouseMarker = 0; // "MOUSE"
uint8 displayTime = 0; // "TIME"
uint8 displayPlayerMarker = 0; // "PLAYER"
uint8 displayTextNumbers = 0; // "TEXT"
uint8 renderSkip = 0; // Toggled on 'S' key - to render only 1 in 4 frames, to speed up game
uint8 definingRectangles = 0; // "RECT"
uint8 draggingRectangle = 0; // 0=waiting to start new rect; 1=currently dragging a rectangle
int16 rect_x1 = 0;
int16 rect_y1 = 0;
int16 rect_x2 = 0;
int16 rect_y2 = 0;
uint8 rectFlicker=0;
uint8 testingSnR = 0; // "SAVEREST" - for system to kill all object resources (except player) in FN_add_human()
int32 startTime = 0; // "TIMEON" & "TIMEOFF" - system start time.
int32 gameCycle = 0; // Counter for game clocks.
int32 textNumber = 0; // current system text line number
int32 showVar[MAX_SHOWVARS]; // "SHOWVAR"
Object_graphic playerGraphic; // for displaying player object's current graphical info
uint32 player_graphic_no_frames=0; // no. of frames in currently displayed anim
uint8 debug_text_blocks[MAX_DEBUG_TEXT_BLOCKS];
//--------------------------------------------------------------------------------------
// function prototypes
void Clear_debug_text_blocks( void );
void Make_debug_text_block( char *text, int16 x, int16 y );
void Plot_cross_hair( int16 x, int16 y, uint8 pen );
void DrawRect( int16 x, int16 y, int16 x2, int16 y2, uint8 pen );
//--------------------------------------------------------------------------------------
#endif // _DEBUG
// THIS FUNCTION STAYS IN THE RELEASE VERSION
// IN FACT, CON_FATAL_ERROR IS MAPPED TO THIS AS WELL, SO WE HAVE A MORE PRESENTABLE ERROR REPORT
void ExitWithReport(char *format,...) // (6dec96 JEL)
{
// Send a printf type string to Paul's windows routine
char buf[500];
va_list arg_ptr; // Variable argument pointer
va_start(arg_ptr,format);
vsprintf(buf, format, arg_ptr);
Zdebug("%s",buf); // send output to 'debug.txt' as well, just for the record
while (GetFadeStatus()) // wait for fade to finish before calling RestoreDisplay()
ServiceWindows();
RestoreDisplay();
ReportFatalError((uint8 *)buf); // display message box
CloseAppWindow();
while (ServiceWindows() != RDERR_APPCLOSED);
exit(0);
}
#if _DEBUG // all other functions only for _DEBUG version
//--------------------------------------------------------------------------------------
void Zdebug(char *format,...) //Tony's special debug logging file March96
{
// Write a printf type string to a debug file
va_list arg_ptr; // Variable argument pointer
FILE * debug_filep=0; // Debug file pointer
static int first_debug = 1; // Flag for first time this is used
va_start(arg_ptr,format);
if (first_debug) //First time round delete any previous debug file
{
unlink("debug.txt");
first_debug = 0;
}
debug_filep = fopen("debug.txt","a+t");
if (debug_filep != NULL) // if it could be opened
{
vfprintf(debug_filep, format, arg_ptr);
fprintf(debug_filep,"\n");
fclose(debug_filep);
}
}
//--------------------------------------------------------------------------------------
void Zdebug(uint32 stream, char *format,...) //Tony's special debug logging file March96
{
// Write a printf type string to a debug file
va_list arg_ptr; // Variable argument pointer
FILE * debug_filep=0; // Debug file pointer
static int first = 1; // Flag for first time this is used
int j;
static int first_debugs[100];
if (first==1) //first time run then reset the states
{ for (j=0;j<100;j++)
first_debugs[j]=0;
first=0;
}
char name[20];
sprintf(name, "debug%d.txt", stream);
va_start(arg_ptr,format);
if (!first_debugs[stream]) //First time round delete any previous debug file
{
unlink(name);
first_debugs[stream] = 1;
}
debug_filep = fopen(name,"a+t");
if (debug_filep != NULL) // if it could be opened
{
vfprintf(debug_filep, format, arg_ptr);
fprintf(debug_filep,"\n");
fclose(debug_filep);
}
}
//--------------------------------------------------------------------------------------
void Clear_debug_text_blocks( void ) // JAMES
{
uint8 blockNo=0;
while ((blockNo < MAX_DEBUG_TEXT_BLOCKS) && (debug_text_blocks[blockNo] > 0))
{
Kill_text_bloc(debug_text_blocks[blockNo]); // kill the system text block
debug_text_blocks[blockNo] = 0; // clear this element of our array of block numbers
blockNo++;
}
}
//--------------------------------------------------------------------------------------
void Make_debug_text_block( char *text, int16 x, int16 y) // JAMES
{
uint8 blockNo=0;
while ((blockNo < MAX_DEBUG_TEXT_BLOCKS) && (debug_text_blocks[blockNo] > 0))
blockNo++;
if (blockNo == MAX_DEBUG_TEXT_BLOCKS)
Con_fatal_error("ERROR: debug_text_blocks[] full in Make_debug_text_block() at line %d in file \"%s\"",__LINE__,__FILE__);
debug_text_blocks[blockNo] = Build_new_block( (uint8 *)text, x, y, 640-x, 0, RDSPR_DISPLAYALIGN, CONSOLE_FONT_ID, NO_JUSTIFICATION);
}
//--------------------------------------------------------------------------------------
//
//
// PC Build_debug_info
//
//
//--------------------------------------------------------------------------------------
void Build_debug_text( void ) // JAMES
{
char buf[128];
int32 showVarNo; // for variable watching
int32 showVarPos;
int32 varNo;
int32 *varTable;
Clear_debug_text_blocks(); // clear the array of text block numbers for the debug text
//-------------------------------------------------------------------
// mouse coords
/*
if (displayMouseMarker) // print mouse coords beside mouse-marker, if it's being displayed
{
sprintf (buf, "%d,%d", mousex+this_screen.scroll_offset_x, mousey+this_screen.scroll_offset_y);
if (mousex>560)
Make_debug_text_block (buf, mousex-50, mousey-15);
else
Make_debug_text_block (buf, mousex+5, mousey-15);
}
*/
//-------------------------------------------------------------------
// mouse area coords
if (draggingRectangle || SYSTEM_TESTING_ANIMS) // defining a mouse area the easy way, by creating a box on-screen
{
rectFlicker = 1-rectFlicker; // so we can see what's behind the lines
sprintf (buf, "x1=%d", rect_x1);
Make_debug_text_block (buf, 0, 120);
sprintf (buf, "y1=%d", rect_y1);
Make_debug_text_block (buf, 0, 135);
sprintf (buf, "x2=%d", rect_x2);
Make_debug_text_block (buf, 0, 150);
sprintf (buf, "y2=%d", rect_y2);
Make_debug_text_block (buf, 0, 165);
}
//-------------------------------------------------------------------
// testingSnR indicator
if (testingSnR) // see FN_add_human()
{
sprintf (buf, "TESTING LOGIC STABILITY!");
Make_debug_text_block (buf, 0, 105);
}
//---------------------------------------------
// speed-up indicator
if (renderSkip) // see sword.cpp
{
sprintf (buf, "SKIPPING FRAMES FOR SPEED-UP!");
Make_debug_text_block (buf, 0, 120);
}
//---------------------------------------------
// debug info at top of screen - enabled/disabled as one complete unit
if (displayTime)
{
int32 time = timeGetTime();
if ((time - startTime) / 1000 >= 10000)
startTime = time;
time -= startTime;
sprintf(buf, "Time %.2d:%.2d:%.2d.%.3d",(time / 3600000) % 60,(time / 60000) % 60, (time / 1000) % 60,time%1000);
Make_debug_text_block(buf, 500, 360);
sprintf(buf, "Game %d", gameCycle);
Make_debug_text_block(buf, 500, 380);
}
//---------------------------------------------
// current text number & speech-sample resource id
if (displayTextNumbers)
{
if (textNumber)
{
if (SYSTEM_TESTING_TEXT)
{
if (SYSTEM_WANT_PREVIOUS_LINE)
sprintf (buf, "backwards");
else
sprintf (buf, "forwards");
Make_debug_text_block (buf, 0, 340);
}
sprintf (buf, "res: %d", textNumber/SIZE);
Make_debug_text_block (buf, 0, 355);
sprintf (buf, "pos: %d", textNumber&0xffff);
Make_debug_text_block (buf, 0, 370);
sprintf (buf, "TEXT: %d", officialTextNumber);
Make_debug_text_block (buf, 0, 385);
}
}
//---------------------------------------------
// resource number currently being checking for animation
if (SYSTEM_TESTING_ANIMS)
{
sprintf (buf, "trying resource %d", SYSTEM_TESTING_ANIMS);
Make_debug_text_block (buf, 0, 90);
}
//---------------------------------------------
// general debug info
if (displayDebugText)
{
//---------------------------------------------
/*
// CD in use
sprintf (buf, "CD-%d", currentCD);
Make_debug_text_block (buf, 0, 0);
*/
//---------------------------------------------
// mouse coords & object pointed to
if (CLICKED_ID)
sprintf (buf, "last click at %d,%d (id %d: %s)", MOUSE_X, MOUSE_Y, CLICKED_ID, FetchObjectName(CLICKED_ID));
else
sprintf (buf, "last click at %d,%d (---)", MOUSE_X, MOUSE_Y);
Make_debug_text_block (buf, 0, 15);
if (mouse_touching)
sprintf (buf, "mouse %d,%d (id %d: %s)", mousex+this_screen.scroll_offset_x, mousey+this_screen.scroll_offset_y, mouse_touching, FetchObjectName(mouse_touching));
else
sprintf (buf, "mouse %d,%d (not touching)", mousex+this_screen.scroll_offset_x, mousey+this_screen.scroll_offset_y);
Make_debug_text_block (buf, 0, 30);
//---------------------------------------------
// player coords & graphic info
if (playerGraphic.anim_resource) // if player objct has a graphic
sprintf (buf, "player %d,%d %s (%d) #%d/%d", this_screen.player_feet_x, this_screen.player_feet_y, FetchObjectName(playerGraphic.anim_resource), playerGraphic.anim_resource, playerGraphic.anim_pc, player_graphic_no_frames);
else
sprintf (buf, "player %d,%d --- %d", this_screen.player_feet_x, this_screen.player_feet_y, playerGraphic.anim_pc);
Make_debug_text_block (buf, 0, 45);
//---------------------------------------------
// frames-per-second counter
sprintf (buf, "fps %d", fps);
Make_debug_text_block (buf, 440, 0);
//---------------------------------------------
// location number
sprintf (buf, "location=%d", LOCATION);
Make_debug_text_block (buf, 440, 15);
//---------------------------------------------
// "result" variable
sprintf (buf, "result=%d", RESULT);
Make_debug_text_block (buf, 440, 30);
//---------------------------------------------
// no. of events in event list
sprintf (buf, "events=%d", CountEvents());
Make_debug_text_block (buf, 440, 45);
//---------------------------------------------
// sprite list usage
sprintf (buf, "bgp0: %d/%d",cur_bgp0,MAX_bgp0_sprites);
Make_debug_text_block (buf, 560, 0);
sprintf (buf, "bgp1: %d/%d",cur_bgp1,MAX_bgp1_sprites);
Make_debug_text_block (buf, 560, 15);
sprintf (buf, "back: %d/%d",cur_back,MAX_back_sprites);
Make_debug_text_block (buf, 560, 30);
sprintf (buf, "sort: %d/%d",cur_sort,MAX_sort_sprites);
Make_debug_text_block (buf, 560, 45);
sprintf (buf, "fore: %d/%d",cur_fore,MAX_fore_sprites);
Make_debug_text_block (buf, 560, 60);
sprintf (buf, "fgp0: %d/%d",cur_fgp0,MAX_fgp0_sprites);
Make_debug_text_block (buf, 560, 75);
sprintf (buf, "fgp1: %d/%d",cur_fgp1,MAX_fgp1_sprites);
Make_debug_text_block (buf, 560, 90);
//---------------------------------------------
// largest layer & sprite
// NB. Strings already constructed in Build_display.cpp
Make_debug_text_block (largest_layer_info, 0, 60);
Make_debug_text_block (largest_sprite_info, 0, 75);
//---------------------------------------------
// "waiting for person" indicator - set form FN_they_do & FN_they_do_we_wait
if (speechScriptWaiting)
{
sprintf (buf, "script waiting for %s (%d)", FetchObjectName(speechScriptWaiting), speechScriptWaiting);
Make_debug_text_block (buf, 0, 90);
}
//---------------------------------------------
// variable watch display
showVarPos = 115; // y-coord for first showVar
varTable = (int32*)(res_man.Res_open(1) + sizeof(_standardHeader)); // res 1 is the global variables resource
for (showVarNo=0; showVarNo < MAX_SHOWVARS; showVarNo++)
{
varNo = showVar[showVarNo]; // get variable number
if (varNo) // if non-zero ie. cannot watch 'id' but not needed anyway because it changes throughout the logic loop
{
sprintf (buf, "var(%d) = %d", varNo, varTable[varNo]);
Make_debug_text_block (buf, 530, showVarPos);
showVarPos += 15; // next line down
}
}
res_man.Res_close(1); // close global variables resource
//---------------------------------------------
// memory indicator - this should come last, to show all the sprite blocks above!
Create_mem_string (buf);
Make_debug_text_block (buf, 0, 0);
//---------------------------------------------
}
//-------------------------------------------------------------------
}
//--------------------------------------------------------------------------------------
void Draw_debug_graphics( void ) // JAMES (08apr97)
{
//-------------------------------
// walk-grid
if (displayWalkGrid)
PlotWalkGrid();
//-------------------------------
// player feet coord marker
if (displayPlayerMarker)
Plot_cross_hair (this_screen.player_feet_x, this_screen.player_feet_y, 215);
//-------------------------------------------------------------------
// mouse marker & coords
if (displayMouseMarker)
Plot_cross_hair (mousex+this_screen.scroll_offset_x, mousey+this_screen.scroll_offset_y, 215);
//-------------------------------------------------------------------
// mouse area rectangle / sprite box rectangle when testing anims
if (SYSTEM_TESTING_ANIMS)
{
DrawRect(rect_x1, rect_y1, rect_x2, rect_y2, 184); // draw box around current frame
}
else if (draggingRectangle) // defining a mouse area the easy way, by creating a box on-screen
{
if (rectFlicker)
DrawRect(rect_x1, rect_y1, rect_x2, rect_y2, 184);
}
//-------------------------------------------------------------------
}
//--------------------------------------------------------------------------------------
void Plot_cross_hair( int16 x, int16 y, uint8 pen )
{
PlotPoint(x,y,pen); // driver function
DrawLine(x-2,y,x-5,y,pen); // driver function
DrawLine(x+2,y,x+5,y,pen);
DrawLine(x,y-2,x,y-5,pen);
DrawLine(x,y+2,x,y+5,pen);
}
//--------------------------------------------------------------------------------------
void DrawRect( int16 x1, int16 y1, int16 x2, int16 y2, uint8 pen )
{
DrawLine(x1,y1,x2,y1,pen); // top edge
DrawLine(x1,y2,x2,y2,pen); // bottom edge
DrawLine(x1,y1,x1,y2,pen); // left edge
DrawLine(x2,y1,x2,y2,pen); // right edge
}
//--------------------------------------------------------------------------------------
void Print_current_info(void) //Tony30Oct96
{
//prints general stuff about the screen, etc.
if (this_screen.background_layer_id)
{ Print_to_console(" background layer id %d", this_screen.background_layer_id);
Print_to_console(" %d wide, %d high", this_screen.screen_wide, this_screen.screen_deep);
Print_to_console(" %d normal layers", this_screen.number_of_layers);
LLogic.Examine_run_list();
}
else
Print_to_console(" no screen");
Scroll_console();
}
//--------------------------------------------------------------------------------------
#else // not debug
void Draw_debug_graphics(void) {};
#endif // _DEBUG
//--------------------------------------------------------------------------------------

92
sword2/debug.h Normal file
View file

@ -0,0 +1,92 @@
/* 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$
*/
#ifndef D_DEBUG
#define D_DEBUG
//--------------------------------------------------------------------------------------
#ifdef _DEBUG // this whole file only included on debug versions
//#include "src\driver96.h"
#include "driver.h"
#include "object.h"
#define MAX_DEBUG_TEXT_BLOCKS 50
extern uint8 displayDebugText; // 0=off; 1=on
extern uint8 displayWalkGrid;
extern uint8 displayMouseMarker;
extern uint8 displayPlayerMarker;
extern uint8 displayTime;
extern uint8 displayTextNumbers;
extern uint8 definingRectangles;
extern uint8 draggingRectangle;
extern uint8 displayTime;
extern int32 startTime;
extern int32 gameCycle;
extern uint8 renderSkip;
extern int16 rect_x1;
extern int16 rect_y1;
extern int16 rect_x2;
extern int16 rect_y2;
extern uint8 testingSnR;
extern int32 textNumber;
extern Object_graphic playerGraphic;
extern uint32 player_graphic_no_frames;
#define MAX_SHOWVARS 15
extern int32 showVar[MAX_SHOWVARS];
void Zdebug(char * ,...); // Tony's special debug logging file March96
void Zdebug(uint32 stream, char *format,...);
void Build_debug_text(void); // James's debug text display
void Draw_debug_graphics(void); // James's debug graphics display
void Print_current_info(void); //Tony30Oct96
#else // ie. not _DEBUG
/* gcc doesn't like this - khalek
#define Zdebug NULL
#define Build_debug_text NULL
#define Draw_debug_graphics NULL
#define Print_current_info NULL
*/
void Zdebug(char * ,...); // Tony's special debug logging file March96
void Build_debug_text(void); // James's debug text display
void Draw_debug_graphics(void); // James's debug graphics display
#endif // _DEBUG // this whole file only included on debug versions
//--------------------------------------------------------------------------------------
void ExitWithReport(char *format,...); // (6dec96 JEL) IN BOTH DEBUG & RELEASE VERSIONS
#endif //D_DEBUG

139
sword2/defs.h Normal file
View file

@ -0,0 +1,139 @@
/* 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$
*/
#ifndef DEFS
#define DEFS
#include "header.h"
#include "resman.h"
//--------------------------------------------------------------------------------------
#define SIZE 0x10000 //65536 items per section
#define NuSIZE 0xffff //& with this
//--------------------------------------------------------------------------------------
//global variable references
// NB. 4 * <number from linc's Global Variables list>
#define ID *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader))
#define RESULT *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1) // 4 * <number from linc's Global Variables list>
#define PLAYER_ACTION *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 2)
//#define CUR_PLAYER_ID *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 3)
#define CUR_PLAYER_ID 8 // always 8 (George object used for Nico player character as well)
#define PLAYER_ID *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 305)
#define TALK_FLAG *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 13)
#define MOUSE_X *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 4)
#define MOUSE_Y *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 5)
#define LEFT_BUTTON *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 109)
#define RIGHT_BUTTON *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 110)
#define CLICKED_ID *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 178)
#define IN_SUBJECT *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 6)
#define COMBINE_BASE *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 7)
#define OBJECT_HELD *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 14)
#define SPEECH_ID *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 9)
#define INS1 *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 10)
#define INS2 *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 11)
#define INS3 *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 12)
#define INS4 *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 60)
#define INS5 *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 61)
#define INS_COMMAND *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 59)
#define PLAYER_FEET_X *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 141)
#define PLAYER_FEET_Y *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 142)
#define PLAYER_CUR_DIR *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 937)
#define LOCATION *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 62) // for debug.cpp
#define SCROLL_X *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 345) // so scripts can force scroll offsets
#define SCROLL_Y *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 346) // so scripts can force scroll offsets
#define EXIT_CLICK_ID *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 710)
#define EXIT_FADING *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 713)
#define SYSTEM_TESTING_ANIMS *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 912)
#define SYSTEM_TESTING_TEXT *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1230)
#define SYSTEM_WANT_PREVIOUS_LINE *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1245)
#define MOUSE_AVAILABLE *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 686) // 1=on 0=off (set in FN_add_human & FN_no_human)
#define AUTO_SELECTED *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1115) // used in FN_choose
#define CHOOSER_COUNT_FLAG *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 15) // see FN_start_conversation & FN_chooser
#define DEMO *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1153) //signifies a demo mode
#define PSXFLAG *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1173) // Indicates to script whether this is the Playstation version.
#define DEAD *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1256) //=1 =dead
#define SPEECHANIMFLAG *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1278) // If set indicates that the speech anim is to run through only once.
#define SCROLL_OFFSET_X *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 1314) //for the engine
#define GAME_LANGUAGE *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* 111) //for the poor PSX so it knows what language is running.
//--------------------------------------------------------------------------------------
//resource id's of pouse mointers. It's pretty much safe to do it like this
#define NORMAL_MOUSE_ID 17
#define SCROLL_LEFT_MOUSE_ID 1440
#define SCROLL_RIGHT_MOUSE_ID 1441
//--------------------------------------------------------------------------------------
// Console Font - does not use game text - only English required
#define CONSOLE_FONT_ID 340 // ConsFont
// Speech Font
#define ENGLISH_SPEECH_FONT_ID 341 // SpchFont
#define FINNISH_SPEECH_FONT_ID 956 // FinSpcFn
#define POLISH_SPEECH_FONT_ID 955 // PolSpcFn
// Control Panel Font (and un-selected savegame descriptions)
#define ENGLISH_CONTROLS_FONT_ID 2005 // Sfont
#define FINNISH_CONTROLS_FONT_ID 959 // FinSavFn
#define POLISH_CONTROLS_FONT_ID 3686 // PolSavFn
// Red Font (for selected savegame descriptions)
#define ENGLISH_RED_FONT_ID 2005 // 1998 // Redfont
#define FINNISH_RED_FONT_ID 959 // 960 // FinRedFn
#define POLISH_RED_FONT_ID 3686 // 3688 // PolRedFn
//--------------------------------------------------------------------------------------
// Control panel palette resource id
#define CONTROL_PANEL_PALETTE 261
//--------------------------------------------------------------------------------------
// res id's of the system menu icons
#define OPTIONS_ICON 344
#define QUIT_ICON 335
#define SAVE_ICON 366
#define RESTORE_ICON 364
#define RESTART_ICON 342
//--------------------------------------------------------------------------------------
// res id of conversation exit icon
#define EXIT_ICON 65 // 'EXIT' menu icon (used in FN_choose)
//--------------------------------------------------------------------------------------
#endif

405
sword2/events.cpp Normal file
View file

@ -0,0 +1,405 @@
/* 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$
*/
//------------------------------------------------------------------------------------
#include <stdio.h>
//#include "src\driver96.h"
#include "console.h"
#include "debug.h"
#include "defs.h"
#include "events.h"
#include "interpreter.h"
#include "logic.h"
#include "memory.h"
#include "object.h"
#include "sync.h"
//------------------------------------------------------------------------------------
_event_unit event_list[MAX_events];
//------------------------------------------------------------------------------------
void Init_event_system(void) //Tony4Dec96
{
uint32 j;
for (j=0;j<MAX_events;j++)
event_list[j].id=0; //denotes free slot
}
//------------------------------------------------------------------------------------
uint32 CountEvents(void)
{
uint32 j;
uint32 count=0;
for (j=0; j<MAX_events; j++)
{
if (event_list[j].id)
count++;
}
return (count);
}
//------------------------------------------------------------------------------------
int32 FN_request_speech(int32 *params) //Tony13Nov96
{
//change current script - must be followed by a TERMINATE script directive
//param 0 id of target to catch the event and startup speech servicing
uint32 j=0;
while(1)
{
if (event_list[j].id == (uint32)params[0])
break;
if (!event_list[j].id)
break;
j++;
}
if (j==MAX_events)
Con_fatal_error("FN_set_event out of event slots (%s line %u)", __FILE__, __LINE__);
//found that slot
event_list[j].id=params[0]; //id of person to stop
event_list[j].interact_id=(params[0]*65536)+6; //full script id to interact with - megas run their own 7th script
return(IR_CONT);
}
//------------------------------------------------------------------------------------
void Set_player_action_event(uint32 id, uint32 interact_id) //Tony4Dec96
{
uint32 j=0;
// if ((event_list[j].id!=id)&&(event_list[j].id))
// while((event_list[j].id!=id)||(event_list[j].id)) //zip along until we find a free slot
// { j++;
// };
while(1)
{
if (event_list[j].id==id)
break;
if (!event_list[j].id)
break;
j++;
}
if (j==MAX_events)
Con_fatal_error("Set_event out of event slots");
//found that slot
event_list[j].id=id; //id of person to stop
event_list[j].interact_id=(interact_id*65536)+2; //full script id of action script number 2
}
//------------------------------------------------------------------------------------
int32 FN_set_player_action_event(int32 *params) //Tony10Feb97
{
//we want to intercept the player character and have him interact with an object - from script
//this code is the same as the mouse engine calls when you click on an object - here, a third party does the clicking IYSWIM
//note - this routine used CUR_PLAYER_ID as the target
//params 0 id to interact with
uint32 j=0;
//search for an existing event or a slot
while(1)
{
if (event_list[j].id==CUR_PLAYER_ID)
break;
if (!event_list[j].id)
break;
j++;
}
if (j==MAX_events)
Con_fatal_error("Set_event out of event slots");
//found that slot
event_list[j].id=CUR_PLAYER_ID; //id of person to stop
event_list[j].interact_id=(params[0]*65536)+2; //full script id of action script number 2
return(IR_CONT);
}
//------------------------------------------------------------------------------------
int32 FN_send_event(int32 *params) //Tony28Feb97
{
//we want to intercept the player character and have him interact with an object - from script
// 0 id to recieve event
// 1 script to run
uint32 j=0;
// Zdebug("*+*+* %d %d", params[0], params[1] );
//search for an existing event or a slot
while(1)
{
if (event_list[j].id==(uint32)params[0])
break;
if (!event_list[j].id)
break;
j++;
}
if (j==MAX_events)
Con_fatal_error("fn_send_event out of event slots");
//found that slot
event_list[j].id=params[0]; //id of person to stop
event_list[j].interact_id=params[1]; //full script id
return(IR_CONT);
}
//------------------------------------------------------------------------------------
int32 FN_check_event_waiting(int32 *params) //Tony4Dec96
{
// returns yes/no in RESULT
// no params
uint32 j;
RESULT=0;
for (j=0; j<MAX_events; j++)
{
if (event_list[j].id == ID) //us?
{
RESULT=1;
break;
}
}
return(IR_CONT);
}
//------------------------------------------------------------------------------------
// like FN_check_event_waiting, but starts the event rather than setting RESULT to 1
int32 FN_check_for_event(int32 *params) // James (04mar97)
{
// no params
uint32 j;
for (j=0; j<MAX_events; j++)
{
if (event_list[j].id == ID) //us?
{
// start the event
LLogic.Logic_one(event_list[j].interact_id); // run 3rd script of target object on level 1
event_list[j].id = 0; // clear the event slot
return(IR_TERMINATE);
}
}
return(IR_CONT);
}
//------------------------------------------------------------------------------------
// combination of FN_pause & FN_check_for_event
// - ie. does a pause, but also checks for event each cycle
int32 FN_pause_for_event(int32 *params) // James (04mar97)
{
// returns yes/no in RESULT
// params: 0 pointer to object's logic structure
// 1 number of game-cycles to pause
Object_logic *ob_logic = (Object_logic *)params[0];
uint32 j;
// first, check for an event
for (j=0; j<MAX_events; j++)
{
if (event_list[j].id == ID) // us?
{
ob_logic->looping = 0; // reset the 'looping' flag
// start the event
LLogic.Logic_one(event_list[j].interact_id); // run 3rd script of target object on level 1
event_list[j].id = 0; // clear the event slot
return(IR_TERMINATE);
}
}
// no event, so do the FN_pause bit
if (ob_logic->looping==0) // start the pause
{
ob_logic->looping = 1;
ob_logic->pause = params[1]; // no. of game cycles
}
if (ob_logic->pause) // if non-zero
{
ob_logic->pause--; // decrement the pause count
return(IR_REPEAT); // drop out of script, but call this again next cycle
}
else // pause count is zerp
{
ob_logic->looping = 0;
return(IR_CONT); // continue script
}
}
//------------------------------------------------------------------------------------
uint32 Check_event_waiting(void) //Tony4Dec96
{
//returns yes/no
uint32 j;
for (j=0;j<MAX_events;j++)
if (event_list[j].id == ID) //us?
return(1); //yes
return(0); //no
}
//------------------------------------------------------------------------------------
int32 FN_clear_event(int32 *params) //Tony11Mar97
{
// no params
// no return vaule
uint32 j;
for (j=0;j<MAX_events;j++)
if (event_list[j].id == ID) //us?
{
event_list[j].id=0; //clear the slot
return(IR_CONT); //
}
return(IR_CONT); //
}
//------------------------------------------------------------------------------------
void Start_event(void) //Tony4Dec96
{
//call this from stuff like fn_walk
//you must follow with a return(IR_TERMINATE)
uint32 j;
for (j=0;j<MAX_events;j++)
if (event_list[j].id == ID) //us?
{
LLogic.Logic_one( event_list[j].interact_id); //run 3rd script of target object on level 1
event_list[j].id=0; //clear the slot
return;
}
//oh dear - stop the system
Con_fatal_error("Start_event can't find event for id %d", ID);
}
//------------------------------------------------------------------------------------
int32 FN_start_event(int32 *params) //Tony4Dec96
{
uint32 j;
for (j=0;j<MAX_events;j++)
if (event_list[j].id == ID) //us?
{
LLogic.Logic_one(event_list[j].interact_id); //run 3rd script of target object on level 1
event_list[j].id=0; //clear the slot
return(IR_TERMINATE);
}
//oh dear - stop the system
Con_fatal_error("FN_start_event can't find event for id %d", ID);
return(0); //never called - but lets stop them bloody errors
}
//------------------------------------------------------------------------------------
void Kill_all_ids_events(uint32 id) //Tony18Dec96
{
uint32 j;
for (j=0;j<MAX_events;j++)
if (event_list[j].id == id) //us?
event_list[j].id=0; //clear the slot
if (id);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

48
sword2/events.h Normal file
View file

@ -0,0 +1,48 @@
/* 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$
*/
#ifndef _EVENTS
#define _EVENTS
//#include "src\driver96.h"
#include "object.h"
typedef struct
{
uint32 id;
uint32 interact_id;
} _event_unit;
#define MAX_events 10
extern _event_unit event_list[MAX_events];
void Init_event_system(void); //Tony4Dec96
int32 FN_set_event(int32 *params); //Tony13Nov96
void Set_player_action_event(uint32 id, uint32 interact_id); //Tony4Dec96
int32 FN_check_event_waiting(void); //Tony4Dec96
void Start_event(void); //Tony4Dec96
int32 FN_start_event(void); //Tony4Dec96
uint32 Check_event_waiting(void); //Tony4Dec96
void Kill_all_ids_events(uint32 id); //Tony18Dec96
uint32 CountEvents(void); // James11july97
#endif

458
sword2/function.cpp Normal file
View file

@ -0,0 +1,458 @@
/* 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$
*/
//------------------------------------------------------------------------------------
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include "driver/driver96.h"
#include "build_display.h"
#include "credits.h"
#include "debug.h"
#include "defs.h"
#include "function.h"
#include "interpreter.h"
#include "layers.h" // for 'this_screen' structure
#include "logic.h"
#include "memory.h"
#include "object.h"
#include "protocol.h"
#include "resman.h"
#include "sword2.h" // for CloseGame()
//------------------------------------------------------------------------------------
typedef struct
{
uint32 a;
uint32 b;
} test_struct;
//------------------------------------------------------------------------------------
Object_graphic engine_graph; // global for engine
Object_mega engine_mega; // global for engine
//------------------------------------------------------------------------------------
int32 FN_test_function(int32 *params)
{
//param 0 address of a flag
Zdebug(" TEST %d %d", *params, RESULT);
return(IR_CONT);
}
//------------------------------------------------------------------------------------
int32 FN_test_flags(int32 *params)
{
//param 0 value of flag
test_struct *tony;
tony = (test_struct*) *params; //address of structure
// Zdebug("\nFN_test_flags %d, %d\n", tony->a, tony->b );
return(IR_CONT);
}
//------------------------------------------------------------------------------------
int32 FN_gosub(int32 *params) //Tony23Sept96
{
//hurray, script subroutines
//param 0 id of script
LLogic.Logic_up(*params);
return(4); //logic goes up - pc is saved for current level
}
//------------------------------------------------------------------------------------
int32 FN_new_script(int32 *params) //Tony13Nov96
{
//change current script - must be followed by a TERMINATE script directive
//param 0 id of script
Zdebug("FN_new_script %d", *params);
PLAYER_ACTION=0; //must clear this
LLogic.Logic_replace( *params );
return(IR_TERMINATE); //drop out no pc save - and around again
}
//------------------------------------------------------------------------------------
int32 FN_interact(int32 *params) //Tony13Nov96
{
//run targets action on a subroutine
//called by player on his base level 0 idle, for example
//param 0 id of target from which we derive action script reference
Zdebug("FN_interact %d", *params);
PLAYER_ACTION=0; //must clear this
LLogic.Logic_up( (*params*65536)+2); //3rd script of clicked on id
return(IR_GOSUB); //out, up and around again - pc is saved for current level to be returned to
}
//------------------------------------------------------------------------------------
// Open & close a resource.
// Forces a resource into memory before it's "officially" opened for use.
// eg. if an anim needs to run on smoothly from another, "preloading" gets it into memory in advance
// to avoid the cacheing delay that normally occurs before the first frame.
int32 FN_preload(int32 *params) // (1Nov96 JEL)
{
res_man.Res_open(params[0]); // open resource
res_man.Res_close(params[0]); // close resource
return(IR_CONT); // continue script
}
// Go fetch resource in the background.
int32 FN_prefetch(int32 *params)
{
return(IR_CONT);
}
// Fetches a resource in the background but prevents the script from continuing until the resource is in memory.
int32 FN_fetch_wait(int32 *params)
{
return (IR_CONT);
}
// Releases a resource from memory. Used for freeing memory for sprites that have just been used
// and will not be used again.
// Sometimes it is better to kick out a sprite straight away so that the memory can be used for
// more frequent animations.
int32 FN_release(int32 *params)
{
return (IR_CONT);
}
//------------------------------------------------------------------------------------
// Generates a random number between 'min' & 'max' inclusive, and sticks it in the script flag 'result'
int32 FN_random(int32 *params) // (1nov96 JEL)
{
uint32 min = params[0];
uint32 max = params[1];
RESULT = (rand() % (max-min+1)) + min; // return_value = random integer between min and max, inclusive
return(IR_CONT); // continue script
}
//------------------------------------------------------------------------------------
int32 FN_pause(int32 *params) // (19nov96 JEL)
{
// params: 0 pointer to object's logic structure
// 1 number of game-cycles to pause
//NB. Pause-value of 0 causes script to continue, 1 causes a 1-cycle quit, 2 gives 2 cycles, etc.
Object_logic *ob_logic = (Object_logic *)params[0];
if (ob_logic->looping==0) // start the pause
{
ob_logic->looping = 1;
ob_logic->pause = params[1]; // no. of game cycles
}
if (ob_logic->pause) // if non-zero
{
ob_logic->pause--; // decrement the pause count
return(IR_REPEAT); // drop out of script, but call this again next cycle
}
else // pause count is zerp
{
ob_logic->looping = 0;
return(IR_CONT); // continue script
}
}
//------------------------------------------------------------------------------------
int32 FN_random_pause(int32 *params) // (26nov96 JEL)
{
// params: 0 pointer to object's logic structure
// 1 minimum number of game-cycles to pause
// 2 maximum number of game-cycles to pause
Object_logic *ob_logic = (Object_logic *)params[0];
int32 pars[2];
if (ob_logic->looping==0)
{
pars[0] = params[1]; // min
pars[1] = params[2]; // max
FN_random(pars);
pars[1] = RESULT; // random value between 'min' & 'max' inclusive
}
pars[0] = params[0]; // &logic
return FN_pause(pars);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
int32 FN_pass_graph(int32 *params) //Tony28Nov96
{
//makes an engine local copy of passed graphic_structure and mega_structure - run script 4 of an object to request this
//used by FN_turn_to(id) etc
//remember, we cannot simply read a compact any longer but instead must request it from the object itself
//params 0 pointer to a graphic structure *might not need this?
memcpy( &engine_graph, (uint8*)params[0], sizeof(Object_graphic));
return(IR_CONT); //makes no odds
}
//------------------------------------------------------------------------------------
int32 FN_pass_mega(int32 *params) //Tony28Nov96
{
//makes an engine local copy of passed graphic_structure and mega_structure - run script 4 of an object to request this
//used by FN_turn_to(id) etc
//remember, we cannot simply read a compact any longer but instead must request it from the object itself
//params 0 pointer to a mega structure
memcpy( &engine_mega, (uint8*)params[0], sizeof(Object_mega));
return(IR_CONT); //makes no odds
}
//------------------------------------------------------------------------------------
// temp. function!
// used for setting far-referenced megaset resource field in mega object, from start script
int32 FN_set_value(int32 *params) // (02jan97 JEL)
{
// params: 0 pointer to object's mega structure
// 1 value to set it to
Object_mega *ob_mega = (Object_mega *)params[0];
ob_mega->megaset_res = params[1];
return(IR_CONT); // continue script
}
//------------------------------------------------------------------------------------
#define BLACK 0
#define WHITE 1
#define RED 2
#define GREEN 3
#define BLUE 4
//------------------------------------------------------------------------------------
uint8 black[4] = {0,0,0,0};
uint8 white[4] = {255,255,255,0};
uint8 red[4] = {255,0,0,0};
uint8 green[4] = {0,255,0,0};
uint8 blue[4] = {0,0,255,0};
//------------------------------------------------------------------------------------
// flash colour 0 (ie. border) - useful during script development
// eg. FN_flash(BLUE) where a text line is missed; RED when some code missing, etc
int32 FN_flash(int32 *params) // (James14feb97)
{
// params 0: colour to flash
#ifdef _DEBUG
uint32 count;
switch (params[0]) // what colour?
{
case WHITE:
SetPalette(0, 1, white, RDPAL_INSTANT);
break;
case RED:
SetPalette(0, 1, red, RDPAL_INSTANT);
break;
case GREEN:
SetPalette(0, 1, green, RDPAL_INSTANT);
break;
case BLUE:
SetPalette(0, 1, blue, RDPAL_INSTANT);
break;
}
for (count=0; count<0x80000; count++)
{
count++;
count--;
}
SetPalette(0, 1, black, RDPAL_INSTANT);
#endif // _DEBUG
return(IR_CONT);
}
//------------------------------------------------------------------------------------
// set border colour - useful during script development
// eg. set to colour during a timer situation, then black when timed out
int32 FN_colour(int32 *params) // (James14feb97)
{
// params 0: colour (see defines above)
#ifdef _DEBUG
switch (params[0]) // what colour?
{
case BLACK:
SetPalette(0, 1, black, RDPAL_INSTANT);
break;
case WHITE:
SetPalette(0, 1, white, RDPAL_INSTANT);
break;
case RED:
SetPalette(0, 1, red, RDPAL_INSTANT);
break;
case GREEN:
SetPalette(0, 1, green, RDPAL_INSTANT);
break;
case BLUE:
SetPalette(0, 1, blue, RDPAL_INSTANT);
break;
}
#endif // _DEBUG
return(IR_CONT);
}
//------------------------------------------------------------------------------------
// Display a message to the user on the screen.
//
int32 FN_display_msg(int32 *params) // (Chris 15/5/97)
{
// params 0: Text number of message to be displayed.
uint32 local_text = params[0]&0xffff;
uint32 text_res = params[0]/SIZE;
// Display message for three seconds.
DisplayMsg(FetchTextLine( res_man.Res_open(text_res), local_text )+2, 3); // +2 to skip the encoded text number in the first 2 chars; 3 is duration in seconds
res_man.Res_close(text_res);
RemoveMsg();
return(IR_CONT);
}
//------------------------------------------------------------------------------------
// FN_reset_globals is used by the demo - so it can loop back & restart itself
int32 FN_reset_globals(int32 *params) //Tony29May97
{
int32 size;
uint32 *globals;
int j;
size = res_man.Res_fetch_len(1);
size-=sizeof(_standardHeader);
Zdebug("\nglobals size %d", size/4);
globals = (uint32*) ((uint8 *) res_man.Res_open(1)+sizeof(_standardHeader));
for (j=0;j<size/4;j++)
globals[j]=0; //blank each global variable
res_man.Res_close(1);
res_man.Kill_all_objects(0); //all objects but george
// SetGlobalInterpreterVariables((int32*)(res_man.Res_open(1)+sizeof(_standardHeader))); //reopen global variables resource & send address to interpreter - it won't be moving
// res_man.Res_close(1);
//---------------------------------------------------------------
// FOR THE DEMO - FORCE THE SCROLLING TO BE RESET! (James29may97)
// - this is taken from FN_init_background
this_screen.scroll_flag = 2; // switch on scrolling (2 means first time on screen)
//---------------------------------------------------------------
return(IR_CONT);
}
//------------------------------------------------------------------------------------
// FN_play_credits - Plays the credits?
// This function just quits the game if this is the playable demo, ie. credits are NOT played in the demo any more!
extern uint8 quitGame; // From sword2.cpp
extern void UpdateCompSampleStreaming(void); // From d_sound.c
int32 FN_play_credits(int32 *params)
{
/* uint32 rv; // for Credits() return value
if (!DEMO) // this ju
{
_drvDrawStatus ds;
_drvSoundStatus ss;
_drvKeyStatus ks;
ClearAllFx(); // Must stop all fx
CloseFx(-2); // including leadins
CloseFx(-1); // including leadouts
StopMusic(); // Stop any streaming music
for (int i = 0; i<16; i++)
UpdateCompSampleStreaming(); // And wait for it to die
GetDrawStatus (&ds);
GetSoundStatus(&ss);
GetKeyStatus (&ks);
rv = Credits(&ds, &ss, res_man.GetCdPath(), GetRenderType()==3, &gotTheFocus, &ks);
SetDrawStatus (&ds); // (James14aug97) Because game crashing when trying to close down after credits
SetSoundStatus(&ss); // -"-
}
// returns non-zero if Ctrl-Q was pressed to quit the game during the credits
if (rv || DEMO) // if Ctrl-Q pressed during credits, or if this is the playable demo
{
Close_game(); //close engine systems down
RestoreDisplay();
CloseAppWindow();
exit(0); // quit the game
}
*/
return (IR_CONT);
}
//------------------------------------------------------------------------------------

31
sword2/function.h Normal file
View file

@ -0,0 +1,31 @@
/* 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$
*/
#ifndef _FUNCTION
#define _FUNCTION
//#include "src\driver96.h"
#include "object.h"
extern Object_graphic engine_graph; // global for engine
extern Object_mega engine_mega; // global for engine
#endif

355
sword2/header.h Normal file
View file

@ -0,0 +1,355 @@
/* 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$
*/
#ifndef _HEADER
#define _HEADER
#include "common/scummsys.h"
//#include "src\driver96.h"
//----------------------------------------------------------
// SYSTEM FILE & FRAME HEADERS (23sep96 JEL)
//----------------------------------------------------------
//#pragma pack( push )
//#pragma pack( 1 )
#if !defined(__GNUC__)
#pragma START_PACK_STRUCTS
#endif
//----------------------------------------------------------
// ALL FILES
//----------------------------------------------------------
// Standard File Header
#define NAME_LEN 34
typedef struct
{
uint8 fileType; // byte to define file type (see below)
uint8 compType; // type of file compression used ie. on whole file (see below)
uint32 compSize; // length of compressed file (ie. length on disk)
uint32 decompSize; // length of decompressed file held in memory (NB. frames still held compressed)
uint8 name[NAME_LEN]; //name of object
} GCC_PACK _standardHeader;
//----------------------------------------------------------
// fileType
// 0 something's wrong!
#define ANIMATION_FILE 1 // all normal animations & sprites including mega-sets & font files which are the same format (but all frames always uncompressed)
#define SCREEN_FILE 2 // each contains background, palette, layer sprites, parallax layers & shading mask
#define GAME_OBJECT 3 // each contains object hub + structures + script data
#define WALK_GRID_FILE 4 // walk-grid data
#define GLOBAL_VAR_FILE 5 // all the global script variables in one file; "there can be only one"
#define PARALLAX_FILE_null 6 // NOT USED
#define RUN_LIST 7 // each contains a list of object resource id's
#define TEXT_FILE 8 // each contains all the lines of text for a location or a character's conversation script
#define SCREEN_MANAGER 9 // one for each location; this contains special startup scripts
#define MOUSE_FILE 10 // mouse pointers and luggage icons (sprites in General \ Mouse pointers & Luggage icons)
#define WAV_FILE 11 // wav file
#define ICON_FILE 12 // menu icon (sprites in General \ Menu icons
#define PALETTE_FILE 13 // separate palette file (see also _paletteHeader)
//----------------------------------------------------------
// compType
#define NO_COMPRESSION 0
#define FILE_COMPRESSION 1 // standard whole-file compression (not yet devised!)
//----------------------------------------------------------
//----------------------------------------------------------
// (1) ANIMATION FILES
//----------------------------------------------------------
// an animation file consists of:
// standard file header
// animation header
// a string of CDT entries (one per frame of the anim)
// a 16-byte colour table ONLY if (runTimeComp==RLE16)
// a string of groups of (frame header + frame data)
//----------------------------------------------------------
// Animation Header
typedef struct
{
uint8 runTimeComp; // type of runtime compression used for the frame data (see below)
uint16 noAnimFrames; // number of frames in the anim (ie. no. of CDT entries)
uint16 feetStartX; // start coords for mega to walk to, before running anim
uint16 feetStartY;
uint8 feetStartDir; // direction to start in before running anim
uint16 feetEndX; // end coords for mega to stand at after running anim (vital if anim starts from an off-screen position, or ends in a different place from the start)
uint16 feetEndY;
uint8 feetEndDir; // direction to start in after running anim
uint16 blend;
} GCC_PACK _animHeader;
//----------------------------------------------------------
// runtimeComp - compression used on each frame of the anim
#define NONE 0 // No frame compression
#define RLE256 1 // James's RLE for 256-colour sprites
#define RLE16 2 // James's RLE for 16- or 17-colour sprites
// (raw blocks have max 16 colours for 2 pixels per byte,
// so '0's are encoded only as FLAT for 17-colour sprites eg. George's mega-set)
//----------------------------------------------------------
// CDT Entry
typedef struct
{
int16 x; // sprite x-coord OR offset to add to mega's feet x-coord to calc sprite y-coord
int16 y; // sprite y-coord OR offset to add to mega's feet y-coord to calc sprite y-coord
uint32 frameOffset; // points to start of frame header (from start of file header)
uint8 frameType; // 0=print sprite normally with top-left corner at (x,y), otherwise see below...
} GCC_PACK _cdtEntry;
// 'frameType' bit values
#define FRAME_OFFSET 1 // print at (feetX+x,feetY+y), with scaling according to feetY
#define FRAME_FLIPPED 2 // print the frame flipped Left->Right
#define FRAME_256_FAST 4 // Frame has been compressed using Pauls fast RLE 256 compression.
//----------------------------------------------------------
//Frame Header
typedef struct
{
uint32 compSize; // compressed size of frame - NB. compression type is now in Anim Header
uint16 width; // dimensions of frame
uint16 height;
} GCC_PACK _frameHeader;
//----------------------------------------------------------
// Frame Data
// uint8 spriteData[width*height]; // one byte per pixel
//----------------------------------------------------------
//----------------------------------------------------------
// (2) SCREEN FILES
//----------------------------------------------------------
// a screen file consists of:
// standard file header
// multi screen header
// 4*256 bytes of palette data
// 256k palette match table
// 2 background parallax layers
// 1 background layer with screen header
// 2 foreground parallax layers
// a string of layer headers
// a string of layer masks
//----------------------------------------------------------
// Multi screen header
// Goes at the beginning of a screen file after the standard
// header.
// Gives offsets from start of table of each of the components
typedef struct
{
uint32 palette;
uint32 bg_parallax[2];
uint32 screen;
uint32 fg_parallax[2];
uint32 layers;
uint32 paletteTable;
uint32 maskOffset;
} GCC_PACK _multiScreenHeader;
//------------------------------------------------------------
// Palette Data
typedef struct
{
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
} GCC_PACK _palEntry;
#define NO_COLOURS 256
// _palEntry palette[NO_COLOURS]
//------------------------------------------------------------
// Screen Header
typedef struct
{
uint16 width; // dimensions of the background screen
uint16 height;
uint16 noLayers; // number of layer areas
} GCC_PACK _screenHeader;
//------------------------------------------------------------
// Background Raw Bitmap
// uint8 backgroundData[width*height]; // one byte per pixel
//------------------------------------------------------------
// Layer Header
// Note that all the layer headers are kept together,
// rather than being placed before each layer mask,
// in order to simplify the sort routine.
typedef struct
{
uint16 x; // coordinates of top-left pixel of area
uint16 y;
uint16 width;
uint16 height;
uint32 maskSize;
uint32 offset; // where to find mask data (from start of standard file header)
} GCC_PACK _layerHeader;
//------------------------------------------------------------
// Layer Mask
// uint8 layerData[width*height/8]; // 8 pixels to a byte
//------------------------------------------------------------
//----------------------------------------------------------
// (3) SCRIPT OBJECT FILES
//----------------------------------------------------------
// a script object file consists of:
// standard file header
// script object header
// script object data
//----------------------------------------------------------
// Script Object Header
// ???????
// ???????
// ???????
//----------------------------------------------------------
// Script Object Data
//----------------------------------------------------------
//----------------------------------------------------------
// (4) WALK-GRID FILES
//----------------------------------------------------------
// a walk-grid file consists of:
// standard file header
// walk-grid file header
// walk-grid data
//----------------------------------------------------------
// Walk-Grid Header - taken directly from old "header.h" in STD_INC
typedef struct
{
int32 numBars; // number of bars on the floor
int32 numNodes; // number of nodes
} GCC_PACK _walkGridHeader;
//----------------------------------------------------------
// Walk-Grid Data
// ???????
//----------------------------------------------------------
//----------------------------------------------------------
// (5) PALETTE FILES
//----------------------------------------------------------
// a palette file consists of:
// standard file header
// 4*256 bytes of palette data
// 256k palette match table
//----------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// PCX file header
//--------------------------------------------------------------------------------------------------
typedef struct
{ uint8 manufacturer;
uint8 version;
uint8 encoding;
uint8 bitsPerPixel;
int16 xmin,ymin;
int16 xmax,ymax;
int16 hres;
int16 vres;
char palette[48];
char reserved;
uint8 colourPlanes;
int16 bytesPerLine;
int16 paletteType;
char filler[58];
} GCC_PACK _PCXHEAD;
//----------------------------------------------------------
#define TREE_SIZE 3
typedef struct // an object hub - which represents all that remains of the compact concept
{
int32 type; // type of object
uint32 logic_level; // what level?
uint32 logic[TREE_SIZE]; // NOT USED
uint32 script_id[TREE_SIZE]; // need this if script
uint32 script_pc[TREE_SIZE]; // need this also
} GCC_PACK _object_hub;
//----------------------------------------------------------
//----------------------------------------------------------
// (6) text module header TW
typedef struct
{
uint32 noOfLines; //how many lines of text are there in this module
} GCC_PACK _textHeader;
//a text file has:
// _standardHeader
// _textHeader
// look up table, to
// line of text,0
// line of text,0
//----------------------------------------------------------
// #pragma pack( pop )
#if !defined(__GNUC__)
#pragma END_PACK_STRUCTS
#endif
#endif

244
sword2/icons.cpp Normal file
View file

@ -0,0 +1,244 @@
/* 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$
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "driver/driver96.h"
#include "console.h"
#include "icons.h"
#include "interpreter.h"
#include "logic.h"
#include "mouse.h"
#include "object.h"
//------------------------------------------------------------------------------------
menu_object temp_list[TOTAL_engine_pockets];
uint32 total_temp=0; //tempory list
menu_object master_menu_list[TOTAL_engine_pockets];
uint32 total_masters=0;
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
int32 FN_add_menu_object(int32 *params) //Tony1Oct96
{
//param 0 pointer to a menu_object structure to copy down
// Zdebug("FN_add_menu_object icon res");
#ifdef _DEBUG
if (total_temp == TOTAL_engine_pockets)
Con_fatal_error("TOTAL_engine_pockets exceeded! (%s line %u)",__FILE__,__LINE__);
#endif
// copy the structure to our in-the-engine list
memcpy( &temp_list[total_temp], (uint8*) *params, sizeof(menu_object)); //
total_temp++;
return(IR_CONT); // script continue
}
//------------------------------------------------------------------------------------
int32 FN_refresh_inventory(int32 *params) // (James28aug97)
{
// called from 'menu_look_or_combine' script in 'menu_master' object
// to update the menu to display a combined object while George runs voice-over
// Note that 'object_held' must be set to the graphic of the combined object
COMBINE_BASE=0; // can reset this now
examining_menu_icon=1; // so that the icon in 'object_held' is coloured while the rest are grey
Build_top_menu();
examining_menu_icon=0;
return(IR_CONT); // script continue
}
//------------------------------------------------------------------------------------
void Build_top_menu(void) //Tony19Nov96
{
// create and start the inventory menu - NOW AT THE BOTTOM OF THE SCREEN!
uint32 null_pc=0;
uint32 j,k;
uint8 icon_coloured;
uint8 *icon;
uint8 *head;
uint32 res;
total_temp=0; //reset temp list which will be totally rebuilt
// Zdebug("\nbuild top menu %d", total_masters);
//clear the temp list before building a new temp list in-case list gets smaller
for (j=0;j<TOTAL_engine_pockets;j++) //check each master
temp_list[j].icon_resource=0; //
//call menu builder script which will register all carried menu objects
head = res_man.Res_open(MENU_MASTER_OBJECT);
RunScript( (char*)head, (char*)head, &null_pc ); // run the 'build_menu' script in the 'menu_master' object
res_man.Res_close(MENU_MASTER_OBJECT);
//compare new with old
//anything in master thats not in new gets removed from master - if found in new too, remove from temp
if (total_masters)
{
for (j=0;j<total_masters;j++) //check each master
{
for (k=0;k<TOTAL_engine_pockets;k++)
{
res=0;
if (master_menu_list[j].icon_resource == temp_list[k].icon_resource) //if master is in temp
{
temp_list[k].icon_resource=0; //kill it in the temp
res=1;
break;
}
}
if (!res)
{ master_menu_list[j].icon_resource=0; //otherwise not in temp so kill in main
// Zdebug("Killed menu %d",j);
}
}
}
//merge master downwards
total_masters=0;
for (j=0;j<TOTAL_engine_pockets;j++) //check each master slot
{
if ((master_menu_list[j].icon_resource)&&(j!=total_masters)) //not current end - meaning out over the end so move down
{
memcpy( &master_menu_list[total_masters++], &master_menu_list[j], sizeof(menu_object)); //
master_menu_list[j].icon_resource=0; //moved down now so kill here
}
else if (master_menu_list[j].icon_resource) //skip full slots
total_masters++;
}
//add those new to menu still in temp but not yet in master to the end of the master
for (j=0;j<TOTAL_engine_pockets;j++) //check each master slot
if (temp_list[j].icon_resource) //here's a new temp
memcpy( &master_menu_list[total_masters++], &temp_list[j], sizeof(menu_object)); //
//init top menu from master list
for (j=0;j<15;j++)
{
if (master_menu_list[j].icon_resource)
{
res = master_menu_list[j].icon_resource; // 'res' is now the resource id of the icon
//-----------------------------------------------------------------------------------------------------
// WHEN AN ICON HAS BEEN RIGHT-CLICKED FOR 'EXAMINE' - SELECTION COLOURED, THE REST GREYED OUT
if (examining_menu_icon) // '1' when examining a menu-icon ('OBJECT_HELD' is the resource of the icon being examined)
{
if (res == OBJECT_HELD) // if this is the icon being examined, make it coloured
icon_coloured=1;
else // if not, grey this one out
icon_coloured=0;
}
//-----------------------------------------------------------------------------------------------------
// WHEN ONE MENU OBJECT IS BEING USED WITH ANOTHER - BOTH TO BE COLOURED, THE REST GREYED OUT
else if (COMBINE_BASE) // resource of second icon clicked
{
if ((res == OBJECT_HELD)||(res == COMBINE_BASE)) // if this if either of the icons being combined...
icon_coloured=1;
else
icon_coloured=0;
}
//-----------------------------------------------------------------------------------------------------
// NORMAL ICON SELECTION - SELECTION GREYED OUT, THE REST COLOURED
else
{
if (res == OBJECT_HELD) // if this is the selction, grey it out
icon_coloured=0;
else // if not, make it coloured
icon_coloured=1;
}
//-----------------------------------------------------------------------------------------------------
if (icon_coloured) // coloured
icon = res_man.Res_open( master_menu_list[j].icon_resource ) + sizeof(_standardHeader) + RDMENU_ICONWIDE*RDMENU_ICONDEEP;
else // greyed out
icon = res_man.Res_open( master_menu_list[j].icon_resource ) + sizeof(_standardHeader);
SetMenuIcon(RDMENU_BOTTOM, j, icon);
res_man.Res_close( res );
}
else
{
SetMenuIcon(RDMENU_BOTTOM, j, NULL); //no icon here
//Zdebug(" NULL for %d", j);
}
}
ShowMenu(RDMENU_BOTTOM);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
void Build_system_menu(void) //Tony19Mar97
{
//start a fresh top system menu
uint8 *icon;
int j;
uint32 icon_list[5] =
{
OPTIONS_ICON,
QUIT_ICON,
SAVE_ICON,
RESTORE_ICON,
RESTART_ICON
};
for (j=0;j<5;j++) //build them all high in full colour - when one is clicked on all the rest will grey out
{
if ((DEAD)&&(j==2)) //dead then SAVE not available
icon = res_man.Res_open( icon_list[j] ) + sizeof(_standardHeader);
else icon = res_man.Res_open( icon_list[j] ) + sizeof(_standardHeader) + RDMENU_ICONWIDE*RDMENU_ICONDEEP;
SetMenuIcon(RDMENU_TOP, j, icon);
res_man.Res_close( icon_list[j] );
}
ShowMenu(RDMENU_TOP);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

42
sword2/icons.h Normal file
View file

@ -0,0 +1,42 @@
/* 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$
*/
#ifndef _ICONS
#define _ICONS
//#include "src\driver96.h"
#include "object.h"
#define MENU_MASTER_OBJECT 44
#define TOTAL_subjects 375-256+1 //the speech subject bar
#define TOTAL_engine_pockets 15+10 // +10 for overflow
typedef struct
{
int32 icon_resource; // icon graphic graphic
int32 luggage_resource; // luggage icon resource (for attaching to mouse pointer)
} menu_object; //define these in a script and then register them with the system
extern menu_object master_menu_list[TOTAL_engine_pockets];
void Build_top_menu(void); //Tony19Nov96
void Build_system_menu(void); //Tony19Mar97
#endif

791
sword2/interpreter.cpp Normal file
View file

@ -0,0 +1,791 @@
/* 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$
*/
#ifndef INSIDE_LINC // Are we running in linc?
#include "console.h"
#endif
#include "driver/driver96.h"
#include "interpreter.h"
// This file serves two purposes. It is compiled as part of the test functions
// of Linc, and also as part of the game
// The machine code table
int32 FN_test_function(int32 *params);
int32 FN_test_flags(int32 *params);
int32 FN_register_start_point(int32 *params);
int32 FN_init_background(int32 *params);
int32 FN_set_session(int32 *params);
int32 FN_back_sprite(int32 *params);
int32 FN_sort_sprite(int32 *params);
int32 FN_fore_sprite(int32 *params);
int32 FN_register_mouse(int32 *params);
int32 FN_anim(int32 *);
int32 FN_random(int32 *);
int32 FN_preload(int32 *);
int32 FN_add_subject(int32 *);
int32 FN_interact(int32 *);
int32 FN_choose(int32 *);
int32 FN_walk(int32 *);
int32 FN_walk_to_anim(int32 *); // walk to start position of anim
int32 FN_turn(int32 *); // turn to (dir)
int32 FN_stand_at(int32 *); // stand at (x,y,dir)
int32 FN_stand(int32 *); // stand facing (dir)
int32 FN_stand_after_anim(int32 *); // stand at end position of anim
int32 FN_pause(int32 *);
int32 FN_mega_table_anim(int32 *);
int32 FN_add_menu_object(int32 *);
int32 FN_start_conversation(int32 *);
int32 FN_end_conversation(int32 *);
int32 FN_set_frame(int32 *);
int32 FN_random_pause(int32 *);
int32 FN_register_frame(int32 *);
int32 FN_no_sprite(int32 *);
int32 FN_send_sync(int32 *);
int32 FN_update_player_stats(int32 *);
int32 FN_pass_graph(int32 *);
int32 FN_init_floor_mouse(int32 *);
int32 FN_pass_mega(int32 *);
int32 FN_face_xy(int32 *);
int32 FN_end_session(int32 *);
int32 FN_no_human(int32 *);
int32 FN_add_human(int32 *);
int32 FN_we_wait(int32 *);
int32 FN_they_do_we_wait(int32 *);
int32 FN_they_do(int32 *);
int32 FN_walk_to_talk_to_mega(int32 *);
int32 FN_fade_down(int32 *);
int32 FN_i_speak(int32 *);
int32 FN_total_restart(int32 *);
int32 FN_set_walkgrid(int32 *);
int32 FN_speech_process(int32 *);
int32 FN_set_scaling(int32 *);
int32 FN_start_event(int32 *);
int32 FN_check_event_waiting(int32 *);
int32 FN_request_speech(int32 *);
int32 FN_gosub(int32 *);
int32 FN_timed_wait(int32 *);
int32 FN_play_fx(int32 *);
int32 FN_stop_fx(int32 *);
int32 FN_play_music(int32 *);
int32 FN_stop_music(int32 *);
int32 FN_set_value(int32 *);
int32 FN_new_script(int32 *);
int32 FN_get_sync(int32 *);
int32 FN_wait_sync(int32 *);
int32 FN_register_walkgrid(int32 *);
int32 FN_reverse_mega_table_anim(int32 *);
int32 FN_reverse_anim(int32 *);
int32 FN_add_to_kill_list(int32 *);
int32 FN_set_standby_coords(int32 *);
int32 FN_back_par0_sprite(int32 *params);
int32 FN_back_par1_sprite(int32 *params);
int32 FN_fore_par0_sprite(int32 *params);
int32 FN_fore_par1_sprite(int32 *params);
int32 FN_fore_par1_sprite(int32 *params);
int32 FN_set_player_action_event(int32 *params);
int32 FN_set_scroll_coordinate(int32 *params);
int32 FN_stand_at_anim(int32 *params);
int32 FN_set_scroll_left_mouse(int32 *params);
int32 FN_set_scroll_right_mouse(int32 *params);
int32 FN_colour(int32 *params);
int32 FN_flash(int32 *params);
int32 FN_prefetch(int32 *params);
int32 FN_get_player_savedata(int32 *params);
int32 FN_pass_player_savedata(int32 *params);
int32 FN_send_event(int32 *params);
int32 FN_add_walkgrid(int32 *params);
int32 FN_remove_walkgrid(int32 *params);
int32 FN_check_for_event(int32 *params);
int32 FN_pause_for_event(int32 *params);
int32 FN_clear_event(int32 *params);
int32 FN_face_mega(int32 *params);
int32 FN_play_sequence(int32 *params);
int32 FN_shaded_sprite(int32 *params);
int32 FN_unshaded_sprite(int32 *params);
int32 FN_fade_up(int32 *params);
int32 FN_display_msg(int32 *params);
int32 FN_set_object_held(int32 *params);
int32 FN_add_sequence_text(int32 *params);
int32 FN_reset_globals(int32 *params);
int32 FN_set_palette(int32 *params);
int32 FN_register_pointer_text(int32 *params);
int32 FN_fetch_wait(int32 *params);
int32 FN_release(int32 *params);
int32 FN_sound_fetch(int32 *params);
int32 FN_prepare_music(int32 *params);
int32 FN_smacker_lead_in(int32 *params);
int32 FN_smacker_lead_out(int32 *params);
int32 FN_stop_all_fx(int32 *params);
int32 FN_check_player_activity(int32 *params);
int32 FN_reset_player_activity_delay(int32 *params);
int32 FN_check_music_playing(int32 *params);
int32 FN_play_credits(int32 *params);
int32 FN_set_scroll_speed_normal(int32 *params);
int32 FN_set_scroll_speed_slow(int32 *params);
int32 FN_remove_chooser(int32 *params);
int32 FN_set_fx_vol_and_pan(int32 *params);
int32 FN_set_fx_vol(int32 *params);
int32 FN_restore_game(int32 *params);
int32 FN_refresh_inventory(int32 *params);
int32 FN_change_shadows(int32 *params);
#define MAX_FN_NUMBER 117
extern int32 (*McodeTable[])(int32 *);
#ifndef INSIDE_LINC
int32 * globalInterpreterVariables2 = NULL; // Point to the global varibale data
int g_debugFlag = 0; // Set this to turn debugging on
#endif
int32 (*McodeTable[MAX_FN_NUMBER+1])(int32 *) =
{ FN_test_function,
FN_test_flags,
FN_register_start_point,
FN_init_background,
FN_set_session,
FN_back_sprite,
FN_sort_sprite,
FN_fore_sprite,
FN_register_mouse,
FN_anim,
FN_random,
FN_preload,
FN_add_subject,
FN_interact,
FN_choose,
FN_walk,
FN_walk_to_anim,
FN_turn,
FN_stand_at,
FN_stand,
FN_stand_after_anim,
FN_pause,
FN_mega_table_anim,
FN_add_menu_object,
FN_start_conversation,
FN_end_conversation,
FN_set_frame,
FN_random_pause,
FN_register_frame,
FN_no_sprite,
FN_send_sync,
FN_update_player_stats,
FN_pass_graph,
FN_init_floor_mouse,
FN_pass_mega,
FN_face_xy,
FN_end_session,
FN_no_human,
FN_add_human,
FN_we_wait,
FN_they_do_we_wait,
FN_they_do,
FN_walk_to_talk_to_mega,
FN_fade_down,
FN_i_speak,
FN_total_restart,
FN_set_walkgrid,
FN_speech_process,
FN_set_scaling,
FN_start_event,
FN_check_event_waiting,
FN_request_speech,
FN_gosub,
FN_timed_wait,
FN_play_fx,
FN_stop_fx,
FN_play_music,
FN_stop_music,
FN_set_value,
FN_new_script,
FN_get_sync,
FN_wait_sync,
FN_register_walkgrid,
FN_reverse_mega_table_anim,
FN_reverse_anim,
FN_add_to_kill_list,
FN_set_standby_coords,
FN_back_par0_sprite,
FN_back_par1_sprite,
FN_fore_par0_sprite,
FN_fore_par1_sprite,
FN_set_player_action_event,
FN_set_scroll_coordinate,
FN_stand_at_anim,
FN_set_scroll_left_mouse,
FN_set_scroll_right_mouse,
FN_colour,
FN_flash,
FN_prefetch,
FN_get_player_savedata,
FN_pass_player_savedata,
FN_send_event,
FN_add_walkgrid,
FN_remove_walkgrid,
FN_check_for_event,
FN_pause_for_event,
FN_clear_event,
FN_face_mega,
FN_play_sequence,
FN_shaded_sprite,
FN_unshaded_sprite,
FN_fade_up,
FN_display_msg,
FN_set_object_held,
FN_add_sequence_text,
FN_reset_globals,
FN_set_palette,
FN_register_pointer_text,
FN_fetch_wait,
FN_release,
FN_prepare_music,
FN_sound_fetch,
FN_prepare_music,
FN_smacker_lead_in,
FN_smacker_lead_out,
FN_stop_all_fx,
FN_check_player_activity,
FN_reset_player_activity_delay,
FN_check_music_playing,
FN_play_credits,
FN_set_scroll_speed_normal,
FN_set_scroll_speed_slow,
FN_remove_chooser,
FN_set_fx_vol_and_pan,
FN_set_fx_vol,
FN_restore_game,
FN_refresh_inventory,
FN_change_shadows,
};
#define CHECKSTACKPOINTER2 ASSERT((stackPointer2>=0)&&(stackPointer2<STACK_SIZE));
#define PUSHONSTACK(x) {stack2[stackPointer2] = (x);stackPointer2++;CHECKSTACKPOINTER2;}
#define POPOFFSTACK(x) {x=stack2[stackPointer2-1];stackPointer2--;CHECKSTACKPOINTER2;}
#define DOOPERATION(x) {stack2[stackPointer2-2] = (x);stackPointer2--;CHECKSTACKPOINTER2;}
#ifndef INSIDE_LINC
void SetGlobalInterpreterVariables(int32 *vars)
{
globalInterpreterVariables2 = vars;
}
#endif
#ifdef INSIDE_LINC // Are we running in linc?
int RunScript ( MCBOVirtualSword &engine , const char * scriptData , char * objectData , uint32 *offset )
#else
int RunScript ( const char * scriptData , char * objectData , uint32 *offset )
#endif
{
#define STACK_SIZE 10
_standardHeader *header = (_standardHeader *)scriptData;
scriptData += sizeof(_standardHeader) + sizeof(_object_hub);
// The script data format:
// int32_TYPE 1 Size of variable space in bytes
// ... The variable space
// int32_TYPE 1 numberOfScripts
// int32_TYPE numberOfScripts The offsets for each script
// Initialise some stuff
int ip = 0; // Code pointer
int curCommand,parameter,value; // Command and parameter variables
int32 stack2[STACK_SIZE]; // The current stack
int32 stackPointer2 = 0; // Position within stack
int parameterReturnedFromMcodeFunction=0; // Allow scripts to return things
int savedStartOfMcode; // For saving start of mcode commands
// Get the start of variables and start of code
DEBUG3("Enter interpreter data %x, object %x, offset %d",scriptData,objectData,*offset);
const char *variables = scriptData + sizeof(int);
const char *code = scriptData + *((int *)scriptData) + sizeof(int);
uint32 noScripts = *((int32 *)code);
if ( (*offset) < noScripts)
{ ip = ((int *)code)[(*offset)+1];
DEBUG2("Start script %d with offset %d",*offset,ip);
}
else
{ ip = (*offset);
DEBUG1("Start script with offset %d",ip);
}
code += noScripts * sizeof(int) + sizeof(int);
/************************************************************************************************/
#ifdef DONTPROCESSSCRIPTCHECKSUM
code += sizeof(int) * 3;
#else
// Code should nopw be pointing at an identifier and a checksum
int *checksumBlock = (int *)code;
code += sizeof(int) * 3;
if (checksumBlock[0] != 12345678)
{
#ifdef INSIDE_LINC
AfxMessageBox(CVString("Invalid script in object %s",header->name));
#else
Con_fatal_error("Invalid script in object %s",header->name);
#endif
return(0);
}
int codeLen = checksumBlock[1];
int checksum = 0;
for (int count = 0 ; count < codeLen ; count++)
checksum += (unsigned char)code[count];
if ( checksum != checksumBlock[2] )
{
#ifdef INSIDE_LINC
AfxMessageBox(CVString("Checksum error in script %s",header->name));
#else
Con_fatal_error("Checksum error in object %s",header->name);
#endif
return(0);
}
#endif //DONTPROCESSSCRIPTCHECKSUM
/************************************************************************************************/
int runningScript = 1;
while ( runningScript )
{ curCommand = code[ip++];
switch(curCommand)
{ case CP_END_SCRIPT: // 0 End the script
DEBUG1("End script",0);
runningScript = 0;
#ifdef INSIDE_LINC
engine.AddTextLine( "End script" , VS_COL_GREY );
engine.AddTextLine( "" , VS_COL_GREY );
#endif
break;
case CP_PUSH_LOCAL_VAR32: // 1 Push the contents of a local variable
Read16ip(parameter)
DEBUG2("Push local var %d (%d)",parameter,*((int *)(variables+parameter)));
PUSHONSTACK ( *((int *)(variables+parameter)) );
break;
case CP_PUSH_GLOBAL_VAR32: // 2 Push a global variable
Read16ip(parameter)
#ifdef INSIDE_LINC
DEBUG2("Push global var %d (%d)",parameter,g_GlobalVariables.GetLocalByIndex(parameter).GetValue());
PUSHONSTACK ( g_GlobalVariables.GetLocalByIndex(parameter).GetValue() );
#else
DEBUG2("Push global var %d (%d)",parameter,globalInterpreterVariables2[parameter]);
ASSERT(globalInterpreterVariables2);
PUSHONSTACK ( globalInterpreterVariables2[parameter] );
#endif
break;
case CP_POP_LOCAL_VAR32: // 3 Pop a value into a local word variable
Read16ip(parameter)
POPOFFSTACK ( value );
DEBUG2("Pop %d into var %d",value,parameter);
*((int *)(variables+parameter)) = value;
break;
case CP_CALL_MCODE: // 4 Call an mcode routine
{
Read16ip(parameter)
ASSERT(parameter <= MAX_FN_NUMBER);
value = *((int8 *)(code+ip)); // amount to adjust stack by (no of parameters)
ip ++;
DEBUG2("Call mcode %d with stack = %x",parameter,stack2+(stackPointer2-value));
#ifdef INSIDE_LINC
int retVal = engine.McodeTable(parameter , stack2+(stackPointer2-value));
#else
int retVal = McodeTable[parameter](stack2+(stackPointer2-value));
#endif
stackPointer2 -= value;
CHECKSTACKPOINTER2
switch ( retVal & 7 )
{ case IR_STOP: // 0: Quit out for a cycle
*offset = ip;
return(0);
case IR_CONT: // 1: // Continue as normal
break;
case IR_TERMINATE: // 2:
// Return without updating the offset
return(2);
case IR_REPEAT: // 3:
// Return setting offset to start of this function call
*offset = savedStartOfMcode;
return(0);
case IR_GOSUB: // 4: //that's really neat
*offset = ip;
return(2);
default:
ASSERT(FALSE);
}
parameterReturnedFromMcodeFunction = retVal >> 3;
}
break;
case CP_PUSH_LOCAL_ADDR: // 5 push the address of a local variable
Read16ip(parameter)
DEBUG2("Push address of local variable %d (%x)",parameter,(int32)(variables + parameter));
PUSHONSTACK ( (int32)(variables + parameter) );
break;
case CP_PUSH_INT32: // 6 Push a long word value on to the stack
Read32ip(parameter)
DEBUG2("Push int32 %d (%x)",parameter,parameter);
PUSHONSTACK ( parameter );
break;
case CP_SKIPONFALSE: // 7 Skip if the value on the stack is false
Read32ipLeaveip(parameter)
POPOFFSTACK ( value );
DEBUG2("Skip %d if %d is false",parameter,value);
if (value)
ip += sizeof(int32);
else
ip += parameter;
break;
case CP_SKIPALLWAYS: // 8 skip a block
Read32ipLeaveip(parameter)
DEBUG1("Skip %d",parameter);
ip += parameter;
break;
case CP_SWITCH: // 9 switch
{ POPOFFSTACK ( value );
int caseCount;
Read32ip(caseCount)
// Search the cases
int foundCase = 0;
for (int count = 0 ; (count < caseCount) && (!foundCase) ; count++)
{
if (value == *((int32 *)(code+ip)))
{ // We have found the case, so lets jump to it
foundCase = 1;
ip += *((int32 *)(code+ip+sizeof(int32)));
}
else
ip += sizeof(int32) * 2;
}
// If we found no matching case then use the default
if (!foundCase)
{
ip += *((int32 *)(code+ip));
}
}
break;
case CP_ADDNPOP_LOCAL_VAR32: // 10
Read16ip(parameter)
POPOFFSTACK ( value );
*((int *)(variables+parameter)) += value;
DEBUG3("+= %d into var %d->%d",value,parameter,*((int *)(variables+parameter)));
break;
case CP_SUBNPOP_LOCAL_VAR32: // 11
Read16ip(parameter)
POPOFFSTACK ( value );
*((int *)(variables+parameter)) -= value;
DEBUG3("-= %d into var %d->%d",value,parameter,*((int *)(variables+parameter)));
break;
case CP_SKIPONTRUE: // 12 Skip if the value on the stack is TRUE
Read32ipLeaveip(parameter)
POPOFFSTACK ( value );
DEBUG2("Skip %d if %d is false",parameter,value);
if (!value)
ip += sizeof(int32);
else
ip += parameter;
break;
case CP_POP_GLOBAL_VAR32: // 13 // Pop a global variable
Read16ip(parameter)
POPOFFSTACK ( value );
DEBUG2("Pop %d into global var %d",value,parameter);
#ifdef INSIDE_LINC
g_GlobalVariables.lclSet(parameter,value);
engine.AddTextLine(CVString( "Set variable %s to %d",
g_GlobalVariables.GetLocalByIndex(parameter).GetName(),
g_GlobalVariables.GetLocalByIndex(parameter).GetValue() ),
VS_COL_GREY);
#else //INSIDE_LINC
#ifdef TRACEGLOBALVARIABLESET
TRACEGLOBALVARIABLESET(parameter,value);
#endif
globalInterpreterVariables2[parameter] = value;
#endif
break;
case CP_ADDNPOP_GLOBAL_VAR32: // 14 Add and pop a global variable
{ Read16ip(parameter)
// parameter = *((int16_TYPE *)(code+ip));
// ip += 2;
POPOFFSTACK ( value );
#ifdef INSIDE_LINC
int newVal = g_GlobalVariables.GetLocalByIndex(parameter).GetValue() + value ;
g_GlobalVariables.lclSet(parameter, newVal );
engine.AddTextLine( CVString( "Set variable %s to %d",
g_GlobalVariables.GetLocalByIndex(parameter).GetName(),
g_GlobalVariables.GetLocalByIndex(parameter).GetValue() ),
VS_COL_GREY);
#else
globalInterpreterVariables2[parameter] += value;
DEBUG3("+= %d into global var %d->%d",value,parameter,*((int *)(variables+parameter)));
#endif
break;
}
case CP_SUBNPOP_GLOBAL_VAR32: // 15 Sub and pop a global variable
{ Read16ip(parameter)
// parameter = *((int16_TYPE *)(code+ip));
// ip += 2;
POPOFFSTACK ( value );
#ifdef INSIDE_LINC
int newVal = g_GlobalVariables.GetLocalByIndex(parameter).GetValue() - value ;
g_GlobalVariables.lclSet(parameter, newVal );
engine.AddTextLine( CVString( "Set variable %s to %d",
g_GlobalVariables.GetLocalByIndex(parameter).GetName(),
g_GlobalVariables.GetLocalByIndex(parameter).GetValue() ),
VS_COL_GREY);
#else
globalInterpreterVariables2[parameter] -= value;
DEBUG3("-= %d into global var %d->%d",value,parameter,*((int *)(variables+parameter)));
#endif
break;
}
case CP_DEBUGON:
// Turn debugging on
g_debugFlag = 1;
break;
case CP_DEBUGOFF:
// Turn debugging on
g_debugFlag = 0;
break;
case CP_QUIT:
#ifdef INSIDE_LINC
break;
#else
// Quit out for a cycle
*offset = ip;
return(0);
#endif
case CP_TERMINATE:
// Quit out immediately without affecting the offset pointer
return(3);
/******************************************************************************************************************
******************************************************************************************************************/
// Operators
case OP_ISEQUAL: // 20 // '=='
DEBUG3("%d == %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] == stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] == stack2[stackPointer2-1]) );
break;
case OP_PLUS: // 21 // '+'
DEBUG3("%d + %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] + stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] + stack2[stackPointer2-1]) );
break;
case OP_MINUS: // 22 // '+'
DEBUG3("%d - %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] - stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] - stack2[stackPointer2-1]) );
break;
case OP_TIMES: // 23 // '+'
DEBUG3("%d * %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] * stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] * stack2[stackPointer2-1]) );
break;
case OP_DEVIDE: // 24 // '+'
DEBUG3("%d / %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] / stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] / stack2[stackPointer2-1]) );
break;
case OP_NOTEQUAL: // 25 // '!='
DEBUG3("%d != %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] != stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] != stack2[stackPointer2-1]) );
break;
case OP_ANDAND: // 26
DEBUG3("%d != %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] && stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] && stack2[stackPointer2-1]) );
break;
case OP_GTTHAN: // 27 >
DEBUG3("%d > %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] > stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] > stack2[stackPointer2-1]) );
break;
case OP_LSTHAN: // 28 <
DEBUG3("%d < %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] < stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] < stack2[stackPointer2-1]) );
break;
case CP_JUMP_ON_RETURNED: // 29
{ // Jump to a part of the script depending on the return value from an mcode routine
parameter = *((int8 *)(code+ip)); // Get the maximum value
ip++;
#ifdef INSIDE_LINC
TRACE("ip %d: Parameter %d skip %d\r\n", ip,
parameterReturnedFromMcodeFunction,
((int32*)(code+ip))[parameterReturnedFromMcodeFunction] );
#endif
ip += ((int32 *)(code+ip))[parameterReturnedFromMcodeFunction];
}
break;
case CP_TEMP_TEXT_PROCESS: // 30
// Process a text line
Read32ip(parameter)
// parameter = *((int32_TYPE *)(code+ip));
// ip += sizeof(int32_TYPE);;
DEBUG1("Process text id %d",parameter);
#ifdef INSIDE_LINC
// Linc only for the moment
engine.ProcessTextLine(parameter);
#endif //INSIDE_LINC
break;
case CP_SAVE_MCODE_START: // 31
// Save the start position on an mcode instruction in case we need to restart it again
savedStartOfMcode = ip-1;
break;
case CP_RESTART_SCRIPT: // 32
{ // Start the script again
// Do a ip search to find the script we are running
const char *tempScrPtr = scriptData + *((int *)scriptData) + sizeof(int);
int scriptNumber = 0;
int foundScript = 0;
uint32 count = 0;
for (count = 1 ; (count < noScripts) && (!foundScript) ; count++)
{ if (ip < ((int *)tempScrPtr)[count+1])
{ scriptNumber = count - 1 ;
foundScript = 1;
}
}
if (!foundScript)
scriptNumber = count - 1 ;
// So we know what script we are running, lets restart it
ip = ((int *)tempScrPtr)[scriptNumber+1];
break;
}
case CP_PUSH_STRING: // 33
{ // Push the address of a string on to the stack
parameter = *((int8 *)(code+ip)); // Get the string size
ip += 1;
// ip points to the string
PUSHONSTACK( (int)(code+ip) );
ip += (parameter+1);
break;
}
case CP_PUSH_DEREFERENCED_STRUCTURE: // 34
{ // Push the address of a dereferenced structure
Read32ip(parameter)
DEBUG1("Push address of far variable (%x)",(int32)(variables + parameter));
PUSHONSTACK( (int)(objectData + sizeof(int) + sizeof(_standardHeader) + sizeof(_object_hub) + parameter));
break;
}
case OP_GTTHANE: // 35 >=
DEBUG3("%d > %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] >= stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] >= stack2[stackPointer2-1]) );
break;
case OP_LSTHANE: // 36 <=
DEBUG3("%d < %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] <= stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] <= stack2[stackPointer2-1]) );
break;
case OP_OROR: // 37
DEBUG3("%d || %d -> %d", stack2[stackPointer2-2],
stack2[stackPointer2-1],
stack2[stackPointer2-2] || stack2[stackPointer2-1]);
DOOPERATION ( (stack2[stackPointer2-2] || stack2[stackPointer2-1]) );
break;
default:
#ifdef INSIDE_LINC
AfxMessageBox(CVString("Invalid interpreter token %d",curCommand));
#else
Con_fatal_error("Interpreter error: Invalid token %d", curCommand);
#endif
return(3);
}
}
return(1);
}

173
sword2/interpreter.h Normal file
View file

@ -0,0 +1,173 @@
/* 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$
*/
// Interpreter return codes
#define IR_STOP 0
#define IR_CONT 1
#define IR_TERMINATE 2
#define IR_REPEAT 3
#define IR_GOSUB 4
#ifdef INSIDE_LINC // Are we running in linc?
extern int g_debugFlag;
#ifdef _DEBUG
#define DEBUG1(x,y) if(g_debugFlag){engine.AddTextLine(CVString(x,y),VS_COL_DEBUG);}
#define DEBUG2(x,y,z) if(g_debugFlag){engine.AddTextLine(CVString(x,y,z),VS_COL_DEBUG);}
#define DEBUG3(x,y,z,a) if(g_debugFlag){engine.AddTextLine(CVString(x,y,z,a),VS_COL_DEBUG);}
#else //_DEBUG
#define DEBUG1
#define DEBUG2
#define DEBUG3
#endif //_DEBUG
#else //INSIDE_LINC
//#include "src\driver96.h"
#include "debug.h"
#include "header.h"
#define DEBUG1 if(g_debugFlag)Zdebug
#define DEBUG2 if(g_debugFlag)Zdebug
#define DEBUG3 if(g_debugFlag)Zdebug
#define ASSERT(x) {if(!(x)){Zdebug("Interpreter ASSERT %s,%d",__FILE__,__LINE__);Con_fatal_error("Assert error in interpreter");}}
#endif
// Get parameter fix so that the playstation version can handle words not on word boundaries
#define Read16ip(var) {var = *((int16 *)(code+ip));ip+=sizeof(int16);}
#define Read32ip(var) {var = *((int32 *)(code+ip));ip+=sizeof(int32);}
#define Read32ipLeaveip(var) {var = *((int32 *)(code+ip));}
void SetGlobalInterpreterVariables(int32 *vars);
#ifdef INSIDE_LINC // Are we running in linc?
int RunScript ( MCBOVirtualSword &engine , const char * scriptData , char * /*objectData*/ , uint32 *offset );
#else
int RunScript ( const char * scriptData , char * /*objectData*/ , uint32 *offset );
#endif
// Command tokens
#define CT_COMMENT 1 // A program comment
#define CT_IF 2 // An if statement
#define CT_OPENBRACKET 3 // (
#define CT_CLOSEBRACKET 4 // )
#define CT_VAR 5 // Define a variable
#define CT_SEMICOLON 6 // ;
#define CT_COMMA 7 // ,
#define CT_OPENBRACE 8 // {
#define CT_CLOSEBRACE 9 // }
#define CT_STRUCT 10 // Struct
#define CT_SWITCH 11 // Switch
#define CT_CASE 12 // Case
#define CT_BREAK 13 // break
#define CT_DEFAULT 14 // default
#define CT_ASSIGN 14 // =
#define CT_PLUSEQ 15 // '+='
#define CT_MINUSEQ 16 // '-='
#define CT_FOR 17 // for
#define CT_DO 18 // do
#define CT_WHILE 19 // while
#define CT_DEBUGON 20 // Turn debugging on
#define CT_DEBUGOFF 21 // Turn debugging off
#define CT_QUIT 22 // Quit for a cycle
#define CT_ENDIF 23 // Endif
#define CT_TEXTOBJECT 24 // Speaker: text line
#define CT_ANIM 25 // An animation
#define CT_ELSE 26 // else to an if
#define CT_CHOOSE 27 // Start a chooser
#define CT_END 28 // end, usually followed by something else
#define CT_END_CHOICE 29 // end choice
#define CT_TERMINATE 30 // Terminate
#define CT_PAUSE 31 // Pause
#define CT_RESTART 32 // Restart script
#define CT_START 33 // Start conversation
#define CT_CALL 34 // Call a character
#define CT_ACTORSCOMMENT 35 // A comment for an actor
#define CT_TALKER 36 // A set talker command
// Special functions
#define SF_RUNLIST 1
#define SF_DOUBLEQUOTE 2
#define SF_BACKGROUND 3
#define SF_SCALEA 4
#define SF_SCALEB 5
#define SF_SPEECHSCRIPT 6
// Compiled tokens
#define CP_END_SCRIPT 0
#define CP_PUSH_LOCAL_VAR32 1 // Push a local variable on to the stack
#define CP_PUSH_GLOBAL_VAR32 2 // Push a global variable
#define CP_POP_LOCAL_VAR32 3 // Pop a local variable from the stack
#define CP_CALL_MCODE 4 // Call a machine code function
#define CP_PUSH_LOCAL_ADDR 5 // Push the address of a local variable
#define CP_PUSH_INT32 6 // Adjust the stack after calling an fn function
#define CP_SKIPONFALSE 7 // Skip if the bottom value on the stack is false
#define CP_SKIPALLWAYS 8 // Skip a block of code
#define CP_SWITCH 9 // Switch on last stack value
#define CP_ADDNPOP_LOCAL_VAR32 10 // Add to a local varible
#define CP_SUBNPOP_LOCAL_VAR32 11 // Subtract to a local variable
#define CP_SKIPONTRUE 12 // Skip if the bottom value on the stack is true
#define CP_POP_GLOBAL_VAR32 13 // Pop a global variable
#define CP_ADDNPOP_GLOBAL_VAR32 14
#define CP_SUBNPOP_GLOBAL_VAR32 15
#define CP_DEBUGON 16 // Turn debugging on
#define CP_DEBUGOFF 17 // Turn debugging off
#define CP_QUIT 18 // Quit for a cycle
#define CP_TERMINATE 19 // Quit script completely
// Operators
#define OP_ISEQUAL 20 // '=='
#define OP_PLUS 21 // '+'
#define OP_MINUS 22 // '-'
#define OP_TIMES 23 // '*'
#define OP_DEVIDE 24 // '/'
#define OP_NOTEQUAL 25 // '=='
#define OP_ANDAND 26 // &&
#define OP_GTTHAN 27 // >
#define OP_LSTHAN 28 // <
// More tokens, mixed types
#define CP_JUMP_ON_RETURNED 29 // Use table of jumps with value returned from fn_mcode
#define CP_TEMP_TEXT_PROCESS 30 // A dummy text process command for me
#define CP_SAVE_MCODE_START 31 // Save the mcode code start for restarting when necessary
#define CP_RESTART_SCRIPT 32 // Start the script from the beginning
#define CP_PUSH_STRING 33 // Push a pointer to a string on the stack
#define CP_PUSH_DEREFERENCED_STRUCTURE 34 // Push the address of a structure thing
#define OP_GTTHANE 35 // >=
#define OP_LSTHANE 36 // <=
#define OP_OROR 37 // || or OR

297
sword2/layers.cpp Normal file
View file

@ -0,0 +1,297 @@
/* 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$
*/
//------------------------------------------------------------------------------------
//high level layer initialising
//the system supports:
// 1 optional background parallax layer
// 1 not optional normal backdrop layer
// 3 normal sorted layers
// up to 2 foreground parallax layers
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "driver/driver96.h"
#include "build_display.h"
#include "console.h"
#include "debug.h"
#include "header.h"
#include "layers.h"
#include "memory.h"
#include "object.h"
#include "protocol.h"
#include "resman.h"
#include "sound.h" // (James22july97) for Clear_fx_queue() called from FN_init_background()
//------------------------------------------------------------------------------------
screen_info this_screen; //this_screen describes the current back buffer and its in-game scroll positions, etc.
//------------------------------------------------------------------------------------
int32 FN_init_background(int32 *params) //Tony11Sept96
{
//param 0 res id of normal background layer - cannot be 0
//param 1 1 yes 0 no for a new palette
//this screen defines the size of the back buffer
_multiScreenHeader *screenLayerTable; // James 06feb97
_screenHeader *screen_head;
_layerHeader *layer;
_spriteInfo spriteInfo;
uint32 j;
uint8 *file;
uint32 rv;
//--------------------------------------
// Write to walkthrough file (zebug0.txt)
#ifdef _DEBUG
Zdebug(0,"=====================================");
Zdebug(0,"CHANGED TO LOCATION \"%s\"", FetchObjectName(*params));
Zdebug(0,"=====================================");
// Also write this to system debug file
Zdebug("=====================================");
Zdebug("CHANGED TO LOCATION \"%s\"", FetchObjectName(*params));
Zdebug("=====================================");
#endif
//--------------------------------------
Clear_fx_queue(); // stops all fx & clears the queue (James22july97)
#ifdef _DEBUG
Zdebug("FN_init_background(%d)", *params);
if (!*params)
{
Con_fatal_error("ERROR: FN_set_background cannot have 0 for background layer id! (%s line=%u)",__FILE__,__LINE__);
}
#endif // _DEBUG
//-------------------------------------------------------
// if the screen is still fading down then wait for black
do
{
ServiceWindows();
}
while(GetFadeStatus()==RDFADE_DOWN);
//-------------------------------------------------------
if (this_screen.mask_flag) // if last screen was using a shading mask (see below) (James 08apr97)
{
rv = CloseLightMask();
if (rv)
ExitWithReport("Driver Error %.8x [%s line %u]", rv, __FILE__, __LINE__);
}
//--------------------------------------------------------
// New stuff for faster screen drivers (James 06feb97)
if (this_screen.background_layer_id) // for drivers: close the previous screen if one is open
CloseBackgroundLayer();
//--------------------------------------------------------
this_screen.background_layer_id=*params; //set the res id
this_screen.new_palette = *(params+1); //yes or no - palette is taken from layer file
//ok, now read the resource and pull out all the normal sort layer info
//and set them up at the beginning of the sort list - why do it each cycle
file = res_man.Res_open(this_screen.background_layer_id); //file points to 1st byte in the layer file
screen_head = FetchScreenHeader(file);
this_screen.number_of_layers= screen_head->noLayers; //set number of special sort layers
this_screen.screen_wide = screen_head->width;
this_screen.screen_deep = screen_head->height;
Zdebug("res test layers=%d width=%d depth=%d", screen_head->noLayers, screen_head->width, screen_head->height);
SetLocationMetrics(screen_head->width, screen_head->height); //initialise the driver back buffer
if (screen_head->noLayers)
for (j=0;j<screen_head->noLayers;j++)
{
layer=FetchLayerHeader(file,j); //get layer header for layer j
// add into the sort list
sort_list[j].sort_y = layer->y+layer->height; //need this for sorting - but leave the rest blank, we'll take from the header at print time
sort_list[j].layer_number=j+1; //signifies a layer
Zdebug("init layer %d", j);
}
//using the screen size setup the scrolling variables
if( ((screen_head->width) > screenWide) || (screen_head->height>screenDeep) ) // if layer is larger than physical screen
{
this_screen.scroll_flag = 2; //switch on scrolling (2 means first time on screen)
// note, if we've already set the player up then we could do the initial scroll set here
this_screen.scroll_offset_x = 0; //reset scroll offsets
this_screen.scroll_offset_y = 0;
// calc max allowed offsets (to prevent scrolling off edge) - MOVE TO NEW_SCREEN in GTM_CORE.C !!
this_screen.max_scroll_offset_x = screen_head->width-screenWide; // NB. min scroll offsets are both zero
this_screen.max_scroll_offset_y = screen_head->height-(screenDeep-(RDMENU_MENUDEEP*2)); // 'screenDeep' includes the menu's, so take away 80 pixels
}
else //layer fits on physical screen - scrolling not required
{
this_screen.scroll_flag = 0; //switch off scrolling
this_screen.scroll_offset_x = 0; //reset scroll offsets
this_screen.scroll_offset_y = 0;
}
ResetRenderEngine(); //no inter-cycle scrol between new screens (see setScrollTarget in build display)
// these are the physical screen coords where the system
// will try to maintain George's actual feet coords
this_screen.feet_x=320;
this_screen.feet_y=340;
//----------------------------------------------------
// shading mask
screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
if (screenLayerTable->maskOffset)
{
spriteInfo.x = 0;
spriteInfo.y = 0;
spriteInfo.w = screen_head->width;
spriteInfo.h = screen_head->height;
spriteInfo.scale = 0;
spriteInfo.scaledWidth = 0;
spriteInfo.scaledHeight = 0;
spriteInfo.type = 0;
spriteInfo.blend = 0;
spriteInfo.data = FetchShadingMask(file);
spriteInfo.colourTable = 0;
rv = OpenLightMask( &spriteInfo );
if (rv)
ExitWithReport("Driver Error %.8x [%s line %u]", rv, __FILE__, __LINE__);
this_screen.mask_flag=1; // so we know to close it later! (see above)
}
else
this_screen.mask_flag=0; // no need to close a mask later
//----------------------------------------------------
res_man.Res_close(this_screen.background_layer_id); //close the screen file
SetUpBackgroundLayers();
Zdebug("end init");
return(1);
}
//------------------------------------------------------------------------------------
// called from FN_init_background & also from control panel
void SetUpBackgroundLayers(void) // James(13jun97)
{
_multiScreenHeader *screenLayerTable; // James 06feb97
_screenHeader *screen_head;
uint8 *file;
if (this_screen.background_layer_id) // if we actually have a screen to initialise (in case called from control panel)
{
//------------------------------
// open resource & set pointers to headers
file = res_man.Res_open(this_screen.background_layer_id); //file points to 1st byte in the layer file
screen_head = FetchScreenHeader(file);
screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
//------------------------------
// first background parallax
if (screenLayerTable->bg_parallax[0])
InitialiseBackgroundLayer(FetchBackgroundParallaxLayer(file,0));
else
InitialiseBackgroundLayer(NULL);
//------------------------------
// second background parallax
if (screenLayerTable->bg_parallax[1])
InitialiseBackgroundLayer(FetchBackgroundParallaxLayer(file,1));
else
InitialiseBackgroundLayer(NULL);
//------------------------------
// normal backround layer
InitialiseBackgroundLayer(FetchBackgroundLayer(file));
//------------------------------
// first foreground parallax
if (screenLayerTable->fg_parallax[0])
InitialiseBackgroundLayer(FetchForegroundParallaxLayer(file,0));
else
InitialiseBackgroundLayer(NULL);
//------------------------------
// second foreground parallax
if (screenLayerTable->fg_parallax[1])
InitialiseBackgroundLayer(FetchForegroundParallaxLayer(file,1));
else
InitialiseBackgroundLayer(NULL);
//----------------------------------------------------
res_man.Res_close(this_screen.background_layer_id); //close the screen file
//----------------------------------------------------
}
else // no current screen to initialise! (In case called from control panel)
{
}
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

61
sword2/layers.h Normal file
View file

@ -0,0 +1,61 @@
/* 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$
*/
#ifndef _LAYERS
#define _LAYERS
//#include "src\driver96.h"
#include "memory.h"
typedef struct
{
uint16 scroll_offset_x; // position x
uint16 scroll_offset_y; // position y
uint16 max_scroll_offset_x; // calc'ed in FN_init_background
uint16 max_scroll_offset_y; //
int16 player_feet_x; // feet coordinates to use - cant just fetch the player compact anymore
int16 player_feet_y;
int16 feet_x; // special offset-to-player position - tweek as desired - always set in screen manager object startup
int16 feet_y;
uint16 screen_wide; // size of background layer - hense size of back buffer itself (Paul actually malloc's it)
uint16 screen_deep;
uint32 background_layer_id; //id of the normal background layer
uint16 number_of_layers; // from the header of the main background layer
uint8 new_palette; // set to non zero to start the palette held within layer file fading up after a build_display
uint8 scroll_flag; // scroll mode 0 off 1 on
uint8 mask_flag; // using shading mask
} screen_info;
extern screen_info this_screen;
int32 FN_init_background(int32 *params); // Tony11Sept96
void SetUpBackgroundLayers(void); // James(13jun97) called from control panel (as well as inside FN_init_background)
#endif

441
sword2/logic.cpp Normal file
View file

@ -0,0 +1,441 @@
/* 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$
*/
//------------------------------------------------------------------------------------
// #include <libsn.h> PSX?
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
//#include "src\driver96.h"
#include "build_display.h"
#include "console.h"
#include "debug.h"
#include "header.h"
#include "interpreter.h"
#include "logic.h"
#include "memory.h"
#include "resman.h"
#include "router.h" // for ClearWalkGridList()
#include "sound.h"
#include "sword2.h" // (James19aug97) for CloseGame()
#include "sync.h"
//------------------------------------------------------------------------------------
logic LLogic; //declare the object
#define LEVEL cur_object_hub->logic_level
#define OBJECT_KILL_LIST_SIZE 50 // this must allow for the largest number of objects in a screen
uint32 object_kill_list[OBJECT_KILL_LIST_SIZE];
uint32 kills=0; // keeps note of no. of objects in the kill list
//------------------------------------------------------------------------------------
int logic::Process_session(void) //Tony6June96 (first run 21Oct96)
{
//do one cycle of the current session
uint32 run_list;
uint32 ret,script;
uint32 *game_object_list;
char *raw_script_ad;
char *raw_data_ad;
uint32 null_pc;
_standardHeader *head;
_standardHeader *far_head;
uint32 id;
run_list=current_run_list; //might change during the session, so take a copy here
pc=0; //point to first object in list
static uint32 cycle=0;
cycle++;
// Zdebug("\n CYCLE %d", cycle);
while(pc!=0xffffffff) //by minusing the pc we can cause an immediate cessation of logic processing on the current list
{
head = (_standardHeader*) res_man.Res_open(run_list);
if (head->fileType!=RUN_LIST)
Con_fatal_error("Logic_engine %d not a run_list", run_list);
game_object_list = (uint32 *) (head+1);
ID = game_object_list[pc++]; //read the next id
id=ID;
res_man.Res_close(run_list); //release the list again so it can float in memory - at this point not one thing should be locked
// Zdebug("%d", ID);
if (!ID) //null terminated
return(0); //end the session naturally
head = (_standardHeader*) res_man.Res_open(ID);
if (head->fileType!=GAME_OBJECT)
Con_fatal_error("Logic_engine %d not an object", ID);
cur_object_hub = (_object_hub *) (head+1);
// Zdebug(" %d id(%d) pc(%d)", cur_object_hub->logic_level, cur_object_hub->script_id[cur_object_hub->logic_level], cur_object_hub->script_pc[cur_object_hub->logic_level]);
// do the logic for this object
// we keep going until a function says to stop - remember, system operations are run via function calls to drivers now
do
{
script = cur_object_hub->script_id[LEVEL]; //get the script id as we may be running a script from another object...
// there is a distinction between running one of our own scripts and that of another object
if ((script/SIZE)==ID) //its our script
{
// Zdebug("run script %d pc%d", script/SIZE, cur_object_hub->script_pc[LEVEL]);
// raw_script_ad = (char *) (cur_object_hub+1); //this is the script data
raw_script_ad = (char*) head;
ret=RunScript( raw_script_ad, raw_script_ad, &cur_object_hub->script_pc[LEVEL] ); //script and data object are us/same
}
else //we're running the script of another game object - get our data object address
{
// get the foreign objects script data address
raw_data_ad=(char*)head;
far_head = (_standardHeader*) res_man.Res_open(script/SIZE);
if ((far_head->fileType!=GAME_OBJECT)&&((far_head->fileType!=SCREEN_MANAGER)))
Con_fatal_error("Logic_engine %d not a far object (its a %d)", script/SIZE, far_head->fileType);
// raw_script_ad = (char*) (head+1) + sizeof(_standardHeader);
// get our objects data address
// raw_data_ad = (char*) (cur_object_hub+1);
raw_script_ad=(char*)far_head;
ret=RunScript( raw_script_ad, raw_data_ad, &cur_object_hub->script_pc[LEVEL] );
res_man.Res_close(script/SIZE); //close foreign object again
raw_script_ad=raw_data_ad; //reset to us for service script
}
if (ret==1) //this script has finished - drop down a level
{
if (cur_object_hub->logic_level) //check that it's not already on level 0 !
cur_object_hub->logic_level--;
else //Hmmm, level 0 terminated :-| Let's be different this time and simply let it restart next go :-)
{
cur_object_hub->script_pc[LEVEL]=(cur_object_hub->script_id[LEVEL]&0xffff); //reset to rerun
// Zdebug("**WARNING object %d script 0 terminated!", id);
ret=0; //cause us to drop out for a cycle
}
}
else if (ret>2)
{
Con_fatal_error("Process_session: illegal script return type %d (%s line %u)",ret,__FILE__,__LINE__);
}
// if ret==2 then we simply go around again - a new script or subroutine will kick in and run
}
while(ret); //keep processing scripts until 0 for quit is returned
// any post logic system requests to go here
Clear_syncs(ID); //clear any syncs that were waiting for this character - it has used them or now looses them
if (pc!=0xffffffff) //the session is still valid so run the service script
{ null_pc=0;
RunScript( raw_script_ad, raw_script_ad, &null_pc ); //call the base script - this is the graphic/mouse service call
}
//made for all live objects
// and that's it so close the object resource
res_man.Res_close(ID);
};
Process_kill_list(); //leaving a room so remove all ids that must reboot correctly
Zdebug("RESTART the loop");
return(1); //means restart the loop
}
//------------------------------------------------------------------------------------
void logic::Express_change_session(uint32 sesh_id) //Tony6June96
{
//a game-object can bring an immediate halt to the session and cause a new one to start without a screen update
current_run_list=sesh_id; //set to new
pc=0xffffffff; //causes session to quit
EXIT_FADING=0; // reset now in case we double-clicked an exit prior to changing screen
Init_sync_system(); // we're trashing the list - presumably to change room
// in theory sync waiting in the list could be left behind and never removed - so we trash the lot
ClearWalkGridList(); // reset walkgrid list (see FN_register_walkgrid)
Clear_fx_queue(); // stops all fx & clears the queue
FreeAllRouteMem(); // free all the route memory blocks from previous game
}
//------------------------------------------------------------------------------------
void logic::Natural_change_session(uint32 sesh_id) //Tony7June96
{
//a new session will begin next game cycle.
//the current cycle will conclude and build the screen and flip into view as normal
current_run_list=sesh_id; //set to new
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
uint32 logic::Return_run_list(void) //Tony18Sept96
{
//pass back the private cur_object_list variable - not sure we need this
return(current_run_list); //return the id
}
//------------------------------------------------------------------------------------
int32 FN_set_session(int32 *params) //Tony29Oct96
{
//used by player invoked start scripts
//param 0 id of new run list
LLogic.Express_change_session(*params); //now!
return(IR_CONT); //cont
}
//------------------------------------------------------------------------------------
int32 FN_end_session(int32 *params) //Tony21Sept96
{
//causes no more objects in this logic loop to be processed
//the logic engine will restart at the beginning of the new list
// !!the current screen will not be drawn!!
//param 0 id of new run-list
LLogic.Express_change_session(*params); //terminate current and change to next run-list
return(0); //stop the script - logic engine will now go around and the new screen will begin
}
//------------------------------------------------------------------------------------
void logic::Logic_up(uint32 new_script) //Tony23Sept96
{
//move the current object up a level
//called by FN_gosub command - remember, only the logic object has access to cur_object_hub
cur_object_hub->logic_level++; //going up a level - and we'll keeping going this cycle
if (cur_object_hub->logic_level==3) //can be 0,1,2
Con_fatal_error("Logic_up id %d has run off script tree! :-O", ID);
cur_object_hub->script_id[cur_object_hub->logic_level]=new_script; //setup new script on next level (not the current level)
cur_object_hub->script_pc[cur_object_hub->logic_level]=new_script&0xffff;
//Zdebug("new pc = %d", new_script&0xffff);
}
//------------------------------------------------------------------------------------
void logic::Logic_one(uint32 new_script) //Tony4Dec96
{
//force to level one
cur_object_hub->logic_level=1;
cur_object_hub->script_id[1]=new_script; //setup new script on level 1
cur_object_hub->script_pc[1]=new_script&0xffff;
}
//------------------------------------------------------------------------------------
void logic::Logic_replace(uint32 new_script) //Tony13Nov96
{
//change current logic - script must quit with a TERMINATE directive - which does not write to &pc
cur_object_hub->script_id[cur_object_hub->logic_level]=new_script; //setup new script on this level
cur_object_hub->script_pc[cur_object_hub->logic_level]=new_script&0xffff;
}
//------------------------------------------------------------------------------------
uint32 logic::Examine_run_list(void) //Tony25Oct96
{
uint32 *game_object_list;
_standardHeader *file_header;
int scrolls=0;
char c;
if (current_run_list)
{
game_object_list = (uint32 *) (res_man.Res_open(current_run_list)+sizeof(_standardHeader)); //open and lock in place
Print_to_console("runlist number %d", current_run_list);
while(*(game_object_list))
{
file_header = (_standardHeader*) res_man.Res_open(*(game_object_list));
Print_to_console(" %d %s",*(game_object_list), file_header->name);
res_man.Res_close(*(game_object_list++));
scrolls++;
Build_display();
if (scrolls==18)
{
Temp_print_to_console("- Press ESC to stop or any other key to continue");
Build_display();
do
{
//--------------------------------------------------
// Service windows
while (!gotTheFocus)
if (ServiceWindows() == RDERR_APPCLOSED)
break;
if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
{
Close_game(); //close engine systems down
RestoreDisplay();
CloseAppWindow();
exit(0); //quit the game
}
//--------------------------------------------------
}
while(!KeyWaiting());
ReadKey(&c); //kill the key we just pressed
if (c==27) //ESC
break;
Clear_console_line(); //clear the Press Esc message ready for the new line
scrolls=0;
}
}
res_man.Res_close(current_run_list);
}
else Print_to_console("no run list set");
Scroll_console();
return(1);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
void logic::Total_restart(void) //Tony18Sept96
{
//reset the object restart script 1 on level 0
cur_object_hub->logic_level=0;
//cur_object_hub->script_id[0]=1;
cur_object_hub->script_pc[0]=1; //reset to rerun
}
//------------------------------------------------------------------------------------
int32 FN_total_restart(int32 *params) //Tony5Dec96
{
//mega runs this to restart its base logic again - like being cached in again
LLogic.Total_restart();
if (params);
return(IR_TERMINATE); //drop out without saving pc and go around again
}
//------------------------------------------------------------------------------------
int32 FN_add_to_kill_list(int32 *params) //James9jan97
{
// call *once* from object's logic script - ie. in startup code
// - so not re-called every time script drops off & restarts!
// mark this object for killing - to be killed when player leaves this screen
// - so object reloads & script restarts upon re-entry to screen
// - causes this object's startup logic to be re-run every time we enter the screen
// - "which is nice"
// params: none
uint32 entry;
if (ID != 8) // DON'T EVER KILL GEORGE!
{
// first, scan list to see if this object is already included (05mar97 James)
entry=0;
while ((entry < kills) && (object_kill_list[entry] != ID))
entry++;
if (entry == kills) // if this ID isn't already in the list, then add it, (otherwise finish) (05mar97 James)
{
#ifdef _DEBUG
if (kills == OBJECT_KILL_LIST_SIZE) // no room at the inn
Con_fatal_error("List full in FN_add_to_kill_list(%u) (%s line %u)",ID,__FILE__,__LINE__);
#endif
object_kill_list[kills] = ID; // add this 'ID' to the kill list
kills++; // "another one bites the dust"
// when we leave the screen, all these object resources are to be cleaned out of memory
// and the kill list emptied by doing 'kills=0'
// - ensuring that all resources are in fact still in memory & more importantly closed
// before killing!
}
}
return(IR_CONT); // continue script
}
//------------------------------------------------------------------------------------
void logic::Process_kill_list(void) //Tony10Jan97
{
uint32 j;
if (kills)
for (j=0;j<kills;j++)
res_man.Remove_res(object_kill_list[j]);
kills=0;
}
//------------------------------------------------------------------------------------
void logic::Reset_kill_list(void) //James 25mar97
{
kills=0;
}
//------------------------------------------------------------------------------------

62
sword2/logic.h Normal file
View file

@ -0,0 +1,62 @@
/* 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$
*/
//logic management
#ifndef _LOGIC
#define _LOGIC
//#include "src\driver96.h"
#include "defs.h"
#include "header.h"
#define TREE_SIZE 3
class logic
{
public:
int Process_session(void); //do one cycle of the current session
void Express_change_session(uint32 sesh_id); //cause the logic loop to terminate and drop out
void Natural_change_session(uint32 sesh_id); //new logic begins next cycle
uint32 Return_run_list(void);
void Logic_up(uint32 new_script); //setup script_id and script_pc in cur_object_hub - called by FN_gosub()
void Logic_replace(uint32 new_script);
void Logic_one(uint32 new_script);
void Total_restart(void);
uint32 Examine_run_list(void);
void Reset_kill_list(void); //James 25mar97
private:
uint32 current_run_list; //denotes the res id of the game-object-list in current use
void Process_kill_list(void);
uint32 pc; //pc during logic loop
_object_hub *cur_object_hub; //each object has one of these tacked onto the beginning
};
extern logic LLogic;
int32 FN_add_to_kill_list(int32 *params); //James9jan97
#endif

694
sword2/maketext.cpp Normal file
View file

@ -0,0 +1,694 @@
/* 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$
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// MAKETEXT - Constructs a single-frame text sprite: returns a handle to a
// FLOATING memory block containing the sprite, given a
// null-terminated string, max width allowed, pen colour and
// pointer to required character set.
//
// NB 1) The routine does not create a standard file header or
// an anim header for the text sprite - the data simply begins
// with the frame header.
//
// NB 2) If pen colour is zero, it copies the characters into the
// sprite without remapping the colours.
// ie. It can handle both the standard 2-colour font for speech
// and any multicoloured fonts for control panels, etc.
//
// Based on textsprt.c as used for Broken Sword 1, but updated for new system
// by JEL on 9oct96 and updated again (for font as a resource) on 5dec96.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define MAX_LINES 30 // max character lines in output sprite
#define BORDER_COL 200 // source colour for character border (only needed for remapping colours)
#define LETTER_COL 193 // source colour for bulk of character ( " )
#define BORDER_PEN 194 // output colour for character border - should be black ( " ) but note that we have to use a different pen number during sequences
#define NO_COL 0 // sprite background - 0 for transparency!
#define SPACE ' '
#define FIRST_CHAR SPACE // first character in character set
#define LAST_CHAR 255 // last character in character set
#define DUD 64 // the first "chequered flag" (dud) symbol in our character set is in the '@' position
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "driver/driver96.h"
#include "console.h"
#include "debug.h"
#include "defs.h" // for SPEECH_FONT_ID & CONSOLE_FONT_ID
#include "header.h"
#include "maketext.h"
#include "memory.h"
#include "protocol.h" // for FetchFrameHeader()
#include "resman.h"
extern uint32 sequenceTextLines; // see anims.cpp
//-----------------------------------------------------------------------------
typedef struct // info for each line of words in the output text sprite
{
uint16 width; // width of line in pixels
uint16 length; // length of line in characters
} _lineInfo;
//-----------------------------------------------------------------------------
// PROTOTYPES
uint16 AnalyseSentence( uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineInfo *line );
mem* BuildTextSprite( uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line, uint16 noOfLines );
uint16 CharWidth( uint8 ch, uint32 fontRes );
uint16 CharHeight( uint32 fontRes );
_frameHeader* FindChar( uint8 ch, uint8 *charSet );
void CopyChar( _frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8 pen );
//-----------------------------------------------------------------------------
// global layout variables - these used to be defines, but now we're dealing with 2 character sets (10dec96 JEL)
int8 line_spacing; // no. of pixels to separate lines of characters in the output sprite - negative for overlap
int8 char_spacing; // no. of pixels to separate characters along each line - negative for overlap
uint8 border_pen; // output pen colour of character borders
//-----------------------------------------------------------------------------
// Global font resource id variables, set up in 'SetUpFontResources()' at bottom of this file
uint32 speech_font_id;
uint32 controls_font_id;
uint32 red_font_id;
uint32 death_font_id;
//-----------------------------------------------------------------------------
mem* MakeTextSprite( uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes )
{
mem *line; // handle for the memory block which will contain the array of lineInfo structures
mem *textSprite; // handle for the block to contain the text sprite itself
uint16 noOfLines; // no of lines of text required to fit within a sprite of width 'maxWidth' pixels
// Zdebug("MakeTextSprite( \"%s\", maxWidth=%u )", sentence, maxWidth );
/////////////////////////////////////////////////////////////////////////////
// NB. ensure sentence contains no leading/tailing/extra spaces
// - if necessary, copy to another array first, missing the extra spaces.
/////////////////////////////////////////////////////////////////////////////
//----------------------------------------------
// set the global layout variables (10dec96 JEL)
if (fontRes == speech_font_id)
{
line_spacing = -6; // overlap lines by 6 pixels
char_spacing = -3; // overlap characters by 3 pixels
}
else if (fontRes == CONSOLE_FONT_ID)
{
line_spacing = 0; // no space or overlap between lines
char_spacing = 1; // 1 pixel spacing between each character
}
else
{
line_spacing = 0;
char_spacing = 0;
}
if (sequenceTextLines) // if rendering text over a sequence
border_pen = 1; // need a different colour number to BORDER_PEN
else
border_pen = BORDER_PEN;
//----------------------------------------------
// allocate memory for array of lineInfo structures
line = Twalloc( MAX_LINES*sizeof(_lineInfo), MEM_locked, UID_temp ); // last param is an optional id for type of mem block
// get details of sentence breakdown into array of _lineInfo structures
// and get the no of lines involved
noOfLines = AnalyseSentence( sentence, maxWidth, fontRes, (_lineInfo *)line->ad );
// construct the sprite based on the info gathered - returns floating mem block
textSprite = BuildTextSprite( sentence, fontRes, pen, (_lineInfo *)line->ad, noOfLines );
// free up the lineInfo array now
Free_mem( line );
return( textSprite );
}
//-----------------------------------------------------------------------------
uint16 AnalyseSentence( uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineInfo *line )
{
uint16 pos=0, wordWidth, wordLength, spaceNeeded, firstWord=TRUE, lineNo=0;
uint8 ch;
// joinWidth = how much extra space is needed to append a word to a line
// NB. SPACE requires TWICE the 'char_spacing' to join a word to line
uint16 joinWidth = CharWidth( SPACE, fontRes ) + 2*char_spacing;
do
{
wordWidth = 0; // new word
wordLength = 0;
ch = sentence[pos++]; // get first char of word (at position 'pos')
while( (ch != SPACE) && ch ) // while not SPACE or NULL terminator
{
// inc wordWidth by (character width + char_spacing) pixels
wordWidth += CharWidth( ch, fontRes ) + char_spacing;
wordLength++;
ch = sentence[pos++]; // get next char
}
wordWidth -= char_spacing; // no char_spacing after final letter of word!
// 'ch' is now the SPACE or NULL following the word
// 'pos' indexes to the position following 'ch'
if( firstWord ) // first word on first line, so no separating SPACE needed
{
line[0].width = wordWidth;
line[0].length = wordLength;
firstWord = FALSE;
}
else
{
// see how much extra space this word will need to fit on current line
// (with a separating space character - also overlapped)
spaceNeeded = joinWidth + wordWidth;
if( (line[lineNo].width + spaceNeeded) <= maxWidth ) // fits this line
{
line[lineNo].width += spaceNeeded;
line[lineNo].length += 1+wordLength; // NB. space+word characters
}
else // put word (without separating SPACE) at start of next line
{
lineNo++; // for next _lineInfo structure in the array
//debug_only( lineNo < MAX_LINES ); // exception if lineNo >= MAX_LINES
line[lineNo].width = wordWidth;
line[lineNo].length = wordLength;
}
}
}
while( ch ); // while not reached the NULL terminator
return lineNo+1; // return no of lines
}
//-----------------------------------------------------------------------------
// Returns a handle to a floating memory block containing a text sprite, given
// a pointer to a null-terminated string, pointer to required character set,
// required text pen colour (or zero to use source colours), pointer to the
// array of linInfo structures created by 'AnalyseSentence()', and the number
// of lines (ie. no. of elements in the 'line' array).
//
//
// PC Version of BuildTextSprite
//
//
mem* BuildTextSprite( uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line, uint16 noOfLines )
{
uint8 *linePtr, *spritePtr;
uint16 lineNo, pos=0, posInLine, spriteWidth=0, spriteHeight, sizeOfSprite;
uint16 charHeight = CharHeight(fontRes);
_frameHeader *frameHeadPtr, *charPtr;
mem *textSprite;
uint8 *charSet;
// spriteWidth = width of widest line of output text
for( lineNo=0; lineNo < noOfLines; lineNo++)
if( line[lineNo].width > spriteWidth )
spriteWidth = line[lineNo].width;
// spriteHeight = tot height of char lines + tot height of separating lines
spriteHeight = (charHeight*noOfLines + line_spacing*(noOfLines-1));
// total size (no of pixels)
sizeOfSprite = spriteWidth * spriteHeight;
// allocate memory for sprite, and lock it ready for use
// NB. 'textSprite' is the given pointer to the handle to be used
textSprite = Twalloc( sizeof(_frameHeader) + sizeOfSprite, MEM_locked, UID_text_sprite );
// the handle (*textSprite) now points to UNMOVABLE memory block
// set up the frame header
frameHeadPtr = (_frameHeader *)textSprite->ad; // point to the start of our memory block
frameHeadPtr->compSize = 0;
frameHeadPtr->width = spriteWidth;
frameHeadPtr->height = spriteHeight;
// Zdebug("spriteWidth=%u",spriteWidth);
// Zdebug("spriteHeight=%u",spriteHeight);
// ok, now point to the start (of the first line) of the sprite data itelf
linePtr = textSprite->ad + sizeof(_frameHeader);
// start with transparent sprite (no colour)
memset( linePtr, NO_COL, sizeOfSprite );
charSet = res_man.Res_open(fontRes); // open font file
// fill sprite with characters, one line at a time
for( lineNo=0; lineNo < noOfLines; lineNo++ )
{
// position the start of the line so that it is centred across the sprite
spritePtr = linePtr + (spriteWidth - line[lineNo].width) / 2;
// copy the sprite for each character in this line to the text sprite
// and inc the sprite ptr by the character's width minus the 'overlap'
for( posInLine=0; posInLine < line[lineNo].length; posInLine++ )
{
charPtr = FindChar( sentence[pos++], charSet );
#ifdef _DEBUG
if ((charPtr->height) != charHeight)
Con_fatal_error("FONT ERROR: '%c' is not same height as the space (%s line %u)",sentence[pos-1],__FILE__,__LINE__);
#endif
CopyChar( charPtr, spritePtr, spriteWidth, pen );
spritePtr += charPtr->width + char_spacing;
}
pos++; // skip space at end of last word in this line
// move to start of next character line in text sprite
linePtr += (charHeight + line_spacing) * spriteWidth;
}
res_man.Res_close(fontRes); // close font file
// unlock the sprite memory block, so it's movable
Float_mem( textSprite );
return( textSprite );
}
//-----------------------------------------------------------------------------
// Returns the width of a character sprite, given the character's ASCII code
// and a pointer to the start of the character set.
uint16 CharWidth( uint8 ch, uint32 fontRes )
{
_frameHeader *charFrame;
uint8 *charSet;
uint16 width;
charSet = res_man.Res_open(fontRes); // open font file
charFrame = FindChar( ch, charSet ); // move to approp. sprite (header)
width = charFrame->width;
res_man.Res_close(fontRes); // close font file
return (width); // return its width
}
//-----------------------------------------------------------------------------
// Returns the height of a character sprite, given the character's ASCII code
// and a pointer to the start of the character set.
uint16 CharHeight( uint32 fontRes ) // assume all chars the same height!
{
_frameHeader *charFrame;
uint8 *charSet;
uint16 height;
charSet = res_man.Res_open(fontRes); // open font file
charFrame = FindChar( FIRST_CHAR, charSet ); // FIRST_CHAR as good as any
height = charFrame->height;
res_man.Res_close(fontRes); // close font file
return (height); // return its height
}
//-----------------------------------------------------------------------------
// Returns a pointer to the header of a character sprite, given the character's
// ASCII code and a pointer to the start of the character set.
_frameHeader* FindChar( uint8 ch, uint8 *charSet )
{
// charSet details:
// ---------------
// starts with the standard file header ie. sizeof(_header) bytes
// then an int32 giving the no of sprites ie. 4 bytes
// then the offset table (an int32 offset for each sprite)
// - each offset counting from the start of the file
if( (ch<FIRST_CHAR) || (ch>LAST_CHAR) ) // if 'ch' out of range
ch = DUD; // then print the 'dud' character (chequered flag)
// address of char = address of charSet + offset to char
//return (charSet + *(int32 *)(charSet + sizeof(_header) + 4 + 4*(ch - FIRST_CHAR)));
return (FetchFrameHeader( charSet, ch-FIRST_CHAR ));
}
//-----------------------------------------------------------------------------
// Copies a character sprite from 'charPtr' to the sprite buffer at 'spritePtr'
// of width 'spriteWidth'. If pen is zero, it copies the data across directly,
// otherwise it maps pixels of BORDER_COL to 'border_pen', and LETTER_COL to 'pen'.
void CopyChar( _frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8 pen )
{
uint8 *rowPtr, *source, *dest;
uint16 rows, cols;
source = (uint8 *)charPtr + sizeof(_frameHeader); // now pts to sprite data for char 'ch'
rowPtr = spritePtr; // pts to start of first row of char within text sprite
for( rows=0; rows < charPtr->height; rows++ )
{
dest = rowPtr; // start at beginning of row
if (pen) // if required output pen is non-zero
{
for( cols=0; cols < charPtr->width; cols++ )
{
switch( *source++ ) // inc source ptr along sprite data
{
case LETTER_COL:
*dest = pen;
break;
case BORDER_COL:
if (!(*dest)) // don't do a border pixel if there already a bit of another character underneath (for overlapping!)
*dest = border_pen;
break;
// do nothing if source pixel is zero - ie. transparent
}
dest++; // inc dest ptr to next pixel along row
}
}
else // pen is zero, so just copy character sprites directly into text sprite without remapping colours
{
memcpy( dest, source, charPtr->width );
source += charPtr->width;
}
rowPtr += spriteWidth; // next row down (add width of text sprite)
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#if _DEBUG
#define MAX_text_blocs MAX_DEBUG_TEXT_BLOCKS+1 // allow enough for all the debug text blocks (see debug.cpp)
#else
#define MAX_text_blocs 2 // only need one for speech, and possibly one for "PAUSED"
#endif // _DEBUG
typedef struct
{
int16 x;
int16 y;
uint16 type; // RDSPR_ status bits - see defintion of _spriteInfo structure for correct size!
mem *text_mem;
} text_bloc;
text_bloc text_sprite_list[MAX_text_blocs];
//-----------------------------------------------------------------------------
void Init_text_bloc_system(void) //Tony16Oct96
{
uint32 j;
for (j=0;j<MAX_text_blocs;j++)
text_sprite_list[j].text_mem=0;
}
//-----------------------------------------------------------------------------
#define TEXT_MARGIN 12 // distance to keep speech text from edges of screen
uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification) //Tony31Oct96
{
//creates a text bloc in the list and returns the bloc number
//the list of blocs are read and blitted at render time
//choose alignment type RDSPR_DISPLAYALIGN or 0
uint32 j=0;
_frameHeader *frame_head;
int16 text_left_margin;
int16 text_right_margin;
int16 text_top_margin;
int16 text_bottom_margin;
//find a free slot
while((j<MAX_text_blocs)&&(text_sprite_list[j].text_mem))
j++;
#ifdef _DEBUG
if (j==MAX_text_blocs) //we've run out
Con_fatal_error("Build_new_block ran out of blocks! (%s line %u)",__FILE__,__LINE__); //might as well stop the system
#endif
text_sprite_list[j].text_mem = MakeTextSprite( ascii, width, pen, fontRes ); // make the sprite!
// speech to be centred above point (x,y), but kept on-screen
// where (x,y) is a point somewhere just above the talker's head
// debug text just to be printed normally from point (x,y)
//-----------------------------------------------------------
// JUSTIFICATION & POSITIONING (James updated 20jun97)
if (justification != NO_JUSTIFICATION) // 'NO_JUSTIFICATION' means print sprite with top-left at (x,y) without margin checking - used for debug text
{
frame_head = (_frameHeader*) text_sprite_list[j].text_mem->ad;
switch (justification)
{
// this one is always used for SPEECH TEXT; possibly also for pointer text
case POSITION_AT_CENTRE_OF_BASE:
x -= (frame_head->width)/2; // subtract half the sprite-width from the given x-coord
y -= frame_head->height; // and the sprite-height from the given y-coord
break;
case POSITION_AT_CENTRE_OF_TOP:
x -= (frame_head->width)/2;
break;
case POSITION_AT_LEFT_OF_TOP:
// the given coords are already correct for this!
break;
case POSITION_AT_RIGHT_OF_TOP:
x -= frame_head->width;
break;
case POSITION_AT_LEFT_OF_BASE:
y -= frame_head->height;
break;
case POSITION_AT_RIGHT_OF_BASE:
x -= frame_head->width;
y -= frame_head->height;
break;
case POSITION_AT_LEFT_OF_CENTRE:
y -= (frame_head->height)/2;
break;
case POSITION_AT_RIGHT_OF_CENTRE:
x -= frame_head->width;
y -= (frame_head->height)/2;
break;
}
// ensure text sprite is a few pixels inside the visible screen
text_left_margin = TEXT_MARGIN;
text_right_margin = 640 - TEXT_MARGIN - frame_head->width;
text_top_margin = 0 + TEXT_MARGIN; // remember - it's RDSPR_DISPLAYALIGN
text_bottom_margin = 400 - TEXT_MARGIN - frame_head->height;
if (x < text_left_margin) // move if too far left or too far right
x = text_left_margin;
else if (x > text_right_margin)
x = text_right_margin;
if (y < text_top_margin) // move if too high or too low
y = text_top_margin;
else if (y > text_bottom_margin)
y = text_bottom_margin;
}
//-----------------------------------------------------------
text_sprite_list[j].x = x;
text_sprite_list[j].y = y;
text_sprite_list[j].type = type+RDSPR_NOCOMPRESSION; // always uncompressed
return(j+1);
}
//-----------------------------------------------------------------------------
//
//
// PC Version of Print_text_blocs
//
//
void Print_text_blocs(void) //Tony16Oct96
{
//called by build_display
_frameHeader *frame;
_spriteInfo spriteInfo;
uint32 j;
uint32 rv;
for (j=0;j<MAX_text_blocs;j++)
{
if (text_sprite_list[j].text_mem)
{
frame = (_frameHeader*) text_sprite_list[j].text_mem->ad;
spriteInfo.x = text_sprite_list[j].x;
spriteInfo.y = text_sprite_list[j].y;
spriteInfo.w = frame->width;
spriteInfo.h = frame->height;
spriteInfo.scale = 0;
spriteInfo.scaledWidth = 0;
spriteInfo.scaledHeight = 0;
spriteInfo.type = text_sprite_list[j].type;
spriteInfo.blend = 0;
spriteInfo.data = text_sprite_list[j].text_mem->ad+sizeof(_frameHeader);
spriteInfo.colourTable = 0;
rv = DrawSprite( &spriteInfo );
if (rv)
ExitWithReport("Driver Error %.8x in Print_text_blocs [%s line %u]", rv, __FILE__, __LINE__);
}
}
}
//-----------------------------------------------------------------------------
void Kill_text_bloc(uint32 bloc_number) //Tony18Oct96
{
bloc_number--; //back to real
if (text_sprite_list[bloc_number].text_mem)
{
Free_mem(text_sprite_list[bloc_number].text_mem); //release the floating memory
text_sprite_list[bloc_number].text_mem=0; //this is how we know the bloc is free
}
else
Con_fatal_error("closing closed text bloc number %d", bloc_number); //illegal kill - stop the system
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// called from InitialiseGame() in sword2.cpp
void InitialiseFontResourceFlags(void) // (James31july97)
{
uint8 *textFile, *textLine;
uint8 language;
#define TEXT_RES 3258 // resource 3258 contains text from location script for 152 (install, save & restore text, etc)
#define SAVE_LINE_NO 1 // local line number of "save" (actor no. 1826)
#ifndef _DEMO // normal game
#define NAME_LINE_NO 54 // local line number of game name (actor no. 3550)
#else
#define NAME_LINE_NO 451 // local line number of demo game name
#endif // _DEMO
//---------------------------------------------------------------------------------
textFile = res_man.Res_open(TEXT_RES); // open the text resource
//---------------------------------------------------------------------------------
// check if language is Polish or Finnish, and therefore requires alternate fonts
textLine = FetchTextLine(textFile, SAVE_LINE_NO )+2; // get the text line (& skip the 2 chars containing the wavId)
if (strcmp((char*)textLine,"tallenna")==0) // if this line contains the Finnish for "save"
language = FINNISH_TEXT; // - then this version must be Finnish
else if (strcmp((char*)textLine,"zapisz")==0) // if this line contains the Polish for "save"
language = POLISH_TEXT; // - then this version must be Polish
else // neither Finnish nor Polish
language = DEFAULT_TEXT; // - use regular fonts
InitialiseFontResourceFlags(language); // Set the game to use the appropriate fonts
//---------------------------------------------------------------------------------
// Get the game name for the windows application
textLine = FetchTextLine(textFile, NAME_LINE_NO )+2; // get the text line (& skip the 2 chars containing the wavId)
SetWindowName((char*)textLine); // driver function
//---------------------------------------------------------------------------------
res_man.Res_close(TEXT_RES); // now ok to close the text file
//---------------------------------------------------------------------------------
}
//------------------------------------------------------------------------------------
// called from the above function, and also from console.cpp
void InitialiseFontResourceFlags(uint8 language) // (James31july97)
{
switch (language)
{
case FINNISH_TEXT: // special Finnish fonts
{
speech_font_id = FINNISH_SPEECH_FONT_ID;
controls_font_id = FINNISH_CONTROLS_FONT_ID;
red_font_id = FINNISH_RED_FONT_ID;
break;
}
case POLISH_TEXT: // special Polish fonts
{
speech_font_id = POLISH_SPEECH_FONT_ID;
controls_font_id = POLISH_CONTROLS_FONT_ID;
red_font_id = POLISH_RED_FONT_ID;
break;
}
default:// DEFAULT_TEXT // regular fonts
{
speech_font_id = ENGLISH_SPEECH_FONT_ID;
controls_font_id = ENGLISH_CONTROLS_FONT_ID;
red_font_id = ENGLISH_RED_FONT_ID;
break;
}
}
}
//------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------

94
sword2/maketext.h Normal file
View file

@ -0,0 +1,94 @@
/* 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$
*/
/****************************************************************************
* MAKETEXT.H Function prototype for text sprite builder routine JEL Oct96
*
* The routine returns a memory handle to a movable memory block containing
* the required sprite, which must be locked before use.
* ie. lock, draw sprite, unlock/free.
* The sprite data contains a frameHeader, but not a standard file header.
*
* Debugger will trap error when word too big for line (maxWidth)
* or when more lines needed than max expected (MAX_LINES)
*
* PARAMETERS:
*
* 'sentence' points to a NULL-TERMINATED STRING
* - string must contain no leading/tailing/extra spaces
* - out-of-range characters in the string are forced to the output as a
* special error-signal character (chequered flag)
*
* 'maxWidth' is the maximum allowed text sprite width, in PIXELS
*
* 'pen' is the desired colour (0-255) for the main body of each character
* NB. Border colour is #DEFINEd in textsprt.c (to a colour value for BLACK)
* if 'pen' is zero, the characters are copied directly and NOT remapped.
*
* 'charSet' points to the beginning of the standard file header for the
* desired character set
* NB. The first and last characters in the set are #DEFINEd in textsprt.c
*
*
* RETURNS:
*
* 'textSprite' points to the handle to be used for the text sprite
*
****************************************************************************/
#ifndef _MAKETEXT_H
#define _MAKETEXT_H
//#include "src\driver96.h"
#include "memory.h"
#define NO_JUSTIFICATION 0 // only for debug text, since it doesn't keep text inside the screen margin!
#define POSITION_AT_CENTRE_OF_BASE 1 // these all force text inside the screen edge margin when necessary
#define POSITION_AT_CENTRE_OF_TOP 2
#define POSITION_AT_LEFT_OF_TOP 3
#define POSITION_AT_RIGHT_OF_TOP 4
#define POSITION_AT_LEFT_OF_BASE 5
#define POSITION_AT_RIGHT_OF_BASE 6
#define POSITION_AT_LEFT_OF_CENTRE 7
#define POSITION_AT_RIGHT_OF_CENTRE 8
mem* MakeTextSprite( uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes );
void Init_text_bloc_system(void);
void Kill_text_bloc(uint32 bloc_number);
void Print_text_blocs(void); //Tony16Oct96
uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification);
//-----------------------------------------------------------------------------
#define DEFAULT_TEXT 0
#define FINNISH_TEXT 1
#define POLISH_TEXT 2
void InitialiseFontResourceFlags(void); // this one works out the language from the text cluster (James31july97)
void InitialiseFontResourceFlags(uint8 language); // this one allow you to select the fonts yourself (James31july97)
extern uint32 speech_font_id;
extern uint32 controls_font_id;
extern uint32 red_font_id;
//-----------------------------------------------------------------------------
#endif

259
sword2/mem_view.cpp Normal file
View file

@ -0,0 +1,259 @@
/* 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$
*/
//--------------------------------------------------------------------------------------
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
//#include <windows.h>
#include "driver/driver96.h"
#include "build_display.h"
#include "console.h"
#include "debug.h"
#include "defs.h"
#include "header.h"
#include "layers.h"
#include "mem_view.h"
#include "memory.h"
#include "resman.h"
#include "sword2.h" // (James11aug97) for CloseGame()
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
char buf[50]; //has to be global because a local in Fetch_mem_owner is destroyed on exit
//--------------------------------------------------------------------------------------
void Console_mem_display(void) //Tony13Aug96
{
//
int pass,found_end,k,j,free=0;
_standardHeader *file_header;
int scrolls=0;
char c;
char inf[][20]=
{
{"M_null "},
{"M_free "},
{"M_locked"},
{"M_float "}
};
j=base_mem_block;
do
{
if (mem_list[j].uid<65536)
{
file_header = (_standardHeader*) res_man.Res_open(mem_list[j].uid);
res_man.Res_close(mem_list[j].uid); //close immediately so give a true count
Zdebug("view %d", mem_list[j].uid);
pass=0;
found_end=0;
for (k=0;k<30;k++)
{
if (file_header->name[k]==0)
{ found_end=1;
break;
}
if ( (file_header->name[k]<32)||(file_header->name[k]>'z'))
pass=1;
}
if (file_header->name[0]==0)
pass=1; //also illegal
if ((!pass)&&(found_end)) //&&(file_header->fileType<10))
Print_to_console("%d %s, size 0x%.5x (%dk %d%%), res %d %s %s, A%d, C%d", j,
inf[mem_list[j].state],
mem_list[j].size, mem_list[j].size/1024, (mem_list[j].size*100)/total_free_memory, mem_list[j].uid,
res_man.Fetch_cluster(mem_list[j].uid),
file_header->name,
res_man.Fetch_age(mem_list[j].uid),
res_man.Fetch_count(mem_list[j].uid));
else Print_to_console(" %d is an illegal resource", mem_list[j].uid);
}
else
Print_to_console("%d %s, size 0x%.5x (%dk %d%%), %s", j,
inf[mem_list[j].state],
mem_list[j].size, mem_list[j].size/1024, (mem_list[j].size*100)/total_free_memory,
Fetch_mem_owner(mem_list[j].uid) );
if (mem_list[j].state==MEM_free)
free+=mem_list[j].size;
j=mem_list[j].child;
scrolls++;
Build_display();
if (scrolls==18)
{
Temp_print_to_console("- Press ESC to stop or any other key to continue");
Build_display();
do
{
//--------------------------------------------------
// Service windows
while (!gotTheFocus)
if (ServiceWindows() == RDERR_APPCLOSED)
break;
if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
{
Close_game(); //close engine systems down
RestoreDisplay();
CloseAppWindow();
exit(0); //quit the game
}
//--------------------------------------------------
}
while(!KeyWaiting());
ReadKey(&c); //kill the key we just pressed
if (c==27) //ESC
break;
Clear_console_line(); //clear the Press Esc message ready for the new line
scrolls=0;
}
}
while (j!=-1);
Scroll_console();
Print_to_console("(total memory block 0x%.8x %dk %dMB) %d / %d%% free", total_free_memory,
total_free_memory/1024,
total_free_memory/(1000*1024),
free,
(free*100)/total_free_memory);
}
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
char *Fetch_mem_owner(uint32 uid) //Tony3June96
{
switch(uid)
{
case UID_memman:
return("MEMMAN");
break;
case UID_font:
return("font");
break;
case UID_temp:
return("temp ram allocation");
break;
case UID_decompression_buffer:
return("decompression buffer");
break;
case UID_shrink_buffer:
return("shrink buffer");
break;
case UID_con_sprite:
return("console sprite buffer");
break;
case UID_text_sprite:
return("text sprite");
break;
case UID_walk_anim:
return("walk anim");
break;
case UID_savegame_buffer:
return("savegame buffer");
break;
default:
sprintf(buf, "<sob> %d?", uid);
return(buf);
break;
}
}
//--------------------------------------------------------------------------------------
void Create_mem_string( char *string ) // James (21oct96 updated 4dec96)
{
int blockNo = base_mem_block;
int blocksUsed=0;
int mem_free=0;
int mem_locked=0;
int mem_floating=0;
int memUsed=0;
int percent;
while (blockNo != -1)
{
switch (mem_list[blockNo].state)
{
case MEM_free:
mem_free++;
break;
case MEM_locked:
mem_locked++;
memUsed += mem_list[blockNo].size;
break;
case MEM_float:
mem_floating++;
memUsed += mem_list[blockNo].size;
break;
}
blocksUsed++;
blockNo = mem_list[blockNo].child;
}
percent = (memUsed * 100) / total_free_memory;
sprintf( string, "locked(%u)+float(%u)+free(%u) = %u/%u blocks (%u%% used)(cur %uk)", mem_locked, mem_floating, mem_free, blocksUsed, MAX_mem_blocks, percent, (res_man.Res_fetch_useage()/1024) );
}
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------

31
sword2/mem_view.h Normal file
View file

@ -0,0 +1,31 @@
/* 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$
*/
#ifndef MEMVIEW_H
#define MEMVIEW_H
//#include "src\driver96.h"
char *Fetch_mem_owner(uint32 uid);
void Console_mem_display(void); // Tony (13Aug96)
void Create_mem_string( char *string ); // James (21oct96 updated 4dec96)
#endif

544
sword2/memory.cpp Normal file
View file

@ -0,0 +1,544 @@
/* 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$
*/
//memory manager - "remember, it's not good to leave memory locked for a moment longer than necessary" Tony
// "actually, in a sequential system theoretically you never need to lock any memory!" Chris ;)
//
// This is a very simple implementation but I see little advantage to being any cleverer
// with the coding - i could have put the mem blocks before the defined blocks instead
// of in an array and then used pointers to child/parent blocks. But why bother? I've Kept it simple.
// When it needs updating or customising it will be accessable to anyone who looks at it.
// *doesn't have a purgeable/age consituant yet - if anyone wants this then I'll add it in.
// MemMan v1.1
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "driver/driver96.h"
#include "console.h"
#include "debug.h"
#include "memory.h"
#include "resman.h"
uint32 total_blocks;
uint32 base_mem_block;
uint32 total_free_memory;
uint8 *free_memman; //address of init malloc to be freed later
//#define MEMDEBUG 1
mem mem_list[MAX_mem_blocks]; //list of defined memory handles - each representing a block of memory.
int32 VirtualDefrag( uint32 size ); // Used to determine if the required size can be obtained if the defragger is allowed to run.
int32 suggestedStart = 0; // Start position of the Defragger as indicated by its sister VirtualDefrag.
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
void Close_memory_manager(void) //Tony2Oct96
{
//unlock our supposedly locked in memory
VirtualUnlock(free_memman, total_free_memory);
free(free_memman);
}
//------------------------------------------------------------------------------------
void Init_memory_manager(void) //Tony9April96
{
uint32 j;
uint8 *memory_base;
//BOOL res;
MEMORYSTATUS memo;
//find out how much actual physical RAM this computer has
GlobalMemoryStatus(&memo);
//now decide how much to grab - 8MB computer are super critical
if (memo.dwTotalPhys<=(8000*1024)) //if 8MB or less :-O
total_free_memory=4500*1024; //4.5MB
else if (memo.dwTotalPhys<=(12000*1024)) //if 8MB or less :-O
total_free_memory=8000*1024; //8MB
else if (memo.dwTotalPhys<=(16000*1024)) //if 16MB or less :-)
total_free_memory=10000*1024; //10MB
else //:-)) loads of RAM
total_free_memory=12000*1024; //12MB
Zdebug("MEM = %d", memo.dwTotalPhys);
Zdebug("Sword 2 grabbed %dk", total_free_memory/1024);
//malloc memory and adjust for long boundaries
memory_base = (uint8 *) malloc(total_free_memory);
if (!memory_base) //could not grab the memory
{
Zdebug("couldn't malloc %d in Init_memory_manager", total_free_memory);
ExitWithReport("Init_memory_manager() couldn't malloc %d bytes [line=%d file=%s]",total_free_memory,__LINE__,__FILE__);
}
free_memman = memory_base; //the original malloc address
//force to long word boundary
memory_base+=3;
memory_base = (uint8 *)((uint32)memory_base & 0xfffffffc); // ** was (int)memory_base
// total_free_memory-=3; //play safe
//set all but first handle to unused
for (j=1;j<MAX_mem_blocks;j++)
mem_list[j].state=MEM_null;
total_blocks=1; //total used (free, locked or floating)
mem_list[0].ad = memory_base;
mem_list[0].state= MEM_free;
mem_list[0].age=0;
mem_list[0].size=total_free_memory;
mem_list[0].parent=-1; //we are base - for now
mem_list[0].child=-1; //we are the end as well
mem_list[0].uid=UID_memman; //init id
base_mem_block=0; //for now
//supposedly this will stop the memory swapping out?? Well, as much as we're allowed
// res=VirtualLock(free_memman, total_free_memory);
// if (res!=TRUE)
// Zdebug(" *VirtualLock failed");
}
//------------------------------------------------------------------------------------
mem *Talloc(uint32 size, uint32 type, uint32 unique_id) //Tony10Apr96
{
//allocate a block of memory - locked or float
// returns 0 if fails to allocate the memory
// or a pointer to a mem structure
int32 nu_block;
uint32 spawn=0;
uint32 slack;
//we must first round the size UP to a dword, so subsequent blocks will start dword alligned
size+=3; //move up
size &= 0xfffffffc; //and back down to boundary
//find a free block large enough
if ( (nu_block = Defrag_mem(size))==-1) //the defragger returns when its made a big enough block. This is a good time to defrag as we're probably not
{ //doing anything super time-critical at the moment
return(0); //error - couldn't find a big enough space
}
//an exact fit?
if (mem_list[nu_block].size==size) //no new block is required as the fit is perfect
{
mem_list[nu_block].state=type; //locked or float
mem_list[nu_block].size=size; //set to the required size
mem_list[nu_block].uid=unique_id; //an identifier
#ifdef MEMDEBUG
Mem_debug();
#endif //MEMDEBUG
return(&mem_list[nu_block]);
}
// nu_block is the free block to split, forming our locked/float block with a new free block in any remaining space
//if our child is free then is can expand downwards to eat up our chopped space
//this is good because it doesn't create an extra bloc so keeping the block count down
//why?
//imagine you Talloc 1000k, then free it. Now keep allocating 10 bytes less and freeing again
//you end up with thousands of new free mini blocks. this way avoids that as the free child keeps growing downwards
if ((mem_list[nu_block].child != -1) && (mem_list[mem_list[nu_block].child].state==MEM_free)) //our child is free
{
slack=mem_list[nu_block].size-size; //the spare memory is the blocks current size minus the amount we're taking
mem_list[nu_block].state=type; //locked or float
mem_list[nu_block].size=size; //set to the required size
mem_list[nu_block].uid=unique_id; //an identifier
mem_list[mem_list[nu_block].child].ad = mem_list[nu_block].ad+size; //child starts after us
mem_list[mem_list[nu_block].child].size += slack; //childs size increases
return(&mem_list[nu_block]);
}
// otherwise we spawn a new block after us and before our child - our child being a proper block that we cannot change
// we remain a child of our parent
// we spawn a new child and it inherits our current child
//find a NULL slot for a new block
while((mem_list[spawn].state!=MEM_null)&&(spawn!=MAX_mem_blocks))
spawn++;
if (spawn==MAX_mem_blocks) //run out of blocks - stop the program. this is a major blow up and we need to alert the developer
{
Mem_debug(); //Lets get a printout of this
ExitWithReport("ERROR: ran out of mem blocks in Talloc() [file=%s line=%u]",__FILE__,__LINE__);
}
mem_list[spawn].state=MEM_free; //new block is free
mem_list[spawn].uid=UID_memman; //a memman created bloc
mem_list[spawn].size= mem_list[nu_block].size-size; //size of the existing parent free block minus the size of the new space Talloc'ed.
//IOW the remaining memory is given to the new free block
mem_list[spawn].ad = mem_list[nu_block].ad+size; //we start 1 byte after the newly allocated block
mem_list[spawn].parent=nu_block; //the spawned child gets it parent - the newly allocated block
mem_list[spawn].child=mem_list[nu_block].child; //the new child inherits the parents old child (we are its new child "Waaaa")
if (mem_list[spawn].child!=-1) //is the spawn the end block?
mem_list[mem_list[spawn].child].parent= spawn; //the child of the new free-spawn needs to know its new parent
mem_list[nu_block].state=type; //locked or float
mem_list[nu_block].size=size; //set to the required size
mem_list[nu_block].uid=unique_id; //an identifier
mem_list[nu_block].child=spawn; //the new blocks new child is the newly formed free block
total_blocks++; //we've brought a new block into the world. Ahhh!
#ifdef MEMDEBUG
Mem_debug();
#endif //MEMDEBUG
return(&mem_list[nu_block]);
}
//------------------------------------------------------------------------------------
void Free_mem(mem *block) //Tony10Apr96
{
//kill a block of memory - which was presumably floating or locked
//once you've done this the memory may be recycled
block->state=MEM_free;
block->uid=UID_memman; //belongs to the memory manager again
#ifdef MEMDEBUG
Mem_debug();
#endif //MEMDEBUG
}
//------------------------------------------------------------------------------------
void Float_mem(mem *block) //Tony10Apr96
{
//set a block to float
//wont be trashed but will move around in memory
block->state=MEM_float;
#ifdef MEMDEBUG
Mem_debug();
#endif //MEMDEBUG
}
//------------------------------------------------------------------------------------
void Lock_mem(mem *block) //Tony11Apr96
{
//set a block to lock
//wont be moved - don't lock memory for any longer than necessary unless you know the locked memory is at the bottom of the heap
block->state=MEM_locked; //can't move now - this block is now crying out to be floated or free'd again
#ifdef MEMDEBUG
Mem_debug();
#endif //MEMDEBUG
}
//------------------------------------------------------------------------------------
int32 Defrag_mem(uint32 req_size) //Tony10Apr96
{
//moves floating blocks down and/or merges free blocks until a large enough space is found
//or there is nothing left to do and a big enough block cannot be found
//we stop when we find/create a large enough block - this is enough defragging.
int32 cur_block; //block 0 remains the parent block
int32 original_parent,child, end_child;
uint32 j;
uint32 *a;
uint32 *b;
// cur_block=base_mem_block; //the mother of all parents
cur_block = suggestedStart;
do
{
if (mem_list[cur_block].state==MEM_free) //is current block a free block?
{
if (mem_list[cur_block].size>=req_size)
{
return(cur_block); //this block is big enough - return its id
}
if (mem_list[cur_block].child==-1) //the child is the end block - stop if the next block along is the end block
return(-1); //no luck, couldn't find a big enough block
// current free block is too small, but if its child is *also* free then merge the two together
if (mem_list[mem_list[cur_block].child].state==MEM_free)
{
// ok, we nuke the child and inherit its child
child=mem_list[cur_block].child;
mem_list[cur_block].size+= mem_list[child].size; //our size grows by the size of our child
mem_list[cur_block].child = mem_list[child].child; //our new child is our old childs, child
if (mem_list[child].child!=-1) //not if the chld we're nuking is the end child (it has no child)
mem_list[mem_list[child].child].parent=cur_block; //the (nuked) old childs childs parent is now us
mem_list[child].state=MEM_null; //clean up the nuked child, so it can be used again
total_blocks--;
}
// current free block is too small, but if its child is a float then we move the floating memory block down and the free up
// but, parent/child relationships must be such that the memory is all continuous between blocks. ie. a childs memory always
// begins 1 byte after its parent finishes. However, the positions in the memory list may become truly random, but, any particular
// block of locked or floating memory must retain its position within the mem_list - the float stays a float because the handle/pointer has been passed back
// what this means is that when the physical memory of the foat moves down (and the free up) the child becomes the parent and the parent the child
// but, remember, the parent had a parent and the child another child - these swap over too as the parent/child swap takes place - phew.
else if (mem_list[mem_list[cur_block].child].state==MEM_float)
{
child=mem_list[cur_block].child; //our child is currently floating
// memcpy(mem_list[cur_block].ad, mem_list[child].ad, mem_list[child].size); //move the higher float down over the free block
a=(uint32*) mem_list[cur_block].ad;
b=(uint32*) mem_list[child].ad;
for (j=0;j<mem_list[child].size/4;j++)
*(a++)=*(b++);
// both *ad's change
mem_list[child].ad = mem_list[cur_block].ad; //the float is now where the free was
mem_list[cur_block].ad += mem_list[child].size; //and the free goes up by the size of the float (which has come down)
// the status of the mem_list blocks must remain the same, so...
original_parent= mem_list[cur_block].parent; //our child gets this when we become its child and it our parent
mem_list[cur_block].parent=child; //the free's child becomes its parent
mem_list[cur_block].child= mem_list[child].child; //the new child inherits its previous childs child
end_child=mem_list[child].child; //save this - see next line
mem_list[child].child=cur_block; //the floats parent becomes its child
mem_list[child].parent= original_parent;
if (end_child!=-1) //if the child had a child
mem_list[end_child].parent=cur_block; //then its parent is now the new child
if (original_parent==-1) //the base block was the true base parent
base_mem_block=child; //then the child that has moved down becomes the base block as it sits at the lowest possible memory location
else
mem_list[original_parent].child=child; //otherwise the parent of the current free block - that is now the child - gets a new child,
//that child being previously the child of the child of the original parent
}
else //if (mem_list[mem_list[cur_block].child].state==MEM_lock) //the child of current is locked - move to it
cur_block=mem_list[cur_block].child; //move to next one along - either locked or END
}
else
{
cur_block=mem_list[cur_block].child; //move to next one along, the current must be floating, locked, or a NULL slot
}
}
while(cur_block!=-1); //while the block we've just done is not the final block
return(-1); //no luck, couldn't find a big enough block
}
//------------------------------------------------------------------------------------
void Mem_debug(void) //Tony11Apr96
{
//gets called with Talloc, Mem_free, Mem_lock & Mem_float if MEMDEBUG has been #defined
//otherwise can be called at any time anywhere else
int j;
char inf[][20]=
{
{"MEM_null"},
{"MEM_free"},
{"MEM_locked"},
{"MEM_float"}
};
Zdebug("\nbase %d total %d", base_mem_block, total_blocks);
//first in mem list order
for (j=0;j<MAX_mem_blocks;j++)
{
if (mem_list[j].state==MEM_null)
Zdebug("%d- NULL", j);
else
Zdebug("%d- state %s, ad %d, size %d, p %d, c %d, id %d", j,
inf[mem_list[j].state],
mem_list[j].ad, mem_list[j].size, mem_list[j].parent, mem_list[j].child, mem_list[j].uid);
}
//now in child/parent order
j=base_mem_block;
do
{
Zdebug(" %d- state %s, ad %d, size %d, p %d, c %d", j,
inf[mem_list[j].state],
mem_list[j].ad, mem_list[j].size, mem_list[j].parent, mem_list[j].child, mem_list[j].uid);
j=mem_list[j].child;
}
while (j!=-1);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
mem *Twalloc(uint32 size, uint32 type, uint32 unique_id) //tony12Feb97
{
//the high level Talloc
//can ask the resman to remove old resources to make space - will either do it or halt the system
mem *membloc;
int j;
uint32 free=0;
while( VirtualDefrag(size) )
{
if (!res_man.Help_the_aged_out()) //trash the oldest closed resource
{
Zdebug("Twalloc ran out of memory! %d %d %d\n", size, type, unique_id);
ExitWithReport("Twalloc ran out of memory!");
}
}
membloc = Talloc(size, type, unique_id);
if (membloc == 0)
{
Zdebug("Talloc failed to get memory VirtualDefrag said was there");
ExitWithReport("Talloc failed to get memory VirtualDefrag said was there");
}
j=base_mem_block;
do
{
if (mem_list[j].state==MEM_free)
free+=mem_list[j].size;
j=mem_list[j].child;
}
while (j!=-1);
return(membloc); //return the pointer to the memory
}
#define MAX_WASTAGE 51200 // Maximum allowed wasted memory.
int32 VirtualDefrag( uint32 size ) // Chris - 07 April '97
{
//
// Virutually defrags memory...
//
// Used to determine if there is potentially are large enough free block available is the
// real defragger was allowed to run.
//
// The idea being that Twalloc will call this and help_the_aged_out until we indicate that
// it is possible to obtain a large enough free block. This way the defragger need only
// run once to yield the required block size.
//
// The reason for its current slowness is that the defragger is potentially called several
// times, each time shifting upto 20Megs around, to obtain the required free block.
//
int32 cur_block;
uint32 currentBubbleSize = 0;
cur_block=base_mem_block;
suggestedStart = base_mem_block;
do
{
if (mem_list[cur_block].state == MEM_free)
{
// Add a little intelligence. At the start the oldest resources are at the bottom of the
// tube. However there will be some air at the top. Thus bubbles will be
// created at the bottom and float to the top. If we ignore the top gap
// then a large enough bubble will form lower down the tube. Thus less memory
// will need to be shifted.
if (mem_list[cur_block].child != -1)
currentBubbleSize += mem_list[cur_block].size;
else if (mem_list[cur_block].size > MAX_WASTAGE)
currentBubbleSize += mem_list[cur_block].size;
if (currentBubbleSize >= size)
return 0;
}
else if (mem_list[cur_block].state == MEM_locked)
{
currentBubbleSize = 0;
suggestedStart = mem_list[cur_block].child; // Any free block of the correct size will be above this locked block.
}
cur_block = mem_list[cur_block].child;
}
while(cur_block != -1);
return(1);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

82
sword2/memory.h Normal file
View file

@ -0,0 +1,82 @@
/* 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$
*/
#ifndef MEMORY_H
#define MEMORY_H
#include "common/scummsys.h"
//#include "src\driver96.h"
typedef struct
{
uint32 state;
uint32 age; // *not used*
uint32 size;
int32 parent; //who is before us
int32 child; //who is after us
uint32 uid; //id of a position in the resList or some other unique id - for the visual display only
uint8 *ad;
} mem;
#define MEM_null 0 //null
#define MEM_free 1
#define MEM_locked 2
#define MEM_float 3
//---------------------------------------
// MEMORY BLOCKS
#define MAX_mem_blocks 999
// maintain at a good 50% higher than the
// highest recorded value from the on-screen info
//---------------------------------------
#define UID_memman 0xffffffff
#define UID_NULL 0xfffffffe //FREE
#define UID_font 0xfffffffd
#define UID_temp 0xfffffffc
#define UID_decompression_buffer 0xfffffffb
#define UID_shrink_buffer 0xfffffffa
#define UID_con_sprite 0xfffffff9
#define UID_text_sprite 0xfffffff8
#define UID_walk_anim 0xfffffff7
#define UID_savegame_buffer 0xfffffff6
#define UID_restoregame_buffer 0xfffffff5
void Init_memory_manager(void);
void Close_memory_manager(void); //Tony2Oct96
//mem *Talloc(uint32 size, uint32 type, uint32 unique_id); //low level
mem *Twalloc(uint32 size, uint32 type, uint32 unique_id); //high level
void Free_mem(mem *block);
void Float_mem(mem *block);
void Lock_mem(mem *block);
void Mem_debug(void);
void Visual_mem_display(void);
int32 Defrag_mem(uint32 req_size); //Tony10Apr96
extern uint32 total_blocks;
extern uint32 base_mem_block;
extern mem mem_list[MAX_mem_blocks];
extern uint32 total_free_memory;
#endif

46
sword2/module.mk Normal file
View file

@ -0,0 +1,46 @@
MODULE := bs2
MODULE_OBJS = \
bs2/anims.o \
bs2/build_display.o \
bs2/console.o \
bs2/controls.o \
bs2/debug.o \
bs2/events.o \
bs2/function.o \
bs2/icons.o \
bs2/interpreter.o \
bs2/layers.o \
bs2/logic.o \
bs2/maketext.o \
bs2/memory.o \
bs2/mem_view.o \
bs2/mouse.o \
bs2/protocol.o \
bs2/resman.o \
bs2/router.o \
bs2/save_rest.o \
bs2/scroll.o \
bs2/sound.o \
bs2/speech.o \
bs2/startup.o \
bs2/sword2.o \
bs2/sync.o \
bs2/tony_gsdk.o \
bs2/walker.o \
bs2/driver/_console.o \
bs2/driver/d_draw.o \
bs2/driver/d_sound.o \
bs2/driver/keyboard.o \
bs2/driver/language.o \
bs2/driver/menu.o \
bs2/driver/misc.o \
bs2/driver/_mouse.o \
bs2/driver/palette.o \
bs2/driver/rdwin.o \
bs2/driver/render.o \
bs2/driver/sprite.o
# Include common rules
include common.rules

1466
sword2/mouse.cpp Normal file

File diff suppressed because it is too large Load diff

89
sword2/mouse.h Normal file
View file

@ -0,0 +1,89 @@
/* 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$
*/
//mouse stuff
#ifndef MOUSE_H
#define MOUSE_H
//#include "src\driver96.h"
#include "object.h"
//---------------------------------------------------------------------------------
#define TOTAL_mouse_list 50
#define MOUSE_normal 0
#define MOUSE_top 1
#define MOUSE_drag 2
#define MOUSE_system_menu 3
#define MOUSE_holding 4
//---------------------------------------------------------------------------------
// mouse unit - like Object_mouse, but with anim resource & pc (needed if sprite is to act as mouse detection mask)
typedef struct
{
int32 x1; // top-left of mouse area is (x1,y1)
int32 y1;
int32 x2; // bottom-right of area is (x2,y2) (these coords are inclusive)
int32 y2;
int32 priority;
int32 pointer; // type (or resource id?) of pointer used over this area
// up to here, this is basically a copy of the Object_mouse structure, but then we have...
int32 id; // object id, used when checking mouse list
int32 anim_resource; // resource id of animation file (if sprite to be used as mask) - otherwise 0
int32 anim_pc; // current frame number of animation
int32 pointer_text; // local id of text line to print when pointer highlights an object
} Mouse_unit;
//---------------------------------------------------------------------------------
extern uint32 cur_mouse;
extern Mouse_unit mouse_list[TOTAL_mouse_list];
extern uint32 mouse_touching;
extern uint32 mouse_mode;
extern uint8 examining_menu_icon;
extern uint32 mouse_status; //human 0 on/1 off
extern uint32 mouse_mode_locked; //0 not !0 mode cannot be changed from normal mouse to top menu (i.e. when carrying big objects)
extern uint32 real_luggage_item; //last minute for pause mode
extern uint32 pointerTextSelected;
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void Reset_mouse_list(void); //Tony26Sept96
void Normal_mouse(void); //Tony30Sept96
void Top_menu_mouse(void); //Tony3Oct96
void Drag_mouse(void); //Tony21Nov96
void System_menu(void); //Tony19Mar97
void Mouse_on_off(void); //Tony30Sept96
uint32 Check_mouse_list(void); //Tony30Sept96
void Mouse_engine(void); //Tony30Sept96
void Set_mouse(uint32 res);
void Set_luggage(uint32 res); //Tony26Nov96
int32 FN_no_human(int32 *params); //Tony30Sept96
int32 FN_add_human(int32 *params); //Tony30Sept96
void ClearPointerText(void); // James16jun97
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
#endif

124
sword2/object.h Normal file
View file

@ -0,0 +1,124 @@
/* 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$
*/
#ifndef _SCRIPT_STRUCTURES
#define _SCRIPT_STRUCTURES
#include "driver/driver96.h"
// these structures represent the broken up compact components
// these here declared to the system must be the same as those declared to LINC (or it wont work)
// mouse structure - defines mouse detection area, detection priority & 'type' flag
typedef struct
{
int32 x1; // top-left of mouse area is (x1,y1)
int32 y1;
int32 x2; // bottom-right of area is (x2,y2) (these coords are inclusive)
int32 y2;
int32 priority;
int32 pointer; // type (or resource id?) of pointer used over this area
} Object_mouse;
// logic structure - contains fields used in logic script processing
typedef struct
{
int32 looping; // 0 when first calling FN_<function>; 1 when calling subsequent times in same loop
int32 pause; // pause count, used by FN_pause()
} Object_logic;
//------------------------------------------------
// status bits for 'type' field of Object_graphic)
// in low word:
#define NO_SPRITE 0x00000000 // don't print
#define BGP0_SPRITE 0x00000001 // fixed to background parallax[0]
#define BGP1_SPRITE 0x00000002 // fixed to background parallax[1]
#define BACK_SPRITE 0x00000004 // 'background' sprite, fixed to main background
#define SORT_SPRITE 0x00000008 // 'sorted' sprite, fixed to main background
#define FORE_SPRITE 0x00000010 // 'foreground' sprite, fixed to main background
#define FGP0_SPRITE 0x00000020 // fixed to foreground parallax[0]
#define FGP1_SPRITE 0x00000040 // fixed to foreground parallax[0]
// in high word:
#define UNSHADED_SPRITE 0x00000000 // not to be shaded
#define SHADED_SPRITE 0x00010000 // to be shaded, based on shading mask
//------------------------------------------------
// graphic structure - contains fields appropriate to sprite output
typedef struct
{
int32 type; // see above
int32 anim_resource; // resource id of animation file
int32 anim_pc; // current frame number of animation
} Object_graphic;
// speech structure - contains fields used by speech scripts & text output
typedef struct
{
int32 pen; // colour to use for body of characters
int32 width; // max width of text sprite
int32 command; // speech script command id
int32 ins1; // speech script instruction parameters (may need more now?)
int32 ins2;
int32 ins3;
int32 ins4;
int32 ins5;
int32 wait_state; //0 not waiting 1 waiting for next speech command
} Object_speech;
// mega structure - contains fields used for mega-character & mega-set processing
typedef struct
{
int32 NOT_USED_1; // only free roaming megas need to check this before registering their graphics for drawing
int32 NOT_USED_2; // id of floor on which we are standing
int32 NOT_USED_3; // id of object which we are getting to
int32 NOT_USED_4; // pixel distance to stand from player character when in conversation
int32 currently_walking; // number given us by the auto router
int32 walk_pc; // current frame number of walk-anim
int32 scale_a; // current scale factors, taken from floor data
int32 scale_b;
int32 feet_x; // mega feet coords - frame-offsets are added to these position mega frames
int32 feet_y;
int32 current_dir; // current dirction faced by mega; used by autorouter to determine turns required
int32 colliding; // means were currently avoiding a collision (see FN_walk)
int32 megaset_res; // resource id of mega-set file
int32 NOT_USED_5; // NOT USED
} Object_mega;
// walk-data structure - contains details of layout of frames in the mega-set, and how they are to be used
typedef struct
{
int32 nWalkFrames; // no. of frames per walk-cycle
int32 usingStandingTurnFrames; // 0=no 1=yes
int32 usingWalkingTurnFrames; // 0=no 1=yes
int32 usingSlowInFrames; // 0=no 1=yes
int32 usingSlowOutFrames; // 0=no !0=number of slow-out frames in each direction
int32 nSlowInFrames[8]; // no. of slow-in frames in each direction
int32 leadingLeg[8]; // leading leg for walk in each direction (0=left 1=right)
int32 dx[8*(12+1)]; // walk step distances in x direction
int32 dy[8*(12+1)]; // walk step distances in y direction
} Object_walkdata;
#endif

240
sword2/protocol.cpp Normal file
View file

@ -0,0 +1,240 @@
/* 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$
*/
#include <stdio.h>
//#include <windows.h>
//#include "src\driver96.h"
#include "console.h"
#include "debug.h"
#include "defs.h"
#include "header.h"
#include "logic.h"
#include "memory.h"
#include "protocol.h"
#include "resman.h"
//-----------------------------------------------------------------------------------------------------------------------
// returns a pointer to the first palette entry, given the pointer to the start of the screen file
// assumes it has been passed a pointer to a valid screen file
uint8 *FetchPalette(uint8 *screenFile) // Chris 04Oct96
{
uint8 *palette;
_multiScreenHeader *mscreenHeader = (_multiScreenHeader *) (screenFile + sizeof(_standardHeader));
palette = (uint8 *)mscreenHeader + mscreenHeader->palette;
palette[0] = 0; // always set colour 0 to black
palette[1] = 0; // because most background screen palettes have a bright colour 0
palette[2] = 0; // although it should come out as black in the game!
palette[3] = 0;
return palette;
}
//-----------------------------------------------------------------------------------------------------------------------
// returns a pointer to the start of the palette match table, given the pointer to the start of the screen file
// assumes it has been passed a pointer to a valid screen file
uint8 *FetchPaletteMatchTable(uint8 *screenFile) // James 09dec96
{
_multiScreenHeader *mscreenHeader = (_multiScreenHeader *) (screenFile + sizeof(_standardHeader));
return (uint8 *) mscreenHeader + mscreenHeader->paletteTable;
}
//-----------------------------------------------------------------------------------------------------------------------
// returns a pointer to the screen header, given the pointer to the start of the screen file
// assumes it has been passed a pointer to a valid screen file
_screenHeader *FetchScreenHeader(uint8 *screenFile) //Chris 04Oct96
{
// Get the table
_multiScreenHeader *mscreenHeader = (_multiScreenHeader *) (screenFile + sizeof(_standardHeader));
return (_screenHeader*) ((uint8 *) mscreenHeader + mscreenHeader->screen);
}
//-----------------------------------------------------------------------------------------------------------------------
// returns a pointer to the requested layer header, given the pointer to the start of the screen file
// drops out if the requested layer number exceeds the number of layers on this screen
// assumes it has been passed a pointer to a valid screen file
_layerHeader *FetchLayerHeader(uint8 *screenFile, uint16 layerNo) //Chris 04Oct96
{
_screenHeader *screenHead;
screenHead = FetchScreenHeader(screenFile);
#ifdef _DEBUG
if (layerNo > (screenHead->noLayers-1)) // layer number too large!
Con_fatal_error("FetchLayerHeader(%d) invalid layer number! (%s line %u)",layerNo,__FILE__,__LINE__);
#endif
_multiScreenHeader *mscreenHeader = (_multiScreenHeader *) (screenFile + sizeof(_standardHeader));
return (_layerHeader *) ((uint8 *) mscreenHeader + mscreenHeader->layers + (layerNo * sizeof(_layerHeader)));
}
//---------------------------------------------------------------
// returns a pointer to the start of the shading mask, given the pointer to the start of the screen file
// assumes it has been passed a pointer to a valid screen file
uint8 *FetchShadingMask(uint8 *screenFile) // James 08apr97
{
_multiScreenHeader *mscreenHeader = (_multiScreenHeader *) (screenFile + sizeof(_standardHeader));
return (uint8 *) mscreenHeader + mscreenHeader->maskOffset;
}
//-----------------------------------------------------------------------------------------------------------------------
// returns a pointer to the anim header, given the pointer to the start of the anim file
// assumes it has been passed a pointer to a valid anim file
_animHeader *FetchAnimHeader(uint8 *animFile) // (25sep96JEL)
{
return (_animHeader *) (animFile + sizeof(_standardHeader));
}
//---------------------------------------------------------------
// returns a pointer to the requested frame number's cdtEntry, given the pointer to the start of the anim file
// drops out if the requested frame number exceeds the number of frames in this anim
// assumes it has been passed a pointer to a valid anim file
_cdtEntry *FetchCdtEntry(uint8 *animFile, uint16 frameNo) // Chris 09Oct96
{
_animHeader *animHead;
animHead = FetchAnimHeader(animFile);
#ifdef _DEBUG
if (frameNo > (animHead->noAnimFrames-1)) // frame number too large!
Con_fatal_error("FetchCdtEntry(animFile,%d) - anim only %d frames (%s line %u)",frameNo,animHead->noAnimFrames,__FILE__,__LINE__);
#endif
return (_cdtEntry *) ( (uint8 *)animHead + sizeof(_animHeader) + frameNo * sizeof(_cdtEntry) );
}
//---------------------------------------------------------------
// returns a pointer to the requested frame number's header, given the pointer to the start of the anim file
// drops out if the requested frame number exceeds the number of frames in this anim
// assumes it has been passed a pointer to a valid anim file
_frameHeader *FetchFrameHeader(uint8 *animFile, uint16 frameNo) // James 31oct96
{
// required address = (address of the start of the anim header) + frameOffset
return (_frameHeader *) (animFile + sizeof(_standardHeader) + (FetchCdtEntry(animFile,frameNo)->frameOffset) );
}
//---------------------------------------------------------------
// Returns a pointer to the requested parallax layer data.
// Assumes it has been passed a pointer to a valid screen file.
_parallax *FetchBackgroundParallaxLayer(uint8 *screenFile, int layer) // Chris 04Oct96
{
_multiScreenHeader *mscreenHeader = (_multiScreenHeader *) (screenFile + sizeof(_standardHeader));
#ifdef _DEBUG
if (mscreenHeader->bg_parallax[layer] == 0)
Con_fatal_error("FetchBackgroundParallaxLayer(%d) - No parallax layer exists (%s line %u)",layer,__FILE__,__LINE__);
#endif
return (_parallax *) ((uint8 *) mscreenHeader + mscreenHeader->bg_parallax[layer]);
}
//---------------------------------------------------------------
_parallax *FetchBackgroundLayer(uint8 *screenFile) // Chris 04Oct96
{
_multiScreenHeader *mscreenHeader = (_multiScreenHeader *) (screenFile + sizeof(_standardHeader));
#ifdef _DEBUG
if (mscreenHeader->screen == 0)
Con_fatal_error("FetchBackgroundLayer (%d) - No background layer exists (%s line %u)",__FILE__,__LINE__);
#endif
return (_parallax *) ((uint8 *) mscreenHeader + mscreenHeader->screen + sizeof(_screenHeader));
}
//---------------------------------------------------------------
_parallax *FetchForegroundParallaxLayer(uint8 *screenFile, int layer) // Chris 04Oct96
{
_multiScreenHeader *mscreenHeader = (_multiScreenHeader *) (screenFile + sizeof(_standardHeader));
#ifdef _DEBUG
if (mscreenHeader->fg_parallax[layer] == 0)
Con_fatal_error("FetchForegroundParallaxLayer(%d) - No parallax layer exists (%s line %u)",layer,__FILE__,__LINE__);
#endif
return (_parallax *) ((uint8 *) mscreenHeader + mscreenHeader->fg_parallax[layer]);
}
//---------------------------------------------------------------
uint8 errorLine[128];
//---------------------------------------------------------------
uint8 *FetchTextLine(uint8 *file, uint32 text_line) //Tony24Oct96
{
// Get the table
_standardHeader *fileHeader;
uint32 *point;
_textHeader *text_header = (_textHeader *) (file + sizeof(_standardHeader));
if (text_line>=text_header->noOfLines) // (James08aug97)
{
fileHeader = (_standardHeader*)file;
sprintf ((char*)errorLine, "xxMissing line %d of %s (only 0..%d)", text_line, fileHeader->name, text_header->noOfLines-1);
errorLine[0]=0; // first 2 chars are NULL so that actor-number comes out as '0'
errorLine[1]=0;
return(errorLine);
// GOT RID OF CON_FATAL_ERROR HERE BECAUSE WE DON'T WANT IT TO CRASH OUT ANY MORE!
// Con_fatal_error("FetchTextLine cannot get %d, only 0..%d avail (%s line %u)", text_line, text_header->noOfLines-1,__FILE__,__LINE__);
}
point=(uint32*) text_header+1; //point to the lookup table
return( (uint8*) (file+ *(point+text_line)) );
}
//---------------------------------------------------------------
// Used for testing text & speech (see FN_I_speak in speech.cpp)
uint8 CheckTextLine(uint8 *file, uint32 text_line) // (James26jun97)
{
_textHeader *text_header = (_textHeader *) (file + sizeof(_standardHeader));
if (text_line>=text_header->noOfLines)
return(0); // out of range => invalid
else
return(1); // valid
}
//---------------------------------------------------------------
uint8 *FetchObjectName(int32 resourceId) // James15jan97
{
_standardHeader *header;
header = (_standardHeader*) res_man.Res_open(resourceId);
res_man.Res_close(resourceId);
return (header->name); // note this pointer is no longer valid, but it should be ok until another resource is opened!
}
//---------------------------------------------------------------
//---------------------------------------------------------------
//---------------------------------------------------------------
//---------------------------------------------------------------
//---------------------------------------------------------------
//---------------------------------------------------------------
//---------------------------------------------------------------
//---------------------------------------------------------------
//---------------------------------------------------------------

44
sword2/protocol.h Normal file
View file

@ -0,0 +1,44 @@
/* 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$
*/
//the usual suspects (the usual suspicions)
#ifndef _PROTOCOL
#define _PROTOCOL
#include "driver/driver96.h"
#include "header.h"
uint8 *FetchPalette(uint8 *screenFile); // Chris 04Oct96
_screenHeader *FetchScreenHeader(uint8 *screenFile); //Chris 04Oct96
_layerHeader *FetchLayerHeader(uint8 *screenFile, uint16 layerNo); //Chris 04Oct96
uint8 *FetchShadingMask(uint8 *screenFile); // James 08apr97
_animHeader *FetchAnimHeader(uint8 *animFile); // (25sep96JEL)
_cdtEntry *FetchCdtEntry(uint8 *animFile, uint16 frameNo); // (31oct96 JEL)
_frameHeader *FetchFrameHeader(uint8 *animFile, uint16 frameNo); // (25sep96JEL)
_parallax *FetchBackgroundParallaxLayer(uint8 *screenFile, int layer); // Chris 04Oct96
_parallax *FetchBackgroundLayer(uint8 *screenFile); // Chris 04Oct96
_parallax *FetchForegroundParallaxLayer(uint8 *screenFile, int layer); // Chris 04Oct96
uint8 *FetchTextLine(uint8 *file, uint32 text_line); //Tony24Oct96
uint8 CheckTextLine(uint8 *file, uint32 text_line); // (James26jun97)
uint8 *FetchPaletteMatchTable(uint8 *screenFile); // James 09dec96
uint8 *FetchObjectName(int32 resourceId); // James15jan97
#endif

1539
sword2/resman.cpp Normal file

File diff suppressed because it is too large Load diff

101
sword2/resman.h Normal file
View file

@ -0,0 +1,101 @@
/* 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$
*/
#ifndef RESMAN_H
#define RESMAN_H
//#include "src\driver96.h"
#include "memory.h"
#define MAX_res_files 20
#define RES_locked 1
#define RES_perm 2
class resMan
{
public:
void InitResMan(void); //read in the config file
void Close_ResMan(void); //Tony29May96
//----
uint8 *Res_open(uint32 res); //returns ad of resource. Loads if not in memory
//retains a count
//resource can be aged out of memory if count=0
//the resource is locked while count!=0
void Res_close(uint32 res); //decrements the count
//----
uint8 Res_check_valid( uint32 res ); // returns '0' if resource out of range or null, otherwise '1' for ok
//resource floats when count=0
//----
char *Fetch_cluster(uint32 res); //for mem_view to query the owners of mem blocs
uint32 Fetch_age(uint32 res); //
uint32 Fetch_count(uint32 count); //
uint32 Help_the_aged_out(void); //Tony10Oct96
uint32 Res_fetch_len( uint32 res ); //Tony27Jan96
void Res_next_cycle( void );
uint32 Res_fetch_useage( void );
void GetCd(int cd); // Prompts the user for the specified CD.
int WhichCd() {return curCd;}
//----console commands
void Print_console_clusters(void); //Tony10Oct96
void Examine_res(uint8 *input); //Tony23Oct96
void Kill_all_res(uint8 wantInfo); //Tony29Nov96
void Kill_all_objects(uint8 wantInfo); // James17jan97
void Remove_res(uint32 res); //Tony10Jan97
void Remove_all_res(void); // James24mar97
void Kill_res(uint8 *res); //Tony23Oct96
char *GetCdPath( void ); // Chris 9Apr97
mem **resList; //pointer to a pointer (or list of pointers in-fact)
private:
int curCd;
uint32 total_res_files;
uint32 total_clusters;
uint32 current_memory_useage;
uint32 resTime; //inc's each time Res_open is called and is given to resource as its age
//cannot be allowed to start at 0! (a pint if you can tell me why)
uint32 *age;
uint16 *res_conv_table; //Gode generated res-id to res number/rel number conversion table
uint16 *count;
char resource_files[MAX_res_files][20];
uint8 cdTab[MAX_res_files]; // Location of each cluster.
char cdPath[256]; // Drive letter of the CD-ROM drive or false CD path.
void CacheNewCluster(uint32 newCluster);
char cdDrives[24];
};
extern resMan res_man; //declare the object global
#endif

3089
sword2/router.cpp Normal file

File diff suppressed because it is too large Load diff

58
sword2/router.h Normal file
View file

@ -0,0 +1,58 @@
/* 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$
*/
#ifndef _ROUTER_H
#define _ROUTER_H
//#include "src\driver96.h"
#include "memory.h"
#include "object.h"
typedef struct _walkData
{
uint16 frame;
int16 x;
int16 y;
uint8 step;
uint8 dir;
} _walkData;
int32 RouteFinder(Object_mega *ob_mega, Object_walkdata *ob_walkdata, int32 x, int32 y, int32 dir);
void EarlySlowOut(Object_mega *ob_mega, Object_walkdata *ob_walkdata);
void AllocateRouteMem(void);
_walkData* LockRouteMem(void);
void FloatRouteMem(void);
void FreeRouteMem(void);
void FreeAllRouteMem(void);
void PlotWalkGrid(void);
void AddWalkGrid(int32 gridResource);
void RemoveWalkGrid(int32 gridResource);
void ClearWalkGridList(void);
uint8 CheckForCollision(void);
//--------------------------------------------------------------------------------------
#endif

556
sword2/save_rest.cpp Normal file
View file

@ -0,0 +1,556 @@
/* 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$
*/
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// SAVE_REST.CPP save, restore & restart functions
//
// James 05feb97
//
// "Jesus Saves", but could he Restore or Restart? He can now...
//
//------------------------------------------------------------------------------------
//#include <direct.h> directx?
#include <stdio.h>
#include <stdlib.h>
#include "driver/driver96.h"
#include "console.h"
#include "defs.h"
#include "function.h" // for engine_logic, engine_graph, etc
#include "interpreter.h" // for IR_CONT, etc
#include "layers.h"
#include "logic.h"
#include "memory.h"
#include "object.h"
#include "protocol.h"
#include "resman.h"
#include "router.h"
#include "save_rest.h"
#include "scroll.h" // for Set_scrolling()
#include "sound.h"
#include "walker.h"
//------------------------------------------------------------------------------------
#define MAX_FILENAME_LEN 128 // max length of a savegame filename, including full path
//------------------------------------------------------------------------------------
// local function prototypes
void GetPlayerStructures(void); // James27feb97
void PutPlayerStructures(void); // James27feb97
uint32 SaveData(uint16 slotNo, uint8 *buffer, uint32 bufferSize);
uint32 RestoreData(uint16 slotNo, uint8 *buffer, uint32 bufferSize);
uint32 CalcChecksum(uint8 *buffer, uint32 size); // James04aug97
//------------------------------------------------------------------------------------
typedef struct // savegame file header (James06feb97)
{
uint32 checksum; // sum of all bytes in file, excluding this uint32
char description[SAVE_DESCRIPTION_LEN]; // player's description of savegame
uint32 varLength; // length of global variables resource
uint32 screenId; // resource id of screen file
uint32 runListId; // resource id of run list
uint32 feet_x; // copy of this_screen.feet_x
uint32 feet_y; // copy of this_screen.feet_y
uint32 music_id; // copy of 'looping_music_id'
_object_hub player_hub; // copy of player object's object_hub structure
Object_logic logic; // copy of player character logic structure
Object_graphic graphic; // copy of player character graphic structure
Object_mega mega; // copy of player character mega structure
}
_savegameHeader;
// savegame consists of header & global variables resource
_savegameHeader header; // global because easier to copy to/from player object structures
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// SAVE GAME
//------------------------------------------------------------------------------------
uint32 SaveGame(uint16 slotNo, uint8 *desc) // (James05feb97)
{
mem *saveBufferMem;
uint32 bufferSize;
uint32 errorCode;
//------------------------------------------------------
// allocate the savegame buffer
bufferSize = FindBufferSize();
saveBufferMem = Twalloc( bufferSize, MEM_locked, UID_savegame_buffer );
FillSaveBuffer(saveBufferMem, bufferSize, desc);
//------------------------------------------------------
// save it (platform-specific)
errorCode = SaveData( slotNo, saveBufferMem->ad, bufferSize ); // save the buffer
//------------------------------------------------------
// free the buffer
Free_mem( saveBufferMem );
//------------------------------------------------------
return(errorCode);
}
//------------------------------------------------------------------------------------
// calculate size of required savegame buffer
uint32 FindBufferSize( void )
{
return (sizeof(header) + res_man.Res_fetch_len(1)); // size of savegame header + size of global variables
}
//------------------------------------------------------------------------------------
void FillSaveBuffer(mem *buffer, uint32 size, uint8 *desc)
{
uint8 *varsRes;
//------------------------------------------------------
// set up the header
// 'checksum' gets filled in last of all
sprintf(header.description, "%s", (char*)desc); // player's description of savegame
header.varLength = res_man.Res_fetch_len(1); // length of global variables resource
header.screenId = this_screen.background_layer_id; // resource id of current screen file
header.runListId = LLogic.Return_run_list(); // resource id of current run-list
header.feet_x = this_screen.feet_x; // those scroll position control things
header.feet_y = this_screen.feet_y; //
header.music_id = looping_music_id; // id of currently looping music (or zero)
// object hub
memcpy (&header.player_hub, res_man.Res_open(CUR_PLAYER_ID) + sizeof(_standardHeader), sizeof(_object_hub));
res_man.Res_close(CUR_PLAYER_ID);
// logic, graphic & mega structures
GetPlayerStructures(); // copy the 4 essential player object structures into the header
//------------------------------------------------------
// copy the header to the buffer
memcpy( buffer->ad, &header, sizeof(header) ); // copy the header to the savegame buffer
//------------------------------------------------------
// copy the global variables to the buffer
varsRes = res_man.Res_open(1); // open variables resource
memcpy( buffer->ad + sizeof(header), varsRes, header.varLength ); // copy that to the buffer, following the header
res_man.Res_close(1); // close variables resource
//------------------------------------------------------
// set the checksum & copy that to the buffer (James05aug97)
header.checksum = CalcChecksum((buffer->ad)+sizeof(header.checksum), size-sizeof(header.checksum));
memcpy( buffer->ad, &header.checksum, sizeof(header.checksum) ); // copy the header to the savegame buffer
//------------------------------------------------------
}
//------------------------------------------------------------------------------------
uint32 SaveData(uint16 slotNo, uint8 *buffer, uint32 bufferSize)
{
char saveFileName[MAX_FILENAME_LEN];
FILE *fp;
uint32 itemsWritten;
//create saves directory just in case not there
_mkdir("saves");
sprintf(saveFileName, "saves\\savegame.%.3d", slotNo); // construct filename
fp = fopen(saveFileName, "wb"); // attempt to open file for writing
if (fp==NULL)
{
return(SR_ERR_FILEOPEN); // error: couldn't open file
}
else
{
// itemsWritten = fwrite(sourceAddress, size, count, fp);
itemsWritten = fwrite(buffer, 1, bufferSize, fp); // write the buffer
fclose(fp); // close savegame file
if (itemsWritten == bufferSize) // if we successfully wrote it all
return(SR_OK); // buffer saved ok
else
return(SR_ERR_WRITEFAIL); // write failed for some reason (could be hard drive full)
}
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// RESTORE GAME
//------------------------------------------------------------------------------------
uint32 RestoreGame(uint16 slotNo) // (James05feb97)
{
mem *saveBufferMem;
uint32 bufferSize;
uint32 errorCode;
//------------------------------------------------------
// allocate the savegame buffer
bufferSize = FindBufferSize();
saveBufferMem = Twalloc( bufferSize, MEM_locked, UID_savegame_buffer );
//------------------------------------------------------
// read the savegame file into our buffer
errorCode = RestoreData( slotNo, saveBufferMem->ad, bufferSize ); // load savegame into buffer
//------------------------------------------------------
// if it was read in successfully, then restore the game from the buffer & free the buffer
if (errorCode == SR_OK)
{
errorCode = RestoreFromBuffer(saveBufferMem, bufferSize);
// Note that the buffer has been freed inside RestoreFromBuffer,
// in order to clear it from memory before loading in the new screen & runlist
}
else
Free_mem( saveBufferMem ); // because RestoreFromBuffer would have freed it
//------------------------------------------------------
return(errorCode); // game restored ok
}
//------------------------------------------------------------------------------------
uint32 RestoreData(uint16 slotNo, uint8 *buffer, uint32 bufferSize)
{
char saveFileName[MAX_FILENAME_LEN];
FILE *fp;
uint32 itemsRead;
sprintf(saveFileName, "saves\\savegame.%.3d", slotNo); // construct filename
fp = fopen(saveFileName, "rb"); // attempt to open file for reading
if (fp==NULL)
{
return(SR_ERR_FILEOPEN); // error: couldn't open file
}
else
{
// itemsRead = fread(destAddress, size, count, fp);
itemsRead = fread(buffer, 1, bufferSize, fp); // read savegame into the buffer
if (itemsRead == bufferSize) // if we successfully read it all
{
fclose(fp); // close savegame file
return(SR_OK); // file read ok
}
else // didn't read the expected amount of data for some reason
{
if (ferror(fp)) // if it was a genuine read error, before reaching the end of the file
{
fclose(fp); // close savegame file
return(SR_ERR_READFAIL); // error: read failed
}
else // we reached the end of the file before we filled the savegame buffer (ie. incompatible savegame file!)
{
fclose(fp); // close savegame file
return(SR_ERR_INCOMPATIBLE); // error: incompatible save-data - can't use!
}
}
}
}
//------------------------------------------------------------------------------------
uint32 RestoreFromBuffer(mem *buffer, uint32 size)
{
uint8 *varsRes;
int32 pars[2];
memcpy( &header, buffer->ad, sizeof(header) ); // get a copy of the header from the savegame buffer
//------------------------------------------------------
// Calc checksum & check that aginst the value stored in the header (James05aug97)
if (header.checksum != CalcChecksum((buffer->ad)+sizeof(header.checksum), size-sizeof(header.checksum)))
{
Free_mem( buffer );
return(SR_ERR_INCOMPATIBLE); // error: incompatible save-data - can't use!
}
//------------------------------------------------------
// check savegame against length of current global variables resource
// This would most probably be trapped by the checksum test anyway, but it doesn't do any harm to check this as well
// Note that during development, earlier savegames will often be shorter than the current expected length
if (header.varLength != res_man.Res_fetch_len(1)) // if header contradicts actual current size of global variables
{
Free_mem( buffer );
return(SR_ERR_INCOMPATIBLE); // error: incompatible save-data - can't use!
}
//----------------------------------
// clean out system
res_man.Kill_all_res(0); // trash all resources from memory except player object & global variables
LLogic.Reset_kill_list(); // clean out the system kill list (no more objects to kill)
//----------------------------------
// get player character data from savegame buffer
// object hub is just after the standard header
memcpy (res_man.Res_open(CUR_PLAYER_ID) + sizeof(_standardHeader), &header.player_hub, sizeof(_object_hub));
res_man.Res_close(CUR_PLAYER_ID);
PutPlayerStructures(); // fill in the 4 essential player object structures from the header
//----------------------------------
// get variables resource from the savegame buffer
varsRes = res_man.Res_open(1); // open variables resource
memcpy( varsRes, buffer->ad + sizeof(header), header.varLength );// copy that to the buffer, following the header
res_man.Res_close(1); // close variables resource
Free_mem( buffer ); // free it now, rather than in RestoreGame, to unblock memory before new screen & runlist loaded
pars[0] = header.screenId;
pars[1] = 1;
FN_init_background(pars);
this_screen.new_palette=99; // (JEL08oct97) so palette not restored immediately after control panel - we want to fade up instead!
this_screen.feet_x = header.feet_x; // these need setting after the defaults get set in FN_init_background
this_screen.feet_y = header.feet_y; // remember that these can change through the game, so need saving & restoring too
LLogic.Express_change_session(header.runListId); // start the new run list
//----------------------------------------------------------------------------
// (James01aug97)
// Force in the new scroll position, so unsightly scroll-catch-up does not occur
// when screen first draws after returning from restore panel
this_screen.player_feet_x = header.mega.feet_x; // set 'this_screen's record of player position
this_screen.player_feet_y = header.mega.feet_y; // - ready for Set_scrolling()
if (this_screen.scroll_flag) // if this screen is wide
Set_scrolling(); // recompute the scroll offsets now,
//----------------------------------------------------------------------------
// Any music required will be started after we've returned from Restore_control()
// - see System_menu() in mouse.cpp!
looping_music_id = header.music_id;
//------------------------------------------------------
//--------------------------------------
// Write to walkthrough file (zebug0.txt)
#ifdef _DEBUG
Zdebug(0,"*************************************");
Zdebug(0,"RESTORED GAME \"%s\"", header.description);
Zdebug(0,"*************************************");
// Also write this to system debug file
Zdebug("*************************************");
Zdebug("RESTORED GAME \"%s\"", header.description);
Zdebug("*************************************");
#endif
//--------------------------------------
return(SR_OK); // game restored ok
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// GetSaveDescription - PC version...
//------------------------------------------------------------------------------------
uint32 GetSaveDescription(uint16 slotNo, uint8 *description) // (James05feb97)
{
char saveFileName[MAX_FILENAME_LEN];
_savegameHeader header;
FILE *fp;
sprintf(saveFileName, "saves\\savegame.%.3d", slotNo); // construct filename
fp = fopen(saveFileName, "rb"); // attempt to open file for reading
if (fp==NULL)
{
return(SR_ERR_FILEOPEN); // error: couldn't open file
}
else
{
// fread(destAddress, size, count, fp);
fread(&header, sizeof(header), 1, fp); // read header
fclose(fp);
sprintf((char*)description, header.description);
return(SR_OK);
}
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
void GetPlayerStructures(void) // James27feb97
{
// request the player object structures which need saving
uint32 null_pc=7; // script no. 7 - 'george_savedata_request' calls FN_pass_player_savedata
char *raw_script_ad;
_standardHeader *head;
head = (_standardHeader*) res_man.Res_open(CUR_PLAYER_ID);
if (head->fileType!=GAME_OBJECT)
Con_fatal_error("incorrect CUR_PLAYER_ID=%d (%s line %u)",CUR_PLAYER_ID,__FILE__,__LINE__);
raw_script_ad = (char *)head; // (head+1) + sizeof(_object_hub); //get to raw script data
RunScript( raw_script_ad, raw_script_ad, &null_pc );
res_man.Res_close(CUR_PLAYER_ID);
}
//------------------------------------------------------------------------------------
void PutPlayerStructures(void) // James27feb97 (updated by James on 29july97)
{
// fill out the player object structures from the savegame structures
// also run the appropriate scripts to set up george's anim tables & walkdata, and nico's anim tables
uint32 null_pc=8; // script no. 8 - 'george_savedata_return' calls FN_get_player_savedata
char *raw_script_ad;
_standardHeader *head;
head = (_standardHeader*) res_man.Res_open(CUR_PLAYER_ID);
if (head->fileType!=GAME_OBJECT)
Con_fatal_error("incorrect CUR_PLAYER_ID=%d (%s line %u)",CUR_PLAYER_ID,__FILE__,__LINE__);
raw_script_ad = (char *)head; // (head+1) + sizeof(_object_hub); //get to raw script data
null_pc=8; // script no. 8 - 'george_savedata_return' calls FN_get_player_savedata
RunScript( raw_script_ad, raw_script_ad, &null_pc );
null_pc=14; // script no. 14 - 'set_up_nico_anim_tables'
RunScript( raw_script_ad, raw_script_ad, &null_pc );
switch (header.mega.megaset_res) // which megaset was the player at the time of saving?
{
case 36: // GeoMega:
null_pc=9; // script no.9 - 'player_is_george'
break;
case 2003: // GeoMegaB:
null_pc=13; // script no.13 - 'player_is_georgeB'
break;
case 1366: // NicMegaA:
null_pc=11; // script no.11 - 'player_is_nicoA'
break;
case 1437: // NicMegaB:
null_pc=12; // script no.12 - 'player_is_nicoB'
break;
case 1575: // NicMegaC:
null_pc=10; // script no.10 - 'player_is_nicoC'
break;
}
RunScript( raw_script_ad, raw_script_ad, &null_pc );
res_man.Res_close(CUR_PLAYER_ID);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
int32 FN_pass_player_savedata(int32 *params) // James27feb97
{
// copies the 4 essential player structures into the savegame header
// - run script 7 of player object to request this
// remember, we cannot simply read a compact any longer but instead must request it from the object itself
// params: 0 pointer to object's logic structure
// 1 pointer to object's graphic structure
// 2 pointer to object's mega structure
// copy from player object to savegame header
memcpy( &header.logic, (uint8*)params[0], sizeof(Object_logic) );
memcpy( &header.graphic, (uint8*)params[1], sizeof(Object_graphic) );
memcpy( &header.mega, (uint8*)params[2], sizeof(Object_mega) );
return(IR_CONT); //makes no odds
}
//------------------------------------------------------------------------------------
int32 FN_get_player_savedata(int32 *params) // James27feb97
{
// reverse of FN_pass_player_savedata
// - run script 8 of player object
// params: 0 pointer to object's logic structure
// 1 pointer to object's graphic structure
// 2 pointer to object's mega structure
Object_logic *ob_logic = (Object_logic*) params[0];
Object_graphic *ob_graphic = (Object_graphic*) params[1];
Object_mega *ob_mega = (Object_mega*) params[2];
int32 pars[3];
// copy from savegame header to player object
memcpy( (uint8*)ob_logic, &header.logic, sizeof(Object_logic) );
memcpy( (uint8*)ob_graphic, &header.graphic, sizeof(Object_graphic) );
memcpy( (uint8*)ob_mega, &header.mega, sizeof(Object_mega) );
// any walk-data must be cleared - the player will be set to stand if he was walking when saved
if (ob_mega->currently_walking) // if the player was walking when game was saved
{
ob_mega->currently_walking = 0; // clear the flag
ob_mega->colliding = 0; // reset this just in case
pars[0] = (int32)ob_graphic; // pointer to object's graphic structure
pars[1] = (int32)ob_mega; // pointer to object's mega structure
pars[2] = ob_mega->current_dir; // target direction
FN_stand(pars); // set player to stand
ob_logic->looping = 0; // reset looping flag (which would have been '1' during FN_walk)
}
return(IR_CONT); //makes no odds
}
//------------------------------------------------------------------------------------
uint32 CalcChecksum(uint8 *buffer, uint32 size) // (James05aug97)
{
uint32 total=0;
uint32 pos;
for (pos=0; pos<size; pos++)
total += buffer[pos];
return(total);
}

47
sword2/save_rest.h Normal file
View file

@ -0,0 +1,47 @@
/* 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$
*/
#ifndef SAVE_REST_H
#define SAVE_REST_H
//#include "src\driver96.h"
#include "memory.h"
#define SAVE_DESCRIPTION_LEN 64
uint32 SaveGame(uint16 slotNo, uint8 *description);
uint32 RestoreGame(uint16 slotNo);
uint32 GetSaveDescription(uint16 slotNo, uint8 *description);
void FillSaveBuffer(mem *buffer, uint32 size, uint8 *desc);
uint32 RestoreFromBuffer(mem *buffer, uint32 size);
uint32 FindBufferSize( void );
// Save & Restore error codes
// ERROR CODE VALUE MEANING REASON
// ========== ===== ======= ======
#define SR_OK 0x00000000 // ok No worries
#define SR_ERR_FILEOPEN 0x00000001 // can't open file Could create file for saving, or couldn't find file for loading
#define SR_ERR_INCOMPATIBLE 0x00000002 // (RestoreGame only) incompatible savegame data Savegame file is obsolete. (Won't happen after development stops)
#define SR_ERR_READFAIL 0x00000003 // (RestoreGame only) failed on reading savegame file Something screwed up during the fread()
#define SR_ERR_WRITEFAIL 0x00000004 // (SaveGame only) failed on writing savegame file Something screwed up during the fwrite() - could be hard-drive full..?
#endif

154
sword2/scroll.cpp Normal file
View file

@ -0,0 +1,154 @@
/* 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$
*/
//------------------------------------------------------------------------------------
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
//#include "src\driver96.h"
#include "build_display.h"
#include "debug.h"
#include "defs.h"
#include "header.h"
#include "interpreter.h"
#include "layers.h"
#include "memory.h"
#include "object.h"
#include "protocol.h"
#include "resman.h"
#include "scroll.h"
//------------------------------------------------------------------------------------
#define MAX_SCROLL_DISTANCE 8 // max no of pixel allowed to scroll per cycle
//------------------------------------------------------------------------------------
uint8 scroll_fraction=16; // used to be a define, but now it's flexible (see new functions below)
//------------------------------------------------------------------------------------
void Set_scrolling(void) //S2.1(2Mar94jel) refurnished Tony25Sept96 :-)
{
// feet_x = 128+320 // normally we aim to get George's feet at (320,250) from top left of screen window
// feet_y = 128+250
// set scroll offsets according to the player's coords
int16 offset_x;
int16 offset_y;
int16 dx, dy;
uint16 scroll_distance_x; // how much we want to scroll
uint16 scroll_distance_y;
if (SCROLL_X || SCROLL_Y) // if the scroll offsets are being forced in script (05feb97 JAMES)
{
// ensure not too far right
if (SCROLL_X < this_screen.max_scroll_offset_x)
this_screen.scroll_offset_x = SCROLL_X;
else
this_screen.scroll_offset_x = this_screen.max_scroll_offset_x;
// ensure not too far down
if (SCROLL_Y < this_screen.max_scroll_offset_y)
this_screen.scroll_offset_y = SCROLL_Y;
else
this_screen.scroll_offset_y = this_screen.max_scroll_offset_y;
}
else
{
offset_x = this_screen.player_feet_x-this_screen.feet_x; // George's offset from the centre - the desired position for him
offset_y = this_screen.player_feet_y-this_screen.feet_y;
// prevent scrolling too far left/right/up/down
offset_x = offset_x < 0 ? 0 : ( (uint32)offset_x > this_screen.max_scroll_offset_x ? this_screen.max_scroll_offset_x : offset_x );
offset_y = offset_y < 0 ? 0 : ( (uint32)offset_y > this_screen.max_scroll_offset_y ? this_screen.max_scroll_offset_y : offset_y );
if (this_screen.scroll_flag==2) // first time on this screen - need absolute scroll immediately!
{
//Zdebug(42,"init scroll");
this_screen.scroll_offset_x = offset_x;
this_screen.scroll_offset_y = offset_y;
this_screen.scroll_flag=1;
}
else // catch up with required scroll offsets - speed depending on distance to catch up (dx and dy) & 'SCROLL_FRACTION' used
{ // but limit to certain number of pixels per cycle (MAX_SCROLL_DISTANCE)
dx = this_screen.scroll_offset_x - offset_x;
dy = this_screen.scroll_offset_y - offset_y;
if (dx < 0) // current scroll_offset_x is less than the required value
{
scroll_distance_x = (1+(-dx)/scroll_fraction); // => inc by (fraction of the differnce) NB. dx is -ve, so we subtract dx/SCROLL_FRACTION
this_screen.scroll_offset_x += scroll_distance_x < MAX_SCROLL_DISTANCE ? scroll_distance_x : MAX_SCROLL_DISTANCE;
}
else if (dx > 0) // current scroll_offset_x is greater than the required value
{
scroll_distance_x = (1+dx/scroll_fraction); // => dec by (fraction of the differnce)
this_screen.scroll_offset_x -= scroll_distance_x < MAX_SCROLL_DISTANCE ? scroll_distance_x : MAX_SCROLL_DISTANCE;
} // NB. I'm adding 1 to the result of dx/SCROLL_FRACTION, because it would otherwise
// not scroll at all when dx < SCROLL_FRACTION
if (dy < 0)
{
scroll_distance_y = (1+(-dy)/scroll_fraction);
this_screen.scroll_offset_y += scroll_distance_y < MAX_SCROLL_DISTANCE ? scroll_distance_y : MAX_SCROLL_DISTANCE;
}
else if (dy > 0)
{
scroll_distance_y = (1+dy/scroll_fraction);
this_screen.scroll_offset_y -= scroll_distance_y < MAX_SCROLL_DISTANCE ? scroll_distance_y : MAX_SCROLL_DISTANCE;
}
}
}
}
//------------------------------------------------------------------------------------
int32 FN_set_scroll_coordinate(int32 *params) //Tony25Sept96
{
// set the special scroll offset variables
// call when starting screens and to change the camera within screens
// call AFTER FN_init_background() to override the defaults
// called feet_x and feet_y to retain intelectual compatibility with Sword1 !
// feet_x & feet_y refer to the physical screen coords where the system will try to maintain George's feet
// param 0 feet_x value
// param 1 feet_y value
this_screen.feet_x = params[0];
this_screen.feet_y = params[1];
return(IR_CONT);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
int32 FN_set_scroll_speed_normal(int32 *params) // James08aug97
{
scroll_fraction=16;
return(IR_CONT);
}
//------------------------------------------------------------------------------------
int32 FN_set_scroll_speed_slow(int32 *params) // James08aug97
{
scroll_fraction=32;
return(IR_CONT);
}
//------------------------------------------------------------------------------------

29
sword2/scroll.h Normal file
View file

@ -0,0 +1,29 @@
/* 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$
*/
//the usual suspects
#ifndef _SCROLL
#define _SCROLL
//#include "src\driver96.h"
void Set_scrolling(void);
#endif

504
sword2/sound.cpp Normal file
View file

@ -0,0 +1,504 @@
/* 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$
*/
//--------------------------------------------------------------------------------------
// BROKEN SWORD 2
//
// SOUND.CPP Contains the sound engine, fx & music functions
// Some very 'sound' code in here ;)
//
// (16Dec96 JEL)
//
//--------------------------------------------------------------------------------------
#include <stdio.h>
//#include "src\driver96.h"
#include "console.h"
#include "defs.h" // for RESULT
#include "interpreter.h"
#include "protocol.h" // for FetchObjectName() for debugging FN_play_fx
#include "resman.h"
#include "sound.h"
//--------------------------------------------------------------------------------------
typedef struct
{
uint32 resource; // resource id of sample
uint32 fetchId; // Id of resource in PSX CD queue. :)
uint16 delay; // cycles to wait before playing (or 'random chance' if FX_RANDOM)
uint8 volume; // 0..16
int8 pan; // -16..16
uint8 type; // FX_SPOT, FX_RANDOM or FX_LOOP
} _fxq_entry;
#define FXQ_LENGTH 32 // max number of fx in queue at once [DO NOT EXCEED 255]
_fxq_entry fxq[FXQ_LENGTH];
//--------------------------------------------------------------------------------------
uint32 looping_music_id=0; // used to store id of tunes that loop, for save & restore
char musicDirectory[120];
//--------------------------------------------------------------------------------------
// local function prototypes
void Trigger_fx (uint8 j);
//--------------------------------------------------------------------------------------
// initialise the fxq by clearing all the entries
void Init_fx_queue(void)
{
uint8 j;
for (j=0; j < FXQ_LENGTH; j++) // scan the queue
{
fxq[j].resource = 0; // 0 resource means 'empty' slot
fxq[j].fetchId = 0; // Not being fetched.
}
}
//--------------------------------------------------------------------------------------
// process the fxq once every game cycle
void Process_fx_queue(void)
{
uint8 j; // assuming FXQ_LENGTH is 255 or less
for (j=0; j < FXQ_LENGTH; j++) // scan the queue
{
if (fxq[j].resource) // if this entry isn't empty
{
if (fxq[j].type == FX_RANDOM) // if it's type FX_RANDOM
{
if (rand()%(fxq[j].delay)==0) // 1 in 'delay' chance of this fx occurring
{
Trigger_fx(j); // play it
}
}
else if(fxq[j].type == FX_SPOT)
{
if (fxq[j].delay) // if delay is above 0
fxq[j].delay--; // decrement delay countdown
else // if zero delay remaining
{
Trigger_fx(j); // play it
fxq[j].type = FX_SPOT2;
}
}
else if (fxq[j].type == FX_SPOT2)
{
if (IsFxOpen(j+1))
fxq[j].resource = 0; // Once the Fx has finished remove it from the queue.
}
}
}
}
//--------------------------------------------------------------------------------------
void Trigger_fx(uint8 j) // called from Process_fx_queue only
{
uint8 *data;
int32 id;
uint32 rv;
id = (uint32)j+1; // because 0 is not a valid id
if (fxq[j].type == FX_SPOT)
{
data = res_man.Res_open(fxq[j].resource); // load in the sample
data += sizeof(_standardHeader);
rv = PlayFx( id, data, fxq[j].volume, fxq[j].pan, RDSE_FXSPOT ); // wav data gets copied to sound memory
res_man.Res_close(fxq[j].resource); // release the sample
// fxq[j].resource = 0; // clear spot fx from queue
}
else // random & looped fx are already loaded into sound memory by FN_play_fx()
{ // - to be referenced by 'j', so pass NULL data
if (fxq[j].type == FX_RANDOM)
rv = PlayFx( id, NULL, fxq[j].volume, fxq[j].pan, RDSE_FXSPOT ); // not looped
else // FX_LOOP
rv = PlayFx( id, NULL, fxq[j].volume, fxq[j].pan, RDSE_FXLOOP ); // looped
}
#ifdef _DEBUG
if (rv)
Zdebug("SFX ERROR: PlayFx() returned %.8x (%s line %u)", rv, __FILE__, __LINE__);
#endif
}
//--------------------------------------------------------------------------------------
int32 FN_play_fx(int32 *params) // called from script only
{
// params: 0 sample resource id
// 1 type (FX_SPOT, FX_RANDOM, FX_LOOP)
// 2 delay (0..65535)
// 3 volume (0..16)
// 4 pan (-16..16)
// example script: FN_play_fx (FXWATER, FX_LOOP, 0, 10, 15);
// fx_water = result; // fx_water is just a local script flag
// .
// .
// .
// FN_stop_fx (fx_water);
uint8 j=0;
uint8 *data;
uint32 id;
uint32 rv;
//----------------------------------
#ifdef _DEBUG
_standardHeader *header;
char type[10];
if (wantSfxDebug)
{
switch (params[1]) // 'type'
{
case FX_SPOT:
strcpy(type,"SPOT");
break;
case FX_LOOP:
strcpy(type,"LOOPED");
break;
case FX_RANDOM:
strcpy(type,"RANDOM");
break;
default:
strcpy(type,"INVALID");
}
Zdebug("SFX (sample=\"%s\", vol=%d, pan=%d, delay=%d, type=%s)", FetchObjectName(params[0]), params[3], params[4], params[2], type);
}
#endif _DEBUG
//----------------------------------
while ((j < FXQ_LENGTH) && (fxq[j].resource != 0))
j++;
if (j==FXQ_LENGTH)
{
return (IR_CONT);
// Con_fatal_error("ERROR: Sound queue overflow in FN_play_fx() (%s line %u)",__FILE__,__LINE__);
}
else
{
fxq[j].resource = params[0]; // wav resource id
fxq[j].type = params[1]; // FX_SPOT, FX_LOOP or FX_RANDOM
if (fxq[j].type == FX_RANDOM) // FX_RANDOM:
fxq[j].delay = params[2] * 12 + 1; // 'delay' param is the intended average no. seconds between playing this effect (+1 to avoid divide-by-zero in Process_fx_queue)
else // FX_SPOT or FX_LOOP:
fxq[j].delay = params[2]; // 'delay' is no. frames to wait before playing
fxq[j].volume = params[3]; // 0..16
fxq[j].pan = params[4]; // -16..16
if (fxq[j].type == FX_SPOT) // spot fx
{
#ifdef _DEBUG
data = res_man.Res_open(fxq[j].resource); // "pre-load" the sample; this gets it into memory
header = (_standardHeader*)data;
if (header->fileType != WAV_FILE)
Con_fatal_error("FN_play_fx given invalid resource (%s line %u)",__FILE__,__LINE__);
#else
res_man.Res_open(fxq[j].resource); // "pre-load" the sample; this gets it into memory
#endif
res_man.Res_close(fxq[j].resource); // but then releases it to "age" out if the space is needed
}
else // random & looped fx
{
id = (uint32)j+1; // because 0 is not a valid id
data = res_man.Res_open(fxq[j].resource); // load in the sample
#ifdef _DEBUG
header = (_standardHeader*)data;
if (header->fileType != WAV_FILE)
Con_fatal_error("FN_play_fx given invalid resource (%s line %u)",__FILE__,__LINE__);
#endif
data += sizeof(_standardHeader);
rv = OpenFx(id,data); // copy it to sound memory, using position in queue as 'id'
#ifdef _DEBUG
if (rv)
Zdebug("SFX ERROR: OpenFx() returned %.8x (%s line %u)", rv, __FILE__, __LINE__);
#endif
res_man.Res_close(fxq[j].resource); // release the sample
}
}
//---------------------------------------------
// (James07uag97)
if (fxq[j].type == FX_LOOP) // looped fx
Trigger_fx(j); // play now, rather than in Process_fx_queue where it was getting played again & again!
//---------------------------------------------
RESULT = j; // in case we want to call FN_stop_fx() later, to kill this fx (mainly for FX_LOOP & FX_RANDOM)
return(IR_CONT); // continue script
}
//--------------------------------------------------------------------------------------
int32 FN_sound_fetch(int32 *params)
{
return (IR_CONT);
}
//--------------------------------------------------------------------------------------
// to alter the volume and pan of a currently playing fx
int32 FN_set_fx_vol_and_pan(int32 *params)
{
// params 0 id of fx (ie. the id returned in 'result' from FN_play_fx
// 1 new volume (0..16)
// 2 new pan (-16..16)
// SetFxVolumePan(int32 id, uint8 vol, uint8 pan);
SetFxVolumePan(1+params[0], params[1], params[2]); // driver fx_id is 1+<pos in queue>
// Zdebug("%d",params[2]);
return (IR_CONT);
}
//--------------------------------------------------------------------------------------
// to alter the volume of a currently playing fx
int32 FN_set_fx_vol(int32 *params)
{
// params 0 id of fx (ie. the id returned in 'result' from FN_play_fx
// 1 new volume (0..16)
// SetFxIdVolume(int32 id, uint8 vol);
SetFxIdVolume(1+params[0], params[1]);
return (IR_CONT);
}
//--------------------------------------------------------------------------------------
int32 FN_stop_fx(int32 *params) // called from script only
{
// params: 0 position in queue
// This will stop looped & random fx instantly, and remove the fx from the queue.
// So although it doesn't stop spot fx, it will remove them from the queue if they haven't yet played
uint8 j = (uint8) params[0];
uint32 id;
uint32 rv;
if ((fxq[j].type == FX_RANDOM) || (fxq[j].type == FX_LOOP))
{
id = (uint32)j+1; // because 0 is not a valid id
rv = CloseFx(id); // stop fx & remove sample from sound memory
#ifdef _DEBUG
if (rv)
Zdebug("SFX ERROR: CloseFx() returned %.8x (%s line %u)", rv, __FILE__, __LINE__);
#endif
}
fxq[j].resource = 0; // remove from queue
return(IR_CONT); // continue script
}
//--------------------------------------------------------------------------------------
int32 FN_stop_all_fx(int32 *params) // called from script only
{
// Stops all looped & random fx and clears the entire queue
// NO PARAMS
Clear_fx_queue();
return(IR_CONT); // continue script
}
//--------------------------------------------------------------------------------------
// Stops all looped & random fx and clears the entire queue
void Clear_fx_queue(void)
{
ClearAllFx(); // stop all fx & remove the samples from sound memory
Init_fx_queue(); // clean out the queue
}
//--------------------------------------------------------------------------------------
//=============================================================================
// int32 StreamMusic(uint8 *filename, int32 loopFlag)
//
// Streams music from the file defined by filename. The loopFlag should
// be set to RDSE_FXLOOP if the music is to loop back to the start.
// Otherwise, it should be RDSE_FXSPOT.
// The return value must be checked for any problems.
//
// --------------------------------------------------------------------------
//
// int32 PauseMusic(void)
//
// Stops the music dead in it's tracks.
//
// --------------------------------------------------------------------------
//
// int32 UnpauseMusic(void)
//
// Re-starts the music from where it was stopped.
//
//=============================================================================
int32 FN_prepare_music(int32 *params)
{
return (IR_CONT);
}
//--------------------------------------------------------------------------------------
// Start a tune playing, to play once or to loop until stopped or next one played
int32 FN_play_music(int32 *params) // updated by James on 10apr97
{
// params 0 tune id
// 1 loop flag (0 or 1)
char filename[128];
uint32 loopFlag;
uint32 rv; // drivers return value
// Zdebug("FN_play_music(%d)", params[0]);
if (params[1]==FX_LOOP) // if it is to loop
{
loopFlag = RDSE_FXLOOP;
looping_music_id = params[0]; // keep a note of the id, for restarting after an interruption to gameplay
}
else // just play once
{
loopFlag = RDSE_FXSPOT;
looping_music_id = 0; // don't need to restart this tune after control panel or restore
}
// add the appropriate file extension & play it
#ifdef _WEBDEMO // (James 01oct97)
sprintf(filename,"MUSIC.CLU");
#else
sprintf(filename,"%sCLUSTERS\\MUSIC.CLU", res_man.GetCdPath());
#endif // _WEBDEMO
rv = StreamCompMusic(filename, params[0], loopFlag);
#ifdef _DEBUG
if (rv)
Zdebug("ERROR: StreamCompMusic(%s, %d, %d) returned error 0x%.8x", filename, params[0], loopFlag, rv);
#endif
// Zdebug("FN_play_music(%d) returning", params[0]);
return(IR_CONT); // continue script
}
//--------------------------------------------------------------------------------------
int32 FN_stop_music(int32 *params) // called from script only
{
// params: none
looping_music_id=0; // clear the 'looping' flag
StopMusic();
if (params);
return(IR_CONT); // continue script
}
//--------------------------------------------------------------------------------------
extern void UpdateCompSampleStreaming(void); // used in Kill_music()
//--------------------------------------------------------------------------------------
void Kill_music(void) // James22aug97
{
uint8 count;
looping_music_id=0; // clear the 'looping' flag
StopMusic();
// THIS BIT CAUSES THE MUSIC TO STOP INSTANTLY!
for(count=0; count<16; count++)
UpdateCompSampleStreaming();
}
//--------------------------------------------------------------------------------------
int32 FN_check_music_playing(int32 *params) // James (30july97)
{
// params: none
// sets result to no. of seconds of current tune remaining
// or 0 if no music playing
RESULT = MusicTimeRemaining(); // in seconds, rounded up to the nearest second
return(IR_CONT); // continue script
}
//--------------------------------------------------------------------------------------
void PauseAllSound(void) // James25july97
{
uint32 rv; // for drivers return value
rv = PauseMusic();
if (rv != RD_OK)
Zdebug("ERROR: PauseMusic() returned %.8x in PauseAllSound()", rv);
rv = PauseSpeech();
if (rv != RD_OK)
Zdebug("ERROR: PauseSpeech() returned %.8x in PauseAllSound()", rv);
rv = PauseFx();
if (rv != RD_OK)
Zdebug("ERROR: PauseFx() returned %.8x in PauseAllSound()", rv);
}
//--------------------------------------------------------------------------------------
void UnpauseAllSound(void) // James25july97
{
uint32 rv; // for drivers return value
rv = UnpauseMusic();
if (rv != RD_OK)
Zdebug("ERROR: UnpauseMusic() returned %.8x in UnpauseAllSound()", rv);
rv = UnpauseSpeech();
if (rv != RD_OK)
Zdebug("ERROR: UnpauseSpeech() returned %.8x in UnpauseAllSound()", rv);
rv = UnpauseFx();
if (rv != RD_OK)
Zdebug("ERROR: UnpauseFx() returned %.8x in UnpauseAllSound()", rv);
}
//--------------------------------------------------------------------------------------

55
sword2/sound.h Normal file
View file

@ -0,0 +1,55 @@
/* 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$
*/
/*****************************************************************************
* SOUND.H Sound engine
*
* SOUND.CPP Contains the sound engine, fx & music functions
* Some very 'sound' code in here ;)
*
* (16Dec96 JEL)
*
****************************************************************************/
#ifndef SOUND_H
#define SOUND_H
#include "scummsys.h"
// fx types
#define FX_SPOT 0
#define FX_LOOP 1
#define FX_RANDOM 2
#define FX_SPOT2 3
void Init_fx_queue(void); // to be called during system initialisation
void Process_fx_queue(void); // to be called from the main loop, once per cycle
void Clear_fx_queue(void); // stops all fx & clears the queue - eg. when leaving a location
void PauseAllSound(void); // James25july97
void UnpauseAllSound(void); // James25july97
void Kill_music(void); // James22aug97
int32 FN_play_music(int32 *params); // for save_Rest.cpp
int32 FN_stop_music(int32 *params);
extern uint32 looping_music_id; // used to store id of tunes that loop, for save & restore
#endif

1994
sword2/speech.cpp Normal file

File diff suppressed because it is too large Load diff

44
sword2/speech.h Normal file
View file

@ -0,0 +1,44 @@
/* 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$
*/
#ifndef _SPEECH
#define _SPEECH
//#include "src\driver96.h"
#include "header.h"
#define MAX_SUBJECT_LIST 30 //is that enough?
typedef struct //array of these for subject menu build up
{
uint32 res;
uint32 ref;
} _subject_unit;
extern uint32 speech_text_bloc_no; // so speech text cleared when running a new start-script
extern int16 officialTextNumber;
extern int32 speechScriptWaiting;
extern int choosing; //could alternately use logic->looping of course
extern uint32 unpause_zone;
#endif

339
sword2/startup.cpp Normal file
View file

@ -0,0 +1,339 @@
/* 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$
*/
//------------------------------------------------------------------------------------
#include <stdio.h>
//#include "src\driver96.h"
#include "build_display.h"
#include "console.h"
#include "debug.h"
#include "defs.h"
#include "header.h"
#include "interpreter.h"
#include "maketext.h" // for Kill_text_bloc()
#include "memory.h"
#include "mouse.h" // for FN_add_human()
#include "object.h"
#include "resman.h"
#include "router.h"
#include "sound.h"
#include "speech.h" // for 'speech_text_bloc_no' - so that speech text can be cleared when running a new start-script
#include "startup.h"
#include "sword2.h" // (James11aug97) for CloseGame()
#include "sync.h"
#include "tony_gsdk.h"
//------------------------------------------------------------------------------------
uint32 total_startups=0;
uint32 total_screen_managers=0;
uint32 res;
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
_startup start_list[MAX_starts];
//------------------------------------------------------------------------------------
uint32 Init_start_menu(void) //Tony13Aug96
{
//print out a list of all the start points available
//there should be a linc produced file called startup.txt
//this file should contain ascii numbers of all the resource game objects that are screen managers
//we query each in turn and setup an array of start structures
//if the file doesn't exist then we say so and return a 0
uint32 end;
mem *temp;
uint32 pos=0;
uint32 j=0;
char *raw_script;
uint32 null_pc;
char ascii_start_ids[MAX_starts][7];
//ok, load in the master screen manager file
total_startups=0; //no starts
Zdebug("initialising start menu");
if (!(end=Read_file("STARTUP.INF", &temp, UID_temp)))
{
Zdebug("Init_start_menu cannot open startup.inf");
return(0); //meaning no start menu available
}
//ok, we've loaded in the resource.inf file which contains a list of all the files
//now extract the filenames
do
{
while(((char)*(temp->ad+j))!=13) //item must have an #0d0a
{
ascii_start_ids[total_screen_managers][pos]=*(temp->ad+j);
j++;
pos++;
};
ascii_start_ids[total_screen_managers][pos]=0; //NULL terminate our extracted string
pos=0; //reset position in current slot between entries
j+=2; //past the 0a
total_screen_managers++; //done another
if (total_screen_managers==MAX_starts)
{ Zdebug("WARNING MAX_starts exceeded!");
break;
}
}
while(j<end); //using this method the Gode generated resource.inf must have #0d0a on the last entry
Zdebug("%d screen manager objects", total_screen_managers);
//open each object and make a query call. the object must fill in a startup structure
//it may fill in several if it wishes - for instance a startup could be set for later in the game where specific vars are set
for (j=0;j<total_screen_managers;j++)
{
res=atoi(ascii_start_ids[j]);
Zdebug("+querying screen manager %d", res);
// resopen each one and run through the interpretter
// script 0 is the query request script
if (res_man.Res_check_valid(res)) // if the resource number is within range & it's not a null resource (James 12mar97)
{ // - need to check in case un-built sections included in start list
Zdebug("- resource %d ok",res);
raw_script= (char*) (res_man.Res_open(res)); //+sizeof(_standardHeader)+sizeof(_object_hub));
null_pc=0; //
RunScript ( raw_script, raw_script, &null_pc );
res_man.Res_close(res);
}
else
{
Zdebug("- resource %d invalid",res);
}
}
Zdebug(""); //line feed
Free_mem(temp); //release the Talloc
return(1);
}
//------------------------------------------------------------------------------------
int32 FN_register_start_point(int32 *params) //Tony14Oct96
{
// param 0 id of startup script to call - key
// param 1 pointer to ascii message
// Zdebug(" FN_register_start_point %d %s", params[0], params[1]);
#ifdef _DEBUG
if (total_startups==MAX_starts)
Con_fatal_error("ERROR: start_list full [%s line %u]",__FILE__,__LINE__);
if (strlen((char*)params[1])+1 > MAX_description) // +1 to allow for NULL terminator
Con_fatal_error("ERROR: startup description too long [%s line %u]",__FILE__,__LINE__);
#endif
start_list[total_startups].start_res_id = res; // this objects id
start_list[total_startups].key = params[0]; // a key code to be passed to a script via a script var to SWITCH in the correct start
strcpy(start_list[total_startups].description, (char*)params[1]);
total_startups++; //point to next
return(1);
}
//------------------------------------------------------------------------------------
uint32 Con_print_start_menu(void) //Tony14Oct96
{
//the console 'starts' (or 's') command which lists out all the registered start points in the game
uint32 j;
int scrolls=0;
char c;
if (!total_startups)
{ Print_to_console("Sorry - no startup positions registered?");
if (!total_screen_managers)
Print_to_console("There is a problem with startup.inf");
else
Print_to_console(" (%d screen managers found in startup.inf)", total_screen_managers);
}
else
{
for(j=0;j<total_startups;j++)
{
Print_to_console("%d (%s)", j, start_list[j].description);
Build_display();
scrolls++;
if (scrolls==18)
{
Temp_print_to_console("- Press ESC to stop or any other key to continue");
Build_display();
do
{
//--------------------------------------------------
// Service windows
while (!gotTheFocus)
if (ServiceWindows() == RDERR_APPCLOSED)
break;
if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
{
Close_game(); //close engine systems down
RestoreDisplay();
CloseAppWindow();
exit(0); //quit the game
}
//--------------------------------------------------
}
while(!KeyWaiting());
ReadKey(&c); //kill the key we just pressed
if (c==27) //ESC
break;
Clear_console_line(); //clear the Press Esc message ready for the new line
scrolls=0;
}
}
}
return(1);
}
//------------------------------------------------------------------------------------
uint32 Con_start(uint8 *input) //Tony15Oct96
{
//if the second word id is a numeric that can be applied to a genuine startup then do it
uint32 j=0;
uint32 start;
char *raw_script;
char *raw_data_ad;
uint32 null_pc;
if (*input == NULL) // so that typing 'S' then <enter> works on NT (James26feb97)
{
Con_print_start_menu();
return(1);
}
while(*(input+j))
{
if ( (*(input+j)>='0') && (*(input+j)<='9') )
j++;
else
break;
}
if (!*(input+j)) //didn't quit out of loop on a non numeric chr$
{
start = atoi((char*)input);
if (!total_startups)
Print_to_console("Sorry - there are no startups!");
else if (start<total_startups) //a legal start
{
// do the startup as we've specified a legal start
//--------------------------------------------------------------
// restarting - stop sfx, music & speech!
Clear_fx_queue();
//---------------------------------------------
FN_stop_music(NULL); // fade out any music that is currently playing
//---------------------------------------------
UnpauseSpeech();
StopSpeech(); // halt the sample prematurely
//--------------------------------------------------------------
// clean out all resources & flags, ready for a total restart (James24mar97)
res_man.Remove_all_res(); // remove all resources from memory, including player object & global variables
SetGlobalInterpreterVariables((int32*)(res_man.Res_open(1)+sizeof(_standardHeader))); // reopen global variables resource & send address to interpreter - it won't be moving
res_man.Res_close(1);
FreeAllRouteMem(); // free all the route memory blocks from previous game
if (speech_text_bloc_no) // if there was speech text
{
Kill_text_bloc(speech_text_bloc_no); // kill the text block
speech_text_bloc_no=0;
}
//--------------------------------------------------------------
// set the key
raw_data_ad= (char*) (res_man.Res_open(8)); //+sizeof(_standardHeader)+sizeof(_object_hub)); //open george
raw_script= (char*) (res_man.Res_open(start_list[start].start_res_id)); //+sizeof(_standardHeader)+sizeof(_object_hub));
null_pc=start_list[start].key&0xffff; //denotes script to run
Print_to_console("running start %d", start);
RunScript ( raw_script, raw_data_ad, &null_pc );
res_man.Res_close(start_list[start].start_res_id);
res_man.Res_close(8); //close george
FN_add_human(NULL); // make sure thre's a mouse, in case restarting while mouse not available
}
else
Print_to_console("not a legal start position");
}
else
{
Con_print_start_menu(); // so that typing 'S' then <enter> works under Win95
}
return(1);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

45
sword2/startup.h Normal file
View file

@ -0,0 +1,45 @@
/* 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$
*/
#ifndef _STARTUP
#define _STARTUP
//#include "src\driver96.h"
#define MAX_starts 100
#define MAX_description 100
typedef struct
{
char description[MAX_description];
uint32 start_res_id; //id of screen manager object
uint32 key; //tell the manager which startup you want (if there are more than 1) (i.e more than 1 entrance to a screen and/or seperate game boots)
} _startup;
extern _startup start_list[MAX_starts];
uint32 Init_start_menu(void); //Tony13Aug96
uint32 Con_print_start_menu(void); //Tony13Aug96
uint32 Con_start(uint8 *input); //Tony15Oct96
#endif

572
sword2/sword2.cpp Normal file
View file

@ -0,0 +1,572 @@
/* 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$
*/
//------------------------------------------------------------------------------------
#include <ctype.h>
#include <stdio.h>
//#include <windows.h>
#include "driver/driver96.h"
#include "common/gameDetector.h"
#include "build_display.h"
#include "console.h"
#include "controls.h"
#include "debug.h"
#include "events.h"
#include "header.h"
#include "interpreter.h"
#include "layers.h"
#include "logic.h"
#include "maketext.h"
#include "memory.h"
#include "mouse.h"
#include "protocol.h"
#include "resman.h"
#include "scroll.h"
#include "sound.h"
#include "speech.h"
#include "startup.h"
#include "sword2.h"
#include "sync.h"
#define MAX_PATH 260
void Start_game(void);
int RunningFromCd();
uint8 quitGame = 0;
//------------------------------------------------------------------------------------
// version & owner details
//So version string is 18 bytes long :
//Version String = <8 byte header,5 character version, \0, INT32 time>
uint8 version_string[HEAD_LEN+10] = {1, 255, 37, 22, 45, 128, 34, 67};
uint8 unencoded_name[HEAD_LEN+48] = {76, 185, 205, 23, 44, 34, 24, 34,
'R','e','v','o','l','u','t','i','o','n',' ',
'S','o','f','t','w','a','r','e',' ','L','t','d',
0};
uint8 encoded_name[HEAD_LEN+48] = {44, 32, 190, 222, 123, 65, 233, 99,
179, 209, 225, 157, 222, 238, 219, 209, 143, 224, 133, 190,
232, 209, 162, 177, 198, 228, 202, 146, 180, 232, 214, 65,
65, 65, 116, 104, 116, 114, 107, 104, 32, 49, 64, 35, 123,
125, 61, 45, 41, 40, 163, 36, 49, 123, 125, 10};
//------------------------------------------------------------------------------------
uint8 gamePaused=0; // James17jun97
//uint32 pause_text_bloc_no=0; // James17jun97
uint8 graphics_level_fudged=0; // James10july97
uint8 stepOneCycle=0; // for use while game paused
//------------------------------------------------------------------------------------
void PauseGame(void); // James17jun97
void UnpauseGame(void); // James17jun97
//------------------------------------------------------------------------------------
static const VersionSettings bs2_settings[] = {
/* Broken Sword 2 */
{"bs2", "Broken Sword II", GID_BS2_FIRST, 99, VersionSettings::ADLIB_DONT_CARE, GF_DEFAULT_TO_1X_SCALER, "players.clu" },
{NULL, NULL, 0, 0, VersionSettings::ADLIB_DONT_CARE, 0, NULL}
};
BS2State *g_bs2 = NULL;
const VersionSettings *Engine_BS2_targetList() {
return bs2_settings;
}
Engine *Engine_BS2_create(GameDetector *detector, OSystem *syst) {
return new BS2State(detector, syst);
}
BS2State::BS2State(GameDetector *detector, OSystem *syst)
: Engine(detector, syst) {
_detector = detector;
_syst = syst;
g_bs2 = this;
}
void BS2State::errorString(const char *buf1, char *buf2) {
strcpy(buf2, buf1);
}
int32 InitialiseGame(void)
{
//init engine drivers
uint8 *file;
Zdebug("CALLING: Init_memory_manager");
Init_memory_manager(); // get some falling RAM and put it in your pocket, never let it slip away
Zdebug("RETURNED.");
Zdebug("CALLING: res_man.InitResMan");
res_man.InitResMan(); // initialise the resource manager
Zdebug("RETURNED from res_man.InitResMan");
// initialise global script variables
file=res_man.Res_open(1); // res 1 is the globals list
Zdebug("CALLING: SetGlobalInterpreterVariables");
SetGlobalInterpreterVariables((int32*)(file+sizeof(_standardHeader)));
Zdebug("RETURNED.");
// res_man.Res_close(1); // DON'T CLOSE VARIABLES RESOURCE - KEEP IT OPEN AT VERY START OF MEMORY SO IT CAN'T MOVE!
file=res_man.Res_open(8); // DON'T CLOSE PLAYER OBJECT RESOURCE - KEEP IT OPEN IN MEMORY SO IT CAN'T MOVE!
//----------------------------------------
Zdebug("CALLING: InitialiseFontResourceFlags");
InitialiseFontResourceFlags(); // Set up font resource variables for this language version (James31july97)
// Also set the windows application name to the proper game name
Zdebug("RETURNED.");
//----------------------------------------
Zdebug("CALLING: Init_console");
Init_console(); // set up the console system
Zdebug("RETURNED.");
#ifdef _DEBUG
Zdebug("CALLING: Init_start_menu");
Init_start_menu(); // read in all the startup information
Zdebug("RETURNED from Init_start_menu");
#endif // _DEBUG
Zdebug("CALLING: Init_text_bloc_system");
Init_text_bloc_system(); // no blocs live
Zdebug("RETURNED.");
Zdebug("CALLING: Init_sync_system");
Init_sync_system();
Zdebug("RETURNED.");
Zdebug("CALLING: Init_event_system");
Init_event_system();
Zdebug("RETURNED.");
Zdebug("CALLING: Init_fx_queue");
Init_fx_queue(); // initialise the sound fx queue
Zdebug("RETURNED.");
#ifdef _DEMO // demo only
DEMO=1; // set script variable
#endif
return(0);
}
//------------------------------------------------------------------------------------
void Close_game() //Tony11Oct96
{
Zdebug("Close_game() STARTING:");
//avoid corruption when windows kicks back in
EraseBackBuffer();
FlipScreens();
EraseBackBuffer();
FlipScreens();
Kill_music(); // Stop music instantly! (James22aug97)
Close_memory_manager(); // free the memory again
res_man.Close_ResMan();
Zdebug("Close_game() DONE.");
}
//------------------------------------------------------------------------------------
int32 GameCycle(void)
{
//do one game cycle
{
if (LLogic.Return_run_list()) //got a screen to run?
{
do //run the logic session UNTIL a full loop has been performed
{
Reset_render_lists(); // reset the graphic 'buildit' list before a new logic list (see FN_register_frame)
Reset_mouse_list(); // reset the mouse hot-spot list (see FN_register_mouse & FN_register_frame)
}
while(LLogic.Process_session()); //keep going as long as new lists keep getting put in - i.e. screen changes
}
else //start the console and print the start options perhaps?
{
StartConsole();
Print_to_console("AWAITING START COMMAND: (Enter 's 1' then 'q' to start from beginning)");
}
}
if (this_screen.scroll_flag) // if this screen is wide
Set_scrolling(); // recompute the scroll offsets every game-cycle
Mouse_engine(); //check the mouse
Process_fx_queue();
res_man.Res_next_cycle(); // update age and calculate previous cycle memory usage
if (quitGame)
return(1);
else
return(0);
}
//------------------------------------------------------------------------------------
// int main(int argc, char *argv[])
// int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
void BS2State::go()
{
uint32 rv;
uint8 breakOut = 0;
char c;
int j=100;
uint32 pc=0;
// Zdebug("[%s]", lpCmdLine);
#ifndef _DEBUG
DisableQuitKey(); // so cannot use Ctrl-Q from the release versions (full game or demo)
#endif
if (RunningFromCd()) //stop this game being run from CD
exit(-1);
// Call the application "Revolution" until the resource manager is ready to dig the name out of a text file
// See InitialiseGame() which calls InitialiseFontResourceFlags() in maketext.cpp
// Have to do it like this since we cannot really fire up the resource manager until a window
// has been created as any errors are displayed via a window, thus time becomes a loop.
Zdebug("CALLING: InitialiseWindow");
// rv = InitialiseWindow(hInstance, hPrevInstance, lpCmdLine, nCmdShow, "Revolution");
rv = RD_OK;
Zdebug("RETURNED with rv = %.8x", rv);
if (rv != RD_OK)
{
// ReportDriverError(rv);
return;
}
Zdebug("CALLING: InitialiseDisplay");
// rv = InitialiseDisplay(640, 480, 8, RD_FULLSCREEN);
_syst->init_size(640, 480);
rv = RD_OK;
Zdebug("RETURNED with rv = %.8x", rv);
if (rv != RD_OK)
{
// ReportDriverError(rv);
CloseAppWindow();
return;
}
Zdebug("CALLING: ReadOptionSettings");
ReadOptionSettings(); //restore the menu settings
Zdebug("RETURNED.");
Zdebug("CALLING: InitialiseSound");
rv = InitialiseSound(22050, 2, 16);
Zdebug("RETURNED with rv = %.8x", rv);
// don't care if this fails, because it should still work without sound cards
// but it should set a global system flag so that we can avoid loading sound fx & streaming music
// because they won't be heard anyway
/*
if (rv != RD_OK)
{
ReportDriverError(rv);
CloseAppWindow();
return(0);
}
*/
Zdebug("CALLING: InitialiseGame");
if (InitialiseGame())
{
Zdebug("RETURNED from InitialiseGame - closing game");
RestoreDisplay();
CloseAppWindow();
return;
}
Zdebug("RETURNED from InitialiseGame - ok");
//check for restore game on startup - at the mo any passed argument is good enough to trigger this
// if (lpCmdLine[0]) //non zero
if (0)
{
Set_mouse(NORMAL_MOUSE_ID);
if (!Restore_control()) // restore a game
Start_game();
}
//-------------------------------------------------------------
// release versions only (full-game and demo)
// #if NDEBUG // comment this out for debug versions to start game automatically!
else
Start_game();
// #endif // comment this out for debug versions to start game automatically!
//-------------------------------------------------------------
Zdebug("CALLING: InitialiseRenderCycle");
InitialiseRenderCycle();
Zdebug("RETURNED.");
while (TRUE)
{
if (ServiceWindows() == RDERR_APPCLOSED)
{
break; // break out of main game loop
}
// check for events
parseEvents();
#ifdef _DEBUG
if (grabbingSequences && (!console_status))
GrabScreenShot();
#endif
while (!gotTheFocus)
{
if (ServiceWindows() == RDERR_APPCLOSED)
{
breakOut = 1;
break; // break out of this while-loop
}
}
if (breakOut) // if we are closing down the game
break; // break out of main game loop
//-----
#ifdef _DEBUG
if (console_status)
{
if (One_console())
{
EndConsole();
UnpauseAllSound(); // see sound.cpp
}
}
#endif
if (!console_status) //not in console mode - if the console is quit we want to get a logic cycle in before
{ //the screen is build. Mostly because of first scroll cycle stuff
#ifdef _DEBUG
if (stepOneCycle) // if we've just stepped forward one cycle while the game was paused
{
PauseGame();
stepOneCycle=0;
}
#endif
if (KeyWaiting())
{
ReadKey(&c);
#ifdef _DEBUG
if (c==27) // ESC whether paused or not
{
PauseAllSound(); // see sound.cpp
StartConsole(); // start the console
}
else
#endif
if (gamePaused) // if currently paused
{
if (toupper(c)=='P') // 'P' while paused = unpause!
{
UnpauseGame();
}
#ifdef _DEBUG
else if (toupper(c)==' ') // SPACE bar while paused = step one frame!
{
stepOneCycle=1; // step through one game cycle
UnpauseGame();
}
#endif // _DEBUG
}
else if (toupper(c)=='P') // 'P' while not paused = pause!
{
PauseGame();
}
#ifdef _DEBUG // frame-skipping only allowed on debug version
else if (toupper(c)=='S') // 'S' toggles speed up (by skipping display rendering)
{
renderSkip = 1 - renderSkip;
}
#endif // _DEBUG
}
if (gamePaused==0) // skip GameCycle if we're paused
{
#ifdef _DEBUG
gameCycle += 1;
#endif
if (GameCycle())
break; // break out of main game loop
}
#ifdef _DEBUG
Build_debug_text(); // creates the debug text blocks
#endif // _DEBUG
}
//-----
// James (24mar97)
#ifdef _DEBUG
if ((console_status)||(renderSkip==0)||(gameCycle%4 == 0)) // if not in console & 'renderSkip' is set, only render display once every 4 game-cycles
Build_display(); // create and flip the screen
#else
Build_display(); // create and flip the screen
#endif // _DEBUG
}
Close_game(); //close engine systems down
RestoreDisplay();
CloseAppWindow();
return; //quit the game
}
//------------------------------------------------------------------------------------
int RunningFromCd()
{
char sCDName[MAX_PATH];
char sRoot[MAX_PATH];
DWORD dwMaxCompLength, dwFSFlags;
/*
GetModuleFileName(NULL , sRoot, _MAX_PATH);
*(strchr(sRoot,'\\')+1) = '\0';
if (!GetVolumeInformation(sRoot, sCDName,_MAX_PATH, NULL, &dwMaxCompLength, &dwFSFlags, NULL, 0))
return -1;
if (!scumm_strnicmp(sCDName,CD1_LABEL,6))
return 1;
if (!scumm_strnicmp(sCDName,CD2_LABEL,6))
return 2;
*/
return 0;
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
void Start_game(void) //Tony29May97
{
//boot the game straight into a start script
Zdebug("Start_game() STARTING:");
#ifdef _DEMO
#define SCREEN_MANAGER_ID 19 // DOCKS SECTION START
#else
#define SCREEN_MANAGER_ID 949 // INTRO & PARIS START
#endif
char *raw_script;
char *raw_data_ad;
uint32 null_pc=1; // the required start-scripts are both script #1 in the respective ScreenManager objects
raw_data_ad = (char*) (res_man.Res_open(8)); // open george object, ready for start script to reference
raw_script = (char*) (res_man.Res_open(SCREEN_MANAGER_ID)); // open the ScreenManager object
RunScript ( raw_script, raw_data_ad, &null_pc ); // run the start script now (because no console)
res_man.Res_close(SCREEN_MANAGER_ID); // close the ScreenManager object
res_man.Res_close(8); // close george
Zdebug("Start_game() DONE.");
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
void PauseGame(void) // James17jun97
{
// uint8 *text;
// text = FetchTextLine( res_man.Res_open(3258), 449 ); // open text file & get the line "PAUSED"
// pause_text_bloc_no = Build_new_block(text+2, 320, 210, 640, 184, RDSPR_TRANS+RDSPR_DISPLAYALIGN, SPEECH_FONT_ID, POSITION_AT_CENTRE_OF_BASE);
// res_man.Res_close(3258); // now ok to close the text file
//---------------------------
// don't allow Pause while screen fading or while black (James 03sep97)
if(GetFadeStatus()!=RDFADE_NONE)
return;
//---------------------------
PauseAllSound();
//make a normal mouse
ClearPointerText();
// mouse_mode=MOUSE_normal;
SetLuggageAnim(NULL, NULL); //this is the only place allowed to do it this way
Set_mouse(NULL); // blank cursor
mouse_touching=1; //forces engine to choose a cursor
if (current_graphics_level==3) // if level at max
{
UpdateGraphicsLevel(3,2); // turn down because palette-matching won't work when dimmed
graphics_level_fudged=1;
}
if (stepOneCycle==0) // don't dim it if we're single-stepping through frames
{
DimPalette(); // dim the palette during the pause (James26jun97)
}
gamePaused=1;
}
//------------------------------------------------------------------------------------
void UnpauseGame(void) // James17jun97
{
// Kill_text_bloc(pause_text_bloc_no); // removed "PAUSED" from screen
if ((OBJECT_HELD)&&(real_luggage_item))
Set_luggage(real_luggage_item);
UnpauseAllSound();
SetFullPalette(0xffffffff); // put back game screen palette; see Build_display.cpp (James26jun97)
if (graphics_level_fudged) // if level at max
{
UpdateGraphicsLevel(2,3); // turn up again
graphics_level_fudged=0;
}
gamePaused=0;
unpause_zone=2;
if ((!mouse_status)||(choosing)) //if mouse is about or we're in a chooser menu
Set_mouse(NORMAL_MOUSE_ID);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

62
sword2/sword2.h Normal file
View file

@ -0,0 +1,62 @@
/* 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$
*/
#ifndef _SWORD2
#define _SWORD2
//#include "src\driver96.h"
#ifdef _PCF76 // Bodge for PCF76 version so that their demo CD can be labelled "PCF76" rather than "RBSII1"
#define CD1_LABEL "PCF76"
#else
#define CD1_LABEL "RBSII1"
#endif
#define CD2_LABEL "RBSII2"
void Close_game(); //Tony11Oct96
void PauseGame(void); // James17jun97
void UnpauseGame(void); // James17jun97
void Start_game(void); // James13aug97
#define HEAD_LEN 8
extern uint8 version_string[]; // for displaying from the console
extern uint8 unencoded_name[];
// TODO move stuff into class
class BS2State : public Engine {
void errorString(const char *buf_input, char *buf_output);
public:
BS2State(GameDetector *detector, OSystem *syst);
void go();
void parseEvents();
OSystem *_syst;
GameDetector *_detector;
private:
bool _quit;
};
extern BS2State *g_bs2;
#endif

179
sword2/sync.cpp Normal file
View file

@ -0,0 +1,179 @@
/* 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$
*/
//------------------------------------------------------------------------------------
#include <stdio.h>
//#include "src\driver96.h"
#include "console.h"
#include "debug.h"
#include "defs.h"
#include "interpreter.h"
#include "memory.h"
#include "object.h"
#include "sync.h"
//------------------------------------------------------------------------------------
typedef struct
{
uint32 id;
uint32 sync;
} _sync_unit; //haaaaaaaa
#define MAX_syncs 10 //there wont be many will there. probably 2 at most i reckon
_sync_unit sync_list[MAX_syncs];
//------------------------------------------------------------------------------------
void Init_sync_system(void) //Tony27Nov96
{
//set list to 0's
uint32 j;
for (j=0;j<MAX_syncs;j++)
sync_list[j].id=0;
}
//------------------------------------------------------------------------------------
int32 FN_send_sync(int32 *params) //Tony27Nov96
{
//param 0 sync's recipient
//param 1 sync value
uint32 current_sync=0;
if (sync_list[current_sync].id)
{
do
current_sync++;
while(sync_list[current_sync].id); //zip along until we find a free slot
}
// Zdebug(" %d sending sync %d to %d", ID, params[1], params[0]);
sync_list[current_sync].id=params[0];
sync_list[current_sync].sync=params[1];
return(IR_CONT);
}
//------------------------------------------------------------------------------------
void Clear_syncs(uint32 id) //Tony27Nov96
{
//clear any syncs registered for this id
//call this just after the id has been processed
uint32 j;
//there could in theory be more than one sync waiting for us so clear the lot
for (j=0;j<MAX_syncs;j++)
if (sync_list[j].id==id)
{ //Zdebug("removing sync %d for %d", j, id);
sync_list[j].id=0;
}
}
//------------------------------------------------------------------------------------
uint32 Get_sync(void) //Tony27Nov96
{
// check for a sync waiting for this character
// - called from system code eg. from inside FN_anim(), to see if animation to be quit
uint32 j;
for (j=0;j<MAX_syncs;j++)
if (sync_list[j].id == ID)
return(1); //means sync found Tony12July97
// return(sync_list[j].sync); //return sync value waiting
return(0); //no sync found
}
//------------------------------------------------------------------------------------
int32 FN_get_sync(int32 *params) //Tony27Nov96
{
// check for a sync waiting for this character
// - called from script
//params none
uint32 j;
for (j=0;j<MAX_syncs;j++)
if (sync_list[j].id == ID)
{ RESULT=sync_list[j].sync;
return(IR_CONT); //return sync value waiting
}
RESULT=0;
if (params);
return(IR_CONT); //no sync found
}
//------------------------------------------------------------------------------------
int32 FN_wait_sync(int32 *params) //Tony27Nov96
{
//keep calling until a sync recieved
//params none
uint32 j;
j=ID;
// Zdebug("%d waits", ID);
for (j=0;j<MAX_syncs;j++)
if (sync_list[j].id == ID)
{ RESULT=sync_list[j].sync;
//Zdebug(" go");
return(IR_CONT); //return sync value waiting
}
if (params);
return(IR_REPEAT); //back again next cycle
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

32
sword2/sync.h Normal file
View file

@ -0,0 +1,32 @@
/* 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$
*/
#ifndef _SYNC
#define _SYNC
//#include "src\driver96.h"
#include "object.h"
void Init_sync_system(void); //Tony27Nov96
void Clear_syncs(uint32 id); //Tony27Nov96
uint32 Get_sync(void); //Tony27Nov96
#endif

151
sword2/tony_gsdk.cpp Normal file
View file

@ -0,0 +1,151 @@
/* 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$
*/
//===================================================================================================================
//
// File - tony_gsdk.cpp
//
//===================================================================================================================
//general odds and ends
#include <sys/type.h>
#include <sys/stat.h>
#include <fcntl.h>
//#include <io.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//#include "src\driver96.h"
#include "debug.h"
#include "header.h"
#include "layers.h"
#include "memory.h"
#include "protocol.h"
#include "resman.h"
#include "tony_gsdk.h"
// TODO replace with file class
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
uint32 Read_file(char *name, mem **membloc, uint32 uid) //Tony25Apr96
{
//read the file in and place into an allocated MEM_float block
//used for non resources manager files - stuff like fonts, etc.
//returns bytes read or 0 for error
FILE *fh=0; //file pointer
uint32 end;
fh = fopen(name, "rb"); //open for binary reading
if (fh==NULL)
{ Zdebug("Read_file cannot open %s", name);
return(0);
}
//ok, find the length and read the file in
fseek(fh, 0, SEEK_END); //get size of file
end = ftell(fh); //finally got the end
*membloc= Twalloc(end, MEM_float, uid); //reserve enough floating memory for the file
fseek( fh, 0, SEEK_SET ); //back to beginning of file
if (fread( (*membloc)->ad, sizeof(char), end,fh)==-1)
{ Zdebug("Read_file read fail %d", name);
return(0);
}
fclose(fh);
return(end); //ok, done it - return bytes read
}
//-----------------------------------------------------------------------------------------------------------------------
int32 Direct_read_file(char *name, char *ad) //Tony1May96
{
//load the file directly into the memory location passed
//memory must be pre-allocated
FILE *fh=0; //file pointer
uint32 end;
fh = fopen(name, "rb"); //open for binary reading
if (fh==NULL)
{ Zdebug("Direct_read_file cannot open %s", name);
return(0);
}
//ok, find the length and read the file in
fseek(fh, 0, SEEK_END); //get size of file
end = ftell(fh); //finally got the end
fseek( fh, 0, SEEK_SET ); //back to beginning of file
if (fread( ad, sizeof(char), end,fh)==-1)
{ Zdebug("Direct_read_file read fail %d", name);
return(0);
}
fclose(fh);
return(end); //ok, done it - return bytes read
}
//-----------------------------------------------------------------------------------------------------------------------
int32 Direct_write_file(char *name, char *ad, uint32 total_bytes) //Tony1May96
{
//load the file directly into the memory location passed
int fh;
//fh = open(name, _O_RDWR | _O_CREAT); //open for reading
fh = open(name, O_RDWR | O_CREAT); //open for reading
if (fh==-1)
{ Zdebug("Direct_write_file open fail %d", name);
return(-1);
}
if (write( fh, ad, total_bytes)==-1)
{ Zdebug("Direct_write_file write fail %d", name);
return(-1);
}
close(fh);
return(0); //ok, done it
}
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------

33
sword2/tony_gsdk.h Normal file
View file

@ -0,0 +1,33 @@
/* 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$
*/
#ifndef TONY_GSDK
#define TONY_GSDK
//#include "src\driver96.h"
#include "memory.h"
uint32 Read_file(char *name, mem **membloc, uint32 uid);
int32 Direct_read_file(char *name, char *ad);
int32 Direct_write_file(char *name, char *ad, uint32 total_bytes);
#endif

932
sword2/walker.cpp Normal file
View file

@ -0,0 +1,932 @@
/* 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$
*/
//--------------------------------------------------------------------------------------
// WALKER.CPP by James (14nov96)
// script functions for moving megas about the place & also for keeping tabs on them
// FN_walk() // walk to (x,y,dir)
// FN_walk_to_anim() // walk to start position of anim
// FN_turn() // turn to (dir)
// FN_stand_at() // stand at (x,y,dir)
// FN_stand() // stand facing (dir)
// FN_stand_after_anim() // stand at end position of anim
// FN_face_id() // turn to face object (id)
// FN_face_xy() // turn to face point (x,y)
// FN_is_facing() // is mega (id) facing us?
// FN_get_pos() // get details of another mega's position
//--------------------------------------------------------------------------------------
//#include "src\driver96.h"
#include "console.h"
#include "defs.h"
#include "events.h"
#include "function.h"
#include "interpreter.h"
#include "logic.h" // for FN_add_to_kill_list
#include "object.h"
#include "protocol.h"
#include "router.h"
#include "sync.h"
//--------------------------------------------------------------------------------------
int16 standby_x; // see FN_set_standby_coords
int16 standby_y;
uint8 standby_dir;
//--------------------------------------------------------------------------------------
/*
uint8 Check_walk_anim_ok( Object_mega *ob_mega, Object_walkdata *ob_walkdata );
//--------------------------------------------------------------------------------------
// NEW CODE TO VERIFY THAT THE WALK-ANIM CONTAINS NO INVALID FRAMES!
// (James 15sep97)
uint8 Check_walk_anim_ok( Object_mega *ob_mega, Object_walkdata *ob_walkdata )
{
int32 walk_pc=0;
_walkData *walkAnim;
uint8 *anim_file;
_animHeader *anim_head;
uint32 lastValidFrameNo;
uint8 ok=1;
anim_file = res_man.Res_open(ob_mega->megaset_res); // open mega-set file
anim_head = FetchAnimHeader( anim_file ); // set up pointer to the animation header
lastValidFrameNo = anim_head->noAnimFrames-1; // get last valid frame number
res_man.Res_close(ob_mega->megaset_res); // close file
walkAnim = LockRouteMem(); // lock the _walkData array
while (ok && (walkAnim[walk_pc].frame != 512)) // '512' id end-marker
{
if (walkAnim[walk_pc].frame > lastValidFrameNo) // if frame exceeds the allowed range
ok=0;
walk_pc++;
}
FloatRouteMem(); // allow _walkData array to float about memory again
return(ok);
}
*/
//--------------------------------------------------------------------------------------
// walk mega to (x,y,dir)
int32 FN_walk(int32 *params) // James (14nov96)
{
// 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 object's walkdata structure
// 4 target x-coord
// 5 target y-coord
// 6 target direction
Object_logic *ob_logic;
Object_graphic *ob_graph;
Object_mega *ob_mega;
Object_walkdata *ob_walkdata;
int16 target_x;
int16 target_y;
uint8 target_dir;
int8 route;
int32 walk_pc;
_walkData *walkAnim;
uint8 colliding=0; // set to 1 when collision avoided
//----------------------------------------------------------------------------------------
// get the parameters
ob_logic = (Object_logic *)params[0];
ob_graph = (Object_graphic *)params[1];
ob_mega = (Object_mega *)params[2];
target_x = params[4];
target_y = params[5];
target_dir = params[6];
//----------------------------------------------------------------------------------------
// if this is the start of the walk, calculate route
if (ob_logic->looping==0)
{
//---------------------------
// If we're already there, don't even bother allocating memory and calling the router,
// just quit back & continue the script!
// This avoids an embarassing mega stand frame appearing for one cycle when we're already
// in position for an anim eg. repeatedly clicking on same object to repeat an anim
// - no mega frame will appear in between runs of the anim.
if ((ob_mega->feet_x == target_x) && (ob_mega->feet_y == target_y)
&& (ob_mega->current_dir == target_dir))
{
RESULT = 0; // 0 means ok - finished walk
return(IR_CONT); // may as well continue the script
}
//---------------------------
if ((params[6] < 0) || (params[6] > 8)) // invalid direction (NB. '8' means end walk on ANY direction)
Con_fatal_error("Invalid direction (%d) in FN_walk (%s line %u)",params[6],__FILE__,__LINE__);
//---------------------------
ob_walkdata = (Object_walkdata *)params[3];
ob_mega->walk_pc=0; //always
AllocateRouteMem(); // set up mem for _walkData in route_slots[] & set mega's 'route_slot_id' accordingly
route = RouteFinder(ob_mega, ob_walkdata, target_x, target_y, target_dir);
/*
if (id == PLAYER)
{
nExtraBars = 0;
nExtraNodes = 0;
if ((route == 1) || (route == 2))
{
megaOnGrid = 0; // if we have just checked a grid with the mega on the grid take the mega off
reRouteGeorge = 0;
}
}
*/
if ((route == 1) || (route == 2)) // 1=created route 2=zero route but may need to turn
{
//-------------------------------------------
ob_logic->looping = 1; // so script FN_walk loop continues until end of walk-anim
// need to animate the route now, so don't set result or return yet!
ob_mega->currently_walking=1; // started walk(James23jun97)
// (see FN_get_player_savedata() in save_rest.cpp
//-------------------------------------------
}
else // 0=can't make route to target
{
FreeRouteMem(); // free up the walkdata mem block
RESULT = 1; // 1 means error, no walk created
return(IR_CONT); // may as well continue the script
}
// ok, walk is about to start, so set the mega's graphic resource
ob_graph->anim_resource = ob_mega->megaset_res;
}
//----------------------------------------------------------------------------------------
// double clicked an exit so quit the walk when screen is black
else if ((EXIT_FADING) && (GetFadeStatus()==RDFADE_BLACK))
{
// ok, thats it - back to script and change screen
ob_logic->looping=0; // so script loop stops
FreeRouteMem(); // free up the walkdata mem block
EXIT_CLICK_ID=0; // must clear in-case on the new screen there's a walk instruction (which would get cut short)
// EXIT_FADING=0; // this will be reset when we change screens, so we can use it in script to check if a 2nd-click came along
ob_mega->currently_walking=0; // finished walk (James23jun97)
// (see FN_get_player_savedata() in save_rest.cpp
ob_mega->colliding=0;
RESULT = 0; // 0 means ok
return(IR_CONT); // continue the script so that RESULT can be checked!
}
//----------------------------------------------------------------------------------------
// get pointer to walkanim & current frame position
walkAnim = LockRouteMem(); // lock the _walkData array
walk_pc = ob_mega->walk_pc;
//----------------------------------------------------------------------------------------
// if stopping the walk early, overwrite the next step with a slow-out, then finish
if (Check_event_waiting())
{
if ((walkAnim[walk_pc].step == 0) && (walkAnim[walk_pc+1].step == 1)) // at the beginning of a step
{
ob_walkdata = (Object_walkdata *)params[3];
EarlySlowOut(ob_mega,ob_walkdata);
}
}
/*
else if (CheckForCollision())
{
if ((walkAnim[walk_pc].step == 0) && (walkAnim[walk_pc+1].step == 1)) // at the beginning of a step
{
ob_walkdata = (Object_walkdata *)params[3];
EarlySlowOut(ob_mega,ob_walkdata);
ob_mega->colliding=1;
}
}
*/
//------------------------------------------------------------------
// get new frame of walk
ob_graph->anim_pc = walkAnim[walk_pc].frame;
ob_mega->current_dir = walkAnim[walk_pc].dir;
ob_mega->feet_x = walkAnim[walk_pc].x;
ob_mega->feet_y = walkAnim[walk_pc].y;
//------------------------------------------------------------------
// check if NEXT frame is in fact the end-marker of the walk sequence
// so we can return to script just as the final (stand) frame of the walk is set
// - so that if followed by an anim, the anim's first frame replaces the final stand-frame
// of the walk (see below)
if (walkAnim[walk_pc+1].frame==512) // '512' is end-marker
{
ob_logic->looping=0; // so script loop stops
FreeRouteMem(); // free up the walkdata mem block
ob_mega->currently_walking=0; // finished walk(James23jun97)
// (see FN_get_player_savedata() in save_rest.cpp
/*
if (ID==CUR_PLAYER_ID)
{
george_walking = 0;
if (megaOnGrid == 2)
megaOnGrid = 0;
}
*/
if (Check_event_waiting()) // if George's walk has been interrupted to run a new action script for instance
{ // or Nico's walk has been interrupted by player clicking on her to talk
ob_mega->colliding=0; // Don't care about collision now we've got an event
Start_event();
RESULT = 1; // 1 means didn't finish walk
return(IR_TERMINATE);
}
else if (ob_mega->colliding) // If we almost collided with another mega,
{ // then we want to re-route from scratch.
ob_mega->colliding=0; // reset the flag now we've acknowledged the collision
return(IR_REPEAT); // Stop the script, but repeat this call next cycle
}
else
{
RESULT = 0; // 0 means ok - finished walk
return(IR_CONT); // CONTINUE the script so that RESULT can be checked!
// Also, if an anim command follows the FN_walk command,
// the 1st frame of the anim (which is always a stand frame itself)
// can replace the final stand frame of the walk, to hide the
// slight difference between the shrinking on the mega frames
// and the pre-shrunk anim start-frame.
}
}
//----------------------------------------------------------------------------------------
// increment the walkanim frame number, float the walkanim & come back next cycle
ob_mega->walk_pc++;
FloatRouteMem(); // allow _walkData array to float about memory again
return(IR_REPEAT); // stop the script, but repeat this call next cycle
//------------------------------------------------------------------
}
//--------------------------------------------------------------------------------------
// walk mega to start position of anim
int32 FN_walk_to_anim(int32 *params) // James (14nov96)
{
// 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 object's walkdata structure
// 4 anim resource id
Object_logic *ob_logic;
uint8 *anim_file;
_animHeader *anim_head;
int32 pars[7];
//----------------------------------------------------------------------------------------
// if this is the start of the walk, read anim file to get start coords
ob_logic = (Object_logic *)params[0];
if (ob_logic->looping==0)
{
anim_file = res_man.Res_open(params[4]); // open anim file
anim_head = FetchAnimHeader( anim_file ); // point to animation header
pars[4] = anim_head->feetStartX; // target_x
pars[5] = anim_head->feetStartY; // target_y
pars[6] = anim_head->feetStartDir; // target_dir
res_man.Res_close(params[4]); // close anim file
//------------------------------------------
if ((pars[4]==0)&&(pars[5]==0)) // if start coords not yet set in anim header
{
pars[4] = standby_x; // use the standby coords
pars[5] = standby_y; // (which should be set beforehand in the script)
pars[6] = standby_dir;
Zdebug("WARNING: FN_walk_to_anim(%s) used standby coords", FetchObjectName(params[4]));
}
if ((pars[6] < 0) || (pars[6] > 7)) // check for invalid direction
Con_fatal_error("Invalid direction (%d) in FN_walk_to_anim (%s line %u)", pars[6],__FILE__,__LINE__);
//------------------------------------------
}
//----------------------------------------------------------------------------------------
// set up the rest of the parameters for FN_walk()
pars[0] = params[0];
pars[1] = params[1];
pars[2] = params[2];
pars[3] = params[3]; // walkdata - needed for EarlySlowOut if player clicks elsewhere during the walk
//-------------------------------------------------------------------------------------------------------
return FN_walk(pars); // call FN_walk() with target coords set to anim start position
}
//--------------------------------------------------------------------------------------
// turn mega to <direction>
// just needs to call FN_walk() with current feet coords, so router can produce anim of turn frames
int32 FN_turn(int32 *params) // James (15nov96)
{
// 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 object's walkdata structure
// 4 target direction
Object_logic *ob_logic;
Object_mega *ob_mega;
int32 pars[7];
// if this is the start of the turn, get the mega's current feet coords + the required direction
ob_logic = (Object_logic *)params[0];
if (ob_logic->looping==0)
{
//--------------------------------------------
if ((params[4] < 0) || (params[4] > 7)) // invalid direction
Con_fatal_error("Invalid direction (%d) in FN_turn (%s line %u)",params[4],__FILE__,__LINE__);
//--------------------------------------------
ob_mega = (Object_mega *)params[2];
pars[4] = ob_mega->feet_x;
pars[5] = ob_mega->feet_y;
pars[6] = params[4]; // DIRECTION to turn to
}
//----------------------------------------------------------------------------------------
// set up the rest of the parameters for FN_walk()
pars[0] = params[0];
pars[1] = params[1];
pars[2] = params[2];
pars[3] = params[3];
//----------------------------------------------------------------------------------------
return FN_walk(pars); // call FN_walk() with target coords set to feet coords
}
//--------------------------------------------------------------------------------------
// stand mega at (x,y,dir)
// sets up the graphic object, but also needs to set the new 'current_dir' in the mega object, so the router knows in future
int32 FN_stand_at(int32 *params) // James
{
// params: 0 pointer to object's graphic structure
// 1 pointer to object's mega structure
// 2 target x-coord
// 3 target y-coord
// 4 target direction
Object_mega *ob_mega;
Object_graphic *ob_graph;
//----------------------------------------------------------------------------------------
// check for invalid direction
if ((params[4] < 0) || (params[4] > 7)) // invalid direction
Con_fatal_error("Invalid direction (%d) in FN_stand_at (%s line %u)",params[4],__FILE__,__LINE__);
//----------------------------------------------------------------------------------------
// set up pointers to the graphic & mega structure
ob_graph = (Object_graphic *)params[0];
ob_mega = (Object_mega *)params[1];
//----------------------------------------------------------------------------------------
// set up the stand frame & set the mega's new direction
ob_graph->anim_resource = ob_mega->megaset_res; // mega-set animation file
ob_mega->feet_x = params[2]; // x
ob_mega->feet_y = params[3]; // y
ob_graph->anim_pc = params[4]+96; // dir + first stand frame (always frame 96)
ob_mega->current_dir = params[4]; // dir
//----------------------------------------------------------------------------------------
return(IR_CONT); // continue the script
}
//--------------------------------------------------------------------------------------
// stand mega in <direction> at current feet coords
// just needs to call FN_stand_at() with current feet coords
int32 FN_stand(int32 *params) // James (15nov96)
{
// params: 0 pointer to object's graphic structure
// 1 pointer to object's mega structure
// 2 target direction
Object_mega *ob_mega = (Object_mega *)params[1];
int32 pars[5];
pars[0] = params[0];
pars[1] = params[1];
pars[2] = ob_mega->feet_x;
pars[3] = ob_mega->feet_y;
pars[4] = params[2]; // DIRECTION to stand in
return FN_stand_at(pars); // call FN_stand_at() with target coords set to feet coords
}
//--------------------------------------------------------------------------------------
// stand mega at end position of anim
int32 FN_stand_after_anim(int32 *params) // James (14nov96)
{
// params: 0 pointer to object's graphic structure
// 1 pointer to object's mega structure
// 2 anim resource id
uint8 *anim_file;
_animHeader *anim_head;
int32 pars[5];
//----------------------------------------------------------------------------------------
// open the anim file & set up a pointer to the animation header
anim_file = res_man.Res_open(params[2]); // open anim file
anim_head = FetchAnimHeader( anim_file );
//----------------------------------------------------------------------------------------
// set up the parameter list for FN_walk_to()
pars[0] = params[0];
pars[1] = params[1];
pars[2] = anim_head->feetEndX; // x
pars[3] = anim_head->feetEndY; // y
pars[4] = anim_head->feetEndDir; // dir
//----------------------------------------------------------------------------------------
if ((pars[2]==0)&&(pars[3]==0)) // if start coords not available either
{
pars[2] = standby_x; // use the standby coords
pars[3] = standby_y; // (which should be set beforehand in the script)
pars[4] = standby_dir;
Zdebug("WARNING: FN_stand_after_anim(%s) used standby coords", FetchObjectName(params[2]));
}
if ((pars[4] < 0) || (pars[4] > 7)) // check for invalid direction
Con_fatal_error("Invalid direction (%d) in FN_stand_after_anim (%s line %u)", pars[4],__FILE__,__LINE__);
//----------------------------------------------------------------------------------------
// close the anim file
res_man.Res_close(params[2]); // close anim file
//----------------------------------------------------------------------------------------
return FN_stand_at(pars); // call FN_stand_at() with target coords set to anim end position
}
//--------------------------------------------------------------------------------------
// stand mega at start position of anim
int32 FN_stand_at_anim(int32 *params) // James (07feb97)
{
// params: 0 pointer to object's graphic structure
// 1 pointer to object's mega structure
// 2 anim resource id
uint8 *anim_file;
_animHeader *anim_head;
int32 pars[5];
//----------------------------------------------------------------------------------------
// open the anim file & set up a pointer to the animation header
anim_file = res_man.Res_open(params[2]); // open anim file
anim_head = FetchAnimHeader( anim_file );
//----------------------------------------------------------------------------------------
// set up the parameter list for FN_walk_to()
pars[0] = params[0];
pars[1] = params[1];
pars[2] = anim_head->feetStartX; // x
pars[3] = anim_head->feetStartY; // y
pars[4] = anim_head->feetStartDir; // dir
if ((pars[2]==0)&&(pars[3]==0)) // if start coords not available
{
pars[2] = standby_x; // use the standby coords
pars[3] = standby_y; // (which should be set beforehand in the script)
pars[4] = standby_dir;
Zdebug("WARNING: FN_stand_at_anim(%s) used standby coords", FetchObjectName(params[2]));
}
if ((pars[4] < 0) || (pars[4] > 7)) // check for invalid direction
Con_fatal_error("Invalid direction (%d) in FN_stand_after_anim (%s line %u)", pars[4],__FILE__,__LINE__);
//-------------------------------------------------------------------------------------------------------
// close the anim file
res_man.Res_close(params[2]); // close anim file
//-------------------------------------------------------------------------------------------------------
return FN_stand_at(pars); // call FN_stand_at() with target coords set to anim end position
}
//--------------------------------------------------------------------------------------
// Code to workout direction from start to dest
#define diagonalx 36 // used in what_target not valid for all megas jps 17mar95
#define diagonaly 8
int What_target(int startX, int startY, int destX, int destY) //S2.1(20Jul95JPS)
{
int tar_dir;
//setting up
int deltaX = destX-startX;
int deltaY = destY-startY;
int signX = (deltaX > 0);
int signY = (deltaY > 0);
int slope;
if ( (abs(deltaY) * diagonalx ) < (abs(deltaX) * diagonaly / 2))
{
slope = 0;// its flat
}
else if ( (abs(deltaY) * diagonalx / 2) > (abs(deltaX) * diagonaly ) )
{
slope = 2;// its vertical
}
else
{
slope = 1;// its diagonal
}
if (slope == 0) //flat
{
if (signX == 1) // going right
{
tar_dir = 2;
}
else
{
tar_dir = 6;
}
}
else if (slope == 2) //vertical
{
if (signY == 1) // going down
{
tar_dir = 4;
}
else
{
tar_dir = 0;
}
}
else if (signX == 1) //right diagonal
{
if (signY == 1) // going down
{
tar_dir = 3;
}
else
{
tar_dir = 1;
}
}
else //left diagonal
{
if (signY == 1) // going down
{
tar_dir = 5;
}
else
{
tar_dir = 7;
}
}
return tar_dir;
}
//--------------------------------------------------------------------------------------
// turn mega to face point (x,y) on the floor
// just needs to call FN_walk() with current feet coords & direction computed by What_target()
int32 FN_face_xy(int32 *params) // James (29nov96)
{
// 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 object's walkdata structure
// 4 target x-coord
// 5 target y-coord
Object_logic *ob_logic;
Object_mega *ob_mega;
int32 pars[7];
//----------------------------------------------------------------------------------------
// if this is the start of the turn, get the mega's current feet coords + the required direction
ob_logic = (Object_logic *)params[0];
if (ob_logic->looping==0)
{
ob_mega = (Object_mega *)params[2];
pars[4] = ob_mega->feet_x;
pars[5] = ob_mega->feet_y;
pars[6] = What_target( ob_mega->feet_x, ob_mega->feet_y, params[4], params[5] ); // set target direction
}
//----------------------------------------------------------------------------------------
// set up the rest of the parameters for FN_walk()
pars[0] = params[0];
pars[1] = params[1];
pars[2] = params[2];
pars[3] = params[3];
//----------------------------------------------------------------------------------------
return FN_walk(pars); // call FN_walk() with target coords set to feet coords
}
//--------------------------------------------------------------------------------------
int32 FN_face_mega(int32 *params) //S2.1(3mar95jps) Tony29Nov96
{
//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 object's walkdata structure
// 4 id of target mega to face
uint32 null_pc=3; //get ob_mega
char *raw_script_ad;
int32 pars[7];
Object_logic *ob_logic;
Object_mega *ob_mega;
_standardHeader *head;
ob_mega = (Object_mega *)params[2];
ob_logic = (Object_logic *)params[0];
if (ob_logic->looping==0)
{
// get targets info
head = (_standardHeader*) res_man.Res_open(params[4]);
if (head->fileType!=GAME_OBJECT)
Con_fatal_error("FN_face_mega %d not an object", params[4]);
raw_script_ad = (char *)head; // (head+1) + sizeof(_object_hub); //get to raw script data
RunScript( raw_script_ad, raw_script_ad, &null_pc ); //call the base script - this is the graphic/mouse service call
res_man.Res_close(params[4]);
// engine_mega is now the Object_mega of mega we want to turn to face
pars[3] = params[3];
pars[4] = ob_mega->feet_x;
pars[5] = ob_mega->feet_y;
pars[6] = What_target( ob_mega->feet_x, ob_mega->feet_y, engine_mega.feet_x, engine_mega.feet_y );
}
pars[0] = params[0];
pars[1] = params[1];
pars[2] = params[2];
pars[3] = params[3];
return FN_walk(pars); // call FN_walk() with target coords set to feet coords
}
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// FN_walk (here for reference instead of splitting a window)
// 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 object's walkdata structure
// 4 target x-coord
// 5 target y-coord
// 6 target direction
//------------------------------------------------------------------------------------
int32 FN_walk_to_talk_to_mega(int32 *params) //Tony2Dec96
{
//we route to left or right hand side of target id if possible
//target is a shrinking mega
Object_mega *ob_mega;
Object_logic *ob_logic;
uint32 null_pc=3; //4th script - get mega
char *raw_script_ad;
int32 pars[7];
int scale;
int mega_seperation=params[5];
_standardHeader *head;
//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 object's walkdata structure
// 4 id of target mega to face
// 5 distance
ob_logic = (Object_logic*) params[0];
ob_mega = (Object_mega*) params[2];
pars[0] = params[0]; // standard stuff
pars[1] = params[1];
pars[2] = params[2];
pars[3] = params[3]; // walkdata
if (!ob_logic->looping) //not been here before so decide where to walk-to
{
// first request the targets info
head = (_standardHeader*) res_man.Res_open(params[4]);
if (head->fileType!=GAME_OBJECT)
Con_fatal_error("FN_walk_to_talk_to_mega %d not an object", params[4]);
raw_script_ad = (char *)head; // (head+1) + sizeof(_object_hub); //get to raw script data
RunScript( raw_script_ad, raw_script_ad, &null_pc ); //call the base script - this is the graphic/mouse service call
res_man.Res_close(params[4]);
// engine_mega is now the Object_mega of mega we want to route to
pars[5] = engine_mega.feet_y; // stand exactly beside the mega, ie. at same y-coord
// apply scale factor to walk distance
scale = (ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b)/256; // Ay+B gives 256*scale ie. 256*256*true_scale for even better accuracy, ie. scale = (Ay+B)/256
mega_seperation= (mega_seperation*scale)/256;
// Zdebug("seperation %d", mega_seperation);
// Zdebug(" target x %d, y %d", engine_mega.feet_x, engine_mega.feet_y);
if (engine_mega.feet_x < ob_mega->feet_x) // target is left of us
{
pars[4] = engine_mega.feet_x+mega_seperation; // so aim to stand to their right
pars[6] = 5; // face down_left
}
else // ok, must be right of us
{
pars[4] = engine_mega.feet_x-mega_seperation; // so aim to stand to their left
pars[6] = 3; // face down_right
}
}
//first cycle builds the route - thereafter merely follows it
return FN_walk(pars); //call FN_walk() with target coords set to feet coords
//RESULT will be 1 when it finishes or 0 if it failed to build route
}
//------------------------------------------------------------------------------------
int32 FN_set_walkgrid(int32 *params) // (6dec96 JEL)
{
Con_fatal_error("FN_set_walkgrid no longer valid");
return(IR_CONT); // continue script
}
//---------------------------------------------------------------------------------------------------------------------
// add this walkgrid resource to the list of those used for routing in this location
// - note this is ignored in the resource is already in the list
int32 FN_add_walkgrid(int32 *params) // (03mar97 JEL)
{
// params 0 id of walkgrid resource
// all objects that add walkgrids must be restarted whenever we reneter a location
if (ID != 8) // DON'T EVER KILL GEORGE!
FN_add_to_kill_list(params);// need to call this in case it wasn't called in script! ('params' just used as dummy param)
AddWalkGrid(params[0]);
res_man.Res_open(params[0]); // Touch the grid, getting it into memory.
res_man.Res_close(params[0]);
return(IR_CONT); // continue script
}
//---------------------------------------------------------------------------------------------------------------------
// remove this walkgrid resource from the list of those used for routing in this location
// - note that this is ignored if the resource isn't actually in the list
int32 FN_remove_walkgrid(int32 *params) // (03mar97 JEL)
{
// params 0 id of walkgrid resource
RemoveWalkGrid(params[0]);
return(IR_CONT); // continue script
}
//---------------------------------------------------------------------------------------------------------------------
int32 FN_register_walkgrid(int32 *params)
{
Con_fatal_error("FN_register_walkgrid no longer valid");
return(IR_CONT); // continue script
}
//---------------------------------------------------------------------------------------------------------------------
int32 FN_set_scaling(int32 *params) // (6dec96 JEL)
{
// params 0 pointer to object's mega structure
// 1 scale constant A
// 2 scale constant B
// 256*s = A*y + B
// where s is system scale, which itself is (256 * actual_scale) ie. s==128 is half size
Object_mega *ob_mega = (Object_mega *) params[0];
ob_mega->scale_a = params[1];
ob_mega->scale_b = params[2];
return(IR_CONT); // continue script
}
//---------------------------------------------------------------------------------------------------------------------
int32 FN_set_standby_coords(int32 *params) // (10dec97 JEL)
{
// set the standby walk coords to be used by FN_walk_to_anim & FN_stand_after_anim
// when the anim header's start/end coords are zero
// useful during development; can stay in final game anyway
// params 0 x-coord
// 1 y-coord
// 2 direction (0..7)
//----------------------------------------------------------------------------------------
// check for invalid direction
if ((params[2] < 0) || (params[2] > 7)) // invalid direction
Con_fatal_error("Invalid direction (%d) in FN_set_standby_coords (%s line %u)",params[2],__FILE__,__LINE__);
//----------------------------------------------------------------------------------------
standby_x = params[0];
standby_y = params[1];
standby_dir = params[2];
return(IR_CONT); // continue script
}
//---------------------------------------------------------------------------------------------------------------------

34
sword2/walker.h Normal file
View file

@ -0,0 +1,34 @@
/* 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$
*/
#ifndef _WALKER
#define _WALKER
//#include "src\driver96.h"
int32 FN_face_mega(int32 *params);
int32 FN_turn(int32 *params);
int32 FN_walk(int32 *params); // James (14nov96)
int32 FN_walk_to_anim(int32 *params); // James (14nov96)
int32 FN_stand_after_anim(int32 *params); // James (18jun97)
int32 FN_stand(int32 *params); // James
#endif