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 "..\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//}