/* * ORXONOX - the hottest 3D action shooter ever to exist * > www.orxonox.net < * * * License notice: * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * Fabian 'x3n' Landau * Co-authors: * Dominik Solenicki * */ #include "controllers/CommonController.h" /* #include "weaponsystem/WeaponMode.h" #include "weaponsystem/WeaponPack.h" #include "weaponsystem/Weapon.h" #include "weaponsystem/WeaponSlot.h" #include "weaponsystem/WeaponSlot.h" #include "worldentities/pawns/SpaceShip.h" */ namespace orxonox { RegisterClass(CommonController); static const float SPEED = 0.6f; static const float ROTATEFACTOR = 0.2f; CommonController::CommonController(Context* context) : Controller(context) { //this->bSetupWorked = false; RegisterObject(CommonController); } CommonController::~CommonController() { } bool CommonController::setWingman (CommonController* wingman) { return false; } bool CommonController::hasWingman() { return true; } void CommonController::setTargetPosition(const Vector3& target) { this->targetPosition_ = target; this->bHasTargetPosition_ = true; } void CommonController::setTargetOrientation(const Quaternion& orient) { this->targetOrientation_=orient; this->bHasTargetOrientation_=true; } void CommonController::setTargetOrientation(ControllableEntity* target) { if (target) setTargetOrientation(target->getOrientation()); } /*void CommonController::spin() { this->moveToTargetPosition(); this->getControllableEntity()->rotateRoll(8.0f); } void CommonController::turn180() { Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->targetPosition_); this->getControllableEntity()->rotateYaw(-2.0f * sgn(coord.x) * coord.x*coord.x); this->getControllableEntity()->rotatePitch(2.0f * sgn(coord.y) * coord.y*coord.y); this->getControllableEntity()->moveFrontBack(SPEED); }*/ //copy the Roll orientation of given Quaternion. void CommonController::copyOrientation(const Quaternion& orient) { //roll angle difference in radian float diff=orient.getRoll(false).valueRadians()-(this->getControllableEntity()->getOrientation().getRoll(false).valueRadians()); while(diff>math::twoPi) diff-=math::twoPi; while(diff<-math::twoPi) diff+=math::twoPi; this->getControllableEntity()->rotateRoll(-diff); } void CommonController::copyTargetOrientation() { if (bHasTargetOrientation_) { copyOrientation(targetOrientation_); } } void CommonController::moveToTargetPosition() { this->moveToPosition(this->targetPosition_); } void CommonController::moveToPosition(const Vector3& target) { if (!this->getControllableEntity()) return; //100 is (so far) the smallest tolerance (empirically found) that can be reached, //with smaller distance spaceships can't reach position and go circles around it instead int tolerance = 100; ControllableEntity* entity = this->getControllableEntity(); Vector2 coord = get2DViewCoordinates (entity->getPosition(), entity->getOrientation() * WorldEntity::FRONT, entity->getOrientation() * WorldEntity::UP, target); float distance = (target - this->getControllableEntity()->getPosition()).length(); //rotates should be in range [-1,+1], clamp cuts off all that is not float rotateX = clamp(coord.x * 10, -1.0f, 1.0f); float rotateY = clamp(coord.y * 10, -1.0f, 1.0f); if (distance > tolerance) { //Yaw and Pitch are enough to start facing the target this->getControllableEntity()->rotateYaw(-2.0f * ROTATEFACTOR * rotateX); this->getControllableEntity()->rotatePitch(2.0f * ROTATEFACTOR * rotateY); //300 works, maybe less is better if (distance < 300) { //Change roll when close. When Spaceship faces target, roll doesn't affect it's trajectory //It's important that roll is not changed in the process of changing yaw and pitch //Wingmen won't face same direction as Leaders, but when Leaders start moving //Yaw and Pitch will adapt. if (bHasTargetOrientation_) { copyTargetOrientation(); } } this->getControllableEntity()->moveFrontBack(1.2f*SPEED); } else { bHasTargetPosition_ = false; bHasTargetOrientation_ = false; } } /* int CommonController::getFiremode(std::string name) { for (std::map< std::string, int >::iterator it = this->weaponModes_.begin(); it != this->weaponModes_.end(); ++it) { if (it->first == name) return it->second; } return -1; } bool CommonController::isCloseAtTarget(float distance) const { if (!this->getControllableEntity()) return false; if (!this->target_) return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) < distance*distance); else return (this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance); } void CommonController::setupWeapons() //TODO: Make this function generic!! (at the moment is is based on conventions) { this->bSetupWorked = false; if(this->getControllableEntity()) { Pawn* pawn = orxonox_cast(this->getControllableEntity()); if(pawn && pawn->isA(Class(SpaceShip))) //fix for First Person Mode: check for SpaceShip { this->weaponModes_.clear(); // reset previous weapon information WeaponSlot* wSlot = 0; for(int l=0; (wSlot = pawn->getWeaponSlot(l)) ; l++) { WeaponMode* wMode = 0; for(int i=0; (wMode = wSlot->getWeapon()->getWeaponmode(i)) ; i++) { std::string wName = wMode->getIdentifier()->getName(); if(this->getFiremode(wName) == -1) //only add a weapon, if it is "new" weaponModes_[wName] = wMode->getMode(); } } if(weaponModes_.size())//at least one weapon detected this->bSetupWorked = true; }//pawn->weaponSystem_->getMunition(SubclassIdentifier< Munition > *identifier)->getNumMunition (WeaponMode *user); } } void CommonController::doFire() { if(!this->bSetupWorked)//setup: find out which weapons are active ! hard coded: laser is "0", lens flare is "1", ... { this->setupWeapons(); } else if(this->getControllableEntity() && weaponModes_.size()&& this->bShooting_ && this->isCloseAtTarget((3)*1000) && this->isLookingAtTarget(math::pi / 20.0f)) { int firemode; float random = rnd(1);// if (this->isCloseAtTarget(130) && (firemode = getFiremode("LightningGun")) > -1 ) {//LENSFLARE: short range weapon this->getControllableEntity()->fire(firemode); //ai uses lens flare if they're close enough to the target } else if ((firemode = getFiremode("HsW01")) > -1 ) //LASER: default weapon this->getControllableEntity()->fire(firemode); } } bool CommonController::isLookingAtTarget(float angle) const { if (!this->getControllableEntity()) return false; return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle); } void CommonController::aimAtTarget() { if (!this->target_ || !this->getControllableEntity()) return; static const float hardcoded_projectile_speed = 750; Vector3 aimPosition = getPredictedPosition(this->getControllableEntity()->getWorldPosition(), hardcoded_projectile_speed, this->target_->getWorldPosition(), this->target_->getVelocity()); Pawn* pawn = orxonox_cast(this->getControllableEntity()); if (pawn) pawn->setAimPosition(aimPosition); }*/ }