Beispiel #1
0
/**
 * 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;
}
Beispiel #6
0
// 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;
}
Beispiel #7
0
/**
 * 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;
}
Beispiel #8
0
/**
 * 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;
	}
}
Beispiel #9
0
// 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;*/
}
Beispiel #10
0
	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;
}
Beispiel #14
0
/**
 * 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;
}
Beispiel #16
0
// 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;
}
Beispiel #17
0
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;
}
Beispiel #18
0
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;
}
Beispiel #21
0
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();
}
Beispiel #22
0
/**
 * 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;
}
Beispiel #26
0
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);
	}
}
Beispiel #27
0
/**
 * 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;
}
Beispiel #29
0
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)));
			}
		}
	}
}