the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 923 lines 25 kB view raw
1#include "stdafx.h" 2#include "..\Minecraft.Client\Minecraft.h" 3#include "net.minecraft.world.effect.h" 4#include "JavaMath.h" 5#include "SharedConstants.h" 6#include "PotionBrewing.h" 7 8const int PotionBrewing::DEFAULT_APPEARANCES[] = 9{ 10 IDS_POTION_PREFIX_MUNDANE, 11 IDS_POTION_PREFIX_UNINTERESTING, 12 IDS_POTION_PREFIX_BLAND, 13 IDS_POTION_PREFIX_CLEAR, 14 IDS_POTION_PREFIX_MILKY, 15 IDS_POTION_PREFIX_DIFFUSE, 16 IDS_POTION_PREFIX_ARTLESS, 17 IDS_POTION_PREFIX_THIN, 18 IDS_POTION_PREFIX_AWKWARD, 19 IDS_POTION_PREFIX_FLAT, 20 IDS_POTION_PREFIX_BULKY, 21 IDS_POTION_PREFIX_BUNGLING, 22 IDS_POTION_PREFIX_BUTTERED, 23 IDS_POTION_PREFIX_SMOOTH, 24 IDS_POTION_PREFIX_SUAVE, 25 IDS_POTION_PREFIX_DEBONAIR, 26 IDS_POTION_PREFIX_THICK, 27 IDS_POTION_PREFIX_ELEGANT, 28 IDS_POTION_PREFIX_FANCY, 29 IDS_POTION_PREFIX_CHARMING, 30 IDS_POTION_PREFIX_DASHING, 31 IDS_POTION_PREFIX_REFINED, 32 IDS_POTION_PREFIX_CORDIAL, 33 IDS_POTION_PREFIX_SPARKLING, 34 IDS_POTION_PREFIX_POTENT, 35 IDS_POTION_PREFIX_FOUL, 36 IDS_POTION_PREFIX_ODORLESS, 37 IDS_POTION_PREFIX_RANK, 38 IDS_POTION_PREFIX_HARSH, 39 IDS_POTION_PREFIX_ACRID, 40 IDS_POTION_PREFIX_GROSS, 41 IDS_POTION_PREFIX_STINKY, 42}; 43 44// bit 4 is the "enabler," lit by nether seeds 45 46 // bits 0-3 are effect identifiers 47 // 0001 - regeneration 48 // 0010 - move speed 49 // 0011 - fire resist 50 // 0100 - poison 51 // 0101 - heal 52 // 0110 - night vision 53 // 0111 - invisibility 54 // 1000 - weakness 55 // 1001 - damage boost 56 // 1010 - move slow 57 // 1011 - 58 // 1100 - harm 59 // 1101 - 60 // 1110 - 61 // 1111 - 62 63/* 4J-JEV: Fix for #81196, 64 * Bit 13 is always set in functional potions. 65 * Therefore if bit 13 is on, don't use netherwart! 66 * Added "&!13" which requires that bit 13 be turned off. 67 */ 68const wstring PotionBrewing::MOD_NETHERWART = L"+4&!13"; // L"+4" 69 70#if _SIMPLIFIED_BREWING 71const wstring PotionBrewing::MOD_WATER = L""; 72const wstring PotionBrewing::MOD_SUGAR = L"-0+1-2-3&4-4+13"; 73const wstring PotionBrewing::MOD_GHASTTEARS = L"+0-1-2-3&4-4+13"; 74const wstring PotionBrewing::MOD_SPIDEREYE = L"-0-1+2-3&4-4+13"; 75const wstring PotionBrewing::MOD_FERMENTEDEYE = L"-0+3-4+13"; 76const wstring PotionBrewing::MOD_SPECKLEDMELON = L"+0-1+2-3&4-4+13"; 77const wstring PotionBrewing::MOD_BLAZEPOWDER = L"+0-1-2+3&4-4+13"; 78const wstring PotionBrewing::MOD_GOLDENCARROT = L"-0+1+2-3+13&4-4"; 79const wstring PotionBrewing::MOD_MAGMACREAM = L"+0+1-2-3&4-4+13"; 80const wstring PotionBrewing::MOD_REDSTONE = L"-5+6-7"; // redstone increases duration 81const wstring PotionBrewing::MOD_GLOWSTONE = L"+5-6-7"; // glowstone increases amplification 82// 4J Stu - Don't require bit 13 to be set. We don't use it in the creative menu. Side effect is you can make a (virtually useless) Splash Mundane potion with water bottle and gunpowder 83const wstring PotionBrewing::MOD_GUNPOWDER = L"+14";//&13-13"; // gunpowder makes them throwable! // gunpowder requires 13 and sets 14 84#else 85const wstring PotionBrewing::MOD_WATER = L"-1-3-5-7-9-11-13"; 86const wstring PotionBrewing::MOD_SUGAR = L"+0"; 87const wstring PotionBrewing::MOD_GHASTTEARS = L"+11"; 88const wstring PotionBrewing::MOD_SPIDEREYE = L"+10+7+5"; 89const wstring PotionBrewing::MOD_FERMENTEDEYE = L"+14+9"; 90const wstring PotionBrewing::MOD_SPECKLEDMELON = L""; 91const wstring PotionBrewing::MOD_BLAZEPOWDER = L"+14"; 92const wstring PotionBrewing::MOD_MAGMACREAM = L"+14+6+1"; 93const wstring PotionBrewing::MOD_REDSTONE = L""; // redstone increases duration 94const wstring PotionBrewing::MOD_GLOWSTONE = L""; // glowstone increases amplification 95const wstring PotionBrewing::MOD_GUNPOWDER = L""; // gunpowder makes them throwable! // gunpowder requires 13 and sets 14 96#endif 97 98PotionBrewing::intStringMap PotionBrewing::potionEffectDuration; 99PotionBrewing::intStringMap PotionBrewing::potionEffectAmplifier; 100 101unordered_map<int, int> PotionBrewing::cachedColors; 102 103void PotionBrewing::staticCtor() 104{ 105#if _SIMPLIFIED_BREWING 106 potionEffectDuration.insert(intStringMap::value_type( MobEffect::regeneration->getId(), L"0 & !1 & !2 & !3 & 0+6" )); 107 potionEffectDuration.insert(intStringMap::value_type( MobEffect::movementSpeed->getId(), L"!0 & 1 & !2 & !3 & 1+6" )); 108 potionEffectDuration.insert(intStringMap::value_type( MobEffect::fireResistance->getId(), L"0 & 1 & !2 & !3 & 0+6" )); 109 potionEffectDuration.insert(intStringMap::value_type( MobEffect::heal->getId(), L"0 & !1 & 2 & !3" )); 110 potionEffectDuration.insert(intStringMap::value_type( MobEffect::poison->getId(), L"!0 & !1 & 2 & !3 & 2+6" )); 111 potionEffectDuration.insert(intStringMap::value_type( MobEffect::weakness->getId(), L"!0 & !1 & !2 & 3 & 3+6" )); 112 potionEffectDuration.insert(intStringMap::value_type( MobEffect::harm->getId(), L"!0 & !1 & 2 & 3" )); 113 potionEffectDuration.insert(intStringMap::value_type( MobEffect::movementSlowdown->getId(), L"!0 & 1 & !2 & 3 & 3+6" )); 114 potionEffectDuration.insert(intStringMap::value_type( MobEffect::damageBoost->getId(), L"0 & !1 & !2 & 3 & 3+6" )); 115 potionEffectDuration.insert(intStringMap::value_type( MobEffect::nightVision->getId(), L"!0 & 1 & 2 & !3 & 2+6" )); 116 potionEffectDuration.insert(intStringMap::value_type( MobEffect::invisibility->getId(), L"!0 & 1 & 2 & 3 & 2+6" )); 117 118 // glowstone increases amplification 119 potionEffectAmplifier.insert(intStringMap::value_type( MobEffect::movementSpeed->getId(), L"5" )); 120 potionEffectAmplifier.insert(intStringMap::value_type( MobEffect::digSpeed->getId(), L"5" )); 121 potionEffectAmplifier.insert(intStringMap::value_type( MobEffect::damageBoost->getId(), L"5" )); 122 potionEffectAmplifier.insert(intStringMap::value_type( MobEffect::regeneration->getId(), L"5" )); 123 potionEffectAmplifier.insert(intStringMap::value_type( MobEffect::harm->getId(), L"5" )); 124 potionEffectAmplifier.insert(intStringMap::value_type( MobEffect::heal->getId(), L"5" )); 125 potionEffectAmplifier.insert(intStringMap::value_type( MobEffect::damageResistance->getId(), L"5" )); 126 potionEffectAmplifier.insert(intStringMap::value_type( MobEffect::poison->getId(), L"5" )); 127#else 128 potionEffectDuration.put(movementSpeed.getId(), "!10 & !4 & 5*2+0 & >1 | !7 & !4 & 5*2+0 & >1"); 129 potionEffectDuration.put(movementSlowdown.getId(), "10 & 7 & !4 & 7+5+1-0"); 130 potionEffectDuration.put(digSpeed.getId(), "2 & 12+2+6-1-7 & <8"); 131 potionEffectDuration.put(digSlowdown.getId(), "!2 & !1*2-9 & 14-5"); 132 potionEffectDuration.put(damageBoost.getId(), "9 & 3 & 9+4+5 & <11"); 133 potionEffectDuration.put(weakness.getId(), "=1>5>7>9+3-7-2-11 & !9 & !0"); 134 potionEffectDuration.put(heal.getId(), "11 & <6"); 135 potionEffectDuration.put(harm.getId(), "!11 & 1 & 10 & !7"); 136 potionEffectDuration.put(jump.getId(), "8 & 2+0 & <5"); 137 potionEffectDuration.put(confusion.getId(), "8*2-!7+4-11 & !2 | 13 & 11 & 2*3-1-5"); 138 potionEffectDuration.put(regeneration.getId(), "!14 & 13*3-!0-!5-8"); 139 potionEffectDuration.put(damageResistance.getId(), "10 & 4 & 10+5+6 & <9"); 140 potionEffectDuration.put(fireResistance.getId(), "14 & !5 & 6-!1 & 14+13+12"); 141 potionEffectDuration.put(waterBreathing.getId(), "0+1+12 & !6 & 10 & !11 & !13"); 142 potionEffectDuration.put(invisibility.getId(), "2+5+13-0-4 & !7 & !1 & >5"); 143 potionEffectDuration.put(blindness.getId(), "9 & !1 & !5 & !3 & =3"); 144 potionEffectDuration.put(nightVision.getId(), "8*2-!7 & 5 & !0 & >3"); 145 potionEffectDuration.put(hunger.getId(), ">4>6>8-3-8+2"); 146 potionEffectDuration.put(poison.getId(), "12+9 & !13 & !0"); 147 148 potionEffectAmplifier.put(movementSpeed.getId(), "7+!3-!1"); 149 potionEffectAmplifier.put(digSpeed.getId(), "1+0-!11"); 150 potionEffectAmplifier.put(damageBoost.getId(), "2+7-!12"); 151 potionEffectAmplifier.put(heal.getId(), "11+!0-!1-!14"); 152 potionEffectAmplifier.put(harm.getId(), "!11-!14+!0-!1"); 153 potionEffectAmplifier.put(damageResistance.getId(), "12-!2"); 154 potionEffectAmplifier.put(poison.getId(), "14>5"); 155#endif 156} 157 158bool PotionBrewing::isWrappedLit(int brew, int position) 159{ 160 return (brew & (1 << (position % NUM_BITS))) != 0; 161} 162 163bool PotionBrewing::isLit(int brew, int position) 164{ 165 return (brew & (1 << position)) != 0; 166} 167 168int PotionBrewing::isBit(int brew, int position) 169{ 170 return isLit(brew, position) ? 1 : 0; 171} 172 173int PotionBrewing::isNotBit(int brew, int position) 174{ 175 return isLit(brew, position) ? 0 : 1; 176} 177 178int PotionBrewing::getAppearanceValue(int brew) 179{ 180 return valueOf(brew, 5, 4, 3, 2, 1); 181} 182 183int PotionBrewing::getColorValue(vector<MobEffectInstance *> *effects) 184{ 185 ColourTable *colourTable = Minecraft::GetInstance()->getColourTable(); 186 187 int baseColor = colourTable->getColor( eMinecraftColour_Potion_BaseColour ); 188 189 if (effects == NULL || effects->empty()) 190 { 191 return baseColor; 192 } 193 194 float red = 0; 195 float green = 0; 196 float blue = 0; 197 float count = 0; 198 199 //for (MobEffectInstance effect : effects){ 200 for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it) 201 { 202 MobEffectInstance *effect = *it; 203 int potionColor = colourTable->getColor( MobEffect::effects[effect->getId()]->getColor() ); 204 205 for (int potency = 0; potency <= effect->getAmplifier(); potency++) 206 { 207 red += (float) ((potionColor >> 16) & 0xff) / 255.0f; 208 green += (float) ((potionColor >> 8) & 0xff) / 255.0f; 209 blue += (float) ((potionColor >> 0) & 0xff) / 255.0f; 210 count++; 211 } 212 } 213 214 red = (red / count) * 255.0f; 215 green = (green / count) * 255.0f; 216 blue = (blue / count) * 255.0f; 217 218 return ((int) red) << 16 | ((int) green) << 8 | ((int) blue); 219} 220 221bool PotionBrewing::areAllEffectsAmbient(vector<MobEffectInstance *> *effects) 222{ 223 for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it) 224 { 225 MobEffectInstance *effect = *it; 226 if (!effect->isAmbient()) return false; 227 } 228 229 return true; 230} 231 232int PotionBrewing::getColorValue(int brew, bool includeDisabledEffects) 233{ 234 if (!includeDisabledEffects) 235 { 236 AUTO_VAR(colIt, cachedColors.find(brew)); 237 if (colIt != cachedColors.end()) 238 { 239 return colIt->second;//cachedColors.get(brew); 240 } 241 vector<MobEffectInstance *> *effects = getEffects(brew, false); 242 int color = getColorValue(effects); 243 if(effects != NULL) 244 { 245 for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it) 246 { 247 MobEffectInstance *effect = *it; 248 delete effect; 249 } 250 delete effects; 251 } 252 cachedColors.insert( std::pair<int,int>(brew, color) ); 253 return color; 254 } 255 256 return getColorValue(getEffects(brew, includeDisabledEffects)); 257} 258 259int PotionBrewing::getSmellValue(int brew) 260{ 261 return valueOf(brew, 12, 11, 6, 4, 0); 262} 263 264int PotionBrewing::getAppearanceName(int brew) 265{ 266 int value = getAppearanceValue(brew); 267 return DEFAULT_APPEARANCES[value]; 268} 269 270int PotionBrewing::constructParsedValue(bool isNot, bool hasMultiplier, bool isNeg, int countCompare, int valuePart, int multiplierPart, int brew) 271{ 272 int value = 0; 273 if (isNot) 274 { 275 value = isNotBit(brew, valuePart); 276 } 277#if !(_SIMPLIFIED_BREWING) 278 else if (countCompare != NO_COUNT) // Never true for simplified brewing 279 { 280 if (countCompare == EQUAL_COUNT && countOnes(brew) == valuePart) 281 { 282 value = 1; 283 } 284 else if (countCompare == GREATER_COUNT && countOnes(brew) > valuePart) 285 { 286 value = 1; 287 } 288 else if (countCompare == LESS_COUNT && countOnes(brew) < valuePart) 289 { 290 value = 1; 291 } 292 } 293#endif 294 else 295 { 296 value = isBit(brew, valuePart); 297 } 298#if !(_SIMPLIFIED_BREWING) 299 if (hasMultiplier) // Always false for simplified brewing 300 { 301 value *= multiplierPart; 302 } 303#endif 304 if (isNeg) 305 { 306 value *= -1; 307 } 308 return value; 309} 310 311int PotionBrewing::countOnes(int brew) 312{ 313 int c = 0; 314 for (; brew > 0; c++) 315 { 316 brew &= brew - 1; 317 } 318 return c; 319} 320 321#if _SIMPLIFIED_BREWING 322// 4J Stu - Trimmed this function to remove all the unused features for simplified brewing 323int PotionBrewing::parseEffectFormulaValue(const wstring &definition, int start, int end, int brew) 324{ 325 if (start >= definition.length() || end < 0 || start >= end) 326 { 327 return 0; 328 } 329 330 // split by and 331 int andIndex = (int)definition.find_first_of(L'&', start); 332 if (andIndex >= 0 && andIndex < end) 333 { 334 int leftSide = parseEffectFormulaValue(definition, start, andIndex - 1, brew); 335 if (leftSide <= 0) 336 { 337 return 0; 338 } 339 340 int rightSide = parseEffectFormulaValue(definition, andIndex + 1, end, brew); 341 if (rightSide <= 0) 342 { 343 return 0; 344 } 345 346 if (leftSide > rightSide) 347 { 348 return leftSide; 349 } 350 return rightSide; 351 } 352 353 bool hasMultiplier = false; 354 bool hasValue = false; 355 bool isNot = false; 356 bool isNeg = false; 357 int bitCount = NO_COUNT; 358 int valuePart = 0; 359 int multiplierPart = 0; 360 int result = 0; 361 for (int i = start; i < end; i++) 362 { 363 364 char current = definition.at(i); 365 if (current >= L'0' && current <= L'9') 366 { 367 valuePart *= 10; 368 valuePart += (int) (current - L'0'); 369 hasValue = true; 370 } 371 else if (current == L'!') 372 { 373 if (hasValue) 374 { 375 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 376 hasValue = isNeg = isNot = false; 377 valuePart = 0; 378 } 379 380 isNot = true; 381 } 382 else if (current == L'-') 383 { 384 if (hasValue) 385 { 386 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 387 hasValue = isNeg = isNot = false; 388 valuePart = 0; 389 } 390 391 isNeg = true; 392 } 393 else if (current == L'+') 394 { 395 if (hasValue) 396 { 397 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 398 hasValue = isNeg = isNot = false; 399 valuePart = 0; 400 } 401 } 402 } 403 if (hasValue) 404 { 405 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 406 } 407 408 return result; 409} 410#else 411int PotionBrewing::parseEffectFormulaValue(const wstring &definition, int start, int end, int brew) 412{ 413 if (start >= definition.length() || end < 0 || start >= end) 414 { 415 return 0; 416 } 417 418 // split by or 419 int orIndex = definition.find_first_of(L'|', start); 420 if (orIndex >= 0 && orIndex < end) 421 { 422 int leftSide = parseEffectFormulaValue(definition, start, orIndex - 1, brew); 423 if (leftSide > 0) 424 { 425 return leftSide; 426 } 427 428 int rightSide = parseEffectFormulaValue(definition, orIndex + 1, end, brew); 429 if (rightSide > 0) 430 { 431 return rightSide; 432 } 433 return 0; 434 } 435 // split by and 436 int andIndex = definition.find_first_of(L'&', start); 437 if (andIndex >= 0 && andIndex < end) 438 { 439 int leftSide = parseEffectFormulaValue(definition, start, andIndex - 1, brew); 440 if (leftSide <= 0) 441 { 442 return 0; 443 } 444 445 int rightSide = parseEffectFormulaValue(definition, andIndex + 1, end, brew); 446 if (rightSide <= 0) 447 { 448 return 0; 449 } 450 451 if (leftSide > rightSide) 452 { 453 return leftSide; 454 } 455 return rightSide; 456 } 457 458 bool isMultiplier = false; 459 bool hasMultiplier = false; 460 bool hasValue = false; 461 bool isNot = false; 462 bool isNeg = false; 463 int bitCount = NO_COUNT; 464 int valuePart = 0; 465 int multiplierPart = 0; 466 int result = 0; 467 for (int i = start; i < end; i++) 468 { 469 470 char current = definition.at(i); 471 if (current >= L'0' && current <= L'9') 472 { 473 if (isMultiplier) 474 { 475 multiplierPart = (int) (current - L'0'); 476 hasMultiplier = true; 477 } 478 else 479 { 480 valuePart *= 10; 481 valuePart += (int) (current - L'0'); 482 hasValue = true; 483 } 484 } 485 else if (current == L'*') 486 { 487 isMultiplier = true; 488 } 489 else if (current == L'!') 490 { 491 if (hasValue) 492 { 493 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 494 hasValue = hasMultiplier = isMultiplier = isNeg = isNot = false; 495 valuePart = multiplierPart = 0; 496 bitCount = NO_COUNT; 497 } 498 499 isNot = true; 500 } 501 else if (current == L'-') 502 { 503 if (hasValue) 504 { 505 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 506 hasValue = hasMultiplier = isMultiplier = isNeg = isNot = false; 507 valuePart = multiplierPart = 0; 508 bitCount = NO_COUNT; 509 } 510 511 isNeg = true; 512 } 513 else if (current == L'=' || current == L'<' || current == L'>') 514 { 515 if (hasValue) 516 { 517 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 518 hasValue = hasMultiplier = isMultiplier = isNeg = isNot = false; 519 valuePart = multiplierPart = 0; 520 bitCount = NO_COUNT; 521 } 522 523 if (current == L'=') 524 { 525 bitCount = EQUAL_COUNT; 526 } 527 else if (current == L'<') 528 { 529 bitCount = LESS_COUNT; 530 } 531 else if (current == L'>') 532 { 533 bitCount = GREATER_COUNT; 534 } 535 } 536 else if (current == L'+') 537 { 538 if (hasValue) 539 { 540 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 541 hasValue = hasMultiplier = isMultiplier = isNeg = isNot = false; 542 valuePart = multiplierPart = 0; 543 bitCount = NO_COUNT; 544 } 545 } 546 } 547 if (hasValue) 548 { 549 result += constructParsedValue(isNot, hasMultiplier, isNeg, bitCount, valuePart, multiplierPart, brew); 550 } 551 552 return result; 553} 554#endif 555 556vector<MobEffectInstance *> *PotionBrewing::getEffects(int brew, bool includeDisabledEffects) 557{ 558 vector<MobEffectInstance *> *list = NULL; 559 560 //for (MobEffect effect : MobEffect.effects) 561 for(unsigned int i = 0; i < MobEffect::NUM_EFFECTS; ++i) 562 { 563 MobEffect *effect = MobEffect::effects[i]; 564 if (effect == NULL || (effect->isDisabled() && !includeDisabledEffects)) 565 { 566 continue; 567 } 568 //wstring durationString = potionEffectDuration.get(effect->getId()); 569 AUTO_VAR(effIt, potionEffectDuration.find(effect->getId())); 570 if ( effIt == potionEffectDuration.end() ) 571 { 572 continue; 573 } 574 wstring durationString = effIt->second; 575 576 int duration = parseEffectFormulaValue(durationString, 0, (int)durationString.length(), brew); 577 if (duration > 0) 578 { 579 int amplifier = 0; 580 AUTO_VAR(ampIt, potionEffectAmplifier.find(effect->getId())); 581 if (ampIt != potionEffectAmplifier.end()) 582 { 583 wstring amplifierString = ampIt->second; 584 amplifier = parseEffectFormulaValue(amplifierString, 0, (int)amplifierString.length(), brew); 585 if (amplifier < 0) 586 { 587 amplifier = 0; 588 } 589 } 590 591 if (effect->isInstantenous()) 592 { 593 duration = 1; 594 } 595 else 596 { 597 // 3, 8, 13, 18.. minutes 598 duration = (SharedConstants::TICKS_PER_SECOND * 60) * (duration * 3 + (duration - 1) * 2); 599 duration >>= amplifier; 600 duration = (int) Math::round((double) duration * effect->getDurationModifier()); 601 602 if ((brew & THROWABLE_MASK) != 0) 603 { 604 duration = (int) Math::round((double) duration * .75 + .5); 605 } 606 } 607 608 if (list == NULL) 609 { 610 list = new vector<MobEffectInstance *>(); 611 } 612 MobEffectInstance *instance = new MobEffectInstance(effect->getId(), duration, amplifier); 613 if ((brew & THROWABLE_MASK) != 0) instance->setSplash(true); 614 list->push_back(instance); 615 } 616 } 617 618 return list; 619} 620 621#if !(_SIMPLIFIED_BREWING) 622int PotionBrewing::boil(int brew) 623{ 624 if ((brew & 1) == 0) 625 { 626 return brew; 627 } 628 629 // save highest bit 630 int savedBit = NUM_BITS - 1; 631 while ((brew & (1 << savedBit)) == 0 && savedBit >= 0) 632 { 633 savedBit--; 634 } 635 // it's not possible to boil if there are no "empty slots" in front of 636 // the last bit 637 if (savedBit < 2 || (brew & (1 << (savedBit - 1))) != 0) 638 { 639 return brew; 640 } 641 if (savedBit >= 0) 642 { 643 brew &= ~(1 << savedBit); 644 } 645 646 brew <<= 1; 647 648 if (savedBit >= 0) 649 { 650 brew |= (1 << savedBit); 651 brew |= (1 << (savedBit - 1)); 652 } 653 654 return brew & BREW_MASK; 655} 656 657int PotionBrewing::shake(int brew) 658{ 659 660 // save highest bit 661 int savedBit = NUM_BITS - 1; 662 while ((brew & (1 << savedBit)) == 0 && savedBit >= 0) 663 { 664 savedBit--; 665 } 666 if (savedBit >= 0) 667 { 668 brew &= ~(1 << savedBit); 669 } 670 671 int currentResult = 0; 672 int nextResult = brew; 673 674 while (nextResult != currentResult) 675 { 676 nextResult = brew; 677 currentResult = 0; 678 // evaluate each bit 679 for (int bit = 0; bit < NUM_BITS; bit++) 680 { 681 682 bool on = isWrappedLit(brew, bit); 683 if (on) 684 { 685 if (!isWrappedLit(brew, bit + 1) && isWrappedLit(brew, bit + 2)) 686 { 687 on = false; 688 } 689 else if (!isWrappedLit(brew, bit - 1) && isWrappedLit(brew, bit - 2)) 690 { 691 on = false; 692 } 693 } 694 else 695 { 696 // turn on if both neighbors are on 697 on = isWrappedLit(brew, bit - 1) && isWrappedLit(brew, bit + 1); 698 } 699 if (on) 700 { 701 currentResult |= (1 << bit); 702 } 703 } 704 brew = currentResult; 705 } 706 707 if (savedBit >= 0) 708 { 709 currentResult |= (1 << savedBit); 710 } 711 712 return currentResult & BREW_MASK; 713} 714 715int PotionBrewing::stirr(int brew) 716{ 717 if ((brew & 1) != 0) 718 { 719 brew = boil(brew); 720 } 721 return shake(brew); 722} 723#endif 724 725int PotionBrewing::applyBrewBit(int currentBrew, int bit, bool isNeg, bool isNot, bool isRequired) 726{ 727 if (isRequired) 728 { 729 // 4J-JEV: I wanted to be able to specify that a 730 // bit is required to be false. 731 if (isLit(currentBrew, bit) == isNot) 732 { 733 return 0; 734 } 735 } 736 else if (isNeg) 737 { 738 currentBrew &= ~(1 << bit); 739 } 740 else if (isNot) 741 { 742 if ((currentBrew & (1 << bit)) == 0) 743 { 744 currentBrew |= (1 << bit); 745 } 746 else 747 { 748 currentBrew &= ~(1 << bit); 749 } 750 } 751 else 752 { 753 currentBrew |= (1 << bit); 754 } 755 return currentBrew; 756} 757 758int PotionBrewing::applyBrew(int currentBrew, const wstring &formula) 759{ 760 761 int start = 0; 762 int end = (int)formula.length(); 763 764 bool hasValue = false; 765 bool isNot = false; 766 bool isNeg = false; 767 bool isRequired = false; 768 int valuePart = 0; 769 for (int i = start; i < end; i++) 770 { 771 char current = formula.at(i); 772 if (current >= L'0' && current <= L'9') 773 { 774 valuePart *= 10; 775 valuePart += (int) (current - L'0'); 776 hasValue = true; 777 } 778 else if (current == L'!') 779 { 780 if (hasValue) 781 { 782 currentBrew = applyBrewBit(currentBrew, valuePart, isNeg, isNot, isRequired); 783 hasValue = isNeg = isNot = isRequired = false; 784 valuePart = 0; 785 } 786 787 isNot = true; 788 } 789 else if (current == L'-') 790 { 791 if (hasValue) 792 { 793 currentBrew = applyBrewBit(currentBrew, valuePart, isNeg, isNot, isRequired); 794 hasValue = isNeg = isNot = isRequired = false; 795 valuePart = 0; 796 } 797 798 isNeg = true; 799 } 800 else if (current == L'+') 801 { 802 if (hasValue) 803 { 804 currentBrew = applyBrewBit(currentBrew, valuePart, isNeg, isNot, isRequired); 805 hasValue = isNeg = isNot = isRequired = false; 806 valuePart = 0; 807 } 808 } 809 else if (current == L'&') 810 { 811 if (hasValue) 812 { 813 currentBrew = applyBrewBit(currentBrew, valuePart, isNeg, isNot, isRequired); 814 hasValue = isNeg = isNot = isRequired = false; 815 valuePart = 0; 816 } 817 isRequired = true; 818 } 819 } 820 if (hasValue) 821 { 822 currentBrew = applyBrewBit(currentBrew, valuePart, isNeg, isNot, isRequired); 823 } 824 825 return currentBrew & BREW_MASK; 826} 827 828int PotionBrewing::setBit(int brew, int position, bool onOff) 829{ 830 if (onOff) 831 { 832 return brew | (1 << position); 833 } 834 return brew & ~(1 << position); 835} 836 837int PotionBrewing::valueOf(int brew, int p1, int p2, int p3, int p4) 838{ 839 return ((isLit(brew, p1) ? 0x08 : 0) | (isLit(brew, p2) ? 0x04 : 0) | (isLit(brew, p3) ? 0x02 : 0) | (isLit(brew, p4) ? 0x01 : 0)); 840} 841 842int PotionBrewing::valueOf(int brew, int p1, int p2, int p3, int p4, int p5) 843{ 844 return (isLit(brew, p1) ? 0x10 : 0) | (isLit(brew, p2) ? 0x08 : 0) | (isLit(brew, p3) ? 0x04 : 0) | (isLit(brew, p4) ? 0x02 : 0) | (isLit(brew, p5) ? 0x01 : 0); 845} 846 847wstring PotionBrewing::toString(int brew) 848{ 849 wstring string; 850 851 int bit = NUM_BITS - 1; 852 while (bit >= 0) 853 { 854 if ((brew & (1 << bit)) != 0) 855 { 856 string.append(L"O"); 857 } 858 else 859 { 860 string.append(L"x"); 861 } 862 bit--; 863 } 864 865 return string; 866} 867 868//void main(String[] args) 869//{ 870 871// HashMap<String, Integer> existingCombinations = new HashMap<String, Integer>(); 872// HashMap<String, Integer> distinctCombinations = new HashMap<String, Integer>(); 873// int noEffects = 0; 874// for (int brew = 0; brew <= BREW_MASK; brew++) { 875// List<MobEffectInstance> effects = PotionBrewing.getEffects(brew, true); 876// if (effects != null) { 877 878// { 879// StringBuilder builder = new StringBuilder(); 880// for (MobEffectInstance effect : effects) { 881// builder.append(effect.toString()); 882// builder.append(" "); 883// } 884// String string = builder.toString(); 885// Integer count = existingCombinations.get(string); 886// if (count != null) { 887// count++; 888// } else { 889// count = 1; 890// } 891// existingCombinations.put(string, count); 892// } 893// { 894// StringBuilder builder = new StringBuilder(); 895// for (MobEffectInstance effect : effects) { 896// builder.append(effect.getDescriptionId()); 897// builder.append(" "); 898// } 899// String string = builder.toString(); 900// Integer count = distinctCombinations.get(string); 901// if (count != null) { 902// count++; 903// } else { 904// count = 1; 905// } 906// distinctCombinations.put(string, count); 907// } 908// } else { 909// noEffects++; 910// } 911// } 912 913// for (String combination : existingCombinations.keySet()) { 914// Integer count = existingCombinations.get(combination); 915// if (count > 20) { 916// System.out.println(combination + ": " + count); 917// } 918// } 919 920// System.out.println("Combination with no effects: " + noEffects + " (" + ((double) noEffects / BREW_MASK * 100.0) + " %)"); 921// System.out.println("Unique combinations: " + existingCombinations.size()); 922// System.out.println("Distinct combinations: " + distinctCombinations.size()); 923//}