Okay, here's a stab at how you need to modify your own game to support log/replay functionality. First, download the SCI_Logging demo game and put the LogEvent.sc script into your game /src directory. Then modify the following files accordingly.
------------------------------------------------------------------------
game.sh
------------------------------------------------------------------------
Add the following defines
(define LOGEVENT_SCRIPT 970)
// all the different possible log events
(define EVENT_LEFTCLICK 0)
(define EVENT_RIGHTCLICK 1)
(define EVENT_KEYMOVE 2)
(define EVENT_PARSEOPEN 3)
(define EVENT_CLOSEPRINT 4)
(define EVENT_OPENPRINT 5)
(define EVENT_GAMEKEY 6)
(define EVENT_GAMELEFTCLICK 7)
(define EVENT_GAMERIGHTCLICK 8)
(define EVENT_PARSECLOSE 9)
// the 3 log actions
(define NO_LOG 0)
(define SAVE_LOG 1)
(define REPLAY_LOG 2)
------------------------------------------------------------------------
Controls.sc
------------------------------------------------------------------------
Include the LogEvent script near the top:
(use "logevent")
Change your Dialog class doit() method to be this (changes highlighted):
(method (doit pItem)
(var hEvent, isClaimed, editControl)
= busy TRUE
= editControl FALSE
(self:eachElementDo(#init))
(if(theItem)
(send theItem:select(FALSE))
)
(if(paramTotal and pItem)
= theItem pItem
)(else
= theItem (self:firstTrue(#checkState TRUE))
)
(if(theItem)
(send theItem:select(TRUE))
)
= isClaimed FALSE
(while((not isClaimed))
(if (== gLogAction REPLAY_LOG)
// Queue up events until we get a parser close or close print event (should just be the next event in the log)
(if (<> gEventEvent EVENT_PARSECLOSE and <> gEventEvent EVENT_CLOSEPRINT)
= gEventClaimed TRUE
QueueEvent()
)
// wait until we should close this window
(if (>= GetTime() gEventTicks)
// it's been closed, get out of the loop
= isClaimed TRUE
break
)
)
(self:eachElementDo(#cycle))
= hEvent (Event:new())
GlobalToLocal(hEvent)
= isClaimed (self:handleEvent(hEvent))
(send hEvent:dispose())
(self:check)
(if( (== isClaimed -1) or (not busy) )
= isClaimed FALSE
= editControl TRUE
EditControl(theItem 0)
break
)
Wait(1)
)
= busy FALSE
// Log the close print event, as long as this is not an EditPrint window
(if (== gLogAction SAVE_LOG and == editControl TRUE)
LogEvent(hEvent "closePrint" )
)
return(isClaimed)
)
Make the Dialog class dispose method look like this:
(method (dispose)
(if(== self gPrintDlg)
SetPort(gOldPort)
= gPrintDlg NULL
= gOldPort NULL
)
(if(window)
(send window:dispose())
)
= window NULL
= theItem NULL
(super:dispose())
// When the print window is destroyed, load up the next event
(if (== gLogAction REPLAY_LOG)
= gEventClaimed TRUE
QueueEvent()
)
)
Add this code before the send to hDText in the Print() procedure
// Logs when either the parser window is opened or a print dialog is opened
(if (== gLogAction SAVE_LOG)
(= dummyEvent Event:new())
(if(== STRINGS_EQUAL StrCmp(@msgBuf "Enter Input:"))
LogEvent(dummyEvent "parseOpen" @msgBuf)
)(else
LogEvent(dummyEvent "openPrint" @msgBuf)
)
)
(send hDText:
text(@msgBuf)
moveTo(4 4)
font(gDefaultFont)
setSize()
)
Further down in the Print() procedure, before the open call:
// Queue up the next event (which should be a CLOSEPRINT event)
(if (== gLogAction REPLAY_LOG and == gEventEvent EVENT_OPENPRINT)
= gEventClaimed TRUE
QueueEvent()
)
(send hDialog:open(moveToX moveToY))
------------------------------------------------------------------------
User.sc
------------------------------------------------------------------------
Again, include the LogEvent script
(use "logevent")
Change the getinput method to look like this:
(method (getInput pEvent)
(var prevSound, strLen)
(if(<> (send pEvent:type) evKEYBOARD)
= inputStr 0
)
// this allows for replaying the typed text into the input window
(if (== gEventEvent EVENT_PARSEOPEN and == gLogAction REPLAY_LOG)
= gEventClaimed TRUE
QueueEvent() // parser close
StrCpy(@inputStr @gEventMsg)
(send pEvent:message(@gEventMsg)) // set the input in input box (from parser close event)
)(else
(if(<> (send pEvent:message) echo)
Format(@inputStr "%c" (send pEvent:message))
)
)
= prevSound (Sound:pause(blocks))
= strLen EditPrint(@inputStr maxInputLen prompt #at x y)
(Sound:pause(prevSound))
return(strLen)
)
And the handleEvent method:
(method (handleEvent pEvent)
(var evType, origKey)
(if(send pEvent:type)
= gUserEvent pEvent
= evType (send pEvent:type)
= origKey (send pEvent:message) // get the original key input, prior to it being manipulated in mapKeyToDir
(if(mapKeyToDir)
MapKeyToDir(pEvent)
)
(if(TheMenuBar)
(TheMenuBar:handleEvent(pEvent evType))
)
GlobalToLocal(pEvent)
(if(not (send pEvent:claimed))
(send gGame:handleEvent(pEvent evType))
)
(if(controls and (not (send pEvent:claimed))
and (send gCast:contains(alterEgo)))
(send alterEgo:handleEvent(pEvent))
)
// logs ego events (mouse clicks and keyboard movements
(if((send pEvent:claimed) and == gLogAction SAVE_LOG)
(send pEvent:message(origKey))
LogEvent(pEvent "ego")
)
(if(canInput and not(send pEvent:claimed))
(if( (== (send pEvent:message) echo) or (<= $20 (send pEvent:message)) and (<= (send pEvent:message) 255))
(if( (self:getInput(pEvent)))
// logs the closing of the parser
(if (== gLogAction SAVE_LOG)
LogEvent(pEvent "parseClose" @inputStr)
)
(if(Parse(@inputStr pEvent))
(send pEvent:type(evSAID))
(self:said(pEvent))
)
)
)
)
// for handling the titlescreen events
(if (== canInput FALSE and not(send pEvent:claimed) and == gLogAction SAVE_LOG)
LogEvent(pEvent "game")
)
)
= gUserEvent NULL
)
------------------------------------------------------------------------
Main.sc
------------------------------------------------------------------------
Include logevent again:
(use "logevent")
Add these local variables:
// Logging variables
gLogLineSize = 116
gLogAction = NO_LOG
gLogFileName[50]
gEventTicks
gEventEvent
gEventX
gEventY
gEventKey
gEventMsg[51]
gLogFileHandle
gEventClaimed = TRUE
At the bottom of the init() method in the Game instance, add ONE of the following code blocks,
depending whether you want to log events or replay a log file:
// for logging events
= gLogAction SAVE_LOG
Format(@gLogFileName "logs\\log%d" Abs(GetTime(gtTIME_OF_DAY)))
= gLogFileHandle FOpen(@gLogFileName fOPENFAIL)
// for replaying events
= gLogAction REPLAY_LOG
StrCpy(@gLogFileName "logs\\LOG19736") // change this to the log file of your choice
= gLogFileHandle FOpen(@gLogFileName fOPENCREATE)
= gEventEvent -1
= gEventTicks -1
At the bottom of the doit() in your Game instance, add this:
// enables replaying of the log
(if (== gLogAction REPLAY_LOG)
ReplayLog()
)