#include "common.hpp"
#include <iostream>
#include "inet.hpp"
#include <math.h>
float stdmaint=1./16384;
float gruemaint=1./65536;
float stdrepro=MAXHEALTH/5;
float gruerepro=MAXHEALTH*.66;
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<Container> deathbed(new Container());
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 '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 (!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,shared_ptr<Thing> > >newlyborngrue;
vector<std::pair<GeneticCode,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));
newlyborngrue.push_back(std::pair<GeneticCode,shared_ptr<Thing> >(GeneticCode(code,partner->code),currentLocation));
health-=gruerepro;
}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));
newlybornsnark.push_back(std::pair<GeneticCode,shared_ptr<Thing> >(GeneticCode(code,partner->code),currentLocation));
health-=stdrepro;
}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(100);
}
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;
for (std::vector<shared_ptr<Thing> >::iterator it=currentLocation.items.begin(),end=currentLocation.items.end();
it!=end;
++it) {
Thing*tmp=it->get();
if (tmp!=this&&dynamic_cast<Snark*>(tmp)) 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;
maintenance=gruemaint;//cheaper
if (newlyborngrue.size()) {
code=newlyborngrue.back().first;
SendCode();
}
}
Snark::Snark (INETsocket controller):Avatar(controller) {
static string snark("Snark");
desc=snark;
if (newlybornsnark.size()) {
code=newlybornsnark.back().first;
SendCode();
}
}