void player::mutate_category(game *g, mutation_category cat) { 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; } // Pull the category's list for valid mutations std::vector<pl_flag> valid; 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 we can't mutate in the category do nothing if (valid.empty()) return; pl_flag selection = valid[ rng(0, valid.size() - 1) ]; // Pick one! mutate_towards(g, selection); return; }
void player::mutate_towards(game *g, pl_flag mut) { if (has_child_flag(g, mut)) { remove_child_flag(g, mut); return; } bool has_prereqs = false; std::vector<pl_flag> prereq = g->mutation_data[mut].prereqs; std::vector<pl_flag> cancel = g->mutation_data[mut].cancels; for (int i = 0; i < cancel.size(); i++) { if (!has_trait( cancel[i] )) { cancel.erase(cancel.begin() + i); i--; } } if (!cancel.empty()) { pl_flag removed = cancel[ rng(0, cancel.size() - 1) ]; remove_mutation(g, removed); return; } for (int i = 0; !has_prereqs && i < prereq.size(); i++) { if (has_trait(prereq[i])) has_prereqs = true; } if (!has_prereqs && !prereq.empty()) { pl_flag devel = prereq[ rng(0, prereq.size() - 1) ]; mutate_towards(g, devel); return; } // Check if one of the prereqs that we have TURNS INTO this one pl_flag replacing = PF_NULL; prereq = g->mutation_data[mut].prereqs; // Reset it for (int i = 0; i < prereq.size(); i++) { if (has_trait(prereq[i])) { pl_flag pre = prereq[i]; for (int j = 0; replacing == PF_NULL && j < g->mutation_data[pre].replacements.size(); j++) { if (g->mutation_data[pre].replacements[j] == mut) replacing = pre; } } } toggle_trait(mut); if (replacing != PF_NULL) { g->add_msg("Your %s turns into %s!", traits[replacing].name.c_str(), traits[mut].name.c_str()); toggle_trait(replacing); } else g->add_msg("You gain %s!", traits[mut].name.c_str()); mutation_effect(g, *this, mut); // Weight us towards any categories that include this mutation for (int i = 0; i < NUM_MUTATION_CATEGORIES; i++) { std::vector<pl_flag> group = mutations_from_category(mutation_category(i)); bool found = false; for (int j = 0; !found && j < group.size(); j++) { if (group[j] == mut) found = true; } if (found) mutation_category_level[i] += 8; else if (mutation_category_level[i] > 0 && !one_in(mutation_category_level[i])) mutation_category_level[i]--; } }
void player::mutate(game *g) { bool force_bad = one_in(3); // 33% chance! if (has_trait(PF_ROBUST) && force_bad && one_in(3)) force_bad = false; // 11% chance! // First, see if we should ugrade/extend an existing mutation std::vector<pl_flag> upgrades; for (int i = 1; i < PF_MAX2; i++) { if (has_trait(i)) { for (int j = 0; j < g->mutation_data[i].replacements.size(); j++) { pl_flag tmp = g->mutation_data[i].replacements[j]; if (!has_trait(tmp) && !has_child_flag(g, tmp) && (!force_bad || traits[tmp].points <= 0)) upgrades.push_back(tmp); } for (int j = 0; j < g->mutation_data[i].additions.size(); j++) { pl_flag tmp = g->mutation_data[i].additions[j]; if (!has_trait(tmp) && !has_child_flag(g, tmp) && (!force_bad || traits[tmp].points <= 0)) upgrades.push_back(tmp); } } } if (upgrades.size() > 0 && rng(0, upgrades.size() + 4) < upgrades.size()) { mutate_towards(g, upgrades[ rng(0, upgrades.size() - 1) ]); return; } // Next, see if we should mutate within a given category mutation_category cat = MUTCAT_NULL; 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]; } } if (rng(0, total) > highest) cat = MUTCAT_NULL; // Not a strong enough pull, just mutate something random! std::vector<pl_flag> valid; // Valid mutations bool first_pass = (cat != MUTCAT_NULL); do { // If we tried once with a non-NULL category, and couldn't find anything valid // there, try again with MUTCAT_NULL if (cat != MUTCAT_NULL && !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, or that we have a child of, or that's // positive and we're forcing bad for (int i = 0; i < valid.size(); i++) { if (has_trait(valid[i]) || has_child_flag(g, valid[i]) || (force_bad && traits[ valid[i] ].points > 0)) { valid.erase(valid.begin() + i); i--; } } if (valid.empty()) first_pass = false; // So we won't repeat endlessly } while (valid.empty() && cat != MUTCAT_NULL); if (valid.empty()) return; // Couldn't find anything at all! pl_flag selection = valid[ rng(0, valid.size() - 1) ]; // Pick one! mutate_towards(g, selection); }
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); }
void player::remove_mutation(game *g, pl_flag mut) { // Check for dependant mutations first std::vector<pl_flag> dependant; for (int i = 0; i < PF_MAX2; i++) { for (std::vector<pl_flag>::iterator it = g->mutation_data[i].prereqs.begin(); it != g->mutation_data[i].prereqs.end(); it++) { if (*it == i) { dependant.push_back((pl_flag)i); break; } } } if (dependant.size() != 0) { remove_mutation(g,dependant[rng(0,dependant.size())]); return; } // Check if there's a prereq we should shrink back into pl_flag replacing = PF_NULL; std::vector<pl_flag> originals = g->mutation_data[mut].prereqs; for (int i = 0; replacing == PF_NULL && i < originals.size(); i++) { pl_flag pre = originals[i]; for (int j = 0; replacing == PF_NULL && j < g->mutation_data[pre].replacements.size(); j++) { if (g->mutation_data[pre].replacements[j] == mut) replacing = pre; } } // See if this mutation is cancelled by a base trait //Only if there's no prereq to shrink to, thus we're at the bottom of the trait line if (replacing == PF_NULL) { //Check each mutation until we reach the end or find a trait to revert to for (int i = 1; replacing == PF_NULL && i < PF_MAX2; i++) { //See if it's in our list of base traits but not active if (has_base_trait(i) && !has_trait(i)) { //See if that base trait cancels the mutation we are using std::vector<pl_flag> traitcheck = g->mutation_data[i].cancels; if (!traitcheck.empty()) { for (int j = 0; replacing == PF_NULL && j < traitcheck.size(); j++) { if (g->mutation_data[i].cancels[j] == mut) replacing = ((pl_flag)i); } } } } } // This should revert back to a removed base trait rather than simply removing the mutation toggle_mutation(mut); if (replacing != PF_NULL) { g->add_msg(_("Your %1$s mutation turns into %2$s."), traits[mut].name.c_str(), traits[replacing].name.c_str()); toggle_mutation(replacing); mutation_loss_effect(g, *this, mut); mutation_effect(g, *this, replacing); } else { g->add_msg(_("You lose your %s mutation."), traits[mut].name.c_str()); mutation_loss_effect(g, *this, mut); } // Reduce the strength of the categories the removed mutation is a part of for (int i = 0; i < NUM_MUTATION_CATEGORIES; i++) { std::vector<pl_flag> group = mutations_from_category(mutation_category(i)); bool found = false; for (int j = 0; !found && j < group.size(); j++) { if (group[j] == mut) found = true; } if (found) { mutation_category_level[i] -= 8; // If the category strength is below 0, set it to 0. We don't want negative category strength. if (mutation_category_level[i] < 0) { mutation_category_level[i] = 0; } } } }