forked from EXTERNAL/bareiron
implement growing saplings with bone meal
This commit is contained in:
6
include/structures.h
Normal file
6
include/structures.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef H_STRUCTURES
|
||||||
|
#define H_STRUCTURES
|
||||||
|
|
||||||
|
void placeTreeStructure (short x, uint8_t y, short z);
|
||||||
|
|
||||||
|
#endif
|
@@ -7,6 +7,8 @@
|
|||||||
#include "packets.h"
|
#include "packets.h"
|
||||||
#include "registries.h"
|
#include "registries.h"
|
||||||
#include "worldgen.h"
|
#include "worldgen.h"
|
||||||
|
#include "structures.h"
|
||||||
|
#include "procedures.h"
|
||||||
|
|
||||||
int client_states[MAX_PLAYERS * 2];
|
int client_states[MAX_PLAYERS * 2];
|
||||||
|
|
||||||
@@ -573,6 +575,35 @@ void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the selected slot doesn't hold any items, exit
|
||||||
|
uint8_t *count = &player->inventory_count[player->hotbar];
|
||||||
|
if (*count == 0) return;
|
||||||
|
|
||||||
|
// Check special item handling
|
||||||
|
uint16_t *item = &player->inventory_items[player->hotbar];
|
||||||
|
if (*item == I_bone_meal) {
|
||||||
|
uint8_t target = getBlockAt(x, y, z);
|
||||||
|
uint8_t target_below = getBlockAt(x, y - 1, z);
|
||||||
|
if (target == B_oak_sapling) {
|
||||||
|
// Consume the bone meal (yes, even before checks)
|
||||||
|
// Wasting bone meal on misplanted saplings is vanilla behavior
|
||||||
|
if ((*count -= 1) == 0) item = 0;
|
||||||
|
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, player->hotbar), *count, *item);
|
||||||
|
if ( // Saplings can only grow when placed on these blocks
|
||||||
|
target_below == B_dirt ||
|
||||||
|
target_below == B_grass_block ||
|
||||||
|
target_below == B_snowy_grass_block
|
||||||
|
) {
|
||||||
|
// Bone meal has a 25% chance of growing a tree from a sapling
|
||||||
|
if ((fast_rand() & 3) == 0) placeTreeStructure(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the selected item doesn't correspond to a block, exit
|
||||||
|
uint8_t block = I_to_B(*item);
|
||||||
|
if (block == 0) return;
|
||||||
|
|
||||||
switch (face) {
|
switch (face) {
|
||||||
case 0: y -= 1; break;
|
case 0: y -= 1; break;
|
||||||
case 1: y += 1; break;
|
case 1: y += 1; break;
|
||||||
@@ -583,18 +614,9 @@ void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t *item = &player->inventory_items[player->hotbar];
|
// Check if the block's placement conditions are met
|
||||||
uint8_t *count = &player->inventory_count[player->hotbar];
|
|
||||||
uint8_t block = I_to_B(*item);
|
|
||||||
|
|
||||||
// if the selected item doesn't correspond to a block, exit
|
|
||||||
if (block == 0) return;
|
|
||||||
// if the selected slot doesn't hold any items, exit
|
|
||||||
if (*count == 0) return;
|
|
||||||
|
|
||||||
// check if the block's placement conditions are met
|
|
||||||
if (
|
if (
|
||||||
!( // player is not in the way
|
!( // Is player in the way?
|
||||||
!isPassableBlock(block) &&
|
!isPassableBlock(block) &&
|
||||||
x == player->x &&
|
x == player->x &&
|
||||||
(y == player->y || y == player->y + 1) &&
|
(y == player->y || y == player->y + 1) &&
|
||||||
@@ -603,15 +625,15 @@ void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t
|
|||||||
isReplaceableBlock(getBlockAt(x, y, z)) &&
|
isReplaceableBlock(getBlockAt(x, y, z)) &&
|
||||||
(!isColumnBlock(block) || getBlockAt(x, y - 1, z) != B_air)
|
(!isColumnBlock(block) || getBlockAt(x, y - 1, z) != B_air)
|
||||||
) {
|
) {
|
||||||
// decrease item amount in selected slot
|
// Decrease item amount in selected slot
|
||||||
*count -= 1;
|
*count -= 1;
|
||||||
// clear item id in slot if amount is zero
|
// Clear item id in slot if amount is zero
|
||||||
if (*count == 0) *item = 0;
|
if (*count == 0) *item = 0;
|
||||||
// apply server-side block change
|
// Apply server-side block change
|
||||||
makeBlockChange(x, y, z, block);
|
makeBlockChange(x, y, z, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync hotbar contents to player
|
// Sync hotbar contents to player
|
||||||
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, player->hotbar), *count, *item);
|
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, player->hotbar), *count, *item);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
55
src/structures.c
Normal file
55
src/structures.c
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
#include "tools.h"
|
||||||
|
#include "registries.h"
|
||||||
|
#include "worldgen.h"
|
||||||
|
#include "procedures.h"
|
||||||
|
#include "structures.h"
|
||||||
|
|
||||||
|
void setBlockIfReplaceable (short x, uint8_t y, short z, uint8_t block) {
|
||||||
|
if (!isReplaceableBlock(getBlockAt(x, y, z))) return;
|
||||||
|
makeBlockChange(x, y, z, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Places a tree centered on the input coordinates
|
||||||
|
void placeTreeStructure (short x, uint8_t y, short z) {
|
||||||
|
|
||||||
|
// Get a random number for tree height and leaf edges
|
||||||
|
uint32_t r = fast_rand();
|
||||||
|
uint8_t height = 4 + (r % 3);
|
||||||
|
|
||||||
|
// Set tree base - replace sapling with log and put dirt below
|
||||||
|
makeBlockChange(x, y - 1, z, B_dirt);
|
||||||
|
makeBlockChange(x, y, z, B_oak_log);
|
||||||
|
// Create tree stump
|
||||||
|
for (int i = 1; i < height; i ++) {
|
||||||
|
setBlockIfReplaceable(x, y + i, z, B_oak_log);
|
||||||
|
}
|
||||||
|
// Keep track of leaf corners, determines random number bit shift
|
||||||
|
uint8_t t = 2;
|
||||||
|
// First (bottom) leaf layer
|
||||||
|
for (int i = -2; i <= 2; i ++) {
|
||||||
|
for (int j = -2; j <= 2; j ++) {
|
||||||
|
setBlockIfReplaceable(x + i, y + height - 3, z + j, B_oak_leaves);
|
||||||
|
// Randomly skip some corners, emulating vanilla tree shape
|
||||||
|
if ((i == 2 || i == -2) && (j == 2 || j == -2)) {
|
||||||
|
t ++;
|
||||||
|
if ((r >> t) & 1) continue;
|
||||||
|
}
|
||||||
|
setBlockIfReplaceable(x + i, y + height - 2, z + j, B_oak_leaves);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Second (top) leaf layer
|
||||||
|
for (int i = -1; i <= 1; i ++) {
|
||||||
|
for (int j = -1; j <= 1; j ++) {
|
||||||
|
setBlockIfReplaceable(x + i, y + height - 1, z + j, B_oak_leaves);
|
||||||
|
if ((i == 1 || i == -1) && (j == 1 || j == -1)) {
|
||||||
|
t ++;
|
||||||
|
if ((r >> t) & 1) continue;
|
||||||
|
}
|
||||||
|
setBlockIfReplaceable(x + i, y + height, z + j, B_oak_leaves);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user