summaryrefslogtreecommitdiffstats
path: root/src/Entities/Compoments/AIAggresssiveComponent.cpp
blob: de8c8d2a9ef5a58b5598c5363ebdec8813fd5f07 (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
147
148
149
150

#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules
#include "AIAggressiveComponent.h"
#include "../Entities/Player.h"
#include "../Tracer.h"



void cAIAggressiveComponent::Tick(float a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);

	if (m_EMState == CHASING)
	{
		CheckEventLostPlayer();
	}
	else
	{
		CheckEventSeePlayer();
	}

	if (m_Target == NULL)
		return;

	cTracer LineOfSight(m_Self->GetWorld());
	Vector3d AttackDirection(m_Target->GetPosition() - m_Self->GetPosition());

	if (ReachedFinalDestination() && !LineOfSight.Trace(m_Self->GetPosition(), AttackDirection, (int)AttackDirection.Length()))
	{
		// Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls)
		Attack(a_Dt / 1000);
	}
}


void cAIAggressiveComponent::Attack(float a_Dt)
{
	float attack_interval = m_Self->GetAttackInterval();
	attack_interval += a_Dt * m_Self->GetAttackRate();

	if ((m_Target != NULL) && (attack_interval > 3.0))
	{
		// Setting this higher gives us more wiggle room for attackrate
		attack_interval = 0.0f;
		m_Target->TakeDamage(dtMobAttack, m_Self, m_Self->GetAttackDamage(), 0);
	}

	m_Self->SetAttackInterval(attack_interval);
}


bool cAIAggressiveComponent::IsMovingToTargetPosition()
{
	// Difference between destination x and target x is negligible (to 10^-12 precision)
	if (fabsf((float)m_Self->m_FinalDestination.x - (float)m_Target->GetPosX()) < std::numeric_limits<float>::epsilon())
	{
		return false;
	}
	// Difference between destination z and target z is negligible (to 10^-12 precision)
	else if (fabsf((float)m_Self->m_FinalDestination.z - (float)m_Target->GetPosZ()) > std::numeric_limits<float>::epsilon())
	{
		return false;
	}
	return true;
}


bool cAIAggressiveComponent::ReachedFinalDestination()
{
	if ((m_Self->GetPosition() - m_Self->m_FinalDestination).Length() <= m_Self->GetAttackRange())
	{
		return true;
	}
	
	return false;
}


/// Event Checkers
//Checks to see if EventSeePlayer should be fired
//monster sez: Do I see the player
void cAIAggressiveComponent::CheckEventSeePlayer(void)
{
	// TODO: Rewrite this to use cWorld's DoWithPlayers()
	cPlayer * Closest = m_Self->GetWorld()->FindClosestPlayer(m_Self->GetPosition(), (float)m_Self->GetSightDistance(), false);

	if (Closest != NULL)
	{
		EventSeePlayer(Closest);
	}
}


void cAIAggressiveComponent::CheckEventLostPlayer(void)
{	
	if (m_Target != NULL)
	{
		if ((m_Target->GetPosition() - m_Self->GetPosition()).Length() > m_Self->GetSightDistance())
		{
			EventLosePlayer();
		}
	}
	else
	{
		EventLosePlayer();
	}
}


/// Event Handlers
void cAIAggressiveComponent::EventSeePlayer(cEntity * a_Entity)
{
	if (!((cPlayer *)a_Entity)->IsGameModeCreative())
	{
		m_Target = a_Entity;
		m_EMState = CHASING;
	}
}


void cAIAggressiveComponent::EventLosePlayer(void)
{
	m_Target = NULL;
	m_EMState = IDLE;
}


/// State Logic
void cAIAggressiveComponent::InStateChasing(float a_Dt)
{

	if (m_Target != NULL)
	{
		if (m_Target->IsPlayer())
		{
			if (((cPlayer *)m_Target)->IsGameModeCreative())
			{
				m_EMState = IDLE;
				return;
			}
		}

		if (!IsMovingToTargetPosition())
		{
			m_Self->MoveToPosition(m_Target->GetPosition());
		}
	}
}