#include "common.hpp"
#include <iostream>
#include "inet.hpp"
#include <math.h>
float stdmaint=(float)MAXHEALTH/16384.0f;
float gruemaint=(float)MAXHEALTH/65536.0f;
float stdrepro=(float)MAXHEALTH/4.0f;
float gruerepro=(float)MAXHEALTH*.25;
float stdinitrepro=(float)MAXHEALTH/8.0f;
float grueinitrepro=MAXHEALTH*.5;
float snarkbite=MAXHEALTH/128.;
float gruebite=MAXHEALTH/16.;
float gruelightbite=MAXHEALTH/256.;
float snarkbitetimecost=MAXHEALTH/256;
int gettimecost=10;
int movetimecost=20;
int bitetimecost=10;
int speaktimecost=2;
int eattimecost=2;
int combinetimecost=10;
int reproducetimecost=50;
int descriptiontimecost=20;
Avatar::Avatar(INETsocket controller){
sock=controller;
maintenance=stdmaint;
health=(float)MAXHEALTH;
lastactiontime=0;
}
bool Avatar::bite(Thing&thing,Container&room) {
return false;
}
bool Snark::bite(Thing&thing,Container&room) {
Grue *targ=dynamic_cast<Grue*>(&thing);
if (targ==NULL) return false;
unsigned int numthings=room.numItems();
float numsnarks=0;
for (unsigned int i=0;i<numthings;++i) {
if (dynamic_cast<Snark*>(room.examineItem(i))!=NULL) {
numsnarks++;
}
}
targ->addHealth(-snarkbite*numsnarks);//this squares the snarkbite defense
health-=snarkbitetimecost;//don't want to warn them
return true;
}
bool Grue::bite(Thing&thing,Container&room) {
Snark *targ=dynamic_cast<Snark*>(&thing);
if (targ==NULL) return false;
float bite=gruebite*(1-room.lightness());
if (targ->health>bite) {
addHealth(bite);
}else {
addHealth(targ->health);
}
targ->addHealth(-bite-gruelightbite);//does more damage than health gained
return true;
}
void Avatar::hungermessage() {
std::string hungry("h:");
int howhungry=(int)(health*99.9f/(float)MAXHEALTH);
hungry+='0'+(howhungry/10)%10;
hungry+='0'+(howhungry%10);
hungry+='\n';
this->privateMessage(FEEL,hungry);
}
float movedecrement=(float)MAXHEALTH/4096.0f;
float thoughtdecrement=(float)MAXHEALTH/65536.0f;//so as not to spam the server
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();
dest->getThing(myindex,location);
this->privateMessage(SEE,dest->look(*this));
float tmp1=(float)floor(health);
health-=movedecrement*(1+items.size());//carrying stuff is heavy
float tmp2=(float)floor(health);
if (tmp1!=tmp2)
hungermessage();
return true;
}
return false;
}
string getSArg(int socket);
string getSArg(std::string &order) {
string retval=order=order.substr(1);
string::size_type where1=order.find('\r');
string::size_type newline=order.find('\n');
string::size_type where2=newline;
if (where1==string::npos) where1=where2;
if (where2==string::npos) where2=where1;
if (where2==string::npos) {
printf ("String error\n");
order=std::string();
return retval;
}
if (where2<where1)where1=where2;
retval=order.substr(0,where1);
if (newline!=string::npos)
order=order.substr(newline+1);
else order=string();
return retval;
}
void Avatar::privateMessage(SENSES sense,std::string message) {
size_t len=message.length();
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) {
hungermessage();
}
bool bytestoread=INET_BytesToRead(sock);
if ( (bytestoread||orderqueue.length())&&lastactiontime<=0) {
char cmd[16];
string arg;
int rsize;
if (bytestoread&&(rsize=INET_Recv(sock,cmd,16))<=0) {
sock=-1;
Die(myindex,*place);
return;
}
if (bytestoread){
orderqueue+=string(cmd,rsize);
}
if (orderqueue.find('\n')!=string::npos) {
float tmp1=(float)floor(health);
health-=thoughtdecrement;
float tmp2=(float)floor(health);
if (tmp1!=tmp2)
hungermessage();
switch(orderqueue[0]) {
case 'b'://bite
for (ptrdiff_t index=place->numItems()-1;index>=0;--index) {
Thing*thang;
if (index!=myindex&&(arg=="all"||(thang=place->examineItem(index))->description()==arg)) {
lastactiontime+=bitetimecost;
if (!bite(*thang,*place)) {
//return failure
}
}
}
break;
case 'g'://get
arg=getSArg(orderqueue);
for (ptrdiff_t index=place->numItems()-1;index>=0;--index) {
if (index!=myindex&&(arg=="all"||place->examineItem(index)->description()==arg)) {
lastactiontime+=gettimecost;
if (!getThing(index,*place)) {
//return failure
}
}
}
break;
case 's':
lastactiontime+=speaktimecost;
for (int index=0;index<place->numItems();++index) {
if (index!=myindex) {
place->examineItem(index)->privateMessage(HEAR,getSArg(orderqueue));
}
}
break;
case 'm'://move
lastactiontime+=movetimecost;
if (!Move(getSArg(orderqueue),*place,myindex)) {
//return failure
}
break;
case 'e'://eat
lastactiontime+=eattimecost;
if (!Eat(getSArg(orderqueue))) {
//return failure
}
break;
case 'c'://combine
lastactiontime+=combinetimecost;
arg=getSArg(orderqueue);
if ((arg=Combine(arg)).length()!=0) {
privateMessage(SEE,arg);
}
break;
case 'i'://inventory
getSArg(orderqueue);
privateMessage(SEE,this->look(*this));
break;
case 'l':
getSArg(orderqueue);
privateMessage(SEE,place->look(*this));
break;
case 'r'://reproduce
lastactiontime+=reproducetimecost;
arg=getSArg(orderqueue);
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
lastactiontime+=descriptiontimecost;
desc=getSArg(orderqueue);
break;
default:
printf ("unknown command %s\n",orderqueue.c_str());
getSArg(orderqueue);//clear it out
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");
return false;
}
}else {
consent[this]=partner;
}
return true;
}
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");
return false;
}
}else {
consent[this]=partner;
}
return true;
}
string Avatar::Combine(string desc) {
string retval;
static string food("food");
static string poison("poison");
int poisoncount=0;
int foodcount=0;
for (std::vector<shared_ptr<Thing> >::iterator it=items.begin(),end=items.end();
it!=end;
++it) {
if (it->get()->description()==food) foodcount++;
if (it->get()->description()==poison) poisoncount++;
}
if (poisoncount>=2&&foodcount>0) {
int deadpoison=0;
for (ptrdiff_t index=items.size()-1;index>=0;--index) {
if (items[index]->description()==poison){
items.erase(items.begin()+index);
deadpoison++;
if (deadpoison==2) break;
}
}
shared_ptr<Thing>myfood(new FoodMeal());
this->addThing(myfood);
}
return retval;
}
bool Avatar::Eat(string desc) {
bool all=(desc=="all");
bool gotone=false;
for (ptrdiff_t index=items.size()-1;
index>=0;
--index) {
if (desc==items[index]->description()||all) {
if (items[index]->EatMe(*this)) {
if(index+1!=items.size()) {
items[index]=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);
return true;
}
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*.25)
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=newlybornsnark.back().second.first;
code=newlybornsnark.back().first;
}
SendCode();
}