214 lines
6.2 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|