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.h
includes definitions for agame_action_condition_t
struct, 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.h
also 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_t
struct defined ininclude/game-state/game.h
as 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_condition
should be added toend_condition
- the new end condition for this game
Returns:
FAILURE
if the end condition cannot be added to the game. This can occur if:- the item in
end_condition
is not already part of the game - the attribute to check does not exist or is not an attribute of the item
- the item in
SUCCESS
if 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:
true
if:- all end conditions have attributes with their expected values
- no end conditions exist (end_conditions is NULL)
false
if 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_t
s 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:
SUCCESS
always
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_game
will 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
actionmanagement
module after an action is successfully completed to determine if the game is over - In
do_item_action
anddo_item_item_action
, in theelse
block that executes if the action is successfully carried out:- Use
sprintf
to addgame_act->success_str
tostring
(note that this code is already implemented) - Check if the final room exists AND the current room is the final room AND
end_conditions_met
returns 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_string
to 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_ROOM
tomove == FINAL_ROOM && end_conditions_met(g)
- Change the conditional statement
move == SUCCESS
tomove == 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_free
function found in the game module to free theend_conditions
field of a game. - I don't know if it matters whether this function is called before
delete_all_rooms
or 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->item
exists usingHASH_FIND
- If item does not exist, return
FAILURE
- If item does not exist, return
- Check that the
end_condition->item
containsend_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->next
togame->end_conditions
- Set
game->end_conditions
toend_condition
- Check that
bool end_conditions_met(game_t *game)
- If
game->end_conditions
is NULL return true - Create new pointer
iterator
togame->end_conditions
- Loop while
iterator->next
is 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
item
orattribute_to_check
is necessary sincedelete_all_rooms
should 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_action
anddo_item_item_action
would need to be changed so that it is passed an additional parameter: a context structchiventure_ctx_t *c
like that found as the first parameter ofdo_path_action
- A search via
get grep -n do_item_action
reveals 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_action
reveals 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.