001 package org.bukkit.inventory;
002
003 import org.bukkit.GameMode;
004 import org.bukkit.entity.HumanEntity;
005 import org.bukkit.event.inventory.InventoryType;
006
007 /**
008 * Represents a view linking two inventories and a single player (whose
009 * inventory may or may not be one of the two).
010 * <p>
011 * Note: If you implement this interface but fail to satisfy the expected
012 * contracts of certain methods, there's no guarantee that the game will work
013 * as it should.
014 */
015 public abstract class InventoryView {
016 public final static int OUTSIDE = -999;
017 /**
018 * Represents various extra properties of certain inventory windows.
019 */
020 public enum Property {
021 /**
022 * The progress of the down-pointing arrow in a brewing inventory.
023 */
024 BREW_TIME(0, InventoryType.BREWING),
025 /**
026 * The progress of the right-pointing arrow in a furnace inventory.
027 */
028 COOK_TIME(0, InventoryType.FURNACE),
029 /**
030 * The progress of the flame in a furnace inventory.
031 */
032 BURN_TIME(1, InventoryType.FURNACE),
033 /**
034 * How many total ticks the current fuel should last.
035 */
036 TICKS_FOR_CURRENT_FUEL(2, InventoryType.FURNACE),
037 /**
038 * In an enchanting inventory, the top button's experience level
039 * value.
040 */
041 ENCHANT_BUTTON1(0, InventoryType.ENCHANTING),
042 /**
043 * In an enchanting inventory, the middle button's experience level
044 * value.
045 */
046 ENCHANT_BUTTON2(1, InventoryType.ENCHANTING),
047 /**
048 * In an enchanting inventory, the bottom button's experience level
049 * value.
050 */
051 ENCHANT_BUTTON3(2, InventoryType.ENCHANTING);
052 int id;
053 InventoryType style;
054 private Property(int id, InventoryType appliesTo) {
055 this.id = id;
056 style = appliesTo;
057 }
058
059 public InventoryType getType() {
060 return style;
061 }
062
063 /**
064 *
065 * @deprecated Magic value
066 */
067 @Deprecated
068 public int getId() {
069 return id;
070 }
071 }
072 /**
073 * Get the upper inventory involved in this transaction.
074 *
075 * @return the inventory
076 */
077 public abstract Inventory getTopInventory();
078
079 /**
080 * Get the lower inventory involved in this transaction.
081 *
082 * @return the inventory
083 */
084 public abstract Inventory getBottomInventory();
085
086 /**
087 * Get the player viewing.
088 *
089 * @return the player
090 */
091 public abstract HumanEntity getPlayer();
092
093 /**
094 * Determine the type of inventory involved in the transaction. This
095 * indicates the window style being shown. It will never return PLAYER,
096 * since that is common to all windows.
097 *
098 * @return the inventory type
099 */
100 public abstract InventoryType getType();
101
102 /**
103 * Sets one item in this inventory view by its raw slot ID.
104 * <p>
105 * Note: If slot ID -999 is chosen, it may be expected that the item is
106 * dropped on the ground. This is not required behaviour, however.
107 *
108 * @param slot The ID as returned by InventoryClickEvent.getRawSlot()
109 * @param item The new item to put in the slot, or null to clear it.
110 */
111 public void setItem(int slot, ItemStack item) {
112 if (slot != OUTSIDE) {
113 if (slot < getTopInventory().getSize()) {
114 getTopInventory().setItem(convertSlot(slot),item);
115 } else {
116 getBottomInventory().setItem(convertSlot(slot),item);
117 }
118 } else {
119 getPlayer().getWorld().dropItemNaturally(getPlayer().getLocation(), item);
120 }
121 }
122
123 /**
124 * Gets one item in this inventory view by its raw slot ID.
125 *
126 * @param slot The ID as returned by InventoryClickEvent.getRawSlot()
127 * @return The item currently in the slot.
128 */
129 public ItemStack getItem(int slot) {
130 if (slot == OUTSIDE) {
131 return null;
132 }
133 if (slot < getTopInventory().getSize()) {
134 return getTopInventory().getItem(convertSlot(slot));
135 } else {
136 return getBottomInventory().getItem(convertSlot(slot));
137 }
138 }
139
140 /**
141 * Sets the item on the cursor of one of the viewing players.
142 *
143 * @param item The item to put on the cursor, or null to remove the item
144 * on their cursor.
145 */
146 public final void setCursor(ItemStack item) {
147 getPlayer().setItemOnCursor(item);
148 }
149
150 /**
151 * Get the item on the cursor of one of the viewing players.
152 *
153 * @return The item on the player's cursor, or null if they aren't holding
154 * one.
155 */
156 public final ItemStack getCursor() {
157 return getPlayer().getItemOnCursor();
158 }
159
160 /**
161 * Converts a raw slot ID into its local slot ID into whichever of the two
162 * inventories the slot points to.
163 * <p>
164 * If the raw slot refers to the upper inventory, it will be returned
165 * unchanged and thus be suitable for getTopInventory().getItem(); if it
166 * refers to the lower inventory, the output will differ from the input
167 * and be suitable for getBottomInventory().getItem().
168 *
169 * @param rawSlot The raw slot ID.
170 * @return The converted slot ID.
171 */
172 public final int convertSlot(int rawSlot) {
173 int numInTop = getTopInventory().getSize();
174 if (rawSlot < numInTop) {
175 return rawSlot;
176 }
177 int slot = rawSlot - numInTop;
178 if (getPlayer().getGameMode() == GameMode.CREATIVE && getType() == InventoryType.PLAYER) {
179 return slot;
180 }
181 if (getType() == InventoryType.CRAFTING) {
182 if(slot < 4) return 39 - slot;
183 else slot -= 4;
184 }
185 if (slot >= 27) slot -= 27;
186 else slot += 9;
187 return slot;
188 }
189
190 /**
191 * Closes the inventory view.
192 */
193 public final void close() {
194 getPlayer().closeInventory();
195 }
196
197 /**
198 * Check the total number of slots in this view, combining the upper and
199 * lower inventories.
200 * <p>
201 * Note though that it's possible for this to be greater than the sum of
202 * the two inventories if for example some slots are not being used.
203 *
204 * @return The total size
205 */
206 public final int countSlots() {
207 return getTopInventory().getSize() + getBottomInventory().getSize();
208 }
209
210 /**
211 * Sets an extra property of this inventory if supported by that
212 * inventory, for example the state of a progress bar.
213 *
214 * @param prop the window property to update
215 * @param value the new value for the window property
216 * @return true if the property was updated successfully, false if the
217 * property is not supported by that inventory
218 */
219 public final boolean setProperty(Property prop, int value) {
220 return getPlayer().setWindowProperty(prop, value);
221 }
222
223 /**
224 * Get the title of this inventory window.
225 *
226 * @return The title.
227 */
228 public final String getTitle() {
229 return getTopInventory().getTitle();
230 }
231 }