Merge branch 'healthtexthud' of https://github.com/T3DCE/CE-OSLab into T3DCE-healthtexthud

This commit is contained in:
DavidWyand-GG 2012-11-15 11:04:09 -05:00
commit fa1a0124a9
13 changed files with 261 additions and 246 deletions

View file

@ -0,0 +1,200 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A gui control that displays health or energy information. Based upon the
// stock healthBar control but rewritten by M.Hall to display a numerical value.
// ----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/core/guiControl.h"
#include "console/consoleTypes.h"
#include "T3D/gameBase/gameConnection.h"
#include "T3D/shapeBase.h"
#include "gfx/gfxDrawUtil.h"
class GuiHealthTextHud : public GuiControl
{
typedef GuiControl Parent;
bool mShowFrame;
bool mShowFill;
bool mShowEnergy;
bool mShowTrueHealth;
ColorF mFillColor;
ColorF mFrameColor;
ColorF mTextColor;
ColorF mWarnColor;
F32 mWarnLevel;
F32 mPulseThreshold;
S32 mPulseRate;
F32 mValue;
public:
GuiHealthTextHud();
void onRender(Point2I, const RectI &);
static void initPersistFields();
DECLARE_CONOBJECT(GuiHealthTextHud);
DECLARE_CATEGORY("Gui Game");
DECLARE_DESCRIPTION("Shows the damage or energy level of the current\n"
"PlayerObjectType control object as a numerical text display.");
};
// ----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiHealthTextHud);
ConsoleDocClass(GuiHealthTextHud,
"@brief Shows the health or energy value of the current PlayerObjectType control object.\n\n"
"This gui can be configured to display either the health or energy value of the current Player Object. "
"It can use an alternate display color if the health or drops below a set value. "
"It can also be set to pulse if the health or energy drops below a set value. "
"This control only works if a server connection exists and it's control object "
"is a PlayerObjectType. If either of these requirements is false, the control is not rendered.\n\n"
"@tsexample\n"
"\n new GuiHealthTextHud()"
"{\n"
" fillColor = \"0.0 0.0 0.0 0.5\"; // Fills with a transparent black color\n"
" frameColor = \"1.0 1.0 1.0 1.0\"; // Solid white frame color\n"
" textColor = \"0.0 1.0 0.0 1.0\" // Solid green text color\n"
" warningColor = \"1.0 0.0 0.0 1.0\"; // Solid red color, used when damaged\n"
" showFill = \"true\";\n"
" showFrame = \"true\";\n"
" showTrueValue = \"false\";\n"
" showEnergy = \"false\";\n"
" warnThreshold = \"50\";\n"
" pulseThreshold = \"25\";\n"
" pulseRate = \"500\";\n"
" profile = \"GuiBigTextProfile\";\n"
"};\n"
"@endtsexample\n\n"
"@ingroup GuiGame\n"
);
GuiHealthTextHud::GuiHealthTextHud()
{
mShowFrame = mShowFill = true;
mShowEnergy = false;
mShowTrueHealth = false;
mFillColor.set(0, 0, 0, 0.5);
mFrameColor.set(1, 1, 1, 1);
mTextColor.set(0, 1, 0, 1);
mWarnColor.set(1, 0, 0, 1);
mWarnLevel = 50.0f;
mPulseThreshold = 25.0f;
mPulseRate = 0;
mValue = 0.2f;
}
void GuiHealthTextHud::initPersistFields()
{
addGroup("Colors");
addField("fillColor", TypeColorF, Offset(mFillColor, GuiHealthTextHud), "Color for the background of the control.");
addField("frameColor", TypeColorF, Offset(mFrameColor, GuiHealthTextHud), "Color for the control's frame.");
addField("textColor", TypeColorF, Offset(mTextColor, GuiHealthTextHud), "Color for the text on this control.");
addField("warningColor", TypeColorF, Offset(mWarnColor, GuiHealthTextHud), "Color for the text when health is low.");
endGroup("Colors");
addGroup("View");
addField("showFill", TypeBool, Offset(mShowFill, GuiHealthTextHud), "If true, draw the background.");
addField("showFrame", TypeBool, Offset(mShowFrame, GuiHealthTextHud), "If true, draw the frame.");
addField("showTrueValue", TypeBool, Offset(mShowTrueHealth, GuiHealthTextHud), "If true, we don't hardcode maxHealth to 100.");
addField("showEnergy", TypeBool, Offset(mShowEnergy, GuiHealthTextHud), "If true, display the energy value rather than the damage value.");
endGroup("View");
addGroup("Alert");
addField("warnThreshold", TypeF32, Offset(mWarnLevel, GuiHealthTextHud), "The health level at which to use the warningColor.");
addField("pulseThreshold", TypeF32, Offset(mPulseThreshold, GuiHealthTextHud), "Health level at which to begin pulsing.");
addField("pulseRate", TypeS32, Offset(mPulseRate, GuiHealthTextHud), "Speed at which the control will pulse.");
endGroup("Alert");
Parent::initPersistFields();
}
// ----------------------------------------------------------------------------
void GuiHealthTextHud::onRender(Point2I offset, const RectI &updateRect)
{
// Must have a connection and player control object
GameConnection* conn = GameConnection::getConnectionToServer();
if (!conn)
return;
ShapeBase* control = dynamic_cast<ShapeBase*>(conn->getControlObject());
if (!control || !(control->getTypeMask() & PlayerObjectType))
return;
// Just grab the damage/energy right off the control object.
// Damage value 0 = no damage (full health).
if(mShowEnergy)
mValue = control->getEnergyLevel();
else
{
if (mShowTrueHealth)
mValue = control->getMaxDamage() - control->getDamageLevel();
else
mValue = 100 - (100 * control->getDamageValue());
}
// If enabled draw background first
if (mShowFill)
GFX->getDrawUtil()->drawRectFill(updateRect, mFillColor);
// Prepare text and center it
S32 val = (S32)mValue;
char buf[256];
dSprintf(buf, sizeof(buf), "%d", val);
offset.x += (getBounds().extent.x - mProfile->mFont->getStrWidth((const UTF8 *)buf)) / 2;
offset.y += (getBounds().extent.y - mProfile->mFont->getHeight()) / 2;
ColorF tColor = mTextColor;
// If warning level is exceeded switch to warning color
if(mValue < mWarnLevel)
{
tColor = mWarnColor;
// If the pulseRate is set then pulse the text if health is below the threshold
if (mPulseRate != 0 && mValue < mPulseThreshold)
{
U32 time = Platform::getVirtualMilliseconds();
F32 alpha = 2.0f * F32(time % mPulseRate) / F32(mPulseRate);
tColor.alpha = (alpha > 1.0f)? 2.0f - alpha: alpha;
}
}
GFX->getDrawUtil()->setBitmapModulation(tColor);
GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);
GFX->getDrawUtil()->clearBitmapModulation();
// If enabled draw the border last
if (mShowFrame)
GFX->getDrawUtil()->drawRect(updateRect, mFrameColor);
}

