home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / pascal / rehack / convers / scripter.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-06-09  |  15.3 KB  |  601 lines

  1. program Scripter (input,output);
  2.  
  3. uses Crt,IOError;
  4.  
  5. {D+,L+}
  6.  
  7. const
  8.  
  9. { Program headers display }
  10.  
  11.   Program_Name = 'Scripter';
  12.  
  13.   System_Name  = 'DEGAS';
  14.   SysDesc_1    = 'Development Environment for';
  15.   SysDesc_2    = 'Graphic Adventures with Sound';
  16.   Version      = '1.0';
  17.   Year         = '1993';
  18.  
  19.   Message_Lines = 10;
  20.   Message_Data : array[1..Message_Lines] of string[30] =
  21.                  ('',
  22.                   System_Name,
  23.                   '',
  24.                   SysDesc_1,
  25.                   SysDesc_2,
  26.                   '',
  27.                   Program_Name+' V '+Version,
  28.                   '',
  29.                   '(c) '+Year+' Mark ''SAM'' Baker',
  30.                   '');
  31.   Message_Frame : array[1..Message_Lines] of string[3] =
  32.                   ('╔═╗',
  33.                    '║ ║',
  34.                    '╟─╢',
  35.                    '║ ║',
  36.                    '║ ║',
  37.                    '╟─╢',
  38.                    '║ ║',
  39.                    '╠═╣',
  40.                    '║ ║',
  41.                    '╚═╝');
  42.  
  43. { Program help display }
  44.  
  45.   Help_Lines        = 9;
  46.   Description_Start = 1;
  47.   Syntax_Start      = 5;
  48.   Help : array[1..Help_Lines] of string[65] =
  49.          ('',
  50.           'SCRIPTER '+Version+'- This program processes a compiled script for an',
  51.           '          adventure game written using '+System_Name+' :',
  52.           '          '+SysDesc_1+' '+SysDesc_2,
  53.           '',
  54.           'The Syntax for running is :-',
  55.           '',
  56.           'SCRIPTER /I=<Inputfile>',
  57.           '         <Inputfile>  is the filename of Compiled Script code)');
  58.  
  59. { General Constants }
  60.   TAB   = #09;
  61.   DOT   = '.';
  62.   SLASH = '/';
  63.   SPACE = ' ';
  64.  
  65. { File extensions }
  66.   MSGFileExt = 'MSC';
  67.   LNEFileExt = 'LNC';
  68.   SCRFileExt = 'SCC';
  69.  
  70.  
  71. { For the sake of this demo, we'll hard code the base information that
  72.   would normally be derived from the character record }
  73.   Start_Message = 1;
  74.   Start_Script  = 1;
  75.  
  76.   OFF = false;
  77.   ON  = true;
  78.  
  79.  
  80. type
  81.  
  82.   StrArrayPtr = ^StrArray;
  83.   StrArray    = array[1..640] of string[80];
  84.   ScrArrayPtr = ^ScrArray;
  85.   ScrArray    = array[1..16384] of word;
  86.  
  87.   Script_Record = record
  88.       Line,
  89.       RspOffs : word;
  90.     end; { Script_Reocrd }
  91.  
  92.  
  93. var
  94.  
  95. { For the sake of this demo, I've just set up the messages and lines as an
  96.   array of string, with no encryption or run-time replacement }
  97. { Character messages }
  98.   Messages     : StrArrayPtr;
  99. { Player options }
  100.   Lines        : StrArrayPtr;
  101. { Script data }
  102.   Script_Index : ScrArrayPtr;
  103.   Script_Data  : ScrArrayPtr;
  104.  
  105. { Parameters }
  106.   IP_Name : string;
  107.  
  108. { Input File Variables }
  109.   MSGFileName,LNEFileName,
  110.   SCRFileName     : string;
  111.   MSGFile,LNEFile : text;
  112.   SCRFile         : file;
  113.   MSGFile_Open,LNEFile_Open,
  114.   SCRFile_Open    : boolean;
  115.  
  116. { Error handling }
  117.   Error_Message     : string;
  118.   Status,Error_Type : byte;
  119.  
  120. { Message and Line variables }
  121.   MsgNbr,LneNbr,
  122.   TotMsg,TotLne : word;
  123.  
  124. { Script variables }
  125.   ScrNbr,
  126.   ScrDataSize,
  127.   No_of_Scripts,
  128.   Valid_Lines,
  129.   No_of_Lines : word;
  130.   End_Conversation : boolean;
  131.   Thread : array[1..10] of Script_Record;
  132.  
  133. { Flags (for test purposes only) }
  134.   Flags : array[1..64] of boolean;
  135.  
  136.  
  137. { Various functions used by the program }
  138.  
  139. function StrUpCase (IS : string) : string;
  140. var
  141.   SI : byte;
  142. begin
  143.   for SI:=1 to Length(IS) do
  144.     IS[SI] := UpCase(IS[SI]);
  145.   StrUpCase := IS;
  146. end; { StrUpCase }
  147.  
  148. function StripSpace (IS : string) : string;
  149. begin
  150.   while (Pos(SPACE,IS) = 1) do
  151.     Delete(IS,1,1);
  152.   StripSpace := IS;
  153. end; { StripSpace }
  154.  
  155. function StripTAB (IS : string) : string;
  156. var
  157.   SI : byte;
  158. begin
  159.   for SI:=1 to Length(IS) do
  160.     if (IS[SI] = TAB) then IS[SI] := SPACE;
  161.   StripTAB := IS;
  162. end; { StripTAB }
  163.  
  164.  
  165. { File handling routines }
  166.  
  167. { Set open file status to FALSE for all Input files }
  168. procedure Initialise_IP_Files;
  169. begin
  170.   MSGFile_Open := false;
  171.   LNEFile_Open := false;
  172.   SCRFile_Open := false;
  173. end; { Initialise_IP_Files }
  174.  
  175. { Close a specified text file if it has been opened }
  176. procedure Close_Text_File
  177.           (var FileOpen : boolean; var FileHandle : text);
  178. begin
  179.   if (FileOpen) then
  180.      Close(FileHandle);
  181.   FileOpen := false;
  182. end; { Close_Text_File }
  183.  
  184. { Close a specified block file if it has been opened }
  185. procedure Close_Block_File
  186.           (var FileOpen : boolean; var FileHandle : file);
  187. begin
  188.   if (FileOpen) then
  189.      Close(FileHandle);
  190.   FileOpen := false;
  191. end; { Close_Block_File }
  192.  
  193. { Close all Input files that are open }
  194. procedure Close_IP_Files;
  195. begin
  196.   Close_Text_File(MSGFile_Open,MSGFile);
  197.   Close_Text_File(LNEFile_Open,LNEFile);
  198.   Close_Block_File(SCRFile_Open,SCRFile);
  199. end; { Close_IP_Files }
  200.  
  201. { Report any IO Errors, and terminate the program }
  202. procedure IOError_Report
  203.           (FileName : string);
  204. begin
  205.   Close_IP_Files;
  206.   IOError_Message(Status,Error_Message,Error_Type);
  207.   TextColor(Red);
  208.   WriteLn('');
  209.   WriteLn('ERROR with file '+FileName+' - '+Error_Message);
  210.   WriteLn('');
  211.   WriteLn('                 ****  SCRIPTING HAS BEEN ABORTED  ****');
  212.   Halt(1);
  213. end; { IOError_Report }
  214.  
  215. { Test if a text Input file exists, and open it }
  216. procedure Open_Text_IP_File
  217.           (var FileName : string; FileExt : string;
  218.            var FileHandle : text; var FileOpen : boolean);
  219. begin
  220.   FileName := IP_Name+DOT+FileExt;
  221.   FileOpen := false;
  222.   Assign(FileHandle,FileName);
  223. {$I-}
  224.   Reset(FileHandle);
  225. {$I+}
  226.   Status := IOResult;
  227.   if (Status = Success) then FileOpen := true
  228.   else IOError_Report(FileName);
  229. end; { Open_Text_IP_File }
  230.  
  231. { Test if a block Input file exists, and open it }
  232. procedure Open_Block_IP_File
  233.           (var FileName : string; FileExt : string; BlockSize : word;
  234.            var FileHandle : file; var FileOpen : boolean);
  235. begin
  236.   FileName := IP_Name+DOT+FileExt;
  237.   FileOpen := false;
  238.   Assign(FileHandle,FileName);
  239. {$I-}
  240.   Reset(FileHandle,BlockSize);
  241. {$I+}
  242.   Status := IOResult;
  243.   if (Status = Success) then FileOpen := true
  244.   else IOError_Report(FileName);
  245. end; { Open_Block_IP_File }
  246.  
  247. { Seeing as this is just a demo, we'll not be fussy about how much memory
  248.   we grab }
  249.  
  250. { Read the Character response messages to the player }
  251. procedure Read_Messages;
  252. var
  253.   MsgLine : word;
  254.   MsgText : string;
  255. begin
  256.   GetMem(Messages,SizeOf(Messages^));
  257.   MsgLine := 1;
  258.   while (not Eof(MsgFile)) do
  259.     begin
  260.       ReadLn(MsgFile,Messages^[MsgLine]);
  261.       Inc(MsgLine);
  262.     end;
  263.   TotMsg := MsgLine - 1;
  264. end; { Read_Messages }
  265.  
  266. { Read the player's conversation line options }
  267. procedure Read_Lines;
  268. var
  269.   LneLine : word;
  270. begin
  271.   GetMem(Lines,SizeOf(Lines^));
  272.   LneLine := 1;
  273.   while (not Eof(LneFile)) do
  274.     begin
  275.       ReadLn(LneFile,Lines^[LneLine]);
  276.       Inc(LneLine);
  277.     end;
  278.   TotLne := LneLine - 1;
  279. end; { Read_Lines }
  280.  
  281. procedure Script_File_Error;
  282. begin
  283.   Status := 255;
  284.   IOError_Report(SCRFileName);
  285. end; { Script_File_Error }
  286.  
  287. { Read the thread data in the script file }
  288. procedure Read_Script_Data;
  289. var
  290.   Verify : word;
  291. begin
  292.   ScrDataSize := FileSize(ScrFile);
  293. { The number of scripts stored }
  294.   BlockRead(ScrFile,No_of_Scripts,1,Verify);
  295.   if (Verify <> 1) then Script_File_Error;
  296. { The script index; a set of word pointers to the individual elements of
  297.   script data }
  298.   GetMem(Script_Index,2 * No_of_Scripts);
  299.   BlockRead(ScrFile,Script_Index^,No_of_Scripts,Verify);
  300.   if (Verify <> No_of_Scripts) then Script_File_Error;
  301. { The script data itself }
  302.   ScrDataSize := ScrDataSize - No_of_Scripts - 1;
  303.   GetMem(Script_Data,2 * ScrDataSize);
  304.   BlockRead(ScrFile,Script_Data^,ScrDataSize,Verify);
  305.   if (Verify <> ScrDataSize) then Script_File_Error;
  306. end; { Read_Script_Data }
  307.  
  308.  
  309. { Now we get to the heart of the program; the script processor }
  310.  
  311. { Display the Character's response message }
  312. procedure Display_Character_Message;
  313. begin
  314.   TextColor(Red);
  315.   WriteLn('');
  316.   WriteLn(Messages^[MsgNbr]);
  317.   WriteLn('');
  318. end; { Display_Character_Message }
  319.  
  320. { Test if this is a valid line to add to our array }
  321. { Seeing as I've disabled most conditions for this demo (as they're too
  322.   tied to the structure of DEGAS as a whole) we'll just work with a simple
  323.   checking flag states (Flag_Is_On) }
  324. procedure Process_Line_Conditions
  325.           (var Valid_Line : boolean; var Data_Offset : word);
  326. var
  327.   F,C,No_of_Conditions : word;
  328. begin
  329.   No_of_Conditions := Script_Data^[Data_Offset];
  330.   Inc(Data_Offset);
  331.   C := 0;
  332. { We continue the Condition test loop, even when we've hit a false condition
  333.   to ensure that we adjust Data_Offset correctly }
  334.   while (C <> No_of_Conditions) do
  335.     begin
  336.       F := Script_Data^[Data_Offset];
  337.       if (Flags[F] = OFF) then Valid_Line := false;
  338.       Inc(Data_Offset);
  339.       Inc(C);
  340.     end;
  341. end; { Process_Line_Conditions }
  342.  
  343. { Perform the actions associated with the selected response }
  344. { Seeing as I've disabled most actions for this demo (as they're too tied to
  345.   the structure of DEGAS as a whole) we'll just work with turning flags on }
  346. procedure Process_Line_Actions
  347.           (var Data_Offset : word);
  348. var
  349.   A,F,No_of_Actions : word;
  350. begin
  351.   No_of_Actions := Script_Data^[Data_Offset];
  352.   Inc(Data_Offset);
  353.   A := 0;
  354.   while (A <> No_of_Actions) do
  355.     begin
  356.       F := Script_Data^[Data_Offset];
  357.       Flags[F] := ON;
  358.       Inc(Data_Offset);
  359.       Inc(A);
  360.     end;
  361. end; { Process_Line_Actions }
  362.  
  363. { Determine which line options we want to display, storing them in our
  364.   Thread array }
  365. procedure Process_Thread_Options;
  366. var
  367.   Valid_Line : boolean;
  368.   L,
  369.   Thread_Offset,
  370.   Data_Offset,
  371.   Line_Offset : word;
  372. begin
  373.   Thread_Offset := Script_Index^[ScrNbr];
  374.   No_of_Lines   := Script_Data^[Thread_Offset];
  375.   Line_Offset   := Thread_Offset;
  376.   Valid_Lines   := 0;
  377.   for L:=1 to No_of_Lines do
  378.     begin
  379.       Inc(Line_Offset);
  380.       Data_Offset := Script_Data^[Line_Offset];
  381.       Valid_Line  := true;
  382.       Process_Line_Conditions(Valid_Line,Data_Offset);
  383.       if (Valid_Line) then
  384.          begin
  385.            Inc(Valid_Lines);
  386.            Thread[L].Line    := Script_Data^[Data_Offset];
  387.            Inc(Data_Offset);
  388.            Thread[L].RspOffs := Data_Offset;
  389.          end;
  390.     end;
  391. end; { Process_Thread_Options }
  392.  
  393. { Display the array options, and find which one the player wants to use as
  394.   his response }
  395. procedure Select_Thread_Option
  396.           (var Line_Nbr : word);
  397. var
  398.   L : word;
  399.   C : integer;
  400.   LS : string;
  401. begin
  402. { Display the options available at this point }
  403.   TextColor(Blue);
  404.   for L:=1 to Valid_Lines do
  405.     begin
  406.       Str(L:2,LS);
  407.       Write(LS);
  408.       Write('  ');
  409.       WriteLn(Lines^[Thread[L].Line]);
  410.     end;
  411. { Use a simple numeric input to indicate the player's choice }
  412.   Write('Select response option : ');
  413.   Line_Nbr := 0;
  414.   while (Line_Nbr = 0) do
  415.     begin
  416.       ReadLn(LS);
  417.       Val(LS,Line_Nbr,C);
  418.       if ((Line_Nbr > Valid_Lines) or (C <> 0)) then Line_Nbr := 0;
  419.     end;
  420. { And highlight the chosen option }
  421.   TextColor(Yellow);
  422.   WriteLn('');
  423.   WriteLn(Lines^[Thread[Line_Nbr].Line]);
  424. end; { Select_Thread_Option }
  425.  
  426. procedure Process_Selected_Option
  427.           (Line_Nbr : word);
  428. var
  429.   Data_Offset : word;
  430. begin
  431.   Data_Offset := Thread[Line_Nbr].RspOffs;
  432.   MsgNbr := Script_Data^[Data_Offset];
  433.   Inc(Data_Offset);
  434.   ScrNbr := Script_Data^[Data_Offset];
  435.   End_Conversation := (ScrNbr and $8000) <> 0;
  436.   ScrNbr := (ScrNbr or $8000) xor $8000;
  437.   if (ScrNbr = 0) then End_Conversation := true;
  438.   Inc(Data_Offset);
  439.   Process_Line_Actions(Data_Offset);
  440. end; { Process_Selected_Option }
  441.  
  442. procedure Process_Script;
  443. var
  444.   Line_Nbr : word;
  445. begin
  446.   while (not End_Conversation) do
  447.     begin
  448.       if (MsgNbr <> 0) then Display_Character_Message;
  449.       if (ScrNbr <> 0) then
  450.          begin
  451.            Process_Thread_Options;
  452.            if (Valid_Lines <> 0) then
  453.               begin
  454.                 Select_Thread_Option(Line_Nbr);
  455.                 Process_Selected_Option(Line_Nbr);
  456.               end
  457.            else ScrNbr := 0;
  458.          end;
  459.     end;
  460. { Final display of any character response to the last selection }
  461.   if (MsgNbr <> 0) then Display_Character_Message;
  462. end; { Process_Script }
  463.  
  464.  
  465. procedure Parameter_Help
  466.           (Start_Line : byte);
  467. var
  468.   Help_Line : byte;
  469. begin
  470.   for Help_Line:=Start_Line to Help_Lines do
  471.     WriteLn(Help[Help_Line]);
  472.   Halt(1);
  473. end; { Parameter Help }
  474.  
  475. procedure Parameter_Error
  476.           (Error_Message : string);
  477. begin
  478.   WriteLn('');
  479.   WriteLn(Error_Message);
  480.   Parameter_Help(Syntax_Start);
  481. end; { Parameter_Error }
  482.  
  483. procedure File_Parameter
  484.           (FT : string; var PStr,Name : string);
  485. var
  486.   K : byte;
  487. begin
  488.   if (PStr[2] = '=') then
  489.      begin
  490.        Delete(PStr,1,2);
  491.        K := Pos(SLASH,PStr);
  492.        if (K = 0) then Name := PStr
  493.        else Name := Copy(PStr,1,K-1);
  494.        if (Name = '') then Parameter_Error(FT+' filename must be specified');
  495.      end
  496.   else Parameter_Error(FT+' filename incorrectly specified');
  497. end; { File_Parameter }
  498.  
  499. procedure Get_Parameters;
  500. var
  501.   I,J : byte;
  502.   PStr : string;
  503.   EndParams : boolean;
  504. begin
  505.   IP_Name     := '';
  506.   if (ParamCount = 0) then Parameter_Help(Description_Start);
  507.   I := 1;
  508.   while (I <= ParamCount) do
  509.     begin
  510.       PStr := StrUpCase(ParamStr(I));
  511.       EndParams := false;
  512.       if PStr[1] <> SLASH then
  513.          Parameter_Error('Parameter incorrectly specified - '+PStr)
  514.       else while not EndParams do
  515.            begin
  516.              Delete(PStr,1,1);
  517.              if PStr = '' then Parameter_Error('Parameter Error');
  518.              case PStr[1] of
  519.                'I' : File_Parameter('Input',PStr,IP_Name);
  520.                else Parameter_Error('Invalid Parameter - '+PStr);
  521.              end;
  522.              J:=Pos(SLASH,PStr);
  523.              if J <> 0 then PStr:=Copy(PStr,J,Length(PStr)-J+1)
  524.              else EndParams:=true;
  525.            end;
  526.       Inc(I);
  527.     end;
  528.   if (IP_Name = '') then Parameter_Error('Input filename MUST be specified');
  529. end; { Get_Parameters }
  530.  
  531.  
  532. procedure Display_Message;
  533. var
  534.   S   : string[80];
  535.   F,L,
  536.   X,Y : byte;
  537. begin
  538.   ClrScr;
  539.   L := 0;
  540.   TextColor(LightRed);
  541.   for Y:=1 to Message_Lines do
  542.     begin
  543.       if (Length(Message_Data[Y]) > L) then L := Length(Message_Data[Y]);
  544.       X := (80 - Length(Message_Data[Y])) div 2;
  545.       GotoXY(X,Y+1);
  546.       Write(Message_Data[Y]);
  547.     end;
  548.   TextColor(Yellow);
  549.   X := ((80 - L) div 2) - 2;
  550.   Inc(L,3);
  551.   for Y:=1 to Message_Lines do
  552.     begin
  553.       GotoXY(X,Y+1);
  554.       Write(Message_Frame[Y,1]);
  555.       if (Message_Frame[Y,2] = SPACE) then GotoXY(X+L,Y+1)
  556.       else begin
  557.              S := '';
  558.              for F:=1 to (L-1) do
  559.                S := S + Message_Frame[Y,2];
  560.              Write(S);
  561.            end;
  562.       Write(Message_Frame[Y,3]);
  563.     end;
  564.   TextColor(LightBlue);
  565.   Window(1,Message_Lines+2,80,25);
  566. end; { Display_Message }
  567.  
  568.  
  569. procedure Initialise_Flags;
  570. var
  571.   F : byte;
  572. begin
  573.   for F:=1 to 64 do Flags[F] := OFF;
  574. end; { Initialise_Flags }
  575.  
  576. procedure Initialise;
  577. begin
  578.   Initialise_IP_Files;
  579.   Open_Text_IP_File(MSGFileName,MSGFileExt,MSGFile,MSGFile_Open);
  580.   Open_Text_IP_File(LNEFileName,LNEFileExt,LNEFile,LNEFile_Open);
  581.   Open_Block_IP_File(SCRFileName,SCRFileExt,2,SCRFile,SCRFile_Open);
  582.   Read_Messages;
  583.   Read_Lines;
  584.   Read_Script_Data;
  585.   Initialise_Flags;
  586.   Close_IP_Files;
  587. end; { Initialise }
  588.  
  589.  
  590. begin
  591.   Get_Parameters;
  592.   Display_Message;
  593.   Initialise;
  594.  
  595.   MsgNbr := Start_Message;
  596.   ScrNbr := Start_Script;
  597.   End_Conversation := false;
  598.   Process_Script;
  599. end. { main program }
  600.  
  601.