fixed plenty of bugs, added agressive behavior
This commit is contained in:
parent
cad7cc19a2
commit
b6379dcc1f
393
behaviors/war_charge_east.cpp
Normal file
393
behaviors/war_charge_east.cpp
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include "behavior.h"
|
||||||
|
|
||||||
|
// g++ -shared war_charge_east.cpp -o war_charge_east.dll -std=c++11 -I../src
|
||||||
|
|
||||||
|
#define KING_POS Coord(2, 2)
|
||||||
|
#define ARMY_POS Coord(12, 4)
|
||||||
|
#define CHARGE_DIR EAST
|
||||||
|
|
||||||
|
enum Purpose { NEWBORN, KING, PEASANT, SOLDIER };
|
||||||
|
|
||||||
|
struct KingMemory{ // 16 bytes
|
||||||
|
int nbPeasants;
|
||||||
|
int nbSoldiers;
|
||||||
|
int date;
|
||||||
|
Dir last_audience_dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PeasantMemory{ // 8 bytes
|
||||||
|
bool tried_picking_up_food;
|
||||||
|
bool brings_food;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoldierMemory{ // 16 bytes
|
||||||
|
Coord target;
|
||||||
|
int charge_countdown;
|
||||||
|
bool commander;
|
||||||
|
};
|
||||||
|
|
||||||
|
union JobMemory { // 16 bytes
|
||||||
|
KingMemory king;
|
||||||
|
PeasantMemory peasant;
|
||||||
|
SoldierMemory soldier;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct memory_data{ // 104 bytes
|
||||||
|
// 40 bytes
|
||||||
|
JobMemory job;
|
||||||
|
Coord pos;
|
||||||
|
bool new_born;
|
||||||
|
int purpose;
|
||||||
|
Dir last_dir;
|
||||||
|
Action::Type last_action;
|
||||||
|
// 64 bytes
|
||||||
|
char debugStr[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* PURPOSES_STRINGS[] {
|
||||||
|
"Newborn",
|
||||||
|
"King",
|
||||||
|
"Peasant",
|
||||||
|
"Soldier"
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" void debugOutput(char *outputString, const char *memory)
|
||||||
|
{
|
||||||
|
memory_data* data = (memory_data*)memory;
|
||||||
|
sprintf(outputString, "%s\n%s", PURPOSES_STRINGS[data->purpose], data->debugStr);
|
||||||
|
if(data->purpose == KING)
|
||||||
|
{
|
||||||
|
sprintf(outputString, "%s\nRuled the kingdom for %d ticks\npopulation :\n%d peasants\n%d soldiers",
|
||||||
|
outputString, data->job.king.date, data->job.king.nbPeasants, data->job.king.nbSoldiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void think(Action *action, char *memory, const Info *info)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PixelType type;
|
||||||
|
|
||||||
|
bool success = info->getSuccess();
|
||||||
|
memory_data* data = (memory_data*)memory;
|
||||||
|
data->debugStr[0] = '\0';
|
||||||
|
|
||||||
|
// if freshly spawned, init the position variable by looking in which direction is the spawn
|
||||||
|
if(!data->new_born){
|
||||||
|
success = false;
|
||||||
|
data->new_born = true;
|
||||||
|
for(i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
type = info->getNear(Dir(i));
|
||||||
|
if(type == SPAWN)
|
||||||
|
{
|
||||||
|
data->pos = Coord(0) - Dir(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update position if last successful action was moving
|
||||||
|
if(data->last_action == Action::MOVE){
|
||||||
|
if(success)
|
||||||
|
data->pos += data->last_dir;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int blockedCount = 0;
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
do{
|
||||||
|
action->dir = Dir((data->last_dir + rand()%3)%4);
|
||||||
|
type = info->getNear(action->dir);
|
||||||
|
++blockedCount;
|
||||||
|
if(blockedCount > 3)
|
||||||
|
{
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}while(!PixelProperty::isWalkable(type));
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "moving around obstacle");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// work any workable resource when encountered
|
||||||
|
if(data->purpose == SOLDIER && data->job.soldier.charge_countdown == 0)
|
||||||
|
{
|
||||||
|
action->dir = CHARGE_DIR;
|
||||||
|
PixelType front = info->getNear(CHARGE_DIR);
|
||||||
|
if(!PixelProperty::isWalkable(front))
|
||||||
|
{
|
||||||
|
if(PixelProperty::isDestructible(front))
|
||||||
|
action->type = Action::ATTACK;
|
||||||
|
else if(PixelProperty::isResource(front))
|
||||||
|
{
|
||||||
|
if(info->getInventory() != EMPTY)
|
||||||
|
{
|
||||||
|
action->type = Action::PUT;
|
||||||
|
action->dir = Dir((CHARGE_DIR+2)%4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action->type = Action::PICK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action->type = Action::WORK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "CHAAAAAAAAAARGE !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(i=0; i<4; i++){
|
||||||
|
type = info->getNear(Dir(i));
|
||||||
|
if(type == BERRIES || type == TREE || type == IRON_ORE || type == ROCK){
|
||||||
|
action->type = Action::WORK;
|
||||||
|
action->dir = Dir(i);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "working on resource");
|
||||||
|
return;
|
||||||
|
}else if(type == FOOD && data->purpose == PEASANT
|
||||||
|
&& !(data->job.peasant.brings_food) && !(data->job.peasant.tried_picking_up_food)){
|
||||||
|
action->type = Action::PICK;
|
||||||
|
action->dir = Dir(i);
|
||||||
|
data->job.peasant.tried_picking_up_food = true;
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "picking up food");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do your job
|
||||||
|
switch(data->purpose)
|
||||||
|
{
|
||||||
|
case NEWBORN :
|
||||||
|
{
|
||||||
|
const Com* com = info->getCom();
|
||||||
|
if(com != nullptr) // no activity
|
||||||
|
{
|
||||||
|
switch(com->data[0])
|
||||||
|
{
|
||||||
|
case 'p': data->purpose = PEASANT; break;
|
||||||
|
case 's':
|
||||||
|
data->purpose = SOLDIER;
|
||||||
|
data->job.soldier.target.x = *((int*)(com->data+2));
|
||||||
|
data->job.soldier.target.y = *((int*)(com->data+6));
|
||||||
|
data->job.soldier.commander = bool(com->data[10]);
|
||||||
|
data->job.soldier.charge_countdown = *((int*)(com->data+11));
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "receiving job : %s", com->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Coord target = data->pos - KING_POS;
|
||||||
|
int distance = target.dist();
|
||||||
|
if(distance == 0) // i am the new king
|
||||||
|
{
|
||||||
|
data->job.king.last_audience_dir = NO_DIR;
|
||||||
|
data->purpose = KING;
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "I AM THE KING, LONG LIVE THE KING");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if adjacent to the king's position, speak to the king if there is one
|
||||||
|
if(distance == 1){
|
||||||
|
for(i=0; i<4; i++){
|
||||||
|
type = info->getNear(Dir(i));
|
||||||
|
if(Coord(Dir((i+2)%4)) == target && type == DUDE){ // it is the king
|
||||||
|
action->dir = Dir(i);
|
||||||
|
action->type = Action::COMMUNICATE;
|
||||||
|
action->com_data.data[0] = 'n'; // "give me a purpose"
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "asking the king to give me a task");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// move to the king's position
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
do{
|
||||||
|
action->dir = Dir( rand() % 4 );
|
||||||
|
}while(~(target + action->dir) > distance && distance != 0);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "walking to the king's throne");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KING :
|
||||||
|
{
|
||||||
|
data->job.king.date += 1;
|
||||||
|
const Com* com = info->getCom();
|
||||||
|
if(com == nullptr || data->job.king.last_audience_dir == Dir(com->flag)) // no activity
|
||||||
|
{
|
||||||
|
data->job.king.last_audience_dir = NO_DIR;
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "waiting for a subject to ask for an audience");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// someone requests an audience to the king
|
||||||
|
char request = com->data[0];
|
||||||
|
if(request == 'n')
|
||||||
|
{
|
||||||
|
int population = data->job.king.nbPeasants + data->job.king.nbSoldiers;
|
||||||
|
if(population < 15 || data->job.king.nbPeasants < (2*population)/3)
|
||||||
|
{
|
||||||
|
action->com_data.data[0] = 'p'; // "thou shall be peasant"
|
||||||
|
data->job.king.nbPeasants += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action->com_data.data[0] = 's'; // "thou shall serve me as a soldier"
|
||||||
|
Coord target = ARMY_POS;
|
||||||
|
target.y -= data->job.king.nbSoldiers % 10;
|
||||||
|
target.x -= data->job.king.nbSoldiers / 10;
|
||||||
|
Coord* ptr = (Coord*)(action->com_data.data + 2);
|
||||||
|
*ptr = target;
|
||||||
|
*((int*)(action->com_data.data+11)) = -1;
|
||||||
|
data->job.king.nbSoldiers += 1;
|
||||||
|
|
||||||
|
if(data->job.king.nbSoldiers % 10 == 9)
|
||||||
|
{
|
||||||
|
action->com_data.data[10] = 1; // "thou shall command the army to march on the corpses of our foes"
|
||||||
|
*((int*)(action->com_data.data+11)) = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action->com_data.data[0] = 'f'; // "you dare disturb me from my royal occupations ? Go "f" yourself !"
|
||||||
|
|
||||||
|
data->job.king.last_audience_dir = Dir(com->flag);
|
||||||
|
action->dir = Dir(com->flag);
|
||||||
|
action->type = Action::COMMUNICATE;
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "receiving request : %s\ngiving job : %s", com->data, action->com_data.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case PEASANT :
|
||||||
|
{
|
||||||
|
if(data->job.peasant.tried_picking_up_food && success)
|
||||||
|
data->job.peasant.brings_food = true;
|
||||||
|
data->job.peasant.tried_picking_up_food = false;
|
||||||
|
|
||||||
|
if(data->job.peasant.brings_food){
|
||||||
|
int distance = data->pos.dist();
|
||||||
|
if(distance == 1){
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
action->dir = NORTH;
|
||||||
|
|
||||||
|
for(i=0; i<4; i++){
|
||||||
|
type = info->getNear(Dir(i));
|
||||||
|
if(type == SPAWN){
|
||||||
|
action->dir = Dir(i);
|
||||||
|
action->type = Action::PUT;
|
||||||
|
data->job.peasant.brings_food = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
do{
|
||||||
|
action->dir = Dir( rand() % 4 );
|
||||||
|
}while(~(data->pos + action->dir) > distance && distance != 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "bringing food back to the spawn");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SOLDIER :
|
||||||
|
{
|
||||||
|
Coord target = data->pos - data->job.soldier.target;
|
||||||
|
int distance = target.dist();
|
||||||
|
const Com* com = info->getCom();
|
||||||
|
if(com != nullptr)
|
||||||
|
{
|
||||||
|
int charge_countdown = *((int*)(com->data));
|
||||||
|
data->job.soldier.charge_countdown = charge_countdown;
|
||||||
|
*((int*)(action->com_data.data))= charge_countdown - 1;
|
||||||
|
action->type = Action::COMMUNICATE;
|
||||||
|
action->dir = Dir((com->flag+2)%4);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
sprintf(data->debugStr, "receiving orders");
|
||||||
|
}
|
||||||
|
else if(distance == 0)
|
||||||
|
{
|
||||||
|
if(data->job.soldier.charge_countdown > 0)
|
||||||
|
{
|
||||||
|
if(data->job.soldier.commander)
|
||||||
|
{
|
||||||
|
data->job.soldier.commander = false;
|
||||||
|
*((int*)(action->com_data.data))= data->job.soldier.charge_countdown;
|
||||||
|
action->type = Action::COMMUNICATE;
|
||||||
|
action->dir = Dir(SOUTH);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
sprintf(data->debugStr, "Notifying the troops that we are going into battle");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
data->job.soldier.charge_countdown -= 1;
|
||||||
|
sprintf(data->debugStr, "Charge in %d...", data->job.soldier.charge_countdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
sprintf(data->debugStr, "waiting orders");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
do{
|
||||||
|
action->dir = Dir( rand() % 4 );
|
||||||
|
}while(~(target + action->dir) > distance && distance != 0);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
sprintf(data->debugStr, "going into formation");
|
||||||
|
}
|
||||||
|
data->last_action = action->type;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wander around
|
||||||
|
int blockedCount = 0;
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
bool ok = false;
|
||||||
|
do{
|
||||||
|
action->dir = Dir((data->last_dir + rand()%3)%4);
|
||||||
|
type = info->getNear(action->dir);
|
||||||
|
ok = PixelProperty::isWalkable(type) && !((data->pos + Coord(action->dir)).x > 12); // do not interfere with military formations
|
||||||
|
++blockedCount;
|
||||||
|
if(blockedCount > 3)
|
||||||
|
{
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
}while(!ok);
|
||||||
|
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "wandering around");
|
||||||
|
}
|
393
behaviors/war_charge_west.cpp
Normal file
393
behaviors/war_charge_west.cpp
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include "behavior.h"
|
||||||
|
|
||||||
|
// g++ -shared war_charge_west.cpp -o war_charge_west.dll -std=c++11 -I../src
|
||||||
|
|
||||||
|
#define KING_POS Coord(2, 2)
|
||||||
|
#define ARMY_POS Coord(-12, 4)
|
||||||
|
#define CHARGE_DIR WEST
|
||||||
|
|
||||||
|
enum Purpose { NEWBORN, KING, PEASANT, SOLDIER };
|
||||||
|
|
||||||
|
struct KingMemory{ // 16 bytes
|
||||||
|
int nbPeasants;
|
||||||
|
int nbSoldiers;
|
||||||
|
int date;
|
||||||
|
Dir last_audience_dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PeasantMemory{ // 8 bytes
|
||||||
|
bool tried_picking_up_food;
|
||||||
|
bool brings_food;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoldierMemory{ // 16 bytes
|
||||||
|
Coord target;
|
||||||
|
int charge_countdown;
|
||||||
|
bool commander;
|
||||||
|
};
|
||||||
|
|
||||||
|
union JobMemory { // 16 bytes
|
||||||
|
KingMemory king;
|
||||||
|
PeasantMemory peasant;
|
||||||
|
SoldierMemory soldier;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct memory_data{ // 104 bytes
|
||||||
|
// 40 bytes
|
||||||
|
JobMemory job;
|
||||||
|
Coord pos;
|
||||||
|
bool new_born;
|
||||||
|
int purpose;
|
||||||
|
Dir last_dir;
|
||||||
|
Action::Type last_action;
|
||||||
|
// 64 bytes
|
||||||
|
char debugStr[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* PURPOSES_STRINGS[] {
|
||||||
|
"Newborn",
|
||||||
|
"King",
|
||||||
|
"Peasant",
|
||||||
|
"Soldier"
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" void debugOutput(char *outputString, const char *memory)
|
||||||
|
{
|
||||||
|
memory_data* data = (memory_data*)memory;
|
||||||
|
sprintf(outputString, "%s\n%s", PURPOSES_STRINGS[data->purpose], data->debugStr);
|
||||||
|
if(data->purpose == KING)
|
||||||
|
{
|
||||||
|
sprintf(outputString, "%s\nRuled the kingdom for %d ticks\npopulation :\n%d peasants\n%d soldiers",
|
||||||
|
outputString, data->job.king.date, data->job.king.nbPeasants, data->job.king.nbSoldiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void think(Action *action, char *memory, const Info *info)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PixelType type;
|
||||||
|
|
||||||
|
bool success = info->getSuccess();
|
||||||
|
memory_data* data = (memory_data*)memory;
|
||||||
|
data->debugStr[0] = '\0';
|
||||||
|
|
||||||
|
// if freshly spawned, init the position variable by looking in which direction is the spawn
|
||||||
|
if(!data->new_born){
|
||||||
|
success = false;
|
||||||
|
data->new_born = true;
|
||||||
|
for(i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
type = info->getNear(Dir(i));
|
||||||
|
if(type == SPAWN)
|
||||||
|
{
|
||||||
|
data->pos = Coord(0) - Dir(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update position if last successful action was moving
|
||||||
|
if(data->last_action == Action::MOVE){
|
||||||
|
if(success)
|
||||||
|
data->pos += data->last_dir;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int blockedCount = 0;
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
do{
|
||||||
|
action->dir = Dir((data->last_dir + rand()%3)%4);
|
||||||
|
type = info->getNear(action->dir);
|
||||||
|
++blockedCount;
|
||||||
|
if(blockedCount > 3)
|
||||||
|
{
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}while(!PixelProperty::isWalkable(type));
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "moving around obstacle");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// work any workable resource when encountered
|
||||||
|
if(data->purpose == SOLDIER && data->job.soldier.charge_countdown == 0)
|
||||||
|
{
|
||||||
|
action->dir = CHARGE_DIR;
|
||||||
|
PixelType front = info->getNear(CHARGE_DIR);
|
||||||
|
if(!PixelProperty::isWalkable(front))
|
||||||
|
{
|
||||||
|
if(PixelProperty::isDestructible(front))
|
||||||
|
action->type = Action::ATTACK;
|
||||||
|
else if(PixelProperty::isResource(front))
|
||||||
|
{
|
||||||
|
if(info->getInventory() != EMPTY)
|
||||||
|
{
|
||||||
|
action->type = Action::PUT;
|
||||||
|
action->dir = Dir((CHARGE_DIR+2)%4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action->type = Action::PICK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action->type = Action::WORK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "CHAAAAAAAAAARGE !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(i=0; i<4; i++){
|
||||||
|
type = info->getNear(Dir(i));
|
||||||
|
if(type == BERRIES || type == TREE || type == IRON_ORE || type == ROCK){
|
||||||
|
action->type = Action::WORK;
|
||||||
|
action->dir = Dir(i);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "working on resource");
|
||||||
|
return;
|
||||||
|
}else if(type == FOOD && data->purpose == PEASANT
|
||||||
|
&& !(data->job.peasant.brings_food) && !(data->job.peasant.tried_picking_up_food)){
|
||||||
|
action->type = Action::PICK;
|
||||||
|
action->dir = Dir(i);
|
||||||
|
data->job.peasant.tried_picking_up_food = true;
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "picking up food");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do your job
|
||||||
|
switch(data->purpose)
|
||||||
|
{
|
||||||
|
case NEWBORN :
|
||||||
|
{
|
||||||
|
const Com* com = info->getCom();
|
||||||
|
if(com != nullptr) // no activity
|
||||||
|
{
|
||||||
|
switch(com->data[0])
|
||||||
|
{
|
||||||
|
case 'p': data->purpose = PEASANT; break;
|
||||||
|
case 's':
|
||||||
|
data->purpose = SOLDIER;
|
||||||
|
data->job.soldier.target.x = *((int*)(com->data+2));
|
||||||
|
data->job.soldier.target.y = *((int*)(com->data+6));
|
||||||
|
data->job.soldier.commander = bool(com->data[10]);
|
||||||
|
data->job.soldier.charge_countdown = *((int*)(com->data+11));
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "receiving job : %s", com->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Coord target = data->pos - KING_POS;
|
||||||
|
int distance = target.dist();
|
||||||
|
if(distance == 0) // i am the new king
|
||||||
|
{
|
||||||
|
data->job.king.last_audience_dir = NO_DIR;
|
||||||
|
data->purpose = KING;
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "I AM THE KING, LONG LIVE THE KING");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if adjacent to the king's position, speak to the king if there is one
|
||||||
|
if(distance == 1){
|
||||||
|
for(i=0; i<4; i++){
|
||||||
|
type = info->getNear(Dir(i));
|
||||||
|
if(Coord(Dir((i+2)%4)) == target && type == DUDE){ // it is the king
|
||||||
|
action->dir = Dir(i);
|
||||||
|
action->type = Action::COMMUNICATE;
|
||||||
|
action->com_data.data[0] = 'n'; // "give me a purpose"
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "asking the king to give me a task");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// move to the king's position
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
do{
|
||||||
|
action->dir = Dir( rand() % 4 );
|
||||||
|
}while(~(target + action->dir) > distance && distance != 0);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "walking to the king's throne");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KING :
|
||||||
|
{
|
||||||
|
data->job.king.date += 1;
|
||||||
|
const Com* com = info->getCom();
|
||||||
|
if(com == nullptr || data->job.king.last_audience_dir == Dir(com->flag)) // no activity
|
||||||
|
{
|
||||||
|
data->job.king.last_audience_dir = NO_DIR;
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "waiting for a subject to ask for an audience");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// someone requests an audience to the king
|
||||||
|
char request = com->data[0];
|
||||||
|
if(request == 'n')
|
||||||
|
{
|
||||||
|
int population = data->job.king.nbPeasants + data->job.king.nbSoldiers;
|
||||||
|
if(population < 15 || data->job.king.nbPeasants < (2*population)/3)
|
||||||
|
{
|
||||||
|
action->com_data.data[0] = 'p'; // "thou shall be peasant"
|
||||||
|
data->job.king.nbPeasants += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action->com_data.data[0] = 's'; // "thou shall serve me as a soldier"
|
||||||
|
Coord target = ARMY_POS;
|
||||||
|
target.y -= data->job.king.nbSoldiers % 10;
|
||||||
|
target.x -= data->job.king.nbSoldiers / 10;
|
||||||
|
Coord* ptr = (Coord*)(action->com_data.data + 2);
|
||||||
|
*ptr = target;
|
||||||
|
*((int*)(action->com_data.data+11)) = -1;
|
||||||
|
data->job.king.nbSoldiers += 1;
|
||||||
|
|
||||||
|
if(data->job.king.nbSoldiers % 10 == 9)
|
||||||
|
{
|
||||||
|
action->com_data.data[10] = 1; // "thou shall command the army to march on the corpses of our foes"
|
||||||
|
*((int*)(action->com_data.data+11)) = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action->com_data.data[0] = 'f'; // "you dare disturb me from my royal occupations ? Go "f" yourself !"
|
||||||
|
|
||||||
|
data->job.king.last_audience_dir = Dir(com->flag);
|
||||||
|
action->dir = Dir(com->flag);
|
||||||
|
action->type = Action::COMMUNICATE;
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "receiving request : %s\ngiving job : %s", com->data, action->com_data.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case PEASANT :
|
||||||
|
{
|
||||||
|
if(data->job.peasant.tried_picking_up_food && success)
|
||||||
|
data->job.peasant.brings_food = true;
|
||||||
|
data->job.peasant.tried_picking_up_food = false;
|
||||||
|
|
||||||
|
if(data->job.peasant.brings_food){
|
||||||
|
int distance = data->pos.dist();
|
||||||
|
if(distance == 1){
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
action->dir = NORTH;
|
||||||
|
|
||||||
|
for(i=0; i<4; i++){
|
||||||
|
type = info->getNear(Dir(i));
|
||||||
|
if(type == SPAWN){
|
||||||
|
action->dir = Dir(i);
|
||||||
|
action->type = Action::PUT;
|
||||||
|
data->job.peasant.brings_food = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
do{
|
||||||
|
action->dir = Dir( rand() % 4 );
|
||||||
|
}while(~(data->pos + action->dir) > distance && distance != 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "bringing food back to the spawn");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SOLDIER :
|
||||||
|
{
|
||||||
|
Coord target = data->pos - data->job.soldier.target;
|
||||||
|
int distance = target.dist();
|
||||||
|
const Com* com = info->getCom();
|
||||||
|
if(com != nullptr)
|
||||||
|
{
|
||||||
|
int charge_countdown = *((int*)(com->data));
|
||||||
|
data->job.soldier.charge_countdown = charge_countdown;
|
||||||
|
*((int*)(action->com_data.data))= charge_countdown - 1;
|
||||||
|
action->type = Action::COMMUNICATE;
|
||||||
|
action->dir = Dir((com->flag+2)%4);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
sprintf(data->debugStr, "receiving orders");
|
||||||
|
}
|
||||||
|
else if(distance == 0)
|
||||||
|
{
|
||||||
|
if(data->job.soldier.charge_countdown > 0)
|
||||||
|
{
|
||||||
|
if(data->job.soldier.commander)
|
||||||
|
{
|
||||||
|
data->job.soldier.commander = false;
|
||||||
|
*((int*)(action->com_data.data))= data->job.soldier.charge_countdown;
|
||||||
|
action->type = Action::COMMUNICATE;
|
||||||
|
action->dir = Dir(SOUTH);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
sprintf(data->debugStr, "Notifying the troops that we are going into battle");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
data->job.soldier.charge_countdown -= 1;
|
||||||
|
sprintf(data->debugStr, "Charge in %d...", data->job.soldier.charge_countdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
sprintf(data->debugStr, "waiting orders");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
do{
|
||||||
|
action->dir = Dir( rand() % 4 );
|
||||||
|
}while(~(target + action->dir) > distance && distance != 0);
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
sprintf(data->debugStr, "going into formation");
|
||||||
|
}
|
||||||
|
data->last_action = action->type;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wander around
|
||||||
|
int blockedCount = 0;
|
||||||
|
action->type = Action::MOVE;
|
||||||
|
bool ok = false;
|
||||||
|
do{
|
||||||
|
action->dir = Dir((data->last_dir + rand()%3)%4);
|
||||||
|
type = info->getNear(action->dir);
|
||||||
|
ok = PixelProperty::isWalkable(type) && !((data->pos + Coord(action->dir)).x < -12); // do not interfere with military formations
|
||||||
|
++blockedCount;
|
||||||
|
if(blockedCount > 3)
|
||||||
|
{
|
||||||
|
action->type = Action::WAIT;
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
}while(!ok);
|
||||||
|
|
||||||
|
data->last_dir = action->dir;
|
||||||
|
data->last_action = action->type;
|
||||||
|
sprintf(data->debugStr, "wandering around");
|
||||||
|
}
|
14
src/dude.cpp
14
src/dude.cpp
@ -23,6 +23,13 @@ Dude::Dude(const Coord &_pos, Map *_map, const int &_team) :
|
|||||||
p_map->getPixel(m_pos).data.dudePtr = this;
|
p_map->getPixel(m_pos).data.dudePtr = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Dude::perish()
|
||||||
|
{
|
||||||
|
m_dead = true;
|
||||||
|
Pixel& p = p_map->getPixel(m_pos);
|
||||||
|
p.type = DEAD_DUDE;
|
||||||
|
}
|
||||||
|
|
||||||
void Dude::move(Dir d)
|
void Dude::move(Dir d)
|
||||||
{
|
{
|
||||||
p_map->getPixel(m_pos).type = m_under;
|
p_map->getPixel(m_pos).type = m_under;
|
||||||
@ -30,14 +37,13 @@ void Dude::move(Dir d)
|
|||||||
// p_map->getPixel(m_pos).data.nbRes = m_underResCount;
|
// p_map->getPixel(m_pos).data.nbRes = m_underResCount;
|
||||||
p_map->getPixel(m_pos).data.dudePtr = NULL;
|
p_map->getPixel(m_pos).data.dudePtr = NULL;
|
||||||
|
|
||||||
m_pos += Coord(d);
|
m_pos = p_map->toreillerLoop(m_pos + Coord(d));
|
||||||
|
|
||||||
m_under = p_map->getPixel(m_pos).type;
|
m_under = p_map->getPixel(m_pos).type;
|
||||||
//if(PixelProperty::isResource(m_under))
|
//if(PixelProperty::isResource(m_under))
|
||||||
// m_underResCount = p_map->getPixel(m_pos).data.nbRes;
|
// m_underResCount = p_map->getPixel(m_pos).data.nbRes;
|
||||||
p_map->getPixel(m_pos).type = DUDE;
|
p_map->getPixel(m_pos).type = DUDE;
|
||||||
p_map->getPixel(m_pos).data.dudePtr = this;
|
p_map->getPixel(m_pos).data.dudePtr = this;
|
||||||
p_map->toreillerLoop(m_pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dude::receiveComData(Dir dir, const char *data)
|
void Dude::receiveComData(Dir dir, const char *data)
|
||||||
@ -61,10 +67,10 @@ void Dude::debugOutput(char *outputString, DebugBehaviorFunction func)
|
|||||||
|
|
||||||
PixelType Dude::getNear(Dir d) const
|
PixelType Dude::getNear(Dir d) const
|
||||||
{
|
{
|
||||||
return p_map->getPixel(Coord(d) + m_pos).type;
|
return p_map->getPixel(p_map->toreillerLoop(Coord(d) + m_pos)).type;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Dude::getInfo(Dir d) const
|
int Dude::getInfo(Dir d) const
|
||||||
{
|
{
|
||||||
return p_map->getPixel(Coord(d) + m_pos).data.nbRes;
|
return p_map->getPixel(p_map->toreillerLoop(Coord(d) + m_pos)).data.nbRes;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ public:
|
|||||||
|
|
||||||
//life-related function
|
//life-related function
|
||||||
bool isAlive() { return !m_dead; }
|
bool isAlive() { return !m_dead; }
|
||||||
void perish() { m_dead = true; }
|
void perish();
|
||||||
|
|
||||||
//movement-related function
|
//movement-related function
|
||||||
const Coord& getPos() { return m_pos; }
|
const Coord& getPos() { return m_pos; }
|
||||||
|
@ -65,6 +65,7 @@ void Simulation::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolveBattles();
|
resolveBattles();
|
||||||
|
removeDead();
|
||||||
|
|
||||||
// for each team, spawn dude if condition met
|
// for each team, spawn dude if condition met
|
||||||
for(unsigned int i=0; i<m_teams.size(); ++i){
|
for(unsigned int i=0; i<m_teams.size(); ++i){
|
||||||
@ -203,6 +204,21 @@ void Simulation::handleAction(Dude *dude)
|
|||||||
else
|
else
|
||||||
dude->setSuccess(false);
|
dude->setSuccess(false);
|
||||||
break;
|
break;
|
||||||
|
case DEAD_DUDE:
|
||||||
|
{
|
||||||
|
PixelType inventory = target.data.dudePtr->getInventory();
|
||||||
|
m_dead_dudes.emplace(target.data.dudePtr);
|
||||||
|
target.data.dudePtr = nullptr;
|
||||||
|
if(inventory != EMPTY)
|
||||||
|
{
|
||||||
|
target.type = inventory;
|
||||||
|
target.data.nbRes = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
target.type = GRASS;
|
||||||
|
dude->setSuccess(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dude->setSuccess(false);
|
dude->setSuccess(false);
|
||||||
break;
|
break;
|
||||||
@ -247,32 +263,51 @@ void Simulation::handleAction(Dude *dude)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Simulation::removeDead()
|
||||||
|
{
|
||||||
|
for(unsigned int i=0; i<m_dudes.size(); ++i)
|
||||||
|
{
|
||||||
|
Dude* d = m_dudes[i];
|
||||||
|
if(m_dead_dudes.count(d))
|
||||||
|
{
|
||||||
|
m_dead_dudes.erase(d);
|
||||||
|
delete d;
|
||||||
|
m_dudes[i] = m_dudes[m_dudes.size()-1];
|
||||||
|
m_dudes.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: verify if battle resolution work
|
// TODO: verify if battle resolution work
|
||||||
void Simulation::resolveBattles(){
|
void Simulation::resolveBattles(){
|
||||||
for (Battle battle : m_battles){
|
for (Battle battle : m_battles){
|
||||||
|
bool attackerWins = true;
|
||||||
Dude *attacker = battle.first, *defender = battle.second;
|
Dude *attacker = battle.first, *defender = battle.second;
|
||||||
if (defender->isAlive() && defender->getAction().type == Action::ATTACK){
|
if (defender->isAlive() && defender->getAction().type == Action::ATTACK){
|
||||||
if (attacker->getPos() == defender->getPos() + Coord(defender->getAction().dir)){
|
if (attacker->getPos() == defender->getPos() + Coord(defender->getAction().dir)){
|
||||||
bool armedAttacker = attacker->getInventory() == PixelType::SWORD, armedDefender = defender->getInventory() == PixelType::SWORD;
|
bool armedAttacker = attacker->getInventory() == PixelType::SWORD, armedDefender = defender->getInventory() == PixelType::SWORD;
|
||||||
if (armedAttacker == armedDefender){
|
if (armedAttacker == armedDefender){
|
||||||
if ((rand()%100 + 1) > 50)
|
if ((rand()%100 + 1) > 50)
|
||||||
attacker->perish();
|
attackerWins = false;
|
||||||
else
|
|
||||||
defender->perish();
|
|
||||||
}else if(armedAttacker){
|
}else if(armedAttacker){
|
||||||
if ((rand()%100 + 1) > 80)
|
if ((rand()%100 + 1) > 80)
|
||||||
attacker->perish();
|
attackerWins = false;
|
||||||
else
|
|
||||||
defender->perish();
|
|
||||||
}else if(armedDefender){
|
}else if(armedDefender){
|
||||||
if ((rand()%100 + 1) > 20)
|
if ((rand()%100 + 1) > 20)
|
||||||
attacker->perish();
|
attackerWins = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(attackerWins)
|
||||||
|
{
|
||||||
|
defender->perish();
|
||||||
|
p_map->updatePixel(defender->getPos());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
defender->perish();
|
{
|
||||||
|
attacker->perish();
|
||||||
|
p_map->updatePixel(attacker->getPos());
|
||||||
}
|
}
|
||||||
}else
|
|
||||||
defender->perish();
|
|
||||||
}else
|
|
||||||
defender->perish();
|
|
||||||
}
|
}
|
||||||
|
m_battles.clear();
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,10 @@ private:
|
|||||||
std::vector<Dude*> m_dudes;
|
std::vector<Dude*> m_dudes;
|
||||||
std::vector<Team> m_teams;
|
std::vector<Team> m_teams;
|
||||||
std::set<Battle,battleComparator> m_battles;
|
std::set<Battle,battleComparator> m_battles;
|
||||||
|
std::set<Dude*> m_dead_dudes;
|
||||||
|
|
||||||
void handleAction(Dude* dude);
|
void handleAction(Dude* dude);
|
||||||
|
void removeDead();
|
||||||
void resolveBattles();
|
void resolveBattles();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user