Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/gui/components/BagSlot.zig
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ size: Vec2f = .{sizeWithBorder, sizeWithBorder + 8},
inventory: *BagInventory,
hovered: bool = false,
pressed: bool = false,
itemColor: u32 = 0xffffffff,

pub fn globalInit() void {
texture = Texture.initFromFile("assets/cubyz/ui/inventory/bag_slot.png");
Expand Down Expand Up @@ -91,7 +92,7 @@ pub fn render(self: *BagSlot, _: Vec2f) void {
const opacity: f32 = std.math.pow(f32, 0.5, @as(f32, @floatFromInt(i)));
const oldColor = draw.setColor(0xffffff | @as(u32, @trunc(opacity*255)) << 24);
defer draw.restoreColor(oldColor);
item.render(self.pos, @splat(sizeWithBorder), border);
item.render(self.pos, @splat(sizeWithBorder), border, self.itemColor);
}

const topItem = self.inventory.peek(0);
Expand Down
18 changes: 14 additions & 4 deletions src/gui/components/ItemSlot.zig
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ size: Vec2f = @splat(sizeWithBorder),
inventory: ClientInventory,
itemSlot: u32,
lastItemAmount: u16 = 0,
itemColor: u32 = 0xffffffff,
onHover: main.callbacks.SimpleCallback,
text: TextBuffer,
textSize: Vec2f = .{0, 0},
hovered: bool = false,
Expand Down Expand Up @@ -57,6 +59,12 @@ const TextureParamType = union(enum) {
}
};

const Options = struct {
texture: TextureParamType = .default,
mode: Mode = .normal,
onHover: main.callbacks.SimpleCallback = .{},
};

