Commit 6f7ced4a authored by louiz’'s avatar louiz’
Browse files

Introduce the spawn work, for building.

Also fix the selection, properly handling a mouse selection containing
buildings etc. Also fix the archive building image.
parent 5b14a9a2
......@@ -2,6 +2,7 @@
- name: Tee
speed: 3
width: 15
spawn_duration: 10
actions:
- type: page # just goes to a different action page
value: 1
......@@ -19,6 +20,12 @@
sprite: building_archive
build_time: 10
cells: 1 # size in map squares
actions:
- type: spawn
value: 0
page: 0
position: 0
image: unit60.png
--- ####### Spells
- name: boost
......
......@@ -19,6 +19,7 @@ class Fix16: public Serializable
Fix16() { value = 0; }
Fix16(const Fix16 &inValue) { value = inValue.value; }
Fix16(const int inValue) { assert(inValue <= 32767); value = fix16_from_int(inValue); }
Fix16(const unsigned int inValue) { assert(inValue <= 32767); value = fix16_from_int(inValue); }
// Fix16(const unsigned int inValue) { value = fix16_from_int(inValue); }
// Fix16(const fix16_t inValue) { value = inValue; }
Fix16(const float inValue) { value = fix16_from_float(inValue); }
......
......@@ -90,4 +90,24 @@ DoBuildEvent::DoBuildEvent(const Command* command):
else
this->valid = true;
}
SpawnEvent::SpawnEvent(const Command* command)
{
if (this->from_string(std::string(command->body,
command->body_size).c_str()) == false)
this->valid = false;
else
this->valid = true;
}
DoSpawnEvent::DoSpawnEvent(const Command* command):
ActionEvent("SPAWN")
{
if (this->from_string(std::string(command->body,
command->body_size).c_str()) == false)
this->valid = false;
else
this->valid = true;
}
unsigned long int Event::current_id = 0;
......@@ -263,5 +263,65 @@ private:
DoBuildEvent& operator=(const DoBuildEvent&);
};
class SpawnEvent: virtual public Event
{
public:
SpawnEvent(): Event() {}
SpawnEvent(const Command*);
SpawnEvent(const SpawnEvent& e):
Event(),
type_id(e.type_id),
actor(e.actor)
{ }
virtual void serialize(boost::archive::text_oarchive& ar, const unsigned int v)
{
Event::serialize(ar, v);
ar & type_id & actor;
}
virtual void serialize(boost::archive::text_iarchive& ar, const unsigned int v)
{
Event::serialize(ar, v);
ar & type_id & actor;
}
/**
* The type_id of the unit to spawn.
*/
unsigned short type_id;
/**
* The id of the building thas has to spawn the unit.
*/
unsigned short actor;
private:
SpawnEvent& operator=(const SpawnEvent&);
};
class DoSpawnEvent: public ActionEvent, public SpawnEvent
{
public:
DoSpawnEvent(const Command*);
DoSpawnEvent(const SpawnEvent& o):
ActionEvent("SPAWN"),
SpawnEvent(o)
{
}
~DoSpawnEvent() {};
virtual void serialize(boost::archive::text_oarchive& ar, const unsigned int v)
{
ActionEvent::serialize(ar, v);
SpawnEvent::serialize(ar, v);
}
virtual void serialize(boost::archive::text_iarchive& ar, const unsigned int v)
{
ActionEvent::serialize(ar, v);
SpawnEvent::serialize(ar, v);
}
private:
DoSpawnEvent(const DoSpawnEvent&);
DoSpawnEvent& operator=(const DoSpawnEvent&);
};
#endif // __EVENT_HPP__
/**@}*/
......@@ -158,14 +158,24 @@ void Camera::set_mouse_selection_to_selection()
mouse_pos.y += this->y;
// First check the number of entities inside the selection. If it's 0, do
// nothing
uint n = 0;
unsigned int number_of_units = 0;
for (std::list<Unit*>::iterator it = this->world->units.begin(); it != this->world->units.end(); ++it)
if (this->mouse_selection.contains(mouse_pos,
this->world_to_camera_position((*it)->pos),
(*it)->width + 4))
n++;
if (n > 0)
number_of_units++;
unsigned int number_of_buildings = 0;
for (std::list<Building*>::iterator it = this->world->buildings.begin(); it != this->world->buildings.end(); ++it)
{
Position pos((*it)->x * CELL_SIZE + CELL_SIZE / 2,
(*it)->y * CELL_SIZE + CELL_SIZE / 2);
if (this->mouse_selection.contains(mouse_pos, this->world_to_camera_position(pos)))
number_of_buildings++;
}
log_warning("in mouse selection: Number of units: " << number_of_units << " and buildings: " << number_of_buildings);
if (number_of_buildings + number_of_units > 0)
{
bool new_unit_was_selected = false;
for (std::list<Unit*>::iterator it = this->world->units.begin(); it != this->world->units.end(); ++it)
{
if (this->mouse_selection.contains(mouse_pos,
......@@ -173,7 +183,32 @@ void Camera::set_mouse_selection_to_selection()
(*it)->width + 4))
{
if (this->world->is_entity_selected(*it) == false)
this->world->select_entity(*it);
{
new_unit_was_selected = true;
this->world->select_entity(*it);
}
}
else
{
if (this->world->is_entity_selected(*it) == true)
this->world->unselect_entity(*it);
}
}
for (std::list<Building*>::iterator it = this->world->buildings.begin(); it != this->world->buildings.end(); ++it)
{
Position pos((*it)->x * CELL_SIZE + CELL_SIZE / 2,
(*it)->y * CELL_SIZE + CELL_SIZE / 2);
if (this->mouse_selection.contains(mouse_pos, this->world_to_camera_position(pos)))
{
if (this->world->is_entity_selected(*it) == false)
{
// We select the building only if no unit was added to the
// selection. This way we can box an area and select only the units
// inside it, because that's what we want most of the time when
// doing that.
if (new_unit_was_selected == false)
this->world->select_entity(*it);
}
}
else
{
......@@ -301,6 +336,27 @@ void Camera::draw()
this->win->draw(tile->sprite);
}
}
Building* building;
for (std::list<Building*>::iterator it = this->world->buildings.begin(); it != this->world->buildings.end(); ++it)
{
building = *it;
Position pos(building->x * static_cast<short>(CELL_SIZE), building->y * static_cast<short>(CELL_SIZE));
this->world->get_cell_at_position(pos, cellx, celly);
sf::Vector2u entpos = this->world_to_camera_position(pos);
if ((celly == y) && ((entpos.x > this->x) && (entpos.x < this->x + win_size.x) &&
(entpos.y > this->y) && (entpos.y < this->y + win_size.y)))
{
// actually call sprite->draw. Let the BuildingSprite draw itself at the position.
sf::Sprite sprite = this->screen->building_sprites[building->type_id - this->world->number_of_units_models()]->get_cursor_sprite();
sprite.setPosition(entpos.x - this->x, entpos.y - this->y - LAYER_HEIGHT);
this->win->draw(sprite);
// this->draw_unit(entity, entpos.x - this->x, entpos.y - this->y,
// this->mouse_selection.contains(mouse_pos,
// entpos, entity->width + 4) ||
// this->screen->is_entity_hovered(entity),
// rectangle);
}
}
// Draw entites on that line.
std::vector<Entity*> entities_at_that_level = entities[level];
int i = 0;
......@@ -313,10 +369,10 @@ void Camera::draw()
(entpos.y > this->y) && (entpos.y < this->y + win_size.y)))
{
this->draw_unit(entity, entpos.x - this->x, entpos.y - this->y,
this->mouse_selection.contains(mouse_pos,
entpos, entity->width + 4) ||
this->screen->is_entity_hovered(entity),
rectangle);
this->mouse_selection.contains(mouse_pos,
entpos, entity->width + 4) ||
this->screen->is_entity_hovered(entity),
rectangle);
}
}
level++;
......
......@@ -28,7 +28,7 @@ public:
* Returns whether or not the mouse selection contains that point.
*/
bool contains(const sf::Vector2i&,
const sf::Vector2u&, const uint width = 0) const;
const sf::Vector2u&, const uint width = 1) const;
private:
MouseSelection(const MouseSelection&);
MouseSelection& operator=(const MouseSelection&);
......
......@@ -37,6 +37,8 @@ int main()
boost::bind(&ClientWorld::path_callback, world, _1));
c->install_callback("BUILD",
boost::bind(&ClientWorld::build_callback, world, _1));
c->install_callback("SPAWN",
boost::bind(&ClientWorld::spawn_callback, world, _1));
// c->connect("88.190.23.192", 7879);
c->connect("127.0.0.1", 7879);
......
......@@ -17,14 +17,12 @@ std::vector<ActionPanelTable*> ClientMod::get_action_tables(Screen* screen)
{
ModActionInfos action_infos;
std::vector<ActionPanelTable*> tables;
log_warning("heu, coucou: " << this->units_doc->size());
for (unsigned int i=0; i < this->units_doc->size(); i++)
{
const YAML::Node& unit = (*this->units_doc)[i];
ActionPanelTable* table = new ActionPanelTable;
tables.push_back(table);
log_warning("Adding a new table, for a unit");
// A table always contains at least ONE page
this->fill_default_unit_actions(screen, table);
const YAML::Node& actions = unit["actions"];
for (unsigned int i=0; i < actions.size(); i++)
......@@ -34,9 +32,20 @@ std::vector<ActionPanelTable*> ClientMod::get_action_tables(Screen* screen)
this->add_action_to_table(table, action_infos, screen);
}
}
// YAML::Node buildings;
// parser.GetNextDocument(units);
for (unsigned int i=0; i < this->buildings_doc->size(); i++)
{
const YAML::Node& building = (*this->buildings_doc)[i];
ActionPanelTable* table = new ActionPanelTable;
tables.push_back(table);
this->fill_default_building_actions(screen, table);
const YAML::Node& actions = building["actions"];
for (unsigned int i=0; i < actions.size(); i++)
{
const YAML::Node& action = actions[i];
action >> action_infos;
this->add_action_to_table(table, action_infos, screen);
}
}
return tables;
}
......@@ -90,6 +99,11 @@ void ClientMod::fill_default_unit_actions(Screen* screen, ActionPanelTable* tabl
0, 4, null_left), 4);
}
void ClientMod::fill_default_building_actions(Screen* screen, ActionPanelTable* table)
{
this->add_empty_pages(table, 1);
}
void ClientMod::add_action_to_table(ActionPanelTable* table, const ModActionInfos& infos, Screen* screen)
{
t_left_click left_click = {0, 0, 0};
......@@ -111,6 +125,13 @@ void ClientMod::add_action_to_table(ActionPanelTable* table, const ModActionInfo
left_click.cursor_callback = boost::bind(&Screen::draw_build_cursor, screen, _1, _2, _3);
button = new ActionPanelButton(infos.image_filename, boost::bind(&Screen::set_left_click_callback, screen, _1), infos.position, left_click);
}
else if (infos.type == "spawn")
{
left_click.id = infos.value;
left_click.callback = 0;
left_click.cursor_callback = 0;
button = new ActionPanelButton(infos.image_filename, boost::bind(&ClientWorld::action_spawn, screen->get_world(), _1), infos.position, left_click);
}
else
{
log_error("Unknown type of action: " << infos.type);
......
......@@ -30,6 +30,7 @@ private:
ClientMod& operator=(const ClientMod&);
void fill_default_unit_actions(Screen*, ActionPanelTable*);
void fill_default_building_actions(Screen*, ActionPanelTable*);
/**
* Add empty pages until the table contains the given number of pages.
* It may not add any pages if there are already enough of them.
......
......@@ -27,6 +27,7 @@ void RemoteGameClient::install_callbacks()
this->install_callback("T", boost::bind(&RemoteGameClient::turn_callback, this, _1));
this->install_callback("MOVE", boost::bind(&ServerWorld::move_callback, world, _1));
this->install_callback("BUILD", boost::bind(&ServerWorld::build_callback, world, _1));
this->install_callback("SPAWN", boost::bind(&ServerWorld::spawn_callback, world, _1));
}
boost::asio::io_service& RemoteGameClient::get_io_service()
......
#include <world/building.hpp>
#include <world/world.hpp>
Building::Building()
{
......@@ -16,10 +17,6 @@ Building::Building(const Building& o):
{
}
void Building::tick(World*)
{
}
bool Building::is_obstructing_position(Entity* entity, const Position& position) const
{
return false;
......@@ -29,3 +26,15 @@ bool Building::contains(const Position&) const
{
return false;
}
bool Building::spawn(World* world, Work* w)
{
log_info("COCUOU je SPAWN");
SpawnWork* work = static_cast<SpawnWork*>(w);
Unit* unit = world->create_unit(work->type_id);
// find free spawning position
unit->pos.x = this->x * CELL_SIZE;
unit->pos.y = this->y * CELL_SIZE;
world->insert_unit(unit);
return true;
}
......@@ -12,6 +12,7 @@
# define __BUILDING_HPP__
#include <world/entity.hpp>
#include <world/work.hpp>
class Building: public Entity
{
......@@ -20,7 +21,6 @@ public:
~Building();
Building(const Building&);
bool contains(const Position&) const;
void tick(World*);
bool is_obstructing_position(Entity*, const Position&) const;
......@@ -33,6 +33,8 @@ public:
ar & name & type_id & x & y;
}
bool spawn(World*, Work*);
private:
Building& operator=(const Building&);
......
......@@ -163,6 +163,15 @@ bool ClientWorld::action_build(const unsigned int x, const unsigned y, const std
return true;
}
void ClientWorld::action_spawn(const t_left_click left_click)
{
assert(this->current_selection.is_empty() == false);
SpawnEvent event;
event.actor = this->current_selection.get_entities().front()->id;
event.type_id = left_click.id;
this->generate_command("SPAWN", event.to_string());
}
bool ClientWorld::action_move(const unsigned int x, const unsigned y, const std::size_t)
{
MoveEvent event;
......@@ -213,7 +222,15 @@ void ClientWorld::add_selection_change_callback(const t_selection_changed_callba
this->current_selection.on_modified_callbacks.push_back(callback);
}
void draw_build_cursor(const unsigned int, const unsigned int y, const std::size_t)
void ClientWorld::spawn_callback(Command* command)
{
DoSpawnEvent* e = new DoSpawnEvent(command);
log_info("Spawn_callback: " << e->actor << " " << e->type_id);
if (e->is_valid() == false)
{
log_warning("Invalid data for Spawn command");
return ;
}
Action* action = new Action(boost::bind(&World::do_spawn, this, _1), e);
this->insert_received_action(action, e);
}
......@@ -60,6 +60,10 @@ public:
* The server tells one unit to build the given building
*/
void build_callback(Command*);
/**
* The server tells one building to spawn the given unit
*/
void spawn_callback(Command*);
/**
* Insert an action, built from a command we received, into the turn handler,
* and confirm it or validate it, depending on if the game is started or not
......@@ -83,6 +87,7 @@ public:
*/
bool action_move(const unsigned int x, const unsigned y, const std::size_t=0);
bool action_build(const unsigned int, const unsigned int, const std::size_t);
void action_spawn(const t_left_click left_click);
/**
* Give the order to all selected and movable units to move to the given
* world coordinates with an attack order (will attack all encountered
......
......@@ -38,9 +38,32 @@ void Entity::queue_work(Work* work)
void Entity::clear_works()
{
if (this->works.empty())
return ;
Work* current = this->works.front();
this->works.pop(); // pop the current without deleting it, in case we want
// to add it back.
while (!this->works.empty())
{
delete this->works.front();
this->works.pop();
}
// if the current work is not interruptible, we put it back in the queue,
// as if we didn’t removed it.
if (!current->is_interruptible())
this->works.push(current);
else
delete current;
}
void Entity::tick(World* world)
{
if (this->works.empty())
return ;
Work* current_work = this->works.front();
if ((*current_work)(world, current_work) == true)
{
delete current_work;
this->works.pop();
}
}
......@@ -36,7 +36,7 @@ public:
/**
* Regularly update the entity.
*/
virtual void tick(World*) = 0;
void tick(World*);
void clear_works();
void set_work(Work*);
......
......@@ -279,6 +279,8 @@ bool Map::can_be_built_on(const int cellx, const int celly) const
cell_path_t Map::do_astar(const uint startx, const uint starty,
const uint endx, const uint endy)
{
log_debug(startx);
log_debug(starty);
assert(startx < this->get_width_in_tiles());
assert(starty < this->get_height_in_tiles());
assert(endx < this->get_width_in_tiles());
......
......@@ -91,6 +91,21 @@ void ServerWorld::build_callback(Command* command)
this->turn_handler->insert_action(action, doevent->turn);
}
void ServerWorld::spawn_callback(Command* command)
{
SpawnEvent event(command);
if (event.is_valid() == false)
{
log_warning("Invalid data for SPAWN command");
return ;
}
DoSpawnEvent* doevent = new DoSpawnEvent(event);
doevent->turn = this->turn_handler->get_current_turn() + 2;
this->generate_command("SPAWN", doevent->to_string());
Action* action = new Action(0, doevent, this->occupants.size());
this->turn_handler->insert_action(action, doevent->turn);
}
bool ServerWorld::validate_action(const unsigned int id, const unsigned long int by)
{
log_debug("Action " << id << " validated by " << by);
......
......@@ -33,6 +33,12 @@ public:
* Check if the position is valid and the building can be built (money, the unit actually has this ability, etc).
*/
void build_callback(Command*);
/**
* Called whenever we receive a SPAWN command from one client. Should
* check if that unit can actually do that (money, capacity to do it,
* etc), before returning a DoSpawnEvent.
*/
void spawn_callback(Command*);
bool validate_action(const unsigned int id, const unsigned long int by);
bool validate_turn(const unsigned int id, const unsigned long int by);
/**
......
......@@ -32,18 +32,6 @@ bool Unit::contains(const Position& pos) const
return false;
}
void Unit::tick(World* world)
{
if (this->works.empty())
return ;
Work* current_work = this->works.front();
if ((*current_work)(world, current_work) == true)
{
delete current_work;
this->works.pop();
}
}
bool Unit::build(World* world, Work* w)
{
BuildWork* work = static_cast<BuildWork*>(w);
......@@ -63,7 +51,7 @@ bool Unit::follow_path(World* world, Work* w)
{
if (work->calculated == false)
{
log_warning("Calculating path");
log_warning("Calculating path: " << this->pos);
work->path = world->calculate_path(work->end_position, this);
work->calculated = true;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment