PixelWars/src/simulation.cpp
2016-06-03 10:03:51 +02:00

214 lines
6.2 KiB
C++

#include "simulation.h"
#include <algorithm>
#include <iostream>
#include <cstring>
#include "map.h"
#include "dude.h"
#include "mapscene.h"
#include "pixeltype.h"
#define MAX_RESOURCES_IN_STACK 5
Simulation::Simulation(MapScene *_map, std::vector<BehaviorFunction> &_behaviors):
p_map(_map)
{
int i=0;
for(BehaviorFunction &behavior : _behaviors){
glm::vec3 color;
color[i%3]=0.5f*(1 + i/3);
m_teams.push_back(Team(color, color*0.8f, behavior));
p_map->setColors(i, color, color*0.8f);
i++;
}
}
Simulation::~Simulation()
{
for(Dude* d : m_dudes)
delete d;
}
void Simulation::update()
{
std::random_shuffle(m_dudes.begin(), m_dudes.end());
for (int i=0; i<m_dudes.size(); ++i){
Dude *dude = m_dudes[i];
m_teams[dude->getTeam()].update(dude); //get action for this dude from behavior function in team
handleAction(dude);
}
// for each team, spawn dude if condition met
for(int i=0; i<m_teams.size(); ++i){
Team &t = m_teams[i];
if(t.updateSpawn())
{
Coord spawnPos = p_map->team(i) + Coord(Dir(rand()%4));
if(PixelProperty::isWalkable(p_map->getPixel(spawnPos).type))
{
t.popDude();
Dude *dude = new Dude(spawnPos,p_map,i);
(*p_map)[spawnPos].data.dudePtr = dude;
p_map->updatePixel(spawnPos);
m_dudes.push_back(dude);
}
}
}
}
void Simulation::handleAction(Dude *dude)
{
const Action &action = dude->getAction();
// initialisation
Coord currentPos(dude->getPos());
Coord targetPos = p_map->toreillerLoop(currentPos + Coord(action.dir));
Pixel &target = p_map->getPixel(targetPos);
dude->setSuccess(false);
switch(action.type){
case Action::MOVE: // DONE
if(PixelProperty::isWalkable(target.type)){
dude->move(action.dir);
p_map->updatePixel(currentPos);
p_map->updatePixel(targetPos);
dude->setSuccess(true);
}
break;
case Action::ATTACK:
if(PixelProperty::isDestructible(target.type))
{
dude->setSuccess(true);
if (target.type == DUDE) // TODO: add fight between dude and targetDude
NULL;
else // DONE
{
if(target.type == SPAWN)
m_teams[target.data.nbRes].destroySpawn();
target.type = GRASS;
p_map->updatePixel(targetPos);
}
}
break;
case Action::PICK: // DONE
if(PixelProperty::isResource(target.type) && dude->getInventory() == EMPTY){
dude->setInventory(target.type);
--target.data.nbRes;
if(target.data.nbRes < 1)
{
target.type = GRASS;
p_map->updatePixel(targetPos);
}
dude->setSuccess(true);
}
break;
case Action::PUT: // DONE
if(dude->getInventory() != EMPTY
&& (target.type == GRASS || target.type == MARK || target.type == dude->getInventory())
&& target.data.nbRes < MAX_RESOURCES_IN_STACK)
{
if(target.type == GRASS || target.type == MARK)
{
target.type = dude->getInventory();
target.data.nbRes = 1;
p_map->updatePixel(targetPos);
}
else
++target.data.nbRes;
dude->setInventory(EMPTY);
dude->setSuccess(true);
}
else if(target.type == SPAWN && dude->getInventory() == FOOD)
{
dude->setInventory(EMPTY);
m_teams[target.data.nbRes].addFood();
dude->setSuccess(true);
}
p_map->updatePixel(targetPos);
break;
case Action::WORK: // DONE
dude->setSuccess(true);
switch(target.type){
case ROCK:
target.type = STONE;
target.data.nbRes = 1;
break;
case BERRIES:
target.type = FOOD;
target.data.nbRes = 1;
break;
case TREE:
target.type = WOOD;
target.data.nbRes = 1;
break;
case IRON_ORE:
target.type = IRON;
target.data.nbRes = 1;
break;
case GRASS:
target.type = MARK;
break;
case MARK:
target.type = GRASS;
break;
case WOOD:
switch(target.data.nbRes){
case 1:
target.type = WALL;
break;
case 2:
target.type = LIBRARY;
target.data.knowledge = new char[LIBRARY_SIZE];
break;
default:
dude->setSuccess(false);
break;
}
case STONE:
if(target.data.nbRes == 1)
target.type = ROAD;
else
dude->setSuccess(false);
break;
case IRON:
if(target.data.nbRes == 1)
target.type = SWORD;
else
dude->setSuccess(false);
break;
default:
dude->setSuccess(false);
break;
}
if(dude->getSuccess())
p_map->updatePixel(targetPos);
break;
case Action::WAIT: // DONE
dude->setSuccess(true);
break;
case Action::COMMUNICATE:
switch(target.type){
case DUDE:
{
Dude *targetDude = target.data.dudePtr;
// TODO check conflicts between writers
targetDude->receiveComData(Dir((action.dir+2)%4), targetDude->getAction().com_data.data);
dude->setSuccess(true);
break;
}
case LIBRARY:
{
int offset = (action.com_data.flag & 3)*COM_SIZE;
if(action.com_data.flag & Com::READ)
dude->receiveComData(action.dir, target.data.knowledge + offset);
else
{
memcpy(target.data.knowledge + offset, action.com_data.data, COM_SIZE);
dude->setSuccess(true);
}
break;
}
default:
break;
}
}
}