Note About This Book: Advanced Lingo For Games was written by Gary Rosenzweig in 2000 for users of Macromedia Director 7. It is presented here for free on an as-is basis, with no updating. Most of the information and code here can be used in the most recent version of Director. The book has been reproduced from the final editing files archived in 2000, and not the final proof galleys. So some minor differences between this version and the printed version my exist. The entire contents of this book are Copyright 2000, Gary Rosenzweig. No part may be reproduced or copied without written permission. The text here is provided for individual use only.
Want to thank me for making this book available for free? Just buy Special Edition Using Macromedia Director MX and we'll call it even!

Advanced Lingo For Games
by Gary Rosenzweig


Chapter 14 Section 3

Making the Game

All the code for this game is kept in the frame behavior script. Thus, the game lives completely in one frame.

The behavior starts off with the on getPropertyDescriptionList where it gathers information about the cursor and text sprite locations, the source of the phrases, the order in which the phrases should be used, and the frame to jump to when all the phrases have been used up. Figure 14.2 shows the Parameters dialog box this creates.

Figure 14.2
The Parameters dialog box for the cryptogram frame behavior.

property pPhraseList -- list of phrases taken from text member
property pRealPhrase -- the actual phrase
property pEncodedPhrase -- the encoded phrase shown to the player
property pSolvedPhrase -- the phrase as the player solves it
property pCursorPos -- the position of the player's typing cursor

property pCursorSprite
property pEncodedTextSprite
property pPhraseSource
property pPhraseOrder
property pEndFrame

on getPropertyDescriptionList me
  list = [:]
  
  -- which sprite to use as the typing cursor
  addProp list, #pCursorSprite,[cc]
    [#comment: "Cursor Sprite",[cc]
     #format: #integer,[cc]
     #default: 4]
  
  -- which sprite to use as the typing cursor
  addProp list, #pEncodedTextSprite,[cc]
    [#comment: "Encoded Text Sprite",[cc]
     #format: #integer,[cc]
     #default: 3]
  
  -- the text member with the phrases in it
  addProp list, #pPhraseSource,[cc]
    [#comment: "Phrase Source",[cc]
     #format: #text,[cc]
     #default: VOID]
  
  -- what order to present the phrases
  addProp list, #pPhraseOrder,[cc]
    [#comment: "Phrase Order",[cc]
     #format: #string,[cc]
     #range: ["In Order", "Random"],[cc]
     #default: 3]
  
  -- the frame to go to when the last phrase is solved
  addProp list, #pEndFrame,[cc]
    [#comment: "End Game Frame",[cc]
     #format: #marker,[cc]
     #default: #next]
  
  return list
end

The on beginSprite handler gets the phrases, sets up the first phrase, and initializes the cursor.


-- get phrases, set up the first phrase
on beginSprite me
  getPhrases(me)
  setUpPhrase(me)
  pCursorPos = 1
  showCursor(me)
end

The "on getPhrases" handler gets the phrase text member and stores all the text in a variable called "text". It then converts each of the characters in the variable to uppercase. Finally, it places each of the lines into an item in "pPhraseList".


-- read phrases from text and put into list
on getPhrases me
  pPhraseList = []
  text = member(pPhraseSource).text
  
  -- make phrases all capital letters
  repeat with i = 1 to text.length
    put convertToCaps(me,text.char[i]) into char i of text
  end repeat
  
  -- add each to list
  repeat with i = 1 to text.line.count
    if text.line[i].length = 0 then next repeat -- skip empty lines
    add pPhraseList, text.line[i]
  end repeat
end

The "on setUpPhrase" handler either takes the first item in the phrase list{1}, or picks a random item{2}. It then removes this item from the list so that it isn't used again.

Next, it creates a translation list{3}. This is a property list in which each property is a letter of the alphabet and its value is the letter that it maps to. This translation is then applied to our phrase to encode it{4}.

One thing that this translation list cannot include is a letter that maps to itself. If one is found{5}, that is noted and a new translation list is generated{6}. This w keeps happening until a translation list where each letter is mapped to a letter other than itself is created.

Finally, the handler builds the "pEncodedPhrase" property and the "pSolvedPhrase" property{7}. The first is a text string in which all the letters have been encoded according to the translation list. The second is a text string in which all the letters are shown as an underscore. Both of these properties are placed in a different text member so that they appear on the screen.


-- set up a phrase
on setUpPhrase me
  -- get next phrase in list
  if pPhraseOrder = "In Order" then
    pRealPhrase = pPhraseList[1]{1}
    deleteAt pPhraseList, 1 -- remove phrase
    
    -- pick a random phrase from list
  else if pPhraseOrder = "Random" then
    r = random(pPhraseList.count)
    pRealPhrase = pPhraseList[r]{2}
    deleteAt pPhraseList, r -- remove phrase
  end if  
  
  -- clear encoded and solved text
  pEncodedPhrase = ""
  pSolvedPhrase = ""
  
  -- create random translation list{3}
  repeat while TRUE
    translationList = [:]
    listGood = TRUE -- assume translation list is good
    
    --- make ordered list of letters
    list = []
    repeat with i = 1 to 26
      add list, numtochar(64+i)
    end repeat
    
    -- loop through letters and assign a random translation
    repeat with i = 1 to 26
      r = random(list.count) -- pick random 
      addProp translationList, numtochar(64+i), list[r] -- add to list
      if i = r then listGood = FALSE -- if translation is a match, list is bad{5}
      deleteAt list, r -- remove character from ordered list
    end repeat
    
    -- keep generating translation lists until one is good
    if listGood then exit repeat{6}
  end repeat
  
  -- create encoded and solved phrases{4}
  repeat with i = 1 to pRealPhrase.length
    realChar = pRealPhrase.char[i] -- correct character
    
    -- if it is in translation list, then translate
    if not voidP(getAProp(translationList,realChar)) then
      code = getProp(translationList,pRealPhrase.char[i])
      put code after pEncodedPhrase -- build encoded phrase
      put "_" after pSolvedPhrase -- build solved phrase
      
      -- if not in translation list, assume it is a space or punctuation
    else
      put realChar after pEncodedPhrase -- build encoded phrase{7}
      put realChar after pSolvedPhrase -- build solved phrase
    end if
  end repeat
  
  -- assign encoded and solved phrases to text members
  member("encoded").text = pEncodedPhrase
  member("solved").text = pSolvedPhrase
end

This next handler is a utility handler used by both "on getPhrases" and on keyUp. It converts a single character to uppercase. If the character is already uppercase, or is not a letter at all, it simply returns the original character. However, if it's a lowercase letter, it returns the converted character.

The charToNum and numToChar functions convert single character strings to code numbers and vice versa. These code numbers are values from 0 to 255. These are called ASCII codes (American Standard Code for Information Interchange). Code 65 is a capital "A" and code 90 is a capital "Z." A lowercase "a" is 97 and a lowercase "z" is 122. Thus, you can convert a lowercase letter to a capital letter by subtracting 32 from its ASCII value.


-- utility handler that takes a character and converts it to uppercase
on convertToCaps me, c
  ascii = charToNum