Hi,
I got my hands on leaked sci source code. Unfortunately I can't share it in its entirety.
Please don't try to pressure me on this.
I will however share a few bits. Hopefully it'll help us all understand SCI better.
Here's the SAVE.SC script:
;;;;
;;;; SAVE.SC
;;;;
;;;; (c) Sierra On-Line, Inc, 1992
;;;;
;;;; Author: Jeff Stephenson
;;;; Updated: Brian K. Hughes
;;;;
;;;; Classes which create the save/restore game user interface. Also
;;;; contains a number of instances of Dialogs and associated DItems
;;;; used in the interface.
;;;;
;;;; Classes:
;;;; SRDialog
;;;; Save
;;;; Restore
(script# SAVE)
(include "990.shm")
(define GAMESSHOWN 8) ;the number of games displayed in the selector
(define MAXGAMES 20) ;maximum number of games in a save directory
(define COMMENTSIZE 36) ;size of user's description of the game
(define COMMENTBUFF (/ (+ 1 COMMENTSIZE) 2))
(define DIRECTORYSIZE 29) ;size of the save directory name
(define DIRECTORYBUFF (/ (+ 1 DIRECTORYSIZE) 2))
(define BUFFERSIZE (+ (* MAXGAMES COMMENTBUFF) 1))
(procedure
GetDirectory
HaveSpace
GetStatus
NeedDescription
)
(public
GetDirectory 0
)
(local
default
i
numGames
selected
theStatus
[butbuf1 15]
[butbuf2 15]
[butbuf3 15]
[butbuf4 15]
[SRbuf 25]
)
(enum
RESTORE ;Restore games
HAVESPACE ;Save, with space on disk
NOSPACE ;Save, no space on disk but games to replace
NOREPLACE ;Save, no space on disk, no games to replace
)
(class SRDialog kindof Dialog
;;; The SRDialog class implements the user interface for save/restore.
;;; Its subclasses are the specific save and restore game dialogs,
;;; Save and Restore.
(method (dispose)
(super dispose: &rest)
)
(method (init theComment names nums
&tmp [buf 250]
)
;; Initialize the dialog.
; give ourself the system window as our window
(= window systemWindow)
;Re-init our size, with no elements.
(= nsBottom 0)
;Get some files for this directory.
(= numGames (GetSaveFiles (theGame name?) names nums))
(if (== numGames -1)
(return FALSE)
)
(= theStatus (GetStatus))
;Set up the edit item for saved games.
(if (== theStatus HAVESPACE)
(editI
text: (StrCpy theComment names),
font: smallFont,
setSize:,
moveTo: MARGIN MARGIN
)
(self add: editI, setSize:)
)
;Set up the selectorI box.
(selectorI
text: names,
font: smallFont,
setSize:,
moveTo: MARGIN (+ nsBottom MARGIN),
state: dExit
)
;Add four buttons down the side.
(switch theStatus
(0
(Message MsgGet SAVE BUTTON_RESTORE NULL NULL 1 @butbuf1)
)
(1
(Message MsgGet SAVE BUTTON_SAVE NULL NULL 1 @butbuf1)
)
(else
(Message MsgGet SAVE BUTTON_REPLACE NULL NULL 1 @butbuf1)
)
)
(= i (+ (selectorI nsRight?) MARGIN))
(okI
text: @butbuf1,
setSize:,
moveTo: i (selectorI nsTop?),
state:
(if (or
(and (== theStatus RESTORE) (not numGames))
(== theStatus NOREPLACE)
)
0
else
(| dActive dExit)
)
)
(Message MsgGet SAVE BUTTON_DELETE NULL NULL 1 @butbuf2)
(deleteI
text: @butbuf2,
setSize:,
moveTo: i (+ (okI nsBottom?) MARGIN),
state: (if (not numGames)
0
else
(| dActive dExit)
)
)
(Message MsgGet SAVE BUTTON_CHANGE NULL NULL 1 @butbuf3)
(changeDirI
text: @butbuf3,
setSize:,
moveTo: i (+ (deleteI nsBottom?) MARGIN),
state: (& (changeDirI state?) (~ dSelected))
)
(Message MsgGet SAVE BUTTON_CANCEL NULL NULL 1 @butbuf4)
(cancelI
text: @butbuf4,
setSize:,
moveTo: i (+ (changeDirI nsBottom?) MARGIN),
state: (& (cancelI state?) (~ dSelected))
)
;Put these elements into the dialog and size it.
(self
add: selectorI okI deleteI changeDirI cancelI,
setSize:
)
;Use the width of the dialog to size the text which goes into it.
(switch theStatus
(0
(Message MsgGet SAVE SELECT_GAME NULL NULL 1 @buf)
)
(1
(Message MsgGet SAVE TYPE_DESC NULL NULL 1 @buf)
)
(else
(Message MsgGet SAVE DIR_NOROOM NULL NULL 1 @buf)
)
)
(textI
text: @buf,
setSize: (- (- nsRight nsLeft) (* 2 MARGIN)),
moveTo: MARGIN MARGIN
)
;Now move all elements down by the height of the text.
(= i (+ (textI nsBottom?) MARGIN))
(self eachElementDo: #move: 0 i)
;Add the text to the dialog, and resize.
(self
add: textI,
setSize:,
center:,
open: wTitled -1 ;don't save PMAP
;*** open: wTitled 15
)
(return TRUE)
)
(method (doit theComment
&tmp fd ret offset
[names BUFFERSIZE] [nums (+ MAXGAMES 1)]
[str 100] [dir 40]
)
;If restore: is called with a TRUE parameter, do nothing if there
;are no saved games. This allows optionally presenting the user
;with his saved games at the start of the game.
(if
(and
(== self Restore)
argc
theComment
)
(= fd (FileIO fileOpen (Format @str {%ssg.dir} (theGame name?))))
(if (== fd -1)
;no directory -> no saved games
(return)
)
(FileIO fileClose fd)
)
(if (not (self init: theComment @names @nums))
(return -1)
)
(repeat
(= default
(switch theStatus
(RESTORE
(if numGames okI else changeDirI)
)
(HAVESPACE
;Edit item of save games is active if present
editI
)
(NOSPACE
;If there are save-games to replace, 'Replace'
;button is active.
okI
)
(else
;Otherwise 'Change Directory' button is active.
changeDirI
)
)
)
(= i (super doit: default))
(= selected (selectorI indexOf: (selectorI cursor?)))
(= offset (* selected COMMENTBUFF))
(cond
((== i changeDirI)
;; kill save window to save hunk
(self dispose:)
(if (GetDirectory curSaveDir)
(= numGames
(GetSaveFiles (theGame name?) @names @nums)
)
(if (== numGames -1)
(= ret -1)
(break)
)
)
;; open save back up with new directory
(self init: theComment @names @nums)
)
((and (== theStatus NOSPACE) (== i okI))
(self dispose:)
(if (GetReplaceName doit: (StrCpy theComment @[names offset]))
(= ret [nums selected])
(break)
)
(self init: theComment @names @nums)
)
((and (== theStatus HAVESPACE) (or (== i okI) (== i editI)))
(if (== (StrLen theComment) 0)
(self dispose:)
(NeedDescription)
(self init: theComment @names @nums)
(continue)
)
(= ret -1)
(for ((= i 0))
(< i numGames)
((++ i))
(= ret (StrCmp theComment @[names (* i COMMENTBUFF)]))
(breakif (not ret))
)
(cond
((not ret)
(= ret [nums i])
)
((== numGames MAXGAMES)
(= ret [nums selected])
)
(else
; find the lowest unused game number
(for ((= ret 0)) TRUE ((++ ret))
(for ((= i 0)) (< i numGames) ((++ i))
(breakif (== ret [nums i])) ; this number is used
)
(if (== i numGames) ; checked all entries in nums
(break) ; and none matched
)
)
)
)
(break)
)
((== i deleteI)
;; kill save window to save hunk
(self dispose:)
; confirm deletion
(if (not
((Print new:)
addText: DEL_TEXT NULL NULL 1 0 0 SAVE,
addButton: FALSE BUTTON_NO NULL NULL 1 0 35 SAVE,
addButton: TRUE BUTTON_YES NULL NULL 1 50 35 SAVE,
init:
))
(self init: theComment @names @nums)
(continue)
)
; open the saved game directory file
((= fd (File new:))
name: (DeviceInfo MakeSaveDirName @str (theGame name?)),
open: fTrunc,
)
; (File write:) requires a pointer to the data it is to write,
; so need to put values into variables, rather than just
; passing them as immediates
(= ret $0a0a) ; so both high and low byte is correct
; write the number and name of each saved game, except the
; one that was selected for deletion
(for ((= i 0)) (< i numGames) ((++ i))
(if (!= i selected)
(fd write: @[nums i] 2)
(fd writeString: @[names (* i COMMENTBUFF)])
(fd write: @ret 1)
)
)
; terminate saved game directory with a word of f's
(= ret -1)
(fd
write: @ret 2,
close:,
dispose:,
)
; delete the save game file itself
(DeviceInfo MakeSaveFileName
@str (theGame name?) [nums selected]
)
(FileIO fileUnlink @str)
; reinit to display updated dialog
(self init: theComment @names @nums)
)
((== i okI)
(= ret [nums selected])
(break)
)
((or (== i -1) (== i cancelI))
(= ret -1)
(break)
)
((== theStatus HAVESPACE)
(editI
cursor:
(StrLen (StrCpy theComment @[names offset])),
draw:
)
)
)
)
(DisposeScript FILE)
(self dispose:)
(DisposeScript SAVE)
(return ret)
)
(procedure (GetStatus)
(return
(cond
((== self Restore)
RESTORE
)
((HaveSpace)
HAVESPACE
)
(numGames
NOSPACE
)
(else
NOREPLACE
)
)
)
)
)
(class Restore of SRDialog
(method (init)
(Message MsgGet SAVE DIALOG_RESTORE NULL NULL 1 @SRbuf)
(= text @SRbuf)
(super init: &rest)
)
)
(class Save of SRDialog
(method (init)
(Message MsgGet SAVE DIALOG_SAVE NULL NULL 1 @SRbuf)
(= text @SRbuf)
(super init: &rest)
)
)
(instance GetReplaceName of Dialog
(method (doit theComment
&tmp ret [buf1 15] [buf2 15] [buf3 15] [buf4 15]
)
; give ourself the system window as our window
(= window systemWindow)
(Message MsgGet SAVE DTEXT_REPLACE NULL NULL 1 @buf1)
(text1
text: @buf1,
setSize:,
moveTo: MARGIN MARGIN
)
(self add:text1, setSize:)
(oldName
text: theComment,
font: smallFont,
setSize:,
moveTo:MARGIN nsBottom
)
(self add:oldName, setSize:)
(Message MsgGet SAVE DTEXT_WITH NULL NULL 1 @buf2)
(text2
text: @buf2,
setSize:,
moveTo: MARGIN nsBottom
)
(self add:text2, setSize:)
(newName
text: theComment,
font: smallFont,
setSize:,
moveTo: MARGIN nsBottom
)
(self add:newName, setSize:)
(Message MsgGet SAVE DTEXT_REPLACE NULL NULL 1 @buf3)
(button1
text: @buf3,
nsLeft: 0,
nsTop: 0,
setSize:
)
(Message MsgGet SAVE BUTTON_NODIRCHG NULL NULL 1 @buf4)
(button2
text: @buf4,
nsLeft: 0,
nsTop: 0,
setSize:
)
(button2
moveTo:
(- nsRight (+ (button2 nsRight?) MARGIN))
nsBottom
)
(button1
moveTo:
(- (button2 nsLeft?) (+ (button1 nsRight?) MARGIN))
nsBottom
)
(self
add:button1 button2,
setSize:,
center:,
open:stdWindow -1 ;don't save PMAP
;*** open:stdWindow 15
)
(= ret (super doit:newName))
(self dispose:)
(if (not (StrLen theComment))
(NeedDescription)
(= ret 0)
)
(return (or (== ret newName) (== ret button1)))
)
)
(procedure (GetDirectory where &tmp result
[newDir 40] [str 100] [buf1 50] len
)
(repeat
(= len (+ (Max DIRECTORYSIZE (+ (StrLen where) 6)) 11))
(= result
((Print new:)
font: SYSFONT,
addText: DIR_PROMPT NULL NULL 1 0 0 SAVE,
addEdit: (StrCpy @newDir where) len 0 20 where,
addButton: TRUE BUTTON_OK NULL NULL 1 0 34 SAVE,
addButton: FALSE BUTTON_NODIRCHG NULL NULL 1 50 34 SAVE,
init:
)
)
;Pressed ESC -- return FALSE.
(if (not result)
(return FALSE)
)
;No string defaults to current drive.
(if (not (StrLen @newDir))
(GetCWD @newDir)
)
;If drive is valid, return TRUE, otherwise complain.
(if (ValidPath @newDir)
(StrCpy where @newDir)
(return TRUE)
else
(Message MsgGet SAVE DIR_INVALID NULL NULL 1 @buf1)
(Format @str @buf1 @newDir)
((Print new:)
font: SYSFONT,
addText: @str,
init:
)
)
)
)
(procedure (HaveSpace)
(return (and (< numGames MAXGAMES) (CheckFreeSpace curSaveDir)))
)
(procedure (NeedDescription)
((Print new:)
font: SYSFONT,
addText: NO_DESC NULL NULL 1 0 0 SAVE,
init:
)
)
(instance selectorI of DSelector
(properties
x: COMMENTSIZE
y: GAMESSHOWN
)
)
(instance editI of DEdit
(properties
max: (- COMMENTSIZE 1)
)
)
(instance okI of DButton
(method (dispose)
(super dispose: TRUE)
)
)
(instance cancelI of DButton
(method (dispose)
(super dispose: TRUE)
)
)
(instance changeDirI of DButton
(method (dispose)
(super dispose: TRUE)
)
)
(instance deleteI of DButton
(method (dispose)
(super dispose: TRUE)
)
)
(instance textI of DText
(properties
font: SYSFONT
)
(method (dispose)
(super dispose: TRUE)
)
)
(instance text1 of DText
(properties
font: SYSFONT
)
(method (dispose)
(super dispose: TRUE)
)
)
(instance text2 of DText
(properties
font: SYSFONT
)
(method (dispose)
(super dispose: TRUE)
)
)
(instance oldName of DText
(method (dispose)
(super dispose: TRUE)
)
)
(instance newName of DEdit
(properties
max: (- COMMENTSIZE 1)
)
)
(instance button1 of DButton
(method (dispose)
(super dispose: TRUE)
)
)
(instance button2 of DButton
(method (dispose)
(super dispose: TRUE)
)
)