/** * Check to see if the player is picking up loot on the ground */ void GameStatePlay::checkLoot() { if (!pc->stats.alive) return; if (menu->isDragging()) return; ItemStack pickup; // Autopickup if (AUTOPICKUP_CURRENCY) { pickup = loot->checkAutoPickup(pc->stats.pos, menu->inv); if (!pickup.empty()) menu->inv->add(pickup); } // Normal pickups if (!pc->stats.attacking) pickup = loot->checkPickup(inpt->mouse, mapr->cam, pc->stats.pos, menu->inv); if (!pickup.empty()) { menu->inv->add(pickup); camp->setStatus(items->items[pickup.item].pickup_status); } if (loot->full_msg) { if (inpt->pressing[MAIN1]) inpt->lock[MAIN1] = true; if (inpt->pressing[ACCEPT]) inpt->lock[ACCEPT] = true; menu->questlog->add(msg->get("Inventory is full."), LOG_TYPE_MESSAGES); menu->hudlog->add(msg->get("Inventory is full.")); loot->full_msg = false; } }
bool MenuStash::add(ItemStack stack, int slot, bool play_sound) { if (stack.empty()) { return true; } if (play_sound) { items->playSound(stack.item); } if (items->items[stack.item].quest_item) { pc->logMsg(msg->get("Can not store quest items in the stash."), Avatar::MSG_NORMAL); drop_stack.push(stack); return false; } ItemStack leftover = stock.add(stack, slot); if (!leftover.empty()) { if (leftover.quantity != stack.quantity) { updated = true; } pc->logMsg(msg->get("Stash is full."), Avatar::MSG_NORMAL); drop_stack.push(leftover); return false; } else { updated = true; } return true; }
/** * Check to see if the player is picking up loot on the ground */ void GameStatePlay::checkLoot() { if (!pc->stats.alive) return; if (menu->isDragging()) return; ItemStack pickup; // Autopickup if (AUTOPICKUP_CURRENCY) { pickup = loot->checkAutoPickup(pc->stats.pos); if (!pickup.empty()) { menu->inv->add(pickup, CARRIED, -1, true, true); pickup.clear(); } } // Normal pickups if (!pc->stats.attacking) { pickup = loot->checkPickup(inpt->mouse, mapr->cam, pc->stats.pos); } if (!pickup.empty()) { menu->inv->add(pickup, CARRIED, -1, true, true); camp->setStatus(items->items[pickup.item].pickup_status); pickup.clear(); } }
ItemStack MenuItemStorage::click(Point position) { ItemStack item; drag_prev_slot = slotOver(position); // try to click on the highlighted (aka in focus) slot // since mouse clicks defocus slots before this point, // we don't have to worry about the mouse being over another slot if (drag_prev_slot == -1) { for (unsigned int i=0; i<slots.size(); i++) { if (slots[i]->in_focus) { drag_prev_slot = i; break; } } } if (drag_prev_slot > -1) { item = storage[drag_prev_slot]; if (TOUCHSCREEN) { if (!slots[drag_prev_slot]->in_focus && !item.empty()) { slots[drag_prev_slot]->in_focus = true; current_slot = slots[drag_prev_slot]; item.clear(); drag_prev_slot = -1; return item; } else { slots[drag_prev_slot]->in_focus = false; current_slot = NULL; } } if (!item.empty()) { if (item.quantity > 1 && !inpt->pressing[CTRL] && (inpt->pressing[SHIFT] || NO_MOUSE || inpt->touch_locked)) { // we use an external menu to let the player pick the desired quantity // we will subtract from this stack after they've made their decision return item; } subtract( drag_prev_slot, item.quantity); } // item will be cleared if item.empty() == true return item; } else { item.clear(); return item; } }
/** * 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; }
// add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil // pos = {x=num, y=num, z=num} int ModApiEnvMod::l_add_item(lua_State *L) { GET_ENV_PTR; // pos //v3f pos = checkFloatPos(L, 1); // item ItemStack item = read_item(L, 2,getServer(L)); if(item.empty() || !item.isKnown(getServer(L)->idef())) return 0; lua_pushcfunction(L, script_error_handler); int errorhandler = lua_gettop(L); // Use spawn_item to spawn a __builtin:item lua_getglobal(L, "core"); lua_getfield(L, -1, "spawn_item"); lua_remove(L, -2); // Remove core if(lua_isnil(L, -1)) return 0; lua_pushvalue(L, 1); lua_pushstring(L, item.getItemString().c_str()); PCALL_RESL(L, lua_pcall(L, 2, 1, errorhandler)); lua_remove(L, errorhandler); // Remove error handler return 1; }
/** * Sell a specific stack of items */ bool MenuInventory::sell(ItemStack stack) { if (stack.empty()) { return false; } // can't sell currency if (stack.item == CURRENCY_ID) return false; // items that have no price cannot be sold if (items->items[stack.item].getPrice() == 0) { items->playSound(stack.item); pc->logMsg(msg->get("This item can not be sold."), true); return false; } // quest items can not be sold if (items->items[stack.item].quest_item) { items->playSound(stack.item); pc->logMsg(msg->get("This item can not be sold."), true); return false; } int value_each = items->items[stack.item].getSellPrice(); int value = value_each * stack.quantity; addCurrency(value); items->playSound(CURRENCY_ID); drag_prev_src = -1; return true; }
/** * Check if there is enough currency to buy the given stack, and if so remove it from the current total and add the stack. * (Handle the drop into the equipment area, but add() don't handle it well in all circonstances. MenuManager::logic() allow only into the carried area.) */ bool MenuInventory::buy(ItemStack stack, int tab, bool dragging) { if (stack.empty()) { return true; } int value_each; if (tab == VENDOR_BUY) value_each = items->items[stack.item].getPrice(); else value_each = items->items[stack.item].getSellPrice(); int count = value_each * stack.quantity; if( inventory[CARRIED].count(CURRENCY_ID) >= count) { if (dragging) { drop(inpt->mouse, stack); } else { add(stack, CARRIED, -1, true, true); } removeCurrency(count); items->playSound(CURRENCY_ID); return true; } else { pc->logMsg(msg->get("Not enough %s.", CURRENCY), true); drop_stack.push(stack); return false; } }
// minetest.add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil // pos = {x=num, y=num, z=num} int ModApiEnvMod::l_add_item(lua_State *L) { GET_ENV_PTR; // pos //v3f pos = checkFloatPos(L, 1); // item ItemStack item = read_item(L, 2,getServer(L)); if(item.empty() || !item.isKnown(getServer(L)->idef())) return 0; // Use minetest.spawn_item to spawn a __builtin:item lua_getglobal(L, "minetest"); lua_getfield(L, -1, "spawn_item"); if(lua_isnil(L, -1)) return 0; lua_pushvalue(L, 1); lua_pushstring(L, item.getItemString().c_str()); if(lua_pcall(L, 2, 1, 0)) script_error(L, "error: %s", lua_tostring(L, -1)); return 1; /*lua_pushvalue(L, 1); lua_pushstring(L, "__builtin:item"); lua_pushstring(L, item.getItemString().c_str()); return l_add_entity(L);*/ /*// Do it ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString()); int objectid = env->addActiveObject(obj); // If failed to add, return nothing (reads as nil) if(objectid == 0) return 0; // Return ObjectRef objectrefGetOrCreate(L, obj); return 1;*/ }
int punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, float time_from_last_punch) { // Take item into inventory ItemStack item = createItemStack(); Inventory *inv = puncher->getInventory(); if(inv != NULL) { std::string wieldlist = puncher->getWieldList(); ItemStack leftover = inv->addItem(wieldlist, item); puncher->setInventoryModified(); if(leftover.empty()) { m_removed = true; } else { m_itemstring = leftover.getItemString(); m_itemstring_changed = true; } } return 0; }
ItemStack MenuItemStorage::click(Point position) { ItemStack item; drag_prev_slot = slotOver(position); // try to click on the highlighted (aka in focus) slot // since mouse clicks defocus slots before this point, // we don't have to worry about the mouse being over another slot if (drag_prev_slot == -1) { for (unsigned int i=0; i<slots.size(); i++) { if (slots[i]->in_focus) { drag_prev_slot = i; break; } } } if (drag_prev_slot > -1) { item = storage[drag_prev_slot]; if (TOUCHSCREEN) { if (!slots[drag_prev_slot]->in_focus && !item.empty()) { slots[drag_prev_slot]->in_focus = true; current_slot = slots[drag_prev_slot]; item.clear(); return item; } else { slots[drag_prev_slot]->in_focus = false; current_slot = NULL; } } if (!item.empty()) { if (inpt->pressing[SHIFT] || NO_MOUSE || inpt->touch_locked) { item.quantity = 1; } substract( drag_prev_slot, item.quantity); } // item will be cleared if item.empty() == true return item; } else { item.clear(); return item; } }
bool MenuStash::add(ItemStack stack, int slot, bool play_sound) { if (stack.empty()) { return true; } if (play_sound) { items->playSound(stack.item); } if (items->items[stack.item].quest_item) { pc->logMsg(msg->get("Can not store quest items in the stash."), Avatar::MSG_NORMAL); drop_stack.push(stack); return false; } else if (items->items[stack.item].no_stash == Item::NO_STASH_ALL) { pc->logMsg(msg->get("This item can not be stored in the stash."), Avatar::MSG_NORMAL); drop_stack.push(stack); return false; } else if (activetab == STASH_PRIVATE && items->items[stack.item].no_stash == Item::NO_STASH_PRIVATE) { pc->logMsg(msg->get("This item can not be stored in the private stash."), Avatar::MSG_NORMAL); drop_stack.push(stack); return false; } else if (activetab == STASH_SHARED && items->items[stack.item].no_stash == Item::NO_STASH_SHARED) { pc->logMsg(msg->get("This item can not be stored in the shared stash."), Avatar::MSG_NORMAL); drop_stack.push(stack); return false; } ItemStack leftover = stock[activetab].add(stack, slot); if (!leftover.empty()) { if (leftover.quantity != stack.quantity) { updated = true; } pc->logMsg(msg->get("Stash is full."), Avatar::MSG_NORMAL); drop_stack.push(leftover); return false; } else { updated = true; } return true; }
/** * 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, bool play_sound) { if (stack.empty()) return; if (play_sound) items->playSound(stack.item); if (!stack.empty()) { if (area < 0) { area = CARRIED; } if (area == CARRIED) { ItemStack leftover = inventory[CARRIED].add(stack, slot); if (!leftover.empty()) { drop_stack.push(leftover); } } else if (area == EQUIPMENT) { ItemStack &dest = inventory[EQUIPMENT].storage[slot]; ItemStack leftover; leftover.item = stack.item; if (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; add(stack, EQUIPMENT, slot, false); } if (!leftover.empty()) { add(leftover, CARRIED, -1, false); } } // if this item has a power, place it on the action bar if possible if (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; }
/** * Insert item into first available carried slot, preferably in the optionnal specified slot * Returns an ItemStack containing anything that couldn't fit * * @param ItemStack Stack of items * @param slot Slot number where it will try to store the item */ ItemStack ItemStorage::add( ItemStack stack, int slot) { if (!stack.empty()) { if (items->items.empty() || stack.item <= 0 || static_cast<unsigned>(stack.item) > items->items.size()-1) { items->addUnknownItem(stack.item); } int max_quantity = items->items[stack.item].max_quantity; if (slot > -1) { // a slot is specified if (storage[slot].item != 0 && storage[slot].item != stack.item) { // the proposed slot isn't available slot = -1; } } else { // first search of stack to complete if the item is stackable int i = 0; while (max_quantity > 1 && slot == -1 && i < slot_number) { if (storage[i].item == stack.item && storage[i].quantity < max_quantity) { slot = i; } i++; } // then an empty slot i = 0; while (slot == -1 && i < slot_number) { if (storage[i].empty()) { slot = i; } i++; } } if (slot != -1) { // Add int quantity_added = std::min( stack.quantity, max_quantity - storage[slot].quantity); storage[slot].item = stack.item; storage[slot].quantity += quantity_added; stack.quantity -= quantity_added; // Add back the remaining, recursivly, until there's no more left to add or we run out of space. if (stack.quantity > 0) { return add(stack); } // everything added successfully, so return an empty ItemStack return ItemStack(); } else { // Returns an ItemStack containing the remaining quantity if we run out of space. // This stack will likely be dropped on the ground return stack; } } return ItemStack(); }
TooltipData ItemManager::getShortTooltip(ItemStack stack) { std::stringstream ss; TooltipData tip; if (stack.empty()) return tip; // name if (stack.quantity > 1) { ss << stack.quantity << " " << getItemName(stack.item); } else { ss << getItemName(stack.item); } tip.addColoredText(ss.str(), getItemColor(stack.item)); return tip; }
// remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack // Returns the items that were actually removed int InvRef::l_remove_item(lua_State *L) { NO_MAP_LOCK_REQUIRED; InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); ItemStack item = read_item(L, 3, getServer(L)->idef()); InventoryList *list = getlist(L, ref, listname); if(list){ ItemStack removed = list->removeItem(item); if(!removed.empty()) reportInventoryChange(L, ref); LuaItemStack::create(L, removed); } else { LuaItemStack::create(L, ItemStack()); } return 1; }
bool ItemStorage::full(ItemStack stack) { if (stack.empty()) return false; for (int i=0; i<slot_number; i++) { if (storage[i].item == stack.item && storage[i].quantity < items->items[stack.item].max_quantity) { if (stack.quantity + storage[i].quantity >= items->items[stack.item].max_quantity) { stack.quantity -= storage[i].quantity; continue; } return false; } if (storage[i].empty()) { return false; } } return true; }
bool CraftDefinitionToolRepair::check(const CraftInput &input, IGameDef *gamedef) const { if (input.method != CRAFT_METHOD_NORMAL) return false; ItemStack item1; ItemStack item2; for (const auto &item : input.items) { if (!item.empty()) { if (item1.empty()) item1 = item; else if (item2.empty()) item2 = item; else return false; } } ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef); return !repaired.empty(); }
void CampaignManager::rewardItem(ItemStack istack) { if (istack.empty()) return; if (menu->inv->inventory[CARRIED].full(istack.item)) { drop_stack.push(istack); } else { menu->inv->add(istack, -1, -1, false); if (istack.item != CURRENCY_ID) { if (istack.quantity <= 1) addMsg(msg->get("You receive %s.", items->getItemName(istack.item))); if (istack.quantity > 1) addMsg(msg->get("You receive %s x%d.", istack.quantity, items->getItemName(istack.item))); items->playSound(istack.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; }
bool CraftDefinitionToolRepair::check(const CraftInput &input, IGameDef *gamedef) const { if (input.method != CRAFT_METHOD_NORMAL) return false; ItemStack item1; ItemStack item2; for (std::vector<ItemStack>::const_iterator it = input.items.begin(); it != input.items.end(); it++) { if (!it->empty()) { if (item1.empty()) item1 = *it; else if (item2.empty()) item2 = *it; else return false; } } ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef); return !repaired.empty(); }
/** * Create detailed tooltip showing all relevant item info */ TooltipData ItemManager::getTooltip(ItemStack stack, StatBlock *stats, int context) { TooltipData tip; if (stack.empty()) return tip; Color color = getItemColor(stack.item); // name std::stringstream ss; if (stack.quantity == 1) ss << getItemName(stack.item); else ss << getItemName(stack.item) << " (" << stack.quantity << ")"; tip.addText(ss.str(), color); // quest item if (items[stack.item].quest_item) { tip.addText(msg->get("Quest Item"), color_bonus); } // only show the name of the currency item if (stack.item == CURRENCY_ID) return tip; // flavor text if (items[stack.item].flavor != "") { tip.addText(substituteVarsInString(items[stack.item].flavor, pc), color_flavor); } // level if (items[stack.item].level != 0) { tip.addText(msg->get("Level %d", items[stack.item].level)); } // type if (items[stack.item].type != "") { tip.addText(msg->get(getItemType(items[stack.item].type))); } // item quality text for colorblind users if (COLORBLIND && items[stack.item].quality != "") { color = color_normal; for (size_t i=0; i<item_qualities.size(); ++i) { if (item_qualities[i].id == items[stack.item].quality) { tip.addText(msg->get("Quality: %s", msg->get(item_qualities[i].name)), color); break; } } } // damage if (items[stack.item].dmg_melee_max > 0) { if (items[stack.item].dmg_melee_min < items[stack.item].dmg_melee_max) tip.addText(msg->get("Melee damage: %d-%d", items[stack.item].dmg_melee_min, items[stack.item].dmg_melee_max)); else tip.addText(msg->get("Melee damage: %d", items[stack.item].dmg_melee_max)); } if (items[stack.item].dmg_ranged_max > 0) { if (items[stack.item].dmg_ranged_min < items[stack.item].dmg_ranged_max) tip.addText(msg->get("Ranged damage: %d-%d", items[stack.item].dmg_ranged_min, items[stack.item].dmg_ranged_max)); else tip.addText(msg->get("Ranged damage: %d", items[stack.item].dmg_ranged_max)); } if (items[stack.item].dmg_ment_max > 0) { if (items[stack.item].dmg_ment_min < items[stack.item].dmg_ment_max) tip.addText(msg->get("Mental damage: %d-%d", items[stack.item].dmg_ment_min, items[stack.item].dmg_ment_max)); else tip.addText(msg->get("Mental damage: %d", items[stack.item].dmg_ment_max)); } // absorb if (items[stack.item].abs_max > 0) { if (items[stack.item].abs_min < items[stack.item].abs_max) tip.addText(msg->get("Absorb: %d-%d", items[stack.item].abs_min, items[stack.item].abs_max)); else tip.addText(msg->get("Absorb: %d", items[stack.item].abs_max)); } // bonuses unsigned bonus_counter = 0; while (bonus_counter < items[stack.item].bonus.size()) { ss.str(""); BonusData* bdata = &items[stack.item].bonus[bonus_counter]; if (bdata->is_speed) { ss << msg->get("%d%% Speed", bdata->value); if (bdata->value >= 100) color = color_bonus; else color = color_penalty; } else { if (bdata->value > 0) { color = color_bonus; } else { color = color_penalty; } getBonusString(ss, bdata); } tip.addText(ss.str(), color); bonus_counter++; } // power if (items[stack.item].power_desc != "") { tip.addText(items[stack.item].power_desc, color_bonus); } // level requirement if (items[stack.item].requires_level > 0) { if (stats->level < items[stack.item].requires_level) color = color_requirements_not_met; else color = color_normal; tip.addText(msg->get("Requires Level %d", items[stack.item].requires_level), color); } // base stat requirement for (unsigned i=0; i<items[stack.item].req_stat.size(); ++i) { if (items[stack.item].req_val[i] > 0) { if (items[stack.item].req_stat[i] == REQUIRES_PHYS) { if (stats->get_physical() < items[stack.item].req_val[i]) color = color_requirements_not_met; else color = color_normal; tip.addText(msg->get("Requires Physical %d", items[stack.item].req_val[i]), color); } else if (items[stack.item].req_stat[i] == REQUIRES_MENT) { if (stats->get_mental() < items[stack.item].req_val[i]) color = color_requirements_not_met; else color = color_normal; tip.addText(msg->get("Requires Mental %d", items[stack.item].req_val[i]), color); } else if (items[stack.item].req_stat[i] == REQUIRES_OFF) { if (stats->get_offense() < items[stack.item].req_val[i]) color = color_requirements_not_met; else color = color_normal; tip.addText(msg->get("Requires Offense %d", items[stack.item].req_val[i]), color); } else if (items[stack.item].req_stat[i] == REQUIRES_DEF) { if (stats->get_defense() < items[stack.item].req_val[i]) color = color_requirements_not_met; else color = color_normal; tip.addText(msg->get("Requires Defense %d", items[stack.item].req_val[i]), color); } } } // requires class if (items[stack.item].requires_class != "") { if (items[stack.item].requires_class != stats->character_class) color = color_requirements_not_met; else color = color_normal; tip.addText(msg->get("Requires Class: %s", msg->get(items[stack.item].requires_class)), color); } // buy or sell price if (items[stack.item].getPrice() > 0 && stack.item != CURRENCY_ID) { int price_per_unit; if (context == VENDOR_BUY) { price_per_unit = items[stack.item].getPrice(); if (stats->currency < price_per_unit) color = color_requirements_not_met; else color = color_normal; if (items[stack.item].max_quantity <= 1) tip.addText(msg->get("Buy Price: %d %s", price_per_unit, CURRENCY), color); else tip.addText(msg->get("Buy Price: %d %s each", price_per_unit, CURRENCY), color); } else if (context == VENDOR_SELL) { price_per_unit = items[stack.item].getSellPrice(); if (stats->currency < price_per_unit) color = color_requirements_not_met; else color = color_normal; if (items[stack.item].max_quantity <= 1) tip.addText(msg->get("Buy Price: %d %s", price_per_unit, CURRENCY), color); else tip.addText(msg->get("Buy Price: %d %s each", price_per_unit, CURRENCY), color); } else if (context == PLAYER_INV) { price_per_unit = items[stack.item].getSellPrice(); if (price_per_unit == 0) price_per_unit = 1; if (items[stack.item].max_quantity <= 1) tip.addText(msg->get("Sell Price: %d %s", price_per_unit, CURRENCY)); else tip.addText(msg->get("Sell Price: %d %s each", price_per_unit, CURRENCY)); } } if (items[stack.item].set > 0) { // item set bonuses ItemSet set = item_sets[items[stack.item].set]; bonus_counter = 0; tip.addText("\n" + msg->get("Set: ") + msg->get(item_sets[items[stack.item].set].name), set.color); while (bonus_counter < set.bonus.size()) { ss.str(""); Set_bonus* bdata = &set.bonus[bonus_counter]; ss << msg->get("%d items: ", bdata->requirement); if (bdata->is_speed) { ss << msg->get("%d%% Speed", bdata->value); } else { getBonusString(ss, bdata); } tip.addText(ss.str(), set.color); bonus_counter++; } } return tip; }
void GUIFormSpecMenu::updateSelectedItem() { // WARNING: BLACK MAGIC // See if there is a stack suited for our current guess. // If such stack does not exist, clear the guess. if(m_selected_content_guess.name != "") { bool found = false; for(u32 i=0; i<m_inventorylists.size() && !found; i++){ const ListDrawSpec &s = m_inventorylists[i]; Inventory *inv = m_invmgr->getInventory(s.inventoryloc); if(!inv) continue; InventoryList *list = inv->getList(s.listname); if(!list) continue; for(s32 i=0; i<s.geom.X*s.geom.Y && !found; i++){ u32 item_i = i + s.start_item_i; if(item_i >= list->getSize()) continue; ItemStack stack = list->getItem(item_i); if(stack.name == m_selected_content_guess.name && stack.count == m_selected_content_guess.count){ found = true; if(m_selected_item){ // If guessed stack is already selected, all is fine if(m_selected_item->inventoryloc == s.inventoryloc && m_selected_item->listname == s.listname && m_selected_item->i == (s32)item_i && m_selected_amount == stack.count){ break; } delete m_selected_item; m_selected_item = NULL; } infostream<<"Client: Changing selected content guess to " <<s.inventoryloc.dump()<<" "<<s.listname <<" "<<item_i<<std::endl; m_selected_item = new ItemSpec(s.inventoryloc, s.listname, item_i); m_selected_amount = stack.count; break; } } } if(!found){ infostream<<"Client: Discarding selected content guess: " <<m_selected_content_guess.getItemString()<<std::endl; m_selected_content_guess.name = ""; } } // If the selected stack has become empty for some reason, deselect it. // If the selected stack has become smaller, adjust m_selected_amount. if(m_selected_item) { bool selection_valid = false; if(m_selected_item->isValid()) { Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc); if(inv) { InventoryList *list = inv->getList(m_selected_item->listname); if(list && (u32) m_selected_item->i < list->getSize()) { ItemStack stack = list->getItem(m_selected_item->i); if(m_selected_amount > stack.count) m_selected_amount = stack.count; if(!stack.empty()) selection_valid = true; } } } if(!selection_valid) { delete m_selected_item; m_selected_item = NULL; m_selected_amount = 0; m_selected_dragging = false; } } // If craftresult is nonempty and nothing else is selected, select it now. if(!m_selected_item) { for(u32 i=0; i<m_inventorylists.size(); i++) { const ListDrawSpec &s = m_inventorylists[i]; if(s.listname == "craftpreview") { Inventory *inv = m_invmgr->getInventory(s.inventoryloc); InventoryList *list = inv->getList("craftresult"); if(list && list->getSize() >= 1 && !list->getItem(0).empty()) { m_selected_item = new ItemSpec; m_selected_item->inventoryloc = s.inventoryloc; m_selected_item->listname = "craftresult"; m_selected_item->i = 0; m_selected_amount = 0; m_selected_dragging = false; break; } } } } // If craftresult is selected, keep the whole stack selected if(m_selected_item && m_selected_item->listname == "craftresult") { Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc); assert(inv); InventoryList *list = inv->getList(m_selected_item->listname); assert(list); m_selected_amount = list->getItem(m_selected_item->i).count; } }
void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef) { Inventory *inv_craft = mgr->getInventory(craft_inv); if (!inv_craft) { infostream << "ICraftAction::apply(): FAIL: inventory not found: " << "craft_inv=\"" << craft_inv.dump() << "\"" << std::endl; return; } InventoryList *list_craft = inv_craft->getList("craft"); InventoryList *list_craftresult = inv_craft->getList("craftresult"); InventoryList *list_main = inv_craft->getList("main"); /* If a list doesn't exist or the source item doesn't exist */ if (!list_craft) { infostream << "ICraftAction::apply(): FAIL: craft list not found: " << "craft_inv=\"" << craft_inv.dump() << "\"" << std::endl; return; } if (!list_craftresult) { infostream << "ICraftAction::apply(): FAIL: craftresult list not found: " << "craft_inv=\"" << craft_inv.dump() << "\"" << std::endl; return; } if (list_craftresult->getSize() < 1) { infostream << "ICraftAction::apply(): FAIL: craftresult list too short: " << "craft_inv=\"" << craft_inv.dump() << "\"" << std::endl; return; } ItemStack crafted; ItemStack craftresultitem; int count_remaining = count; std::vector<ItemStack> output_replacements; getCraftingResult(inv_craft, crafted, output_replacements, false, gamedef); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv); bool found = !crafted.empty(); while (found && list_craftresult->itemFits(0, crafted)) { InventoryList saved_craft_list = *list_craft; std::vector<ItemStack> temp; // Decrement input and add crafting output getCraftingResult(inv_craft, crafted, temp, true, gamedef); PLAYER_TO_SA(player)->item_OnCraft(crafted, player, &saved_craft_list, craft_inv); list_craftresult->addItem(0, crafted); mgr->setInventoryModified(craft_inv); // Add the new replacements to the list IItemDefManager *itemdef = gamedef->getItemDefManager(); for (std::vector<ItemStack>::iterator it = temp.begin(); it != temp.end(); it++) { for (std::vector<ItemStack>::iterator jt = output_replacements.begin(); jt != output_replacements.end(); jt++) { if (it->name == jt->name) { *it = jt->addItem(*it, itemdef); if (it->empty()) continue; } } output_replacements.push_back(*it); } actionstream << player->getDescription() << " crafts " << crafted.getItemString() << std::endl; // Decrement counter if (count_remaining == 1) break; else if (count_remaining > 1) count_remaining--; // Get next crafting result found = getCraftingResult(inv_craft, crafted, temp, false, gamedef); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv); found = !crafted.empty(); } // Put the replacements in the inventory or drop them on the floor, if // the invenotry is full for (std::vector<ItemStack>::iterator it = output_replacements.begin(); it != output_replacements.end(); it++) { if (list_main) *it = list_main->addItem(*it); if (it->empty()) continue; u16 count = it->count; do { PLAYER_TO_SA(player)->item_OnDrop(*it, player, player->getBasePosition() + v3f(0,1,0)); if (count >= it->count) { errorstream << "Couldn't drop replacement stack " << it->getItemString() << " because drop loop didn't " "decrease count." << std::endl; break; } } while (!it->empty()); } infostream<<"ICraftAction::apply(): crafted " <<" craft_inv=\""<<craft_inv.dump()<<"\"" <<std::endl; }
bool GUIFormSpecMenu::OnEvent(const SEvent& event) { if(event.EventType==EET_KEY_INPUT_EVENT) { KeyPress kp(event.KeyInput); if (event.KeyInput.PressedDown && (kp == EscapeKey || kp == getKeySetting("keymap_inventory"))) { quitMenu(); return true; } if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown) { acceptInput(); quitMenu(); return true; } } if(event.EventType==EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_MOUSE_MOVED) { // Mouse moved m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y); } if(event.EventType==EET_MOUSE_INPUT_EVENT && event.MouseInput.Event != EMIE_MOUSE_MOVED) { // Mouse event other than movement v2s32 p(event.MouseInput.X, event.MouseInput.Y); m_pointer = p; // Get selected item and hovered/clicked item (s) updateSelectedItem(); ItemSpec s = getItemAtPos(p); Inventory *inv_selected = NULL; Inventory *inv_s = NULL; if(m_selected_item) { inv_selected = m_invmgr->getInventory(m_selected_item->inventoryloc); assert(inv_selected); assert(inv_selected->getList(m_selected_item->listname) != NULL); } u32 s_count = 0; if(s.isValid()) do{ // breakable inv_s = m_invmgr->getInventory(s.inventoryloc); if(!inv_s){ errorstream<<"InventoryMenu: The selected inventory location " <<"\""<<s.inventoryloc.dump()<<"\" doesn't exist" <<std::endl; s.i = -1; // make it invalid again break; } InventoryList *list = inv_s->getList(s.listname); if(list == NULL){ verbosestream<<"InventoryMenu: The selected inventory list \"" <<s.listname<<"\" does not exist"<<std::endl; s.i = -1; // make it invalid again break; } if((u32)s.i >= list->getSize()){ infostream<<"InventoryMenu: The selected inventory list \"" <<s.listname<<"\" is too small (i="<<s.i<<", size=" <<list->getSize()<<")"<<std::endl; s.i = -1; // make it invalid again break; } s_count = list->getItem(s.i).count; }while(0); bool identical = (m_selected_item != NULL) && s.isValid() && (inv_selected == inv_s) && (m_selected_item->listname == s.listname) && (m_selected_item->i == s.i); // buttons: 0 = left, 1 = right, 2 = middle // up/down: 0 = down (press), 1 = up (release), 2 = unknown event int button = 0; int updown = 2; if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { button = 0; updown = 0; } else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) { button = 1; updown = 0; } else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN) { button = 2; updown = 0; } else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) { button = 0; updown = 1; } else if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) { button = 1; updown = 1; } else if(event.MouseInput.Event == EMIE_MMOUSE_LEFT_UP) { button = 2; updown = 1; } // Set this number to a positive value to generate a move action // from m_selected_item to s. u32 move_amount = 0; // Set this number to a positive value to generate a drop action // from m_selected_item. u32 drop_amount = 0; // Set this number to a positive value to generate a craft action at s. u32 craft_amount = 0; if(updown == 0) { // Some mouse button has been pressed //infostream<<"Mouse button "<<button<<" pressed at p=(" // <<p.X<<","<<p.Y<<")"<<std::endl; m_selected_dragging = false; if(s.isValid() && s.listname == "craftpreview") { // Craft preview has been clicked: craft craft_amount = (button == 2 ? 10 : 1); } else if(m_selected_item == NULL) { if(s_count != 0) { // Non-empty stack has been clicked: select it m_selected_item = new ItemSpec(s); if(button == 1) // right m_selected_amount = (s_count + 1) / 2; else if(button == 2) // middle m_selected_amount = MYMIN(s_count, 10); else // left m_selected_amount = s_count; m_selected_dragging = true; } } else // m_selected_item != NULL { assert(m_selected_amount >= 1); if(s.isValid()) { // Clicked a slot: move if(button == 1) // right move_amount = 1; else if(button == 2) // middle move_amount = MYMIN(m_selected_amount, 10); else // left move_amount = m_selected_amount; if(identical) { if(move_amount >= m_selected_amount) m_selected_amount = 0; else m_selected_amount -= move_amount; move_amount = 0; } } else if(getAbsoluteClippingRect().isPointInside(m_pointer)) { // Clicked somewhere else: deselect m_selected_amount = 0; } else { // Clicked outside of the window: drop if(button == 1) // right drop_amount = 1; else if(button == 2) // middle drop_amount = MYMIN(m_selected_amount, 10); else // left drop_amount = m_selected_amount; } } } else if(updown == 1) { // Some mouse button has been released //infostream<<"Mouse button "<<button<<" released at p=(" // <<p.X<<","<<p.Y<<")"<<std::endl; if(m_selected_item != NULL && m_selected_dragging && s.isValid()) { if(!identical) { // Dragged to different slot: move all selected move_amount = m_selected_amount; } } else if(m_selected_item != NULL && m_selected_dragging && !(getAbsoluteClippingRect().isPointInside(m_pointer))) { // Dragged outside of window: drop all selected drop_amount = m_selected_amount; } m_selected_dragging = false; } // Possibly send inventory action to server if(move_amount > 0) { // Send IACTION_MOVE assert(m_selected_item && m_selected_item->isValid()); assert(s.isValid()); assert(inv_selected && inv_s); InventoryList *list_from = inv_selected->getList(m_selected_item->listname); InventoryList *list_to = inv_s->getList(s.listname); assert(list_from && list_to); ItemStack stack_from = list_from->getItem(m_selected_item->i); ItemStack stack_to = list_to->getItem(s.i); // Check how many items can be moved move_amount = stack_from.count = MYMIN(move_amount, stack_from.count); ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef()); // If source stack cannot be added to destination stack at all, // they are swapped if(leftover.count == stack_from.count && leftover.name == stack_from.name) { m_selected_amount = stack_to.count; // In case the server doesn't directly swap them but instead // moves stack_to somewhere else, set this m_selected_content_guess = stack_to; m_selected_content_guess_inventory = s.inventoryloc; } // Source stack goes fully into destination stack else if(leftover.empty()) { m_selected_amount -= move_amount; m_selected_content_guess = ItemStack(); // Clear } // Source stack goes partly into destination stack else { move_amount -= leftover.count; m_selected_amount -= move_amount; m_selected_content_guess = ItemStack(); // Clear } infostream<<"Handing IACTION_MOVE to manager"<<std::endl; IMoveAction *a = new IMoveAction(); a->count = move_amount; a->from_inv = m_selected_item->inventoryloc; a->from_list = m_selected_item->listname; a->from_i = m_selected_item->i; a->to_inv = s.inventoryloc; a->to_list = s.listname; a->to_i = s.i; m_invmgr->inventoryAction(a); } else if(drop_amount > 0) { m_selected_content_guess = ItemStack(); // Clear // Send IACTION_DROP assert(m_selected_item && m_selected_item->isValid()); assert(inv_selected); InventoryList *list_from = inv_selected->getList(m_selected_item->listname); assert(list_from); ItemStack stack_from = list_from->getItem(m_selected_item->i); // Check how many items can be dropped drop_amount = stack_from.count = MYMIN(drop_amount, stack_from.count); assert(drop_amount > 0 && drop_amount <= m_selected_amount); m_selected_amount -= drop_amount; infostream<<"Handing IACTION_DROP to manager"<<std::endl; IDropAction *a = new IDropAction(); a->count = drop_amount; a->from_inv = m_selected_item->inventoryloc; a->from_list = m_selected_item->listname; a->from_i = m_selected_item->i; m_invmgr->inventoryAction(a); } else if(craft_amount > 0) { m_selected_content_guess = ItemStack(); // Clear // Send IACTION_CRAFT assert(s.isValid()); assert(inv_s); infostream<<"Handing IACTION_CRAFT to manager"<<std::endl; ICraftAction *a = new ICraftAction(); a->count = craft_amount; a->craft_inv = s.inventoryloc; m_invmgr->inventoryAction(a); } // If m_selected_amount has been decreased to zero, deselect if(m_selected_amount == 0) { delete m_selected_item; m_selected_item = NULL; m_selected_amount = 0; m_selected_dragging = false; m_selected_content_guess = ItemStack(); } } if(event.EventType==EET_GUI_EVENT) { if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST && isVisible()) { if(!canTakeFocus(event.GUIEvent.Element)) { infostream<<"GUIFormSpecMenu: Not allowing focus change." <<std::endl; // Returning true disables focus change return true; } } if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED) { switch(event.GUIEvent.Caller->getID()) { case 257: acceptInput(); quitMenu(); // quitMenu deallocates menu return true; } // find the element that was clicked for(u32 i=0; i<m_fields.size(); i++) { FieldSpec &s = m_fields[i]; // if its a button, set the send field so // lua knows which button was pressed if (s.is_button && s.fid == event.GUIEvent.Caller->getID()) { s.send = true; acceptInput(); if(s.is_exit){ quitMenu(); return true; }else{ s.send = false; // Restore focus to the full form Environment->setFocus(this); return true; } } } } if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER) { if(event.GUIEvent.Caller->getID() > 257) { acceptInput(); quitMenu(); // quitMenu deallocates menu return true; } } } return Parent ? Parent->OnEvent(event) : false; }
void drawItemStack(video::IVideoDriver *driver, gui::IGUIFont *font, const ItemStack &item, const core::rect<s32> &rect, const core::rect<s32> *clip, IGameDef *gamedef) { if(item.empty()) return; const ItemDefinition &def = item.getDefinition(gamedef->idef()); video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef); // Draw the inventory texture if(texture != NULL) { const video::SColor color(255,255,255,255); const video::SColor colors[] = {color,color,color,color}; driver->draw2DImage(texture, rect, core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(texture->getOriginalSize())), clip, colors, true); } if(def.type == ITEM_TOOL && item.wear != 0) { // Draw a progressbar float barheight = rect.getHeight()/16; float barpad_x = rect.getWidth()/16; float barpad_y = rect.getHeight()/16; core::rect<s32> progressrect( rect.UpperLeftCorner.X + barpad_x, rect.LowerRightCorner.Y - barpad_y - barheight, rect.LowerRightCorner.X - barpad_x, rect.LowerRightCorner.Y - barpad_y); // Shrink progressrect by amount of tool damage float wear = item.wear / 65535.0; int progressmid = wear * progressrect.UpperLeftCorner.X + (1-wear) * progressrect.LowerRightCorner.X; // Compute progressbar color // wear = 0.0: green // wear = 0.5: yellow // wear = 1.0: red video::SColor color(255,255,255,255); int wear_i = MYMIN(floor(wear * 600), 511); wear_i = MYMIN(wear_i + 10, 511); if(wear_i <= 255) color.set(255, wear_i, 255, 0); else color.set(255, 255, 511-wear_i, 0); core::rect<s32> progressrect2 = progressrect; progressrect2.LowerRightCorner.X = progressmid; driver->draw2DRectangle(color, progressrect2, clip); color = video::SColor(255,0,0,0); progressrect2 = progressrect; progressrect2.UpperLeftCorner.X = progressmid; driver->draw2DRectangle(color, progressrect2, clip); } if(font != NULL && item.count >= 2) { // Get the item count as a string std::string text = itos(item.count); v2u32 dim = font->getDimension(narrow_to_wide(text).c_str()); v2s32 sdim(dim.X,dim.Y); core::rect<s32> rect2( /*rect.UpperLeftCorner, core::dimension2d<u32>(rect.getWidth(), 15)*/ rect.LowerRightCorner - sdim, sdim ); video::SColor bgcolor(128,0,0,0); driver->draw2DRectangle(bgcolor, rect2, clip); video::SColor color(255,255,255,255); font->draw(text.c_str(), rect2, color, false, false, clip); } }
/** * 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; }
/** * Create detailed tooltip showing all relevant item info */ TooltipData ItemManager::getTooltip(ItemStack stack, StatBlock *stats, int context) { TooltipData tip; if (stack.empty()) return tip; Color color = getItemColor(stack.item); // name std::stringstream ss; if (stack.quantity == 1) ss << getItemName(stack.item); else ss << getItemName(stack.item) << " (" << stack.quantity << ")"; tip.addColoredText(ss.str(), color); // quest item if (items[stack.item].quest_item) { tip.addColoredText(msg->get("Quest Item"), font->getColor(FontEngine::COLOR_ITEM_BONUS)); } // only show the name of the currency item if (stack.item == eset->misc.currency_id) return tip; // flavor text if (items[stack.item].flavor != "") { tip.addColoredText(Utils::substituteVarsInString(items[stack.item].flavor, pc), font->getColor(FontEngine::COLOR_ITEM_FLAVOR)); } // level if (items[stack.item].level != 0) { tip.addText(msg->get("Level %d", items[stack.item].level)); } // type if (items[stack.item].type != "") { tip.addText(msg->get(getItemType(items[stack.item].type))); } // item quality text for colorblind users if (settings->colorblind && items[stack.item].quality != "") { color = font->getColor(FontEngine::COLOR_WIDGET_NORMAL); for (size_t i=0; i<item_qualities.size(); ++i) { if (item_qualities[i].id == items[stack.item].quality) { tip.addColoredText(msg->get("Quality: %s", msg->get(item_qualities[i].name)), color); break; } } } // damage for (size_t i = 0; i < eset->damage_types.list.size(); ++i) { if (items[stack.item].dmg_max[i] > 0) { std::stringstream dmg_str; dmg_str << eset->damage_types.list[i].name; if (items[stack.item].dmg_min[i] < items[stack.item].dmg_max[i]) { dmg_str << ": " << items[stack.item].dmg_min[i] << "-" << items[stack.item].dmg_max[i]; tip.addText(dmg_str.str()); } else { dmg_str << ": " << items[stack.item].dmg_max[i]; tip.addText(dmg_str.str()); } } } // absorb if (items[stack.item].abs_max > 0) { if (items[stack.item].abs_min < items[stack.item].abs_max) tip.addText(msg->get("Absorb: %d-%d", items[stack.item].abs_min, items[stack.item].abs_max)); else tip.addText(msg->get("Absorb: %d", items[stack.item].abs_max)); } // bonuses unsigned bonus_counter = 0; while (bonus_counter < items[stack.item].bonus.size()) { ss.str(""); BonusData* bdata = &items[stack.item].bonus[bonus_counter]; if (bdata->is_speed || bdata->is_attack_speed) { if (bdata->value >= 100) color = font->getColor(FontEngine::COLOR_ITEM_BONUS); else color = font->getColor(FontEngine::COLOR_ITEM_PENALTY); } else { if (bdata->value > 0) color = font->getColor(FontEngine::COLOR_ITEM_BONUS); else color = font->getColor(FontEngine::COLOR_ITEM_PENALTY); } getBonusString(ss, bdata); tip.addColoredText(ss.str(), color); bonus_counter++; } // power if (items[stack.item].power_desc != "") { tip.addColoredText(items[stack.item].power_desc, font->getColor(FontEngine::COLOR_ITEM_BONUS)); } // level requirement if (items[stack.item].requires_level > 0) { if (stats->level < items[stack.item].requires_level) color = font->getColor(FontEngine::COLOR_REQUIREMENTS_NOT_MET); else color = font->getColor(FontEngine::COLOR_WIDGET_NORMAL); tip.addColoredText(msg->get("Requires Level %d", items[stack.item].requires_level), color); } // base stat requirement for (unsigned i=0; i<items[stack.item].req_stat.size(); ++i) { if (items[stack.item].req_val[i] > 0) { if (stats->get_primary(items[stack.item].req_stat[i]) < items[stack.item].req_val[i]) color = font->getColor(FontEngine::COLOR_REQUIREMENTS_NOT_MET); else color = font->getColor(FontEngine::COLOR_WIDGET_NORMAL); tip.addColoredText(msg->get("Requires %s %d", eset->primary_stats.list[items[stack.item].req_stat[i]].name, items[stack.item].req_val[i]), color); } } // requires class if (items[stack.item].requires_class != "") { if (items[stack.item].requires_class != stats->character_class) color = font->getColor(FontEngine::COLOR_REQUIREMENTS_NOT_MET); else color = font->getColor(FontEngine::COLOR_WIDGET_NORMAL); tip.addColoredText(msg->get("Requires Class: %s", msg->get(items[stack.item].requires_class)), color); } // buy or sell price if (items[stack.item].getPrice() > 0 && stack.item != eset->misc.currency_id) { int price_per_unit; if (context == VENDOR_BUY) { price_per_unit = items[stack.item].getPrice(); if (stats->currency < price_per_unit) color = font->getColor(FontEngine::COLOR_REQUIREMENTS_NOT_MET); else color = font->getColor(FontEngine::COLOR_WIDGET_NORMAL); if (items[stack.item].max_quantity <= 1) tip.addColoredText(msg->get("Buy Price: %d %s", price_per_unit, eset->loot.currency), color); else tip.addColoredText(msg->get("Buy Price: %d %s each", price_per_unit, eset->loot.currency), color); } else if (context == VENDOR_SELL) { price_per_unit = items[stack.item].getSellPrice(stack.can_buyback); if (stats->currency < price_per_unit) color = font->getColor(FontEngine::COLOR_REQUIREMENTS_NOT_MET); else color = font->getColor(FontEngine::COLOR_WIDGET_NORMAL); if (items[stack.item].max_quantity <= 1) tip.addColoredText(msg->get("Buy Price: %d %s", price_per_unit, eset->loot.currency), color); else tip.addColoredText(msg->get("Buy Price: %d %s each", price_per_unit, eset->loot.currency), color); } else if (context == PLAYER_INV) { price_per_unit = items[stack.item].getSellPrice(DEFAULT_SELL_PRICE); if (price_per_unit == 0) price_per_unit = 1; if (items[stack.item].max_quantity <= 1) tip.addText(msg->get("Sell Price: %d %s", price_per_unit, eset->loot.currency)); else tip.addText(msg->get("Sell Price: %d %s each", price_per_unit, eset->loot.currency)); } } if (items[stack.item].set > 0) { // item set bonuses ItemSet set = item_sets[items[stack.item].set]; bonus_counter = 0; tip.addColoredText("\n" + msg->get("Set:") + ' ' + msg->get(item_sets[items[stack.item].set].name), set.color); while (bonus_counter < set.bonus.size()) { ss.str(""); SetBonusData* bdata = &set.bonus[bonus_counter]; ss << msg->get("%d items:", bdata->requirement) << ' '; getBonusString(ss, bdata); tip.addColoredText(ss.str(), set.color); bonus_counter++; } } // input hint for consumables/books // TODO hint when not using mouse control. The action for using an item there is hard to describe if (context == PLAYER_INV && !settings->no_mouse) { int power_id = items[stack.item].power; if (power_id > 0 && items[stack.item].type == "consumable") { tip.addColoredText('\n' + msg->get("Press [%s] to use", inpt->getBindingString(Input::MAIN2)), font->getColor(FontEngine::COLOR_ITEM_BONUS)); } else if (!items[stack.item].book.empty()) { tip.addColoredText('\n' + msg->get("Press [%s] to read", inpt->getBindingString(Input::MAIN2)), font->getColor(FontEngine::COLOR_ITEM_BONUS)); } } return tip; }
void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef) { Inventory *inv_craft = mgr->getInventory(craft_inv); if(!inv_craft){ infostream<<"ICraftAction::apply(): FAIL: inventory not found: " <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl; return; } InventoryList *list_craft = inv_craft->getList("craft"); InventoryList *list_craftresult = inv_craft->getList("craftresult"); /* If a list doesn't exist or the source item doesn't exist */ if(!list_craft){ infostream<<"ICraftAction::apply(): FAIL: craft list not found: " <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl; return; } if(!list_craftresult){ infostream<<"ICraftAction::apply(): FAIL: craftresult list not found: " <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl; return; } if(list_craftresult->getSize() < 1){ infostream<<"ICraftAction::apply(): FAIL: craftresult list too short: " <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl; return; } ItemStack crafted; ItemStack craftresultitem; int count_remaining = count; bool found = getCraftingResult(inv_craft, crafted, false, gamedef); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv); found = !crafted.empty(); while(found && list_craftresult->itemFits(0, crafted)) { InventoryList saved_craft_list = *list_craft; // Decrement input and add crafting output getCraftingResult(inv_craft, crafted, true, gamedef); PLAYER_TO_SA(player)->item_OnCraft(crafted, player, &saved_craft_list, craft_inv); list_craftresult->addItem(0, crafted); mgr->setInventoryModified(craft_inv); actionstream<<player->getDescription() <<" crafts " <<crafted.getItemString() <<std::endl; // Decrement counter if(count_remaining == 1) break; else if(count_remaining > 1) count_remaining--; // Get next crafting result found = getCraftingResult(inv_craft, crafted, false, gamedef); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv); found = !crafted.empty(); } infostream<<"ICraftAction::apply(): crafted " <<" craft_inv=\""<<craft_inv.dump()<<"\"" <<std::endl; }
void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase) { video::IVideoDriver* driver = Environment->getVideoDriver(); // Get font gui::IGUIFont *font = NULL; gui::IGUISkin* skin = Environment->getSkin(); if (skin) font = skin->getFont(); Inventory *inv = m_invmgr->getInventory(s.inventoryloc); if(!inv){ infostream<<"GUIFormSpecMenu::drawList(): WARNING: " <<"The inventory location " <<"\""<<s.inventoryloc.dump()<<"\" doesn't exist" <<std::endl; return; } InventoryList *ilist = inv->getList(s.listname); if(!ilist){ infostream<<"GUIFormSpecMenu::drawList(): WARNING: " <<"The inventory list \""<<s.listname<<"\" @ \"" <<s.inventoryloc.dump()<<"\" doesn't exist" <<std::endl; return; } core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y); for(s32 i=0; i<s.geom.X*s.geom.Y; i++) { u32 item_i = i + s.start_item_i; if(item_i >= ilist->getSize()) break; s32 x = (i%s.geom.X) * spacing.X; s32 y = (i/s.geom.X) * spacing.Y; v2s32 p(x,y); core::rect<s32> rect = imgrect + s.pos + p; ItemStack item; if(ilist) item = ilist->getItem(item_i); bool selected = m_selected_item && m_invmgr->getInventory(m_selected_item->inventoryloc) == inv && m_selected_item->listname == s.listname && m_selected_item->i == i; bool hovering = rect.isPointInside(m_pointer); if(phase == 0) { if(hovering && m_selected_item) { video::SColor bgcolor(255,192,192,192); driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect); } else { video::SColor bgcolor(255,128,128,128); driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect); } } if(phase == 1) { // Draw item stack if(selected) { item.takeItem(m_selected_amount); } if(!item.empty()) { drawItemStack(driver, font, item, rect, &AbsoluteClippingRect, m_gamedef); } // Draw tooltip std::string tooltip_text = ""; if(hovering && !m_selected_item) tooltip_text = item.getDefinition(m_gamedef->idef()).description; if(tooltip_text != "") { m_tooltip_element->setVisible(true); this->bringToFront(m_tooltip_element); m_tooltip_element->setText(narrow_to_wide(tooltip_text).c_str()); s32 tooltip_x = m_pointer.X + 15; s32 tooltip_y = m_pointer.Y + 15; s32 tooltip_width = m_tooltip_element->getTextWidth() + 15; s32 tooltip_height = m_tooltip_element->getTextHeight() + 5; m_tooltip_element->setRelativePosition(core::rect<s32>( core::position2d<s32>(tooltip_x, tooltip_y), core::dimension2d<s32>(tooltip_width, tooltip_height))); } } } }