Part 24: Objects - Part 4: In the character's sheet
Downloads
Objects positions
<items>
<!-- ======================== Weapons ======================== -->
<!-- EYE OF TIME -->
<item name="ITEM001">
<category>Weapon</category>
<floor_image>00W_Ring.png</floor_image>
<image_file>Items0.png</image_file>
<image_num>17</image_num>
<position>hBCP</position>
</item>
[...]
</items>
Body parts
#define BACKPACK_SIZE 17
class CCharacter
{
public:
enum EBodyParts
{
eBodyPartHead = 0,
eBodyPartNeck,
eBodyPartTorso,
eBodyPartLeftHand,
eBodyPartRightHand,
eBodyPartLegs,
eBodyPartFeet,
eBodyPartPouch1,
eBodyPartPouch2,
eBodyPartQuiver1,
eBodyPartQuiver2,
eBodyPartQuiver3,
eBodyPartQuiver4,
eBodyPartBackpack,
eBodyPartCount = eBodyPartBackpack + BACKPACK_SIZE
};
The array that holds the objects of our character will change too. previously we had a placeholder array of ints, now we
CObject bodyObjects[eBodyPartCount];
Defining the objects slots
class CInterface
{
public:
[...]
struct SBodyInfos
{
CVec2 pos;
char type;
int defaultImage;
};
[...]
private:
[...]
SBodyInfos bodyInfos[CCharacter::eBodyPartCount];
};
This array is initialized in the constructor of CInterface:
CInterface::CInterface()
{
[...]
// initialize the positions of objects in the character's sheet
bodyInfos[CCharacter::eBodyPartHead].pos = CVec2(34, 59);
bodyInfos[CCharacter::eBodyPartNeck].pos = CVec2( 6, 66);
bodyInfos[CCharacter::eBodyPartTorso].pos = CVec2(34, 79);
bodyInfos[CCharacter::eBodyPartLeftHand].pos = CVec2( 6, 86);
bodyInfos[CCharacter::eBodyPartRightHand].pos = CVec2(62, 86);
bodyInfos[CCharacter::eBodyPartLegs].pos = CVec2(34, 99);
bodyInfos[CCharacter::eBodyPartFeet].pos = CVec2(34, 119);
bodyInfos[CCharacter::eBodyPartPouch1].pos = CVec2( 6, 106);
bodyInfos[CCharacter::eBodyPartPouch2].pos = CVec2( 6, 123);
bodyInfos[CCharacter::eBodyPartQuiver1].pos = CVec2(62, 106);
bodyInfos[CCharacter::eBodyPartQuiver2].pos = CVec2(79, 106);
bodyInfos[CCharacter::eBodyPartQuiver3].pos = CVec2(62, 123);
bodyInfos[CCharacter::eBodyPartQuiver4].pos = CVec2(79, 123);
bodyInfos[CCharacter::eBodyPartHead].type = 'H';
bodyInfos[CCharacter::eBodyPartNeck].type = 'N';
bodyInfos[CCharacter::eBodyPartTorso].type = 'T';
bodyInfos[CCharacter::eBodyPartLeftHand].type = 'h';
bodyInfos[CCharacter::eBodyPartRightHand].type = 'h';
bodyInfos[CCharacter::eBodyPartLegs].type = 'L';
bodyInfos[CCharacter::eBodyPartFeet].type = 'F';
bodyInfos[CCharacter::eBodyPartPouch1].type = 'P';
bodyInfos[CCharacter::eBodyPartPouch2].type = 'P';
bodyInfos[CCharacter::eBodyPartQuiver1].type = 'Q';
bodyInfos[CCharacter::eBodyPartQuiver2].type = 'q';
bodyInfos[CCharacter::eBodyPartQuiver3].type = 'q';
bodyInfos[CCharacter::eBodyPartQuiver4].type = 'q';
for (int i = 0; i < BACKPACK_SIZE; ++i)
{
int x = 66 + ((i + 1) % 9) * 17;
int y = 49 + ((i + 1) / 9) * 17;
bodyInfos[CCharacter::eBodyPartBackpack + i].pos = CVec2(x, y);
bodyInfos[CCharacter::eBodyPartBackpack + i].type = 'B';
}
// default images for the body parts
for (int i = 0; i < CCharacter::eBodyPartCount; ++i)
bodyInfos[i].defaultImage = -1;
bodyInfos[CCharacter::eBodyPartHead].defaultImage = 24;
bodyInfos[CCharacter::eBodyPartNeck].defaultImage = 16;
bodyInfos[CCharacter::eBodyPartTorso].defaultImage = 26;
bodyInfos[CCharacter::eBodyPartLeftHand].defaultImage = 20;
bodyInfos[CCharacter::eBodyPartRightHand].defaultImage = 22;
bodyInfos[CCharacter::eBodyPartLegs].defaultImage = 28;
bodyInfos[CCharacter::eBodyPartFeet].defaultImage = 30;
bodyInfos[CCharacter::eBodyPartPouch1].defaultImage = 17;
bodyInfos[CCharacter::eBodyPartQuiver1].defaultImage = 18;
bodyInfos[CCharacter::eBodyPartBackpack + 8].defaultImage = 19;
}
Drawing and mouse area
void CInterface::drawBodyPart(QImage* image, CVec2 pos, int championNum, CCharacter::EBodyParts part, bool enableArea)
It starts with the drawing part. We check if there is an object int the bodyObjects array for the given character.
{
CCharacter* c = &game.characters[championNum];
int objType = c->bodyObjects[part].getType();
if (objType != 0)
{
// draw the object in this slot
CObjects::CObjectInfo object = objects.mObjectInfos[objType - 1];
QImage objImage = fileCache.getImage(object.imageFile.toLocal8Bit().constData());
CRect rect = getItemRect(object.imageNum);
graph2D.drawImageAtlas(image, pos, objImage, rect);
}
else if (bodyInfos[part].defaultImage != -1)
{
// draw the default image
QImage bodyParts = fileCache.getImage("gfx/interface/Items6.png");
CRect rect = getItemRect(bodyInfos[part].defaultImage);
graph2D.drawImageAtlas(image, pos, bodyParts, rect);
}
The second part of the function defines the mouse area.
// mouse area
int objHandType = mouse.mObjectInHand.getType();
CRect mouseRect(pos, pos + CVec2(ITEM_WIDTH - 1, ITEM_HEIGHT - 1));
bool isPositionCompatible = true;
// check if the object we are holding can be put in this type of slot
if (objHandType != 0)
{
QString& positions = objects.mObjectInfos[objHandType - 1].positions;
isPositionCompatible = positions.contains(bodyInfos[part].type);
}
if (isPositionCompatible == true && enableArea == true)
mouse.addArea(eMouseArea_InvObject, mouseRect, eCursor_Hand, (void*)championNum, (void*)part);
}
Now in drawInventory(), we can draw all the objects with this simple loop:
for (int i = 0; i < CCharacter::eBodyPartCount; ++i)
drawBodyPart(image, bodyInfos[i].pos, currentChampion, (CCharacter::EBodyParts)i);
Checking the mouse area
void CInterface::update(SMouseArea* clickedArea)
{
[...]
if (clickedArea != NULL)
{
if (mouse.mButtonPressing == true)
{
switch (clickedArea->type)
{
[...]
// object slot in inventory
case eMouseArea_InvObject:
{
// get current character and position in inventory
int champNum = (int)clickedArea->param1;
CCharacter* c = &game.characters[champNum];
int objectPos = (int)clickedArea->param2;
// swap the object we are holding with the one in the inventory
CObject temp = mouse.mObjectInHand;
mouse.mObjectInHand = c->bodyObjects[objectPos];
c->bodyObjects[objectPos] = temp;
}
break;
default:
break;
}
}
[...]
}
We simply exchange the object we are holding with the one in the slot.
Champions' starting objects
<!-- ELIJA -->
<champion firstName="CHAMP_FNAME00" lastName="CHAMP_LNAME00">
[...]
<object pos="T">52</object>
<object pos="L">53</object>
<object pos="F">50</object>
<object pos="21">133</object>
</champion>
For the position, you can either put the slot number following the EBodyParts enum or use one of these shortcuts:
class CCharacter
{
[...]
private:
struct SDBObject
{
int pos;
int type;
};
struct SChampDBData
{
[...]
std::vector<SDBObject> objects;
};
[...]
};
When we call fromDB() to initialize a character, its objects are created from this list:
void CCharacter::fromDB(int num)
{
[...]
for (size_t i = 0; i < eBodyPartCount; ++i)
bodyObjects[i].setType(0);
for (size_t i = 0; i < db.objects.size(); ++i)
{
int pos = db.objects[i].pos;
int type = db.objects[i].type;
bodyObjects[pos].setType(type);
}
}
Hands at the top
void CInterface::drawChampion(QImage* image, int num)
{
[...]
// draw hands
mouse.addArea(eMouseArea_None, handMouseRect, eCursor_Hand);
drawBodyPart(image, CVec2(69 * num + 4, 10), num, CCharacter::eBodyPartLeftHand, !isResurrecting);
drawBodyPart(image, CVec2(69 * num + 24, 10), num, CCharacter::eBodyPartRightHand, !isResurrecting);
You can see that we also set the last parameterof this function - the enableArea flag.