Plastic Gem #33: Damaged/Bloody Weapons
by Anthony Rosenbaum · 07/25/2008 (6:15 am) · 5 comments

IFL Skin on ShapeBaseImages
Have you ever noticed that threads on ShapeBaseImages can only be played via its state machine? Have you ever wanted to play a thread on that ShapeBaseImages weapon to show a change in its appearance such as showing damage or blood? Well using ifls to change the texture of the ShapeBaseImage is the focus of this resource. There will be C changes, art requirements, and script examples so follow closely. That being said, this resource could be used as a stepping off point for playing other animations on the ShapeBaseImage separate from the state machine.
This code can be implemented in TGEA 1.7 and TGE 1.5.2
1) Add an blend IFL animation to your .dts labeled "damage_skin"
Ok the Art requirements are done, be sure you test it in the show tool and before going on to the C side.
We'll need a place to store that sequence in the ShapeBaseImageData
2) In ShapeBase.h in ShapeBaseImageData class before
S32 spinSequence; ///< ID of the spin animation sequence. ADD
// > pg damage blood S32 sequenceDamage; ///< Blood Damage thread sequence. //< pg damage blood
Now we'll need a variable to store the current position of the thread.
3) In the ShapeBase class within the MountedImage Struct after
bool wet; ///< Is the weapon wet? ADD
// > pg damage blood F32 damagePos; // < pg damage blood
We'll need a new thread on the MountedImage Struct to play so
4) After TSThread *spinThread; Add
// > pg damage blood TSThread *damageThread; // < pg damage blood
5) Now it is time to declare an interface, also within Shapebase after
void getMuzzlePoint(U32 imageSlot,Point3F* pos); ADD
// > pg damage blood void setDamageBloodPos(U32 imageSlot, F32 pos); // < pg damage blood
Time for a quick stop in ShapeBase.cc to transmit the sequence position over the network
6) In U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream) AFTER
con->packStringHandleU(stream, image.skinNameHandle); ADD
// > pg damage blood stream->write(image.damagePos); // < pg damage blood
7) In void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream) AFTER
StringHandle skinDesiredNameHandle = con->unpackStringHandleU(stream); ADD
// > pg damage blood stream->read(&image.damagePos); setDamageBloodPos(i, image.damagePos); // < pg damage bloodNotice how we set the position each time it is transmitted, this might seem like over kill right now but setDamageBloodPos() does some checking to reduce the transmittions.
Moving on to ShapeImage.cc, we'll need to associate the sequence to the datablock.
8) In bool ShapeBaseImageData::preload(bool server, char errorBuffer[256])
After
spinSequence = shape->findSequence("spin"); ADD
// > pg damage blood
sequenceDamage = shape->findSequence("damage_skin");
// < pg damage bloodTime to initalize our thread when the image is set on the shapebase9) In void ShapeBase::setImage()
AFTER
image.spinThread = 0; ADD
// > pg damage blood image.damageThread = 0; // < pg damage blood
And not to far below that code, if the sequenceDamage actually exsist on the datablock we will associate the sequence to the thread
10) In ShapeBase::SetImage() after the
if (image.dataBlock->spinSequence != -1) {} Block ADD
// > pg damage blood
if (image.dataBlock->sequenceDamage != -1) {
image.damageThread = image.shapeInstance->addThread();
image.shapeInstance->setTimeScale(image.damageThread,1);
image.shapeInstance->setSequence(image.damageThread,
image.dataBlock->sequenceDamage,0);
}
// < pg damage bloodOur final C change is defineing the setBloodDamagePos() function and its console interface. Notice how the bits are only set if it is a server object and if the position has changed, this reduces network traffic. This same function is also reused by the console interface.
11) At the bottom of the file add
// > pg damage blood
void ShapeBase::setDamageBloodPos(U32 imageSlot,F32 pos)
{
if (isServerObject())
{
MountedImage& image = mMountedImageList[imageSlot];
if (image.dataBlock)
{
if (pos == image.damagePos)
return; // nothing changed...
setMaskBits(ImageMaskN << imageSlot);
image.damagePos = pos;
}
}
else
{
// put client crap here...
MountedImage& image = mMountedImageList[imageSlot];
if (image.dataBlock != NULL && image.dataBlock->sequenceDamage != -1)
image.shapeInstance->setPos(image.damageThread,pos);
}
}
ConsoleMethod( ShapeBase, setDamageBloodPos, void, 4, 4, "(int slot, float pos)")
{
int imageSlot = dAtoi(argv[2]);
F32 pos = dAtof(argv[3]);
if (imageSlot >= 0 && imageSlot < ShapeBase::MaxMountedImages && pos >= 0.0)
object->setDamageBloodPos(imageSlot, pos);
}
// < pg damage bloodNow you are set up to see the ShapeBaseImage change it's ifl as you determine.
Here is an example of some script to cheat and see the texture change. Be aware that each time to remount the image it will reset the ifl position to 0 so you'll need to maintian the current position and update the positiion as you see fit.
12) In YOURGAMENAME/client/scripts/default.bind.cs Add
// > pg damage blood
MoveMap.bind(keyboard, "ctrl-alt 1", CheatDamageBlood);
function CheatDamageBlood(%val)
{
if(%val)
commandToServer('CheatDamageBlood');
}
// < pg damage blood13) In YOURGAMENAME/server/scripts/commands.cs ADD
// < pg damage blood
function serverCmdCheatDamageBlood(%client)
{
%player = %client.player;
%weapon = %player.getMountedImage($WeaponSlot);
%BloodPos = %player.BloodPos;
if(%BloodPos $= "")
%BloodPos = 0;
%BloodPos = %BloodPos + 0.25;
if(%BloodPos > 1)
%BloodPos = 1;
echo("blood pos" SPC %BloodPos SPC %slot);
%player.setDamageBloodPos($WeaponSlot, %BloodPos);
%player.BloodPos = %BloodPos;
}
// < pg damage bloodNow mount the ShapeBaseImage and hit "ctrl + alt 1" to watch the texture change, of course, in your game you probably want to tie this code into the Armor::onDamage() function, but that is your call.
About the author
#2
08/03/2008 (7:26 pm)
Will it work with TGE ?
#3
08/05/2008 (8:23 pm)
Charin - yes this works with both TGE and TGEA
#4
09/30/2008 (12:33 pm)
Excellet idea, and perfect for what I want to do :) Also gives me some info on adding new sequences to images, which is probably something I'll be doing in the future...
#5
03/09/2009 (5:15 am)
Does this work in TGEA 1.8.1? 
Torque Owner Erik Madison