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 "net.minecraft.world.item.h"
3#include "net.minecraft.world.item.enchantment.h"
4#include "net.minecraft.world.entity.h"
5#include "net.minecraft.world.entity.player.h"
6#include "net.minecraft.world.damagesource.h"
7#include "WeighedRandom.h"
8#include "EnchantmentHelper.h"
9
10Random EnchantmentHelper::random;
11
12int EnchantmentHelper::getEnchantmentLevel(int enchantmentId, shared_ptr<ItemInstance> piece)
13{
14 if (piece == NULL)
15 {
16 return 0;
17 }
18 ListTag<CompoundTag> *enchantmentTags = piece->getEnchantmentTags();
19 if (enchantmentTags == NULL)
20 {
21 return 0;
22 }
23 for (int i = 0; i < enchantmentTags->size(); i++)
24 {
25 int type = enchantmentTags->get(i)->getShort((wchar_t *)ItemInstance::TAG_ENCH_ID);
26 int level = enchantmentTags->get(i)->getShort((wchar_t *)ItemInstance::TAG_ENCH_LEVEL);
27
28 if (type == enchantmentId)
29 {
30 return level;
31 }
32 }
33 return 0;
34}
35
36unordered_map<int, int> *EnchantmentHelper::getEnchantments(shared_ptr<ItemInstance> item)
37{
38 unordered_map<int, int> *result = new unordered_map<int, int>();
39 ListTag<CompoundTag> *list = item->id == Item::enchantedBook_Id ? Item::enchantedBook->getEnchantments(item) : item->getEnchantmentTags();
40
41 if (list != NULL)
42 {
43 for (int i = 0; i < list->size(); i++)
44 {
45 int type = list->get(i)->getShort((wchar_t *)ItemInstance::TAG_ENCH_ID);
46 int level = list->get(i)->getShort((wchar_t *)ItemInstance::TAG_ENCH_LEVEL);
47
48 result->insert( unordered_map<int, int>::value_type(type, level));
49 }
50 }
51
52 return result;
53}
54
55void EnchantmentHelper::setEnchantments(unordered_map<int, int> *enchantments, shared_ptr<ItemInstance> item)
56{
57 ListTag<CompoundTag> *list = new ListTag<CompoundTag>();
58
59 //for (int id : enchantments.keySet())
60 for(AUTO_VAR(it, enchantments->begin()); it != enchantments->end(); ++it)
61 {
62 int id = it->first;
63 CompoundTag *tag = new CompoundTag();
64
65 tag->putShort((wchar_t *)ItemInstance::TAG_ENCH_ID, (short) id);
66 tag->putShort((wchar_t *)ItemInstance::TAG_ENCH_LEVEL, (short)(int)it->second);
67
68 list->add(tag);
69
70 if (item->id == Item::enchantedBook_Id)
71 {
72 Item::enchantedBook->addEnchantment(item, new EnchantmentInstance(id, it->second));
73 }
74 }
75
76 if (list->size() > 0)
77 {
78 if (item->id != Item::enchantedBook_Id)
79 {
80 item->addTagElement(L"ench", list);
81 }
82 }
83 else if (item->hasTag())
84 {
85 item->getTag()->remove(L"ench");
86 }
87}
88
89int EnchantmentHelper::getEnchantmentLevel(int enchantmentId, ItemInstanceArray inventory)
90{
91 if (inventory.data == NULL) return 0;
92 int bestLevel = 0;
93 //for (ItemInstance piece : inventory)
94 for(unsigned int i = 0; i < inventory.length; ++i)
95 {
96 int newLevel = getEnchantmentLevel(enchantmentId, inventory[i]);
97 if (newLevel > bestLevel)
98 {
99 bestLevel = newLevel;
100 }
101 }
102 return bestLevel;
103}
104
105void EnchantmentHelper::runIterationOnItem(EnchantmentIterationMethod &method, shared_ptr<ItemInstance> piece)
106{
107 if (piece == NULL)
108 {
109 return;
110 }
111 ListTag<CompoundTag> *enchantmentTags = piece->getEnchantmentTags();
112 if (enchantmentTags == NULL)
113 {
114 return;
115 }
116 for (int i = 0; i < enchantmentTags->size(); i++)
117 {
118 int type = enchantmentTags->get(i)->getShort((wchar_t *)ItemInstance::TAG_ENCH_ID);
119 int level = enchantmentTags->get(i)->getShort((wchar_t *)ItemInstance::TAG_ENCH_LEVEL);
120
121 if (Enchantment::enchantments[type] != NULL)
122 {
123 method.doEnchantment(Enchantment::enchantments[type], level);
124 }
125 }
126}
127
128void EnchantmentHelper::runIterationOnInventory(EnchantmentIterationMethod &method, ItemInstanceArray inventory)
129{
130 //for (ItemInstance piece : inventory)
131 for(unsigned int i = 0; i < inventory.length; ++i)
132 {
133 runIterationOnItem(method, inventory[i]);
134 }
135}
136
137void EnchantmentHelper::GetDamageProtectionIteration::doEnchantment(Enchantment *enchantment, int level)
138{
139 sum += enchantment->getDamageProtection(level, source);
140}
141
142EnchantmentHelper::GetDamageProtectionIteration EnchantmentHelper::getDamageProtectionIteration;
143
144/**
145* Fetches the protection value for enchanted items.
146*
147* @param inventory
148* @param source
149* @return
150*/
151int EnchantmentHelper::getDamageProtection(ItemInstanceArray armor, DamageSource *source)
152{
153 getDamageProtectionIteration.sum = 0;
154 getDamageProtectionIteration.source = source;
155
156 runIterationOnInventory(getDamageProtectionIteration, armor);
157
158 if (getDamageProtectionIteration.sum > 25)
159 {
160 getDamageProtectionIteration.sum = 25;
161 }
162 // enchantment protection is on the scale of 0 to 25, where 20 or more
163 // will nullify nearly all damage (there will be damage spill)
164 return ((getDamageProtectionIteration.sum + 1) >> 1) + random.nextInt((getDamageProtectionIteration.sum >> 1) + 1);
165}
166
167void EnchantmentHelper::GetDamageBonusIteration::doEnchantment(Enchantment *enchantment, int level)
168{
169 sum += enchantment->getDamageBonus(level, target);
170}
171
172
173EnchantmentHelper::GetDamageBonusIteration EnchantmentHelper::getDamageBonusIteration;
174
175/**
176*
177* @param inventory
178* @param target
179* @return
180*/
181float EnchantmentHelper::getDamageBonus(shared_ptr<LivingEntity> source, shared_ptr<LivingEntity> target)
182{
183
184 getDamageBonusIteration.sum = 0;
185 getDamageBonusIteration.target = target;
186
187 runIterationOnItem(getDamageBonusIteration, source->getCarriedItem() );
188
189 return getDamageBonusIteration.sum;
190}
191
192int EnchantmentHelper::getKnockbackBonus(shared_ptr<LivingEntity> source, shared_ptr<LivingEntity> target)
193{
194 return getEnchantmentLevel(Enchantment::knockback->id, source->getCarriedItem() );
195}
196
197int EnchantmentHelper::getFireAspect(shared_ptr<LivingEntity> source)
198{
199 return getEnchantmentLevel(Enchantment::fireAspect->id, source->getCarriedItem());
200}
201
202int EnchantmentHelper::getOxygenBonus(shared_ptr<LivingEntity> source)
203{
204 return getEnchantmentLevel(Enchantment::drownProtection->id, source->getEquipmentSlots() );
205}
206
207int EnchantmentHelper::getDiggingBonus(shared_ptr<LivingEntity> source)
208{
209 return getEnchantmentLevel(Enchantment::diggingBonus->id, source->getCarriedItem() );
210}
211
212int EnchantmentHelper::getDigDurability(shared_ptr<LivingEntity> source)
213{
214 return getEnchantmentLevel(Enchantment::digDurability->id, source->getCarriedItem() );
215}
216
217bool EnchantmentHelper::hasSilkTouch(shared_ptr<LivingEntity> source)
218{
219 return getEnchantmentLevel(Enchantment::untouching->id, source->getCarriedItem() ) > 0;
220}
221
222int EnchantmentHelper::getDiggingLootBonus(shared_ptr<LivingEntity> source)
223{
224 return getEnchantmentLevel(Enchantment::resourceBonus->id, source->getCarriedItem() );
225}
226
227int EnchantmentHelper::getKillingLootBonus(shared_ptr<LivingEntity> source)
228{
229 return getEnchantmentLevel(Enchantment::lootBonus->id, source->getCarriedItem() );
230}
231
232bool EnchantmentHelper::hasWaterWorkerBonus(shared_ptr<LivingEntity> source)
233{
234 return getEnchantmentLevel(Enchantment::waterWorker->id, source->getEquipmentSlots() ) > 0;
235}
236
237int EnchantmentHelper::getArmorThorns(shared_ptr<LivingEntity> source)
238{
239 return getEnchantmentLevel(Enchantment::thorns->id, source->getEquipmentSlots());
240}
241
242shared_ptr<ItemInstance> EnchantmentHelper::getRandomItemWith(Enchantment *enchantment, shared_ptr<LivingEntity> source)
243{
244 ItemInstanceArray items = source->getEquipmentSlots();
245 for(unsigned int i = 0; i < items.length; ++i)
246 {
247 shared_ptr<ItemInstance> item = items[i];
248 if (item != NULL && getEnchantmentLevel(enchantment->id, item) > 0)
249 {
250 return item;
251 }
252 }
253
254 return nullptr;
255}
256
257/**
258*
259* @param random
260* @param slot
261* The table slot, 0-2
262* @param bookcases
263* How many book cases that are found around the table.
264* @param itemInstance
265* Which item that is being enchanted.
266* @return The enchantment cost, 0 means unchantable, 50 is max.
267*/
268int EnchantmentHelper::getEnchantmentCost(Random *random, int slot, int bookcases, shared_ptr<ItemInstance> itemInstance)
269{
270 Item *item = itemInstance->getItem();
271 int itemValue = item->getEnchantmentValue();
272
273 if (itemValue <= 0)
274 {
275 // not enchantable
276 return 0;
277 }
278
279 // 4J Stu - Updated function to 1.3 version for TU7
280 if (bookcases > 15)
281 {
282 bookcases = 15;
283 }
284
285 int selected = random->nextInt(8) + 1 + (bookcases >> 1) + random->nextInt(bookcases + 1);
286 if (slot == 0)
287 {
288 return max((selected / 3), 1);
289 }
290 if (slot == 1)
291 {
292 return max(selected, bookcases * 2);
293 }
294 return selected;
295}
296
297shared_ptr<ItemInstance> EnchantmentHelper::enchantItem(Random *random, shared_ptr<ItemInstance> itemInstance, int enchantmentCost)
298{
299 vector<EnchantmentInstance *> *newEnchantment = EnchantmentHelper::selectEnchantment(random, itemInstance, enchantmentCost);
300 bool isBook = itemInstance->id == Item::book_Id;
301
302 if (isBook) itemInstance->id = Item::enchantedBook_Id;
303
304 if (newEnchantment != NULL)
305 {
306 for(AUTO_VAR(it, newEnchantment->begin()); it != newEnchantment->end(); ++it)
307 {
308 EnchantmentInstance *e = *it;
309 if (isBook)
310 {
311 Item::enchantedBook->addEnchantment(itemInstance, e);
312 }
313 else
314 {
315 itemInstance->enchant(e->enchantment, e->level);
316 }
317 delete e;
318 }
319 delete newEnchantment;
320 }
321 return itemInstance;
322}
323
324/**
325*
326* @param random
327* @param itemInstance
328* @param enchantmentCost
329* @return
330*/
331vector<EnchantmentInstance *> *EnchantmentHelper::selectEnchantment(Random *random, shared_ptr<ItemInstance> itemInstance, int enchantmentCost)
332{
333 // withdraw bonus from item
334 Item *item = itemInstance->getItem();
335 int itemBonus = item->getEnchantmentValue();
336
337 if (itemBonus <= 0)
338 {
339 return NULL;
340 }
341 // 4J Stu - Update function to 1.3 version for TU7
342 itemBonus /= 2;
343 itemBonus = 1 + random->nextInt((itemBonus >> 1) + 1) + random->nextInt((itemBonus >> 1) + 1);
344
345 int enchantmentValue = itemBonus + enchantmentCost;
346
347 // the final enchantment cost will have another random span of +- 15%
348 float deviation = (random->nextFloat() + random->nextFloat() - 1.0f) * .15f;
349 int realValue = (int) ((float) enchantmentValue * (1.0f + deviation) + .5f);
350 if (realValue < 1)
351 {
352 realValue = 1;
353 }
354
355 vector<EnchantmentInstance *> *results = NULL;
356
357 unordered_map<int, EnchantmentInstance *> *availableEnchantments = getAvailableEnchantmentResults(realValue, itemInstance);
358 if (availableEnchantments != NULL && !availableEnchantments->empty())
359 {
360 vector<WeighedRandomItem *> values;
361 for(AUTO_VAR(it, availableEnchantments->begin()); it != availableEnchantments->end(); ++it)
362 {
363 values.push_back(it->second);
364 }
365 EnchantmentInstance *instance = (EnchantmentInstance *) WeighedRandom::getRandomItem(random, &values);
366 values.clear();
367
368 if (instance != NULL)
369 {
370 results = new vector<EnchantmentInstance *>();
371 results->push_back( instance->copy() ); // 4J Stu - Inserting a copy so we can clear memory from the availableEnchantments collection
372
373 int bonusChance = realValue;
374 while (random->nextInt(50) <= bonusChance)
375 {
376
377 // remove incompatible enchantments from previous result
378 //final Iterator<Integer> mapIter = availableEnchantments.keySet().iterator();
379 //while (mapIter.hasNext())
380 for(AUTO_VAR(it, availableEnchantments->begin()); it != availableEnchantments->end();)
381 {
382 int nextEnchantment = it->first;//mapIter.next();
383 bool valid = true;
384 //for (EnchantmentInstance *current : results)
385 for(AUTO_VAR(resIt, results->begin()); resIt != results->end(); ++resIt)
386 {
387 EnchantmentInstance *current = *resIt;
388 if (!current->enchantment->isCompatibleWith(Enchantment::enchantments[nextEnchantment]))
389 {
390 valid = false;
391 break;
392 }
393 }
394 if (!valid)
395 {
396 //mapIter.remove();
397 delete it->second;
398 it = availableEnchantments->erase(it);
399 }
400 else
401 {
402 ++it;
403 }
404 }
405
406 if (!availableEnchantments->empty())
407 {
408 for(AUTO_VAR(it, availableEnchantments->begin()); it != availableEnchantments->end(); ++it)
409 {
410 values.push_back(it->second);
411 }
412 EnchantmentInstance *nextInstance = (EnchantmentInstance *) WeighedRandom::getRandomItem(random, &values);
413 values.clear();
414 results->push_back( nextInstance->copy() ); // 4J Stu - Inserting a copy so we can clear memory from the availableEnchantments collection
415 }
416
417 bonusChance >>= 1;
418 }
419 }
420 }
421 if(availableEnchantments != NULL)
422 {
423 for(AUTO_VAR(it, availableEnchantments->begin()); it != availableEnchantments->end(); ++it)
424 {
425 delete it->second;
426 }
427 delete availableEnchantments;
428 }
429
430 return results;
431}
432
433unordered_map<int, EnchantmentInstance *> *EnchantmentHelper::getAvailableEnchantmentResults(int value, shared_ptr<ItemInstance> itemInstance)
434{
435 Item *item = itemInstance->getItem();
436 unordered_map<int, EnchantmentInstance *> *results = NULL;
437
438 bool isBook = itemInstance->id == Item::book_Id;
439
440 //for (Enchantment e : Enchantment.enchantments)
441 for(unsigned int i = 0; i < Enchantment::enchantments.length; ++i)
442 {
443 Enchantment *e = Enchantment::enchantments[i];
444 if (e == NULL)
445 {
446 continue;
447 }
448
449 // Only picks "normal" enchantments, no specialcases
450 if (!e->category->canEnchant(item) && !isBook)
451 {
452 continue;
453 }
454
455 for (int level = e->getMinLevel(); level <= e->getMaxLevel(); level++)
456 {
457 if (value >= e->getMinCost(level) && value <= e->getMaxCost(level))
458 {
459 if (results == NULL)
460 {
461 results = new unordered_map<int, EnchantmentInstance *>();
462 }
463 AUTO_VAR(it, results->find(e->id));
464 if(it != results->end())
465 {
466 delete it->second;
467 }
468 (*results)[e->id] = new EnchantmentInstance(e, level);
469 }
470 }
471 }
472
473 return results;
474}