You're
coming to the end of the long haul. You’ve finished the private data and
functions, and the public functions are left:
public:
cCharController()
{
ZeroMemory(this, sizeof(*this));
}
~cCharController()
{
shutdown();
}
void free()
{
delete m_root_char;
m_root_char = NULL;
m_num_char = 0;
}
void shutdown()
{
free();
delete[] m_mesh_anim;
m_mesh_anim = NULL;
m_num_mesh_anim = 0;
delete[] m_char_anim;
m_char_anim = NULL;
m_num_char_anim = 0;
m_spell_controller = NULL;
m_def_file[0] = '\0';
m_weapon_mesh_path[0] = '\0';
m_texture_path[0] = '\0';
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void cCharController::init(ID3DXFont* font, PCSTR def_file,
sItem* mil, sSpell* msl,
long num_mesh_anim, PCSTR* mesh_names,
PCSTR weapon_mesh_path, PCSTR texture_path,
long num_char_anim, sCharAnimInfo* char_anims)
{
free();
if(mesh_names == NULL || def_file == NULL)
return;
m_font = font;
strcpy(m_def_file, def_file);
m_mil = mil;
m_msl = msl;
// copy over mesh path and texture path (or set default)
strcpy(m_weapon_mesh_path, weapon_mesh_path ? weapon_mesh_path : ".\\");
strcpy(m_texture_path, texture_path ? texture_path : ".\\");
// get mesh names
if((m_num_mesh_anim = num_mesh_anim) != 0)
{
m_mesh_anim = new sMeshAnim[num_mesh_anim];
for(long i = 0; i < m_num_mesh_anim; i++)
strcpy(m_mesh_anim[i].filename, mesh_names[i]);
}
// get animation data
if((m_num_char_anim = num_char_anim) != 0)
{
m_char_anim = new sCharAnimInfo[m_num_char_anim];
for(long i = 0; i < m_num_char_anim; i++)
memcpy(&m_char_anim[i], &char_anims[i], sizeof(sCharAnimInfo));
}
}
In addition to the typical class
constructor and destructor are the init and
shutdown pair
of functions. For the controller to operate, it must first be initialized with a
call to init.
When you’re done with the character controller class, a call to
shutdown is in order.
Somewhat similar in nature to
shutdown, the free function completely
removes all characters in the list of active characters. This function is useful
for
clearing the list when a character leaves a level and a whole new set of
characters
need to be added to the list.
Speaking of
adding characters to the list, here comes the function that does it all.
With the
add_char function, you need to provide a unique identification number, the MCL
character definition number to use, the character’s type to assign (CHAR_PC,
CHAR_NPC,
or CHAR_MONSTER), the artificial intelligence to use, and the character’s
coordinates and
Y-axis angle used to point the character in a specific direction.
Following
add_char are two functions that remove a character in the list. The remove
function
takes a character’s unique identification number as an argument,
and the remove_char function takes a pointer to the
character structure.
///////////////////////////////////////////////////////////////////////////////////////////////////
bool cCharController::add_char(long id, long def, long type, long ai,
float pos_x, float pos_y, float pos_z,
float direction)
{
FILE* fp;
if((fp = fopen(m_def_file, "rb")) == NULL)
return false;
sCharacter* character = new sCharacter;
character->def = def;
character->id = id;
character->type = type;
character->ai = ai;
character->pos_x = pos_x;
character->pos_y = pos_y;
character->pos_z = pos_z;
character->direction = direction;
character->update_enable = true;
character->charge = rand()%101;
sCharDef& char_def = character->char_def;
fseek(fp, sizeof(sCharDef) * def, SEEK_SET);
fread(&char_def, 1, sizeof(sCharDef), fp);
fclose(fp);
character->health_points = char_def.health_points;
character->mana_points = char_def.mana_points;
// load character ics
if(char_def.item_filename)
{
character->char_ics = new cCharIcs;
character->char_ics->load(char_def.item_filename);
}
sMeshAnim& mesh_anim = m_mesh_anim[char_def.mesh_index];
// load mesh and animation if needed
if(mesh_anim.count == 0)
{
mesh_anim.mesh.load(mesh_anim.filename, m_texture_path);
mesh_anim.anim.load(mesh_anim.filename, &mesh_anim.mesh);
for(long i = 0; i < m_num_char_anim; i++)
mesh_anim.anim.set_loop(m_char_anim[i].is_loop, m_char_anim[i].name);
}
character->object.create(&mesh_anim.mesh);
mesh_anim.count++;
// load and configure weapon (if any)
if(m_mil && char_def.weapon != -1 && m_mil[char_def.weapon].mesh_filename)
{
char path[MAX_PATH];
sprintf(path, "%s%s", m_weapon_mesh_path, m_mil[char_def.weapon].mesh_filename);
character->weapon_mesh.load(path, m_texture_path);
character->weapon_object.create(&character->weapon_mesh);
character->weapon_object.attach_to_object(&character->object, "WeaponHand");
}
// link into head of list
if(m_root_char)
m_root_char->prev = character;
character->next = m_root_char;
m_root_char = character;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void cCharController::remove_char(sCharacter* character)
{
if(character == NULL)
return;
// decrease mesh count and release if no more
sMeshAnim& mesh_anim = m_mesh_anim[character->char_def.mesh_index];
if(--mesh_anim.count == 0)
{
mesh_anim.mesh.free();
mesh_anim.anim.free();
}
// remove from list
if(character->prev)
character->prev->next = character->next;
else
m_root_char = character->next;
if(character->next)
character->next->prev = character->prev;
character->prev = character->next = NULL;
delete character;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void remove(long char_id)
{
return remove_char(get_char(char_id));
}