NPC ~ Design and Planning - uchicago-cs/chiventure GitHub Wiki

team-npc: Lily Ehsani, Sadrac Camacho Guitierrez, Keith Heinz, Val Muhalia, Alex Sun

Introduction

This document will outline how existing interfaces of Chiventure will be used to create non-playable characters, and how new modules will be designed to implement and future-proof NPCs. For a more in

Important Existing Interfaces

game.h

  • game struct includes iteratable hash tables for players, rooms, and items

item.h

  • item struct includes hash handle, string id, string short description, string long description, hash table of actions, and hash table of attributes
  • attribute struct includes hash handle, string id, tag, and value (union of types to be loaded from WDL/used by action management)

player.h

  • player struct includes hash handle, string id, int level, int health, int xp, hash table of items inventory

New NPC Module

npc_t struct

NPC struct should include:

  • hash handle
  • string id
  • short description
  • long description
  • player class
  • dialogue tree hash table
  • item hash table inventory
  • will_fight (bool)
  • npc-battle struct:
    • health
    • stats
    • moves
    • ai
    • hostility level (friendly, conditional friendly, hostile)
    • surrender level (ie the level of health at which the NPC will surrender the battle)
    • maybe: a range of levels that a player has to be to fight the NPC
  • npc_mov struct:
    • room npc is currently in
    • movement type (definite or indefinite)

Code mockup:

typedef struct npc {
    UT_hash_handle hh;
    char *npc_id;
    char *short_desc;
    char *long_desc;
    convo_t *dialogue;
    item_hash_t *inventory;
    class_t *class; 
    npc_battle_t *npc_battle;
    npc_mov_t *movement;
} npc_t;

Also considering:

npc_t functions

  • npc_new
  • npc_init
  • npc_free
  • get_health and change_health (borrow from player.h?)
  • get_inventory (borrow from player.h?)

npc movement

Dialogue

Dialogue employs a branching dialogue methodology, as described here and here. For more information, please see the dialogue Wiki page.

Integration of NPC Module

game-state

npc.c and npc.h would take the form of game-state modules listed above.

Currently, the main game struct includes lists of all items and rooms present in the game. We would propose a similar list for NPCs so the game has access to that information. Additionally, the presence of NPCs in various rooms also needs to be stored either through the NPC struct or the room struct.

WDL/WDL++

Specifying an NPC should not be too difficult, as the struct is essentially a mix of components of items and players. The only issue I foresee is dialogue trees. As mentioned above, it is relatively simple to code dialogue trees using functions that print different text then call another function based on user input. It will be more of a challenge to program a framework for WDL/WDL++ specification of dialogue trees.

Dialogue integration

Note: As of the beginning of the 2022 edition of the class, this issue has been addressed. (See "CLI Integration" section of "NPC ~ Dialogue")

A current issue with the way conversations are run is that it requires opportunities for players to select options that are not specifically actions. The problem with this is that it puts the user in a state where they can both take actions and select dialogue options. This would let them, for example, leave the room in the middle of a conversation.

Possible solution: Modify the CLI to offer two different "modes" - (1) normal mode for regular interactions (including talk that could initiate a conversation), (2) conversation mode (in which the program only checks for dialogue options). This solution has other benefits, such as it potentially being used by the battle team if they need a way to isolate battle options from game actions.

RPG - Player Class and Skill Trees Overview

Overview provided by npc2 team (Matias, Andrew, Dylan)

  • NPC struct currently contains two class_t structs defined ambiguously:
      1. npc_class (the npc’s class)
      1. class (pointer to existing class struct)
  • There is no clear distinction between these, as mentioned in the New NPC Module Section
  • Class struct currently contains a skilltree_stub_t struct
    • This skilltree is stubbed, but is currently being integrated properly into the class struct
  • New ideas:
    • Implementing a set of passive skills or a “player_class_skill_tree” where alignment with a specific player class results in a set of passive skills then added to a player/npc general skill set.

NPC-Battle Integration

Ideas provided by the rpg-battle team including Sophie Veys and Celia Anderson

  • Hostile NPCs that can engage in battle
  • Weapons and spells that NPCs can have and use
  • NPC battle related stats
    • XP
    • HP/damage
    • HP regenerating (heal)
  • Players should battle NPCs with similar battle stats
  • NPC death
  • NPC item drop post death

New Ideas in 2021

  • We can add battle related stats to the NPC struct directly. To avoid clutter, we can have an npc-battle struct including health, moves, stats, etc.
  • Then in the battle module, they can get rid of the npc_enemy struct because all of that information would already be stored in the npc struct. The set_enemies function could just take a list of NPCs and return a combatant struct.
  • Finally, to address item drop post death, we were thinking that players should be presented with a list of items owned by the NPC they killed and should get to choose whether or not to add those to their items. We aren't totally sure how to implement this yet but will keep this in mind as a future step.

New structs and functions to integrate NPC and Battle

  • a new enum type, hostility, which specifies if an npc never fights (friendly), fights only when attacked (conditional_friendly), or attacks first (hostile)
    • Note: we should maybe change this because no friendly npcs should have a battle struct; maybe change it to just hostile (attacks first) and not hostile (fights when provoked)? Code mockup:
typedef enum hostility {
    FRIENDLY = 0,
    CONDITIONAL_FRIENDLY = 1,
    HOSTILE = 2
} hostility_t;
  • an npc_battle struct with relevant information for battles:
    • note: this should only be made for npcs that will fight (ie for whom will_fight = true). Npcs that never fight should have npc_battle be NULL instead of being a pointer to an npc_battle struct.
    • should we add a range of levels that the npc will fight?
typedef struct npc_battle {
    int health;
    stat_t *stats;
    move_t *moves;
    difficulty_t ai;
    hostility_t hostility_level;
    int surrender_level;
} npc_battle_t;
  • Basic functions for npc_battle struct:
    • npc_battle_init: initializes fields of a new npc_battle struct
    • npc_battle_new: creates a pointer to a new npc_battle struct
    • npc_battle_free: frees a pointer to an npc_battle struct
  • More advanced functions for npc_battle struct:
    • npc_add_battle: adds a pointer to a battle_struct to an npc struct
    • will_npc_fight: returns true if npc will fight, false otherwise
    • get functions for different fields in npc_battle (get_npc_surrender_level, etc.)
      • will talk with the battle team about which get functions would be the most helpful
    • set functions for different fields in npc_battle (change_npc_hostility, etc.)
      • again will talk with the battle team about which functions would be the most helpful, but should definitely include hostility_level, ai, and surrender_level

Next steps

See the RPC NPC Dependencies: Player class, Open world, Battle wiki page for details about our future plans for integrating NPC and Battle.

Task allocation between NPC teams (updated for Spring 2021)

(Will be updated upon first meeting of NPC teams)

  • NPC:
    • Movement
    • Rooms
  • NPC2:
    • Dialogue trees
    • Skill trees / Player classes

For a different document revision of this Wiki: Design Doc.pdf