//************************************************************************** //** //** cl_effect.c //** //** Client side effects. //** //** $Header: /HexenWorld/Client/cl_effect.c 89 5/25/98 1:29p Mgummelt $ //** //************************************************************************** // HEADER FILES ------------------------------------------------------------ #include "quakedef.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- #define MAX_EFFECT_ENTITIES 256 // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- extern void CreateStream(int type, int ent, int flags, int tag, float duration, int skin, vec3_t source, vec3_t dest); extern void CLTENT_XbowImpact(vec3_t pos, vec3_t vel, int chType, int damage, int arrowType);//so xbow effect can use tents extern void CLTENT_SpawnDeathBubble(vec3_t pos); entity_state_t *FindState(int EntNum); int TempSoundChannel(); void setseed(unsigned int seed); float seedrand(void); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static int NewEffectEntity(void); static void FreeEffectEntity(int index); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- // PRIVATE DATA DEFINITIONS ------------------------------------------------ static entity_t EffectEntities[MAX_EFFECT_ENTITIES]; static qboolean EntityUsed[MAX_EFFECT_ENTITIES]; static int EffectEntityCount; // CODE -------------------------------------------------------------------- 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_InitTEnts // //========================================================================== sfx_t *cl_fxsfx_bone; sfx_t *cl_fxsfx_bonefpow; sfx_t *cl_fxsfx_xbowshoot; sfx_t *cl_fxsfx_xbowfshoot; sfx_t *cl_fxsfx_explode; sfx_t *cl_fxsfx_mmfire; sfx_t *cl_fxsfx_eidolon; sfx_t *cl_fxsfx_scarabwhoosh; sfx_t *cl_fxsfx_scarabgrab; sfx_t *cl_fxsfx_scarabhome; sfx_t *cl_fxsfx_scarabrip; sfx_t *cl_fxsfx_scarabbyebye; sfx_t *cl_fxsfx_ravensplit; sfx_t *cl_fxsfx_ravenfire; sfx_t *cl_fxsfx_ravengo; sfx_t *cl_fxsfx_drillashoot; sfx_t *cl_fxsfx_drillaspin; sfx_t *cl_fxsfx_drillameat; sfx_t *cl_fxsfx_arr2flsh; sfx_t *cl_fxsfx_arr2wood; sfx_t *cl_fxsfx_met2stn; sfx_t *cl_fxsfx_ripple; sfx_t *cl_fxsfx_splash; void CL_InitEffects(void) { cl_fxsfx_bone = S_PrecacheSound ("necro/bonefnrm.wav"); cl_fxsfx_bonefpow = S_PrecacheSound ("necro/bonefpow.wav"); cl_fxsfx_xbowshoot = S_PrecacheSound ("assassin/firebolt.wav"); cl_fxsfx_xbowfshoot = S_PrecacheSound ("assassin/firefblt.wav"); cl_fxsfx_explode = S_PrecacheSound ("weapons/explode.wav"); cl_fxsfx_mmfire = S_PrecacheSound ("necro/mmfire.wav"); cl_fxsfx_eidolon = S_PrecacheSound ("eidolon/spell.wav"); cl_fxsfx_scarabwhoosh = S_PrecacheSound ("misc/whoosh.wav"); cl_fxsfx_scarabgrab = S_PrecacheSound ("assassin/chn2flsh.wav"); cl_fxsfx_scarabhome = S_PrecacheSound ("assassin/chain.wav"); cl_fxsfx_scarabrip = S_PrecacheSound ("assassin/chntear.wav"); cl_fxsfx_scarabbyebye = S_PrecacheSound ("items/itmspawn.wav"); cl_fxsfx_ravensplit = S_PrecacheSound ("raven/split.wav"); cl_fxsfx_ravenfire = S_PrecacheSound ("raven/rfire1.wav"); cl_fxsfx_ravengo = S_PrecacheSound ("raven/ravengo.wav"); cl_fxsfx_drillashoot = S_PrecacheSound ("assassin/pincer.wav"); cl_fxsfx_drillaspin = S_PrecacheSound ("assassin/spin.wav"); cl_fxsfx_drillameat = S_PrecacheSound ("assassin/core.wav"); cl_fxsfx_arr2flsh = S_PrecacheSound ("assassin/arr2flsh.wav"); cl_fxsfx_arr2wood = S_PrecacheSound ("assassin/arr2wood.wav"); cl_fxsfx_met2stn = S_PrecacheSound ("weapons/met2stn.wav"); cl_fxsfx_ripple = S_PrecacheSound ("misc/drip.wav"); cl_fxsfx_splash = S_PrecacheSound ("raven/outwater.wav"); } void CL_ClearEffects(void) { memset(cl.Effects,0,sizeof(cl.Effects)); memset(EntityUsed,0,sizeof(EntityUsed)); EffectEntityCount = 0; } void CL_FreeEffect(int index) { int i; switch(cl.Effects[index].type) { case CE_RAIN: break; case CE_FOUNTAIN: break; case CE_QUAKE: break; case CE_TELESMK1: FreeEffectEntity(cl.Effects[index].Smoke.entity_index2); //no break wanted here case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_ACID_MUZZFL: case CE_FLAMESTREAM: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: FreeEffectEntity(cl.Effects[index].Smoke.entity_index); break; case CE_DEATHBUBBLES: break; // Just go through animation and then remove case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FBOOM: case CE_BOMB: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: FreeEffectEntity(cl.Effects[index].Smoke.entity_index); break; // Go forward then backward through animation then remove case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: FreeEffectEntity(cl.Effects[index].Flash.entity_index); break; case CE_RIDER_DEATH: break; case CE_TELEPORTERPUFFS: for (i=0;i<8;++i) FreeEffectEntity(cl.Effects[index].Teleporter.entity_index[i]); break; case CE_HWSHEEPINATOR: for (i=0;i<5;++i) FreeEffectEntity(cl.Effects[index].Xbow.ent[i]); break; case CE_HWXBOWSHOOT: for (i=0;iorigin); if ((cl.Effects[index].type == CE_WHITE_SMOKE) || (cl.Effects[index].type == CE_SLOW_WHITE_SMOKE)) ent->model = Mod_ForName("models/whtsmk1.spr", true); else if (cl.Effects[index].type == CE_GREEN_SMOKE) ent->model = Mod_ForName("models/grnsmk1.spr", true); else if (cl.Effects[index].type == CE_GREY_SMOKE) ent->model = Mod_ForName("models/grysmk1.spr", true); else if (cl.Effects[index].type == CE_RED_SMOKE) ent->model = Mod_ForName("models/redsmk1.spr", true); else if (cl.Effects[index].type == CE_TELESMK1) ent->model = Mod_ForName("models/telesmk1.spr", true); else if (cl.Effects[index].type == CE_TELESMK2) ent->model = Mod_ForName("models/telesmk2.spr", true); else if (cl.Effects[index].type == CE_REDCLOUD) ent->model = Mod_ForName("models/rcloud.spr", true); else if (cl.Effects[index].type == CE_FLAMESTREAM) ent->model = Mod_ForName("models/flamestr.spr", true); else if (cl.Effects[index].type == CE_ACID_MUZZFL) { ent->model = Mod_ForName("models/muzzle1.spr", true); ent->drawflags=DRF_TRANSLUCENT|MLS_ABSLIGHT; ent->abslight=0.2; } else if (cl.Effects[index].type == CE_FLAMEWALL) ent->model = Mod_ForName("models/firewal1.spr", true); else if (cl.Effects[index].type == CE_FLAMEWALL2) ent->model = Mod_ForName("models/firewal2.spr", true); else if (cl.Effects[index].type == CE_ONFIRE) { float rdm = rand() & 3; if (rdm < 1) ent->model = Mod_ForName("models/firewal1.spr", true); else if (rdm < 2) ent->model = Mod_ForName("models/firewal2.spr", true); else ent->model = Mod_ForName("models/firewal3.spr", true); ent->drawflags = DRF_TRANSLUCENT; ent->abslight = 1; ent->frame = cl.Effects[index].Smoke.frame; } else if (cl.Effects[index].type == CE_RIPPLE) { if(cl.Effects[index].Smoke.framelength==2) { R_SplashParticleEffect (cl.Effects[index].Smoke.origin, 200, 406+rand()%8, pt_slowgrav, 40);//splash S_StartSound (TempSoundChannel(), 1, cl_fxsfx_splash, cl.Effects[index].Smoke.origin, 1, 1); } else if(cl.Effects[index].Smoke.framelength==1) R_SplashParticleEffect (cl.Effects[index].Smoke.origin, 100, 406+rand()%8, pt_slowgrav, 20);//splash else S_StartSound (TempSoundChannel(), 1, cl_fxsfx_ripple, cl.Effects[index].Smoke.origin, 1, 1); cl.Effects[index].Smoke.framelength=0.05; ent->model = Mod_ForName("models/ripple.spr", true); ent->drawflags = DRF_TRANSLUCENT;//|SCALE_TYPE_XYONLY|SCALE_ORIGIN_CENTER; ent->angles[0]=90; //ent->scale = 1; } else { ImmediateFree = true; Con_Printf ("Bad effect type %d\n",(int)cl.Effects[index].type); } if (cl.Effects[index].type != CE_REDCLOUD&&cl.Effects[index].type != CE_ACID_MUZZFL&&cl.Effects[index].type != CE_FLAMEWALL&&cl.Effects[index].type != CE_RIPPLE) ent->drawflags = DRF_TRANSLUCENT; if (cl.Effects[index].type == CE_FLAMESTREAM) { ent->drawflags = DRF_TRANSLUCENT | MLS_ABSLIGHT; ent->abslight = 1; ent->frame = cl.Effects[index].Smoke.frame; } if (cl.Effects[index].type == CE_GHOST) { ent->model = Mod_ForName("models/ghost.spr", true); ent->drawflags = DRF_TRANSLUCENT | MLS_ABSLIGHT; ent->abslight = .5; } if (cl.Effects[index].type == CE_TELESMK1) { S_StartSound (TempSoundChannel(), 1, cl_fxsfx_ravenfire, cl.Effects[index].Smoke.origin, 1, 1); if ((cl.Effects[index].Smoke.entity_index2 = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Smoke.entity_index2]; VectorCopy(cl.Effects[index].Smoke.origin, ent->origin); ent->model = Mod_ForName("models/telesmk1.spr", true); ent->drawflags = DRF_TRANSLUCENT; } } } else ImmediateFree = true; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FBOOM: case CE_BOMB: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: cl.Effects[index].Smoke.origin[0] = MSG_ReadCoord (); cl.Effects[index].Smoke.origin[1] = MSG_ReadCoord (); cl.Effects[index].Smoke.origin[2] = MSG_ReadCoord (); if ((cl.Effects[index].Smoke.entity_index = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Smoke.entity_index]; VectorCopy(cl.Effects[index].Smoke.origin, ent->origin); if (cl.Effects[index].type == CE_BLUESPARK) ent->model = Mod_ForName("models/bspark.spr", true); else if (cl.Effects[index].type == CE_YELLOWSPARK) ent->model = Mod_ForName("models/spark.spr", true); else if (cl.Effects[index].type == CE_SM_CIRCLE_EXP) ent->model = Mod_ForName("models/fcircle.spr", true); else if (cl.Effects[index].type == CE_BG_CIRCLE_EXP) ent->model = Mod_ForName("models/xplod29.spr", true); else if (cl.Effects[index].type == CE_SM_WHITE_FLASH) ent->model = Mod_ForName("models/sm_white.spr", true); else if (cl.Effects[index].type == CE_YELLOWRED_FLASH) { ent->model = Mod_ForName("models/yr_flsh.spr", true); ent->drawflags = DRF_TRANSLUCENT; } else if (cl.Effects[index].type == CE_SM_EXPLOSION) ent->model = Mod_ForName("models/sm_expld.spr", true); else if (cl.Effects[index].type == CE_SM_EXPLOSION2) { ent->model = Mod_ForName("models/sm_expld.spr", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_explode, cl.Effects[index].Smoke.origin, 1, 1); } else if (cl.Effects[index].type == CE_BG_EXPLOSION) { ent->model = Mod_ForName("models/bg_expld.spr", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_explode, cl.Effects[index].Smoke.origin, 1, 1); } else if (cl.Effects[index].type == CE_FLOOR_EXPLOSION) ent->model = Mod_ForName("models/fl_expld.spr", true); else if (cl.Effects[index].type == CE_BLUE_EXPLOSION) ent->model = Mod_ForName("models/xpspblue.spr", true); else if (cl.Effects[index].type == CE_REDSPARK) ent->model = Mod_ForName("models/rspark.spr", true); else if (cl.Effects[index].type == CE_GREENSPARK) ent->model = Mod_ForName("models/gspark.spr", true); else if (cl.Effects[index].type == CE_ICEHIT) ent->model = Mod_ForName("models/icehit.spr", true); else if (cl.Effects[index].type == CE_MEDUSA_HIT) ent->model = Mod_ForName("models/medhit.spr", true); else if (cl.Effects[index].type == CE_MEZZO_REFLECT) ent->model = Mod_ForName("models/mezzoref.spr", true); else if (cl.Effects[index].type == CE_FLOOR_EXPLOSION2) ent->model = Mod_ForName("models/flrexpl2.spr", true); else if (cl.Effects[index].type == CE_XBOW_EXPLOSION) ent->model = Mod_ForName("models/xbowexpl.spr", true); else if (cl.Effects[index].type == CE_NEW_EXPLOSION) ent->model = Mod_ForName("models/gen_expl.spr", true); else if (cl.Effects[index].type == CE_MAGIC_MISSILE_EXPLOSION) { ent->model = Mod_ForName("models/mm_expld.spr", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_explode, cl.Effects[index].Smoke.origin, 1, 1); } else if (cl.Effects[index].type == CE_BONE_EXPLOSION) ent->model = Mod_ForName("models/bonexpld.spr", true); else if (cl.Effects[index].type == CE_BLDRN_EXPL) ent->model = Mod_ForName("models/xplsn_1.spr", true); else if (cl.Effects[index].type == CE_ACID_HIT) ent->model = Mod_ForName("models/axplsn_2.spr", true); else if (cl.Effects[index].type == CE_ACID_SPLAT) ent->model = Mod_ForName("models/axplsn_1.spr", true); else if (cl.Effects[index].type == CE_ACID_EXPL) { ent->model = Mod_ForName("models/axplsn_5.spr", true); ent->drawflags = MLS_ABSLIGHT; ent->abslight = 1; } else if (cl.Effects[index].type == CE_FBOOM) ent->model = Mod_ForName("models/fboom.spr", true); else if (cl.Effects[index].type == CE_BOMB) ent->model = Mod_ForName("models/pow.spr", true); else if (cl.Effects[index].type == CE_LBALL_EXPL) ent->model = Mod_ForName("models/Bluexp3.spr", true); else if (cl.Effects[index].type == CE_FIREWALL_SMALL) ent->model = Mod_ForName("models/firewal1.spr", true); else if (cl.Effects[index].type == CE_FIREWALL_MEDIUM) ent->model = Mod_ForName("models/firewal5.spr", true); else if (cl.Effects[index].type == CE_FIREWALL_LARGE) ent->model = Mod_ForName("models/firewal4.spr", true); else if (cl.Effects[index].type == CE_BRN_BOUNCE) ent->model = Mod_ForName("models/spark.spr", true); else if (cl.Effects[index].type == CE_LSHOCK) { ent->model = Mod_ForName("models/vorpshok.mdl", true); ent->drawflags=MLS_TORCH; ent->angles[2]=90; ent->scale=255; } } else { ImmediateFree = true; } break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: cl.Effects[index].Flash.origin[0] = MSG_ReadCoord (); cl.Effects[index].Flash.origin[1] = MSG_ReadCoord (); cl.Effects[index].Flash.origin[2] = MSG_ReadCoord (); cl.Effects[index].Flash.reverse = 0; if ((cl.Effects[index].Flash.entity_index = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Flash.entity_index]; VectorCopy(cl.Effects[index].Flash.origin, ent->origin); if (cl.Effects[index].type == CE_WHITE_FLASH) ent->model = Mod_ForName("models/gryspt.spr", true); else if (cl.Effects[index].type == CE_BLUE_FLASH) ent->model = Mod_ForName("models/bluflash.spr", true); else if (cl.Effects[index].type == CE_SM_BLUE_FLASH) ent->model = Mod_ForName("models/sm_blue.spr", true); else if (cl.Effects[index].type == CE_RED_FLASH) ent->model = Mod_ForName("models/redspt.spr", true); else if (cl.Effects[index].type == CE_HWSPLITFLASH) { ent->model = Mod_ForName("models/sm_blue.spr", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_ravensplit, cl.Effects[index].Flash.origin, 1, 1); } ent->drawflags = DRF_TRANSLUCENT; } else { ImmediateFree = true; } break; case CE_RIDER_DEATH: cl.Effects[index].RD.origin[0] = MSG_ReadCoord (); cl.Effects[index].RD.origin[1] = MSG_ReadCoord (); cl.Effects[index].RD.origin[2] = MSG_ReadCoord (); break; case CE_TELEPORTERPUFFS: cl.Effects[index].Teleporter.origin[0] = MSG_ReadCoord (); cl.Effects[index].Teleporter.origin[1] = MSG_ReadCoord (); cl.Effects[index].Teleporter.origin[2] = MSG_ReadCoord (); cl.Effects[index].Teleporter.framelength = .05; dir = 0; for (i=0;i<8;++i) { if ((cl.Effects[index].Teleporter.entity_index[i] = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Teleporter.entity_index[i]]; VectorCopy(cl.Effects[index].Teleporter.origin, ent->origin); angleval = dir * M_PI*2 / 360; sinval = sin(angleval); cosval = cos(angleval); cl.Effects[index].Teleporter.velocity[i][0] = 10*cosval; cl.Effects[index].Teleporter.velocity[i][1] = 10*sinval; cl.Effects[index].Teleporter.velocity[i][2] = 0; dir += 45; ent->model = Mod_ForName("models/telesmk2.spr", true); ent->drawflags = DRF_TRANSLUCENT; } } break; case CE_TELEPORTERBODY: cl.Effects[index].Teleporter.origin[0] = MSG_ReadCoord (); cl.Effects[index].Teleporter.origin[1] = MSG_ReadCoord (); cl.Effects[index].Teleporter.origin[2] = MSG_ReadCoord (); cl.Effects[index].Teleporter.velocity[0][0] = MSG_ReadFloat (); cl.Effects[index].Teleporter.velocity[0][1] = MSG_ReadFloat (); cl.Effects[index].Teleporter.velocity[0][2] = MSG_ReadFloat (); skinnum = MSG_ReadFloat (); cl.Effects[index].Teleporter.framelength = .05; dir = 0; if ((cl.Effects[index].Teleporter.entity_index[0] = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Teleporter.entity_index[0]]; VectorCopy(cl.Effects[index].Teleporter.origin, ent->origin); ent->model = Mod_ForName("models/teleport.mdl", true); ent->drawflags = SCALE_TYPE_XYONLY | DRF_TRANSLUCENT; ent->scale = 100; ent->skinnum = skinnum; } break; case CE_BONESHRAPNEL: case CE_HWBONEBALL: cl.Effects[index].Missile.origin[0] = MSG_ReadCoord (); cl.Effects[index].Missile.origin[1] = MSG_ReadCoord (); cl.Effects[index].Missile.origin[2] = MSG_ReadCoord (); cl.Effects[index].Missile.velocity[0] = MSG_ReadFloat (); cl.Effects[index].Missile.velocity[1] = MSG_ReadFloat (); cl.Effects[index].Missile.velocity[2] = MSG_ReadFloat (); cl.Effects[index].Missile.angle[0] = MSG_ReadFloat (); cl.Effects[index].Missile.angle[1] = MSG_ReadFloat (); cl.Effects[index].Missile.angle[2] = MSG_ReadFloat (); cl.Effects[index].Missile.avelocity[0] = MSG_ReadFloat (); cl.Effects[index].Missile.avelocity[1] = MSG_ReadFloat (); cl.Effects[index].Missile.avelocity[2] = MSG_ReadFloat (); if ((cl.Effects[index].Missile.entity_index = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; VectorCopy(cl.Effects[index].Missile.origin, ent->origin); VectorCopy(cl.Effects[index].Missile.angle, ent->angles); if (cl.Effects[index].type == CE_BONESHRAPNEL) ent->model = Mod_ForName("models/boneshrd.mdl", true); else if (cl.Effects[index].type == CE_HWBONEBALL) { ent->model = Mod_ForName("models/bonelump.mdl", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_bonefpow, cl.Effects[index].Missile.origin, 1, 1); } } else ImmediateFree = true; break; case CE_BONESHARD: case CE_HWRAVENSTAFF: case CE_HWRAVENPOWER: cl.Effects[index].Missile.origin[0] = MSG_ReadCoord (); cl.Effects[index].Missile.origin[1] = MSG_ReadCoord (); cl.Effects[index].Missile.origin[2] = MSG_ReadCoord (); cl.Effects[index].Missile.velocity[0] = MSG_ReadFloat (); cl.Effects[index].Missile.velocity[1] = MSG_ReadFloat (); cl.Effects[index].Missile.velocity[2] = MSG_ReadFloat (); vectoangles(cl.Effects[index].Missile.velocity, cl.Effects[index].Missile.angle); if ((cl.Effects[index].Missile.entity_index = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; VectorCopy(cl.Effects[index].Missile.origin, ent->origin); VectorCopy(cl.Effects[index].Missile.angle, ent->angles); if (cl.Effects[index].type == CE_HWRAVENSTAFF) { cl.Effects[index].Missile.avelocity[2] = 1000; ent->model = Mod_ForName("models/vindsht1.mdl", true); } else if (cl.Effects[index].type == CE_BONESHARD) { cl.Effects[index].Missile.avelocity[0] = (rand() % 1554) - 777; ent->model = Mod_ForName("models/boneshot.mdl", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_bone, cl.Effects[index].Missile.origin, 1, 1); } else if (cl.Effects[index].type == CE_HWRAVENPOWER) { ent->model = Mod_ForName("models/ravproj.mdl", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_ravengo, cl.Effects[index].Missile.origin, 1, 1); } } else ImmediateFree = true; break; case CE_DEATHBUBBLES: cl.Effects[index].Bubble.owner = MSG_ReadShort(); cl.Effects[index].Bubble.offset[0] = MSG_ReadByte(); cl.Effects[index].Bubble.offset[1] = MSG_ReadByte(); cl.Effects[index].Bubble.offset[2] = MSG_ReadByte(); cl.Effects[index].Bubble.count = MSG_ReadByte();//num of bubbles cl.Effects[index].Bubble.time_amount = 0; break; case CE_HWXBOWSHOOT: origin[0] = MSG_ReadCoord (); origin[1] = MSG_ReadCoord (); origin[2] = MSG_ReadCoord (); cl.Effects[index].Xbow.angle[0] = MSG_ReadAngle (); cl.Effects[index].Xbow.angle[1] = MSG_ReadAngle (); cl.Effects[index].Xbow.angle[2] = 0;//MSG_ReadFloat (); cl.Effects[index].Xbow.bolts = MSG_ReadByte(); cl.Effects[index].Xbow.randseed = MSG_ReadByte(); cl.Effects[index].Xbow.turnedbolts = MSG_ReadByte(); cl.Effects[index].Xbow.activebolts= MSG_ReadByte(); setseed(cl.Effects[index].Xbow.randseed); AngleVectors (cl.Effects[index].Xbow.angle, forward, right, up); VectorNormalize(forward); VectorCopy(forward, cl.Effects[index].Xbow.velocity); // VectorScale(forward, 1000, cl.Effects[index].Xbow.velocity); if (cl.Effects[index].Xbow.bolts == 3) { S_StartSound (TempSoundChannel(), 1, cl_fxsfx_xbowshoot, origin, 1, 1); } else if (cl.Effects[index].Xbow.bolts == 5) { S_StartSound (TempSoundChannel(), 1, cl_fxsfx_xbowfshoot, origin, 1, 1); } for (i=0;iorigin); vectoangles(cl.Effects[index].Xbow.vel[i],ent->angles); if (cl.Effects[index].Xbow.bolts == 5) ent->model = Mod_ForName("models/flaming.mdl", true); else ent->model = Mod_ForName("models/arrow.mdl", true); } } break; case CE_HWSHEEPINATOR: origin[0] = MSG_ReadCoord (); origin[1] = MSG_ReadCoord (); origin[2] = MSG_ReadCoord (); cl.Effects[index].Xbow.angle[0] = MSG_ReadAngle (); cl.Effects[index].Xbow.angle[1] = MSG_ReadAngle (); cl.Effects[index].Xbow.angle[2] = 0;//MSG_ReadFloat (); cl.Effects[index].Xbow.turnedbolts = MSG_ReadByte(); cl.Effects[index].Xbow.activebolts= MSG_ReadByte(); cl.Effects[index].Xbow.bolts = 5; cl.Effects[index].Xbow.randseed = 0; AngleVectors (cl.Effects[index].Xbow.angle, forward, right, up); VectorNormalize(forward); VectorCopy(forward, cl.Effects[index].Xbow.velocity); // S_StartSound (TempSoundChannel(), 1, cl_fxsfx_xbowshoot, origin, 1, 1); for (i=0;iorigin); vectoangles(cl.Effects[index].Xbow.vel[i],ent->angles); ent->model = Mod_ForName("models/polymrph.spr", true); } } break; case CE_HWDRILLA: cl.Effects[index].Missile.origin[0] = MSG_ReadCoord (); cl.Effects[index].Missile.origin[1] = MSG_ReadCoord (); cl.Effects[index].Missile.origin[2] = MSG_ReadCoord (); cl.Effects[index].Missile.angle[0] = MSG_ReadAngle (); cl.Effects[index].Missile.angle[1] = MSG_ReadAngle (); cl.Effects[index].Missile.angle[2] = 0; cl.Effects[index].Missile.speed = MSG_ReadShort(); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_drillashoot, cl.Effects[index].Missile.origin, 1, 1); AngleVectors(cl.Effects[index].Missile.angle,cl.Effects[index].Missile.velocity,right,up); VectorScale(cl.Effects[index].Missile.velocity,cl.Effects[index].Missile.speed,cl.Effects[index].Missile.velocity); if ((cl.Effects[index].Missile.entity_index = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; VectorCopy(cl.Effects[index].Missile.origin, ent->origin); VectorCopy(cl.Effects[index].Missile.angle, ent->angles); ent->model = Mod_ForName("models/scrbstp1.mdl", true); } else ImmediateFree = true; break; case CE_SCARABCHAIN: cl.Effects[index].Chain.origin[0] = MSG_ReadCoord (); cl.Effects[index].Chain.origin[1] = MSG_ReadCoord (); cl.Effects[index].Chain.origin[2] = MSG_ReadCoord (); cl.Effects[index].Chain.owner = MSG_ReadShort (); cl.Effects[index].Chain.tag = MSG_ReadByte(); cl.Effects[index].Chain.material = cl.Effects[index].Chain.owner>>12; cl.Effects[index].Chain.owner &= 0x0fff; cl.Effects[index].Chain.height = 16;//MSG_ReadByte (); cl.Effects[index].Chain.sound_time = cl.time; cl.Effects[index].Chain.state = 0;//state 0: move slowly toward owner S_StartSound (TempSoundChannel(), 1, cl_fxsfx_scarabwhoosh, cl.Effects[index].Chain.origin, 1, 1); if ((cl.Effects[index].Chain.ent1 = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Chain.ent1]; VectorCopy(cl.Effects[index].Chain.origin, ent->origin); ent->model = Mod_ForName("models/scrbpbdy.mdl", true); } else ImmediateFree = true; break; case CE_TRIPMINE: cl.Effects[index].Chain.origin[0] = MSG_ReadCoord (); cl.Effects[index].Chain.origin[1] = MSG_ReadCoord (); cl.Effects[index].Chain.origin[2] = MSG_ReadCoord (); cl.Effects[index].Chain.velocity[0] = MSG_ReadFloat (); cl.Effects[index].Chain.velocity[1] = MSG_ReadFloat (); cl.Effects[index].Chain.velocity[2] = MSG_ReadFloat (); if ((cl.Effects[index].Chain.ent1 = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Chain.ent1]; VectorCopy(cl.Effects[index].Chain.origin, ent->origin); ent->model = Mod_ForName("models/twspike.mdl", true); } else ImmediateFree = true; break; case CE_TRIPMINESTILL: // Con_DPrintf("Allocating chain effect...\n"); cl.Effects[index].Chain.origin[0] = MSG_ReadCoord (); cl.Effects[index].Chain.origin[1] = MSG_ReadCoord (); cl.Effects[index].Chain.origin[2] = MSG_ReadCoord (); cl.Effects[index].Chain.velocity[0] = MSG_ReadFloat (); cl.Effects[index].Chain.velocity[1] = MSG_ReadFloat (); cl.Effects[index].Chain.velocity[2] = MSG_ReadFloat (); if ((cl.Effects[index].Chain.ent1 = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Chain.ent1]; VectorCopy(cl.Effects[index].Chain.velocity, ent->origin); ent->model = Mod_ForName("models/twspike.mdl", true); } else { // Con_DPrintf("ERROR: Couldn't allocate chain effect!\n"); ImmediateFree = true; } break; case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: cl.Effects[index].Star.origin[0] = MSG_ReadCoord (); cl.Effects[index].Star.origin[1] = MSG_ReadCoord (); cl.Effects[index].Star.origin[2] = MSG_ReadCoord (); cl.Effects[index].Star.velocity[0] = MSG_ReadFloat (); cl.Effects[index].Star.velocity[1] = MSG_ReadFloat (); cl.Effects[index].Star.velocity[2] = MSG_ReadFloat (); vectoangles(cl.Effects[index].Star.velocity, cl.Effects[index].Star.angle); cl.Effects[index].Missile.avelocity[2] = 300 + rand()%300; if ((cl.Effects[index].Star.entity_index = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Star.entity_index]; VectorCopy(cl.Effects[index].Star.origin, ent->origin); VectorCopy(cl.Effects[index].Star.angle, ent->angles); ent->model = Mod_ForName("models/ball.mdl", true); } else ImmediateFree = true; cl.Effects[index].Star.scaleDir = 1; cl.Effects[index].Star.scale = 0.3; if ((cl.Effects[index].Star.ent1 = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Star.ent1]; VectorCopy(cl.Effects[index].Star.origin, ent->origin); ent->drawflags |= MLS_ABSLIGHT; ent->abslight = 0.5; ent->angles[2] = 90; if(cl.Effects[index].type == CE_HWMISSILESTAR) { ent->model = Mod_ForName("models/star.mdl", true); ent->scale = 0.3; S_StartSound (TempSoundChannel(), 1, cl_fxsfx_mmfire, ent->origin, 1, 1); } else { ent->model = Mod_ForName("models/glowball.mdl", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_eidolon, ent->origin, 1, 1); } } if(cl.Effects[index].type == CE_HWMISSILESTAR) { if ((cl.Effects[index].Star.ent2 = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Star.ent2]; VectorCopy(cl.Effects[index].Star.origin, ent->origin); ent->model = Mod_ForName("models/star.mdl", true); ent->drawflags |= MLS_ABSLIGHT; ent->abslight = 0.5; ent->scale = 0.3; } } break; default: Sys_Error ("CL_ParseEffect: bad type"); } if (ImmediateFree) { cl.Effects[index].type = CE_NONE; } } // these are in cl_tent.c void CreateRavenDeath(vec3_t pos); void CreateExplosionWithSound(vec3_t pos); void CL_EndEffect(void) { int index; entity_t *ent; index = MSG_ReadByte(); switch(cl.Effects[index].type ) { case CE_HWRAVENPOWER: if(cl.Effects[index].Missile.entity_index > -1) { ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; CreateRavenDeath(ent->origin); } break; case CE_HWRAVENSTAFF: if(cl.Effects[index].Missile.entity_index > -1) { ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; CreateExplosionWithSound(ent->origin); } break; } CL_FreeEffect(index); } void XbowImpactPuff(vec3_t origin, int material)//hopefully can use this with xbow & chain both { int part_color; switch(material) { case XBOW_IMPACT_REDFLESH: part_color = 256 + 8 * 16 + rand()%9; //Blood red break; case XBOW_IMPACT_STONE: part_color = 256 + 20 + rand()%8; // Gray break; case XBOW_IMPACT_METAL: part_color = 256 + (8 * 15); // Sparks break; case XBOW_IMPACT_WOOD: part_color = 256 + (5 * 16) + rand()%8; // Wood chunks break; case XBOW_IMPACT_ICE: part_color = 406+rand()%8; // Ice particles break; case XBOW_IMPACT_GREENFLESH: part_color = 256 + 183 + rand()%8; // Spider's have green blood break; default: part_color = 256 + (3 * 16) + 4; // Dust Brown break; } R_RunParticleEffect4 (origin, 24, part_color, pt_fastgrav, 20); } void CL_ReviseEffect(void) // be sure to read, in the switch statement, everything // in this message, even if the effect is not the right kind or invalid, // or else client is sure to crash. { int index,type,revisionCode; int curEnt,material,takedamage; entity_t *ent; vec3_t forward,right,up,pos; float dist,speed; entity_state_t *es; index = MSG_ReadByte (); type = MSG_ReadByte (); if (cl.Effects[index].type==type) switch(type) { case CE_SCARABCHAIN://attach to new guy or retract if new guy is world curEnt = MSG_ReadShort(); if (cl.Effects[index].type==type) { cl.Effects[index].Chain.material = curEnt>>12; curEnt &= 0x0fff; if (curEnt) { cl.Effects[index].Chain.state = 1; cl.Effects[index].Chain.owner = curEnt; es = FindState(cl.Effects[index].Chain.owner); if (es) { ent = &EffectEntities[cl.Effects[index].Chain.ent1]; XbowImpactPuff(ent->origin, cl.Effects[index].Chain.material); } } else cl.Effects[index].Chain.state = 2; } break; case CE_HWXBOWSHOOT: revisionCode = MSG_ReadByte(); //this is one packed byte! //highest bit: for impact revision, indicates whether damage is done // for redirect revision, indicates whether new origin was sent //next 3 high bits: for all revisions, indicates which bolt is to be revised //highest 3 of the low 4 bits: for impact revision, indicates the material that was hit //lowest bit: indicates whether revision is of impact or redirect variety curEnt = (revisionCode>>4)&7; if (revisionCode & 1)//impact effect: { cl.Effects[index].Xbow.activebolts &= ~(1<origin); material = (revisionCode & 14); takedamage = (revisionCode & 128); if (takedamage) { cl.Effects[index].Xbow.gonetime[curEnt] = cl.time; } else { cl.Effects[index].Xbow.gonetime[curEnt] += cl.time; } VectorCopy(cl.Effects[index].Xbow.vel[curEnt],forward); VectorNormalize(forward); VectorScale(forward,8,forward); // do a particle effect here, with the color depending on chType XbowImpactPuff(ent->origin,material); // impact sound: switch (material) { case XBOW_IMPACT_GREENFLESH: case XBOW_IMPACT_REDFLESH: case XBOW_IMPACT_MUMMY: S_StartSound (TempSoundChannel(), 0, cl_fxsfx_arr2flsh, ent->origin, 1, 1); break; case XBOW_IMPACT_WOOD: S_StartSound (TempSoundChannel(), 0, cl_fxsfx_arr2wood, ent->origin, 1, 1); break; default: S_StartSound (TempSoundChannel(), 0, cl_fxsfx_met2stn, ent->origin, 1, 1); break; } CLTENT_XbowImpact(ent->origin, forward, material, takedamage, cl.Effects[index].Xbow.bolts); } } else { if (cl.Effects[index].Xbow.ent[curEnt]!=-1) { ent = &EffectEntities[cl.Effects[index].Xbow.ent[curEnt]]; ent->angles[0] = MSG_ReadAngle(); if (ent->angles[0] < 0) ent->angles[0] += 360; ent->angles[0]*=-1; ent->angles[1] = MSG_ReadAngle(); if (ent->angles[1] < 0) ent->angles[1] += 360; ent->angles[2] = 0; if (revisionCode &128)//new origin { cl.Effects[index].Xbow.origin[curEnt][0]=MSG_ReadCoord(); cl.Effects[index].Xbow.origin[curEnt][1]=MSG_ReadCoord(); cl.Effects[index].Xbow.origin[curEnt][2]=MSG_ReadCoord(); } AngleVectors(ent->angles,forward,right,up); speed = Length(cl.Effects[index].Xbow.vel[curEnt]); VectorScale(forward,speed,cl.Effects[index].Xbow.vel[curEnt]); VectorCopy(cl.Effects[index].Xbow.origin[curEnt],ent->origin); } else { pos[0] = MSG_ReadAngle(); if (pos[0] < 0) pos[0] += 360; pos[0]*=-1; pos[1] = MSG_ReadAngle(); if (pos[1] < 0) pos[1] += 360; pos[2] = 0; if (revisionCode &128)//new origin { cl.Effects[index].Xbow.origin[curEnt][0]=MSG_ReadCoord(); cl.Effects[index].Xbow.origin[curEnt][1]=MSG_ReadCoord(); cl.Effects[index].Xbow.origin[curEnt][2]=MSG_ReadCoord(); } AngleVectors(pos,forward,right,up); speed = Length(cl.Effects[index].Xbow.vel[curEnt]); VectorScale(forward,speed,cl.Effects[index].Xbow.vel[curEnt]); } } break; case CE_HWSHEEPINATOR: revisionCode = MSG_ReadByte(); curEnt = (revisionCode>>4)&7; if (revisionCode & 1)//impact { dist = MSG_ReadCoord(); cl.Effects[index].Xbow.activebolts &= ~(1<origin); R_ColoredParticleExplosion(ent->origin,(rand()%16)+144/*(144,159)*/,20,30); } } else//direction change { if (cl.Effects[index].Xbow.ent[curEnt] != -1) { ent = &EffectEntities[cl.Effects[index].Xbow.ent[curEnt]]; ent->angles[0] = MSG_ReadAngle(); if (ent->angles[0] < 0) ent->angles[0] += 360; ent->angles[0]*=-1; ent->angles[1] = MSG_ReadAngle(); if (ent->angles[1] < 0) ent->angles[1] += 360; ent->angles[2] = 0; if (revisionCode &128)//new origin { cl.Effects[index].Xbow.origin[curEnt][0]=MSG_ReadCoord(); cl.Effects[index].Xbow.origin[curEnt][1]=MSG_ReadCoord(); cl.Effects[index].Xbow.origin[curEnt][2]=MSG_ReadCoord(); } AngleVectors(ent->angles,forward,right,up); speed = Length(cl.Effects[index].Xbow.vel[curEnt]); VectorScale(forward,speed,cl.Effects[index].Xbow.vel[curEnt]); VectorCopy(cl.Effects[index].Xbow.origin[curEnt],ent->origin); } else { pos[0] = MSG_ReadAngle(); if (pos[0] < 0) pos[0] += 360; pos[0]*=-1; pos[1] = MSG_ReadAngle(); if (pos[1] < 0) pos[1] += 360; pos[2] = 0; if (revisionCode &128)//new origin { cl.Effects[index].Xbow.origin[curEnt][0]=MSG_ReadCoord(); cl.Effects[index].Xbow.origin[curEnt][1]=MSG_ReadCoord(); cl.Effects[index].Xbow.origin[curEnt][2]=MSG_ReadCoord(); } AngleVectors(pos,forward,right,up); speed = Length(cl.Effects[index].Xbow.vel[curEnt]); VectorScale(forward,speed,cl.Effects[index].Xbow.vel[curEnt]); } } break; case CE_HWDRILLA: revisionCode = MSG_ReadByte(); if (revisionCode == 0)//impact { pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); material = MSG_ReadByte(); //throw lil bits of victim at entry XbowImpactPuff(pos,material); if ((material == XBOW_IMPACT_GREENFLESH) || (material == XBOW_IMPACT_GREENFLESH)) {//meaty sound and some chunks too S_StartSound (TempSoundChannel(), 0, cl_fxsfx_drillameat, pos, 1, 1); //todo: the chunks } //lil bits at exit VectorCopy(cl.Effects[index].Missile.velocity,forward); VectorNormalize(forward); VectorScale(forward,36,forward); VectorAdd(forward,pos,pos); XbowImpactPuff(pos,material); } else//turn { if (cl.Effects[index].Missile.entity_index!=-1) { ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; ent->angles[0] = MSG_ReadAngle(); if (ent->angles[0] < 0) ent->angles[0] += 360; ent->angles[0]*=-1; ent->angles[1] = MSG_ReadAngle(); if (ent->angles[1] < 0) ent->angles[1] += 360; ent->angles[2] = 0; cl.Effects[index].Missile.origin[0]=MSG_ReadCoord(); cl.Effects[index].Missile.origin[1]=MSG_ReadCoord(); cl.Effects[index].Missile.origin[2]=MSG_ReadCoord(); AngleVectors(ent->angles,forward,right,up); speed = Length(cl.Effects[index].Missile.velocity); VectorScale(forward,speed,cl.Effects[index].Missile.velocity); VectorCopy(cl.Effects[index].Missile.origin,ent->origin); } else { pos[0] = MSG_ReadAngle(); if (pos[0] < 0) pos[0] += 360; pos[0]*=-1; pos[1] = MSG_ReadAngle(); if (pos[1] < 0) pos[1] += 360; pos[2] = 0; cl.Effects[index].Missile.origin[0]=MSG_ReadCoord(); cl.Effects[index].Missile.origin[1]=MSG_ReadCoord(); cl.Effects[index].Missile.origin[2]=MSG_ReadCoord(); AngleVectors(pos,forward,right,up); speed = Length(cl.Effects[index].Missile.velocity); VectorScale(forward,speed,cl.Effects[index].Missile.velocity); } } break; } else { // Con_DPrintf("Received Unrecognized Effect Update!\n"); switch(type) { case CE_SCARABCHAIN://attach to new guy or retract if new guy is world curEnt = MSG_ReadShort(); break; case CE_HWXBOWSHOOT: revisionCode = MSG_ReadByte(); curEnt = (revisionCode>>4)&7; if (revisionCode & 1)//impact effect: { MSG_ReadCoord(); } else { MSG_ReadAngle(); MSG_ReadAngle(); if (revisionCode &128)//new origin { MSG_ReadCoord(); MSG_ReadCoord(); MSG_ReadCoord(); // create a clc message to retrieve effect information // MSG_WriteByte (&cls.netchan.message, clc_get_effect); // MSG_WriteByte (&cls.netchan.message, index); } } break; case CE_HWSHEEPINATOR: revisionCode = MSG_ReadByte(); curEnt = (revisionCode>>4)&7; if (revisionCode & 1)//impact { MSG_ReadCoord(); } else//direction change { MSG_ReadAngle(); MSG_ReadAngle(); if (revisionCode &128)//new origin { MSG_ReadCoord(); MSG_ReadCoord(); MSG_ReadCoord(); // create a clc message to retrieve effect information // MSG_WriteByte (&cls.netchan.message, clc_get_effect); // MSG_WriteByte (&cls.netchan.message, index); } } break; case CE_HWDRILLA: revisionCode = MSG_ReadByte(); if (revisionCode == 0)//impact { MSG_ReadCoord(); MSG_ReadCoord(); MSG_ReadCoord(); MSG_ReadByte(); } else//turn { MSG_ReadAngle(); MSG_ReadAngle(); MSG_ReadCoord(); MSG_ReadCoord(); MSG_ReadCoord(); // create a clc message to retrieve effect information // MSG_WriteByte (&cls.netchan.message, clc_get_effect); // MSG_WriteByte (&cls.netchan.message, index); } break; } } } void UpdateMissilePath(vec3_t oldorg, vec3_t neworg, vec3_t newvel, float time) { vec3_t endpos; //the position it should be at currently float delta; delta = cl.time - time; VectorMA(neworg, delta, newvel, endpos); VectorCopy(neworg, oldorg); //set orig, maybe vel too } void CL_TurnEffect(void) { int index; entity_t *ent; vec3_t pos, vel; float time; index = MSG_ReadByte (); time = MSG_ReadFloat (); pos[0] = MSG_ReadCoord(); pos[1] = MSG_ReadCoord(); pos[2] = MSG_ReadCoord(); vel[0] = MSG_ReadCoord(); vel[1] = MSG_ReadCoord(); vel[2] = MSG_ReadCoord(); switch(cl.Effects[index].type) { case CE_HWRAVENSTAFF: case CE_HWRAVENPOWER: case CE_BONESHARD: case CE_BONESHRAPNEL: case CE_HWBONEBALL: if(cl.Effects[index].Missile.entity_index > -1) { ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; UpdateMissilePath(ent->origin, pos, vel, time); VectorCopy(vel, cl.Effects[index].Missile.velocity); vectoangles(cl.Effects[index].Missile.velocity, cl.Effects[index].Missile.angle); } break; case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: if(cl.Effects[index].Star.entity_index > -1) { ent = &EffectEntities[cl.Effects[index].Star.entity_index]; UpdateMissilePath(ent->origin, pos, vel, time); VectorCopy(vel, cl.Effects[index].Star.velocity); } break; case 0: // create a clc message to retrieve effect information // MSG_WriteByte (&cls.netchan.message, clc_get_effect); // MSG_WriteByte (&cls.netchan.message, index); // Con_Printf("CL_TurnEffect: null effect %d\n", index); break; default: Con_Printf ("CL_TurnEffect: bad type %d\n", cl.Effects[index].type); break; } } void CL_LinkEntity(entity_t *ent) { if (cl_numvisedicts == MAX_VISEDICTS) { // object list is full //Sys_Error("CL_LinkEntity: Out of vis edicts\n"); return; } //debug: if visedicts getting messed up, it should appear here. // if (ent->model < 10) // { // ent->model = 3; // } cl_visedicts[cl_numvisedicts++] = *ent; } void R_RunQuakeEffect (vec3_t org, float distance); void RiderParticle(int count, vec3_t origin); void CL_UpdateEffects(void) { int index,cur_frame; vec3_t mymin,mymax; float frametime; // edict_t test; // trace_t trace; vec3_t org,org2,old_origin; int x_dir,y_dir; entity_t *ent, *ent2; float distance,smoketime; int i; entity_state_t *es; mleaf_t *l; frametime = host_frametime; if (!frametime) return; // Con_Printf("Here at %f\n",cl.time); for(index=0;index= cl.Effects[index].Rain.wait) { R_RainEffect(org,org2,x_dir,y_dir,cl.Effects[index].Rain.color, cl.Effects[index].Rain.count); cl.Effects[index].Rain.next_time = 0; } break; case CE_FOUNTAIN: mymin[0] = (-3 * cl.Effects[index].Fountain.vright[0] * cl.Effects[index].Fountain.movedir[0]) + (-3 * cl.Effects[index].Fountain.vforward[0] * cl.Effects[index].Fountain.movedir[1]) + (2 * cl.Effects[index].Fountain.vup[0] * cl.Effects[index].Fountain.movedir[2]); mymin[1] = (-3 * cl.Effects[index].Fountain.vright[1] * cl.Effects[index].Fountain.movedir[0]) + (-3 * cl.Effects[index].Fountain.vforward[1] * cl.Effects[index].Fountain.movedir[1]) + (2 * cl.Effects[index].Fountain.vup[1] * cl.Effects[index].Fountain.movedir[2]); mymin[2] = (-3 * cl.Effects[index].Fountain.vright[2] * cl.Effects[index].Fountain.movedir[0]) + (-3 * cl.Effects[index].Fountain.vforward[2] * cl.Effects[index].Fountain.movedir[1]) + (2 * cl.Effects[index].Fountain.vup[2] * cl.Effects[index].Fountain.movedir[2]); mymin[0] *= 15; mymin[1] *= 15; mymin[2] *= 15; mymax[0] = (3 * cl.Effects[index].Fountain.vright[0] * cl.Effects[index].Fountain.movedir[0]) + (3 * cl.Effects[index].Fountain.vforward[0] * cl.Effects[index].Fountain.movedir[1]) + (10 * cl.Effects[index].Fountain.vup[0] * cl.Effects[index].Fountain.movedir[2]); mymax[1] = (3 * cl.Effects[index].Fountain.vright[1] * cl.Effects[index].Fountain.movedir[0]) + (3 * cl.Effects[index].Fountain.vforward[1] * cl.Effects[index].Fountain.movedir[1]) + (10 * cl.Effects[index].Fountain.vup[1] * cl.Effects[index].Fountain.movedir[2]); mymax[2] = (3 * cl.Effects[index].Fountain.vright[2] * cl.Effects[index].Fountain.movedir[0]) + (3 * cl.Effects[index].Fountain.vforward[2] * cl.Effects[index].Fountain.movedir[1]) + (10 * cl.Effects[index].Fountain.vup[2] * cl.Effects[index].Fountain.movedir[2]); mymax[0] *= 15; mymax[1] *= 15; mymax[2] *= 15; R_RunParticleEffect2 (cl.Effects[index].Fountain.pos,mymin,mymax, cl.Effects[index].Fountain.color,2,cl.Effects[index].Fountain.cnt); /* memset(&test,0,sizeof(test)); trace = SV_Move (cl.Effects[index].Fountain.pos, mymin, mymax, mymin, false, &test); Con_Printf("Fraction is %f\n",trace.fraction);*/ break; case CE_QUAKE: R_RunQuakeEffect (cl.Effects[index].Quake.origin,cl.Effects[index].Quake.radius); break; case CE_RIPPLE: cl.Effects[index].Smoke.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Smoke.entity_index]; smoketime = cl.Effects[index].Smoke.framelength; if (!smoketime) smoketime = HX_FRAME_TIME*2; while(cl.Effects[index].Smoke.time_amount >= smoketime&&ent->scale<250) { ent->frame++; ent->angles[1]+=1; cl.Effects[index].Smoke.time_amount -= smoketime; } if (ent->frame >= 10) { CL_FreeEffect(index); } else CL_LinkEntity(ent); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: cl.Effects[index].Smoke.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Smoke.entity_index]; smoketime = cl.Effects[index].Smoke.framelength; if (!smoketime) smoketime = HX_FRAME_TIME; ent->origin[0] += (frametime/smoketime) * cl.Effects[index].Smoke.velocity[0]; ent->origin[1] += (frametime/smoketime) * cl.Effects[index].Smoke.velocity[1]; ent->origin[2] += (frametime/smoketime) * cl.Effects[index].Smoke.velocity[2]; i=0; while(cl.Effects[index].Smoke.time_amount >= smoketime) { ent->frame++; i++; cl.Effects[index].Smoke.time_amount -= smoketime; } if (ent->frame >= ent->model->numframes) { CL_FreeEffect(index); } else CL_LinkEntity(ent); if(cl.Effects[index].type == CE_TELESMK1) { ent = &EffectEntities[cl.Effects[index].Smoke.entity_index2]; ent->origin[0] -= (frametime/smoketime) * cl.Effects[index].Smoke.velocity[0]; ent->origin[1] -= (frametime/smoketime) * cl.Effects[index].Smoke.velocity[1]; ent->origin[2] -= (frametime/smoketime) * cl.Effects[index].Smoke.velocity[2]; ent->frame += i; if (ent->frame < ent->model->numframes) { CL_LinkEntity(ent); } } break; // Just go through animation and then remove case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_BRN_BOUNCE: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FBOOM: case CE_BOMB: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: cl.Effects[index].Smoke.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Smoke.entity_index]; if (cl.Effects[index].type != CE_BG_CIRCLE_EXP) { while(cl.Effects[index].Smoke.time_amount >= HX_FRAME_TIME) { ent->frame++; cl.Effects[index].Smoke.time_amount -= HX_FRAME_TIME; } } else { while(cl.Effects[index].Smoke.time_amount >= HX_FRAME_TIME * 2) { ent->frame++; cl.Effects[index].Smoke.time_amount -= HX_FRAME_TIME * 2; } } if (ent->frame >= ent->model->numframes) { CL_FreeEffect(index); } else CL_LinkEntity(ent); break; // Go forward then backward through animation then remove case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: cl.Effects[index].Flash.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Flash.entity_index]; while(cl.Effects[index].Flash.time_amount >= HX_FRAME_TIME) { if (!cl.Effects[index].Flash.reverse) { if (ent->frame >= ent->model->numframes-1) // Ran through forward animation { cl.Effects[index].Flash.reverse = 1; ent->frame--; } else ent->frame++; } else ent->frame--; cl.Effects[index].Flash.time_amount -= HX_FRAME_TIME; } if ((ent->frame <= 0) && (cl.Effects[index].Flash.reverse)) { CL_FreeEffect(index); } else CL_LinkEntity(ent); break; case CE_RIDER_DEATH: cl.Effects[index].RD.time_amount += frametime; if (cl.Effects[index].RD.time_amount >= 1) { cl.Effects[index].RD.stage++; cl.Effects[index].RD.time_amount -= 1; } VectorCopy(cl.Effects[index].RD.origin,org); org[0] += sin(cl.Effects[index].RD.time_amount * 2 * M_PI) * 30; org[1] += cos(cl.Effects[index].RD.time_amount * 2 * M_PI) * 30; if (cl.Effects[index].RD.stage <= 6) { RiderParticle(cl.Effects[index].RD.stage+1,org); } else { // To set the rider's origin point for the particles RiderParticle(0,org); if (cl.Effects[index].RD.stage == 7) { cl.cshifts[CSHIFT_BONUS].destcolor[0] = 255; cl.cshifts[CSHIFT_BONUS].destcolor[1] = 255; cl.cshifts[CSHIFT_BONUS].destcolor[2] = 255; cl.cshifts[CSHIFT_BONUS].percent = 256; } else if (cl.Effects[index].RD.stage > 13) { // cl.Effects[index].RD.stage = 0; CL_FreeEffect(index); } } break; case CE_TELEPORTERPUFFS: cl.Effects[index].Teleporter.time_amount += frametime; smoketime = cl.Effects[index].Teleporter.framelength; ent = &EffectEntities[cl.Effects[index].Teleporter.entity_index[0]]; while(cl.Effects[index].Teleporter.time_amount >= HX_FRAME_TIME) { ent->frame++; cl.Effects[index].Teleporter.time_amount -= HX_FRAME_TIME; } cur_frame = ent->frame; if (cur_frame >= ent->model->numframes) { CL_FreeEffect(index); break; } for (i=0;i<8;++i) { ent = &EffectEntities[cl.Effects[index].Teleporter.entity_index[i]]; ent->origin[0] += (frametime/smoketime) * cl.Effects[index].Teleporter.velocity[i][0]; ent->origin[1] += (frametime/smoketime) * cl.Effects[index].Teleporter.velocity[i][1]; ent->origin[2] += (frametime/smoketime) * cl.Effects[index].Teleporter.velocity[i][2]; ent->frame = cur_frame; CL_LinkEntity(ent); } break; case CE_TELEPORTERBODY: cl.Effects[index].Teleporter.time_amount += frametime; smoketime = cl.Effects[index].Teleporter.framelength; ent = &EffectEntities[cl.Effects[index].Teleporter.entity_index[0]]; while(cl.Effects[index].Teleporter.time_amount >= HX_FRAME_TIME) { ent->scale -= 15; cl.Effects[index].Teleporter.time_amount -= HX_FRAME_TIME; } ent = &EffectEntities[cl.Effects[index].Teleporter.entity_index[0]]; ent->angles[1] += 45; if (ent->scale <= 10) { CL_FreeEffect(index); } else { CL_LinkEntity(ent); } break; case CE_HWDRILLA: cl.Effects[index].Missile.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; if ((int)(cl.time) != (int)(cl.time - host_frametime)) { S_StartSound (TempSoundChannel(), 1, cl_fxsfx_drillaspin, ent->origin, 1, 1); } ent->angles[0] += frametime * cl.Effects[index].Missile.avelocity[0]; ent->angles[1] += frametime * cl.Effects[index].Missile.avelocity[1]; ent->angles[2] += frametime * cl.Effects[index].Missile.avelocity[2]; VectorCopy(ent->origin,old_origin); ent->origin[0] += frametime * cl.Effects[index].Missile.velocity[0]; ent->origin[1] += frametime * cl.Effects[index].Missile.velocity[1]; ent->origin[2] += frametime * cl.Effects[index].Missile.velocity[2]; R_RocketTrail (old_origin, ent->origin, rt_setstaff); CL_LinkEntity(ent); break; case CE_HWXBOWSHOOT: cl.Effects[index].Xbow.time_amount += frametime; for (i=0;iorigin[0] += frametime * cl.Effects[index].Xbow.vel[i][0]; ent->origin[1] += frametime * cl.Effects[index].Xbow.vel[i][1]; ent->origin[2] += frametime * cl.Effects[index].Xbow.vel[i][2]; CL_LinkEntity(ent); } else if (cl.Effects[index].Xbow.bolts == 5)//fiery bolts don't just go away { if (cl.Effects[index].Xbow.state[i] == 0)//waiting to explode state { if (cl.Effects[index].Xbow.gonetime[i] > cl.time)//fiery bolts stick around for a while { ent = &EffectEntities[cl.Effects[index].Xbow.ent[i]]; CL_LinkEntity(ent); } else//when time's up on fiery guys, they explode { //set state to exploding cl.Effects[index].Xbow.state[i] = 1; ent = &EffectEntities[cl.Effects[index].Xbow.ent[i]]; //move bolt back a little to make explosion look better VectorNormalize(cl.Effects[index].Xbow.vel[i]); VectorScale(cl.Effects[index].Xbow.vel[i],-8,cl.Effects[index].Xbow.vel[i]); VectorAdd(ent->origin,cl.Effects[index].Xbow.vel[i],ent->origin); //turn bolt entity into an explosion ent->model = Mod_ForName("models/xbowexpl.spr", true); ent->frame = 0; //set frame change counter cl.Effects[index].Xbow.gonetime[i] = cl.time + HX_FRAME_TIME * 2; //play explosion sound S_StartSound (TempSoundChannel(), 1, cl_fxsfx_explode, ent->origin, 1, 1); CL_LinkEntity(ent); } } else if (cl.Effects[index].Xbow.state[i] == 1)//fiery bolt exploding state { ent = &EffectEntities[cl.Effects[index].Xbow.ent[i]]; //increment frame if it's time while(cl.Effects[index].Xbow.gonetime[i] <= cl.time) { ent->frame++; cl.Effects[index].Xbow.gonetime[i] += HX_FRAME_TIME * 0.75; } if (ent->frame >= ent->model->numframes) { cl.Effects[index].Xbow.state[i] = 2;//if anim is over, set me to inactive state } else CL_LinkEntity(ent); } } } } break; case CE_HWSHEEPINATOR: cl.Effects[index].Xbow.time_amount += frametime; for (i=0;iorigin[0] += frametime * cl.Effects[index].Xbow.vel[i][0]; ent->origin[1] += frametime * cl.Effects[index].Xbow.vel[i][1]; ent->origin[2] += frametime * cl.Effects[index].Xbow.vel[i][2]; R_RunParticleEffect4(ent->origin,7,(rand()%15)+144,pt_explode2,(rand()%5)+1); CL_LinkEntity(ent); } } } break; case CE_DEATHBUBBLES: cl.Effects[index].Bubble.time_amount += frametime; if (cl.Effects[index].Bubble.time_amount > 0.1)//10 bubbles a sec { cl.Effects[index].Bubble.time_amount = 0; cl.Effects[index].Bubble.count--; es = FindState(cl.Effects[index].Bubble.owner); if (es) { VectorCopy(es->origin,org); VectorAdd(org,cl.Effects[index].Bubble.offset,org); l = Mod_PointInLeaf (org, cl.worldmodel); if(l->contents!=CONTENTS_WATER) { //not in water anymore CL_FreeEffect(index); break; } else { CLTENT_SpawnDeathBubble(org); } } } if (cl.Effects[index].Bubble.count <= 0) CL_FreeEffect(index); break; case CE_SCARABCHAIN: cl.Effects[index].Chain.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Chain.ent1]; switch (cl.Effects[index].Chain.state) { case 0://zooming in toward owner es = FindState(cl.Effects[index].Chain.owner); if (cl.Effects[index].Chain.sound_time <= cl.time) { cl.Effects[index].Chain.sound_time = cl.time + 0.5; S_StartSound (TempSoundChannel(), 1, cl_fxsfx_scarabhome, ent->origin, 1, 1); } if (es) { VectorCopy(es->origin,org); org[2]+=cl.Effects[index].Chain.height; VectorSubtract(org,ent->origin,org); if (fabs(VectorNormalize(org))<500*frametime) { S_StartSound (TempSoundChannel(), 1, cl_fxsfx_scarabgrab, ent->origin, 1, 1); cl.Effects[index].Chain.state = 1; VectorCopy(es->origin, ent->origin); ent->origin[2] += cl.Effects[index].Chain.height; XbowImpactPuff(ent->origin, cl.Effects[index].Chain.material); } else { VectorScale(org,500*frametime,org); VectorAdd(ent->origin,org,ent->origin); } } break; case 1://attached--snap to owner's pos es = FindState(cl.Effects[index].Chain.owner); if (es) { VectorCopy(es->origin, ent->origin); ent->origin[2] += cl.Effects[index].Chain.height; } break; case 2://unattaching, server needs to set this state VectorCopy(ent->origin,org); VectorSubtract(cl.Effects[index].Chain.origin,org,org); if (fabs(VectorNormalize(org))>350*frametime)//closer than 30 is too close? { VectorScale(org,350*frametime,org); VectorAdd(ent->origin,org,ent->origin); } else//done--flash & git outa here (change type to redflash) { S_StartSound (TempSoundChannel(), 1, cl_fxsfx_scarabbyebye, ent->origin, 1, 1); cl.Effects[index].Flash.entity_index = cl.Effects[index].Chain.ent1; cl.Effects[index].type = CE_RED_FLASH; VectorCopy(ent->origin,cl.Effects[index].Flash.origin); cl.Effects[index].Flash.reverse = 0; ent->model = Mod_ForName("models/redspt.spr", true); ent->frame = 0; ent->drawflags = DRF_TRANSLUCENT; } break; } CL_LinkEntity(ent); //damndamndamn--add stream stuff here! VectorCopy(cl.Effects[index].Chain.origin, org); VectorCopy(ent->origin, org2); CreateStream(TE_STREAM_CHAIN, cl.Effects[index].Chain.ent1, 1, cl.Effects[index].Chain.tag, 0.1, 0, org, org2); break; case CE_TRIPMINESTILL: cl.Effects[index].Chain.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Chain.ent1]; // if (cl.Effects[index].Chain.ent1 < 0)//fixme: remove this!!! // Con_DPrintf("OHSHITOHSHIT--bad chain ent\n"); CL_LinkEntity(ent); // Con_DPrintf("Chain Ent at: %d %d %d\n",(int)cl.Effects[index].Chain.origin[0],(int)cl.Effects[index].Chain.origin[1],(int)cl.Effects[index].Chain.origin[2]); //damndamndamn--add stream stuff here! VectorCopy(cl.Effects[index].Chain.origin, org); VectorCopy(ent->origin, org2); CreateStream(TE_STREAM_CHAIN, cl.Effects[index].Chain.ent1, 1, 1, 0.1, 0, org, org2); break; case CE_TRIPMINE: cl.Effects[index].Chain.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Chain.ent1]; ent->origin[0] += frametime * cl.Effects[index].Chain.velocity[0]; ent->origin[1] += frametime * cl.Effects[index].Chain.velocity[1]; ent->origin[2] += frametime * cl.Effects[index].Chain.velocity[2]; CL_LinkEntity(ent); //damndamndamn--add stream stuff here! VectorCopy(cl.Effects[index].Chain.origin, org); VectorCopy(ent->origin, org2); CreateStream(TE_STREAM_CHAIN, cl.Effects[index].Chain.ent1, 1, 1, 0.1, 0, org, org2); break; case CE_BONESHARD: case CE_BONESHRAPNEL: case CE_HWBONEBALL: case CE_HWRAVENSTAFF: case CE_HWRAVENPOWER: cl.Effects[index].Missile.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; // ent->angles[0] = cl.Effects[index].Missile.angle[0]; // ent->angles[1] = cl.Effects[index].Missile.angle[1]; // ent->angles[2] = cl.Effects[index].Missile.angle[2]; ent->angles[0] += frametime * cl.Effects[index].Missile.avelocity[0]; ent->angles[1] += frametime * cl.Effects[index].Missile.avelocity[1]; ent->angles[2] += frametime * cl.Effects[index].Missile.avelocity[2]; ent->origin[0] += frametime * cl.Effects[index].Missile.velocity[0]; ent->origin[1] += frametime * cl.Effects[index].Missile.velocity[1]; ent->origin[2] += frametime * cl.Effects[index].Missile.velocity[2]; if(cl.Effects[index].type == CE_HWRAVENPOWER) { while(cl.Effects[index].Missile.time_amount >= HX_FRAME_TIME) { ent->frame++; cl.Effects[index].Missile.time_amount -= HX_FRAME_TIME; } if (ent->frame > 7) { ent->frame = 0; break; } } CL_LinkEntity(ent); if(cl.Effects[index].type == CE_HWBONEBALL) { R_RunParticleEffect4 (ent->origin, 10, 368 + rand() % 16, pt_slowgrav, 3); } break; case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: // update scale if(cl.Effects[index].Star.scaleDir) { cl.Effects[index].Star.scale += 0.05; if(cl.Effects[index].Star.scale >= 1) { cl.Effects[index].Star.scaleDir = 0; } } else { cl.Effects[index].Star.scale -= 0.05; if(cl.Effects[index].Star.scale <= 0.01) { cl.Effects[index].Star.scaleDir = 1; } } cl.Effects[index].Star.time_amount += frametime; ent = &EffectEntities[cl.Effects[index].Star.entity_index]; ent->angles[0] += frametime * cl.Effects[index].Star.avelocity[0]; ent->angles[1] += frametime * cl.Effects[index].Star.avelocity[1]; ent->angles[2] += frametime * cl.Effects[index].Star.avelocity[2]; ent->origin[0] += frametime * cl.Effects[index].Star.velocity[0]; ent->origin[1] += frametime * cl.Effects[index].Star.velocity[1]; ent->origin[2] += frametime * cl.Effects[index].Star.velocity[2]; CL_LinkEntity(ent); if (cl.Effects[index].Star.ent1 != -1) { ent2= &EffectEntities[cl.Effects[index].Star.ent1]; VectorCopy(ent->origin, ent2->origin); ent2->scale = cl.Effects[index].Star.scale; ent2->angles[1] += frametime * 300; ent2->angles[2] += frametime * 400; CL_LinkEntity(ent2); } if(cl.Effects[index].type == CE_HWMISSILESTAR) { if (cl.Effects[index].Star.ent2 != -1) { ent2 = &EffectEntities[cl.Effects[index].Star.ent2]; VectorCopy(ent->origin, ent2->origin); ent2->scale = cl.Effects[index].Star.scale; ent2->angles[1] += frametime * -300; ent2->angles[2] += frametime * -400; CL_LinkEntity(ent2); } } if(rand() % 10 < 3) { R_RunParticleEffect4 (ent->origin, 7, 148 + rand() % 11, pt_grav, 10 + rand() % 10); } break; } } // Con_DPrintf("Effect Ents: %d\n",EffectEntityCount); } // this creates multi effects from one packet void CreateRavenExplosions(vec3_t pos); void CL_ParseMultiEffect(void) { int type, index, count; vec3_t orig, vel, right; entity_t *ent; type = MSG_ReadByte(); switch(type) { case CE_HWRAVENPOWER: orig[0] = MSG_ReadCoord(); orig[1] = MSG_ReadCoord(); orig[2] = MSG_ReadCoord(); vel[0] = MSG_ReadCoord(); vel[1] = MSG_ReadCoord(); vel[2] = MSG_ReadCoord(); for(count=0;count<3;count++) { index = MSG_ReadByte(); // create the effect cl.Effects[index].type = type; VectorCopy(orig, cl.Effects[index].Missile.origin); VectorCopy(vel, cl.Effects[index].Missile.velocity); vectoangles(cl.Effects[index].Missile.velocity, cl.Effects[index].Missile.angle); if ((cl.Effects[index].Missile.entity_index = NewEffectEntity()) != -1) { ent = &EffectEntities[cl.Effects[index].Missile.entity_index]; VectorCopy(cl.Effects[index].Missile.origin, ent->origin); VectorCopy(cl.Effects[index].Missile.angle, ent->angles); ent->model = Mod_ForName("models/ravproj.mdl", true); S_StartSound (TempSoundChannel(), 1, cl_fxsfx_ravengo, cl.Effects[index].Missile.origin, 1, 1); } } CreateRavenExplosions(orig); break; default: Sys_Error ("CL_ParseMultiEffect: bad type"); } } //========================================================================== // // NewEffectEntity // //========================================================================== static int NewEffectEntity(void) { entity_t *ent; int counter; if(cl_numvisedicts == MAX_VISEDICTS) { return -1; } if(EffectEntityCount == MAX_EFFECT_ENTITIES) { return -1; } for(counter=0;countercolormap = vid.colormap; return counter; } static void FreeEffectEntity(int index) { if (index != -1 && EntityUsed[index]) { EntityUsed[index] = false; EffectEntityCount--; } else if (index != -1) { EffectEntityCount--;//still decrement counter; since value is -1, counter was incremented // Con_DPrintf("ERROR: Redeleting Effect Entity: %d!\n",index);//fixme: this should not be in final version } else { // Con_DPrintf("ERROR: Deleting Invalid Effect Entity: %d!\n",index);//fixme: this should not be in final version } } /* * $Log: /HexenWorld/Client/cl_effect.c $ * * 89 5/25/98 1:29p Mgummelt * * 88 5/07/98 8:26p Mgummelt * * 87 5/05/98 8:33p Mgummelt * Added 6th playerclass for Siege only- Dwarf * * 86 4/24/98 1:31a Mgummelt * Siege version 0.02 4/24/98 1:31 AM * * 85 4/23/98 5:15p Mgummelt * Fixes for Siege * * 84 4/20/98 8:16p Mgummelt * Added CE_Ripple * * 83 4/20/98 2:02p Rjohnson * Big update * * 82 4/10/98 3:45p Ssengele * made xbolt explosions fast...Way too fast... * * 81 4/01/98 3:03p Ssengele * faster xbolts, initial optimizing of forcecube. * * 80 3/26/98 5:00p Mgummelt * Added new Mission Pack client effects for succubus' weapons * * 79 3/20/98 1:41p Ssengele * commented debug messages * * 78 3/19/98 8:32p Ssengele * scarab chains instantly attach to ya, to alleviate possible problems * with them setting values on a target they might not ever hit. * * 77 3/14/98 3:17p Ssengele * lambinator doesn't make xbow sound when firing anymore--old cut 'n' * paste thing. is there a lambinator sound? * * 76 3/13/98 1:20a Ssengele * debug message out * * 75 3/13/98 1:19a Ssengele * client effect crash fixed--xbow bolts were using visedicts even tho * they were set to -1 * * 74 3/12/98 12:31p Ssengele * same fix as previous check-in, in a different spot. * * 73 3/12/98 12:30p Ssengele * fixed bug with drilla--new coordinates always sent, but weren't always * looked for. * * 72 3/11/98 9:46p Ssengele * xbolts (& theoretically, setstaff & lambinator) teleport cleanly. * currently cause a spike, which can and will be fixed soon. * server by default only sends the effects close enough to client to * matter to that client. * * 71 3/10/98 8:00p Ssengele * debug print * * 70 3/10/98 5:31p Ssengele * client asks for effect if origin changes and client doesn't recognize * effect. more info for effect kept updated on server. almost ready for * effects to work thru teleporters. hmm...will look into how much * traffic the arrows, lambinator, and drilla would take if they used * nailgun code. * * 69 3/10/98 3:54p Ssengele * fixed client effects getting screwed up--xbolt effect ents were getting * removed without being set validly * * 68 3/09/98 4:47p Ssengele * started solidifying server tracking of updateable effects: not used * yet; made recoil from daggerdive less extreme than jab; made sure * update message doesn't write over effect info if the type updated is * different from the type already there. * * 67 3/09/98 2:47p Rmidthun * when turneffect is called and the effect does not exist, the client * will ask for the effect. * * 66 3/07/98 3:52p Rjohnson * Doesn't stop the game if max vis edicts is reached * * 65 3/07/98 3:07p Rjohnson * Increased the max number of vis edicts, and added a check to make sure * we don't overflow * * 64 3/06/98 4:07p Ssengele * impact effect for ovinomancer jobby * * 63 3/06/98 12:04p Ssengele * fixed bug in failsafe--cut-and-paste made drilla completely screwed * * 62 3/06/98 11:25a Rmidthun * ravens needed their animation put back * * 61 3/05/98 9:58p Ssengele * attempt to limit flickering of scarab chains; minimum of 3 b&g mana for * untomed scarab * * 60 3/05/98 5:57p Ssengele * failsafes for updating effects * * 59 3/05/98 12:19p Ssengele * sheepinator spead corrected * * 58 3/04/98 9:58a Rmidthun * moved ravenshot explosion into its remove effect * * 57 3/03/98 8:49p Ssengele * untomed scarab staff should turn now * * 56 3/03/98 8:09p Ssengele * reflection code for xbow bolts and sheepinator; also, a little variance * for where bolts start out, so autoaim doesn't make them clump up quite * as much (variance is consistent between sv & cl) * * 55 3/03/98 4:43p Ssengele * sheepinator uses xbow code now. * * 54 3/03/98 3:01p Rmidthun * client effect missiles needed an update function to be called when * other things change their velocity, this was put into invntory.hc. * * 53 3/03/98 1:58p Ssengele * er, took a break from weapon stuff to move the bubble code over to a * client effect * * 52 3/03/98 11:51a Ssengele * moved untomed setstaff drilling to client (will add meat chunks to * client stuff if time permits) * * 51 3/02/98 6:02p Ssengele * made scarab chains disappear w/o being burden on nettraffic * * 50 3/02/98 4:12p Ssengele * minor improvement for xbow, punchdagger sheep gone away * * 49 3/02/98 2:35p Ssengele * set staff worst-case not bad at all anymore--the drilla is an effect * * 48 3/02/98 12:36p Ssengele * shaved a few bytes from powered up setstaff (moving puffs to client), * have begun working on worst-case unpowered setstaff (explosions are now * tempent * vs effect & sound they were before). unpowered ss still clogs up net * when firing fast--i believe i'll make the whole thing an effect. * * 47 2/28/98 3:40p Rjohnson * Added protos for all the particle effects, and changed the radius for * the crossbow hit * * 46 2/28/98 3:26p Ssengele * some work on set staff * * 45 2/27/98 7:29p Ssengele * shaved off a couple more bytes from the xbow * * 44 2/27/98 7:12p Ssengele * grrrrrrrr...xbow more optimized than ever (plus chunks, or did i add * those yesterday?), still spiking not-so-pretty (nudges first red line) * occasionally in the worst case scenario. * * 43 2/27/98 1:48p Rmidthun * seems to be a problem when turneffect is lagged, trying to correct it * * 42 2/26/98 7:47p Ssengele * redirected arrows' angles correct * * 41 2/26/98 6:55p Ssengele * arrows fall into bits * * 40 2/26/98 5:55p Rmidthun * started work on correction mechanism for missile client effects * * 39 2/26/98 4:19p Rmidthun * added pos to turneffect so it can correct if need be, still working on * the actual correction * * 38 2/26/98 3:55p Rmidthun * powered ravenstaff uses multieffect, also moved tempent stuff to be * called from client effects, there is STILL a little red and I'm not * sure if the client effects are always in the correct place, but it * should be close anyway. * * 37 2/26/98 2:35p Ssengele * added rubbly particles for xbow impact; er, they last kinda long right * now... * * 36 2/26/98 2:03p Ssengele * further optimizing of xbow--at impact, i send distance it travelled * rather than end pos; pack alot of little pieces of info into a byte * * 35 2/26/98 1:34p Rmidthun * working on multiple effects with one net message * * 34 2/25/98 7:21p Ssengele * scarab chains look normal when they hit somebody other than their * target. * * 33 2/25/98 4:00p Rmidthun * ravens are now client effect too, still need to reduce the large * creation spike * * 32 2/25/98 12:22p Rjohnson * Put back some particle effects * * 31 2/24/98 2:26p Ssengele * xbow impact in correct position. !whew! * * 30 2/24/98 11:44a Rmidthun * magic missiles are client effects, the homing function sends updates * * 29 2/24/98 11:07a Ssengele * debugging * * 28 2/24/98 10:18a Rmidthun * telesmk1 will now do both smoke puffs and the sound * * 27 2/23/98 8:04p Ssengele * erg--checking in so's not to hog these files TOO much. cleffect that * handles multiple xbow bolts is IN, but impact is neither consistant nor * in the right spot. * * 26 2/23/98 10:44a Rmidthun * bone shards should rotate differently * * 25 2/23/98 9:48a Rmidthun * combined small blue flash and split sound for raven staff * * 24 2/20/98 7:32p Ssengele * scarab staff faster, lookin' good. much like the xbow stuff, it spikes * and then becomes fine; will work more on it later (movin back to xbow * improving). * * 23 2/20/98 4:45p Rmidthun * moved rest of sounds to client side * * 22 2/20/98 3:53p Ssengele * scarab staff ok, still needs a good chunk of work: only one chain seems * to be rendering * * 21 2/20/98 1:21p Rmidthun * missile rotation * * 20 2/20/98 1:05p Rmidthun * sounds use TempSoundChannel so they don't cut each other off, fixed * angles for missile effects * * 19 2/20/98 12:16p Ssengele * client is ready for scarab chain to be a client effect--feel free to * make ce_scarabchain be some other value * * 18 2/20/98 10:08a Rmidthun * bone shards don't need to send angle or angular vel * * 17 2/19/98 8:07p Ssengele * tripmine client effect in--added access to streams in cl_effect * * 16 2/19/98 7:01p Rmidthun * ravenstaff is almost all client effect, added a "turneffect" builtin to * reduce net traffic further * * 15 2/19/98 4:52p Rmidthun * added ravenstaff missile, it isn't used just yet * * 14 2/19/98 3:55p Rmidthun * boneball added * * 13 2/19/98 3:00p Ssengele * very basic framework for tripmine chain--no access to streams from * cl_effects, tho, which causes me great pain and sorrow * * 12 2/19/98 2:08p Rmidthun * * 11 2/19/98 12:45p Ssengele * put in client effect for powered-up xbow; spikes even bigger than * normal xbow,tho, so i'd like to chunk all of the arrows into one big * client effect, rather than give each of them their own. this i'll do * later. * * 10 2/19/98 11:13a Ssengele * made xbow sound-playing a little nicer * * 9 2/18/98 8:25p Ssengele * xbow client effect (for normal mode) lookin good--but it trades off * significantly less traffic when arrows are in air for a slightly bigger * spike when they're fired. will figure out how to minimize that spike * yet. * * 8 2/18/98 5:37p Ssengele * start at xbow bolt client effect * * 7 2/18/98 2:14p Rmidthun * moved sound to client effect * * 6 2/18/98 11:50a Rmidthun * eidolon missile (in case someone wants coop) * * 5 2/18/98 10:29a Rmidthun * * 4 2/17/98 6:52p Rmidthun * started moving star to client effect, its about halfway done, I checked * in so others could use it * * 3 2/06/98 4:43p Rjohnson * Got client interpolation in * * 2 2/05/98 1:23a Rjohnson * Got network protocols aligned * * 1 2/04/98 11:33p Rjohnson * * 32 10/13/97 10:28a Rlove * Made the bone shard powerup more network friendly. * * 31 10/10/97 9:13a Rlove * Moved bone shard shrapnel to client side effect * * 30 10/08/97 11:14a Rlove * * 29 10/06/97 12:19p Rjohnson * Fixed a name * * 28 10/06/97 12:14p Rlove * * 27 10/06/97 11:41a Rjohnson * Partically fixed teleporter effect * * 26 9/25/97 2:31p Rlove * * 25 9/04/97 4:44p Rjohnson * Updates * * 24 8/22/97 7:25a Rlove * Added red cloud temp effect * * 23 8/07/97 9:00a Rlove * * 22 8/06/97 3:46p Rjohnson * Rider death update * * 21 8/04/97 4:44p Rjohnson * Rider's Death doesn't repeat * * 20 7/31/97 2:49p Rlove * Added a few new effect entities * * 19 7/25/97 3:12p Rlove * * 18 7/25/97 3:05p Rlove * * 17 7/24/97 3:31p Rlove * * 16 7/24/97 3:28p Rlove * * 15 7/01/97 4:09p Rjohnson * Saving / Loading of client effects * * 14 6/30/97 10:29a Rlove * Added wait to rain entity * * 13 6/13/97 11:42a Rlove * * 12 6/12/97 12:13p Rlove * Added red and green sparks * * 11 6/12/97 6:42a Rlove * Smoke entities are being deleted (before they weren't) * * 10 6/04/97 9:59a Rjohnson * Added flash effect for rider's death * * 9 6/03/97 10:26a Rlove * * 8 6/03/97 9:00a Rlove * Added fx_smoke_generator entity * * 7 5/30/97 12:01p Rlove * New blue explosion * * 6 5/30/97 11:42a Rjohnson * Removed the message field of the effects * * 5 5/28/97 10:45a Rlove * Moved sprite effects to client side - smoke, explosions, and flashes. * * 4 5/27/97 4:46p Rjohnson * Added the smoke puff effect * * 3 5/23/97 3:05p Rjohnson * Update to effects / particle types * * 2 5/20/97 11:32a Rjohnson * Revised Effects * * 1 5/19/97 2:54p Rjohnson * Initial Version */