Action Management ~ End Conditions Design - uchicago-cs/chiventure GitHub Wiki
Team Action Management - End Conditions Design (Eric Chang)
Introduction
As of writing this, the only way to end a game is if a player moves into a "final room." This document describes the design of an additional game-ending mechanism: the game ends if specific items have been interacted with such that their attributes have been changed to an "end state." After the implementation of this feature, a game can end in three different ways:
- A player moves into a "final room"
- Specific items have been interacted with appropriately
- A combination of the above two methods
Mechanism Overview
How will this new mechanism be implemented?
- The file
include/game-state/item.hincludes definitions for agame_action_condition_tstruct, which would appropriately store an end condition. This struct contains:- a pointer to an item
- a pointer to an attribute to check
- the expected value of the attribute
include/game-state/item.halso contains a definition for anaction_condition_list_t, which would appropriately store a list of end conditions.- This list will be stored in the
game_tstruct defined ininclude/game-state/game.has the fieldaction_condition_list_t *end_conditions.
How can end conditions be added to a game?
The following function (which would add an end condition to a game's list of end conditions) would be added to game state's game module:
int add_end_condition_to_game(game_t *game, game_action_condition_t *end_condition)
Parameters:
game- the game to whichend_conditionshould be added toend_condition- the new end condition for this game
Returns:
FAILUREif the end condition cannot be added to the game. This can occur if:- the item in
end_conditionis not already part of the game - the attribute to check does not exist or is not an attribute of the item
- the item in
SUCCESSif the end_condition is successfully added to the game.
A note to WDL: since add_end_condition_to_game requires the item referenced in end_condition to already be a part of a game, end conditions should not be added to a game until after items have been added.
How will end conditions be checked during a game?
The following function (which would check if all end conditions have been met) would be added to game state's game module:
bool end_conditions_met(game_t *game)
Parameters:
game- the game to check the end conditions of
Returns:
trueif:- all end conditions have attributes with their expected values
- no end conditions exist (end_conditions is NULL)
falseif the attribute of at least one end condition does not match with its expected value
How will end conditions be removed from a game?
The following function (which would delete and free all game_action_condition_ts from an action_condition_list_t) would be added to game state's item module:
int delete_action_condition_llist(action_condition_list_t *head)
Parameters:
head- pointer to the first element in the list
Returns:
SUCCESSalways
Utilizing this Mechanism
add_end_condition_to_game- Used by WDL when loading games into chiventure
- Note that this function must be used AFTER loading in items into a game
- While I go into detail in how the following functions are used, I am not doing that with this function. Determining how exactly
add_end_condition_to_gamewill be utilized is a problem for WDL to work out. Since I am on the action management team and I will already be changing the code of game state to implement the functions, I or my team will likely be doing the work of integrating the other two functions into the code, so I went ahead and thought about how this can be done.
end_conditions_met- Used by action management in the
actionmanagementmodule after an action is successfully completed to determine if the game is over - In
do_item_actionanddo_item_item_action, in theelseblock that executes if the action is successfully carried out:- Use
sprintfto addgame_act->success_strtostring(note that this code is already implemented) - Check if the final room exists AND the current room is the final room AND
end_conditions_metreturns true- If this test evaluates to true, append a congratulatory message (similar to that on line 168) to
string
- If this test evaluates to true, append a congratulatory message (similar to that on line 168) to
- Set the value of
ret_stringto that ofstring(note that this code is already implemented) - Return
SUCCESS(note that this code is already implemented)
- Use
- In
do_path_action:- Switch the placements of the
if (move == SUCCESS)andelse if (move == FINAL_ROOM)so that the check for the final room comes first - Change the conditional statement
move == FINAL_ROOMtomove == FINAL_ROOM && end_conditions_met(g) - Change the conditional statement
move == SUCCESStomove == SUCCESS || move == FINAL_ROOM
- Switch the placements of the
- Used by action management in the
delete_action_condition_llist- Used by game state in the
game_freefunction found in the game module to free theend_conditionsfield of a game. - I don't know if it matters whether this function is called before
delete_all_roomsor after since both might be trying to free the same items - keep this in mind as a likely culprit if there's some nasty looking error from this area of the code
- Used by game state in the
Implementation Details
int add_end_condition_to_game(game_t *game, game_action_condition_t *end_condition):- Check that
end_condition->itemexists usingHASH_FIND- If item does not exist, return
FAILURE
- If item does not exist, return
- Check that the
end_condition->itemcontainsend_condition->attribute_to_check- If this check fails, return
FAILURE - Get attribute key, use
get_attribute, see if return value and original attribute point to same value/place in memory
- If this check fails, return
- Set
end_condition->nexttogame->end_conditions - Set
game->end_conditionstoend_condition
- Check that
bool end_conditions_met(game_t *game)- If
game->end_conditionsis NULL return true - Create new pointer
iteratortogame->end_conditions - Loop while
iterator->nextis not NULL:- if not
check_condition(iterator)return false
- if not
- At this point, all conditions have been checked and confirmed to be their expected values - return true
- If
int delete_action_condition_llist(action_condition_list_t *head):- For each node, free node
- I don't think freeing
itemorattribute_to_checkis necessary sincedelete_all_roomsshould free them (again though if there's an error I suspect this would be a cause)
Final Notes
- To use
end_conditions_met, the headers ofdo_item_actionanddo_item_item_actionwould need to be changed so that it is passed an additional parameter: a context structchiventure_ctx_t *clike that found as the first parameter ofdo_path_action- A search via
get grep -n do_item_actionreveals that the only places in code that use this function are in:src/cli/src/operations.c:161- the function that contains this line of code is itself passed a context struct, so updating the call would be simpletests/action_management/test_item_actions.c- this would require creating a dummy context struct to pass along
- A search via
get grep -n do_item_item_actionreveals that the only places in code that use this function are in:src/cli/src/operations.c:231- the function that contains this line of code is itself passed a context struct, so updating the call would be simpletests/action_management/test_item_item_actions.c- again, this would require creating a dummy context struct to pass along
- A search via
- I don't have any other actual notes. This design is probably way more detailed than is actually necessary, but I wanted to get as many details ironed out as possible dangit.