Skip to content
2 changes: 1 addition & 1 deletion assets/cubyz/tools/axe.zig.zon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.{
.blockTags = .{.choppable},
.tags = .{.choppable},
.disabled = .{
0, 0, 1, 1, 1,
0, 0, 0, 1, 1,
Expand Down
2 changes: 1 addition & 1 deletion assets/cubyz/tools/chisel.zig.zon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.{
.blockTags = .{.chiselable},
.tags = .{.chiselable},
.disabled = .{
0, 0, 1, 1, 1,
0, 0, 0, 1, 1,
Expand Down
2 changes: 1 addition & 1 deletion assets/cubyz/tools/pickaxe.zig.zon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.{
.blockTags = .{.mineable},
.tags = .{.mineable},
.disabled = .{
0, 0, 0, 0, 1,
0, 0, 0, 1, 1,
Expand Down
2 changes: 1 addition & 1 deletion assets/cubyz/tools/shover.zig.zon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.{
.blockTags = .{.diggable},
.tags = .{.diggable},
.disabled = .{
0, 0, 0, 1, 1,
0, 0, 0, 0, 1,
Expand Down
2 changes: 1 addition & 1 deletion assets/cubyz/tools/sickle.zig.zon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.{
.blockTags = .{.cuttable},
.tags = .{.cuttable},
.disabled = .{
1, 0, 0, 0, 1,
0, 0, 0, 0, 0,
Expand Down
4 changes: 2 additions & 2 deletions mods/cubyz/rotation/stairs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ fn closestRay(comptime typ: enum { bit, intersection }, block: Block, relativePl
pub fn rayIntersection(block: Block, item: main.items.Item, relativePlayerPos: Vec3f, playerDir: Vec3f) ?RayIntersectionResult {
switch (item) {
.proceduralItem => |proceduralItem| {
const tags = proceduralItem.type.blockTags();
const tags = proceduralItem.type.tags();
for (tags) |tag| {
if (tag == .chiselable) {
return closestRay(.intersection, block, relativePlayerPos, playerDir);
Expand All @@ -289,7 +289,7 @@ pub fn rayIntersection(block: Block, item: main.items.Item, relativePlayerPos: V
pub fn onBlockBreaking(item: main.items.Item, relativePlayerPos: Vec3f, playerDir: Vec3f, currentData: *Block) void {
switch (item) {
.proceduralItem => |proceduralItem| {
for (proceduralItem.type.blockTags()) |tag| {
for (proceduralItem.type.tags()) |tag| {
if (tag == .chiselable) {
currentData.data |= closestRay(.bit, currentData.*, relativePlayerPos, playerDir);
if (currentData.data == 255) currentData.* = .{.typ = 0, .data = 0};
Expand Down
48 changes: 39 additions & 9 deletions src/blocks.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const Image = graphics.Image;
const Color = graphics.Color;
const TextureArray = graphics.TextureArray;
const items = @import("items.zig");
const Item = items.Item;
const models = @import("models.zig");
const ModelIndex = models.ModelIndex;
const rotation = @import("rotation.zig");
Expand All @@ -33,6 +34,21 @@ pub const maxBlockCount: usize = 65536; // 16 bit limit
pub const BlockDrop = struct {
items: []const items.ItemStack,
chance: f32,
forbiddenToolTags: []Tag,
allowedToolTags: ?[]Tag = null,

pub fn isDroppedWhenBrokenWithItem(self: BlockDrop, item: Item) bool {
if (item != .proceduralItem) return self.allowedToolTags == null;
Comment thread
DellieDelta marked this conversation as resolved.

const proceduralItem = item.proceduralItem;
for (self.forbiddenToolTags) |tag| if (proceduralItem.hasTag(tag)) return false;
if (self.allowedToolTags) |tags| {
for (tags) |tag| if (proceduralItem.hasTag(tag)) return true;
return false;
}

return true;
}
};

/// Ores can be found underground in veins.
Expand Down Expand Up @@ -68,7 +84,7 @@ var _degradable: [maxBlockCount]bool = undefined;
var _viewThrough: [maxBlockCount]bool = undefined;
var _alwaysViewThrough: [maxBlockCount]bool = undefined;
var _hasBackFace: [maxBlockCount]bool = undefined;
var _blockTags: [maxBlockCount][]Tag = undefined;
var _tags: [maxBlockCount][]Tag = undefined;
Comment thread
DellieDelta marked this conversation as resolved.
var _light: [maxBlockCount]u32 = undefined;
/// How much light this block absorbs if it is transparent
var _absorption: [maxBlockCount]u32 = undefined;
Expand Down Expand Up @@ -108,10 +124,10 @@ pub fn register(_: []const u8, id: []const u8, zon: ZonElement) u16 {
const rotation_tags = _mode[size].getBlockTags();
const block_tags = Tag.loadTagsFromZon(main.stackAllocator, zon.getChild("tags"));
defer main.stackAllocator.free(block_tags);
_blockTags[size] = std.mem.concat(main.worldArena.allocator, Tag, &.{rotation_tags, block_tags}) catch unreachable;
_tags[size] = std.mem.concat(main.worldArena.allocator, Tag, &.{rotation_tags, block_tags}) catch unreachable;

if (_blockTags[size].len == 0) std.log.err("Block {s} is missing 'tags' field", .{id});
for (_blockTags[size]) |tag| {
if (_tags[size].len == 0) std.log.err("Block {s} is missing 'tags' field", .{id});
for (_tags[size]) |tag| {
if (tag == Tag.sbbChild) {
sbb.registerChildBlock(@intCast(size), _id[size]);
break;
Expand Down Expand Up @@ -165,7 +181,6 @@ pub fn loadBlockDrop(blockId: ?[]const u8, zon: ZonElement) []const BlockDrop {
const blockDrops = main.worldArena.alloc(BlockDrop, drops.len);

for (drops, 0..) |blockDrop, i| {
blockDrops[i].chance = blockDrop.get(f32, "chance", 1);
const itemZons = blockDrop.getChild("items").toSlice();
var resultItems = main.List(items.ItemStack).initCapacity(main.stackAllocator, itemZons.len);
defer resultItems.deinit();
Expand All @@ -192,7 +207,22 @@ pub fn loadBlockDrop(blockId: ?[]const u8, zon: ZonElement) []const BlockDrop {
const item = items.BaseItemIndex.fromId(name) orelse continue;
resultItems.append(.{.item = .{.baseItem = item}, .amount = amount});
}
blockDrops[i].items = main.worldArena.dupe(main.items.ItemStack, resultItems.items);

var allowedToolTags: ?[]Tag = null;
if (blockDrop.getChildOrNull("allowedToolTags")) |tagZon| {
const tags = Tag.loadTagsFromZon(main.worldArena, tagZon);
if (tags.len == 0) {
std.log.err("Field '.allowedToolTags' is an empty array. No tool can drop this blockDrop", .{});
}
allowedToolTags = tags;
}

blockDrops[i] = .{
.items = main.worldArena.dupe(main.items.ItemStack, resultItems.items),
.chance = blockDrop.get(f32, "chance", 1),
.forbiddenToolTags = Tag.loadTagsFromZon(main.worldArena, blockDrop.getChild("forbiddenToolTags")),
.allowedToolTags = allowedToolTags,
};
}
return blockDrops;
}
Expand Down Expand Up @@ -410,12 +440,12 @@ pub const Block = packed struct { // MARK: Block
return _hasBackFace[self.typ];
}

pub inline fn blockTags(self: Block) []const Tag {
return _blockTags[self.typ];
pub inline fn tags(self: Block) []const Tag {
return _tags[self.typ];
}

pub inline fn hasTag(self: Block, tag: Tag) bool {
return std.mem.containsAtLeastScalar(Tag, self.blockTags(), 1, tag);
return std.mem.containsAtLeastScalar(Tag, self.tags(), 1, tag);
}

pub inline fn light(self: Block) u32 {
Expand Down
2 changes: 1 addition & 1 deletion src/gui/windows/creative_inventory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn initContent() void {
if (searchString.len > 1 and searchString[0] == '.') {
const tag = searchString[1..];
while (itemIterator.next()) |item| {
if (hasMatchingTag(item.tags(), tag) or (item.block() != null and hasMatchingTag((main.blocks.Block{.typ = item.block().?, .data = undefined}).blockTags(), tag))) {
if (hasMatchingTag(item.tags(), tag) or (item.block() != null and hasMatchingTag((main.blocks.Block{.typ = item.block().?, .data = undefined}).tags(), tag))) {
items.append(Item{.baseItem = item.*});
}
}
Expand Down
21 changes: 13 additions & 8 deletions src/items.zig
Original file line number Diff line number Diff line change
Expand Up @@ -600,8 +600,8 @@ pub const ProceduralItemTypeIndex = enum(u16) {
pub fn id(self: ProceduralItemTypeIndex) []const u8 {
return proceduralItemTypeList.items[@intFromEnum(self)].id;
}
pub fn blockTags(self: ProceduralItemTypeIndex) []const Tag {
return proceduralItemTypeList.items[@intFromEnum(self)].blockTags;
pub fn tags(self: ProceduralItemTypeIndex) []const Tag {
return proceduralItemTypeList.items[@intFromEnum(self)].tags;
}
pub fn properties(self: ProceduralItemTypeIndex) []const PropertyMatrix {
return proceduralItemTypeList.items[@intFromEnum(self)].properties;
Expand All @@ -619,7 +619,7 @@ pub const ProceduralItemTypeIndex = enum(u16) {

pub const ProceduralItemType = struct { // MARK: ProceduralItemType
id: []const u8,
blockTags: []main.Tag,
tags: []main.Tag,
properties: []PropertyMatrix,
slotInfos: [25]SlotInfo,
pixelSources: [16][16]u8,
Expand Down Expand Up @@ -883,11 +883,16 @@ pub const ProceduralItem = struct { // MARK: ProceduralItem
return self.tooltip.items;
}

pub fn hasTag(self: *ProceduralItem, tag: Tag) bool {
for (self.type.tags()) |proceduralItemTag| {
if (proceduralItemTag == tag) return true;
}
return false;
}

pub fn isEffectiveOn(self: *ProceduralItem, block: main.blocks.Block) bool {
for (block.blockTags()) |blockTag| {
for (self.type.blockTags()) |ProceduralItemTag| {
if (ProceduralItemTag == blockTag) return true;
}
for (block.tags()) |tag| {
if (self.hasTag(tag)) return true;
}
return false;
}
Expand Down Expand Up @@ -1290,7 +1295,7 @@ pub fn registerProceduralItem(assetFolder: []const u8, id: []const u8, zon: ZonE
const idDupe = main.worldArena.dupe(u8, id);
proceduralItemTypeList.append(main.worldArena, .{
.id = idDupe,
.blockTags = Tag.loadTagsFromZon(main.worldArena, zon.getChild("blockTags")),
.tags = Tag.loadTagsFromZon(main.worldArena, zon.getChild("tags")),
.slotInfos = slotInfos,
.properties = parameterMatrices.toOwnedSlice(),
.pixelSources = pixelSources,
Expand Down
2 changes: 1 addition & 1 deletion src/proceduralItem/modifiers/bad_at.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn combineModifiers(data1: Data, data2: Data) ?Data {
}

pub fn changeBlockDamage(damage: f32, block: main.blocks.Block, data: Data) f32 {
for (block.blockTags()) |tag| {
for (block.tags()) |tag| {
if (tag == data.tag) return damage*(1 - data.strength);
}
return damage;
Expand Down
2 changes: 1 addition & 1 deletion src/proceduralItem/modifiers/good_at.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn combineModifiers(data1: Data, data2: Data) ?Data {
}

pub fn changeBlockDamage(damage: f32, block: main.blocks.Block, data: Data) f32 {
for (block.blockTags()) |tag| {
for (block.tags()) |tag| {
if (tag == data.tag) return damage*(1 + data.strength);
}
return damage;
Expand Down
3 changes: 3 additions & 0 deletions src/sync.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,7 @@ pub const Command = struct { // MARK: Command
}

// Apply inventory changes:
const handItem = self.source.inv.getItem(self.source.slot); // State should be stored before procedural item breaks
switch (costOfChange) {
.no => unreachable,
.yes => {},
Expand All @@ -1499,6 +1500,8 @@ pub const Command = struct { // MARK: Command
const dropAmount = self.oldBlock.mode().itemDropsOnChange(self.oldBlock, self.newBlock);
for (0..dropAmount) |_| {
for (self.oldBlock.blockDrops()) |drop| {
if (!drop.isDroppedWhenBrokenWithItem(handItem)) continue;

if (drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) {
self.dropLocation.drop(self.pos, self.newBlock, drop);
}
Expand Down
Loading