Initial commit
This commit is contained in:
1593
engines/director/lingo/docs/d10.1-keywords.txt
Normal file
1593
engines/director/lingo/docs/d10.1-keywords.txt
Normal file
File diff suppressed because it is too large
Load Diff
264
engines/director/lingo/docs/d3.keywords.txt
Normal file
264
engines/director/lingo/docs/d3.keywords.txt
Normal file
@@ -0,0 +1,264 @@
|
||||
|
||||
-
|
||||
-
|
||||
()
|
||||
*
|
||||
/
|
||||
&
|
||||
&&
|
||||
+
|
||||
<
|
||||
<=
|
||||
<>
|
||||
=
|
||||
>
|
||||
>=
|
||||
abs
|
||||
alert
|
||||
and
|
||||
backColor
|
||||
BACKSPACE
|
||||
beep
|
||||
beepOn
|
||||
bottom
|
||||
buttonStyle
|
||||
cast hilite
|
||||
cast name
|
||||
cast number
|
||||
cast picture
|
||||
cast size
|
||||
cast text
|
||||
castNum
|
||||
centerStage
|
||||
char
|
||||
chars
|
||||
charToNum
|
||||
checkBoxAccess
|
||||
checkBoxType
|
||||
clearGlobals
|
||||
clickOn
|
||||
closeDA
|
||||
closeResFile
|
||||
closeXLib
|
||||
colorDepth
|
||||
colorQD
|
||||
commandDown
|
||||
constrainH
|
||||
constraint
|
||||
constrainV
|
||||
contains
|
||||
continue
|
||||
controlDown
|
||||
controller
|
||||
cursor
|
||||
cursor
|
||||
date
|
||||
delay
|
||||
delete
|
||||
directToStage
|
||||
do
|
||||
dontPassEvent
|
||||
doubleClick
|
||||
duration
|
||||
editableText
|
||||
EMPTY
|
||||
ENTER
|
||||
exit
|
||||
exitLock
|
||||
factory
|
||||
factory
|
||||
FALSE
|
||||
field
|
||||
field textAlign
|
||||
field textFont
|
||||
field textHeight
|
||||
field textSize
|
||||
field textStyle
|
||||
fixStageSize
|
||||
floatp
|
||||
floatPrecision
|
||||
foreColor
|
||||
frame
|
||||
framesToHMS
|
||||
freeBlock
|
||||
freeBytes
|
||||
fullColorPermit
|
||||
global
|
||||
go to
|
||||
go to movie
|
||||
height
|
||||
hilite
|
||||
HMStoFrames
|
||||
if
|
||||
imageDirect
|
||||
immediate
|
||||
ink
|
||||
installMenu
|
||||
instance
|
||||
integer
|
||||
integerp
|
||||
item
|
||||
key
|
||||
keyCode
|
||||
keyDownScript
|
||||
label
|
||||
labelList
|
||||
lastClick
|
||||
lastEvent
|
||||
lastKey
|
||||
lastRoll
|
||||
left
|
||||
length
|
||||
line
|
||||
lineSize
|
||||
locH
|
||||
locV
|
||||
loop
|
||||
machineType
|
||||
macro
|
||||
marker
|
||||
maxInteger
|
||||
mci
|
||||
memorySize
|
||||
menu checkMark
|
||||
menu enabled
|
||||
menu name
|
||||
menu script
|
||||
menu:
|
||||
method
|
||||
mod
|
||||
mouseCast
|
||||
mouseChar
|
||||
mouseDown
|
||||
mouseDownScript
|
||||
mouseH
|
||||
mouseItem
|
||||
mouseLine
|
||||
mouseUp
|
||||
mouseUpScript
|
||||
mouseV
|
||||
mouseWord
|
||||
moveableSprite
|
||||
movie
|
||||
movieRate
|
||||
movieTime
|
||||
multiSound
|
||||
not
|
||||
nothing
|
||||
numToChar
|
||||
objectp
|
||||
offset
|
||||
on
|
||||
on idle
|
||||
on startMovie
|
||||
on stepMovie
|
||||
on stopMovie
|
||||
open
|
||||
openDA
|
||||
openResFile
|
||||
openXLib
|
||||
optionDown
|
||||
or
|
||||
pathName
|
||||
pattern
|
||||
pause
|
||||
pauseState
|
||||
perFrameHook
|
||||
play
|
||||
play done
|
||||
play movie
|
||||
playAccel
|
||||
preLoad
|
||||
preLoadCast
|
||||
printFrom
|
||||
puppet
|
||||
puppetPalette
|
||||
puppetSound
|
||||
puppetSprite
|
||||
puppetTempo
|
||||
puppetTransition
|
||||
put
|
||||
put after
|
||||
put before
|
||||
put into
|
||||
quickTimePresent
|
||||
quit
|
||||
QUOTE
|
||||
ramNeeded
|
||||
random
|
||||
repeat while
|
||||
repeat with
|
||||
restart
|
||||
result
|
||||
return
|
||||
RETURN
|
||||
right
|
||||
rollover
|
||||
romanLingo
|
||||
selection
|
||||
selEnd
|
||||
selStart
|
||||
set
|
||||
setCallBack
|
||||
shiftDown
|
||||
showGlobals
|
||||
showLocals
|
||||
showResFile
|
||||
showXlib
|
||||
shutDown
|
||||
sound
|
||||
sound fadeIn
|
||||
sound fadeOut
|
||||
sound playFile
|
||||
sound stop
|
||||
sound volume
|
||||
soundBusy
|
||||
soundEnabled
|
||||
soundLevel
|
||||
sprite s intersects
|
||||
sprite s within
|
||||
spriteBox
|
||||
sqrt
|
||||
stageBottom
|
||||
stageColor
|
||||
stageLeft
|
||||
stageRight
|
||||
stageTop
|
||||
starts
|
||||
startTime
|
||||
startTimer
|
||||
stillDown
|
||||
stopTime
|
||||
stretch
|
||||
string
|
||||
stringp
|
||||
switchColorDepth
|
||||
symbolp
|
||||
TAB
|
||||
ticks
|
||||
time
|
||||
timeoutKeydown
|
||||
timeoutLapsed
|
||||
timeoutLength
|
||||
timeoutMouse
|
||||
timeoutPlay
|
||||
timeoutScript
|
||||
timer
|
||||
top
|
||||
trails
|
||||
TRUE
|
||||
type
|
||||
unLoad
|
||||
unLoadCast
|
||||
updateStage
|
||||
value
|
||||
visibility
|
||||
volume
|
||||
when keyDown
|
||||
when mouseDown
|
||||
when mouseUp
|
||||
when timeOut
|
||||
width
|
||||
word
|
||||
xfactoryList
|
||||
zoomBox
|
||||
21
engines/director/lingo/docs/d3.menus.txt
Normal file
21
engines/director/lingo/docs/d3.menus.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
menu: Commands A-O
|
||||
alert;beep;clearGlobals;closeDA;closeResFile;closeXLib;continue;cursor;delay;delete;do;dontPassEvent;editableText;go to;go to movie;hilite;installMenu;mci;moveableSprite;nothing;open;openDA;openResFile;openXLib
|
||||
menu: Commands P-Z
|
||||
pause;play;play done;play movie;playAccel;preLoad;preLoadCast;printFrom;puppetPalette;puppetSound;puppetSprite;puppetTempo;puppetTransition;put ;put after;put before;put into;quit;restart;set;setCallBack;showGlobals;showLocals;showResFile;showXlib;shutDown;sound fadeIn;sound fadeOut;sound playFile;sound stop;spriteBox;startTimer;unLoad;unLoadCast;updateStage;when keyDown;when mouseDown;when mouseUp;when timeOut;zoomBox
|
||||
menu: Functions A-L
|
||||
abs;char;chars;charToNum;clickOn;colorQD;commandDown;constrainH;constrainV;controlDown;date;doubleClick;factory;floatp;frame;framesToHMS;freeBlock;freeBytes;HMStoFrames;integer;integerp;item;key;keyCode;label;labelList;lastClick;lastEvent;lastKey;lastRoll;length;line
|
||||
menu: Functions M-Z
|
||||
machineType;marker;memorySize;mouseCast;mouseChar;mouseItem;mouseLine;mouseDown;mouseWord;mouseH;mouseUp;mouseV;movie;multiSound;numToChar;objectp;offset;optionDown;pathName;pauseState;quickTimePresent;ramNeeded;random;result;rollover;selection;shiftDown;sqrt;stageBottom;stageLeft;stageRight;stageTop;stillDown;string;stringp;soundBusy;symbolp;ticks;time;value;word;xfactoryList
|
||||
menu: Keywords
|
||||
exit;factory;global;if;instance;macro;menu:;method;on;on idle;on startMovie;on stepMovie;on stopMovie;repeat while;repeat with;return
|
||||
menu: Operators
|
||||
() ;sprite s within ;sprite s intersects ; - ;not ;and ;or ;* ;/ ;mod ;+ ; - ;& ;&& ;< ;<= ;> ;>= ;<> ;contains ;starts ;=
|
||||
menu: Constants
|
||||
BACKSPACE ;EMPTY ;ENTER ;FALSE ;QUOTE ;RETURN ;TAB ;TRUE
|
||||
menu: Properties
|
||||
beepOn;buttonStyle;centerStage;checkBoxAccess;checkBoxType;colorDepth;exitLock;fixStageSize;floatPrecision;fullColorPermit;imageDirect;keyDownScript;maxInteger;mouseDownScript;mouseUpScript;perFrameHook;romanLingo;soundEnabled;soundLevel;stageColor;switchColorDepth;timeoutKeydown;timeoutLapsed;timeoutLength;timeoutMouse;timeoutPlay;timeoutScript;timer
|
||||
menu: Sprite Properties
|
||||
backColor;bottom;castNum;constraint;cursor;foreColor;height;immediate;ink;left;lineSize;locH;locV;movieRate;movieTime;pattern;puppet;right;startTime;stopTime;stretch;top;trails;type;visibility;volume;width
|
||||
menu: Other Properties
|
||||
cast hilite;cast name;cast number;cast picture;cast size;cast text;controller;directToStage;duration;field;field textAlign;field textFont;field textHeight;field textSize;field textStyle;loop;menu checkMark;menu enabled;menu name;menu script;selEnd;selStart;sound;sound volume
|
||||
|
||||
505
engines/director/lingo/docs/d4-keywords.txt
Normal file
505
engines/director/lingo/docs/d4-keywords.txt
Normal file
@@ -0,0 +1,505 @@
|
||||
,*
|
||||
,
|
||||
(
|
||||
)
|
||||
[
|
||||
]
|
||||
:
|
||||
-
|
||||
+
|
||||
not
|
||||
*
|
||||
/
|
||||
mod
|
||||
contains
|
||||
starts
|
||||
and
|
||||
or
|
||||
=
|
||||
<
|
||||
<>
|
||||
<=
|
||||
>
|
||||
>=
|
||||
&
|
||||
&&
|
||||
then
|
||||
else
|
||||
the
|
||||
char
|
||||
word
|
||||
item
|
||||
line
|
||||
#
|
||||
true
|
||||
false
|
||||
return
|
||||
enter
|
||||
tab
|
||||
backSpace
|
||||
quote
|
||||
empty
|
||||
field
|
||||
sprite
|
||||
put
|
||||
go
|
||||
play
|
||||
to
|
||||
if
|
||||
into
|
||||
before
|
||||
after
|
||||
idle
|
||||
startMovie
|
||||
stopMovie
|
||||
stepMovie
|
||||
mouseUp
|
||||
mouseDown
|
||||
done
|
||||
frame
|
||||
method
|
||||
of
|
||||
me
|
||||
off
|
||||
macro
|
||||
factory
|
||||
while
|
||||
repeat
|
||||
end
|
||||
with
|
||||
movie
|
||||
type
|
||||
castNum
|
||||
top
|
||||
left
|
||||
width
|
||||
height
|
||||
linesize
|
||||
ink
|
||||
keyDown
|
||||
within
|
||||
intersects
|
||||
nosound
|
||||
byFrame
|
||||
click
|
||||
clickStop
|
||||
loop
|
||||
noUpdate
|
||||
sync
|
||||
tempo
|
||||
whatfits
|
||||
mnew
|
||||
mname
|
||||
mdescribe
|
||||
matframe
|
||||
right
|
||||
bottom
|
||||
locV
|
||||
locH
|
||||
pattern
|
||||
transition
|
||||
palette
|
||||
sound
|
||||
editableText
|
||||
moveableSprite
|
||||
pause
|
||||
timeout
|
||||
label
|
||||
puppet
|
||||
immediate
|
||||
forecolor
|
||||
backcolor
|
||||
stretch
|
||||
cursor
|
||||
text
|
||||
hilite
|
||||
cast
|
||||
mverb
|
||||
mdispose
|
||||
mget
|
||||
mput
|
||||
super
|
||||
noflush
|
||||
xcmdglue
|
||||
midiStart
|
||||
midiStop
|
||||
midiContinue
|
||||
midiBeat
|
||||
midiSong
|
||||
midiSongpointer
|
||||
constraint
|
||||
mPerform
|
||||
mActivate
|
||||
mUpdate
|
||||
mIdle
|
||||
mMouseDown
|
||||
mMouseUp
|
||||
mKeyDown
|
||||
mStartUp
|
||||
mQuit
|
||||
playRect
|
||||
mEvent
|
||||
on
|
||||
mOpenEditor
|
||||
mCloseEditor
|
||||
mSetText
|
||||
mGetText
|
||||
noclear
|
||||
mVerbDispose
|
||||
startScript
|
||||
version
|
||||
mRespondsTo
|
||||
mInstanceRespondsTo
|
||||
mMessageList
|
||||
chars
|
||||
words
|
||||
items
|
||||
lines
|
||||
picture
|
||||
in
|
||||
mPerformOther
|
||||
fadeIn
|
||||
fadeOut
|
||||
stop
|
||||
playFile
|
||||
playCast
|
||||
name
|
||||
textStyle
|
||||
textFont
|
||||
textHeight
|
||||
textAlign
|
||||
textSize
|
||||
castmembers
|
||||
center
|
||||
plain
|
||||
bold
|
||||
italic
|
||||
underline
|
||||
outline
|
||||
shadow
|
||||
condense
|
||||
extend
|
||||
mSetHandler
|
||||
menu
|
||||
menus
|
||||
menuItem
|
||||
menuItems
|
||||
mAtTransition
|
||||
mCanDoTrans
|
||||
mTransDial
|
||||
resource
|
||||
soundEnabled
|
||||
imageDirect
|
||||
colorDepth
|
||||
exitLock
|
||||
fullColorPermit
|
||||
selStart
|
||||
selEnd
|
||||
switchColorDepth
|
||||
fixStageSize
|
||||
centerStage
|
||||
checkBoxAccess
|
||||
checkBoxType
|
||||
buttonStyle
|
||||
multiSound
|
||||
stageColor
|
||||
beepOn
|
||||
mouseDownScript
|
||||
mouseUpScript
|
||||
keyDownScript
|
||||
timeoutScript
|
||||
timer
|
||||
timeoutLength
|
||||
timeoutLapsed
|
||||
timeoutKeydown
|
||||
timeoutMouse
|
||||
timeoutPlay
|
||||
number
|
||||
volume
|
||||
checkMark
|
||||
enabled
|
||||
script
|
||||
floatPrecision
|
||||
instance
|
||||
global
|
||||
set
|
||||
exit
|
||||
when
|
||||
delete
|
||||
puppetSound
|
||||
open
|
||||
ticks
|
||||
abs
|
||||
length
|
||||
string
|
||||
charToNum
|
||||
numToChar
|
||||
sqrt
|
||||
integerp
|
||||
stringp
|
||||
objectp
|
||||
floatp
|
||||
integer
|
||||
offset
|
||||
maxinteger
|
||||
result
|
||||
nothing
|
||||
value
|
||||
memorysize
|
||||
freeBlock
|
||||
freeBytes
|
||||
commandDown
|
||||
optionDown
|
||||
stillDown
|
||||
shiftDown
|
||||
controlDown
|
||||
clickOn
|
||||
key
|
||||
stageLeft
|
||||
stageRight
|
||||
stageTop
|
||||
stageBottom
|
||||
machineType
|
||||
mouseH
|
||||
mouseV
|
||||
selection
|
||||
pathName
|
||||
labelList
|
||||
pauseState
|
||||
mouseLine
|
||||
mouseItem
|
||||
mouseWord
|
||||
mouseChar
|
||||
mouseCast
|
||||
colorQD
|
||||
doubleClick
|
||||
keyCode
|
||||
lastClick
|
||||
lastKey
|
||||
lastRoll
|
||||
lastEvent
|
||||
marker
|
||||
rollOver
|
||||
soundBusy
|
||||
xfactoryList
|
||||
random
|
||||
constrainH
|
||||
constrainV
|
||||
continue
|
||||
delay
|
||||
openDA
|
||||
installMenu
|
||||
showResFile
|
||||
printFrom
|
||||
quit
|
||||
spriteBox
|
||||
startTimer
|
||||
restart
|
||||
shutDown
|
||||
zoomBox
|
||||
openXLib
|
||||
closeXLib
|
||||
showXLib
|
||||
dontPassEvent
|
||||
openResFile
|
||||
closeResFile
|
||||
updateStage
|
||||
playAccel
|
||||
immediateSprite
|
||||
puppetSprite
|
||||
puppetTempo
|
||||
puppetTransition
|
||||
puppetPalette
|
||||
alert
|
||||
preLoad
|
||||
preLoadCast
|
||||
mci
|
||||
setCallBack
|
||||
beep
|
||||
showLocals
|
||||
showGlobals
|
||||
perFrameHook
|
||||
long
|
||||
short
|
||||
abbreviated
|
||||
abbrev
|
||||
abbr
|
||||
time
|
||||
date
|
||||
do
|
||||
clearGlobals
|
||||
unLoad
|
||||
unLoadCast
|
||||
trails
|
||||
duration
|
||||
controller
|
||||
directToStage
|
||||
visibility
|
||||
ramNeeded
|
||||
movieRate
|
||||
movieTime
|
||||
startTime
|
||||
stopTime
|
||||
romanLingo
|
||||
quickTimePresent
|
||||
picturep
|
||||
float
|
||||
soundLevel
|
||||
framesToHMS
|
||||
hmsToFrames
|
||||
mciWait
|
||||
mciBusy
|
||||
closeDA
|
||||
window
|
||||
copyToClipBoard
|
||||
pasteClipBoardInto
|
||||
move
|
||||
importFileInto
|
||||
duplicate
|
||||
findEmpty
|
||||
fileName
|
||||
title
|
||||
visible
|
||||
close
|
||||
titleVisible
|
||||
tell
|
||||
size
|
||||
add
|
||||
addAt
|
||||
addProp
|
||||
append
|
||||
deleteAt
|
||||
deleteAll
|
||||
deleteProp
|
||||
deleteOne
|
||||
getAt
|
||||
getProp
|
||||
getaProp
|
||||
getPropAt
|
||||
getPos
|
||||
getOne
|
||||
getLast
|
||||
setAt
|
||||
setProp
|
||||
setaProp
|
||||
count
|
||||
findPos
|
||||
findPosNear
|
||||
sort
|
||||
min
|
||||
max
|
||||
loc
|
||||
rect
|
||||
point
|
||||
inflate
|
||||
intersect
|
||||
union
|
||||
inside
|
||||
map
|
||||
scriptText
|
||||
regPoint
|
||||
bitmap
|
||||
filmLoop
|
||||
button
|
||||
shape
|
||||
digitalVideo
|
||||
modified
|
||||
loaded
|
||||
castType
|
||||
lastFrame
|
||||
frameLabel
|
||||
framePalette
|
||||
frameTempo
|
||||
frameScript
|
||||
moveToFront
|
||||
moveToBack
|
||||
sin
|
||||
cos
|
||||
tan
|
||||
atan
|
||||
exp
|
||||
log
|
||||
log10
|
||||
power
|
||||
pi
|
||||
param
|
||||
paramCount
|
||||
next
|
||||
previous
|
||||
keyUp
|
||||
erase
|
||||
depth
|
||||
randomSeed
|
||||
trace
|
||||
saveMovie
|
||||
clickLoc
|
||||
preLoadEventAbort
|
||||
updateMovieEnabled
|
||||
drawRect
|
||||
sourceRect
|
||||
windowType
|
||||
modal
|
||||
windowList
|
||||
itemDelimiter
|
||||
last
|
||||
keyUpScript
|
||||
forget
|
||||
down
|
||||
moviePath
|
||||
movieName
|
||||
enterFrame
|
||||
exitFrame
|
||||
halt
|
||||
abort
|
||||
pass
|
||||
property
|
||||
list
|
||||
linearList
|
||||
propList
|
||||
stage
|
||||
traceLoad
|
||||
traceLogFile
|
||||
purgePriority
|
||||
frameRate
|
||||
preloadRam
|
||||
pausedAtStart
|
||||
video
|
||||
blend
|
||||
scoreColor
|
||||
scriptNum
|
||||
searchPaths
|
||||
searchCurrentFolder
|
||||
movieFileSize
|
||||
movieFileFreeSize
|
||||
getNthFileNameInFolder
|
||||
actor
|
||||
actorList
|
||||
ancestor
|
||||
collectChangeRects
|
||||
updateRect
|
||||
stepFrame
|
||||
mouseTrack
|
||||
birth
|
||||
hitTest
|
||||
mouseHitTest
|
||||
ilk
|
||||
void
|
||||
voidp
|
||||
listp
|
||||
send
|
||||
sendAncestor
|
||||
symbolp
|
||||
crop
|
||||
cpuHogTicks
|
||||
symbol
|
||||
object
|
||||
activateWindow
|
||||
deactivateWindow
|
||||
openWindow
|
||||
closeWindow
|
||||
moveWindow
|
||||
zoomInWindow
|
||||
zoomOutWindow
|
||||
doEffects
|
||||
searchPath
|
||||
videoForWindowsPresent
|
||||
693
engines/director/lingo/docs/d5-keywords.txt
Normal file
693
engines/director/lingo/docs/d5-keywords.txt
Normal file
@@ -0,0 +1,693 @@
|
||||
,*
|
||||
,
|
||||
(
|
||||
)
|
||||
[
|
||||
]
|
||||
:
|
||||
-
|
||||
+
|
||||
not
|
||||
*
|
||||
/
|
||||
mod
|
||||
contains
|
||||
starts
|
||||
and
|
||||
or
|
||||
=
|
||||
<
|
||||
<>
|
||||
<=
|
||||
>
|
||||
>=
|
||||
&
|
||||
&&
|
||||
then
|
||||
else
|
||||
the
|
||||
char
|
||||
word
|
||||
item
|
||||
line
|
||||
#
|
||||
true
|
||||
false
|
||||
return
|
||||
enter
|
||||
tab
|
||||
backSpace
|
||||
quote
|
||||
empty
|
||||
field
|
||||
sprite
|
||||
put
|
||||
go
|
||||
play
|
||||
to
|
||||
if
|
||||
into
|
||||
before
|
||||
after
|
||||
idle
|
||||
startMovie
|
||||
stopMovie
|
||||
stepMovie
|
||||
mouseUp
|
||||
mouseDown
|
||||
done
|
||||
frame
|
||||
method
|
||||
of
|
||||
me
|
||||
off
|
||||
macro
|
||||
factory
|
||||
while
|
||||
repeat
|
||||
end
|
||||
with
|
||||
movie
|
||||
type
|
||||
castNum
|
||||
top
|
||||
left
|
||||
width
|
||||
height
|
||||
linesize
|
||||
ink
|
||||
keyDown
|
||||
within
|
||||
intersects
|
||||
nosound
|
||||
byFrame
|
||||
click
|
||||
clickStop
|
||||
loop
|
||||
noUpdate
|
||||
sync
|
||||
tempo
|
||||
whatfits
|
||||
mnew
|
||||
mname
|
||||
mdescribe
|
||||
matframe
|
||||
right
|
||||
bottom
|
||||
locV
|
||||
locH
|
||||
pattern
|
||||
transition
|
||||
palette
|
||||
sound
|
||||
editableText
|
||||
moveableSprite
|
||||
pause
|
||||
timeout
|
||||
label
|
||||
puppet
|
||||
immediate
|
||||
forecolor
|
||||
backcolor
|
||||
stretch
|
||||
cursor
|
||||
text
|
||||
hilite
|
||||
cast
|
||||
mverb
|
||||
mdispose
|
||||
mget
|
||||
mput
|
||||
super
|
||||
noflush
|
||||
xcmdglue
|
||||
midiStart
|
||||
midiStop
|
||||
midiContinue
|
||||
midiBeat
|
||||
midiSong
|
||||
midiSongpointer
|
||||
constraint
|
||||
mPerform
|
||||
mActivate
|
||||
mUpdate
|
||||
mIdle
|
||||
mMouseDown
|
||||
mMouseUp
|
||||
mKeyDown
|
||||
mStartUp
|
||||
mQuit
|
||||
playRect
|
||||
mEvent
|
||||
on
|
||||
mOpenEditor
|
||||
mCloseEditor
|
||||
mSetText
|
||||
mGetText
|
||||
noclear
|
||||
mVerbDispose
|
||||
startScript
|
||||
version
|
||||
mRespondsTo
|
||||
mInstanceRespondsTo
|
||||
mMessageList
|
||||
chars
|
||||
words
|
||||
items
|
||||
lines
|
||||
picture
|
||||
in
|
||||
mPerformOther
|
||||
fadeIn
|
||||
fadeOut
|
||||
stop
|
||||
playFile
|
||||
playCast
|
||||
name
|
||||
textStyle
|
||||
textFont
|
||||
textHeight
|
||||
textAlign
|
||||
textSize
|
||||
castmembers
|
||||
center
|
||||
plain
|
||||
bold
|
||||
italic
|
||||
underline
|
||||
outline
|
||||
shadow
|
||||
condense
|
||||
extend
|
||||
mSetHandler
|
||||
menu
|
||||
menus
|
||||
menuItem
|
||||
menuItems
|
||||
mAtTransition
|
||||
mCanDoTrans
|
||||
mTransDial
|
||||
resource
|
||||
soundEnabled
|
||||
imageDirect
|
||||
colorDepth
|
||||
exitLock
|
||||
fullColorPermit
|
||||
selStart
|
||||
selEnd
|
||||
switchColorDepth
|
||||
fixStageSize
|
||||
centerStage
|
||||
checkBoxAccess
|
||||
checkBoxType
|
||||
buttonStyle
|
||||
multiSound
|
||||
stageColor
|
||||
beepOn
|
||||
mouseDownScript
|
||||
mouseUpScript
|
||||
keyDownScript
|
||||
timeoutScript
|
||||
timer
|
||||
timeoutLength
|
||||
timeoutLapsed
|
||||
timeoutKeydown
|
||||
timeoutMouse
|
||||
timeoutPlay
|
||||
number
|
||||
volume
|
||||
checkMark
|
||||
enabled
|
||||
script
|
||||
floatPrecision
|
||||
instance
|
||||
global
|
||||
set
|
||||
exit
|
||||
when
|
||||
delete
|
||||
puppetSound
|
||||
open
|
||||
ticks
|
||||
abs
|
||||
length
|
||||
string
|
||||
charToNum
|
||||
numToChar
|
||||
sqrt
|
||||
integerp
|
||||
stringp
|
||||
objectp
|
||||
floatp
|
||||
integer
|
||||
offset
|
||||
maxinteger
|
||||
result
|
||||
nothing
|
||||
value
|
||||
memorysize
|
||||
freeBlock
|
||||
freeBytes
|
||||
commandDown
|
||||
optionDown
|
||||
stillDown
|
||||
shiftDown
|
||||
controlDown
|
||||
clickOn
|
||||
key
|
||||
stageLeft
|
||||
stageRight
|
||||
stageTop
|
||||
stageBottom
|
||||
machineType
|
||||
mouseH
|
||||
mouseV
|
||||
selection
|
||||
pathName
|
||||
labelList
|
||||
pauseState
|
||||
mouseLine
|
||||
mouseItem
|
||||
mouseWord
|
||||
mouseChar
|
||||
mouseCast
|
||||
colorQD
|
||||
doubleClick
|
||||
keyCode
|
||||
lastClick
|
||||
lastKey
|
||||
lastRoll
|
||||
lastEvent
|
||||
marker
|
||||
rollOver
|
||||
soundBusy
|
||||
xfactoryList
|
||||
random
|
||||
constrainH
|
||||
constrainV
|
||||
continue
|
||||
delay
|
||||
openDA
|
||||
installMenu
|
||||
showResFile
|
||||
printFrom
|
||||
quit
|
||||
spriteBox
|
||||
startTimer
|
||||
restart
|
||||
shutDown
|
||||
zoomBox
|
||||
openXLib
|
||||
closeXLib
|
||||
showXLib
|
||||
dontPassEvent
|
||||
openResFile
|
||||
closeResFile
|
||||
updateStage
|
||||
playAccel
|
||||
immediateSprite
|
||||
puppetSprite
|
||||
puppetTempo
|
||||
puppetTransition
|
||||
puppetPalette
|
||||
alert
|
||||
preLoad
|
||||
preLoadCast
|
||||
mci
|
||||
setCallBack
|
||||
beep
|
||||
showLocals
|
||||
showGlobals
|
||||
perFrameHook
|
||||
long
|
||||
short
|
||||
abbreviated
|
||||
abbrev
|
||||
abbr
|
||||
time
|
||||
date
|
||||
do
|
||||
clearGlobals
|
||||
unLoad
|
||||
unLoadCast
|
||||
trails
|
||||
duration
|
||||
controller
|
||||
directToStage
|
||||
visibility
|
||||
ramNeeded
|
||||
movieRate
|
||||
movieTime
|
||||
startTime
|
||||
stopTime
|
||||
romanLingo
|
||||
quickTimePresent
|
||||
picturep
|
||||
float
|
||||
soundLevel
|
||||
framesToHMS
|
||||
hmsToFrames
|
||||
mciWait
|
||||
mciBusy
|
||||
closeDA
|
||||
window
|
||||
copyToClipBoard
|
||||
pasteClipBoardInto
|
||||
move
|
||||
importFileInto
|
||||
duplicate
|
||||
findEmpty
|
||||
fileName
|
||||
title
|
||||
visible
|
||||
close
|
||||
titleVisible
|
||||
tell
|
||||
size
|
||||
add
|
||||
addAt
|
||||
addProp
|
||||
append
|
||||
deleteAt
|
||||
deleteAll
|
||||
deleteProp
|
||||
deleteOne
|
||||
getAt
|
||||
getProp
|
||||
getaProp
|
||||
getPropAt
|
||||
getPos
|
||||
getOne
|
||||
getLast
|
||||
setAt
|
||||
setProp
|
||||
setaProp
|
||||
count
|
||||
findPos
|
||||
findPosNear
|
||||
sort
|
||||
min
|
||||
max
|
||||
loc
|
||||
rect
|
||||
point
|
||||
inflate
|
||||
intersect
|
||||
union
|
||||
inside
|
||||
map
|
||||
scriptText
|
||||
regPoint
|
||||
bitmap
|
||||
filmLoop
|
||||
button
|
||||
shape
|
||||
digitalVideo
|
||||
modified
|
||||
loaded
|
||||
castType
|
||||
lastFrame
|
||||
frameLabel
|
||||
framePalette
|
||||
frameTempo
|
||||
frameScript
|
||||
moveToFront
|
||||
moveToBack
|
||||
sin
|
||||
cos
|
||||
tan
|
||||
atan
|
||||
exp
|
||||
log
|
||||
log10
|
||||
power
|
||||
pi
|
||||
param
|
||||
paramCount
|
||||
next
|
||||
previous
|
||||
keyUp
|
||||
erase
|
||||
depth
|
||||
randomSeed
|
||||
trace
|
||||
saveMovie
|
||||
clickLoc
|
||||
preLoadEventAbort
|
||||
updateMovieEnabled
|
||||
drawRect
|
||||
sourceRect
|
||||
windowType
|
||||
modal
|
||||
windowList
|
||||
itemDelimiter
|
||||
last
|
||||
keyUpScript
|
||||
forget
|
||||
down
|
||||
moviePath
|
||||
movieName
|
||||
enterFrame
|
||||
exitFrame
|
||||
halt
|
||||
abort
|
||||
pass
|
||||
property
|
||||
list
|
||||
linearList
|
||||
propList
|
||||
stage
|
||||
traceLoad
|
||||
traceLogFile
|
||||
purgePriority
|
||||
frameRate
|
||||
preloadRam
|
||||
pausedAtStart
|
||||
video
|
||||
blend
|
||||
scoreColor
|
||||
scriptNum
|
||||
searchPaths
|
||||
searchCurrentFolder
|
||||
movieFileSize
|
||||
movieFileFreeSize
|
||||
getNthFileNameInFolder
|
||||
actor
|
||||
actorList
|
||||
ancestor
|
||||
collectChangeRects
|
||||
updateRect
|
||||
stepFrame
|
||||
mouseTrack
|
||||
birth
|
||||
hitTest
|
||||
mouseHitTest
|
||||
ilk
|
||||
void
|
||||
voidp
|
||||
listp
|
||||
send
|
||||
sendAncestor
|
||||
symbolp
|
||||
crop
|
||||
cpuHogTicks
|
||||
symbol
|
||||
object
|
||||
doEffects
|
||||
searchPath
|
||||
videoForWindowsPresent
|
||||
xtra
|
||||
xtras
|
||||
interface
|
||||
member
|
||||
members
|
||||
castLib
|
||||
castLibs
|
||||
new
|
||||
beginRecording
|
||||
endRecording
|
||||
clearFrame
|
||||
updateFrame
|
||||
duplicateFrame
|
||||
deleteFrame
|
||||
insertFrame
|
||||
createName
|
||||
modifyName
|
||||
playing
|
||||
defaultColorDepth
|
||||
defaultStageRect
|
||||
defaultPalette
|
||||
antiAlias
|
||||
remapPalettes
|
||||
castCount
|
||||
memberCount
|
||||
minMember
|
||||
maxMember
|
||||
finishIdleLoad
|
||||
cancelIdleLoad
|
||||
idleLoadDone
|
||||
idleLoadTag
|
||||
idleLoadPeriod
|
||||
idleLoadMode
|
||||
idleReadChunkSize
|
||||
idleHandlerPeriod
|
||||
preLoadMode
|
||||
save
|
||||
richText
|
||||
ole
|
||||
media
|
||||
boxType
|
||||
border
|
||||
margin
|
||||
scroll
|
||||
dropShadow
|
||||
boxDropShadow
|
||||
autoTab
|
||||
textWrap
|
||||
editable
|
||||
sampleSize
|
||||
sampleRate
|
||||
channelCount
|
||||
buttonType
|
||||
shapeType
|
||||
filled
|
||||
scriptsEnabled
|
||||
track
|
||||
tracks
|
||||
scriptType
|
||||
music
|
||||
timeCode
|
||||
pushButton
|
||||
checkBox
|
||||
radioButton
|
||||
oval
|
||||
roundRect
|
||||
score
|
||||
parent
|
||||
adjust
|
||||
fixed
|
||||
limit
|
||||
digitalVideoTimeScale
|
||||
videoForWindows
|
||||
quickTime
|
||||
fileType
|
||||
case
|
||||
digitalVideoType
|
||||
timeScale
|
||||
composite
|
||||
image
|
||||
textStyles
|
||||
moaHandle
|
||||
moaPixels
|
||||
moaSound
|
||||
macPICT
|
||||
macGWorld
|
||||
macSnd
|
||||
macTEStyles
|
||||
macColorTable
|
||||
winDIB
|
||||
winPICT
|
||||
winWAVE
|
||||
winPALETTE
|
||||
is
|
||||
otherwise
|
||||
paletteMapping
|
||||
updateLock
|
||||
frameTransition
|
||||
frameSound1
|
||||
frameSound2
|
||||
waitSeconds
|
||||
waitClick
|
||||
waitSound
|
||||
waitDigitalVideo
|
||||
paletteTransitionType
|
||||
paletteOverTime
|
||||
paletteSpeed
|
||||
paletteFrames
|
||||
normal
|
||||
fadeToBlack
|
||||
fadeToWhite
|
||||
transitionType
|
||||
changeArea
|
||||
chunkSize
|
||||
lineCount
|
||||
lineHeight
|
||||
linePosToLocV
|
||||
locVToLinePos
|
||||
charPosToLoc
|
||||
locToCharPos
|
||||
pageHeight
|
||||
scrollTop
|
||||
scrollByPage
|
||||
scrollByLine
|
||||
systemMac
|
||||
systemWin
|
||||
rainbow
|
||||
grayscale
|
||||
pastels
|
||||
vivid
|
||||
NTSC
|
||||
metallic
|
||||
authorMode
|
||||
trackCount
|
||||
trackType
|
||||
trackStartTime
|
||||
trackStopTime
|
||||
trackEnabled
|
||||
setTrackEnabled
|
||||
trackNextSampleTime
|
||||
trackPreviousSampleTime
|
||||
trackNextKeyTime
|
||||
trackPreviousKeyTime
|
||||
trackText
|
||||
mouseDoubleClick
|
||||
mouseEnter
|
||||
mouseLeave
|
||||
mouseStillDown
|
||||
mouseWithin
|
||||
folderName
|
||||
activateWindow
|
||||
deactivateWindow
|
||||
openWindow
|
||||
closeWindow
|
||||
moveWindow
|
||||
resizeWindow
|
||||
zoomWindow
|
||||
activeWindow
|
||||
frontWindow
|
||||
windowPresent
|
||||
deskTopRectList
|
||||
scoreSelection
|
||||
memberNum
|
||||
castLibNum
|
||||
paletteRef
|
||||
keyPressed
|
||||
rightMouseDown
|
||||
rightMouseUp
|
||||
emulateMultiButtonMouse
|
||||
platform
|
||||
preLoadMovie
|
||||
unloadMovie
|
||||
messageLock
|
||||
mouseSprite
|
||||
editFocusSprite
|
||||
activeCast
|
||||
activeCastLib
|
||||
maskMember
|
||||
serialNumber
|
||||
userName
|
||||
organizationName
|
||||
runMode
|
||||
appFileSpec
|
||||
productName
|
||||
productVersion
|
||||
moaTEStyles
|
||||
alignment
|
||||
font
|
||||
fontSize
|
||||
fontStyle
|
||||
wordWrap
|
||||
unloadMember
|
||||
preloadMember
|
||||
systemWinDir4
|
||||
vga
|
||||
755
engines/director/lingo/docs/d6-keywords.txt
Normal file
755
engines/director/lingo/docs/d6-keywords.txt
Normal file
@@ -0,0 +1,755 @@
|
||||
,*
|
||||
,
|
||||
(
|
||||
)
|
||||
[
|
||||
]
|
||||
:
|
||||
-
|
||||
+
|
||||
not
|
||||
*
|
||||
/
|
||||
mod
|
||||
contains
|
||||
starts
|
||||
and
|
||||
or
|
||||
=
|
||||
<
|
||||
<>
|
||||
<=
|
||||
>
|
||||
>=
|
||||
&
|
||||
&&
|
||||
then
|
||||
else
|
||||
the
|
||||
char
|
||||
word
|
||||
item
|
||||
line
|
||||
#
|
||||
true
|
||||
false
|
||||
return
|
||||
enter
|
||||
tab
|
||||
backSpace
|
||||
quote
|
||||
empty
|
||||
field
|
||||
sprite
|
||||
put
|
||||
go
|
||||
play
|
||||
to
|
||||
if
|
||||
into
|
||||
before
|
||||
after
|
||||
idle
|
||||
startMovie
|
||||
stopMovie
|
||||
stepMovie
|
||||
mouseUp
|
||||
mouseDown
|
||||
done
|
||||
frame
|
||||
method
|
||||
of
|
||||
me
|
||||
off
|
||||
macro
|
||||
factory
|
||||
while
|
||||
repeat
|
||||
end
|
||||
with
|
||||
movie
|
||||
type
|
||||
castNum
|
||||
top
|
||||
left
|
||||
width
|
||||
height
|
||||
linesize
|
||||
ink
|
||||
keyDown
|
||||
within
|
||||
intersects
|
||||
nosound
|
||||
byFrame
|
||||
click
|
||||
clickStop
|
||||
loop
|
||||
noUpdate
|
||||
sync
|
||||
tempo
|
||||
whatfits
|
||||
mnew
|
||||
mname
|
||||
mdescribe
|
||||
matframe
|
||||
right
|
||||
bottom
|
||||
locV
|
||||
locH
|
||||
pattern
|
||||
transition
|
||||
palette
|
||||
sound
|
||||
editableText
|
||||
moveableSprite
|
||||
pause
|
||||
timeout
|
||||
label
|
||||
puppet
|
||||
immediate
|
||||
forecolor
|
||||
backcolor
|
||||
stretch
|
||||
cursor
|
||||
text
|
||||
hilite
|
||||
cast
|
||||
mverb
|
||||
mdispose
|
||||
mget
|
||||
mput
|
||||
super
|
||||
noflush
|
||||
xcmdglue
|
||||
midiStart
|
||||
midiStop
|
||||
midiContinue
|
||||
midiBeat
|
||||
midiSong
|
||||
midiSongpointer
|
||||
constraint
|
||||
mPerform
|
||||
mActivate
|
||||
mUpdate
|
||||
mIdle
|
||||
mMouseDown
|
||||
mMouseUp
|
||||
mKeyDown
|
||||
mStartUp
|
||||
mQuit
|
||||
playRect
|
||||
mEvent
|
||||
on
|
||||
mOpenEditor
|
||||
mCloseEditor
|
||||
mSetText
|
||||
mGetText
|
||||
noclear
|
||||
mVerbDispose
|
||||
startScript
|
||||
version
|
||||
mRespondsTo
|
||||
mInstanceRespondsTo
|
||||
mMessageList
|
||||
chars
|
||||
words
|
||||
items
|
||||
lines
|
||||
picture
|
||||
in
|
||||
mPerformOther
|
||||
fadeIn
|
||||
fadeOut
|
||||
stop
|
||||
playFile
|
||||
playCast
|
||||
name
|
||||
textStyle
|
||||
textFont
|
||||
textHeight
|
||||
textAlign
|
||||
textSize
|
||||
castmembers
|
||||
center
|
||||
plain
|
||||
bold
|
||||
italic
|
||||
underline
|
||||
outline
|
||||
shadow
|
||||
condense
|
||||
extend
|
||||
mSetHandler
|
||||
menu
|
||||
menus
|
||||
menuItem
|
||||
menuItems
|
||||
mAtTransition
|
||||
mCanDoTrans
|
||||
mTransDial
|
||||
resource
|
||||
soundEnabled
|
||||
imageDirect
|
||||
colorDepth
|
||||
exitLock
|
||||
fullColorPermit
|
||||
selStart
|
||||
selEnd
|
||||
switchColorDepth
|
||||
fixStageSize
|
||||
centerStage
|
||||
checkBoxAccess
|
||||
checkBoxType
|
||||
buttonStyle
|
||||
multiSound
|
||||
stageColor
|
||||
beepOn
|
||||
mouseDownScript
|
||||
mouseUpScript
|
||||
keyDownScript
|
||||
timeoutScript
|
||||
timer
|
||||
timeoutLength
|
||||
timeoutLapsed
|
||||
timeoutKeydown
|
||||
timeoutMouse
|
||||
timeoutPlay
|
||||
number
|
||||
volume
|
||||
checkMark
|
||||
enabled
|
||||
script
|
||||
floatPrecision
|
||||
instance
|
||||
global
|
||||
set
|
||||
exit
|
||||
when
|
||||
delete
|
||||
puppetSound
|
||||
open
|
||||
ticks
|
||||
abs
|
||||
length
|
||||
string
|
||||
charToNum
|
||||
numToChar
|
||||
sqrt
|
||||
integerp
|
||||
stringp
|
||||
objectp
|
||||
floatp
|
||||
integer
|
||||
offset
|
||||
maxinteger
|
||||
result
|
||||
nothing
|
||||
value
|
||||
memorysize
|
||||
freeBlock
|
||||
freeBytes
|
||||
commandDown
|
||||
optionDown
|
||||
stillDown
|
||||
shiftDown
|
||||
controlDown
|
||||
clickOn
|
||||
key
|
||||
stageLeft
|
||||
stageRight
|
||||
stageTop
|
||||
stageBottom
|
||||
machineType
|
||||
mouseH
|
||||
mouseV
|
||||
selection
|
||||
pathName
|
||||
labelList
|
||||
pauseState
|
||||
mouseLine
|
||||
mouseItem
|
||||
mouseWord
|
||||
mouseChar
|
||||
mouseCast
|
||||
colorQD
|
||||
doubleClick
|
||||
keyCode
|
||||
lastClick
|
||||
lastKey
|
||||
lastRoll
|
||||
lastEvent
|
||||
marker
|
||||
rollOver
|
||||
soundBusy
|
||||
xfactoryList
|
||||
random
|
||||
constrainH
|
||||
constrainV
|
||||
continue
|
||||
delay
|
||||
openDA
|
||||
installMenu
|
||||
showResFile
|
||||
printFrom
|
||||
quit
|
||||
spriteBox
|
||||
startTimer
|
||||
restart
|
||||
shutDown
|
||||
zoomBox
|
||||
openXLib
|
||||
closeXLib
|
||||
showXLib
|
||||
dontPassEvent
|
||||
openResFile
|
||||
closeResFile
|
||||
updateStage
|
||||
playAccel
|
||||
immediateSprite
|
||||
puppetSprite
|
||||
puppetTempo
|
||||
puppetTransition
|
||||
puppetPalette
|
||||
alert
|
||||
preLoad
|
||||
preLoadCast
|
||||
mci
|
||||
setCallBack
|
||||
beep
|
||||
showLocals
|
||||
showGlobals
|
||||
perFrameHook
|
||||
long
|
||||
short
|
||||
abbreviated
|
||||
abbrev
|
||||
abbr
|
||||
time
|
||||
date
|
||||
do
|
||||
clearGlobals
|
||||
unLoad
|
||||
unLoadCast
|
||||
trails
|
||||
duration
|
||||
controller
|
||||
directToStage
|
||||
visibility
|
||||
ramNeeded
|
||||
movieRate
|
||||
movieTime
|
||||
startTime
|
||||
stopTime
|
||||
romanLingo
|
||||
quickTimePresent
|
||||
picturep
|
||||
float
|
||||
soundLevel
|
||||
framesToHMS
|
||||
hmsToFrames
|
||||
mciWait
|
||||
mciBusy
|
||||
closeDA
|
||||
window
|
||||
copyToClipBoard
|
||||
pasteClipBoardInto
|
||||
move
|
||||
importFileInto
|
||||
duplicate
|
||||
findEmpty
|
||||
fileName
|
||||
title
|
||||
visible
|
||||
close
|
||||
titleVisible
|
||||
tell
|
||||
size
|
||||
add
|
||||
addAt
|
||||
addProp
|
||||
append
|
||||
deleteAt
|
||||
deleteAll
|
||||
deleteProp
|
||||
deleteOne
|
||||
getAt
|
||||
getProp
|
||||
getaProp
|
||||
getPropAt
|
||||
getPos
|
||||
getOne
|
||||
getLast
|
||||
setAt
|
||||
setProp
|
||||
setaProp
|
||||
count
|
||||
findPos
|
||||
findPosNear
|
||||
sort
|
||||
min
|
||||
max
|
||||
loc
|
||||
rect
|
||||
point
|
||||
inflate
|
||||
intersect
|
||||
union
|
||||
inside
|
||||
map
|
||||
scriptText
|
||||
regPoint
|
||||
bitmap
|
||||
filmLoop
|
||||
button
|
||||
shape
|
||||
digitalVideo
|
||||
modified
|
||||
loaded
|
||||
castType
|
||||
lastFrame
|
||||
frameLabel
|
||||
framePalette
|
||||
frameTempo
|
||||
frameScript
|
||||
moveToFront
|
||||
moveToBack
|
||||
sin
|
||||
cos
|
||||
tan
|
||||
atan
|
||||
exp
|
||||
log
|
||||
log10
|
||||
power
|
||||
pi
|
||||
param
|
||||
paramCount
|
||||
next
|
||||
previous
|
||||
keyUp
|
||||
erase
|
||||
depth
|
||||
randomSeed
|
||||
trace
|
||||
saveMovie
|
||||
clickLoc
|
||||
preLoadEventAbort
|
||||
updateMovieEnabled
|
||||
drawRect
|
||||
sourceRect
|
||||
windowType
|
||||
modal
|
||||
windowList
|
||||
itemDelimiter
|
||||
last
|
||||
keyUpScript
|
||||
forget
|
||||
down
|
||||
moviePath
|
||||
movieName
|
||||
enterFrame
|
||||
exitFrame
|
||||
halt
|
||||
abort
|
||||
pass
|
||||
property
|
||||
list
|
||||
linearList
|
||||
propList
|
||||
stage
|
||||
traceLoad
|
||||
traceLogFile
|
||||
purgePriority
|
||||
frameRate
|
||||
preloadRam
|
||||
pausedAtStart
|
||||
video
|
||||
blend
|
||||
scoreColor
|
||||
scriptNum
|
||||
searchPaths
|
||||
searchCurrentFolder
|
||||
movieFileSize
|
||||
movieFileFreeSize
|
||||
getNthFileNameInFolder
|
||||
actor
|
||||
actorList
|
||||
ancestor
|
||||
collectChangeRects
|
||||
updateRect
|
||||
stepFrame
|
||||
mouseTrack
|
||||
birth
|
||||
hitTest
|
||||
mouseHitTest
|
||||
ilk
|
||||
void
|
||||
voidp
|
||||
listp
|
||||
symbolp
|
||||
crop
|
||||
cpuHogTicks
|
||||
symbol
|
||||
object
|
||||
doEffects
|
||||
searchPath
|
||||
videoForWindowsPresent
|
||||
xtra
|
||||
xtras
|
||||
interface
|
||||
member
|
||||
members
|
||||
castLib
|
||||
castLibs
|
||||
new
|
||||
beginRecording
|
||||
endRecording
|
||||
clearFrame
|
||||
updateFrame
|
||||
duplicateFrame
|
||||
deleteFrame
|
||||
insertFrame
|
||||
createName
|
||||
modifyName
|
||||
playing
|
||||
defaultColorDepth
|
||||
defaultStageRect
|
||||
defaultPalette
|
||||
antiAlias
|
||||
remapPalettes
|
||||
castCount
|
||||
memberCount
|
||||
minMember
|
||||
maxMember
|
||||
finishIdleLoad
|
||||
cancelIdleLoad
|
||||
idleLoadDone
|
||||
idleLoadTag
|
||||
idleLoadPeriod
|
||||
idleLoadMode
|
||||
idleReadChunkSize
|
||||
idleHandlerPeriod
|
||||
preLoadMode
|
||||
save
|
||||
richText
|
||||
ole
|
||||
media
|
||||
boxType
|
||||
border
|
||||
margin
|
||||
scroll
|
||||
dropShadow
|
||||
boxDropShadow
|
||||
autoTab
|
||||
textWrap
|
||||
editable
|
||||
sampleSize
|
||||
sampleRate
|
||||
channelCount
|
||||
buttonType
|
||||
shapeType
|
||||
filled
|
||||
scriptsEnabled
|
||||
track
|
||||
tracks
|
||||
scriptType
|
||||
music
|
||||
timeCode
|
||||
pushButton
|
||||
checkBox
|
||||
radioButton
|
||||
oval
|
||||
roundRect
|
||||
score
|
||||
parent
|
||||
adjust
|
||||
fixed
|
||||
limit
|
||||
digitalVideoTimeScale
|
||||
videoForWindows
|
||||
quickTime
|
||||
fileType
|
||||
case
|
||||
digitalVideoType
|
||||
timeScale
|
||||
composite
|
||||
image
|
||||
textStyles
|
||||
moaHandle
|
||||
moaPixels
|
||||
moaSound
|
||||
macPICT
|
||||
macGWorld
|
||||
macSnd
|
||||
macTEStyles
|
||||
macColorTable
|
||||
winDIB
|
||||
winPICT
|
||||
winWAVE
|
||||
winPALETTE
|
||||
is
|
||||
otherwise
|
||||
paletteMapping
|
||||
updateLock
|
||||
frameTransition
|
||||
frameSound1
|
||||
frameSound2
|
||||
waitSeconds
|
||||
waitClick
|
||||
waitSound
|
||||
waitDigitalVideo
|
||||
waitCuePoint
|
||||
paletteTransitionType
|
||||
paletteOverTime
|
||||
paletteSpeed
|
||||
paletteFrames
|
||||
normal
|
||||
fadeToBlack
|
||||
fadeToWhite
|
||||
transitionType
|
||||
changeArea
|
||||
chunkSize
|
||||
lineCount
|
||||
lineHeight
|
||||
linePosToLocV
|
||||
locVToLinePos
|
||||
charPosToLoc
|
||||
locToCharPos
|
||||
pageHeight
|
||||
scrollTop
|
||||
scrollByPage
|
||||
scrollByLine
|
||||
systemMac
|
||||
systemWin
|
||||
rainbow
|
||||
grayscale
|
||||
pastels
|
||||
vivid
|
||||
NTSC
|
||||
metallic
|
||||
authorMode
|
||||
trackCount
|
||||
trackType
|
||||
trackStartTime
|
||||
trackStopTime
|
||||
trackEnabled
|
||||
setTrackEnabled
|
||||
trackNextSampleTime
|
||||
trackPreviousSampleTime
|
||||
trackNextKeyTime
|
||||
trackPreviousKeyTime
|
||||
trackText
|
||||
prepareFrame
|
||||
mouseEnter
|
||||
mouseLeave
|
||||
mouseStillDown
|
||||
mouseWithin
|
||||
folderName
|
||||
activateWindow
|
||||
deactivateWindow
|
||||
openWindow
|
||||
closeWindow
|
||||
moveWindow
|
||||
resizeWindow
|
||||
zoomWindow
|
||||
activeWindow
|
||||
frontWindow
|
||||
windowPresent
|
||||
deskTopRectList
|
||||
scoreSelection
|
||||
memberNum
|
||||
castLibNum
|
||||
paletteRef
|
||||
keyPressed
|
||||
rightMouseDown
|
||||
rightMouseUp
|
||||
emulateMultiButtonMouse
|
||||
platform
|
||||
preLoadMovie
|
||||
unloadMovie
|
||||
messageLock
|
||||
mouseSprite
|
||||
editFocusSprite
|
||||
activeCast
|
||||
activeCastLib
|
||||
maskMember
|
||||
serialNumber
|
||||
userName
|
||||
organizationName
|
||||
runMode
|
||||
appFileSpec
|
||||
productName
|
||||
productVersion
|
||||
moaTEStyles
|
||||
alignment
|
||||
font
|
||||
fontSize
|
||||
fontStyle
|
||||
wordWrap
|
||||
unloadMember
|
||||
preloadMember
|
||||
systemWinDir4
|
||||
vga
|
||||
SetPref
|
||||
externalParamCount
|
||||
externalParamName
|
||||
externalParamValue
|
||||
getPref
|
||||
stopEvent
|
||||
scriptInstanceList
|
||||
currentScript
|
||||
local
|
||||
alertHook
|
||||
testPointHook
|
||||
spriteNum
|
||||
mouseUpOutSide
|
||||
getPropertyDescriptionList
|
||||
getBehaviorDescription
|
||||
runPropertyDialog
|
||||
default
|
||||
range
|
||||
comment
|
||||
format
|
||||
boolean
|
||||
graphic
|
||||
indexcolor
|
||||
rgbcolor
|
||||
cuePointNames
|
||||
cuePointTimes
|
||||
mediaBusy
|
||||
mostRecentCuePoint
|
||||
currentTime
|
||||
CuePassed
|
||||
IsPastCuePoint
|
||||
ForcePreloadCuePoints
|
||||
Sound1
|
||||
Sound2
|
||||
Sound3
|
||||
Sound4
|
||||
Sound5
|
||||
Sound6
|
||||
Sound7
|
||||
Sound8
|
||||
mediaReady
|
||||
call
|
||||
callAncestor
|
||||
sendSprite
|
||||
sendAllSprites
|
||||
beginSprite
|
||||
endSprite
|
||||
currentSpriteNum
|
||||
applicationPath
|
||||
space
|
||||
frameReady
|
||||
tweened
|
||||
scriptStyles
|
||||
mouseMember
|
||||
netPresent
|
||||
rowBytes
|
||||
safePlayer
|
||||
prepareMovie
|
||||
send
|
||||
sendAncestor
|
||||
netThrottleTicks
|
||||
soundKeepDevice
|
||||
alphaInfo
|
||||
806
engines/director/lingo/docs/d7-keywords.txt
Normal file
806
engines/director/lingo/docs/d7-keywords.txt
Normal file
@@ -0,0 +1,806 @@
|
||||
,*
|
||||
.
|
||||
..
|
||||
,
|
||||
(
|
||||
)
|
||||
[
|
||||
]
|
||||
{
|
||||
}
|
||||
:
|
||||
-
|
||||
+
|
||||
not
|
||||
*
|
||||
/
|
||||
mod
|
||||
contains
|
||||
starts
|
||||
and
|
||||
or
|
||||
=
|
||||
<
|
||||
<>
|
||||
<=
|
||||
>
|
||||
>=
|
||||
&
|
||||
&&
|
||||
then
|
||||
else
|
||||
the
|
||||
char
|
||||
word
|
||||
item
|
||||
line
|
||||
#
|
||||
true
|
||||
false
|
||||
return
|
||||
enter
|
||||
tab
|
||||
backSpace
|
||||
quote
|
||||
empty
|
||||
field
|
||||
sprite
|
||||
put
|
||||
go
|
||||
play
|
||||
to
|
||||
if
|
||||
into
|
||||
before
|
||||
after
|
||||
idle
|
||||
startMovie
|
||||
stopMovie
|
||||
stepMovie
|
||||
mouseUp
|
||||
mouseDown
|
||||
done
|
||||
frame
|
||||
method
|
||||
of
|
||||
me
|
||||
off
|
||||
factory
|
||||
while
|
||||
repeat
|
||||
end
|
||||
with
|
||||
movie
|
||||
type
|
||||
castNum
|
||||
top
|
||||
left
|
||||
width
|
||||
height
|
||||
linesize
|
||||
ink
|
||||
keyDown
|
||||
within
|
||||
intersects
|
||||
loop
|
||||
sync
|
||||
tempo
|
||||
mnew
|
||||
mname
|
||||
mdescribe
|
||||
right
|
||||
bottom
|
||||
locV
|
||||
locH
|
||||
pattern
|
||||
transition
|
||||
palette
|
||||
sound
|
||||
editableText
|
||||
moveableSprite
|
||||
pause
|
||||
timeout
|
||||
label
|
||||
puppet
|
||||
immediate
|
||||
forecolor
|
||||
backcolor
|
||||
stretch
|
||||
cursor
|
||||
text
|
||||
hilite
|
||||
cast
|
||||
mdispose
|
||||
mget
|
||||
mput
|
||||
super
|
||||
constraint
|
||||
mPerform
|
||||
on
|
||||
version
|
||||
mRespondsTo
|
||||
mInstanceRespondsTo
|
||||
mMessageList
|
||||
chars
|
||||
words
|
||||
items
|
||||
lines
|
||||
picture
|
||||
in
|
||||
fadeIn
|
||||
fadeOut
|
||||
stop
|
||||
playFile
|
||||
name
|
||||
textStyle
|
||||
textFont
|
||||
textHeight
|
||||
textAlign
|
||||
textSize
|
||||
castmembers
|
||||
center
|
||||
plain
|
||||
bold
|
||||
italic
|
||||
underline
|
||||
outline
|
||||
shadow
|
||||
condense
|
||||
extend
|
||||
menu
|
||||
menus
|
||||
menuItem
|
||||
menuItems
|
||||
soundEnabled
|
||||
colorDepth
|
||||
exitLock
|
||||
selStart
|
||||
selEnd
|
||||
switchColorDepth
|
||||
fixStageSize
|
||||
centerStage
|
||||
checkBoxAccess
|
||||
checkBoxType
|
||||
buttonStyle
|
||||
multiSound
|
||||
stageColor
|
||||
beepOn
|
||||
mouseDownScript
|
||||
mouseUpScript
|
||||
keyDownScript
|
||||
timeoutScript
|
||||
timer
|
||||
timeoutLength
|
||||
timeoutLapsed
|
||||
timeoutKeydown
|
||||
timeoutMouse
|
||||
timeoutPlay
|
||||
number
|
||||
volume
|
||||
checkMark
|
||||
enabled
|
||||
script
|
||||
floatPrecision
|
||||
instance
|
||||
global
|
||||
set
|
||||
exit
|
||||
when
|
||||
delete
|
||||
puppetSound
|
||||
open
|
||||
ticks
|
||||
abs
|
||||
length
|
||||
string
|
||||
charToNum
|
||||
numToChar
|
||||
sqrt
|
||||
integerp
|
||||
stringp
|
||||
objectp
|
||||
floatp
|
||||
integer
|
||||
offset
|
||||
maxinteger
|
||||
result
|
||||
nothing
|
||||
value
|
||||
memorysize
|
||||
freeBlock
|
||||
freeBytes
|
||||
commandDown
|
||||
optionDown
|
||||
stillDown
|
||||
shiftDown
|
||||
controlDown
|
||||
clickOn
|
||||
key
|
||||
stageLeft
|
||||
stageRight
|
||||
stageTop
|
||||
stageBottom
|
||||
machineType
|
||||
mouseH
|
||||
mouseV
|
||||
selection
|
||||
pathName
|
||||
labelList
|
||||
pauseState
|
||||
mouseLine
|
||||
mouseItem
|
||||
mouseWord
|
||||
mouseChar
|
||||
mouseCast
|
||||
colorQD
|
||||
doubleClick
|
||||
keyCode
|
||||
lastClick
|
||||
lastKey
|
||||
lastRoll
|
||||
lastEvent
|
||||
marker
|
||||
rollOver
|
||||
soundBusy
|
||||
xfactoryList
|
||||
random
|
||||
constrainH
|
||||
constrainV
|
||||
continue
|
||||
delay
|
||||
installMenu
|
||||
showResFile
|
||||
printFrom
|
||||
quit
|
||||
spriteBox
|
||||
startTimer
|
||||
restart
|
||||
shutDown
|
||||
zoomBox
|
||||
openXLib
|
||||
closeXLib
|
||||
showXLib
|
||||
dontPassEvent
|
||||
openResFile
|
||||
closeResFile
|
||||
updateStage
|
||||
immediateSprite
|
||||
puppetSprite
|
||||
puppetTempo
|
||||
puppetTransition
|
||||
puppetPalette
|
||||
alert
|
||||
preLoad
|
||||
preLoadCast
|
||||
mci
|
||||
beep
|
||||
showLocals
|
||||
showGlobals
|
||||
perFrameHook
|
||||
long
|
||||
short
|
||||
abbreviated
|
||||
abbrev
|
||||
abbr
|
||||
time
|
||||
date
|
||||
do
|
||||
clearGlobals
|
||||
unLoad
|
||||
unLoadCast
|
||||
trails
|
||||
duration
|
||||
controller
|
||||
directToStage
|
||||
visibility
|
||||
ramNeeded
|
||||
movieRate
|
||||
movieTime
|
||||
startTime
|
||||
stopTime
|
||||
romanLingo
|
||||
quickTimePresent
|
||||
picturep
|
||||
float
|
||||
soundLevel
|
||||
framesToHMS
|
||||
hmsToFrames
|
||||
window
|
||||
copyToClipBoard
|
||||
pasteClipBoardInto
|
||||
move
|
||||
importFileInto
|
||||
duplicate
|
||||
findEmpty
|
||||
fileName
|
||||
title
|
||||
visible
|
||||
close
|
||||
titleVisible
|
||||
tell
|
||||
size
|
||||
add
|
||||
addAt
|
||||
addProp
|
||||
append
|
||||
deleteAt
|
||||
deleteAll
|
||||
deleteProp
|
||||
deleteOne
|
||||
getAt
|
||||
getProp
|
||||
getaProp
|
||||
getPropAt
|
||||
getPos
|
||||
getOne
|
||||
getLast
|
||||
setAt
|
||||
setProp
|
||||
setaProp
|
||||
count
|
||||
findPos
|
||||
findPosNear
|
||||
sort
|
||||
min
|
||||
max
|
||||
loc
|
||||
rect
|
||||
point
|
||||
inflate
|
||||
intersect
|
||||
union
|
||||
inside
|
||||
map
|
||||
scriptText
|
||||
regPoint
|
||||
bitmap
|
||||
filmLoop
|
||||
button
|
||||
shape
|
||||
digitalVideo
|
||||
modified
|
||||
loaded
|
||||
castType
|
||||
lastFrame
|
||||
frameLabel
|
||||
framePalette
|
||||
frameTempo
|
||||
frameScript
|
||||
moveToFront
|
||||
moveToBack
|
||||
sin
|
||||
cos
|
||||
tan
|
||||
atan
|
||||
exp
|
||||
log
|
||||
log10
|
||||
power
|
||||
pi
|
||||
param
|
||||
paramCount
|
||||
next
|
||||
previous
|
||||
keyUp
|
||||
erase
|
||||
depth
|
||||
randomSeed
|
||||
trace
|
||||
saveMovie
|
||||
clickLoc
|
||||
preLoadEventAbort
|
||||
updateMovieEnabled
|
||||
drawRect
|
||||
sourceRect
|
||||
windowType
|
||||
modal
|
||||
windowList
|
||||
itemDelimiter
|
||||
last
|
||||
keyUpScript
|
||||
forget
|
||||
down
|
||||
moviePath
|
||||
movieName
|
||||
enterFrame
|
||||
exitFrame
|
||||
halt
|
||||
abort
|
||||
pass
|
||||
property
|
||||
list
|
||||
linearList
|
||||
propList
|
||||
stage
|
||||
traceLoad
|
||||
traceLogFile
|
||||
purgePriority
|
||||
frameRate
|
||||
preloadRam
|
||||
pausedAtStart
|
||||
video
|
||||
blend
|
||||
scoreColor
|
||||
scriptNum
|
||||
searchPaths
|
||||
searchCurrentFolder
|
||||
movieFileSize
|
||||
movieFileFreeSize
|
||||
getNthFileNameInFolder
|
||||
actor
|
||||
actorList
|
||||
ancestor
|
||||
collectChangeRects
|
||||
updateRect
|
||||
stepFrame
|
||||
mouseTrack
|
||||
birth
|
||||
hitTest
|
||||
mouseHitTest
|
||||
ilk
|
||||
void
|
||||
voidp
|
||||
listp
|
||||
symbolp
|
||||
crop
|
||||
cpuHogTicks
|
||||
symbol
|
||||
object
|
||||
doEffects
|
||||
searchPath
|
||||
videoForWindowsPresent
|
||||
xtra
|
||||
xtras
|
||||
interface
|
||||
member
|
||||
members
|
||||
castLib
|
||||
castLibs
|
||||
new
|
||||
beginRecording
|
||||
endRecording
|
||||
clearFrame
|
||||
updateFrame
|
||||
duplicateFrame
|
||||
deleteFrame
|
||||
insertFrame
|
||||
createName
|
||||
modifyName
|
||||
playing
|
||||
defaultColorDepth
|
||||
defaultStageRect
|
||||
defaultPalette
|
||||
antiAlias
|
||||
remapPalettes
|
||||
castCount
|
||||
memberCount
|
||||
minMember
|
||||
maxMember
|
||||
finishIdleLoad
|
||||
cancelIdleLoad
|
||||
idleLoadDone
|
||||
idleLoadTag
|
||||
idleLoadPeriod
|
||||
idleLoadMode
|
||||
idleReadChunkSize
|
||||
idleHandlerPeriod
|
||||
preLoadMode
|
||||
save
|
||||
richText
|
||||
ole
|
||||
media
|
||||
boxType
|
||||
border
|
||||
margin
|
||||
scroll
|
||||
dropShadow
|
||||
boxDropShadow
|
||||
autoTab
|
||||
textWrap
|
||||
editable
|
||||
sampleSize
|
||||
sampleRate
|
||||
channelCount
|
||||
buttonType
|
||||
shapeType
|
||||
filled
|
||||
scriptsEnabled
|
||||
track
|
||||
tracks
|
||||
scriptType
|
||||
music
|
||||
timeCode
|
||||
pushButton
|
||||
checkBox
|
||||
radioButton
|
||||
oval
|
||||
roundRect
|
||||
score
|
||||
parent
|
||||
adjust
|
||||
fixed
|
||||
limit
|
||||
digitalVideoTimeScale
|
||||
videoForWindows
|
||||
quickTime
|
||||
fileType
|
||||
case
|
||||
digitalVideoType
|
||||
timeScale
|
||||
composite
|
||||
image
|
||||
textStyles
|
||||
moaHandle
|
||||
moaPixels
|
||||
moaSound
|
||||
macPICT
|
||||
macGWorld
|
||||
macSnd
|
||||
macTEStyles
|
||||
macColorTable
|
||||
winDIB
|
||||
winPICT
|
||||
winWAVE
|
||||
winPALETTE
|
||||
is
|
||||
otherwise
|
||||
paletteMapping
|
||||
updateLock
|
||||
frameTransition
|
||||
frameSound1
|
||||
frameSound2
|
||||
waitSeconds
|
||||
waitClick
|
||||
waitSound
|
||||
waitDigitalVideo
|
||||
waitCuePoint
|
||||
paletteTransitionType
|
||||
paletteOverTime
|
||||
paletteSpeed
|
||||
paletteFrames
|
||||
normal
|
||||
fadeToBlack
|
||||
fadeToWhite
|
||||
transitionType
|
||||
changeArea
|
||||
chunkSize
|
||||
lineCount
|
||||
lineHeight
|
||||
linePosToLocV
|
||||
locVToLinePos
|
||||
charPosToLoc
|
||||
locToCharPos
|
||||
pageHeight
|
||||
scrollTop
|
||||
scrollByPage
|
||||
scrollByLine
|
||||
systemMac
|
||||
systemWin
|
||||
web216
|
||||
rainbow
|
||||
grayscale
|
||||
pastels
|
||||
vivid
|
||||
NTSC
|
||||
metallic
|
||||
authorMode
|
||||
trackCount
|
||||
trackType
|
||||
trackStartTime
|
||||
trackStopTime
|
||||
trackEnabled
|
||||
setTrackEnabled
|
||||
trackNextSampleTime
|
||||
trackPreviousSampleTime
|
||||
trackNextKeyTime
|
||||
trackPreviousKeyTime
|
||||
trackText
|
||||
prepareFrame
|
||||
mouseEnter
|
||||
mouseLeave
|
||||
mouseStillDown
|
||||
mouseWithin
|
||||
folderName
|
||||
activateWindow
|
||||
deactivateWindow
|
||||
openWindow
|
||||
closeWindow
|
||||
moveWindow
|
||||
resizeWindow
|
||||
zoomWindow
|
||||
activeWindow
|
||||
frontWindow
|
||||
windowPresent
|
||||
deskTopRectList
|
||||
scoreSelection
|
||||
memberNum
|
||||
castLibNum
|
||||
paletteRef
|
||||
keyPressed
|
||||
rightMouseDown
|
||||
rightMouseUp
|
||||
emulateMultiButtonMouse
|
||||
platform
|
||||
preLoadMovie
|
||||
unloadMovie
|
||||
messageLock
|
||||
mouseSprite
|
||||
editFocusSprite
|
||||
activeCast
|
||||
activeCastLib
|
||||
maskMember
|
||||
serialNumber
|
||||
userName
|
||||
organizationName
|
||||
runMode
|
||||
appFileSpec
|
||||
productName
|
||||
productVersion
|
||||
moaTEStyles
|
||||
alignment
|
||||
font
|
||||
fontSize
|
||||
fontStyle
|
||||
wordWrap
|
||||
unloadMember
|
||||
preloadMember
|
||||
systemWinDir4
|
||||
vga
|
||||
SetPref
|
||||
externalParamCount
|
||||
externalParamName
|
||||
externalParamValue
|
||||
getPref
|
||||
stopEvent
|
||||
scriptInstanceList
|
||||
currentScript
|
||||
local
|
||||
alertHook
|
||||
testPointHook
|
||||
spriteNum
|
||||
mouseUpOutSide
|
||||
getPropertyDescriptionList
|
||||
getBehaviorDescription
|
||||
runPropertyDialog
|
||||
default
|
||||
range
|
||||
comment
|
||||
format
|
||||
boolean
|
||||
graphic
|
||||
indexcolor
|
||||
rgbcolor
|
||||
cuePointNames
|
||||
cuePointTimes
|
||||
mediaBusy
|
||||
mostRecentCuePoint
|
||||
currentTime
|
||||
CuePassed
|
||||
IsPastCuePoint
|
||||
Sound1
|
||||
Sound2
|
||||
Sound3
|
||||
Sound4
|
||||
Sound5
|
||||
Sound6
|
||||
Sound7
|
||||
Sound8
|
||||
mediaReady
|
||||
call
|
||||
callAncestor
|
||||
sendSprite
|
||||
sendAllSprites
|
||||
beginSprite
|
||||
endSprite
|
||||
currentSpriteNum
|
||||
applicationPath
|
||||
space
|
||||
frameReady
|
||||
tweened
|
||||
scriptStyles
|
||||
mouseMember
|
||||
netPresent
|
||||
rowBytes
|
||||
safePlayer
|
||||
prepareMovie
|
||||
send
|
||||
sendAncestor
|
||||
netThrottleTicks
|
||||
soundKeepDevice
|
||||
alphaInfo
|
||||
cut
|
||||
copy
|
||||
paste
|
||||
CastMemberProperties
|
||||
quickTimeMedia
|
||||
thumbnail
|
||||
urlAdmin
|
||||
useAlpha
|
||||
alphaThreshold
|
||||
rotation
|
||||
skew
|
||||
flipH
|
||||
flipV
|
||||
allowSaveLocal
|
||||
allowVolumeControl
|
||||
allowTransportControl
|
||||
allowZooming
|
||||
allowCustomCaching
|
||||
allowGraphicMenu
|
||||
getPropRef
|
||||
getContents
|
||||
setContents
|
||||
globals
|
||||
quad
|
||||
keyboardFocusSprite
|
||||
startFrame
|
||||
endFrame
|
||||
lineDirection
|
||||
color
|
||||
colorType
|
||||
index
|
||||
rgb
|
||||
paletteIndex
|
||||
red
|
||||
green
|
||||
blue
|
||||
hexString
|
||||
bgColor
|
||||
bgStageColor
|
||||
systemDate
|
||||
year
|
||||
month
|
||||
day
|
||||
mouseLoc
|
||||
setContentsBefore
|
||||
setContentsAfter
|
||||
dither
|
||||
mediaFormat
|
||||
localString
|
||||
editableMedia
|
||||
soundDeviceList
|
||||
soundDevice
|
||||
movieCopyrightInfo
|
||||
movieAboutInfo
|
||||
getBehaviorTooltip
|
||||
imlScrollBar
|
||||
autoHilite
|
||||
vectorShape
|
||||
blendLevel
|
||||
mapMemberToStage
|
||||
mapStageToMember
|
||||
xtraList
|
||||
movieXtraList
|
||||
milliSeconds
|
||||
flash
|
||||
swa
|
||||
locZ
|
||||
getPixel
|
||||
setPixel
|
||||
environment
|
||||
shockMachine
|
||||
paragraph
|
||||
paragraphs
|
||||
centerregpoint
|
||||
animgif
|
||||
lastChannel
|
||||
bitAnd
|
||||
bitOr
|
||||
bitXor
|
||||
bitNot
|
||||
scriptList
|
||||
useFastQuads
|
||||
internetConnected
|
||||
online
|
||||
offline
|
||||
unknown
|
||||
applicationName
|
||||
uiLanguage
|
||||
productBuildVersion
|
||||
activateApplication
|
||||
deactivateApplication
|
||||
commandLine
|
||||
appMinimize
|
||||
tempoScaleFactor
|
||||
soundMixMedia
|
||||
shockMachineVersion
|
||||
918
engines/director/lingo/docs/d8-keywords.txt
Normal file
918
engines/director/lingo/docs/d8-keywords.txt
Normal file
@@ -0,0 +1,918 @@
|
||||
,*
|
||||
.
|
||||
..
|
||||
,
|
||||
(
|
||||
)
|
||||
[
|
||||
]
|
||||
{
|
||||
}
|
||||
:
|
||||
-
|
||||
+
|
||||
not
|
||||
*
|
||||
/
|
||||
mod
|
||||
contains
|
||||
starts
|
||||
and
|
||||
or
|
||||
=
|
||||
<
|
||||
<>
|
||||
<=
|
||||
>
|
||||
>=
|
||||
&
|
||||
&&
|
||||
then
|
||||
else
|
||||
the
|
||||
char
|
||||
word
|
||||
item
|
||||
line
|
||||
#
|
||||
true
|
||||
false
|
||||
return
|
||||
enter
|
||||
tab
|
||||
backSpace
|
||||
quote
|
||||
empty
|
||||
field
|
||||
sprite
|
||||
put
|
||||
to
|
||||
if
|
||||
into
|
||||
before
|
||||
after
|
||||
idle
|
||||
startMovie
|
||||
stopMovie
|
||||
stepMovie
|
||||
mouseUp
|
||||
mouseDown
|
||||
done
|
||||
frame
|
||||
method
|
||||
of
|
||||
me
|
||||
off
|
||||
factory
|
||||
while
|
||||
repeat
|
||||
end
|
||||
with
|
||||
top
|
||||
left
|
||||
width
|
||||
height
|
||||
keyDown
|
||||
within
|
||||
intersects
|
||||
mnew
|
||||
mname
|
||||
mdescribe
|
||||
right
|
||||
bottom
|
||||
locV
|
||||
locH
|
||||
sound
|
||||
pause
|
||||
timeout
|
||||
delete
|
||||
member
|
||||
cast
|
||||
tell
|
||||
setContents
|
||||
setContentsBefore
|
||||
setContentsAfter
|
||||
down
|
||||
in
|
||||
next
|
||||
case
|
||||
otherwise
|
||||
on
|
||||
global
|
||||
set
|
||||
exit
|
||||
when
|
||||
castLib
|
||||
last
|
||||
keyUp
|
||||
enterFrame
|
||||
exitFrame
|
||||
activateWindow
|
||||
deactivateWindow
|
||||
openWindow
|
||||
closeWindow
|
||||
moveWindow
|
||||
zoomWindow
|
||||
resizeWindow
|
||||
mouseEnter
|
||||
mouseLeave
|
||||
mouseStillDown
|
||||
mouseWithin
|
||||
rightMouseDown
|
||||
rightMouseUp
|
||||
prepareFrame
|
||||
script
|
||||
window
|
||||
xtra
|
||||
void
|
||||
space
|
||||
pi
|
||||
getPropRef
|
||||
new
|
||||
property
|
||||
time
|
||||
date
|
||||
maxinteger
|
||||
systemDate
|
||||
result
|
||||
abs
|
||||
length
|
||||
string
|
||||
symbol
|
||||
numToChar
|
||||
sqrt
|
||||
integerp
|
||||
stringp
|
||||
vectorp
|
||||
charToNum
|
||||
objectp
|
||||
floatp
|
||||
integer
|
||||
value
|
||||
float
|
||||
picturep
|
||||
clickLoc
|
||||
paramCount
|
||||
param
|
||||
random
|
||||
floatPrecision
|
||||
mouseDownScript
|
||||
mouseUpScript
|
||||
keyDownScript
|
||||
keyUpScript
|
||||
timeoutScript
|
||||
short
|
||||
long
|
||||
abbreviated
|
||||
abbrev
|
||||
abbr
|
||||
object
|
||||
picture
|
||||
number
|
||||
nothing
|
||||
do
|
||||
abort
|
||||
pass
|
||||
symbolp
|
||||
voidp
|
||||
listp
|
||||
offset
|
||||
sin
|
||||
cos
|
||||
tan
|
||||
atan
|
||||
exp
|
||||
log
|
||||
power
|
||||
list
|
||||
propList
|
||||
rect
|
||||
point
|
||||
color
|
||||
rgb
|
||||
paletteIndex
|
||||
call
|
||||
callAncestor
|
||||
send
|
||||
sendAncestor
|
||||
bitAnd
|
||||
bitOr
|
||||
bitXor
|
||||
bitNot
|
||||
linearList
|
||||
prepend
|
||||
add
|
||||
addAt
|
||||
addProp
|
||||
append
|
||||
deleteAt
|
||||
deleteAll
|
||||
deleteProp
|
||||
deleteOne
|
||||
getAt
|
||||
getProp
|
||||
getaProp
|
||||
getPropAt
|
||||
getPos
|
||||
getOne
|
||||
getLast
|
||||
setAt
|
||||
setProp
|
||||
setaProp
|
||||
count
|
||||
findPos
|
||||
findPosNear
|
||||
sort
|
||||
min
|
||||
max
|
||||
ilk
|
||||
duplicate
|
||||
inflate
|
||||
intersect
|
||||
union
|
||||
map
|
||||
inside
|
||||
getContents
|
||||
instance
|
||||
hexString
|
||||
colorType
|
||||
red
|
||||
green
|
||||
blue
|
||||
year
|
||||
month
|
||||
day
|
||||
mPerform
|
||||
mRespondsTo
|
||||
mdispose
|
||||
mput
|
||||
mget
|
||||
super
|
||||
mInstanceRespondsTo
|
||||
text
|
||||
fileName
|
||||
ancestor
|
||||
birth
|
||||
actor
|
||||
media
|
||||
mMessageList
|
||||
interface
|
||||
name
|
||||
mouseUpOutSide
|
||||
beginSprite
|
||||
endSprite
|
||||
runPropertyDialog
|
||||
getPropertyDescriptionList
|
||||
getBehaviorDescription
|
||||
getBehaviorTooltip
|
||||
default
|
||||
forget
|
||||
romanLingo
|
||||
randomSeed
|
||||
itemDelimiter
|
||||
globals
|
||||
milliSeconds
|
||||
paragraph
|
||||
paragraphs
|
||||
chars
|
||||
words
|
||||
items
|
||||
lines
|
||||
hilite
|
||||
handler
|
||||
handlers
|
||||
rawNew
|
||||
period
|
||||
sleep
|
||||
wait
|
||||
notify
|
||||
timeOutList
|
||||
persistent
|
||||
timeOutHandler
|
||||
target
|
||||
beep
|
||||
showLocals
|
||||
showGlobals
|
||||
clearGlobals
|
||||
memorysize
|
||||
freeBlock
|
||||
freeBytes
|
||||
ticks
|
||||
version
|
||||
openXLib
|
||||
closeXLib
|
||||
showXLib
|
||||
seconds
|
||||
shockwave3d
|
||||
vector
|
||||
transform
|
||||
sweep
|
||||
protect
|
||||
stats
|
||||
free
|
||||
file
|
||||
type
|
||||
folderChar
|
||||
exists
|
||||
volumeInfo
|
||||
blockSize
|
||||
freeBlocks
|
||||
creator
|
||||
locked
|
||||
position
|
||||
size
|
||||
read
|
||||
write
|
||||
rename
|
||||
exchange
|
||||
getTempPath
|
||||
copyTo
|
||||
createFolder
|
||||
deleteFolder
|
||||
open
|
||||
create
|
||||
flush
|
||||
close
|
||||
folder
|
||||
visible
|
||||
extension
|
||||
readValue
|
||||
writeValue
|
||||
movie
|
||||
loop
|
||||
go
|
||||
play
|
||||
label
|
||||
puppet
|
||||
immediate
|
||||
cursor
|
||||
castNum
|
||||
foreColor
|
||||
backColor
|
||||
lineSize
|
||||
stretch
|
||||
ink
|
||||
pattern
|
||||
type
|
||||
moveableSprite
|
||||
editableText
|
||||
palette
|
||||
transition
|
||||
tempo
|
||||
constraint
|
||||
fadeIn
|
||||
fadeOut
|
||||
stop
|
||||
playFile
|
||||
textStyle
|
||||
textFont
|
||||
textHeight
|
||||
textAlign
|
||||
textSize
|
||||
castMembers
|
||||
center
|
||||
plain
|
||||
bold
|
||||
italic
|
||||
underline
|
||||
outline
|
||||
shadow
|
||||
condense
|
||||
extend
|
||||
menu
|
||||
menus
|
||||
menuItem
|
||||
menuItems
|
||||
soundEnabled
|
||||
colorDepth
|
||||
exitLock
|
||||
selStart
|
||||
selEnd
|
||||
switchColorDepth
|
||||
fixStageSize
|
||||
centerStage
|
||||
checkBoxAccess
|
||||
checkBoxType
|
||||
buttonStyle
|
||||
multisound
|
||||
stageColor
|
||||
beepOn
|
||||
timer
|
||||
timeoutLength
|
||||
timeoutLapsed
|
||||
timeoutKeydown
|
||||
timeoutMouse
|
||||
timeoutPlay
|
||||
volume
|
||||
checkMark
|
||||
enabled
|
||||
puppetSound
|
||||
open
|
||||
commandDown
|
||||
optionDown
|
||||
stillDown
|
||||
shiftDown
|
||||
controlDown
|
||||
clickOn
|
||||
key
|
||||
stageLeft
|
||||
stageRight
|
||||
stageTop
|
||||
stageBottom
|
||||
machineType
|
||||
mouseH
|
||||
mouseV
|
||||
selection
|
||||
pathname
|
||||
labelList
|
||||
pauseState
|
||||
mouseLine
|
||||
mouseItem
|
||||
mouseWord
|
||||
mouseChar
|
||||
mouseCast
|
||||
colorQD
|
||||
doubleClick
|
||||
keyCode
|
||||
lastClick
|
||||
lastKey
|
||||
lastRoll
|
||||
lastEvent
|
||||
marker
|
||||
rollover
|
||||
soundBusy
|
||||
xFactoryList
|
||||
constrainH
|
||||
constrainV
|
||||
continue
|
||||
delay
|
||||
installMenu
|
||||
showResFile
|
||||
printFrom
|
||||
quit
|
||||
spriteBox
|
||||
startTimer
|
||||
restart
|
||||
shutDown
|
||||
zoomBox
|
||||
dontPassEvent
|
||||
openResFile
|
||||
closeResFile
|
||||
updateStage
|
||||
immediateSprite
|
||||
puppetSprite
|
||||
puppetTempo
|
||||
puppetTransition
|
||||
puppetPalette
|
||||
alert
|
||||
preload
|
||||
preloadCast
|
||||
mci
|
||||
perFrameHook
|
||||
unload
|
||||
unloadCast
|
||||
trails
|
||||
duration
|
||||
controller
|
||||
directToStage
|
||||
visibility
|
||||
ramNeeded
|
||||
movieRate
|
||||
movieTime
|
||||
startTime
|
||||
stopTime
|
||||
quickTimePresent
|
||||
soundLevel
|
||||
framesToHms
|
||||
hmsToFrames
|
||||
copyToClipboard
|
||||
pasteClipboardInto
|
||||
move
|
||||
importFileInto
|
||||
findEmpty
|
||||
title
|
||||
visible
|
||||
close
|
||||
titleVisible
|
||||
size
|
||||
loc
|
||||
scriptText
|
||||
regPoint
|
||||
bitmap
|
||||
filmLoop
|
||||
button
|
||||
shape
|
||||
digitalVideo
|
||||
modified
|
||||
loaded
|
||||
castType
|
||||
lastFrame
|
||||
frameLabel
|
||||
framePalette
|
||||
frameTempo
|
||||
frameScript
|
||||
moveToFront
|
||||
moveToBack
|
||||
previous
|
||||
erase
|
||||
depth
|
||||
trace
|
||||
saveMovie
|
||||
preloadEventAbort
|
||||
updateMovieEnabled
|
||||
drawRect
|
||||
sourceRect
|
||||
windowType
|
||||
modal
|
||||
windowList
|
||||
moviePath
|
||||
movieName
|
||||
halt
|
||||
stage
|
||||
traceLoad
|
||||
traceLogFile
|
||||
purgePriority
|
||||
frameRate
|
||||
preloadRam
|
||||
pausedAtStart
|
||||
video
|
||||
blend
|
||||
scoreColor
|
||||
scriptNum
|
||||
searchPaths
|
||||
searchCurrentFolder
|
||||
movieFileSize
|
||||
movieFileFreeSize
|
||||
getNthFileNameInFolder
|
||||
actorList
|
||||
collectChangeRects
|
||||
updateRect
|
||||
stepFrame
|
||||
mouseTrack
|
||||
hitTest
|
||||
mouseHitTest
|
||||
crop
|
||||
cpuHogTicks
|
||||
doEffects
|
||||
searchPath
|
||||
videoForWindowsPresent
|
||||
xtras
|
||||
members
|
||||
castLibs
|
||||
beginRecording
|
||||
endRecording
|
||||
clearFrame
|
||||
updateFrame
|
||||
duplicateFrame
|
||||
deleteFrame
|
||||
insertFrame
|
||||
createName
|
||||
modifyName
|
||||
playing
|
||||
defaultColorDepth
|
||||
defaultStageRect
|
||||
defaultPalette
|
||||
antialias
|
||||
remapPalettes
|
||||
castCount
|
||||
memberCount
|
||||
minMember
|
||||
maxMember
|
||||
finishIdleLoad
|
||||
cancelIdleLoad
|
||||
idleLoadDone
|
||||
idleLoadTag
|
||||
idleLoadPeriod
|
||||
idleLoadMode
|
||||
idleReadChunkSize
|
||||
idleHandlerPeriod
|
||||
preloadMode
|
||||
save
|
||||
richText
|
||||
ole
|
||||
boxType
|
||||
border
|
||||
margin
|
||||
scroll
|
||||
dropShadow
|
||||
boxDropShadow
|
||||
autoTab
|
||||
textWrap
|
||||
editable
|
||||
sampleSize
|
||||
sampleRate
|
||||
channelCount
|
||||
buttonType
|
||||
shapeType
|
||||
filled
|
||||
scriptsEnabled
|
||||
track
|
||||
tracks
|
||||
scriptType
|
||||
music
|
||||
timeCode
|
||||
pushButton
|
||||
checkBox
|
||||
radioButton
|
||||
oval
|
||||
roundRect
|
||||
score
|
||||
parent
|
||||
adjust
|
||||
fixed
|
||||
limit
|
||||
digitalVideoTimeScale
|
||||
videoForWindows
|
||||
quickTime
|
||||
fileType
|
||||
digitalVideoType
|
||||
timeScale
|
||||
composite
|
||||
image
|
||||
textStyles
|
||||
moaHandle
|
||||
moaPixels
|
||||
moaSound
|
||||
macPict
|
||||
macGWorld
|
||||
macSnd
|
||||
macTEStyles
|
||||
macColorTable
|
||||
winDIB
|
||||
winPict
|
||||
winWave
|
||||
winPalette
|
||||
paletteMapping
|
||||
updateLock
|
||||
frameTransition
|
||||
frameSound1
|
||||
frameSound2
|
||||
waitSeconds
|
||||
waitClick
|
||||
waitSound
|
||||
waitDigitalVideo
|
||||
waitCuePoint
|
||||
paletteTransitionType
|
||||
paletteOverTime
|
||||
paletteSpeed
|
||||
paletteFrames
|
||||
normal
|
||||
fadeToBlack
|
||||
fadeToWhite
|
||||
transitionType
|
||||
changeArea
|
||||
chunkSize
|
||||
lineCount
|
||||
lineHeight
|
||||
linePosToLocV
|
||||
locVToLinePos
|
||||
charPosToLoc
|
||||
locToCharPos
|
||||
pageHeight
|
||||
scrollTop
|
||||
scrollByPage
|
||||
scrollByLine
|
||||
systemMac
|
||||
systemWin
|
||||
web216
|
||||
rainbow
|
||||
grayscale
|
||||
pastels
|
||||
vivid
|
||||
ntsc
|
||||
metallic
|
||||
authorMode
|
||||
trackCount
|
||||
trackType
|
||||
trackStartTime
|
||||
trackStopTime
|
||||
trackEnabled
|
||||
setTrackEnabled
|
||||
trackNextSampleTime
|
||||
trackPreviousSampleTime
|
||||
trackNextKeyTime
|
||||
trackPreviousKeyTime
|
||||
trackText
|
||||
folderName
|
||||
activeWindow
|
||||
frontWindow
|
||||
windowPresent
|
||||
desktopRectList
|
||||
scoreSelection
|
||||
memberNum
|
||||
castLibNum
|
||||
paletteRef
|
||||
keyPressed
|
||||
emulateMultibuttonMouse
|
||||
platform
|
||||
preloadMovie
|
||||
unloadMovie
|
||||
messageLock
|
||||
mouseSprite
|
||||
editFocusSprite
|
||||
activeCast
|
||||
activeCastLib
|
||||
maskMember
|
||||
serialNumber
|
||||
userName
|
||||
organizationName
|
||||
runMode
|
||||
appFileSpec
|
||||
productName
|
||||
productVersion
|
||||
moaTEStyles
|
||||
alignment
|
||||
font
|
||||
fontSize
|
||||
fontStyle
|
||||
wordWrap
|
||||
unloadMember
|
||||
preloadMember
|
||||
systemWinDir4
|
||||
vga
|
||||
setPref
|
||||
externalParamCount
|
||||
externalParamName
|
||||
externalParamValue
|
||||
getPref
|
||||
stopEvent
|
||||
scriptInstanceList
|
||||
currentScript
|
||||
local
|
||||
alertHook
|
||||
testPointHook
|
||||
spriteNum
|
||||
range
|
||||
comment
|
||||
format
|
||||
boolean
|
||||
graphic
|
||||
indexColor
|
||||
rgbColor
|
||||
cuePointNames
|
||||
cuePointTimes
|
||||
mediaBusy
|
||||
mostRecentCuePoint
|
||||
currentTime
|
||||
cuePassed
|
||||
isPastCuePoint
|
||||
sound1
|
||||
sound2
|
||||
sound3
|
||||
sound4
|
||||
sound5
|
||||
sound6
|
||||
sound7
|
||||
sound8
|
||||
mediaReady
|
||||
sendSprite
|
||||
sendAllSprites
|
||||
currentSpriteNum
|
||||
applicationPath
|
||||
frameReady
|
||||
tweened
|
||||
scriptStyles
|
||||
mouseMember
|
||||
netPresent
|
||||
rowBytes
|
||||
safePlayer
|
||||
prepareMovie
|
||||
netThrottleTicks
|
||||
soundKeepDevice
|
||||
alphaInfo
|
||||
cut
|
||||
copy
|
||||
paste
|
||||
castMemberProperties
|
||||
quickTimeMedia
|
||||
thumbnail
|
||||
urlAdmin
|
||||
useAlpha
|
||||
alphaThreshold
|
||||
rotation
|
||||
skew
|
||||
flipH
|
||||
flipV
|
||||
allowSaveLocal
|
||||
allowVolumeControl
|
||||
allowTransportControl
|
||||
allowZooming
|
||||
allowCustomCaching
|
||||
allowGraphicMenu
|
||||
quad
|
||||
keyboardFocusSprite
|
||||
startFrame
|
||||
endFrame
|
||||
lineDirection
|
||||
index
|
||||
bgColor
|
||||
bgStageColor
|
||||
mouseLoc
|
||||
dither
|
||||
mediaFormat
|
||||
localString
|
||||
editableMedia
|
||||
soundDeviceList
|
||||
soundDevice
|
||||
movieCopyrightInfo
|
||||
movieAboutInfo
|
||||
imlScrollBar
|
||||
autohilite
|
||||
vectorShape
|
||||
blendLevel
|
||||
mapMemberToStage
|
||||
mapStageToMember
|
||||
xtraList
|
||||
movieXtraList
|
||||
flash
|
||||
swa
|
||||
locZ
|
||||
getPixel
|
||||
setPixel
|
||||
environment
|
||||
shockMachine
|
||||
centerRegPoint
|
||||
animGif
|
||||
lastChannel
|
||||
scriptList
|
||||
useFastQuads
|
||||
internetConnected
|
||||
online
|
||||
offline
|
||||
unknown
|
||||
applicationName
|
||||
uiLanguage
|
||||
productBuildVersion
|
||||
activateApplication
|
||||
deactivateApplication
|
||||
commandLine
|
||||
appMinimize
|
||||
tempoScaleFactor
|
||||
soundMixMedia
|
||||
shockMachineVersion
|
||||
collide
|
||||
copyPixels
|
||||
fill
|
||||
createMatte
|
||||
trimWhiteSpace
|
||||
extractAlpha
|
||||
setAlpha
|
||||
draw
|
||||
creationDate
|
||||
modifiedDate
|
||||
modifiedBy
|
||||
comments
|
||||
windowInFront
|
||||
windowBehind
|
||||
command
|
||||
propertyDescriptionList
|
||||
itemDescriptionList
|
||||
granularity
|
||||
imageCompression
|
||||
imageQuality
|
||||
movieSetting
|
||||
standard
|
||||
jpeg
|
||||
gif
|
||||
movieImageCompression
|
||||
movieImageQuality
|
||||
linked
|
||||
transparent
|
||||
reverse
|
||||
ghost
|
||||
notCopy
|
||||
notTransparent
|
||||
notReverse
|
||||
notGhost
|
||||
matte
|
||||
mask
|
||||
addPin
|
||||
subtractPin
|
||||
backgroundTransparent
|
||||
lightest
|
||||
subtract
|
||||
darkest
|
||||
lighten
|
||||
darken
|
||||
maskImage
|
||||
maskOffset
|
||||
createMask
|
||||
movieFileVersion
|
||||
editShortcutsEnabled
|
||||
inlineImeEnabled
|
||||
linkAs
|
||||
flushInputEvents
|
||||
setScriptList
|
||||
isOKToAttach
|
||||
osLanguage
|
||||
pointToChar
|
||||
pointToWord
|
||||
pointToLine
|
||||
pointToItem
|
||||
pointToParagraph
|
||||
selectedText
|
||||
markerlist
|
||||
enableInkmodeLimitations
|
||||
_soundXtra
|
||||
helpTopic
|
||||
disableImagingTransformation
|
||||
1500
engines/director/lingo/docs/d8.5-keywords.txt
Normal file
1500
engines/director/lingo/docs/d8.5-keywords.txt
Normal file
File diff suppressed because it is too large
Load Diff
1050
engines/director/lingo/lingo-ast.h
Normal file
1050
engines/director/lingo/lingo-ast.h
Normal file
File diff suppressed because it is too large
Load Diff
4283
engines/director/lingo/lingo-builtins.cpp
Normal file
4283
engines/director/lingo/lingo-builtins.cpp
Normal file
File diff suppressed because it is too large
Load Diff
257
engines/director/lingo/lingo-builtins.h
Normal file
257
engines/director/lingo/lingo-builtins.h
Normal file
@@ -0,0 +1,257 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_BUILTINS_H
|
||||
#define DIRECTOR_LINGO_BUILTINS_H
|
||||
|
||||
namespace Director {
|
||||
|
||||
namespace LB {
|
||||
|
||||
// builtin functions
|
||||
void b_abs(int nargs);
|
||||
void b_atan(int nargs);
|
||||
void b_cos(int nargs);
|
||||
void b_exp(int nargs);
|
||||
void b_float(int nargs);
|
||||
void b_integer(int nargs);
|
||||
void b_log(int nargs);
|
||||
void b_pi(int nargs);
|
||||
void b_power(int nargs);
|
||||
void b_random(int nargs);
|
||||
void b_sin(int nargs);
|
||||
void b_sqrt(int nargs);
|
||||
void b_tan(int nargs);
|
||||
void b_void(int nargs);
|
||||
|
||||
void b_chars(int nargs);
|
||||
void b_charToNum(int nargs);
|
||||
void b_length(int nargs);
|
||||
void b_numToChar(int nargs);
|
||||
void b_offset(int nargs);
|
||||
void b_string(int nargs);
|
||||
|
||||
void b_add(int nargs);
|
||||
void b_addAt(int nargs);
|
||||
void b_addProp(int nargs);
|
||||
void b_append(int nargs);
|
||||
void b_count(int nargs);
|
||||
void b_deleteAt(int nargs);
|
||||
void b_deleteOne(int nargs);
|
||||
void b_deleteProp(int nargs);
|
||||
void b_duplicateList(int nargs);
|
||||
void b_findPos(int nargs);
|
||||
void b_findPosNear(int nargs);
|
||||
void b_getaProp(int nargs);
|
||||
void b_getAt(int nargs);
|
||||
void b_getLast(int nargs);
|
||||
void b_getOne(int nargs);
|
||||
void b_getPos(int nargs);
|
||||
void b_getProp(int nargs);
|
||||
void b_getPropAt(int nargs);
|
||||
void b_list(int nargs);
|
||||
void b_listP(int nargs);
|
||||
void b_max(int nargs);
|
||||
void b_min(int nargs);
|
||||
void b_setaProp(int nargs);
|
||||
void b_setAt(int nargs);
|
||||
void b_setProp(int nargs);
|
||||
void b_sort(int nargs);
|
||||
|
||||
void b_factory(int nargs);
|
||||
void b_floatP(int nargs);
|
||||
void b_ilk(int nargs);
|
||||
void b_integerp(int nargs);
|
||||
void b_objectp(int nargs);
|
||||
void b_pictureP(int nargs);
|
||||
void b_stringp(int nargs);
|
||||
void b_symbol(int nargs);
|
||||
void b_symbolp(int nargs);
|
||||
void b_voidP(int nargs);
|
||||
|
||||
void b_alert(int nargs);
|
||||
void b_clearGlobals(int nargs);
|
||||
void b_cursor(int nargs);
|
||||
void b_framesToHMS(int nargs);
|
||||
void b_HMStoFrames(int nargs);
|
||||
void b_param(int nargs);
|
||||
void b_printFrom(int nargs);
|
||||
void b_put(int nargs);
|
||||
void b_setPref(int nargs);
|
||||
void b_showGlobals(int nargs);
|
||||
void b_showLocals(int nargs);
|
||||
void b_value(int nargs);
|
||||
|
||||
void b_constrainH(int nargs);
|
||||
void b_constrainV(int nargs);
|
||||
void b_copyToClipBoard(int nargs);
|
||||
void b_duplicate(int nargs);
|
||||
void b_editableText(int nargs);
|
||||
void b_erase(int nargs);
|
||||
void b_findEmpty(int nargs);
|
||||
void b_importFileInto(int nargs);
|
||||
void b_installMenu(int nargs);
|
||||
void b_label(int nargs);
|
||||
void b_marker(int nargs);
|
||||
void b_move(int nargs);
|
||||
void b_moveableSprite(int nargs);
|
||||
void b_pasteClipBoardInto(int nargs);
|
||||
void b_puppetPalette(int nargs);
|
||||
void b_puppetSound(int nargs);
|
||||
void b_puppetSprite(int nargs);
|
||||
void b_puppetTempo(int nargs);
|
||||
void b_puppetTransition(int nargs);
|
||||
void b_ramNeeded(int nargs);
|
||||
void b_rollOver(int nargs);
|
||||
void b_sendAllSprites(int nargs);
|
||||
void b_sendSprite(int nargs);
|
||||
void b_spriteBox(int nargs);
|
||||
void b_unLoad(int nargs);
|
||||
void b_unLoadCast(int nargs);
|
||||
void b_unLoadMovie(int nargs);
|
||||
void b_updateStage(int nargs);
|
||||
void b_zoomBox(int nargs);
|
||||
void b_immediateSprite(int nargs);
|
||||
|
||||
void b_clearFrame(int nargs);
|
||||
void b_deleteFrame(int nargs);
|
||||
void b_duplicateFrame(int nargs);
|
||||
void b_insertFrame(int nargs);
|
||||
void b_updateFrame(int nargs);
|
||||
|
||||
void b_abort(int nargs);
|
||||
void b_call(int nargs);
|
||||
void b_callAncestor(int nargs);
|
||||
void b_cancelIdleLoad(int nargs);
|
||||
void b_continue(int nargs);
|
||||
void b_dontPassEvent(int nargs);
|
||||
void b_delay(int nargs);
|
||||
void b_do(int nargs);
|
||||
void b_finishIdleLoad(int nargs);
|
||||
void b_go(int nargs);
|
||||
void b_halt(int nargs);
|
||||
void b_idleLoadDone(int nargs);
|
||||
void b_nothing(int nargs);
|
||||
void b_pass(int nargs);
|
||||
void b_pause(int nargs);
|
||||
void b_play(int nargs);
|
||||
void b_playAccel(int nargs);
|
||||
void b_preLoad(int nargs);
|
||||
void b_preLoadCast(int nargs);
|
||||
void b_preLoadMovie(int nargs);
|
||||
void b_quit(int nargs);
|
||||
void b_restart(int nargs);
|
||||
void b_shutDown(int nargs);
|
||||
void b_startTimer(int nargs);
|
||||
void b_stopEvent(int nargs);
|
||||
void b_return(int nargs);
|
||||
|
||||
void b_closeDA(int nargs);
|
||||
void b_closeResFile(int nargs);
|
||||
void b_closeXlib(int nargs);
|
||||
void b_getNthFileNameInFolder(int nargs);
|
||||
void b_open(int nargs);
|
||||
void b_openDA(int nargs);
|
||||
void b_openResFile(int nargs);
|
||||
void b_openXlib(int nargs);
|
||||
void b_setCallBack(int nargs);
|
||||
void b_save(int nargs);
|
||||
void b_saveMovie(int nargs);
|
||||
void b_showResFile(int nargs);
|
||||
void b_showXlib(int nargs);
|
||||
void b_xFactoryList(int nargs);
|
||||
void b_xtra(int nargs);
|
||||
|
||||
void b_point(int nargs);
|
||||
void b_inflate(int nargs);
|
||||
void b_inside(int nargs);
|
||||
void b_intersect(int nargs);
|
||||
void b_map(int nargs);
|
||||
void b_offsetRect(int nargs);
|
||||
void b_rect(int nargs);
|
||||
void b_union(int nargs);
|
||||
|
||||
void b_beep(int nargs);
|
||||
void b_mci(int nargs);
|
||||
void b_mciwait(int nargs);
|
||||
void b_sound(int nargs);
|
||||
void b_soundBusy(int nargs);
|
||||
|
||||
void b_backspace(int nargs);
|
||||
void b_empty(int nargs);
|
||||
void b_enter(int nargs);
|
||||
void b_false(int nargs);
|
||||
void b_quote(int nargs);
|
||||
void b_returnconst(int nargs);
|
||||
void b_tab(int nargs);
|
||||
void b_true(int nargs);
|
||||
void b_version(int nargs);
|
||||
|
||||
void b_cast(int nargs);
|
||||
void b_castLib(int nargs);
|
||||
void b_member(int nargs);
|
||||
void b_script(int nargs);
|
||||
void b_sprite(int nargs);
|
||||
void b_window(int nargs);
|
||||
void b_windowPresent(int nargs);
|
||||
|
||||
void b_charPosToLoc(int nargs);
|
||||
void b_linePosToLocV(int nargs);
|
||||
void b_locToCharPos(int nargs);
|
||||
void b_locVToLinePos(int nargs);
|
||||
void b_scrollByLine(int nargs);
|
||||
void b_scrollByPage(int nargs);
|
||||
void b_lineHeight(int nargs);
|
||||
|
||||
void b_numberofchars(int nargs);
|
||||
void b_numberofitems(int nargs);
|
||||
void b_numberoflines(int nargs);
|
||||
void b_numberofwords(int nargs);
|
||||
|
||||
void b_trackCount(int nargs);
|
||||
void b_trackStartTime(int nargs);
|
||||
void b_trackStopTime(int nargs);
|
||||
void b_trackType(int nargs);
|
||||
|
||||
void b_isPastCuePoint(int nargs);
|
||||
|
||||
void b_beginRecording(int nargs);
|
||||
void b_endRecording(int nargs);
|
||||
|
||||
void b_scummvmassert(int nargs);
|
||||
void b_scummvmassertequal(int nargs);
|
||||
void b_scummvmNoFatalError(int nargs);
|
||||
|
||||
// XCMD/XFCN (HyperCard), normally exposed
|
||||
void b_getVolumes(int nargs);
|
||||
|
||||
void b_externalParamCount(int nargs); // Shockwave D6
|
||||
void b_externalParamName(int nargs); // Shockwave D6
|
||||
void b_externalParamValue(int nargs); // Shockwave D6
|
||||
void b_frameReady(int nargs); // Shockwave D6
|
||||
void b_getPref(int nargs); // Shockwave D6
|
||||
void b_netPresent(int nargs); // Shockwave D6
|
||||
|
||||
} // End of namespace LB
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
1760
engines/director/lingo/lingo-bytecode.cpp
Normal file
1760
engines/director/lingo/lingo-bytecode.cpp
Normal file
File diff suppressed because it is too large
Load Diff
55
engines/director/lingo/lingo-bytecode.h
Normal file
55
engines/director/lingo/lingo-bytecode.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_LINGO_BYTECODE_H
|
||||
#define DIRECTOR_LINGO_LINGO_BYTECODE_H
|
||||
|
||||
namespace Director {
|
||||
|
||||
typedef void (*inst)(void);
|
||||
|
||||
struct LingoV4Bytecode {
|
||||
const uint8 opcode;
|
||||
const inst func;
|
||||
const char *proto;
|
||||
};
|
||||
|
||||
enum TheEntityArgsType {
|
||||
kTEANOArgs = 0,
|
||||
kTEAItemId = 1,
|
||||
kTEAString,
|
||||
kTEAMenuId,
|
||||
kTEAMenuIdItemId,
|
||||
kTEAChunk
|
||||
};
|
||||
|
||||
struct LingoV4TheEntity {
|
||||
const uint8 bank;
|
||||
const uint8 firstArg;
|
||||
const int entity;
|
||||
const int field;
|
||||
const bool writable;
|
||||
const TheEntityArgsType type;
|
||||
};
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
2000
engines/director/lingo/lingo-code.cpp
Normal file
2000
engines/director/lingo/lingo-code.cpp
Normal file
File diff suppressed because it is too large
Load Diff
180
engines/director/lingo/lingo-code.h
Normal file
180
engines/director/lingo/lingo-code.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_LINGO_CODE_H
|
||||
#define DIRECTOR_LINGO_LINGO_CODE_H
|
||||
|
||||
namespace Director {
|
||||
|
||||
namespace LC {
|
||||
|
||||
void c_xpop();
|
||||
|
||||
Datum mapBinaryOp(Datum (*func)(Datum &, Datum &), Datum &d1, Datum &d2);
|
||||
Datum addData(Datum &d1, Datum &d2);
|
||||
void c_add();
|
||||
Datum subData(Datum &d1, Datum &d2);
|
||||
void c_sub();
|
||||
Datum mulData(Datum &d1, Datum &d2);
|
||||
void c_mul();
|
||||
Datum divData(Datum &d1, Datum &d2);
|
||||
void c_div();
|
||||
Datum modData(Datum &d1, Datum &d2);
|
||||
void c_mod();
|
||||
Datum negateData(Datum &d1);
|
||||
void c_negate();
|
||||
|
||||
void c_and();
|
||||
void c_or();
|
||||
void c_not();
|
||||
|
||||
void c_ampersand();
|
||||
void c_putafter();
|
||||
void c_putbefore();
|
||||
void c_concat();
|
||||
void c_contains();
|
||||
void c_starts();
|
||||
|
||||
void c_intersects();
|
||||
void c_within();
|
||||
Datum chunkRef(ChunkType type, int startChunk, int endChunk, const Datum &src);
|
||||
Datum lastChunk(ChunkType type, const Datum &src);
|
||||
Datum readChunkRef(const Datum &src);
|
||||
void c_of();
|
||||
void c_charToOfRef();
|
||||
void c_charToOf();
|
||||
void c_itemToOfRef();
|
||||
void c_itemToOf();
|
||||
void c_lineToOfRef();
|
||||
void c_lineToOf();
|
||||
void c_wordToOfRef();
|
||||
void c_wordToOf();
|
||||
|
||||
void c_constpush();
|
||||
void c_intpush();
|
||||
void c_voidpush();
|
||||
void c_floatpush();
|
||||
void c_stringpush();
|
||||
void c_symbolpush();
|
||||
void c_namepush();
|
||||
void c_varrefpush();
|
||||
void c_globalrefpush();
|
||||
void c_localrefpush();
|
||||
void c_proprefpush();
|
||||
void c_varpush();
|
||||
void c_globalinit();
|
||||
void c_globalpush();
|
||||
void c_localpush();
|
||||
void c_proppush();
|
||||
void c_argcpush();
|
||||
void c_argcnoretpush();
|
||||
void c_arraypush();
|
||||
void c_proparraypush();
|
||||
void c_stackpeek();
|
||||
void c_stackdrop();
|
||||
void c_assign();
|
||||
bool verify(const Symbol &s);
|
||||
|
||||
void c_swap();
|
||||
|
||||
void c_theentitypush();
|
||||
void c_themenuentitypush();
|
||||
void c_theentityassign();
|
||||
void c_objectproppush();
|
||||
void c_objectpropassign();
|
||||
|
||||
void c_whencode();
|
||||
void c_tell();
|
||||
void c_telldone();
|
||||
Datum compareArrays(Datum (*compareFunc)(Datum, Datum), Datum d1, Datum d2, bool location = false, bool value = false);
|
||||
Datum eqData(Datum d1, Datum d2);
|
||||
Datum eqDataStrict(Datum d1, Datum d2);
|
||||
void c_eq();
|
||||
Datum neqData(Datum d1, Datum d2);
|
||||
void c_neq();
|
||||
Datum gtData(Datum d1, Datum d2);
|
||||
void c_gt();
|
||||
Datum ltData(Datum d1, Datum d2);
|
||||
void c_lt();
|
||||
Datum geData(Datum d1, Datum d2);
|
||||
void c_ge();
|
||||
Datum leData(Datum d1, Datum d2);
|
||||
void c_le();
|
||||
void c_jump();
|
||||
void c_jumpifz();
|
||||
void c_callcmd();
|
||||
void c_callfunc();
|
||||
|
||||
void call(const Symbol &targetSym, int nargs, bool allowRetVal);
|
||||
void call(const Common::String &name, int nargs, bool allowRetVal);
|
||||
|
||||
void c_procret();
|
||||
void procret();
|
||||
|
||||
void c_mci();
|
||||
void c_mciwait();
|
||||
|
||||
void c_open();
|
||||
void c_delete();
|
||||
void c_hilite();
|
||||
void c_field();
|
||||
void c_fieldref();
|
||||
|
||||
// custom instructions for testing
|
||||
void c_asserterror();
|
||||
void c_asserterrordone();
|
||||
|
||||
// stubs for unknown instructions
|
||||
void cb_unk();
|
||||
void cb_unk1();
|
||||
void cb_unk2();
|
||||
|
||||
// bytecode-related instructions
|
||||
void cb_call();
|
||||
void cb_delete();
|
||||
void cb_hilite();
|
||||
void cb_globalassign();
|
||||
void cb_globalpush();
|
||||
void cb_list();
|
||||
void cb_localcall();
|
||||
void cb_objectcall();
|
||||
void cb_objectfieldassign();
|
||||
void cb_objectfieldpush();
|
||||
void cb_varrefpush();
|
||||
void cb_theassign();
|
||||
void cb_theassign2();
|
||||
void cb_thepush();
|
||||
void cb_thepush2();
|
||||
void cb_proplist();
|
||||
void cb_varassign();
|
||||
void cb_varpush();
|
||||
void cb_v4assign();
|
||||
void cb_v4assign2();
|
||||
void cb_v4theentitypush();
|
||||
void cb_v4theentitynamepush();
|
||||
void cb_v4theentityassign();
|
||||
void cb_zeropush();
|
||||
|
||||
} // End of namespace LC
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
1687
engines/director/lingo/lingo-codegen.cpp
Normal file
1687
engines/director/lingo/lingo-codegen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
141
engines/director/lingo/lingo-codegen.h
Normal file
141
engines/director/lingo/lingo-codegen.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_LINGO_CODEGEN_H
|
||||
#define DIRECTOR_LINGO_LINGO_CODEGEN_H
|
||||
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-ast.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
class LingoCompiler : NodeVisitor {
|
||||
public:
|
||||
LingoCompiler();
|
||||
virtual ~LingoCompiler() {}
|
||||
|
||||
ScriptContext *compileAnonymous(const Common::U32String &code, uint32 preprocFlags = 0);
|
||||
ScriptContext *compileLingo(const Common::U32String &code, LingoArchive *archive, ScriptType type, CastMemberID id, const Common::String &scriptName, bool anonyomous = false, uint32 preprocFlags = kLPPNone);
|
||||
ScriptContext *compileLingoV4(Common::SeekableReadStreamEndian &stream, uint16 lctxIndex, LingoArchive *archive, const Common::String &archName, uint16 version);
|
||||
|
||||
int code1(inst code) { _currentAssembly->push_back(code); return _currentAssembly->size() - 1; }
|
||||
int code2(inst code_1, inst code_2) { int o = code1(code_1); code1(code_2); return o; }
|
||||
int code3(inst code_1, inst code_2, inst code_3) { int o = code1(code_1); code1(code_2); code1(code_3); return o; }
|
||||
int code4(inst code_1, inst code_2, inst code_3, inst code_4) { int o = code1(code_1); code1(code_2); code1(code_3); code1(code_4); return o; }
|
||||
int codeCmd(const Common::String &s, int numpar);
|
||||
int codeFloat(double f);
|
||||
int codeFunc(const Common::String &s, int numpar);
|
||||
int codeInt(int val);
|
||||
int codeString(const char *s);
|
||||
void codeVarSet(const Common::String &name);
|
||||
void codeVarRef(const Common::String &name);
|
||||
void codeVarGet(const Common::String &name);
|
||||
int getTheFieldID(int entity, const Common::String &field, bool silent = false);
|
||||
void registerFactory(Common::String &s);
|
||||
void registerMethodVar(const Common::String &name, VarType type = kVarGeneric);
|
||||
void updateLoopJumps(uint nextTargetPos, uint exitTargetPos);
|
||||
|
||||
LingoArchive *_assemblyArchive;
|
||||
ScriptContext *_assemblyContext;
|
||||
Common::SharedPtr<Node> _assemblyAST;
|
||||
int32 _assemblyId;
|
||||
ScriptData *_currentAssembly;
|
||||
bool _indef;
|
||||
uint _linenumber;
|
||||
uint _colnumber;
|
||||
uint _bytenumber;
|
||||
const char *_lines[3];
|
||||
bool _inFactory;
|
||||
LoopNode *_currentLoop;
|
||||
bool _refMode;
|
||||
|
||||
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVars;
|
||||
|
||||
bool _hadError;
|
||||
|
||||
public:
|
||||
virtual bool visitScriptNode(ScriptNode *node);
|
||||
virtual bool visitFactoryNode(FactoryNode *node);
|
||||
virtual bool visitHandlerNode(HandlerNode *node);
|
||||
virtual bool visitCmdNode(CmdNode *node);
|
||||
virtual bool visitPutIntoNode(PutIntoNode *node);
|
||||
virtual bool visitPutAfterNode(PutAfterNode *node);
|
||||
virtual bool visitPutBeforeNode(PutBeforeNode *node);
|
||||
virtual bool visitSetNode(SetNode *node);
|
||||
virtual bool visitGlobalNode(GlobalNode *node);
|
||||
virtual bool visitPropertyNode(PropertyNode *node);
|
||||
virtual bool visitInstanceNode(InstanceNode *node);
|
||||
virtual bool visitIfStmtNode(IfStmtNode *node);
|
||||
virtual bool visitIfElseStmtNode(IfElseStmtNode *node);
|
||||
virtual bool visitRepeatWhileNode(RepeatWhileNode *node);
|
||||
virtual bool visitRepeatWithToNode(RepeatWithToNode *node);
|
||||
virtual bool visitRepeatWithInNode(RepeatWithInNode *node);
|
||||
virtual bool visitNextRepeatNode(NextRepeatNode *node);
|
||||
virtual bool visitExitRepeatNode(ExitRepeatNode *node);
|
||||
virtual bool visitExitNode(ExitNode *node);
|
||||
virtual bool visitReturnNode(ReturnNode *node);
|
||||
virtual bool visitTellNode(TellNode *node);
|
||||
virtual bool visitWhenNode(WhenNode *node);
|
||||
virtual bool visitDeleteNode(DeleteNode *node);
|
||||
virtual bool visitHiliteNode(HiliteNode *node);
|
||||
virtual bool visitAssertErrorNode(AssertErrorNode *node);
|
||||
virtual bool visitIntNode(IntNode *node);
|
||||
virtual bool visitFloatNode(FloatNode *node);
|
||||
virtual bool visitSymbolNode(SymbolNode *node);
|
||||
virtual bool visitStringNode(StringNode *node);
|
||||
virtual bool visitListNode(ListNode *node);
|
||||
virtual bool visitPropListNode(PropListNode *node);
|
||||
virtual bool visitPropPairNode(PropPairNode *node);
|
||||
virtual bool visitFuncNode(FuncNode *node);
|
||||
virtual bool visitVarNode(VarNode *node);
|
||||
virtual bool visitParensNode(ParensNode *node);
|
||||
virtual bool visitUnaryOpNode(UnaryOpNode *node);
|
||||
virtual bool visitBinaryOpNode(BinaryOpNode *node);
|
||||
virtual bool visitFrameNode(FrameNode *node);
|
||||
virtual bool visitMovieNode(MovieNode *node);
|
||||
virtual bool visitIntersectsNode(IntersectsNode *node);
|
||||
virtual bool visitWithinNode(WithinNode *node);
|
||||
virtual bool visitTheNode(TheNode *node);
|
||||
virtual bool visitTheOfNode(TheOfNode *node);
|
||||
virtual bool visitTheNumberOfNode(TheNumberOfNode *node);
|
||||
virtual bool visitTheLastNode(TheLastNode *node);
|
||||
virtual bool visitTheDateTimeNode(TheDateTimeNode *node);
|
||||
virtual bool visitMenuNode(MenuNode *node);
|
||||
virtual bool visitMenuItemNode(MenuItemNode *node);
|
||||
virtual bool visitSoundNode(SoundNode *node);
|
||||
virtual bool visitSpriteNode(SpriteNode *node);
|
||||
virtual bool visitChunkExprNode(ChunkExprNode *node);
|
||||
|
||||
private:
|
||||
int parse(const char *code);
|
||||
|
||||
public:
|
||||
// lingo-preprocessor.cpp
|
||||
Common::U32String codePreprocessor(const Common::U32String &code, LingoArchive *archive, ScriptType type, CastMemberID id, uint32 flags);
|
||||
MethodHash prescanMethods(const Common::U32String &code);
|
||||
|
||||
// lingo-patcher.cpp
|
||||
Common::U32String patchLingoCode(const Common::U32String &line, LingoArchive *archive, ScriptType type, CastMemberID id, int linenumber);
|
||||
};
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
903
engines/director/lingo/lingo-events.cpp
Normal file
903
engines/director/lingo/lingo-events.cpp
Normal file
@@ -0,0 +1,903 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/debugger.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-builtins.h"
|
||||
#include "director/lingo/lingo-code.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/cast.h"
|
||||
#include "director/castmember/castmember.h"
|
||||
#include "director/channel.h"
|
||||
#include "director/frame.h"
|
||||
#include "director/movie.h"
|
||||
#include "director/score.h"
|
||||
#include "director/sprite.h"
|
||||
#include "director/types.h"
|
||||
#include "director/window.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
struct EventHandlerType {
|
||||
LEvent handler;
|
||||
const char *name;
|
||||
} static const eventHandlerDescs[] = {
|
||||
{ kEventPrepareMovie, "prepareMovie" }, // D6
|
||||
{ kEventStartMovie, "startMovie" }, // D3
|
||||
{ kEventStepMovie, "stepMovie" }, // D3
|
||||
{ kEventStopMovie, "stopMovie" }, // D3
|
||||
|
||||
{ kEventBeginSprite, "beginSprite" }, // D6
|
||||
{ kEventEndSprite, "endSprite" }, // D6
|
||||
|
||||
{ kEventEnterFrame, "enterFrame" }, // D4
|
||||
{ kEventPrepareFrame, "prepareFrame" }, // D6
|
||||
{ kEventIdle, "idle" }, // D3
|
||||
{ kEventStepFrame, "stepFrame"}, // D5
|
||||
{ kEventExitFrame, "exitFrame" }, // D4
|
||||
|
||||
{ kEventActivateWindow, "activateWindow" }, // D5
|
||||
{ kEventDeactivateWindow, "deactivateWindow" }, // D5
|
||||
{ kEventMoveWindow, "moveWindow" }, // D5
|
||||
{ kEventResizeWindow, "resizeWindow" }, // D5
|
||||
{ kEventOpenWindow, "openWindow" }, // D5
|
||||
{ kEventCloseWindow, "closeWindow" }, // D5
|
||||
{ kEventZoomWindow, "zoomWindow" }, // D5
|
||||
|
||||
{ kEventKeyUp, "keyUp" }, // D4
|
||||
{ kEventKeyDown, "keyDown" }, // D2 w D4 (as when from D2)
|
||||
{ kEventMouseUp, "mouseUp" }, // D2 w D3
|
||||
{ kEventMouseDown, "mouseDown" }, // D2 w D3
|
||||
{ kEventRightMouseDown, "rightMouseDown" }, // D5
|
||||
{ kEventRightMouseUp, "rightMouseUp" }, // D5
|
||||
{ kEventMouseEnter, "mouseEnter" }, // D6, present in D5
|
||||
{ kEventMouseLeave, "mouseLeave" }, // D6, present in D5
|
||||
{ kEventMouseUpOutSide, "mouseUpOutSide" }, // D6
|
||||
{ kEventMouseWithin, "mouseWithin" }, // D6, present in D5
|
||||
|
||||
{ kEventTimeout, "timeout" }, // D2 as when
|
||||
{ kEventCuePassed, "cuePassed" }, // D6
|
||||
|
||||
{ kEventStartUp, "startUp" },
|
||||
|
||||
{ kEventGetBehaviorDescription, "getBehaviorDescription" }, // D6
|
||||
{ kEventGetPropertyDescriptionList, "getPropertyDescriptionList" }, // D6
|
||||
{ kEventRunPropertyDialog, "runPropertyDialog" }, // D6
|
||||
|
||||
{ kEventGeneric, "scummvm_generic" },
|
||||
|
||||
{ kEventNone, nullptr }
|
||||
};
|
||||
|
||||
void Lingo::initEventHandlerTypes() {
|
||||
for (const EventHandlerType *t = &eventHandlerDescs[0]; t->handler != kEventNone; ++t) {
|
||||
_eventHandlerTypeIds[t->name] = t->handler;
|
||||
_eventHandlerTypes[t->handler] = t->name;
|
||||
}
|
||||
_eventHandlerTypes[kEventNone] = 0;
|
||||
}
|
||||
|
||||
ScriptType Lingo::event2script(LEvent ev) {
|
||||
if (_vm->getVersion() < 400) {
|
||||
switch (ev) {
|
||||
//case kEventStartMovie: // We are precompiling it now
|
||||
// return kMovieScript;
|
||||
case kEventExitFrame:
|
||||
return kScoreScript;
|
||||
default:
|
||||
return kNoneScript;
|
||||
}
|
||||
}
|
||||
|
||||
return kNoneScript;
|
||||
}
|
||||
|
||||
void Movie::setPrimaryEventHandler(LEvent event, const Common::String &code) {
|
||||
debugC(3, kDebugLingoExec, "setting primary event handler (%s)", _lingo->_eventHandlerTypes[event]);
|
||||
LingoArchive *mainArchive = getMainLingoArch();
|
||||
mainArchive->primaryEventHandlers[event] = code;
|
||||
mainArchive->replaceCode(code, kEventScript, event);
|
||||
}
|
||||
|
||||
void Movie::resolveScriptEvent(LingoEvent &event) {
|
||||
// Resolve the script details of an event.
|
||||
// This must be done at execution time, as it relies on
|
||||
// e.g. the current frame, the current arrangement of sprites...
|
||||
uint16 spriteId = 0;
|
||||
if (event.mousePos != Common::Point(-1, -1)) {
|
||||
// Fetch the sprite underneath the mouse cursor.
|
||||
|
||||
// D3 doesn't have both mouse up and down.
|
||||
// But we still want to know if the mouse is down for press effects.
|
||||
// Since we don't have mouse up and down before D3, then we use ActiveSprite
|
||||
if (g_director->getVersion() < 400)
|
||||
spriteId = _score->getActiveSpriteIDFromPos(event.mousePos);
|
||||
else
|
||||
spriteId = _score->getMouseSpriteIDFromPos(event.mousePos);
|
||||
|
||||
if (event.event == kEventMouseDown || event.event == kEventRightMouseDown)
|
||||
_lastClickedSpriteId = _score->getActiveSpriteIDFromPos(event.mousePos); // the clickOn
|
||||
}
|
||||
// Very occasionally, we want to specify an event with a channel ID
|
||||
// rather than infer it from the position. Allow it to override.
|
||||
if (event.channelId == 0) {
|
||||
event.channelId = spriteId;
|
||||
}
|
||||
|
||||
// mouseDown/mouseUp events will have one of each of the source types queued.
|
||||
// run these steps at the very beginning (i.e. before the first source type).
|
||||
if (event.eventHandlerSourceType == kPrimaryHandler) {
|
||||
if ((event.event == kEventMouseDown) || (event.event == kEventRightMouseDown)) {
|
||||
if (!event.channelId && _isBeepOn) {
|
||||
g_lingo->func_beep(1);
|
||||
}
|
||||
|
||||
if (event.channelId > 0) {
|
||||
if (_score->_channels[event.channelId]->_sprite->shouldHilite()) {
|
||||
_currentHiliteChannelId = event.channelId;
|
||||
g_director->_wm->_hilitingWidget = true;
|
||||
g_director->getCurrentWindow()->setDirty(true);
|
||||
g_director->getCurrentWindow()->addDirtyRect(_score->_channels[_currentHiliteChannelId]->getBbox());
|
||||
}
|
||||
|
||||
CastMember *cast = getCastMember(_score->_channels[event.channelId]->_sprite->_castId);
|
||||
if (cast && cast->_type == kCastButton)
|
||||
_mouseDownWasInButton = true;
|
||||
|
||||
if (_score->_channels[event.channelId]->_sprite->_moveable) {
|
||||
_draggingSpriteOffset = _score->_channels[event.channelId]->getPosition() - event.mousePos;
|
||||
_currentDraggedChannel = _score->_channels[event.channelId];
|
||||
}
|
||||
|
||||
// In the case of clicking the mouse, it is possible for a mouseDown action to
|
||||
// change the cast member underneath. on mouseUp should always load the cast
|
||||
// script for the original cast member, not the new one.
|
||||
_currentMouseDownCastID = _score->_channels[event.channelId]->_sprite->_castId;
|
||||
_currentMouseDownSpriteScriptID = _score->_channels[event.channelId]->_sprite->_scriptId;
|
||||
_currentMouseDownSpriteImmediate = _score->_channels[event.channelId]->_sprite->_immediate;
|
||||
} else {
|
||||
_currentHiliteChannelId = 0;
|
||||
_mouseDownWasInButton = false;
|
||||
_draggingSpriteOffset = Common::Point(0, 0);
|
||||
_currentDraggedChannel = nullptr;
|
||||
_currentMouseDownCastID = CastMemberID();
|
||||
_currentMouseDownSpriteScriptID = CastMemberID();
|
||||
_currentMouseDownSpriteImmediate = false;
|
||||
}
|
||||
|
||||
} else if ((event.event == kEventMouseUp) || (event.event == kEventRightMouseUp)) {
|
||||
if (_currentHiliteChannelId && _score->_channels[_currentHiliteChannelId]) {
|
||||
g_director->getCurrentWindow()->setDirty(true);
|
||||
g_director->getCurrentWindow()->addDirtyRect(_score->_channels[_currentHiliteChannelId]->getBbox());
|
||||
}
|
||||
g_director->_wm->_hilitingWidget = false;
|
||||
|
||||
_currentDraggedChannel = nullptr;
|
||||
|
||||
// If this is a button cast member, and the last mouse down event was in a button
|
||||
// (any button), flip this button's hilite flag.
|
||||
// Now you might think, "Wait, we don't flip this flag in the mouseDown event.
|
||||
// And why any button??? This doesn't make any sense."
|
||||
// No, it doesn't make sense, but it's what Director does.
|
||||
if (_mouseDownWasInButton && event.channelId) {
|
||||
CastMember *cast = getCastMember(_score->_channels[event.channelId]->_sprite->_castId);
|
||||
if (cast && cast->_type == kCastButton)
|
||||
cast->_hilite = !cast->_hilite;
|
||||
}
|
||||
_currentHiliteChannelId = 0;
|
||||
_mouseDownWasInButton = false;
|
||||
g_director->loadSlowdownCooloff();
|
||||
}
|
||||
}
|
||||
|
||||
switch (event.eventHandlerSourceType) {
|
||||
case kPrimaryHandler:
|
||||
// Run the primary event handler.
|
||||
// Note that this isn't a "real" cast member ID, it's just the enum
|
||||
// of the type of event, so it can be crammed into the script context
|
||||
// index. kEventScript is a script type reserved for the primary event
|
||||
// handlers (e.g. the mouseDownScript, the mouseUpScript), so there will
|
||||
// be no collision with script cast members like ScoreScripts.
|
||||
{
|
||||
CastMemberID scriptId(event.event, DEFAULT_CAST_LIB);
|
||||
if (getScriptContext(kEventScript, scriptId)) {
|
||||
event.event = kEventGeneric;
|
||||
event.scriptType = kEventScript;
|
||||
event.scriptId = scriptId;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* When the mouseDown or mouseUp occurs over a sprite, the message
|
||||
* goes first to the sprite script, then to the script of the cast
|
||||
* member, to the frame script and finally to the movie scripts.
|
||||
*
|
||||
* When the mouseDown or mouseUp doesn't occur over a sprite, the
|
||||
* message goes to the frame script and then to the movie script.
|
||||
*
|
||||
* When more than one movie script [...]
|
||||
* [D4 docs] */
|
||||
case kSpriteHandler:
|
||||
{
|
||||
CastMemberID scriptId;
|
||||
bool immediate = false;
|
||||
Common::String initializerParams;
|
||||
// mouseUp events seem to check the frame script ID from the original mouseDown event
|
||||
// In Director 5 and above, we always generate event for the actual sprite under the mouse
|
||||
if (((event.event == kEventMouseUp) || (event.event == kEventRightMouseUp)) && _vm->getVersion() < 500) {
|
||||
scriptId = _currentMouseDownSpriteScriptID;
|
||||
immediate = _currentMouseDownSpriteImmediate;
|
||||
} else {
|
||||
if (!event.channelId)
|
||||
return;
|
||||
Frame *currentFrame = _score->_currentFrame;
|
||||
assert(currentFrame != nullptr);
|
||||
Sprite *sprite = _score->getSpriteById(event.channelId);
|
||||
if (!sprite)
|
||||
return;
|
||||
|
||||
if (_vm->getVersion() >= 600) {
|
||||
if (event.behaviorIndex >= 0) {
|
||||
if (event.behaviorIndex >= (int)sprite->_behaviors.size()) {
|
||||
warning("Movie::resolveScriptEvent: invalid behavior index %d, ignoring", event.behaviorIndex);
|
||||
} else {
|
||||
scriptId = sprite->_behaviors[event.behaviorIndex].memberID;
|
||||
initializerParams = sprite->_behaviors[event.behaviorIndex].initializerParams;
|
||||
}
|
||||
} else {
|
||||
_lastClickedSpriteId = 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!sprite->_scriptId.member) {
|
||||
_lastClickedSpriteId = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
scriptId = sprite->_scriptId;
|
||||
}
|
||||
|
||||
immediate = sprite->_immediate;
|
||||
}
|
||||
|
||||
if (_vm->getVersion() >= 600) {
|
||||
event.scriptType = kScoreScript;
|
||||
event.scriptId = scriptId;
|
||||
if (event.behaviorIndex >= 0 && event.behaviorIndex < (int)_score->_channels[event.channelId]->_scriptInstanceList.size())
|
||||
event.scriptInstance = _score->_channels[event.channelId]->_scriptInstanceList[event.behaviorIndex].u.obj;
|
||||
else
|
||||
warning("resolveScriptEvent: behaviorIndex %d out of range", event.behaviorIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sprite (score) script
|
||||
ScriptContext *script = getScriptContext(kScoreScript, scriptId);
|
||||
if (script) {
|
||||
if (script->_eventHandlers.contains(event.event)) {
|
||||
// D4-style event handler
|
||||
event.scriptType = kScoreScript;
|
||||
event.scriptId = scriptId;
|
||||
} else if (script->_eventHandlers.contains(kEventGeneric)) {
|
||||
// D3-style sprite script, not contained in a handler
|
||||
// If sprite is immediate, its script is run on mouseDown, otherwise on mouseUp
|
||||
if ((event.event == kEventMouseDown && immediate) || (event.event == kEventMouseUp && !immediate)) {
|
||||
event.event = kEventGeneric;
|
||||
event.scriptType = kScoreScript;
|
||||
event.scriptId = scriptId;
|
||||
}
|
||||
return; // FIXME: Do not execute the cast script if there is a D3-style sprite script
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kCastHandler:
|
||||
{
|
||||
// Cast script
|
||||
// A strange quirk; if we're in a mouseDown event, Director will test
|
||||
// at runtime to find out whatever is under the mouse and use that.
|
||||
// If we're in a mouseUp event, Director will use whatever was
|
||||
// discovered -at the very beginning- of the mouseDown event chain.
|
||||
// This means e.g. the cast member can be swapped out from underneath in
|
||||
// the mouseDown sprite script and the event passed down, which
|
||||
// will mean the old cast member cast script does not get a mouseDown
|
||||
// call, but it -does- get a mouseUp call.
|
||||
// A bit unhinged, but we have a test that proves Director does this,
|
||||
// so we have to do it too.
|
||||
//
|
||||
// mouseEnter and mouseLeave events should also defer to the value of channelId.
|
||||
CastMemberID targetCast = _currentMouseDownCastID;
|
||||
if ((event.event == kEventMouseDown) || (event.event == kEventRightMouseDown) ||
|
||||
(event.event == kEventMouseEnter) || (event.event == kEventMouseLeave)) {
|
||||
if (!event.channelId)
|
||||
return;
|
||||
Sprite *sprite = _score->getSpriteById(event.channelId);
|
||||
targetCast = sprite->_castId;
|
||||
}
|
||||
|
||||
ScriptContext *script = getScriptContext(kCastScript, targetCast);
|
||||
if (script && script->_eventHandlers.contains(event.event)) {
|
||||
event.scriptType = kCastScript;
|
||||
event.scriptId = targetCast;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kFrameHandler:
|
||||
{
|
||||
/* [in D4] the enterFrame, exitFrame, idle and timeout messages
|
||||
* are sent to a frame script and then a movie script. If the
|
||||
* current frame has no frame script when the event occurs, the
|
||||
* message goes to movie scripts.
|
||||
* [p.81 of D4 docs]
|
||||
*/
|
||||
|
||||
if (_score->_currentFrame == nullptr)
|
||||
return;
|
||||
|
||||
if (_vm->getVersion() >= 600) {
|
||||
if (_score->_scriptChannelScriptInstance.type == OBJECT) {
|
||||
event.scriptType = kScoreScript;
|
||||
event.scriptId = CastMemberID(); // No ID for the script channel script
|
||||
event.scriptInstance = _score->_scriptChannelScriptInstance.u.obj;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Pre D6
|
||||
CastMemberID scriptId = _score->_currentFrame->_mainChannels.actionId;
|
||||
if (!scriptId.member)
|
||||
return;
|
||||
|
||||
ScriptContext *script = getScriptContext(kScoreScript, scriptId);
|
||||
if (!script)
|
||||
return;
|
||||
|
||||
if (script->_eventHandlers.contains(event.event)) {
|
||||
event.scriptType = kScoreScript;
|
||||
event.scriptId = scriptId;
|
||||
return;
|
||||
}
|
||||
|
||||
// Scopeless statements (ie one lined lingo commands) are executed at exitFrame
|
||||
// A score script can have both scopeless and scoped lingo. (eg. porting from D3.1 to D4)
|
||||
// In the event of both being specified in the ScoreScript, the scopeless handler is ignored.
|
||||
|
||||
if (event.event == kEventExitFrame && script->_eventHandlers.contains(kEventGeneric) &&
|
||||
!(script->_eventHandlers.contains(kEventExitFrame) || script->_eventHandlers.contains(kEventEnterFrame))) {
|
||||
event.event = kEventGeneric;
|
||||
event.scriptType = kScoreScript;
|
||||
event.scriptId = scriptId;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kMovieHandler:
|
||||
{
|
||||
/* If more than one movie script handles the same message, Lingo
|
||||
* searches the movie scripts according to their order in the cast
|
||||
* window [p.81 of D4 docs]
|
||||
*/
|
||||
|
||||
// FIXME: shared cast movie scripts could come before main movie ones
|
||||
// Movie scripts are fixed, so it's fine to look them up in advance.
|
||||
for (auto &cast : _casts) {
|
||||
LingoArchive *archive = cast._value->_lingoArchive;
|
||||
for (auto &it : archive->scriptContexts[kMovieScript]) {
|
||||
if (it._value->_eventHandlers.contains(event.event)) {
|
||||
event.scriptType = kMovieScript;
|
||||
event.scriptId = CastMemberID(it._key, cast._key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
LingoArchive *sharedArchive = getSharedLingoArch();
|
||||
if (sharedArchive) {
|
||||
for (auto &it : sharedArchive->scriptContexts[kMovieScript]) {
|
||||
if (it._value->_eventHandlers.contains(event.event)) {
|
||||
event.scriptType = kMovieScript;
|
||||
event.scriptId = CastMemberID(it._key, DEFAULT_CAST_LIB);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Movie::queueEvent(Common::Queue<LingoEvent> &queue, LEvent event, int targetId, Common::Point pos) {
|
||||
if (_nextEventId < 0)
|
||||
_nextEventId = 0;
|
||||
_nextEventId++;
|
||||
int eventId = _nextEventId;
|
||||
|
||||
int oldQueueSize = queue.size();
|
||||
|
||||
uint16 channelId = 0;
|
||||
uint16 pointedSpriteId = 0;
|
||||
|
||||
// In D6+ there are multiple behavors per sprite, find the sprite
|
||||
if (g_director->getVersion() >= 600) {
|
||||
if (targetId == 0) {
|
||||
pointedSpriteId = _score->getMouseSpriteIDFromPos(pos);
|
||||
} else {
|
||||
pointedSpriteId = targetId;
|
||||
}
|
||||
}
|
||||
|
||||
/* When an event occurs the message [...] is first sent to a
|
||||
* primary event handler: [... if exists it is executed] and the
|
||||
* event is passed on to other objects unless you explicitly stop
|
||||
* the message by including the dontPassEvent command in the script
|
||||
* [D4 docs page 77]
|
||||
*/
|
||||
/* N.B.: No primary event handlers for events other than
|
||||
* keyup, keydown, mouseup, mousedown, timeout
|
||||
* [see: www.columbia.edu/itc/visualarts/r4110/s2001/handouts
|
||||
* /03_03_Event_Hierarchy.pdf]
|
||||
*/
|
||||
switch (event) {
|
||||
case kEventMouseDown:
|
||||
case kEventMouseUp:
|
||||
case kEventRightMouseDown:
|
||||
case kEventRightMouseUp:
|
||||
case kEventKeyUp:
|
||||
case kEventKeyDown:
|
||||
case kEventTimeout:
|
||||
{
|
||||
// Queue a call to the the primary event handler.
|
||||
// As per above, by default this will pass through to any subsequent handlers,
|
||||
// unless the script calls "dontPassEvent".
|
||||
queue.push(LingoEvent(event, eventId, kPrimaryHandler, true, pos));
|
||||
|
||||
// Key up and key down events can be sent to the channel with an active widget
|
||||
if ((event == kEventKeyUp) || (event == kEventKeyDown)) {
|
||||
channelId = targetId;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kEventMenuCallback:
|
||||
{
|
||||
CastMemberID scriptID = CastMemberID(targetId, DEFAULT_CAST_LIB);
|
||||
if (getScriptContext(kEventScript, scriptID)) {
|
||||
queue.push(LingoEvent(kEventGeneric, eventId, kEventScript, true, scriptID, pos));
|
||||
}
|
||||
}
|
||||
break;
|
||||
// For mouseEnter/mouseLeave events, we want to specify exactly what sprite channel to resolve to.
|
||||
case kEventMouseEnter:
|
||||
case kEventMouseLeave:
|
||||
case kEventPrepareFrame:
|
||||
case kEventBeginSprite:
|
||||
case kEventEndSprite:
|
||||
case kEventMouseUpOutSide: // D6+
|
||||
case kEventMouseWithin: // D6+
|
||||
if (targetId != 0) {
|
||||
channelId = targetId;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_vm->getVersion() < 400) {
|
||||
// In D2-3, specific objects handle each event, with no passing
|
||||
switch(event) {
|
||||
case kEventMouseUp:
|
||||
case kEventMouseDown:
|
||||
queue.push(LingoEvent(event, eventId, kSpriteHandler, false, pos));
|
||||
queue.push(LingoEvent(event, eventId, kCastHandler, false, pos));
|
||||
break;
|
||||
|
||||
case kEventExitFrame:
|
||||
queue.push(LingoEvent(event, eventId, kFrameHandler, false, pos));
|
||||
break;
|
||||
|
||||
case kEventIdle:
|
||||
case kEventStartUp:
|
||||
case kEventStartMovie:
|
||||
case kEventStepMovie:
|
||||
case kEventStopMovie:
|
||||
queue.push(LingoEvent(event, eventId, kMovieHandler, false, pos));
|
||||
break;
|
||||
|
||||
// no-op; only handled by the primary event handler above
|
||||
// empty case avoids them generating logs from the default
|
||||
// unhandled event case below.
|
||||
case kEventKeyUp:
|
||||
case kEventKeyDown:
|
||||
case kEventTimeout:
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("registerEvent: Unhandled event %s", _lingo->_eventHandlerTypes[event]);
|
||||
}
|
||||
} else {
|
||||
/* In D4+, queue any objects that responds to this event, in order of precedence.
|
||||
* (Sprite -> Cast Member -> Frame -> Movie)
|
||||
* Once one of these objects handles the event, any event handlers queued
|
||||
* for the same event will be ignored unless the pass command was called.
|
||||
*/
|
||||
switch (event) {
|
||||
case kEventKeyUp:
|
||||
case kEventKeyDown:
|
||||
case kEventMouseUp:
|
||||
case kEventMouseDown:
|
||||
case kEventRightMouseUp:
|
||||
case kEventRightMouseDown:
|
||||
case kEventBeginSprite:
|
||||
case kEventEndSprite:
|
||||
case kEventMouseEnter:
|
||||
case kEventMouseLeave:
|
||||
case kEventPrepareFrame: // D6+
|
||||
case kEventMouseUpOutSide: // D6+
|
||||
case kEventMouseWithin: // D6+
|
||||
if (_vm->getVersion() >= 600) {
|
||||
if (pointedSpriteId != 0) {
|
||||
Channel *channel = _score->getChannelById(pointedSpriteId);
|
||||
|
||||
// Generate event for each behavior, and pass through for all but the last one.
|
||||
// This is to allow multiple behaviors on a single sprite to each have a
|
||||
// chance to handle the event.
|
||||
for (uint i = 0; i < channel->_scriptInstanceList.size(); i++) {
|
||||
bool passThrough = (i != channel->_scriptInstanceList.size() - 1);
|
||||
queue.push(LingoEvent(event, eventId, kSpriteHandler, passThrough, pos, pointedSpriteId, i));
|
||||
}
|
||||
|
||||
if (event == kEventBeginSprite || event == kEventEndSprite || event == kEventMouseUpOutSide) {
|
||||
// These events do not go any further than the sprite behaviors
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// We have no sprite under the mouse, no SpriteHandler to queue.
|
||||
}
|
||||
} else {
|
||||
queue.push(LingoEvent(event, eventId, kSpriteHandler, false, pos, channelId));
|
||||
}
|
||||
queue.push(LingoEvent(event, eventId, kCastHandler, false, pos, channelId));
|
||||
// fall through
|
||||
|
||||
case kEventIdle:
|
||||
case kEventEnterFrame:
|
||||
case kEventExitFrame:
|
||||
case kEventTimeout:
|
||||
queue.push(LingoEvent(event, eventId, kFrameHandler, false, pos, channelId));
|
||||
// fall through
|
||||
|
||||
case kEventStartUp:
|
||||
case kEventStartMovie:
|
||||
case kEventStepMovie:
|
||||
case kEventStopMovie:
|
||||
|
||||
case kEventPrepareMovie: // D6
|
||||
|
||||
case kEventActivateWindow: // D5
|
||||
case kEventDeactivateWindow: // D5
|
||||
case kEventMoveWindow: // D5
|
||||
case kEventResizeWindow: // D5
|
||||
case kEventOpenWindow: // D5
|
||||
case kEventCloseWindow: // D5
|
||||
case kEventZoomWindow: // D5
|
||||
queue.push(LingoEvent(event, eventId, kMovieHandler, false, pos, channelId));
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("registerEvent: Unhandled event %s", _lingo->_eventHandlerTypes[event]);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldQueueSize == queue.size()) {
|
||||
debugC(9, kDebugEvents, "Lingo::queueEvent(%s): no event handler", _lingo->_eventHandlerTypes[event]);
|
||||
}
|
||||
}
|
||||
|
||||
void Movie::queueInputEvent(LEvent event, int targetId, Common::Point pos) {
|
||||
queueEvent(_inputEventQueue, event, targetId, pos);
|
||||
}
|
||||
|
||||
void Movie::processEvent(LEvent event, int targetId) {
|
||||
Common::Queue<LingoEvent> queue;
|
||||
queueEvent(queue, event, targetId);
|
||||
_vm->setCurrentWindow(this->getWindow());
|
||||
_lingo->processEvents(queue, false);
|
||||
}
|
||||
|
||||
void Movie::broadcastEvent(LEvent event) {
|
||||
Common::Queue<LingoEvent> queue;
|
||||
|
||||
for (uint i = 1; i < _score->_channels.size(); i++) {
|
||||
if (_score->_channels[i] && _score->_channels[i]->_sprite && _score->_channels[i]->_sprite->_behaviors.size()) {
|
||||
queueEvent(queue, event, i);
|
||||
}
|
||||
}
|
||||
_vm->setCurrentWindow(this->getWindow());
|
||||
_lingo->processEvents(queue, false);
|
||||
}
|
||||
|
||||
void Lingo::processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent) {
|
||||
if (isInputEvent && _currentInputEvent.type != VOIDSYM) {
|
||||
// only one input event should be in flight at a time.
|
||||
return;
|
||||
}
|
||||
Movie *movie = _vm->getCurrentMovie();
|
||||
Score *sc = movie->getScore();
|
||||
|
||||
bool behavioursCompleted = false;
|
||||
|
||||
while (!queue.empty()) {
|
||||
LingoEvent el = queue.pop();
|
||||
|
||||
if (sc->_playState == kPlayStopped && el.event != kEventStopMovie)
|
||||
continue;
|
||||
|
||||
// fetch the sprite ID, script ID to call, etc if not present.
|
||||
movie->resolveScriptEvent(el);
|
||||
|
||||
if (el.scriptType == kNoneScript) {
|
||||
debugC(9, kDebugEvents, "Lingo::processEvents: no matching script for event (%s, %s, %s, %d), continuing",
|
||||
_eventHandlerTypes[el.event], scriptType2str(el.scriptType), el.scriptId.asString().c_str(), el.channelId
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
int lastEventId = movie->_lastEventId.getValOrDefault(el.event, 0);
|
||||
if (lastEventId && lastEventId == el.eventId && !_passEvent) {
|
||||
debugC(5, kDebugEvents, "Lingo::processEvents: swallowed event (%s, %s, %s, %d) because _passEvent was false",
|
||||
_eventHandlerTypes[el.event], scriptType2str(el.scriptType), el.scriptId.asString().c_str(), el.channelId
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
_passEvent = el.passByDefault;
|
||||
|
||||
debugC(5, kDebugEvents, "Lingo::processEvents: starting event script (%s, %s, %s, %d)",
|
||||
_eventHandlerTypes[el.event], scriptType2str(el.scriptType), el.scriptId.asString().c_str(), el.channelId
|
||||
);
|
||||
bool completed = processEvent(el.event, el.scriptType, el.scriptId, el.channelId, el.scriptInstance);
|
||||
movie->_lastEventId[el.event] = el.eventId;
|
||||
|
||||
if (_vm->getVersion() >= 600) {
|
||||
// Reset it for further event processing
|
||||
g_director->getCurrentMovie()->_currentSpriteNum = 0;
|
||||
|
||||
// We need to execute all behaviours before deciding if we pass
|
||||
// through or not
|
||||
if (el.scriptType == kScoreScript && el.passByDefault == true) {
|
||||
behavioursCompleted |= completed;
|
||||
completed = true;
|
||||
} else {
|
||||
completed |= behavioursCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
if (isInputEvent && !completed) {
|
||||
debugC(5, kDebugEvents, "Lingo::processEvents: context frozen on an input event, stopping");
|
||||
LingoState *state = g_director->getCurrentWindow()->getLastFrozenLingoState();
|
||||
if (state && !state->callstack.empty()) {
|
||||
_currentInputEvent = state->callstack.front()->sp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool Lingo::processEvent(LEvent event, ScriptType st, CastMemberID scriptId, int channelId, AbstractObject *obj) {
|
||||
_currentChannelId = channelId;
|
||||
|
||||
if (!_eventHandlerTypes.contains(event))
|
||||
error("processEvent: Unknown event %d", event);
|
||||
|
||||
|
||||
if (g_director->getVersion() >= 600 && st == kScoreScript && obj) {
|
||||
if (obj->getMethod(_eventHandlerTypes[event]).type != VOIDSYM) {
|
||||
g_director->getCurrentMovie()->_currentSpriteNum = channelId;
|
||||
push(Datum(obj));
|
||||
LC::call(_eventHandlerTypes[event], 1, false);
|
||||
return execute();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ScriptContext *script = g_director->getCurrentMovie()->getScriptContext(st, scriptId);
|
||||
int nargs = 0;
|
||||
|
||||
if (script && script->_eventHandlers.contains(event)) {
|
||||
debugC(1, kDebugEvents, "Lingo::processEvent(%s, %s, %s): executing event handler", _eventHandlerTypes[event], scriptType2str(st), scriptId.asString().c_str());
|
||||
g_debugger->eventHook(event);
|
||||
|
||||
// Normally event handlers are called with no arguments, however RolloverToolkit expects
|
||||
// the first argument to be the sprite number.
|
||||
if ((event == kEventMouseEnter && script->_eventHandlers[event].name->equalsIgnoreCase("startRollover")) ||
|
||||
(event == kEventMouseLeave && script->_eventHandlers[event].name->equalsIgnoreCase("endRollover"))) {
|
||||
push(Datum(channelId));
|
||||
nargs = 1;
|
||||
}
|
||||
|
||||
LC::call(script->_eventHandlers[event], nargs, false);
|
||||
return execute();
|
||||
} else {
|
||||
debugC(9, kDebugEvents, "Lingo::processEvent(%s, %s, %s): no handler", _eventHandlerTypes[event], scriptType2str(st), scriptId.asString().c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************
|
||||
* Script Instances
|
||||
***********************/
|
||||
|
||||
void Score::killScriptInstances(int frameNum) {
|
||||
if (_version < kFileVer600) // No-op for early Directors
|
||||
return;
|
||||
|
||||
if (frameNum < _currentFrame->_mainChannels.scriptSpriteInfo.startFrame ||
|
||||
frameNum > _currentFrame->_mainChannels.scriptSpriteInfo.endFrame) {
|
||||
if (_scriptChannelScriptInstance.type == OBJECT) {
|
||||
_scriptChannelScriptInstance = Datum();
|
||||
debugC(1, kDebugLingoExec, "Score::killScriptInstances(): Killed script instances for script channel. frame %d [%d-%d]",
|
||||
frameNum,
|
||||
_currentFrame->_mainChannels.scriptSpriteInfo.startFrame,
|
||||
_currentFrame->_mainChannels.scriptSpriteInfo.endFrame);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)_channels.size(); i++) {
|
||||
Channel *channel = _channels[i];
|
||||
|
||||
if (channel->_scriptInstanceList.size() == 0)
|
||||
continue;
|
||||
|
||||
if (frameNum < channel->_startFrame || frameNum > channel->_endFrame) {
|
||||
bool prevDis = _disableGoPlayUpdateStage;
|
||||
_disableGoPlayUpdateStage = true;
|
||||
_movie->processEvent(kEventEndSprite, i);
|
||||
_disableGoPlayUpdateStage = prevDis;
|
||||
|
||||
channel->_scriptInstanceList.clear();
|
||||
channel->_sprite->_behaviors.clear();
|
||||
debugC(1, kDebugLingoExec, "Score::killScriptInstances(): Killed script instances for channel %d. frame %d [%d-%d]",
|
||||
i + 1, frameNum, channel->_startFrame, channel->_endFrame);
|
||||
|
||||
channel->_startFrame = channel->_endFrame = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Datum Score::createScriptInstance(BehaviorElement *behavior) {
|
||||
// Instantiate the behavior
|
||||
ScriptContext *scr = _movie->getScriptContext(kScoreScript, behavior->memberID);
|
||||
|
||||
// Some movies have behaviors with missing scripts
|
||||
if (scr == nullptr) {
|
||||
debugC(7, kDebugLingoExec, "Score::createScriptInstance(): Missing script for behavior %s", behavior->toString().c_str());
|
||||
return Datum();
|
||||
}
|
||||
|
||||
g_lingo->push(scr);
|
||||
LC::call("new", 1, true);
|
||||
Datum instance = g_lingo->pop();
|
||||
|
||||
if (instance.type != OBJECT) {
|
||||
warning("Score::createScriptInstance(): Could not instantiate behavior %s", behavior->toString().c_str());
|
||||
return Datum();
|
||||
}
|
||||
|
||||
debugC(1, kDebugLingoExec, " Instantiated behavior %s", behavior->toString().c_str());
|
||||
|
||||
// No initializer, we are done
|
||||
if (behavior->initializerIndex == 0)
|
||||
return instance;
|
||||
|
||||
// Evaluate the params
|
||||
g_lingo->push(behavior->initializerParams);
|
||||
LB::b_value(1);
|
||||
g_lingo->execute();
|
||||
|
||||
if (debugChannelSet(5, kDebugLingoExec)) {
|
||||
g_lingo->printStack(" Parsed behavior parameters: ", 0);
|
||||
}
|
||||
|
||||
if (g_lingo->_state->stack.size() == 0) {
|
||||
warning("Score::createScriptInstance(): Could not evaluate initializer params '%s' for behavior %s",
|
||||
behavior->initializerParams.c_str(), behavior->toString().c_str());
|
||||
return instance;
|
||||
}
|
||||
|
||||
Datum proplist = _lingo->pop();
|
||||
|
||||
if (proplist.type != PARRAY) {
|
||||
warning("Score::createScriptInstance(): Could not evaluate initializer params '%s' for behavior %s",
|
||||
behavior->initializerParams.c_str(), behavior->toString().c_str());
|
||||
return instance;
|
||||
}
|
||||
|
||||
debugC(2, kDebugLingoExec, " Setting %d properties", proplist.u.parr->arr.size());
|
||||
|
||||
for (uint k = 0; k < proplist.u.parr->arr.size(); k++) {
|
||||
Datum key = proplist.u.parr->arr[k].p;
|
||||
Datum val = proplist.u.parr->arr[k].v;
|
||||
|
||||
instance.u.obj->setProp(key.asString(), val);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
void Score::createScriptInstances(int frameNum) {
|
||||
if (_version < kFileVer600) // No-op for early Directors
|
||||
return;
|
||||
|
||||
if (frameNum >= _currentFrame->_mainChannels.scriptSpriteInfo.startFrame &&
|
||||
frameNum <= _currentFrame->_mainChannels.scriptSpriteInfo.endFrame) {
|
||||
|
||||
// We have no instantiated script
|
||||
if (_scriptChannelScriptInstance.type != OBJECT) {
|
||||
if (_currentFrame->_mainChannels.behaviors.size() > 0) {
|
||||
debugC(1, kDebugLingoExec, "Score::createScriptInstances(): Creating script instances for script channel, frames [%d-%d]",
|
||||
_currentFrame->_mainChannels.scriptSpriteInfo.startFrame,
|
||||
_currentFrame->_mainChannels.scriptSpriteInfo.endFrame);
|
||||
_scriptChannelScriptInstance = createScriptInstance(&_currentFrame->_mainChannels.behaviors[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)_channels.size(); i++) {
|
||||
Channel *channel = _channels[i];
|
||||
Sprite *sprite = channel->_sprite;
|
||||
|
||||
// The frame does not belong to the range
|
||||
if (frameNum < channel->_startFrame || frameNum > channel->_endFrame)
|
||||
continue;
|
||||
|
||||
// We create scriptInstance only for new sprites
|
||||
if (channel->_scriptInstanceList.size() != 0)
|
||||
continue;
|
||||
|
||||
// No behaviors, nothing to do
|
||||
if (sprite->_behaviors.size() == 0)
|
||||
continue;
|
||||
|
||||
debugC(1, kDebugLingoExec, "Score::createScriptInstances(): Creating script instances for channel %d, %d behaviors, frames [%d-%d]",
|
||||
i + 1, sprite->_behaviors.size(), channel->_startFrame, channel->_endFrame);
|
||||
|
||||
for (uint j = 0; j < sprite->_behaviors.size(); j++) {
|
||||
Datum instance = createScriptInstance(&sprite->_behaviors[j]);
|
||||
|
||||
if (instance.type != OBJECT) {
|
||||
if (!instance.isVoid())
|
||||
warning("Score::createScriptInstances(): Could not instantiate behavior %s", sprite->_behaviors[j].toString().c_str());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
channel->_scriptInstanceList.push_back(instance);
|
||||
}
|
||||
|
||||
bool prevDis = _disableGoPlayUpdateStage;
|
||||
_disableGoPlayUpdateStage = true;
|
||||
_movie->processEvent(kEventBeginSprite, i);
|
||||
_disableGoPlayUpdateStage = prevDis;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
275
engines/director/lingo/lingo-funcs.cpp
Normal file
275
engines/director/lingo/lingo-funcs.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "common/file.h"
|
||||
#include "common/macresman.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "graphics/macgui/macwindowmanager.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/archive.h"
|
||||
#include "director/cursor.h"
|
||||
#include "director/movie.h"
|
||||
#include "director/score.h"
|
||||
#include "director/sound.h"
|
||||
#include "director/window.h"
|
||||
|
||||
#include "director/lingo/lingo-builtins.h"
|
||||
|
||||
|
||||
namespace Director {
|
||||
|
||||
void Lingo::func_goto(Datum &frame, Datum &movie, bool calledfromgo) {
|
||||
_vm->_playbackPaused = false;
|
||||
|
||||
if (!_vm->getCurrentMovie())
|
||||
return;
|
||||
|
||||
if (movie.type == VOID && frame.type == VOID)
|
||||
return;
|
||||
|
||||
Window *stage = _vm->getCurrentWindow();
|
||||
Score *score = stage->getCurrentMovie()->getScore();
|
||||
|
||||
if (score->_disableGoPlayUpdateStage) {
|
||||
warning("Lingo::func_goto(): ignoring goto due to disableGoPlayUpdateStage flag");
|
||||
return;
|
||||
}
|
||||
|
||||
stage->_skipFrameAdvance = true;
|
||||
|
||||
// If there isn't already frozen Lingo (e.g. from a previous func_goto we haven't yet unfrozen),
|
||||
// freeze this script context. We'll return to it after entering the next frame.
|
||||
|
||||
// Returning from a script with "play done" does not freeze the state. Instead it obliterates it.
|
||||
if (!g_lingo->_playDone)
|
||||
g_lingo->_freezeState = true;
|
||||
|
||||
if (movie.type != VOID) {
|
||||
Common::String movieFilenameRaw = movie.asString();
|
||||
|
||||
if (!stage->setNextMovie(movieFilenameRaw))
|
||||
return;
|
||||
|
||||
// If we reached here from b_go, and the movie is getting swapped out,
|
||||
// reset all of the custom event handlers.
|
||||
if (calledfromgo)
|
||||
g_lingo->resetLingoGo();
|
||||
|
||||
if (g_lingo->_updateMovieEnabled) {
|
||||
// Save the movie when branching to another movie.
|
||||
LB::b_saveMovie(0);
|
||||
}
|
||||
|
||||
score->_playState = kPlayStopped;
|
||||
|
||||
stage->_nextMovie.frameS.clear();
|
||||
stage->_nextMovie.frameI = -1;
|
||||
|
||||
if (frame.type == STRING) {
|
||||
debugC(3, kDebugLingoExec, "Lingo::func_goto(): going to movie \"%s\", frame \"%s\"", movieFilenameRaw.c_str(), frame.u.s->c_str());
|
||||
stage->_nextMovie.frameS = *frame.u.s;
|
||||
} else if (frame.type != VOID) {
|
||||
debugC(3, kDebugLingoExec, "Lingo::func_goto(): going to movie \"%s\", frame %d", movieFilenameRaw.c_str(), frame.asInt());
|
||||
stage->_nextMovie.frameI = frame.asInt();
|
||||
} else {
|
||||
debugC(3, kDebugLingoExec, "Lingo::func_goto(): going to start of movie \"%s\"", movieFilenameRaw.c_str());
|
||||
}
|
||||
|
||||
// Set cursor to watch.
|
||||
score->_defaultCursor.readFromResource(4);
|
||||
score->renderCursor(stage->getMousePos());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame.type == STRING) {
|
||||
debugC(3, kDebugLingoExec, "Lingo::func_goto(): going to frame \"%s\"", frame.u.s->c_str());
|
||||
score->setStartToLabel(*frame.u.s);
|
||||
} else {
|
||||
debugC(3, kDebugLingoExec, "Lingo::func_goto(): going to frame %d", frame.asInt());
|
||||
score->setCurrentFrame(frame.asInt());
|
||||
}
|
||||
|
||||
// Since the frames are not going to be consecutive, we might run into
|
||||
// an endge case, so better kill behaviors proactively.
|
||||
score->killScriptInstances(score->getNextFrame());
|
||||
}
|
||||
|
||||
void Lingo::func_gotoloop() {
|
||||
if (!_vm->getCurrentMovie())
|
||||
return;
|
||||
Window *stage = _vm->getCurrentWindow();
|
||||
Score *score = stage->getCurrentMovie()->getScore();
|
||||
debugC(3, kDebugLingoExec, "Lingo::func_gotoloop(): looping frame %d", score->getCurrentFrameNum());
|
||||
|
||||
score->gotoLoop();
|
||||
|
||||
stage->_skipFrameAdvance = true;
|
||||
}
|
||||
|
||||
void Lingo::func_gotonext() {
|
||||
if (!_vm->getCurrentMovie())
|
||||
return;
|
||||
|
||||
Window *stage = _vm->getCurrentWindow();
|
||||
Score *score = stage->getCurrentMovie()->getScore();
|
||||
score->gotoNext();
|
||||
debugC(3, kDebugLingoExec, "Lingo::func_gotonext(): going to next frame %d", score->getNextFrame());
|
||||
|
||||
stage->_skipFrameAdvance = true;
|
||||
}
|
||||
|
||||
void Lingo::func_gotoprevious() {
|
||||
if (!_vm->getCurrentMovie())
|
||||
return;
|
||||
|
||||
Window *stage = _vm->getCurrentWindow();
|
||||
Score *score = stage->getCurrentMovie()->getScore();
|
||||
score->gotoPrevious();
|
||||
debugC(3, kDebugLingoExec, "Lingo::func_gotoprevious(): going to previous frame %d", score->getNextFrame());
|
||||
|
||||
stage->_skipFrameAdvance = true;
|
||||
}
|
||||
|
||||
void Lingo::func_play(Datum &frame, Datum &movie) {
|
||||
MovieReference ref;
|
||||
Window *stage = _vm->getCurrentWindow();
|
||||
|
||||
if (stage->getCurrentMovie()->getScore()->_disableGoPlayUpdateStage) {
|
||||
warning("Lingo::func_play(): ignoring play due to disableGoPlayUpdateStage flag");
|
||||
return;
|
||||
}
|
||||
|
||||
// play #done
|
||||
if (frame.type == SYMBOL) {
|
||||
if (!frame.u.s->equals("done")) {
|
||||
warning("Lingo::func_play: unknown symbol: #%s", frame.u.s->c_str());
|
||||
return;
|
||||
}
|
||||
_playDone = true;
|
||||
if (stage->_movieStack.empty()) { // No op if no nested movies
|
||||
|
||||
return;
|
||||
}
|
||||
ref = stage->_movieStack.back();
|
||||
|
||||
stage->_movieStack.pop_back();
|
||||
|
||||
Datum m, f;
|
||||
|
||||
if (ref.movie.empty()) {
|
||||
m.type = VOID;
|
||||
} else {
|
||||
m.type = STRING;
|
||||
m.u.s = new Common::String(ref.movie);
|
||||
}
|
||||
|
||||
f.type = INT;
|
||||
f.u.i = ref.frameI;
|
||||
|
||||
func_goto(f, m);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_vm->getCurrentMovie()) {
|
||||
warning("Lingo::func_play(): no movie");
|
||||
return;
|
||||
}
|
||||
|
||||
if (movie.type != VOID) {
|
||||
ref.movie = _vm->getCurrentMovie()->_movieArchive->getPathName().toString(g_director->_dirSeparator);
|
||||
}
|
||||
ref.frameI = _vm->getCurrentMovie()->getScore()->getCurrentFrameNum();
|
||||
|
||||
// if we are issuing play command from script channel script. then play done should return to next frame
|
||||
if (g_lingo->_currentChannelId == 0)
|
||||
ref.frameI++;
|
||||
|
||||
stage->_movieStack.push_back(ref);
|
||||
|
||||
func_goto(frame, movie);
|
||||
_freezePlay = true;
|
||||
}
|
||||
|
||||
void Lingo::func_cursor(Datum cursorDatum) {
|
||||
Window *stage = _vm->getCurrentWindow();
|
||||
Score *score = stage->getCurrentMovie()->getScore();
|
||||
if (cursorDatum.type == ARRAY){
|
||||
score->_defaultCursor.readFromCast(cursorDatum);
|
||||
} else {
|
||||
score->_defaultCursor.readFromResource(cursorDatum);
|
||||
}
|
||||
score->_cursorDirty = true;
|
||||
}
|
||||
|
||||
void Lingo::func_beep(int repeats) {
|
||||
for (int r = 1; r <= repeats; r++) {
|
||||
_vm->getCurrentWindow()->getSoundManager()->systemBeep();
|
||||
if (r < repeats)
|
||||
g_director->delayMillis(400);
|
||||
}
|
||||
}
|
||||
|
||||
int Lingo::func_marker(int m) {
|
||||
if (!_vm->getCurrentMovie())
|
||||
return 0;
|
||||
|
||||
Window *stage = _vm->getCurrentWindow();
|
||||
Score *score = stage->getCurrentMovie()->getScore();
|
||||
int labelNumber = score->getCurrentLabelNumber();
|
||||
if (m != 0) {
|
||||
if (m < 0) {
|
||||
for (int marker = 0; marker > m; marker--)
|
||||
labelNumber = score->getPreviousLabelNumber(labelNumber);
|
||||
} else {
|
||||
for (int marker = 0; marker < m; marker++)
|
||||
labelNumber = score->getNextLabelNumber(labelNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return labelNumber;
|
||||
}
|
||||
|
||||
uint16 Lingo::func_label(Datum &label) {
|
||||
Window *stage = _vm->getCurrentWindow();
|
||||
Score *score = stage->getCurrentMovie()->getScore();
|
||||
|
||||
if (!score->_labels)
|
||||
return 0;
|
||||
|
||||
if (label.type == STRING)
|
||||
return score->getLabel(*label.u.s);
|
||||
|
||||
int num = CLIP<int>(label.asInt() - 1, 0, score->_labels->size() - 1);
|
||||
|
||||
uint16 res = score->getNextLabelNumber(0);
|
||||
|
||||
while (--num > 0)
|
||||
res = score->getNextLabelNumber(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
4996
engines/director/lingo/lingo-gr.cpp
Normal file
4996
engines/director/lingo/lingo-gr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
186
engines/director/lingo/lingo-gr.h
Normal file
186
engines/director/lingo/lingo-gr.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
|
||||
especially those whose name start with YY_ or yy_. They are
|
||||
private implementation details that can be changed or removed. */
|
||||
|
||||
#ifndef YY_YY_ENGINES_DIRECTOR_LINGO_LINGO_GR_H_INCLUDED
|
||||
# define YY_YY_ENGINES_DIRECTOR_LINGO_LINGO_GR_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 1
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
extern int yydebug;
|
||||
#endif
|
||||
|
||||
/* Token kinds. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
enum yytokentype
|
||||
{
|
||||
YYEMPTY = -2,
|
||||
YYEOF = 0, /* "end of file" */
|
||||
YYerror = 256, /* error */
|
||||
YYUNDEF = 257, /* "invalid token" */
|
||||
tUNARY = 258, /* tUNARY */
|
||||
tINT = 259, /* tINT */
|
||||
tFLOAT = 260, /* tFLOAT */
|
||||
tVARID = 261, /* tVARID */
|
||||
tSTRING = 262, /* tSTRING */
|
||||
tSYMBOL = 263, /* tSYMBOL */
|
||||
tENDCLAUSE = 264, /* tENDCLAUSE */
|
||||
tCAST = 265, /* tCAST */
|
||||
tFIELD = 266, /* tFIELD */
|
||||
tSCRIPT = 267, /* tSCRIPT */
|
||||
tWINDOW = 268, /* tWINDOW */
|
||||
tMEMBER = 269, /* tMEMBER */
|
||||
tCASTLIB = 270, /* tCASTLIB */
|
||||
tDELETE = 271, /* tDELETE */
|
||||
tDOWN = 272, /* tDOWN */
|
||||
tELSE = 273, /* tELSE */
|
||||
tEXIT = 274, /* tEXIT */
|
||||
tFRAME = 275, /* tFRAME */
|
||||
tGLOBAL = 276, /* tGLOBAL */
|
||||
tGO = 277, /* tGO */
|
||||
tHILITE = 278, /* tHILITE */
|
||||
tIF = 279, /* tIF */
|
||||
tIN = 280, /* tIN */
|
||||
tINTO = 281, /* tINTO */
|
||||
tMACRO = 282, /* tMACRO */
|
||||
tRETURN = 283, /* tRETURN */
|
||||
tMOVIE = 284, /* tMOVIE */
|
||||
tNEXT = 285, /* tNEXT */
|
||||
tOF = 286, /* tOF */
|
||||
tPREVIOUS = 287, /* tPREVIOUS */
|
||||
tPUT = 288, /* tPUT */
|
||||
tREPEAT = 289, /* tREPEAT */
|
||||
tSET = 290, /* tSET */
|
||||
tTHEN = 291, /* tTHEN */
|
||||
tTO = 292, /* tTO */
|
||||
tWHEN = 293, /* tWHEN */
|
||||
tWITH = 294, /* tWITH */
|
||||
tWHILE = 295, /* tWHILE */
|
||||
tFACTORY = 296, /* tFACTORY */
|
||||
tOPEN = 297, /* tOPEN */
|
||||
tPLAY = 298, /* tPLAY */
|
||||
tINSTANCE = 299, /* tINSTANCE */
|
||||
tGE = 300, /* tGE */
|
||||
tLE = 301, /* tLE */
|
||||
tEQ = 302, /* tEQ */
|
||||
tNEQ = 303, /* tNEQ */
|
||||
tAND = 304, /* tAND */
|
||||
tOR = 305, /* tOR */
|
||||
tNOT = 306, /* tNOT */
|
||||
tMOD = 307, /* tMOD */
|
||||
tAFTER = 308, /* tAFTER */
|
||||
tBEFORE = 309, /* tBEFORE */
|
||||
tCONCAT = 310, /* tCONCAT */
|
||||
tCONTAINS = 311, /* tCONTAINS */
|
||||
tSTARTS = 312, /* tSTARTS */
|
||||
tCHAR = 313, /* tCHAR */
|
||||
tCHARS = 314, /* tCHARS */
|
||||
tITEM = 315, /* tITEM */
|
||||
tITEMS = 316, /* tITEMS */
|
||||
tLINE = 317, /* tLINE */
|
||||
tLINES = 318, /* tLINES */
|
||||
tWORD = 319, /* tWORD */
|
||||
tWORDS = 320, /* tWORDS */
|
||||
tABBREVIATED = 321, /* tABBREVIATED */
|
||||
tABBREV = 322, /* tABBREV */
|
||||
tABBR = 323, /* tABBR */
|
||||
tLONG = 324, /* tLONG */
|
||||
tSHORT = 325, /* tSHORT */
|
||||
tDATE = 326, /* tDATE */
|
||||
tLAST = 327, /* tLAST */
|
||||
tMENU = 328, /* tMENU */
|
||||
tMENUS = 329, /* tMENUS */
|
||||
tMENUITEM = 330, /* tMENUITEM */
|
||||
tMENUITEMS = 331, /* tMENUITEMS */
|
||||
tNUMBER = 332, /* tNUMBER */
|
||||
tTHE = 333, /* tTHE */
|
||||
tTIME = 334, /* tTIME */
|
||||
tXTRAS = 335, /* tXTRAS */
|
||||
tCASTLIBS = 336, /* tCASTLIBS */
|
||||
tSOUND = 337, /* tSOUND */
|
||||
tSPRITE = 338, /* tSPRITE */
|
||||
tINTERSECTS = 339, /* tINTERSECTS */
|
||||
tWITHIN = 340, /* tWITHIN */
|
||||
tTELL = 341, /* tTELL */
|
||||
tPROPERTY = 342, /* tPROPERTY */
|
||||
tON = 343, /* tON */
|
||||
tMETHOD = 344, /* tMETHOD */
|
||||
tENDIF = 345, /* tENDIF */
|
||||
tENDREPEAT = 346, /* tENDREPEAT */
|
||||
tENDTELL = 347, /* tENDTELL */
|
||||
tASSERTERROR = 348 /* tASSERTERROR */
|
||||
};
|
||||
typedef enum yytokentype yytoken_kind_t;
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 118 "engines/director/lingo/lingo-gr.y"
|
||||
|
||||
Common::String *s;
|
||||
int i;
|
||||
double f;
|
||||
Director::ChunkType chunktype;
|
||||
struct {
|
||||
Common::String *eventName;
|
||||
Common::String *stmt;
|
||||
} w;
|
||||
|
||||
Director::IDList *idlist;
|
||||
Director::Node *node;
|
||||
Director::NodeList *nodelist;
|
||||
|
||||
#line 172 "engines/director/lingo/lingo-gr.h"
|
||||
|
||||
};
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
|
||||
int yyparse (void);
|
||||
|
||||
|
||||
#endif /* !YY_YY_ENGINES_DIRECTOR_LINGO_LINGO_GR_H_INCLUDED */
|
||||
926
engines/director/lingo/lingo-gr.y
Normal file
926
engines/director/lingo/lingo-gr.y
Normal file
@@ -0,0 +1,926 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Heavily inspired by hoc
|
||||
// Copyright (C) AT&T 1995
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software and
|
||||
// its documentation for any purpose and without fee is hereby
|
||||
// granted, provided that the above copyright notice appear in all
|
||||
// copies and that both that the copyright notice and this
|
||||
// permission notice and warranty disclaimer appear in supporting
|
||||
// documentation, and that the name of AT&T or any of its entities
|
||||
// not be used in advertising or publicity pertaining to
|
||||
// distribution of the software without specific, written prior
|
||||
// permission.
|
||||
//
|
||||
// AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
// IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
// THIS SOFTWARE.
|
||||
|
||||
%require "3.6"
|
||||
%defines "engines/director/lingo/lingo-gr.h"
|
||||
%output "engines/director/lingo/lingo-gr.cpp"
|
||||
%define parse.error custom
|
||||
%define parse.trace
|
||||
|
||||
// %glr-parser
|
||||
|
||||
%{
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fwrite
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fread
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdin
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getc
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-ast.h"
|
||||
#include "director/lingo/lingo-code.h"
|
||||
#include "director/lingo/lingo-codegen.h"
|
||||
#include "director/lingo/lingo-gr.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/lingo/lingo-the.h"
|
||||
|
||||
extern int yylex();
|
||||
|
||||
using namespace Director;
|
||||
|
||||
static void yyerror(const char *s) {
|
||||
LingoCompiler *compiler = g_lingo->_compiler;
|
||||
compiler->_hadError = true;
|
||||
warning("%s LINGO: %s at line %d col %d in %s id: %d",
|
||||
(g_director->_noFatalLingoError ? "####" : "######################"), s, compiler->_linenumber, compiler->_colnumber, scriptType2str(compiler->_assemblyContext->_scriptType),
|
||||
compiler->_assemblyContext->_id);
|
||||
if (compiler->_lines[2] != compiler->_lines[1])
|
||||
warning("# %3d: %s", compiler->_linenumber - 2, Common::String(compiler->_lines[2], compiler->_lines[1] - 1).c_str());
|
||||
|
||||
if (compiler->_lines[1] != compiler->_lines[0])
|
||||
warning("# %3d: %s", compiler->_linenumber - 1, Common::String(compiler->_lines[1], compiler->_lines[0] - 1).c_str());
|
||||
|
||||
const char *ptr = compiler->_lines[0];
|
||||
|
||||
while (*ptr && *ptr != '\n')
|
||||
ptr++;
|
||||
|
||||
warning("# %3d: %s", compiler->_linenumber, Common::String(compiler->_lines[0], ptr).c_str());
|
||||
|
||||
Common::String arrow;
|
||||
for (uint i = 0; i < compiler->_colnumber; i++)
|
||||
arrow += ' ';
|
||||
|
||||
warning("# %s^ about here", arrow.c_str());
|
||||
}
|
||||
|
||||
static void checkEnd(Common::String *token, Common::String *expect, bool required) {
|
||||
if (required) {
|
||||
if (token->compareToIgnoreCase(*expect)) {
|
||||
Common::String err = Common::String::format("end mismatch. Expected %s but got %s", expect->c_str(), token->c_str());
|
||||
yyerror(err.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
Common::String *s;
|
||||
int i;
|
||||
double f;
|
||||
Director::ChunkType chunktype;
|
||||
struct {
|
||||
Common::String *eventName;
|
||||
Common::String *stmt;
|
||||
} w;
|
||||
|
||||
Director::IDList *idlist;
|
||||
Director::Node *node;
|
||||
Director::NodeList *nodelist;
|
||||
}
|
||||
|
||||
%token tUNARY
|
||||
|
||||
%token<i> tINT
|
||||
%token<f> tFLOAT
|
||||
%token<s> tVARID tSTRING tSYMBOL
|
||||
%token<s> tENDCLAUSE
|
||||
%token tCAST tFIELD tSCRIPT tWINDOW tMEMBER tCASTLIB
|
||||
%token tDELETE tDOWN tELSE tEXIT tFRAME tGLOBAL tGO tHILITE tIF tIN tINTO tMACRO tRETURN
|
||||
%token tMOVIE tNEXT tOF tPREVIOUS tPUT tREPEAT tSET tTHEN tTO tWHEN
|
||||
%token tWITH tWHILE tFACTORY tOPEN tPLAY tINSTANCE
|
||||
%token tGE tLE tEQ tNEQ tAND tOR tNOT tMOD
|
||||
%token tAFTER tBEFORE tCONCAT tCONTAINS tSTARTS
|
||||
%token tCHAR tCHARS tITEM tITEMS tLINE tLINES tWORD tWORDS
|
||||
%token tABBREVIATED tABBREV tABBR tLONG tSHORT
|
||||
%token tDATE tLAST tMENU tMENUS tMENUITEM tMENUITEMS tNUMBER tTHE tTIME tXTRAS tCASTLIBS
|
||||
%token tSOUND tSPRITE tINTERSECTS tWITHIN tTELL tPROPERTY
|
||||
%token tON tMETHOD tENDIF tENDREPEAT tENDTELL
|
||||
%token tASSERTERROR
|
||||
|
||||
// D5
|
||||
// %token tCASE tOTHERWISE
|
||||
|
||||
%type<w> tWHEN
|
||||
|
||||
// TOP-LEVEL STUFF
|
||||
%type<node> script scriptpart
|
||||
%type<nodelist> scriptpartlist
|
||||
|
||||
// MACRO
|
||||
%type<node> macro
|
||||
|
||||
// FACTORY
|
||||
%type<node> factory method
|
||||
%type<nodelist> methodlist nonemptymethodlist
|
||||
%type<node> methodlistline
|
||||
|
||||
// HANDLER
|
||||
%type<node> handler
|
||||
|
||||
// GENERIC VAR STUFF
|
||||
%type<s> CMDID ID
|
||||
%type<idlist> idlist nonemptyidlist
|
||||
|
||||
// STATEMENT
|
||||
%type<node> stmt stmt_insideif stmtoneliner
|
||||
%type<node> proc asgn definevars
|
||||
%type<node> ifstmt ifelsestmt loop tell when
|
||||
%type<nodelist> cmdargs frameargs stmtlist nonemptystmtlist stmtlist_insideif nonemptystmtlist_insideif
|
||||
%type<node> stmtlistline stmtlistline_insideif
|
||||
|
||||
// EXPRESSION
|
||||
%type<node> simpleexpr_nounarymath simpleexpr
|
||||
%type<node> unarymath
|
||||
%type<node> expr expr_nounarymath expr_noeq sprite
|
||||
%type<node> var varorchunk varorthe
|
||||
%type<chunktype> chunktype
|
||||
%type<node> the theobj menu thedatetime thenumberof
|
||||
%type<node> writablethe writabletheobj
|
||||
%type<node> list proppair
|
||||
%type<node> chunk object
|
||||
%type<nodelist> refargs proplist exprlist nonemptyexprlist
|
||||
|
||||
%left tAND tOR
|
||||
%left '<' tLE '>' tGE tEQ tNEQ tCONTAINS tSTARTS
|
||||
%left '&' tCONCAT
|
||||
%left '+' '-'
|
||||
%left '*' '/' tMOD
|
||||
%right tUNARY
|
||||
// %right tCAST tFIELD tSCRIPT tWINDOW
|
||||
// %nonassoc tVARID
|
||||
|
||||
%destructor { delete $$; } <s>
|
||||
%destructor { delete $$; } <node>
|
||||
|
||||
%%
|
||||
|
||||
// TOP-LEVEL STUFF
|
||||
|
||||
script: scriptpartlist { g_lingo->_compiler->_assemblyAST = Common::SharedPtr<Node>(new ScriptNode($scriptpartlist)); $$ = nullptr; } ;
|
||||
|
||||
scriptpartlist: scriptpart[item] {
|
||||
NodeList *list = new NodeList;
|
||||
if ($item) {
|
||||
list->push_back($item);
|
||||
}
|
||||
$$ = list; }
|
||||
| scriptpartlist[prev] scriptpart[item] {
|
||||
if ($item) {
|
||||
$prev->push_back($item);
|
||||
}
|
||||
$$ = $prev; }
|
||||
;
|
||||
|
||||
scriptpart: '\n' { $$ = nullptr; }
|
||||
| macro
|
||||
| factory
|
||||
| handler
|
||||
| stmt
|
||||
| tENDCLAUSE endargdef '\n' { $$ = nullptr; delete $tENDCLAUSE; } // stray `end`s are allowed for some reason
|
||||
;
|
||||
|
||||
// MACRO
|
||||
|
||||
// Special Note The macro keyword is retained in Director 3.0 to maintain compatibility
|
||||
// with scripts developed under Version 2.0. When writing new scripts, or editing old
|
||||
// scripts, you should use handlers instead of macros. (Handlers are defined with the on keyword.)
|
||||
//
|
||||
// Syntax:
|
||||
//
|
||||
// -- [comment]
|
||||
// macro macroName [argument1] [, argument2]
|
||||
// [, argument3]
|
||||
// [statement1]
|
||||
// [statement2]
|
||||
//
|
||||
// Keyword. Defines a macro. A macro is a multiple-line script defined
|
||||
// in the Text window. Macros can accept arguments (inputs) and
|
||||
// optionally return a result. Macros can call other macros and can be
|
||||
// called from any other script or factory.
|
||||
//
|
||||
// The first line of a castmember in the Text window that contains a macro must be
|
||||
// a comment (--). You can define more than one macro in a given text castmember.
|
||||
// The macro definition ends where the next macro (or factory) begins.
|
||||
//
|
||||
// See also:
|
||||
// on keyword
|
||||
|
||||
macro: tMACRO ID idlist '\n' stmtlist { $$ = new HandlerNode($ID, $idlist, $stmtlist); } ;
|
||||
|
||||
// FACTORY
|
||||
|
||||
factory: tFACTORY ID '\n' methodlist { $$ = new FactoryNode($ID, $methodlist); } ;
|
||||
|
||||
method: tMETHOD ID idlist '\n' stmtlist { $$ = new HandlerNode($ID, $idlist, $stmtlist); } ;
|
||||
|
||||
methodlist: /* empty */ { $$ = new NodeList; }
|
||||
| nonemptymethodlist
|
||||
;
|
||||
|
||||
nonemptymethodlist: methodlistline[item] {
|
||||
NodeList *list = new NodeList;
|
||||
if ($item) {
|
||||
list->push_back($item);
|
||||
}
|
||||
$$ = list; }
|
||||
| nonemptymethodlist[prev] methodlistline[item] {
|
||||
if ($item) {
|
||||
$prev->push_back($item);
|
||||
}
|
||||
$$ = $prev; }
|
||||
;
|
||||
|
||||
methodlistline: '\n' { $$ = nullptr; }
|
||||
| method
|
||||
| tENDCLAUSE endargdef '\n' { $$ = nullptr; delete $tENDCLAUSE; } // stray `end`s are allowed for some reason
|
||||
;
|
||||
|
||||
// HANDLER
|
||||
|
||||
handler: tON ID idlist '\n' stmtlist tENDCLAUSE endargdef '\n' { // D3
|
||||
$$ = new HandlerNode($ID, $idlist, $stmtlist);
|
||||
checkEnd($tENDCLAUSE, $ID, false);
|
||||
delete $tENDCLAUSE; }
|
||||
| tON ID idlist '\n' stmtlist { // D4. No 'end' clause
|
||||
$$ = new HandlerNode($ID, $idlist, $stmtlist); }
|
||||
;
|
||||
|
||||
endargdef: /* nothing */
|
||||
| ID { delete $ID; }
|
||||
| endargdef ',' ID { delete $ID; }
|
||||
;
|
||||
|
||||
// GENERIC VAR STUFF
|
||||
|
||||
// This is only the identifiers that can appaear at the start of a line
|
||||
// and will not conflict with other statement types.
|
||||
CMDID: tVARID
|
||||
| tABBREVIATED { $$ = new Common::String("abbreviated"); }
|
||||
| tABBREV { $$ = new Common::String("abbrev"); }
|
||||
| tABBR { $$ = new Common::String("abbr"); }
|
||||
| tAFTER { $$ = new Common::String("after"); }
|
||||
| tBEFORE { $$ = new Common::String("before"); }
|
||||
| tCAST { $$ = new Common::String("cast"); }
|
||||
| tCASTLIB { $$ = new Common::String("castLib"); }
|
||||
| tCHAR { $$ = new Common::String("char"); }
|
||||
| tCHARS { $$ = new Common::String("chars"); }
|
||||
| tDATE { $$ = new Common::String("date"); }
|
||||
| tDELETE { $$ = new Common::String("delete"); }
|
||||
| tDOWN { $$ = new Common::String("down"); }
|
||||
| tFIELD { $$ = new Common::String("field"); }
|
||||
| tFRAME { $$ = new Common::String("frame"); }
|
||||
| tHILITE { $$ = new Common::String("hilite"); }
|
||||
| tIN { $$ = new Common::String("in"); }
|
||||
| tINTERSECTS { $$ = new Common::String("intersects"); }
|
||||
| tINTO { $$ = new Common::String("into"); }
|
||||
| tITEM { $$ = new Common::String("item"); }
|
||||
| tITEMS { $$ = new Common::String("items"); }
|
||||
| tLAST { $$ = new Common::String("last"); }
|
||||
| tLINE { $$ = new Common::String("line"); }
|
||||
| tLINES { $$ = new Common::String("lines"); }
|
||||
| tLONG { $$ = new Common::String("long"); }
|
||||
| tMEMBER { $$ = new Common::String("member"); }
|
||||
| tMENU { $$ = new Common::String("menu"); }
|
||||
| tMENUITEM { $$ = new Common::String("menuItem"); }
|
||||
| tMENUITEMS { $$ = new Common::String("menuItems"); }
|
||||
| tMOVIE { $$ = new Common::String("movie"); }
|
||||
| tNEXT { $$ = new Common::String("next"); }
|
||||
| tNUMBER { $$ = new Common::String("number"); }
|
||||
| tOF { $$ = new Common::String("of"); }
|
||||
| tPREVIOUS { $$ = new Common::String("previous"); }
|
||||
| tREPEAT { $$ = new Common::String("repeat"); }
|
||||
| tSCRIPT { $$ = new Common::String("script"); }
|
||||
| tASSERTERROR { $$ = new Common::String("scummvmAssertError"); }
|
||||
| tSHORT { $$ = new Common::String("short"); }
|
||||
| tSOUND { $$ = new Common::String("sound"); }
|
||||
| tSPRITE { $$ = new Common::String("sprite"); }
|
||||
| tTHE { $$ = new Common::String("the"); }
|
||||
| tTIME { $$ = new Common::String("time"); }
|
||||
| tTO { $$ = new Common::String("to"); }
|
||||
| tWHILE { $$ = new Common::String("while"); }
|
||||
| tWINDOW { $$ = new Common::String("window"); }
|
||||
| tWITH { $$ = new Common::String("with"); }
|
||||
| tWITHIN { $$ = new Common::String("within"); }
|
||||
| tWORD { $$ = new Common::String("word"); }
|
||||
| tWORDS { $$ = new Common::String("words"); }
|
||||
;
|
||||
|
||||
ID: CMDID
|
||||
| tELSE { $$ = new Common::String("else"); }
|
||||
| tENDCLAUSE { $$ = new Common::String("end"); delete $tENDCLAUSE; }
|
||||
| tEXIT { $$ = new Common::String("exit"); }
|
||||
| tFACTORY { $$ = new Common::String("factory"); }
|
||||
| tGLOBAL { $$ = new Common::String("global"); }
|
||||
| tGO { $$ = new Common::String("go"); }
|
||||
| tIF { $$ = new Common::String("if"); }
|
||||
| tINSTANCE { $$ = new Common::String("instance"); }
|
||||
| tMACRO { $$ = new Common::String("macro"); }
|
||||
| tMETHOD { $$ = new Common::String("method"); }
|
||||
| tON { $$ = new Common::String("on"); }
|
||||
| tOPEN { $$ = new Common::String("open"); }
|
||||
| tPLAY { $$ = new Common::String("play"); }
|
||||
| tPROPERTY { $$ = new Common::String("property"); }
|
||||
| tPUT { $$ = new Common::String("put"); }
|
||||
| tRETURN { $$ = new Common::String("return"); }
|
||||
| tSET { $$ = new Common::String("set"); }
|
||||
| tTELL { $$ = new Common::String("tell"); }
|
||||
| tTHEN { $$ = new Common::String("then"); }
|
||||
;
|
||||
|
||||
idlist: /* empty */ { $$ = new IDList; }
|
||||
| nonemptyidlist
|
||||
| nonemptyidlist ',' // allow trailing comma
|
||||
;
|
||||
|
||||
nonemptyidlist: ID[item] {
|
||||
Common::Array<Common::String *> *list = new IDList;
|
||||
list->push_back($item);
|
||||
$$ = list; }
|
||||
| nonemptyidlist[prev] ',' ID[item] {
|
||||
$prev->push_back($item);
|
||||
$$ = $prev; }
|
||||
;
|
||||
|
||||
// STATEMENT
|
||||
// N.B. A statement must always be terminated by a '\n' symbol.
|
||||
// Sometimes this '\n' is in a nested statement (e.g. tIF expr tTHEN stmt).
|
||||
// It may not look like there's a '\n', but it's there.
|
||||
|
||||
stmt: stmt_insideif
|
||||
| tENDIF '\n' { $$ = nullptr; } // stray `end if`s are allowed for some reason
|
||||
;
|
||||
|
||||
stmt_insideif: stmtoneliner
|
||||
| ifstmt
|
||||
| ifelsestmt
|
||||
| loop
|
||||
| tell
|
||||
| when
|
||||
;
|
||||
|
||||
stmtoneliner: proc
|
||||
| asgn
|
||||
| definevars
|
||||
;
|
||||
|
||||
proc: CMDID cmdargs '\n' { $$ = new CmdNode($CMDID, $cmdargs, g_lingo->_compiler->_linenumber - 1); }
|
||||
| tPUT cmdargs '\n' { $$ = new CmdNode(new Common::String("put"), $cmdargs, g_lingo->_compiler->_linenumber - 1); }
|
||||
| tGO cmdargs '\n' { $$ = new CmdNode(new Common::String("go"), $cmdargs, g_lingo->_compiler->_linenumber - 1); }
|
||||
| tGO frameargs '\n' { $$ = new CmdNode(new Common::String("go"), $frameargs, g_lingo->_compiler->_linenumber - 1); }
|
||||
| tPLAY cmdargs '\n' { $$ = new CmdNode(new Common::String("play"), $cmdargs, g_lingo->_compiler->_linenumber - 1); }
|
||||
| tPLAY frameargs '\n' { $$ = new CmdNode(new Common::String("play"), $frameargs, g_lingo->_compiler->_linenumber - 1); }
|
||||
| tOPEN cmdargs '\n' { $$ = new CmdNode(new Common::String("open"), $cmdargs, g_lingo->_compiler->_linenumber - 1); }
|
||||
| tOPEN expr[arg1] tWITH expr[arg2] '\n' {
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($arg1);
|
||||
args->push_back($arg2);
|
||||
$$ = new CmdNode(new Common::String("open"), args, g_lingo->_compiler->_linenumber - 1); }
|
||||
| tNEXT tREPEAT '\n' { $$ = new NextRepeatNode(); }
|
||||
| tEXIT tREPEAT '\n' { $$ = new ExitRepeatNode(); }
|
||||
| tEXIT '\n' { $$ = new ExitNode(); }
|
||||
| tRETURN '\n' { $$ = new ReturnNode(nullptr); }
|
||||
| tRETURN expr '\n' { $$ = new ReturnNode($expr); }
|
||||
| tDELETE chunk '\n' { $$ = new DeleteNode($chunk); }
|
||||
| tHILITE chunk '\n' { $$ = new HiliteNode($chunk); }
|
||||
| tASSERTERROR stmtoneliner { $$ = new AssertErrorNode($stmtoneliner); }
|
||||
;
|
||||
|
||||
cmdargs: /* empty */ {
|
||||
// This matches `cmd`
|
||||
$$ = new NodeList; }
|
||||
| expr trailingcomma {
|
||||
// This matches `cmd arg` and `cmd(arg)`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($expr);
|
||||
$$ = args; }
|
||||
| expr ',' nonemptyexprlist[args] trailingcomma {
|
||||
// This matches `cmd arg, ...)
|
||||
$args->insert_at(0, $expr);
|
||||
$$ = $args; }
|
||||
| expr expr_nounarymath trailingcomma {
|
||||
// This matches `cmd arg arg`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($expr);
|
||||
args->push_back($expr_nounarymath);
|
||||
$$ = args; }
|
||||
| expr expr_nounarymath ',' nonemptyexprlist[args] trailingcomma {
|
||||
// This matches `cmd arg arg, ...`
|
||||
$args->insert_at(0, $expr_nounarymath);
|
||||
$args->insert_at(0, $expr);
|
||||
$$ = $args; }
|
||||
| '(' ')' {
|
||||
// This matches `cmd()`
|
||||
$$ = new NodeList; }
|
||||
| '(' expr ',' ')' {
|
||||
// This matches `cmd(arg,)`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($expr);
|
||||
$$ = args; }
|
||||
| '(' expr ',' nonemptyexprlist[args] trailingcomma ')' {
|
||||
// This matches `cmd(arg, ...)`
|
||||
$args->insert_at(0, $expr);
|
||||
$$ = $args; }
|
||||
| '(' var[method] expr_nounarymath trailingcomma ')' {
|
||||
// This matches `obj(method arg)`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($method);
|
||||
args->push_back($expr_nounarymath);
|
||||
$$ = args; }
|
||||
| '(' var[method] expr_nounarymath ',' nonemptyexprlist[args] trailingcomma ')' {
|
||||
// This matches `obj(method arg, ...)`
|
||||
$args->insert_at(0, $expr_nounarymath);
|
||||
$args->insert_at(0, $method);
|
||||
$$ = $args; }
|
||||
;
|
||||
|
||||
trailingcomma: /* empty */ | ',' ;
|
||||
|
||||
frameargs:
|
||||
// On the off chance that we encounter something like `play frame done`
|
||||
// we will wrap the frame arg in a FrameNode. This has no purpose other than
|
||||
// to avoid detecting this case as `play done`.
|
||||
tFRAME expr[frame] {
|
||||
// This matches `play frame arg`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back(new FrameNode($frame));
|
||||
$$ = args; }
|
||||
| tMOVIE expr[movie] {
|
||||
// This matches `play movie arg`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back(new IntNode(1));
|
||||
args->push_back(new MovieNode($movie));
|
||||
$$ = args; }
|
||||
| tFRAME expr[frame] tOF tMOVIE expr[movie] {
|
||||
// This matches `play frame arg of movie arg`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back(new FrameNode($frame));
|
||||
args->push_back(new MovieNode($movie));
|
||||
$$ = args; }
|
||||
| expr[frame] tOF tMOVIE expr[movie] {
|
||||
// This matches `play arg of movie arg` (weird but valid)
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($frame);
|
||||
args->push_back(new MovieNode($movie));
|
||||
$$ = args; }
|
||||
| tFRAME expr[frame] expr_nounarymath[movie] {
|
||||
// This matches `play frame arg arg` (also weird but valid)
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back(new FrameNode($frame));
|
||||
args->push_back($movie);
|
||||
$$ = args; }
|
||||
;
|
||||
|
||||
asgn: tPUT expr tINTO varorchunk '\n' { $$ = new PutIntoNode($expr, $varorchunk); }
|
||||
| tPUT expr tAFTER varorchunk '\n' { $$ = new PutAfterNode($expr, $varorchunk); }
|
||||
| tPUT expr tBEFORE varorchunk '\n' { $$ = new PutBeforeNode($expr, $varorchunk); }
|
||||
| tSET varorthe to expr '\n' { $$ = new SetNode($varorthe, $expr); }
|
||||
;
|
||||
|
||||
to: tTO | tEQ ;
|
||||
|
||||
definevars: tGLOBAL idlist '\n' { $$ = new GlobalNode($idlist); }
|
||||
| tPROPERTY idlist '\n' { $$ = new PropertyNode($idlist); }
|
||||
| tINSTANCE idlist '\n' { $$ = new InstanceNode($idlist); }
|
||||
;
|
||||
|
||||
ifstmt: tIF expr tTHEN stmt {
|
||||
NodeList *stmtlist = new NodeList;
|
||||
stmtlist->push_back($stmt);
|
||||
$$ = new IfStmtNode($expr, stmtlist); }
|
||||
| tIF expr tTHEN '\n' stmtlist_insideif endif {
|
||||
$$ = new IfStmtNode($expr, $stmtlist_insideif); }
|
||||
;
|
||||
|
||||
ifelsestmt: tIF expr tTHEN stmt[stmt1] tELSE stmt[stmt2] {
|
||||
NodeList *stmtlist1 = new NodeList;
|
||||
stmtlist1->push_back($stmt1);
|
||||
NodeList *stmtlist2 = new NodeList;
|
||||
stmtlist2->push_back($stmt2);
|
||||
$$ = new IfElseStmtNode($expr, stmtlist1, stmtlist2); }
|
||||
| tIF expr tTHEN stmt[stmt1] tELSE '\n' stmtlist_insideif[stmtlist2] endif {
|
||||
NodeList *stmtlist1 = new NodeList;
|
||||
stmtlist1->push_back($stmt1);
|
||||
$$ = new IfElseStmtNode($expr, stmtlist1, $stmtlist2); }
|
||||
| tIF expr tTHEN '\n' stmtlist_insideif[stmtlist1] tELSE stmt[stmt2] {
|
||||
NodeList *stmtlist2 = new NodeList;
|
||||
stmtlist2->push_back($stmt2);
|
||||
$$ = new IfElseStmtNode($expr, $stmtlist1, stmtlist2); }
|
||||
| tIF expr tTHEN '\n' stmtlist_insideif[stmtlist1] tELSE '\n' stmtlist_insideif[stmtlist2] endif {
|
||||
$$ = new IfElseStmtNode($expr, $stmtlist1, $stmtlist2); }
|
||||
;
|
||||
|
||||
endif: /* empty */ {
|
||||
LingoCompiler *compiler = g_lingo->_compiler;
|
||||
warning("LingoCompiler::parse: no end if at line %d col %d in %s id: %d",
|
||||
compiler->_linenumber, compiler->_colnumber, scriptType2str(compiler->_assemblyContext->_scriptType),
|
||||
compiler->_assemblyContext->_id);
|
||||
|
||||
}
|
||||
| tENDIF '\n' ;
|
||||
|
||||
loop: tREPEAT tWHILE expr '\n' stmtlist tENDREPEAT '\n' {
|
||||
$$ = new RepeatWhileNode($expr, $stmtlist); }
|
||||
| tREPEAT tWITH ID tEQ expr[start] tTO expr[end] '\n' stmtlist tENDREPEAT '\n' {
|
||||
$$ = new RepeatWithToNode($ID, $start, false, $end, $stmtlist); }
|
||||
| tREPEAT tWITH ID tEQ expr[start] tDOWN tTO expr[end] '\n' stmtlist tENDREPEAT '\n' {
|
||||
$$ = new RepeatWithToNode($ID, $start, true, $end, $stmtlist); }
|
||||
| tREPEAT tWITH ID tIN expr '\n' stmtlist tENDREPEAT '\n' {
|
||||
$$ = new RepeatWithInNode($ID, $expr, $stmtlist); }
|
||||
;
|
||||
|
||||
tell: tTELL expr tTO stmtoneliner {
|
||||
NodeList *stmtlist = new NodeList;
|
||||
stmtlist->push_back($stmtoneliner);
|
||||
$$ = new TellNode($expr, stmtlist); }
|
||||
| tTELL expr '\n' stmtlist tENDTELL '\n' {
|
||||
$$ = new TellNode($expr, $stmtlist); }
|
||||
;
|
||||
|
||||
when: tWHEN '\n' { $$ = new WhenNode($tWHEN.eventName, $tWHEN.stmt); } ;
|
||||
|
||||
stmtlist: /* empty */ { $$ = new NodeList; }
|
||||
| nonemptystmtlist
|
||||
;
|
||||
|
||||
nonemptystmtlist:
|
||||
stmtlistline[item] {
|
||||
NodeList *list = new NodeList;
|
||||
if ($item) {
|
||||
list->push_back($item);
|
||||
}
|
||||
$$ = list; }
|
||||
| nonemptystmtlist[prev] stmtlistline[item] {
|
||||
if ($item) {
|
||||
$prev->push_back($item);
|
||||
}
|
||||
$$ = $prev; }
|
||||
;
|
||||
|
||||
stmtlistline: '\n' { $$ = nullptr; }
|
||||
| stmt
|
||||
;
|
||||
|
||||
stmtlist_insideif: /* empty */ { $$ = new NodeList; }
|
||||
| nonemptystmtlist_insideif
|
||||
;
|
||||
|
||||
nonemptystmtlist_insideif:
|
||||
stmtlistline_insideif[item] {
|
||||
NodeList *list = new NodeList;
|
||||
if ($item) {
|
||||
list->push_back($item);
|
||||
}
|
||||
$$ = list; }
|
||||
| nonemptystmtlist_insideif[prev] stmtlistline_insideif[item] {
|
||||
if ($item) {
|
||||
$prev->push_back($item);
|
||||
}
|
||||
$$ = $prev; }
|
||||
;
|
||||
|
||||
stmtlistline_insideif: '\n' { $$ = nullptr; }
|
||||
| stmt_insideif
|
||||
;
|
||||
|
||||
// EXPRESSION
|
||||
|
||||
simpleexpr_nounarymath:
|
||||
tINT { $$ = new IntNode($tINT); }
|
||||
| tFLOAT { $$ = new FloatNode($tFLOAT); }
|
||||
| tSYMBOL { $$ = new SymbolNode($tSYMBOL); } // D3
|
||||
| tSTRING { $$ = new StringNode($tSTRING); }
|
||||
| tNOT simpleexpr[arg] %prec tUNARY { $$ = new UnaryOpNode(LC::c_not, $arg); }
|
||||
| ID '(' ')' { $$ = new FuncNode($ID, new NodeList); }
|
||||
| ID '(' nonemptyexprlist[args] trailingcomma ')' { $$ = new FuncNode($ID, $args); }
|
||||
| ID '(' var[method] expr_nounarymath trailingcomma ')' {
|
||||
// This matches `obj(method arg)`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($method);
|
||||
args->push_back($expr_nounarymath);
|
||||
$$ = new FuncNode($ID, args); }
|
||||
| ID '(' var[method] expr_nounarymath ',' nonemptyexprlist[args] trailingcomma ')' {
|
||||
// This matches `obj(method arg, ...)`
|
||||
$args->insert_at(0, $expr_nounarymath);
|
||||
$args->insert_at(0, $method);
|
||||
$$ = new FuncNode($ID, $args); }
|
||||
| '(' expr ')' { $$ = $expr; } ;
|
||||
| var
|
||||
| chunk
|
||||
| object
|
||||
| the
|
||||
| list
|
||||
;
|
||||
|
||||
var: ID { $$ = new VarNode($ID); } ;
|
||||
|
||||
varorchunk: var
|
||||
| chunk
|
||||
;
|
||||
|
||||
varorthe: var
|
||||
| writablethe
|
||||
;
|
||||
|
||||
chunk: tFIELD refargs { $$ = new FuncNode(new Common::String("field"), $refargs); }
|
||||
| tCAST refargs { $$ = new FuncNode(new Common::String("cast"), $refargs); }
|
||||
| tMEMBER refargs { $$ = new FuncNode(new Common::String("member"), $refargs); }
|
||||
| tCASTLIB refargs { $$ = new FuncNode(new Common::String("castLib"), $refargs); }
|
||||
| tCHAR expr[idx] tOF simpleexpr[src] {
|
||||
$$ = new ChunkExprNode(kChunkChar, $idx, nullptr, $src); }
|
||||
| tCHAR expr[start] tTO expr[end] tOF simpleexpr[src] {
|
||||
$$ = new ChunkExprNode(kChunkChar, $start, $end, $src); }
|
||||
| tWORD expr[idx] tOF simpleexpr[src] {
|
||||
$$ = new ChunkExprNode(kChunkWord, $idx, nullptr, $src); }
|
||||
| tWORD expr[start] tTO expr[end] tOF simpleexpr[src] {
|
||||
$$ = new ChunkExprNode(kChunkWord, $start, $end, $src); }
|
||||
| tITEM expr[idx] tOF simpleexpr[src] {
|
||||
$$ = new ChunkExprNode(kChunkItem, $idx, nullptr, $src); }
|
||||
| tITEM expr[start] tTO expr[end] tOF simpleexpr[src] {
|
||||
$$ = new ChunkExprNode(kChunkItem, $start, $end, $src); }
|
||||
| tLINE expr[idx] tOF simpleexpr[src] {
|
||||
$$ = new ChunkExprNode(kChunkLine, $idx, nullptr, $src); }
|
||||
| tLINE expr[start] tTO expr[end] tOF simpleexpr[src] {
|
||||
$$ = new ChunkExprNode(kChunkLine, $start, $end, $src); }
|
||||
| tTHE tLAST chunktype inof simpleexpr { $$ = new TheLastNode($chunktype, $simpleexpr); }
|
||||
;
|
||||
|
||||
chunktype: tCHAR { $$ = kChunkChar; }
|
||||
| tWORD { $$ = kChunkWord; }
|
||||
| tITEM { $$ = kChunkItem; }
|
||||
| tLINE { $$ = kChunkLine; }
|
||||
;
|
||||
|
||||
object: tSCRIPT refargs { $$ = new FuncNode(new Common::String("script"), $refargs); }
|
||||
| tWINDOW refargs { $$ = new FuncNode(new Common::String("window"), $refargs); }
|
||||
;
|
||||
|
||||
refargs: simpleexpr {
|
||||
// This matches `ref arg` and `ref(arg)`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($simpleexpr);
|
||||
$$ = args; }
|
||||
| '(' ')' {
|
||||
// This matches `ref()`
|
||||
$$ = new NodeList; }
|
||||
| '(' expr ',' ')' {
|
||||
// This matches `ref(arg,)`
|
||||
NodeList *args = new NodeList;
|
||||
args->push_back($expr);
|
||||
$$ = args; }
|
||||
| '(' expr ',' nonemptyexprlist[args] trailingcomma ')' {
|
||||
// This matches `ref(arg, ...)`
|
||||
$args->insert_at(0, $expr);
|
||||
$$ = $args; }
|
||||
;
|
||||
|
||||
the: tTHE ID { $$ = new TheNode($ID); }
|
||||
| tTHE ID tOF theobj { $$ = new TheOfNode($ID, $theobj); }
|
||||
| tTHE tNUMBER tOF theobj { $$ = new TheOfNode(new Common::String("number"), $theobj); }
|
||||
| thedatetime
|
||||
| thenumberof
|
||||
;
|
||||
|
||||
theobj: simpleexpr
|
||||
| menu
|
||||
| tMENUITEM simpleexpr[item] tOF tMENU simpleexpr[menu] { $$ = new MenuItemNode($item, $menu); }
|
||||
| tSOUND simpleexpr[arg] { $$ = new SoundNode($arg); }
|
||||
| tSPRITE simpleexpr[arg] { $$ = new SpriteNode($arg); }
|
||||
;
|
||||
|
||||
menu: tMENU simpleexpr[arg] { $$ = new MenuNode($arg); } ;
|
||||
|
||||
thedatetime: tTHE tABBREVIATED tDATE { $$ = new TheDateTimeNode(kTheAbbr, kTheDate); }
|
||||
| tTHE tABBREVIATED tTIME { $$ = new TheDateTimeNode(kTheAbbr, kTheTime); }
|
||||
| tTHE tABBREV tDATE { $$ = new TheDateTimeNode(kTheAbbr, kTheDate); }
|
||||
| tTHE tABBREV tTIME { $$ = new TheDateTimeNode(kTheAbbr, kTheTime); }
|
||||
| tTHE tABBR tDATE { $$ = new TheDateTimeNode(kTheAbbr, kTheDate); }
|
||||
| tTHE tABBR tTIME { $$ = new TheDateTimeNode(kTheAbbr, kTheTime); }
|
||||
| tTHE tLONG tDATE { $$ = new TheDateTimeNode(kTheLong, kTheDate); }
|
||||
| tTHE tLONG tTIME { $$ = new TheDateTimeNode(kTheLong, kTheTime); }
|
||||
| tTHE tSHORT tDATE { $$ = new TheDateTimeNode(kTheShort, kTheDate); }
|
||||
| tTHE tSHORT tTIME { $$ = new TheDateTimeNode(kTheShort, kTheTime); }
|
||||
;
|
||||
|
||||
thenumberof:
|
||||
tTHE tNUMBER tOF tCHARS inof simpleexpr { $$ = new TheNumberOfNode(kNumberOfChars, $simpleexpr); }
|
||||
| tTHE tNUMBER tOF tWORDS inof simpleexpr { $$ = new TheNumberOfNode(kNumberOfWords, $simpleexpr); }
|
||||
| tTHE tNUMBER tOF tITEMS inof simpleexpr { $$ = new TheNumberOfNode(kNumberOfItems, $simpleexpr); }
|
||||
| tTHE tNUMBER tOF tLINES inof simpleexpr { $$ = new TheNumberOfNode(kNumberOfLines, $simpleexpr); }
|
||||
| tTHE tNUMBER tOF tMENUITEMS inof menu { $$ = new TheNumberOfNode(kNumberOfMenuItems, $menu); }
|
||||
| tTHE tNUMBER tOF tMENUS { $$ = new TheNumberOfNode(kNumberOfMenus, nullptr); }
|
||||
| tTHE tNUMBER tOF tXTRAS { $$ = new TheNumberOfNode(kNumberOfXtras, nullptr); } // D5
|
||||
| tTHE tNUMBER tOF tCASTLIBS { $$ = new TheNumberOfNode(kNumberOfCastlibs, nullptr); } // D5
|
||||
;
|
||||
|
||||
inof: tIN | tOF ;
|
||||
|
||||
writablethe: tTHE ID { $$ = new TheNode($ID); }
|
||||
| tTHE ID tOF writabletheobj { $$ = new TheOfNode($ID, $writabletheobj); }
|
||||
;
|
||||
|
||||
writabletheobj: simpleexpr
|
||||
| tMENU expr_noeq[arg] { $$ = new MenuNode($arg); } ;
|
||||
| tMENUITEM expr_noeq[item] tOF tMENU expr_noeq[menu] { $$ = new MenuItemNode($item, $menu); }
|
||||
| tSOUND expr_noeq[arg] { $$ = new SoundNode($arg); }
|
||||
| tSPRITE expr_noeq[arg] { $$ = new SpriteNode($arg); }
|
||||
;
|
||||
|
||||
list: '[' exprlist ']' { $$ = new ListNode($exprlist); }
|
||||
| '[' ':' ']' { $$ = new PropListNode(new NodeList); }
|
||||
| '[' proplist ']' { $$ = new PropListNode($proplist); }
|
||||
;
|
||||
|
||||
// A property list must start with a proppair, but it may be followed by
|
||||
// keyless expressions, which will be compiled as equivalent to the
|
||||
// proppair <index>: <expr>.
|
||||
proplist: proppair[item] {
|
||||
NodeList *list = new NodeList;
|
||||
list->push_back($item);
|
||||
$$ = list; }
|
||||
| proplist[prev] ',' proppair[item] {
|
||||
$prev->push_back($item);
|
||||
$$ = $prev; }
|
||||
| proplist[prev] ',' expr[item] {
|
||||
$prev->push_back($item);
|
||||
$$ = $prev; }
|
||||
;
|
||||
|
||||
proppair: tSYMBOL ':' expr { $$ = new PropPairNode(new SymbolNode($tSYMBOL), $expr); }
|
||||
| ID ':' expr { $$ = new PropPairNode(new SymbolNode($ID), $expr); }
|
||||
| tSTRING ':' expr { $$ = new PropPairNode(new StringNode($tSTRING), $expr); }
|
||||
| tINT ':' expr { $$ = new PropPairNode(new IntNode($tINT), $expr); }
|
||||
| tFLOAT ':' expr { $$ = new PropPairNode(new FloatNode($tFLOAT), $expr); }
|
||||
;
|
||||
|
||||
unarymath: '+' simpleexpr[arg] %prec tUNARY { $$ = $arg; }
|
||||
| '-' simpleexpr[arg] %prec tUNARY { $$ = new UnaryOpNode(LC::c_negate, $arg); }
|
||||
;
|
||||
|
||||
simpleexpr: simpleexpr_nounarymath
|
||||
| unarymath
|
||||
;
|
||||
|
||||
// REMEMBER TO SYNC THIS WITH expr_nounarymath and expr_noeq!
|
||||
expr: simpleexpr
|
||||
| sprite
|
||||
| expr[a] '+' expr[b] { $$ = new BinaryOpNode(LC::c_add, $a, $b); }
|
||||
| expr[a] '-' expr[b] { $$ = new BinaryOpNode(LC::c_sub, $a, $b); }
|
||||
| expr[a] '*' expr[b] { $$ = new BinaryOpNode(LC::c_mul, $a, $b); }
|
||||
| expr[a] '/' expr[b] { $$ = new BinaryOpNode(LC::c_div, $a, $b); }
|
||||
| expr[a] tMOD expr[b] { $$ = new BinaryOpNode(LC::c_mod, $a, $b); }
|
||||
| expr[a] '>' expr[b] { $$ = new BinaryOpNode(LC::c_gt, $a, $b); }
|
||||
| expr[a] '<' expr[b] { $$ = new BinaryOpNode(LC::c_lt, $a, $b); }
|
||||
| expr[a] tEQ expr[b] { $$ = new BinaryOpNode(LC::c_eq, $a, $b); }
|
||||
| expr[a] tNEQ expr[b] { $$ = new BinaryOpNode(LC::c_neq, $a, $b); }
|
||||
| expr[a] tGE expr[b] { $$ = new BinaryOpNode(LC::c_ge, $a, $b); }
|
||||
| expr[a] tLE expr[b] { $$ = new BinaryOpNode(LC::c_le, $a, $b); }
|
||||
| expr[a] tAND expr[b] { $$ = new BinaryOpNode(LC::c_and, $a, $b); }
|
||||
| expr[a] tOR expr[b] { $$ = new BinaryOpNode(LC::c_or, $a, $b); }
|
||||
| expr[a] '&' expr[b] { $$ = new BinaryOpNode(LC::c_ampersand, $a, $b); }
|
||||
| expr[a] tCONCAT expr[b] { $$ = new BinaryOpNode(LC::c_concat, $a, $b); }
|
||||
| expr[a] tCONTAINS expr[b] { $$ = new BinaryOpNode(LC::c_contains, $a, $b); }
|
||||
| expr[a] tSTARTS expr[b] { $$ = new BinaryOpNode(LC::c_starts, $a, $b); }
|
||||
;
|
||||
|
||||
// This is the same as expr except it can't start with a unary math operator.
|
||||
// It's ugly but unfortunately necessary to allow two expressions in a row with no delimeter.
|
||||
// Without this, `cmd 1 + 1` could be interpreted as either `cmd(1 + 1)` or `cmd(1, +1)`.
|
||||
// We only want to allow the first interpretation, so we must exclude unary math from the second expression.
|
||||
expr_nounarymath: simpleexpr_nounarymath
|
||||
| sprite
|
||||
| expr_nounarymath[a] '+' expr[b] { $$ = new BinaryOpNode(LC::c_add, $a, $b); }
|
||||
| expr_nounarymath[a] '-' expr[b] { $$ = new BinaryOpNode(LC::c_sub, $a, $b); }
|
||||
| expr_nounarymath[a] '*' expr[b] { $$ = new BinaryOpNode(LC::c_mul, $a, $b); }
|
||||
| expr_nounarymath[a] '/' expr[b] { $$ = new BinaryOpNode(LC::c_div, $a, $b); }
|
||||
| expr_nounarymath[a] tMOD expr[b] { $$ = new BinaryOpNode(LC::c_mod, $a, $b); }
|
||||
| expr_nounarymath[a] '>' expr[b] { $$ = new BinaryOpNode(LC::c_gt, $a, $b); }
|
||||
| expr_nounarymath[a] '<' expr[b] { $$ = new BinaryOpNode(LC::c_lt, $a, $b); }
|
||||
| expr_nounarymath[a] tEQ expr[b] { $$ = new BinaryOpNode(LC::c_eq, $a, $b); }
|
||||
| expr_nounarymath[a] tNEQ expr[b] { $$ = new BinaryOpNode(LC::c_neq, $a, $b); }
|
||||
| expr_nounarymath[a] tGE expr[b] { $$ = new BinaryOpNode(LC::c_ge, $a, $b); }
|
||||
| expr_nounarymath[a] tLE expr[b] { $$ = new BinaryOpNode(LC::c_le, $a, $b); }
|
||||
| expr_nounarymath[a] tAND expr[b] { $$ = new BinaryOpNode(LC::c_and, $a, $b); }
|
||||
| expr_nounarymath[a] tOR expr[b] { $$ = new BinaryOpNode(LC::c_or, $a, $b); }
|
||||
| expr_nounarymath[a] '&' expr[b] { $$ = new BinaryOpNode(LC::c_ampersand, $a, $b); }
|
||||
| expr_nounarymath[a] tCONCAT expr[b] { $$ = new BinaryOpNode(LC::c_concat, $a, $b); }
|
||||
| expr_nounarymath[a] tCONTAINS expr[b] { $$ = new BinaryOpNode(LC::c_contains, $a, $b); }
|
||||
| expr_nounarymath[a] tSTARTS expr[b] { $$ = new BinaryOpNode(LC::c_starts, $a, $b); }
|
||||
;
|
||||
|
||||
expr_noeq: simpleexpr
|
||||
| sprite
|
||||
| expr_noeq[a] '+' expr_noeq[b] { $$ = new BinaryOpNode(LC::c_add, $a, $b); }
|
||||
| expr_noeq[a] '-' expr_noeq[b] { $$ = new BinaryOpNode(LC::c_sub, $a, $b); }
|
||||
| expr_noeq[a] '*' expr_noeq[b] { $$ = new BinaryOpNode(LC::c_mul, $a, $b); }
|
||||
| expr_noeq[a] '/' expr_noeq[b] { $$ = new BinaryOpNode(LC::c_div, $a, $b); }
|
||||
| expr_noeq[a] tMOD expr_noeq[b] { $$ = new BinaryOpNode(LC::c_mod, $a, $b); }
|
||||
| expr_noeq[a] '>' expr_noeq[b] { $$ = new BinaryOpNode(LC::c_gt, $a, $b); }
|
||||
| expr_noeq[a] '<' expr_noeq[b] { $$ = new BinaryOpNode(LC::c_lt, $a, $b); }
|
||||
| expr_noeq[a] tNEQ expr_noeq[b] { $$ = new BinaryOpNode(LC::c_neq, $a, $b); }
|
||||
| expr_noeq[a] tGE expr_noeq[b] { $$ = new BinaryOpNode(LC::c_ge, $a, $b); }
|
||||
| expr_noeq[a] tLE expr_noeq[b] { $$ = new BinaryOpNode(LC::c_le, $a, $b); }
|
||||
| expr_noeq[a] tAND expr_noeq[b] { $$ = new BinaryOpNode(LC::c_and, $a, $b); }
|
||||
| expr_noeq[a] tOR expr_noeq[b] { $$ = new BinaryOpNode(LC::c_or, $a, $b); }
|
||||
| expr_noeq[a] '&' expr_noeq[b] { $$ = new BinaryOpNode(LC::c_ampersand, $a, $b); }
|
||||
| expr_noeq[a] tCONCAT expr_noeq[b] { $$ = new BinaryOpNode(LC::c_concat, $a, $b); }
|
||||
| expr_noeq[a] tCONTAINS expr_noeq[b] { $$ = new BinaryOpNode(LC::c_contains, $a, $b); }
|
||||
| expr_noeq[a] tSTARTS expr_noeq[b] { $$ = new BinaryOpNode(LC::c_starts, $a, $b); }
|
||||
;
|
||||
|
||||
sprite: tSPRITE expr tINTERSECTS simpleexpr { $$ = new IntersectsNode($expr, $simpleexpr); }
|
||||
| tSPRITE expr tWITHIN simpleexpr { $$ = new WithinNode($expr, $simpleexpr); }
|
||||
;
|
||||
|
||||
exprlist: /* empty */ { $$ = new NodeList; }
|
||||
| nonemptyexprlist
|
||||
;
|
||||
|
||||
nonemptyexprlist: expr[item] {
|
||||
NodeList *list = new NodeList;
|
||||
list->push_back($item);
|
||||
$$ = list; }
|
||||
| nonemptyexprlist[prev] ',' expr[item] {
|
||||
$prev->push_back($item);
|
||||
$$ = $prev; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
int yyreport_syntax_error(const yypcontext_t *ctx) {
|
||||
int res = 0;
|
||||
|
||||
Common::String msg = "syntax error, ";
|
||||
|
||||
// Report the unexpected token.
|
||||
yysymbol_kind_t lookahead = yypcontext_token(ctx);
|
||||
if (lookahead != YYSYMBOL_YYEMPTY)
|
||||
msg += Common::String::format("unexpected %s", yysymbol_name(lookahead));
|
||||
|
||||
// Report the tokens expected at this point.
|
||||
enum { TOKENMAX = 10 };
|
||||
yysymbol_kind_t expected[TOKENMAX];
|
||||
|
||||
int n = yypcontext_expected_tokens(ctx, expected, TOKENMAX);
|
||||
if (n < 0)
|
||||
// Forward errors to yyparse.
|
||||
res = n;
|
||||
else
|
||||
for (int i = 0; i < n; ++i)
|
||||
msg += Common::String::format("%s %s", i == 0 ? ": expected" : " or", yysymbol_name(expected[i]));
|
||||
|
||||
yyerror(msg.c_str());
|
||||
|
||||
return res;
|
||||
}
|
||||
2686
engines/director/lingo/lingo-lex.cpp
Normal file
2686
engines/director/lingo/lingo-lex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
335
engines/director/lingo/lingo-lex.l
Normal file
335
engines/director/lingo/lingo-lex.l
Normal file
@@ -0,0 +1,335 @@
|
||||
%top{
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define YY_NO_UNISTD_H
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fwrite
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fread
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdin
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getc
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-ast.h"
|
||||
#include "director/lingo/lingo-codegen.h"
|
||||
#include "director/lingo/lingo-gr.h"
|
||||
#include "director/lingo/lingo-the.h"
|
||||
|
||||
using namespace Director;
|
||||
|
||||
static const char *inputbuffer;
|
||||
static uint inputlen;
|
||||
|
||||
}
|
||||
|
||||
%option noyywrap
|
||||
%option noinput
|
||||
%option nounput
|
||||
%option never-interactive
|
||||
%option case-insensitive
|
||||
|
||||
%option outfile="engines/director/lingo/lingo-lex.cpp"
|
||||
|
||||
%{
|
||||
|
||||
// Push lines in stack
|
||||
static void pushLine(uint num) {
|
||||
LingoCompiler *compiler = g_lingo->_compiler;
|
||||
|
||||
if (num > inputlen)
|
||||
return;
|
||||
|
||||
compiler->_lines[2] = compiler->_lines[1];
|
||||
compiler->_lines[1] = compiler->_lines[0];
|
||||
compiler->_lines[0] = &inputbuffer[num];
|
||||
}
|
||||
|
||||
static void count() {
|
||||
LingoCompiler *compiler = g_lingo->_compiler;
|
||||
|
||||
if (debugChannelSet(-1, kDebugParse))
|
||||
debug("LEXER: Read '%s' at %d:%d", yytext, compiler->_linenumber, compiler->_colnumber);
|
||||
|
||||
char *p = yytext;
|
||||
|
||||
while (*p) {
|
||||
if (*p == '\n') {
|
||||
compiler->_linenumber++;
|
||||
compiler->_colnumber = 0;
|
||||
pushLine(compiler->_bytenumber + 1);
|
||||
} else if (*p == '\xC2' && *(p + 1) == '\xAC') { // continuation
|
||||
compiler->_linenumber++;
|
||||
compiler->_colnumber = 0;
|
||||
} else {
|
||||
compiler->_colnumber++;
|
||||
}
|
||||
p++;
|
||||
compiler->_bytenumber++;
|
||||
}
|
||||
}
|
||||
|
||||
static Common::String *cleanupString(const char *s) {
|
||||
Common::String *res = new Common::String;
|
||||
|
||||
while (*s) {
|
||||
if (*s == '\xC2' && *(s + 1) == '\xAC') { // continuation
|
||||
s += 2;
|
||||
*res += ' '; // replace with space
|
||||
continue;
|
||||
}
|
||||
*res += *s;
|
||||
s++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void skipWhitespace(const char **ptr) {
|
||||
while (true) {
|
||||
if (**ptr == ' ' || **ptr == '\t') {
|
||||
*ptr += 1;
|
||||
} else if (**ptr == '\xC2' && *(*ptr + 1) == '\xAC') { // continuation
|
||||
*ptr += 2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Common::String *readUntilWhitespace(const char **ptr) {
|
||||
Common::String *res = new Common::String;
|
||||
|
||||
while (true) {
|
||||
if (**ptr == ' ' || **ptr == '\t') {
|
||||
break;
|
||||
}
|
||||
if (**ptr == '\xC2' && *(*ptr + 1) == '\xAC') { // continuation
|
||||
break;
|
||||
}
|
||||
*res += **ptr;
|
||||
*ptr += 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static Common::String *readUntilNewline(const char **ptr) {
|
||||
Common::String *res = new Common::String;
|
||||
|
||||
while ((**ptr != '\n') && (**ptr != '\r') && (**ptr != '\0')) {
|
||||
if (**ptr == '\xC2' && *(*ptr + 1) == '\xAC') { // continuation
|
||||
*ptr += 2;
|
||||
*res += ' '; // replace with space
|
||||
continue;
|
||||
}
|
||||
*res += **ptr;
|
||||
*ptr += 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
identifier [_[:alpha:]][_\.[:alnum:]]*
|
||||
constfloat [[:digit:]]+\.[[:digit:]]*
|
||||
constinteger [[:digit:]]+
|
||||
conststring \"[^\"\r\n]*\"
|
||||
operator [-+*/%^:,()><&\[\]]
|
||||
newline (" "|\t|\xC2\xAC)*[\n\r]
|
||||
spc (" "|\t|\xC2\xAC)
|
||||
eventname (keyDown|keyUp|mouseDown|mouseUp|timeOut)
|
||||
unparsedstmt [^\r\n]*
|
||||
|
||||
%%
|
||||
|
||||
{spc}+ { count(); }
|
||||
|
||||
[#]{identifier} { count(); yylval.s = new Common::String(yytext + 1); return tSYMBOL; } // D3, skip '#'
|
||||
|
||||
abbreviated { count(); return tABBREVIATED; }
|
||||
abbrev { count(); return tABBREV; }
|
||||
abbr { count(); return tABBR; }
|
||||
after { count(); return tAFTER; } // D3
|
||||
and { count(); return tAND; }
|
||||
before { count(); return tBEFORE; } // D3
|
||||
cast { count(); return tCAST; }
|
||||
castlib { count(); return tCASTLIB; } // D5
|
||||
castlibs { count(); return tCASTLIBS; } // D5
|
||||
char { count(); return tCHAR; } // D3
|
||||
chars { count(); return tCHARS; }
|
||||
contains { count(); return tCONTAINS; }
|
||||
date { count(); return tDATE; }
|
||||
delete { count(); return tDELETE; }
|
||||
down { count(); return tDOWN; }
|
||||
else { count(); return tELSE; }
|
||||
end({spc}+{identifier})? {
|
||||
count();
|
||||
|
||||
const char *ptr = &yytext[3]; // Skip 'end '
|
||||
skipWhitespace(&ptr);
|
||||
|
||||
if (!scumm_stricmp(ptr, "if"))
|
||||
return tENDIF;
|
||||
else if (!scumm_stricmp(ptr, "repeat"))
|
||||
return tENDREPEAT;
|
||||
else if (!scumm_stricmp(ptr, "tell"))
|
||||
return tENDTELL;
|
||||
|
||||
yylval.s = new Common::String(ptr);
|
||||
|
||||
return tENDCLAUSE;
|
||||
}
|
||||
exit { count(); return tEXIT; }
|
||||
^{spc}*factory { count(); return tFACTORY; }
|
||||
field { count(); return tFIELD; }
|
||||
frame { count(); return tFRAME; }
|
||||
global { count(); return tGLOBAL; }
|
||||
go({spc}+to)? { count(); return tGO; }
|
||||
hilite { count(); return tHILITE; }
|
||||
if { count(); return tIF; }
|
||||
instance { count(); return tINSTANCE; }
|
||||
intersects { count(); return tINTERSECTS;}
|
||||
into { count(); return tINTO; }
|
||||
in { count(); return tIN; }
|
||||
item { count(); return tITEM; }
|
||||
items { count(); return tITEMS; }
|
||||
last { count(); return tLAST; }
|
||||
line { count(); return tLINE; }
|
||||
lines { count(); return tLINES; }
|
||||
long { count(); return tLONG; }
|
||||
macro { count(); return tMACRO; }
|
||||
member { count(); return tMEMBER; }
|
||||
menu { count(); return tMENU; }
|
||||
menus { count(); return tMENUS; }
|
||||
menuItem { count(); return tMENUITEM;}
|
||||
menuItems { count(); return tMENUITEMS; }
|
||||
method { count(); return tMETHOD; }
|
||||
mod { count(); return tMOD;}
|
||||
movie { count(); return tMOVIE; }
|
||||
next { count(); return tNEXT; }
|
||||
not { count(); return tNOT; }
|
||||
number { count(); return tNUMBER; }
|
||||
of { count(); return tOF; }
|
||||
on { count(); return tON; } // D3
|
||||
open { count(); return tOPEN; }
|
||||
or { count(); return tOR; }
|
||||
play { count(); return tPLAY; }
|
||||
previous { count(); return tPREVIOUS; }
|
||||
property { count(); return tPROPERTY; } // D4
|
||||
put { count(); return tPUT; }
|
||||
repeat { count(); return tREPEAT; }
|
||||
return { count(); return tRETURN; }
|
||||
script { count(); return tSCRIPT; }
|
||||
scummvmAssertError { count(); return tASSERTERROR; }
|
||||
set { count(); return tSET; }
|
||||
short { count(); return tSHORT; }
|
||||
sound { count(); return tSOUND; }
|
||||
sprite { count(); return tSPRITE; }
|
||||
starts { count(); return tSTARTS; }
|
||||
tell { count(); return tTELL; }
|
||||
the { count(); return tTHE; }
|
||||
then { count(); return tTHEN; }
|
||||
time { count(); return tTIME; }
|
||||
to { count(); return tTO; }
|
||||
when{spc}+{eventname}{spc}+then{spc}*{unparsedstmt} {
|
||||
count();
|
||||
|
||||
const char *ptr = &yytext[5]; // Skip 'when '
|
||||
skipWhitespace(&ptr);
|
||||
|
||||
Common::String *eventName = readUntilWhitespace(&ptr);
|
||||
|
||||
skipWhitespace(&ptr);
|
||||
ptr += 4; // Skip 'then'
|
||||
skipWhitespace(&ptr);
|
||||
|
||||
Common::String *stmt = readUntilNewline(&ptr);
|
||||
|
||||
yylval.w.eventName = eventName;
|
||||
yylval.w.stmt = stmt;
|
||||
return tWHEN;
|
||||
}
|
||||
while { count(); return tWHILE; }
|
||||
window { count(); return tWINDOW; }
|
||||
with { count(); return tWITH; }
|
||||
within { count(); return tWITHIN; }
|
||||
word { count(); return tWORD; }
|
||||
words { count(); return tWORDS; }
|
||||
xtras { count(); return tXTRAS; } // D5
|
||||
|
||||
[<][>] { count(); return tNEQ; }
|
||||
[>][=] { count(); return tGE; }
|
||||
[<][=] { count(); return tLE; }
|
||||
[&][&] { count(); return tCONCAT; }
|
||||
[=] { count(); return tEQ; }
|
||||
|
||||
{identifier} {
|
||||
count();
|
||||
yylval.s = new Common::String(yytext);
|
||||
|
||||
return tVARID;
|
||||
}
|
||||
{constfloat} { count(); yylval.f = atof(yytext); return tFLOAT; }
|
||||
{constinteger} { count(); yylval.i = strtol(yytext, NULL, 10); return tINT; }
|
||||
{operator} { count(); return *yytext; }
|
||||
{newline} { count(); return '\n'; }
|
||||
{conststring} { count(); yylval.s = cleanupString(&yytext[1]); yylval.s->deleteLastChar(); return tSTRING; }
|
||||
. { count(); }
|
||||
|
||||
%%
|
||||
|
||||
extern int yydebug;
|
||||
|
||||
namespace Director {
|
||||
|
||||
int LingoCompiler::parse(const char *code) {
|
||||
inputbuffer = code;
|
||||
_bytenumber = 0;
|
||||
inputlen = strlen(code);
|
||||
|
||||
_lines[0] = _lines[1] = _lines[2] = code;
|
||||
|
||||
YY_BUFFER_STATE bp;
|
||||
|
||||
if (debugChannelSet(-1, kDebugParse))
|
||||
yydebug = 1;
|
||||
else
|
||||
yydebug = 0;
|
||||
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
|
||||
bp = yy_scan_string(code);
|
||||
yy_switch_to_buffer(bp);
|
||||
yyparse();
|
||||
yy_delete_buffer(bp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
482
engines/director/lingo/lingo-mci.cpp
Normal file
482
engines/director/lingo/lingo-mci.cpp
Normal file
@@ -0,0 +1,482 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The MCI documentation is: https://learn.microsoft.com/en-us/windows/win32/multimedia/mci
|
||||
* Based on sources from Wine: https://github.com/wine-mirror/wine/blob/master/dlls/winmm/mci.c
|
||||
* Table structure and algorithms also described in: https://patentimages.storage.googleapis.com/ad/06/7a/48766ca9df6fbc/US6397263.pdf
|
||||
*/
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/wave.h"
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/score.h"
|
||||
#include "director/sound.h"
|
||||
#include "director/window.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
enum MCITokenType {
|
||||
MCI_PLAY,
|
||||
MCI_OPEN,
|
||||
MCI_CLOSE,
|
||||
MCI_STATUS,
|
||||
MCI_RECORD,
|
||||
MCI_SEEK,
|
||||
MCI_STOP,
|
||||
MCI_PAUSE,
|
||||
MCI_GETDEVCAPS,
|
||||
MCI_SYSINFO,
|
||||
MCI_BREAK,
|
||||
MCI_SOUND,
|
||||
MCI_SAVE,
|
||||
MCI_LOAD,
|
||||
MCI_RESUME,
|
||||
MCI_SET,
|
||||
MCI_INFO,
|
||||
};
|
||||
|
||||
|
||||
enum MCIDataType {
|
||||
MCI_COMMAND_HEAD,
|
||||
MCI_END_COMMAND,
|
||||
MCI_END_COMMAND_LIST,
|
||||
MCI_CONSTANT,
|
||||
MCI_END_CONSTANT,
|
||||
MCI_RETURN,
|
||||
|
||||
MCI_FLAG,
|
||||
MCI_INTEGER,
|
||||
MCI_STRING,
|
||||
MCI_RECT,
|
||||
MCI_DWORD_PTR,
|
||||
};
|
||||
|
||||
typedef struct MCITokenData {
|
||||
MCIDataType type;
|
||||
Common::String string;
|
||||
int integer = 0;
|
||||
} MCITokenData;
|
||||
|
||||
typedef struct MCICommand {
|
||||
MCITokenType id;
|
||||
uint flags = 0;
|
||||
Common::String device; /* MCI device name */
|
||||
Common::HashMap<Common::String, MCITokenData> parameters;
|
||||
} MCICommand;
|
||||
|
||||
enum MCIError {
|
||||
MCIERR_NO_ERROR,
|
||||
MCIERR_UNRECOGNISED_COMMAND,
|
||||
MCIERR_STRING_PARSE,
|
||||
};
|
||||
|
||||
struct CmdTableRow {
|
||||
const char *keystr;
|
||||
int flag;
|
||||
int num;
|
||||
MCIDataType data_type;
|
||||
};
|
||||
|
||||
static const CmdTableRow table[] = {
|
||||
{"open" ,MCI_OPEN ,0 ,MCI_COMMAND_HEAD },
|
||||
{"" ,MCI_INTEGER ,0 ,MCI_RETURN } ,
|
||||
{"notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{"wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{"type" ,0x00002000L ,-1 ,MCI_STRING } ,
|
||||
{"element" ,0x00000200L ,-1 ,MCI_STRING } ,
|
||||
{"alias" ,0x00000400L ,-1 ,MCI_STRING } ,
|
||||
{"shareable" ,0x00000100L ,-1 ,MCI_FLAG } ,
|
||||
{"" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{"close" ,MCI_CLOSE ,0 ,MCI_COMMAND_HEAD },
|
||||
{"notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{"wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{"" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{"play" ,MCI_PLAY ,0 ,MCI_COMMAND_HEAD },
|
||||
{"notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{"wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{"from" ,0x00000004L ,-1 ,MCI_INTEGER } ,
|
||||
{"to" ,0x00000008L ,-1 ,MCI_INTEGER } ,
|
||||
{"" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{"status" ,MCI_STATUS ,0 ,MCI_COMMAND_HEAD },
|
||||
{"" ,MCI_DWORD_PTR ,0 ,MCI_RETURN } ,
|
||||
{"notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{"wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{"" ,0x00000100L ,-1 ,MCI_CONSTANT } ,
|
||||
{"position" ,0x00000002L ,-1 ,MCI_INTEGER } ,
|
||||
{"length" ,0x00000001L ,-1 ,MCI_INTEGER } ,
|
||||
{"number of tracks",-1 ,0x00000003L,MCI_INTEGER } ,
|
||||
{"ready" ,0x00000007L ,-1 ,MCI_INTEGER } ,
|
||||
{"mode" ,0x00000004L ,-1 ,MCI_INTEGER } ,
|
||||
{"time format" ,-1 ,0x00000006L,MCI_INTEGER } ,
|
||||
{"current track" ,-1 ,0x00000008L,MCI_INTEGER } ,
|
||||
{"" ,0x00000000L ,-1 ,MCI_END_CONSTANT },
|
||||
{ "track" ,0x00000010L ,-1 ,MCI_INTEGER } ,
|
||||
{ "start" ,0x00000200L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "record" ,MCI_RECORD ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "from" ,0x00000004L ,-1 ,MCI_INTEGER } ,
|
||||
{ "to" ,0x00000008L ,-1 ,MCI_INTEGER } ,
|
||||
{ "insert" ,0x00000100L ,-1 ,MCI_FLAG } ,
|
||||
{ "overwrite" ,0x00000200L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "seek" ,MCI_SEEK ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "to start" ,0x00000100L ,-1 ,MCI_FLAG } ,
|
||||
{ "to end" ,0x00000200L ,-1 ,MCI_FLAG } ,
|
||||
{ "to" ,0x00000008L ,-1 ,MCI_INTEGER } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "stop" ,MCI_STOP ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "pause" ,MCI_PAUSE ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "capability" ,MCI_GETDEVCAPS,0 ,MCI_COMMAND_HEAD },
|
||||
{ "" ,MCI_INTEGER ,0 ,MCI_RETURN } ,
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000100L ,-1 ,MCI_CONSTANT } ,
|
||||
{ "can record" ,0x00000001L ,-1 ,MCI_INTEGER } ,
|
||||
{ "has audio" ,0x00000002L ,-1 ,MCI_INTEGER } ,
|
||||
{ "has video" ,0x00000003L ,-1 ,MCI_INTEGER } ,
|
||||
{ "uses files" ,0x00000005L ,-1 ,MCI_INTEGER } ,
|
||||
{ "compound device",0x00000006L ,-1 ,MCI_INTEGER } ,
|
||||
{ "device type" ,0x00000004L ,-1 ,MCI_INTEGER } ,
|
||||
{ "can eject" ,0x00000007L ,-1 ,MCI_INTEGER } ,
|
||||
{ "can play" ,0x00000008L ,-1 ,MCI_INTEGER } ,
|
||||
{ "can save" ,0x00000009L ,-1 ,MCI_INTEGER } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_CONSTANT },
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "info" ,MCI_INFO ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "" ,MCI_STRING ,0 ,MCI_RETURN } ,
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "product" ,0x00000100L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "set" ,MCI_SET ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "time format" ,0x00000400L ,-1 ,MCI_CONSTANT } ,
|
||||
{ "milliseconds" ,0x00000000L ,-1 ,MCI_INTEGER } ,
|
||||
{ "ms" ,0x00000000L ,-1 ,MCI_INTEGER } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_CONSTANT },
|
||||
{ "door open" ,0x00000100L ,-1 ,MCI_FLAG } ,
|
||||
{ "door closed" ,0x00000200L ,-1 ,MCI_FLAG } ,
|
||||
{ "audio" ,0x00000800L ,-1 ,MCI_CONSTANT } ,
|
||||
{ "all" ,0x00000000L ,-1 ,MCI_INTEGER } ,
|
||||
{ "left" ,0x00000001L ,-1 ,MCI_INTEGER } ,
|
||||
{ "right" ,0x00000002L ,-1 ,MCI_INTEGER } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_CONSTANT },
|
||||
{ "video" ,0x00001000L ,-1 ,MCI_FLAG } ,
|
||||
{ "on" ,0x00002000L ,-1 ,MCI_FLAG } ,
|
||||
{ "off" ,0x00004000L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "sysinfo" ,MCI_SYSINFO ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "" ,MCI_STRING ,0 ,MCI_RETURN } ,
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "quantity" ,0x00000100L ,-1 ,MCI_FLAG } ,
|
||||
{ "open" ,0x00000200L ,-1 ,MCI_FLAG } ,
|
||||
{ "installname" ,0x00000800L ,-1 ,MCI_FLAG } ,
|
||||
{ "name" ,0x00000400L ,-1 ,MCI_INTEGER } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "break" ,MCI_BREAK ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "on" ,0x00000100L ,-1 ,MCI_INTEGER } ,
|
||||
{ "off" ,0x00000400L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "sound" ,MCI_SOUND ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "save" ,MCI_SAVE ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000100L ,-1 ,MCI_STRING } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "load" ,MCI_LOAD ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000100L ,-1 ,MCI_STRING } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
|
||||
{ "resume" ,MCI_RESUME ,0 ,MCI_COMMAND_HEAD },
|
||||
{ "notify" ,0x00000001L ,-1 ,MCI_FLAG } ,
|
||||
{ "wait" ,0x00000002L ,-1 ,MCI_FLAG } ,
|
||||
{ "" ,0x00000000L ,-1 ,MCI_END_COMMAND } ,
|
||||
};
|
||||
|
||||
static MCIError getString(const Common::String &name, uint &idx, Common::String &str) {
|
||||
uint i_end;
|
||||
|
||||
if (name[idx] == '"' || name[idx] == '\'') { /* Quoted string */
|
||||
char quote = name[idx];
|
||||
i_end = name.findFirstOf(quote, idx + 1);
|
||||
if (i_end == Common::String::npos) {
|
||||
return MCIERR_STRING_PARSE; /* Unterminated string */
|
||||
}
|
||||
str = name.substr(idx + 1, i_end - idx - 1);
|
||||
idx = i_end + 2;
|
||||
} else { /* No quotes, so just find the next space */
|
||||
i_end = name.findFirstOf(' ', idx);
|
||||
if (i_end == Common::String::npos) {
|
||||
i_end = name.size();
|
||||
}
|
||||
|
||||
str = name.substr(idx, i_end - idx);
|
||||
idx = i_end + 1;
|
||||
}
|
||||
|
||||
debugC(5, kDebugLingoExec, "get_string(): Got string \"%s\"", str.c_str());
|
||||
return MCIERR_NO_ERROR;
|
||||
}
|
||||
|
||||
static void createTokenList(Common::StringArray &tokenList, const Common::String &name) {
|
||||
uint idx = 0;
|
||||
|
||||
while (idx < name.size()) {
|
||||
Common::String str;
|
||||
MCIError err = getString(name, idx, str);
|
||||
|
||||
if (err != MCIERR_NO_ERROR) {
|
||||
break;
|
||||
}
|
||||
tokenList.push_back(str);
|
||||
}
|
||||
}
|
||||
|
||||
static MCIError parseMCICommand(const Common::String &name, MCICommand &parsedCmd) {
|
||||
Common::StringArray token_list;
|
||||
createTokenList(token_list, name);
|
||||
|
||||
uint i_token = 0;
|
||||
int i_table = 0;
|
||||
int tableStart = -1, tableEnd = -1;
|
||||
|
||||
Common::String &verb = token_list[0];
|
||||
|
||||
/* Find the table section corresponding to the command's verb. */
|
||||
for (auto& cmd : table) {
|
||||
if ((tableStart < 0) && (cmd.data_type == MCI_COMMAND_HEAD) && (cmd.keystr == verb)) {
|
||||
tableStart = i_table;
|
||||
} else if ((tableStart >= 0) && (cmd.data_type == MCI_END_COMMAND)) {
|
||||
tableEnd = i_table;
|
||||
break;
|
||||
}
|
||||
i_table++;
|
||||
}
|
||||
|
||||
debugC(5, kDebugLingoExec, "parseMCICommand(): tableStart: %d, tableEnd: %d", tableStart, tableEnd);
|
||||
if (tableStart == -1 || tableEnd == -1) {
|
||||
warning("parseMCICommand(): Verb %s not found in table", verb.c_str());
|
||||
return MCIERR_UNRECOGNISED_COMMAND;
|
||||
}
|
||||
|
||||
auto cmd = table[tableStart];
|
||||
parsedCmd.id = (MCITokenType)cmd.flag;
|
||||
parsedCmd.flags = cmd.num;
|
||||
|
||||
/* The MCI device will ALWAYS be the second token. */
|
||||
parsedCmd.device = token_list[1];
|
||||
|
||||
/* Parse the rest of the arguments */
|
||||
i_token = 2;
|
||||
|
||||
while (i_token < token_list.size()) {
|
||||
bool found = false;
|
||||
bool inConst = false;
|
||||
int flag, cflag = 0;
|
||||
const CmdTableRow *cmdtable, *c_cmdtable = nullptr;
|
||||
auto& token = token_list[i_token];
|
||||
|
||||
for (i_table = tableStart; i_table < tableEnd; i_table++) {
|
||||
MCIDataType cmd_type = table[i_table].data_type;
|
||||
flag = table[i_table].flag;
|
||||
cmdtable = &table[i_table];
|
||||
|
||||
switch (cmd_type) {
|
||||
case MCI_CONSTANT:
|
||||
c_cmdtable = cmdtable;
|
||||
inConst = true;
|
||||
cflag = flag;
|
||||
break;
|
||||
|
||||
case MCI_END_CONSTANT:
|
||||
c_cmdtable = nullptr;
|
||||
inConst = false;
|
||||
cflag = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (token != table[i_table].keystr)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
|
||||
switch (cmd_type) {
|
||||
case MCI_COMMAND_HEAD:
|
||||
case MCI_RETURN:
|
||||
case MCI_END_COMMAND:
|
||||
case MCI_END_COMMAND_LIST:
|
||||
case MCI_CONSTANT:
|
||||
case MCI_END_CONSTANT:
|
||||
break;
|
||||
|
||||
case MCI_FLAG:
|
||||
parsedCmd.flags |= flag;
|
||||
i_token++;
|
||||
break;
|
||||
|
||||
case MCI_INTEGER: {
|
||||
if (inConst) { /* Handle the case where we've hit a MCI_INTEGER which is inside a MCI_CONSTANT block. */
|
||||
MCITokenData token_data;
|
||||
if (parsedCmd.parameters.tryGetVal(c_cmdtable->keystr, token_data)) {
|
||||
token_data.integer |= flag;
|
||||
} else {
|
||||
token_data.type = MCI_CONSTANT;
|
||||
token_data.integer |= flag;
|
||||
parsedCmd.parameters[c_cmdtable->keystr] = token_data;
|
||||
}
|
||||
parsedCmd.flags |= cflag;
|
||||
inConst = false;
|
||||
} else {
|
||||
parsedCmd.flags |= flag;
|
||||
|
||||
MCITokenData token_data;
|
||||
token_data.type = MCI_INTEGER;
|
||||
token_data.integer = atoi(token_list[++i_token].c_str());
|
||||
parsedCmd.parameters[token] = token_data;
|
||||
}
|
||||
i_token++;
|
||||
break;
|
||||
}
|
||||
|
||||
case MCI_STRING: {
|
||||
parsedCmd.flags |= flag;
|
||||
|
||||
MCITokenData token_data;
|
||||
token_data.type = MCI_STRING;
|
||||
token_data.string = token_list[++i_token];
|
||||
parsedCmd.parameters[token] = token_data;
|
||||
i_token++;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
warning("parseMCICommand(): Unhandled command type %d", cmd_type);
|
||||
return MCIERR_UNRECOGNISED_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
warning("parseMCICommand(): Parameter %s not found in table", token_list[i_token].c_str());
|
||||
return MCIERR_UNRECOGNISED_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
return MCIERR_NO_ERROR;
|
||||
}
|
||||
|
||||
void Lingo::func_mci(const Common::String &name) {
|
||||
|
||||
MCICommand parsedCmd;
|
||||
parseMCICommand(name, parsedCmd);
|
||||
|
||||
switch (parsedCmd.id) {
|
||||
case MCI_OPEN: {
|
||||
Common::File *file = new Common::File();
|
||||
|
||||
if (!file->open(Common::Path(parsedCmd.device, g_director->_dirSeparator))) {
|
||||
warning("func_mci(): Failed to open %s", parsedCmd.device.c_str());
|
||||
delete file;
|
||||
return;
|
||||
}
|
||||
|
||||
parsedCmd.parameters["type"].string.toLowercase(); /* In the case the open command type has something like WaveAudio instead of waveaudio */
|
||||
|
||||
if (parsedCmd.parameters["type"].string == "waveaudio") {
|
||||
Audio::AudioStream *sound = Audio::makeWAVStream(file, DisposeAfterUse::YES);
|
||||
if (parsedCmd.parameters.contains("alias")) {
|
||||
_audioAliases[parsedCmd.parameters["alias"].string] = sound;
|
||||
} else {
|
||||
delete sound;
|
||||
}
|
||||
} else {
|
||||
warning("func_mci(): Unhandled audio type %s", parsedCmd.parameters["type"].string.c_str());
|
||||
delete file;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MCI_PLAY: {
|
||||
warning("func_mci(): MCI play file: %s, from: %d, to: %d", parsedCmd.device.c_str(), parsedCmd.parameters["from"].integer, parsedCmd.parameters["to"].integer);
|
||||
|
||||
if (!_audioAliases.contains(parsedCmd.device)) {
|
||||
warning("func_mci(): Unknown alias %s", parsedCmd.device.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 from = parsedCmd.parameters["from"].integer;
|
||||
uint32 to = parsedCmd.parameters.contains("to") ? parsedCmd.parameters["to"].integer : -1;
|
||||
|
||||
_vm->getCurrentWindow()->getSoundManager()->playMCI(*_audioAliases[parsedCmd.device], from, to);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("func_mci: Unhandled MCI command: %d", parsedCmd.id); /* TODO: Convert MCITokenType into string */
|
||||
}
|
||||
}
|
||||
|
||||
void Lingo::func_mciwait(const Common::String &name) {
|
||||
warning("STUB: MCI wait file: %s", name.c_str());
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
995
engines/director/lingo/lingo-object.cpp
Normal file
995
engines/director/lingo/lingo-object.cpp
Normal file
@@ -0,0 +1,995 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
#include "graphics/macgui/mactext.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/movie.h"
|
||||
#include "director/window.h"
|
||||
#include "director/lingo/lingo-ast.h"
|
||||
#include "director/lingo/lingo-code.h"
|
||||
#include "director/lingo/lingo-the.h"
|
||||
|
||||
#include "director/lingo/xlibs/a/aiff.h"
|
||||
#include "director/lingo/xlibs/a/applecdxobj.h"
|
||||
#include "director/lingo/xlibs/a/askuser.h"
|
||||
#include "director/lingo/xlibs/b/backdrop.h"
|
||||
#include "director/lingo/xlibs/b/barakeobj.h"
|
||||
#include "director/lingo/xlibs/b/batqt.h"
|
||||
#include "director/lingo/xlibs/b/bimxobj.h"
|
||||
#include "director/lingo/xlibs/b/blitpict.h"
|
||||
#include "director/lingo/xlibs/b/blockthedrawingxobj.h"
|
||||
#include "director/lingo/xlibs/c/cdromxobj.h"
|
||||
#include "director/lingo/xlibs/c/closebleedwindowxcmd.h"
|
||||
#include "director/lingo/xlibs/c/colorxobj.h"
|
||||
#include "director/lingo/xlibs/c/colorcursorxobj.h"
|
||||
#include "director/lingo/xlibs/c/consumer.h"
|
||||
#include "director/lingo/xlibs/c/cursorxobj.h"
|
||||
#include "director/lingo/xlibs/d/darkenscreen.h"
|
||||
#include "director/lingo/xlibs/d/dateutil.h"
|
||||
#include "director/lingo/xlibs/d/developerStack.h"
|
||||
#include "director/lingo/xlibs/d/dialogsxobj.h"
|
||||
#include "director/lingo/xlibs/d/dirutil.h"
|
||||
#include "director/lingo/xlibs/d/dllglue.h"
|
||||
#include "director/lingo/xlibs/d/dpwavi.h"
|
||||
#include "director/lingo/xlibs/d/dpwqtw.h"
|
||||
#include "director/lingo/xlibs/d/draw.h"
|
||||
#include "director/lingo/xlibs/e/ednox.h"
|
||||
#include "director/lingo/xlibs/e/eventq.h"
|
||||
#include "director/lingo/xlibs/f/fadegammadownxcmd.h"
|
||||
#include "director/lingo/xlibs/f/fadegammaupxcmd.h"
|
||||
#include "director/lingo/xlibs/f/fadegammaxcmd.h"
|
||||
#include "director/lingo/xlibs/f/fedracul.h"
|
||||
#include "director/lingo/xlibs/f/feimasks.h"
|
||||
#include "director/lingo/xlibs/f/feiprefs.h"
|
||||
#include "director/lingo/xlibs/f/fileexists.h"
|
||||
#include "director/lingo/xlibs/f/fileio.h"
|
||||
#include "director/lingo/xlibs/f/findereventsxcmd.h"
|
||||
#include "director/lingo/xlibs/f/findfolder.h"
|
||||
#include "director/lingo/xlibs/f/findsys.h"
|
||||
#include "director/lingo/xlibs/f/findwin.h"
|
||||
#include "director/lingo/xlibs/f/flushxobj.h"
|
||||
#include "director/lingo/xlibs/f/fplayxobj.h"
|
||||
#include "director/lingo/xlibs/f/fsutil.h"
|
||||
#include "director/lingo/xlibs/g/genutils.h"
|
||||
#include "director/lingo/xlibs/g/getscreenrectsxfcn.h"
|
||||
#include "director/lingo/xlibs/g/getscreensizexfcn.h"
|
||||
#include "director/lingo/xlibs/g/getsoundinlevel.h"
|
||||
#include "director/lingo/xlibs/g/gpid.h"
|
||||
#include "director/lingo/xlibs/h/henry.h"
|
||||
#include "director/lingo/xlibs/h/hitmap.h"
|
||||
#include "director/lingo/xlibs/i/inixobj.h"
|
||||
#include "director/lingo/xlibs/i/instobj.h"
|
||||
#include "director/lingo/xlibs/j/jwxini.h"
|
||||
#include "director/lingo/xlibs/i/iscd.h"
|
||||
#include "director/lingo/xlibs/i/ispippin.h"
|
||||
#include "director/lingo/xlibs/j/jitdraw3.h"
|
||||
#include "director/lingo/xlibs/l/labeldrvxobj.h"
|
||||
#include "director/lingo/xlibs/l/listdev.h"
|
||||
#include "director/lingo/xlibs/m/maniacbg.h"
|
||||
#include "director/lingo/xlibs/m/mapnavigatorxobj.h"
|
||||
#include "director/lingo/xlibs/m/memcheckxobj.h"
|
||||
#include "director/lingo/xlibs/m/memoryxobj.h"
|
||||
#include "director/lingo/xlibs/m/misc.h"
|
||||
#include "director/lingo/xlibs/m/miscx.h"
|
||||
#include "director/lingo/xlibs/m/mmaskxobj.h"
|
||||
#include "director/lingo/xlibs/m/mmovie.h"
|
||||
#include "director/lingo/xlibs/m/moovxobj.h"
|
||||
#include "director/lingo/xlibs/m/movemousejp.h"
|
||||
#include "director/lingo/xlibs/m/movemousexobj.h"
|
||||
#include "director/lingo/xlibs/m/movieidxxobj.h"
|
||||
#include "director/lingo/xlibs/m/movutils.h"
|
||||
#include "director/lingo/xlibs/m/msfile.h"
|
||||
#include "director/lingo/xlibs/m/mystisle.h"
|
||||
#include "director/lingo/xlibs/m/mazexobj.h"
|
||||
#include "director/lingo/xlibs/o/openbleedwindowxcmd.h"
|
||||
#include "director/lingo/xlibs/o/orthoplayxobj.h"
|
||||
#include "director/lingo/xlibs/p/paco.h"
|
||||
#include "director/lingo/xlibs/p/palxobj.h"
|
||||
#include "director/lingo/xlibs/p/panel.h"
|
||||
#include "director/lingo/xlibs/p/pharaohs.h"
|
||||
#include "director/lingo/xlibs/p/popupmenuxobj.h"
|
||||
#include "director/lingo/xlibs/p/porta.h"
|
||||
#include "director/lingo/xlibs/p/prefpath.h"
|
||||
#include "director/lingo/xlibs/p/printomatic.h"
|
||||
#include "director/lingo/xlibs/p/processxobj.h"
|
||||
#include "director/lingo/xlibs/p/putcurs.h"
|
||||
#include "director/lingo/xlibs/p/playsoundmoviexobj.h"
|
||||
#include "director/lingo/xlibs/q/qtmovie.h"
|
||||
#include "director/lingo/xlibs/q/qtcatmovieplayerxobj.h"
|
||||
#include "director/lingo/xlibs/q/qtvr.h"
|
||||
#include "director/lingo/xlibs/q/quicktime.h"
|
||||
#include "director/lingo/xlibs/r/registercomponent.h"
|
||||
#include "director/lingo/xlibs/r/remixxcmd.h"
|
||||
#include "director/lingo/xlibs/s/serialportxobj.h"
|
||||
#include "director/lingo/xlibs/s/smallutil.h"
|
||||
#include "director/lingo/xlibs/s/soundjam.h"
|
||||
#include "director/lingo/xlibs/s/spacemgr.h"
|
||||
#include "director/lingo/xlibs/s/stagetc.h"
|
||||
#include "director/lingo/xlibs/s/syscolor.h"
|
||||
#include "director/lingo/xlibs/s/savenrestorexobj.h"
|
||||
#include "director/lingo/xlibs/t/tengu.h"
|
||||
#include "director/lingo/xlibs/t/temnotaxobj.h"
|
||||
#include "director/lingo/xlibs/u/unittest.h"
|
||||
#include "director/lingo/xlibs/v/valkyrie.h"
|
||||
#include "director/lingo/xlibs/v/versions.h"
|
||||
#include "director/lingo/xlibs/v/videodiscxobj.h"
|
||||
#include "director/lingo/xlibs/v/vmisonxfcn.h"
|
||||
#include "director/lingo/xlibs/v/vmpresent.h"
|
||||
#include "director/lingo/xlibs/v/volumelist.h"
|
||||
#include "director/lingo/xlibs/v/voyagerxsound.h"
|
||||
#include "director/lingo/xlibs/w/widgetxobj.h"
|
||||
#include "director/lingo/xlibs/w/window.h"
|
||||
#include "director/lingo/xlibs/w/wininfo.h"
|
||||
#include "director/lingo/xlibs/w/winxobj.h"
|
||||
#include "director/lingo/xlibs/x/xcmdglue.h"
|
||||
#include "director/lingo/xlibs/x/xio.h"
|
||||
#include "director/lingo/xlibs/x/xplayanim.h"
|
||||
#include "director/lingo/xlibs/x/xplaypacoxfcn.h"
|
||||
#include "director/lingo/xlibs/x/xsoundxfcn.h"
|
||||
#include "director/lingo/xlibs/x/xwin.h"
|
||||
#include "director/lingo/xlibs/y/yasix.h"
|
||||
#include "director/lingo/xtras/a/audio.h"
|
||||
#include "director/lingo/xtras/b/budapi.h"
|
||||
#include "director/lingo/xtras/directsound.h"
|
||||
#include "director/lingo/xtras/d/displayres.h"
|
||||
#include "director/lingo/xtras/filextra.h"
|
||||
#include "director/lingo/xtras/keypoll.h"
|
||||
#include "director/lingo/xtras/masterapp.h"
|
||||
#include "director/lingo/xtras/m/mui.h"
|
||||
#include "director/lingo/xtras/m/mui.h"
|
||||
#include "director/lingo/xtras/openurl.h"
|
||||
#include "director/lingo/xtras/oscheck.h"
|
||||
#include "director/lingo/xtras/qtvrxtra.h"
|
||||
#include "director/lingo/xtras/r/registryreader.h"
|
||||
#include "director/lingo/xtras/rtk.h"
|
||||
#include "director/lingo/xtras/scrnutil.h"
|
||||
#include "director/lingo/xtras/s/smacker.h"
|
||||
#include "director/lingo/xtras/s/staytoonedhall.h"
|
||||
#include "director/lingo/xtras/s/staytoonedball.h"
|
||||
#include "director/lingo/xtras/s/staytoonedglop.h"
|
||||
#include "director/lingo/xtras/s/staytoonedhigh.h"
|
||||
#include "director/lingo/xtras/s/staytoonedober.h"
|
||||
#include "director/lingo/xtras/s/staytoonedtoon.h"
|
||||
#include "director/lingo/xtras/timextra.h"
|
||||
#include "director/lingo/xtras/xsound.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
static const struct PredefinedProto {
|
||||
const char *name;
|
||||
void (*func)(int);
|
||||
int minArgs; // -1 -- arglist
|
||||
int maxArgs;
|
||||
int type;
|
||||
int version;
|
||||
} predefinedMethods[] = {
|
||||
// all except window
|
||||
{ "new", LM::m_new, -1, 0, kAllObj, 200 }, // D2
|
||||
|
||||
// factory and XObject
|
||||
{ "describe", LM::m_describe, 0, 0, kXObj, 200 }, // D2
|
||||
{ "dispose", LM::m_dispose, 0, 0, kFactoryObj | kXObj, 200 }, // D2
|
||||
{ "get", LM::m_get, 1, 1, kFactoryObj, 200 }, // D2
|
||||
{ "instanceRespondsTo", LM::m_instanceRespondsTo, 1, 1, kXObj, 300 }, // D3
|
||||
{ "messageList", LM::m_messageList, 0, 0, kXObj, 300 }, // D3
|
||||
{ "name", LM::m_name, 0, 0, kXObj, 300 }, // D3
|
||||
{ "perform", LM::m_perform, -1, 0, kFactoryObj | kXObj, 300 }, // D3
|
||||
{ "put", LM::m_put, 2, 2, kFactoryObj, 200 }, // D2
|
||||
{ "respondsTo", LM::m_respondsTo, 1, 1, kXObj, 200 }, // D2
|
||||
|
||||
// script object and Xtra
|
||||
{ "birth", LM::m_new, -1, 0, kScriptObj | kXtraObj, 400 }, // D4
|
||||
|
||||
{ nullptr, nullptr, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const MethodProto windowMethods[] = {
|
||||
// window / stage
|
||||
{ "close", LM::m_close, 0, 0, 400 }, // D4
|
||||
{ "forget", LM::m_forget, 0, 0, 400 }, // D4
|
||||
{ "open", LM::m_open, 0, 0, 400 }, // D4
|
||||
{ "moveToBack", LM::m_moveToBack, 0, 0, 400 }, // D4
|
||||
{ "moveToFront", LM::m_moveToFront, 0, 0, 400 }, // D4
|
||||
{ nullptr, nullptr, 0, 0, 0 }
|
||||
};
|
||||
|
||||
void Lingo::initMethods() {
|
||||
for (const PredefinedProto *mtd = predefinedMethods; mtd->name; mtd++) {
|
||||
if (mtd->version > _vm->getVersion())
|
||||
continue;
|
||||
|
||||
Symbol sym;
|
||||
sym.name = new Common::String(mtd->name);
|
||||
sym.type = HBLTIN;
|
||||
sym.nargs = mtd->minArgs;
|
||||
sym.maxArgs = mtd->maxArgs;
|
||||
sym.targetType = mtd->type;
|
||||
sym.u.bltin = mtd->func;
|
||||
_methods[mtd->name] = sym;
|
||||
}
|
||||
Window::initMethods(windowMethods);
|
||||
}
|
||||
|
||||
void Lingo::cleanupMethods() {
|
||||
_methods.clear();
|
||||
Window::cleanupMethods();
|
||||
}
|
||||
|
||||
#define XLIBDEF(class, flags, version) \
|
||||
{ #class, class::fileNames, class::open, class::close, flags, version }
|
||||
|
||||
static const struct XLibProto {
|
||||
const char *className;
|
||||
const XlibFileDesc *names;
|
||||
XLibOpenerFunc opener;
|
||||
XLibCloserFunc closer;
|
||||
int type;
|
||||
int version;
|
||||
} xlibs[] = {
|
||||
XLIBDEF(AiffXObj, kXObj, 400), // D4
|
||||
XLIBDEF(AppleCDXObj, kXObj, 300), // D3
|
||||
XLIBDEF(AskUser, kXObj, 400), // D4
|
||||
XLIBDEF(AudioXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(BackdropXObj, kXObj, 400), // D4
|
||||
XLIBDEF(BarakeObj, kXObj, 400), // D4
|
||||
XLIBDEF(BatQT, kXObj, 400), // D4
|
||||
XLIBDEF(BIMXObj, kXObj, 400), // D4
|
||||
XLIBDEF(BlitPictXObj, kXObj, 400), // D4
|
||||
XLIBDEF(BlockTheDrawingXObj, kXObj, 400), // D4
|
||||
XLIBDEF(BudAPIXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(CDROMXObj, kXObj, 200), // D2
|
||||
XLIBDEF(CloseBleedWindowXCMD,kXObj, 300), // D3
|
||||
XLIBDEF(ColorXObj, kXObj, 400), // D4
|
||||
XLIBDEF(ColorCursorXObj, kXObj, 400), // D4
|
||||
XLIBDEF(ConsumerXObj, kXObj, 400), // D4
|
||||
XLIBDEF(CursorXObj, kXObj, 400), // D4
|
||||
XLIBDEF(DLLGlueXObj, kXObj, 400), // D4
|
||||
XLIBDEF(DPWAVIXObj, kXObj, 300), // D3
|
||||
XLIBDEF(DPWQTWXObj, kXObj, 300), // D3
|
||||
XLIBDEF(DarkenScreen, kXObj, 300), // D3
|
||||
XLIBDEF(DateUtilXObj, kXObj, 400), // D4
|
||||
XLIBDEF(DeveloperStack, kXObj, 300), // D3
|
||||
XLIBDEF(DialogsXObj, kXObj, 400), // D4
|
||||
XLIBDEF(DirUtilXObj, kXObj, 400), // D4
|
||||
XLIBDEF(DirectsoundXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(DisplayResXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(DrawXObj, kXObj, 400), // D4
|
||||
XLIBDEF(Ednox, kXObj, 300), // D3
|
||||
XLIBDEF(EventQXObj, kXObj, 400), // D4
|
||||
XLIBDEF(FEDraculXObj, kXObj, 400), // D4
|
||||
XLIBDEF(FEIMasksXObj, kXObj, 400), // D4
|
||||
XLIBDEF(FEIPrefsXObj, kXObj, 400), // D4
|
||||
XLIBDEF(FSUtilXObj, kXObj, 400), // D4
|
||||
XLIBDEF(FadeGammaDownXCMD, kXObj, 400), // D4
|
||||
XLIBDEF(FadeGammaUpXCMD, kXObj, 400), // D4
|
||||
XLIBDEF(FadeGammaXCMD, kXObj, 400), // D4
|
||||
XLIBDEF(FileExists, kXObj, 300), // D3
|
||||
XLIBDEF(FileIO, kXObj | kXtraObj,200), // D2
|
||||
XLIBDEF(FileXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(FindFolder, kXObj, 300), // D3
|
||||
XLIBDEF(FindSys, kXObj, 400), // D4
|
||||
XLIBDEF(FindWin, kXObj, 400), // D4
|
||||
XLIBDEF(FinderEventsXCMD, kXObj, 400), // D4
|
||||
XLIBDEF(FlushXObj, kXObj, 300), // D3
|
||||
XLIBDEF(FPlayXObj, kXObj, 200), // D2
|
||||
XLIBDEF(GenUtilsXObj, kXObj, 400), // D4
|
||||
XLIBDEF(GetScreenRectsXFCN, kXObj, 300), // D3
|
||||
XLIBDEF(GetScreenSizeXFCN, kXObj, 300), // D3
|
||||
XLIBDEF(GetSoundInLevelXObj,kXObj, 400), // D4
|
||||
XLIBDEF(GpidXObj, kXObj, 400), // D4
|
||||
XLIBDEF(HenryXObj, kXObj, 400), // D4
|
||||
XLIBDEF(HitMap, kXObj, 400), // D4
|
||||
XLIBDEF(IniXObj, kXObj, 400), // D4
|
||||
XLIBDEF(InstObjXObj, kXObj, 400), // D4
|
||||
XLIBDEF(IsCD, kXObj, 300), // D3
|
||||
XLIBDEF(IsPippin, kXObj, 400), // D4
|
||||
XLIBDEF(JITDraw3XObj, kXObj, 400), // D4
|
||||
XLIBDEF(JourneyWareXINIXObj,kXObj, 400), // D4
|
||||
XLIBDEF(KeypollXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(LabelDrvXObj, kXObj, 400), // D4
|
||||
XLIBDEF(ListDevXObj, kXObj, 500), // D5
|
||||
XLIBDEF(MMovieXObj, kXObj, 400), // D4
|
||||
XLIBDEF(ManiacBgXObj, kXObj, 300), // D3
|
||||
XLIBDEF(MapNavigatorXObj, kXObj, 400), // D4
|
||||
XLIBDEF(MasterAppXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(MazeXObj, kXObj, 400), // D4
|
||||
XLIBDEF(MemCheckXObj, kXObj, 400), // D4
|
||||
XLIBDEF(MemoryXObj, kXObj, 300), // D3
|
||||
XLIBDEF(Misc, kXObj, 400), // D4
|
||||
XLIBDEF(MiscX, kXObj, 400), // D4
|
||||
XLIBDEF(MMaskXObj, kXObj, 400), // D4
|
||||
XLIBDEF(MoovXObj, kXObj, 300), // D3
|
||||
XLIBDEF(MoveMouseJPXObj, kXObj, 400), // D4
|
||||
XLIBDEF(MoveMouseXObj, kXObj, 400), // D4
|
||||
XLIBDEF(MovieIdxXObj, kXObj, 400), // D4
|
||||
XLIBDEF(MovUtilsXObj, kXObj, 400), // D4
|
||||
XLIBDEF(MSFile, kXObj, 400), // D4
|
||||
XLIBDEF(MuiXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(MystIsleXObj, kXObj, 400), // D4
|
||||
XLIBDEF(OSCheckXtra, kXtraObj, 400), // D4
|
||||
XLIBDEF(OpenBleedWindowXCMD,kXObj, 300), // D3
|
||||
XLIBDEF(OpenURLXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(OrthoPlayXObj, kXObj, 400), // D4
|
||||
XLIBDEF(PACoXObj, kXObj, 300), // D3
|
||||
XLIBDEF(PalXObj, kXObj, 400), // D4
|
||||
XLIBDEF(PanelXObj, kXObj, 200), // D2
|
||||
XLIBDEF(PharaohsXObj, kXObj, 400), // D4
|
||||
XLIBDEF(PlaySoundMovieXObj, kXObj, 400), // D4
|
||||
XLIBDEF(PopUpMenuXObj, kXObj, 200), // D2
|
||||
XLIBDEF(Porta, kXObj, 300), // D3
|
||||
XLIBDEF(PrefPath, kXObj, 400), // D4
|
||||
XLIBDEF(PrintOMaticXObj, kXObj | kXtraObj,400), // D4
|
||||
XLIBDEF(ProcessXObj, kXObj, 400), // D4
|
||||
XLIBDEF(PutcursXObj, kXObj, 400), // D4
|
||||
XLIBDEF(QTCatMoviePlayerXObj,kXObj, 400), // D4
|
||||
XLIBDEF(QTMovie, kXObj, 400), // D4
|
||||
XLIBDEF(QTVR, kXObj, 400), // D4
|
||||
XLIBDEF(QtvrxtraXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(Quicktime, kXObj, 300), // D3
|
||||
XLIBDEF(RearWindowXObj, kXObj, 400), // D4
|
||||
XLIBDEF(RegisterComponent, kXObj, 400), // D4
|
||||
XLIBDEF(RegistryReaderXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(RemixXCMD, kXObj, 300), // D3
|
||||
XLIBDEF(RolloverToolkitXtra,kXtraObj, 500), // D5
|
||||
XLIBDEF(SaveNRestoreXObj, kXObj, 400), // D4
|
||||
XLIBDEF(ScrnUtilXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(SerialPortXObj, kXObj, 200), // D2
|
||||
XLIBDEF(SmackerXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(SmallUtilXObj, kXObj, 400), // D4
|
||||
XLIBDEF(SoundJam, kXObj, 400), // D4
|
||||
XLIBDEF(SpaceMgr, kXObj, 400), // D4
|
||||
XLIBDEF(StageTCXObj, kXObj, 400), // D4
|
||||
XLIBDEF(StayToonedBallXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(StayToonedGlopXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(StayToonedHallXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(StayToonedHighXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(StayToonedOberXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(StayToonedToonXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(SysColorXObj, kXObj, 400), // D4
|
||||
XLIBDEF(TemnotaXObj, kXObj, 400), // D4
|
||||
XLIBDEF(TenguXObj, kXObj, 400), // D4
|
||||
XLIBDEF(TimextraXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(UnitTestXObj, kXObj, 400), // D4
|
||||
XLIBDEF(VMPresentXObj, kXObj, 400), // D4
|
||||
XLIBDEF(VMisOnXFCN, kXObj, 400), // D4
|
||||
XLIBDEF(ValkyrieXObj, kXObj, 400), // D4
|
||||
XLIBDEF(VersionsXObj, kXObj, 400), // D4
|
||||
XLIBDEF(VideodiscXObj, kXObj, 200), // D2
|
||||
XLIBDEF(VolumeList, kXObj, 300), // D3
|
||||
XLIBDEF(VoyagerXSoundXObj, kXObj, 400), // D4
|
||||
XLIBDEF(WinInfoXObj, kXObj, 400), // D4
|
||||
XLIBDEF(WidgetXObj, kXObj, 400), // D4
|
||||
XLIBDEF(WindowXObj, kXObj, 200), // D2
|
||||
XLIBDEF(XCMDGlueXObj, kXObj, 200), // D2
|
||||
XLIBDEF(XPlayPACoXFCN, kXObj, 300), // D3
|
||||
XLIBDEF(XSoundXFCN, kXObj, 400), // D4
|
||||
XLIBDEF(XWINXObj, kXObj, 300), // D3
|
||||
XLIBDEF(XioXObj, kXObj, 400), // D3
|
||||
XLIBDEF(XPlayAnim, kXObj, 300), // D3
|
||||
XLIBDEF(XsoundXtra, kXtraObj, 500), // D5
|
||||
XLIBDEF(Yasix, kXObj, 300), // D3
|
||||
{ nullptr, nullptr, nullptr, nullptr, 0, 0 }
|
||||
};
|
||||
|
||||
void Lingo::initXLibs() {
|
||||
Common::HashMap<Common::String, uint32, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> quirks;
|
||||
for (const XLibProto *lib = xlibs; lib->names; lib++) {
|
||||
if (lib->version > _vm->getVersion())
|
||||
continue;
|
||||
|
||||
for (uint i = 0; lib->names[i].name; i++) {
|
||||
bool isQuirk = false;
|
||||
if (lib->names[i].gameId) {
|
||||
isQuirk = strcmp(lib->names[i].gameId, g_director->getGameId()) == 0;
|
||||
// If this entry belongs to a specific game, skip it unless matched
|
||||
if (!isQuirk)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isQuirk) {
|
||||
quirks[lib->names[i].name] = i;
|
||||
} else if (quirks.contains(lib->names[i].name)) {
|
||||
// Ignore new entries that conflict with per-game quirks
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isQuirk && _xlibOpeners.contains(lib->names[i].name))
|
||||
warning("Lingo::initXLibs(): Duplicate entry for %s", lib->names[i].name);
|
||||
|
||||
debugC(5, kDebugLingoExec, "Lingo::initXLibs(): %s -> %s", lib->names[i].name, lib->className);
|
||||
|
||||
_xlibOpeners[lib->names[i].name] = lib->opener;
|
||||
_xlibClosers[lib->names[i].name] = lib->closer;
|
||||
_xlibTypes[lib->names[i].name] = lib->type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Lingo::cleanupXLibs() {
|
||||
_xlibOpeners.clear();
|
||||
_xlibClosers.clear();
|
||||
}
|
||||
|
||||
Common::String Lingo::normalizeXLibName(Common::String name) {
|
||||
// Normalize to remove machintosh path delimiters (':', '@:')
|
||||
name = convertPath(name);
|
||||
|
||||
size_t pos = name.findLastOf(g_director->_dirSeparator);
|
||||
if (pos != Common::String::npos)
|
||||
name = name.substr(pos + 1, name.size());
|
||||
|
||||
Common::Platform platform = _vm->getPlatform();
|
||||
if (platform == Common::kPlatformMacintosh || platform == Common::kPlatformMacintoshII) {
|
||||
if (name.hasSuffixIgnoreCase(".xlib"))
|
||||
name = name.substr(0, name.size() - 5);
|
||||
} else if (platform == Common::kPlatformWindows) {
|
||||
if (name.hasSuffixIgnoreCase(".dll"))
|
||||
name = name.substr(0, name.size() - 4);
|
||||
if (name.hasSuffixIgnoreCase(".x16"))
|
||||
name = name.substr(0, name.size() - 4);
|
||||
if (name.hasSuffixIgnoreCase(".x32"))
|
||||
name = name.substr(0, name.size() - 4);
|
||||
}
|
||||
|
||||
name.trim();
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
void Lingo::openXLib(Common::String name, ObjectType type, const Common::Path &path) {
|
||||
name = normalizeXLibName(name);
|
||||
|
||||
if (_openXLibs.contains(name))
|
||||
return;
|
||||
|
||||
if (type == 0 && _xlibTypes.contains(name)) {
|
||||
type = (_xlibTypes[name] & kXtraObj) ? kXtraObj : kXObj;
|
||||
}
|
||||
|
||||
// manual override for game quirks
|
||||
if (name.equalsIgnoreCase("fileio")) {
|
||||
if (g_director->_fileIOType == kXtraObj && g_director->getVersion() >= 500) {
|
||||
type = kXtraObj;
|
||||
} else if (g_director->_fileIOType == kXObj) {
|
||||
type = kXObj;
|
||||
}
|
||||
}
|
||||
|
||||
_openXLibs[name] = type;
|
||||
|
||||
if (_xlibOpeners.contains(name)) {
|
||||
(*_xlibOpeners[name])(type, path);
|
||||
} else {
|
||||
warning("Lingo::openXLib: Unimplemented xlib: '%s'", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Lingo::closeXLib(Common::String name) {
|
||||
name = normalizeXLibName(name);
|
||||
|
||||
if (!_openXLibs.contains(name)) {
|
||||
warning("Lingo::closeXLib: xlib %s is not open", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectType type = _openXLibs[name];
|
||||
_openXLibs.erase(name);
|
||||
|
||||
if (_xlibClosers.contains(name)) {
|
||||
(*_xlibClosers[name])(type);
|
||||
} else {
|
||||
warning("Lingo::closeXLib: Unimplemented xlib: '%s'", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Lingo::closeOpenXLibs() {
|
||||
for (auto &it : _openXLibs) {
|
||||
// does not affect Xtras
|
||||
if (it._value == kXObj) {
|
||||
closeXLib(it._key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Lingo::reloadOpenXLibs() {
|
||||
OpenXLibsHash openXLibsCopy = _openXLibs;
|
||||
for (auto &it : openXLibsCopy) {
|
||||
closeXLib(it._key);
|
||||
// FIXME: keep track of where the xlib path is
|
||||
openXLib(it._key, it._value, Common::Path());
|
||||
}
|
||||
}
|
||||
|
||||
// Initialization/disposal
|
||||
|
||||
void LM::m_new(int nargs) {
|
||||
// This is usually overridden by a user-defined mNew
|
||||
//
|
||||
// However, in behaviors it is often absent, and it is
|
||||
// in essence our default constructor.
|
||||
g_lingo->push(g_lingo->_state->me);
|
||||
}
|
||||
|
||||
void LM::m_dispose(int nargs) {
|
||||
g_lingo->_state->me.u.obj->dispose();
|
||||
}
|
||||
|
||||
/* ScriptContext */
|
||||
|
||||
ScriptContext::ScriptContext(Common::String name, ScriptType type, int id, uint16 castLibHint, uint16 parentNumber, int scriptId)
|
||||
: Object<ScriptContext>(name), _scriptType(type), _id(id), _castLibHint(castLibHint), _parentNumber(parentNumber), _scriptId(scriptId) {
|
||||
_objType = kScriptObj;
|
||||
}
|
||||
|
||||
ScriptContext::ScriptContext(const ScriptContext &sc) : Object<ScriptContext>(sc) {
|
||||
_scriptType = sc._scriptType;
|
||||
_functionNames = sc._functionNames;
|
||||
for (auto &it : sc._functionHandlers) {
|
||||
_functionHandlers[it._key] = it._value;
|
||||
_functionHandlers[it._key].ctx = this;
|
||||
}
|
||||
for (auto &it : sc._eventHandlers) {
|
||||
_eventHandlers[it._key] = it._value;
|
||||
_eventHandlers[it._key].ctx = this;
|
||||
}
|
||||
_constants = sc._constants;
|
||||
_properties = sc._properties;
|
||||
_propertyNames = sc._propertyNames;
|
||||
_parentNumber = sc._parentNumber;
|
||||
_scriptId = sc._scriptId;
|
||||
|
||||
_id = sc._id;
|
||||
_castLibHint = sc._castLibHint;
|
||||
}
|
||||
|
||||
ScriptContext::~ScriptContext() {
|
||||
}
|
||||
|
||||
Common::String ScriptContext::asString() {
|
||||
return Common::String::format("script: %d \"%s\" %d %p", _id, _name.c_str(), _inheritanceLevel, (void *)this);
|
||||
}
|
||||
|
||||
Symbol ScriptContext::define(const Common::String &name, ScriptData *code, Common::Array<Common::String> *argNames, Common::Array<Common::String> *varNames) {
|
||||
Symbol sym;
|
||||
sym.name = new Common::String(name);
|
||||
sym.type = HANDLER;
|
||||
sym.u.defn = code;
|
||||
sym.nargs = argNames->size();
|
||||
sym.maxArgs = argNames->size();
|
||||
sym.argNames = argNames;
|
||||
sym.varNames = varNames;
|
||||
sym.ctx = this;
|
||||
|
||||
if (debugChannelSet(1, kDebugCompile)) {
|
||||
debugC(1, kDebugCompile, "%s", g_lingo->formatFunctionBody(sym).c_str());
|
||||
debugC(1, kDebugCompile, "<end define code>");
|
||||
}
|
||||
|
||||
_functionHandlers[name] = sym;
|
||||
if (g_lingo->_eventHandlerTypeIds.contains(name)) {
|
||||
_eventHandlers[g_lingo->_eventHandlerTypeIds[name]] = sym;
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
Symbol ScriptContext::getMethod(const Common::String &methodName) {
|
||||
Symbol sym;
|
||||
|
||||
if (_functionHandlers.contains(methodName)) {
|
||||
sym = _functionHandlers[methodName];
|
||||
sym.target = this;
|
||||
return sym;
|
||||
}
|
||||
|
||||
sym = Object<ScriptContext>::getMethod(methodName);
|
||||
if (sym.type != VOIDSYM)
|
||||
return sym;
|
||||
|
||||
if (_objType == kScriptObj) {
|
||||
if (_properties.contains("ancestor") && _properties["ancestor"].type == OBJECT
|
||||
&& (_properties["ancestor"].u.obj->getObjType() & (kScriptObj | kXtraObj))) {
|
||||
// ancestor method
|
||||
sym = _properties["ancestor"].u.obj->getMethod(methodName);
|
||||
if (sym.type != VOIDSYM)
|
||||
debugC(3, kDebugLingoExec, "Calling method '%s' on ancestor: <%s>", methodName.c_str(), _properties["ancestor"].asString(true).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
bool ScriptContext::hasProp(const Common::String &propName) {
|
||||
if (_disposed) {
|
||||
error("Property '%s' accessed on disposed object <%s>", propName.c_str(), Datum(this).asString(true).c_str());
|
||||
}
|
||||
if (_properties.contains(propName)) {
|
||||
return true;
|
||||
}
|
||||
if (_objType == kScriptObj) {
|
||||
if (_properties.contains("ancestor") && _properties["ancestor"].type == OBJECT
|
||||
&& (_properties["ancestor"].u.obj->getObjType() & (kScriptObj | kXtraObj))) {
|
||||
return _properties["ancestor"].u.obj->hasProp(propName);
|
||||
}
|
||||
|
||||
// This is used by behaviors
|
||||
if (propName.equalsIgnoreCase("spriteNum")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Datum ScriptContext::getProp(const Common::String &propName) {
|
||||
if (_disposed) {
|
||||
error("Property '%s' accessed on disposed object <%s>", propName.c_str(), Datum(this).asString(true).c_str());
|
||||
}
|
||||
if (_properties.contains(propName)) {
|
||||
return _properties[propName];
|
||||
}
|
||||
if (_objType == kScriptObj) {
|
||||
if (_properties.contains("ancestor") && _properties["ancestor"].type == OBJECT
|
||||
&& (_properties["ancestor"].u.obj->getObjType() & (kScriptObj | kXtraObj))) {
|
||||
debugC(3, kDebugLingoExec, "Getting prop '%s' from ancestor: <%s>", propName.c_str(), _properties["ancestor"].asString(true).c_str());
|
||||
return _properties["ancestor"].u.obj->getProp(propName);
|
||||
}
|
||||
|
||||
// This is used by behaviors
|
||||
if (propName.equalsIgnoreCase("spriteNum")) {
|
||||
return Datum((int)g_director->getCurrentMovie()->_currentSpriteNum);
|
||||
}
|
||||
}
|
||||
_propertyNames.push_back(propName);
|
||||
return _properties[propName]; // return new property
|
||||
}
|
||||
|
||||
Common::String ScriptContext::getPropAt(uint32 index) {
|
||||
uint32 target = 1;
|
||||
for (auto &it : _propertyNames) {
|
||||
if (target == index) {
|
||||
return it;
|
||||
}
|
||||
target += 1;
|
||||
}
|
||||
return Common::String();
|
||||
}
|
||||
|
||||
uint32 ScriptContext::getPropCount() {
|
||||
return _propertyNames.size();
|
||||
}
|
||||
|
||||
void ScriptContext::setProp(const Common::String &propName, const Datum &value, bool force) {
|
||||
if (_disposed) {
|
||||
error("Property '%s' accessed on disposed object <%s>", propName.c_str(), Datum(this).asString(true).c_str());
|
||||
}
|
||||
if (_properties.contains(propName)) {
|
||||
_properties[propName] = value;
|
||||
return;
|
||||
}
|
||||
if (force) {
|
||||
// used by e.g. the script compiler to add properties
|
||||
_propertyNames.push_back(propName);
|
||||
_properties[propName] = value;
|
||||
} else if (_objType == kScriptObj) {
|
||||
if (_properties.contains("ancestor") && _properties["ancestor"].type == OBJECT
|
||||
&& (_properties["ancestor"].u.obj->getObjType() & (kScriptObj | kXtraObj))) {
|
||||
debugC(3, kDebugLingoExec, "Getting prop '%s' from ancestor: <%s>", propName.c_str(), _properties["ancestor"].asString(true).c_str());
|
||||
_properties["ancestor"].u.obj->setProp(propName, value, force);
|
||||
}
|
||||
} else if (_objType == kFactoryObj) {
|
||||
// D3 style anonymous objects/factories, set whatever properties you like
|
||||
_propertyNames.push_back(propName);
|
||||
_properties[propName] = value;
|
||||
}
|
||||
}
|
||||
|
||||
Common::String ScriptContext::formatFunctionList(const char *prefix) {
|
||||
Common::String result;
|
||||
for (auto it = _functionHandlers.begin(); it != _functionHandlers.end(); ++it) {
|
||||
result += Common::String::format("%s%s\n", prefix, g_lingo->formatFunctionName(it->_value).c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Object array
|
||||
|
||||
void LM::m_get(int nargs) {
|
||||
ScriptContext *me = static_cast<ScriptContext *>(g_lingo->_state->me.u.obj);
|
||||
Datum indexD = g_lingo->pop();
|
||||
uint index = MAX(0, indexD.asInt());
|
||||
if (me->_objArray.contains(index)) {
|
||||
g_lingo->push(me->_objArray[index]);
|
||||
} else {
|
||||
g_lingo->push(Datum(0));
|
||||
}
|
||||
}
|
||||
|
||||
void LM::m_put(int nargs) {
|
||||
ScriptContext *me = static_cast<ScriptContext *>(g_lingo->_state->me.u.obj);
|
||||
Datum value = g_lingo->pop();
|
||||
Datum indexD = g_lingo->pop();
|
||||
uint index = MAX(0, indexD.asInt());
|
||||
me->_objArray[index] = value;
|
||||
}
|
||||
|
||||
// Other
|
||||
|
||||
void LM::m_perform(int nargs) {
|
||||
bool allowRetVal = g_lingo->pop().asInt() != 0; // Pop allowRetVal that should be used for the LC::Call
|
||||
|
||||
// Lingo doesn't seem to bother cloning the object when
|
||||
// mNew is called with mPerform
|
||||
Datum d(g_lingo->_state->me);
|
||||
AbstractObject *me = d.u.obj;
|
||||
Datum methodName = g_lingo->_state->stack.remove_at(g_lingo->_state->stack.size() - nargs); // Take method name out of stack
|
||||
Symbol funcSym = me->getMethod(*methodName.u.s);
|
||||
// Object methods expect the first argument to be the object
|
||||
g_lingo->_state->stack.insert_at(g_lingo->_state->stack.size() - nargs + 1, d);
|
||||
LC::call(funcSym, nargs, allowRetVal);
|
||||
|
||||
if (allowRetVal) {
|
||||
// If the method expects a return value, push dummy on stack
|
||||
g_lingo->pushVoid();
|
||||
}
|
||||
}
|
||||
|
||||
// XObject
|
||||
|
||||
void LM::m_describe(int nargs) {
|
||||
warning("STUB: m_describe");
|
||||
}
|
||||
|
||||
void LM::m_instanceRespondsTo(int nargs) {
|
||||
AbstractObject *me = g_lingo->_state->me.u.obj;
|
||||
Datum d = g_lingo->pop();
|
||||
Common::String methodName = d.asString();
|
||||
|
||||
if (me->getMethod(methodName).type != VOIDSYM) {
|
||||
g_lingo->push(Datum(1));
|
||||
} else {
|
||||
g_lingo->push(Datum(0));
|
||||
}
|
||||
}
|
||||
|
||||
void LM::m_messageList(int nargs) {
|
||||
warning("STUB: m_messageList");
|
||||
g_lingo->push(Datum(""));
|
||||
}
|
||||
|
||||
void LM::m_name(int nargs) {
|
||||
AbstractObject *me = g_lingo->_state->me.u.obj;
|
||||
g_lingo->push(me->getName());
|
||||
}
|
||||
|
||||
void LM::m_respondsTo(int nargs) {
|
||||
AbstractObject *me = g_lingo->_state->me.u.obj;
|
||||
Datum d = g_lingo->pop();
|
||||
Common::String methodName = d.asString();
|
||||
|
||||
// TODO: Check inheritance level
|
||||
if (me->getMethod(methodName).type != VOIDSYM) {
|
||||
g_lingo->push(Datum(1));
|
||||
} else {
|
||||
g_lingo->push(Datum(0));
|
||||
}
|
||||
}
|
||||
|
||||
// Window
|
||||
|
||||
Common::String Window::asString() {
|
||||
return "window \"" + getName() + "\"";
|
||||
}
|
||||
|
||||
bool Window::hasProp(const Common::String &propName) {
|
||||
Common::String fieldName = Common::String::format("%d%s", kTheWindow, propName.c_str());
|
||||
return g_lingo->_theEntityFields.contains(fieldName) && hasField(g_lingo->_theEntityFields[fieldName]->field);
|
||||
}
|
||||
|
||||
Datum Window::getProp(const Common::String &propName) {
|
||||
Common::String fieldName = Common::String::format("%d%s", kTheWindow, propName.c_str());
|
||||
if (g_lingo->_theEntityFields.contains(fieldName)) {
|
||||
return getField(g_lingo->_theEntityFields[fieldName]->field);
|
||||
}
|
||||
|
||||
warning("Window::getProp: unknown property '%s'", propName.c_str());
|
||||
return Datum();
|
||||
}
|
||||
|
||||
void Window::setProp(const Common::String &propName, const Datum &value, bool force) {
|
||||
Common::String fieldName = Common::String::format("%d%s", kTheWindow, propName.c_str());
|
||||
if (g_lingo->_theEntityFields.contains(fieldName)) {
|
||||
setField(g_lingo->_theEntityFields[fieldName]->field, value);
|
||||
return;
|
||||
}
|
||||
|
||||
warning("Window::setProp: unknown property '%s'", propName.c_str());
|
||||
}
|
||||
|
||||
bool Window::hasField(int field) {
|
||||
switch (field) {
|
||||
case kTheDrawRect:
|
||||
case kTheFileName:
|
||||
case kTheModal:
|
||||
case kTheRect:
|
||||
case kTheSourceRect:
|
||||
case kTheTitle:
|
||||
case kTheTitleVisible:
|
||||
case kTheVisible:
|
||||
case kTheWindowType:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Datum Window::getField(int field) {
|
||||
switch (field) {
|
||||
case kTheTitle:
|
||||
return _window->getTitle();
|
||||
case kTheTitleVisible:
|
||||
return _window->isTitleVisible();
|
||||
case kTheVisible:
|
||||
return _window->isVisible();
|
||||
case kTheWindowType:
|
||||
return getWindowType();
|
||||
case kTheRect:
|
||||
return getStageRect();
|
||||
case kTheModal:
|
||||
return getModal();
|
||||
case kTheFileName:
|
||||
return getFileName();
|
||||
case kTheDrawRect:
|
||||
warning("Window::getField: poorly handled getting field 'drawRect'");
|
||||
ensureMovieIsLoaded();
|
||||
|
||||
// TODO: This should allow stretching or panning
|
||||
return getStageRect();
|
||||
case kTheSourceRect:
|
||||
// case kTheImage:
|
||||
// case kThePicture::
|
||||
ensureMovieIsLoaded(); // Remove fallthrough once implemented
|
||||
// fallthrough
|
||||
default:
|
||||
warning("Window::getField: unhandled field '%s'", g_lingo->field2str(field));
|
||||
return Datum();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::setField(int field, const Datum &value) {
|
||||
switch (field) {
|
||||
case kTheTitle:
|
||||
setTitle(value.asString());
|
||||
break;
|
||||
case kTheTitleVisible:
|
||||
setTitleVisible((bool)value.asInt());
|
||||
break;
|
||||
case kTheVisible:
|
||||
setVisible((bool)value.asInt());
|
||||
break;
|
||||
case kTheWindowType:
|
||||
setWindowType(value.asInt());
|
||||
break;
|
||||
case kTheDrawRect:
|
||||
warning("Window::setField: poorly handled setting field 'drawRect'");
|
||||
// fallthrough
|
||||
case kTheRect:
|
||||
setStageRect(value);
|
||||
break;
|
||||
case kTheModal:
|
||||
setModal((bool)value.asInt());
|
||||
break;
|
||||
case kTheFileName:
|
||||
setFileName(value.asString());
|
||||
break;
|
||||
default:
|
||||
warning("Window::setField: unhandled field '%s'", g_lingo->field2str(field));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LM::m_close(int nargs) {
|
||||
Window *me = static_cast<Window *>(g_lingo->_state->me.u.obj);
|
||||
me->setVisible(false);
|
||||
}
|
||||
|
||||
void LM::m_forget(int nargs) {
|
||||
Window *me = static_cast<Window *>(g_lingo->_state->me.u.obj);
|
||||
FArray *windowList = g_lingo->_windowList.u.farr;
|
||||
|
||||
int windowIndex = -1;
|
||||
for (int i = 0; i < (int)windowList->arr.size(); i++) {
|
||||
if (windowList->arr[i].type != OBJECT || windowList->arr[i].u.obj->getObjType() != kWindowObj)
|
||||
continue;
|
||||
|
||||
Window *window = static_cast<Window *>(windowList->arr[i].u.obj);
|
||||
if (window == me) {
|
||||
windowIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (windowIndex == -1) {
|
||||
warning("m_forget: me object %s not found in window list", g_lingo->_state->me.asString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (windowIndex < (int)windowList->arr.size())
|
||||
windowList->arr.remove_at(windowIndex);
|
||||
|
||||
// remove me from global vars
|
||||
for (auto &it : g_lingo->_globalvars) {
|
||||
if (it._value.type != OBJECT || it._value.u.obj->getObjType() != kWindowObj)
|
||||
continue;
|
||||
|
||||
if (it._value.u.obj == me)
|
||||
g_lingo->_globalvars[it._key] = 0;
|
||||
}
|
||||
g_director->forgetWindow(me);
|
||||
}
|
||||
|
||||
void LM::m_open(int nargs) {
|
||||
Window *me = static_cast<Window *>(g_lingo->_state->me.u.obj);
|
||||
bool wasVisible = me->_window->isVisible();
|
||||
me->setVisible(true);
|
||||
|
||||
if (!wasVisible)
|
||||
me->sendWindowEvent(kEventOpenWindow);
|
||||
}
|
||||
|
||||
void LM::m_moveToBack(int nargs) {
|
||||
g_lingo->printSTUBWithArglist("m_moveToBack", nargs);
|
||||
g_lingo->dropStack(nargs);
|
||||
}
|
||||
|
||||
void LM::m_moveToFront(int nargs) {
|
||||
Window *me = static_cast<Window *>(g_lingo->_state->me.u.obj);
|
||||
me->ensureMovieIsLoaded();
|
||||
|
||||
bool wasActive = (g_director->_wm->getActiveWindow() == me->getId());
|
||||
g_director->_wm->setActiveWindow(me->getId());
|
||||
|
||||
if (!wasActive)
|
||||
me->sendWindowEvent(kEventOpenWindow);
|
||||
}
|
||||
|
||||
// Actor
|
||||
/*
|
||||
collectChangeRects
|
||||
getAProp
|
||||
hitTest
|
||||
ilk
|
||||
mouseDown
|
||||
mouseHitTest
|
||||
mouseTrack
|
||||
mouseUp
|
||||
setAProp
|
||||
stepFrame
|
||||
updateRect
|
||||
*/
|
||||
|
||||
|
||||
} // End of namespace Director
|
||||
283
engines/director/lingo/lingo-object.h
Normal file
283
engines/director/lingo/lingo-object.h
Normal file
@@ -0,0 +1,283 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_OBJECT_H
|
||||
#define DIRECTOR_LINGO_OBJECT_H
|
||||
|
||||
#include "director/lingo/lingo.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
struct MethodProto {
|
||||
const char *name;
|
||||
void (*func)(int);
|
||||
int minArgs; // -1 -- arglist
|
||||
int maxArgs;
|
||||
int version;
|
||||
};
|
||||
|
||||
struct XlibFileDesc {
|
||||
const char *name; // Base file name for the Xlib file in the original
|
||||
const char *gameId; // GameId or nullptr if applicable to all
|
||||
};
|
||||
|
||||
class AbstractObject {
|
||||
public:
|
||||
virtual ~AbstractObject() {};
|
||||
|
||||
virtual Common::String getName() const = 0;
|
||||
virtual ObjectType getObjType() const = 0;
|
||||
virtual bool isDisposed() const = 0;
|
||||
virtual int *getRefCount() const = 0;
|
||||
virtual void incRefCount() = 0;
|
||||
virtual void decRefCount() = 0;
|
||||
virtual int getInheritanceLevel() const = 0;
|
||||
|
||||
virtual void setName(const Common::String &name) = 0;
|
||||
virtual void dispose() = 0;
|
||||
|
||||
virtual Common::String asString() = 0;
|
||||
virtual AbstractObject *clone() = 0;
|
||||
virtual Symbol getMethod(const Common::String &methodName) = 0;
|
||||
virtual bool hasProp(const Common::String &propName) = 0;
|
||||
virtual Datum getProp(const Common::String &propName) = 0;
|
||||
virtual Common::String getPropAt(uint32 index) = 0;
|
||||
virtual uint32 getPropCount() = 0;
|
||||
virtual void setProp(const Common::String &propName, const Datum &value, bool force = false) = 0;
|
||||
virtual bool hasField(int field) = 0;
|
||||
virtual Datum getField(int field) = 0;
|
||||
virtual void setField(int field, const Datum &value) = 0;
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
class Object : public AbstractObject {
|
||||
public:
|
||||
int *_refCount;
|
||||
|
||||
protected:
|
||||
Object(Common::String objName) {
|
||||
_name = objName;
|
||||
_objType = kNoneObj;
|
||||
_disposed = false;
|
||||
_inheritanceLevel = 1;
|
||||
_refCount = new int;
|
||||
*_refCount = 0;
|
||||
};
|
||||
|
||||
Object(const Object &obj) {
|
||||
_name = obj._name;
|
||||
_objType = obj._objType;
|
||||
_disposed = obj._disposed;
|
||||
_inheritanceLevel = obj._inheritanceLevel + 1;
|
||||
_refCount = new int;
|
||||
*_refCount = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
static void initMethods(const MethodProto protos[]) {
|
||||
if (_methods) {
|
||||
warning("Object::initMethods: Methods already initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
_methods = new SymbolHash;
|
||||
for (const MethodProto *mtd = protos; mtd->name; mtd++) {
|
||||
if (mtd->version > g_lingo->_vm->getVersion())
|
||||
continue;
|
||||
|
||||
Symbol sym;
|
||||
sym.name = new Common::String(mtd->name);
|
||||
sym.type = HBLTIN;
|
||||
sym.nargs = mtd->minArgs;
|
||||
sym.maxArgs = mtd->maxArgs;
|
||||
sym.u.bltin = mtd->func;
|
||||
(*_methods)[mtd->name] = sym;
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanupMethods() {
|
||||
delete _methods;
|
||||
_methods = nullptr;
|
||||
}
|
||||
|
||||
virtual ~Object() {
|
||||
delete _refCount;
|
||||
};
|
||||
|
||||
Common::String getName() const override { return _name; };
|
||||
ObjectType getObjType() const override { return _objType; };
|
||||
bool isDisposed() const override { return _disposed; };
|
||||
int *getRefCount() const override { return _refCount; };
|
||||
void incRefCount() override { *_refCount += 1; };
|
||||
virtual void decRefCount() override {
|
||||
*_refCount -= 1;
|
||||
if (*_refCount <= 0)
|
||||
delete this;
|
||||
};
|
||||
int getInheritanceLevel() const override { return _inheritanceLevel; };
|
||||
|
||||
void setName(const Common::String &name) override { _name = name; };
|
||||
void dispose() override { _disposed = true; };
|
||||
|
||||
Common::String asString() override {
|
||||
return Common::String::format("object: #%s %d %p", _name.c_str(), _inheritanceLevel, (void *)this);
|
||||
};
|
||||
|
||||
AbstractObject *clone() override {
|
||||
return new Derived(static_cast<Derived const &>(*this));
|
||||
};
|
||||
|
||||
Symbol getMethod(const Common::String &methodName) override {
|
||||
Symbol sym;
|
||||
|
||||
if (_disposed) {
|
||||
warning("Method '%s' called on disposed object <%s>, returning VOID", methodName.c_str(), asString().c_str());
|
||||
return sym;
|
||||
}
|
||||
|
||||
Common::String methodId;
|
||||
if ((_objType & (kFactoryObj | kXObj)) && methodName.hasPrefixIgnoreCase("m")) {
|
||||
methodId = methodName.substr(1);
|
||||
} else {
|
||||
methodId = methodName;
|
||||
}
|
||||
|
||||
if (_methods && _methods->contains(methodId)) {
|
||||
sym = (*_methods)[methodId];
|
||||
sym.target = this;
|
||||
return sym;
|
||||
}
|
||||
if (g_lingo->_methods.contains(methodId) && (g_lingo->_methods[methodId].targetType & _objType)) {
|
||||
sym = g_lingo->_methods[methodId];
|
||||
sym.target = this;
|
||||
return sym;
|
||||
}
|
||||
|
||||
return sym;
|
||||
};
|
||||
|
||||
bool hasProp(const Common::String &propName) override {
|
||||
return false;
|
||||
};
|
||||
Datum getProp(const Common::String &propName) override {
|
||||
return Datum();
|
||||
};
|
||||
Common::String getPropAt(uint32 index) override {
|
||||
return Common::String();
|
||||
};
|
||||
uint32 getPropCount() override {
|
||||
return 0;
|
||||
};
|
||||
void setProp(const Common::String &propName, const Datum &value, bool force = false) override {
|
||||
return;
|
||||
};
|
||||
bool hasField(int field) override {
|
||||
return false;
|
||||
};
|
||||
Datum getField(int field) override {
|
||||
return Datum();
|
||||
};
|
||||
void setField(int field, const Datum &value) override {
|
||||
return;
|
||||
};
|
||||
|
||||
protected:
|
||||
static SymbolHash *_methods;
|
||||
Common::String _name;
|
||||
ObjectType _objType;
|
||||
bool _disposed;
|
||||
int _inheritanceLevel; // 1 for original object
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
SymbolHash *Object<Derived>::_methods = nullptr;
|
||||
|
||||
class ScriptContext : public Object<ScriptContext> {
|
||||
public:
|
||||
ScriptType _scriptType;
|
||||
int _id;
|
||||
int _scriptId;
|
||||
uint16 _parentNumber;
|
||||
uint16 _castLibHint;
|
||||
Common::Array<Common::String> _functionNames; // used by cb_localcall
|
||||
Common::HashMap<Common::String, Common::Array<uint32>> _functionByteOffsets;
|
||||
SymbolHash _functionHandlers;
|
||||
Common::HashMap<uint32, Symbol> _eventHandlers;
|
||||
Common::Array<Datum> _constants;
|
||||
Common::HashMap<uint32, Datum> _objArray;
|
||||
MethodHash _methodNames;
|
||||
Common::SharedPtr<Node> _assemblyAST; // Optionally contains AST when we compile Lingo
|
||||
|
||||
private:
|
||||
DatumHash _properties;
|
||||
Common::Array<Common::String> _propertyNames;
|
||||
bool _onlyInLctxContexts = false;
|
||||
|
||||
public:
|
||||
ScriptContext(Common::String name, ScriptType type = kNoneScript, int id = 0, uint16 castLibHint = 0, uint16 parentNumber = 0, int scriptId = 0);
|
||||
ScriptContext(const ScriptContext &sc);
|
||||
~ScriptContext() override;
|
||||
|
||||
bool isFactory() const { return _objType == kFactoryObj; };
|
||||
void setFactory(bool flag) { _objType = flag ? kFactoryObj : kScriptObj; }
|
||||
|
||||
void setOnlyInLctxContexts() { _onlyInLctxContexts = true; }
|
||||
bool getOnlyInLctxContexts() { return _onlyInLctxContexts; }
|
||||
|
||||
Common::String asString() override;
|
||||
Symbol getMethod(const Common::String &methodName) override;
|
||||
bool hasProp(const Common::String &propName) override;
|
||||
Datum getProp(const Common::String &propName) override;
|
||||
Common::String getPropAt(uint32 index) override;
|
||||
uint32 getPropCount() override;
|
||||
void setProp(const Common::String &propName, const Datum &value, bool force = false) override;
|
||||
|
||||
Symbol define(const Common::String &name, ScriptData *code, Common::Array<Common::String> *argNames, Common::Array<Common::String> *varNames);
|
||||
|
||||
Common::String formatFunctionList(const char *prefix);
|
||||
};
|
||||
|
||||
namespace LM {
|
||||
|
||||
// predefined methods
|
||||
void m_describe(int nargs);
|
||||
void m_dispose(int nargs);
|
||||
void m_get(int nargs);
|
||||
void m_instanceRespondsTo(int nargs);
|
||||
void m_messageList(int nargs);
|
||||
void m_name(int nargs);
|
||||
void m_new(int nargs);
|
||||
void m_perform(int nargs);
|
||||
void m_put(int nargs);
|
||||
void m_respondsTo(int nargs);
|
||||
|
||||
// window
|
||||
void m_close(int nargs);
|
||||
void m_forget(int nargs);
|
||||
void m_moveToBack(int nargs);
|
||||
void m_moveToFront(int nargs);
|
||||
void m_open(int nargs);
|
||||
|
||||
} // End of namespace LM
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
609
engines/director/lingo/lingo-patcher.cpp
Normal file
609
engines/director/lingo/lingo-patcher.cpp
Normal file
@@ -0,0 +1,609 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/punycode.h"
|
||||
#include "director/director.h"
|
||||
#include "director/cast.h"
|
||||
#include "director/movie.h"
|
||||
#include "director/lingo/lingo-codegen.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
using namespace Common;
|
||||
|
||||
struct ScriptPatch {
|
||||
const char *gameId;
|
||||
const char *extra;
|
||||
Common::Platform platform; // Specify kPlatformUnknown for skipping platform check
|
||||
const char *movie;
|
||||
ScriptType type;
|
||||
uint16 id;
|
||||
uint16 castLib;
|
||||
int linenum;
|
||||
const char *orig;
|
||||
const char *replace;
|
||||
} const scriptPatches[] = {
|
||||
// Garbage at end of script
|
||||
{"warlock", nullptr, kPlatformMacintosh, "WARLOCKSHIP:UpForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
2, "SS Warlock:DATA:WARLOCKSHIP:Up.GCGunner", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "WARLOCKSHIP:UpForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
3, "Channels 17 to 18", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "WARLOCKSHIP:UpForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
4, "Frames 150 to 160", ""},
|
||||
|
||||
// Garbage at end of script
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:HE.Aft", kScoreScript, 8, DEFAULT_CAST_LIB,
|
||||
2, "SS Warlock:DATA:WARLOCKSHIP:HangStairsFore", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:HE.Aft", kScoreScript, 8, DEFAULT_CAST_LIB,
|
||||
3, "Channels 4 to 5", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:HE.Aft", kScoreScript, 8, DEFAULT_CAST_LIB,
|
||||
4, "Frames 20 to 20", ""},
|
||||
|
||||
// Garbage at end of script
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:ENG:D10", kScoreScript, 8, DEFAULT_CAST_LIB,
|
||||
2, "SS Warlock:ENG.Fold:C9", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:ENG:D10", kScoreScript, 8, DEFAULT_CAST_LIB,
|
||||
3, "Channels 19 to 20", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:ENG:D10", kScoreScript, 8, DEFAULT_CAST_LIB,
|
||||
4, "Frames 165 to 180", ""},
|
||||
|
||||
// Garbage at end of script
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:Up.c2", kScoreScript, 10, DEFAULT_CAST_LIB,
|
||||
2, "Frames 150 to 160", ""},
|
||||
|
||||
// Garbage at end of script
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:Up.ForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
2, "SS Warlock:DATA:WARLOCKSHIP:Up.GCGunner", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:Up.ForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
3, "Channels 17 to 18", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:Up.ForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
4, "Frames 150 to 160", ""},
|
||||
|
||||
// Garbage at end of script
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:Up.B2", kScoreScript, 9, DEFAULT_CAST_LIB,
|
||||
2, "SS Warlock:DATA:WARLOCKSHIP:Up.GCGunner", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:Up.B2", kScoreScript, 9, DEFAULT_CAST_LIB,
|
||||
3, "Channels 17 to 18", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:Up.B2", kScoreScript, 9, DEFAULT_CAST_LIB,
|
||||
4, "Frames 150 to 160", ""},
|
||||
|
||||
// Garbage at end of script
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:BELSHAZZAR:STELLA:ORIGIN", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
2, "Frames 1 to 1", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:BELSHAZZAR:STELLA:ORIGIN", kScoreScript, 13, DEFAULT_CAST_LIB,
|
||||
2, "Frames 1 to 1", ""},
|
||||
|
||||
// Garbage at end of script
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:HangHallAft", kScoreScript, 7, DEFAULT_CAST_LIB,
|
||||
2, "SS Warlock:DATA:WARLOCKSHIP:HangStairsFore", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:HangHallAft", kScoreScript, 7, DEFAULT_CAST_LIB,
|
||||
3, "Channels 4 to 5", ""},
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:HangHallAft", kScoreScript, 7, DEFAULT_CAST_LIB,
|
||||
4, "Frames 20 to 20", ""},
|
||||
|
||||
// Stray 'then' (obvious copy/paste error)
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:K:KT:OutMarauderKT", kMovieScript, 14, DEFAULT_CAST_LIB,
|
||||
23, "set Spacesuit = 0 then", "set Spacesuit = 0"},
|
||||
|
||||
// Missing '&'
|
||||
{"warlock", nullptr, kPlatformMacintosh, "DATA:NAV:Shared Cast", kMovieScript, 510, DEFAULT_CAST_LIB,
|
||||
19, "alert \"Failed Save.\" & return & \"Error message number: \" string ( filer )",
|
||||
"alert \"Failed Save.\" & return & \"Error message number: \" & string ( filer )"},
|
||||
|
||||
// Garbage at end of script
|
||||
{"warlock", "v1.1.3 MPC", kPlatformWindows, "WRLCKSHP:UpForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
2, "SS Warlock:DATA:WARLOCKSHIP:Up.GCGunner", ""},
|
||||
{"warlock", "v1.1.3 MPC", kPlatformWindows, "WRLCKSHP:UpForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
3, "Channels 17 to 18", ""},
|
||||
{"warlock", "v1.1.3 MPC", kPlatformWindows, "WRLCKSHP:UpForeECall", kScoreScript, 12, DEFAULT_CAST_LIB,
|
||||
4, "Frames 150 to 160", ""},
|
||||
|
||||
// Missing '&'
|
||||
{"warlock", nullptr, kPlatformUnknown, "NAV:Shared Cast", kMovieScript, 510, DEFAULT_CAST_LIB,
|
||||
23, "alert \"Failed Save.\" & return & \"Error message number: \" string ( filer )",
|
||||
"alert \"Failed Save.\" & return & \"Error message number: \" & string ( filer )"},
|
||||
|
||||
// Non-existent menu cast reference
|
||||
{"warlock", nullptr, kPlatformWindows, "STARBIRD:ABOUT", kScoreScript, 4, DEFAULT_CAST_LIB,
|
||||
1, "installmenu A13", ""},
|
||||
|
||||
// Typo
|
||||
{"rodneyfs", nullptr, kPlatformMacintosh, "Shared Cast", kMovieScript, 496, DEFAULT_CAST_LIB,
|
||||
7, "if the soundLevel <> 7 then set the the soundLevel to 7", "if the soundLevel <> 7 then set the soundLevel to 7"},
|
||||
|
||||
// Patching dead loop which was fixed in v2
|
||||
{"lzone", "", kPlatformMacintosh, "DATA:R-A:Ami-00", kScoreScript, 3, DEFAULT_CAST_LIB,
|
||||
2, "continue", "go \"OUT\""},
|
||||
|
||||
// Garbage at end of statements
|
||||
{"lzone", "", kPlatformMacintosh, "DATA:R-E:ZD2-LAS", kScoreScript, 7, DEFAULT_CAST_LIB,
|
||||
4, "go to the frame 0", "go to the frame"},
|
||||
{"lzone", "", kPlatformMacintosh, "DATA:R-E:zd1-con1", kScoreScript, 27, DEFAULT_CAST_LIB,
|
||||
1, "go to the frame 0", "go to the frame"},
|
||||
{"lzone", "", kPlatformMacintosh, "DATA:R-E:zd1-con1", kScoreScript, 30, DEFAULT_CAST_LIB,
|
||||
4, "go the frame 0", "go to the frame"},
|
||||
{"lzone", "", kPlatformMacintosh, "DATA:R-G:st-c", kScoreScript, 14, DEFAULT_CAST_LIB,
|
||||
1, "go to the frame 0", "go to the frame"},
|
||||
{"lzone", "", kPlatformMacintosh, "DATA:R-G:st-d.mo", kScoreScript, 4, DEFAULT_CAST_LIB,
|
||||
1, "go to the frame 0", "go to the frame"},
|
||||
{"lzone", "", kPlatformMacintosh, "DATA:R-F:ARCH-U.D-1", kScoreScript, 8, DEFAULT_CAST_LIB,
|
||||
1, "GO \"SPACE\" OF MOVIE \"L-ZONE:DATA:R-G:ST-A2\",\"242,197\"",
|
||||
"GO \"SPACE\" OF MOVIE \"L-ZONE:DATA:R-G:ST-A2\""},
|
||||
|
||||
|
||||
{"lingoexpo", "", kPlatformMacintosh, "Lingo Expo:Navigator", kMovieScript, 9, DEFAULT_CAST_LIB,
|
||||
97, " append(codeExampleList,\"6,301,302,303,304,305,306\") - KIOSK SCRIPTS",
|
||||
" append(codeExampleList,\"6,301,302,303,304,305,306\")"},
|
||||
|
||||
|
||||
{"jman", "", kPlatformWindows, "mmm:Mars Space Game 05", kMovieScript, 10, DEFAULT_CAST_LIB,
|
||||
68, "set DamageParameter = (gProcessorSpeed/2) + 7)",
|
||||
"set DamageParameter = (gProcessorSpeed/2) + 7"},
|
||||
|
||||
{"jman", "", kPlatformWindows, "MMM:Shared Cast B&W", kMovieScript, 323, DEFAULT_CAST_LIB,
|
||||
187, "set the trails of sprite 19 to 0", "set the locH of sprite 19 to 408"},
|
||||
{"jman", "", kPlatformWindows, "MMM:Shared Cast B&W", kMovieScript, 323, DEFAULT_CAST_LIB,
|
||||
188, "set the locH of sprite 19 to 408", "set the locV of sprite 19 to 168"},
|
||||
{"jman", "", kPlatformWindows, "MMM:Shared Cast B&W", kMovieScript, 323, DEFAULT_CAST_LIB,
|
||||
189, "set the locV of sprite 19 to 168", "set the text of field \"Description\" = description"},
|
||||
{"jman", "", kPlatformWindows, "MMM:Shared Cast B&W", kMovieScript, 323, DEFAULT_CAST_LIB,
|
||||
190, "set the text of field \"Description\" = description", "set the castnum of sprite 19 to the number of cast \"Description\""},
|
||||
{"jman", "", kPlatformWindows, "MMM:Shared Cast B&W", kMovieScript, 323, DEFAULT_CAST_LIB,
|
||||
191, "set the castnum of sprite 19 to the number of cast \"Description\"", "updateStage"},
|
||||
{"jman", "", kPlatformWindows, "MMM:Shared Cast B&W", kMovieScript, 323, DEFAULT_CAST_LIB,
|
||||
192, "updateStage", "set the trails of sprite 19 to 0"},
|
||||
|
||||
|
||||
{"snh", "Hybrid release", kPlatformWindows, "SNHstart", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
3, "changedrive", ""}, // HACK: This macro inserts \x01 after the first character in myCD/myHD
|
||||
{"snh", "Hybrid release", kPlatformWindows, "SNHstart", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
6, "set mytest2 = FileIO(mnew, \"read\" mymovie)", "set mytest2 = FileIO(mnew, \"read\", mymovie)"},
|
||||
{"snh", "Hybrid release", kPlatformWindows, "SNHstart", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
14, "set mytest3 = FileIO(mnew, \"read\" mymovie)", "set mytest3 = FileIO(mnew, \"read\", mymovie)"},
|
||||
|
||||
|
||||
// Ambiguous syntax that's parsed differently between D3 and later versions
|
||||
{"henachoco03", "", kPlatformMacintosh, "xn--oj7cxalkre7cjz1d2agc0e8b1cm", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
183, "locaobject(mLHizikaraHand (rhenka + 1),dotti)", "locaobject(mLHizikaraHand,(rhenka + 1),dotti)"},
|
||||
{"henachoco03", "", kPlatformMacintosh, "xn--oj7cxalkre7cjz1d2agc0e8b1cm", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
196, "locaobject(mRHizikaraHand (rhenka + 1),dotti)", "locaobject(mRHizikaraHand,(rhenka + 1),dotti)"},
|
||||
|
||||
// Same patch applied to the demos, with different line numbers
|
||||
{"henachoco03", "Trial Version", kPlatformMacintosh, "ITA Choco", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
123, "locaobject(mLHizikaraHand (rhenka + 1),dotti)", "locaobject(mLHizikaraHand,(rhenka + 1),dotti)"},
|
||||
{"henachoco03", "Trial Version", kPlatformMacintosh, "ITA Choco", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
136, "locaobject(mRHizikaraHand (rhenka + 1),dotti)", "locaobject(mRHizikaraHand,(rhenka + 1),dotti)"},
|
||||
{"henachoco03", "Demo", kPlatformMacintosh, "Muzukashiihon", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
123, "locaobject(mLHizikaraHand (rhenka + 1),dotti)", "locaobject(mLHizikaraHand,(rhenka + 1),dotti)"},
|
||||
{"henachoco03", "Demo", kPlatformMacintosh, "Muzukashiihon", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
136, "locaobject(mRHizikaraHand (rhenka + 1),dotti)", "locaobject(mRHizikaraHand,(rhenka + 1),dotti)"},
|
||||
|
||||
|
||||
// The same ambiguous syntax as above, in a different disc
|
||||
{"journey2source", "", kPlatformMacintosh, "StartJourney", kScoreScript, 2, DEFAULT_CAST_LIB,
|
||||
2, "set DiskChk = FileIO(mnew,\"read\"¬\"The Source:Put Contents on Hard Drive:Journey to the Source:YZ.DATA\")", "set DiskChk = FileIO(mnew,\"read\",¬\"The Source:Put Contents on Hard Drive:Journey to the Source:YZ.DATA\")"},
|
||||
|
||||
|
||||
// C.H.A.O.S
|
||||
{"chaos", "", kPlatformWindows, "Intro", kCastScript, 10, DEFAULT_CAST_LIB,
|
||||
9, "rHyperPACo \"blank\", 498, 350 gGenPathWay", "rHyperPACo \"blank\", 498, 350, gGenPathWay"},
|
||||
|
||||
|
||||
{"smile", "v1.1", kPlatformMacintosh, "SMILE! The Splattering", kScoreScript, 24, DEFAULT_CAST_LIB,
|
||||
1, "go to frame \"Info b\"If you have not paid ", "go to frame \"Info b\""},
|
||||
|
||||
|
||||
// Hack to fix the undefined sprite collision behaviour relied on by the boar hunt
|
||||
{"wrath", "", kPlatformWindows, "57AM1", kMovieScript, 1, DEFAULT_CAST_LIB,
|
||||
385, "(StartV57a-6) <= YesV57a", " if sprite 5 intersects 3 and StartV57a <= YesV57a + 16 then"},
|
||||
{"wrath", "", kPlatformMacintosh, "Wrath:57AM1", kMovieScript, 1, DEFAULT_CAST_LIB,
|
||||
382, "(StartV57a-6) <= YesV57a", " if sprite 5 intersects 3 and StartV57a <= YesV57a + 16 then"},
|
||||
|
||||
|
||||
{"amandastories", "", kPlatformWindows, "Shared Cast", kMovieScript, 512, DEFAULT_CAST_LIB,
|
||||
55, " set mytest1 = FileIO(mnew, \"read\" mymovie)", " set mytest1 = FileIO(mnew, \"read\", mymovie)"},
|
||||
{"amandastories", "", kPlatformWindows, "Shared Cast", kMovieScript, 512, DEFAULT_CAST_LIB,
|
||||
63, " set mytest2 = FileIO(mnew, \"read\" mymovie)", " set mytest2 = FileIO(mnew, \"read\", mymovie)"},
|
||||
{"amandastories", "", kPlatformWindows, "Shared Cast", kMovieScript, 512, DEFAULT_CAST_LIB,
|
||||
70, " set mytest3 = FileIO(mnew, \"read\" mymovie)", " set mytest3 = FileIO(mnew, \"read\", mymovie)"},
|
||||
{"amandastories", "", kPlatformWindows, "ASstart", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
5, " set mytest = FileIO(mnew, \"read\" mymovie)", " set mytest = FileIO(mnew, \"read\", mymovie)"},
|
||||
{"amandastories", "", kPlatformWindows, "ASstart", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
11, " set mytest2 = FileIO(mnew, \"read\" mymovie)", " set mytest2 = FileIO(mnew, \"read\", mymovie)"},
|
||||
{"amandastories", "", kPlatformWindows, "ASstart", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
19, " set mytest3 = FileIO(mnew, \"read\" mymovie)", " set mytest3 = FileIO(mnew, \"read\", mymovie)"},
|
||||
|
||||
|
||||
{"erikotamuraoz", "Demo", kPlatformMacintosh, "Shared Cast", kMovieScript, 391, DEFAULT_CAST_LIB,
|
||||
21, "", "end repeat"},
|
||||
|
||||
|
||||
{"cts", "Metric", kPlatformMacintosh, "CTS", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
307, " alert(\"Sorry. No keyword was entered for this recipe.)", " alert(\"Sorry. No keyword was entered for this recipe.\")"},
|
||||
{"cts", "Imperial", kPlatformMacintosh, "CTS", kMovieScript, 0, DEFAULT_CAST_LIB,
|
||||
307, " alert(\"Sorry. No keyword was entered for this recipe.)", " alert(\"Sorry. No keyword was entered for this recipe.\")"},
|
||||
|
||||
|
||||
// garbage script
|
||||
{"refixion2", "", kPlatformMacintosh, "data:Movie:ROgo", kScoreScript, 3, DEFAULT_CAST_LIB,
|
||||
1, "Are you sure to cut off KANJI Talk", ""},
|
||||
|
||||
|
||||
{nullptr, nullptr, kPlatformUnknown, nullptr, kNoneScript, 0, 0, 0, nullptr, nullptr}
|
||||
};
|
||||
|
||||
/*
|
||||
* Cosmology of Kyoto has a text entry system, however for the English version
|
||||
* at least you are very unlikely to guess the correct sequence of letters that
|
||||
* constitute a valid answer. This is an attempt to make things fairer by removing
|
||||
* the need for precise whitespace and punctuation. As a fallback, "yes" should
|
||||
* always mean a yes response, and "no" should always mean a no response.
|
||||
*/
|
||||
|
||||
const char *const kyotoTextEntryFix = " \
|
||||
on scrubInput inputString \r\
|
||||
set result = \"\" \r\
|
||||
repeat with x = 1 to the number of chars in inputString \r\
|
||||
if chars(inputString, x, x) = \" \" then continue \r\
|
||||
else if chars(inputString, x, x) = \".\" then continue \r\
|
||||
else if chars(inputString, x, x) = \"!\" then continue \r\
|
||||
else if chars(inputString, x, x) = \"?\" then continue \r\
|
||||
else if chars(inputString, x, x) = \"。\" then continue \r\
|
||||
else \r\
|
||||
set result = result & char x of inputString \r\
|
||||
end if \r\
|
||||
end repeat \r\
|
||||
return result \r\
|
||||
end \r\
|
||||
\r\
|
||||
on checkkaiwa kaiwatrue, kaiwafalse \r\
|
||||
global myparadata \r\
|
||||
if (keyCode() <> 36) and (keyCode() <> 76) then \r\
|
||||
exit \r\
|
||||
end if \r\
|
||||
put \"Original YES options: \" & kaiwatrue \r\
|
||||
put \"Original NO options: \" & kaiwafalse \r\
|
||||
-- yes and no should always give consistent results \r\
|
||||
if kaiwaans = \"yes\" then \r\
|
||||
return \"YES\" \r\
|
||||
else if kaiwaans = \"no\" then \r\
|
||||
return \"NO\" \r\
|
||||
end if \r\
|
||||
-- pre-scrub all input and choices to remove effect of whitespace/punctuation \r\
|
||||
set kaiwaans = scrubInput(field \"KaiwaWindow\") \r\
|
||||
set kaiwatrue = scrubInput(kaiwatrue) \r\
|
||||
set kaiwafalse = scrubInput(kaiwafalse) \r\
|
||||
repeat with y = 1 to the number of items in kaiwatrue \r\
|
||||
if item y of kaiwatrue starts kaiwaans then \r\
|
||||
when keyDown then CheckQuit \r\
|
||||
put EMPTY into field \"KaiwaWindow\" \r\
|
||||
return \"YES\" \r\
|
||||
end if \r\
|
||||
end repeat \r\
|
||||
repeat with n = 1 to the number of items in kaiwafalse \r\
|
||||
if item n of kaiwafalse starts kaiwaans then \r\
|
||||
when keyDown then CheckQuit \r\
|
||||
put EMPTY into field \"KaiwaWindow\" \r\
|
||||
return \"NO\" \r\
|
||||
end if \r\
|
||||
end repeat \r\
|
||||
set kaiwafool to scrubInput(\"あほんだら,ばか,うんこ,しっこ,しね,死ね,うるさい,うるせえ,\" & \"fool,simpleton,stupid person,kill,Shut up!,Get out of my hair!\") \r\
|
||||
repeat with f = 1 to the number of items in kaiwafool \r\
|
||||
if item f of kaiwafool starts kaiwaans then \r\
|
||||
myparadata(maddparadata, 2, 1) \r\
|
||||
when keyDown then CheckQuit \r\
|
||||
put EMPTY into field \"KaiwaWindow\" \r\
|
||||
return \"error\" \r\
|
||||
end if \r\
|
||||
end repeat \r\
|
||||
when keyDown then CheckQuit \r\
|
||||
put EMPTY into field \"KaiwaWindow\" \r\
|
||||
return \"error\" \r\
|
||||
end \r\
|
||||
";
|
||||
|
||||
/*
|
||||
* Virtual Nightclub will try and list all the files from all 26 drive letters
|
||||
* to determine which has the CD. This works, but takes forever.
|
||||
*/
|
||||
|
||||
const char *const vncSkipDetection = " \
|
||||
global cdDriveLetter, gMultiDisk \r\
|
||||
on findVNCVolume \r\
|
||||
set cdDriveLetter to \"D\" \r\
|
||||
set gMultiDisk to 1 \r\
|
||||
return 1 \r\
|
||||
end \r\
|
||||
";
|
||||
|
||||
/*
|
||||
* Virtual Nightclub has a number of cheat codes for debugging.
|
||||
* These are normally enabled by pressing Option + 0, however the
|
||||
* released game has this code stubbed out with a return.
|
||||
*/
|
||||
|
||||
const char *const vncEnableCheats = " \
|
||||
on togCh\r\
|
||||
if getFlag(#cheats) then\r\
|
||||
setFlag(#cheats, 0)\r\
|
||||
setMode(0) -- disable debug logging\r\
|
||||
set the foreColor of field \"viewName_cast\" to 255\r\
|
||||
alert(\"VNC Cheats off\")\r\
|
||||
else\r\
|
||||
if platform() < 256 then\r\
|
||||
set the textFont of field \"viewName_cast\" to \"Monaco\"\r\
|
||||
end if\r\
|
||||
set the foreColor of field \"viewName_cast\" to 172\r\
|
||||
set the textSize of field \"viewName_cast\" to 9\r\
|
||||
setFlag(#cheats)\r\
|
||||
setMode(10) -- enable debug logging\r\
|
||||
alert(\"VNC Cheats on\")\r\
|
||||
end if\r\
|
||||
end\r\
|
||||
";
|
||||
|
||||
/*
|
||||
* AMBER: Journeys Beyond has a check to ensure that the CD and hard disk data are on
|
||||
* different drive letters. ScummVM will pretend that every drive letter contains the
|
||||
* game contents, so we need to hotpatch the CD detection routine to return D:.
|
||||
*/
|
||||
const char *const amberDriveDetectionFix = " \
|
||||
on GetCDLetter tagFile, discNumber\r\
|
||||
return \"D:\"\r\
|
||||
end \r\
|
||||
";
|
||||
|
||||
/* Frankenstein: Through The Eyes Of The Monster uses a projector FRANKIE.EXE, which calls an
|
||||
* identically-named submovie FRANKIE.DIR. For now we can work around this mess by referring to
|
||||
* the full "path" of the embedded submovie so path detection doesn't collide with FRANKIE.EXE.
|
||||
*/
|
||||
const char *const frankensteinSwapFix = " \
|
||||
on exitFrame \r\
|
||||
go(1, \"FRANKIE\\FRANKIE.DIR\")\r\
|
||||
end \r\
|
||||
";
|
||||
|
||||
/* GADGET: Past As Future was released on 4 CDs, and detects which CD is present by reading
|
||||
* a file "diskid.txt". Replace this with the honour system so we can support merging the
|
||||
* contents of all 4 discs.
|
||||
*/
|
||||
const char *const gadgetPafDetectionFixAlert = " \
|
||||
on exitFrame \r\
|
||||
end \r\
|
||||
";
|
||||
const char *const gadgetPafDetectionFix12 = " \
|
||||
on exitFrame \r\
|
||||
go(\"start-ok\")\r\
|
||||
end \r\
|
||||
";
|
||||
const char *const gadgetPafDetectionFix13 = " \
|
||||
on exitFrame \r\
|
||||
go(\"load-ok\")\r\
|
||||
end \r\
|
||||
";
|
||||
const char *const gadgetPafDetectionFix4 = " \
|
||||
on exitFrame \r\
|
||||
go(\"eject1-ok\")\r\
|
||||
end \r\
|
||||
";
|
||||
const char *const gadgetPafDetectionFix6 = " \
|
||||
on exitFrame \r\
|
||||
go(\"eject3-ok\")\r\
|
||||
end \r\
|
||||
";
|
||||
const char *const gadgetPafDetectionFix9 = " \
|
||||
on exitFrame \r\
|
||||
go(\"eject2-ok\")\r\
|
||||
end \r\
|
||||
";
|
||||
|
||||
/*
|
||||
* Pink Gear Collection has a check to ensure that the CD and hard disk data are on
|
||||
* different drive letters by checking if "PINKPINK.TXT" is the first file in the
|
||||
* "PG_WORLD\PINKCD" folder. Later, it iterates over every drive letter to find the CD
|
||||
* using the same method. Removing this check as ScummVM will pretend that every drive
|
||||
* letter contains the game contents.
|
||||
*/
|
||||
const char *const pinkGearDriveDetectionFix1 = " \
|
||||
on startMovie\r\
|
||||
global oricolor, projname, mtype\r\
|
||||
cursor(200)\r\
|
||||
set oricolor to the colorDepth\r\
|
||||
set projname to the pathName\r\
|
||||
if oricolor <> 8 then\r\
|
||||
sound fadeIn 1, 1 * 60\r\
|
||||
puppetSound(\"BAMEN11k\")\r\
|
||||
go(\"noH2\")\r\
|
||||
else\r\
|
||||
set mtype to 2\r\
|
||||
go(\"01\")\r\
|
||||
end if\r\
|
||||
";
|
||||
|
||||
const char *const pinkGearDriveDetectionFix2 = " \
|
||||
on exitFrame\r\
|
||||
go(1, \"C:\\PG_WORLD\\A_IN01\")\r\
|
||||
";
|
||||
|
||||
/*
|
||||
* Mission Code: Millennium has some drive detection code which prevents the game from loading
|
||||
* if it detects DESTINA.MLD is present "on the hard disk". Provide the same code without that check.
|
||||
*/
|
||||
const char *const mcmillenniumDriveDetectionFix = "\
|
||||
on initPaths\r\
|
||||
global PD, theCDPath, theHDPath, theVCAudioPath, theNotePath, proxPath\r\
|
||||
if the machineType = 256 then\r\
|
||||
set PD to \"\\\"\r\
|
||||
else\r\
|
||||
set PD to \":\"\r\
|
||||
end if\r\
|
||||
if the machineType = 256 then\r\
|
||||
set theCDPath to getAt(the searchPaths, 2)\r\
|
||||
else\r\
|
||||
if checkFileExists(the pathName & \"DESTINA.MLD\") = 1 then\r\
|
||||
set theCDPath to the pathName\r\
|
||||
else\
|
||||
set theCDPath to \"Millennium:\"\r\
|
||||
end if\r\
|
||||
end if\r\
|
||||
set theHDPath to the pathName\r\
|
||||
set theVCAudioPath to theCDPath & \"AUDIO\" & PD & \"VIDCOM\" & PD\r\
|
||||
set theNotePath to the pathName\r\
|
||||
set proxPath to theCDPath & \"prox\" & PD\r\
|
||||
end\r\
|
||||
";
|
||||
|
||||
/*
|
||||
* Mission Code: Millennium has a bizarre method of checking the dimensions of the screen by
|
||||
* measuring the stage position of a 512x384 movie and seeing if it matches 640x480.
|
||||
* Even when forcing desktop mode this doesn't match up exactly, so patch it out.
|
||||
*/
|
||||
const char *const mcmillenniumResDetectionFix = "\
|
||||
on getRes\r\
|
||||
end\r\
|
||||
";
|
||||
|
||||
/*
|
||||
* GORD@K has a complicated CD detection method which includes writing a temp file to the CD
|
||||
* drive. Since this always works, we have to stub out the entire method.
|
||||
*/
|
||||
const char *const gordakDetectionFix = "\
|
||||
on checkFiles\r\
|
||||
go to movie \"gordak\\intro.dxr\"\r\
|
||||
end\r\
|
||||
";
|
||||
|
||||
struct ScriptHandlerPatch {
|
||||
const char *gameId;
|
||||
const char *extra;
|
||||
Common::Platform platform; // Specify kPlatformUnknown for skipping platform check
|
||||
const char *movie;
|
||||
ScriptType type;
|
||||
uint16 id;
|
||||
uint16 castLib;
|
||||
const char *const *handlerBody;
|
||||
} const scriptHandlerPatches[] = {
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\dd_dairi\\shared.dxr", kMovieScript, 906, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\findfldr\\shared.dxr", kMovieScript, 802, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\ichi\\shared.dxr", kMovieScript, 906, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\jigoku\\shared.dxr", kMovieScript, 840, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\kusamura\\shared.dxr", kMovieScript, 906, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\map01\\shared.dxr", kMovieScript, 906, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\map02\\shared.dxr", kMovieScript, 906, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\map03\\shared.dxr", kMovieScript, 906, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\map04\\shared.dxr", kMovieScript, 906, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\opening\\shared.dxr", kMovieScript, 802, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\rajoumon\\shared.dxr", kMovieScript, 840, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"kyoto", nullptr, kPlatformWindows, "ck_data\\rokudou\\shared.dxr", kMovieScript, 846, DEFAULT_CAST_LIB, &kyotoTextEntryFix},
|
||||
{"vnc", nullptr, kPlatformWindows, "VNC\\VNC.EXE", kMovieScript, 57, DEFAULT_CAST_LIB, &vncSkipDetection},
|
||||
{"vnc", nullptr, kPlatformWindows, "VNC2\\SHARED.DXR", kMovieScript, 1248, DEFAULT_CAST_LIB, &vncEnableCheats},
|
||||
{"amber", nullptr, kPlatformWindows, "AMBER_F\\AMBER_JB.EXE", kMovieScript, 7, DEFAULT_CAST_LIB, &amberDriveDetectionFix},
|
||||
{"frankenstein", nullptr, kPlatformWindows, "FRANKIE.EXE", kScoreScript, 21, DEFAULT_CAST_LIB, &frankensteinSwapFix},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 2, DEFAULT_CAST_LIB, &gadgetPafDetectionFixAlert},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 8, DEFAULT_CAST_LIB, &gadgetPafDetectionFixAlert},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 10, DEFAULT_CAST_LIB, &gadgetPafDetectionFixAlert},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 11, DEFAULT_CAST_LIB, &gadgetPafDetectionFixAlert},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 18, DEFAULT_CAST_LIB, &gadgetPafDetectionFixAlert},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 12, DEFAULT_CAST_LIB, &gadgetPafDetectionFix12},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 13, DEFAULT_CAST_LIB, &gadgetPafDetectionFix13},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 4, DEFAULT_CAST_LIB, &gadgetPafDetectionFix4},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\DISKCNG.DIR", kScoreScript, 6, DEFAULT_CAST_LIB, &gadgetPafDetectionFix6},
|
||||
{"gadgetpaf", nullptr, kPlatformWindows, "GADGET\\GADGET.EXE", kScoreScript, 9, DEFAULT_CAST_LIB, &gadgetPafDetectionFix9},
|
||||
{"pinkgear", nullptr, kPlatformWindows, "GOTOPINK.EXE", kMovieScript, 4, DEFAULT_CAST_LIB, &pinkGearDriveDetectionFix1},
|
||||
{"pinkgear", nullptr, kPlatformWindows, "GOTOPINK.EXE", kScoreScript, 6, DEFAULT_CAST_LIB, &pinkGearDriveDetectionFix2},
|
||||
{"mcmillennium", nullptr, kPlatformWindows, "PC\\MILL.EXE", kMovieScript, 15, DEFAULT_CAST_LIB, &mcmillenniumResDetectionFix},
|
||||
{"mcmillennium", nullptr, kPlatformMacintosh, "Mission Code Millennium:Mission Code Millennium", kMovieScript, 15, DEFAULT_CAST_LIB, &mcmillenniumResDetectionFix},
|
||||
{"mcmillennium", nullptr, kPlatformWindows, "PC\\SHARED.DXR", kMovieScript, 1013, DEFAULT_CAST_LIB, &mcmillenniumDriveDetectionFix},
|
||||
{"mcmillennium", nullptr, kPlatformMacintosh, "Mission Code Millennium:SHARED.Dxr", kMovieScript, 1013, DEFAULT_CAST_LIB, &mcmillenniumDriveDetectionFix},
|
||||
{"gordak", nullptr, kPlatformWindows, "GORDAKCD.EXE", kMovieScript, 2, DEFAULT_CAST_LIB, &gordakDetectionFix},
|
||||
{nullptr, nullptr, kPlatformUnknown, nullptr, kNoneScript, 0, 0, nullptr},
|
||||
|
||||
};
|
||||
|
||||
void LingoArchive::patchScriptHandler(ScriptType type, CastMemberID id) {
|
||||
const ScriptHandlerPatch *patch = scriptHandlerPatches;
|
||||
Common::String movie = g_director->getCurrentPath() + cast->getMacName();
|
||||
|
||||
// So far, we have not many patches, so do linear lookup
|
||||
while (patch->gameId) {
|
||||
// First, we do cheap comparisons
|
||||
if (patch->type != type || patch->id != id.member || patch->castLib != id.castLib ||
|
||||
(patch->platform != kPlatformUnknown && patch->platform != g_director->getPlatform())) {
|
||||
patch++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now expensive ones
|
||||
U32String moviename = punycode_decode(patch->movie);
|
||||
if (movie.compareToIgnoreCase(moviename) || strcmp(patch->gameId, g_director->getGameId())
|
||||
|| (patch->extra && strcmp(patch->extra, g_director->getExtra()))) {
|
||||
patch++;
|
||||
continue;
|
||||
}
|
||||
patchCode(Common::U32String(*patch->handlerBody), patch->type, patch->id);
|
||||
patch++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Common::U32String LingoCompiler::patchLingoCode(const Common::U32String &line, LingoArchive *archive, ScriptType type, CastMemberID id, int linenum) {
|
||||
if (!archive)
|
||||
return line;
|
||||
|
||||
const ScriptPatch *patch = scriptPatches;
|
||||
Common::String movie = g_director->getCurrentPath() + archive->cast->getMacName();
|
||||
|
||||
// So far, we have not many patches, so do linear lookup
|
||||
while (patch->gameId) {
|
||||
// First, we do cheap comparisons
|
||||
if (patch->type != type || patch->id != id.member || patch->castLib != id.castLib || patch->linenum != linenum ||
|
||||
(patch->platform != kPlatformUnknown && patch->platform != g_director->getPlatform())) {
|
||||
patch++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now expensive ones
|
||||
U32String moviename = punycode_decode(patch->movie);
|
||||
if (movie.compareToIgnoreCase(moviename) || strcmp(patch->gameId, g_director->getGameId())
|
||||
|| (patch->extra && strcmp(patch->extra, g_director->getExtra()))) {
|
||||
patch++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now do a safeguard
|
||||
if (!line.contains(Common::U32String(patch->orig)) && line.encode().c_str() != Common::U32String()) {
|
||||
warning("Lingo::patchLingoCode(): Unmatched patch for '%s', '%s' %s:%s @ %d. Expecting '%s' but got '%s'",
|
||||
patch->gameId, patch->movie, scriptType2str(type), id.asString().c_str(), linenum,
|
||||
patch->orig, line.encode().c_str());
|
||||
return line;
|
||||
}
|
||||
|
||||
// Now everything matched
|
||||
warning("Lingo::patchLingoCode(): Applied a patch for '%s', '%s' %s:%s @ %d. \"%s\" -> \"%s\"",
|
||||
patch->gameId, patch->movie, scriptType2str(type), id.asString().c_str(), linenum,
|
||||
patch->orig, patch->replace);
|
||||
return Common::U32String(patch->replace);
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
297
engines/director/lingo/lingo-preprocessor.cpp
Normal file
297
engines/director/lingo/lingo-preprocessor.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "director/director.h"
|
||||
#include "director/cast.h"
|
||||
#include "director/movie.h"
|
||||
#include "director/lingo/lingo-codegen.h"
|
||||
#include "director/types.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
bool isspec(Common::u32char_type_t c) {
|
||||
if (c > 127)
|
||||
return false;
|
||||
|
||||
return strchr("-+*/%^:,()><&[]=", (char)c) != nullptr;
|
||||
}
|
||||
|
||||
static Common::U32String nexttok(const Common::u32char_type_t *s, const Common::u32char_type_t **newP = nullptr) {
|
||||
Common::U32String res;
|
||||
|
||||
// Scan first non-whitespace
|
||||
while (*s && (*s == ' ' || *s == '\t' || *s == CONTINUATION)) // If we see a whitespace
|
||||
s++;
|
||||
|
||||
if (*s == '"') { // If it is a string then scan till end quote
|
||||
res += *s++;
|
||||
|
||||
while (*s && *s != '"')
|
||||
res += *s++;
|
||||
|
||||
if (*s == '"')
|
||||
res += *s++;
|
||||
} else if (Common::isAlnum(*s) || *s == '#' || *s == '.') {
|
||||
// Now copy everything till whitespace
|
||||
while (*s && (Common::isAlnum(*s) || *s == '.' || *s == '#' || *s == '_'))
|
||||
res += *s++;
|
||||
} else {
|
||||
while (*s && isspec(*s))
|
||||
res += *s++;
|
||||
}
|
||||
|
||||
if (newP)
|
||||
*newP = s;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Common::U32String LingoCompiler::codePreprocessor(const Common::U32String &code, LingoArchive *archive, ScriptType type, CastMemberID id, uint32 flags) {
|
||||
const Common::u32char_type_t *s = code.c_str();
|
||||
Common::U32String res;
|
||||
if (debugChannelSet(2, kDebugPreprocess)) {
|
||||
Common::String movie = g_director->getCurrentPath();
|
||||
if (archive)
|
||||
movie += archive->cast->getMacName();
|
||||
debugC(2, kDebugPreprocess, "LingoCompiler::codePreprocessor: \"%s\", %s, %d, %d", movie.c_str(), scriptType2str(type), id.member, id.castLib);
|
||||
}
|
||||
|
||||
// We start from processing the continuation symbols
|
||||
// (The continuation symbol is \xC2 in Mac Roman, \xAC in Unicode.)
|
||||
// \xAC\n -> \xAC
|
||||
// This will greatly simplify newline processing, still leaving
|
||||
// the line number tracking intact
|
||||
while (*s) {
|
||||
if (*s == CONTINUATION) {
|
||||
res += *s++;
|
||||
if (!*s) // Who knows, maybe it is the last symbol in the script
|
||||
break;
|
||||
s++;
|
||||
continue;
|
||||
} else if (*s == 0xFF82) { // Misparsed Japanese continuation
|
||||
if (!*(s+1)) { // EOS - write as is and finish up
|
||||
res += *s++;
|
||||
break;
|
||||
}
|
||||
// Next character isn't a newline; write as is and keep
|
||||
// going.
|
||||
if (*(s+1) != 13) {
|
||||
res += *s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
s++;
|
||||
// This is a bit of a hack; in MacJapanese the codepoint at
|
||||
// C2 is the half-width katakana "tsu", so ScummVM is
|
||||
// getting confused about what's here in the script after
|
||||
// translating from MacJapanese to Unicode.
|
||||
// Just swap the character out for the right Unicode character here.
|
||||
// This can be removed if Lingo parsing is reworked to act
|
||||
// on the original raw bytes instead of a Unicode translation.
|
||||
res += CONTINUATION;
|
||||
if (!*s)
|
||||
break;
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
res += *s++;
|
||||
}
|
||||
|
||||
Common::U32String tmp(res);
|
||||
res.clear();
|
||||
s = tmp.c_str();
|
||||
|
||||
// Strip comments
|
||||
bool inString = false;
|
||||
while (*s) {
|
||||
if (*s == '"')
|
||||
inString = !inString;
|
||||
|
||||
if (*s == '\r' || *s == '\n') // Lingo does not allow multiline strings
|
||||
inString = false;
|
||||
|
||||
if (!inString && *s == '-' && *(s + 1) == '-') { // At the end of the line we will have \0
|
||||
while (*s && *s != '\r' && *s != '\n')
|
||||
s++;
|
||||
}
|
||||
|
||||
if (*s == '\r')
|
||||
res += '\n';
|
||||
else if (*s)
|
||||
res += *s;
|
||||
|
||||
if (*s)
|
||||
s++;
|
||||
}
|
||||
|
||||
tmp = res;
|
||||
res.clear();
|
||||
|
||||
// Strip trailing whitespaces
|
||||
s = tmp.c_str();
|
||||
while (*s) {
|
||||
if (*s == ' ' || *s == '\t' || *s == CONTINUATION) { // If we see a whitespace
|
||||
const Common::u32char_type_t *ps = s; // Remember where we saw it
|
||||
|
||||
while (*ps == ' ' || *ps == '\t' || *ps == CONTINUATION) // Scan until end of whitespaces
|
||||
ps++;
|
||||
|
||||
if (*ps) { // Not end of the string
|
||||
if (*ps == '\n') { // If it is newline, then we continue from it
|
||||
s = ps;
|
||||
} else { // It is not a newline
|
||||
while (s != ps) { // Add all whitespaces
|
||||
res += *s;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*s)
|
||||
res += *s;
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
if (flags & kLPPSimple)
|
||||
return res;
|
||||
|
||||
tmp = res;
|
||||
s = tmp.c_str();
|
||||
res.clear();
|
||||
|
||||
Common::U32String line, tok, res1;
|
||||
int linenumber = 1;
|
||||
bool defFound = false;
|
||||
|
||||
const Common::U32String macro("macro"), factory("factory"), on("on"), global("global"), property("property"),
|
||||
mci("mci");
|
||||
|
||||
while (*s) {
|
||||
line.clear();
|
||||
res1.clear();
|
||||
|
||||
// Get next line
|
||||
int continuationCount = 0;
|
||||
while (*s && *s != '\n') { // If we see a whitespace
|
||||
res1 += *s;
|
||||
line += tolower(*s++);
|
||||
|
||||
if (*s == CONTINUATION) {
|
||||
linenumber++;
|
||||
continuationCount++;
|
||||
}
|
||||
}
|
||||
debugC(2, kDebugPreprocess, "line %d: '%s'", linenumber, line.encode().c_str());
|
||||
|
||||
if (!defFound && (type == kMovieScript || type == kCastScript) && (g_director->getVersion() < 400 || g_director->getCurrentMovie()->_allowOutdatedLingo)) {
|
||||
tok = nexttok(line.c_str());
|
||||
if (tok.equals(macro) || tok.equals(factory)) {
|
||||
defFound = true;
|
||||
} else if (!(flags & kLPPForceD2)) {
|
||||
if (tok.equals(on) || tok.equals(global) || tok.equals(property)) {
|
||||
defFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!defFound) {
|
||||
debugC(2, kDebugPreprocess, "skipping line before first definition");
|
||||
for (int i = 0; i < continuationCount; i++) {
|
||||
res += CONTINUATION;
|
||||
}
|
||||
linenumber++;
|
||||
if (*s) // copy newline symbol
|
||||
res += *s++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// In MultiMedia Movie format, .MMM files used by Microsoft
|
||||
// 'mci' keyword is followed by the unquoted commands, e.g.
|
||||
// mci close all
|
||||
// mci play wave to 15228 hold
|
||||
//
|
||||
// Since Director requires them in a single thing, we add
|
||||
// quotes around
|
||||
const Common::u32char_type_t *contLine;
|
||||
tok = nexttok(line.c_str(), &contLine);
|
||||
|
||||
if (tok.equals(mci) && *contLine != 0 && !Common::U32String(contLine).contains('\"')) {
|
||||
// Scan first non-whitespace
|
||||
while (*contLine && (*contLine == ' ' || *contLine == '\t' || *contLine == CONTINUATION)) // If we see a whitespace
|
||||
contLine++;
|
||||
|
||||
res1 = Common::U32String::format("%S \"%S\"", tok.c_str(), contLine);
|
||||
|
||||
debugC(2, kDebugPreprocess, "wrapped mci command into quotes");
|
||||
}
|
||||
|
||||
res1 = patchLingoCode(res1, archive, type, id, linenumber);
|
||||
|
||||
res += res1;
|
||||
|
||||
linenumber++; // We do it here because of 'continue' statements
|
||||
|
||||
if (*s) // copy newline symbol
|
||||
res += *s++;
|
||||
}
|
||||
|
||||
// Make the parser happier when there is no newline at the end
|
||||
res += '\n';
|
||||
|
||||
debugC(2, kDebugPreprocess, "#############\n%s\n#############", res.encode().c_str());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
MethodHash LingoCompiler::prescanMethods(const Common::U32String &code) {
|
||||
const Common::u32char_type_t *s = code.c_str();
|
||||
Common::U32String line, tok;
|
||||
MethodHash res;
|
||||
|
||||
const Common::U32String macro("macro"), on("on"), method("method");
|
||||
|
||||
while (*s) {
|
||||
line.clear();
|
||||
|
||||
// Get next line
|
||||
while (*s && *s != '\n')
|
||||
line += tolower(*s++);
|
||||
|
||||
const Common::u32char_type_t *contLine;
|
||||
tok = nexttok(line.c_str(), &contLine);
|
||||
|
||||
if ((tok.equals(macro) || tok.equals(on) || tok.equals(method)) && *contLine != 0) {
|
||||
Common::U32String methodname = nexttok(contLine);
|
||||
|
||||
res[methodname] = true;
|
||||
}
|
||||
|
||||
if (*s)
|
||||
s++; // Newline symbol
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
2830
engines/director/lingo/lingo-the.cpp
Normal file
2830
engines/director/lingo/lingo-the.cpp
Normal file
File diff suppressed because it is too large
Load Diff
343
engines/director/lingo/lingo-the.h
Normal file
343
engines/director/lingo/lingo-the.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_LINGO_THE_H
|
||||
#define DIRECTOR_LINGO_LINGO_THE_H
|
||||
|
||||
namespace Director {
|
||||
|
||||
enum TheEntityType {
|
||||
kTheNOEntity = 0,
|
||||
kTheObject = 1,
|
||||
kTheActiveWindow,
|
||||
kTheActorList,
|
||||
kTheAlertHook,
|
||||
kTheApplicationPath,
|
||||
kTheBeepOn,
|
||||
kTheButtonStyle,
|
||||
kTheCast,
|
||||
kTheCastLib,
|
||||
kTheCastLibs,
|
||||
kTheCastMembers,
|
||||
kTheCenterStage,
|
||||
kTheChars,
|
||||
kTheCheckBoxAccess,
|
||||
kTheCheckBoxType,
|
||||
kTheChunk,
|
||||
kTheClickLoc,
|
||||
kTheClickOn,
|
||||
kTheColorDepth,
|
||||
kTheColorQD,
|
||||
kTheCommandDown,
|
||||
kTheControlDown,
|
||||
kTheCpuHogTicks,
|
||||
kTheCurrentSpriteNum,
|
||||
kTheDate,
|
||||
kTheDeskTopRectList,
|
||||
kTheDigitalVideoTimeScale,
|
||||
kTheDoubleClick,
|
||||
kTheEmulateMultiButtonMouse,
|
||||
kTheExitLock,
|
||||
kTheField,
|
||||
kTheFixStageSize,
|
||||
kTheFloatPrecision,
|
||||
kTheFrame,
|
||||
kTheFrameLabel,
|
||||
kTheFramePalette,
|
||||
kTheFrameScript,
|
||||
kTheFrameSound1,
|
||||
kTheFrameSound2,
|
||||
kTheFrameTempo,
|
||||
kTheFrameTransition,
|
||||
kTheFreeBlock,
|
||||
kTheFreeBytes,
|
||||
kTheFrontWindow,
|
||||
kTheFullColorPermit,
|
||||
kTheIdleHandlerPeriod,
|
||||
kTheIdleLoadMode,
|
||||
kTheIdleLoadPeriod,
|
||||
kTheIdleLoadTag,
|
||||
kTheIdleReadChunkSize,
|
||||
kTheImageDirect,
|
||||
kTheItemDelimiter,
|
||||
kTheItems,
|
||||
kTheKey,
|
||||
kTheKeyCode,
|
||||
kTheKeyDownScript,
|
||||
kTheKeyPressed,
|
||||
kTheKeyUpScript,
|
||||
kTheLabelList,
|
||||
kTheLastClick,
|
||||
kTheLastEvent,
|
||||
kTheLastFrame,
|
||||
kTheLastKey,
|
||||
kTheLastRoll,
|
||||
kTheLines,
|
||||
kTheMachineType,
|
||||
kTheMaxInteger,
|
||||
kTheMemorySize,
|
||||
kTheMenu,
|
||||
kTheMenuItem,
|
||||
kTheMenuItems,
|
||||
kTheMenus,
|
||||
kTheMouseCast,
|
||||
kTheMouseChar,
|
||||
kTheMouseDown,
|
||||
kTheMouseDownScript,
|
||||
kTheMouseH,
|
||||
kTheMouseItem,
|
||||
kTheMouseLine,
|
||||
kTheMouseMember,
|
||||
kTheMouseUp,
|
||||
kTheMouseUpScript,
|
||||
kTheMouseV,
|
||||
kTheMouseWord,
|
||||
kTheMovie,
|
||||
kTheMovieFileFreeSize,
|
||||
kTheMovieFileSize,
|
||||
kTheMovieName,
|
||||
kTheMoviePath,
|
||||
kTheMultiSound,
|
||||
kTheNetThrottleTicks,
|
||||
kTheOptionDown,
|
||||
kTheOrganizationName,
|
||||
kTheParamCount,
|
||||
kThePathName,
|
||||
kThePauseState,
|
||||
kThePerFrameHook,
|
||||
kThePi,
|
||||
kThePlatform,
|
||||
kThePreloadEventAbort,
|
||||
kThePreLoadRAM,
|
||||
kTheProductName,
|
||||
kTheProductVersion,
|
||||
kTheQuickTimePresent,
|
||||
kTheRandomSeed,
|
||||
kTheResult,
|
||||
kTheRightMouseDown,
|
||||
kTheRightMouseUp,
|
||||
kTheRollOver,
|
||||
kTheRomanLingo,
|
||||
kTheRunMode,
|
||||
kTheSafePlayer,
|
||||
kTheScore,
|
||||
kTheScummvmVersion, // set the Director version via lingo in tests
|
||||
kTheSearchCurrentFolder,
|
||||
kTheSearchPath,
|
||||
kTheSearchPaths,
|
||||
kTheSelection,
|
||||
kTheSelEnd,
|
||||
kTheSelStart,
|
||||
kTheSerialNumber,
|
||||
kTheShiftDown,
|
||||
kTheSoundEntity,
|
||||
kTheSoundEnabled,
|
||||
kTheSoundKeepDevice,
|
||||
kTheSoundLevel,
|
||||
kTheSprite,
|
||||
kTheSqrt,
|
||||
kTheStage,
|
||||
kTheStageBottom,
|
||||
kTheStageColor,
|
||||
kTheStageLeft,
|
||||
kTheStageRight,
|
||||
kTheStageTop,
|
||||
kTheStillDown,
|
||||
kTheSwitchColorDepth,
|
||||
kTheTicks,
|
||||
kTheTime,
|
||||
kTheTimeoutKeyDown,
|
||||
kTheTimeoutLapsed,
|
||||
kTheTimeoutLength,
|
||||
kTheTimeoutMouse,
|
||||
kTheTimeoutPlay,
|
||||
kTheTimeoutScript,
|
||||
kTheTimer,
|
||||
kTheTrace,
|
||||
kTheTraceLoad,
|
||||
kTheTraceLogFile,
|
||||
kTheUpdateMovieEnabled,
|
||||
kTheUserName,
|
||||
kTheVideoForWindowsPresent,
|
||||
kTheWindow,
|
||||
kTheWindowList,
|
||||
kTheWords,
|
||||
kTheXtras,
|
||||
kTheMaxTheEntityType // This must be always last
|
||||
};
|
||||
|
||||
enum TheFieldType {
|
||||
kTheNOField = 0,
|
||||
kTheAbbr = 1,
|
||||
kTheAntiAlias,
|
||||
kTheAutoTab,
|
||||
kTheBackColor,
|
||||
kTheBlend,
|
||||
kTheBorder,
|
||||
kTheBottom,
|
||||
kTheBoxDropShadow,
|
||||
kTheBoxType,
|
||||
kTheButtonType,
|
||||
kTheCastLibNum,
|
||||
kTheCastNum,
|
||||
kTheCastType,
|
||||
kTheCenter,
|
||||
kTheChangeArea,
|
||||
kTheChannelCount,
|
||||
kTheCheckMark,
|
||||
kTheChunkSize,
|
||||
kTheConstraint,
|
||||
kTheController,
|
||||
kTheCrop,
|
||||
kTheCuePointNames,
|
||||
kTheCuePointTimes,
|
||||
kTheCurrentTime,
|
||||
kTheCursor,
|
||||
kTheDepth,
|
||||
kTheDigitalVideoType,
|
||||
kTheDirectToStage,
|
||||
kTheDrawRect,
|
||||
kTheDropShadow,
|
||||
kTheDuration,
|
||||
kTheEditable,
|
||||
kTheEditableText,
|
||||
kTheEnabled,
|
||||
kTheFileName,
|
||||
kTheFilled,
|
||||
kTheFlipH,
|
||||
kTheFlipV,
|
||||
kTheForeColor,
|
||||
kTheFrameRate,
|
||||
kTheHeight,
|
||||
kTheHilite,
|
||||
kTheImmediate,
|
||||
kTheInk,
|
||||
kTheInterface,
|
||||
kTheLast,
|
||||
kTheLeft,
|
||||
kTheLineCount,
|
||||
kTheLineSize,
|
||||
kTheLoaded,
|
||||
kTheLoc,
|
||||
kTheLocH,
|
||||
kTheLocV,
|
||||
kTheLong,
|
||||
kTheLoop,
|
||||
kTheMargin,
|
||||
kTheMedia,
|
||||
kTheMediaBusy,
|
||||
kTheMediaReady,
|
||||
kTheMember,
|
||||
kTheMemberNum,
|
||||
kTheModal,
|
||||
kTheModified,
|
||||
kTheMostRecentCuePoint,
|
||||
kTheMoveableSprite,
|
||||
kTheMovieRate,
|
||||
kTheMovieTime,
|
||||
kTheName,
|
||||
kTheNumber,
|
||||
kThePageHeight,
|
||||
kThePalette,
|
||||
kThePaletteMapping,
|
||||
kThePaletteRef,
|
||||
kThePattern,
|
||||
kThePausedAtStart,
|
||||
kThePicture,
|
||||
kThePreLoad,
|
||||
kThePreLoadMode,
|
||||
kThePuppet,
|
||||
kThePurgePriority,
|
||||
kTheRect,
|
||||
kTheRegPoint,
|
||||
kTheRight,
|
||||
kTheSampleRate,
|
||||
kTheSampleSize,
|
||||
kTheScoreColor,
|
||||
kTheScoreSelection,
|
||||
kTheScript,
|
||||
kTheScriptInstanceList,
|
||||
kTheScriptNum,
|
||||
kTheScriptText,
|
||||
kTheScriptType,
|
||||
kTheScriptsEnabled,
|
||||
kTheSelectionField,
|
||||
kTheSetTrackEnabled,
|
||||
kTheShapeType,
|
||||
kTheShort,
|
||||
kTheSize,
|
||||
kTheSound,
|
||||
kTheSourceRect,
|
||||
kTheSpriteNum,
|
||||
kTheStartTime,
|
||||
kTheStopTime,
|
||||
kTheStrech,
|
||||
kTheStretch,
|
||||
kTheText,
|
||||
kTheTextAlign,
|
||||
kTheTextFont,
|
||||
kTheTextHeight,
|
||||
kTheTextSize,
|
||||
kTheTextStyle,
|
||||
kTheTimeScale,
|
||||
kTheTitle,
|
||||
kTheTitleVisible,
|
||||
kTheTop,
|
||||
kTheTrackEnabled,
|
||||
kTheTrackNextKeyTime,
|
||||
kTheTrackNextSampleTime,
|
||||
kTheTrackPreviousKeyTime,
|
||||
kTheTrackPreviousSampleTime,
|
||||
kTheTrackText,
|
||||
kTheTrails,
|
||||
kTheTransitionType,
|
||||
kTheTweened,
|
||||
kTheType,
|
||||
kTheUpdateLock,
|
||||
kTheVideo,
|
||||
kTheVisibility,
|
||||
kTheVisible,
|
||||
kTheVolume,
|
||||
kTheWidth,
|
||||
kTheWindowType,
|
||||
kTheWordWrap,
|
||||
kTheScrollTop,
|
||||
kTheMaxTheFieldType // This must be always last
|
||||
};
|
||||
|
||||
struct TheEntity {
|
||||
TheEntityType entity;
|
||||
const char *name;
|
||||
bool hasId;
|
||||
int version;
|
||||
bool isFunction;
|
||||
};
|
||||
|
||||
struct TheEntityField {
|
||||
TheEntityType entity;
|
||||
const char *name;
|
||||
TheFieldType field;
|
||||
int version;
|
||||
};
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
126
engines/director/lingo/lingo-utils.cpp
Normal file
126
engines/director/lingo/lingo-utils.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
static const struct CharNormProto {
|
||||
Common::u32char_type_t from;
|
||||
const char *to;
|
||||
} charNormProtos[] = {
|
||||
{ 0x00C0, "a" }, // À - \xCB in Mac Roman, \xC0 in Windows-1252
|
||||
{ 0x00C1, "a" }, // Á - \xE7 in Mac Roman, \xC1 in Windows-1252
|
||||
{ 0x00C2, "a" }, // Â - \xE5 in Mac Roman, \xC2 in Windows-1252
|
||||
{ 0x00C3, "a" }, // Ã - \xCC in Mac Roman, \xC3 in Windows-1252
|
||||
{ 0x00C4, "a" }, // Ä - \x80 in Mac Roman, \xC4 in Windows-1252
|
||||
{ 0x00C5, "a" }, // Å - \x81 in Mac Roman, \xC5 in Windows-1252
|
||||
{ 0x00C6, "ae" }, // Æ - \xAE in Mac Roman, \xC6 in Windows-1252
|
||||
{ 0x00C7, "c" }, // Ç - \x82 in Mac Roman, \xC7 in Windows-1252
|
||||
{ 0x00C8, "e" }, // È - \xE9 in Mac Roman, \xC8 in Windows-1252
|
||||
{ 0x00C9, "e" }, // É - \x83 in Mac Roman, \xC9 in Windows-1252
|
||||
{ 0x00CA, "e" }, // Ê - \xE6 in Mac Roman, \xCA in Windows-1252
|
||||
{ 0x00CB, "e" }, // Ë - \xE8 in Mac Roman, \xCB in Windows-1252
|
||||
{ 0x00CC, "i" }, // Ì - \xED in Mac Roman, \xCC in Windows-1252
|
||||
{ 0x00CD, "i" }, // Í - \xEA in Mac Roman, \xCD in Windows-1252
|
||||
{ 0x00CE, "i" }, // Î - \xEB in Mac Roman, \xCE in Windows-1252
|
||||
{ 0x00CF, "i" }, // Ï - \xEC in Mac Roman, \xCF in Windows-1252
|
||||
{ 0x00D0, "d" }, // Ð - \xD0 in Windows-1252
|
||||
{ 0x00D1, "n" }, // Ñ - \x84 in Mac Roman, \xD1 in Windows-1252
|
||||
{ 0x00D2, "o" }, // Ò - \xF1 in Mac Roman, \xD2 in Windows-1252
|
||||
{ 0x00D3, "o" }, // Ó - \xEE in Mac Roman, \xD3 in Windows-1252
|
||||
{ 0x00D4, "o" }, // Ô - \xEF in Mac Roman, \xD4 in Windows-1252
|
||||
{ 0x00D5, "o" }, // Õ - \xCD in Mac Roman, \xD5 in Windows-1252
|
||||
{ 0x00D6, "o" }, // Ö - \x85 in Mac Roman, \xD6 in Windows-1252
|
||||
{ 0x00D8, "o" }, // Ø - \xAF in Mac Roman, \xD8 in Windows-1252
|
||||
{ 0x00D9, "u" }, // Ù - \xF4 in Mac Roman, \xD9 in Windows-1252
|
||||
{ 0x00DA, "u" }, // Ú - \xF2 in Mac Roman, \xDA in Windows-1252
|
||||
{ 0x00DB, "u" }, // Û - \xF3 in Mac Roman, \xDB in Windows-1252
|
||||
{ 0x00DC, "u" }, // Ü - \x86 in Mac Roman, \xDC in Windows-1252
|
||||
{ 0x00DD, "y" }, // Ý - \xDD in Windows-1252
|
||||
{ 0x00DE, "\xC3\xBE" }, // Þ - \xDE in Windows-1252
|
||||
{ 0x00DF, "s" }, // ß - \xDF in Windows-1252
|
||||
{ 0x00E0, "a" }, // à - \x88 in Mac Roman, \xE0 in Windows-1252
|
||||
{ 0x00E1, "a" }, // á - \x87 in Mac Roman, \xE1 in Windows-1252
|
||||
{ 0x00E2, "a" }, // â - \x89 in Mac Roman, \xE2 in Windows-1252
|
||||
{ 0x00E3, "a" }, // ã - \x8B in Mac Roman, \xE3 in Windows-1252
|
||||
{ 0x00E4, "a" }, // ä - \x8A in Mac Roman, \xE4 in Windows-1252
|
||||
{ 0x00E5, "a" }, // å - \x8C in Mac Roman, \xE5 in Windows-1252
|
||||
{ 0x00E6, "ae" }, // æ - \xBE in Mac Roman, \xE6 in Windows-1252
|
||||
{ 0x00E7, "c" }, // ç - \x8D in Mac Roman, \xE7 in Windows-1252
|
||||
{ 0x00E8, "e" }, // è - \x8F in Mac Roman, \xE8 in Windows-1252
|
||||
{ 0x00E9, "e" }, // é - \x8E in Mac Roman, \xE9 in Windows-1252
|
||||
{ 0x00EA, "e" }, // ê - \x90 in Mac Roman, \xEA in Windows-1252
|
||||
{ 0x00EB, "e" }, // ë - \x91 in Mac Roman, \xEB in Windows-1252
|
||||
{ 0x00EC, "i" }, // ì - \x93 in Mac Roman, \xEC in Windows-1252
|
||||
{ 0x00ED, "i" }, // í - \x92 in Mac Roman, \xED in Windows-1252
|
||||
{ 0x00EE, "i" }, // î - \x94 in Mac Roman, \xEE in Windows-1252
|
||||
{ 0x00EF, "i" }, // ï - \x95 in Mac Roman, \xEF in Windows-1252
|
||||
{ 0x00F0, "d" }, // ð - \xF0 in Windows-1252
|
||||
{ 0x00F1, "n" }, // ñ - \x96 in Mac Roman, \xF1 in Windows-1252
|
||||
{ 0x00F2, "o" }, // ò - \x98 in Mac Roman, \xF2 in Windows-1252
|
||||
{ 0x00F3, "o" }, // ó - \x97 in Mac Roman, \xF3 in Windows-1252
|
||||
{ 0x00F4, "o" }, // ô - \x99 in Mac Roman, \xF4 in Windows-1252
|
||||
{ 0x00F5, "o" }, // õ - \x9B in Mac Roman, \xF5 in Windows-1252
|
||||
{ 0x00F6, "o" }, // ö - \x9A in Mac Roman, \xF6 in Windows-1252
|
||||
{ 0x00F8, "o" }, // ø - \xBF in Mac Roman, \xF8 in Windows-1252
|
||||
{ 0x00F9, "u" }, // ù - \x9D in Mac Roman, \xF9 in Windows-1252
|
||||
{ 0x00FA, "u" }, // ú - \x9C in Mac Roman, \xFA in Windows-1252
|
||||
{ 0x00FB, "u" }, // û - \x9E in Mac Roman, \xFB in Windows-1252
|
||||
{ 0x00FC, "u" }, // ü - \x9F in Mac Roman, \xFC in Windows-1252
|
||||
{ 0x00FD, "y" }, // ý - \xFD in Windows-1252
|
||||
{ 0x00FF, "y" }, // ÿ - \xD8 in Mac Roman
|
||||
{ 0x0131, "i" }, // ı - \xF5 in Mac Roman
|
||||
{ 0x0152, "oe" }, // Œ - \xCE in Mac Roman, \x8C in Windows-1252
|
||||
{ 0x0153, "oe" }, // œ - \xCF in Mac Roman, \x9C in Windows-1252
|
||||
{ 0x0160, "s" }, // Š - \x8A in Windows-1252
|
||||
{ 0x0161, "s" }, // š - \x9A in Windows-1252
|
||||
{ 0x0178, "y" }, // Ÿ - \xD9 in Mac Roman, \x9F in Windows-1252
|
||||
{ 0x017D, "z" }, // Ž - \x8E in Windows-1252
|
||||
{ 0x017E, "z" }, // ž - \x9E in Windows-1252
|
||||
{ 0xFB01, "fi" }, // fi - \xDE in Mac Roman
|
||||
{ 0xFB02, "fl" }, // fl - \xDF in Mac Roman
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
void Lingo::initCharNormalizations() {
|
||||
for (char ch = 'A'; ch <= 'Z'; ch++) {
|
||||
_charNormalizations[ch] = Common::U32String(Common::String(tolower(ch)), Common::kUtf8);
|
||||
}
|
||||
for (const CharNormProto *norm = charNormProtos; norm->to; norm++) {
|
||||
_charNormalizations[norm->from] = Common::U32String(norm->to, Common::kUtf8);
|
||||
}
|
||||
}
|
||||
|
||||
Common::String Lingo::normalizeString(const Common::String &str) {
|
||||
Common::U32String u32Str = str.decode(Common::kUtf8);
|
||||
Common::U32String res;
|
||||
for (const Common::u32char_type_t *ch = u32Str.c_str(); *ch; ch++) {
|
||||
if (_charNormalizations.contains(*ch))
|
||||
res += _charNormalizations[*ch];
|
||||
else
|
||||
res += *ch;
|
||||
}
|
||||
return res.encode(Common::kUtf8);
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
82
engines/director/lingo/lingo-utils.h
Normal file
82
engines/director/lingo/lingo-utils.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_LINGO_UTILS_H
|
||||
#define DIRECTOR_LINGO_LINGO_UTILS_H
|
||||
|
||||
#define ARGNUMCHECK(n) \
|
||||
if (nargs != (n)) { \
|
||||
warning("BUILDBOT: %s: expected %d argument%s, got %d", __FUNCTION__, (n), ((n) == 1 ? "" : "s"), nargs); \
|
||||
g_lingo->dropStack(nargs); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define TYPECHECK(datum,t) \
|
||||
if ((datum).type != (t)) { \
|
||||
warning("BUILDBOT: %s: %s arg should be of type %s, not %s", __FUNCTION__, #datum, #t, (datum).type2str()); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define TYPECHECK2(datum, t1, t2) \
|
||||
if ((datum).type != (t1) && (datum).type != (t2)) { \
|
||||
warning("BUILDBOT: %s: %s arg should be of type %s or %s, not %s", __FUNCTION__, #datum, #t1, #t2, (datum).type2str()); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define TYPECHECK3(datum, t1, t2, t3) \
|
||||
if ((datum).type != (t1) && (datum).type != (t2) && (datum).type != (t3)) { \
|
||||
warning("BUILDBOT: %s: %s arg should be of type %s, %s, or %s, not %s", __FUNCTION__, #datum, #t1, #t2, #t3, (datum).type2str()); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define TYPECHECK4(datum, t1, t2, t3, t4) \
|
||||
if ((datum).type != (t1) && (datum).type != (t2) && (datum).type != (t3) && (datum).type != (t4)) { \
|
||||
warning("BUILDBOT: %s: %s arg should be of type %s, %s, %s, or %s, not %s", __FUNCTION__, #datum, #t1, #t2, #t3, #t4, (datum).type2str()); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define ARRBOUNDSCHECK(idx,array) \
|
||||
if ((idx)-1 < 0 || (idx) > (int)(array).u.farr->arr.size()) { \
|
||||
g_lingo->lingoError("%s: index out of bounds (%d of %d)", __FUNCTION__, (idx), (array).u.farr->arr.size()); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define XOBJSTUB(methname,retval) \
|
||||
void methname(int nargs) { \
|
||||
g_lingo->printSTUBWithArglist(#methname, nargs); \
|
||||
g_lingo->dropStack(nargs); \
|
||||
g_lingo->push(Datum(retval)); \
|
||||
}
|
||||
|
||||
#define XOBJSTUBV(methname) \
|
||||
void methname(int nargs) { \
|
||||
g_lingo->printSTUBWithArglist(#methname, nargs); \
|
||||
g_lingo->dropStack(nargs); \
|
||||
g_lingo->push(Datum()); \
|
||||
}
|
||||
|
||||
#define XOBJSTUBNR(methname) \
|
||||
void methname(int nargs) { \
|
||||
g_lingo->printSTUBWithArglist(#methname, nargs); \
|
||||
g_lingo->dropStack(nargs); \
|
||||
}
|
||||
|
||||
#endif
|
||||
2058
engines/director/lingo/lingo.cpp
Normal file
2058
engines/director/lingo/lingo.cpp
Normal file
File diff suppressed because it is too large
Load Diff
613
engines/director/lingo/lingo.h
Normal file
613
engines/director/lingo/lingo.h
Normal file
@@ -0,0 +1,613 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_LINGO_H
|
||||
#define DIRECTOR_LINGO_LINGO_H
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
}
|
||||
namespace Common {
|
||||
class SeekableReadStreamEndian;
|
||||
}
|
||||
|
||||
namespace Director {
|
||||
|
||||
struct ChunkReference;
|
||||
struct MenuReference;
|
||||
struct PictureReference;
|
||||
struct TheEntity;
|
||||
struct TheEntityField;
|
||||
struct LingoArchive;
|
||||
struct LingoV4Bytecode;
|
||||
struct LingoV4TheEntity;
|
||||
struct Node;
|
||||
struct Picture;
|
||||
class AbstractObject;
|
||||
class Cast;
|
||||
class ScriptContext;
|
||||
class DirectorEngine;
|
||||
class Frame;
|
||||
class LingoCompiler;
|
||||
struct Breakpoint;
|
||||
|
||||
typedef void (*inst)(void);
|
||||
#define STOP (inst)0
|
||||
#define ENTITY_INDEX(t,id) ((t) * 100000 + (id))
|
||||
|
||||
int calcStringAlignment(const char *s);
|
||||
int calcCodeAlignment(int l);
|
||||
|
||||
typedef Common::Array<inst> ScriptData;
|
||||
|
||||
struct FuncDesc {
|
||||
Common::String name;
|
||||
const char *proto;
|
||||
|
||||
FuncDesc(Common::String n, const char *p) { name = n; proto = p; }
|
||||
};
|
||||
|
||||
typedef Common::HashMap<void *, FuncDesc *> FuncHash;
|
||||
|
||||
typedef Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> MethodHash;
|
||||
|
||||
struct BuiltinProto {
|
||||
const char *name;
|
||||
void (*func)(int);
|
||||
int minArgs; // -1 -- arglist
|
||||
int maxArgs;
|
||||
int version;
|
||||
SymbolType type;
|
||||
};
|
||||
|
||||
struct Symbol { /* symbol table entry */
|
||||
Common::String *name;
|
||||
SymbolType type;
|
||||
union {
|
||||
ScriptData *defn; /* HANDLER */
|
||||
void (*func)(); /* OPCODE */
|
||||
void (*bltin)(int); /* BUILTIN */
|
||||
Common::String *s; /* STRING */
|
||||
} u;
|
||||
|
||||
int *refCount;
|
||||
|
||||
int nargs; /* number of arguments */
|
||||
int maxArgs; /* maximal number of arguments, for builtins */
|
||||
int targetType; /* valid target objects, for method builtins */
|
||||
|
||||
Common::Array<Common::String> *argNames;
|
||||
Common::Array<Common::String> *varNames;
|
||||
ScriptContext *ctx; /* optional script context to execute with */
|
||||
AbstractObject *target; /* optional method target */
|
||||
bool anonymous;
|
||||
|
||||
Symbol();
|
||||
Symbol(const Symbol &s);
|
||||
Symbol& operator=(const Symbol &s);
|
||||
bool operator==(Symbol &s) const;
|
||||
void reset();
|
||||
~Symbol();
|
||||
};
|
||||
|
||||
struct PArray {
|
||||
bool _sorted;
|
||||
PropertyArray arr;
|
||||
|
||||
PArray() : _sorted(false) {}
|
||||
|
||||
PArray(int size) : _sorted(false), arr(size) {}
|
||||
};
|
||||
|
||||
struct FArray {
|
||||
bool _sorted;
|
||||
DatumArray arr;
|
||||
|
||||
FArray() : _sorted(false) {}
|
||||
|
||||
FArray(int size) : _sorted(false), arr(size) {}
|
||||
};
|
||||
|
||||
|
||||
struct Datum { /* interpreter stack type */
|
||||
DatumType type;
|
||||
|
||||
union {
|
||||
int i; /* INT, ARGC, ARGCNORET */
|
||||
double f; /* FLOAT */
|
||||
Common::String *s; /* STRING, VARREF, OBJECT */
|
||||
FArray *farr; /* ARRAY, POINT, RECT */
|
||||
PArray *parr; /* PARRAY */
|
||||
AbstractObject *obj; /* OBJECT */
|
||||
ChunkReference *cref; /* CHUNKREF */
|
||||
CastMemberID *cast; /* CASTREF, FIELDREF */
|
||||
MenuReference *menu; /* MENUREF */
|
||||
PictureReference *picture; /* PICTUREREF */
|
||||
} u;
|
||||
|
||||
int *refCount;
|
||||
|
||||
bool ignoreGlobal; // True if this Datum should be ignored by showGlobals and clearGlobals
|
||||
|
||||
Datum();
|
||||
Datum(const Datum &d);
|
||||
Datum& operator=(const Datum &d);
|
||||
Datum(int val);
|
||||
Datum(double val);
|
||||
Datum(const Common::String &val);
|
||||
Datum(AbstractObject *val);
|
||||
Datum(CastMember *val);
|
||||
Datum(const CastMemberID &val);
|
||||
Datum(const Common::Point &point);
|
||||
Datum(const Common::Rect &rect);
|
||||
void reset();
|
||||
|
||||
~Datum() {
|
||||
reset();
|
||||
}
|
||||
|
||||
Datum eval() const;
|
||||
double asFloat() const;
|
||||
int asInt() const;
|
||||
Common::String asString(bool printonly = false) const;
|
||||
CastMemberID asMemberID(CastType castType = kCastTypeAny, int castLib = 0) const;
|
||||
Common::Point asPoint() const;
|
||||
Datum clone() const;
|
||||
|
||||
bool isRef() const;
|
||||
bool isVarRef() const;
|
||||
bool isCastRef() const;
|
||||
bool isArray() const;
|
||||
bool isNumeric() const;
|
||||
bool isVoid() const { return type == VOID; }
|
||||
|
||||
const char *type2str(bool ilk = false) const;
|
||||
|
||||
int equalTo(const Datum &d, bool ignoreCase = false) const;
|
||||
uint32 compareTo(const Datum &d) const;
|
||||
|
||||
bool operator==(const Datum &d) const;
|
||||
bool operator>(const Datum &d) const;
|
||||
bool operator<(const Datum &d) const;
|
||||
bool operator>=(const Datum &d) const;
|
||||
bool operator<=(const Datum &d) const;
|
||||
};
|
||||
|
||||
struct ChunkReference {
|
||||
Datum source;
|
||||
ChunkType type;
|
||||
int startChunk;
|
||||
int endChunk;
|
||||
int start;
|
||||
int end;
|
||||
|
||||
ChunkReference(const Datum &src, ChunkType t, int sc, int ec, int s, int e)
|
||||
: source(src), type(t), startChunk(sc), endChunk(ec), start(s), end(e) {}
|
||||
};
|
||||
|
||||
struct MenuReference {
|
||||
int menuIdNum;
|
||||
Common::String *menuIdStr;
|
||||
int menuItemIdNum;
|
||||
Common::String *menuItemIdStr;
|
||||
|
||||
MenuReference();
|
||||
};
|
||||
|
||||
struct PictureReference {
|
||||
Picture *_picture = nullptr;
|
||||
~PictureReference();
|
||||
};
|
||||
|
||||
struct PCell {
|
||||
Datum p;
|
||||
Datum v;
|
||||
|
||||
PCell();
|
||||
PCell(const Datum &prop, const Datum &val);
|
||||
};
|
||||
|
||||
struct Builtin {
|
||||
void (*func)(void);
|
||||
int nargs;
|
||||
|
||||
Builtin(void (*func1)(void), int nargs1) : func(func1), nargs(nargs1) {}
|
||||
};
|
||||
|
||||
typedef Common::HashMap<int32, ScriptContext *> ScriptContextHash;
|
||||
typedef Common::HashMap<int32, Common::HashMap<Common::String, ScriptContext *> *> FactoryContextHash;
|
||||
typedef Common::Array<Datum> StackData;
|
||||
typedef Common::HashMap<Common::String, Symbol, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SymbolHash;
|
||||
typedef Common::HashMap<Common::String, Datum, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> DatumHash;
|
||||
typedef Common::HashMap<Common::String, Builtin *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> BuiltinHash;
|
||||
typedef Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> VarTypeHash;
|
||||
typedef void (*XLibOpenerFunc)(ObjectType, const Common::Path &);
|
||||
typedef void (*XLibCloserFunc)(ObjectType);
|
||||
typedef Common::HashMap<Common::String, XLibOpenerFunc, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> XLibOpenerFuncHash;
|
||||
typedef Common::HashMap<Common::String, XLibCloserFunc, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> XLibCloserFuncHash;
|
||||
typedef Common::HashMap<Common::String, int, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> XLibTypeHash;
|
||||
typedef Common::HashMap<Common::String, ObjectType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> OpenXLibsHash;
|
||||
typedef Common::HashMap<Common::String, AbstractObject *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> OpenXLibsStateHash;
|
||||
|
||||
typedef Common::HashMap<Common::String, const TheEntity *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> TheEntityHash;
|
||||
typedef Common::HashMap<Common::String, const TheEntityField *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> TheEntityFieldHash;
|
||||
|
||||
struct CFrame { /* proc/func call stack frame */
|
||||
Symbol sp; /* symbol table entry */
|
||||
int retPC; /* where to resume after return */
|
||||
ScriptData *retScript; /* which script to resume after return */
|
||||
ScriptContext *retContext; /* which script context to use after return */
|
||||
DatumHash *retLocalVars;
|
||||
Datum retMe; /* which me obj to use after return */
|
||||
uint stackSizeBefore;
|
||||
bool allowRetVal; /* whether to allow a return value */
|
||||
Datum defaultRetVal; /* default return value */
|
||||
int paramCount; /* original number of arguments submitted */
|
||||
Common::Array<Datum> paramList; /* original argument list */
|
||||
};
|
||||
|
||||
struct LingoEvent {
|
||||
LEvent event;
|
||||
int eventId;
|
||||
EventHandlerSourceType eventHandlerSourceType;
|
||||
ScriptType scriptType;
|
||||
bool passByDefault;
|
||||
uint16 channelId;
|
||||
CastMemberID scriptId;
|
||||
Common::Point mousePos;
|
||||
int behaviorIndex;
|
||||
AbstractObject *scriptInstance;
|
||||
|
||||
LingoEvent(LEvent e, int ei, ScriptType st, bool pass, CastMemberID si = CastMemberID(), Common::Point mp = Common::Point(-1, -1), int bi = -1) {
|
||||
event = e;
|
||||
eventId = ei;
|
||||
eventHandlerSourceType = kNoneHandler;
|
||||
scriptType = st;
|
||||
passByDefault = pass;
|
||||
channelId = 0;
|
||||
scriptId = si;
|
||||
mousePos = mp;
|
||||
behaviorIndex = bi;
|
||||
scriptInstance = nullptr;
|
||||
}
|
||||
|
||||
LingoEvent(LEvent e, int ei, EventHandlerSourceType ehst, bool pass, Common::Point mp = Common::Point(-1, -1), uint16 ci = 0, int bi = -1) {
|
||||
event = e;
|
||||
eventId = ei;
|
||||
eventHandlerSourceType = ehst;
|
||||
scriptType = kNoneScript;
|
||||
passByDefault = pass;
|
||||
channelId = ci;
|
||||
scriptId = CastMemberID();
|
||||
mousePos = mp;
|
||||
behaviorIndex = bi;
|
||||
scriptInstance = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct LingoArchive {
|
||||
LingoArchive(Cast *c) : cast(c) {};
|
||||
~LingoArchive();
|
||||
|
||||
Cast *cast;
|
||||
ScriptContextHash lctxContexts;
|
||||
ScriptContextHash scriptContexts[kMaxScriptType + 1];
|
||||
FactoryContextHash factoryContexts;
|
||||
Common::Array<Common::String> names;
|
||||
Common::HashMap<uint32, Common::String> primaryEventHandlers;
|
||||
SymbolHash functionHandlers;
|
||||
|
||||
ScriptContext *getScriptContext(ScriptType type, uint16 id);
|
||||
ScriptContext *findScriptContext(uint16 id);
|
||||
Common::String getName(uint16 id);
|
||||
Common::String formatFunctionList(const char *prefix);
|
||||
|
||||
void addCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName = nullptr, uint32 preprocFlags = kLPPNone);
|
||||
void patchCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName = nullptr, uint32 preprocFlags = kLPPNone);
|
||||
void removeCode(ScriptType type, uint16 id);
|
||||
void replaceCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName = nullptr);
|
||||
void addCodeV4(Common::SeekableReadStreamEndian &stream, uint16 lctxIndex, const Common::String &archName, uint16 version);
|
||||
void addNamesV4(Common::SeekableReadStreamEndian &stream);
|
||||
|
||||
// lingo-patcher.cpp
|
||||
void patchScriptHandler(ScriptType type, CastMemberID id);
|
||||
};
|
||||
|
||||
struct LingoState {
|
||||
// Execution state for a Lingo process, created every time
|
||||
// a top-level handler is called (e.g. on mouseDown).
|
||||
// Can be swapped out when another script gets called with priority.
|
||||
// Call frames are pushed and popped from the callstack with
|
||||
// pushContext and popContext.
|
||||
Common::Array<CFrame *> callstack; // call stack
|
||||
uint pc = 0; // current program counter
|
||||
ScriptData *script = nullptr; // current Lingo script
|
||||
ScriptContext *context = nullptr; // current Lingo script context
|
||||
DatumHash *localVars = nullptr; // current local variables
|
||||
Datum me; // current me object
|
||||
StackData stack;
|
||||
|
||||
~LingoState();
|
||||
};
|
||||
|
||||
enum LingoExecState {
|
||||
kRunning,
|
||||
kPause,
|
||||
};
|
||||
|
||||
class Lingo {
|
||||
|
||||
public:
|
||||
Lingo(DirectorEngine *vm);
|
||||
~Lingo();
|
||||
|
||||
void resetLingo();
|
||||
void cleanupLingo();
|
||||
void resetLingoGo();
|
||||
|
||||
int getMenuNum();
|
||||
int getMenuItemsNum(Datum &d);
|
||||
int getXtrasNum();
|
||||
int getCastLibsNum();
|
||||
int getMembersNum(uint16 castLibID);
|
||||
|
||||
void executeHandler(const Common::String &name, int numargs = 0);
|
||||
void executeScript(ScriptType type, CastMemberID id);
|
||||
Common::String formatStack();
|
||||
void printStack(const char *s, uint pc);
|
||||
Common::String formatCallStack(uint pc);
|
||||
void printCallStack(uint pc);
|
||||
Common::String formatFrame();
|
||||
Common::String formatCurrentInstruction();
|
||||
Common::String decodeInstruction(ScriptData *sd, uint pc, uint *newPC = NULL);
|
||||
Common::String decodeScript(ScriptData *sd);
|
||||
Common::String formatFunctionName(Symbol &sym);
|
||||
Common::String formatFunctionBody(Symbol &sym);
|
||||
|
||||
void reloadBuiltIns();
|
||||
void initBuiltIns();
|
||||
void initBuiltIns(const BuiltinProto protos[]);
|
||||
void cleanupBuiltIns();
|
||||
void cleanupBuiltIns(const BuiltinProto protos[]);
|
||||
void initFuncs();
|
||||
void cleanupFuncs();
|
||||
void initBytecode();
|
||||
void initMethods();
|
||||
void cleanupMethods();
|
||||
void initXLibs();
|
||||
void cleanupXLibs();
|
||||
|
||||
Common::String normalizeXLibName(Common::String name);
|
||||
void openXLib(Common::String name, ObjectType type, const Common::Path &path);
|
||||
void closeXLib(Common::String name);
|
||||
void closeOpenXLibs();
|
||||
void reloadOpenXLibs();
|
||||
|
||||
void runTests();
|
||||
|
||||
// lingo-events.cpp
|
||||
private:
|
||||
void initEventHandlerTypes();
|
||||
bool processEvent(LEvent event, ScriptType st, CastMemberID scriptId, int channelId = -1, AbstractObject *obj = nullptr);
|
||||
|
||||
public:
|
||||
ScriptType event2script(LEvent ev);
|
||||
Symbol getHandler(const Common::String &name);
|
||||
|
||||
void processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent);
|
||||
|
||||
public:
|
||||
bool execute(int targetFrame = -1);
|
||||
void switchStateFromWindow();
|
||||
void freezeState();
|
||||
void freezePlayState();
|
||||
void pushContext(const Symbol funcSym, bool allowRetVal, Datum defaultRetVal, int paramCount, int nargs);
|
||||
void popContext(bool aborting = false);
|
||||
void cleanLocalVars();
|
||||
void varAssign(const Datum &var, const Datum &value);
|
||||
Datum varFetch(const Datum &var, bool silent = false);
|
||||
Common::U32String evalChunkRef(const Datum &var);
|
||||
Datum findVarV4(int varType, const Datum &id);
|
||||
CastMemberID resolveCastMember(const Datum &memberID, const Datum &castLib, CastType type);
|
||||
CastMemberID toCastMemberID(const Datum &member, const Datum &castLib);
|
||||
void exposeXObject(const char *name, Datum obj);
|
||||
|
||||
int getAlignedType(const Datum &d1, const Datum &d2, bool equality);
|
||||
|
||||
Common::String formatAllVars();
|
||||
void printAllVars();
|
||||
|
||||
inst readInst() { return getInst(_state->pc++); }
|
||||
inst getInst(uint pc) { return (*_state->script)[pc]; }
|
||||
int readInt() { return getInt(_state->pc++); }
|
||||
int getInt(uint pc);
|
||||
double readFloat() { double d = getFloat(_state->pc); _state->pc += calcCodeAlignment(sizeof(double)); return d; }
|
||||
double getFloat(uint pc) { return *(double *)(&((*_state->script)[_state->pc])); }
|
||||
char *readString() { char *s = getString(_state->pc); _state->pc += calcStringAlignment(s); return s; }
|
||||
char *getString(uint pc) { return (char *)(&((*_state->script)[_state->pc])); }
|
||||
|
||||
Datum getVoid();
|
||||
void pushVoid();
|
||||
|
||||
void printArgs(const char *funcname, int nargs, const char *prefix = nullptr);
|
||||
inline void printSTUBWithArglist(const char *funcname, int nargs) { printArgs(funcname, nargs, "STUB: "); }
|
||||
void convertVOIDtoString(int arg, int nargs);
|
||||
void dropStack(int nargs);
|
||||
void drop(uint num);
|
||||
|
||||
void lingoError(const char *s, ...);
|
||||
|
||||
void func_mci(const Common::String &name);
|
||||
void func_mciwait(const Common::String &name);
|
||||
void func_beep(int repeats);
|
||||
void func_goto(Datum &frame, Datum &movie, bool commandgo = false );
|
||||
void func_gotoloop();
|
||||
void func_gotonext();
|
||||
void func_gotoprevious();
|
||||
void func_play(Datum &frame, Datum &movie);
|
||||
void func_playdone();
|
||||
void func_cursor(Datum cursorDatum);
|
||||
int func_marker(int m);
|
||||
uint16 func_label(Datum &label);
|
||||
|
||||
// lingo-the.cpp
|
||||
public:
|
||||
void initTheEntities();
|
||||
void cleanUpTheEntities();
|
||||
const char *entity2str(int id);
|
||||
const char *field2str(int id);
|
||||
|
||||
// global kTheEntity
|
||||
Datum _actorList;
|
||||
Common::u32char_type_t _itemDelimiter;
|
||||
bool _exitLock;
|
||||
bool _preLoadEventAbort; // no-op, everything is always preloaded
|
||||
Datum _searchPath;
|
||||
bool _trace; // state of movie's trace function
|
||||
int _traceLoad; // internal Director verbosity level
|
||||
bool _updateMovieEnabled;
|
||||
bool _romanLingo;
|
||||
|
||||
Datum getTheEntity(int entity, Datum &id, int field);
|
||||
void setTheEntity(int entity, Datum &id, int field, Datum &d);
|
||||
Datum getTheSprite(Datum &id, int field);
|
||||
void setTheSprite(Datum &id, int field, Datum &d);
|
||||
Datum getTheCast(Datum &id, int field);
|
||||
void setTheCast(Datum &id, int field, Datum &d);
|
||||
Datum getTheCastLib(Datum &id, int field);
|
||||
void setTheCastLib(Datum &id, int field, Datum &d);
|
||||
Datum getTheField(Datum &id1, int field);
|
||||
void setTheField(Datum &id1, int field, Datum &d);
|
||||
Datum getTheChunk(Datum &chunk, int field);
|
||||
void setTheChunk(Datum &chunk, int field, Datum &d);
|
||||
void getObjectProp(Datum &obj, Common::String &propName);
|
||||
void setObjectProp(Datum &obj, Common::String &propName, Datum &d);
|
||||
Datum getTheDate(int field);
|
||||
Datum getTheTime(int field);
|
||||
Datum getTheDeskTopRectList();
|
||||
|
||||
private:
|
||||
Common::StringArray _entityNames;
|
||||
Common::StringArray _fieldNames;
|
||||
|
||||
public:
|
||||
LingoCompiler *_compiler;
|
||||
LingoState *_state;
|
||||
|
||||
int _currentChannelId;
|
||||
|
||||
bool _freezeState;
|
||||
bool _freezePlay;
|
||||
bool _playDone;
|
||||
bool _abort;
|
||||
bool _expectError;
|
||||
bool _caughtError;
|
||||
|
||||
TheEntityHash _theEntities;
|
||||
TheEntityFieldHash _theEntityFields;
|
||||
|
||||
int _objectEntityId;
|
||||
|
||||
SymbolHash _builtinCmds;
|
||||
SymbolHash _builtinFuncs;
|
||||
SymbolHash _builtinConsts;
|
||||
SymbolHash _builtinListHandlers;
|
||||
SymbolHash _methods;
|
||||
XLibOpenerFuncHash _xlibOpeners;
|
||||
XLibCloserFuncHash _xlibClosers;
|
||||
XLibTypeHash _xlibTypes;
|
||||
|
||||
OpenXLibsHash _openXLibs;
|
||||
OpenXLibsStateHash _openXLibsState;
|
||||
Common::StringArray _openXtras;
|
||||
Common::Array<Datum> _openXtraObjects;
|
||||
OpenXLibsStateHash _openXtrasState;
|
||||
|
||||
Common::String _floatPrecisionFormat;
|
||||
|
||||
public:
|
||||
void push(Datum d);
|
||||
Datum pop();
|
||||
Datum peek(uint offset);
|
||||
|
||||
public:
|
||||
Common::HashMap<uint32, const char *> _eventHandlerTypes;
|
||||
Common::HashMap<Common::String, uint32, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _eventHandlerTypeIds;
|
||||
Common::HashMap<Common::String, Audio::AudioStream *> _audioAliases;
|
||||
|
||||
DatumHash _globalvars;
|
||||
|
||||
FuncHash _functions;
|
||||
|
||||
Common::HashMap<int, const LingoV4Bytecode *> _lingoV4;
|
||||
Common::HashMap<int, const LingoV4TheEntity *> _lingoV4TheEntity;
|
||||
|
||||
uint _globalCounter;
|
||||
|
||||
DirectorEngine *_vm;
|
||||
|
||||
int _floatPrecision;
|
||||
|
||||
Datum _theResult;
|
||||
|
||||
// events
|
||||
bool _passEvent;
|
||||
Datum _perFrameHook;
|
||||
|
||||
Datum _windowList;
|
||||
Symbol _currentInputEvent;
|
||||
|
||||
struct {
|
||||
LingoExecState _state = kRunning;
|
||||
bool (*_shouldPause)() = nullptr;
|
||||
} _exec;
|
||||
|
||||
public:
|
||||
void executeImmediateScripts(Frame *frame);
|
||||
void executePerFrameHook(int frame, int subframe, bool stepFrame = true);
|
||||
|
||||
// lingo-utils.cpp
|
||||
private:
|
||||
Common::HashMap<uint32, Common::U32String> _charNormalizations;
|
||||
void initCharNormalizations();
|
||||
|
||||
public:
|
||||
Common::String normalizeString(const Common::String &str);
|
||||
|
||||
public:
|
||||
void addBreakpoint(Breakpoint &bp);
|
||||
bool delBreakpoint(int id);
|
||||
Breakpoint *getBreakpoint(int id);
|
||||
|
||||
const Common::Array<Breakpoint> &getBreakpoints() const { return _breakpoints; }
|
||||
Common::Array<Breakpoint> &getBreakpoints() { return _breakpoints; }
|
||||
|
||||
private:
|
||||
int _bpNextId = 1;
|
||||
Common::Array<Breakpoint> _breakpoints;
|
||||
};
|
||||
|
||||
extern Lingo *g_lingo;
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
12
engines/director/lingo/lingodec/README.md
Normal file
12
engines/director/lingo/lingodec/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
This directory is coming straight from the ProjectorRays project
|
||||
|
||||
https://github.com/ProjectorRays/ProjectorRays/tree/master/src/lingodec
|
||||
|
||||
And should be kept in sync.
|
||||
|
||||
At the time of writing, the changes have not yet been merged within
|
||||
ProjectorRays and as such, live in 'scummvm' branch:
|
||||
|
||||
https://github.com/ProjectorRays/ProjectorRays/tree/scummvm/src/lingodec
|
||||
|
||||
The original code is licensed under the Mozilla Public License 2.0.
|
||||
274
engines/director/lingo/lingodec/ast.cpp
Normal file
274
engines/director/lingo/lingodec/ast.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "common/util.h"
|
||||
#include "./ast.h"
|
||||
#include "./handler.h"
|
||||
#include "./names.h"
|
||||
#include "./script.h"
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
/* Datum */
|
||||
|
||||
int Datum::toInt() {
|
||||
switch (type) {
|
||||
case kDatumInt:
|
||||
return i;
|
||||
case kDatumFloat:
|
||||
return f;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AST */
|
||||
|
||||
void AST::addStatement(Common::SharedPtr<Node> statement) {
|
||||
currentBlock->addChild(Common::move(statement));
|
||||
}
|
||||
|
||||
void AST::enterBlock(BlockNode *block) {
|
||||
currentBlock = block;
|
||||
}
|
||||
|
||||
void AST::exitBlock() {
|
||||
auto ancestorStatement = currentBlock->ancestorStatement();
|
||||
if (!ancestorStatement) {
|
||||
currentBlock = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
ancestorStatement->_endOffset = currentBlock->_endOffset;
|
||||
|
||||
auto block = ancestorStatement->parent;
|
||||
if (!block || block->type != kBlockNode) {
|
||||
currentBlock = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
currentBlock = static_cast<BlockNode *>(block);
|
||||
}
|
||||
|
||||
/* Node */
|
||||
|
||||
Common::SharedPtr<Datum> Node::getValue() {
|
||||
return Common::SharedPtr<Datum>(new Datum());
|
||||
}
|
||||
|
||||
Node *Node::ancestorStatement() {
|
||||
Node *ancestor = parent;
|
||||
while (ancestor && !ancestor->isStatement) {
|
||||
ancestor = ancestor->parent;
|
||||
}
|
||||
return ancestor;
|
||||
}
|
||||
|
||||
LoopNode *Node::ancestorLoop() {
|
||||
Node *ancestor = parent;
|
||||
while (ancestor && !ancestor->isLoop) {
|
||||
ancestor = ancestor->parent;
|
||||
}
|
||||
return static_cast<LoopNode *>(ancestor);
|
||||
}
|
||||
|
||||
bool Node::hasSpaces(bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ErrorNode */
|
||||
|
||||
bool ErrorNode::hasSpaces(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* LiteralNode */
|
||||
|
||||
Common::SharedPtr<Datum> LiteralNode::getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
bool LiteralNode::hasSpaces(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* BlockNode */
|
||||
|
||||
void BlockNode::addChild(Common::SharedPtr<Node> child) {
|
||||
child->parent = this;
|
||||
children.push_back(Common::move(child));
|
||||
}
|
||||
|
||||
/* BinaryOpNode */
|
||||
|
||||
unsigned int BinaryOpNode::getPrecedence() const {
|
||||
switch (opcode) {
|
||||
case kOpMul:
|
||||
case kOpDiv:
|
||||
case kOpMod:
|
||||
return 1;
|
||||
case kOpAdd:
|
||||
case kOpSub:
|
||||
return 2;
|
||||
case kOpLt:
|
||||
case kOpLtEq:
|
||||
case kOpNtEq:
|
||||
case kOpEq:
|
||||
case kOpGt:
|
||||
case kOpGtEq:
|
||||
return 3;
|
||||
case kOpAnd:
|
||||
return 4;
|
||||
case kOpOr:
|
||||
return 5;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MemberExprNode */
|
||||
|
||||
bool MemberExprNode::hasSpaces(bool dot) {
|
||||
return !dot;
|
||||
}
|
||||
|
||||
/* VarNode */
|
||||
|
||||
bool VarNode::hasSpaces(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* CaseStmtNode */
|
||||
|
||||
void CaseStmtNode::addOtherwise(uint32 offset) {
|
||||
otherwise = Common::SharedPtr<OtherwiseNode>(new OtherwiseNode(offset));
|
||||
otherwise->parent = this;
|
||||
otherwise->block->endPos = endPos;
|
||||
}
|
||||
|
||||
/* CallNode */
|
||||
|
||||
bool CallNode::noParens() const {
|
||||
if (isStatement) {
|
||||
// TODO: Make a complete list of commonly paren-less commands
|
||||
if (name == "put")
|
||||
return true;
|
||||
if (name == "return")
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CallNode::isMemberExpr() const {
|
||||
if (isExpression) {
|
||||
size_t nargs = argList->getValue()->l.size();
|
||||
if (name == "cast" && (nargs == 1 || nargs == 2))
|
||||
return true;
|
||||
if (name == "member" && (nargs == 1 || nargs == 2))
|
||||
return true;
|
||||
if (name == "script" && (nargs == 1 || nargs == 2))
|
||||
return true;
|
||||
if (name == "castLib" && nargs == 1)
|
||||
return true;
|
||||
if (name == "window" && nargs == 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CallNode::hasSpaces(bool dot) {
|
||||
if (!dot && isMemberExpr())
|
||||
return true;
|
||||
|
||||
if (noParens())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ObjCallNode */
|
||||
|
||||
bool ObjCallNode::hasSpaces(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ObjCallV4Node */
|
||||
|
||||
bool ObjCallV4Node::hasSpaces(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ObjPropExprNode */
|
||||
|
||||
bool ObjPropExprNode::hasSpaces(bool dot) {
|
||||
return !dot;
|
||||
}
|
||||
|
||||
/* ObjBracketExprNode */
|
||||
|
||||
bool ObjBracketExprNode::hasSpaces(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ObjPropIndexExprNode */
|
||||
|
||||
bool ObjPropIndexExprNode::hasSpaces(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ErrorNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void CommentNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void LiteralNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void IfStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void NewObjNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void EndCaseNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void HandlerNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ObjCallNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void PutStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void TheExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void BinaryOpNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void CaseStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ExitStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void TellStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void WhenStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void CaseLabelNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ChunkExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void InverseOpNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ObjCallV4Node::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void OtherwiseNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void MemberExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ObjPropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void PlayCmdStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ThePropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void MenuPropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void SoundCmdStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void SoundPropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void AssignmentStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ExitRepeatStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void NextRepeatStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ObjBracketExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void SpritePropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ChunkDeleteStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ChunkHiliteStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void RepeatWhileStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void MenuItemPropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void ObjPropIndexExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void RepeatWithInStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void RepeatWithToStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void SpriteWithinExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void LastStringChunkExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void SpriteIntersectsExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void StringChunkCountExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void VarNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void CallNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void BlockNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
void NotOpNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
|
||||
|
||||
} // namespace LingoDec
|
||||
864
engines/director/lingo/lingodec/ast.h
Normal file
864
engines/director/lingo/lingodec/ast.h
Normal file
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef LINGODEC_AST_H
|
||||
#define LINGODEC_AST_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/ptr.h"
|
||||
#include "common/str.h"
|
||||
#include "common/util.h"
|
||||
#include "./enums.h"
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
struct CaseLabelNode;
|
||||
struct Handler;
|
||||
struct LoopNode;
|
||||
struct Node;
|
||||
struct RepeatWithInStmtNode;
|
||||
|
||||
/* Datum */
|
||||
|
||||
struct Datum {
|
||||
DatumType type;
|
||||
int i = -1;
|
||||
double f = 0.0f;
|
||||
Common::String s;
|
||||
Common::Array<Common::SharedPtr<Node>> l;
|
||||
|
||||
Datum() {
|
||||
type = kDatumVoid;
|
||||
}
|
||||
Datum(int val) {
|
||||
type = kDatumInt;
|
||||
i = val;
|
||||
}
|
||||
Datum(double val) {
|
||||
type = kDatumFloat;
|
||||
f = val;
|
||||
}
|
||||
Datum(DatumType t, Common::String val) {
|
||||
type = t;
|
||||
s = val;
|
||||
}
|
||||
Datum(DatumType t, Common::Array<Common::SharedPtr<Node>> val) {
|
||||
type = t;
|
||||
l = val;
|
||||
}
|
||||
|
||||
int toInt();
|
||||
};
|
||||
|
||||
class NodeVisitor;
|
||||
|
||||
/* Node */
|
||||
|
||||
struct Node {
|
||||
NodeType type;
|
||||
bool isExpression;
|
||||
bool isStatement;
|
||||
bool isLabel;
|
||||
bool isLoop;
|
||||
Node *parent;
|
||||
uint32 _startOffset;
|
||||
uint32 _endOffset;
|
||||
|
||||
Node(NodeType t, uint32 offset) : type(t), isExpression(false), isStatement(false), isLabel(false), isLoop(false), parent(nullptr), _startOffset(offset), _endOffset(offset) {}
|
||||
virtual ~Node() {}
|
||||
virtual void accept(NodeVisitor& visitor) const = 0;
|
||||
virtual Common::SharedPtr<Datum> getValue();
|
||||
Node *ancestorStatement();
|
||||
LoopNode *ancestorLoop();
|
||||
virtual bool hasSpaces(bool dot);
|
||||
};
|
||||
|
||||
/* ExprNode */
|
||||
|
||||
struct ExprNode : Node {
|
||||
ExprNode(NodeType t, uint32 offset) : Node(t, offset) {
|
||||
isExpression = true;
|
||||
}
|
||||
};
|
||||
|
||||
/* StmtNode */
|
||||
|
||||
struct StmtNode : Node {
|
||||
StmtNode(NodeType t, uint32 offset) : Node(t, offset) {
|
||||
isStatement = true;
|
||||
}
|
||||
};
|
||||
|
||||
/* LabelNode */
|
||||
|
||||
struct LabelNode : Node {
|
||||
LabelNode(NodeType t, uint32 offset) : Node(t, offset) {
|
||||
isLabel = true;
|
||||
}
|
||||
};
|
||||
|
||||
/* LoopNode */
|
||||
|
||||
struct LoopNode : StmtNode {
|
||||
uint32 startIndex;
|
||||
|
||||
LoopNode(NodeType t, uint32 startIndex_, uint32 offset) : StmtNode(t, offset), startIndex(startIndex_) {
|
||||
isLoop = true;
|
||||
}
|
||||
};
|
||||
|
||||
/* ErrorNode */
|
||||
|
||||
struct ErrorNode : ExprNode {
|
||||
explicit ErrorNode(uint32 offset) : ExprNode(kErrorNode, offset) {}
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* CommentNode */
|
||||
|
||||
struct CommentNode : Node {
|
||||
Common::String text;
|
||||
|
||||
CommentNode(uint32 offset, Common::String t) : Node(kCommentNode, offset), text(t) {}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* LiteralNode */
|
||||
|
||||
struct LiteralNode : ExprNode {
|
||||
Common::SharedPtr<Datum> value;
|
||||
|
||||
LiteralNode(uint32 offset, Common::SharedPtr<Datum> d) : ExprNode(kLiteralNode, offset) {
|
||||
value = Common::move(d);
|
||||
}
|
||||
Common::SharedPtr<Datum> getValue() override;
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* BlockNode */
|
||||
|
||||
struct BlockNode : Node {
|
||||
Common::Array<Common::SharedPtr<Node>> children;
|
||||
|
||||
// for use during translation:
|
||||
uint32 endPos;
|
||||
CaseLabelNode *currentCaseLabel = nullptr;
|
||||
|
||||
explicit BlockNode(uint32 offset) : Node(kBlockNode, offset), endPos(Common::String::npos) {}
|
||||
void addChild(Common::SharedPtr<Node> child);
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* HandlerNode */
|
||||
|
||||
struct HandlerNode : Node {
|
||||
Handler *handler;
|
||||
Common::SharedPtr<BlockNode> block;
|
||||
|
||||
HandlerNode(uint32 offset, Handler *h)
|
||||
: Node(kHandlerNode, offset), handler(h) {
|
||||
block = Common::SharedPtr<BlockNode>(new BlockNode(offset));
|
||||
block->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ExitStmtNode */
|
||||
|
||||
struct ExitStmtNode : StmtNode {
|
||||
explicit ExitStmtNode(uint32 offset) : StmtNode(kExitStmtNode, offset) {}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* InverseOpNode */
|
||||
|
||||
struct InverseOpNode : ExprNode {
|
||||
Common::SharedPtr<Node> operand;
|
||||
|
||||
InverseOpNode(uint32 offset, Common::SharedPtr<Node> o) : ExprNode(kInverseOpNode, offset) {
|
||||
operand = Common::move(o);
|
||||
operand->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* NotOpNode */
|
||||
|
||||
struct NotOpNode : ExprNode {
|
||||
Common::SharedPtr<Node> operand;
|
||||
|
||||
NotOpNode(uint32 offset, Common::SharedPtr<Node> o) : ExprNode(kNotOpNode, offset) {
|
||||
operand = Common::move(o);
|
||||
operand->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* BinaryOpNode */
|
||||
|
||||
struct BinaryOpNode : ExprNode {
|
||||
OpCode opcode;
|
||||
Common::SharedPtr<Node> left;
|
||||
Common::SharedPtr<Node> right;
|
||||
|
||||
BinaryOpNode(uint32 offset, OpCode op, Common::SharedPtr<Node> a, Common::SharedPtr<Node> b)
|
||||
: ExprNode(kBinaryOpNode, offset), opcode(op) {
|
||||
left = Common::move(a);
|
||||
left->parent = this;
|
||||
right = Common::move(b);
|
||||
right->parent = this;
|
||||
}
|
||||
virtual unsigned int getPrecedence() const;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ChunkExprNode */
|
||||
|
||||
struct ChunkExprNode : ExprNode {
|
||||
ChunkExprType type;
|
||||
Common::SharedPtr<Node> first;
|
||||
Common::SharedPtr<Node> last;
|
||||
Common::SharedPtr<Node> string;
|
||||
|
||||
ChunkExprNode(uint32 offset, ChunkExprType t, Common::SharedPtr<Node> a, Common::SharedPtr<Node> b, Common::SharedPtr<Node> s)
|
||||
: ExprNode(kChunkExprNode, offset), type(t) {
|
||||
first = Common::move(a);
|
||||
first->parent = this;
|
||||
last = Common::move(b);
|
||||
last->parent = this;
|
||||
string = Common::move(s);
|
||||
string->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ChunkHiliteStmtNode */
|
||||
|
||||
struct ChunkHiliteStmtNode : StmtNode {
|
||||
Common::SharedPtr<Node> chunk;
|
||||
|
||||
ChunkHiliteStmtNode(uint32 offset, Common::SharedPtr<Node> c) : StmtNode(kChunkHiliteStmtNode, offset) {
|
||||
chunk = Common::move(c);
|
||||
chunk->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ChunkDeleteStmtNode */
|
||||
|
||||
struct ChunkDeleteStmtNode : StmtNode {
|
||||
Common::SharedPtr<Node> chunk;
|
||||
|
||||
ChunkDeleteStmtNode(uint32 offset, Common::SharedPtr<Node> c) : StmtNode(kChunkDeleteStmtNode, offset) {
|
||||
chunk = Common::move(c);
|
||||
chunk->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* SpriteIntersectsExprNode */
|
||||
|
||||
struct SpriteIntersectsExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> firstSprite;
|
||||
Common::SharedPtr<Node> secondSprite;
|
||||
|
||||
SpriteIntersectsExprNode(uint32 offset, Common::SharedPtr<Node> a, Common::SharedPtr<Node> b)
|
||||
: ExprNode(kSpriteIntersectsExprNode, offset) {
|
||||
firstSprite = Common::move(a);
|
||||
firstSprite->parent = this;
|
||||
secondSprite = Common::move(b);
|
||||
secondSprite->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* SpriteWithinExprNode */
|
||||
|
||||
struct SpriteWithinExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> firstSprite;
|
||||
Common::SharedPtr<Node> secondSprite;
|
||||
|
||||
SpriteWithinExprNode(uint32 offset, Common::SharedPtr<Node> a, Common::SharedPtr<Node> b)
|
||||
: ExprNode(kSpriteWithinExprNode, offset) {
|
||||
firstSprite = Common::move(a);
|
||||
firstSprite->parent = this;
|
||||
secondSprite = Common::move(b);
|
||||
secondSprite->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* MemberExprNode */
|
||||
|
||||
struct MemberExprNode : ExprNode {
|
||||
Common::String type;
|
||||
Common::SharedPtr<Node> memberID;
|
||||
Common::SharedPtr<Node> castID;
|
||||
|
||||
MemberExprNode(uint32 offset, Common::String type_, Common::SharedPtr<Node> memberID_, Common::SharedPtr<Node> castID_)
|
||||
: ExprNode(kMemberExprNode, offset), type(type_) {
|
||||
this->memberID = Common::move(memberID_);
|
||||
this->memberID->parent = this;
|
||||
if (castID_) {
|
||||
this->castID = Common::move(castID_);
|
||||
this->castID->parent = this;
|
||||
}
|
||||
}
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* VarNode */
|
||||
|
||||
struct VarNode : ExprNode {
|
||||
Common::String varName;
|
||||
|
||||
VarNode(uint32 offset, Common::String v) : ExprNode(kVarNode, offset), varName(v) {}
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* AssignmentStmtNode */
|
||||
|
||||
struct AssignmentStmtNode : StmtNode {
|
||||
Common::SharedPtr<Node> variable;
|
||||
Common::SharedPtr<Node> value;
|
||||
bool forceVerbose;
|
||||
|
||||
AssignmentStmtNode(uint32 offset, Common::SharedPtr<Node> var, Common::SharedPtr<Node> val, bool forceVerbose_ = false)
|
||||
: StmtNode(kAssignmentStmtNode, offset), forceVerbose(forceVerbose_) {
|
||||
variable = Common::move(var);
|
||||
variable->parent = this;
|
||||
value = Common::move(val);
|
||||
value->parent = this;
|
||||
}
|
||||
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* IfStmtNode */
|
||||
|
||||
struct IfStmtNode : StmtNode {
|
||||
bool hasElse;
|
||||
Common::SharedPtr<Node> condition;
|
||||
Common::SharedPtr<BlockNode> block1;
|
||||
Common::SharedPtr<BlockNode> block2;
|
||||
|
||||
IfStmtNode(uint32 offset, Common::SharedPtr<Node> c) : StmtNode(kIfStmtNode, offset), hasElse(false) {
|
||||
condition = Common::move(c);
|
||||
condition->parent = this;
|
||||
block1 = Common::SharedPtr<BlockNode>(new BlockNode(offset));
|
||||
block1->parent = this;
|
||||
block2 = Common::SharedPtr<BlockNode>(new BlockNode(offset));
|
||||
block2->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* RepeatWhileStmtNode */
|
||||
|
||||
struct RepeatWhileStmtNode : LoopNode {
|
||||
Common::SharedPtr<Node> condition;
|
||||
Common::SharedPtr<BlockNode> block;
|
||||
|
||||
RepeatWhileStmtNode(uint32 startIndex_, Common::SharedPtr<Node> c, uint32 offset)
|
||||
: LoopNode(kRepeatWhileStmtNode, startIndex_, offset) {
|
||||
condition = Common::move(c);
|
||||
condition->parent = this;
|
||||
block = Common::SharedPtr<BlockNode>(new BlockNode(offset));
|
||||
block->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* RepeatWithInStmtNode */
|
||||
|
||||
struct RepeatWithInStmtNode : LoopNode {
|
||||
Common::String varName;
|
||||
Common::SharedPtr<Node> list;
|
||||
Common::SharedPtr<BlockNode> block;
|
||||
|
||||
RepeatWithInStmtNode(uint32 startIndex_, Common::String v, Common::SharedPtr<Node> l, uint32 offset)
|
||||
: LoopNode(kRepeatWithInStmtNode, startIndex_, offset) {
|
||||
varName = v;
|
||||
list = Common::move(l);
|
||||
list->parent = this;
|
||||
block = Common::SharedPtr<BlockNode>(new BlockNode(offset));
|
||||
block->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* RepeatWithToStmtNode */
|
||||
|
||||
struct RepeatWithToStmtNode : LoopNode {
|
||||
Common::String varName;
|
||||
Common::SharedPtr<Node> start;
|
||||
bool up;
|
||||
Common::SharedPtr<Node> end;
|
||||
Common::SharedPtr<BlockNode> block;
|
||||
|
||||
RepeatWithToStmtNode(uint32 startIndex_, Common::String v, Common::SharedPtr<Node> s, bool _up, Common::SharedPtr<Node> e, uint32 offset)
|
||||
: LoopNode(kRepeatWithToStmtNode, startIndex_, offset), up(_up) {
|
||||
varName = v;
|
||||
start = Common::move(s);
|
||||
start->parent = this;
|
||||
end = Common::move(e);
|
||||
end->parent = this;
|
||||
block = Common::SharedPtr<BlockNode>(new BlockNode(offset));
|
||||
block->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* CaseLabelNode */
|
||||
|
||||
struct CaseLabelNode : LabelNode {
|
||||
Common::SharedPtr<Node> value;
|
||||
CaseExpect expect;
|
||||
|
||||
Common::SharedPtr<CaseLabelNode> nextOr;
|
||||
|
||||
Common::SharedPtr<CaseLabelNode> nextLabel;
|
||||
Common::SharedPtr<BlockNode> block;
|
||||
|
||||
CaseLabelNode(uint32 offset, Common::SharedPtr<Node> v, CaseExpect e) : LabelNode(kCaseLabelNode, offset), expect(e) {
|
||||
value = Common::move(v);
|
||||
value->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* OtherwiseNode */
|
||||
|
||||
struct OtherwiseNode : LabelNode {
|
||||
Common::SharedPtr<BlockNode> block;
|
||||
|
||||
explicit OtherwiseNode(uint32 offset) : LabelNode(kOtherwiseNode, offset) {
|
||||
block = Common::SharedPtr<BlockNode>(new BlockNode(offset));
|
||||
block->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* EndCaseNode */
|
||||
|
||||
struct EndCaseNode : LabelNode {
|
||||
explicit EndCaseNode(uint32 offset) : LabelNode(kEndCaseNode, offset) {}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* CaseStmtNode */
|
||||
|
||||
struct CaseStmtNode : StmtNode {
|
||||
Common::SharedPtr<Node> value;
|
||||
Common::SharedPtr<CaseLabelNode> firstLabel;
|
||||
Common::SharedPtr<OtherwiseNode> otherwise;
|
||||
|
||||
// for use during translation:
|
||||
int32 endPos = -1;
|
||||
int32 potentialOtherwisePos = -1;
|
||||
|
||||
CaseStmtNode(uint32 offset, Common::SharedPtr<Node> v) : StmtNode(kCaseStmtNode, offset) {
|
||||
value = Common::move(v);
|
||||
value->parent = this;
|
||||
}
|
||||
void addOtherwise(uint32 offset);
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* TellStmtNode */
|
||||
|
||||
struct TellStmtNode : StmtNode {
|
||||
Common::SharedPtr<Node> window;
|
||||
Common::SharedPtr<BlockNode> block;
|
||||
|
||||
TellStmtNode(uint32 offset, Common::SharedPtr<Node> w) : StmtNode(kTellStmtNode, offset) {
|
||||
window = Common::move(w);
|
||||
window->parent = this;
|
||||
block = Common::SharedPtr<BlockNode>(new BlockNode(offset));
|
||||
block->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* SoundCmdStmtNode */
|
||||
|
||||
struct SoundCmdStmtNode : StmtNode {
|
||||
Common::String cmd;
|
||||
Common::SharedPtr<Node> argList;
|
||||
|
||||
SoundCmdStmtNode(uint32 offset, Common::String c, Common::SharedPtr<Node> a) : StmtNode(kSoundCmdStmtNode, offset) {
|
||||
cmd = c;
|
||||
argList = Common::move(a);
|
||||
argList->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* PlayCmdStmtNode */
|
||||
|
||||
struct PlayCmdStmtNode : StmtNode {
|
||||
Common::SharedPtr<Node> argList;
|
||||
|
||||
PlayCmdStmtNode(uint32 offset, Common::SharedPtr<Node> a) : StmtNode(kPlayCmdStmtNode, offset) {
|
||||
argList = Common::move(a);
|
||||
argList->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* CallNode */
|
||||
|
||||
struct CallNode : Node {
|
||||
Common::String name;
|
||||
Common::SharedPtr<Node> argList;
|
||||
|
||||
CallNode(uint32 offset, Common::String n, Common::SharedPtr<Node> a) : Node(kCallNode, offset) {
|
||||
name = n;
|
||||
argList = Common::move(a);
|
||||
argList->parent = this;
|
||||
if (argList->getValue()->type == kDatumArgListNoRet)
|
||||
isStatement = true;
|
||||
else
|
||||
isExpression = true;
|
||||
}
|
||||
bool noParens() const;
|
||||
bool isMemberExpr() const;
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ObjCallNode */
|
||||
|
||||
struct ObjCallNode : Node {
|
||||
Common::String name;
|
||||
Common::SharedPtr<Node> argList;
|
||||
|
||||
ObjCallNode(uint32 offset, Common::String n, Common::SharedPtr<Node> a) : Node(kObjCallNode, offset) {
|
||||
name = n;
|
||||
argList = Common::move(a);
|
||||
argList->parent = this;
|
||||
if (argList->getValue()->type == kDatumArgListNoRet)
|
||||
isStatement = true;
|
||||
else
|
||||
isExpression = true;
|
||||
}
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ObjCallV4Node */
|
||||
|
||||
struct ObjCallV4Node : Node {
|
||||
Common::SharedPtr<Node> obj;
|
||||
Common::SharedPtr<Node> argList;
|
||||
|
||||
ObjCallV4Node(uint32 offset, Common::SharedPtr<Node> o, Common::SharedPtr<Node> a) : Node(kObjCallV4Node, offset) {
|
||||
obj = o;
|
||||
argList = Common::move(a);
|
||||
argList->parent = this;
|
||||
if (argList->getValue()->type == kDatumArgListNoRet)
|
||||
isStatement = true;
|
||||
else
|
||||
isExpression = true;
|
||||
}
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* TheExprNode */
|
||||
|
||||
struct TheExprNode : ExprNode {
|
||||
Common::String prop;
|
||||
|
||||
TheExprNode(uint32 offset, Common::String p) : ExprNode(kTheExprNode, offset), prop(p) {}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* LastStringChunkExprNode */
|
||||
|
||||
struct LastStringChunkExprNode : ExprNode {
|
||||
ChunkExprType type;
|
||||
Common::SharedPtr<Node> obj;
|
||||
|
||||
LastStringChunkExprNode(uint32 offset, ChunkExprType t, Common::SharedPtr<Node> o)
|
||||
: ExprNode(kLastStringChunkExprNode, offset), type(t) {
|
||||
obj = Common::move(o);
|
||||
obj->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* StringChunkCountExprNode */
|
||||
|
||||
struct StringChunkCountExprNode : ExprNode {
|
||||
ChunkExprType type;
|
||||
Common::SharedPtr<Node> obj;
|
||||
|
||||
StringChunkCountExprNode(uint32 offset, ChunkExprType t, Common::SharedPtr<Node> o)
|
||||
: ExprNode(kStringChunkCountExprNode, offset), type(t) {
|
||||
obj = Common::move(o);
|
||||
obj->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* MenuPropExprNode */
|
||||
|
||||
struct MenuPropExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> menuID;
|
||||
unsigned int prop;
|
||||
|
||||
MenuPropExprNode(uint32 offset, Common::SharedPtr<Node> m, unsigned int p)
|
||||
: ExprNode(kMenuPropExprNode, offset), prop(p) {
|
||||
menuID = Common::move(m);
|
||||
menuID->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* MenuItemPropExprNode */
|
||||
|
||||
struct MenuItemPropExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> menuID;
|
||||
Common::SharedPtr<Node> itemID;
|
||||
unsigned int prop;
|
||||
|
||||
MenuItemPropExprNode(uint32 offset, Common::SharedPtr<Node> m, Common::SharedPtr<Node> i, unsigned int p)
|
||||
: ExprNode(kMenuItemPropExprNode, offset), prop(p) {
|
||||
menuID = Common::move(m);
|
||||
menuID->parent = this;
|
||||
itemID = Common::move(i);
|
||||
itemID->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* SoundPropExprNode */
|
||||
|
||||
struct SoundPropExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> soundID;
|
||||
unsigned int prop;
|
||||
|
||||
SoundPropExprNode(uint32 offset, Common::SharedPtr<Node> s, unsigned int p)
|
||||
: ExprNode(kSoundPropExprNode, offset), prop(p) {
|
||||
soundID = Common::move(s);
|
||||
soundID->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* SpritePropExprNode */
|
||||
|
||||
struct SpritePropExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> spriteID;
|
||||
unsigned int prop;
|
||||
|
||||
SpritePropExprNode(uint32 offset, Common::SharedPtr<Node> s, unsigned int p)
|
||||
: ExprNode(kSpritePropExprNode, offset), prop(p) {
|
||||
spriteID = Common::move(s);
|
||||
spriteID->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ThePropExprNode */
|
||||
|
||||
struct ThePropExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> obj;
|
||||
Common::String prop;
|
||||
|
||||
ThePropExprNode(uint32 offset, Common::SharedPtr<Node> o, Common::String p)
|
||||
: ExprNode(kThePropExprNode, offset), prop(p) {
|
||||
obj = Common::move(o);
|
||||
obj->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ObjPropExprNode */
|
||||
|
||||
struct ObjPropExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> obj;
|
||||
Common::String prop;
|
||||
|
||||
ObjPropExprNode(uint32 offset, Common::SharedPtr<Node> o, Common::String p)
|
||||
: ExprNode(kObjPropExprNode, offset), prop(p) {
|
||||
obj = Common::move(o);
|
||||
obj->parent = this;
|
||||
}
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ObjBracketExprNode */
|
||||
|
||||
struct ObjBracketExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> obj;
|
||||
Common::SharedPtr<Node> prop;
|
||||
|
||||
ObjBracketExprNode(uint32 offset, Common::SharedPtr<Node> o, Common::SharedPtr<Node> p)
|
||||
: ExprNode(kObjBracketExprNode, offset) {
|
||||
obj = Common::move(o);
|
||||
obj->parent = this;
|
||||
prop = Common::move(p);
|
||||
prop->parent = this;
|
||||
}
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ObjPropIndexExprNode */
|
||||
|
||||
struct ObjPropIndexExprNode : ExprNode {
|
||||
Common::SharedPtr<Node> obj;
|
||||
Common::String prop;
|
||||
Common::SharedPtr<Node> index;
|
||||
Common::SharedPtr<Node> index2;
|
||||
|
||||
ObjPropIndexExprNode(uint32 offset, Common::SharedPtr<Node> o, Common::String p, Common::SharedPtr<Node> i, Common::SharedPtr<Node> i2)
|
||||
: ExprNode(kObjPropIndexExprNode, offset), prop(p) {
|
||||
obj = Common::move(o);
|
||||
obj->parent = this;
|
||||
index = Common::move(i);
|
||||
index->parent = this;
|
||||
if (i2) {
|
||||
index2 = Common::move(i2);
|
||||
index2->parent = this;
|
||||
}
|
||||
}
|
||||
bool hasSpaces(bool dot) override;
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* ExitRepeatStmtNode */
|
||||
|
||||
struct ExitRepeatStmtNode : StmtNode {
|
||||
explicit ExitRepeatStmtNode(uint32 offset) : StmtNode(kExitRepeatStmtNode, offset) {}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* NextRepeatStmtNode */
|
||||
|
||||
struct NextRepeatStmtNode : StmtNode {
|
||||
explicit NextRepeatStmtNode(uint32 offset) : StmtNode(kNextRepeatStmtNode, offset) {}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* PutStmtNode */
|
||||
|
||||
struct PutStmtNode : StmtNode {
|
||||
PutType type;
|
||||
Common::SharedPtr<Node> variable;
|
||||
Common::SharedPtr<Node> value;
|
||||
|
||||
PutStmtNode(uint32 offset, PutType t, Common::SharedPtr<Node> var, Common::SharedPtr<Node> val)
|
||||
: StmtNode(kPutStmtNode, offset), type(t) {
|
||||
variable = Common::move(var);
|
||||
variable->parent = this;
|
||||
value = Common::move(val);
|
||||
value->parent = this;
|
||||
}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* WhenStmtNode */
|
||||
|
||||
struct WhenStmtNode : StmtNode {
|
||||
int event;
|
||||
Common::String script;
|
||||
|
||||
WhenStmtNode(uint32 offset, int e, Common::String s)
|
||||
: StmtNode(kWhenStmtNode, offset), event(e), script(s) {}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
/* NewObjNode */
|
||||
|
||||
struct NewObjNode : ExprNode {
|
||||
Common::String objType;
|
||||
Common::SharedPtr<Node> objArgs;
|
||||
|
||||
NewObjNode(uint32 offset, Common::String o, Common::SharedPtr<Node> args) : ExprNode(kNewObjNode, offset), objType(o), objArgs(args) {}
|
||||
void accept(NodeVisitor &visitor) const override;
|
||||
};
|
||||
|
||||
class NodeVisitor {
|
||||
public:
|
||||
virtual ~NodeVisitor() {}
|
||||
virtual void visit(const HandlerNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ErrorNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const CommentNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const NewObjNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const LiteralNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const IfStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const EndCaseNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ObjCallNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const PutStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const TheExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const BinaryOpNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const CaseStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ExitStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const TellStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const WhenStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const CaseLabelNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ChunkExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const InverseOpNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ObjCallV4Node &node) { defaultVisit(node); }
|
||||
virtual void visit(const OtherwiseNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const MemberExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ObjPropExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const PlayCmdStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ThePropExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const MenuPropExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const SoundCmdStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const SoundPropExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const AssignmentStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ExitRepeatStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const NextRepeatStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ObjBracketExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const SpritePropExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ChunkDeleteStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ChunkHiliteStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const RepeatWhileStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const MenuItemPropExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const ObjPropIndexExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const RepeatWithInStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const RepeatWithToStmtNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const SpriteWithinExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const LastStringChunkExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const SpriteIntersectsExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const StringChunkCountExprNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const VarNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const CallNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const BlockNode &node) { defaultVisit(node); }
|
||||
virtual void visit(const NotOpNode &node) { defaultVisit(node); }
|
||||
|
||||
virtual void defaultVisit(const Node &) {}
|
||||
};
|
||||
|
||||
/* AST */
|
||||
|
||||
struct AST {
|
||||
Common::SharedPtr<HandlerNode> root;
|
||||
BlockNode *currentBlock;
|
||||
|
||||
AST(uint32 offset, Handler *handler){
|
||||
root = Common::SharedPtr<HandlerNode>(new HandlerNode(offset, handler));
|
||||
currentBlock = root->block.get();
|
||||
}
|
||||
|
||||
void addStatement(Common::SharedPtr<Node> statement);
|
||||
void enterBlock(BlockNode *block);
|
||||
void exitBlock();
|
||||
};
|
||||
|
||||
} // namespace LingoDec
|
||||
|
||||
#endif // LINGODEC_AST_H
|
||||
876
engines/director/lingo/lingodec/codewritervisitor.cpp
Normal file
876
engines/director/lingo/lingodec/codewritervisitor.cpp
Normal file
@@ -0,0 +1,876 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "common/ptr.h"
|
||||
#include "./ast.h"
|
||||
#include "./handler.h"
|
||||
#include "./names.h"
|
||||
#include "./script.h"
|
||||
#include "./codewritervisitor.h"
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
void CodeWriterVisitor::visit(const HandlerNode &node) {
|
||||
if (node.handler->isGenericEvent) {
|
||||
node.block->accept(*this);
|
||||
} else {
|
||||
Script *script = node.handler->script;
|
||||
bool isMethod = script->isFactory();
|
||||
if (isMethod) {
|
||||
write("method ");
|
||||
} else {
|
||||
write("on ");
|
||||
}
|
||||
write(node.handler->name);
|
||||
if (node.handler->argumentNames.size() > 0) {
|
||||
write(" ");
|
||||
for (size_t i = 0; i < node.handler->argumentNames.size(); i++) {
|
||||
if (i > 0)
|
||||
write(", ");
|
||||
write(node.handler->argumentNames[i]);
|
||||
}
|
||||
}
|
||||
writeLine();
|
||||
indent();
|
||||
if (isMethod && script->propertyNames.size() > 0 && node.handler == &script->handlers[0]) {
|
||||
write("instance ");
|
||||
for (size_t i = 0; i < script->propertyNames.size(); i++) {
|
||||
if (i > 0)
|
||||
write(", ");
|
||||
write(script->propertyNames[i]);
|
||||
}
|
||||
writeLine();
|
||||
}
|
||||
if (node.handler->globalNames.size() > 0) {
|
||||
write("global ");
|
||||
for (size_t i = 0; i < node.handler->globalNames.size(); i++) {
|
||||
if (i > 0)
|
||||
write(", ");
|
||||
write(node.handler->globalNames[i]);
|
||||
}
|
||||
writeLine();
|
||||
}
|
||||
unindent();
|
||||
node.block->accept(*this);
|
||||
if (!isMethod) {
|
||||
writeLine("end");
|
||||
}
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ErrorNode &) {
|
||||
write("ERROR");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const CommentNode &node) {
|
||||
write("-- ");
|
||||
write(node.text);
|
||||
}
|
||||
void CodeWriterVisitor::visit(const NewObjNode &node) {
|
||||
write("new ");
|
||||
write(node.objType);
|
||||
write("(");
|
||||
node.objArgs->accept(*this);
|
||||
write(")");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const LiteralNode &node) {
|
||||
write(*node.value);
|
||||
}
|
||||
void CodeWriterVisitor::visit(const IfStmtNode &node) {
|
||||
write("if ");
|
||||
node.condition->accept(*this);
|
||||
write(" then");
|
||||
if (_sum) {
|
||||
if (node.hasElse) {
|
||||
write(" / else");
|
||||
}
|
||||
} else {
|
||||
writeLine();
|
||||
node.block1->accept(*this);
|
||||
if (node.hasElse) {
|
||||
writeLine("else");
|
||||
node.block2->accept(*this);
|
||||
}
|
||||
write("end if");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const EndCaseNode &) {
|
||||
write("end case");
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::visit(const ObjCallNode &node) {
|
||||
auto &rawArgs = node.argList->getValue()->l;
|
||||
|
||||
auto &obj = rawArgs[0];
|
||||
bool parenObj = obj->hasSpaces(_dot);
|
||||
if (parenObj) {
|
||||
write("(");
|
||||
}
|
||||
obj->accept(*this);
|
||||
if (parenObj) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
write(".");
|
||||
write(node.name);
|
||||
write("(");
|
||||
for (size_t i = 1; i < rawArgs.size(); i++) {
|
||||
if (i > 1)
|
||||
write(", ");
|
||||
rawArgs[i]->accept(*this);
|
||||
}
|
||||
write(")");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const PutStmtNode &node) {
|
||||
write("put ");
|
||||
node.value->accept(*this);
|
||||
write(" ");
|
||||
write(StandardNames::putTypeNames[node.type]);
|
||||
write(" ");
|
||||
node.variable->accept(*this); // TODO: we want the variable to always be verbose
|
||||
}
|
||||
void CodeWriterVisitor::visit(const TheExprNode &node) {
|
||||
write("the ");
|
||||
write(node.prop);
|
||||
}
|
||||
void CodeWriterVisitor::visit(const BinaryOpNode &node) {
|
||||
unsigned int precedence = node.getPrecedence();
|
||||
bool parenLeft = false;
|
||||
bool parenRight = false;
|
||||
if (precedence) {
|
||||
if (node.left->type == kBinaryOpNode) {
|
||||
auto leftBinaryOpNode = static_cast<BinaryOpNode *>(node.left.get());
|
||||
parenLeft = (leftBinaryOpNode->getPrecedence() != precedence);
|
||||
}
|
||||
parenRight = (node.right->type == kBinaryOpNode);
|
||||
}
|
||||
|
||||
if (parenLeft) {
|
||||
write("(");
|
||||
}
|
||||
node.left->accept(*this);
|
||||
if (parenLeft) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
write(" ");
|
||||
write(StandardNames::binaryOpNames[node.opcode]);
|
||||
write(" ");
|
||||
|
||||
if (parenRight) {
|
||||
write("(");
|
||||
}
|
||||
node.right->accept(*this);
|
||||
if (parenRight) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const CaseStmtNode &node) {
|
||||
write("case ");
|
||||
node.value->accept(*this);
|
||||
write(" of");
|
||||
if (_sum) {
|
||||
if (!node.firstLabel) {
|
||||
if (node.otherwise) {
|
||||
write(" / otherwise:");
|
||||
} else {
|
||||
write(" / end case");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
writeLine();
|
||||
indent();
|
||||
if (node.firstLabel) {
|
||||
node.firstLabel->accept(*this);
|
||||
}
|
||||
if (node.otherwise) {
|
||||
node.otherwise->accept(*this);
|
||||
}
|
||||
unindent();
|
||||
write("end case");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ExitStmtNode &) {
|
||||
write("exit");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const TellStmtNode &node) {
|
||||
write("tell ");
|
||||
node.window->accept(*this);
|
||||
if (!_sum) {
|
||||
writeLine();
|
||||
node.block->accept(*this);
|
||||
write("end tell");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const WhenStmtNode &node) {
|
||||
write("when ");
|
||||
write(StandardNames::whenEventNames[node.event]);
|
||||
write(" then");
|
||||
|
||||
for (size_t i = 0; i < node.script.size(); i++) {
|
||||
char ch = node.script[i];
|
||||
if (ch == '\r') {
|
||||
if (i != node.script.size() - 1) {
|
||||
writeLine();
|
||||
}
|
||||
} else {
|
||||
write(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::visit(const CaseLabelNode &node) {
|
||||
if (_sum) {
|
||||
write("(case) ");
|
||||
if (node.parent->type == kCaseLabelNode) {
|
||||
auto parentLabel = static_cast<CaseLabelNode *>(node.parent);
|
||||
if (parentLabel->nextOr.get() == &node) {
|
||||
write("..., ");
|
||||
}
|
||||
}
|
||||
|
||||
bool parenValue = node.value->hasSpaces(_dot);
|
||||
if (parenValue) {
|
||||
write("(");
|
||||
}
|
||||
node.value->accept(*this);
|
||||
if (parenValue) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
if (node.nextOr) {
|
||||
write(", ...");
|
||||
} else {
|
||||
write(":");
|
||||
}
|
||||
} else {
|
||||
bool parenValue = node.value->hasSpaces(_dot);
|
||||
if (parenValue) {
|
||||
write("(");
|
||||
}
|
||||
node.value->accept(*this);
|
||||
if (parenValue) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
if (node.nextOr) {
|
||||
write(", ");
|
||||
node.nextOr->accept(*this);
|
||||
} else {
|
||||
writeLine(":");
|
||||
node.block->accept(*this);
|
||||
}
|
||||
if (node.nextLabel) {
|
||||
node.nextLabel->accept(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ChunkExprNode &node) {
|
||||
write(StandardNames::chunkTypeNames[node.type]);
|
||||
write(" ");
|
||||
node.first->accept(*this);
|
||||
if (!(node.last->type == kLiteralNode && node.last->getValue()->type == kDatumInt && node.last->getValue()->i == 0)) {
|
||||
write(" to ");
|
||||
node.last->accept(*this);
|
||||
}
|
||||
write(" of ");
|
||||
node.string->accept(*this); // TODO: we want the string to always be verbose
|
||||
}
|
||||
void CodeWriterVisitor::visit(const InverseOpNode &node) {
|
||||
write("-");
|
||||
|
||||
bool parenOperand = node.operand->hasSpaces(_dot);
|
||||
if (parenOperand) {
|
||||
write("(");
|
||||
}
|
||||
node.operand->accept(*this);
|
||||
if (parenOperand) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ObjCallV4Node &node) {
|
||||
node.obj->accept(*this);
|
||||
write("(");
|
||||
node.argList->accept(*this);
|
||||
write(")");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const OtherwiseNode &node) {
|
||||
if (_sum) {
|
||||
write("(case) otherwise:");
|
||||
} else {
|
||||
writeLine("otherwise:");
|
||||
node.block->accept(*this);
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const MemberExprNode &node) {
|
||||
bool hasCastID = node.castID && !(node.castID->type == kLiteralNode && node.castID->getValue()->type == kDatumInt && node.castID->getValue()->i == 0);
|
||||
write(node.type);
|
||||
if (_dot) {
|
||||
write("(");
|
||||
node.memberID->accept(*this);
|
||||
if (hasCastID) {
|
||||
write(", ");
|
||||
node.castID->accept(*this);
|
||||
}
|
||||
write(")");
|
||||
} else {
|
||||
write(" ");
|
||||
|
||||
bool parenMemberID = (node.memberID->type == kBinaryOpNode);
|
||||
if (parenMemberID) {
|
||||
write("(");
|
||||
}
|
||||
node.memberID->accept(*this);
|
||||
if (parenMemberID) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
if (hasCastID) {
|
||||
write(" of castLib ");
|
||||
|
||||
bool parenCastID = (node.castID->type == kBinaryOpNode);
|
||||
if (parenCastID) {
|
||||
write("(");
|
||||
}
|
||||
node.castID->accept(*this);
|
||||
if (parenCastID) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ObjPropExprNode &node) {
|
||||
if (_dot) {
|
||||
bool parenObj = node.obj->hasSpaces(_dot);
|
||||
if (parenObj) {
|
||||
write("(");
|
||||
}
|
||||
node.obj->accept(*this);
|
||||
if (parenObj) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
write(".");
|
||||
write(node.prop);
|
||||
} else {
|
||||
write("the ");
|
||||
write(node.prop);
|
||||
write(" of ");
|
||||
|
||||
bool parenObj = (node.obj->type == kBinaryOpNode);
|
||||
if (parenObj) {
|
||||
write("(");
|
||||
}
|
||||
node.obj->accept(*this);
|
||||
if (parenObj) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const PlayCmdStmtNode &node) {
|
||||
auto &rawArgs = node.argList->getValue()->l;
|
||||
|
||||
write("play");
|
||||
|
||||
if (rawArgs.size() == 0) {
|
||||
write(" done");
|
||||
return;
|
||||
}
|
||||
|
||||
auto &frame = rawArgs[0];
|
||||
if (rawArgs.size() == 1) {
|
||||
write(" frame ");
|
||||
frame->accept(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
auto &movie = rawArgs[1];
|
||||
if (!(frame->type == kLiteralNode && frame->getValue()->type == kDatumInt && frame->getValue()->i == 1)) {
|
||||
write(" frame ");
|
||||
frame->accept(*this);
|
||||
write(" of");
|
||||
}
|
||||
write(" movie ");
|
||||
movie->accept(*this);
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ThePropExprNode &node) {
|
||||
write("the ");
|
||||
write(node.prop);
|
||||
write(" of ");
|
||||
|
||||
bool parenObj = (node.obj->type == kBinaryOpNode);
|
||||
if (parenObj) {
|
||||
write("(");
|
||||
}
|
||||
node.obj->accept(*this); // TODO: we want the object to always be verbose
|
||||
if (parenObj) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const MenuPropExprNode &node) {
|
||||
write("the ");
|
||||
write(StandardNames::menuPropertyNames[node.prop]);
|
||||
write(" of menu ");
|
||||
|
||||
bool parenMenuID = (node.menuID->type == kBinaryOpNode);
|
||||
if (parenMenuID) {
|
||||
write("(");
|
||||
}
|
||||
node.menuID->accept(*this);
|
||||
if (parenMenuID) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const SoundCmdStmtNode &node) {
|
||||
write("sound ");
|
||||
write(node.cmd);
|
||||
if (node.argList->getValue()->l.size() > 0) {
|
||||
write(" ");
|
||||
node.argList->accept(*this);
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const SoundPropExprNode &node) {
|
||||
write("the ");
|
||||
write(StandardNames::soundPropertyNames[node.prop]);
|
||||
write(" of sound ");
|
||||
|
||||
bool parenSoundID = (node.soundID->type == kBinaryOpNode);
|
||||
if (parenSoundID) {
|
||||
write("(");
|
||||
}
|
||||
node.soundID->accept(*this);
|
||||
if (parenSoundID) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const AssignmentStmtNode &node) {
|
||||
if (!_dot) { // TODO: forceVerboseÒ
|
||||
write("set ");
|
||||
node.variable->accept(*this); // TODO: we want the variable to always be verbose
|
||||
write(" to ");
|
||||
node.value->accept(*this);
|
||||
} else {
|
||||
node.variable->accept(*this);
|
||||
write(" = ");
|
||||
node.value->accept(*this);
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ExitRepeatStmtNode &) {
|
||||
write("exit repeat");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const NextRepeatStmtNode &) {
|
||||
write("next repeat");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ObjBracketExprNode &node) {
|
||||
bool parenObj = node.obj->hasSpaces(_dot);
|
||||
if (parenObj) {
|
||||
write("(");
|
||||
}
|
||||
node.obj->accept(*this);
|
||||
if (parenObj) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
write("[");
|
||||
node.prop->accept(*this);
|
||||
write("]");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const SpritePropExprNode &node) {
|
||||
write("the ");
|
||||
write(StandardNames::spritePropertyNames[node.prop]);
|
||||
write(" of sprite ");
|
||||
|
||||
bool parenSpriteID = (node.spriteID->type == kBinaryOpNode);
|
||||
if (parenSpriteID) {
|
||||
write("(");
|
||||
}
|
||||
node.spriteID->accept(*this);
|
||||
if (parenSpriteID) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ChunkDeleteStmtNode &node) {
|
||||
write("delete ");
|
||||
node.chunk->accept(*this);
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ChunkHiliteStmtNode &node) {
|
||||
write("hilite ");
|
||||
node.chunk->accept(*this);
|
||||
}
|
||||
void CodeWriterVisitor::visit(const RepeatWhileStmtNode &node) {
|
||||
write("repeat while ");
|
||||
node.condition->accept(*this);
|
||||
if (!_sum) {
|
||||
writeLine();
|
||||
node.block->accept(*this);
|
||||
write("end repeat");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const MenuItemPropExprNode &node) {
|
||||
write("the ");
|
||||
write(StandardNames::menuItemPropertyNames[node.prop]);
|
||||
write(" of menuItem ");
|
||||
|
||||
bool parenItemID = (node.itemID->type == kBinaryOpNode);
|
||||
if (parenItemID) {
|
||||
write("(");
|
||||
}
|
||||
node.itemID->accept(*this);
|
||||
if (parenItemID) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
write(" of menu ");
|
||||
|
||||
bool parenMenuID = (node.menuID->type ==kBinaryOpNode);
|
||||
if (parenMenuID) {
|
||||
write("(");
|
||||
}
|
||||
node.menuID->accept(*this);
|
||||
if (parenMenuID) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const ObjPropIndexExprNode &node) {
|
||||
bool parenObj = node.obj->hasSpaces(_dot);
|
||||
if (parenObj) {
|
||||
write("(");
|
||||
}
|
||||
node.obj->accept(*this);
|
||||
if (parenObj) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
write(".");
|
||||
write(node.prop);
|
||||
write("[");
|
||||
node.index->accept(*this);
|
||||
if (node.index2) {
|
||||
write("..");
|
||||
node.index2->accept(*this);
|
||||
}
|
||||
write("]");
|
||||
}
|
||||
void CodeWriterVisitor::visit(const RepeatWithInStmtNode &node) {
|
||||
write("repeat with ");
|
||||
write(node.varName);
|
||||
write(" in ");
|
||||
node.list->accept(*this);
|
||||
if (!_sum) {
|
||||
writeLine();
|
||||
node.block->accept(*this);
|
||||
write("end repeat");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const RepeatWithToStmtNode &node) {
|
||||
write("repeat with ");
|
||||
write(node.varName);
|
||||
write(" = ");
|
||||
node.start->accept(*this);
|
||||
if (node.up) {
|
||||
write(" to ");
|
||||
} else {
|
||||
write(" down to ");
|
||||
}
|
||||
node.end->accept(*this);
|
||||
if (!_sum) {
|
||||
writeLine();
|
||||
node.block->accept(*this);
|
||||
write("end repeat");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const SpriteWithinExprNode &node) {
|
||||
write("sprite ");
|
||||
|
||||
bool parenFirstSprite = (node.firstSprite->type == kBinaryOpNode);
|
||||
if (parenFirstSprite) {
|
||||
write("(");
|
||||
}
|
||||
node.firstSprite->accept(*this);
|
||||
if (parenFirstSprite) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
write(" within ");
|
||||
|
||||
bool parenSecondSprite = (node.secondSprite->type == kBinaryOpNode);
|
||||
if (parenSecondSprite) {
|
||||
write("(");
|
||||
}
|
||||
node.secondSprite->accept(*this);
|
||||
if (parenSecondSprite) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const LastStringChunkExprNode &node) {
|
||||
write("the last ");
|
||||
write(StandardNames::chunkTypeNames[node.type]);
|
||||
write(" in ");
|
||||
|
||||
bool parenObj = (node.obj->type == kBinaryOpNode);
|
||||
if (parenObj) {
|
||||
write("(");
|
||||
}
|
||||
node.obj->accept(*this); // TODO: we want the object to always be verbose
|
||||
if (parenObj) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const SpriteIntersectsExprNode &node) {
|
||||
write("sprite ");
|
||||
|
||||
bool parenFirstSprite = (node.firstSprite->type == kBinaryOpNode);
|
||||
if (parenFirstSprite) {
|
||||
write("(");
|
||||
}
|
||||
node.firstSprite->accept(*this);
|
||||
if (parenFirstSprite) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
write(" intersects ");
|
||||
|
||||
bool parenSecondSprite = (node.secondSprite->type == kBinaryOpNode);
|
||||
if (parenSecondSprite) {
|
||||
write("(");
|
||||
}
|
||||
node.secondSprite->accept(*this);
|
||||
if (parenSecondSprite) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const StringChunkCountExprNode &node) {
|
||||
write("the number of ");
|
||||
write(StandardNames::chunkTypeNames[node.type]); // we want the object to always be verbose
|
||||
write("s in ");
|
||||
|
||||
bool parenObj = (node.obj->type == kBinaryOpNode);
|
||||
if (parenObj) {
|
||||
write("(");
|
||||
}
|
||||
node.obj->accept(*this); // TODO dot false?
|
||||
if (parenObj) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const VarNode &node) {
|
||||
write(node.varName);
|
||||
}
|
||||
void CodeWriterVisitor::visit(const CallNode &node) {
|
||||
if (node.isExpression && node.argList->getValue()->l.size() == 0) {
|
||||
if (node.name == "pi") {
|
||||
write("PI");
|
||||
return;
|
||||
}
|
||||
if (node.name == "space") {
|
||||
write("SPACE");
|
||||
return;
|
||||
}
|
||||
if (node.name == "void") {
|
||||
write("VOID");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_dot && node.isMemberExpr()) {
|
||||
/**
|
||||
* In some cases, member expressions such as `member 1 of castLib 1` compile
|
||||
* to the function call `member(1, 1)`. However, this doesn't parse correctly
|
||||
* in pre-dot-syntax versions of Director, and `put(member(1, 1))` does not
|
||||
* compile. Therefore, we rewrite these expressions to the verbose syntax when
|
||||
* in verbose mode.
|
||||
*/
|
||||
write(node.name);
|
||||
write(" ");
|
||||
|
||||
auto memberID = node.argList->getValue()->l[0];
|
||||
bool parenMemberID = (memberID->type == kBinaryOpNode);
|
||||
if (parenMemberID) {
|
||||
write("(");
|
||||
}
|
||||
memberID->accept(*this);
|
||||
if (parenMemberID) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
if (node.argList->getValue()->l.size() == 2) {
|
||||
write(" of castLib ");
|
||||
|
||||
auto castID = node.argList->getValue()->l[1];
|
||||
bool parenCastID = (castID->type == kBinaryOpNode);
|
||||
if (parenCastID) {
|
||||
write("(");
|
||||
}
|
||||
castID->accept(*this);
|
||||
if (parenCastID) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
write(node.name);
|
||||
if (node.noParens()) {
|
||||
write(" ");
|
||||
node.argList->accept(*this);
|
||||
} else {
|
||||
write("(");
|
||||
node.argList->accept(*this);
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
void CodeWriterVisitor::visit(const BlockNode &node) {
|
||||
indent();
|
||||
for (const auto &child : node.children) {
|
||||
child->accept(*this);
|
||||
writeLine();
|
||||
}
|
||||
unindent();
|
||||
}
|
||||
void CodeWriterVisitor::visit(const NotOpNode &node) {
|
||||
write("not ");
|
||||
|
||||
bool parenOperand = node.operand->hasSpaces(_dot);
|
||||
if (parenOperand) {
|
||||
write("(");
|
||||
}
|
||||
node.operand->accept(*this);
|
||||
if (parenOperand) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::indent() {
|
||||
_indent++;
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::unindent() {
|
||||
if (_indent > 0)
|
||||
_indent--;
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::writeIndentation() {
|
||||
if (_indentWritten)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _indent; i++) {
|
||||
_str += _indentation;
|
||||
}
|
||||
|
||||
_indentWritten = true;
|
||||
_lineWidth = _indent * _indentation.size();
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::write(char c) {
|
||||
writeIndentation();
|
||||
_str += c;
|
||||
_lineWidth++;
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::write(const Common::String &s) {
|
||||
writeIndentation();
|
||||
_str += s;
|
||||
_lineWidth += s.size();
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::writeLine() {
|
||||
_str += _lineEnding;
|
||||
_lineWidth += _lineEnding.size();
|
||||
_indentWritten = false;
|
||||
_lineWidth = 0;
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::writeLine(const Common::String &s) {
|
||||
writeIndentation();
|
||||
_str += s;
|
||||
_lineWidth += s.size();
|
||||
_str += _lineEnding;
|
||||
_lineWidth += _lineEnding.size();
|
||||
_indentWritten = false;
|
||||
_lineWidth = 0;
|
||||
}
|
||||
|
||||
void CodeWriterVisitor::write(Datum &datum) {
|
||||
switch (datum.type) {
|
||||
case kDatumVoid:
|
||||
write("VOID");
|
||||
return;
|
||||
case kDatumSymbol:
|
||||
write("#" + datum.s);
|
||||
return;
|
||||
case kDatumVarRef:
|
||||
write(datum.s);
|
||||
return;
|
||||
case kDatumString:
|
||||
if (datum.s.size() == 0) {
|
||||
write("EMPTY");
|
||||
return;
|
||||
}
|
||||
if (datum.s.size() == 1) {
|
||||
switch (datum.s[0]) {
|
||||
case '\x03':
|
||||
write("ENTER");
|
||||
return;
|
||||
case '\x08':
|
||||
write("BACKSPACE");
|
||||
return;
|
||||
case '\t':
|
||||
write("TAB");
|
||||
return;
|
||||
case '\r':
|
||||
write("RETURN");
|
||||
return;
|
||||
case '"':
|
||||
write("QUOTE");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_sum) {
|
||||
write("\"" + Common::toPrintable(datum.s) + "\"");
|
||||
return;
|
||||
}
|
||||
write("\"" + datum.s + "\"");
|
||||
return;
|
||||
case kDatumInt:
|
||||
write(Common::String::format("%d", datum.i));
|
||||
return;
|
||||
case kDatumFloat:
|
||||
write(Common::String::format("%g", datum.f));
|
||||
return;
|
||||
case kDatumList:
|
||||
case kDatumArgList:
|
||||
case kDatumArgListNoRet: {
|
||||
if (datum.type == kDatumList)
|
||||
write("[");
|
||||
for (size_t ii = 0; ii < datum.l.size(); ii++) {
|
||||
if (ii > 0)
|
||||
write(", ");
|
||||
datum.l[ii]->accept(*this);
|
||||
}
|
||||
if (datum.type == kDatumList)
|
||||
write("]");
|
||||
}
|
||||
return;
|
||||
case kDatumPropList: {
|
||||
write("[");
|
||||
if (datum.l.size() == 0) {
|
||||
write(":");
|
||||
} else {
|
||||
for (size_t ii = 0; ii < datum.l.size(); ii += 2) {
|
||||
if (ii > 0)
|
||||
write(", ");
|
||||
datum.l[ii]->accept(*this);
|
||||
write(": ");
|
||||
datum.l[ii + 1]->accept(*this);
|
||||
}
|
||||
}
|
||||
write("]");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace LingoDec
|
||||
92
engines/director/lingo/lingodec/codewritervisitor.h
Normal file
92
engines/director/lingo/lingodec/codewritervisitor.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef LINGODEC_CODEWRITERVISITOR_H
|
||||
#define LINGODEC_CODEWRITERVISITOR_H
|
||||
|
||||
#include "./ast.h"
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
class CodeWriterVisitor: public LingoDec::NodeVisitor {
|
||||
public:
|
||||
CodeWriterVisitor(bool dotSyntax, bool sum, const Common::String &lineEnding = "\n", const Common::String &indentation = " ")
|
||||
: _dot(dotSyntax), _sum(sum), _lineEnding(lineEnding), _indentation(indentation) {}
|
||||
virtual ~CodeWriterVisitor() {}
|
||||
virtual void visit(const LingoDec::HandlerNode& node) override;
|
||||
virtual void visit(const LingoDec::ErrorNode& node) override;
|
||||
virtual void visit(const LingoDec::CommentNode& node) override;
|
||||
virtual void visit(const LingoDec::NewObjNode& node) override;
|
||||
virtual void visit(const LingoDec::LiteralNode& node) override;
|
||||
virtual void visit(const LingoDec::IfStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::EndCaseNode& node) override;
|
||||
virtual void visit(const LingoDec::ObjCallNode& node) override;
|
||||
virtual void visit(const LingoDec::PutStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::TheExprNode& node) override;
|
||||
virtual void visit(const LingoDec::BinaryOpNode& node) override;
|
||||
virtual void visit(const LingoDec::CaseStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::ExitStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::TellStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::WhenStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::CaseLabelNode& node) override;
|
||||
virtual void visit(const LingoDec::ChunkExprNode& node) override;
|
||||
virtual void visit(const LingoDec::InverseOpNode& node) override;
|
||||
virtual void visit(const LingoDec::ObjCallV4Node& node) override;
|
||||
virtual void visit(const LingoDec::OtherwiseNode& node) override;
|
||||
virtual void visit(const LingoDec::MemberExprNode& node) override;
|
||||
virtual void visit(const LingoDec::ObjPropExprNode& node) override;
|
||||
virtual void visit(const LingoDec::PlayCmdStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::ThePropExprNode& node) override;
|
||||
virtual void visit(const LingoDec::MenuPropExprNode& node) override;
|
||||
virtual void visit(const LingoDec::SoundCmdStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::SoundPropExprNode& node) override;
|
||||
virtual void visit(const LingoDec::AssignmentStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::ExitRepeatStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::NextRepeatStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::ObjBracketExprNode& node) override;
|
||||
virtual void visit(const LingoDec::SpritePropExprNode& node) override;
|
||||
virtual void visit(const LingoDec::ChunkDeleteStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::ChunkHiliteStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::RepeatWhileStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::MenuItemPropExprNode& node) override;
|
||||
virtual void visit(const LingoDec::ObjPropIndexExprNode& node) override;
|
||||
virtual void visit(const LingoDec::RepeatWithInStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::RepeatWithToStmtNode& node) override;
|
||||
virtual void visit(const LingoDec::SpriteWithinExprNode& node) override;
|
||||
virtual void visit(const LingoDec::LastStringChunkExprNode& node) override;
|
||||
virtual void visit(const LingoDec::SpriteIntersectsExprNode& node) override;
|
||||
virtual void visit(const LingoDec::StringChunkCountExprNode& node) override;
|
||||
virtual void visit(const LingoDec::VarNode& node) override;
|
||||
virtual void visit(const LingoDec::CallNode& node) override;
|
||||
virtual void visit(const LingoDec::BlockNode& node) override;
|
||||
virtual void visit(const LingoDec::NotOpNode& node) override;
|
||||
|
||||
size_t lineWidth() const { return _lineWidth; }
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeIndentation();
|
||||
void write(char c);
|
||||
void write(const Common::String& s);
|
||||
void writeLine();
|
||||
void writeLine(const Common::String& s);
|
||||
void write(LingoDec::Datum& datum);
|
||||
|
||||
public:
|
||||
Common::String _str;
|
||||
|
||||
private:
|
||||
bool _dot = false;
|
||||
bool _sum = false;
|
||||
Common::String _lineEnding;
|
||||
Common::String _indentation = " ";
|
||||
bool _indentWritten = false;
|
||||
int _indent = 0;
|
||||
size_t _lineWidth = 0;
|
||||
};
|
||||
|
||||
} // namespace LingoDec
|
||||
|
||||
#endif // LINGODEC_CODEWRITERVISITOR_H
|
||||
84
engines/director/lingo/lingodec/context.cpp
Normal file
84
engines/director/lingo/lingodec/context.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/util.h"
|
||||
#include "./context.h"
|
||||
#include "./names.h"
|
||||
#include "./resolver.h"
|
||||
#include "./script.h"
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
struct ScriptContextMapEntry;
|
||||
|
||||
/* ScriptContext */
|
||||
|
||||
void ScriptContext::read(Common::SeekableReadStream &stream) {
|
||||
// Lingo scripts are always big endian regardless of file endianness
|
||||
unknown0 = stream.readSint32BE();
|
||||
unknown1 = stream.readSint32BE();
|
||||
entryCount = stream.readUint32BE();
|
||||
entryCount2 = stream.readUint32BE();
|
||||
entriesOffset = stream.readUint16BE();
|
||||
unknown2 = stream.readSint16BE();
|
||||
unknown3 = stream.readSint32BE();
|
||||
unknown4 = stream.readSint32BE();
|
||||
unknown5 = stream.readSint32BE();
|
||||
lnamSectionID = stream.readSint32BE();
|
||||
validCount = stream.readUint16BE();
|
||||
flags = stream.readUint16BE();
|
||||
freePointer = stream.readSint16BE();
|
||||
|
||||
stream.seek(entriesOffset);
|
||||
sectionMap.resize(entryCount);
|
||||
for (auto &entry : sectionMap) {
|
||||
entry.read(stream);
|
||||
}
|
||||
|
||||
lnam = resolver->getScriptNames(lnamSectionID);
|
||||
for (uint32 i = 1; i <= entryCount; i++) {
|
||||
auto section = sectionMap[i - 1];
|
||||
if (section.sectionID > -1) {
|
||||
Script *script = resolver->getScript(section.sectionID);
|
||||
script->setContext(this);
|
||||
scripts[i] = script;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = scripts.begin(); it != scripts.end(); ++it) {
|
||||
Script *script = it->second;
|
||||
if (script->isFactory()) {
|
||||
Script *parent = scripts[script->parentNumber + 1];
|
||||
parent->factories.push_back(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptContext::validName(int id) const {
|
||||
return lnam->validName(id);
|
||||
}
|
||||
|
||||
Common::String ScriptContext::getName(int id) const {
|
||||
return lnam->getName(id);
|
||||
}
|
||||
|
||||
void ScriptContext::parseScripts() {
|
||||
for (auto it = scripts.begin(); it != scripts.end(); ++it) {
|
||||
it->second->parse();
|
||||
}
|
||||
}
|
||||
|
||||
/* ScriptContextMapEntry */
|
||||
|
||||
void ScriptContextMapEntry::read(Common::SeekableReadStream &stream) {
|
||||
unknown0 = stream.readSint32BE();
|
||||
sectionID = stream.readSint32BE();
|
||||
unknown1 = stream.readUint16BE();
|
||||
unknown2 = stream.readUint16BE();
|
||||
}
|
||||
|
||||
} // namespace LingoDec
|
||||
70
engines/director/lingo/lingodec/context.h
Normal file
70
engines/director/lingo/lingodec/context.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef LINGODEC_CONTEXT_H
|
||||
#define LINGODEC_CONTEXT_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/stablemap.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
class ChunkResolver;
|
||||
struct Script;
|
||||
struct ScriptContextMapEntry;
|
||||
struct ScriptNames;
|
||||
|
||||
/* ScriptContext */
|
||||
|
||||
struct ScriptContext {
|
||||
int32 unknown0;
|
||||
int32 unknown1;
|
||||
uint32 entryCount;
|
||||
uint32 entryCount2;
|
||||
uint16 entriesOffset;
|
||||
int16 unknown2;
|
||||
int32 unknown3;
|
||||
int32 unknown4;
|
||||
int32 unknown5;
|
||||
int32 lnamSectionID;
|
||||
uint16 validCount;
|
||||
uint16 flags;
|
||||
int16 freePointer;
|
||||
|
||||
unsigned int version;
|
||||
ChunkResolver *resolver;
|
||||
ScriptNames *lnam;
|
||||
Common::Array<ScriptContextMapEntry> sectionMap;
|
||||
Common::StableMap<uint32, Script *> scripts;
|
||||
|
||||
ScriptContext(unsigned int version_, ChunkResolver *resolver_) : version(version_),
|
||||
resolver(resolver_),
|
||||
lnam(nullptr) {}
|
||||
|
||||
void read(Common::SeekableReadStream &stream);
|
||||
bool validName(int id) const;
|
||||
Common::String getName(int id) const;
|
||||
void parseScripts();
|
||||
};
|
||||
|
||||
/* ScriptContextMapEntry */
|
||||
|
||||
struct ScriptContextMapEntry {
|
||||
int32 unknown0;
|
||||
int32 sectionID;
|
||||
uint16 unknown1;
|
||||
uint16 unknown2;
|
||||
|
||||
void read(Common::SeekableReadStream &stream);
|
||||
};
|
||||
|
||||
} // namespace LingoDec
|
||||
|
||||
#endif // LINGODEC_CONTEXT_H
|
||||
216
engines/director/lingo/lingodec/enums.h
Normal file
216
engines/director/lingo/lingodec/enums.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef LINGODEC_ENUMS_H
|
||||
#define LINGODEC_ENUMS_H
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
enum OpCode {
|
||||
// single-byte
|
||||
kOpRet = 0x01,
|
||||
kOpRetFactory = 0x02,
|
||||
kOpPushZero = 0x03,
|
||||
kOpMul = 0x04,
|
||||
kOpAdd = 0x05,
|
||||
kOpSub = 0x06,
|
||||
kOpDiv = 0x07,
|
||||
kOpMod = 0x08,
|
||||
kOpInv = 0x09,
|
||||
kOpJoinStr = 0x0a,
|
||||
kOpJoinPadStr = 0x0b,
|
||||
kOpLt = 0x0c,
|
||||
kOpLtEq = 0x0d,
|
||||
kOpNtEq = 0x0e,
|
||||
kOpEq = 0x0f,
|
||||
kOpGt = 0x10,
|
||||
kOpGtEq = 0x11,
|
||||
kOpAnd = 0x12,
|
||||
kOpOr = 0x13,
|
||||
kOpNot = 0x14,
|
||||
kOpContainsStr = 0x15,
|
||||
kOpContains0Str = 0x16,
|
||||
kOpGetChunk = 0x17,
|
||||
kOpHiliteChunk = 0x18,
|
||||
kOpOntoSpr = 0x19,
|
||||
kOpIntoSpr = 0x1a,
|
||||
kOpGetField = 0x1b,
|
||||
kOpStartTell = 0x1c,
|
||||
kOpEndTell = 0x1d,
|
||||
kOpPushList = 0x1e,
|
||||
kOpPushPropList = 0x1f,
|
||||
kOpSwap = 0x21,
|
||||
|
||||
// multi-byte
|
||||
kOpPushInt8 = 0x41,
|
||||
kOpPushArgListNoRet = 0x42,
|
||||
kOpPushArgList = 0x43,
|
||||
kOpPushCons = 0x44,
|
||||
kOpPushSymb = 0x45,
|
||||
kOpPushVarRef = 0x46,
|
||||
kOpGetGlobal2 = 0x48,
|
||||
kOpGetGlobal = 0x49,
|
||||
kOpGetProp = 0x4a,
|
||||
kOpGetParam = 0x4b,
|
||||
kOpGetLocal = 0x4c,
|
||||
kOpSetGlobal2 = 0x4e,
|
||||
kOpSetGlobal = 0x4f,
|
||||
kOpSetProp = 0x50,
|
||||
kOpSetParam = 0x51,
|
||||
kOpSetLocal = 0x52,
|
||||
kOpJmp = 0x53,
|
||||
kOpEndRepeat = 0x54,
|
||||
kOpJmpIfZ = 0x55,
|
||||
kOpLocalCall = 0x56,
|
||||
kOpExtCall = 0x57,
|
||||
kOpObjCallV4 = 0x58,
|
||||
kOpPut = 0x59,
|
||||
kOpPutChunk = 0x5a,
|
||||
kOpDeleteChunk = 0x5b,
|
||||
kOpGet = 0x5c,
|
||||
kOpSet = 0x5d,
|
||||
kOpGetMovieProp = 0x5f,
|
||||
kOpSetMovieProp = 0x60,
|
||||
kOpGetObjProp = 0x61,
|
||||
kOpSetObjProp = 0x62,
|
||||
kOpTellCall = 0x63,
|
||||
kOpPeek = 0x64,
|
||||
kOpPop = 0x65,
|
||||
kOpTheBuiltin = 0x66,
|
||||
kOpObjCall = 0x67,
|
||||
kOpPushChunkVarRef = 0x6d,
|
||||
kOpPushInt16 = 0x6e,
|
||||
kOpPushInt32 = 0x6f,
|
||||
kOpGetChainedProp = 0x70,
|
||||
kOpPushFloat32 = 0x71,
|
||||
kOpGetTopLevelProp = 0x72,
|
||||
kOpNewObj = 0x73
|
||||
};
|
||||
|
||||
enum DatumType {
|
||||
kDatumVoid,
|
||||
kDatumSymbol,
|
||||
kDatumVarRef,
|
||||
kDatumString,
|
||||
kDatumInt,
|
||||
kDatumFloat,
|
||||
kDatumList,
|
||||
kDatumArgList,
|
||||
kDatumArgListNoRet,
|
||||
kDatumPropList
|
||||
};
|
||||
|
||||
enum ChunkExprType {
|
||||
kChunkChar = 0x01,
|
||||
kChunkWord = 0x02,
|
||||
kChunkItem = 0x03,
|
||||
kChunkLine = 0x04
|
||||
};
|
||||
|
||||
enum PutType {
|
||||
kPutInto = 0x01,
|
||||
kPutAfter = 0x02,
|
||||
kPutBefore = 0x03
|
||||
};
|
||||
|
||||
enum NodeType {
|
||||
kNoneNode,
|
||||
kErrorNode,
|
||||
kTempNode,
|
||||
kCommentNode,
|
||||
kLiteralNode,
|
||||
kBlockNode,
|
||||
kHandlerNode,
|
||||
kExitStmtNode,
|
||||
kInverseOpNode,
|
||||
kNotOpNode,
|
||||
kBinaryOpNode,
|
||||
kChunkExprNode,
|
||||
kChunkHiliteStmtNode,
|
||||
kChunkDeleteStmtNode,
|
||||
kSpriteIntersectsExprNode,
|
||||
kSpriteWithinExprNode,
|
||||
kMemberExprNode,
|
||||
kVarNode,
|
||||
kAssignmentStmtNode,
|
||||
kIfStmtNode,
|
||||
kRepeatWhileStmtNode,
|
||||
kRepeatWithInStmtNode,
|
||||
kRepeatWithToStmtNode,
|
||||
kCaseStmtNode,
|
||||
kCaseLabelNode,
|
||||
kOtherwiseNode,
|
||||
kEndCaseNode,
|
||||
kTellStmtNode,
|
||||
kSoundCmdStmtNode,
|
||||
kPlayCmdStmtNode,
|
||||
kCallNode,
|
||||
kObjCallNode,
|
||||
kObjCallV4Node,
|
||||
kTheExprNode,
|
||||
kLastStringChunkExprNode,
|
||||
kStringChunkCountExprNode,
|
||||
kMenuPropExprNode,
|
||||
kMenuItemPropExprNode,
|
||||
kSoundPropExprNode,
|
||||
kSpritePropExprNode,
|
||||
kThePropExprNode,
|
||||
kObjPropExprNode,
|
||||
kObjBracketExprNode,
|
||||
kObjPropIndexExprNode,
|
||||
kExitRepeatStmtNode,
|
||||
kNextRepeatStmtNode,
|
||||
kPutStmtNode,
|
||||
kWhenStmtNode,
|
||||
kNewObjNode
|
||||
};
|
||||
|
||||
enum BytecodeTag {
|
||||
kTagNone,
|
||||
kTagSkip,
|
||||
kTagRepeatWhile,
|
||||
kTagRepeatWithIn,
|
||||
kTagRepeatWithTo,
|
||||
kTagRepeatWithDownTo,
|
||||
kTagNextRepeatTarget,
|
||||
kTagEndCase
|
||||
};
|
||||
|
||||
enum CaseExpect {
|
||||
kCaseExpectEnd,
|
||||
kCaseExpectOr,
|
||||
kCaseExpectNext,
|
||||
kCaseExpectOtherwise
|
||||
};
|
||||
|
||||
enum ScriptFlag {
|
||||
kScriptFlagUnused = (1 << 0x0),
|
||||
kScriptFlagFuncsGlobal = (1 << 0x1),
|
||||
kScriptFlagVarsGlobal = (1 << 0x2), // Occurs in event scripts (which have no local vars). Correlated with use of alternate global var opcodes.
|
||||
kScriptFlagUnk3 = (1 << 0x3),
|
||||
kScriptFlagFactoryDef = (1 << 0x4),
|
||||
kScriptFlagUnk5 = (1 << 0x5),
|
||||
kScriptFlagUnk6 = (1 << 0x6),
|
||||
kScriptFlagUnk7 = (1 << 0x7),
|
||||
kScriptFlagHasFactory = (1 << 0x8),
|
||||
kScriptFlagEventScript = (1 << 0x9),
|
||||
kScriptFlagEventScript2 = (1 << 0xa),
|
||||
kScriptFlagUnkB = (1 << 0xb),
|
||||
kScriptFlagUnkC = (1 << 0xc),
|
||||
kScriptFlagUnkD = (1 << 0xd),
|
||||
kScriptFlagUnkE = (1 << 0xe),
|
||||
kScriptFlagUnkF = (1 << 0xf)
|
||||
};
|
||||
|
||||
enum LiteralType {
|
||||
kLiteralString = 1,
|
||||
kLiteralInt = 4,
|
||||
kLiteralFloat = 9
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LINGODEC_ENUMS_H
|
||||
1323
engines/director/lingo/lingodec/handler.cpp
Normal file
1323
engines/director/lingo/lingodec/handler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
110
engines/director/lingo/lingodec/handler.h
Normal file
110
engines/director/lingo/lingodec/handler.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef LINGODEC_HANDLER_H
|
||||
#define LINGODEC_HANDLER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/stablemap.h"
|
||||
#include "common/str.h"
|
||||
#include "./enums.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
struct AST;
|
||||
struct Bytecode;
|
||||
class CodeWriterVisitor;
|
||||
struct Node;
|
||||
struct Script;
|
||||
|
||||
/* Handler */
|
||||
|
||||
struct Handler {
|
||||
int16 nameID = 0;
|
||||
uint16 vectorPos = 0;
|
||||
uint32 compiledLen = 0;
|
||||
uint32 compiledOffset = 0;
|
||||
uint16 argumentCount = 0;
|
||||
uint32 argumentOffset = 0;
|
||||
uint16 localsCount = 0;
|
||||
uint32 localsOffset = 0;
|
||||
uint16 globalsCount = 0;
|
||||
uint32 globalsOffset = 0;
|
||||
uint32 unknown1 = 0;
|
||||
uint16 unknown2 = 0;
|
||||
uint16 lineCount = 0;
|
||||
uint32 lineOffset = 0;
|
||||
uint32 stackHeight = 0;
|
||||
|
||||
Common::Array<int16> argumentNameIDs;
|
||||
Common::Array<int16> localNameIDs;
|
||||
Common::Array<int16> globalNameIDs;
|
||||
|
||||
Script *script = nullptr;
|
||||
Common::Array<Bytecode> bytecodeArray;
|
||||
Common::StableMap<uint32, size_t> bytecodePosMap;
|
||||
Common::Array<Common::String> argumentNames;
|
||||
Common::Array<Common::String> localNames;
|
||||
Common::Array<Common::String> globalNames;
|
||||
Common::String name;
|
||||
|
||||
Common::Array<Common::SharedPtr<Node>> stack;
|
||||
AST ast;
|
||||
|
||||
bool isGenericEvent = false;
|
||||
|
||||
Handler(): ast(0, this) {}
|
||||
|
||||
void setScript(Script *s) {
|
||||
script = s;
|
||||
}
|
||||
|
||||
void readRecord(Common::SeekableReadStream &stream);
|
||||
void readData(Common::SeekableReadStream &stream);
|
||||
Common::Array<int16> readVarnamesTable(Common::SeekableReadStream &stream, uint16 count, uint32 offset);
|
||||
void readNames();
|
||||
bool validName(int id) const;
|
||||
Common::String getName(int id) const;
|
||||
Common::String getArgumentName(int id) const;
|
||||
Common::String getLocalName(int id) const;
|
||||
Common::SharedPtr<Node> pop();
|
||||
int variableMultiplier();
|
||||
Common::SharedPtr<Node> readVar(int varType);
|
||||
Common::String getVarNameFromSet(const Bytecode &bytecode);
|
||||
Common::SharedPtr<Node> readV4Property(uint32 offset, int propertyType, int propertyID);
|
||||
Common::SharedPtr<Node> readChunkRef(uint32 offset, Common::SharedPtr<Node> string);
|
||||
void tagLoops();
|
||||
bool isRepeatWithIn(uint32 startIndex, uint32 endIndex);
|
||||
BytecodeTag identifyLoop(uint32 startIndex, uint32 endIndex);
|
||||
void parse();
|
||||
uint32 translateBytecode(Bytecode &bytecode, uint32 index);
|
||||
void writeBytecodeText(CodeWriterVisitor &code) const;
|
||||
};
|
||||
|
||||
/* Bytecode */
|
||||
|
||||
struct Bytecode {
|
||||
byte opID;
|
||||
OpCode opcode;
|
||||
int32 obj;
|
||||
uint32 pos;
|
||||
BytecodeTag tag;
|
||||
uint32 ownerLoop;
|
||||
Common::SharedPtr<Node> translation;
|
||||
|
||||
Bytecode(byte op, int32 o, uint32 p)
|
||||
: opID(op), obj(o), pos(p), tag(kTagNone), ownerLoop(0xffffffff) {
|
||||
opcode = static_cast<OpCode>(op >= 0x40 ? 0x40 + op % 0x40 : op);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LINGODEC_HANDLER_H
|
||||
365
engines/director/lingo/lingodec/names.cpp
Normal file
365
engines/director/lingo/lingodec/names.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/util.h"
|
||||
#include "./enums.h"
|
||||
#include "./names.h"
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
namespace StandardNames {
|
||||
/* StandardNames */
|
||||
|
||||
const char *const opcodeNamesS[] = {
|
||||
// single-byte
|
||||
"unk00",
|
||||
"ret", // kOpRet 0x01
|
||||
"retfactory", // kOpRetFactory 0x02
|
||||
"pushzero", // kOpPushZero 0x03
|
||||
"mul", // kOpMul 0x04
|
||||
"add", // kOpAdd 0x05
|
||||
"sub", // kOpSub 0x06
|
||||
"div", // kOpDiv 0x07
|
||||
"mod", // kOpMod 0x08
|
||||
"inv", // kOpInv 0x09
|
||||
"joinstr", // kOpJoinStr 0x0a
|
||||
"joinpadstr", // kOpJoinPadStr 0x0b
|
||||
"lt", // kOpLt 0x0c
|
||||
"lteq", // kOpLtEq 0x0d
|
||||
"nteq", // kOpNtEq 0x0e
|
||||
"eq", // kOpEq 0x0f
|
||||
"gt", // kOpGt 0x10
|
||||
"gteq", // kOpGtEq 0x11
|
||||
"and", // kOpAnd 0x12
|
||||
"or", // kOpOr 0x13
|
||||
"not", // kOpNot 0x14
|
||||
"containsstr", // kOpContainsStr 0x15
|
||||
"contains0str", // kOpContains0Str 0x16
|
||||
"getchunk", // kOpGetChunk 0x17
|
||||
"hilitechunk", // kOpHiliteChunk 0x18
|
||||
"ontospr", // kOpOntoSpr 0x19
|
||||
"intospr", // kOpIntoSpr 0x1a
|
||||
"getfield", // kOpGetField 0x1b
|
||||
"starttell", // kOpStartTell 0x1c
|
||||
"endtell", // kOpEndTell 0x1d
|
||||
"pushlist", // kOpPushList 0x1e
|
||||
"pushproplist", // kOpPushPropList 0x1f
|
||||
"unk20",
|
||||
"swap", // kOpSwap 0x21
|
||||
};
|
||||
|
||||
const char *const opcodeNamesM[] = {
|
||||
// multi-byte
|
||||
"unk40",
|
||||
"pushint8", // kOpPushInt8 0x41
|
||||
"pusharglistnoret", // kOpPushArgListNoRet 0x42
|
||||
"pusharglist", // kOpPushArgList 0x43
|
||||
"pushcons", // kOpPushCons 0x44
|
||||
"pushsymb", // kOpPushSymb 0x45
|
||||
"pushvarref", // kOpPushVarRef 0x46
|
||||
"unk47",
|
||||
"getglobal2", // kOpGetGlobal2 0x48
|
||||
"getglobal", // kOpGetGlobal 0x49
|
||||
"getprop", // kOpGetProp 0x4a
|
||||
"getparam", // kOpGetParam 0x4b
|
||||
"getlocal", // kOpGetLocal 0x4c
|
||||
"unk4d",
|
||||
"setglobal2", // kOpSetGlobal2 0x4e
|
||||
"setglobal", // kOpSetGlobal 0x4f
|
||||
"setprop", // kOpSetProp 0x50
|
||||
"setparam", // kOpSetParam 0x51
|
||||
"setlocal", // kOpSetLocal 0x52
|
||||
"jmp", // kOpJmp 0x53
|
||||
"endrepeat", // kOpEndRepeat 0x54
|
||||
"jmpifz", // kOpJmpIfZ 0x55
|
||||
"localcall", // kOpLocalCall 0x56
|
||||
"extcall", // kOpExtCall 0x57
|
||||
"objcallv4", // kOpObjCallV4 0x58
|
||||
"put", // kOpPut 0x59
|
||||
"putchunk", // kOpPutChunk 0x5a
|
||||
"deletechunk", // kOpDeleteChunk 0x5b
|
||||
"get", // kOpGet 0x5c
|
||||
"set", // kOpSet 0x5d
|
||||
"unk5e",
|
||||
"getmovieprop", // kOpGetMovieProp 0x5f
|
||||
"setmovieprop", // kOpSetMovieProp 0x60
|
||||
"getobjprop", // kOpGetObjProp 0x61
|
||||
"setobjprop", // kOpSetObjProp 0x62
|
||||
"tellcall", // kOpTellCall 0x63
|
||||
"peek", // kOpPeek 0x64
|
||||
"pop", // kOpPop 0x65
|
||||
"thebuiltin", // kOpTheBuiltin 0x66
|
||||
"objcall", // kOpObjCall 0x67
|
||||
"unk68",
|
||||
"unk69",
|
||||
"unk6a",
|
||||
"unk6b",
|
||||
"unk6c",
|
||||
"pushchunkvarref", // kOpPushChunkVarRef 0x6d
|
||||
"pushint16", // kOpPushInt16 0x6e
|
||||
"pushint32", // kOpPushInt32 0x6f
|
||||
"getchainedprop", // kOpGetChainedProp 0x70
|
||||
"pushfloat32", // kOpPushFloat32 0x71
|
||||
"gettoplevelprop", // kOpGetTopLevelProp 0x72
|
||||
"newobj", // kOpNewObj 0x73
|
||||
};
|
||||
|
||||
const char *const binaryOpNames[] = {
|
||||
"unk00",
|
||||
"unk01",
|
||||
"unk02",
|
||||
"unk03",
|
||||
"*", // kOpMul 0x04
|
||||
"+", // kOpAdd 0x05
|
||||
"-", // kOpSub 0x06
|
||||
"/", // kOpDiv 0x07
|
||||
"mod", // kOpMod 0x08
|
||||
"unk09",
|
||||
"&", // kOpJoinStr 0x0a
|
||||
"&&", // kOpJoinPadStr 0x0b
|
||||
"<", // kOpLt 0x0c
|
||||
"<=", // kOpLtEq 0x0d
|
||||
"<>", // kOpNtEq 0x0e
|
||||
"=", // kOpEq 0x0f
|
||||
">", // kOpGt 0x10
|
||||
">=", // kOpGtEq 0x11
|
||||
"and", // kOpAnd 0x12
|
||||
"or", // kOpOr 0x13
|
||||
"unk14",
|
||||
"contains", // kOpContainsStr 0x15
|
||||
"starts", // kOpContains0Str 0x16
|
||||
};
|
||||
|
||||
const char *const chunkTypeNames[] = {
|
||||
"unk00",
|
||||
"char", // kChunkChar 0x01
|
||||
"word", // kChunkWord 0x02
|
||||
"item", // kChunkItem 0x03
|
||||
"line", // kChunkLine 0x04
|
||||
};
|
||||
|
||||
const char *const putTypeNames[] = {
|
||||
"unk00",
|
||||
"into", // kPutInto 0x01
|
||||
"after", // kPutAfter 0x02
|
||||
"before", // kPutBefore 0x03
|
||||
};
|
||||
|
||||
const char *const moviePropertyNames[] = {
|
||||
"floatPrecision", // 0x00
|
||||
"mouseDownScript", // 0x01
|
||||
"mouseUpScript", // 0x02
|
||||
"keyDownScript", // 0x03
|
||||
"keyUpScript", // 0x04
|
||||
"timeoutScript", // 0x05
|
||||
"short time", // 0x06
|
||||
"abbr time", // 0x07
|
||||
"long time", // 0x08
|
||||
"short date", // 0x09
|
||||
"abbr date", // 0x0a
|
||||
"long date", // 0x0b
|
||||
};
|
||||
|
||||
const char *const whenEventNames[] = {
|
||||
"unk00",
|
||||
"mouseDown",// 0x01
|
||||
"mouseUp", // 0x02
|
||||
"keyDown", // 0x03
|
||||
"keyUp", // 0x04
|
||||
"timeOut", // 0x05
|
||||
};
|
||||
|
||||
const char *const menuPropertyNames[] = {
|
||||
"unk00",
|
||||
"name", // 0x01
|
||||
"number of menuItems", // 0x02
|
||||
};
|
||||
|
||||
const char *const menuItemPropertyNames[] = {
|
||||
"unk00",
|
||||
"name", // 0x01
|
||||
"checkMark",// 0x02
|
||||
"enabled", // 0x03
|
||||
"script", // 0x04
|
||||
};
|
||||
|
||||
const char *const soundPropertyNames[] = {
|
||||
"unk00",
|
||||
"volume", // 0x01
|
||||
};
|
||||
|
||||
const char *const spritePropertyNames[] = {
|
||||
"unk00",
|
||||
"type", // 0x01
|
||||
"backColor", // 0x02
|
||||
"bottom", // 0x03
|
||||
"castNum", // 0x04
|
||||
"constraint", // 0x05
|
||||
"cursor", // 0x06
|
||||
"foreColor", // 0x07
|
||||
"height", // 0x08
|
||||
"immediate", // 0x09
|
||||
"ink", // 0x0a
|
||||
"left", // 0x0b
|
||||
"lineSize", // 0x0c
|
||||
"locH", // 0x0d
|
||||
"locV", // 0x0e
|
||||
"movieRate", // 0x0f
|
||||
"movieTime", // 0x10
|
||||
"pattern", // 0x11
|
||||
"puppet", // 0x12
|
||||
"right", // 0x13
|
||||
"startTime", // 0x14
|
||||
"stopTime", // 0x15
|
||||
"stretch", // 0x16
|
||||
"top", // 0x17
|
||||
"trails", // 0x18
|
||||
"visible", // 0x19
|
||||
"volume", // 0x1a
|
||||
"width", // 0x1b
|
||||
"blend", // 0x1c
|
||||
"scriptNum", // 0x1d
|
||||
"moveableSprite", // 0x1e
|
||||
"editableText", // 0x1f
|
||||
"scoreColor", // 0x20
|
||||
"loc", // 0x21
|
||||
"rect", // 0x22
|
||||
"memberNum", // 0x23
|
||||
"castLibNum", // 0x24
|
||||
"member", // 0x25
|
||||
"scriptInstanceList", // 0x26
|
||||
"currentTime", // 0x27
|
||||
"mostRecentCuePoint", // 0x28
|
||||
"tweened", // 0x29
|
||||
"name", // 0x2a
|
||||
};
|
||||
|
||||
const char *const animationPropertyNames[] = {
|
||||
"unk00",
|
||||
"beepOn", // 0x01
|
||||
"buttonStyle", // 0x02
|
||||
"centerStage", // 0x03
|
||||
"checkBoxAccess", // 0x04
|
||||
"checkboxType", // 0x05
|
||||
"colorDepth", // 0x06
|
||||
"colorQD", // 0x07
|
||||
"exitLock", // 0x08
|
||||
"fixStageSize", // 0x09
|
||||
"fullColorPermit", // 0x0a
|
||||
"imageDirect", // 0x0b
|
||||
"doubleClick", // 0x0c
|
||||
"key", // 0x0d
|
||||
"lastClick", // 0x0e
|
||||
"lastEvent", // 0x0f
|
||||
"keyCode", // 0x10
|
||||
"lastKey", // 0x11
|
||||
"lastRoll", // 0x12
|
||||
"timeoutLapsed", // 0x13
|
||||
"multiSound", // 0x14
|
||||
"pauseState", // 0x15
|
||||
"quickTimePresent", // 0x16
|
||||
"selEnd", // 0x17
|
||||
"selStart", // 0x18
|
||||
"soundEnabled", // 0x19
|
||||
"soundLevel", // 0x1a
|
||||
"stageColor", // 0x1b
|
||||
// 0x1c indicates dontPassEvent was called.
|
||||
// It doesn't seem to have a Lingo-accessible name.
|
||||
"unk1c",
|
||||
"switchColorDepth", // 0x1d
|
||||
"timeoutKeyDown", // 0x1e
|
||||
"timeoutLength", // 0x1f
|
||||
"timeoutMouse", // 0x20
|
||||
"timeoutPlay", // 0x21
|
||||
"timer", // 0x22
|
||||
"preLoadRAM", // 0x23
|
||||
"videoForWindowsPresent", // 0x24
|
||||
"netPresent", // 0x25
|
||||
"safePlayer", // 0x26
|
||||
"soundKeepDevice", // 0x27
|
||||
"soundMixMedia", // 0x28
|
||||
};
|
||||
|
||||
const char *const animation2PropertyNames[] = {
|
||||
"unk00",
|
||||
"perFrameHook", // 0x01
|
||||
"number of castMembers",// 0x02
|
||||
"number of menus", // 0x03
|
||||
"number of castLibs", // 0x04
|
||||
"number of xtras", // 0x05
|
||||
};
|
||||
|
||||
const char *const memberPropertyNames[] = {
|
||||
"unk00",
|
||||
"name", // 0x01
|
||||
"text", // 0x02
|
||||
"textStyle", // 0x03
|
||||
"textFont", // 0x04
|
||||
"textHeight", // 0x05
|
||||
"textAlign", // 0x06
|
||||
"textSize", // 0x07
|
||||
"picture", // 0x08
|
||||
"hilite", // 0x09
|
||||
"number", // 0x0a
|
||||
"size", // 0x0b
|
||||
"loop", // 0x0c
|
||||
"duration", // 0x0d
|
||||
"controller", // 0x0e
|
||||
"directToStage",// 0x0f
|
||||
"sound", // 0x10
|
||||
"foreColor", // 0x11
|
||||
"backColor", // 0x12
|
||||
"type", // 0x13
|
||||
};
|
||||
|
||||
Common::String getOpcodeName(byte id) {
|
||||
if (id < 0x22)
|
||||
return opcodeNamesS[id];
|
||||
|
||||
if (id < 0x40)
|
||||
return Common::String::format("unk%02x" , id);
|
||||
|
||||
id = id % 0x40;
|
||||
|
||||
if (id < 0x34)
|
||||
return opcodeNamesM[id];
|
||||
|
||||
return Common::String::format("unk%02x" , id);
|
||||
}
|
||||
|
||||
} // namespace StandardNames
|
||||
|
||||
/* ScriptNames */
|
||||
|
||||
void ScriptNames::read(Common::SeekableReadStream &stream) {
|
||||
// Lingo scripts are always big endian regardless of file endianness
|
||||
unknown0 = stream.readSint32BE();
|
||||
unknown1 = stream.readSint32BE();
|
||||
len1 = stream.readUint32BE();
|
||||
len2 = stream.readUint32BE();
|
||||
namesOffset = stream.readUint16BE();
|
||||
namesCount = stream.readUint16BE();
|
||||
|
||||
stream.seek(namesOffset);
|
||||
names.resize(namesCount);
|
||||
for (auto &name : names) {
|
||||
name = stream.readPascalString();
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptNames::validName(int id) const {
|
||||
return -1 < id && (unsigned)id < names.size();
|
||||
}
|
||||
|
||||
Common::String ScriptNames::getName(int id) const {
|
||||
if (validName(id))
|
||||
return names[id];
|
||||
return Common::String::format("UNKNOWN_NAME_%d", id);
|
||||
}
|
||||
|
||||
}
|
||||
63
engines/director/lingo/lingodec/names.h
Normal file
63
engines/director/lingo/lingodec/names.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef LINGODEC_NAMES_H
|
||||
#define LINGODEC_NAMES_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/stablemap.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
class String;
|
||||
}
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
/* StandardNames */
|
||||
|
||||
namespace StandardNames {
|
||||
extern const char *const opcodeNamesS[];
|
||||
extern const char *const opcodeNamesM[];
|
||||
extern const char *const binaryOpNames[];
|
||||
extern const char *const chunkTypeNames[];
|
||||
extern const char *const putTypeNames[];
|
||||
|
||||
extern const char *const moviePropertyNames[];
|
||||
extern const char *const whenEventNames[];
|
||||
extern const char *const menuPropertyNames[];
|
||||
extern const char *const menuItemPropertyNames[];
|
||||
extern const char *const soundPropertyNames[];
|
||||
extern const char *const spritePropertyNames[];
|
||||
extern const char *const animationPropertyNames[];
|
||||
extern const char *const animation2PropertyNames[];
|
||||
extern const char *const memberPropertyNames[];
|
||||
|
||||
Common::String getOpcodeName(byte id);
|
||||
}
|
||||
|
||||
/* ScriptNames */
|
||||
|
||||
struct ScriptNames {
|
||||
int32 unknown0 = 0;
|
||||
int32 unknown1 = 0;
|
||||
uint32 len1 = 0;
|
||||
uint32 len2 = 0;
|
||||
uint16 namesOffset = 0;
|
||||
uint16 namesCount = 0;
|
||||
Common::Array<Common::String> names;
|
||||
|
||||
unsigned int version;
|
||||
|
||||
ScriptNames(unsigned int version_) : version(version_) {}
|
||||
void read(Common::SeekableReadStream &stream);
|
||||
bool validName(int id) const;
|
||||
Common::String getName(int id) const;
|
||||
};
|
||||
|
||||
} // namespace LingoDec
|
||||
|
||||
#endif // LINGODEC_NAMES_H
|
||||
25
engines/director/lingo/lingodec/resolver.h
Normal file
25
engines/director/lingo/lingodec/resolver.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef LINGODEC_RESOLVER_H
|
||||
#define LINGODEC_RESOLVER_H
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
struct Script;
|
||||
struct ScriptNames;
|
||||
|
||||
class ChunkResolver {
|
||||
public:
|
||||
ChunkResolver() {}
|
||||
virtual ~ChunkResolver() {}
|
||||
virtual Script *getScript(int32 id) = 0;
|
||||
virtual ScriptNames *getScriptNames(int32 id) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LINGODEC_RESOLVER_H
|
||||
256
engines/director/lingo/lingodec/script.cpp
Normal file
256
engines/director/lingo/lingodec/script.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "./ast.h"
|
||||
#include "./codewritervisitor.h"
|
||||
#include "./context.h"
|
||||
#include "./handler.h"
|
||||
#include "./script.h"
|
||||
|
||||
double readAppleFloat80(void *ptr);
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
/* Script */
|
||||
|
||||
Script::Script(unsigned int version_) :
|
||||
version(version_),
|
||||
context(nullptr) {}
|
||||
|
||||
Script::~Script() = default;
|
||||
|
||||
void Script::read(Common::SeekableReadStream &stream) {
|
||||
// Lingo scripts are always big endian regardless of file endianness
|
||||
stream.seek(8);
|
||||
/* 8 */ totalLength = stream.readUint32BE();
|
||||
/* 12 */ totalLength2 = stream.readUint32BE();
|
||||
/* 16 */ headerLength = stream.readUint16BE();
|
||||
/* 18 */ scriptNumber = stream.readUint16BE();
|
||||
/* 20 */ unk20 = stream.readSint16BE();
|
||||
/* 22 */ parentNumber = stream.readSint16BE();
|
||||
|
||||
stream.seek(38);
|
||||
/* 38 */ scriptFlags = stream.readUint32BE();
|
||||
/* 42 */ unk42 = stream.readSint16BE();
|
||||
/* 44 */ unk43 = stream.readSint16BE();
|
||||
/* 46 */ castID = stream.readSint16BE();
|
||||
/* 48 */ factoryNameID = stream.readSint16BE();
|
||||
/* 50 */ handlerVectorsCount = stream.readUint16BE();
|
||||
/* 52 */ handlerVectorsOffset = stream.readUint32BE();
|
||||
/* 56 */ handlerVectorsSize = stream.readUint32BE();
|
||||
/* 60 */ propertiesCount = stream.readUint16BE();
|
||||
/* 62 */ propertiesOffset = stream.readUint32BE();
|
||||
/* 66 */ globalsCount = stream.readUint16BE();
|
||||
/* 68 */ globalsOffset = stream.readUint32BE();
|
||||
/* 72 */ handlersCount = stream.readUint16BE();
|
||||
/* 74 */ handlersOffset = stream.readUint32BE();
|
||||
/* 78 */ literalsCount = stream.readUint16BE();
|
||||
/* 80 */ literalsOffset = stream.readUint32BE();
|
||||
/* 84 */ literalsDataCount = stream.readUint32BE();
|
||||
/* 88 */ literalsDataOffset = stream.readUint32BE();
|
||||
|
||||
propertyNameIDs = readVarnamesTable(stream, propertiesCount, propertiesOffset);
|
||||
globalNameIDs = readVarnamesTable(stream, globalsCount, globalsOffset);
|
||||
|
||||
handlers.resize(handlersCount);
|
||||
for (auto &handler : handlers) {
|
||||
handler.setScript(this);
|
||||
}
|
||||
if ((scriptFlags & LingoDec::kScriptFlagEventScript) && handlersCount > 0) {
|
||||
handlers[0].isGenericEvent = true;
|
||||
}
|
||||
|
||||
stream.seek(handlersOffset);
|
||||
for (auto &handler : handlers) {
|
||||
handler.readRecord(stream);
|
||||
}
|
||||
for (auto &handler : handlers) {
|
||||
handler.readData(stream);
|
||||
}
|
||||
|
||||
stream.seek(literalsOffset);
|
||||
literals.resize(literalsCount);
|
||||
for (auto &literal : literals) {
|
||||
literal.readRecord(stream, version);
|
||||
}
|
||||
for (auto &literal : literals) {
|
||||
literal.readData(stream, literalsDataOffset);
|
||||
}
|
||||
}
|
||||
|
||||
Common::Array<int16> Script::readVarnamesTable(Common::SeekableReadStream &stream, uint16 count, uint32 offset) {
|
||||
stream.seek(offset);
|
||||
Common::Array<int16> nameIDs(count);
|
||||
for (uint16 i = 0; i < count; i++) {
|
||||
nameIDs[i] = stream.readSint16BE();
|
||||
}
|
||||
return nameIDs;
|
||||
}
|
||||
|
||||
bool Script::validName(int id) const {
|
||||
return context->validName(id);
|
||||
}
|
||||
|
||||
Common::String Script::getName(int id) const {
|
||||
return context->getName(id);
|
||||
}
|
||||
|
||||
void Script::setContext(ScriptContext *ctx) {
|
||||
this->context = ctx;
|
||||
if (factoryNameID != -1) {
|
||||
factoryName = getName(factoryNameID);
|
||||
}
|
||||
for (auto nameID : propertyNameIDs) {
|
||||
if (validName(nameID)) {
|
||||
Common::String name = getName(nameID);
|
||||
if (isFactory() && name == "me")
|
||||
continue;
|
||||
propertyNames.push_back(name);
|
||||
}
|
||||
}
|
||||
for (auto nameID : globalNameIDs) {
|
||||
if (validName(nameID)) {
|
||||
globalNames.push_back(getName(nameID));
|
||||
}
|
||||
}
|
||||
for (auto &handler : handlers) {
|
||||
handler.readNames();
|
||||
}
|
||||
}
|
||||
|
||||
void Script::parse() {
|
||||
for (auto &handler : handlers) {
|
||||
handler.parse();
|
||||
}
|
||||
}
|
||||
|
||||
void Script::writeVarDeclarations(CodeWriterVisitor &code) const {
|
||||
if (!isFactory()) {
|
||||
if (propertyNames.size() > 0) {
|
||||
code.write("property ");
|
||||
for (size_t i = 0; i < propertyNames.size(); i++) {
|
||||
if (i > 0)
|
||||
code.write(", ");
|
||||
code.write(propertyNames[i]);
|
||||
}
|
||||
code.writeLine();
|
||||
}
|
||||
}
|
||||
if (globalNames.size() > 0) {
|
||||
code.write("global ");
|
||||
for (size_t i = 0; i < globalNames.size(); i++) {
|
||||
if (i > 0)
|
||||
code.write(", ");
|
||||
code.write(globalNames[i]);
|
||||
}
|
||||
code.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
void Script::writeScriptText(CodeWriterVisitor &code) const {
|
||||
size_t origSize = code._str.size();
|
||||
writeVarDeclarations(code);
|
||||
if (isFactory()) {
|
||||
if (code._str.size() != origSize) {
|
||||
code.writeLine();
|
||||
}
|
||||
code.write("factory ");
|
||||
code.writeLine(factoryName);
|
||||
}
|
||||
for (size_t i = 0; i < handlers.size(); i++) {
|
||||
if ((!isFactory() || i > 0) && code._str.size() != origSize) {
|
||||
code.writeLine();
|
||||
}
|
||||
handlers[i].ast.root->accept(code);
|
||||
}
|
||||
for (auto factory : factories) {
|
||||
if (code._str.size() != origSize) {
|
||||
code.writeLine();
|
||||
}
|
||||
factory->writeScriptText(code);
|
||||
}
|
||||
}
|
||||
|
||||
Common::String Script::scriptText(const char *lineEnding, bool dotSyntax) const {
|
||||
CodeWriterVisitor code(dotSyntax, false, lineEnding);
|
||||
writeScriptText(code);
|
||||
return code._str;
|
||||
}
|
||||
|
||||
void Script::writeBytecodeText(CodeWriterVisitor &code) const {
|
||||
size_t origSize = code._str.size();
|
||||
writeVarDeclarations(code);
|
||||
if (isFactory()) {
|
||||
if (code._str.size() != origSize) {
|
||||
code.writeLine();
|
||||
}
|
||||
code.write("factory ");
|
||||
code.writeLine(factoryName);
|
||||
}
|
||||
for (size_t i = 0; i < handlers.size(); i++) {
|
||||
if ((!isFactory() || i > 0) && code._str.size() != origSize) {
|
||||
code.writeLine();
|
||||
}
|
||||
handlers[i].writeBytecodeText(code);
|
||||
}
|
||||
for (auto factory : factories) {
|
||||
if (code._str.size() != origSize) {
|
||||
code.writeLine();
|
||||
}
|
||||
factory->writeBytecodeText(code);
|
||||
}
|
||||
}
|
||||
|
||||
Common::String Script::bytecodeText(const char *lineEnding, bool dotSyntax) const {
|
||||
CodeWriterVisitor code(dotSyntax, true, lineEnding);
|
||||
writeBytecodeText(code);
|
||||
return code._str;
|
||||
}
|
||||
|
||||
bool Script::isFactory() const {
|
||||
return (scriptFlags & LingoDec::kScriptFlagFactoryDef);
|
||||
}
|
||||
|
||||
/* LiteralStore */
|
||||
|
||||
void LiteralStore::readRecord(Common::SeekableReadStream &stream, int version) {
|
||||
if (version >= 500)
|
||||
type = static_cast<LiteralType>(stream.readUint32BE());
|
||||
else
|
||||
type = static_cast<LiteralType>(stream.readUint16BE());
|
||||
offset = stream.readUint32BE();
|
||||
}
|
||||
|
||||
void LiteralStore::readData(Common::SeekableReadStream &stream, uint32 startOffset) {
|
||||
if (type == kLiteralInt) {
|
||||
value = Common::SharedPtr<LingoDec::Datum>(new LingoDec::Datum((int)offset));
|
||||
} else {
|
||||
stream.seek(startOffset + offset);
|
||||
auto length = stream.readUint32BE();
|
||||
if (type == kLiteralString) {
|
||||
char *buf = new char[length];
|
||||
stream.read(buf, length - 1);
|
||||
buf[length - 1] = '\0';
|
||||
value = Common::SharedPtr<LingoDec::Datum>(new LingoDec::Datum(LingoDec::kDatumString, Common::String(buf)));
|
||||
delete[] buf;
|
||||
} else if (type == kLiteralFloat) {
|
||||
double floatVal = 0.0;
|
||||
if (length == 8) {
|
||||
floatVal = stream.readDoubleBE();
|
||||
} else if (length == 10) {
|
||||
byte buf[10];
|
||||
stream.read(buf, 10);
|
||||
floatVal = readAppleFloat80(buf);
|
||||
}
|
||||
value = Common::SharedPtr<LingoDec::Datum>(new LingoDec::Datum(floatVal));
|
||||
} else {
|
||||
value = Common::SharedPtr<LingoDec::Datum>(new LingoDec::Datum());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace LingoDec
|
||||
98
engines/director/lingo/lingodec/script.h
Normal file
98
engines/director/lingo/lingodec/script.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef LINGODEC_SCRIPT_H
|
||||
#define LINGODEC_SCRIPT_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
#include "common/str.h"
|
||||
#include "./enums.h"
|
||||
|
||||
namespace Common {
|
||||
class ReadStream;
|
||||
}
|
||||
|
||||
namespace LingoDec {
|
||||
|
||||
class CodeWriterVisitor;
|
||||
struct Datum;
|
||||
struct Handler;
|
||||
struct ScriptContext;
|
||||
|
||||
/* LiteralStore */
|
||||
|
||||
struct LiteralStore {
|
||||
LiteralType type;
|
||||
uint32 offset;
|
||||
Common::SharedPtr<Datum> value;
|
||||
|
||||
void readRecord(Common::SeekableReadStream &stream, int version);
|
||||
void readData(Common::SeekableReadStream &stream, uint32 startOffset);
|
||||
};
|
||||
|
||||
/* Script */
|
||||
|
||||
struct Script {
|
||||
/* 8 */ uint32 totalLength;
|
||||
/* 12 */ uint32 totalLength2;
|
||||
/* 16 */ uint16 headerLength;
|
||||
/* 18 */ uint16 scriptNumber;
|
||||
/* 20 */ int16 unk20;
|
||||
/* 22 */ int16 parentNumber;
|
||||
|
||||
/* 38 */ uint32 scriptFlags;
|
||||
/* 42 */ int16 unk42;
|
||||
/* 44 */ int16 unk43;
|
||||
// This castID is not reliable
|
||||
/* 46 */ int16 castID;
|
||||
/* 48 */ int16 factoryNameID;
|
||||
/* 50 */ uint16 handlerVectorsCount;
|
||||
/* 52 */ uint32 handlerVectorsOffset;
|
||||
/* 56 */ uint32 handlerVectorsSize;
|
||||
/* 60 */ uint16 propertiesCount;
|
||||
/* 62 */ uint32 propertiesOffset;
|
||||
/* 66 */ uint16 globalsCount;
|
||||
/* 68 */ uint32 globalsOffset;
|
||||
/* 72 */ uint16 handlersCount;
|
||||
/* 74 */ uint32 handlersOffset;
|
||||
/* 78 */ uint16 literalsCount;
|
||||
/* 80 */ uint32 literalsOffset;
|
||||
/* 84 */ uint32 literalsDataCount;
|
||||
/* 88 */ uint32 literalsDataOffset;
|
||||
|
||||
Common::Array<int16> propertyNameIDs;
|
||||
Common::Array<int16> globalNameIDs;
|
||||
|
||||
Common::String factoryName;
|
||||
Common::Array<Common::String> propertyNames;
|
||||
Common::Array<Common::String> globalNames;
|
||||
Common::Array<Handler> handlers;
|
||||
Common::Array<LiteralStore> literals;
|
||||
Common::Array<Script *> factories;
|
||||
|
||||
unsigned int version;
|
||||
ScriptContext *context;
|
||||
|
||||
Script(unsigned int version_);
|
||||
~Script();
|
||||
void read(Common::SeekableReadStream &stream);
|
||||
Common::Array<int16> readVarnamesTable(Common::SeekableReadStream &stream, uint16 count, uint32 offset);
|
||||
bool validName(int id) const;
|
||||
Common::String getName(int id) const;
|
||||
void setContext(ScriptContext *ctx);
|
||||
void parse();
|
||||
void writeVarDeclarations(CodeWriterVisitor &code) const;
|
||||
void writeScriptText(CodeWriterVisitor &code) const;
|
||||
Common::String scriptText(const char *lineEnding, bool dotSyntax) const;
|
||||
void writeBytecodeText(CodeWriterVisitor &code) const;
|
||||
Common::String bytecodeText(const char *lineEnding, bool dotSyntax) const;
|
||||
|
||||
bool isFactory() const;
|
||||
};
|
||||
|
||||
} // namespace LingoDec
|
||||
|
||||
#endif // LINGODEC_SCRIPT_H
|
||||
37
engines/director/lingo/tests/XObjects.lingo
Normal file
37
engines/director/lingo/tests/XObjects.lingo
Normal file
@@ -0,0 +1,37 @@
|
||||
openXLib("FlushXObj")
|
||||
set flush = FlushXObj(mNew)
|
||||
flush(mClearMask)
|
||||
flush(mAddToMask, 0, 0)
|
||||
flush(mFlush)
|
||||
flush(mFlushEvents, 0, 0)
|
||||
|
||||
openXLib("PalXObj")
|
||||
set fixpal = FixPalette(mNew, 0, 20, 512, 20)
|
||||
fixpal(mPatchIt)
|
||||
|
||||
openXLib("winXOBJ")
|
||||
set winxobj = RearWindow(mNew, "M")
|
||||
scummVMAssert(winxobj(mGetMemoryNeeded) = 0)
|
||||
|
||||
-- test closing XObject
|
||||
scummVMAssert(objectp(FlushXObj) = 1)
|
||||
closeXlib "FlushXObj"
|
||||
scummVMAssert(objectp(FlushXObj) = 0)
|
||||
|
||||
scummVMAssert(objectp(RearWindow) = 1)
|
||||
closeXlib()
|
||||
scummVMAssert(objectp(RearWindow) = 0)
|
||||
|
||||
-- test showGlobals and clearGlobals on XObjects
|
||||
clearGlobals()
|
||||
openXLib("FileIO")
|
||||
scummVMAssert(objectp(FileIO))
|
||||
|
||||
showGlobals() -- FileIO should not be listed
|
||||
clearGlobals()
|
||||
scummVMAssert(objectp(FileIO)) -- FileIO should not be cleared
|
||||
|
||||
set FileIO = "test"
|
||||
showGlobals() -- FileIO should be listed
|
||||
clearGlobals()
|
||||
scummVMAssert(voidp(FileIO)) -- FileIO should be cleared
|
||||
BIN
engines/director/lingo/tests/blend2.pic
Normal file
BIN
engines/director/lingo/tests/blend2.pic
Normal file
Binary file not shown.
55
engines/director/lingo/tests/builtin.lingo
Normal file
55
engines/director/lingo/tests/builtin.lingo
Normal file
@@ -0,0 +1,55 @@
|
||||
beep
|
||||
beep 3
|
||||
alert "Hi"
|
||||
alert "Hi" && "there"
|
||||
|
||||
open "Hello"
|
||||
open "Hello" with "Finder"
|
||||
open "Hello" && "more" with "Finder"
|
||||
|
||||
-- These are D4+
|
||||
move cast 1, cast 1
|
||||
move cast 1, 3
|
||||
move cast 3, 1
|
||||
move cast 1
|
||||
|
||||
put findEmpty(cast 10)
|
||||
pasteClipBoardInto cast 2
|
||||
put the width of cast 1
|
||||
|
||||
-- Puppet commands must come after the move commands
|
||||
-- move does a force render. Combined with puppetTransitions it just waits and causes a timeout on the buildbot
|
||||
puppetPalette "Rainbow"
|
||||
puppetPalette "System",30
|
||||
puppetPalette "custompal", 15,4
|
||||
|
||||
puppetSound "Air Lock Lock"
|
||||
puppetSound 0
|
||||
|
||||
puppetSprite 15, true
|
||||
|
||||
puppetTempo 30
|
||||
puppetTransition 1
|
||||
puppetTransition 2,4,20
|
||||
|
||||
unload
|
||||
unload ab
|
||||
unload ab, bc
|
||||
|
||||
put framesToHMS(integer(field 3),30,false,false) into field 5
|
||||
|
||||
set save to the scummvmVersion
|
||||
|
||||
set the scummvmVersion to 300
|
||||
scummvmAssert(version = "3.0")
|
||||
set the scummvmVersion to 310
|
||||
scummvmAssert(version = "3.1")
|
||||
set the scummvmVersion to 404
|
||||
scummvmAssert(version = "4.0.4")
|
||||
set the scummvmVersion to 1201
|
||||
scummvmAssert(version = "12.0.1")
|
||||
|
||||
set the scummvmVersion to save
|
||||
|
||||
set n = getNthFileNameInFolder("@", 1)
|
||||
scummvmAssertEqual(n, "0testfile")
|
||||
23
engines/director/lingo/tests/c2.lingo
Normal file
23
engines/director/lingo/tests/c2.lingo
Normal file
@@ -0,0 +1,23 @@
|
||||
-- This file is binary. Watch for 0xC2 symbol at the line ends
|
||||
|
||||
if the text of cast 1 <> the text of cast 2 then Â
|
||||
put "Hello"
|
||||
|
||||
if the text of cast 1 <> the text of cast 2 then Â
|
||||
put "Goodbye"
|
||||
|
||||
set the selStart to Â
|
||||
0
|
||||
|
||||
set the selStart to Â
|
||||
0
|
||||
|
||||
-- This comment is Â
|
||||
the continuationÂ
|
||||
of previous line
|
||||
|
||||
if the castNum of sprite 1 > the number of cast 2 then set the castNum of sprite 1 to the number of Â
|
||||
cast 1
|
||||
|
||||
put "HelloÂ
|
||||
World!"
|
||||
45
engines/director/lingo/tests/chunks.lingo
Normal file
45
engines/director/lingo/tests/chunks.lingo
Normal file
@@ -0,0 +1,45 @@
|
||||
-- put randomName() into item i of field "In"
|
||||
|
||||
-- put the last word of field 1 into field 3
|
||||
|
||||
scummvmAssertEqual(the last char of "Macromedia, the multimedia company", "y")
|
||||
scummvmAssertEqual(the last word of "Macromedia, the multimedia company", "company")
|
||||
scummvmAssertEqual(the last word of "Macromedia, the multimedia company" && "man", "company man")
|
||||
scummvmAssertEqual(word -30000 of "Macromedia, the multimedia company", "company")
|
||||
scummvmAssertEqual(word -30000 of "Macromedia, the multimedia company" && "man", "company man")
|
||||
|
||||
set src = "abcdefghijklmnopqrstuvwxyz"
|
||||
scummvmAssertEqual(char 2 of src, "b")
|
||||
scummvmAssertEqual(char 2 to 0 of src, "b")
|
||||
scummvmAssertEqual(char 2 to 4 of src, "bcd")
|
||||
scummvmAssertEqual(char 2 to 1000 of src, "bcdefghijklmnopqrstuvwxyz")
|
||||
scummvmAssertEqual(char 1000 of src, "")
|
||||
|
||||
set src = " the quick brown fox jumped over the lazy dog"
|
||||
scummvmAssertEqual(word 2 of src, "quick")
|
||||
scummvmAssertEqual(word 2 to 4 of src, "quick brown fox")
|
||||
scummvmAssertEqual(word 2 to 1000 of src, "quick brown fox jumped over the lazy dog")
|
||||
scummvmAssertEqual(word 1000 of src, "")
|
||||
|
||||
set src = "the,quick,brown,fox,jumped,over,the,lazy,dog"
|
||||
scummvmAssertEqual(item 2 of src, "quick")
|
||||
scummvmAssertEqual(item 2 to 4 of src, "quick,brown,fox")
|
||||
scummvmAssertEqual(item 2 to 1000 of src, "quick,brown,fox,jumped,over,the,lazy,dog")
|
||||
scummvmAssertEqual(item 1000 of src, "")
|
||||
|
||||
set src = "the quick" & RETURN & "brown fox" & RETURN & "jumped over" & RETURN & "the lazy dog"
|
||||
scummvmAssertEqual(line 2 of src, "brown fox")
|
||||
scummvmAssertEqual(line 2 to 4 of src, "brown fox" & RETURN & "jumped over" & RETURN & "the lazy dog")
|
||||
scummvmAssertEqual(line 2 to 1000 of src, "brown fox" & RETURN & "jumped over" & RETURN & "the lazy dog")
|
||||
scummvmAssertEqual(line 1000 of src, "")
|
||||
|
||||
put "abcdefghijklmnopqrstuvwxyz" into field 1
|
||||
scummvmAssertEqual(char 2 of field 1, "b")
|
||||
scummvmAssertEqual(char 2 to 0 of field 1, "b")
|
||||
scummvmAssertEqual(char 2 to 4 of field 1, "bcd")
|
||||
scummvmAssertEqual(char 2 to 1000 of field 1, "bcdefghijklmnopqrstuvwxyz")
|
||||
scummvmAssertEqual(char 1000 of field 1, "")
|
||||
|
||||
put "lorem ipsum dolor sit amet" into field 1
|
||||
set the foreColor of word 2 of field 1 to 10
|
||||
put the foreColor of word 2 of field 1
|
||||
93
engines/director/lingo/tests/delete.lingo
Normal file
93
engines/director/lingo/tests/delete.lingo
Normal file
@@ -0,0 +1,93 @@
|
||||
put "qwertyuiop" into test
|
||||
delete char 2 of test
|
||||
scummvmAssertEqual(test, "qertyuiop")
|
||||
|
||||
put "qwertyuiop" into test
|
||||
delete char 2 to 9 of test
|
||||
scummvmAssertEqual(test, "qp")
|
||||
|
||||
put "qwertyuiop" into test
|
||||
delete char 2 to 1000 of test
|
||||
scummvmAssertEqual(test, "q")
|
||||
|
||||
put "qwertyuiop" into test
|
||||
delete char 0 of test
|
||||
scummvmAssertEqual(test, "")
|
||||
|
||||
put "qwertyuiop" into test
|
||||
delete the last char of test
|
||||
scummvmAssertEqual(test, "qwertyuio")
|
||||
|
||||
put "lorem ipsum dolor" into test
|
||||
delete word 2 of test
|
||||
scummvmAssertEqual(test, "lorem dolor")
|
||||
|
||||
put "lorem ipsum dolor" into test
|
||||
delete word 2 to 3 of test
|
||||
scummvmAssertEqual(test, "lorem ")
|
||||
|
||||
put "lorem ipsum dolor" into test
|
||||
delete word 2 to 1000 of test
|
||||
scummvmAssertEqual(test, "lorem ")
|
||||
|
||||
put "lorem ipsum dolor" into test
|
||||
delete the last word of test
|
||||
scummvmAssertEqual(test, "lorem ipsum ")
|
||||
|
||||
put "lorem,ipsum,dolor,sit,amet" into test
|
||||
delete item 3 of test
|
||||
scummvmAssertEqual(test, "lorem,ipsum,sit,amet")
|
||||
|
||||
put "lorem,ipsum,dolor,sit,amet" into test
|
||||
delete item 2 to 5 of test
|
||||
scummvmAssertEqual(test, "lorem")
|
||||
|
||||
put "lorem,ipsum,dolor,sit,amet" into test
|
||||
delete item 1 of test
|
||||
scummvmAssertEqual(test, "ipsum,dolor,sit,amet")
|
||||
|
||||
put "lorem,ipsum,dolor,sit,amet" into test
|
||||
delete the last item of test
|
||||
scummvmAssertEqual(test, "lorem,ipsum,dolor,sit")
|
||||
|
||||
put "lorem" & RETURN & "ipsum" & RETURN & "dolor" & RETURN & "sit" & RETURN & "amet" into test
|
||||
delete line 3 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & "ipsum" & RETURN & "sit" & RETURN & "amet")
|
||||
|
||||
put "lorem" & RETURN & "ipsum" & RETURN & "dolor" & RETURN & "sit" & RETURN & "amet" into test
|
||||
delete line 2 to 5 of test
|
||||
scummvmAssertEqual(test, "lorem")
|
||||
|
||||
put "lorem" & RETURN & "ipsum" & RETURN & "dolor" & RETURN & "sit" & RETURN & "amet" into test
|
||||
delete the last line of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & "ipsum" & RETURN & "dolor" & RETURN & "sit")
|
||||
|
||||
put "foo" & RETURN & "lorem ipsum" into test
|
||||
delete char 3 of word 2 of line 2 of test
|
||||
scummvmAssertEqual(test, "foo" & RETURN & "lorem ipum")
|
||||
|
||||
put "lorem" & RETURN & "ipsum" & RETURN & "dolor,sit,amet" & RETURN & "nunc" into test
|
||||
delete item 1 of line 3 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & "ipsum" & RETURN & "sit,amet" & RETURN & "nunc")
|
||||
|
||||
put "lorem" & RETURN & "ipsum" & RETURN & "dolor,sit,amet" & RETURN & "nunc" into test
|
||||
delete item 2 of line 3 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & "ipsum" & RETURN & "dolor,amet" & RETURN & "nunc")
|
||||
|
||||
put "lorem" & RETURN & "ipsum" & RETURN & "dolor,sit,amet" & RETURN & "nunc" into test
|
||||
delete item 3 of line 3 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & "ipsum" & RETURN & "dolor,sit" & RETURN & "nunc")
|
||||
|
||||
put "lorem" & RETURN & "ipsum" & RETURN & "dolor,sit,amet" & RETURN & "nunc" into test
|
||||
delete item 1 of line 2 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & RETURN & "dolor,sit,amet" & RETURN & "nunc")
|
||||
delete item 1 of line 2 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & RETURN & "dolor,sit,amet" & RETURN & "nunc")
|
||||
delete item 4 of line 2 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & RETURN & "dolor,sit,amet" & RETURN & "nunc")
|
||||
delete item 4 of line 4 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & RETURN & "dolor,sit,amet" & RETURN & "nunc")
|
||||
delete item 1 of line 4 of test
|
||||
scummvmAssertEqual(test, "lorem" & RETURN & RETURN & "dolor,sit,amet" & RETURN)
|
||||
|
||||
|
||||
249
engines/director/lingo/tests/equality.lingo
Normal file
249
engines/director/lingo/tests/equality.lingo
Normal file
@@ -0,0 +1,249 @@
|
||||
scummvmAssert(VOID = VOID)
|
||||
scummvmAssert(not(VOID < VOID))
|
||||
scummvmAssert(VOID <= VOID)
|
||||
scummvmAssert(not(VOID > VOID))
|
||||
scummvmAssert(VOID >= VOID)
|
||||
|
||||
scummvmAssert(VOID = 0)
|
||||
scummvmAssert(VOID < 0)
|
||||
scummvmAssert(VOID <= 0)
|
||||
scummvmAssert(not(VOID > 0))
|
||||
scummvmAssert(not(VOID >= 0))
|
||||
|
||||
scummvmAssert(not(0 = VOID))
|
||||
scummvmAssert(0 > VOID)
|
||||
scummvmAssert(0 >= VOID)
|
||||
scummvmAssert(not(0 < VOID))
|
||||
scummvmAssert(not(0 <= VOID))
|
||||
|
||||
scummvmAssert(1 = 1)
|
||||
scummvmAssert(1 = "1")
|
||||
scummvmAssert(1 = 1.0)
|
||||
scummvmAssert(cast 1 = cast 1)
|
||||
scummvmAssert("test" = "test")
|
||||
scummvmAssert(#test = #test)
|
||||
set string = the text of field 1
|
||||
scummvmAssert(field 1 = string)
|
||||
scummvmAssert(0 = "")
|
||||
scummvmAssert(1 <> cast 1)
|
||||
scummvmAssert("test" <> #test)
|
||||
|
||||
-- If string parses as a float, coerce to float
|
||||
scummvmAssert("2000" > 25)
|
||||
scummvmAssert(25 < "2000")
|
||||
scummvmAssert("2000.5" > 25)
|
||||
scummvmAssert(25 < "2000.5")
|
||||
scummvmAssert("20e5" > 25)
|
||||
scummvmAssert(25 < "20e5")
|
||||
scummvmAssert(" 2000" > 25)
|
||||
scummvmAssert(25 < " 2000")
|
||||
scummvmAssert("2000" > 2.5)
|
||||
scummvmAssert(25 < "2000")
|
||||
scummvmAssert("2000.5" > 2.5)
|
||||
scummvmAssert(2.5 < "2000.5")
|
||||
scummvmAssert("20e5" > 2.5)
|
||||
scummvmAssert(2.5 < "20e5")
|
||||
scummvmAssert(" 2000" > 2.5)
|
||||
scummvmAssert(2.5 < " 2000")
|
||||
|
||||
-- If a string doesn't parse as a float, coerce the number to a string
|
||||
scummvmAssert("2/" < 20)
|
||||
scummvmAssert(20 > "2/")
|
||||
scummvmAssert("2000 e" < 25)
|
||||
scummvmAssert(25 > "2000 e")
|
||||
|
||||
-- Two strings, treat with normal string ordering rules
|
||||
scummvmAssert("2000" <> "2000.0")
|
||||
scummvmAssert("2000" < "25")
|
||||
scummvmAssert("abc" < "abcd")
|
||||
scummvmAssert("abc" < "def")
|
||||
|
||||
-- Non-coercable string is always bigger than a number or void
|
||||
scummvmAssert("test" > 3000)
|
||||
scummvmAssert(3000 < "test")
|
||||
scummvmAssert("test" > 300.0)
|
||||
scummvmAssert(300.0 < "test")
|
||||
scummvmAssert("test" > VOID)
|
||||
scummvmAssert(VOID < "test")
|
||||
|
||||
|
||||
-- Mimic an object
|
||||
scummvmAssert("<Object:#FileIO" > 0)
|
||||
|
||||
-- Invalid comparisons should return FALSE
|
||||
scummvmAssert(not (#test <= 0))
|
||||
|
||||
-- Picture comparisons are always false, even between the exact same cast.
|
||||
-- set a to the picture of cast 1
|
||||
-- scummvmAssert(a <> a)
|
||||
-- scummvmAssert(a <> the picture of cast 1) -- always false
|
||||
|
||||
|
||||
-- String comparison
|
||||
scummvmAssert("a" = "A")
|
||||
scummvmAssert(not("a" < "A"))
|
||||
scummvmAssert(not("a" <= "A"))
|
||||
scummvmAssert("a" > "A")
|
||||
scummvmAssert("a" >= "A")
|
||||
|
||||
scummvmAssert(not("a" = "Z"))
|
||||
scummvmAssert("a" < "Z")
|
||||
scummvmAssert("a" <= "Z")
|
||||
scummvmAssert(not("a" > "Z"))
|
||||
scummvmAssert(not("a" >= "Z"))
|
||||
|
||||
scummvmAssert(not("Z" = "a"))
|
||||
scummvmAssert(not("Z" < "a"))
|
||||
scummvmAssert(not("Z" <= "a"))
|
||||
scummvmAssert("Z" > "a")
|
||||
scummvmAssert("Z" >= "a")
|
||||
|
||||
scummvmAssert(not("a" = "Bubba"))
|
||||
scummvmAssert("a" < "Bubba")
|
||||
scummvmAssert("a" <= "Bubba")
|
||||
scummvmAssert(not("a" > "Bubba"))
|
||||
scummvmAssert(not("a" >= "Bubba"))
|
||||
|
||||
scummvmAssert("z" = "Z")
|
||||
scummvmAssert(not("z" < "Z"))
|
||||
scummvmAssert(not("z" <= "Z"))
|
||||
scummvmAssert("z" > "Z")
|
||||
scummvmAssert("z" >= "Z")
|
||||
|
||||
scummvmAssert("abba" = "Abba")
|
||||
scummvmAssert(not("abba" < "Abba"))
|
||||
scummvmAssert(not("abba" <= "Abba"))
|
||||
scummvmAssert("abba" > "Abba")
|
||||
scummvmAssert("abba" >= "Abba")
|
||||
|
||||
scummvmAssert("Erwin's Catalyst" = "Erwin's Catalyst")
|
||||
scummvmAssert(not("Erwin's Catalyst" < "Erwin's Catalyst"))
|
||||
scummvmAssert("Erwin's Catalyst" <= "Erwin's Catalyst")
|
||||
scummvmAssert(not("Erwin's Catalyst" > "Erwin's Catalyst"))
|
||||
scummvmAssert("Erwin's Catalyst" >= "Erwin's Catalyst")
|
||||
|
||||
-- Char 213 resolves to U+2018 LEFT SINGLE QUOTATION MARK under D4-mac
|
||||
scummvmAssert("Erwin's Catalyst" = ("Erwin" & numToChar(213) & "s Catalyst"))
|
||||
scummvmAssert("Erwin's Catalyst" < ("Erwin" & numToChar(213) & "s Catalyst"))
|
||||
scummvmAssert("Erwin's Catalyst" <= ("Erwin" & numToChar(213) & "s Catalyst"))
|
||||
scummvmAssert(not("Erwin's Catalyst" > ("Erwin" & numToChar(213) & "s Catalyst")))
|
||||
scummvmAssert(not("Erwin's Catalyst" >= ("Erwin" & numToChar(213) & "s Catalyst")))
|
||||
|
||||
|
||||
-- Array comparison with coercion
|
||||
scummvmAssert([] = [])
|
||||
scummvmAssert(not([] <> []))
|
||||
scummvmAssert([1, 2] = [1, 2])
|
||||
scummvmAssert(not([1, 2] <> [1, 2]))
|
||||
scummvmAssert([1, 2] = [1, "2"])
|
||||
scummvmAssert(not([1, 2] <> [1, "2"]))
|
||||
scummvmAssert([1, 2, 3] = [1, "2", 3.0])
|
||||
scummvmAssert(not([1, 2, 3] <> [1, "2", 3.0]))
|
||||
scummvmAssert(["testa", "testb"] = ["testa", "TESTB"])
|
||||
scummvmAssert([#a: "testa", #b: "testb"] = [#a: "testa", #b: "TESTB"])
|
||||
|
||||
-- D4 has a quirk where only the left side list elements are checked
|
||||
set the scummvmVersion to 400
|
||||
scummvmAssert([] = [1, "2", 4])
|
||||
scummvmAssert(not([] <> [1, "2", 4]))
|
||||
scummvmAssert([1, 2] = [1, "2", 4])
|
||||
scummvmAssert(not([1, 2] <> [1, "2", 4]))
|
||||
scummvmAssert([1, 2, 3] <> [1, "2", 4])
|
||||
scummvmAssert(not([1, 2, 3] = [1, "2", 4]))
|
||||
scummvmAssert([1, 2, 3] <> [1, "2"])
|
||||
scummvmAssert(not([1, 2, 3] = [1, "2"]))
|
||||
scummvmAssert([:] = [#a: 1, #b: "2", #c: 4])
|
||||
scummvmAssert(not([:] <> [#a: 1, #b: "2", #c: 4]))
|
||||
scummvmAssert([#a: 1, #b: 2] = [#a: 1, #b: "2", #c: 4])
|
||||
scummvmAssert(not([#a: 1, #b: 2] <> [#a: 1, #b: "2", #c: 4]))
|
||||
scummvmAssert([#a: 1, #b: 2, #c: 3] <> [#a: 1, #b: "2", #c: 4])
|
||||
scummvmAssert(not([#a: 1, #b: 2, #c: 3] = [#a: 1, #b: "2", #c: 4]))
|
||||
scummvmAssert([#a: 1, #b: 2, #c: 3] <> [#a: 1, #b: "2"])
|
||||
scummvmAssert(not([#a: 1, #b: 2, #c: 3] = [#a: 1, #b: "2"]))
|
||||
|
||||
set the scummvmVersion to 500
|
||||
scummvmAssert([] <> [1, "2", 4])
|
||||
scummvmAssert(not([] = [1, "2", 4]))
|
||||
scummvmAssert([1, 2] <> [1, "2", 4])
|
||||
scummvmAssert(not([1, 2] = [1, "2", 4]))
|
||||
scummvmAssert([1, 2, 3] <> [1, "2", 4])
|
||||
scummvmAssert(not([1, 2, 3] = [1, "2", 4]))
|
||||
scummvmAssert([1, 2, 3] <> [1, "2"])
|
||||
scummvmAssert(not([1, 2, 3] = [1, "2"]))
|
||||
scummvmAssert([:] <> [#a: 1, #b: "2", #c: 4])
|
||||
scummvmAssert(not([:] = [#a: 1, #b: "2", #c: 4]))
|
||||
scummvmAssert([#a: 1, #b: 2] <> [#a: 1, #b: "2", #c: 4])
|
||||
scummvmAssert(not([#a: 1, #b: 2] = [#a: 1, #b: "2", #c: 4]))
|
||||
scummvmAssert([#a: 1, #b: 2, #c: 3] <> [#a: 1, #b: "2", #c: 4])
|
||||
scummvmAssert(not([#a: 1, #b: 2, #c: 3] = [#a: 1, #b: "2", #c: 4]))
|
||||
scummvmAssert([#a: 1, #b: 2, #c: 3] <> [#a: 1, #b: "2"])
|
||||
scummvmAssert(not([#a: 1, #b: 2, #c: 3] = [#a: 1, #b: "2"]))
|
||||
|
||||
-- single-element equality check, check to see if all list elements match
|
||||
scummvmAssert(0 = [])
|
||||
scummvmAssert([] = 0)
|
||||
scummvmAssert(not(0 <> []))
|
||||
scummvmAssert(not([] <> 0))
|
||||
scummvmAssert(2 = [])
|
||||
scummvmAssert([] = 2)
|
||||
scummvmAssert(not(2 <> []))
|
||||
scummvmAssert(not([] <> 2))
|
||||
scummvmAssert(2 = [2, 2.0, "2", "2.0"])
|
||||
scummvmAssert([2, 2.0, "2", "2.0"] = 2)
|
||||
scummvmAssert(2 <> [2, 2.0, "2", "2.1"])
|
||||
scummvmAssert([2, 2.0, "2", "2.1"] <> 2)
|
||||
|
||||
scummvmAssert(0 = [:])
|
||||
scummvmAssert([:] = 0)
|
||||
scummvmAssert(not(0 <> [:]))
|
||||
scummvmAssert(not([:] <> 0))
|
||||
scummvmAssert(2 = [:])
|
||||
scummvmAssert([:] = 2)
|
||||
scummvmAssert(not(2 <> [:]))
|
||||
scummvmAssert(not([:] <> 2))
|
||||
scummvmAssert(2 = [#a: 2, #b: 2.0, #c: "2", #d: "2.0"])
|
||||
scummvmAssert([#a: 2, #b: 2.0, #c: "2", #d: "2.0"] = 2)
|
||||
scummvmAssert(2 <> [#a: 2, #b: 2.0, #c: "2", #d: "2.1"])
|
||||
scummvmAssert([#a: 2, #b: 2.0, #c: "2", #d: "2.1"] <> 2)
|
||||
|
||||
scummvmAssert(0 = point(0, 0))
|
||||
scummvmAssert(point(0, 0) = 0)
|
||||
scummvmAssert(2 = point(2, 2))
|
||||
scummvmAssert(point(2, 2) = 2)
|
||||
scummvmAssert(2 <> point(2, 3))
|
||||
scummvmAssert(point(2, 3) <> 2)
|
||||
|
||||
scummvmAssert(0 = rect(0, 0, 0, 0))
|
||||
scummvmAssert(rect(0, 0, 0, 0) = 0)
|
||||
scummvmAssert(2 = rect(2, 2, 2, 2))
|
||||
scummvmAssert(rect(2, 2, 2, 2) = 2)
|
||||
scummvmAssert(2 <> rect(2, 2, 2, 3))
|
||||
scummvmAssert(rect(2, 2, 2, 3) <> 2)
|
||||
|
||||
|
||||
|
||||
-- Void comparison
|
||||
set v1 = value("!")
|
||||
set v2 = value("!")
|
||||
|
||||
scummvmAssert(v1 = v2)
|
||||
scummvmAssert(not(v1 < v2))
|
||||
scummvmAssert(not(v1 > v2))
|
||||
|
||||
scummvmAssert(v1 = 0)
|
||||
scummvmAssert(v1 < 0)
|
||||
scummvmAssert(not(v1 > 0))
|
||||
|
||||
scummvmAssert(not(v1 = 0.0))
|
||||
scummvmAssert(v1 < 0.0)
|
||||
scummvmAssert(not(v1 > 0.0))
|
||||
|
||||
scummvmAssert(not(v1 = "0"))
|
||||
scummvmAssert(v1 < "0")
|
||||
scummvmAssert(not(v1 > "0"))
|
||||
|
||||
scummvmAssert(not(v1 = "what"))
|
||||
scummvmAssert(v1 < "what")
|
||||
scummvmAssert(not(v1 > "what"))
|
||||
|
||||
|
||||
21
engines/director/lingo/tests/events.lingo
Normal file
21
engines/director/lingo/tests/events.lingo
Normal file
@@ -0,0 +1,21 @@
|
||||
on exitFrame
|
||||
beep
|
||||
end exitFrame
|
||||
|
||||
on enterFrame me
|
||||
beep
|
||||
end
|
||||
|
||||
on annoy howMuch
|
||||
beep random(howMuch)
|
||||
alert "Aren't handlers fun?"
|
||||
end annoy
|
||||
|
||||
on annoy2 howMuch
|
||||
beep random(howMuch)
|
||||
alert "Aren't handlers fun?"
|
||||
end annoy2 howMuch
|
||||
|
||||
on move me
|
||||
set h = the locH of sprite pSprite + pChangeH
|
||||
end
|
||||
18
engines/director/lingo/tests/factory-do.lingo
Normal file
18
engines/director/lingo/tests/factory-do.lingo
Normal file
@@ -0,0 +1,18 @@
|
||||
abc(mNew)
|
||||
|
||||
factory abc
|
||||
method mNew
|
||||
instance avar
|
||||
set avar to "a variable"
|
||||
set res1 = me(callDo)
|
||||
scummvmAssertEqual(res1, "a variable")
|
||||
me(setDo)
|
||||
scummvmAssertEqual(avar, 100)
|
||||
|
||||
method callDo
|
||||
set myvar = 0
|
||||
do("set myvar = avar")
|
||||
return myvar
|
||||
|
||||
method setDo
|
||||
do("set avar = 100")
|
||||
143
engines/director/lingo/tests/factory.lingo
Normal file
143
engines/director/lingo/tests/factory.lingo
Normal file
@@ -0,0 +1,143 @@
|
||||
AimGun2
|
||||
|
||||
aim1(mDispose)
|
||||
|
||||
set notAMethod = 0
|
||||
scummvmAssertError aim2(notAMethod) -- should error
|
||||
aim2("notAMethod") -- should run fallback handler
|
||||
|
||||
-- method call syntax without parens
|
||||
GrammarFactory mSetStatusToArg "foo"
|
||||
scummvmAssertEqual status "foo"
|
||||
GrammarFactory mSetStatusToArg2 "foo", "bar"
|
||||
scummvmAssertEqual status "bar"
|
||||
|
||||
-- method call syntax with parens and a comma
|
||||
GrammarFactory(mSetStatusToArg, "foo")
|
||||
scummvmAssertEqual status "foo"
|
||||
GrammarFactory(mSetStatusToArg2, "foo", "bar")
|
||||
scummvmAssertEqual status "bar"
|
||||
scummvmAssertEqual GrammarFactory(mReturnArg, "foo") "foo"
|
||||
scummvmAssertEqual GrammarFactory(mReturnArg2, "foo", "bar") "bar"
|
||||
|
||||
-- method call syntax with parens and no comma
|
||||
GrammarFactory(mSetStatusToArg "foo")
|
||||
scummvmAssertEqual status "foo"
|
||||
GrammarFactory(mSetStatusToArg2 "foo", "bar")
|
||||
scummvmAssertEqual status "bar"
|
||||
scummvmAssertEqual GrammarFactory(mReturnArg "foo") "foo"
|
||||
scummvmAssertEqual GrammarFactory(mReturnArg2 "foo", "bar") "bar"
|
||||
|
||||
--
|
||||
macro AimGun2
|
||||
global aim1
|
||||
set aim1 = aim2(mNew)
|
||||
--
|
||||
factory aim2
|
||||
method mNew
|
||||
dontpassevent
|
||||
global aim1
|
||||
when mousedown then aim1(fire)
|
||||
when keydown then aim1(mExit)
|
||||
set the locv of sprite 24 to 540
|
||||
method mMove x, y
|
||||
global aimCopy
|
||||
set the locH of sprite 15 to x
|
||||
set the locV of sprite 15 to y-250
|
||||
set aimCopy = me
|
||||
method mAtFrame
|
||||
dontpassevent
|
||||
me(mMove, the mouseH, the mouseV)
|
||||
method fire
|
||||
global fire1, targeth, targetv
|
||||
set fire1 = fire2(mNew)
|
||||
set the perframehook to fire1
|
||||
me(mDispose)
|
||||
method mExit
|
||||
set the perframehook to false
|
||||
postfire
|
||||
me(mDispose)
|
||||
method mDispose
|
||||
global aim1
|
||||
set aim1 = 1
|
||||
when keydown then nothing
|
||||
--
|
||||
factory fire2
|
||||
method mNew
|
||||
dontpassevent
|
||||
when mousedown then nothing
|
||||
set the castnum of sprite 14 to f15
|
||||
method mAtFrame
|
||||
Global StartH, StartV, targetv, stepH, stepV, bcast
|
||||
dontpassevent
|
||||
set the castnum of sprite 14 to bcast
|
||||
set the LocV of sprite 14 to (startV-stepV)
|
||||
if sprite 14 intersects 10 and (startV-6) <= targetV then
|
||||
set the castnum of sprite 14 to f16
|
||||
set the perframehook to false
|
||||
me(hit)
|
||||
exit
|
||||
end if
|
||||
if startV < targetV or bcast>g17 then
|
||||
set the perframehook to false
|
||||
set the locV of sprite 14 to 340
|
||||
aimgun2
|
||||
exit
|
||||
end if
|
||||
set startV to (startV-stepV)
|
||||
set bcast = bcast + 1
|
||||
method hit
|
||||
global KillLoc
|
||||
set killloc to the loch of sprite 3
|
||||
go "Death"
|
||||
set the locV of sprite 14 to 400
|
||||
aimgun2
|
||||
if factory(killloc) then put "boo"
|
||||
method mDispose
|
||||
global fire1
|
||||
set fire1 = 0
|
||||
Method mNew2 theSprite, startCastRight, endCastRight, startCastLeft, endCastLeft
|
||||
instance startDrawLeft, endDrawLeft, startDrawRight, endDrawRight, multiDrawP
|
||||
|
||||
if startCastLeft and endCastLeft then set multiDrawP to TRUE
|
||||
set startDrawLeft to startCastRight
|
||||
set endDrawLeft to endCastRight
|
||||
set startDrawRight to startCastLeft
|
||||
set endDrawRight to endCastLeft
|
||||
|
||||
me(mInitBirdPart, theSprite, startCastRight)
|
||||
Method mAtFrame2 frame, subFrame
|
||||
global gMouseH, gMouseV
|
||||
set gMouseH = mouseH()
|
||||
set gMouseV = mouseV()
|
||||
|
||||
-- Exit when "Done" button, which resides upon score channel 6.
|
||||
if (the clickOn = 6) then exit
|
||||
|
||||
put the mouseDown into mouseClick
|
||||
Body(mEveryFrame, mouseClick)
|
||||
RightWing(mEveryFrame, mouseClick)
|
||||
LeftWing(mEveryFrame, mouseClick)
|
||||
|
||||
|
||||
--
|
||||
macro KillIt2
|
||||
global KillLoc
|
||||
set the locH of sprite 3 to KillLoc
|
||||
|
||||
on aim2 test
|
||||
put "fallback worked!"
|
||||
end
|
||||
|
||||
--
|
||||
factory GrammarFactory
|
||||
method mSetStatusToArg arg
|
||||
global status
|
||||
set status = arg
|
||||
method mSetStatusToArg2 arg1, arg2
|
||||
global status
|
||||
set status = arg2
|
||||
method mReturnArg arg
|
||||
return arg
|
||||
method mReturnArg2 arg1, arg2
|
||||
return arg2
|
||||
27
engines/director/lingo/tests/global.lingo
Normal file
27
engines/director/lingo/tests/global.lingo
Normal file
@@ -0,0 +1,27 @@
|
||||
global version
|
||||
|
||||
on initPattern
|
||||
global MaxPattern
|
||||
set MaxPattern = 65
|
||||
put "first: " & MaxPattern
|
||||
set a = 5
|
||||
end initPattern
|
||||
|
||||
on increase
|
||||
global MaxPattern
|
||||
set MaxPattern = MaxPattern + 1
|
||||
put MaxPattern
|
||||
set a = 10
|
||||
end increase
|
||||
|
||||
set a = 8
|
||||
set MaxPattern = 3
|
||||
|
||||
initPattern
|
||||
|
||||
increase
|
||||
increase
|
||||
|
||||
put MaxPattern
|
||||
|
||||
put a
|
||||
28
engines/director/lingo/tests/goto.lingo
Normal file
28
engines/director/lingo/tests/goto.lingo
Normal file
@@ -0,0 +1,28 @@
|
||||
go to frame "Open23" of movie "OpenCabin23"
|
||||
go "CARDBACK"
|
||||
go movie "BAR 1"
|
||||
go to "Open23" of movie "OpenCabin23"
|
||||
go to "Chair"
|
||||
|
||||
set varframe to "VARFrame"
|
||||
set varmovie to "VARMovie"
|
||||
|
||||
go to frame 35
|
||||
go the frame
|
||||
go "label two"
|
||||
go to movie "Chicago"
|
||||
go to frame 23 of movie "Chicago"
|
||||
go to frame "main loop" of movie "Basic With"
|
||||
go to marker(1)
|
||||
go frame "dissolve" of movie "captain's table"
|
||||
|
||||
play frame 37
|
||||
play frame "label one"
|
||||
play movie "Desert Scene"
|
||||
play frame 23 of movie "Chicago"
|
||||
play frame varframe of movie varmovie
|
||||
play frame "main loop" of movie "Basic With"
|
||||
play done
|
||||
|
||||
playAccel "Lungs.mma"
|
||||
playAccel "Bolitas.mma", loop, clickStop, whatFits
|
||||
13
engines/director/lingo/tests/hms.lingo
Normal file
13
engines/director/lingo/tests/hms.lingo
Normal file
@@ -0,0 +1,13 @@
|
||||
scummvmAssertEqual framesToHMS(123456, 30, FALSE, FALSE), " 01:08:35.06 "
|
||||
scummvmAssertEqual framesToHMS(-123456, 30, FALSE, FALSE), "-01:08:35.06 "
|
||||
|
||||
scummvmAssertEqual framesToHMS(123456, 30, FALSE, TRUE), " 01:08:35.20 "
|
||||
|
||||
scummvmAssertEqual HMSToFrames(" 01:08:35.06 ", 30, FALSE, FALSE), 123456
|
||||
scummvmAssertEqual HMSToFrames("-01:08:35.06 ", 30, FALSE, FALSE), -123456
|
||||
scummvmAssertEqual HMSToFrames("01:08:35.06", 30, FALSE, FALSE), 123456
|
||||
scummvmAssertEqual HMSToFrames("08:35.06", 30, FALSE, FALSE), 15456
|
||||
scummvmAssertEqual HMSToFrames("35.06", 30, FALSE, FALSE), 1056
|
||||
scummvmAssertEqual HMSToFrames("35", 30, FALSE, FALSE), 1050
|
||||
|
||||
scummvmAssertEqual HMSToFrames(" 01:08:35.20 ", 30, FALSE, TRUE), 123456
|
||||
172
engines/director/lingo/tests/if.lingo
Normal file
172
engines/director/lingo/tests/if.lingo
Normal file
@@ -0,0 +1,172 @@
|
||||
--
|
||||
set x = 1
|
||||
if x = 5 then exit
|
||||
else put 10.0
|
||||
|
||||
if x = 6 then put 2
|
||||
|
||||
set y = 4
|
||||
|
||||
-- defined variables are falsy when checked with not
|
||||
-- i.e. not varundefined => true
|
||||
-- only a var with value 0 is seen as false when checked with not
|
||||
-- i.e. not 0 => true
|
||||
scummvmAssert(varundefined = 0)
|
||||
scummvmAssert(not varundefined = 1)
|
||||
|
||||
set a to 0
|
||||
scummvmAssert(not a = 1)
|
||||
set a to 0.0
|
||||
scummvmAssert(not a = 0)
|
||||
set a to "string"
|
||||
scummvmAssert(not a = 0)
|
||||
set parray to [#pt: 1, #ar: 0]
|
||||
scummvmAssert(not parray = 0)
|
||||
--
|
||||
|
||||
repeat with x = 1 to 6
|
||||
if x = 3 then put 30
|
||||
else if x = 4 then put 40
|
||||
else if x = 5 then put 50
|
||||
else put 10.0
|
||||
if x = 1 then
|
||||
put 1
|
||||
else if x = 2 then
|
||||
put 1232.12345678901234
|
||||
put 2.2
|
||||
else if x = 3 then
|
||||
put 3
|
||||
else if x = 4 then
|
||||
put 4
|
||||
else if x = 5 then
|
||||
put 5
|
||||
else if x = 6 then
|
||||
put 6
|
||||
end if
|
||||
if x = 4 then put 40
|
||||
else put 50
|
||||
end repeat
|
||||
|
||||
if the keyCode = 36 then -- return key goes to first menu
|
||||
go to frame 1
|
||||
else if the keyCode = 123 then -- left arrow goes to previous menu
|
||||
dontPassEvent
|
||||
go to marker(-1)
|
||||
else if the keyCode = 124 then -- right arrow goes to next menu
|
||||
dontPassEvent
|
||||
go to marker(1)
|
||||
else if the keyCode = 125 then -- down arrow goes to last (bottom) menu
|
||||
dontPassEvent
|
||||
go to frame "credits"
|
||||
else if the keyCode = 126 then -- up arrow goes to first (top) menu
|
||||
dontPassEvent
|
||||
go to frame 1
|
||||
end if
|
||||
|
||||
if abs(y) = x and abs(x) = y then
|
||||
put TRUE
|
||||
else
|
||||
put FALSE
|
||||
end if
|
||||
|
||||
if abs(y) = x and abs(x) = y then put 5
|
||||
if abs(y) = x and abs(x) = y then put 5
|
||||
else put 6
|
||||
|
||||
if the selection = the text of cast 1 then
|
||||
go to frame "sEnd"
|
||||
exit
|
||||
else if whichTry = 1 then go to frame "sTell"
|
||||
else if whichTry = 2 then go to frame "sShow"
|
||||
else if whichTry = 3 then go to frame "sDo"
|
||||
|
||||
if the selection = the text of cast 1 then
|
||||
go to frame "sEnd"
|
||||
exit
|
||||
else if whichTry = 1 then
|
||||
go to frame "sTell"
|
||||
else if whichTry = 2 then
|
||||
put 5
|
||||
go to frame "sShow"
|
||||
else if whichTry = 3 then go to frame "sDo"
|
||||
else put 6
|
||||
|
||||
if the selection = the text of cast 1 then go to frame "sEnd"
|
||||
else put 7
|
||||
|
||||
if the selection = the text of cast 1 then go to frame "sEnd"
|
||||
else if whichTry = 1 then
|
||||
go to frame "sTell"
|
||||
else if whichTry = 2 then
|
||||
put 5
|
||||
go to frame "sShow"
|
||||
else if whichTry = 3 then go to frame "sDo"
|
||||
else
|
||||
put 6
|
||||
put 7
|
||||
end if
|
||||
|
||||
if the selection = the text of cast 1 then go to frame "sEnd"
|
||||
else if whichTry = 1 then
|
||||
go to frame "sTell"
|
||||
else if whichTry = 2 then
|
||||
put 5
|
||||
go to frame "sShow"
|
||||
else if whichTry = 3 then go to frame "sDo"
|
||||
else put 7
|
||||
|
||||
if rollOver(2) then
|
||||
put "The cursor is INSIDE the square." into field "Cursor Status"
|
||||
else
|
||||
put "The cursor is OUTSIDE the square." into field "Cursor Status"
|
||||
end if
|
||||
|
||||
if the selection = the text of cast 1 then
|
||||
if whichTry = 3 then
|
||||
go to frame "sDo"
|
||||
end if
|
||||
else if whichTry = 1 then
|
||||
if whichTry = 3 then go to frame "sDo"
|
||||
else
|
||||
put 5
|
||||
end if
|
||||
else if whichTry = 2 then
|
||||
if whichTry = 3 then go to frame "sDo"
|
||||
else
|
||||
if the selection = the text of cast A21 then
|
||||
if whichTry = 3 then
|
||||
go to frame "Foo"
|
||||
end if
|
||||
else if abra = 5 then put 6
|
||||
else
|
||||
put 7
|
||||
if abra = 7 then put 5
|
||||
end if
|
||||
end if
|
||||
else if whichTry = 3 then go to frame "sDo"
|
||||
else put 6
|
||||
|
||||
if the selection = the text of cast 1 then go to frame "sEnd"
|
||||
|
||||
when keyDown then if the key = RETURN then checkField
|
||||
when keyDown then if the key = QUOTE then checkField
|
||||
|
||||
if the mouseH > ((the right of sprite 15) - 20) then beep
|
||||
else if ((the mouseH > ((the left of sprite 15) + 30)) and Â
|
||||
(the mouseH < ((the left of sprite 15) + 73)) and Â
|
||||
(the mouseV > ((the top of sprite 15) + 20)) and Â
|
||||
(the mouseV < ((the top of sprite 15) + 40))) then StoreButtonHit
|
||||
else if ((the mouseH > ((the left of sprite 15) + 81)) and Â
|
||||
(the mouseH < ((the left of sprite 15) +124)) and Â
|
||||
(the mouseV > ((the top of sprite 15) + 20)) and Â
|
||||
(the mouseV < ((the top of sprite 15) + 40))) then LoadButtonHit
|
||||
else if ((the mouseH > ((the left of sprite 15) + 30)) and Â
|
||||
(the mouseH < ((the left of sprite 15) +124)) and Â
|
||||
(the mouseV > ((the top of sprite 15) + 55)) and Â
|
||||
(the mouseV < ((the top of sprite 15) + 83))) then AudioButtonHit
|
||||
end if
|
||||
|
||||
macro WindowHorzP X
|
||||
set X1 = constrainH( 14, X )
|
||||
if X1 = X then return( TRUE )
|
||||
else return( FALSE )
|
||||
17
engines/director/lingo/tests/ilk.lingo
Normal file
17
engines/director/lingo/tests/ilk.lingo
Normal file
@@ -0,0 +1,17 @@
|
||||
-- single arg variant, return type
|
||||
put ilk(10)
|
||||
put ilk(20.0)
|
||||
put ilk("Macromedia")
|
||||
put ilk(point(10, 20))
|
||||
put ilk(ilk(10))
|
||||
set x = point(10, 20)
|
||||
put ilk(x)
|
||||
|
||||
-- two arg variant, return if type matches
|
||||
put ilk(10, #integer)
|
||||
put ilk("Macromedia", #string)
|
||||
set x = list(1,2,3)
|
||||
put ilk(x, #list)
|
||||
put ilk(x, #linearlist)
|
||||
put ilk(x, #integer)
|
||||
|
||||
0
engines/director/lingo/tests/lingotests
Normal file
0
engines/director/lingo/tests/lingotests
Normal file
34
engines/director/lingo/tests/listoverride.lingo
Normal file
34
engines/director/lingo/tests/listoverride.lingo
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
on count l
|
||||
return "what is this"
|
||||
end
|
||||
|
||||
on add l, x
|
||||
return "this is the worst"
|
||||
end
|
||||
|
||||
set result = count([1, 2, 3])
|
||||
scummvmAssertEqual(result, 3)
|
||||
|
||||
set result = count([1: 2, 3: 4, 5: 6])
|
||||
scummvmAssertEqual(result, 3)
|
||||
|
||||
set result = count(rect(1, 2, 3, 4))
|
||||
scummvmAssertEqual(result, 4)
|
||||
|
||||
set result = count(point(1, 2))
|
||||
scummvmAssertEqual(result, 2)
|
||||
|
||||
set result = count("not an array")
|
||||
scummvmAssertEqual(result, "what is this")
|
||||
|
||||
set result = add("still not an array")
|
||||
scummvmAssertEqual(result, "this is the worst")
|
||||
|
||||
set result = add("even less of an array", 8)
|
||||
scummvmAssertEqual(result, "this is the worst")
|
||||
|
||||
set target = [1, 2, 3]
|
||||
add(target, 4)
|
||||
scummvmAssertEqual(count(target), 4)
|
||||
|
||||
371
engines/director/lingo/tests/lists.lingo
Normal file
371
engines/director/lingo/tests/lists.lingo
Normal file
@@ -0,0 +1,371 @@
|
||||
set x = []
|
||||
set y = [:]
|
||||
set machinery = [#gears:6, #balls:3, #ramps:8]
|
||||
set nested = [1, 2, [3, 4], 5]
|
||||
set gList = ["car":1, "boat": 20]
|
||||
|
||||
set a to [1, 2, 3]
|
||||
put a
|
||||
|
||||
set gList = [point(70, 190), point(217, 66), point(364, 185)]
|
||||
|
||||
set gBugList = [[energy: 10, mood: "Happy"], [energy: -10, mood: "Sad"], [energy: 60, mood: "Hungry"], [energy: 20, mood: "Sad"]]
|
||||
|
||||
set b to [4, 5, 6, 7]
|
||||
scummvmAssertEqual(string(a + b), "[5, 7, 9]")
|
||||
scummvmAssertEqual(string(a - b), "[-3, -3, -3]")
|
||||
scummvmAssertEqual(string(a * b), "[4, 10, 18]")
|
||||
scummvmAssertEqual(string(b / a), "[4, 2, 2]")
|
||||
scummvmAssertEqual(string(b mod a), "[0, 1, 0]")
|
||||
scummvmAssertEqual(string(-a), "[-1, -2, -3]")
|
||||
|
||||
set floats to [4.0, 5.0, 6.0, 7.0]
|
||||
set strings to ["4", "5", "6", "7"]
|
||||
|
||||
scummvmAssertEqual(a + floats, [5.0, 7.0, 9.0])
|
||||
scummvmAssertEqual(a + strings, [5.0, 7.0, 9.0])
|
||||
scummvmAssertEqual(string(a + 1), "[2, 3, 4]")
|
||||
scummvmAssertEqual(string(1 + b), "[5, 6, 7, 8]")
|
||||
|
||||
-- property Array tests
|
||||
set propArray to [501: "cast", 502: "value", 1.5: "script", a: "score", #b: "member", "color": "red"]
|
||||
set var to getPropAt(propArray, 1)
|
||||
scummvmAssertEqual(var, 501)
|
||||
set var to getAt(propArray, 1)
|
||||
scummvmAssertEqual(var, "cast")
|
||||
|
||||
set var to getProp(propArray, 1.5)
|
||||
scummvmAssertEqual(var, "script")
|
||||
set var to getProp(propArray, #a)
|
||||
scummvmAssertEqual(var, "score")
|
||||
set var to getProp(propArray, "a")
|
||||
scummvmAssertEqual(var, "score")
|
||||
set var to getProp(propArray, #color)
|
||||
scummvmAssertEqual(var, "red")
|
||||
set var to getProp(propArray, #b)
|
||||
scummvmAssertEqual(var, "member")
|
||||
|
||||
-- itemOf
|
||||
set string_array to "one,, three, four"
|
||||
set res to item 2 of string_array
|
||||
scummvmAssert(res="")
|
||||
set res to item 3 of string_array
|
||||
scummvmAssert(res=" three")
|
||||
set res to item 4 of string_array
|
||||
scummvmAssert(res=" four")
|
||||
|
||||
-- itemOf check for float
|
||||
set res to item 3.4 of string_array
|
||||
scummvmAssert(res=" three")
|
||||
|
||||
-- itemOf out of bounds checks
|
||||
set res to item 5 of string_array
|
||||
scummvmAssert(res="")
|
||||
|
||||
set res to item -1 of string_array
|
||||
scummvmAssert(res=string_array)
|
||||
|
||||
-- itemOf: test delimiter
|
||||
set save = the itemDelimiter
|
||||
set the itemDelimiter = ":"
|
||||
set delim_array to "one: two: three: four"
|
||||
set res to item 3 of delim_array
|
||||
scummvmAssert(res=" three")
|
||||
set the itemDelimiter = save
|
||||
|
||||
-- rects
|
||||
set rct to rect(0, 0, 100, 100)
|
||||
set gA to getAt(rct, 2)
|
||||
scummvmAssertEqual(gA, 0)
|
||||
set gA to getAt(rct, 3)
|
||||
scummvmAssertEqual(gA, 100)
|
||||
setAt rct, 2, 20
|
||||
scummvmAssertEqual(getAt(rct, 2), 20)
|
||||
|
||||
-- array conversions
|
||||
set a to point(11, 12)
|
||||
set b to rect(21, 22, 23, 24)
|
||||
set c to [31]
|
||||
set d to [41, 42]
|
||||
set e to [51, 52, 53]
|
||||
set f to [61, 62, 63, 64]
|
||||
set g to [71, 72, 73, 74, 75]
|
||||
set h to 5
|
||||
|
||||
scummvmAssertEqual(string(a + a), "point(22, 24)")
|
||||
scummvmAssertEqual(string(a + b), "[32, 34]")
|
||||
scummvmAssertEqual(string(a + c), "[42]")
|
||||
scummvmAssertEqual(string(a + d), "point(52, 54)")
|
||||
scummvmAssertEqual(string(a + e), "[62, 64]")
|
||||
scummvmAssertEqual(string(a + f), "[72, 74]")
|
||||
scummvmAssertEqual(string(a + g), "[82, 84]")
|
||||
scummvmAssertEqual(string(a + h), "point(16, 17)")
|
||||
|
||||
scummvmAssertEqual(string(b + a), "[32, 34]")
|
||||
scummvmAssertEqual(string(b + b), "rect(42, 44, 46, 48)")
|
||||
scummvmAssertEqual(string(b + c), "[52]")
|
||||
scummvmAssertEqual(string(b + d), "[62, 64]")
|
||||
scummvmAssertEqual(string(b + e), "[72, 74, 76]")
|
||||
scummvmAssertEqual(string(b + f), "rect(82, 84, 86, 88)")
|
||||
scummvmAssertEqual(string(b + g), "[92, 94, 96, 98]")
|
||||
scummvmAssertEqual(string(b + h), "rect(26, 27, 28, 29)")
|
||||
|
||||
scummvmAssertEqual(string(c + a), "[42]")
|
||||
scummvmAssertEqual(string(c + b), "[52]")
|
||||
scummvmAssertEqual(string(c + c), "[62]")
|
||||
scummvmAssertEqual(string(c + d), "[72]")
|
||||
scummvmAssertEqual(string(c + e), "[82]")
|
||||
scummvmAssertEqual(string(c + f), "[92]")
|
||||
scummvmAssertEqual(string(c + g), "[102]")
|
||||
scummvmAssertEqual(string(c + h), "[36]")
|
||||
|
||||
scummvmAssertEqual(string(d + a), "[52, 54]")
|
||||
scummvmAssertEqual(string(d + b), "[62, 64]")
|
||||
scummvmAssertEqual(string(d + c), "[72]")
|
||||
scummvmAssertEqual(string(d + d), "[82, 84]")
|
||||
scummvmAssertEqual(string(d + e), "[92, 94]")
|
||||
scummvmAssertEqual(string(d + f), "[102, 104]")
|
||||
scummvmAssertEqual(string(d + g), "[112, 114]")
|
||||
scummvmAssertEqual(string(d + h), "[46, 47]")
|
||||
|
||||
scummvmAssertEqual(string(e + a), "[62, 64]")
|
||||
scummvmAssertEqual(string(e + b), "[72, 74, 76]")
|
||||
scummvmAssertEqual(string(e + c), "[82]")
|
||||
scummvmAssertEqual(string(e + d), "[92, 94]")
|
||||
scummvmAssertEqual(string(e + e), "[102, 104, 106]")
|
||||
scummvmAssertEqual(string(e + f), "[112, 114, 116]")
|
||||
scummvmAssertEqual(string(e + g), "[122, 124, 126]")
|
||||
scummvmAssertEqual(string(e + h), "[56, 57, 58]")
|
||||
|
||||
scummvmAssertEqual(string(f + a), "[72, 74]")
|
||||
scummvmAssertEqual(string(f + b), "[82, 84, 86, 88]")
|
||||
scummvmAssertEqual(string(f + c), "[92]")
|
||||
scummvmAssertEqual(string(f + d), "[102, 104]")
|
||||
scummvmAssertEqual(string(f + e), "[112, 114, 116]")
|
||||
scummvmAssertEqual(string(f + f), "[122, 124, 126, 128]")
|
||||
scummvmAssertEqual(string(f + g), "[132, 134, 136, 138]")
|
||||
scummvmAssertEqual(string(f + h), "[66, 67, 68, 69]")
|
||||
|
||||
scummvmAssertEqual(string(g + a), "[82, 84]")
|
||||
scummvmAssertEqual(string(g + b), "[92, 94, 96, 98]")
|
||||
scummvmAssertEqual(string(g + c), "[102]")
|
||||
scummvmAssertEqual(string(g + d), "[112, 114]")
|
||||
scummvmAssertEqual(string(g + e), "[122, 124, 126]")
|
||||
scummvmAssertEqual(string(g + f), "[132, 134, 136, 138]")
|
||||
scummvmAssertEqual(string(g + g), "[142, 144, 146, 148, 150]")
|
||||
scummvmAssertEqual(string(g + h), "[76, 77, 78, 79, 80]")
|
||||
|
||||
scummvmAssertEqual(string(h + a), "point(16, 17)")
|
||||
scummvmAssertEqual(string(h + b), "rect(26, 27, 28, 29)")
|
||||
scummvmAssertEqual(string(h + c), "[36]")
|
||||
scummvmAssertEqual(string(h + d), "[46, 47]")
|
||||
scummvmAssertEqual(string(h + e), "[56, 57, 58]")
|
||||
scummvmAssertEqual(string(h + f), "[66, 67, 68, 69]")
|
||||
scummvmAssertEqual(string(h + g), "[76, 77, 78, 79, 80]")
|
||||
scummvmAssertEqual(string(h + h), "10")
|
||||
|
||||
-- proplist with missing keys
|
||||
set proplist_without_keys = ["key": "value", "keyless expr 1", "keyless expr 2"]
|
||||
set proplist_with_keys = ["key": "value", 2: "keyless expr 1", 3: "keyless expr 2"]
|
||||
scummvmAssert(proplist_without_keys = proplist_with_keys)
|
||||
|
||||
-- list with symbol or string as key
|
||||
set templst to [#mood: 1]
|
||||
set tempmood to the mood of templst
|
||||
scummvmAssert(tempmood = 1)
|
||||
put templst
|
||||
|
||||
-- assign and check
|
||||
set the mood of templst to 2
|
||||
set tempmood to the mood of templst
|
||||
scummvmAssert(tempmood = 2)
|
||||
put templst
|
||||
|
||||
|
||||
-- add
|
||||
set list1 = [1, 4, 2]
|
||||
add list1, 3
|
||||
scummVMAssert(getPos(list1, 3) = 4)
|
||||
set list1 = [1, 4, 2]
|
||||
sort list1
|
||||
add list1, 3
|
||||
scummVMAssert(getPos(list1, 3) = 3)
|
||||
|
||||
-- addAt
|
||||
|
||||
|
||||
-- addProp
|
||||
|
||||
|
||||
-- append
|
||||
|
||||
|
||||
-- count
|
||||
|
||||
|
||||
-- deleteAt (uses getAt as basis)
|
||||
set testList to [1, 2, 3, 4, 5]
|
||||
deleteAt testList, 3
|
||||
scummvmAssertEqual(testList, [1, 2, 4, 5])
|
||||
set testList to [#a: 1, #b: 2, #c: 3, #d: 4, #e: 5]
|
||||
deleteAt testList, 3
|
||||
scummvmAssertEqual(testList, [#a: 1, #b: 2, #d: 4, #e: 5])
|
||||
|
||||
|
||||
-- deleteOne (uses getOne as basis)
|
||||
set testList to [5, 4, 3, 1, 4]
|
||||
deleteOne testList, 4
|
||||
scummvmAssertEqual(testList, [5, 3, 1, 4])
|
||||
set testlist to [5, "4.0", 3, 1, 4]
|
||||
deleteOne testList, 4
|
||||
scummvmAssertEqual(testList, [5, 3, 1, 4])
|
||||
set testlist to [5, 4.0, 3, 1, 4]
|
||||
deleteOne testList, 4
|
||||
scummvmAssertEqual(testList, [5, 3, 1, 4])
|
||||
set testlist to [5, "urgh", 3, 1, "urgh"]
|
||||
deleteOne testList, "urgh"
|
||||
scummvmAssertEqual(testList, [5, 3, 1, "urgh"])
|
||||
set testlist to [5, "URGH", 3, 1, "urgh"]
|
||||
deleteOne testList, "urgh"
|
||||
scummvmAssertEqual(testList, [5, "URGH", 3, 1])
|
||||
|
||||
|
||||
-- deleteProp
|
||||
|
||||
|
||||
-- findPos
|
||||
set testList to [#a: 1, #b: 2, #bb: 3, #d: 4, #e: 5]
|
||||
scummvmAssertEqual(findPos(testList, #b), 2)
|
||||
scummvmAssertEqual(findPos(testList, #f), VOID)
|
||||
|
||||
set testList to []
|
||||
scummvmAssertEqual(findPos(testList, #3), 0)
|
||||
set testList to [1, 3, 0]
|
||||
scummvmAssertEqual(findPos(testList, 3), 3)
|
||||
scummvmAssertEqual(findPos(testList, 2), 2)
|
||||
scummvmAssertEqual(findPos(testList, 4), 0)
|
||||
scummvmAssertEqual(findPos(testList, -1), 0)
|
||||
scummvmAssertEqual(findPos(testList, 1), 1)
|
||||
sort testList
|
||||
scummvmAssertEqual(findPos(testList, 1), 2)
|
||||
scummvmAssertEqual(findPos(testList, 0), 1)
|
||||
scummvmAssertEqual(findPos(testList, 2), 0)
|
||||
scummvmAssertEqual(findPos(testList, 4), 0)
|
||||
|
||||
-- findPosNear
|
||||
set testList to [#b: 2, #a: 1, #bb: 3, #d: 4, #e: 5]
|
||||
scummvmAssertEqual(findPosNear(testList, #b), 1)
|
||||
-- if the property list isn't sorted and the value isn't there, return the size of the list + 1
|
||||
scummvmAssertEqual(findPosNear(testList, #missing), 6)
|
||||
scummvmAssertEqual(findPosNear(testList, #bbb), 6)
|
||||
sort testList
|
||||
scummvmAssertEqual(findPosNear(testList, #bbb), 4)
|
||||
|
||||
set testList to [1: 2, 4: 8, 16: 32]
|
||||
scummvmAssertEqual(findPosNear(testList, 4), 2)
|
||||
scummvmAssertEqual(findPosNear(testList, 10), 4)
|
||||
sort testList
|
||||
scummvmAssertEqual(findPosNear(testList, 10), 3)
|
||||
|
||||
-- the manual claims that findPosNear throws an error if you give it a regular list. the manual is wrong.
|
||||
set testList to [62, 5, 33]
|
||||
scummvmAssertEqual(findPosNear(testList, 5), 2)
|
||||
-- if the property list isn't sorted and the value isn't there, return the value
|
||||
scummvmAssertEqual(findPosNear(testList, 44), 44)
|
||||
sort testList
|
||||
scummvmAssertEqual(findPosNear(testList, 5), 1)
|
||||
scummvmAssertEqual(findPosNear(testList, 44), 3)
|
||||
|
||||
|
||||
-- getaProp
|
||||
set testList to [#a, #b, #c, #d, #e]
|
||||
scummvmAssertEqual(getaProp(testList, 4), #d)
|
||||
scummvmAssertError getaProp(testList, 7)
|
||||
set testList to [#a: 5, #b: 4, #c: 3, #d: 2, #e: 1]
|
||||
scummvmAssertEqual(getaProp(testList, #d), 2)
|
||||
scummvmAssert(voidp(getaProp(testList, #g)))
|
||||
|
||||
|
||||
-- getAt
|
||||
set testList to [5, 4, 3, 2, 1]
|
||||
scummvmAssertEqual(getAt(testList, 2), 4)
|
||||
scummvmAssertError getAt(testList, 7)
|
||||
set testList to [#a: 5, #b: 4, #c: 3, #d: 2, #e: 1]
|
||||
scummvmAssertEqual(getAt(testList, 2), 4)
|
||||
scummvmAssertError getAt(testList, 7)
|
||||
|
||||
|
||||
-- getLast
|
||||
set testList to [#a, #b, #c]
|
||||
scummvmAssertEqual(getLast(testList), #c)
|
||||
scummvmAssert(voidp(getLast([])))
|
||||
set testList to [#a: 3, #b: 2, #c: 1]
|
||||
scummvmAssertEqual(getLast(testList), 1)
|
||||
scummvmAssert(voidp(getLast([:])))
|
||||
|
||||
|
||||
-- getOne
|
||||
set testList to [#a, #b, #c, #d, #d, #e]
|
||||
scummvmAssertEqual(getOne(testList, #d), 4)
|
||||
scummvmAssertEqual(getOne(testList, #g), 0)
|
||||
|
||||
set testList to [5, 4, 3, 1, 4]
|
||||
scummvmAssertEqual(getOne(testList, 4), 2)
|
||||
set testlist to [5, "4.0", 3, 1, 4]
|
||||
scummvmAssertEqual(getOne(testList, 4), 2)
|
||||
set testlist to [5, 4.0, 3, 1, 4]
|
||||
scummvmAssertEqual(getOne(testList, 4), 2)
|
||||
set testlist to [5, "urgh", 3, 1, "urgh"]
|
||||
scummvmAssertEqual(getOne(testList, "urgh"), 2)
|
||||
set testlist to [5, "URGH", 3, 1, "urgh"]
|
||||
scummvmAssertEqual(getOne(testList, "urgh"), 5)
|
||||
|
||||
-- for finding ARRAY/PARRAY, check the pointer, not the contents
|
||||
set testList to [#a, #b, [1, 2, 3]]
|
||||
scummvmAssertEqual(getOne(testList, [1, 2, 3]), 0)
|
||||
set subItem to [1, 2, 3]
|
||||
set testList to [#a, #b, subItem]
|
||||
scummvmAssertEqual(getOne(testList, subItem), 3)
|
||||
|
||||
|
||||
-- getProp
|
||||
set testList to [#a, #b, #c, #d, #e]
|
||||
scummvmAssertEqual(getProp(testList, 3), #c)
|
||||
|
||||
|
||||
-- getPropAt
|
||||
|
||||
|
||||
-- ilk
|
||||
|
||||
|
||||
-- list
|
||||
|
||||
|
||||
-- listP
|
||||
|
||||
|
||||
-- max
|
||||
|
||||
|
||||
-- min
|
||||
|
||||
|
||||
-- setaProp
|
||||
|
||||
|
||||
-- setAt
|
||||
set lst to []
|
||||
setAt lst,1,5
|
||||
scummvmAssertEqual(lst, [5])
|
||||
set lst to []
|
||||
setAt lst,3,5
|
||||
scummvmAssertEqual(lst, [0,0,5])
|
||||
setAt lst,2,5
|
||||
scummvmAssertEqual(lst, [0,5,5])
|
||||
|
||||
|
||||
-- setProp
|
||||
|
||||
|
||||
-- sort
|
||||
65
engines/director/lingo/tests/loops.lingo
Normal file
65
engines/director/lingo/tests/loops.lingo
Normal file
@@ -0,0 +1,65 @@
|
||||
set x = 5
|
||||
if x <= 5 then set x = 6
|
||||
if (x = 5) then
|
||||
set x = 7 -- this is comment
|
||||
else
|
||||
set x = 8
|
||||
-- this is another comment
|
||||
end if
|
||||
put x
|
||||
-- this is more comment
|
||||
set y = 1
|
||||
repeat while (y < 5)
|
||||
set y = y + 1
|
||||
put y
|
||||
end repeat
|
||||
|
||||
repeat with z = 10 to 15
|
||||
put z
|
||||
end repeat
|
||||
repeat with y = 5 down to 1
|
||||
put y
|
||||
end repeat
|
||||
|
||||
repeat while y < 5
|
||||
set y = y + 1
|
||||
put y
|
||||
end repeat
|
||||
|
||||
|
||||
repeat while y < 5
|
||||
set y = y + 1
|
||||
if y = 3 then next repeat
|
||||
put y
|
||||
end repeat
|
||||
|
||||
-- tests for repeat with
|
||||
|
||||
on exitRepeatWith
|
||||
set aList = [1,2,3,4]
|
||||
repeat with a in aList
|
||||
if a = 3 then
|
||||
exit repeat
|
||||
end if
|
||||
end repeat
|
||||
return a
|
||||
end exitRepeatWith
|
||||
|
||||
on returnRepeatWith
|
||||
set aList = [1,2,3,4]
|
||||
repeat with a in aList
|
||||
if a = 3 then
|
||||
return a
|
||||
end if
|
||||
end repeat
|
||||
end returnRepeatWith
|
||||
|
||||
on directListRepeatWith
|
||||
repeat with a in [1,2,3,4]
|
||||
put a
|
||||
end repeat
|
||||
end directListRepeatWith
|
||||
|
||||
put exitRepeatWith()
|
||||
put returnRepeatWith()
|
||||
directListRepeatWith()
|
||||
44
engines/director/lingo/tests/macros.lingo
Normal file
44
engines/director/lingo/tests/macros.lingo
Normal file
@@ -0,0 +1,44 @@
|
||||
global x, y
|
||||
set y = 8
|
||||
shipx
|
||||
put x
|
||||
zipx
|
||||
put x
|
||||
put y
|
||||
|
||||
test
|
||||
test()
|
||||
put test
|
||||
put test()
|
||||
if test then test
|
||||
|
||||
--
|
||||
macro SHIPX
|
||||
global x, y
|
||||
set x = Random(5)
|
||||
if x = 1 then
|
||||
go "Zoom"
|
||||
exit
|
||||
end if
|
||||
if x >1 then
|
||||
set y = 10
|
||||
exit
|
||||
end if
|
||||
put 100
|
||||
|
||||
--
|
||||
macro ZIPX
|
||||
set x = Random(5)
|
||||
if x = 1 then
|
||||
go "ZIP"
|
||||
exit
|
||||
end if
|
||||
if x >1 then
|
||||
put x
|
||||
check x, 5
|
||||
exit
|
||||
end if
|
||||
|
||||
--
|
||||
macro test
|
||||
return "a"
|
||||
165
engines/director/lingo/tests/math.lingo
Normal file
165
engines/director/lingo/tests/math.lingo
Normal file
@@ -0,0 +1,165 @@
|
||||
if random(4) > 2 then put 1000
|
||||
set z = 5.5
|
||||
set z1 = 2
|
||||
set z2 = z / z1
|
||||
put z
|
||||
put z1
|
||||
put z2
|
||||
put integer(z2)
|
||||
put cos(z2)
|
||||
|
||||
set x = 2 + 3 * (4 / 2)
|
||||
put x
|
||||
|
||||
put power(2, 8)
|
||||
put power(2, 8, 0)
|
||||
put power(2)
|
||||
updatestage
|
||||
|
||||
-- Type conversion
|
||||
put (1024/4096)*100 -- 0
|
||||
put (1024/4096)*100.0 -- 0.0
|
||||
put ((1024*1.0)/4096)*100.0 -- 25.0
|
||||
|
||||
put the sqrt of 9
|
||||
scummvmAssertEqual(ilk(sqrt(EMPTY)), #float)
|
||||
scummvmAssertEqual(sqrt(EMPTY), 0.0)
|
||||
|
||||
scummvmAssertEqual(ilk(sqrt(4)), #integer)
|
||||
scummvmAssertEqual(string(sqrt(0)), "0")
|
||||
scummvmAssertEqual(string(sqrt(4)), "2")
|
||||
scummvmAssertEqual(string(sqrt(5)), "2")
|
||||
scummvmAssertEqual(string(sqrt(8)), "3")
|
||||
|
||||
scummvmAssertEqual(ilk(sqrt(4.0)), #float)
|
||||
scummvmAssertEqual(sqrt(0.0), 0.0)
|
||||
scummvmAssertEqual(sqrt(4.0), 2.0)
|
||||
scummvmAssertEqual(abs(sqrt(5.0) - 2.2361) < 0.0001, 1)
|
||||
scummvmAssertEqual(abs(sqrt(8.0) - 2.8284) < 0.0001, 1)
|
||||
|
||||
scummvmAssertEqual(ilk(sqrt("4.0")), #float)
|
||||
scummvmAssertEqual(sqrt("0.0"), 0.0)
|
||||
scummvmAssertEqual(sqrt("4.0"), 2.0)
|
||||
scummvmAssertEqual(abs(sqrt("5.0") - 2.2361) < 0.0001, 1)
|
||||
scummvmAssertEqual(abs(sqrt("8.0") - 2.8284) < 0.0001, 1)
|
||||
|
||||
scummvmAssertEqual(ilk(sqrt("4")), #float)
|
||||
scummvmAssertEqual(sqrt("0"), 0.0)
|
||||
scummvmAssertEqual(sqrt("4"), 2.0)
|
||||
scummvmAssertEqual(abs(sqrt("5") - 2.2361) < 0.0001, 1)
|
||||
scummvmAssertEqual(abs(sqrt("8") - 2.8284) < 0.0001, 1)
|
||||
|
||||
-- Testing rounding
|
||||
set save to the scummvmVersion
|
||||
set the scummvmVersion to 300
|
||||
scummvmAssertEqual(integer(2.5), 3)
|
||||
scummvmAssertEqual(integer(2.49), 2)
|
||||
scummvmAssertEqual(integer(2.1), 2)
|
||||
scummvmAssertEqual(integer(2.0), 2)
|
||||
scummvmAssertEqual(integer(1.9), 2)
|
||||
scummvmAssertEqual(integer(1.5), 2)
|
||||
scummvmAssertEqual(integer(1.49), 1)
|
||||
scummvmAssertEqual(integer(1.0), 1)
|
||||
scummvmAssertEqual(integer(0.0), 0)
|
||||
scummvmAssertEqual(integer(-0.49), 0)
|
||||
scummvmAssertEqual(integer(-0.5), 0)
|
||||
scummvmAssertEqual(integer(-1.0), 0)
|
||||
scummvmAssertEqual(integer(-1.49), 0)
|
||||
scummvmAssertEqual(integer(-1.5), -1)
|
||||
scummvmAssertEqual(integer(-1.9), -1)
|
||||
scummvmAssertEqual(integer(-2.0), -1)
|
||||
scummvmAssertEqual(integer(-2.1), -1)
|
||||
scummvmAssertEqual(integer(-2.49), -1)
|
||||
scummvmAssertEqual(integer(-2.5), -2)
|
||||
|
||||
set the scummvmVersion to save
|
||||
|
||||
-- Min/max - D4 has bugs related to handling VOID
|
||||
set the scummvmVersion to 400
|
||||
scummvmAssertEqual(min(VOID, 30), 30)
|
||||
scummvmAssertEqual(ilk(max(VOID, 30)), #void)
|
||||
scummvmAssertEqual(ilk(min(30, VOID)), #void)
|
||||
scummvmAssertEqual(max(30, VOID), 30)
|
||||
|
||||
scummvmAssertEqual(min(VOID, "test"), "test")
|
||||
scummvmAssertEqual(ilk(max(VOID, "test")), #void)
|
||||
scummvmAssertEqual(ilk(min("test", VOID)), #void)
|
||||
scummvmAssertEqual(max("test", VOID), "test")
|
||||
|
||||
scummvmAssertEqual(min(1, VOID, 3), 3)
|
||||
scummvmAssertEqual(max(1, VOID, 3), 3)
|
||||
scummvmAssertEqual(min(VOID, 3, "test"), 3)
|
||||
scummvmAssertEqual(ilk(max(VOID, 3, "test")), #void)
|
||||
scummvmAssertEqual(min(1, VOID, 3, "test"), 3)
|
||||
scummvmAssertEqual(max(1, VOID, 3, "test"), "test")
|
||||
|
||||
scummvmAssertEqual(min(VOID, "test", 3), 3)
|
||||
scummvmAssertEqual(ilk(max(VOID, "test", 3)), #void)
|
||||
scummvmAssertEqual(min(3, VOID, "test"), "test")
|
||||
scummvmAssertEqual(max(3, VOID, "test"), "test")
|
||||
scummvmAssertEqual(ilk(min(3, "test", VOID)), #void)
|
||||
scummvmAssertEqual(max(3, "test", VOID), "test")
|
||||
scummvmAssertEqual(ilk(min("test", 3, VOID)), #void)
|
||||
scummvmAssertEqual(max("test", 3, VOID), "test")
|
||||
scummvmAssertEqual(min("test", VOID, 3), 3)
|
||||
scummvmAssertEqual(max("test", VOID, 3), "test")
|
||||
scummvmAssertEqual(min("test", VOID, 3, "2.5"), "2.5")
|
||||
scummvmAssertEqual(max("test", VOID, 3, "2.5"), "test")
|
||||
scummvmAssertEqual(min(1, "test", VOID, 3, "2.5"), "2.5")
|
||||
scummvmAssertEqual(max(1, "test", VOID, 3, "2.5"), "test")
|
||||
scummvmAssertEqual(min(1, "test", 3, "2.5"), 1)
|
||||
scummvmAssertEqual(max(1, "test", 3, "2.5"), "test")
|
||||
|
||||
-- D5 fixes the VOID bug
|
||||
set the scummvmVersion to 500
|
||||
scummvmAssertEqual(ilk(min(VOID, 30)), #void)
|
||||
scummvmAssertEqual(max(VOID, 30), 30)
|
||||
scummvmAssertEqual(ilk(min(30, VOID)), #void)
|
||||
scummvmAssertEqual(max(30, VOID), 30)
|
||||
|
||||
scummvmAssertEqual(min(VOID, "test"), "test")
|
||||
scummvmAssertEqual(ilk(max(VOID, "test")), #void)
|
||||
scummvmAssertEqual(min("test", VOID), "test")
|
||||
scummvmAssertEqual(ilk(max("test", VOID)), #void)
|
||||
|
||||
scummvmAssertEqual(ilk(min(1, VOID, 3)), #void)
|
||||
scummvmAssertEqual(max(1, VOID, 3), 3)
|
||||
scummvmAssertEqual(min(VOID, 3, "test"), "test")
|
||||
scummvmAssertEqual(max(VOID, 3, "test"), "test")
|
||||
scummvmAssertEqual(min(1, VOID, 3, "test"), "test")
|
||||
scummvmAssertEqual(max(1, VOID, 3, "test"), "test")
|
||||
|
||||
scummvmAssertEqual(min(VOID, "test", 3), 3)
|
||||
scummvmAssertEqual(max(VOID, "test", 3), 3)
|
||||
scummvmAssertEqual(min(3, VOID, "test"), "test")
|
||||
scummvmAssertEqual(max(3, VOID, "test"), "test")
|
||||
scummvmAssertEqual(ilk(min(3, "test", VOID)), #void)
|
||||
scummvmAssertEqual(ilk(max(3, "test", VOID)), #void)
|
||||
scummvmAssertEqual(ilk(min("test", 3, VOID)), #void)
|
||||
scummvmAssertEqual(ilk(max("test", 3, VOID)), #void)
|
||||
scummvmAssertEqual(min("test", VOID, 3), 3)
|
||||
scummvmAssertEqual(max("test", VOID, 3), 3)
|
||||
scummvmAssertEqual(min("test", VOID, 3, "2.5"), "2.5")
|
||||
scummvmAssertEqual(max("test", VOID, 3, "2.5"), 3)
|
||||
scummvmAssertEqual(min(1, "test", VOID, 3, "2.5"), "2.5")
|
||||
scummvmAssertEqual(max(1, "test", VOID, 3, "2.5"), 3)
|
||||
scummvmAssertEqual(min(1, "test", 3, "2.5"), 1)
|
||||
scummvmAssertEqual(max(1, "test", 3, "2.5"), "test")
|
||||
|
||||
-- cases the same for both
|
||||
set the scummvmVersion to 400
|
||||
scummvmAssertEqual(min(29, "30.0"), 29)
|
||||
scummvmAssertEqual(max(29, "30.0"), "30.0")
|
||||
scummvmAssertEqual(min(30, "30.0"), 30)
|
||||
scummvmAssertEqual(max(30, "30.0"), "30.0")
|
||||
scummvmAssertEqual(min(31, "30.0"), "30.0")
|
||||
scummvmAssertEqual(max(31, "30.0"), 31)
|
||||
scummvmAssertEqual(min(30.0, "30.1"), 30.0)
|
||||
scummvmAssertEqual(max(30.0, "30.1"), "30.1")
|
||||
scummvmAssertEqual(min(30.2, "30.1"), "30.1")
|
||||
scummvmAssertEqual(max(30.2, "30.1"), 30.2)
|
||||
|
||||
scummvmAssertEqual(min(50000, "test"), 50000)
|
||||
scummvmAssertEqual(max(50000, "test"), "test")
|
||||
scummvmAssertEqual(min(5000.0, "test"), 5000.0)
|
||||
scummvmAssertEqual(max(5000.0, "test"), "test")
|
||||
17
engines/director/lingo/tests/mci.lingo
Normal file
17
engines/director/lingo/tests/mci.lingo
Normal file
@@ -0,0 +1,17 @@
|
||||
mci "open MM\T005045a.wav type WaveAudio alias T005045a"
|
||||
mci "play T005045a from 22710 to 32872"
|
||||
|
||||
sound playFile 1, "Jet Blast"
|
||||
sound fadeOut 1
|
||||
sound fadeOut 1, 20
|
||||
sound fadeIn 1
|
||||
sound fadeIn 1, 15
|
||||
sound stop 1
|
||||
|
||||
playAccel "globe.mma", repeat, 5, noFlush, clickStop
|
||||
playAccel "globe.mma", tempo, 100, repeat, 10, noFlush, clickStop
|
||||
playAccel "globe.mma", tempo, 10, repeat, 4, noFlush, clickStop
|
||||
|
||||
mci
|
||||
mci close all
|
||||
mci play wave to 15228 hold
|
||||
14
engines/director/lingo/tests/mixed-code.lingo
Normal file
14
engines/director/lingo/tests/mixed-code.lingo
Normal file
@@ -0,0 +1,14 @@
|
||||
put "ONE"
|
||||
|
||||
on two
|
||||
put "TWO"
|
||||
end two
|
||||
|
||||
put "THREE"
|
||||
|
||||
on four
|
||||
put "FOUR"
|
||||
end FOUR
|
||||
|
||||
four
|
||||
two
|
||||
25
engines/director/lingo/tests/mperform.lingo
Normal file
25
engines/director/lingo/tests/mperform.lingo
Normal file
@@ -0,0 +1,25 @@
|
||||
abc(mNew)
|
||||
abc(callPerform)
|
||||
|
||||
factory abc
|
||||
method mnew
|
||||
put "init"
|
||||
|
||||
method callMe
|
||||
put "Am i called?"
|
||||
return "a1"
|
||||
|
||||
method callMe2
|
||||
put "Am i called2?"
|
||||
|
||||
method callMe3
|
||||
put "Am I called3?"
|
||||
|
||||
method callPerform
|
||||
put "stepped into matFrame"
|
||||
set retval to me(mPerform, "callMe")
|
||||
me(mPerform, "callMe2")
|
||||
me(mPerform, "callMe3")
|
||||
put "returned" && retval
|
||||
|
||||
scummvmAssertEqual(retval, "a1")
|
||||
3
engines/director/lingo/tests/point.lingo
Normal file
3
engines/director/lingo/tests/point.lingo
Normal file
@@ -0,0 +1,3 @@
|
||||
put point(10, 20)
|
||||
set x = point(20,30)
|
||||
put x
|
||||
43
engines/director/lingo/tests/put.lingo
Normal file
43
engines/director/lingo/tests/put.lingo
Normal file
@@ -0,0 +1,43 @@
|
||||
put "qwertyuiop" into test
|
||||
put "a" before char 3 of test
|
||||
scummvmAssertEqual(test, "qwaertyuiop")
|
||||
|
||||
put "qwertyuiop" into test
|
||||
put "a" into char 3 of test
|
||||
scummvmAssertEqual(test, "qwartyuiop")
|
||||
|
||||
put "qwertyuiop" into test
|
||||
put "a" after char 3 of test
|
||||
scummvmAssertEqual(test, "qweartyuiop")
|
||||
|
||||
put "lorem ipsum dolor sit amet" into test
|
||||
put "asdf" before word 3 of test
|
||||
scummvmAssertEqual(test, "lorem ipsum asdfdolor sit amet")
|
||||
|
||||
put "lorem ipsum dolor sit amet" into test
|
||||
put "asdf" into word 3 of test
|
||||
scummvmAssertEqual(test, "lorem ipsum asdf sit amet")
|
||||
|
||||
put "lorem ipsum dolor sit amet" into test
|
||||
put "asdf" after word 3 of test
|
||||
scummvmAssertEqual(test, "lorem ipsum dolorasdf sit amet")
|
||||
|
||||
put "123456789" into test
|
||||
put "foo" into char 20 of test
|
||||
scummvmAssertEqual(test, "123456789 foo")
|
||||
|
||||
put "foo" into test
|
||||
put "bar" into word 10000 of test
|
||||
scummvmAssertEqual(test, "foobar")
|
||||
|
||||
put "foo" into test
|
||||
put "bar" into item 10 of test
|
||||
scummvmAssertEqual(test, "foo,,,,,,,,,bar")
|
||||
|
||||
put "foo" into test"
|
||||
put "bar" into line 10 of test
|
||||
scummvmAssertEqual(test, "foo" & RETURN & RETURN & RETURN & RETURN & RETURN & RETURN & RETURN & RETURN & RETURN & "bar")
|
||||
|
||||
put "foo" & RETURN & "lorem ipsum" into test
|
||||
put "bar" into char 3 of word 2 of line 2 of test
|
||||
scummvmAssertEqual(test, "foo" & RETURN & "lorem ipbarum")
|
||||
50
engines/director/lingo/tests/reference.lingo
Normal file
50
engines/director/lingo/tests/reference.lingo
Normal file
@@ -0,0 +1,50 @@
|
||||
-- basic references
|
||||
set a = cast 1
|
||||
set a = cast "castname"
|
||||
set a = field 1
|
||||
set a = field "castname"
|
||||
set a = script "scriptname"
|
||||
set a = window "windowname"
|
||||
|
||||
-- assign to field reference
|
||||
put "asdf" into field 1
|
||||
put "lorem ipsum" into cast 1
|
||||
|
||||
-- the property of reference
|
||||
put the text of cast 1
|
||||
put line 1 to 5 of field the number of cast "MasterList" into field the number of cast "InventoryList"
|
||||
|
||||
-- the loaded of cast
|
||||
|
||||
-- real casts
|
||||
scummvmAssert(the loaded of cast 1)
|
||||
set test to cast 1
|
||||
scummvmAssert(the loaded of test)
|
||||
|
||||
-- nonexistent casts
|
||||
scummvmAssert(not the loaded of cast 500)
|
||||
set test to cast 500
|
||||
scummvmAssert(not the loaded of test)
|
||||
|
||||
put the loaded of cast "fake"
|
||||
set test to cast "fake"
|
||||
|
||||
-- the following test should not be executed
|
||||
-- we are testing only compilation
|
||||
if scummvmCompileOnly = 1337 then
|
||||
|
||||
-- user-defined handlers/factories w/ reference name
|
||||
-- (mainly to test grammar, so no factory definition)
|
||||
set theWindow = Window(mNew,#noGrowDoc,"Window " & windowNumber)
|
||||
|
||||
-- other weird stuff with reference name
|
||||
-- FIXME: We need to find a way of clean execution of these
|
||||
put window("test")
|
||||
set window = 1
|
||||
put window
|
||||
window("test")
|
||||
window "test"
|
||||
window cast
|
||||
fi
|
||||
|
||||
put cast cast
|
||||
6
engines/director/lingo/tests/roman.lingo
Normal file
6
engines/director/lingo/tests/roman.lingo
Normal file
@@ -0,0 +1,6 @@
|
||||
set z = "foo bar baz"
|
||||
set z1 = z & " meow"
|
||||
set z1 = z1 && "woof"
|
||||
scummvmAssert(z1 contains "MeÍW")
|
||||
|
||||
scummvmAssert("meow" = "MeÍW")
|
||||
24
engines/director/lingo/tests/sort.lingo
Normal file
24
engines/director/lingo/tests/sort.lingo
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
-- Just ints, use numeric sort
|
||||
set test to [200, 100, 25, 4, 3, 2, 1]
|
||||
sort(test)
|
||||
scummvmAssertEqual(test, [1, 2, 3, 4, 25, 100, 200])
|
||||
|
||||
-- Just floats, use numeric sort
|
||||
set test to [200.5, 100.5, 25.5, 4.5, 3.5, 2.5, 1.5]
|
||||
sort(test)
|
||||
scummvmAssertEqual(test, [1.5, 2.5, 3.5, 4.5, 25.5, 100.5, 200.5])
|
||||
|
||||
-- ints and floats, use numeric sort
|
||||
set test to [200, 100, 25, 4, 3, 2, 1, 2.5]
|
||||
sort(test)
|
||||
scummvmAssertEqual(test, [1, 2, 2.5, 3, 4, 25, 100, 200])
|
||||
|
||||
-- Just strings, use string sort
|
||||
set test to ["200", "100", "25", "4", "3", "2", "1", "2.5", "oh no"]
|
||||
sort(test)
|
||||
scummvmAssertEqual(test, ["1", "100", "2", "2.5", "200", "25", "3", "4", "oh no"])
|
||||
|
||||
-- For combined types (e.g. ints and strings), the result is undefined.
|
||||
-- The real interpreter will give an answer that's nearly the same as the
|
||||
-- string sort order, or softlock.
|
||||
6
engines/director/lingo/tests/sound.lingo
Normal file
6
engines/director/lingo/tests/sound.lingo
Normal file
@@ -0,0 +1,6 @@
|
||||
Sound playfile 3, "Sound.AIF"
|
||||
|
||||
sound fadeIn 5
|
||||
sound fadeIn 5, 10
|
||||
sound stop 1
|
||||
sound close 1
|
||||
191
engines/director/lingo/tests/strings.lingo
Normal file
191
engines/director/lingo/tests/strings.lingo
Normal file
@@ -0,0 +1,191 @@
|
||||
set z = "foo bar baz"
|
||||
set z1 = z & " meow"
|
||||
set z1 = z1 && "woof"
|
||||
scummvmAssert(z1 contains "bar")
|
||||
|
||||
set c = chars("Macromedia", 6, 6)
|
||||
scummvmAssertEqual(c, "m")
|
||||
set c = chars("Macromedia", 6, 10)
|
||||
scummvmAssertEqual(c, "media")
|
||||
set c = chars("Macromedia", -1, 15)
|
||||
scummvmAssertEqual(c, "Macromedia")
|
||||
set save to the scummvmVersion
|
||||
set the scummvmVersion to 300
|
||||
set c = chars("Macromedia", 1, 1.1)
|
||||
scummvmAssertEqual(c, 0)
|
||||
set the scummvmVersion to save
|
||||
|
||||
put "That is the last line of the file." & return & "Click Done to exit." && return && "foo"
|
||||
|
||||
if the key = Return then
|
||||
dontPassEvent
|
||||
end if
|
||||
|
||||
when keydown then if the key=return then set the stagecolor to random (256)
|
||||
|
||||
put return
|
||||
|
||||
put "foo" into test
|
||||
put return after test
|
||||
put test
|
||||
scummvmAssertEqual(test, "foo" & return)
|
||||
|
||||
put return before test
|
||||
scummvmAssertEqual(test, return & "foo" & return)
|
||||
|
||||
put return into test
|
||||
scummvmAssertEqual(test, return)
|
||||
|
||||
-- coercing strings to numbers
|
||||
-- str(int) + int
|
||||
scummvmAssertEqual("2" + 5, 7.0)
|
||||
scummvmAssertEqual(5 + "2", 7.0)
|
||||
-- str(int) + float
|
||||
scummvmAssertEqual("2" + 5.5, 7.5)
|
||||
scummvmAssertEqual(5.5 + "2", 7.5)
|
||||
-- str(float) + int
|
||||
scummvmAssertEqual("2.5" + 5, 7.5)
|
||||
scummvmAssertEqual(5 + "2.5", 7.5)
|
||||
-- str(float) + float
|
||||
scummvmAssertEqual("2.25" + 5.5, 7.75)
|
||||
scummvmAssertEqual(5.5 + "2.25", 7.75)
|
||||
|
||||
-- str(int) + str(int)
|
||||
scummvmAssertEqual("2" + "5", 7.0)
|
||||
scummvmAssertEqual("5" + "2", 7.0)
|
||||
-- str(int) + str(float)
|
||||
scummvmAssertEqual("2" + "5.5", 7.5)
|
||||
scummvmAssertEqual("5.5" + "2", 7.5)
|
||||
-- str(float) + str(int)
|
||||
scummvmAssertEqual("2.5" + "5", 7.5)
|
||||
scummvmAssertEqual("5" + "2.5", 7.5)
|
||||
-- str(float) + str(float)
|
||||
scummvmAssertEqual("2.25" + "5.5", 7.75)
|
||||
scummvmAssertEqual("5.5" + "2.25", 7.75)
|
||||
|
||||
|
||||
|
||||
-- float syntax
|
||||
scummvmAssertEqual("-2" + 5, 3.0)
|
||||
scummvmAssertEqual("-2.5" + 5, 2.5)
|
||||
scummvmAssertEqual("+2" + 5, 7.0)
|
||||
scummvmAssertEqual("+2.5" + 5, 7.5)
|
||||
scummvmAssertEqual("2e3" + 5, 2005.0)
|
||||
scummvmAssertEqual("2.5e3" + 5, 2505.0)
|
||||
scummvmAssertEqual(" 2" + 5, 7.0)
|
||||
scummvmAssertEqual(" 2.5" + 5, 7.5)
|
||||
|
||||
-- non number strings should coerce to a pointer
|
||||
scummvmAssertEqual(ilk("incorrect" + 5), #integer)
|
||||
scummvmAssertEqual(ilk(" 2.5 " + 5), #integer)
|
||||
scummvmAssert(ilk("2 uhhh" + 5), #integer)
|
||||
scummvmAssert(ilk("2.5 uhhh" + 5), #integer)
|
||||
put "sausages" into testString
|
||||
put (testString + 0) into testPointer
|
||||
scummvmAssertEqual(ilk(testPointer), #integer)
|
||||
scummvmAssertEqual(testString + 4, testPointer + 4)
|
||||
scummvmAssertEqual(testString - 4, testPointer - 4)
|
||||
scummvmAssertEqual(testString * 4, testPointer * 4)
|
||||
scummvmAssertEqual(testString / 4, testPointer / 4)
|
||||
-- same horrible logic should apply to symbols
|
||||
put #haggis into testString
|
||||
put (testString + 0) into testPointer
|
||||
scummvmAssertEqual(ilk(testPointer), #integer)
|
||||
scummvmAssertEqual(testString + 4, testPointer + 4)
|
||||
scummvmAssertEqual(testString - 4, testPointer - 4)
|
||||
scummvmAssertEqual(testString * 4, testPointer * 4)
|
||||
scummvmAssertEqual(testString / 4, testPointer / 4)
|
||||
|
||||
-- casting to integer
|
||||
scummvmAssertEqual(integer("2"), 2)
|
||||
scummvmAssertEqual(integer("-2"), -2)
|
||||
scummvmAssertEqual(integer(" 2"), 2)
|
||||
scummvmAssertEqual(integer("2.5"), VOID)
|
||||
scummvmAssertEqual(integer(" 2.5"), VOID)
|
||||
scummvmAssertEqual(integer("incorrect"), VOID)
|
||||
scummvmAssertEqual(integer("2 extra"), 2)
|
||||
scummvmAssertEqual(integer("2.5 extra"), VOID)
|
||||
scummvmAssertEqual(integer(" 2 extra"), 2)
|
||||
scummvmAssertEqual(integer(" 2.5 extra"), VOID)
|
||||
scummvmAssertEqual(integer("2extra"), VOID)
|
||||
scummvmAssertEqual(integer(" 2extra"), VOID)
|
||||
|
||||
-- casting to float
|
||||
scummvmAssertEqual(float("2"), 2.0)
|
||||
scummvmAssertEqual(float("-2"), -2.0)
|
||||
scummvmAssertEqual(float(" 2"), 2.0)
|
||||
scummvmAssertEqual(float("2.5"), 2.5)
|
||||
scummvmAssertEqual(float(" 2.5"), 2.5)
|
||||
scummvmAssertEqual(float("incorrect"), "incorrect")
|
||||
scummvmAssertEqual(float("2 extra"), "2 extra")
|
||||
scummvmAssertEqual(float("2.5 extra"), "2.5 extra")
|
||||
scummvmAssertEqual(float(" 2 extra"), " 2 extra")
|
||||
scummvmAssertEqual(float(" 2.5 extra"), " 2.5 extra")
|
||||
scummvmAssertEqual(float("2extra"), "2extra")
|
||||
scummvmAssertEqual(float(" 2extra"), " 2extra")
|
||||
|
||||
|
||||
-- LC::charOF
|
||||
set string to "Macromedia"
|
||||
set res to char 6 of string
|
||||
scummvmAssertEqual(res, "m")
|
||||
|
||||
-- error and bounds checks
|
||||
set res to char 60 of string
|
||||
scummvmAssertEqual(res, EMPTY)
|
||||
set res to char 0 of string
|
||||
scummvmAssertEqual(res, string)
|
||||
-- Test D4, it does a floor
|
||||
set res to char 5.49 of string
|
||||
scummvmAssertEqual(res, "o")
|
||||
set res to char 5.5 of string
|
||||
scummvmAssertEqual(res, "o")
|
||||
-- Test D3, it does a round
|
||||
set save to the scummvmVersion
|
||||
set the scummvmVersion to 300
|
||||
set res to char 5.49 of string
|
||||
scummvmAssertEqual(res, "o")
|
||||
set res to char 5.5 of string
|
||||
scummvmAssertEqual(res, "m")
|
||||
set the scummvmVersion to save
|
||||
|
||||
-- LC::charToOf
|
||||
set string to "Macromedia"
|
||||
set res to char 6 to 9 of string
|
||||
scummvmAssertEqual(res, "medi")
|
||||
|
||||
-- error and bounds checks
|
||||
set res to char 5.4 to 7.9 of string
|
||||
scummvmAssertEqual(res, "ome")
|
||||
|
||||
set res to char 6 to 5 of string
|
||||
scummvmAssertEqual(res, "")
|
||||
|
||||
set res to char 6 to 60 of string
|
||||
scummvmAssertEqual(res, "media")
|
||||
|
||||
set res to char -1 to -2 of string
|
||||
scummvmAssertEqual(res, string)
|
||||
|
||||
set res to char 50 to 60 of string
|
||||
scummvmAssertEqual(res, "")
|
||||
|
||||
-- LB::b_lastcharof
|
||||
scummvmAssertEqual(the last char of "", "")
|
||||
scummvmAssertEqual(the last char of "hello", "o")
|
||||
|
||||
-- LB::b_lastitemof
|
||||
scummvmAssertEqual(the last item of "", "")
|
||||
scummvmAssertEqual(the last item of "onetwo", "onetwo")
|
||||
scummvmAssertEqual(the last item of "one,two", "two")
|
||||
set save to the itemDelimiter
|
||||
set the itemDelimiter to ":"
|
||||
scummvmAssertEqual(the last item of "one:two", "two")
|
||||
set the itemDelimiter to save
|
||||
scummvmAssertEqual(the last item of "onetwo", "onetwo")
|
||||
|
||||
-- LB::b_offset
|
||||
set pos to offset("mov", "mov")
|
||||
scummvmAssertEqual(pos, 1)
|
||||
set pos to offset("mov", "C:\GAMES\OPEN.MOV")
|
||||
scummvmAssertEqual(pos, 15)
|
||||
9
engines/director/lingo/tests/tell.lingo
Normal file
9
engines/director/lingo/tests/tell.lingo
Normal file
@@ -0,0 +1,9 @@
|
||||
tell window "ball" to puppettempo 5
|
||||
|
||||
tell window "hello" to continue
|
||||
|
||||
tell window childMovie
|
||||
go to frame 50
|
||||
set the stageColor to 100
|
||||
updateStage
|
||||
end tell
|
||||
95
engines/director/lingo/tests/the.lingo
Normal file
95
engines/director/lingo/tests/the.lingo
Normal file
@@ -0,0 +1,95 @@
|
||||
put 1.0 / 3
|
||||
set the floatPrecision to 6
|
||||
put 1.0 / 3
|
||||
put the loch of sprite 4
|
||||
set the loch of sprite 5 to 10
|
||||
set the castnum of sprite 8 to the number of cast "A Blank Castmember"
|
||||
|
||||
put the time
|
||||
put the abbrev time
|
||||
put the long time
|
||||
|
||||
put the date
|
||||
put the short date
|
||||
put the abbrev date
|
||||
put the long date
|
||||
|
||||
set a = 5
|
||||
|
||||
set gravityConst = the value of ( QUOTE & the text of cast 1 & QUOTE )
|
||||
set the hilite of cast 1 to (a = 3)
|
||||
set the text of cast 1 = string( gravityConst )
|
||||
|
||||
-- This is object setting. D4+
|
||||
set BlastWindow to window "Media Blast"
|
||||
set the filename of BlastWindow to "blastwin"
|
||||
set the titleVisible of BlastWindow to true
|
||||
set the modal of BlastWindow to true
|
||||
set the windowtype of BlastWindow to 5
|
||||
|
||||
set the bottom of sprite 1 to originV + (the number of lines in someText) * 16
|
||||
set the bottom of sprite 1 to originV + (the number of words in someText) * 16
|
||||
|
||||
put the number of words of field 1 into field 2
|
||||
|
||||
set pSprite to 1
|
||||
set pChangeH to 10
|
||||
|
||||
set h = the locH of sprite pSprite + pChangeH
|
||||
|
||||
set the volume of sound 1 to 255
|
||||
put the volume of sound 1 into field 1
|
||||
|
||||
set the checkMark of menuItem "Horizontal" of menu "The Ball" to False
|
||||
|
||||
put the number of castMembers into field 2
|
||||
|
||||
put the number of menuItems of menu "sam" into field 2
|
||||
|
||||
put abs( the locH of sprite 2 - the mouseH) into field 2
|
||||
|
||||
set the castNum of sprite the clickon = the number of cast 1
|
||||
|
||||
-- set castname = the name of cast(the castnum of sprite 1)
|
||||
|
||||
set res = the soundBusy of 1
|
||||
|
||||
put the sqrt of 9
|
||||
|
||||
put 5 into field the number of cast "MasterList"
|
||||
|
||||
set the text of field 1 = "Hello"
|
||||
|
||||
-- The next statement is valid lingo, however it's hard to parse.
|
||||
-- We have no indication that this one off type of code is used.
|
||||
-- set the text of field 0 + 1 = "Hello"
|
||||
|
||||
set h to "Hello"
|
||||
|
||||
set gMarkerName = the length of h + 2
|
||||
|
||||
scummvmAssertEqual(0, the length of 123)
|
||||
|
||||
-- test the itemDelimiter
|
||||
set save = the itemDelimiter
|
||||
scummvmAssert(save=",")
|
||||
set the itemDelimiter = ":"
|
||||
scummvmAssert(the itemDelimiter=":")
|
||||
set the itemDelimiter = ":,"
|
||||
scummvmAssert(the itemDelimiter=":")
|
||||
set the itemDelimiter = ""
|
||||
scummvmAssert(the itemDelimiter="")
|
||||
set the itemDelimiter = save
|
||||
|
||||
-- test number of items
|
||||
set chunkExpr to "one:two:three"
|
||||
scummvmAssertEqual(the number of items in chunkExpr, 1)
|
||||
set the itemDelimiter to ":"
|
||||
scummvmAssertEqual(the number of items in chunkExpr, 3)
|
||||
set the itemDelimiter to save
|
||||
|
||||
-- test initialisation
|
||||
scummvmAssertEqual(the beepOn, 0)
|
||||
scummvmAssertEqual(the keyDownScript, "")
|
||||
scummvmAssertEqual(the mouseDownScript, "")
|
||||
scummvmAssertEqual(the mouseUpScript, "")
|
||||
10
engines/director/lingo/tests/trailingcomma.lingo
Normal file
10
engines/director/lingo/tests/trailingcomma.lingo
Normal file
@@ -0,0 +1,10 @@
|
||||
on test a, b, c,
|
||||
put a
|
||||
end
|
||||
|
||||
global foo, bar,
|
||||
property baz,
|
||||
|
||||
test "foo", "bar", "baz",
|
||||
|
||||
put sqrt(4,)
|
||||
25
engines/director/lingo/tests/value.lingo
Normal file
25
engines/director/lingo/tests/value.lingo
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
-- int
|
||||
scummvmAssertEqual(55, value("55"))
|
||||
-- float
|
||||
scummvmAssertEqual(5.55, value("5.55"))
|
||||
-- array
|
||||
scummvmAssertEqual([1, 2, 3], value("[1, 2, 3]"))
|
||||
-- parray
|
||||
scummvmAssertEqual([#a: 1, #b: 2], value("[#a: 1, #b: 2]"))
|
||||
|
||||
-- expressions
|
||||
scummvmAssertEqual(9, value("3*3"))
|
||||
|
||||
-- the kicker; you are allowed to have garbage on the end!!!
|
||||
-- if it hits a token it doesn't understand, the parser should try again but stopping just before that token.
|
||||
scummvmNoFatalError(true)
|
||||
|
||||
scummvmAssertEqual(9, value("3*3[34]"))
|
||||
scummvmAssertEqual([1, 2, 3], value("[1, 2, 3],4]"))
|
||||
|
||||
scummvmNoFatalError(false)
|
||||
|
||||
-- if there's no valid expression at all, return void
|
||||
set test = value("#")
|
||||
scummvmAssert(voidP(test))
|
||||
7
engines/director/lingo/tests/varnames.lingo
Normal file
7
engines/director/lingo/tests/varnames.lingo
Normal file
@@ -0,0 +1,7 @@
|
||||
set a.1 = 2
|
||||
set a1 = 3
|
||||
set a1. = 4
|
||||
|
||||
scummvmAssert(a.1=2)
|
||||
scummvmAssert(a1=3)
|
||||
scummvmAssert(a1.=4)
|
||||
120
engines/director/lingo/xlibs/a/aiff.cpp
Normal file
120
engines/director/lingo/xlibs/a/aiff.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* USED IN:
|
||||
* Gahan Wilson's Ultimate Haunted House
|
||||
*
|
||||
*************************************/
|
||||
|
||||
/*
|
||||
* -- copyright 1994 by Byron Priess Multimedia, authored by MayoSmith and Lee
|
||||
* aiff
|
||||
* I mNew --Read Docs to avoid Hard Drive failure
|
||||
* X mDispose --Disposes of XObject instance
|
||||
* S mName --Returns the XObject name (Widget)
|
||||
* I mStatus --Returns an integer status code
|
||||
* SI mError, code --Returns an error string
|
||||
* S mLastError --Returns last error string
|
||||
* III mAdd, arg1, arg2 --Returns arg1+arg2
|
||||
* SSI mFirst, str, nchars --Return the first nchars of string str
|
||||
* V mMul, f1, f2 --Returns f1*f2 as floating point
|
||||
* X mGlobals --Sample code to Read & Modify globals
|
||||
* X mSymbols --Sample code to work with Symbols
|
||||
* X mSendPerform --Sample code to show SendPerform call
|
||||
* X mFactory --Sample code to find Factory objects
|
||||
* IS mDuration, str --Read Docs to avoid Hard Drive failure
|
||||
*/
|
||||
|
||||
#include "common/macresman.h"
|
||||
#include "audio/decoders/aiff.h"
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/lingo/xlibs/a/aiff.h"
|
||||
|
||||
|
||||
namespace Director {
|
||||
|
||||
const char *const AiffXObj::xlibName = "aiff";
|
||||
const XlibFileDesc AiffXObj::fileNames[] = {
|
||||
{ "AIFF", nullptr },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
static const MethodProto xlibMethods[] = {
|
||||
{ "new", AiffXObj::m_new, 0, 0, 400 }, // D4
|
||||
{ "Duration", AiffXObj::m_duration, 1, 1, 400 }, // D4
|
||||
{ nullptr, nullptr, 0, 0, 0 }
|
||||
};
|
||||
|
||||
void AiffXObj::open(ObjectType type, const Common::Path &path) {
|
||||
if (type == kXObj) {
|
||||
AiffXObject::initMethods(xlibMethods);
|
||||
AiffXObject *xobj = new AiffXObject(kXObj);
|
||||
g_lingo->exposeXObject(xlibName, xobj);
|
||||
}
|
||||
}
|
||||
|
||||
void AiffXObj::close(ObjectType type) {
|
||||
if (type == kXObj) {
|
||||
AiffXObject::cleanupMethods();
|
||||
g_lingo->_globalvars[xlibName] = Datum();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AiffXObject::AiffXObject(ObjectType ObjectType) :Object<AiffXObject>("Aiff") {
|
||||
_objType = ObjectType;
|
||||
}
|
||||
|
||||
void AiffXObj::m_new(int nargs) {
|
||||
g_lingo->printSTUBWithArglist("AiffXObj::new", nargs);
|
||||
g_lingo->push(g_lingo->_state->me);
|
||||
}
|
||||
|
||||
void AiffXObj::m_duration(int nargs) {
|
||||
Common::String filePath = g_lingo->pop().asString();
|
||||
|
||||
Common::SeekableReadStream *aiffStream = Common::MacResManager::openFileOrDataFork(findPath(filePath));
|
||||
if (!aiffStream) {
|
||||
warning("AiffXObj::m_duration: Failed to open %s", filePath.c_str());
|
||||
g_lingo->push(0);
|
||||
return;
|
||||
}
|
||||
|
||||
Audio::AIFFHeader *aiffHeader = Audio::AIFFHeader::readAIFFHeader(aiffStream, DisposeAfterUse::NO);
|
||||
if (!aiffHeader) {
|
||||
warning("AiffXObj::m_duration: No AIFF header found for %s", filePath.c_str());
|
||||
g_lingo->push(0);
|
||||
delete aiffStream;
|
||||
return;
|
||||
}
|
||||
|
||||
int duration = (aiffHeader->getFrameCount() / (float)aiffHeader->getFrameRate()) * 60;
|
||||
|
||||
delete aiffHeader;
|
||||
delete aiffStream;
|
||||
g_lingo->push(Datum(duration));
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
49
engines/director/lingo/xlibs/a/aiff.h
Normal file
49
engines/director/lingo/xlibs/a/aiff.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DIRECTOR_LINGO_XLIBS_AIFF_H
|
||||
#define DIRECTOR_LINGO_XLIBS_AIFF_H
|
||||
|
||||
namespace Director {
|
||||
|
||||
class AiffXObject : public Object<AiffXObject> {
|
||||
public:
|
||||
AiffXObject(ObjectType objType);
|
||||
};
|
||||
|
||||
namespace AiffXObj {
|
||||
|
||||
extern const char *const xlibName;
|
||||
extern const XlibFileDesc fileNames[];
|
||||
|
||||
void open(ObjectType type, const Common::Path &path);
|
||||
void close(ObjectType type);
|
||||
|
||||
void m_new(int nargs);
|
||||
|
||||
void m_duration(int nargs);
|
||||
|
||||
} // End of namespace AiffXObj
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
321
engines/director/lingo/xlibs/a/applecdxobj.cpp
Normal file
321
engines/director/lingo/xlibs/a/applecdxobj.cpp
Normal file
@@ -0,0 +1,321 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* USED IN:
|
||||
* Classical Cats
|
||||
* The Daedalus Encounter
|
||||
* Refixion II
|
||||
*
|
||||
*************************************/
|
||||
|
||||
/*
|
||||
-! Category compactDisc
|
||||
* -! Title AppleCD SC
|
||||
* -! Protocol Ortho-Play 1.6.1
|
||||
* --© 1990,1991 MacroMind, Inc. Alan McNeil
|
||||
* ------------------------------------------------------
|
||||
* --AppleCD SC, version 2.5.6
|
||||
* --Mar 7 1994
|
||||
* --including AppleCD SC Plus volume control
|
||||
* ------------------------------------------------------
|
||||
* X mNew
|
||||
* X mDispose
|
||||
* --
|
||||
* I mGetMaxNodes
|
||||
* SI mGetNodeTitle NodeNum
|
||||
* II mSelectNode NodeNum
|
||||
* --
|
||||
* I mService
|
||||
* I mGetValue
|
||||
* I mCancel
|
||||
* S mExplain
|
||||
* I mIdle
|
||||
* --
|
||||
* X mReadStatus
|
||||
* X mReadPos
|
||||
* XI mSearchTo position
|
||||
* X mPlay
|
||||
* X mStill
|
||||
* X mStop
|
||||
* X mScanForward
|
||||
* X mScanReverse
|
||||
* X mEject
|
||||
* --
|
||||
* I mGetFirstTrack
|
||||
* I mGetLastTrack
|
||||
* II mGetFirstFrame tracknum
|
||||
* II mGetLastFrame tracknum
|
||||
* I mGetTrack
|
||||
* XII mAudioEnable number number
|
||||
* I mGetFrameResolution
|
||||
* --
|
||||
* II mSetInPoint frame
|
||||
* II mSetOutPoint frame
|
||||
* II mSetDuration frames
|
||||
* --
|
||||
* X mPlayCue
|
||||
* X mPlaySegment
|
||||
* --
|
||||
* S mTitle
|
||||
* SI mTrackName tracknum
|
||||
* IS mSetTitle string
|
||||
* IIS mSetTrackName tracknum string
|
||||
* II mGetTrackType tracknum
|
||||
* III mSetVolume leftVolume rightVolume
|
||||
* II mGetVolume leftFlag
|
||||
* --
|
||||
*/
|
||||
|
||||
#include "backends/audiocd/audiocd.h"
|
||||
#include "common/file.h"
|
||||
#include "common/formats/cue.h"
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/lingo/xlibs/a/applecdxobj.h"
|
||||
|
||||
|
||||
namespace Director {
|
||||
|
||||
const char *const AppleCDXObj::xlibName = "AppleCD";
|
||||
const XlibFileDesc AppleCDXObj::fileNames[] = {
|
||||
{ "AppleCD", nullptr },
|
||||
{ "AppleCD XObj", nullptr },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
static const MethodProto xlibMethods[] = {
|
||||
{ "new", AppleCDXObj::m_new, 0, 0, 300 }, // D3
|
||||
{ "dispose", AppleCDXObj::m_dispose, 0, 0, 300 }, // D3
|
||||
{ "Service", AppleCDXObj::m_service, 0, 0, 300 }, // D4
|
||||
{ "Still", AppleCDXObj::m_still, 0, 0, 300 }, // D3
|
||||
{ "ReadStatus", AppleCDXObj::m_readStatus, 0, 0, 300 }, // D3
|
||||
{ "GetValue", AppleCDXObj::m_getValue, 0, 0, 300 }, // D3
|
||||
{ "Eject", AppleCDXObj::m_eject, 0, 0, 300 }, // D3
|
||||
{ "GetFirstTrack", AppleCDXObj::m_getFirstTrack, 0, 0, 300 }, // D3
|
||||
{ "GetLastTrack", AppleCDXObj::m_getLastTrack, 0, 0, 300 }, // D3
|
||||
{ "GetFirstFrame", AppleCDXObj::m_getFirstFrame, 1, 1, 300 }, // D3
|
||||
{ "GetLastFrame", AppleCDXObj::m_getLastFrame, 1, 1, 300 }, // D3
|
||||
{ "SetInPoint", AppleCDXObj::m_setInPoint, 1, 1, 300 }, // D3
|
||||
{ "SetOutPoint", AppleCDXObj::m_setOutPoint, 1, 1, 300 }, // D3
|
||||
{ "PlayCue", AppleCDXObj::m_playCue, 0, 0, 300 }, // D3
|
||||
{ "PlaySegment", AppleCDXObj::m_playSegment, 0, 0, 300 }, // D3
|
||||
{ "ReadPos", AppleCDXObj::m_readPos, 0, 0, 300 }, // D3
|
||||
{ nullptr, nullptr, 0, 0, 0 }
|
||||
};
|
||||
|
||||
void AppleCDXObj::open(ObjectType type, const Common::Path &path) {
|
||||
if (type == kXObj) {
|
||||
AppleCDXObject::initMethods(xlibMethods);
|
||||
AppleCDXObject *xobj = new AppleCDXObject(kXObj);
|
||||
g_lingo->exposeXObject(xlibName, xobj);
|
||||
}
|
||||
}
|
||||
|
||||
void AppleCDXObj::close(ObjectType type) {
|
||||
if (type == kXObj) {
|
||||
AppleCDXObject::cleanupMethods();
|
||||
g_lingo->_globalvars[xlibName] = Datum();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AppleCDXObject::AppleCDXObject(ObjectType ObjectType) :Object<AppleCDXObject>("AppleCD") {
|
||||
_objType = ObjectType;
|
||||
_inpoint = 0;
|
||||
_outpoint = 0;
|
||||
|
||||
Common::File cuefile;
|
||||
if (cuefile.open("disc.cue")) {
|
||||
Common::String cuestring = cuefile.readString(0, cuefile.size());
|
||||
|
||||
_cue = Common::SharedPtr<Common::CueSheet>(new Common::CueSheet(cuestring.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_new(int nargs) {
|
||||
g_lingo->push(g_lingo->_state->me);
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_dispose(int nargs) {
|
||||
g_director->_system->getAudioCDManager()->stop();
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_still(int nargs) {
|
||||
g_director->_system->getAudioCDManager()->stop();
|
||||
}
|
||||
|
||||
// Not implemented yet; needs to be able to return appropriate values
|
||||
// for playing/paused.
|
||||
void AppleCDXObj::m_service(int nargs) {
|
||||
g_lingo->push(Datum(0));
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_readStatus(int nargs) {
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_getValue(int nargs) {
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
|
||||
g_lingo->push(Datum(me->_returnValue));
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_setInPoint(int nargs) {
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
|
||||
int inpoint = g_lingo->pop().asInt();
|
||||
debug(5, "AppleCDXObj::setInPoint: %i", inpoint);
|
||||
me->_inpoint = inpoint;
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_setOutPoint(int nargs) {
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
|
||||
int outpoint = g_lingo->pop().asInt();
|
||||
debug(5, "AppleCDXObj::setOutPoint: %i", outpoint);
|
||||
me->_outpoint = outpoint;
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_playCue(int nargs) {
|
||||
// Essentially a noop for us; this asks the drive to seek to that point,
|
||||
// then poll until it does. We don't have seek times, so we'll
|
||||
// simply noop.
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_playSegment(int nargs) {
|
||||
// Performs playback at the pre-specified absolute point on the disc,
|
||||
// using the values from setInPoint and setOutPoint
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
|
||||
g_director->_system->getAudioCDManager()->playAbsolute(me->_inpoint, -1, 0, 0);
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_readPos(int nargs) {
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
|
||||
AudioCDManager::Status status = g_director->_system->getAudioCDManager()->getStatus();
|
||||
if (me->_cue) {
|
||||
// ScummVM currently doesn't support specifying the exact frame, so we pretend we're at the first frame of the song
|
||||
Common::CueSheet::CueTrack *track = me->_cue->getTrack(status.track);
|
||||
if (track != nullptr) {
|
||||
me->_returnValue = track->indices[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_getFirstTrack(int nargs) {
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
|
||||
if (me->_cue) {
|
||||
Common::Array<Common::CueSheet::CueTrack> tracks = me->_cue->tracks();
|
||||
// If we have a set of tracks parsed, return the first track's number
|
||||
int index;
|
||||
if (tracks.size() >= 1) {
|
||||
index = tracks[0].number;
|
||||
} else {
|
||||
index = 1;
|
||||
}
|
||||
debug(5, "AppleCDXObj::m_getFirstTrack: returning %i", index);
|
||||
g_lingo->push(Datum(index));
|
||||
} else {
|
||||
// If we don't have a TOC, just assume the first track is 1
|
||||
debug(5, "AppleCDXObj::m_getFirstTrack: returning default");
|
||||
g_lingo->push(Datum(1));
|
||||
}
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_getLastTrack(int nargs) {
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
|
||||
if (me->_cue) {
|
||||
Common::Array<Common::CueSheet::CueTrack> tracks = me->_cue->tracks();
|
||||
// If we have a set of tracks parsed, return the final track's number
|
||||
int index;
|
||||
if (tracks.size() >= 1) {
|
||||
index = tracks.back().number;
|
||||
} else {
|
||||
index = 1;
|
||||
}
|
||||
debug(5, "AppleCDXObj::m_getLastTrack: returning %i", index);
|
||||
} else {
|
||||
// If we don't have a TOC, just assume the last track is 1
|
||||
debug(5, "AppleCDXObj::m_getLastTrack: returning default");
|
||||
g_lingo->push(Datum(1));
|
||||
}
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_getFirstFrame(int nargs) {
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
int trackNum = g_lingo->pop().asInt();
|
||||
|
||||
if (me->_cue) {
|
||||
Common::CueSheet::CueTrack *track = me->_cue->getTrack(trackNum);
|
||||
|
||||
// We use index 1 here because index 0 is typically the
|
||||
// pregap, and we don't want to describe the first sector of the
|
||||
// pregap as being the first sector of the track. Most discs
|
||||
// will have only two indices, and the second index is where the
|
||||
// actual track begins.
|
||||
int index = track->indices.size() > 1 ? track->indices[1] : track->indices[0];
|
||||
debug(5, "AppleCDXObj::m_getFirstFrame(%i): returning %i", trackNum, index);
|
||||
g_lingo->push(Datum(index));
|
||||
} else {
|
||||
// If we don't have a TOC, just provide a stub value
|
||||
debug(5, "AppleCDXObj::m_getFirstFrame(%i): returning default", trackNum);
|
||||
g_lingo->push(Datum(0));
|
||||
}
|
||||
}
|
||||
|
||||
// Currently calculated based on the start of the next track, since
|
||||
// cuesheets don't contain the duration of a song.
|
||||
void AppleCDXObj::m_getLastFrame(int nargs) {
|
||||
AppleCDXObject *me = static_cast<AppleCDXObject *>(g_lingo->_state->me.u.obj);
|
||||
int trackNum = g_lingo->pop().asInt();
|
||||
|
||||
if (me->_cue) {
|
||||
// We look for the pregap of the next track, if there is one.
|
||||
// TODO opening the actual audio track and getting its length
|
||||
// in sectors would produce a more accurate result for the final track
|
||||
Common::CueSheet::CueTrack *track = me->_cue->getTrack(trackNum + 1);
|
||||
int index;
|
||||
if (track) {
|
||||
// Don't use the pregap if there is no pregap
|
||||
index = track->indices[0] == -1 ? track->indices[1] : track->indices[0];
|
||||
} else {
|
||||
debug(5, "AppleCDXObj::m_getLastFrame(%i): no track at trackNum %i, setting index to 0", trackNum, trackNum + 1);
|
||||
index = 0;
|
||||
}
|
||||
debug(5, "AppleCDXObj::m_getLastFrame(%i): returning %i", trackNum, index);
|
||||
g_lingo->push(Datum(index));
|
||||
} else {
|
||||
// If we don't have a TOC, just provide a stub value
|
||||
debug(5, "AppleCDXObj::m_getLastFrame(%i): returning default", trackNum);
|
||||
g_lingo->push(Datum(0));
|
||||
}
|
||||
}
|
||||
|
||||
void AppleCDXObj::m_eject(int nargs) {
|
||||
debug(5, "AppleCDXObj::eject: Ejecting CD");
|
||||
}
|
||||
|
||||
} // End of namespace Director
|
||||
74
engines/director/lingo/xlibs/a/applecdxobj.h
Normal file
74
engines/director/lingo/xlibs/a/applecdxobj.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_XLIBS_APPLECDXOBJ_H
|
||||
#define DIRECTOR_LINGO_XLIBS_APPLECDXOBJ_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
|
||||
namespace Common {
|
||||
class CueSheet;
|
||||
}
|
||||
|
||||
namespace Director {
|
||||
|
||||
class AppleCDXObject : public Object<AppleCDXObject> {
|
||||
public:
|
||||
AppleCDXObject(ObjectType objType);
|
||||
int _inpoint;
|
||||
int _outpoint;
|
||||
// Instead of immediately returning values, methods which return
|
||||
// a value store it internally and return it via a subsequent
|
||||
// call to mGetValue.
|
||||
int _returnValue;
|
||||
Common::SharedPtr<Common::CueSheet> _cue;
|
||||
};
|
||||
|
||||
namespace AppleCDXObj {
|
||||
|
||||
extern const char *const xlibName;
|
||||
extern const XlibFileDesc fileNames[];
|
||||
|
||||
void open(ObjectType type, const Common::Path &path);
|
||||
void close(ObjectType type);
|
||||
|
||||
void m_new(int nargs);
|
||||
void m_dispose(int nargs);
|
||||
void m_still(int nargs);
|
||||
void m_service(int nargs);
|
||||
void m_readStatus(int nargs);
|
||||
void m_getValue(int nargs);
|
||||
void m_setInPoint(int nargs);
|
||||
void m_setOutPoint(int nargs);
|
||||
void m_playCue(int nargs);
|
||||
void m_playSegment(int nargs);
|
||||
void m_readPos(int nargs);
|
||||
void m_getFirstTrack(int nargs);
|
||||
void m_getLastTrack(int nargs);
|
||||
void m_getFirstFrame(int nargs);
|
||||
void m_getLastFrame(int nargs);
|
||||
void m_eject(int nargs);
|
||||
|
||||
} // End of namespace AppleCDXObj
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
140
engines/director/lingo/xlibs/a/askuser.cpp
Normal file
140
engines/director/lingo/xlibs/a/askuser.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
#include "director/types.h"
|
||||
#include "gui/message.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/lingo/xlibs/a/askuser.h"
|
||||
|
||||
namespace Director {
|
||||
|
||||
/**************************************************
|
||||
*
|
||||
* USED IN:
|
||||
* DEVO Presents: Adventures of the Smart Patrol
|
||||
*
|
||||
**************************************************/
|
||||
|
||||
/*
|
||||
* -- AskUser XObject. Copyright 1996 Inscape v1.0 24May96 BDL
|
||||
* AskUser
|
||||
* I mNew --Creates a new instance
|
||||
* X mDispose --Disposes XObject instance
|
||||
* SSSS mAsk --Data to display in the message box.
|
||||
*/
|
||||
|
||||
const char *const AskUser::xlibName = "AskUser";
|
||||
const XlibFileDesc AskUser::fileNames[] = {
|
||||
{ "AskUser", nullptr },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
static const MethodProto xlibMethods[] = {
|
||||
{ "new", AskUser::m_new, 0, 0, 400 }, // D4
|
||||
{ "ask", AskUser::m_ask, 3, 3, 400 }, // D4
|
||||
{ nullptr, nullptr, 0, 0, 0 }
|
||||
};
|
||||
|
||||
AskUserXObject::AskUserXObject(ObjectType ObjectType) :Object<AskUserXObject>("AskUser") {
|
||||
_objType = ObjectType;
|
||||
}
|
||||
|
||||
void AskUser::open(ObjectType type, const Common::Path &path) {
|
||||
if (type == kXObj) {
|
||||
AskUserXObject::initMethods(xlibMethods);
|
||||
AskUserXObject *xobj = new AskUserXObject(kXObj);
|
||||
g_lingo->exposeXObject(xlibName, xobj);
|
||||
}
|
||||
}
|
||||
|
||||
void AskUser::close(ObjectType type) {
|
||||
if (type == kXObj) {
|
||||
AskUserXObject::cleanupMethods();
|
||||
g_lingo->_globalvars[xlibName] = Datum();
|
||||
}
|
||||
}
|
||||
|
||||
void AskUser::m_new(int nargs) {
|
||||
g_lingo->printSTUBWithArglist("AskUser::m_new", nargs);
|
||||
g_lingo->dropStack(nargs);
|
||||
g_lingo->push(g_lingo->_state->me);
|
||||
}
|
||||
|
||||
void AskUser::m_ask(int nargs) {
|
||||
if (nargs != 3) {
|
||||
warning("AskUser::m_ask: expected 3 arguments");
|
||||
g_lingo->dropStack(nargs);
|
||||
g_lingo->push(Datum("Ok"));
|
||||
return;
|
||||
}
|
||||
Datum text = g_lingo->pop();
|
||||
Datum caption = g_lingo->pop(); // ScummVM doesn't have a title for message boxes, not used
|
||||
Datum mbType = g_lingo->pop();
|
||||
if (text.type != STRING) {
|
||||
warning("AskUser::m_ask: expected text to be a string, not %s", text.type2str());
|
||||
g_lingo->push(Datum("Ok"));
|
||||
return;
|
||||
}
|
||||
if (mbType.type != STRING) {
|
||||
warning("AskUser::m_ask: expected mbType to be a string, not %s", mbType.type2str());
|
||||
g_lingo->push(Datum("Ok"));
|
||||
return;
|
||||
}
|
||||
|
||||
Common::U32String defaultButton;
|
||||
Common::U32StringArray altButtons;
|
||||
|
||||
if (mbType.u.s->equals("YesNoCancel")) {
|
||||
defaultButton = Common::U32String("Yes");
|
||||
altButtons.push_back(Common::U32String("No"));
|
||||
altButtons.push_back(Common::U32String("Cancel"));
|
||||
} else if (mbType.u.s->equals("YesNo")) {
|
||||
defaultButton = Common::U32String("Yes");
|
||||
altButtons.push_back(Common::U32String("No"));
|
||||
} else if (mbType.u.s->equals("OkCancel")) {
|
||||
defaultButton = Common::U32String("OK");
|
||||
altButtons.push_back(Common::U32String("Cancel"));
|
||||
} else if (mbType.u.s->equals("Ok")) {
|
||||
defaultButton = Common::U32String("OK");
|
||||
} else {
|
||||
warning("AskUser::m_ask: unhandled mbType %s, falling back to Ok", mbType.u.s->c_str());
|
||||
defaultButton = Common::U32String("OK");
|
||||
}
|
||||
|
||||
g_director->_wm->clearHandlingWidgets();
|
||||
GUI::MessageDialog dialog(Common::U32String(text.u.s->c_str()), defaultButton, altButtons);
|
||||
int result = dialog.runModal();
|
||||
|
||||
if (result == GUI::kMessageOK) {
|
||||
g_lingo->push(Datum(Common::String(defaultButton)));
|
||||
} else if ((result >= GUI::kMessageAlt) && (result < GUI::kMessageAlt + (int)altButtons.size())) {
|
||||
g_lingo->push(Datum(Common::String(altButtons[result - GUI::kMessageAlt])));
|
||||
} else {
|
||||
warning("AskUser::m_ask: got unexpected dialog result of %d", result);
|
||||
g_lingo->push(Datum("Ok"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
48
engines/director/lingo/xlibs/a/askuser.h
Normal file
48
engines/director/lingo/xlibs/a/askuser.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_XLIBS_ASKUSER_H
|
||||
#define DIRECTOR_LINGO_XLIBS_ASKUSER_H
|
||||
|
||||
namespace Director {
|
||||
|
||||
class AskUserXObject : public Object<AskUserXObject> {
|
||||
public:
|
||||
AskUserXObject(ObjectType objType);
|
||||
};
|
||||
|
||||
namespace AskUser {
|
||||
|
||||
extern const char *const xlibName;
|
||||
extern const XlibFileDesc fileNames[];
|
||||
|
||||
void open(ObjectType type, const Common::Path &path);
|
||||
void close(ObjectType type);
|
||||
|
||||
void m_new(int nargs);
|
||||
void m_dispose(int nargs);
|
||||
void m_ask(int nargs);
|
||||
|
||||
} // End of namespace AskUser
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
125
engines/director/lingo/xlibs/b/backdrop.cpp
Normal file
125
engines/director/lingo/xlibs/b/backdrop.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/lingo/lingo-utils.h"
|
||||
#include "director/lingo/xlibs/b/backdrop.h"
|
||||
|
||||
/**************************************************
|
||||
*
|
||||
* USED IN:
|
||||
* A Trip To The Sky
|
||||
* Die Hexenakademie
|
||||
*
|
||||
**************************************************/
|
||||
|
||||
/*
|
||||
-- Backdrop XObject
|
||||
-- Draws a backdrop behind the Director stage
|
||||
-- Version 2.0.1, September 27, 1994
|
||||
-- ©1993-94 Electronic Ink
|
||||
I mNew
|
||||
X mDispose
|
||||
X mShow
|
||||
X mHide
|
||||
X mPaint
|
||||
V mSetColor, index [or] r,g,b
|
||||
V mSetBgColor, index [or] r,g,b
|
||||
V mSetPattern, patNum [or] patName
|
||||
XI mSetPPat, ppatID
|
||||
V mSetPicture, castPict [or] pictID [or] pictFile
|
||||
XI mHideInBack, trueOrFalse
|
||||
XI mHideMessages, trueOrFalse
|
||||
XS mRegister, serialNumber
|
||||
*/
|
||||
|
||||
namespace Director {
|
||||
|
||||
const char *const BackdropXObj::xlibName = "Backdrop";
|
||||
const XlibFileDesc BackdropXObj::fileNames[] = {
|
||||
{ "Backdrop", nullptr },
|
||||
{ "backdrop.obj", nullptr },
|
||||
{ "Backdrop XObj", nullptr },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
static const MethodProto xlibMethods[] = {
|
||||
{ "new", BackdropXObj::m_new, 0, 0, 400 },
|
||||
{ "dispose", BackdropXObj::m_dispose, 0, 0, 400 },
|
||||
{ "show", BackdropXObj::m_show, 0, 0, 400 },
|
||||
{ "hide", BackdropXObj::m_hide, 0, 0, 400 },
|
||||
{ "paint", BackdropXObj::m_paint, 0, 0, 400 },
|
||||
{ "setColor", BackdropXObj::m_setColor, 0, 0, 400 },
|
||||
{ "setBgColor", BackdropXObj::m_setBgColor, 0, 0, 400 },
|
||||
{ "setPattern", BackdropXObj::m_setPattern, 0, 0, 400 },
|
||||
{ "setPPat", BackdropXObj::m_setPPat, 1, 1, 400 },
|
||||
{ "setPicture", BackdropXObj::m_setPicture, 0, 0, 400 },
|
||||
{ "hideInBack", BackdropXObj::m_hideInBack, 1, 1, 400 },
|
||||
{ "hideMessages", BackdropXObj::m_hideMessages, 1, 1, 400 },
|
||||
{ "register", BackdropXObj::m_register, 1, 1, 400 },
|
||||
{ nullptr, nullptr, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const BuiltinProto xlibBuiltins[] = {
|
||||
{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
|
||||
};
|
||||
|
||||
BackdropXObject::BackdropXObject(ObjectType ObjectType) :Object<BackdropXObject>("Backdrop") {
|
||||
_objType = ObjectType;
|
||||
}
|
||||
|
||||
void BackdropXObj::open(ObjectType type, const Common::Path &path) {
|
||||
BackdropXObject::initMethods(xlibMethods);
|
||||
BackdropXObject *xobj = new BackdropXObject(type);
|
||||
g_lingo->exposeXObject(xlibName, xobj);
|
||||
g_lingo->initBuiltIns(xlibBuiltins);
|
||||
}
|
||||
|
||||
void BackdropXObj::close(ObjectType type) {
|
||||
BackdropXObject::cleanupMethods();
|
||||
g_lingo->_globalvars[xlibName] = Datum();
|
||||
|
||||
}
|
||||
|
||||
void BackdropXObj::m_new(int nargs) {
|
||||
g_lingo->printSTUBWithArglist("BackdropXObj::m_new", nargs);
|
||||
g_lingo->dropStack(nargs);
|
||||
g_lingo->push(g_lingo->_state->me);
|
||||
}
|
||||
|
||||
XOBJSTUBNR(BackdropXObj::m_dispose)
|
||||
XOBJSTUBNR(BackdropXObj::m_show)
|
||||
XOBJSTUBNR(BackdropXObj::m_hide)
|
||||
XOBJSTUBNR(BackdropXObj::m_paint)
|
||||
XOBJSTUB(BackdropXObj::m_setColor, 0)
|
||||
XOBJSTUB(BackdropXObj::m_setBgColor, 0)
|
||||
XOBJSTUB(BackdropXObj::m_setPattern, 0)
|
||||
XOBJSTUBNR(BackdropXObj::m_setPPat)
|
||||
XOBJSTUB(BackdropXObj::m_setPicture, 0)
|
||||
XOBJSTUBNR(BackdropXObj::m_hideInBack)
|
||||
XOBJSTUBNR(BackdropXObj::m_hideMessages)
|
||||
XOBJSTUBNR(BackdropXObj::m_register)
|
||||
|
||||
}
|
||||
58
engines/director/lingo/xlibs/b/backdrop.h
Normal file
58
engines/director/lingo/xlibs/b/backdrop.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_XLIBS_BACKDROP_H
|
||||
#define DIRECTOR_LINGO_XLIBS_BACKDROP_H
|
||||
|
||||
namespace Director {
|
||||
|
||||
class BackdropXObject : public Object<BackdropXObject> {
|
||||
public:
|
||||
BackdropXObject(ObjectType objType);
|
||||
};
|
||||
|
||||
namespace BackdropXObj {
|
||||
|
||||
extern const char *const xlibName;
|
||||
extern const XlibFileDesc fileNames[];
|
||||
|
||||
void open(ObjectType type, const Common::Path &path);
|
||||
void close(ObjectType type);
|
||||
|
||||
void m_new(int nargs);
|
||||
void m_dispose(int nargs);
|
||||
void m_show(int nargs);
|
||||
void m_hide(int nargs);
|
||||
void m_paint(int nargs);
|
||||
void m_setColor(int nargs);
|
||||
void m_setBgColor(int nargs);
|
||||
void m_setPattern(int nargs);
|
||||
void m_setPPat(int nargs);
|
||||
void m_setPicture(int nargs);
|
||||
void m_hideInBack(int nargs);
|
||||
void m_hideMessages(int nargs);
|
||||
void m_register(int nargs);
|
||||
|
||||
} // End of namespace BackdropXObj
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
90
engines/director/lingo/xlibs/b/barakeobj.cpp
Normal file
90
engines/director/lingo/xlibs/b/barakeobj.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* USED IN:
|
||||
* Angel Gate demo
|
||||
*
|
||||
*************************************/
|
||||
/*
|
||||
* -- Picter, a simple demo XObject, v1.0
|
||||
* I mNew
|
||||
* XIII mGpal, h, l, s
|
||||
* XIIIIII mLine, y1, y2, y3, y4, y5, c
|
||||
* II mGetDate, value
|
||||
* X mClear
|
||||
*/
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/lingo/lingo-utils.h"
|
||||
#include "director/lingo/xlibs/b/barakeobj.h"
|
||||
|
||||
|
||||
namespace Director {
|
||||
|
||||
const char *const BarakeObj::xlibName = "BarakeObj";
|
||||
const XlibFileDesc BarakeObj::fileNames[] = {
|
||||
{ "BarakeObj", nullptr },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
static const MethodProto xlibMethods[] = {
|
||||
{ "new", BarakeObj::m_new, 0, 0, 400 }, // D4
|
||||
{ "Clear", BarakeObj::m_clear, 0, 0, 400 }, // D4
|
||||
{ "Gpal", BarakeObj::m_gpal, 3, 3, 400 }, // D4
|
||||
{ "Line", BarakeObj::m_line, 6, 6, 400 }, // D4
|
||||
{ nullptr, nullptr, 0, 0, 0 }
|
||||
};
|
||||
|
||||
void BarakeObj::open(ObjectType type, const Common::Path &path) {
|
||||
if (type == kXObj) {
|
||||
BarakeObject::initMethods(xlibMethods);
|
||||
BarakeObject *xobj = new BarakeObject(kXObj);
|
||||
g_lingo->exposeXObject(xlibName, xobj);
|
||||
}
|
||||
}
|
||||
|
||||
void BarakeObj::close(ObjectType type) {
|
||||
if (type == kXObj) {
|
||||
BarakeObject::cleanupMethods();
|
||||
g_lingo->_globalvars[xlibName] = Datum();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BarakeObject::BarakeObject(ObjectType ObjectType) :Object<BarakeObject>("BarakeObj") {
|
||||
_objType = ObjectType;
|
||||
}
|
||||
|
||||
void BarakeObj::m_new(int nargs) {
|
||||
g_lingo->push(g_lingo->_state->me);
|
||||
}
|
||||
|
||||
void BarakeObj::m_clear(int nargs) {
|
||||
}
|
||||
|
||||
XOBJSTUBNR(BarakeObj::m_gpal)
|
||||
XOBJSTUBNR(BarakeObj::m_line)
|
||||
|
||||
} // End of namespace Director
|
||||
49
engines/director/lingo/xlibs/b/barakeobj.h
Normal file
49
engines/director/lingo/xlibs/b/barakeobj.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_XLIBS_BARAKEOBJ_H
|
||||
#define DIRECTOR_LINGO_XLIBS_BARAKEOBJ_H
|
||||
|
||||
namespace Director {
|
||||
|
||||
class BarakeObject : public Object<BarakeObject> {
|
||||
public:
|
||||
BarakeObject(ObjectType objType);
|
||||
};
|
||||
|
||||
namespace BarakeObj {
|
||||
|
||||
extern const char *const xlibName;
|
||||
extern const XlibFileDesc fileNames[];
|
||||
|
||||
void open(ObjectType type, const Common::Path &path);
|
||||
void close(ObjectType type);
|
||||
|
||||
void m_new(int nargs);
|
||||
void m_clear(int nargs);
|
||||
void m_gpal(int nargs);
|
||||
void m_line(int nargs);
|
||||
|
||||
} // End of namespace BarakeObj
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
281
engines/director/lingo/xlibs/b/batqt.cpp
Normal file
281
engines/director/lingo/xlibs/b/batqt.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* USED IN:
|
||||
* teamxtreme1-win
|
||||
* teamxtreme2-win
|
||||
*
|
||||
*************************************/
|
||||
|
||||
/*
|
||||
* -- BatQt quicktime factory. 9Aug94 RNB
|
||||
* BatQt
|
||||
* I mNew --Creates a new instance of the XObject
|
||||
* X mDispose --Disposes of XObject instance
|
||||
* S mName --Returns the XObject name
|
||||
* I mStatus --Returns an integer status code
|
||||
* SI mError, code --Returns an error string
|
||||
* S mLastError --Returns last error string
|
||||
* ISI mOpen --Opens the specified movie
|
||||
* IIIS mPlay --Play the movie, after setting parms
|
||||
* I mStop --Stop the movie
|
||||
* S mGetTimeRange --Gets the current time range
|
||||
* S mGetMovieBox --Gets the current bounds box of the movie
|
||||
* I mGetTime --Gets the current time of the movie
|
||||
* SI mSetTime --Sets the current time of the movie
|
||||
* SI mSetVolume --Sets the volume of the movie
|
||||
* I mLength --Gets the length of the movie
|
||||
* IIIII mSetMovieBox --Sets the bounding box of the movie
|
||||
* III mSetTimeRange -- Sets the active segment of the movie
|
||||
* II mAddCallback -- Adds a callback for the movie
|
||||
* II mRemoveCallback -- Removes a callback for the movie
|
||||
* I mResetCallbacks -- Resets the sent status of the callbacks
|
||||
* XS mSetBatch -- Applies a set of batch commands
|
||||
*/
|
||||
|
||||
#include "graphics/paletteman.h"
|
||||
#include "video/qt_decoder.h"
|
||||
#include "director/director.h"
|
||||
#include "director/util.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/lingo/lingo-utils.h"
|
||||
#include "director/lingo/xlibs/b/batqt.h"
|
||||
|
||||
|
||||
namespace Director {
|
||||
|
||||
// The name is different from the obj filename.
|
||||
const char *const BatQT::xlibName = "batQT";
|
||||
const XlibFileDesc BatQT::fileNames[] = {
|
||||
{ "batQT", nullptr },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
static const MethodProto xlibMethods[] = {
|
||||
{ "new", BatQT::m_new, 0, 0, 400 }, // D4
|
||||
{ "dispose", BatQT::m_dispose, 1, 1, 400 }, // D4
|
||||
{ "name", BatQT::m_name, 0, 0, 400 }, // D4
|
||||
{ "status", BatQT::m_status, 0, 0, 400 }, // D4
|
||||
{ "error", BatQT::m_error, 1, 1, 400 }, // D4
|
||||
{ "lastError", BatQT::m_lastError, 0, 0, 400 }, // D4
|
||||
{ "open", BatQT::m_open, 2, 2, 400 }, // D4
|
||||
{ "play", BatQT::m_play, 3, 3, 400 }, // D4
|
||||
{ "stop", BatQT::m_stop, 0, 0, 400 }, // D4
|
||||
{ "getTimeRange", BatQT::m_getTimeRange, 0, 0, 400 }, // D4
|
||||
{ "getMovieBox", BatQT::m_getMovieBox, 0, 0, 400 }, // D4
|
||||
{ "getTime", BatQT::m_getTime, 0, 0, 400 }, // D4
|
||||
{ "setTime", BatQT::m_setTime, 1, 1, 400 }, // D4
|
||||
{ "setVolume", BatQT::m_setVolume, 1, 1, 400 }, // D4
|
||||
{ "length", BatQT::m_length, 0, 0, 400 }, // D4
|
||||
{ "setMovieBox", BatQT::m_setMovieBox, 4, 4, 400 }, // D4
|
||||
{ "setTimeRange", BatQT::m_setTimeRange, 2, 2, 400 }, // D4
|
||||
{ "addCallback", BatQT::m_addCallback, 1, 1, 400 }, // D4
|
||||
{ "removeCallback", BatQT::m_removeCallback,1, 1, 400 }, // D4
|
||||
{ "resetCallbacks", BatQT::m_resetCallbacks,0, 0, 400 }, // D4
|
||||
{ "setBatch", BatQT::m_setBatch, 1, 1, 400 }, // D4
|
||||
{ nullptr, nullptr, 0, 0, 0 }
|
||||
};
|
||||
|
||||
void BatQT::open(ObjectType type, const Common::Path &path) {
|
||||
if (type == kXObj) {
|
||||
BatQTXObject::initMethods(xlibMethods);
|
||||
BatQTXObject *xobj = new BatQTXObject(kXObj);
|
||||
g_lingo->exposeXObject(xlibName, xobj);
|
||||
}
|
||||
}
|
||||
|
||||
void BatQT::close(ObjectType type) {
|
||||
if (type == kXObj) {
|
||||
BatQTXObject::cleanupMethods();
|
||||
g_lingo->_globalvars[xlibName] = Datum();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BatQTXObject::BatQTXObject(ObjectType ObjectType) : Object<BatQTXObject>("BatQt") {
|
||||
_objType = ObjectType;
|
||||
_video = nullptr;
|
||||
}
|
||||
|
||||
BatQTXObject::~BatQTXObject() {
|
||||
if (_video) {
|
||||
delete _video;
|
||||
_video = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BatQT::m_new(int nargs) {
|
||||
g_lingo->push(g_lingo->_state->me);
|
||||
}
|
||||
|
||||
void BatQT::m_dispose(int nargs) {
|
||||
debug(5, "BatQT::m_dispose");
|
||||
BatQTXObject *me = static_cast<BatQTXObject *>(g_lingo->_state->me.u.obj);
|
||||
if (me->_video) {
|
||||
delete me->_video;
|
||||
me->_video = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
XOBJSTUB(BatQT::m_name, "")
|
||||
XOBJSTUB(BatQT::m_status, 0)
|
||||
XOBJSTUB(BatQT::m_error, "")
|
||||
XOBJSTUB(BatQT::m_lastError, "")
|
||||
|
||||
void BatQT::m_open(int nargs) {
|
||||
ARGNUMCHECK(2);
|
||||
Datum unk = g_lingo->pop();
|
||||
Datum path = g_lingo->pop();
|
||||
TYPECHECK(path, STRING);
|
||||
BatQTXObject *me = static_cast<BatQTXObject *>(g_lingo->_state->me.u.obj);
|
||||
Common::Path normPath = findPath(path.asString());
|
||||
if (!normPath.empty()) {
|
||||
me->_video = new Video::QuickTimeDecoder();
|
||||
debugC(5, kDebugXObj, "BatQT::m_open: Loading QT file %s", normPath.toString().c_str());
|
||||
if (me->_video->loadFile(normPath)) {
|
||||
me->_movieBox = Common::Rect(me->_video->getWidth(), me->_video->getHeight());
|
||||
if (g_director->_pixelformat.bytesPerPixel == 1) {
|
||||
// Director supports playing back RGB and paletted video in 256 colour mode.
|
||||
// In both cases they are dithered to match the Director palette.
|
||||
me->_video->setDitheringPalette(g_director->getPalette());
|
||||
}
|
||||
} else {
|
||||
warning("BatQT::m_open: Could not load QT file %s", normPath.toString().c_str());
|
||||
}
|
||||
} else {
|
||||
warning("BatQT::m_open: Could not resolve path %s", path.asString().c_str());
|
||||
}
|
||||
g_lingo->push(0);
|
||||
}
|
||||
|
||||
void BatQT::m_play(int nargs) {
|
||||
ARGNUMCHECK(3);
|
||||
Datum unk3 = g_lingo->pop();
|
||||
Datum unk2 = g_lingo->pop();
|
||||
Datum unk1 = g_lingo->pop();
|
||||
TYPECHECK(unk1, INT);
|
||||
TYPECHECK(unk2, INT);
|
||||
TYPECHECK(unk3, STRING);
|
||||
BatQTXObject *me = static_cast<BatQTXObject *>(g_lingo->_state->me.u.obj);
|
||||
if (me->_video) {
|
||||
debugC(5, kDebugXObj, "BatQT::m_play: Starting playback");
|
||||
me->_video->start();
|
||||
} else {
|
||||
warning("BatQT::m_play: No video loaded");
|
||||
}
|
||||
g_lingo->push(0);
|
||||
}
|
||||
|
||||
void BatQT::m_stop(int nargs) {
|
||||
ARGNUMCHECK(0);
|
||||
BatQTXObject *me = static_cast<BatQTXObject *>(g_lingo->_state->me.u.obj);
|
||||
if (me->_video) {
|
||||
debugC(5, kDebugXObj, "BatQT::m_stop: Stopping playback");
|
||||
me->_video->stop();
|
||||
} else {
|
||||
warning("BatQT::m_stop: No video loaded");
|
||||
}
|
||||
g_lingo->push(0);
|
||||
}
|
||||
|
||||
XOBJSTUB(BatQT::m_getTimeRange, "")
|
||||
|
||||
void BatQT::m_getMovieBox(int nargs) {
|
||||
BatQTXObject *me = static_cast<BatQTXObject *>(g_lingo->_state->me.u.obj);
|
||||
Common::String result = Common::String::format(
|
||||
"%d,%d,%d,%d",
|
||||
me->_movieBox.left,
|
||||
me->_movieBox.top,
|
||||
me->_movieBox.width(),
|
||||
me->_movieBox.height()
|
||||
);
|
||||
debugC(5, kDebugXObj, "BatQT::m_getMovieBox: %s", result.c_str());
|
||||
g_lingo->push(result);
|
||||
}
|
||||
|
||||
void BatQT::m_getTime(int nargs) {
|
||||
ARGNUMCHECK(0);
|
||||
BatQTXObject *me = static_cast<BatQTXObject *>(g_lingo->_state->me.u.obj);
|
||||
Datum result(0);
|
||||
if (me->_video) {
|
||||
// Game uses a polling loop of m_getTime to measure progress,
|
||||
// therefore we need to render the frames in here
|
||||
if (me->_video->needsUpdate()) {
|
||||
const Graphics::Surface *frame = me->_video->decodeNextFrame();
|
||||
if (frame) {
|
||||
Graphics::Surface *temp = frame->scale(me->_movieBox.width(), me->_movieBox.height(), false);
|
||||
g_system->copyRectToScreen(temp->getPixels(), temp->pitch, me->_movieBox.left, me->_movieBox.top, temp->w, temp->h);
|
||||
g_system->updateScreen();
|
||||
delete temp;
|
||||
}
|
||||
}
|
||||
result = Datum(me->_video->getCurFrame() + 1);
|
||||
debugC(5, kDebugXObj, "BatQT::m_getTime: %d", result.asInt());
|
||||
} else {
|
||||
warning("BatQT::m_getTime: No video loaded");
|
||||
}
|
||||
g_lingo->push(result);
|
||||
}
|
||||
|
||||
XOBJSTUB(BatQT::m_setTime, "")
|
||||
XOBJSTUB(BatQT::m_setVolume, "")
|
||||
|
||||
void BatQT::m_length(int nargs) {
|
||||
ARGNUMCHECK(0);
|
||||
BatQTXObject *me = static_cast<BatQTXObject *>(g_lingo->_state->me.u.obj);
|
||||
Datum result(0);
|
||||
if (me->_video) {
|
||||
result = Datum((int)me->_video->getFrameCount());
|
||||
debugC(5, kDebugXObj, "BatQT::m_length: %d", result.asInt());
|
||||
}
|
||||
g_lingo->push(result);
|
||||
}
|
||||
|
||||
void BatQT::m_setMovieBox(int nargs) {
|
||||
ARGNUMCHECK(4);
|
||||
Datum h = g_lingo->pop();
|
||||
Datum w = g_lingo->pop();
|
||||
Datum y = g_lingo->pop();
|
||||
Datum x = g_lingo->pop();
|
||||
TYPECHECK(h, INT);
|
||||
TYPECHECK(w, INT);
|
||||
TYPECHECK(y, INT);
|
||||
TYPECHECK(x, INT);
|
||||
|
||||
BatQTXObject *me = static_cast<BatQTXObject *>(g_lingo->_state->me.u.obj);
|
||||
me->_movieBox.left = x.asInt();
|
||||
me->_movieBox.top = y.asInt();
|
||||
me->_movieBox.setWidth(w.asInt());
|
||||
me->_movieBox.setHeight(h.asInt());
|
||||
debugC(5, kDebugXObj, "BatQT::m_setMovieBox: %d,%d,%d,%d", me->_movieBox.left, me->_movieBox.top, me->_movieBox.width(), me->_movieBox.height());
|
||||
g_lingo->push(0);
|
||||
}
|
||||
|
||||
XOBJSTUB(BatQT::m_setTimeRange, 0)
|
||||
XOBJSTUB(BatQT::m_addCallback, 0)
|
||||
XOBJSTUB(BatQT::m_removeCallback, 0)
|
||||
XOBJSTUB(BatQT::m_resetCallbacks, 0)
|
||||
XOBJSTUBNR(BatQT::m_setBatch)
|
||||
|
||||
} // End of namespace Director
|
||||
76
engines/director/lingo/xlibs/b/batqt.h
Normal file
76
engines/director/lingo/xlibs/b/batqt.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIRECTOR_LINGO_XLIBS_BATQT_H
|
||||
#define DIRECTOR_LINGO_XLIBS_BATQT_H
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Video {
|
||||
class QuickTimeDecoder;
|
||||
}
|
||||
|
||||
namespace Director {
|
||||
|
||||
class BatQTXObject : public Object<BatQTXObject> {
|
||||
public:
|
||||
BatQTXObject(ObjectType objType);
|
||||
~BatQTXObject();
|
||||
|
||||
Video::QuickTimeDecoder *_video;
|
||||
Common::Rect _movieBox;
|
||||
};
|
||||
|
||||
namespace BatQT {
|
||||
|
||||
extern const char *const xlibName;
|
||||
extern const XlibFileDesc fileNames[];
|
||||
|
||||
void open(ObjectType type, const Common::Path &path);
|
||||
void close(ObjectType type);
|
||||
|
||||
void m_new(int nargs);
|
||||
void m_dispose(int nargs);
|
||||
void m_name(int nargs);
|
||||
void m_status(int nargs);
|
||||
void m_error(int nargs);
|
||||
void m_lastError(int nargs);
|
||||
void m_open(int nargs);
|
||||
void m_play(int nargs);
|
||||
void m_stop(int nargs);
|
||||
void m_getTimeRange(int nargs);
|
||||
void m_getMovieBox(int nargs);
|
||||
void m_getTime(int nargs);
|
||||
void m_setTime(int nargs);
|
||||
void m_setVolume(int nargs);
|
||||
void m_length(int nargs);
|
||||
void m_setMovieBox(int nargs);
|
||||
void m_setTimeRange(int nargs);
|
||||
void m_addCallback(int nargs);
|
||||
void m_removeCallback(int nargs);
|
||||
void m_resetCallbacks(int nargs);
|
||||
void m_setBatch(int nargs);
|
||||
|
||||
} // End of namespace BatQT
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
#endif
|
||||
97
engines/director/lingo/xlibs/b/bimxobj.cpp
Normal file
97
engines/director/lingo/xlibs/b/bimxobj.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-object.h"
|
||||
#include "director/lingo/lingo-utils.h"
|
||||
#include "director/lingo/xlibs/b/bimxobj.h"
|
||||
|
||||
/**************************************************
|
||||
*
|
||||
* USED IN:
|
||||
* Karma: Curse of the 12 Caves
|
||||
*
|
||||
**************************************************/
|
||||
|
||||
/*
|
||||
* -- BIM16 External Factory. 14JULY94
|
||||
* --BIM
|
||||
* I mNew --Creates a new instance of the XObject
|
||||
* ISII mPlay, FileName, x, y --Play Flc file
|
||||
* ISIII mPlayTo, FileName, x, y, frame --Play Flc file
|
||||
* ISIII mVideo, FileName, x, y, delay --Play Flc file
|
||||
* ISIIII mStretch, FileName, destx, desty, destw, desth --Play Flc file
|
||||
* I mDispose --Disposes of XObject instance
|
||||
*/
|
||||
|
||||
namespace Director {
|
||||
|
||||
const char *const BIMXObj::xlibName = "BIM";
|
||||
const XlibFileDesc BIMXObj::fileNames[] = {
|
||||
{ "FLC", nullptr },
|
||||
{ "BIM", nullptr },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
static const MethodProto xlibMethods[] = {
|
||||
{"new", BIMXObj::m_new, 0, 0, 400},
|
||||
{"play", BIMXObj::m_play, 3, 3, 400},
|
||||
{"playTo", BIMXObj::m_playTo, 4, 4, 400},
|
||||
{"video", BIMXObj::m_video, 4, 4, 400},
|
||||
{"stretch", BIMXObj::m_stretch, 5, 5, 400},
|
||||
{nullptr, nullptr, 0, 0, 0}
|
||||
};
|
||||
|
||||
static const BuiltinProto xlibBuiltins[] = {
|
||||
{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
|
||||
};
|
||||
|
||||
BIMXObject::BIMXObject(const ObjectType objType) :Object<BIMXObject>("BIM") {
|
||||
_objType = objType;
|
||||
}
|
||||
|
||||
void BIMXObj::open(ObjectType type, const Common::Path &path) {
|
||||
BIMXObject::initMethods(xlibMethods);
|
||||
BIMXObject *xobj = new BIMXObject(type);
|
||||
g_lingo->exposeXObject(xlibName, xobj);
|
||||
g_lingo->initBuiltIns(xlibBuiltins);
|
||||
}
|
||||
|
||||
void BIMXObj::close(ObjectType type) {
|
||||
BIMXObject::cleanupMethods();
|
||||
g_lingo->_globalvars[xlibName] = Datum();
|
||||
}
|
||||
|
||||
void BIMXObj::m_new(const int nargs) {
|
||||
g_lingo->printSTUBWithArglist("BIMXObj::m_new", nargs);
|
||||
g_lingo->dropStack(nargs);
|
||||
g_lingo->push(g_lingo->_state->me);
|
||||
}
|
||||
|
||||
XOBJSTUB(BIMXObj::m_play, 0)
|
||||
XOBJSTUB(BIMXObj::m_playTo, 0)
|
||||
XOBJSTUB(BIMXObj::m_video, 0)
|
||||
XOBJSTUB(BIMXObj::m_stretch, 0)
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user