Achievements System
Relevant source files
The following files were used as context for generating this wiki page:
The Achievements System is a client-side module designed to track player progress and reward them for reaching specific milestones within the game. It operates by periodically checking the game state against a predefined list of conditions. When a condition is met, an achievement is unlocked, a notification is displayed in the game's console, and the UI is updated.
The system is self-contained within the skidinc.achievements namespace. Its state, specifically the list of owned achievements, is integrated into the main game save and load mechanism, ensuring player progress is persisted across sessions.
Sources: app/js/achievements.js, app/js/core.js:10, 20, src/renderer/save-manager.js:283-285
Core Architecture
The system is managed through the global skidinc.achievements object, which holds the state and logic for all achievement-related functionality.
Sources: app/js/achievements.js:1
Key Components
| Component | Type | Description | Source File |
|---|---|---|---|
skidinc.achievements.ach | Array | Stores all achievement definition objects created by skidinc.achievements.create. | app/js/achievements.js:4 |
skidinc.achievements.owned | Array | A boolean array that tracks the unlocked status of each achievement. The index corresponds to the index in the ach array. | app/js/achievements.js:3 |
skidinc.achievements.categories | Array | A list of unique category names derived from the defined achievements. | app/js/achievements.js:2 |
skidinc.achievements.loop() | Function | The main loop that runs every second to check for unlock conditions. | app/js/achievements.js:203-217 |
skidinc.achievements.init() | Function | Initializes the system by defining all achievements and starting the main loop. | app/js/achievements.js:46-136 |
Data Structures
Achievement Object
Achievements are defined using the skidinc.achievements.create constructor. Each object contains the metadata and the condition required to unlock it.
// from app/js/achievements.js:40-45
skidinc.achievements.create = function(name, desc, category, icon, varCheck, typeCheck, amount) {
this.name = name;
this.desc = desc;
this.category = category;
this.icon = icon;
this.varCheck = varCheck;
this.typeCheck = typeCheck;
this.amount = amount;
};
Sources: app/js/achievements.js:40-45
The parameters for an achievement are as follows:
| Parameter | Type | Description |
|---|---|---|
name | String | The display name of the achievement. |
desc | String | A description of how to earn the achievement. |
category | String | A grouping category for the achievement. Used for UI. |
icon | String | The Font Awesome icon class for the UI. |
varCheck | String | A string representing the game state variable to check (e.g., 'skidinc.player.level'). |
typeCheck | String | The comparison operator (e.g., '>=', '=='). |
amount | Number | The value to compare the game state variable against. |
Sources: app/js/achievements.js:40-45
Achievement Data Relationship
The diagram below shows how achievement definitions are linked to the player's owned status.
This diagram illustrates that each defined achievement has a corresponding owned status in the player's state.
Sources: app/js/achievements.js:3-4, app/js/achievements.js:127-133
Execution Flow
Initialization
The achievement system is started during the game's initial setup.
skidinc.init()is called when the application starts.- This function calls
skidinc.achievements.init(). skidinc.achievements.init()populates theskidinc.achievements.acharray with dozens of predefined achievements.- It also initializes the
skidinc.achievements.ownedarray withfalsevalues for each achievement. - Finally, it starts a
setIntervalthat callsskidinc.achievements.loop()every 1000 milliseconds. - Separately,
skidinc.achievements.domInit()is called to build the achievement display in the UI.
Sources: app/js/core.js:10, 20, app/js/achievements.js:46-136
Main Loop and Unlocking Logic
The core logic resides in the skidinc.achievements.loop() function, which continuously checks if any unearned achievements have met their unlock criteria.
The following flowchart visualizes the process within the loop function.
This flowchart shows the process of checking each achievement, evaluating its condition if not already owned, and unlocking it if the condition is met.
The condition is constructed and evaluated dynamically using eval(). For example, an achievement defined as:
new skidinc.achievements.create('Experienced I', 'Reach level 5.', 'levelReached', 'fa-star', 'skidinc.player.level', '>=', 5)
will result in the evaluation of the string 'skidinc.player.level>=5'.
Sources: app/js/achievements.js:203-217
UI Integration
The achievements are displayed to the player in a modal window and can also be listed via a console command.
Achievements Modal
The main UI is a modal defined in index.html.
- Trigger: The modal is opened by clicking the "Success" link in the "More" dropdown menu in the stats panel.
- Structure: The modal (
#modal-achievements) contains a content area (#achievements-content) that is populated dynamically. - Dynamic Content: The
domInit()function creates the initial grid of achievement icons and names. Theupdate()function is called when an achievement is unlocked to refresh the description and name of the next achievement in that category.
<!-- from index.html:317-329 -->
<div id="modal-achievements" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="modal-success" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="fa fa-bar-chart"></i> Achievements (hover them for infos)</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<div id="achievements-content" class="modal-body">
<div class="row">
<div class="col-md-6 offset-3">
<p id="achievements-owned" class="text-center"></p>
</div>
</div>
</div>
</div>
</div>
</div>
Sources: index.html:84, 317-329, app/js/achievements.js:160-184
Console Command
The achievements command can be typed into the game's terminal to see a list of the next available achievements for each category. This is handled by the skidinc.achievements.list() function, which gets the next unowned achievement from each category and formats it for the console.
Sources: app/js/achievements.js:138-150, USER_GUIDE.md:126
Data Persistence
The player's achievement progress is saved as part of the main game state.
Saving State
- The
SaveStateManagerin the Electron renderer process gathers the current game state viagetCurrentGameState(). - This function captures the
skidinc.achievements.ownedarray. - The game state object, including the
achievementsproperty, is sent to the main process to be written to a file.
The achievements object in the save file is defined by the schema in data-validator.js.
// from src/data-validator.js:68-73
achievements: {
type: 'object',
required: false,
properties: {
owned: { type: 'array', required: true, default: [] }
}
},
Sources: src/renderer/save-manager.js:283-285, src/data-validator.js:68-73
Loading State
- When a save file is loaded, the
skidinc.save.load()function is called. - It parses the saved data and applies the
achievements.ownedarray from the save file to theskidinc.achievements.ownedobject in the running game. - The
saveInit()function is then called to ensure theownedarray's length matches the current number of defined achievements, preventing errors if new achievements were added in a game update.
This sequence diagram shows the save and load flow for achievement data.
Summary
The Achievements System is a robust, loop-driven module for managing player accomplishments. It defines achievements as objects with dynamic checking conditions, uses a setInterval to periodically evaluate them, and updates the UI and console upon unlocking. The system's state is simple—a boolean array tracking ownership—which is seamlessly integrated into the game's core save/load functionality, ensuring player progress is always preserved.