diff --git a/launcher/src/client/available-feature-flags b/launcher/src/client/available-feature-flags index de7b9cb..583ea18 100644 --- a/launcher/src/client/available-feature-flags +++ b/launcher/src/client/available-feature-flags @@ -53,3 +53,4 @@ TRUE 3D Chest Model TRUE Replace Block Highlight With Outline TRUE Use Java Beta 1.3 Light Ramp TRUE Send Full Level When Hosting Game +FALSE Food Overlay diff --git a/mods/src/misc/misc.c b/mods/src/misc/misc.c index 6163094..0b07fbc 100644 --- a/mods/src/misc/misc.c +++ b/mods/src/misc/misc.c @@ -3,6 +3,7 @@ #include #include #include +#include #ifndef MCPI_HEADLESS_MODE #include @@ -19,6 +20,58 @@ #include "misc-internal.h" #include +// Heart food overlay +static int heal_amount = 0, heal_amount_drawing = 0; +void Gui_renderHearts_injection(Gui *gui) { + // Get heal_amount + heal_amount = heal_amount_drawing = 0; + + Inventory *inventory = gui->minecraft->player->inventory; + ItemInstance *held_ii = Inventory_getSelected(inventory); + if (held_ii) { + Item *held = Item_items[held_ii->id]; + if (held->vtable->isFood(held) && held_ii->id) { + int nutrition = ((FoodItem *) held)->nutrition; + int cur_health = gui->minecraft->player->health; + int heal_num = fmin(cur_health + nutrition, 20) - cur_health; + heal_amount = heal_amount_drawing = heal_num; + } + } + + // Call original + Gui_renderHearts(gui); +} + +Gui_blit_t Gui_blit_renderHearts_injection = NULL; +void Gui_renderHearts_GuiComponent_blit_overlay_empty_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) { + // Call original + Gui_blit_renderHearts_injection(gui, x1, y1, x2, y2, w1, h1, w2, h2); + // Render the overlay + if (heal_amount_drawing == 1) { + // Half heart + Gui_blit_renderHearts_injection(gui, x1, y1, 79, 0, w1, h1, w2, h2); + heal_amount_drawing = 0; + } else if (heal_amount_drawing > 0) { + // Full heart + Gui_blit_renderHearts_injection(gui, x1, y1, 70, 0, w1, h1, w2, h2); + heal_amount_drawing -= 2; + } +} + +void Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) { + // Offset the overlay + if (x2 == 52) { + heal_amount_drawing += 2; + } else if (x2 == 61 && heal_amount) { + // Half heart, flipped + Gui_blit_renderHearts_injection(gui, x1, y1, 70, 0, w1, h1, w2, h2); + heal_amount_drawing += 1; + }; + // Call original + Gui_blit_renderHearts_injection(gui, x1, y1, x2, y2, w1, h1, w2, h2); + heal_amount_drawing = fmin(heal_amount_drawing, heal_amount); +} + // Classic HUD #define DEFAULT_HUD_PADDING 2 #define NEW_HUD_PADDING 1 @@ -568,14 +621,27 @@ void init_misc() { patch((void *) 0x63c98, invalid_item_background_patch); } + // Food overlay + char food_overlay = 0; + Gui_blit_renderHearts_injection = Gui_blit; + if (feature_has("Food Overlay", server_disabled)) { + food_overlay = 1; + overwrite_calls((void *) Gui_renderHearts, Gui_renderHearts_injection); + overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_overlay_empty_injection); + overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection); + } + // Classic HUD if (feature_has("Classic HUD", server_disabled)) { use_classic_hud = 1; - overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection); overwrite_call((void *) 0x26758, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection); - overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection); overwrite_call((void *) 0x2656c, (void *) Gui_renderHearts_GuiComponent_blit_armor_injection); overwrite_call((void *) 0x268c4, (void *) Gui_renderBubbles_GuiComponent_blit_injection); + if (!food_overlay) { + overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection); + overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection); + } + Gui_blit_renderHearts_injection = Gui_renderHearts_GuiComponent_blit_hearts_injection; } // Render Selected Item Text + Hide Chat Messages diff --git a/symbols/CMakeLists.txt b/symbols/CMakeLists.txt index 7cd1b13..5bfae66 100644 --- a/symbols/CMakeLists.txt +++ b/symbols/CMakeLists.txt @@ -82,6 +82,7 @@ set(SRC src/item/AuxDataTileItem.def src/item/ItemInstance.def src/item/Item.def + src/item/FoodItem.def src/item/ArmorMaterial.def src/item/ArmorItem.def src/item/TileItem.def diff --git a/symbols/src/gui/Gui.def b/symbols/src/gui/Gui.def index 2878998..f676ea6 100644 --- a/symbols/src/gui/Gui.def +++ b/symbols/src/gui/Gui.def @@ -13,6 +13,7 @@ method void getSlotPos(int slot, int *x, int *y) = 0x25548; method void renderSlot(int slot, int x, int y, float alpha) = 0x25cc0; method void renderSlotText(ItemInstance *item, float x, float y, bool finite, bool shadow) = 0x25df8; method void handleKeyPressed(int key) = 0x25a08; +method void renderHearts() = 0x2641c; property Minecraft *minecraft = 0x9f4; property float selected_item_text_timer = 0x9fc; diff --git a/symbols/src/item/FoodItem.def b/symbols/src/item/FoodItem.def new file mode 100644 index 0000000..5c1c159 --- /dev/null +++ b/symbols/src/item/FoodItem.def @@ -0,0 +1,7 @@ +extends Item; + +size 0x30; +vtable 0x10e7b0; +vtable-size 0x98; + +property int nutrition = 0x24; diff --git a/symbols/src/item/Item.def b/symbols/src/item/Item.def index 6c70872..8c3e296 100644 --- a/symbols/src/item/Item.def +++ b/symbols/src/item/Item.def @@ -10,6 +10,7 @@ virtual-method void setIcon(int texture_x, int texture_y) = 0x18; virtual-method int getIcon(int auxiliary) = 0x14; virtual-method int useOn(ItemInstance *item_instance, Player *player, Level *level, int x, int y, int z, int hit_side, float hit_x, float hit_y, float hit_z) = 0x20; virtual-method ItemInstance *use(ItemInstance *item_instance, Level *level, Player *player) = 0x30; +virtual-method bool isFood() = 0x64; virtual-method void setDescriptionId(std::string *name) = 0x6c; virtual-method std::string getDescriptionId(ItemInstance *item_instance) = 0x7c;