the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "com.mojang.nbt.h"
3#include "BrewingStandTileEntity.h"
4#include "SharedConstants.h"
5#include "net.minecraft.h"
6#include "net.minecraft.world.level.h"
7#include "net.minecraft.world.item.h"
8#include "net.minecraft.world.item.alchemy.h"
9
10int slotsForUp [] = { BrewingStandTileEntity::INGREDIENT_SLOT };
11int slotsForOtherFaces [] = { 0, 1, 2 };
12
13intArray BrewingStandTileEntity::SLOTS_FOR_UP = intArray(slotsForUp, 1);
14intArray BrewingStandTileEntity::SLOTS_FOR_OTHER_FACES = intArray(slotsForOtherFaces, 3);
15
16BrewingStandTileEntity::BrewingStandTileEntity()
17{
18 brewTime = 0;
19 items = ItemInstanceArray(4);
20 name = L"";
21}
22
23BrewingStandTileEntity::~BrewingStandTileEntity()
24{
25 delete [] items.data;
26}
27
28wstring BrewingStandTileEntity::getName()
29{
30 return hasCustomName() ? name : app.GetString(IDS_TILE_BREWINGSTAND);
31}
32
33wstring BrewingStandTileEntity::getCustomName()
34{
35 return hasCustomName() ? name : L"";
36}
37
38bool BrewingStandTileEntity::hasCustomName()
39{
40 return !name.empty();
41}
42
43void BrewingStandTileEntity::setCustomName(const wstring &name)
44{
45 this->name = name;
46}
47
48unsigned int BrewingStandTileEntity::getContainerSize()
49{
50 return items.length;
51}
52
53void BrewingStandTileEntity::tick()
54{
55 if (brewTime > 0)
56 {
57 brewTime--;
58
59 if (brewTime == 0)
60 {
61 // apply ingredients to all potions
62 doBrew();
63 setChanged();
64 }
65 else if (!isBrewable())
66 {
67 brewTime = 0;
68 setChanged();
69 }
70 else if (ingredientId != items[INGREDIENT_SLOT]->id)
71 {
72 brewTime = 0;
73 setChanged();
74 }
75 }
76 else if (isBrewable())
77 {
78 brewTime = SharedConstants::TICKS_PER_SECOND * PotionBrewing::BREWING_TIME_SECONDS;
79 ingredientId = items[INGREDIENT_SLOT]->id;
80 }
81
82 int newCount = getPotionBits();
83 if (newCount != lastPotionCount)
84 {
85 lastPotionCount = newCount;
86 level->setData(x, y, z, newCount, Tile::UPDATE_CLIENTS);
87 }
88
89 TileEntity::tick();
90}
91
92int BrewingStandTileEntity::getBrewTime()
93{
94 return brewTime;
95}
96
97bool BrewingStandTileEntity::isBrewable()
98{
99 if (items[INGREDIENT_SLOT] == NULL || items[INGREDIENT_SLOT]->count <= 0)
100 {
101 return false;
102 }
103 shared_ptr<ItemInstance> ingredient = items[INGREDIENT_SLOT];
104 if (PotionBrewing::SIMPLIFIED_BREWING)
105 {
106 if (!Item::items[ingredient->id]->hasPotionBrewingFormula())
107 {
108 return false;
109 }
110
111 bool oneResult = false;
112 for (int dest = 0; dest < 3; dest++)
113 {
114 if (items[dest] != NULL && items[dest]->id == Item::potion_Id)
115 {
116 int currentBrew = items[dest]->getAuxValue();
117 int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) );
118
119 if (!PotionItem::isThrowable(currentBrew) && PotionItem::isThrowable(newBrew))
120 {
121 oneResult = true;
122 break;
123 }
124
125 vector<MobEffectInstance *> *currentEffects = Item::potion->getMobEffects(currentBrew);
126 vector<MobEffectInstance *> *newEffects = Item::potion->getMobEffects(newBrew);
127
128 // 4J - this code replaces an expression "currentEffects.equals(newEffects)" in the java.
129 // TODO - find out whether actually checking pointers to MobEffectInstance classes for equality
130 // is of any use
131 bool equals = false;
132 if( ( currentEffects != NULL ) && ( newEffects != NULL ) )
133 {
134 if( currentEffects->size() == newEffects->size() )
135 {
136 if( std::equal(currentEffects->begin(), currentEffects->end(), newEffects->begin() ) )
137 {
138 equals = true;
139 }
140 }
141 }
142
143 if ((currentBrew > 0 && currentEffects == newEffects) ||
144 (currentEffects != NULL && (equals || newEffects == NULL)))
145 {
146 }
147 else if (currentBrew != newBrew)
148 {
149 oneResult = true;
150 break;
151 }
152 }
153 }
154 return oneResult;
155
156 }
157 else
158 {
159 if (!Item::items[ingredient->id]->hasPotionBrewingFormula() && ingredient->id != Item::bucket_water_Id && ingredient->id != Item::netherwart_seeds_Id)
160 {
161 return false;
162 }
163 bool isWater = ingredient->id == Item::bucket_water_Id;
164
165 // at least one destination potion must have a result
166 bool oneResult = false;
167 for (int dest = 0; dest < 3; dest++)
168 {
169 if (items[dest] != NULL && items[dest]->id == Item::potion_Id)
170 {
171 int currentBrew = items[dest]->getAuxValue();
172 int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) );
173 if (currentBrew != newBrew)
174 {
175 oneResult = true;
176 break;
177 }
178 }
179 else if (isWater && items[dest] != NULL && items[dest]->id == Item::glassBottle_Id)
180 {
181 oneResult = true;
182 break;
183 }
184 }
185 return oneResult;
186 }
187}
188
189void BrewingStandTileEntity::doBrew()
190{
191 if (!isBrewable())
192 {
193 return;
194 }
195
196 shared_ptr<ItemInstance> ingredient = items[INGREDIENT_SLOT];
197
198 if (PotionBrewing::SIMPLIFIED_BREWING)
199 {
200 for (int dest = 0; dest < 3; dest++)
201 {
202 if (items[dest] != NULL && items[dest]->id == Item::potion_Id)
203 {
204 int currentBrew = items[dest]->getAuxValue();
205 int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) );
206
207 vector<MobEffectInstance *> *currentEffects = Item::potion->getMobEffects(currentBrew);
208 vector<MobEffectInstance *> *newEffects = Item::potion->getMobEffects(newBrew);
209
210 // 4J - this code replaces an expression "currentEffects.equals(newEffects)" in the java.
211 // TODO - find out whether actually checking pointers to MobEffectInstance classes for equality
212 // is of any use
213 bool equals = false;
214 if( ( currentEffects != NULL ) && ( newEffects != NULL ) )
215 {
216 if( currentEffects->size() == newEffects->size() )
217 {
218 if( std::equal(currentEffects->begin(), currentEffects->end(), newEffects->begin() ) )
219 {
220 equals = true;
221 }
222 }
223 }
224
225 if ((currentBrew > 0 && currentEffects == newEffects) ||
226 (currentEffects != NULL && (equals || newEffects == NULL)))
227 {
228 if (!PotionItem::isThrowable(currentBrew) && PotionItem::isThrowable(newBrew))
229 {
230 items[dest]->setAuxValue(newBrew);
231 }
232
233 }
234 else if (currentBrew != newBrew)
235 {
236 items[dest]->setAuxValue(newBrew);
237 }
238
239 }
240 }
241
242 }
243 else
244 {
245 bool isWater = ingredient->id == Item::bucket_water_Id;
246
247 for (int dest = 0; dest < 3; dest++)
248 {
249 if (items[dest] != NULL && items[dest]->id == Item::potion_Id)
250 {
251 int currentBrew = items[dest]->getAuxValue();
252 int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) );
253 items[dest]->setAuxValue(newBrew);
254 }
255 else if (isWater && items[dest] != NULL && items[dest]->id == Item::glassBottle_Id)
256 {
257 items[dest] = shared_ptr<ItemInstance>(new ItemInstance(Item::potion));
258 }
259 }
260 }
261
262 if (Item::items[ingredient->id]->hasCraftingRemainingItem())
263 {
264 items[INGREDIENT_SLOT] = shared_ptr<ItemInstance>(new ItemInstance(Item::items[ingredient->id]->getCraftingRemainingItem()));
265 }
266 else
267 {
268 items[INGREDIENT_SLOT]->count--;
269 if (items[INGREDIENT_SLOT]->count <= 0)
270 {
271 items[INGREDIENT_SLOT] = nullptr;
272 }
273 }
274}
275
276int BrewingStandTileEntity::applyIngredient(int currentBrew, shared_ptr<ItemInstance> ingredient)
277{
278 if (ingredient == NULL)
279 {
280 return currentBrew;
281 }
282 if (!PotionBrewing::SIMPLIFIED_BREWING)
283 {
284#if !(_SIMPLIFIED_BREWING)
285 // 4J Stu - SIMPLIFIED_BREWING is on, so we never use this
286 if (ingredient->id == Item::bucket_water_Id)
287 {
288 return PotionBrewing::applyBrew(currentBrew, PotionBrewing::MOD_WATER);
289 }
290 if (ingredient->id == Item::netherwart_seeds_Id)
291 {
292 return PotionBrewing::stirr(currentBrew);
293 }
294#endif
295 }
296 if (Item::items[ingredient->id]->hasPotionBrewingFormula())
297 {
298 return PotionBrewing::applyBrew(currentBrew, Item::items[ingredient->id]->getPotionBrewingFormula());
299 }
300 return currentBrew;
301}
302
303void BrewingStandTileEntity::load(CompoundTag *base)
304{
305 TileEntity::load(base);
306
307 ListTag<CompoundTag> *inventoryList = (ListTag<CompoundTag> *) base->getList(L"Items");
308 delete [] items.data;
309 items = ItemInstanceArray(getContainerSize());
310 for (int i = 0; i < inventoryList->size(); i++)
311 {
312 CompoundTag *tag = inventoryList->get(i);
313 int slot = tag->getByte(L"Slot");
314 if (slot >= 0 && slot < items.length) items[slot] = ItemInstance::fromTag(tag);
315 }
316
317 brewTime = base->getShort(L"BrewTime");
318 if (base->contains(L"CustomName")) name = base->getString(L"CustomName");
319}
320
321void BrewingStandTileEntity::save(CompoundTag *base)
322{
323 TileEntity::save(base);
324
325 base->putShort(L"BrewTime", (short) (brewTime));
326 ListTag<CompoundTag> *listTag = new ListTag<CompoundTag>();
327
328 for (int i = 0; i < items.length; i++)
329 {
330 if (items[i] != NULL)
331 {
332 CompoundTag *tag = new CompoundTag();
333 tag->putByte(L"Slot", (byte) i);
334 items[i]->save(tag);
335 listTag->add(tag);
336 }
337 }
338 base->put(L"Items", listTag);
339 if (hasCustomName()) base->putString(L"CustomName", name);
340}
341
342shared_ptr<ItemInstance> BrewingStandTileEntity::getItem(unsigned int slot)
343{
344 if (slot >= 0 && slot < items.length)
345 {
346 return items[slot];
347 }
348 return nullptr;
349}
350
351shared_ptr<ItemInstance> BrewingStandTileEntity::removeItem(unsigned int slot, int count)
352{
353 // 4J Stu - Changed the implementation of this function to be the same as ChestTileEntity to enable the "Pickup Half"
354 // option on the ingredients slot
355 // Fix for #65373 - TU8: Content: UI: Command "Take Half" in the Brewing Stand interface doesn't work as intended.
356
357 if (slot >= 0 && slot < items.length && items[slot] != NULL)
358 {
359 if (items[slot]->count <= count)
360 {
361 shared_ptr<ItemInstance> item = items[slot];
362 items[slot] = nullptr;
363 this->setChanged();
364 // 4J Stu - Fix for duplication glitch
365 if(item->count <= 0) return nullptr;
366 return item;
367 }
368 else
369 {
370 shared_ptr<ItemInstance> i = items[slot]->remove(count);
371 if (items[slot]->count == 0) items[slot] = nullptr;
372 this->setChanged();
373 // 4J Stu - Fix for duplication glitch
374 if(i->count <= 0) return nullptr;
375 return i;
376 }
377 }
378 return nullptr;
379}
380
381shared_ptr<ItemInstance> BrewingStandTileEntity::removeItemNoUpdate(int slot)
382{
383 if (slot >= 0 && slot < items.length)
384 {
385 shared_ptr<ItemInstance> item = items[slot];
386 items[slot] = nullptr;
387 return item;
388 }
389 return nullptr;
390}
391
392void BrewingStandTileEntity::setItem(unsigned int slot, shared_ptr<ItemInstance> item)
393{
394 if (slot >= 0 && slot < items.length)
395 {
396 items[slot] = item;
397 }
398}
399
400int BrewingStandTileEntity::getMaxStackSize() const
401{
402 // this value is not used for the potion slots
403 return 64;
404}
405
406bool BrewingStandTileEntity::stillValid(shared_ptr<Player> player)
407{
408 if (level->getTileEntity(x, y, z) != shared_from_this()) return false;
409 if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false;
410 return true;
411}
412
413void BrewingStandTileEntity::startOpen()
414{
415}
416
417void BrewingStandTileEntity::stopOpen()
418{
419}
420
421bool BrewingStandTileEntity::canPlaceItem(int slot, shared_ptr<ItemInstance> item)
422{
423 if (slot == INGREDIENT_SLOT)
424 {
425 if (PotionBrewing::SIMPLIFIED_BREWING)
426 {
427 return Item::items[item->id]->hasPotionBrewingFormula();
428 }
429 else
430 {
431 return Item::items[item->id]->hasPotionBrewingFormula() || item->id == Item::netherwart_seeds_Id || item->id == Item::bucket_water_Id;
432 }
433 }
434
435 return item->id == Item::potion_Id || item->id == Item::glassBottle_Id;
436}
437
438void BrewingStandTileEntity::setBrewTime(int value)
439{
440 brewTime = value;
441}
442
443int BrewingStandTileEntity::getPotionBits()
444{
445 int newCount = 0;
446 for (int potion = 0; potion < 3; potion++)
447 {
448 if (items[potion] != NULL)
449 {
450 newCount |= (1 << potion);
451 }
452 }
453 return newCount;
454}
455
456intArray BrewingStandTileEntity::getSlotsForFace(int face)
457{
458 if (face == Facing::UP)
459 {
460 return SLOTS_FOR_UP;
461 }
462
463 return SLOTS_FOR_OTHER_FACES;
464}
465
466bool BrewingStandTileEntity::canPlaceItemThroughFace(int slot, shared_ptr<ItemInstance> item, int face)
467{
468 return canPlaceItem(slot, item);
469}
470
471bool BrewingStandTileEntity::canTakeItemThroughFace(int slot, shared_ptr<ItemInstance> item, int face)
472{
473 return true;
474}
475
476// 4J Added
477shared_ptr<TileEntity> BrewingStandTileEntity::clone()
478{
479 shared_ptr<BrewingStandTileEntity> result = shared_ptr<BrewingStandTileEntity>( new BrewingStandTileEntity() );
480 TileEntity::clone(result);
481
482 result->brewTime = brewTime;
483 result->lastPotionCount = lastPotionCount;
484 result->ingredientId = ingredientId;
485
486 for (unsigned int i = 0; i < items.length; i++)
487 {
488 if (items.data[i] != NULL)
489 {
490 result->items.data[i] = ItemInstance::clone(items.data[i]);
491 }
492 }
493 return result;
494}