summaryrefslogtreecommitdiffstats
path: root/src/Entities/SplashPotionEntity.cpp
blob: 8356806b35d0fcf09bcaf6a3a46c53da3ca1cb31 (plain) (blame)
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
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "SplashPotionEntity.h"
#include "Pawn.h"
#include "../ClientHandle.h"
#include "../EffectID.h"





/** Converts an angle in radians into a byte representation used by the network protocol */
#define ANGLE_TO_PROTO(X) static_cast<Byte>(X * 255 / 360)





////////////////////////////////////////////////////////////////////////////////
// cSplashPotionEntityCallback:

/** Used to distribute the splashed potion effect among nearby entities */
class cSplashPotionCallback :
	public cEntityCallback
{
public:
	/** Creates the callback.
	@param a_HitPos            The position where the splash potion has splashed
	@param a_EntityEffectType  The effect type of the potion
	@param a_EntityEffect      The effect description */
	cSplashPotionCallback(Vector3d a_HitPos, cEntityEffect::eType a_EntityEffectType, const cEntityEffect & a_EntityEffect) :
		m_HitPos(a_HitPos),
		m_EntityEffectType(a_EntityEffectType),
		m_EntityEffect(a_EntityEffect)
	{
	}

	/** Called by cWorld::ForEachEntity(), adds the stored entity effect to the entity, if it is close enough. */
	virtual bool Item(cEntity * a_Entity) override
	{
		if (!a_Entity->IsPawn())
		{
			// Not an entity that can take effects
			return false;
		}

		double SplashDistance = (a_Entity->GetPosition() - m_HitPos).Length();
		if (SplashDistance >= 20)
		{
			// Too far away
			return false;
		}

		// y = -0.25x + 1, where x is the distance from the player. Approximation for potion splash.
		// TODO: better equation
		double Reduction = -0.25 * SplashDistance + 1.0;
		Reduction = std::max(Reduction, 0.0);

		static_cast<cPawn *>(a_Entity)->AddEntityEffect(m_EntityEffectType, m_EntityEffect.GetDuration(), m_EntityEffect.GetIntensity(), Reduction);
		return false;
	}

private:
	Vector3d m_HitPos;
	cEntityEffect::eType m_EntityEffectType;
	const cEntityEffect & m_EntityEffect;
};





////////////////////////////////////////////////////////////////////////////////
// cSplashPotionEntity:

cSplashPotionEntity::cSplashPotionEntity(
	cEntity * a_Creator,
	double a_X, double a_Y, double a_Z,
	const Vector3d & a_Speed,
	const cItem & a_Item
) :
	super(pkSplashPotion, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
	m_Item(a_Item),
	m_DestroyTimer(-1)
{
	SetSpeed(a_Speed);
	m_EntityEffectType = cEntityEffect::GetPotionEffectType(a_Item.m_ItemDamage);
	m_EntityEffect = cEntityEffect(
		cEntityEffect::GetPotionEffectDuration(a_Item.m_ItemDamage),
		cEntityEffect::GetPotionEffectIntensity(a_Item.m_ItemDamage)
	);
	m_PotionColor = cEntityEffect::GetPotionColor(a_Item.m_ItemDamage);
}





void cSplashPotionEntity::OnHitSolidBlock(Vector3d a_HitPos, eBlockFace a_HitFace)
{
	Splash(a_HitPos);
	m_DestroyTimer = 2;
}





void cSplashPotionEntity::OnHitEntity(cEntity & a_EntityHit, Vector3d a_HitPos)
{
	a_EntityHit.TakeDamage(dtRangedAttack, this, 0, 1);
	Splash(a_HitPos);
	m_DestroyTimer = 5;
}





void cSplashPotionEntity::Splash(Vector3d a_HitPos)
{
	cSplashPotionCallback Callback(a_HitPos, m_EntityEffectType, m_EntityEffect);
	m_World->ForEachEntity(Callback);

	m_World->BroadcastSoundParticleEffect(
		EffectID::PARTICLE_SPLASH_POTION,
		FloorC(a_HitPos.x),
		FloorC(a_HitPos.y),
		FloorC(a_HitPos.z),
		m_PotionColor
	);
}





void cSplashPotionEntity::SpawnOn(cClientHandle & a_Client)
{
	a_Client.SendSpawnObject(*this, 73, m_PotionColor, ANGLE_TO_PROTO(GetYaw()), ANGLE_TO_PROTO(GetPitch()));
	a_Client.SendEntityMetadata(*this);
}