Esempio n. 1
0
void
Turret::serverProcessWaiting(DWORD in_currTime)
{
   Parent::serverProcess(in_currTime);

   if (!getControlClient() && getState () == StaticBase::Enabled && isActive()) {
      targetsTracked = 0;
      Player *closePlayer = chooseTarget ();

      if (targetsTracked)
         sleepTime = manager->getCurrentTime() + 3.0;

      if (closePlayer) {
         if (state == EXTENDED) 
            trackAndFire(closePlayer, 0.032);
         else
            extend (0.032);

      } else if (!targetsTracked && manager->getCurrentTime() > sleepTime) {
         if (state != RETRACTED)
            retract (0.032);
      }
   }
   
   if (!getControlClient())
      updateMove (NULL, 0.032);
   else
      updateSkip++;
}
Esempio n. 2
0
/** Updates an armed swatter: it checks for any karts that are close enough
 *  and not invulnerable, it swats the kart.
 *  \param dt Time step size.
 *  \return True if the attachment should be discarded.
 */
bool Swatter::updateAndTestFinished(float dt)
{
    if (m_removing_bomb)
    {
        m_swat_bomb_frame += dt*25.0f;
        m_scene_node->setRotation(core::vector3df(0.0, -180.0, 0.0));
        
        m_scene_node->setCurrentFrame(m_swat_bomb_frame);
        
        if (m_swat_bomb_frame >= 32.5f && m_bomb_scene_node != NULL)
        {
            m_bomb_scene_node->setPosition(m_bomb_scene_node->getPosition() +
                                      core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
            m_bomb_scene_node->setRotation(m_bomb_scene_node->getRotation() +
                                      core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
        }
        
        if (m_swat_bomb_frame >= m_scene_node->getEndFrame())
        {
            return true;
        }
        else if (m_swat_bomb_frame >= 35)
        {
            if (m_bomb_scene_node != NULL)
            {
                irr_driver->removeNode(m_bomb_scene_node);
                m_bomb_scene_node = NULL;
            }
        }   // bom_frame > 35
        
        return false;
    }   // if removing bomb
    
    switch(m_animation_phase)
    {
    case SWATTER_AIMING:
        {
            chooseTarget();
            pointToTarget();
            if(!m_target) break;

            // Is the target too near?
            float dist_to_target2 = 
                (m_target->getXYZ()- m_scene_node->getAbsolutePosition())
                .length2();
            float min_dist2 
                 = m_kart->getKartProperties()->getSwatterDistance2();
            if(dist_to_target2 < min_dist2)
            {
                // Start squashing
                m_animation_phase = SWATTER_TO_TARGET;

                // Setup the animation
                m_scene_node->setCurrentFrame(0.0f);
                m_scene_node->setLoopMode(false);
                m_scene_node->setAnimationSpeed(SWATTER_ANIMATION_SPEED);
            }
        }
        break;
    case SWATTER_TO_TARGET:
        {
            pointToTarget();

            const float middle_frame    = m_scene_node->getEndFrame()/2.0f;
            float       current_frame   = m_scene_node->getFrameNr();

            // Did we just finish the first part of the movement?
            if(current_frame >= middle_frame)
            {
                // Squash the karts and items around and 
                // change the current phase
                squashThingsAround();
                m_animation_phase = SWATTER_FROM_TARGET;
            }
        }
        break;

    case SWATTER_FROM_TARGET:
        break;
    }

    // If the swatter is used up, trigger cleaning up
    // TODO: use a timeout
    // TODO: how does it work currently...?
    return false;
}   // updateAndTestFinished
Esempio n. 3
0
void Phantom::update()
{
    if(guiSetup) {
        //        if(prevPoint.x==map->getAStar()->getPos(targetID).x&&prevPoint.y==map->getAStar()->getPos(targetID).x) {
        if(map->getAStar()->closedOnTarget(this->id,targetID)) {
            if(targetID!=map->getHero()->id) {
                status = AtDestination;
            }
        }
        if(metaStatus == Patrolling) {
            speed = 0.0125;
            if(status == HackingPort) {
                if( boost::static_pointer_cast<Port>(map->getSquare(program->getPos().x,program->getPos().y))->containsFlag(Port::EnemyOwned)) {
                    status = Walking;
                    program.reset();
                    move();
                }
            } else if(status == HackingNode) {
                if(! boost::static_pointer_cast<Node>(map->getSquare(program->getPos().x,program->getPos().y))->containsFlag(Node::UserOwned)) {
                    status = Walking;
                    program.reset();
                    move();
                }
            } else {
                chooseTarget();
                if(status == Walking) {
                    targetPos = map->getAStar()->getPos(targetID);
                    //                    targetIcon->setPosition(targetPos.x*Terminal::getSingletonPtr()->pixelSize+Terminal::getSingletonPtr()->pixelSize*0.25, targetPos.y*Terminal::getSingletonPtr()->pixelSize+Terminal::getSingletonPtr()->pixelSize*0.25);
                    //                    scanIcon->setPosition(nextPoint.x*Terminal::getSingletonPtr()->pixelSize+Terminal::getSingletonPtr()->pixelSize*0.25, nextPoint.y*Terminal::getSingletonPtr()->pixelSize+Terminal::getSingletonPtr()->pixelSize*0.25);
                    if(abs(nextPoint.x-pos.x)>1&&abs(nextPoint.y-pos.y)>1){
                        status = Idle;
                        chooseTarget();
                        updateR = 1.1;
                    } else {
                        scan();
                        move();
                    }
                }
            }
        } else if(metaStatus == Alarmed) {
            speed = 0.03;
            targetID = map->getHero()->id;
            if(status == Walking) {
                scan();
                move();
                if(abs(nextPoint.x-pos.x)>1&&abs(nextPoint.y-pos.y)>1){
                    //                    status = Idle;
                    //                    chooseTarget();
                    updateR = 1.1;
                }
            } else if(status == HackingPort) {
                if( boost::static_pointer_cast<Port>(map->getSquare(program->getPos().x,program->getPos().y))->containsFlag(Port::EnemyOwned)) {
                    status = Walking;
                    program.reset();
                    move();
                }
            } else if(status == HackingNode) {
                if(! boost::static_pointer_cast<Node>(map->getSquare(program->getPos().x,program->getPos().y))->containsFlag(Node::UserOwned)) {
                    status = Walking;
                    program.reset();
                    move();
                }
            }
        }
    }
}
Esempio n. 4
0
void Phantom::scan()
{
    /*
    4   5   6   7   8
        1   2   3
            0
      */
    scanTimer++;
    if(scanTimer > scanRate) {
        scanNum++;
        if(scanNum>3) {
            scanNum = 0;
        }
        scanTimer = 0;
    }

    switch(scanNum) {
    case 0:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP)scanPos.y+=1;
        if(facing==DOWN)scanPos.y-=1;
        if(facing==LEFT)scanPos.x-=1;
        if(facing==RIGHT)scanPos.x+=1;
        break;
    case 1:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP) {scanPos.x-=1;scanPos.y+=2;}
        if(facing==DOWN) {scanPos.x+=1;scanPos.y-=2;}
        if(facing==LEFT) {scanPos.x-=2;scanPos.y-=1;}
        if(facing==RIGHT) {scanPos.x+=2;scanPos.y+=1;}
        break;
    case 2:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP) {scanPos.y+=2;}
        if(facing==DOWN) {scanPos.y-=2;}
        if(facing==LEFT) {scanPos.x-=2;}
        if(facing==RIGHT) {scanPos.x+=2;}
        break;
    case 3:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP) {scanPos.x+=1;scanPos.y+=2;}
        if(facing==DOWN) {scanPos.x-=1;scanPos.y-=2;}
        if(facing==LEFT) {scanPos.x-=2;scanPos.y+=1;}
        if(facing==RIGHT) {scanPos.x+=2;scanPos.y-=1;}
        break;
    case 4:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP) {scanPos.x-=2;scanPos.y+=3;}
        if(facing==DOWN) {scanPos.x+=2;scanPos.y-=3;}
        if(facing==LEFT) {scanPos.x-=3;scanPos.y-=2;}
        if(facing==RIGHT) {scanPos.x+=3;scanPos.y+=2;}
        break;
    case 5:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP) {scanPos.x-=1;scanPos.y+=3;}
        if(facing==DOWN) {scanPos.x+=1;scanPos.y-=3;}
        if(facing==LEFT) {scanPos.x-=3;scanPos.y-=1;}
        if(facing==RIGHT) {scanPos.x+=3;scanPos.y+=1;}
        break;
    case 6:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP) {scanPos.y+=3;}
        if(facing==DOWN) {scanPos.y-=3;}
        if(facing==LEFT) {scanPos.x-=3;}
        if(facing==RIGHT) {scanPos.x+=3;}
        break;
    case 7:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP) {scanPos.x+=2;scanPos.y+=3;}
        if(facing==DOWN) {scanPos.x-=2;scanPos.y-=3;}
        if(facing==LEFT) {scanPos.x-=3;scanPos.y+=2;}
        if(facing==RIGHT) {scanPos.x+=3;scanPos.y-=2;}
        break;
    case 8:
        scanPos.x = pos.x;
        scanPos.y = pos.y;
        if(facing==UP) {scanPos.x+=1;scanPos.y+=3;}
        if(facing==DOWN) {scanPos.x-=1;scanPos.y-=3;}
        if(facing==LEFT) {scanPos.x-=3;scanPos.y+=1;}
        if(facing==RIGHT) {scanPos.x+=3;scanPos.y-=1;}
        break;
    }
    if(facing==DOWN)scanPos.y+=1;
    if(facing==LEFT)scanPos.x+=1;

    //    scanIcon->setPosition(scanPos.x*Terminal::getSingletonPtr()->pixelSize+Terminal::getSingletonPtr()->pixelSize*0.25, scanPos.y*Terminal::getSingletonPtr()->pixelSize+Terminal::getSingletonPtr()->pixelSize*0.25);

    if(map->getSquare(scanPos.x,scanPos.y)->getChar()==NODE) {
        boost::shared_ptr<Room> parent = boost::static_pointer_cast<Node>((map->getSquare(scanPos.x,scanPos.y)))->getParent();
        if(!(parent->getPort1()->containsFlag(Port::Trojaned)&&parent->getPort2()->containsFlag(Port::Trojaned))) {
            status = HackingNode;
            initProgram(Program::EnemyInfect);
        }
    } else if(map->getHero()->getX() == scanPos.x && map->getHero()->getY()==scanPos.y) {
        if(!map->getHero()->isInvisible()) {
            map->getHero()->addSuspicion(0.25);
            metaStatus = Alarmed;
            status = Walking;
            scanRate = 3;
            targetID = map->getHero()->id;
            map->getHero()->damageHealth(0.01);
            //            std::cout << "HERO DETECTED" << std::endl;
        } else {
            metaStatus = Patrolling;
            //            std::cout << "HERO INVISIBLE" << std::endl;
            if(targetID==map->getHero()->id) {
                chooseTarget();
            }
        }
    } else if(map->getSquare(scanPos.x,scanPos.y)->getChar()==PORT) {
        boost::shared_ptr<Port> port = boost::static_pointer_cast<Port>(map->getSquare(scanPos.x,scanPos.y));
        if(port->containsFlag(Port::Alarmed)) {
            map->getHero()->addSuspicion(-0.001);
        }
        if(port->containsFlag(Port::BlackICED)) {
            map->deletePhantom(this->id);
        } else if(port->containsFlag(Port::Daemoned)) {
            port->explodeDaemon();
            map->deletePhantom(this->id);
        } else if(!port->containsFlag(Port::Trojaned)) {
            status = HackingPort;
            initProgram(Program::EnemyCrack);
        }
    }
}
Esempio n. 5
0
void Enemy::update(float _dt)
{
	if (bIsDead)
	{
		gSound->getSystem()->playSound(FMOD_CHANNEL_FREE, enemyDeath, false, NULL);
		return;
	}
	Pawn::update(_dt);
	//if it has seen the player/follower, decrease its point value over time
	if (bSeenPlayer && mPoints > mMinPoints)
	{
		mPoints -= (mPointDrain * _dt);
		mPoints = max(mMinPoints, mPoints);//if it dropped below min value, push it back up
	}


	mLastPathFound += _dt;//when last path was found
	mAttackTime += _dt;//when last attack was made
	mLoseSightPlayer += _dt;
	mLoseSightFollower += _dt;
	D3DXVECTOR3 targetPosition;
/*	static float aiCheck = 0.0f;
	aiCheck += _dt;
	if (aiCheck >= RUN_AI)//only run the AI every so many frames*/
		//inside this conditional you should use aiCheck where you'd normally use _dt
	{
		switch (mState)
		{
		case PSTATE_WANDER:
			//if they have recently seen player/follower or see them now
			if (mLoseSightPlayer < LOSE_SIGHT || mLoseSightFollower < LOSE_SIGHT ||
				noticeFollower() || noticePlayer())
			{
				if (bAfraid)//if afraid, run
				{
					mState = PSTATE_AFRAID;
					break;
				}
				else
				{
					chooseTarget();
					mState = PSTATE_PURSUE;
					gSound->getSystem()->playSound(FMOD_CHANNEL_FREE, enemyAttack, false, 0);
					break;
				}
			}
			else //if they can't see the player, just wander
				//unless low on health, in which case seek a heal spot
			{
				if (mHealth == mHealthMax)
				{
					if (!followPath(0.75f) && mLastPathFound > MIN_PATH_TIME)
					{
						setPathRandom();
						break;
					}
				}
				else
				{
					mState = PSTATE_INJURED;
					bHealing = false;
					gSound->getSystem()->playSound(FMOD_CHANNEL_FREE, enemyGetHit, false, 0);
					break;
				}
			}
			break;
		case PSTATE_PURSUE:
			//if they no longer see the target, go back to wandering state
			// if pursuing player and doesn't see player and hasn't seen them for a while
			if ((bPursuingPlayer && !noticePlayer() && mLoseSightPlayer >= LOSE_SIGHT) ||
				//if pursuing follower and doesn't see them and hasn't seen them for a while
				(!bPursuingPlayer && !noticeFollower() && mLoseSightFollower >= LOSE_SIGHT))
			{
				mState = PSTATE_WANDER;
				break;
			}
			//if can see their target, but is afraid
			if (bAfraid)
			{
				mState = PSTATE_AFRAID;
				break;
			}
			//otherwise they can see and aren't afraid

			//stop if they are too close to the target, otherwise try to get closer
			if (bPursuingPlayer) targetPosition = gPlayer->getPosition();
			else                 targetPosition = gFollower->getPosition();

			if ((D3DXVec3LengthSq(&(mPosition - targetPosition))) <= mClosestDistanceSq)
			{
				mVelocity = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
			}
			else
			{
				if (mLastPathFound >= MIN_PATH_TIME || !followPath(1.0f))
				{
					if (bPursuingPlayer) setPathPlayer();
					else                setPathFollower();
				}
			}
			//attack if it can
			if (mAttackTime > mAttackDelay)
			{
				if (bPursuingPlayer)
				{
					if (bAttackPlayer)
					{
						attack(gPlayer->getPosition());
						mAttackTime = 0.0f;
						gSound->getSystem()->playSound(FMOD_CHANNEL_FREE, enemyAttack, false, 0);
					}
				}
				else
				{
					if (bAttackFollower)
					{
						attack(gFollower->getPosition());
						mAttackTime = 0.0f;
						gSound->getSystem()->playSound(FMOD_CHANNEL_FREE, enemyAttack, false, 0);
					}
				}
			}
			break;
		case PSTATE_AFRAID:
			//if they reached good health again, they are no longer afraid
			//the add health function will take away fear state when they reach proper hp
			if (!bAfraid)
			{
				mState = PSTATE_WANDER;
				break;
			}
			//if they no longer see the target, go back to wandering state
			// if pursuing player and doesn't see player and hasn't seen them for a while
			if ((bPursuingPlayer && !noticePlayer() && mLoseSightPlayer >= LOSE_SIGHT) ||
				//if pursuing follower and doesn't see them and hasn't seen them for a while
				(!bPursuingPlayer && !noticeFollower() && mLoseSightFollower >= LOSE_SIGHT))
			{
				mState = PSTATE_INJURED;
				break;
			}
			if (mLastPathFound >= MIN_PATH_TIME || !followPath(1.0f))
			{
				setPathFlee();
			}
			//still attack if they are close enough
			if (mAttackTime >= mAttackDelay)
			{
				if (bPursuingPlayer)
				{
					if (bAttackPlayer)
					{
						attack(gPlayer->getPosition());
						mAttackTime = 0.0f;
						gSound->getSystem()->playSound(FMOD_CHANNEL_FREE, enemyAttack, false, 0);
					}
				}
				else
				{
					if (bAttackFollower)
					{
						attack(gFollower->getPosition());
						mAttackTime = 0.0f;
						gSound->getSystem()->playSound(FMOD_CHANNEL_FREE, enemyAttack, false, 0);
					}
				}
			}
			break;
		case PSTATE_INJURED://enemy is injured and cannot presently see player/wanderer
			//if they have recently seen player/follower or see them now
			if (mLoseSightPlayer < LOSE_SIGHT || mLoseSightFollower < LOSE_SIGHT ||
				noticeFollower() || noticePlayer())
			{
				//if they are afraid, flee. If not, pursue
				if (bAfraid)
				{
					mState = PSTATE_AFRAID;
					break;
				}
				else
				{
					chooseTarget();
					mState = PSTATE_PURSUE;
					gSound->getSystem()->playSound(FMOD_CHANNEL_FREE,enemyAttack, false, 0);
					break;
				}
			}
			else//if they don't see the player or follower, find a healing spot to recover
			{
				if (mHealth == mHealthMax)
				{//when fully healed, go back to wandering
					mState = PSTATE_WANDER;
					break;
				}
				if (bHealing)
				{
					stop();
					if (mHealth == mHealthMax)
					{
						bHealing = false;
						mState = PSTATE_WANDER;
						break;
					}
				}
				else
				{
					if (mLastPathFound >= MIN_PATH_TIME || !followPath(1.0f))
					{
						setPathHealing();
					}
				}
			}
			break;
		}
		//rotate to the direction you're going
		pointForward(_dt);
		//update position
		mPosition += mVelocity * _dt;
		detectCollision();
		mMesh->setPosRot(mPosition, mRotation);
	}
}
Esempio n. 6
0
void Turret::serverProcess (DWORD time)
{
	Parent::serverProcess(time);

   if (data->isSustained == false) {
	   if (!getControlClient() && getState () == StaticBase::Enabled && isActive())
	   	{
	   		targetsTracked = 0;
	   		Player *closePlayer = chooseTarget ();

	   		if (targetsTracked)
	   			sleepTime = manager->getCurrentTime() + 3.0;

	   		if (closePlayer)
	   			{
	   				if (state == EXTENDED)
	   					trackAndFire (closePlayer, 0.032);
	   				else
	   					extend (0.032);
	   			}
	   		else
	   			if (!targetsTracked && manager->getCurrentTime() > sleepTime)
	   				{
	   					if (state != RETRACTED)
	   						{
	   							retract (0.032);
	   						}
	   				}
	   	}
	
	   if (!getControlClient())
	   	updateMove (NULL, 0.032);
	   else
	   	updateSkip++;
   } else {
      switch (m_fireState) {
        case Waiting: {
         serverProcessWaiting(time);
         }
         break;

        case Firing: {
         serverProcessFiring(time);
         }
         break;
         
        case Reloading: {
         serverProcessReloading(time);
         }
         break;
         
        default:
         AssertFatal(0, "invalid state");
      }

      if (m_fireState == Firing) {
         float e = getEnergy();
         e -= data->energyRate * 0.032;
         if(e < 0.0) {
            unshoot();
            e = 0.0;
         }
         setEnergy(e);
      }
   }
}
Esempio n. 7
0
int AIMomirPlayer::computeActions()
{
    //Part of the strategy goes here. When should we put a land into play ?
    /*
     Another gift from Alex Majlaton on my first day playing Momir, and it has served me well ever since. It goes a little something like this: (a) if you are on the play, hit your Two through Four, skip your Five, and then hit all the way to Eight; (b) if you are on the draw and your opponent skips his One, you make Two through Eight; (c) if you are on the draw and your opponent hits a One, you match him drop-for-drop for the rest of the game.

     You skip your Five on the play because it is the weakest drop. There are plenty of serviceable guys there, but very few bombs compared to other drops
     the general rule is this: if you want to get to Eight, you have to skip two drops on the play and one drop on the draw.
     */

    Player * p = observer->currentPlayer;
    if (!(observer->currentlyActing() == this)) return 0;
    if (chooseTarget()) return 1;
    int currentGamePhase = observer->getCurrentGamePhase();
    if (observer->isInterrupting == this)
    {   // interrupting
        selectAbility();
        return 1;
    }
    else if (p == this && observer->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0)
    {   //standard actions
        CardDescriptor cd;
        MTGCardInstance * card = NULL;

        switch (currentGamePhase)
        {
        case MTG_PHASE_FIRSTMAIN:
        {
            ManaCost * potentialMana = getPotentialMana();
            int converted = potentialMana->getConvertedCost();
            SAFE_DELETE(potentialMana);

            if (converted < 8 || game->hand->nb_cards > 1)
            {
                //Attempt to put land into play
                cd.init();
                cd.setColor(Constants::MTG_COLOR_LAND);
                card = cd.match(game->hand);
                int canPutLandsIntoPlay = game->playRestrictions->canPutIntoZone(card, game->inPlay);
                if (card && (canPutLandsIntoPlay == PlayRestriction::CAN_PLAY))
                {
                    MTGAbility * putIntoPlay = observer->mLayers->actionLayer()->getAbility(MTGAbility::PUT_INTO_PLAY);
                    AIAction * a = NEW AIAction(this, putIntoPlay, card); //TODO putinplay action
                    clickstream.push(a);
                    return 1;
                }
            }
            momir();
            return 1;
            break;
        }
        case MTG_PHASE_SECONDMAIN:
            selectAbility();
            return 1;
            break;
        default:
            return AIPlayerBaka::computeActions();
            break;
        }
    }
    return AIPlayerBaka::computeActions();
}
void ShootingAI::think(double dt) {
   // Whether or not the ship should fire.
   bool shouldFire = false;

   // If the ShootingAI isn't enabled, or there's no gamestate, skip shooting.
   if(!enabled || ship->gameState == NULL) {
      return;
   }

   /* Also, do we want to try and rechoose a target every think (ie frame)?
    * If not, it would make the shooter a little quicker, but may end up
    * shooting at bad targets (if the gun is pointed in the opposite direction,
    * it will take time to rotate it around to shoot the target, then
    * time to kill the asteroid, and throughout all this time a new asteroid
    * could have become a better target, or even a critical target)
    *
    * Just an idea, we will talk it over.
    */
   if (targetID != -1) {
      target = ship->gameState->custodian[targetID];
   }

   /* If there is no target, or we need to choose a target b/c the old one
    * went off screen, or if the timer is up and we're allowed to switch
    * targets.
    */
   if (target == NULL || needToChooseTarget || (targetSwitchTimer.isRunning && targetSwitchTimer.getTimeLeft() <= 0)) {
      target = chooseTarget();
      // If there was nothing on screen, target could have wound up NULL
      if (target != NULL) {
         targetID = target->id;
         targetSwitchTimer.restartCountDown();
         // If the chosen target is a Shard, remember that till the next time we choose a target.
         if (target->type == TYPE_SHARD)
            targetIsAShard = true;
         else
            targetIsAShard = false;
      }
   }

   // If it's been more than weaponSwitchSpeed seconds, we can switch weapons.
   // Don't bother choosing a weapon if target is NULL
   if (target != NULL && weaponSwitchTimer.isRunning && weaponSwitchTimer.getTimeLeft() <= 0) {
      prevWeapon = ship->getCurrentWeapon();
      chooseWeapon(target);
      // If we chose a new weapon, reset the timer so we can't switch again soon.
      if (prevWeapon != chosenWeapon) {
         weaponSwitchTimer.restartCountDown();
      }
   }

   // If we've got an actual target
   if (target != NULL) {
      // aimAt aims the cursos and returns whether or not the ship is ready to fire.
      shouldFire = aimAt(dt, target);
      // Make sure we don't fire incorrect weapons at shards.
      if (targetIsAShard) {
         // If the current weapon is not a tractor beam.
         if (ship->currentWeapon != TRACTOR_WEAPON_INDEX) {
            // Don't fire.
            shouldFire = false;
         }
      }
      ship->fire(shouldFire);
   }
   // Otherwise we've got no target
   else {
      // Aim the cursor in front of the ship
      aimCursorAtMiddle(dt);
      // Make sure we stop firing.
      ship->fire(false);
   }
}