68 lines
1.9 KiB
Dart
68 lines
1.9 KiB
Dart
// lib/game/daily/daily_reward.dart
|
|
import '../models/booster.dart';
|
|
|
|
/// The result of evaluating the calendar for "today".
|
|
class DailyResolution {
|
|
const DailyResolution({required this.claimable, required this.day});
|
|
final bool claimable;
|
|
final int day; // 1..7, the day to show/grant
|
|
}
|
|
|
|
/// Pure 7-day login-calendar logic. No storage or clock — callers pass the
|
|
/// persisted state and today's date so it is fully unit-testable.
|
|
class DailyRewardCalendar {
|
|
const DailyRewardCalendar();
|
|
|
|
static const int cycle = 7;
|
|
|
|
String ymd(DateTime date) {
|
|
final m = date.month.toString().padLeft(2, '0');
|
|
final d = date.day.toString().padLeft(2, '0');
|
|
return '${date.year}-$m-$d';
|
|
}
|
|
|
|
DailyResolution resolve({
|
|
required String? lastClaimedYmd,
|
|
required int storedDay,
|
|
required DateTime today,
|
|
}) {
|
|
final todayYmd = ymd(today);
|
|
if (lastClaimedYmd == todayYmd) {
|
|
return DailyResolution(claimable: false, day: storedDay);
|
|
}
|
|
final yesterday = ymd(today.subtract(const Duration(days: 1)));
|
|
final int day;
|
|
if (lastClaimedYmd == yesterday) {
|
|
day = (storedDay % cycle) + 1; // advance, wrapping 7 -> 1
|
|
} else {
|
|
day = 1; // first ever, or a day was missed
|
|
}
|
|
return DailyResolution(claimable: true, day: day);
|
|
}
|
|
|
|
/// Boosters granted for a given calendar day (1..7). Tunable.
|
|
Map<BoosterType, int> rewardFor(int day) {
|
|
switch (day) {
|
|
case 1:
|
|
return {BoosterType.hammer: 1};
|
|
case 2:
|
|
return {BoosterType.shuffle: 1};
|
|
case 3:
|
|
return {BoosterType.lineBomb: 1};
|
|
case 4:
|
|
return {BoosterType.hammer: 1, BoosterType.shuffle: 1};
|
|
case 5:
|
|
return {BoosterType.shuffle: 1, BoosterType.lineBomb: 1};
|
|
case 6:
|
|
return {BoosterType.hammer: 1, BoosterType.lineBomb: 1};
|
|
case 7:
|
|
default:
|
|
return {
|
|
BoosterType.hammer: 2,
|
|
BoosterType.shuffle: 2,
|
|
BoosterType.lineBomb: 2,
|
|
};
|
|
}
|
|
}
|
|
}
|