File size: 4,617 Bytes
b6a38d7 |
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 |
ach_print = CreatePrint{
--"ach",
}
-- Game-specific hooks, titles should override these:
function CanUnlockAchievement(achievement)
local reasons = {}
Msg("UnableToUnlockAchievementReasons", reasons, achievement)
local reason = next(reasons)
return not reason, reason
end
-- Platform-specific functions:
function AsyncAchievementUnlock(achievement)
Msg("AchievementUnlocked", achievement)
end
function SynchronizeAchievements() end
PlatformCanUnlockAchievement = return_true
CheatPlatformUnlockAllAchievements = empty_func
CheatPlatformResetAllAchievements = empty_func
-- Common functions:
-- return unlocked, secret
function GetAchievementFlags(achievement)
return AccountStorage.achievements.unlocked[achievement], AchievementPresets[achievement].secret
end
function GetUnlockedAchievementsCount()
local unlocked, total = 0, 0
ForEachPreset(Achievement, function(achievement)
if not achievement:IsCurrentlyUsed() then return end
unlocked = unlocked + (AccountStorage.achievements.unlocked[achievement.id] and 1 or 0)
total = total + 1
end)
return unlocked, total
end
function _CheckAchievementProgress(achievement, dont_unlock_in_provider)
local progress = AccountStorage.achievements.progress[achievement] or 0
local target = AchievementPresets[achievement].target
if target and progress >= target then
AchievementUnlock(achievement, dont_unlock_in_provider)
end
end
local function EngineCanUnlockAchievement(achievement)
if Platform.demo then return false, "not available in demo" end
if GameState.Tutorial then
return false, "in tutorial"
end
if AccountStorage.achievements.unlocked[achievement] then
return false, "already unlocked"
end
assert(AchievementPresets[achievement])
if not AchievementPresets[achievement] then
return false, "dlc not present"
end
return PlatformCanUnlockAchievement(achievement)
end
local function CanModifyAchievementProgress(achievement)
-- 1. Engine-specific reasons not to modify achievement progress?
local success, reason = EngineCanUnlockAchievement(achievement)
if not success then
ach_print("cannot modify achievement progress, forbidden by engine check ", achievement, reason)
return false
end
-- 2. Game-specific reasons not to modify achievement progress?
local success, reason = CanUnlockAchievement(achievement)
if not success then
ach_print("cannot modify achievement progress, forbidden by title-specific check ", achievement, reason)
return false
end
return true
end
function AddAchievementProgress(achievement, progress, max_delay_save)
if not CanModifyAchievementProgress(achievement) then
return
end
local ach = AchievementPresets[achievement]
local current = AccountStorage.achievements.progress[achievement] or 0
local save_storage = not ach.save_interval or ((current + progress) / ach.save_interval > (current / ach.save_interval))
local total = current + progress
local target = ach.target or 0
if total >= target then
total = target
save_storage = false
end
AccountStorage.achievements.progress[achievement] = total
if save_storage then
SaveAccountStorage(max_delay_save)
end
Msg("AchievementProgress", achievement)
_CheckAchievementProgress(achievement)
return true
end
function ClearAchievementProgress(achievement, max_delay_save)
if not CanModifyAchievementProgress(achievement) then
return
end
AccountStorage.achievements.progress[achievement] = 0
SaveAccountStorage(max_delay_save)
Msg("AchievementProgress", achievement)
return true
end
-- Synchronous version, launches a thread
function AchievementUnlock(achievement, dont_unlock_in_provider)
if not CanModifyAchievementProgress(achievement) then
return
end
-- We set this before the thread, as otherwise calling AchievementUnlock twice will attempt to unlock it twice
AccountStorage.achievements.unlocked[achievement] = true
if not dont_unlock_in_provider then
AsyncAchievementUnlock(achievement)
end
SaveAccountStorage(5000)
return true
end
if Platform.developer then
function AchievementUnlockAll()
CreateRealTimeThread(function()
for id, achievement_data in sorted_pairs(AchievementPresets) do
AchievementUnlock(id)
Sleep(100)
end
end)
end
end
function OnMsg.NetConnect()
local unlocked = AccountStorage and AccountStorage.achievements and AccountStorage.achievements.unlocked
if not unlocked then return end
local achievements = {}
ForEachPreset(Achievement, function(achievement)
if unlocked[achievement.id] then
table.insert(achievements, achievement.id)
end
end)
NetGossip("AllAchievementsUnlocked", achievements)
end |