From aa998cb745ae4be25219737c6b4c8e9aaf2d6cb8 Mon Sep 17 00:00:00 2001 From: OzoneH3 Date: Mon, 11 Nov 2019 15:42:02 +0100 Subject: [PATCH] Create template from character. --- src/avatar.cpp | 8 +++++ src/avatar.h | 24 +++++++------ src/character.cpp | 6 ++-- src/character.h | 3 +- src/main_menu.cpp | 83 ++++++++++++++++++++++++++------------------ src/newcharacter.cpp | 19 ++++++---- 6 files changed, 87 insertions(+), 56 deletions(-) diff --git a/src/avatar.cpp b/src/avatar.cpp index 390b50bab3a9c..b6365f31d3fc1 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -193,6 +193,14 @@ mission *avatar::get_active_mission() const return active_mission; } +void avatar::reset_all_misions() +{ + active_mission = nullptr; + active_missions.clear(); + completed_missions.clear(); + failed_missions.clear(); +} + tripoint avatar::get_active_mission_target() const { if( active_mission == nullptr ) { diff --git a/src/avatar.h b/src/avatar.h index babd655e71bab..8110c584b112f 100644 --- a/src/avatar.h +++ b/src/avatar.h @@ -82,6 +82,8 @@ class avatar : public player void update_mental_focus(); /** Resets stats, and applies effects in an idempotent manner */ void reset_stats() override; + /** Resets all missions before saving character to template */ + void reset_all_misions(); std::vector get_active_missions() const; std::vector get_completed_missions() const; @@ -252,7 +254,7 @@ struct points_left { return stat_points + trait_points + skill_points; case MULTI_POOL: return std::min( trait_points_left(), - stat_points + std::min( 0, trait_points + skill_points ) ); + stat_points + std::min( 0, trait_points + skill_points ) ); case TRANSFER: return 0; } @@ -284,8 +286,8 @@ struct points_left { bool is_valid() { return is_freeform() || - ( stat_points_left() >= 0 && trait_points_left() >= 0 && - skill_points_left() >= 0 ); + ( stat_points_left() >= 0 && trait_points_left() >= 0 && + skill_points_left() >= 0 ); } bool has_spare() { @@ -295,16 +297,16 @@ struct points_left { std::string to_string() { if( limit == MULTI_POOL ) { return string_format( - _( "Points left: %d%c%d%c%d=%d" ), - stat_points_left() >= 0 ? "light_gray" : "red", stat_points, - trait_points >= 0 ? '+' : '-', - trait_points_left() >= 0 ? "light_gray" : "red", abs( trait_points ), - skill_points >= 0 ? '+' : '-', - skill_points_left() >= 0 ? "light_gray" : "red", abs( skill_points ), - is_valid() ? "light_gray" : "red", stat_points + trait_points + skill_points ); + _( "Points left: %d%c%d%c%d=%d" ), + stat_points_left() >= 0 ? "light_gray" : "red", stat_points, + trait_points >= 0 ? '+' : '-', + trait_points_left() >= 0 ? "light_gray" : "red", abs( trait_points ), + skill_points >= 0 ? '+' : '-', + skill_points_left() >= 0 ? "light_gray" : "red", abs( skill_points ), + is_valid() ? "light_gray" : "red", stat_points + trait_points + skill_points ); } else if( limit == ONE_POOL ) { return string_format( _( "Points left: %4d" ), skill_points_left() ); - } else if( limit == TRANSFER ){ + } else if( limit == TRANSFER ) { return _( "Character Transfer: No changes can be made." ); } else { return _( "Freeform" ); diff --git a/src/character.cpp b/src/character.cpp index a802ab7fddd5c..2163ee4bff5a2 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -280,11 +280,11 @@ Character::~Character() = default; Character::Character( Character && ) = default; Character &Character::operator=( Character && ) = default; -void Character::setID( character_id i ) +void Character::setID( character_id i, const bool force ) { - if( id.is_valid() ) { + if( id.is_valid() && !force ) { debugmsg( "tried to set id of a npc/player, but has already a id: %d", id.get_value() ); - } else if( !i.is_valid() ) { + } else if( !i.is_valid() && !force ) { debugmsg( "tried to set invalid id of a npc/player: %d", i.get_value() ); } else { id = i; diff --git a/src/character.h b/src/character.h index ff6d811470f24..9a45de6b4a3fd 100644 --- a/src/character.h +++ b/src/character.h @@ -199,7 +199,8 @@ class Character : public Creature, public visitable character_id getID() const; // sets the ID, will *only* succeed when the current id is not valid - void setID( character_id i ); + // allows forcing a -1 id which is required for templates to not throw errors + void setID( character_id i, const bool force = false ); field_type_id bloodType() const override; field_type_id gibType() const override; diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 99b48c7302f41..c48f3f3a87b50 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -880,36 +880,41 @@ bool main_menu::new_character_tab() bool main_menu::load_character_tab( bool transfer ) { + bool start = false; + const auto all_worldnames = world_generator->all_worldnames(); + if( transfer ) { layer = 3; sel1 = 2; sel2 -= 1; - } - - bool start = false; - const auto all_worldnames = world_generator->all_worldnames(); - - const size_t last_world_pos = std::find( all_worldnames.begin(), all_worldnames.end(), - world_generator->last_world_name ) - all_worldnames.begin(); - if( last_world_pos < all_worldnames.size() ) { - sel2 = last_world_pos; + sel3 = 0; savegames = world_generator->get_world( all_worldnames[sel2] )->world_saves; - } - const size_t last_character_pos = std::find_if( savegames.begin(), savegames.end(), - []( const save_t &it ) { - return it.player_name() == world_generator->last_character_name; - } ) - savegames.begin(); - if( last_character_pos < savegames.size() ) { - sel3 = last_character_pos; } else { - sel3 = 0; + const size_t last_world_pos = std::find( all_worldnames.begin(), all_worldnames.end(), + world_generator->last_world_name ) - all_worldnames.begin(); + if( last_world_pos < all_worldnames.size() ) { + sel2 = last_world_pos; + savegames = world_generator->get_world( all_worldnames[sel2] )->world_saves; + } + + const size_t last_character_pos = std::find_if( savegames.begin(), savegames.end(), + []( const save_t &it ) { + return it.player_name() == world_generator->last_character_name; + } ) - savegames.begin(); + if( last_character_pos < savegames.size() ) { + sel3 = last_character_pos; + } else { + sel3 = 0; + } } + const int offset_x = transfer ? 25 : 15; + const int offset_y = transfer ? -1 : 0; while( !start && sel1 == 2 && ( layer == 2 || layer == 3 ) ) { - print_menu( w_open, 2, menu_offset ); + print_menu( w_open, transfer ? 3 : 2, menu_offset ); if( layer == 2 && sel1 == 2 ) { if( all_worldnames.empty() ) { - mvwprintz( w_open, menu_offset + point( 15 + extra_w / 2, -2 ), + mvwprintz( w_open, menu_offset + point( offset_x + extra_w / 2, -2 ), c_red, "%s", _( "No Worlds found!" ) ); on_error(); } else { @@ -925,7 +930,7 @@ bool main_menu::load_character_tab( bool transfer ) color1 = c_white; color2 = h_white; } - mvwprintz( w_open, point( 15 + menu_offset.x + extra_w / 2, line ), + mvwprintz( w_open, point( offset_x + menu_offset.x + extra_w / 2, line + offset_y ), ( sel2 == i ? color2 : color1 ), "%s (%d)", world_name, savegames_count ); } @@ -967,11 +972,11 @@ bool main_menu::load_character_tab( bool transfer ) savegames.erase( new_end, savegames.end() ); } - mvwprintz( w_open, menu_offset + point( 15 + extra_w / 2, -2 - sel2 ), h_white, + mvwprintz( w_open, menu_offset + point( offset_x + extra_w / 2, -2 - sel2 + offset_y ), h_white, "%s", wn ); if( savegames.empty() ) { - mvwprintz( w_open, menu_offset + point( 40 + extra_w / 2, -2 - sel2 ), + mvwprintz( w_open, menu_offset + point( 40 + extra_w / 2, -2 - sel2 + offset_y ), c_red, "%s", _( "No save games found!" ) ); on_error(); } else { @@ -979,7 +984,7 @@ bool main_menu::load_character_tab( bool transfer ) for( const auto &savename : savegames ) { const bool selected = sel3 + line == menu_offset.y - 2; - mvwprintz( w_open, point( 40 + menu_offset.x + extra_w / 2, line-- ), + mvwprintz( w_open, point( 40 + menu_offset.x + extra_w / 2, line-- + offset_y ), selected ? h_white : c_white, "%s", savename.player_name() ); } @@ -989,7 +994,7 @@ bool main_menu::load_character_tab( bool transfer ) std::string action = handle_input_timeout( ctxt ); if( errflag && action != "TIMEOUT" ) { clear_error(); - layer = 2; + layer = transfer ? 1 : 2; } else if( action == "DOWN" ) { if( sel3 > 0 ) { sel3--; @@ -1003,7 +1008,7 @@ bool main_menu::load_character_tab( bool transfer ) sel3 = 0; } } else if( action == "LEFT" || action == "QUIT" ) { - layer = 2; + layer = transfer ? 1 : 2; sel3 = 0; print_menu( w_open, sel1, menu_offset ); } @@ -1011,11 +1016,13 @@ bool main_menu::load_character_tab( bool transfer ) if( sel3 >= 0 && sel3 < static_cast( savegames.size() ) ) { werase( w_background ); wrefresh( w_background ); + WORLDPTR world = world_generator->get_world( all_worldnames[sel2] ); world_generator->last_world_name = world->world_name; world_generator->last_character_name = savegames[sel3].player_name(); world_generator->save_last_world_info(); world_generator->set_active_world( world ); + try { g->setup(); } catch( const std::exception &err ) { @@ -1030,6 +1037,14 @@ bool main_menu::load_character_tab( bool transfer ) } } } // end while + + if( transfer ) { + layer = 3; + sel1 = 3; + sel2++; + sel3 = vWorldSubItems.size() - 1; + } + return start; } @@ -1037,20 +1052,21 @@ void main_menu::world_tab() { while( sel1 == 3 && ( layer == 2 || layer == 3 || layer == 4 ) ) { print_menu( w_open, 3, menu_offset ); - if ( layer == 4 ) { - if ( load_character_tab( true ) ) { - //test_mode = true; //Prevent game drawing - //test_mode = false; - + if( layer == 4 ) { //Character to Template + if( load_character_tab( true ) ) { points_left points; points.stat_points = 0; points.trait_points = 0; points.skill_points = 0; points.limit = points_left::TRANSFER; - avatar::save_template(g->u, g->u.name, points); - g->uquit = QUIT_NOSAVED; - g->cleanup_at_end(); + g->u.setID( character_id(), true ); + g->u.reset_all_misions(); + avatar::save_template( g->u, g->u.name, points ); + + g->u = avatar(); + MAPBUFFER.reset(); + overmap_buffer.clear(); load_char_templates(); @@ -1058,7 +1074,6 @@ void main_menu::world_tab() wrefresh( w_background ); layer = 3; - //sel1 = 3; } } else if( layer == 3 ) { // World Menu // Show options for Destroy, Reset worlds. diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index f525e1eba4e8d..4911fdc643bd1 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -378,6 +378,7 @@ bool avatar::create( character_type type, const std::string &tempname ) } // We want to prevent recipes known by the template from being applied to the // new character. The recipe list will be rebuilt when entering the game. + // Except if it is a character transfer template if( points.limit != points_left::TRANSFER ) { learned_recipes->clear(); } @@ -2199,7 +2200,8 @@ tab_direction set_description( const catacurses::window &w, avatar &you, const b wrefresh( w_stats ); mvwprintz( w_traits, point_zero, COL_HEADER, _( "Traits: " ) ); - std::vector current_traits = you.get_base_traits(); + std::vector current_traits = points.limit == points_left::TRANSFER ? you.get_mutations() : + you.get_base_traits(); if( current_traits.empty() ) { wprintz( w_traits, c_light_red, _( "None!" ) ); } else { @@ -2224,13 +2226,16 @@ tab_direction set_description( const catacurses::window &w, avatar &you, const b profession::StartingSkillList list_skills = you.prof->skills(); for( auto &elem : skillslist ) { int level = you.get_skill_level( elem->ident() ); - profession::StartingSkillList::iterator i = list_skills.begin(); - while( i != list_skills.end() ) { - if( i->first == ( elem )->ident() ) { - level += i->second; - break; + + if( points.limit != points_left::TRANSFER ) { + profession::StartingSkillList::iterator i = list_skills.begin(); + while( i != list_skills.end() ) { + if( i->first == ( elem )->ident() ) { + level += i->second; + break; + } + ++i; } - ++i; } if( level > 0 ) {