Skip to content

Commit

Permalink
Merge pull request #27734 from mlangsdorf/npctalk_misc_json
Browse files Browse the repository at this point in the history
npctalk: add a bunch of new options to JSON
  • Loading branch information
ZhilkinSerg authored Jan 22, 2019
2 parents e4cfba7 + 60a36ea commit ab702bc
Show file tree
Hide file tree
Showing 6 changed files with 325 additions and 40 deletions.
99 changes: 99 additions & 0 deletions doc/NPCs.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,23 @@ A complex `dynamic_line` usually contains several `dynamic_line` entry and some
In all cases, `npc_` refers to the NPC, and `u_` refers to the player. Optional lines do not have to be defined, but the NPC should always have something to say. Entries are always parsed as `dynamic_line` and can be nested.
#### Several lines joined together
The dynamic line is a list of dynamic lines, all of which are displayed. The dynamic lines in the list are processed normally.
```C++
{
"and": [
{
"npc_male": "I'm a man.",
"npc_female": "I'm a woman."
},
" ",
{
"u_male": "You're a man.",
"u_female": "You're a woman."
}
]
}
```
#### Based on the gender of the NPC / NPC
The dynamic line is chosen based on the gender of the NPC. Both entries must exist.

Expand Down Expand Up @@ -263,6 +280,30 @@ The dynamic line is chosen based on whether the player character is performing a
}
```

#### Based on whether the player character or NPC are driving vehicles or not
The dynamic line is chosen if the player is driving a vehicle, or the NPC is driving a vehicle, or if neither are driving vehicles. The line from `u_driving` is chosen if the player is in control of a vehicle, the line from `npc_driving` is chosen if the NPC is in control of a vehicle, and the line from `no_vehicle` is chosen if neither are controlling a vehicle.

**NOTE**: NPCs can't drive vehicles right now.

```C++
{
"u_driving": "I said take a left at Albequerque!",
"npc_driving": "Who died and put me behind the wheel?",
"no_vehicle": "This is a good time to chat."
}
```

#### 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.

```C++
{
"has_pickup_list": true,
"yes": "I know what to get.",
"no": "What was I supposed to take?"
}
```

#### Based on the days since the Cataclysm
The dynamic line is chosen based on the specified number of days have elapsed since the start of the Catacylsm. Both entries are optional. The line from `yes` will be shown if at least that many days have passed, otherwise the line from `no`.

Expand Down Expand Up @@ -483,6 +524,9 @@ give_equipment | Allows your character to select items from the NPC's inventory
u_buy_item: item_string, (*optional* cost: cost_num, *optional* count: count_num, *optional* container: container_string) | The NPC will give your character the item or `count_num` copies of the item, contained in container, and will remove `cost_num` from your character's cash if specified.<br/>If cost isn't present, the NPC gives your character the item at no charge.
u_sell_item: item_string, (*optional* cost: cost_num, *optional* count: count_num) | Your character will give the NPC the item or `count_num` copies of the item, and will add `cost_num` to your character's cash if specified.<br/>If cost isn't present, the your character gives the NPC the item at no charge.<br/>This effect will fail if you do not have at least `count_num` copies of the item, so it should be checked with `u_has_items`.
u_spend_cash: cost_num | Remove `cost_num` from your character's cash. Negative values means your character gains cash.
add_debt: mod_list | Increases the NPC's debt to the player by the values in the mod_list.<br />The following would increase the NPC's debt to the player by 1500x the NPC's altruism and 1000x the NPC's opinion of the player's value.<br />```
{ "effect": { "add_debt": [ [ "ALTRUISM", 3 ], [ "VALUE", 2 ], [ "TOTAL", 500 ] ]
```
#### Behaviour / AI
Expand Down Expand Up @@ -539,6 +583,9 @@ trust, value, fear, and anger are optional keywords inside the opinion object. E
{ "effect": "follow", "opinion": { "trust": 1, "value": 1 }, "topic": "TALK_DONE" }
{ "topic": "TALK_DENY_FOLLOW", "effect": "deny_follow", "opinion": { "fear": -1, "value": -1, "anger": 1 } }
```
#### mission_opinion: { }
trust, value, fear, and anger are optional keywords inside the opinion object. Each keyword must be followed by a numeric value. The NPC's opinion is modified by the value of the current mission divided by the value of the keyword.
---
### response conditions
Expand Down Expand Up @@ -585,6 +632,9 @@ Condition | Type | Description
"has_no_available_mission" | simple string | `true` if the NPC has no jobs available for the player character.
"has_available_mission" | simple string | `true` if the NPC has one job available for the player character.
"has_many_available_missions" | simple string | `true` if the NPC has several jobs available for the player character.
"mission_goal" | string | `true` if the NPC's current mission has the same goal as `mission_goal`.
"mission_complete" | simple string | `true` if the player has completed the NPC's current mission.
"mission_incomplete" | simple string | `true` if the player hasn't completed the NPC's current mission.
"npc_service" | int | `true` if the NPC does not have the "currently_busy" effect and the player character has at least npc_service cash available. Useful to check if the player character can hire an NPC to perform a task that would take time to complete. Functionally, this is identical to `"and": [ { "not": { "npc_has_effect": "currently_busy" } }, { "u_has_cash": service_cost } ]`
"npc_allies" | int | `true` if the player character has at least `npc_allies` number of NPC allies.
"npc_following" | simple string | `true` if the NPC is following the player character.
Expand All @@ -594,6 +644,11 @@ Condition | Type | Description
Condition | Type | Description
--- | --- | ---
"npc_available" | simple string | `true` if the NPC does not have effect "currently_busy".
"npc_following" | simple string | `true` if the NPC is following the player character.
"npc_friend" | simple string | `true` if the NPC is friendly to the player character.
"npc_hostile" | simple string | `true` if the NPC is an enemy of the player character.
"npc_train_skills" | simple string | `true` if the NPC has one or more skills with more levels than the player.
"npc_train_styles" | simple string | `true` if the NPC knows one or more martial arts styles that the player does not know.
"npc_has_any_trait" | array | `true` if the NPC has any trait or mutation in the array. Used to check multiple traits.
"npc_has_class" | array | `true` if the NPC is a member of an NPC class.
"npc_has_effect" | string | `true` if the NPC is under the effect with npc_has_effect's `effect_id`.
Expand Down Expand Up @@ -668,5 +723,49 @@ Condition | Type | Description
{ "not": { "u_has_effect": "has_og_comm_freq" } }
]
}
},
{
"text": "I killed them. All of them.",
"topic": "TALK_MISSION_SUCCESS",
"condition": {
"and": [ { "or": [ { "mission_goal": "KILL_MONSTER_SPEC" }, { "mission_goal": "KILL_MONSTER_TYPE" } ] }, "mission_complete" ]
},
"switch": true
},
{
"text": "Glad to help. I need no payment.",
"topic": "TALK_NONE",
"effect": "clear_mission",
"mission_opinion": { "trust": 4, "value": 3 },
"opinion": { "fear": -1, "anger": -1 }
},
{
"text": "Maybe you can teach me something as payment?",
"topic": "TALK_TRAIN",
"condition": { "or": [ "npc_train_skills", "npc_train_styles" ] },
"effect": "mission_reward"
},
{
"truefalsetext": {
"true": "I killed him.",
"false": "I killed it.",
"condition": { "mission_goal": "ASSASSINATE" }
},
"condition": {
"and": [
"mission_incomplete",
{
"or": [
{ "mission_goal": "ASSASSINATE" },
{ "mission_goal": "KILL_MONSTER" },
{ "mission_goal": "KILL_MONSTER_SPEC" },
{ "mission_goal": "KILL_MONSTER_TYPE" }
]
}
]
},
"trial": { "type": "LIE", "difficulty": 10, "mod": [ [ "TRUST", 3 ] ] },
"success": { "topic": "TALK_NONE" },
"failure": { "topic": "TALK_MISSION_FAILURE" }
}
```
9 changes: 8 additions & 1 deletion src/dialogue.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ struct talk_effect_fun_t {
void set_u_sell_item( const std::string &new_trait, int cost, int count );
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 operator()( const dialogue &d ) const {
if( !function ) {
return;
Expand All @@ -118,9 +119,15 @@ struct talk_effect_fun_t {
*/
struct talk_effect_t {
/**
* How (if at all) the NPCs opinion of the player character (@ref npc::op_of_u) will change.
* How (if at all) the NPCs opinion of the player character (@ref npc::op_of_u)
* will change.
*/
npc_opinion opinion;
/**
* How (if at all) the NPCs opinion of the player character (@ref npc::op_of_u)
* will change. These values are divisors of the mission value.
*/
npc_opinion mission_opinion;
/**
* Topic to switch to. TALK_DONE ends the talking, TALK_NONE keeps the current topic.
*/
Expand Down
18 changes: 18 additions & 0 deletions src/mission.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <functional>
#include <iosfwd>
#include <map>
#include <unordered_map>
#include <string>
#include <vector>

Expand Down Expand Up @@ -66,6 +67,23 @@ enum mission_goal {
MGOAL_KILL_MONSTER_SPEC, // Kill a number of monsters from a given species
NUM_MGOAL
};
const std::unordered_map<std::string, mission_goal> mission_goal_strs = { {
{ "MGOAL_NULL", MGOAL_NULL },
{ "MGOAL_GO_TO", MGOAL_GO_TO },
{ "MGOAL_GO_TO_TYPE", MGOAL_GO_TO_TYPE },
{ "MGOAL_FIND_ITEM", MGOAL_FIND_ITEM },
{ "MGOAL_FIND_ANY_ITEM", MGOAL_FIND_ANY_ITEM },
{ "MGOAL_FIND_MONSTER", MGOAL_FIND_MONSTER },
{ "MGOAL_FIND_NPC", MGOAL_FIND_NPC },
{ "MGOAL_ASSASSINATE", MGOAL_ASSASSINATE },
{ "MGOAL_KILL_MONSTER", MGOAL_KILL_MONSTER },
{ "MGOAL_KILL_MONSTER_TYPE", MGOAL_KILL_MONSTER_TYPE },
{ "MGOAL_RECRUIT_NPC", MGOAL_RECRUIT_NPC },
{ "MGOAL_RECRUIT_NPC_CLASS", MGOAL_RECRUIT_NPC_CLASS },
{ "MGOAL_COMPUTER_TOGGLE", MGOAL_COMPUTER_TOGGLE },
{ "MGOAL_KILL_MONSTER_SPEC", MGOAL_KILL_MONSTER_SPEC }
}
};

struct mission_place {
// Return true if the place (global overmap terrain coordinate) is valid for starting a mission
Expand Down
Loading

0 comments on commit ab702bc

Please sign in to comment.