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.entity.ai.attributes.h"
3#include "net.minecraft.world.entity.ai.control.h"
4#include "net.minecraft.world.entity.ai.goal.h"
5#include "net.minecraft.world.entity.ai.goal.target.h"
6#include "net.minecraft.world.entity.ai.navigation.h"
7#include "net.minecraft.world.entity.ai.village.h"
8#include "net.minecraft.world.entity.animal.h"
9#include "net.minecraft.world.entity.player.h"
10#include "net.minecraft.world.entity.monster.h"
11#include "net.minecraft.world.entity.h"
12#include "net.minecraft.world.damagesource.h"
13#include "net.minecraft.world.item.h"
14#include "net.minecraft.world.level.h"
15#include "net.minecraft.world.level.tile.h"
16#include "net.minecraft.world.phys.h"
17#include "..\Minecraft.Client\Textures.h"
18#include "SynchedEntityData.h"
19#include "VillagerGolem.h"
20#include "ParticleTypes.h"
21
22VillagerGolem::VillagerGolem(Level *level) : Golem(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 this->defineSynchedData();
27 registerAttributes();
28 setHealth(getMaxHealth());
29
30 villageUpdateInterval = 0;
31 village = weak_ptr<Village>();
32 attackAnimationTick = 0;
33 offerFlowerTick = 0;
34
35 setSize(1.4f, 2.9f);
36
37 getNavigation()->setAvoidWater(true);
38
39 goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true));
40 goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9, 32));
41 goalSelector.addGoal(3, new MoveThroughVillageGoal(this, 0.6, true));
42 goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 1.0));
43 goalSelector.addGoal(5, new OfferFlowerGoal(this));
44 goalSelector.addGoal(6, new RandomStrollGoal(this, 0.6));
45 goalSelector.addGoal(7, new LookAtPlayerGoal(this, typeid(Player), 6));
46 goalSelector.addGoal(8, new RandomLookAroundGoal(this));
47
48 targetSelector.addGoal(1, new DefendVillageTargetGoal(this));
49 targetSelector.addGoal(2, new HurtByTargetGoal(this, false));
50 targetSelector.addGoal(3, new NearestAttackableTargetGoal(this, typeid(Mob), 0, false, true, Enemy::ENEMY_SELECTOR));
51}
52
53void VillagerGolem::defineSynchedData()
54{
55 Golem::defineSynchedData();
56 entityData->define(DATA_FLAGS_ID, (byte) 0);
57}
58
59bool VillagerGolem::useNewAi()
60{
61 return true;
62}
63
64void VillagerGolem::serverAiMobStep()
65{
66 if (--villageUpdateInterval <= 0)
67 {
68 villageUpdateInterval = 70 + random->nextInt(50);
69 shared_ptr<Village> _village = level->villages->getClosestVillage(Mth::floor(x), Mth::floor(y), Mth::floor(z), Villages::MaxDoorDist);
70 village = _village;
71 if (_village == NULL) clearRestriction();
72 else
73 {
74 Pos *center = _village->getCenter();
75 restrictTo(center->x, center->y, center->z, (int)((float)_village->getRadius()) * 0.6f);
76 }
77 }
78
79 Golem::serverAiMobStep();
80}
81
82void VillagerGolem::registerAttributes()
83{
84 Golem::registerAttributes();
85
86 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(100);
87 getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f);
88}
89
90int VillagerGolem::decreaseAirSupply(int currentSupply)
91{
92 // infinite air supply
93 return currentSupply;
94}
95
96void VillagerGolem::doPush(shared_ptr<Entity> e)
97{
98 if ( e->instanceof(eTYPE_ENEMY) )
99 {
100 if (getRandom()->nextInt(20) == 0)
101 {
102 setTarget(dynamic_pointer_cast<LivingEntity>(e));
103 }
104 }
105 Golem::doPush(e);
106}
107
108void VillagerGolem::aiStep()
109{
110 Golem::aiStep();
111
112 if (attackAnimationTick > 0) --attackAnimationTick;
113 if (offerFlowerTick > 0) --offerFlowerTick;
114
115 if (xd * xd + zd * zd > MoveControl::MIN_SPEED_SQR && random->nextInt(5) == 0)
116 {
117 int xt = Mth::floor(x);
118 int yt = Mth::floor(y - 0.2f - heightOffset);
119 int zt = Mth::floor(z);
120 int t = level->getTile(xt, yt, zt);
121 int d = level->getData(xt, yt, zt);
122 if (t > 0)
123 {
124 level->addParticle(PARTICLE_TILECRACK(t,d), x + (random->nextFloat() - 0.5) * bbWidth, bb->y0 + 0.1, z + (random->nextFloat() - 0.5) * bbWidth, 4 * (random->nextFloat() - 0.5), .5,
125 (random->nextFloat() - 0.5) * 4);
126 }
127 }
128}
129
130bool VillagerGolem::canAttackType(eINSTANCEOF targetType)
131{
132 if (isPlayerCreated() && (eTYPE_PLAYER & targetType) == eTYPE_PLAYER ) return false;
133 return Golem::canAttackType(targetType);
134}
135
136void VillagerGolem::addAdditonalSaveData(CompoundTag *tag)
137{
138 Golem::addAdditonalSaveData(tag);
139 tag->putBoolean(L"PlayerCreated", isPlayerCreated());
140}
141
142void VillagerGolem::readAdditionalSaveData(CompoundTag *tag)
143{
144 Golem::readAdditionalSaveData(tag);
145 setPlayerCreated(tag->getBoolean(L"PlayerCreated"));
146}
147
148bool VillagerGolem::doHurtTarget(shared_ptr<Entity> target)
149{
150 attackAnimationTick = 10;
151 level->broadcastEntityEvent(shared_from_this(), EntityEvent::START_ATTACKING);
152 bool hurt = target->hurt(DamageSource::mobAttack(dynamic_pointer_cast<Mob>(shared_from_this())), 7 + random->nextInt(15));
153 if (hurt) target->yd += 0.4f;
154 playSound(eSoundType_MOB_IRONGOLEM_THROW, 1, 1);
155 return hurt;
156}
157
158void VillagerGolem::handleEntityEvent(byte id)
159{
160 if (id == EntityEvent::START_ATTACKING)
161 {
162 attackAnimationTick = 10;
163 playSound(eSoundType_MOB_IRONGOLEM_THROW, 1, 1);
164 }
165 else if (id == EntityEvent::OFFER_FLOWER)
166 {
167 offerFlowerTick = OfferFlowerGoal::OFFER_TICKS;
168 }
169 else Golem::handleEntityEvent(id);
170}
171
172shared_ptr<Village> VillagerGolem::getVillage()
173{
174 return village.lock();
175}
176
177int VillagerGolem::getAttackAnimationTick()
178{
179 return attackAnimationTick;
180}
181
182void VillagerGolem::offerFlower(bool offer)
183{
184 offerFlowerTick = offer ? OfferFlowerGoal::OFFER_TICKS : 0;
185 level->broadcastEntityEvent(shared_from_this(), EntityEvent::OFFER_FLOWER);
186}
187
188int VillagerGolem::getAmbientSound()
189{
190 return -1;
191}
192
193int VillagerGolem::getHurtSound()
194{
195 return eSoundType_MOB_IRONGOLEM_HIT;
196}
197
198int VillagerGolem::getDeathSound()
199{
200 return eSoundType_MOB_IRONGOLEM_DEATH;
201}
202
203void VillagerGolem::playStepSound(int xt, int yt, int zt, int t)
204{
205 playSound(eSoundType_MOB_IRONGOLEM_WALK, 1, 1);
206}
207
208void VillagerGolem::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
209{
210 int roses = random->nextInt(3);
211 for (int i = 0; i < roses; i++)
212 {
213 spawnAtLocation(Tile::rose_Id, 1);
214 }
215 int iron = 3 + random->nextInt(3);
216 for (int i = 0; i < iron; i++)
217 {
218 spawnAtLocation(Item::ironIngot_Id, 1);
219 }
220}
221
222int VillagerGolem::getOfferFlowerTick()
223{
224 return offerFlowerTick;
225}
226
227bool VillagerGolem::isPlayerCreated()
228{
229 return (entityData->getByte(DATA_FLAGS_ID) & 0x01) != 0;
230}
231
232void VillagerGolem::setPlayerCreated(bool value)
233{
234 byte current = entityData->getByte(DATA_FLAGS_ID);
235 if (value)
236 {
237 entityData->set(DATA_FLAGS_ID, (byte) (current | 0x01));
238 }
239 else
240 {
241 entityData->set(DATA_FLAGS_ID, (byte) (current & ~0x01));
242 }
243}
244
245void VillagerGolem::die(DamageSource *source)
246{
247 if (!isPlayerCreated() && lastHurtByPlayer != NULL && village.lock() != NULL)
248 {
249 village.lock()->modifyStanding(lastHurtByPlayer->getName(), -5);
250 }
251 Golem::die(source);
252}
253
254bool VillagerGolem::hurt(DamageSource *source, float dmg)
255{
256 // 4J: Protect owned golem from untrusted players
257 if (isPlayerCreated())
258 {
259 shared_ptr<Entity> entity = source->getDirectEntity();
260 if (entity != NULL && entity->instanceof(eTYPE_PLAYER))
261 {
262 shared_ptr<Player> player = dynamic_pointer_cast<Player>(entity);
263 if (!player->isAllowedToAttackPlayers()) return false;
264 }
265 }
266
267 return Golem::hurt(source, dmg);
268}