/* ================ idBrittleFracture::Shatter ================ */ void idBrittleFracture::Shatter( const idVec3 &point, const idVec3 &impulse, const int time ) { int i; idVec3 dir; shard_t *shard; float m; if ( gameLocal.isServer ) { idBitMsg msg; byte msgBuf[MAX_EVENT_PARAM_SIZE]; msg.Init( msgBuf, sizeof( msgBuf ) ); msg.BeginWriting(); msg.WriteFloat( point[0] ); msg.WriteFloat( point[1] ); msg.WriteFloat( point[2] ); msg.WriteFloat( impulse[0] ); msg.WriteFloat( impulse[1] ); msg.WriteFloat( impulse[2] ); ServerSendEvent( EVENT_SHATTER, &msg, true, -1 ); } if ( time > ( gameLocal.time - SHARD_ALIVE_TIME ) ) { StartSound( "snd_shatter", SND_CHANNEL_ANY, 0, false, NULL ); } if ( !IsBroken() ) { Break(); } if ( fxFracture.Length() ) { idEntityFx::StartFx( fxFracture, &point, &GetPhysics()->GetAxis(), this, true ); } dir = impulse; m = dir.Normalize(); for ( i = 0; i < shards.Num(); i++ ) { shard = shards[i]; if ( shard->droppedTime != -1 ) { continue; } if ( ( shard->clipModel->GetOrigin() - point ).LengthSqr() > Square( maxShatterRadius ) ) { continue; } DropShard( shard, point, dir, m, time ); } DropFloatingIslands( point, impulse, time ); //trigger it. if (!firedTargets) { firedTargets = true; ActivateTargets(this); } }
/* ================ c4tnt: now fractures can be broken at start idBrittleFracture::StartBroken ================ */ void idBrittleFracture::StartBroken( const float part, float disperse) { int i, counter; shard_t *shard; shard_t *shardorg; idVec3 point; if ( disperse > 0.9) disperse = 0.9f; if ( !IsBroken() ) { Break(); } counter = shards.Num() * part; if ( counter > shards.Num()) counter = shards.Num(); while (counter > 0) { for ( i = 0; i < shards.Num(); i++ ) { shardorg = shards[i]; if ( shardorg->droppedTime != -1 ) { continue; } if (gameLocal.random.RandomFloat() > disperse) { counter--; point = shardorg->clipModel->GetOrigin(); for ( i = 0; i < shards.Num(); i++ ) { shard = shards[i]; if ( shard->droppedTime != -1 || shard == shardorg) { continue; } if ( ( shard->clipModel->GetOrigin() - point ).LengthSqr() > Square( maxShatterRadius ) ) { continue; } counter--; DropShard( shard ); } DropShard( shardorg ); DropFloatingIslands( &counter ); } } } }
/* ================ idBrittleFracture::DropFloatingIslands ================ */ void idBrittleFracture::DropFloatingIslands( const idVec3 &point, const idVec3 &impulse, const int time ) { int i, j, numIslands; int queueStart, queueEnd; shard_t *curShard, *nextShard, **queue; bool touchesEdge; idVec3 dir; dir = impulse; dir.Normalize(); numIslands = 0; queue = ( shard_t ** ) _alloca16( shards.Num() * sizeof( shard_t ** ) ); for( i = 0; i < shards.Num(); i++ ) { shards[i]->islandNum = 0; } for( i = 0; i < shards.Num(); i++ ) { if( shards[i]->droppedTime != -1 ) { continue; } if( shards[i]->islandNum ) { continue; } queueStart = 0; queueEnd = 1; queue[0] = shards[i]; shards[i]->islandNum = numIslands + 1; touchesEdge = false; if( shards[i]->atEdge ) { touchesEdge = true; } for( curShard = queue[queueStart]; queueStart < queueEnd; curShard = queue[++queueStart] ) { for( j = 0; j < curShard->neighbours.Num(); j++ ) { nextShard = curShard->neighbours[j]; if( nextShard->droppedTime != -1 ) { continue; } if( nextShard->islandNum ) { continue; } queue[queueEnd++] = nextShard; nextShard->islandNum = numIslands + 1; if( nextShard->atEdge ) { touchesEdge = true; } } } numIslands++; // if the island is not connected to the world at any edges if( !touchesEdge ) { for( j = 0; j < queueEnd; j++ ) { DropShard( queue[j], point, dir, 0.0f, time ); } } } }
/* ================ idBrittleFracture::Shatter ================ */ void idBrittleFracture::Shatter( const idVec3& point, const idVec3& impulse, const int time ) { int i; idVec3 dir; shard_t* shard; float m; if( common->IsServer() ) { idBitMsg msg; byte msgBuf[MAX_EVENT_PARAM_SIZE]; msg.InitWrite( msgBuf, sizeof( msgBuf ) ); msg.BeginWriting(); msg.WriteFloat( point[0] ); msg.WriteFloat( point[1] ); msg.WriteFloat( point[2] ); msg.WriteFloat( impulse[0] ); msg.WriteFloat( impulse[1] ); msg.WriteFloat( impulse[2] ); ServerSendEvent( EVENT_SHATTER, &msg, true ); } // Store off the event so we can rebuilt the object if we reload a savegame fractureEvent_s fractureEvent; fractureEvent.eventType = EVENT_SHATTER; fractureEvent.point = point; fractureEvent.vector = impulse; storedEvents.Append( fractureEvent ); if( time > ( gameLocal.time - SHARD_ALIVE_TIME ) ) { StartSound( "snd_shatter", SND_CHANNEL_ANY, 0, false, NULL ); } if( !IsBroken() ) { Break(); } if( fxFracture.Length() ) { idEntityFx::StartFx( fxFracture, &point, &GetPhysics()->GetAxis(), this, true ); } dir = impulse; m = dir.Normalize(); for( i = 0; i < shards.Num(); i++ ) { shard = shards[i]; if( shard->droppedTime != -1 ) { continue; } if( ( shard->clipModel->GetOrigin() - point ).LengthSqr() > Square( maxShatterRadius ) ) { continue; } DropShard( shard, point, dir, m, time ); } DropFloatingIslands( point, impulse, time ); }