View file

@ -1632,6 +1632,11 @@ F32 ShapeBase::getDamageValue()
return mDamage / mDataBlock->maxDamage;
}
F32 ShapeBase::getMaxDamage()
{
return mDataBlock->maxDamage;
}
void ShapeBase::updateDamageLevel()
{
if (mDamageThread) {
@ -4534,6 +4539,13 @@ DefineEngineMethod( ShapeBase, getDamagePercent, F32, (),,
{
return object->getDamageValue();
}
DefineEngineMethod(ShapeBase, getMaxDamage, F32, (),,
"Get the object's maxDamage level.\n"
"@return datablock.maxDamage\n")
{
return object->getMaxDamage();
}
DefineEngineMethod( ShapeBase, setDamageState, bool, ( const char* state ),,
"@brief Set the object's damage state.\n\n"

View file

@ -1265,6 +1265,9 @@ public:
///
/// @return Damage factor, between 0.0 - 1.0
F32 getDamageValue();
/// Returns the datablock.maxDamage value
F32 getMaxDamage();
/// Returns the rate at which the object regenerates damage
F32 getRepairRate() { return mRepairRate; }

View file

@ -240,57 +240,31 @@
canSaveDynamicFields = "0";
};
};
new GuiBitmapBorderCtrl(HealthHUD) {
isContainer = "0";
Profile = "ChatHudBorderProfile";
HorizSizing = "right";
VertSizing = "top";
position = "6 693";
Extent = "72 72";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
tooltipprofile = "GuiToolTipProfile";
new GuiHealthTextHud() {
fillColor = "0 0 0 0.65";
frameColor = "0 0 0 1";
textColor = "1 1 1 1";
warningColor = "1 0 0 1";
showFill = "1";
showFrame = "1";
showTrueValue = "0";
showEnergy = "0";
warnThreshold = "25";
pulseThreshold = "15";
pulseRate = "750";
position = "5 693";
extent = "72 72";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "top";
profile = "GuiBigTextProfile";
visible = "1";
active = "1";
tooltipProfile = "GuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
canSave = "1";
canSaveDynamicFields = "0";
new GuiBitmapCtrl() {
bitmap = "core/art/gui/images/hudfill.png";
wrap = "0";
isContainer = "0";
Profile = "GuiDefaultProfile";
HorizSizing = "width";
VertSizing = "height";
position = "8 8";
Extent = "56 56";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
tooltipprofile = "GuiToolTipProfile";
hovertime = "1000";
canSaveDynamicFields = "0";
};
new GuiTextCtrl(numericalHealthHUD) {
maxLength = "255";
Margin = "0 0 0 0";
Padding = "0 0 0 0";
AnchorTop = "0";
AnchorBottom = "0";
AnchorLeft = "0";
AnchorRight = "0";
isContainer = "0";
Profile = "NumericHealthProfile";
HorizSizing = "center";
VertSizing = "center";
position = "0 22";
Extent = "72 32";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
tooltipprofile = "GuiToolTipProfile";
hovertime = "1000";
canSaveDynamicFields = "0";
};
};
new GuiBitmapCtrl(OOBSign) {
bitmap = "art/gui/playHud/missionAreaWarning.png";

View file

@ -45,26 +45,6 @@ function clientCmdSyncClock(%time)
// or when a client joins a game in progress.
}
//-----------------------------------------------------------------------------
// Numerical Health Counter
//-----------------------------------------------------------------------------
function clientCmdSetNumericalHealthHUD(%curHealth)
{
// Skip if the hud is missing.
if (!isObject(numericalHealthHUD))
return;
// The server has sent us our current health, display it on the HUD
numericalHealthHUD.setValue(%curHealth);
// Ensure the HUD is set to visible while we have health / are alive
if (%curHealth)
HealthHUD.setVisible(true);
else
HealthHUD.setVisible(false);
}
//-----------------------------------------------------------------------------
// Damage Direction Indicator
//-----------------------------------------------------------------------------

View file

@ -676,9 +676,6 @@ function GameCore::onDeath(%game, %client, %sourceObject, %sourceClient, %damage
// Clear out the name on the corpse
%client.player.setShapeName("");
// Update the numerical Health HUD
%client.player.updateHealth();
// Switch the client over to the death cam and unhook the player object.
if (isObject(%client.camera) && isObject(%client.player))
{

View file

@ -36,9 +36,6 @@ function HealthPatch::onCollision(%this, %obj, %col)
{
%col.applyRepair(%this.repairAmount);
// Update the Health GUI while repairing
%this.doHealthUpdate(%col);
%obj.respawn();
if (%col.client)
messageClient(%col.client, 'MsgHealthPatchUsed', '\c2Health Patch Applied');
@ -46,28 +43,6 @@ function HealthPatch::onCollision(%this, %obj, %col)
}
}
function HealthPatch::doHealthUpdate(%this, %obj)
{
// Would be better to add a onRepair() callback to shapeBase.cpp in order to
// prevent any excess/unneccesary schedules from this. But for the time
// being....
// This is just a rough timer to update the Health HUD every 250 ms. From
// my tests a large health pack will fully heal a player from 10 health in
// 36 iterations (ie. 9 seconds). If either the scheduling time, the repair
// amount, or the repair rate is changed then the healthTimer counter should
// be changed also.
if (%obj.healthTimer < 40) // 40 = 10 seconds at 1 iteration per 250 ms.
{
%obj.UpdateHealth();
%this.schedule(250, doHealthUpdate, %obj);
%obj.healthTimer++;
}
else
%obj.healthTimer = 0;
}
function ShapeBase::tossPatch(%this)
{
//error("ShapeBase::tossPatch(" SPC %this.client.nameBase SPC ")");

View file

@ -53,12 +53,6 @@ function Armor::onAdd(%this, %obj)
// Default dynamic armor stats
%obj.setRechargeRate(%this.rechargeRate);
%obj.setRepairRate(0);
// Set the numerical Health HUD
//%obj.updateHealth();
// Calling updateHealth() must be delayed now... for some reason
%obj.schedule(50, "updateHealth");
}
function Armor::onRemove(%this, %obj)
@ -227,9 +221,6 @@ function Armor::damage(%this, %obj, %sourceObject, %position, %damage, %damageTy
%location = "Body";
// Update the numerical Health HUD
%obj.updateHealth();
// Deal with client callbacks here because we don't have this
// information in the onDamage or onDisable methods
%client = %obj.client;
@ -435,23 +426,6 @@ function Player::playPain(%this)
}
// ----------------------------------------------------------------------------
// Numerical Health Counter
// ----------------------------------------------------------------------------
function Player::updateHealth(%player)
{
//echo("\c4Player::updateHealth() -> Player Health changed, updating HUD!");
// Calcualte player health
%maxDamage = %player.getDatablock().maxDamage;
%damageLevel = %player.getDamageLevel();
%curHealth = %maxDamage - %damageLevel;
%curHealth = mceil(%curHealth);
// Send the player object's current health level to the client, where it
// will Update the numericalHealth HUD.
commandToClient(%player.client, 'setNumericalHealthHUD', %curHealth);
}
function Player::setDamageDirection(%player, %sourceObject, %damagePos)
{

View file

@ -240,57 +240,31 @@
canSaveDynamicFields = "0";
};
};
new GuiBitmapBorderCtrl(HealthHUD) {
isContainer = "0";
Profile = "ChatHudBorderProfile";
HorizSizing = "right";
VertSizing = "top";
position = "6 693";
Extent = "72 72";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
tooltipprofile = "GuiToolTipProfile";
new GuiHealthTextHud() {
fillColor = "0 0 0 0.65";
frameColor = "0 0 0 1";
textColor = "1 1 1 1";
warningColor = "1 0 0 1";
showFill = "1";
showFrame = "1";
showTrueValue = "0";
showEnergy = "0";
warnThreshold = "25";
pulseThreshold = "15";
pulseRate = "750";
position = "5 693";
extent = "72 72";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "top";
profile = "GuiBigTextProfile";
visible = "1";
active = "1";
tooltipProfile = "GuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
canSave = "1";
canSaveDynamicFields = "0";
new GuiBitmapCtrl() {
bitmap = "core/art/gui/images/hudfill.png";
wrap = "0";
isContainer = "0";
Profile = "GuiDefaultProfile";
HorizSizing = "width";
VertSizing = "height";
position = "8 8";
Extent = "56 56";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
tooltipprofile = "GuiToolTipProfile";
hovertime = "1000";
canSaveDynamicFields = "0";
};
new GuiTextCtrl(numericalHealthHUD) {
maxLength = "255";
Margin = "0 0 0 0";
Padding = "0 0 0 0";
AnchorTop = "0";
AnchorBottom = "0";
AnchorLeft = "0";
AnchorRight = "0";
isContainer = "0";
Profile = "NumericHealthProfile";
HorizSizing = "center";
VertSizing = "center";
position = "0 22";
Extent = "72 32";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
tooltipprofile = "GuiToolTipProfile";
hovertime = "1000";
canSaveDynamicFields = "0";
};
};
new GuiBitmapCtrl(OOBSign) {
bitmap = "art/gui/playHud/missionAreaWarning.png";

View file

@ -45,26 +45,6 @@ function clientCmdSyncClock(%time)
// or when a client joins a game in progress.
}
//-----------------------------------------------------------------------------
// Numerical Health Counter
//-----------------------------------------------------------------------------
function clientCmdSetNumericalHealthHUD(%curHealth)
{
// Skip if the hud is missing.
if (!isObject(numericalHealthHUD))
return;
// The server has sent us our current health, display it on the HUD
numericalHealthHUD.setValue(%curHealth);
// Ensure the HUD is set to visible while we have health / are alive
if (%curHealth)
HealthHUD.setVisible(true);
else
HealthHUD.setVisible(false);
}
//-----------------------------------------------------------------------------
// Damage Direction Indicator
//-----------------------------------------------------------------------------

View file

@ -676,9 +676,6 @@ function GameCore::onDeath(%game, %client, %sourceObject, %sourceClient, %damage
// Clear out the name on the corpse
%client.player.setShapeName("");
// Update the numerical Health HUD
%client.player.updateHealth();
// Switch the client over to the death cam and unhook the player object.
if (isObject(%client.camera) && isObject(%client.player))
{

View file

@ -36,9 +36,6 @@ function HealthPatch::onCollision(%this, %obj, %col)
{
%col.applyRepair(%this.repairAmount);
// Update the Health GUI while repairing
%this.doHealthUpdate(%col);
%obj.respawn();
if (%col.client)
messageClient(%col.client, 'MsgHealthPatchUsed', '\c2Health Patch Applied');
@ -46,28 +43,6 @@ function HealthPatch::onCollision(%this, %obj, %col)
}
}
function HealthPatch::doHealthUpdate(%this, %obj)
{
// Would be better to add a onRepair() callback to shapeBase.cpp in order to
// prevent any excess/unneccesary schedules from this. But for the time
// being....
// This is just a rough timer to update the Health HUD every 250 ms. From
// my tests a large health pack will fully heal a player from 10 health in
// 36 iterations (ie. 9 seconds). If either the scheduling time, the repair
// amount, or the repair rate is changed then the healthTimer counter should
// be changed also.
if (%obj.healthTimer < 40) // 40 = 10 seconds at 1 iteration per 250 ms.
{
%obj.UpdateHealth();
%this.schedule(250, doHealthUpdate, %obj);
%obj.healthTimer++;
}
else
%obj.healthTimer = 0;
}
function ShapeBase::tossPatch(%this)
{
//error("ShapeBase::tossPatch(" SPC %this.client.nameBase SPC ")");

View file

@ -53,12 +53,6 @@ function Armor::onAdd(%this, %obj)
// Default dynamic armor stats
%obj.setRechargeRate(%this.rechargeRate);
%obj.setRepairRate(0);
// Set the numerical Health HUD
//%obj.updateHealth();
// Calling updateHealth() must be delayed now... for some reason
%obj.schedule(50, "updateHealth");
}
function Armor::onRemove(%this, %obj)
@ -227,9 +221,6 @@ function Armor::damage(%this, %obj, %sourceObject, %position, %damage, %damageTy
%location = "Body";
// Update the numerical Health HUD
%obj.updateHealth();
// Deal with client callbacks here because we don't have this
// information in the onDamage or onDisable methods
%client = %obj.client;
@ -435,23 +426,6 @@ function Player::playPain(%this)
}
// ----------------------------------------------------------------------------
// Numerical Health Counter
// ----------------------------------------------------------------------------
function Player::updateHealth(%player)
{
//echo("\c4Player::updateHealth() -> Player Health changed, updating HUD!");
// Calcualte player health
%maxDamage = %player.getDatablock().maxDamage;
%damageLevel = %player.getDamageLevel();
%curHealth = %maxDamage - %damageLevel;
%curHealth = mceil(%curHealth);
// Send the player object's current health level to the client, where it
// will Update the numericalHealth HUD.
commandToClient(%player.client, 'setNumericalHealthHUD', %curHealth);
}
function Player::setDamageDirection(%player, %sourceObject, %damagePos)
{