/** * 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; }
/** * Return dragged item to previous slot */ void MenuInventory::itemReturn( ItemStack stack) { inventory[drag_prev_src].itemReturn( stack); // if returning equipment, prepare to change stats/sprites if (drag_prev_src == EQUIPMENT) { updateEquipment( inventory[EQUIPMENT].drag_prev_slot); } drag_prev_src = -1; }
void MenuInventory::removeFromPrevSlot(int quantity) { if (drag_prev_src > -1 && inventory[drag_prev_src].drag_prev_slot > -1) { int drag_prev_slot = inventory[drag_prev_src].drag_prev_slot; inventory[drag_prev_src].subtract(drag_prev_slot, quantity); if (inventory[drag_prev_src].storage[drag_prev_slot].empty()) { if (drag_prev_src == EQUIPMENT) updateEquipment(inventory[EQUIPMENT].drag_prev_slot); } } }
/** * 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); } } } }
/** * Return dragged item to previous slot */ void MenuInventory::itemReturn(ItemStack stack) { if (drag_prev_src == -1) { add(stack, CARRIED, -1, false, false); } else { int prev_slot = inventory[drag_prev_src].drag_prev_slot; inventory[drag_prev_src].itemReturn(stack); // if returning equipment, prepare to change stats/sprites if (drag_prev_src == EQUIPMENT) { updateEquipment(prev_slot); } } drag_prev_src = -1; }
/** * Click-start dragging in the inventory */ ItemStack MenuInventory::click(InputState * input) { ItemStack item; item.item = 0; item.quantity = 0; drag_prev_src = areaOver(input->mouse); if( drag_prev_src > -1) { item = inventory[drag_prev_src].click(input); // if dragging equipment, prepare to change stats/sprites if (drag_prev_src == EQUIPMENT) { updateEquipment( inventory[EQUIPMENT].drag_prev_slot); } } return item; }
/** * 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; }
/** * 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 */ bool MenuInventory::add(ItemStack stack, int area, int slot, bool play_sound, bool auto_equip) { if (stack.empty()) return true; bool success = true; if (play_sound) items->playSound(stack.item); if (auto_equip && AUTO_EQUIP) { int equip_slot = getEquipSlotFromItem(stack.item, true); if (equip_slot >= 0 && inventory[EQUIPMENT].slots[equip_slot]->enabled) { area = EQUIPMENT; slot = equip_slot; } } if (area == CARRIED) { ItemStack leftover = inventory[CARRIED].add(stack, slot); if (!leftover.empty()) { pc->logMsg(msg->get("Inventory is full."), true); drop_stack.push(leftover); success = false; } } else if (area == EQUIPMENT) { ItemStack &dest = inventory[EQUIPMENT].storage[slot]; ItemStack leftover; leftover.item = stack.item; if (!dest.empty() && dest.item != stack.item) { // items don't match, so just add the stack to the carried area leftover.quantity = stack.quantity; } else if (dest.quantity + stack.quantity > items->items[stack.item].max_quantity) { // items match, so attempt to merge the stacks. Any leftover will be added to the carried area leftover.quantity = dest.quantity + stack.quantity - items->items[stack.item].max_quantity; stack.quantity = items->items[stack.item].max_quantity - dest.quantity; if (stack.quantity > 0) { add(stack, EQUIPMENT, slot, false, false); } } else { // put the item in the appropriate equipment slot inventory[EQUIPMENT].add(stack, slot); updateEquipment(slot); leftover.clear(); } if (!leftover.empty()) { add(leftover, CARRIED, -1, false, false); } applyEquipment(); } // if this item has a power, place it on the action bar if possible if (success && items->items[stack.item].type == "consumable" && items->items[stack.item].power > 0) { menu_act->addPower(items->items[stack.item].power, 0); } drag_prev_src = -1; 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(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; }