Files
Bubberstation/code/controllers/subsystem/achievements.dm
SkyratBot f4ff22e017 [MIRROR] Achievements now show how many people have unlocked them. [MDB IGNORE] (#23344)
* Achievements now show how many people have unlocked them. (#77083)

## About The Pull Request
Checking the achievements UI now shows a line below the Unlocked/Locked
status for normal achievements, informing the user of how many players
have unlocked said achievement. It also contains a tooltip; within it is
a percentile comparison with the most unlocked achievement.

Beside that, I've added a check in the achievement unit test to
ascertain that all award categories are actually present in the UI, and
as well moved all `ui_data` to `static_ui_date` considering it is not
the sort of interface that has to be constantly updated like an air
alarm or an APC.

Here's a screenshot of the UI, with the tooltip where my cursor would be
(the hot damn! achievement was var-edited of course):
![Hot damn
th](https://github.com/tgstation/tgstation/assets/42542238/d80bfe3a-e755-4036-a360-276d5d3395dc)

## Why It's Good For The Game
This should provide some fundamental statistics for achievements, from
which contributors and players can deduct the rarity and bragging
rights.

## Changelog

🆑
qol: The Achievements UI now shows how many people have unlocked a given
achievement.
fix: The "Skills" Category for achievements should no longer be hidden.
/🆑

---------

Co-authored-by: san7890 <the@ san7890.com>
Co-authored-by: Jordie0608 <4343468+Jordie0608@ users.noreply.github.com>

* Achievements now show how many people have unlocked them.

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
Co-authored-by: san7890 <the@ san7890.com>
Co-authored-by: Jordie0608 <4343468+Jordie0608@ users.noreply.github.com>
2023-08-26 10:49:51 -07:00

104 lines
3.6 KiB
Plaintext

SUBSYSTEM_DEF(achievements)
name = "Achievements"
flags = SS_NO_FIRE
init_order = INIT_ORDER_ACHIEVEMENTS
var/achievements_enabled = FALSE
///List of achievements
var/list/datum/award/achievement/achievements = list()
///The achievement with the highest amount of players that have unlocked it.
var/datum/award/achievement/most_unlocked_achievement
///List of scores
var/list/datum/award/score/scores = list()
///List of all awards
var/list/datum/award/awards = list()
/datum/controller/subsystem/achievements/Initialize()
if(!SSdbcore.Connect())
return SS_INIT_NO_NEED
achievements_enabled = TRUE
var/list/achievements_by_db_id = list()
for(var/datum/award/achievement/achievement as anything in subtypesof(/datum/award/achievement))
if(!initial(achievement.database_id)) // abstract type
continue
var/datum/award/achievement/instance = new achievement
achievements[achievement] = instance
awards[achievement] = instance
achievements_by_db_id[instance.database_id] = instance
for(var/datum/award/score/score as anything in subtypesof(/datum/award/score))
if(!initial(score.database_id)) // abstract type
continue
var/instance = new score
scores[score] = instance
awards[score] = instance
update_metadata()
/**
* Count how many (unlocked) achievements are in the achievements database
* then store that amount in the times_achieved variable for each achievement.
*
* Thanks to Jordie for the query.
*/
var/datum/db_query/query = SSdbcore.NewQuery(
"SELECT a.achievement_key, COUNT(a.achievement_key) AS count FROM achievements a \
JOIN achievement_metadata m ON a.achievement_key = m.achievement_key AND m.achievement_type = 'achievement' \
GROUP BY a.achievement_key ORDER BY count DESC"
)
if(query.Execute(async = TRUE))
while(query.NextRow())
var/id = query.item[1]
var/datum/award/achievement/instance = id ? achievements_by_db_id[id] : null
if(isnull(instance)) // removed achievement
continue
instance.times_achieved = query.item[2]
// the results are ordered in descending orders, so the first in the list should be the most unlocked one.
if(!most_unlocked_achievement)
most_unlocked_achievement = instance
qdel(query)
for(var/i in GLOB.clients)
var/client/C = i
if(!C.player_details.achievements.initialized)
C.player_details.achievements.InitializeData()
return SS_INIT_SUCCESS
/datum/controller/subsystem/achievements/Shutdown()
save_achievements_to_db()
/datum/controller/subsystem/achievements/proc/save_achievements_to_db()
var/list/cheevos_to_save = list()
for(var/ckey in GLOB.player_details)
var/datum/player_details/PD = GLOB.player_details[ckey]
if(!PD || !PD.achievements)
continue
cheevos_to_save += PD.achievements.get_changed_data()
if(!length(cheevos_to_save))
return
SSdbcore.MassInsert(format_table_name("achievements"),cheevos_to_save,duplicate_key = TRUE)
//Update the metadata if any are behind
/datum/controller/subsystem/achievements/proc/update_metadata()
var/list/current_metadata = list()
//select metadata here
var/datum/db_query/Q = SSdbcore.NewQuery("SELECT achievement_key,achievement_version FROM [format_table_name("achievement_metadata")]")
if(!Q.Execute(async = TRUE))
qdel(Q)
return
else
while(Q.NextRow())
current_metadata[Q.item[1]] = text2num(Q.item[2])
qdel(Q)
var/list/to_update = list()
for(var/T in awards)
var/datum/award/A = awards[T]
if(!current_metadata[A.database_id] || current_metadata[A.database_id] < A.achievement_version)
to_update += list(A.get_metadata_row())
if(to_update.len)
SSdbcore.MassInsert(format_table_name("achievement_metadata"),to_update,duplicate_key = TRUE)