Community
SCI Programming => SCI Development Tools => Topic started by: OmerMor on November 26, 2015, 03:34:56 PM
-
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)
)
)
-
Wow, cool!
Some interesting things in there... the array syntax I don't think we've seen before. Looks like
// SCI Studio
buffer[100]
// Sierra
[buffer 100]
I see a cond statement in there too, which is like LISP. And a repeat statement.
And it looks like they use a strange syntax for temp variables:
(method (doit theComment
&tmp ret [buf1 15] [buf2 15] [buf3 15] [buf4 15]
)
.. they are declared inline with the method parameters. Interesting... lots to look at in there!
-
Oh this is exciting!
-
So cool! Thanks for sharing this!
-
Maybe with this the decompiler can be improved so it doesn't have to fall back to assembly for SRDialog::doit and
proc990_0 GetDirectory :D
-
Possibly, but the decompiler is very complex, and I'm not sure the amount-of-work to benefit ratio would be good.
-
Even with all the other fallen-back scripts?
-
I think only about 2% of the code "falls back" to assembly. Making changes to the decompiler at this point is too risky, and the functions in assembly don't block people from making games.
Unless you want to fund me at a full-time salary until it's done, then I'll be glad to do it :-).
-
Then we will never have readable card game code. And that's okay by me. :D
Oh, also various puzzles.
Because for Hoyle's Classic Card Games and Dr. Brain, that 2% is more like 40%. ;D
-
Unless you want to fund me at a full-time salary until it's done, then I'll be glad to do it :-).
If I ever hit the lotto consider yourself hired.
-
Well if I ever did a kickstarter for any games, I had always intended to set aside some of it for you for the IDE development and Brandon would probably get some as well for the music composition. My best chance of a successful one might have been the current SQ: The Early Years but that would require a lot more for licensing as well. Besides feeling wrong about selling the two fan games included in there. We'll just have to wait on that for a truly unique endeavor which I am not sure will ever actually happen on my end :P
But anyway, the thought's what matters right... and I have thought about it.
-
Here's the header for the Tandy keyboard driver TANDYKBD.S:
;TANDYKBD.S
;Keyboard driver for the Tandy 1000 machines and their brain-damaged keyboards.
;D
-
It gets better when you have a browser extension that turns "keyboard" into "leopard (http://xkcd.com/1031/)".
-
I got a little bored waiting for something unrelated, so here's GetDirectory (aka proc990_0) rewritten in Studio dialect, reducing a 112-line routine to 32 lines. I've already tested this to work.
(procedure public (GetDirectory where)
(var result, newDir[40], str[100], buf1[50], len)
(while (TRUE) //closest thing to "repeat".
= len (+ Max(29 (+ StrLen(where) 6)) 11) //29 = DIRECTORYSIZE
= result (Print:
font(0)
addText(1 0 0 1 0 0 scriptNumber)
addEdit(StrCpy(@newDir where) len 0 20 where)
addButton(TRUE 27 0 0 1 0 34 scriptNumber)
addButton(FALSE 38 0 0 1 50 34 scriptNumber)
init()
)
(if (not result)
return FALSE
)
(if (not StrLen(@newDir))
GetCWD(@newDir)
)
(if (ValidPath(@newDir))
StrCpy(where @newDir)
return TRUE
)(else
Message(msgGET scriptNumber 29 0 0 1 @buf1)
Format(@str @buf1 @newDir) //Could probably FormatPrint/Printf this instead. I don't care.
(Print:
font(0)
addText(@str)
init()
)
)
)
)
I think it might be the repeat that killed it. Also, you need to (use "obj") for Max.
The next big question is, should I do this to SRDialog::doit(), 486 lines in Companion, 197 in OmerMor's leak?
-
I'll just put this pdf document here.
The Script Programming Language
Author: Jeff Stephenson
Date: 4 April 1988
-
I think I fucked up the logic somewhere converting SRDialog::doit. I blame the lack of continue and cond -- they make it difficult.
-
cond is just a nested if-else pattern
(cond (a A) (b B) (c C) (else D))
turns into
(if (a)
A
)
(else
(if (b)
B
)
(else
(if (c)
C
)
(else
D
)
)
)
For continue, the pattern is
(while (something)
something1
(if (blah)
continue
)
something2
)
becomes
(while (something)
something1
(if (not blah)
something2
)
)
But of course if it's nested inside a bunch of other logic, suddenly that becomes more complicated. Can't off the top of my head figure out the right transformation. You could always set a variable and skip the rest of the stuff conditionally based on that variable.
-
Thank you for that, it'll help for the second run-through. Though I think I fucked up a bit with the save catalog creation, too... no biggie though, considering as you said, the asm version works ;)
-
Did you notice that break, breakif, continue and continueif take an optional parameter to indicate the number of loop levels to break/continue from?
Supporting constructs for iteration:
(break [n])
Break out of n levels of loops. If n is not specified break out of the
innermost loop.
(breakif expression [n])
If expression is not FALSE, break out of n levels of loops. If n is
not specified, break out of the innermost loop.
(continue [n])
Loop back to the beginning of the nth level loop. If n is not
specified, loop to the beginning of the innermost loop.
(contif expression [n])
If expression is not FALSE, loop back to the beginning of the nth
level loop. If n is not specified, loop to the beginning of the
innermost loop.
-
I hadn't gotten that far in the document yet. More languages should support that.
-
Kawa,
in your version for GetDirectory, why did you use all those magic numbers?
Don't you have the constant definitions?
If you need some missing definitions from the original sci, let me know.
-
I'm on the fence about that :P.
The purist in me doesn't like using continue, or even break. Or even early returns (i.e. returns from the middle of a function). They're all like gotos - they break up your logic, sometimes making it harder to understand whatever algorithm you're implementing. I think some of that comes from when I coded a lot in "old style" C++ where smart pointers and RAII were not used, so you needed to ensure you always freed any resources you allocated. Jumping out of a loop at random points (or jumping out of a function from random points) often leads to resource leaks, since cleanup code is skipped.
It's not an issue with C# or modern C++ (with smart pointers and proper use of RAII). It *could* be an issue with SCI, since there is no garbage collection and no scoped variables. However, SCI doesn't follow the allocate-dosomething-free pattern all that much. There are *some* places in SCI1.1 that do that (with the Memory kernel). And problem some places that create new objects (like an Event) and dispose of them immediately.
Anyway, rant over. I do admit the multi-level break could be useful at times. And it might make things easier to understand, not harder (it's just that you *do* need to be cognizant of all the code you're skipping).
-
It *could* be an issue with SCI, since there is no garbage collection
There is in ScummVM :P
-
in your version for GetDirectory, why did you use all those magic numbers?
Don't you have the constant definitions?
If you need some missing definitions from the original sci, let me know.
For lines like = len (+ Max(29 (+ StrLen(where) 6)) 11) //29 = DIRECTORYSIZE I had the constants, but I wanted to keep it reasonably in-place replaceable.
For lines like addButton(TRUE 27 0 0 1 0 34 scriptNumber) I don't have a 990.shm, though one could be made from what save.sc reveals.
Nothing to it, really.
lol I accidentally used noun 30 instead of 29 :D
My srdialog.sc now has one big asm block, one commented-out counterpart to that block, and about 18 lines worth of noun constants.
-
990.SHM
; 990.SHM -- Produced by SCI Message Editor 3.350
; This file should only be edited with ME
; NOUNS
(define BUTTON_CANCEL 22)
(define BUTTON_CHANGE 23)
(define BUTTON_DELETE 24)
(define BUTTON_NO 31)
(define BUTTON_NODIRCHG 38)
(define BUTTON_OK 27)
(define BUTTON_REPLACE 25)
(define BUTTON_RESTORE 26)
(define BUTTON_SAVE 28)
(define BUTTON_YES 32)
(define BUT_REPLACE 9)
(define BUT_RESTORE 7)
(define BUT_SAVE 8)
(define CANCEL_BUTTON 5)
(define CHANGE_BUTTON 18)
(define DELETE_BUTTON 19)
(define DEL_NO 13)
(define DEL_TEXT 12)
(define DEL_YES 14)
(define DIALOG_RESTORE 20)
(define DIALOG_SAVE 21)
(define DIR_INVALID 29)
(define DIR_NOROOM 30)
(define DIR_PROMPT 1)
(define DTEXT_REPLACE 33)
(define DTEXT_WITH 34)
(define INVALID_DIR 2)
(define NOROOM 6)
(define NO_DESC 3)
(define OK_BUTTON 4)
(define REPLACE_BUTTON 15)
(define RESTORE_BUTTON 16)
(define SAVE_BUTTON 17)
(define SELECT_GAME 10)
(define TEXT_REPLACE 37)
(define TEXT_RESTORE 35)
(define TEXT_SAVE 36)
(define TYPE_DESC 11)
; CASES
-
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.
This is awesome!! What version of SCI are we looking at here? I see 1992 in the copyright message but I guess that gives the earliest date.
You're probably already aware that I've been working on the following web page over the past few years, adding bits and pieces to it as we've discovered them:
http://www.scriptinterpreter.com/syntax
I'm resisting the urge to fill in the gaps now. I can't really do that without referring to this post. Are we okay to do that?
This kind of puts less emphasis on the original game disk "slack space" project I started working on a few months back.
-
What version of SCI are we looking at here?
SCI11 at best, considering the Message calls in save.sc.
-
I'll just put this pdf document here.
The Script Programming Language
Author: Jeff Stephenson
Date: 4 April 1988
And with that document it really does fill in the rest of the gaps. This document must be what Mark Wilden was referring on his Smalltalk page and blog post:
My brother-in-law Chris Smith, who got me a job with Sierra in late 1989, sent me some sketchy documentation for SCI. One of the highlights of my programming life was sitting on my bed reading that documentation the day I got it
http://web.archive.org/web/20101219175024/http://www.mwilden.com/smalltalk/index.htm
I'll never forget that first night reading the documentation on my bed and just being consumed with this language that did things I wanted to do and even things I didn't know I wanted it to do.
http://mwilden.blogspot.co.uk/2009/06/discovering-oop.html
Not much in the document in relation to the OO side of the language though. And it seems to be missing the switchto keyword we know existed from the SWAT source snippet. This is probably because the document states 1988 as the publish date and I guess we're assuming that it was added to over time.
-
There are also references to other SCI manuals.
-
I think only about 2% of the code "falls back" to assembly. Making changes to the decompiler at this point is too risky, and the functions in assembly don't block people from making games.
Unless you want to fund me at a full-time salary until it's done, then I'll be glad to do it :-).
Hmmm. You know Omer does imply he has a lot of this code but can't share most of it. But maybe an extraction of all of the original class names and procedure names, particularly the ones from the common framework, would be very useful for the decompiler.
-
There are also references to other SCI manuals.
Ah, yes. Just spotted the reference to "Object Oriented Programming in Script". Is that the only one?
-
Did you notice that break, breakif, continue and continueif take an optional parameter to indicate the number of loop levels to break/continue from?
That might actually explain some of the weird compiled code we see from time to time. We were thinking there might be a continue, but there seems to be a number of variations. Good luck to the decompiler.
-
Except for the part where Phil doesn't want to touch the decompiler :)
-
lance: You can go ahead and use this material.
I'll probably share some more docs.
-
Hmmm. You know Omer does imply he has a lot of this code but can't share most of it. But maybe an extraction of all of the original class names and procedure names, particularly the ones from the common framework, would be very useful for the decompiler.
The problem with this is that it would be game-specific. I mean, the "long class names" seem fairly consistent over different games (but the short names are already pretty easy to understand anyway, so not much added value). Having public procedure names would be great, but that will only work if the procedure is at the same export index in the same script number in every game. There would undoubtedly be a lot of mismatches if this were done automatically by the decompiler (nothing stopping you from renaming them as you decompile though, based on some suggested list).
-
Here's the Kernel document.
BTW - the SCI sources I have are from version 1.001.099.
-
That might actually explain some of the weird compiled code we see from time to time. We were thinking there might be a continue, but there seems to be a number of variations. Good luck to the decompiler.
That's undoubtedly true. Multi-level break/continue, and just regular continue especially, are not patterns the decompiler expects to see, nor is it feasible to reconstruct them in SCI Studio syntax.
-
BTW - the SCI sources I have are from version 1.001.099.
So version 1.001.099 I can't seem to find any references to at all on the Internet. Ignoring the PQ4 and GK demos, the closest for a full game is Freddy Pharkas. I'm guessing this is where it is from then.
-
From going over the sources/docs it seems that the SCI infrastructure consisted of:
- Interpreter
- System Classes
- Tools (compiler, etc.)
This set evolved with time, and games just took the version that was available at that time and worked with it. Perhaps they might sync to a newer version later. But the team that wrote the infrastructure advanced it regardless of specific games. It was an ongoing project, developed in parallel to the games.
-
Ah, yes. Just spotted the reference to "Object Oriented Programming in Script". Is that the only one?
This is the one.
-
The SCRIPT, KERNEL, and OBJECT documents all refer, in multiple places, to yet another document called "Script Classes for Adventure Games". :D
-
Spotted another one. "Vocabulary documentation" is referred to twice in the SCRIPT document.
-
Omer, would you mind putting some of this on the Wiki, at least what you are comfortable doing?
-
Any guesses as to why a comma was used to separate selector send params? Seems redundant, since the boundary could easily be detected by encountering the next selector name with : at the end of it.
-
Yeah, that's a good question. It isn't consistent. The OBJECT pdf has an example without using the commas, from page 11, which suggests it wasn't required, at least not at first:
Any number of messages can be sent in one fell swoop:
(ego
x:50
y:50
setMotion: MoveTo 100 100
setCycle: Reverse self
)
Using a comma feels impure to me. It distracts from the smalltalk/Objective-C keyword message syntax. Maybe the comma was optional. Maybe some developers preferred using it. It doesn't seem to make sense as a requirement, unless there were a possibility of encountering a colon in a place where it doesn't follow a selector name.
-
I've uploaded 2 more documents to the wiki:
http://sciwiki.sierrahelp.com/index.php?title=Official_SCI_Documentation (http://sciwiki.sierrahelp.com/index.php?title=Official_SCI_Documentation)
The current list contains the following documents:
- The Script Programming Language
- SCI Kernel Documentation
- Object Oriented Programming in Script
- Script Classes for Adventure Games
- SCI Parser Programmer's Reference
-
Thanks.
-
The Classes document is brilliant! Quite a bit bigger than the others and full of detail.
I spotted another example on page 7 of that document where the message passing doesn't use commas:
(list add:
((Actor new:)
posn:100 100
view:5
setCycle: EndLoop
myself:
)
)
I'm tempted to join all these PDFs together and send it somewhere to get a properly printed and bound hard copy, with a nice glossy cover. I know by now we probably all have these on our phones, and can read them whenever in PDF format, but there's something about having a hard copy to flick through, something like the Oreilly pocket reference size would be great.
-
I made .txt versions, because that's basically what these PDF files are -- plaintext.
They have formfeed characters. That's a first for me.
-
I uploaded 2 more files to the wiki:
- Run Time System Changes
- SCI Changes & Updates
And from the SCI Changes document, we can find the explanation to the comma separator mystery:
11/16/88
- (Jeff) A relatively major change in the way selectors are handled by the
compiler and interpreter has been made and will require a change in
syntax of your source code. Fortunately, there is a conversion program
which will do the syntax change for you, though you will need to learn
a few new habits for writing new code.
The nature of the change is that there is no longer a distinction between
the various forms of a selector, i.e. "state:", "state?", and "state"
are identical in all respects except visually. The interpreter now deals
with the message
(anObject aSelector [args ...])
in the following way:
(cond
(- aSelector is a method of anObject
The method aSelector is invoked with args.
)
(- there are no arguments
The value of the property aSelector is returned.
)
(- else
The value of the property aSelector is set to the
value of the first argument.
)
)
This leads to several niceties:
- The selector symbol table in sc will now be only a third as large
as it is currently, so you'll have a bit more space for your compiles.
- You can now convert between properties and active values with no
source code changes outside the class involved. An 'active value'
is a value which has some sort of side effect when accessed. See
the document "/games/sci/system/doc/active.doc" for a further
explanation.
- System code has been reduced in size by 300 bytes since (for esoteric
reasons) we now have 128 more byte-length selectors. Don't be usin'
that space, though -- a new Avoider is on the way once Pablo gets
well which will eat it all back up.
What this requires in terms of syntax is the following:
- Multiple messages to the same object in an expression must now
be delimited by commas, so that the compiler can tell where each
message ends. Thus,
(ego
view: 5
posn: 100 200
setMotion: MoveTo y x self
init:
)
becomes
(ego
view: 5,
posn: 100 200,
setMotion: MoveTo y x self,
init:
)
- All 'pseudo-selectors' such as 'at:', 'title:', etc. in Print,
SetMenu, and other function calls must be preceeded with a '#' to
let the compiler know that you're just passing a number rather
than trying to access a property. Thus,
(Print "This is a pain." at: 100 100)
becomes
(Print "This is a pain." #at: 100 100)
The good news is that there is a conversion program, cvtsci.exe, which
will do all this syntax conversion for you. Usage is
cvtsci file_spec [file_spec ...]
You probably just want to 'cvtsci *.sc'. This program can also be run
over already converted source, so if you forget to use the new syntax
while modifying an already converted file, just cvtsci it again.
Note to the sceptical: the entire source of Leisure Suit Larry II has
been converted, compiled with the new compiler, and played to completion
on the new interpreter. You really shouldn't encounter problems. If
you do, I'm sure you'll let me know.
-
Hmm, I don't find their reasons very compelling. It seems they could have satisfied their requirements by just making "foo?" equivalent to "foo:" (which I am fine with).
But making "foo?" and "foo:" also equivalent to "foo", they introduce the yucky comma requirement, and I don't see the benefit. Unless it has something to do with the space savings they mention, I don't see a reason to make the unadorned token work as a selector.
-
Yeah, I completely agree with that. The language seemed a lot cleaner before this change. Supporting the selector without either a : or ? would make it quite ugly to read. I quite like the visual appearance of the pure keyword message syntax.
-
So the messager script is conv.sc, hmm?
Edit: omg a tutorial for Tutorial.
-
So the messager script is conv.sc, hmm?
Looks like it's messager.sc. conv.sc is probably the Conversation class (currently named messageobj.sc in our template game).
Edit: omg a tutorial for Tutorial.
There's a find!
-
I know right? I tried it just now. Step two is fucked, but step one works -- that's "select this verb in the icon bar".
-
Plaintext is so... plain, don'tcha think? (http://helmet.kafuka.org/sci/original/conversions/object.docx)
-
I have started to Wiki-ize the docs. It should make it easier to navigate and adds it to Wiki's searchable database.
http://sciwiki.sierrahelp.com//index.php?title=The_Script_Programming_Language
I would still want to leave the original PDFs for download.
-
Cool. I'll have my own documentation with SCI Companion, but the syntax won't be 100% the same, so it's good to have the original somewhere.
-
Nice work, Kawa & Collector.
Kawa: you should probably use fixed-width font for code snippets. I also don't like Word so much because it's doesn't have a good collaboration story like Google Docs does (the fact that I work for Google is irrelevant ;D). I'll try to import it to Google Docs later and see if it looks good enough.
Collector: I like the wiki of the docs. I also edited it a bit.
-
myself:
This is obviously not SCI in its final form. SCI in its final form calls this yourself (even KQ4), even though the purpose is the same: To pass the address of the newly created object on to the outer expression (adding it to the list), rather than what the second-to-last message would otherwise return.
-
you should probably use fixed-width font for code snippets.
Consolas isn't fixed-width?
-
Ah... I'm on a linux box with libre office and no consolas.
So it just shows some random font instead.
-
I thought it'd be something like that.
-
I'll try to Wikify the other dos, but it will take some time. I might try to automate this some way. I did discover an item in the index that had no entry in the document. 'base.sh' in the Files chapter. I added an empty section for it. I am not sure if we can deduce what the entry should have been or not. http://sciwiki.sierrahelp.com//index.php?title=The_Script_Programming_Language/Files#base.sh
-
It's probably what system.sh was called at one time, so you can probably just remove it. As with most documentation, bits and pieces get out of date as the software changes.
-
Incidentally, I've seen what you're up to on Github, Phil.
I don't fully understand it all, but I've seen it >:3
-
I suppose checkin comments like "convert all" functionality for moving a project to SCI Syntax don't leave much to the imagination, do they??
-
myself:
This is obviously not SCI in its final form. SCI in its final form calls this yourself (even KQ4), even though the purpose is the same: To pass the address of the newly created object on to the outer expression (adding it to the list), rather than what the second-to-last message would otherwise return.
Interesting. Yeah, it looks like there was this original set of documentation produced, that we're seeing now, that was probably never updated. Instead they seem to have kept track of most changes via the change history document. Can't seem to find a myself: becomes yourself: change in the changes doc though.
-
http://sciwiki.sierrahelp.com//index.php?title=The_Script_Programming_Language/Using_SC
So the usage message for the compiler proves that it did do optimizations by default. I guess we were already assuming that based on some of the compiled code, but this confirms it.
-
I have been working on the Wiki. I added categories to the official scripting reference to make it more accessible from related entries. I edited Omer's official documentation page to function as a main page for this documentation and left the PDF links for anyone who wants a local copy in its original format.
http://sciwiki.sierrahelp.com//index.php?title=Official_SCI_Documentation
I will do the missing ones after a break and as I find time. The Wiki conversion is a little bit maddening with a lot of tedious busy work. I also added a link to Phil's help file in the sidebar, next to the SCI Studio help file. This will add it to the Wiki without having to worry about keeping it in sync with the original if and when Phil updates it.
-
myself:
This is obviously not SCI in its final form. SCI in its final form calls this yourself (even KQ4), even though the purpose is the same: To pass the address of the newly created object on to the outer expression (adding it to the list), rather than what the second-to-last message would otherwise return.
Interesting. Yeah, it looks like there was this original set of documentation produced, that we're seeing now, that was probably never updated. Instead they seem to have kept track of most changes via the change history document. Can't seem to find a myself: becomes yourself: change in the changes doc though.
They added a define from myself --> yourself :
;For compatability -- bringing stuff in line with SmallTalk syntax.
(define myself yourself)
Here's the complete SYSTEM.SH script:
;;;;
;;;; SYSTEM.SH
;;;;
;;;; (c) Sierra On-Line, Inc, 1992
;;;;
;;;; Author: Unknown
;;;;
;;;; This is the header file for the SCI system
;;;;
;;;; Last Updated:
;;;; Brian K. Hughes
;;;; August 19, 1992
(include kernel.sh) ;kernel external declarations
;╔════════════════╗
;║ ║
;║ Module Defines ║
;║ ║
;╚════════════════╝
(define SYSTEM 999)
(define ACTOR 998)
(define MENU 997)
(define USER 996)
(define INVENT 995)
(define GAME 994)
(define FILE 993)
(define MOTION 992)
(define JUMP 991)
(define SAVE 990)
(define MUSIC 989)
(define EGO 988) ; was EXTRA
(define GAUGE 987)
(define ORBIT 986)
(define FLAGS 985) ; was AVOIDER
(define REGPATH 984) ; was SORTCOPY
(define PATH 983)
(define SIGHT 982)
(define WINDOW 981)
(define TUTORIAL 980) ; was TEXTRA
(define UNUSED_4 979) ; was MOUSER
(define GCONTROL 978)
(define GROOPER 977)
(define CAT 976)
(define SCALETO 975) ; was DEMO
(define NAMEFIND 974)
(define TIMER 973)
(define CHASE 972)
(define FOLLOW 971)
(define WANDER 970)
(define REVERSE 969)
(define SMOOPER 968)
(define DCICON 967)
(define SORT 966)
(define COUNT 965)
(define DPATH 964) ; will be merged into PATH
(define RELDPATH 963) ; will be merged into PATH
(define UNUSED_7 962) ; was QSCRIPT
(define STOPWALK 961)
(define UNUSED_8 960) ; was TIMEDCUE
(define QSOUND 959)
(define LOADMANY 958)
(define UNUSED_10 957) ; was LASTLINK
(define FORCOUNT 956)
(define TRACK 955)
(define DOOR 954) ; was GOTOSAID
(define APPROACH 953)
(define LOGGER 952)
(define MOVEFWD 951)
(define FEATURE 950)
(define BLOCK 949)
(define WRITEFTR 948)
(define DLGEDIT 947) ; was DELAYEVT
(define POLYGON 946)
(define POLYPATH 945)
(define FILESEL 944)
(define POLYEDIT 943)
(define MOVECYC 942)
(define RANDCYC 941)
(define UNUSED_11 940) ; was PRINTD
(define OSC 939)
(define RANGEOSC 938) ; was PCYCLE
(define ICONBAR 937)
(define BORDWIND 936)
(define SCALER 935)
(define SLIDEICON 934)
(define PMOUSE 933)
(define PFOLLOW 932) ; was LANGUAGE
(define CDACTOR 931)
(define PCHASE 930)
(define SYNC 929)
(define TALKER 928)
(define PAVOID 927)
(define FLIPPOLY 926)
(define CONV 925)
(define MESSAGER 924)
(define INSET 923)
(define DIALOG 922) ;Contains DIcon, DButton, DEdit, DSelector, Controls
(define PRINT 921) ;Front-end for dialogs
(define INTRFACE 255)
;╔════════════════╗
;║ ║
;║ Extern Defines ║
;║ ║
;╚════════════════╝
(extern
Prints PRINT 0
Printf PRINT 1
GetInput PRINT 2
FindFormatLen PRINT 3
StillDown INTRFACE 0
GetNumber INTRFACE 1
MousedOn INTRFACE 2
sign SYSTEM 0
umod SYSTEM 1
Min SYSTEM 2
Max SYSTEM 3
InRect SYSTEM 4
OneOf SYSTEM 5
WordAt SYSTEM 6
Eval SYSTEM 7
LoadMany LOADMANY 0
IsOffScreen SIGHT 0
CantBeSeen SIGHT 1
AngleDiff SIGHT 2
FlipPoly FLIPPOLY 0
FlipFeature FLIPPOLY 1
)
;╔══════════════════╗
;║ ║
;║ Resource Defines ║
;║ ║
;╚══════════════════╝
;Resource types
(define VIEW $80) ; For backward compatability
(define PICTURE $81)
(define SCRIPT $82)
(define TEXT $83)
(define SOUND $84)
(define MEMORY $85)
(define VOCAB $86)
(define FONT $87)
(define CURSOR $88) ;
(define RES_VIEW $80)
(define RES_PIC $81)
(define RES_SCRIPT $82)
(define RES_TEXT $83)
(define RES_SOUND $84)
(define RES_MEMORY $85)
(define RES_VOCAB $86)
(define RES_FONT $87)
(define RES_CURSOR $88)
(define RES_PATCH $89)
(define RES_BITMAP $8A)
(define RES_PALETTE $8B)
(define RES_CDAUDIO $8C)
(define RES_AUDIO $8D)
(define RES_SYNC $8E)
(define RES_MESSAGE $8F)
(define RES_MAP $90)
(define RES_HEAP $91)
(define RES_AUDIO36 $92)
(define RES_SYNC36 $93)
;Virtual bitmap ID's
(define VMAP 1)
(define PMAP 2)
(define CMAP 4)
;Picture change style constants
(define HWIPE 0)
(define HSHUTTER 0)
(define VSHUTTER 1)
(define WIPELEFT 2)
(define WIPERIGHT 3)
(define WIPEUP 4)
(define WIPEDOWN 5)
(define IRISIN 6)
(define IRISOUT 7)
(define DISSOLVE 8)
(define PIXELDISSOLVE 9)
(define FADEOUT 10) ;Defaults to PLAIN in 16 color
(define SCROLLRIGHT 11) ;Relative order of these four is important
(define SCROLLLEFT 12) ; in order for ShowPic to work correctly
(define SCROLLUP 13)
(define SCROLLDOWN 14)
(define PLAIN 100) ;Draw quickly with no special effects
(define DONTSHOW $1000) ;Draw pic, but don't show yet
(define VMIRROR $2000) ;Mirror pic vertically
(define HMIRROR $4000) ;Mirror pic horizontally
(define BLACKOUT $8000) ;"or" with other style to blacken screen first
;╔════════════════╗
;║ ║
;║ Cursor Defines ║
;║ ║
;╚════════════════╝
(define ARROW_CURSOR 999)
(define SNAIL_CURSOR 998)
(define HAND_CURSOR 997)
(define INVIS_CURSOR 996)
;╔══════════════════════════╗
;║ ║
;║ Numeric Constant Defines ║
;║ ║
;╚══════════════════════════╝
(define INFINITY $7fff)
(define NULL 0)
;Bits in the -info- property.
(define CLONED $0001)
(define NODISPOSE $0002)
(define NODISPLAY $0004)
(define CLASS $8000)
;For compatability -- bringing stuff in line with SmallTalk syntax.
(define myself yourself)
;Screen dimensions
(define MINTOP 0)
(define MINLEFT 0)
(define MAXRIGHT 320)
(define MAXBOTTOM 200)
;Screen edges for edgeHit
(enum 1
NORTH
EAST
SOUTH
WEST
)
;Values for above
(define northEdge 40)
(define southEdge 189)
(define eastEdge 319)
(define westEdge 0)
;Screen dimensions
(define SCRNWIDE 320)
(define SCRNHIGH 200)
;Values returned by (GameIsRestarting)
(enum 1
RESTARTING
RESTORING
)
(define PATHEND $8000) ;Indicates end of path array
(define ENDPOLY $8000) ;Indicates end of polygon array
(define SAMEVIEW -1) ;Indicates stop cels are in same view as walks
(define END_CONV 0) ;Indicates end of Conversation array
(define MARGIN 4) ;Standard intrface item/edge spacing
;System font should not be screwed with
(define SYSFONT 0)
(define USERFONT 1)
;Used to specify the origin of an Actor in certain methods.
(define origin 1)
;File opening parameters
(define fAppend 0) ;appends to end of file
(define fRead 1) ;positions at start of file
(define fTrunc 2) ;truncates file on open
;File seek parameters (limited to offset of +/- 32767)
(enum
fileSeekBeg ; seek from beginning of file (positive offset)
fileSeekCur ; seek from current position of file (positively/negatively)
fileSeekEnd ; seek from end of file (negative offset)
)
;Define for features shiftClick and contClick properties
; that say don't do proximity checks if clicked on.
(define NOCHECKMOUSE $8000)
;Enums for Extra class
(enum
ExtraForward ;0=default
ExtraEndLoop ;1
ExtraEndAndBeginLoop ;2
)
(enum -2
ExtraLastCel ;-1
ExtraRandomCel ;-2
)
; Feature defines
(define ftrDefault $6789)
(define ftrControl $0001)
(define ftrPolygon $0002)
(define FACINGME $0001)
(define NEARCHECK $0002)
(define FARCHECK $0004)
(define ISNOTHIDDEN $0008)
(define SKIPCHECK $1000)
(define maxFileName 13) ;MS-DOS maximum
;Enums for polygon types for the polygon based avoider
(enum
PTotalAccess
PNearestAccess
PBarredAccess
PContainedAccess
)
;(define NODIRECTION $7fff);Arbitrary value for an undefined heading
;(define goToSaid $8000);or with longRangeDist to indicate goToSaid desired
;(define turnIfSaid $8000);or with sightAngle to indicate turnIfSaid desired
;Defines for the system view
(define SYSVIEW 999)
;(define STOPSIGN SYSVIEW 0 0)
;(define QUESTIONMARK SYSVIEW 0 1)
;(define EXCLAMATION SYSVIEW 0 2)
;Text rendering
;(define TPLAIN 0)
;(define TDIMMED 1)
;Door defines
(enum
doorClosed
doorOpening
doorOpen
doorClosing
)
(enum
doorWalkEgo ; ->: ego will walk in through the door
; <-: ego will walk out the door to new room
doorPlaceEgo ; ->: ego will appear in front of the door
; <-: ego will walk out the door & door will close
doorLeaveEgo ; both: the door does not affect ego
)
; Language defines
(define ENGLISH 1)
(define FRENCH 33)
(define SPANISH 34)
(define ITALIAN 39)
(define GERMAN 49)
(define JAPANESE 81)
(define PORTUGUESE 351)
;╔════════════════╗
;║ ║
;║ Dialog Defines ║
;║ ║
;╚════════════════╝
;Dialog item types
(define dButton 1)
(define dText 2)
(define dEdit 3)
(define dIcon 4)
(define dMenu 5) ; the title portion
(define dSelector 6)
;Dialog item states
(define dActive $0001)
(define dExit $0002)
(define dBold $0004)
(define dSelected $0008)
(define dIconTop $0010)
;Window manager defines
(define stdWindow $0000)
(define wNoSave $0001)
(define wNoBorder $0002)
(define wTitled $0004)
(define wCustom $0080)
;Text justification for DItem mode
(define teJustLeft 0)
(define teJustCenter 1)
(define teJustRight -1)
;Message type definitions
(define TEXT_MSG $0001)
(define CD_MSG $0002)
;Defines for messages
(define NEXT -1)
(define ALL 0)
;╔═══════════════╗
;║ ║
;║ Event Defines ║
;║ ║
;╚═══════════════╝
;Event types
(define nullEvt $0000)
(define mouseDown $0001)
(define mouseUp $0002)
(define keyDown $0004)
(define keyUp $0008)
(define direction $0040)
(define speechEvent $0080)
(define joyDown $0100)
(define joyUp $0200)
(define walkEvent $1000)
(define helpEvent $2000)
(define userEvent $4000)
(define allEvents $7fff)
(define leaveIt $8000)
(define speechNoun 1)
(define speechVerb 0)
;Event modifiers (in who property)
(define shiftRight 1) ; right shift key pressed
(define shiftLeft 2) ; left shift key pressed
(define shiftDown 3) ; either shift key pressed
(define ctrlDown 4) ; control key pressed
(define altDown 8) ; alt key down pressed
;Pseudo selectors for SetMenu, Display, and Print (eventually)
; must be duplicated by #define's in KERNEL.H
(define p_at: 100)
(define p_mode: 101)
(define p_color: 102)
(define p_back: 103)
(define p_style: 104)
(define p_font: 105)
(define p_width: 106)
(define p_save: 107)
(define p_restore: 108)
(define p_said: 109)
(define p_text: 110)
(define p_key: 111)
(define p_state: 112)
(define p_value: 113)
(define p_dispose: 114)
(define p_time: 115)
(define p_title: 116)
(define p_draw: 117)
(define p_edit: 118)
(define p_button: 119)
(define p_icon: 120)
(define p_noshow: 121)
;Direction event messages.
(enum
dirStop
dirN
dirNE
dirE
dirSE
dirS
dirSW
dirW
dirNW
)
;Standard loop order for actors
(enum
loopE
loopW
loopS
loopN
loopSE
loopSW
loopNE
loopNW
)
(enum
facingEast
facingWest
facingSouth
facingNorth
facingSE
facingSW
facingNE
facingNW
)
;╔═════════════╗
;║ ║
;║ Key Defines ║
;║ ║
;╚═════════════╝
(define ESC 27)
(define SPACEBAR 32)
(define ENTER `^m)
(define TAB `^i)
(define SHIFTTAB $0f00)
(define BACKSPACE `^h)
;Numeric key code in scan code order with missing codes added
(define HOMEKEY $4700)
(define UPARROW $4800)
(define PAGEUP $4900)
(define LEFTARROW $4b00)
(define CENTERKEY $4c00)
(define RIGHTARROW $4d00)
(define ENDKEY $4f00)
(define DOWNARROW $5000)
(define PAGEDOWN $5100)
(define INSERT $5200)
(define DELETE $5300)
;╔════════════════════╗
;║ ║
;║ Signal Bit Defines ║
;║ ║
;╚════════════════════╝
(define stopUpdOn $0001)
(define startUpdOn $0002)
(define updOn $0003)
(define notUpd $0004)
(define hideActor $0008)
(define fixPriOn $0010)
(define viewAdded $0020) ;view will be added to picture
(define forceUpdOn $0040)
(define actorHidden $0080)
(define staticView $0100)
(define blocked $0400) ;tried to move, but couldn't
(define fixedLoop $0800) ;loop is fixed
(define skipCheck $1000) ;onMe will check skip
(define ignrHrz $2000) ;can ignore horizon
(define ignrAct $4000) ;can ignore other actors
(define delObj $8000)
(define ADDTOPIC (| delObj stopUpdOn viewAdded))
;scaleSignal bits
(define scalable $0001) ;scale on user-defined criteria
(define autoScale $0002) ;scaling as a function of y
(define noStepScale $0004) ;don't try to change stepSize when scaling
(define scaleBase 128) ;represents 100%
(define scaleShift 7)
(define MATCH -1)
;╔═══════════════════╗
;║ ║
;║ State Bit Defines ║
;║ ║
;╚═══════════════════╝
(define dynamicName $0001) ;name of object is dynamically allocated
(define approachObj $0002) ;ego will try to approach objects
(define onMeIsControl $0004) ;onMeCheck is bit-mapped control colors
;╔═══════════════╗
;║ ║
;║ Sound Defines ║
;║ ║
;╚═══════════════╝
(define SND_DONE -1) ;sound finished playing
;MIDI commands
(define mNOTEOFF $80)
(define mNOTEON $90)
(define mPOLYAFTER $a0)
(define mCONTROLLER $b0)
(define mPROGRAMCHANGE $c0)
(define mCHNLAFTER $d0)
(define mPITCHBEND $e0)
;MIDI controller #'s
(define mMODULATION 1)
(define mVOLUME 7)
(define mPAN 10)
(define mMUTE 78)
;Flags bits
(define mNOPAUSE $0001)
(define mFIXEDPRI $0002)
;╔═══════════════╗
;║ ║
;║ Color Defines ║
;║ ║
;╚═══════════════╝
;Screen colors
(define BLACK 0)
;CONTROL colors
(define cBLACK $0001) ; 0
(define cBLUE $0002) ; 1
(define cGREEN $0004) ; 2
(define cCYAN $0008) ; 3
(define cRED $0010) ; 4
(define cMAGENTA $0020) ; 5
(define cBROWN $0040) ; 6
(define cLGREY $0080) ; 7
(define cGREY $0100) ; 8
(define cLBLUE $0200) ; 9
(define cLGREEN $0400) ; 10
(define cLCYAN $0800) ; 11
(define cLRED $1000) ; 12
(define cLMAGENTA $2000) ; 13
(define cYELLOW $4000) ; 14
(define cWHITE $8000) ; 15
;VISUAL colors
(enum
vBLACK ; 0
vBLUE ; 1
vGREEN ; 2
vCYAN ; 3
vRED ; 4
vMAGENTA ; 5
vBROWN ; 6
vLGREY ; 7
vGREY ; 8
vLBLUE ; 9
vLGREEN ; 10
vLCYAN ; 11
vLRED ; 12
vLMAGENTA ; 13
vYELLOW ; 14
vWHITE ; 15
)
;PRIORITY colors
(enum
pBLACK ; 0
pBLUE ; 1
pGREEN ; 2
pCYAN ; 3
pRED ; 4
pMAGENTA ; 5
pBROWN ; 6
pLGREY ; 7
pGREY ; 8
pLBLUE ; 9
pLGREEN ; 10
pLCYAN ; 11
pLRED ; 12
pLMAGENTA ; 13
pYELLOW ; 14
pWHITE ; 15
)
;╔═════════════════╗
;║ ║
;║ Iconbar Defines ║
;║ ║
;╚═════════════════╝
(define RELVERIFY $0001) ;release verify, track mouse
(define IMMEDIATE $0002) ;do the job now, don't condition events
(define DISABLED $0004) ;icon or bar not enabled
(define TRANSLATOR $0010) ;condition event message (used internally)
(define IB_ACTIVE $0020) ;iconbar is up
(define HIDEBAR $0040) ;close bar after action
(define FIXED_POSN $0080) ;Item has fixed position in inv window
(define VICON $0100) ;up and down arrows will advance and retreat
(define RELSEND $0200) ;for sliders-don't send message until mouseUp
(define OPENIFONME $0400) ;close if mouse not on bar
(define NOCLICKHELP $0800)
(define UPDATE_CURSOR $1000) ;transfer view, loop, & cel to cursor obj
(define FORCE $8000)
;╔══════════════════════════╗
;║ ║
;║ System Globals (0 to 99) ║
;║ ║
;╚══════════════════════════╝
(global
ego 0 ;pointer to ego
theGame 1 ;ID of the Game instance
curRoom 2 ;ID of current room
unused_1 3
quit 4 ;when TRUE, quit game
cast 5 ;collection of actors
regions 6 ;set of current regions
timers 7 ;list of timers in the game
sounds 8 ;set of sounds being played
inventory 9 ;set of inventory items in game
addToPics 10 ;list of views added to the picture
curRoomNum 11 ;current room number
prevRoomNum 12 ;previous room number
newRoomNum 13 ;number of room to change to
debugOn 14 ;generic debug flag -- set from debug menu
score 15 ;the player's current score
possibleScore 16 ;highest possible score
textCode 17 ;code that handles interactive text
cuees 18 ;list of who-to-cues for next cycle
theCursor 19 ;the number of the current cursor
normalCursor 20 = ARROW_CURSOR ;number of normal cursor form
waitCursor 21 = HAND_CURSOR ;cursor number of "wait" cursor
userFont 22 = USERFONT ;font to use for Print
smallFont 23 = 4 ;small font for save/restore, etc.
lastEvent 24 ;the last event (used by save/restore game)
modelessDialog 25 ;the modeless Dialog known to User and Intrface
bigFont 26 = USERFONT ;large font
version 27 = 0 ;pointer to 'incver' version string
; WARNING! Must be set in room 0
; (usually to {x.yyy } or {x.yyy.zzz})
unused_3 28
curSaveDir 29 ;address of current save drive/directory string
unused_4 30
perspective 31 ;player's viewing angle: degrees away
; from vertical along y axis
features 32 ;locations that may respond to events
unused_5 33
useSortedFeatures 34 = FALSE ;enable cast & feature sorting?
unused_6 35
;actors behind ego within angle
;from straight behind.
;Default zero is no blind spot
overlays 36 = -1
doMotionCue 37 ;a motion cue has occurred - process it
systemWindow 38 ;ID of standard system window
unused_7 39
unused_8 40
modelessPort 41
sysLogPath 42 ;-used for system standard logfile path
endSysLogPath 62 ;/ (uses 40 globals)
gameControls 63 ;pointer to instance of game controls
ftrInitializer 64 ;pointer to code that gets called from
; a feature's init
doVerbCode 65 ;pointer to code that gets invoked if
; no feature claims a user event
approachCode 66 ;pointer to code that translates verbs
; into bits
useObstacles 67 = TRUE ;will Ego use PolyPath or not?
unused_9 68
theIconBar 69 ;points to TheIconBar or Null
mouseX 70 ;-last known mouse position
mouseY 71 ;/
keyDownHandler 72 ;-our EventHandlers, get called by game
mouseDownHandler 73 ;/
directionHandler 74 ;/
speechHandler 75 ;a special handler for speech events
lastVolume 76
pMouse 77 = NULL ;pointer to a Pseudo-Mouse, or NULL
theDoits 78 = NULL ;list of objects to get doits each cycle
eatMice 79 = 60 ;how many ticks before we can mouse
user 80 = NULL ;pointer to specific applications User
syncBias 81 ;-globals used by sync.sc
theSync 82 ;/ (will be removed shortly)
unused_10 83 ;
fastCast 84 ;list of talkers on screen
inputFont 85 = SYSFONT ;font used for user type-in
tickOffset 86 ;used to adjust gameTime after restore
howFast 87 ;measurment of how fast a machine is
gameTime 88 ;ticks since game start
narrator 89 ;pointer to narrator (normally Narrator)
msgType 90 = TEXT_MSG ;type of messages used
messager 91 ;pointer to messager (normally Messager)
prints 92 ;list of Print's on screen
walkHandler 93 ;list of objects to get walkEvents
textSpeed 94 = 2 ;time text remains on screen
altPolyList 95 ;list of alternate obstacles
lastSysGlobal 99
)
-
I have the kernel documentation done, though I still have to finish linking the index entries.
http://sciwiki.sierrahelp.com//index.php?title=SCI_Kernel_Documentation
-
Gabriel Knight decompiled source in (roughly) Sierra script
-
*inhuman noise of excitement*
-
Too bad all this was not available before Brian set the Studio syntax. I understand the work it would take to do a new template game using the SCI script, but how much work would it take to get the compiler to work with it? Not that I am asking that it be done, I'm just curious.
-
I understand the work it would take to do a new template game using the SCI script
Do you want a Studio-to-Script converter? Cos I've been looking for a parser challenge.
I may or may not be joking.
-
Well, you could assume from the GK decompiled code that this functionality already exists (not to mention the github comments I hinted at before).
The compiler already works with a syntax tree. The steps are:
Studio source code -> (parser)-> syntax tree -> (compiler) -> byte code
I've written the Sierra script parser, so it was mostly a matter of just substituting the new parser:
Sierra source code -> (new Sierra syntax parser)-> syntax tree -> (compiler) -> byte code
The parser wasn't exactly trivial, and it's probably not easy code to understand if you didn't write it, but it's not too bad. I can basically write the grammar in BNF form using C++ operators, very similar to Boost Spirit. Only took a 3 days or so. (Separate from that, minor modifications to the compiler were required to support continue statements, and multi-level break/continue).
And the decompiler does the opposite:
byte code -> (ridiculously complex decompiler) -> syntax tree -> (source code formatter) -> source code.
And clearly from GK1 source provided I've already got the Sierra source code formatter working:
byte code -> (ridiculously complex decompiler) -> syntax tree -> (Sierra source code formatter) -> Sierra source code.
From the above, you may deduce that the pieces are in place for the following:
Studio source code -> (Studio parser) -> syntax tree -> (Sierra source code formatter) -> Sierra source
And you'd be correct!
You'd also be correct if you assumed I have implemented one-click functionality to convert an entire project from Studio syntax to Sierra syntax, and that I did this with the template game and it all successfully compiles and runs (to the best of my knowledge) without problems. I'm sure there are some bugs somewhere, but I haven't found any major ones yet.
You could also technically go back to Studio script from Sierra script, though I haven't tested that yet, and I know it will fail for some cases (like continue statements, which have no equivalent). So let's call it "not supported".
The benefits of having the syntax tree abstraction in there are huge. It made things like the Insert Object/Insert Method script editor functionality nearly "just work". Because that was never directly pasting source code... it parsed source code (the stuff in the Objects subfolder of SCI Companion) into a syntax tree, made the necessary modifications, and then spit it out using the source code formatter, and pasted that.
I've tried to make the Sierra syntax code formatter much better than the Studio syntax code formatter. So if you see badly placed parentheses or badly-indented stuff, let me know. I haven't even looked at the GK1 source code I provided. I've just been looking at the template game.
The major thing left to do is to fix up the autocomplete functionality for the new syntax. And then some polish and what not...
-
I should also mention I've taken some deviations from Sierra script syntax, much of it due to the way the compiler is set up (and requiring compatibility with SCI Studio). It's possible I can make it closer to the original, but only if I don't need to maintain two separate ways of compiling. The more code I can re-use the easier it makes testing, etc...
Anyway, some differences:
- : or ? will be required for selector names. Sierra's code appears to have stuck with this convention anyway, so not a big deal.
- , will be optional (instead of required) when separating selector calls (made possible by requiring : and ? above)
- procedures and methods don't need to be forward declared
- Currently I'm still requiring the "use" statements that Studio syntax uses ( :P ). Sierra didn't have this. As far as I can tell, all classes were in global scope (so they could always be referred to). And procedures required an "extern" statement that mapped procedure names to script/export index pairs, and which was typically included in a header file I think. I'm tempted to try to replicate this, but it might mean maintaining two different code paths for part of the compilation process, and I'm a bit reluctant to do that.
Some possibly irritating things about the Sierra syntax that I *won't* change:
- all operators have to have white space after them:
(++i) -> this is a compile error
(++ i) -> this is valid
- it is *very* strict about parentheses. Unlike Studio syntax, you cannot arbitrarily enclose expressions in parentheses. Luckily this makes it much easier to parse than Studio syntax.
(if (something) 1 else 2) -> compile error, because something is enclosed in parentheses. We think it's a procedure.
(if something 1 else 2) -> valid
(if (== something TRUE) 1 else 2) -> valid, since all expressions have to be enclosed in parentheses
= temp0 6 -> compile error
(= temp0 6) -> valid!
- the array syntax is unorthodox, but I'm not changing that
The Sierra syntax overall is easier to parse than Studio syntax. It's more logical and consistent (and compiles are about 20% faster).
-
Part of my curiosity is from going through the docs and noting the differences. The way my brain is wired the Sierra syntax seemed to be easier to understand.
BTW, the Kernel Functions document is fully Wikified, including the index.
-
troflip,
your work is outstanding.
I'm sorry my leaked source gave you so much work. I wish I had it sooner, so you won't have to do stuff twice.
Thank you for doing so much for our small community!
-
Did you improve the decompiler to support more constructs?
Is it able to decompile stuff that used to fallback to disassembly?
-
Nope, I've done no work on the decompiler. So, that means you'll never see continue or contif in any of the decompiled source code (and those will probably fall back to assembly). Honestly, the decompiler was a real headache to work on and test, so I'd like to leave it as is.
The other "new" statements, like cond, repeat or breakif will, however, show up in decompiled code. Those are just transformations of already-existing statements like ifs and loops.
-
Indeed, troflip. Thank you so very much. I really need to get back to a SCI.1 project, too. Without you Collector, Gumby (sometimes), and I would still be here trying to make sense out of the SCI Studio 4 source code which is beyond any of our capabilities. I was still trying to figure out how to get SCI1/SCI1.1 pictures to display. I acquired an ancient version of Borland just to open the SCI Studio project and get it to compile. Half the stuff was never completed and things kept causing crashes. I fixed simple bugs, but I couldn't do anything else. The bitmap import function was incredibly gimped because what I did get working came out all distorted and the wrong colours. So thank you!!
Here's an off-topic question, the VGA SCI1 template game is just sitting there in the SCI Studio 4 source. What are the chances of getting that working? Did SCI Studio 4 VGA also have a compiler for SCI1 included? I'm not asking anybody to work on it, I'm just curious how close Brian actually was.
-
Speaking of Brian's work, does anybody have a copy of that VGA demo he'd released?
-
Speaking of Brian's work, does anybody have a copy of that VGA demo he'd released?
Here you go.
-
Thank you.
Is it me or are those picture resources so messed up only SSCI can load them?
-
SV does not.
-
Not to mention the LOOKUP_ERRORs everywhere in the decompilation -- I've never seen those before.
-
That demo is actually pretty cool, lol.
"SCI Studio VGA will be better than SCI Studio EGA!"
Looks like he was using the interpreter from Leisure Suit Larry VGA (1.000.577). Companion completely mis-recognizes the resources as being from SCI0 EGA. So does SV.exe, I guess.
btw, if you open the game version dialog and switch the pic format to VGA 1 and click reload, Companion will show the pics correctly (you have to do this each time you open the game, I should really make it stick).
Anyone want to make a SCI Companion VGA game demo?
-
I read that as "redo this for Companion" and I was like SURE
-
btw, if you open the game version dialog and switch the pic format to VGA 1 and click reload, Companion will show the pics correctly (you have to do this each time you open the game, I should really make it stick).
It can be set in SV.exe as well via (Version Info --> Graphics --> Version 1) && (Version Info --> Auto detection --> Off)
-
*rips the pictures, giggles at Adam West*
Update: I am now in a position to replace the screenshots and text in this remake.
-
Here's some "media" if you need them.
-
I'll find a use for those.
Tomorrow.
-
Phil, what about that little demo you made a while back? That does demonstrate what you can do.
-
Yeah, that's still around. Argh, I still have some work left to do on it. That's more of a "this is how you can do some things", instead of a "rah rah rah SCI Companion" thing, which is kind of what Brian's thing was, and presumably what Kawa's interpretation of it will be like.
-
That it will be.
Edit: okay, I'm done.
-
Haha, awesome. Nice job :-0