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.h"
3#include "net.minecraft.world.entity.ai.attributes.h"
4#include "net.minecraft.world.entity.monster.h"
5#include "net.minecraft.world.level.h"
6#include "net.minecraft.world.level.tile.h"
7#include "net.minecraft.world.phys.h"
8#include "Bat.h"
9
10Bat::Bat(Level *level) : AmbientCreature(level)
11{
12 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
13 // the derived version of the function is called
14 this->defineSynchedData();
15 registerAttributes();
16 setHealth(getMaxHealth());
17
18 targetPosition = NULL;
19
20 setSize(.5f, .9f);
21 setResting(true);
22}
23
24void Bat::defineSynchedData()
25{
26 AmbientCreature::defineSynchedData();
27
28 entityData->define(DATA_ID_FLAGS, (char) 0);
29}
30
31float Bat::getSoundVolume()
32{
33 return 0.1f;
34}
35
36float Bat::getVoicePitch()
37{
38 return AmbientCreature::getVoicePitch() * .95f;
39}
40
41int Bat::getAmbientSound()
42{
43 if (isResting() && random->nextInt(4) != 0)
44 {
45 return -1;
46 }
47 return eSoundType_MOB_BAT_IDLE; //"mob.bat.idle";
48}
49
50int Bat::getHurtSound()
51{
52 return eSoundType_MOB_BAT_HURT; //"mob.bat.hurt";
53}
54
55int Bat::getDeathSound()
56{
57 return eSoundType_MOB_BAT_DEATH; //"mob.bat.death";
58}
59
60bool Bat::isPushable()
61{
62 // bats can't be pushed by other mobs
63 return false;
64}
65
66void Bat::doPush(shared_ptr<Entity> e)
67{
68 // bats don't push other mobs
69}
70
71void Bat::pushEntities()
72{
73 // bats don't push other mobs
74}
75
76void Bat::registerAttributes()
77{
78 AmbientCreature::registerAttributes();
79
80 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(6);
81}
82
83bool Bat::isResting()
84{
85 return (entityData->getByte(DATA_ID_FLAGS) & FLAG_RESTING) != 0;
86}
87
88void Bat::setResting(bool value)
89{
90 char current = entityData->getByte(DATA_ID_FLAGS);
91 if (value)
92 {
93 entityData->set(DATA_ID_FLAGS, (char) (current | FLAG_RESTING));
94 }
95 else
96 {
97 entityData->set(DATA_ID_FLAGS, (char) (current & ~FLAG_RESTING));
98 }
99}
100
101bool Bat::useNewAi()
102{
103 return true;
104}
105
106void Bat::tick()
107{
108
109 AmbientCreature::tick();
110
111 if (isResting())
112 {
113 xd = yd = zd = 0;
114 y = Mth::floor(y) + 1.0 - bbHeight;
115 }
116 else
117 {
118 yd *= .6f;
119 }
120
121}
122
123inline int signum(double x) { return (x > 0) - (x < 0); }
124
125void Bat::newServerAiStep()
126{
127 AmbientCreature::newServerAiStep();
128
129 if (isResting())
130 {
131 if (!level->isSolidBlockingTile(Mth::floor(x), (int) y + 1, Mth::floor(z)))
132 {
133 setResting(false);
134 level->levelEvent(nullptr, LevelEvent::SOUND_BAT_LIFTOFF, (int) x, (int) y, (int) z, 0);
135 }
136 else
137 {
138
139 if (random->nextInt(200) == 0)
140 {
141 yHeadRot = random->nextInt(360);
142 }
143
144 if (level->getNearestPlayer(shared_from_this(), 4.0f) != NULL)
145 {
146 setResting(false);
147 level->levelEvent(nullptr, LevelEvent::SOUND_BAT_LIFTOFF, (int) x, (int) y, (int) z, 0);
148 }
149 }
150 }
151 else
152 {
153
154 if (targetPosition != NULL && (!level->isEmptyTile(targetPosition->x, targetPosition->y, targetPosition->z) || targetPosition->y < 1))
155 {
156 delete targetPosition;
157 targetPosition = NULL;
158 }
159 if (targetPosition == NULL || random->nextInt(30) == 0 || targetPosition->distSqr((int) x, (int) y, (int) z) < 4)
160 {
161 delete targetPosition;
162 targetPosition = new Pos((int) x + random->nextInt(7) - random->nextInt(7), (int) y + random->nextInt(6) - 2, (int) z + random->nextInt(7) - random->nextInt(7));
163 }
164
165 double dx = (targetPosition->x + .5) - x;
166 double dy = (targetPosition->y + .1) - y;
167 double dz = (targetPosition->z + .5) - z;
168
169 xd = xd + (signum(dx) * .5f - xd) * .1f;
170 yd = yd + (signum(dy) * .7f - yd) * .1f;
171 zd = zd + (signum(dz) * .5f - zd) * .1f;
172
173 float yRotD = (float) (atan2(zd, xd) * 180 / PI) - 90;
174 float rotDiff = Mth::wrapDegrees(yRotD - yRot);
175 yya = .5f;
176 yRot += rotDiff;
177
178 if (random->nextInt(100) == 0 && level->isSolidBlockingTile(Mth::floor(x), (int) y + 1, Mth::floor(z)))
179 {
180 setResting(true);
181 }
182
183 }
184}
185
186bool Bat::makeStepSound()
187{
188 return false;
189}
190
191void Bat::causeFallDamage(float distance)
192{
193}
194
195void Bat::checkFallDamage(double ya, bool onGround)
196{
197 // this method is empty because flying creatures should
198 // not trigger the "fallOn" tile calls (such as trampling crops)
199}
200
201bool Bat::isIgnoringTileTriggers()
202{
203 return true;
204}
205
206bool Bat::hurt(DamageSource *source, float dmg)
207{
208 if (isInvulnerable()) return false;
209 if (!level->isClientSide)
210 {
211 if (isResting())
212 {
213 setResting(false);
214 }
215 }
216
217 return AmbientCreature::hurt(source, dmg);
218}
219
220void Bat::readAdditionalSaveData(CompoundTag *tag)
221{
222 AmbientCreature::readAdditionalSaveData(tag);
223
224 entityData->set(DATA_ID_FLAGS, tag->getByte(L"BatFlags"));
225}
226
227void Bat::addAdditonalSaveData(CompoundTag *entityTag)
228{
229 AmbientCreature::addAdditonalSaveData(entityTag);
230
231 entityTag->putByte(L"BatFlags", entityData->getByte(DATA_ID_FLAGS));
232}
233
234
235bool Bat::canSpawn()
236{
237 int yt = Mth::floor(bb->y0);
238 if (yt >= level->seaLevel) return false;
239
240 int xt = Mth::floor(x);
241 int zt = Mth::floor(z);
242
243 int br = level->getRawBrightness(xt, yt, zt);
244 int maxLight = 4;
245
246 if ((Calendar::GetDayOfMonth() + 1 == 10 && Calendar::GetDayOfMonth() >= 20) || (Calendar::GetMonth() + 1 == 11 && Calendar::GetMonth() <= 3))
247 {
248 maxLight = 7;
249 }
250 else if (random->nextBoolean())
251 {
252 return false;
253 }
254
255 if (br > random->nextInt(maxLight)) return false;
256
257 return AmbientCreature::canSpawn();
258}