//-----------------------------------------------------------------------------
//
//  $Logfile:: /Quake 2 Engine/Sin/code/game/gamescript.h                     $
// $Revision:: 11                                                             $
//   $Author:: Jimdose                                                        $
//     $Date:: 10/25/98 11:53p                                                $
//
// Copyright (C) 1997 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// $Log:: /Quake 2 Engine/Sin/code/game/gamescript.h                          $
// 
// 11    10/25/98 11:53p Jimdose
// added EXPORT_TEMPLATE
// 
// 10    10/20/98 10:30p Jimdose
// added crc checking to unarchive
// 
// 9     10/07/98 11:50p Jimdose
// Rewrote archiving functions for savegames
// got rid of type
// 
// 8     9/22/98 1:49a Jimdose
// removed freelabels
// 
// 7     9/21/98 10:15p Markd
// Putting archiving and unarchiving functions in
// 
// 6     7/13/98 5:57p Markd
// Added Setgamescript and Getgamescript methods
// 
// 5     7/11/98 8:43p Markd
// Added SetDialogScript
// 
// 4     7/07/98 11:36p Jimdose
// Added GameScriptMarker
// 
// 3     6/09/98 4:24p Jimdose
// finished implimentation
// 
// 2     6/05/98 2:37p Jimdose
// Created file
// 
// DESCRIPTION:
// Subclass of script that preprocesses labels
//

#ifndef __GAMESCRIPT_H__
#define __GAMESCRIPT_H__

#include "class.h"
#include "script.h"

typedef struct
	{
	scriptmarker_t pos;
	str labelname;
	} script_label_t;

class GameScript;

class GameScriptMarker : public Class
	{
	public:
		CLASS_PROTOTYPE( GameScriptMarker );

      str               filename;
		scriptmarker_t		scriptmarker;
      virtual void      Archive( Archiver &arc );
      virtual void      Unarchive( Archiver &arc );
	};

inline void GameScriptMarker::Archive
	(
	Archiver &arc
	)

   {
   // Game scripts are unique in that we don't call our superclass to archive it's data.
   // Instead, we only read enough info to then initialize the script ourselves.
   arc.WriteString( filename );
   arc.WriteBoolean( scriptmarker.tokenready );
   arc.WriteInteger( scriptmarker.offset );
   arc.WriteInteger( scriptmarker.line );
   arc.WriteRaw( scriptmarker.token, sizeof( scriptmarker.token ) );
   }

inline void GameScriptMarker::Unarchive
	(
	Archiver &arc
	)

   {
   // Game scripts are unique in that we don't call our superclass to archive it's data.
   // Instead, we only read enough info to then initialize the script ourselves.
   arc.ReadString( &filename );
   arc.ReadBoolean( &scriptmarker.tokenready );
   arc.ReadInteger( &scriptmarker.offset );
   arc.ReadInteger( &scriptmarker.line );
   arc.ReadRaw( scriptmarker.token, sizeof( scriptmarker.token ) );
   }

#ifdef EXPORT_TEMPLATE
template class Container<script_label_t *>;
#endif

class GameScript : public Script
	{
	protected:
		Container<script_label_t *>	*labelList;
		GameScript							*sourcescript;
      unsigned                      crc;

	public:
      CLASS_PROTOTYPE( GameScript );

								GameScript();
								GameScript( GameScript *scr );
								~GameScript();
		void					Close( void );
		void					SetSourceScript( GameScript *scr );
		void					LoadFile( const char *filename );

		void					Mark( GameScriptMarker *mark );
		void					Restore( GameScriptMarker *mark );

		void					FreeLabels( void );
		void					FindLabels( void );
		qboolean				labelExists( const char *name );
		qboolean				Goto( const char *name );
      virtual void      Archive( Archiver &arc );
      virtual void      Unarchive( Archiver &arc );
	};

#ifdef EXPORT_TEMPLATE
template class Container<GameScript *>;
#endif

class ScriptLibrarian : public Class
	{
	protected:
		Container<GameScript *>	scripts;
      str                     dialog_script;
      str                     game_script;

	public:
      CLASS_PROTOTYPE( ScriptLibrarian );

		~ScriptLibrarian();

		void			CloseScripts( void );
		void			SetDialogScript( str scriptname );
		void			SetGameScript( str scriptname );
		const char  *GetGameScript( void );
      GameScript  *FindScript( const char *name );
		GameScript	*GetScript( const char *name );
		qboolean		Goto( GameScript *scr, const char *name );
		qboolean		labelExists( GameScript *scr, const char *name );
      virtual void Archive( Archiver &arc );
      virtual void Unarchive( Archiver &arc );
	};

inline void ScriptLibrarian::Archive
	(
	Archiver &arc
	)
   {
   GameScript * scr;
   int i, num;

   Class::Archive( arc );

   num = scripts.NumObjects();
   arc.WriteInteger( num );
   for ( i = 1; i <= num; i++ )
      {
      scr = scripts.ObjectAt( i );
      arc.WriteObject( scr );
      }
   arc.WriteString( dialog_script );
   arc.WriteString( game_script );
   }

inline void ScriptLibrarian::Unarchive
	(
	Archiver &arc
	)
   {
   GameScript * scr;
   int i, num;

   Class::Unarchive( arc );

   scripts.FreeObjectList();

   arc.ReadInteger( &num );
   for ( i = 1; i <= num; i++ )
      {
      scr = new GameScript;
      arc.ReadObject( scr );
      scripts.AddObject( scr );
      }

   arc.ReadString( &dialog_script );
   arc.ReadString( &game_script );
   }

extern ScriptLibrarian ScriptLib;

inline void GameScript::Archive
	(
	Archiver &arc
	)

   {
   // Game scripts are unique in that we don't call our superclass to archive it's data.
   // Instead, we only read enough info to then initialize the script ourselves.
   GameScriptMarker mark;

   arc.WriteUnsigned( crc );

   Mark( &mark );
   arc.WriteObject( &mark );
   }

inline void GameScript::Unarchive
	(
	Archiver &arc
	)

   {
   // This function is based in part on Restore, so it changes, we must update this function as well.
   // Game scripts are unique in that we don't call our superclass to archive it's data.
   // Instead, we only read enough info to then initialize the script ourselves.
   GameScriptMarker mark;
   unsigned filecrc;
   GameScript *scr;

   arc.ReadUnsigned( &filecrc );
   arc.ReadObject( &mark );

   scr = ScriptLib.FindScript( mark.filename.c_str() );
   if ( scr )
      {
      SetSourceScript( scr );
      }
   else
      {
      LoadFile( mark.filename.c_str() );
      }

   // Error out if CRCs have changed
   if ( filecrc != crc )
      {
      gi.error( "File '%s' has changed from when this savegame was written.  Load cancelled.\n", filename.c_str() );
      }

	RestorePosition( &mark.scriptmarker );
   }

#endif
