;rcharsav.sc   Quest for Glory...save character stats.

(script# rCharSave) ;840

(public
   CharSave    0
)

;; Bits in svMiscEquip
(define  FINESWORD_BIT  $0001) ; fine sword
(define  FLAMESWORD_BIT $0002) ; flaming sword
(define  COMPASS_BIT    $0003) ; compass
(define  PIN_BIT        $0004) ; spahire pin
(define  LAMP_BIT       $0008) ; brass lamp
(define  TOKEN_BIT      $0010) ; EOF token
(define  GLASSES_BIT    $0020) ; X-Ray Glasses

; things transferred from "Quest for Glory 1"
(define  BABA_BIT       $0030) ; Flag set from QG1
(define  SWORD_BIT      $0040) ; Sword
(define  CHAIN_BIT      $0080) ;
(define  PICK_BIT       $0100) ;
(define  TOOL_BIT       $0200) ;

(define  EXTRA_DATA  18)   ; Data items other than stats and name
(define  CHECK_DATA  10)   ; Data items that are in check sums

(define textWidth 220)

(local
;; local data for saving hero stats for next game
                         ;;;;;;;;;;;;;;;;;;start;;;;;;;;;;;;;;;;;;
   statsKey = $53        ;;;;;;;;order dependent variables;;;;;;;;
   svCharType            ;;;;;;;;order dependent variables;;;;;;;;
;**   svExperience          ;;;;;;;;order dependent variables;;;;;;;;
   svHighDinar           ;;;;;;;;order dependent variables;;;;;;;;
   svLowDinar            ;;;;;;;;order dependent variables;;;;;;;;
   svScore               ;;;;;;;;order dependent variables;;;;;;;;
   svMiscEquip           ;;;;;;;;order dependent variables;;;;;;;;
   [codedStats NUM_ATTRIBS] ;;;;;;;;order dependent variables;;;;;;;;
   svDaggers             ;;;;;;;;order dependent variables;;;;;;;;
   svHealingPill         ;;;;;;;;order dependent variables;;;;;;;;
   svManaPill            ;;;;;;;;order dependent variables;;;;;;;;
   svStaminaPill         ;;;;;;;;order dependent variables;;;;;;;;
   svPoisonCurePill      ;;;;;;;;order dependent variables;;;;;;;;   
   bogus0   = $a0        ;;;;;;;;order dependent variables;;;;;;;;
   bogus1   = $3e        ;;;;;;;;order dependent variables;;;;;;;;
   checkSum1             ;;;;;;;;order dependent variables;;;;;;;;
   checkSum2             ;;;;;;;;order dependent variables;;;;;;;;
   bogus2   = $2f        ;;;;;;;;order dependent variables;;;;;;;;
   bogus3   = $90        ;;;;;;;;order dependent variables;;;;;;;;
   bogus4   = $19        ;;;;;;;;order dependent variables;;;;;;;;
   bogus5   = $a3        ;;;;;;;;order dependent variables;;;;;;;;
   checkSumKey = $da     ;;;;;;;;order dependent variables;;;;;;;;
                         ;;;;;;;;;;;;;;;;;;;end;;;;;;;;;;;;;;;;;;;
   check1
   check2
   [YNSTR 5]
   [yesOrNo 5]
   [heroFileName 44]
   [bigStr 400]
   hasSaved              ;TRUE if hero saved
   [str 40]
   answer
)

(enum          ;states of saveHero Script
   congrats
   playItAgain
   askSave
   getInfoFileName
   checkFile
   openFile
   writeHeroInfo
   writeComplete
   writeComplete2
   tryAgain
   saveDone
   checkSong
   redrawRoom
   goToCredits
)


(instance CharSave of Room
   (properties
      picture  pCredits1
      horizon  0
      style    IRISOUT
   )
   
   (method (dispose)
      (StatusLine code: dftStatusCode)
      (keyDownHandler delete: self)
      (super dispose:)
   )

   (method (init)
      (StatusLine
         code: endStatus,
         enable:
      )
      (keyDownHandler add: self)
      (super init: &rest)

      (customWindow
         back: vBLACK,
         color: vWHITE,
      )

      (songObj init:, hide:)
      (addToPics 
         add: frame1 frame2 frame3 frame4 frame5 frame6 frame7 frame8,
         eachElementDo: #init:,
         doit:
      )

      (cSound
         number: sStars,
         loop: -1,
         priority: 5,
         play:
      )

      ; don't let'm control anything!
      (User canControl: FALSE, canInput: FALSE)

      (self setScript: saveHero)
      (songObj setScript: songScript)
   )

)
(instance heroinfo of File
   (properties
      name  {glory2.sav}
   )
)

(instance saveHero of Script

   (method (handleEvent event)
      (if
         (and
            (== (event type?) keyDown)
            (== (event message?) ENTER)
         )
         (if register
            (= register 0)
            (= cycles 1) 
            (event claimed: TRUE)
         )
      )
   )
   (method (changeState newState &tmp whichSkill oldDinar
                                 lineEndString oldExper retry)
      (switch (= state newState)
         (congrats
            (Format @heroFileName "a:glory2.sav")
            (if (>= score possibleScore)
               (Format @bigStr "CONGRATULATIONS!!\n
                     You have successfully completed\n
                     \"Quest for Glory II:__Trial by Fire\"\n
                     with the maximum possible score, %d of %d!!\n
                     We welcome you to the ranks of the few, the proud,
                     the True Heroes!"
                  possibleScore possibleScore
               )
               (Print @bigStr
                  #window: customWindow
                  #mode: teJustCenter
                  #width: textWidth
                  #dispose:
               )
            else
               (Print (Format @bigStr "Congratulations!__You have
                        successfully completed\n
                        \"Quest for Glory II:__Trial by Fire.\"\n
                        Your final score was %d of %d possible Puzzle Points."
                        score possibleScore
                     )
                  #window: customWindow
                  #mode: teJustCenter
                  #width: textWidth
                  #dispose:
               )
            )
            (= register 1)
         )
         (playItAgain
            (Print "If you have not already done so,\n
                  we encourage you to play\n
                  \"Quest for Glory II\"\n
                  again with the other two character types; many of the
                  puzzles are different, or have alternate solutions."
                  #window: customWindow
                  #mode: teJustCenter
                  #width: textWidth
                  #dispose:
            )
            (= register 1)
         )
         (askSave
            (Print "In the meantime,\n you are already a winner!
                  Please insert a writable disk in your floppy drive to
                  save your winning Hero for use in\n
                  \"Quest for Glory III:\n
                  _Shadows of Darkness.\""
                  #window: customWindow
                  #mode: teJustCenter
                  #width: textWidth
                  #dispose:
            )
            (= register 1)
         )

         (getInfoFileName      ; actually gets file name to save it as.
            (cls)
;**            (if (GetInput @heroFileName 30
;**                     {Disk file in which to save your Hero.})
            (if 
               (Print 
                  "Disk file in which to save your Hero."
                  #window: customWindow
                  #mode: teJustCenter
                  #edit: @heroFileName 30
               )
               (heroinfo name: @heroFileName)
               (= cycles 2)
            else
               (self changeState: tryAgain)
            )
         )

         (checkFile      ; checks if file already exists. and warns user
            (= answer 0)
            (if (!= (heroinfo open: fRead) NULL)
               (repeat 
                  (= answer 
                     (Print
                        "File already exists.__Do 
                        you wish to overwrite?"
                        #title: {_WARNING!_}
                        #mode: teJustCenter
                        #window: Warning
                        #button: {_NO_}   1
                        #button: {_YES_}  2
                     )
                  )
                  (if answer
                     (break)
                  )
               )
               (switch answer
                  (1 (self changeState: getInfoFileName))
                  (2 (= cycles 1))
               )
            else
               (= cycles 1)
            )
         )

         (openFile
            (if (heroinfo open: fTrunc)
               (heroinfo close:)
               (= seconds 2)
            else
               (Print (Format @bigStr "Could not create file -- %s."
                     (heroinfo name?))
                  #window: Warning
                  #mode: teJustCenter
                  #width: textWidth
               )
               (self changeState: tryAgain)
            )
         )               

         (writeHeroInfo
            (if (not (heroinfo open: fAppend))
               (self  changeState: tryAgain)
               (return)
            )
            ; it's always nice to know what the computer is doing
            (Print "Saving Character"
               #window: customWindow
               #mode: teJustCenter
               #dispose:
            )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

            ; puts all ego stats in array (called codedStats) to save
            (for  ((= whichSkill 0))
                  (< whichSkill NUM_ATTRIBS)
                  ((++ whichSkill))
;**               (Printf "egoStat # %d = %d" whichSkill [egoStats whichSkill])
               (= [codedStats whichSkill] [egoStats whichSkill])
            )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  order dependant variables
            (= oldDinar [invNum iDinar])
            (= svCharType heroType)
;**            (= svExperience ( / [egoStats EXPER] 100))
            (= svHighDinar ( / oldDinar 100))
            (= svLowDinar  (mod oldDinar 100))
            (= svScore score)
            (= svMiscEquip 0)
            (if (ego has: iFineSword)     (|= svMiscEquip FINESWORD_BIT))
            (if (ego has: iSoulforge)     (|= svMiscEquip FLAMESWORD_BIT))
            (if (ego has: iCompass)       (|= svMiscEquip COMPASS_BIT))
            (if (ego has: iSapphPin)      (|= svMiscEquip PIN_BIT))
            (if (ego has: iBrassLamp)     (|= svMiscEquip LAMP_BIT))
            (if (ego has: iEOFToken)      (|= svMiscEquip TOKEN_BIT))
            (if (ego has: iGlasses)       (|= svMiscEquip GLASSES_BIT))
            (if (Btst fBabaFrog)          (|= svMiscEquip BABA_BIT))
            (if (ego has: iSword)         (|= svMiscEquip SWORD_BIT))
            (if (ego has: iChainMail)     (|= svMiscEquip CHAIN_BIT))
            (if (ego has: iLockPick)      (|= svMiscEquip PICK_BIT))
            (if (ego has: iThiefKit)      (|= svMiscEquip TOOL_BIT))

            (= svDaggers         [invNum iDagger])
            (= svHealingPill     [invNum iHealingPill])
            (= svManaPill        [invNum iManaPill])
            (= svStaminaPill     [invNum iStaminaPill])
            (= svPoisonCurePill  [invNum iPoisonCure])

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (= check1 checkSumKey)
            (for  ((= whichSkill 0))
                  (< whichSkill (+ NUM_ATTRIBS CHECK_DATA))
                  ((+= whichSkill 2))
               (= [statsKey (+ whichSkill 1)] (& [statsKey (+ whichSkill 1)] 255))
               (+= check1 [statsKey (+ whichSkill 1)])
            )

            (= check2 0)
            (for  ((= whichSkill 1))
                  (< whichSkill (+ NUM_ATTRIBS CHECK_DATA))
                  ((+= whichSkill 2))
               (= [statsKey (+ whichSkill 1)] (& [statsKey (+ whichSkill 1)] 255))
               (+= check2 [statsKey (+ whichSkill 1)])
            )

            (&= check1 255)
            (&= check2 255)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (= checkSum1 check1)
            (= checkSum2 check2)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            ; exclusive-OR all stats into one number
            (for  ((= whichSkill 0))
                  (< whichSkill (+ NUM_ATTRIBS EXTRA_DATA))
                  ((++ whichSkill))
               (= [statsKey (+ whichSkill 1)] (& [statsKey (+ whichSkill 1)] 255))
               (^= [statsKey (+ whichSkill 1)] [statsKey whichSkill])
            )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (= lineEndString {*})      ; Kludge for null string
            (StrAt lineEndString 0 `^J)

            ; multiple strings can be sent at once
            (heroinfo writeString: @userName lineEndString)

            (for  ((= whichSkill 1))
                  ( < whichSkill (+ NUM_ATTRIBS EXTRA_DATA 1))
                  ((++ whichSkill))
               (Format @bigStr "%2x" [statsKey whichSkill])
               (heroinfo writeString: @bigStr)
            )
            (heroinfo writeString: lineEndString)
            (heroinfo close:)
            (= seconds 2)
         )

         (writeComplete
            (if modelessDialog
               (modelessDialog dispose:)
            )
            (Print "The save character file has been created.__Save
                  this disk for use with \"Quest for Glory III:__Shadows of Darkness\"
                  from Sierra On-Line."
                  #window: customWindow
                  #width: textWidth
                  #mode: teJustCenter
                  #dispose:
            )
            (= register 1)
         )
         (writeComplete2
            (= hasSaved TRUE)
            (self changeState: saveDone)
;**            (= cycles 2)
         )

         (tryAgain
            (repeat
               (if
                  (= retry
                     (Print 
                        "Do you wish to try saving
                        your character again?"
                        #button: {_No_}   1
                        #button: {_Yes_}  2
                        #window: customWindow
                        #mode:   teJustCenter
                     )
                  )
                  (switch retry
                     (1 (= retry saveDone) (break))
                     (2 
                        (= retry getInfoFileName) 
                        (= bogus0 $79)
                        (= bogus1 $86)
                        (= bogus2 $43) 
                        (= bogus3 $88) 
                        (= bogus4 $ad) 
                        (= bogus5 $f0) 
                        (break)
                     )
                  )
               )
            )
            (self changeState: retry)
         )
;**            (if (GetInput @YNSTR 2
;**                     {If you wish to try saving your character again,
;**                        type \"y\", then ENTER.__Otherwise type \"n\",
;**                        then ENTER.}
;**                  )
;**               (if (StrCmp @YNSTR {y})
;**                  (self changeState: saveDone)
;**               else
;**                  (= bogus0 $79)
;**                  (= bogus1 $86)
;**                  (= bogus2 $43) 
;**                  (= bogus3 $88) 
;**                  (= bogus4 $ad) 
;**                  (= bogus5 $f0) 
;**                  (self changeState: getInfoFileName)
;**               )
;**            else
;**               (= cycles 2)
;**            )

;**         (badAnswer
;**            (Print "Please answer \"y\" or \"n\"."
;**                  #window: Warning
;**                  #mode: teJustCenter
;**            )
;**            (self  changeState: tryAgain)
;**         )

         (saveDone
            (Print "Thank you for playing\n 
                  \"Quest for Glory II:__Trial by Fire,\"\n
                  and congratulations again on winning.__We'll see you again soon in\n
                  \"Quest for Glory III:\n
                  Shadows of Darkness.\""
                  #window: customWindow
                  #width: textWidth
                  #mode: teJustCenter
            )
            (= seconds 4)
         )
         (checkSong
            (if (== (miscSound number?) sMoon1)
               (= cycles 1)
            else
               (self setScript: waitForSong self)
            )
         )
         (redrawRoom
            (curRoom drawPic: pCredits1 IRISOUT)
            (= cycles 1)
         )
         (goToCredits
            (curRoom newRoom: rClosingCredits)
         )
      )
   )
)

(instance endStatus of Code
   (method (doit strg)
      (if (== heroType PALADIN)
         (Format strg "____Congratulations, Paladin!__[score %d of %d]"
               score possibleScore)
      else
         (Format strg "_______Hero of Two Lands!__[score %d of %d]"
               score possibleScore)
      )
   )
)

(instance frame1 of PicView
   (properties
      view        242
      loop        0
      cel         0
      x           81
      y           33
   )
)

(instance frame2 of PicView
   (properties
      view        242
      loop        1
      cel         0
      x           239
      y           33
   )
)

(instance frame3 of PicView
   (properties
      view        242
      loop        0
      cel         1
      x           19
      y           94
   )
)

(instance frame4 of PicView
   (properties
      view        242
      loop        0
      cel         2
      x           20
      y           156
   )
)

(instance frame5 of PicView
   (properties
      view        242
      loop        0
      cel         3
      x           81
      y           189
   )
)

(instance frame6 of PicView
   (properties
      view        242
      loop        1
      cel         3
      x           238
      y           189
   )
)

(instance frame7 of PicView
   (properties
      view        242
      loop        1
      cel         2
      x           300
      y           156
   )
)

(instance frame8 of PicView
   (properties
      view        242
      loop        1
      cel         1
      x           301
      y           94
   )
)
(instance Warning of SysWindow
   (properties
      back: vRED
      color: vYELLOW
   )
)

(instance songObj of Prop)

(instance songScript of Script
   (method (changeState newState)
      (switchto (= state newState)
         (
            (= seconds 8)
         )
         (
            (spareSound
               number: sLowDrone,
               priority: 10,
               loop: -1,
               play:
            )
            (= seconds 8)
         )
         (
            (if (== (saveHero script?) waitForSong)
               (waitForSong cue:)
            else
               (waitForSong start: 1)
            )
            (miscSound
               number: sMoon1,
               loop: -1,
               priority: 11,
               play:
            )
            (= cycles 1)
         )
         ((self dispose:))
      )
   )
)

(instance waitForSong of Script
   (method (changeState newState)
      (switch (= state newState)
         (0 0)
         (1 (self dispose:))
      )
   )
)

