示例#1
0
/*!
  In \a phase 0, increment the missile's age and return if
  the missile has expired. If not, move the missile based
  on its current position and velocity. Then get the its
  list of colliding sprites and traverse the list. When a
  rock is found in the list, mark both the rock and the
  missile dead and return.

  In phase 1, if the missile is marked dead, delete it;
  \internal
 */
void KMissile::advance(int phase)
{
    if (phase == 0) {
	if (dying())
	    markDead();
	else
	    incrementAge();
	if (isDead())
	    return;
	KSprite::advance(phase);
        QList<QGraphicsItem*> hits = collidingItems();
        QList<QGraphicsItem*>::iterator i;
        for (i=hits.begin(); i!=hits.end(); ++i) {
	    if ((*i)->type() > ID_Base) {
		KSprite* sprite = (KSprite*)(*i);
		if (sprite->isRock()) {
		    sprite->markDead();
		    markDead();
		    break;
		}
	    }
        }
    }
    else if (isDead() || dying())
	delete this;
}
示例#2
0
void LLHUDEffectBeam::packData(LLMessageSystem *mesgsys)
{
	LLViewerObject* source_object = (LLViewerObject*)mSourceObject;

	if (!source_object)
	{
		markDead();
		return;
	}
	else if (!source_object->isAvatar())
	{
		LL_DEBUGS("HUDEffect")<<"Non-Avatar HUDEffectBeam message for ID: " 
			<<  source_object->getID().asString()<< LL_ENDL;
		markDead();
		return;
	}
	else 
	{
		LLVOAvatar* source_avatar = (LLVOAvatar*)source_object;
		if (!source_avatar->isSelf())
		{
			LL_DEBUGS("HUDEffect")<<"Non-self HUDEffectBeam message for ID: " 
				<< source_avatar->getID().asString()<< LL_ENDL;
			markDead();
			return;
		}
	}

	// Pack the default data
	LLHUDEffect::packData(mesgsys);

	// Pack the type-specific data.  Uses a fun packed binary format.  Whee!
	// 16 + 24 + 1 = 41
	U8 packed_data[41];
	memset(packed_data, 0, 41);
	if (mSourceObject)
	{
		htonmemcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16);
	}

	if (mTargetObject)
	{
		packed_data[16] = 1;
	}
	else
	{
		packed_data[16] = 0;
	}

	if (mTargetObject)
	{
		htonmemcpy(&(packed_data[17]), mTargetObject->mID.mData, MVT_LLUUID, 16);
	}
	else
	{
		htonmemcpy(&(packed_data[17]), mTargetPos.mdV, MVT_LLVector3d, 24);
	}
	mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, 41);
}
示例#3
0
void LLSpatialBridge::updateDistance(LLCamera& camera_in)
{
	if (mDrawable == NULL)
	{
		markDead();
		return;
	}

	LLCamera camera = transformCamera(camera_in);
	
	mDrawable->updateDistance(camera);
	
	if (mDrawable->getVObj())
	{
		LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
			 iter != child_list.end(); iter++)
		{
			LLViewerObject* child = *iter;
			LLDrawable* drawable = child->mDrawable;					
			if (!drawable)
			{
				llwarns << "Corrupt drawable found while updating spatial bridge distance." << llendl;
				continue;
			}

			if (!drawable->isAvatar())
			{
				drawable->updateDistance(camera);
			}
		}
	}
}
示例#4
0
void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
{
	if (mDrawable == NULL)
	{
		markDead();
		return;
	}

	LLCamera camera = transformCamera(camera_in);
	
	mDrawable->updateDistance(camera, force_update);
	
	if (mDrawable->getVObj())
	{
		LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
			 iter != child_list.end(); iter++)
		{
			LLViewerObject* child = *iter;
			LLDrawable* drawable = child->mDrawable;					
			if (!drawable)
			{
				continue;
			}

			if (!drawable->isAvatar())
			{
				drawable->updateDistance(camera, force_update);
			}
		}
	}
}
//-----------------------------------------------------------------------------
// update()
//-----------------------------------------------------------------------------
void LLHUDEffectLookAt::update()
{
    static const LLCachedControl<bool> show_look_at("AscentShowLookAt", false);

    // If the target object is dead, set the target object to NULL
    if (!mTargetObject.isNull() && mTargetObject->isDead())
    {
        clearLookAtTarget();
    }

    // if source avatar is null or dead, mark self as dead and return
    if (mSourceObject.isNull() || mSourceObject->isDead())
    {
        markDead();
        return;
    }

    // make sure the proper set of avatar attention are currently being used.
    LLVOAvatar* source_avatar = (LLVOAvatar*)(LLViewerObject*)mSourceObject;
    // for now the first cut will just switch on sex. future development could adjust
    // timeouts according to avatar age and/or other features.
    mAttentions = (source_avatar->getSex() == SEX_MALE) ? &gBoyAttentions : &gGirlAttentions;
    //printf("updated to %s\n", (source_avatar->getSex() == SEX_MALE) ? "male" : "female");

    F32 time = mTimer.getElapsedTimeF32();

    // clear out the effect if time is up
    if (mKillTime != 0.f && time > mKillTime)
    {
        if (mTargetType != LOOKAT_TARGET_NONE)
        {
            clearLookAtTarget();
            // look at timed out (only happens on own avatar), so tell everyone
            setNeedsSendToSim(TRUE);
        }
    }

    if (mTargetType != LOOKAT_TARGET_NONE)
    {
        if (calcTargetPosition())
        {
            //LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT);
            //if (!head_motion || head_motion->isStopped())
            // singu: startMotion does basically the same as the above two lines... it starts it, unless it was already started.
            {
                ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->startMotion(ANIM_AGENT_HEAD_ROT);
            }
        }
    }

    // Singu note: this displays extra information for look at targets. Due to the bug in llvoavatar.cpp
    // it was never displayed before and is not something users exect: turning it off for now
#if 0
    if (show_look_at)
    {
        ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->addDebugText((*mAttentions)[mTargetType].mName);
    }
#endif
}
示例#6
0
void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
{
	if (mDrawable == NULL)
	{
		markDead();
		return;
	}

	if (gShiftFrame)
	{
		return;
	}

	if (mDrawable->getVObj())
	{
		if (mDrawable->getVObj()->isAttachment())
		{
			LLDrawable* parent = mDrawable->getParent();
			if (parent)
			{
				LLViewerObject *obj = parent->getVObj();
				if (obj && obj->isAvatar() && ((LLVOAvatar*)obj)->isImpostor())
				{
					return;
				}
			}
			else
			{
				static const LLCachedControl<bool> draw_orphans("ShyotlDrawOrphanAttachments",false);
				if(!draw_orphans)
					return;
			}
		}

		LLCamera camera = transformCamera(camera_in);
	
		mDrawable->updateDistance(camera, force_update);
	
		LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
			 iter != child_list.end(); iter++)
		{
			LLViewerObject* child = *iter;
			LLDrawable* drawable = child->mDrawable;					
			if (!drawable)
			{
				continue;
			}

			if (!drawable->isAvatar())
			{
				drawable->updateDistance(camera, force_update);
			}
		}
	}
}
示例#7
0
//-----------------------------------------------------------------------------
// update()
//-----------------------------------------------------------------------------
void LLHUDEffectLookAt::update()
{
	LLHUDEffectLookAt::sDebugLookAt = gSavedSettings.getBOOL("PersistShowLookAt");

	// If the target object is dead, set the target object to NULL
	if (!mTargetObject.isNull() && mTargetObject->isDead())
	{
		clearLookAtTarget();
	}

	// if source avatar is null or dead, mark self as dead and return
	if (mSourceObject.isNull() || mSourceObject->isDead())
	{
		markDead();
		return;
	}

	// make sure the proper set of avatar attention are currently being used.
	LLVOAvatar* source_avatar = (LLVOAvatar*)(LLViewerObject*)mSourceObject;
	// for now the first cut will just switch on sex. future development could adjust 
	// timeouts according to avatar age and/or other features. 
	mAttentions = (source_avatar->getSex() == SEX_MALE) ? &gBoyAttentions : &gGirlAttentions;
	//printf("updated to %s\n", (source_avatar->getSex() == SEX_MALE) ? "male" : "female");

	F32 time = mTimer.getElapsedTimeF32();

	// clear out the effect if time is up
	if (mKillTime != 0.f && time > mKillTime)
	{
		if (mTargetType != LOOKAT_TARGET_NONE)
		{
			clearLookAtTarget();
			// look at timed out (only happens on own avatar), so tell everyone
			setNeedsSendToSim(TRUE);
		}
	}

	if (mTargetType != LOOKAT_TARGET_NONE)
	{
		if (calcTargetPosition())
		{
			LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT);
			if (!head_motion || head_motion->isStopped())
			{
				((LLVOAvatar*)(LLViewerObject*)mSourceObject)->startMotion(ANIM_AGENT_HEAD_ROT);
			}
		}
	}

	if (sDebugLookAt)
	{
		((LLVOAvatar*)(LLViewerObject*)mSourceObject)->addDebugText((*mAttentions)[mTargetType].mName);
	}
}
示例#8
0
/*!
  This function is called by QGraphicsScene::advance().
  It is called twice for each item at each animation step,
  first with \a phase = 0, and then with \a phase = 1.

  In phase 0, each item moves itself. In phase 1, each item
  that is responsible for handling collisions detects its
  collisions and handles them.

  Note: Each subclass of this base class must implement
  advance() and call this function when \a phase == 0.
  \internal
 */
