#include "common.hpp"
#include <iostream>
#include "inet.hpp"
#include <math.h>
float stdmaint=1./4096;
float gruemaint=1./16384;
float stdrepro=MAXHEALTH/4;
float gruerepro=MAXHEALTH*.25;
float stdinitrepro=MAXHEALTH/8;
float grueinitrepro=MAXHEALTH*.5;
Avatar::Avatar(INETsocket controller){
sock=controller;
maintenance=stdmaint;
health=(float)MAXHEALTH;
}
bool Avatar::Move(string destination, Container&location, unsigned int myindex) {
map<string,weak_ptr<Room> >* links=location.exits();
map<string,weak_ptr<Room> >::iterator where=links->find(destination);
if (where!=links->end()) {
shared_ptr<Room> dest=where->second.lock();
int numpeople=dest->numItems();
for (unsigned int i=0;i<numpeople;++i) {
dest->examineItem(i)->privateMessage(SEE,this->description());
}
dest->getThing(myindex,location);
this->privateMessage(SEE,dest->look(*this));
return true;
}
return false;
}
string getSArg(int socket);
void Avatar::privateMessage(SENSES sense,std::string message) {
size_t len=message.length()+1;
unsigned char csense[4]={len%256,(len/256)%256,(len/65536)%256,sense};
INET_Write(sock,4,(const char*)csense);
INET_Write(sock,message.length(),message.data());
}
shared_ptr<Room> deathbed(new Room(0));
void Avatar::Die(int myindex, Container&place) {
deathbed->getThing(myindex,place);
INET_close(sock);
sock=-1;
}
float healthdecrement=1.0f/16384;
void Avatar::tick(shared_ptr<Thing>&location, unsigned int myindex) {
Container::tick(location,myindex);
Container * place=static_cast<Container*>(location.get());
float tmp1=(float)floor(health);
health-=maintenance;
float tmp2=(float)floor(health);
if (health<0){
Die(myindex,*place);
return;
}
if (tmp1!=tmp2) {
std::string hungry("hungry:");
int howhungry=(int)(health*99.9f/(float)MAXHEALTH);
hungry+='0'+(howhungry/10)%10;
hungry+='0'+(howhungry%10);
hungry+='\n';
this->privateMessage(FEEL,hungry);
}
if (INET_BytesToRead(sock)) {
char cmd[4];
string arg;
if (!INET_Read(sock,cmd,1)) {
sock=-1;
Die(myindex,*place);
return;
}
switch(cmd[0]) {
case 'g'://get
arg=getSArg(sock);
for (ptrdiff_t index=place->numItems()-1;index>=0;--index) {
if (index!=myindex&&(arg=="all"||place->examineItem(index)->description()==arg)) {
if (!getThing(index,*place)) {
//return failure
}
}
}
break;
case 's':
for (int index=0;index<place->numItems();++index) {
if (index!=myindex) {
place->examineItem(index)->privateMessage(HEAR,getSArg(sock));
}
}
case 'm'://move
if (!Move(getSArg(sock),*place,myindex)) {
//return failure
}
break;
case 'e'://eat
if (!Eat(getSArg(sock))) {
//return failure
}
break;
case 'i'://inventory
getSArg(sock);
//FIXME
break;
case 'l':
getSArg(sock);
privateMessage(SEE,place->look(*this));
break;
case 'r'://reproduce
arg=getSArg(sock);
for (int index=0;index<place->numItems();++index) {
if (index!=myindex&&(arg=="all"||place->examineItem(index)->description()==arg)) {
if (!place->examineItem(index)->reproduce(*this,location)) {
//return failure
}
}
}
break;
case 'd'://change description
desc=getSArg(sock);
break;
default:
break;
}
}
//FIXME process client commands
//FIXME send update to client
}
void Avatar::addHealth(float health) {
this->health+=health;
if (this->health>MAXHEALTH)
this->health=MAXHEALTH;
if (health>0) {
privateMessage(TASTE,"tasty");
}else {
privateMessage(TASTE,"foul");
}
}
map <Avatar*,Avatar*> consent;
vector<std::pair<GeneticCode,std::pair<float,shared_ptr<Thing> > > >newlyborngrue;
vector<std::pair<GeneticCode,std::pair<float,shared_ptr<Thing> > > >newlybornsnark;
bool Grue::canConnect() {
return newlyborngrue.size()>1;
}
bool Snark::canConnect() {
return newlybornsnark.size()>1;
}
bool Grue::reproduce(Avatar&who, shared_ptr<Thing>¤tLocation) {
Grue*partner;
if (!(partner=dynamic_cast<Grue*>(&who))) {
return false;
}
if (consent[partner]==this) {
consent.erase(consent.find(partner));
health-=gruerepro;
who.health-=grueinitrepro;
GeneticCode combinedcode(code);
if (combinedcode.combine(code,partner->code)) {
privateMessage(FEEL,"happy");
partner->privateMessage(FEEL,"happy");
float h=stdrepro+stdinitrepro;
if (health<0) h+=health; //dying soon, not a healthy child
if (who.health<0) h+=who.health;//dying soon
newlyborngrue.push_back(std::pair<GeneticCode,std::pair<float,shared_ptr<Thing> > >(combinedcode,std::pair<float,shared_ptr<Thing> > (h,currentLocation)));
}else {
privateMessage(FEEL,"sad");
partner->privateMessage(FEEL,"sad");
}
}else {
consent[this]=partner;
}
}
bool Snark::reproduce(Avatar&who, shared_ptr<Thing>¤tLocation) {
Snark*partner;
if (!(partner=dynamic_cast<Snark*>(&who))) {
return false;
}
if (consent[partner]==this) {
consent.erase(consent.find(partner));
health-=stdrepro;
who.health-=stdinitrepro;
GeneticCode combinedcode(code);
if (combinedcode.combine(code,partner->code)) {
float h=stdrepro+stdinitrepro;
if (health<0) h+=health; //dying soon, not a healthy child
if (who.health<0) h+=who.health;//dying soon
newlybornsnark.push_back(std::pair<GeneticCode,std::pair<float,shared_ptr<Thing> > >(combinedcode,std::pair<float,shared_ptr<Thing> > (h,currentLocation)));
privateMessage(FEEL,"happy");
partner->privateMessage(FEEL,"happy");
}else {
privateMessage(FEEL,"sad");
partner->privateMessage(FEEL,"sad");
}
}else {
consent[this]=partner;
}
}
bool Avatar::Eat(string desc) {
bool all=(desc=="all");
bool gotone=false;
for (std::vector<shared_ptr<Thing> >::iterator it=items.begin(),end=items.end();
it!=end;
++it) {
if (desc==it->get()->description()||all) {
if (it->get()->EatMe(*this)) {
*it=items.back();
items.pop_back();
gotone=true;
if (!all)
return true;
}
}
}
if (gotone) return true;
return false;
}
Avatar::~Avatar() {
if (sock!=-1)
INET_close(sock);
std::cout << description()<<" died\n";
}
Grue::~Grue(){}
Snark::~Snark(){}
bool Grue::getThing(unsigned int thingindex, Container&previous) {
Thing* item=previous.examineItem(thingindex);
Grue * tmp=dynamic_cast<Grue*> (item);
if (tmp) return false;
Avatar * tmp1=dynamic_cast<Avatar*> (item);
if (tmp1&&previous.lightness()>.5) {
return false;
}
if (!tmp1) return false;//carnivore
return this->Avatar::getThing(thingindex,previous);
}
bool Grue::takeMe(Container& destination, Container& currentLocation) {
return dynamic_cast<Room*>(&destination)!=NULL;///impervious to attack
}
bool Snark::EatMe(Avatar& thing) {
thing.addHealth(health);
}
bool Snark::getThing(unsigned int thingindex, Container&previous) {
Thing* item=previous.examineItem(thingindex);
Avatar * tmp=dynamic_cast<Avatar*> (item);
if (tmp)return false;
return Avatar::getThing(thingindex,previous);
}
bool Snark::takeMe(Container& destination, Container& currentLocation) {
if (dynamic_cast<Room*>(&destination)!=NULL)return true;
float tot=0;
for (std::vector<shared_ptr<Thing> >::iterator it=currentLocation.items.begin(),end=currentLocation.items.end();
it!=end;
++it) {
Thing*tmp=it->get();
Snark* healther;
if (tmp!=this&&(healther=dynamic_cast<Snark*>(tmp))!=NULL) {
tot+=healther->health;
}
}
if (tot>MAXHEALTH*1.1)
return false;
return Avatar::takeMe(destination,currentLocation);
}
void Avatar::SendCode() {
string codedata=code.tostring();
size_t len=codedata.length();
unsigned char dat[4]={(len/(65536*256))%256,
(len/(65536))%256,
(len/(256))%256,
len%256};
INET_Write(sock,4,(char*)dat);
INET_Write(sock,len,codedata.data());
}
Grue::Grue (INETsocket controller):Avatar(controller) {
static string grue("Grue");
desc=grue;
health=grueinitrepro;
health+=gruerepro;
maintenance=gruemaint;//cheaper
if (newlyborngrue.size()) {
health=newlyborngrue.back().second.first;
code=newlyborngrue.back().first;
SendCode();
}
}
Snark::Snark (INETsocket controller):Avatar(controller) {
static string snark("Snark");
desc=snark;
health=stdinitrepro;
health+=stdrepro;
if (newlybornsnark.size()) {
health=newlyborngrue.back().second.first;
code=newlybornsnark.back().first;
SendCode();
}
}