forked from TecProg-grupo4-2018-2/panel-attack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Game.lua
256 lines (222 loc) · 9.1 KB
/
Game.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
local consts = require("consts")
require("TimeQueue")
-- The main game object for tracking everything in Panel Attack.
-- Not to be confused with "Match" which is the current battle / instance of the game.
Game =
class(
function(self)
self.scores = require("scores")
self.match = nil -- Match - the current match going on or nil if inbetween games
self.battleRoom = nil -- BattleRoom - the current room being used for battles
self.focused = true -- if the window is focused
self.backgroundImage = nil -- the background image for the game, should always be set to something with the proper dimensions
self.droppedFrames = 0
self.puzzleSets = {} -- all the puzzles loaded into the game
self.gameIsPaused = false -- game can be paused while playing on local
self.renderDuringPause = false -- if the game can render when you are paused
self.currently_paused_tracks = {} -- list of tracks currently paused
self.rich_presence = nil
self.muteSoundEffects = false
self.canvasX = 0
self.canvasY = 0
self.canvasXScale = 1
self.canvasYScale = 1
self.availableScales = {1, 1.5, 2, 2.5, 3}
self.showGameScale = false
self.needsAssetReload = false
self.previousWindowWidth = 0
self.previousWindowHeight = 0
self.sendNetworkQueue = TimeQueue()
self.receiveNetworkQueue = TimeQueue()
end
)
function Game:update(dt)
updateNetwork(dt)
end
function Game.clearMatch(self)
if self.match then
self.match:deinit()
self.match = nil
end
self:reset()
end
function Game:reset()
self.gameIsPaused = false
self.renderDuringPause = false
self.preventSounds = false
self.currently_paused_tracks = {}
self.muteSoundEffects = false
P1 = nil
P2 = nil
end
function Game.errorData(errorString, traceBack)
local system_info = "OS: " .. love.system.getOS()
local loveVersion = Game.loveVersionString() or "Unknown"
local username = config.name or "Unknown"
local buildVersion = GAME_UPDATER_GAME_VERSION or "Unknown"
local systemInfo = system_info or "Unknown"
local errorData = {
stack = traceBack,
name = username,
error = errorString,
engine_version = VERSION,
release_version = buildVersion,
operating_system = systemInfo,
love_version = loveVersion,
theme = config.theme
}
if GAME.match then
errorData.matchInfo = GAME.match:getInfo()
end
return errorData
end
function Game.detailedErrorLogString(errorData)
local newLine = "\n"
local now = os.date("*t", to_UTC(os.time()))
local formattedTime = string.format("%04d-%02d-%02d %02d:%02d:%02d", now.year, now.month, now.day, now.hour, now.min, now.sec)
local detailedErrorLogString =
"Stack Trace: " .. errorData.stack .. newLine ..
"Username: " .. errorData.name .. newLine ..
"Theme: " .. errorData.theme .. newLine ..
"Error Message: " .. errorData.error .. newLine ..
"Engine Version: " .. errorData.engine_version .. newLine ..
"Build Version: " .. errorData.release_version .. newLine ..
"Operating System: " .. errorData.operating_system .. newLine ..
"Love Version: " .. errorData.love_version .. newLine ..
"UTC Time: " .. formattedTime
if errorData.matchInfo then
detailedErrorLogString = detailedErrorLogString .. newLine ..
errorData.matchInfo.mode .. " Match Info: " .. newLine ..
" Stage: " .. errorData.matchInfo.stage .. newLine ..
" Stacks: "
for i = 1, #errorData.matchInfo.stacks do
local stack = errorData.matchInfo.stacks[i]
detailedErrorLogString = detailedErrorLogString .. newLine ..
" P" .. i .. ": " .. newLine ..
" Player Number: " .. stack.playerNumber .. newLine ..
" Character: " .. stack.character .. newLine ..
" Panels: " .. stack.panels .. newLine ..
" Rollback Count: " .. stack.rollbackCount .. newLine ..
" Rollback Frames Saved: " .. stack.rollbackCopyCount
end
end
return detailedErrorLogString
end
local loveVersionStringValue = nil
function Game.loveVersionString()
if loveVersionStringValue then
return loveVersionStringValue
end
local major, minor, revision, codename = love.getVersion()
loveVersionStringValue = string.format("%d.%d.%d", major, minor, revision)
return loveVersionStringValue
end
-- Calculates the proper dimensions to not stretch the game for various sizes
function scale_letterbox(width, height, w_ratio, h_ratio)
if height / h_ratio > width / w_ratio then
local scaled_height = h_ratio * width / w_ratio
return 0, (height - scaled_height) / 2, width, scaled_height
end
local scaled_width = w_ratio * height / h_ratio
return (width - scaled_width) / 2, 0, scaled_width, height
end
-- Updates the scale and position values to use up the right size of the window based on the user's settings.
function Game:updateCanvasPositionAndScale(newWindowWidth, newWindowHeight)
local scaleIsUpdated = false
if config.gameScaleType ~= "fit" then
local availableScales = shallowcpy(self.availableScales)
if config.gameScaleType == "fixed" then
availableScales = {config.gameScaleFixedValue}
end
-- Handle both "auto" and a fixed scale
-- Go from biggest to smallest and used the highest one that still fits
for i = #availableScales, 1, -1 do
local scale = availableScales[i]
if config.gameScaleType ~= "auto" or
(newWindowWidth >= canvas_width * scale and newWindowHeight >= canvas_height * scale) then
GAME.canvasXScale = scale
GAME.canvasYScale = scale
GAME.canvasX = math.floor((newWindowWidth - (scale * canvas_width)) / 2)
GAME.canvasY = math.floor((newWindowHeight - (scale * canvas_height)) / 2)
scaleIsUpdated = true
break
end
end
end
if scaleIsUpdated == false then
-- The only thing left to do is scale to fit the window
local w, h
GAME.canvasX, GAME.canvasY, w, h = scale_letterbox(newWindowWidth, newWindowHeight, 16, 9)
GAME.canvasXScale = w / canvas_width
GAME.canvasYScale = h / canvas_height
end
GAME.previousWindowWidth = newWindowWidth
GAME.previousWindowHeight = newWindowHeight
end
-- Provides a scale that is on .5 boundary to make sure it renders well.
-- Useful for creating new canvas with a solid DPI
function Game:newCanvasSnappedScale()
local result = math.max(1, math.floor(self.canvasXScale*2)/2)
return result
end
-- Reloads the canvas and all images / fonts for the new game scale
function Game:refreshCanvasAndImagesForNewScale()
if themes == nil or themes[config.theme] == nil then
return -- EARLY RETURN, assets haven't loaded the first time yet
-- they will load through the normal process
end
GAME:drawLoadingString(loc("ld_characters"))
coroutine.yield()
self.globalCanvas = love.graphics.newCanvas(canvas_width, canvas_height, {dpiscale=GAME:newCanvasSnappedScale()})
-- We need to reload all assets and fonts to get the new scaling info and filters
-- Reload theme to get the new resolution assets
themes[config.theme]:graphics_init()
themes[config.theme]:final_init()
-- Reload stages to get the new resolution assets
stages_reload_graphics()
-- Reload panels to get the new resolution assets
panels_init()
-- Reload characters to get the new resolution assets
characters_reload_graphics()
-- Reload loc to get the new font
localization:set_language(config.language_code)
for _, menu in pairs(CLICK_MENUS) do
menu:reloadGraphics()
end
end
-- Transform from window coordinates to game coordinates
function Game:transform_coordinates(x, y)
return (x - self.canvasX) / self.canvasXScale, (y - self.canvasY) / self.canvasYScale
end
function Game:drawLoadingString(loadingString)
local textMaxWidth = 300
local textHeight = 40
local x = 0
local y = canvas_height/2 - textHeight/2
local backgroundPadding = 10
grectangle_color("fill", (canvas_width / 2 - (textMaxWidth/2)) / GFX_SCALE , (y - backgroundPadding) / GFX_SCALE, textMaxWidth/GFX_SCALE, textHeight/GFX_SCALE, 0, 0, 0, 0.5)
gprintf(loadingString, x, y, canvas_width, "center", nil, nil, 10)
end
function Game:setupFileSystem()
-- create folders in appdata for those who don't have them already
love.filesystem.createDirectory("characters")
love.filesystem.createDirectory("panels")
love.filesystem.createDirectory("themes")
love.filesystem.createDirectory("stages")
love.filesystem.createDirectory("training")
local oldServerDirectory = consts.SERVER_SAVE_DIRECTORY .. consts.LEGACY_SERVER_LOCATION
local newServerDirectory = consts.SERVER_SAVE_DIRECTORY .. consts.SERVER_LOCATION
if not love.filesystem.getInfo(newServerDirectory) then
love.filesystem.createDirectory(newServerDirectory)
-- Move the old user ID spot to the new folder (we won't delete the old one for backwards compatibility and safety)
if love.filesystem.getInfo(oldServerDirectory) then
local userID = read_user_id_file(consts.LEGACY_SERVER_LOCATION)
write_user_id_file(userID, consts.SERVER_LOCATION)
end
end
if #FileUtil.getFilteredDirectoryItems("training") == 0 then
recursive_copy("default_data/training", "training")
end
end
local game = Game()
return game