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;
}
Beispiel #3
0
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;
}