-
Notifications
You must be signed in to change notification settings - Fork 0
/
Pickable.cpp
175 lines (136 loc) · 5.9 KB
/
Pickable.cpp
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
#include "main.hpp"
bool Pickable::pick(Actor *t_owner, Actor *t_picker)
{
// Check if container has space
if (t_picker->m_container && t_picker->m_container->hasSpace())
{
// Look for myself in the engines "inventory"
auto it_actor{std::find_if(Engine::s_engine->m_actors.begin(), Engine::s_engine->m_actors.end(), [&t_owner](std::unique_ptr<Actor> &t_actor) { return t_actor.get() == t_owner; })};
// Did i find myself?
if (it_actor != Engine::s_engine->m_actors.end())
{
// Make move iterator
auto to_move{std::make_move_iterator(it_actor)};
// Add myself to the picker's inventory
t_picker->m_container->m_inventory.emplace_back(*to_move);
// Clean my previous position at the engine's "inventory"
Engine::s_engine->m_actors.erase(it_actor);
// Item moved suceesfully
return true;
}
}
// The destination doesn't have enough space to store me
return false;
}
bool Pickable::use(Actor *t_owner, Actor *t_carrier)
{
// Does the wearer even have an inventory?
if (t_carrier->m_container)
{
// Remove already handles memory thanks to smart pointers
t_carrier->m_container->remove(t_carrier, t_owner);
return true;
}
return false;
}
void Pickable::drop(Actor *t_owner, Actor *t_dropper)
{
// Check if owner has container
if (t_dropper->m_container)
{
// Look for the items unique_ptr in the droppers inventory
auto it_item{std::find_if(
t_dropper->m_container->m_inventory.begin(),
t_dropper->m_container->m_inventory.end(),
[this](std::unique_ptr<Actor> &t_item) { return t_item->m_pickable.get() == this; })};
// Check if there was a match
if (it_item != t_dropper->m_container->m_inventory.end())
{
// Change coordinates to the dropper's coordinates, else the item would appeaer where it was first picked
t_owner->m_x = t_dropper->m_x;
t_owner->m_y = t_dropper->m_y;
// Make move iterator
auto to_move{std::make_move_iterator(it_item)};
// Get the item into the level's "inventory"
Engine::s_engine->m_actors.emplace_back(*to_move);
// Clean the pludered item in the dropper's inventory
t_dropper->m_container->m_inventory.erase(it_item);
// Display a message
Engine::s_engine->m_gui->message(TCODColor::lightGrey, "%s drops a %s.", t_dropper->m_name.c_str(), t_owner->m_name.c_str());
}
}
}
Healer::Healer(const float t_amount) : m_amount{t_amount} {}
bool Healer::use(Actor *t_owner, Actor *t_carrier)
{
// Can the carrier even be healed?
if (t_carrier->m_destructible)
{
// Heal by the amount of the healer item
float amountHealed{t_carrier->m_destructible->heal(m_amount)};
if (amountHealed > 0)
{
return Pickable::use(t_owner, t_carrier);
}
}
return false;
}
LightingBolt::LightingBolt(const float t_range, const float t_damage) : m_range{t_range}, m_damage{t_damage} {}
bool LightingBolt::use(Actor *t_owner, Actor *t_user)
{
Actor *closestMonster{Engine::s_engine->getClosestMonster(t_user->m_x, t_user->m_y, m_range)};
if (!closestMonster)
{
Engine::s_engine->m_gui->message(TCODColor::lightGrey, "No enemy is close enough to strike.");
return false;
}
// Hit closest monster for damage
Engine::s_engine->m_gui->message(TCODColor::lightBlue, "A lighting bolt strikes the %s with a loud thunder!\nThe damage is %g hit points.", closestMonster->m_name.c_str(), m_damage);
closestMonster->m_destructible->takeDamage(closestMonster, DamageType::ELECTRIC,m_damage);
return Pickable::use(t_owner, t_user);
}
FireBall::FireBall(const float t_range, const float t_damage) : LightingBolt(t_range, t_damage) {}
bool FireBall::use(Actor *t_owner, Actor *t_user)
{
Engine::s_engine->m_gui->message(TCODColor::cyan, "Left click a target to shoot fireball.\nRight click to cancel.");
int x{0};
int y{0};
// pickATile() returns false if selection is canceled
if (!Engine::s_engine->pickATile(&x, &y))
{
return false;
}
// Burn all in range (including player)
Engine::s_engine->m_gui->message(TCODColor::orange, "The firebal explodes, burning everything within %g tiles!", m_range);
for (auto it_actor{Engine::s_engine->m_actors.begin()}; it_actor < Engine::s_engine->m_actors.end(); it_actor++)
{
if ((*it_actor)->m_destructible && !(*it_actor)->m_destructible->isDead() && (*it_actor)->getDistance(x, y) <= m_range)
{
Engine::s_engine->m_gui->message(TCODColor::orange, "The %s gets burned for %g hit points.", (*it_actor)->m_name.c_str(), m_damage);
(*it_actor)->m_destructible->takeDamage((*it_actor).get(), DamageType::HEAT, m_damage);
}
}
return Pickable::use(t_owner, t_user);
}
Confuser::Confuser(const int t_num_turns, const float t_range) : m_num_turns{t_num_turns}, m_range{t_range} {}
bool Confuser::use(Actor *t_owner, Actor *t_user)
{
Engine::s_engine->m_gui->message(TCODColor::cyan, "Left-click an enemy to confuse it,'n or right-click to cancel.");
int x{0};
int y{0};
if (!Engine::s_engine->pickATile(&x, &y, m_range))
{
return false;
}
Actor *actor{Engine::s_engine->getActor(x, y)};
if (!actor)
{
return false;
}
// Confuse the fpr <m_num_turns> turns
std::unique_ptr<ConfusedMonsterAi> confuseAi{std::make_unique<ConfusedMonsterAi>(m_num_turns, std::move(actor->m_ai))};
actor->m_ai = std::move(confuseAi);
// Display use message and destroy the scroll
Engine::s_engine->m_gui->message(TCODColor::lightGreen, "The eyes of the %s look vacant, \nas it starts to stumble around!", actor->m_name.c_str());
return Pickable::use(t_owner, t_user);
}