// cl_tent.c -- client side temporary entities // HEADER FILES ------------------------------------------------------------ #include "quakedef.h" // MACROS ------------------------------------------------------------------ #define MAX_BEAMS 8 #define MAX_STREAMS 32 #define MAX_STREAM_ENTITIES 128 #define STREAM_ATTACHED 16 #define STREAM_TRANSLUCENT 32 #define MAX_EXPLOSIONS 128 #define FRANDOM() (rand()*(1.0/RAND_MAX)) static unsigned int randomseed; void setseed(unsigned int seed) { randomseed = seed; } //unsigned int seedrand(int max) float seedrand(void) { randomseed = (randomseed * 877 + 573) % 9968; return (float)randomseed / 9968; } // TYPES ------------------------------------------------------------------- typedef struct { int entity; struct model_s *model; float endtime; vec3_t start, end; } beam_t; typedef struct { int type; int entity; int tag; int flags; int skin; struct model_s *models[4]; vec3_t source; vec3_t dest; vec3_t offset; float endTime; float lastTrailTime; } stream_t; typedef struct explosion_t explosion_t; typedef enum { EXFLAG_ROTATE = 1, EXFLAG_COLLIDE = 2, EXFLAG_STILL_FRAME = 4 } exflags_t; struct explosion_t { vec3_t origin; vec3_t oldorg;// holds position from last frame float startTime; float endTime; vec3_t velocity; vec3_t accel; vec3_t angles; vec3_t avel; // angular velocity int flags; int abslight; exflags_t exflags; int skin; int scale; model_t *model; void (*frameFunc)(explosion_t *ex); void (*removeFunc)(explosion_t *ex); float data; //for easy transition of script code that relied on counters of some sort }; // PUBLIC FUNCTION DEFINITIONS --------------------------------------------- int TempSoundChannel() { static int last = -1; last--; if(last<-20) last=-1; return last; } // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void ParseStream(int type); static stream_t *NewStream(int ent, int tag, int *isNew); void MultiGrenadeThink (explosion_t *ex); void MultiGrenadePieceThink (explosion_t *ex); void MultiGrenadePiece2Think (explosion_t *ex); void ChunkThink(explosion_t *ex); void BubbleThink(explosion_t *ex); void MissileFlashThink(explosion_t *ex); void TeleportFlashThink(explosion_t *ex); void CheckSpaceThink(explosion_t *ex); void SwordFrameFunc(explosion_t *ex); void zapFrameFunc(explosion_t *ex); void fireBallUpdate(explosion_t *ex); void sunBallUpdate(explosion_t *ex); void sunPowerUpdate(explosion_t *ex); void purify1Update(explosion_t *ex); void telEffectUpdate (explosion_t *ex); void CL_UpdateTargetBall(void); void updateBloodRain(explosion_t *ex); void updatePurify2(explosion_t *ex); void updateSwordShot(explosion_t *ex); void updateIceShot(explosion_t *ex); void updateMeteor(explosion_t *ex); void SmokeRingFrameFunc(explosion_t *ex); void updateAcidBlob(explosion_t *ex); void updateAcidBall(explosion_t *ex); void MeteorCrushSpawnThink(explosion_t *ex); // PRIVATE DATA DEFINITIONS ------------------------------------------------ beam_t cl_beams[MAX_BEAMS]; explosion_t cl_explosions[MAX_EXPLOSIONS]; static stream_t cl_Streams[MAX_STREAMS]; static entity_t StreamEntities[MAX_STREAM_ENTITIES]; static int StreamEntityCount; static int MultiGrenadeCurrentChannel; //sfx_t *cl_sfx_wizhit; //sfx_t *cl_sfx_knighthit; sfx_t *cl_sfx_tink1; sfx_t *cl_sfx_ric1; sfx_t *cl_sfx_ric2; sfx_t *cl_sfx_ric3; sfx_t *cl_sfx_r_exp3; sfx_t *cl_sfx_explode; sfx_t *cl_sfx_bonehit; sfx_t *cl_sfx_bonewal; sfx_t *cl_sfx_bonephit; sfx_t *cl_sfx_ravendie; sfx_t *cl_sfx_buzzbee; sfx_t *cl_sfx_iceflesh; sfx_t *cl_sfx_icewall; sfx_t *cl_sfx_iceshatter; sfx_t *cl_sfx_icestorm; sfx_t *cl_sfx_sunstaff; sfx_t *cl_sfx_sunhit; sfx_t *cl_sfx_lightning1; sfx_t *cl_sfx_lightning2; sfx_t *cl_sfx_hammersound; sfx_t *cl_sfx_tornado; sfx_t *cl_sfx_swordExplode; sfx_t *cl_sfx_axeBounce; sfx_t *cl_sfx_axeExplode; sfx_t *cl_sfx_fireBall; sfx_t *cl_sfx_purify2; sfx_t *cl_sfx_telefrag; sfx_t *cl_sfx_big_gib; sfx_t *cl_sfx_gib1; sfx_t *cl_sfx_gib2; sfx_t *cl_sfx_purify1_fire; sfx_t *cl_sfx_purify1_hit; sfx_t *cl_sfx_acidhit; sfx_t *cl_sfx_dropfizzle; sfx_t *cl_sfx_flameend; sfx_t *cl_sfx_teleport[5]; sfx_t *cl_sfx_ravengo; /* ================= CL_ParseTEnts ================= */ void CL_InitTEnts (void) { // cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); // cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav"); cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav"); cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav"); cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); cl_sfx_explode = S_PrecacheSound ("weapons/explode.wav"); cl_sfx_bonephit = S_PrecacheSound ("necro/bonephit.wav"); cl_sfx_bonehit = S_PrecacheSound ("necro/bonenhit.wav"); cl_sfx_bonewal = S_PrecacheSound ("necro/bonenwal.wav"); cl_sfx_ravendie = S_PrecacheSound ("raven/death.wav"); cl_sfx_buzzbee = S_PrecacheSound ("assassin/scrbfly.wav"); cl_sfx_iceflesh = S_PrecacheSound ("crusader/icehit.wav"); cl_sfx_icewall = S_PrecacheSound ("crusader/icewall.wav"); cl_sfx_iceshatter = S_PrecacheSound ("misc/icestatx.wav"); cl_sfx_icestorm = S_PrecacheSound ("crusader/blizzard.wav"); cl_sfx_sunstaff = S_PrecacheSound ("crusader/sunhum.wav"); cl_sfx_sunhit = S_PrecacheSound ("crusader/sunhit.wav"); cl_sfx_lightning1 = S_PrecacheSound ("crusader/lghtn1.wav"); cl_sfx_lightning2 = S_PrecacheSound ("crusader/lghtn2.wav"); cl_sfx_hammersound = S_PrecacheSound ("paladin/axblade.wav"); cl_sfx_tornado = S_PrecacheSound ("crusader/tornado.wav"); cl_sfx_swordExplode = S_PrecacheSound ("weapons/explode.wav"); cl_sfx_axeBounce = S_PrecacheSound ("paladin/axric1.wav"); cl_sfx_axeExplode = S_PrecacheSound ("weapons/explode.wav"); cl_sfx_fireBall = S_PrecacheSound ("weapons/fbfire.wav"); cl_sfx_purify2 = S_PrecacheSound ("weapons/exphuge.wav"); cl_sfx_telefrag = S_PrecacheSound ("player/telefrag.wav"); cl_sfx_big_gib = S_PrecacheSound ("player/megagib.wav"); cl_sfx_gib1 = S_PrecacheSound ("player/gib1.wav"); cl_sfx_gib2 = S_PrecacheSound ("player/gib2.wav"); cl_sfx_purify1_fire = S_PrecacheSound ("paladin/purfire.wav"); cl_sfx_purify1_hit = S_PrecacheSound ("weapons/expsmall.wav"); cl_sfx_acidhit = S_PrecacheSound ("succubus/acidhit.wav"); cl_sfx_dropfizzle = S_PrecacheSound ("succubus/dropfizz.wav"); cl_sfx_flameend = S_PrecacheSound ("succubus/flamend.wav"); cl_sfx_teleport[0] = S_PrecacheSound ("misc/teleprt1.wav"); cl_sfx_teleport[1] = S_PrecacheSound ("misc/teleprt2.wav"); cl_sfx_teleport[2] = S_PrecacheSound ("misc/teleprt3.wav"); cl_sfx_teleport[3] = S_PrecacheSound ("misc/teleprt4.wav"); cl_sfx_teleport[4] = S_PrecacheSound ("misc/teleprt5.wav"); cl_sfx_ravengo = S_PrecacheSound ("raven/ravengo.wav"); } static void vectoangles(vec3_t vec, vec3_t ang) { float forward; float yaw, pitch; if (vec[1] == 0 && vec[0] == 0) { yaw = 0; if (vec[2] > 0) pitch = 90; else pitch = 270; } else { yaw = (int) (atan2(vec[1], vec[0]) * 180 / M_PI); if (yaw < 0) yaw += 360; forward = sqrt (vec[0]*vec[0] + vec[1]*vec[1]); pitch = (int) (atan2(vec[2], forward) * 180 / M_PI); if (pitch < 0) pitch += 360; } ang[0] = pitch; ang[1] = yaw; ang[2] = 0; } /* ================= CL_ClearTEnts ================= */ void CL_ClearTEnts (void) { memset (&cl_beams, 0, sizeof(cl_beams)); memset (&cl_explosions, 0, sizeof(cl_explosions)); memset(cl_Streams, 0, sizeof(cl_Streams)); } /* ================= CL_AllocExplosion **** CAREFUL!!! This may overwrite an explosion!!!!! ================= */ explosion_t *CL_AllocExplosion (void) { int i,freeSlot; float time; int index; index = 0; freeSlot = false; for (i=0 ; ientity == ent) { b->entity = ent; b->model = m; b->endtime = cl.time + 0.2; VectorCopy (start, b->start); VectorCopy (end, b->end); return; } // find a free beam for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) { if (!b->model || b->endtime < cl.time) { b->entity = ent; b->model = m; b->endtime = cl.time + 0.2; VectorCopy (start, b->start); VectorCopy (end, b->end); return; } } Con_Printf ("beam list overflow!\n"); } entity_state_t *FindState(int EntNum) { packet_entities_t *pack; static entity_state_t pretend_player; int pnum; if (EntNum >= 1 && EntNum <= MAX_CLIENTS) { EntNum--; if (EntNum == cl.playernum) { VectorCopy(cl.simorg, pretend_player.origin); } else { VectorCopy(cl.frames[cls.netchan.incoming_sequence&UPDATE_MASK].playerstate[EntNum].origin, pretend_player.origin); } return &pretend_player; } pack = &cl.frames[cls.netchan.incoming_sequence&UPDATE_MASK].packet_entities; for (pnum=0 ; pnumnum_entities ; pnum++) { if (pack->entities[pnum].number == EntNum) { return &pack->entities[pnum]; } } return NULL; } //========================================================================== // // CreateStream--for use mainly external to cl_tent (i.e. cl_effect) // // generally pass in 0 for skin // //========================================================================== void CreateStream(int type, int ent, int flags, int tag, float duration, int skin, vec3_t source, vec3_t dest) { stream_t *stream; model_t *models[4]; entity_state_t *state; models[1] = models[2] = models[3] = NULL; switch(type) { case TE_STREAM_CHAIN: models[0] = Mod_ForName("models/stchain.mdl", true); break; case TE_STREAM_SUNSTAFF1: models[0] = Mod_ForName("models/stsunsf1.mdl", true); models[1] = Mod_ForName("models/stsunsf2.mdl", true); models[2] = Mod_ForName("models/stsunsf3.mdl", true); models[3] = Mod_ForName("models/stsunsf4.mdl", true); break; case TE_STREAM_SUNSTAFF2: models[0] = Mod_ForName("models/stsunsf5.mdl", true); models[2] = Mod_ForName("models/stsunsf3.mdl", true); models[3] = Mod_ForName("models/stsunsf4.mdl", true); break; case TE_STREAM_LIGHTNING: models[0] = Mod_ForName("models/stlghtng.mdl", true); break; case TE_STREAM_LIGHTNING_SMALL: models[0] = Mod_ForName("models/stltng2.mdl", true); break; case TE_STREAM_FAMINE: models[0] = Mod_ForName("models/fambeam.mdl", true); break; case TE_STREAM_COLORBEAM: models[0] = Mod_ForName("models/stclrbm.mdl", true); break; case TE_STREAM_ICECHUNKS: models[0] = Mod_ForName("models/stice.mdl", true); break; case TE_STREAM_GAZE: models[0] = Mod_ForName("models/stmedgaz.mdl", true); break; default: Sys_Error("CreateStream: bad type"); } if((stream = NewStream(ent, tag, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } stream->type = type; stream->tag = tag; stream->flags = flags; stream->entity = ent; stream->skin = skin; stream->models[0] = models[0]; stream->models[1] = models[1]; stream->models[2] = models[2]; stream->models[3] = models[3]; stream->endTime = cl.time+duration; stream->lastTrailTime = 0; VectorCopy(source, stream->source); VectorCopy(dest, stream->dest); if(flags&STREAM_ATTACHED) { VectorCopy(vec3_origin, stream->offset); state = FindState(ent); if (state) { // rjr - potential problem if this doesn't ever get set - origin might have to be set properly in script code? VectorSubtract(source, state->origin, stream->offset); } } } void CLTENT_SpawnDeathBubble(vec3_t pos) { explosion_t *ex; int i; //generic spinny impact image ex=CL_AllocExplosion(); VectorCopy(pos,ex->origin); VectorSet(ex->velocity,0,0,17); ex->data=cl.time; ex->scale=128; ex->frameFunc = BubbleThink; ex->startTime=cl.time; ex->endTime=cl.time+15; ex->model=Mod_ForName ("models/s_bubble.spr", true); ex->flags = DRF_TRANSLUCENT | MLS_ABSLIGHT; ex->abslight=175; } void CLTENT_XbowImpact(vec3_t pos, vec3_t vel, int chType, int damage, int arrowType)//arrowType is total # of arrows in effect { explosion_t *ex; float cnt; int i; //generic spinny impact image ex=CL_AllocExplosion(); ex->origin[0]=pos[0]-vel[0]; ex->origin[1]=pos[1]-vel[1]; ex->origin[2]=pos[2]-vel[2]; vectoangles(vel,ex->angles); ex->avel[2]=(rand()%500)+200; ex->scale=10; ex->frameFunc = MissileFlashThink; ex->startTime=cl.time; ex->endTime=cl.time+0.3; ex->model=Mod_ForName ("models/arrowhit.mdl", true); ex->exflags = EXFLAG_ROTATE; ex->flags = DRF_TRANSLUCENT | MLS_ABSLIGHT; ex->abslight=175; //white smoke if invulnerable impact if (!damage) { ex=CL_AllocExplosion(); ex->origin[0]=pos[0]-vel[0]*2; ex->origin[1]=pos[1]-vel[1]*2; ex->origin[2]=pos[2]-vel[2]*2; ex->velocity[0] = 0.0; ex->velocity[1] = 0.0; ex->velocity[2] = 80.0; vectoangles(vel,ex->angles); ex->startTime=cl.time; ex->endTime=cl.time+0.35; ex->model=Mod_ForName ("models/whtsmk1.spr", true); ex->flags = DRF_TRANSLUCENT; if (arrowType == 3)//little arrows go away { if (rand()&3)//chunky go { cnt = rand()%2+1; for(i = 0; i < cnt; i++) { float final; ex = CL_AllocExplosion(); ex->frameFunc = ChunkThink; VectorSubtract(pos,vel,ex->origin); // temp modify them... ex->velocity[0] = (rand()%140)-70; ex->velocity[1] = (rand()%140)-70; ex->velocity[2] = (rand()%140)-70; // are these in degrees or radians? ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = rand()%850 - 425; ex->avel[1] = rand()%850 - 425; ex->avel[2] = rand()%850 - 425; ex->scale = 30 + 100 * (cnt / 40.0) + rand()%40; ex->data = THINGTYPE_WOOD; final = (rand()%100)*.01; if (final < 0.25) ex->model = Mod_ForName ("models/splnter1.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/splnter2.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/splnter3.mdl", true); else ex->model = Mod_ForName ("models/splnter4.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + 4.0; } } else if (rand()&1)//whole go { ex = CL_AllocExplosion(); ex->frameFunc = ChunkThink; VectorSubtract(pos,vel,ex->origin); // temp modify them... ex->velocity[0] = (rand()%140)-70; ex->velocity[1] = (rand()%140)-70; ex->velocity[2] = (rand()%140)-70; // are these in degrees or radians? ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = rand()%850 - 425; ex->avel[1] = rand()%850 - 425; ex->avel[2] = rand()%850 - 425; ex->scale = 128; ex->data = THINGTYPE_WOOD; ex->model = Mod_ForName ("models/arrow.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + 4.0; } } } } //========================================================================== // // ParseStream // //========================================================================== static void ParseStream(int type) { int ent; int tag; int flags; int skin; vec3_t source; vec3_t dest; stream_t *stream; float duration; model_t *models[4]; entity_state_t *state; ent = MSG_ReadShort(); flags = MSG_ReadByte(); tag = flags&15; duration = (float)MSG_ReadByte()*0.05; skin = 0; if(type == TE_STREAM_COLORBEAM) { skin = MSG_ReadByte(); } source[0] = MSG_ReadCoord(); source[1] = MSG_ReadCoord(); source[2] = MSG_ReadCoord(); dest[0] = MSG_ReadCoord(); dest[1] = MSG_ReadCoord(); dest[2] = MSG_ReadCoord(); models[1] = models[2] = models[3] = NULL; switch(type) { case TE_STREAM_CHAIN: models[0] = Mod_ForName("models/stchain.mdl", true); break; case TE_STREAM_SUNSTAFF1: models[0] = Mod_ForName("models/stsunsf1.mdl", true); models[1] = Mod_ForName("models/stsunsf2.mdl", true); models[2] = Mod_ForName("models/stsunsf3.mdl", true); models[3] = Mod_ForName("models/stsunsf4.mdl", true); break; case TE_STREAM_SUNSTAFF2: models[0] = Mod_ForName("models/stsunsf5.mdl", true); models[2] = Mod_ForName("models/stsunsf3.mdl", true); models[3] = Mod_ForName("models/stsunsf4.mdl", true); break; case TE_STREAM_LIGHTNING: models[0] = Mod_ForName("models/stlghtng.mdl", true); break; case TE_STREAM_LIGHTNING_SMALL: models[0] = Mod_ForName("models/stltng2.mdl", true); break; case TE_STREAM_FAMINE: models[0] = Mod_ForName("models/fambeam.mdl", true); break; case TE_STREAM_COLORBEAM: models[0] = Mod_ForName("models/stclrbm.mdl", true); break; case TE_STREAM_ICECHUNKS: models[0] = Mod_ForName("models/stice.mdl", true); break; case TE_STREAM_GAZE: models[0] = Mod_ForName("models/stmedgaz.mdl", true); break; default: Sys_Error("ParseStream: bad type"); } if((stream = NewStream(ent, tag, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } stream->type = type; stream->tag = tag; stream->flags = flags; stream->entity = ent; stream->skin = skin; stream->models[0] = models[0]; stream->models[1] = models[1]; stream->models[2] = models[2]; stream->models[3] = models[3]; stream->endTime = cl.time+duration; stream->lastTrailTime = 0; VectorCopy(source, stream->source); VectorCopy(dest, stream->dest); if(flags&STREAM_ATTACHED) { VectorCopy(vec3_origin, stream->offset); state = FindState(ent); if (state) { // rjr - potential problem if this doesn't ever get set - origin might have to be set properly in script code? VectorSubtract(source, state->origin, stream->offset); } } } //========================================================================== // // NewStream // //========================================================================== static stream_t *NewStream(int ent, int tag, int *isNew) { int i; stream_t *stream; // Search for a stream with matching entity and tag for(i = 0, stream = cl_Streams; i < MAX_STREAMS; i++, stream++) { if(stream->entity == ent && stream->tag == tag) { if(isNew) { if(stream->endTime > cl.time) { *isNew = 0; } else { // this stream was already used up *isNew = 1; } } return stream; } } // Search for a free stream for(i = 0, stream = cl_Streams; i < MAX_STREAMS; i++, stream++) { if(!stream->models[0] || stream->endTime < cl.time) { if(isNew)*isNew = 1; return stream; } } return NULL; } /* ================= CL_ParseTEnt ================= */ void CL_ParseTEnt (void) { int type; vec3_t pos, vel, movedir, offset; dlight_t *dl; int rnd; explosion_t *ex; int cnt, cnt2, i, chType; int colorStart, colorLength; int damage; float volume, scale; float dir, cosval, sinval; type = MSG_ReadByte (); switch (type) { case TE_WIZSPIKE: // spike hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 20, 30); // S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1); break; case TE_KNIGHTSPIKE: // spike hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 226, 20); // S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1); break; case TE_SPIKE: // spike hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 0, 10); if ( rand() % 5 ) S_StartSound (TempSoundChannel(), 0, cl_sfx_tink1, pos, 1, 1); else { rnd = rand() & 3; if (rnd == 1) S_StartSound (TempSoundChannel(), 0, cl_sfx_ric1, pos, 1, 1); else if (rnd == 2) S_StartSound (TempSoundChannel(), 0, cl_sfx_ric2, pos, 1, 1); else S_StartSound (TempSoundChannel(), 0, cl_sfx_ric3, pos, 1, 1); } break; case TE_SUPERSPIKE: // super spike hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 0, 20); if ( rand() % 5 ) S_StartSound (TempSoundChannel(), 0, cl_sfx_tink1, pos, 1, 1); else { rnd = rand() & 3; if (rnd == 1) S_StartSound (TempSoundChannel(), 0, cl_sfx_ric1, pos, 1, 1); else if (rnd == 2) S_StartSound (TempSoundChannel(), 0, cl_sfx_ric2, pos, 1, 1); else S_StartSound (TempSoundChannel(), 0, cl_sfx_ric3, pos, 1, 1); } break; case TE_DRILLA_EXPLODE: // particles pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); ex = CL_AllocExplosion(); VectorCopy(pos,ex->origin); ex->model = Mod_ForName("models/gen_expl.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + ex->model->numframes * 0.1; // sound S_StartSound (TempSoundChannel(), 0, cl_sfx_explode, pos, 1, 1); break; case TE_EXPLOSION: // rocket explosion // particles pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_ParticleExplosion (pos); // light dl = CL_AllocDlight (0); VectorCopy (pos, dl->origin); dl->radius = 350; dl->die = cl.time + 0.5; dl->decay = 300; dl->color[0] = 0.2; dl->color[1] = 0.1; dl->color[2] = 0.05; dl->color[3] = 0.7; // sound S_StartSound (TempSoundChannel(), 0, cl_sfx_r_exp3, pos, 1, 1); break; case TE_TAREXPLOSION: // tarbaby explosion pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_BlobExplosion (pos); S_StartSound (TempSoundChannel(), 0, cl_sfx_r_exp3, pos, 1, 1); break; case TE_LIGHTNING1: // lightning bolts CL_ParseBeam (NULL); break; case TE_LIGHTNING2: // lightning bolts CL_ParseBeam (NULL); break; case TE_LIGHTNING3: // lightning bolts CL_ParseBeam (NULL); break; case TE_STREAM_CHAIN: case TE_STREAM_SUNSTAFF1: case TE_STREAM_SUNSTAFF2: case TE_STREAM_LIGHTNING: case TE_STREAM_LIGHTNING_SMALL: case TE_STREAM_COLORBEAM: case TE_STREAM_ICECHUNKS: case TE_STREAM_GAZE: case TE_STREAM_FAMINE: ParseStream(type); break; case TE_LAVASPLASH: pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_LavaSplash (pos); break; case TE_TELEPORT: pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_TeleportSplash (pos); break; case TE_GUNSHOT: // bullet hitting wall cnt = MSG_ReadByte (); pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 0, 20*cnt); break; case TE_BLOOD: // bullets hitting body cnt = MSG_ReadByte (); pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 73, 20*cnt); break; case TE_LIGHTNINGBLOOD: // lightning hitting body pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 225, 50); break; case TE_BIGGRENADE: // effect for big grenade pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos,pos,225,1024); ex = CL_AllocExplosion(); VectorCopy(pos,ex->origin); ex->frameFunc = MultiGrenadeThink; ex->data=250; ex->model = Mod_ForName("models/sm_expld.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + ex->model->numframes * 0.1; break; case TE_CHUNK: //directed chunks case TE_CHUNK2: //volume based chunks pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); vel[0] = MSG_ReadCoord(); //vel for CHUNK, volume for CHUNK2 vel[1] = MSG_ReadCoord(); vel[2] = MSG_ReadCoord(); chType = MSG_ReadByte(); if(type == TE_CHUNK) { cnt = MSG_ReadByte(); } else { volume = vel[0] * vel[1] * vel[2]; cnt = volume / 8192; if (volume < 5000) { scale = .20; cnt *= 3; // Because so few pieces come out of a small object } else if (volume < 50000) { scale = .45; cnt *= 3; // Because so few pieces come out of a small object } else if (volume < 500000) { scale = .50; } else if (volume < 1000000) { scale = .75; } else { scale = 1; } if(cnt > 30) { cnt = 30; } } for(i = 0; i < cnt; i++) { float final; ex = CL_AllocExplosion(); ex->frameFunc = ChunkThink; if(type == TE_CHUNK) { VectorCopy(pos,ex->origin); VectorCopy(vel, ex->velocity); VectorScale(ex->velocity, .80 + ((rand()%4)/10.0), ex->velocity); // temp modify them... ex->velocity[0] += (rand()%140)-70; ex->velocity[1] += (rand()%140)-70; ex->velocity[2] += (rand()%140)-70; // are these in degrees or radians? ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = rand()%850 - 425; ex->avel[1] = rand()%850 - 425; ex->avel[2] = rand()%850 - 425; ex->scale = 30 + 100 * (cnt / 40.0) + rand()%40; } else { // set origin (origin is really absmin here) VectorCopy(pos, ex->origin); ex->origin[0] += FRANDOM() * vel[0]; ex->origin[1] += FRANDOM() * vel[1]; ex->origin[2] += FRANDOM() * vel[2]; // set velocity ex->velocity[0] = -210 + FRANDOM() * 420; ex->velocity[1] = -210 + FRANDOM() * 420; ex->velocity[2] = -210 + FRANDOM() * 490; // set scale ex->scale = scale*100; // set angles, avel ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->avel[0] = rand()%1200; ex->avel[1] = rand()%1200; ex->avel[2] = rand()%1200; } ex->data = chType; final = (rand()%100)*.01; if ((chType==THINGTYPE_GLASS) || (chType==THINGTYPE_REDGLASS) || (chType==THINGTYPE_CLEARGLASS) || (chType==THINGTYPE_WEBS)) { if (final<0.20) ex->model = Mod_ForName ("models/shard1.mdl", true); else if (final<0.40) ex->model = Mod_ForName ("models/shard2.mdl", true); else if (final<0.60) ex->model = Mod_ForName ("models/shard3.mdl", true); else if (final<0.80) ex->model = Mod_ForName ("models/shard4.mdl", true); else ex->model = Mod_ForName ("models/shard5.mdl", true); if (chType==THINGTYPE_CLEARGLASS) { ex->skin = 1; ex->flags |= DRF_TRANSLUCENT; } else if (chType==THINGTYPE_REDGLASS) { ex->skin = 2; } else if (chType==THINGTYPE_WEBS) { ex->skin = 3; ex->flags |= DRF_TRANSLUCENT; } } else if (chType==THINGTYPE_WOOD) { if (final < 0.25) ex->model = Mod_ForName ("models/splnter1.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/splnter2.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/splnter3.mdl", true); else ex->model = Mod_ForName ("models/splnter4.mdl", true); } else if (chType==THINGTYPE_METAL) { if (final < 0.25) ex->model = Mod_ForName ("models/metlchk1.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/metlchk2.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/metlchk3.mdl", true); else ex->model = Mod_ForName ("models/metlchk4.mdl", true); } else if (chType==THINGTYPE_FLESH) { if (final < 0.33) ex->model = Mod_ForName ("models/flesh1.mdl", true); else if (final < 0.66) ex->model = Mod_ForName ("models/flesh2.mdl", true); else ex->model = Mod_ForName ("models/flesh3.mdl", true); } else if (chType==THINGTYPE_BROWNSTONE||chType==THINGTYPE_DIRT) { if (final < 0.25) ex->model = Mod_ForName ("models/schunk1.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/schunk2.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/schunk3.mdl", true); else ex->model = Mod_ForName ("models/schunk4.mdl", true); ex->skin = 1; } else if (chType==THINGTYPE_CLAY) { if (final < 0.25) ex->model = Mod_ForName ("models/clshard1.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/clshard2.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/clshard3.mdl", true); else ex->model = Mod_ForName ("models/clshard4.mdl", true); } else if (chType==THINGTYPE_LEAVES) { if (final < 0.33) ex->model = Mod_ForName ("models/leafchk1.mdl", true); else if (final < 0.66) ex->model = Mod_ForName ("models/leafchk2.mdl", true); else ex->model = Mod_ForName ("models/leafchk3.mdl", true); } else if (chType==THINGTYPE_HAY) { if (final < 0.33) ex->model = Mod_ForName ("models/hay1.mdl", true); else if (final < 0.66) ex->model = Mod_ForName ("models/hay2.mdl", true); else ex->model = Mod_ForName ("models/hay3.mdl", true); } else if (chType==THINGTYPE_CLOTH) { if (final < 0.33) ex->model = Mod_ForName ("models/clthchk1.mdl", true); else if (final < 0.66) ex->model = Mod_ForName ("models/clthchk2.mdl", true); else ex->model = Mod_ForName ("models/clthchk3.mdl", true); } else if (chType==THINGTYPE_WOOD_LEAF) { if (final < 0.14) ex->model = Mod_ForName ("models/splnter1.mdl", true); else if (final < 0.28) ex->model = Mod_ForName ("models/leafchk1.mdl", true); else if (final < 0.42) ex->model = Mod_ForName ("models/splnter2.mdl", true); else if (final < 0.56) ex->model = Mod_ForName ("models/leafchk2.mdl", true); else if (final < 0.70) ex->model = Mod_ForName ("models/splnter3.mdl", true); else if (final < 0.84) ex->model = Mod_ForName ("models/leafchk3.mdl", true); else ex->model = Mod_ForName ("models/splnter4.mdl", true); } else if (chType==THINGTYPE_WOOD_METAL) { if (final < 0.125) ex->model = Mod_ForName ("models/splnter1.mdl", true); else if (final < 0.25) ex->model = Mod_ForName ("models/metlchk1.mdl", true); else if (final < 0.375) ex->model = Mod_ForName ("models/splnter2.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/metlchk2.mdl", true); else if (final < 0.625) ex->model = Mod_ForName ("models/splnter3.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/metlchk3.mdl", true); else if (final < 0.875) ex->model = Mod_ForName ("models/splnter4.mdl", true); else ex->model = Mod_ForName ("models/metlchk4.mdl", true); } else if (chType==THINGTYPE_WOOD_STONE) { if (final < 0.125) ex->model = Mod_ForName ("models/splnter1.mdl", true); else if (final < 0.25) ex->model = Mod_ForName ("models/schunk1.mdl", true); else if (final < 0.375) ex->model = Mod_ForName ("models/splnter2.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/schunk2.mdl", true); else if (final < 0.625) ex->model = Mod_ForName ("models/splnter3.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/schunk3.mdl", true); else if (final < 0.875) ex->model = Mod_ForName ("models/splnter4.mdl", true); else ex->model = Mod_ForName ("models/schunk4.mdl", true); } else if (chType==THINGTYPE_METAL_STONE) { if (final < 0.125) ex->model = Mod_ForName ("models/metlchk1.mdl", true); else if (final < 0.25) ex->model = Mod_ForName ("models/schunk1.mdl", true); else if (final < 0.375) ex->model = Mod_ForName ("models/metlchk2.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/schunk2.mdl", true); else if (final < 0.625) ex->model = Mod_ForName ("models/metlchk3.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/schunk3.mdl", true); else if (final < 0.875) ex->model = Mod_ForName ("models/metlchk4.mdl", true); else ex->model = Mod_ForName ("models/schunk4.mdl", true); } else if (chType==THINGTYPE_METAL_CLOTH) { if (final < 0.14) ex->model = Mod_ForName ("models/metlchk1.mdl", true); else if (final < 0.28) ex->model = Mod_ForName ("models/clthchk1.mdl", true); else if (final < 0.42) ex->model = Mod_ForName ("models/metlchk2.mdl", true); else if (final < 0.56) ex->model = Mod_ForName ("models/clthchk2.mdl", true); else if (final < 0.70) ex->model = Mod_ForName ("models/metlchk3.mdl", true); else if (final < 0.84) ex->model = Mod_ForName ("models/clthchk3.mdl", true); else ex->model = Mod_ForName ("models/metlchk4.mdl", true); } else if (chType==THINGTYPE_ICE) { ex->model = Mod_ForName("models/shard.mdl", true); ex->skin = 0; //ent->frame = rand()%2; ex->flags |= DRF_TRANSLUCENT|MLS_ABSLIGHT; //ent->abslight = 0.5; } else if (chType==THINGTYPE_METEOR) { ex->model = Mod_ForName("models/tempmetr.mdl", true); ex->skin = 0; //ex->scale *= .6; VectorScale(ex->avel, 4.0, ex->avel); } else if (chType==THINGTYPE_ACID) { // no spinning if possible... ex->model = Mod_ForName("models/sucwp2p.mdl", true); ex->skin = 0; } else if (chType==THINGTYPE_GREENFLESH) { // spider guts if (final < 0.33) ex->model = Mod_ForName ("models/sflesh1.mdl", true); else if (final < 0.66) ex->model = Mod_ForName ("models/sflesh2.mdl", true); else ex->model = Mod_ForName ("models/sflesh3.mdl", true); ex->skin = 0; } else// if (chType==THINGTYPE_GREYSTONE) { if (final < 0.25) ex->model = Mod_ForName ("models/schunk1.mdl", true); else if (final < 0.50) ex->model = Mod_ForName ("models/schunk2.mdl", true); else if (final < 0.75) ex->model = Mod_ForName ("models/schunk3.mdl", true); else ex->model = Mod_ForName ("models/schunk4.mdl", true); ex->skin = 0; } ex->startTime = cl.time; ex->endTime = ex->startTime + 4.0; } break; case TE_XBOWHIT: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); vel[0] = MSG_ReadCoord(); vel[1] = MSG_ReadCoord(); vel[2] = MSG_ReadCoord(); chType = MSG_ReadByte(); damage = MSG_ReadByte(); // do a particle effect here, with the color depending on chType // impact sound: switch (chType) { case THINGTYPE_FLESH: // S_StartSound (TempSoundChannel(), 0, cl_sfx_arr2flsh, pos, 1, 1); break; case THINGTYPE_WOOD: // S_StartSound (TempSoundChannel(), 0, cl_sfx_arr2wood, pos, 1, 1); break; default: // S_StartSound (TempSoundChannel(), 0, cl_sfx_met2stn, pos, 1, 1); break; } //generic spinny impact image ex=CL_AllocExplosion(); ex->origin[0]=pos[0]-vel[0]; ex->origin[1]=pos[1]-vel[1]; ex->origin[2]=pos[2]-vel[2]; vectoangles(vel,ex->angles); ex->avel[2]=(rand()%500)+200; ex->scale=10; ex->startTime=cl.time; ex->endTime=cl.time+0.3; ex->model=Mod_ForName ("models/arrowhit.mdl", true); ex->exflags = EXFLAG_ROTATE; ex->flags = DRF_TRANSLUCENT | MLS_ABSLIGHT; ex->abslight=128; //white smoke if invulnerable impact if (!damage) { ex=CL_AllocExplosion(); ex->origin[0]=pos[0]-vel[0]*2; ex->origin[1]=pos[1]-vel[1]*2; ex->origin[2]=pos[2]-vel[2]*2; ex->velocity[0] = 0.0; ex->velocity[1] = 0.0; ex->velocity[2] = 80.0; vectoangles(vel,ex->angles); ex->startTime=cl.time; ex->endTime=cl.time+0.35; ex->model=Mod_ForName ("models/whtsmk1.spr", true); ex->flags = DRF_TRANSLUCENT; } break; case TE_METEORHIT: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); // always make 8 meteors i = (host_frametime < .07) ? 0 : 4; // based on framerate for( ; i < 8; i++) { float final; ex = CL_AllocExplosion(); VectorCopy(pos,ex->origin); ex->frameFunc = ChunkThink; // temp modify them... ex->velocity[0] += (rand()%400)-200; ex->velocity[1] += (rand()%400)-200; ex->velocity[2] += (rand()%200)+150; // are these in degrees or radians? ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = rand()%850 - 425; ex->avel[1] = rand()%850 - 425; ex->avel[2] = rand()%850 - 425; ex->scale = 45 + rand()%10; ex->data = THINGTYPE_METEOR; final = (rand()%100)*.01; ex->model = Mod_ForName("models/tempmetr.mdl", true); ex->skin = 0; VectorScale(ex->avel, 4.0, ex->avel); ex->startTime = cl.time; ex->endTime = ex->startTime + 4.0; } // make the actual explosion //for(i = 0; i < 7; i++) i = (host_frametime < .07) ? 0 : 8; // based on framerate for( ; i < 11; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->origin[0] += (rand()%10) - 5; ex->origin[1] += (rand()%10) - 5; ex->origin[2] += (rand()%10) - 5; ex->velocity[0] = (ex->origin[0] - pos[0])*12; ex->velocity[1] = (ex->origin[1] - pos[1])*12; ex->velocity[2] = (ex->origin[2] - pos[2])*12; /* ex->origin[0] += rand()%10 - 5; ex->origin[1] += rand()%10 - 5; ex->origin[2] += rand()%10 - 5; ex->velocity[0] = (ex->origin[0] - pos[0])*10; ex->velocity[1] = (ex->origin[1] - pos[1])*10; ex->velocity[2] = (ex->origin[2] - pos[2])*10 + 200;*/ switch(rand()%4) { case 0: case 1: ex->model = Mod_ForName("models/sm_expld.spr", true); break; case 2: ex->model = Mod_ForName("models/bg_expld.spr", true); break; case 3: ex->model = Mod_ForName("models/gen_expl.spr", true); break; } if(host_frametime < .07) { ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; } ex->abslight = 160 + rand()%64; ex->skin = 0; ex->scale = 80 + rand()%40; ex->startTime = cl.time + (rand()%50 / 200.0); ex->endTime = ex->startTime + ex->model->numframes * 0.04; } S_StartSound (TempSoundChannel(), 0, cl_sfx_axeExplode, pos, 1, 1); break; case TE_HWBONEPOWER: cnt = MSG_ReadByte (); pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); movedir[0] = MSG_ReadCoord (); movedir[1] = MSG_ReadCoord (); movedir[2] = MSG_ReadCoord (); R_RunParticleEffect4 (pos, 50, 368 + rand() % 16, pt_grav, 10); // particle4 (50, rand(368-384), grav, 10); ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); VectorMA(ex->origin, -6, movedir, ex->origin); ex->data=250; ex->model = Mod_ForName("models/sm_expld.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + ex->model->numframes * 0.1; for(cnt2=0; cnt2origin); VectorMA(ex->origin, -8, movedir, ex->origin); VectorCopy(offset, ex->velocity); ex->velocity[2] += 30; ex->data=250; ex->model = Mod_ForName("models/ghost.spr", true); ex->abslight = 128; ex->flags = DRF_TRANSLUCENT | MLS_ABSLIGHT; ex->startTime = cl.time; ex->endTime = ex->startTime + ex->model->numframes * 0.1; } for(cnt2=0; cnt2<20; cnt2++) { // want faster velocity to hide the fact that these // aren't in the real location offset[0] = rand() % 400 + 300; if(rand() % 2) offset[0] = -offset[0]; offset[1] = rand() % 400 + 300; if(rand() % 2) offset[1] = -offset[1]; offset[2] = rand() % 400 + 300; if(rand() % 2) offset[2] = -offset[2]; ex = CL_AllocExplosion (); VectorMA(pos, 1/700, offset, ex->origin); VectorCopy(offset, ex->velocity); ex->data=250; ex->model = Mod_ForName("models/boneshrd.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + rand() * 50 / 100; ex->flags |= EXFLAG_ROTATE|EXFLAG_COLLIDE; ex->angles[0] = rand() % 700; ex->angles[1] = rand() % 700; ex->angles[2] = rand() % 700; ex->avel[0] = rand() % 700; ex->avel[1] = rand() % 700; ex->avel[2] = rand() % 700; ex->frameFunc = CheckSpaceThink; } S_StartSound(TempSoundChannel(), 1, cl_sfx_bonephit, pos, 1, 1); break; case TE_HWBONEPOWER2: cnt2 = MSG_ReadByte (); //did it hit? changes sound pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); // white smoke ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + ex->model->numframes * 0.1; //sound if(cnt2) { S_StartSound(TempSoundChannel(), 1, cl_sfx_bonehit, pos, 1, 1); } else { S_StartSound(TempSoundChannel(), 1, cl_sfx_bonewal, pos, 1, 1); } R_RunParticleEffect4 (pos, 3, 368 + rand() % 16, pt_grav, 7); // particle4(self.origin,3,random(368,384),PARTICLETYPE_GRAV,self.dmg/2); break; case TE_HWRAVENDIE: pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->velocity[1] = 8; ex->velocity[2] = -10; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->velocity[2] = -10; ex->model = Mod_ForName("models/redsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->velocity[1] = -8; ex->velocity[2] = -10; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; S_StartSound(TempSoundChannel(), 1, cl_sfx_ravendie, pos, 1, 1); break; case TE_HWRAVENEXPLODE: pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->velocity[2] = 8; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->origin[2] -= 5; ex->velocity[2] = 8; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->origin[2] -= 10; ex->velocity[2] = 8; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; S_StartSound(TempSoundChannel(), 1, cl_sfx_ravengo, pos, 1, 1); break; case TE_ICEHIT: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); cnt2 = MSG_ReadByte(); // 0 for person, 1 for wall if(cnt2) { i = (host_frametime < .07) ? 0 : 5; // based on framerate for( ; i < 9; i++) { ex = CL_AllocExplosion(); VectorCopy(pos,ex->origin); ex->frameFunc = ChunkThink; ex->velocity[0] += (rand()%1000)-500; ex->velocity[1] += (rand()%1000)-500; ex->velocity[2] += (rand()%200)-50; // are these in degrees or radians? ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = rand()%850 - 425; ex->avel[1] = rand()%850 - 425; ex->avel[2] = rand()%850 - 425; if(cnt2 == 2) { ex->scale = 65 + rand()%10; } else { ex->scale = 35 + rand()%10; } ex->data = THINGTYPE_ICE; ex->model = Mod_ForName("models/shard.mdl", true); ex->skin = 0; //ent->frame = rand()%2; ex->flags |= DRF_TRANSLUCENT|MLS_ABSLIGHT; ex->abslight = 128; ex->startTime = cl.time; ex->endTime = ex->startTime + 2.0; if(cnt2 == 2) { ex->endTime += 3.0; } } } else { vec3_t dmin = {-10, -10, -10}; vec3_t dmax = {10, 10, 10}; R_ColoredParticleExplosion(pos,14,10,10); R_RunParticleEffect2 (pos, dmin, dmax, 145, 5, 14); } // make the actual explosion ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/icehit.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + ex->model->numframes * 0.1; // Add in the sound if(cnt2 == 1) { // hit a wall S_StartSound (TempSoundChannel(), 0, cl_sfx_icewall, pos, 1, 1); } else if (cnt2 == 2) { S_StartSound (TempSoundChannel(), 0, cl_sfx_iceshatter, pos, 1, 1); } else { // hit a person S_StartSound (TempSoundChannel(), 0, cl_sfx_iceflesh, pos, 1, 1); } break; case TE_ICESTORM: { int ent; vec3_t center; stream_t *stream; float duration; model_t *models[2]; entity_state_t *state; static float playIceSound = .6; ent = MSG_ReadShort(); state = FindState(ent); if (state) { VectorCopy(state->origin, center); playIceSound+=host_frametime; if(playIceSound >= .6) { S_StartSound (TempSoundChannel(), 0, cl_sfx_icestorm, center, 1, 1); playIceSound -= .6; } for (i = 0; i < 5; i++) { // make some ice beams... models[0] = Mod_ForName("models/stice.mdl", true); if((stream = NewStream(ent, i, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } stream->type = TE_STREAM_ICECHUNKS; stream->tag = (i)&15;// FIXME stream->flags = (i+STREAM_ATTACHED); stream->entity = ent; stream->skin = 0; stream->models[0] = models[0]; stream->endTime = cl.time+0.3; stream->lastTrailTime = 0; VectorCopy(center, stream->source); stream->source[0] += rand()%100 - 50; stream->source[1] += rand()%100 - 50; VectorCopy(stream->source, stream->dest); stream->dest[2] += 128; VectorCopy(vec3_origin, stream->offset); VectorSubtract(stream->source, state->origin, stream->offset); } } } break; case TE_HWMISSILEFLASH: pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); vel[0] = MSG_ReadCoord (); //angles vel[1] = MSG_ReadCoord (); vel[2] = rand() % 360; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); VectorCopy(vel, ex->angles); ex->frameFunc = MissileFlashThink; ex->model = Mod_ForName("models/handfx.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + 2; ex->exflags = EXFLAG_ROTATE; ex->avel[2] = rand() * 360 + 360; ex->flags = MLS_ABSLIGHT|DRF_TRANSLUCENT; ex->abslight = 128; //ex->scale = .8 + (rand()%100) * 0.004; // .8 to 1.2 ex->scale = 80 + rand()%40; break; case TE_SUNSTAFF_CHEAP: { int ent; vec3_t points[4]; int reflect_count; short int tempVal; entity_state_t *state; int i, j; vec3_t center; stream_t *stream; float duration; model_t *models[4]; ent = MSG_ReadShort(); reflect_count = MSG_ReadByte(); state = FindState(ent); if (state) { // read in up to 4 points for up to 3 beams for(i = 0; i < 3; i++) { tempVal = MSG_ReadCoord(); points[0][i] = tempVal; } for(i = 1; i < 2 + reflect_count; i++) { for(j = 0; j < 3; j++) { tempVal = MSG_ReadCoord(); points[i][j] = tempVal; } } // actually create the sun model pieces for ( i = 0; i < reflect_count + 1; i++) { models[0] = Mod_ForName("models/stsunsf1.mdl", true); models[1] = Mod_ForName("models/stsunsf2.mdl", true); models[2] = Mod_ForName("models/stsunsf3.mdl", true); models[3] = Mod_ForName("models/stsunsf4.mdl", true); //if((stream = NewStream(ent, i, NULL)) == NULL) if((stream = NewStream(ent, i, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } stream->type = TE_STREAM_SUNSTAFF1; stream->tag = i; if(!i) { stream->flags = (i+STREAM_ATTACHED); } else { stream->flags = i; } stream->entity = ent; stream->skin = 0; stream->models[0] = models[0]; stream->models[1] = models[1]; stream->models[2] = models[2]; stream->models[3] = models[3]; stream->endTime = cl.time+0.5; // FIXME stream->lastTrailTime = 0; VectorCopy(points[i], stream->source); VectorCopy(points[i+1], stream->dest); if(!i) { VectorCopy(vec3_origin, stream->offset); VectorSubtract(stream->source, state->origin, stream->offset); } } } else { // read in everything to keep everything in sync for(i = 0; i < (2 + reflect_count)*3; i++) { tempVal = MSG_ReadShort(); } } } break; case TE_LIGHTNING_HAMMER: { int ent; stream_t *stream; float duration; model_t *models[2]; entity_state_t *state; ent = MSG_ReadShort(); state = FindState(ent); if (state) { if(rand()&1) { S_StartSound (TempSoundChannel(), 0, cl_sfx_lightning1, state->origin, 1, 1); } else { S_StartSound (TempSoundChannel(), 0, cl_sfx_lightning2, state->origin, 1, 1); } for (i = 0; i < 5; i++) { // make some lightning models[0] = Mod_ForName("models/stlghtng.mdl", true); if((stream = NewStream(ent, i, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } //stream->type = TE_STREAM_ICECHUNKS; stream->type = TE_STREAM_LIGHTNING; stream->tag = i; stream->flags = i; stream->entity = ent; stream->skin = 0; stream->models[0] = models[0]; stream->endTime = cl.time+0.5; stream->lastTrailTime = 0; VectorCopy(state->origin, stream->source); stream->source[0] += rand()%30 - 15; stream->source[1] += rand()%30 - 15; VectorCopy(stream->source, stream->dest); stream->dest[0] += rand()%80 - 40; stream->dest[1] += rand()%80 - 40; stream->dest[2] += 64 + (rand()%48); } } } break; case TE_HWTELEPORT: pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); cnt = MSG_ReadShort(); //skin# S_StartSound (TempSoundChannel(), 0, cl_sfx_teleport[rand() % 5], pos, 1, 1); ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->frameFunc = TeleportFlashThink; ex->model = Mod_ForName("models/teleport.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + 2; ex->avel[2] = rand() * 360 + 360; ex->flags = SCALE_TYPE_XYONLY | DRF_TRANSLUCENT; ex->skin = cnt; ex->scale = 100; for(dir=0; dir<360; dir+=45) { cosval = 10 * cos(dir *M_PI*2 / 360); sinval = 10 * sin(dir *M_PI*2 / 360); ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/telesmk2.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + .5; ex->velocity[0] = cosval; ex->velocity[1] = sinval; ex->flags = DRF_TRANSLUCENT; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->origin[2] += 64; ex->model = Mod_ForName("models/telesmk2.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + .5; ex->velocity[0] = cosval; ex->velocity[1] = sinval; ex->flags = DRF_TRANSLUCENT; } break; case TE_SWORD_EXPLOSION: { vec3_t pos; int ent; stream_t *stream; float duration; model_t *models[2]; entity_state_t *state; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); ent = MSG_ReadShort(); state = FindState(ent); if (state) { if(rand()&1) { S_StartSound (TempSoundChannel(), 0, cl_sfx_lightning1, pos, 1, 1); } else { S_StartSound (TempSoundChannel(), 0, cl_sfx_lightning2, pos, 1, 1); } for (i = 0; i < 5; i++) { // make some lightning models[0] = Mod_ForName("models/stlghtng.mdl", true); if((stream = NewStream(ent, i, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } //stream->type = TE_STREAM_ICECHUNKS; stream->type = TE_STREAM_LIGHTNING; stream->tag = i; stream->flags = i; stream->entity = ent; stream->skin = 0; stream->models[0] = models[0]; stream->endTime = cl.time+0.5; stream->lastTrailTime = 0; VectorCopy(pos, stream->source); stream->source[0] += rand()%30 - 15; stream->source[1] += rand()%30 - 15; VectorCopy(stream->source, stream->dest); stream->dest[0] += rand()%80 - 40; stream->dest[1] += rand()%80 - 40; stream->dest[2] += 64 + (rand()%48); } } ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/vorpshok.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + 1.0; ex->flags |= MLS_ABSLIGHT; ex->abslight = 128; ex->skin = 0; ex->scale = 100; ex->frameFunc = SwordFrameFunc; S_StartSound (TempSoundChannel(), 0, cl_sfx_swordExplode, pos, 1, 1); } break; case TE_AXE_BOUNCE: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/spark.spr", true); ex->startTime = cl.time; ex->flags |= MLS_ABSLIGHT; ex->abslight = 128; ex->skin = 0; ex->scale = 100; ex->endTime = ex->startTime + ex->model->numframes * 0.05; S_StartSound (TempSoundChannel(), 0, cl_sfx_axeBounce, pos, 1, 1); break; case TE_AXE_EXPLODE: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); i = (host_frametime < .07) ? 0 : 3; // based on framerate for( ; i < 5; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->origin[0] += rand()%6 - 3; ex->origin[1] += rand()%6 - 3; ex->origin[2] += rand()%6 - 3; ex->velocity[0] = (ex->origin[0] - pos[0])*15; ex->velocity[1] = (ex->origin[1] - pos[1])*15; ex->velocity[2] = (ex->origin[2] - pos[2])*15; switch(rand()%6) { case 0: case 1: ex->model = Mod_ForName("models/xpspblue.spr", true); break; case 2: case 3: ex->model = Mod_ForName("models/xpspblue.spr", true); ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; break; case 4: case 5: ex->model = Mod_ForName("models/spark0.spr", true); ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; break; } ex->flags |= MLS_ABSLIGHT;//|DRF_TRANSLUCENT; ex->abslight = 160+rand()%24; ex->skin = 0; ex->scale = 80 + rand()%40; ex->startTime = cl.time + (rand()%50 / 200.0); ex->endTime = ex->startTime + ex->model->numframes * 0.05; } S_StartSound (TempSoundChannel(), 0, cl_sfx_axeExplode, pos, 1, 1); break; case TE_TIME_BOMB: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); i = (host_frametime < .07) ? 0 : 14; // based on framerate for(; i < 20; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->origin[0] += rand()%6 - 3; ex->origin[1] += rand()%6 - 3; ex->origin[2] += rand()%6 - 3; ex->velocity[0] = (ex->origin[0] - pos[0])*40; ex->velocity[1] = (ex->origin[1] - pos[1])*40; ex->velocity[2] = (ex->origin[2] - pos[2])*40; switch(rand()%4) { case 0: ex->model = Mod_ForName("models/sm_expld.spr", true); break; case 2: ex->model = Mod_ForName("models/bg_expld.spr", true); break; case 1: case 3: ex->model = Mod_ForName("models/gen_expl.spr", true); break; } ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; ex->abslight = 160+rand()%24; ex->skin = 0; ex->scale = 80 + rand()%40; ex->startTime = cl.time + (rand()%50 / 200.0); ex->endTime = ex->startTime + ex->model->numframes * 0.05; } S_StartSound (TempSoundChannel(), 0, cl_sfx_axeExplode, pos, 1, 1); break; case TE_FIREBALL: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/blast.mdl", true); ex->flags |= MLS_ABSLIGHT|SCALE_TYPE_UNIFORM|SCALE_ORIGIN_CENTER; ex->abslight = 128; ex->skin = 0; ex->scale = 1; ex->startTime = cl.time; ex->endTime = ex->startTime + 1.0; ex->frameFunc = fireBallUpdate; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = 50; ex->avel[1] = 50; ex->avel[2] = 50; S_StartSound (TempSoundChannel(), 0, cl_sfx_fireBall, pos, 1, 1); break; case TE_SUNSTAFF_POWER: { int ent; stream_t *stream; float duration; model_t *models[4]; entity_state_t *state; ent = MSG_ReadShort(); vel[0] = MSG_ReadCoord(); vel[1] = MSG_ReadCoord(); vel[2] = MSG_ReadCoord(); pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); for(i = 0; i < 2; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); if(i) { ex->model = Mod_ForName("models/stsunsf3.mdl", true); ex->scale = 200; ex->frameFunc = sunPowerUpdate; } else { ex->model = Mod_ForName("models/blast.mdl", true); ex->flags |= DRF_TRANSLUCENT; ex->frameFunc = sunBallUpdate; ex->scale = 120; } ex->flags |= MLS_ABSLIGHT|SCALE_TYPE_UNIFORM|SCALE_ORIGIN_CENTER; ex->abslight = 128; ex->skin = 0; ex->scale = 200; ex->startTime = cl.time; ex->endTime = ex->startTime + .8; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = 50; ex->avel[1] = 50; ex->avel[2] = 50; } S_StartSound (TempSoundChannel(), 0, cl_sfx_fireBall, pos, 1, 1); state = FindState(ent); if (state) { S_StartSound (TempSoundChannel(), 0, cl_sfx_sunstaff, state->origin, 1, 1); models[0] = Mod_ForName("models/stsunsf2.mdl", true); models[1] = Mod_ForName("models/stsunsf1.mdl", true); models[2] = Mod_ForName("models/stsunsf3.mdl", true); models[3] = Mod_ForName("models/stsunsf4.mdl", true); if((stream = NewStream(ent, 0, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } stream->type = TE_STREAM_SUNSTAFF2; stream->tag = 0; //stream->flags = STREAM_ATTACHED; stream->flags = 0; stream->entity = ent; stream->skin = 0; stream->models[0] = models[0]; stream->models[1] = models[1]; stream->models[2] = models[2]; stream->models[3] = models[3]; stream->endTime = cl.time+0.8; stream->lastTrailTime = 0; VectorCopy(vel, stream->source); VectorCopy(pos, stream->dest); //VectorCopy(vec3_origin, stream->offset); //VectorSubtract(stream->source, vel, stream->offset); // make some spiffy particles to glue it all together } } break; case TE_PURIFY2_EXPLODE: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/xplod29.spr", true); ex->startTime = cl.time; ex->flags |= MLS_ABSLIGHT; ex->abslight = 128; ex->skin = 0; ex->scale = 100; ex->endTime = ex->startTime + ex->model->numframes * 0.05; i = (host_frametime < .07) ? 0 : 8; // based on framerate for(i = 0; i < 12; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->origin[0] += (rand()%20) - 10; ex->origin[1] += (rand()%20) - 10; ex->origin[2] += (rand()%20) - 10; ex->velocity[0] = (ex->origin[0] - pos[0])*12; ex->velocity[1] = (ex->origin[1] - pos[1])*12; ex->velocity[2] = (ex->origin[2] - pos[2])*12; switch(rand()%4) { case 0: case 1: ex->model = Mod_ForName("models/sm_expld.spr", true); break; case 2: ex->model = Mod_ForName("models/bg_expld.spr", true); break; case 3: ex->model = Mod_ForName("models/gen_expl.spr", true); break; } if(host_frametime < 0.07) { ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; } ex->abslight = 160 + rand()%64; ex->skin = 0; ex->scale = 80 + rand()%40; ex->startTime = cl.time + (rand()%50 / 200.0); ex->endTime = ex->startTime + ex->model->numframes * 0.04; } S_StartSound (TempSoundChannel(), 0, cl_sfx_purify2, pos, 1, 1); break; case TE_PLAYER_DEATH: { int angle; // from 0 to 256 int pitch; // from 0 to 256 int force; int style; float throwPower, curAng, curPitch; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); angle = MSG_ReadByte(); pitch = MSG_ReadByte(); force = MSG_ReadByte(); style = MSG_ReadByte(); i = (host_frametime < 0.07) ? 0 : 8; for( ; i < 12; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->origin[0] += (rand()%40)-20; ex->origin[1] += (rand()%40)-20; ex->origin[2] += rand()%40; ex->frameFunc = ChunkThink; throwPower = 3.5 + ((rand()%100)/100.0); curAng = angle*6.28/256.0 + ((rand()%100)/50.0) - 1.0; curPitch = pitch*6.28/256.0 + ((rand()%100)/100.0) - .5; ex->velocity[0] = force*throwPower * cos(curAng) * cos(curPitch); ex->velocity[1] = force*throwPower * sin(curAng) * cos(curPitch); ex->velocity[2] = force*throwPower * sin(curPitch); // are these in degrees or radians? ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = rand()%850 - 425; ex->avel[1] = rand()%850 - 425; ex->avel[2] = rand()%850 - 425; ex->scale = 80 + rand()%40; ex->data = THINGTYPE_FLESH; switch(rand()%3) { case 0: ex->model = Mod_ForName("models/flesh1.mdl", true); break; case 1: ex->model = Mod_ForName("models/flesh2.mdl", true); break; case 2: ex->model = Mod_ForName("models/flesh3.mdl", true); break; } ex->skin = 0; ex->startTime = cl.time; ex->endTime = ex->startTime + 4.0; } switch(style) { case 0: S_StartSound (TempSoundChannel(), 0, cl_sfx_big_gib, pos, 1, 1); break; case 1: if(rand()%2) { S_StartSound (TempSoundChannel(), 0, cl_sfx_gib1, pos, 1, 1); } else { S_StartSound (TempSoundChannel(), 0, cl_sfx_gib2, pos, 1, 1); } break; case 2: S_StartSound (TempSoundChannel(), 0, cl_sfx_telefrag, pos, 1, 1); break; } } break; case TE_PURIFY1_EFFECT: { float angle; float pitch; float dist; vec3_t endPos; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); angle = MSG_ReadByte()*6.28/256.0; pitch = MSG_ReadByte()*6.28/256.0; dist = MSG_ReadShort(); endPos[0] = pos[0] + dist * cos(angle) * cos(pitch); endPos[1] = pos[1] + dist * sin(angle) * cos(pitch); endPos[2] = pos[2] + dist * sin(pitch); //R_RocketTrail (pos, endPos, rt_purify); R_RocketTrail (pos, endPos, rt_purify); S_StartSound (TempSoundChannel(), 0, cl_sfx_purify1_fire, pos, 1, 1); S_StartSound (TempSoundChannel(), 0, cl_sfx_purify1_hit, endPos, 1, 1); ex = CL_AllocExplosion(); VectorCopy(endPos, ex->origin); ex->model = Mod_ForName("models/fcircle.spr", true); ex->startTime = cl.time; ex->flags |= MLS_ABSLIGHT; ex->abslight = 128; ex->skin = 0; ex->scale = 100; ex->endTime = ex->startTime + ex->model->numframes * 0.05; } break; case TE_TELEPORT_LINGER: { float duration; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); duration = MSG_ReadCoord(); ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/bspark.spr", true); ex->startTime = cl.time; ex->flags |= MLS_ABSLIGHT; ex->abslight = 128; ex->frameFunc = telEffectUpdate; ex->skin = 0; ex->scale = 0; ex->endTime = ex->startTime + duration; } break; case TE_LINE_EXPLOSION: { int distance; vec3_t endPos,midPos,curPos,distVec; float ratio; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); endPos[0] = MSG_ReadCoord(); endPos[1] = MSG_ReadCoord(); endPos[2] = MSG_ReadCoord(); VectorAdd(pos,endPos,midPos); VectorScale(midPos,0.5,midPos); VectorSubtract(midPos,pos,distVec); distance = (int)(VectorNormalize(distVec)*0.025); if (distance > 0) { VectorScale(distVec,40,distVec); VectorCopy(midPos,curPos); for (i=0;iorigin); switch(rand()%3) { case 0: ex->model = Mod_ForName("models/gen_expl.spr", true); break; case 1: ex->model = Mod_ForName("models/bg_expld.spr", true); break; case 2: ex->model = Mod_ForName("models/sm_expld.spr", true); break; } ex->flags |= MLS_ABSLIGHT; ex->abslight = 128; ex->skin = 0; ratio = (float)i/(float)distance; ex->scale = 200-(int)(150.0*ratio); ex->startTime = cl.time+ratio*0.75; ex->endTime = ex->startTime + ex->model->numframes * (0.025+FRANDOM()*0.01); VectorAdd(curPos,distVec,curPos); } VectorScale(distVec,-1,distVec); VectorCopy(midPos,curPos); for (i=0;iorigin); switch(rand()%3) { case 0: ex->model = Mod_ForName("models/gen_expl.spr", true); break; case 1: ex->model = Mod_ForName("models/bg_expld.spr", true); break; case 2: ex->model = Mod_ForName("models/sm_expld.spr", true); break; } ex->flags |= MLS_ABSLIGHT; ex->abslight = 128; ex->skin = 0; ratio = (float)i/(float)distance; ex->scale = 200-(int)(150.0*ratio); ex->startTime = cl.time+ratio*0.75; ex->endTime = ex->startTime + ex->model->numframes * (0.025+FRANDOM()*0.01); VectorAdd(curPos,distVec,curPos); } } } break; case TE_METEOR_CRUSH: { float maxDist; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); maxDist = MSG_ReadLong(); ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/null.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + 0.4; ex->frameFunc = MeteorCrushSpawnThink; ex->data = maxDist; S_StartSound (TempSoundChannel(), 0, cl_sfx_axeExplode, pos, 1, 1); } break; case TE_ACIDBALL: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); i = (host_frametime < 0.07) ? 0 : 2; for( ; i < 5; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->origin[0] += rand()%6 - 3; ex->origin[1] += rand()%6 - 3; ex->origin[2] += rand()%6 - 3; ex->velocity[0] = (ex->origin[0] - pos[0])*6; ex->velocity[1] = (ex->origin[1] - pos[1])*6; ex->velocity[2] = (ex->origin[2] - pos[2])*6; ex->model = Mod_ForName("models/axplsn_2.spr", true); if(host_frametime < 0.07) { ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; } ex->abslight = 160+rand()%24; ex->skin = 0; ex->scale = 80 + rand()%40; ex->startTime = cl.time + (rand()%50 / 200.0); ex->endTime = ex->startTime + ex->model->numframes * 0.05; } S_StartSound (TempSoundChannel(), 0, cl_sfx_acidhit, pos, 1, 1); break; case TE_ACIDBLOB: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); i = (host_frametime < 0.07) ? 0 : 7; for( ; i < 12; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->origin[0] += rand()%6 - 3; ex->origin[1] += rand()%6 - 3; ex->origin[2] += rand()%6 - 3; ex->velocity[0] = (ex->origin[0] - pos[0])*25; ex->velocity[1] = (ex->origin[1] - pos[1])*25; ex->velocity[2] = (ex->origin[2] - pos[2])*25; switch(rand()%4) { case 0: ex->model = Mod_ForName("models/axplsn_2.spr", true); break; case 1: ex->model = Mod_ForName("models/axplsn_1.spr", true); break; case 2: case 3: ex->model = Mod_ForName("models/axplsn_5.spr", true); break; } if(host_frametime < 0.07) { ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; } ex->abslight = 1; ex->skin = 0; ex->scale = 80 + rand()%40; ex->startTime = cl.time + (rand()%50 / 200.0); ex->endTime = ex->startTime + ex->model->numframes * 0.05; } // always make 8 meteors i = (host_frametime < 0.07) ? 0 : 4; for( ; i < 8; i++) { ex = CL_AllocExplosion(); VectorCopy(pos,ex->origin); ex->frameFunc = ChunkThink; // temp modify them... ex->velocity[0] = (rand()%500)-250; ex->velocity[1] = (rand()%500)-250; ex->velocity[2] = (rand()%200)+200; // are these in degrees or radians? ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = rand()%850 - 425; ex->avel[1] = rand()%850 - 425; ex->avel[2] = rand()%850 - 425; ex->scale = 45 + rand()%10; ex->data = THINGTYPE_ACID; ex->model = Mod_ForName("models/sucwp2p.mdl", true); ex->skin = 0; VectorScale(ex->avel, 4.0, ex->avel); ex->startTime = cl.time; ex->endTime = ex->startTime + 4.0; } S_StartSound (TempSoundChannel(), 0, cl_sfx_acidhit, pos, 1, 1); break; case TE_FIREWALL: { float travelAng, travelPitch; float fireCounts; dlight_t *dlx; vec3_t endPos, curPos, posAdd; mleaf_t *l; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; fireCounts = MSG_ReadByte(); dlx = CL_AllocDlight (0); VectorCopy (pos, dlx->origin); dlx->radius = 200 + (rand()&31); dlx->die = cl.time + 0.001; VectorCopy(pos, endPos); endPos[0] += cos(travelAng) * cos(travelPitch) * 450; endPos[1] += sin(travelAng) * cos(travelPitch) * 450; endPos[2] += sin(travelPitch) * 450; VectorCopy(pos, curPos); VectorSubtract(endPos, pos, posAdd); VectorScale(posAdd, .125, posAdd); for(i = 0; i < fireCounts; i++) { ex = CL_AllocExplosion(); VectorCopy(curPos, ex->origin); switch(rand()%3) { case 0: ex->model = Mod_ForName("models/firewal1.spr", true); break; case 1: ex->model = Mod_ForName("models/firewal5.spr", true); break; case 2: ex->model = Mod_ForName("models/firewal4.spr", true); break; } ex->startTime = cl.time + .3/8.0 * i; ex->endTime = ex->startTime + ex->model->numframes * 0.05; do { // I dunno how expensive this is, but it kind of sucks anyway around it... l = Mod_PointInLeaf (ex->origin, cl.worldmodel); if(l->contents == CONTENTS_EMPTY) { ex->origin[2] -= 16; } else { ex->origin[2] += 16; } }while(l->contents == CONTENTS_EMPTY); ex->origin[0] += (rand()%8)-4; ex->origin[1] += (rand()%8)-4; ex->origin[2] += (rand()%6)+21; ex = CL_AllocExplosion(); VectorCopy(curPos, ex->origin); ex->origin[0] += (rand()%8)-4; ex->origin[1] += (rand()%8)-4; ex->origin[2] += (rand()%6)-3; ex->model = Mod_ForName("models/flamestr.spr", true); ex->startTime = cl.time + .3/8.0 * i; ex->endTime = ex->startTime + ex->model->numframes * 0.05; ex->flags |= DRF_TRANSLUCENT; VectorAdd(curPos, posAdd, curPos); } } break; case TE_FIREWALL_IMPACT: // Add in the actual explosion pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); i = (host_frametime < 0.07) ? 0 : 8; for( ; i < 12; i++) { ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->origin[0] += (rand()%32)-16; ex->origin[1] += (rand()%32)-16; ex->origin[2] += (rand()%32)-16; ex->model = Mod_ForName("models/fboom.spr", true); ex->startTime = cl.time + ((rand()%150)/200); ex->endTime = ex->startTime + ex->model->numframes * 0.05; } S_StartSound (TempSoundChannel(), 0, cl_sfx_flameend, pos, 1, 1); break; case TE_HWBONERIC: pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); cnt = MSG_ReadByte (); R_RunParticleEffect4 (pos, 3, 368 + rand() % 16, pt_grav, cnt); rnd = rand() % 100; if (rnd > 95) S_StartSound (TempSoundChannel(), 0, cl_sfx_ric1, pos, 1, 1); else if (rnd > 91) S_StartSound (TempSoundChannel(), 0, cl_sfx_ric2, pos, 1, 1); else if (rnd > 87) S_StartSound (TempSoundChannel(), 0, cl_sfx_ric3, pos, 1, 1); break; case TE_POWERFLAME: { float travelAng, travelPitch; float fireCounts; dlight_t *dlx; vec3_t endPos, curPos, posAdd; vec3_t angles, forward, right, up; float cVal, sVal; float svTime; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; fireCounts = MSG_ReadByte(); svTime = MSG_ReadLong(); angles[0] = travelPitch*360/(2*M_PI); angles[1] = travelAng*360/(2*M_PI); angles[2] = 0; AngleVectors(angles, forward, right, up); dlx = CL_AllocDlight (0); VectorCopy (pos, dlx->origin); dlx->radius = 200 + (rand()&31); dlx->die = cl.time + 0.001; VectorCopy(pos, endPos); endPos[0] += cos(travelAng) * cos(travelPitch) * 375; endPos[1] += sin(travelAng) * cos(travelPitch) * 375; endPos[2] += sin(travelPitch) * 375; VectorCopy(pos, curPos); VectorSubtract(endPos, pos, posAdd); VectorScale(posAdd, .125, posAdd); for(i = 0; i < fireCounts; i++) { cVal = cos((svTime + (i*.3/8.0))*8)*10; sVal = sin((svTime + (i*.3/8.0))*8)*10; // cVal = cos((svTime + (i*.3/8.0))*16)*35; // sVal = sin((svTime + (i*.3/8.0))*16)*35; ex = CL_AllocExplosion(); VectorCopy(curPos, ex->origin); VectorMA(ex->origin, cVal, right, ex->origin); VectorMA(ex->origin, sVal, up, ex->origin); ex->origin[0] += (rand()%8)-4; ex->origin[1] += (rand()%8)-4; ex->origin[2] += (rand()%6)-3; ex->model = Mod_ForName("models/flamestr.spr", true); ex->startTime = cl.time + .3/8.0 * i; ex->endTime = ex->startTime + ex->model->numframes * 0.05; ex->flags |= DRF_TRANSLUCENT; ex->velocity[0] = 0; ex->velocity[1] = 0; ex->velocity[2] = 0; VectorMA(ex->velocity, cVal * 4.0, right, ex->velocity); VectorMA(ex->velocity, sVal * 4.0, up, ex->velocity); ex = CL_AllocExplosion(); VectorCopy(curPos, ex->origin); VectorMA(ex->origin, -cVal, right, ex->origin); VectorMA(ex->origin, -sVal, up, ex->origin); ex->origin[0] += (rand()%8)-4; ex->origin[1] += (rand()%8)-4; ex->origin[2] += (rand()%6)-3; ex->model = Mod_ForName("models/flamestr.spr", true); ex->startTime = cl.time + .3/8.0 * i; ex->endTime = ex->startTime + ex->model->numframes * 0.05; ex->flags |= DRF_TRANSLUCENT; ex->velocity[0] = 0; ex->velocity[1] = 0; ex->velocity[2] = 0; VectorMA(ex->velocity, -cVal * 4.0, right, ex->velocity); VectorMA(ex->velocity, -sVal * 4.0, up, ex->velocity); VectorAdd(curPos, posAdd, curPos); } } break; case TE_BLOODRAIN: { float travelAng, travelPitch; float trailLen; vec3_t vel; unsigned char health; vec3_t angles, forward, right, up; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte(); health = MSG_ReadByte(); vel[0] = cos(travelAng) * cos(travelPitch) * 800; vel[1] = sin(travelAng) * cos(travelPitch) * 800; vel[2] = sin(travelPitch) * 800; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/sucwp1p.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3/240.0; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; ex->scale = health; VectorCopy(vel, ex->velocity); ex->frameFunc = updateBloodRain; ex->exflags |= EXFLAG_COLLIDE; if(health > 90) { angles[0] = travelPitch*360/(2*M_PI); angles[1] = travelAng*360/(2*M_PI); angles[2] = 0; AngleVectors(angles, forward, right, up); ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); VectorMA(ex->origin, 7, right, ex->origin); ex->model = Mod_ForName("models/sucwp1p.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3/240.0; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; ex->scale = health - 90; VectorCopy(vel, ex->velocity); ex->frameFunc = updateBloodRain; ex->exflags & EXFLAG_COLLIDE; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); VectorMA(ex->origin, -7, right, ex->origin); ex->model = Mod_ForName("models/sucwp1p.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3/240.0; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; ex->scale = health - 90; VectorCopy(vel, ex->velocity); ex->frameFunc = updateBloodRain; ex->exflags |= EXFLAG_COLLIDE; } } break; case TE_AXE: { float travelAng, travelPitch; float trailLen; vec3_t vel; vec3_t angles, forward, right, up; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte() * .01; vel[0] = cos(travelAng) * cos(travelPitch) * 1100; vel[1] = sin(travelAng) * cos(travelPitch) * 1100; vel[2] = sin(travelPitch) * 1100; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/axblade.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/axtail.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex->exflags |= EXFLAG_STILL_FRAME; ex->data = 0; ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; ex->abslight = 128; ex->skin = 0; } break; case TE_PURIFY2_MISSILE: { float travelAng, travelPitch; float trailLen; vec3_t vel; vec3_t angles, forward, right, up; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte() * .01; vel[0] = cos(travelAng) * cos(travelPitch) * 1000; vel[1] = sin(travelAng) * cos(travelPitch) * 1000; vel[2] = sin(travelPitch) * 1000; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/drgnball.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex->frameFunc = updatePurify2; ex->scale = 150; } break; case TE_SWORD_SHOT: { float travelAng, travelPitch; float trailLen; vec3_t vel; vec3_t angles, forward, right, up; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte() * .01; vel[0] = cos(travelAng) * cos(travelPitch) * 1200; vel[1] = sin(travelAng) * cos(travelPitch) * 1200; vel[2] = sin(travelPitch) * 1200; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/vorpshot.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex->frameFunc = updateSwordShot; ex->scale = 100; ex->exflags |= EXFLAG_STILL_FRAME; ex->data = 16 + ((int)(cl.time * 20.0)%13); } break; case TE_ICESHOT: { float travelAng, travelPitch; float trailLen; vec3_t vel; explosion_t *ex2; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte() * .01; vel[0] = cos(travelAng) * cos(travelPitch) * 1200; vel[1] = sin(travelAng) * cos(travelPitch) * 1200; vel[2] = sin(travelPitch) * 1200; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/iceshot1.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex->frameFunc = updateIceShot; ex->scale = 100; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = 425; ex->avel[1] = 425; ex->avel[2] = 425; ex2 = ex; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/iceshot2.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; //ex->frameFunc = updateSwordShot; ex->scale = 200; ex->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; ex->abslight = 128; ex->exflags = EXFLAG_ROTATE; VectorCopy(ex2->avel, ex->avel); } break; case TE_METEOR: { float travelAng, travelPitch; float trailLen; vec3_t vel; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte() * .01; vel[0] = cos(travelAng) * cos(travelPitch) * 1000; vel[1] = sin(travelAng) * cos(travelPitch) * 1000; vel[2] = sin(travelPitch) * 1000; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/tempmetr.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex->frameFunc = updateMeteor; ex->scale = 100; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = 200; ex->avel[1] = 200; ex->avel[2] = 200; } break; case TE_LIGHTNINGBALL: { float travelAng, travelPitch; float trailLen; vec3_t vel; float speed; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; speed = MSG_ReadShort(); trailLen = MSG_ReadByte() * .01; // light dl = CL_AllocDlight (0); VectorCopy (pos, dl->origin); dl->radius = 350; dl->die = cl.time + 0.5; dl->decay = 300; dl->color[0] = 0.2; dl->color[1] = 0.1; dl->color[2] = 0.05; dl->color[3] = 0.7; vel[0] = cos(travelAng) * cos(travelPitch) * speed; vel[1] = sin(travelAng) * cos(travelPitch) * speed; vel[2] = sin(travelPitch) * speed; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/lball.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.2; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; //ex->frameFunc = updateMeteor; //ex->scale = 230; //ex->exflags = EXFLAG_ROTATE; //ex->avel[0] = 200; //ex->avel[1] = 200; //ex->avel[2] = 200; } break; case TE_MEGAMETEOR: { float travelAng, travelPitch; float trailLen; vec3_t vel; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte() * .01; vel[0] = cos(travelAng) * cos(travelPitch) * 1600; vel[1] = sin(travelAng) * cos(travelPitch) * 1600; vel[2] = sin(travelPitch) * 1600; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/tempmetr.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex->frameFunc = updateMeteor; ex->scale = 230; ex->flags |= DRF_TRANSLUCENT; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = 200; ex->avel[1] = 200; ex->avel[2] = 200; } break; case TE_CUBEBEAM: { int type; int ent; int ent2; int tag; int flags; int skin; vec3_t source; vec3_t dest; vec3_t smokeDir; float duration; entity_state_t *state; entity_state_t *state2; type = TE_STREAM_COLORBEAM; ent = MSG_ReadShort(); ent2 = MSG_ReadShort(); flags = 0; tag = 0; duration = 0.1; skin = rand()%5; // source[0] = MSG_ReadCoord(); // source[1] = MSG_ReadCoord(); // source[2] = MSG_ReadCoord(); // dest[0] = MSG_ReadCoord(); // dest[1] = MSG_ReadCoord(); // dest[2] = MSG_ReadCoord(); state = FindState(ent); state2 = FindState(ent2); if (state || state2) { if (state) { VectorCopy(state->origin, source); } else//don't know where the damn cube is--prolly won't see beam anyway then, so put it all at the target { VectorCopy(state2->origin, source); source[2]+=10; } if (state2) { VectorCopy(state2->origin, dest);//in case they're both valid, copy me again dest[2]+=30; } else//don't know where the damn victim is--prolly won't see beam anyway then, so put it all at the cube { VectorCopy(source, dest); dest[2]+=10; } VectorSet(smokeDir,0,0,100); S_StartSound (TempSoundChannel(), 0, cl_sfx_sunstaff, source, 1, 1); S_StartSound (TempSoundChannel(), 0, cl_sfx_sunhit, dest, 1, 1); R_SunStaffTrail(dest, source); CreateStream(TE_STREAM_COLORBEAM, ent, flags, tag, duration, skin, source, dest); } } break; case TE_LIGHTNINGEXPLODE: { int ent; stream_t *stream; float duration; model_t *models[2]; entity_state_t *state; float tempAng, tempPitch; ent = MSG_ReadShort(); state = FindState(ent); pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); if(rand()&1) { S_StartSound (TempSoundChannel(), 0, cl_sfx_lightning1, pos, 1, 1); } else { S_StartSound (TempSoundChannel(), 0, cl_sfx_lightning2, pos, 1, 1); } for (i = 0; i < 10; i++) { // make some lightning models[0] = Mod_ForName("models/stlghtng.mdl", true); if((stream = NewStream(ent, i, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } stream->type = TE_STREAM_LIGHTNING; stream->tag = i; stream->flags = i; stream->entity = ent; stream->skin = 0; stream->models[0] = models[0]; stream->endTime = cl.time+0.5; stream->lastTrailTime = 0; tempAng = (rand()%628)/100.0; tempPitch = (rand()%628)/100.0; VectorCopy(pos, stream->source); VectorCopy(stream->source, stream->dest); stream->dest[0] += 75.0 * cos(tempAng) * cos(tempPitch); stream->dest[1] += 75.0 * sin(tempAng) * cos(tempPitch); stream->dest[2] += 75.0 * sin(tempPitch); } } break; case TE_ACID_BALL_FLY: { float travelAng, travelPitch; float trailLen; vec3_t vel; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte() * .01; vel[0] = cos(travelAng) * cos(travelPitch) * 850; vel[1] = sin(travelAng) * cos(travelPitch) * 850; vel[2] = sin(travelPitch) * 850; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/sucwp2p.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex->frameFunc = updateAcidBall; } break; case TE_ACID_BLOB_FLY: { float travelAng, travelPitch; float trailLen; vec3_t vel; pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); travelAng = MSG_ReadByte()*6.28/256.0; travelPitch = MSG_ReadByte()*6.28/256.0; trailLen = MSG_ReadByte() * .01; vel[0] = cos(travelAng) * cos(travelPitch) * 1000; vel[1] = sin(travelAng) * cos(travelPitch) * 1000; vel[2] = sin(travelPitch) * 1000; ex = CL_AllocExplosion(); VectorCopy(pos, ex->origin); ex->model = Mod_ForName("models/sucwp2p.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + trailLen*.3; ex->angles[0] = travelPitch*360/6.28; ex->angles[1] = travelAng*360/6.28; VectorCopy(vel, ex->velocity); ex->exflags |= EXFLAG_COLLIDE; ex->frameFunc = updateAcidBlob; ex->scale = 230; //ex->exflags = EXFLAG_ROTATE; //ex->avel[0] = 200; //ex->avel[1] = 200; //ex->avel[2] = 200; } break; case TE_CHAINLIGHTNING: { vec3_t points[12]; int numTargs = 0; int oldNum; int temp; int ent; stream_t *stream; float duration; model_t *models[2]; ent = MSG_ReadShort(); do { points[numTargs][0] = MSG_ReadCoord(); points[numTargs][1] = MSG_ReadCoord(); points[numTargs][2] = MSG_ReadCoord(); oldNum = numTargs; if(points[numTargs][0]||points[numTargs][1]||points[numTargs][2]) { if(numTargs < 9) { numTargs++; } } }while(points[oldNum][0]||points[oldNum][1]||points[oldNum][2]); if(numTargs == 0) { break; } for(temp = 0; temp < numTargs - 1; temp++) { // make the connecting lightning... models[0] = Mod_ForName("models/stlghtng.mdl", true); if((stream = NewStream(ent, temp, NULL)) == NULL) { Con_Printf("stream list overflow\n"); return; } stream->type = TE_STREAM_LIGHTNING; stream->tag = temp; stream->flags = temp; stream->entity = ent; stream->skin = 0; stream->models[0] = models[0]; stream->endTime = cl.time+0.3; stream->lastTrailTime = 0; VectorCopy(points[temp], stream->source); VectorCopy(points[temp + 1], stream->dest); ex = CL_AllocExplosion(); VectorCopy(points[temp+1], ex->origin); ex->model = Mod_ForName("models/vorpshok.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + .3; ex->flags |= MLS_ABSLIGHT;//|DRF_TRANSLUCENT; //ex->abslight = 128; ex->abslight = 224; ex->skin = rand()&1; ex->scale = 150; ex->frameFunc = zapFrameFunc; //ex->frameFunc = SwordFrameFunc; //ex->flags = DRF_TRANSLUCENT;// | MLS_ABSLIGHT; //ex->angles[0] = travelPitch*360/6.28; //ex->angles[1] = travelAng*360/6.28; } } break; default: Sys_Error ("CL_ParseTEnt: bad type"); } } /* ================= CL_NewTempEntity ================= */ entity_t *CL_NewTempEntity (void) { entity_t *ent; if (cl_numvisedicts == MAX_VISEDICTS) return NULL; ent = &cl_visedicts[cl_numvisedicts]; cl_numvisedicts++; ent->keynum = 0; memset (ent, 0, sizeof(*ent)); ent->colormap = vid.colormap; return ent; } /* ================= CL_UpdateBeams ================= */ void CL_UpdateBeams (void) { int i; beam_t *b; vec3_t dist, org; float d; entity_t *ent; float yaw, pitch; float forward; // update lightning for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) { if (!b->model || b->endtime < cl.time) continue; // if coming from the player, update the start position if (b->entity == cl.playernum+1) // entity 0 is the world { VectorCopy (cl.simorg, b->start); b->start[2] -= 22; // adjust for view height } // calculate pitch and yaw VectorSubtract (b->end, b->start, dist); if (dist[1] == 0 && dist[0] == 0) { yaw = 0; if (dist[2] > 0) pitch = 90; else pitch = 270; } else { yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI); if (yaw < 0) yaw += 360; forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); pitch = (int) (atan2(dist[2], forward) * 180 / M_PI); if (pitch < 0) pitch += 360; } // add new entities for the lightning VectorCopy (b->start, org); d = VectorNormalize(dist); while (d > 0) { ent = CL_NewTempEntity (); if (!ent) return; VectorCopy (org, ent->origin); ent->model = b->model; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = rand()%360; for (i=0 ; i<3 ; i++) org[i] += dist[i]*30; d -= 30; } } } /* ================= CL_UpdateExplosions ================= */ void CL_UpdateExplosions (void) { int i; int f; explosion_t *ex; entity_t *ent; mleaf_t *l; for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++) { if (!ex->model) continue; if(ex->exflags & EXFLAG_COLLIDE) { l = Mod_PointInLeaf (ex->origin, cl.worldmodel); if(l->contents != CONTENTS_EMPTY) { if (ex->removeFunc) { ex->removeFunc(ex); } ex->model = NULL; continue; } } // if we hit endTime, get rid of explosion (i assume endTime is greater than startTime, etc) if (ex->endTime <= cl.time) { if (ex->removeFunc) { ex->removeFunc(ex); } ex->model = NULL; continue; } VectorCopy(ex->origin, ex->oldorg); // set the current frame so i finish anim at endTime if(ex->exflags & EXFLAG_STILL_FRAME) { // if it's a still frame, use the data field f = (int)ex->data; } else { f = (ex->model->numframes-1) * (cl.time - ex->startTime) / (ex->endTime - ex->startTime); } // apply velocity ex->origin[0] += host_frametime * ex->velocity[0]; ex->origin[1] += host_frametime * ex->velocity[1]; ex->origin[2] += host_frametime * ex->velocity[2]; // apply acceleration ex->velocity[0] += host_frametime * ex->accel[0]; ex->velocity[1] += host_frametime * ex->accel[1]; ex->velocity[2] += host_frametime * ex->accel[2]; // add in angular velocity if(ex->exflags & EXFLAG_ROTATE) { VectorMA(ex->angles, host_frametime, ex->avel, ex->angles); } // you can set startTime to some point in the future to delay the explosion showing up or thinking; it'll still move, though if (ex->startTime > cl.time) continue; if (ex->frameFunc) { ex->frameFunc(ex); } // allow for the possibility for the frame func to reset startTime if (ex->startTime > cl.time) continue; // just incase the frameFunc eliminates the thingy here. if (ex->model == NULL) continue; ent = CL_NewTempEntity (); if (!ent) continue; VectorCopy (ex->origin, ent->origin); VectorCopy (ex->angles, ent->angles); ent->model = ex->model; ent->frame = f; ent->skinnum = ex->skin; ent->drawflags = ex->flags; if(ex->flags & MLS_ABSLIGHT) { ent->abslight = ex->abslight; } if(ex->scale) { ent->scale = ex->scale; } } } void CL_UpdateStreams(void) { int i; stream_t *stream; vec3_t dist; vec3_t org; vec3_t discard, right, up; float cosTime, sinTime, lifeTime, cos2Time, sin2Time; float d; entity_t *ent; float yaw, pitch; float forward; int segmentCount; int offset; entity_state_t *state; // Update streams StreamEntityCount = 0; for(i = 0, stream = cl_Streams; i < MAX_STREAMS; i++, stream++) { if(!stream->models[0])// || stream->endTime < cl.time) { // Inactive continue; } if(stream->endTime < cl.time) { // Inactive if(stream->type!=TE_STREAM_LIGHTNING&&stream->type!=TE_STREAM_LIGHTNING_SMALL) continue; else if(stream->endTime + 0.25 < cl.time) continue; } if(stream->flags&STREAM_ATTACHED&&stream->endTime >= cl.time) { // Attach the start position to owner state = FindState(stream->entity); if (state) { VectorAdd(state->origin, stream->offset, stream->source); } } VectorSubtract(stream->dest, stream->source, dist); if(dist[1] == 0 && dist[0] == 0) { yaw = 0; if(dist[2] > 0) { pitch = 90; } else { pitch = 270; } } else { yaw = (int)(atan2(dist[1], dist[0])*180/M_PI); if(yaw < 0) { yaw += 360; } forward = sqrt(dist[0]*dist[0]+dist[1]*dist[1]); pitch = (int)(atan2(dist[2], forward)*180/M_PI); if(pitch < 0) { pitch += 360; } } VectorCopy(stream->source, org); d = VectorNormalize(dist); if(stream->type == TE_STREAM_SUNSTAFF2) { discard[YAW] = yaw; discard[PITCH] = pitch; discard[ROLL] = 0; AngleVectors(discard, discard, right, up); lifeTime = ((stream->endTime - cl.time)/.8); cosTime = cos(cl.time*5); sinTime = sin(cl.time*5); cos2Time = cos(cl.time*5 + 3.14); sin2Time = sin(cl.time*5 + 3.14); } segmentCount = 0; if(stream->type == TE_STREAM_ICECHUNKS) { offset = (int)(cl.time*40)%30; for(i = 0; i < 3; i++) { org[i] += dist[i]*offset; } } while(d > 0) { ent = CL_NewTempEntity(); if(!ent) { return; } VectorCopy(org, ent->origin); ent->model = stream->models[0]; ent->angles[0] = pitch; ent->angles[1] = yaw; switch(stream->type) { case TE_STREAM_CHAIN: ent->angles[2] = 0; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; break; case TE_STREAM_SUNSTAFF1: ent->angles[2] = (int)(cl.time*10)%360; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; ent->scale = 50 + 100 * ((stream->endTime - cl.time)/.3); //ent->frame = (int)(cl.time*20)%20; ent = CL_NewTempEntity(); if(!ent) { return; } VectorCopy(org, ent->origin); ent->model = stream->models[1]; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = (int)(cl.time*50)%360; ent->drawflags = MLS_ABSLIGHT|DRF_TRANSLUCENT; ent->abslight = 128; ent->scale = 50 + 100 * ((stream->endTime - cl.time)/.5); //stream->endTime = cl.time+0.3; // FIXME break; case TE_STREAM_SUNSTAFF2: ent->angles[2] = (int)(cl.time*100)%360; ent->drawflags = MLS_ABSLIGHT|DRF_TRANSLUCENT; ent->abslight = 128; ent->scale = 100 + 150 * lifeTime; VectorMA(ent->origin, cosTime * (40 * lifeTime), right, ent->origin); VectorMA(ent->origin, sinTime * (40 * lifeTime), up, ent->origin); ent = CL_NewTempEntity(); if(!ent) { return; } VectorCopy(org, ent->origin); ent->model = stream->models[0]; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = (int)(cl.time*100)%360; ent->drawflags = MLS_ABSLIGHT|DRF_TRANSLUCENT; ent->abslight = 128; ent->scale = 100 + 150 * lifeTime; VectorMA(ent->origin, cos2Time * (40 * lifeTime), right, ent->origin); VectorMA(ent->origin, sin2Time * (40 * lifeTime), up, ent->origin); { int ix; for(ix = 0; ix < 2; ix++) { ent = CL_NewTempEntity(); if(!ent) { return; } VectorCopy(org, ent->origin); if(i) { VectorMA(ent->origin, cos2Time * (40 * lifeTime), right, ent->origin); VectorMA(ent->origin, sin2Time * (40 * lifeTime), up, ent->origin); } else { VectorMA(ent->origin, cosTime * (40 * lifeTime), right, ent->origin); VectorMA(ent->origin, sinTime * (40 * lifeTime), up, ent->origin); } ent->model = stream->models[1]; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = (int)(cl.time*20)%360; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; ent->scale = 100 + 150 * lifeTime; } } break; case TE_STREAM_LIGHTNING: if(stream->endTime < cl.time) {//fixme: keep last non-translucent frame and angle ent->drawflags = MLS_ABSLIGHT|DRF_TRANSLUCENT; ent->abslight = 128 + (stream->endTime - cl.time)*192; } else { ent->angles[2] = rand()%360; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; ent->frame = rand()%6; } break; case TE_STREAM_LIGHTNING_SMALL: if(stream->endTime < cl.time) { ent->drawflags = MLS_ABSLIGHT|DRF_TRANSLUCENT; ent->abslight = 128 + (stream->endTime - cl.time)*192; } else { ent->angles[2] = rand()%360; ent->frame = rand()%6; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; } case TE_STREAM_FAMINE: ent->angles[2] = rand()%360; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; ent->frame = 0; break; case TE_STREAM_COLORBEAM: ent->angles[2] = 0; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; ent->skinnum = stream->skin; break; case TE_STREAM_GAZE: ent->angles[2] = 0; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; ent->frame = (int)(cl.time*40)%36; break; case TE_STREAM_ICECHUNKS: ent->angles[2] = rand()%360; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; ent->frame = rand()%5; break; /* ent->angles[2] = (int)(cl.time*80)%360; ent->origin[0] += (rand()%4)-2; ent->origin[1] += (rand()%4)-2; ent->origin[2] += (rand()%4)-2; ent->frame = segmentCount%4; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; if((rand()&255) > 128) { break; } ent = NewStreamEntity(); if(!ent) { return; } VectorCopy(org, ent->origin); ent->model = stream->models[0]; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = rand()%360; ent->origin[0] += (rand()%20)-10; ent->origin[1] += (rand()%20)-10; ent->origin[2] += (rand()%20)-10; ent->frame = 4+(rand()&1); ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; break; */ default: ent->angles[2] = 0; } for(i = 0; i < 3; i++) { org[i] += dist[i]*30; } d -= 30; segmentCount++; } if(stream->type == TE_STREAM_SUNSTAFF1) { if(stream->lastTrailTime+0.2 < cl.time) { stream->lastTrailTime = cl.time; R_SunStaffTrail(stream->source, stream->dest); } ent = CL_NewTempEntity(); if(ent == NULL) { return; } VectorCopy(stream->dest, ent->origin); ent->model = stream->models[2]; ent->drawflags = MLS_ABSLIGHT; ent->abslight = 128; ent->scale = 80+(rand()&15); //ent->frame = (int)(cl.time*20)%20; ent = CL_NewTempEntity(); if(ent == NULL) { return; } VectorCopy(stream->dest, ent->origin); ent->model = stream->models[3]; ent->drawflags = MLS_ABSLIGHT|DRF_TRANSLUCENT; ent->abslight = 128; ent->scale = 150+(rand()&15); } } } /* ================= CL_UpdateTEnts ================= */ void CL_UpdateTEnts (void) { CL_UpdateBeams (); CL_UpdateExplosions (); CL_UpdateStreams(); CL_UpdateTargetBall(); } void MultiGrenadeExplodeSound (explosion_t *ex)//plug up all of -1's channels w/ grenade sounds { if (!(rand()&7)) { if (MultiGrenadeCurrentChannel>=MAX_DYNAMIC_CHANNELS || MultiGrenadeCurrentChannel<0) { MultiGrenadeCurrentChannel=0; } S_StartSound (TempSoundChannel(), MultiGrenadeCurrentChannel++, cl_sfx_explode, ex->origin, 1, 1); } ex->frameFunc=NULL; } void MultiGrenadeThink (explosion_t *ex) {//FIXME: too messy explosion_t *missile; int attack_counter,number_explosions; float ftemp; VectorSet(ex->velocity,0,0,0); VectorSet(ex->accel,0,0,0); ex->frameFunc=MultiGrenadeExplodeSound; attack_counter=0; number_explosions=(rand()&2)+6; while(attack_counterframeFunc = MultiGrenadePieceThink; VectorCopy(ex->origin,missile->origin); if (rand()&1) missile->model = Mod_ForName("models/gen_expl.spr", true); else missile->model = Mod_ForName("models/bg_expld.spr", true); switch (attack_counter % 3) { case 2: missile->frameFunc = MultiGrenadePieceThink; missile->velocity[0]=(rand()%600)-300; missile->velocity[1]=(rand()%600)-300; missile->velocity[2]=0;//(rand()%100)+50; ftemp = ( rand() / RAND_MAX * (0.5) ); missile->startTime = cl.time;// + 0.1 + ftemp - (ex->startTime - cl.time); ftemp = ( rand() / RAND_MAX * (0.3) )-0.15; missile->endTime = missile->startTime + missile->model->numframes * 0.1 + ftemp; break; case 1: missile->frameFunc = MultiGrenadePiece2Think; missile->velocity[0]=(rand()%80)-40; missile->velocity[1]=(rand()%80)-40; missile->velocity[2]=(rand()%150)+150; ftemp = ( rand() / RAND_MAX * (0.5) ); missile->startTime = cl.time;// + 0.1 + ftemp - (ex->startTime - cl.time); ftemp = ( rand() / RAND_MAX * (0.3) )-0.15; missile->endTime = missile->startTime + missile->model->numframes * 0.1 + ftemp; break; default://some extra explosions for at first missile->frameFunc = NULL; missile->origin[0]+=(rand()%50)-25; missile->origin[1]+=(rand()%50)-25; missile->origin[2]+=(rand()%50)-25; ftemp = ( rand() / RAND_MAX * (0.2) ); missile->startTime = cl.time + ftemp; ftemp = ( rand() / RAND_MAX * (0.2) )-0.1; missile->endTime = missile->startTime + missile->model->numframes * 0.1 + ftemp; break; } ftemp = ( rand() / RAND_MAX * (0.2) ); missile->data=ex->data*(0.7 + ftemp); } } void MultiGrenadePieceThink (explosion_t *ex) {//FIXME: too messy explosion_t *missile; int attack_counter,number_explosions; float ftemp; VectorSet(ex->velocity,0,0,0); VectorSet(ex->accel,0,0,0); ex->frameFunc=MultiGrenadeExplodeSound; if (ex->data < 70) ex->data = 70; ftemp = ( rand() / RAND_MAX * (0.2) )-0.1; ex->startTime = cl.time + ((1-(ex->data-69)/180.0)+ftemp-0.3) * 1.25; if (ex->startTime < cl.time) { ex->startTime = cl.time; } ftemp = ( rand() / RAND_MAX * (0.4) )-0.4; ex->endTime = ex->startTime + ex->model->numframes * 0.1 + ftemp; if (ex->model->numframes > 14) { ex->startTime -= 0.4; ex->endTime -= 0.4; } if (ex->data <= 71) return; attack_counter=0; number_explosions=(rand()&3)+2; while(attack_counterframeFunc = MultiGrenadePieceThink; VectorCopy(ex->origin,missile->origin); missile->origin[0]+=(rand()%100)-50; missile->origin[1]+=(rand()%100)-50; missile->origin[2]+=(rand()%10)-4; ftemp = ( rand() / RAND_MAX * (0.2) ); missile->data=ex->data*(0.7 + ftemp); if (rand()&7) missile->model = Mod_ForName("models/bg_expld.spr", true); else missile->model = Mod_ForName("models/fl_expld.spr", true); ftemp = ( rand() / RAND_MAX * (0.5) ); missile->startTime = cl.time+0.01; missile->endTime = missile->startTime + missile->model->numframes * 0.1; } } void MultiGrenadePiece2Think (explosion_t *ex) {//FIXME: too messy explosion_t *missile; int attack_counter,number_explosions; float ftemp; VectorSet(ex->velocity,0,0,0); VectorSet(ex->accel,0,0,0); ex->frameFunc=MultiGrenadeExplodeSound; if (ex->data < 70) { ex->data = 70; } ftemp = 0;//( rand() / RAND_MAX * (0.2) )-0.1; ex->startTime = cl.time + (((1 - (ex->data-69)/200.0)+ftemp)*1.5) - 0.2; ftemp = ( rand() / RAND_MAX * (0.4) )-0.2; ex->endTime = ex->startTime + ex->model->numframes * 0.1 + ftemp; if (ex->data <= 71) return; attack_counter=0; number_explosions=(rand()%3)+2; while(attack_counterframeFunc = MultiGrenadePiece2Think; VectorCopy(ex->origin,missile->origin); missile->origin[0]+=(rand()%30)-15; missile->origin[1]+=(rand()%30)-15; ftemp = rand() / RAND_MAX; missile->origin[2]+=(ftemp*7)+30; missile->data=ex->data - ftemp * 10 - 20; if (rand()&1) missile->model = Mod_ForName("models/gen_expl.spr", true); else missile->model = Mod_ForName("models/bg_expld.spr", true); ftemp = ( rand() / RAND_MAX * (0.5) ); missile->startTime = cl.time+0.01; missile->endTime = missile->startTime + missile->model->numframes * 0.1; } } void ChunkThink(explosion_t *ex) { vec3_t oldorg; mleaf_t *l; int moving = 1; l = Mod_PointInLeaf (ex->origin, cl.worldmodel); if(l->contents!=CONTENTS_EMPTY) //||in_solid==true { //collided with world VectorCopy(ex->oldorg, ex->origin); if((int)ex->data == THINGTYPE_FLESH) { if(VectorNormalize(ex->velocity) > 100.0) { // hit, now make a splash of blood vec3_t dmin = {-40, -40, 10}; vec3_t dmax = {40, 40, 40}; //R_RunParticleEffect4 (ex->origin, 300.0, 136 + (rand()%5), pt_darken, 25); //R_RunParticleEffect2 (ex->origin, dmin, dmax, 136 + (rand()%5), pt_fastgrav, 12); R_RunParticleEffect2 (ex->origin, dmin, dmax, 136 + (rand()%5), pt_darken, 20); } } else if((int)ex->data == THINGTYPE_ACID) { if(VectorNormalize(ex->velocity) > 100.0) { // hit, now make a splash of acid vec3_t dmin = {-40, -40, 10}; vec3_t dmax = {40, 40, 40}; //R_RunParticleEffect2 (ex->origin, dmin, dmax, 136 + (rand()%5), pt_darken, 20); // FIXME - These should be green if(!(rand()%3)) { S_StartSound (TempSoundChannel(), 0, cl_sfx_dropfizzle, ex->origin, 1, 1); } } } ex->velocity[0] = 0; ex->velocity[1] = 0; ex->velocity[2] = 0; ex->avel[0] = 0; ex->avel[1] = 0; ex->avel[2] = 0; moving = 0; } if(cl.time + host_frametime * 5 > ex->endTime) { // chunk leaves in 5 frames about switch((int)ex->data) { case THINGTYPE_METEOR: if(cl.time + host_frametime * 4 < ex->endTime) { // just crossed the threshold ex->abslight = 200; } else { ex->abslight -= 35; } ex->flags |= DRF_TRANSLUCENT|MLS_ABSLIGHT; ex->scale *= 1.4; ex->angles[0] += 20; break; default: ex->scale *= .8; break; } } ex->velocity[2] -= host_frametime * movevars.gravity; // this is gravity switch((int)ex->data) { case THINGTYPE_GREYSTONE: break; case THINGTYPE_WOOD: break; case THINGTYPE_METAL: break; case THINGTYPE_FLESH: if(moving)R_RocketTrail (ex->oldorg, ex->origin, rt_blood); break; case THINGTYPE_FIRE: break; case THINGTYPE_CLAY: break; case THINGTYPE_LEAVES: break; case THINGTYPE_HAY: break; case THINGTYPE_BROWNSTONE: case THINGTYPE_DIRT: break; case THINGTYPE_CLOTH: break; case THINGTYPE_WOOD_LEAF: break; case THINGTYPE_WOOD_METAL: break; case THINGTYPE_WOOD_STONE: break; case THINGTYPE_METAL_STONE: break; case THINGTYPE_METAL_CLOTH: break; case THINGTYPE_WEBS: break; case THINGTYPE_GLASS: break; case THINGTYPE_ICE: ex->velocity[2] += host_frametime * movevars.gravity * 0.5; // lower gravity for ice chunks if(moving)R_RocketTrail (ex->oldorg, ex->origin, rt_ice); break; case THINGTYPE_CLEARGLASS: break; case THINGTYPE_REDGLASS: break; case THINGTYPE_ACID: if(moving)R_RocketTrail (ex->oldorg, ex->origin, 16); break; case THINGTYPE_METEOR: VectorCopy(ex->oldorg, oldorg); if(!moving) { // resting meteors still give off smoke oldorg[0] += rand()%7 - 3; oldorg[1] += rand()%7 - 3; oldorg[2] += 16; } R_RocketTrail (oldorg, ex->origin, 1); break; case THINGTYPE_GREENFLESH: if(moving)R_RocketTrail (ex->oldorg, ex->origin, 16); break; } } void BubbleThink(explosion_t *ex) { vec3_t oldorg; mleaf_t *l; l = Mod_PointInLeaf (ex->origin, cl.worldmodel); if(l->contents==CONTENTS_WATER) { //still in water if (ex->data < cl.time)//change course { ex->velocity[0] += rand()%20 - 10; ex->velocity[1] += rand()%20 - 10; ex->velocity[2] += rand()%10 + 10; if (ex->velocity[0] > 10) ex->velocity[0] = 5; if (ex->velocity[0] < -10) ex->velocity[0] = -5; if (ex->velocity[1] > 10) ex->velocity[1] = 5; if (ex->velocity[1] < -10) ex->velocity[1] = -5; if (ex->velocity[2] < 10) ex->velocity[2] = 15; if (ex->velocity[2] > 30) ex->velocity[2] = 25; ex->data += 0.5; } } else { ex->endTime= cl.time; } } void MissileFlashThink(explosion_t *ex) { ex->abslight-=(0.05*256); ex->scale+=5; if(ex->abslight < (0.05*256)) ex->endTime = ex->startTime; //remove } void TeleportFlashThink(explosion_t *ex) { ex->scale -= 15; if(ex->scale < 10) ex->endTime = ex->startTime; } // remove tent if not in open air void CheckSpaceThink(explosion_t *ex) { mleaf_t *l; l = Mod_PointInLeaf (ex->origin, cl.worldmodel); if(l->contents!=CONTENTS_EMPTY) { ex->endTime = ex->startTime; } } // functions to create tempents from client effect calls void CreateRavenExplosions(vec3_t pos) { explosion_t *ex; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->velocity[2] = 8; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->origin[2] -= 5; ex->velocity[2] = 8; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->origin[2] -= 10; ex->velocity[2] = 8; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; } void CreateRavenDeath(vec3_t pos) { explosion_t *ex; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->velocity[1] = 8; ex->velocity[2] = -10; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->velocity[2] = -10; ex->model = Mod_ForName("models/redsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->velocity[1] = -8; ex->velocity[2] = -10; ex->model = Mod_ForName("models/whtsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; S_StartSound(TempSoundChannel(), 1, cl_sfx_ravendie, pos, 1, 1); } void CreateExplosionWithSound(vec3_t pos) { explosion_t *ex; ex = CL_AllocExplosion (); VectorCopy(pos, ex->origin); ex->startTime = cl.time; ex->endTime = ex->startTime + HX_FRAME_TIME * 10; ex->model = Mod_ForName("models/sm_expld.spr", true); S_StartSound (TempSoundChannel(), 1, cl_sfx_explode, pos, 1, 1); } void SwordFrameFunc(explosion_t *ex) { ex->scale = (ex->endTime - cl.time)*150 + 1; if(((int)(cl.time * 20.0))%2) { ex->skin = 0; } else { ex->skin = 1; } } void zapFrameFunc(explosion_t *ex) { ex->scale = (ex->endTime - cl.time)*(150/.3) + 1; //ex->abslight = (224/.3) * (ex->endTime - cl.time) + 1; if(((int)(cl.time * 20.0))%2) { ex->skin = 0; } else { ex->skin = 1; } } void fireBallUpdate(explosion_t *ex) { ex->scale = (int)(((cl.time - ex->startTime) / 1.0) * 250)+1; } void sunBallUpdate(explosion_t *ex) { ex->scale = 121 - (int)(((cl.time - ex->startTime) / .8) * 120); } void sunPowerUpdate(explosion_t *ex) { } void purify1Update(explosion_t *ex) { R_RocketTrail (ex->oldorg, ex->origin, rt_purify); //R_RocketTrail (ex->oldorg, ex->origin, rt_setstaff); } void MeteorBlastThink(explosion_t *ex) { int i, maxI; mleaf_t *l; explosion_t *ex2; vec3_t tempVect, oldPos; int hitWall = 0; R_RocketTrail (ex->oldorg, ex->origin, rt_fireball); ex->data -= 1600 * host_frametime; // decrease distance, roughly... if(ex->data <= 0) { // ran out of juice VectorCopy(ex->origin, oldPos); hitWall = 1; } else { VectorCopy(ex->oldorg, tempVect); for(i = 0; (i < 10)&&(!hitWall); i++) { VectorCopy(tempVect, oldPos); VectorScale(ex->origin, .1 * (i+1), tempVect); VectorMA(tempVect, 1.0 - (.1 * (i+1)), ex->oldorg, tempVect); l = Mod_PointInLeaf (tempVect, cl.worldmodel); if(l->contents != CONTENTS_EMPTY) { hitWall = 1; } } } if(hitWall) { //collided with world VectorCopy(oldPos, ex->origin); maxI = (host_frametime <= 0.05) ? 12:5; for(i = 0; i < maxI; i++) { ex2 = CL_AllocExplosion(); VectorCopy(ex->origin, ex2->origin); ex2->origin[0] += (rand()%10) - 5; ex2->origin[1] += (rand()%10) - 5; ex2->origin[2] += (rand()%10); ex2->velocity[0] = (ex2->origin[0] - ex->origin[0])*12; ex2->velocity[1] = (ex2->origin[1] - ex->origin[1])*12; ex2->velocity[2] = (ex2->origin[2] - ex->origin[2])*12; switch(rand()%4) { case 0: case 1: ex2->model = Mod_ForName("models/sm_expld.spr", true); break; case 2: ex2->model = Mod_ForName("models/bg_expld.spr", true); break; case 3: ex2->model = Mod_ForName("models/gen_expl.spr", true); break; } ex2->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; ex2->abslight = 160 + rand()%64; ex2->skin = 0; ex2->scale = 80 + rand()%40; ex2->startTime = cl.time + (rand()%30 / 200.0); ex2->endTime = ex2->startTime + ex2->model->numframes * 0.03; } if(rand()&1) { S_StartSound (TempSoundChannel(), 0, cl_sfx_axeExplode, ex->origin, 1, 1); } ex->model == NULL; ex->endTime = cl.time; } } void MeteorCrushSpawnThink(explosion_t *ex) { float chance; explosion_t *ex2; if(host_frametime <= 0.05) { chance = (host_frametime / .4 * 16); } else { chance = (host_frametime / .4 * 8); } while(chance > 0) { if(chance < 1.0) { // take care of fractional numbers of meteors... if((rand()%100) > chance * 100) { return; } } ex2 = CL_AllocExplosion(); VectorCopy(ex->origin, ex2->origin); ex2->origin[0] += (rand()%160) - 80; ex2->origin[1] += (rand()%160) - 80; ex2->model = Mod_ForName("models/tempmetr.mdl", true); ex2->startTime = cl.time; ex2->endTime = ex2->startTime + 2.0; ex2->frameFunc = MeteorBlastThink; ex2->exflags = EXFLAG_ROTATE; ex2->avel[0] = 800; ex2->avel[1] = 800; ex2->avel[2] = 800; // ex2->velocity[0] = rand()%1200 - 600; // ex2->velocity[1] = rand()%1200 - 600; ex2->velocity[0] = rand()%180 - 90; ex2->velocity[1] = rand()%180 - 90; ex2->velocity[2] = -1600 - (rand()%200); ex2->data = ex->data; // stores how far the thingy can travel max ex2->scale = 200 + (rand()%120); chance -= 1.0; } } void updateBloodRain(explosion_t *ex) { R_RocketTrail (ex->oldorg, ex->origin, rt_blood); ex->scale -= host_frametime / .3 * 60; if(ex->scale <= 0) { ex->endTime = cl.time - 1; } } void updatePurify2(explosion_t *ex) { explosion_t *ex2; int numSprites; R_RocketTrail (ex->oldorg, ex->origin, rt_purify); if(host_frametime <= 0.05) { numSprites = 20; } else { numSprites = 8; } if((rand()%100)/100.0 < numSprites * host_frametime) { ex2 = CL_AllocExplosion(); VectorCopy(ex->origin, ex2->origin); ex2->model = Mod_ForName("models/ring.mdl", true); ex2->startTime = cl.time; ex2->endTime = ex2->startTime + 1.2; ex2->scale = 150; VectorCopy(ex->angles, ex2->angles); ex2->angles[2] += 90; ex2->exflags |= EXFLAG_STILL_FRAME; ex2->data = 0; ex2->skin = 0; ex2->frameFunc = SmokeRingFrameFunc; ex2->velocity[2] = 15.0; ex2->flags |= DRF_TRANSLUCENT | SCALE_ORIGIN_CENTER; } } void updateSwordShot(explosion_t *ex) { int testVal; R_RocketTrail (ex->oldorg, ex->origin, rt_vorpal); ex->data = 16 + ((int)(cl.time * 20.0)%13); ex->flags |= MLS_ABSLIGHT; ex->abslight = 128; testVal = (int)(cl.time * 20.0); if(testVal % 2) { ex->skin = 0; } else { ex->skin = 1; } } void updateIceShot(explosion_t *ex) { R_RocketTrail (ex->oldorg, ex->origin, rt_ice); } void updateMeteor(explosion_t *ex) { R_RocketTrail (ex->oldorg, ex->origin, rt_smoke); } void updateAcidBlob(explosion_t *ex) { explosion_t *ex2; int testVal, testVal2; R_RocketTrail (ex->oldorg, ex->origin, rt_acidball); testVal = (int)(cl.time * 10.0); testVal2 = (int)((cl.time - host_frametime)*10.0); if(testVal != testVal2) { if(!(testVal%2)) { ex2 = CL_AllocExplosion(); VectorCopy(ex->origin, ex2->origin); ex2->model = Mod_ForName("models/muzzle1.spr", true); ex2->startTime = cl.time; ex2->endTime = ex2->startTime + .4; VectorCopy(ex->angles, ex2->angles); ex2->angles[2] += 90; //ex->exflags |= EXFLAG_STILL_FRAME; //ex->data = 0; ex2->skin = 0; ex2->velocity[0] = 0; ex2->velocity[1] = 0; ex2->velocity[2] = 0; ex2->flags |= DRF_TRANSLUCENT | SCALE_ORIGIN_CENTER; } } } void updateAcidBall(explosion_t *ex) { R_RocketTrail (ex->oldorg, ex->origin, rt_acidball); } //***************************************************************************** // // FLAG UPDATE FUNCTIONS // //***************************************************************************** void CL_UpdatePoisonGas(entity_t *ent, int edict_num) { explosion_t *ex; float smokeCount; if(host_frametime <= 0.05) { smokeCount = 32 * host_frametime; } else { smokeCount = 16 * host_frametime; } while(smokeCount > 0) { if(smokeCount < 1.0) { if((rand()%100)/100 > smokeCount) { // account for fractional chance of more smoke... smokeCount = 0; continue; } } ex = CL_AllocExplosion(); VectorCopy(ent->origin, ex->origin); ex->model = Mod_ForName("models/grnsmk1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + .7 + (rand()%200)*.001; ex->scale = 100; VectorCopy(ent->angles, ex->angles); ex->angles[2] += 90; //ex->exflags |= EXFLAG_STILL_FRAME; //ex->data = 0; ex->skin = 0; ex->velocity[0] = (rand()%100) - 50; ex->velocity[1] = (rand()%100) - 50; ex->velocity[2] = 150.0; ex->flags |= DRF_TRANSLUCENT | SCALE_ORIGIN_CENTER; smokeCount -= 1.0; } } void CL_UpdateAcidBlob(entity_t *ent, int edict_num) { explosion_t *ex; int testVal, testVal2; testVal = (int)(cl.time * 10.0); testVal2 = (int)((cl.time - host_frametime)*10.0); if(testVal != testVal2) { if(!(testVal%2)) { ex = CL_AllocExplosion(); VectorCopy(ent->origin, ex->origin); ex->model = Mod_ForName("models/muzzle1.spr", true); ex->startTime = cl.time; ex->endTime = ex->startTime + .4; ex->scale = 100; VectorCopy(ent->angles, ex->angles); ex->angles[2] += 90; //ex->exflags |= EXFLAG_STILL_FRAME; //ex->data = 0; ex->skin = 0; ex->velocity[0] = 0; ex->velocity[1] = 0; ex->velocity[2] = 0; ex->flags |= DRF_TRANSLUCENT | SCALE_ORIGIN_CENTER; } } } void CL_UpdateOnFire(entity_t *ent, int edict_num) { explosion_t *ex; if((rand()%100)/100.0 < 5.0 * host_frametime) { ex = CL_AllocExplosion(); VectorCopy(ent->origin, ex->origin); //raise and randomize origin some //ex->origin[0]+=(rand()%ent->maxs[0])-ent->maxs[0]/2; //ex->origin[1]+=(rand()%ent->maxs[1])-ent->maxs[1]/2; //ex->origin[2]+=ent->maxs[2]/2; ex->origin[0]+=(rand()%10) - 5; ex->origin[1]+=(rand()%10) - 5; ex->origin[2]+=rand()%20+10;//at least 10 up from origin, sprite's origin is in center! switch(rand()%3) { case 0: ex->model = Mod_ForName("models/firewal1.spr", true); break; case 1: ex->model = Mod_ForName("models/firewal2.spr", true); break; case 2: ex->model = Mod_ForName("models/firewal3.spr", true); break; } ex->startTime = cl.time; ex->endTime = ex->startTime + ex->model->numframes * 0.05; ex->scale = 100; VectorCopy(ent->angles, ex->angles); ex->angles[2] += 90; ex->velocity[0] = (rand()%40)-20; ex->velocity[1] = (rand()%40)-20; ex->velocity[2] = 50 + (rand()%100); if(rand()%5)//translucent 80% of the time ex->flags |= DRF_TRANSLUCENT; } } /* void CL_UpdatePowerFlame(entity_t *ent, int edict_num, vec3_t oldOrg) { explosion_t *ex; vec3_t curPos, posAdd; float len; int spriteCount, i; vec3_t forward, up, right; float cVal, sVal; AngleVectors(ent->angles, forward, right, up); VectorCopy(oldOrg, curPos); VectorSubtract(ent->origin, oldOrg, posAdd); len = VectorNormalize(posAdd); VectorScale(posAdd, 32.0, posAdd); spriteCount = (int)(len / 32.0) + 1; for(i = 0; i < spriteCount; i++) { cVal = cos((cl.time + (i*0.025))*12)*15; sVal = sin((cl.time + (i*0.025))*12)*15; ex = CL_AllocExplosion(); VectorCopy(curPos, ex->origin); VectorMA(ex->origin, cVal, right, ex->origin); VectorMA(ex->origin, sVal, up, ex->origin); ex->model = Mod_ForName("models/flamestr.spr", true); ex->startTime = cl.time + i*0.025; ex->endTime = ex->startTime + ex->model->numframes * 0.04; ex->scale = 100; VectorCopy(ent->angles, ex->angles); ex->angles[2] += 90; ex->flags |= DRF_TRANSLUCENT; ex = CL_AllocExplosion(); VectorCopy(curPos, ex->origin); VectorMA(ex->origin, -cVal, right, ex->origin); VectorMA(ex->origin, -sVal, up, ex->origin); ex->model = Mod_ForName("models/flamestr.spr", true); ex->startTime = cl.time + i*0.025; ex->endTime = ex->startTime + ex->model->numframes * 0.04; ex->scale = 100; VectorCopy(ent->angles, ex->angles); ex->angles[2] += 90; ex->flags |= DRF_TRANSLUCENT; VectorAdd(curPos, posAdd, curPos); } } */ void PowerFlameBurnRemove(explosion_t *ex) { explosion_t *ex2; vec3_t srcVec; ex2 = CL_AllocExplosion(); VectorCopy(ex->origin, ex2->origin); switch(rand()%3) { case 0: ex2->model = Mod_ForName("models/sm_expld.spr", true); break; case 1: ex2->model = Mod_ForName("models/fboom.spr", true); break; case 2: ex2->model = Mod_ForName("models/pow.spr", true); break; } ex2->startTime = cl.time; ex2->endTime = ex2->startTime + ex2->model->numframes * 0.05; ex2->scale = 100; ex2->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; ex2->abslight = 128; if(rand()&1)S_StartSound(TempSoundChannel(), 1, cl_sfx_flameend, ex2->origin, 1, 1); } void CL_UpdatePowerFlameBurn(entity_t *ent, int edict_num) { explosion_t *ex, *ex2; vec3_t srcVec; if((rand()%100)/100.0 < host_frametime * 10) { ex = CL_AllocExplosion(); VectorCopy(ent->origin, ex->origin); ex->origin[0] += (rand()%120)-60; ex->origin[1] += (rand()%120)-60; ex->origin[2] += (rand()%120)-60+120; ex->model = Mod_ForName("models/sucwp1p.mdl", true); ex->startTime = cl.time; ex->endTime = ex->startTime + .25; ex->removeFunc = PowerFlameBurnRemove; ex->scale = 100; VectorSubtract(ent->origin, ex->origin, srcVec); VectorCopy(srcVec, ex->velocity); ex->velocity[2] += 24; VectorScale(ex->velocity, 1.0 / .25, ex->velocity); VectorNormalize(srcVec); vectoangles(srcVec, ex->angles); ex->flags |= MLS_ABSLIGHT;//|DRF_TRANSLUCENT; ex->abslight = 128; // I'm not seeing this right now... (?) ex2 = CL_AllocExplosion(); VectorCopy(ex->origin, ex2->origin); ex2->model = Mod_ForName("models/flamestr.spr", true); ex2->startTime = cl.time; ex2->endTime = ex2->startTime + ex2->model->numframes * 0.05; ex2->flags |= DRF_TRANSLUCENT; } } void CL_UpdateHammer(entity_t *ent, int edict_num) { int testVal, testVal2; // do this every .3 seconds testVal = (int)(cl.time * 10.0); testVal2 = (int)((cl.time - host_frametime)*10.0); if(testVal != testVal2) { if(!(testVal%3)) { //S_StartSound(TempSoundChannel(), 1, cl_sfx_hammersound, ent->origin, 1, 1); S_StartSound(edict_num, 2, cl_sfx_hammersound, ent->origin, 1, 1); } } } void CL_UpdateBug(entity_t *ent) { int testVal, testVal2; testVal = (int)(cl.time * 10.0); testVal2 = (int)((cl.time - host_frametime)*10.0); if(testVal != testVal2) { // do this every .1 seconds // if(!(testVal%3)) // { S_StartSound(TempSoundChannel(), 1, cl_sfx_buzzbee, ent->origin, 1, 1); // } } } void CL_UpdateIceStorm(entity_t *ent, int edict_num) { vec3_t center, side1, tempVect, wishLoc; vec3_t side2 = {160, 160, 128}; stream_t *stream; float duration; model_t *models[2]; entity_state_t *state; int i; static float playIceSound = .6; int wasNew; state = FindState(edict_num); if (state) { VectorCopy(state->origin, center); // handle the particles VectorCopy(center, side1); side1[0] -= 80; side1[1] -= 80; side1[2] += 104; R_RainEffect2(side1, side2, rand()%400-200, rand()%400-200, rand()%15 + 9*16, (int)(30*20*host_frametime)); playIceSound+=host_frametime; if(playIceSound >= .6) { S_StartSound (TempSoundChannel(), 0, cl_sfx_icestorm, center, 1, 1); playIceSound -= .6; } } // toss little ice chunks if(rand()%100 < host_frametime * 100.0 * 3) { float final; explosion_t *ex; ex = CL_AllocExplosion(); VectorCopy(ent->origin,ex->origin); ex->origin[0] += rand()%32 - 16; ex->origin[1] += rand()%32 - 16; ex->origin[2] += 48 + rand()%32; ex->frameFunc = ChunkThink; ex->velocity[0] += (rand()%300)-150; ex->velocity[1] += (rand()%300)-150; ex->velocity[2] += (rand()%200)-50; // are these in degrees or radians? ex->angles[0] = rand()%360; ex->angles[1] = rand()%360; ex->angles[2] = rand()%360; ex->exflags = EXFLAG_ROTATE; ex->avel[0] = rand()%850 - 425; ex->avel[1] = rand()%850 - 425; ex->avel[2] = rand()%850 - 425; ex->scale = 65 + rand()%10; ex->data = THINGTYPE_ICE; ex->model = Mod_ForName("models/shard.mdl", true); ex->skin = 0; //ent->frame = rand()%2; ex->flags |= DRF_TRANSLUCENT|MLS_ABSLIGHT; ex->abslight = 128; ex->startTime = cl.time; ex->endTime = ex->startTime + 2.0; } } void telPuffMove (explosion_t *ex) { vec3_t tvec,tvec2; VectorSubtract(ex->angles, ex->origin, tvec); VectorCopy(tvec,tvec2); VectorNormalize(tvec); VectorScale(tvec,320,tvec); ex->velocity[0] = tvec[1]; ex->velocity[1] = -tvec[0]; ex->velocity[2] += FRANDOM(); if (ex->velocity[2] > 40) { ex->velocity[2] = 30; } //keep it from getting too spread out: ex->velocity[0] += tvec2[0]; ex->velocity[1] += tvec2[1]; R_RocketTrail (ex->oldorg, ex->origin, rt_magicmissile); // ex->accel[0] = ex->velocity[1]*5; // ex->accel[1] = -ex->velocity[0]*5; // ex->accel[2] += FRANDOM()*3.0; } void telEffectUpdate (explosion_t *ex) { explosion_t *ex2; float angle; int testVal, testVal2; vec3_t tvec; if (ex->endTime - cl.time <= 1.2) ex->frameFunc = NULL; testVal = (int)(cl.time * 10.0); testVal2 = (int)((cl.time - host_frametime)*10.0); if(testVal != testVal2) { if(!(testVal%3)) { ex2 = CL_AllocExplosion(); angle = FRANDOM() * 3.14159; VectorCopy(ex->origin,ex2->origin); VectorCopy(ex->origin,ex2->angles); ex2->origin[0]+=cos(angle)*10; ex2->origin[1]+=sin(angle)*10; VectorSubtract(ex->origin, ex2->origin, tvec); VectorScale(tvec,20,tvec); ex2->model = Mod_ForName("models/sm_blue.spr", true); ex2->startTime = cl.time; ex2->endTime = ex2->startTime + 3.2; ex2->scale = 100; ex2->data = 0; ex2->skin = 0; ex2->frameFunc = telPuffMove; ex2->velocity[0] = tvec[1]; ex2->velocity[1] = -tvec[0]; ex2->velocity[2] = 20.0; ex2->flags |= MLS_ABSLIGHT; ex2->abslight = 128; } } if (ex->endTime > cl.time + 0.01) { ex->startTime = cl.time+0.01; } } void CL_UpdateTargetBall(void) { int i; explosion_t *ex1 = NULL; explosion_t *ex2 = NULL; model_t *iceMod; vec3_t newOrg; float newScale; if (v_targDist < 24) { // either there is no ball, or it's too close to be needed... return; } // search for the two thingies. If they don't exist, make new ones and set v_oldTargOrg iceMod = Mod_ForName("models/iceshot2.mdl", true); for(i = 0; i < MAX_EXPLOSIONS; i++) { if(cl_explosions[i].endTime > cl.time) { // make certain it's an active one if(cl_explosions[i].model == iceMod) { if(cl_explosions[i].flags & DRF_TRANSLUCENT) { ex1 = &cl_explosions[i]; } else { ex2 = &cl_explosions[i]; } } } } VectorCopy(cl.simorg, newOrg); newOrg[0] += cos(v_targAngle*M_PI*2/256.0) * 50 * cos(v_targPitch*M_PI*2/256.0); newOrg[1] += sin(v_targAngle*M_PI*2/256.0) * 50 * cos(v_targPitch*M_PI*2/256.0); newOrg[2] += 44 + sin(v_targPitch*M_PI*2/256.0) * 50 + cos(cl.time*2)*5; if(v_targDist < 60) { // make it scale back down up close... newScale = 172 - (172 * (1.0 - (v_targDist - 24.0)/36.0)); } else { newScale = 80 + (120 * ((256.0 - v_targDist)/256.0)); } if(ex1 == NULL) { ex1 = CL_AllocExplosion(); ex1->model = iceMod; ex1->exflags |= EXFLAG_STILL_FRAME; ex1->data = 0; ex1->flags |= MLS_ABSLIGHT|DRF_TRANSLUCENT; ex1->skin = 0; VectorCopy(newOrg, ex1->origin); ex1->scale = newScale; } VectorScale(ex1->origin, (.75 - host_frametime * 1.5), ex1->origin); // FIXME this should be affected by frametime... VectorMA(ex1->origin, (.25 + host_frametime * 1.5), newOrg, ex1->origin); ex1->startTime = cl.time; ex1->endTime = ex1->startTime + host_frametime + 0.2; ex1->scale = (ex1->scale * (.75 - host_frametime * 1.5) + newScale * (.25 + host_frametime * 1.5)); ex1->angles[0] = v_targPitch*360/256.0; ex1->angles[1] = v_targAngle*360/256.0; ex1->angles[2] = cl.time * 240; ex1->abslight = 96 + (32 * cos(cl.time*6.5)) + (64 * ((256.0 - v_targDist)/256.0)); if(v_targDist < 60) { // make it scale back down up close... newScale = 76 - (76 * (1.0 - (v_targDist - 24.0)/36.0)); } else { newScale = 30 + (60 * ((256.0 - v_targDist)/256.0)); } if(ex2 == NULL) { ex2 = CL_AllocExplosion(); ex2->model = iceMod; ex2->exflags |= EXFLAG_STILL_FRAME; ex2->data = 0; ex2->flags |= MLS_ABSLIGHT; ex2->skin = 0; ex2->scale = newScale; } VectorCopy(ex1->origin, ex2->origin); ex2->startTime = cl.time; ex2->endTime = ex2->startTime + host_frametime + 0.2; ex2->scale = (ex2->scale * (.75 - host_frametime * 1.5) + newScale * (.25 + host_frametime * 1.5)); ex2->angles[0] = ex1->angles[0]; ex2->angles[1] = ex1->angles[1]; ex2->angles[2] = cl.time * -360; ex2->abslight = 96 + (128 * cos(cl.time*4.5)); R_TargetBallEffect (ex1->origin); } void SmokeRingFrameFunc(explosion_t *ex) { if(cl.time - ex->startTime < .3) { ex->skin = 0; } else if(cl.time - ex->startTime < .6) { ex->skin = 1; } else if(cl.time - ex->startTime < .9) { ex->skin = 2; } else { ex->skin = 3; } }