/************************************************************************************************ * CRMGroupInstance::Spawn * Adds the group instance to the given landscape using the specified origin. All sub instances * will be added to the landscape within their min and max range from the origin. * * inputs: * landscape: landscape to add the instance group to * origin: origin of the instance group * * return: * none * ************************************************************************************************/ bool CRMGroupInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer ) { rmInstanceIter_t it; // Spawn all the instances associated with this group for(it = mInstances.begin(); it != mInstances.end(); ++it) { CRMInstance* instance = *it; instance->SetSide(GetSide()); // which side owns it? // Add the instance to the landscape now instance->Spawn ( terrain, IsServer ); } DrawAutomapSymbol(); return true; }
/************************************************************************************************ * CRMBSPInstance::Spawn * spawns a bsp into the world using the previously aquired origin * * inputs: * none * * return: * none * ************************************************************************************************/ bool CRMBSPInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer) { #ifndef PRE_RELEASE_DEMO // TEntity* ent; float yaw; char temp[10000]; char *savePtr; vec3_t origin; vec3_t notmirrored; float water_level = terrain->GetLandScape()->GetWaterHeight(); const vec3_t& terxelSize = terrain->GetLandScape()->GetTerxelSize ( ); const vec3pair_t& bounds = terrain->GetLandScape()->GetBounds(); // If this entity somehow lost its collision flag then boot it if ( !GetArea().IsCollisionEnabled ( ) ) { return false; } // copy out the unmirrored version VectorCopy(GetOrigin(), notmirrored); // we want to mirror it before determining the Z value just in case the landscape isn't perfectly mirrored if (mMirror) { GetOrigin()[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - GetOrigin()[0]; GetOrigin()[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - GetOrigin()[1]; } // Align the instance to the center of a terxel GetOrigin ( )[0] = bounds[0][0] + (int)((GetOrigin ( )[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0]; GetOrigin ( )[1] = bounds[0][1] + (int)((GetOrigin ( )[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1]; // Make sure the bsp is resting on the ground, not below or above it // NOTE: This check is basically saying "is this instance not a bridge", because when instances are created they are all // placed above the world's Z boundary, EXCEPT FOR BRIDGES. So this call to GetWorldHeight will move all other instances down to // ground level except bridges if ( GetOrigin()[2] > terrain->GetBounds()[1][2] ) { if( GetFlattenRadius() ) { terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), false ); GetOrigin()[2] += 5; } else if (IsServer) { // if this instance does not flatten the ground around it, do a trace to more accurately determine its Z value trace_t tr; vec3_t end; vec3_t start; VectorCopy(GetOrigin(), end); VectorCopy(GetOrigin(), start); // start the trace below the top height of the landscape start[2] = TheRandomMissionManager->GetLandScape()->GetBounds()[1][2] - 1; // end the trace at the bottom of the world end[2] = MIN_WORLD_COORD; memset ( &tr, 0, sizeof ( tr ) ); SV_Trace( &tr, start, vec3_origin, vec3_origin, end, ENTITYNUM_NONE, CONTENTS_TERRAIN|CONTENTS_SOLID, G2_NOCOLLIDE, 0); //qfalse, 0, 10 ); if( !(tr.contents & CONTENTS_TERRAIN) || (tr.fraction == 1.0) ) { if ( 0 ) assert(0); // this should never happen // restore the unmirrored origin VectorCopy( notmirrored, GetOrigin() ); // don't spawn return false; } // assign the Z-value to wherever it hit the terrain GetOrigin()[2] = tr.endpos[2]; // lower it a little, otherwise the bottom of the instance might be exposed if on some weird sloped terrain GetOrigin()[2] -= 16; // FIXME: would it be better to use a number related to the instance itself like 1/5 it's height or something... } } else { terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), true ); } // save away the origin VectorCopy(GetOrigin(), origin); // make sure not to spawn if in water if (!HasObjective() && GetOrigin()[2] < water_level) return false; // restore the origin VectorCopy(origin, GetOrigin()); if (mMirror) { // change blue things to red for symmetric maps if (strlen(mFilter) > 0) { char * blue = strstr(mFilter,"blue"); if (blue) { blue[0] = (char) 0; strcat(mFilter, "red"); SetSide(SIDE_RED); } } if (strlen(mTeamFilter) > 0) { char * blue = strstr(mTeamFilter,"blue"); if (blue) { strcpy(mTeamFilter, "red"); SetSide(SIDE_RED); } } yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle) + 180; } else { yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle); } /* if( TheRandomMissionManager->GetMission()->GetSymmetric() ) { vec3_t diagonal; vec3_t lineToPoint; vec3_t mins; vec3_t maxs; vec3_t point; vec3_t vProj; vec3_t vec; float distance; VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[1], maxs ); VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[0], mins ); VectorCopy( GetOrigin(), point ); mins[2] = maxs[2] = point[2] = 0; VectorSubtract( point, mins, lineToPoint ); VectorSubtract( maxs, mins, diagonal); VectorNormalize(diagonal); VectorMA( mins, DotProduct(lineToPoint, diagonal), diagonal, vProj); VectorSubtract(point, vProj, vec ); distance = VectorLength(vec); // if an instance is too close to the imaginary diagonal that cuts the world in half, don't spawn it // otherwise you can get overlapping instances if( distance < GetSpacingRadius() ) { #ifdef _DEBUG mAutomapSymbol = AUTOMAP_END; #endif if( !HasObjective() ) { return false; } } } */ // Spawn in the bsp model sprintf(temp, "{\n" "\"classname\" \"misc_bsp\"\n" "\"bspmodel\" \"%s\"\n" "\"origin\" \"%f %f %f\"\n" "\"angles\" \"0 %f 0\"\n" "\"filter\" \"%s\"\n" "\"teamfilter\" \"%s\"\n" "\"spacing\" \"%d\"\n" "\"flatten\" \"%d\"\n" "}\n", mBsp, GetOrigin()[0], GetOrigin()[1], GetOrigin()[2], AngleNormalize360(yaw), mFilter, mTeamFilter, (int)GetSpacingRadius(), (int)GetFlattenRadius() ); if (IsServer) { // only allow for true spawning on the server savePtr = sv.entityParsePoint; sv.entityParsePoint = temp; // VM_Call( cgvm, GAME_SPAWN_RMG_ENTITY ); // char *s; int bufferSize = 1024; char buffer[1024]; // s = COM_Parse( (const char **)&sv.entityParsePoint ); Q_strncpyz( buffer, sv.entityParsePoint, bufferSize ); if ( sv.entityParsePoint && sv.entityParsePoint[0] ) { ge->GameSpawnRMGEntity(sv.entityParsePoint); } sv.entityParsePoint = savePtr; } #ifndef DEDICATED DrawAutomapSymbol(); #endif Com_DPrintf( "RMG: Building '%s' spawned at (%f %f %f)\n", mBsp, GetOrigin()[0], GetOrigin()[1], GetOrigin()[2] ); // now restore the instances un-mirrored origin // NOTE: all this origin flipping, setting the side etc... should be done when mMirror is set // because right after this function is called, mMirror is set to 0 but all the instance data is STILL MIRRORED -- not good VectorCopy(notmirrored, GetOrigin()); #endif // PRE_RELEASE_DEMO return true; }