void
KSprite::advance(int phase)
{
    if (phase == 0) {
	if (dying())
	    markDead();
	if ((vx_ != 0.0) || (vy_ != 0.0)) {
	    moveBy(vx_,vy_);
	    wrap();
	}
    }
}
示例#9
0
void LLHUDEffectSpiral::render()
{
	F32 time = mTimer.getElapsedTimeF32();

	if ((!mSourceObject.isNull() && mSourceObject->isDead()) ||
	    (!mTargetObject.isNull() && mTargetObject->isDead()) ||
	    mKillTime < time ||
		(!mPartSourcep.isNull() && !gSavedSettings.getBOOL("ShowSelectionBeam")) )
	{
		markDead();
		return;
	}
}
void LLHUDEffectSpiral::render()
{
	F32 time = mTimer.getElapsedTimeF32();

	static BOOL* sShowSelectionBeam = rebind_llcontrol<BOOL>("ShowSelectionBeam", &gSavedSettings, true);

	if ((!mSourceObject.isNull() && mSourceObject->isDead()) ||
	    (!mTargetObject.isNull() && mTargetObject->isDead()) ||
	    mKillTime < time ||
		(!mPartSourcep.isNull() && !*sShowSelectionBeam) )
	{
		markDead();
		return;
	}
}
示例#11
0
/*!
  In phase 0, age the exhaust and mark it dead if it has
  expired. Also advance the exhaust image and move the
  exhaust with the ship.

  In phase 1, if the exhaust has been marked dead,
  destroy it.
  \internal
 */
