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
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "SplashPotionEntity.h"
#include "Pawn.h"
#include "../ClientHandle.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(const 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:
const 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_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(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
Splash(a_HitPos);
m_DestroyTimer = 2;
}
void cSplashPotionEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
a_EntityHit.TakeDamage(dtRangedAttack, this, 0, 1);
Splash(a_HitPos);
m_DestroyTimer = 5;
}
void cSplashPotionEntity::Splash(const Vector3d & a_HitPos)
{
cSplashPotionCallback Callback(a_HitPos, m_EntityEffectType, m_EntityEffect);
m_World->ForEachEntity(Callback);
m_World->BroadcastSoundParticleEffect(
2002,
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);
}
|