;charsave.sc   Hero's Quest...save character stats.

(script# CHARSAVE)

(public
   CharSave    0
)

;; Bits in svMiscEquip
(define  SWORD_BIT   1)
(define  CHAIN_BIT   2)
(define  PICK_BIT    4)
(define  TOOL_BIT    8)
(define  MIRROR_BIT  16)
(define  BABA_BIT    32)          
(define  SCORE_BIT   64)

(define  EXTRA_DATA  18)   ; Data items other than stats and name
(define  CHECK_DATA  10)   ; Data items that are in check sums

(local
;; local data for saving hero stats for next game
                         ;;;;;;;;;;;;;;;;;;start;;;;;;;;;;;;;;;;;;
   statsKey = $53        ;;;;;;;;order dependent variables;;;;;;;;
   svCharType            ;;;;;;;;order dependent variables;;;;;;;;
   svHighGold            ;;;;;;;;order dependent variables;;;;;;;;
   svLowGold             ;;;;;;;;order dependent variables;;;;;;;;
   svScore               ;;;;;;;;order dependent variables;;;;;;;;
   svMiscEquip           ;;;;;;;;order dependent variables;;;;;;;;
   [codedStats NUMSTATS] ;;;;;;;;order dependent variables;;;;;;;;
   svDaggers             ;;;;;;;;order dependent variables;;;;;;;;
   svHealing             ;;;;;;;;order dependent variables;;;;;;;;
   svMana                ;;;;;;;;order dependent variables;;;;;;;;
   svStamina             ;;;;;;;;order dependent variables;;;;;;;;
   svGhostOil            ;;;;;;;;order dependent variables;;;;;;;;
   bogus0   = $79        ;;;;;;;;order dependent variables;;;;;;;;
   bogus1   = $86        ;;;;;;;;order dependent variables;;;;;;;;
   checkSum1             ;;;;;;;;order dependent variables;;;;;;;;
   checkSum2             ;;;;;;;;order dependent variables;;;;;;;;
   bogus2   = $43        ;;;;;;;;order dependent variables;;;;;;;;
   bogus3   = $88        ;;;;;;;;order dependent variables;;;;;;;;
   bogus4   = $ad        ;;;;;;;;order dependent variables;;;;;;;;
   bogus5   = $f0        ;;;;;;;;order dependent variables;;;;;;;;
   checkSumKey = $ce     ;;;;;;;;order dependent variables;;;;;;;;
                         ;;;;;;;;;;;;;;;;;;;end;;;;;;;;;;;;;;;;;;;
   check1
   check2
   [YNSTR 5]
   [heroFileName 16]
   [bigStr 400]
   hasSaved              ;TRUE if hero saved
   [str 40]
)

(enum          ;states of saveHero Script
   askSave
   getInfoFileName
   getInfoFileName2
   openFile
   writeHeroInfo
   writeComplete
   tryAgain
   badAnswer
   saveDone
)

;(procedure
;  makeChar
;  makeZero
;  restoreHero
;  convWord
;  convByte
;)
;
;(procedure (makeZero &tmp whichSkill)
;  (HighPrint "make Zero")
;  (for  ((= whichSkill 0))
;        (< whichSkill NUMSTATS)
;        ((++ whichSkill))
;     (= [egoStats whichSkill] 0)
;  )
;  (= [invNum iGold] (= [invNum iSilver] (= score 0)))
;  (ego use: iSword)      
;  (ego use: iChainMail)  
;  (ego use: iLockPick)   
;  (ego use: iThiefKit)   
;  (ego use: iMagicMirror)
;  (Bclr fBabaFrog)     
;  (= [invNum iDagger] 0)
;  (= [invNum iHealingPotion] 0)
;  (= [invNum iManaPotion] 0)
;  (= [invNum iStaminaPotion] 0)
;  (= [invNum iGhostOil] 0)
;  (= score 0)
;  (= heroType 0)
;  (StrCpy @userName {xxxxxxxxxxy})
;  (for  ((= whichSkill 0))
;        (< whichSkill (+ NUMSTATS EXTRA_DATA))
;        ((++ whichSkill))
;     (= [statsKey (+ whichSkill 1)] 0)
;  )
;  (HighPrint "char Zeroed")
;  (return)
;)
;
;(procedure (makeChar &tmp whichSkill)
;  (HighPrint "make Char")
;  (for  ((= whichSkill 0))
;        (< whichSkill NUMSTATS)
;        ((++ whichSkill))
;     (= [egoStats whichSkill] whichSkill)
;  )
;  (= [invNum iDagger] 1)
;  (= [invNum iHealingPotion] 2)
;  (= [invNum iManaPotion] 3)
;  (= [invNum iStaminaPotion] 4)
;  (= [invNum iGhostOil] 5)
;  (= score 432)
;  (HighPrint "Char made")
;  (return)
;)
;
;(procedure (restoreHero &tmp whichSkill)
;  (HighPrint "restore Hero")
;  (if (not (heroinfo open: fRead))
;     (HighPrint "Failure in opening file")
;     (return)
;  )
;  (heroinfo readString: @userName 52)
;  (heroinfo readString: @bigStr 90)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  (for  ((= whichSkill 0))
;        (< whichSkill (+ NUMSTATS EXTRA_DATA))
;        ((++ whichSkill))
;
;     (= [statsKey (+ whichSkill 1)] (convWord [bigStr whichSkill]))
;
;  )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  (for  ((= whichSkill (+ NUMSTATS EXTRA_DATA)))
;        (< 0 whichSkill)
;        ((-- whichSkill))
;
;     (^= [statsKey whichSkill] (& [statsKey (- whichSkill 1)] 127))
;
;  )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  (= check1 checkSumKey)
;  (for  ((= whichSkill 0))
;        (< whichSkill (+ NUMSTATS CHECK_DATA))
;        ((+= whichSkill 2))
;     (= [statsKey (+ whichSkill 1)] (& [statsKey (+ whichSkill 1)] 127))
;     (+= check1 [statsKey (+ whichSkill 1)])
;  )
;  (= check2 0)
;  (for  ((= whichSkill 1))
;        (< whichSkill (+ NUMSTATS CHECK_DATA))
;        ((+= whichSkill 2))
;     (= [statsKey (+ whichSkill 1)] (& [statsKey (+ whichSkill 1)] 127))
;     (+= check2 [statsKey (+ whichSkill 1)])
;  )
;  (&= check1 127)
;  (&= check2 127)
;  (if (or (!= check1 checkSum1) (!= check2 checkSum2))
;     (HighPrint "CHECKSUM ERROR")
;  )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  (for  ((= whichSkill 0))
;        (< whichSkill NUMSTATS)
;        ((++ whichSkill))
;     (= [egoStats whichSkill] [codedStats whichSkill])
;  )
;  (= [invNum iDagger] svDaggers)  
;  (= [invNum iHealingPotion] svHealing)  
;  (= [invNum iManaPotion] svMana)     
;  (= [invNum iStaminaPotion] svStamina)  
;  (= [invNum iGhostOil] svGhostOil) 
;  (= [invNum iGold] (+ (* svHighGold 100) svLowGold))
;  (= score (+ svScore 128))
;  (if (& svMiscEquip SCORE_BIT) (+= score 256))
;  (if (& svMiscEquip SWORD_BIT) (= [invNum iSword] 1))
;  (if (& svMiscEquip CHAIN_BIT) (= [invNum iChainMail] 1)) 
;  (if (& svMiscEquip PICK_BIT)  (= [invNum iLockPick] 1))  
;  (if (& svMiscEquip TOOL_BIT)  (= [invNum iThiefKit] 1))  
;  (if (& svMiscEquip MIRROR_BIT) (= [invNum iMagicMirror] 1))
;  (HighPrint "Hero restored")
;  (return)
;)
;
;(procedure (convWord ascii)
;  (return (+ (convByte (>> ascii 8)) (* (convByte (& ascii 255)) 16)))
;)
;
;(procedure (convByte ascii)
;  (cond
;     ((== ascii 32)
;        (return 0)
;     )
;     ((<= 48 ascii 57)
;        (return (- ascii 48))
;     )
;     (else
;        (return (- ascii 87))
;     )
;  )
;)

(instance CharSave of Room
   (properties
      picture  pBlueSkyForCarpet
      horizon  0
      style    IRISOUT
   )
   
   (method (dispose)
      (StatusLine code: dftStatusCode)
      (super dispose:)
   )

   (method (init)
      (StatusLine
         code: endStatus,
         enable:)
      (super init: &rest)
      (cSound stop:)

      ; don't let'm control anything!
      (User canControl: FALSE, canInput: FALSE)
;;    (User canControl: FALSE, canInput: TRUE)

      (self setScript: saveHero)
   )

;  (method (handleEvent event) 
;     (if (Said 'quit')
;        (= quit TRUE)
;     )
;     (if (Said 'make/zero')
;        (makeZero)
;     )
;     (if (Said 'make/hero')
;        (makeChar)
;     )
;     (if (and (Said 'restore/hero') hasSaved)
;        (restoreHero)
;     )
;  )
)


(instance heroinfo of File
   (properties
      name  {hq1_hero.sav})
)

(instance saveHero of Script
   (method (changeState newState &tmp whichSkill oldGold)
      (switch (= state newState)
         (askSave
;           (makeChar)
            (Format @heroFileName "a:hq1\_hero.sav")
            (if (>= score 500)
               (HighPrint "CONGRATULATIONS!!__You have successfully
                     completed \"Hero's Quest I:__So You Want To Be
                     A Hero\" with the maximum possible score, 500 of 500!!_
                     We welcome you to the ranks of the few, the proud,
                     the True Heroes!")
            else
               (HighPrint (Format @bigStr "Congratulations!__You have
                     successfully completed \"Hero's Quest I:__So You
                     Want To Be A Hero.\"__Your final score was %d of
                     500 possible Puzzle Points." score))
            )

            (HighPrint "If you have not already done so,
                  we encourage you to play \"Hero's Quest I\" again
                  with the other two character types; many of the
                  puzzles are different, or have alternate solutions.")

            (HighPrint "In the meantime, you are already a winner!__Please
                  insert a writeable disk in your floppy drive to
                  save your winning Hero for use in\n
                  \"Hero's Quest II:__Trial By Fire.\"")
            (self  cue:)
         )

         (getInfoFileName
            (= cycles 2)
         )

         (getInfoFileName2
            (if (GetInput @heroFileName 30
                     {Disk file in which to save your Hero.})
               (heroinfo name: @heroFileName)
               (= cycles 2)
            else
               (self changeState: tryAgain)
            )
         )

         (openFile
            (if (heroinfo open: fTrunc)
               (heroinfo close:)
               (= seconds 2)
            else
               (HighPrint (Format @bigStr "Could not create file -- %s."
                     (heroinfo name?)))
               (self changeState: tryAgain)
            )
         )               

         (writeHeroInfo
            (if (not (heroinfo open: fAppend))
               (self  changeState: tryAgain)
               (return)
            )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (for  ((= whichSkill 0))
                  (< whichSkill NUMSTATS)
                  ((++ whichSkill))
               (= [codedStats whichSkill] [egoStats whichSkill])
            )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (= oldGold (+ [invNum iGold] (/ [invNum iSilver] 10)))
            (= svCharType heroType)
            (= svHighGold ( /  oldGold 100))
            (= svLowGold  (mod oldGold 100))
            (= svScore score)
            (= svMiscEquip 0)
            (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))
            (if (ego has: iMagicMirror)   (|= svMiscEquip MIRROR_BIT))
            (if (Btst fBabaFrog)          (|= svMiscEquip BABA_BIT))
            (if (< 255 score)             (|= svMiscEquip SCORE_BIT))
            (= svDaggers  [invNum iDagger])
;           (= svHealing  [invNum iHealingPotion])
;           (= svMana     [invNum iManaPotion])
;           (= svStamina  [invNum iStaminaPotion])
            (= svGhostOil [invNum iGhostOil])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (= checkSum1 checkSumKey)
            (for  ((= whichSkill 0))
                  (< whichSkill (+ NUMSTATS CHECK_DATA))
                  ((+= whichSkill 2))
               (= [statsKey (+ whichSkill 1)] (& [statsKey (+ whichSkill 1)] 127))
               (+= checkSum1 [statsKey (+ whichSkill 1)])
            )
            (= checkSum2 0)
            (for  ((= whichSkill 1))
                  (< whichSkill (+ NUMSTATS CHECK_DATA))
                  ((+= whichSkill 2))
               (= [statsKey (+ whichSkill 1)] (& [statsKey (+ whichSkill 1)] 127))
               (+= checkSum2 [statsKey (+ whichSkill 1)])
            )
            (&= checkSum1 127)
            (&= checkSum2 127)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (for  ((= whichSkill 0))
                  (< whichSkill (+ NUMSTATS EXTRA_DATA))
                  ((++ whichSkill))
               (= [statsKey (+ whichSkill 1)] (& [statsKey (+ whichSkill 1)] 127))
               (^= [statsKey (+ whichSkill 1)] [statsKey whichSkill])
            )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (heroinfo writeString: @userName)
            (heroinfo writeString: {\n})
            (for  ((= whichSkill 1))
                  ( < whichSkill (+ NUMSTATS EXTRA_DATA 1))
                  ((++ whichSkill))
               (Format @bigStr "%2x" [statsKey whichSkill])
               (heroinfo writeString: @bigStr)
            )
            (heroinfo writeString: {\n})
            (heroinfo close:)
            (= seconds 2)
         )

         (writeComplete
            (HighPrint "The save character file has been created.__Save
                  this disk for use with \"Hero's Quest II:__Trial By Fire\"
                  from Sierra On-Line.")
            (= hasSaved TRUE)
            (= cycles 2)
         )

         (tryAgain
            (Format @YNSTR "n")
            (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
            (HighPrint "Please answer \"y\" or \"n\".")
            (self  changeState: tryAgain)
         )

         (saveDone
            (HighPrint "Thank you for playing \"Hero's Quest I:__So You
                  Want To Be A Hero,\" and congratulations again on
                  winning.__We'll see you again soon in\n
                  \"Hero's Quest II:__Trial By Fire.\"")
            (= quit TRUE)
         )
      )
   )
)

(instance endStatus of Code
   (method (doit strg)
      (Format strg "___Wow!__You're Really A Hero!__[score %d of 500]" score)
   )
)

