aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/EnderDragon.h
blob: 9f39767ebfef38120eb9993a101a48b815223f1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#pragma once
using namespace std;
#include "BossMob.h"
#include "MultiEntityMob.h"
#include "Enemy.h"

class MultiEntityMobPart;
class EnderCrystal;
class Node;
class BinaryHeap;
class Path;

class EnderDragon : public Mob, public BossMob, public MultiEntityMob, public Enemy
{
public:
	eINSTANCEOF GetType() { return eTYPE_ENDERDRAGON; };
	static Entity *create(Level *level) { return new EnderDragon(level); }

private:	
	// 4J Added for new behaviours
	static const int DATA_ID_SYNCHED_ACTION = 17;

	static const int positionsLength = 64; // 4J Stu - Defined this so that we can keep the positions array as a basic type array
public:
	double xTarget, yTarget, zTarget;

	double positions[positionsLength][3];
	int posPointer;

	//MultiEntityMobPart[] subEntities;
	vector<shared_ptr<Entity> > subEntities;
	shared_ptr<MultiEntityMobPart> head;
	shared_ptr<MultiEntityMobPart> neck; // 4J Added
	shared_ptr<MultiEntityMobPart> body;
	shared_ptr<MultiEntityMobPart> tail1;
	shared_ptr<MultiEntityMobPart> tail2;
	shared_ptr<MultiEntityMobPart> tail3;
	shared_ptr<MultiEntityMobPart> wing1;
	shared_ptr<MultiEntityMobPart> wing2;

	float oFlapTime;
	float flapTime;
	bool newTarget;
	bool inWall;

	// 4J Stu - Added for new dragon behaviour
private:
	int m_fireballCharge;
	float m_holdingPatternAngle;
	bool m_holdingPatternClockwise;
	int m_actionTicks;
	int m_sittingDamageReceived;
	int m_remainingCrystalsCount;
	int m_flameAttacks;

	int m_iGrowlTimer;

	double m_headYRot;
	AABB *m_acidArea;

	NodeArray *m_nodes;
	int m_nodeAdjacency[24];
	BinaryHeap *openSet;
	Path *m_currentPath;

	enum EEnderdragonAction
	{
		e_EnderdragonAction_HoldingPattern,
		e_EnderdragonAction_StrafePlayer,
		e_EnderdragonAction_LandingApproach,
		e_EnderdragonAction_Landing,
		e_EnderdragonAction_Takeoff,
		e_EnderdragonAction_Sitting_Flaming,
		e_EnderdragonAction_Sitting_Scanning,
		e_EnderdragonAction_Sitting_Attacking,
	};

	static const int CRYSTAL_COUNT;

	static const int FLAME_TICKS;
	static const float FLAME_ANGLE;
	static const int FLAME_PASSES;
	static const int FLAME_FREQUENCY;
	static const int FLAME_RANGE;

	static const int ATTACK_TICKS;

	static const int SITTING_ATTACK_Y_VIEW_RANGE;
	static const int SITTING_ATTACK_VIEW_RANGE;
	static const int SITTING_ATTACK_RANGE;
	static const int SITTING_POST_ATTACK_IDLE_TICKS;
	static const int SITTING_SCANNING_IDLE_TICKS;
	static const int SITTING_FLAME_ATTACKS_COUNT;

	// The percentage of max health that the dragon will take while in the "Sitting" states before flying away
	static const float SITTING_ALLOWED_DAMAGE_PERCENTAGE;

	static const int PODIUM_X_POS = 0;
	static const int PODIUM_Z_POS = 0;

private:
	shared_ptr<Entity> attackTarget;

public:
	int dragonDeathTime;

public:
	shared_ptr<EnderCrystal> nearestCrystal;

private:
	void _init();

public:
	EnderDragon(Level *level);
	void AddParts();
	virtual ~EnderDragon();

protected:
	virtual void registerAttributes();
	virtual void defineSynchedData();

public:
	void getLatencyPos(doubleArray result, int step, float a);
	virtual void aiStep();

private:
	using MultiEntityMob::hurt;

	void checkCrystals();
	void checkAttack();
	void knockBack(vector<shared_ptr<Entity> > *entities);
	void hurt(vector<shared_ptr<Entity> > *entities);
	void findNewTarget();
	float rotWrap(double d);
	bool checkWalls(AABB *bb);

public:
	virtual bool hurt(shared_ptr<MultiEntityMobPart> MultiEntityMobPart, DamageSource *source, float damage);
	virtual bool hurt(DamageSource *source, float damage);

protected:
	virtual bool reallyHurt(DamageSource *source, float damage);
	virtual void tickDeath();

private:
	void spawnExitPortal(int x, int z);

protected:
	virtual void checkDespawn();
public:
	virtual vector<shared_ptr<Entity> > *getSubEntities();
	virtual bool isPickable();
	Level *getLevel();

protected:
	int getAmbientSound();
	int getHurtSound();
	float getSoundVolume();

private:
	// 4J added for new dragon behaviour
	bool setSynchedAction(EEnderdragonAction action, bool force = false);
	EEnderdragonAction getSynchedAction();
	int findClosestNode(double tX, double tY, double tZ);
	int findClosestNode();
	Path *findPath(int startIndex, int endIndex, Node *finalNode  = nullptr);
	Path *reconstruct_path(Node *from, Node *to);

	void strafeAttackTarget();
	void navigateToNextPathNode();

public:	
	virtual void addAdditonalSaveData(CompoundTag *entityTag);
	virtual void readAdditionalSaveData(CompoundTag *tag);
	
public:
	void handleCrystalDestroyed(DamageSource *source);

	float getTilt(float a);
	double getHeadYOffset(float a);
	double getHeadYRotDiff(float a);
	double getHeadPartYOffset(int partIndex, doubleArray bodyPos, doubleArray partPos);
	double getHeadPartYRotDiff(int partIndex, doubleArray bodyPos, doubleArray partPos);
	Vec3 *getHeadLookVector(float a);

	virtual wstring getAName() { return app.GetString(IDS_ENDERDRAGON); };
	virtual float getHealth() { return LivingEntity::getHealth(); };
	virtual float getMaxHealth() { return LivingEntity::getMaxHealth(); };
};