Browse Source

item stack stuff, mockable Item

opengl-renderer-broken
Martin Dørum 4 years ago
parent
commit
d4f08974a5

+ 1
- 0
libswan/CMakeLists.txt View File

@@ -6,6 +6,7 @@ add_library(libswan SHARED
src/Game.cc
src/gfxutil.cc
src/Item.cc
src/ItemStack.cc
src/Mod.cc
src/OS.cc
src/Resource.cc

+ 14
- 1
libswan/include/swan/Item.h View File

@@ -12,15 +12,28 @@ public:
struct Builder {
std::string name;
std::string image;
int max_stack = 64;
};

Item(const ResourceManager &resources, const Builder &builder):
name_(builder.name), image_(resources.getImage(builder.image)) {}
name_(builder.name), image_(resources.getImage(builder.image)),
max_stack_(builder.max_stack) {}

const std::string name_;
const ImageResource &image_;
const int max_stack_;

static std::unique_ptr<Item> createInvalid(Context &ctx);

// For testing, we want to be able to create Items without an actual ImageResource.
// Tests can create a MockItem class which inherits from Item and uses this ctor,
// as long as the test never does anything which tries to follow the image_ member.
// Eventually, this should become unnecessary, because we don't need to require
// a complete ImageResource for a headless server, but for now, this will suffice.
protected:
Item(const Builder &builder):
name_(builder.name), image_(*(ImageResource *)this),
max_stack_(builder.max_stack) {}
};

}

+ 1
- 33
libswan/include/swan/ItemStack.h View File

@@ -1,17 +1,11 @@
#pragma once

#include <optional>

#include "log.h"

namespace Swan {

class Item;

class ItemStack {
public:
static constexpr int MAX_COUNT = 64;

ItemStack(Item *item, int count = 0): item_(item), count_(count) {

// We don't want a "partially empty" state.
@@ -26,33 +20,7 @@ public:
bool empty() { return item_ == nullptr; }

// Insert as much of 'st' as possible, returning the leftovers
ItemStack insert(ItemStack st) {

// If this is an empty item stack, just copy over st
if (empty()) {
item_ = st.item_;
count_ = st.count_;
st.item_ = nullptr;
st.count_ = 0;
return st;
}

// If st is a stack of a different kind of item, we don't want it
if (st.item_ != item_)
return st;

// Merge
count_ += st.count_;
if (count_ > MAX_COUNT) {
st.count_ = count_ - MAX_COUNT;
count_ = MAX_COUNT;
} else {
st.count_ = 0;
st.item_ = nullptr;
}

return st;
}
ItemStack insert(ItemStack st);

private:
Item *item_;

+ 35
- 0
libswan/src/ItemStack.cc View File

@@ -0,0 +1,35 @@
#include "ItemStack.h"

#include "Item.h"

namespace Swan {

ItemStack ItemStack::insert(ItemStack st) {

// If this is an empty item stack, just copy over st
if (empty()) {
item_ = st.item_;
count_ = st.count_;
st.item_ = nullptr;
st.count_ = 0;
return st;
}

// If st is a stack of a different kind of item, we don't want it
if (st.item_ != item_)
return st;

// Merge
count_ += st.count_;
if (count_ > item_->max_stack_) {
st.count_ = count_ - item_->max_stack_;
count_ = item_->max_stack_;
} else {
st.count_ = 0;
st.item_ = nullptr;
}

return st;
}

}

+ 39
- 18
libswan/test/ItemStack.t.cc View File

@@ -1,17 +1,18 @@
#include "ItemStack.h"
#include "Item.h"

#include "lib/test.h"

// Most of these tests need two ItemStacks.
// ItemStack requires an Item pointer, and only ever looks at the pointer.
// Therefore, we'll just give the ItemStacks pointers to ints.
static int itint1, itint2;
static Swan::Item *item1 = (Swan::Item *)&itint1;
static Swan::Item *item2 = (Swan::Item *)&itint2;
class MockItem: public Swan::Item {
public:
MockItem(const Builder &builder): Item(builder) {}
};

test("Basic insert") {
Swan::ItemStack s1(item1, 0);
Swan::ItemStack s2(item1, 10);
MockItem item1({ .name = "item1", .image = "no" });

Swan::ItemStack s1(&item1, 0);
Swan::ItemStack s2(&item1, 10);
s2 = s1.insert(s2);

expecteq(s1.count(), 10);
@@ -19,8 +20,11 @@ test("Basic insert") {
}

test("Insert rejects different items") {
Swan::ItemStack s1(item1, 5);
Swan::ItemStack s2(item2, 10);
MockItem item1({ .name = "item1", .image = "no" });
MockItem item2({ .name = "itemm2", .image = "no" });

Swan::ItemStack s1(&item1, 5);
Swan::ItemStack s2(&item2, 10);
Swan::ItemStack ret = s1.insert(s2);

expecteq(s1.count(), 5);
@@ -30,18 +34,33 @@ test("Insert rejects different items") {
}

test("Insert never overflows") {
Swan::ItemStack s1(item1, 40);
Swan::ItemStack s2(item1, 40);
MockItem item1({ .name = "item1", .image = "no" });

Swan::ItemStack s1(&item1, 40);
Swan::ItemStack s2(&item1, 40);
s2 = s1.insert(s2);

expecteq(s1.count(), Swan::ItemStack::MAX_COUNT);
expecteq(s2.count(), 80 - Swan::ItemStack::MAX_COUNT);
expecteq(s1.count(), item1.max_stack_);
expecteq(s2.count(), 80 - item1.max_stack_);
}

test("Insert respects max_stack_") {
MockItem item1({ .name = "item1", .image = "no", .max_stack = 20 });

Swan::ItemStack s1(&item1, 15);
Swan::ItemStack s2(&item1, 19);
s2 = s1.insert(s2);

expecteq(s1.count(), 20);
expecteq(s2.count(), 14);
}

test("When insert empties an ItemStack, it should have its item nulled out") {
Swan::ItemStack s1(item1, 10);
Swan::ItemStack s2(item1, 10);
MockItem item1({ .name = "item1", .image = "no" });
MockItem item2({ .name = "itemm2", .image = "no" });

Swan::ItemStack s1(&item1, 10);
Swan::ItemStack s2(&item1, 10);
s2 = s1.insert(s2);

expecteq(s1.count(), 20);
@@ -51,12 +70,14 @@ test("When insert empties an ItemStack, it should have its item nulled out") {
}

test("Insert on an empty item stack") {
MockItem item1({ .name = "item1", .image = "no" });

Swan::ItemStack s1(nullptr, 0);
Swan::ItemStack s2(item1, 10);
Swan::ItemStack s2(&item1, 10);
s2 = s1.insert(s2);

expecteq(s1.count(), 10);
expecteq(s1.item(), item1);
expecteq(s1.item(), &item1);
expecteq(s2.count(), 0);
expect(s2.empty());
}

Loading…
Cancel
Save