Quests ~ Globalization - uchicago-cs/chiventure GitHub Wiki
Overview
The Problem
Previously, we intended to add quests to the player struct by simply adding a quest_hash_t
typed variable into the struct and calling it a day. This turns out to cause many, many problems, primarily because it creates a circular dependency. The quest module includes many functions that depend on the player and adding this quest hash-table to the player class would make the player module also rely on the quest module. When we tried this, it gave numerous errors in a bunch of different files (including many that aren't related to quests at all other than include statements), all pertaining to different types not being declared. After some testing, it was clear these strange bugs were caused by the circular dependency.
The Solution
Much of the quest module relies on the player module, so removing that functionality is near-impossible. That means the best solution is to remove quests from the player module and find some other way of including quests without referencing quest_state.h
. From a conceptual standpoint, this means we need to globalize quests, making it so the only instance of each quest is in game_state
and all of the duplicate instances like the ones we were going to put into player
will be removed. That way, the player can communicate with quests indirectly by storing ids that the quests can manage through game_state
.
Note that quests are already getting stored in game_state
, so this rework is not introducing any additional global scope to muck up game_state
. If anything, this change actually cleans up the code by no longer requiring multiple duplicates of every quest for each player.
Struct Changes
The easiest way of accomplishing this design change is by replacing the quest_hash_t
we were going to add to the player module with a hash table of player_quest_t
structs and a hash table of player_task_t
structs as defined below:
typedef struct player_quest {
UI_hash_handle hh;
char *quest_id;
int completion;
} player_quest_t;
typedef struct player_task {
UT_hash_handle hh;
char *task_id;
bool completed;
} player_task_t;
This change should come along with removing int status
from the quest
struct and removing bool completed
from the task
struct.
By defining these structs in the player struct and using these over the regular quest_hash_t
tables, the player module can take advantage of quest ids being strings to remove the circular dependency.
Function Changes
Moving int status
and bool completed
from the quest
and task
structs is going to require small reworks to many of the functions in the quest
module. Here is a list of all of the functions that need to be changed:
quest_new()
: Currently callsquest_init()
with the final parameter,int status
, set to 0. This parameter is getting removed, so it should be removed from here as well.quest_init()
: Currently setsquest->status
to itsint status
parameter which is no longer relevant. This functionality needs to be removed.start_quest()
andfail_quest()
: Currently only setsquest->status
which is no longer relevant. Needs to be reworked to update a specific player's quest status instead. Also, these functions could be consolidated into a singleupdate_quest_status()
function since they both contain the same logic with the only difference being the new quest status value.is_quest_completed()
When this function determines that a quest is completed, it sets the quest's completion status, which now needs to be reworked with this new quest completion design.get_quest_status()
: This function no longer applies at all and barely served a purpose before this redesign. Realistically, it should be removed entirely.task_init()
: Currently setstask->completed
to false which is no longer relevant. This functionality needs to be removed.find_task()
: Currently checks if a given task is in the current path of a given tree and relies on completion to make the search more efficient. Needs to be reworked to take the completion status from a given player'splayer_task
hash table.complete_task()
: Currently sets completion for the task. Needs to set completion in the player'splayer_task
hash table.