Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --------------------------------------------------------------------------------
- --------------------------------------------------------------------------------
- ------ Sonic Speedometer v1.0 --------------------------------------------------
- ------ For multiple versions ---------------------------------------------------
- --------------------------------------------------------------------------------
- --------------------------------------------------------------------------------
- -- This script shows several interesting values read directly out of the game
- -- engine. All of these, except for the speedometer, will autohide themselves.
- -- This currently works for Sonic 2 and Sonic 3&K.
- -- Use Gens Rerecording http://code.google.com/p/gens-rerecording/
- -- Items marked with a + will appear when you press Up + C; tap C multiple times
- -- to get them to stay onscreen longer. Or, use Up + B to toggle them.
- -- + Checkpoint: Shows most recent checkpoint.
- -- + Remaining: Shows how many rings are left to collect until you get a
- -- Perfect Bonus.
- -- + Circular thing with a number: This shows you the distance and bearing to
- -- the nearest ring. In other words, the needle in the circle shows you in
- -- what direction the nearest ring lies, and the number next to it shows how
- -- far away the ring is.
- -- Yes, I know this won't always give a correct distance/bearing for
- -- Metropolis Zone due to the wrapping.
- -- + UP D/L/R: These change color to show which collision collision plane is
- -- active: yellow for the primary, cyan for the secondary.
- -- - LOCK: Shows up when a control lock engages.
- -- - Air: Shows up under water. Shows how how many seconds of air are left.
- -- - Invincible: This timer shows up when you get an invincibility monitor.
- -- - Speed Shoe: When this timer show up, it shows what you'd think it shows.
- -- - Unlabeled red number: Shows how many FRAMES of temporary invunerability
- -- you have left.
- -- - Flying: Shows up when Tails is flying
- -- - Continues: Reminds you how many continues you have got.
- -- - Speed: This shows your speed. The dial also features a digital readout
- -- of your speed below. The gray needle bounces up and down to show your
- -- most recent maximum speed; the red number above shows what this speed is.
- -- You can change the range of the speedometer
- -- - Boost: Shows up only when you do a spin dash. Freezes to show how
- -- powerful the dash was.
- --
- -- Lua is supposed to be easy to understand, even for non-coders. You shouldn't
- -- have trouble changing what gets shown on screen.
- --
- -- To Do:
- -- - Fix ring finder for Metropolis Zone and other zones that loop
- -- - Implement non-sucky arc-drawing and fill algorithms. I'll probably never
- -- actually do this, but feel free to contribute one for me.
- --
- -- Consider this script to be given out under the GPL. --- DrDnar, 1 May 2012
- --
- -- Change log:
- --------------------------------------------------------------------------------
- ------ Game-specific Data ------------------------------------------------------
- --------------------------------------------------------------------------------
- isPaused = {}
- gameActive = {}
- buttonsChanged = {}
- perfectCounter = {}
- xLocation = {}
- yLocation = {}
- xSpeed = {}
- ySpeed = {}
- continues = {}
- checkpoint = {}
- airRemaining = {}
- hLockTimer = {}
- invulnTimer = {}
- invincTimer = {}
- speedShoeTimer = {}
- spinDashFlag = {}
- spinDashCharge = {}
- collisionsUpFlag = {}
- collisionsDLRFlag = {}
- ringTable = {}
- checkpoint = {}
- spriteTable = {}
- currentCharacter = {}
- function ReadROM(start, length)
- array = {}
- for n = 0, length-1 do
- array[n+1] = memory.readbyte(start + n)
- end
- return array
- end
- function ArrayEquals(one, two)
- local n = 1
- while one[n] ~= nil and two[n] ~= nil do
- -- print(string.format("%2X %2X | ", one[n], two[n]))
- if one[n] ~= two[n] then return false end
- n = n + 1
- end
- if one[n] ~= two[n] then return false end
- return true
- end
- romIDLocation = 0x180
- romIDLength = 14
- s1id = {0x47, 0x4D, 0x20, 0x30, 0x30, 0x30, 0x30, 0x34, 0x30, 0x34, 0x39, 0x2D, 0x30, 0x31}
- -- G M 0 0 0 0 4 0 4 9 - 0 1
- sonic1 = 1
- s2id = {0x47, 0x4D, 0x20, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x35, 0x31, 0x2D, 0x30, 0x31}
- -- G M 0 0 0 0 1 0 5 1 - 0 1
- sonic2 = 2
- s3kid = {0x47, 0x4D, 0x20, 0x4D, 0x4B, 0x2D, 0x31, 0x35, 0x36, 0x33, 0x20, 0x2D, 0x30, 0x30}
- -- G M M K - 1 5 6 3 - 0 0
- sonic3k = 3
- --if ArrayEquals(s1id, ReadROM(romIDLocation, romIDLength)) then
- -- isS1 = true
- -- currentGame = sonic1
- --end
- if ArrayEquals(s2id, ReadROM(romIDLocation, romIDLength)) then
- print("ROM type: S2")
- isS2 = true
- currentGame = sonic2
- isPaused.location = 0xFFF63B
- gameActive.location = 0xFFF711
- buttonsChanged.location = 0xFFF605
- perfectCounter.location = 0xFFFF40
- xLocation.location = 0xFFB008
- yLocation.location = 0xFFB00C
- xSpeed.location = 0xFFB010
- ySpeed.location = 0xFFB012
- continues.location = 0xFFFE18
- checkpoint.location = 0xFFFE30
- airRemaining.location = 0xFFB028
- hLockTimer.location = 0xFFB02E
- function invulnTimer.get() return memory.readwordunsigned(0xFFB030) end
- function invincTimer.get() return memory.readwordunsigned(0xFFB032) end
- function speedShoeTimer.get() return memory.readwordunsigned(0xFFB034) end
- spinDashFlag.location = 0xFFB039
- spinDashFlag.exists = true
- spinDashCharge.location = 0xFFB03A
- collisionsUpFlag.location = 0xFFB03E
- collisionsUpFlag.exists = true
- collisionsDLRFlag.location = 0xFFB03F
- ringTable.location = 0xFFE806
- ringTable.length = 0x600
- ringTable.type = sonic2
- checkpoint.location = 0xFFFE30
- spriteTable.itemSize = 0x40
- spriteTable.location = 0xFFB000
- end
- if ArrayEquals(s3kid, ReadROM(romIDLocation, romIDLength)) then
- print("ROM type: S3&K")
- isS3K = true
- currentGame = sonic3k
- isPaused.location = 0xFFF63B
- gameActive.location = 0xFFF711
- buttonsChanged.location = 0xFFF605
- perfectCounter.location = 0xFFFF04
- xLocation.location = 0xFFB010
- yLocation.location = 0xFFB014
- xSpeed.location = 0xFFB018
- ySpeed.location = 0xFFB01A
- continues.location = 0xFFFE18
- checkpoint.location = 0xFFFE2A
- airRemaining.location = 0xFFB02C
- hLockTimer.location = 0xFFB032
- function invulnTimer.get() return memory.readbyteunsigned(0xFFB034) end
- function invincTimer.get() return memory.readbyteunsigned(0xFFB035)*8 end
- function speedShoeTimer.get() return memory.readbyteunsigned(0xFFB036)*8 end
- spinDashFlag.location = 0xFFB03D
- spinDashFlag.exists = true
- spinDashCharge.location = 0xFFB03E
- collisionsUpFlag.location = 0xFFB046
- collisionsDLRFlag.location = 0xFFB047
- ringTable.location = 0xFFE806
- ringTable.length = 0x600
- ringTable.type = sonic3k
- checkpoint.location = 0xFFFE30
- spriteTable.itemSize = 0x4A
- spriteTable.location = 0xFFB000
- currentCharacter.location = 0xFFFF08
- end
- if currentGame == nil then
- error("Possibily unsupported game. Script editing is required.")
- end
- --------------------------------------------------------------------------------
- ------ Meter Object ------------------------------------------------------------
- --------------------------------------------------------------------------------
- -- This object lets you draw a generic meter or dial, with multiple needles.
- -- To declare a meter, do
- -- - Meter:Create(baseX, baseY, size, thetaMin, thetaMax, scaleInc, fgColor, bgColor, fill)
- -- - baseX, baseY: X&Y location for the meter
- -- - size: Radius of the meter
- -- - thetaMin, thetaMax: These variables control the arc that the meter's
- -- range will sweep. You could, for example, have the meter sweep a range
- -- less than the semicircle used in this example.
- -- - scaleInc: If not nil, this controls how often tic marks appear on the
- -- meter's scale. Specified as an angular incrememt.
- -- - fgColor, bgColor: Controls the color of the main outer arc and the
- -- shadowing of that arc.
- -- - fill: Controls the fill color of the arc.
- -- * The color values tend to look funny if you specify an opacity that isn't
- -- fully opaque or transparent.
- -- This function will return a new Meter object. Don't forget to assign it to a
- -- variable:
- -- - aMeter = Meter:Create(...)
- -- To draw the meter on the screen, first do
- -- - aMeter:DrawMeter()
- -- to draw the meter's basic graphic. Then, for each needle value you want to
- -- show, do
- -- - aMeter:DrawNeedle(percentage, color, saturate, size)
- -- - percentage: A number between 0 and 1 that represents the fraction of the
- -- arc between thetaMin and thetaMax that the needle should point to.
- -- - color: The color of the needle line. At the moment, there is no support
- -- for shadowing the needle color.
- -- - saturate: If true, then any percentage value less than 0 will be treated
- -- as zero, and any value greater than 1 will be treated as one.
- -- - size: Controls the length (radius) of the needle.
- -- The parameters after color may be omitted. They will default to
- -- - color: fgColor passed to Create() method
- -- - saturate: false
- -- - size: size passed to Create() method.
- Meter = {}
- Meter.__index = Meter
- function Meter:Create(baseX, baseY, size, thetaMin, thetaMax, scaleInc, fgColor, bgColor, fill)
- local newItem = {}
- setmetatable(newItem, Meter) -- Bind object methods to new object
- newItem.baseX = baseX -- x location
- newItem.baseY = baseY -- y location
- newItem.thetaMin = thetaMin
- newItem.thetaMax = thetaMax
- newItem.thetaDelta = thetaMax - thetaMin
- newItem.size = size -- size
- newItem.scaleInc = scaleInc
- newItem.bg = bgColor
- newItem.fg = fgColor
- newItem.fill = fill
- return newItem
- end
- function Meter:DrawMeter()
- local inc = math.asin(1/self.size)/(self.size/2)
- local start, stop = self.thetaMin, self.thetaMax
- if start > stop then
- start, stop = stop, start
- end
- local theta = start
- local size, basex, basey = self.size, self.baseX, self.baseY
- local cos, sin
- while theta < stop do
- cos = math.cos(theta)
- sin = math.sin(theta)
- gui.pixel(sin*size + basex, cos*size + basey, self.fg)
- gui.pixel(sin*(size+0.5) + basex, cos*(size+0.5) + basey, self.fg)
- --gui.pixel(sin*(size-1) + basex, cos*(size-1) + basey, self.fg)
- if self.bg ~= nil then
- gui.pixel(sin*(size-1) + basex, cos*(size-1) + basey, self.bg)
- gui.pixel(sin*(size-1.5) + basex, cos*(size-1.5) + basey, self.bg)
- end
- if self.bg ~= nil then
- gui.line(basex, basey, sin*(size-2) + basex, cos*(size-2) + basey, self.fill)
- end
- theta = theta + inc
- end
- theta = start
- while theta < stop do
- cos = math.cos(theta)
- sin = math.sin(theta)
- if self.scaleInc ~= nil and ((theta-start)/self.scaleInc)%1 * self.scaleInc > (self.scaleInc-(2*inc)) then
- gui.pixel(sin*(size-1) + basex, cos*(size-1) + basey, self.fg)
- gui.pixel(sin*(size-1.5) + basex, cos*(size-1.5) + basey, self.fg)
- gui.pixel(sin*(size-2) + basex, cos*(size-2) + basey, self.fg)
- gui.pixel(sin*(size-2.5) + basex, cos*(size-2.5) + basey, self.fg)
- -- gui.line(sin*(size-1) + basex, cos*(size-1) + basey, sin*(size-3) + basex, cos*(size-3) + basey, self.fg)
- end
- theta = theta + inc
- end
- end
- function Meter:DrawNeedle(percent, fgColor, saturate, size)
- if saturate and percent > 1 then
- percent = 1
- end
- if saturate and percent < 0 then
- percent = 0
- end
- if fgColor == nil then
- fgColor = self.fgColor
- end
- if size == nil then
- size = self.size - 3
- end
- local theta = percent * self.thetaDelta + self.thetaMin
- local sin, cos = math.cos(theta), math.sin(theta)
- gui.line(self.baseX, self.baseY, size*cos + self.baseX, size*sin + self.baseY, fgColor)
- end
- --------------------------------------------------------------------------------
- ------ Globals -----------------------------------------------------------------
- --------------------------------------------------------------------------------
- lastSpindashValue = 0
- boostMeter = Meter:Create(231, 214, 20, 3*math.pi/2, math.pi/2, math.pi/8, 0xFFFF00FF, 0x000000FF, 0x202020FF)
- boostTimer = 0
- speedometer = Meter:Create(287, 214, 20, 3*math.pi/2, math.pi/2, math.pi/8, 0xFFFF00FF, 0x000000FF, 0x202020FF)
- maxSpeed = 0
- maxMaxSpeed = 0
- maximumSpeed = 4096
- ringFinder = Meter:Create(27, 72, 10, math.pi*2+math.pi/2, math.pi/2, math.pi/4, 0xFFFF00FF, 0x000000FF, 0x202020FF)
- lastRingBearing = 0
- showThingsTimer = 0
- showThingsFlag = false
- fps = 60 -- frames per second, change if needed
- nearestDistance = 0 -- needs init, not really global though
- --------------------------------------------------------------------------------
- ------ Show Stuff on-Screen ----------------------------------------------------
- --------------------------------------------------------------------------------
- gui.register( function ()
- -- Hide the additional HUD elements if we're not in the normal game loop.
- if memory.readbyte(gameActive.location) ~= 0 then
- perfectCounter.value = memory.readwordunsigned(perfectCounter.location)
- -- Cache Sonic's location and other things
- xLocation.value = memory.readwordunsigned(xLocation.location)
- yLocation.value = memory.readwordunsigned(yLocation.location)
- xSpeed.value = memory.readwordsigned(xSpeed.location)
- ySpeed.value = memory.readwordsigned(ySpeed.location)
- perfectCounter.value = memory.readwordunsigned(perfectCounter.location)
- if currentGame == sonic3k then
- currentCharacter.value = memory.readwordunsigned(currentCharacter.location)
- end
- -- Autohide various things
- isPaused.value = memory.readbyte(isPaused.location) ~= 0
- currentButtons = joypad.get(1)
- if currentButtons.up and AND(memory.readbyte(buttonsChanged.location), 0x20) == 0x20 then
- showThingsTimer = showThingsTimer + 120
- showThingsFlag = false
- else
- if not isPaused.value and showThingsTimer ~= 0 then
- showThingsTimer = showThingsTimer - 1
- end
- end
- if currentButtons.up and AND(memory.readbyte(buttonsChanged.location), 0x10) == 0x10 then
- if showThingsFlag then
- showThingsFlag = false
- else
- showThingsFlag = true
- showThingsTimer = 1
- end
- end
- if showThingsFlag then
- showThingsTimer = 1
- end
- if showThingsTimer == 0 then
- showThingsFlag = false
- end
- -- Ring finder
- haveBearing = false
- -- Sonic 2
- if perfectCounter.value ~= 0 and not isPaused.value and currentGame == sonic2 then
- -- Initalize scanning loop
- keepGoing = true
- address = 0xFFE806
- nearestDistance = 65535
- nearestBearing = 0
- -- Scan the ring table in RAM, keeping track of the smallest distance found.
- -- The ring table has 6-byte entries. The first word is the
- -- destruction animation counter. The next two are simply the x and y
- -- location. 0xFFFFFFFF marks the end of the table.
- while keepGoing and address < 0xFFEDFF do
- value = memory.readwordunsigned(address)
- if value == 0 then
- deltax = memory.readwordunsigned(address+2) - xLocation.value
- deltay = memory.readwordunsigned(address+4) - yLocation.value
- value = math.sqrt(deltax*deltax + deltay*deltay)
- if value < nearestDistance then
- nearestDistance = value
- nearestBearing = math.atan2(deltay, deltax)
- end
- haveBearing = true
- else
- if value == 0xFFFF and memory.readwordunsigned(address+2) == 0xFFFF then
- keepGoing = false
- end
- end
- address = address + 6
- end
- end
- -- S3&K
- if perfectCounter.value ~= 0 and (currentGame == sonic3k) then
- haveBearing = true
- -- Scan backwards
- keepGoing = true
- address = memory.readwordunsigned(0xFFEE42)
- address = address * 65536 + memory.readwordunsigned(0xFFEE44)
- status = 0xFF0000 + memory.readwordunsigned(0xFFEE4A)
- nearestDistance = 65535
- nearestBearing = 0
- while keepGoing do
- value = memory.readwordunsigned(address)
- if value ~= 0 then
- value = memory.readwordunsigned(status)
- if memory.readwordunsigned(status) == 0 then
- deltax = memory.readwordunsigned(address) - xLocation.value
- deltay = memory.readwordunsigned(address+2) - yLocation.value
- value = math.sqrt(deltax*deltax + deltay*deltay)
- if value < nearestDistance then
- nearestDistance = value
- nearestBearing = math.atan2(deltay, deltax)
- haveBearing = true
- end
- end
- else
- keepGoing = false
- end
- address = address - 4
- status = status - 2
- end
- -- Scan forwards
- keepGoing = true
- address = memory.readwordunsigned(0xFFEE42)
- address = address * 65536 + memory.readwordunsigned(0xFFEE44)
- status = 0xFF0000 + memory.readwordunsigned(0xFFEE4A)
- while keepGoing do
- value = memory.readwordunsigned(address)
- if value ~= 0xFFFF then
- if memory.readwordunsigned(status) == 0 then
- deltax = memory.readwordunsigned(address) - xLocation.value
- deltay = memory.readwordunsigned(address+2) - yLocation.value
- value = math.sqrt(deltax*deltax + deltay*deltay)
- if value < nearestDistance then
- nearestDistance = value
- nearestBearing = math.atan2(deltay, deltax)
- haveBearing = true
- end
- end
- else
- keepGoing = false
- end
- address = address + 4
- status = status + 2
- end
- end
- if haveBearing then
- if not isPaused.value then
- -- Make 0 < nearestBearing < 2*pi
- if nearestBearing < 0 then nearestBearing = nearestBearing + 2*math.pi end
- -- Now remap that to be between 0 and 1 (input for the DrawNeedle() method)
- nearestBearing = nearestBearing/(2*math.pi)
- -- Here's where we get to the fancy animation. This finds the
- -- direction the needle needs to swing in to make the shortest arc to
- -- the current bearing.
- smallestDelta = 1
- for n = -1, 1 do
- delta = math.abs(nearestBearing - lastRingBearing - n)
- if smallestDelta > delta then
- smallestDelta = delta
- value = nearestBearing - lastRingBearing - n
- end
- end
- -- Then, by dividing by a number, we make it swing to the location,
- -- instead of jumping there instantly.
- if math.abs(value) > 0.006 then -- Implement minimum speed
- value = (value/math.abs(value)) * (value*value / 3 + 0.002)
- if math.abs(value) > 0.03 then -- Implement maximum speed
- value = 0.03 * value/math.abs(value)
- end
- end
- lastRingBearing = value + lastRingBearing
- lastRingBearing = lastRingBearing - math.floor(lastRingBearing)
- nearestDistance = nearestDistance - 14
- if nearestDistance < 0 then nearestDistance = 0 end
- end
- -- Now show the results, if wanted. Note that the needle still
- -- swings when it isn't visible.
- if showThingsTimer ~= 0 then
- ringFinder:DrawMeter()
- ringFinder:DrawNeedle(lastRingBearing, 0xFFFF00FF)
- gui.text(40, 64, string.format("%d", nearestDistance), 0xFFFF00FF, 0x000000FF)
- end
- end
- -- Speed
- value = math.sqrt(xSpeed.value*xSpeed.value + ySpeed.value*ySpeed.value)
- speedometer:DrawMeter()
- if value > maxSpeed then
- maxSpeed = value
- maxMaxSpeed = value
- else
- if not isPaused.value then
- maxSpeed = maxSpeed - 16
- if maxSpeed < 0 then
- maxSpeed = 0
- maxMaxSpeed = 0
- end
- end
- end
- if maxMaxSpeed ~= 0 then
- gui.text(290, 184, string.format("%5d", maxMaxSpeed), 0xFF0000FF, "black")
- end
- gui.text(266, 216, string.format("Speed:%5d", value), 0xFFFF00FF, "black")
- speedometer:DrawNeedle(maxSpeed/maximumSpeed, 0xFF0000FF, false, speedometer.size-4)
- speedometer:DrawNeedle(value/maximumSpeed, 0xFFFF00FF)
- -- Perfect counter
- if perfectCounter then
- if showThingsTimer ~= 0 then
- color = 0xFFFF00FF
- bgColor = 0x000000FF
- value = perfectCounter.value
- if value == 0 then
- color = 0xFFFFFF60
- bgColor = 0x00000060
- end
- gui.text(17, 54, string.format("Remaining: %3d", value), color, bgColor)
- end
- end
- -- Spin-dash "Boost meter"
- if spinDashFlag then
- color = 0xFFFF00FF--0xFFFF00A0
- bgColor = 0x000000FF--0x000000A0
- boostColor = 0x808080FF
- if memory.readbyte(spinDashFlag.location) ~= 0 then
- lastSpindashValue = memory.readword(spinDashCharge.location)
- boostColor = 0xFF2020FF
- boostTimer = 90
- else
- if not isPaused.value then
- if boostTimer > 0 then boostTimer = boostTimer - 1 end
- end
- end
- if boostTimer > 0 then
- boostMeter:DrawMeter()
- boostMeter:DrawNeedle(lastSpindashValue/0x800, boostColor)
- message = string.format("Boost: %4d", lastSpindashValue)
- gui.text(210, 216, message, color, bgColor)
- end
- end
- -- Collisions selection
- if showThingsTimer ~= 0 then
- color = 0xFFFF00FF
- bgColor = 0x000000FF
- if memory.readbyte(collisionsUpFlag.location) ~= 0x0C then
- color = 0x00FFFFFF
- end
- gui.text(276, 0, "UP", color, bgColor)
- color = 0xFFFF00FF
- bgColor = 0x000000FF
- if memory.readbyte(collisionsDLRFlag.location) ~= 0x0D then
- color = 0x00FFFFFF
- end
- gui.text(290, 0, "D/L/R", color, bgColor)
- end
- -- Horizontal control lock
- value = memory.readwordunsigned(hLockTimer.location)
- if value ~= 0 then
- gui.text(300, 18, "LOCK", 0xFF0000FF, 0x000000FF)
- end
- -- Continues
- if showThingsTimer ~= 0 then
- color = 0xFFFF0080
- bgColor = 0x00000080
- gui.text(17, 216, string.format("Continues: %d", memory.readbyte(continues.location)), color, bgColor)
- end
- -- Checkpoint
- if showThingsTimer ~= 0 then
- color = 0xFFFFFF80
- bgColor = 0x00000080
- value = memory.readbyteunsigned(checkpoint.location)
- if value ~= 0 then
- color = 0xFFFF00FF
- bgColor = 0x000000FF
- end
- gui.text(17, 0, string.format("Checkpoint: %d", value), color, bgColor)
- -- memory.writebyte(0xFFFE30,0)--Disables checkpoints
- end
- -- Timers
- -- Air
- value = memory.readbyte(airRemaining.location)
- if value ~= 0x1E then
- gui.text(80, 0, string.format("Air: %2d", value), 0xFFFFFFFF, 0x000000FF)
- end
- -- Temporary invunerability
- value = invulnTimer.get()
- if value ~= 0 then
- gui.text(246, 9, string.format("%4d", value), 0xFF0000FF, 0x000000FF)
- end
- -- Invincibility
- value = invincTimer.get()
- if value ~= 0 then
- gui.text(120, 0, string.format("Invincible: %2d", value/fps), 0xFFFFFFFF, 0x000000FF)
- end
- -- Speed shoe
- value = speedShoeTimer.get()
- if value ~= 0 then
- gui.text(192, 0, string.format("Speed Shoe: %2d", value/fps), 0xFFFFFFFF, 0x000000FF)
- end
- -- Tails flying time
- if currentGame == sonic3k then
- if currentCharacter.value == 0 then
- value = memory.readbyteunsigned(0xFFB06F)*2
- if memory.readbyteunsigned(0xFFB079) ~= 0 then
- gui.text(192, 9, string.format("Flying: %2d", value/fps), 0xFFFFFFFF, 0x000000FF)
- end
- end
- if currentCharacter.value == 02 then
- value = memory.readbyteunsigned(0xFFB025)*2
- if memory.readbyteunsigned(0xFFB02F) ~= 0 then
- gui.text(192, 9, string.format("Flying: %2d", value/fps), 0xFFFFFFFF, 0x000000FF)
- end
- end
- end
- else
- showThingsFlag = false
- end
- end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement