diff options
-rw-r--r-- | apps/plugins/boomshine.lua | 698 |
1 files changed, 435 insertions, 263 deletions
diff --git a/apps/plugins/boomshine.lua b/apps/plugins/boomshine.lua index c7ed6dfdf1..fcdf7c9a1c 100644 --- a/apps/plugins/boomshine.lua +++ b/apps/plugins/boomshine.lua | |||
@@ -11,7 +11,7 @@ | |||
11 | See http://www.yvoschaap.com/chainrxn/ and http://www.k2xl.com/games/boomshine/ | 11 | See http://www.yvoschaap.com/chainrxn/ and http://www.k2xl.com/games/boomshine/ |
12 | 12 | ||
13 | Copyright (C) 2009 by Maurus Cuelenaere | 13 | Copyright (C) 2009 by Maurus Cuelenaere |
14 | Copyright (C) 2018 William Wilgus -- Added circles, logic rewrite, hard levels | 14 | Copyright (C) 2020 William Wilgus -- Added circles, logic rewrite, hard levels |
15 | 15 | ||
16 | This program is free software; you can redistribute it and/or | 16 | This program is free software; you can redistribute it and/or |
17 | modify it under the terms of the GNU General Public License | 17 | modify it under the terms of the GNU General Public License |
@@ -23,7 +23,9 @@ | |||
23 | 23 | ||
24 | ]]-- | 24 | ]]-- |
25 | require "actions" | 25 | require "actions" |
26 | --[[only save the actions we are using]] | 26 | local DEBUG = false |
27 | |||
28 | --[[only save the actions we are using]]---------------------------------------- | ||
27 | pla = {} | 29 | pla = {} |
28 | for key, val in pairs(rb.actions) do | 30 | for key, val in pairs(rb.actions) do |
29 | for _, v in ipairs({"PLA_", "TOUCHSCREEN", "_NONE"}) do | 31 | for _, v in ipairs({"PLA_", "TOUCHSCREEN", "_NONE"}) do |
@@ -33,15 +35,32 @@ for key, val in pairs(rb.actions) do | |||
33 | end | 35 | end |
34 | end | 36 | end |
35 | rb.actions, rb.contexts = nil, nil | 37 | rb.actions, rb.contexts = nil, nil |
36 | -------------------------------------- | 38 | -------------------------------------------------------------------------------- |
39 | |||
40 | |||
41 | --[[ Profiling ]]--------------------------------------------------------------- | ||
42 | local screen_redraw_count = 0 | ||
43 | local screen_redraw_duration = 0 | ||
44 | -------------------------------------------------------------------------------- | ||
45 | |||
37 | 46 | ||
47 | --[[ References ]]-------------------------------------------------------------- | ||
38 | local _LCD = rb.lcd_framebuffer() | 48 | local _LCD = rb.lcd_framebuffer() |
39 | local rocklib_image = getmetatable(_LCD) | 49 | local rocklib_image = getmetatable(_LCD) |
40 | local _ellipse = rocklib_image.ellipse | 50 | local _ellipse = rocklib_image.ellipse-- |
41 | local BSAND = 0x8 | 51 | local irand = math.random-- |
42 | local irand = math.random | 52 | local lcd_putsxy = rb.lcd_putsxy-- |
43 | 53 | local strfmt = string.format-- | |
54 | local Cursor_Ref = nil | ||
55 | local Ball_Ref = {} | ||
56 | -------------------------------------------------------------------------------- | ||
57 | |||
58 | |||
59 | --[[ 'Constants' ]]------------------------------------------------------------- | ||
60 | local SCORE_MULTIPLY = 10 | ||
61 | local BSAND = 0x8-- | ||
44 | local HAS_TOUCHSCREEN = rb.action_get_touchscreen_press ~= nil | 62 | local HAS_TOUCHSCREEN = rb.action_get_touchscreen_press ~= nil |
63 | local Empty_fn = function() end | ||
45 | local LCD_H, LCD_W = rb.LCD_HEIGHT, rb.LCD_WIDTH | 64 | local LCD_H, LCD_W = rb.LCD_HEIGHT, rb.LCD_WIDTH |
46 | local DEFAULT_BALL_SZ = LCD_H > LCD_W and LCD_W / 30 or LCD_H / 30 | 65 | local DEFAULT_BALL_SZ = LCD_H > LCD_W and LCD_W / 30 or LCD_H / 30 |
47 | DEFAULT_BALL_SZ = DEFAULT_BALL_SZ - bit.band(DEFAULT_BALL_SZ, 1) | 66 | DEFAULT_BALL_SZ = DEFAULT_BALL_SZ - bit.band(DEFAULT_BALL_SZ, 1) |
@@ -61,10 +80,16 @@ end | |||
61 | 80 | ||
62 | local FMT_EXPEND, FMT_LEVEL = "%d balls expended", "Level %d" | 81 | local FMT_EXPEND, FMT_LEVEL = "%d balls expended", "Level %d" |
63 | local FMT_TOTPTS, FMT_LVPTS = "%d total points", "%d level points" | 82 | local FMT_TOTPTS, FMT_LVPTS = "%d total points", "%d level points" |
83 | -------------------------------------------------------------------------------- | ||
84 | |||
85 | |||
86 | --[[ Other ]]------------------------------------------------------------------- | ||
87 | local Player_Added | ||
88 | local Action_Evt = pla.ACTION_NONE | ||
64 | 89 | ||
65 | local levels = { | 90 | local levels = { |
66 | -- {GOAL, TOTAL_BALLS}, | 91 | -- {GOAL, TOTAL_BALLS}, |
67 | {1, 5}, | 92 | {1, 5}, |
68 | {2, 10}, | 93 | {2, 10}, |
69 | {4, 15}, | 94 | {4, 15}, |
70 | {6, 20}, | 95 | {6, 20}, |
@@ -85,7 +110,21 @@ local levels = { | |||
85 | {4, 5}, | 110 | {4, 5}, |
86 | {5, 5} | 111 | {5, 5} |
87 | } | 112 | } |
113 | -------------------------------------------------------------------------------- | ||
88 | 114 | ||
115 | |||
116 | --[[ Event Callback ]]---------------------------------------------------------- | ||
117 | function action_event(action) | ||
118 | if action == pla.PLA_CANCEL then | ||
119 | Action_Evt = pla.PLA_EXIT | ||
120 | else | ||
121 | Action_Evt = action | ||
122 | end | ||
123 | end | ||
124 | -------------------------------------------------------------------------------- | ||
125 | |||
126 | |||
127 | --[[ Helper functions ]]-------------------------------------------------------- | ||
89 | local function getstringsize(str) | 128 | local function getstringsize(str) |
90 | local _, w, h = rb.font_getstringsize(str, rb.FONT_UI) | 129 | local _, w, h = rb.font_getstringsize(str, rb.FONT_UI) |
91 | return w, h | 130 | return w, h |
@@ -97,90 +136,180 @@ local function set_foreground(color) | |||
97 | end | 136 | end |
98 | end | 137 | end |
99 | 138 | ||
100 | local function random_color() | 139 | local function calc_score(total, level, goal, expended) |
101 | if rb.lcd_rgbpack ~= nil then -- color target | 140 | local bonus = 0 |
102 | return rb.lcd_rgbpack(irand(1,255), irand(1,255), irand(1,255)) | 141 | local score = (expended * level) * SCORE_MULTIPLY |
142 | if expended < goal then | ||
143 | score = -(score + (level * SCORE_MULTIPLY)) | ||
144 | elseif expended > goal then | ||
145 | bonus = (expended - goal) * (level * SCORE_MULTIPLY) | ||
146 | end | ||
147 | total = total + score + bonus | ||
148 | return total, score, bonus | ||
149 | end | ||
150 | |||
151 | local function wait_anykey(to_secs) | ||
152 | rb.sleep(rb.HZ / 2) | ||
153 | rb.button_clear_queue() | ||
154 | rb.button_get_w_tmo(rb.HZ * to_secs) | ||
155 | end | ||
156 | |||
157 | local function disp_msg(to, ...) | ||
158 | local message = strfmt(...) | ||
159 | local w, h = getstringsize(message) | ||
160 | local x, y = (LCD_W - w) / 2, (LCD_H - h) / 2 | ||
161 | |||
162 | rb.lcd_clear_display() | ||
163 | set_foreground(DEFAULT_FG_CLR) | ||
164 | |||
165 | if w > LCD_W then | ||
166 | rb.lcd_puts_scroll(0, (y / h), message) | ||
167 | else | ||
168 | lcd_putsxy(x, y, message) | ||
169 | end | ||
170 | |||
171 | if to == -1 then | ||
172 | local msg = "Press button to exit" | ||
173 | w, h = getstringsize(msg) | ||
174 | x = (LCD_W - w) / 2 | ||
175 | if x < 0 then | ||
176 | rb.lcd_puts_scroll(0, (y / h) + 1, msg) | ||
177 | else | ||
178 | lcd_putsxy(x, y + h, msg) | ||
179 | end | ||
180 | end | ||
181 | rb.lcd_update() | ||
182 | |||
183 | if to == -1 then | ||
184 | wait_anykey(60) | ||
185 | else | ||
186 | rb.sleep(to) | ||
103 | end | 187 | end |
104 | 188 | ||
105 | local color = irand(1, rb.LCD_DEPTH) | 189 | rb.lcd_scroll_stop() -- Stop our scrolling message |
106 | color = (rb.LCD_DEPTH == 2) and (3 - color) or color -- invert for 2-bit screens | 190 | end |
107 | 191 | ||
108 | return color | 192 | local function test_speed() |
193 | local test_spd, redraw, dur = start_round(0, 0, 0, 0) -- test speed of target | ||
194 | --Logic speed, screen redraw, duration | ||
195 | if DEBUG == true then | ||
196 | disp_msg(rb.HZ * 5, "Spd: %d, Redraw: %d Dur: %d Ms", test_spd, redraw, dur) | ||
197 | end | ||
198 | if test_spd < 25 or redraw < 10 then | ||
199 | rb.splash(rb.HZ, "Slow Target..") | ||
200 | |||
201 | if test_spd < 10 then | ||
202 | MAX_BALL_SPEED = MAX_BALL_SPEED + MAX_BALL_SPEED | ||
203 | elseif test_spd < 15 then | ||
204 | MAX_BALL_SPEED = MAX_BALL_SPEED + MAX_BALL_SPEED / 2 | ||
205 | elseif test_spd < 25 then | ||
206 | MAX_BALL_SPEED = MAX_BALL_SPEED + MAX_BALL_SPEED / 4 | ||
207 | end | ||
208 | end | ||
109 | end | 209 | end |
210 | -------------------------------------------------------------------------------- | ||
110 | 211 | ||
212 | |||
213 | --[[ Ball Functions ]]---------------------------------------------------------- | ||
111 | local Ball = { | 214 | local Ball = { |
112 | -- Ball defaults | 215 | -- Ball defaults |
113 | sz = DEFAULT_BALL_SZ, | 216 | sz = DEFAULT_BALL_SZ, |
114 | next_tick = 0, | 217 | next_tick = 0, |
115 | state = B_MOVE | 218 | state = B_MOVE, |
116 | } | 219 | } |
117 | 220 | ||
118 | function Ball:new(o, level) | 221 | function Ball:new(o, level, color) |
222 | local function random_color() | ||
223 | if color == nil then | ||
224 | if rb.lcd_rgbpack ~= nil then -- color target | ||
225 | return rb.lcd_rgbpack(irand(1,255), irand(1,255), irand(1,255)) | ||
226 | end | ||
227 | color = irand(1, rb.LCD_DEPTH) | ||
228 | color = (rb.LCD_DEPTH == 2) and (3 - color) or color -- invert for 2-bit screens | ||
229 | end | ||
230 | return color | ||
231 | end | ||
232 | |||
119 | if o == nil then | 233 | if o == nil then |
120 | level = level or 1 | 234 | level = level or 1 |
121 | local maxdelay = (level <= 5) and 10 or level | 235 | local maxdelay = (level <= 5) and 15 or level * 2 |
122 | o = { | 236 | o = { |
123 | x = irand(1, LCD_W - self.sz), | 237 | x = irand(1, LCD_W - self.sz), |
124 | y = irand(1, LCD_H - self.sz), | 238 | y = irand(1, LCD_H - self.sz), |
125 | color = random_color(), | 239 | color = random_color(), |
126 | xi = Ball:genSpeed(), | 240 | xi = self.genSpeed(), -- x increment; x + sz after explode |
127 | yi = Ball:genSpeed(), | 241 | yi = self.genSpeed(), -- y increment; y + sz after explode |
128 | step_delay = irand(3, maxdelay / 2), | 242 | step_delay = irand(3, maxdelay / 2), |
129 | explosion_sz = irand(2 * self.sz, 4 * self.sz), | 243 | explosion_sz = irand(2 * self.sz, 4 * self.sz), |
130 | life_ticks = irand(rb.HZ / level, rb.HZ * (maxdelay / 5)) | 244 | life_ticks = irand(rb.HZ / level, rb.HZ * (maxdelay / 5)), |
245 | draw_fn = nil, | ||
246 | step_fn = self.step -- reference to current stepping function | ||
131 | } | 247 | } |
132 | end | 248 | end |
133 | o.life_ticks = o.life_ticks + DEFAULT_BALL_SZ -- extra time for larger screens | 249 | local Ball = o or {} -- so we can use Ball. instead of self |
250 | |||
251 | -- these functions end up in a closure; faster to call, use more RAM | ||
252 | function Ball.draw() | ||
253 | _ellipse(_LCD, o.x, o.y, o.x + o.sz, o.y + o.sz, o.color, o.color, true) | ||
254 | end | ||
255 | |||
256 | function Ball.draw_exploded() | ||
257 | _ellipse(_LCD, o.x, o.y, o.xi, o.yi, o.color, nil, true) | ||
258 | end | ||
259 | |||
260 | if Ball.draw_fn == nil then | ||
261 | Ball.draw_fn = Ball.draw -- reference to current drawing function | ||
262 | end | ||
263 | |||
134 | setmetatable(o, self) | 264 | setmetatable(o, self) |
135 | self.__index = self | 265 | self.__index = self |
136 | return o | 266 | return o |
137 | end | 267 | end |
138 | 268 | ||
269 | -- these functions are shared by reference, slower to call, use less RAM | ||
139 | function Ball:genSpeed() | 270 | function Ball:genSpeed() |
140 | local speed = irand(-MAX_BALL_SPEED, MAX_BALL_SPEED) | 271 | local speed = irand(-MAX_BALL_SPEED, MAX_BALL_SPEED) |
141 | return speed ~= 0 and speed or MAX_BALL_SPEED -- Make sure all balls move | 272 | return speed ~= 0 and speed or MAX_BALL_SPEED -- Make sure all balls move |
142 | end | 273 | end |
143 | 274 | ||
144 | function Ball:draw() | ||
145 | _ellipse(_LCD, self.x, self.y, | ||
146 | self.x + self.sz, self.y + self.sz , self.color, self.color, true) | ||
147 | end | ||
148 | |||
149 | function Ball:step(tick) | 275 | function Ball:step(tick) |
276 | local function rndspeed(cur) | ||
277 | local speed = cur + irand(-2, 2) | ||
278 | if speed < -MAX_BALL_SPEED then | ||
279 | speed = -MAX_BALL_SPEED | ||
280 | elseif speed > MAX_BALL_SPEED then | ||
281 | speed = MAX_BALL_SPEED | ||
282 | elseif speed == 0 then | ||
283 | speed = cur | ||
284 | end | ||
285 | return speed | ||
286 | end | ||
287 | |||
150 | self.next_tick = tick + self.step_delay | 288 | self.next_tick = tick + self.step_delay |
151 | self.x = self.x + self.xi | 289 | self.x = self.x + self.xi |
152 | self.y = self.y + self.yi | 290 | self.y = self.y + self.yi |
291 | local max_x = LCD_W - self.sz | ||
292 | local max_y = LCD_H - self.sz | ||
153 | 293 | ||
154 | if (self.x <= 0 or self.x >= (LCD_W - self.sz)) then | 294 | if self.x <= 0 then |
155 | self.xi = -self.xi | 295 | self.xi = -self.xi |
156 | self.x = self.x + self.xi | 296 | self.x = 1 |
297 | self.yi = rndspeed(self.yi) | ||
298 | elseif self.x >= max_x then | ||
299 | self.xi = -self.xi | ||
300 | self.x = max_x | ||
301 | self.yi = rndspeed(self.yi) | ||
157 | end | 302 | end |
158 | 303 | ||
159 | if (self.y <= 0 or self.y >= (LCD_H - self.sz)) then | 304 | if self.y <= 0 then |
160 | self.yi = -self.yi | 305 | self.yi = -self.yi |
161 | self.y = self.y + self.yi | 306 | self.y = 1 |
162 | end | 307 | self.xi = rndspeed(self.xi) |
163 | end | 308 | elseif self.y >= max_y then |
164 | 309 | self.yi = -self.yi | |
165 | function Ball:checkHit(other) | 310 | self.y = max_y |
166 | if (other.xi >= self.x) and (other.yi >= self.y) and | 311 | self.xi = rndspeed(self.xi) |
167 | (self.x + self.sz >= other.x) and (self.y + self.sz >= other.y) then | ||
168 | self.state = B_EXPLODE | ||
169 | -- x/y increment no longer needed it is now impact region | ||
170 | self.xi = self.x + self.sz | ||
171 | self.yi = self.y + self.sz | ||
172 | |||
173 | if other.state < B_EXPLODE then -- add duration to the ball that got hit | ||
174 | other.next_tick = other.next_tick + self.life_ticks | ||
175 | end | ||
176 | return true | ||
177 | end | 312 | end |
178 | |||
179 | return false | ||
180 | end | ||
181 | |||
182 | function Ball:draw_exploded() | ||
183 | _ellipse(_LCD, self.x, self.y, self.xi, self.yi, self.color, nil, true) | ||
184 | end | 313 | end |
185 | 314 | ||
186 | function Ball:step_exploded(tick) | 315 | function Ball:step_exploded(tick) |
@@ -188,20 +317,24 @@ function Ball:step_exploded(tick) | |||
188 | -- B_EXPLODE >> B_DIE >> BWAIT >> B_IMPLODE >> B_DEAD | 317 | -- B_EXPLODE >> B_DIE >> BWAIT >> B_IMPLODE >> B_DEAD |
189 | if self.state == B_EXPLODE and self.sz < self.explosion_sz then | 318 | if self.state == B_EXPLODE and self.sz < self.explosion_sz then |
190 | self.sz = self.sz + 2 | 319 | self.sz = self.sz + 2 |
191 | self.x = self.x - 1 -- We do this because we want to stay centered | 320 | self.x = self.x - 1 -- stay centered |
192 | self.y = self.y - 1 | 321 | self.y = self.y - 1 |
193 | elseif self.state == B_DIE then | 322 | elseif self.state == B_DIE then |
194 | self.state = B_WAIT | 323 | self.state = B_WAIT |
195 | self.next_tick = tick + self.life_ticks | 324 | self.next_tick = tick + self.life_ticks |
196 | return | 325 | return |
197 | elseif self.state == B_IMPLODE and self.sz > 0 then | 326 | elseif self.state == B_IMPLODE then |
198 | self.sz = self.sz - 2 | 327 | if self.sz > 0 then |
199 | self.x = self.x + 1 -- We do this because we want to stay centered | 328 | self.sz = self.sz - 2 |
200 | self.y = self.y + 1 | 329 | self.x = self.x + 1 -- stay centered |
201 | elseif self.state <= B_IMPLODE then | 330 | self.y = self.y + 1 |
202 | self.state = B_DEAD | 331 | else |
203 | return | 332 | self.state = B_DEAD |
204 | elseif self.next_tick < tick then | 333 | self.draw_fn = Empty_fn |
334 | self.step_fn = Empty_fn | ||
335 | return B_DEAD | ||
336 | end | ||
337 | elseif self.next_tick < tick then -- decay to next lower state | ||
205 | self.state = self.state - 1 | 338 | self.state = self.state - 1 |
206 | return | 339 | return |
207 | end | 340 | end |
@@ -211,59 +344,90 @@ function Ball:step_exploded(tick) | |||
211 | self.yi = self.y + self.sz | 344 | self.yi = self.y + self.sz |
212 | end | 345 | end |
213 | 346 | ||
347 | function Ball:checkHit(other) | ||
348 | local x, y = self.x, self.y | ||
349 | if (other.xi >= x) and (other.yi >= y) then | ||
350 | local sz = self.sz | ||
351 | local xi, yi = x + sz, y + sz | ||
352 | if (xi >= other.x) and (yi >= other.y) then | ||
353 | -- update impact region | ||
354 | self.xi = xi | ||
355 | self.yi = yi | ||
356 | -- change to exploded state | ||
357 | self.state = B_EXPLODE | ||
358 | self.draw_fn = self.draw_exploded | ||
359 | self.step_fn = self.step_exploded | ||
360 | |||
361 | if other.state < B_EXPLODE then -- add duration to the ball that got hit | ||
362 | other.next_tick = other.next_tick + self.life_ticks | ||
363 | end | ||
364 | return true | ||
365 | end | ||
366 | end | ||
367 | |||
368 | return false | ||
369 | end | ||
370 | -------------------------------------------------------------------------------- | ||
371 | |||
372 | |||
373 | --[[ Cursor Functions ]]-------------------------------------------------------- | ||
214 | local Cursor = { | 374 | local Cursor = { |
215 | sz = (DEFAULT_BALL_SZ * 2), | 375 | sz = (DEFAULT_BALL_SZ * 2), |
216 | x = (LCD_W / 2), | 376 | x = (LCD_W / 2), |
217 | y = (LCD_H / 2), | 377 | y = (LCD_H / 2), |
218 | color = DEFAULT_FG_CLR | 378 | color = DEFAULT_FG_CLR |
379 | --image = nil | ||
219 | } | 380 | } |
220 | 381 | ||
221 | function Cursor:new() | 382 | function Cursor:new() |
222 | if rb.LCD_DEPTH == 2 then -- invert for 2 - bit screens | 383 | if rb.LCD_DEPTH == 2 then -- invert for 2 - bit screens |
223 | self.color = 3 - DEFAULT_FG_CLR | 384 | self.color = 3 - DEFAULT_FG_CLR |
224 | end | 385 | end |
225 | self:create_image(DEFAULT_BALL_SZ * 2) | 386 | if not HAS_TOUCHSCREEN and not self.image then |
226 | return self | 387 | local function create_image(sz) |
227 | end | 388 | sz = sz + 1 |
228 | 389 | local img = rb.new_image(sz, sz) | |
229 | function Cursor:create_image(sz) | 390 | local sz2 = (sz / 2) + 1 |
230 | if not HAS_TOUCHSCREEN then | 391 | local sz4 = (sz / 4) |
231 | sz = sz + 1 | 392 | |
232 | local img = rb.new_image(sz, sz) | 393 | img:clear(0) |
233 | local sz2 = (sz / 2) + 1 | 394 | img:line(1, 1, sz4 + 1, 1, 1) |
234 | local sz4 = (sz / 4) | 395 | img:line(1, 1, 1, sz4 + 1, 1) |
235 | 396 | ||
236 | img:clear(0) | 397 | img:line(1, sz, sz4 + 1, sz, 1) |
237 | img:line(1, 1, sz4 + 1, 1, 1) | 398 | img:line(1, sz, 1, sz - sz4, 1) |
238 | img:line(1, 1, 1, sz4 + 1, 1) | 399 | |
239 | 400 | img:line(sz, sz, sz - sz4, sz, 1) | |
240 | img:line(1, sz, sz4 + 1, sz, 1) | 401 | img:line(sz, sz, sz, sz - sz4, 1) |
241 | img:line(1, sz, 1, sz - sz4, 1) | 402 | |
242 | 403 | img:line(sz, 1, sz - sz4, 1, 1) | |
243 | img:line(sz, sz, sz - sz4, sz, 1) | 404 | img:line(sz, 1, sz, sz4 + 1, 1) |
244 | img:line(sz, sz, sz, sz - sz4, 1) | 405 | |
245 | 406 | -- crosshairs | |
246 | img:line(sz, 1, sz - sz4, 1, 1) | 407 | img:line(sz2 - sz4, sz2, sz2 + sz4, sz2, 1) |
247 | img:line(sz, 1, sz, sz4 + 1, 1) | 408 | img:line(sz2, sz2 - sz4, sz2, sz2 + sz4, 1) |
248 | 409 | return img | |
249 | -- crosshairs | 410 | end |
250 | img:line(sz2 - sz4, sz2, sz2 + sz4, sz2, 1) | 411 | self.image = create_image(DEFAULT_BALL_SZ * 2) |
251 | img:line(sz2, sz2 - sz4, sz2, sz2 + sz4, 1) | ||
252 | self.image = img | ||
253 | end | 412 | end |
254 | end | ||
255 | 413 | ||
256 | local function clamp_roll(iVal, iMin, iMax) | 414 | function Cursor.draw() |
257 | if iVal < iMin then | 415 | rocklib_image.copy(_LCD, self.image, self.x, self.y, _NIL, _NIL, |
258 | iVal = iMax | 416 | _NIL, _NIL, true, BSAND, self.color) |
259 | elseif iVal > iMax then | ||
260 | iVal = iMin | ||
261 | end | 417 | end |
262 | 418 | ||
263 | return iVal | 419 | return self |
264 | end | 420 | end |
265 | 421 | ||
266 | function Cursor:do_action(action) | 422 | function Cursor:do_action(action) |
423 | local function clamp_roll(iVal, iMin, iMax) | ||
424 | if iVal < iMin then | ||
425 | iVal = iMax | ||
426 | elseif iVal > iMax then | ||
427 | iVal = iMin | ||
428 | end | ||
429 | return iVal | ||
430 | end | ||
267 | local xi, yi = 0, 0 | 431 | local xi, yi = 0, 0 |
268 | 432 | ||
269 | if HAS_TOUCHSCREEN and action == pla.ACTION_TOUCHSCREEN then | 433 | if HAS_TOUCHSCREEN and action == pla.ACTION_TOUCHSCREEN then |
@@ -279,188 +443,225 @@ function Cursor:do_action(action) | |||
279 | yi = -self.sz | 443 | yi = -self.sz |
280 | elseif (action == pla.PLA_DOWN or action == pla.PLA_DOWN_REPEAT) then | 444 | elseif (action == pla.PLA_DOWN or action == pla.PLA_DOWN_REPEAT) then |
281 | yi = self.sz | 445 | yi = self.sz |
446 | else | ||
447 | Action_Evt = pla.ACTION_NONE | ||
448 | return false | ||
282 | end | 449 | end |
283 | 450 | ||
284 | self.x = clamp_roll(self.x + xi, 1, LCD_W - self.sz) | 451 | self.x = clamp_roll(self.x + xi, 1, LCD_W - self.sz) |
285 | self.y = clamp_roll(self.y + yi, 1, LCD_H - self.sz) | 452 | self.y = clamp_roll(self.y + yi, 1, LCD_H - self.sz) |
286 | 453 | Action_Evt = pla.ACTION_NONE | |
287 | return false | 454 | return false |
288 | end | 455 | end |
456 | -------------------------------------------------------------------------------- | ||
289 | 457 | ||
290 | function Cursor:draw() | ||
291 | rocklib_image.copy(_LCD, self.image, self.x, self.y, _NIL, _NIL, | ||
292 | _NIL, _NIL, true, BSAND, self.color) | ||
293 | end | ||
294 | 458 | ||
295 | local function calc_score(total, level, goal, expended) | 459 | --[[ Game function ]]----------------------------------------------------------- |
296 | local score = (expended * level) * 100 | 460 | function start_round(level, goal, nrBalls, total) |
297 | if expended < goal then | 461 | Player_Added = false |
298 | score = -(score + (level * 100)) | 462 | --[[ References ]]-- |
299 | end | 463 | local current_tick = rb.current_tick |
300 | total = total + score | 464 | local lcd_update = rb.lcd_update |
301 | return total | 465 | local lcd_clear_display = rb.lcd_clear_display |
302 | end | ||
303 | |||
304 | local function draw_pos_str(bottom, right, str) | ||
305 | local w, h = getstringsize(str) | ||
306 | local x = (right > 0) and ((LCD_W - w) * right - 1) or 1 | ||
307 | local y = (bottom > 0) and ((LCD_H - h) * bottom - 1) or 1 | ||
308 | rb.lcd_putsxy(x, y, str) | ||
309 | end | ||
310 | |||
311 | local function wait_anykey(to_secs) | ||
312 | rb.sleep(rb.HZ / 2) | ||
313 | rb.button_clear_queue() | ||
314 | rb.button_get_w_tmo(rb.HZ * to_secs) | ||
315 | end | ||
316 | 466 | ||
317 | local function start_round(level, goal, nrBalls, total) | 467 | local test_spd = false |
318 | local player_added, score = false, 0 | 468 | local is_exit = false; |
469 | local score = 0 | ||
319 | local last_expend, nrBalls_expend = 0, 0 | 470 | local last_expend, nrBalls_expend = 0, 0 |
320 | local balls_exploded = 1 -- keep looping when player_added == false | ||
321 | local action = 0 | ||
322 | local Balls = {} | 471 | local Balls = {} |
323 | local str_level = string.format(FMT_LEVEL, level) -- static | 472 | local balls_exploded = 1 -- to keep looping when player_added == false |
324 | local str_totpts = string.format(FMT_TOTPTS, total) -- static | 473 | |
474 | local tick_next = 0 | ||
475 | local cursor = nil | ||
476 | local draw_cursor = Empty_fn | ||
477 | local refresh = rb.HZ/20 | ||
478 | |||
479 | local function level_stats(level, total) | ||
480 | return strfmt(FMT_LEVEL, level), strfmt(FMT_TOTPTS, total) | ||
481 | end | ||
482 | |||
483 | local str_level, str_totpts = level_stats(level, total) -- static for lvl | ||
325 | local str_expend, str_lvlpts | 484 | local str_expend, str_lvlpts |
326 | local tick, cursor | ||
327 | local test_spd = false | ||
328 | 485 | ||
329 | local function update_stats() | 486 | local function update_stats() |
330 | -- we only create a new string when a hit is detected | 487 | -- we only create a new string when a hit is detected |
331 | str_expend = string.format(FMT_EXPEND, nrBalls_expend) | 488 | str_expend = strfmt(FMT_EXPEND, nrBalls_expend) |
332 | str_lvlpts = string.format(FMT_LVPTS, score) | 489 | str_lvlpts = strfmt(FMT_LVPTS, score) |
333 | end | 490 | end |
334 | 491 | ||
335 | local function draw_stats() | 492 | function draw_stats() |
493 | local function draw_pos_str(bottom, right, str) | ||
494 | local w, h = getstringsize(str) | ||
495 | local x = (right > 0) and ((LCD_W - w) * right - 1) or 1 | ||
496 | local y = (bottom > 0) and ((LCD_H - h) * bottom - 1) or 1 | ||
497 | lcd_putsxy(x, y, str) | ||
498 | end | ||
499 | -- pos(B, R) [B/R]=0 => [y/x]=1, [B/R]=1 => [y/x]=lcd[H/W]-string[H/W] | ||
336 | draw_pos_str(0, 0, str_expend) | 500 | draw_pos_str(0, 0, str_expend) |
337 | draw_pos_str(0, 1, str_level) | 501 | draw_pos_str(0, 1, str_level) |
338 | draw_pos_str(1, 1, str_lvlpts) | 502 | draw_pos_str(1, 1, str_lvlpts) |
339 | draw_pos_str(1, 0, str_totpts) | 503 | draw_pos_str(1, 0, str_totpts) |
340 | end | 504 | end |
341 | 505 | ||
506 | -- all Balls share same function, will by changed by player_add() | ||
507 | local checkhit_fn = Empty_fn | ||
508 | |||
509 | local function checkhit(Ball) | ||
510 | if Ball.state == B_MOVE then | ||
511 | for i = #Balls, 1, -1 do | ||
512 | if Balls[i].state < B_MOVE and | ||
513 | Ball:checkHit(Balls[i]) then -- exploded? | ||
514 | balls_exploded = balls_exploded + 1 | ||
515 | nrBalls_expend = nrBalls_expend + 1 | ||
516 | break | ||
517 | end | ||
518 | end | ||
519 | end | ||
520 | end | ||
521 | |||
342 | local function add_player() | 522 | local function add_player() |
343 | -- cursor becomes exploded ball | 523 | -- cursor becomes exploded ball |
344 | local player = Ball:new({ | 524 | local player = Ball:new({ |
345 | x = cursor.x, | 525 | x = cursor.x - cursor.sz, |
346 | y = cursor.y, | 526 | y = cursor.y - cursor.sz, |
347 | color = cursor.color, | 527 | color = cursor.color, |
348 | step_delay = 3, | 528 | step_delay = 3, |
349 | explosion_sz = (3 * DEFAULT_BALL_SZ), | 529 | explosion_sz = (3 * DEFAULT_BALL_SZ), |
350 | life_ticks = (test_time == true) and (100) or | 530 | life_ticks = (test_spd) and (rb.HZ) or |
351 | irand(rb.HZ * 2, rb.HZ * DEFAULT_BALL_SZ), | 531 | irand(rb.HZ * 2, rb.HZ * DEFAULT_BALL_SZ), |
352 | sz = 10, | 532 | sz = 10, |
353 | state = B_EXPLODE | 533 | state = B_EXPLODE |
354 | }) | 534 | }) |
355 | -- set x/y impact region | 535 | -- set x/y impact region -->[] |
356 | player.xi = player.x + player.sz | 536 | player.xi = player.x + player.sz |
357 | player.yi = player.y + player.sz | 537 | player.yi = player.y + player.sz |
538 | player.draw_fn = player.draw_exploded | ||
539 | player.step_fn = player.step_exploded | ||
358 | 540 | ||
359 | table.insert(Balls, player) | 541 | table.insert(Balls, player) |
360 | balls_exploded = 1 | 542 | balls_exploded = 1 |
361 | player_added = true | 543 | Player_Added = true |
362 | cursor = nil | 544 | cursor = nil |
545 | draw_cursor = Empty_fn | ||
546 | -- only need collision detection after player add | ||
547 | checkhit_fn = checkhit | ||
363 | end | 548 | end |
364 | 549 | ||
365 | if level < 1 then | 550 | local function speedtest() |
366 | -- check speed of target | 551 | -- check speed of target |
367 | set_foreground(DEFAULT_BG_CLR) --hide text during test | 552 | set_foreground(DEFAULT_BG_CLR) --hide text during test |
368 | local bkcolor = (rb.LCD_DEPTH == 2) and (3) or 0 | ||
369 | level = 1 | 553 | level = 1 |
370 | nrBalls = 20 | 554 | nrBalls = 100 |
371 | cursor = { x = LCD_W * 2, y = LCD_H * 2, color = bkcolor} | 555 | cursor = {x = LCD_W * 2, y = LCD_H * 2, color = 0, sz = 1} |
372 | table.insert(Balls, Ball:new({ | 556 | table.insert(Balls, Ball:new({ |
373 | x = 1, y = 1, xi = 1, yi = 1, | 557 | x = 1, y = 1, xi = 1, yi = 1, |
374 | color = bkcolor, step_delay = 1, | 558 | color = 0, step_delay = 0, |
375 | explosion_sz = 0, life_ticks = 0, | 559 | explosion_sz = 0, life_ticks = 0, |
376 | step = function() test_spd = test_spd + 1 end | 560 | draw_fn = Empty_fn, |
561 | step_fn = function() test_spd = test_spd + 1 end | ||
377 | }) | 562 | }) |
378 | ) | 563 | ) |
379 | add_player() | ||
380 | test_spd = 0 | 564 | test_spd = 0 |
565 | add_player() | ||
566 | end | ||
567 | |||
568 | local function screen_redraw() | ||
569 | -- (draw_fn changes dynamically at runtime) | ||
570 | for i = 1, #Balls do | ||
571 | Balls[i].draw_fn() | ||
572 | end | ||
573 | |||
574 | draw_stats() | ||
575 | draw_cursor() | ||
576 | |||
577 | lcd_update() | ||
578 | lcd_clear_display() | ||
579 | end | ||
580 | |||
581 | local function game_loop() | ||
582 | local tick = current_tick() | ||
583 | for _, Ball in ipairs(Balls) do | ||
584 | if tick > Ball.next_tick then | ||
585 | -- (step_fn changes dynamically at runtime) | ||
586 | if Ball:step_fn(tick) == B_DEAD then | ||
587 | balls_exploded = balls_exploded - 1 | ||
588 | else | ||
589 | checkhit_fn(Ball) | ||
590 | end | ||
591 | end | ||
592 | end | ||
593 | return tick | ||
594 | end | ||
595 | |||
596 | if level < 1 then | ||
597 | speedtest() | ||
598 | local bkcolor = (rb.LCD_DEPTH == 2) and (3) or 0 | ||
599 | -- Initialize the balls | ||
600 | if DEBUG then bkcolor = nil end | ||
601 | for i=1, nrBalls do | ||
602 | table.insert(Balls, Ball:new(nil, level, bkcolor)) | ||
603 | end | ||
381 | else | 604 | else |
605 | speedtest = nil | ||
382 | set_foreground(DEFAULT_FG_CLR) -- color for text | 606 | set_foreground(DEFAULT_FG_CLR) -- color for text |
383 | cursor = Cursor:new() | 607 | cursor = Cursor:new() |
384 | end | 608 | if not HAS_TOUCHSCREEN then |
385 | 609 | draw_cursor = cursor.draw | |
386 | -- Initialize the balls | 610 | end |
387 | for i=1, nrBalls do | 611 | -- Initialize the balls |
388 | table.insert(Balls, Ball:new(nil, level)) | 612 | for i=1, nrBalls do |
613 | table.insert(Balls, Ball:new(nil, level)) | ||
614 | end | ||
389 | end | 615 | end |
390 | 616 | ||
391 | -- Make sure there are no unwanted touchscreen presses | 617 | -- Make sure there are no unwanted touchscreen presses |
392 | rb.button_clear_queue() | 618 | rb.button_clear_queue() |
393 | 619 | ||
620 | Action_Evt = pla.ACTION_NONE | ||
621 | |||
394 | update_stats() -- load status strings | 622 | update_stats() -- load status strings |
395 | 623 | ||
396 | -- Check if the round is over | 624 | if rb.cpu_boost then rb.cpu_boost(true) end |
397 | while balls_exploded > 0 do | 625 | collectgarbage("collect") -- run gc now to hopefully prevent interruption later |
398 | tick = rb.current_tick() | ||
399 | 626 | ||
400 | if action ~= pla.ACTION_NONE and (action == pla.PLA_EXIT or | 627 | local duration = current_tick() |
401 | action == pla.PLA_CANCEL) then | 628 | -- Game loop >> Check if the round is over |
402 | action = pla.PLA_EXIT | 629 | while balls_exploded > 0 do |
630 | if Action_Evt == pla.PLA_EXIT then | ||
631 | is_exit = true | ||
403 | break | 632 | break |
404 | end | 633 | end |
405 | 634 | ||
406 | rb.lcd_clear_display() | 635 | if game_loop() > tick_next then |
407 | 636 | tick_next = current_tick() + refresh | |
408 | if not player_added then | 637 | if not Player_Added then |
409 | if action ~= pla.ACTION_NONE and cursor:do_action(action) then | 638 | if Action_Evt ~= pla.ACTION_NONE and cursor:do_action(Action_Evt) then |
410 | add_player() | 639 | add_player() |
411 | elseif not HAS_TOUCHSCREEN then | ||
412 | cursor:draw() | ||
413 | end | ||
414 | end | ||
415 | |||
416 | for _, Ball in ipairs(Balls) do | ||
417 | if Ball.state == B_MOVE then | ||
418 | if tick > Ball.next_tick then | ||
419 | Ball:step(tick) | ||
420 | for i = #Balls, 1, -1 do | ||
421 | if Balls[i].state < B_MOVE and | ||
422 | Ball:checkHit(Balls[i]) then -- exploded? | ||
423 | balls_exploded = balls_exploded + 1 | ||
424 | nrBalls_expend = nrBalls_expend + 1 | ||
425 | break | ||
426 | end | ||
427 | end | ||
428 | end | ||
429 | -- check if state changed draw ball if still moving | ||
430 | if Ball.state == B_MOVE then | ||
431 | Ball:draw() | ||
432 | end | ||
433 | elseif Ball.state ~= B_DEAD then | ||
434 | if tick > Ball.next_tick then | ||
435 | Ball:step_exploded(tick) | ||
436 | end | ||
437 | if Ball.state ~= B_DEAD then | ||
438 | Ball:draw_exploded() | ||
439 | else | ||
440 | balls_exploded = balls_exploded - 1 | ||
441 | end | 640 | end |
442 | end | 641 | end |
443 | end | ||
444 | 642 | ||
445 | draw_stats() -- stats redrawn every frame | 643 | if nrBalls_expend ~= last_expend then -- hit detected? |
446 | rb.lcd_update() -- Push framebuffer to the LCD | 644 | last_expend = nrBalls_expend |
645 | score = (nrBalls_expend * level) * SCORE_MULTIPLY | ||
646 | update_stats() -- only update stats when not current | ||
647 | if nrBalls_expend == nrBalls then break end -- round is over? | ||
648 | end | ||
447 | 649 | ||
448 | if nrBalls_expend ~= last_expend then -- hit detected? | 650 | screen_redraw_count = screen_redraw_count + 1 |
449 | last_expend = nrBalls_expend | 651 | screen_redraw() |
450 | score = (nrBalls_expend * level) * 100 | ||
451 | update_stats() -- only update stats when not current | ||
452 | if nrBalls_expend == nrBalls then break end -- round is over? | ||
453 | end | 652 | end |
454 | |||
455 | rb.yield() -- yield to other tasks | 653 | rb.yield() -- yield to other tasks |
456 | |||
457 | action = rb.get_plugin_action(0) -- Check for actions | ||
458 | end | 654 | end |
459 | 655 | ||
460 | if test_spd and test_spd > 0 then return test_spd end | 656 | screen_redraw_duration = screen_redraw_duration + (rb.current_tick() - duration) |
657 | if rb.cpu_boost then rb.cpu_boost(false) end | ||
658 | |||
659 | if test_spd and test_spd > 0 then | ||
660 | return test_spd, screen_redraw_count, screen_redraw_duration *10 --ms | ||
661 | end | ||
461 | 662 | ||
462 | -- splash the final stats for a moment at end | 663 | -- splash the final stats for a moment at end |
463 | rb.lcd_clear_display() | 664 | lcd_clear_display() |
464 | for _, Ball in ipairs(Balls) do | 665 | for _, Ball in ipairs(Balls) do |
465 | -- move balls back to their initial exploded positions | 666 | -- move balls back to their initial exploded positions |
466 | if Ball.state == B_DEAD then | 667 | if Ball.state == B_DEAD then |
@@ -471,56 +672,22 @@ local function start_round(level, goal, nrBalls, total) | |||
471 | Ball:draw() | 672 | Ball:draw() |
472 | end | 673 | end |
473 | 674 | ||
474 | if DEFAULT_BALL_SZ > 3 then | 675 | if DEFAULT_BALL_SZ > 3 then -- dither |
475 | _LCD:clear(nil, nil, nil, nil, nil, nil, 2, 2) | 676 | _LCD:clear(nil, nil, nil, nil, nil, nil, 2, 2) |
476 | end | 677 | end |
477 | 678 | ||
478 | total = calc_score(total, level, goal, nrBalls_expend) | 679 | total = calc_score(total, level, goal, nrBalls_expend) |
479 | str_totpts = string.format(FMT_TOTPTS, total) | 680 | str_level, str_totpts = level_stats(level, total) |
480 | draw_stats() | 681 | draw_stats() |
481 | rb.lcd_update() | 682 | lcd_update() |
482 | wait_anykey(2) | 683 | wait_anykey(2) |
483 | 684 | ||
484 | return action == pla.PLA_EXIT, score, nrBalls_expend | 685 | return is_exit, score, nrBalls_expend |
485 | end | 686 | end |
687 | -------------------------------------------------------------------------------- | ||
486 | 688 | ||
487 | -- Helper function to display a message | ||
488 | local function disp_msg(to, ...) | ||
489 | local message = string.format(...) | ||
490 | local w, h = getstringsize(message) | ||
491 | local x, y = (LCD_W - w) / 2, (LCD_H - h) / 2 | ||
492 | |||
493 | rb.lcd_clear_display() | ||
494 | set_foreground(DEFAULT_FG_CLR) | ||
495 | |||
496 | if w > LCD_W then | ||
497 | rb.lcd_puts_scroll(0, (y / h), message) | ||
498 | else | ||
499 | rb.lcd_putsxy(x, y, message) | ||
500 | end | ||
501 | 689 | ||
502 | if to == -1 then | 690 | --[[MAIN PROGRAM]]-------------------------------------------------------------- |
503 | local msg = "Press button to exit" | ||
504 | w, h = getstringsize(msg) | ||
505 | x = (LCD_W - w) / 2 | ||
506 | if x < 0 then | ||
507 | rb.lcd_puts_scroll(0, (y / h) + 1, msg) | ||
508 | else | ||
509 | rb.lcd_putsxy(x, y + h, msg) | ||
510 | end | ||
511 | end | ||
512 | rb.lcd_update() | ||
513 | |||
514 | if to == -1 then | ||
515 | wait_anykey(60) | ||
516 | else | ||
517 | rb.sleep(to) | ||
518 | end | ||
519 | |||
520 | rb.lcd_scroll_stop() -- Stop our scrolling message | ||
521 | end | ||
522 | |||
523 | --[[MAIN PROGRAM]] | ||
524 | do -- attempt to get stats to fit on screen | 691 | do -- attempt to get stats to fit on screen |
525 | local function getwidth(str) | 692 | local function getwidth(str) |
526 | local w, _ = getstringsize(str) | 693 | local w, _ = getstringsize(str) |
@@ -530,7 +697,7 @@ do -- attempt to get stats to fit on screen | |||
530 | if (w0 + w1) > LCD_W then | 697 | if (w0 + w1) > LCD_W then |
531 | FMT_EXPEND, FMT_LEVEL = "%d balls", "Lv %d" | 698 | FMT_EXPEND, FMT_LEVEL = "%d balls", "Lv %d" |
532 | end | 699 | end |
533 | w0, w1 = getwidth(FMT_TOTPTS), getwidth(FMT_LVPTS) | 700 | w0, w1 = getwidth(FMT_TOTPTS), getwidth(FMT_LVPTS) |
534 | if (w0 + w1 + getwidth("0000000")) > LCD_W then | 701 | if (w0 + w1 + getwidth("0000000")) > LCD_W then |
535 | FMT_TOTPTS, FMT_LVPTS = "%d total", "%d lv" | 702 | FMT_TOTPTS, FMT_LVPTS = "%d total", "%d lv" |
536 | end | 703 | end |
@@ -542,23 +709,16 @@ end | |||
542 | 709 | ||
543 | rb.backlight_force_on() | 710 | rb.backlight_force_on() |
544 | 711 | ||
545 | math.randomseed(os.time()) | 712 | local eva = rockev.register("action", action_event, rb.HZ / 10) |
546 | |||
547 | local idx, highscore = 1, 0 | ||
548 | 713 | ||
549 | local test_spd = start_round(0, 0, 0, 0) -- test speed of target | 714 | math.randomseed(os.time() or 1) |
550 | 715 | ||
551 | if test_spd < 100 then | 716 | local idx, highscore = 1, 0 |
552 | rb.splash(100, "Slow Target..") | ||
553 | 717 | ||
554 | if test_spd < 25 then | 718 | disp_msg(rb.HZ, "BoomShine") |
555 | MAX_BALL_SPEED = MAX_BALL_SPEED + MAX_BALL_SPEED | 719 | test_speed() |
556 | elseif test_spd < 50 then | 720 | rb.sleep(rb.HZ * 2) |
557 | MAX_BALL_SPEED = MAX_BALL_SPEED + MAX_BALL_SPEED / 2 | 721 | test_speed = nil |
558 | elseif test_spd < 100 then | ||
559 | MAX_BALL_SPEED = MAX_BALL_SPEED + MAX_BALL_SPEED / 4 | ||
560 | end | ||
561 | end | ||
562 | 722 | ||
563 | while levels[idx] ~= nil do | 723 | while levels[idx] ~= nil do |
564 | local goal, nrBalls = levels[idx][1], levels[idx][2] | 724 | local goal, nrBalls = levels[idx][1], levels[idx][2] |
@@ -567,18 +727,26 @@ while levels[idx] ~= nil do | |||
567 | 727 | ||
568 | disp_msg(rb.HZ * 2, "Level %d: get %d out of %d balls", idx, goal, nrBalls) | 728 | disp_msg(rb.HZ * 2, "Level %d: get %d out of %d balls", idx, goal, nrBalls) |
569 | 729 | ||
570 | local exit, score, nrBalls_expend = start_round(idx, goal, nrBalls, highscore) | 730 | local is_exit, score, nrBalls_expend = start_round(idx, goal, nrBalls, highscore) |
731 | if DEBUG == true then | ||
732 | local fps = screen_redraw_count * 100 / screen_redraw_duration | ||
733 | disp_msg(rb.HZ * 5, "Redraw: %d fps", fps) | ||
734 | end | ||
571 | 735 | ||
572 | if exit then | 736 | if is_exit then |
573 | break -- Exiting.. | 737 | break -- Exiting.. |
574 | else | 738 | else |
575 | highscore = calc_score(highscore, idx, goal, nrBalls_expend) | 739 | highscore, score, bonus = calc_score(highscore, idx, goal, nrBalls_expend) |
576 | if nrBalls_expend >= goal then | 740 | if nrBalls_expend >= goal then |
577 | disp_msg(rb.HZ * 2, "You won!") | 741 | if bonus == 0 then |
742 | disp_msg(rb.HZ * 2, "You won!") | ||
743 | else | ||
744 | disp_msg(rb.HZ * 2, "You won BONUS!") | ||
745 | end | ||
578 | levels[idx] = nil | 746 | levels[idx] = nil |
579 | idx = idx + 1 | 747 | idx = idx + 1 |
580 | else | 748 | else |
581 | disp_msg(rb.HZ * 2, "You lost %d points!", score + (idx * 100)) | 749 | disp_msg(rb.HZ * 2, "You lost %d points!", -score) |
582 | if highscore < 0 then break end | 750 | if highscore < 0 then break end |
583 | end | 751 | end |
584 | end | 752 | end |
@@ -594,3 +762,7 @@ end | |||
594 | 762 | ||
595 | -- Restore user backlight settings | 763 | -- Restore user backlight settings |
596 | rb.backlight_use_settings() | 764 | rb.backlight_use_settings() |
765 | if rb.cpu_boost then rb.cpu_boost(false) end | ||
766 | |||
767 | os.exit() | ||
768 | -------------------------------------------------------------------------------- | ||