void KExhaust::advance(int phase)
{
    if (phase == 0) {
	if (dying())
	    markDead();
	else
	    incrementAge();
	if (isDead())
	    return;
	advanceImage();
	KSprite::advance(phase);
    }
    else if (isDead() || dying())
	delete this;
}
示例#12
0
/*!
  This function is only called by \l QGraphicsScene::advance().

  The shield's position is always computed from the ship's
  position, so the shield is not moved here. Neither is the
  shield destroyed here, because the shield is meant to
  exist for as long as the ship exists. The only thing that
  happens here is that in \a phase 1 the shield is either
  shown or hidden depending on whether it is marked as
  being up or not.

  The shield is created when the ship is created. The shield
  is deleted when the ship is deleted.

  \internal
 */
void KShield::advance(int phase)
{
    if ((phase == 0) && dying())
	markDead();
    else if (phase == 1) {
	if (isDead() || dying()) {
	    delete this;
	    return;
	}
	if (isUp())
	    show();
	else
	    hide();
    }
}
void LLHUDEffectSpiral::render()
{
	F32 time = mTimer.getElapsedTimeF32();

	static LLCachedControl<bool> showSelectionBeam(gSavedSettings, "ShowSelectionBeam"); // <FS:Ansariel> Performance tweak
	if ((!mSourceObject.isNull() && mSourceObject->isDead()) ||
	    (!mTargetObject.isNull() && mTargetObject->isDead()) ||
	    mKillTime < time ||
		// <FS:Ansariel> Performance tweak
		//(!mPartSourcep.isNull() && !gSavedSettings.getBOOL("ShowSelectionBeam")) )
		(!mPartSourcep.isNull() && !showSelectionBeam) ) 
	{
		markDead();
		return;
	}
}
示例#14
0
/*!
  In phase 0, age the powerup sprite and move it
  based on its current position and velocity.

  In phase 1, if the powerup has been marked for
  being applied to the ship, increase the ship's
  fire power.
  \internal
 */
