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.effect.h"
3#include "net.minecraft.world.damagesource.h"
4#include "net.minecraft.world.entity.h"
5#include "net.minecraft.world.entity.ai.attributes.h"
6#include "net.minecraft.world.entity.ai.goal.h"
7#include "net.minecraft.world.entity.ai.goal.target.h"
8#include "net.minecraft.world.entity.monster.h"
9#include "net.minecraft.world.entity.projectile.h"
10#include "net.minecraft.world.item.h"
11#include "net.minecraft.world.item.alchemy.h"
12#include "net.minecraft.world.level.h"
13#include "net.minecraft.world.phys.h"
14#include "Witch.h"
15
16AttributeModifier *Witch::SPEED_MODIFIER_DRINKING = (new AttributeModifier(eModifierId_MOB_WITCH_DRINKSPEED, -0.25f, AttributeModifier::OPERATION_ADDITION))->setSerialize(false);
17
18const int Witch::DEATH_LOOT[Witch::DEATH_LOOT_COUNT] = {
19 Item::yellowDust_Id, Item::sugar_Id, Item::redStone_Id, Item::spiderEye_Id, Item::glassBottle_Id, Item::gunpowder_Id, Item::stick_Id, Item::stick_Id,
20};
21
22Witch::Witch(Level *level) : Monster(level)
23{
24 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
25 // the derived version of the function is called
26 defineSynchedData();
27 registerAttributes();
28 setHealth(getMaxHealth());
29
30 usingTime = 0;
31
32 goalSelector.addGoal(1, new FloatGoal(this));
33 goalSelector.addGoal(2, new RangedAttackGoal(this, this, 1.0, SharedConstants::TICKS_PER_SECOND * 3, 10));
34 goalSelector.addGoal(2, new RandomStrollGoal(this, 1.0));
35 goalSelector.addGoal(3, new LookAtPlayerGoal(this, typeid(Player), 8));
36 goalSelector.addGoal(3, new RandomLookAroundGoal(this));
37
38 targetSelector.addGoal(1, new HurtByTargetGoal(this, false));
39 targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 0, true));
40}
41
42void Witch::defineSynchedData()
43{
44 Monster::defineSynchedData();
45
46 getEntityData()->define(DATA_USING_ITEM, (byte) 0);
47}
48
49int Witch::getAmbientSound()
50{
51 return eSoundType_MOB_WITCH_IDLE; //"mob.witch.idle";
52}
53
54int Witch::getHurtSound()
55{
56 return eSoundType_MOB_WITCH_HURT; //"mob.witch.hurt";
57}
58
59int Witch::getDeathSound()
60{
61 return eSoundType_MOB_WITCH_DEATH; //"mob.witch.death";
62}
63
64void Witch::setUsingItem(bool isUsing)
65{
66 getEntityData()->set(DATA_USING_ITEM, isUsing ? (byte) 1 : (byte) 0);
67}
68
69bool Witch::isUsingItem()
70{
71 return getEntityData()->getByte(DATA_USING_ITEM) == 1;
72}
73
74void Witch::registerAttributes()
75{
76 Monster::registerAttributes();
77
78 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(26);
79 getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f);
80}
81
82bool Witch::useNewAi()
83{
84 return true;
85}
86
87void Witch::aiStep()
88{
89 if (!level->isClientSide)
90 {
91 if (isUsingItem())
92 {
93 if (usingTime-- <= 0)
94 {
95 setUsingItem(false);
96 shared_ptr<ItemInstance> item = getCarriedItem();
97 setEquippedSlot(SLOT_WEAPON, nullptr);
98
99 if (item != NULL && item->id == Item::potion_Id)
100 {
101 vector<MobEffectInstance *> *effects = Item::potion->getMobEffects(item);
102 if (effects != NULL)
103 {
104 for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it)
105 {
106 addEffect(new MobEffectInstance(*it));
107 }
108 }
109 delete effects;
110 }
111
112 getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->removeModifier(SPEED_MODIFIER_DRINKING);
113 }
114 }
115 else
116 {
117 int potion = -1;
118
119 if (random->nextFloat() < 0.15f && isOnFire() && !hasEffect(MobEffect::fireResistance))
120 {
121 potion = PotionBrewing::POTION_ID_FIRE_RESISTANCE;
122 }
123 else if (random->nextFloat() < 0.05f && getHealth() < getMaxHealth())
124 {
125 potion = PotionBrewing::POTION_ID_HEAL;
126 }
127 else if (random->nextFloat() < 0.25f && getTarget() != NULL && !hasEffect(MobEffect::movementSpeed) && getTarget()->distanceToSqr(shared_from_this()) > 11 * 11)
128 {
129 potion = PotionBrewing::POTION_ID_SWIFTNESS;
130 }
131 else if (random->nextFloat() < 0.25f && getTarget() != NULL && !hasEffect(MobEffect::movementSpeed) && getTarget()->distanceToSqr(shared_from_this()) > 11 * 11)
132 {
133 potion = PotionBrewing::POTION_ID_SWIFTNESS;
134 }
135
136 if (potion > -1)
137 {
138 setEquippedSlot(SLOT_WEAPON, shared_ptr<ItemInstance>( new ItemInstance(Item::potion, 1, potion)) );
139 usingTime = getCarriedItem()->getUseDuration();
140 setUsingItem(true);
141 AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
142 speed->removeModifier(SPEED_MODIFIER_DRINKING);
143 speed->addModifier(new AttributeModifier(*SPEED_MODIFIER_DRINKING));
144 }
145 }
146
147 if (random->nextFloat() < 0.00075f)
148 {
149 level->broadcastEntityEvent(shared_from_this(), EntityEvent::WITCH_HAT_MAGIC);
150 }
151 }
152
153 Monster::aiStep();
154}
155
156void Witch::handleEntityEvent(byte id)
157{
158 if (id == EntityEvent::WITCH_HAT_MAGIC)
159 {
160 for (int i = 0; i < random->nextInt(35) + 10; i++)
161 {
162 level->addParticle(eParticleType_witchMagic, x + random->nextGaussian() * .13f, bb->y1 + 0.5f + random->nextGaussian() * .13f, z + random->nextGaussian() * .13f, 0, 0, 0);
163 }
164 }
165 else
166 {
167 Monster::handleEntityEvent(id);
168 }
169}
170
171float Witch::getDamageAfterMagicAbsorb(DamageSource *damageSource, float damage)
172{
173 damage = Monster::getDamageAfterMagicAbsorb(damageSource, damage);
174
175 if (damageSource->getEntity() == shared_from_this()) damage = 0;
176 if (damageSource->isMagic()) damage *= 0.15;
177
178 return damage;
179}
180
181void Witch::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
182{
183 int passes = random->nextInt(3) + 1;
184 for (int pass = 0; pass < passes; pass++)
185 {
186 int count = random->nextInt(3);
187 int type = DEATH_LOOT[random->nextInt(DEATH_LOOT_COUNT)];
188 if (playerBonusLevel > 0) count += random->nextInt(playerBonusLevel + 1);
189
190 for (int i = 0; i < count; i++)
191 {
192 spawnAtLocation(type, 1);
193 }
194 }
195}
196
197void Witch::performRangedAttack(shared_ptr<LivingEntity> target, float power)
198{
199 if (isUsingItem()) return;
200
201 shared_ptr<ThrownPotion> potion = shared_ptr<ThrownPotion>( new ThrownPotion(level, dynamic_pointer_cast<LivingEntity>(shared_from_this()), PotionBrewing::POTION_ID_SPLASH_DAMAGE) );
202 potion->xRot -= -20;
203 double xd = (target->x + target->xd) - x;
204 double yd = (target->y + target->getHeadHeight() - 1.1f) - y;
205 double zd = (target->z + target->zd) - z;
206 float dist = Mth::sqrt(xd * xd + zd * zd);
207
208 if (dist >= 8 && !target->hasEffect(MobEffect::movementSlowdown))
209 {
210 potion->setPotionValue(PotionBrewing::POTION_ID_SPLASH_SLOWNESS);
211 }
212 else if (target->getHealth() >= 8 && !target->hasEffect(MobEffect::poison))
213 {
214 potion->setPotionValue(PotionBrewing::POTION_ID_SPLASH_POISON);
215 }
216 else if (dist <= 3 && !target->hasEffect(MobEffect::weakness) && random->nextFloat() < 0.25f)
217 {
218 potion->setPotionValue(PotionBrewing::POTION_ID_SPLASH_WEAKNESS);
219 }
220
221 potion->shoot(xd, yd + dist * 0.2f, zd, 0.75f, 8);
222
223 level->addEntity(potion);
224}