rubysketch-solitaire 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +3 -0
- data/.gitignore +2 -0
- data/.hooks/pre-commit +69 -0
- data/ChangeLog.md +21 -0
- data/Gemfile.lock +10 -10
- data/Podfile.lock +33 -33
- data/Rakefile +107 -10
- data/RubySolitaire/Ad.swift +88 -0
- data/RubySolitaire/Assets.xcassets/AppIcon.appiconset/AppIcon.png +0 -0
- data/RubySolitaire/Assets.xcassets/AppIcon.appiconset/Contents.json +3 -87
- data/RubySolitaire/Base.lproj/Localizable.strings +6 -0
- data/RubySolitaire/Extensions.swift +5 -0
- data/RubySolitaire/GameView.swift +75 -13
- data/RubySolitaire/Helper.swift +70 -0
- data/RubySolitaire/MenuScreen.swift +140 -0
- data/RubySolitaire/RubySolitaireApp.swift +188 -1
- data/RubySolitaire/SafariView.swift +16 -0
- data/RubySolitaire/Strings.swift +48 -0
- data/RubySolitaire/ja.lproj/InfoPlist.strings +4 -0
- data/RubySolitaire/ja.lproj/Localizable.strings +6 -0
- data/VERSION +1 -1
- data/data/card.png +0 -0
- data/data/classicPSPWave.glsl +94 -0
- data/data/colorfulUnderwaterBubbles2.glsl +113 -0
- data/data/cosmic2.glsl +121 -0
- data/data/reflectiveHexes.glsl +219 -0
- data/fastlane/Fastfile +76 -0
- data/fastlane/metadata/copyright.txt +1 -0
- data/fastlane/metadata/en-US/apple_tv_privacy_policy.txt +1 -0
- data/fastlane/metadata/en-US/description.txt +5 -0
- data/fastlane/metadata/en-US/keywords.txt +1 -0
- data/fastlane/metadata/en-US/marketing_url.txt +1 -0
- data/fastlane/metadata/en-US/name.txt +1 -0
- data/fastlane/metadata/en-US/privacy_url.txt +1 -0
- data/fastlane/metadata/en-US/promotional_text.txt +1 -0
- data/fastlane/metadata/en-US/release_notes.txt +1 -0
- data/fastlane/metadata/en-US/subtitle.txt +1 -0
- data/fastlane/metadata/en-US/support_url.txt +1 -0
- data/fastlane/metadata/ja/apple_tv_privacy_policy.txt +1 -0
- data/fastlane/metadata/ja/description.txt +5 -0
- data/fastlane/metadata/ja/keywords.txt +1 -0
- data/fastlane/metadata/ja/marketing_url.txt +1 -0
- data/fastlane/metadata/ja/name.txt +1 -0
- data/fastlane/metadata/ja/privacy_url.txt +1 -0
- data/fastlane/metadata/ja/promotional_text.txt +1 -0
- data/fastlane/metadata/ja/release_notes.txt +1 -0
- data/fastlane/metadata/ja/subtitle.txt +1 -0
- data/fastlane/metadata/ja/support_url.txt +1 -0
- data/fastlane/metadata/primary_category.txt +1 -0
- data/fastlane/metadata/primary_first_sub_category.txt +1 -0
- data/fastlane/metadata/primary_second_sub_category.txt +1 -0
- data/fastlane/metadata/review_information/demo_password.txt +1 -0
- data/fastlane/metadata/review_information/demo_user.txt +1 -0
- data/fastlane/metadata/review_information/email_address.txt +1 -0
- data/fastlane/metadata/review_information/first_name.txt +0 -0
- data/fastlane/metadata/review_information/last_name.txt +0 -0
- data/fastlane/metadata/review_information/notes.txt +1 -0
- data/fastlane/metadata/review_information/phone_number.txt +0 -0
- data/fastlane/metadata/secondary_category.txt +1 -0
- data/fastlane/metadata/secondary_first_sub_category.txt +1 -0
- data/fastlane/metadata/secondary_second_sub_category.txt +1 -0
- data/lib/rubysketch/solitaire/background.rb +115 -12
- data/lib/rubysketch/solitaire/card.rb +10 -87
- data/lib/rubysketch/solitaire/common/animation.rb +34 -34
- data/lib/rubysketch/solitaire/common/button.rb +49 -19
- data/lib/rubysketch/solitaire/common/dialog.rb +78 -21
- data/lib/rubysketch/solitaire/common/scene.rb +15 -4
- data/lib/rubysketch/solitaire/common/settings.rb +10 -2
- data/lib/rubysketch/solitaire/common/timer.rb +2 -2
- data/lib/rubysketch/solitaire/common/transitions.rb +12 -6
- data/lib/rubysketch/solitaire/common/utils.rb +15 -0
- data/lib/rubysketch/solitaire/klondike.rb +378 -81
- data/lib/rubysketch/solitaire/places.rb +12 -102
- data/lib/rubysketch/solitaire/skin.rb +151 -0
- data/lib/rubysketch/solitaire.rb +33 -9
- data/main.rb +1 -0
- data/project.yml +85 -4
- metadata +54 -2
@@ -13,6 +13,25 @@ class Klondike < Scene
|
|
13
13
|
super + [*cards, *places].map(&:sprite) + interfaces
|
14
14
|
end
|
15
15
|
|
16
|
+
def difficulty()
|
17
|
+
@difficulty ||= :normal
|
18
|
+
end
|
19
|
+
|
20
|
+
def pause()
|
21
|
+
super
|
22
|
+
@prevTime = nil
|
23
|
+
stopTimer :save
|
24
|
+
end
|
25
|
+
|
26
|
+
def resume()
|
27
|
+
super
|
28
|
+
return if !started? || completed?
|
29
|
+
@prevTime = now
|
30
|
+
startInterval :save, 1, now: true do
|
31
|
+
save
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
16
35
|
def draw()
|
17
36
|
sprite *places.map(&:sprite)
|
18
37
|
sprite *cards.sort {|a, b| a.z <=> b.z}.map(&:sprite)
|
@@ -25,6 +44,10 @@ class Klondike < Scene
|
|
25
44
|
updateLayout w, h
|
26
45
|
end
|
27
46
|
|
47
|
+
def focusChanged(focus)
|
48
|
+
focus ? resume : pause if ios?
|
49
|
+
end
|
50
|
+
|
28
51
|
def canDrop?(card)
|
29
52
|
case card.place
|
30
53
|
when *columns then card.opened?
|
@@ -70,7 +93,7 @@ class Klondike < Scene
|
|
70
93
|
def save()
|
71
94
|
settings['state'] = {
|
72
95
|
version: 1,
|
73
|
-
|
96
|
+
difficulty: difficulty,
|
74
97
|
history: history.to_h {|o| o.id if o.respond_to? :id},
|
75
98
|
score: score.to_h,
|
76
99
|
elapsedTime: elapsedTime,
|
@@ -87,7 +110,7 @@ class Klondike < Scene
|
|
87
110
|
findAll = -> id { all.find {|obj| obj .id == id} or raise "No object '#{id}'"}
|
88
111
|
findCard = -> id {cards.find {|card| card.id == id} or raise "No card '#{id}'"}
|
89
112
|
|
90
|
-
|
113
|
+
@difficulty = hash['difficulty'].intern
|
91
114
|
|
92
115
|
self.history = History.load hash['history'] do |id|
|
93
116
|
(id.respond_to?('=~') && id =~ /^id:/) ? findAll[id] : nil
|
@@ -110,7 +133,7 @@ class Klondike < Scene
|
|
110
133
|
raise "Failed to restore state" unless
|
111
134
|
places.reduce([]) {|a, place| a + place.cards}.size == 52
|
112
135
|
|
113
|
-
|
136
|
+
start!
|
114
137
|
end
|
115
138
|
|
116
139
|
def inspect()
|
@@ -151,22 +174,81 @@ class Klondike < Scene
|
|
151
174
|
}
|
152
175
|
end
|
153
176
|
|
177
|
+
def addScore(name)
|
178
|
+
old = score.value
|
179
|
+
score.add name if history.enabled?
|
180
|
+
history.push [:score, score.value, old] if score.value != old
|
181
|
+
end
|
182
|
+
|
154
183
|
def bestTime()
|
155
|
-
settings[
|
184
|
+
settings[bestRecordKey :time] || 24 * 60 * 60 - 1
|
156
185
|
end
|
157
186
|
|
158
187
|
def bestScore()
|
159
|
-
settings[
|
188
|
+
settings[bestRecordKey :score] || 0
|
189
|
+
end
|
190
|
+
|
191
|
+
def dailyBestTime()
|
192
|
+
key = bestRecordKey :time, true
|
193
|
+
settings[key] = nil if settings["#{key}Date"] != today
|
194
|
+
settings[key] || 24 * 60 * 60 - 1
|
195
|
+
end
|
196
|
+
|
197
|
+
def dailyBestScore()
|
198
|
+
key = bestRecordKey :score, true
|
199
|
+
settings[key] = nil if settings["#{key}Date"] != today
|
200
|
+
settings[key] || 0
|
160
201
|
end
|
161
202
|
|
162
203
|
def updateBests()
|
163
|
-
newTime
|
164
|
-
newScore
|
204
|
+
newTime = elapsedTime < bestTime
|
205
|
+
newScore = score.value > bestScore
|
206
|
+
newDailyTime = elapsedTime < dailyBestTime
|
207
|
+
newDailyScore = score.value > dailyBestScore
|
208
|
+
|
209
|
+
settings[bestRecordKey :time] = elapsedTime if newTime
|
210
|
+
settings[bestRecordKey :score] = score.value if newScore
|
211
|
+
|
212
|
+
if newDailyTime
|
213
|
+
settings[bestRecordKey(:time, true)] = elapsedTime
|
214
|
+
settings[bestRecordKey(:time, true, 'Date')] = today
|
215
|
+
end
|
216
|
+
|
217
|
+
if newDailyScore
|
218
|
+
settings[bestRecordKey(:score, true)] = score.value
|
219
|
+
settings[bestRecordKey(:score, true, 'Date')] = today
|
220
|
+
end
|
221
|
+
|
222
|
+
return newTime, newScore, newDailyTime, newDailyScore
|
223
|
+
end
|
224
|
+
|
225
|
+
def clearAllTimeBests()
|
226
|
+
%i[time score]
|
227
|
+
.map {|type| bestRecordKey type}
|
228
|
+
.each {|key| settings[key] = nil}
|
229
|
+
end
|
230
|
+
|
231
|
+
def clearDailyBests()
|
232
|
+
%i[time score]
|
233
|
+
.map {|type| ['', 'Date'].map {|s| bestRecordKey type, true, s}}
|
234
|
+
.flatten
|
235
|
+
.each {|key| settings[key] = nil}
|
236
|
+
end
|
237
|
+
|
238
|
+
def bestRecordKey(type, daily = false, suffix = '')
|
239
|
+
difficulty.to_s +
|
240
|
+
(daily ? 'Daily' : '') +
|
241
|
+
'Best' +
|
242
|
+
type.to_s.capitalize +
|
243
|
+
suffix
|
244
|
+
end
|
165
245
|
|
166
|
-
|
167
|
-
|
246
|
+
def timeToText(time)
|
247
|
+
Time.at(time).strftime('%M:%S')
|
248
|
+
end
|
168
249
|
|
169
|
-
|
250
|
+
def today()
|
251
|
+
Time.now.strftime '%Y%m%d'
|
170
252
|
end
|
171
253
|
|
172
254
|
def cards()
|
@@ -180,23 +262,23 @@ class Klondike < Scene
|
|
180
262
|
end
|
181
263
|
|
182
264
|
def deck()
|
183
|
-
@deck ||= CardPlace.new(:deck).tap do |deck|
|
265
|
+
@deck ||= CardPlace.new(self, :deck).tap do |deck|
|
184
266
|
deck.sprite.mouseClicked {deckClicked}
|
185
267
|
end
|
186
268
|
end
|
187
269
|
|
188
270
|
def nexts()
|
189
|
-
@nexts ||= NextsPlace.new(:nexts).tap do |nexts|
|
271
|
+
@nexts ||= NextsPlace.new(self, :nexts).tap do |nexts|
|
190
272
|
nexts.sprite.mouseClicked {nextsClicked}
|
191
273
|
end
|
192
274
|
end
|
193
275
|
|
194
276
|
def marks()
|
195
|
-
@marks ||= Card::MARKS.size.times.map {|i| MarkPlace.new "mark_#{i + 1}"}
|
277
|
+
@marks ||= Card::MARKS.size.times.map {|i| MarkPlace.new self, "mark_#{i + 1}"}
|
196
278
|
end
|
197
279
|
|
198
280
|
def columns()
|
199
|
-
@culumns ||= 7.times.map.with_index {|i| ColumnPlace.new "column_#{i + 1}"}
|
281
|
+
@culumns ||= 7.times.map.with_index {|i| ColumnPlace.new self, "column_#{i + 1}"}
|
200
282
|
end
|
201
283
|
|
202
284
|
def dealSound()
|
@@ -215,12 +297,12 @@ class Klondike < Scene
|
|
215
297
|
end
|
216
298
|
|
217
299
|
def interfaces()
|
218
|
-
[undoButton, redoButton,
|
300
|
+
[undoButton, redoButton, pauseButton, finishButton, status, debugButton]
|
219
301
|
end
|
220
302
|
|
221
303
|
def undoButton()
|
222
304
|
@undoButton ||= Button.new(
|
223
|
-
'◀',
|
305
|
+
'◀', fontSize: 28, round: [20, 4, 4, 20]
|
224
306
|
).tap do |b|
|
225
307
|
b.update {b.enable history.canUndo?}
|
226
308
|
b.clicked {history.undo {|action| undo action}}
|
@@ -229,18 +311,16 @@ class Klondike < Scene
|
|
229
311
|
|
230
312
|
def redoButton()
|
231
313
|
@redoButton ||= Button.new(
|
232
|
-
'▶',
|
314
|
+
'▶', fontSize: 28, round: [4, 20, 20, 4]
|
233
315
|
).tap do |b|
|
234
316
|
b.update {b.enable history.canRedo?}
|
235
317
|
b.clicked {history.redo {|action| self.redo action}}
|
236
318
|
end
|
237
319
|
end
|
238
320
|
|
239
|
-
def
|
240
|
-
@
|
241
|
-
|
242
|
-
).tap do |b|
|
243
|
-
b.clicked {showMenuDialog}
|
321
|
+
def pauseButton()
|
322
|
+
@pauseButton ||= Button.new(icon: skin.pauseIcon).tap do |b|
|
323
|
+
b.clicked {showPauseDialog}
|
244
324
|
end
|
245
325
|
end
|
246
326
|
|
@@ -248,7 +328,7 @@ class Klondike < Scene
|
|
248
328
|
@status ||= Sprite.new.tap do |sp|
|
249
329
|
sp.draw do
|
250
330
|
push do
|
251
|
-
fill
|
331
|
+
fill *skin.translucentBackgroundColor
|
252
332
|
rect 0, 0, sp.w, sp.h, 10
|
253
333
|
fill 255
|
254
334
|
|
@@ -260,7 +340,7 @@ class Klondike < Scene
|
|
260
340
|
}.each do |label, value|
|
261
341
|
textSize 12
|
262
342
|
textAlign LEFT, TOP
|
263
|
-
text label, x + mx, my, w - mx, sp.h - my * 2
|
343
|
+
text str(label), x + mx, my, w - mx, sp.h - my * 2
|
264
344
|
textSize 20
|
265
345
|
textAlign LEFT, BOTTOM
|
266
346
|
text value, x + mx, my, w - mx, sp.h - my * 2
|
@@ -282,71 +362,174 @@ class Klondike < Scene
|
|
282
362
|
|
283
363
|
def debugButton()
|
284
364
|
@debugButton ||= Button.new(:DEBUG, width: 3).tap do |b|
|
285
|
-
b.hide
|
286
|
-
b.clicked {}
|
365
|
+
b.hide unless debug?
|
366
|
+
b.clicked {showDebugDialog}
|
287
367
|
end
|
288
368
|
end
|
289
369
|
|
290
370
|
def showReadyDialog()
|
291
371
|
add Dialog.new(alpha: 50).tap {|d|
|
292
|
-
d.addButton 'EASY', width: 5 do
|
293
|
-
start
|
372
|
+
d.addButton str('EASY'), width: 5 do
|
373
|
+
start :easy
|
294
374
|
d.close
|
295
375
|
end
|
296
|
-
d.addButton '
|
297
|
-
start
|
376
|
+
d.addButton str('NORMAL'), width: 5 do
|
377
|
+
start :normal
|
378
|
+
d.close
|
379
|
+
end
|
380
|
+
d.addButton str('HARD'), width: 5 do
|
381
|
+
start :hard
|
298
382
|
d.close
|
299
383
|
end
|
300
384
|
}
|
301
385
|
end
|
302
386
|
|
303
|
-
def
|
304
|
-
|
305
|
-
|
306
|
-
d.
|
387
|
+
def showPauseDialog()
|
388
|
+
add Dialog.new {|d|
|
389
|
+
d.addLabel "#{str 'Difficulty'}: #{str difficulty.upcase}"
|
390
|
+
d.addLabel "#{str 'Best Time'}: #{timeToText bestTime}"
|
391
|
+
d.addLabel "#{str 'Best Score'}: #{bestScore}"
|
392
|
+
d.addLabel "#{str "Today's Best Time"}: #{timeToText dailyBestTime}"
|
393
|
+
d.addLabel "#{str "Today's Best Score"}: #{dailyBestScore}"
|
394
|
+
d.addSpace 20
|
395
|
+
d.addButton str('Resume'), width: 6 do
|
396
|
+
d.close
|
397
|
+
end
|
398
|
+
d.addButton str('New Game'), width: 6 do
|
307
399
|
d.close
|
308
|
-
|
400
|
+
showNewGameDialog
|
309
401
|
end
|
310
|
-
d.
|
402
|
+
d.addSpace 10
|
403
|
+
d.group do
|
404
|
+
if ios?
|
405
|
+
d.addButton icon: skin.menuIcon do
|
406
|
+
sendCommand :showMenu
|
407
|
+
end
|
408
|
+
end
|
409
|
+
d.addButton icon: skin.settingsIcon do
|
410
|
+
showSettingsDialog
|
411
|
+
end
|
412
|
+
end
|
413
|
+
}
|
414
|
+
end
|
415
|
+
|
416
|
+
def showNewGameDialog()
|
417
|
+
add Dialog.new(alpha: 180).tap {|d|
|
418
|
+
d.addLabel str("Start New Game?")
|
419
|
+
d.addSpace 20
|
420
|
+
d.addButton str('OK'), width: 4 do
|
311
421
|
startNewGame
|
422
|
+
d.close
|
423
|
+
end
|
424
|
+
d.addButton str('Cancel'), width: 4 do
|
425
|
+
d.close
|
312
426
|
end
|
313
|
-
d.addSpace 50
|
314
|
-
d.addLabel "Best Time: #{timeToText bestTime}"
|
315
|
-
d.addLabel "Best Score: #{bestScore}"
|
316
427
|
}
|
317
428
|
end
|
318
429
|
|
319
|
-
def
|
320
|
-
|
430
|
+
def showSettingsDialog()
|
431
|
+
closedImage = -> {
|
432
|
+
i = skin.closedImage
|
433
|
+
resizeImage i, i.width / 2, i.height / 2
|
434
|
+
}
|
435
|
+
add Dialog.new(alpha: 255).tap {|d|
|
436
|
+
bg = d.add Background.new backgroundScene.type
|
437
|
+
cardImage = d.addElement Sprite.new image: closedImage.call
|
438
|
+
d.addButton str('Change Card Design'), width: 7 do
|
439
|
+
skin skin.index + 1
|
440
|
+
settings['skinIndex'] = skin.index
|
441
|
+
cardImage.image = closedImage.call
|
442
|
+
end
|
443
|
+
d.addSpace 10
|
444
|
+
author = -> {bg.author&.then {|author| "by #{author}"} || '-'}
|
445
|
+
bgName = bgAuthor = nil
|
446
|
+
d.group :vertical, space: 0 do
|
447
|
+
bgName = d.addLabel(bg.name, alpha: 0) {sendCommand :openURL, bg.url}
|
448
|
+
bgAuthor = d.addLabel author.call, fontSize: 16, alpha: 0
|
449
|
+
end
|
450
|
+
d.addButton str('Change Background'), width: 7 do
|
451
|
+
bg.set bg.nextType
|
452
|
+
bgName .label = bg.name
|
453
|
+
bgAuthor.label = author.call
|
454
|
+
backgroundScene.set bg.type
|
455
|
+
end
|
456
|
+
d.addSpace 20
|
457
|
+
d.addButton str('Close'), width: 6 do
|
458
|
+
d.close
|
459
|
+
end
|
460
|
+
}
|
461
|
+
end
|
462
|
+
|
463
|
+
def showCompletedDialog(
|
464
|
+
bestTime = false, bestScore = false,
|
465
|
+
dailyBestTime = false, dailyBestScore = false)
|
466
|
+
|
467
|
+
suffix = -> allTime, daily do
|
468
|
+
return str '(New Record!)' if allTime
|
469
|
+
return str "(Today's Best!)" if daily
|
470
|
+
''
|
471
|
+
end
|
472
|
+
|
321
473
|
add Dialog.new.tap {|d|
|
322
|
-
d.addLabel 'Congratulations!', fontSize: 44
|
474
|
+
d.addLabel str('Congratulations!'), fontSize: 44
|
323
475
|
d.addLabel(
|
324
|
-
"Time: #{timeToText elapsedTime} #{
|
476
|
+
"#{str 'Time'}: #{timeToText elapsedTime} #{suffix.call bestTime, dailyBestTime}",
|
325
477
|
fontSize: 28)
|
326
478
|
d.addLabel(
|
327
|
-
"Score: #{score.value} #{
|
479
|
+
"#{str 'Score'}: #{score.value} #{suffix.call bestScore, dailyBestScore}",
|
328
480
|
fontSize: 28)
|
329
481
|
d.addSpace 50
|
330
|
-
d.addButton '
|
482
|
+
d.addButton str('Start Next Game'), width: 5 do
|
331
483
|
startNewGame
|
332
484
|
end
|
333
485
|
}
|
334
486
|
end
|
335
487
|
|
488
|
+
def showDebugDialog()
|
489
|
+
add Dialog.new.tap {|d|
|
490
|
+
d.addButton str('Clear all settings'), width: 6 do
|
491
|
+
settings.clear
|
492
|
+
d.close
|
493
|
+
end
|
494
|
+
d.addButton str('Clear all time bests'), width: 6 do
|
495
|
+
clearAllTimeBests
|
496
|
+
d.close
|
497
|
+
end
|
498
|
+
d.addButton str("Clear today's bests"), width: 6 do
|
499
|
+
clearDailyBests
|
500
|
+
d.close
|
501
|
+
end
|
502
|
+
d.addButton str("One step for completion"), width: 6 do
|
503
|
+
cards.sort.group_by(&:mark).each.with_index do |(mark, cards), index|
|
504
|
+
place = marks[index]
|
505
|
+
place.clear
|
506
|
+
cards.reverse.each.with_index do |card, i|
|
507
|
+
card.z = i
|
508
|
+
place.add card.open
|
509
|
+
end
|
510
|
+
end
|
511
|
+
d.close
|
512
|
+
end
|
513
|
+
d.addButton str('Close'), width: 6 do
|
514
|
+
d.close
|
515
|
+
end
|
516
|
+
}
|
517
|
+
end
|
518
|
+
|
336
519
|
def updateLayout(w, h)
|
337
520
|
card = cards.first
|
338
521
|
cw, ch = card.then {|c| [c.w, c.h]}
|
339
|
-
mx, my =
|
522
|
+
mx, my = skin.margin, cw * 0.2 # margin x, y
|
340
523
|
y = my
|
341
524
|
|
342
|
-
undoButton.pos
|
343
|
-
redoButton.pos
|
344
|
-
|
345
|
-
status.pos
|
346
|
-
status.right
|
347
|
-
status.height
|
525
|
+
undoButton.pos = [mx, y]
|
526
|
+
redoButton.pos = [undoButton.x + undoButton.w + 2, y]
|
527
|
+
pauseButton.pos = [width - (pauseButton.w + mx), y]
|
528
|
+
status.pos = [redoButton.right + mx, y]
|
529
|
+
status.right = pauseButton.left - mx
|
530
|
+
status.height = pauseButton.h
|
348
531
|
|
349
|
-
y = undoButton.y + undoButton.h + my
|
532
|
+
y = undoButton.y + undoButton.h + my * 3
|
350
533
|
|
351
534
|
deck.pos = [w - (deck.w + mx), y]
|
352
535
|
nexts.pos = [deck.x - (nexts.w + mx), deck.y]
|
@@ -379,8 +562,9 @@ class Klondike < Scene
|
|
379
562
|
end
|
380
563
|
end
|
381
564
|
|
382
|
-
def start(
|
383
|
-
|
565
|
+
def start(difficulty = :normal)
|
566
|
+
@difficulty = difficulty
|
567
|
+
start!
|
384
568
|
|
385
569
|
history.disable
|
386
570
|
lasts = columns.map(&:last).compact
|
@@ -390,7 +574,6 @@ class Klondike < Scene
|
|
390
574
|
if lasts.all? {|card| card.opened?}
|
391
575
|
drawNexts
|
392
576
|
history.enable
|
393
|
-
resume
|
394
577
|
end
|
395
578
|
end
|
396
579
|
end
|
@@ -411,7 +594,7 @@ class Klondike < Scene
|
|
411
594
|
|
412
595
|
def firstDistribution()
|
413
596
|
n = columns.size
|
414
|
-
(0...n).map {
|
597
|
+
(0...n).map {|row| (row...n).map {|col| [col, row]}}.flatten(1)
|
415
598
|
end
|
416
599
|
|
417
600
|
def openCard(card, gain: 0.5)
|
@@ -471,6 +654,19 @@ class Klondike < Scene
|
|
471
654
|
completed if completed?
|
472
655
|
end
|
473
656
|
|
657
|
+
def start!()
|
658
|
+
@started = true
|
659
|
+
[*cards, *places].each do |o|
|
660
|
+
o.started if o.respond_to? :started
|
661
|
+
end
|
662
|
+
places.each {|p| p.updateCards 0}
|
663
|
+
resume
|
664
|
+
end
|
665
|
+
|
666
|
+
def started?()
|
667
|
+
@started ||= false
|
668
|
+
end
|
669
|
+
|
474
670
|
def canFinish?()
|
475
671
|
deck.empty? && nexts.empty? &&
|
476
672
|
columns.any? {|col| !col.empty?} &&
|
@@ -525,7 +721,7 @@ class Klondike < Scene
|
|
525
721
|
|
526
722
|
def showFinishButton()
|
527
723
|
finishButton.tap do |b|
|
528
|
-
m =
|
724
|
+
m = skin.margin
|
529
725
|
b.x = marks.last.then {|mark| mark.x + mark.w} + m * 2
|
530
726
|
b.y = -deck.h
|
531
727
|
b.w = width - b.x - m
|
@@ -588,6 +784,7 @@ class Klondike < Scene
|
|
588
784
|
end
|
589
785
|
|
590
786
|
def backToPlace(card, vel)
|
787
|
+
return if vel.mag == 0
|
591
788
|
vec = vel.dup.normalize * sqrt(vel.mag) / 10 * sqrt(card.count)
|
592
789
|
return if vec.mag < 3
|
593
790
|
shakeScreen vector: vec
|
@@ -623,28 +820,6 @@ class Klondike < Scene
|
|
623
820
|
end
|
624
821
|
end
|
625
822
|
|
626
|
-
def timeToText(time)
|
627
|
-
Time.at(time).strftime('%M:%S')
|
628
|
-
end
|
629
|
-
|
630
|
-
def pause()
|
631
|
-
@prevTime = nil
|
632
|
-
stopTimer :save
|
633
|
-
end
|
634
|
-
|
635
|
-
def resume()
|
636
|
-
@prevTime = now
|
637
|
-
startInterval :save, 1, now: true do
|
638
|
-
save
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
def addScore(name)
|
643
|
-
old = score.value
|
644
|
-
score.add name if history.enabled?
|
645
|
-
history.push [:score, score.value, old] if score.value != old
|
646
|
-
end
|
647
|
-
|
648
823
|
def undo(action)
|
649
824
|
history.disable do
|
650
825
|
case action
|
@@ -670,7 +845,129 @@ class Klondike < Scene
|
|
670
845
|
end
|
671
846
|
|
672
847
|
def startNewGame()
|
673
|
-
|
848
|
+
$newGameCount ||= 0
|
849
|
+
$newGameCount += 1
|
850
|
+
showAd = $newGameCount % 3 == 0
|
851
|
+
transition self.class.new, [Fade, Curtain, Pixelate].sample, showAd: showAd
|
852
|
+
end
|
853
|
+
|
854
|
+
STRINGS = {
|
855
|
+
OK: {},
|
856
|
+
Cancel: {ja: 'キャンセル'},
|
857
|
+
Close: {ja: '閉じる'},
|
858
|
+
|
859
|
+
Time: {ja: 'タイム'},
|
860
|
+
Score: {ja: 'スコア'},
|
861
|
+
Move: {ja: '移動回数'},
|
862
|
+
|
863
|
+
Difficulty: {ja: '難易度'},
|
864
|
+
EASY: {ja: '簡単'},
|
865
|
+
NORMAL: {ja: '普通'},
|
866
|
+
HARD: {ja: '難しい'},
|
867
|
+
|
868
|
+
'New Game': {ja: '新規ゲーム'},
|
869
|
+
'Resume': {ja: 'ゲーム再開'},
|
870
|
+
|
871
|
+
'Best Time': {ja: 'ベストタイム'},
|
872
|
+
'Best Score': {ja: 'ベストスコア'},
|
873
|
+
"Today's Best Time": {ja: '本日のベストタイム'},
|
874
|
+
"Today's Best Score": {ja: '本日のベストスコア'},
|
875
|
+
|
876
|
+
"Start New Game?": {ja: '新しいゲームをはじめますか?'},
|
877
|
+
"Start Next Game": {ja: '次のゲームを開始'},
|
878
|
+
|
879
|
+
"Change Card Design": {ja: 'カードデザインを変更'},
|
880
|
+
"Change Background": {ja: 'ゲーム背景を変更'},
|
881
|
+
|
882
|
+
'(New Record!)': {ja: '(新記録!)'},
|
883
|
+
"(Today's Best!)": {ja: '(本日のベスト!)'},
|
884
|
+
}
|
885
|
+
|
886
|
+
def str(s, lang: $language)
|
887
|
+
STRINGS.dig(s.intern, lang&.intern) || s.to_s
|
674
888
|
end
|
675
889
|
|
676
890
|
end# Klondike
|
891
|
+
|
892
|
+
|
893
|
+
class Klondike::NextsPlace < CardPlace
|
894
|
+
|
895
|
+
def drawCount()
|
896
|
+
@game.difficulty == :hard ? 3 : 1
|
897
|
+
end
|
898
|
+
|
899
|
+
def started()
|
900
|
+
w = skin.cardSpriteSize[0] + overlap * (drawCount - 1)
|
901
|
+
self.x -= w - self.w
|
902
|
+
self.w = w
|
903
|
+
end
|
904
|
+
|
905
|
+
def add(*cards, **kwargs)
|
906
|
+
super
|
907
|
+
updateCards excludes: cards
|
908
|
+
end
|
909
|
+
|
910
|
+
def pop(*args)
|
911
|
+
super
|
912
|
+
updateCards
|
913
|
+
end
|
914
|
+
|
915
|
+
def posFor(card, index = nil)
|
916
|
+
index ||= indexFor card
|
917
|
+
super.tap do |pos|
|
918
|
+
rindex = cards.size - index
|
919
|
+
pos.x += overlap * (drawCount - rindex).clamp(0, drawCount - 1)
|
920
|
+
end
|
921
|
+
end
|
922
|
+
|
923
|
+
def overlap()
|
924
|
+
skin.cardSpriteSize[0] * 0.4
|
925
|
+
end
|
926
|
+
|
927
|
+
end# Klondike::NextsPlace
|
928
|
+
|
929
|
+
|
930
|
+
class Klondike::MarkPlace < CardPlace
|
931
|
+
|
932
|
+
def mark()
|
933
|
+
last&.mark
|
934
|
+
end
|
935
|
+
|
936
|
+
def accept?(x, y, card)
|
937
|
+
return false if !card || card.closed? || !card.canDrop?
|
938
|
+
hit?(x, y) &&
|
939
|
+
card.last? &&
|
940
|
+
card.opened? &&
|
941
|
+
(!mark || mark == card.mark) &&
|
942
|
+
card.number == last&.number.then {|n| n ? n + 1 : 1}
|
943
|
+
end
|
944
|
+
|
945
|
+
end# Klondike::MarkPlace
|
946
|
+
|
947
|
+
|
948
|
+
class Klondike::ColumnPlace < CardPlace
|
949
|
+
|
950
|
+
def initialize(*args, **kwargs, &block)
|
951
|
+
super(*args, linkCards: true, **kwargs, &block)
|
952
|
+
end
|
953
|
+
|
954
|
+
def accept?(x, y, card)
|
955
|
+
return false if !card || card.closed? || !card.canDrop?
|
956
|
+
if empty?
|
957
|
+
hit?(x, y) &&
|
958
|
+
card.number == 13
|
959
|
+
else
|
960
|
+
any? {|card| card.hit?(x, y)} &&
|
961
|
+
card.number == last.number - 1 &&
|
962
|
+
(@game.difficulty == :easy || card.color != last.color)
|
963
|
+
end
|
964
|
+
end
|
965
|
+
|
966
|
+
def posFor(card, index = nil)
|
967
|
+
index ||= indexFor card
|
968
|
+
super.tap do |pos|
|
969
|
+
pos.y += self.h * 0.3 * index
|
970
|
+
end
|
971
|
+
end
|
972
|
+
|
973
|
+
end# Klondike::ColumnPlace
|