I decided against using an integer to represent what kind of thing a mob is (meat/vegie, etc.) and so settled on using boolean on whether
1. do you eat meat T/F
2. do you eat vegies T/F
Which pretty much get the vast majority of cases I could think of and since they're in the struct, it wouldn't take much to expand it later.
There was also the issue of expressing whether a mob is a meat or is a vegie.
1. i am meat T/F
2. i am vegie T/F
Same kind of thing, as described above, is happening here.
before I sat down to code this, the integer idea seemed like the way to go. Then i started looking at the chaos I'd have to deal with and decided some boolean checks would get the job done and be easier to put in place. And, as a bonus, might conserve on resources more than a sint8 (or whatever).
If my theory holds true, these simpler pieces, when and once assembled, will create a nifty illusion. Still a little while to go though
todo/notes:
mobs have properties of animalinstincts, but not methods like npcs
if the player doesn't have a target selected, then the npc can't eat (so if a player unselects target before death, then npc can't feast on body)
::Starve() needs done (just reverse of Eat but w/o having to do -'s)
need to think about what kind of benefits should fall onto a mob for having good health. For example, maybe if you aren't hungry then your stun timer doesn't last as long. And if you are hungry, then it lasts longer.
Phase 3 will consist of a few things that I pushed aside in p2. Namely, messing around with players giving npcs items and having that translate to food for the npc. Note to self: OP_Click_Give.
Anyhow, here's the bulk of phase 2 (I expect to amend this later), which is more proof of concept groundwork:
Code:
npc.h
//malevolent
struct strctAnimalInstincts
{
sint8 Hunger; // -100<x<100 : 0 equilibrium [threshold]
bool Meat; //do you eat meat?
bool Vegetables; //do you eat vegetables?
};
class:
//*****************************************************************//
//Animal instincts: Hunger
void Eat(int HowMuchFood); //malevolent: eat
void Starve(int FastAmount);//malevolent: start
int GetHungerStatus() { return AnimalInstincts->Hunger;}
bool IsHungry(); //malevolent: checks to see if the npc is hungry
//*****************************************************************//
Protected:
//Malevolent: Animal Instincts
strctAnimalInstincts* AnimalInstincts;
npc.cpp
//malevolent:: is the critter hungry? returns the int value representing their hunger
bool NPC::IsHungry()
{
if (this->AnimalInstincts->Hunger >= 0)
return false;
else
return true;
}
//This should fire after npc has eaten
void NPC::Eat(int amount)
{
strctAnimalInstincts* instincts=new strctAnimalInstincts;
instincts->Hunger=this->AnimalInstincts->Hunger + amount;
//bounds checks
//max
if (instincts->Hunger >100)
instincts->Hunger =100;
//min
if (instincts->Hunger <-100)
instincts->Hunger =-100;
//now assign
this->AnimalInstincts=instincts;
}
mob.h
public:
//*****************************************
//malevolent
bool IsMeat(){return foodtype->IsMeat;}
bool IsVegie(){return foodtype->IsVegie;}
//*******************************************
protected:
//malevolent:
FoodType* foodtype; //what kind of food am i?
//Malevolent animal instincts
struct FoodType {
bool IsMeat; //is a meat-based mob
bool IsVegie; //is a vegie-based mob
};
mob.cpp
in constructor:
//malevolent
FoodType* ft = new FoodType;
ft->IsMeat=true;
ft->IsVegie=false;
this->foodtype=ft;
client.cpp
//Malevolent
//hunger look up on target NPC
else if (strcasecmp(sep.arg[0], "#Hungry") == 0)
{
if (target != 0 && target->IsNPC())
{
Message(0,"Asking target if they are hungry..");
switch(target->CastToNPC()->IsHungry())
{
case false:
Message(0,"Hungry!");
break;
case true:
Message(0,"Not hungry.");
break;
default:
Message(0, "Does not eat.");
break;
}
}
}
//Malevolent
//ForceFeed the NPC
else if (strcasecmp(sep.arg[0], "#ForceFeed") == 0)
{
if (target != 0 && target->IsNPC())
{
target->CastToNPC()->Eat(atoi(sep.arg[1]));
Message(0,"Fed: %i",atoi(sep.arg[1]));
}
}
//Malevolent
//Lookup the NPC's instinct values
else if (strcasecmp(sep.arg[0], "#HungerThreshold") == 0)
{
if (target != 0 && target->IsNPC())
{
Message(0,"Hunger Value: %i",target->CastToNPC()->GetHungerStatus());
}
}
//Malevolent
//Check to see if the npc can eat the user
else if (strcasecmp(sep.arg[0], "#CanYouEatMe") == 0)
{
if (target !=0 && (target->IsNPC() || target->IsMob()) )
{
if(target->CastToNPC()->CanIEatYou(this->CastToMob()))
{
Message(0, "Yum, yum! I can eat you..");
if(target->CastToNPC()->IsHungry())
Message(0, "I'm going to eat you!");
else
Message(0, "I'm fine and full. I won't eat you.");
}
}
else
{
Message(0, "You really think that such a thing could eat?");
}
}
//Malevolent
//Check on whether they are meat or vegie
else if (strcasecmp(sep.arg[0], "#voretype") == 0)
{
if (target !=0 && (target->IsNPC() || target->IsMob()) )
{
if(target->IsMeat())
Message(0,"I'm meat.");
else
Message(0,"I'm not meat. Move along.");
if(target->IsVegie())
Message(0,"I'm vegie.");
else
Message(0,"I'm not a vegie. You really think I'm green?");
}
}
//Malevolent
//Check to see if the npc can eat the user
else if (strcasecmp(sep.arg[0], "#EatMe") == 0)
{
if (target !=0 && (target->IsNPC()))
{
if(target->CastToNPC()->CanIEatYou(this->CastToMob()))
{
Message(0, "mmmm..foood");
if(target->CastToNPC()->IsHungry())
{
Message(0, "I'm going to eat you!");
target->CastToNPC()->AddToHateList(this,100); //be sure to *stick* to the target
target->CastToNPC()->Attack(this); //attack 'm!
}
else
{
Message(0, "I'm fine and full. I won't eat you.");
}
} else
{
Message(0, "%s says, \"I cannot eat you. You sure people eat your kind?.\"",target->GetName());
}
}
else
{
Message(0, "You really think that such a thing could eat?");
}
}
//malevolent
//using sic code, but adds if npc is hungry and if it can eat the target
//todo add a method to npc with a sicifhungry() signature
else if (strcasecmp(sep.arg[0], "#sicifhungry") == 0)
{
if (target && target->IsNPC() && sep.arg[1] != 0)
{
Mob* sictar = entity_list.GetMob(sep.arg[1]);
if (sictar)
{
if(target->CastToNPC()->CanIEatYou(this->CastToMob()))
{
Message(0, "mmmm..foood");
if(target->CastToNPC()->IsHungry())
{
Message(0, "I'm going to eat you!");
target->CastToNPC()->AddToHateList(sictar,100); //be sure to *stick* to the target
target->CastToNPC()->Attack(this); //attack 'm!
}
else
{
Message(0, "I'm full. I won't eat.");
}
}
}
else
{
Message(0, "Error: %s not found", sep.arg[1]);
}
}
else
{
Message(0, "Usage: (needs NPC targeted) #sic targetname");
}
}
attack.cpp
::death
at end of the tunnel
//malevolent
if (other->IsNPC())
other->CastToNPC()->Eat(pp.level);
--MV