Ejemplo n.º 1
0
// Get use methods of this item and its contents
bool item_has_uses_recursive( const item &it )
{
    if( !it.type->use_methods.empty() ) {
        return true;
    }

    for( const auto &elem : it.contents ) {
        if( item_has_uses_recursive( elem ) ) {
            return true;
        }
    }

    return false;
}
Ejemplo n.º 2
0
item_action_map item_action_generator::map_actions_to_items( player &p,
        const std::vector<item *> &pseudos ) const
{
    std::set< item_action_id > unmapped_actions;
    for( auto &ia_ptr : item_actions ) { // Get ids of wanted actions
        unmapped_actions.insert( ia_ptr.first );
    }

    item_action_map candidates;
    std::vector< item * > items = p.inv_dump();
    items.reserve( items.size() + pseudos.size() );
    items.insert( items.end(), pseudos.begin(), pseudos.end() );

    std::unordered_set< item_action_id > to_remove;
    for( item *i : items ) {
        if( !item_has_uses_recursive( *i ) ) {
            continue;
        }

        for( const item_action_id &use : unmapped_actions ) {
            // Actually used item can be different from the "outside item"
            // For example, sheathed knife
            item *actual_item = i->get_usable_item( use );
            if( actual_item == nullptr ) {
                continue;
            }

            const use_function *func = actual_item->get_use( use );
            if( !( func && func->get_actor_ptr() &&
                   func->get_actor_ptr()->can_use( p, *actual_item, false, p.pos() ) ) ) {
                continue;
            }
            if( !actual_item->ammo_sufficient() ) {
                continue;
            }

            // Add to usable items if it needs less charges per use or has less charges
            auto found = candidates.find( use );
            bool better = false;
            if( found == candidates.end() ) {
                better = true;
            } else {
                if( actual_item->ammo_required() > found->second->ammo_required() ) {
                    continue; // Other item consumes less charges
                }

                if( found->second->ammo_remaining() > actual_item->ammo_remaining() ) {
                    better = true; // Items with less charges preferred
                }
            }

            if( better ) {
                candidates[use] = i;
                if( actual_item->ammo_required() == 0 ) {
                    to_remove.insert( use );
                }
            }
        }

        for( const item_action_id &r : to_remove ) {
            unmapped_actions.erase( r );
        }
    }

    return candidates;
}
Ejemplo n.º 3
0
item_action_map item_action_generator::map_actions_to_items( player &p,
        const std::vector<item *> &pseudos ) const
{
    std::set< item_action_id > unmapped_actions;
    for( auto &ia_ptr : item_actions ) { // Get ids of wanted actions
        unmapped_actions.insert( ia_ptr.first );
    }

    item_action_map candidates;
    std::vector< item * > items = p.inv_dump();
    items.reserve( items.size() + pseudos.size() );
    items.insert( items.end(), pseudos.begin(), pseudos.end() );

    std::unordered_set< item_action_id > to_remove;
    for( item *i : items ) {
        if( !item_has_uses_recursive( *i ) ) {
            continue;
        }

        for( const item_action_id &use : unmapped_actions ) {
            // Actually used item can be different from the "outside item"
            // For example, sheathed knife
            item *actual_item = i->get_usable_item( use );
            if( actual_item == nullptr ) {
                continue;
            }

            const auto tool = dynamic_cast<const it_tool *>( actual_item->type );
            const use_function *ufunc = actual_item->get_use( use );
            // Can't just test for charges_per_use > charges, because charges can be -1
            if( ufunc == nullptr ||
                    ( ufunc->get_actor_ptr() != nullptr &&
                      !ufunc->get_actor_ptr()->can_use( &p, actual_item, false, p.pos() ) ) ||
                    ( tool != nullptr && tool->charges_per_use > 0 &&
                      tool->charges_per_use > actual_item->charges ) ) {
                continue;
            }

            // Add to usable items if it needs less charges per use or has less charges
            auto found = candidates.find( use );
            int would_use_charges = tool == nullptr ? 0 : tool->charges_per_use;
            bool better = false;
            if( found == candidates.end() ) {
                better = true;
            } else {
                const auto other = dynamic_cast<const it_tool *>( found->second->type );
                if( other == nullptr || would_use_charges > other->charges_per_use ) {
                    continue; // Other item consumes less charges
                }

                if( found->second->charges > actual_item->charges ) {
                    better = true; // Items with less charges preferred
                }
            }

            if( better ) {
                candidates[use] = i;
                if( would_use_charges == 0 ) {
                    to_remove.insert( use );
                }
            }
        }

        for( const item_action_id &r : to_remove ) {
            unmapped_actions.erase( r );
        }
    }

    return candidates;
}