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.player.h"
3#include "net.minecraft.world.entity.h"
4#include "net.minecraft.world.entity.ai.attributes.h"
5#include "net.minecraft.world.entity.monster.h"
6#include "net.minecraft.world.item.h"
7#include "net.minecraft.world.level.h"
8#include "net.minecraft.world.level.tile.h"
9#include "net.minecraft.world.damagesource.h"
10#include "net.minecraft.world.phys.h"
11#include "com.mojang.nbt.h"
12#include "..\Minecraft.Client\Textures.h"
13#include "EnderMan.h"
14
15AttributeModifier *EnderMan::SPEED_MODIFIER_ATTACKING = (new AttributeModifier(eModifierId_MOB_ENDERMAN_ATTACKSPEED, 6.2f, AttributeModifier::OPERATION_ADDITION))->setSerialize(false);
16
17bool EnderMan::MAY_TAKE[256];
18
19void EnderMan::staticCtor()
20{
21 ZeroMemory(MAY_TAKE, sizeof(bool) * 256);
22 MAY_TAKE[Tile::grass_Id] = true;
23 MAY_TAKE[Tile::dirt_Id] = true;
24 MAY_TAKE[Tile::sand_Id] = true;
25 MAY_TAKE[Tile::gravel_Id] = true;
26 MAY_TAKE[Tile::flower_Id] = true;
27 MAY_TAKE[Tile::rose_Id] = true;
28 MAY_TAKE[Tile::mushroom_brown_Id] = true;
29 MAY_TAKE[Tile::mushroom_red_Id] = true;
30 MAY_TAKE[Tile::tnt_Id] = true;
31 MAY_TAKE[Tile::cactus_Id] = true;
32 MAY_TAKE[Tile::clay_Id] = true;
33 MAY_TAKE[Tile::pumpkin_Id] = true;
34 MAY_TAKE[Tile::melon_Id] = true;
35 MAY_TAKE[Tile::mycel_Id] = true;
36}
37
38EnderMan::EnderMan(Level *level) : Monster( level )
39{
40 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
41 // the derived version of the function is called
42 // Brought forward from 1.2.3
43 this->defineSynchedData();
44 registerAttributes();
45 setHealth(getMaxHealth());
46
47 // 4J initialisors
48 teleportTime = 0;
49 aggroTime = 0;
50 lastAttackTarget = nullptr;
51 aggroedByPlayer = false;
52
53 setSize(0.6f, 2.9f);
54 footSize = 1;
55}
56
57void EnderMan::registerAttributes()
58{
59 Monster::registerAttributes();
60
61 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(40);
62 getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.3f);
63 getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(7);
64}
65
66void EnderMan::defineSynchedData()
67{
68 Monster::defineSynchedData();
69
70 entityData->define(DATA_CARRY_ITEM_ID, (byte) 0);
71 entityData->define(DATA_CARRY_ITEM_DATA, (byte) 0);
72 entityData->define(DATA_CREEPY, (byte) 0);
73}
74
75void EnderMan::addAdditonalSaveData(CompoundTag *tag)
76{
77 Monster::addAdditonalSaveData(tag);
78 tag->putShort(L"carried", (short) getCarryingTile());
79 tag->putShort(L"carriedData", (short) getCarryingData());
80}
81
82void EnderMan::readAdditionalSaveData(CompoundTag *tag)
83{
84 Monster::readAdditionalSaveData(tag);
85 setCarryingTile(tag->getShort(L"carried"));
86 setCarryingData(tag->getShort(L"carryingData"));
87}
88
89shared_ptr<Entity> EnderMan::findAttackTarget()
90{
91#ifndef _FINAL_BUILD
92 if(app.GetMobsDontAttackEnabled())
93 {
94 return shared_ptr<Player>();
95 }
96#endif
97
98 shared_ptr<Player> player = level->getNearestAttackablePlayer(shared_from_this(), 64);
99 if (player != NULL)
100 {
101 if (isLookingAtMe(player))
102 {
103 aggroedByPlayer = true;
104 if (aggroTime == 0) level->playEntitySound(player, eSoundType_MOB_ENDERMAN_STARE, 1, 1);
105 if (aggroTime++ == 5)
106 {
107 aggroTime = 0;
108 setCreepy(true);
109 return player;
110 }
111 }
112 else
113 {
114 aggroTime = 0;
115 }
116 }
117 return nullptr;
118}
119
120bool EnderMan::isLookingAtMe(shared_ptr<Player> player)
121{
122 shared_ptr<ItemInstance> helmet = player->inventory->armor[3];
123 if (helmet != NULL && helmet->id == Tile::pumpkin_Id) return false;
124
125 Vec3 *look = player->getViewVector(1)->normalize();
126 Vec3 *dir = Vec3::newTemp(x - player->x, (bb->y0 + bbHeight / 2) - (player->y + player->getHeadHeight()), z - player->z);
127 double dist = dir->length();
128 dir = dir->normalize();
129 double dot = look->dot(dir);
130 if (dot > 1 - 0.025 / dist)
131 {
132 return player->canSee(shared_from_this());
133 }
134 return false;
135}
136
137void EnderMan::aiStep()
138{
139 if (isInWaterOrRain()) hurt(DamageSource::drown, 1);
140
141 if (lastAttackTarget != attackTarget)
142 {
143 AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
144 speed->removeModifier(SPEED_MODIFIER_ATTACKING);
145
146 if (attackTarget != NULL)
147 {
148 speed->addModifier(new AttributeModifier(*SPEED_MODIFIER_ATTACKING));
149 }
150 }
151
152 lastAttackTarget = attackTarget;
153
154 if (!level->isClientSide)
155 {
156 if (level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING))
157 {
158 if (getCarryingTile() == 0)
159 {
160 if (random->nextInt(20) == 0)
161 {
162 int xt = Mth::floor(x - 2 + random->nextDouble() * 4);
163 int yt = Mth::floor(y + random->nextDouble() * 3);
164 int zt = Mth::floor(z - 2 + random->nextDouble() * 4);
165 int t = level->getTile(xt, yt, zt);
166 if(MAY_TAKE[t])
167 {
168 setCarryingTile(level->getTile(xt, yt, zt));
169 setCarryingData(level->getData(xt, yt, zt));
170 level->setTileAndUpdate(xt, yt, zt, 0);
171 }
172 }
173 }
174 else
175 {
176 if (random->nextInt(2000) == 0)
177 {
178 int xt = Mth::floor(x - 1 + random->nextDouble() * 2);
179 int yt = Mth::floor(y + random->nextDouble() * 2);
180 int zt = Mth::floor(z - 1 + random->nextDouble() * 2);
181 int t = level->getTile(xt, yt, zt);
182 int bt = level->getTile(xt, yt - 1, zt);
183 if (t == 0 && bt > 0 && Tile::tiles[bt]->isCubeShaped())
184 {
185 level->setTileAndData(xt, yt, zt, getCarryingTile(), getCarryingData(), Tile::UPDATE_ALL);
186 setCarryingTile(0);
187 }
188 }
189 }
190 }
191 }
192
193
194 for (int i = 0; i < 2; i++)
195 {
196 level->addParticle(eParticleType_ender, x + (random->nextDouble() - 0.5) * bbWidth, y + random->nextDouble() * bbHeight - 0.25f, z + (random->nextDouble() - 0.5) * bbWidth,
197 (random->nextDouble() - 0.5) * 2, -random->nextDouble(), (random->nextDouble() - 0.5) * 2);
198 }
199
200 if (level->isDay() && !level->isClientSide)
201 {
202 float br = getBrightness(1);
203 if (br > 0.5f)
204 {
205 if (level->canSeeSky(Mth::floor(x), (int)floor( y + 0.5 ), Mth::floor(z)) && random->nextFloat() * 30 < (br - 0.4f) * 2)
206 {
207 attackTarget = nullptr;
208 setCreepy(false);
209 aggroedByPlayer = false;
210 teleport();
211 }
212 }
213 }
214
215 if (isInWaterOrRain() || isOnFire())
216 {
217 attackTarget = nullptr;
218 setCreepy(false);
219 aggroedByPlayer = false;
220 teleport();
221 }
222
223 if (isCreepy() && !aggroedByPlayer && random->nextInt(100) == 0)
224 {
225 setCreepy(false);
226 }
227
228 jumping = false;
229 if (attackTarget != NULL)
230 {
231 lookAt(attackTarget, 100, 100);
232 }
233
234 if (!level->isClientSide && isAlive())
235 {
236 if (attackTarget != NULL)
237 {
238 if ( attackTarget->instanceof(eTYPE_PLAYER) && isLookingAtMe(dynamic_pointer_cast<Player>(attackTarget)))
239 {
240 if (attackTarget->distanceToSqr(shared_from_this()) < 4 * 4)
241 {
242 teleport();
243 }
244 teleportTime = 0;
245 }
246 else if (attackTarget->distanceToSqr(shared_from_this()) > 16 * 16)
247 {
248 if (teleportTime++ >= 30)
249 {
250 if (teleportTowards(attackTarget))
251 {
252 teleportTime = 0;
253 }
254 }
255 }
256 }
257 else
258 {
259 setCreepy(false);
260 teleportTime = 0;
261 }
262 }
263
264 Monster::aiStep();
265}
266
267bool EnderMan::teleport()
268{
269 double xx = x + (random->nextDouble() - 0.5) * 64;
270 double yy = y + (random->nextInt(64) - 32);
271 double zz = z + (random->nextDouble() - 0.5) * 64;
272 return teleport(xx, yy, zz);
273}
274
275bool EnderMan::teleportTowards(shared_ptr<Entity> e)
276{
277 Vec3 *dir = Vec3::newTemp(x - e->x, bb->y0 + bbHeight / 2 - e->y + e->getHeadHeight(), z - e->z);
278 dir = dir->normalize();
279 double d = 16;
280 double xx = x + (random->nextDouble() - 0.5) * 8 - dir->x * d;
281 double yy = y + (random->nextInt(16) - 8) - dir->y * d;
282 double zz = z + (random->nextDouble() - 0.5) * 8 - dir->z * d;
283 return teleport(xx, yy, zz);
284}
285
286bool EnderMan::teleport(double xx, double yy, double zz)
287{
288 double xo = x;
289 double yo = y;
290 double zo = z;
291
292 x = xx;
293 y = yy;
294 z = zz;
295 bool ok = false;
296 int xt = Mth::floor(x);
297 int yt = Mth::floor(y);
298 int zt = Mth::floor(z);
299
300 if (level->hasChunkAt(xt, yt, zt))
301 {
302 bool landed = false;
303 while (!landed && yt > 0)
304 {
305 int t = level->getTile(xt, yt - 1, zt);
306 if (t == 0 || !(Tile::tiles[t]->material->blocksMotion()))
307 {
308 y--;
309 yt--;
310 }
311 else
312 {
313 landed = true;
314 }
315 }
316 if (landed)
317 {
318 setPos(x, y, z);
319 if (level->getCubes(shared_from_this(), bb)->empty() && !level->containsAnyLiquid(bb))
320 {
321 ok = true;
322 }
323 }
324 }
325
326
327 if (ok)
328 {
329 int count = 128;
330 for (int i = 0; i < count; i++)
331 {
332 double d = i / (count - 1.0);
333 float xa = (random->nextFloat() - 0.5f) * 0.2f;
334 float ya = (random->nextFloat() - 0.5f) * 0.2f;
335 float za = (random->nextFloat() - 0.5f) * 0.2f;
336
337 double _x = xo + (x - xo) * d + (random->nextDouble() - 0.5) * bbWidth * 2;
338 double _y = yo + (y - yo) * d + random->nextDouble() * bbHeight;
339 double _z = zo + (z - zo) * d + (random->nextDouble() - 0.5) * bbWidth * 2;
340
341 level->addParticle(eParticleType_ender, _x, _y, _z, xa, ya, za);
342 }
343 level->playSound(xo, yo, zo, eSoundType_MOB_ENDERMEN_PORTAL, 1, 1);
344 playSound(eSoundType_MOB_ENDERMEN_PORTAL, 1, 1);
345 return true;
346 }
347 else
348 {
349 setPos(xo, yo, zo);
350 return false;
351 }
352}
353
354int EnderMan::getAmbientSound()
355{
356 return isCreepy()? eSoundType_MOB_ENDERMAN_SCREAM : eSoundType_MOB_ENDERMEN_IDLE;
357}
358
359int EnderMan::getHurtSound()
360{
361 return eSoundType_MOB_ENDERMEN_HIT;
362}
363
364int EnderMan::getDeathSound()
365{
366 return eSoundType_MOB_ENDERMEN_DEATH;
367}
368
369int EnderMan::getDeathLoot()
370{
371 return Item::enderPearl_Id;
372}
373
374void EnderMan::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
375{
376 int loot = getDeathLoot();
377 if (loot > 0)
378 {
379 int count = random->nextInt(2 + playerBonusLevel);
380 for (int i = 0; i < count; i++)
381 spawnAtLocation(loot, 1);
382 }
383}
384
385// 4J Brought forward from 1.2.3 to help fix Enderman behaviour
386void EnderMan::setCarryingTile(int carryingTile)
387{
388 entityData->set(DATA_CARRY_ITEM_ID, (byte) (carryingTile & 0xff));
389}
390
391int EnderMan::getCarryingTile()
392{
393 return entityData->getByte(DATA_CARRY_ITEM_ID);
394}
395
396void EnderMan::setCarryingData(int carryingData)
397{
398 entityData->set(DATA_CARRY_ITEM_DATA, (byte) (carryingData & 0xff));
399}
400
401int EnderMan::getCarryingData()
402{
403 return entityData->getByte(DATA_CARRY_ITEM_DATA);
404}
405
406bool EnderMan::hurt(DamageSource *source, float damage)
407{
408 if (isInvulnerable()) return false;
409 setCreepy(true);
410
411 if ( dynamic_cast<EntityDamageSource *>(source) != NULL && source->getEntity()->instanceof(eTYPE_PLAYER))
412 {
413 aggroedByPlayer = true;
414 }
415
416 if (dynamic_cast<IndirectEntityDamageSource *>(source) != NULL)
417 {
418 aggroedByPlayer = false;
419 for (int i = 0; i < 64; i++)
420 {
421 if (teleport())
422 {
423 return true;
424 }
425 }
426 return false;
427 }
428 return Monster::hurt(source, damage);
429}
430
431bool EnderMan::isCreepy()
432{
433 return entityData->getByte(DATA_CREEPY) > 0;
434}
435
436void EnderMan::setCreepy(bool creepy)
437{
438 entityData->set(DATA_CREEPY, (byte)(creepy ? 1 : 0));
439}