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.h"
3#include "net.minecraft.world.phys.h"
4#include "net.minecraft.world.level.h"
5#include "net.minecraft.world.entity.h"
6#include "net.minecraft.world.entity.ai.attributes.h"
7#include "net.minecraft.world.entity.projectile.h"
8#include "net.minecraft.world.entity.player.h"
9#include "net.minecraft.world.entity.monster.h"
10#include "net.minecraft.world.item.h"
11#include "net.minecraft.world.damagesource.h"
12#include "net.minecraft.stats.h"
13#include "Ghast.h"
14#include "..\Minecraft.Client\Textures.h"
15#include "LevelEvent.h"
16#include "SoundTypes.h"
17
18
19
20void Ghast::_init()
21{
22 explosionPower = 1;
23 floatDuration = 0;
24 target = nullptr;
25 retargetTime = 0;
26 oCharge = 0;
27 charge = 0;
28
29 xTarget = 0.0f;
30 yTarget = 0.0f;
31 zTarget = 0.0f;
32}
33
34Ghast::Ghast(Level *level) : FlyingMob( level )
35{
36 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
37 // the derived version of the function is called
38 this->defineSynchedData();
39 registerAttributes();
40 setHealth(getMaxHealth());
41
42 _init();
43
44 setSize(4, 4);
45 fireImmune = true;
46 xpReward = Enemy::XP_REWARD_MEDIUM;
47}
48
49bool Ghast::isCharging()
50{
51 return entityData->getByte(DATA_IS_CHARGING) != 0;
52}
53
54bool Ghast::hurt(DamageSource *source, float dmg)
55{
56 if (isInvulnerable()) return false;
57 if (source->getMsgId() == ChatPacket::e_ChatDeathFireball)
58 {
59 if ( (source->getEntity() != NULL) && source->getEntity()->instanceof(eTYPE_PLAYER) )
60 {
61 // reflected fireball, kill the ghast
62 FlyingMob::hurt(source, 1000);
63 dynamic_pointer_cast<Player>(source->getEntity())->awardStat(GenericStats::ghast(), GenericStats::param_ghast());
64 return true;
65 }
66 }
67
68 return FlyingMob::hurt(source, dmg);
69}
70
71void Ghast::defineSynchedData()
72{
73 FlyingMob::defineSynchedData();
74
75 entityData->define(DATA_IS_CHARGING, (byte) 0);
76}
77
78void Ghast::registerAttributes()
79{
80 FlyingMob::registerAttributes();
81
82 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(10);
83}
84
85void Ghast::serverAiStep()
86{
87 if (!level->isClientSide && level->difficulty == Difficulty::PEACEFUL) remove();
88 checkDespawn();
89
90 oCharge = charge;
91 double xd = xTarget - x;
92 double yd = yTarget - y;
93 double zd = zTarget - z;
94
95 double dd = xd * xd + yd * yd + zd * zd;
96
97 if (dd < 1 * 1 || dd > 60 * 60)
98 {
99 xTarget = x + (random->nextFloat() * 2 - 1) * 16;
100 yTarget = y + (random->nextFloat() * 2 - 1) * 16;
101 zTarget = z + (random->nextFloat() * 2 - 1) * 16;
102 }
103
104 if (floatDuration-- <= 0)
105 {
106 floatDuration += random->nextInt(5) + 2;
107
108 dd = sqrt(dd);
109
110 if (canReach(xTarget, yTarget, zTarget, dd))
111 {
112 this->xd += xd / dd * 0.1;
113 this->yd += yd / dd * 0.1;
114 this->zd += zd / dd * 0.1;
115 }
116 else
117 {
118 xTarget = x;
119 yTarget = y;
120 zTarget = z;
121 }
122 }
123
124 if (target != NULL && target->removed) target = nullptr;
125 if (target == NULL || retargetTime-- <= 0)
126 {
127 target = level->getNearestAttackablePlayer(shared_from_this(), 100);
128 if (target != NULL)
129 {
130 retargetTime = 20;
131 }
132 }
133
134 double maxDist = 64.0f;
135 if (target != NULL && target->distanceToSqr(shared_from_this()) < maxDist * maxDist)
136 {
137 double xdd = target->x - x;
138 double ydd = (target->bb->y0 + target->bbHeight / 2) - (y + bbHeight / 2);
139 double zdd = target->z - z;
140 yBodyRot = yRot = -(float) atan2(xdd, zdd) * 180 / PI;
141
142 if (canSee(target))
143 {
144 if (charge == 10)
145 {
146 // 4J - change brought forward from 1.2.3
147 level->levelEvent(nullptr, LevelEvent::SOUND_GHAST_WARNING, (int) x, (int) y, (int) z, 0);
148 }
149 charge++;
150 if (charge == 20)
151 {
152 // 4J - change brought forward from 1.2.3
153 level->levelEvent(nullptr, LevelEvent::SOUND_GHAST_FIREBALL, (int) x, (int) y, (int) z, 0);
154 shared_ptr<LargeFireball> ie = shared_ptr<LargeFireball>( new LargeFireball(level, dynamic_pointer_cast<Mob>( shared_from_this() ), xdd, ydd, zdd) );
155 ie->explosionPower = explosionPower;
156 double d = 4;
157 Vec3 *v = getViewVector(1);
158 ie->x = x + v->x * d;
159 ie->y = y + bbHeight / 2 + 0.5f;
160 ie->z = z + v->z * d;
161 level->addEntity(ie);
162 charge = -40;
163 }
164 }
165 else
166 {
167 if (charge > 0) charge--;
168 }
169 }
170 else
171 {
172 yBodyRot = yRot = -(float) atan2(this->xd, this->zd) * 180 / PI;
173 if (charge > 0) charge--;
174 }
175
176 if (!level->isClientSide)
177 {
178 byte old = entityData->getByte(DATA_IS_CHARGING);
179 byte current = (byte) (charge > 10 ? 1 : 0);
180 if (old != current)
181 {
182 entityData->set(DATA_IS_CHARGING, current);
183 }
184 }
185}
186
187bool Ghast::canReach(double xt, double yt, double zt, double dist)
188{
189 double xd = (xTarget - x) / dist;
190 double yd = (yTarget - y) / dist;
191 double zd = (zTarget - z) / dist;
192
193 AABB *bb = this->bb->copy();
194 for (int d = 1; d < dist; d++)
195 {
196 bb->move(xd, yd, zd);
197 if (!level->getCubes( shared_from_this(), bb)->empty()) return false;
198 }
199
200 return true;
201}
202
203int Ghast::getAmbientSound()
204{
205 return eSoundType_MOB_GHAST_MOAN;
206}
207
208int Ghast::getHurtSound()
209{
210 return eSoundType_MOB_GHAST_SCREAM;
211}
212
213int Ghast::getDeathSound()
214{
215 return eSoundType_MOB_GHAST_DEATH;
216}
217
218int Ghast::getDeathLoot()
219{
220 return Item::gunpowder_Id;
221}
222
223void Ghast::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
224{
225 int count = random->nextInt(2) + random->nextInt(1 + playerBonusLevel);
226 for (int i = 0; i < count; i++)
227 {
228 spawnAtLocation(Item::ghastTear_Id, 1);
229 }
230 count = random->nextInt(3) + random->nextInt(1 + playerBonusLevel);
231 for (int i = 0; i < count; i++)
232 {
233 spawnAtLocation(Item::gunpowder_Id, 1);
234 }
235}
236
237float Ghast::getSoundVolume()
238{
239 return 0.4f;//10; 4J-PB - changing due to customer demands
240}
241
242bool Ghast::canSpawn()
243{
244 return (random->nextInt(20) == 0 && FlyingMob::canSpawn() && level->difficulty > Difficulty::PEACEFUL);
245}
246
247int Ghast::getMaxSpawnClusterSize()
248{
249 return 1;
250}
251void Ghast::addAdditonalSaveData(CompoundTag *tag)
252{
253 FlyingMob::addAdditonalSaveData(tag);
254 tag->putInt(L"ExplosionPower", explosionPower);
255}
256
257void Ghast::readAdditionalSaveData(CompoundTag *tag)
258{
259 FlyingMob::readAdditionalSaveData(tag);
260 if (tag->contains(L"ExplosionPower")) explosionPower = tag->getInt(L"ExplosionPower");
261}