tge/engine/game/vehicles/flyingVehicle.cc
2017-04-17 06:17:10 -06:00

735 lines
23 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "game/vehicles/flyingVehicle.h"
#include "platform/platform.h"
#include "dgl/dgl.h"
#include "game/game.h"
#include "math/mMath.h"
#include "console/simBase.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "collision/clippedPolyList.h"
#include "collision/planeExtractor.h"
#include "game/moveManager.h"
#include "core/bitStream.h"
#include "core/dnet.h"
#include "game/gameConnection.h"
#include "ts/tsShapeInstance.h"
#include "game/fx/particleEngine.h"
#include "audio/audioDataBlock.h"
#include "game/missionArea.h"
//----------------------------------------------------------------------------
const static U32 sCollisionMoveMask = (TerrainObjectType | InteriorObjectType |
WaterObjectType | PlayerObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType | StaticTSObjectType);
static U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
static U32 sClientCollisionMask = sCollisionMoveMask;
static F32 sFlyingVehicleGravity = -20;
// Sound
static F32 sIdleEngineVolume = 0.2;
//
const char* FlyingVehicle::sJetSequence[FlyingVehicle::JetAnimCount] =
{
"activateBack",
"maintainBack",
"activateBot",
"maintainBot",
};
const char* FlyingVehicleData::sJetNode[FlyingVehicleData::MaxJetNodes] =
{
"JetNozzle0", // Thrust Forward
"JetNozzle1",
"JetNozzleX", // Thrust Backward
"JetNozzleX",
"JetNozzle2", // Thrust Downward
"JetNozzle3",
"contrail0", // Trail
"contrail1",
"contrail2",
"contrail3",
};
// Convert thrust direction into nodes & emitters
FlyingVehicle::JetActivation FlyingVehicle::sJetActivation[NumThrustDirections] = {
{ FlyingVehicleData::ForwardJetNode, FlyingVehicleData::ForwardJetEmitter },
{ FlyingVehicleData::BackwardJetNode, FlyingVehicleData::BackwardJetEmitter },
{ FlyingVehicleData::DownwardJetNode, FlyingVehicleData::DownwardJetEmitter },
};
//----------------------------------------------------------------------------
IMPLEMENT_CO_DATABLOCK_V1(FlyingVehicleData);
FlyingVehicleData::FlyingVehicleData()
{
maneuveringForce = 0;
horizontalSurfaceForce = 0;
verticalSurfaceForce = 0;
autoInputDamping = 1;
steeringForce = 1;
steeringRollForce = 1;
rollForce = 1;
autoAngularForce = 0;
rotationalDrag = 0;
autoLinearForce = 0;
maxAutoSpeed = 0;
hoverHeight = 2;
createHoverHeight = 2;
maxSteeringAngle = M_PI;
minTrailSpeed = 1;
maxSpeed = 100;
for (S32 k = 0; k < MaxJetNodes; k++)
jetNode[k] = -1;
for (S32 j = 0; j < MaxJetEmitters; j++)
jetEmitter[j] = 0;
for (S32 i = 0; i < MaxSounds; i++)
sound[i] = 0;
vertThrustMultiple = 1.0;
}
bool FlyingVehicleData::preload(bool server, char errorBuffer[256])
{
if (!Parent::preload(server, errorBuffer))
return false;
TSShapeInstance* si = new TSShapeInstance(shape,false);
// Resolve objects transmitted from server
if (!server) {
for (S32 i = 0; i < MaxSounds; i++)
if (sound[i])
Sim::findObject(SimObjectId(sound[i]),sound[i]);
for (S32 j = 0; j < MaxJetEmitters; j++)
if (jetEmitter[j])
Sim::findObject(SimObjectId(jetEmitter[j]),jetEmitter[j]);
}
// Extract collision planes from shape collision detail level
if (collisionDetails[0] != -1) {
MatrixF imat(1);
PlaneExtractorPolyList polyList;
polyList.mPlaneList = &rigidBody.mPlaneList;
polyList.setTransform(&imat, Point3F(1,1,1));
si->animate(collisionDetails[0]);
si->buildPolyList(&polyList,collisionDetails[0]);
}
// Resolve jet nodes
for (S32 j = 0; j < MaxJetNodes; j++)
jetNode[j] = shape->findNode(sJetNode[j]);
//
maxSpeed = maneuveringForce / minDrag;
delete si;
return true;
}
void FlyingVehicleData::initPersistFields()
{
Parent::initPersistFields();
addField("jetSound", TypeAudioProfilePtr, Offset(sound[JetSound], FlyingVehicleData));
addField("engineSound", TypeAudioProfilePtr, Offset(sound[EngineSound], FlyingVehicleData));
addField("maneuveringForce", TypeF32, Offset(maneuveringForce, FlyingVehicleData));
addField("horizontalSurfaceForce", TypeF32, Offset(horizontalSurfaceForce, FlyingVehicleData));
addField("verticalSurfaceForce", TypeF32, Offset(verticalSurfaceForce, FlyingVehicleData));
addField("autoInputDamping", TypeF32, Offset(autoInputDamping, FlyingVehicleData));
addField("steeringForce", TypeF32, Offset(steeringForce, FlyingVehicleData));
addField("steeringRollForce", TypeF32, Offset(steeringRollForce, FlyingVehicleData));
addField("rollForce", TypeF32, Offset(rollForce, FlyingVehicleData));
addField("autoAngularForce", TypeF32, Offset(autoAngularForce, FlyingVehicleData));
addField("rotationalDrag", TypeF32, Offset(rotationalDrag, FlyingVehicleData));
addField("autoLinearForce", TypeF32, Offset(autoLinearForce, FlyingVehicleData));
addField("maxAutoSpeed", TypeF32, Offset(maxAutoSpeed, FlyingVehicleData));
addField("hoverHeight", TypeF32, Offset(hoverHeight, FlyingVehicleData));
addField("createHoverHeight", TypeF32, Offset(createHoverHeight, FlyingVehicleData));
addField("forwardJetEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[ForwardJetEmitter], FlyingVehicleData));
addField("backwardJetEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[BackwardJetEmitter], FlyingVehicleData));
addField("downJetEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[DownwardJetEmitter], FlyingVehicleData));
addField("trailEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[TrailEmitter], FlyingVehicleData));
addField("minTrailSpeed", TypeF32, Offset(minTrailSpeed, FlyingVehicleData));
addField("vertThrustMultiple", TypeF32, Offset(vertThrustMultiple, FlyingVehicleData));
}
void FlyingVehicleData::packData(BitStream* stream)
{
Parent::packData(stream);
for (S32 i = 0; i < MaxSounds; i++)
{
if (stream->writeFlag(sound[i]))
{
SimObjectId writtenId = packed ? SimObjectId(sound[i]) : sound[i]->getId();
stream->writeRangedU32(writtenId, DataBlockObjectIdFirst, DataBlockObjectIdLast);
}
}
for (S32 j = 0; j < MaxJetEmitters; j++)
{
if (stream->writeFlag(jetEmitter[j]))
{
SimObjectId writtenId = packed ? SimObjectId(jetEmitter[j]) : jetEmitter[j]->getId();
stream->writeRangedU32(writtenId, DataBlockObjectIdFirst,DataBlockObjectIdLast);
}
}
stream->write(maneuveringForce);
stream->write(horizontalSurfaceForce);
stream->write(verticalSurfaceForce);
stream->write(autoInputDamping);
stream->write(steeringForce);
stream->write(steeringRollForce);
stream->write(rollForce);
stream->write(autoAngularForce);
stream->write(rotationalDrag);
stream->write(autoLinearForce);
stream->write(maxAutoSpeed);
stream->write(hoverHeight);
stream->write(createHoverHeight);
stream->write(minTrailSpeed);
stream->write(vertThrustMultiple);
}
void FlyingVehicleData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
for (S32 i = 0; i < MaxSounds; i++) {
sound[i] = NULL;
if (stream->readFlag())
sound[i] = (AudioProfile*)stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast);
}
for (S32 j = 0; j < MaxJetEmitters; j++) {
jetEmitter[j] = NULL;
if (stream->readFlag())
jetEmitter[j] = (ParticleEmitterData*)stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast);
}
stream->read(&maneuveringForce);
stream->read(&horizontalSurfaceForce);
stream->read(&verticalSurfaceForce);
stream->read(&autoInputDamping);
stream->read(&steeringForce);
stream->read(&steeringRollForce);
stream->read(&rollForce);
stream->read(&autoAngularForce);
stream->read(&rotationalDrag);
stream->read(&autoLinearForce);
stream->read(&maxAutoSpeed);
stream->read(&hoverHeight);
stream->read(&createHoverHeight);
stream->read(&minTrailSpeed);
stream->read(&vertThrustMultiple);
}
//----------------------------------------------------------------------------
IMPLEMENT_CO_NETOBJECT_V1(FlyingVehicle);
FlyingVehicle::FlyingVehicle()
{
mSteering.set(0,0);
mThrottle = 0;
mJetting = false;
mJetSound = 0;
mEngineSound = 0;
mBackMaintainOn = false;
mBottomMaintainOn = false;
createHeightOn = false;
for (S32 i = 0; i < JetAnimCount; i++)
mJetThread[i] = 0;
}
FlyingVehicle::~FlyingVehicle()
{
if (mJetSound)
alxStop(mJetSound);
if (mEngineSound)
alxStop(mEngineSound);
}
//----------------------------------------------------------------------------
bool FlyingVehicle::onAdd()
{
if(!Parent::onAdd())
return false;
addToScene();
if (isServerObject())
scriptOnAdd();
return true;
}
bool FlyingVehicle::onNewDataBlock(GameBaseData* dptr)
{
mDataBlock = dynamic_cast<FlyingVehicleData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
return false;
// Sounds
if (mJetSound) {
alxStop(mJetSound);
mJetSound = 0;
}
if (mEngineSound) {
alxStop(mEngineSound);
mEngineSound = 0;
}
if (isGhost()) {
if (mDataBlock->sound[FlyingVehicleData::EngineSound])
mEngineSound = alxPlay(mDataBlock->sound[FlyingVehicleData::EngineSound], &getTransform());
}
// Jet Sequences
for (S32 i = 0; i < JetAnimCount; i++) {
TSShape const* shape = mShapeInstance->getShape();
mJetSeq[i] = shape->findSequence(sJetSequence[i]);
if (mJetSeq[i] != -1) {
if (i == BackActivate || i == BottomActivate) {
mJetThread[i] = mShapeInstance->addThread();
mShapeInstance->setSequence(mJetThread[i],mJetSeq[i],0);
mShapeInstance->setTimeScale(mJetThread[i],0);
}
}
else
mJetThread[i] = 0;
}
scriptOnNewDataBlock();
return true;
}
void FlyingVehicle::onRemove()
{
scriptOnRemove();
removeFromScene();
Parent::onRemove();
}
//----------------------------------------------------------------------------
void FlyingVehicle::advanceTime(F32 dt)
{
Parent::advanceTime(dt);
updateEngineSound(1);
updateJet(dt);
}
//----------------------------------------------------------------------------
void FlyingVehicle::updateMove(const Move* move)
{
Parent::updateMove(move);
if (move == &NullMove)
mSteering.set(0,0);
F32 speed = mRigid.linVelocity.len();
if (speed < mDataBlock->maxAutoSpeed)
mSteering *= mDataBlock->autoInputDamping;
// Check the mission area to get the factor for the flight ceiling
MissionArea * obj = dynamic_cast<MissionArea*>(Sim::findObject("MissionArea"));
mCeilingFactor = 1.0f;
if (obj != NULL)
{
F32 flightCeiling = obj->getFlightCeiling();
F32 ceilingRange = obj->getFlightCeilingRange();
if (mRigid.linPosition.z > flightCeiling)
{
// Thrust starts to fade at the ceiling, and is 0 at ceil + range
if (ceilingRange == 0)
{
mCeilingFactor = 0;
}
else
{
mCeilingFactor = 1.0f - ((mRigid.linPosition.z - flightCeiling) / (flightCeiling + ceilingRange));
if (mCeilingFactor < 0.0f)
mCeilingFactor = 0.0f;
}
}
}
mThrust.x = move->x;
mThrust.y = move->y;
if (mThrust.y != 0.0f)
if (mThrust.y > 0)
mThrustDirection = ThrustForward;
else
mThrustDirection = ThrustBackward;
else
mThrustDirection = ThrustDown;
if (mCeilingFactor != 1.0f)
mJetting = false;
}
//----------------------------------------------------------------------------
Point3F JetOffset[4] =
{
Point3F(-1,-1,0),
Point3F(+1,-1,0),
Point3F(-1,+1,0),
Point3F(+1,+1,0)
};
void FlyingVehicle::updateForces(F32 /*dt*/)
{
MatrixF currPosMat;
mRigid.getTransform(&currPosMat);
mRigid.atRest = false;
Point3F massCenter;
currPosMat.mulP(mDataBlock->massCenter,&massCenter);
Point3F xv,yv,zv;
currPosMat.getColumn(0,&xv);
currPosMat.getColumn(1,&yv);
currPosMat.getColumn(2,&zv);
F32 speed = mRigid.linVelocity.len();
Point3F force = Point3F(0, 0, sFlyingVehicleGravity * mRigid.mass * mGravityMod);
Point3F torque = Point3F(0, 0, 0);
// Drag at any speed
force -= mRigid.linVelocity * mDataBlock->minDrag;
torque -= mRigid.angMomentum * mDataBlock->rotationalDrag;
// Auto-stop at low speeds
if (speed < mDataBlock->maxAutoSpeed) {
F32 autoScale = 1 - speed / mDataBlock->maxAutoSpeed;
// Gyroscope
F32 gf = mDataBlock->autoAngularForce * autoScale;
torque -= xv * gf * mDot(yv,Point3F(0,0,1));
// Manuevering jets
F32 sf = mDataBlock->autoLinearForce * autoScale;
force -= yv * sf * mDot(yv, mRigid.linVelocity);
force -= xv * sf * mDot(xv, mRigid.linVelocity);
}
// Hovering Jet
F32 vf = -sFlyingVehicleGravity * mRigid.mass * mGravityMod;
F32 h = getHeight();
if (h <= 1) {
if (h > 0) {
vf -= vf * h * 0.1;
} else {
vf += mDataBlock->jetForce * -h;
}
}
force += zv * vf;
// Damping "surfaces"
force -= xv * speed * mDot(xv,mRigid.linVelocity) * mDataBlock->horizontalSurfaceForce;
force -= zv * speed * mDot(zv,mRigid.linVelocity) * mDataBlock->verticalSurfaceForce;
// Turbo Jet
if (mJetting) {
if (mThrustDirection == ThrustForward)
force += yv * mDataBlock->jetForce * mCeilingFactor;
else if (mThrustDirection == ThrustBackward)
force -= yv * mDataBlock->jetForce * mCeilingFactor;
else
force += zv * mDataBlock->jetForce * mDataBlock->vertThrustMultiple * mCeilingFactor;
}
// Maneuvering jets
force += yv * (mThrust.y * mDataBlock->maneuveringForce * mCeilingFactor);
force += xv * (mThrust.x * mDataBlock->maneuveringForce * mCeilingFactor);
// Steering
Point2F steering;
steering.x = mSteering.x / mDataBlock->maxSteeringAngle;
steering.x *= mFabs(steering.x);
steering.y = mSteering.y / mDataBlock->maxSteeringAngle;
steering.y *= mFabs(steering.y);
torque -= xv * steering.y * mDataBlock->steeringForce;
torque -= zv * steering.x * mDataBlock->steeringForce;
// Roll
torque += yv * steering.x * mDataBlock->steeringRollForce;
F32 ar = mDataBlock->autoAngularForce * mDot(xv,Point3F(0,0,1));
ar -= mDataBlock->rollForce * mDot(xv, mRigid.linVelocity);
torque += yv * ar;
// Add in force from physical zones...
force += mAppliedForce;
// Container buoyancy & drag
force -= Point3F(0, 0, 1) * (mBuoyancy * sFlyingVehicleGravity * mRigid.mass * mGravityMod);
force -= mRigid.linVelocity * mDrag;
//
mRigid.force = force;
mRigid.torque = torque;
}
//----------------------------------------------------------------------------
F32 FlyingVehicle::getHeight()
{
Point3F sp,ep;
RayInfo collision;
const F32 height = (createHeightOn) ? mDataBlock->createHoverHeight : mDataBlock->hoverHeight;
const F32 r = 10 + height;
getTransform().getColumn(3, &sp);
ep.x = sp.x;
ep.y = sp.y;
ep.z = sp.z - r;
disableCollision();
if (!mContainer->castRay(sp, ep, sCollisionMoveMask, &collision))
collision.t = 1;
enableCollision();
return (r * collision.t - height) / 10;
}
//----------------------------------------------------------------------------
U32 FlyingVehicle::getCollisionMask()
{
if (isServerObject())
return sServerCollisionMask;
else
return sClientCollisionMask;
}
//----------------------------------------------------------------------------
void FlyingVehicle::updateEngineSound(F32 level)
{
if (mEngineSound) {
alxSourceMatrixF(mEngineSound, &getTransform());
alxSourcef(mEngineSound, AL_GAIN_LINEAR, level);
}
}
void FlyingVehicle::updateJet(F32 dt)
{
// Thrust Animation threads
// Back
if (mJetSeq[BackActivate] >=0 ) {
if(!mBackMaintainOn || mThrustDirection != ThrustForward) {
if(mBackMaintainOn) {
mShapeInstance->setPos(mJetThread[BackActivate], 1);
mShapeInstance->destroyThread(mJetThread[BackMaintain]);
mBackMaintainOn = false;
}
mShapeInstance->setTimeScale(mJetThread[BackActivate],
(mThrustDirection == ThrustForward)? 1: -1);
mShapeInstance->advanceTime(dt,mJetThread[BackActivate]);
}
if(mJetSeq[BackMaintain] >= 0 && !mBackMaintainOn &&
mShapeInstance->getPos(mJetThread[BackActivate]) >= 1.0) {
mShapeInstance->setPos(mJetThread[BackActivate], 0);
mShapeInstance->setTimeScale(mJetThread[BackActivate], 0);
mJetThread[BackMaintain] = mShapeInstance->addThread();
mShapeInstance->setSequence(mJetThread[BackMaintain],mJetSeq[BackMaintain],0);
mShapeInstance->setTimeScale(mJetThread[BackMaintain],1);
mBackMaintainOn = true;
}
if(mBackMaintainOn)
mShapeInstance->advanceTime(dt,mJetThread[BackMaintain]);
}
// Thrust Animation threads
// Bottom
if (mJetSeq[BottomActivate] >=0 ) {
if(!mBottomMaintainOn || mThrustDirection != ThrustDown || !mJetting) {
if(mBottomMaintainOn) {
mShapeInstance->setPos(mJetThread[BottomActivate], 1);
mShapeInstance->destroyThread(mJetThread[BottomMaintain]);
mBottomMaintainOn = false;
}
mShapeInstance->setTimeScale(mJetThread[BottomActivate],
(mThrustDirection == ThrustDown && mJetting)? 1: -1);
mShapeInstance->advanceTime(dt,mJetThread[BottomActivate]);
}
if(mJetSeq[BottomMaintain] >= 0 && !mBottomMaintainOn &&
mShapeInstance->getPos(mJetThread[BottomActivate]) >= 1.0) {
mShapeInstance->setPos(mJetThread[BottomActivate], 0);
mShapeInstance->setTimeScale(mJetThread[BottomActivate], 0);
mJetThread[BottomMaintain] = mShapeInstance->addThread();
mShapeInstance->setSequence(mJetThread[BottomMaintain],mJetSeq[BottomMaintain],0);
mShapeInstance->setTimeScale(mJetThread[BottomMaintain],1);
mBottomMaintainOn = true;
}
if(mBottomMaintainOn)
mShapeInstance->advanceTime(dt,mJetThread[BottomMaintain]);
}
// Jet particles
for (S32 j = 0; j < NumThrustDirections; j++) {
JetActivation& jet = sJetActivation[j];
updateEmitter(mJetting && j == mThrustDirection,dt,mDataBlock->jetEmitter[jet.emitter],
jet.node,FlyingVehicleData::MaxDirectionJets);
}
// Trail jets
Point3F yv;
mObjToWorld.getColumn(1,&yv);
F32 speed = mFabs(mDot(yv,mRigid.linVelocity));
F32 trail = 0;
if (speed > mDataBlock->minTrailSpeed) {
trail = dt;
if (speed < mDataBlock->maxSpeed)
trail *= (speed - mDataBlock->minTrailSpeed) / mDataBlock->maxSpeed;
}
updateEmitter(trail,trail,mDataBlock->jetEmitter[FlyingVehicleData::TrailEmitter],
FlyingVehicleData::TrailNode,FlyingVehicleData::MaxTrails);
// Allocate/Deallocate voice on demand.
if (!mDataBlock->sound[FlyingVehicleData::JetSound])
return;
if (!mJetting) {
if (mJetSound) {
alxStop(mJetSound);
mJetSound = 0;
}
}
else {
if (!mJetSound)
mJetSound = alxPlay(mDataBlock->sound[FlyingVehicleData::JetSound], &getTransform());
alxSourceMatrixF(mJetSound, &getTransform());
}
}
//----------------------------------------------------------------------------
void FlyingVehicle::updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 idx,S32 count)
{
if (!emitter)
return;
for (S32 j = idx; j < idx + count; j++)
if (active) {
if (mDataBlock->jetNode[j] != -1) {
if (!bool(mJetEmitter[j])) {
mJetEmitter[j] = new ParticleEmitter;
mJetEmitter[j]->onNewDataBlock(emitter);
mJetEmitter[j]->registerObject();
}
MatrixF mat;
Point3F pos,axis;
mat.mul(getRenderTransform(),
mShapeInstance->mNodeTransforms[mDataBlock->jetNode[j]]);
mat.getColumn(1,&axis);
mat.getColumn(3,&pos);
mJetEmitter[j]->emitParticles(pos,true,axis,getVelocity(),(U32)(dt * 1000));
}
}
else {
for (S32 j = idx; j < idx + count; j++)
if (bool(mJetEmitter[j])) {
mJetEmitter[j]->deleteWhenEmpty();
mJetEmitter[j] = 0;
}
}
}
//----------------------------------------------------------------------------
void FlyingVehicle::writePacketData(GameConnection *connection, BitStream *stream)
{
Parent::writePacketData(connection, stream);
}
void FlyingVehicle::readPacketData(GameConnection *connection, BitStream *stream)
{
Parent::readPacketData(connection, stream);
setPosition(mRigid.linPosition,mRigid.angPosition);
mDelta.pos = mRigid.linPosition;
mDelta.rot[1] = mRigid.angPosition;
}
U32 FlyingVehicle::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
// The rest of the data is part of the control object packet update.
// If we're controlled by this client, we don't need to send it.
if(stream->writeFlag(getControllingClient() == con && !(mask & InitialUpdateMask)))
return retMask;
stream->writeFlag(createHeightOn);
stream->writeInt(mThrustDirection,NumThrustBits);
return retMask;
}
void FlyingVehicle::unpackUpdate(NetConnection *con, BitStream *stream)
{
Parent::unpackUpdate(con,stream);
if(stream->readFlag())
return;
createHeightOn = stream->readFlag();
mThrustDirection = ThrustDirection(stream->readInt(NumThrustBits));
}
void FlyingVehicle::initPersistFields()
{
Parent::initPersistFields();
}
ConsoleMethod( FlyingVehicle, useCreateHeight, void, 3, 3, "(bool enabled)"
"Should the vehicle temporarily use the create height specified in the datablock? This can help avoid problems with spawning.")
{
object->useCreateHeight(dAtob(argv[2]));
}
void FlyingVehicle::useCreateHeight(bool val)
{
createHeightOn = val;
setMaskBits(HoverHeight);
}