/src/effects.cpp
C++ | 2603 lines | 1925 code | 365 blank | 313 comment | 293 complexity | 23761e801e4bd3c91c8cd6e70b9526ba MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause, LGPL-2.1, GPL-2.0, CC-BY-SA-4.0
Large files files are truncated, but you can click here to view the full file
- /*
- This file is part of Warzone 2100.
- Copyright (C) 1999-2004 Eidos Interactive
- Copyright (C) 2005-2013 Warzone 2100 Project
- Warzone 2100 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.
- Warzone 2100 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 Warzone 2100; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- /*
- Spot FX code - will handle every miscellaneous imd render and update for temporary
- entities except projectiles.
- Handles stuff like
- - Smoke sprites on the card.
- - Explosions
- - Building body kit - flashing lights etc etc
- - Construction graphics
- - Gravitons
- - Dust
- - Blood
- It's now PSX friendly in that there's no floats
- ************************************************************
- * STILL NEED TO REMOVE SOME MAGIC NUMBERS INTO #DEFINES!!! *
- ************************************************************
- */
- #include "lib/framework/wzapp.h"
- #include "lib/framework/wzconfig.h"
- #include "lib/framework/frameresource.h"
- #include "lib/framework/input.h"
- #include "lib/framework/math_ext.h"
- #include "lib/ivis_opengl/ivisdef.h" //ivis matrix code
- #include "lib/ivis_opengl/piedef.h" //ivis matrix code
- #include "lib/framework/fixedpoint.h"
- #include "lib/ivis_opengl/piepalette.h"
- #include "lib/ivis_opengl/piestate.h"
- #include "lib/ivis_opengl/piematrix.h"
- #include "lib/ivis_opengl/piemode.h"
- #include "lib/gamelib/gtime.h"
- #include "lib/sound/audio.h"
- #include "lib/sound/audio_id.h"
- #include "display3d.h"
- #include "map.h"
- #include "bucket3d.h"
- #include "effects.h"
- #include "mission.h"
- #include "miscimd.h"
- #include "hci.h"
- #include "lighting.h"
- #include "console.h"
- #include "loop.h"
- #include "multiplay.h"
- #include "game.h"
- #include "component.h"
- #define GRAVITON_GRAVITY ((float)-800)
- #define EFFECT_X_FLIP 0x1
- #define EFFECT_Y_FLIP 0x2
- #define EFFECT_CYCLIC 0x4
- #define EFFECT_ESSENTIAL 0x8
- #define EFFECT_FACING 0x10
- #define EFFECT_SCALED 0x20
- #define EFFECT_LIT 0x40
- #define TEST_FLIPPED_X(x) (x->control & EFFECT_X_FLIP)
- #define TEST_FLIPPED_Y(x) (x->control & EFFECT_Y_FLIP)
- #define TEST_ESSENTIAL(x) (x->control & EFFECT_ESSENTIAL)
- #define TEST_FACING(x) (x->control & EFFECT_FACING)
- #define TEST_CYCLIC(x) (x->control & EFFECT_CYCLIC)
- #define TEST_SCALED(x) (x->control & EFFECT_SCALED)
- #define TEST_LIT(x) (x->control & EFFECT_LIT)
- #define SET_FLIPPED_X(x) ((x->control) = (UBYTE)(x->control | EFFECT_X_FLIP))
- #define SET_FLIPPED_Y(x) ((x->control) = (UBYTE)(x->control | EFFECT_Y_FLIP))
- #define SET_ESSENTIAL(x) ((x->control) = (UBYTE)(x->control | EFFECT_ESSENTIAL))
- #define SET_FACING(x) ((x->control) = (UBYTE)(x->control | EFFECT_FACING))
- #define SET_CYCLIC(x) ((x->control) = (UBYTE)(x->control | EFFECT_CYCLIC))
- #define SET_SCALED(x) ((x->control) = (UBYTE)(x->control | EFFECT_SCALED))
- #define SET_LIT(x) ((x->control) = (UBYTE)(x->control | EFFECT_LIT))
- #define NORMAL_SMOKE_LIFESPAN (6000 + rand()%3000)
- #define SMALL_SMOKE_LIFESPAN (3000 + rand()%3000)
- #define TRAIL_SMOKE_LIFESPAN (1200)
- #define CONSTRUCTION_LIFESPAN (5000)
- #define SMOKE_FRAME_DELAY (40 + rand()%30)
- #define EXPLOSION_FRAME_DELAY (25 + rand()%40)
- #define EXPLOSION_TESLA_FRAME_DELAY (65)
- #define EXPLOSION_PLASMA_FRAME_DELAY (45)
- #define BLOOD_FRAME_DELAY (150)
- #define DESTRUCTION_FRAME_DELAY (200)
- #define TESLA_SPEED (170)// + (30 - rand()%60))
- #define TESLA_SIZE (100)// + (20 - rand()%40))
- #define GRAVITON_FRAME_DELAY (100 + rand()%50)
- #define GRAVITON_BLOOD_DELAY (200 + rand()%100)
- #define CONSTRUCTION_FRAME_DELAY (40 + rand()%30)
- #define EXPLOSION_SIZE (110+(30-rand()%60))
- #define BLOOD_SIZE (100+(30-rand()%60))
- #define BLOOD_FALL_SPEED (-(20+rand()%20))
- #define GRAVITON_INIT_VEL_X (float)(200 - rand() % 300)
- #define GRAVITON_INIT_VEL_Z (float)(200 - rand() % 300)
- #define GRAVITON_INIT_VEL_Y (float)(300 + rand() % 100)
- #define GIBLET_INIT_VEL_X (float)(50 - rand() % 100)
- #define GIBLET_INIT_VEL_Z (float)(50 - rand() % 100)
- #define GIBLET_INIT_VEL_Y 12.f
- #define DROID_DESTRUCTION_DURATION (3*GAME_TICKS_PER_SEC/2) // 1.5 seconds
- #define STRUCTURE_DESTRUCTION_DURATION ((7*GAME_TICKS_PER_SEC)/2) // 3.5 seconds
- #define EFFECT_EXPLOSION_ADDITIVE 164
- #define EFFECT_PLASMA_ADDITIVE 224
- #define EFFECT_SMOKE_TRANSPARENCY 130
- #define EFFECT_STEAM_TRANSPARENCY 128
- #define EFFECT_BLOOD_TRANSPARENCY 128
- #define EFFECT_DROID_DIVISION 101
- #define EFFECT_STRUCTURE_DIVISION 103
- #define DROID_UPDATE_INTERVAL 500
- #define STRUCTURE_UPDATE_INTERVAL 1250
- #define BASE_FLAME_SIZE 80
- #define BASE_LASER_SIZE 10
- #define BASE_PLASMA_SIZE 0
- #define DISCOVERY_SIZE 60
- #define FLARE_SIZE 100
- #define SHOCKWAVE_SPEED (GAME_TICKS_PER_SEC)
- #define MAX_SHOCKWAVE_SIZE 500
- /*! Number of effects in one chunk */
- #define EFFECT_CHUNK_SIZE 10000
- /*! A memory chunk of effects */
- struct EffectChunk
- {
- EFFECT effects[EFFECT_CHUNK_SIZE]; //!< Chunk of effects
- EffectChunk *next; //!< Next element in list
- };
- /*! List containing all allocated effect chunks */
- struct chunkList_t {
- EffectChunk *first; //!< First element of list, used for iteration
- EffectChunk *last; //!< Last element of list, used for appending
- } chunkList = {
- NULL, NULL
- };
- /*! Our lists of all game world effects */
- struct activeList_t {
- size_t num; //!< Number of effects in this list, used when saving
- EFFECT *first; //!< First element of list, used for iteration / finding free effects
- EFFECT *last; //!< Last element of list, used for appending
- } activeList = { //!< List of all active effects
- 0, NULL, NULL
- }, inactiveList = { //!< List of unused effects
- 0, NULL, NULL
- };
- /* Tick counts for updates on a particular interval */
- static UDWORD lastUpdateDroids[EFFECT_DROID_DIVISION];
- static UDWORD lastUpdateStructures[EFFECT_STRUCTURE_DIVISION];
- static UDWORD auxVar; // dirty filthy hack - don't look for what this does.... //FIXME
- static UDWORD auxVarSec; // dirty filthy hack - don't look for what this does.... //FIXME
- static UDWORD specifiedSize;
- static UDWORD ellSpec;
- static uint8_t EffectForPlayer = 0;
- // ----------------------------------------------------------------------------------------
- /* PROTOTYPES */
- // ----------------------------------------------------------------------------------------
- // ---- Update functions - every group type of effect has one of these */
- static void updateWaypoint(EFFECT *psEffect);
- static void updateExplosion(EFFECT *psEffect);
- static void updatePolySmoke(EFFECT *psEffect);
- static void updateGraviton(EFFECT *psEffect);
- static void updateConstruction(EFFECT *psEffect);
- static void updateBlood (EFFECT *psEffect);
- static void updateDestruction(EFFECT *psEffect);
- static void updateFire(EFFECT *psEffect);
- static void updateSatLaser(EFFECT *psEffect);
- static void updateFirework(EFFECT *psEffect);
- static void updateEffect(EFFECT *psEffect); // MASTER function
- // ----------------------------------------------------------------------------------------
- // ---- The render functions - every group type of effect has a distinct one
- static void renderExplosionEffect ( const EFFECT *psEffect );
- static void renderSmokeEffect ( const EFFECT *psEffect );
- static void renderGravitonEffect ( const EFFECT *psEffect );
- static void renderConstructionEffect( const EFFECT *psEffect );
- static void renderWaypointEffect ( const EFFECT *psEffect );
- static void renderBloodEffect ( const EFFECT *psEffect );
- static void renderDestructionEffect ( const EFFECT *psEffect );
- static void renderFirework ( const EFFECT *psEffect );
- static void positionEffect(const EFFECT *psEffect);
- /* There is no render destruction effect! */
- // ----------------------------------------------------------------------------------------
- // ---- The set up functions - every type has one
- static void effectSetupSmoke ( EFFECT *psEffect );
- static void effectSetupGraviton ( EFFECT *psEffect );
- static void effectSetupExplosion ( EFFECT *psEffect );
- static void effectSetupConstruction ( EFFECT *psEffect );
- static void effectSetupWayPoint ( EFFECT *psEffect );
- static void effectSetupBlood ( EFFECT *psEffect );
- static void effectSetupDestruction ( EFFECT *psEffect );
- static void effectSetupFire ( EFFECT *psEffect );
- static void effectSetupSatLaser ( EFFECT *psEffect );
- static void effectSetupFirework ( EFFECT *psEffect );
- static void effectStructureUpdates();
- static void effectDroidUpdates(void);
- static UDWORD effectGetNumFrames(EFFECT *psEffect);
- static void killEffect(EFFECT *e);
- /*!
- * Initialise memory between first and last as singly linked list
- * \param first First element in memory chunk
- * \param last Last element in memory chunk
- */
- static void initEffectPool(EFFECT *first, EFFECT *last)
- {
- EFFECT *it;
- for (it = first; it < last; it++)
- {
- // We do not need a double-linked-list for inactiveeffects, since we always pick from the front:
- it->prev = NULL;
- it->next = it+1;
- }
- last->prev = NULL;
- last->next = NULL;
- }
- /*!
- * Allocate a new effect from memory pool
- * FIXME: Does not deal with out-of-memory conditions (yet)
- * \return New, uninitialised effect
- */
- static EFFECT *Effect_malloc(void)
- {
- /* Take the first item in inactiveList */
- EFFECT *instance = inactiveList.first;
- /* Remove from inactiveList */
- inactiveList.first = instance->next; // Singly linked, so do not update prev
- instance->next = NULL; // We are the last in activeList now
- /* Append to activeList */
- instance->prev = activeList.last;
- if (instance->prev == NULL) {
- activeList.first = instance; // activeList was empty, so fill it
- }
- else {
- activeList.last->next = instance;
- }
- activeList.last = instance;
- /* Adjust counts */
- activeList.num++;
- inactiveList.num--;
- /* Ensure the next search will have something to feed its hunger with */
- if (inactiveList.first == NULL)
- {
- /* Allocate new effect chunk */
- EffectChunk *chunk = (EffectChunk *)calloc(1, sizeof(EffectChunk));
- debug(LOG_MEMORY, "%lu effects in use, allocating %d extra", (unsigned long)activeList.num, EFFECT_CHUNK_SIZE);
- /* Deal with out-of-memory conditions */
- if (chunk == NULL) {
- debug(LOG_ERROR, "Out of memory");
- return NULL; // The next call relies on inactiveList being non-empty, and would thus segfault, so bail out early instead
- }
- /* Append to list */
- chunk->next = NULL; // Last element
- chunkList.last->next = chunk; // chunkList is never empty, thus we can rely on last!=NULL
- /* Update inactiveList */
- inactiveList.num = EFFECT_CHUNK_SIZE;
- inactiveList.first = &chunk->effects[0];
- inactiveList.last = &chunk->effects[EFFECT_CHUNK_SIZE-1];
- /* Initialise list links between inactive effects */
- initEffectPool(inactiveList.first, inactiveList.last);
- }
- return instance;
- }
- /*!
- * Return an effect into memory pool
- * \param self Effect to be freed
- */
- static void Effect_free(EFFECT *instance)
- {
- instance->group = EFFECT_FREED;
- /* Remove from activeList and fixup endings necessary */
- if (instance->prev != NULL) {
- instance->prev->next = instance->next;
- }
- else {
- activeList.first = instance->next; // We were the first in activeList
- }
- if (instance->next != NULL) {
- instance->next->prev = instance->prev;
- }
- else {
- activeList.last = instance->prev; // We were the last in activeList
- }
- /* Append to inactiveList */
- instance->prev = NULL; // Singly linked
- instance->next = NULL; // Last element
- // inactiveList is never empty (guaranteed in Effect_malloc), thus we can rely on last!=NULL
- inactiveList.last->next = instance;
- inactiveList.last = instance;
- /* Adjust counts */
- inactiveList.num++;
- ASSERT_OR_RETURN(, activeList.num > 0, "Underflow");
- activeList.num--;
- }
- void shutdownEffectsSystem(void)
- {
- EFFECT *eff;
- /* Traverse the list */
- for (eff = activeList.first; eff;)
- {
- EFFECT *effNext = eff->next;
- killEffect(eff);
- eff = effNext;
- }
- free(chunkList.first);
- chunkList.first = NULL;
- chunkList.last = NULL;
- }
- /*!
- * Initialise effects system
- * Cleans up old effects, allocates a first chunk of effects, initialises (in)active lists
- */
- void initEffectsSystem(void)
- {
- EffectChunk *chunk;
- /* Clean up old chunks */
- shutdownEffectsSystem();
- /* Allocate new chunk */
- chunk = (EffectChunk *)calloc(1, sizeof(EffectChunk));
- /* Deal with out-of-memory conditions */
- if (chunk == NULL)
- return; // FIXME We have no way to report an error here...
- /* Create chunkList */
- chunkList.first = chunk;
- chunkList.last = chunk;
- chunk->next = NULL; // Last element
- /* activeList is empty at start */
- activeList.num = 0;
- activeList.first = NULL;
- activeList.last = NULL;
- /* inactiveList contains all elements */
- inactiveList.num = EFFECT_CHUNK_SIZE;
- inactiveList.first = &chunk->effects[0];
- inactiveList.last = &chunk->effects[EFFECT_CHUNK_SIZE-1];
- /* Initialise free-effects pool */
- initEffectPool(inactiveList.first, inactiveList.last);
- }
- static void positionEffect(const EFFECT *psEffect)
- {
- /* Establish world position */
- Vector3i dv(
- psEffect->position.x - player.p.x,
- psEffect->position.y,
- -(psEffect->position.z - player.p.z)
- );
- /* Push the indentity matrix */
- pie_MatBegin();
- /* Move to position */
- pie_TRANSLATE(dv.x, dv.y, dv.z);
- }
- static void killEffect(EFFECT *e)
- {
- /* Put effect back into pool */
- Effect_free(e);
- }
- void effectSetLandLightSpec(LAND_LIGHT_SPEC spec)
- {
- ellSpec = spec;
- }
- void effectSetSize(UDWORD size)
- {
- specifiedSize = size;
- }
- void addMultiEffect(const Vector3i *basePos, Vector3i *scatter, EFFECT_GROUP group,
- EFFECT_TYPE type, bool specified, iIMDShape *imd, unsigned int number, bool lit, unsigned int size, unsigned effectTime)
- {
- if (number == 0)
- {
- return;
- }
- /* Set up the scaling for specified ones */
- specifiedSize = size;
- /* If there's only one, make sure it's in the centre */
- if (number == 1)
- {
- addEffect(basePos, group, type, specified, imd, lit, effectTime);
- }
- else
- {
- unsigned int i;
- /* Fix for jim */
- *scatter = *scatter / 10;
- /* There are multiple effects - so scatter them around according to parameter */
- for(i=0; i<number; i++)
- {
- // This scatters in a cube - is there a good reason for that, or just legacy?
- Vector3i scatPos = *basePos + *scatter - Vector3i(rand()%(scatter->x*2 + 1),
- rand()%(scatter->y*2 + 1),
- rand()%(scatter->z*2 + 1)
- );
- addEffect(&scatPos, group, type, specified, imd, lit, effectTime);
- }
- }
- }
- // When we need to set the effect for the player's color
- void SetEffectForPlayer(uint8_t player)
- {
- ASSERT(player < MAX_PLAYERS, "player is set to a invalid number of %d", (int) player);
- EffectForPlayer = getPlayerColour(player);
- }
- void addEffect(const Vector3i *pos, EFFECT_GROUP group, EFFECT_TYPE type, bool specified, iIMDShape *imd, int lit)
- {
- return addEffect(pos, group, type, specified, imd, lit, graphicsTime);
- }
- void addEffect(const Vector3i *pos, EFFECT_GROUP group, EFFECT_TYPE type, bool specified, iIMDShape *imd, int lit, unsigned effectTime)
- {
- EFFECT *psEffect = NULL;
- if(gamePaused())
- {
- return;
- }
- /* Retrieve a new effect from pool */
- psEffect = Effect_malloc();
- /* Deal with out-of-memory conditions */
- if (psEffect == NULL) {
- debug(LOG_ERROR, "Out of memory");
- return; // FIXME We have no way to report an error here...
- }
- /* Reset control bits */
- psEffect->control = 0;
- /* Store away it's position - into FRACTS */
- psEffect->position.x = pos->x;
- psEffect->position.y = pos->y;
- psEffect->position.z = pos->z;
- /* Now, note group and type */
- psEffect->group = group;
- psEffect->type = type;
- // and if the effect needs the player's color for certain things
- psEffect->player = EffectForPlayer;
- SetEffectForPlayer(0); // reset it
- /* Set when it entered the world */
- psEffect->birthTime = psEffect->lastFrame = effectTime;
- if(group == EFFECT_GRAVITON && (type == GRAVITON_TYPE_GIBLET || type == GRAVITON_TYPE_EMITTING_DR))
- {
- psEffect->frameNumber = lit;
- }
- else
- {
- /* Starts off on frame zero */
- psEffect->frameNumber = 0;
- }
- /*
- See what kind of effect it is - the add fucnction is different for each,
- although some things are shared
- */
- psEffect->imd = NULL;
- if(lit)
- {
- SET_LIT(psEffect);
- }
- if(specified)
- {
- /* We're specifying what the imd is - override */
- psEffect->imd = imd;
- psEffect->size = specifiedSize;
- }
- /* Do all the effect type specific stuff */
- switch(group)
- {
- case EFFECT_SMOKE:
- effectSetupSmoke(psEffect);
- break;
- case EFFECT_GRAVITON:
- effectSetupGraviton(psEffect);
- break;
- case EFFECT_EXPLOSION:
- effectSetupExplosion(psEffect);
- break;
- case EFFECT_CONSTRUCTION:
- effectSetupConstruction(psEffect);
- break;
- case EFFECT_WAYPOINT:
- effectSetupWayPoint(psEffect);
- break;
- case EFFECT_BLOOD:
- effectSetupBlood(psEffect);
- break;
- case EFFECT_DESTRUCTION:
- effectSetupDestruction(psEffect);
- break;
- case EFFECT_FIRE:
- effectSetupFire(psEffect);
- break;
- case EFFECT_SAT_LASER:
- effectSetupSatLaser(psEffect);
- break;
- case EFFECT_FIREWORK:
- effectSetupFirework(psEffect);
- break;
- case EFFECT_FREED:
- ASSERT( false,"Weirdy group type for an effect" );
- break;
- }
- /* As of yet, it hasn't bounced (or whatever)... */
- if(type!=EXPLOSION_TYPE_LAND_LIGHT)
- {
- psEffect->specific = 0;
- }
- ASSERT(psEffect->imd != NULL || group == EFFECT_DESTRUCTION || group == EFFECT_FIRE || group == EFFECT_SAT_LASER, "null effect imd");
- }
- /* Calls all the update functions for each different currently active effect */
- void processEffects(void)
- {
- EFFECT *it;
- /* Traverse the list */
- for (it = activeList.first; it != NULL;)
- {
- EFFECT *itNext = it->next; // If updateEffect deletes something, we would be screwed...
- if (it->birthTime <= graphicsTime) // Don't process, if it doesn't exist yet.
- {
- /* Run updates, effect may be deleted here */
- updateEffect(it);
- /* Is it on the grid */
- if (it->group != EFFECT_FREED && clipXY(it->position.x, it->position.z))
- {
- /* Add it to the bucket */
- bucketAddTypeToList(RENDER_EFFECT, it);
- }
- }
- it = itNext;
- }
- /* Add any droid effects */
- effectDroidUpdates();
- /* Add any structure effects */
- effectStructureUpdates();
- }
- /* The general update function for all effects - calls a specific one for each */
- static void updateEffect(EFFECT *psEffect)
- {
- /* What type of effect are we dealing with? */
- switch(psEffect->group)
- {
- case EFFECT_EXPLOSION:
- updateExplosion(psEffect);
- return;
- case EFFECT_WAYPOINT:
- if(!gamePaused()) updateWaypoint(psEffect);
- return;
- case EFFECT_CONSTRUCTION:
- if(!gamePaused()) updateConstruction(psEffect);
- return;
- case EFFECT_SMOKE:
- if(!gamePaused()) updatePolySmoke(psEffect);
- return;
- case EFFECT_GRAVITON:
- if(!gamePaused()) updateGraviton(psEffect);
- return;
- case EFFECT_BLOOD:
- if(!gamePaused()) updateBlood(psEffect);
- return;
- case EFFECT_DESTRUCTION:
- if(!gamePaused()) updateDestruction(psEffect);
- return;
- case EFFECT_FIRE:
- if(!gamePaused()) updateFire(psEffect);
- return;
- case EFFECT_SAT_LASER:
- if(!gamePaused()) updateSatLaser(psEffect);
- return;
- case EFFECT_FIREWORK:
- if(!gamePaused()) updateFirework(psEffect);
- return;
- case EFFECT_FREED:
- break;
- }
- debug( LOG_ERROR, "Weirdy class of effect passed to updateEffect" );
- abort();
- }
- // ----------------------------------------------------------------------------------------
- // ALL THE UPDATE FUNCTIONS
- // ----------------------------------------------------------------------------------------
- /** Update the waypoint effects.*/
- static void updateWaypoint(EFFECT *psEffect)
- {
- if(!(keyDown(KEY_LCTRL) || keyDown(KEY_RCTRL) ||
- keyDown(KEY_LSHIFT) || keyDown(KEY_RSHIFT)))
- {
- killEffect(psEffect);
- }
- }
- static void updateFirework(EFFECT *psEffect)
- {
- UDWORD height;
- UDWORD xDif,yDif,radius,val;
- Vector3i dv;
- SDWORD dif;
- UDWORD drop;
- /* Move it */
- psEffect->position.x += graphicsTimeAdjustedIncrement(psEffect->velocity.x);
- psEffect->position.y += graphicsTimeAdjustedIncrement(psEffect->velocity.y);
- psEffect->position.z += graphicsTimeAdjustedIncrement(psEffect->velocity.z);
- if(psEffect->type == FIREWORK_TYPE_LAUNCHER)
- {
- height = psEffect->position.y;
- if(height > psEffect->size)
- {
- dv.x = psEffect->position.x;
- dv.z = psEffect->position.z;
- dv.y = psEffect->position.y + (psEffect->radius / 2);
- addEffect(&dv,EFFECT_EXPLOSION,EXPLOSION_TYPE_MEDIUM,false,NULL,0);
- audio_PlayStaticTrack(psEffect->position.x, psEffect->position.z, ID_SOUND_EXPLOSION);
- for(dif =0; dif < (psEffect->radius*2); dif+=20)
- {
- if(dif<psEffect->radius)
- {
- drop = psEffect->radius-dif;
- }
- else
- {
- drop = dif - psEffect->radius;
- }
- radius = (UDWORD)sqrtf(psEffect->radius * psEffect->radius - drop * drop);
- //val = getStaticTimeValueRange(720,360); // grab an angle - 4 seconds cyclic
- for(val = 0; val<=180; val+=20)
- {
- xDif = iSinR(DEG(val), radius);
- yDif = iCosR(DEG(val), radius);
- dv.x = psEffect->position.x + xDif;
- dv.z = psEffect->position.z + yDif;
- dv.y = psEffect->position.y + dif;
- effectGiveAuxVar(100);
- addEffect(&dv,EFFECT_FIREWORK, FIREWORK_TYPE_STARBURST,false,NULL,0);
- dv.x = psEffect->position.x - xDif;
- dv.z = psEffect->position.z - yDif;
- dv.y = psEffect->position.y + dif;
- effectGiveAuxVar(100);
- addEffect(&dv,EFFECT_FIREWORK, FIREWORK_TYPE_STARBURST,false,NULL,0);
- dv.x = psEffect->position.x + xDif;
- dv.z = psEffect->position.z - yDif;
- dv.y = psEffect->position.y + dif;
- effectGiveAuxVar(100);
- addEffect(&dv,EFFECT_FIREWORK, FIREWORK_TYPE_STARBURST,false,NULL,0);
- dv.x = psEffect->position.x - xDif;
- dv.z = psEffect->position.z + yDif;
- dv.y = psEffect->position.y + dif;
- effectGiveAuxVar(100);
- addEffect(&dv,EFFECT_FIREWORK, FIREWORK_TYPE_STARBURST,false,NULL,0);
- }
- }
- killEffect(psEffect);
- }
- else
- {
- /* Add an effect at the firework's position */
- dv.x = psEffect->position.x;
- dv.y = psEffect->position.y;
- dv.z = psEffect->position.z;
- /* Add a trail graphic */
- addEffect(&dv,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
- }
- }
- else // must be a startburst
- {
- /* Time to update the frame number on the smoke sprite */
- if(graphicsTime - psEffect->lastFrame > psEffect->frameDelay)
- {
- /* Store away last frame change time */
- psEffect->lastFrame = graphicsTime;
- /* Are we on the last frame? */
- if(++psEffect->frameNumber >= effectGetNumFrames(psEffect))
- {
- /* Does the anim wrap around? */
- if(TEST_CYCLIC(psEffect))
- {
- psEffect->frameNumber = 0;
- }
- else
- {
- /* Kill it off */
- killEffect(psEffect);
- return;
- }
- }
- }
- /* If it doesn't get killed by frame number, then by age */
- if(TEST_CYCLIC(psEffect))
- {
- /* Has it overstayed it's welcome? */
- if(graphicsTime - psEffect->birthTime > psEffect->lifeSpan)
- {
- /* Kill it */
- killEffect(psEffect);
- }
- }
- }
- }
- static void updateSatLaser(EFFECT *psEffect)
- {
- Vector3i dv;
- UDWORD val;
- UDWORD radius;
- UDWORD xDif,yDif;
- UDWORD i;
- UDWORD startHeight,endHeight;
- UDWORD xPos,yPos;
- LIGHT light;
- // Do these here cause there used by the lighting code below this if.
- xPos = psEffect->position.x;
- startHeight = psEffect->position.y;
- endHeight = startHeight+1064;
- yPos = psEffect->position.z;
- if(psEffect->baseScale)
- {
- psEffect->baseScale = 0;
- /* Add some big explosions....! */
- for(i=0; i<16; i++)
- {
- dv.x = xPos+(200-rand()%400);
- dv.z = yPos+(200-rand()%400);
- dv.y = startHeight + rand()%100;
- addEffect(&dv,EFFECT_EXPLOSION,EXPLOSION_TYPE_MEDIUM,false,NULL,0);
- }
- /* Add a sound effect */
- audio_PlayStaticTrack(psEffect->position.x, psEffect->position.z, ID_SOUND_EXPLOSION);
- /* Add a shockwave */
- dv.x = xPos;
- dv.z = yPos;
- dv.y = startHeight+SHOCK_WAVE_HEIGHT;
- addEffect(&dv,EFFECT_EXPLOSION,EXPLOSION_TYPE_SHOCKWAVE,false,NULL,0);
- /* Now, add the column of light */
- for(i=startHeight; i<endHeight; i+=56)
- {
- radius = 80;
- /* Add 36 around in a circle..! */
- for(val = 0; val<=180; val+=30)
- {
- xDif = iSinR(DEG(val), radius);
- yDif = iCosR(DEG(val), radius);
- dv.x = xPos+xDif+i/64;
- dv.z = yPos+yDif;
- dv.y = startHeight+i;
- effectGiveAuxVar(100);
- addEffect(&dv,EFFECT_EXPLOSION, EXPLOSION_TYPE_MEDIUM,false,NULL,0);
- dv.x = xPos-xDif+i/64;
- dv.z = yPos-yDif;
- dv.y = startHeight+i;
- effectGiveAuxVar(100);
- addEffect(&dv,EFFECT_EXPLOSION, EXPLOSION_TYPE_MEDIUM,false,NULL,0);
- dv.x = xPos+xDif+i/64;
- dv.z = yPos-yDif;
- dv.y = startHeight+i;
- effectGiveAuxVar(100);
- addEffect(&dv,EFFECT_EXPLOSION, EXPLOSION_TYPE_MEDIUM,false,NULL,0);
- dv.x = xPos-xDif+i/64;
- dv.z = yPos+yDif;
- dv.y = startHeight+i;
- effectGiveAuxVar(100);
- addEffect(&dv,EFFECT_EXPLOSION, EXPLOSION_TYPE_MEDIUM,false,NULL,0);
- }
- }
- }
- if(graphicsTime - psEffect->birthTime < 1000)
- {
- light.position.x = xPos;
- light.position.y = startHeight;
- light.position.z = yPos;
- light.range = 800;
- light.colour = LIGHT_BLUE;
- processLight(&light);
- }
- else
- {
- killEffect(psEffect);
- }
- }
- /** The update function for the explosions */
- static void updateExplosion(EFFECT *psEffect)
- {
- LIGHT light;
- UDWORD percent;
- UDWORD range;
- float scaling;
- if (TEST_LIT(psEffect))
- {
- if (psEffect->lifeSpan)
- {
- percent = PERCENT(graphicsTime - psEffect->birthTime, psEffect->lifeSpan);
- if (percent > 100)
- {
- percent = 100;
- }
- else if (percent > 50)
- {
- percent = 100 - percent;
- }
- }
- else
- {
- percent = 100;
- }
- range = percent;
- light.position.x = psEffect->position.x;
- light.position.y = psEffect->position.y;
- light.position.z = psEffect->position.z;
- light.range = (3*range)/2;
- light.colour = LIGHT_RED;
- processLight(&light);
- }
- if (psEffect->type == EXPLOSION_TYPE_SHOCKWAVE)
- {
- psEffect->size += graphicsTimeAdjustedIncrement(SHOCKWAVE_SPEED);
- scaling = (float)psEffect->size / (float)MAX_SHOCKWAVE_SIZE;
- psEffect->frameNumber = scaling * effectGetNumFrames(psEffect);
- light.position.x = psEffect->position.x;
- light.position.y = psEffect->position.y;
- light.position.z = psEffect->position.z;
- light.range = psEffect->size+200;
- light.colour = LIGHT_YELLOW;
- processLight(&light);
- if (psEffect->size > MAX_SHOCKWAVE_SIZE || light.range > 600)
- {
- /* Kill it off */
- killEffect(psEffect);
- return;
- }
- }
- /* Time to update the frame number on the explosion */
- else while (graphicsTime - psEffect->lastFrame > psEffect->frameDelay)
- {
- psEffect->lastFrame += psEffect->frameDelay;
- /* Are we on the last frame? */
- if (++psEffect->frameNumber >= effectGetNumFrames(psEffect))
- {
- if (psEffect->type != EXPLOSION_TYPE_LAND_LIGHT)
- {
- /* Kill it off */
- killEffect(psEffect);
- return;
- }
- else
- {
- psEffect->frameNumber = 0;
- }
- }
- }
- if(!gamePaused())
- {
- /* Tesla explosions are the only ones that rise, or indeed move */
- if(psEffect->type == EXPLOSION_TYPE_TESLA)
- {
- psEffect->position.y += graphicsTimeAdjustedIncrement(psEffect->velocity.y);
- }
- }
- }
- /** The update function for blood */
- static void updateBlood(EFFECT *psEffect)
- {
- /* Time to update the frame number on the blood */
- if(graphicsTime - psEffect->lastFrame > psEffect->frameDelay)
- {
- psEffect->lastFrame = graphicsTime;
- /* Are we on the last frame? */
- if(++psEffect->frameNumber >= effectGetNumFrames(psEffect))
- {
- /* Kill it off */
- killEffect(psEffect);
- return;
- }
- }
- /* Move it about in the world */
- psEffect->position.x += graphicsTimeAdjustedIncrement(psEffect->velocity.x);
- psEffect->position.y += graphicsTimeAdjustedIncrement(psEffect->velocity.y);
- psEffect->position.z += graphicsTimeAdjustedIncrement(psEffect->velocity.z);
- }
- /** Processes all the drifting smoke
- Handles the smoke puffing out the factory as well */
- static void updatePolySmoke(EFFECT *psEffect)
- {
- /* Time to update the frame number on the smoke sprite */
- while (graphicsTime - psEffect->lastFrame > psEffect->frameDelay)
- {
- /* Store away last frame change time */
- psEffect->lastFrame += psEffect->frameDelay;
- /* Are we on the last frame? */
- if(++psEffect->frameNumber >= effectGetNumFrames(psEffect))
- {
- /* Does the anim wrap around? */
- if(TEST_CYCLIC(psEffect))
- {
- /* Does it change drift direction? */
- if(psEffect->type == SMOKE_TYPE_DRIFTING)
- {
- /* Make it change direction */
- psEffect->velocity.x = (float)(rand() % 20);
- psEffect->velocity.z = (float)(10 - rand() % 20);
- psEffect->velocity.y = (float)(10 + rand() % 20);
- }
- /* Reset the frame */
- psEffect->frameNumber = 0;
- }
- else
- {
- /* Kill it off */
- killEffect(psEffect);
- return;
- }
- }
- }
- /* Update position */
- psEffect->position.x += graphicsTimeAdjustedIncrement(psEffect->velocity.x);
- psEffect->position.y += graphicsTimeAdjustedIncrement(psEffect->velocity.y);
- psEffect->position.z += graphicsTimeAdjustedIncrement(psEffect->velocity.z);
- /* If it doesn't get killed by frame number, then by age */
- if(TEST_CYCLIC(psEffect))
- {
- /* Has it overstayed it's welcome? */
- if(graphicsTime - psEffect->birthTime > psEffect->lifeSpan)
- {
- /* Kill it */
- killEffect(psEffect);
- }
- }
- }
- /**
- Gravitons just fly up for a bit and then drop down and are
- killed off when they hit the ground
- */
- static void updateGraviton(EFFECT *psEffect)
- {
- float accel;
- Vector3i dv;
- MAPTILE *psTile;
- LIGHT light;
- if(psEffect->type!=GRAVITON_TYPE_GIBLET)
- {
- light.position.x = psEffect->position.x;
- light.position.y = psEffect->position.y;
- light.position.z = psEffect->position.z;
- light.range = 128;
- light.colour = LIGHT_YELLOW;
- processLight(&light);
- }
- if(gamePaused())
- {
- /* Only update the lights if it's paused */
- return;
- }
- /* Move it about in the world */
- psEffect->position.x += graphicsTimeAdjustedIncrement(psEffect->velocity.x);
- psEffect->position.y += graphicsTimeAdjustedIncrement(psEffect->velocity.y);
- psEffect->position.z += graphicsTimeAdjustedIncrement(psEffect->velocity.z);
- /* If it's bounced/drifted off the map then kill it */
- if (map_coord(psEffect->position.x) >= mapWidth
- || map_coord(psEffect->position.z) >= mapHeight)
- {
- killEffect(psEffect);
- return;
- }
- int groundHeight = map_Height(psEffect->position.x, psEffect->position.z);
- /* If it's going up and it's still under the landscape, then remove it... */
- if (psEffect->position.y<groundHeight
- && psEffect->velocity.y > 0)
- {
- killEffect(psEffect);
- return;
- }
- /* Does it emit a trail? And is it high enough? */
- if ((psEffect->type == GRAVITON_TYPE_EMITTING_DR)
- || ((psEffect->type == GRAVITON_TYPE_EMITTING_ST)
- && (psEffect->position.y>(groundHeight+10))))
- {
- /* Time to add another trail 'thing'? */
- if(graphicsTime > psEffect->lastFrame + psEffect->frameDelay)
- {
- /* Store away last update */
- psEffect->lastFrame = graphicsTime;
- /* Add an effect at the gravitons's position */
- dv.x = psEffect->position.x;
- dv.y = psEffect->position.y;
- dv.z = psEffect->position.z;
- /* Add a trail graphic */
- addEffect(&dv,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
- }
- }
- else if(psEffect->type == GRAVITON_TYPE_GIBLET && (psEffect->position.y>(groundHeight+5)))
- {
- /* Time to add another trail 'thing'? */
- if(graphicsTime > psEffect->lastFrame + psEffect->frameDelay)
- {
- /* Store away last update */
- psEffect->lastFrame = graphicsTime;
- /* Add an effect at the gravitons's position */
- dv.x = psEffect->position.x;
- dv.y = psEffect->position.y;
- dv.z = psEffect->position.z;
- addEffect(&dv,EFFECT_BLOOD,BLOOD_TYPE_NORMAL,false,NULL,0);
- }
- }
- /* Spin it round a bit */
- psEffect->rotation.x += graphicsTimeAdjustedIncrement(psEffect->spin.x);
- psEffect->rotation.y += graphicsTimeAdjustedIncrement(psEffect->spin.y);
- psEffect->rotation.z += graphicsTimeAdjustedIncrement(psEffect->spin.z);
- /* Update velocity (and retarding of descent) according to present frame rate */
- accel = graphicsTimeAdjustedIncrement(GRAVITON_GRAVITY);
- psEffect->velocity.y += accel;
- /* If it's bounced/drifted off the map then kill it */
- if ((int)psEffect->position.x <= TILE_UNITS
- || (int)psEffect->position.z <= TILE_UNITS)
- {
- killEffect(psEffect);
- return;
- }
- /* Are we below it? - Hit the ground? */
- if ((int)psEffect->position.y < (int)groundHeight)
- {
- psTile = mapTile(map_coord(psEffect->position.x), map_coord(psEffect->position.z));
- if (terrainType(psTile) == TER_WATER)
- {
- killEffect(psEffect);
- return;
- }
- else
- /* Are we falling - rather than rising? */
- if((int)psEffect->velocity.y < 0)
- {
- /* Has it sufficient energy to keep bouncing? */
- if (abs(psEffect->velocity.y) > 16
- && psEffect->specific <= 2)
- {
- psEffect->specific++;
- /* Half it's velocity */
- psEffect->velocity.y/=(float)(-2); // only y gets flipped
- /* Set it at ground level - may have gone through */
- psEffect->position.y = (float)groundHeight;
- }
- else
- {
- /* Giblets don't blow up when they hit the ground! */
- if(psEffect->type!=GRAVITON_TYPE_GIBLET)
- {
- /* Remove the graviton and add an explosion */
- dv.x = psEffect->position.x;
- dv.y = psEffect->position.y + 10;
- dv.z = psEffect->position.z;
- addEffect(&dv,EFFECT_EXPLOSION,EXPLOSION_TYPE_VERY_SMALL,false,NULL,0);
- }
- killEffect(psEffect);
- return;
- }
- }
- }
- }
- /** This isn't really an on-screen effect itself - it just spawns other ones.... */
- static void updateDestruction(EFFECT *psEffect)
- {
- Vector3i pos;
- UDWORD effectType;
- UDWORD widthScatter = 0, breadthScatter = 0, heightScatter = 0;
- SDWORD iX, iY;
- LIGHT light;
- int percent;
- UDWORD range;
- float div;
- UDWORD height;
- percent = PERCENT(graphicsTime - psEffect->birthTime, psEffect->lifeSpan);
- if(percent > 100)
- {
- percent = 100;
- }
- range = 50 - abs(50-percent);
- light.position.x = psEffect->position.x;
- light.position.y = psEffect->position.y;
- light.position.z = psEffect->position.z;
- if(psEffect->type == DESTRUCTION_TYPE_STRUCTURE)
- {
- light.range = range*10;
- }
- else
- {
- light.range = range*4;
- }
- if(psEffect->type == DESTRUCTION_TYPE_POWER_STATION)
- {
- light.range *=3;
- light.colour = LIGHT_WHITE;
- }
- else
- {
- light.colour = LIGHT_RED;
- }
- processLight(&light);
- if(graphicsTime > psEffect->birthTime + psEffect->lifeSpan)
- {
- /* Kill it - it's too old */
- killEffect(psEffect);
- return;
- }
- if(psEffect->type == DESTRUCTION_TYPE_SKYSCRAPER)
- {
- if(graphicsTime - psEffect->birthTime > psEffect->lifeSpan * 9/10)
- {
- pos.x = psEffect->position.x;
- pos.z = psEffect->position.z;
- pos.y = psEffect->position.y;
- addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_LARGE,false,NULL,0);
- killEffect(psEffect);
- return;
- }
- div = 1.f - (float)(graphicsTime - psEffect->birthTime) / psEffect->lifeSpan;
- if(div < 0.f)
- div = 0.f;
- height = div * psEffect->imd->max.y;
- }
- else
- {
- height = 16;
- }
- /* Time to add another effect? */
- if((graphicsTime - psEffect->lastFrame) > psEffect->frameDelay)
- {
- psEffect->lastFrame = graphicsTime;
- switch(psEffect->type)
- {
- case DESTRUCTION_TYPE_SKYSCRAPER:
- widthScatter = TILE_UNITS;
- breadthScatter = TILE_UNITS;
- heightScatter = TILE_UNITS;
- break;
- case DESTRUCTION_TYPE_POWER_STATION:
- case DESTRUCTION_TYPE_STRUCTURE:
- widthScatter = TILE_UNITS/2;
- breadthScatter = TILE_UNITS/2;
- heightScatter = TILE_UNITS/4;
- break;
- case DESTRUCTION_TYPE_DROID:
- case DESTRUCTION_TYPE_WALL_SECTION:
- case DESTRUCTION_TYPE_FEATURE:
- widthScatter = TILE_UNITS/6;
- breadthScatter = TILE_UNITS/6;
- heightScatter = TILE_UNITS/6;
- break;
- default:
- ASSERT( false,"Weirdy destruction type effect" );
- break;
- }
- /* Find a position to dump it at */
- pos.x = psEffect->position.x + widthScatter - rand() % (2 * widthScatter);
- pos.z = psEffect->position.z + breadthScatter - rand() % (2 * breadthScatter);
- pos.y = psEffect->position.y + height + rand() % heightScatter;
- if(psEffect->type == DESTRUCTION_TYPE_SKYSCRAPER)
- {
- pos.y = psEffect->position.y + height;
- }
- /* Choose an effect */
- effectType = rand()%15;
- switch(effectType)
- {
- case 0:
- addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_DRIFTING,false,NULL,0);
- break;
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- if(psEffect->type == DESTRUCTION_TYPE_SKYSCRAPER)
- {
- addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_LARGE,false,NULL,0);
- }
- /* Only structures get the big explosions */
- else if(psEffect->type==DESTRUCTION_TYPE_STRUCTURE)
- {
- addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_MEDIUM,false,NULL,0);
- }
- else
- {
- addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_SMALL,false,NULL,0);
- }
- break;
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- if(psEffect->type == DESTRUCTION_TYPE_STRUCTURE)
- {
- addEffect(&pos,EFFECT_GRAVITON,GRAVITON_TYPE_EMITTING_ST,true,getRandomDebrisImd(),0);
- }
- else
- {
- addEffect(&pos,EFFECT_GRAVITON,GRAVITON_TYPE_EMITTING_DR,true,getRandomDebrisImd(),0);
- }
- break;
- case 11:
- addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_DRIFTING,false,NULL,0);
- break;
- case 12:
- case 13:
- addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_SMALL,false,NULL,0);
- break;
- case 14:
- /* Add sound effect, but only if we're less than 3/4 of the way thru' destruction */
- if (graphicsTime < (psEffect->birthTime + psEffect->lifeSpan) * 3/4)
- {
- iX = psEffect->position.x;
- iY = psEffect->position.z;
- audio_PlayStaticTrack( iX, iY, ID_SOUND_EXPLOSION );
- }
- break;
- }
- }
- }
- /** Moves the construction graphic about - dust cloud or whatever.... */
- static void updateConstruction(EFFECT *psEffect)
- {
- /* Time to update the frame number on the construction sprite */
- if(graphicsTime - psEffect->lastFrame > psEffect->frameDelay)
- {
- psEffect->lastFrame = graphicsTime;
- /* Are we on the last frame? */
- if(++psEffect->frameNumber >= effectGetNumFrames(psEffect))
- {
- /* Is it a cyclic sprite? */
- if(TEST_CYCLIC(psEffect))
- {
- psEffect->frameNumber = 0;
- }
- else
- {
- killEffect(psEffect);
- return;
- }
- }
- }
- /* Move it about in the world */
- psEffect->position.x += graphicsTimeAdjustedIncrement(psEffect->velocity.x);
- psEffect->position.y += graphicsTimeAdjustedIncrement(psEffect->velocity.y);
- psEffect->position.z += graphicsTimeAdjustedIncrement(psEffect->velocity.z);
- /* If it doesn't get killed by frame number, then by height */
- if(TEST_CYCLIC(psEffect))
- {
- /* Has it hit the ground */
- if ((int)psEffect->position.y <=
- map_Height(psEffect->position.x, psEffect->position.z))
- {
- killEffect(psEffect);
- return;
- }
- if (graphicsTime - psEffect->birthTime > psEffect->lifeSpan)
- {
- killEffect(psEffect);
- return;
- }
- }
- }
- /** Update fire sequences */
- static void updateFire(EFFECT *psEffect)
- {
- Vector3i pos;
- LIGHT light;
- UDWORD percent;
- percent = PERCENT(graphicsTime - psEffect->birthTime, std::max<unsigned>(psEffect->lifeSpan, 1));
- if(percent > 100)
- {
- percent = 100;
- }
- light.position.x = psEffect->position.x;
- light.position.y = psEffect->position.y;
- light.position.z = psEffect->position.z;
- light.range = (percent*psEffect->radius*3)/100;
- light.colour = LIGHT_RED;
- processLight(&light);
- /* Time to update the frame number on the construction sprite */
- if (graphicsTime - psEffect->lastFrame > psEffect->frameDelay)
- {
- psEffect->lastFrame = graphicsTime;
- pos.x = (psEffect->position.x + ((rand() % psEffect->radius) - (rand() % (2 * psEffect->radius))));
- pos.z = (psEffect->position.z + ((rand() % psEffect->radius) - (rand() % (2 * psEffect->radius))));
- // Effect is off map, no need to update it anymore
- if(!worldOnMap(pos.x, pos.z))
- {
- killEffect(psEffect);
- return;
- }
- pos.y = map_Height(pos.x,pos.z);
- if(psEffect->type == FIRE_TYPE_SMOKY_BLUE)
- {
- addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_FLAMETHROWER,false,NULL,0);
- }
- else
- {
- addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_SMALL,false,NULL,0);
- }
- if(psEffect->type == FIRE_TYPE_SMOKY || psEffect->type == FIRE_TYPE_SMOKY_BLUE)
- {
- pos.x = (psEffect->position.x + ((rand() % psEffect->radius / 2) - (rand() % (2 * psEffect->radius / 2))));
- pos.z = (psEffect->position.z + ((rand() % psEffect->radius / 2) - (rand() % (2 * psEffect->radius / 2))));
- pos.y = map_Height(pos.x,pos.z);
- addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_DRIFTING_HIGH,false,NULL,0);
- }
- else
- {
- pos.x = (psEffect->position.x + ((rand() % psEffect->radius) - (rand() % (2 * psEffect->radius))));
- pos.z = (psEffect->position.z + ((rand() % psEffect->radius) - (rand() % (2 * psEffect->radius))));
- // Effect is off map, no need to update it anymore
- if(!worldOnMap(pos.x, pos.z))
- {
- killEffect(psEffect);
- return;
- }
- pos.y = map_Height(pos.x,pos.z);
- addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_SMALL,false,NULL,0);
- }
- /*
- pos.x = psEffect->position.x;
- pos.y = psEffect->position.y;
- pos.z = psEffect->position.z;
- scatter.x = psEffect->radius; scatter.y = 0; scatter.z = psEffect->radius;
- addMultiEffect(&pos,&scatter,EFFECT_EXPLOSION,EXPLOSION_TYPE_SMALL,false,NULL,2,0,0);
- */
- }
- if (graphicsTime - psEffect->birthTime > psEffect->lifeSpan)
- {
- killEffect(psEffect);
- return;
- }
- }
- // ----------------------------------------------------------------------------------------
- // ALL THE RENDER FUNCTIONS
- // ----------------------------------------------------------------------------------------
- /** Calls the appropriate render routine for each type of effect */
- void renderEffect(const EFFECT *psEffect)
- {
- /* What type of effect are we dealing with? */
- switch(psEffect->group)
- {
- case EFFECT_WAYPOINT:
- renderWaypointEffect(psEffect);
- return;
- case EFFECT_EXPLOSION:
- renderExplosionEffect(psEffect);
- return;
- case EFFECT_CONSTRUCTION:
- renderConstructionEffect(psEffect);
- return;
- case EFFECT_SMOKE:
- renderSmokeEffect(psEffect);
- return;
- case EFFECT_GRAVITON:
- renderGravitonEffect(psEffect);
- return;
- case EFFECT_BLOOD:
- renderBloodEffect(psEffect);
- return;
- case EFFECT_DESTRUCTION:
- /* There is no display func for a destruction effect -
- it merely spawn other effects over time */
- renderDestructionEffect(psEffect);
- return;
- case EFFECT_FIRE:
- /* Likewise */
- return;
- case EFFECT_SAT_LASER:
- /* Likewise */
- return;
- case EFFECT_FIREWORK:
- renderFirework(psEffect);
- return;
- case EFFECT_FREED:
- break;
- }
- debug( LOG_ERROR, "Weirdy class of effect passed to renderEffect" );
- abort();
- }
- /** drawing func for wapypoints */
- static void renderWaypointEffect(const EFFECT *psEffect)
- {
- positionEffect(psEffect);
- pie_Draw3DShape(psEffect->imd, 0, 0, WZCOL_WHITE, 0, 0);
- pie_MatEnd();
- }
- static void renderFirework(const EFFECT *psEffect)
- {
- /* these don't get rendered */
- if(psEffect->type == FIREWORK_TYPE_LAUNCHER)
- {
- return;
- }
- positionEffect(psEffect);
- pie_MatRotY(-player.r.y);
- pie_MatRotX(-player.r.x);
- pie_MatScale(psEffect->size / 100.f);
- pie_Draw3DShape(psEffect->imd, psEffect->frameNumber, 0, WZCOL_WHITE, pie_ADDITIVE, EFFECT_EXPLOSION_ADDITIVE);
- pie_MatEnd();
- }
- /** drawing func for blood. */
- static void renderBloodEffect(const EFFECT *psEffect)
- {
- positionEffect(psEffect);
- pie_MatRotY(-player.r.y);
- pie_MatRotX(-player.r.x);
- pie_MatScale(psEffect->size / 100.f);
- pie_Draw3DShape(getImdFromIndex(MI_BLOOD), psEffect->frameNumber, 0, WZCOL_WHITE, pie_TRANSLUCENT, EFFECT_BLOOD_TRANSPARENCY);
- pie_MatEnd();
- }
- static void renderDestructionEffect(const EFFECT *psEffect)
- {
- float div;
- SDWORD percent;
- if(psEffect->type!=DESTRUCTION_TYPE_SKYSCRAPER)
- {
- return;
- }
- positionEffect(psEffect);
- div = (float)(graphicsTime - psEffect->birthTime) / psEffect->lifeSpan;
- if(div>1.0) div = 1.0; //temporary!
- {
- div = 1.0 - div;
- percent = (SDWORD)(div*pie_RAISE_SCALE);
- }
- if(!gamePaused())
- {
- pie_MatRotX(SKY_SHIMMY);
- pie_MatRotY(SKY_SHIMMY);
- pie_MatRotZ(SKY_SHIMMY);
- }
- pie_Draw3DShape(psEffect->imd, 0, 0, WZCOL_WHITE, pie_RAISE, percent);
- pie_MatEnd();
- }
- static bool rejectLandLight(LAND_LIGHT_SPEC type)
- {
- unsigned int timeSlice = graphicsTime%2000;
- if (timeSlice < 400)
- {
- return (type != LL_MIDDLE); // reject all expect middle
- }
- else if (timeSlice < 800)
- {
- return (type == LL_OUTER); // reject only outer
- }
- else if (timeSlice < 1200)
- {
- return(false); //reject none
- }
- else if (timeSlice < 1600)
- {
- return (type == LL_OUTER); // reject only outer
- }
- else
- {
- return (type != LL_MIDDLE); // reject all expect middle
- }
- }
- /** Renders the standard explosion effect */
- static void renderExplosionEffect(const EFFECT *psEffect)
- {
- const PIELIGHT brightness = WZCOL_WHITE;
- if(psEffect->type == EXPLOSION_TYPE_LAND_LIGHT)
- {
- if(rejectLandLight((LAND_LIGHT_SPEC)psEffect->specific))
- {
- return;
- }
- }
- positionEffect(psEffect);
- /* Bit in comments - doesn't quite work yet? */
- if(TEST_FACING(psEffect))
- {
- /* Always face the viewer! */
- // TODO This only faces towards the viewer, if the effect is in the middle of the screen... It draws the effect parallel with the screens near/far planes.
- pie_MatRotY(-player.r.y);
- pie_MatRotX(-player.r.x);
- }
- /* Tesla explosions diminish in size */
- if(psEffect->type == EXPLOSION_TYPE_TESLA)
- {
- float scale = (graphicsTime - psEffect->birthTime) / (float)psEffect->lifeSpan;
- if (scale < 0.f)
- scale = 0.f;
- else if (scale > .45f)
- scale = .45f;
- pie_MatScale(psEffect->size / 100.f - scale);
- }
- else if(psEffect->type == EXPLOSION_TYPE_PLASMA)
- {
- float scale = (graphicsTime - psEffect->birthTime) / (float)psEffect->lifeSpan / 3.f;
- pie_MatScale(BASE_PLASMA_SIZE / 100.f + scale);
- }
- else
- {
- pie_MatScale(psEffect->size / 100.f);
- }
- bool premultiplied = false;
- if (psEffect->imd->flags & iV_IMD_PREMULTIPLIED)
- {
- premultiplied = true;
- }
- if (premultiplied)
- {
- pie_Draw3DShape(psEffect->imd, psEffect->frameNumber, 0, brightness, pie_PREMULTIPLIED, 0);
- }
- else if (psEffect->type == EXPLOSION_TYPE_PLASMA)
- {
- pie_Draw3DShape(psEffect->imd, psEffect->frameNumber, 0, brightness, pie_ADDITIVE, EFFECT_PLASMA_ADDITIVE);
- }
- else if(psEffect->type == EXPLOSION_TYPE_KICKUP)
- {
- pie_Draw3DShape(psEffect->imd, psEffect->frameNumber, 0, brightness, pie_TRANSLUCENT, 128);
- }
- else
- {
- pie_Draw3DShape(psEffect->imd, psEffect->frameNumber, 0, brightness, pie_ADDITIVE, EFFECT_EXPLOSION_ADDITIVE);
- }
- pie_MatEnd();
- }
- static void renderGravitonEffect(const EFFECT *psEffect)
- {
- positionEffect(psEffect);
- pie_MatRotX(psEffect->rotation.x);
- pie_MatRotY(psEffect->rotation.y);
- pie_MatRotZ(psEffect->rotation.z);
- /* Buildings emitted by gravitons are chunkier */
- if(psEffect->type == GRAVITON_TYPE_EMITTING_ST)
- {
- /* Twice as big - 150 percent */
- pie_MatScale(psEffect->size / 100.f);
- }
- pie_Draw3DShape(psEffect->imd, psEffect->frameNumber, psEffect->player, WZCOL_WHITE, 0, 0);
- /* Pop the matrix */
- pie_MatEnd();
- }
- /** Renders the standard construction effect */
- static void renderConstructionEffect(const EFFECT *psEffect)
- {
- Vector3i null;
- int percent, translucency;
- float size;
- /* No rotation about arbitrary axis */
- null.x = null.y = null.z = 0;
- positionEffect(psEffect);
- /* Bit in comments doesn't quite work yet? */
- if(TEST_FACING(psEffect))
- {
- pie_MatRotY(-player.r.y);
- pie_MatRotX(-player.r.x);
- }
- /* Scale size according to age */
- percent = PERCENT(graphicsTime - psEffect->birthTime, psEffect->lifeSpan);
- if(percent<0) percent = 0;
- if(percent>100) percent = 100;
- /* Make imds be transparent on 3dfx */
- if(percent<50)
- {
- translucency = percent * 2;
- }
- else
- {
- translucency = (100 - percent) * 2;
- }
- translucency+=10;
- size = MIN(2.f * translucency / 100.f, .90f);
- pie_MatScale(size);
- pie_Draw3DShape(psEffect->imd, psEffect->frameNumber, 0, WZCOL_WHITE, pie_TRANSLUCENT, translucency);
- /* Pop the matrix */
- pie_MatEnd();
- }
- /** Renders the standard smoke effect - it is now scaled in real-time as well */
- static void renderSmokeEffect(const EFFECT *psEffect)
- {
- int transparency = 0;
- const PIELIGHT brightness = WZCOL_WHITE;
- positionEffect(psEffect);
- /* Bit in comments doesn't quite work yet? */
- if(TEST_FACING(psEffect))
- {
- /* Always face the viewer! */
- pie_MatRotY(-player.r.y);
- pie_MatRotX(-player.r.x);
- }
- if(TEST_SCALED(psEffect))
- {
- const unsigned int lifetime = graphicsTime - psEffect->birthTime;
- unsigned int percent;
- // Since psEffect->birthTime will be set to graphicsTime on
- // creation, and graphicsTime only increments, birthTime should be
- // smaller than or equal to graphicsTime. As a great man once said
- // though (hehe, I just love exaggarating ;-) -- Giel):
- // "Always assert your assumptions!". So here it goes:
- assert(psEffect->birthTime <= graphicsTime);
- ASSERT(psEffect->lifeSpan != 0, "Effect lifespan is zero (seconds); it really should be non-zero!");
- // HACK: Work around a bug that bit me causing a "integer divide by zero" at this location -- Giel
- if (psEffect->lifeSpan != 0)
- percent = (lifetime * 100) / psEffect->lifeSpan;
- else
- percent = 100;
- pie_MatScale((percent + psEffect->baseScale) / 100.f);
- transparency = (EFFECT_SMOKE_TRANSPARENCY * (100 - percent))/100;
- }
- transparency = (transparency * 3) / 2; //JPS smoke strength incr…
Large files files are truncated, but you can click here to view the full file