From 1386b3d6586ac507c5b25f6cf496f84e9710fdd2 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Fri, 4 Aug 2023 11:18:28 +0300 Subject: [PATCH] * Improve survival mode stuff. --- GameMods.hpp | 1 + source/App/Minecraft.cpp | 53 ++++-- source/App/Minecraft.hpp | 5 +- source/GUI/Gui.cpp | 56 ++++--- source/GUI/Gui.hpp | 1 + .../GUI/Screen/IngameBlockSelectionScreen.cpp | 8 +- source/GameMode/CreativeMode.cpp | 26 +-- source/GameMode/CreativeMode.hpp | 20 +-- source/GameMode/GameMode.cpp | 23 +++ source/GameMode/SurvivalMode.cpp | 158 ++++++++++++++++++ source/GameMode/SurvivalMode.hpp | 39 +++++ source/Inventory.cpp | 103 +++++++++++- source/Inventory.hpp | 14 +- source/World/Entity/ItemEntity.cpp | 7 +- source/World/Entity/Player.cpp | 3 - source/World/Renderer/ItemRenderer.cpp | 18 ++ source/World/Renderer/ItemRenderer.hpp | 1 + source/World/Tile/Tile.cpp | 2 +- windows_vs/minecraftcpp.vcxproj | 2 + windows_vs/minecraftcpp.vcxproj.filters | 6 + 20 files changed, 458 insertions(+), 88 deletions(-) create mode 100644 source/GameMode/SurvivalMode.cpp create mode 100644 source/GameMode/SurvivalMode.hpp diff --git a/GameMods.hpp b/GameMods.hpp index 328e0fc..3f7338a 100644 --- a/GameMods.hpp +++ b/GameMods.hpp @@ -40,6 +40,7 @@ // Tests //#define TEST_DROPPED_ITEMS // Allow dropped items to be dropped and collected. +#define TEST_SURVIVAL_MODE // Test survival mode. // Toggle Demo Mode //#define DEMO diff --git a/source/App/Minecraft.cpp b/source/App/Minecraft.cpp index 10fde24..1d4cfd1 100644 --- a/source/App/Minecraft.cpp +++ b/source/App/Minecraft.cpp @@ -14,6 +14,9 @@ #include "ServerSideNetworkHandler.hpp" #include "ClientSideNetworkHandler.hpp" +#include "SurvivalMode.hpp" +#include "CreativeMode.hpp" + #ifndef ORIGINAL_CODE #include "MouseTurnInput.hpp" #else @@ -233,14 +236,15 @@ label_3: return; } - ItemInstance item(m_pLocalPlayer->m_pInventory->getSelectedItemId(), 999, 0); - if (m_pGameMode->useItemOn(m_pLocalPlayer, m_pLevel, item.m_itemID < 0 ? nullptr : &item, hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide)) + ItemInstance* pItem = getSelectedItem(); + + if (m_pGameMode->useItemOn(m_pLocalPlayer, m_pLevel, pItem->m_itemID < 0 ? nullptr : pItem, hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide)) { m_pLocalPlayer->swing(); if (!isOnline()) return; - if (item.m_itemID > C_MAX_TILES || item.m_itemID < 0) + if (pItem->m_itemID > C_MAX_TILES || pItem->m_itemID < 0) return; int dx = hr.m_tileX, dz = hr.m_tileZ; @@ -259,7 +263,7 @@ label_3: } } - m_pRakNetInstance->send(new PlaceBlockPacket(m_pLocalPlayer->m_EntityID, dx, dy, dz, uint8_t(item.m_itemID), uint8_t(hr.m_hitSide))); + m_pRakNetInstance->send(new PlaceBlockPacket(m_pLocalPlayer->m_EntityID, dx, dy, dz, uint8_t(pItem->m_itemID), uint8_t(hr.m_hitSide))); return; } } @@ -286,8 +290,9 @@ label_3: int id = m_pLocalPlayer->m_pInventory->getSelectedItemId(); if (id >= 0) { - ItemInstance item(m_pLocalPlayer->m_pInventory->getSelectedItemId(), 999, 0); - if (m_pGameMode->useItem(m_pLocalPlayer, m_pLevel, &item)) + ItemInstance* pItem = getSelectedItem(); + + if (m_pGameMode->useItem(m_pLocalPlayer, m_pLevel, pItem)) m_pGameRenderer->m_pItemInHandRenderer->itemUsed(); } } @@ -402,6 +407,15 @@ void Minecraft::tickInput() { pauseGame(); } + else if (keyCode == AKEYCODE_Q) + { + int itemID = m_pLocalPlayer->m_pInventory->getSelectedItemId(); + if (itemID > 0) + { + ItemInstance inst(itemID, 1, 0); + m_pLocalPlayer->drop(&inst); + } + } #ifdef ENH_ALLOW_AO else if (keyCode == AKEYCODE_F4) { @@ -411,13 +425,6 @@ void Minecraft::tickInput() m_pLevelRenderer->allChanged(); } #endif - #ifdef TEST_DROPPED_ITEMS - else if (keyCode == AKEYCODE_Q) - { - ItemInstance inst(m_pLocalPlayer->m_pInventory->getSelectedItemId(), 1, 0); - m_pLocalPlayer->drop(&inst); - } - #endif } if (m_options.field_19) @@ -592,7 +599,12 @@ void Minecraft::init() m_pGameRenderer = new GameRenderer(this); m_pParticleEngine = new ParticleEngine(m_pLevel, m_pTextures); m_pUser = new User("TestUser", ""); + +#ifdef TEST_SURVIVAL_MODE + m_pGameMode = new SurvivalMode(this); +#else m_pGameMode = new CreativeMode(this); +#endif reloadOptions(); @@ -739,6 +751,7 @@ void Minecraft::generateLevel(const std::string& unused, Level* pLevel) { pLocalPlayer = m_pGameMode->createPlayer(pLevel); m_pLocalPlayer = pLocalPlayer; + m_pGameMode->initPlayer(pLocalPlayer); } if (pLocalPlayer) @@ -837,6 +850,20 @@ LevelStorageSource* Minecraft::getLevelSource() return m_pLevelStorageSource; } +ItemInstance* Minecraft::getSelectedItem() +{ + ItemInstance* pInst = m_pLocalPlayer->m_pInventory->getSelectedItem(); + + if (m_pGameMode->isSurvivalType()) + return pInst; + + m_CurrItemInstance.m_itemID = pInst->m_itemID; + m_CurrItemInstance.m_amount = 999; + m_CurrItemInstance.m_auxValue = pInst->m_auxValue; + + return &m_CurrItemInstance; +} + void Minecraft::leaveGame(bool bCopyMap) { m_bPreparingLevel = false; diff --git a/source/App/Minecraft.hpp b/source/App/Minecraft.hpp index bc0a5e0..f03ddad 100644 --- a/source/App/Minecraft.hpp +++ b/source/App/Minecraft.hpp @@ -18,7 +18,7 @@ #include "Level.hpp" #include "CThread.hpp" #include "LocalPlayer.hpp" -#include "CreativeMode.hpp" +#include "GameMode.hpp" #include "ITurnInput.hpp" #include "EntityRenderDispatcher.hpp" #include "ParticleEngine.hpp" @@ -71,6 +71,8 @@ public: const char* getProgressMessage(); LevelStorageSource* getLevelSource(); + ItemInstance* getSelectedItem(); + public: static int width, height; static bool useAmbientOcclusion; @@ -122,5 +124,6 @@ public: bool field_DB1 = 0; Screen* m_pScreen = nullptr; int m_licenseID = -2; + ItemInstance m_CurrItemInstance; }; diff --git a/source/GUI/Gui.cpp b/source/GUI/Gui.cpp index edc0aa2..f321966 100644 --- a/source/GUI/Gui.cpp +++ b/source/GUI/Gui.cpp @@ -234,36 +234,24 @@ void Gui::render(float f, bool bHaveScreen, int mouseX, int mouseY) m->m_pTextures->loadAndBindTexture("gui/gui_blocks.png"); - Tesselator& t = Tesselator::instance; - t.begin(); - - // if we aren't trying to build the real deal, don't do this. It only does worse -#ifdef ORIGINAL_CODE - t.voidBeginAndEndCalls(true); // to ensure that Gui::renderSlot doesn't end() our tesselator right away? -#endif - int slotX = cenX - 88; -#ifdef ENH_ENABLE_9TH_SLOT -#define HOTBAR_DIFF 0 -#else -#define HOTBAR_DIFF 1 -#endif - for (int i = 0; i < C_MAX_HOTBAR_ITEMS - HOTBAR_DIFF; i++) + for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++) { renderSlot(i, slotX, height - 19, f); slotX += 20; } -#undef HOTBAR_DIFF + + slotX = cenX - 88; + for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++) + { + renderSlotOverlay(i, slotX, height - 19, f); + + slotX += 20; + } field_A3C = false; -#ifdef ORIGINAL_CODE - t.voidBeginAndEndCalls(false); -#endif - - t.draw(); - // blit the "more items" button #ifndef ENH_ENABLE_9TH_SLOT m->m_pTextures->loadAndBindTexture(C_TERRAIN_NAME); @@ -315,12 +303,30 @@ void Gui::tick() void Gui::renderSlot(int slot, int x, int y, float f) { - int itemID = m_pMinecraft->m_pLocalPlayer->m_pInventory->getQuickSlotItemId(slot); - if (itemID < 0) + Inventory* pInv = m_pMinecraft->m_pLocalPlayer->m_pInventory; + + ItemInstance* pInst = pInv->getQuickSlotItem(slot); + if (!pInst) return; - ItemInstance inst(Item::items[itemID], 1, 0); - ItemRenderer::renderGuiItem(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, &inst, x, y, true); + if (!pInst->m_itemID) + return; + + ItemRenderer::renderGuiItem(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, pInst, x, y, true); +} + +void Gui::renderSlotOverlay(int slot, int x, int y, float f) +{ + Inventory* pInv = m_pMinecraft->m_pLocalPlayer->m_pInventory; + + ItemInstance* pInst = pInv->getQuickSlotItem(slot); + if (!pInst) + return; + + if (!pInst->m_itemID) + return; + + ItemRenderer::renderGuiItemOverlay(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, pInst, x, y); } int Gui::getSlotIdAt(int mouseX, int mouseY) diff --git a/source/GUI/Gui.hpp b/source/GUI/Gui.hpp index e3a7dcd..dc453fa 100644 --- a/source/GUI/Gui.hpp +++ b/source/GUI/Gui.hpp @@ -35,6 +35,7 @@ public: void render(float f, bool bHaveScreen, int mouseX, int mouseY); void tick(); void renderSlot(int slot, int x, int y, float f); + void renderSlotOverlay(int slot, int x, int y, float f); int getSlotIdAt(int mx, int my); bool isInside(int mx, int my); void handleClick(int id, int mx, int my); diff --git a/source/GUI/Screen/IngameBlockSelectionScreen.cpp b/source/GUI/Screen/IngameBlockSelectionScreen.cpp index b8960de..33d8b08 100644 --- a/source/GUI/Screen/IngameBlockSelectionScreen.cpp +++ b/source/GUI/Screen/IngameBlockSelectionScreen.cpp @@ -71,7 +71,7 @@ void IngameBlockSelectionScreen::init() { if (pInv->getItem(i)->m_itemID == pInv->getSelectedItemId()) { - m_selectedSlot = i - 9; + m_selectedSlot = i; break; } } @@ -86,7 +86,11 @@ void IngameBlockSelectionScreen::renderSlot(int index, int x, int y, float f) if (!pItem) return; - ItemRenderer::renderGuiItem(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, pItem, x, y, pItem != nullptr); + if (!pItem->m_itemID) + return; + + ItemRenderer::renderGuiItem(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, pItem, x, y, true); + ItemRenderer::renderGuiItemOverlay(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, pItem, x, y); } void IngameBlockSelectionScreen::renderSlots() diff --git a/source/GameMode/CreativeMode.cpp b/source/GameMode/CreativeMode.cpp index 95b2774..31f5a6d 100644 --- a/source/GameMode/CreativeMode.cpp +++ b/source/GameMode/CreativeMode.cpp @@ -16,7 +16,8 @@ CreativeMode::CreativeMode(Minecraft* pMC) : GameMode(pMC) void CreativeMode::initPlayer(Player* p) { - p->m_yaw = -180.0; + p->m_yaw = -180.0f; + p->m_pInventory->prepareCreativeInventory(); } void CreativeMode::startDestroyBlock(int x, int y, int z, int i) @@ -144,26 +145,3 @@ bool CreativeMode::isSurvivalType() { return true; } - -bool GameMode::useItem(Player* player, Level* level, ItemInstance* instance) -{ - int oldAmount = instance->m_amount; - - if (instance == instance->use(level, player)) - return instance->m_amount != oldAmount; - - return true; -} - -bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* instance, int x, int y, int z, int d) -{ - TileID tile = level->getTile(x, y, z); - if (tile > 0 && Tile::tiles[tile]->use(level, x, y, z, player)) - return true; - - if (instance) - return instance->useOn(player, level, x, y, z, d); - - return false; -} - diff --git a/source/GameMode/CreativeMode.hpp b/source/GameMode/CreativeMode.hpp index 746e398..22f8940 100644 --- a/source/GameMode/CreativeMode.hpp +++ b/source/GameMode/CreativeMode.hpp @@ -15,16 +15,16 @@ class CreativeMode : public GameMode public: CreativeMode(Minecraft*); - virtual void startDestroyBlock(int x, int y, int z, int i) override; - virtual bool destroyBlock(int x, int y, int z, int i); - virtual void continueDestroyBlock(int x, int y, int z, int i); - virtual void stopDestroyBlock() override; - virtual void tick() override; - virtual void render(float f) override; - virtual float getPickRange() override; - virtual bool isCreativeType() override; - virtual bool isSurvivalType() override; - virtual void initPlayer(Player*) override; + void startDestroyBlock(int x, int y, int z, int i) override; + bool destroyBlock(int x, int y, int z, int i); + void continueDestroyBlock(int x, int y, int z, int i); + void stopDestroyBlock() override; + void tick() override; + void render(float f) override; + float getPickRange() override; + bool isCreativeType() override; + bool isSurvivalType() override; + void initPlayer(Player*) override; public: int m_destroyingX = -1; diff --git a/source/GameMode/GameMode.cpp b/source/GameMode/GameMode.cpp index 2fe1144..04238e3 100644 --- a/source/GameMode/GameMode.cpp +++ b/source/GameMode/GameMode.cpp @@ -116,3 +116,26 @@ bool GameMode::isSurvivalType() { return false; } + +bool GameMode::useItem(Player* player, Level* level, ItemInstance* instance) +{ + int oldAmount = instance->m_amount; + + if (instance == instance->use(level, player)) + return instance->m_amount != oldAmount; + + return true; +} + +bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* instance, int x, int y, int z, int d) +{ + TileID tile = level->getTile(x, y, z); + if (tile > 0 && Tile::tiles[tile]->use(level, x, y, z, player)) + return true; + + if (instance) + return instance->useOn(player, level, x, y, z, d); + + return false; +} + diff --git a/source/GameMode/SurvivalMode.cpp b/source/GameMode/SurvivalMode.cpp new file mode 100644 index 0000000..7a90140 --- /dev/null +++ b/source/GameMode/SurvivalMode.cpp @@ -0,0 +1,158 @@ +/******************************************************************** + Minecraft: Pocket Edition - Decompilation Project + Copyright (C) 2023 iProgramInCpp + + The following code is licensed under the BSD 1 clause license. + SPDX-License-Identifier: BSD-1-Clause + ********************************************************************/ + +#include "SurvivalMode.hpp" +#include "Minecraft.hpp" + +SurvivalMode::SurvivalMode(Minecraft* pMC) : GameMode(pMC) +{ +} + +void SurvivalMode::initPlayer(Player* p) +{ + p->m_yaw = -180.0f; + p->m_pInventory->prepareSurvivalInventory(); +} + +bool SurvivalMode::canHurtPlayer() +{ + return true; +} + +void SurvivalMode::startDestroyBlock(int x, int y, int z, int i) +{ + TileID tile = m_pMinecraft->m_pLevel->getTile(x, y, z); + + if (tile <= 0) + return; + + if (field_18 == 0.0f) + { + Tile::tiles[tile]->attack(m_pMinecraft->m_pLevel, x, y, z, m_pMinecraft->m_pLocalPlayer); + } + + if (Tile::tiles[tile]->getDestroyProgress(m_pMinecraft->m_pLocalPlayer) >= 1.0f) + { + destroyBlock(x, y, z, i); + } + + return; +} + +bool SurvivalMode::destroyBlock(int x, int y, int z, int i) +{ + m_pMinecraft->m_pParticleEngine->destroy(x, y, z); + + TileID tile = m_pMinecraft->m_pLevel->getTile(x, y, z); + int data = m_pMinecraft->m_pLevel->getData(x, y, z); + + if (!GameMode::destroyBlock(x, y, z, i)) + return false; + + //@HUH: check too late? + bool bCanDestroy = m_pMinecraft->m_pLocalPlayer->canDestroy(Tile::tiles[tile]); + + if (bCanDestroy) + { + Tile::tiles[tile]->playerDestroy(m_pMinecraft->m_pLevel, m_pMinecraft->m_pLocalPlayer, x, y, z, data); + + if (m_pMinecraft->isOnline()) + { + m_pMinecraft->m_pRakNetInstance->send(new RemoveBlockPacket(m_pMinecraft->m_pLocalPlayer->m_EntityID, x, y, z)); + } + } + + return true; +} + +void SurvivalMode::continueDestroyBlock(int x, int y, int z, int i) +{ + if (field_24 > 0) + { + field_24--; + return; + } + + if (m_destroyingX != x || m_destroyingY != y || m_destroyingZ != z) + { + field_18 = 0.0f; + field_1C = 0.0f; + field_20 = 0; + m_destroyingX = x; + m_destroyingY = y; + m_destroyingZ = z; + return; + } + + TileID tile = m_pMinecraft->m_pLevel->getTile(m_destroyingX, m_destroyingY, m_destroyingZ); + if (!tile) + return; + + Tile* pTile = Tile::tiles[tile]; + float destroyProgress = pTile->getDestroyProgress(m_pMinecraft->m_pLocalPlayer); + + field_18 += 16.0f * destroyProgress; + field_20++; + + if ((field_20 & 3) == 1) + { + m_pMinecraft->m_pSoundEngine->play("step." + pTile->m_pSound->m_name, + float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, + 0.5f * (1.0f + pTile->m_pSound->field_18), 0.8f * pTile->m_pSound->field_1C); + } + + if (field_18 >= 1.0f) + { + destroyBlock(m_destroyingX, m_destroyingY, m_destroyingZ, i); + field_20 = 0; + field_24 = 5; + field_18 = 0.0f; + field_1C = 0.0f; + } +} + +void SurvivalMode::stopDestroyBlock() +{ + field_18 = 0.0f; + field_24 = 0; +} + +void SurvivalMode::tick() +{ + field_1C = field_18; +} + +void SurvivalMode::render(float f) +{ + if (field_18 <= 0.0f) + { + m_pMinecraft->m_gui.field_8 = 0.0f; + m_pMinecraft->m_pLevelRenderer->field_10 = 0.0f; + } + else + { + float x = field_1C + (field_18 - field_1C) * f; + m_pMinecraft->m_gui.field_8 = x; + m_pMinecraft->m_pLevelRenderer->field_10 = x; + } +} + +float SurvivalMode::getPickRange() +{ + return 5.0f; +} + +bool SurvivalMode::isCreativeType() +{ + return false; +} + +bool SurvivalMode::isSurvivalType() +{ + return true; +} diff --git a/source/GameMode/SurvivalMode.hpp b/source/GameMode/SurvivalMode.hpp new file mode 100644 index 0000000..6e4d36b --- /dev/null +++ b/source/GameMode/SurvivalMode.hpp @@ -0,0 +1,39 @@ +/******************************************************************** + Minecraft: Pocket Edition - Decompilation Project + Copyright (C) 2023 iProgramInCpp + + The following code is licensed under the BSD 1 clause license. + SPDX-License-Identifier: BSD-1-Clause + ********************************************************************/ + +#pragma once + +#include "GameMode.hpp" + +class SurvivalMode : public GameMode +{ +public: + SurvivalMode(Minecraft*); + + void startDestroyBlock(int x, int y, int z, int i) override; + bool destroyBlock(int x, int y, int z, int i); + void continueDestroyBlock(int x, int y, int z, int i); + void stopDestroyBlock() override; + void tick() override; + void render(float f) override; + float getPickRange() override; + bool isCreativeType() override; + bool isSurvivalType() override; + void initPlayer(Player*) override; + bool canHurtPlayer() override; + +public: + int m_destroyingX = -1; + int m_destroyingY = -1; + int m_destroyingZ = -1; + float field_18 = 0.0f; + float field_1C = 0.0f; + int field_20 = 0; + int field_24 = 0; +}; + diff --git a/source/Inventory.cpp b/source/Inventory.cpp index bb081e7..9016ff7 100644 --- a/source/Inventory.cpp +++ b/source/Inventory.cpp @@ -16,7 +16,6 @@ void Inventory::prepareCreativeInventory() m_items.clear(); - // add some items addCreativeItem(Tile::rock->m_ID); addCreativeItem(Tile::stoneBrick->m_ID); addCreativeItem(Tile::sandStone->m_ID); @@ -67,14 +66,24 @@ void Inventory::prepareCreativeInventory() addCreativeItem(Item::door_wood->m_itemID); addCreativeItem(Item::door_iron->m_itemID); - for (int i = C_MAX_HOTBAR_ITEMS - 1; i >= 0; i--) - selectItem(i); + for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++) + m_hotbar[i] = i; } void Inventory::prepareSurvivalInventory() { m_bIsSurvival = true; m_items.clear(); + m_items.resize(C_NUM_SURVIVAL_SLOTS); + + // Add some items for testing + addTestItem(Item::stick->m_itemID, 64); + addTestItem(Item::wheat->m_itemID, 64); + addTestItem(Item::sugar->m_itemID, 64); + addTestItem(Item::camera->m_itemID, 64); + + for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++) + m_hotbar[i] = i; } int Inventory::getNumSlots() @@ -95,6 +104,77 @@ void Inventory::addCreativeItem(int itemID, int auxValue) m_items.emplace_back(ItemInstance(itemID, 1, auxValue)); } +void Inventory::clear() +{ + m_items.clear(); + m_items.resize(C_NUM_SURVIVAL_SLOTS); +} + +void Inventory::addItem(ItemInstance* pInst) +{ + if (!m_bIsSurvival) + { + // Just get rid of the item. + pInst->m_amount = 0; + return; + } + + // look for an item with the same ID + for (int i = 0; i < getNumItems(); i++) + { + if (m_items[i].m_itemID != pInst->m_itemID) + continue; + + int maxStackSize = m_items[i].getMaxStackSize(); + bool bIsStackedByData = Item::items[pInst->m_itemID]->isStackedByData(); + if (bIsStackedByData && m_items[i].m_auxValue != pInst->m_auxValue) + continue; + + // try to collate. + int combinedItemAmount = pInst->m_amount + m_items[i].m_amount; + + int leftover = combinedItemAmount - maxStackSize; + if (leftover < 0) + leftover = 0; + else + combinedItemAmount = C_MAX_AMOUNT; + + m_items[i].m_amount = combinedItemAmount; + + pInst->m_amount = leftover; + + if (!bIsStackedByData) + m_items[i].m_auxValue = 0; + } + + // If there's nothing leftover: + if (!pInst->m_amount) + return; + + // try to add it to an empty slot + for (int i = 0; i < getNumItems(); i++) + { + if (m_items[i].m_itemID != 0) + continue; + + m_items[i] = *pInst; + pInst->m_amount = 0; + return; + } +} + +void Inventory::addTestItem(int itemID, int amount, int auxValue) +{ + ItemInstance inst(itemID, amount, auxValue); + addItem(&inst); + + if (inst.m_amount != 0) + { + LogMsg("AddTestItem: Couldn't add all %d of %s, only gave %d", + amount, Item::items[itemID]->m_DescriptionID.c_str(), amount - inst.m_amount); + } +} + ItemInstance* Inventory::getItem(int slotNo) { if (slotNo < 0 || slotNo >= int(m_items.size())) @@ -116,6 +196,19 @@ int Inventory::getQuickSlotItemId(int slotNo) return pInst->m_itemID; } +ItemInstance* Inventory::getQuickSlotItem(int slotNo) +{ + if (slotNo < 0 || slotNo >= C_MAX_HOTBAR_ITEMS) + return nullptr; + + return getItem(m_hotbar[slotNo]); +} + +ItemInstance* Inventory::getSelectedItem() +{ + return getQuickSlotItem(m_SelectedHotbarSlot); +} + int Inventory::getSelectedItemId() { return getQuickSlotItemId(m_SelectedHotbarSlot); @@ -156,7 +249,9 @@ void Inventory::setQuickSlotIndexByItemId(int slotNo, int itemID) if (slotNo < 0 || slotNo >= C_MAX_HOTBAR_ITEMS) return; - // TODO: survival mode handling + if (m_bIsSurvival) + return; // TODO + for (int i = 0; i < getNumItems(); i++) { if (m_items[i].m_itemID == itemID) diff --git a/source/Inventory.hpp b/source/Inventory.hpp index 50322f3..ba099e3 100644 --- a/source/Inventory.hpp +++ b/source/Inventory.hpp @@ -6,8 +6,8 @@ class Player; // in case we're included from Player.hpp #define C_MAX_HOTBAR_ITEMS (9) - #define C_NUM_SURVIVAL_SLOTS (36) +#define C_MAX_AMOUNT (64) class Inventory { @@ -20,8 +20,14 @@ public: int getNumItems(); void addCreativeItem(int itemID, int auxValue = 0); + void addTestItem(int itemID, int amount, int auxValue = 0); + + void clear(); + void addItem(ItemInstance* pInst); ItemInstance* getItem(int slotNo); + ItemInstance* getQuickSlotItem(int slotNo); + ItemInstance* getSelectedItem(); int getQuickSlotItemId(int slotNo); int getSelectedItemId(); void selectItem(int slotNo); // selects an item by slot number and puts it in the quick slots if needed @@ -30,8 +36,14 @@ public: void setQuickSlotIndexByItemId(int slotNo, int itemID); void selectItemById(int itemID); + int getSelectedSlotNo() const + { + return m_SelectedHotbarSlot; + } + public: int m_SelectedHotbarSlot = 0; +private: Player* m_pPlayer = nullptr; bool m_bIsSurvival = false; diff --git a/source/World/Entity/ItemEntity.cpp b/source/World/Entity/ItemEntity.cpp index 6cc987a..f3d49ab 100644 --- a/source/World/Entity/ItemEntity.cpp +++ b/source/World/Entity/ItemEntity.cpp @@ -70,18 +70,17 @@ bool ItemEntity::isInWater() void ItemEntity::playerTouch(Player* player) { // Here, this would give the item to the player, and remove the item entity. -#ifdef TEST_DROPPED_ITEMS if (field_E4 != 0) return; - // No inventory to add an item to. Just set the amount to 0 - m_pItemInstance->m_amount = 0; + Inventory* pInventory = player->m_pInventory; + + pInventory->addItem(m_pItemInstance); // No "random.pop" sound. if (m_pItemInstance->m_amount <= 0) remove(); -#endif } void ItemEntity::tick() diff --git a/source/World/Entity/Player.cpp b/source/World/Entity/Player.cpp index 38d7b58..38dff19 100644 --- a/source/World/Entity/Player.cpp +++ b/source/World/Entity/Player.cpp @@ -15,9 +15,6 @@ Player::Player(Level* pLevel) : Mob(pLevel) m_pInventory = new Inventory(this); - // @TODO: GameMode::prepareInventory - m_pInventory->prepareCreativeInventory(); - field_84 = 1.62f; Pos pos = m_pLevel->getSharedSpawnPos(); diff --git a/source/World/Renderer/ItemRenderer.cpp b/source/World/Renderer/ItemRenderer.cpp index ce8f06f..903cc6f 100644 --- a/source/World/Renderer/ItemRenderer.cpp +++ b/source/World/Renderer/ItemRenderer.cpp @@ -6,6 +6,7 @@ SPDX-License-Identifier: BSD-1-Clause ********************************************************************/ +#include #include "ItemRenderer.hpp" #include "TileRenderer.hpp" #include "ItemEntity.hpp" @@ -157,6 +158,23 @@ void ItemRenderer::blit(int dx, int dy, int sx, int sy, int tw, int th) t.draw(); } +void ItemRenderer::renderGuiItemOverlay(Font* font, Textures* textures, ItemInstance* instance, int x, int y) +{ + if (!instance) + return; + + if (instance->m_amount == 1) + return; + + std::stringstream ss; + ss << instance->m_amount; + std::string amtstr = ss.str(); + + int width = font->width(amtstr), height = font->height(amtstr) + 8; + + font->drawShadow(amtstr, x + 17 - width, y + 17 - height, 0xFFFFFF); +} + void ItemRenderer::renderGuiItem(Font* font, Textures* textures, ItemInstance* instance, int x, int y, bool b) { // @NOTE: Font unused but would presumably be used to draw the item amount. diff --git a/source/World/Renderer/ItemRenderer.hpp b/source/World/Renderer/ItemRenderer.hpp index 37d4997..25d47d9 100644 --- a/source/World/Renderer/ItemRenderer.hpp +++ b/source/World/Renderer/ItemRenderer.hpp @@ -22,6 +22,7 @@ public: static void blit(int, int, int, int, int, int); static void renderGuiItem(Font*, Textures*, ItemInstance*, int, int, bool); + static void renderGuiItemOverlay(Font*, Textures*, ItemInstance*, int, int); public: Random m_random; diff --git a/source/World/Tile/Tile.cpp b/source/World/Tile/Tile.cpp index 72db6bc..57634ca 100644 --- a/source/World/Tile/Tile.cpp +++ b/source/World/Tile/Tile.cpp @@ -1092,10 +1092,10 @@ void Tile::spawnResources(Level* pLevel, int x, int y, int z, int i) void Tile::spawnResources(Level* pLevel, int x, int y, int z, int data, float fChance) { -#ifdef TEST_DROPPED_ITEMS if (pLevel->field_11) return; +#ifdef TEST_SURVIVAL_MODE int count = getResourceCount(&pLevel->field_38); for (int i = 0; i < count; i++) { diff --git a/windows_vs/minecraftcpp.vcxproj b/windows_vs/minecraftcpp.vcxproj index 47d1d7c..4bb09b8 100644 --- a/windows_vs/minecraftcpp.vcxproj +++ b/windows_vs/minecraftcpp.vcxproj @@ -50,6 +50,7 @@ + @@ -346,6 +347,7 @@ + diff --git a/windows_vs/minecraftcpp.vcxproj.filters b/windows_vs/minecraftcpp.vcxproj.filters index 7bd6909..e41cd3a 100644 --- a/windows_vs/minecraftcpp.vcxproj.filters +++ b/windows_vs/minecraftcpp.vcxproj.filters @@ -1086,6 +1086,9 @@ Source Files\World\Tile + + Source Files\Game Modes + @@ -1970,6 +1973,9 @@ Header Files\World\Renderer\Entity + + Header Files\Game Modes +