-- Text module for GameGuru -- Written by Chris Stapleton local T = {_G = _G} -- import section: modules local byte = string.byte local sub = string.sub local min = math.min local max = math.max local sin = math.sin local cos = math.cos local rad = math.rad local yScale = GetDeviceWidth() / GetDeviceHeight() local pairs = pairs -- GG functions/Tables local createSpr = CreateSprite local deleteSpr = DeleteSprite local setSprSize = SetSpriteSize local setSprOff = SetSpriteOffset local setSprPos = SetSpritePosition local setSprCol = SetSpriteColor local setSprDepth = SetSpriteDepth local setSprAng = SetSpriteAngle local getImageH = GetImageHeight local getImageW = GetImageWidth -- include these for debugging local Prompt = Prompt _ENV = T local characterSets = {} local textStrings = {} local function getUnusedSpr( pool, ch ) local entry = nil for k, v in pairs( pool ) do if v.ch == ch and not v.used then entry = k break end end if entry ~= nil then pool[ entry ]. used = true end return entry end local function freeSprite( set, spr ) local thisSet = characterSets[ set ] -- set specified not registered! if thisSet == nil then return end local entry = nil for k, v in pairs( thisSet.sprPool ) do if v.spr == spr then setSprPos ( spr, 250, 250 ) entry = k break end end if entry ~= nil then thisSet.sprPool[ entry ].used = false end end local textColour = nil local textDepth = nil local function getCharSpr( set, ch, size ) local thisSet = characterSets[ set ] -- set specified not registered! if thisSet == nil then return end -- set specified does not contain character specified! if thisSet.chars[ ch ] == nil then return nil end -- look for unused character in sprite pool local poolEntry = getUnusedSpr( thisSet.sprPool, ch ) -- if no unused entries create new entry in pool if poolEntry == nil then poolEntry = #thisSet.sprPool + 1 thisSet.sprPool[ poolEntry ] = { ch = ch, spr = createSpr( thisSet.chars[ ch ] ), used = true } end local spr = thisSet.sprPool[ poolEntry ].spr local ysize = thisSet.yAdj * size * thisSet.charh local xsize = thisSet.xAdj * size * thisSet.charw[ ch ] setSprSize( spr, xsize, ysize ) setSprOff ( spr, xsize / 2, ysize / 2 ) setSprPos ( spr, 250, 250 ) if textColour ~= nil then setSprCol( spr, textColour.r, textColour.g, textColour.b, textColour.a ) end if textDepth ~= nil then setSprDepth( spr, textDepth ) else setSprDepth( spr, 1 ) end return thisSet.sprPool[ poolEntry ].spr end local function getUnusedMsg() for k, v in pairs( textStrings ) do if not v.used then textStrings[ k ].used = true return k end end local msg = #textStrings + 1 textStrings[ msg ] = { used = true, sprites = {}, alpha = 255 } return msg end -------------------------------------------------------- -- Function to register a set of character images -- -- parameters: -- -- imageList : a list in the form -- -- { ['A'] = LoadImage( ... ), -- -- ['B'] = LoadImage( ... ), -- -- ... etc ... -- -- ['?'] = LoadImage( ... ) } -- -- -- -- xsize, ysize : width and height of widest -- -- character in screen %, this is used to -- -- calculate the scaling value for the font. -- -- spacing : basically this value specifies a -- -- spacing factor, start with 1 and see how -- -- it looks then tweak it until you get the -- -- look you want. -- -- backGnd : an image to use as the background. -- -- -- -- Returns an id which is then used in calls to other -- -- functions to specify which character set to use. -- -------------------------------------------------------- function T.RegisterSprites( imageList, xsize, ysize, spacing, backGnd ) spacing = spacing or 1 local id = #characterSets + 1 characterSets[ id ] = {} local thisSet = characterSets[ id ] if backGnd ~= nil then -- background image thisSet.back = backGnd end thisSet.chars = imageList thisSet.space = xsize * spacing / 2 thisSet.charw = {} thisSet.yAdj = nil -- all characters have to be the same height so get the image height -- from the first image but collect widths for all images for k, v in pairs( imageList ) do thisSet.charw[k] = getImageW( v ) if thisSet.yAdj == nil then thisSet.charh = getImageH( v ) thisSet.yAdj = ysize / thisSet.charh end end thisSet.s = spacing local widest = 0 for _, v in pairs( thisSet.charw ) do if v > widest then widest = v end end thisSet.xAdj = xsize / widest thisSet.sprPool = {} return id end -------------------------------------------------------- -- Function to display a text string using the -- -- specified sprite set. -- -- -- -- parameters: -- -- str : text string to display. e.g. 'Hello' -- -- -- -- set : the sprite set to use, i.e. the value -- -- returned by the RegisterSprites call. -- -- -- -- xpos, ypos : screen position in % where text -- -- will be displayed. -- -- -- -- size : This relates to the size parameters -- -- specified in the RegisterSprites, i.e. 1 -- -- means the same size as that specified, 2 -- -- would be twice the size, 0.5 half the -- -- size etc. (defaults to 1) -- -- -- just : 'Left', 'Centre' or 'Right' justify the -- -- displayed text relative to the position -- -- specified. (defaults to 'Left') -- -- -- -- angle: angle of text -- -- -- -- Returns an identifier for this string for use in -- -- other functions below. -- -------------------------------------------------------- function T.DisplayNewText( str, set, xpos, ypos, size, just, angle ) size = size or 1 just = just or 'Left' angle = angle or 0 local thisSet = characterSets[ set ] -- set specified not registered! if thisSet == nil then return end local msg = getUnusedMsg() textStrings[ msg ].sprites = {} textStrings[ msg ].set = set local numChars = #str local lhs = xpos -- first work out 'width' of string on screen local totWidth = 0 local adj = thisSet.xAdj * size * thisSet.s for i = 1, numChars do local ch = sub( str, i, i ) if ch == ' ' then totWidth = totWidth + thisSet.space * size else totWidth = totWidth + thisSet.charw[ ch ] * adj end end local sAng = sin( rad( angle ) ) local cAng = cos( rad( angle ) ) if just == 'Centre' then lhs = xpos - ( totWidth / 2 ) * cAng ypos = ypos - ( totWidth / 2 ) * sAng * yScale elseif just == 'Right' then lhs = xpos - totWidth * cAng ypos = ypos - totWidth * sAng * yScale end local ysize = thisSet.charh * thisSet.yAdj * size -- create background if thisSet.back ~= nil then textStrings[ msg ].back = createSpr( thisSet.back ) local spr = textStrings[ msg ].back setSprSize( spr, totWidth, ysize ) setSprOff ( spr, 0, ysize / 2 ) setSprPos ( spr, lhs, ypos ) setSprAng ( spr, angle ) if textDepth ~= nil then setSprDepth( spr, textDepth + 1 ) else setSprDepth( spr, 2 ) end end local xSoFar = 0 for i = 1, numChars do local ch = sub( str, i, i ) if ch == ' ' then xSoFar = xSoFar + thisSet.space * size else local spr = getCharSpr( set, sub( str, i, i ), size ) if spr ~= nil then local w = thisSet.charw[ ch ] * adj / 2 xSoFar = xSoFar + w setSprPos ( spr, lhs + xSoFar * cAng, ypos + xSoFar * sAng * yScale ) setSprAng ( spr, angle ) xSoFar = xSoFar + w textStrings[ msg ].sprites[ i ] = spr end end end if textColour ~= nil then textStrings[ msg ].colour = { r = textColour.r, g = textColour.g, b = textColour.b, a = textColour.a } else textStrings[ msg ].colour = nil end return msg end -------------------------------------------------------- -- Function to delete a text string and return the -- -- sprites that it used back to the comon pool. -- -- parameters: -- -- msg : identifies which string to delete. This -- -- is the return value from the Display -- -- DisplayNewText function. -- -------------------------------------------------------- function T.DeleteText( msg ) if textStrings[ msg ] ~= nil and textStrings[ msg ].used then textStrings[ msg ].used = false for _, v in pairs( textStrings[ msg ].sprites ) do freeSprite( textStrings[ msg ].set, v ) end local spr = textStrings[ msg ].back if spr ~= nil then deleteSpr( spr ) end textStrings[ msg ].sprites = {} end end -------------------------------------------------------- -- Functions to control the characteristics of the -- -- text displayed. -- -- These work in a global sense in that once set all -- -- new strings displayed from then on inherit these -- -- specified characteristics. -- -------------------------------------------------------- function T.ClearTextColour() textColour = nil end function T.SetTextColour( r, g, b, a ) textColour = { r = r or 255, g = g or 255, b = b or 255, a = a or 255 } end function T.ClearTextDepth() textDepth = nil end function T.SetTextDepth( val ) textDepth = val or 0 end -------------------------------------------------------- -- Function to Fade out a displayed text. Call this -- -- every frame. -- -- -- -- msg : identifies the string. -- -- -- -- amount : amount to fade by each call. -- -- (defaults to 1) -- -- limit : value to stop at. -- -- -- -- Needs SetTextColour to have been used first to set -- -- initial alpha value. -- -------------------------------------------------------- function T.FadeOutText( msg, amount, limit ) amount = amount or 1 limit = limit or 0 limit = max( limit, 0 ) if limit > 254 then return end local txt = textStrings[ msg ] if txt ~= nil and txt.used and txt.colour ~= nil then if txt.colour.a <= limit then return else txt.colour.a = max( txt.colour.a - amount, limit ) end for _, v in pairs( txt.sprites ) do setSprCol( v, txt.colour.r, txt.colour.g, txt.colour.b, txt.colour.a ) end end end -------------------------------------------------------- -- Function to Fade in a displayed text. Call this -- -- every frame. -- -- -- -- msg : identifies the string. -- -- -- -- amount : amount to 'fade in' by each call. -- -- (defaults to 1) -- -- limit : value to stop at. -- -- -- -- Needs SetTextColour to have been used first to set -- -- initial alpha value. -- -------------------------------------------------------- function T.FadeInText( msg, amount, limit ) amount = amount or 1 limit = limit or 255 limit = min( limit, 255 ) if limit < 1 then return end local txt = textStrings[ msg ] if txt ~= nil and txt.used and txt.colour ~= nil then if txt.colour.a >= limit then return else txt.colour.a = min( txt.colour.a + amount, limit ) end for _, v in pairs( txt.sprites ) do setSprCol( v, txt.colour.r, txt.colour.g, txt.colour.b, txt.colour.a ) end end end return T