/* base/platform.cc This file is part of the Osirion project and is distributed under the terms and conditions of the GNU General Public License version 2 */ #include "core/gameserver.h" #include "core/entityprojectile.h" #include "base/game.h" #include "base/faction.h" #include "base/platform.h" #include "base/ship.h" #include "base/weapon.h" #include "sys/sys.h" #include namespace game { Platform::Platform() : Entity() { entity_moduletypeid = platform_enttype; platform_cannon = 0; platform_turret = 0; } Platform::~Platform() { } void Platform::set_cannon(const Weapon *cannon) { platform_cannon = cannon; } void Platform::set_turret(const Weapon *turret) { platform_turret = turret; } void Platform::frame(const unsigned long elapsed) { const float weapon_range = math::max((cannon() ? cannon()->projectile_range() : 0.0f), (turret() ? turret()->projectile_range() : 0.0f)); if ((weapon_range > 0.0f) && slots() && zone()->keepalive_run()) { // create list of potential enemies std::list enemylist; for (core::Zone::Content::iterator zit = zone()->content().begin(); zit != zone()->content().end(); ++zit) { if ((*zit)->moduletype() == ship_enttype) { Ship *other_ship = static_cast((*zit)); if ((other_ship->state() != Normal) && (other_ship->state() != ImpulseInitiate) && (other_ship->state() != Impulse)) { continue; } const float d = math::distance(location(), other_ship->location()); const float r = radius() + other_ship->radius(); // too far if (d > weapon_range + r) { continue; } // reputation is interprated as "what others think of me" float reputation = 0.0f; if (other_ship->owner()) { // check owner reputation for the faction this platform belongs to reputation = other_ship->owner()->reputation(faction()); } else if (other_ship->faction()) { // check other ships's faction for the faction this platform belongs to assert(other_ship->faction()->type() == Faction::infotype()); reputation = static_cast(other_ship->faction())->reputation(faction()); } // reputation threshold to get attacked if (reputation > core::range::reputation_hostile) { continue; } enemylist.push_back(other_ship); } } // platforms do not need weapons in inventory to fire if (enemylist.size()) { for (core::Slots::iterator slit = slots()->begin(); slit != slots()->end(); slit++) { core::Slot *slot = (*slit); // found out if this slot is a cannon or a turret const Weapon *weapon = 0; if (slot->type() == model::Slot::Cannon) { weapon = cannon(); } else if (slot->type() == model::Slot::Turret) { weapon = turret(); } if ((!weapon) || (weapon->projectile_interval() == 0)) { continue; } if ((slot->last_fired() + weapon->projectile_interval() > core::server()->timestamp())) { continue; } // find a target for this slot Ship *current_enemy = 0; float current_distance = 0.0f; math::Vector3f projectile_location(location() + (axis() * slot->location())); math::Vector3f projectile_direction; math::Axis projectile_axis(axis() * slot->axis()); math::Vector3f aim_location; // we only need half the cone angle for the cosine calculation const float conecos = cosf(slot->cone() * 0.5f); for (std::list::const_iterator enemy_it = enemylist.begin(); enemy_it != enemylist.end(); enemy_it++) { const float d = math::distance((*enemy_it)->location(), projectile_location); if (d > weapon->projectile_range() + (*enemy_it)->radius()) { continue; } if ((current_distance > 0) && (d > current_distance)) { continue; } aim_location.assign((*enemy_it)->location() + (*enemy_it)->axis().forward() * ( (*enemy_it)->radius() * 0.25f)); projectile_direction.assign(aim_location - projectile_location); projectile_direction.normalize(); const float cosa = math::dotproduct(projectile_direction, projectile_axis.forward()); // check if the ship is in the slot's cone if fire if (cosa >= conecos) { current_distance = d; current_enemy = (*enemy_it); } } if (current_enemy) { aim_location.assign(current_enemy->location() + current_enemy->axis().forward() * (current_enemy->radius() * 0.25f)); projectile_direction.assign(aim_location - projectile_location); projectile_direction.normalize(); const float cosa = math::dotproduct(projectile_direction, projectile_axis.forward()); // point the projectile into the fire direction math::Vector3f normal(math::crossproduct(projectile_direction, projectile_axis.forward())); if (normal.length() > MIN_DELTA) { float sina = sqrt(1.0f - cosa * cosa); normal.normalize(); projectile_axis.rotate(normal, cosa, sina); } // spawn a new projectile core::EntityProjectile *projectile = new core::EntityProjectile(this); projectile->set_damage(weapon->damage()); projectile->set_lifespan(weapon->projectile_lifespan()); projectile->set_projectile_modelname(weapon->projectile_modelname()); projectile->set_projectile_soundname(weapon->projectile_soundname()); projectile->set_axis(projectile_axis); projectile->set_location(projectile_location); projectile->set_speed(weapon->projectile_speed()); projectile->reset(); slot->set_last_fired(core::server()->timestamp()); } } } } } }