Structures. And make the entity property of the structure. But there are many ways to handle them. This is the architecture that I use for handling a "complex" data structure (keep in mind some data-types and functions are fictional, you'll have to make these yourself):
//complex structure
typedef struct {
BOOL alive; //indicates if the NPC is alive
BOOL freeze; //indicates if the NPC is frozen
ENTITY* appearance; //the model for the NPC
unsigned short npc_type; //what kind of NPC
unsigned int anim_state; //animation state
VECTOR* pos; //current position (passed on to ENTITY*
VECTOR* target; //target to move to
DIALOGUES* dialoges; //NPC's dialogues
LINKEDLIST* questlist; //NPC's questlist
} NPC;
//npc function (called by create_npc)
void handle_npc(NPC* npc) {
while(npc->alive == true) {
//do everything here
wait(1);
}
//npc is dead, apparantly... remove the object!
remove_npc(npc);
}
//creator function (called by game-logic)
NPC* create_npc(STRING* npc_model, VECTOR* start_pos) {
//allocate memory for a new NPC!
NPC* npc = (NPC*)malloc(sizeof(NPC));
npc->alive = true;
npc->freeze = false;
npc->appearance = ent_create(npc_model, start_pos, NULL);
npc->npc_type = NPC_VILLAGER; //regular villager
npc->anim_state = 0; //start at idle animation
npc->pos = pos;
npc->target = NULLVECTOR;
npc->dialogues = get_dialogues(DIALOGUE_VILLAGER); //get dialogue of the villager
npc->questlist = create_linkedlist();
//give the NPC two quests at creation
add_linkedlist_item( npc->questlist, "quest_1"); //add new item to the linkedlist
add_linkedlist_item( npc->questlist, "quest_2"); //add new item to the linkedlist
handle_npc(npc); //start it's main function
return(npc); //return pointer to the calling function for possible further process
}
//removing function (called by handle_npc())
void remove_npc(NPC* npc) {
//remove all the stored objects that are only stored as pointer first before removing the npc itself.
//else we'd lose spaces of memory because we throw away the only pointer available to the object.
ptr_remove( npc->appearance );
ptr_remove( npc->pos );
ptr_remove( npc->target );
//ptr_remove can't throw away our own created structures, we need to call their remove functions to prevent memory gaps.
//just like we do with this npc remove function.
//note that we don't use remove_dialogues( npc->dialogues ); because more NPC's make use of the same dialogue. This data array is shared.
remove_linkedlist( npc->questlist ); //this function will then throw away all the objects stored in the linked list (the two quests we assigned earlier).
//at last, we can remove the npc object safely
ptr_remove(npc);
}
And this is, then, the code collection of one object in your game. I put each and every object in a separate file to keep things clear.
simply call create_npc("npc1.mdl", NULLVECTOR); and tatam! You'll get a self-functional NPC.
Of course, my code wont work unless you also create all the other missing structures and functions, but it's just an example.