aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sword2/.cvsignore1
-rw-r--r--sword2/anims.cpp911
-rw-r--r--sword2/anims.h36
-rw-r--r--sword2/build_display.cpp1255
-rw-r--r--sword2/build_display.h81
-rw-r--r--sword2/console.cpp1341
-rw-r--r--sword2/console.h81
-rw-r--r--sword2/controls.cpp2917
-rw-r--r--sword2/controls.h38
-rw-r--r--sword2/credits.h28
-rw-r--r--sword2/debug.cpp553
-rw-r--r--sword2/debug.h92
-rw-r--r--sword2/defs.h139
-rw-r--r--sword2/events.cpp405
-rw-r--r--sword2/events.h48
-rw-r--r--sword2/function.cpp458
-rw-r--r--sword2/function.h31
-rw-r--r--sword2/header.h355
-rw-r--r--sword2/icons.cpp244
-rw-r--r--sword2/icons.h42
-rw-r--r--sword2/interpreter.cpp791
-rw-r--r--sword2/interpreter.h173
-rw-r--r--sword2/layers.cpp297
-rw-r--r--sword2/layers.h61
-rw-r--r--sword2/logic.cpp441
-rw-r--r--sword2/logic.h62
-rw-r--r--sword2/maketext.cpp694
-rw-r--r--sword2/maketext.h94
-rw-r--r--sword2/mem_view.cpp259
-rw-r--r--sword2/mem_view.h31
-rw-r--r--sword2/memory.cpp544
-rw-r--r--sword2/memory.h82
-rw-r--r--sword2/module.mk46
-rw-r--r--sword2/mouse.cpp1466
-rw-r--r--sword2/mouse.h89
-rw-r--r--sword2/object.h124
-rw-r--r--sword2/protocol.cpp240
-rw-r--r--sword2/protocol.h44
-rw-r--r--sword2/resman.cpp1539
-rw-r--r--sword2/resman.h101
-rw-r--r--sword2/router.cpp3089
-rw-r--r--sword2/router.h58
-rw-r--r--sword2/save_rest.cpp556
-rw-r--r--sword2/save_rest.h47
-rw-r--r--sword2/scroll.cpp154
-rw-r--r--sword2/scroll.h29
-rw-r--r--sword2/sound.cpp504
-rw-r--r--sword2/sound.h55
-rw-r--r--sword2/speech.cpp1994
-rw-r--r--sword2/speech.h44
-rw-r--r--sword2/startup.cpp339
-rw-r--r--sword2/startup.h45
-rw-r--r--sword2/sword2.cpp572
-rw-r--r--sword2/sword2.h62
-rw-r--r--sword2/sync.cpp179
-rw-r--r--sword2/sync.h32
-rw-r--r--sword2/tony_gsdk.cpp151
-rw-r--r--sword2/tony_gsdk.h33
-rw-r--r--sword2/walker.cpp932
-rw-r--r--sword2/walker.h34
60 files changed, 25143 insertions, 0 deletions
diff --git a/sword2/.cvsignore b/sword2/.cvsignore
new file mode 100644
index 0000000000..39a06683b7
--- /dev/null
+++ b/sword2/.cvsignore
@@ -0,0 +1 @@
+.deps
diff --git a/sword2/anims.cpp b/sword2/anims.cpp
new file mode 100644
index 0000000000..ad3f5f80ae
--- /dev/null
+++ b/sword2/anims.cpp
@@ -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
+}
+//---------------------------------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------------------------------
diff --git a/sword2/anims.h b/sword2/anims.h
new file mode 100644
index 0000000000..3b9d245a61
--- /dev/null
+++ b/sword2/anims.h
@@ -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
diff --git a/sword2/build_display.cpp b/sword2/build_display.cpp
new file mode 100644
index 0000000000..600d0b19b7
--- /dev/null
+++ b/sword2/build_display.cpp
@@ -0,0 +1,1255 @@
+/* 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$
+ */
+
+//------------------------------------------------------------------------------------
+// BUILD_DISPLAY.CPP like the old spr_engi but slightly more aptly named
+//------------------------------------------------------------------------------------
+//#include <mmsystem.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+//#include <windows.h>
+//#include <windowsx.h>
+
+#include "driver/driver96.h"
+#include "build_display.h"
+#include "console.h"
+#include "debug.h"
+#include "defs.h"
+#include "events.h"
+#include "function.h"
+#include "header.h"
+#include "interpreter.h"
+#include "layers.h"
+#include "logic.h"
+#include "maketext.h"
+#include "memory.h"
+#include "mouse.h"
+#include "object.h"
+#include "protocol.h"
+#include "resman.h"
+#include "router.h"
+#include "save_rest.h"
+#include "scroll.h"
+#include "sword2.h"
+
+//------------------------------------------------------------------------------------
+
+buildit bgp0_list[MAX_bgp0_sprites];
+buildit bgp1_list[MAX_bgp1_sprites];
+buildit back_list[MAX_back_sprites];
+buildit sort_list[MAX_sort_sprites];
+buildit fore_list[MAX_fore_sprites];
+buildit fgp0_list[MAX_fgp0_sprites];
+buildit fgp1_list[MAX_fgp1_sprites];
+
+uint16 sort_order[MAX_sort_sprites]; //holds the order of the sort list - i.e the list stays static and we sort this
+
+uint32 cur_bgp0;
+uint32 cur_bgp1;
+uint32 cur_back;
+uint32 cur_sort;
+uint32 cur_fore;
+uint32 cur_fgp0;
+uint32 cur_fgp1;
+
+#ifdef _DEBUG
+uint32 largest_layer_area=0; // should be reset to zero at start of each screen change
+uint32 largest_sprite_area=0; // - " -
+char largest_layer_info[128] = {"largest layer: none registered"};
+char largest_sprite_info[128] = {"largest sprite: none registered"};
+#endif
+
+//------------------------------------------------------------------------------------
+// last palette used - so that we can restore the correct one after a pause (which dims the screen)
+// - and it's not always the main screen palette that we want, eg. during the eclipse
+
+// This flag gets set in Start_new_palette() and SetFullPalette()
+
+uint32 lastPaletteRes=0;
+
+//------------------------------------------------------------------------------------
+// 'frames per second' counting stuff
+
+uint32 fps=0;
+uint32 cycleTime=0;
+uint32 frameCount=0;
+extern uint32 mouse_status; // So I know if the control Panel can be activated - CJR 1-5-97
+
+//------------------------------------------------------------------------------------
+// function prototypes not needed externally
+
+void Start_new_palette(void); //Tony25Sept96
+
+void Register_frame(int32 *params, buildit *build_unit); // (1nov96JEL)
+void Process_image(buildit *frame);
+void Process_layer(uint32 layer_number); //Tony24Sept96
+void Sort_the_sort_list(void); //Tony18Sept96
+
+void Send_back_par0_frames(void); //James23Jan97
+void Send_back_par1_frames(void); //James23Jan97
+void Send_back_frames(void); //Tony23Sept96
+void Send_sort_frames(void);
+void Send_fore_frames(void);
+void Send_fore_par0_frames(void); //James23Jan97
+void Send_fore_par1_frames(void); //James23Jan97
+
+
+//------------------------------------------------------------------------------------
+//
+// PC Build_display
+//
+//------------------------------------------------------------------------------------
+void Build_display(void) //Tony21Sept96
+{
+ BOOL end;
+ uint8 pal[12]={0,0,0,0,0,0,0,0,0,255,0,0};
+ uint8 *file;
+ _multiScreenHeader *screenLayerTable;
+
+#ifdef _DEBUG // only used by console
+ _spriteInfo spriteInfo;
+ uint32 rv; // drivers error return value
+#endif
+
+
+
+ if ((!console_status)&&(this_screen.new_palette))
+ {
+ Start_new_palette(); // start the layer palette fading up
+
+ #ifdef _DEBUG // (James23jun97)
+ largest_layer_area=0; // should be reset to zero at start of each screen change
+ largest_sprite_area=0; // - " -
+ #endif
+ }
+
+
+
+ if ((!console_status)&&(this_screen.background_layer_id)) // there is a valid screen to run
+ {
+ SetScrollTarget(this_screen.scroll_offset_x, this_screen.scroll_offset_y); // set the scroll position
+
+ AnimateMouse(); // increment the mouse frame
+
+ StartRenderCycle();
+
+ while (1) // START OF RENDER CYCLE
+ {
+ //----------------------------------------------------
+ // clear the back buffer, before building up the new screen
+ // from the back forwards
+
+ EraseBackBuffer();
+
+ //----------------------------------------------------
+ // first background parallax + related anims
+
+ file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
+ screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
+
+ if (screenLayerTable->bg_parallax[0])
+ {
+ RenderParallax(FetchBackgroundParallaxLayer(file, 0), 0);
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource before cacheing the sprites
+ Send_back_par0_frames();
+ }
+ else
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource
+
+ //----------------------------------------------------
+ // second background parallax + related anims
+
+ file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
+ screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
+
+ if (screenLayerTable->bg_parallax[1])
+ {
+ RenderParallax(FetchBackgroundParallaxLayer(file, 1), 1);
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource before cacheing the sprites
+ Send_back_par1_frames();
+ }
+ else
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource
+
+ //----------------------------------------------------
+ // normal backround layer (just the one!)
+
+ file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
+ RenderParallax(FetchBackgroundLayer(file), 2);
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource
+
+ //----------------------------------------------------
+ // sprites & layers
+
+ Send_back_frames(); // background sprites
+ Sort_the_sort_list();
+ Send_sort_frames(); // sorted sprites & layers
+ Send_fore_frames(); // foreground sprites
+
+ //----------------------------------------------------
+ // first foreground parallax + related anims
+
+ file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
+ screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
+
+ if (screenLayerTable->fg_parallax[0])
+ {
+ RenderParallax(FetchForegroundParallaxLayer(file, 0), 3);
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource before cacheing the sprites
+ Send_fore_par0_frames();
+ }
+ else
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource
+
+ //----------------------------------------------------
+ // second foreground parallax + related anims
+
+ file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
+ screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
+
+ if (screenLayerTable->fg_parallax[1])
+ {
+ RenderParallax(FetchForegroundParallaxLayer(file, 1), 4);
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource before cacheing the sprites
+ Send_fore_par1_frames();
+ }
+ else
+ res_man.Res_close(this_screen.background_layer_id); // release the screen resource
+
+ //----------------------------------------------------
+ // walkgrid, mouse & player markers & mouse area rectangle
+
+ Draw_debug_graphics(); // JAMES (08apr97)
+
+ //----------------------------------------------------
+ // text blocks
+
+ Print_text_blocs(); // speech blocks and headup debug text
+
+ //----------------------------------------------------
+ // menu bar & icons
+
+ ProcessMenu();
+
+ //----------------------------------------------------
+ // ready - blit to screen
+
+ CopyScreenBuffer();
+ FlipScreens();
+
+ //----------------------------------------------------
+ // update our fps reading
+
+ frameCount += 1;
+ if (timeGetTime() > cycleTime)
+ {
+ fps = frameCount;
+ frameCount = 0;
+ cycleTime = timeGetTime()+1000;
+ }
+ //----------------------------------------------------
+ // check if we've got time to render the screen again this cycle
+ // (so drivers can smooth out the scrolling in between normal game cycles)
+
+ EndRenderCycle(&end);
+
+ if (end) // if we haven't got time to render again this cycle, drop out of 'render cycle' while-loop
+ break;
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if the game is being shut down, drop out
+ break;
+
+ //----------------------------------------------------
+ } // END OF RENDER CYCLE
+
+
+ }
+#ifdef _DEBUG
+ else if (console_status)
+ {
+ spriteInfo.x = 0;
+ spriteInfo.y = con_y;
+ spriteInfo.w = con_width;
+ spriteInfo.h = con_depth;
+ spriteInfo.scale = 0;
+ spriteInfo.scaledWidth = 0;
+ spriteInfo.scaledHeight = 0;
+ spriteInfo.type = RDSPR_DISPLAYALIGN+RDSPR_NOCOMPRESSION; // no compression!
+ spriteInfo.blend = 0;
+ spriteInfo.data = console_sprite->ad;
+ spriteInfo.colourTable = 0;
+
+
+ rv = DrawSprite( &spriteInfo );
+ if (rv)
+ ExitWithReport("Driver Error %.8x (drawing console) [%s line %u]", rv, __FILE__, __LINE__);
+
+ CopyScreenBuffer();
+ FlipScreens();
+ }
+ else
+ {
+ StartConsole();
+ SetPalette(0, 3, pal, RDPAL_INSTANT); //force the palette
+ Print_to_console("no valid screen?");
+ }
+#endif // _DEBUG
+
+}
+
+//------------------------------------------------------------------------------------
+//
+// Fades down and displays a message on the screen for time seconds
+//
+void DisplayMsg( uint8 *text, int time ) // Chris 15May97
+{
+ mem *text_spr;
+ _frameHeader *frame;
+ _spriteInfo spriteInfo;
+ bool done = false;
+ _palEntry pal[256];
+ _palEntry oldPal[256];
+ int16 oldY;
+ int16 oldX;
+ uint32 rv; // drivers error return value
+
+ warning("DisplayMsg: %s", (char *) text);
+
+
+ if (GetFadeStatus() != RDFADE_BLACK)
+ {
+ FadeDown((float) 0.75);
+
+ 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(GetFadeStatus()==RDFADE_DOWN);
+ }
+
+ Set_mouse(NULL);
+ Set_luggage(0); //tw28Aug
+
+ EraseBackBuffer(); // for hardware rendering
+ EraseSoftwareScreenBuffer(); // for software rendering
+
+ text_spr = MakeTextSprite( text, 640, 187, speech_font_id );
+
+ frame = (_frameHeader*) text_spr->ad;
+
+ spriteInfo.x = screenWide/2 - frame->width/2;
+ if (!time)
+ spriteInfo.y = screenDeep/2 - frame->height/2 - RDMENU_MENUDEEP;
+ else
+ spriteInfo.y = 400 - frame->height;
+ spriteInfo.w = frame->width;
+ spriteInfo.h = frame->height;
+ spriteInfo.scale = 0;
+ spriteInfo.scaledWidth = 0;
+ spriteInfo.scaledHeight = 0;
+ spriteInfo.type = RDSPR_DISPLAYALIGN+RDSPR_NOCOMPRESSION+RDSPR_TRANS;
+ spriteInfo.blend = 0;
+ spriteInfo.data = text_spr->ad + sizeof(_frameHeader);
+ spriteInfo.colourTable = 0;
+ oldX = spriteInfo.x;
+ oldY = spriteInfo.y;
+
+
+ rv = DrawSprite( &spriteInfo );
+ if (rv)
+ ExitWithReport("Driver Error %.8x (in DisplayMsg) [%s line %u]", rv, __FILE__, __LINE__);
+
+
+
+ spriteInfo.x = oldX;
+ spriteInfo.y = oldY;
+
+ memcpy((char *) oldPal, (char *) palCopy, 256*sizeof(_palEntry));
+
+ memset(pal, 0, 256*sizeof(_palEntry));
+ pal[187].red = 255;
+ pal[187].green = 255;
+ pal[187].blue = 255;
+ SetPalette(0, 256, (uint8 *) pal, RDPAL_FADE);
+
+ CopyScreenBuffer();
+ FlipScreens();
+
+ FadeUp((float)0.75);
+
+ Free_mem(text_spr);
+
+ 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(GetFadeStatus()==RDFADE_UP);
+
+ DWORD targetTime = timeGetTime() + (time*1000);
+
+ while(timeGetTime() < targetTime)
+ {
+ //--------------------------------------------------
+ // 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
+ }
+ //--------------------------------------------------
+
+ EraseBackBuffer(); // for hardware rendering
+ EraseSoftwareScreenBuffer(); // for software rendering
+
+ rv = DrawSprite( &spriteInfo ); // Keep the message there even when the user task swaps.
+ if (rv)
+ ExitWithReport("Driver Error %.8x (in DisplayMsg) [%s line %u]", rv, __FILE__, __LINE__);
+
+ spriteInfo.y = oldY; // Drivers change the y co-ordinate, don't know why...
+ spriteInfo.x = oldX;
+ CopyScreenBuffer();
+ FlipScreens();
+ }
+
+ SetPalette(0, 256, (uint8 *) oldPal, RDPAL_FADE);
+}
+
+//------------------------------------------------------------------------------------
+//
+// Fades message down and removes it, fading up again afterwards
+//
+void RemoveMsg( void ) // Chris 15May97
+{
+ FadeDown((float)0.75);
+
+ 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(GetFadeStatus()==RDFADE_DOWN);
+
+ EraseBackBuffer(); // for hardware rendering
+ EraseSoftwareScreenBuffer(); // for software rendering
+ CopyScreenBuffer();
+ FlipScreens();
+
+// FadeUp((float)0.75);
+// removed by JEL (08oct97) to prevent "eye" smacker corruption when restarting game from CD2
+// and also to prevent palette flicker when restoring game to a different CD
+// - since the "insert CD" message uses this routine to clean up!
+
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+void Send_back_par0_frames(void) //James23Jan97
+{
+ uint32 j;
+
+ for (j=0; j<cur_bgp0; j++) // could be none at all - theoretically at least
+ {
+ Process_image(&bgp0_list[j]); // frame attached to 1st background parallax
+ }
+}
+//------------------------------------------------------------------------------------
+void Send_back_par1_frames(void) //James23Jan97
+{
+ uint32 j;
+
+ for (j=0; j<cur_bgp1; j++) // could be none at all - theoretically at least
+ {
+ Process_image(&bgp1_list[j]); // frame attached to 1nd background parallax
+ }
+}
+//------------------------------------------------------------------------------------
+void Send_back_frames(void) //Tony23Sept96
+{
+ uint32 j;
+
+ for (j=0; j<cur_back; j++) // could be none at all - theoretically at least
+ {
+ Process_image(&back_list[j]);
+ }
+}
+//------------------------------------------------------------------------------------
+void Send_sort_frames(void) //Tony23Sept96
+{
+ //send the sort frames for printing - layers, shrinkers & normal flat sprites
+ uint32 j;
+
+ for (j=0; j<cur_sort; j++) // could be none at all - theoretically at least
+ {
+ if (sort_list[sort_order[j]].layer_number) //its a layer - minus 1 for true layer number
+ Process_layer(sort_list[sort_order[j]].layer_number-1); //we need to know from the buildit because the layers will have been sorted in random order
+ else
+ Process_image(&sort_list[sort_order[j]]); // sprite
+ }
+}
+//------------------------------------------------------------------------------------
+void Send_fore_frames(void) //Tony23Sept96
+{
+ uint32 j;
+
+ for (j=0; j<cur_fore; j++) // could be none at all - theoretically at least
+ {
+ Process_image(&fore_list[j]);
+ }
+}
+//------------------------------------------------------------------------------------
+void Send_fore_par0_frames(void) //James23Jan97
+{
+ uint32 j;
+
+ for (j=0; j<cur_fgp0; j++) // could be none at all - theoretically at least
+ {
+ Process_image(&fgp0_list[j]); // frame attached to 1st foreground parallax
+ }
+}
+//------------------------------------------------------------------------------------
+void Send_fore_par1_frames(void) //James23Jan97
+{
+ uint32 j;
+
+ for (j=0; j<cur_fgp1; j++) // could be none at all - theoretically at least
+ {
+ Process_image(&fgp1_list[j]); // frame attached to 2nd foreground parallax
+ }
+}
+//------------------------------------------------------------------------------------
+void Process_layer(uint32 layer_number) //Tony24Sept96
+{
+ uint8 *file;
+ _layerHeader *layer_head;
+ _spriteInfo spriteInfo;
+ uint32 rv;
+
+ #ifdef _DEBUG
+ uint32 current_layer_area=0;
+ #endif
+
+
+ file = res_man.Res_open(this_screen.background_layer_id); // file points to 1st byte in the layer file
+
+ layer_head = FetchLayerHeader(file,layer_number); // point to layer header
+
+
+ spriteInfo.x = layer_head->x;
+ spriteInfo.y = layer_head->y;
+ spriteInfo.w = layer_head->width;
+ spriteInfo.scale = 0;
+ spriteInfo.scaledWidth = 0;
+ spriteInfo.scaledHeight = 0;
+ spriteInfo.h = layer_head->height;
+ spriteInfo.type = RDSPR_TRANS + RDSPR_RLE256FAST;
+ spriteInfo.blend = 0;
+ spriteInfo.data = file+sizeof(_standardHeader)+layer_head->offset;
+ spriteInfo.colourTable = 0;
+
+
+ //------------------------------------------
+ // check for largest layer for debug info
+ #ifdef _DEBUG
+ current_layer_area = layer_head->width * layer_head->height;
+
+ if (current_layer_area > largest_layer_area)
+ {
+ largest_layer_area = current_layer_area;
+ sprintf (largest_layer_info, "largest layer: %s layer(%d) is %dx%d", FetchObjectName(this_screen.background_layer_id), layer_number, layer_head->width, layer_head->height);
+ }
+ #endif
+ //------------------------------------------
+
+ rv = DrawSprite( &spriteInfo );
+ if (rv)
+ ExitWithReport("Driver Error %.8x in Process_layer(%d) [%s line %u]", rv, layer_number, __FILE__, __LINE__);
+
+
+ res_man.Res_close(this_screen.background_layer_id);
+
+}
+//------------------------------------------------------------------------------------
+void Process_image(buildit *build_unit) // (5nov96 JEL)
+{
+ uint8 *file, *colTablePtr=NULL;
+ _animHeader *anim_head;
+ _frameHeader *frame_head;
+ _cdtEntry *cdt_entry;
+ _spriteInfo spriteInfo;
+ uint32 spriteType;
+ uint32 rv;
+
+ #ifdef _DEBUG
+ uint32 current_sprite_area=0;
+ #endif
+
+ file = res_man.Res_open(build_unit->anim_resource); // open anim resource file & point to base
+
+ anim_head = FetchAnimHeader( file );
+ cdt_entry = FetchCdtEntry( file, build_unit->anim_pc );
+ frame_head = FetchFrameHeader( file, build_unit->anim_pc );
+
+
+ spriteType = RDSPR_TRANS; // so that 0-colour is transparent
+
+ if (anim_head->blend)
+ spriteType += RDSPR_BLEND;
+
+ if ((cdt_entry->frameType) & FRAME_FLIPPED) // if the frame is to be flipped (only really applicable to frames using offsets)
+ spriteType += RDSPR_FLIP;
+
+ if ((cdt_entry->frameType) & FRAME_256_FAST)
+ {
+ if ((build_unit->scale)||(anim_head->blend)||(build_unit->shadingFlag)) // scaling, shading & blending don't work with RLE256FAST
+ spriteType += RDSPR_RLE256; // but the same compression can be decompressed using the RLE256 routines!
+ else
+ spriteType += RDSPR_RLE256FAST;
+ }
+ else
+ {
+ switch (anim_head->runTimeComp) // what compression was used?
+ {
+ case NONE:
+ spriteType += RDSPR_NOCOMPRESSION;
+ break;
+ case RLE256:
+ spriteType += RDSPR_RLE256;
+ break;
+ case RLE16:
+ spriteType += RDSPR_RLE16;
+ colTablePtr = (uint8*)(anim_head+1) + anim_head->noAnimFrames*sizeof(_cdtEntry);
+ // points to just after last cdt_entry, ie. start of colour table
+ break;
+ }
+ }
+
+ if (build_unit->shadingFlag==1) // if we want this frame to be affected by the shading mask
+ spriteType += RDSPR_SHADOW; // add the status bit
+
+ spriteInfo.x = build_unit->x;
+ spriteInfo.y = build_unit->y;
+ spriteInfo.w = frame_head->width;
+ spriteInfo.h = frame_head->height;
+ spriteInfo.scale = build_unit->scale;
+ spriteInfo.scaledWidth = build_unit->scaled_width;
+ spriteInfo.scaledHeight = build_unit->scaled_height;
+ spriteInfo.type = spriteType;
+ spriteInfo.blend = anim_head->blend;
+ spriteInfo.data = (uint8*)(frame_head+1); // points to just after frame header, ie. start of sprite data
+ spriteInfo.colourTable = colTablePtr;
+
+
+ //------------------------------------------
+ // check for largest layer for debug info
+ #ifdef _DEBUG
+ current_sprite_area = frame_head->width * frame_head->height;
+
+ if (current_sprite_area > largest_sprite_area)
+ {
+ largest_sprite_area = current_sprite_area;
+ sprintf (largest_sprite_info, "largest sprite: %s frame(%d) is %dx%d", FetchObjectName(build_unit->anim_resource), build_unit->anim_pc, frame_head->width, frame_head->height);
+ }
+ #endif
+ //------------------------------------------
+
+
+ //-----------------------------------------------------------
+ #ifdef _DEBUG
+ if (SYSTEM_TESTING_ANIMS) // see anims.cpp
+ {
+ if ((spriteInfo.x + spriteInfo.scaledWidth) >= 639) // bring the anim into the visible screen
+ spriteInfo.x = 639-spriteInfo.scaledWidth; // but leave extra pixel at edge for box
+
+ if ((spriteInfo.y + spriteInfo.scaledHeight) >= 399)
+ spriteInfo.y = 399-spriteInfo.scaledHeight;
+
+ if (spriteInfo.x < 1)
+ spriteInfo.x = 1;
+
+ if (spriteInfo.y < 1)
+ spriteInfo.y = 1;
+
+ rect_x1 = spriteInfo.x - 1; // create box to surround sprite - just outside sprite box
+ rect_y1 = spriteInfo.y - 1;
+ rect_x2 = spriteInfo.x + spriteInfo.scaledWidth;
+ rect_y2 = spriteInfo.y + spriteInfo.scaledHeight;
+ }
+ #endif
+ //-----------------------------------------------------------
+
+ //--------------------------------------------------
+// #ifdef _DEBUG
+// if (frame_head->width <= 1)
+// {
+// Zdebug(8,"WARNING: 1-pixel-wide frame found in %s (%d)", FetchObjectName(build_unit->anim_resource), build_unit->anim_resource);
+// }
+// #endif
+ //--------------------------------------------------
+
+ rv = DrawSprite( &spriteInfo );
+ if (rv)
+ ExitWithReport("Driver Error %.8x with sprite %s (%d) in Process_image [%s line %u]", rv, FetchObjectName(build_unit->anim_resource), build_unit->anim_resource, __FILE__, __LINE__);
+
+
+ res_man.Res_close(build_unit->anim_resource); // release the anim resource
+
+}
+//------------------------------------------------------------------------------------
+void Reset_render_lists(void) //Tony18Sept96
+{
+//reset the sort lists - do this before a logic loop
+//takes into account the fact that the start of the list is pre-built with the special sortable layers
+
+ uint32 j;
+
+ cur_bgp0=0;
+ cur_bgp1=0;
+ cur_back=0;
+ cur_sort=this_screen.number_of_layers; //beginning of sort list is setup with the special sort layers
+ cur_fore=0;
+ cur_fgp0=0;
+ cur_fgp1=0;
+
+
+ if (cur_sort) //there are some layers - so rebuild the sort order positioning
+ for (j=0;j<cur_sort;j++)
+ sort_order[j]=j; //rebuild the order list
+}
+//------------------------------------------------------------------------------------
+void Sort_the_sort_list(void) //Tony18Sept96
+{
+//sort the list
+
+ uint16 i,j,swap;
+
+
+//sort the list
+
+ if (cur_sort>1) //cannot bubble sort 0 or 1 items!
+ for (i=0; i<cur_sort-1; i++)
+ for (j=0; j<cur_sort-1; j++)
+ if (sort_list[sort_order[j]].sort_y > sort_list[sort_order[j+1]].sort_y) //this > next then swap
+ { swap=sort_order[j];
+ sort_order[j]=sort_order[j+1];
+ sort_order[j+1]=swap;
+ }
+}
+//------------------------------------------------------------------------------------
+void Register_frame(int32 *params, buildit *build_unit) // (1nov96JEL)
+{
+ // params: 0 pointer to mouse structure or NULL for no write to mouse list (non-zero means write sprite-shape to mouse list)
+ // 1 pointer to graphic structure
+ // 2 pointer to mega structure
+
+ Object_mega *ob_mega;
+ Object_graphic *ob_graph;
+ Object_mouse *ob_mouse;
+ uint8 *file;
+ _frameHeader *frame_head;
+ _animHeader *anim_head;
+ _cdtEntry *cdt_entry;
+ int scale=0;
+
+
+ //-------------------------------------------
+ // open animation file & set up the necessary pointers
+
+ ob_graph = (Object_graphic *) params[1];
+
+ #ifdef _DEBUG
+ if (ob_graph->anim_resource == 0)
+ Con_fatal_error("ERROR: %s(%d) has no anim resource in Register_frame [line=%d file=%s]", FetchObjectName(ID), ID, __LINE__, __FILE__);
+ #endif
+
+ file = res_man.Res_open(ob_graph->anim_resource);
+
+ anim_head = FetchAnimHeader( file );
+ cdt_entry = FetchCdtEntry( file, ob_graph->anim_pc );
+ frame_head = FetchFrameHeader( file, ob_graph->anim_pc );
+
+
+ #ifdef _DEBUG
+ if (ID == CUR_PLAYER_ID) // update player graphic details for on-screen debug info
+ {
+ playerGraphic.type = ob_graph->type;
+ playerGraphic.anim_resource = ob_graph->anim_resource;
+ playerGraphic.anim_pc = ob_graph->anim_pc+1; // counting 1st frame as 'frame 1'
+ player_graphic_no_frames = anim_head->noAnimFrames;
+ }
+ #endif
+
+ //-------------------------------------------
+ // fill in the buildit structure for this frame
+
+ build_unit->anim_resource = ob_graph->anim_resource; //retrieve the resource
+ build_unit->anim_pc = ob_graph->anim_pc; //retrieve the frame
+ build_unit->layer_number = 0; //not a layer
+
+ if (ob_graph->type & SHADED_SPRITE)
+ build_unit->shadingFlag = 1; // affected by shading mask
+ else
+ build_unit->shadingFlag = 0; // not shaded
+
+ //-------------------------------------------
+ // check if this frame has offsets ie. this is a scalable mega frame
+ if ((cdt_entry->frameType) & FRAME_OFFSET)
+ {
+ ob_mega = (Object_mega *) params[2]; // param 2 is pointer to mega structure
+
+ // calc scale at which to print the sprite, based on feet y-coord & scaling constants (NB. 'scale' is actually 256*true_scale, to maintain accuracy)
+ 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
+ // calc final render coordinates (top-left of sprite), based on feet coords & scaled offsets
+ build_unit->x = ob_mega->feet_x + (cdt_entry->x * scale)/256; // add scaled offsets to feet coords
+ build_unit->y = ob_mega->feet_y + (cdt_entry->y * scale)/256;
+
+ // work out new width and height
+ build_unit->scaled_width = ((scale * frame_head->width) / 256); // always divide by 256 after everything else, to maintain accurary
+ build_unit->scaled_height = ((scale * frame_head->height) / 256);
+ }
+ else // it's a non-scaling anim
+ {
+ // get render coords for sprite, from cdt
+ build_unit->x = cdt_entry->x; //retrieve the x
+ build_unit->y = cdt_entry->y; //retrieve the y
+
+ // get width and height
+ build_unit->scaled_width = frame_head->width;
+ build_unit->scaled_height = frame_head->height;
+ }
+ //-------------------------------------------
+
+ build_unit->scale = scale; // either 0 or required scale, depending on whether 'scale' computed
+
+ // calc the bottom y-coord for sorting purposes
+ build_unit->sort_y = build_unit->y + build_unit->scaled_height - 1;
+ //-------------------------------------------
+
+ if (params[0]) // passed a mouse structure, so add to the mouse_list
+ {
+ ob_mouse = (Object_mouse *) params[0];
+
+ if (ob_mouse->pointer) // only if 'pointer' isn't NULL (James13feb97)
+ {
+ #ifdef _DEBUG
+ if (cur_mouse==TOTAL_mouse_list)
+ Con_fatal_error("ERROR: mouse_list full [%s line %u]",__FILE__,__LINE__);
+ #endif
+
+ mouse_list[cur_mouse].x1 = build_unit->x;
+ mouse_list[cur_mouse].y1 = build_unit->y;
+ mouse_list[cur_mouse].x2 = build_unit->x + build_unit->scaled_width;
+ mouse_list[cur_mouse].y2 = build_unit->y + build_unit->scaled_height;
+
+ mouse_list[cur_mouse].priority = ob_mouse->priority;
+ mouse_list[cur_mouse].pointer = ob_mouse->pointer;
+
+ //-----------------------------------------------
+ // (James17jun97)
+ // check if pointer text field is set due to previous object using this slot (ie. not correct for this one)
+ if ((mouse_list[cur_mouse].pointer_text) && (mouse_list[cur_mouse].id != (int32)ID)) // if 'pointer_text' field is set, but the 'id' field isn't same is current id
+ mouse_list[cur_mouse].pointer_text=0; // then we don't want this "left over" pointer text
+ //-----------------------------------------------
+
+
+ mouse_list[cur_mouse].id = ID;
+
+ mouse_list[cur_mouse].anim_resource = 0; // not using sprite as detection mask
+ mouse_list[cur_mouse].anim_pc = 0;
+
+ cur_mouse++;
+ }
+ }
+ //-------------------------------------------
+
+ res_man.Res_close(ob_graph->anim_resource); // close animation file
+}
+//------------------------------------------------------------------------------------
+
+int32 FN_register_frame(int32 *params) // (27nov96 JEL)
+{
+ //this call would be made from an objects service script 0
+
+ // params: 0 pointer to mouse structure or NULL for no write to mouse list (non-zero means write sprite-shape to mouse list)
+ // 1 pointer to graphic structure
+ // 2 pointer to mega structure or NULL if not a mega
+
+ Object_graphic *ob_graph = (Object_graphic *) params[1];
+
+
+ switch (ob_graph->type & 0x0000ffff) // check low word for sprite type
+ {
+ //---------------
+ case BGP0_SPRITE:
+ {
+ #ifdef _DEBUG
+ if (cur_bgp0==MAX_bgp0_sprites)
+ Con_fatal_error("ERROR: bgp0_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
+ #endif
+
+ Register_frame(params, &bgp0_list[cur_bgp0]);
+ cur_bgp0++;
+ }
+ break;
+ //---------------
+ case BGP1_SPRITE:
+ {
+ #ifdef _DEBUG
+ if (cur_bgp1==MAX_bgp1_sprites)
+ Con_fatal_error("ERROR: bgp1_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
+ #endif
+
+ Register_frame(params, &bgp1_list[cur_bgp1]);
+ cur_bgp1++;
+ }
+ break;
+ //---------------
+ case BACK_SPRITE:
+ {
+ #ifdef _DEBUG
+ if (cur_back==MAX_back_sprites)
+ Con_fatal_error("ERROR: back_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
+ #endif
+
+ Register_frame(params, &back_list[cur_back]);
+ cur_back++;
+ }
+ break;
+ //---------------
+ case SORT_SPRITE:
+ {
+ #ifdef _DEBUG
+ if (cur_sort==MAX_sort_sprites)
+ Con_fatal_error("ERROR: sort_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
+ #endif
+
+ sort_order[cur_sort]=cur_sort;
+
+ Register_frame(params, &sort_list[cur_sort]);
+ cur_sort++;
+ }
+ break;
+ //---------------
+ case FORE_SPRITE:
+ {
+ #ifdef _DEBUG
+ if (cur_fore==MAX_fore_sprites)
+ Con_fatal_error("ERROR: fore_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
+ #endif
+
+ Register_frame(params, &fore_list[cur_fore]);
+ cur_fore++;
+ }
+ break;
+ //---------------
+ case FGP0_SPRITE:
+ {
+ #ifdef _DEBUG
+ if (cur_fgp0==MAX_fgp0_sprites)
+ Con_fatal_error("ERROR: fgp0_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
+ #endif
+
+ Register_frame(params, &fgp0_list[cur_fgp0]);
+ cur_fgp0++;
+ }
+ break;
+ //---------------
+ case FGP1_SPRITE:
+ {
+ #ifdef _DEBUG
+ if (cur_fgp1==MAX_fgp1_sprites)
+ Con_fatal_error("ERROR: fgp1_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
+ #endif
+
+ Register_frame(params, &fgp1_list[cur_fgp1]);
+ cur_fgp1++;
+ }
+ break;
+ //---------------
+ // NO_SPRITE no registering!
+ }
+
+
+ return(IR_CONT);
+}
+//------------------------------------------------------------------------------------
+void Start_new_palette(void) //Tony25Sept96
+{
+ //start layer palette fading up
+ uint8 black[4]={0,0,0,0};
+
+ uint8 *screenFile;
+
+ //if the screen is still fading down then wait for black - could happen when everythings cached into a large memory model
+ do
+ {
+ ServiceWindows();
+ }
+ while(GetFadeStatus()==RDFADE_DOWN);
+
+
+ screenFile = res_man.Res_open(this_screen.background_layer_id); // open the screen file
+
+ UpdatePaletteMatchTable((uint8 *) FetchPaletteMatchTable(screenFile));
+
+ SetPalette(0, 256, FetchPalette(screenFile), RDPAL_FADE);
+ lastPaletteRes=0; // indicating that it's a screen palette
+
+ res_man.Res_close(this_screen.background_layer_id); // close screen file
+
+ //FadeUp((float)1.75); // start fade up
+ FadeUp((float)0.75); // start fade up
+
+ this_screen.new_palette=0; // reset
+}
+//------------------------------------------------------------------------------------
+int32 FN_update_player_stats(int32 *params) //Tony28Nov96
+{
+//engine needs to know certain info about the player
+
+
+ Object_mega *ob_mega = (Object_mega *) params[0];
+
+
+
+
+ this_screen.player_feet_x = ob_mega->feet_x;
+ this_screen.player_feet_y = ob_mega->feet_y;
+
+ PLAYER_FEET_X=ob_mega->feet_x; //for the script
+ PLAYER_FEET_Y=ob_mega->feet_y;
+ PLAYER_CUR_DIR=ob_mega->current_dir;
+
+ SCROLL_OFFSET_X=this_screen.scroll_offset_x;
+
+ //Zdebug(42,"%d %d", ob_mega->feet_x, ob_mega->feet_y);
+
+ return(IR_CONT);
+}
+//------------------------------------------------------------------------------------
+int32 FN_fade_down(int32 *params) //Tony5Dec96
+{
+
+ if (GetFadeStatus()==RDFADE_NONE) //NONE means up! can only be called when screen is fully faded up - multiple calls wont have strange effects
+ {
+ FadeDown((float)0.75);
+
+ return(IR_CONT);
+ }
+
+ return(IR_CONT);
+}
+
+int32 FN_fade_up(int32 *params) //Chris 15May97
+{
+ do
+ {
+ ServiceWindows();
+ }
+ while(GetFadeStatus()==RDFADE_DOWN);
+
+ if (GetFadeStatus()==RDFADE_BLACK)
+ {
+ FadeUp((float)0.75);
+
+ return(IR_CONT);
+ }
+
+ return(IR_CONT);
+}
+//------------------------------------------------------------------------------------
+// typedef struct
+// {
+// uint8 red;
+// uint8 green;
+// uint8 blue;
+// uint8 alpha;
+// } _palEntry;
+
+//------------------------------------------------------------
+// typedef struct
+// {
+// uint8 firstEntry; // first colour number in this palette (0..255)
+// uint8 noEntries; // number of Entries-1 (0..255) to be taken as (1..256)
+// } _paletteHeader;
+
+//------------------------------------------------------------
+int32 FN_set_palette(int32 *params) // James05jun97
+{
+ SetFullPalette(params[0]);
+
+ return(IR_CONT);
+}
+//------------------------------------------------------------
+void SetFullPalette(int32 palRes) // James17jun97
+{
+ // params 0 resource number of palette file
+ // or 0 if it's to be the palette from the current screen
+
+ uint8 black[4]={0,0,0,0};
+ uint8 *file;
+ _standardHeader *head;
+
+
+ //----------------------------------
+ // fudge for hut interior
+ // - unpausing should restore last palette as normal (could be screen palette or 'dark_palette_13')
+ // - but restoring the screen palette after 'dark_plaette_13' should now work properly too!
+ if (LOCATION==13) // hut interior
+ {
+ if (palRes==0xffffffff) // unpausing
+ palRes = lastPaletteRes; // restore whatever palette was last set (screen palette or 'dark_palette_13')
+ }
+ else
+ {
+ // (James 03sep97)
+ // check if we're just restoring the current screen palette
+ // because we might actually need to use a separate palette file anyway
+ // eg. for pausing & unpausing during the eclipse
+
+ if (palRes==0xffffffff) // unpausing (fudged for location 13)
+ palRes=0; // we really meant '0'
+
+ if ((palRes==0) && (lastPaletteRes))
+ palRes = lastPaletteRes;
+ }
+ //----------------------------------
+
+
+ if (palRes) // non-zero: set palette to this separate palette file
+ {
+ head = (_standardHeader*)res_man.Res_open(palRes); // open the palette file
+
+ #ifdef _DEBUG
+ if (head->fileType != PALETTE_FILE)
+ Con_fatal_error("FN_set_palette() called with invalid resource! (%s line %u)",__FILE__,__LINE__);
+ #endif
+
+ file = (uint8*)(head+1);
+
+ file[0] = 0; // always set colour 0 to black
+ file[1] = 0; // because most background screen palettes have a bright colour 0
+ file[2] = 0; // although it should come out as black in the game!
+ file[3] = 0;
+
+// UpdatePaletteMatchTable(file+(256*4)); // not yet in separate palette files
+
+ SetPalette(0, 256, file, RDPAL_INSTANT);
+
+ if (palRes != CONTROL_PANEL_PALETTE) // (James 03sep97)
+ lastPaletteRes=palRes; // indicating that it's a separate palette resource
+
+
+ res_man.Res_close(palRes); // close palette file
+ }
+ else // 0: set palette to current screen palette
+ {
+ if (this_screen.background_layer_id)
+ {
+ file = res_man.Res_open(this_screen.background_layer_id); // open the screen file
+
+ UpdatePaletteMatchTable((uint8 *) FetchPaletteMatchTable(file));
+
+ SetPalette(0, 256, FetchPalette(file), RDPAL_INSTANT);
+ lastPaletteRes=0; // indicating that it's a screen palette
+
+ res_man.Res_close(this_screen.background_layer_id); // close screen file
+ }
+ else
+ Con_fatal_error("FN_set_palette(0) called, but no current screen available! (%s line %u)",__FILE__,__LINE__);
+ }
+}
+//------------------------------------------------------------
+
+int32 FN_restore_game(int32 *params)
+{
+
+ return (IR_CONT);
+}
+
+//------------------------------------------------------------
+
+int32 FN_change_shadows(int *params)
+{
+ uint32 rv;
+
+ 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__);
+
+ this_screen.mask_flag = 0;
+ }
+
+ return (IR_CONT);
+}
+
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+
diff --git a/sword2/build_display.h b/sword2/build_display.h
new file mode 100644
index 0000000000..84fda47aab
--- /dev/null
+++ b/sword2/build_display.h
@@ -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
diff --git a/sword2/console.cpp b/sword2/console.cpp
new file mode 100644
index 0000000000..3ae37ae23a
--- /dev/null
+++ b/sword2/console.cpp
@@ -0,0 +1,1341 @@
+/* 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 "driver/driver96.h"
+
+uint32 console_status=0; //0 off // LEFT IN RELEASE VERSION
+
+
+#ifdef _DEBUG
+
+//-----------------------------------------------------------------------------------------------------------------------
+//its the console! <great>
+//-----------------------------------------------------------------------------------------------------------------------
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h> // for version string stuff
+
+#include "build_display.h"
+#include "console.h"
+#include "debug.h"
+#include "defs.h"
+#include "events.h" // so we can disaply the event list in Con_display_events()
+#include "header.h"
+#include "layers.h"
+#include "logic.h"
+#include "maketext.h" // for InitialiseFontResourceFlags()
+#include "mouse.h"
+#include "mem_view.h"
+#include "memory.h"
+#include "protocol.h"
+#include "resman.h"
+#include "save_rest.h"
+#include "startup.h"
+#include "sword2.h"
+#include "time.h"
+
+//-----------------------------------------------------------------------------------------------------------------------
+// local function prototypes
+
+uint32 Parse_user_input(void); // Tony13Aug96
+void Clear_console_line(void); // Tony13Aug96
+void Con_help(void); // Tony13Aug96
+
+void Con_colour_block(int x, int width, int height, uint32 pen, uint32 paper, uint8 *sprite_data_ad);
+void Con_print(uint8 *ascii, uint32 pen, uint32 paper);
+uint32 Tconsole(uint32 mode); // Tony9Oct96
+
+void Con_list_savegames(void); // James05feb97
+void Con_save_game(int total_commands, uint8 *slotString, uint8 *description); // James05feb97
+void Con_restore_game(int total_commands, uint8 *slotString); // James05feb97
+uint8 Is_number(uint8 *ascii); // James05feb97
+void Con_start_timer(int total_commands, uint8 *slotString); // Paul12feb97
+void ShowVar(uint8 *varNoPtr); // James19mar97
+void HideVar(uint8 *varNoPtr); // James19mar97
+void Con_display_version(void); // James27mar97
+
+void Var_check(uint8 *pointer); //Tony8Jan97
+void Var_set(uint8 *pointer, uint8 *p2); //Tony8Jan97
+
+void Con_display_events(); // (James11july97)
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+uint8 wantSfxDebug=0; // sfx debug file enabled/disabled from console
+//-----------------------------------------------------------------------------------------------------------------------
+
+
+#define MAX_CONSOLE_BUFFER 70
+#define MAX_CONSOLE_PARAMS 5
+
+#define CON_PEN 187
+
+#define VK_TAB 0x09
+#define VK_RETURN 0x0D
+
+char console_buffer[MAX_CONSOLE_BUFFER];
+
+char last_command[MAX_CONSOLE_BUFFER]; // James 03apr97
+int last_command_len=0; // James 03apr97
+
+uint8 grabbingSequences=0;
+
+int console_pos=0; //cursor position within the typed line
+
+int console_mode=0; //0 is the base command line
+ //1 means only parse for yes or no commands
+ //1 on
+
+
+
+
+#define TOTAL_CONSOLE_COMMANDS 47
+
+uint8 commands[TOTAL_CONSOLE_COMMANDS][9]= // note '9' is max command length including null-terminator
+{
+ "HELP", // 0
+ "MEM", // 1
+ "Q", // 2
+ "TONY", // 3
+ "YES", // 4
+ "NO", // 5
+ "RES", // 6
+ "STARTS", // 7
+ "START", // 8
+ "INFO", // 9
+ "WALKGRID", // 10
+ "MOUSE", // 11
+ "PLAYER", // 12
+ "RESLOOK", // 13
+ "CUR", // 14
+ "RUNLIST", // 15
+ "KILL", // 16
+ "NUKE", // 17
+ "S", // 18
+ "VAR", // 19
+ "RECT", // 20
+ "CLEAR", // 21
+ "DEBUGON", // 22
+ "DEBUGOFF", // 23
+ "SAVEREST", // 24
+ "SAVES", // 25
+ "SAVE", // 26
+ "RESTORE", // 27
+ "BLTFXON", // 28
+ "BLTFXOFF", // 29
+ "TIMEON", // 30
+ "TIMEOFF", // 31
+ "TEXT", // 32
+ "SHOWVAR", // 33
+ "HIDEVAR", // 34
+ "VERSION", // 35
+ "SOFT", // 36
+ "HARD", // 37
+ "ANIMTEST", // 38
+ "TEXTTEST", // 39
+ "LINETEST", // 40
+ "GRAB", // 41
+ "EVENTS", // 42
+ "SFX", // 43
+ "ENGLISH", // 44
+ "FINNISH", // 45
+ "POLISH" // 46
+};
+
+mem *console_sprite;
+uint32 con_y;
+uint32 con_depth;
+uint32 con_width;
+uint32 con_chr_height;
+
+#define CON_lines 20 //10 lines deep
+
+//-----------------------------------------------------------------------------------------------------------------------
+void Init_console(void) //Tony9Sept96
+{
+//grab the memory for the console sprite
+
+ uint32 j;
+ uint8 *ad;
+ uint8 white[4] = {255,255,255,0}; // Chris 11Apr97
+
+
+ con_chr_height=12;
+ con_width=screenWide; //max across
+
+ SetPalette(CON_PEN, 1, white, RDPAL_INSTANT); // Force a palatte for the console. Chris 11Apr97
+
+ console_sprite = Twalloc(con_width*(CON_lines*con_chr_height), MEM_float, UID_con_sprite);
+
+ con_depth= CON_lines*con_chr_height;
+ con_y= 399-con_depth;
+
+
+
+//clear the buffer for a nice fresh start
+ ad=console_sprite->ad;
+ for (j=0;j<con_width*(CON_lines*con_chr_height);j++)
+ *(ad+j)=0;
+
+
+ if (!console_sprite)
+ {
+ Zdebug("Init_console Talloc fail");
+ ExitWithReport("Init_console Talloc fail [file=%s line=%u]",__FILE__,__LINE__);
+ }
+
+ Zdebug("console height %d, y %d", con_depth, con_y);
+
+ //first time in message
+ Con_display_version();
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void StartConsole(void) //Tony12Aug96
+{
+//start console up and restart new line
+//can ne called for newline
+
+ int j;
+
+
+ console_pos=0; //start of new line
+
+ for (j=0;j<MAX_CONSOLE_BUFFER;j++) //we need to clear the whole buffer - else the cursor overwrites the end 0
+ console_buffer[j]=0;
+
+
+ console_status=1; //on
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void EndConsole(void) //Tony9Oct96
+{
+
+ console_status=0; //off
+}
+//-----------------------------------------------------------------------------------------------------------------------
+uint32 Tconsole(uint32 mode) //Tony9Oct96
+{
+//call from anywhere
+//returns a positive value of the token typed or 0 for windows quiting - the caller should drop back
+
+ uint32 ret,breakOut=0;
+
+
+
+
+
+
+
+ console_mode=mode; //set command frame
+
+
+ StartConsole();
+
+ while (TRUE)
+ {
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ {
+ break;
+ }
+
+ while (!gotTheFocus)
+ {
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ {
+ breakOut = 1;
+ break;
+ }
+
+ }
+ if (breakOut)
+ {
+ break;
+ }
+
+//-----
+ if (ret = One_console())
+ { EndConsole();
+ return(ret);
+ }
+//-----
+ Build_display(); //create and flip the screen
+ }
+
+
+
+//a windows message is throwing us out of here
+
+ EndConsole(); //switch off drawing
+ return(0);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Scroll_console(void) //Tony13Aug96
+{
+//scroll the console sprite up 12 pixels
+
+ uint32 *to_buffer;
+ uint32 *from_buffer;
+ int x;
+
+
+ x=((con_depth-con_chr_height)*640)/4; //number of dwords
+
+ to_buffer= (uint32 *) console_sprite->ad; //base of console sprite
+ from_buffer= to_buffer+((con_chr_height*640)/4);
+
+ while(x--)
+ *(to_buffer++)=*(from_buffer++);
+
+
+
+ Clear_console_line(); //blank the on-coming bottom line
+}
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+void Clear_console_line(void) //Tony13Aug96
+{
+//blank the bottom line
+
+ uint32 *pbuffer;
+ uint32 x;
+
+
+ pbuffer= (uint32 *) console_sprite->ad; //base of our off-screen back buffer
+ pbuffer+= ((con_depth-con_chr_height)*con_width/4); //index to console text position
+
+ for (x=0;x<con_chr_height*(con_width/4);x++) //clear the bottom text line
+ *(pbuffer+x)=0;
+}
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+void Print_to_console(char *format,...) //Tony13Aug96
+{
+//print a NULL terminated string of ascii to the next console line
+//we can assume that the user has just entered a command by pressing return - which means we're on a clean line
+//so output the line and line feed
+
+ va_list arg_ptr; // Variable argument pointer
+ char buf[150];
+
+ va_start(arg_ptr,format);
+ _vsnprintf( buf, 150, format, arg_ptr);
+
+ Con_print( (uint8*)buf, 2, 0);
+ Scroll_console(); //line feed
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Temp_print_to_console(char *format,...) //Tony13Aug96
+{
+//print a NULL terminated string of ascii to the next console line
+//we can assume that the user has just entered a command by pressing return - which means we're on a clean line
+//so output the line and line feed
+
+ va_list arg_ptr; // Variable argument pointer
+ char buf[150];
+
+ va_start(arg_ptr,format);
+ _vsnprintf( buf, 150, format, arg_ptr);
+
+ Con_print( (uint8*)buf, 2, 0);
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+uint32 One_console(void) //Tony12Aug96
+{
+//its the console command line system
+//do an update - check keys and flash cursor and so on
+ char c;
+ static int flash=0; //controls the flashing cursor rate
+ uint32 res;
+
+
+ if (KeyWaiting())
+ {
+ ReadKey(&c);
+
+
+ if (!c) //escape sequences
+ {
+ }
+ else if (c==VK_TAB) // UP arrow
+ {
+ if (last_command_len) // if anything stored in buffer
+ {
+ // retrieve 'last_command' buffer
+ memset (console_buffer, 0, MAX_CONSOLE_BUFFER); // first clear the entire current buffer
+ memcpy (console_buffer, last_command, last_command_len); // now copy in the last command
+ console_pos = last_command_len;
+ }
+ }
+ else if (c==VK_RETURN) //RETurn
+ {
+ console_buffer[console_pos]=' '; //by putting a space in we'll always have a chr$ in the buffer
+ Clear_console_line();
+ Print_to_console(console_buffer);
+
+// parse the input I guess
+
+ if (console_pos)
+ {
+ // save to 'last_command' buffer, in case need to repeat same command (James03apr97)
+ memcpy (last_command, console_buffer, console_pos); // get a copy of the current command
+ last_command_len = console_pos; // get a copy of the length as well
+
+ res = Parse_user_input();
+ if (res)
+ return(res);
+ }
+
+ StartConsole(); //reset buffer
+ }
+ else if (c==8) //delete
+ {
+ if (console_pos)
+ {
+ console_buffer[console_pos]=0; //delete cursor chr$
+ console_pos--;
+ console_buffer[console_pos]=0;
+ }
+ }
+ else if ((c<32)||(c>'z'))
+ Zdebug("console ignoring key - %d", c);
+ else
+ {
+ if (console_pos<(MAX_CONSOLE_BUFFER-1)) //less one to leave room for the cursor
+ console_buffer[console_pos++]=c;
+
+ else //end of line has been reached, so keep replacing last letter
+ console_buffer[console_pos-1]=c; //replace
+ }
+ }
+
+
+ flash++;
+ if (flash<7)
+ console_buffer[console_pos]='_';
+ else
+ console_buffer[console_pos]=' '; //by putting a space in we'll always have a chr$ in the buffer
+
+ if (flash==14)
+ flash=0;
+
+
+
+//update the real screen - done every cycle to keep the cursor flashing
+ Clear_console_line();
+ Con_print( (uint8*)console_buffer, 2, 0);
+
+ return(0);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+uint32 Parse_user_input(void) //Tony13Aug96
+{
+//pressed return and now we need to analyse whats been written and call up the relevent commands
+
+ uint8 input[MAX_CONSOLE_PARAMS][MAX_CONSOLE_BUFFER];
+ int i,j,total_commands=0;
+ int index=0;
+ uint32 rv; // for driver return value
+ uint8 pal[4]={255,255,255,0};
+
+
+
+
+//quick check for numbers here
+ if (!isalpha(console_buffer[0]))
+ {
+ Print_to_console("Eh?"); //print the standard error message and quit
+ return(0);
+ }
+
+
+
+ j=0; //current command
+ do
+ {
+ i=0;
+ do
+ input[j][i++]=toupper(console_buffer[index++]);
+ while( isgraph(console_buffer[index]) );
+
+ input[j][i]=0; //NULL terminate
+
+ j++;
+ total_commands++;
+
+ if (index==console_pos)
+ break;
+
+ do
+ index++;
+ while( console_buffer[index]==' ' );
+ }
+ while(j<MAX_CONSOLE_PARAMS); //only parse first 5 params
+
+
+
+
+//try to find the first word in the commands base
+
+ for (j=0;j<TOTAL_CONSOLE_COMMANDS;j++)
+ {
+ i=0;
+ while((input[0][i]==commands[j][i])&&(input[0][i]))
+ i++;
+
+ if ((!input[0][i])&&(!commands[j][i])) //got to the end of an entry - so must have matched the whole word
+ {
+ switch(console_mode) //the console mode denotes the scope of the commands accepted 0 is the base mode
+ { //external console commands may only be requiring a yes/no input for example
+ //a different scope would only accept yes and no and drop back out when found... see?
+
+ case 0: //base command line
+ switch(j)
+ {
+ //---------------------------------
+ case 0: // HELP
+ Con_help();
+ return(0);
+ break;
+ //---------------------------------
+ case 1: // MEM
+ Console_mem_display();
+ return(0);
+ break;
+ //---------------------------------
+ case 2: // Q
+ return(1); //quit the console
+ break;
+ //---------------------------------
+ case 3: // TONY
+ Print_to_console("What about him?");
+ return(0);
+ break;
+ //---------------------------------
+ case 6: // RES
+ res_man.Print_console_clusters();
+ return(0);
+ break;
+ //---------------------------------
+ case 7: // STARTS
+ Con_print_start_menu();
+ return(0);
+ break;
+ //---------------------------------
+ case 8: // START
+ Con_start(&input[1][0]);
+ SetPalette(187, 1, pal, RDPAL_INSTANT); //force the palette
+ return(0);
+ break;
+ //---------------------------------
+ case 9: // INFO
+ displayDebugText = 1-displayDebugText;
+ if (displayDebugText)
+ Print_to_console("info text on");
+ else
+ Print_to_console("info text off");
+ return(0);
+ break;
+ //---------------------------------
+ case 10: // WALKGRID
+ displayWalkGrid = 1-displayWalkGrid;
+ if (displayWalkGrid)
+ Print_to_console("walk-grid display on");
+ else
+ Print_to_console("walk-grid display off");
+ return(0);
+ break;
+ //---------------------------------
+ case 11: // MOUSE
+ displayMouseMarker = 1-displayMouseMarker;
+ if (displayMouseMarker)
+ Print_to_console("mouse marker on");
+ else
+ Print_to_console("mouse marker off");
+ return(0);
+ break;
+ //---------------------------------
+ case 12: // PLAYER
+ displayPlayerMarker = 1-displayPlayerMarker;
+ if (displayPlayerMarker)
+ Print_to_console("player feet marker on");
+ else
+ Print_to_console("player feet marker off");
+ return(0);
+ break;
+ //---------------------------------
+ case 13: // RESLOOK
+ res_man.Examine_res(&input[1][0]);
+ return(0);
+ break;
+ //---------------------------------
+ case 14: // CUR
+ Print_current_info();
+ return(0);
+ break;
+ //---------------------------------
+ case 15: // RUNLIST
+ LLogic.Examine_run_list();
+ return(0);
+ break;
+ //---------------------------------
+ case 16: // KILL
+ res_man.Kill_res(&input[1][0]);
+ return(0);
+ break;
+ //---------------------------------
+ case 17: // NUKE
+ Print_to_console("killing all resources except variable file & player object...");
+ res_man.Kill_all_res(1); // '1' means we want output to console
+ return(0);
+ break;
+ //---------------------------------
+ case 18: // S (same as START)
+ Con_start(&input[1][0]);
+ SetPalette(187, 1, pal, RDPAL_INSTANT); //force the palette
+ return(0);
+ break;
+ //---------------------------------
+ case 19: // VAR
+ if (total_commands==2)
+ Var_check(&input[1][0]);
+ else Var_set(&input[1][0], &input[2][0]);
+
+ return(0);
+ break;
+ //---------------------------------
+ case 20: // RECT
+ definingRectangles = 1-definingRectangles; // switch on/off
+ if (definingRectangles)
+ Print_to_console("mouse rectangles enabled");
+ else
+ Print_to_console("mouse rectangles disabled");
+ draggingRectangle=0; // reset (see debug.cpp & mouse.cpp)
+ return(0);
+ break;
+ //---------------------------------
+ case 21: // CLEAR
+ Print_to_console("killing all object resources except player...");
+ res_man.Kill_all_objects(1); // '1' means we want output to console
+ return(0);
+ break;
+ //---------------------------------
+ case 22: // DEBUGON
+ displayDebugText = 1;
+ displayWalkGrid = 1;
+ displayMouseMarker = 1;
+ displayPlayerMarker = 1;
+ displayTextNumbers = 1;
+
+ Print_to_console("enabled all on-screen debug info");
+ return(0);
+ break;
+ //---------------------------------
+ case 23: // DEBUGOFF
+ displayDebugText = 0;
+ displayWalkGrid = 0;
+ displayMouseMarker = 0;
+ displayPlayerMarker = 0;
+ displayTextNumbers = 0;
+
+ definingRectangles = 0;
+ draggingRectangle = 0;
+
+ Print_to_console("disabled all on-screen debug info");
+ return(0);
+ break;
+ //---------------------------------
+ case 24: // SAVEREST
+ testingSnR = 1-testingSnR;
+ if (testingSnR)
+ Print_to_console("Enabled S&R logic_script stability checking");
+ else
+ Print_to_console("Disabled S&R logic_script stability checking");
+ return(0);
+ break;
+ //---------------------------------
+ case 25: // SAVES (James05feb97)
+ Print_to_console("Savegames:");
+ Con_list_savegames();
+ return(0);
+ break;
+ //---------------------------------
+ case 26: // SAVE <slotNo> <description> (James05feb97)
+ Con_save_game(total_commands, &input[1][0], &input[2][0]);
+ return(0);
+ break;
+ //---------------------------------
+ case 27: // RESTORE <slotNo> <description> (James05feb97)
+ Con_restore_game(total_commands, &input[1][0]);
+ return(1); //quit the console
+ break;
+ //---------------------------------
+ case 28: // BLTFXON (Paul12feb97)
+ SetBltFx();
+ Print_to_console("blit fx enabled");
+ return(0);
+ break;
+ //---------------------------------
+ case 29: // BLTFXOFF (Paul12feb97)
+ ClearBltFx();
+ Print_to_console("blit fx disabled");
+ return(0);
+ break;
+ //---------------------------------
+ case 30: // TIMEON (Paul12feb97)
+ Con_start_timer(total_commands, &input[1][0]);
+ Print_to_console("timer display on");
+ return(0);
+ break;
+ //---------------------------------
+ case 31: // TIMEOFF (Paul12feb97)
+ displayTime = 0;
+ Print_to_console("timer display off");
+ return(0);
+ break;
+ //---------------------------------
+ case 32: // TEXT (James25feb97)
+ displayTextNumbers = 1-displayTextNumbers;
+ if (displayTextNumbers)
+ Print_to_console("text numbers on");
+ else
+ Print_to_console("text numbers off");
+ return(0);
+ break;
+ //---------------------------------
+ case 33: // SHOWVAR <varNo> (James19mar97)
+ ShowVar(&input[1][0]); // add variable to watch-list
+ return(0);
+ break;
+ //---------------------------------
+ case 34: // HIDEVAR <varNo> (James19mar97)
+ HideVar(&input[1][0]); // remove variable from watch-list
+ return(0);
+ break;
+ //---------------------------------
+ case 35: // VERSION (James21mar97)
+ Con_display_version();
+ return(0);
+ break;
+ //---------------------------------
+ case 36: // SOFT (James07apr97)
+ if (RenderSoft())
+ Print_to_console("Software Rendering already enabled");
+ else
+ {
+ Print_to_console("Software Rendering enabled");
+ CloseBackgroundLayer(); // unlock from memory (because used in hardware rendering)
+ }
+ return(0);
+ break;
+ //---------------------------------
+ case 37: // HARD (James07apr97)
+ rv = RenderHard();
+
+ if (rv==RDERR_NOHARDWARE)
+ Print_to_console("Hardware Rendering not available");
+ else if (rv==RDERR_ALREADYON)
+ Print_to_console("Hardware Rendering already enabled");
+ else
+ Print_to_console("Hardware Rendering enabled");
+ return(0);
+ break;
+ //---------------------------------
+ case 38: // ANIMTEST
+ Con_start((uint8*)"32"); // automatically do "s 32" to run the text/speech testing start-script
+
+ Print_to_console("Setting flag 'system_testing_anims'");
+ Var_set((uint8*)"912", &input[1][0]); // same as typing "VAR 912 <value>" at the console
+
+ return(1);
+ break;
+ //---------------------------------
+ case 39: // TEXTTEST
+ Con_start((uint8*)"33"); // automatically do "s 33" to run the text/speech testing start-script
+
+ Print_to_console("Setting flag 'system_testing_text'");
+ Var_set((uint8*)"1230", &input[1][0]); // same as typing "VAR 1230 <value>" at the console
+
+ displayTextNumbers=1;
+ Print_to_console("text numbers on");
+
+ return(1);
+ break;
+ //---------------------------------
+ case 40: // LINETEST
+ Con_start((uint8*)"33"); // automatically do "s 33" to run the text/speech testing start-script
+
+ Print_to_console("Setting var 1230 (system_testing_text):");
+ Var_set((uint8*)"1230", &input[1][0]); // same as typing "VAR 1230 <value>" at the console
+
+ Print_to_console("Setting var 1264 (system_test_line_no):");
+ Var_set((uint8*)"1264", &input[2][0]); // same as typing "VAR 1264 <value>" at the console
+
+ displayTextNumbers=1;
+ Print_to_console("text numbers on");
+
+ return(1);
+ break;
+ //---------------------------------
+ case 41: // GRAB (James27jun97)
+ grabbingSequences = 1-grabbingSequences;
+ if (grabbingSequences)
+ Print_to_console("PCX-grabbing enabled");
+ else
+ Print_to_console("PCX-grabbing disabled");
+ return(0);
+ break;
+ //---------------------------------
+ case 42: // EVENTS (James11july97)
+ Con_display_events();
+ return(0);
+ break;
+ //---------------------------------
+ case 43: // SFX (James 16july97)
+ wantSfxDebug = 1-wantSfxDebug;
+ if (wantSfxDebug)
+ Print_to_console("SFX logging activated (see zebug.txt)");
+ else
+ Print_to_console("SFX logging deactivated");
+ return(0);
+ break;
+ //---------------------------------
+ case 44: // ENGLISH (James31july97)
+ InitialiseFontResourceFlags(DEFAULT_TEXT);
+ Print_to_console("Default fonts selected");
+ return(0);
+ break;
+ //---------------------------------
+ case 45: // FINNISH (James31july97)
+ InitialiseFontResourceFlags(FINNISH_TEXT);
+ Print_to_console("Finnish fonts selected");
+ return(0);
+ break;
+ //---------------------------------
+ case 46: // POLISH (James31july97)
+ InitialiseFontResourceFlags(POLISH_TEXT);
+ Print_to_console("Polish fonts selected");
+ return(0);
+ break;
+ //---------------------------------
+ default: //ignores 'yes' and 'no' (for example)
+ Print_to_console("??");
+ return(0);
+ break;
+ //---------------------------------
+ }
+ break;
+
+
+ case 1: //checks for YES and NO and returns the 1 or 2 to the calling code
+ switch(j)
+ {
+ case 4: //YES
+ return(1);
+
+ case 5: //NO
+ return(2);
+
+ default: //ignore yes and no for example
+ Print_to_console("??");
+ return(0);
+
+ }
+ break;
+
+ }
+ break;
+ }
+ }
+ Print_to_console("?"); //couldn't find a proper match
+ return(0);
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_help(void) //Tony13Aug96
+{
+// print out a list of commands
+
+ int command;
+ int scrolls=0;
+ char c;
+
+
+
+
+
+ Scroll_console();
+
+
+
+ for (command=0; command < TOTAL_CONSOLE_COMMANDS; command++)
+ {
+ Print_to_console((char *)commands[command]);
+ 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;
+ }
+
+
+ }
+
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_print(uint8 *ascii, uint32 pen, uint32 paper) //Em(13Apr95tw)
+{
+//print pixels in closen pen number - no clipping on this one
+//where file is the graphic file of ascii characters
+
+ _frameHeader *head;
+ uint8 *charSet, *charPtr;
+ int chr, x=0;
+
+
+
+ charSet = res_man.Res_open(CONSOLE_FONT_ID); // open font file
+
+ do
+ {
+
+// Zdebug("#%d", *(ascii) );
+
+ chr = (int) *(ascii);
+ chr-=32;
+
+ head = (_frameHeader *)FetchFrameHeader(charSet,chr);
+ charPtr = (uint8 *)(head+1);
+
+ Con_colour_block( x, head->width, head->height, pen, paper, charPtr);
+
+ x+=head->width+1; //move on the x coordinate
+ ascii++;
+ }
+ while(*(ascii));
+
+
+ res_man.Res_close(CONSOLE_FONT_ID); // close font file
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_colour_block(int x, int width, int height, uint32 pen, uint32 paper, uint8 *sprite_data_ad) //Em(26Apr96tw)
+{
+ int deltaX,xx,yy;
+ char *ad;
+
+
+ deltaX = con_width-width;
+
+ ad = (char *) console_sprite->ad;
+ ad += (con_width*(con_depth-con_chr_height))+x; //locate bottom character row
+
+ for (yy=0;yy<height;yy++)
+ {
+ for (xx=0;xx<width;xx++)
+ { if (pen = *(sprite_data_ad++)) //color
+ *(ad++)= (uint8)CON_PEN;
+ else *(ad++)= (uint8) paper;
+ }
+ ad+=deltaX;
+ }
+}
+//-----------------------------------------------------------------------------------------------------------------------
+
+
+
+
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_fatal_error(char *format,...) //Tony17Oct96
+{
+//use this to alert the user of a major problem from which we cannot allow the game to continue
+//while in console mode the user will still be ble to use the console commands - which may be useful
+//this message is also written to the Zdebug file in case the console itself blows up
+
+ va_list arg_ptr; //variable argument pointer
+ char buf[150];
+ uint8 white[4] = {255,255,255,0}; // (James 05mar97)
+
+
+ SetPalette(CON_PEN, 1, white, RDPAL_INSTANT); // set text colour in case screen is faded down! (James 05mar97)
+
+ va_start(arg_ptr,format);
+ _vsnprintf( buf, 150, format, arg_ptr);
+
+ this_screen.background_layer_id=0; //in case error in display loop
+
+ Zdebug("CON_FATAL_ERROR:");
+ Zdebug(buf); //write to file first in-case the screen is screwed up and we never see the console
+
+ Print_to_console(buf);
+ Print_to_console("fatal error, sword2 must terminate :-( (%d)", ID);
+ Tconsole(0); //mode 0 so all commands are available but quit will terminate the game
+
+
+ Close_game(); //should down game services - free's mallocs, etc.
+
+ RestoreDisplay(); //reset the Windows stuff
+ CloseAppWindow(); //
+
+ exit(0);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Var_check(uint8 *pointer) //Tony8Jan97
+{
+ int var;
+
+
+ sscanf((char*)pointer,"%d",&var);
+
+ Print_to_console("%d", *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4*var) );
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Var_set(uint8 *pointer, uint8 *p2) //Tony8Jan97
+{
+ int var;
+ int val;
+
+
+
+ sscanf((char*)pointer,"%d",&var);
+ sscanf((char*)p2,"%d",&val);
+
+
+ Print_to_console("was %d", *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4*var) );
+
+ *(uint32 *)(res_man.resList[1]->ad+sizeof(_standardHeader)+4* var)=val;
+
+ Print_to_console("now %d", val);
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+void ShowVar(uint8 *varNoPtr) // James19mar97
+{
+ int32 showVarNo=0;
+ int32 varNo;
+
+
+ sscanf((char*)varNoPtr,"%d",&varNo); // 'varNo' is what we want to add
+
+ // search for a spare slot in the watch-list, but also watch out for this variable already being in the list
+ while ((showVarNo < MAX_SHOWVARS) && (showVar[showVarNo] != 0) && (showVar[showVarNo] != varNo))
+ showVarNo++;
+
+ if (showVarNo < MAX_SHOWVARS) // if we've found a spare slot or the variable's already there
+ {
+ if (showVar[showVarNo]==0) // empty slot
+ {
+ showVar[showVarNo] = varNo; // add it to the list at this slot
+ Print_to_console("var(%d) added to the watch-list", varNo);
+ }
+ else
+ Print_to_console("var(%d) already in the watch-list!", varNo);
+ }
+ else
+ Print_to_console("Sorry - no more allowed - hide one or extend the system watch-list");
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void HideVar(uint8 *varNoPtr) // James19mar97
+{
+ int32 showVarNo=0;
+ int32 varNo;
+
+
+ sscanf((char*)varNoPtr,"%d",&varNo); // 'varNo' is what we want to remove
+
+ while ((showVarNo < MAX_SHOWVARS) && (showVar[showVarNo] != varNo)) // search for 'varNo' in the watch-list
+ showVarNo++;
+
+ if (showVarNo < MAX_SHOWVARS) // if we've found 'varNo' in the list
+ {
+ showVar[showVarNo] = 0; // clear this slot
+ Print_to_console("var(%d) removed from watch-list", varNo);
+ }
+ else
+ Print_to_console("Sorry - can't find var(%d) in the list", varNo);
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_list_savegames(void) // (James05feb97) Tony1Apr97
+{
+ uint8 description[SAVE_DESCRIPTION_LEN];
+ int j, scrolls=0;
+ char c;
+
+ for (j=0;j<100;j++)
+ if (GetSaveDescription(j, description) == SR_OK) //if there is a save game print the name
+ { Print_to_console("%d: \"%s\"", j, description);
+
+ 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;
+ }
+ }
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+#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..?
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_save_game(int total_commands, uint8 *slotString, uint8 *description) // James05feb97
+{
+ uint16 slotNo;
+ uint32 rv;
+
+ if ((mouse_status) || (mouse_mode_locked)) // if mouse if off, or system menu is locked off
+ {
+ Print_to_console("WARNING: Cannot save game while control menu unavailable!");
+ return;
+ }
+
+ if (total_commands >= 3) // SAVE <slot> <description>
+ {
+ if (Is_number(slotString))
+ {
+ slotNo = atoi((char*)slotString);
+
+ rv = SaveGame(slotNo,description);
+
+ if (rv == SR_OK)
+ Print_to_console("Saved game \"%s\" to file \"savegame.%.3d\"", description, slotNo);
+
+ else if (rv == SR_ERR_FILEOPEN)
+ Print_to_console("ERROR: Cannot open file \"savegame.%.3d\"", slotNo);
+
+ else // SR_ERR_WRITEFAIL
+ Print_to_console("ERROR: Write error on file \"savegame.%.3d\"", slotNo);
+ }
+ }
+ else
+ Print_to_console("Syntax Error: type SAVE (slot_number) (description)");
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_restore_game(int total_commands, uint8 *slotString) // James05feb97
+{
+ uint16 slotNo;
+ uint8 description[SAVE_DESCRIPTION_LEN];
+ uint32 rv;
+
+
+ if ((mouse_status) || (mouse_mode_locked)) // if mouse if off, or system menu is locked off
+ {
+ Print_to_console("WARNING: Cannot restore game while control menu unavailable!");
+ return;
+ }
+
+ if (total_commands >= 2) // RESTORE <slot>
+ {
+ if (Is_number(slotString))
+ {
+ slotNo = atoi((char*)slotString);
+ rv = RestoreGame(slotNo);
+
+ if (rv == SR_OK)
+ {
+ GetSaveDescription(slotNo, description);
+ Print_to_console("Restored game \"%s\" from file \"savegame.%.3d\"", description, slotNo);
+ }
+ else if (rv == SR_ERR_FILEOPEN)
+ Print_to_console("ERROR: Cannot open file \"savegame.%.3d\"", slotNo);
+
+ else if (rv == SR_ERR_INCOMPATIBLE)
+ Print_to_console("ERROR: \"savegame.%.3d\" is no longer compatible with current player/variable resources", slotNo);
+
+ else // SR_ERR_READFAIL
+ Print_to_console("ERROR: Read error on file \"savegame.%.3d\"", slotNo);
+ }
+ }
+ else
+ Print_to_console("Syntax Error: type RESTORE (slot_number)");
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_start_timer(int total_commands, uint8 *slotString) // Paul12feb97
+{
+
+ if (total_commands >= 2) // RESTORE <slot>
+ {
+ if (Is_number(slotString))
+ {
+ startTime = timeGetTime() - (atoi((char*)slotString) * 1000);
+ }
+ }
+ else
+ {
+ if (startTime = 0)
+ startTime = timeGetTime();
+ }
+ displayTime = 1;
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+uint8 Is_number(uint8 *ascii) // James05feb97
+{
+ while (*ascii) // until we reach the null terminator
+ {
+ if ((*ascii >= '0') && (*ascii <= '9'))
+ ascii++;
+ else
+ return(0);
+ }
+
+ return(1);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_display_version(void) // James27mar97
+{
+ struct tm *time;
+ time_t t;
+ char dateStamp[255];
+ char version[6];
+
+ strcpy(version,(char*)version_string+HEAD_LEN);
+ *(((unsigned char *)&t)) = *(version_string+14);
+ *(((unsigned char *)&t)+1) = *(version_string+15);
+ *(((unsigned char *)&t)+2) = *(version_string+16);
+ *(((unsigned char *)&t)+3) = *(version_string+17);
+
+ time = localtime( &t );
+ sprintf(dateStamp,"%s", asctime( time ) );
+ dateStamp[24]=0; // fudge over the newline character!
+
+ Print_to_console("\"Broken Sword II\" (c) Revolution Software 1997.");
+ Print_to_console("v%s created on %s for %s", version, dateStamp, unencoded_name+HEAD_LEN);
+ Scroll_console();
+
+ // THE FOLLOWING LINES ARE TO BE COMMENTED OUT OF THE FINAL VERSION
+// Print_to_console("This program has a personalised fingerprint encrypted into the code.");
+// Print_to_console("If this CD was not sent directly to you by Virgin Interactive or Revolution Software");
+// Print_to_console("then please contact James Long at Revolution on (+44) 1904 639698.");
+// Scroll_console();
+}
+//-----------------------------------------------------------------------------------------------------------------------
+// typedef struct
+// {
+// uint32 id;
+// uint32 interact_id;
+// } _event_unit;
+//-----------------------------------------------------------------------------------------------------------------------
+void Con_display_events() // (James11july97)
+{
+ uint32 j;
+ uint32 target;
+ uint32 script;
+
+
+ Print_to_console("EVENT LIST:");
+
+ for (j=0; j<MAX_events; j++)
+ {
+ if (event_list[j].id)
+ {
+ target = event_list[j].id;
+ script = event_list[j].interact_id;
+
+ Print_to_console("slot %d: id = %s (%d)", j, FetchObjectName(target), target);
+ Print_to_console(" script = %s (%d) pos %d", FetchObjectName(script/65536), script/65536, script%65536);
+ }
+ }
+}
+//------------------------------------------------------------------------------------
+
+#else // not debug
+
+void Print_to_console(char *format,...) {};
+void Temp_print_to_console(char *format,...) {};
+void Clear_console_line(void) {};
+void Scroll_console(void) {};
+void Init_console(void) {};
+void StartConsole(void) {};
+
+#endif // _DEBUG
diff --git a/sword2/console.h b/sword2/console.h
new file mode 100644
index 0000000000..1dd5014044
--- /dev/null
+++ b/sword2/console.h
@@ -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
diff --git a/sword2/controls.cpp b/sword2/controls.cpp
new file mode 100644
index 0000000000..d30a2ebf99
--- /dev/null
+++ b/sword2/controls.cpp
@@ -0,0 +1,2917 @@
+/* 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+//#include "src\driver96.h"
+
+#include "build_display.h"
+#include "console.h"
+#include "controls.h"
+#include "debug.h"
+#include "defs.h"
+#include "header.h"
+#include "interpreter.h"
+#include "layers.h"
+#include "logic.h"
+#include "maketext.h" // for font resource variables
+#include "mem_view.h"
+#include "memory.h"
+#include "mouse.h"
+#include "protocol.h"
+#include "resman.h"
+#include "router.h"
+#include "save_rest.h"
+#include "sound.h" // for FN_stop_music()
+#include "startup.h"
+#include "sword2.h"
+
+//-----------------------------------------------------------------------------------------------------------------------
+#define WINDOW_RES 2016
+#define MAX_STRING_LEN 64 // 20 was too low; better to be safe ;)
+
+#define CHARACTER_OVERLAP 2 // overlap characters by 3 pixels
+//-----------------------------------------------------------------------------------------------------------------------
+
+void Create_surface_image(_spriteInfo *sprite, uint32 *surface, uint32 res, uint32 x, uint32 y, uint32 pc);
+void Build_surfaces(void);
+void Build_chr_surfaces(void);
+void Kill_chr_surfaces(void);
+void Kill_surfaces(void);
+void Renew_surfaces(void);
+void Engine_string(uint32 x, uint32 y, uint32 res, uint32 *surface_list, uint8 *buf);
+void Kill_mini_surfaces(void);
+void Build_mini_surfaces(void);
+uint32 Generic_mini_control(uint32 text_id);
+uint32 Pixel_text_length(uint8 *buf, uint32 res);
+void Control_error(char* text);
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+#define WINDOW_X 0
+
+#define REST_X 84
+#define REST_Y 40
+
+#define SLAB_X (REST_X+30)
+#define SLAB_Y (REST_Y+32)
+
+#define REST_BUT_X 130
+#define REST_BUT_Y 377
+
+#define CAN_BUT_X 350
+#define CAN_BUT_Y 377
+
+#define UP_BUT_X 516
+#define UP_BUT_Y 85
+
+#define DOWN_BUT_X 516
+#define DOWN_BUT_Y 329
+
+#define ZUP_BUT_Y 85-20
+
+#define ZDOWN_BUT_Y 329+21
+
+#define SLAB_Y_SPACING 35
+
+#define QUIT_X 203
+#define QUIT_Y 104
+
+#define OPTION_X 45
+#define OPTION_Y 40
+#define OPTION_W 552
+
+#define OPT_BUT_W 53
+#define OPT_BUT_H 32
+
+#define OPT_OK_X (OPTION_X+(OPTION_W/3)-(OPT_BUT_W/2))
+#define OPT_OK_Y (OPTION_Y+368-(OPT_BUT_W/2))
+
+#define OPT_CAN_X (OPTION_X+350)
+#define OPT_CAN_Y (OPT_OK_Y)
+
+#define SLIDER_TRK_X (OPTION_X+264)
+#define SLIDER_TRK_W 132
+#define SLIDER_TRK_H 27
+#define SLIDER_W 38
+
+#define OBJ_LABEL_X (SLIDER_TRK_X-5)
+#define OBJ_LABEL_Y (OPTION_Y+60)
+
+#define SUBTITLE_X (OPTION_X+465)
+#define SUBTITLE_Y (OBJ_LABEL_Y)
+
+#define STEREO_X (SLIDER_TRK_X-5)
+#define STEREO_Y (OPTION_Y+253)
+
+#define MUSIC_TRK_Y (OPTION_Y+121)
+#define SPEECH_TRK_Y (OPTION_Y+168)
+#define FX_TRK_Y (OPTION_Y+214)
+#define GRFX_TRK_Y (OPTION_Y+301)
+
+#define MUTE_W 40
+#define MUTE_H 32
+#define MUTE_X (SUBTITLE_X+OPT_BUT_W/2-MUTE_W/2)
+
+#define GRFX_ICON_X (OPTION_X+450)
+#define GRFX_ICON_Y (OPTION_Y+270)
+
+//--------------------------------------------
+
+uint32 panel_surface;
+_spriteInfo panel_sprite;
+
+_spriteInfo slab_sprite[8];
+uint32 slab_surface[8];
+
+_spriteInfo chr_sprite;
+
+#define SIZE_OF_CHAR_SET (256-32) // our fonts start on SPACE character (32)
+uint32 chr_surface[SIZE_OF_CHAR_SET];
+uint32 red_chr_surface[SIZE_OF_CHAR_SET];
+
+_spriteInfo can_button_sprite[2];
+uint32 can_button_surface[2];
+uint32 can_button_state=0;
+uint32 touching_can_button=0;
+
+_spriteInfo button_sprite[2];
+uint32 button_surface[2];
+uint32 restore_button_state=0;
+uint32 touching_restore_button=0;
+
+_spriteInfo up_button_sprite[2];
+uint32 up_button_surface[2];
+uint32 up_button_state=0;
+uint32 touching_up_button=0;
+
+_spriteInfo down_button_sprite[2];
+uint32 down_button_surface[2];
+uint32 down_button_state=0;
+uint32 touching_down_button=0;
+
+_spriteInfo zup_button_sprite[2];
+uint32 zup_button_surface[2];
+uint32 zup_button_state=0;
+uint32 touching_zup_button=0;
+
+_spriteInfo zdown_button_sprite[2];
+uint32 zdown_button_surface[2];
+uint32 zdown_button_state=0;
+uint32 touching_zdown_button=0;
+
+_spriteInfo grfx_icon_sprite[4];
+uint32 grfx_icon_surface[4];
+
+uint8 *charSet;
+uint8 *red_charSet;
+
+_frameHeader *head;
+
+uint32 base_slot=0;
+
+uint8 subtitles; // text selected
+uint8 speechSelected;
+uint8 stereoReversed = 0;
+
+uint8 current_graphics_level;
+
+//-----------------------------------------------------------------------------------------------------------------------
+uint32 Restore_control(void) //Tony20Mar97
+{
+//well, this is nice and hard wired - not the way to do it really
+
+// returns 0 for no restore
+// 1 for restored ok
+
+
+ uint8 *colTablePtr=NULL;
+
+ int breakOut=0;
+ uint32 j;
+ uint8 black[4]={0,0,0,0};
+ char key_press=0;
+ uint8 description[SAVE_DESCRIPTION_LEN];
+ uint8 buf[8][SAVE_DESCRIPTION_LEN];
+
+ uint8 chr;
+ int char_no;
+ _mouseEvent *me;
+
+ uint8 restore_text[MAX_STRING_LEN];
+ uint8 cancel_text[MAX_STRING_LEN];
+ uint8 *text;
+
+
+ uint32 slab_text_x;
+ uint32 slab_text_y;
+
+ uint32 slot=1000; //nothing selected
+ uint32 clicked_slot;
+ uint32 cur_slot_states[9];
+
+ int scroll_rate=0;
+ //static uint32 base_slot=0;
+
+ int first=0;
+
+ uint32 rv; // return value for RestoreGame
+ uint32 res; //result from primer game cycle
+
+
+ int names_built=0; //0 redo, else dont
+
+
+
+//do some driver stuff
+// for (j=0;j<1000;j++)
+// ResetRenderEngine();
+
+
+
+
+//buttons unpressed
+ restore_button_state=0;
+ can_button_state=0;
+
+
+
+
+ Build_surfaces();
+ Build_chr_surfaces();
+
+//fetch the 'restore' text
+ text = FetchTextLine( res_man.Res_open(149618690/SIZE), 149618690&0xffff ); // open text file & get the line
+ strcpy((char*)&restore_text[0], (char*)text+2);
+//fetch the 'cancel' text
+ text = FetchTextLine( res_man.Res_open(149618689/SIZE), 149618689&0xffff ); // open text file & get the line
+ strcpy((char*)&cancel_text[0], (char*)text+2);
+//blimey, life's never easy is it?
+
+
+//control loop
+ while (1)
+ {
+ //--------------------------------------------------
+ // Service windows
+ 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
+ }
+
+ while (!gotTheFocus)
+ { names_built=0;
+ slot=1000;
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ break;
+ }
+ //--------------------------------------------------
+
+ EraseBackBuffer();
+
+
+//print panel
+ if (DrawSurface(&panel_sprite, panel_surface)==RDERR_SURFACELOST)
+ Renew_surfaces();
+
+
+//print words on panel
+ Engine_string(REST_BUT_X+32, REST_BUT_Y, controls_font_id, chr_surface, restore_text);
+ Engine_string(CAN_BUT_X+32, REST_BUT_Y, controls_font_id, chr_surface, cancel_text);
+
+
+
+
+ slab_text_y=76;
+
+// print slabs
+ for (j=0;j<8;j++)
+ {
+
+ if (slot==base_slot+j) //red
+ { slab_sprite[((base_slot+j)&3)+4].y=SLAB_Y+(j*SLAB_Y_SPACING);
+ DrawSurface(&slab_sprite[((base_slot+j)&3)+4], slab_surface[((base_slot+j)&3)+4] );
+ }
+ else
+ { slab_sprite[((base_slot+j)&3)].y=SLAB_Y+(j*SLAB_Y_SPACING);
+ DrawSurface(&slab_sprite[((base_slot+j)&3)], slab_surface[((base_slot+j)&3)] );
+ }
+
+// print save name on slab if a game is saved in this slot
+ if (!names_built)
+ { if (GetSaveDescription(base_slot+j, description) == SR_OK) //if there is a savegame at this slot
+ {
+ cur_slot_states[j]=1; //slot used
+
+ if (!description[0])
+ Con_fatal_error("NULL file name passed from GetSaveDescription!");
+
+ // print the name on the slab
+ sprintf((char*)buf[j], "%d. %s", base_slot+j, description );
+ }
+ else
+ {
+ sprintf((char*)buf[j], "%d.", base_slot+j); //simply print the number
+ cur_slot_states[j]=0; //slot not used
+ }
+ }
+
+
+ char_no=0;
+
+ slab_text_x=SLAB_X+16;
+
+
+ do
+ {
+ chr = buf[j][char_no];
+ chr-=32; //got true chr$
+
+ chr_sprite.x=slab_text_x;
+
+
+ chr_sprite.scale=0;
+ chr_sprite.type= RDSPR_NOCOMPRESSION+RDSPR_TRANS;
+ chr_sprite.blend= 0;
+
+ if (slot==base_slot+j)
+ {
+ head = (_frameHeader *)FetchFrameHeader(red_charSet, chr);
+
+ chr_sprite.w=head->width;
+ chr_sprite.h=head->height;
+
+ chr_sprite.y=slab_text_y+2;
+ DrawSurface(&chr_sprite, red_chr_surface[chr]); //print
+ }
+ else
+ {
+ head = (_frameHeader *)FetchFrameHeader(charSet, chr);
+
+ chr_sprite.w=head->width;
+ chr_sprite.h=head->height;
+
+ chr_sprite.y=slab_text_y;
+ DrawSurface(&chr_sprite, chr_surface[chr]); //print
+ }
+
+ slab_text_x+=head->width-CHARACTER_OVERLAP;
+ char_no++;
+ }
+ while(buf[j][char_no]);
+
+
+ slab_text_y+=SLAB_Y_SPACING;
+ }
+
+
+
+ names_built=1; //dont GetSaveDescription each cycle
+
+//print buttons
+//print restore button
+ DrawSurface(&button_sprite[restore_button_state], button_surface[restore_button_state] );
+
+//print cancel button
+ DrawSurface(&can_button_sprite[can_button_state], can_button_surface[can_button_state] );
+
+//print up button
+ DrawSurface(&up_button_sprite[up_button_state], up_button_surface[up_button_state] );
+
+//print down button
+ DrawSurface(&down_button_sprite[down_button_state], down_button_surface[down_button_state] );
+
+//print zup button
+ DrawSurface(&zup_button_sprite[zup_button_state], zup_button_surface[zup_button_state] );
+
+//print zdown button
+ DrawSurface(&zdown_button_sprite[zdown_button_state], zdown_button_surface[zdown_button_state] );
+
+
+ ProcessMenu();
+
+ if (!first)
+ {
+ first++;
+ SetFullPalette(CONTROL_PANEL_PALETTE); // see Build_display.cpp (James17jun97)
+ }
+
+ FlipScreens();
+
+
+
+
+
+
+
+
+//mouse over buttons?
+//restore
+ if ((mousex>REST_BUT_X)&&(mousex<REST_BUT_X+24)&&((mousey+40)>REST_BUT_Y)&&((mousey+40)<REST_BUT_Y+24))
+ touching_restore_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { restore_button_state=0;
+ touching_restore_button=0;
+ }
+
+//cancel
+ if ((mousex>CAN_BUT_X)&&(mousex<CAN_BUT_X+24)&&((mousey+40)>CAN_BUT_Y)&&((mousey+40)<CAN_BUT_Y+24))
+ touching_can_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { can_button_state=0;
+ touching_can_button=0;
+ }
+
+//up
+ if ((mousex>UP_BUT_X)&&(mousex<UP_BUT_X+17)&&((mousey+40)>UP_BUT_Y)&&((mousey+40)<UP_BUT_Y+17))
+ touching_up_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { up_button_state=0;
+ touching_up_button=0;
+ }
+
+//down
+ if ((mousex>DOWN_BUT_X)&&(mousex<DOWN_BUT_X+17)&&((mousey+40)>DOWN_BUT_Y)&&((mousey+40)<DOWN_BUT_Y+17))
+ touching_down_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { down_button_state=0;
+ touching_down_button=0;
+ }
+
+//up
+ if ((mousex>UP_BUT_X)&&(mousex<UP_BUT_X+17)&&((mousey+40)>ZUP_BUT_Y)&&((mousey+40)<ZUP_BUT_Y+17))
+ touching_zup_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { zup_button_state=0;
+ touching_zup_button=0;
+ }
+
+//down
+ if ((mousex>DOWN_BUT_X)&&(mousex<DOWN_BUT_X+17)&&((mousey+40)>ZDOWN_BUT_Y)&&((mousey+40)<ZDOWN_BUT_Y+17))
+ touching_zdown_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { zdown_button_state=0;
+ touching_zdown_button=0;
+ }
+
+
+
+
+
+
+
+//check mouse clicked on a slab
+ me = MouseEvent(); //get mouse event
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) //there's a mouse event to be processed
+ {
+ if ((mousex>SLAB_X)&&(mousex<SLAB_X+384)&&((mousey+40)>SLAB_Y)&&((mousey+40)<SLAB_Y+SLAB_Y_SPACING*8))
+ {
+ clicked_slot=((mousey+40)-SLAB_Y)/SLAB_Y_SPACING;
+
+ //Zdebug("clicked slab %d", slot);
+
+ if (cur_slot_states[clicked_slot]) //a selectable slot
+ {
+ if (slot!= clicked_slot+base_slot) //can select if not selected now
+ slot=clicked_slot+base_slot; //now selected
+
+ else slot=1000; //else deselect
+ }
+ }
+
+// clicking on the restore button
+ if (touching_restore_button)
+ restore_button_state=1; //button now down
+
+// clicking on the cancel button
+ if (touching_can_button)
+ can_button_state=1; //button now down
+
+// clicking on the up button
+ if (touching_up_button)
+ { up_button_state=1; //button now down
+ scroll_rate=0;
+ }
+
+// clicking on the down button
+ if (touching_down_button)
+ { down_button_state=1; //button now down
+ scroll_rate=0;
+ }
+// clicking on the zup button
+ if (touching_zup_button)
+ { zup_button_state=1; //button now down
+ scroll_rate=0;
+ }
+
+// clicking on the zdown button
+ if (touching_zdown_button)
+ { zdown_button_state=1; //button now down
+ scroll_rate=0;
+ }
+
+
+ }
+
+//check for releasing the mouse button over a button
+ if ((key_press==13)||((me!=NULL)&&(me->buttons&RD_LEFTBUTTONUP))) //there's a mouse event to be processed
+ {
+ if ((key_press==13)||((touching_restore_button)&&(restore_button_state)))
+ {
+ restore_button_state=0;
+
+ if (slot!=1000) //restore the game!
+ {
+ breakOut=1;
+
+ rv = RestoreGame(slot);
+
+ if (rv == SR_OK)
+ {
+// DEAD=0; //in case we were dead - well we're not anymore!
+
+// prime system with a game cycle
+ 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)
+
+ res = LLogic.Process_session();
+
+ if (res)
+ Con_fatal_error("restart 1st cycle failed??");
+
+
+ // Control_error("restored OK :)");
+
+ Kill_surfaces();
+ Kill_chr_surfaces();
+
+ return(1);
+ }
+ else
+ {
+// Save & Restore error codes
+
+// ERROR CODE VALUE MEANING REASON
+// ========== ===== ======= ======
+// SR_OK 0x00000000 // ok No worries
+// SR_ERR_FILEOPEN 0x00000001 // can't open file Could create file for saving, or couldn't find file for loading
+// SR_ERR_INCOMPATIBLE 0x00000002 // (RestoreGame only) incompatible savegame data Savegame file is obsolete. (Won't happen after development stops)
+// SR_ERR_READFAIL 0x00000003 // (RestoreGame only) failed on reading savegame file Something screwed up during the fread()
+// SR_ERR_WRITEFAIL 0x00000004 // (SaveGame only) failed on writing savegame file Something screwed up during the fwrite() - could be hard-drive full..?
+
+
+ // WE NEED A MESSAGE BOX TO INDICATE FAILED SAVE - DON'T HALT THE GAME!
+
+ if (rv == SR_ERR_FILEOPEN)
+ Control_error((char*)(FetchTextLine( res_man.Res_open(213516670/SIZE), 213516670&0xffff)+2));
+// Restore failed - could not open file
+
+ else if (rv == SR_ERR_INCOMPATIBLE)
+ Control_error((char*)(FetchTextLine( res_man.Res_open(213516671/SIZE), 213516671&0xffff)+2));
+// Restore failed - incompatible savegame data
+
+ else // SR_ERR_READFAIL
+ Control_error((char*)(FetchTextLine( res_man.Res_open(213516673/SIZE), 213516673&0xffff)+2));
+// Restore failed
+ }
+ }
+ }
+ else if ((touching_can_button)&&(can_button_state)) //quit the screen
+ breakOut=1;
+
+ else if (touching_up_button)
+ up_button_state=0;
+
+ else if (touching_down_button)
+ down_button_state=0;
+
+ else if (touching_zup_button)
+ zup_button_state=0;
+
+ else if (touching_zdown_button)
+ zdown_button_state=0;
+
+ }
+
+
+
+//scrolling downward
+ if ( ((scroll_rate<1)||(scroll_rate>12))&&(!(scroll_rate&3))&&(down_button_state)&&(base_slot<92))
+ { base_slot++;
+ names_built=0;
+ }
+
+//scrolling upward
+ if (((scroll_rate<1)||(scroll_rate>12))&&(!(scroll_rate&3))&&(up_button_state)&&(base_slot))
+ { base_slot--;
+ names_built=0;
+ }
+
+//scrolling zdownward
+ if (((scroll_rate<1)||(scroll_rate>12))&&(!(scroll_rate&3))&&(zdown_button_state)&&(base_slot<92))
+ { base_slot+=8;
+ if (base_slot>92)
+ base_slot=92;
+
+ names_built=0;
+ }
+
+//scrolling zupward
+ if (((scroll_rate<1)||(scroll_rate>12))&&(!(scroll_rate&3))&&(zup_button_state)&&(base_slot))
+ { base_slot-=8;
+ if (base_slot>92)
+ base_slot=0;
+
+ names_built=0;
+ }
+
+
+//update scroll stuff
+ scroll_rate++;
+
+
+
+
+//-----
+ key_press=0;
+ if (KeyWaiting())
+ {
+ ReadKey(&key_press); //kill the key we just pressed
+ if (key_press==27) //ESC
+ break;
+ }
+
+
+ if (breakOut)
+ {
+ break; //quit this stuff - ap will eventually close in the mainloop
+ }
+
+
+ } //while
+
+
+ Kill_surfaces();
+ Kill_chr_surfaces();
+
+ return(0);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Create_surface_image(_spriteInfo *sprite, uint32 *surface, uint32 res, uint32 x, uint32 y, uint32 pc) //TonyMarch97
+{
+ uint8 *file, *colTablePtr=NULL;
+ _animHeader *anim_head;
+ _frameHeader *frame_head;
+ _cdtEntry *cdt_entry;
+ //_spriteInfo spriteInfo;
+ uint32 spriteType=RDSPR_TRANS;
+
+
+ file = res_man.Res_open(res); // open anim resource file & point to base
+
+
+ anim_head = FetchAnimHeader( file );
+ cdt_entry = FetchCdtEntry( file, pc );
+ frame_head = FetchFrameHeader( file, pc );
+
+
+
+
+ if (anim_head->blend)
+ spriteType += RDSPR_BLEND;
+
+ if ((cdt_entry->frameType) & FRAME_FLIPPED) //if the frame is to be flipped (only really applicable to frames using offsets)
+ spriteType += RDSPR_FLIP;
+
+ switch (anim_head->runTimeComp) // what compression was used?
+ {
+ case NONE:
+ spriteType += RDSPR_NOCOMPRESSION;
+ break;
+ case RLE256:
+ spriteType += RDSPR_RLE256;
+ break;
+ case RLE16:
+ spriteType += RDSPR_RLE16;
+ colTablePtr = (uint8*)(anim_head+1) + anim_head->noAnimFrames*sizeof(_cdtEntry);
+ // points to just after last cdt_entry, ie. start of colour table
+ break;
+ }
+
+ sprite->x = x;
+ sprite->y = y;
+ sprite->w = frame_head->width;
+ sprite->h = frame_head->height;
+ sprite->scale = 0;
+// spriteInfo.scaledWidth = build_unit->scaled_width;
+// spriteInfo.scaledHeight = build_unit->scaled_height;
+ sprite->type = spriteType;
+ sprite->blend = anim_head->blend;
+ sprite->data = (uint8*)(frame_head+1); // points to just after frame header, ie. start of sprite data
+// spriteInfo.colourTable = colTablePtr;
+
+
+// Zdebug("w %d h %d", frame_head->width, frame_head->height);
+
+ CreateSurface(sprite, surface);
+
+
+ res_man.Res_close(res); //release the anim resource
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Build_surfaces(void) //Tony27March97
+{
+
+
+//setup the control window
+ Create_surface_image(&panel_sprite, &panel_surface, WINDOW_RES, WINDOW_X, REST_Y, 0);
+
+
+
+//setup slabs as surfaces
+ Create_surface_image(&slab_sprite[0], &slab_surface[0], 2006, SLAB_X, 0, 0);
+ Create_surface_image(&slab_sprite[1], &slab_surface[1], 2007, SLAB_X, 0, 0);
+ Create_surface_image(&slab_sprite[2], &slab_surface[2], 2008, SLAB_X, 0, 0);
+ Create_surface_image(&slab_sprite[3], &slab_surface[3], 2009, SLAB_X, 0, 0);
+
+//now the red selected panels
+ Create_surface_image(&slab_sprite[4], &slab_surface[4], 2006, SLAB_X, 0, 1);
+ Create_surface_image(&slab_sprite[5], &slab_surface[5], 2007, SLAB_X, 0, 1);
+ Create_surface_image(&slab_sprite[6], &slab_surface[6], 2008, SLAB_X, 0, 1);
+ Create_surface_image(&slab_sprite[7], &slab_surface[7], 2009, SLAB_X, 0, 1);
+
+//restore button
+ Create_surface_image(&button_sprite[0], &button_surface[0], 2002, REST_BUT_X, REST_BUT_Y, 0);
+ Create_surface_image(&button_sprite[1], &button_surface[1], 2002, REST_BUT_X, REST_BUT_Y, 1);
+
+//cancel button
+ Create_surface_image(&can_button_sprite[0], &can_button_surface[0], 2002, CAN_BUT_X, CAN_BUT_Y, 0);
+ Create_surface_image(&can_button_sprite[1], &can_button_surface[1], 2002, CAN_BUT_X, CAN_BUT_Y, 1);
+
+//up button
+ Create_surface_image(&up_button_sprite[0], &up_button_surface[0], 2067, UP_BUT_X, UP_BUT_Y, 0);
+ Create_surface_image(&up_button_sprite[1], &up_button_surface[1], 2067, UP_BUT_X, UP_BUT_Y, 1);
+
+//down button
+ Create_surface_image(&down_button_sprite[0], &down_button_surface[0], 1986, DOWN_BUT_X, DOWN_BUT_Y, 0);
+ Create_surface_image(&down_button_sprite[1], &down_button_surface[1], 1986, DOWN_BUT_X, DOWN_BUT_Y, 1);
+
+//zup button
+ Create_surface_image(&zup_button_sprite[0], &zup_button_surface[0], 1982, UP_BUT_X, ZUP_BUT_Y, 0);
+ Create_surface_image(&zup_button_sprite[1], &zup_button_surface[1], 1982, UP_BUT_X, ZUP_BUT_Y, 1);
+
+//zdown button
+ Create_surface_image(&zdown_button_sprite[0], &zdown_button_surface[0], 1988, DOWN_BUT_X, ZDOWN_BUT_Y, 0);
+ Create_surface_image(&zdown_button_sprite[1], &zdown_button_surface[1], 1988, DOWN_BUT_X, ZDOWN_BUT_Y, 1);
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Build_chr_surfaces(void) //tony2Apr97
+{
+
+ int j;
+
+
+//sort out the font
+ charSet = res_man.Res_open(controls_font_id); //open font file
+ red_charSet = res_man.Res_open(red_font_id); //open font file
+
+
+//set up the chr$ set frame surfaces
+ chr_sprite.scale=0;
+ chr_sprite.type= RDSPR_NOCOMPRESSION+RDSPR_TRANS;
+ chr_sprite.blend= 0;
+
+ for (j=0; j < SIZE_OF_CHAR_SET; j++)
+ { //normal
+ head = (_frameHeader *)FetchFrameHeader(charSet,j);
+ chr_sprite.data = (uint8 *)(head+1);
+ chr_sprite.w=head->width;
+ chr_sprite.h=head->height;
+ CreateSurface(&chr_sprite, &chr_surface[j]);
+
+// red
+ head = (_frameHeader *)FetchFrameHeader(red_charSet,j);
+ chr_sprite.data = (uint8 *)(head+1);
+ chr_sprite.w=head->width;
+ chr_sprite.h=head->height;
+ CreateSurface(&chr_sprite, &red_chr_surface[j]);
+
+ }
+
+ res_man.Res_close(controls_font_id); //close font file
+ res_man.Res_close(red_font_id); //close font file
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Kill_surfaces(void) //Tony27March97
+{
+
+//remove the surfaces
+ DeleteSurface(panel_surface);
+ DeleteSurface(slab_surface[0]);
+ DeleteSurface(slab_surface[1]);
+ DeleteSurface(slab_surface[2]);
+ DeleteSurface(slab_surface[3]);
+ DeleteSurface(slab_surface[4]);
+ DeleteSurface(slab_surface[5]);
+ DeleteSurface(slab_surface[6]);
+ DeleteSurface(slab_surface[7]);
+
+ DeleteSurface(button_surface[0]);
+ DeleteSurface(button_surface[1]);
+
+ DeleteSurface(can_button_surface[0]);
+ DeleteSurface(can_button_surface[1]);
+
+ DeleteSurface(up_button_surface[0]);
+ DeleteSurface(up_button_surface[1]);
+
+ DeleteSurface(down_button_surface[0]);
+ DeleteSurface(down_button_surface[1]);
+
+ DeleteSurface(zup_button_surface[0]);
+ DeleteSurface(zup_button_surface[1]);
+
+ DeleteSurface(zdown_button_surface[0]);
+ DeleteSurface(zdown_button_surface[1]);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Kill_chr_surfaces(void) //Tony2Apr97
+{
+ int j;
+
+
+
+//release chr$ set surfaces
+ for (j=0; j < SIZE_OF_CHAR_SET; j++)
+ { //normal
+ DeleteSurface(chr_surface[j]);
+// red
+ DeleteSurface(red_chr_surface[j]);
+ }
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Renew_surfaces(void) //Tony27March97
+{
+ Kill_surfaces();
+ Kill_chr_surfaces();
+ Build_surfaces();
+ Build_chr_surfaces();
+}
+//-----------------------------------------------------------------------------------------------------------------------
+
+
+
+
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+void Save_control(void) //Tony1Apr97 not a joke
+{
+//largely the same as the restore code
+
+
+ uint8 *colTablePtr=NULL;
+
+ int breakOut=0;
+ uint32 j;
+ uint8 black[4]={0,0,0,0};
+ char key_press;
+ uint8 description[SAVE_DESCRIPTION_LEN];
+ uint8 buf[8][SAVE_DESCRIPTION_LEN];
+ uint8 ed_buf[SAVE_DESCRIPTION_LEN];
+ int char_no;
+ uint8 chr;
+ _mouseEvent *me;
+ int esc_release=0;
+
+ uint32 slab_text_x;
+ uint32 slab_text_y;
+
+ uint32 slot=1000; //nothing selected
+ uint32 clicked_slot, edit_screen_slot=1000;
+ uint32 cur_slot_states[9];
+
+ int scroll_rate=0;
+// static uint32 base_slot=0;
+
+ int edit_pos, first_chr, flash=0;
+
+ uint8 save_text[MAX_STRING_LEN];
+ uint8 cancel_text[MAX_STRING_LEN];
+ uint8 *text;
+
+ int first=0;
+
+ uint32 rv; // return value for SaveGame
+
+ uint32 edit_width;
+
+ int names_built=0;
+
+
+
+//buttons unpressed
+ restore_button_state=0;
+ can_button_state=0;
+
+
+//do some driver stuff
+// ResetRenderEngine();
+
+
+
+//sort out the font
+ charSet = res_man.Res_open(controls_font_id); //open font file
+ red_charSet = res_man.Res_open(red_font_id); //open font file
+
+ chr_sprite.scale=0;
+ chr_sprite.type= RDSPR_NOCOMPRESSION+RDSPR_TRANS;
+ chr_sprite.blend= 0;
+
+
+
+
+ Build_surfaces();
+ Build_chr_surfaces();
+
+//fetch the 'save' text
+ text = FetchTextLine( res_man.Res_open(149618691/SIZE), 149618691&0xffff ); // open text file & get the line
+ strcpy((char*)&save_text[0], (char*)text+2);
+//fetch the 'cancel' text
+ text = FetchTextLine( res_man.Res_open(149618689/SIZE), 149618689&0xffff ); // open text file & get the line
+ strcpy((char*)&cancel_text[0], (char*)text+2);
+//blimey, life's never easy is it?
+
+
+
+//control loop
+ while (1)
+ {
+ //--------------------------------------------------
+ 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
+ }
+
+ // Service windows
+ while (!gotTheFocus)
+ { names_built=0;
+ edit_screen_slot=1000;
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ break;
+ }
+ //--------------------------------------------------
+
+ EraseBackBuffer();
+
+
+//print panel
+ if (DrawSurface(&panel_sprite, panel_surface)==RDERR_SURFACELOST)
+ Renew_surfaces();
+
+//print words on panel
+ Engine_string(REST_BUT_X+32, REST_BUT_Y, controls_font_id, chr_surface, save_text);
+ Engine_string(CAN_BUT_X+32, REST_BUT_Y, controls_font_id, chr_surface, cancel_text);
+
+
+
+
+
+ slab_text_y=76;
+
+// print slabs
+ for (j=0;j<8;j++)
+ {
+ if (edit_screen_slot!=j)
+ { slab_sprite[((base_slot+j)&3)].y=SLAB_Y+(j*SLAB_Y_SPACING);
+ DrawSurface(&slab_sprite[((base_slot+j)&3)], slab_surface[((base_slot+j)&3)] );
+
+// print save name on slab if a game is saved in this slot
+ if (!names_built)
+ {
+ if (GetSaveDescription(base_slot+j, description) == SR_OK) //if there is a savegame at this slot
+ { cur_slot_states[j]=1; //slot used
+
+ if (!description[0])
+ Con_fatal_error("NULL file name passed from GetSaveDescription!");
+
+
+ // print the name on the slab
+ sprintf((char*)buf[j], "%d. %s", base_slot+j, description );
+ }
+ else
+ { sprintf((char*)buf[j], "%d.", base_slot+j); //simply print the number
+ cur_slot_states[j]=0; //slot not used
+ }
+ }
+
+ char_no=0;
+
+ slab_text_x=SLAB_X+16;
+
+
+ do
+ {
+ chr = buf[j][char_no];
+ chr-=32; //got true chr$
+
+ chr_sprite.x=slab_text_x;
+
+ head = (_frameHeader *)FetchFrameHeader(charSet, chr);
+
+ chr_sprite.w=head->width;
+ chr_sprite.h=head->height;
+
+ chr_sprite.y=slab_text_y;
+ DrawSurface(&chr_sprite, chr_surface[chr]); //print
+
+ slab_text_x+=head->width-CHARACTER_OVERLAP; // overlap characters by 3 pixels;
+ char_no++;
+ }
+ while(buf[j][char_no]);
+ }
+ slab_text_y+=SLAB_Y_SPACING;
+ }
+
+ names_built=1;
+
+//draw the typing slab and text if we are still editing
+ if (edit_screen_slot!=1000) //we are typing a name in
+ {
+
+ flash++;
+ if (flash<7)
+ ed_buf[edit_pos]='_';
+ else
+ ed_buf[edit_pos]=' '; //by putting a space in we'll always have a chr$ in the buffer
+
+ if (flash==14)
+ flash=0;
+
+
+// now draw the current edit line
+// draw a red slab
+ slab_sprite[(clicked_slot&3)+4].y=SLAB_Y+(edit_screen_slot*SLAB_Y_SPACING);
+ DrawSurface(&slab_sprite[(clicked_slot&3)+4], slab_surface[(clicked_slot&3)+4] );
+
+// draw the text line
+ char_no=0;
+ edit_width=0; //total pixel width of text being typed in
+ slab_text_x=SLAB_X+16;
+
+// print the chr$
+ do
+ {
+ chr = ed_buf[char_no];
+ chr-=32; //got true chr$
+
+ chr_sprite.x=slab_text_x;
+
+ head = (_frameHeader *)FetchFrameHeader(red_charSet, chr);
+
+ chr_sprite.w=head->width;
+ chr_sprite.h=head->height;
+
+ chr_sprite.y=SLAB_Y+(edit_screen_slot*SLAB_Y_SPACING)+5; //why 5? when its 2 on restore????????
+ DrawSurface(&chr_sprite, red_chr_surface[chr]); //print
+
+ slab_text_x+=head->width-CHARACTER_OVERLAP;
+ edit_width+=head->width-CHARACTER_OVERLAP;
+
+ char_no++;
+ }
+ while(ed_buf[char_no]);
+ }
+
+
+
+
+//print buttons
+//print restore button
+ DrawSurface(&button_sprite[restore_button_state], button_surface[restore_button_state] );
+
+//print cancel button
+ DrawSurface(&can_button_sprite[can_button_state], can_button_surface[can_button_state] );
+
+//print up button
+ DrawSurface(&up_button_sprite[up_button_state], up_button_surface[up_button_state] );
+
+//print down button
+ DrawSurface(&down_button_sprite[down_button_state], down_button_surface[down_button_state] );
+
+//print zup button
+ DrawSurface(&zup_button_sprite[zup_button_state], zup_button_surface[zup_button_state] );
+
+//print zdown button
+ DrawSurface(&zdown_button_sprite[zdown_button_state], zdown_button_surface[zdown_button_state] );
+
+
+ ProcessMenu();
+
+
+
+
+//mouse over buttons?
+//restore
+ if ((mousex>REST_BUT_X)&&(mousex<REST_BUT_X+24)&&((mousey+40)>REST_BUT_Y)&&((mousey+40)<REST_BUT_Y+24))
+ touching_restore_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { restore_button_state=0;
+ touching_restore_button=0;
+ }
+
+//cancel
+ if ((mousex>CAN_BUT_X)&&(mousex<CAN_BUT_X+24)&&((mousey+40)>CAN_BUT_Y)&&((mousey+40)<CAN_BUT_Y+24))
+ touching_can_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { can_button_state=0;
+ touching_can_button=0;
+ }
+
+//up
+ if ((mousex>UP_BUT_X)&&(mousex<UP_BUT_X+17)&&((mousey+40)>UP_BUT_Y)&&((mousey+40)<UP_BUT_Y+17))
+ touching_up_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { up_button_state=0;
+ touching_up_button=0;
+ }
+
+//down
+ if ((mousex>DOWN_BUT_X)&&(mousex<DOWN_BUT_X+17)&&((mousey+40)>DOWN_BUT_Y)&&((mousey+40)<DOWN_BUT_Y+17))
+ touching_down_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { down_button_state=0;
+ touching_down_button=0;
+ }
+
+//up
+ if ((mousex>UP_BUT_X)&&(mousex<UP_BUT_X+17)&&((mousey+40)>ZUP_BUT_Y)&&((mousey+40)<ZUP_BUT_Y+17))
+ touching_zup_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { zup_button_state=0;
+ touching_zup_button=0;
+ }
+
+//down
+ if ((mousex>DOWN_BUT_X)&&(mousex<DOWN_BUT_X+17)&&((mousey+40)>ZDOWN_BUT_Y)&&((mousey+40)<ZDOWN_BUT_Y+17))
+ touching_zdown_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { zdown_button_state=0;
+ touching_zdown_button=0;
+ }
+
+
+
+
+
+
+
+//check mouse clicked on a slab
+ me = MouseEvent(); //get mouse event
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) //there's a mouse event to be processed
+ {
+ if ((mousex>SLAB_X)&&(mousex<SLAB_X+384)&&((mousey+40)>SLAB_Y)&&((mousey+40)<SLAB_Y+SLAB_Y_SPACING*8))
+ {
+ edit_screen_slot=((mousey+40)-SLAB_Y)/SLAB_Y_SPACING;
+ clicked_slot=edit_screen_slot+base_slot;
+
+ Zdebug("+ %d %d", edit_screen_slot, clicked_slot);
+
+// now edit the line
+// take a copy of the string
+
+ for (j=0;j<SAVE_DESCRIPTION_LEN;j++)
+ ed_buf[j]=0; //zero the string
+
+
+ sprintf((char*)ed_buf, "%d. ", clicked_slot); //simply print the number - assume no name in panel
+ first_chr=strlen((char*)ed_buf);
+ edit_pos=first_chr;
+
+
+ if (GetSaveDescription(clicked_slot, description) == SR_OK) //if there is a savegame at this slot
+ {
+ sprintf((char*)ed_buf, "%d. %s", clicked_slot, description );
+ edit_pos=strlen((char*)ed_buf); //recalculate cursor pos to end of string
+ }
+
+ Zdebug("first %d [%s]", first_chr, ed_buf);
+
+ }
+
+// clicking on the restore button
+ if (touching_restore_button)
+ restore_button_state=1; //button now down
+
+// clicking on the cancel button
+ if (touching_can_button)
+ can_button_state=1; //button now down
+
+// clicking on the up button
+ if (touching_up_button)
+ { up_button_state=1; //button now down
+ scroll_rate=0;
+ }
+
+// clicking on the down button
+ if (touching_down_button)
+ { down_button_state=1; //button now down
+ scroll_rate=0;
+ }
+// clicking on the zup button
+ if (touching_zup_button)
+ { zup_button_state=1; //button now down
+ scroll_rate=0;
+ }
+
+// clicking on the zdown button
+ if (touching_zdown_button)
+ { zdown_button_state=1; //button now down
+ scroll_rate=0;
+ }
+
+
+ }
+
+//check for releasing the mouse button over a button
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONUP)) //there's a mouse event to be processed
+ {
+
+ if ((touching_restore_button)&&(restore_button_state))
+ {
+ restore_button_state=0;
+
+ if ((edit_screen_slot!=1000)&&(edit_pos!=first_chr)) //we are editing and have a legal file name typed in
+ { //then save game - can also be saved when you press RETurn
+ ed_buf[edit_pos]=0; //remove cursor/[space]
+
+ rv = SaveGame(clicked_slot, (uint8*)&ed_buf[first_chr]);
+
+ if (rv == SR_OK)
+ { breakOut=1; //finished
+ if ((edit_screen_slot>6)&(base_slot<92))
+ base_slot++;
+ }
+ else
+ {
+// Save & Restore error codes
+
+// ERROR CODE VALUE MEANING REASON
+// ========== ===== ======= ======
+// SR_OK 0x00000000 // ok No worries
+// SR_ERR_FILEOPEN 0x00000001 // can't open file Could create file for saving, or couldn't find file for loading
+// SR_ERR_INCOMPATIBLE 0x00000002 // (RestoreGame only) incompatible savegame data Savegame file is obsolete. (Won't happen after development stops)
+// SR_ERR_READFAIL 0x00000003 // (RestoreGame only) failed on reading savegame file Something screwed up during the fread()
+// SR_ERR_WRITEFAIL 0x00000004 // (SaveGame only) failed on writing savegame file Something screwed up during the fwrite() - could be hard-drive full..?
+
+ // WE NEED A MESSAGE BOX TO INDICATE FAILED SAVE - DON'T HALT THE GAME!
+
+ if (rv == SR_ERR_FILEOPEN)
+ Control_error((char*)(FetchTextLine( res_man.Res_open(213516674/SIZE), 213516674&0xffff)+2));
+// Save failed - could not open file
+
+ else // SR_ERR_WRITEFAIL
+ Control_error((char*)(FetchTextLine( res_man.Res_open(213516676/SIZE), 213516676&0xffff)+2));
+// Save failed
+ }
+ }
+ }
+ else if ((touching_can_button)&&(can_button_state)) //quit the screen
+ breakOut=1;
+
+ else if (touching_up_button)
+ up_button_state=0;
+
+ else if (touching_down_button)
+ down_button_state=0;
+
+ else if (touching_zup_button)
+ zup_button_state=0;
+
+ else if (touching_zdown_button)
+ zdown_button_state=0;
+
+ }
+
+
+
+//scrolling downward
+ if ( ((scroll_rate<1)||(scroll_rate>12))&&(!(scroll_rate&3))&&(down_button_state)&&(base_slot<92))
+ { base_slot++;
+ names_built=0;
+
+ if (edit_screen_slot!=1000)
+ { edit_screen_slot--;
+ if (base_slot>clicked_slot)
+ edit_screen_slot=1000;
+ }
+ }
+
+//scrolling upward
+ if (((scroll_rate<1)||(scroll_rate>12))&&(!(scroll_rate&3))&&(up_button_state)&&(base_slot))
+ { base_slot--;
+ names_built=0;
+
+ if (edit_screen_slot!=1000)
+ { edit_screen_slot++;
+ if ((base_slot+7)<clicked_slot)
+ edit_screen_slot=1000;
+ }
+ }
+
+//scrolling zdownward
+ if (((scroll_rate<1)||(scroll_rate>12))&&(!(scroll_rate&3))&&(zdown_button_state)&&(base_slot<92))
+ { base_slot+=8;
+ names_built=0;
+
+ if (base_slot>92)
+ base_slot=92;
+
+ edit_screen_slot=1000; //no more editing
+ }
+
+//scrolling zupward
+ if (((scroll_rate<1)||(scroll_rate>12))&&(!(scroll_rate&3))&&(zup_button_state)&&(base_slot))
+ { base_slot-=8;
+ names_built=0;
+
+ if (base_slot>92)
+ base_slot=0;
+ edit_screen_slot=1000; //no more editing
+ }
+
+
+
+
+//update scroll stuff
+ scroll_rate++;
+
+
+
+
+//-----
+
+//deal with user input if the user is inputting
+ if ((edit_screen_slot!=1000)&&(KeyWaiting())) //we are typing a name in
+ {
+ ReadKey(&key_press);
+
+ if (!key_press) //escape sequences
+ {
+ }
+ else if (key_press==27) //ESC
+ {
+ edit_screen_slot=1000; //quit this edit
+ esc_release=42; //stop the ESC key auto-repeating after this and quiting the save control
+ }
+ else if (key_press==13) //RETurn
+ {
+ if (edit_pos!=first_chr)
+ { //save game
+ ed_buf[edit_pos]=0; //remove cursor/[space]
+
+ Zdebug("%d %d %s", first_chr, edit_pos, &ed_buf[first_chr]);
+
+ rv = SaveGame(clicked_slot, (uint8*)&ed_buf[first_chr]);
+
+ if (rv == SR_OK)
+ { breakOut=1; //finished
+ if ((edit_screen_slot>6)&(base_slot<92))
+ base_slot++;
+ }
+ else
+ {
+// Save & Restore error codes
+
+// ERROR CODE VALUE MEANING REASON
+// ========== ===== ======= ======
+// SR_OK 0x00000000 // ok No worries
+// SR_ERR_FILEOPEN 0x00000001 // can't open file Could create file for saving, or couldn't find file for loading
+// SR_ERR_INCOMPATIBLE 0x00000002 // (RestoreGame only) incompatible savegame data Savegame file is obsolete. (Won't happen after development stops)
+// SR_ERR_READFAIL 0x00000003 // (RestoreGame only) failed on reading savegame file Something screwed up during the fread()
+// SR_ERR_WRITEFAIL 0x00000004 // (SaveGame only) failed on writing savegame file Something screwed up during the fwrite() - could be hard-drive full..?
+
+
+ // WE NEED A MESSAGE BOX TO INDICATE FAILED SAVE - DON'T HALT THE GAME!
+
+ if (rv == SR_ERR_FILEOPEN)
+ Control_error((char*)(FetchTextLine( res_man.Res_open(213516674/SIZE), 213516674&0xffff)+2));
+// Save failed - could not open file
+
+ else // SR_ERR_WRITEFAIL
+ Control_error((char*)(FetchTextLine( res_man.Res_open(213516676/SIZE), 213516676&0xffff)+2));
+// Save failed
+ }
+ }
+ else edit_screen_slot=1000; //dont save an empty slot and cancel editing
+ }
+
+ else if (key_press==8) //delete
+ {
+ if (edit_pos!=first_chr)
+ {
+ ed_buf[edit_pos]=0; //delete cursor chr$
+ edit_pos--;
+ ed_buf[edit_pos]=0;
+ }
+ }
+ else if ((key_press<32)||(key_press>'z'))
+ Zdebug("save ignoring key - %d", key_press);
+ else
+ {
+// if (edit_pos<(20)) //less one to leave room for the cursor
+
+
+ if ((edit_width<350)&&(edit_pos<SAVE_DESCRIPTION_LEN-2))
+ ed_buf[edit_pos++]=key_press;
+ else //end of line has been reached, so keep replacing last letter
+ ed_buf[edit_pos-1]=key_press; //replace
+ }
+ }
+ else if (KeyWaiting())
+ {
+ ReadKey(&key_press); //kill the key we just pressed
+ if ((key_press==27)&&(!esc_release)) //ESC
+ breakOut=1;
+
+ else if (key_press!=27)
+ esc_release=0;
+ }
+ else if (!KeyWaiting())
+ esc_release=0;
+
+
+
+
+
+
+
+
+
+
+
+ if (breakOut)
+ {
+ break; //quit this stuff - ap will eventually close in the mainloop
+ }
+
+ if (!first)
+ {
+ first++;
+ SetFullPalette(CONTROL_PANEL_PALETTE); // see Build_display.cpp (James17jun97)
+ }
+
+ FlipScreens();
+
+ } //while
+
+
+ Kill_surfaces();
+ Kill_chr_surfaces();
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+void Quit_control(void) //Tony2Apr97
+{
+ uint32 res;
+
+
+ res=Generic_mini_control(149618692); //quit text
+
+
+ if (!res)
+ return; //just return to game
+
+//avoid corruption when windows kicks back in
+ EraseBackBuffer();
+ FlipScreens();
+ EraseBackBuffer();
+ FlipScreens();
+
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+
+ exit(0);
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Restart_control(void) //Tony4Apr97
+{
+ uint32 res;
+ uint32 temp_demo_flag;
+
+
+ res=Generic_mini_control(149618693); //restart text
+
+
+ if (!res)
+ return; //just return to game
+
+
+ Kill_music(); // Stop music instantly! (James22aug97)
+
+
+ DEAD=0; //in case we were dead - well we're not anymore!
+
+//clean up surface memory
+ Kill_mini_surfaces();
+ EraseBackBuffer();
+ //ProcessMenu(); //draw menu
+ FlipScreens();
+
+
+//restart the game
+//clear all memory and reset the globals
+
+ temp_demo_flag = DEMO;
+
+ 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);
+
+ DEMO = temp_demo_flag;
+
+ FreeAllRouteMem(); // free all the route memory blocks from previous game
+
+ Start_game(); // call the same function that first started us up
+
+
+//prime system with a game cycle
+ 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)
+
+ CloseMenuImmediately();
+
+
+ //---------------------------------------------------------------
+ // 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)
+ //---------------------------------------------------------------
+
+ res = LLogic.Process_session();
+
+ if (res)
+ Con_fatal_error("restart 1st cycle failed??");
+
+ this_screen.new_palette=99; // (JEL08oct97) so palette not restored immediately after control panel - we want to fade up instead!
+
+}
+//-----------------------------------------------------------------------------------------------------------------------
+uint32 Generic_mini_control(uint32 text_id) //Tony2Apr97
+{
+
+// returns 1 for OK pressed
+// returns 0 for CANCEL pressed
+
+ uint8 black[4]={0,0,0,0};
+ int breakOut=0;
+ char c;
+
+ uint8 quit_text[MAX_STRING_LEN];
+ uint8 ok_text[MAX_STRING_LEN];
+ uint8 cancel_text[MAX_STRING_LEN];
+ uint8 *text;
+
+ _mouseEvent *me;
+
+ int first=0;
+
+ int text_len;
+
+ #define OK_BUT_X (QUIT_X+40)
+ #define OK_BUT_Y (QUIT_Y+110)
+ #define CAN_BU_Y (QUIT_Y+172)
+
+
+//do some driver stuff
+// ResetRenderEngine();
+
+
+//fetch the 'quit' text
+ text = FetchTextLine( res_man.Res_open(text_id/SIZE), text_id&0xffff ); //quit or restart
+ strcpy((char*)&quit_text[0], (char*)text+2);
+ text_len = Pixel_text_length(&quit_text[0], controls_font_id);
+
+
+//fetch the 'ok' text
+ text = FetchTextLine( res_man.Res_open(149618688/SIZE), 149618688&0xffff ); //ok
+ strcpy((char*)&ok_text[0], (char*)text+2);
+
+//fetch the 'cancel' text
+ text = FetchTextLine( res_man.Res_open(149618689/SIZE), 149618689&0xffff ); //cancel
+ strcpy((char*)&cancel_text[0], (char*)text+2);
+//blimey, life's never easy is it?
+
+
+
+
+//buttons unpressed
+ restore_button_state=0;
+ can_button_state=0;
+
+
+//build surfaces
+ Build_mini_surfaces();
+
+
+
+//control loop
+ while (1)
+ {
+ //--------------------------------------------------
+ // Service windows
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+
+ while (!gotTheFocus)
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ break;
+
+ //--------------------------------------------------
+
+
+ EraseBackBuffer();
+
+
+//print panel
+ if (DrawSurface(&panel_sprite, panel_surface)==RDERR_SURFACELOST)
+ {
+ Kill_mini_surfaces();
+ Build_mini_surfaces();
+ }
+
+//print words on panel quit_x+81
+ Engine_string(310-(text_len/2), QUIT_Y+30, controls_font_id, chr_surface, quit_text); // quit
+ Engine_string(QUIT_X+67, QUIT_Y+110, controls_font_id, chr_surface, ok_text); // ok
+ Engine_string(QUIT_X+67, QUIT_Y+172, controls_font_id, chr_surface, cancel_text); // cancel
+
+//print buttons
+//print ok button
+ DrawSurface(&button_sprite[restore_button_state], button_surface[restore_button_state] );
+//print cancel button
+ DrawSurface(&can_button_sprite[can_button_state], can_button_surface[can_button_state] );
+
+//keep menu up too
+ ProcessMenu();
+
+//user can ESC quit
+ if (KeyWaiting())
+ {
+ ReadKey(&c); //kill the key we just pressed
+ if (c==27) //ESC
+ break;
+ }
+
+
+//mouse over ok button?
+ if ((mousex>OK_BUT_X)&&(mousex<OK_BUT_X+24)&&((mousey+40)>OK_BUT_Y)&&((mousey+40)<OK_BUT_Y+24))
+ touching_restore_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { restore_button_state=0;
+ touching_restore_button=0;
+ }
+//mouse over cancel button?
+ if ((mousex>OK_BUT_X)&&(mousex<OK_BUT_X+24)&&((mousey+40)>CAN_BU_Y)&&((mousey+40)<CAN_BU_Y+24))
+ touching_can_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { can_button_state=0;
+ touching_can_button=0;
+ }
+
+
+//pressing on a button
+ me = MouseEvent(); //get mouse event
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) //there's a mouse event to be processed
+ {
+ if (touching_restore_button)
+ restore_button_state=1;
+
+ if (touching_can_button)
+ can_button_state=1;
+
+ }
+ else if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONUP))
+ {
+ if ((touching_restore_button)&&(restore_button_state)) //quit the game
+ {
+ return(1);
+ }
+
+ if ((touching_can_button)&&(can_button_state))
+ { can_button_state=0;
+ breakOut=1;
+ }
+
+ }
+
+
+ if (breakOut)
+ break;
+
+ FlipScreens();
+ if (!first)
+ {
+ first++;
+ SetFullPalette(CONTROL_PANEL_PALETTE); // see Build_display.cpp (James17jun97)
+ }
+ }
+
+
+ Kill_mini_surfaces();
+
+ return(0);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Build_mini_surfaces(void) //tony3Apr97
+{
+ Create_surface_image(&panel_sprite, &panel_surface, 1996, QUIT_X, QUIT_Y, 0);
+//ok button
+ Create_surface_image(&button_sprite[0], &button_surface[0], 2002, OK_BUT_X, OK_BUT_Y, 0);
+ Create_surface_image(&button_sprite[1], &button_surface[1], 2002, OK_BUT_X, OK_BUT_Y, 1);
+//cancel button
+ Create_surface_image(&can_button_sprite[0], &can_button_surface[0], 2002, OK_BUT_X, CAN_BU_Y, 0);
+ Create_surface_image(&can_button_sprite[1], &can_button_surface[1], 2002, OK_BUT_X, CAN_BU_Y, 1);
+
+ Build_chr_surfaces();
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Kill_mini_surfaces(void) //tony3Apr97
+{
+ DeleteSurface(panel_surface);
+//ok button
+ DeleteSurface(button_surface[0]);
+ DeleteSurface(button_surface[1]);
+//cancel button
+ DeleteSurface(can_button_surface[0]);
+ DeleteSurface(can_button_surface[1]);
+
+ Kill_chr_surfaces();
+}
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+void Engine_string(uint32 x, uint32 y, uint32 res, uint32 *surface_list, uint8 *buf) //tony2Apr97
+{
+//takes fonts as sprites and prints transparently to screen
+//requires the chr$ surfaces have been setup
+
+ int char_no=0;
+ int chr;
+ uint8 *chars;
+
+
+ chars = res_man.Res_open(res); //open font file
+
+ chr_sprite.scale=0;
+ chr_sprite.type= RDSPR_NOCOMPRESSION+RDSPR_TRANS;
+ chr_sprite.blend= 0;
+
+
+ chr_sprite.x=x;
+ chr_sprite.y=y;
+
+ do
+ {
+ chr = buf[char_no];
+ chr-=32; //got true chr$
+
+ head = (_frameHeader *)FetchFrameHeader(chars, chr);
+
+ chr_sprite.w=head->width;
+ chr_sprite.h=head->height;
+
+ DrawSurface(&chr_sprite, surface_list[chr]); //print
+
+ chr_sprite.x+=head->width-CHARACTER_OVERLAP;
+ char_no++;
+ }
+ while(buf[char_no]);
+
+ res_man.Res_close(res); //close font file
+}
+//-----------------------------------------------------------------------------------------------------------------------
+uint32 Pixel_text_length(uint8 *buf, uint32 res) //tony4Apr97
+{
+
+ int char_no=0;
+ int chr;
+ uint8 *chars;
+ uint32 width=0;
+
+
+ chars = res_man.Res_open(res); //open font file
+
+ do
+ {
+ chr = buf[char_no];
+ chr-=32; //got true chr$
+
+ head = (_frameHeader *)FetchFrameHeader(chars, chr);
+
+ width+=head->width-CHARACTER_OVERLAP;
+
+ char_no++;
+ }
+ while(buf[char_no]);
+
+ res_man.Res_close(res); //close font file
+
+ return(width);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Control_error(char* text) //Tony13May97
+{
+//print a message on screen, wait for key, return
+
+ _mouseEvent *me;
+ char c;
+
+ DisplayMsg( (uint8*)text, 0 ); // 2nd param is duration
+
+
+ while (1)
+ {
+ //--------------------------------------------------
+ // Service windows
+
+ 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
+ }
+
+ while (!gotTheFocus)
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ break;
+ //--------------------------------------------------
+
+ if (KeyWaiting())
+ {
+ ReadKey(&c); //kill the key we just pressed
+ if (c==27) //ESC
+ break;
+ }
+
+ me = MouseEvent(); //get mouse event
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) //there's a mouse event to be processed
+ break;
+
+
+
+ }
+
+
+ RemoveMsg(); // Removes the message.
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+int32 ReadOptionSettings(void) //pete10Jun97
+{
+ // settings file is 9 bytes long, bytes 1 to 3 = music, speech and fx volumes
+ // bytes 4 to 6 = music, speech and fx mute states, byte 7 = grfx level
+ // byte 8 = subtitle state and byte 9 = object label state.
+
+ uint8 buff[10];
+ FILE *fp;
+
+ if ((fp = fopen("Settings.dat","rb"))== NULL)
+ return (1);
+
+ if (fread(buff,1,10,fp) != 10)
+ {
+ fclose(fp);
+ return (2);
+ }
+
+ fclose(fp);
+
+ SetMusicVolume(buff[0]);
+ SetSpeechVolume(buff[1]);
+ SetFxVolume(buff[2]);
+ MuteMusic(buff[3]);
+ MuteSpeech(buff[4]);
+ MuteFx(buff[5]);
+
+
+ UpdateGraphicsLevel(GetRenderType(), buff[6]); // (James13jun97)
+
+ speechSelected = !buff[4];
+ subtitles = buff[7];
+ pointerTextSelected = buff[8];
+
+ if (buff[9] != stereoReversed)
+ ReverseStereo();
+
+ stereoReversed = buff[9];
+
+ return (0);
+}
+//-----------------------------------------------------------------------------------------------------------------------
+int32 WriteOptionSettings(void) //pete10Jun97
+{
+ uint8 buff[10];
+ FILE *fp;
+
+ buff[0] = GetMusicVolume();
+ buff[1] = GetSpeechVolume();
+ buff[2] = GetFxVolume();
+ buff[3] = IsMusicMute();
+ buff[4] = IsSpeechMute();
+ buff[5] = IsFxMute();
+ buff[6] = GetRenderType();
+ buff[7] = subtitles;
+ buff[8] = pointerTextSelected;
+ buff[9] = stereoReversed;
+
+ if ((fp = fopen("Settings.dat","wb"))== NULL)
+ return (1);
+
+ if (fwrite(buff,1,10,fp) != 10)
+ {
+ fclose(fp);
+ return (2);
+ }
+
+ fclose(fp);
+
+ return (0);
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+void Build_option_surfaces(void) //pete6Jun97
+{
+ Create_surface_image(&panel_sprite, &panel_surface, 3405, 0, OPTION_Y, 0);
+// object label button
+ Create_surface_image(&up_button_sprite[0], &up_button_surface[0], 3687, OBJ_LABEL_X,OBJ_LABEL_Y, 0);
+ Create_surface_image(&up_button_sprite[1], &up_button_surface[1], 3687, OBJ_LABEL_X,OBJ_LABEL_Y, 1);
+//subtitle button
+ Create_surface_image(&down_button_sprite[0], &down_button_surface[0], 3687, SUBTITLE_X, SUBTITLE_Y, 0);
+ Create_surface_image(&down_button_sprite[1], &down_button_surface[1], 3687, SUBTITLE_X, SUBTITLE_Y, 1);
+//ok button
+ Create_surface_image(&button_sprite[0], &button_surface[0], 901, OPT_OK_X, OPT_OK_Y, 0);
+ Create_surface_image(&button_sprite[1], &button_surface[1], 901, OPT_OK_X, OPT_OK_Y, 1);
+//cancel button
+ Create_surface_image(&can_button_sprite[0], &can_button_surface[0], 901, OPT_CAN_X, OPT_CAN_Y, 0);
+ Create_surface_image(&can_button_sprite[1], &can_button_surface[1], 901, OPT_CAN_X, OPT_CAN_Y, 1);
+//sliders
+ Create_surface_image(&slab_sprite[0], &slab_surface[0], 3406, SLIDER_TRK_X,MUSIC_TRK_Y,0); // music slider
+ Create_surface_image(&slab_sprite[1], &slab_surface[1], 3406, SLIDER_TRK_X,SPEECH_TRK_Y,0); // speech slider
+ Create_surface_image(&slab_sprite[2], &slab_surface[2], 3406, SLIDER_TRK_X,FX_TRK_Y,0); // fx slider
+ Create_surface_image(&slab_sprite[3], &slab_surface[3], 3406, SLIDER_TRK_X,GRFX_TRK_Y,0); // graphics slider
+//mute buttons
+ Create_surface_image(&zup_button_sprite[0], &zup_button_surface[0], 3315, MUTE_X, MUSIC_TRK_Y-4, 0); // music mute
+ Create_surface_image(&zup_button_sprite[1], &zup_button_surface[1], 3315, MUTE_X, MUSIC_TRK_Y-4, 1);
+ Create_surface_image(&zdown_button_sprite[0], &zdown_button_surface[0],3315, MUTE_X, SPEECH_TRK_Y-3, 0);// speech mute
+ Create_surface_image(&zdown_button_sprite[1], &zdown_button_surface[1],3315, MUTE_X, SPEECH_TRK_Y-3, 1);
+ Create_surface_image(&slab_sprite[4], &slab_surface[4], 3315, MUTE_X,FX_TRK_Y-4,0); // fx mute
+ Create_surface_image(&slab_sprite[5], &slab_surface[5], 3315, MUTE_X,FX_TRK_Y-4,1);
+//graphics level icon
+ Create_surface_image(&grfx_icon_sprite[0], &grfx_icon_surface[0], 256, GRFX_ICON_X, GRFX_ICON_Y, 0); // lowest grapihics level icon
+ Create_surface_image(&grfx_icon_sprite[1], &grfx_icon_surface[1], 256, GRFX_ICON_X, GRFX_ICON_Y, 1); // medium low grapihics level icon
+ Create_surface_image(&grfx_icon_sprite[2], &grfx_icon_surface[2], 256, GRFX_ICON_X, GRFX_ICON_Y, 2); // mewdium high grapihics level icon
+ Create_surface_image(&grfx_icon_sprite[3], &grfx_icon_surface[3], 256, GRFX_ICON_X, GRFX_ICON_Y, 3); // highest grapihics level icon
+//reverse stereo button
+ Create_surface_image(&slab_sprite[6], &slab_surface[6], 3687, STEREO_X,STEREO_Y,0);
+ Create_surface_image(&slab_sprite[7], &slab_surface[7], 3687, STEREO_X,STEREO_Y,1);
+
+ Build_chr_surfaces();
+}
+//-----------------------------------------------------------------------------------------------------------------------
+void Kill_option_surfaces(void) //pete6Jun97
+{
+ DeleteSurface(panel_surface);
+//object label button
+ DeleteSurface(up_button_surface[0]);
+ DeleteSurface(up_button_surface[1]);
+//subtitle button
+ DeleteSurface(down_button_surface[0]);
+ DeleteSurface(down_button_surface[1]);
+//ok button
+ DeleteSurface(button_surface[0]);
+ DeleteSurface(button_surface[1]);
+//cancel button
+ DeleteSurface(can_button_surface[0]);
+ DeleteSurface(can_button_surface[1]);
+//sliders
+ DeleteSurface(slab_surface[0]);
+ DeleteSurface(slab_surface[1]);
+ DeleteSurface(slab_surface[2]);
+ DeleteSurface(slab_surface[3]);
+//mute buttons
+ DeleteSurface(zup_button_surface[0]);
+ DeleteSurface(zup_button_surface[1]);
+ DeleteSurface(zdown_button_surface[0]);
+ DeleteSurface(zdown_button_surface[1]);
+ DeleteSurface(slab_surface[4]);
+ DeleteSurface(slab_surface[5]);
+//graphics level icon
+ DeleteSurface(grfx_icon_surface[0]);
+ DeleteSurface(grfx_icon_surface[1]);
+ DeleteSurface(grfx_icon_surface[2]);
+ DeleteSurface(grfx_icon_surface[3]);
+//reverse stereo icon
+ DeleteSurface(slab_surface[6]);
+ DeleteSurface(slab_surface[7]);
+
+ Kill_chr_surfaces();
+}
+//-----------------------------------------------------------------------------------------------------------------------
+int Mouse_touching_button(int32 x, int32 y, int32 w, int32 h) //pete9Jun97
+{
+ if ((mousex>x)&&(mousex<x+w)&&((mousey+40)>y)&&((mousey+40)<y+h))
+ return (1);
+ else
+ return (0);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+void Option_control(void) //Pete6Jun97
+{
+#define WORD_BUTTON_GAP 10
+
+// some things left by the last tennant
+ uint8 black[4] = {0,0,0,0};
+ char c;
+ _mouseEvent *me;
+ int first = 0;
+
+// text strings and lengths
+ uint8 title_text[MAX_STRING_LEN];
+ uint8 subtitle_text[MAX_STRING_LEN];
+ uint8 object_text[MAX_STRING_LEN];
+ uint8 ok_text[MAX_STRING_LEN];
+ uint8 cancel_text[MAX_STRING_LEN];
+ uint8 music_text[MAX_STRING_LEN];
+ uint8 speech_text[MAX_STRING_LEN];
+ uint8 fx_text[MAX_STRING_LEN];
+ uint8 graphics_text[MAX_STRING_LEN];
+ uint8 stereo_text[MAX_STRING_LEN];
+ uint8 *text;
+ int title_len, subtitle_len, ok_len, cancel_len, left_align, test_len;
+
+// slider values
+ uint8 musicVolume = GetMusicVolume();
+ uint8 speechVolume = GetSpeechVolume();
+ uint8 fxVolume = GetFxVolume();
+ uint8 grfxLevel = GetRenderType();
+
+// safe slider values for restoring on cancel
+ uint8 safe_musicVolume = musicVolume;
+ uint8 safe_speechVolume = speechVolume;
+ uint8 safe_fxVolume = fxVolume;
+ uint8 safe_grfxLevel = grfxLevel;
+
+// button state variables
+ uint8 dreverse_stereo_state = 0, dmusic_mute_state = 0, dspeech_mute_state = 0, dfx_mute_state = 0, dobject_state = 0, dsubtitle_state = 0;
+ uint8 touching_reverse_stereo, touching_music_mute, touching_fx_mute, touching_speech_mute, touching_object, touching_subtitle;
+ uint8 lb_down = 0;
+
+// Slider targets
+ uint8 music_target = musicVolume;
+ uint8 fx_target = fxVolume;
+ uint8 speech_target = speechVolume;
+ uint8 grfx_target = grfxLevel;
+
+// Slider movement types (click in track or drag button)
+ uint8 music_tracking = 0, fx_tracking = 0, speech_tracking = 0, grfx_tracking = 0;
+
+//do some driver stuff
+// ResetRenderEngine();
+
+// FETCH THE TEXT
+//fetch the 'options' text
+ text = FetchTextLine( res_man.Res_open(149618698/SIZE), 149618698&0xffff ); //options (title)
+ strcpy((char*)title_text, (char*)text+2);
+ title_len = Pixel_text_length(title_text, controls_font_id);
+
+//fetch the 'subtitles' text
+ text = FetchTextLine( res_man.Res_open(149618699/SIZE), 149618699&0xffff ); //subtitles
+ strcpy((char*)subtitle_text, (char*)text+2);
+ subtitle_len = Pixel_text_length(subtitle_text, controls_font_id) + WORD_BUTTON_GAP;
+
+//fetch the 'object labels' text
+ text = FetchTextLine( res_man.Res_open(149618700/SIZE), 149618700&0xffff ); //object
+ strcpy((char*)object_text, (char*)text+2);
+ left_align = Pixel_text_length(object_text, controls_font_id) + WORD_BUTTON_GAP;
+
+//fetch the 'ok' text
+ text = FetchTextLine( res_man.Res_open(149618688/SIZE), 149618688&0xffff ); //ok
+ strcpy((char*)ok_text, (char*)text+2);
+ ok_len = Pixel_text_length(ok_text, controls_font_id) + WORD_BUTTON_GAP;
+
+//fetch the 'cancel' text
+ text = FetchTextLine( res_man.Res_open(149618689/SIZE), 149618689&0xffff ); //cancel
+ strcpy((char*)cancel_text, (char*)text+2);
+ cancel_len = Pixel_text_length(cancel_text, controls_font_id) + WORD_BUTTON_GAP;
+
+//fetch the 'music volume' text
+ text = FetchTextLine( res_man.Res_open(149618702/SIZE), 149618702&0xffff ); //music volume
+ strcpy((char*)music_text, (char*)text+2);
+ test_len = Pixel_text_length(music_text, controls_font_id) + WORD_BUTTON_GAP;
+ if (test_len>left_align)
+ left_align = test_len;
+
+//fetch the 'speech volume' text
+ text = FetchTextLine( res_man.Res_open(149618703/SIZE), 149618703&0xffff ); //speech volume
+ strcpy((char*)speech_text, (char*)text+2);
+ test_len = Pixel_text_length(speech_text, controls_font_id) + WORD_BUTTON_GAP;
+ if (test_len>left_align)
+ left_align = test_len;
+
+//fetch the 'fx volume' text
+ text = FetchTextLine( res_man.Res_open(149618704/SIZE), 149618704&0xffff ); //fx volume
+ strcpy((char*)fx_text, (char*)text+2);
+ test_len = Pixel_text_length(fx_text, controls_font_id) + WORD_BUTTON_GAP;
+ if (test_len>left_align)
+ left_align = test_len;
+
+//fetch the 'grapihics quality' text
+ text = FetchTextLine( res_man.Res_open(149618705/SIZE), 149618705&0xffff ); //graphics quality
+ strcpy((char*)graphics_text, (char*)text+2);
+ test_len = Pixel_text_length(graphics_text, controls_font_id) + WORD_BUTTON_GAP;
+ if (test_len>left_align)
+ left_align = test_len;
+
+//fetch the 'grapihics quality' text
+ text = FetchTextLine( res_man.Res_open(149618709/SIZE), 149618709&0xffff ); //graphics quality
+ strcpy((char*)stereo_text, (char*)text+2);
+ test_len = Pixel_text_length(stereo_text, controls_font_id) + WORD_BUTTON_GAP;
+ if (test_len>left_align)
+ left_align = test_len;
+
+
+//blimey, life's never easy is it?
+//not once you've got out of bed !
+
+
+//set the button states
+ restore_button_state = 0;
+ can_button_state = 0;
+ touching_object = 0;
+ touching_subtitle = 0;
+ uint8 object_state = pointerTextSelected;
+ uint8 subtitle_state = subtitles;
+ uint8 stereo_state = stereoReversed;
+
+ uint8 music_mute_state = IsMusicMute();
+ uint8 speech_mute_state = IsSpeechMute();
+ uint8 fx_mute_state = IsFxMute();
+
+
+//build the button surfaces surfaces
+ Build_option_surfaces();
+
+//position the sliders
+ slab_sprite[0].x = SLIDER_TRK_X + (SLIDER_TRK_W * musicVolume) / 16;
+ slab_sprite[1].x = SLIDER_TRK_X + (SLIDER_TRK_W * speechVolume) / 14;
+ slab_sprite[2].x = SLIDER_TRK_X + (SLIDER_TRK_W * fxVolume) / 14;
+ slab_sprite[3].x = SLIDER_TRK_X + (SLIDER_TRK_W * grfxLevel) / 3;
+
+//control loop
+ while (1)
+ {
+// Update any moving sliders
+ // music
+ if (slab_sprite[0].x<SLIDER_TRK_X + (SLIDER_TRK_W * music_target) / 16)
+ {
+ if ((SLIDER_TRK_X + (SLIDER_TRK_W * music_target) / 16)-slab_sprite[0].x<2)
+ slab_sprite[0].x++;
+ else
+ slab_sprite[0].x +=2;
+ musicVolume = (int)((float)((slab_sprite[0].x-SLIDER_TRK_X)*16)/(float)SLIDER_TRK_W+0.5);
+ }
+ else if (slab_sprite[0].x>SLIDER_TRK_X + (SLIDER_TRK_W * music_target) / 16)
+ {
+ if (slab_sprite[0].x-(SLIDER_TRK_X + (SLIDER_TRK_W * music_target) / 16)<2)
+ slab_sprite[0].x--;
+ else
+ slab_sprite[0].x -=2;
+ musicVolume = (int)((float)((slab_sprite[0].x-SLIDER_TRK_X)*16)/(float)SLIDER_TRK_W+0.5);
+
+ if (!musicVolume)
+ music_mute_state = 1;
+ else
+ music_mute_state = 0;
+ }
+
+ // speech
+ if (slab_sprite[1].x<SLIDER_TRK_X + (SLIDER_TRK_W * speech_target) / 14)
+ {
+ if ((SLIDER_TRK_X + (SLIDER_TRK_W * speech_target) / 14)-slab_sprite[1].x<2)
+ slab_sprite[1].x++;
+ else
+ slab_sprite[1].x +=2;
+ speechVolume = (int)((float)((slab_sprite[1].x-SLIDER_TRK_X)*14)/(float)SLIDER_TRK_W+0.5);
+ }
+ else if (slab_sprite[1].x>SLIDER_TRK_X + (SLIDER_TRK_W * speech_target) / 14)
+ {
+ if (slab_sprite[1].x-(SLIDER_TRK_X + (SLIDER_TRK_W * speech_target) / 14)<2)
+ slab_sprite[1].x--;
+ else
+ slab_sprite[1].x -=2;
+ speechVolume = (int)((float)((slab_sprite[1].x-SLIDER_TRK_X)*14)/(float)SLIDER_TRK_W+0.5);
+
+ if (!speechVolume)
+ speech_mute_state = 1;
+ else
+ speech_mute_state = 0;
+ }
+
+ // fx
+ if (slab_sprite[2].x<SLIDER_TRK_X + (SLIDER_TRK_W * fx_target) / 14)
+ {
+ if ((SLIDER_TRK_X + (SLIDER_TRK_W * fx_target) / 14)-slab_sprite[2].x<2)
+ slab_sprite[2].x++;
+ else
+ slab_sprite[2].x +=2;
+ fxVolume = (int)((float)((slab_sprite[2].x-SLIDER_TRK_X)*14)/(float)SLIDER_TRK_W+0.5);
+ }
+ else if (slab_sprite[2].x>SLIDER_TRK_X + (SLIDER_TRK_W * fx_target) / 14)
+ {
+ if (slab_sprite[2].x-(SLIDER_TRK_X + (SLIDER_TRK_W * fx_target) / 14)<2)
+ slab_sprite[2].x--;
+ else
+ slab_sprite[2].x -=2;
+ fxVolume = (int)((float)((slab_sprite[2].x-SLIDER_TRK_X)*14)/(float)SLIDER_TRK_W+0.5);
+
+ if (!fxVolume)
+ fx_mute_state = 1;
+ else
+ fx_mute_state = 0;
+ }
+
+ // grfx
+ if (slab_sprite[3].x<SLIDER_TRK_X + (SLIDER_TRK_W * grfx_target) / 3)
+ {
+ if ((SLIDER_TRK_X + (SLIDER_TRK_W * grfx_target) / 3)-slab_sprite[3].x<2)
+ slab_sprite[3].x++;
+ else
+ slab_sprite[3].x +=2;
+ grfxLevel = (int)((float)((slab_sprite[3].x-SLIDER_TRK_X)*3)/(float)SLIDER_TRK_W+0.5);
+ }
+ else if (slab_sprite[3].x>SLIDER_TRK_X + (SLIDER_TRK_W * grfx_target) / 3)
+ {
+ if (slab_sprite[3].x-(SLIDER_TRK_X + (SLIDER_TRK_W * grfx_target) / 3)<2)
+ slab_sprite[3].x--;
+ else
+ slab_sprite[3].x -=2;
+ grfxLevel = (int)((float)((slab_sprite[3].x-SLIDER_TRK_X)*3)/(float)SLIDER_TRK_W+0.5);
+ }
+
+
+ if (music_tracking) // music tracking
+ {
+ slab_sprite[0].x = mousex - SLIDER_W/2;
+ if (slab_sprite[0].x < SLIDER_TRK_X)
+ slab_sprite[0].x = SLIDER_TRK_X;
+ else if (slab_sprite[0].x > SLIDER_TRK_X+SLIDER_TRK_W)
+ slab_sprite[0].x = SLIDER_TRK_X+SLIDER_TRK_W;
+ music_target = musicVolume = (int)((float)((slab_sprite[0].x-SLIDER_TRK_X)*16)/(float)SLIDER_TRK_W+0.5);
+
+ if (!musicVolume)
+ music_mute_state = 1;
+ else
+ music_mute_state = 0;
+
+ }
+ else if (speech_tracking) // speech tracking
+ {
+ slab_sprite[1].x = mousex - SLIDER_W/2;
+ if (slab_sprite[1].x < SLIDER_TRK_X)
+ slab_sprite[1].x = SLIDER_TRK_X;
+ else if (slab_sprite[1].x > SLIDER_TRK_X+SLIDER_TRK_W)
+ slab_sprite[1].x = SLIDER_TRK_X+SLIDER_TRK_W;
+ speech_target = speechVolume = (int)((float)((slab_sprite[1].x-SLIDER_TRK_X)*14)/(float)SLIDER_TRK_W+0.5);
+
+ if (!speechVolume)
+ speech_mute_state = 1;
+ else
+ speech_mute_state = 0;
+
+ }
+ else if (fx_tracking) // fx tracking
+ {
+ slab_sprite[2].x = mousex - SLIDER_W/2;
+ if (slab_sprite[2].x < SLIDER_TRK_X)
+ slab_sprite[2].x = SLIDER_TRK_X;
+ else if (slab_sprite[2].x > SLIDER_TRK_X+SLIDER_TRK_W)
+ slab_sprite[2].x = SLIDER_TRK_X+SLIDER_TRK_W;
+ fx_target = fxVolume = (int)((float)((slab_sprite[2].x-SLIDER_TRK_X)*14)/(float)SLIDER_TRK_W+0.5);
+
+ if (!fxVolume)
+ fx_mute_state = 1;
+ else
+ fx_mute_state = 0;
+
+ }
+ else if (grfx_tracking) // grfx tracking
+ {
+ slab_sprite[3].x = mousex - SLIDER_W/2;
+ if (slab_sprite[3].x < SLIDER_TRK_X)
+ slab_sprite[3].x = SLIDER_TRK_X;
+ else if (slab_sprite[3].x > SLIDER_TRK_X+SLIDER_TRK_W)
+ slab_sprite[3].x = SLIDER_TRK_X+SLIDER_TRK_W;
+ grfx_target = grfxLevel = (int)((float)((slab_sprite[3].x-SLIDER_TRK_X)*3)/(float)SLIDER_TRK_W+0.5);
+ }
+
+ if (!music_mute_state)
+ SetMusicVolume(musicVolume);
+ else
+ SetMusicVolume(0);
+
+ if (!fx_mute_state)
+ SetFxVolume(fxVolume);
+ else
+ SetFxVolume(0);
+
+ if (!speech_mute_state)
+ SetSpeechVolume(speechVolume);
+ else
+ SetSpeechVolume(0);
+
+ //--------------------------------------------------
+ // Service windows
+
+ 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
+ }
+
+ while (!gotTheFocus)
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ break;
+ //--------------------------------------------------
+
+ EraseBackBuffer();
+
+
+//print panel
+ while (DrawSurface(&panel_sprite, panel_surface)==RDERR_SURFACELOST)
+ {
+ Kill_option_surfaces();
+ Build_option_surfaces();
+ };
+
+//print words on panel option panel
+ Engine_string(OPTION_W/2-(title_len/2)+OPTION_X,OPTION_Y+15, controls_font_id, chr_surface, title_text); //options
+ Engine_string(SUBTITLE_X-subtitle_len, SUBTITLE_Y+3, controls_font_id, chr_surface, subtitle_text); //subtitles
+ Engine_string(SLIDER_TRK_X-left_align, OBJ_LABEL_Y+3, controls_font_id, chr_surface, object_text); //object labels
+ Engine_string(OPT_OK_X-ok_len, OPT_OK_Y, controls_font_id, chr_surface, ok_text); //ok
+ Engine_string(OPT_CAN_X-cancel_len, OPT_CAN_Y, controls_font_id, chr_surface, cancel_text); //cancel
+ Engine_string(SLIDER_TRK_X-left_align, MUSIC_TRK_Y, controls_font_id, chr_surface, music_text); //music volume
+ Engine_string(SLIDER_TRK_X-left_align, SPEECH_TRK_Y, controls_font_id, chr_surface, speech_text); //speech volume
+ Engine_string(SLIDER_TRK_X-left_align, FX_TRK_Y, controls_font_id, chr_surface, fx_text); //fx volume
+ Engine_string(SLIDER_TRK_X-left_align, GRFX_TRK_Y, controls_font_id, chr_surface, graphics_text); //graphics quality
+ Engine_string(SLIDER_TRK_X-left_align, STEREO_Y+3, controls_font_id, chr_surface, stereo_text); //reverse stereo
+
+//print buttons
+ DrawSurface(&down_button_sprite[subtitle_state], down_button_surface[subtitle_state] ); //print subtitles button
+
+ DrawSurface(&up_button_sprite[object_state], up_button_surface[object_state] ); //print object labels button
+
+ DrawSurface(&button_sprite[restore_button_state], button_surface[restore_button_state] ); //print ok button
+
+ DrawSurface(&can_button_sprite[can_button_state], can_button_surface[can_button_state] ); //print cancel button
+
+ DrawSurface(&slab_sprite[0], slab_surface[0]); //print sliders
+ DrawSurface(&slab_sprite[1], slab_surface[1]);
+ DrawSurface(&slab_sprite[2], slab_surface[2]);
+ DrawSurface(&slab_sprite[3], slab_surface[3]);
+
+ DrawSurface(&zup_button_sprite[music_mute_state], zup_button_surface[music_mute_state] ); //print mute buttons
+ DrawSurface(&zdown_button_sprite[speech_mute_state], zdown_button_surface[speech_mute_state] );
+ DrawSurface(&slab_sprite[fx_mute_state+4], slab_surface[fx_mute_state+4] );
+
+ DrawSurface(&grfx_icon_sprite[grfxLevel], grfx_icon_surface[grfxLevel] ); //print the graphics level icon
+
+ DrawSurface(&slab_sprite[6+stereo_state], slab_surface[6+stereo_state]); // print reverse stereo button
+
+//keep menu up too
+ ProcessMenu();
+
+//user can ESC quit
+ if (KeyWaiting())
+ {
+ ReadKey(&c); //kill the key we just pressed
+ if (c==27) //ESC
+ {
+ ReadOptionSettings(); // Reset options to previous settings.
+ break;
+ }
+ }
+
+// check what if anything the mouse is touching
+//mouse over ok button?
+ if (Mouse_touching_button(OPT_OK_X,OPT_OK_Y,OPT_BUT_W,OPT_BUT_H))
+ touching_restore_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { restore_button_state=0;
+ touching_restore_button=0;
+ }
+
+//mouse over cancel button?
+ if (Mouse_touching_button(OPT_CAN_X,OPT_CAN_Y,OPT_BUT_W,OPT_BUT_H))
+ touching_can_button=1; //mouse over button
+ else //not over so release even if pressed previously
+ { can_button_state=0;
+ touching_can_button=0;
+ }
+
+//mouse over object label button?
+ if (Mouse_touching_button(OBJ_LABEL_X,OBJ_LABEL_Y,OPT_BUT_W,OPT_BUT_H))
+ {
+ if (!lb_down)
+ touching_object=1; //mouse over button
+ }
+ else //not over so release even if pressed previously
+ {
+ if (touching_object && lb_down && !dobject_state)
+ object_state=!object_state;
+ touching_object=0;
+ }
+
+//mouse over subtitles button?
+ if (Mouse_touching_button(SUBTITLE_X,SUBTITLE_Y,OPT_BUT_W,OPT_BUT_H))
+ {
+ if (!lb_down)
+ touching_subtitle=1; //mouse over button
+ }
+ else //not over so release even if pressed previously
+ {
+ if (touching_subtitle && lb_down && !dsubtitle_state)
+ subtitle_state=!subtitle_state;
+ touching_subtitle=0;
+ }
+
+//mouse over reverse stereo button?
+ if (Mouse_touching_button(STEREO_X,STEREO_Y,OPT_BUT_W,OPT_BUT_H))
+ {
+ if (!lb_down)
+ touching_reverse_stereo=1; //mouse over button
+ }
+ else //not over so release even if pressed previously
+ {
+ if (touching_reverse_stereo && lb_down && !dreverse_stereo_state)
+ stereo_state=!stereo_state;
+ touching_reverse_stereo=0;
+ }
+
+//mouse over music mute button?
+ if (Mouse_touching_button(MUTE_X,MUSIC_TRK_Y-4,MUTE_W,MUTE_H))
+ {
+ if (!lb_down)
+ touching_music_mute=1; //mouse over button
+ }
+ else //not over so release even if pressed previously
+ {
+ if (touching_music_mute && lb_down && !dmusic_mute_state)
+ music_mute_state=!music_mute_state;
+ touching_music_mute=0;
+ }
+
+//mouse over fx mute button?
+ if (Mouse_touching_button(MUTE_X,FX_TRK_Y-4,MUTE_W,MUTE_H))
+ {
+ if (!lb_down)
+ touching_fx_mute=1; //mouse over button
+ }
+ else //not over so release even if pressed previously
+ {
+ if (touching_fx_mute && lb_down && !dfx_mute_state)
+ fx_mute_state=!fx_mute_state;
+ touching_fx_mute=0;
+ }
+
+//mouse over speech mute button?
+ if (Mouse_touching_button(MUTE_X,SPEECH_TRK_Y-4,MUTE_W,MUTE_H))
+ {
+ if (!lb_down)
+ touching_speech_mute=1; //mouse over button
+ }
+ else //not over so release even if pressed previously
+ {
+ if (touching_speech_mute && lb_down && !dspeech_mute_state)
+ speech_mute_state=!speech_mute_state;
+ touching_speech_mute=0;
+ }
+
+
+//pressing on a button
+ me = MouseEvent(); //get mouse event
+
+ if (me!=NULL)
+ {
+ if (me->buttons&RD_LEFTBUTTONUP)
+ {
+ lb_down = 0;
+ if (touching_restore_button && restore_button_state) // ok to settings
+ {
+ UpdateGraphicsLevel(safe_grfxLevel, grfxLevel); // (James13jun97)
+
+ MuteMusic(music_mute_state); // Ensure all the levels are recorded correctly (Pete21Aug97)
+ MuteSpeech(speech_mute_state);
+ MuteFx(fx_mute_state);
+ SetMusicVolume(music_target);
+ SetSpeechVolume(speech_target);
+ SetFxVolume(fx_target);
+
+ subtitles = subtitle_state; // Save object label and subtitle settings
+ pointerTextSelected = object_state;
+ speechSelected = !speech_mute_state;
+
+ if (stereo_state != stereoReversed)
+ ReverseStereo();
+
+ stereoReversed = stereo_state;
+ WriteOptionSettings();
+ break;
+ }
+
+ if (touching_can_button && can_button_state) // cancel, so restore old settings
+ {
+ ReadOptionSettings();
+ break;
+ }
+
+ if (touching_object && dobject_state)
+ dobject_state = object_state=0; // if the button was in now let it out
+
+ if (touching_subtitle && dsubtitle_state)
+ subtitle_state = dsubtitle_state = 0; // if the button was in now let it out
+
+ if (touching_reverse_stereo && dreverse_stereo_state)
+ dreverse_stereo_state = stereo_state = 0; // if the button was in now let it out
+
+ if (touching_music_mute && dmusic_mute_state) {
+ music_mute_state = dmusic_mute_state = 0; // if the button was in now let it out
+ MuteMusic(0);
+ }
+
+ if (touching_fx_mute && dfx_mute_state) {
+ fx_mute_state = dfx_mute_state = 0; // if the button was in now let it out
+ MuteFx(0);
+ }
+
+ if (touching_speech_mute && dspeech_mute_state) {
+ speech_mute_state = dspeech_mute_state = 0; // if the button was in now let it out
+ MuteSpeech(0);
+ }
+
+ // Stop tracking any sliders
+ music_tracking = fx_tracking = speech_tracking = grfx_tracking = 0;
+ }
+
+ else if (me->buttons&RD_LEFTBUTTONDOWN) //there's a mouse event to be processed
+ {
+ lb_down = 1;
+ if (touching_restore_button)
+ restore_button_state=1;
+
+ if (touching_can_button)
+ can_button_state=1;
+
+ if (touching_object)
+ {
+ if (object_state) // push in the button if it's out
+ dobject_state = 1;
+ else
+ object_state=!object_state;
+ }
+
+ if (touching_subtitle)
+ {
+ if (subtitle_state)
+ dsubtitle_state = 1;
+ else
+ subtitle_state=!subtitle_state;
+ }
+
+ if (touching_reverse_stereo)
+ {
+ if (stereo_state) // push in the button if it's out
+ dreverse_stereo_state = 1;
+ else
+ stereo_state = !stereo_state;
+ }
+
+
+ if (touching_music_mute)
+ {
+ if (music_mute_state)
+ dmusic_mute_state = 1;
+ else
+ {
+ music_mute_state = 1;
+ MuteMusic(1);
+ }
+ }
+
+ if (touching_fx_mute)
+ {
+ if (fx_mute_state)
+ dfx_mute_state = 1;
+ else
+ {
+ fx_mute_state=1;
+ MuteFx(1);
+ }
+ }
+
+ if (touching_speech_mute)
+ {
+ if (speech_mute_state)
+ dspeech_mute_state = 1;
+ else
+ {
+ speech_mute_state=1;
+ MuteSpeech(1);
+ }
+ }
+
+ if (Mouse_touching_button(SLIDER_TRK_X,MUSIC_TRK_Y,SLIDER_TRK_W+SLIDER_W,SLIDER_TRK_H))
+ {
+ if (music_mute_state)
+ {
+ music_mute_state = 0;
+ MuteMusic(0);
+ }
+
+ if (mousex>(slab_sprite[0].x+SLIDER_W))
+ {
+ if (music_target<musicVolume)
+ music_target = musicVolume;
+ music_target++;
+ if (music_target>15)
+ music_target = 15;
+ }
+ else if (mousex<slab_sprite[0].x)
+ {
+ if (music_target>musicVolume)
+ music_target = musicVolume;
+ music_target--;
+ if (music_target>15)
+ music_target = 0;
+ } else
+ music_tracking = 1;
+ }
+
+ if (Mouse_touching_button(SLIDER_TRK_X,SPEECH_TRK_Y,SLIDER_TRK_W+SLIDER_W,SLIDER_TRK_H))
+ {
+ if (speech_mute_state)
+ {
+ speech_mute_state = 0;
+ MuteSpeech(0);
+ }
+
+ if (mousex>(slab_sprite[1].x+SLIDER_W))
+ {
+ if (speech_target<speechVolume)
+ speech_target = speechVolume;
+ speech_target++;
+ if (speech_target>14)
+ speech_target = 14;
+ }
+ else if (mousex<slab_sprite[1].x)
+ {
+ if (speech_target>speechVolume)
+ speech_target = speechVolume;
+ speech_target--;
+ if (speech_target>14)
+ speech_target = 0;
+ } else
+ speech_tracking = 1;
+ }
+
+ if (Mouse_touching_button(SLIDER_TRK_X,FX_TRK_Y,SLIDER_TRK_W+SLIDER_W,SLIDER_TRK_H))
+ {
+ if (fx_mute_state)
+ {
+ fx_mute_state = 0;
+ MuteFx(0);
+ }
+
+ if (mousex>(slab_sprite[2].x+SLIDER_W))
+ {
+ if (fx_target<fxVolume)
+ fx_target = fxVolume;
+ fx_target++;
+ if (fx_target>14)
+ fx_target = 14;
+ }
+ else if (mousex<slab_sprite[2].x)
+ {
+ if (fx_target>fxVolume)
+ fx_target = fxVolume;
+ fx_target--;
+ if (fx_target>14)
+ fx_target = 0;
+ }
+ else
+ fx_tracking = 1;
+
+ fx_mute_state = 0;
+ }
+
+ if (Mouse_touching_button(SLIDER_TRK_X,GRFX_TRK_Y,SLIDER_TRK_W+SLIDER_W,SLIDER_TRK_H))
+ {
+ if (mousex>(slab_sprite[3].x+SLIDER_W))
+ {
+ if (grfx_target<grfxLevel)
+ grfx_target = grfxLevel;
+ grfx_target++;
+ if (grfx_target>3)
+ grfx_target = 3;
+ }
+ else if (mousex<slab_sprite[3].x)
+ {
+ if (grfx_target>grfxLevel)
+ grfx_target = grfxLevel;
+ grfx_target--;
+ if (grfx_target>3)
+ grfx_target = 0;
+ }
+ else
+ grfx_tracking = 1;
+ }
+ }
+ }
+
+
+ if (!first)
+ {
+ first++;
+ SetFullPalette(CONTROL_PANEL_PALETTE); // see Build_display.cpp (James17jun97)
+ }
+ FlipScreens();
+ }
+
+
+ Kill_option_surfaces();
+
+ return; //just return to game
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+void UpdateGraphicsLevel(uint8 oldLevel, uint8 newLevel) // (James13jun97)
+{
+
+ switch (oldLevel) // Set the graphics level
+ {
+ //-------------------------------
+ case 0: // lowest setting: h/w only; no graphics fx
+ switch(newLevel)
+ {
+ case 0:
+ break;
+
+ case 1:
+ RenderSoft();
+ ClearBltFx();
+ ClearShadowFx();
+ CloseBackgroundLayer();
+ break;
+
+ case 2:
+ RenderSoft();
+ ClearBltFx();
+ CloseBackgroundLayer();
+ break;
+
+ case 3: // same as case 2 until case 2 has edge-blending inactivated
+ RenderSoft();
+ CloseBackgroundLayer();
+ break;
+ }
+ break;
+ //-------------------------------
+ case 1: // medium-low setting: s/w transparency-blending
+ switch(newLevel)
+ {
+ case 1:
+ break;
+
+ case 0:
+ RenderHard();
+ SetUpBackgroundLayers(); // InitialiseBackgroundLayer for each layer! (see layers.cpp)
+ break;
+
+ case 2:
+ SetShadowFx();
+ break;
+
+ case 3: // same as case 2 until case 2 has edge-blending inactivated
+ SetBltFx();
+ break;
+ }
+ break;
+ //-------------------------------
+ case 2: // medium-high setting: s/w transparency-blending + shading
+ switch(newLevel)
+ {
+ case 2:
+ break;
+
+ case 3: // same as case 2 until case 2 has edge-blending inactivated
+ SetBltFx();
+ break;
+
+ case 1:
+ ClearShadowFx();
+ break;
+
+ case 0:
+ RenderHard();
+ SetUpBackgroundLayers(); // InitialiseBackgroundLayer for each layer! (see layers.cpp)
+ break;
+ }
+ break;
+ //-------------------------------
+ case 3: // highest setting: s/w transparency-blending + shading + edge-blending (& improved stretching)
+ switch(newLevel)
+ {
+ case 2:
+ ClearBltFx();
+ break;
+
+ case 3: // same as case 2 until case 2 has edge-blending inactivated
+ break;
+
+ case 1:
+ ClearBltFx();
+ ClearShadowFx();
+ break;
+
+ case 0:
+ RenderHard();
+ SetUpBackgroundLayers(); // InitialiseBackgroundLayer for each layer! (see layers.cpp)
+ break;
+ }
+ break;
+ //-------------------------------
+ }
+
+ // update our global variable - which needs to be checked when dimming the palette
+ // in PauseGame() in sword2.cpp (since palette-matching cannot be done with dimmed palette
+ // so we turn down one notch while dimmed, if at top level)
+ current_graphics_level = newLevel;
+}
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+
diff --git a/sword2/controls.h b/sword2/controls.h
new file mode 100644
index 0000000000..95045e2e63
--- /dev/null
+++ b/sword2/controls.h
@@ -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
diff --git a/sword2/credits.h b/sword2/credits.h
new file mode 100644
index 0000000000..26337c81c6
--- /dev/null
+++ b/sword2/credits.h
@@ -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
diff --git a/sword2/debug.cpp b/sword2/debug.cpp
new file mode 100644
index 0000000000..c7f1010140
--- /dev/null
+++ b/sword2/debug.cpp
@@ -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
+//--------------------------------------------------------------------------------------
diff --git a/sword2/debug.h b/sword2/debug.h
new file mode 100644
index 0000000000..0ecca67830
--- /dev/null
+++ b/sword2/debug.h
@@ -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
diff --git a/sword2/defs.h b/sword2/defs.h
new file mode 100644
index 0000000000..f90e662f07
--- /dev/null
+++ b/sword2/defs.h
@@ -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
diff --git a/sword2/events.cpp b/sword2/events.cpp
new file mode 100644
index 0000000000..b7f339c99a
--- /dev/null
+++ b/sword2/events.cpp
@@ -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);
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+
diff --git a/sword2/events.h b/sword2/events.h
new file mode 100644
index 0000000000..d4fc6a632e
--- /dev/null
+++ b/sword2/events.h
@@ -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
diff --git a/sword2/function.cpp b/sword2/function.cpp
new file mode 100644
index 0000000000..214924a503
--- /dev/null
+++ b/sword2/function.cpp
@@ -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);
+}
+//------------------------------------------------------------------------------------
+
diff --git a/sword2/function.h b/sword2/function.h
new file mode 100644
index 0000000000..963bd6acff
--- /dev/null
+++ b/sword2/function.h
@@ -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
diff --git a/sword2/header.h b/sword2/header.h
new file mode 100644
index 0000000000..b4caaab3c4
--- /dev/null
+++ b/sword2/header.h
@@ -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
diff --git a/sword2/icons.cpp b/sword2/icons.cpp
new file mode 100644
index 0000000000..880fcbc0da
--- /dev/null
+++ b/sword2/icons.cpp
@@ -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);
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
diff --git a/sword2/icons.h b/sword2/icons.h
new file mode 100644
index 0000000000..c841a01633
--- /dev/null
+++ b/sword2/icons.h
@@ -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
diff --git a/sword2/interpreter.cpp b/sword2/interpreter.cpp
new file mode 100644
index 0000000000..91bf84f3ad
--- /dev/null
+++ b/sword2/interpreter.cpp
@@ -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);
+}
diff --git a/sword2/interpreter.h b/sword2/interpreter.h
new file mode 100644
index 0000000000..2f28ca83f9
--- /dev/null
+++ b/sword2/interpreter.h
@@ -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
diff --git a/sword2/layers.cpp b/sword2/layers.cpp
new file mode 100644
index 0000000000..0cf405407f
--- /dev/null
+++ b/sword2/layers.cpp
@@ -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)
+ {
+ }
+}
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
diff --git a/sword2/layers.h b/sword2/layers.h
new file mode 100644
index 0000000000..8bc73b7dda
--- /dev/null
+++ b/sword2/layers.h
@@ -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
diff --git a/sword2/logic.cpp b/sword2/logic.cpp
new file mode 100644
index 0000000000..4519badee8
--- /dev/null
+++ b/sword2/logic.cpp
@@ -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;
+}
+//------------------------------------------------------------------------------------
+
diff --git a/sword2/logic.h b/sword2/logic.h
new file mode 100644
index 0000000000..a10f3a6613
--- /dev/null
+++ b/sword2/logic.h
@@ -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
diff --git a/sword2/maketext.cpp b/sword2/maketext.cpp
new file mode 100644
index 0000000000..eb90d7d7cc
--- /dev/null
+++ b/sword2/maketext.cpp
@@ -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;
+ }
+ }
+}
+//------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+
+
+
+
+
diff --git a/sword2/maketext.h b/sword2/maketext.h
new file mode 100644
index 0000000000..e770687361
--- /dev/null
+++ b/sword2/maketext.h
@@ -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
diff --git a/sword2/mem_view.cpp b/sword2/mem_view.cpp
new file mode 100644
index 0000000000..11542ce576
--- /dev/null
+++ b/sword2/mem_view.cpp
@@ -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) );
+}
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
diff --git a/sword2/mem_view.h b/sword2/mem_view.h
new file mode 100644
index 0000000000..725c55ff5c
--- /dev/null
+++ b/sword2/mem_view.h
@@ -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
diff --git a/sword2/memory.cpp b/sword2/memory.cpp
new file mode 100644
index 0000000000..a8fba5b780
--- /dev/null
+++ b/sword2/memory.cpp
@@ -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);
+}
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
diff --git a/sword2/memory.h b/sword2/memory.h
new file mode 100644
index 0000000000..0ea75a47dc
--- /dev/null
+++ b/sword2/memory.h
@@ -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
diff --git a/sword2/module.mk b/sword2/module.mk
new file mode 100644
index 0000000000..b5892f6204
--- /dev/null
+++ b/sword2/module.mk
@@ -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
diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp
new file mode 100644
index 0000000000..7332b5b39b
--- /dev/null
+++ b/sword2/mouse.cpp
@@ -0,0 +1,1466 @@
+/* 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 "driver/driver96.h"
+#include "build_display.h"
+#include "console.h"
+#include "controls.h"
+#include "debug.h"
+#include "defs.h"
+#include "events.h"
+#include "icons.h"
+#include "interpreter.h"
+#include "layers.h"
+#include "maketext.h"
+#include "mouse.h" //assure integrety
+#include "object.h"
+#include "protocol.h"
+#include "resman.h"
+#include "sound.h"
+#include "sword2.h" // for PauseGame() & UnpauseGame()
+//------------------------------------------------------------------------------------
+// pointer resource id's
+
+#define CROSHAIR 18
+#define EXIT0 788
+#define EXIT1 789
+#define EXIT2 790
+#define EXIT3 791
+#define EXIT4 792
+#define EXIT5 793
+#define EXIT6 794
+#define EXIT7 795
+#define EXITDOWN 796
+#define EXITUP 797
+#define MOUTH 787
+#define NORMAL 17
+#define PICKUP 3099
+#define SCROLL_L 1440
+#define SCROLL_R 1441
+#define USE 3100
+//------------------------------------------------------------------------------------
+//the mouse list stuff
+uint32 cur_mouse;
+Mouse_unit mouse_list[TOTAL_mouse_list];
+
+uint32 mouse_touching=0; //set by Check_mouse_list
+uint32 old_mouse_touching=0;
+
+uint32 menu_selected_pos;
+uint8 examining_menu_icon=0;
+
+uint32 mouse_pointer_res=0; // if it's NORMAL_MOUSE_ID (ie. normal pointer) then it's over a floor area (or hidden hot-zone
+uint32 mouse_mode=0; //0 normal in game
+ //1 top menu down (bottom!)
+ //2 dragging luggage
+ //3 system menu chooser (top)
+ //4 speech chooser
+
+//Object_mouse old_mouse_object; //copy structure from list when moving onto a mouse area
+
+uint32 menu_status; //0 available - 1 unavailable
+uint32 mouse_status; //human 0 on/1 off
+
+uint32 mouse_mode_locked=0; //0 not !0 mode cannot be changed from normal mouse to top menu (i.e. when carrying big objects)
+uint32 current_luggage_resource=0;
+
+uint32 subject_status; //0 off 1 on
+
+uint32 old_button=0; //for the re-click stuff - must be same button you see
+uint32 button_click=0;
+
+uint32 pointer_text_bloc_no=0;
+uint32 pointerTextSelected=0;
+
+uint32 player_activity_delay=0; // player activity delay counter
+
+uint32 real_luggage_item=0; //last minute for pause mode
+
+//------------------------------------------------------------------------------------
+/*
+#define RD_LEFTBUTTONDOWN 0x01
+#define RD_LEFTBUTTONUP 0x02
+#define RD_RIGHTBUTTONDOWN 0x04
+#define RD_RIGHTBUTTONUP 0x08
+*/
+//------------------------------------------------------------------------------------
+// local function prototypes
+
+//uint8 Check_sprite_pixel( uint32 j );
+void CreatePointerText(uint32 TextId, uint32 pointerRes); // James16jun97
+void ClearPointerText(void); // James16jun97
+void Monitor_player_activity(void); // James23july97
+
+int32 FN_no_human(int32 *params);
+void No_human(void);
+
+//------------------------------------------------------------------------------------
+void Reset_mouse_list(void) //Tony26Sept96
+{
+//call at beginning of gameloop
+
+ cur_mouse=1;
+}
+//------------------------------------------------------------------------------------
+void Mouse_engine(void) //Tony30Sept96
+{
+
+ Monitor_player_activity(); // James23july97
+
+ ClearPointerText(); // James16jun97
+
+
+ if (DEAD) //George is dead ;)
+ {
+ if (mouse_mode!=MOUSE_system_menu)
+ {
+ mouse_mode=MOUSE_system_menu;
+ if (mouse_touching)
+ {
+// get off
+ old_mouse_touching=0; //we've moved off
+ mouse_touching=0; //we were on something but not anymore
+ }
+
+ Set_mouse(NORMAL_MOUSE_ID);
+
+ Build_system_menu(); //Tony19Mar97
+ }
+ System_menu();
+
+ return;
+ }
+
+
+ if (mouse_status) //no human
+ return;
+
+
+ switch(mouse_mode)
+ {
+ case MOUSE_normal: //0 normal in game
+ Normal_mouse();
+ break;
+
+ case MOUSE_top: //1 top menu down
+ Top_menu_mouse();
+ break;
+
+ case MOUSE_drag: //2 dragging luggage
+ Drag_mouse();
+ break;
+
+ case MOUSE_system_menu: //3 in game bottom menu - save/restore, etc?
+ System_menu();
+ break;
+
+ case MOUSE_holding: //4 wait for mouse to move off bottom menu - after speech
+ if (mousey<400)
+ { mouse_mode=MOUSE_normal;
+ Zdebug(" releasing");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+}
+//------------------------------------------------------------------------------------
+void System_menu(void) //Tony19Mar97
+{
+ uint32 safe_looping_music_id;
+ _mouseEvent *me;
+ int j,hit;
+ uint8 *icon;
+ uint32 rv; // for drivers return value
+ int32 pars[2];
+ uint32 icon_list[5] =
+ {
+ OPTIONS_ICON,
+ QUIT_ICON,
+ SAVE_ICON,
+ RESTORE_ICON,
+ RESTART_ICON
+ };
+
+
+
+ if ((mousey>0)&&(!DEAD)) //can't close when player is dead
+ { mouse_mode=MOUSE_normal; //close menu
+
+// start the menu coming down
+ HideMenu(RDMENU_TOP);
+
+ return;
+ }
+
+ me = MouseEvent(); //get mouse event
+
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) //there's a mouse event to be processed
+ {
+
+// clicked on a top mouse pointer?
+
+ if ((mousex>=24)&&(mousex<640-24)&&(mousey<0))
+ {
+ hit=(mousex-24)/40; //which are we over?
+
+ if ((hit==2)&&(DEAD))
+ return; //no save when dead
+
+ if (hit<5) //there are 5 system menus
+ { for (j=0;j<5;j++) //build them all high in full colour - when on eis clicked on all the rest will grey out
+ if (j!=hit) //change all others to grey
+ {
+ icon = res_man.Res_open( icon_list[j] ) + sizeof(_standardHeader);
+ SetMenuIcon(RDMENU_TOP, j, icon);
+ res_man.Res_close( icon_list[j] );
+ }
+
+ //------------------------
+ rv = PauseFx();
+ if (rv != RD_OK)
+ Zdebug("ERROR: PauseFx() returned %.8x in SystemMenu()", rv);
+ //------------------------
+ // NB. Need to keep a safe copy of 'looping_music_id' for savegame
+ // & for playing when returning from control panels
+ // because control panel music will overwrite it!
+ safe_looping_music_id = looping_music_id;
+ pars[0] = 221; // SystemM234 (M234.wav)
+ pars[1] = FX_LOOP;
+ FN_play_music(pars);
+ looping_music_id = safe_looping_music_id; // restore proper looping_music_id
+ //------------------------
+ //------------------------
+ // clear the screen & set up the new palette for the menus
+
+ EraseBackBuffer();
+ ProcessMenu(); // drivers to redraw menu over this blank screen!
+ FlipScreens();
+ ResetRenderEngine();
+ //------------------------
+
+ switch(hit) //call the relevent screen
+ {
+ case 0: // options
+ Option_control(); // game options
+ break;
+
+ case 1: // quit
+ Quit_control(); // quit to windows
+ break;
+
+ case 2: // save
+ Save_control(); // save the game
+ break;
+
+ case 3: // restore
+ Restore_control(); // restore a game
+ break;
+
+ case 4: // restart
+ Restart_control(); // restart the game
+ break;
+
+ }
+ //------------------------
+// start the menu coming down
+ if (!DEAD) //not death screen
+ { mouse_mode=MOUSE_normal; //close menu
+ HideMenu(RDMENU_TOP); //but not when dead
+ }
+ else
+ { Set_mouse(NORMAL_MOUSE_ID);
+ Build_system_menu(); //reset top menu
+ }
+ //------------------------
+ // clear the screen & restore the location palette
+
+ EraseBackBuffer();
+ ProcessMenu(); // drivers to redraw menu over this blank screen!
+ FlipScreens();
+
+ //------------------------
+ // reset game palette, but not after a successful restore or restart!
+
+ if (this_screen.new_palette != 99) // see RestoreFromBuffer() in save_rest.cpp
+ {
+ SetFullPalette(0); // '0' means put back game screen palette; see Build_display.cpp (James17jun97)
+ this_screen.new_palette=0; //stop the engine fading in the restored screens palette
+ }
+ else
+ this_screen.new_palette=1;
+
+ //------------------------
+ rv = UnpauseFx();
+ if (rv != RD_OK)
+ Zdebug("ERROR: UnpauseFx() returned %.8x in SystemMenu()", rv);
+ //------------------------
+ // If there was looping music before coming into the control panels then restart it!
+ // NB. This will also start music required when a game has been restored
+
+ if (looping_music_id)
+ {
+ pars[0] = looping_music_id;
+ pars[1] = FX_LOOP;
+ FN_play_music(pars);
+ // cross-fades into the required music:
+ // - either a restored game tune
+ // - or music playing prior to entering control panels
+ }
+ else
+ FN_stop_music(NULL); // stop the control panel music
+ //------------------------
+ }
+ }
+ }
+
+}
+//------------------------------------------------------------------------------------
+void Drag_mouse(void) //Tony21Nov96
+{
+ _mouseEvent *me;
+ uint32 pos;
+// uint32 null_pc=1; //script 1 is combine script
+
+
+ if ((mousey<400)&&(!menu_status))
+ { mouse_mode=MOUSE_normal; //close menu
+
+// start the menu coming down
+ HideMenu(RDMENU_BOTTOM);
+
+ return;
+ }
+
+
+ Mouse_on_off(); //handles cursors and the luggage on/off according to type
+
+
+
+// now do the normal click stuff
+
+ me = MouseEvent(); //get mouse event
+
+
+// we only care about left clicks when the mouse is over an object
+// we ignore mouse releases
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) //there's a mouse event to be processed
+ {
+
+// could be clicking on an on screen object or on the top menu which is currently displayed
+
+ if (mouse_touching) //mouse is over an on screen object - and we have luggage
+ { //depending on type we'll maybe kill the object_held - like for exits
+ if (me->buttons&RD_LEFTBUTTONDOWN) // set global script variable 'button'
+ {
+ LEFT_BUTTON = 1;
+ RIGHT_BUTTON = 0;
+ }
+ else
+ {
+ LEFT_BUTTON = 0;
+ RIGHT_BUTTON = 1;
+ }
+
+ MOUSE_X=(uint32)mousex+this_screen.scroll_offset_x;
+ MOUSE_Y=(uint32)mousey+this_screen.scroll_offset_y; //these might be required by the action script about to be run
+
+ CLICKED_ID = mouse_touching; // for scripts to know what's been clicked (21jan97). First used for 'room_13_turning_script' in object 'biscuits_13'
+
+
+
+ Set_player_action_event(CUR_PLAYER_ID, mouse_touching); //Tony4Dec96
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"USED \"%s\" ICON ON %s", FetchObjectName(OBJECT_HELD), FetchObjectName(CLICKED_ID));
+ #endif
+ //--------------------------------------
+
+
+ HideMenu(RDMENU_BOTTOM); //hide menu too
+ mouse_mode=MOUSE_normal; //back to normal menu mode
+ }
+ else //better check for combine/cancel cancel puts us back in Top_menu_mouse mode
+ {
+ if ((mousex>=24)&&(mousex<640-24))
+ {
+ pos=(mousex-24)/40; //which are we over?
+
+ if (master_menu_list[pos].icon_resource) //clicked on something - what button?
+ {
+ mouse_mode=MOUSE_top; //always back into top menu mode
+
+ Set_luggage(0); // remove luggage
+
+ if (pos==menu_selected_pos) // if we've clicked on the same icon as the one we're dragging
+ {
+ OBJECT_HELD=0; // reset first icon
+ menu_selected_pos=0;
+ }
+ else // combine the 2 icons
+ {
+// Zdebug("combine");
+ COMBINE_BASE=master_menu_list[pos].icon_resource; //what we clicked on, not what we're dragging
+
+ Set_player_action_event(CUR_PLAYER_ID, MENU_MASTER_OBJECT); //Tony4Dec96
+
+ No_human(); // turn off mouse now, to prevent player trying to click elsewhere BUT leave the bottom menu open
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"USED \"%s\" ICON ON \"%s\" ICON", FetchObjectName(OBJECT_HELD), FetchObjectName(COMBINE_BASE));
+ #endif
+ //--------------------------------------
+ }
+
+ Build_top_menu(); // refresh the menu
+
+
+// Zdebug("switch to top mode");
+ }
+ }
+ }
+ }
+
+
+}
+//------------------------------------------------------------------------------------
+void Top_menu_mouse(void) //Tony3Oct96
+{
+//top menu is down
+ _mouseEvent *me;
+ uint32 pos;
+
+ if ((mousey<400)&&(!menu_status))
+ { mouse_mode=MOUSE_normal; //close menu
+
+// start the menu coming down
+ HideMenu(RDMENU_BOTTOM);
+
+ return;
+ }
+
+ me=MouseEvent(); //get mouse event
+
+
+
+// we only care about left clicks when the mouse is over an object
+// we ignore mouse releases
+
+ if (me!=NULL) //there's a mouse event to be processed
+ {
+// now check if we've clicked on an actual icon
+
+ if ((mousex>=24)&&(mousex<640-24))
+ {
+ pos=(mousex-24)/40; //which are we over?
+
+ if (master_menu_list[pos].icon_resource) //clicked on something - what button?
+ {
+
+ if (me->buttons&RD_RIGHTBUTTONDOWN) //right button look
+ {
+ examining_menu_icon=1;
+ OBJECT_HELD = master_menu_list[pos].icon_resource; //id the object via its graphic
+ EXIT_CLICK_ID=0; // (JEL09oct97) must clear this so next click on exit becomes 1st click again
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"RIGHT-CLICKED ON \"%s\" ICON", FetchObjectName(OBJECT_HELD));
+ #endif
+ //--------------------------------------
+
+ Set_player_action_event(CUR_PLAYER_ID, MENU_MASTER_OBJECT); //Tony4Dec96
+
+ Build_top_menu(); // refresh the menu
+ No_human(); // turn off mouse now, to prevent player trying to click elsewhere BUT leave the bottom menu open
+ }
+ else if (me->buttons&RD_LEFTBUTTONDOWN) //left button - highlight the object and bung us into drag luggage mode
+ {
+ menu_selected_pos=pos; //menu slot we clicked on - derive luggage resource from this in mouse_on_off()
+ current_luggage_resource=master_menu_list[pos].luggage_resource;
+
+ mouse_mode=MOUSE_drag;
+// Zdebug("setting OH in top menu");
+ OBJECT_HELD = master_menu_list[pos].icon_resource; //id the object via its graphic
+ EXIT_CLICK_ID=0; // (JEL09oct97) must clear this so next click on exit becomes 1st click again
+
+ Build_top_menu(); // refresh the menu
+
+ Set_luggage(master_menu_list[pos].luggage_resource);
+
+// Zdebug("switch to drag mode");
+ }
+ }
+ }
+ }
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+void Normal_mouse(void) //Tony30Sept96
+{
+//the gane is playing and none of the menus are activated - but, we need to check if the top menu is to start
+//note, wont have luggage
+
+ _mouseEvent *me;
+
+
+
+
+ if ((mousey<0)&&(!menu_status)&&(!mouse_mode_locked)&&(!OBJECT_HELD)) //no save in big-object menu lock situation
+ {
+ mouse_mode=MOUSE_system_menu;
+
+ if (mouse_touching)
+ {
+// get off
+ old_mouse_touching=0; //we've moved off
+ mouse_touching=0; //we were on something but not anymore
+
+ }
+
+// reset mouse cursor - in case we're between mice
+ Set_mouse(NORMAL_MOUSE_ID);
+
+ Build_system_menu(); //Tony19Mar97
+ }
+
+
+
+
+
+ if ((mousey>399)&&(!menu_status)&&(!mouse_mode_locked))
+ {
+
+
+ if (!OBJECT_HELD) //why are we testing for this?
+ {
+ mouse_mode=MOUSE_top; //bring down top menu
+ }
+ else
+ {
+ mouse_mode=MOUSE_drag;
+ }
+
+// if mouse is moving off an object and onto the top menu then do a standard get-off
+ if (mouse_touching)
+ {
+// get off
+
+ old_mouse_touching=0; //we've moved off
+ mouse_touching=0; //we were on something but not anymore
+
+ }
+
+// reset mouse cursor
+ Set_mouse(NORMAL_MOUSE_ID);
+
+// build menu and start the menu coming down
+
+ Build_top_menu();
+
+ return;
+ }
+
+
+//check also for bringing the bottom menu up
+
+
+
+
+ Mouse_on_off(); //handles
+
+
+
+// now do the normal click stuff
+
+ me = MouseEvent(); //get mouse event
+
+ //-----------------------------------------------------
+#ifdef _DEBUG
+ if (definingRectangles)
+ {
+ if (draggingRectangle==0) // not yet dragging a rectangle, so need click to start
+ {
+ if ( (me!=NULL) && ((me->buttons&RD_LEFTBUTTONDOWN)||(me->buttons&RD_RIGHTBUTTONDOWN)) )
+ {
+ rect_x1 = rect_x2 = (uint32)mousex+this_screen.scroll_offset_x; // set both (x1,y1)
+ rect_y1 = rect_y2 = (uint32)mousey+this_screen.scroll_offset_y; // & (x2,y2) to this point
+ draggingRectangle=1;
+ }
+ }
+ else if (draggingRectangle==1) // currently dragging a rectangle
+ {
+ if ( (me!=NULL) && ((me->buttons&RD_LEFTBUTTONDOWN)||(me->buttons&RD_RIGHTBUTTONDOWN)) ) // click means reset
+ {
+ draggingRectangle=2; // lock rectangle, so you can let go of mouse to type in the coords
+ }
+ else // drag rectangle
+ {
+ rect_x2 = (uint32)mousex+this_screen.scroll_offset_x;
+ rect_y2 = (uint32)mousey+this_screen.scroll_offset_y;
+ }
+ }
+ else // currently locked to avoid knocking out of place while reading off the coords
+ {
+ if ( (me!=NULL) && ((me->buttons&RD_LEFTBUTTONDOWN)||(me->buttons&RD_RIGHTBUTTONDOWN)) ) // click means reset
+ {
+ draggingRectangle=0; // back to start again
+ }
+ }
+ }
+ else
+#endif // _DEBUG
+ //-----------------------------------------------------
+ {
+
+ // we only care about down clicks when the mouse is over an object
+ // we ignore mouse releases
+
+ if ((me!=NULL)&&((me->buttons&RD_LEFTBUTTONDOWN)||(me->buttons&RD_RIGHTBUTTONDOWN))&&(mouse_touching)) //there's a mouse event to be processed and the mouse is on something
+ {
+// ok, there are no menus about so its nice and simple
+// this is as close to the old advisor_188 script as we get I'm sorry to say.
+
+
+// if player is walking or relaxing then those need to terminate correctly
+
+
+// otherwise set player run the targets action script
+// or, do a special walk if clicking on the scroll-more icon
+
+// PLAYER_ACTION = mouse_touching; //PLAYER_ACTION script variable - whatever catches this must reset to 0 again
+ //idle or router-anim will catch it
+
+
+ if (me->buttons&RD_LEFTBUTTONDOWN) // set global script variable 'button'
+ {
+ LEFT_BUTTON = 1;
+ RIGHT_BUTTON = 0;
+ button_click=0; //for re-click
+ }
+ else
+ {
+ LEFT_BUTTON = 0;
+ RIGHT_BUTTON = 1;
+ button_click=1; //for re-click
+ }
+
+ MOUSE_X=(uint32)mousex+this_screen.scroll_offset_x;
+ MOUSE_Y=(uint32)mousey+this_screen.scroll_offset_y; //these might be required by the action script about to be run
+
+
+ if ((mouse_touching==EXIT_CLICK_ID)&&(me->buttons&RD_LEFTBUTTONDOWN)) //only left button
+ {
+// its the exit double click situation
+// let the existing interaction continue and start fading down - switch the human off too
+
+ FN_no_human(NULL);
+ FN_fade_down(NULL);
+ EXIT_FADING=1; //tell the walker
+
+ }
+ else if ((old_button==button_click)&&(mouse_touching==CLICKED_ID)&&(mouse_pointer_res!=NORMAL_MOUSE_ID))
+ { //re-click - do nothing - except on floors
+ }
+ else //allow the click
+ {
+ old_button=button_click; //for re-click
+
+ CLICKED_ID = mouse_touching; // for scripts to know what's been clicked (21jan97). First used for 'room_13_turning_script' in object 'biscuits_13'
+ EXIT_CLICK_ID=0; //must clear these two double-click control flags - do it here so reclicks after exit clicks are cleared up
+ EXIT_FADING=0;
+ Set_player_action_event(CUR_PLAYER_ID, mouse_touching); //Tony4Dec96
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ if (OBJECT_HELD)
+ Zdebug(0,"USED \"%s\" ICON ON %s", FetchObjectName(OBJECT_HELD), FetchObjectName(CLICKED_ID));
+ else if (LEFT_BUTTON)
+ Zdebug(0,"LEFT-CLICKED ON %s", FetchObjectName(CLICKED_ID));
+ else // RIGHT BUTTON
+ Zdebug(0,"RIGHT-CLICKED ON %s", FetchObjectName(CLICKED_ID));
+ #endif
+ //--------------------------------------
+ }
+ }
+ }
+}
+//------------------------------------------------------------------------------------
+void Mouse_on_off(void) //Tony30Sept96
+{
+ //this handles the cursor graphic when moving on and off mouse areas
+ //it also handles the luggage thingy
+
+ uint32 pointer_type;
+ static uint8 mouse_flicked_off=0;
+
+
+ old_mouse_touching=mouse_touching;
+
+
+ if ((mousey<0)||(mousey>399)) // don't detect objects that are hidden behind the menu bars (ie. in the scrolled-off areas of the screen)
+ {
+ pointer_type=0;
+ mouse_touching=0;
+ }
+ else
+ pointer_type = Check_mouse_list(); // set 'mouse_touching' & return pointer_type
+
+
+
+
+ if ((!mouse_flicked_off)&&(old_mouse_touching==mouse_touching)) //same as previous cycle?
+ return; //yes, so nothing to do BUT CARRY ON IF MOUSE WAS FLICKED OFF!
+
+ mouse_flicked_off=0; // can reset this now
+
+
+ if ((!old_mouse_touching)&&(mouse_touching)) //the cursor has moved onto something
+ {
+
+// make a copy of the object we've moved onto
+// because one day we'll move back off again! (but the list positioning could theoretically have changed)
+// we can only move onto something from being on nothing - we stop the system going from one to another when objects overlap
+
+// memcpy( &old_mouse_object, &mouse_list[mouse_touching], sizeof(Object_mouse));
+
+ old_mouse_touching=mouse_touching; //
+
+// run get on
+
+ if (pointer_type)
+ {
+ Set_mouse(pointer_type); // 'pointer_type' holds the resource id of the pointer anim
+
+ if (OBJECT_HELD) // setup luggage icon
+// Set_luggage(master_menu_list[menu_selected_pos].luggage_resource);
+ Set_luggage(current_luggage_resource);
+
+ }
+ else
+ Con_fatal_error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", mouse_touching, FetchObjectName(mouse_touching));
+ }
+ else if ((old_mouse_touching)&&(!mouse_touching)) // the cursor has moved off something
+ {
+ old_mouse_touching=0; // we've moved off
+ Set_mouse(NORMAL_MOUSE_ID); // reset cursor to normal pointer
+ // reset luggage only when necessary
+ }
+ else if ((old_mouse_touching)&&(mouse_touching)) // the cursor has moved off something and onto something else
+ { // flip to a blank cursor for a cycle
+ mouse_touching=0; // ignore the new id this cycle - should hit next cycle
+ old_mouse_touching=0; // we've moved off
+ Set_mouse(NULL); // blank cursor
+ mouse_flicked_off=1; // so we know to set the mouse pointer back to normal if 2nd hot-spot doesn't register because mouse pulled away quickly (onto nothing)
+
+ // reset luggage only when necessary
+ }
+ else // for when mouse was flicked off for one cycle, but then moved onot nothing before 2nd hot-spot registered
+ {
+ // both 'old_mouse_touching' & 'mouse_touching' will be zero
+ Set_mouse(NORMAL_MOUSE_ID); // reset cursor to normal pointer
+ }
+
+ // possible check for edge of screen more-to-scroll here on large screens
+
+}
+//------------------------------------------------------------------------------------
+void Set_mouse(uint32 res) // (4dec96 JEL)
+{
+ uint8 *icon;
+ uint32 len;
+
+ mouse_pointer_res=res; //high level - whats the mouse - for the engine
+
+ if (res) // if it's not NULL
+ {
+ icon = res_man.Res_open( res ) + sizeof(_standardHeader);
+ len = res_man.resList[res]->size - sizeof(_standardHeader);
+
+ if (res == NORMAL_MOUSE_ID) // don't pulse the normal pointer
+ SetMouseAnim(icon, len, RDMOUSE_NOFLASH); // 0 means don't pulse this pointer, just do the regular anim loop
+ else
+ SetMouseAnim(icon, len, RDMOUSE_FLASH); // 1 mean pulse before starting regular anim loop
+
+ res_man.Res_close( res );
+ }
+ else
+ SetMouseAnim(NULL,0,0); // blank cursor
+}
+//------------------------------------------------------------------------------------
+void Set_luggage(uint32 res) //Tony26Nov96
+{
+ uint8 *icon;
+ uint32 len;
+
+ if (res) // if not NULL
+ {
+ real_luggage_item=res;
+
+ icon = res_man.Res_open( res ) + sizeof(_standardHeader);
+ len = res_man.resList[res]->size - sizeof(_standardHeader);
+
+ SetLuggageAnim(icon, len);
+
+ res_man.Res_close( res );
+ }
+ else
+ { real_luggage_item=0;
+ SetLuggageAnim(NULL, 0);
+ }
+}
+//------------------------------------------------------------------------------------
+uint32 Check_mouse_list(void) //Tony30Sept96
+{
+ int32 priority=0;
+ uint32 j=1;
+
+
+ if (cur_mouse>1)
+ {
+ while(priority<10) //number of priorities subject to implementation needs
+ {
+ if ((mouse_list[j].priority==priority) && // if the mouse pointer is over this mouse-detection-box
+ (mousex+this_screen.scroll_offset_x >= mouse_list[j].x1) &&
+ (mousex+this_screen.scroll_offset_x <= mouse_list[j].x2) &&
+ (mousey+this_screen.scroll_offset_y >= mouse_list[j].y1) &&
+ (mousey+this_screen.scroll_offset_y <= mouse_list[j].y2))
+ {
+
+/*
+ if (mouse_list[j].anim_resource) // want to use sprite as a mouse mask, for better accuracy of detection (25oct96 JEL)
+ {
+ // only works for uncompressed sprite data!!
+ // THIS IS NEVER USED IN SWORD2
+
+ if (Check_sprite_pixel(j)) // if the mouse is touching a non-zero pixel of the sprite
+ {
+ mouse_touching=mouse_list[j].id; // record id
+ CreatePointerText(mouse_list[j].pointer_text); // James16jun97
+ return(mouse_list[j].pointer); //return pointer type
+ }
+ }
+ else // ok, we're touching the detection-box
+*/
+ {
+ mouse_touching=mouse_list[j].id; // record id
+
+ // change all COGS pointers to CROSHAIR
+ if (mouse_list[j].pointer == USE)
+ mouse_list[j].pointer = CROSHAIR;
+ CreatePointerText(mouse_list[j].pointer_text, mouse_list[j].pointer); // James16jun97
+ return(mouse_list[j].pointer); //return pointer type
+ }
+ }
+
+ j++; //next
+ if (j==cur_mouse)
+ {
+ j=0;
+ priority++; //next priority - 0 being the highest, 9 the lowest
+ }
+ }
+ }
+
+ mouse_touching=0; // touching nothing
+ return(0); // no pointer to return
+}
+//------------------------------------------------------------------------------------
+
+void CreatePointerText(uint32 textId, uint32 pointerRes) // James16jun97
+{
+ uint32 local_text;
+ uint32 text_res;
+ uint8 *text;
+ int16 xOffset, yOffset; // offsets for pointer text sprite from pointer position
+ uint8 justification;
+
+ #define POINTER_TEXT_WIDTH 640 // just in case!
+ #define POINTER_TEXT_PEN 184 // white
+
+ if (pointerTextSelected)
+ {
+ if (textId)
+ {
+ //-------------------------------------------
+ // check what the pointer is, to set offsets correctly for text position
+
+ switch(pointerRes)
+ {
+ case CROSHAIR:
+ yOffset = -7; // above (above & to the right of the pointer coordinate)
+ xOffset = +10; // right
+ break;
+
+ case EXIT0:
+ yOffset = +15; // below
+ xOffset = +20; // right
+ break;
+
+ case EXIT1:
+ yOffset = +16; // below
+ xOffset = -10; // left
+ break;
+
+ case EXIT2:
+ yOffset = +10; // below
+ xOffset = -22; // left
+ break;
+
+ case EXIT3:
+ yOffset = -16; // above
+ xOffset = -10; // left
+ break;
+
+ case EXIT4:
+ yOffset = -15; // above
+ xOffset = +15; // right
+ break;
+
+ case EXIT5:
+ yOffset = -12; // above
+ xOffset = +10; // right
+ break;
+
+ case EXIT6:
+ yOffset = +10; // below
+ xOffset = +25; // right
+ break;
+
+ case EXIT7:
+ yOffset = +16; // below
+ xOffset = +20; // right
+ break;
+
+ case EXITDOWN:
+ yOffset = -20; // above
+ xOffset = -10; // left
+ break;
+
+ case EXITUP:
+ yOffset = +20; // below
+ xOffset = +20; // right
+ break;
+
+ case MOUTH:
+ yOffset = -10; // above
+ xOffset = +15; // right
+ break;
+
+ case NORMAL:
+ yOffset = -10; // above
+ xOffset = +15; // right
+ break;
+
+ case PICKUP:
+ yOffset = -40; // above
+ xOffset = +10; // right
+ break;
+
+ case SCROLL_L:
+ yOffset = -20; // above
+ xOffset = +20; // right
+ break;
+
+ case SCROLL_R:
+ yOffset = -20; // above
+ xOffset = -20; // left
+ break;
+
+ case USE:
+ yOffset = -8; // above
+ xOffset = +20; // right
+ break;
+
+ default: // shouldn't happen if we cover all the different mouse pointers above
+ yOffset = -10; // above
+ xOffset = +10; // right
+ }
+
+ //-------------------------------------------
+ // set up justification for text sprite,
+ // based on it's offsets from the pointer position
+
+ // from maketext.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
+
+ //-----------------------------------------
+ if (yOffset < 0) // if above pointer
+ {
+ if (xOffset < 0) // above left
+ {
+ justification = POSITION_AT_RIGHT_OF_BASE;
+ }
+ else if (xOffset > 0) // above right
+ {
+ justification = POSITION_AT_LEFT_OF_BASE; // text sprite is justified from it's bottom-left corner
+ }
+ else // (xOffset==0) // above centre
+ {
+ justification = POSITION_AT_CENTRE_OF_BASE;
+ }
+ }
+ //-----------------------------------------
+ else if (yOffset > 0) // if below pointer
+ {
+ if (xOffset < 0) // below left
+ {
+ justification = POSITION_AT_RIGHT_OF_TOP;
+ }
+ else if (xOffset > 0) // below right
+ {
+ justification = POSITION_AT_LEFT_OF_TOP;
+ }
+ else // (xOffset==0) // below centre
+ {
+ justification = POSITION_AT_CENTRE_OF_TOP;
+ }
+ }
+ //-----------------------------------------
+ else // if at same y-coord as pointer
+ {
+ if (xOffset < 0) // centre left
+ {
+ justification = POSITION_AT_RIGHT_OF_CENTRE;
+ }
+ else if (xOffset > 0) // centre right
+ {
+ justification = POSITION_AT_LEFT_OF_CENTRE;
+ }
+ else // (xOffset==0) // centre centre
+ {
+ justification = POSITION_AT_LEFT_OF_CENTRE; // shouldn't happen anyway!
+ }
+ }
+ //-------------------------------------------
+
+ text_res = textId/SIZE; // text resource number
+ local_text = textId&0xffff; // text line number within the resource
+
+ text = FetchTextLine( res_man.Res_open(text_res), local_text ); // open text file & get the line
+
+ // 'text+2' to skip the first 2 bytes which form the line reference number
+ pointer_text_bloc_no = Build_new_block(text+2, mousex+xOffset, mousey+yOffset, POINTER_TEXT_WIDTH, POINTER_TEXT_PEN, RDSPR_TRANS+RDSPR_DISPLAYALIGN, speech_font_id, justification);
+
+ res_man.Res_close(text_res); // now ok to close the text file
+ }
+ }
+}
+//------------------------------------------------------------------------------------
+void ClearPointerText(void) // James16jun97
+{
+ if (pointer_text_bloc_no)
+ {
+ Kill_text_bloc(pointer_text_bloc_no);
+ pointer_text_bloc_no=0;
+ }
+}
+//------------------------------------------------------------------------------------
+/* NOT USED IN SWORD2
+uint8 Check_sprite_pixel( uint32 j ) // (25oct96 JEL)
+{
+ // only works for uncompressed sprite data!!
+
+ uint8 *file;
+ uint8 hit;
+ _frameHeader *frame_head;
+ int16 sprite_x, sprite_y;
+ int16 in_sprite_x, in_sprite_y;
+ uint8 *sprite_data;
+
+
+ sprite_x = mouse_list[j].x1; // sprite coords have been copied to mouse area coords by FN_register_X_frame (X = sort, back or fore)
+ sprite_y = mouse_list[j].y1; // so easier to get them from there than from the anim file again
+
+
+ file = res_man.Res_open(mouse_list[j].anim_resource); // open the anim file & point to start of it
+ frame_head = FetchFrameHeader(file,mouse_list[j].anim_pc); // point to frame header of current frame
+ sprite_data = (uint8 *)(frame_head + 1); // point to start of frame data
+
+ in_sprite_x = mousex + this_screen.scroll_offset_x - sprite_x; // x-coord of mouse from origin at top-left of sprite
+ in_sprite_y = mousey + this_screen.scroll_offset_y - sprite_y; // y-coord of mouse from origin at top-left of sprite
+
+ hit = sprite_data[in_sprite_y * frame_head->width + in_sprite_x]; // hit = value of pixel to which the mouse is pointing
+
+ res_man.Res_close(mouse_list[j].anim_resource); // close anim file
+
+ return (hit); // we are touching the sprite if 'hit' is non-zero
+}
+*/
+//------------------------------------------------------------------------------------
+int32 FN_no_human(int32 *params) //Tony30Sept96
+{
+//param none
+
+ MOUSE_AVAILABLE = 0; // for logic scripts (James21may97)
+
+ ClearPointerText();
+
+ mouse_status=1; //human/mouse off
+
+ Set_mouse(NULL); // blank cursor
+ Set_luggage(NULL); // blank cursor
+
+
+//must be normal mouse situation or a largely neutral situation - special menus use No_human
+ if (TALK_FLAG==0) //dont hide menu in conversations
+ HideMenu(RDMENU_BOTTOM);
+
+
+ if (mouse_mode==MOUSE_system_menu)
+ {
+ mouse_mode=MOUSE_normal; //close menu
+ HideMenu(RDMENU_TOP); // start the menu coming down
+ }
+
+
+ if (params);
+
+
+ return(1); //script continue
+}
+//------------------------------------------------------------------------------------
+void No_human(void) //Tony4June97
+{
+//leaves the menus open
+//used by the system when clicking right on a menu item to examine it and
+//when combining objects
+
+ MOUSE_AVAILABLE = 0; // for logic scripts (James21may97)
+
+ mouse_status=1; //human/mouse off
+
+ Set_mouse(NULL); // blank cursor
+ Set_luggage(NULL); // blank cursor
+}
+//------------------------------------------------------------------------------------
+int32 FN_add_human(int32 *params) //Tony30Sept96
+{
+ //param none
+#ifdef _DEBUG
+ uint8 black[4] = {0,0,0,0};
+ uint8 white[4] = {255,255,255,0};
+#endif // ('0' means don't print to console, but console isn't up anyway)
+
+
+
+ MOUSE_AVAILABLE = 1; // for logic scripts (James21may97)
+
+
+ if (mouse_status) //off
+ {
+ mouse_status=0; //on
+ mouse_touching=1; //forces engine to choose a cursor
+ }
+
+ CLICKED_ID=0; //clear this to reset no-second-click system
+
+ // this is now done outside the OBJECT_HELD check in case it's set to zero before now! (James 10july97)
+ mouse_mode_locked=0; //unlock the mouse from possible large object lock situtations - see syphon in rm 3
+
+ if (OBJECT_HELD) //was dragging something around
+ {
+ OBJECT_HELD=0; // need to clear this again
+
+ examining_menu_icon=0; // and these may also need clearing
+ COMBINE_BASE=0; // - just in case
+
+
+ Set_luggage(NULL); // blank cursor
+ }
+
+
+
+ if ((mousey>399)&&(mouse_mode!=MOUSE_holding)) // if mouse is over menu area
+ {
+ mouse_mode=MOUSE_normal; // VITAL - reset things & rebuild the menu
+ Set_mouse(NORMAL_MOUSE_ID);
+ }
+ else if (mousey>399)
+ Set_mouse(NORMAL_MOUSE_ID);
+
+
+ //----------------------------------------------------------------------------------------------
+ // enabled/disabled from console; status printed with on-screen debug info
+#ifdef _DEBUG
+ if (testingSnR) // testing logic scripts by simulating an instant Save & Restore
+ {
+ SetPalette(0, 1, white, RDPAL_INSTANT);
+
+ Clear_fx_queue(); // stops all fx & clears the queue - eg. when leaving a location
+ res_man.Kill_all_objects(0); // ie. trashing all object resources so they load in fresh & restart their logic scripts
+
+ SetPalette(0, 1, black, RDPAL_INSTANT);
+ }
+#endif // ('0' means don't print to console, but console isn't up anyway)
+ //----------------------------------------------------------------------------------------------
+ if (params);
+
+ return(1); //script continue
+}
+//------------------------------------------------------------------------------------
+int32 FN_register_mouse(int32 *params) //Tony29Oct96
+{
+//this call would be made from an objects service script 0
+//the object would be one with no graphic but with a mouse - i.e. a floor
+// or one whose mouse area is manually defined rather than intended to fit sprite shape
+
+//param 0 pointer to Object_mouse or 0 for no write to mouse list
+
+// Zdebug(1,"cur_mouse = %d", cur_mouse);
+
+
+ Object_mouse *ob_mouse;
+
+ ob_mouse = (Object_mouse *) params[0]; // param 1 is pointer to mouse structure
+
+ if (ob_mouse->pointer) // only if 'pointer' isn't NULL
+ {
+ #ifdef _DEBUG
+ if (cur_mouse==TOTAL_mouse_list)
+ Con_fatal_error("ERROR: mouse_list full [%s line %u]",__FILE__,__LINE__);
+ #endif
+
+ mouse_list[cur_mouse].x1 = ob_mouse->x1;
+ mouse_list[cur_mouse].y1 = ob_mouse->y1;
+ mouse_list[cur_mouse].x2 = ob_mouse->x2;
+ mouse_list[cur_mouse].y2 = ob_mouse->y2;
+
+ mouse_list[cur_mouse].priority = ob_mouse->priority;
+ mouse_list[cur_mouse].pointer = ob_mouse->pointer;
+
+ //-----------------------------------------------
+ // (James17jun97)
+ // check if pointer text field is set due to previous object using this slot (ie. not correct for this one)
+ if ((mouse_list[cur_mouse].pointer_text) && (mouse_list[cur_mouse].id != (int32)ID)) // if 'pointer_text' field is set, but the 'id' field isn't same is current id
+ mouse_list[cur_mouse].pointer_text=0; // then we don't want this "left over" pointer text
+ //-----------------------------------------------
+
+ mouse_list[cur_mouse].id = ID; // get id from system variable 'id' which is correct for current object
+
+ mouse_list[cur_mouse].anim_resource = 0; // not using sprite as mask - this is only done from FN_register_frame()
+ mouse_list[cur_mouse].anim_pc = 0;
+
+ //Zdebug("mouse id %d", mouse_list[cur_mouse].id);
+
+ cur_mouse++;
+ }
+
+ return(IR_CONT); // continue script
+}
+//------------------------------------------------------------------------------------
+// use this in the object's service script prior to registering the mouse area
+// ie. before FN_register_mouse or FN_register_frame
+// - best if kept at very top of service script
+
+int32 FN_register_pointer_text(int32 *params) // James16jun97
+{
+// param 0 local id of text line to use as pointer text
+
+ #ifdef _DEBUG
+ if (cur_mouse==TOTAL_mouse_list)
+ Con_fatal_error("ERROR: mouse_list full [%s line %u]",__FILE__,__LINE__);
+ #endif
+
+ mouse_list[cur_mouse].id = ID; // current object id - used for checking pointer_text when mouse area registered (in FN_register_mouse & FN_register_frame)
+ mouse_list[cur_mouse].pointer_text = params[0];
+
+ return(IR_CONT); // continue script
+
+}
+//------------------------------------------------------------------------------------
+int32 FN_blank_mouse(int32 *params) //Tony29Oct96
+{
+//set mouse to normal pointer - used in speech
+
+//no params
+
+
+ Set_mouse(NULL);
+
+ if (params);
+
+ return(1); //cont
+}
+//------------------------------------------------------------------------------------
+int32 FN_init_floor_mouse(int32 *params) // James29nov96
+{
+ // params 0 pointer to object's mouse structure
+
+ Object_mouse *ob_mouse = (Object_mouse *) params[0];
+
+ ob_mouse->x1 = 0;
+ ob_mouse->y1 = 0;
+ ob_mouse->x2 = this_screen.screen_wide-1;
+ ob_mouse->y2 = this_screen.screen_deep-1;
+ ob_mouse->priority = 9; // floor is always lowest priority
+ ob_mouse->pointer = NORMAL_MOUSE_ID; // normal pointer
+
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------------------------------
+#define SCROLL_MOUSE_WIDTH 20 // James13feb97 (updated by James 25mar97)
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_set_scroll_left_mouse(int32 *params) // James13feb97
+{
+ // params 0 pointer to object's mouse structure
+
+ Object_mouse *ob_mouse = (Object_mouse *) params[0];
+
+
+ ob_mouse->x1 = 0;
+ ob_mouse->y1 = 0;
+ ob_mouse->x2 = this_screen.scroll_offset_x + SCROLL_MOUSE_WIDTH;
+ ob_mouse->y2 = this_screen.screen_deep-1;
+ ob_mouse->priority = 0; // highest priority
+
+ if (this_screen.scroll_offset_x > 0) // if not fully scrolled to the left
+ ob_mouse->pointer = SCROLL_LEFT_MOUSE_ID;
+ else
+ ob_mouse->pointer = 0; // so the mouse area doesn't get registered
+
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_set_scroll_right_mouse(int32 *params) // James13feb97
+{
+ // params 0 pointer to object's mouse structure
+
+ Object_mouse *ob_mouse = (Object_mouse *) params[0];
+
+
+ ob_mouse->x1 = this_screen.scroll_offset_x + screenWide - SCROLL_MOUSE_WIDTH;
+ ob_mouse->y1 = 0;
+ ob_mouse->x2 = this_screen.screen_wide-1;
+ ob_mouse->y2 = this_screen.screen_deep-1;
+ ob_mouse->priority = 0; // highest priority
+
+ if (this_screen.scroll_offset_x < this_screen.max_scroll_offset_x) // if not fully scrolled to the right
+ ob_mouse->pointer = SCROLL_RIGHT_MOUSE_ID;
+ else
+ ob_mouse->pointer = 0; // so the mouse area doesn't get registered
+
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_set_object_held(int32 *params) //tony19May97
+{
+//params 0 luggage icon to set
+
+ Set_luggage(params[0]);
+
+ OBJECT_HELD=params[0];
+ current_luggage_resource=params[0];
+
+ mouse_mode_locked=1; //mode locked - no top menu available
+
+
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+// called from speech scripts to remove the chooser bar when it's not appropriate to keep it displayed
+int32 FN_remove_chooser(int32 *params) // James13aug97
+{
+ HideMenu(RDMENU_BOTTOM);
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_disable_menu(int32 *params) //Tony1Oct96
+{
+ mouse_mode_locked=1; //mode locked - no top menu available
+ mouse_mode=MOUSE_normal;
+
+ HideMenu(RDMENU_TOP);
+ HideMenu(RDMENU_BOTTOM);
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_enable_menu(int32 *params) //tony4June97
+{
+
+
+ mouse_mode_locked=0; //mode locked - no top menu available
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_check_player_activity(int32 *params) // James23july97
+{
+// Used to decide when to trigger music cues described as "no player activity for a while"
+
+// params 0 threshold delay in seconds, ie. what we want to check the actual delay against
+
+ uint32 threshold = params[0]*12; // in game cycles
+
+ if (player_activity_delay >= threshold) // if the actual delay is at or above the given threshold
+ {
+ player_activity_delay=0; // reset activity delay counter, now that we've got a positive check
+ RESULT=1;
+ }
+ else
+ RESULT=0;
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_reset_player_activity_delay(int32 *params) // James23july97
+{
+// Use if you want to deliberately reset the "no player activity" counter for any reason
+
+// no params
+
+ player_activity_delay=0; // reset activity delay counter
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+void Monitor_player_activity(void) // James23july97
+{
+ if (CheckForMouseEvents()) // if there is at least one mouse event outstanding
+ player_activity_delay=0; // reset activity delay counter
+ else
+ player_activity_delay++; // no. of game cycles since mouse event queue last empty
+}
+//---------------------------------------------------------------------------------------------------------------------
+
diff --git a/sword2/mouse.h b/sword2/mouse.h
new file mode 100644
index 0000000000..3845818875
--- /dev/null
+++ b/sword2/mouse.h
@@ -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
diff --git a/sword2/object.h b/sword2/object.h
new file mode 100644
index 0000000000..b5e5763c77
--- /dev/null
+++ b/sword2/object.h
@@ -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
diff --git a/sword2/protocol.cpp b/sword2/protocol.cpp
new file mode 100644
index 0000000000..bfeb804dfe
--- /dev/null
+++ b/sword2/protocol.cpp
@@ -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!
+}
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
diff --git a/sword2/protocol.h b/sword2/protocol.h
new file mode 100644
index 0000000000..97751f0881
--- /dev/null
+++ b/sword2/protocol.h
@@ -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
diff --git a/sword2/resman.cpp b/sword2/resman.cpp
new file mode 100644
index 0000000000..37afab5a4d
--- /dev/null
+++ b/sword2/resman.cpp
@@ -0,0 +1,1539 @@
+/* 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 <process.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "engine.h"
+
+#include "driver/driver96.h"
+#include "build_display.h"
+#include "console.h"
+#include "debug.h"
+#include "defs.h"
+#include "function.h"
+#include "header.h"
+#include "interpreter.h"
+#include "maketext.h"
+#include "memory.h"
+#include "mouse.h" // for system Set_mouse & Set_luggage routines
+#include "protocol.h"
+#include "resman.h"
+#include "sound.h" // (James22july97) for Clear_fx_queue() called from CacheNewCluster()
+#include "sword2.h" // (James11aug97) for CloseGame()
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//welcome to the easy resource manager - written in simple code for easy maintenance
+
+//the resource compiler will create two files
+
+// resource.inf which is a list of ascii cluster file names
+// resource.tab which is a table which tells us which cluster a resource is located in and the number within the cluster
+
+
+//------------------------------------------------------------------------------------
+
+#define NONE 0
+#define FETCHING 1
+
+#define BUFFERSIZE 4096
+
+
+resMan res_man; //declare the object global
+
+
+//------------------------------------------------------------------------------------
+//
+//
+// resman.
+//
+//
+//------------------------------------------------------------------------------------
+#define BOTH 0x0 // Cluster is on both CDs
+#define CD1 0x1 // Cluster is on CD1 only
+#define CD2 0x2 // Cluster is on CD2 only
+#define LOCAL_CACHE 0x4 // Cluster is cached on HDD
+#define LOCAL_PERM 0x8 // Cluster is on HDD.
+
+
+typedef struct
+{
+ uint8 clusterName[20]; // Null terminated cluster name.
+ uint8 cd; // Cd cluster is on and whether it is on the local drive or not.
+} _cd_inf;
+
+//------------------------------------------------------------------------------------
+
+void resMan::InitResMan(void) //Tony29May96
+{
+//we read in the resource info which tells us the names of the resource cluster files
+//ultimately, although there might be groups within the clusters at this point it makes no difference.
+//we only wish to know what resource files there are and what is in each
+
+ File file;
+ uint32 end;
+ mem *temp;
+ uint32 pos=0;
+ uint32 j=0;
+
+
+ total_clusters=0;
+
+
+ if (file.open("resource.inf", g_bs2->getGameDataPath()) == false) {
+ Zdebug("InitResMan cannot *OPEN* resource.inf");
+ ExitWithReport("InitResMan cannot *OPEN* resource.inf [file=%s line=%u]",__FILE__,__LINE__);
+ }
+
+ end = file.size();
+
+// Zdebug("seek end %d %d", fh, end);
+
+ temp = Twalloc(end, MEM_locked, UID_temp); //get some space for the incoming resource file - soon to be trashed
+
+ file.seek(0, SEEK_SET );
+ if (file.read( temp->ad, end )==-1)
+ {
+ file.close();
+ Zdebug("InitResMan cannot *READ* resource.inf");
+ ExitWithReport("InitResMan cannot *READ* resource.inf [file=%s line=%u]",__FILE__,__LINE__);
+ }
+
+ file.close();
+
+
+//ok, we've loaded in the resource.inf file which contains a list of all the files
+//now extract the filenames
+ do
+ {
+ while(*(temp->ad+j)!=13) //item must have an #0d0a
+ { resource_files[total_clusters][pos]=*(temp->ad+j);
+ j++;
+ pos++;
+ };
+
+ resource_files[total_clusters][pos]=0; //NULL terminate our extracted string
+
+ pos=0; //reset position in current slot between entries
+ j+=2; //past the 0a
+ total_clusters++; //done another
+
+// put overload check here
+
+
+ }
+ while(j!=end); //using this method the Gode generated resource.inf must have #0d0a on the last entry
+
+
+
+
+
+//now load in the binary id to res conversion table
+ if (file.open("resource.tab", g_bs2->getGameDataPath()) == false) {
+ Zdebug("InitResMan cannot *OPEN* resource.tab");
+ ExitWithReport("InitResMan cannot *OPEN* resource.tab [file=%s line=%u]",__FILE__,__LINE__);
+ }
+
+
+//find how many resources
+ end = file.size();
+ file.seek( 0, SEEK_SET); // Back to the beginning of the file
+
+ total_res_files=end/4;
+
+//table seems ok so malloc some space
+ res_conv_table = (uint16 *) malloc( end );
+
+ if (file.read( res_conv_table, end )==-1)
+ {
+ file.close();
+ Zdebug("InitResMan cannot *READ* resource.tab");
+ ExitWithReport("InitResMan cannot *READ* resource.tab [file=%s line=%u]",__FILE__,__LINE__);
+ }
+ file.close();
+
+
+ if (file.open("cd.inf", g_bs2->getGameDataPath()) == false) {
+ Zdebug("InitResMan cannot *OPEN* cd.inf");
+ ExitWithReport("InitResMan cannot *OPEN* cd.inf [file=%s line=%u]",__FILE__,__LINE__);
+ }
+
+
+ _cd_inf *cdInf = new _cd_inf[total_clusters];
+
+ for (j=0;j<total_clusters;j++)
+ {
+ if (file.read(&cdInf[j], sizeof(_cd_inf)) != sizeof(_cd_inf))
+ {
+ Zdebug("InitResMan failed to read cd.inf. Insufficient entries?");
+ ExitWithReport("InitResMan failed to read cd.inf. Insufficient entries? [file=%s line=%u]",__FILE__,__LINE__);
+ }
+ }
+
+ file.close();
+
+ for (j=0; j<total_clusters; j++)
+ {
+ uint32 i=0;
+
+ while((scumm_stricmp((char *) cdInf[i].clusterName, resource_files[j]) != 0) && (i<total_clusters))
+ i++;
+
+ if (i == total_clusters)
+ {
+ Zdebug("InitResMan, %s is not in cd.inf", resource_files[j]);
+ ExitWithReport("InitResMan, %s is not in cd.inf [file=%s line=%u]",resource_files[j],__FILE__,__LINE__);
+ }
+ else
+ cdTab[j] = cdInf[i].cd;
+ }
+
+
+ Zdebug("\n%d resources in %d cluster files", total_res_files, total_clusters);
+ for (j=0;j<total_clusters;j++)
+ Zdebug("filename of cluster %d: -%s", j, resource_files[j]);
+ Zdebug("");
+
+
+ resList = (mem **) malloc( total_res_files * sizeof(mem *)); //create space for a list of pointers to mem's
+
+
+ age = (uint32 *) malloc( total_res_files * sizeof(uint32) );
+
+// status = (uint16 *) malloc( total_res_files * sizeof(uint16) );
+
+ count = (uint16 *) malloc( total_res_files * sizeof(uint16) );
+
+
+ for (j=0;j<total_res_files;j++)
+ { age[j]=0; //age must be 0 if the file is not in memory at all
+ count[j]=0;
+ }
+
+ resTime=1; //cannot start at 0
+
+ Free_mem(temp); //get that memory back
+
+/* we don't have to worry about BSODs here - khalek :)
+ // Stop that nasty blue screen??
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+*/
+
+
+ if (file.open("revcd1.id", g_bs2->getGameDataPath()) == false) {
+ int index = 0;
+/*
+ // Scan for CD drives.
+ for (char c='C'; c<='Z'; c++)
+ {
+ sprintf(cdPath, "%c:\\", c);
+ if (GetDriveType(cdPath) == DRIVE_CDROM)
+ cdDrives[index++] = c;
+ }
+*/
+ cdDrives[index++] = 'C';
+
+ if (index == 0)
+ {
+ Zdebug("InitResMan, cannot find CD drive.");
+ ExitWithReport("InitResMan, cannot find CD drive. [file=%s line=%u]",__FILE__,__LINE__);
+ }
+
+ while (index<24)
+ cdDrives[index++] = 0;
+ }
+ else
+ file.close();
+}
+
+//------------------------------------------------------------------------------------
+
+char *resMan::GetCdPath(void)
+{
+ return cdPath;
+}
+
+//------------------------------------------------------------------------------------
+
+void resMan::Close_ResMan(void) //Tony29May96
+{
+//free up our mallocs
+
+
+ free(resList);
+ free(age);
+
+// status = (uint16 *) malloc( total_res_files * sizeof(uint16) );
+
+ free(count);
+}
+
+//------------------------------------------------------------------------------------
+uint8 *resMan::Res_open( uint32 res ) //BHTony30May96
+{
+//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 i.e. until a res_close is called
+
+ File file;
+ uint16 parent_res_file;
+ uint16 actual_res;
+ uint32 pos,len;
+
+ uint32 table_offset;
+
+ int first=0;
+
+
+#ifdef _DEBUG
+ if (res>=total_res_files)
+ Con_fatal_error("Res_open illegal resource %d (there are %d resources 0-%d)", res, total_res_files, total_res_files-1);
+#endif
+
+//is the resource in memory already?
+ if (!age[res]) //if the file is not in memory then age should and MUST be 0
+ {
+// fetch the correct file and read in the correct portion
+// if the file cannot fit then we must trash the oldest large enough floating file
+
+ parent_res_file = res_conv_table[res*2]; //points to the number of the ascii filename
+
+#ifdef _DEBUG
+ if (parent_res_file==0xffff)
+ Con_fatal_error("Res_open tried to open null & void resource number %d", res);
+#endif
+
+ actual_res= res_conv_table[(res*2)+1]; //relative resource within the file
+
+// first we have to find the file via the res_conv_table
+
+// Zdebug("resOpen %s res %d", resource_files[parent_res_file], res);
+// ** at this point here we start to think about where the file is and prompt the user for the right CD to be inserted **
+// ** we need to know the position that we're at within the game - LINC should write this someplace.
+
+
+ if (!(cdTab[parent_res_file] & LOCAL_CACHE) && !(cdTab[parent_res_file] & LOCAL_PERM))
+ {
+ // This cluster is on a CD, we need to cache a new one.
+ CacheNewCluster(parent_res_file);
+ }
+ else if (!(cdTab[parent_res_file] & LOCAL_PERM))
+ {
+ GetCd(cdTab[parent_res_file] & 3); // Makes sure that the correct CD is in the drive.
+ }
+
+ //open the cluster file
+ if (file.open(resource_files[parent_res_file], g_bs2->getGameDataPath()) == false)
+ Con_fatal_error("Res_open cannot *OPEN* %s", resource_files[parent_res_file]);
+
+
+ //1st DWORD of a cluster is an offset to the look-up table
+ table_offset = file.readUint32LE();
+
+
+ //Zdebug("table offset = %d", table_offset);
+
+ file.seek( (table_offset+(actual_res*8)), SEEK_SET); //2 dwords per resource
+ file.read( &pos, 4); //get position of our resource within the cluster file
+ file.read( &len, 4); //read the length
+
+ file.seek(pos, SEEK_SET); // ** get to position in file of our particular resource
+
+// Zdebug("res len %d", len);
+
+// ok, we know the length so try and allocate the memory
+// if it can't then old files will be ditched until it works
+ resList[res] = Twalloc(len, MEM_locked, res);
+
+ // Do a quick ServiceWindows to stop the music screwing up.
+ ServiceWindows();
+
+// now load the file
+ file.read( resList[res]->ad, len); //hurray, load it in.
+
+ file.close(); //close the cluster
+ }
+ else
+ {
+// Zdebug("RO %d, already open count=%d", res, count[res]);
+ }
+
+
+
+ count[res]++; //number of times opened - the file won't move in memory while count is non zero
+
+ age[res]=resTime; //update the accessed time stamp - touch the file in other words
+
+
+
+
+ Lock_mem( resList[res] ); //pass the address of the mem & lock the memory too
+ //might be locked already (if count>1)
+
+ return( (uint8 *) resList[res]->ad );
+}
+
+//------------------------------------------------------------------------------------
+uint8 resMan::Res_check_valid( uint32 res ) // James 12mar97
+{
+ // returns '1' if resource is valid, otherwise returns '0'
+ // used in startup.cpp to ignore invalid screen-manager resources
+
+ uint16 parent_res_file;
+
+
+ if (res>=total_res_files)
+ return(0); // resource number out of range
+
+ parent_res_file = res_conv_table[res*2]; // points to the number of the ascii filename
+
+ if (parent_res_file==0xffff)
+ return(0); // null & void resource
+
+ return(1); // ok
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+
+void resMan::Res_next_cycle( void ) //Tony8Feb97
+{
+//increment the cycle and calculate actual per-cycle memory useage
+
+#ifdef _DEBUG
+ uint32 j;
+#endif
+
+
+
+#ifdef _DEBUG
+ current_memory_useage=0;
+
+ for (j=1;j<total_res_files;j++)
+ if ( age[j]==resTime ) //was accessed last cycle
+ current_memory_useage += resList[j]->size;
+#endif
+
+ resTime++;
+
+ if (!resTime)
+ resTime++; //if you left the game running for a hundred years when this went to 0
+ //there'd be a resource left stuck in memory - after another hundred years there'd be another...
+
+
+}
+//------------------------------------------------------------------------------------
+uint32 resMan::Res_fetch_useage( void ) //Tony8Feb97
+{
+//returns memory usage previous cycle
+
+ return(current_memory_useage);
+}
+//------------------------------------------------------------------------------------
+
+
+
+
+void resMan::Res_close( uint32 res ) //Tony30May96
+{
+//decrements the count
+//resource floats when count=0
+
+
+#ifdef _DEBUG
+ if (res>=total_res_files)
+ Con_fatal_error("Res_closeing illegal resource %d (there are %d resources 0-%d)", res, total_res_files, total_res_files-1);
+
+ if (!(count[res])) //closing but isnt open?
+ Con_fatal_error("Res_close closing %d but it isn't open", res);
+#endif
+
+
+ count[res]--; //one less has it open
+
+ if (!count[res]) //if noone has the file open then unlock and allow to float
+ {
+ Float_mem( resList[res] ); //pass the address of the mem
+
+// *(status+res)-=RES_locked; //unlock the resource
+
+ }
+
+
+}
+
+//------------------------------------------------------------------------------------
+uint32 resMan::Res_fetch_len( uint32 res ) //Tony27Jan96
+{
+//returns the total file length of a resource - i.e. all headers are included too
+
+ FILE *fh=0; //file pointer
+ uint16 parent_res_file;
+ uint16 actual_res;
+ uint32 len;
+ uint32 table_offset;
+
+
+ parent_res_file = res_conv_table[res*2]; //points to the number of the ascii filename
+
+ actual_res= res_conv_table[(res*2)+1]; //relative resource within the file
+
+// first we have to find the file via the res_conv_table
+
+
+ fh = fopen(resource_files[parent_res_file],"rb"); //open the cluster file
+ if (fh==NULL)
+ Con_fatal_error("Res_fetch_len cannot *OPEN* %s", resource_files[parent_res_file]);
+
+
+ fread( &table_offset, sizeof(char), sizeof(uint32), fh); //1st DWORD of a cluster is an offset to the look-up table
+
+
+ fseek(fh, table_offset+(actual_res*8)+4, SEEK_SET); //2 dwords per resource + skip the position dword
+ //fread( &pos, sizeof(char), 4, fh); //get position of our resource within the cluster file
+ fread( &len, sizeof(char), 4, fh); //read the length
+
+
+ return(len);
+
+}
+
+
+//------------------------------------------------------------------------------------
+char *resMan::Fetch_cluster( uint32 res) //Tony3June96
+{
+//returns a pointer to the ascii name of the cluster file which contains resource res
+
+ return(resource_files[res_conv_table[res*2]]);
+}
+//------------------------------------------------------------------------------------
+uint32 resMan::Fetch_age(uint32 res) //Tony3June96
+{
+//return the age of res
+
+ return(age[res]);
+}
+//------------------------------------------------------------------------------------
+uint32 resMan::Fetch_count(uint32 res) //Tony3June96
+{
+//return the open count of res
+
+ return(count[res]);
+}
+//------------------------------------------------------------------------------------
+uint32 resMan::Help_the_aged_out(void) //Tony10Oct96
+{
+//remove from memory the oldest closed resource
+
+ uint32 oldest_res; //holds id of oldest found so far when we have to chuck stuff out of memory
+ uint32 oldest_age; //age of above during search
+ uint32 j;
+ uint32 largestResource = 0;
+
+
+ oldest_age=resTime;
+ oldest_res=0;
+
+ for (j=2;j<total_res_files;j++)
+ if ( (!count[j]) && (age[j]) && (age[j]<=oldest_age)) //not held open and older than this one
+ {
+ if ((age[j] == oldest_age) && (resList[j]->size > largestResource))
+ {
+ oldest_res = j;
+ largestResource = resList[j]->size; // Kick old resource of oldest age and largest size (Helps the poor defragger).
+ }
+ else if (age[j] < oldest_age)
+ {
+ oldest_res = j;
+ oldest_age = age[j];
+ largestResource = resList[j]->size;
+ }
+ }
+
+ if (!oldest_res) //there was not a file we could release
+ return(0); //no bytes released - oh dear, lets hope this never happens
+
+
+// Zdebug(42,"removing %d, age %d, size %d", oldest_res, age[oldest_res], resList[oldest_res]->size);
+
+// trash this old resource
+
+ age[oldest_res]=0; //effectively gone from resList
+ Free_mem(resList[oldest_res]); //release the memory too
+
+ return(resList[oldest_res]->size); //return bytes freed
+}
+//------------------------------------------------------------------------------------
+void resMan::Print_console_clusters(void) //Tony10Oct96
+{
+ uint32 j;
+
+
+ if (total_clusters)
+ { for (j=0;j<total_clusters;j++)
+ Print_to_console(" %s", resource_files[j]);
+
+ Print_to_console(" %d resources", total_res_files);
+ }
+ else
+ Print_to_console(" argh! No resources");
+
+
+ Scroll_console();
+}
+//------------------------------------------------------------------------------------
+void resMan::Examine_res(uint8 *input) //Tony23Oct96
+{
+ uint32 j=0;
+ uint32 res;
+ _standardHeader *file_header;
+
+
+
+ do
+ { if ( (*(input+j)>='0') && (*(input+j)<='9'))
+ j++;
+ else
+ break;
+ }
+ while(*(input+j));
+
+
+ if (!*(input+j)) //didn't quit out of loop on a non numeric chr$
+ { res = atoi((char*)input);
+
+ if (!res)
+ Print_to_console("illegal resource");
+
+ else if(res>=total_res_files)
+ Print_to_console("illegal resource %d (there are %d resources 0-%d)", res, total_res_files, total_res_files-1);
+
+ else if (res_conv_table[res*2]==0xffff)
+ Print_to_console("%d is a null & void resource number", res);
+
+ else //open up the resource and take a look inside!
+ {
+ file_header = (_standardHeader*) res_man.Res_open(res);
+
+// Print_to_console("%d", file_header->fileType);
+// Print_to_console("%s", file_header->name);
+
+
+ //--------------------------------------------------------------------------------
+ // resource types: (taken from header.h)
+
+ // 0 something's wrong!
+// #define ANIMATION_FILE 1 // all normal animations & sprites including mega-sets & font files which are the same format
+// #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 ICON_FILE 12 // menu icon (sprites in General \ Menu icons
+//----------------------------------------------------------
+
+
+ switch(file_header->fileType)
+ {
+ //-----------------------
+ case ANIMATION_FILE: // 1
+ Print_to_console(" <anim> %s", file_header->name);
+ break;
+ //-----------------------
+ case SCREEN_FILE: // 2
+ Print_to_console(" <layer> %s", file_header->name);
+ break;
+ //-----------------------
+ case GAME_OBJECT: // 3
+ Print_to_console(" <game object> %s", file_header->name);
+ break;
+ //-----------------------
+ case WALK_GRID_FILE: // 4
+ Print_to_console(" <walk grid> %s", file_header->name);
+ break;
+ //-----------------------
+ case GLOBAL_VAR_FILE: // 5
+ Print_to_console(" <global variables> %s", file_header->name);
+ break;
+ //-----------------------
+ case PARALLAX_FILE_null: // 6
+ Print_to_console(" <parallax file NOT USED!> %s", file_header->name);
+ break;
+ //-----------------------
+ case RUN_LIST: // 6
+ Print_to_console(" <run list> %s", file_header->name);
+ break;
+ //-----------------------
+ case TEXT_FILE: // 8
+ Print_to_console(" <text file> %s", file_header->name);
+ break;
+ //-----------------------
+ case SCREEN_MANAGER: // 9
+ Print_to_console(" <screen manager> %s", file_header->name);
+ break;
+ //-----------------------
+ case MOUSE_FILE: // 10
+ Print_to_console(" <mouse pointer> %s", file_header->name);
+ break;
+ //-----------------------
+ case ICON_FILE: // 12
+ Print_to_console(" <menu icon> %s", file_header->name);
+ break;
+ //-----------------------
+ default: // 0 or >13
+ Print_to_console(" unrecognised fileType %d", file_header->fileType);
+ break;
+ //-----------------------
+ }
+ res_man.Res_close(res);
+ }
+ }
+ else
+ {
+ Print_to_console("try typing a number");
+ }
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+void resMan::Kill_res(uint8 *input) //Tony23Oct96
+{
+ int j=0;
+ uint32 res;
+
+
+
+
+ do
+ { if ( (*(input+j)>='0') && (*(input+j)<='9'))
+ j++;
+ else
+ break;
+ }
+ while(*(input+j));
+
+
+
+ if (!*(input+j)) //didn't quit out of loop on a non numeric chr$
+ {
+ res = atoi((char*)input);
+
+
+#ifdef _DEBUG
+ if (!res)
+ Print_to_console("illegal resource");
+
+ if (res>=total_res_files)
+ Con_fatal_error(" llegal resource %d (there are %d resources 0-%d)", res, total_res_files, total_res_files-1);
+#endif
+
+
+ if (!count[res]) //if noone has the file open then unlock and allow to float
+ {
+ if (age[res])
+ {
+ age[res]=0; //effectively gone from resList
+ Free_mem(resList[res]); //release the memory too
+ Print_to_console(" trashed %d", res);
+ }
+ else
+ Print_to_console("%d not in memory", res);
+ }
+ else
+ Print_to_console(" file is open - cannot remove");
+ }
+ else
+ {
+ Print_to_console("try typing a number");
+ }
+
+
+}
+//------------------------------------------------------------------------------------
+void resMan::Remove_res(uint32 res) //Tony10Jan97
+{
+ if (age[res])
+ {
+ age[res]=0; //effectively gone from resList
+ Free_mem(resList[res]); //release the memory too
+// Zdebug(" - Trashing %d", res);
+ }
+ else
+ Zdebug("Remove_res(%d) not even in memory!",res);
+}
+//------------------------------------------------------------------------------------
+void resMan::Remove_all_res(void) // James24mar97
+{
+ // remove all res files from memory - ready for a total restart
+ // including player object & global variables resource
+
+ int j=0;
+ uint32 res;
+
+
+ j=base_mem_block;
+
+ do
+ {
+ if (mem_list[j].uid<65536) //a resource
+ {
+ res=mem_list[j].uid;
+
+ age[res]=0; //effectively gone from resList
+ Free_mem(resList[res]); //release the memory too
+ }
+
+ j=mem_list[j].child;
+ }
+ while (j!=-1);
+}
+//------------------------------------------------------------------------------------
+void resMan::Kill_all_res(uint8 wantInfo) //Tony29Nov96
+{
+ // remove all res files from memory
+ // its quicker to search the mem blocs for res files than search resource lists for those in memory
+
+ int j=0;
+ uint32 res;
+ uint32 nuked=0;
+ _standardHeader *header;
+ int scrolls=0;
+ char c;
+
+
+ j=base_mem_block;
+
+ do
+ {
+ if (mem_list[j].uid<65536) //a resource
+ {
+ res=mem_list[j].uid;
+
+ if ((res!=1)&&(res!=CUR_PLAYER_ID)) //not the global vars which are assumed to be open in memory & not the player object! (James17jan97)
+ {
+ header = (_standardHeader*) res_man.Res_open(res);
+ res_man.Res_close(res);
+
+ age[res]=0; //effectively gone from resList
+ Free_mem(resList[res]); //release the memory too
+ nuked++;
+
+ if ((wantInfo)&&(console_status)) // if this was called from the console + we want info
+ {
+ Print_to_console(" nuked %5d: %s", res, header->name);
+ Zdebug(" nuked %d: %s", res, header->name);
+ 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
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+
+ while (!gotTheFocus)
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ break;
+ //--------------------------------------------------
+ }
+ 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;
+ }
+ }
+ }
+ }
+
+ j=mem_list[j].child;
+ }
+ while (j!=-1);
+
+
+ if ((wantInfo)&&(console_status)) // if this was called from the console + we want info!
+ { Scroll_console();
+ Print_to_console(" expelled %d resource(s)", nuked);
+ }
+}
+//------------------------------------------------------------------------------------
+// Like Kill_all_res but only kills objects (except George & the variable table of course)
+// - ie. forcing them to reload & restart their scripts, which simulates the effect
+// of a save & restore, thus checking that each object's re-entrant logic works correctly,
+// and doesn't cause a statuette to disappear forever, or some plaster-filled holes
+// in sand to crash the game & get James in trouble again.
+
+void resMan::Kill_all_objects(uint8 wantInfo) // James17jan97
+{
+ // remove all object res files from memory, excluding George
+ // its quicker to search the mem blocs for res files than search resource lists for those in memory
+
+ int j=0;
+ uint32 res;
+ uint32 nuked=0;
+ _standardHeader *header;
+ int scrolls=0;
+ char c;
+
+ j=base_mem_block;
+
+ do
+ {
+ if (mem_list[j].uid<65536) //a resource
+ {
+ res=mem_list[j].uid;
+
+ if ((res!=1)&&(res!=CUR_PLAYER_ID)) //not the global vars which are assumed to be open in memory & not the player object! (James17jan97)
+ {
+ header = (_standardHeader*) res_man.Res_open(res);
+ res_man.Res_close(res);
+
+ if (header->fileType == GAME_OBJECT)
+ {
+ age[res]=0; //effectively gone from resList
+ Free_mem(resList[res]); //release the memory too
+ nuked++;
+
+ if ((wantInfo)&&(console_status)) // if this was called from the console + we want info
+ {
+ Print_to_console(" nuked %5d: %s", res, header->name);
+ Zdebug(" nuked %d: %s", res, header->name);
+ Build_display();
+
+ scrolls++;
+ if (scrolls==18)
+ {
+ Print_to_console("- Press ESC to stop or any other key to continue");
+ Build_display();
+
+ do
+ {
+ //--------------------------------------------------
+ // Service windows
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+
+ while (!gotTheFocus)
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ break;
+ //--------------------------------------------------
+ }
+ while(!KeyWaiting());
+
+
+ ReadKey(&c); //kill the key we just pressed
+ scrolls=0;
+ }
+ }
+ }
+ }
+ }
+
+ j=mem_list[j].child;
+ }
+ while (j!=-1);
+
+
+ if ((wantInfo)&&(console_status)) // if this was called from the console + we want info
+ Print_to_console(" expelled %d object resource(s)", nuked);
+}
+
+//------------------------------------------------------------------------------------
+
+void resMan::CacheNewCluster(uint32 newCluster)
+{
+ uint8 black[4]={0,0,0,0};
+
+ //----------------------------------------------------------------------------------------
+ // Stop any music from streaming off the CD before we start the cluster-copy!
+ // - eg. the looping restore-panel music will still be playing if we restored a game
+ // to a different cluster on the same CD
+ // - and music streaming would interfere with cluster copying, slowing it right down
+ // - but if we restored to a different CD the music is stopped in GetCd() when it asks for the CD
+
+ FN_stop_music(NULL); // (James16sep97)
+ //----------------------------------------------------------------------------------------
+
+ Clear_fx_queue(); // stops all fx & clears the queue (James22july97)
+
+ GetCd(cdTab[newCluster] & 3);
+
+ // Kick out old cached cluster and load the new one.
+ uint32 i=0;
+ while ((!(cdTab[i] & LOCAL_CACHE)) && (i<total_clusters))
+ i++;
+
+ if (i<total_clusters)
+ {
+ SetFileAttributes(resource_files[i], FILE_ATTRIBUTE_NORMAL);
+ DeleteFile(resource_files[i]);
+ cdTab[i] &= (0xff - LOCAL_CACHE);
+ FILE *file;
+ file = fopen("cd.inf", "r+b");
+
+ if (file == NULL)
+ {
+ Zdebug("CacheNewCluster cannot *OPEN* cd.inf");
+ Con_fatal_error("InitResMan cannot *OPEN* cd.inf [file=%s line=%u]",__FILE__,__LINE__);
+ }
+
+ _cd_inf cdInf;
+
+ do
+ {
+ fread(&cdInf, 1, sizeof(_cd_inf), file);
+ } while ((scumm_stricmp((char *) cdInf.clusterName, resource_files[i]) != 0) && !feof(file));
+
+ if (feof(file))
+ {
+ Zdebug("CacheNewCluster cannot find %s in cd.inf", resource_files[i]);
+ Con_fatal_error("CacheNewCluster cannot find %s in cd.inf", resource_files[i]);
+ }
+
+ fseek(file, -1, SEEK_CUR);
+ fwrite(&cdTab[i], 1, 1, file);
+ fclose(file);
+ }
+
+ char buf[1024];
+ sprintf(buf, "%sClusters\\%s", cdPath, resource_files[newCluster]);
+
+ uint8 fadeStat;
+
+ do
+ {
+ fadeStat = GetFadeStatus();
+
+
+ //--------------------------------------------------
+ // Service windows
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+ //--------------------------------------------------
+
+ } while ((fadeStat == RDFADE_UP) || (fadeStat == RDFADE_DOWN));
+
+ if (GetFadeStatus() != RDFADE_BLACK)
+ {
+ FadeDown((float) 0.75);
+
+ do
+ {
+ //--------------------------------------------------
+ // Service windows
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+ //--------------------------------------------------
+ }
+ while(GetFadeStatus()!=RDFADE_BLACK);
+ }
+
+
+//get rid of top menu flash (tony 26Aug97)
+ EraseBackBuffer();
+ FlipScreens();
+ EraseBackBuffer();
+ FlipScreens();
+
+
+
+ Set_mouse(NULL);
+ Set_luggage(0); //tw28Aug
+
+ uint8 *bgfile;
+ bgfile = res_man.Res_open(2950); // open the screen resource
+ InitialiseBackgroundLayer(NULL);
+ InitialiseBackgroundLayer(NULL);
+ InitialiseBackgroundLayer(FetchBackgroundLayer(bgfile));
+ InitialiseBackgroundLayer(NULL);
+ InitialiseBackgroundLayer(NULL);
+ SetPalette(0, 256, FetchPalette(bgfile), RDPAL_FADE);
+
+ RenderParallax(FetchBackgroundLayer(bgfile), 2);
+ res_man.Res_close(2950); // release the screen resource
+
+ SetFileAttributes(resource_files[newCluster], FILE_ATTRIBUTE_NORMAL); // Git rid of read-only status, if it is set.
+
+ FILE *inFile, *outFile;
+
+ inFile = fopen(buf, "rb");
+ outFile = fopen(resource_files[newCluster], "wb");
+
+ if ((inFile == NULL) || (outFile == NULL))
+ {
+ Zdebug("Cache new cluster could not copy %s to %s", buf, resource_files[newCluster]);
+ Con_fatal_error("Cache new cluster could not copy %s to %s [file=%s line=%u]", buf, resource_files[newCluster],__FILE__,__LINE__);
+ }
+
+ _spriteInfo textSprite;
+ _spriteInfo barSprite;
+ mem *text_spr;
+ _frameHeader *frame;
+ uint8 *loadingBar;
+ _cdtEntry *cdt;
+
+ text_spr = MakeTextSprite( FetchTextLine(res_man.Res_open(2283),8)+2, 640, 187, speech_font_id );
+
+ frame = (_frameHeader*) text_spr->ad;
+
+ textSprite.x = screenWide/2 - frame->width/2;
+ textSprite.y = screenDeep/2 - frame->height/2 - RDMENU_MENUDEEP;
+ textSprite.w = frame->width;
+ textSprite.h = frame->height;
+ textSprite.scale = 0;
+ textSprite.scaledWidth = 0;
+ textSprite.scaledHeight = 0;
+ textSprite.type = RDSPR_DISPLAYALIGN+RDSPR_NOCOMPRESSION+RDSPR_TRANS;
+ textSprite.blend = 0;
+ textSprite.colourTable = 0;
+
+ res_man.Res_close(2283);
+
+ loadingBar = res_man.Res_open(2951);
+
+ frame = FetchFrameHeader(loadingBar, 0);
+ cdt = FetchCdtEntry(loadingBar, 0);
+
+ barSprite.x = cdt->x;
+ barSprite.y = cdt->y;
+ barSprite.w = frame->width;
+ barSprite.h = frame->height;
+ barSprite.scale = 0;
+ barSprite.scaledWidth = 0;
+ barSprite.scaledHeight = 0;
+ barSprite.type = RDSPR_RLE256FAST+RDSPR_TRANS;
+ barSprite.blend = 0;
+ barSprite.colourTable = 0;
+
+ res_man.Res_close(2951);
+
+ loadingBar = res_man.Res_open(2951);
+ frame = FetchFrameHeader(loadingBar, 0);
+ barSprite.data = (uint8 *) (frame+1);
+ res_man.Res_close(2951);
+
+ int16 barX = barSprite.x;
+ int16 barY = barSprite.y;
+ int16 textX = textSprite.x;
+ int16 textY = textSprite.y;
+
+ DrawSprite(&barSprite);
+ barSprite.x = barX;
+ barSprite.y = barY;
+
+ textSprite.data = text_spr->ad + sizeof(_frameHeader);
+ DrawSprite(&textSprite);
+ textSprite.x = textX;
+ textSprite.y = textY;
+
+ CopyScreenBuffer();
+ FlipScreens();
+
+ FadeUp((float)0.75);
+
+ do
+ {
+ //--------------------------------------------------
+ // Service windows
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+ //--------------------------------------------------
+ }
+ while(GetFadeStatus()==RDFADE_UP);
+
+ fseek(inFile, 0, SEEK_END);
+ uint32 size = ftell(inFile);
+ fseek(inFile, 0, SEEK_SET);
+
+ char buffer[BUFFERSIZE];
+ int stepSize = (size/BUFFERSIZE)/100;
+ uint32 read = 0;
+ int step = stepSize;
+ int fr = 0;
+ uint32 realRead = 0;
+
+ do
+ {
+ realRead = fread(buffer, 1, BUFFERSIZE, inFile);
+ read += realRead;
+ if (fwrite(buffer, 1, realRead, outFile) != realRead)
+ {
+ Zdebug("Cache new cluster could not copy %s to %s", buf, resource_files[newCluster]);
+ Con_fatal_error("Cache new cluster could not copy %s to %s [file=%s line=%u]", buf, resource_files[newCluster],__FILE__,__LINE__);
+ }
+
+ if (step == stepSize)
+ {
+ step = 0;
+ bgfile = res_man.Res_open(2950); // open the screen resource
+ RenderParallax(FetchBackgroundLayer(bgfile), 2);
+ res_man.Res_close(2950); // release the screen resource
+ loadingBar = res_man.Res_open(2951);
+ frame = FetchFrameHeader(loadingBar, fr);
+ barSprite.data = (uint8 *) (frame+1);
+ res_man.Res_close(2951);
+ DrawSprite(&barSprite);
+ barSprite.x = barX;
+ barSprite.y = barY;
+
+ textSprite.data = text_spr->ad + sizeof(_frameHeader);
+ DrawSprite(&textSprite);
+ textSprite.x = textX;
+ textSprite.y = textY;
+
+ CopyScreenBuffer();
+ FlipScreens();
+
+ fr += 1;
+ }
+ else
+ step += 1;
+
+ //--------------------------------------------------
+ // Service windows
+ // NOTE: Carry on even when not got the focus!!!
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+ //--------------------------------------------------
+
+ } while ((read % BUFFERSIZE) == 0);
+
+ if (read != size)
+ {
+ Zdebug("Cache new cluster could not copy %s to %s", buf, resource_files[newCluster]);
+ Con_fatal_error("Cache new cluster could not copy %s to %s [file=%s line=%u]", buf, resource_files[newCluster],__FILE__,__LINE__);
+ }
+
+ fclose(inFile);
+ fclose(outFile);
+ Free_mem(text_spr);
+
+ EraseBackBuffer(); // for hardware rendering
+ EraseSoftwareScreenBuffer(); // for software rendering
+
+ FadeDown((float)0.75);
+
+ do
+ {
+ //--------------------------------------------------
+ // Service windows
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+ //--------------------------------------------------
+ }
+ while(GetFadeStatus()==RDFADE_DOWN);
+
+ CopyScreenBuffer();
+ FlipScreens();
+ FadeUp((float)0.75);
+
+ SetFileAttributes(resource_files[newCluster], FILE_ATTRIBUTE_NORMAL); // Git rid of read-only status.
+
+ // Update cd.inf and cdTab
+ cdTab[newCluster] |= LOCAL_CACHE;
+
+ FILE *file;
+ file = fopen("cd.inf", "r+b");
+
+ if (file == NULL)
+ {
+ Zdebug("CacheNewCluster cannot *OPEN* cd.inf");
+ Con_fatal_error("InitResMan cannot *OPEN* cd.inf [file=%s line=%u]",__FILE__,__LINE__);
+ }
+
+ _cd_inf cdInf;
+
+ do
+ {
+ fread(&cdInf, 1, sizeof(_cd_inf), file);
+ } while ((scumm_stricmp((char *) cdInf.clusterName, resource_files[newCluster]) != 0) && !feof(file));
+
+ if (feof(file))
+ {
+ Zdebug("CacheNewCluster cannot find %s in cd.inf", resource_files[newCluster]);
+ Con_fatal_error("CacheNewCluster cannot find %s in cd.inf", resource_files[newCluster]);
+ }
+
+ fseek(file, -1, SEEK_CUR);
+ fwrite(&cdTab[newCluster], 1, 1, file);
+ fclose(file);
+
+ // Now update DelList.log to indicate that this cluster should be removed at uninstall.
+ file = fopen("DelList.log", "r+");
+
+ if (file != NULL)
+ {
+ fseek(file, -3, SEEK_END);
+
+ char path[_MAX_PATH];
+ GetCurrentDirectory(_MAX_PATH, path);
+
+ strcat(path, "\\");
+ strcat(path, resource_files[newCluster]);
+ fwrite(path, 1, strlen(path), file);
+
+ sprintf(path, "\nend");
+ fwrite(path, 1, 4, file);
+
+ fclose(file);
+ }
+}
+
+//------------------------------------------------------------------------------------
+
+void resMan::GetCd(int cd)
+{
+ bool done = false;
+ char sCDName[_MAX_PATH];
+ DWORD dwMaxCompLength, dwFSFlags;
+ mem *text_spr;
+ _frameHeader *frame;
+ _spriteInfo spriteInfo;
+ int16 oldY;
+ int16 oldX;
+ FILE *file;
+ char name[16];
+ int offNetwork = 0;
+ int index = 0;
+ uint8 *textRes;
+
+ //----------------------------------------------------------------------------------------
+ #ifdef _WEBDEMO // (James 01oct97)
+ return; // don't ask for CD's in the playable demo downloaded from our web-site!
+ #endif // _WEBDEMO
+
+ #ifdef _PCGUIDE
+ return; // don't ask for CD in the patch for the demo on "PC Guide" magazine
+ #endif
+ //----------------------------------------------------------------------------------------
+
+ sprintf(name, "revcd%d.id", cd);
+ file = fopen(name, "r");
+
+ if (file == NULL)
+ {
+ // Determine what CD is in the drive, and either use it or ask the user to insert the correct CD.
+ // Scan all CD drives for our CD as well.
+ while((cdDrives[index] != 0) && (index<24))
+ {
+ sprintf(cdPath, "%c:\\", cdDrives[index]);
+
+ if (!GetVolumeInformation(cdPath, sCDName, _MAX_PATH, NULL, &dwMaxCompLength, &dwFSFlags, NULL, 0))
+ {
+ sCDName[0] = 0; // Force the following code to ask for the correct CD.
+ }
+
+ curCd = cd;
+
+ if (!scumm_stricmp(sCDName,CD1_LABEL))
+ {
+ if (cd == CD1)
+ return;
+ }
+ else if (!scumm_stricmp(sCDName,CD2_LABEL))
+ {
+ if (cd == CD2)
+ return;
+ }
+
+ index += 1;
+ }
+ }
+ else // must be running off the network, but still want to see CD-requests to show where they would occur when playing from CD
+ {
+ Zdebug("RUNNING OFF NETWORK");
+
+ fscanf(file, "%s", cdPath);
+ fclose(file);
+
+ if (curCd == cd)
+ return;
+ else
+ curCd = cd;
+
+ if (SYSTEM_TESTING_ANIMS || SYSTEM_TESTING_TEXT) // don't show CD-requests if testing anims or text/speech
+ return;
+
+ offNetwork = 1;
+ }
+
+ //----------------------------------------------------------------------------------------
+ // stop any music from playing - so the system no longer needs the current CD
+ // - otherwise when we take out the CD, Windows will complain!
+
+ FN_stop_music(NULL); // (James29aug97)
+ //----------------------------------------------------------------------------------------
+
+
+ textRes = res_man.Res_open(2283);
+ DisplayMsg( FetchTextLine(textRes, 5+cd)+2, 0 );
+ text_spr = MakeTextSprite( FetchTextLine( textRes, 5+cd)+2, 640, 187, speech_font_id );
+
+ frame = (_frameHeader*) text_spr->ad;
+
+ spriteInfo.x = screenWide/2 - frame->width/2;
+ spriteInfo.y = screenDeep/2 - frame->height/2 - RDMENU_MENUDEEP;
+ spriteInfo.w = frame->width;
+ spriteInfo.h = frame->height;
+ spriteInfo.scale = 0;
+ spriteInfo.scaledWidth = 0;
+ spriteInfo.scaledHeight = 0;
+ spriteInfo.type = RDSPR_DISPLAYALIGN+RDSPR_NOCOMPRESSION+RDSPR_TRANS;
+ spriteInfo.blend = 0;
+ spriteInfo.data = text_spr->ad + sizeof(_frameHeader);
+ spriteInfo.colourTable = 0;
+ oldY = spriteInfo.y;
+ oldX = spriteInfo.x;
+
+ res_man.Res_close(2283);
+
+ do
+ {
+ if (offNetwork == 1)
+ done = TRUE;
+ else
+ {
+ char sCDName[_MAX_PATH];
+ DWORD dwMaxCompLength, dwFSFlags;
+
+ index = 0;
+ while((cdDrives[index] != 0) && (!done) && (index<24))
+ {
+ sprintf(cdPath, "%c:\\", cdDrives[index]);
+
+ if (!GetVolumeInformation(cdPath, sCDName, _MAX_PATH, NULL, &dwMaxCompLength, &dwFSFlags, NULL, 0))
+ {
+ sCDName[0] = 0;
+ }
+
+ if (!scumm_stricmp(sCDName,CD1_LABEL))
+ {
+ if (cd == CD1)
+ done = TRUE;
+ }
+ else if (!scumm_stricmp(sCDName,CD2_LABEL))
+ {
+ if (cd == CD2)
+ done = TRUE;
+ }
+
+ index += 1;
+ }
+ }
+
+ //--------------------------------------------------
+ // Service windows
+
+ if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
+ {
+ Close_game(); //close engine systems down
+ RestoreDisplay();
+ CloseAppWindow();
+ exit(0); //quit the game
+ }
+
+ while (!gotTheFocus)
+ if (ServiceWindows() == RDERR_APPCLOSED)
+ break;
+
+ //--------------------------------------------------
+
+ if (gotTheFocus)
+ {
+ EraseBackBuffer(); // for hardware rendering
+ EraseSoftwareScreenBuffer(); // for software rendering
+ DrawSprite( &spriteInfo ); // Keep the message there even when the user task swaps.
+ spriteInfo.y = oldY; // Drivers change the y co-ordinate, don't know why...
+ spriteInfo.x = oldX;
+ CopyScreenBuffer();
+ FlipScreens();
+ }
+
+ } while (!done);
+
+ Free_mem(text_spr);
+ RemoveMsg();
+}
+//------------------------------------------------------------------------------------
+
+
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+
+
diff --git a/sword2/resman.h b/sword2/resman.h
new file mode 100644
index 0000000000..fb7a215b1e
--- /dev/null
+++ b/sword2/resman.h
@@ -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
diff --git a/sword2/router.cpp b/sword2/router.cpp
new file mode 100644
index 0000000000..cf81c45670
--- /dev/null
+++ b/sword2/router.cpp
@@ -0,0 +1,3089 @@
+/* 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$
+ */
+
+//--------------------------------------------------------------------------------------
+// ROUTER.CPP by James
+
+// A rehash of Jeremy's original jrouter.c, containing low-level system routines
+// for calculating routes between points inside a walk-grid, and constructing
+// walk animations from mega-sets.
+
+// jrouter.c undwent 2 major reworks from the original:
+// (1) Restructured to allow more flexibility in the mega-sets, ie. more info taken from the walk-data
+// - the new George & Nico mega-sets & walk-data were then tested & tweaked in the Sword1 system
+// (2) Updated for the new Sword2 system, ie. new object structures
+// - now compatible with Sword2, the essential code already having been tested
+
+//--------------------------------------------------------------------------------------
+
+
+/****************************************************************************
+ * JROUTER.C polygon router with modular walks
+ * using a tree of modules
+ * 21 july 94
+ * 3 november 94
+ * System currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes), the smoothest eight directional PATH
+ * through these nodes is then found, and a WALK created to fit the PATH.
+ *
+ * Two funtions are called by the user, RouteFinder creates a route as a
+ * module list, HardWalk creates an animation list from the module list.
+ * The split is only provided to allow the possibility of turning the
+ * autorouter over two game cycles.
+ ****************************************************************************
+ *
+ * Routine timings on osborne 486
+ *
+ * Read floor resource (file already loaded) 112 pixels
+ *
+ * Read mega resource (file already loaded) 112 pixels
+ *
+ *
+ *
+ ****************************************************************************
+ *
+ * Modified 12 Oct 95
+ *
+ * Target Points within 1 pixel of a line are ignored ???
+ *
+ * Modules split into Points within 1 pixel of a line are ignored ???
+ *
+ ****************************************************************************
+ *
+ * TOTALLY REHASHED BY JAMES FOR NEW MEGAS USING OLD SYSTEM
+ * THEN REINCARNATED BY JAMES FOR NEW MEGAS USING NEW SYSTEM
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+
+//#define PLOT_PATHS 1
+
+
+/*
+ * Include Files
+ */
+
+
+#include "driver/driver96.h"
+#include "console.h"
+#include "debug.h"
+#include "defs.h"
+#include "header.h"
+#include "interpreter.h"
+#include "memory.h"
+#include "object.h"
+#include "resman.h"
+#include "router.h"
+
+//#ifdef PLOT_PATHS
+//#include "grengine.h"
+//#endif
+
+#define MAX_FRAMES_PER_CYCLE 16
+#define NO_DIRECTIONS 8
+#define MAX_FRAMES_PER_CHAR (MAX_FRAMES_PER_CYCLE * NO_DIRECTIONS)
+#define ROUTE_END_FLAG 255
+
+
+
+
+//---------------------------------------
+// TEMP!
+int8 forceSlidy; // 1 = force the use of slidy router (so solid path not used when ending walk in ANY direction)
+//---------------------------------------
+
+/*
+ * Type Defines
+ */
+
+#define O_WALKANIM_SIZE 600 // max number of nodes in router output
+#define O_GRID_SIZE 200 // max 200 lines & 200 points
+#define EXTRA_GRID_SIZE 20 // max 20 lines & 20 points
+#define O_ROUTE_SIZE 50 // max number of modules in a route
+
+
+typedef struct
+{
+ int16 x1;
+ int16 y1;
+ int16 x2;
+ int16 y2;
+ int16 xmin;
+ int16 ymin;
+ int16 xmax;
+ int16 ymax;
+ int16 dx; // x2 - x1
+ int16 dy; // y2 - y1
+ int32 co; // co = (y1 *dx)- (x1*dy) from an equation for a line y*dx = x*dy + co
+}_barData;
+
+typedef struct
+{
+ int16 x;
+ int16 y;
+ int16 level;
+ int16 prev;
+ int16 dist;
+}_nodeData;
+
+typedef struct
+{
+ int32 nbars;
+ _barData *bars;
+ int32 nnodes;
+ _nodeData *node;
+} _floorData;
+
+typedef struct
+{
+ int32 x;
+ int32 y;
+ int32 dirS;
+ int32 dirD;
+} _routeData;
+
+typedef struct
+{
+ int32 x;
+ int32 y;
+ int32 dir;
+ int32 num;
+} _pathData;
+
+
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
+// Function prototypes
+
+int32 GetRoute(void);
+void ExtractRoute(void);
+void LoadWalkGrid(void);
+void SetUpWalkGrid(Object_mega *ob_mega, int32 x, int32 y, int32 dir);
+void LoadWalkData(Object_walkdata *ob_walkdata);
+void PlotCross(int16 x, int16 y, uint8 colour);
+
+int32 Scan(int32);
+int32 NewCheck(int32, int32 , int32 , int32 , int32);
+int32 LineCheck(int32 , int32 , int32 , int32);
+int32 VertCheck(int32 , int32 , int32);
+int32 HorizCheck(int32 , int32 , int32);
+int32 Check(int32 , int32 , int32 , int32);
+int32 CheckTarget(int32 , int32);
+
+int32 SmoothestPath();
+int32 SlidyPath();
+int32 SolidPath();
+
+int32 SmoothCheck(int32 best, int32 p, int32 dirS, int32 dirD);
+
+int32 AddSlowInFrames(_walkData *walkAnim);
+void AddSlowOutFrames(_walkData *walkAnim);
+void SlidyWalkAnimator(_walkData *walkAnim);
+int32 SolidWalkAnimator(_walkData *walkAnim);
+void RouteLine(int32 x1,int32 y1,int32 x2,int32 y2 ,int32 colour);
+
+//--------------------------------------------------------------------------------------
+#define MAX_WALKGRIDS 10
+
+int32 walkGridList[MAX_WALKGRIDS];
+
+//--------------------------------------------------------------------------------------
+#define TOTAL_ROUTE_SLOTS 2 // because we only have 2 megas in the game!
+
+mem *route_slots[TOTAL_ROUTE_SLOTS]; // stores pointers to mem blocks containing routes created & used by megas (NULL if slot not in use)
+
+//--------------------------------------------------------------------------------------
+// Local Variables
+
+static int32 nbars;
+static int32 nnodes;
+static _barData bars[O_GRID_SIZE+EXTRA_GRID_SIZE]; // because extra bars will be copied into here afer walkgrid loaded
+static _nodeData node[O_GRID_SIZE+EXTRA_GRID_SIZE];
+
+// area for extra route data to block parts of floors and enable routing round mega charaters
+static int32 nExtraBars = 0;
+static int32 nExtraNodes = 0;
+static _barData extraBars[EXTRA_GRID_SIZE];
+static _nodeData extraNode[EXTRA_GRID_SIZE];
+
+static int32 startX;
+static int32 startY;
+static int32 startDir;
+static int32 targetX;
+static int32 targetY;
+static int32 targetDir;
+static int32 scaleA;
+static int32 scaleB;
+static _routeData route[O_ROUTE_SIZE];
+static _pathData smoothPath[O_ROUTE_SIZE];
+static _pathData modularPath[O_ROUTE_SIZE];
+static int32 routeLength;
+
+
+int32 framesPerStep;
+int32 framesPerChar;
+
+uint8 nWalkFrames; // no. of frames per walk cycle
+uint8 usingStandingTurnFrames; // any standing turn frames?
+uint8 usingWalkingTurnFrames; // any walking turn frames?
+uint8 usingSlowInFrames; // any slow-in frames?
+uint8 usingSlowOutFrames; // any slow-out frames?
+int32 dx[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
+int32 dy[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
+int8 modX[NO_DIRECTIONS];
+int8 modY[NO_DIRECTIONS];
+int32 diagonalx = 0;
+int32 diagonaly = 0;
+
+int32 firstStandFrame;
+
+int32 firstStandingTurnLeftFrame;
+int32 firstStandingTurnRightFrame;
+
+int32 firstWalkingTurnLeftFrame; // left walking turn
+int32 firstWalkingTurnRightFrame; // right walking turn
+
+uint32 firstSlowInFrame[NO_DIRECTIONS];
+uint32 numberOfSlowInFrames[NO_DIRECTIONS];
+
+uint32 leadingLeg[NO_DIRECTIONS];
+
+int32 firstSlowOutFrame;
+int32 numberOfSlowOutFrames; // number of slow-out frames on for each leading-leg in each direction
+
+
+int32 stepCount;
+
+int32 moduleX;
+int32 moduleY;
+int32 currentDir;
+int32 lastCount;
+int32 frame;
+
+// ie. total number of slow-out frames = (numberOfSlowOutFrames * 2 * NO_DIRECTIONS)
+
+/*
+ * CODE
+ */
+
+// **************************************************************************
+
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
+uint8 CheckForCollision(void)
+{
+ static uint32 player_pc;
+ static uint32 non_player_pc;
+
+
+ uint8 collision=0;
+
+ return (collision);
+}
+//--------------------------------------------------------------------------------------
+uint8 ReturnSlotNo(uint32 megaId)
+{
+ if (ID==CUR_PLAYER_ID) // George (8)
+ return(0);
+ else // One of Nico's mega id's
+ return(1);
+}
+//--------------------------------------------------------------------------------------
+void AllocateRouteMem(void)
+{
+// uint8 slotNo=0;
+ uint8 slotNo;
+
+ //------------------------------------------
+ // removed (James23June96)
+ /*
+ while (route_slots[slotNo] > 0)
+ {
+ slotNo++;
+
+ #ifdef _DEBUG
+ if (slotNo == TOTAL_ROUTE_SLOTS)
+ Con_fatal_error("ERROR: route_slots[] full in AllocateRouteMem() (%s line %u)",__FILE__,__LINE__);
+ #endif
+ }
+ */
+ //------------------------------------------
+ // added (James23June96)
+ // Player character always always slot 0, while the other mega (normally Nico) always uses slot 1
+ // Better this way, so that if mega object removed from memory while in middle of route,
+ // the old route will be safely cleared from memory just before they create a new one
+
+ slotNo = ReturnSlotNo(ID);
+
+ // if this slot is already used, then it can't be needed any more
+ // because this id is creating a new route!
+ if (route_slots[slotNo])
+ {
+ FreeRouteMem();
+ }
+ //------------------------------------------
+
+ route_slots[slotNo] = Twalloc( 4800, MEM_locked, UID_walk_anim );
+ // 12000 bytes were used for this in Sword1 mega compacts, based on 20 bytes per '_walkData' frame
+ // ie. allowing for 600 frames including end-marker
+ // Now '_walkData' is 8 bytes, so 8*600 = 4800 bytes.
+ // Note that a 600 frame walk lasts about 48 seconds! (600fps / 12.5s = 48s)
+
+// megaObject->route_slot_id = slotNo+1; // mega keeps note of which slot contains the pointer to it's walk animation mem block
+ // +1 so that '0' can mean "not walking"
+}
+//--------------------------------------------------------------------------------------
+_walkData* LockRouteMem(void)
+{
+ uint8 slotNo = ReturnSlotNo(ID);
+
+ Lock_mem( route_slots[slotNo] );
+ return (_walkData *)route_slots[slotNo]->ad;
+}
+//--------------------------------------------------------------------------------------
+void FloatRouteMem(void)
+{
+ uint8 slotNo = ReturnSlotNo(ID);
+
+ Float_mem( route_slots[slotNo] );
+}
+//--------------------------------------------------------------------------------------
+void FreeRouteMem(void)
+{
+ uint8 slotNo = ReturnSlotNo(ID);
+
+ Free_mem( route_slots[slotNo] ); // free the mem block pointed to from this entry of route_slots[]
+ route_slots[slotNo] = NULL; // clear this route_slots[] entry
+}
+//--------------------------------------------------------------------------------------
+void FreeAllRouteMem(void)
+{
+ uint8 slotNo;
+
+ for (slotNo=0; slotNo < TOTAL_ROUTE_SLOTS; slotNo++)
+ {
+ if (route_slots[slotNo])
+ {
+ Free_mem( route_slots[slotNo] ); // free the mem block pointed to from this entry of route_slots[]
+ route_slots[slotNo] = NULL;
+ }
+ }
+}
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+int32 RouteFinder(Object_mega *ob_mega, Object_walkdata *ob_walkdata, int32 x, int32 y, int32 dir)
+{
+/****************************************************************************
+ * RouteFinder.C polygon router with modular walks
+ * 21 august 94
+ * 3 november 94
+ * RouteFinder creates a list of modules that enables HardWalk to create
+ * an animation list.
+ *
+ * RouteFinder currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes), the smoothest eight directional PATH
+ * through these nodes is then found, this information is made available to
+ * HardWalk for a WALK to be created to fit the PATH.
+ *
+ * 30 november 94 return values modified
+ *
+ * return 0 = failed to find a route
+ *
+ * 1 = found a route
+ *
+ * 2 = mega already at target
+ *
+ ****************************************************************************/
+
+ int32 routeFlag = 0;
+ int32 solidFlag = 0;
+ _walkData *walkAnim;
+
+// megaId = id;
+
+
+ SetUpWalkGrid(ob_mega, x, y, dir);
+ LoadWalkData(ob_walkdata);
+
+ walkAnim = LockRouteMem(); // lock the _walkData array (NB. AFTER loading walkgrid & walkdata!)
+
+// **************************************************************************
+// All route data now loaded start finding a route
+// **************************************************************************
+// **************************************************************************
+// Check if we can get a route through the floor changed 12 Oct95 JPS
+// **************************************************************************
+
+ routeFlag = GetRoute();
+
+
+ if (routeFlag == 2) //special case for zero length route
+ {
+ if (targetDir >7)// if target direction specified as any
+ {
+ targetDir = startDir;
+ }
+ // just a turn on the spot is required set an end module for the route let the animator deal with it
+ // modularPath is normally set by ExtractRoute
+ modularPath[0].dir = startDir;
+ modularPath[0].num = 0;
+ modularPath[0].x = startX;
+ modularPath[0].y = startY;
+ modularPath[1].dir = targetDir;
+ modularPath[1].num = 0;
+ modularPath[1].x = startX;
+ modularPath[1].y = startY;
+ modularPath[2].dir = 9;
+ modularPath[2].num = ROUTE_END_FLAG;
+
+ SlidyWalkAnimator(walkAnim);
+ routeFlag = 2;
+ }
+ else if (routeFlag == 1) // a normal route
+ {
+ SmoothestPath();//Converts the route to an exact path
+ // The Route had waypoints and direction options
+ // The Path is an exact set of lines in 8 directions that reach the target.
+ // The path is in module format, but steps taken in each direction are not accurate
+ // if target dir = 8 then the walk isn't linked to an anim so
+ // we can create a route without sliding and miss the exact target
+
+ if (!forceSlidy)
+ {
+ if (targetDir == 8) // can end facing ANY direction (ie. exact end position not vital) - so use SOLID walk to avoid sliding to exact position
+ {
+ SolidPath();
+ solidFlag = SolidWalkAnimator(walkAnim);
+ }
+ }
+
+ if(!solidFlag) // if we failed to create a SOLID route, do a SLIDY one instead
+ {
+ SlidyPath();
+ SlidyWalkAnimator(walkAnim);
+ }
+ }
+ else // Route didn't reach target so assume point was off the floor
+ {
+// routeFlag = 0;
+ }
+
+
+ #ifdef PLOT_PATHS
+ #ifdef _WIN32
+ RenderScreenGDK( screenDef.buffer, scroll_offset_x, scroll_offset_y, screenDef.width * XBLOCKSIZE );
+ #else
+ RenderOffScreenBuffer( scroll_offset_x, scroll_offset_y, SCREEN_WIDTH, SCREEN_DEPTH );
+ #endif
+ FlipScreens();
+
+ FlushMouseEvents(); // clear mouse buffer
+ while (!TestForMouseEvent()); // wait for a button press or release
+ FlushMouseEvents(); // clear mouse buffer again to prevent rapid fire!
+ #endif
+
+
+ FloatRouteMem(); // float the _walkData array again
+
+ return routeFlag; // send back null route
+}
+
+/*******************************************************************************
+ *******************************************************************************
+ * GET A ROUTE
+ *******************************************************************************
+ *******************************************************************************/
+
+
+int32 GetRoute(void)
+{
+ /****************************************************************************
+ * GetRoute.C extract a path from walk grid
+ * 12 october 94
+ *
+ * GetRoute currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes).
+ * static _routeData route[O_ROUTE_SIZE];
+ *
+ * return 0 = failed to find a route
+ *
+ * 1 = found a route
+ *
+ * 2 = mega already at target
+ *
+ * 3 = failed to find a route because target was on a line
+ *
+ ****************************************************************************/
+ int32 routeGot = 0;
+ int32 level;
+ int32 changed;
+
+ if ((startX == targetX) && (startY == targetY))
+ routeGot = 2;
+
+ else // 'else' added by JEL (23jan96) otherwise 'routeGot' affected even when already set to '2' above - causing some 'turns' to walk downwards on the spot
+ routeGot = CheckTarget(targetX,targetY);// returns 3 if target on a line ( +- 1 pixel )
+
+
+ if (routeGot == 0) //still looking for a route check if target is within a pixel of a line
+ {
+ // scan through the nodes linking each node to its nearest neighbour until no more nodes change
+ // This is the routine that finds a route using Scan()
+ level = 1;
+ do
+ {
+ changed = Scan(level);
+ level =level + 1;
+ }
+ while(changed == 1);
+
+ // Check to see if the route reached the target
+ if (node[nnodes].dist < 9999)
+ {
+ routeGot = 1;
+ ExtractRoute(); // it did so extract the route as nodes and the directions to go between each node
+ // route.X,route.Y and route.Dir now hold all the route infomation with the target dir or route continuation
+ }
+ }
+
+ return routeGot;
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE SLIDY PATH ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+
+
+int32 SmoothestPath()
+{
+/*
+ * This is the second big part of the route finder and the the only bit that tries to be clever
+ * (the other bits are clever).
+ * This part of the autorouter creates a list of modules from a set of lines running across the screen
+ * The task is complicated by two things;
+ * Firstly in choosing a route through the maze of nodes the routine tries to minimise the amount of each
+ * individual turn avoiding 90 degree and greater turns (where possible) and reduces the total number of
+ * turns (subject to two 45 degree turns being better than one 90 degree turn).
+ * Secondly when walking in a given direction the number of steps required to reach the end of that run
+ * is not calculated accurately. This is because I was unable to derive a function to relate number of
+ * steps taken between two points to the shrunken step size
+ *
+ */
+ int32 p;
+ int32 dirS;
+ int32 dirD;
+ int32 dS;
+ int32 dD;
+ int32 dSS;
+ int32 dSD;
+ int32 dDS;
+ int32 dDD;
+ int32 SS;
+ int32 SD;
+ int32 DS;
+ int32 DD;
+ int32 i;
+ int32 j;
+ int32 temp;
+ int32 steps;
+ int32 option;
+ int32 options;
+ int32 lastDir;
+ int32 nextDirS;
+ int32 nextDirD;
+ int32 tempturns[4];
+ int32 turns[4];
+ int32 turntable[NO_DIRECTIONS] = {0,1,3,5,7,5,3,1};
+
+ // route.X route.Y and route.Dir start at far end
+ smoothPath[0].x = startX;
+ smoothPath[0].y = startY;
+ smoothPath[0].dir = startDir;
+ smoothPath[0].num = 0;
+ p = 0;
+ lastDir = startDir;
+ // for each section of the route
+ do
+ {
+
+ dirS = route[p].dirS;
+ dirD = route[p].dirD;
+ nextDirS = route[p+1].dirS;
+ nextDirD = route[p+1].dirD;
+
+ // Check directions into and out of a pair of nodes
+ // going in
+ dS = dirS - lastDir;
+ if ( dS < 0)
+ dS = dS + NO_DIRECTIONS;
+
+ dD = dirD - lastDir;
+ if ( dD < 0)
+ dD = dD + NO_DIRECTIONS;
+
+ // coming out
+ dSS = dirS - nextDirS;
+ if ( dSS < 0)
+ dSS = dSS + NO_DIRECTIONS;
+
+ dDD = dirD - nextDirD;
+ if ( dDD < 0)
+ dDD = dDD + NO_DIRECTIONS;
+
+ dSD = dirS - nextDirD;
+ if ( dSD < 0)
+ dSD = dSD + NO_DIRECTIONS;
+
+ dDS = dirD - nextDirS;
+ if ( dDS < 0)
+ dDS = dDS + NO_DIRECTIONS;
+
+ // Determine the amount of turning involved in each possible path
+ dS = turntable[dS];
+ dD = turntable[dD];
+ dSS = turntable[dSS];
+ dDD = turntable[dDD];
+ dSD = turntable[dSD];
+ dDS = turntable[dDS];
+ // get the best path out ie assume next section uses best direction
+ if (dSD < dSS)
+ {
+ dSS = dSD;
+ }
+ if (dDS < dDD)
+ {
+ dDD = dDS;
+ }
+ // rate each option
+ SS = dS + dSS + 3; // Split routes look crap so weight against them
+ SD = dS + dDD;
+ DS = dD + dSS;
+ DD = dD + dDD + 3;
+ // set up turns as a sorted array of the turn values
+ tempturns[0] = SS;
+ turns[0] = 0;
+ tempturns[1] = SD;
+ turns[1] = 1;
+ tempturns[2] = DS;
+ turns[2] = 2;
+ tempturns[3] = DD;
+ turns[3] = 3;
+ i = 0;
+ do
+ {
+ j = 0;
+ do
+ {
+ if (tempturns[j] > tempturns[j + 1])
+ {
+ temp = turns[j];
+ turns[j] = turns[j+1];
+ turns[j+1] = temp;
+ temp = tempturns[j];
+ tempturns[j] = tempturns[j+1];
+ tempturns[j+1] = temp;
+ }
+ j = j + 1;
+ }
+ while (j < 3);
+ i = i + 1;
+ }
+ while (i < 3);
+
+ // best option matched in order of the priority we would like to see on the screen
+ // but each option must be checked to see if it can be walked
+
+ options = NewCheck(1, route[p].x, route[p].y, route[p + 1].x, route[p + 1].y);
+
+#ifdef _DEBUG
+ if (options == 0)
+ {
+ Zdebug("BestTurns fail %d %d %d %d",route[p].x, route[p].y, route[p + 1].x, route[p + 1].y);
+ Zdebug("BestTurns fail %d %d %d %d",turns[0],turns[1],turns[2],options);
+ Con_fatal_error("BestTurns failed (%s line %u)",__FILE__,__LINE__);
+ }
+#endif
+
+ i = 0;
+ steps = 0;
+ do
+ {
+ option = 1 << turns[i];
+ if (option & options)
+ steps = SmoothCheck(turns[i],p,dirS,dirD);
+ i = i + 1;
+ }
+ while ((steps == 0) && (i < 4));
+
+#ifdef PLOT_PATHS // plot the best path
+ if (steps != 0)
+ {
+ i = 0;
+ do
+ {
+ RouteLine(smoothPath[i].x, smoothPath[i].y, smoothPath[i+1].x, smoothPath[i+1].y, 228);
+ i = i + 1;
+ }
+ while (i < steps);
+ }
+#endif
+
+
+#ifdef _DEBUG
+ if (steps == 0)
+ {
+ Zdebug("BestTurns failed %d %d %d %d",route[p].x, route[p].y, route[p + 1].x, route[p + 1].y);
+ Zdebug("BestTurns failed %d %d %d %d",turns[0],turns[1],turns[2],options);
+ Con_fatal_error("BestTurns failed (%s line %u)",__FILE__,__LINE__);
+ }
+#endif
+
+ // route.X route.Y route.dir and bestTurns start at far end
+ p = p + 1;
+
+
+ }
+ while (p < (routeLength));
+ // best turns will end heading as near as possible to target dir rest is down to anim for now
+ smoothPath[steps].dir = 9;
+ smoothPath[steps].num = ROUTE_END_FLAG;
+ return 1;
+}
+
+
+
+
+int32 SmoothCheck(int32 best, int32 p, int32 dirS, int32 dirD)
+/****************************************************************************
+ * Slip sliding away
+ * This path checker checks to see if a walk that exactly follows the path
+ * would be valid. This should be inherently true for atleast one of the turn
+ * options.
+ * No longer checks the data it only creates the smoothPath array JPS
+ ****************************************************************************/
+{
+ static int32 k;
+ int32 tempK;
+ int32 x;
+ int32 y;
+ int32 x2;
+ int32 y2;
+ int32 dx;
+ int32 dy;
+ int32 dsx;
+ int32 dsy;
+ int32 ddx;
+ int32 ddy;
+ int32 dirX;
+ int32 dirY;
+ int32 ss0;
+ int32 ss1;
+ int32 ss2;
+ int32 sd0;
+ int32 sd1;
+ int32 sd2;
+
+
+ if (p == 0)
+ {
+ k = 1;
+ }
+ tempK = 0;
+ x = route[p].x;
+ y = route[p].y;
+ x2 = route[p + 1].x;
+ y2 = route[p + 1].y;
+ dx = x2 - x;
+ dy = y2 - y;
+ dirX = 1;
+ dirY = 1;
+ if (dx < 0)
+ {
+ dx = -dx;
+ dirX = -1;
+ }
+
+ if (dy < 0)
+ {
+ dy = -dy;
+ dirY = -1;
+ }
+
+// set up sd0-ss2 to reflect possible movement in each direction
+ if ((dirS == 0) || (dirS == 4))// vert and diag
+ {
+ ddx = dx;
+ ddy = (dx*diagonaly)/diagonalx;
+ dsy = dy - ddy;
+ ddx = ddx * dirX;
+ ddy = ddy * dirY;
+ dsy = dsy * dirY;
+ dsx = 0;
+
+ sd0 = (ddx + modX[dirD]/2)/ modX[dirD];
+ ss0 = (dsy + modY[dirS]/2) / modY[dirS];
+ sd1 = sd0/2;
+ ss1 = ss0/2;
+ sd2 = sd0 - sd1;
+ ss2 = ss0 - ss1;
+ }
+ else
+ {
+ ddy = dy;
+ ddx = (dy*diagonalx)/diagonaly;
+ dsx = dx - ddx;
+ ddy = ddy * dirY;
+ ddx = ddx * dirX;
+ dsx = dsx * dirX;
+ dsy = 0;
+
+ sd0 = (ddy + modY[dirD]/2)/ modY[dirD];
+ ss0 = (dsx + modX[dirS]/2)/ modX[dirS];
+ sd1 = sd0/2;
+ ss1 = ss0/2;
+ sd2 = sd0 - sd1;
+ ss2 = ss0 - ss1;
+ }
+
+ if (best == 0) //halfsquare, diagonal, halfsquare
+ {
+ smoothPath[k].x = x+dsx/2;
+ smoothPath[k].y = y+dsy/2;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss1;
+ k = k + 1;
+ smoothPath[k].x = x+dsx/2+ddx;
+ smoothPath[k].y = y+dsy/2+ddy;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd0;
+ k = k + 1;
+ smoothPath[k].x = x+dsx+ddx;
+ smoothPath[k].y = y+dsy+ddy;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss2;
+ k = k + 1;
+ tempK = k;
+ }
+ else if (best == 1) //square, diagonal
+ {
+ smoothPath[k].x = x+dsx;
+ smoothPath[k].y = y+dsy;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss0;
+ k = k + 1;
+ smoothPath[k].x = x2;
+ smoothPath[k].y = y2;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd0;
+ k = k + 1;
+ tempK = k;
+ }
+ else if (best == 2) //diagonal square
+ {
+ smoothPath[k].x = x+ddx;
+ smoothPath[k].y = y+ddy;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd0;
+ k = k + 1;
+ smoothPath[k].x = x2;
+ smoothPath[k].y = y2;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss0;
+ k = k + 1;
+ tempK = k;
+ }
+ else //halfdiagonal, square, halfdiagonal
+ {
+ smoothPath[k].x = x+ddx/2;
+ smoothPath[k].y = y+ddy/2;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd1;
+ k = k + 1;
+ smoothPath[k].x = x+dsx+ddx/2;
+ smoothPath[k].y = y+dsy+ddy/2;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss0;
+ k = k + 1;
+ smoothPath[k].x = x2;
+ smoothPath[k].y = y2;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd2;
+ k = k + 1;
+ tempK = k;
+ }
+
+ return tempK;
+}
+
+int32 SlidyPath()
+{
+/****************************************************************************
+ * SlidyPath creates a path based on part steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * currently unused, but is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+int32 smooth;
+int32 slidy;
+int32 scale;
+int32 stepX;
+int32 stepY;
+int32 deltaX;
+int32 deltaY;
+
+ // strip out the short sections
+ slidy = 1;
+ smooth = 1;
+ modularPath[0].x = smoothPath[0].x;
+ modularPath[0].y = smoothPath[0].y;
+ modularPath[0].dir = smoothPath[0].dir;
+ modularPath[0].num = 0;
+
+ while (smoothPath[smooth].num < ROUTE_END_FLAG)
+ {
+ scale = scaleA * smoothPath[smooth].y + scaleB;
+ deltaX = smoothPath[smooth].x - modularPath[slidy-1].x;
+ deltaY = smoothPath[smooth].y - modularPath[slidy-1].y;
+ stepX = modX[smoothPath[smooth].dir];
+ stepY = modY[smoothPath[smooth].dir];
+ stepX = stepX * scale;
+ stepY = stepY * scale;
+ stepX = stepX >> 19;// quarter a step minimum
+ stepY = stepY >> 19;
+ if ((abs(deltaX)>=abs(stepX)) && (abs(deltaY)>=abs(stepY)))
+ {
+ modularPath[slidy].x = smoothPath[smooth].x;
+ modularPath[slidy].y = smoothPath[smooth].y;
+ modularPath[slidy].dir = smoothPath[smooth].dir;
+ modularPath[slidy].num = 1;
+ slidy += 1;
+ }
+ smooth += 1;
+ }
+ // in case the last bit had no steps
+ if (slidy > 1)
+ {
+ modularPath[slidy-1].x = smoothPath[smooth-1].x;
+ modularPath[slidy-1].y = smoothPath[smooth-1].y;
+ }
+ // set up the end of the walk
+ modularPath[slidy].x = smoothPath[smooth-1].x;
+ modularPath[slidy].y = smoothPath[smooth-1].y;
+ modularPath[slidy].dir = targetDir;
+ modularPath[slidy].num = 0;
+ slidy += 1;
+ modularPath[slidy].x = smoothPath[smooth-1].x;
+ modularPath[slidy].y = smoothPath[smooth-1].y;
+ modularPath[slidy].dir = 9;
+ modularPath[slidy].num = ROUTE_END_FLAG;
+ return 1;
+
+}
+
+//****************************************************************************
+// SLOW IN
+
+int32 AddSlowInFrames(_walkData *walkAnim)
+{
+ uint32 slowInFrameNo;
+
+
+ if ((usingSlowInFrames) && (modularPath[1].num > 0))
+ {
+ for (slowInFrameNo=0; slowInFrameNo<numberOfSlowInFrames[currentDir]; slowInFrameNo++)
+ {
+ walkAnim[stepCount].frame = firstSlowInFrame[currentDir] + slowInFrameNo;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+//----------------------------------------------------------------------------
+void EarlySlowOut(Object_mega *ob_mega, Object_walkdata *ob_walkdata)
+{
+ int32 slowOutFrameNo;
+ int32 walk_pc;
+ _walkData *walkAnim;
+
+
+ //Zdebug("\nEARLY SLOW-OUT");
+
+ LoadWalkData(ob_walkdata);
+
+ //Zdebug("********************************");
+ //Zdebug("framesPerStep =%d",framesPerStep); // 6;
+ //Zdebug("numberOfSlowOutFrames =%d",numberOfSlowOutFrames); // 7;
+ //Zdebug("firstWalkingTurnLeftFrame =%d",firstWalkingTurnLeftFrame); // 120;
+ //Zdebug("firstWalkingTurnRightFrame =%d",firstWalkingTurnRightFrame); // 216;
+ //Zdebug("firstSlowOutFrame =%d",firstSlowOutFrame); // 344;
+ //Zdebug("********************************");
+
+
+ walk_pc = ob_mega->walk_pc;
+
+ walkAnim = LockRouteMem(); // lock the _walkData array (NB. AFTER loading walkgrid & walkdata!)
+
+
+ if (usingSlowOutFrames) // if this mega does actually have slow-out frames
+ {
+ do // overwrite the next step (half a cycle) of the walk (ie .step - 0..5
+ {
+ //Zdebug("\nSTEP NUMBER: walkAnim[%d].step = %d",walk_pc,walkAnim[walk_pc].step);
+ //Zdebug("ORIGINAL FRAME: walkAnim[%d].frame = %d",walk_pc,walkAnim[walk_pc].frame);
+ // map from existing walk frame across to correct frame number of slow-out - remember, there may be more slow-out frames than walk-frames!
+
+ if (walkAnim[walk_pc].frame >= firstWalkingTurnRightFrame) // if it's a walking turn-right, rather than a normal step
+ {
+ walkAnim[walk_pc].frame -= firstWalkingTurnRightFrame; // then map it to a normal step frame first
+ //Zdebug("MAPPED TO WALK: walkAnim[%d].frame = %d (walking turn-right frame --> walk frame)",walk_pc,walkAnim[walk_pc].frame);
+ }
+
+ else if (walkAnim[walk_pc].frame >= firstWalkingTurnLeftFrame) // if it's a walking turn-left, rather than a normal step
+ {
+ walkAnim[walk_pc].frame -= firstWalkingTurnLeftFrame; // then map it to a normal step frame first
+ //Zdebug("MAPPED TO WALK: walkAnim[%d].frame = %d (walking turn-left frame --> walk frame)",walk_pc,walkAnim[walk_pc].frame);
+ }
+
+ walkAnim[walk_pc].frame += firstSlowOutFrame + ((walkAnim[walk_pc].frame / framesPerStep) * (numberOfSlowOutFrames-framesPerStep));
+ walkAnim[walk_pc].step = 0;
+ //Zdebug("SLOW-OUT FRAME: walkAnim[%d].frame = %d",walk_pc,walkAnim[walk_pc].frame);
+ walk_pc += 1;
+ }
+ while(walkAnim[walk_pc].step > 0 );
+
+ //Zdebug("\n");
+
+ for (slowOutFrameNo=framesPerStep; slowOutFrameNo < numberOfSlowOutFrames; slowOutFrameNo++) // add stationary frame(s) (OPTIONAL)
+ {
+ walkAnim[walk_pc].frame = walkAnim[walk_pc-1].frame + 1;
+ //Zdebug("EXTRA FRAME: walkAnim[%d].frame = %d",walk_pc,walkAnim[walk_pc].frame);
+ walkAnim[walk_pc].step = 0;
+ walkAnim[walk_pc].dir = walkAnim[walk_pc-1].dir;
+ walkAnim[walk_pc].x = walkAnim[walk_pc-1].x;
+ walkAnim[walk_pc].y = walkAnim[walk_pc-1].y;
+ walk_pc++;
+ }
+ }
+ else // this mega doesn't have slow-out frames
+ {
+ walkAnim[walk_pc].frame = firstStandFrame + walkAnim[walk_pc-1].dir; // stand in current direction
+ walkAnim[walk_pc].step = 0;
+ walkAnim[walk_pc].dir = walkAnim[walk_pc-1].dir;
+ walkAnim[walk_pc].x = walkAnim[walk_pc-1].x;
+ walkAnim[walk_pc].y = walkAnim[walk_pc-1].y;
+ walk_pc++;
+ }
+
+ walkAnim[walk_pc].frame = 512; // end of sequence
+ walkAnim[walk_pc].step = 99; // so that this doesn't happen again while 'george_walking' is still '2'
+}
+//----------------------------------------------------------------------------
+// SLOW OUT
+
+void AddSlowOutFrames(_walkData *walkAnim)
+{
+ int32 slowOutFrameNo;
+
+
+ if ((usingSlowOutFrames)&&(lastCount>=framesPerStep)) // if the mega did actually walk, we overwrite the last step (half a cycle) with slow-out frames + add any necessary stationary frames
+ {
+ // place stop frames here
+ // slowdown at the end of the last walk
+
+ slowOutFrameNo = lastCount - framesPerStep;
+
+
+ //Zdebug("SLOW OUT: slowOutFrameNo(%d) = lastCount(%d) - framesPerStep(%d)",slowOutFrameNo,lastCount,framesPerStep);
+
+ do // overwrite the last step (half a cycle) of the walk
+ {
+ // map from existing walk frame across to correct frame number of slow-out - remember, there may be more slow-out frames than walk-frames!
+ walkAnim[slowOutFrameNo].frame += firstSlowOutFrame + ((walkAnim[slowOutFrameNo].frame / framesPerStep) * (numberOfSlowOutFrames-framesPerStep));
+ walkAnim[slowOutFrameNo].step = 0; // because no longer a normal walk-step
+ //Zdebug("walkAnim[%d].frame = %d",slowOutFrameNo,walkAnim[slowOutFrameNo].frame);
+ slowOutFrameNo += 1;
+ }
+ while(slowOutFrameNo < lastCount );
+
+ for (slowOutFrameNo=framesPerStep; slowOutFrameNo < numberOfSlowOutFrames; slowOutFrameNo++) // add stationary frame(s) (OPTIONAL)
+ {
+ walkAnim[stepCount].frame = walkAnim[stepCount-1].frame + 1;
+ //Zdebug("EXTRA FRAMES: walkAnim[%d].frame = %d",stepCount,walkAnim[stepCount].frame);
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = walkAnim[stepCount-1].dir;
+ walkAnim[stepCount].x = walkAnim[stepCount-1].x;
+ walkAnim[stepCount].y = walkAnim[stepCount-1].y;
+ stepCount += 1;
+ }
+ }
+}
+//----------------------------------------------------------------------------
+
+void SlidyWalkAnimator(_walkData *walkAnim)
+/****************************************************************************
+ * Skidding every where HardWalk creates an animation that exactly fits the
+ * smoothPath and uses foot slipping to fit whole steps into the route
+ * Parameters: georgeg,mouseg
+ * Returns: rout
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+{
+ static int32 left = 0;
+ int32 p;
+ int32 lastDir;
+ int32 lastRealDir;
+ int32 turnDir;
+ int32 scale;
+ int32 step;
+ int32 module;
+ int32 moduleEnd;
+ int32 module16X;
+ int32 module16Y;
+ int32 stepX;
+ int32 stepY;
+ int32 errorX;
+ int32 errorY;
+ int32 lastErrorX;
+ int32 lastErrorY;
+ int32 frameCount;
+ int32 frames;
+
+
+ p = 0;
+ lastDir = modularPath[0].dir;
+ currentDir = modularPath[1].dir;
+ if (currentDir == NO_DIRECTIONS)
+ {
+ currentDir = lastDir;
+ }
+ moduleX = startX;
+ moduleY = startY;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ stepCount = 0;
+
+ //****************************************************************************
+ // SLIDY
+ // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
+ // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
+ //****************************************************************************
+ //Zdebug("\nSLIDY: STARTING THE WALK");
+ module = framesPerChar + lastDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ //****************************************************************************
+ // SLIDY
+ // TURN TO START THE WALK
+ //****************************************************************************
+ //Zdebug("\nSLIDY: TURNING TO START THE WALK");
+ // rotate if we need to
+ if (lastDir != currentDir)
+ {
+ // get the direction to turn
+ turnDir = currentDir - lastDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to new walk direction
+ // for george and nico put in a head turn at the start
+ if (usingStandingTurnFrames)
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ module = firstStandingTurnRightFrame + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate till were facing new dir then go back 45 degrees
+ while (lastDir != currentDir)
+ {
+ lastDir += turnDir;
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ if ( lastDir < 0)
+ lastDir += NO_DIRECTIONS;
+ module = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ if ( lastDir > 7)
+ lastDir -= NO_DIRECTIONS;
+ module = firstStandingTurnRightFrame + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ // the back 45 degrees bit
+ stepCount -= 1;// step back one because new head turn for george takes us past the new dir
+ }
+ // his head is in the right direction
+ lastRealDir = currentDir;
+
+ //****************************************************************************
+ // SLIDY: THE SLOW IN
+
+ AddSlowInFrames(walkAnim);
+ //****************************************************************************
+
+ //****************************************************************************
+ // SLIDY
+ // THE WALK
+ //****************************************************************************
+
+ //Zdebug("\nSLIDY: THE WALK");
+
+ //---------------------------------------------------
+ // start the walk on the left or right leg, depending on how the slow-in frames were drawn
+
+ if (leadingLeg[currentDir]==0) // (0=left; 1=right)
+ left = 0; // start the walk on the left leg (ie. at beginning of the first step of the walk cycle)
+ else
+ left = framesPerStep; // start the walk on the right leg (ie. at beginning of the second step of the walk cycle)
+ //---------------------------------------------------
+
+
+ lastCount = stepCount;
+ lastDir = 99;// this ensures that we don't put in turn frames for the start
+ currentDir = 99;// this ensures that we don't put in turn frames for the start
+ do
+ {
+ while (modularPath[p].num == 0)
+ {
+ p = p + 1;
+ if (currentDir != 99)
+ lastRealDir = currentDir;
+ lastDir = currentDir;
+ lastCount = stepCount;
+ }
+ //calculate average amount to lose in each step on the way to the next node
+ currentDir = modularPath[p].dir;
+ if (currentDir < NO_DIRECTIONS)
+ {
+ module = currentDir * framesPerStep * 2 + left;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ moduleEnd = module + framesPerStep;
+ step = 0;
+ scale = (scaleA * moduleY + scaleB);
+ do
+ {
+ module16X += dx[module]*scale;
+ module16Y += dy[module]*scale;
+ moduleX = module16X >> 16;
+ moduleY = module16Y >> 16;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = step; // normally 0,1,2,3,4,5,0,1,2,etc
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ step += 1;
+ module += 1;
+ }
+ while( module < moduleEnd) ;
+ stepX = modX[modularPath[p].dir];
+ stepY = modY[modularPath[p].dir];
+ errorX = modularPath[p].x - moduleX;
+ errorX = errorX * stepX;
+ errorY = modularPath[p].y - moduleY;
+ errorY = errorY * stepY;
+ if ((errorX < 0) || (errorY < 0))
+ {
+ modularPath[p].num = 0; // the end of the path
+ // okay those last steps took us past our target but do we want to scoot or moonwalk
+ frames = stepCount - lastCount;
+ errorX = modularPath[p].x - walkAnim[stepCount-1].x;
+ errorY = modularPath[p].y - walkAnim[stepCount-1].y;
+
+ if (frames > framesPerStep)
+ {
+ lastErrorX = modularPath[p].x - walkAnim[stepCount-7].x;
+ lastErrorY = modularPath[p].y - walkAnim[stepCount-7].y;
+ if (stepX==0)
+ {
+ if (3*abs(lastErrorY) < abs(errorY)) //the last stop was closest
+ {
+ stepCount -= framesPerStep;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ }
+ }
+ else
+ {
+ if (3*abs(lastErrorX) < abs(errorX)) //the last stop was closest
+ {
+ stepCount -= framesPerStep;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ }
+ }
+ }
+ errorX = modularPath[p].x - walkAnim[stepCount-1].x;
+ errorY = modularPath[p].y - walkAnim[stepCount-1].y;
+ // okay we've reached the end but we still have an error
+ if (errorX != 0)
+ {
+ frameCount = 0;
+ frames = stepCount - lastCount;
+ do
+ {
+ frameCount += 1;
+ walkAnim[lastCount + frameCount - 1].x += errorX*frameCount/frames;
+ }
+ while(frameCount<frames);
+ }
+ if (errorY != 0)
+ {
+ frameCount = 0;
+ frames = stepCount - lastCount;
+ do
+ {
+ frameCount += 1;
+ walkAnim[lastCount + frameCount-1].y += errorY*frameCount/frames;
+ }
+ while(frameCount<frames);
+ }
+ // Now is the time to put in the turn frames for the last turn
+ if (frames < framesPerStep)
+ currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
+ if (currentDir != 99)
+ lastRealDir = currentDir;
+ // check each turn condition in turn
+ if (((lastDir != 99) && (currentDir != 99)) && (usingWalkingTurnFrames)) // only for george
+ {
+ lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left
+ if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6)))
+ {
+ // turn at the end of the last walk
+ frame = lastCount - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += firstWalkingTurnLeftFrame; //was 104; //turning left
+ frame += 1;
+ }
+ while(frame < lastCount );
+ }
+ if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6)))
+ {
+ // turn at the end of the current walk
+ frame = lastCount - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += firstWalkingTurnRightFrame; // was 200; // turning right
+ frame += 1;
+ }
+ while(frame < lastCount );
+ }
+ lastDir = currentDir;
+ }
+ // all turns checked
+
+ lastCount = stepCount;
+ moduleX = walkAnim[stepCount-1].x;
+ moduleY = walkAnim[stepCount-1].y;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ }
+ }
+ }
+ while (modularPath[p].dir < NO_DIRECTIONS);
+
+
+
+#ifdef _DEBUG
+ if (lastRealDir == 99)
+ {
+ Con_fatal_error("SlidyWalkAnimatorlast direction error (%s line %u)",__FILE__,__LINE__);
+ }
+#endif
+
+ //****************************************************************************
+ // SLIDY: THE SLOW OUT
+ AddSlowOutFrames(walkAnim);
+
+ //****************************************************************************
+ // SLIDY
+ // TURNS TO END THE WALK ?
+ //****************************************************************************
+
+ // We've done the walk now put in any turns at the end
+
+
+ if (targetDir == 8) // ANY direction -> stand in the last direction
+ {
+ module = firstStandFrame + lastRealDir;
+ targetDir = lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ if (targetDir == 9) // 'stance' was non-zero
+ {
+ if (stepCount == 0)
+ {
+ module = framesPerChar + lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ }
+ else if (targetDir != lastRealDir) // rotate to targetDir
+ {
+ // rotate to target direction
+ turnDir = targetDir - lastRealDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to target direction
+ // for george and nico put in a head turn at the start
+ if (usingStandingTurnFrames)
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ module = firstStandingTurnRightFrame + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate if we need to
+ while (lastRealDir != targetDir)
+ {
+ lastRealDir += turnDir;
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ if ( lastRealDir < 0)
+ lastRealDir += NO_DIRECTIONS;
+ module = firstStandingTurnLeftFrame + lastRealDir;
+ }
+ else
+ {
+ if ( lastRealDir > 7)
+ lastRealDir -= NO_DIRECTIONS;
+ module = firstStandingTurnRightFrame + lastRealDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ module = firstStandFrame + lastRealDir;
+ walkAnim[stepCount-1].frame = module;
+ }
+ else // just stand at the end
+ {
+ module = firstStandFrame + lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+
+
+ //-------------------------------------------
+ // write all the frames to "debug.txt"
+
+ //Zdebug("\nTHE WALKDATA:");
+ for (frame=0; frame<=stepCount; frame++)
+ {
+ //Zdebug("walkAnim[%d].frame=%d",frame,walkAnim[frame].frame);
+ }
+ //-------------------------------------------
+
+
+// Zdebug("RouteFinder RouteSize is %d", stepCount);
+ return;
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE SOLID PATH ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+
+int32 SolidPath()
+{
+/****************************************************************************
+ * SolidPath creates a path based on whole steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * currently unused, but is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+int32 smooth;
+int32 solid;
+int32 scale;
+int32 stepX;
+int32 stepY;
+int32 deltaX;
+int32 deltaY;
+
+ // strip out the short sections
+ solid = 1;
+ smooth = 1;
+ modularPath[0].x = smoothPath[0].x;
+ modularPath[0].y = smoothPath[0].y;
+ modularPath[0].dir = smoothPath[0].dir;
+ modularPath[0].num = 0;
+
+ do
+ {
+ scale = scaleA * smoothPath[smooth].y + scaleB;
+ deltaX = smoothPath[smooth].x - modularPath[solid-1].x;
+ deltaY = smoothPath[smooth].y - modularPath[solid-1].y;
+ stepX = modX[smoothPath[smooth].dir];
+ stepY = modY[smoothPath[smooth].dir];
+ stepX = stepX * scale;
+ stepY = stepY * scale;
+ stepX = stepX >> 16;
+ stepY = stepY >> 16;
+ if ((abs(deltaX)>=abs(stepX)) && (abs(deltaY)>=abs(stepY)))
+ {
+ modularPath[solid].x = smoothPath[smooth].x;
+ modularPath[solid].y = smoothPath[smooth].y;
+ modularPath[solid].dir = smoothPath[smooth].dir;
+ modularPath[solid].num = 1;
+ solid += 1;
+ }
+ smooth += 1;
+ }
+ while (smoothPath[smooth].num < ROUTE_END_FLAG);
+ // in case the last bit had no steps
+ if (solid == 1) //there were no paths so put in a dummy end
+ {
+ solid = 2;
+ modularPath[1].dir = smoothPath[0].dir;
+ modularPath[1].num = 0;
+ }
+ modularPath[solid-1].x = smoothPath[smooth-1].x;
+ modularPath[solid-1].y = smoothPath[smooth-1].y;
+ // set up the end of the walk
+ modularPath[solid].x = smoothPath[smooth-1].x;
+ modularPath[solid].y = smoothPath[smooth-1].y;
+ modularPath[solid].dir = 9;
+ modularPath[solid].num = ROUTE_END_FLAG;
+ return 1;
+
+}
+
+int32 SolidWalkAnimator(_walkData *walkAnim)
+{
+/****************************************************************************
+ * SolidWalk creates an animation based on whole steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ * returns 0 if solid route not found
+ ****************************************************************************/
+
+ int32 p;
+ int32 i;
+ int32 left;
+ int32 lastDir;
+ int32 turnDir;
+ int32 scale;
+ int32 step;
+ int32 module;
+ int32 module16X;
+ int32 module16Y;
+ int32 errorX;
+ int32 errorY;
+ int32 moduleEnd;
+ int32 slowStart=0;
+
+
+
+ // start at the beginning for a change
+ lastDir = modularPath[0].dir;
+ p = 1;
+ currentDir = modularPath[1].dir;
+ module = framesPerChar + lastDir;
+ moduleX = startX;
+ moduleY = startY;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ stepCount = 0;
+
+ //****************************************************************************
+ // SOLID
+ // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
+ // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
+ //****************************************************************************
+
+ //Zdebug("\nSOLID: STARTING THE WALK");
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ //****************************************************************************
+ // SOLID
+ // TURN TO START THE WALK
+ //****************************************************************************
+ //Zdebug("\nSOLID: TURNING TO START THE WALK");
+ // rotate if we need to
+ if (lastDir != currentDir)
+ {
+ // get the direction to turn
+ turnDir = currentDir - lastDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to new walk direction
+ // for george and nico put in a head turn at the start
+ if (usingStandingTurnFrames)
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ module = firstStandingTurnRightFrame + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate till were facing new dir then go back 45 degrees
+ while (lastDir != currentDir)
+ {
+ lastDir += turnDir;
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ if ( lastDir < 0)
+ lastDir += NO_DIRECTIONS;
+ module = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ if ( lastDir > 7)
+ lastDir -= NO_DIRECTIONS;
+ module = firstStandingTurnRightFrame + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ // the back 45 degrees bit
+ stepCount -= 1;// step back one because new head turn for george takes us past the new dir
+ }
+
+ //****************************************************************************
+ // SOLID: THE SLOW IN
+
+ slowStart = AddSlowInFrames(walkAnim);
+
+ //****************************************************************************
+ // SOLID
+ // THE WALK
+ //****************************************************************************
+
+ //Zdebug("\nSOLID: THE WALK");
+
+ //---------------------------------------------------
+ // start the walk on the left or right leg, depending on how the slow-in frames were drawn
+
+ if (leadingLeg[currentDir]==0) // (0=left; 1=right)
+ left = 0; // start the walk on the left leg (ie. at beginning of the first step of the walk cycle)
+ else
+ left = framesPerStep; // start the walk on the right leg (ie. at beginning of the second step of the walk cycle)
+ //---------------------------------------------------
+
+
+ lastCount = stepCount;
+ lastDir = 99;// this ensures that we don't put in turn frames for the start
+ currentDir = 99;// this ensures that we don't put in turn frames for the start
+
+ do
+ {
+ while(modularPath[p].num > 0)
+ {
+ currentDir = modularPath[p].dir;
+ if (currentDir< NO_DIRECTIONS)
+ {
+
+ module = currentDir * framesPerStep * 2 + left;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ moduleEnd = module + framesPerStep;
+ step = 0;
+ scale = (scaleA * moduleY + scaleB);
+ do
+ {
+ module16X += dx[module]*scale;
+ module16Y += dy[module]*scale;
+ moduleX = module16X >> 16;
+ moduleY = module16Y >> 16;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = step; // normally 0,1,2,3,4,5,0,1,2,etc
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ module += 1;
+ step += 1;
+ }
+ while( module < moduleEnd) ;
+ errorX = modularPath[p].x - moduleX;
+ errorX = errorX * modX[modularPath[p].dir];
+ errorY = modularPath[p].y - moduleY;
+ errorY = errorY * modY[modularPath[p].dir];
+ if ((errorX < 0) || (errorY < 0))
+ {
+ modularPath[p].num = 0;
+ stepCount -= framesPerStep;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ // Okay this is the end of a section
+ moduleX = walkAnim[stepCount-1].x;
+ moduleY = walkAnim[stepCount-1].y;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ modularPath[p].x =moduleX;
+ modularPath[p].y =moduleY;
+ // Now is the time to put in the turn frames for the last turn
+ if ((stepCount - lastCount) < framesPerStep)// no step taken
+ {
+ if (slowStart == 1)// clean up if a slow in but no walk
+ {
+ //stepCount -= 3;
+ stepCount -= numberOfSlowInFrames[currentDir]; // (James08sep97)
+ //lastCount -= 3;
+ lastCount -= numberOfSlowInFrames[currentDir]; // (James08sep97)
+ slowStart = 0;
+ }
+ currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
+ }
+ // check each turn condition in turn
+ if (((lastDir != 99) && (currentDir != 99)) && (usingWalkingTurnFrames)) // only for george
+ {
+ lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left
+ if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6)))
+ {
+ // turn at the end of the last walk
+ frame = lastCount - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += firstWalkingTurnLeftFrame; // was 104; //turning left
+ frame += 1;
+ }
+ while(frame < lastCount );
+ }
+ if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6)))
+ {
+ // turn at the end of the current walk
+ frame = lastCount - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += firstWalkingTurnRightFrame; // was 200; // turning right
+ frame += 1;
+ }
+ while(frame < lastCount );
+ }
+ }
+ // all turns checked
+ lastCount = stepCount;
+ }
+ }
+ }
+ p = p + 1;
+ lastDir = currentDir;
+ slowStart = 0; //can only be valid first time round
+ }
+ while (modularPath[p].dir < NO_DIRECTIONS);
+
+
+ //****************************************************************************
+ // SOLID: THE SLOW OUT
+ AddSlowOutFrames(walkAnim);
+
+ //****************************************************************************
+
+ module = framesPerChar + modularPath[p-1].dir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = modularPath[p-1].dir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+
+ //-------------------------------------------
+ // write all the frames to "debug.txt"
+
+ //Zdebug("\nTHE WALKDATA:");
+ for (frame=0; frame<=stepCount; frame++)
+ {
+ //Zdebug("walkAnim[%d].frame=%d",frame,walkAnim[frame].frame);
+ }
+ //-------------------------------------------
+
+ //****************************************************************************
+ // SOLID
+ // NO END TURNS
+ //****************************************************************************
+
+// Zdebug("RouteFinder RouteSize is %d", stepCount);
+// now check the route
+ i = 0;
+ do
+ {
+ if (!Check(modularPath[i].x, modularPath[i].y, modularPath[i+1].x, modularPath[i+1].y))
+ p=0;
+ #ifdef PLOT_PATHS
+ RouteLine(modularPath[i].x, modularPath[i].y, modularPath[i+1].x, modularPath[i+1].y, 227);
+ #endif
+ i += 1;
+ }
+ while(i<p-1);
+ if (p != 0)
+ {
+ targetDir = modularPath[p-1].dir;
+ }
+ if (p != 0)
+ {
+ if (CheckTarget(moduleX,moduleY) == 3)// new target on a line
+ {
+ p = 0;
+ //Zdebug("Solid walk target was on a line %d %d", moduleX, moduleY);
+ }
+ }
+
+ return p;
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE SCAN ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+
+int32 Scan(int32 level)
+/*******************************************************************************
+ * Called successively from RouteFinder until no more changes take place in the
+ * grid array ie he best path has been found
+ *
+ * Scans through every point in the node array and checks if there is a route
+ * between each point and if this route gives a new route.
+ *
+ * This routine could probably halve its processing time if it doubled up on the
+ * checks after each route check
+ *
+ *******************************************************************************/
+{
+ int32 i;
+ int32 k;
+ int32 x1;
+ int32 y1;
+ int32 x2;
+ int32 y2;
+ int32 distance;
+ int32 changed = 0;
+ // For all the nodes that have new values and a distance less than enddist
+ // ie dont check for new routes from a point we checked before or from a point
+ // that is already further away than the best route so far.
+ i = 0;
+ do
+ {
+ if ((node[i].dist < node[nnodes].dist) && (node[i].level == level))
+ {
+ x1 = node[i].x;
+ y1 = node[i].y;
+ k=nnodes;
+ do
+ {
+ if (node[k].dist > node[i].dist)
+ {
+ x2 = node[k].x;
+ y2 = node[k].y;
+
+ if (abs(x2-x1)>(4.5*abs(y2-y1)))
+ {
+ distance = (8*abs(x2-x1)+18*abs(y2-y1))/(54*8)+1;
+ }
+ else
+ {
+ distance = (6*abs(x2-x1)+36*abs(y2-y1))/(36*14)+1;
+ }
+
+ if ((distance + node[i].dist < node[nnodes].dist) && (distance + node[i].dist < node[k].dist))
+ {
+ if (NewCheck(0, x1,y1,x2,y2))
+ {
+ node[k].level = level + 1;
+ node[k].dist = distance + node[i].dist;
+ node[k].prev = i;
+ changed = 1;
+ }
+ }
+ }
+ k-=1;
+ }
+ while(k > 0);
+ }
+ i=i+1;
+ }
+ while(i < nnodes);
+ return changed;
+}
+
+
+int32 NewCheck(int32 status, int32 x1 , int32 y1 , int32 x2 ,int32 y2)
+/*******************************************************************************
+ * NewCheck routine checks if the route between two points can be achieved
+ * without crossing any of the bars in the Bars array.
+ *
+ * NewCheck differs from check in that that 4 route options are considered
+ * corresponding to actual walked routes.
+ *
+ * Note distance doesnt take account of shrinking ???
+ *
+ * Note Bars array must be properly calculated ie min max dx dy co
+ *******************************************************************************/
+{
+ int32 dx;
+ int32 dy;
+ int32 dlx;
+ int32 dly;
+ int32 dirX;
+ int32 dirY;
+ int32 step1;
+ int32 step2;
+ int32 step3;
+ int32 steps;
+ int32 options;
+
+ steps = 0;
+ options = 0;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dirX = 1;
+ dirY = 1;
+ if (dx < 0)
+ {
+ dx = -dx;
+ dirX = -1;
+ }
+
+ if (dy < 0)
+ {
+ dy = -dy;
+ dirY = -1;
+ }
+
+ //make the route options
+ if ((diagonaly * dx) > (diagonalx * dy)) // dir = 1,2 or 2,3 or 5,6 or 6,7
+ {
+ dly = dy;
+ dlx = (dy*diagonalx)/diagonaly;
+ dx = dx - dlx;
+ dlx = dlx * dirX;
+ dly = dly * dirY;
+ dx = dx * dirX;
+ dy = 0;
+
+ //options are
+ //square, diagonal a code 1 route
+ step1 = Check(x1, y1, x1+dx, y1);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dx, y1, x2, y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+ options = options + 2;
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dx, y1, 231);
+ RouteLine(x1+dx, y1, x2, y2, 231);
+ }
+ #endif
+ }
+ }
+ //diagonal, square a code 2 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dlx,y1+dly);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dlx, y2, x2, y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+ options = options + 4;
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dlx,y1+dly, 231);
+ RouteLine(x1+dlx, y2, x2, y2, 231);
+ }
+ #endif
+ }
+ }
+ }
+ //halfsquare, diagonal, halfsquare a code 0 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dx/2, y1);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dx/2, y1, x1+dx/2+dlx, y2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dx/2+dlx, y2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ options = options + 1;
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dx/2, y1, 231);
+ RouteLine(x1+dx/2, y1, x1+dx/2+dlx, y2, 231);
+ RouteLine(x1+dx/2+dlx, y2, x2, y2, 231);
+ }
+ #endif
+ }
+ }
+ }
+ }
+ //halfdiagonal, square, halfdiagonal a code 3 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dlx/2, y1+dly/2);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dlx/2, y1+dly/2, x1+dx+dlx/2, y1+dly/2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dx+dlx/2, y1+dly/2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dlx/2, y1+dly/2, 231);
+ RouteLine(x1+dlx/2, y1+dly/2, x1+dx+dlx/2, y1+dly/2, 231);
+ RouteLine(x1+dx+dlx/2, y1+dly/2, x2, y2, 231);
+ }
+ #endif
+ options = options + 8;
+ }
+ }
+ }
+ }
+ }
+ else // dir = 7,0 or 0,1 or 3,4 or 4,5
+ {
+ dlx = dx;
+ dly = (dx*diagonaly)/diagonalx;
+ dy = dy - dly;
+ dlx = dlx * dirX;
+ dly = dly * dirY;
+ dy = dy * dirY;
+ dx = 0;
+
+ //options are
+ //square, diagonal a code 1 route
+ step1 = Check(x1 ,y1 ,x1 ,y1+dy );
+ if (step1 != 0)
+ {
+ step2 = Check(x1 ,y1+dy ,x2,y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1 ,y1 ,x1 ,y1+dy, 231);
+ RouteLine(x1 ,y1+dy ,x2, y2, 231);
+ }
+ #endif
+ options = options + 2;
+ }
+ }
+ //diagonal, square a code 2 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x2, y1+dly);
+ if (step1 != 0)
+ {
+ step2 = Check(x2, y1+dly, x2, y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x2, y1+dly, 231);
+ RouteLine(x2, y1+dly, x2, y2, 231);
+ }
+ #endif
+ options = options + 4;
+ }
+ }
+ }
+ //halfsquare, diagonal, halfsquare a code 0 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1, y1+dy/2);
+ if (step1 != 0)
+ {
+ step2 = Check(x1, y1+dy/2, x2, y1+dy/2+dly);
+ if (step2 != 0)
+ {
+ step3 = Check(x2, y1+dy/2+dly, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1, y1+dy/2, 231);
+ RouteLine(x1, y1+dy/2, x2, y1+dy/2+dly, 231);
+ RouteLine(x2, y1+dy/2+dly, x2, y2, 231);
+ }
+ #endif
+ options = options + 1;
+ }
+ }
+ }
+ }
+ //halfdiagonal, square, halfdiagonal a code 3 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dlx/2, y1+dly/2);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dlx/2, y1+dly/2, x1+dlx/2, y1+dy+dly/2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dlx/2, y1+dy+dly/2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ options = options + 8;
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dlx/2, y1+dly/2, 231);
+ RouteLine(x1+dlx/2, y1+dly/2, x1+dlx/2, y1+dy+dly/2, 231);
+ RouteLine(x1+dlx/2, y1+dy+dly/2, x2, y2, 231);
+ }
+ #endif
+ }
+ }
+ }
+ }
+ }
+ if (status == 0)
+ {
+ status = steps;
+ }
+ else
+ {
+ status = options;
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * CHECK ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+
+
+int32 Check(int32 x1 , int32 y1 , int32 x2 ,int32 y2)
+{
+//call the fastest line check for the given line
+//returns 1 if line didn't cross any bars
+ int32 steps;
+
+ if ((x1 == x2) && (y1 == y2))
+ {
+ steps = 1;
+ }
+ else if (x1 == x2)
+ {
+ steps = VertCheck(x1, y1, y2);
+ }
+ else if (y1 == y2)
+ {
+ steps = HorizCheck(x1, y1, x2);
+ }
+ else
+ {
+ steps = LineCheck(x1, y1, x2, y2);
+ }
+ return steps;
+
+}
+
+
+int32 LineCheck(int32 x1 , int32 y1 , int32 x2 ,int32 y2)
+{
+ int32 dirx;
+ int32 diry;
+ int32 co;
+ int32 slope;
+ int32 i;
+ int32 xc;
+ int32 yc;
+ int32 xmin;
+ int32 ymin;
+ int32 xmax;
+ int32 ymax;
+ int32 linesCrossed = 1;
+
+
+ if (x1 > x2)
+ {
+ xmin = x2;
+ xmax = x1;
+ }
+ else
+ {
+ xmin = x1;
+ xmax = x2;
+ }
+ if (y1 > y2)
+ {
+ ymin = y2;
+ ymax = y1;
+ }
+ else
+ {
+ ymin = y1;
+ ymax = y2;
+ }
+ //line set to go one step in chosen direction
+ //so ignore if it hits anything
+ dirx = x2 - x1;
+ diry = y2 - y1;
+ co = (y1 *dirx)- (x1*diry); //new line equation
+
+ i = 0;
+ do
+ {
+ // this is the inner inner loop
+ if ((xmax >= bars[i].xmin) && ( xmin <= bars[i].xmax)) //skip if not on module
+ {
+ if ((ymax >= bars[i].ymin) && ( ymin <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ slope = (bars[i].dx * diry) - (bars[i].dy *dirx);// slope it he slope between the two lines
+ if (slope != 0)//assuming parallel lines don't cross
+ {
+ //calculate x intercept and check its on both lines
+ xc = ((bars[i].co * dirx) - (co * bars[i].dx)) / slope;
+
+ if ((xc >= xmin-1) && (xc <= xmax+1)) //skip if not on module
+ {
+ if ((xc >= bars[i].xmin-1) && (xc <= bars[i].xmax+1)) //skip if not on line
+ {
+
+ yc = ((bars[i].co * diry) - (co * bars[i].dy)) / slope;
+
+ if ((yc >= ymin-1) && (yc <= ymax+1)) //skip if not on module
+ {
+ if ((yc >= bars[i].ymin-1) && (yc <= bars[i].ymax+1)) //skip if not on line
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+
+int32 HorizCheck(int32 x1 , int32 y , int32 x2)
+{
+ int32 dy;
+ int32 i;
+ int32 xc;
+ int32 xmin;
+ int32 xmax;
+ int32 linesCrossed = 1;
+
+ if (x1 > x2)
+ {
+ xmin = x2;
+ xmax = x1;
+ }
+ else
+ {
+ xmin = x1;
+ xmax = x2;
+ }
+ //line set to go one step in chosen direction
+ //so ignore if it hits anything
+
+ i = 0;
+ do
+ {
+ // this is the inner inner loop
+ if ((xmax >= bars[i].xmin) && ( xmin <= bars[i].xmax)) //skip if not on module
+ {
+ if ((y >= bars[i].ymin) && ( y <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ if (bars[i].dy == 0)
+ {
+ linesCrossed = 0;
+ }
+ else
+ {
+ dy = y-bars[i].y1;
+ xc = bars[i].x1 + (bars[i].dx * dy)/bars[i].dy;
+ if ((xc >= xmin-1) && (xc <= xmax+1)) //skip if not on module
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+
+int32 VertCheck(int32 x, int32 y1, int32 y2)
+{
+ int32 dx;
+ int32 i;
+ int32 yc;
+ int32 ymin;
+ int32 ymax;
+ int32 linesCrossed = 1;
+
+ if (y1 > y2)
+ {
+ ymin = y2;
+ ymax = y1;
+ }
+ else
+ {
+ ymin = y1;
+ ymax = y2;
+ }
+ //line set to go one step in chosen direction
+ //so ignore if it hits anything
+ i = 0;
+ do // this is the inner inner loop
+ {
+ if ((x >= bars[i].xmin) && ( x <= bars[i].xmax)) //overlapping
+ {
+ if ((ymax >= bars[i].ymin) && ( ymin <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ if (bars[i].dx == 0)//both lines vertical and overlap in x and y so they cross
+ {
+ linesCrossed = 0;
+ }
+ else
+ {
+ dx = x-bars[i].x1;
+ yc = bars[i].y1 + (bars[i].dy * dx)/bars[i].dx;
+ if ((yc >= ymin-1) && (yc <= ymax+1)) //the intersept overlaps
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+int32 CheckTarget(int32 x , int32 y)
+/*******************************************************************************
+ *******************************************************************************/
+{
+ int32 dx;
+ int32 dy;
+ int32 i;
+ int32 xc;
+ int32 yc;
+ int32 xmin;
+ int32 xmax;
+ int32 ymin;
+ int32 ymax;
+ int32 onLine = 0;
+
+ xmin = x - 1;
+ xmax = x + 1;
+ ymin = y - 1;
+ ymax = y + 1;
+
+ // check if point +- 1 is on the line
+ //so ignore if it hits anything
+
+ i = 0;
+ do
+ {
+
+ // this is the inner inner loop
+
+ if ((xmax >= bars[i].xmin) && ( xmin <= bars[i].xmax)) //overlapping line
+ {
+ if ((ymax >= bars[i].ymin) && ( ymin <= bars[i].ymax)) //overlapping line
+ {
+
+ // okay this line overlaps the target calculate an y intersept for x
+
+ if (bars[i].dx == 0)// vertical line so we know it overlaps y
+ {
+ yc = 0;
+ }
+ else
+ {
+ dx = x-bars[i].x1;
+ yc = bars[i].y1 + (bars[i].dy * dx)/bars[i].dx;
+ }
+
+ if ((yc >= ymin) && (yc <= ymax)) //overlapping point for y
+ {
+ onLine = 3;// target on a line so drop out
+ //Zdebug("RouteFail due to target on a line %d %d",x,y);
+ }
+ else
+ {
+ if (bars[i].dy == 0)// vertical line so we know it overlaps y
+ {
+ xc = 0;
+ }
+ else
+ {
+ dy = y-bars[i].y1;
+ xc = bars[i].x1 + (bars[i].dx * dy)/bars[i].dy;
+ }
+
+ if ((xc >= xmin) && (xc <= xmax)) //skip if not on module
+ {
+ onLine = 3;// target on a line so drop out
+ //Zdebug("RouteFail due to target on a line %d %d",x,y);
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while((i < nbars) && (onLine == 0));
+
+
+ return onLine;
+}
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE SETUP ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+//------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------
+
+void LoadWalkData(Object_walkdata *ob_walkdata)
+{
+ uint8 direction;
+ uint16 firstFrameOfDirection;
+ uint16 walkFrameNo;
+ uint32 frameCounter = 0; // starts at frame 0 of mega set (16sep96 JEL)
+
+
+ nWalkFrames = ob_walkdata->nWalkFrames;
+ usingStandingTurnFrames = ob_walkdata->usingStandingTurnFrames;
+ usingWalkingTurnFrames = ob_walkdata->usingWalkingTurnFrames;
+ usingSlowInFrames = ob_walkdata->usingSlowInFrames;
+ usingSlowOutFrames = ob_walkdata->usingSlowOutFrames;
+ numberOfSlowOutFrames = usingSlowOutFrames; // 0 = not using slow out frames; non-zero = using that many frames for each leading leg for each direction
+
+ memcpy(&numberOfSlowInFrames[0],ob_walkdata->nSlowInFrames,NO_DIRECTIONS*sizeof(numberOfSlowInFrames[0]));
+ memcpy(&leadingLeg[0],ob_walkdata->leadingLeg,NO_DIRECTIONS*sizeof(leadingLeg[0]));
+ memcpy(&dx[0],ob_walkdata->dx,NO_DIRECTIONS*(nWalkFrames+1)*sizeof(dx[0]));
+ memcpy(&dy[0],ob_walkdata->dy,NO_DIRECTIONS*(nWalkFrames+1)*sizeof(dy[0]));
+
+ //---------------------------------------------------------
+
+ for (direction=0; direction<NO_DIRECTIONS; direction++)
+ {
+ firstFrameOfDirection = direction * nWalkFrames;
+
+ modX[direction]=0;
+ modY[direction]=0;
+
+ for (walkFrameNo=firstFrameOfDirection; walkFrameNo < (firstFrameOfDirection + (nWalkFrames/2)); walkFrameNo++ )
+ {
+ modX[direction] += dx[walkFrameNo]; // eg. modX[0] is the sum of the x-step sizes for the first half of the walk cycle for direction 0
+ modY[direction] += dy[walkFrameNo];
+ }
+ }
+
+ diagonalx = modX[3];
+ diagonaly = modY[3];
+
+ //----------------------------------------------------
+ // interpret the walk data
+ //----------------------------------------------------
+
+ framesPerStep = nWalkFrames/2;
+ framesPerChar = nWalkFrames * NO_DIRECTIONS;
+
+ // offset pointers added Oct 30 95 JPS
+ // mega id references removed 16sep96 by JEL
+
+ //---------------------
+ // WALK FRAMES
+ // start on frame 0
+ frameCounter += framesPerChar;
+
+ //---------------------
+ // STAND FRAMES
+ firstStandFrame = frameCounter; // stand frames come after the walk frames
+ frameCounter += NO_DIRECTIONS; // one stand frame for each direction
+
+ //---------------------
+ // STANDING TURN FRAMES - OPTIONAL!
+ if (usingStandingTurnFrames)
+ {
+ firstStandingTurnLeftFrame = frameCounter; // standing turn-left frames come after the slow-out frames
+ frameCounter += NO_DIRECTIONS; // one for each direction
+
+ firstStandingTurnRightFrame = frameCounter; // standing turn-left frames come after the standing turn-right frames
+ frameCounter += NO_DIRECTIONS; // one for each direction
+ }
+ else
+ {
+ firstStandingTurnLeftFrame = firstStandFrame; // refer instead to the normal stand frames
+ firstStandingTurnRightFrame = firstStandFrame; // -"-
+ }
+ //---------------------
+ // WALKING TURN FRAMES - OPTIONAL!
+ if (usingWalkingTurnFrames)
+ {
+ firstWalkingTurnLeftFrame = frameCounter; // walking left-turn frames come after the stand frames
+ frameCounter += framesPerChar;
+
+ firstWalkingTurnRightFrame = frameCounter; // walking right-turn frames come after the walking left-turn frames
+ frameCounter += framesPerChar;
+ }
+ else
+ {
+ firstWalkingTurnLeftFrame = 0;
+ firstWalkingTurnRightFrame = 0;
+ }
+ //---------------------
+ // SLOW-IN FRAMES - OPTIONAL!
+
+ if (usingSlowInFrames) // slow-in frames come after the walking right-turn frames
+ {
+ for (direction=0; direction<NO_DIRECTIONS; direction++)
+ {
+ firstSlowInFrame[direction] = frameCounter; // make note of frame number of first slow-in frame for each direction
+ frameCounter += numberOfSlowInFrames[direction]; // can be a different number of slow-in frames in each direction
+ }
+ }
+ //---------------------
+ // SLOW-OUT FRAMES - OPTIONAL!
+
+ if (usingSlowOutFrames)
+ {
+ firstSlowOutFrame = frameCounter; // slow-out frames come after the slow-in frames
+ }
+ //---------------------
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE ROUTE EXTRACTOR
+ *******************************************************************************
+ *******************************************************************************/
+
+void ExtractRoute()
+/****************************************************************************
+ * ExtractRoute gets route from the node data after a full scan, route is
+ * written with just the basic way points and direction options for heading
+ * to the next point.
+ ****************************************************************************/
+{
+ int32 prev;
+ int32 prevx;
+ int32 prevy;
+ int32 last;
+ int32 point;
+ int32 p;
+ int32 dirx;
+ int32 diry;
+ int32 dir;
+ int32 dx;
+ int32 dy;
+
+
+ // extract the route from the node data
+ prev = nnodes;
+ last = prev;
+ point = O_ROUTE_SIZE - 1;
+ route[point].x = node[last].x;
+ route[point].y = node[last].y;
+ do
+ {
+ point = point - 1;
+ prev = node[last].prev;
+ prevx = node[prev].x;
+ prevy = node[prev].y;
+ route[point].x = prevx;
+ route[point].y = prevy;
+ last = prev;
+ }
+ while (prev > 0);
+
+ // now shuffle route down in the buffer
+ routeLength = 0;
+ do
+ {
+ route[routeLength].x = route[point].x;
+ route[routeLength].y = route[point].y;
+ point = point + 1;
+ routeLength = routeLength + 1;
+ }
+ while (point < O_ROUTE_SIZE);
+ routeLength = routeLength - 1;
+
+ // okay the route exists as a series point now put in some directions
+ p = 0;
+ do
+ {
+ #ifdef PLOT_PATHS
+ BresenhamLine(route[p+1].x-128,route[p+1].y-128, route[p].x-128,route[p].y-128, (uint8*)screen_ad, true_pixel_size_x, pixel_size_y, ROUTE_END_FLAG);
+ #endif
+ dx = route[p+1].x - route[p].x;
+ dy = route[p+1].y - route[p].y;
+ dirx = 1;
+ diry = 1;
+ if (dx < 0)
+ {
+ dx = -dx;
+ dirx = -1;
+ }
+ if (dy < 0)
+ {
+ dy = -dy;
+ diry = -1;
+ }
+
+ if ((diagonaly * dx) > (diagonalx * dy)) // dir = 1,2 or 2,3 or 5,6 or 6,7
+ {
+ dir = 4 - 2 * dirx; // 2 or 6
+ route[p].dirS = dir;
+ dir = dir + diry * dirx; // 1,3,5 or 7
+ route[p].dirD = dir;
+ }
+ else // dir = 7,0 or 0,1 or 3,4 or 4,5
+ {
+ dir = 2 + 2 * diry; // 0 or 4
+ route[p].dirS = dir;
+ dir = 4 - 2 * dirx; // 2 or 6
+ dir = dir + diry * dirx; // 1,3,5 or 7
+ route[p].dirD = dir;
+ }
+ p = p + 1;
+ }
+ while (p < (routeLength));
+ // set the last dir to continue previous route unless specified
+ if (targetDir == 8) // ANY direction
+ {
+ route[p].dirS = route[p-1].dirS;
+ route[p].dirD = route[p-1].dirD;
+ }
+ else
+ {
+ route[p].dirS = targetDir;
+ route[p].dirD = targetDir;
+ }
+ return;
+}
+
+//*******************************************************************************
+
+void RouteLine(int32 x1,int32 y1,int32 x2,int32 y2 ,int32 colour)
+{
+ if (x1);
+ if (x2);
+ if (y1);
+ if (y2);
+ if (colour);
+// BresenhamLine(x1-128, y1-128, x2-128, y2-128, (uint8*)screen_ad, true_pixel_size_x, pixel_size_y, colour);
+ return;
+}
+
+//*******************************************************************************
+
+void SetUpWalkGrid(Object_mega *ob_mega, int32 x, int32 y, int32 dir)
+{
+ int32 i;
+
+
+ LoadWalkGrid(); // get walk grid file + extra grid into 'bars' & 'node' arrays
+
+
+ // copy the mega structure into the local variables for use in all subroutines
+
+ startX = ob_mega->feet_x;
+ startY = ob_mega->feet_y;
+ startDir = ob_mega->current_dir;
+ targetX = x;
+ targetY = y;
+ targetDir = dir;
+
+ scaleA = ob_mega->scale_a;
+ scaleB = ob_mega->scale_b;
+
+
+ // mega's current position goes into first node
+ node[0].x = startX;
+ node[0].y = startY;
+ node[0].level = 1;
+ node[0].prev = 0;
+ node[0].dist = 0;
+
+ // reset other nodes
+ for (i=1; i<nnodes; i++)
+ {
+ node[i].level = 0;
+ node[i].prev = 0;
+ node[i].dist = 9999;
+ }
+
+ // target position goes into final node
+ node[nnodes].x = targetX;
+ node[nnodes].y = targetY;
+ node[nnodes].level = 0;
+ node[nnodes].prev = 0;
+ node[nnodes].dist = 9999;
+}
+
+//------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------
+void PlotWalkGrid(void)
+{
+ int32 j;
+
+
+ LoadWalkGrid(); // get walk grid file + extra grid into 'bars' & 'node' arrays
+
+ //-------------------------------
+ // lines
+
+ for (j=0; j<nbars; j++)
+ {
+ DrawLine(bars[j].x1,bars[j].y1, bars[j].x2,bars[j].y2, 254);
+ }
+ //-------------------------------
+ // nodes
+
+ for (j=1; j<nnodes; j++) // leave node 0 for start node
+ {
+ PlotCross(node[j].x,node[j].y, 184);
+ }
+ //-------------------------------
+}
+//------------------------------------------------------------------------------------------
+void PlotCross(int16 x, int16 y, uint8 colour)
+{
+ DrawLine(x-1, y-1, x+1, y+1, colour);
+ DrawLine(x+1, y-1, x-1, y+1, colour);
+}
+//------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------
+
+void LoadWalkGrid(void)
+{
+// _standardHeader header;
+ _walkGridHeader floorHeader;
+ uint32 j;
+ uint8 *fPolygrid;
+ int entry;
+ uint32 theseBars;
+ uint32 theseNodes;
+
+
+ nbars = 0; // reset counts
+ nnodes = 1; // leave node 0 for start-node
+
+ //-------------------------------
+ // STATIC GRIDS (added/removed by object logics)
+
+ for (entry=0; entry < MAX_WALKGRIDS; entry++) // go through walkgrid list
+ {
+ if (walkGridList[entry])
+ {
+ fPolygrid = res_man.Res_open(walkGridList[entry]); // open walk grid file
+
+ // memmove( (uint8*)&header, fPolygrid, sizeof(_standardHeader) );
+ fPolygrid += sizeof(_standardHeader);
+
+ memmove( (uint8*)&floorHeader, fPolygrid, sizeof(_walkGridHeader) );
+ fPolygrid += sizeof(_walkGridHeader);
+
+ //-------------------------------
+ // how many bars & nodes are we getting from this walkgrid file
+
+ theseBars = floorHeader.numBars;
+ theseNodes = floorHeader.numNodes;
+
+ //-------------------------------
+ // check that we're not going to exceed the max allowed in the complete walkgrid arrays
+
+ #ifdef _DEBUG
+ if ((nbars+theseBars) >= O_GRID_SIZE)
+ Con_fatal_error("Adding walkgrid(%d): %d+%d bars exceeds max %d (%s line %u)", walkGridList[entry], nbars, theseBars, O_GRID_SIZE, __FILE__, __LINE__);
+
+ if ((nnodes+theseNodes) >= O_GRID_SIZE)
+ Con_fatal_error("Adding walkgrid(%d): %d+%d nodes exceeds max %d (%s line %u)", walkGridList[entry], nnodes, theseBars, O_GRID_SIZE, __FILE__, __LINE__);
+ #endif
+
+ //-------------------------------
+ // lines
+
+ memmove( (uint8*)&bars[nbars], fPolygrid, theseBars*sizeof(_barData) );
+ fPolygrid += theseBars*sizeof(_barData);//move pointer to start of node data
+
+ //-------------------------------
+ // nodes
+
+ for (j=0; j<theseNodes; j++) // leave node 0 for start node
+ {
+ memmove( (uint8*)&node[nnodes+j].x, fPolygrid, 2*sizeof(int16) );
+ fPolygrid += 2*sizeof(int16);
+ }
+
+ //-------------------------------
+
+ res_man.Res_close(walkGridList[entry]); // close walk grid file
+
+ nbars += theseBars; // increment counts of total bars & nodes in whole walkgrid
+ nnodes += theseNodes;
+ }
+ }
+
+ //-------------------------------
+ // EXTRA GRIDS (moveable grids added by megas)
+
+ // Note that these will be checked against allowed max at the time of creating them
+
+ //-------------------------------
+ // extra lines
+
+ memmove((uint8 *) &bars[nbars], (uint8 *) &extraBars[0], nExtraBars*sizeof(_barData));
+ nbars += nExtraBars;
+
+ //-------------------------------
+ // extra nodes
+
+ memmove((uint8 *) &node[nnodes], (uint8 *) &extraNode[0], nExtraNodes*sizeof(_nodeData));
+ nnodes += nExtraNodes;
+
+ //-------------------------------
+}
+
+//------------------------------------------------------------------------------------------
+void ClearWalkGridList(void)
+{
+ int entry;
+
+ for (entry=0; entry < MAX_WALKGRIDS; entry++)
+ walkGridList[entry] = 0;
+}
+//------------------------------------------------------------------------------------------
+// called from FN_add_walkgrid
+void AddWalkGrid(int32 gridResource)
+{
+ int entry;
+
+ // first, scan list to see if this grid is already included
+ entry=0;
+ while ((entry < MAX_WALKGRIDS) && (walkGridList[entry] != gridResource))
+ entry++;
+
+ if (entry == MAX_WALKGRIDS) // if this new resource isn't already in the list, then add it, (otherwise finish)
+ {
+ // scan the list for a free slot
+ entry=0;
+ while ((entry < MAX_WALKGRIDS) && (walkGridList[entry]))
+ entry++;
+
+ if (entry < MAX_WALKGRIDS) // if we found a free slot
+ walkGridList[entry] = gridResource;
+ else
+ Con_fatal_error("ERROR: walkGridList[] full in %s line %d",__FILE__,__LINE__);
+ }
+}
+//--------------------------------------------------------------------------------------
+// called from FN_remove_walkgrid
+void RemoveWalkGrid(int32 gridResource)
+{
+ int entry;
+
+ // first, scan list to see if this grid is actually there
+ entry=0;
+ while ((entry < MAX_WALKGRIDS) && (walkGridList[entry] != gridResource))
+ entry++;
+
+ if (entry < MAX_WALKGRIDS) // if we've found it in the list, reset entry to zero (otherwise just ignore the request)
+ walkGridList[entry] = 0;
+}
+//--------------------------------------------------------------------------------------
+
diff --git a/sword2/router.h b/sword2/router.h
new file mode 100644
index 0000000000..447bdc9d33
--- /dev/null
+++ b/sword2/router.h
@@ -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
diff --git a/sword2/save_rest.cpp b/sword2/save_rest.cpp
new file mode 100644
index 0000000000..10a374a7a3
--- /dev/null
+++ b/sword2/save_rest.cpp
@@ -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);
+}
diff --git a/sword2/save_rest.h b/sword2/save_rest.h
new file mode 100644
index 0000000000..b59c52fe45
--- /dev/null
+++ b/sword2/save_rest.h
@@ -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
diff --git a/sword2/scroll.cpp b/sword2/scroll.cpp
new file mode 100644
index 0000000000..65148e00f3
--- /dev/null
+++ b/sword2/scroll.cpp
@@ -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);
+}
+//------------------------------------------------------------------------------------
+
diff --git a/sword2/scroll.h b/sword2/scroll.h
new file mode 100644
index 0000000000..649ffb71f1
--- /dev/null
+++ b/sword2/scroll.h
@@ -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
diff --git a/sword2/sound.cpp b/sword2/sound.cpp
new file mode 100644
index 0000000000..e355d8f412
--- /dev/null
+++ b/sword2/sound.cpp
@@ -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);
+}
+//--------------------------------------------------------------------------------------
+
diff --git a/sword2/sound.h b/sword2/sound.h
new file mode 100644
index 0000000000..bca28ad66f
--- /dev/null
+++ b/sword2/sound.h
@@ -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
diff --git a/sword2/speech.cpp b/sword2/speech.cpp
new file mode 100644
index 0000000000..b7101c2c0b
--- /dev/null
+++ b/sword2/speech.cpp
@@ -0,0 +1,1994 @@
+/* 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 <io.h> // for access()
+#include <stdio.h>
+
+//#include "src\driver96.h"
+#include "anims.h"
+#include "console.h"
+#include "controls.h" // for 'subtitles' & 'speechSelected'
+#include "debug.h"
+#include "defs.h"
+#include "events.h"
+#include "function.h"
+#include "interpreter.h"
+#include "layers.h" // for 'this_screen'
+#include "logic.h"
+#include "maketext.h"
+#include "memory.h"
+#include "mouse.h"
+#include "object.h"
+#include "protocol.h"
+#include "resman.h"
+#include "sound.h"
+#include "speech.h"
+#include "walker.h"
+//------------------------------------------------------------------------------------
+
+#define INS_talk 1
+#define INS_anim 2
+#define INS_reverse_anim 3
+#define INS_walk 4
+#define INS_turn 5
+#define INS_face 6
+#define INS_trace 7
+#define INS_no_sprite 8
+#define INS_sort 9
+#define INS_foreground 10
+#define INS_background 11
+#define INS_table_anim 12
+#define INS_reverse_table_anim 13
+#define INS_walk_to_anim 14
+#define INS_set_frame 15
+#define INS_stand_after_anim 16
+
+#define INS_quit 42
+
+//------------------------------------------------------------------------------------
+
+uint32 speech_time=0; //when not playing a wav we calculate the speech time based upon length of ascii
+
+uint32 speech_text_bloc_no=0;
+uint32 anim_id=0;
+uint32 speech_anim_type; //0 lip synced and repeating - 1 normal once through
+uint32 left_click_delay=0; // click-delay for LEFT mouse button
+uint32 right_click_delay=0; // click-delay for RIGHT mouse button
+
+uint32 default_response_id=0; // ref number for default response when luggage icon is used on a person
+ // & it doesn't match any of the icons which would have been in the chooser
+int16 officialTextNumber=0; // "TEXT" - current official text line number - will match the wav filenames
+
+int32 speechScriptWaiting = 0; // usually 0; if non-zero then it's the id of whoever we're waiting for in a speech script
+ // see FN_they_do, FN_they_do_we_wait & FN_we_wait
+
+int16 text_x, text_y; // calculated by LocateTalker() for use in speech-panning & text-sprite positioning
+
+_subject_unit subject_list[MAX_SUBJECT_LIST];
+
+
+//------------------------------------------------------------------------------------
+// local function prototypes
+
+int32 FN_i_speak(int32 *params);
+void LocateTalker(int32 *params); // (James 01july97)
+void Form_text(int32 *params); //Tony18Oct96
+BOOL Is_anim_boxed(uint32 res); //Tony20Oct96
+uint8 WantSpeechForLine(uint32 wavId); // James (29july97)
+
+#ifdef _DEBUG
+void GetCorrectCdForSpeech(int32 wavId); // for testing speech & text
+#endif
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+int32 FN_add_subject(int32 *params) // James12nov96 / Tony18Nov96
+{
+// param[0] id
+// param[1] daves reference number
+
+ if (IN_SUBJECT==0) // if this is the start of the new subject list (James 07may97)
+ default_response_id=0; // set the default repsonse id to zero in case we're never passed one
+ // - this just means we'd get the response for the 1st icon in the chooser
+ // which is better than crashing
+
+ if (params[0] == -1) // this isn't an icon at all, it's telling us the id of the default response
+ {
+ default_response_id = params[1]; // and here it is - this is the ref number we will return if
+ // a luggage icon is clicked on someone when it wouldn't have
+ // been in the chooser list (see FN_choose below)
+ }
+ else
+ {
+ subject_list[IN_SUBJECT].res=params[0];
+ subject_list[IN_SUBJECT].ref=params[1];
+
+// Zdebug("FN_add_subject res %d, uid %d", params[0], params[1]);
+
+ IN_SUBJECT+=1;
+ }
+
+
+ return(IR_CONT); // continue script
+}
+//------------------------------------------------------------------------------------
+int choosing=0; //could alternately use logic->looping of course
+
+int32 FN_choose(int32 *params) //Tony19Nov96
+{
+//no params
+
+//the human is switched off so there will be no normal mouse engine
+
+
+ _mouseEvent *me;
+ uint32 j,hit;
+ uint8 *icon;
+ uint32 pos=0;
+
+// Zdebug("into choose");
+
+
+ AUTO_SELECTED=0; // see below (James23may97)
+
+
+ //-------------------------------------------
+ // new thing to intercept objects held at time of clicking on a person
+ // (James 06may97)
+
+ if (OBJECT_HELD) // if we are using a luggage icon on the person
+ {
+ // scan the subject list to see if this icon would have been available at this time
+ // if it is there, return the relevant 'ref' number (as if it had been selected from within the conversation)
+ // if not, just return a special code to get the default text line(s) for unsupported objects
+ // Note that we won't display the subject icons in this case!
+
+ while (pos < IN_SUBJECT) // scan the subject list for a match with our 'object_held'
+ {
+ if (subject_list[pos].res == OBJECT_HELD) // if we've found a match
+ {
+ OBJECT_HELD=0; // clear it so it doesn't keep happening!
+ IN_SUBJECT=0; // clear the subject list
+ return(IR_CONT+(subject_list[pos].ref<<3)); // return special subject chosen code (same as in normal chooser routine below)
+ }
+ pos++; // next position
+ }
+
+ OBJECT_HELD=0; // clear it so it doesn't keep happening!
+ IN_SUBJECT=0; // clear the subject list
+ return(IR_CONT+(default_response_id<<3)); // so that the speech script uses the default text for objects that are not accounted for
+ }
+ //-------------------------------------------
+ // new thing for skipping chooser with "nothing else to say" text
+ // (James 23may97)
+
+ // If this is the 1st time the chooser is coming up in this conversation
+ // AND there's only 1 subject
+ // AND it's the EXIT icon
+ if ((CHOOSER_COUNT_FLAG==0) && (IN_SUBJECT==1) && (subject_list[0].res == EXIT_ICON))
+ {
+ AUTO_SELECTED=1; // for speech script
+
+ IN_SUBJECT=0; // clear the subject list
+ return(IR_CONT+(subject_list[0].ref<<3)); // return special subject chosen code (same as in normal chooser routine below)
+ }
+ //-------------------------------------------
+
+
+ if (!choosing) //new choose session
+ {
+
+
+// build menus from subject_list
+
+ if (!IN_SUBJECT)
+ Con_fatal_error("FN_choose with no subjects :-O");
+
+//init top menu from master list
+ for (j=0;j<15;j++) //all icons are highlighted / full colour
+ {
+ if (j<IN_SUBJECT)
+ {
+// Zdebug(" ICON res %d for %d", subject_list[j].res, j);
+ icon = res_man.Res_open( subject_list[j].res ) + sizeof(_standardHeader) + RDMENU_ICONWIDE*RDMENU_ICONDEEP;
+ SetMenuIcon(RDMENU_BOTTOM, j, icon);
+ res_man.Res_close( subject_list[j].res );
+ }
+ else
+ { SetMenuIcon(RDMENU_BOTTOM, j, NULL); //no icon here
+ //Zdebug(" NULL for %d", j);
+ }
+ }
+
+// start menus appearing
+ ShowMenu(RDMENU_BOTTOM);
+
+
+// lets have the mouse pointer back
+ Set_mouse(NORMAL_MOUSE_ID);
+
+ choosing=1;
+
+ return(IR_REPEAT); //again next cycle
+ }
+
+ else //menu is there - we're just waiting for a click
+ {
+// Zdebug("choosing");
+ me = MouseEvent(); //get mouse event
+
+// we only care about left clicks
+// we ignore mouse releases
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN))
+ {
+// check for click on a menu
+// if so then end the choose, highlight only the chosen, blank the mouse and return the ref code *8
+
+ if ((mousey>399)&&(mousex>=24)&&(mousex<640-24))
+ {
+ hit=(mousex-24)/40; //which are we over?
+
+ if (hit<IN_SUBJECT) //clicked on something - what button?
+ {
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"----------------------");
+ Zdebug(0,"Icons available:");
+ #endif
+ //--------------------------------------
+
+ for (j=0;j<IN_SUBJECT;j++) //change icons
+ {
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"%s", FetchObjectName(subject_list[j].res));
+ #endif
+ //--------------------------------------
+
+ if (j!=hit) //change all others to grey
+ {
+ icon = res_man.Res_open( subject_list[j].res ) + sizeof(_standardHeader); //now grey
+ SetMenuIcon(RDMENU_BOTTOM, j, icon);
+ res_man.Res_close( subject_list[j].res );
+ }
+ }
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"Selected: %s", FetchObjectName(subject_list[hit].res));
+ Zdebug(0,"----------------------");
+ #endif
+ //--------------------------------------
+
+ choosing=0; //this is our looping flag
+
+ IN_SUBJECT=0;
+
+ Set_mouse(NULL); //blank mouse again
+
+// Zdebug("hit %d - ref %d ref*8 %d", hit, subject_list[hit].ref, subject_list[hit].ref*8);
+
+ RESULT=subject_list[hit].res; //for non-speech scripts that manually call the chooser
+
+ return(IR_CONT+(subject_list[hit].ref<<3)); //return special subject chosen code
+ }
+ }
+ }
+// Zdebug("end choose");
+ return(IR_REPEAT); //again next cycle
+ }
+}
+//------------------------------------------------------------------------------------
+int32 FN_start_conversation(int32 *params) //Tony27Nov96
+{
+//Start conversation
+
+//FN_no_human(); // an FN_no_human
+//FN_change_speech_text (PLAYER, GEORGE_WIDTH, GEORGE_PEN );
+
+//params: 0 <empty>
+
+// Zdebug("FN_start_conversation %d", ID);
+
+ //--------------------------------------------------------------
+ // reset 'chooser_count_flag' at the start of each conversation:
+
+ // Note that FN_start_conversation might accidently be called
+ // every time the script loops back for another chooser
+ // but we only want to reset the chooser count flag the first time this function is called
+ // ie. when talk flag is zero
+ if (TALK_FLAG==0)
+ CHOOSER_COUNT_FLAG=0; // see FN_chooser & speech scripts
+ //--------------------------------------------------------------
+
+ FN_no_human(params);
+
+ return(IR_CONT);
+}
+//------------------------------------------------------------------------------------
+int32 FN_end_conversation(int32 *params) //Tony27Nov96
+{
+//end conversation
+//talk_flag=0;
+//FN_end_chooser();
+//FN_add_human();
+//FN_change_speech_text (PLAYER, VOICE_OVER_WIDTH, VOICE_OVER_PEN );
+//FN_idle();
+//params: 0 <empty>
+
+
+// Zdebug("FN_end_conversation");
+
+ HideMenu(RDMENU_BOTTOM);
+
+ if (mousey>399)
+ { mouse_mode=MOUSE_holding; //will wait for cursor to move off the bottom menu
+ Zdebug(" holding");
+ }
+
+ TALK_FLAG=0; //in-case DC forgets
+
+
+// restart george's base script
+// LLogic.Total_restart();
+
+ if (params);
+
+ return(IR_CONT); //drop out without saving pc and go around again
+}
+//------------------------------------------------------------------------------------
+int32 FN_they_do(int32 *params) //S2.1(18Jan95tw) Tony3Dec96
+{
+//doesn't send the command until target is waiting - once sent we carry on
+
+//params 0 target
+// 1 command
+// 2 ins1
+// 3 ins2
+// 4 ins3
+// 5 ins4
+// 6 ins5
+
+ uint32 null_pc=5; //4th script - get-speech-state
+ char *raw_script_ad;
+ _standardHeader *head;
+ int32 target=params[0];
+
+
+//request status of target
+ head = (_standardHeader*) res_man.Res_open(target);
+ if (head->fileType!=GAME_OBJECT)
+ Con_fatal_error("FN_they_do %d not an object", target);
+
+ 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(target);
+
+//result is 1 for waiting, 0 for busy
+
+ if ((RESULT==1)&&(!INS_COMMAND)) //its waiting and no other command is queueing
+ {
+ speechScriptWaiting = 0; // reset debug flag now that we're no longer waiting - see debug.cpp
+
+ SPEECH_ID = params[0];
+ INS_COMMAND = params[1];
+ INS1 = params[2];
+ INS2 = params[3];
+ INS3 = params[4];
+ INS4 = params[5];
+ INS5 = params[6];
+
+ return(IR_CONT); //script cont
+ }
+
+ speechScriptWaiting = target; // debug flag to indicate who we're waiting for - see debug.cpp
+ return(IR_REPEAT); // target is busy so come back again next cycle
+}
+//------------------------------------------------------------------------------------
+int32 FN_they_do_we_wait(int32 *params) //Tony3Dec96
+{
+//give target a command and wait for it to register as finished
+
+//params 0 pointer to ob_logic
+// 1 target
+// 2 command
+// 3 ins1
+// 4 ins2
+// 5 ins3
+// 6 ins4
+// 7 ins5
+
+//'looping' flag is used as a sent command yes/no
+
+ Object_logic *ob_logic;
+
+ uint32 null_pc=5; //4th script - get-speech-state
+ char *raw_script_ad;
+ _standardHeader *head;
+ int32 target=params[1];
+
+
+// Zdebug("FN_they_do_we_wait id %d, command %d", params[1], params[2]);
+
+
+// ok, see if the target is busy - we must request this info from the target object
+ head = (_standardHeader*) res_man.Res_open(target);
+ if (head->fileType!=GAME_OBJECT)
+ Con_fatal_error("FN_they_do_we_wait %d not an object", target);
+
+ 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(target);
+
+
+
+
+
+ ob_logic = (Object_logic *)params[0];
+
+ if ((!INS_COMMAND)&&(RESULT==1)&&(ob_logic->looping==0)) //first time so set up targets command if target is waiting
+ {
+
+// Zdebug("FNtdww sending command to %d", target);
+
+ SPEECH_ID = params[1];
+ INS_COMMAND = params[2];
+ INS1 = params[3];
+ INS2 = params[4];
+ INS3 = params[5];
+ INS4 = params[6];
+ INS5 = params[7];
+
+ ob_logic->looping=1;
+
+ speechScriptWaiting = target; // debug flag to indicate who we're waiting for - see debug.cpp
+ return(IR_REPEAT); // finish this cycle - but come back again to check for it being finished
+ }
+ else if (ob_logic->looping==0) //did not send the command
+ {
+ speechScriptWaiting = target; // debug flag to indicate who we're waiting for - see debug.cpp
+ return(IR_REPEAT); // come back next go and try again to send the instruction
+ }
+
+
+//ok, the command has been sent - has the target actually done it yet?
+
+//result is 1 for waiting, 0 for busy
+
+ if (RESULT==1) // its waiting now so we can be finished with all this
+ {
+// Zdebug("FNtdww finished");
+ ob_logic->looping=0; // not looping anymore
+
+ speechScriptWaiting = 0; // reset debug flag now that we're no longer waiting - see debug.cpp
+ return(IR_CONT); // script cont
+ }
+
+// Zdebug("FNtdww just waiting");
+
+ speechScriptWaiting = target; // debug flag to indicate who we're waiting for - see debug.cpp
+ return(IR_REPEAT); // see ya next cycle
+}
+//------------------------------------------------------------------------------------
+int32 FN_we_wait(int32 *params) //Tony3Dec96
+{
+//loop until the target is free
+
+//params 0 target
+
+ uint32 null_pc=5; //4th script - get-speech-state
+ char *raw_script_ad;
+ _standardHeader *head;
+ int32 target=params[0];
+
+//request status of target
+ head = (_standardHeader*) res_man.Res_open(target);
+ if (head->fileType!=GAME_OBJECT)
+ Con_fatal_error("FN_we_wait %d not an object", target);
+
+ 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(target);
+
+//result is 1 for waiting, 0 for busy
+
+ if (RESULT==1)
+ {
+ speechScriptWaiting = 0; // reset debug flag now that we're no longer waiting - see debug.cpp
+ return(IR_CONT); // script cont
+ }
+
+ speechScriptWaiting = target; // debug flag to indicate who we're waiting for - see debug.cpp
+ return(IR_REPEAT); // target is busy so come back again next cycle
+}
+//------------------------------------------------------------------------------------
+int32 FN_timed_wait(int32 *params) //Tony12Dec96
+{
+//loop until the target is free but only while the timer is high
+//useful when clicking on a target to talk to them - if they never reply then this'll fall out avoiding a lock up
+
+//params 0 ob_logic
+// 1 target
+// 2 number of cycles before give up
+
+ uint32 null_pc=5; //4th script - get-speech-state
+ char *raw_script_ad;
+ Object_logic *ob_logic;
+ _standardHeader *head;
+ int32 target=params[1];
+
+
+ ob_logic = (Object_logic *)params[0];
+
+
+ if (!ob_logic->looping)
+ ob_logic->looping=params[2]; //first time in
+
+
+//request status of target
+ head = (_standardHeader*) res_man.Res_open(target);
+ if (head->fileType!=GAME_OBJECT)
+ Con_fatal_error("FN_timed_wait %d not an object", target);
+
+ 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(target);
+
+//result is 1 for waiting, 0 for busy
+
+ ob_logic->looping--;
+
+ if (RESULT==1) //its waiting
+ {
+ ob_logic->looping=0; //reset because counter is likely to be still high
+ RESULT=0; //means ok
+
+ speechScriptWaiting = 0; // reset debug flag now that we're no longer waiting - see debug.cpp
+ return(IR_CONT); // script cont
+ }
+
+
+ if (!ob_logic->looping) //time up - caller must check RESULT
+ {
+
+ RESULT=1; //not ok
+
+// kill the event
+
+ Kill_all_ids_events(target); //clear the event that hasn't been picked up - in theory, none of this should ever happen
+
+ Zdebug("EVENT timed out");
+
+ speechScriptWaiting = 0; // reset debug flag now that we're no longer waiting - see debug.cpp
+ return(IR_CONT); //script cont
+ }
+
+ speechScriptWaiting = target; // debug flag to indicate who we're waiting for - see debug.cpp
+ return(IR_REPEAT); // target is busy so come back again next cycle
+}
+//------------------------------------------------------------------------------------
+int32 FN_speech_process(int32 *params) //Tony5Dec96
+{
+//recieve and sequence the commands sent from the conversation script
+//we have to do this in a slightly tweeky manner as we can no longer have generic scripts
+//this function comes in with all the structures that will be required
+
+//param 0 pointer to ob_graphic
+//param 1 pointer to ob_speech
+//param 2 pointer to ob_logic
+//param 3 pointer to ob_mega
+//param 4 pointer to ob_walkdata
+
+//note - we could save a var and ditch wait_state and check 'command' for non zero means busy
+
+ Object_speech *ob_speech;
+
+ int32 pars[9];
+ int32 ret;
+
+
+ ob_speech = (Object_speech*) params[1];
+
+
+// Zdebug(" SP");
+
+ while(1)
+ {
+ if (ob_speech->command) //we are currently running a command
+ {
+ switch(ob_speech->command)
+ {
+ //----------------------------------------------
+ case INS_talk:
+
+ pars[0]=params[0]; //ob_graphic
+ pars[1]=params[1]; //ob_speech
+ pars[2]=params[2]; //ob_logic
+ pars[3]=params[3]; //ob_mega
+
+ pars[4]=ob_speech->ins1; //param 4 encoded text number
+ pars[5]=ob_speech->ins2; //param 5 wav res id
+ pars[6]=ob_speech->ins3; //param 6 anim res id
+ pars[7]=ob_speech->ins4; //param 7 anim table res id
+ pars[8]=ob_speech->ins5; //param 8 animation mode 0 lip synced, 1 just straight animation
+
+ // Zdebug("speech-process talk");
+
+ ret = FN_i_speak(pars); //run the function - (it thinks its been called from script - bloody fool)
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+// Zdebug("speech-process talk finished");
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_turn:
+
+ pars[0]=params[2]; // ob_logic
+ pars[1]=params[0]; // ob_graphic
+ pars[2]=params[3]; // ob_mega
+ pars[3]=params[4]; // ob_walkdata
+ pars[4]=ob_speech->ins1; // direction to turn to
+
+ ret = FN_turn(pars);
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_face:
+
+ pars[0]=params[2]; // ob_logic
+ pars[1]=params[0]; // ob_graphic
+ pars[2]=params[3]; // ob_mega
+ pars[3]=params[4]; // ob_walkdata
+ pars[4]=ob_speech->ins1; // target
+
+ ret = FN_face_mega(pars);
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_anim:
+
+ pars[0]=params[2]; //ob_logic
+ pars[1]=params[0]; //ob_graphic
+ pars[2]=ob_speech->ins1; //anim res
+
+ ret= FN_anim(pars);
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_reverse_anim:
+
+ pars[0]=params[2]; //ob_logic
+ pars[1]=params[0]; //ob_graphic
+ pars[2]=ob_speech->ins1; //anim res
+
+ ret= FN_reverse_anim(pars);
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_table_anim:
+
+ pars[0]=params[2]; //ob_logic
+ pars[1]=params[0]; //ob_graphic
+ pars[2]=params[3]; //ob_mega
+ pars[3]=ob_speech->ins1; //pointer to anim table
+
+ ret= FN_mega_table_anim(pars);
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_reverse_table_anim:
+
+ pars[0]=params[2]; //ob_logic
+ pars[1]=params[0]; //ob_graphic
+ pars[2]=params[3]; //ob_mega
+ pars[3]=ob_speech->ins1; //pointer to anim table
+
+ ret= FN_reverse_mega_table_anim(pars);
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_no_sprite:
+
+ FN_no_sprite(params); // ob_graphic;
+
+ ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+
+ return(IR_REPEAT);
+
+ //----------------------------------------------
+ case INS_sort:
+
+ FN_sort_sprite(params); // ob_graphic;
+
+ ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+
+ return(IR_REPEAT);
+
+ //----------------------------------------------
+ case INS_foreground:
+
+ FN_fore_sprite(params); // ob_graphic;
+
+ ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+
+ return(IR_REPEAT);
+
+ //----------------------------------------------
+ case INS_background:
+
+ FN_back_sprite(params); // ob_graphic;
+
+ ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+
+ return(IR_REPEAT);
+
+ //----------------------------------------------
+ case INS_walk:
+
+ pars[0]=params[2]; //ob_logic
+ pars[1]=params[0]; //ob_graphic
+ pars[2]=params[3]; //ob_mega
+ pars[3]=params[4]; //ob_walkdata
+
+ pars[4]=ob_speech->ins1; //target x
+ pars[5]=ob_speech->ins2; //target y
+ pars[6]=ob_speech->ins3; //target direction
+
+ ret= FN_walk(pars);
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+// Zdebug("speech-process walk finished");
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_walk_to_anim:
+
+ pars[0]=params[2]; //ob_logic
+ pars[1]=params[0]; //ob_graphic
+ pars[2]=params[3]; //ob_mega
+ pars[3]=params[4]; //ob_walkdata
+
+ pars[4]=ob_speech->ins1; // anim resource
+
+ ret= FN_walk_to_anim(pars);
+
+ if (ret!=IR_REPEAT)
+ { ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+// Zdebug("speech-process walk finished");
+ }
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_stand_after_anim:
+
+ pars[0]=params[0]; // ob_graphic
+ pars[1]=params[3]; // ob_mega
+ pars[2]=ob_speech->ins1; // anim resource
+
+ ret= FN_stand_after_anim(pars);
+
+ ob_speech->command=0; // command finished
+ ob_speech->wait_state=1; // waiting for command
+
+ return(IR_REPEAT); // come back again next cycle
+
+ //----------------------------------------------
+ case INS_set_frame:
+
+ pars[0]=params[0]; // ob_graphic
+ pars[1]=ob_speech->ins1; // anim_resource
+ pars[2]=ob_speech->ins2; // FIRST_FRAME or LAST_FRAME
+
+ ret= FN_set_frame(pars);
+
+ ob_speech->command=0; //command finished
+ ob_speech->wait_state=1; //waiting for command
+
+ return(IR_REPEAT); //come back again next cycle
+
+ //----------------------------------------------
+ case INS_quit:
+
+// Zdebug("speech-process - quit");
+ ob_speech->command=0; //finish with all this
+ // ob_speech->wait_state=0; //start with waiting for command next conversation
+ return(IR_CONT); //thats it, we're finished with this
+
+ //----------------------------------------------
+ default:
+
+ ob_speech->command=0; //not yet implemented - just cancel
+ ob_speech->wait_state=1; //waiting for command
+ break;
+
+ //----------------------------------------------
+ }
+ }
+
+
+
+ if (SPEECH_ID==ID) //new command for us!
+ {
+
+ SPEECH_ID=0; //clear this or it could trigger next go
+
+// grab the command - potentially, we only have this cycle to do this
+ ob_speech->command = INS_COMMAND;
+ ob_speech->ins1 = INS1;
+ ob_speech->ins2 = INS2;
+ ob_speech->ins3 = INS3;
+ ob_speech->ins4 = INS4;
+ ob_speech->ins5 = INS5;
+
+ INS_COMMAND=0; //the current send has been recieved - i.e. seperate multiple they-do's
+
+ ob_speech->wait_state=0; //now busy
+
+// Zdebug("received new command %d", INS_COMMAND);
+
+// we'll drop off and be caught by the while(1), so kicking in the new command straight away
+
+ }
+ else //no new command
+ {
+// we could run a blink anim (or something) here
+
+ ob_speech->wait_state=1; //now free
+ return(IR_REPEAT); //come back again next cycle
+ }
+ }
+
+
+}
+//------------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+#if 1==2
+
+
+ ooo l dddd sss ttttt u u fffff fffff
+o o l d d s t u u f f
+o o l d d sss t u u ffff ffff
+o o l d d s t u u f f
+o o l d d s s t u u f f
+o o l d d s s t u u f f
+ ooo llll dddd sss t uuu f f
+
+
+
+
+// ScriptReference 0,19
+mega_interact //standard interact protocol for megas who have been clicked on
+{ //replaces S2's mega_sss... (Jan95tw)
+
+ o_down_flag=0; //reset on entry - we dont know what this flag will be
+ //we will not be wiping a command because the player will
+ //not start until we signal - at the end of this loop...
+ //"smart" - readers voice
+ do
+ {
+ if (o_down_flag!=0) //recieved any instructions?
+
+ switch(o_down_flag)
+ {
+ //--------------------------------------------
+ case INS_talk: // (o_ins3=cdt or anim table, o_ins2=text id, o_ins1=graphic or 0)
+ {
+ FN_I_speak(o_ins3, o_ins2, o_ins1);
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_anim: //run coord-less anim (o_ins1=cdt or anim table, o_ins2=graphic or 0, o_ins3=0)
+ {
+ FN_anim( o_ins1, o_ins2 );
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+
+ case INS_full_anim: //run anim with coords (o_ins1=cdt o_ins2=graphic o_ins3=0)
+ {
+ FN_full_anim( o_ins1, o_ins2 );
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_walk: // walk to (o_ins1,o_ins2) & stand in direction 'o_ins3'
+ {
+ FN_walk(o_ins1,o_ins2,o_ins3,STAND);
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_turn: //turn/stand as specified
+ {
+ FN_turn(o_ins1,STAND); // turn to direction 'o_ins1'
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_face: //turn to face specified mega character
+ {
+ FN_face(o_ins1);
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_trace: // face compact id 'o_ins1' - continues until next command (because 'o_down_flag' not reset to zero)
+ {
+ FN_face(o_ins1);
+ o_down_flag=INS_trace; // do this again & again until a new command is received
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_no_sprite:
+ {
+ FN_no_sprite();
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_sort:
+ {
+ FN_sort();
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_foreground:
+ {
+ FN_foreground();
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_background:
+ {
+ FN_background();
+ o_down_flag=0;
+ }
+ break;
+
+ //--------------------------------------------
+ case INS_quit:
+ {
+ }
+ break; //fall out of outer loop
+
+ //--------------------------------------------
+ default:
+ {
+ FN_talk_error(); //shut the system down - I can't be bothered to recover from this
+ }
+ break;
+
+ //--------------------------------------------
+ }
+
+
+ FN_add_talk_wait_status_bit(); // add waiting bit to status for player to pickup
+ FN_quit(); // drop out of script until next cycle to see if new instructions have arrived
+ FN_remove_talk_wait_status_bit(); // off again, in case command received
+
+ }
+ while(o_down_flag!=INS_quit); //until we're told to terminate
+
+
+ FN_goto_bookmark(); //get the mega going again
+}
+//-----------------------------------------------------------------------------------------
+// ScriptReference 0,20
+
+mega_approach_script // George runs this script to get over to 'target_mega', who's already running 'mega_interact'
+{
+
+ //FN_they_do_we_wait(target_mega,INS_trace,GEORGE,0,0); // 'target_mega' repeatedly faces george while he walks over
+
+ FN_they_do_we_wait(target_mega,INS_face,GEORGE,0,0); // Mega turns to face George
+
+ FN_get_pos(target_mega);
+ target_x = return_value;
+ target_y = return_value_2;
+ distance_apart = return_value_4;
+
+ walk_attempt = 0; // keep count of attempts
+
+ if ((o_xcoord) < target_x) // If George is currently left of Duane
+ walk_flag = 0; // try LHS first
+ else
+ walk_flag = 1; // try RHS first
+
+
+ //--------------------------------------------------------
+ do
+ {
+ if (walk_flag==0) // (0) try LHS - & face DOWN_RIGHT
+ {
+ FN_walk(target_x-distance_apart,target_y,DOWN_RIGHT,STAND);
+
+ if (o_down_flag)
+ walk_flag=2; // made it
+ else
+ walk_flag=1; // try RHS next, or fail (to anywhere)
+ }
+
+ else // (1) try RHS & face DOWN_LEFT
+ {
+ FN_walk(target_x+distance_apart,target_y,DOWN_LEFT,STAND);
+
+ if (o_down_flag)
+ walk_flag=2; // made it
+ else
+ walk_flag=0; // try LHS next, or fail (to anywhere)
+ }
+
+ walk_attempt+=1;
+ }
+ while ((walk_flag<2)&&(walk_attempt<2)); // try again until we get there or we've tried both sides
+ //--------------------------------------------------------
+
+
+ if (walk_flag!=2) // if LHS & RHS both failed - try anywhere
+ {
+ FN_walk(target_x,target_y,ANY,STAND); // walk George to (near) Mega's coords
+ }
+
+
+ FN_we_wait(target_mega); // wait for Duane to be ready to receive a command
+
+ if ((o_xcoord) < target_x) // If George is now left of Duane
+ {
+ FN_they_do_we_wait(target_mega,INS_turn,DOWN_LEFT,0,0); // Mega faces DOWN_LEFT
+ FN_turn(DOWN_RIGHT, STAND); // George faces DOWN_RIGHT
+ }
+ else // George is now right of Duane
+ {
+ FN_they_do_we_wait(target_mega,INS_turn,DOWN_RIGHT,0,0); // Mega faces DOWN_LEFT
+ FN_turn(DOWN_LEFT, STAND); // George faces DOWN_RIGHT
+ }
+ //-----------------------------------------------------------------------------------
+}
+//------------------------------------------------------------------------------------
+int32 FN_they_do(object *compact, int32 id, int32 tar, int32 a, int32 b, int32 c, int32 d, int32 x) //S2.1(18Jan95tw)
+{
+ // NB. a, b & c could be resID's!! (25jul95 JEL)
+
+ object *target;
+
+ compact;id;x;
+
+ //Tdebug("FN_they_do %d %d %d %d %d", tar,a,b,c,d);
+
+ target = (object *) Lock_object(tar);
+
+ target->o_down_flag = a; // the actual instruction; INS_talk, INS_quit, etc.
+ target->o_ins1 = b; // and now the 3 parameters... (updated 24apr95JEL)
+ target->o_ins2 = c;
+ target->o_ins3 = d;
+
+ Unlock_object(tar);
+
+ return(1); //script cont
+}
+
+//--------------------------------------------------------------------------------------
+
+//send an instruction to mega we're talking to and wait until it has finished before
+//returning to script
+
+int32 FN_they_do_we_wait(object *compact, int32 id, int32 tar, int32 a, int32 b, int32 c, int32 d, int32 x)
+{ //S2.1(18Jan95tw)
+
+ // NB. a, b & c could be resID's!! (25jul95 JEL)
+
+ object *target;
+
+ compact;id;x;
+
+ //Tdebug("FN_they_do_we_wait %d %d %d %d %d", tar,a,b,c,d);
+
+ target = (object *) Lock_object(tar);
+
+ target->o_down_flag = a; // the actual instruction; INS_talk, INS_quit, etc.
+ target->o_ins1 = b; // and now the 3 parameters... (updated 24apr95JEL)
+ target->o_ins2 = c;
+ target->o_ins3 = d;
+
+ compact->o_logic = LOGIC_wait_for_talk; // we wait until they've finished
+ compact->o_down_flag=tar; // we wait for this person
+
+ target->o_status &= (0xffffffff-STAT_TALK_WAIT); // remove for this cycle - remember, this damn system is totally seamless...
+
+ Unlock_object(tar);
+ return(0); //script stop
+}
+
+//--------------------------------------------------------------------------------------
+// wait until last instruction it has finished before returning to script
+
+int32 FN_we_wait(object *compact, int32 id, int32 tar, int32 a, int32 b, int32 c, int32 d, int32 e) // (7JULY95 JEL)
+{
+ object *target;
+
+ compact;id;a;b;c;d;e;
+
+ target = (object *) Lock_object(tar);
+
+ //Tdebug("FN_we_wait %d", tar);
+
+ compact->o_logic = LOGIC_wait_for_talk; // we wait until they've finished
+ compact->o_down_flag=tar; // we wait for this person
+
+ target->o_status &= (0xffffffff-STAT_TALK_WAIT); // remove for this cycle - remember, this damn system is totally seamless...
+
+ Unlock_object(tar);
+ return(0); //script stop
+}
+
+//--------------------------------------------------------------------------------------
+int32 FN_add_talk_wait_status_bit(object *compact, int32 id, int32 tar, int32 a, int32 b, int32 c, int32 d, int32 e) // (21may96 JEL)
+{
+ id;tar;a;b;c;d;e;
+
+ compact->o_status |= STAT_TALK_WAIT;
+
+ return(1); //script continue
+}
+//--------------------------------------------------------------------------------------
+int32 FN_remove_talk_wait_status_bit(object *compact, int32 id, int32 tar, int32 a, int32 b, int32 c, int32 d, int32 e) // (21may96 JEL)
+{
+ id;tar;a;b;c;d;e;
+
+ compact->o_status &= (0xffffffff-STAT_TALK_WAIT);
+
+ return(1); //script continue
+}
+//--------------------------------------------------------------------------------------
+
+//mega_interact has recieved an instruction it does not understand - I have chosen to
+//halt the game to ensure the error is noticed...
+
+int32 FN_talk_error(object *compact, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) //S2.1(18Jan95tw)
+{
+ compact;id;a;b;c;d;z;x;
+
+ Tdebug("FN_talk_error for %d - instruct = %d",id, compact->o_down_flag);
+ Go_dos("FN_talk_error for %d - instruct = %d",id, compact->o_down_flag);
+
+ return(0);
+}
+
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
+
+//wait for target to switch into STAT_TALK_WAIT then go back into script mode
+//used during speech they_do commands - we must look to a specific target in-case
+//of multiple particpents in the conversation - a sync from the target is not enough...
+
+Logic_wait_talk(object *compact, int id) //S2.1(25Jan95tw)
+{
+ object *target;
+
+ id;
+
+ target = (object *) Lock_object(compact->o_down_flag); //holds id of person we're waiting for
+
+
+ if (!(target->o_status&STAT_TALK_WAIT))
+ {
+ Unlock_object(compact->o_down_flag); //holds id of person we're waiting for
+ return(0); //0 which means drop out of logic
+ }
+ else
+ {
+ compact->o_logic=LOGIC_script; //back to script again next cycle
+ Unlock_object(compact->o_down_flag); //holds id of person we're waiting for
+ return(1); // go straight back into script
+ //return(0); // drop out for one cycle (allows speech text sprite to disappear before continuing - 13Mar95JEL)
+ }
+}
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+#endif
+
+
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+uint32 unpause_zone=0;
+//------------------------------------------------------------------------------------
+int32 FN_i_speak(int32 *params) //Tony18Oct96 (revamped by James01july97)
+{
+//its the super versatile FN_speak
+//text and wavs can be selected in any combination
+
+//we can assume no human - there should be no human at least!
+
+//param 0 pointer to ob_graphic
+//param 1 pointer to ob_speech
+//param 2 pointer to ob_logic
+//param 3 pointer to ob_mega
+
+//param 4 encoded text number
+//param 5 wav res id
+//param 6 anim res id
+//param 7 anim table res id
+//param 8 animation mode 0 lip synced, 1 just straight animation
+
+#define S_OB_GRAPHIC 0
+#define S_OB_SPEECH 1
+#define S_OB_LOGIC 2
+#define S_OB_MEGA 3
+
+#define S_TEXT 4
+#define S_WAV 5
+#define S_ANIM 6
+#define S_DIR_TABLE 7
+#define S_ANIM_MODE 8
+
+ _mouseEvent *me;
+ _animHeader *anim_head;
+ Object_logic *ob_logic;
+ Object_graphic *ob_graphic;
+ Object_mega *ob_mega;
+ uint8 *anim_file;
+ uint32 local_text;
+ uint32 text_res;
+ uint8 *text;
+ static uint8 textRunning, speechRunning;
+ int32 *anim_table;
+ uint8 speechFinished=0; // James25feb97
+ int8 speech_pan;
+ char speechFile[256];
+ static uint8 cycle_skip=0;
+
+ #ifdef _DEBUG // (James26jun97)
+ _standardHeader *head; // for text/speech testing & checking for correct file type
+ static uint32 currentTextResource=0; // for text/speech testing - keeping track of text resource currently being tested
+ #endif
+
+ uint32 rv; // drivers return value
+
+
+ //-----------------------------------------------
+ // set up the pointers which we know we'll always need
+
+ ob_logic = (Object_logic *) params[S_OB_LOGIC];
+ ob_graphic = (Object_graphic *) params[S_OB_GRAPHIC];
+
+ //-----------------------------------------------
+ // FIRST TIME ONLY: create the text, load the wav, set up the anim, etc.
+
+ if (!ob_logic->looping)
+ {
+ //-------------------------
+ // New fudge to wait for smacker samples to finish (James31july97)
+ // since they can over-run into the game
+
+ if (GetSpeechStatus()!=RDSE_SAMPLEFINISHED) // has it finished?
+ return (IR_REPEAT);
+
+ //-------------------------
+ // New fudge for 'fx' subtitles (James 29july97)
+ // If subtitles switched off, and we don't want to use a wav for this line either,
+ // then just quit back to script right now!
+ if ((subtitles==0) && (WantSpeechForLine(params[S_WAV])==0))
+ return (IR_CONT);
+
+ //-------------------------
+ if (cycle_skip==0) // (James 17july97)
+ {
+ // drop out for 1st cycle to allow walks/anims to end & display last frame
+ // before system locks while speech loaded
+ cycle_skip=1;
+ return (IR_REPEAT);
+ }
+ else
+ cycle_skip=0;
+ //-------------------------
+
+ //-----------------------------------------------------------
+ #ifdef _DEBUG // (James26jun97)
+
+ textNumber = params[S_TEXT]; // for debug info
+
+ // For testing all text & speech! (James26jun97)
+ // A script loop can send any text number to FN_I_speak & it will only run the valid ones
+ // or return with 'result' equal to '1' or '2' to mean 'invalid text resource'
+ // and 'text number out of range' respectively
+ // See 'testing_routines' object in George's Player Character section of linc
+
+ if (SYSTEM_TESTING_TEXT)
+ {
+ RESULT=0;
+
+ text_res = params[S_TEXT]/SIZE;
+ local_text = params[S_TEXT]&0xffff;
+
+ if (res_man.Res_check_valid(text_res)) // if the resource number is within range & it's not a null resource
+ {
+ head = (_standardHeader*) res_man.Res_open(text_res); // open the resource
+
+ if (head->fileType==TEXT_FILE) // if it's not an animation file
+ {
+ if (CheckTextLine((uint8*)head,local_text)==0) // if line number is out of range
+ RESULT=2; // line number out of range
+ }
+ else
+ RESULT=1; // invalid (not a text resource)
+
+ res_man.Res_close(text_res); // close the resource
+
+ if (RESULT)
+ return(IR_CONT);
+ }
+ else
+ { // not a valid resource number
+ RESULT=1; // invalid (null resource)
+ return(IR_CONT);
+ }
+ }
+
+ #endif // _DEBUG
+ //-----------------------------------------------------------
+ // pull out the text line to get the official text number (for wav id)
+ // Once the wav id's go into all script text commands, we'll only need this for _DEBUG
+
+ text_res = params[S_TEXT]/SIZE;
+ local_text = params[S_TEXT]&0xffff;
+
+ text = FetchTextLine( res_man.Res_open(text_res), local_text ); // open text file & get the line
+ //officialTextNumber = *(uint16*)text; // 1st word of text line is the official line number (this doesn't work on PSX)
+ memcpy(&officialTextNumber, text, 2); // this works on PSX & PC
+
+ res_man.Res_close(text_res); // now ok to close the text file
+
+ //--------------------------------------
+ #ifdef _DEBUG // (James09jul97)
+
+ // prevent dud lines from appearing while testing text & speech
+ // since these will not occur in the game anyway
+
+ if (SYSTEM_TESTING_TEXT) // if testing text & speech
+ { // if actor number is 0 and text line is just a 'dash' character
+ if ((officialTextNumber==0) && (text[2]=='-') && (text[3]==NULL))
+ {
+ RESULT=3; // dud line
+ return(IR_CONT); // return & continue script
+ }
+ }
+
+ #endif // _DEBUG
+ //--------------------------------------
+ // set the 'looping_flag' & the text-click-delay
+
+ ob_logic->looping=1;
+ left_click_delay=6; // can't left-click past the text for the first half second
+ right_click_delay=3; // can't right-click past the text for the first quarter second
+
+ //----------------------------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+
+ #ifdef _DEBUG
+ if (PLAYER_ID!=CUR_PLAYER_ID) // if (player_id != george), then player is controlling Nico
+ Zdebug(0,"(%d) Nico: %s", officialTextNumber, text+2); // so write 'Nico' instead of George
+ else // ok, it's George anyway
+ Zdebug(0,"(%d) %s: %s", officialTextNumber, FetchObjectName(ID), text+2);
+ #endif
+
+ //--------------------------------------
+ // Set up the speech animation
+
+ if (params[S_ANIM]) //just a straight anim
+ {
+ anim_id=params[S_ANIM];
+ speech_anim_type=SPEECHANIMFLAG; //params[S_ANIM_MODE]; //anim type
+
+ ob_graphic->anim_resource = anim_id; // set the talker's graphic to this speech anim now
+ ob_graphic->anim_pc = 0; // set to first frame
+ }
+ else if (params[S_DIR_TABLE]) //use this direction table to derive the anim NB. ASSUMES WE HAVE A MEGA OBJECT!!
+ {
+ ob_mega = (Object_mega*) params[S_OB_MEGA];
+
+ anim_table = (int32 *)params[S_DIR_TABLE]; // pointer to anim table
+ anim_id = anim_table[ob_mega->current_dir]; // appropriate anim resource is in 'table[direction]'
+
+ speech_anim_type=SPEECHANIMFLAG; //params[S_ANIM_MODE]; //anim type
+
+ ob_graphic->anim_resource = anim_id; // set the talker's graphic to this speech anim now
+ ob_graphic->anim_pc = 0; // set to first frame
+ }
+ else //no animation choosen
+ {
+ anim_id=0; //no animation
+ }
+
+ SPEECHANIMFLAG = 0; // Default back to looped lip synced anims.
+
+ //--------------------------------------
+ // set up 'text_x' & 'text_y' for speech-pan and/or text-sprite position
+
+ LocateTalker(params);
+
+ //--------------------------------------
+ // is it to be speech or subtitles or both?
+
+ speechRunning=0; // assume not running until know otherwise
+
+ // New fudge for 'fx' subtitles (James 29july97)
+ // if speech is selected, and this line is allowed speech (not if it's an fx subtitle!)
+ if (speechSelected && WantSpeechForLine(officialTextNumber))
+ {
+ // if the wavId paramter is zero because not yet compiled into speech command,
+ // we can still get it from the 1st 2 chars of the text line
+ if (!params[S_WAV])
+ params[S_WAV] = (int32)officialTextNumber;
+
+ #define SPEECH_VOLUME 16 // 0..16
+ #define SPEECH_PAN 0 // -16..16
+
+ speech_pan = ((text_x-320)*16)/320;
+ // 'text_x' 'speech_pan'
+ // 0 -16
+ // 320 0
+ // 640 16
+
+ if (speech_pan<-16) // keep within limits of -16..16, just in case
+ speech_pan=-16;
+ else if (speech_pan>16)
+ speech_pan=16;
+
+ #ifdef _DEBUG
+ if (SYSTEM_TESTING_TEXT) // if we're testing text & speech
+ {
+ // if we've moved onto a new text resource, we will want to check
+ // if the CD needs changing again
+ // - can only know which CD to get if the wavID is non-zero
+ if ((text_res != currentTextResource) && (params[S_WAV]))
+ {
+ GetCorrectCdForSpeech(params[S_WAV]); // ensure correct CD is in for this wavId
+ currentTextResource = text_res;
+ }
+ }
+ #endif
+
+ //------------------------------
+ // 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 01oct97)
+ 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
+ //------------------------------
+
+
+ rv = PlayCompSpeech(speechFile, params[S_WAV], SPEECH_VOLUME, speech_pan); // Load speech but don't start playing yet
+ if (rv == RD_OK)
+ {
+ speechRunning=1; // ok, we've got something to play (2 means not playing yet - see below)
+ UnpauseSpeech(); // set it playing now (we might want to do this next cycle, don't know yet)
+ }
+ #ifdef _DEBUG
+ else
+ {
+ Zdebug("ERROR: PlayCompSpeech(speechFile=\"%s\", wav=%d (res=%d pos=%d)) returned %.8x", speechFile, params[S_WAV], text_res, local_text, rv);
+ }
+ #endif
+
+
+ }
+
+ if (subtitles || (speechRunning==0)) // if we want subtitles, or speech failed to load
+ {
+ textRunning=1; // then we're going to show the text
+ Form_text(params); // so create the text sprite
+ }
+ else
+ textRunning=0; // otherwise don't want text
+
+ //--------------------------------------
+
+ }
+ //-----------------------------------------------
+ // EVERY TIME: run a cycle of animation, if there is one
+
+ if (anim_id) // there is an animation
+ {
+ ob_graphic->anim_pc++; // increment the anim frame number
+
+ anim_file = res_man.Res_open(ob_graphic->anim_resource); // open the anim file
+ anim_head = FetchAnimHeader( anim_file );
+
+ if (!speech_anim_type) // ANIM IS TO BE LIP-SYNC'ED & REPEATING
+ {
+ if (ob_graphic->anim_pc == (int32)(anim_head->noAnimFrames)) // if finished the anim
+ ob_graphic->anim_pc=0; // restart from frame 0
+ else if (speechRunning) // if playing a sample
+ {
+ if (!unpause_zone)
+ { if (AmISpeaking()==RDSE_QUIET) // if we're at a quiet bit
+ ob_graphic->anim_pc=0; // restart from frame 0 ('closed mouth' frame)
+ }
+ }
+ }
+ else // ANIM IS TO PLAY ONCE ONLY
+ {
+ if (ob_graphic->anim_pc == (int32)(anim_head->noAnimFrames)-1) // reached the last frame of the anim
+ {
+ anim_id=0; // hold anim on this last frame
+ }
+ }
+
+ res_man.Res_close(ob_graphic->anim_resource); // close the anim file
+ }
+ else if (speech_anim_type)
+ speech_anim_type = 0; // Placed here so we actually display the last frame of the anim.
+
+ //-----------------------------------------------------------------------
+ //-----------------------------------------------------------------------
+ // EVERY TIME: FIND OUT IF WE NEED TO STOP THE SPEECH NOW...
+ //-----------------------------------------------------------------------
+ // if there is a wav then we're using that to end the speech naturally
+
+ if (speechRunning==1) // if playing a sample (note that value of '2' means about to play!)
+ {
+ if (!unpause_zone)
+ { if (GetSpeechStatus()==RDSE_SAMPLEFINISHED) // has it finished?
+ speechFinished=1; // James25feb97
+ }
+ else unpause_zone--;
+ }
+ //-----------------------------------------------------------------------
+ // if no sample then we're using speech_time to end speech naturally
+
+ else if ((speechRunning==0)&&(speech_time)) // counting down text time because there is no sample - this ends the speech
+ {
+ speech_time--;
+ if (!speech_time)
+ speechFinished=1; // James25feb97
+ }
+ //-----------------------------------------------------------------------
+ // ok, all is running along smoothly - but a click means stop unnaturally
+
+ #ifdef _DEBUG
+ if ((SYSTEM_TESTING_TEXT==0)||(mousey>0)) // so that we can go to the options panel while text & speech is being tested
+ #endif
+ {
+ me = MouseEvent(); // get mouse event
+
+ // Note that we now have TWO click-delays - one for LEFT button, one for RIGHT BUTTON
+ if ( ((!left_click_delay)&&(me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) || ((!right_click_delay)&&(me!=NULL)&&(me->buttons&RD_RIGHTBUTTONDOWN)) )
+ {
+ // mouse click, after click_delay has expired -> end the speech
+ // we ignore mouse releases
+
+ //-----------------------------------------------------------
+ #ifdef _DEBUG // (James26jun97)
+ if (SYSTEM_TESTING_TEXT) // if testing text & speech
+ {
+ if (me->buttons&RD_RIGHTBUTTONDOWN) // and RB used to click past text
+ SYSTEM_WANT_PREVIOUS_LINE=1; // then we want the previous line again
+ else
+ SYSTEM_WANT_PREVIOUS_LINE=0; // LB just want next line again
+ }
+ #endif
+ //-----------------------------------------------------------
+
+ do
+ me = MouseEvent(); //trash anything thats buffered
+ while(me!=NULL);
+
+ speechFinished=1; // James25feb97
+
+ if (speechRunning) // if speech sample playing
+ {
+ StopSpeech(); // halt the sample prematurely
+ }
+ }
+ }
+ //-----------------------------------------------------------------------
+ // if we are finishing the speech this cycle, do the business
+
+ if (speechFinished && !speech_anim_type) // !speech_anim_type, as we want an anim which is playing once to have finished.
+ {
+ if (speech_text_bloc_no) // if there is text
+ {
+ Kill_text_bloc(speech_text_bloc_no); // kill the text block
+ speech_text_bloc_no=0;
+ }
+
+ if (anim_id) // if there is a speech anim
+ {
+ anim_id=0;
+ ob_graphic->anim_pc=0; // end it on 1st frame (closed mouth)
+ }
+
+ textRunning=0;
+ speechRunning=0;
+
+ ob_logic->looping=0; // no longer in a script function loop
+
+#ifdef _DEBUG
+ textNumber = 0; // reset for debug info
+#endif // _DEBUG
+ officialTextNumber = 0; // reset to zero, in case text line not even extracted (since this number comes from the text line)
+
+ RESULT=0; // ok (James09july97)
+ return(IR_CONT); // continue with the script
+ }
+ //-----------------------------------------------------------------------
+ // speech still going, so decrement the click_delay if it's still active
+
+ if (left_click_delay)
+ left_click_delay--; // count down to clickability
+
+ if (right_click_delay)
+ right_click_delay--; // count down to clickability
+
+ //-----------------------------------------------------------------------
+
+ return(IR_REPEAT); // back again next cycle
+
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+void LocateTalker(int32 *params) // (James 01july97)
+{
+ // sets 'text_x' & 'text_y' for position of text sprite
+ // but 'text_x' also used to calculate speech-pan
+
+ //param 0 pointer to ob_graphic
+ //param 1 pointer to ob_speech
+ //param 2 pointer to ob_logic
+ //param 3 pointer to ob_mega
+
+ //param 4 encoded text number
+ //param 5 wav res id
+ //param 6 anim res id
+ //param 7 pointer to anim table
+ //param 8 animation mode 0 lip synced, 1 just straight animation
+
+ Object_mega *ob_mega;
+
+ uint8 *file;
+ _frameHeader *frame_head;
+ _animHeader *anim_head;
+ _cdtEntry *cdt_entry;
+ uint16 scale;
+
+
+
+
+ if (anim_id==0) // if there's no anim
+ { // assume it's Voice-Over text
+ text_x = 320; // so it goes at bottom of screen
+ text_y = 400;
+ }
+ else
+ {
+ #define GAP_ABOVE_HEAD 20 // distance kept above talking sprite
+
+ //-------------------------------------------
+ // Note: this code has been adapted from Register_frame() in build_display.cpp
+ //-------------------------------------------
+ // open animation file & set up the necessary pointers
+
+ file = res_man.Res_open(anim_id);
+
+ anim_head = FetchAnimHeader( file );
+ cdt_entry = FetchCdtEntry( file, 0 ); // '0' means 1st frame
+ frame_head = FetchFrameHeader( file, 0 ); // '0' means 1st frame
+
+ //-------------------------------------------
+ // check if this frame has offsets ie. this is a scalable mega frame
+
+ if ((cdt_entry->frameType) & FRAME_OFFSET)
+ {
+ ob_mega = (Object_mega*) params[S_OB_MEGA]; // this may be NULL
+
+ // calc scale at which to print the sprite, based on feet y-coord & scaling constants (NB. 'scale' is actually 256*true_scale, to maintain accuracy)
+ 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
+
+ // calc suitable centre point above the head, based on scaled height
+ text_x = ob_mega->feet_x; // just use 'feet_x' as centre
+ text_y = ob_mega->feet_y + (cdt_entry->y * scale)/256; // add scaled y-offset to feet_y coord to get top of sprite
+ }
+ else // it's a non-scaling anim
+ {
+ // calc suitable centre point above the head, based on scaled width
+ text_x = cdt_entry->x + (frame_head->width)/2; // x-coord + half of width
+ text_y = cdt_entry->y; // y-coord
+ }
+
+ text_y -= GAP_ABOVE_HEAD; // leave space above their head
+
+ //-------------------------------------------
+ // adjust the text coords for RDSPR_DISPLAYALIGN
+
+ text_x -= this_screen.scroll_offset_x;
+ text_y -= this_screen.scroll_offset_y;
+
+ //-------------------------------------------
+ // release the anim resource
+
+ res_man.Res_close(anim_id);
+
+ //-------------------------------------------
+ }
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+void Form_text(int32 *params) //Tony18Oct96
+{
+//its the first time in so we build the text block if we need one
+//we also bring in the wav if there is one
+//also setup the animation if there is one
+
+//anim is optional - anim can be a repeating lip-sync or a run-once anim
+//if there is no wav then the text comes up instead
+//there can be any combination of text/wav playing
+
+//param 0 pointer to ob_graphic
+//param 1 pointer to ob_speech
+//param 2 pointer to ob_logic
+//param 3 pointer to ob_mega
+
+//param 4 encoded text number
+//param 5 wav res id
+//param 6 anim res id
+//param 7 pointer to anim table
+//param 8 animation mode 0 lip synced, 1 just straight animation
+
+
+ uint32 local_text;
+ uint32 text_res;
+ uint8 *text;
+ uint32 textWidth;
+ Object_speech *ob_speech;
+
+
+
+ if (params[S_TEXT]) //should always be a text line, as all text is derived from line of text
+ {
+ ob_speech = (Object_speech*) params[S_OB_SPEECH];
+
+ //----------------------------------------------------------
+ // establish the max width allowed for this text sprite
+
+ if (ob_speech->width) // if a specific width has been set up for this character
+ textWidth = ob_speech->width; // override the default
+ else
+ textWidth = 400; // otherwise use the default
+
+ //----------------------------------------------------------
+ // pull out the text line & make the sprite & text block
+
+ text_res = params[S_TEXT]/SIZE;
+ local_text = params[S_TEXT]&0xffff;
+
+ text = FetchTextLine( res_man.Res_open(text_res), local_text ); // open text file & get the line
+
+ // 'text+2' to skip the first 2 bytes which form the line reference number
+ speech_text_bloc_no = Build_new_block(text+2, text_x, text_y, textWidth, ob_speech->pen, RDSPR_TRANS+RDSPR_DISPLAYALIGN, speech_font_id, POSITION_AT_CENTRE_OF_BASE);
+
+ res_man.Res_close(text_res); // now ok to close the text file
+
+ //----------------------------------------------------------
+ // set speech duration, in case not using wav
+
+ speech_time = strlen((char *)text) + 30; // no. of cycles = (no. of chars) + 10
+
+ //----------------------------------------------------------
+ }
+ else // no text line passed? - this is bad
+ {
+ // Zdebug(9,"no text line for speech wav %d", params[S_WAV]); //stream 9 for missing text & wavs
+ Zdebug("no text line for speech wav %d", params[S_WAV]); //stream 9 for missing text & wavs
+ }
+}
+//------------------------------------------------------------------------------------
+#ifdef _DEBUG
+
+void GetCorrectCdForSpeech(int32 wavId)
+{
+ FILE *fp;
+ uint8 cd; // 1, 2 or 0 (if speech on both cd's, ie. no need to change)
+
+ fp = fopen("cd.bin","rb");
+
+ if (fp==NULL)
+ Con_fatal_error("Need cd.bin file for testing speech!");
+
+ fseek(fp, wavId, SEEK_SET);
+ fread(&cd, 1, 1, fp);
+
+ fclose(fp);
+
+ if ((cd==1)||(cd==2)) // if we specifically need CD1 or CD2 (ie. it's not on both)
+ res_man.GetCd(cd); // then check it's there (& ask for it if it's not there)
+}
+
+#endif
+//------------------------------------------------------------------------------------
+// For preventing sfx subtitles from trying to load speech samples
+// - since the sfx are implemented as normal sfx, so we don't want them as speech samples too
+// - and we only want the subtitles if selected, not if samples can't be found!
+
+uint8 WantSpeechForLine(uint32 wavId) // James (29july97)
+{
+ switch (wavId)
+ {
+ case 1328: // AttendantSpeech
+ // SFX(Phone71);
+ // FX <Telephone rings>
+
+ case 2059: // PabloSpeech
+ // SFX (2059);
+ // FX <Sound of sporadic gunfire from below>
+
+ case 4082: // DuaneSpeech
+ // SFX (4082);
+ // FX <Pffffffffffft! Frp. (Unimpressive, flatulent noise.)>
+
+ case 4214: // cat_52
+ // SFX (4214);
+ // 4214FXMeow!
+
+ case 4568: // trapdoor_13
+ // SFX (4568);
+ // 4568fx<door slamming>
+
+ case 4913: // LobineauSpeech
+ // SFX (tone2);
+ // FX <Lobineau hangs up>
+
+ case 5120: // bush_66
+ // SFX (5120);
+ // 5120FX<loud buzzing>
+
+ case 528: // PresidentaSpeech
+ // SFX (528);
+ // FX <Nearby Crash of Collapsing Masonry>
+
+ case 920: // location 62
+
+ case 923: // location 62
+
+ case 926: // location 62
+
+ {
+ return 0; // don't want speech for these lines!
+ break;
+ }
+
+ default:
+ return 1; // ok for all other lines
+ }
+}
+//------------------------------------------------------------------------------------
diff --git a/sword2/speech.h b/sword2/speech.h
new file mode 100644
index 0000000000..3630f56110
--- /dev/null
+++ b/sword2/speech.h
@@ -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
diff --git a/sword2/startup.cpp b/sword2/startup.cpp
new file mode 100644
index 0000000000..0096a389e2
--- /dev/null
+++ b/sword2/startup.cpp
@@ -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);
+}
+
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+
+
diff --git a/sword2/startup.h b/sword2/startup.h
new file mode 100644
index 0000000000..da69389164
--- /dev/null
+++ b/sword2/startup.h
@@ -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
diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp
new file mode 100644
index 0000000000..c12d7bb09f
--- /dev/null
+++ b/sword2/sword2.cpp
@@ -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);
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+
diff --git a/sword2/sword2.h b/sword2/sword2.h
new file mode 100644
index 0000000000..0ec86e8c39
--- /dev/null
+++ b/sword2/sword2.h
@@ -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
diff --git a/sword2/sync.cpp b/sword2/sync.cpp
new file mode 100644
index 0000000000..7f8454db52
--- /dev/null
+++ b/sword2/sync.cpp
@@ -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
+
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+
diff --git a/sword2/sync.h b/sword2/sync.h
new file mode 100644
index 0000000000..4db00c4731
--- /dev/null
+++ b/sword2/sync.h
@@ -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
diff --git a/sword2/tony_gsdk.cpp b/sword2/tony_gsdk.cpp
new file mode 100644
index 0000000000..ea39086166
--- /dev/null
+++ b/sword2/tony_gsdk.cpp
@@ -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
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------------------------------
+
diff --git a/sword2/tony_gsdk.h b/sword2/tony_gsdk.h
new file mode 100644
index 0000000000..b5b9cf3f65
--- /dev/null
+++ b/sword2/tony_gsdk.h
@@ -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
diff --git a/sword2/walker.cpp b/sword2/walker.cpp
new file mode 100644
index 0000000000..9ae5c5e0fe
--- /dev/null
+++ b/sword2/walker.cpp
@@ -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
+}
+//---------------------------------------------------------------------------------------------------------------------
diff --git a/sword2/walker.h b/sword2/walker.h
new file mode 100644
index 0000000000..864c239c60
--- /dev/null
+++ b/sword2/walker.h
@@ -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