itype* game::new_artifact() { if (one_in(2)) { // Generate a "tool" artifact it_artifact_tool *art = new it_artifact_tool(); int form = rng(ARTTOOLFORM_NULL + 1, NUM_ARTTOOLFORMS - 1); artifact_tool_form_datum *info = &(artifact_tool_form_data[form]); art->name = artifact_name(info->name); art->color = info->color; art->sym = info->sym; art->m1 = info->m1; art->m2 = info->m2; art->volume = rng(info->volume_min, info->volume_max); art->weight = rng(info->weight_min, info->weight_max); // Set up the basic weapon type artifact_weapon_datum *weapon = &(artifact_weapon_data[info->base_weapon]); art->melee_dam = rng(weapon->bash_min, weapon->bash_max); art->melee_cut = rng(weapon->cut_min, weapon->cut_max); art->m_to_hit = rng(weapon->to_hit_min, weapon->to_hit_max); if( weapon->tag != "" ) { art->item_tags.insert(weapon->tag); } // Add an extra weapon perhaps? if (one_in(2)) { int select = rng(0, 2); if (info->extra_weapons[select] != ARTWEAP_NULL) { weapon = &(artifact_weapon_data[ info->extra_weapons[select] ]); art->volume += weapon->volume; art->weight += weapon->weight; art->melee_dam += rng(weapon->bash_min, weapon->bash_max); art->melee_cut += rng(weapon->bash_min, weapon->bash_max); art->m_to_hit += rng(weapon->to_hit_min, weapon->to_hit_max); if( weapon->tag != "" ) { art->item_tags.insert(weapon->tag); } std::stringstream newname; newname << weapon->adjective << " " << info->name; art->name = artifact_name(newname.str()); } } art->description = string_format(_("This is the %s.\nIt is the only one of its kind.\nIt may have unknown powers; use 'a' to activate them."), art->name.c_str()); // Finally, pick some powers art_effect_passive passive_tmp = AEP_NULL; art_effect_active active_tmp = AEA_NULL; int num_good = 0, num_bad = 0, value = 0; std::vector<art_effect_passive> good_effects = fill_good_passive(); std::vector<art_effect_passive> bad_effects = fill_bad_passive(); // Wielded effects first while (!good_effects.empty() && !bad_effects.empty() && num_good < 3 && num_bad < 3 && (num_good < 1 || num_bad < 1 || one_in(num_good + 1) || one_in(num_bad + 1) || value > 1)) { if (value < 1 && one_in(2)) { // Good int index = rng(0, good_effects.size() - 1); passive_tmp = good_effects[index]; good_effects.erase(good_effects.begin() + index); num_good++; } else if (!bad_effects.empty()) { // Bad effect int index = rng(0, bad_effects.size() - 1); passive_tmp = bad_effects[index]; bad_effects.erase(bad_effects.begin() + index); num_bad++; } value += passive_effect_cost[passive_tmp]; art->effects_wielded.push_back(passive_tmp); } // Next, carried effects; more likely to be just bad num_good = 0; num_bad = 0; value = 0; good_effects = fill_good_passive(); bad_effects = fill_bad_passive(); while (one_in(2) && !good_effects.empty() && !bad_effects.empty() && num_good < 3 && num_bad < 3 && ((num_good > 2 && one_in(num_good + 1)) || num_bad < 1 || one_in(num_bad + 1) || value > 1)) { if (value < 1 && one_in(3)) { // Good int index = rng(0, good_effects.size() - 1); passive_tmp = good_effects[index]; good_effects.erase(good_effects.begin() + index); num_good++; } else { // Bad effect int index = rng(0, bad_effects.size() - 1); passive_tmp = bad_effects[index]; bad_effects.erase(bad_effects.begin() + index); num_bad++; } value += passive_effect_cost[passive_tmp]; art->effects_carried.push_back(passive_tmp); } // Finally, activated effects; not necessarily good or bad num_good = 0; num_bad = 0; value = 0; art->def_charges = 0; art->max_charges = 0; std::vector<art_effect_active> good_a_effects = fill_good_active(); std::vector<art_effect_active> bad_a_effects = fill_bad_active(); while (!good_a_effects.empty() && !bad_a_effects.empty() && num_good < 3 && num_bad < 3 && (value > 3 || (num_bad > 0 && num_good == 0) || !one_in(3 - num_good) || !one_in(3 - num_bad))) { if (!one_in(3) && value <= 1) { // Good effect int index = rng(0, good_a_effects.size() - 1); active_tmp = good_a_effects[index]; good_a_effects.erase(good_a_effects.begin() + index); num_good++; value += active_effect_cost[active_tmp]; } else { // Bad effect int index = rng(0, bad_a_effects.size() - 1); active_tmp = bad_a_effects[index]; bad_a_effects.erase(bad_a_effects.begin() + index); num_bad++; value += active_effect_cost[active_tmp]; } art->effects_activated.push_back(active_tmp); art->max_charges += rng(1, 3); } art->def_charges = art->max_charges; // If we have charges, pick a recharge mechanism if (art->max_charges > 0) art->charge_type = art_charge( rng(ARTC_NULL + 1, NUM_ARTCS - 1) ); if (one_in(8) && num_bad + num_good >= 4) art->charge_type = ARTC_NULL; // 1 in 8 chance that it can't recharge! art->id = itypes.size(); itypes[art->id]=art; artifact_itype_ids.push_back(art->id); return art; } else { // Generate an armor artifact it_artifact_armor *art = new it_artifact_armor(); int form = rng(ARTARMFORM_NULL + 1, NUM_ARTARMFORMS - 1); artifact_armor_form_datum *info = &(artifact_armor_form_data[form]); art->name = artifact_name(info->name); art->sym = '['; // Armor is always [ art->color = info->color; art->m1 = info->m1; art->m2 = info->m2; art->volume = info->volume; art->weight = info->weight; art->melee_dam = info->melee_bash; art->melee_cut = info->melee_cut; art->m_to_hit = info->melee_hit; art->covers = info->covers; art->encumber = info->encumb; art->coverage = info->coverage; art->thickness = info->thickness; art->env_resist = info->env_resist; art->warmth = info->warmth; art->storage = info->storage; std::stringstream description; description << string_format(info->plural? _("This is the %s.\nThey are the only ones of their kind.") : _("This is the %s.\nIt is the only one of its kind."), art->name.c_str()); // Modify the armor further if (!one_in(4)) { int index = rng(0, 4); if (info->available_mods[index] != ARMORMOD_NULL) { artifact_armor_mod mod = info->available_mods[index]; artifact_armor_form_datum *modinfo = &(artifact_armor_mod_data[mod]); if (modinfo->volume >= 0 || art->volume > abs(modinfo->volume)) art->volume += modinfo->volume; else art->volume = 1; if (modinfo->weight >= 0 || art->weight > abs(modinfo->weight)) art->weight += modinfo->weight; else art->weight = 1; art->encumber += modinfo->encumb; if (modinfo->coverage > 0 || art->coverage > abs(modinfo->coverage)) art->coverage += modinfo->coverage; else art->coverage = 0; if (modinfo->thickness > 0 || art->thickness > abs(modinfo->thickness)) art->thickness += modinfo->thickness; else art->thickness = 0; if (modinfo->env_resist > 0 || art->env_resist > abs(modinfo->env_resist)) art->env_resist += modinfo->env_resist; else art->env_resist = 0; art->warmth += modinfo->warmth; if (modinfo->storage > 0 || art->storage > abs(modinfo->storage)) art->storage += modinfo->storage; else art->storage = 0; description << string_format(info->plural? _("\nThey are %s") : _("\nIt is %s"), modinfo->name.c_str()); } } art->description = description.str(); // Finally, pick some effects int num_good = 0, num_bad = 0, value = 0; art_effect_passive passive_tmp = AEP_NULL; std::vector<art_effect_passive> good_effects = fill_good_passive(); std::vector<art_effect_passive> bad_effects = fill_bad_passive(); while (!good_effects.empty() && !bad_effects.empty() && num_good < 3 && num_bad < 3 && (num_good < 1 || one_in(num_good * 2) || value > 1 || (num_bad < 3 && !one_in(3 - num_bad)))) { if (value < 1 && one_in(2)) { // Good effect int index = rng(0, good_effects.size() - 1); passive_tmp = good_effects[index]; good_effects.erase(good_effects.begin() + index); num_good++; } else { // Bad effect int index = rng(0, bad_effects.size() - 1); passive_tmp = bad_effects[index]; bad_effects.erase(bad_effects.begin() + index); num_bad++; } value += passive_effect_cost[passive_tmp]; art->effects_worn.push_back(passive_tmp); } std::stringstream artid; artid << "artifact" << artifact_itype_ids.size(); art->id = artid.str(); itypes[art->id] = art; artifact_itype_ids.push_back(art->id); return art; } }
itype* game::new_natural_artifact(artifact_natural_property prop) { // Natural artifacts are always tools. it_artifact_tool *art = new it_artifact_tool(); // Pick a form artifact_natural_shape shape = artifact_natural_shape(rng(ARTSHAPE_NULL + 1, ARTSHAPE_MAX - 1)); artifact_shape_datum *shape_data = &(artifact_shape_data[shape]); // Pick a property artifact_natural_property property = (prop > ARTPROP_NULL ? prop : artifact_natural_property(rng(ARTPROP_NULL + 1, ARTPROP_MAX - 1))); artifact_property_datum *property_data = &(artifact_property_data[property]); art->sym = ':'; art->color = c_yellow; art->m1 = "stone"; art->m2 = "null"; art->volume = rng(shape_data->volume_min, shape_data->volume_max); art->weight = rng(shape_data->weight_min, shape_data->weight_max); art->melee_dam = 0; art->melee_cut = 0; art->m_to_hit = 0; art->name = rmp_format(_("<artifact_name>%1$s %2$s"), property_data->name.c_str(), shape_data->name.c_str()); art->description = rmp_format(_("<artifact_desc>This %1$s %2$s."), shape_data->desc.c_str(), property_data->desc.c_str()); // Add line breaks to the description as necessary /* size_t pos = 76; while (art->description.length() - pos >= 76) { pos = art->description.find_last_of(' ', pos); if (pos == std::string::npos) pos = art->description.length(); else { art->description[pos] = '\n'; pos += 76; } }*/ // Three possibilities: good passive + bad passive, good active + bad active, // and bad passive + good active bool good_passive = false, bad_passive = false, good_active = false, bad_active = false; switch (rng(1, 3)) { case 1: good_passive = true; bad_passive = true; break; case 2: good_active = true; bad_active = true; break; case 3: bad_passive = true; good_active = true; break; } int value_to_reach = 0; // This is slowly incremented, allowing for better arts int value = 0; art_effect_passive aep_good = AEP_NULL, aep_bad = AEP_NULL; art_effect_active aea_good = AEA_NULL, aea_bad = AEA_NULL; do { if (good_passive) { aep_good = property_data->passive_good[ rng(0, 3) ]; if (aep_good == AEP_NULL || one_in(4)) aep_good = art_effect_passive(rng(AEP_NULL + 1, AEP_SPLIT - 1)); } if (bad_passive) { aep_bad = property_data->passive_bad[ rng(0, 3) ]; if (aep_bad == AEP_NULL || one_in(4)) aep_bad = art_effect_passive(rng(AEP_SPLIT + 1, NUM_AEAS - 1)); } if (good_active) { aea_good = property_data->active_good[ rng(0, 3) ]; if (aea_good == AEA_NULL || one_in(4)) aea_good = art_effect_active(rng(AEA_NULL + 1, AEA_SPLIT - 1)); } if (bad_active) { aea_bad = property_data->active_bad[ rng(0, 3) ]; if (aea_bad == AEA_NULL || one_in(4)) aea_bad = art_effect_active(rng(AEA_SPLIT + 1, NUM_AEAS - 1)); } value = passive_effect_cost[aep_good] + passive_effect_cost[aep_bad] + active_effect_cost[aea_good] + active_effect_cost[aea_bad]; value_to_reach++; // Yes, it is intentional that this is 1 the first check } while (value > value_to_reach); if (aep_good != AEP_NULL) art->effects_carried.push_back(aep_good); if (aep_bad != AEP_NULL) art->effects_carried.push_back(aep_bad); if (aea_good != AEA_NULL) art->effects_activated.push_back(aea_good); if (aea_bad != AEA_NULL) art->effects_activated.push_back(aea_bad); // Natural artifacts ALWAYS can recharge // (When "implanting" them in a mundane item, this ability may be lost if (!art->effects_activated.empty()) { art->max_charges = rng(1, 4); art->def_charges = art->max_charges; art->charge_type = art_charge( rng(ARTC_NULL + 1, NUM_ARTCS - 1) ); } std::stringstream artid; artid << "artifact" << artifact_itype_ids.size(); art->id = artid.str(); artifact_itype_ids.push_back(art->id); itypes[art->id] = art; return art; }
std::string new_natural_artifact(artifact_natural_property prop) { // Natural artifacts are always tools. it_artifact_tool *art = new it_artifact_tool(); // Pick a form artifact_natural_shape shape = artifact_natural_shape(rng(ARTSHAPE_NULL + 1, ARTSHAPE_MAX - 1)); artifact_shape_datum *shape_data = &(artifact_shape_data[shape]); // Pick a property artifact_natural_property property = (prop > ARTPROP_NULL ? prop : artifact_natural_property(rng(ARTPROP_NULL + 1, ARTPROP_MAX - 1))); artifact_property_datum *property_data = &(artifact_property_data[property]); art->sym = ':'; art->color = c_yellow; art->materials.push_back("stone"); art->volume = rng(shape_data->volume_min, shape_data->volume_max); art->weight = rng(shape_data->weight_min, shape_data->weight_max); art->melee_dam = 0; art->melee_cut = 0; art->m_to_hit = 0; art->create_name(property_data->name, shape_data->name); art->description = rmp_format(_("<artifact_desc>This %1$s %2$s."), shape_data->desc.c_str(), property_data->desc.c_str()); // Three possibilities: good passive + bad passive, good active + bad active, // and bad passive + good active bool good_passive = false, bad_passive = false, good_active = false, bad_active = false; switch (rng(1, 3)) { case 1: good_passive = true; bad_passive = true; break; case 2: good_active = true; bad_active = true; break; case 3: bad_passive = true; good_active = true; break; } int value_to_reach = 0; // This is slowly incremented, allowing for better arts int value = 0; art_effect_passive aep_good = AEP_NULL, aep_bad = AEP_NULL; art_effect_active aea_good = AEA_NULL, aea_bad = AEA_NULL; do { if (good_passive) { aep_good = property_data->passive_good[ rng(0, 3) ]; if (aep_good == AEP_NULL || one_in(4)) { aep_good = art_effect_passive(rng(AEP_NULL + 1, AEP_SPLIT - 1)); } } if (bad_passive) { aep_bad = property_data->passive_bad[ rng(0, 3) ]; if (aep_bad == AEP_NULL || one_in(4)) { aep_bad = art_effect_passive(rng(AEP_SPLIT + 1, NUM_AEAS - 1)); } } if (good_active) { aea_good = property_data->active_good[ rng(0, 3) ]; if (aea_good == AEA_NULL || one_in(4)) { aea_good = art_effect_active(rng(AEA_NULL + 1, AEA_SPLIT - 1)); } } if (bad_active) { aea_bad = property_data->active_bad[ rng(0, 3) ]; if (aea_bad == AEA_NULL || one_in(4)) { aea_bad = art_effect_active(rng(AEA_SPLIT + 1, NUM_AEAS - 1)); } } value = passive_effect_cost[aep_good] + passive_effect_cost[aep_bad] + active_effect_cost[aea_good] + active_effect_cost[aea_bad]; value_to_reach++; // Yes, it is intentional that this is 1 the first check } while (value > value_to_reach); if (aep_good != AEP_NULL) { art->effects_carried.push_back(aep_good); } if (aep_bad != AEP_NULL) { art->effects_carried.push_back(aep_bad); } if (aea_good != AEA_NULL) { art->effects_activated.push_back(aea_good); } if (aea_bad != AEA_NULL) { art->effects_activated.push_back(aea_bad); } // Natural artifacts ALWAYS can recharge // (When "implanting" them in a mundane item, this ability may be lost if (!art->effects_activated.empty()) { art->max_charges = rng(1, 4); art->def_charges = art->max_charges; art->rand_charges.push_back(art->max_charges); art->charge_type = art_charge( rng(ARTC_NULL + 1, NUM_ARTCS - 1) ); } item_controller->add_item_type( art ); return art->id; }