void activity_on_turn_move_items()
{
    // Move activity has source square, target square,
    // indices of items on map, and quantities of same.
    point source = g->u.activity.placement;
    point destination = point( g->u.activity.values[0], g->u.activity.values[1] );
    std::list<int> indices;
    std::list<int> quantities;
    // Note i = 2, skipping first few elements.
    for( size_t i = 2; i < g->u.activity.values.size(); i += 2 ) {
        indices.push_back( g->u.activity.values[i] );
        quantities.push_back( g->u.activity.values[ i + 1 ] );
    }
    // Nuke the current activity, leaving the backlog alone.
    g->u.activity = player_activity();

    move_items( source, destination, indices, quantities );

    if( !indices.empty() ) {
        g->u.assign_activity( ACT_MOVE_ITEMS, 0 );
        g->u.activity.placement = source;
        g->u.activity.values.push_back( destination.x );
        g->u.activity.values.push_back( destination.y );
        while( !indices.empty() ) {
            g->u.activity.values.push_back( indices.front() );
            indices.pop_front();
            g->u.activity.values.push_back( quantities.front() );
            quantities.pop_front();
        }
    }
}
예제 #2
0
void player::disassemble_all( bool one_pass )
{
    // Reset all the activity values
    assign_activity( activity_id( "ACT_DISASSEMBLE" ), 0 );
    auto items = g->m.i_at( pos() );
    bool found_any = false;
    if( !one_pass ) {
        // Kinda hacky
        // That INT_MIN notes we want infinite uncraft
        // If INT_MIN is reached in complete_disassemble,
        // we will call this function again.
        activity.values.push_back( INT_MIN );
        activity.str_values.push_back( "" );
        activity.coords.push_back( tripoint_min );
    }

    for( size_t i = 0; i < items.size(); i++ ) {
        if( disassemble( items[i], i, true, false ) ) {
            found_any = true;
        }
    }

    if( !found_any ) {
        // Reset the activity - don't loop if there is nothing to do
        activity = player_activity();
    }
}
void craft_command::execute()
{
    if( empty() ) {
        return;
    }

    bool need_selections = true;
    inventory map_inv;
    map_inv.form_from_map( crafter->pos(), PICKUP_RANGE );

    if( has_cached_selections() ) {
        std::vector<comp_selection<item_comp>> missing_items = check_item_components_missing( map_inv );
        std::vector<comp_selection<tool_comp>> missing_tools = check_tool_components_missing( map_inv );

        if( missing_items.empty() && missing_tools.empty() ) {
            // All items we used previously are still there, so we don't need to do selection.
            need_selections = false;
        } else if( !query_continue( missing_items, missing_tools ) ) {
            return;
        }
    }

    const auto needs = rec->requirements();

    if( need_selections ) {
        item_selections.clear();
        for( const auto &it : needs.get_components() ) {
            comp_selection<item_comp> is = crafter->select_item_component( it, batch_size, map_inv, true );
            if( is.use_from == cancel ) {
                return;
            }
            item_selections.push_back( is );
        }

        tool_selections.clear();
        for( const auto &it : needs.get_tools() ) {
            comp_selection<tool_comp> ts = crafter->select_tool_component(
                                               it, batch_size, map_inv, DEFAULT_HOTKEYS, true );
            if( ts.use_from == cancel ) {
                return;
            }
            tool_selections.push_back( ts );
        }
    }

    auto activity = player_activity( is_long ? ACT_LONGCRAFT : ACT_CRAFT,
                                     rec->batch_time( batch_size ),
                                     -1, INT_MIN, rec->ident() );
    activity.values.push_back( batch_size );

    crafter->assign_activity( activity );

    /* legacy support for lua bindings to last_batch and lastrecipe */
    crafter->last_batch = batch_size;
    crafter->lastrecipe = rec->ident();
}
/*      values explanation
 *      0: items from vehicle?
 *      1: items to a vehicle?
 *      2: index <-+
 *      3: amount  |
 *      n: ^-------+
 */
