Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add widgets for bodypart status #53975

Merged
merged 1 commit into from
Jan 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions data/json/ui/bodypart_status.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
[
{
"id": "bodypart_status_text",
"//": "Base widget for showing body part status; needs bodypart field defined in derived widget.",
"type": "widget",
"style": "text",
"var": "bp_status_text"
},
{
"id": "bp_status_head_text",
"type": "widget",
"label": "HEAD",
"bodypart": "head",
"copy-from": "bodypart_status_text"
},
{
"id": "bp_status_torso_text",
"type": "widget",
"label": "TORSO",
"bodypart": "torso",
"copy-from": "bodypart_status_text"
},
{
"id": "bp_status_left_arm_text",
"type": "widget",
"label": "L ARM",
"bodypart": "arm_l",
"copy-from": "bodypart_status_text"
},
{
"id": "bp_status_right_arm_text",
"type": "widget",
"label": "R ARM",
"bodypart": "arm_r",
"copy-from": "bodypart_status_text"
},
{
"id": "bp_status_left_leg_text",
"type": "widget",
"label": "L LEG",
"bodypart": "leg_l",
"copy-from": "bodypart_status_text"
},
{
"id": "bp_status_right_leg_text",
"type": "widget",
"label": "R LEG",
"bodypart": "leg_r",
"copy-from": "bodypart_status_text"
},
{
"id": "bodypart_status_top_layout",
"type": "widget",
"style": "layout",
"arrange": "columns",
"widgets": [ "bp_status_left_arm_text", "bp_status_head_text", "bp_status_right_arm_text" ]
},
{
"id": "bodypart_status_bottom_layout",
"type": "widget",
"style": "layout",
"arrange": "columns",
"widgets": [ "bp_status_left_leg_text", "bp_status_torso_text", "bp_status_right_leg_text" ]
},
{
"id": "bodypart_status_layout",
"type": "widget",
"style": "layout",
"label": "Body Part Status",
"arrange": "rows",
"widgets": [
"bp_status_head_text",
"bp_status_torso_text",
"bp_status_left_arm_text",
"bp_status_right_arm_text",
"bp_status_left_leg_text",
"bp_status_right_leg_text"
]
}
]
3 changes: 2 additions & 1 deletion data/json/ui/sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,8 @@
"rad_badge_desc",
"weapon_style_layout",
"place_date_time_layout",
"light_moon_wind_temp_layout"
"light_moon_wind_temp_layout",
"bodypart_status_layout"
]
}
]
16 changes: 16 additions & 0 deletions data/mods/TEST_DATA/widgets.json
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,22 @@
"bodypart": "torso",
"style": "number"
},
{
"id": "test_status_torso_text",
"type": "widget",
"label": "TORSO STATUS",
"var": "bp_status_text",
"bodypart": "torso",
"style": "text"
},
{
"id": "test_status_left_arm_text",
"type": "widget",
"label": "LEFT ARM STATUS",
"var": "bp_status_text",
"bodypart": "arm_l",
"style": "text"
},
{
"id": "test_stat_panel",
"type": "widget",
Expand Down
121 changes: 87 additions & 34 deletions src/panels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@
#include "weather_type.h"
#include "widget.h"

static const efftype_id effect_bandaged( "bandaged" );
static const efftype_id effect_bite( "bite" );
static const efftype_id effect_bleed( "bleed" );
static const efftype_id effect_disinfected( "disinfected" );
static const efftype_id effect_got_checked( "got_checked" );
static const efftype_id effect_hunger_blank( "hunger_blank" );
static const efftype_id effect_hunger_engorged( "hunger_engorged" );
Expand Down Expand Up @@ -1329,42 +1331,34 @@ nc_color display::limb_color( const Character &u, const bodypart_id &bp, bool bl
if( bp == bodypart_str_id::NULL_ID() ) {
return c_light_gray;
}
int color_bit = 0;
nc_color i_color = c_light_gray;
const int intense = u.get_effect_int( effect_bleed, bp );
if( bleed && intense > 0 ) {
color_bit += 1;
}
if( bite && u.has_effect( effect_bite, bp.id() ) ) {
color_bit += 10;
}
if( infect && u.has_effect( effect_infected, bp.id() ) ) {
color_bit += 100;
}
switch( color_bit ) {
case 1:
i_color = colorize_bleeding_intensity( intense );
break;
case 10:
i_color = c_blue;
break;
case 100:
i_color = c_green;
break;
case 11:
if( intense < 21 ) {
i_color = c_magenta;
} else {
i_color = c_magenta_red;
}
break;
case 101:
if( intense < 21 ) {
i_color = c_yellow;
} else {
i_color = c_yellow_red;
}
break;
const bool bleeding = bleed && intense > 0;
const bool bitten = bite && u.has_effect( effect_bite, bp.id() );
const bool infected = infect && u.has_effect( effect_infected, bp.id() );

// Handle worst cases first
if( bleeding && infected ) {
// Red and green make yellow
if( intense < 21 ) {
i_color = c_yellow;
} else {
i_color = c_yellow_red;
}
} else if( bleeding && bitten ) {
// Red and blue make magenta
if( intense < 21 ) {
i_color = c_magenta;
} else {
i_color = c_magenta_red;
}
} else if( infected ) {
i_color = c_green; // Green is very bad
} else if( bitten ) {
i_color = c_blue; // Blue is also bad
} else if( bleeding ) {
// Blood is some shade of red, naturally
i_color = colorize_bleeding_intensity( intense );
}

return i_color;
Expand Down Expand Up @@ -1434,6 +1428,65 @@ std::pair<std::string, nc_color> display::rad_badge_text_color( const Character
return std::make_pair( rad_text, rad_color );
}

std::vector<std::pair<std::string, nc_color>> display::bodypart_status_colors( const Character &u,
const bodypart_id &bp )
{
// List of status strings and colors
std::vector<std::pair<std::string, nc_color>> ret;
// Empty if no bodypart given
if( bp == bodypart_str_id::NULL_ID() ) {
return ret;
}

const int bleed_intensity = u.get_effect_int( effect_bleed, bp );
const bool bleeding = bleed_intensity > 0;
const bool bitten = u.has_effect( effect_bite, bp.id() );
const bool infected = u.has_effect( effect_infected, bp.id() );
const bool broken = u.is_limb_broken( bp ) && bp->is_limb;
const bool splinted = u.worn_with_flag( json_flag_SPLINT, bp );
const bool bandaged = u.has_effect( effect_bandaged, bp.id() );
const bool disinfected = u.has_effect( effect_disinfected, bp.id() );

// Ailments
if( broken ) {
ret.emplace_back( std::make_pair( "broken", c_magenta ) );
}
if( bitten ) {
ret.emplace_back( std::make_pair( "bitten", c_yellow ) );
}
if( bleeding ) {
ret.emplace_back( std::make_pair( "bleeding",
colorize_bleeding_intensity( bleed_intensity ) ) );
}
if( infected ) {
ret.emplace_back( std::make_pair( "infected", c_pink ) );
}
// Treatments
if( splinted ) {
ret.emplace_back( std::make_pair( "splinted", c_light_gray ) );
}
if( bandaged ) {
ret.emplace_back( std::make_pair( "bandaged", c_white ) );
}
if( disinfected ) {
ret.emplace_back( std::make_pair( "disinfected", c_light_green ) );
}

return ret;
}

std::string display::colorized_bodypart_status_text( const Character &u, const bodypart_id &bp )
{
// Colorized strings for each status
std::vector<std::string> color_strings;
// Get all status strings and colorize them
for( const std::pair<std::string, nc_color> &sc : display::bodypart_status_colors( u, bp ) ) {
color_strings.emplace_back( colorize( sc.first, sc.second ) );
}
// Join with commas, or return "--" if no statuses
return color_strings.empty() ? "--" : join( color_strings, ", " );
}

static void draw_stats( const draw_args &args )
{
const avatar &u = args._ava;
Expand Down
6 changes: 6 additions & 0 deletions src/panels.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ std::pair<std::string, nc_color> morale_emotion( const int morale_cur, const moo
// Current movement mode and color, as single letter or full word
std::pair<std::string, nc_color> move_mode_letter_color( const Character &u );
std::pair<std::string, nc_color> move_mode_text_color( const Character &u );
// Current body part status (bleeding, bitten, infected) phrase, fully colorized
std::string colorized_bodypart_status_text( const Character &u, const bodypart_id &bp );

std::pair<std::string, nc_color> temp_text_color( const Character &u );
std::pair<std::string, nc_color> power_text_color( const Character &u );
Expand All @@ -103,6 +105,10 @@ nc_color bodytemp_color( const Character &u, const bodypart_id &bp );
// Returns color which this limb would have in healing menus
nc_color limb_color( const Character &u, const bodypart_id &bp, bool bleed, bool bite,
bool infect );
// Return strings for all statuses affecting body part (bleeding, bitten, bandaged, etc.)
std::vector<std::pair<std::string, nc_color>> bodypart_status_colors( const Character &u,
const bodypart_id &bp );

// Color for displaying the given encumbrance level
nc_color encumb_color( const int level );

Expand Down
10 changes: 9 additions & 1 deletion src/widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ std::string enum_to_string<widget_var>( widget_var data )
return "activity_text";
case widget_var::body_temp_text:
return "body_temp_text";
case widget_var::bp_status_text:
return "bp_status_text";
case widget_var::date_text:
return "date_text";
case widget_var::env_temp_text:
Expand Down Expand Up @@ -442,6 +444,7 @@ bool widget::uses_text_function()
switch( _var ) {
case widget_var::activity_text:
case widget_var::body_temp_text:
case widget_var::bp_status_text:
case widget_var::date_text:
case widget_var::env_temp_text:
case widget_var::fatigue_text:
Expand Down Expand Up @@ -476,6 +479,7 @@ bool widget::uses_text_function()
std::string widget::color_text_function_string( const avatar &ava, unsigned int /*max_width*/ )
{
std::string ret;
bool apply_color = true;
std::pair<std::string, nc_color> desc;
// Give a default color (some widget_vars do not define one)
desc.second = c_light_gray;
Expand All @@ -486,6 +490,10 @@ std::string widget::color_text_function_string( const avatar &ava, unsigned int
case widget_var::body_temp_text:
desc = display::temp_text_color( ava );
break;
case widget_var::bp_status_text:
desc.first = display::colorized_bodypart_status_text( ava, _bp_id );
apply_color = false; // Has embedded color already
break;
case widget_var::date_text:
desc.first = display::date_string();
break;
Expand Down Expand Up @@ -563,7 +571,7 @@ std::string widget::color_text_function_string( const avatar &ava, unsigned int
io::enum_to_string<widget_var>( _var ) );
return _( "???" );
}
ret += colorize( desc.first, desc.second );
ret += apply_color ? colorize( desc.first, desc.second ) : desc.first;
return ret;
}

Expand Down
1 change: 1 addition & 0 deletions src/widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum class widget_var : int {
// Text vars
activity_text, // Activity level text, color string
body_temp_text, // Felt body temperature, color string
bp_status_text, // Status of bodypart (bleeding, bitten, and/or infected)
date_text, // Current date, in terms of day within season
env_temp_text, // Environment temperature, if character has thermometer
fatigue_text, // Fagitue description text, color string
Expand Down
Loading