pub fn globalInit() void {
defaultTexture = Texture.initFromFile("assets/cubyz/ui/inventory/slot.png");
immutableTexture = Texture.initFromFile("assets/cubyz/ui/inventory/immutable_slot.png");
Expand All @@ -69,7 +77,7 @@ pub fn globalDeinit() void {
craftingResultTexture.deinit();
}

pub fn init(pos: Vec2f, inventory: ClientInventory, itemSlot: u32, texture: TextureParamType, mode: Mode) *ItemSlot {
pub fn init(pos: Vec2f, inventory: ClientInventory, itemSlot: u32, options: Options) *ItemSlot {
const self = main.globalAllocator.create(ItemSlot);
const amount = inventory.getAmount(itemSlot);
var buf: [16]u8 = undefined;
Expand All @@ -79,8 +87,9 @@ pub fn init(pos: Vec2f, inventory: ClientInventory, itemSlot: u32, texture: Text
.pos = pos,
.text = TextBuffer.init(main.globalAllocator, std.fmt.bufPrint(&buf, "{}", .{amount}) catch "∞", .{}, false, .right),
.lastItemAmount = amount,
.texture = texture.value(),
.mode = mode,
.texture = options.texture.value(),
.mode = options.mode,
.onHover = options.onHover,
};
self.textSize = self.text.calculateLineBreaks(8, self.size[0] - 2*border);
return self;
Expand Down Expand Up @@ -115,6 +124,7 @@ pub fn toComponent(self: *ItemSlot) GuiComponent {
pub fn updateHovered(self: *ItemSlot, _: Vec2f) main.callbacks.Result {
self.hovered = true;
gui.hoveredItemSlot = self;
self.onHover.run();
return .handled;
}

Expand All @@ -137,7 +147,7 @@ pub fn render(self: *ItemSlot, _: Vec2f) void {
}
const item = self.inventory.getItem(self.itemSlot);
if (item != .null) {
item.render(self.pos, self.size, border);
item.render(self.pos, self.size, border, self.itemColor);
const shouldRenderStackSizeText = item.stackSize() > 1 and self.inventory.type != .creative;
if (shouldRenderStackSizeText) {
self.text.render(self.pos[0] + self.size[0] - self.textSize[0] - border, self.pos[1] + self.size[1] - self.textSize[1] - border, 8);
Expand Down
2 changes: 1 addition & 1 deletion src/gui/gui.zig
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ pub const inventory = struct { // MARK: inventory

pub fn init() void {
carried = ClientInventory.init(main.globalAllocator, 1, .serverShared, .{.hand = main.game.Player.id}, .{});
carriedItemSlot = ItemSlot.init(.{0, 0}, carried, 0, .default, .normal);
carriedItemSlot = ItemSlot.init(.{0, 0}, carried, 0, .{.texture = .default, .mode = .normal});
carriedItemSlot.renderFrame = false;
initialized = true;
isCrafting = false;
Expand Down
2 changes: 1 addition & 1 deletion src/gui/windows/chest.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub fn onOpen() void {
const row = HorizontalList.init();
for (0..10) |x| {
const index: usize = y*10 + x;
const slot = ItemSlot.init(.{0, 0}, openInventory, @intCast(index), .default, .normal);
const slot = ItemSlot.init(.{0, 0}, openInventory, @intCast(index), .{.texture = .default, .mode = .normal});
itemSlots.append(main.globalAllocator, slot);
row.add(slot);
}
Expand Down
4 changes: 2 additions & 2 deletions src/gui/windows/creative_inventory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ fn initContent() void {
const row = HorizontalList.init();
for (0..slotsPerRow) |_| {
if (i >= items.items.len) {
row.add(ItemSlot.init(.{0, 0}, inventory, i, .immutable, .immutable));
row.add(ItemSlot.init(.{0, 0}, inventory, i, .{.texture = .immutable, .mode = .immutable}));
} else {
row.add(ItemSlot.init(.{0, 0}, inventory, i, .default, .takeOnly));
row.add(ItemSlot.init(.{0, 0}, inventory, i, .{.texture = .default, .mode = .takeOnly}));
}
i += 1;
}
Expand Down
2 changes: 1 addition & 1 deletion src/gui/windows/hotbar.zig
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var itemSlots: [12]*ItemSlot = undefined;
pub fn onOpen() void {
const list = HorizontalList.init();
for (0..12) |i| {
itemSlots[i] = ItemSlot.init(.{0, 0}, Player.inventory, @intCast(i), .{.custom = hotbarSlotTexture}, .normal);
itemSlots[i] = ItemSlot.init(.{0, 0}, Player.inventory, @intCast(i), .{.texture = .{.custom = hotbarSlotTexture}, .mode = .normal});
list.add(itemSlots[i]);
}
list.finish(.{0, 0}, .center);
Expand Down
2 changes: 1 addition & 1 deletion src/gui/windows/inventory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub fn onOpen() void {
const row = HorizontalList.init();
for (0..10) |x| {
const index: usize = 12 + y*10 + x;
const slot = ItemSlot.init(.{0, 0}, Player.inventory, @intCast(index), .default, .normal);
const slot = ItemSlot.init(.{0, 0}, Player.inventory, @intCast(index), .{.texture = .default, .mode = .normal});
itemSlots[index - 12] = slot;
row.add(slot);
}
Expand Down
4 changes: 2 additions & 2 deletions src/gui/windows/inventory_crafting.zig
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ fn findAvailableRecipes(list: *VerticalList) bool {
if (col < remainder) itemsThisColumn += 1;
const columnList = VerticalList.init(.{0, 0}, std.math.inf(f32), 0);
for (0..itemsThisColumn) |_| {
columnList.add(ItemSlot.init(.{0, 0}, inv, i, .immutable, .immutable));
columnList.add(ItemSlot.init(.{0, 0}, inv, i, .{.texture = .immutable, .mode = .immutable}));
i += 1;
}
columnList.finish(.center);
rowList.add(columnList);
}
rowList.add(Icon.init(.{8, 0}, .{32, 32}, arrowTexture));
const itemSlot = ItemSlot.init(.{8, 0}, inv, @intCast(recipe.sourceItems.len), .craftingResult, .takeOnly);
const itemSlot = ItemSlot.init(.{8, 0}, inv, @intCast(recipe.sourceItems.len), .{.texture = .default, .mode = .normal});
rowList.add(itemSlot);
rowList.finish(.{0, 0}, .center);
list.add(rowList);
Expand Down
50 changes: 48 additions & 2 deletions src/gui/windows/workbench.zig
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,48 @@ fn updateResult(_: main.items.Inventory.Source) void {
craftingResultInv.super._items[0] = .{.item = Item{.proceduralItem = main.items.ProceduralItem.initFromInventory(craftingGridInv.super) orelse return}, .amount = 1};
}

fn updateModifierRestrictionVisuals(hoveredSlotNumber: usize) void {
var slotItems: [25]?main.items.BaseItemIndex = @splat(null);
for (itemSlots, 0..) |slot, i| {
slot.itemColor = 0xffffffff;
slotItems[i] = if (slot.inventory.getItem(i) == .baseItem) slot.inventory.getItem(i).baseItem else null;
}

const hoveredSlot = itemSlots[hoveredSlotNumber];
const material = hoveredSlot.inventory.getItem(hoveredSlotNumber).baseItem.material() orelse return;
if (material.modifiers.len == 0) return;
const x: i32 = if (hoveredSlotNumber != 0) @intCast(@mod(hoveredSlotNumber, 5)) else 0;
const y: i32 = @intCast(@divFloor(hoveredSlotNumber, 5));
for (0..25) |i| {
if (i == hoveredSlotNumber) continue;
var newTag: main.items.Checked = .always;
for (material.modifiers) |modifier| {
const searchedCheckedGrid = modifier.restriction.printCheckedGrid(slotItems, x, y)[i];
switch (searchedCheckedGrid) {
.validTag => {
newTag = .validTag;
break;
},
.invalidTag => if (newTag != .validTag) {
newTag = .invalidTag;
},
.notChecked => if ((newTag != .validTag) and (newTag != .invalidTag)) {
newTag = .invalidTag;
},
.always => if (newTag == .always) {
newTag = .always;
},
}
}
switch (newTag) {
.validTag => itemSlots[i].itemColor = 0xcfddffdd,
.invalidTag => itemSlots[i].itemColor = 0xefeebbbb,
.notChecked => itemSlots[i].itemColor = 0x33eeeeff,
.always => continue,
}
}
}

fn openInventory() void {
craftingGridInv = ClientInventory.init(main.globalAllocator, 25, .serverShared, .{.workbench = .{.playerId = main.game.Player.id, .proceduralItemIndex = proceduralItemTypes.items[currentProceduralItemType]}}, .{.onUpdateCallback = &updateResult, .canPutInto = items.ProceduralItem.canPutIntoWorkbenchCallback});
craftingResultInv = ClientInventory.init(main.globalAllocator, 1, .{.workbenchResult = craftingGridInv.super.id}, .other, .{});
Expand All @@ -72,7 +114,11 @@ fn openInventory() void {
for (0..5) |x| {
const index = x + y*5;
const slotInfo = proceduralItemTypes.items[currentProceduralItemType].slotInfos()[index];
const slot = ItemSlot.init(.{0, 0}, craftingGridInv, @intCast(index), if (slotInfo.disabled) .invisible else if (slotInfo.optional) .immutable else .default, if (slotInfo.disabled) .immutable else .normal);
const slot = ItemSlot.init(.{0, 0}, craftingGridInv, @intCast(index), .{
.texture = if (slotInfo.disabled) .invisible else if (slotInfo.optional) .immutable else .default,
.mode = if (slotInfo.disabled) .immutable else .normal,
.onHover = .initWithInt(updateModifierRestrictionVisuals, @intCast(index)),
});
itemSlots[index] = slot;
row.add(slot);
}
Expand All @@ -87,7 +133,7 @@ fn openInventory() void {
const buttonHeight = verticalThing.size[1];
const craftingResultList = HorizontalList.init();
craftingResultList.add(Icon.init(.{0, 0}, .{32, 32}, inventory_crafting.arrowTexture));
craftingResultList.add(ItemSlot.init(.{8, 0}, craftingResultInv, 0, .craftingResult, .takeOnly));
craftingResultList.add(ItemSlot.init(.{8, 0}, craftingResultInv, 0, .{.texture = .craftingResult, .mode = .takeOnly}));
craftingResultList.finish(.{padding, padding}, .center);
verticalThing.add(craftingResultList);
verticalThing.size[1] += buttonHeight + 2*padding; // Centering the thing
Expand Down
40 changes: 36 additions & 4 deletions src/items.zig
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,17 @@ pub const ModifierRestriction = struct {
satisfied: *const fn (data: *anyopaque, proceduralItem: *const ProceduralItem, x: i32, y: i32) bool,
loadFromZon: *const fn (allocator: NeverFailingAllocator, zon: ZonElement) *anyopaque,
printTooltip: *const fn (data: *anyopaque, outString: *main.ListManaged(u8)) void,
printCheckedGrid: *const fn (data: *anyopaque, givenGrid: [25]?main.items.BaseItemIndex, x: i32, y: i32) [25]Checked,
};

pub fn satisfied(self: ModifierRestriction, proceduralItem: *const ProceduralItem, x: i32, y: i32) bool {
return self.vTable.satisfied(self.data, proceduralItem, x, y);
}

pub fn printCheckedGrid(self: ModifierRestriction, givenGrid: [25]?main.items.BaseItemIndex, x: i32, y: i32) [25]Checked {
return self.vTable.printCheckedGrid(self.data, givenGrid, x, y);
}

pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) ModifierRestriction {
const id = zon.get([]const u8, "id") orelse "always";
const vTable = modifierRestrictions.get(id) orelse blk: {
Expand Down Expand Up @@ -814,6 +819,13 @@ const ProceduralItemProperty = enum {
}
};

pub const Checked = enum(u8) {
notChecked = 0,
invalidTag = 1,
validTag = 2,
always = 3,
};

pub const ProceduralItem = struct { // MARK: ProceduralItem
const craftingGridSize = 25;
const CraftingGridMask = std.meta.Int(.unsigned, craftingGridSize);
Expand Down Expand Up @@ -1005,10 +1017,25 @@ pub const ProceduralItem = struct { // MARK: ProceduralItem
return hash;
}

pub fn getItemAt(self: *const ProceduralItem, x: i32, y: i32) ?BaseItemIndex {
pub fn getItemAt(x: i32, y: i32, craftingGrid: [craftingGridSize]?BaseItemIndex) ?BaseItemIndex {
if (x < 0 or x >= 5) return null;
if (y < 0 or y >= 5) return null;
return self.craftingGrid[@intCast(x + y*5)];
return craftingGrid[@intCast(x + y*5)];
}

pub fn getCheckedAt(x: i32, y: i32, craftingGrid: [craftingGridSize]?BaseItemIndex, tag: Tag, checkedGrid: *[25]Checked) void {
if (x < 0 or x >= 5) return;
if (y < 0 or y >= 5) return;
const item = ProceduralItem.getItemAt(x, y, craftingGrid);
const gridPos: usize = @intCast(x + y*5);
if (item == null) {
checkedGrid[gridPos] = .invalidTag;
} else if (item.?.hasTag(tag)) {
checkedGrid[gridPos] = .validTag;
} else {
std.log.debug("found invalid", .{});
checkedGrid[gridPos] = .invalidTag;
}
}

pub fn getProperty(self: *ProceduralItem, prop: ProceduralItemProperty) f32 {
Expand Down Expand Up @@ -1232,10 +1259,14 @@ pub const Item = union(ItemType) { // MARK: Item
};
}

pub fn render(self: Item, pos: Vec2f, slotSize: Vec2f, border: f32) void {
pub fn render(self: Item, pos: Vec2f, slotSize: Vec2f, border: f32, color: u32) void {
const itemTexture = self.getTexture();
itemTexture.bindTo(0);
graphics.draw.boundImage(pos + @as(Vec2f, @splat(border)), slotSize - @as(Vec2f, @splat(2*border)));
{
const oldColor = graphics.draw.setColor(color);
defer graphics.draw.restoreColor(oldColor);
graphics.draw.boundImage(pos + @as(Vec2f, @splat(border)), slotSize - @as(Vec2f, @splat(2*border)));
}

if (self == .proceduralItem) {
const proceduralItem = self.proceduralItem;
Expand Down Expand Up @@ -1410,6 +1441,7 @@ pub fn globalInit() void {
.satisfied = comptime main.meta.castFunctionSelfToAnyopaque(ModifierRestrictionStruct.satisfied),
.loadFromZon = comptime main.meta.castFunctionReturnToAnyopaque(ModifierRestrictionStruct.loadFromZon),
.printTooltip = comptime main.meta.castFunctionSelfToAnyopaque(ModifierRestrictionStruct.printTooltip),
.printCheckedGrid = comptime main.meta.castFunctionSelfToAnyopaque(ModifierRestrictionStruct.printCheckedGrid),
}) catch unreachable;
}
Inventory.client.init();
Expand Down
5 changes: 5 additions & 0 deletions src/proceduralItem/modifiers/restrictions/always.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ pub fn satisfied(_: *const anyopaque, _: *const ProceduralItem, _: i32, _: i32)
return true;
}

pub fn printCheckedGrid(_: *const anyopaque, _: [25]?main.items.BaseItemIndex, _: i32, _: i32) [25]main.items.Checked {
const checkedGrid: [25]main.items.Checked = @splat(.always);
return checkedGrid;
}

pub fn loadFromZon(_: NeverFailingAllocator, _: ZonElement) *const anyopaque {
return undefined;
}
Expand Down
27 changes: 27 additions & 0 deletions src/proceduralItem/modifiers/restrictions/and.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,33 @@ pub fn satisfied(self: *const And, proceduralItem: *const ProceduralItem, x: i32
return true;
}

pub fn printCheckedGrid(self: *const And, givenGrid: [25]?main.items.BaseItemIndex, x: i32, y: i32) [25]main.items.Checked {
var checkedGrid: [25]main.items.Checked = @splat(.notChecked);
for (0..25) |i| {
var newTag: main.items.Checked = .always;
for (self.children) |child| {
const searchedCheckedGrid = child.printCheckedGrid(givenGrid, x, y)[i];
switch (searchedCheckedGrid) {
.invalidTag => {
newTag = .invalidTag;
break;
},
.validTag => if (newTag != .invalidTag) {
newTag = .validTag;
},
.notChecked => if ((newTag != .validTag) and (newTag != .invalidTag)) {
newTag = .invalidTag;
},
.always => if (newTag == .always) {
newTag = .always;
},
}
}
checkedGrid[i] = newTag;
}
return checkedGrid;
}

pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) *const And {
const result = allocator.create(And);
const childrenZon = zon.getChild("children").toSlice();
Expand Down
12 changes: 11 additions & 1 deletion src/proceduralItem/modifiers/restrictions/encased.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,22 @@ pub fn satisfied(self: *const Encased, proceduralItem: *const ProceduralItem, x:
var count: usize = 0;
for ([_]i32{-1, 0, 1}) |dx| {
for ([_]i32{-1, 0, 1}) |dy| {
if ((proceduralItem.getItemAt(x + dx, y + dy) orelse continue).hasTag(self.tag)) count += 1;
if ((ProceduralItem.getItemAt(x + dx, y + dy, proceduralItem.craftingGrid) orelse continue).hasTag(self.tag)) count += 1;
}
}
return count >= self.amount;
}

pub fn printCheckedGrid(self: *const Encased, givenGrid: [25]?main.items.BaseItemIndex, x: i32, y: i32) [25]main.items.Checked {
var checkedGrid: [25]main.items.Checked = @splat(.notChecked);
for ([_]i32{-1, 0, 1}) |dx| {
for ([_]i32{-1, 0, 1}) |dy| {
ProceduralItem.getCheckedAt(x + dx, y + dy, givenGrid, self.tag, &checkedGrid);
}
}
return checkedGrid;
}

pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) *const Encased {
const result = allocator.create(Encased);
result.* = .{
Expand Down
5 changes: 5 additions & 0 deletions src/proceduralItem/modifiers/restrictions/not.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ pub fn satisfied(self: *const Not, proceduralItem: *const ProceduralItem, x: i32
return !self.child.satisfied(proceduralItem, x, y);
}

pub fn printCheckedGrid(self: *const Not, givenGrid: [25]?main.items.BaseItemIndex, x: i32, y: i32) [25]main.items.Checked {
const childCheckedGrid = self.child.printCheckedGrid(givenGrid, x, y);
return childCheckedGrid;
}

pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) *const Not {
const result = allocator.create(Not);
result.* = .{
Expand Down
Loading
Loading