Skip to content

Commit

Permalink
Merge pull request #55380 from Ramza13/string_vars
Browse files Browse the repository at this point in the history
Improve dialog string variables
  • Loading branch information
kevingranade authored Feb 19, 2022
2 parents d5c8ddd + 3122f4d commit 27ab2a5
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 7 deletions.
4 changes: 3 additions & 1 deletion doc/NPCs.md
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ Effect | Description
`u_add_var, npc_add_var`: `var_name, type: type_str`, `context: context_str`, either `value: value_str` or `time: true` or `possible_values: string_array` | Your character or the NPC will store `value_str` as a variable that can be later retrieved by `u_has_var` or `npc_has_var`. `npc_add_var` can be used to store arbitrary local variables, and `u_add_var` can be used to store arbitrary "global" variables, and should be used in preference to setting effects. If `time` is used instead of `value_str`, then the current turn of the game is stored. If `possible_values` is used one of the values given at random will be used.
`u_lose_var`, `npc_lose_var`: `var_name`, `type: type_str`, `context: context_str` | Your character or the NPC will clear any stored variable that has the same `var_name`, `type_str`, and `context_str`.
`u_adjust_var, npc_adjust_var`: `var_name, type: type_str`, `context: context_str`, `adjustment: adjustment_num or adjustment_variable_object` | Your character or the NPC will adjust the stored variable by `adjustment_num` (or the value of the variable described by `adjustment_num` see `variable_object` above).
`set_string_var`: `type: string or variable object`, `target_var: variable_object`| Store string (or the variable described) from `set_string_var` in the variable object `target_var`.
`u_location_variable, npc_location_variable`: `target_var`,*optional* `min_radius: min_radius_int or min_radius_variable_object`,*optional* `max_radius: max_radius_int or max_radius_variable_object`, *optional* `outdoor_only: outdoor_only_bool`, *optional* `target_params: assign_mission_target` parameters | If `target_params` is defined it will be used to find a tile. See [the missions docs](MISSIONS_JSON.md) for `assign_mission_target` parameters. Otherwise targets a point between `min_radius_int`( or `min_radius_variable_object`)(defaults to 0) and `max_radius_int`( or `max_radius_variable_object`)(defaults to 0) spaces of the target and if `outdoor_only_bool` is true(defaults to false) will only choose outdoor spaces. The chosen point will be saved to `target_var` which is a `variable_object`.
`barber_hair` | Opens a menu allowing the player to choose a new hair style.
`barber_beard` | Opens a menu allowing the player to choose a new beard style.
Expand All @@ -645,7 +646,7 @@ Effect | Description
`u_add_morale: morale_string`, (*optional* `bonus: bonus_int` ), (*optional* `max_bonus: max_bonus_int or max_bonus_variable_object` ), (*optional* `duration: duration_string or duration_variable_object`), (*optional* `decay_start` : `decay_string or decay_variable_object`), (*optional* `capped`: `capped_bool`)<br/> `npc_add_morale: morale_string`, (*optional* `bonus: bonus_int or bonus_variable_object` ), (*optional* `max_bonus: max_bonus_int` ), (*optional* `duration: duration_int`), (*optional*`decay_start` : `decay_int`), (*optional* `capped`: `capped_bool`)| Your character or the NPC will gain a morale bonus of type `morale_string`. Morale is changed by `bonus_int`( or the value of the variable described by `bonus_variable_object` see `variable_object` above) (default 1), with a maximum of up to `max_bonus_int`(or `max_bonus_variable_object`) (default 1). It will last for `duration: duration_string` time (default 1 hour) or `duration_variable_object`. It will begin to decay after `decay_string` time (default 30 minutes) or `decay_variable_object`. `capped_bool` Whether this morale is capped or not, defaults to false.
`u_lose_morale: morale_string`<br/>`npc_lose_morale: morale_string` | Your character or the NPC will lose any morale of type `morale_string`.
`u_add_faction_trust: amount_int`<br/>`u_lose_faction_trust: amount_int` | Your character gains or loses trust with the speaking NPC's faction, which affects which items become available for trading from shopkeepers of that faction.
`u_message, npc_message: message_string`, (*optional* `sound: sound_bool`),(*optional* `outdoor_only: outdoor_only_bool`),(*optional* `snippet: snippet_bool`),(*optional* `same_snippet: snippet_bool`,(*optional* `type: type_string`),(*optional* `popup: popup_bool`) | Displays a message to either the player or the npc of `message_string`. Will not display unless the player or npc is the actual player. If `snippet_bool` is true(defaults to false) it will instead display a random snippet from `message_string` category, if `same_snippet_bool` is true(defaults to false) it will always use the same snippet and will set a variable that can be used for custom item names(this requires the snippets to have id's set). If `sound` is true (defaults to false) it will only display the message if the player is not deaf. `outdoor_only`(defaults to false) only matters when `sound` is true and will make the message less likely to be heard if the player is underground. Message will display as type of `type_string`. Type affects the color of message and can be any of the following values: good, neutral, bad, mixed, warning, info, debug, headshot, critical, grazing. enums.h has more info on each types use. If `popup_bool` is true the message will be in a modal popup the user has to dismiss to continue.
`u_message, npc_message: message_string`, (*optional* `sound: sound_bool`),(*optional* `outdoor_only: outdoor_only_bool`),(*optional* `snippet: snippet_bool`),(*optional* `same_snippet: snippet_bool`,(*optional* `type: type_string`),(*optional* `popup: popup_bool`) | Displays a message to either the player or the npc of `message_string`. Will not display unless the player or npc is the actual player. If `snippet_bool` is true(defaults to false) it will instead display a random snippet from `message_string` category, if `same_snippet_bool` is true(defaults to false) it will always use the same snippet and will set a variable that can be used for custom item names(this requires the snippets to have id's set). If `sound` is true (defaults to false) it will only display the message if the player is not deaf. `outdoor_only`(defaults to false) only matters when `sound` is true and will make the message less likely to be heard if the player is underground. Message will display as type of `type_string`. Type affects the color of message and can be any of the following values: good, neutral, bad, mixed, warning, info, debug, headshot, critical, grazing. enums.h has more info on each types use. If `popup_bool` is true the message will be in a modal popup the user has to dismiss to continue. You can add variable values into a message by use of the tags `<u_val:var_name>`, `<npc_val:var_name>` or `<global_val:var_name>`.
`u_cast_spell, npc_cast_spell : fake_spell_data` | The spell described by fake_spell_data will be cast with u or the npc as the caster and u or the npc's location as the target. Fake spell data can have the following attributes: `id:string`: the id of the spell to cast, (*optional* `hit_self`: bool ( defaults to false ) if true can hit the caster, `trigger_message`: string to display on trigger, `npc_message`: string for message if npc uses, `max_level` int max level of the spell, `min_level` int min level of the spell )
`u_assign_activity, npc_assign_activity: activity_id_string`, `duration: duration_string or duration_variable_object`) | Your character or the NPC will start activity `activity_id_string`. It will last for `duration: duration_string` time or `duration_variable_object`.
`u_teleport, npc_teleport: target_var_object`, (*optional* `success_message: success_message_string`), (*optional* `fail_message: fail_message_string`) | u or npc are teleported to the destination stored in the variable named by `target_var`. `target_var` is an object with `value`,`type` and `context` as string values and a bool `global` which determines if the variable is global or not. If the teleport succeeds and `success_message` is defined it will be displayed, if it fails and `fail_message` is defined it will be displayed.
Expand Down Expand Up @@ -817,6 +818,7 @@ Condition | Type | Description
`"u_has_var"`, `"npc_has_var"` | string | `"type": type_str`, `"context": context_str`, and `"value": value_str` are required fields in the same dictionary as `"u_has_var"` or `"npc_has_var"`.<br/>`true` is the player character or NPC has a variable set by `"u_add_var"` or `"npc_add_var"` with the string, `type_str`, `context_str`, and `value_str`.
`"u_compare_var"`, `"npc_compare_var"` | dictionary | `"type": type_str`, `"context": context_str`, `"op": op_str`, `"value": value_num or variable_object` are required fields, referencing a var as in `"u_add_var"` or `"npc_add_var"`.<br/>`true` if the player character or NPC has a stored variable that is true for the provided operator `op_str` (one of `==`, `!=`, `<`, `>`, `<=`, `>=`) and value (or the value of the variable described by `value` see `variable_object` above).
`"u_compare_time_since_var"`, `"npc_compare_time_since_var_"` | dictionary | `"type": type_str`, `"context": context_str`, `"op": op_str`, `"time": time_string` are required fields, referencing a var as in `"u_add_var"` or `"npc_add_var"`.<br/>`true` if the player character or NPC has a stored variable and the current turn and that value (converted to a time point) plus the time_string is true for the provided operator `op_str` (one of `==`, `!=`, `<`, `>`, `<=`, `>=`). *example*: `{ "u_compare_time_since_var": "test", "type": "test", "context": "var_time_test", "op": ">", "time": "3 days" }` returns true if the player character has a "test", "test", "var_time_test" variable and the current turn is greater than that value plus 3 days' worth of turns.
`"compare_string"` | array | The array must contain exactly two entries. They can be either strings or objects containing a variable object. Returns true if the strings are the same.
`"u_has_strength"`<br/>`"npc_has_strength"` | int or variable_object | `true` if the player character's or NPC's strength is at least the value of `u_has_strength` or `npc_has_strength` (or the value of the variable described see `variable_object` above).
`"u_has_dexterity"`<br/>`"npc_has_dexterity"` | int or variable_object | `true` if the player character's or NPC's dexterity is at least the value of `u_has_dexterity` or `npc_has_dexterity` ( or the value of the variable described see `variable_object` above).
`"u_has_intelligence"`<br/>`"npc_has_intelligence"` | int or variable_object| `true` if the player character's or NPC's intelligence is at least the value of `u_has_intelligence` or `npc_has_intelligence` ( or the value of the variable described see `variable_object` above).
Expand Down
55 changes: 54 additions & 1 deletion src/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,25 @@ duration_or_var get_duration_or_var( const JsonObject &jo, std::string member, b
return ret_val;
}

str_or_var get_str_or_var( const JsonValue &jv, std::string member, bool required,
std::string default_val )
{
str_or_var ret_val;
if( jv.test_string() ) {
ret_val.str_val = jv.get_string();
} else if( jv.test_object() ) {
var_info var = read_var_info( jv.get_object(), true );
ret_val.type = var.type;
ret_val.var_val = var.name;
ret_val.default_val = var.default_val;
} else if( required ) {
jv.throw_error( "No valid value for " + member );
} else {
ret_val.str_val = default_val;
}
return ret_val;
}

tripoint get_tripoint_from_var( talker *target, cata::optional<std::string> target_var,
var_type vtype, talker *var_source )
{
Expand All @@ -188,7 +207,9 @@ tripoint get_tripoint_from_var( talker *target, cata::optional<std::string> targ
var_info read_var_info( JsonObject jo, bool require_default )
{
std::string default_val;
if( jo.has_string( "default" ) ) {
if( jo.has_string( "default_str" ) ) {
default_val = jo.get_string( "default_str" );
} else if( jo.has_string( "default" ) ) {
default_val = std::to_string( to_turns<int>( read_from_json_string<time_duration>
( jo.get_member( "default" ), time_duration::units ) ) );
} else if( jo.has_int( "default" ) ) {
Expand Down Expand Up @@ -1104,6 +1125,36 @@ static tripoint get_tripoint_from_string( std::string type, T &d )
return tripoint();
}

template<class T>
void conditional_t<T>::set_compare_string( const JsonObject &jo, const std::string &member )
{
str_or_var first;
str_or_var second;
JsonArray objects = jo.get_array( member );
if( objects.size() != 2 ) {
jo.throw_error( "incorrect number of values. Expected 2 in " + jo.str() );
condition = []( const T & ) {
return false;
};
return;
}

if( objects.has_object( 0 ) ) {
first = get_str_or_var( objects.next(), member, true );
} else {
first.str_val = objects.next_string();
}
if( objects.has_object( 1 ) ) {
second = get_str_or_var( objects.next(), member, true );
} else {
second.str_val = objects.next_string();
}

condition = [first, second]( const T & d ) {
return first.evaluate( d.actor( first.is_npc() ) ) == second.evaluate( d.actor( second.is_npc() ) );
};
}

template<class T>
void conditional_t<T>::set_compare_int( const JsonObject &jo, const std::string &member )
{
Expand Down Expand Up @@ -1938,6 +1989,8 @@ conditional_t<T>::conditional_t( const JsonObject &jo )
set_has_faction_trust( jo, "u_has_faction_trust" );
} else if( jo.has_member( "compare_int" ) ) {
set_compare_int( jo, "compare_int" );
} else if( jo.has_member( "compare_string" ) ) {
set_compare_string( jo, "compare_string" );
} else {
for( const std::string &sub_member : dialogue_data::simple_string_conds ) {
if( jo.has_string( sub_member ) ) {
Expand Down
5 changes: 4 additions & 1 deletion src/condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ const std::unordered_set<std::string> complex_conds = { {
"is_temperature", "is_windpower", "is_humidity", "is_pressure", "u_is_height", "npc_is_height",
"u_has_worn_with_flag", "npc_has_worn_with_flag", "u_has_wielded_with_flag", "npc_has_wielded_with_flag",
"u_has_pain", "npc_has_pain", "u_has_power", "npc_has_power", "u_has_focus", "npc_has_focus", "u_has_morale",
"npc_has_morale", "u_is_on_terrain", "npc_is_on_terrain", "u_is_in_field", "npc_is_in_field", "compare_int"
"npc_has_morale", "u_is_on_terrain", "npc_is_on_terrain", "u_is_in_field", "npc_is_in_field", "compare_int", "compare_string"
}
};
} // namespace dialogue_data
str_or_var get_str_or_var( const JsonValue &jv, std::string member, bool required = true,
std::string default_val = "" );
int_or_var get_int_or_var( const JsonObject &jo, std::string member, bool required = true,
int default_val = 0 );
int_or_var_part get_int_or_var_part( const JsonValue &jv, std::string member, bool required = true,
Expand Down Expand Up @@ -171,6 +173,7 @@ struct conditional_t {
void set_u_know_recipe( const JsonObject &jo, const std::string &member );
void set_mission_has_generic_rewards();
void set_can_see( bool is_npc = false );
void set_compare_string( const JsonObject &jo, const std::string &member );
void set_compare_int( const JsonObject &jo, const std::string &member );
static std::function<int( const T & )> get_get_int( const JsonObject &jo );
static std::function<int( const T & )> get_get_int( std::string value, const JsonObject &jo );
Expand Down
Loading

0 comments on commit 27ab2a5

Please sign in to comment.