mirror of
https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1.git
synced 2026-03-20 15:03:32 +00:00
475 lines
14 KiB
C++
Executable File
475 lines
14 KiB
C++
Executable File
#include "ChestScreen.h"
|
|
#include "touch/TouchStartMenuScreen.h"
|
|
#include "../Screen.h"
|
|
#include "../components/NinePatch.h"
|
|
#include "../../Minecraft.h"
|
|
#include "../../player/LocalPlayer.h"
|
|
#include "../../renderer/Tesselator.h"
|
|
#include "../../renderer/entity/ItemRenderer.h"
|
|
#include "../../../world/item/Item.h"
|
|
#include "../../../world/item/ItemCategory.h"
|
|
#include "../../../world/entity/player/Inventory.h"
|
|
#include "../../../world/entity/item/ItemEntity.h"
|
|
#include "../../../world/level/Level.h"
|
|
#include "../../../locale/I18n.h"
|
|
#include "../../../util/StringUtils.h"
|
|
#include "../../../network/packet/ContainerSetSlotPacket.h"
|
|
#include "../../../network/RakNetInstance.h"
|
|
#include "../../../world/level/tile/entity/TileEntity.h"
|
|
#include "../../../world/level/tile/entity/ChestTileEntity.h"
|
|
#include "../../../world/inventory/ContainerMenu.h"
|
|
#include "../../../util/Mth.h"
|
|
|
|
//static NinePatchLayer* guiPaneFrame = NULL;
|
|
|
|
static __inline void setIfNotSet(bool& ref, bool condition) {
|
|
ref = (ref || condition);
|
|
}
|
|
|
|
template<typename T,typename V>
|
|
T* upcast(V* x) { return x; }
|
|
|
|
static int heldMs = -1;
|
|
static int percent = -1;
|
|
static const float MaxHoldMs = 500.0f;
|
|
static const int MinChargeMs = 200;
|
|
|
|
class ItemDiffer {
|
|
public:
|
|
ItemDiffer(int size)
|
|
: size(size),
|
|
count(0)
|
|
{
|
|
base = new ItemInstance[size];
|
|
}
|
|
ItemDiffer(const std::vector<const ItemInstance*>& v)
|
|
: size(v.size()),
|
|
count(0)
|
|
{
|
|
base = new ItemInstance[size];
|
|
init(v);
|
|
}
|
|
|
|
~ItemDiffer() {
|
|
delete[] base;
|
|
}
|
|
|
|
void init(const std::vector<const ItemInstance*>& v) {
|
|
for (int i = 0; i < size; ++i) {
|
|
if (v[i]) base[i] = *v[i];
|
|
else base[i].setNull();
|
|
}
|
|
}
|
|
|
|
int getDiff(const std::vector<const ItemInstance*>& v, std::vector<int>& outIndices) {
|
|
int diffLen = v.size() - size;
|
|
int minLen = Mth::Max((int)v.size(), size);
|
|
for (int i = 0; i < minLen; ++i) {
|
|
//LOGI("%s, %s\n", base[i].toString().c_str(), v[i]?v[i]->toString().c_str() : "null");
|
|
if (!ItemInstance::matchesNulls(&base[i], v[i]))
|
|
outIndices.push_back(i);
|
|
}
|
|
return diffLen;
|
|
}
|
|
|
|
private:
|
|
int size;
|
|
int count;
|
|
ItemInstance* base;
|
|
};
|
|
|
|
const int descFrameWidth = 100;
|
|
|
|
const int rgbActive = 0xfff0f0f0;
|
|
const int rgbInactive = 0xc0635558;
|
|
const int rgbInactiveShadow = 0xc0aaaaaa;
|
|
|
|
#ifdef __APPLE__
|
|
static const float BorderPixels = 3;
|
|
#ifdef DEMO_MODE
|
|
static const float BlockPixels = 22;
|
|
#else
|
|
static const float BlockPixels = 22;
|
|
#endif
|
|
#else
|
|
static const float BorderPixels = 4;
|
|
static const float BlockPixels = 24;
|
|
#endif
|
|
static const int ItemSize = (int)(BlockPixels + 2*BorderPixels);
|
|
|
|
static const int Bx = 10; // Border Frame width
|
|
static const int By = 6; // Border Frame height
|
|
|
|
typedef struct FlyingItem {
|
|
ItemInstance item;
|
|
float startTime;
|
|
float sx, sy;
|
|
float dx, dy;
|
|
} FlyingItem ;
|
|
|
|
static std::vector<FlyingItem> flyingItems;
|
|
|
|
ChestScreen::ChestScreen(Player* player, ChestTileEntity* chest)
|
|
: super(new ContainerMenu(chest, chest->runningId)), //@huge @attn
|
|
inventoryPane(NULL),
|
|
chestPane(NULL),
|
|
btnClose(4, ""),
|
|
bHeader (5, "Inventory"),
|
|
bHeaderChest (6, "Chest"),
|
|
guiBackground(NULL),
|
|
guiSlot(NULL),
|
|
guiSlotMarked(NULL),
|
|
guiSlotMarker(NULL),
|
|
player(player),
|
|
chest(chest),
|
|
selectedSlot(-1),
|
|
doRecreatePane(false)
|
|
//guiSlotItem(NULL),
|
|
//guiSlotItemSelected(NULL)
|
|
{
|
|
}
|
|
|
|
ChestScreen::~ChestScreen() {
|
|
delete inventoryPane;
|
|
delete chestPane;
|
|
|
|
delete guiBackground;
|
|
delete guiSlot;
|
|
delete guiSlotMarked;
|
|
delete guiSlotMarker;
|
|
delete guiPaneFrame;
|
|
|
|
delete menu;
|
|
|
|
if (chest->clientSideOnly)
|
|
delete chest;
|
|
}
|
|
|
|
void ChestScreen::init() {
|
|
super::init();
|
|
//printf("-> %d\n", width/2);
|
|
|
|
ImageDef def;
|
|
def.name = "gui/spritesheet.png";
|
|
def.x = 0;
|
|
def.y = 1;
|
|
def.width = def.height = 18;
|
|
def.setSrc(IntRectangle(60, 0, 18, 18));
|
|
btnClose.setImageDef(def, true);
|
|
btnClose.scaleWhenPressed = false;
|
|
|
|
buttons.push_back(&bHeader);
|
|
buttons.push_back(&bHeaderChest);
|
|
buttons.push_back(&btnClose);
|
|
|
|
// GUI - nine patches
|
|
NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png");
|
|
|
|
guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4);
|
|
guiSlot = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 3, 3);
|
|
guiSlotMarked = builder.createSymmetrical(IntRectangle(0, 44, 8, 8), 3, 3);
|
|
guiSlotMarker = builder.createSymmetrical(IntRectangle(10, 42, 16, 16), 5, 5);
|
|
guiPaneFrame = builder.createSymmetrical(IntRectangle(28, 42, 4, 4), 1, 1)->exclude(4);
|
|
}
|
|
|
|
void ChestScreen::setupPositions() {
|
|
// Left - Categories
|
|
bHeader.x = 0;
|
|
bHeader.y = bHeaderChest.y = 0;
|
|
bHeader.width = bHeaderChest.width = width / 2;// - bDone.w;
|
|
bHeaderChest.x = bHeader.x + bHeader.width;
|
|
|
|
// Right - Description
|
|
btnClose.width = btnClose.height = 19;
|
|
btnClose.x = width - btnClose.width;
|
|
btnClose.y = 0;
|
|
|
|
//guiPaneFrame->setSize((float)paneFuelRect.w + 2, (float)paneFuelRect.h + 4);
|
|
guiBackground->setSize((float)width, (float)height);
|
|
//guiSlotItem->setSize((float)width, 22); //@todo
|
|
//guiSlotItemSelected->setSize((float)width, 22);
|
|
|
|
setupPane();
|
|
}
|
|
|
|
void ChestScreen::tick() {
|
|
if (inventoryPane)
|
|
inventoryPane->tick();
|
|
|
|
if (chestPane)
|
|
chestPane->tick();
|
|
|
|
if (doRecreatePane) {
|
|
setupPane();
|
|
doRecreatePane = false;
|
|
}
|
|
}
|
|
|
|
void ChestScreen::handleRenderPane(Touch::InventoryPane* pane, Tesselator& t, int xm, int ym, float a) {
|
|
if (pane) {
|
|
int ms, id;
|
|
pane->markerIndex = -1;
|
|
if (pane->queryHoldTime(&id, &ms)) {
|
|
heldMs = ms;
|
|
|
|
FillingContainer* c = (pane == inventoryPane)?
|
|
upcast<FillingContainer>(minecraft->player->inventory)
|
|
: upcast<FillingContainer>(chest);
|
|
|
|
const int slotIndex = id + c->getNumLinkedSlots();
|
|
ItemInstance* item = c->getItem(slotIndex);
|
|
int count = (item && !item->isNull())? item->count : 0;
|
|
float maxHoldMs = item? 700 + 10 * item->count: MaxHoldMs;
|
|
|
|
if (count > 1) {
|
|
float share = (heldMs-MinChargeMs) / maxHoldMs;
|
|
pane->markerType = 1;//(heldMs >= MinChargeMs)? 1 : 0;
|
|
pane->markerIndex = id;
|
|
pane->markerShare = Mth::Max(share, 0.0f);
|
|
|
|
percent = (int)Mth::clamp(100.0f * share, 0.0f, 100.0f);
|
|
if (percent >= 100) {
|
|
addItem(pane, id);
|
|
}
|
|
}
|
|
}
|
|
|
|
pane->render(xm, ym, a);
|
|
guiPaneFrame->draw(t, (float)(pane->rect.x - 1), (float)(pane->rect.y - 1));
|
|
//LOGI("query-iv: %d, %d\n", gridId, heldMs);
|
|
|
|
}
|
|
}
|
|
|
|
void ChestScreen::render(int xm, int ym, float a) {
|
|
const int N = 5;
|
|
static StopwatchNLast r(N);
|
|
//renderBackground();
|
|
|
|
Tesselator& t = Tesselator::instance;
|
|
guiBackground->draw(t, 0, 0);
|
|
glEnable2(GL_ALPHA_TEST);
|
|
|
|
// Buttons (Left side + crafting)
|
|
super::render(xm, ym, a);
|
|
|
|
heldMs = -1;
|
|
|
|
handleRenderPane(inventoryPane, t, xm, ym, a);
|
|
handleRenderPane(chestPane, t, xm, ym, a);
|
|
|
|
float now = getTimeS();
|
|
float MaxTime = 0.3f;
|
|
std::vector<FlyingItem> flyingToSave;
|
|
|
|
glEnable2(GL_BLEND);
|
|
glColor4f(1, 1, 1, 0.2f);
|
|
t.beginOverride();
|
|
//t.color(1.0f, 0.0f, 0.0f, 0.2f);
|
|
//t.noColor();
|
|
|
|
glEnable2(GL_SCISSOR_TEST);
|
|
//LOGI("panesBox: %d, %d - %d, %d\n", panesBbox.x, panesBbox.y, panesBbox.w, panesBbox.h);
|
|
minecraft->gui.setScissorRect(panesBbox);
|
|
for (unsigned int i = 0; i < flyingItems.size(); ++i) {
|
|
FlyingItem& fi = flyingItems[i];
|
|
float since = (now - fi.startTime);
|
|
if (since > MaxTime) continue;
|
|
float t = since / MaxTime;
|
|
t *= t;
|
|
//float xx = fi.sx + t * 100.0f;
|
|
|
|
float xx = Mth::lerp(fi.sx, fi.dx, t);
|
|
float yy = Mth::lerp(fi.sy, fi.dy, t);
|
|
ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, &fi.item, xx + 7, yy + 8, true);
|
|
//minecraft->gui.renderSlotText(&fi.item, xx + 3, yy + 3, true, true);
|
|
|
|
flyingToSave.push_back(fi);
|
|
}
|
|
t.enableColor();
|
|
t.endOverrideAndDraw();
|
|
glDisable2(GL_SCISSOR_TEST);
|
|
|
|
flyingItems = flyingToSave;
|
|
|
|
t.colorABGR(0xffffffff);
|
|
glDisable2(GL_BLEND);
|
|
|
|
minecraft->textures->loadAndBindTexture("gui/spritesheet.png");
|
|
}
|
|
|
|
void ChestScreen::buttonClicked(Button* button) {
|
|
if (button == &btnClose) {
|
|
minecraft->player->closeContainer();
|
|
}
|
|
}
|
|
|
|
bool ChestScreen::handleAddItem(FillingContainer* from, FillingContainer* to, int itemIndex) {
|
|
const int itemOffset = from->getNumLinkedSlots();
|
|
const int slotIndex = itemIndex + itemOffset;
|
|
ItemInstance* item = from->getItem(slotIndex);
|
|
|
|
bool added = false;
|
|
bool fromChest = (from == chest);
|
|
Touch::InventoryPane* pane = fromChest? chestPane : inventoryPane;
|
|
Touch::InventoryPane* toPane = fromChest? inventoryPane : chestPane;
|
|
|
|
int wantedCount = (item && !item->isNull())? item->count * percent / 100 : 0;
|
|
if ((item && !item->isNull()) && (!wantedCount || heldMs < MinChargeMs)) {
|
|
wantedCount = 1;
|
|
}
|
|
|
|
if (wantedCount > 0) {
|
|
ItemInstance takenItem(*item);
|
|
takenItem.count = wantedCount;
|
|
|
|
ItemDiffer differ(getItems(toPane));
|
|
to->add(&takenItem);
|
|
|
|
added = (takenItem.count != wantedCount);
|
|
|
|
if (added) {
|
|
item->count -= (wantedCount - takenItem.count);
|
|
std::vector<int> changed;
|
|
std::vector<const ItemInstance*> items = getItems(toPane);
|
|
differ.getDiff(items, changed);
|
|
|
|
ScrollingPane::GridItem g, gTo;
|
|
pane->getGridItemFor_slow(itemIndex, g);
|
|
|
|
//LOGI("Changed: %d\n", changed.size());
|
|
for (unsigned int i = 0; i < changed.size(); ++i) {
|
|
FlyingItem fi;
|
|
fi.startTime = getTimeS();
|
|
fi.item = *item;
|
|
|
|
fi.sx = g.xf;
|
|
fi.sy = g.yf;
|
|
|
|
int toIndex = changed[i];
|
|
toPane->getGridItemFor_slow(toIndex, gTo);
|
|
|
|
fi.dx = gTo.xf;
|
|
fi.dy = gTo.yf;
|
|
flyingItems.push_back(fi);
|
|
|
|
if (!fromChest && minecraft->level->isClientSide) {
|
|
int j = toIndex;
|
|
ItemInstance item = items[j]? *items[j] : ItemInstance();
|
|
ContainerSetSlotPacket p(menu->containerId, j, item);
|
|
minecraft->raknetInstance->send(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Send to server, needs a bit special handling
|
|
if (fromChest) {
|
|
ItemInstance ins(item->count <= 0? ItemInstance() : *item);
|
|
ContainerSetSlotPacket p(menu->containerId, slotIndex, ins);
|
|
minecraft->raknetInstance->send(p);
|
|
}
|
|
if (item->count <= 0)
|
|
from->clearSlot(slotIndex);
|
|
}
|
|
// Clear the marker indices
|
|
pane->markerIndex = toPane->markerIndex = -1;
|
|
|
|
return added;
|
|
}
|
|
|
|
bool ChestScreen::addItem(const Touch::InventoryPane* forPane, int itemIndex) {
|
|
//LOGI("items.size, index: %d, %d\n", inventoryItems.size(), itemIndex);
|
|
bool l2r = (forPane == inventoryPane);
|
|
return handleAddItem( l2r? upcast<FillingContainer>(minecraft->player->inventory) : upcast<FillingContainer>(chest),
|
|
l2r? upcast<FillingContainer>(chest) : upcast<FillingContainer>(minecraft->player->inventory),
|
|
itemIndex);
|
|
}
|
|
|
|
bool ChestScreen::isAllowed( int slot )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool ChestScreen::renderGameBehind()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::vector<const ItemInstance*> ChestScreen::getItems( const Touch::InventoryPane* forPane )
|
|
{
|
|
if (forPane == inventoryPane) {
|
|
for (int i = Inventory::MAX_SELECTION_SIZE, j = 0; i < minecraft->player->inventory->getContainerSize(); ++i, ++j)
|
|
inventoryItems[j] = minecraft->player->inventory->getItem(i);
|
|
return inventoryItems;
|
|
}
|
|
else {
|
|
for (int i = 0; i < chest->getContainerSize(); ++i)
|
|
chestItems[i] = chest->getItem(i);
|
|
return chestItems;
|
|
}
|
|
}
|
|
|
|
|
|
void ChestScreen::setupPane()
|
|
{
|
|
inventoryItems.clear();
|
|
for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) {
|
|
ItemInstance* item = minecraft->player->inventory->getItem(i);
|
|
/*if (!item || item->isNull()) continue;*/
|
|
inventoryItems.push_back(item);
|
|
}
|
|
chestItems.clear();
|
|
for (int i = 0; i < chest->getContainerSize(); ++i) {
|
|
ItemInstance* item = chest->getItem(i);
|
|
/*if (!item || item->isNull()) continue;*/
|
|
chestItems.push_back(item);
|
|
}
|
|
|
|
int maxWidth = width/2 - Bx/2;//- Bx - Bx/*- Bx*/;
|
|
int InventoryColumns = maxWidth / ItemSize;
|
|
const int realWidth = InventoryColumns * ItemSize;
|
|
int paneWidth = realWidth;// + Bx + Bx;
|
|
const int realBx = (width/2 - realWidth) / 2;
|
|
|
|
IntRectangle rect(realBx,
|
|
#ifdef __APPLE__
|
|
24 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-24);
|
|
#else
|
|
24 + By, realWidth, height-By-By-24);
|
|
#endif
|
|
// IntRectangle(0, 0, 100, 100)
|
|
if (inventoryPane) delete inventoryPane;
|
|
inventoryPane = new Touch::InventoryPane(this, minecraft, rect, paneWidth, BorderPixels, minecraft->player->inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE, ItemSize, (int)BorderPixels);
|
|
inventoryPane->fillMarginX = 0;
|
|
inventoryPane->fillMarginY = 0;
|
|
guiPaneFrame->setSize((float)rect.w + 2, (float)rect.h + 2);
|
|
|
|
panesBbox = rect;
|
|
rect.x += width/2;// - rect.w - Bx;
|
|
panesBbox.w += (rect.x - panesBbox.x);
|
|
|
|
if (chestPane) delete chestPane;
|
|
chestPane = new Touch::InventoryPane(this, minecraft, rect, paneWidth, BorderPixels, chest->getContainerSize(), ItemSize, (int)BorderPixels);
|
|
chestPane->fillMarginX = 0;
|
|
chestPane->fillMarginY = 0;
|
|
LOGI("Creating new panes\n:"
|
|
" Inventory %d %p\n"
|
|
" Chest %d %p\n", (int)inventoryItems.size(), inventoryPane, (int)chestItems.size(), chestPane);
|
|
}
|
|
|
|
void ChestScreen::drawSlotItemAt( Tesselator& t, const ItemInstance* item, int x, int y, bool selected)
|
|
{
|
|
float xx = (float)x;
|
|
float yy = (float)y;
|
|
|
|
(selected? guiSlot/*Marked*/ : guiSlot)->draw(t, xx, yy);
|
|
|
|
if (selected)
|
|
guiSlotMarker->draw(t, xx - 2, yy - 2);
|
|
|
|
if (item && !item->isNull()) {
|
|
ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, xx + 7, yy + 8, true);
|
|
minecraft->gui.renderSlotText(item, xx + 3, yy + 3, true, true);
|
|
}
|
|
}
|