Esempio n. 1
0
void game::complete_construction()
{
 inventory map_inv;
 map_inv.form_from_map(this, point(u.posx, u.posy), PICKUP_RANGE);
 int stage_num = u.activity.values[0];
 constructable *built = constructions[u.activity.index];
 construction_stage stage = built->stages[stage_num];
 std::vector<component> player_use;
 std::vector<component> map_use;

 u.practice(sk_carpentry, built->difficulty * 10);
 if (built->difficulty < 1)
  u.practice(sk_carpentry, 10);
 for (int i = 0; i < 3; i++) {
  if (!stage.components[i].empty())
   consume_items(this, stage.components[i]);
 }
 
// Make the terrain change
 int terx = u.activity.placement.x, tery = u.activity.placement.y;
 m.ter(terx, tery) = stage.terrain;
 construct effects;
 (effects.*(built->done))(this, point(terx, tery));

// Strip off the first stage in our list...
 u.activity.values.erase(u.activity.values.begin());
// ...and start the next one, if it exists
 if (u.activity.values.size() > 0) {
  construction_stage next = built->stages[u.activity.values[0]];
  u.activity.moves_left = next.time * 1000;
 } else // We're finished!
  u.activity.type = ACT_NULL;
}
Esempio n. 2
0
void game::complete_construction()
{
    int stage_num = u.activity.values[0];
    constructable *built = constructions[u.activity.index];
    construction_stage stage = built->stages[stage_num];

    u.practice(turn, "carpentry", std::max(built->difficulty, 1) * 10);
    for (int i = 0; i < 10; i++) {
        if (!stage.components[i].empty()) {
            consume_items(&u, stage.components[i]);
        }
    }

    // Make the terrain change
    int terx = u.activity.placement.x, tery = u.activity.placement.y;
    if (stage.terrain != t_null) { m.ter_set(terx, tery, stage.terrain); }
    if (stage.furniture != f_null) { m.furn_set(terx, tery, stage.furniture); }

    // Strip off the first stage in our list...
    u.activity.values.erase(u.activity.values.begin());
    // ...and start the next one, if it exists
    if (u.activity.values.size() > 0) {
        construction_stage next = built->stages[u.activity.values[0]];
        u.activity.moves_left = next.time * 1000;
    } else { // We're finished!
        u.activity.type = ACT_NULL;
    }

    // This comes after clearing the activity, in case the function interrupts
    // activities
    construct effects;
    (effects.*(built->done))(this, point(terx, tery));
}
Esempio n. 3
0
void player::complete_craft()
{
    const recipe *making = &recipe_dict[ activity.name ]; // Which recipe is it?
    int batch_size = activity.values.front();
    if( making == nullptr ) {
        debugmsg( "no recipe with id %s found", activity.name.c_str() );
        activity.set_to_null();
        return;
    }

    int secondary_dice = 0;
    int secondary_difficulty = 0;
    for( const auto &pr : making->required_skills ) {
        secondary_dice += get_skill_level( pr.first );
        secondary_difficulty += pr.second;
    }

    // # of dice is 75% primary skill, 25% secondary (unless secondary is null)
    int skill_dice;
    if( secondary_difficulty > 0 ) {
        skill_dice = get_skill_level( making->skill_used ) * 3 + secondary_dice;
    } else {
        skill_dice = get_skill_level( making->skill_used ) * 4;
    }

    auto helpers = g->u.get_crafting_helpers();
    for( const npc *np : helpers ) {
        if( np->get_skill_level( making->skill_used ) >=
            get_skill_level( making->skill_used ) ) {
            // NPC assistance is worth half a skill level
            skill_dice += 2;
            add_msg( m_info, _( "%s helps with crafting..." ), np->name.c_str() );
            break;
        }
    }

    // farsightedness can impose a penalty on electronics and tailoring success
    // it's equivalent to a 2-rank electronics penalty, 1-rank tailoring
    if( has_trait( trait_id( "HYPEROPIC" ) ) && !is_wearing( "glasses_reading" ) &&
        !is_wearing( "glasses_bifocal" ) && !has_effect( effect_contacts ) ) {
        int main_rank_penalty = 0;
        if( making->skill_used == skill_id( "electronics" ) ) {
            main_rank_penalty = 2;
        } else if( making->skill_used == skill_id( "tailor" ) ) {
            main_rank_penalty = 1;
        }
        skill_dice -= main_rank_penalty * 4;
    }

    // It's tough to craft with paws.  Fortunately it's just a matter of grip and fine-motor,
    // not inability to see what you're doing
    if( has_trait( trait_PAWS ) || has_trait( trait_PAWS_LARGE ) ) {
        int paws_rank_penalty = 0;
        if( has_trait( trait_PAWS_LARGE ) ) {
            paws_rank_penalty += 1;
        }
        if( making->skill_used == skill_id( "electronics" )
            || making->skill_used == skill_id( "tailor" )
            || making->skill_used == skill_id( "mechanics" ) ) {
            paws_rank_penalty += 1;
        }
        skill_dice -= paws_rank_penalty * 4;
    }

    // Sides on dice is 16 plus your current intelligence
    ///\EFFECT_INT increases crafting success chance
    int skill_sides = 16 + int_cur;

    int diff_dice;
    if( secondary_difficulty > 0 ) {
        diff_dice = making->difficulty * 3 + secondary_difficulty;
    } else {
        // Since skill level is * 4 also
        diff_dice = making->difficulty * 4;
    }

    int diff_sides = 24; // 16 + 8 (default intelligence)

    int skill_roll = dice( skill_dice, skill_sides );
    int diff_roll  = dice( diff_dice,  diff_sides );

    if( making->skill_used ) {
        const double batch_mult = 1 + time_to_craft( *making, batch_size ) / 30000.0;
        //normalize experience gain to crafting time, giving a bonus for longer crafting
        practice( making->skill_used, ( int )( ( making->difficulty * 15 + 10 ) * batch_mult ),
                  ( int )making->difficulty * 1.25 );

        //NPCs assisting or watching should gain experience...
        for( auto &elem : helpers ) {
            //If the NPC can understand what you are doing, they gain more exp
            if( elem->get_skill_level( making->skill_used ) >= making->difficulty ) {
                elem->practice( making->skill_used,
                                ( int )( ( making->difficulty * 15 + 10 ) * batch_mult *
                                         .50 ), ( int )making->difficulty * 1.25 );
                if( batch_size > 1 ) {
                    add_msg( m_info, _( "%s assists with crafting..." ), elem->name.c_str() );
                }
                if( batch_size == 1 ) {
                    add_msg( m_info, _( "%s could assist you with a batch..." ), elem->name.c_str() );
                }
                //NPCs around you understand the skill used better
            } else {
                elem->practice( making->skill_used,
                                ( int )( ( making->difficulty * 15 + 10 ) * batch_mult * .15 ),
                                ( int )making->difficulty * 1.25 );
                add_msg( m_info, _( "%s watches you craft..." ), elem->name.c_str() );
            }
        }

    }

    // Messed up badly; waste some components.
    if( making->difficulty != 0 && diff_roll > skill_roll * ( 1 + 0.1 * rng( 1, 5 ) ) ) {
        add_msg( m_bad, _( "You fail to make the %s, and waste some materials." ),
                 item::nname( making->result ).c_str() );
        if( last_craft->has_cached_selections() ) {
            last_craft->consume_components();
        } else {
            // @todo Guarantee that selections are cached
            const auto &req = making->requirements();
            for( const auto &it : req.get_components() ) {
                consume_items( it, batch_size );
            }
            for( const auto &it : req.get_tools() ) {
                consume_tools( it, batch_size );
            }
        }
        activity.set_to_null();
        return;
        // Messed up slightly; no components wasted.
    } else if( diff_roll > skill_roll ) {
        add_msg( m_neutral, _( "You fail to make the %s, but don't waste any materials." ),
                 item::nname( making->result ).c_str() );
        //this method would only have been called from a place that nulls activity.type,
        //so it appears that it's safe to NOT null that variable here.
        //rationale: this allows certain contexts (e.g. ACT_LONGCRAFT) to distinguish major and minor failures
        return;
    }

    // If we're here, the craft was a success!
    // Use up the components and tools
    std::list<item> used;
    if( !last_craft->has_cached_selections() ) {
        // This should fail and return, but currently crafting_command isn't saved
        // Meaning there are still cases where has_cached_selections will be false
        // @todo Allow saving last_craft and debugmsg+fail craft if selection isn't cached
        if( !has_trait( trait_id( "DEBUG_HS" ) ) ) {
            const auto &req = making->requirements();
            for( const auto &it : req.get_components() ) {
                std::list<item> tmp = consume_items( it, batch_size );
                used.splice( used.end(), tmp );
            }
            for( const auto &it : req.get_tools() ) {
                consume_tools( it, batch_size );
            }
        }
    } else if( !has_trait( trait_id( "DEBUG_HS" ) ) ) {
        used = last_craft->consume_components();
        if( used.empty() ) {
            return;
        }
    }

    // Set up the new item, and assign an inventory letter if available
    std::vector<item> newits = making->create_results( batch_size );
    bool first = true;
    float used_age_tally = 0;
    int used_age_count = 0;
    size_t newit_counter = 0;
    for( item &newit : newits ) {
        // messages, learning of recipe, food spoilage calc only once
        if( first ) {
            first = false;
            if( knows_recipe( making ) ) {
                add_msg( _( "You craft %s from memory." ), newit.type_name( 1 ).c_str() );
            } else {
                add_msg( _( "You craft %s using a book as a reference." ), newit.type_name( 1 ).c_str() );
                // If we made it, but we don't know it,
                // we're making it from a book and have a chance to learn it.
                // Base expected time to learn is 1000*(difficulty^4)/skill/int moves.
                // This means time to learn is greatly decreased with higher skill level,
                // but also keeps going up as difficulty goes up.
                // Worst case is lvl 10, which will typically take
                // 10^4/10 (1,000) minutes, or about 16 hours of crafting it to learn.
                int difficulty = has_recipe( making, crafting_inventory(), helpers );
                ///\EFFECT_INT increases chance to learn recipe when crafting from a book
                if( x_in_y( making->time, ( 1000 * 8 *
                                            ( difficulty * difficulty * difficulty * difficulty ) ) /
                            ( std::max( get_skill_level( making->skill_used ).level(), 1 ) * std::max( get_int(), 1 ) ) ) ) {
                    learn_recipe( ( recipe * )making );
                    add_msg( m_good, _( "You memorized the recipe for %s!" ),
                             newit.type_name( 1 ).c_str() );
                }
            }

            for( auto &elem : used ) {
                if( elem.goes_bad() ) {
                    used_age_tally += elem.get_relative_rot();
                    ++used_age_count;
                }
            }
        }

        // Don't store components for things made by charges,
        // don't store components for things that can't be uncrafted.
        if( recipe_dictionary::get_uncraft( making->result ) && !newit.count_by_charges() ) {
            // Setting this for items counted by charges gives only problems:
            // those items are automatically merged everywhere (map/vehicle/inventory),
            // which would either loose this information or merge it somehow.
            set_components( newit.components, used, batch_size, newit_counter );
            newit_counter++;
        }
        finalize_crafted_item( newit, used_age_tally, used_age_count );
        set_item_inventory( newit );
    }

    if( making->has_byproducts() ) {
        std::vector<item> bps = making->create_byproducts( batch_size );
        for( auto &bp : bps ) {
            finalize_crafted_item( bp, used_age_tally, used_age_count );
            set_item_inventory( bp );
        }
    }

    inv.restack( this );
}
Esempio n. 4
0
/* This call is in-efficient when doing it for multiple items with the same map inventory.
In that case, consider using select_item_component with 1 pre-created map inventory, and then passing the results
to consume_items */
std::list<item> player::consume_items( const std::vector<item_comp> &components, int batch )
{
    inventory map_inv;
    map_inv.form_from_map( pos(), PICKUP_RANGE );
    return consume_items( select_item_component( components, batch, map_inv ), batch );
}
Esempio n. 5
0
void game::complete_craft()
{
 recipe* making = recipes[u.activity.index]; // Which recipe is it?

// # of dice is 75% primary skill, 25% secondary (unless secondary is null)
 int skill_dice = u.sklevel[making->sk_primary] * 3;
 if (making->sk_secondary == sk_null)
  skill_dice += u.sklevel[making->sk_primary];
 else
  skill_dice += u.sklevel[making->sk_secondary];
// Sides on dice is 16 plus your current intelligence
 int skill_sides = 16 + u.int_cur;

 int diff_dice = making->difficulty * 4; // Since skill level is * 4 also
 int diff_sides = 24;	// 16 + 8 (default intelligence)

 int skill_roll = dice(skill_dice, skill_sides);
 int diff_roll  = dice(diff_dice,  diff_sides);

 if (making->sk_primary != sk_null)
  u.practice(making->sk_primary, making->difficulty * 5 + 20);
 if (making->sk_secondary != sk_null)
  u.practice(making->sk_secondary, 5);

// Messed up badly; waste some components.
 if (making->difficulty != 0 && diff_roll > skill_roll * (1 + 0.1 * rng(1, 5))) {
  add_msg("You fail to make the %s, and waste some materials.",
          itypes[making->result]->name.c_str());
  for (int i = 0; i < 5; i++) {
   if (making->components[i].size() > 0) {
    std::vector<component> copy = making->components[i];
    for (int j = 0; j < copy.size(); j++)
     copy[j].count = rng(0, copy[j].count);
    consume_items(this, copy);
   }
   if (making->tools[i].size() > 0)
    consume_tools(this, making->tools[i]);
  }
  u.activity.type = ACT_NULL;
  return;
  // Messed up slightly; no components wasted.
 } else if (diff_roll > skill_roll) {
  add_msg("You fail to make the %s, but don't waste any materials.",
          itypes[making->result]->name.c_str());
  u.activity.type = ACT_NULL;
  return;
 }
// If we're here, the craft was a success!
// Use up the components and tools
 for (int i = 0; i < 5; i++) {
  if (making->components[i].size() > 0)
   consume_items(this, making->components[i]);
  if (making->tools[i].size() > 0)
   consume_tools(this, making->tools[i]);
 }

  // Set up the new item, and pick an inventory letter
 int iter = 0;
 item newit(itypes[making->result], turn, nextinv);
 if (!newit.craft_has_charges())
  newit.charges = 0;
 do {
  newit.invlet = nextinv;
  advance_nextinv();
  iter++;
 } while (u.has_item(newit.invlet) && iter < 52);
 //newit = newit.in_its_container(&itypes);
 if (newit.made_of(LIQUID))
  handle_liquid(newit, false, false);
 else {
// We might not have space for the item
  if (iter == 52 || u.volume_carried()+newit.volume() > u.volume_capacity()) {
   add_msg("There's no room in your inventory for the %s, so you drop it.",
             newit.tname().c_str());
   m.add_item(u.posx, u.posy, newit);
  } else if (u.weight_carried() + newit.volume() > u.weight_capacity()) {
   add_msg("The %s is too heavy to carry, so you drop it.",
           newit.tname().c_str());
   m.add_item(u.posx, u.posy, newit);
  } else {
   u.i_add(newit);
   add_msg("%c - %s", newit.invlet, newit.tname().c_str());
  }
 }
}