Snow::Snow() : WorldObject() { m_positionOffset = syncfrand(10.0); m_xaxisRate = syncfrand(2.0); m_yaxisRate = syncfrand(2.0); m_zaxisRate = syncfrand(2.0); m_timeSync = GetNetworkTime(); m_type = EffectSnow; }
Zombie::Zombie() : WorldObject(), m_life(0.0) { m_positionOffset = syncfrand(10.0); m_xaxisRate = syncfrand(2.0); m_yaxisRate = syncfrand(2.0); m_zaxisRate = syncfrand(2.0); m_type = EffectZombie; }
bool SoulDestroyer::SearchForRandomPosition() { Vector3 toSpawnPoint = ( m_pos - m_spawnPoint ); toSpawnPoint.y = 0.0; double distToSpawnPoint = toSpawnPoint.Mag(); double chanceOfReturn = ( distToSpawnPoint / m_roamRange ); if( chanceOfReturn >= 1.0 || syncfrand(1.0) <= chanceOfReturn ) { // We have strayed too far from our spawn point // So head back there now Vector3 targetPos = m_spawnPoint; targetPos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( targetPos.x, targetPos.z ); targetPos.y += 100.0 + syncsfrand( 100.0 ); Vector3 returnVector = ( targetPos - m_pos ); returnVector.SetLength( 160.0 ); m_targetPos = m_pos + returnVector; } else { double distance = 160.0; double angle = syncsfrand(2.0 * M_PI); m_targetPos = m_pos + Vector3( iv_sin(angle) * distance, 0.0, iv_cos(angle) * distance ); m_targetPos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( m_targetPos.x, m_targetPos.z ); m_targetPos.y += (100.0 + syncsfrand( 100.0 )); } return true; }
bool SoulDestroyer::Advance( Unit *_unit ) { if( m_dead ) return AdvanceDead( _unit ); if( m_panic > 0.0 ) { m_targetEntity.SetInvalid(); if( syncfrand(10.0) < 5.0 ) { SearchForRetreatPosition(); } m_panic -= SERVER_ADVANCE_PERIOD; } else if( m_targetEntity.IsValid() ) { WorldObject *target = g_app->m_location->GetEntity( m_targetEntity ); if( target ) { double distance = (target->m_pos - m_pos).Mag(); m_targetPos = target->m_pos; if( distance > SOULDESTROYER_MAXSEARCHRANGE ) { m_targetEntity.SetInvalid(); } } else { m_targetEntity.SetInvalid(); } } m_retargetTimer -= SERVER_ADVANCE_PERIOD; bool arrived = AdvanceToTargetPosition(); if( arrived || m_targetPos == g_zeroVector || m_retargetTimer < 0.0) { m_retargetTimer = 5.0; bool found = false; if( !found && m_panic < 0.1 ) found = SearchForTargetEnemy(); if( !found ) found = SearchForRandomPosition(); } RecordHistoryPosition(); if( m_panic < 0.1 ) Attack( m_pos ); #ifdef USE_DIRECT3D if(g_deformEffect) { Vector3* pos1 = m_positionHistory.GetPointer(m_positionHistory.Size()-1); Vector3* pos2 = m_positionHistory.GetPointer(m_positionHistory.Size()-2); //if(pos1) g_deformEffect->AddTearing(*pos1,0.4); //if(pos1 && pos2) g_deformEffect->AddTearing((*pos1+*pos2)*0.5,0.4); if(pos1 && pos2) g_deformEffect->AddTearingPath(*pos1,*pos2,0.4); } #endif return Entity::Advance(_unit); }
bool AntHill::SearchForScoutArea ( Vector3 &_pos ) { Vector3 scoutPos = m_pos; float radius = ANTHILL_SEARCHRANGE/2.0f + syncfrand(ANTHILL_SEARCHRANGE/2.0f); float theta = syncfrand(M_PI * 2); scoutPos.x += radius * sinf(theta); scoutPos.z += radius * cosf(theta); scoutPos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( scoutPos.x, scoutPos.z ); if( scoutPos.y > 0 ) { _pos = scoutPos; return true; } return false; }
void AntHill::Damage ( float _damage ) { Building::Damage( _damage ); if( m_health > 0 ) { int healthBandBefore = int(m_health / 20.0f); m_health += _damage; int healthBandAfter = int(m_health / 20.0f); if( healthBandAfter != healthBandBefore ) { Matrix34 mat( m_front, g_upVector, m_pos ); g_explosionManager.AddExplosion( m_shape, mat, 1.0f - (float)m_health/100.0f ); g_app->m_soundSystem->TriggerBuildingEvent( this, "Damage" ); } if( m_health <= 0 ) { Matrix34 mat( m_front, g_upVector, m_pos ); g_explosionManager.AddExplosion( m_shape, mat ); int numSpirits = m_numAntsInside + m_numSpiritsInside; for( int i = 0; i < numSpirits; ++i ) { Vector3 pos = m_pos; float radius = syncfrand(20.0f); float theta = syncfrand(M_PI * 2); pos.x += radius * sinf(theta); pos.z += radius * cosf(theta); Vector3 vel = ( pos - m_pos ); vel.SetLength( syncfrand(50.0f) ); g_app->m_location->SpawnSpirit( pos, vel, m_id.GetTeamId(), WorldObjectId() ); } g_app->m_soundSystem->TriggerBuildingEvent( this, "Explode" ); m_health = 0; } } }
void Entity::SetType( unsigned char _type ) { m_type = _type; for( int i = 0; i < NumStats; ++i ) { m_stats[i] = EntityBlueprint::GetStat( m_type, i ); } m_reloading = syncfrand( m_stats[StatRate] ); }
bool SoulDestroyer::ChangeHealth( int _amount, int _damageType ) { if( _damageType == DamageTypeLaser ) return false; if( !m_dead && _amount < 0 ) { Entity::ChangeHealth(_amount); double fractionDead = 1.0 - (double) m_stats[StatHealth] / (double) EntityBlueprint::GetStat( TypeSoulDestroyer, StatHealth ); fractionDead = max( fractionDead, 0.5 ); fractionDead = min( fractionDead, 1.0 ); if( m_dead ) fractionDead = 1.0; Panic( 2.0 + syncfrand(2.0) ); Vector3 predictedRight = m_up ^ m_front; Vector3 predictedFront = predictedRight ^ m_up; Matrix34 transform(predictedFront, m_up, m_pos); g_explosionManager.AddExplosion( m_shape, transform, fractionDead ); if( fractionDead ) { // We just died for( int i = 1; i < m_positionHistory.Size(); i+=1 ) { Vector3 pos1 = *m_positionHistory.GetPointer(i); Vector3 pos2 = *m_positionHistory.GetPointer(i-1); Vector3 pos = pos1 + (pos2 - pos1); Vector3 front = (pos2 - pos1).Normalise(); Vector3 right = front ^ g_upVector; Vector3 up = right ^ front; double scale = 1.0 - ( (double) i / (double) m_positionHistory.Size() ); scale *= 1.5; if( i == m_positionHistory.Size()-1 ) scale = 0.8; scale = max( scale, 0.5 ); Matrix34 tailMat( front, up, pos ); tailMat.u *= scale; tailMat.r *= scale; tailMat.f *= scale; g_explosionManager.AddExplosion( m_shape, tailMat, 1.0 ); } } } return true; }
AIObjectiveMarker::AIObjectiveMarker() : Building(), m_scanRange(100.0), m_objectiveId(-1), m_registered(false), m_armourObjective(0), m_objectiveBuildingId(-1), m_pickupAvailable(false), m_pickupOnly(0), m_defenseMarker(false), m_timer(0.0) { m_type = Building::TypeAIObjectiveMarker; m_timer = syncfrand(1.0); }
bool Snow::Advance() { m_vel *= 0.9; // // Make me double around slowly m_positionOffset += SERVER_ADVANCE_PERIOD; m_xaxisRate += syncsfrand(1.0); m_yaxisRate += syncsfrand(1.0); m_zaxisRate += syncsfrand(1.0); if( m_xaxisRate > 2.0 ) m_xaxisRate = 2.0; if( m_xaxisRate < 0.0 ) m_xaxisRate = 0.0; if( m_yaxisRate > 2.0 ) m_yaxisRate = 2.0; if( m_yaxisRate < 0.0 ) m_yaxisRate = 0.0; if( m_zaxisRate > 2.0 ) m_zaxisRate = 2.0; if( m_zaxisRate < 0.0 ) m_zaxisRate = 0.0; m_hover.x = iv_sin( m_positionOffset ) * m_xaxisRate; m_hover.y = iv_sin( m_positionOffset ) * m_yaxisRate; m_hover.z = iv_sin( m_positionOffset ) * m_zaxisRate; double heightAboveGround = m_pos.y - g_app->m_location->m_landscape.m_heightMap->GetValue( m_pos.x, m_pos.z ); if( heightAboveGround > -10.0 ) { double fractionAboveGround = heightAboveGround / 100.0; fractionAboveGround = min( fractionAboveGround, 1.0 ); fractionAboveGround = max( fractionAboveGround, 0.2 ); m_hover.y = (-20.0 - syncfrand(20.0)) * fractionAboveGround; } else { return true; } Vector3 oldPos = m_pos; m_pos += m_vel * SERVER_ADVANCE_PERIOD; m_pos += m_hover * SERVER_ADVANCE_PERIOD; double worldSizeX = g_app->m_location->m_landscape.GetWorldSizeX(); double worldSizeZ = g_app->m_location->m_landscape.GetWorldSizeZ(); if( m_pos.x < 0.0 ) m_pos.x = 0.0; if( m_pos.z < 0.0 ) m_pos.z = 0.0; if( m_pos.x >= worldSizeX ) m_pos.x = worldSizeX; if( m_pos.z >= worldSizeZ ) m_pos.z = worldSizeZ; return false; }
unsigned char GenerateSyncValue() { START_PROFILE( "GenerateSyncValue" ); // // Generate a number between 0 and 255 that represents every unit in game // So if a single one is different, we will know immediately unsigned char result = 0; // // Objects hash_context c; hash_initial(&c); #ifdef TRACK_SYNC_RAND for( int i = 0; i < g_app->GetWorld()->m_objects.Size(); ++i ) { if( g_app->GetWorld()->m_objects.ValidIndex(i) ) { WorldObject *obj = g_app->GetWorld()->m_objects[i]; Hash( c, obj->m_longitude ); Hash( c, obj->m_latitude ); Hash( c, obj->m_vel.x ); Hash( c, obj->m_vel.y ); Hash( c, obj->m_currentState ); } } #endif // // Random value Hash( c, syncfrand(255) ); uint32 hashResult[5]; hash_final(&c, hashResult); result = hashResult[0] & 0xFF; END_PROFILE( "GenerateSyncValue" ); return result; }
bool PylonStart::Advance() { // // Is the Generator online? bool generatorOnline = false; int generatorLocationId = g_app->m_globalWorld->GetLocationId("generator"); GlobalBuilding *globalRefinery = NULL; for( int i = 0; i < g_app->m_globalWorld->m_buildings.Size(); ++i ) { if( g_app->m_globalWorld->m_buildings.ValidIndex(i) ) { GlobalBuilding *gb = g_app->m_globalWorld->m_buildings[i]; if( gb && gb->m_locationId == generatorLocationId && gb->m_type == TypeGenerator && gb->m_online ) { generatorOnline = true; break; } } } if( generatorOnline ) { // // Is our required building online yet? GlobalBuilding *globalBuilding = g_app->m_globalWorld->GetBuilding( m_reqBuildingId, g_app->m_locationId ); if( globalBuilding && globalBuilding->m_online ) { if( syncfrand() > 0.7f ) { TriggerSurge(0.0f); } } } return PowerBuilding::Advance(); }
bool SolarPanel::Advance() { float fractionOccupied = (float) GetNumPortsOccupied() / (float) GetNumPorts(); if( syncfrand(20.0f) <= fractionOccupied ) { TriggerSurge(0.0f); } if( fractionOccupied > 0.6f ) { if( !m_operating ) g_app->m_soundSystem->TriggerBuildingEvent( this, "Operate" ); m_operating = true; } if( fractionOccupied < 0.3f ) { if( m_operating ) g_app->m_soundSystem->StopAllSounds( m_id, "SolarPanel Operate" ); m_operating = false; } return PowerBuilding::Advance(); }
bool Officer::Advance( Unit *_unit ) { if( !m_onGround ) AdvanceInAir(_unit); bool amIDead = Entity::Advance(_unit); if( m_inWater != -1.0f ) AdvanceInWater(_unit); if( m_onGround && !m_dead ) m_pos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( m_pos.x, m_pos.z ); // // Advance in whatever state we are in if( !amIDead && m_onGround && m_inWater == -1.0f ) { switch( m_state ) { case StateIdle : amIDead = AdvanceIdle(); break; case StateToWaypoint : amIDead = AdvanceToWaypoint(); break; case StateGivingOrders : amIDead = AdvanceGivingOrders(); break; } } if( m_dead ) { m_vel.y -= 20.0f; m_pos.y += m_vel.y * SERVER_ADVANCE_PERIOD; } // // If we are giving orders, render them if( m_orders == OrderGoto ) { if( syncfrand() < 0.05f ) { OfficerOrders *orders = new OfficerOrders(); orders->m_pos = m_pos + Vector3(0,2,0); orders->m_wayPoint = m_orderPosition; int index = g_app->m_location->m_effects.PutData( orders ); orders->m_id.Set( m_id.GetTeamId(), UNIT_EFFECTS, index, -1 ); orders->m_id.GenerateUniqueId(); } } // // If we are absorbing, look around for Darwinians if( m_absorb ) Absorb(); // // Attack anything nearby with our "shield" if( m_shield > 0 ) { WorldObjectId id = g_app->m_location->m_entityGrid->GetBestEnemy( m_pos.x, m_pos.z, 0.0f, OFFICER_ATTACKRANGE, m_id.GetTeamId() ); if( id.IsValid() ) { Entity *entity = g_app->m_location->GetEntity( id ); entity->ChangeHealth( -10 ); m_shield --; Vector3 themToUs = m_pos - entity->m_pos; g_app->m_location->SpawnSpirit( m_pos, themToUs, 0, WorldObjectId() ); } } // // Use teleports. Remember which teleport we entered, // As there may be people following us if( m_wayPointTeleportId != -1 ) { int teleportId = EnterTeleports(m_wayPointTeleportId); if( teleportId != -1 ) { m_ordersBuildingId = teleportId; Teleport *teleport = (Teleport *) g_app->m_location->GetBuilding( teleportId ); Vector3 exitPos, exitFront; bool exitFound = teleport->GetExit( exitPos, exitFront ); if( exitFound ) m_wayPoint = exitPos + exitFront * 30.0f; if( m_orders == OrderGoto ) m_orders = OrderNone; m_wayPointTeleportId = -1; } } return amIDead || m_demoted; }
bool AntHill::Advance() { Building::Advance(); // // Is the world awake yet ? if( !g_app->m_location ) return false; if( !g_app->m_location->m_teams ) return false; if( g_app->m_location->m_teams[ m_id.GetTeamId() ].m_teamType != Team::TeamTypeCPU ) return false; bool popLocked = PopulationLocked(); // // Is it time to look for a new objective? if( !popLocked && GetHighResTime() > m_objectiveTimer && m_objectives.Size() < 3 ) { Vector3 targetPos; WorldObjectId targetId; bool targetFound = false; if( !targetFound ) targetFound = SearchForDarwinians ( targetPos, targetId ); if( !targetFound ) targetFound = SearchForEnemies ( targetPos, targetId ); if( !targetFound ) targetFound = SearchForSpirits ( targetPos ); if( !targetFound ) targetFound = SearchForScoutArea ( targetPos ); if( targetFound ) { AntObjective *objective = new AntObjective(); objective->m_pos = targetPos; objective->m_targetId = targetId; objective->m_numToSend = 5 + 5 * (g_app->m_difficultyLevel / 10.0); m_objectives.PutData( objective ); } m_objectiveTimer = GetHighResTime() + syncrand() % 5; } // // Send out ants to our existing objectives if( !popLocked && m_objectives.Size() > 0 && GetHighResTime() > m_spawnTimer && m_numAntsInside > 0 ) { Unit *unit = g_app->m_location->GetUnit( WorldObjectId( m_id.GetTeamId(), m_unitId, -1, -1 ) ); if( !unit ) { unit = g_app->m_location->m_teams[m_id.GetTeamId()].NewUnit( Entity::TypeArmyAnt, m_numAntsInside, &m_unitId, m_pos ); } int chosenIndex = syncrand() % m_objectives.Size(); AntObjective *objective = m_objectives[chosenIndex]; Vector3 spawnPos = m_pos; spawnPos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( spawnPos.x, spawnPos.z ); WorldObjectId spawnedId = g_app->m_location->SpawnEntities( spawnPos, m_id.GetTeamId(), m_unitId, Entity::TypeArmyAnt, 1, g_zeroVector, 10.0f ); ArmyAnt *ant = (ArmyAnt *) g_app->m_location->GetEntity( spawnedId ); ant->m_buildingId = m_id.GetUniqueId(); ant->m_front = ( ant->m_pos - m_pos ).Normalise(); ant->m_orders = ArmyAnt::ScoutArea; ant->m_wayPoint = objective->m_pos; ant->m_targetId = objective->m_targetId; float radius = syncfrand(30.0f); float theta = syncfrand(M_PI * 2); ant->m_wayPoint.x += radius * sinf(theta); ant->m_wayPoint.z += radius * cosf(theta); ant->m_wayPoint = ant->PushFromObstructions( ant->m_wayPoint ); ant->m_wayPoint.y = g_app->m_location->m_landscape.m_heightMap->GetValue( ant->m_wayPoint.x, ant->m_wayPoint.z ); m_numAntsInside--; objective->m_numToSend--; if( objective->m_numToSend <= 0 ) { m_objectives.RemoveData( chosenIndex ); } m_spawnTimer = GetHighResTime() + 0.2f - (0.2 * g_app->m_difficultyLevel / 10.0); } // // Convert spirits into ants if( m_numSpiritsInside > 0 && GetHighResTime() > m_eggConvertTimer ) { m_numSpiritsInside--; m_numAntsInside += 3; m_eggConvertTimer = GetHighResTime() + 5.0f; } // // Flicker if we are damaged float healthFraction = (float) m_health / 100.0f; float timeIndex = g_gameTime + m_id.GetUniqueId() * 10; m_renderDamaged = ( frand(0.75f) * (1.0f - fabs(sinf(timeIndex))*1.2f) > healthFraction ); return ( m_health <= 0 ); }
void SoulDestroyer::Attack( Vector3 const &_pos ) { int numFound; g_app->m_location->m_entityGrid->GetEnemies( s_neighbours, _pos.x, _pos.z, SOULDESTROYER_DAMAGERANGE, &numFound, m_id.GetTeamId() ); for( int i = 0; i < numFound; ++i ) { WorldObjectId id = s_neighbours[i]; Entity *entity = (Entity *) g_app->m_location->GetEntity( id ); bool killed = false; Vector3 pushVector = ( entity->m_pos - _pos ); double distance = pushVector.Mag(); if( distance < SOULDESTROYER_DAMAGERANGE ) { g_app->m_soundSystem->TriggerEntityEvent( this, "Attack" ); pushVector.SetLength( SOULDESTROYER_DAMAGERANGE - distance ); g_app->m_location->m_entityGrid->RemoveObject( id, entity->m_pos.x, entity->m_pos.z, entity->m_radius ); entity->m_pos += pushVector; g_app->m_location->m_entityGrid->AddObject( id, entity->m_pos.x, entity->m_pos.z, entity->m_radius ); bool dead = entity->m_dead; entity->ChangeHealth( (SOULDESTROYER_DAMAGERANGE - distance) * -50.0 ); if( !dead && entity->m_dead ) killed = true; } if( killed ) { // Eat the spirit int spiritIndex = g_app->m_location->GetSpirit( id ); if( spiritIndex != -1 ) { g_app->m_location->m_spirits.RemoveData( spiritIndex ); if( m_spirits.NumUsed() < SOULDESTROYER_MAXSPIRITS ) { m_spirits.PutData( (double) GetHighResTime() ); } else { // Doesnt need to be sync safe int index = AppRandom() % SOULDESTROYER_MAXSPIRITS; m_spirits.PutData( (double) GetHighResTime(), index ); } } if(entity->m_type == TypeDarwinian ) { // Create a zombie Zombie *zombie = new Zombie(); zombie->m_pos = entity->m_pos; zombie->m_front = entity->m_front; zombie->m_up = g_upVector; zombie->m_up.RotateAround( zombie->m_front * syncsfrand(1) ); zombie->m_vel = m_vel * 0.5; zombie->m_vel.y = 20.0 + syncfrand(25.0); int index = g_app->m_location->m_effects.PutData( zombie ); zombie->m_id.Set( id.GetTeamId(), UNIT_EFFECTS, index, -1 ); zombie->m_id.GenerateUniqueId(); } } } }
bool LaserFence::Advance () { if( !m_radiusSet ) { Building *building = g_app->m_location->GetBuilding( m_nextLaserFenceId ); if( building ) { m_centrePos = ( building->m_pos + m_pos ) / 2.0f; m_radius = ( building->m_pos - m_pos ).Mag() / 2.0f + m_radius; } m_radiusSet = true; } if( m_mode != ModeDisabled ) { m_sparkTimer -= SERVER_ADVANCE_PERIOD; if( m_sparkTimer < 0.0f ) { m_sparkTimer = 8.0f + syncfrand(4.0f); Spark(); } } switch( m_mode ) { case ModeEnabling: m_status += LASERFENCE_RAISESPEED * SERVER_ADVANCE_PERIOD; if( m_status >= 0.5f && m_nextLaserFenceId != -1 && !m_nextToggled ) { LaserFence *nextFence = (LaserFence *) g_app->m_location->GetBuilding( m_nextLaserFenceId ); if( nextFence ) { nextFence->Enable(); m_nextToggled = true; } } if( m_status >= 1.0f ) { m_status = 1.0f; m_mode = ModeEnabled; if( m_nextLaserFenceId == -1) { g_app->m_location->m_obstructionGrid->CalculateAll(); } } break; case ModeDisabling: if( m_status <= 0.5f && m_nextLaserFenceId != -1 && !m_nextToggled) { LaserFence *nextFence = (LaserFence *) g_app->m_location->GetBuilding( m_nextLaserFenceId ); if( nextFence ) { nextFence->Disable(); m_nextToggled = true; } } m_status -= LASERFENCE_RAISESPEED * SERVER_ADVANCE_PERIOD; if( m_status <= 0.0f ) { m_status = 0.0f; m_mode = ModeDisabled; if( m_nextLaserFenceId == -1) { g_app->m_location->m_obstructionGrid->CalculateAll(); } } break; case ModeEnabled: { if( m_status < 1.0f ) { m_status = 1.0f; if( m_nextLaserFenceId == -1) { g_app->m_location->m_obstructionGrid->CalculateAll(); } } break; } case ModeDisabled: m_status = 0.0f; break; } return Building::Advance(); }