summaryrefslogtreecommitdiffstats
path: root/src/Mobs/Silverfish.cpp
blob: 76407151e2947d7da71ef6fd2fb22eb13f2c6682 (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

#include "Globals.h"

#include "Silverfish.h"

#include "../World.h"
#include "../Chunk.h"
#include "../Blocks/BlockHandler.h"
#include "../Blocks/BlockInfested.h"





cSilverfish::cSilverfish() :
	Super(
		"Silverfish",
		mtSilverfish,
		"entity.silverfish.hurt",
		"entity.silverfish.death",
		"entity.silverfish.ambient",
		0.4f,
		0.3f
	)
{
}





bool cSilverfish::DoTakeDamage(TakeDamageInfo & a_TDI)
{
	// Call on our brethren to attack!
	// TODO: stop this if /gamerule mobGriefing is set to false

	// If the entity didn't take any damage, bail:
	if (!Super::DoTakeDamage(a_TDI))
	{
		return false;
	}

	// Or, conversely took lethal damage, bail:
	if (m_Health <= 0)
	{
		return true;
	}

	if (a_TDI.Attacker == nullptr)
	{
		if ((a_TDI.DamageType != dtPoison) && (a_TDI.DamageType != dtPotionOfHarming))
		{
			// Bail if attacker doesn't exist and it wasn't a splash potion:
			return true;
		}
	}
	else if (!a_TDI.Attacker->IsPlayer())
	{
		// Bail if it wasn't a player attack:
		return true;
	}

	auto & Random = GetRandomProvider();

	// Tries to spawn another Silverfish, returning if the search should continue.
	auto CheckInfested = [this, &Random, Position = GetPosition().Floor()](const Vector3i Offset) mutable
	{
		const auto Block = Position + Offset;
		if (m_World->GetBlock(Block) == E_BLOCK_SILVERFISH_EGG)
		{
			m_World->DigBlock(Block);
			return Random.RandBool();
		}
		return false;
	};

	// Search the faces of an increasingly large cube (so the positions closest get looked at first)
	// of min 3, max 10, for infested blocks and spawn additional reinforcements:
	for (int CubeSideLength = 3; CubeSideLength <= 10; CubeSideLength += 2)
	{
		const int HalfSide = CubeSideLength / 2;

		for (int OffsetX = -HalfSide; OffsetX <= HalfSide; OffsetX++)
		{
			for (int OffsetZ = -HalfSide; OffsetZ <= HalfSide; OffsetZ++)
			{
				if (CheckInfested({OffsetX, +HalfSide, OffsetZ}) || CheckInfested({OffsetX, -HalfSide, OffsetZ}))
				{
					return true;
				}
			}
		}

		for (int OffsetX = -HalfSide; OffsetX <= HalfSide; OffsetX++)
		{
			for (int OffsetY = -HalfSide + 1; OffsetY <= HalfSide - 1; OffsetY++)
			{
				if (CheckInfested({OffsetX, OffsetY, +HalfSide}) || CheckInfested({OffsetX, OffsetY, -HalfSide}))
				{
					return true;
				}
			}
		}

		for (int OffsetZ = -HalfSide + 1; OffsetZ <= HalfSide - 1; OffsetZ++)
		{
			for (int OffsetY = -HalfSide + 1; OffsetY <= HalfSide - 1; OffsetY++)
			{
				if (CheckInfested({+HalfSide, OffsetY, OffsetZ}) || CheckInfested({-HalfSide, OffsetY, OffsetZ}))
				{
					return true;
				}
			}
		}
	}

	return true;
}