the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 474 lines 13 kB view raw
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}