-
Notifications
You must be signed in to change notification settings - Fork 13
NPC ~ NPC Battle Integration Changes Design Document
Most of the changes we'd like to make answer the questions under NPC_Battle and Class type in the NPC Battle Integration Design Document. This document essentially addresses two questions: 1) making npc_t
and npc_battle_t
more compatible with battle structs; 2) incorporating player class. To this end, we would like to make several changes to npc_t
, npc_battle_t
, and related functions in order to increase compatibility among npc_battle, npc, and battle modules. We have also met with RPG-Battles and RPG-Player Class to consult these changes and get our ideas approved.
typedef struct npc {
/* hh is used for hashtable, as provided in uthash.h */
/* Second hash handle is for storing npcs in specific rooms */
UT_hash_handle hh, hh_room;
/* NPC identifier */
char *npc_id;
/* short description of the NPC, <51 chars */
char *short_desc;
/* long description of the NPC, <301 chars */
char *long_desc;
/* pointer to an existing convo struct */
convo_t *dialogue;
/* pointer to inventory hashtable */
item_hash_t *inventory;
/* pointer to an existing class struct */
class_t *class;
/* pointer to an exisitng npc_move struct */
npc_mov_t *movement;
/* boolean representing whether or not the NPC will engage in battles */
bool will_fight;
/* either NULL or a pointer to an existing npc_battle struct */
npc_battle_t *npc_battle;
} npc_t;
typedef struct npc {
/* hh is used for hashtable, as provided in uthash.h */
/* Second hash handle is for storing npcs in specific rooms */
UT_hash_handle hh, hh_room;
/* NPC identifier */
char *npc_id;
/* short description of the NPC, <51 chars */
char *short_desc;
/* long description of the NPC, <301 chars */
char *long_desc;
/* pointer to an existing convo struct */
convo_t *dialogue;
/* pointer to inventory hashtable */
item_hash_t *inventory;
/* pointer to an existing class struct */
class_t *class;
/* pointer to an existing npc_move struct */
npc_mov_t *movement;
/* enum indicating hostility level of the npc */
hostility_t hostility_level;
/* either NULL or a pointer to an existing npc_battle struct */
npc_battle_t *npc_battle;
} npc_t;
We replaced bool will_fight
, a boolean indicating whether the NPC will engage in battle, with hostility_level
, which is a hostility_t
enum indicating whether an NPC is HOSTILE, CONDITIONAL FRIENDLY, or FRIENDLY. Instead of having a boolean, we can test whether an NPC can engage in battle by checking if their hostility_level
is HOSTILE. This is a more nuanced version of will_fight as there are more interesting scenarios that can branch off when incorporating the hostility_t
struct into npc_t
.
With this design, the line between FRIENDLY and non-FRIENDLY npcs will be more clear. FRIENDLY npcs, such as those that guide players through the game, introduce quests, etc. will remain FRIENDLY throughout the game as their main purpose is not to fight. HOSTILE npcs will always be ready to fight as they primarily serve as battlers. CONDITIONAL FRIENDLY npcs can also fight but only when circumstances push them towards becoming HOSTILE. For example, when a player provokes them using dialogue or by challenging them to a battle to increase their xp points or unlock a new level in the game. Such npcs will be initialized as CONDITIONAL FRIENDLY at the start of the game but upon provocation, their hostility_level
will be set as HOSTILE. As such, we will need to implement a function convert_hostility()
that converts an npc's hostility_level
from CONDITIONAL FRIENDLY to HOSTILE if a player has provoked an npc.
void convert_hostility(npc_t *npc, node_action_t *actions)
{
assert(npc != NULL);
assert(actions != NULL);
if (actions->action == START_BATTLE &&
npc->hostility_level == CONDITIONAL_FRIENDLY) {
npc->hostility_level = HOSTILE;
}
return;
}
NPC dialogue can incorporate convert_hostility()
into do_node_actions()
in src/npc/src/dialogue.c such that if a node action is START_BATTLE, the function calls convert_hostility()
.
typedef struct npc_battle {
/* NPC health level */
int health;
/* pointer to an existing stat struct */
stat_t *stats;
/* pointer to an existing move struct */
move_t *moves;
/* difficulty of the NPC's ai */
difficulty_t ai;
/* hostility level of the npc */
hostility_t hostility_level;
/* health level at which the NPC will surrender */
int surrender_level;
} npc_battle_t;
typedef struct npc_battle {
/* pointer to an existing stat struct */
stat_t *stats;
/* pointer to an existing move struct */
move_t *moves;
/* difficulty of the NPC's ai */
difficulty_t ai;
/* hostility level of the npc */
hostility_t hostility_level;
/* class of the npc */
class_t *class_type;
/* An inventory of items that can be used in battle */
battle_item_t *items;
} npc_battle_t;
After meeting with Battles, we decided to move surrender_level
into stat_t
and we removed health
from npc_battle_t
as stat_t
more comprehensively incorporates player health levels. hp
indicates current health level and max_hp
indicates maximum health level (starting health level). Additionally, we added class_type
and items
. Because the stats and battle items an npc holds will differ based on its class_type
, we decided to incorporate that attribute into npc_battle_t
. Adding battle_item_t
can increase compatibility between npc_battle_t
and combatant_t
, which is a struct in battle_structs.h
for a player engaged in battle. These changes will require making further changes to the main interface (init, new, and free) functions in relevant modules.
Player Class told us they are including a "vanilla" or standard class_type
for NPCs. During our meeting, we concluded that npcs and players can both share the default class_types listed in src/playerclass/src/class_prefabs.c
:
const char* const DEFAULT_CLASS_NAMES[] = {
"bard",
"monk",
"ranger",
"rogue",
"warrior",
"wizard"
};
To differentiate between npcs and players, however, Player Class will include a flag in class_prefab_new()
indicating whether the character is an npc or not. This way, the functions class_prefab_add_skills()
, class_allocate_skills()
, etc. will be applicable to npcs as well which will be useful when setting distinct skills for certain class_types
. For example, the vanilla/basic npc can have a default max_hp set to 30 and speed set to 20 while a bard npc can have max_hp set to 15 and speed set to 15.
We also decided to keep hostility_level
and class_type
as separate attributes. That is, an npc will not have a predetermined hostility_level
based simply on their class_type
. Instead, each class can have players with various hostility levels that can even change throughout the game upon provocation.
In our meeting with Skill Trees, we discussed having certain special skill nodes unlocked already for certain classes like wizard or warrior that are more powerful than other classes, while having all nodes locked for the vanilla npc case. The Skill Trees team is currently more focused on developing the effects of skills to be more complex and adding nodes to the skill tree struct rather than on differentiating skill trees for each class_type
. But in the future, they could collaborate with Player Class to develop a separate skill tree for each class_type
, including the basic npc.
The following are modules to make changes to in order to implement the aforementioned design plans.
- npc_battle.h and npc_battle.c
- npc.h and npc.c
- npc tests
- test_npc.c
- test_npc_battle.c
- battle tests
- test_battle_flow.c
- test_battle_print.c
- npc examples
- battle examples
In addition to modifying the above modules, for the next sprint we will first focus on working with NPC dialogue to implement a situation where the player provokes a CONDITIONAL FRIENDLY npc and starts a battle. Second, as mentioned in our initial design document, we will work with Open World to design where npcs will be located based on their hostility_level
, how a player can come up to challenge an npc to battle, and how a HOSTILE npc will come up to a player to start a fight.
A joint meeting between the Battle and Dialogue teams produced the following ideas for a potential use of hostility_t
in dialogue:
- Implement more NPC Actions specifically designed to provoke NPCs. Actions are represented as
nodes
within the directed graph representing dialogue. Thenode
struct is defined as follows:
typedef struct node {
char *node_id;
char *npc_dialogue;
int num_edges;
int num_available_edges;
edge_list_t *edges;
node_action_t *actions;
} node_t;
A specific struct called node_action_t
represents action nodes, meaning that for every NPC dialogue option, there are a certain number of defined actions that the player can take in response. The types of actions are defined by the node_action
enum.
typedef enum {
GIVE_ITEM,
TAKE_ITEM,
START_QUEST,
START_BATTLE
} node_action_type;
typedef struct node_action {
node_action_type action;
char *action_id;
struct node_action *next, *prev;
} node_action_t;
In future implementations, we could have dialogues trigger certain actions by adding more options to node_action_type
that can directly affect hostility_level
. Some examples include INSULT
, PUNCH
/KICK
, or YELL
. These actions can be taken outside or inside a dialogue, causing the dynamic modification of hostility_level
. However, this would depend on the integration of dialogue and action, which likely may not happen soon enough.
- Implement a
tone_t
enum within edge struct. Edges contain player dialogue responses.
typedef struct edge {
char *quip;
node_t *from, *to;
condition_t *conditions;
} edge_t;
We suggest the following modification of the edge_t
to include a tone_t
enum.
typedef struct edge {
char *quip;
node_t *from, *to;
condition_t *conditions;
tone_t tone;
} edge_t;
Various types of tones could be defined which would then be checked to dynamically alter hostility_level
. Here are some potential examples of types of tones:
typedef enum {
FRIENDLY,
ANGRY,
SAD,
JEALOUS,
SHY,
DISAPPOINTED,
APOLOGETIC,
HAPPY;
} tone_t;
When the player chooses a response in dialogue, the tone value of the option will be checked. Certain types of tones could cause the a CONDITIONAL_FRIENDLY
NPC to become HOSTILE
(ANGRY
, JEALOUS
) or vice-versa (APOLOGETIC
, FRIENDLY
).
- Another way to modify
hostility_level
would be to check for certain NPC dialogue responses in the code designing a conversation itself. For example, an example for NPC Dialogue calledconvotest.c
defines ascene_t
enum, where each NPC dialogue option is identified with a certain scene. We could simply check which scene the conversation is taking place in and modifyhostility_level
accordingly.
enum scene {wellMet, privacyVio, homeExpl, FightFlwr, FightStnd, Leave, ERROR};
char *scene_name(enum scene s)
{
switch(s)
{
case 1:
return "WellMet";
case 2:
return "PrivacyVio";
case 3:
return "HomeExpl";
case 4:
return "FightFlwr";
case 5:
return "FightStnd";
case 6:
return "Leave";
default:
return "ERROR";
};
}
-
Action Management
-
Battles
- Design Document
- Text Based Combat in Other Games
- User Stories
- Wishlist
- Battle Planning 2022
- Battle User Stories Review 2022
- Structs in Other Modules Related to Battles 2022
- Stat Changes Design Document
- Run Function Design Document
- CLI Integration Design Document
- Move Changes Design Document
- Unstubbing Stubs Design Document
- Battle Items and Equipment Design Document
- Battle Item Stats
- Battles Demo Design Document
- Battles Testing Moves, Items, and Equipment Design Document
- Sound integration with battle (design document)
-
Custom Actions
-
Custom Scripts
-
DSL
-
CLI
-
Enhanced CLI
-
Game-State
-
Graphics
- Design Plan
- Design document for integrating split screen graphics with chiventure
- GDL (Graphical Description Language)
- Graphics Sandbox
- Design Document for NPC Graphics and Dialogue
- Feature Wishlist (Spring 2021)
- Installing and Building raylib on a VM
- LibSDL Research
- Module Interactions
- Working with Raylib and SSH
- raylib
- GDL
-
Linking the Libzip and Json C to chiventure on CSIL machines
-
Lua
-
NPC
- Dependencies: Player class, Open world, Battle
- Action Documentation
- Design Document for NPC Generation in Openworld
- Design and Planning
- Establishing Dependencies
- Implementation of Custom Scripts
- Independent Feature: NPC Movement Design Document
- Player Interaction Design and Planning
- Dialogue
- Design Document for NPC Dialogue and Action Implementation
- Loading NPCs from WDL Files
- NPC Battle Integration Design Document
- NPC Battle Integration Changes Design Document
-
Open World
- Autogeneration and Game State
- Deciding an integration approach
- Designing approach for static integration into chiventure
- Feature Wishlist
- Generation Module Design layout
- Potential connections to the rest of chiventure
- Single Room Generation Module Design
- Source Document
- User Stories
- World Generation Algorithm Plan
- Loading OpenWorld Attribute from WDL
-
Player Class
-
Player
-
Quests
-
Rooms
-
Skill Trees
- Avoiding soft locks in skill tree integration
- Components of Exemplary Skill Trees
- Design Document and Interface Guide
- Environment interactions based on skill characteristics
- Integrating complex skill (combined, random, sequential, etc.) implementation
- Integration of a Leveling System
- Potential Integration with existing WDL
- Research on game balancing in regards to skill trees
- Research on skill tree support in modern day game engines
- SkillTree Wiki Summary
- Skilltree "effect" implementation and roadmap
- Summary of md doc file for skilltrees
- Design ideas in connection to other features
- Summary of Skill Tree Integration 2022
- The Difficulty of the Reading the World
- Complex Skills Summary
-
Sound
-
Stats
-
WDL