1 /*
2  * Copyright (c) 2017-2019 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: Copyright (c) 2017-2019 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/selery/source/selery/item/slot.d, selery/item/slot.d)
28  */
29 module selery.item.slot;
30 
31 import std.conv : to;
32 
33 import selery.about;
34 import selery.item.item : Item;
35 import selery.item.items : Items;
36 
37 /**
38  * Container for an item stack that has always a value.
39  * If the slot is not empty, an Item instance and the count
40  * can be stored.
41  * 
42  * Conventionally an empty slot is always constructed using Slot(null)
43  */
44 struct Slot {
45 
46 	private Item n_item;
47 	public ubyte count;
48 
49 	/**
50 	 * Creates a slot with an item and its highest value as count.
51 	 * Example:
52 	 * ---
53 	 * assert(Slot(new Items.DiamondSword()).count == 1);
54 	 * assert(Slot(new Items.Snowball()).count == 16);
55 	 * assert(Slot(null).count == 0);
56 	 * ---
57 	 */
58 	public @safe @nogc this(Item item) {
59 		if(item !is null) {
60 			this.n_item = item;
61 			this.count = this.item.max;
62 		}
63 	}
64 
65 	/**
66 	 * Creates a slot giving an item and a count in range 0..255 (unsigned byte).
67 	 * Setting an higher value it's impossible due to protocol's limitations.
68 	 * Example:
69 	 * ---
70 	 * assert(Slot(new Items.DiamondSword(), 22).count == 22);
71 	 * assert(Slot(new Items.Snowball(), 2).count == 2);
72 	 * assert(Slot(null, 100).count == 0);
73 	 * ---
74 	 */
75 	public @safe @nogc this(Item item, ubyte count) {
76 		this(item);
77 		if(this.item !is null) this.count = count;
78 	}
79 
80 	/**
81 	 * Gets the slot's item.
82 	 */
83 	public pure nothrow @property @safe @nogc Item item() {
84 		return this.n_item;
85 	}
86 
87 	/**
88 	 * Checks whether or not the slot is empty.
89 	 * A slot is considered empty when its count is equal to 0 or
90 	 * when its item is null.
91 	 * Example:
92 	 * ---
93 	 * Slot slot = Slot(null);
94 	 * assert(slot.empty);
95 	 * 
96 	 * slot = Slot(new Items.Snowball(), 1);
97 	 * assert(!slot.empty);
98 	 * 
99 	 * slot.count--;
100 	 * assert(slot.empty);
101 	 * ---
102 	 */
103 	public pure nothrow @property @safe @nogc bool empty() {
104 		return this.count == 0 || this.item is null;
105 	}
106 
107 	/**
108 	 * Checks whether or not the slot is full.
109 	 * The slot is considered full when its count is equals or
110 	 * higher than the item's max stackable size.
111 	 * Example:
112 	 * ---
113 	 * assert(Slot(new Items.DiamondSword(), 1).full);
114 	 * assert(!Slot(new Items.Snowball(), 15).full);
115 	 * ---
116 	 * 
117 	 * This property should be called only if the slot isn't empty due
118 	 * to its call on the item's property, that can be null.
119 	 * ---
120 	 * if(!slot.empty && slot.full) { ... }
121 	 * ---
122 	 */
123 	public pure nothrow @property @safe @nogc bool full() {
124 		return this.count >= this.item.max;
125 	}
126 
127 	/**
128 	 * Fills the slot setting the count as the max stacking value
129 	 * of the item.
130 	 * Example:
131 	 * ---
132 	 * Slot slot = Slot(new Item.Snowball(), 1);
133 	 * assert(slot.count == 1);
134 	 * slot.fill();
135 	 * assert(slot.count == 16);
136 	 * ---
137 	 * 
138 	 * Like full, this function requires item to not be null due to
139 	 * its call on its max property.
140 	 * ---
141 	 * if(slot.item !is null) {
142 	 *    slot.fill();
143 	 * }
144 	 * ---
145 	 */
146 	public pure nothrow @safe @nogc void fill() {
147 		this.count = this.item.max;
148 	}
149 
150 	public bool opEquals(Slot slot) {
151 		return this.empty == slot.empty && (this.empty || this.count == slot.count && this.item == slot.item);
152 	}
153 
154 	public bool opEquals(Item item) {
155 		return this.empty == !!(item is null) && (this.empty || this.item == item);
156 	}
157 
158 	public bool opEquals(item_t item) {
159 		return this.empty == (item == Items.air) && (this.empty || this.item == item);
160 	}
161 
162 	public string toString() {
163 		return "Slot(" ~ (this.empty ? "null" : (this.item.toString() ~ " x" ~ this.count.to!string)) ~ ")";
164 	}
165 
166 }