📄 lightning.cc
字号:
{
if (isLastState(state, stateKey))
return false;
setLastState(state, stateKey);
// This should be sufficient for most objects that don't manage zones, and
// don't need to return a specialized RenderImage...
if (state->isObjectRendered(this)) {
SceneRenderImage* image = new SceneRenderImage;
image->obj = this;
image->isTranslucent = true;
image->sortType = SceneRenderImage::EndSort;
state->insertRenderImage(image);
}
return false;
}
void Lightning::renderObject(SceneState* state, SceneRenderImage*)
{
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
RectI viewport;
glMatrixMode(GL_PROJECTION);
glPushMatrix();
dglGetViewport(&viewport);
// Uncomment this if this is a "simple" (non-zone managing) object
state->setupObjectProjection(this);
// RENDER CODE HERE
MatrixF mv;
dglGetModelview(&mv);
Point3F camAxis;
mv.getRow(1, &camAxis);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDepthMask( GL_FALSE );
if( useFog )
{
if (dglDoesSupportARBMultitexture() && dglDoesSupportFogCoord()) {
glEnable(GL_FOG);
glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
GLfloat fogColor[4];
fogColor[0] = state->getFogColor().red;
fogColor[1] = state->getFogColor().green;
fogColor[2] = state->getFogColor().blue;
fogColor[3] = 0.5f;
glFogfv(GL_FOG_COLOR, fogColor);
glFogi(GL_FOG_MODE, GL_LINEAR);
glFogf(GL_FOG_START, 0.0f);
glFogf(GL_FOG_END, 1.0f);
}
}
Strike* walk = mStrikeListHead;
while (walk != NULL) {
glBindTexture(GL_TEXTURE_2D, mDataBlock->strikeTextures[0].getGLName());
for( U32 i=0; i<3; i++ )
{
if( walk->bolt[i].isFading )
{
F32 alpha = 1.0 - walk->bolt[i].percentFade;
if( alpha < 0.0 ) alpha = 0.0;
glColor4f( fadeColor.red, fadeColor.green, fadeColor.blue, alpha );
}
else
{
glColor4fv( color );
}
walk->bolt[i].render( state->getCameraPosition() );
}
walk = walk->next;
}
glDepthMask( GL_TRUE );
glDisable(GL_FOG);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
dglSetViewport(viewport);
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
}
void Lightning::scheduleThunder(Strike* newStrike)
{
AssertFatal(isClientObject(), "Lightning::scheduleThunder: server objects should not enter this version of the function");
// If no thunder sounds, don't schedule anything!
if (mDataBlock->numThunders == 0)
return;
GameConnection* connection = GameConnection::getConnectionToServer();
if (connection) {
MatrixF cameraMatrix;
if (connection->getControlCameraTransform(0, &cameraMatrix)) {
Point3F worldPos;
cameraMatrix.getColumn(3, &worldPos);
worldPos.x -= newStrike->xVal;
worldPos.y -= newStrike->yVal;
worldPos.z = 0;
F32 dist = worldPos.len();
F32 t = dist / 330.0;
// Ok, we need to schedule a random strike sound t secs in the future...
//
if (t <= 0.03) {
// If it's really close, just play it...
U32 thunder = sgLightningRand.randI(0, mDataBlock->numThunders - 1);
alxPlay(mDataBlock->thunderSounds[thunder]);
} else {
Thunder* pThunder = new Thunder;
pThunder->tRemaining = t;
pThunder->next = mThunderListHead;
mThunderListHead = pThunder;
}
}
}
}
//--------------------------------------------------------------------------
void Lightning::processTick(const Move* move)
{
Parent::processTick(move);
if (isServerObject()) {
S32 msBetweenStrikes = (S32)(60.0 / strikesPerMinute * 1000.0);
mLastThink += TickMs;
if( mLastThink > msBetweenStrikes )
{
strikeRandomPoint();
mLastThink -= msBetweenStrikes;
}
}
}
void Lightning::interpolateTick(F32 dt)
{
Parent::interpolateTick(dt);
}
void Lightning::advanceTime(F32 dt)
{
Parent::advanceTime(dt);
Strike** pWalker = &mStrikeListHead;
while (*pWalker != NULL) {
Strike* pStrike = *pWalker;
for( U32 i=0; i<3; i++ )
{
pStrike->bolt[i].update( dt );
}
pStrike->currentAge += dt;
if (pStrike->currentAge > pStrike->deathAge) {
*pWalker = pStrike->next;
delete pStrike;
} else {
pWalker = &((*pWalker)->next);
}
}
Thunder** pThunderWalker = &mThunderListHead;
while (*pThunderWalker != NULL) {
Thunder* pThunder = *pThunderWalker;
pThunder->tRemaining -= dt;
if (pThunder->tRemaining <= 0.0) {
*pThunderWalker = pThunder->next;
delete pThunder;
// Play the sound...
U32 thunder = sgLightningRand.randI(0, mDataBlock->numThunders - 1);
alxPlay(mDataBlock->thunderSounds[thunder]);
} else {
pThunderWalker = &((*pThunderWalker)->next);
}
}
}
//--------------------------------------------------------------------------
void Lightning::processEvent(LightningStrikeEvent* pEvent)
{
AssertFatal(pEvent->mStart.x >= 0 && pEvent->mStart.x <= 1.0, "Out of bounds coord!");
Strike* pStrike = new Strike;
Point3F strikePoint;
strikePoint.zero();
if( pEvent->mTarget )
{
Point3F objectCenter;
pEvent->mTarget->getObjBox().getCenter( &objectCenter );
objectCenter.convolve( pEvent->mTarget->getScale() );
pEvent->mTarget->getTransform().mulP( objectCenter );
strikePoint = objectCenter;
}
else
{
strikePoint.x = pEvent->mStart.x;
strikePoint.y = pEvent->mStart.y;
strikePoint *= mObjScale;
strikePoint += getPosition();
strikePoint += Point3F( -mObjScale.x * 0.5, -mObjScale.y * 0.5, 0.0 );
RayInfo rayInfo;
Point3F start = strikePoint;
start.z = mObjScale.z * 0.5 + getPosition().z;
strikePoint.z += -mObjScale.z * 0.5;
bool rayHit = gClientContainer.castRay( start, strikePoint,
(STATIC_COLLISION_MASK | WaterObjectType),
&rayInfo);
if( rayHit )
{
strikePoint.z = rayInfo.point.z;
}
else
{
strikePoint.z = pStrike->bolt[0].findHeight( strikePoint, mSceneManager );
}
}
pStrike->xVal = strikePoint.x;
pStrike->yVal = strikePoint.y;
pStrike->deathAge = 1.6;
pStrike->currentAge = 0.0;
pStrike->next = mStrikeListHead;
for( U32 i=0; i<3; i++ )
{
F32 randStart = boltStartRadius;
F32 height = mObjScale.z * 0.5 + getPosition().z;
pStrike->bolt[i].startPoint = Point3F( pStrike->xVal + gRandGen.randF( -randStart, randStart ), pStrike->yVal + gRandGen.randF( -randStart, randStart ), height );
pStrike->bolt[i].endPoint = strikePoint;
pStrike->bolt[i].width = strikeWidth;
pStrike->bolt[i].numMajorNodes = 10;
pStrike->bolt[i].maxMajorAngle = 30;
pStrike->bolt[i].numMinorNodes = 4;
pStrike->bolt[i].maxMinorAngle = 15;
pStrike->bolt[i].generate();
pStrike->bolt[i].startSplits();
pStrike->bolt[i].lifetime = 1.0;
pStrike->bolt[i].fadeTime = 0.2;
pStrike->bolt[i].renderTime = gRandGen.randF(0.0, 0.25);
}
mStrikeListHead = pStrike;
scheduleThunder(pStrike);
MatrixF trans(true);
trans.setPosition( strikePoint );
if (mDataBlock->strikeSound)
{
alxPlay(mDataBlock->strikeSound, &trans );
}
}
void Lightning::warningFlashes()
{
AssertFatal(isServerObject(), "Error, client objects may not initiate lightning!");
SimGroup* pClientGroup = Sim::getClientGroup();
for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++) {
NetConnection* nc = static_cast<NetConnection*>(*itr);
if (nc != NULL)
{
LightningStrikeEvent* pEvent = new LightningStrikeEvent;
pEvent->mLightning = this;
nc->postNetEvent(pEvent);
}
}
}
void Lightning::strikeRandomPoint()
{
AssertFatal(isServerObject(), "Error, client objects may not initiate lightning!");
Point3F strikePoint;
strikePoint.x = gRandGen.randF( 0.0, 1.0 );
strikePoint.y = gRandGen.randF( 0.0, 1.0 );
strikePoint.z = 0.0;
// check if an object is within target range
strikePoint *= mObjScale;
strikePoint += getPosition();
strikePoint += Point3F( -mObjScale.x * 0.5, -mObjScale.y * 0.5, 0.0 );
Box3F queryBox;
F32 boxWidth = strikeRadius * 2;
queryBox.min.set( -boxWidth * 0.5, -boxWidth * 0.5, -mObjScale.z * 0.5 );
queryBox.max.set( boxWidth * 0.5, boxWidth * 0.5, mObjScale.z * 0.5 );
queryBox.min += strikePoint;
queryBox.max += strikePoint;
SimpleQueryList sql;
getContainer()->findObjects(queryBox, DAMAGEABLE_MASK,
SimpleQueryList::insertionCallback, &sql);
SceneObject *highestObj = NULL;
F32 highestPnt = 0.0;
for( U32 i = 0; i < sql.mList.size(); i++ )
{
Point3F objectCenter;
sql.mList[i]->getObjBox().getCenter(&objectCenter);
objectCenter.convolve(sql.mList[i]->getScale());
sql.mList[i]->getTransform().mulP(objectCenter);
// check if object can be struck
RayInfo rayInfo;
Point3F start = objectCenter;
start.z = mObjScale.z * 0.5 + getPosition().z;
Point3F end = objectCenter;
end.z = -mObjScale.z * 0.5 + getPosition().z;
bool rayHit = gServerContainer.castRay( start, end,
(0xFFFFFFFF),
&rayInfo);
if( rayHit && rayInfo.object == sql.mList[i] )
{
if( !highestObj )
{
highestObj = sql.mList[i];
highestPnt = objectCenter.z;
continue;
}
if( objectCenter.z > highestPnt )
{
highestObj = sql.mList[i];
highestPnt = objectCenter.z;
}
}
}
// hah haaaaa, we have a target!
SceneObject *targetObj = NULL;
if( highestObj )
{
F32 chance = gRandGen.randF();
if( chance <= chanceToHitTarget )
{
Point3F objectCenter;
highestObj->getObjBox().getCenter(&objectCenter);
objectCenter.convolve(highestObj->getScale());
highestObj->getTransform().mulP(objectCenter);
bool playerInWarmup = false;
Player *playerObj = dynamic_cast< Player * >(highestObj);
if( playerObj )
{
if( !playerObj->getControllingClient() )
{
playerInWarmup = true;
}
}
if( !playerInWarmup )
{
applyDamage( objectCenter, VectorF( 0.0, 0.0, 1.0 ), highestObj );
targetObj = highestObj;
}
}
}
SimGroup* pClientGroup = Sim::getClientGroup();
for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++)
{
NetConnection* nc = static_cast<NetConnection*>(*itr);
LightningStrikeEvent* pEvent = new LightningStrikeEvent;
pEvent->mLightning = this;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -