Przeglądaj źródła

item stack stuff, mockable Item

opengl-renderer-broken
Martin Dørum 4 lat temu
rodzic
commit
d4f08974a5

+ 1
- 0
libswan/CMakeLists.txt Wyświetl plik

src/Game.cc src/Game.cc
src/gfxutil.cc src/gfxutil.cc
src/Item.cc src/Item.cc
src/ItemStack.cc
src/Mod.cc src/Mod.cc
src/OS.cc src/OS.cc
src/Resource.cc src/Resource.cc

+ 14
- 1
libswan/include/swan/Item.h Wyświetl plik

struct Builder { struct Builder {
std::string name; std::string name;
std::string image; std::string image;
int max_stack = 64;
}; };


Item(const ResourceManager &resources, const Builder &builder): 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 std::string name_;
const ImageResource &image_; const ImageResource &image_;
const int max_stack_;


static std::unique_ptr<Item> createInvalid(Context &ctx); 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 Wyświetl plik

#pragma once #pragma once


#include <optional>

#include "log.h"

namespace Swan { namespace Swan {


class Item; class Item;


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

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


// We don't want a "partially empty" state. // We don't want a "partially empty" state.
bool empty() { return item_ == nullptr; } bool empty() { return item_ == nullptr; }


// Insert as much of 'st' as possible, returning the leftovers // 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: private:
Item *item_; Item *item_;

+ 35
- 0
libswan/src/ItemStack.cc Wyświetl plik

#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 Wyświetl plik

#include "ItemStack.h" #include "ItemStack.h"
#include "Item.h"


#include "lib/test.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") { 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); s2 = s1.insert(s2);


expecteq(s1.count(), 10); expecteq(s1.count(), 10);
} }


test("Insert rejects different items") { 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); Swan::ItemStack ret = s1.insert(s2);


expecteq(s1.count(), 5); expecteq(s1.count(), 5);
} }


test("Insert never overflows") { 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); 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") { 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); s2 = s1.insert(s2);


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


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

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


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

Ładowanie…
Anuluj
Zapisz