void player::mutate_category(std::string cat) { bool force_bad = one_in(3); bool force_good = false; if (has_trait("ROBUST") && force_bad) { // Robust Genetics gives you a 33% chance for a good mutation, // instead of the 33% chance of a bad one. force_bad = false; force_good = true; } // Pull the category's list for valid mutations std::vector<std::string> valid; valid = mutations_category[cat]; // Remove anything we already have, that we have a child of, or that // goes against our intention of a good/bad mutation for (int i = 0; i < valid.size(); i++) { if (!mutation_ok(valid[i], force_good, force_bad)) { valid.erase(valid.begin() + i); i--; } } // if we can't mutate in the category do nothing if (valid.empty()) { return; } std::string selection = valid[ rng(0, valid.size() - 1) ]; // Pick one! mutate_towards(selection); return; }
void player::mutate_category( const std::string &cat ) { // Hacky ID comparison is better than separate hardcoded branch used before // @todo: Turn it into the null id if( cat == "MUTCAT_ANY" ) { mutate(); return; } bool force_bad = one_in(3); bool force_good = false; if (has_trait( trait_ROBUST ) && force_bad) { // Robust Genetics gives you a 33% chance for a good mutation, // instead of the 33% chance of a bad one. force_bad = false; force_good = true; } // Pull the category's list for valid mutations std::vector<trait_id> valid; valid = mutations_category[cat]; // Remove anything we already have, that we have a child of, or that // goes against our intention of a good/bad mutation for (size_t i = 0; i < valid.size(); i++) { if (!mutation_ok(valid[i], force_good, force_bad)) { valid.erase(valid.begin() + i); i--; } } // if we can't mutate in the category do nothing if (valid.empty()) { return; } if (mutate_towards(random_entry(valid))) { return; } else { // if mutation failed (errors, post-threshold pick), try again once. mutate_towards(random_entry(valid)); } }
void player::mutate_category( const std::string &cat ) { bool force_bad = one_in(3); bool force_good = false; if (has_trait("ROBUST") && force_bad) { // Robust Genetics gives you a 33% chance for a good mutation, // instead of the 33% chance of a bad one. force_bad = false; force_good = true; } // Pull the category's list for valid mutations std::vector<std::string> valid; valid = mutations_category[cat]; // Remove anything we already have, that we have a child of, or that // goes against our intention of a good/bad mutation for (size_t i = 0; i < valid.size(); i++) { if (!mutation_ok(valid[i], force_good, force_bad)) { valid.erase(valid.begin() + i); i--; } } // if we can't mutate in the category do nothing if (valid.empty()) { return; } if (mutate_towards(random_entry(valid))) { return; } else { // if mutation failed (errors, post-threshold pick), try again once. mutate_towards(random_entry(valid)); } }
void player::mutate() { bool force_bad = one_in(3); bool force_good = false; if (has_trait("ROBUST") && force_bad) { // Robust Genetics gives you a 33% chance for a good mutation, // instead of the 33% chance of a bad one. force_bad = false; force_good = true; } // Determine the highest mutation categorie std::string cat = get_highest_category(); // See if we should ugrade/extend an existing mutation... std::vector<std::string> upgrades; // ... or remove one that is not in our highest category std::vector<std::string> downgrades; // For each mutation... for (std::map<std::string, trait>::iterator iter = traits.begin(); iter != traits.end(); ++iter) { std::string base_mutation = iter->first; // ...that we have... if (has_trait(base_mutation)) { // ...consider the mutations that replace it. for (int i = 0; i < mutation_data[base_mutation].replacements.size(); i++) { std::string mutation = mutation_data[base_mutation].replacements[i]; if (mutation_ok(mutation, force_good, force_bad)) { upgrades.push_back(mutation); } } // ...consider the mutations that add to it. for (int i = 0; i < mutation_data[base_mutation].additions.size(); i++) { std::string mutation = mutation_data[base_mutation].additions[i]; if (mutation_ok(mutation, force_good, force_bad)) { upgrades.push_back(mutation); } } // ...consider whether its in our highest category if( has_trait(base_mutation) && !has_base_trait(base_mutation) ) { // Starting traits don't count toward categories std::vector<std::string> group = mutations_category[cat]; bool in_cat = false; for (int j = 0; j < group.size(); j++) { if (group[j] == base_mutation) { in_cat = true; break; } } // mark for removal if(!in_cat) { downgrades.push_back(base_mutation); } } } } // Preliminary round to either upgrade or remove existing mutations if(one_in(2)) { if (upgrades.size() > 0) { // (upgrade count) chances to pick an upgrade, 4 chances to pick something else. int roll = rng(0, upgrades.size() + 4); if (roll < upgrades.size()) { // We got a valid upgrade index, so use it and return. mutate_towards(upgrades[roll]); return; } } } else { // Remove existing mutations that don't fit into our category if (downgrades.size() > 0 && cat != "") { int roll = rng(0, downgrades.size() + 4); if (roll < downgrades.size()) { remove_mutation(downgrades[roll]); return; } } } std::vector<std::string> valid; // Valid mutations bool first_pass = true; do { // If we tried once with a non-NULL category, and couldn't find anything valid // there, try again with MUTCAT_NULL if (!first_pass) { cat = ""; } if (cat == "") { // Pull the full list for (std::map<std::string, trait>::iterator iter = traits.begin(); iter != traits.end(); ++iter) { if (mutation_data[iter->first].valid) { valid.push_back( iter->first ); } } } else { // Pull the category's list valid = mutations_category[cat]; } // Remove anything we already have, that we have a child of, or that // goes against our intention of a good/bad mutation for (int i = 0; i < valid.size(); i++) { if (!mutation_ok(valid[i], force_good, force_bad)) { valid.erase(valid.begin() + i); i--; } } if (valid.empty()) { // So we won't repeat endlessly first_pass = false; } } while (valid.empty() && cat != ""); if (valid.empty()) { // Couldn't find anything at all! return; } std::string selection = valid[ rng(0, valid.size() - 1) ]; // Pick one! mutate_towards(selection); }
void player::mutate() { bool force_bad = one_in(3); bool force_good = false; if (has_trait( trait_ROBUST ) && force_bad) { // Robust Genetics gives you a 33% chance for a good mutation, // instead of the 33% chance of a bad one. force_bad = false; force_good = true; } // Determine the highest mutation category std::string cat = get_highest_category(); // See if we should upgrade/extend an existing mutation... std::vector<trait_id> upgrades; // ... or remove one that is not in our highest category std::vector<trait_id> downgrades; // For each mutation... for( auto &traits_iter : mutation_branch::get_all() ) { const auto &base_mutation = traits_iter.first; const auto &base_mdata = traits_iter.second; bool thresh_save = base_mdata.threshold; bool prof_save = base_mdata.profession; bool purify_save = base_mdata.purifiable; // ...that we have... if (has_trait(base_mutation)) { // ...consider the mutations that replace it. for( auto &mutation : base_mdata.replacements ) { bool valid_ok = mutation->valid; if ( (mutation_ok(mutation, force_good, force_bad)) && (valid_ok) ) { upgrades.push_back(mutation); } } // ...consider the mutations that add to it. for( auto &mutation : base_mdata.additions ) { bool valid_ok = mutation->valid; if ( (mutation_ok(mutation, force_good, force_bad)) && (valid_ok) ) { upgrades.push_back(mutation); } } // ...consider whether its in our highest category if( has_trait(base_mutation) && !has_base_trait(base_mutation) ) { // Starting traits don't count toward categories std::vector<trait_id> group = mutations_category[cat]; bool in_cat = false; for( auto &elem : group ) { if( elem == base_mutation ) { in_cat = true; break; } } // mark for removal // no removing Thresholds/Professions this way! if(!in_cat && !thresh_save && !prof_save) { // non-purifiable stuff should be pretty tenacious // category-enforcement only targets it 25% of the time // (purify_save defaults true, = false for non-purifiable) if( purify_save || ( one_in( 4 ) && !purify_save ) ) { downgrades.push_back(base_mutation); } } } } } // Preliminary round to either upgrade or remove existing mutations if(one_in(2)) { if (!upgrades.empty()) { // (upgrade count) chances to pick an upgrade, 4 chances to pick something else. size_t roll = rng(0, upgrades.size() + 4); if (roll < upgrades.size()) { // We got a valid upgrade index, so use it and return. mutate_towards(upgrades[roll]); return; } } } else { // Remove existing mutations that don't fit into our category if( !downgrades.empty() && !cat.empty() ) { size_t roll = rng(0, downgrades.size() + 4); if (roll < downgrades.size()) { remove_mutation(downgrades[roll]); return; } } } std::vector<trait_id> valid; // Valid mutations bool first_pass = true; do { // If we tried once with a non-NULL category, and couldn't find anything valid // there, try again with MUTCAT_NULL if (!first_pass) { cat.clear(); } if( cat.empty() ) { // Pull the full list for( auto &traits_iter : mutation_branch::get_all() ) { if( traits_iter.second.valid ) { valid.push_back( traits_iter.first ); } } } else { // Pull the category's list valid = mutations_category[cat]; } // Remove anything we already have, that we have a child of, or that // goes against our intention of a good/bad mutation for (size_t i = 0; i < valid.size(); i++) { if ( (!mutation_ok(valid[i], force_good, force_bad)) || (!valid[i]->valid) ) { valid.erase(valid.begin() + i); i--; } } if (valid.empty()) { // So we won't repeat endlessly first_pass = false; } } while ( valid.empty() && !cat.empty() ); if (valid.empty()) { // Couldn't find anything at all! return; } if (mutate_towards(random_entry(valid))) { return; } else { // if mutation failed (errors, post-threshold pick), try again once. mutate_towards(random_entry(valid)); } }
void player::mutate(game *g) { bool force_bad = one_in(3); bool force_good = false; if (has_trait(PF_ROBUST) && force_bad) { // Robust Genetics gives you a 33% chance for a good mutation, // instead of the 33% chance of a bad one. force_bad = false; force_good = true; } // Determine the mutation categorie mutation_category cat = MUTCAT_NULL; // Count up the players number of mutations in categories and find // the category with the highest single count. int total = 0, highest = 0; for (int i = 0; i < NUM_MUTATION_CATEGORIES; i++) { total += mutation_category_level[i]; if (mutation_category_level[i] > highest) { cat = mutation_category(i); highest = mutation_category_level[i]; } } // See if we should ugrade/extend an existing mutation... std::vector<pl_flag> upgrades; // ... or remove one that is not in our highest category std::vector<pl_flag> downgrades; // For each mutation... for (int base_mutation_index = 1; base_mutation_index < PF_MAX2; base_mutation_index++) { pl_flag base_mutation = (pl_flag) base_mutation_index; // ...that we have... if (has_trait(base_mutation)) { // ...consider the mutations that replace it. for (int i = 0; i < g->mutation_data[base_mutation].replacements.size(); i++) { pl_flag mutation = g->mutation_data[base_mutation].replacements[i]; if (mutation_ok(g, mutation, force_good, force_bad)) { upgrades.push_back(mutation); } } // ...consider the mutations that add to it. for (int i = 0; i < g->mutation_data[base_mutation].additions.size(); i++) { pl_flag mutation = g->mutation_data[base_mutation].additions[i]; if (mutation_ok(g, mutation, force_good, force_bad)) { upgrades.push_back(mutation); } } // ...consider whether its in our highest category if( has_trait(base_mutation) && !has_base_trait(base_mutation) ){ // Starting traits don't count toward categories std::vector<pl_flag> group = mutations_from_category(cat); bool in_cat = false; for (int j = 0; j < group.size(); j++) { if (group[j] == base_mutation) { in_cat = true; break; } } // mark for removal if(!in_cat) downgrades.push_back(base_mutation); } } } // Preliminary round to either upgrade or remove existing mutations if(one_in(2)){ if (upgrades.size() > 0) { // (upgrade count) chances to pick an upgrade, 4 chances to pick something else. int roll = rng(0, upgrades.size() + 4); if (roll < upgrades.size()) { // We got a valid upgrade index, so use it and return. mutate_towards(g, upgrades[roll]); return; } } } else { // Remove existing mutations that don't fit into our category if (downgrades.size() > 0 && cat != MUTCAT_NULL) { int roll = rng(0, downgrades.size() + 4); if (roll < downgrades.size()) { remove_mutation(g, downgrades[roll]); return; } } } std::vector<pl_flag> valid; // Valid mutations bool first_pass = true; do { // If we tried once with a non-NULL category, and couldn't find anything valid // there, try again with MUTCAT_NULL if (!first_pass) { cat = MUTCAT_NULL; } if (cat == MUTCAT_NULL) { // Pull the full list for (int i = 1; i < PF_MAX2; i++) { if (g->mutation_data[i].valid) { valid.push_back( pl_flag(i) ); } } } else { // Pull the category's list valid = mutations_from_category(cat); } // Remove anything we already have, that we have a child of, or that // goes against our intention of a good/bad mutation for (int i = 0; i < valid.size(); i++) { if (!mutation_ok(g, valid[i], force_good, force_bad)) { valid.erase(valid.begin() + i); i--; } } if (valid.empty()) { // So we won't repeat endlessly first_pass = false; } } while (valid.empty() && cat != MUTCAT_NULL); if (valid.empty()) { // Couldn't find anything at all! return; } pl_flag selection = valid[ rng(0, valid.size() - 1) ]; // Pick one! mutate_towards(g, selection); }