Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
louiz’
batajelo
Commits
a901f1ec
Commit
a901f1ec
authored
Jan 21, 2015
by
louiz’
Browse files
Implement the cast of abilities
With an example of Blink
parent
b6db67cd
Changes
33
Hide whitespace changes
Inline
Side-by-side
src/game/game.cpp
View file @
a901f1ec
...
...
@@ -53,6 +53,31 @@ void Game::move_callback(Message* message)
srl
.
turn
());
}
void
Game
::
cast_callback
(
Message
*
message
)
{
log_debug
(
"Game::cast_callback"
);
auto
srl
=
message
->
parse_body_to_protobuf_object
<
ser
::
order
::
Cast
>
();
if
(
!
srl
.
IsInitialized
())
{
log_error
(
"Invalid data received for cast: "
<<
srl
.
InitializationErrorString
());
return
;
}
std
::
vector
<
EntityId
>
ids
;
for
(
const
auto
&
id
:
srl
.
entity_id
())
ids
.
push_back
(
id
);
Position
pos
;
pos
.
x
.
raw
()
=
srl
.
pos
().
x
();
pos
.
y
.
raw
()
=
srl
.
pos
().
y
();
uint32_t
type
=
srl
.
type
();
this
->
turn_handler
.
insert_action
(
std
::
bind
(
&
World
::
do_cast
,
&
this
->
world
,
ids
,
pos
,
static_cast
<
AbilityType
>
(
type
),
srl
.
queue
()),
srl
.
turn
());
}
void
Game
::
do_new_entity
(
const
EntityType
type
,
const
Position
&
pos
,
const
uint16_t
team
)
{
log_debug
(
"Game::do_new_entity"
);
...
...
src/game/game.hpp
View file @
a901f1ec
...
...
@@ -21,6 +21,7 @@ public:
void
new_entity_callback
(
Message
*
msg
);
void
move_callback
(
Message
*
msg
);
void
cast_callback
(
Message
*
msg
);
virtual
void
do_new_entity
(
const
EntityType
type
,
const
Position
&
pos
,
const
uint16_t
team
);
...
...
src/game/game_client.cpp
View file @
a901f1ec
...
...
@@ -29,6 +29,8 @@ GameClient::GameClient(const std::shared_ptr<Screen>& screen):
std
::
bind
(
&
GameClient
::
turn_callback
,
this
,
std
::
placeholders
::
_1
));
this
->
install_callback
(
"MOVE"
,
std
::
bind
(
&
Game
::
move_callback
,
this
,
std
::
placeholders
::
_1
));
this
->
install_callback
(
"CAST"
,
std
::
bind
(
&
Game
::
cast_callback
,
this
,
std
::
placeholders
::
_1
));
this
->
screen
->
add_element
(
&
this
->
camera
,
0
);
this
->
screen
->
add_element
(
&
this
->
hud
,
1
);
...
...
@@ -226,10 +228,11 @@ void GameClient::path_callback(Message* message)
{
}
bool
GameClient
::
action_move
(
std
::
vector
<
EntityId
>
ids
,
const
Position
&
pos
,
const
bool
queue
)
bool
GameClient
::
action_move
(
const
std
::
vector
<
EntityId
>
&
ids
,
const
Position
&
pos
,
const
bool
queue
)
{
ser
::
request
::
Move
srl
;
srl
.
set_queue
(
queue
);
if
(
queue
)
srl
.
set_queue
(
queue
);
srl
.
mutable_pos
()
->
set_x
(
pos
.
x
.
raw
());
srl
.
mutable_pos
()
->
set_y
(
pos
.
y
.
raw
());
for
(
const
EntityId
id
:
ids
)
...
...
@@ -238,6 +241,21 @@ bool GameClient::action_move(std::vector<EntityId> ids, const Position& pos, con
return
true
;
}
bool
GameClient
::
action_cast
(
const
std
::
vector
<
EntityId
>&
ids
,
const
Position
&
pos
,
const
AbilityType
&
type
,
const
bool
queue
)
{
ser
::
request
::
Cast
srl
;
if
(
queue
)
srl
.
set_queue
(
queue
);
srl
.
mutable_pos
()
->
set_x
(
pos
.
x
.
raw
());
srl
.
mutable_pos
()
->
set_y
(
pos
.
y
.
raw
());
for
(
const
EntityId
id
:
ids
)
srl
.
add_entity_id
(
id
);
srl
.
set_type
(
static_cast
<
uint32_t
>
(
type
));
this
->
send_message
(
"CAST"
,
srl
);
return
true
;
}
void
GameClient
::
select_entity
(
const
Entity
*
entity
)
{
this
->
current_selection
.
add_to_selection
(
entity
);
...
...
src/game/game_client.hpp
View file @
a901f1ec
...
...
@@ -78,10 +78,21 @@ public:
void
graphical_tick
();
/**
* Give the order to all selected and movable units to move to the given
* world coordinates.
* Send, to the server, a request to move the given entities to the given
* destination. Queue indicates whether or not this work should be queued.
*/
bool
action_move
(
const
std
::
vector
<
EntityId
>&
ids
,
const
Position
&
pos
,
const
bool
queue
);
/**
* Send, to the server, a request to make the list of entities cast the
* given spell. There are three versions, each for each type of possible
* target (Position, Entity, nothing).
*/
bool
action_move
(
std
::
vector
<
EntityId
>
ids
,
const
Position
&
pos
,
bool
action_cast
(
const
std
::
vector
<
EntityId
>&
ids
,
const
Position
&
pos
,
const
AbilityType
&
type
,
const
bool
queue
);
bool
action_cast
(
const
std
::
vector
<
EntityId
>&
ids
,
const
EntityId
target
,
const
AbilityType
&
type
,
const
bool
queue
);
bool
action_cast
(
const
std
::
vector
<
EntityId
>&
ids
,
const
AbilityType
&
type
,
const
bool
queue
);
/**
* Give the order to all selected and movable units to move to the given
...
...
src/game/game_server.cpp
View file @
a901f1ec
...
...
@@ -205,11 +205,49 @@ void GameServer::on_move_request(Message* message)
for
(
const
auto
&
id
:
srl
.
entity_id
())
ids
.
push_back
(
id
);
Position
pos
;
pos
.
x
.
raw
()
=
srl
.
mutable_
pos
()
->
x
();
pos
.
y
.
raw
()
=
srl
.
mutable_
pos
()
->
y
();
pos
.
x
.
raw
()
=
srl
.
pos
()
.
x
();
pos
.
y
.
raw
()
=
srl
.
pos
()
.
y
();
this
->
send_move_order
(
ids
,
pos
,
srl
.
queue
());
}
void
GameServer
::
on_cast_request
(
Message
*
message
)
{
auto
srl
=
message
->
parse_body_to_protobuf_object
<
ser
::
request
::
Cast
>
();
if
(
!
srl
.
IsInitialized
())
{
log_error
(
"Invalid data received for Cast request: "
<<
srl
.
InitializationErrorString
());
return
;
}
std
::
vector
<
EntityId
>
ids
;
for
(
const
auto
&
id
:
srl
.
entity_id
())
ids
.
push_back
(
id
);
if
(
srl
.
has_pos
())
{
Position
pos
;
pos
.
x
.
raw
()
=
srl
.
pos
().
x
();
pos
.
y
.
raw
()
=
srl
.
pos
().
y
();
this
->
send_cast_order
(
ids
,
pos
,
srl
.
type
(),
srl
.
queue
());
}
}
void
GameServer
::
send_cast_order
(
const
std
::
vector
<
EntityId
>&
ids
,
const
Position
&
pos
,
const
uint32_t
type
,
const
bool
queue
)
{
ser
::
order
::
Cast
srl
;
srl
.
set_turn
(
this
->
turn_handler
.
get_current_turn
()
+
2
);
if
(
queue
)
srl
.
set_queue
(
queue
);
for
(
const
EntityId
id
:
ids
)
srl
.
add_entity_id
(
id
);
srl
.
set_type
(
type
);
srl
.
mutable_pos
()
->
set_x
(
pos
.
x
.
raw
());
srl
.
mutable_pos
()
->
set_y
(
pos
.
y
.
raw
());
this
->
send_order_to_all
(
"CAST"
,
srl
);
this
->
turn_handler
.
insert_action
(
std
::
bind
(
&
World
::
do_cast
,
&
this
->
world
,
ids
,
pos
,
static_cast
<
AbilityType
>
(
type
),
queue
),
srl
.
turn
());
}
void
GameServer
::
send_new_entity_order
(
const
EntityType
type
,
const
Position
&
pos
,
const
uint16_t
team
)
{
...
...
src/game/game_server.hpp
View file @
a901f1ec
...
...
@@ -68,6 +68,16 @@ public:
void
send_new_entity_order
(
const
EntityType
type
,
const
Position
&
pos
,
const
uint16_t
team
);
void
send_move_order
(
const
std
::
vector
<
EntityId
>
ids
,
const
Position
&
pos
,
const
bool
queue
);
/**
* Send an Order to each client, to make each of these entities cast the
* given ability.
*/
void
send_cast_order
(
const
std
::
vector
<
EntityId
>&
ids
,
const
Position
&
pos
,
const
uint32_t
type
,
const
bool
queue
);
void
send_cast_order
(
const
std
::
vector
<
EntityId
>&
ids
,
const
EntityId
pos
,
const
uint32_t
type
,
const
bool
queue
);
void
send_cast_order
(
const
std
::
vector
<
EntityId
>&
ids
,
const
uint32_t
type
,
const
bool
queue
);
/**
* This will create the initial game
* state.
...
...
@@ -87,6 +97,10 @@ public:
* send that path action to all clients.
*/
void
on_move_request
(
Message
*
);
/**
* Called whenever we receive a CAST message from one client.
*/
void
on_cast_request
(
Message
*
);
/**
* Called whenever we receive a BUILD message from one client.
* Check if the position is valid and the building can be built (money, the unit actually has this ability, etc).
...
...
src/game/remote_game_client.cpp
View file @
a901f1ec
...
...
@@ -26,4 +26,5 @@ void RemoteGameClient::on_connection_closed()
void
RemoteGameClient
::
install_callbacks
()
{
this
->
install_callback
(
"MOVE"
,
std
::
bind
(
&
GameServer
::
on_move_request
,
this
->
server
,
std
::
placeholders
::
_1
));
this
->
install_callback
(
"CAST"
,
std
::
bind
(
&
GameServer
::
on_cast_request
,
this
->
server
,
std
::
placeholders
::
_1
));
}
src/game/turn_handler.cpp
View file @
a901f1ec
...
...
@@ -33,7 +33,6 @@ void TurnHandler::tick()
{
if
(
this
->
is_next_turn_ready
()
==
false
)
{
log_debug
(
"Next turn is not validated"
);
this
->
pause
();
return
;
}
...
...
src/gui/camera/camera.cpp
View file @
a901f1ec
...
...
@@ -94,50 +94,12 @@ bool Camera::handle_event(const sf::Event& event)
log_debug
(
"Mouse button not implemented."
);
}
}
else
if
(
event
.
type
==
sf
::
Event
::
KeyPressed
)
this
->
handle_keypress
(
event
);
this
->
fixup_camera_position
();
if
(
this
->
mouse_selection
.
ongoing
==
true
)
return
true
;
return
false
;
}
void
Camera
::
activate_ability
(
const
std
::
size_t
nb
)
{
const
Selection
&
selection
=
this
->
game
->
get_selection
();
if
(
selection
.
is_empty
())
this
->
game
->
get_hud
().
add_info_message
(
"No entity selected"
);
else
{
const
auto
entity
=
selection
.
get_entities
().
front
();
Abilities
*
abilities
=
entity
->
get
<
Abilities
>
();
if
(
!
abilities
)
this
->
game
->
get_hud
().
add_info_message
(
"Selected entity has no ability."
);
else
{
const
Ability
*
ability
=
abilities
->
get
(
nb
);
if
(
!
ability
)
this
->
game
->
get_hud
().
add_info_message
(
"Selected entity has no ability number "
+
std
::
to_string
(
nb
));
else
{
this
->
game
->
get_hud
().
add_info_message
(
"Activating ability "
+
ability
->
get_name
());
}
}
}
// TODO actually only look in the abilities of active entity TYPE, not the
// first one
}
void
Camera
::
handle_keypress
(
const
sf
::
Event
&
event
)
{
this
->
game
->
get_hud
().
add_info_message
(
"Received key: "
+
std
::
to_string
(
event
.
key
.
code
));
switch
(
event
.
key
.
code
)
{
case
sf
::
Keyboard
::
A
:
this
->
activate_ability
(
0
);
}
}
void
Camera
::
handle_middle_click
(
const
sf
::
Event
&
)
{
}
...
...
src/gui/camera/fog.cpp
View file @
a901f1ec
...
...
@@ -24,7 +24,7 @@ Fog::Fog(const unsigned int width, const unsigned int height,
void
Fog
::
resize
(
const
unsigned
int
width
,
const
unsigned
int
height
)
{
// TODO, have a fallback
assert
(
this
->
texture
.
create
(
width
,
height
)
)
;
this
->
texture
.
create
(
width
,
height
);
this
->
texture
.
setSmooth
(
true
);
this
->
invalidate
();
}
...
...
src/gui/hud/abilities_panel.cpp
0 → 100644
View file @
a901f1ec
#include
<SFML/Graphics.hpp>
#include
<gui/hud/abilities_panel.hpp>
#include
<game/game_client.hpp>
#include
<logging/logging.hpp>
#include
<world/entity.hpp>
#include
<world/abilities.hpp>
#include
<world/abilities/blink.hpp>
#include
<utility>
AbilitiesPanel
::
AbilitiesPanel
(
GameClient
*
game
)
{
auto
&
blink
=
this
->
gui_abilities
[
AbilityType
::
Blink
];
blink
.
left_click
=
{
[
game
](
const
Position
&
pos
)
{
std
::
vector
<
EntityId
>
ids
;
const
auto
&
selection
=
game
->
get_selection
();
if
(
selection
.
is_empty
())
return
true
;
// Find all entities with a blink ability
for
(
const
auto
&
entity
:
selection
.
get_entities
())
{
Abilities
*
abilities
=
entity
->
get
<
Abilities
>
();
if
(
abilities
)
{
Ability
*
ability
=
abilities
->
find
(
AbilityType
::
Blink
);
if
(
ability
)
{
Blink
*
blink
=
static_cast
<
Blink
*>
(
ability
);
// Check cooldown, mana, etc etc etc
Entity
*
e
=
const_cast
<
Entity
*>
(
entity
);
ids
.
push_back
(
e
->
get_id
());
}
}
}
if
(
ids
.
empty
())
return
true
;
const
bool
queue
=
(
sf
::
Keyboard
::
isKeyPressed
(
sf
::
Keyboard
::
LShift
)
||
sf
::
Keyboard
::
isKeyPressed
(
sf
::
Keyboard
::
RShift
));
return
game
->
action_cast
(
ids
,
pos
,
AbilityType
::
Blink
,
queue
);
},
[](
const
sf
::
Vector2i
&
)
{
return
cursor
::
Move
;
}
};
}
const
GuiAbility
*
AbilitiesPanel
::
get
(
const
AbilityType
&
type
)
const
{
const
auto
it
=
this
->
gui_abilities
.
find
(
type
);
if
(
it
==
this
->
gui_abilities
.
end
())
return
nullptr
;
return
&
it
->
second
;
}
src/gui/hud/abilities_panel.hpp
0 → 100644
View file @
a901f1ec
#ifndef ABILITIES_PANEL_HPP_INCLUDED
#define ABILITIES_PANEL_HPP_INCLUDED
#include
<world/abilities.hpp>
#include
<gui/hud/gui_ability.hpp>
#include
<map>
class
GameClient
;
class
AbilitiesPanel
{
public:
AbilitiesPanel
(
GameClient
*
game
);
~
AbilitiesPanel
()
=
default
;
const
GuiAbility
*
get
(
const
AbilityType
&
type
)
const
;
private:
std
::
map
<
AbilityType
,
GuiAbility
>
gui_abilities
;
AbilitiesPanel
(
const
AbilitiesPanel
&
)
=
delete
;
AbilitiesPanel
(
AbilitiesPanel
&&
)
=
delete
;
AbilitiesPanel
&
operator
=
(
const
AbilitiesPanel
&
)
=
delete
;
AbilitiesPanel
&
operator
=
(
AbilitiesPanel
&&
)
=
delete
;
};
#endif
/* ABILITIES_PANEL_HPP_INCLUDED */
src/gui/hud/gui_ability.hpp
0 → 100644
View file @
a901f1ec
#ifndef GUI_ABILITY_HPP_INCLUDED
#define GUI_ABILITY_HPP_INCLUDED
/**
* Contains all the information about an ability, for the GUI part. For
* example the icone to use, the activate callback (it can execute the
* ability directly, or change the LeftClick structure, which only involves
* the GUI)
*/
#include
<gui/screen/left_click.hpp>
class
GuiAbility
{
public:
GuiAbility
()
=
default
;
~
GuiAbility
()
=
default
;
LeftClick
left_click
;
private:
GuiAbility
(
const
GuiAbility
&
)
=
delete
;
GuiAbility
(
GuiAbility
&&
)
=
delete
;
GuiAbility
&
operator
=
(
const
GuiAbility
&
)
=
delete
;
GuiAbility
&
operator
=
(
GuiAbility
&&
)
=
delete
;
};
#endif
/* GUI_ABILITY_HPP_INCLUDED */
src/gui/hud/hud.cpp
View file @
a901f1ec
...
...
@@ -7,6 +7,7 @@
#include
<world/abilities.hpp>
#include
<world/abilities/blink.hpp>
#include
<gui/hud/abilities_panel.hpp>
#include
<logging/logging.hpp>
...
...
@@ -16,7 +17,8 @@ Hud::Hud(GameClient* game, Screen* screen):
// minimap(game, screen),
// selection_panel(game, world->get_selection_ptr()),
// action_panel(game, screen, world->get_selection_ptr(), mod),
game
(
game
)
game
(
game
),
abilities_panel
(
game
)
{
const
sf
::
Vector2u
win_size
=
this
->
screen
->
get_window_size
();
// Install a callback on the selection that will reset the action_panel
...
...
@@ -87,12 +89,22 @@ void Hud::draw()
bool
Hud
::
handle_event
(
const
sf
::
Event
&
event
)
{
// if (this->minimap.handle_event(event) == true)
// return true;
// if (this->selection_panel.handle_event(event, this->world) == true)
// return true;
// if (this->action_panel.handle_event(event) == true)
// return true;
if
(
event
.
type
==
sf
::
Event
::
KeyPressed
)
return
this
->
handle_keypress
(
event
);
return
false
;
}
bool
Hud
::
handle_keypress
(
const
sf
::
Event
&
event
)
{
this
->
game
->
get_hud
().
add_info_message
(
"Received key: "
+
std
::
to_string
(
event
.
key
.
code
));
switch
(
event
.
key
.
code
)
{
case
sf
::
Keyboard
::
A
:
this
->
activate_ability
(
0
);
return
true
;
default:
return
false
;
}
return
false
;
}
...
...
@@ -111,3 +123,34 @@ bool Hud::is_entity_hovered(const Entity* entity) const
// return this->selection_panel.is_entity_hovered(entity);
return
false
;
}
void
Hud
::
activate_ability
(
const
std
::
size_t
nb
)
{
const
Selection
&
selection
=
this
->
game
->
get_selection
();
if
(
selection
.
is_empty
())
this
->
game
->
get_hud
().
add_info_message
(
"No entity selected"
);
else
{
const
auto
entity
=
selection
.
get_entities
().
front
();
Abilities
*
abilities
=
entity
->
get
<
Abilities
>
();
if
(
!
abilities
)
this
->
game
->
get_hud
().
add_info_message
(
"Selected entity has no ability."
);
else
{
const
Ability
*
ability
=
abilities
->
get
(
nb
);
if
(
!
ability
)
this
->
game
->
get_hud
().
add_info_message
(
"Selected entity has no ability number "
+
std
::
to_string
(
nb
));
else
{
this
->
game
->
get_hud
().
add_info_message
(
"Activating ability "
+
ability
->
get_name
());
this
->
game
->
get_hud
().
add_info_message
(
"The ability type is "
+
std
::
to_string
(
static_cast
<
int
>
(
ability
->
get_type
())));
const
GuiAbility
*
gui_ab
=
this
->
abilities_panel
.
get
(
ability
->
get_type
());
assert
(
gui_ab
);
this
->
screen
->
set_left_click
(
gui_ab
->
left_click
);
}
}
}
// TODO actually only look in the abilities of actiev entity TYPE, not the
// first one
}
src/gui/hud/hud.hpp
View file @
a901f1ec
...
...
@@ -17,11 +17,9 @@
#define HUD_HEIGHT 323
#include
<gui/camera/camera.hpp>
// #include <gui/hud/minimap.hpp>
// #include <gui/hud/selection_panel.hpp>
// #include <gui/hud/action_panel.hpp>
#include
<gui/screen/screen_element.hpp>
#include
<gui/hud/info_hud.hpp>
#include
<gui/hud/abilities_panel.hpp>
class
Screen
;
class
GameClient
;
...
...
@@ -36,18 +34,18 @@ public:
void
update
(
const
utils
::
Duration
&
dt
)
override
final
;
bool
is_entity_hovered
(
const
Entity
*
)
const
;
void
add_info_message
(
std
::
string
&&
text
);
void
activate_ability
(
const
std
::
size_t
nb
);
bool
handle_keypress
(
const
sf
::
Event
&
event
);
private:
Hud
(
const
Hud
&
);
Hud
&
operator
=
(
const
Hud
&
);
// Minimap minimap;
// SelectionPanel selection_panel;
// ActionPanel action_panel;
GameClient
*
game
;
sf
::
Texture
hud_texture
;
sf
::
Sprite
hud_sprite
;
sf
::
Font
font
;
AbilitiesPanel
abilities_panel
;
InfoHud
info_hud
;
};
...
...
src/gui/screen/screen.hpp
View file @
a901f1ec
...
...
@@ -31,31 +31,11 @@
#include
<world/position.hpp>
#include
<gui/screen/screen_element.hpp>
#include
<gui/
cursor
.hpp>
#include
<gui/
screen/left_click
.hpp>
#include
<vector>
#include
<memory>
/**
* Structure containing informations about the current “left click”
* action. It contains a callback of what happens when the user left clicks
* on the camera area, and what to draw at the cursor position.
*/
struct
LeftClick
{
/**
* The callback called when we left click. Returns True if the callback
* has been successfull and the LeftClick can be reset to LeftClick::null.
*/
std
::
function
<
bool
(
const
Position
&
world_position
)
>
callback
;
/**
* The callback called when we draw the cursor (for example to draw the
* area of effect of the selected spell, or the building to be built)
*/
std
::
function
<
cursor
::
type
(
const
sf
::
Vector2i
&
mouse_pos
)
>
cursor_callback
;
static
LeftClick
null
;
};
class
Screen
{
public:
...
...
src/network/server.hpp
View file @
a901f1ec
...
...
@@ -24,6 +24,7 @@
#include
<boost/asio.hpp>
#include
<boost/asio/steady_timer.hpp>
#include
<boost/chrono.hpp>
#include
<logging/logging.hpp>
#include
<network/base_ioservice.hpp>
...
...
src/world/abilities.cpp
View file @
a901f1ec
#include
<world/entity.hpp>
#include
<world/abilities.hpp>
#include
<cassert>
...
...
@@ -19,3 +20,33 @@ void Abilities::add(const std::size_t index,
{
this
->
abilities
[
index
]
=
std
::
move
(
ability
);
}
Ability
*
Abilities
::
find
(
const
AbilityType
&
type
)
const
{
for
(
auto
&
ability
:
this
->
abilities
)
{
if
(
ability
->
get_type
()
==
type
)
return
ability
.
get
();
}
return
nullptr
;
}
template
<
typename
T
>
T
*
get_ability
(
Entity
*
entity
)
{
Abilities
*
abilities
=
entity
->
get
<
Abilities
>
();
if
(
!
abilities
)
return
nullptr
;
Ability
*
ability
=
abilities
->
find
(
T
::
ability_type
);
if
(
!
ability
)
return
nullptr
;
return
static_cast
<
T
*>
(
ability
);
}
Ability
*
get_ability
(
Entity
*
entity
,
const
AbilityType
&
type
)
{
Abilities
*
abilities
=
entity
->
get
<
Abilities
>
();
if
(
!
abilities
)
return
nullptr
;
return
abilities
->
find
(
type
);
}
src/world/abilities.hpp
View file @
a901f1ec
...
...
@@ -3,7 +3,6 @@
/**
* Container for one or more abilities.
* This is static
*/
#include
<world/components.hpp>
...
...
@@ -32,6 +31,10 @@ public:
const
std
::
vector
<
std
::
unique_ptr
<
Ability
>>&
get
()
const
;
const
Ability
*
get
(
const
std
::
size_t
index
)
const
;
/**
* Look for an Ability with that type.
*/
Ability
*
find
(
const
AbilityType
&
type
)
const
;
private:
std
::
vector
<
std
::
unique_ptr
<
Ability
>>
abilities
;
...
...
@@ -42,4 +45,8 @@ private:
Abilities
&
operator
=
(
Abilities
&&
)
=
delete
;
};
template
<
typename
T
>