void activity_on_turn_move_items()
{
    // Drop activity if we don't know destination coordinates.
    if( g->u.activity.coords.empty() ) {
        g->u.activity = player_activity();
        return;
    }

    // Move activity has source square, target square,
    // indices of items on map, and quantities of same.
    const tripoint destination = g->u.activity.coords[0];
    const tripoint source = g->u.activity.placement;
    bool from_vehicle = g->u.activity.values[0];
    bool to_vehicle = g->u.activity.values[1];
    std::list<int> indices;
    std::list<int> quantities;

    // Note i = 4, skipping first few elements.
    for( size_t i = 2; i < g->u.activity.values.size(); i += 2 ) {
        indices.push_back( g->u.activity.values[i] );
        quantities.push_back( g->u.activity.values[i + 1] );
    }
    // Nuke the current activity, leaving the backlog alone.
    g->u.activity = player_activity();


    // *puts on 3d glasses from 90s cereal box*
    move_items( source, from_vehicle, destination, to_vehicle, indices, quantities );

    if( !indices.empty() ) {
        g->u.assign_activity( activity_id( "ACT_MOVE_ITEMS" ) );
        g->u.activity.placement = source;
        g->u.activity.coords.push_back( destination );
        g->u.activity.values.push_back( from_vehicle );
        g->u.activity.values.push_back( to_vehicle );
        while( !indices.empty() ) {
            g->u.activity.values.push_back( indices.front() );
            indices.pop_front();
            g->u.activity.values.push_back( quantities.front() );
            quantities.pop_front();
        }
    }
}
예제 #5
0
void player_activity::do_turn( player &p )
{
    // Should happen before activity or it may fail du to 0 moves
    if( *this && type->will_refuel_fires() ) {
        try_refuel_fire( p );
    }

    if( type->based_on() == based_on_type::TIME ) {
        moves_left -= 100;
    } else if( type->based_on() == based_on_type::SPEED ) {
        if( p.moves <= moves_left ) {
            moves_left -= p.moves;
            p.moves = 0;
        } else {
            p.moves -= moves_left;
            moves_left = 0;
        }
    }

    // This might finish the activity (set it to null)
    type->call_do_turn( this, &p );

    if( *this && type->rooted() ) {
        p.rooted();
        p.pause();
    }

    if( *this && moves_left <= 0 ) {
        // Note: For some activities "finish" is a misnomer; that's why we explicitly check if the
        // type is ACT_NULL below.
        if( !( type->call_finish( this, &p ) ) ) {
            // "Finish" is never a misnomer for any activity without a finish function
            set_to_null();
        }
    }
    if( !*this ) {
        // Make sure data of previous activity is cleared
        p.activity = player_activity();
        if( !p.backlog.empty() && p.backlog.front().auto_resume ) {
            p.activity = p.backlog.front();
            p.backlog.pop_front();
        }

        // If whatever activity we were doing forced us to pick something up to
        // handle it, drop any overflow that may have caused
        p.drop_invalid_inventory();
    }
}
예제 #6
0
void game::place_construction(constructable *con)
{
 refresh_all();
 inventory total_inv;
 total_inv.form_from_map(this, point(u.posx, u.posy), PICKUP_RANGE);
 total_inv.add_stack(u.inv_dump());

 std::vector<point> valid;
 for (int x = u.posx - 1; x <= u.posx + 1; x++) {
  for (int y = u.posy - 1; y <= u.posy + 1; y++) {
   if (x == u.posx && y == u.posy)
    y++;
   construct test;
   bool place_okay = (test.*(con->able))(this, point(x, y));
   for (int i = 0; i < con->stages.size() && !place_okay; i++) {
    if (m.ter(x, y) == con->stages[i].terrain)
     place_okay = true;
   }

   if (place_okay) {
// Make sure we're not trying to continue a construction that we can't finish
    int starting_stage = 0, max_stage = 0;
    for (int i = 0; i < con->stages.size(); i++) {
     if (m.ter(x, y) == con->stages[i].terrain)
      starting_stage = i + 1;
     if (player_can_build(u, total_inv, con, i, true))
      max_stage = i;
    }

    if (max_stage >= starting_stage) {
     valid.push_back(point(x, y));
     m.drawsq(w_terrain, u, x, y, true, false);
     wrefresh(w_terrain);
    }
   }
  }
 }
 mvprintz(0, 0, c_red, _("Pick a direction in which to construct:"));
 int dirx, diry;
 get_direction(this, dirx, diry, input());
 if (dirx == -2) {
  add_msg(_("Invalid direction."));
  return;
 }
 dirx += u.posx;
 diry += u.posy;
 bool point_is_okay = false;
 for (int i = 0; i < valid.size() && !point_is_okay; i++) {
  if (valid[i].x == dirx && valid[i].y == diry)
   point_is_okay = true;
 }
 if (!point_is_okay) {
  add_msg(_("You cannot build there!"));
  return;
 }

// Figure out what stage to start at, and what stage is the maximum
 int starting_stage = 0, max_stage = 0;
 for (int i = 0; i < con->stages.size(); i++) {
  if (m.ter(dirx, diry) == con->stages[i].terrain)
   starting_stage = i + 1;
  if (player_can_build(u, total_inv, con, i, true))
   max_stage = i;
 }

 u.activity = player_activity(ACT_BUILD, con->stages[starting_stage].time*1000,
                              con->id);
 u.moves = 0;
 std::vector<int> stages;
 for (int i = starting_stage; i <= max_stage; i++)
  stages.push_back(i);
 u.activity.values = stages;
 u.activity.placement = point(dirx, diry);
}
예제 #7
0
void player_activity::finish( player *p )
{
    switch( type ) {
        case ACT_RELOAD:
            activity_handlers::reload_finish( this, p );
            break;
        case ACT_READ:
            p->do_read( &( p->i_at( position ) ) );
            if( type == ACT_NULL ) {
                add_msg( _( "You finish reading." ) );
            }
            break;
        case ACT_WAIT:
        case ACT_WAIT_WEATHER:
            add_msg( _( "You finish waiting." ) );
            type = ACT_NULL;
            break;
        case ACT_WAIT_NPC:
            add_msg( _( "%s finishes with you..." ), str_values[0].c_str() );
            type = ACT_NULL;
            break;
        case ACT_CRAFT:
            p->complete_craft();
            type = ACT_NULL;
            break;
        case ACT_LONGCRAFT: {
            int batch_size = values.front();
            p->complete_craft();
            type = ACT_NULL;
            // Workaround for a bug where longcraft can be unset in complete_craft().
            if( p->making_would_work( p->lastrecipe, batch_size ) ) {
                p->make_all_craft( p->lastrecipe, batch_size );
            }
        }
        break;
        case ACT_FORAGE:
            activity_handlers::forage_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_DISASSEMBLE:
            p->complete_disassemble();
            break;
        case ACT_BUTCHER:
            activity_handlers::butcher_finish( this, p );
            break;
        case ACT_LONGSALVAGE:
            activity_handlers::longsalvage_finish( this, p );
            break;
        case ACT_VEHICLE:
            activity_handlers::vehicle_finish( this, p );
            break;
        case ACT_BUILD:
            complete_construction();
            type = ACT_NULL;
            break;
        case ACT_TRAIN:
            activity_handlers::train_finish( this, p );
            break;
        case ACT_FIRSTAID:
            activity_handlers::firstaid_finish( this, p );
            break;
        case ACT_FISH:
            activity_handlers::fish_finish( this, p );
            break;
        case ACT_PICKAXE:
            activity_handlers::pickaxe_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_BURROW:
            activity_handlers::burrow_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_VIBE:
            add_msg( m_good, _( "You feel much better." ) );
            type = ACT_NULL;
            break;
        case ACT_MAKE_ZLAVE:
            activity_handlers::make_zlave_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_PICKUP:
        case ACT_MOVE_ITEMS:
            // Only do nothing if the item being picked up doesn't need to be equipped.
            // If it needs to be equipped, our activity_handler::pickup_finish() does so.
            // This is primarily used by AIM to advance moves while moving items around.
            activity_handlers::pickup_finish( this, p );
            break;
        case ACT_START_FIRE:
            activity_handlers::start_fire_finish( this, p );
            break;
        case ACT_OPEN_GATE:
            activity_handlers::open_gate_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_HOTWIRE_CAR:
            activity_handlers::hotwire_finish( this, p );
            break;
        case ACT_AIM:
            // Aim bails itself by resetting itself every turn,
            // you only re-enter if it gets set again.
            break;
        case ACT_ATM:
            // ATM sets index to 0 to indicate it's finished.
            if( !index ) {
                type = ACT_NULL;
            }
            break;
        case ACT_START_ENGINES:
            activity_handlers::start_engines_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_OXYTORCH:
            activity_handlers::oxytorch_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_CRACKING:
            activity_handlers::cracking_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_REPAIR_ITEM:
            // Unsets activity (if needed) inside function
            activity_handlers::repair_item_finish( this, p );
            break;
        case ACT_MEND_ITEM:
            activity_handlers::mend_item_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_GUNMOD_ADD:
            activity_handlers::gunmod_add_finish( this, p );
            type = ACT_NULL;
            break;
        default:
            type = ACT_NULL;
    }
    if( type == ACT_NULL ) {
        // Make sure data of previous activity is cleared
        p->activity = player_activity();
        if( !p->backlog.empty() && p->backlog.front().auto_resume ) {
            p->activity = p->backlog.front();
            p->backlog.pop_front();
        }
    }
}
예제 #8
0
void game::make_craft(recipe *making)
{
 u.activity = player_activity(ACT_CRAFT, making->time, making->id);
 u.moves = 0;
}
void activity_on_turn_move_loot( player_activity &, player &p )
{
    const activity_id act_move_loot = activity_id( "ACT_MOVE_LOOT" );
    auto &mgr = zone_manager::get_manager();
    if( g->m.check_vehicle_zones( g->get_levz() ) ) {
        mgr.cache_vzones();
    }
    const auto abspos = g->m.getabs( p.pos() );
    const auto &src_set = mgr.get_near( zone_type_id( "LOOT_UNSORTED" ), abspos );
    vehicle *src_veh, *dest_veh;
    int src_part, dest_part;

    // Nuke the current activity, leaving the backlog alone.
    p.activity = player_activity();

    // sort source tiles by distance
    const auto &src_sorted = get_sorted_tiles_by_distance( abspos, src_set );

    if( !mgr.is_sorting() ) {
        mgr.start_sort( src_sorted );
    }

    for( auto &src : src_sorted ) {
        const auto &src_loc = g->m.getlocal( src );
        if( !g->m.inbounds( src_loc ) ) {
            if( !g->m.inbounds( p.pos() ) ) {
                // p is implicitly an NPC that has been moved off the map, so reset the activity
                // and unload them
                p.assign_activity( act_move_loot );
                p.set_moves( 0 );
                g->reload_npcs();
                mgr.end_sort();
                return;
            }
            std::vector<tripoint> route;
            route = g->m.route( p.pos(), src_loc, p.get_pathfinding_settings(),
                                p.get_path_avoid() );
            if( route.empty() ) {
                // can't get there, can't do anything, skip it
                continue;
            }
            p.set_destination( route, player_activity( act_move_loot ) );
            mgr.end_sort();
            return;
        }

        bool is_adjacent_or_closer = square_dist( p.pos(), src_loc ) <= 1;

        // skip tiles in IGNORE zone and tiles on fire
        // (to prevent taking out wood off the lit brazier)
        // and inaccessible furniture, like filled charcoal kiln
        if( mgr.has( zone_type_id( "LOOT_IGNORE" ), src ) ||
            g->m.get_field( src_loc, fd_fire ) != nullptr ||
            !g->m.can_put_items_ter_furn( src_loc ) ) {
            continue;
        }

        // the boolean in this pair being true indicates the item is from a vehicle storage space
        auto items = std::vector<std::pair<item *, bool>>();

        //Check source for cargo part
        //map_stack and vehicle_stack are different types but inherit from item_stack
        // TODO: use one for loop
        if( const cata::optional<vpart_reference> vp = g->m.veh_at( src_loc ).part_with_feature( "CARGO",
                false ) ) {
            src_veh = &vp->vehicle();
            src_part = vp->part_index();
            for( auto &it : src_veh->get_items( src_part ) ) {
                items.push_back( std::make_pair( &it, true ) );
            }
        } else {
            src_veh = nullptr;
            src_part = -1;
        }
        for( auto &it : g->m.i_at( src_loc ) ) {
            items.push_back( std::make_pair( &it, false ) );
        }
        //Skip items that have already been processed
        for( auto it = items.begin() + mgr.get_num_processed( src ); it < items.end(); it++ ) {

            mgr.increment_num_processed( src );

            const auto thisitem = it->first;

            if( thisitem->made_of_from_type( LIQUID ) ) { // skip unpickable liquid
                continue;
            }

            // Only if it's from a vehicle do we use the vehicle source location information.
            vehicle *this_veh = it->second ? src_veh : nullptr;
            const int this_part = it->second ? src_part : -1;

            const auto id = mgr.get_near_zone_type_for_item( *thisitem, abspos );

            // checks whether the item is already on correct loot zone or not
            // if it is, we can skip such item, if not we move the item to correct pile
            // think empty bag on food pile, after you ate the content
            if( !mgr.has( id, src ) ) {
                const auto &dest_set = mgr.get_near( id, abspos );

                for( auto &dest : dest_set ) {
                    const auto &dest_loc = g->m.getlocal( dest );

                    //Check destination for cargo part
                    if( const cata::optional<vpart_reference> vp = g->m.veh_at( dest_loc ).part_with_feature( "CARGO",
                            false ) ) {
                        dest_veh = &vp->vehicle();
                        dest_part = vp->part_index();
                    } else {
                        dest_veh = nullptr;
                        dest_part = -1;
                    }

                    // skip tiles with inaccessible furniture, like filled charcoal kiln
                    if( !g->m.can_put_items_ter_furn( dest_loc ) ) {
                        continue;
                    }

                    units::volume free_space;
                    // if there's a vehicle with space do not check the tile beneath
                    if( dest_veh ) {
                        free_space = dest_veh->free_volume( dest_part );
                    } else {
                        free_space = g->m.free_volume( dest_loc );
                    }
                    // check free space at destination
                    if( free_space >= thisitem->volume() ) {
                        // before we move any item, check if player is at or
                        // adjacent to the loot source tile
                        if( !is_adjacent_or_closer ) {
                            std::vector<tripoint> route;
                            bool adjacent = false;

                            // get either direct route or route to nearest adjacent tile if
                            // source tile is impassable
                            if( g->m.passable( src_loc ) ) {
                                route = g->m.route( p.pos(), src_loc, p.get_pathfinding_settings(),
                                                    p.get_path_avoid() );
                            } else {
                                // immpassable source tile (locker etc.),
                                // get route to nerest adjacent tile instead
                                route = route_adjacent( p, src_loc );
                                adjacent = true;
                            }

                            // check if we found path to source / adjacent tile
                            if( route.empty() ) {
                                add_msg( m_info, _( "%s can't reach the source tile. Try to sort out loot without a cart." ),
                                         p.disp_name() );
                                mgr.end_sort();
                                return;
                            }

                            // shorten the route to adjacent tile, if necessary
                            if( !adjacent ) {
                                route.pop_back();
                            }

                            // set the destination and restart activity after player arrives there
                            // we don't need to check for safe mode,
                            // activity will be restarted only if
                            // player arrives on destination tile
                            p.set_destination( route, player_activity( act_move_loot ) );
                            mgr.end_sort();
                            return;
                        }
                        move_item( p, *thisitem, thisitem->count(), src_loc, dest_loc, this_veh, this_part );

                        // moved item away from source so decrement
                        mgr.decrement_num_processed( src );

                        break;
                    }
                }
                if( p.moves <= 0 ) {
                    // Restart activity and break from cycle.
                    p.assign_activity( act_move_loot );
                    mgr.end_sort();
                    return;
                }
            }
        }
    }

    // If we got here without restarting the activity, it means we're done
    add_msg( m_info, string_format( _( "%s sorted out every item possible." ), p.disp_name() ) );
    mgr.end_sort();
}
예제 #10
0
void player_activity::finish( player *p )
{
    switch (type) {
        case ACT_RELOAD:
            activity_handlers::reload_finish( this, p );
            break;
        case ACT_READ:
            p->do_read(&(p->i_at(position)));
            if (type == ACT_NULL) {
                add_msg(_("You finish reading."));
            }
            break;
        case ACT_WAIT:
        case ACT_WAIT_WEATHER:
            add_msg(_("You finish waiting."));
            type = ACT_NULL;
            break;
        case ACT_CRAFT:
            p->complete_craft();
            type = ACT_NULL;
            break;
        case ACT_LONGCRAFT:
            {
                int batch_size = values.front();
                p->complete_craft();
		type = ACT_NULL;
                // Workaround for a bug where longcraft can be unset in complete_craft().
                if( p->making_would_work( p->lastrecipe, batch_size ) ) {
                    p->make_all_craft( p->lastrecipe, batch_size );
                }
            }
            break;
        case ACT_FORAGE:
            activity_handlers::forage_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_DISASSEMBLE:
            p->complete_disassemble();
            type = ACT_NULL;
            break;
        case ACT_BUTCHER:
            activity_handlers::butcher_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_LONGSALVAGE:
            activity_handlers::longsalvage_finish( this, p );
            break;
        case ACT_VEHICLE:
            activity_handlers::vehicle_finish( this, p );
            break;
        case ACT_BUILD:
            complete_construction();
            type = ACT_NULL;
            break;
        case ACT_TRAIN:
            activity_handlers::train_finish( this, p );
            break;
        case ACT_FIRSTAID:
            activity_handlers::firstaid_finish( this, p );
            break;
        case ACT_FISH:
            activity_handlers::fish_finish( this, p );
            break;
        case ACT_PICKAXE:
            activity_handlers::pickaxe_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_BURROW:
            activity_handlers::burrow_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_VIBE:
            add_msg(m_good, _("You feel much better."));
            type = ACT_NULL;
            break;
        case ACT_MAKE_ZLAVE:
            activity_handlers::make_zlave_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_PICKUP:
        case ACT_MOVE_ITEMS:
            // Do nothing, the only way this happens is if we set this activity after
            // entering the advanced inventory menu as an activity, and we want it to play out.
            break;
        case ACT_START_FIRE:
            activity_handlers::start_fire_finish( this, p );
            break;
        case ACT_HOTWIRE_CAR:
            activity_handlers::hotwire_finish( this, p );
            break;
        case ACT_AIM:
            // Aim bails itself by resetting itself every turn,
            // you only re-enter if it gets set again.
            break;
        case ACT_ATM:
            // ATM sets index to 0 to indicate it's finished.
            if (!index) {
                type = ACT_NULL;
            }
            break;
        case ACT_START_ENGINES:
            activity_handlers::start_engines_finish( this, p );
            type = ACT_NULL;
            break;
        case ACT_OXYTORCH:
            activity_handlers::oxytorch_finish( this, p );
            type = ACT_NULL;
            break;
        default:
            type = ACT_NULL;
    }
    if (type == ACT_NULL) {
        // Make sure data of previous activity is cleared
        p->activity = player_activity();
        if( !p->backlog.empty() && p->backlog.front().auto_resume ) {
            p->activity = p->backlog.front();
            p->backlog.pop_front();
        }
    }
}