Skip to content

Commit

Permalink
npctalk: NPC AI follower rules to JSON
Browse files Browse the repository at this point in the history
Change npc_follower_rules to use a enum bitfield instead of individual
booleans to make it easier to write a single function to toggle the
rules.

Then create functions to toggle NPC follower AI rules and move all that
dialogue into JSON.
  • Loading branch information
mlangsdorf committed Jan 26, 2019
1 parent 5da8e39 commit ce1b434
Show file tree
Hide file tree
Showing 12 changed files with 724 additions and 435 deletions.
414 changes: 414 additions & 0 deletions data/json/npcs/TALK_COMMON_ALLY.json

Large diffs are not rendered by default.

70 changes: 1 addition & 69 deletions data/json/npcs/TALK_COMMON_OTHER.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,65 +13,6 @@
{ "text": "Well, bye.", "topic": "TALK_DONE" }
]
},
{
"id": "TALK_FRIEND",
"type": "talk_topic",
"responses": [
{
"text": "Relax and chat with me for a while...",
"topic": "TALK_FRIEND_CHAT",
"condition": { "not": { "npc_has_effect": "asked_to_socialize" } }
}
]
},
{
"id": "TALK_FRIEND_CHAT",
"type": "talk_topic",
"dynamic_line": [
{ "u_has_item": "beer", "yes": "<noticedbooze>", "no": "<neutralchitchat>" },
{ "u_has_item": "european_pilsner", "yes": "<noticedbooze>", "no": "<neutralchitchat>" },
{ "u_has_item": "pale_ale", "yes": "<noticedbooze>", "no": "<neutralchitchat>" },
{ "u_has_item": "india_pale_ale", "yes": "<noticedbooze>", "no": "<neutralchitchat>" },
{
"is_season": "summer",
"yes": "Yeah, this summer heat is hitting me hard, let's take a quick break, how goes it <name_g>?",
"no": "<neutralchitchat>"
},
{
"is_season": "winter",
"yes": "OK, maybe it'll stop me from freezing in this weather, what's up?",
"no": "<neutralchitchat>"
},
{
"is_day": "Well, it's the time of day for a quick break surely! How are you holding up?",
"is_night": "Man it's dark out isn't it? what's up?"
},
{
"npc_has_effect": "infected",
"yes": "Well, I'm feeling pretty sick... are you doing OK though?",
"no": "<neutralchitchat>"
},
{
"u_has_mission": true,
"many": "Definitely, by the way, thanks for helping me so much with my tasks! Anyway, you coping OK, <name_g>? ",
"one": "OK, let's take a moment, oh, and thanks for helping me with that thing, so... what's up?",
"none": "<neutralchitchat>"
},
{
"days_since_cataclysm": 30,
"yes": "Now, we've got a moment, I was just thinking it's been a month or so since... since all this, how are you coping with it all?",
"no": "<neutralchitchat>"
}
],
"responses": [
{
"text": "Oh you know, not bad, not bad...",
"topic": "TALK_DONE",
"switch": true,
"effect": [ "morale_chat_activity", { "npc_add_effect": "asked_to_socialize", "duration": 7000 } ]
}
]
},
{
"id": "TALK_SHELTER_PLANS",
"type": "talk_topic",
Expand Down Expand Up @@ -168,15 +109,6 @@
"dynamic_line": "Yeah... I don't think so.",
"responses": [ { "text": "Oh, okay.", "topic": "TALK_DONE" } ]
},
{
"id": "TALK_LEAVE",
"type": "talk_topic",
"dynamic_line": "You're really leaving?",
"responses": [
{ "text": "Yeah, I'm sure. Bye.", "topic": "TALK_DONE", "effect": "leave" },
{ "text": "Nah, I'm just kidding.", "topic": "TALK_NONE" }
]
},
{
"id": "TALK_LEADER",
"type": "talk_topic",
Expand Down Expand Up @@ -230,7 +162,7 @@
"dynamic_line": "I'm on watch.",
"responses": [
{ "text": "I need you to come with me.", "topic": "TALK_FRIEND", "effect": "stop_guard" },
{ "text": "See you around.", "topic": "TALK_NONE" }
{ "text": "See you around.", "topic": "TALK_DONE" }
]
},
{
Expand Down
19 changes: 19 additions & 0 deletions data/json/npcs/TALK_TEST.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,25 @@
{ "text": "This an error! npc allies 2 test response.", "topic": "TALK_DONE", "condition": { "npc_allies": 2 } }
]
},
{
"type": "talk_topic",
"id": "TALK_TEST_NPC_RULES",
"dynamic_line": "This is a test conversation that shouldn't appear in the game.",
"responses": [
{ "text": "This is a basic test response.", "topic": "TALK_DONE" },
{
"text": "This is a npc engagement rule test response.",
"topic": "TALK_DONE",
"condition": { "npc_engagement_rule": "ENGAGE_ALL" }
},
{
"text": "This is a npc aim rule test response.",
"topic": "TALK_DONE",
"condition": { "npc_aim_rule": "AIM_SPRAY" }
},
{ "text": "This is a npc rule test response.", "topic": "TALK_DONE", "condition": { "npc_rule": "use_silent" } }
]
},
{
"type": "talk_topic",
"id": "TALK_TEST_NPC_NEEDS",
Expand Down
38 changes: 38 additions & 0 deletions doc/NPCs.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,33 @@ The dynamic line is chosen if the player is driving a vehicle, or the NPC is dri
}
```

#### Based on an NPC follower AI rule
The dynamic line is chosen based on NPC follower AI rules settings. There are three variants: `npc_aim_rule`, `npc_engagement_rule`, and `npc_rule`, all of which take a rule value and an optional `yes` and `no` response. The `yes` response is chosen if the NPC follower AI rule value matches the rule value and otherwise the no value is chosen.

`npc_aim_rule` values are currently "AIM_SPRAY", "AIM_WHEN_CONVENIENT", "AIM_PRECISE", or "AIM_STRICTLY_PRECISE".
`npc_engagement_rule` values are currently "ENGAGE_NONE", "ENGAGE_CLOSE", "ENGAGE_WEAK", "ENGAGE_HIT", or "ENGAGE_NO_MOVE".
`npc_rule` values are currently "use_guns", "use_grenades", "use_silent", "avoid_friendly_fire", "allow_pick_up", "allow_bash", "allow_sleep", "allow_complain", "allow_pulp", or "close_doors".

```C++
{
"and": [
{
"npc_aim_rule": "AIM_STRICTLY_PRECISE",
"yes": "No wasting ammo, got it. "
},
{
"npc_engagement_rule": "ENGAGE_NO_MOVE",
"yes": "Stay where I am. "
},
{
"npc_rule": "allow_pulp",
"yes": "Pulp the corpses when I'm done.",
"no": "Leave the corpses for someone else to deal with."
}
]
}
```

#### Based on whether the NPC has a pickup list
The dynamic line is chosen based on whether the NPC has a pickup list or not. The line from `yes` will be shown if they have a pickup list and otherwise the line from `no`. The line from `yes` will be shown even if `npc_rule`: `allow_pick_up` is false.

Expand Down Expand Up @@ -582,6 +609,9 @@ bionic_install | The NPC installs a bionic from your character's inventory onto
bionic_remove | The NPC removes a bionic from your character, using very high skill, and charging you according to the operation's difficulty.
npc_faction_change: faction_string | Change the NPC's faction membership to `faction_string`.
u_faction_rep: rep_num | Increase's your reputation with the NPC's current faction, or decreases it if `rep_num` is negative.
toggle_npc_rule: rule_string | Toggles the value of a boolean NPC follower AI rule such as "use_silent" or "allow_bash"
set_npc_engagement_rule: rule_string | Sets the NPC follower AI rule for engagement distance to the value of `rule_string`.
set_npc_aim_rule: rule_string | Sets the NPC follower AI rule for aiming speed to the value of `rule_string`.
#### Deprecated
Expand Down Expand Up @@ -683,6 +713,13 @@ Condition | Type | Description
"npc_role_nearby" | string | `true` if there is an NPC with the same companion mission role as `npc_role_nearby` within 100 tiles.
"npc_has_weapon" | simple string | `true` if the NPC is wielding a weapon.
#### NPC Follower AI rules
Condition | Type | Description
--- | --- | ---
"npc_aim_rule" | string | `true` if the NPC follower AI rule for aiming matches the string.
"npc_engagement_rule" | string | `true` if the NPC follower AI rule for engagement matches the string.
"npc_rule" | string | `true` if the NPC follower AI rule for that matches string is set.
#### Environment
Condition | Type | Description
Expand All @@ -692,6 +729,7 @@ Condition | Type | Description
"is_day" | simple string | `true` if it is currently daytime.
"is_outside" | simple string | `true` if the NPC is on a tile without a roof.
#### Sample responses with conditions
```C++
{
Expand Down
4 changes: 4 additions & 0 deletions src/dialogue.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ struct talk_effect_fun_t {
void set_npc_change_faction( const std::string &faction_name );
void set_change_faction_rep( int amount );
void set_add_debt( const std::vector<trial_mod> debt_modifiers );
void set_toggle_npc_rule( const std::string &rule );
void set_npc_engagement_rule( const std::string &setting );
void set_npc_aim_rule( const std::string &setting );

void operator()( const dialogue &d ) const {
if( !function ) {
return;
Expand Down
43 changes: 42 additions & 1 deletion src/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1655,7 +1655,7 @@ Creature::Attitude npc::attitude_to( const Creature &other ) const

int npc::smash_ability() const
{
if( !is_following() || rules.allow_bash ) {
if( !is_following() || rules.has_flag( ally_rule::allow_bash ) ) {
///\EFFECT_STR_NPC increases smash ability
return str_cur + weapon.damage_melee( DT_BASH );
}
Expand Down Expand Up @@ -2439,3 +2439,44 @@ void npc::set_attitude( npc_attitude new_attitude )
}
attitude = new_attitude;
}

npc_follower_rules::npc_follower_rules()
{
engagement = ENGAGE_CLOSE;
aim = AIM_WHEN_CONVENIENT;
set_flag( ally_rule::use_guns );
set_flag( ally_rule::use_grenades );
clear_flag( ally_rule::use_silent );
set_flag( ally_rule::avoid_friendly_fire );

clear_flag( ally_rule::allow_pick_up );
clear_flag( ally_rule::allow_bash );
clear_flag( ally_rule::allow_sleep );
set_flag( ally_rule::allow_complain );
set_flag( ally_rule::allow_pulp );
clear_flag( ally_rule::close_doors );
}

bool npc_follower_rules::has_flag( ally_rule test ) const
{
return static_cast<int>( test ) & static_cast<int>( flags );
}

void npc_follower_rules::set_flag( ally_rule setit )
{
flags = static_cast<ally_rule>( static_cast<int>( flags ) | static_cast<int>( setit ) );
}

void npc_follower_rules::clear_flag( ally_rule clearit )
{
flags = static_cast<ally_rule>( static_cast<int>( flags ) & ~static_cast<int>( clearit ) );
}

void npc_follower_rules::toggle_flag( ally_rule toggle )
{
if( has_flag( toggle ) ) {
clear_flag( toggle );
} else {
set_flag( toggle );
}
}
60 changes: 51 additions & 9 deletions src/npc.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ enum combat_engagement {
ENGAGE_ALL,
ENGAGE_NO_MOVE
};
const std::unordered_map<std::string, combat_engagement> combat_engagement_strs = { {
{ "ENGAGE_NONE", ENGAGE_NONE },
{ "ENGAGE_CLOSE", ENGAGE_CLOSE },
{ "ENGAGE_WEAK", ENGAGE_WEAK },
{ "ENGAGE_HIT", ENGAGE_HIT },
{ "ENGAGE_ALL", ENGAGE_ALL },
{ "ENGAGE_NO_MOVE", ENGAGE_NO_MOVE }
}
};


enum aim_rule {
// Aim some
Expand All @@ -190,19 +200,45 @@ enum aim_rule {
// If you can't aim, don't shoot
AIM_STRICTLY_PRECISE
};
const std::unordered_map<std::string, aim_rule> aim_rule_strs = { {
{ "AIM_WHEN_CONVENIENT", AIM_WHEN_CONVENIENT },
{ "AIM_SPRAY", AIM_SPRAY },
{ "AIM_PRECISE", AIM_PRECISE },
{ "AIM_STRICTLY_PRECISE", AIM_STRICTLY_PRECISE }
}
};

enum class ally_rule {
DEFAULT = 0,
use_guns = 1,
use_grenades = 2,
use_silent = 4,
avoid_friendly_fire = 8,
allow_pick_up = 16,
allow_bash = 32,
allow_sleep = 64,
allow_complain = 128,
allow_pulp = 256,
close_doors = 512
};
const std::unordered_map<std::string, ally_rule> ally_rule_strs = { {
{ "use_guns", ally_rule::use_guns },
{ "use_grenades", ally_rule::use_grenades },
{ "use_silent", ally_rule::use_silent },
{ "avoid_friendly_fire", ally_rule::avoid_friendly_fire },
{ "allow_pick_up", ally_rule::allow_pick_up },
{ "allow_bash", ally_rule::allow_bash },
{ "allow_sleep", ally_rule::allow_sleep },
{ "allow_complain", ally_rule::allow_complain },
{ "allow_pulp", ally_rule::allow_pulp },
{ "close_doors", ally_rule::close_doors }
}
};

struct npc_follower_rules {
combat_engagement engagement;
aim_rule aim = AIM_WHEN_CONVENIENT;
bool use_guns;
bool use_grenades;
bool use_silent;

bool allow_pick_up;
bool allow_bash;
bool allow_sleep;
bool allow_complain;
bool allow_pulp;
ally_rule flags;

bool close_doors;

Expand All @@ -212,6 +248,12 @@ struct npc_follower_rules {

void serialize( JsonOut &jsout ) const;
void deserialize( JsonIn &jsin );

bool has_flag( ally_rule test ) const;
void set_flag( ally_rule setit );
void clear_flag( ally_rule clearit );
void toggle_flag( ally_rule toggle );

};

// Data relevant only for this action
Expand Down
Loading

0 comments on commit ce1b434

Please sign in to comment.