Skip to content

Saturday Sessions: 20240728 Screen & Room Info

Joshua Wierenga edited this page Jul 28, 2024 · 3 revisions

Room Creation Tutorial Draft

This is a rough tutorial for creating new rooms in the project with unique functionality.

  1. Head to the “types.in.h” file in the backend folder of the project. Navigate to the InputOutcome enum and add a name for your custom room’s action (e.g. GameLookAroundOutcome with ID 11 in the following example). InputOutcome is used by the backend to run custom code when the user makes an input.
// InputOutcome is a uint16_t with (0, 65535]
JSON_ENUM_START(InputOutcome)
  JSON_ENUM_ITEM(InvalidInputOutcome,      0)
  ...
  JSON_ENUM_ITEM(GameOpenChestOutcome,     10)
             // <--- Your room outcome with following ID here (would be 11 in this case)
JSON_ENUM_END
  1. Also in “types.in.h”, add a room type that your room can be identified by in the RoomType enum following the same rules. RoomType is used by the backend to run custom code when displaying a game room.
// RoomType is a uint8_t with [0, 255)
JSON_ENUM_START(RoomType)
  JSON_ENUM_ITEM(EmptyRoomType,          0)
  ...
              // <--- Your room type name with ID here
  JSON_ENUM_ITEM(InvalidRoomType,      255)
JSON_ENUM_END
  1. Head to “GameData.in.json” and look for the GameCustomScreenCode section of the file. Add your new option players that will be able to select in your room here. The title field is the option players will see while the outcome is the function that will be run when it is selected. Some buttons have more fields containing extra information that the backend needs to handle that outcome as well.``
"screens": [
    ...
    {
      // ID: 1
      ...
      "buttons": [
        ...
        {
          "title": "Open Chest",
          "outcome": GameOpenChestOutcome
        },
          // <--- Your game button with title, outcome and possibly extra data here
        ...
      }
    },
    ...
  ]
  1. Below that, look for the rooms section of the json where information about rooms is stored. Add your room here, giving it the room type variable you created earlier, the position in which you want it to appear (x,y coords) and any extra data you want to include below.
"rooms": {
    ...
    "roomsArray": [
      ...
      {
        "type": HealthChangeRoomType,
        "position": [1, 2],
        "description": "You have come across a trap",
        "percentageChance": 50,
        "healthChange": -10
      },
      {
        "type": CustomChestRoomType,
        "position": [1, 3],
        "description": "A room with a chest lays before you",
        "itemContainedID": 11
      }, // <--- Add comma
         // <--- Your game room with type, position and possibly extra data here
    ]
    ...
  },
  1. Move to “specialscreens.c” and look for the CreateGameScreen function and find the room type for loop. This will define the conditions in which your option appears (e.g. being in the correct room type being obvious but other conditions such as stats or other features too).
static bool CreateGameScreen(const struct GameInfo *info, struct GameState *state) {
  ...
  for (uint_fast8_t i = 0; i < state->inputCount; ++i) {
    switch (state->inputs[i].outcome) {
      ...
      case GameHealthChangeOutcome:
        state->inputs[i].visible = state->roomInfo->type == HealthChangeRoomType;
        break;
      case GameOpenChestOutcome:
        state->inputs[i].visible = *pOpenedChest == 0 && state->roomInfo->type == CustomChestRoomType;
        break;
           // <--- Your button visibility check here
      default:
        break;
    }
  }

  return true;
}
  1. Go to “game.c” and look for the button.outcome switch statement in the HandleGameInput function. This is where the functionality of every selectable game option is defined. Create a case for your option following the structure of the others.
enum InputOutcome HandleGameInput(const struct GameInfo *info, struct GameState *state,
                                  uint_fast8_t buttonInputIndex, const char *textInput) {
  ...
  if (ButtonScreenInputType == state->inputType && UINT_FAST8_MAX != buttonInputIndex) {
  ...
    switch (button.outcome) {
      case GotoScreenOutcome:
        state->screenID = button.newScreenID;
        return GetNextOutputOutcome;
      ...
      case GameOpenChestOutcome:
        size_t openedChestVarOffset = GetGameStateOffset(state->screenID, 1);
        if (openedChestVarOffset == SIZE_MAX) {
          return InvalidInputOutcome;
        }
        uint8_t *pOpenedChest = (uint8_t *)(state->stateData + openedChestVarOffset);
        *pOpenedChest = 1;
        
        return GetNextOutputOutcome;
            // <--- Your button outcome code here
      ...
    }
  ...

  return InvalidInputOutcome;
}

Clone this wiki locally