There are a lot of ways to code this system, personally, I would code it in such a way to allow for high extendability and efficiency.
Off the top of my head, I would venture to say that we need a way to track user progress on challenges as well as a list of generated or hard-coded challenges to achieve.
Here is a free hand code example of what is going through my head.
local Goals = {
[1] = {
Kills = 100,
Progress = 0,
Discr = "Kill 100 Players",
}
}
Rewards = {
[1] = {
Gold = 100,
}
}
Here we have an example of the Goals table, what the user needs to do. Then we have a one-to-one relationship with the rewards table which allows us to attach the goal to the reward given the id of 1.
We can also consider a one to many with the rewards being the primary key and the foreign key being attacked to the Goals.
That would look like this:
local Goals = {
[1] = {
Kills = 100,
Progress = 0,
Discr = "Kill 100 Players",
RewardId = 1,
}
[2] = {
XP= 1000,
Progress = 0,
Discr = "Get 1000 XP",
RewardId = 1,
}
}
Rewards = {
[1] = {
Gold = 100,
}
}
Above is the established one-to-many with the rewards for the goals. This allows us to easily add new rewards and goals without overcomplicating the logic.
Now, Assuming we want to make this work, we need to use the actor-observer pattern. We need to setup events to keep track of when players do something that could add to the goals progress.
Lets say we have this player data table here.
local PlrData = {
Challenges = {1, 2}
}
This may look strange but bear with me, the values in this table correspond to another table called “PlayerProgress”. We would need to query that table to get the progress of the goals for that user.
That table structure would look like this:
local Database_PlayerProgress = {
[UserId] = {
[1] = {
Kills = 0;
};
[2] = {
XP = 0;
}
}
}
All we store is the progress of that challenge.
Now, when the user does something like kill the player, we can send an event to the controller and update that value.
function KillPlayerEvent(Player : Player)
local UserID = Player.UserId
local Progress = Database_PlayerProgress[UserID][1]
if Progress then -- this assumes we have the user id set.
Progress.Kills += 1
end
end
Saving the data is really simple, we have 4 separate tables, all of which contain separate data to keep things normalized and to prevent tight coupling.
This is my approach, many will disagree with me, but I come from a Data-Driven Design background and I have worked at some top Software companies and this is logically what came to mind. Hope this helped you.