Add buckets of milk
- Milk Buckets can be obtained by using an empty bucket on a cow - They can be drunk, but they don't heal you - Adds the `misc_run_on_language_setup` function - Changes `misc_run_on_tile_setup` and `misc_run_on_item_setup` to run after the original function is called - Fix used items transferring durability - Add more symbols
This commit is contained in:
parent
6c5d647a7f
commit
f78a4e47ac
|
@ -1 +1 @@
|
|||
Subproject commit 0b696bd55b31416929d0a29d84ad50ab5ba0ceae
|
||||
Subproject commit ea31be1cb2b43decb9c906215f80ff20efd2b479
|
|
@ -22,6 +22,7 @@ void misc_run_on_creative_inventory_setup(misc_update_function_FillingContainer_
|
|||
typedef void (*misc_update_function_void_t)(void *obj);
|
||||
void misc_run_on_tiles_setup(misc_update_function_void_t function); // obj == NULL
|
||||
void misc_run_on_items_setup(misc_update_function_void_t function); // obj == NULL
|
||||
void misc_run_on_language_setup(misc_update_function_void_t function); // obj == NULL
|
||||
|
||||
void Level_saveLevelData_injection(Level *level);
|
||||
|
||||
|
|
|
@ -6,31 +6,57 @@
|
|||
#include <mods/misc/misc.h>
|
||||
|
||||
// Items
|
||||
Item *bucket = NULL;
|
||||
FoodItem *bucket = NULL;
|
||||
|
||||
// Description And Texture
|
||||
static std::string BucketItem_getDescriptionId(__attribute__((unused)) Item *item, ItemInstance *item_instance) {
|
||||
static std::string BucketItem_getDescriptionId(__attribute__((unused)) FoodItem *item, ItemInstance *item_instance) {
|
||||
if (item_instance->auxiliary == Tile_water->id) {
|
||||
return "item.bucketWater";
|
||||
} else if (item_instance->auxiliary == Tile_lava->id) {
|
||||
return "item.bucketLava";
|
||||
} else if (item_instance->auxiliary == 1) {
|
||||
return "item.bucketMilk";
|
||||
} else {
|
||||
return "item.bucket";
|
||||
}
|
||||
}
|
||||
static int32_t BucketItem_getIcon(__attribute__((unused)) Item *item, int32_t auxiliary) {
|
||||
static int32_t BucketItem_getIcon(__attribute__((unused)) FoodItem *item, int32_t auxiliary) {
|
||||
if (auxiliary == Tile_water->id) {
|
||||
return 75;
|
||||
} else if (auxiliary == Tile_lava->id) {
|
||||
return 76;
|
||||
} else if (auxiliary == 1) {
|
||||
return 77;
|
||||
} else {
|
||||
return 74;
|
||||
}
|
||||
}
|
||||
|
||||
// Filling
|
||||
static bool fill_bucket(ItemInstance *item_instance, Player *player, int new_auxiliary) {
|
||||
bool success = false;
|
||||
if (item_instance->count == 1) {
|
||||
item_instance->auxiliary = new_auxiliary;
|
||||
success = true;
|
||||
} else {
|
||||
ItemInstance new_item;
|
||||
new_item.id = bucket->id;
|
||||
new_item.count = 1;
|
||||
new_item.auxiliary = new_auxiliary;
|
||||
Inventory *inventory = player->inventory;
|
||||
if (inventory->vtable->add(inventory, &new_item)) {
|
||||
// Added To Inventory
|
||||
success = true;
|
||||
item_instance->count -= 1;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
// Use Bucket
|
||||
static int32_t BucketItem_useOn(__attribute__((unused)) Item *item, ItemInstance *item_instance, Player *player, Level *level, int32_t x, int32_t y, int32_t z, int32_t hit_side, __attribute__((unused)) float hit_x, __attribute__((unused)) float hit_y, __attribute__((unused)) float hit_z) {
|
||||
if (item_instance->count < 1) {
|
||||
static int32_t BucketItem_useOn(__attribute__((unused)) FoodItem *item, ItemInstance *item_instance, Player *player, Level *level, int32_t x, int32_t y, int32_t z, int32_t hit_side, __attribute__((unused)) float hit_x, __attribute__((unused)) float hit_y, __attribute__((unused)) float hit_z) {
|
||||
if (item_instance->count < 1 || item_instance->auxiliary == 1) {
|
||||
return 0;
|
||||
} else if (item_instance->auxiliary == 0) {
|
||||
// Empty Bucket
|
||||
|
@ -43,23 +69,7 @@ static int32_t BucketItem_useOn(__attribute__((unused)) Item *item, ItemInstance
|
|||
}
|
||||
if (new_auxiliary != 0) {
|
||||
// Valid
|
||||
bool success = false;
|
||||
if (item_instance->count == 1) {
|
||||
item_instance->auxiliary = new_auxiliary;
|
||||
success = true;
|
||||
} else {
|
||||
ItemInstance new_item;
|
||||
new_item.id = bucket->id;
|
||||
new_item.count = 1;
|
||||
new_item.auxiliary = new_auxiliary;
|
||||
Inventory *inventory = player->inventory;
|
||||
if (inventory->vtable->add(inventory, &new_item)) {
|
||||
// Added To Inventory
|
||||
success = true;
|
||||
item_instance->count -= 1;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
if (fill_bucket(item_instance, player, new_auxiliary)) {
|
||||
Level_setTileAndData(level, x, y, z, 0, 0);
|
||||
return 1;
|
||||
} else {
|
||||
|
@ -116,28 +126,64 @@ static int32_t BucketItem_useOn(__attribute__((unused)) Item *item, ItemInstance
|
|||
}
|
||||
}
|
||||
|
||||
static int BucketItem_getUseDuration(__attribute__((unused)) FoodItem *item, ItemInstance *item_instance) {
|
||||
if (item_instance->auxiliary == 1) {
|
||||
return 0x20;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void BucketItem_useTimeDepleted(FoodItem *item, uchar *param_1, ItemInstance *item_instance, Level *level, Player *player) {
|
||||
if (item_instance->auxiliary == 1) {
|
||||
(*FoodItem_useTimeDepleted_vtable_addr)(item, param_1, item_instance, level, player);
|
||||
// Set it to a empty bucket
|
||||
item_instance->auxiliary = 0;
|
||||
item_instance->count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int BucketItem_getUseAnimation(__attribute__((unused)) FoodItem *item) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static bool BucketItem_isFood(__attribute__((unused)) FoodItem *item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static ItemInstance *BucketItem_use(FoodItem *item, ItemInstance *item_instance, __attribute__((unused)) Level *level, Player *player) {
|
||||
if (item_instance->auxiliary == 1) {
|
||||
return (*FoodItem_use_vtable_addr)(item, item_instance, level, player);
|
||||
}
|
||||
return item_instance;
|
||||
}
|
||||
|
||||
// Bucket VTable
|
||||
static Item_vtable *get_bucket_vtable() {
|
||||
static Item_vtable *vtable = NULL;
|
||||
static FoodItem_vtable *get_bucket_vtable() {
|
||||
static FoodItem_vtable *vtable = NULL;
|
||||
if (vtable == NULL) {
|
||||
// Init
|
||||
vtable = dup_Item_vtable(Item_vtable_base);
|
||||
vtable = dup_FoodItem_vtable(FoodItem_vtable_base);
|
||||
ALLOC_CHECK(vtable);
|
||||
|
||||
// Modify
|
||||
vtable->getDescriptionId = BucketItem_getDescriptionId;
|
||||
vtable->getIcon = BucketItem_getIcon;
|
||||
vtable->useOn = BucketItem_useOn;
|
||||
vtable->getUseDuration = BucketItem_getUseDuration;
|
||||
vtable->useTimeDepleted = BucketItem_useTimeDepleted;
|
||||
vtable->getUseAnimation = BucketItem_getUseAnimation;
|
||||
vtable->isFood = BucketItem_isFood;
|
||||
vtable->use = BucketItem_use;
|
||||
}
|
||||
return vtable;
|
||||
}
|
||||
|
||||
// Create Items
|
||||
static Item *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std::string name) {
|
||||
static FoodItem *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std::string name) {
|
||||
// Construct
|
||||
Item *item = alloc_Item();
|
||||
FoodItem *item = alloc_FoodItem();
|
||||
ALLOC_CHECK(item);
|
||||
Item_constructor(item, id);
|
||||
Item_constructor((Item *) item, id);
|
||||
|
||||
// Set VTable
|
||||
item->vtable = get_bucket_vtable();
|
||||
|
@ -149,6 +195,7 @@ static Item *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std
|
|||
item->category = 2;
|
||||
item->max_damage = 0;
|
||||
item->max_stack_size = 1;
|
||||
item->nutrition = 0;
|
||||
|
||||
// Return
|
||||
return item;
|
||||
|
@ -168,17 +215,29 @@ static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance *item_instanc
|
|||
}
|
||||
}
|
||||
|
||||
// Milking
|
||||
bool Cow_interact_injection(Cow *self, Player *player) {
|
||||
ItemInstance *item = Inventory_getSelected(player->inventory);
|
||||
if (item && item->id == bucket->id && item->auxiliary == 0) {
|
||||
// Fill with milk
|
||||
fill_bucket(item, player, 1);
|
||||
return true;
|
||||
}
|
||||
return Cow_interact_non_virtual(self, player);
|
||||
}
|
||||
|
||||
// Creative Inventory
|
||||
static void inventory_add_item(FillingContainer *inventory, Item *item, int32_t auxiliary) {
|
||||
static void inventory_add_item(FillingContainer *inventory, FoodItem *item, int32_t auxiliary) {
|
||||
ItemInstance *item_instance = new ItemInstance;
|
||||
ALLOC_CHECK(item_instance);
|
||||
item_instance = ItemInstance_constructor_item_extra(item_instance, item, 1, auxiliary);
|
||||
item_instance = ItemInstance_constructor_item_extra(item_instance, (Item *) item, 1, auxiliary);
|
||||
FillingContainer_addItem(inventory, item_instance);
|
||||
}
|
||||
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) {
|
||||
inventory_add_item(filling_container, bucket, 0);
|
||||
inventory_add_item(filling_container, bucket, Tile_water->id);
|
||||
inventory_add_item(filling_container, bucket, Tile_lava->id);
|
||||
inventory_add_item(filling_container, bucket, 1);
|
||||
}
|
||||
|
||||
// Make Liquids Selectable
|
||||
|
@ -273,6 +332,10 @@ static void FurnaceTileEntity_tick_ItemInstance_setNull_injection(ItemInstance *
|
|||
}
|
||||
}
|
||||
|
||||
static void Language_injection(__attribute__((unused)) void *null) {
|
||||
I18n__strings.insert(std::make_pair("item.bucketMilk.name", "Milk Bucket"));
|
||||
}
|
||||
|
||||
// Init
|
||||
void init_bucket() {
|
||||
// Add Buckets
|
||||
|
@ -281,6 +344,8 @@ void init_bucket() {
|
|||
misc_run_on_items_setup(Item_initItems_injection);
|
||||
// Change Max Stack Size Based On Auxiliary
|
||||
overwrite_calls((void *) ItemInstance_getMaxStackSize, (void *) ItemInstance_getMaxStackSize_injection);
|
||||
// Enable milking
|
||||
patch_address((void *) Cow_interact_vtable_addr, (void *) Cow_interact_injection);
|
||||
// Creative Inventory
|
||||
misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection);
|
||||
// Make Liquids Selectable
|
||||
|
@ -293,5 +358,7 @@ void init_bucket() {
|
|||
// Custom Furnace Fuel
|
||||
overwrite_calls((void *) FurnaceTileEntity_getBurnDuration, (void *) FurnaceTileEntity_getBurnDuration_injection);
|
||||
overwrite_call((void *) 0xd351c, (void *) FurnaceTileEntity_tick_ItemInstance_setNull_injection);
|
||||
// Language for milk
|
||||
misc_run_on_language_setup(Language_injection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ SETUP_CALLBACK(creative_inventory_setup, FillingContainer);
|
|||
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container, ItemInstance *item_instance) {
|
||||
// Call Original Method
|
||||
FillingContainer_addItem(filling_container, item_instance);
|
||||
|
||||
// Run Functions
|
||||
handle_misc_creative_inventory_setup(filling_container);
|
||||
}
|
||||
|
@ -85,22 +86,33 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
|
|||
SETUP_CALLBACK(tiles_setup, void);
|
||||
// Handle Custom Tiles Setup Behavior
|
||||
static void Tile_initTiles_injection() {
|
||||
// Run Functions
|
||||
handle_misc_tiles_setup(NULL);
|
||||
|
||||
// Call Original Method
|
||||
Tile_initTiles();
|
||||
|
||||
// Run Functions
|
||||
handle_misc_tiles_setup(NULL);
|
||||
}
|
||||
|
||||
// Run Functions On Items Setup
|
||||
SETUP_CALLBACK(items_setup, void);
|
||||
// Handle Custom Items Setup Behavior
|
||||
static void Item_initItems_injection() {
|
||||
// Run Functions
|
||||
handle_misc_items_setup(NULL);
|
||||
|
||||
// Call Original Method
|
||||
Item_initItems();
|
||||
|
||||
// Run Functions
|
||||
handle_misc_items_setup(NULL);
|
||||
}
|
||||
|
||||
// Run Functions On Language Setup
|
||||
SETUP_CALLBACK(language_setup, void);
|
||||
// Handle Custom Items Setup Behavior
|
||||
static void I18n_loadLanguage_injection(AppPlatform *app, std::string language_name) {
|
||||
// Call Original Method
|
||||
I18n_loadLanguage(app, language_name);
|
||||
|
||||
// Run Functions
|
||||
handle_misc_language_setup(NULL);
|
||||
}
|
||||
|
||||
// Init
|
||||
|
@ -117,4 +129,6 @@ void _init_misc_api() {
|
|||
// Handle Custom Item/Tile Init Behavior
|
||||
overwrite_calls((void *) Tile_initTiles, (void *) Tile_initTiles_injection);
|
||||
overwrite_calls((void *) Item_initItems, (void *) Item_initItems_injection);
|
||||
// Handle Custom Language Entries
|
||||
overwrite_calls((void *) I18n_loadLanguage, (void *) I18n_loadLanguage_injection);
|
||||
}
|
||||
|
|
|
@ -545,6 +545,19 @@ static int FurnaceTileEntity_getLitProgress_injection(FurnaceTileEntity *furnace
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Fix used items transferring durability
|
||||
static int selected_slot = -1;
|
||||
static void Player_startUsingItem_injection(Player *self, ItemInstance *item_instance, int time) {
|
||||
selected_slot = self->inventory->selectedSlot;
|
||||
Player_startUsingItem(self, item_instance, time);
|
||||
}
|
||||
static void Player_stopUsingItem_injection(Player *self) {
|
||||
if (selected_slot != self->inventory->selectedSlot) {
|
||||
self->itemBeingUsed.id = 0;
|
||||
}
|
||||
Player_stopUsingItem(self);
|
||||
}
|
||||
|
||||
// Init
|
||||
static void nop() {
|
||||
}
|
||||
|
@ -731,6 +744,10 @@ void init_misc() {
|
|||
unsigned char mov_r3_ff[4] = {0xff, 0x30, 0xa0, 0xe3}; // "mov r3, #0xff"
|
||||
patch((void *) 0x7178c, mov_r3_ff);
|
||||
|
||||
// Fix used items transferring durability
|
||||
overwrite_calls((void *) Player_startUsingItem, (void *) Player_startUsingItem_injection);
|
||||
overwrite_calls((void *) Player_stopUsingItem, (void *) Player_stopUsingItem_injection);
|
||||
|
||||
// Init C++ And Logging
|
||||
_init_misc_cpp();
|
||||
_init_misc_logging();
|
||||
|
|
|
@ -40,8 +40,9 @@ set(SRC
|
|||
src/entity/MobFactory.def
|
||||
src/entity/EntityRenderDispatcher.def
|
||||
src/entity/MobRenderer.def
|
||||
src/entity/AgableMob.def
|
||||
src/entity/Animal.def
|
||||
src/entity/animal/AgableMob.def
|
||||
src/entity/animal/Animal.def
|
||||
src/entity/animal/Cow.def
|
||||
src/entity/Mob.def
|
||||
src/entity/player/ServerPlayer.def
|
||||
src/entity/player/Player.def
|
||||
|
@ -82,6 +83,7 @@ set(SRC
|
|||
src/item/ArmorMaterial.def
|
||||
src/item/ArmorItem.def
|
||||
src/item/TileItem.def
|
||||
src/item/FoodItem.def
|
||||
src/api/OffsetPosTranslator.def
|
||||
src/api/CommandServer.def
|
||||
src/api/ConnectedClient.def
|
||||
|
@ -125,6 +127,7 @@ set(SRC
|
|||
src/tile/GrassTile.def
|
||||
src/tile/HeavyTile.def
|
||||
src/misc/Strings.def
|
||||
src/misc/I18n.def
|
||||
src/entity/ModelPart.def
|
||||
src/misc/Tesselator.def
|
||||
src/misc/AABB.def
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
virtual-method void remove() = 0x10;
|
||||
virtual-method void tick() = 0x34;
|
||||
virtual-method bool interact(Player *with) = 0x6c;
|
||||
virtual-method bool hurt(Entity *attacker, int damage) = 0xa4;
|
||||
virtual-method int getEntityTypeId() = 0xdc;
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
extends Animal;
|
||||
|
||||
vtable 0x10ba38;
|
|
@ -2,12 +2,18 @@ extends Mob;
|
|||
|
||||
vtable 0x10de70;
|
||||
|
||||
method int isUsingItem() = 0x8f15c;
|
||||
virtual-method void drop(ItemInstance *item_instance, bool is_death) = 0x208;
|
||||
virtual-method void stopSleepInBed(bool param_1, bool param_2, bool param_3) = 0x228;
|
||||
virtual-method void openTextEdit(TileEntity *sign) = 0x230;
|
||||
method ItemInstance *getArmor(int slot) = 0x8fda4;
|
||||
|
||||
property std::string username = 0xbf4;
|
||||
method int isUsingItem() = 0x8f15c;
|
||||
method void stopUsingItem() = 0x8f514;
|
||||
method void startUsingItem(ItemInstance *item_instance, int use_duration) = 0x8f4b8;
|
||||
method ItemInstance *getArmor(int slot) = 0x8fda4;
|
||||
method bool isHurt() = 0x8fb44;
|
||||
|
||||
property Inventory *inventory = 0xbe0;
|
||||
property std::string username = 0xbf4;
|
||||
property bool immortal = 0xbfc;
|
||||
property bool infinite_items = 0xbff;
|
||||
property ItemInstance itemBeingUsed = 0xc34;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
extends Item;
|
||||
|
||||
size 0x30;
|
||||
vtable 0x10e7b0;
|
||||
vtable-size 0x98;
|
||||
|
||||
property int nutrition = 0x24;
|
|
@ -6,12 +6,22 @@ vtable 0x10f128;
|
|||
size 0x24;
|
||||
constructor (int id) = 0x99488;
|
||||
|
||||
virtual-method void setIcon(int texture_x, int texture_y) = 0x18;
|
||||
virtual-method int getIcon(int auxiliary) = 0x14;
|
||||
virtual-method void setIcon(int texture_x, int texture_y) = 0x18;
|
||||
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;
|
||||
// Normally returns 0
|
||||
virtual-method int getUseDuration(ItemInstance *item_instance) = 0x24;
|
||||
// I don't know much about param_1, it might be some partially initialized ItemInstance*
|
||||
virtual-method void useTimeDepleted(uchar *param_1, ItemInstance *item_instance, Level *level, Player *player) = 0x28;
|
||||
virtual-method int getDestorySpeed(ItemInstance *item_instance, Tile *tile) = 0x2c;
|
||||
virtual-method ItemInstance *use(ItemInstance *item_instance, Level *level, Player *player) = 0x30;
|
||||
virtual-method bool mineBlock(ItemInstance *instance, int tile_id, int x, int y, int z) = 0x48;
|
||||
virtual-method bool isFood() = 0x64;
|
||||
virtual-method bool isArmor() = 0x68;
|
||||
virtual-method void setDescriptionId(std::string *name) = 0x6c;
|
||||
virtual-method std::string getDescriptionId(ItemInstance *item_instance) = 0x7c;
|
||||
// Swing = 0, eating = 1, drinking = 2, bow = 4, anything else is nothing
|
||||
virtual-method int getUseAnimation() = 0x94;
|
||||
|
||||
property int id = 0x4;
|
||||
property int max_damage = 0x8;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
static-method void loadLanguage(AppPlatform *app, std::string language_name) = 0x680d0;
|
||||
|
||||
static-property std::map<std::string, std::string> _strings = 0x137d98;
|
|
@ -1,4 +1,15 @@
|
|||
method void Write_uchar(uchar *i) = 0x18448;
|
||||
method void Write_int(int *i) = 0x18454;
|
||||
method void Write_ushort(ushort *i) = 0x45a68;
|
||||
method void Write_short(short *i) = 0x71918;
|
||||
// right_aligned should be true
|
||||
method void WriteBits(uchar *buff, uint bits, bool right_aligned) = 0xd41b4;
|
||||
|
||||
method void Read_uchar(uchar *i) = 0x45ab0;
|
||||
method void Read_int(int *i) = 0x184ec;
|
||||
method void Read_ushort(ushort *i) = 0x45acc;
|
||||
method void Read_short(short *i) = 0x72070;
|
||||
// right_aligned should be true
|
||||
method void ReadBits(uchar *buff, uint bits, bool right_aligned) = 0xd3e18;
|
||||
|
||||
property uint readOffset = 0x8;
|
||||
|
|
Loading…
Reference in New Issue