Compare commits
3 Commits
4d986aef08
...
1e85ee23c0
Author | SHA1 | Date | |
---|---|---|---|
1e85ee23c0 | |||
6e09bb288e | |||
7048b0c111 |
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -2,6 +2,8 @@
|
||||
"Lua.diagnostics.disable": [
|
||||
"different-requires",
|
||||
"need-check-nil",
|
||||
"cast-local-type"
|
||||
"cast-local-type",
|
||||
"undefined-field",
|
||||
"inject-field"
|
||||
]
|
||||
}
|
@ -126,7 +126,7 @@
|
||||
-26,
|
||||
5
|
||||
],
|
||||
"loop": true,
|
||||
"loop": false,
|
||||
"fps": 24,
|
||||
"anim": "scared",
|
||||
"indices": [],
|
||||
|
@ -176,7 +176,7 @@
|
||||
"name": "GF Dancing Beat Hair Landing"
|
||||
},
|
||||
{
|
||||
"loop": true,
|
||||
"loop": false,
|
||||
"offsets": [
|
||||
-2,
|
||||
-17
|
||||
|
@ -50,11 +50,15 @@
|
||||
0,
|
||||
0
|
||||
],
|
||||
"fps": 12,
|
||||
"anim": "idle",
|
||||
"fps": 24,
|
||||
"anim": "danceLeft",
|
||||
"indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6
|
||||
],
|
||||
"name": "spooky dance idle"
|
||||
@ -65,13 +69,19 @@
|
||||
0,
|
||||
0
|
||||
],
|
||||
"fps": 12,
|
||||
"fps": 24,
|
||||
"anim": "danceRight",
|
||||
"indices": [
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
14
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
0
|
||||
],
|
||||
"name": "spooky dance idle"
|
||||
},
|
||||
|
1
discord_app.lua
Normal file
1
discord_app.lua
Normal file
@ -0,0 +1 @@
|
||||
return "1380367531314778122"
|
19
main.lua
19
main.lua
@ -5,6 +5,8 @@ local myTypes = require("modules.types")
|
||||
local files = require("modules.files")
|
||||
local json = require("modules.json")
|
||||
local logging = require("modules.logging")
|
||||
local discord = require("modules.discord")
|
||||
local applicationid = require("discord_app")
|
||||
|
||||
local songs = require("charts.songs")
|
||||
|
||||
@ -41,16 +43,19 @@ local function setup()
|
||||
logo.position = myTypes.Vector2(-80, 0)
|
||||
|
||||
freaky:play()
|
||||
|
||||
local timeStamp = os.time()
|
||||
|
||||
discord.updatePresence({
|
||||
details = "In menu",
|
||||
largeImageKey = "bigimage",
|
||||
startTimestamp = timeStamp,
|
||||
state = "TaggedEngine: FNF in LUA, better than ever."
|
||||
})
|
||||
end
|
||||
|
||||
local font = love.graphics.newFont("fonts/Phantomuff.ttf", 40)
|
||||
|
||||
-- for index, song in next, songs do
|
||||
-- curSong = index
|
||||
-- curDiff = song[1]
|
||||
-- break
|
||||
-- end
|
||||
|
||||
local gettingKey
|
||||
|
||||
local settings = json.parse(files.read_file("settings.json"))
|
||||
@ -175,4 +180,6 @@ end
|
||||
|
||||
love.window.setMode(1280, 720, { fullscreen = false , resizable = true})
|
||||
|
||||
discord.initialize(applicationid, true)
|
||||
|
||||
setup()
|
252
modules/discord.lua
Normal file
252
modules/discord.lua
Normal file
@ -0,0 +1,252 @@
|
||||
local ffi = require "ffi"
|
||||
local discordRPClib = ffi.load("discord-rpc")
|
||||
|
||||
ffi.cdef[[
|
||||
typedef struct DiscordRichPresence {
|
||||
const char* state; /* max 128 bytes */
|
||||
const char* details; /* max 128 bytes */
|
||||
int64_t startTimestamp;
|
||||
int64_t endTimestamp;
|
||||
const char* largeImageKey; /* max 32 bytes */
|
||||
const char* largeImageText; /* max 128 bytes */
|
||||
const char* smallImageKey; /* max 32 bytes */
|
||||
const char* smallImageText; /* max 128 bytes */
|
||||
const char* partyId; /* max 128 bytes */
|
||||
int partySize;
|
||||
int partyMax;
|
||||
const char* matchSecret; /* max 128 bytes */
|
||||
const char* joinSecret; /* max 128 bytes */
|
||||
const char* spectateSecret; /* max 128 bytes */
|
||||
int8_t instance;
|
||||
} DiscordRichPresence;
|
||||
|
||||
typedef struct DiscordUser {
|
||||
const char* userId;
|
||||
const char* username;
|
||||
const char* discriminator;
|
||||
const char* avatar;
|
||||
} DiscordUser;
|
||||
|
||||
typedef void (*readyPtr)(const DiscordUser* request);
|
||||
typedef void (*disconnectedPtr)(int errorCode, const char* message);
|
||||
typedef void (*erroredPtr)(int errorCode, const char* message);
|
||||
typedef void (*joinGamePtr)(const char* joinSecret);
|
||||
typedef void (*spectateGamePtr)(const char* spectateSecret);
|
||||
typedef void (*joinRequestPtr)(const DiscordUser* request);
|
||||
|
||||
typedef struct DiscordEventHandlers {
|
||||
readyPtr ready;
|
||||
disconnectedPtr disconnected;
|
||||
erroredPtr errored;
|
||||
joinGamePtr joinGame;
|
||||
spectateGamePtr spectateGame;
|
||||
joinRequestPtr joinRequest;
|
||||
} DiscordEventHandlers;
|
||||
|
||||
void Discord_Initialize(const char* applicationId,
|
||||
DiscordEventHandlers* handlers,
|
||||
int autoRegister,
|
||||
const char* optionalSteamId);
|
||||
|
||||
void Discord_Shutdown(void);
|
||||
|
||||
void Discord_RunCallbacks(void);
|
||||
|
||||
void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
||||
|
||||
void Discord_ClearPresence(void);
|
||||
|
||||
void Discord_Respond(const char* userid, int reply);
|
||||
|
||||
void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
|
||||
]]
|
||||
|
||||
local discordRPC = {} -- module table
|
||||
|
||||
-- proxy to detect garbage collection of the module
|
||||
discordRPC.gcDummy = newproxy(true)
|
||||
|
||||
local function unpackDiscordUser(request)
|
||||
return ffi.string(request.userId), ffi.string(request.username),
|
||||
ffi.string(request.discriminator), ffi.string(request.avatar)
|
||||
end
|
||||
|
||||
-- callback proxies
|
||||
-- note: callbacks are not JIT compiled (= SLOW), try to avoid doing performance critical tasks in them
|
||||
-- luajit.org/ext_ffi_semantics.html
|
||||
local ready_proxy = ffi.cast("readyPtr", function(request)
|
||||
if discordRPC.ready then
|
||||
discordRPC.ready(unpackDiscordUser(request))
|
||||
end
|
||||
end)
|
||||
|
||||
local disconnected_proxy = ffi.cast("disconnectedPtr", function(errorCode, message)
|
||||
if discordRPC.disconnected then
|
||||
discordRPC.disconnected(errorCode, ffi.string(message))
|
||||
end
|
||||
end)
|
||||
|
||||
local errored_proxy = ffi.cast("erroredPtr", function(errorCode, message)
|
||||
if discordRPC.errored then
|
||||
discordRPC.errored(errorCode, ffi.string(message))
|
||||
end
|
||||
end)
|
||||
|
||||
local joinGame_proxy = ffi.cast("joinGamePtr", function(joinSecret)
|
||||
if discordRPC.joinGame then
|
||||
discordRPC.joinGame(ffi.string(joinSecret))
|
||||
end
|
||||
end)
|
||||
|
||||
local spectateGame_proxy = ffi.cast("spectateGamePtr", function(spectateSecret)
|
||||
if discordRPC.spectateGame then
|
||||
discordRPC.spectateGame(ffi.string(spectateSecret))
|
||||
end
|
||||
end)
|
||||
|
||||
local joinRequest_proxy = ffi.cast("joinRequestPtr", function(request)
|
||||
if discordRPC.joinRequest then
|
||||
discordRPC.joinRequest(unpackDiscordUser(request))
|
||||
end
|
||||
end)
|
||||
|
||||
-- helpers
|
||||
local function checkArg(arg, argType, argName, func, maybeNil)
|
||||
assert(type(arg) == argType or (maybeNil and arg == nil),
|
||||
string.format("Argument \"%s\" to function \"%s\" has to be of type \"%s\"",
|
||||
argName, func, argType))
|
||||
end
|
||||
|
||||
local function checkStrArg(arg, maxLen, argName, func, maybeNil)
|
||||
if maxLen then
|
||||
assert(type(arg) == "string" and arg:len() <= maxLen or (maybeNil and arg == nil),
|
||||
string.format("Argument \"%s\" of function \"%s\" has to be of type string with maximum length %d",
|
||||
argName, func, maxLen))
|
||||
else
|
||||
checkArg(arg, "string", argName, func, true)
|
||||
end
|
||||
end
|
||||
|
||||
local function checkIntArg(arg, maxBits, argName, func, maybeNil)
|
||||
maxBits = math.min(maxBits or 32, 52) -- lua number (double) can only store integers < 2^53
|
||||
local maxVal = 2^(maxBits-1) -- assuming signed integers, which, for now, are the only ones in use
|
||||
assert(type(arg) == "number" and math.floor(arg) == arg
|
||||
and arg < maxVal and arg >= -maxVal
|
||||
or (maybeNil and arg == nil),
|
||||
string.format("Argument \"%s\" of function \"%s\" has to be a whole number <= %d",
|
||||
argName, func, maxVal))
|
||||
end
|
||||
|
||||
-- function wrappers
|
||||
function discordRPC.initialize(applicationId, autoRegister, optionalSteamId)
|
||||
local func = "discordRPC.Initialize"
|
||||
checkStrArg(applicationId, nil, "applicationId", func)
|
||||
checkArg(autoRegister, "boolean", "autoRegister", func)
|
||||
if optionalSteamId ~= nil then
|
||||
checkStrArg(optionalSteamId, nil, "optionalSteamId", func)
|
||||
end
|
||||
|
||||
local eventHandlers = ffi.new("struct DiscordEventHandlers")
|
||||
eventHandlers.ready = ready_proxy
|
||||
eventHandlers.disconnected = disconnected_proxy
|
||||
eventHandlers.errored = errored_proxy
|
||||
eventHandlers.joinGame = joinGame_proxy
|
||||
eventHandlers.spectateGame = spectateGame_proxy
|
||||
eventHandlers.joinRequest = joinRequest_proxy
|
||||
|
||||
discordRPClib.Discord_Initialize(applicationId, eventHandlers,
|
||||
autoRegister and 1 or 0, optionalSteamId)
|
||||
end
|
||||
|
||||
function discordRPC.shutdown()
|
||||
discordRPClib.Discord_Shutdown()
|
||||
end
|
||||
|
||||
function discordRPC.runCallbacks()
|
||||
discordRPClib.Discord_RunCallbacks()
|
||||
end
|
||||
-- http://luajit.org/ext_ffi_semantics.html#callback :
|
||||
-- It is not allowed, to let an FFI call into a C function (runCallbacks)
|
||||
-- get JIT-compiled, which in turn calls a callback, calling into Lua again (e.g. discordRPC.ready).
|
||||
-- Usually this attempt is caught by the interpreter first and the C function
|
||||
-- is blacklisted for compilation.
|
||||
-- solution:
|
||||
-- "Then you'll need to manually turn off JIT-compilation with jit.off() for
|
||||
-- the surrounding Lua function that invokes such a message polling function."
|
||||
jit.off(discordRPC.runCallbacks)
|
||||
|
||||
function discordRPC.updatePresence(presence)
|
||||
local func = "discordRPC.updatePresence"
|
||||
checkArg(presence, "table", "presence", func)
|
||||
|
||||
-- -1 for string length because of 0-termination
|
||||
checkStrArg(presence.state, 127, "presence.state", func, true)
|
||||
checkStrArg(presence.details, 127, "presence.details", func, true)
|
||||
|
||||
checkIntArg(presence.startTimestamp, 64, "presence.startTimestamp", func, true)
|
||||
checkIntArg(presence.endTimestamp, 64, "presence.endTimestamp", func, true)
|
||||
|
||||
checkStrArg(presence.largeImageKey, 31, "presence.largeImageKey", func, true)
|
||||
checkStrArg(presence.largeImageText, 127, "presence.largeImageText", func, true)
|
||||
checkStrArg(presence.smallImageKey, 31, "presence.smallImageKey", func, true)
|
||||
checkStrArg(presence.smallImageText, 127, "presence.smallImageText", func, true)
|
||||
checkStrArg(presence.partyId, 127, "presence.partyId", func, true)
|
||||
|
||||
checkIntArg(presence.partySize, 32, "presence.partySize", func, true)
|
||||
checkIntArg(presence.partyMax, 32, "presence.partyMax", func, true)
|
||||
|
||||
checkStrArg(presence.matchSecret, 127, "presence.matchSecret", func, true)
|
||||
checkStrArg(presence.joinSecret, 127, "presence.joinSecret", func, true)
|
||||
checkStrArg(presence.spectateSecret, 127, "presence.spectateSecret", func, true)
|
||||
|
||||
checkIntArg(presence.instance, 8, "presence.instance", func, true)
|
||||
|
||||
local cpresence = ffi.new("struct DiscordRichPresence")
|
||||
cpresence.state = presence.state
|
||||
cpresence.details = presence.details
|
||||
cpresence.startTimestamp = presence.startTimestamp or 0
|
||||
cpresence.endTimestamp = presence.endTimestamp or 0
|
||||
cpresence.largeImageKey = presence.largeImageKey
|
||||
cpresence.largeImageText = presence.largeImageText
|
||||
cpresence.smallImageKey = presence.smallImageKey
|
||||
cpresence.smallImageText = presence.smallImageText
|
||||
cpresence.partyId = presence.partyId
|
||||
cpresence.partySize = presence.partySize or 0
|
||||
cpresence.partyMax = presence.partyMax or 0
|
||||
cpresence.matchSecret = presence.matchSecret
|
||||
cpresence.joinSecret = presence.joinSecret
|
||||
cpresence.spectateSecret = presence.spectateSecret
|
||||
cpresence.instance = presence.instance or 0
|
||||
|
||||
discordRPClib.Discord_UpdatePresence(cpresence)
|
||||
end
|
||||
|
||||
function discordRPC.clearPresence()
|
||||
discordRPClib.Discord_ClearPresence()
|
||||
end
|
||||
|
||||
local replyMap = {
|
||||
no = 0,
|
||||
yes = 1,
|
||||
ignore = 2
|
||||
}
|
||||
|
||||
-- maybe let reply take ints too (0, 1, 2) and add constants to the module
|
||||
function discordRPC.respond(userId, reply)
|
||||
checkStrArg(userId, nil, "userId", "discordRPC.respond")
|
||||
assert(replyMap[reply], "Argument 'reply' to discordRPC.respond has to be one of \"yes\", \"no\" or \"ignore\"")
|
||||
discordRPClib.Discord_Respond(userId, replyMap[reply])
|
||||
end
|
||||
|
||||
-- garbage collection callback
|
||||
getmetatable(discordRPC.gcDummy).__gc = function()
|
||||
discordRPC.shutdown()
|
||||
ready_proxy:free()
|
||||
disconnected_proxy:free()
|
||||
errored_proxy:free()
|
||||
joinGame_proxy:free()
|
||||
spectateGame_proxy:free()
|
||||
joinRequest_proxy:free()
|
||||
end
|
||||
|
||||
return discordRPC
|
@ -10,6 +10,7 @@ local function state(songName, songDifficulty)
|
||||
local logger = require("modules.logging")
|
||||
local socket = require("socket")
|
||||
local logging= require("modules.logging")
|
||||
local discord = require("modules.discord")
|
||||
-- I NEED THEM IMPORTS
|
||||
|
||||
local startTime = 0
|
||||
@ -71,6 +72,7 @@ local function state(songName, songDifficulty)
|
||||
shit = 0,
|
||||
miss = 0,
|
||||
}
|
||||
local score = 0
|
||||
|
||||
local rankWindows = {
|
||||
{
|
||||
@ -142,6 +144,8 @@ local function state(songName, songDifficulty)
|
||||
local deadBF
|
||||
local restart = false
|
||||
|
||||
local startTimestamp = os.time()
|
||||
|
||||
local function quit()
|
||||
if restart then return end
|
||||
playing = false
|
||||
@ -239,6 +243,8 @@ local function state(songName, songDifficulty)
|
||||
|
||||
notes[closestIndex] = nil
|
||||
closestNote:destroy()
|
||||
|
||||
score = score + rating.score
|
||||
end
|
||||
end
|
||||
|
||||
@ -291,7 +297,7 @@ local function state(songName, songDifficulty)
|
||||
-- gf:PlayAnimation("BF NOTE LEFT", 30, false)
|
||||
for name, character in next, characters do
|
||||
if not character.singing then
|
||||
if name == "gf" then
|
||||
if name == "gf" or character.animInfo.danceLeft then
|
||||
character:PlayAnimation("danceLeft")
|
||||
else
|
||||
character:PlayAnimation("idle")
|
||||
@ -300,10 +306,20 @@ local function state(songName, songDifficulty)
|
||||
end
|
||||
if beat % 4 == 0 then
|
||||
zoom = zoom + .1
|
||||
discord.updatePresence({
|
||||
details = string.format("Playing %s on difficulty %s", songName, songDifficulty),
|
||||
largeImageKey = "bigimage",
|
||||
startTimestamp = startTimestamp,
|
||||
state = string.format("Score: %s", score)
|
||||
})
|
||||
end
|
||||
else
|
||||
if characters.gf and not characters.gf.singing then
|
||||
characters.gf:PlayAnimation("danceRight")
|
||||
for name, character in next, characters do
|
||||
if not character.singing then
|
||||
if name == "gf" or character.animInfo.danceLeft then
|
||||
character:PlayAnimation("danceRight")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -336,9 +352,9 @@ local function state(songName, songDifficulty)
|
||||
myTypes.updateSprites(dt)
|
||||
|
||||
for name, character in next, characters do
|
||||
if name ~= "gf" and character.sprite.animation ~= "idle" and character.sprite.ended then
|
||||
if name ~= "gf" and character.animInfo.idle and character.sprite.animation ~= "idle" and character.sprite.ended then
|
||||
character:PlayAnimation("idle")
|
||||
elseif name == "gf" and character.singing and character.sprite.animation ~= "danceLeft" and character.sprite.ended then
|
||||
elseif (name == "gf" or character.animInfo.danceLeft) and character.singing and character.sprite.animation ~= "danceLeft" and character.sprite.ended then
|
||||
character:PlayAnimation("danceLeft")
|
||||
end
|
||||
end
|
||||
@ -365,7 +381,7 @@ local function state(songName, songDifficulty)
|
||||
for index, note in next, notes do
|
||||
if note.mustPress then
|
||||
note.sprite.position = myTypes.Vector2(600 + (79 * (note.direction - 1)), settings.Downscroll and 430 - (note.position-elapsed) * speed or (note.position - elapsed) * speed)
|
||||
if note.position - elapsed < -150 then
|
||||
if (note.position - elapsed) * speed < -150 then
|
||||
note:destroy()
|
||||
miss:stop()
|
||||
miss:play()
|
||||
@ -373,10 +389,11 @@ local function state(songName, songDifficulty)
|
||||
notes[index] = nil
|
||||
ratings.miss = ratings.miss + 1
|
||||
health = health - note.missHealth
|
||||
score = score - 200
|
||||
end
|
||||
else
|
||||
note.sprite.position = myTypes.Vector2(50 + 79 * (note.direction - 1), settings.Downscroll and 430 - (note.position-elapsed) * speed or (note.position - elapsed) * speed)
|
||||
if note.position - elapsed < 10 then
|
||||
if (note.position - elapsed) * speed < 10 then
|
||||
notes[index] = nil
|
||||
if section.gfSection or chart.song == "Tutorial" then
|
||||
if section.altAnim or note.altAnim then
|
||||
@ -400,7 +417,7 @@ local function state(songName, songDifficulty)
|
||||
for index, hold in next, holdNotes do
|
||||
if hold.mustPress then
|
||||
hold.sprite.position = myTypes.Vector2(625 + (79 * (hold.direction - 1)), settings.Downscroll and 430 - (hold.position-elapsed) * speed or (hold.position - elapsed) * speed)
|
||||
if hold.position - elapsed < 10 then
|
||||
if (hold.position - elapsed) * speed < 10 then
|
||||
if love.keyboard.isDown(keyBinds[hold.direction]) then
|
||||
if characters.bf.animInfo["sing"..directions[hold.direction].."-alt"] and (section.altAnim or hold.altAnim) then
|
||||
characters.bf:PlayAnimation("sing"..directions[hold.direction].."-alt")
|
||||
@ -409,20 +426,17 @@ local function state(songName, songDifficulty)
|
||||
end
|
||||
hold:destroy()
|
||||
holdNotes[index] = nil
|
||||
health = health + hold.hitHealth * 0.1
|
||||
elseif hold.position - elapsed < -150 then
|
||||
health = health + hold.hitHealth * 0.2
|
||||
elseif (hold.position - elapsed) * speed < -150 then
|
||||
hold:destroy()
|
||||
miss:stop()
|
||||
miss:play()
|
||||
characters.bf:PlayAnimation("sing"..directions[hold.direction].."miss")
|
||||
holdNotes[index] = nil
|
||||
ratings.miss = ratings.miss + 1
|
||||
health = health - hold.missHealth * 0.1
|
||||
health = health - hold.missHealth * 0.2
|
||||
end
|
||||
end
|
||||
else
|
||||
hold.sprite.position = myTypes.Vector2(75 + (79 * (hold.direction - 1)), settings.Downscroll and 430 - (hold.position-elapsed) * speed or (hold.position - elapsed) * speed)
|
||||
if hold.position - elapsed < 10 then
|
||||
if (hold.position - elapsed) * speed < 10 then
|
||||
if characters.dad.animInfo["sing"..directions[hold.direction].."-alt"] and (section.altAnim or hold.altAnim) then
|
||||
characters.dad:PlayAnimation("sing"..directions[hold.direction].."-alt")
|
||||
else
|
||||
@ -554,7 +568,8 @@ local function state(songName, songDifficulty)
|
||||
if chart.player2 ~= "none" then -- you can have no player2 but always player1
|
||||
characters.dad = myTypes.character(chart.player2)
|
||||
characters.dad.stagePosition = myTypes.Vector2(stage.opponent[1], stage.opponent[2])
|
||||
characters.dad:PlayAnimation("idle")
|
||||
|
||||
characters.dad:PlayAnimation(characters.dad.animInfo.idle and "idle" or "danceLeft")
|
||||
local image = love.graphics.newImage(string.format("images/icons/icon-%s.png", characters.dad.icon))
|
||||
icons.dad = {image = image, alive = love.graphics.newQuad(0,0, 150, 150, image), dead = love.graphics.newQuad(150, 0, 150, 150, image)}
|
||||
end
|
||||
@ -651,6 +666,15 @@ local function state(songName, songDifficulty)
|
||||
playing = true
|
||||
|
||||
startTime = socket.gettime()
|
||||
|
||||
startTimestamp = os.time()
|
||||
|
||||
discord.updatePresence({
|
||||
details = string.format("Playing %s on difficulty %s", songName, songDifficulty),
|
||||
largeImageKey = "bigimage",
|
||||
startTimestamp = startTimestamp,
|
||||
state = "Score: 0"
|
||||
})
|
||||
end
|
||||
|
||||
function state.keypressed(key, un, is)
|
||||
@ -664,6 +688,14 @@ local function state(songName, songDifficulty)
|
||||
voices:pause()
|
||||
end
|
||||
pauseStart = socket.gettime() * 1000
|
||||
|
||||
local pauseStamp = os.time()
|
||||
discord.updatePresence({
|
||||
details = string.format("Paused %s on difficulty %s", songName, songDifficulty),
|
||||
largeImageKey = "bigimage",
|
||||
startTimestamp = pauseStamp,
|
||||
state = string.format("Score: %s", score)
|
||||
})
|
||||
else
|
||||
inst:play()
|
||||
if chart.needsVoices then
|
||||
|
@ -87,11 +87,18 @@ function module.Sprite(image, sheet)
|
||||
end
|
||||
end
|
||||
|
||||
function Sprite:PlayAnimation(name, fps, loop)
|
||||
function Sprite:PlayAnimation(name, fps, loop, allowed)
|
||||
self.animation = name
|
||||
self.fps = fps
|
||||
self.looping = loop
|
||||
self.frame = 1
|
||||
|
||||
if self.allowedFrames then
|
||||
self.allowedFrame = 1
|
||||
else
|
||||
self.frame = 0
|
||||
end
|
||||
|
||||
|
||||
self.ended = false
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user