/** * Dragging and dropping an item can be used to rearrange the stash */ void MenuStash::drop(Point position, ItemStack stack) { int slot; int drag_prev_slot; items->playSound(stack.item); slot = stock.slotOver(position); drag_prev_slot = stock.drag_prev_slot; if (slot == -1) { itemReturn(stack); } else if (slot != drag_prev_slot) { if (stock[slot].item == stack.item || stock[slot].empty()) { // Drop the stack, merging if needed add(stack, slot); } else if (drag_prev_slot != -1 && stock[drag_prev_slot].empty()) { // Check if the previous slot is free (could still be used if SHIFT was used). // Swap the two stacks itemReturn(stock[slot]); stock[slot] = stack; } else { itemReturn(stack); } } else { itemReturn(stack); // cancel } updated = true; }
/** * Click-start dragging in the inventory */ ItemStack MenuInventory::click(Point position) { ItemStack item; drag_prev_src = areaOver(position); if (drag_prev_src > -1) { item = inventory[drag_prev_src].click(position); if (TOUCHSCREEN) { tablist.setCurrent(inventory[drag_prev_src].current_slot); } if (item.empty()) { drag_prev_src = -1; return item; } // if dragging equipment, prepare to change stats/sprites if (drag_prev_src == EQUIPMENT) { if (stats->humanoid) { updateEquipment(inventory[EQUIPMENT].drag_prev_slot); } else { itemReturn(item); item.clear(); } } } return item; }
/** * Insert item into first available carried slot, preferably in the optionnal specified slot * * @param ItemStack Stack of items * @param area Area number where it will try to store the item * @param slot Slot number where it will try to store the item */ void MenuInventory::add(ItemStack stack, int area, int slot) { int max_quantity; int quantity_added; int i; items->playSound(stack.item); if( stack.item != 0) { if( area < 0) { area = CARRIED; } max_quantity = items->items[stack.item].max_quantity; if( slot > -1 && inventory[area][slot].item != 0 && inventory[area][slot].item != stack.item) { // the proposed slot isn't available, search for another one slot = -1; } if( area == CARRIED) { // first search of stack to complete if the item is stackable i = 0; while( max_quantity > 1 && slot == -1 && i < MAX_CARRIED) { if (inventory[area][i].item == stack.item && inventory[area][i].quantity < max_quantity) { slot = i; } i++; } // then an empty slot i = 0; while( slot == -1 && i < MAX_CARRIED) { if (inventory[area][i].item == 0) { slot = i; } i++; } } if( slot != -1) { // Add quantity_added = min( stack.quantity, max_quantity - inventory[area][slot].quantity); inventory[area][slot].item = stack.item; inventory[area][slot].quantity += quantity_added; stack.quantity -= quantity_added; // Add back the remaining if( stack.quantity > 0) { if( drag_prev_src > -1) { itemReturn( stack); } else { add( stack); } } } else { // No available slot, drop // TODO: We should drop on the floor an item we can't store } } }
/** * Right-clicking on a usable item in the inventory causes it to activate. * e.g. drink a potion * e.g. equip an item */ void MenuInventory::activate(InputState * input) { int slot; int equip_slot; ItemStack stack; Point nullpt; nullpt.x = nullpt.y = 0; // clicked a carried item slot = inventory[CARRIED].slotOver(input->mouse); // use a consumable item if (items->items[inventory[CARRIED][slot].item].type == ITEM_TYPE_CONSUMABLE) { powers->activate(items->items[inventory[CARRIED][slot].item].power, stats, nullpt); // intercept used_item flag. We will destroy the item here. powers->used_item = -1; inventory[CARRIED].substract(slot); } // equip an item else { equip_slot = items->items[inventory[CARRIED][slot].item].type; if (equip_slot == ITEM_TYPE_MAIN || equip_slot == ITEM_TYPE_BODY || equip_slot == ITEM_TYPE_OFF || equip_slot == ITEM_TYPE_ARTIFACT) { if (requirementsMet(inventory[CARRIED][slot].item)) { stack = click( input); if( inventory[EQUIPMENT][equip_slot].item == stack.item) { // Merge the stacks add( stack, EQUIPMENT, equip_slot); } else if( inventory[EQUIPMENT][equip_slot].item == 0) { // Drop the stack inventory[EQUIPMENT][equip_slot] = stack; } else { if( inventory[CARRIED][slot].item == 0) { // Don't forget this slot may have been emptied by the click() // Swap the two stacks itemReturn( inventory[EQUIPMENT][equip_slot]); } else { // Drop the equipped item anywhere add( inventory[EQUIPMENT][equip_slot]); } inventory[EQUIPMENT][equip_slot] = stack; } updateEquipment( equip_slot); items->playSound(inventory[EQUIPMENT][equip_slot].item); } } } }
/** * Dragging and dropping an item can be used to rearrange the stash */ bool MenuStash::drop(const Point& position, ItemStack stack) { if (stack.empty()) { return true; } int slot; int drag_prev_slot; bool success = true; items->playSound(stack.item); slot = stock[activetab].slotOver(position); drag_prev_slot = stock[activetab].drag_prev_slot; if (slot == -1) { success = add(stack, slot, !ADD_PLAY_SOUND); } else if (drag_prev_slot != -1) { if (stock[activetab][slot].item == stack.item || stock[activetab][slot].empty()) { // Drop the stack, merging if needed success = add(stack, slot, !ADD_PLAY_SOUND); } else if (drag_prev_slot != -1 && stock[activetab][drag_prev_slot].empty()) { // Check if the previous slot is free (could still be used if SHIFT was used). // Swap the two stacks itemReturn(stock[activetab][slot]); stock[activetab][slot] = stack; updated = true; } else { itemReturn(stack); updated = true; } } else { success = add(stack, slot, !ADD_PLAY_SOUND); } return success; }
/** * Right-clicking on a usable item in the inventory causes it to activate. * e.g. drink a potion * e.g. equip an item */ void MenuInventory::activate(Point position) { ItemStack stack; Point nullpt; nullpt.x = nullpt.y = 0; // clicked a carried item int slot = inventory[CARRIED].slotOver(position); if (slot == -1) return; // empty slot if (inventory[CARRIED][slot].empty()) return; // can't interact with quest items if (items->items[inventory[CARRIED][slot].item].type == "quest") { return; } else if (items->items[inventory[CARRIED][slot].item].type == "book") { snd->play(sfx_open); show_book = items->items[inventory[CARRIED][slot].item].book; } // use a consumable item else if (items->items[inventory[CARRIED][slot].item].type == "consumable" && items->items[inventory[CARRIED][slot].item].power > 0) { int power_id = items->items[inventory[CARRIED][slot].item].power; // if the power consumes items, make sure we have enough if (powers->powers[power_id].requires_item > 0 && powers->powers[power_id].requires_item_quantity > getItemCountCarried(powers->powers[power_id].requires_item)) { log_msg = msg->get("You don't have enough of the required item."); return; } // check power & item requirements if (!stats->canUsePower(powers->powers[power_id], power_id)) return; //check for power cooldown if (pc->hero_cooldown[power_id] > 0) return; else pc->hero_cooldown[power_id] = powers->powers[power_id].cooldown; // if this item requires targeting it can't be used this way if (!powers->powers[power_id].requires_targeting) { powers->activate(power_id, stats, nullpt); } else { // let player know this can only be used from the action bar log_msg = msg->get("This item can only be used from the action bar."); } } // equip an item else if (stats->humanoid) { int equip_slot = -1; const ItemStack &src = inventory[CARRIED].storage[slot]; // find first empty(or just first) slot for item to equip for (int i = 0; i < MAX_EQUIPPED; i++) { if (slot_type[i] == items->items[src.item].type) { if (equip_slot == -1) { // non-empty and matching equip_slot = i; } else if (inventory[EQUIPMENT].storage[i].empty()) { // empty and matching, no need to search more equip_slot = i; break; } } } if (equip_slot != -1) { if (items->requirementsMet(stats, inventory[CARRIED][slot].item)) { stack = click(position); if( inventory[EQUIPMENT][equip_slot].item == stack.item) { // Merge the stacks add(stack, EQUIPMENT, equip_slot, false); } else if( inventory[EQUIPMENT][equip_slot].empty()) { // Drop the stack inventory[EQUIPMENT][equip_slot] = stack; } else { if( inventory[CARRIED][slot].empty()) { // Don't forget this slot may have been emptied by the click() // Swap the two stacks itemReturn( inventory[EQUIPMENT][equip_slot]); } else { // Drop the equipped item anywhere add( inventory[EQUIPMENT][equip_slot]); } inventory[EQUIPMENT][equip_slot] = stack; } updateEquipment( equip_slot); items->playSound(inventory[EQUIPMENT][equip_slot].item); // if this item has a power, place it on the action bar if possible if (items->items[stack.item].power > 0) { menu_act->addPower(items->items[stack.item].power, 0); } } } else logError("MenuInventory: Can't find equip slot, corresponding to type %s", items->items[inventory[CARRIED][slot].item].type.c_str()); } drag_prev_src = -1; }
/** * Dragging and dropping an item can be used to rearrange the inventory * and equip items */ void MenuInventory::drop(Point position, ItemStack stack) { items->playSound(stack.item); int area = areaOver(position); if (area < 0) { // not dropped into a slot. Just return it to the previous slot. itemReturn(stack); return; } int slot = inventory[area].slotOver(position); if (slot == -1) { // not dropped into a slot. Just return it to the previous slot. itemReturn(stack); return; } int drag_prev_slot = -1; if (drag_prev_src != -1) drag_prev_slot = inventory[drag_prev_src].drag_prev_slot; if (area == EQUIPMENT) { // dropped onto equipped item // make sure the item is going to the correct slot // we match slot_type to stack.item's type to place items in the proper slots // also check to see if the hero meets the requirements if (slot_type[slot] == items->items[stack.item].type && items->requirementsMet(stats, stack.item) && stats->humanoid && inventory[EQUIPMENT].slots[slot]->enabled) { if (inventory[area][slot].item == stack.item) { // Merge the stacks add(stack, area, slot, false); } else { // Swap the two stacks if (!inventory[area][slot].empty()) itemReturn(inventory[area][slot]); inventory[area][slot] = stack; updateEquipment(slot); } // if this item has a power, place it on the action bar if possible if (items->items[stack.item].power > 0) { menu_act->addPower(items->items[stack.item].power, 0); } } else { // equippable items only belong to one slot, for the moment itemReturn(stack); // cancel updateEquipment(slot); } } else if (area == CARRIED) { // dropped onto carried item if (drag_prev_src == CARRIED) { if (slot != drag_prev_slot) { if (inventory[area][slot].item == stack.item) { // Merge the stacks add(stack, area, slot, false); } else if (inventory[area][slot].empty()) { // Drop the stack inventory[area][slot] = stack; } else if (drag_prev_slot != -1 && inventory[drag_prev_src][drag_prev_slot].empty()) { // Check if the previous slot is free (could still be used if SHIFT was used). // Swap the two stacks itemReturn( inventory[area][slot]); inventory[area][slot] = stack; } else { itemReturn( stack); } } else { itemReturn( stack); // cancel } } else { // note: equipment slots 0-3 correspond with item types 0-3 // also check to see if the hero meets the requirements if (inventory[area][slot].item == stack.item || drag_prev_src == -1) { // Merge the stacks add(stack, area, slot, false); } else if (inventory[area][slot].empty()) { // Drop the stack inventory[area][slot] = stack; } else if( inventory[EQUIPMENT][drag_prev_slot].empty() && inventory[CARRIED][slot].item != stack.item && items->items[inventory[CARRIED][slot].item].type == slot_type[drag_prev_slot] && items->requirementsMet(stats, inventory[CARRIED][slot].item) ) { // The whole equipped stack is dropped on an empty carried slot or on a wearable item // Swap the two stacks itemReturn(inventory[area][slot]); updateEquipment(drag_prev_slot); // if this item has a power, place it on the action bar if possible if (items->items[inventory[EQUIPMENT][drag_prev_slot].item].power > 0) { menu_act->addPower(items->items[inventory[EQUIPMENT][drag_prev_slot].item].power, 0); } inventory[area][slot] = stack; } else { itemReturn(stack); // cancel } } } drag_prev_src = -1; }
/** * Dragging and dropping an item can be used to rearrange the inventory * and equip items */ void MenuInventory::drop(Point mouse, ItemStack stack) { int area; int slot; int drag_prev_slot; items->playSound(stack.item); area = areaOver( mouse); slot = inventory[area].slotOver(mouse); drag_prev_slot = inventory[drag_prev_src].drag_prev_slot; if (area == EQUIPMENT) { // dropped onto equipped item // make sure the item is going to the correct slot // note: equipment slots 0-3 correspond with item types 0-3 // also check to see if the hero meets the requirements if (drag_prev_src == CARRIED && slot == items->items[stack.item].type && requirementsMet(stack.item)) { if( inventory[area][slot].item == stack.item) { // Merge the stacks add( stack, area, slot); } else if( inventory[drag_prev_src][drag_prev_slot].item == 0) { // Swap the two stacks itemReturn( inventory[area][slot]); inventory[area][slot] = stack; updateEquipment( slot); } else { itemReturn( stack); } } else { // equippable items only belong to one slot, for the moment itemReturn( stack); // cancel } } else if (area == CARRIED) { // dropped onto carried item if (drag_prev_src == CARRIED) { if (slot != drag_prev_slot) { if( inventory[area][slot].item == stack.item) { // Merge the stacks add( stack, area, slot); } else if( inventory[area][slot].item == 0) { // Drop the stack inventory[area][slot] = stack; } else if( inventory[drag_prev_src][drag_prev_slot].item == 0) { // Check if the previous slot is free (could still be used if SHIFT was used). // Swap the two stacks itemReturn( inventory[area][slot]); inventory[area][slot] = stack; } else { itemReturn( stack); } } else { itemReturn( stack); // cancel } } else { // note: equipment slots 0-3 correspond with item types 0-3 // also check to see if the hero meets the requirements if (inventory[area][slot].item == stack.item) { // Merge the stacks add( stack, area, slot); } else if( inventory[area][slot].item == 0) { // Drop the stack inventory[area][slot] = stack; } else if( inventory[EQUIPMENT][drag_prev_slot].item == 0 && inventory[CARRIED][slot].item != stack.item && items->items[inventory[CARRIED][slot].item].type == drag_prev_slot && requirementsMet(inventory[CARRIED][slot].item) ) { // The whole equipped stack is dropped on an empty carried slot or on a wearable item // Swap the two stacks itemReturn( inventory[area][slot]); inventory[area][slot] = stack; } else { itemReturn( stack); // cancel } } } else { itemReturn( stack); // not dropped into a slot. Just return it to the previous slot. } drag_prev_src = -1; }
/** * Right-clicking on a usable item in the inventory causes it to activate. * e.g. drink a potion * e.g. equip an item */ void MenuInventory::activate(const Point& position) { ItemStack stack; Point nullpt; nullpt.x = nullpt.y = 0; // clicked a carried item int slot = inventory[CARRIED].slotOver(position); if (slot == -1) return; // empty slot if (inventory[CARRIED][slot].empty()) return; // if the item is a book, open it if (items->items[inventory[CARRIED][slot].item].book != "") { snd->play(sfx_open); show_book = items->items[inventory[CARRIED][slot].item].book; } // use a consumable item else if (!items->items[inventory[CARRIED][slot].item].quest_item && items->items[inventory[CARRIED][slot].item].type == "consumable" && items->items[inventory[CARRIED][slot].item].power > 0) { int power_id = items->items[inventory[CARRIED][slot].item].power; // equipment might want to replace powers, so do it here for (int i = 0; i < inventory[EQUIPMENT].getSlotNumber(); ++i) { int id = inventory[EQUIPMENT][i].item; for (size_t j = 0; j < items->items[id].replace_power.size(); ++j) { if (power_id == items->items[id].replace_power[j].x) { power_id = items->items[id].replace_power[j].y; break; } } } // if the power consumes items, make sure we have enough if (powers->powers[power_id].requires_item > 0 && powers->powers[power_id].requires_item_quantity > inventory[CARRIED].count(powers->powers[power_id].requires_item)) { pc->logMsg(msg->get("You don't have enough of the required item."), true); return; } // check power & item requirements if (!stats->canUsePower(powers->powers[power_id], power_id)) return; //check for power cooldown if (pc->hero_cooldown[power_id] > 0) return; else pc->hero_cooldown[power_id] = powers->powers[power_id].cooldown; // if this item requires targeting it can't be used this way if (!powers->powers[power_id].requires_targeting) { powers->activate(power_id, stats, nullpt); } else { // let player know this can only be used from the action bar pc->logMsg(msg->get("This item can only be used from the action bar."), true); } } // equip an item else if (stats->humanoid && items->items[inventory[CARRIED][slot].item].type != "") { int equip_slot = getEquipSlotFromItem(inventory[CARRIED].storage[slot].item, false); if (equip_slot >= 0) { stack = click(position); if (inventory[EQUIPMENT][equip_slot].item == stack.item) { // Merge the stacks add(stack, EQUIPMENT, equip_slot, false, false); } else if (inventory[EQUIPMENT][equip_slot].empty()) { // Drop the stack inventory[EQUIPMENT][equip_slot] = stack; } else { if (inventory[CARRIED][slot].empty()) { // Don't forget this slot may have been emptied by the click() // Swap the two stacks itemReturn(inventory[EQUIPMENT][equip_slot]); } else { // Drop the equipped item anywhere add(inventory[EQUIPMENT][equip_slot], CARRIED, -1, true, false); } inventory[EQUIPMENT][equip_slot] = stack; } updateEquipment(equip_slot); items->playSound(inventory[EQUIPMENT][equip_slot].item); // if this item has a power, place it on the action bar if possible if (items->items[stack.item].power > 0) { menu_act->addPower(items->items[stack.item].power, 0); } } else if (equip_slot == -1) { logError("MenuInventory: Can't find equip slot, corresponding to type %s", items->items[inventory[CARRIED][slot].item].type.c_str()); } } drag_prev_src = -1; }
/** * Dragging and dropping an item can be used to rearrange the inventory * and equip items */ bool MenuInventory::drop(const Point& position, ItemStack stack) { items->playSound(stack.item); bool success = true; int area = areaOver(position); if (area < 0) { if (drag_prev_src == -1) { success = add(stack, CARRIED, -1, false, true); } else { // not dropped into a slot. Just return it to the previous slot. itemReturn(stack); } return success; } int slot = inventory[area].slotOver(position); if (slot == -1) { if (drag_prev_src == -1) { success = add(stack, CARRIED, -1, false, true); } else { // not dropped into a slot. Just return it to the previous slot. itemReturn(stack); } return success; } int drag_prev_slot = -1; if (drag_prev_src != -1) drag_prev_slot = inventory[drag_prev_src].drag_prev_slot; if (area == EQUIPMENT) { // dropped onto equipped item // make sure the item is going to the correct slot // we match slot_type to stack.item's type to place items in the proper slots // also check to see if the hero meets the requirements if (slot_type[slot] == items->items[stack.item].type && items->requirementsMet(stats, stack.item) && stats->humanoid && inventory[EQUIPMENT].slots[slot]->enabled) { if (inventory[area][slot].item == stack.item) { // Merge the stacks success = add(stack, area, slot, false, false); } else { // Swap the two stacks if (!inventory[area][slot].empty()) itemReturn(inventory[area][slot]); inventory[area][slot] = stack; updateEquipment(slot); // if this item has a power, place it on the action bar if possible if (items->items[stack.item].power > 0) { menu_act->addPower(items->items[stack.item].power, 0); } } } else { // equippable items only belong to one slot, for the moment itemReturn(stack); // cancel updateEquipment(slot); } } else if (area == CARRIED) { // dropped onto carried item if (drag_prev_src == CARRIED) { if (slot != drag_prev_slot) { if (inventory[area][slot].item == stack.item) { // Merge the stacks success = add(stack, area, slot, false, false); } else if (inventory[area][slot].empty()) { // Drop the stack inventory[area][slot] = stack; } else if (drag_prev_slot != -1 && inventory[drag_prev_src][drag_prev_slot].empty()) { // Check if the previous slot is free (could still be used if SHIFT was used). // Swap the two stacks itemReturn( inventory[area][slot]); inventory[area][slot] = stack; } else { itemReturn( stack); } } else { itemReturn( stack); // cancel // allow reading books on touchscreen devices // since touch screens don't have right-click, we use a "tap" (drop on same slot quickly) to activate // NOTE: the quantity must be 1, since the number picker appears when tapping on a stack of more than 1 item // NOTE: we only support activating books since equipment activation doesn't work for some reason // NOTE: Consumables are usually in stacks > 1, so we ignore those as well for consistency if (TOUCHSCREEN && tap_to_activate_ticks > 0 && !items->items[stack.item].book.empty() && stack.quantity == 1) { activate(position); } } } else { if (inventory[area][slot].item == stack.item || drag_prev_src == -1) { // Merge the stacks success = add(stack, area, slot, false, false); } else if (inventory[area][slot].empty()) { // Drop the stack inventory[area][slot] = stack; } else if( inventory[EQUIPMENT][drag_prev_slot].empty() && inventory[CARRIED][slot].item != stack.item && items->items[inventory[CARRIED][slot].item].type == slot_type[drag_prev_slot] && items->requirementsMet(stats, inventory[CARRIED][slot].item) ) { // The whole equipped stack is dropped on an empty carried slot or on a wearable item // Swap the two stacks itemReturn(inventory[area][slot]); updateEquipment(drag_prev_slot); // if this item has a power, place it on the action bar if possible if (items->items[inventory[EQUIPMENT][drag_prev_slot].item].power > 0) { menu_act->addPower(items->items[inventory[EQUIPMENT][drag_prev_slot].item].power, 0); } inventory[area][slot] = stack; } else { itemReturn(stack); // cancel } } } drag_prev_src = -1; return success; }