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.alchemy.h"
4#include "net.minecraft.world.effect.h"
5#include "net.minecraft.world.level.h"
6#include "net.minecraft.world.entity.ai.attributes.h"
7#include "net.minecraft.world.entity.player.h"
8#include "net.minecraft.world.entity.projectile.h"
9#include "net.minecraft.world.h"
10#include "MobEffectInstance.h"
11#include "StringHelpers.h"
12#include "SharedConstants.h"
13#include "PotionItem.h"
14#include "SoundTypes.h"
15
16const wstring PotionItem::DEFAULT_ICON = L"potion";
17const wstring PotionItem::THROWABLE_ICON = L"potion_splash";
18const wstring PotionItem::CONTENTS_ICON = L"potion_contents";
19
20// 4J Added
21vector<pair<int, int> > PotionItem::s_uniquePotionValues;
22
23PotionItem::PotionItem(int id) : Item(id)
24{
25 setMaxStackSize(1);
26 setStackedByData(true);
27 setMaxDamage(0);
28
29 iconThrowable = NULL;
30 iconDrinkable = NULL;
31 iconOverlay = NULL;
32}
33
34vector<MobEffectInstance *> *PotionItem::getMobEffects(shared_ptr<ItemInstance> potion)
35{
36 if (!potion->hasTag() || !potion->getTag()->contains(L"CustomPotionEffects"))
37 {
38 vector<MobEffectInstance *> *effects = NULL;
39 AUTO_VAR(it, cachedMobEffects.find(potion->getAuxValue()));
40 if(it != cachedMobEffects.end()) effects = it->second;
41 if (effects == NULL)
42 {
43 effects = PotionBrewing::getEffects(potion->getAuxValue(), false);
44 cachedMobEffects[potion->getAuxValue()] = effects;
45 }
46
47 // Result should be a new (unmanaged) vector, so create a new one
48 return effects == NULL ? NULL : new vector<MobEffectInstance *>(*effects);
49 }
50 else
51 {
52 vector<MobEffectInstance *> *effects = new vector<MobEffectInstance *>();
53 ListTag<CompoundTag> *customList = (ListTag<CompoundTag> *) potion->getTag()->getList(L"CustomPotionEffects");
54
55 for (int i = 0; i < customList->size(); i++)
56 {
57 CompoundTag *tag = customList->get(i);
58 effects->push_back(MobEffectInstance::load(tag));
59 }
60
61 return effects;
62 }
63}
64
65vector<MobEffectInstance *> *PotionItem::getMobEffects(int auxValue)
66{
67 vector<MobEffectInstance *> *effects = NULL;
68 AUTO_VAR(it, cachedMobEffects.find(auxValue));
69 if(it != cachedMobEffects.end()) effects = it->second;
70 if (effects == NULL)
71 {
72 effects = PotionBrewing::getEffects(auxValue, false);
73 if(effects != NULL) cachedMobEffects.insert( std::pair<int, vector<MobEffectInstance *> *>(auxValue, effects) );
74 }
75 return effects;
76}
77
78shared_ptr<ItemInstance> PotionItem::useTimeDepleted(shared_ptr<ItemInstance> instance, Level *level, shared_ptr<Player> player)
79{
80 if (!player->abilities.instabuild) instance->count--;
81
82 if (!level->isClientSide)
83 {
84 vector<MobEffectInstance *> *effects = getMobEffects(instance);
85 if (effects != NULL)
86 {
87 //for (MobEffectInstance effect : effects)
88 for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it)
89 {
90 player->addEffect(new MobEffectInstance(*it));
91 }
92 }
93 }
94 if (!player->abilities.instabuild)
95 {
96 if (instance->count <= 0)
97 {
98 return shared_ptr<ItemInstance>( new ItemInstance(Item::glassBottle) );
99 }
100 else
101 {
102 player->inventory->add( shared_ptr<ItemInstance>( new ItemInstance(Item::glassBottle) ) );
103 }
104 }
105
106 return instance;
107}
108
109int PotionItem::getUseDuration(shared_ptr<ItemInstance> itemInstance)
110{
111 return DRINK_DURATION;
112}
113
114UseAnim PotionItem::getUseAnimation(shared_ptr<ItemInstance> itemInstance)
115{
116 return UseAnim_drink;
117}
118
119bool PotionItem::TestUse(shared_ptr<ItemInstance> itemInstance, Level *level, shared_ptr<Player> player)
120{
121 return true;
122}
123
124shared_ptr<ItemInstance> PotionItem::use(shared_ptr<ItemInstance> instance, Level *level, shared_ptr<Player> player)
125{
126 if (isThrowable(instance->getAuxValue()))
127 {
128 if (!player->abilities.instabuild) instance->count--;
129 level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f));
130 if (!level->isClientSide) level->addEntity(shared_ptr<ThrownPotion>( new ThrownPotion(level, player, instance->getAuxValue()) ));
131 return instance;
132 }
133 player->startUsingItem(instance, getUseDuration(instance));
134 return instance;
135}
136
137bool PotionItem::useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Player> player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly)
138{
139 return false;
140}
141
142Icon *PotionItem::getIcon(int auxValue)
143{
144 if (isThrowable(auxValue))
145 {
146 return iconThrowable;
147 }
148 return iconDrinkable;
149}
150
151Icon *PotionItem::getLayerIcon(int auxValue, int spriteLayer)
152{
153 if (spriteLayer == 0)
154 {
155 return iconOverlay;
156 }
157 return Item::getLayerIcon(auxValue, spriteLayer);
158}
159
160bool PotionItem::isThrowable(int auxValue)
161{
162 return ((auxValue & PotionBrewing::THROWABLE_MASK) != 0);
163}
164
165int PotionItem::getColor(int data)
166{
167 return PotionBrewing::getColorValue(data, false);
168}
169
170int PotionItem::getColor(shared_ptr<ItemInstance> item, int spriteLayer)
171{
172 if (spriteLayer > 0)
173 {
174 return 0xffffff;
175 }
176 return PotionBrewing::getColorValue(item->getAuxValue(), false);
177}
178
179bool PotionItem::hasMultipleSpriteLayers()
180{
181 return true;
182}
183
184bool PotionItem::hasInstantenousEffects(int itemAuxValue)
185{
186 vector<MobEffectInstance *> *mobEffects = getMobEffects(itemAuxValue);
187 if (mobEffects == NULL || mobEffects->empty())
188 {
189 return false;
190 }
191 //for (MobEffectInstance effect : mobEffects) {
192 for(AUTO_VAR(it, mobEffects->begin()); it != mobEffects->end(); ++it)
193 {
194 MobEffectInstance *effect = *it;
195 if (MobEffect::effects[effect->getId()]->isInstantenous())
196 {
197 return true;
198 }
199 }
200 return false;
201}
202
203wstring PotionItem::getHoverName(shared_ptr<ItemInstance> itemInstance)
204{
205 if (itemInstance->getAuxValue() == 0)
206 {
207 return app.GetString(IDS_ITEM_WATER_BOTTLE); // I18n.get("item.emptyPotion.name").trim();
208 }
209
210 wstring elementName = Item::getHoverName(itemInstance);
211 if (isThrowable(itemInstance->getAuxValue()))
212 {
213 //elementName = I18n.get("potion.prefix.grenade").trim() + " " + elementName;
214 elementName = replaceAll(elementName,L"{*splash*}",app.GetString(IDS_POTION_PREFIX_GRENADE));
215 }
216 else
217 {
218 elementName = replaceAll(elementName,L"{*splash*}",L"");
219 }
220
221 vector<MobEffectInstance *> *effects = ((PotionItem *) Item::potion)->getMobEffects(itemInstance);
222 if (effects != NULL && !effects->empty())
223 {
224 //String postfixString = effects.get(0).getDescriptionId();
225 //postfixString += ".postfix";
226 //return elementName + " " + I18n.get(postfixString).trim();
227
228 elementName = replaceAll(elementName,L"{*prefix*}",L"");
229 elementName = replaceAll(elementName,L"{*postfix*}",app.GetString(effects->at(0)->getPostfixDescriptionId()));
230 }
231 else
232 {
233 //String appearanceName = PotionBrewing.getAppearanceName(itemInstance.getAuxValue());
234 //return I18n.get(appearanceName).trim() + " " + elementName;
235
236 elementName = replaceAll(elementName,L"{*prefix*}",app.GetString( PotionBrewing::getAppearanceName(itemInstance->getAuxValue())));
237 elementName = replaceAll(elementName,L"{*postfix*}",L"");
238 }
239 return elementName;
240}
241
242void PotionItem::appendHoverText(shared_ptr<ItemInstance> itemInstance, shared_ptr<Player> player, vector<HtmlString> *lines, bool advanced)
243{
244 if (itemInstance->getAuxValue() == 0)
245 {
246 return;
247 }
248 vector<MobEffectInstance *> *effects = ((PotionItem *) Item::potion)->getMobEffects(itemInstance);
249 attrAttrModMap modifiers;
250 if (effects != NULL && !effects->empty())
251 {
252 //for (MobEffectInstance effect : effects)
253 for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it)
254 {
255 MobEffectInstance *effect = *it;
256 wstring effectString = app.GetString( effect->getDescriptionId() );
257
258 MobEffect *mobEffect = MobEffect::effects[effect->getId()];
259 unordered_map<Attribute*, AttributeModifier*> *effectModifiers = mobEffect->getAttributeModifiers();
260
261 if (effectModifiers != NULL && effectModifiers->size() > 0)
262 {
263 for(AUTO_VAR(it, effectModifiers->begin()); it != effectModifiers->end(); ++it)
264 {
265 // 4J - anonymous modifiers added here are destroyed shortly?
266 AttributeModifier *original = it->second;
267 AttributeModifier *modifier = new AttributeModifier(mobEffect->getAttributeModifierValue(effect->getAmplifier(), original), original->getOperation());
268 modifiers.insert( std::pair<eATTRIBUTE_ID, AttributeModifier*>( it->first->getId(), modifier) );
269 }
270 }
271
272 // Don't want to delete this (that's a pointer to mobEffects internal vector of modifiers)
273 // delete effectModifiers;
274
275 if (effect->getAmplifier() > 0)
276 {
277 wstring potencyString = L"";
278 switch(effect->getAmplifier())
279 {
280 case 1:
281 potencyString = L" ";
282 potencyString += app.GetString( IDS_POTION_POTENCY_1 );
283 break;
284 case 2:
285 potencyString = L" ";
286 potencyString += app.GetString( IDS_POTION_POTENCY_2 );
287 break;
288 case 3:
289 potencyString = L" ";
290 potencyString += app.GetString( IDS_POTION_POTENCY_3 );
291 break;
292 default:
293 potencyString = app.GetString( IDS_POTION_POTENCY_0 );
294 break;
295 }
296 effectString += potencyString; // + I18n.get("potion.potency." + effect.getAmplifier()).trim();
297 }
298 if (effect->getDuration() > SharedConstants::TICKS_PER_SECOND)
299 {
300 effectString += L" (" + MobEffect::formatDuration(effect) + L")";
301 }
302
303 eMinecraftColour color = eMinecraftColour_NOT_SET;
304
305 if (mobEffect->isHarmful())
306 {
307 color = eHTMLColor_c;
308 }
309 else
310 {
311 color = eHTMLColor_7;
312 }
313
314 lines->push_back(HtmlString(effectString, color));
315 }
316 }
317 else
318 {
319 wstring effectString = app.GetString(IDS_POTION_EMPTY); //I18n.get("potion.empty").trim();
320
321 lines->push_back(HtmlString(effectString, eHTMLColor_7)); //"�7"
322 }
323
324 if (!modifiers.empty())
325 {
326 // Add new line
327 lines->push_back(HtmlString(L""));
328 lines->push_back(HtmlString(app.GetString(IDS_POTION_EFFECTS_WHENDRANK), eHTMLColor_5));
329
330 // Add modifier descriptions
331 for (AUTO_VAR(it, modifiers.begin()); it != modifiers.end(); ++it)
332 {
333 // 4J: Moved modifier string building to AttributeModifier
334 lines->push_back(it->second->getHoverText(it->first));
335 }
336 }
337}
338
339bool PotionItem::isFoil(shared_ptr<ItemInstance> itemInstance)
340{
341 vector<MobEffectInstance *> *mobEffects = getMobEffects(itemInstance);
342 return mobEffects != NULL && !mobEffects->empty();
343}
344
345unsigned int PotionItem::getUseDescriptionId(shared_ptr<ItemInstance> instance)
346{
347 int brew = instance->getAuxValue();
348 if(brew == 0) return IDS_POTION_DESC_WATER_BOTTLE;
349 else if( MACRO_POTION_IS_REGENERATION(brew)) return IDS_POTION_DESC_REGENERATION;
350 else if( MACRO_POTION_IS_SPEED(brew) ) return IDS_POTION_DESC_MOVESPEED;
351 else if( MACRO_POTION_IS_FIRE_RESISTANCE(brew)) return IDS_POTION_DESC_FIRERESISTANCE;
352 else if( MACRO_POTION_IS_INSTANTHEALTH(brew)) return IDS_POTION_DESC_HEAL;
353 else if( MACRO_POTION_IS_NIGHTVISION(brew)) return IDS_POTION_DESC_NIGHTVISION;
354 else if( MACRO_POTION_IS_INVISIBILITY(brew)) return IDS_POTION_DESC_INVISIBILITY;
355 else if( MACRO_POTION_IS_WEAKNESS(brew)) return IDS_POTION_DESC_WEAKNESS;
356 else if( MACRO_POTION_IS_STRENGTH(brew)) return IDS_POTION_DESC_DAMAGEBOOST;
357 else if( MACRO_POTION_IS_SLOWNESS(brew)) return IDS_POTION_DESC_MOVESLOWDOWN;
358 else if( MACRO_POTION_IS_POISON(brew)) return IDS_POTION_DESC_POISON;
359 else if( MACRO_POTION_IS_INSTANTDAMAGE(brew)) return IDS_POTION_DESC_HARM;
360 return IDS_POTION_DESC_EMPTY;
361}
362
363void PotionItem::registerIcons(IconRegister *iconRegister)
364{
365 iconDrinkable = iconRegister->registerIcon(DEFAULT_ICON);
366 iconThrowable = iconRegister->registerIcon(THROWABLE_ICON);
367 iconOverlay = iconRegister->registerIcon(CONTENTS_ICON);
368}
369
370Icon *PotionItem::getTexture(const wstring &name)
371{
372 if (name.compare(DEFAULT_ICON) == 0) return Item::potion->iconDrinkable;
373 if (name.compare(THROWABLE_ICON) == 0) return Item::potion->iconThrowable;
374 if (name.compare(CONTENTS_ICON) == 0) return Item::potion->iconOverlay;
375 return NULL;
376}
377
378
379// 4J Stu - Based loosely on a function that gets added in java much later on (1.3)
380vector<pair<int, int> > *PotionItem::getUniquePotionValues()
381{
382 if (s_uniquePotionValues.empty())
383 {
384 for (int brew = 0; brew <= PotionBrewing::BREW_MASK; ++brew)
385 {
386 vector<MobEffectInstance *> *effects = PotionBrewing::getEffects(brew, false);
387
388 if (effects != NULL)
389 {
390 if(!effects->empty())
391 {
392 // 4J Stu - Based on implementation of Java List.hashCode() at http://docs.oracle.com/javase/6/docs/api/java/util/List.html#hashCode()
393 // and adding deleting to clear up as we go
394 int effectsHashCode = 1;
395 for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it)
396 {
397 MobEffectInstance *mei = *it;
398 effectsHashCode = 31*effectsHashCode + (mei==NULL ? 0 : mei->hashCode());
399 delete (*it);
400 }
401
402 bool toAdd = true;
403 for(AUTO_VAR(it, s_uniquePotionValues.begin()); it != s_uniquePotionValues.end(); ++it)
404 {
405 // Some potions hash the same (identical effects) but are throwable so account for that
406 if(it->first == effectsHashCode && !(!isThrowable(it->second) && isThrowable(brew)) )
407 {
408 toAdd = false;
409 break;
410 }
411 }
412 if( toAdd )
413 {
414 s_uniquePotionValues.push_back(pair<int,int>(effectsHashCode, brew) );
415 }
416 }
417 delete effects;
418 }
419 }
420 }
421 return &s_uniquePotionValues;
422}