void KShootPowerup::advance(int phase)
{
    if (phase == 0) {
	if (dying())
	    markDead();
	else
	    incrementAge();
	KSprite::advance(phase);
    }
    else {
	if (apply() && ship_)
	    ship_->incrementFirePower();
	if (isDead() || dying())
	    delete this;
    }
}
示例#15
0
/*!
  In phase 0, age the powerup sprite and move it
  based on its current position and velocity.

  In phase 1, if the powerup has been marked for
  being applied to the ship, increase the ship's
  power level.
  \internal
 */
void KEnergyPowerup::advance(int phase)
{
    if (phase == 0) {
	if (dying())
	    markDead();
	else
	    incrementAge();
	KSprite::advance(phase);
    }
    else {
	if (apply() && ship_)
	    ship_->increasePowerLevel(FUEL_POWERUP_BONUS);
	if (isDead() || dying())
	    delete this;
    }
}
示例#16
0
void Changer::clearBeforeMove_impl() {
    markDead();
    // remove dead
    eraseElements(remaining_actions_, -1);
    eraseElements(remaining_pseudo_actions_, -1);
    eraseElements(completed_commands_, -1);
    // clear model
    model_->clearBeforeMove(team_);
    // resize Changer's private vectors
    int bacteria = getBacteriaNumber_impl();
    remaining_actions_.resize(bacteria, MAX_ACTIONS);
    remaining_pseudo_actions_.resize(bacteria, MAX_PSEUDO_ACTIONS);
    completed_commands_.resize(bacteria, 0);
    // max remaining actions (because of new move)
    for (int b = 0; b < bacteria; b++) {
        remaining_actions_[b] = MAX_ACTIONS;
        remaining_pseudo_actions_[b] = MAX_PSEUDO_ACTIONS;
    }
}
void LLHUDEffectBlob::render()
{
	F32 time = mTimer.getElapsedTimeF32();
	if (mDuration < time)
	{
		markDead();
	}

	LLVector3 pos_agent = gAgent.getPosAgentFromGlobal(mPositionGlobal);

	LLVector3 pixel_up, pixel_right;

	LLViewerCamera::instance().getPixelVectors(pos_agent, pixel_up, pixel_right);

	LLGLSPipelineAlpha gls_pipeline_alpha;
	gGL.getTexUnit(0)->bind(mImage->getImage());

	LLColor4U color = mColor;
	color.mV[VALPHA] = (U8)clamp_rescale(time, 0.f, mDuration, 255.f, 0.f);
	gGL.color4ubv(color.mV);

	{ gGL.pushMatrix();
		gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]);
		LLVector3 u_scale = pixel_right * (F32)mPixelSize;
		LLVector3 v_scale = pixel_up * (F32)mPixelSize;
		
		{ gGL.begin(LLRender::QUADS);
			gGL.texCoord2f(0.f, 1.f);
			gGL.vertex3fv((v_scale - u_scale).mV);
			gGL.texCoord2f(0.f, 0.f);
			gGL.vertex3fv((-v_scale - u_scale).mV);
			gGL.texCoord2f(1.f, 0.f);
			gGL.vertex3fv((-v_scale + u_scale).mV);
			gGL.texCoord2f(1.f, 1.f);
			gGL.vertex3fv((v_scale + u_scale).mV);
		} gGL.end();

	} gGL.popMatrix();
}
//-----------------------------------------------------------------------------
// update()
//-----------------------------------------------------------------------------
void LLHUDEffectPointAt::update()
{
	// If the target object is dead, set the target object to NULL
	if (!mTargetObject.isNull() && mTargetObject->isDead())
	{
		clearPointAtTarget();
	}

	if (mSourceObject.isNull() || mSourceObject->isDead())
	{
		markDead();
		return;
	}
	
	F32 time = mTimer.getElapsedTimeF32();

	// clear out the effect if time is up
	if (mKillTime != 0.f && time > mKillTime)
	{
		mTargetType = POINTAT_TARGET_NONE;
	}

	if (mSourceObject->isAvatar())
	{
		if (mTargetType == POINTAT_TARGET_NONE)
		{
			((LLVOAvatar*)(LLViewerObject*)mSourceObject)->removeAnimationData("PointAtPoint");
		}
		else
		{
			if (calcTargetPosition())
			{
				((LLVOAvatar*)(LLViewerObject*)mSourceObject)->startMotion(ANIM_AGENT_EDITING);
			}
		}
	}
}
void LLHUDEffectBeam::render()
{
	if (!mSourceObject)
	{
		markDead();
		return;
	}
	if (mSourceObject->isDead())
	{
		markDead();
		return;
	}

	F32 time = mTimer.getElapsedTimeF32();

	// Kill us if our time is over...
	if (mKillTime < time)
	{
		markDead();
		return;
	}

	LLGLSPipelineAlpha gls_pipeline_alpha;
	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);


	// Interpolate the global fade alpha
	mFadeInterp.update(time);

	if (mTargetObject.notNull() && mTargetObject->mDrawable.notNull())
	{
		// use viewer object position on freshly created objects
		if (mTargetObject->mDrawable->getGeneration() == -1)
		{
			mTargetPos = mTargetObject->getPositionGlobal();
		}
		// otherwise use drawable
		else
		{
			mTargetPos = gAgent.getPosGlobalFromAgent(mTargetObject->mDrawable->getPositionAgent());
		}
	}


	// Init the color of the particles
	LLColor4U coloru = mColor;

	// Draw the particles
	S32 i;
	for (i = 0; i < NUM_POINTS; i++)
	{
		mInterp[i].update(time);
		if (!mInterp[i].isActive())
		{
			continue;
		}
		mInterpFade[i].update(time);

		if (mInterp[i].isDone())
		{
			// Reinitialize the particle when the particle has finished its animation.
			setupParticle(i);
		}

		F32 frac = mInterp[i].getCurFrac();
		F32 scale = 0.025f + fabs(0.05f*sin(2.f*F_PI*(frac - time)));
		scale *= mInterpFade[i].getCurVal();

		LLVector3 pos_agent = gAgent.getPosAgentFromGlobal(mInterp[i].getCurVal());

		F32 alpha = mFadeInterp.getCurVal()*mColor.mV[3];
		alpha *= mInterpFade[i].getCurVal();
		coloru.mV[3] = (U8)alpha;
		glColor4ubv(coloru.mV);

		glPushMatrix();
		glTranslatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]);
		glScalef(scale, scale, scale);
		gSphere.render(0);
		glPopMatrix();
	}
}
示例#20
0
TrieadOwner::~TrieadOwner()
{
	markDead();
}
示例#21
0
void LLHUDEffectSpiral::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
{
	const size_t EFFECT_SIZE = 56;
	U8 packed_data[EFFECT_SIZE];

	LLHUDEffect::unpackData(mesgsys, blocknum);
	LLUUID object_id, target_object_id;
	S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData);
	if (size != EFFECT_SIZE)
	{
		llwarns << "Spiral effect with bad size " << size << llendl;
		return;
	}
	mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, 
		packed_data, EFFECT_SIZE, blocknum, EFFECT_SIZE);
	
	htonmemcpy(object_id.mData, packed_data, MVT_LLUUID, 16);
	htonmemcpy(target_object_id.mData, packed_data + 16, MVT_LLUUID, 16);
	htonmemcpy(mPositionGlobal.mdV, packed_data + 32, MVT_LLVector3d, 24);

	LLViewerObject *objp = NULL;

	if (object_id.isNull())
	{
		setSourceObject(NULL);
	}
	else
	{
		LLViewerObject *objp = gObjectList.findObject(object_id);
		if (objp)
		{
			setSourceObject(objp);
		}
		else
		{
			// We don't have this object, kill this effect
			markDead();
			return;
		}
	}

	if (target_object_id.isNull())
	{
		setTargetObject(NULL);
	}
	else
	{
		objp = gObjectList.findObject(target_object_id);
		if (objp)
		{
			setTargetObject(objp);
		}
		else
		{
			// We don't have this object, kill this effect
			markDead();
			return;
		}
	}

	triggerLocal();
}
示例#22
0
void Connection::markDead(const char* reason) {
  return markDead(reason, s_retryTimeout);
}
示例#23
0
/*!
  The advance function does quite a lot for the ship sprite.
  In \a phase 0, if the ship is marked dead, just return. If
  not, move the ship using its current position and velocity.
  Then get the list of all collisions with the ship and run
  through the list.

  If the ship collides with a rock, then if the shield is
  up, destroy the rock. If the shiled is down (normal), mark
  the ship dead and return.

  If the ship collides with a powerup, then if the shield is
  up, mark the powerup destroyed. If the shield is not up,
  apply the powerup to the ship.

  In phase 1, if the ship is marked dead, explode the ship,
  delete it, and return. Otherwise, handle ship rotation,
  breaking, ship velocity, an teleporting. also update the
  image if the ship is rotating, and the exhaust image, if
  the engine is on. If the shiled is up, handle its image
  and age. Finally, in phase one, handle the firing of the
  missiles.
  \internal
 */
