Custom Scripts ~ Preliminary Design Ideas for Incorporation with Current Source Code - uchicago-cs/chiventure GitHub Wiki
Sprint #1: Source Code Notes and Preliminary Design Ideas
Status Quo of WDL (YAML)
- Game
- Start and end rooms
- Rooms
- Description of rooms
- Connection to other rooms
- Items
- ID and descriptions
- Actions(e.g. pull, push, take)
Given this structure, I believe it makes sense to begin with adding custom scripts only for ITEMS. Customizable actions for ITEMS include for example “taking the table is only successful if the player already has a chair in their inventory.” After figuring out the way to support custom scripts for ITEMS, we can then support customization for ROOMS, for example “Room B is only connected to Room D only if the player has the key.” With this in mind, we should ensure we design a versatile way to incorporate custom scripts to support additional aspects of the game in the future (tricky).
Potential Ways to Incorporate Custom Scripts into WDL
WDL specifies what the game is composed of and the actions possible for each item. Below are two possible ways we can incorporate custom scripts into WDL. The advantages and disadvantages of each method will be discussed, taking into account the current YAML implementation as well as its adaptability to the upcoming JSON implementation.
1
Since we are planning to require one custom script for each customizable action, we can pass on the custom script under each object we want to support customization for. Using the above table example and the existing code from connected rooms.wdl for demonstration purposes:
- id: "TABLE"
short_desc: "This is a table"
long_desc: "This is a table long"
in: "room B"
actions:
- action: "PUSH"
text_success: "You push the table"
text_fail: "You cannot push this table"
- action: "PULL"
text_success: "You pull the table"
text_fail: "You cannot pull this table"
- action: "TAKE"
custom_script: "\taketable_custom.lua"
text_success: "You take the table"
text_fail: "You cannot take this table"
state: "solid"
value: "no"
The custom script, which will be a Lua file for now, is added and passed on as a component of the TAKE action, which will be subsequently handled by Action Management.
Advantages
- Easy to understand from game-author perspective
- Readable format and only requires the addition of a custom script tag under the specific item or action the author wants to modify.
- High adaptability to JSON
- The hierarchical structure of this method, by including the custom script under the relevant item or object, lends itself nicely to the JSON format, which like YAML is hierarchical in nature.
- Suited to the current design of actions
- Actions, in Chiventure, are structs with multiple fields (this design will be further discussed later). The addition of this custom script component in the WDL can be easily dealt with by adding a matching field in the game action_t struct.
Disdvantages
- Potential difficulty in identifying which actions have custom scripts
- Readable format and only requires the addition of a custom script tag under the specific item or action the author wants to modify.
- High adaptability to JSON
- For large WDL files with many items, it may be difficult to quickly identify the objects that have custom scripts. Game authors will have to scroll through the entire file, looking for the custom script tag for each item.
2
To address 1’s disadvantage of having custom script tags scattered around the WDL file, another way to specify custom scripts is by having a dedicated block for custom scripts, just like how GAME and ROOMS do. Using the YAML syntax, it may look something like the following:
- - - # CUSTOM SCRIPTS
- "\taketable_custom.lua"
- "\randomizegold_chest"
- ...
This would require a separate struct containing these custom scripts to be created in the game_t struct when the WDL file is parsed. Then, Action Management, when executing each action, would iterate over this custom scripts struct and run any relevant custom scripts.
Advantages
- Centralized location of all custom scripts of the game
- Game-authors can easily see which custom scripts are included in the game in the WDL file and add more custom scripts if desired.
Disadvantages
- Separate struct is needed in game t
- An additional field would be needed in the game struct to specify the custom scripts included in the game by the game-author.
- Action and script stored separately
- With this design, the custom scripts are stored separately from their actions. Therefore, it is unclear how action management would be able to efficiently find and connect each script with its corresponding action during runtime.
Based on these two methods, 1 seems to be more appropriate since storing the script with its relevant action would be much more convenient for implementation purposes. Additionally, the hierarchical nature of 1 also lends itself to supporting custom scripts for rooms.
However, given that WDL will be undergoing a transformation and I haven’t done research on the exact details of how Lua scripts are run within in a program, this analysis should only provide a high-level idea of how we can include custom scripts into WDL.
Custom Scripts’ Impact and Reliance on Game State and Action
Management Since we want to add custom scripts for items, it is important to understand how Chiventure currently stores and uses information about each item and its actions:
- ITEM
- ID and descriptions
- Attributes
- Actions
- Action Name
- Conditions for action (Linked List Struct)
- ITEM
- Attribute to check and its expected value
- Next condition
- Effects of action
- Success and fail messages
It appears there is existing code in game_action.h supporting conditions for actions, but the code is not used or fully finished. Regardless, this is insightful for our purposes. Instead of having this condition struct (bolded above) and functions using and modifying these condition structs, we can potentially substitute it with a field that purely contains the custom script to be run. Then these condition functions (such as adding a new condition to the action, checking the condition, etc.) will not be needed in the source code and be moved to the Lua custom scripts. This change will also allow for more flexibility and customizability for game-authors who want to add more complex conditions.
Therefore, we may have to work with the Game State team to discuss how information about the custom script would be included within the action and item data structures. One possible idea is the following:
- ITEM
- ID and descriptions
- Attributes
- Actions
- Action Name
- Custom Script
- Effects of action
- Success and fail messages
Then, under this proposed structure, Action Management, instead of checking each con- dition when doing each action (currently this is done by all conditions met() specified in game action.h and used in actionmanagement.h), would simply run the custom script using the Lua API (I have not done research on how Lua files can be run within a C file yet, so I am not sure how exactly action management would run the script. But I will talk to my other members who have done research on Lua as part of their Task).
Customizable Aspects
There is a wide range of customizability that can be supported. However, each custom script may have a different purpose and, thus, require different implementations. Below are some examples of the uses of custom scripts and the aspects they may operate on:
- Scripts for checking conditions of an action
- Example 1: picking up table is successful if and only if the player has a chair in their inventory
- Scripts for returning a result used by an action
- Example 2: compute a random number, equal to the amount of gold the player will receive upon opening the chest
- Scripts for modification of game state
- Example 3: clear player’s inventory
- Example 4: dynamic room connections based on certain conditions
These scripts have different purposes. 1 returns a boolean specifying whether an action is successful, 2 returns a value that is used by the action, while 3 modifies the player’s attributes.
This exemplifies the variability of our custom scripts: 1 and 3 will require access to the player’s inventory; 2 will return a random number. How we can implement these different custom scripts in a standardized way so that a function can run the custom script and use its results regardless of its purpose/return type is still unclear. I will discuss this issue with the rest of the team.