Exemplo n.º 1
0
// When hit by Baul spray, gas clouds explodes transforming into a lethal shockwave.
static void
generate_shockwave (ELEMENT *ElementPtr, BYTE which_player)
{
	STARSHIP *StarShipPtr;
	
	GetElementStarShip (ElementPtr, &StarShipPtr);
	
	// Gas is still 'solid' when it's hit by the spray. Let's make a shockwave and kill the gas cloud. 
	if (!(ElementPtr->state_flags & NONSOLID))
	{
		HELEMENT hShockwave;
				
		hShockwave = AllocElement ();
		if (hShockwave)
		{
			ELEMENT *ShockwavePtr;
			STARSHIP *StarShipPtr;
			
			GetElementStarShip (ElementPtr, &StarShipPtr);
			
			PutElement (hShockwave);
			LockElement (hShockwave, &ShockwavePtr);
			SetElementStarShip (ShockwavePtr, StarShipPtr);
			ShockwavePtr->hit_points = ShockwavePtr->mass_points = 0;
			ShockwavePtr->playerNr = which_player;
			ShockwavePtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID | IGNORE_SIMILAR;
			ShockwavePtr->life_span = SHOCKWAVE_FRAMES;
			SetPrimType (&(GLOBAL (DisplayArray))[ShockwavePtr->PrimIndex], STAMP_PRIM);
			ShockwavePtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special;
			ShockwavePtr->current.image.frame = SetAbsFrameIndex(StarShipPtr->RaceDescPtr->ship_data.special[0], LAST_GAS_INDEX);
			ShockwavePtr->next.image.frame = SetAbsFrameIndex(ElementPtr->current.image.frame, LAST_GAS_INDEX);
			ShockwavePtr->current.location = ElementPtr->current.location;
			ShockwavePtr->preprocess_func = shockwave_preprocess;
			ShockwavePtr->postprocess_func = NULL;
			ShockwavePtr->death_func = NULL;
			ZeroVelocityComponents (&ShockwavePtr->velocity);
			UnlockElement (hShockwave);
		}
		
		// Gas dies on the next turn.
		ElementPtr->state_flags |= NONSOLID;
		
		// Explosion sounds.
		ProcessSound (SetAbsSoundIndex (StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), ElementPtr);
		ProcessSound (SetAbsSoundIndex (GameSounds, TARGET_DAMAGED_FOR_6_PLUS_PT), ElementPtr);
	}

	{
		// This is called during PostProcessQueue(), close to or at the end,
		// for the temporary shockwave element to apply the damage.
		// The effects are not seen until the next frame.
		HELEMENT hElement, hNextElement;
		
		for (hElement = GetHeadElement (); hElement != 0; hElement = hNextElement)
		{
			ELEMENT *ObjPtr;
			
			LockElement (hElement, &ObjPtr);
			hNextElement = GetSuccElement (ObjPtr);
			
			if (IS_GAS (ObjPtr))
			{
				SIZE delta_x, delta_y;
				DWORD dist;
				
				if ((delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x) < 0) delta_x = -delta_x;
				if ((delta_y = ObjPtr->next.location.y - ElementPtr->next.location.y) < 0) delta_y = -delta_y;
				
				delta_x = WORLD_TO_DISPLAY (delta_x);
				delta_y = WORLD_TO_DISPLAY (delta_y);
				
				if (delta_x <= SHOCKWAVE_RANGE && delta_y <= SHOCKWAVE_RANGE
					&& (dist = (DWORD)(delta_x * delta_x) + (DWORD)(delta_y * delta_y)) <= (DWORD)(SHOCKWAVE_RANGE * SHOCKWAVE_RANGE))
				{
					SIZE destruction;
					
					destruction = ((MAX_DESTRUCTION * (SHOCKWAVE_RANGE - square_root (dist))) / SHOCKWAVE_RANGE) + 1;
					
					// The shockwave is delayed according to how far it is from the shockwave that set it off.
					ObjPtr->life_span = (10 / destruction);
					ObjPtr->death_func = generate_shockwave_2;
					ObjPtr->playerNr = which_player;
				}
			}
			else if (CollidingElement (ObjPtr) || ORZ_MARINE (ObjPtr))
			{
				SIZE delta_x, delta_y;
				DWORD dist;
				
				if ((delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x) < 0) delta_x = -delta_x;
				if ((delta_y = ObjPtr->next.location.y - ElementPtr->next.location.y) < 0) delta_y = -delta_y;
				
				delta_x = WORLD_TO_DISPLAY (delta_x);
				delta_y = WORLD_TO_DISPLAY (delta_y);
				
				if (delta_x <= SHOCKWAVE_RANGE && delta_y <= SHOCKWAVE_RANGE
					&& (dist = (DWORD)(delta_x * delta_x) + (DWORD)(delta_y * delta_y)) <= (DWORD)(SHOCKWAVE_RANGE * SHOCKWAVE_RANGE))
				{
					SIZE destruction;
					
					destruction = ((MAX_DESTRUCTION * (SHOCKWAVE_RANGE - square_root (dist))) / SHOCKWAVE_RANGE) + 1;
					
					if (ObjPtr->state_flags & PLAYER_SHIP && ObjPtr->playerNr != which_player)
					{
						STARSHIP *EnemyShipPtr;
						
						GetElementStarShip (ObjPtr, &EnemyShipPtr);
						
						// Deal damage to ships except shield-using Yehat & Utwig.
						if (!((EnemyShipPtr->SpeciesID == YEHAT_ID || EnemyShipPtr->SpeciesID == UTWIG_ID) 
							  && ObjPtr->life_span > NORMAL_LIFE))
						{
							if (!DeltaCrew (ObjPtr, -destruction))
								ObjPtr->life_span = 0;
						}
						// Charge Utwig shield.
						else if (EnemyShipPtr->SpeciesID == UTWIG_ID && ObjPtr->life_span > NORMAL_LIFE)
							ObjPtr->life_span += destruction;
					}
					else if (!GRAVITY_MASS (ObjPtr->mass_points) && ObjPtr->playerNr != which_player)
					{
						if ((BYTE)destruction < ObjPtr->hit_points)
							ObjPtr->hit_points -= (BYTE)destruction;
						else
						{
							ObjPtr->hit_points = 0;
							ObjPtr->life_span = 0;
						}
					}
				}
			}
			
			UnlockElement (hElement);
		}
	}
}
Exemplo n.º 2
0
static void
self_destruct (PELEMENT ElementPtr)
{
	STARSHIPPTR StarShipPtr;

	GetElementStarShip (ElementPtr, &StarShipPtr);
	if (ElementPtr->state_flags & PLAYER_SHIP)
	{
		HELEMENT hDestruct;
		
		hDestruct = AllocElement ();
		if (hDestruct)
		{
			ELEMENTPTR DestructPtr;

			LockElement (hDestruct, &DestructPtr);
			DestructPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE |
					(ElementPtr->state_flags & (GOOD_GUY | BAD_GUY));
			DestructPtr->next.location = ElementPtr->next.location;
			DestructPtr->life_span = 0;
			DestructPtr->pParent = ElementPtr->pParent;
			DestructPtr->hTarget = 0;

			DestructPtr->death_func = self_destruct;

			UnlockElement (hDestruct);

			PutElement (hDestruct);
		}

		ElementPtr->state_flags |= NONSOLID;
		ElementPtr->life_span = 0;

		ElementPtr->preprocess_func = destruct_preprocess;
	}
	else
	{
		HELEMENT hElement, hNextElement;

		for (hElement = GetHeadElement ();
				hElement != 0; hElement = hNextElement)
		{
			ELEMENTPTR ObjPtr;

			LockElement (hElement, &ObjPtr);
			hNextElement = GetSuccElement (ObjPtr);

			if (CollidingElement (ObjPtr) || ORZ_MARINE (ObjPtr))
			{
#define DESTRUCT_RANGE 180
				SIZE delta_x, delta_y;
				DWORD dist;

				if ((delta_x = ObjPtr->next.location.x
						- ElementPtr->next.location.x) < 0)
					delta_x = -delta_x;
				if ((delta_y = ObjPtr->next.location.y
						- ElementPtr->next.location.y) < 0)
					delta_y = -delta_y;
				delta_x = WORLD_TO_DISPLAY (delta_x);
				delta_y = WORLD_TO_DISPLAY (delta_y);
				if (delta_x <= DESTRUCT_RANGE && delta_y <= DESTRUCT_RANGE
						&& (dist = (DWORD)(delta_x * delta_x)
						+ (DWORD)(delta_y * delta_y)) <=
						(DWORD)(DESTRUCT_RANGE * DESTRUCT_RANGE))
				{
#define MAX_DESTRUCTION (DESTRUCT_RANGE / 10)
					SIZE destruction;

					destruction = ((MAX_DESTRUCTION
							* (DESTRUCT_RANGE - square_root (dist)))
							/ DESTRUCT_RANGE) + 1;

					if (ObjPtr->state_flags & PLAYER_SHIP)
					{
						if (!DeltaCrew (ObjPtr, -destruction))
							ObjPtr->life_span = 0;
					}
					else if (!GRAVITY_MASS (ObjPtr->mass_points))
					{
						if ((BYTE)destruction < ObjPtr->hit_points)
							ObjPtr->hit_points -= (BYTE)destruction;
						else
						{
							ObjPtr->hit_points = 0;
							ObjPtr->life_span = 0;
						}
					}
				}
			}

			UnlockElement (hElement);
		}
	}
}
Exemplo n.º 3
0
// XXX: This function should be split into two
static void
self_destruct (ELEMENT *ElementPtr)
{
    STARSHIP *StarShipPtr;

    GetElementStarShip (ElementPtr, &StarShipPtr);
    if (ElementPtr->state_flags & PLAYER_SHIP)
    {
        HELEMENT hDestruct;

        // Spawn a temporary element, which dies in this same frame, in order
        // to defer the effects of the glory explosion.
        // It will be the last element (or one of the last) for which the
        // death_func will be called from PostProcessQueue() in this frame.
        hDestruct = AllocElement ();
        if (hDestruct)
        {
            ELEMENT *DestructPtr;

            LockElement (hDestruct, &DestructPtr);
            DestructPtr->playerNr = ElementPtr->playerNr;
            DestructPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE;
            DestructPtr->next.location = ElementPtr->next.location;
            DestructPtr->life_span = 0;
            DestructPtr->pParent = ElementPtr->pParent;
            DestructPtr->hTarget = 0;

            DestructPtr->death_func = self_destruct;

            UnlockElement (hDestruct);

            PutElement (hDestruct);
        }

        ElementPtr->state_flags |= NONSOLID;
        // The ship is now dead. It's death_func, i.e. ship_death(), will be
        // called the next frame.
        ElementPtr->life_span = 0;

        ElementPtr->preprocess_func = destruct_preprocess;
    }
    else
    {
        // This is called during PostProcessQueue(), close to or at the end,
        // for the temporary destruct element to apply the effects of glory
        // explosion. The effects are not seen until the next frame.
        HELEMENT hElement, hNextElement;

        for (hElement = GetHeadElement ();
                hElement != 0; hElement = hNextElement)
        {
            ELEMENT *ObjPtr;

            LockElement (hElement, &ObjPtr);
            hNextElement = GetSuccElement (ObjPtr);

            if (CollidingElement (ObjPtr) || ORZ_MARINE (ObjPtr))
            {
#define DESTRUCT_RANGE 180
                SIZE delta_x, delta_y;
                DWORD dist;

                if ((delta_x = ObjPtr->next.location.x
                               - ElementPtr->next.location.x) < 0)
                    delta_x = -delta_x;
                if ((delta_y = ObjPtr->next.location.y
                               - ElementPtr->next.location.y) < 0)
                    delta_y = -delta_y;
                delta_x = WORLD_TO_DISPLAY (delta_x);
                delta_y = WORLD_TO_DISPLAY (delta_y);
                if (delta_x <= DESTRUCT_RANGE && delta_y <= DESTRUCT_RANGE
                        && (dist = (DWORD)(delta_x * delta_x)
                                   + (DWORD)(delta_y * delta_y)) <=
                        (DWORD)(DESTRUCT_RANGE * DESTRUCT_RANGE))
                {
#define MAX_DESTRUCTION (DESTRUCT_RANGE / 10)
                    SIZE destruction;

                    destruction = ((MAX_DESTRUCTION
                                    * (DESTRUCT_RANGE - square_root (dist)))
                                   / DESTRUCT_RANGE) + 1;

                    if (ObjPtr->state_flags & PLAYER_SHIP)
                    {
                        if (!DeltaCrew (ObjPtr, -destruction))
                            ObjPtr->life_span = 0;
                    }
                    else if (!GRAVITY_MASS (ObjPtr->mass_points))
                    {
                        if ((BYTE)destruction < ObjPtr->hit_points)
                            ObjPtr->hit_points -= (BYTE)destruction;
                        else
                        {
                            ObjPtr->hit_points = 0;
                            ObjPtr->life_span = 0;
                        }
                    }
                }
            }

            UnlockElement (hElement);
        }
    }
}