void KShip::advance(int phase)
{
    if (phase == 0) {
	if (dying())
	    markDead();
	if (isDead() || teleport_)
	    return;
	KSprite::advance(phase);
	QList<QGraphicsItem*> hits = ship_->collidingItems();
	QList<QGraphicsItem*>::Iterator i;
	for (i=hits.begin(); i!=hits.end(); ++i) {
	    if ((*i)->type() <= ID_Base)
		continue;
	    KSprite* sprite = (KSprite*)(*i);
	    if (sprite->isRock()) {
		if (shield_->isUp()) {
		    /*
		      The ship hit a rock with the shield up.
		      The rock is marked for death, which will
		      cause it to break up or just disappear in
		      in phase 1.

		      The shield's strength is reduced by an
		      amount commensurate with the rock size.
		      If the strength goes to 0, the shield
		      will be dropped in phase 1.
		     */
		    sprite->markDead();
		    int s = 1;
		    if (sprite->isLargeRock())
			s = 3;
		    else if (sprite->isMediumRock())
			s = 2;
		    int pl = s * (SHIELD_HIT_COST - (shield_->strength()*2));
		    shield_->reduceStrength(s);
		    reducePowerLevel(pl);
		}
		else {
		    /*
		      The ship hit a rock with the shield down.
		      Mark the ship dead and return. The ship
		      will be exploded in phase 1.
		     */
                    view_->setCanPause(false);
		    markDead();
		    shield_->markDead();
		    return;
		}
	    }
	    else if (sprite->isPowerup()) {
		if (shield_->isUp()) {
		    sprite->markDead();
		}
		else {
		    /*
		      The ship hit a powerup with the shield down.
		      Mark the powerup for apply. It will be applied
		      to the ship in phase 1, if the ship survives.
		      Also mark the powerup dead, ie consumed.
		     */
		    sprite->markApply();
		    sprite->markDead();
		    return;
		}
	    }
            else if (powerLevel() <= EMPTY_SHIP_POWER_LEVEL) {
                ship_->markDead();
                shield_->markDead();
            }
	}
    }
    else { // phase 1
	if (isDead() || dying()) {
	    explode(); // shatters the ship into spinning fragments.
	    delete this;
	    return;
	}
	if (rotateSlow_)
	    rotateSlow_--;

	if (rotateLeft_) {
	    angleIndex_ -= rotateSlow_ ? 1 : rotationRate_;
	    if (angleIndex_ < 0)
		angleIndex_ = SHIP_STEPS-1;
	    angle_ = angleIndex_ * PI_X_2 / SHIP_STEPS;
	    cosangle_ = cos(angle_);
	    sinangle_ = sin(angle_);
	}

	if (rotateRight_) {
	    angleIndex_ += rotateSlow_ ? 1 : rotationRate_;
	    if (angleIndex_ >= SHIP_STEPS)
		angleIndex_ = 0;
	    angle_ = angleIndex_ * PI_X_2 / SHIP_STEPS;
	    cosangle_ = cos(angle_);
	    sinangle_ = sin(angle_);
	}

	if (isBraking()) {
	    stopEngine();
	    stopRotation();
	    if ((fabs(dx_) < 2.5) && (fabs(dy_) < 2.5)) {
		dx_ = 0.0;
		dy_ = 0.0;
		setVelocity(dx_,dy_);
		releaseBrakes();
	    }
	    else {
		double motionAngle = atan2(-dy_,-dx_);
		if (angle_ > M_PI)
		    angle_ -= PI_X_2;
		double angleDiff = angle_ - motionAngle;
		if (angleDiff > M_PI)
		    angleDiff = PI_X_2 - angleDiff;
		else if (angleDiff < -M_PI)
		    angleDiff = PI_X_2 + angleDiff;
		double fdiff = fabs(angleDiff);
		if (fdiff > 0.08) {
		    if (angleDiff > 0)
			rotateLeft_ = true;
		    else if (angleDiff < 0)
			rotateRight_ = true;
		    if (fdiff > 0.6)
			rotationRate_ = brakeForce() + 1;
		    else if (fdiff > 0.4)
			rotationRate_ = 2;
		    else
			rotationRate_ = 1;

		    if (rotationRate_ > 5)
			rotationRate_ = 5;
		}
		else if ((fabs(dx_)>1) || (fabs(dy_)>1)) {
		    startEngine();
		    // we'll make braking a bit faster
		    dx_ += cosangle_/6 * (brakeForce() - 1);
		    dy_ += sinangle_/6 * (brakeForce() - 1);
		    reducePowerLevel(BRAKE_ON_COST);
		    KExhaust::add(ship_->x() + 10 - cosangle_*11,
				  ship_->y() + 10 - sinangle_*11,
				  dx_-cosangle_,
				  dy_-sinangle_,
				  brakeForce()+1);
		}
	    }
	}
	else if (engineIsOn()) {
	    /*
	      The ship has a terminal velocity, but trying
	      to go faster still uses fuel (can go faster
	      diagonally - don't care).
	    */
	    double thrustx = cosangle_/8;
	    double thrusty = sinangle_/8;
	    if (fabs(dx_ + thrustx) < MAX_SHIP_SPEED)
		dx_ += thrustx;
	    if (fabs(dy_ + thrusty) < MAX_SHIP_SPEED)
		dy_ += thrusty;
	    setVelocity(dx_,dy_);
	    reducePowerLevel(5);
	    KExhaust::add(x() + 10 - cosangle_*10,
			  y() + 10 - sinangle_*10,
			  dx_-cosangle_,
			  dy_-sinangle_,
			  3);
	}

	setImage(angleIndex_ >> 1);

	if (teleport_) {
	    int ra = rand() % 10;
	    if(ra == 0)
		ra += rand() % 20;
	    int xra = ra * 60 + ((rand() % 20) * (rand() % 20));
	    int yra = ra * 50 - ((rand() % 20) * (rand() % 20));
	    setPos(xra,yra);
	    teleport_ = false;
	    if (teleportCount_ > 0) {
		--teleportCount_;
		view_->markVitalsChanged();
	    }
	    wrap();
	}

	if (shield_->isUp()) {
	    /*
	      The shield's position always depends on the
	      ship's position.
	     */
	    static int sf = 0;
	    sf++;
	    if (sf % 2)
		shield_->advanceImage();
	    shield_->setPos(x()-5,y()-5);
	    shield_->show();
	}

	if (isShooting()) {
	    int maxMissiles = firePower_ + 2;
	    if (canShoot() && (KMissile::missiles() < maxMissiles)) {
		KMissile* missile = new KMissile();
		missile->setMaximumAge(12);
		missile->setPos(11 + x() + cosangle_ * 11,
				11 + y() + sinangle_ * 11);
		missile->setVelocity(dx_ + cosangle_ * MISSILE_SPEED,
				     dy_ + sinangle_ * MISSILE_SPEED);
		missile->show();
		reducePowerLevel(1);
		view_->reportMissileFired();
		int delay = 5 - firePower_;
		if (delay < 0)
		    delay = 0;
		delayShooting(delay); // delay firing next missile.
	    }
	    decrementNextShotDelay();
	}
    }
}