// Returns distance or 9999 if invalid for some reason static float Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec, qboolean checkvis) { float len; trace_t trace; vec3_t v; vectoangles (vec, v); VectorCopy (v, pmove.angles); VectorNormalize (vec); VectorMultAdd (player->pls.origin, 800, vec, v); // v is endpos // fake a player move trace = Cam_DoTrace (player->pls.origin, v); if ( /* trace.inopen || */ trace.inwater) return 9999; VectorCopy (trace.endpos, vec); len = VectorDistance (trace.endpos, player->pls.origin); if (len < 32 || len > 800) return 9999; if (checkvis) { trace = Cam_DoTrace (self->pls.origin, vec); if (trace.fraction != 1 || trace.inwater) return 9999; len = VectorDistance (trace.endpos, self->pls.origin); } return len; }
char *AIFunc_Heinrich_MeleeStart(cast_state_t *cs) { gentity_t *ent = &g_entities[cs->entityNum]; gentity_t *enemy = &g_entities[cs->enemyNum]; int rnd; static int lastStomp; if (cs->enemyNum < 0) { return NULL; } // record weapon fire cs->weaponFireTimes[cs->weaponNum] = level.time; // face them AICast_AimAtEnemy(cs); // clear flags cs->aiFlags &= ~(AIFL_MISCFLAG1|AIFL_MISCFLAG2); // decide which attack to use if (VectorDistance(ent->r.currentOrigin, enemy->r.currentOrigin) < 60) { rnd = 0; // sword slash up close } else if (VectorDistance(ent->r.currentOrigin, enemy->r.currentOrigin) >= HEINRICH_SLASH_RANGE) { rnd = 1; // too far away, stomp } else { // pick at random rnd = rand() % 2; } switch (rnd) { case 0: { int rnd = rand() % 3; switch (rnd) { case 0: return AIFunc_Heinrich_SwordSideSlashStart(cs); case 1: return AIFunc_Heinrich_SwordKnockbackStart(cs); case 2: return AIFunc_Heinrich_SwordLungeStart(cs); } } case 1: // dont do stomp too often if (lastStomp > level.time - 12000) { // plenty of time to let debris disappear return NULL; } lastStomp = level.time; cs->aiFlags |= AIFL_SPECIAL_FUNC; // sound G_AddEvent(ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_EARTHQUAKE_START]); // play the anim BG_PlayAnimName(&ent->client->ps, "attack7", ANIM_BP_BOTH, qtrue, qfalse, qtrue); // start the func cs->aifunc = AIFunc_Heinrich_Earthquake; return "AIFunc_Heinrich_Earthquake"; } // shutup compiler return NULL; }
/* ============= AI_AvoidDangerousEntity Alerts all AI in vaccinity of the given ent, so they can flee if possible ============= */ void AI_AvoidDangerousEntity( edict_t *ent ) { int i; float old_time; if (deathmatch->value) return; ent->s.origin[2] += 4; old_time = level.time; for (i=1; i<level.num_characters; i++) { if (!level.characters[i] || level.characters[i]->health <= 0) continue; if (level.characters[i] == ent) continue; if (!ent->client && VectorDistance( level.characters[i]->s.origin, ent->s.origin ) > ent->dmg_radius*2) continue; // if they are already fleeing this ent, check our fleeing position if (level.characters[i]->cast_info.aiflags & AI_TAKE_COVER) { if (level.characters[i]->combat_goalent && !CanDamage( level.characters[i]->combat_goalent, ent )) continue; } if (!gi.inPVS( level.characters[i]->s.origin, ent->s.origin )) continue; if ((VectorDistance( level.characters[i]->s.origin, ent->s.origin ) > 64) && !CanDamage( level.characters[i], ent)) continue; // gi.dprintf( "RUN FOR YOUR LIVES!!!!\n" ); level.characters[i]->last_gethidepos = 0; level.time -= 0.1; // so we bypass speed optimization AI_ForceTakeCover( level.characters[i], ent, (ent->client == NULL) ); ent->noise_time = level.time; } level.time = old_time; ent->s.origin[2] -= 4; }
void CCam::satchelCam(camInfo_t *ci) { int satchelEntityNum = Engine.findSatchel(); // If don't find satchel or is out of range to fire if (satchelEntityNum == -1 || VectorDistance(eth32.cg.refdef->vieworg, eth32.cg.gentity[satchelEntityNum].lerpOrigin) > 2000) return; int w = ci->x2 - ci->x1; int h = ci->y2 - ci->y1; // Set the view memcpy(&camRefDef, ð32.cg.refdef, sizeof(refdef_t)); // fov camRefDef.fov_x = (w>h) ? ci->fov : ci->fov * w / h; camRefDef.fov_y = (h>w) ? ci->fov : ci->fov * h / w; // origin VectorCopy(eth32.cg.gentity[satchelEntityNum].lerpOrigin, camRefDef.vieworg); camRefDef.vieworg[ROLL] += ci->distance; // view angle vec3_t camAngle; VectorCopy(eth32.cg.refdefViewAngles, camAngle); camAngle[PITCH] = ci->angle; AnglesToAxis(camAngle, camRefDef.viewaxis); // Draw the spycam drawCam(ci->x1, ci->y1, w, h, &camRefDef, qfalse); }
void cashroll_animate( edict_t *self ) { // reduce XY velocity (air friction) self->velocity[0] *= 0.9; self->velocity[1] *= 0.9; if (level.time > (self->timestamp)) { cash_kill( self ); return; } if (self->movetype != MOVETYPE_NONE) { if (VectorDistance( self->s.origin, self->pos1 ) < 1) self->count++; else self->count = 0; VectorCopy( self->s.origin, self->pos1 ); if (self->count > 2) // rested for 2 frames { VectorClear( self->velocity ); VectorClear( self->avelocity ); self->s.angles[PITCH] = 0; self->s.angles[ROLL] = 0; self->movetype = MOVETYPE_NONE; } } self->nextthink = level.time + 0.1; }
void R_MeshQueue_AddTransparent(dptransparentsortcategory_t category, const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight) { meshqueue_t *mq; if (mqt_count >= mqt_total || !mqt_array) { int newtotal = max(1024, mqt_total * 2); meshqueue_t *newarray = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, newtotal * sizeof(meshqueue_t)); if (mqt_array) { memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t)); Mem_Free(mqt_array); } mqt_array = newarray; mqt_total = newtotal; } mq = &mqt_array[mqt_count++]; mq->callback = callback; mq->ent = ent; mq->surfacenumber = surfacenumber; mq->rtlight = rtlight; mq->category = category; if (r_transparent_useplanardistance.integer) mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist; else mq->dist = VectorDistance(center, r_refdef.view.origin); mq->next = NULL; mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist); }
itementity_t *CItemMng::SearchShortestEntity( vec3_t pos ) { itementity_t *entity; float minDist, dist; int selected = -1; minDist = 100000000.0f; entity = m_linked; while( entity ) { dist = VectorDistance( pos, entity->origin ); if( dist < minDist ) { minDist = dist; selected = entity->idx; } entity = entity->next; } if( selected < 0 ) return NULL; return &m_entities[ selected ]; }
char *AIFunc_Heinrich_RaiseDead(cast_state_t *cs) { int i; gentity_t *ent = &g_entities[cs->entityNum]; gentity_t *enemy = &g_entities[cs->enemyNum]; gentity_t *trav, *closest; float closestDist, dist; cs->aiFlags |= AIFL_SPECIAL_FUNC; if (cs->enemyNum < 0) { if (!ent->client->ps.torsoTimer) { return AIFunc_DefaultStart(cs); } return NULL; } // record weapon fire cs->weaponFireTimes[cs->weaponNum] = level.time; if (!ent->client->ps.torsoTimer) { return AIFunc_DefaultStart(cs); } if (ent->count2 && lastRaise < level.time - HEINRICH_RAISEDEAD_DELAY) { lastRaise = level.time; // summons the closest warrior closest = NULL; closestDist = 0; // shutup the compiler for (i = 0, trav = g_entities; i < level.maxclients; i++, trav++) { if (!trav->inuse) { continue; } if (!trav->aiInactive) { continue; } if (trav->aiCharacter != AICHAR_WARZOMBIE) { continue; } dist = VectorDistance(trav->s.pos.trBase, enemy->r.currentOrigin); if (!closest || dist < closestDist) { closest = trav; closestDist = dist; } } if (closest) { closest->AIScript_AlertEntity(closest); // make them aware of the player AICast_UpdateVisibility(closest, enemy, qtrue, qtrue); // reduce the count ent->count2--; } } return NULL; }
char *AIFunc_ZombieFlameAttack( cast_state_t *cs ) { gentity_t *ent; // ent = &g_entities[cs->entityNum]; // ent->s.onFireEnd = level.time + 2000; // if ( ent->health < 0 ) { ent->s.onFireEnd = 0; return AIFunc_DefaultStart( cs ); } // if ( cs->bs->enemy < 0 ) { ent->s.onFireEnd = level.time + 1500; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return AIFunc_DefaultStart( cs ); } // if outside range, move closer if ( VectorDistance( cs->bs->origin, cs->vislist[cs->bs->enemy].visible_pos ) > ZOMBIE_FLAME_RADIUS ) { ent->s.onFireEnd = level.time + 1500; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return AIFunc_DefaultStart( cs ); } // we are firing this weapon, so record it cs->weaponFireTimes[WP_MONSTER_ATTACK1] = level.time; // once an attack has started, only abort once the player leaves our view, or time runs out if ( cs->thinkFuncChangeTime < level.time - ZOMBIE_FLAME_DURATION ) { // finish this attack ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return AIFunc_DefaultStart( cs ); } else { ent->client->ps.torsoTimer = 400; //ent->client->ps.legsTimer = 400; // draw the client-side effect ent->client->ps.eFlags |= EF_MONSTER_EFFECT3; // keep facing them AICast_AimAtEnemy( cs ); // look slightly downwards since animation is facing upwards slightly cs->bs->ideal_viewangles[PITCH] += 10; } // // return NULL; }
qboolean TooCloseToOtherSpawnpoint ( int flagnum, vec3_t origin ) { int i = 0; for (i = 0;i < flag_list[flagnum].num_spawnpoints;i++) { if (VectorDistance(flag_list[flagnum].spawnpoints[i], origin) < 64) return qtrue; } return qfalse; }
static void LookingAtEnemyLogic(gedict_t* self) { if (Visible_360(self, self->fb.look_object)) { if (self->fb.look_object == &g_edicts[self->s.v.enemy]) { self->fb.enemy_dist = VectorDistance (self->fb.look_object->s.v.origin, self->s.v.origin); } else if (PAST(enemy_time)) { ClearLookObject(self); } } else { ClearLookObject(self); } }
void GTH_GetRealPosition( vec3_t position, float dist ) { vec3_t pos; float realDist; realDist = VectorDistance( position, g_pApp->m_myCharacter->position ); if( dist > realDist ) return; VectorSubtract( pos, position, g_pApp->m_myCharacter->position ); VectorNormalize( pos ); VectorScale( pos, pos, dist ); VectorAdd( position, pos, g_pApp->m_myCharacter->position ); }
void AI_CheckMakeEnemy( edict_t *self, edict_t *other ) { if (other != self->enemy && other->cast_group != self->cast_group && other->enemy == self) { // make them our enemy now if ( !self->enemy || !(self->cast_info.aiflags & AI_MELEE) || VectorDistance(self->s.origin, other->s.origin) < 128) { if (level.global_cast_memory[self->character_index][other->character_index]) self->enemy = other; } } }
qboolean R_Shader_IsLightInScopeByLeaf( unsigned int lightIndex, mleaf_t *leaf ) { const R_ShaderLight *light = GetLightFromIndex( lightIndex ); if( !light->active ) { return false; } if( !R_Shader_IsLightVisibleFromLeaf( light, leaf ) ) { return false; } // bounding sphere check { vec3_t midPoint; float boundingSphereRadius; VectorLerp( &leaf->minmaxs[ 0 ], 0.5f, &leaf->minmaxs[ 3 ], midPoint ); boundingSphereRadius = VectorDistance( &leaf->minmaxs[ 0 ], midPoint ); if( VectorDistance( light->origin, midPoint ) > light->maxDistance + boundingSphereRadius ) { return false; } } return true; }
qboolean R_Shader_IsLightInScopeByPoint( unsigned int lightIndex, const vec3_t renderOrigin ) { const R_ShaderLight *light = GetLightFromIndex( lightIndex ); mleaf_t *leaf; if( !light->active ) { return false; } if( VectorDistance( light->origin, renderOrigin ) > light->maxDistance ) { return false; } leaf = Mod_PointInLeaf( (float*)renderOrigin, cl.worldmodel ); if( leaf == NULL ) { return true; } return R_Shader_IsLightVisibleFromLeaf( light, leaf ); }
const char *AIFunc_Heinrich_SpawnSpiritsStart( cast_state_t *cs ) { gentity_t *ent = &g_entities[cs->entityNum]; gentity_t *trav, *spirits; float circleDist; // // enable all the spirit spawners trav = NULL; // TTimo: gcc: suggest () around assignment used as truth value while ( ( trav = G_Find( trav, FOFS( classname ), "func_bats" ) ) ) { if ( !trav->active && trav->spawnflags & 4 ) { trav->active = 1; // let them release spirits now } } // is the player outside the circle? trav = NULL; // TTimo: gcc: suggest () around assignment used as truth value while ( ( trav = G_Find( trav, FOFS( classname ), "func_bats" ) ) ) { if ( trav->spawnflags & 4 ) { spirits = trav; circleDist = trav->radius; trav = G_Find( NULL, FOFS( targetname ), trav->target ); if ( trav ) { if ( VectorDistance( g_entities[0].s.pos.trBase, trav->s.origin ) > circleDist ) { cs->aiFlags &= ~AIFL_MISCFLAG1; ent->count2 = 0; cs->aiFlags |= AIFL_SPECIAL_FUNC; // start the animation BG_PlayAnimName( &ent->client->ps, "attack4", ANIM_BP_BOTH, qtrue, qfalse, qtrue ); // play the sound G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_RAISEDEAD_START] ); // start the func cs->aifunc = AIFunc_Heinrich_RaiseDead; // just do raise dead, without raising any warriors return "AIFunc_Heinrich_RaiseDead"; } } break; } } // return NULL; }
int CCam::nearestEntity(void) { distance = 100000; for(int i = 0; i < numFramePlayers; i++) { int clientNum = framePlayers[i]; player_t *player = ð32.cg.players[clientNum]; float d = VectorDistance(eth32.cg.refdef->vieworg, player->orHead.origin); if(!player->friendly) { if(d < distance) { distance = d; return player->clientNum; } } } return -1; }
static void demoEffectDrawPath( demoEffectPoint_t *point, const vec4_t color) { int i; polyVert_t verts[4]; qboolean skipFirst = qtrue; vec3_t origin, lastOrigin; demoEffectPoint_t *match[4]; vec3_t control[4]; float lerp, lerpFactor; int len, steps; int times[4] = {0, 1, 2, 3}; demoEffectPointMatch( point, CAM_ORIGIN, match ); if (match[1] != point) return; if (!match[2]) return; demoEffectMatchOrigin( match, control ); len = VectorDistance( control[1], control[2] ); steps = len / 25; if (steps < 5) steps = 5; demoDrawSetupVerts( verts, color ); lerpFactor = 0.9999f / steps; for ( i = 0; i <= steps; i++) { lerp = i * lerpFactor; VectorTimeSpline( lerp, times, control[0], origin, 3); if (skipFirst) { skipFirst = qfalse; VectorCopy( origin, lastOrigin ); continue; } demoDrawRawLine( origin, lastOrigin, 1, verts ); VectorCopy( origin, lastOrigin); } }
void ForceEnergy(Particle *p1, Particle *p2, int pbc_x, int pbc_y){ if(pbc_x != 0) p1->position.x -= GRIDSIZE; if(pbc_y != 0) p1->position.y -= GRIDSIZE; double distance = VectorDistance(p1->position, p2->position); if (distance >= RCUT) { if(pbc_x != 0) p1->position.x += GRIDSIZE; if(pbc_y != 0) p1->position.y += GRIDSIZE; return; } double force = (2.0*REPULSIVE_CST*fabs(distance-RCUT)/SQR(RCUT)); Vector relative_position; relative_position.x = (p1->position.x - p2->position.x); relative_position.y = (p1->position.y - p2->position.y); Vector forceVector; forceVector.x = relative_position.x * force/distance; forceVector.y = relative_position.y * force/distance; p1->force[1].x += forceVector.x; p1->force[1].y += forceVector.y; p2->force[1].x -= forceVector.x; p2->force[1].y -= forceVector.y; // Potential and pressure are summed over all particles later, // there is no need to explicitly save p2->potential or p2->pressure p1->potential += REPULSIVE_CST*SQR(distance-RCUT)/SQR(RCUT); p1->pressure_contribution += 2*(forceVector.x*relative_position.x + forceVector.y*relative_position.y) / (2 * SQR(GRIDSIZE)); int rdf_bin_index = NUMBER_OF_BINS*distance/RCUT; p1->radial_distribution[rdf_bin_index] += 2; if(pbc_x != 0) p1->position.x += GRIDSIZE; if(pbc_y != 0) p1->position.y += GRIDSIZE; }
void GTH_GetRealMousePosition( vec3_t mousePos, vec3_t position ) { vec3_t pos; float dist; dist = VectorDistance( mousePos, g_pApp->m_myCharacter->position ); dist -= g_cgv.mouseClickEventDistance; if( g_cgv.clickEvent == GTH_CEV_CHAR_IDLE || g_cgv.clickEvent == GTH_CEV_CHAR_NONE ) { VectorCopy( position, mousePos ); return; } else if( dist < 0.0f ) { VectorCopy( position, g_pApp->m_myCharacter->position ); return; } VectorSubtract( pos, mousePos, g_pApp->m_myCharacter->position ); VectorNormalize( pos ); VectorScale( pos, pos, dist ); VectorAdd( position, pos, g_pApp->m_myCharacter->position ); }
int Aimbot::FindTarget() // This is the aim filter, here we pick the best possible aim target avaible { // Invalidate target int iTarget = INVALID_TARGET; float flClosestTarget = 99999999.0f; // Loop players and get best target for (int i = 0; i <= MAX_CLIENTS; ++i) { // Valid if (ValidAimTarget(i) == false) continue; // Go by distance float flDistance = VectorDistance(g_Local.EyePosition, g_Player[i].AimOrigin); if (flDistance < flClosestTarget) { iTarget = i; flClosestTarget = flDistance; } } return iTarget; }
qboolean CG_DisguiseMapCheck(mapEntityData_t *mEnt) { if (mEnt->data < 0 || mEnt->data >= 64) { return qfalse; } if (!cgs.clientinfo[mEnt->data].infoValid) { return qfalse; } if (!(cg_entities[mEnt->data].currentState.powerups & (1 << PW_OPS_DISGUISED))) { return qfalse; } if (VectorDistance(cg.snap->ps.origin, cg_entities[mEnt->data].lerpOrigin) < 512) { return qfalse; } return qtrue; }
void CG_AddTrailToScene(trailJunc_t *trail, int iteration, int numJuncs) { #define MAX_TRAIL_VERTS 2048 polyVert_t verts[MAX_TRAIL_VERTS]; polyVert_t outVerts[MAX_TRAIL_VERTS * 3]; int k, i, n, l, numOutVerts; polyVert_t mid; float mod[4]; float sInc = 0.0f, s = 0.0f; // TTimo: init trailJunc_t *j, *jNext; vec3_t fwd, up, p, v; (void)fwd; // Ignore compiler warning -- Justasic // clipping vars #define TRAIL_FADE_CLOSE_DIST 64.0 #define TRAIL_FADE_FAR_SCALE 4.0 vec3_t viewProj; float viewDist, fadeAlpha; // add spark shader at head position if(trail->flags & TJFL_SPARKHEADFLARE) { j = trail; VectorCopy(j->pos, p); VectorMA(p, -j->width * 2, vup, p); VectorMA(p, -j->width * 2, vright, p); VectorCopy(p, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = (unsigned char)(j->alpha * 255.0); VectorCopy(j->pos, p); VectorMA(p, -j->width * 2, vup, p); VectorMA(p, j->width * 2, vright, p); VectorCopy(p, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = (unsigned char)(j->alpha * 255.0); VectorCopy(j->pos, p); VectorMA(p, j->width * 2, vup, p); VectorMA(p, j->width * 2, vright, p); VectorCopy(p, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = (unsigned char)(j->alpha * 255.0); VectorCopy(j->pos, p); VectorMA(p, j->width * 2, vup, p); VectorMA(p, -j->width * 2, vright, p); VectorCopy(p, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = (unsigned char)(j->alpha * 255.0); trap_R_AddPolyToScene(cgs.media.sparkFlareShader, 4, verts); } // if (trail->flags & TJFL_CROSSOVER && iteration < 1) { // iteration = 1; // } if(!numJuncs) { // first count the number of juncs in the trail j = trail; numJuncs = 0; sInc = 0; while(j) { numJuncs++; // check for a dead next junc if(!j->inuse && j->nextJunc && !j->nextJunc->inuse) { CG_KillTrail(j); } else if(j->nextJunc && j->nextJunc->freed) { // not sure how this can happen, but it does, and causes infinite loops j->nextJunc = NULL; } if(j->nextJunc) { sInc += VectorDistance(j->nextJunc->pos, j->pos); } j = j->nextJunc; } } if(numJuncs < 2) { return; } if(trail->sType == STYPE_STRETCH) { //sInc = ((1.0 - 0.1) / (float)(numJuncs)); // hack, the end of funnel shows a bit of the start (looping) s = 0.05; //s = 0.05; } else if(trail->sType == STYPE_REPEAT) { s = trail->sTex; } // now traverse the list j = trail; jNext = j->nextJunc; i = 0; while(jNext) { // first get the directional vectors to the next junc VectorSubtract(jNext->pos, j->pos, fwd); GetPerpendicularViewVector(cg.refdef.vieworg, j->pos, jNext->pos, up); // if it's a crossover, draw it twice if(j->flags & TJFL_CROSSOVER) { if(iteration > 0) { ProjectPointOntoVector(cg.refdef.vieworg, j->pos, jNext->pos, viewProj); VectorSubtract(cg.refdef.vieworg, viewProj, v); VectorNormalize(v); if(iteration == 1) { VectorMA(up, 0.3, v, up); } else { VectorMA(up, -0.3, v, up); } VectorNormalize(up); } } // do fading when moving towards the projection point onto the trail segment vector else if(!(j->flags & TJFL_NOCULL) && (j->widthEnd > 4 || jNext->widthEnd > 4)) { ProjectPointOntoVector(cg.refdef.vieworg, j->pos, jNext->pos, viewProj); viewDist = Distance(viewProj, cg.refdef.vieworg); if(viewDist < (TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE)) { if(viewDist < TRAIL_FADE_CLOSE_DIST) { fadeAlpha = 0.0; } else { fadeAlpha = (viewDist - TRAIL_FADE_CLOSE_DIST) / (TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE); } if(fadeAlpha < j->alpha) { j->alpha = fadeAlpha; } if(fadeAlpha < jNext->alpha) { jNext->alpha = fadeAlpha; } } } // now output the QUAD for this segment // 1 ---- VectorMA(j->pos, 0.5 * j->width, up, p); VectorCopy(p, verts[i].xyz); verts[i].st[0] = s; verts[i].st[1] = 1.0; for(k = 0; k < 3; k++) verts[i].modulate[k] = (unsigned char)(j->color[k] * 255.0); verts[i].modulate[3] = (unsigned char)(j->alpha * 255.0); // blend this with the previous junc if(j != trail) { VectorAdd(verts[i].xyz, verts[i - 1].xyz, verts[i].xyz); VectorScale(verts[i].xyz, 0.5, verts[i].xyz); VectorCopy(verts[i].xyz, verts[i - 1].xyz); } else if(j->flags & TJFL_FADEIN) { verts[i].modulate[3] = 0; // fade in } i++; // 2 ---- VectorMA(p, -1 * j->width, up, p); VectorCopy(p, verts[i].xyz); verts[i].st[0] = s; verts[i].st[1] = 0.0; for(k = 0; k < 3; k++) verts[i].modulate[k] = (unsigned char)(j->color[k] * 255.0); verts[i].modulate[3] = (unsigned char)(j->alpha * 255.0); // blend this with the previous junc if(j != trail) { VectorAdd(verts[i].xyz, verts[i - 3].xyz, verts[i].xyz); VectorScale(verts[i].xyz, 0.5, verts[i].xyz); VectorCopy(verts[i].xyz, verts[i - 3].xyz); } else if(j->flags & TJFL_FADEIN) { verts[i].modulate[3] = 0; // fade in } i++; if(trail->sType == STYPE_REPEAT) { s = jNext->sTex; } else { //s += sInc; s += VectorDistance(j->pos, jNext->pos) / sInc; if(s > 1.0) { s = 1.0; } } // 3 ---- VectorMA(jNext->pos, -0.5 * jNext->width, up, p); VectorCopy(p, verts[i].xyz); verts[i].st[0] = s; verts[i].st[1] = 0.0; for(k = 0; k < 3; k++) verts[i].modulate[k] = (unsigned char)(jNext->color[k] * 255.0); verts[i].modulate[3] = (unsigned char)(jNext->alpha * 255.0); i++; // 4 ---- VectorMA(p, jNext->width, up, p); VectorCopy(p, verts[i].xyz); verts[i].st[0] = s; verts[i].st[1] = 1.0; for(k = 0; k < 3; k++) verts[i].modulate[k] = (unsigned char)(jNext->color[k] * 255.0); verts[i].modulate[3] = (unsigned char)(jNext->alpha * 255.0); i++; if(i + 4 > MAX_TRAIL_VERTS) { break; } j = jNext; jNext = j->nextJunc; } if(trail->flags & TJFL_FIXDISTORT) { // build the list of outVerts, by dividing up the QUAD's into 4 Tri's each, so as to allow // any shaped (convex) Quad without bilinear distortion for(k = 0, numOutVerts = 0; k < i; k += 4) { VectorCopy(verts[k].xyz, mid.xyz); mid.st[0] = verts[k].st[0]; mid.st[1] = verts[k].st[1]; for(l = 0; l < 4; l++) { mod[l] = (float)verts[k].modulate[l]; } for(n = 1; n < 4; n++) { VectorAdd(verts[k + n].xyz, mid.xyz, mid.xyz); mid.st[0] += verts[k + n].st[0]; mid.st[1] += verts[k + n].st[1]; for(l = 0; l < 4; l++) { mod[l] += (float)verts[k + n].modulate[l]; } } VectorScale(mid.xyz, 0.25, mid.xyz); mid.st[0] *= 0.25; mid.st[1] *= 0.25; for(l = 0; l < 4; l++) { mid.modulate[l] = (unsigned char)(mod[l] / 4.0); } // now output the tri's for(n = 0; n < 4; n++) { outVerts[numOutVerts++] = verts[k + n]; outVerts[numOutVerts++] = mid; if(n < 3) { outVerts[numOutVerts++] = verts[k + n + 1]; } else { outVerts[numOutVerts++] = verts[k]; } } } if(!(trail->flags & TJFL_NOPOLYMERGE)) { trap_R_AddPolysToScene(trail->shader, 3, &outVerts[0], numOutVerts / 3); } else { int k; for(k = 0; k < numOutVerts / 3; k++) { trap_R_AddPolyToScene(trail->shader, 3, &outVerts[k * 3]); } } } else { // send the polygons // FIXME: is it possible to send a GL_STRIP here? We are actually sending 2x the verts we really need to if(!(trail->flags & TJFL_NOPOLYMERGE)) { trap_R_AddPolysToScene(trail->shader, 4, &verts[0], i / 4); } else { int k; for(k = 0; k < i / 4; k++) { trap_R_AddPolyToScene(trail->shader, 4, &verts[k * 4]); } } } // do we need to make another pass? if(trail->flags & TJFL_CROSSOVER) { if(iteration < 2) { CG_AddTrailToScene(trail, iteration + 1, numJuncs); } } }
/* ============ AICast_Blocked ============ */ void AICast_Blocked( cast_state_t *cs, bot_moveresult_t *moveresult, int activate, bot_goal_t *goal ) { vec3_t pos, dir; aicast_predictmove_t move; usercmd_t ucmd; bot_input_t bi; cast_state_t *ocs; int i, blockEnt = -1; bot_goal_t ogoal; if ( cs->blockedAvoidTime < level.time ) { if ( cs->blockedAvoidTime < level.time - 300 ) { if ( VectorCompare( cs->bs->cur_ps.velocity, vec3_origin ) && !cs->bs->lastucmd.forwardmove && !cs->bs->lastucmd.rightmove ) { // not moving, don't bother checking cs->blockedAvoidTime = level.time - 1; return; } // are we going to hit someone soon? trap_EA_GetInput( cs->entityNum, (float) level.time / 1000, &bi ); AICast_InputToUserCommand( cs, &bi, &ucmd, cs->bs->cur_ps.delta_angles ); AICast_PredictMovement( cs, 1, 0.6, &move, &ucmd, ( goal && goal->entitynum > -1 ) ? goal->entitynum : cs->entityNum ); // blocked if we hit a client (or non-stationary mover) other than our enemy or goal if ( move.stopevent != PREDICTSTOP_HITCLIENT ) { // not blocked cs->blockedAvoidTime = level.time - 1; return; } // if we stopped passed our goal, ignore it if ( goal ) { if ( VectorDistance( cs->bs->origin, goal->origin ) < VectorDistance( cs->bs->origin, move.endpos ) ) { vec3_t v1, v2; VectorSubtract( goal->origin, cs->bs->origin, v1 ); VectorSubtract( goal->origin, move.endpos, v2 ); VectorNormalize( v1 ); VectorNormalize( v2 ); if ( DotProduct( v1, v2 ) < 0 ) { // we went passed the goal, so assume we can reach it cs->blockedAvoidTime = level.time - 1; return; } } } // try and get them to move, in case we can't get around them blockEnt = -1; for ( i = 0; i < move.numtouch; i++ ) { if ( move.touchents[i] >= MAX_CLIENTS ) { if ( !Q_stricmp( g_entities[move.touchents[i]].classname, "script_mover" ) ) { // avoid script_mover's blockEnt = move.touchents[i]; } // if we are close to the impact point, then avoid this entity else if ( VectorDistance( cs->bs->origin, move.endpos ) < 10 ) { //G_Printf("AI (%s) avoiding %s\n", g_entities[cs->entityNum].aiName, g_entities[move.touchents[i]].classname ); blockEnt = move.touchents[i]; } continue; } // ocs = AICast_GetCastState( move.touchents[i] ); if ( !ocs->bs ) { blockEnt = move.touchents[i]; } // reject this blocker if we are following or going to them else if ( cs->followEntity != ocs->entityNum ) { // if they are moving away from us already, let them go if ( VectorLength( ocs->bs->cur_ps.velocity ) > 10 ) { vec3_t v1, v2; VectorSubtract( ocs->bs->origin, cs->bs->origin, v2 ); VectorNormalize( v2 ); VectorNormalize2( ocs->bs->cur_ps.velocity, v1 ); if ( DotProduct( v1, v2 ) > 0.0 ) { continue; } } // // if they recently were asked to avoid us, then they're probably not listening if ( ocs->obstructingTime > level.time - 500 ) { blockEnt = move.touchents[i]; } // // if they are not avoiding, ignore if ( !( ocs->aiFlags & AIFL_NOAVOID ) ) { continue; } // // they should avoid us if ( ocs->leaderNum >= 0 ) { ogoal.entitynum = ocs->leaderNum; VectorCopy( g_entities[ocs->leaderNum].r.currentOrigin, ogoal.origin ); if ( AICast_GetAvoid( ocs, &ogoal, ocs->obstructingPos, qfalse, cs->entityNum ) ) { // give them time to move somewhere else ocs->obstructingTime = level.time + 1000; } else { // make sure they don't call GetAvoid() for another few frames to let others avoid also ocs->obstructingTime = level.time - 1; blockEnt = move.touchents[i]; } } else { if ( AICast_GetAvoid( ocs, NULL, ocs->obstructingPos, qfalse, cs->entityNum ) ) { // give them time to move somewhere else ocs->obstructingTime = level.time + 1000; } else { // make sure they don't call GetAvoid() for another few frames to let others avoid also ocs->obstructingTime = level.time - 1; blockEnt = move.touchents[i]; } } } } } else { return; } if ( blockEnt < 0 ) { // nothing found to be worth avoding cs->blockedAvoidTime = level.time - 1; return; } // something is blocking our path if ( g_entities[blockEnt].aiName && g_entities[blockEnt].client ) { int oldId = cs->castScriptStatus.scriptId; AICast_ScriptEvent( cs, "blocked", g_entities[blockEnt].aiName ); if ( oldId != cs->castScriptStatus.scriptId ) { // the script has changed, so assume the scripting is handling the avoidance return; } } // avoid geometry and props, but assume clients will get out the way if ( /*blockEnt > MAX_CLIENTS &&*/ AICast_GetAvoid( cs, goal, pos, qfalse, blockEnt ) ) { VectorSubtract( pos, cs->bs->cur_ps.origin, dir ); VectorNormalize( dir ); cs->blockedAvoidYaw = vectoyaw( dir ); if ( blockEnt >= MAX_CLIENTS ) { cs->blockedAvoidTime = level.time + 100 + rand() % 200; } else { cs->blockedAvoidTime = level.time + 300 + rand() % 400; } } else { cs->blockedAvoidTime = level.time - 1; // don't look again for another few frames return; } } VectorClear( pos ); pos[YAW] = cs->blockedAvoidYaw; AngleVectors( pos, dir, NULL, NULL ); if ( moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE ) { trap_EA_Jump( cs->bs->entitynum ); } trap_EA_Move( cs->bs->entitynum, dir, 200 ); //400); vectoangles( dir, cs->bs->ideal_viewangles ); cs->bs->ideal_viewangles[2] *= 0.5; }
void SV_LinkEdict(edict_t *ent) { guard(SV_LinkEdict); int i, j, k; //!! HOOK - move outside ? if (bspfile.type != map_q2) { if (ent->s.modelindex >= 0 && ent->s.modelindex < MAX_MODELS) { // link model hook const char *modelName = sv.configstrings[CS_MODELS + ent->s.modelindex]; if (!strcmp(modelName, "models/objects/dmspot/tris.md2")) { // teleporter (source+target) was found // appPrintf(S_CYAN"teleport: %g %g %g\n", VECTOR_ARG(ent->s.origin)); return; // simply do not link model; trigger entity will be added anyway } } } if (ent->area.prev) SV_UnlinkEdict(ent); // unlink from old position (i.e. relink edict) if (ent == ge->edicts) return; // don't add the world if (!ent->inuse) return; entityHull_t &ex = ents[NUM_FOR_EDICT(ent)]; memset(&ex, 0, sizeof(entityHull_t)); ex.owner = ent; ex.axis.FromEuler(ent->s.angles); // set the size VectorSubtract(ent->bounds.maxs, ent->bounds.mins, ent->size); // encode the size into the entity_state for client prediction if (ent->solid == SOLID_BBOX) { // assume that x/y are equal and symetric i = appRound(ent->bounds.maxs[0] / 8); // z is not symetric j = appRound(-ent->bounds.mins[2] / 8); // and z maxs can be negative... k = appRound((ent->bounds.maxs[2] + 32) / 8); // original Q2 have bounded i/j/k/ with lower margin==1 (for client prediction only); this will // produce incorrect collision test when bbox mins/maxs is (0,0,0) i = bound(i, 0, 31); // mins/maxs[0,1] range is -248..0/0..248 j = bound(j, 0, 31); // mins[2] range is [-248..0] k = bound(k, 0, 63); // maxs[2] range is [-32..472] // if SVF_DEADMONSTER, s.solid should be 0 ent->s.solid = (ent->svflags & SVF_DEADMONSTER) ? 0 : (k<<10) | (j<<5) | i; i *= 8; j *= 8; k *= 8; ex.bounds.mins.Set(-i, -i, -j); ex.bounds.maxs.Set(i, i, k - 32); ex.bounds.GetCenter(ex.center); ex.center.Add(ent->s.origin); ex.model = NULL; ex.radius = VectorDistance(ex.bounds.maxs, ex.bounds.mins) / 2; } else if (ent->solid == SOLID_BSP) { ex.model = sv.models[ent->s.modelindex]; if (!ex.model) Com_DropError("MOVETYPE_PUSH with a non bsp model"); CVec3 v; ex.model->bounds.GetCenter(v); UnTransformPoint(ent->s.origin, ex.axis, v, ex.center); ex.radius = ex.model->radius; ent->s.solid = 31; // a SOLID_BBOX will never create this value (mins=(-248,-248,0) maxs=(248,248,-32)) } else if (ent->solid == SOLID_TRIGGER) { ent->s.solid = 0; // check for model link ex.model = sv.models[ent->s.modelindex]; if (!ex.model) { // model not attached by game, check entstring //?? can optimize: add 'bool spawningEnts', set to 'true' before SpawnEntities() //?? and 'false' after; skip code below when 'false' for (triggerModelLink_t *link = bspfile.modelLinks; link; link = link->next) #define CMP(n) (fabs(ent->s.origin[n] - link->origin[n]) < 0.5f) if (CMP(0) && CMP(1) && CMP(2)) { CBspModel *model = CM_InlineModel(link->modelIdx); VectorSubtract(model->bounds.maxs, ent->s.origin, ent->bounds.maxs); VectorSubtract(model->bounds.mins, ent->s.origin, ent->bounds.mins); break; } #undef CMP } } else ent->s.solid = 0; // set the abs box if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2])) { // expand for rotation for (i = 0; i < 3 ; i++) { ent->absBounds.mins[i] = ex.center[i] - ex.radius; ent->absBounds.maxs[i] = ex.center[i] + ex.radius; } } else { // normal VectorAdd(ent->s.origin, ent->bounds.mins, ent->absBounds.mins); VectorAdd(ent->s.origin, ent->bounds.maxs, ent->absBounds.maxs); } // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch for (i = 0; i < 3; i++) { ent->absBounds.mins[i] -= 1; ent->absBounds.maxs[i] += 1; } // link to PVS leafs ent->num_clusters = 0; ent->zonenum = 0; ent->zonenum2 = 0; // get all leafs, including solids CBspLeaf *leafs[MAX_TOTAL_ENT_LEAFS]; int topnode; int num_leafs = CM_BoxLeafs(ent->absBounds, ARRAY_ARG(leafs), &topnode); // set zones int clusters[MAX_TOTAL_ENT_LEAFS]; for (i = 0; i < num_leafs; i++) { clusters[i] = leafs[i]->cluster; int zone = leafs[i]->zone; if (zone) { // doors may legally straggle two zones, // but nothing should evern need more than that if (ent->zonenum && ent->zonenum != zone) { if (ent->zonenum2 && ent->zonenum2 != zone && sv.state == ss_loading) Com_DPrintf("Object touching 3 zones at %g %g %g\n", VECTOR_ARG(ent->absBounds.mins)); ent->zonenum2 = zone; } else ent->zonenum = zone; } } if (num_leafs >= MAX_TOTAL_ENT_LEAFS) { // assume we missed some leafs, and mark by headnode ent->num_clusters = -1; ent->headnode = topnode; } else { ent->num_clusters = 0; for (i = 0; i < num_leafs; i++) { if (clusters[i] == -1) continue; // not a visible leaf for (j = 0; j < i; j++) if (clusters[j] == clusters[i]) break; if (j == i) { if (ent->num_clusters == MAX_ENT_CLUSTERS) { // assume we missed some leafs, and mark by headnode ent->num_clusters = -1; ent->headnode = topnode; break; } ent->clusternums[ent->num_clusters++] = clusters[i]; } } } // if first time, make sure old_origin is valid if (!ent->linkcount) ent->s.old_origin = ent->s.origin; ent->linkcount++; if (ent->solid == SOLID_NOT) return; // find the first node that the ent's box crosses areanode_t *node = areaNodes; while (node->axis != -1) { if (ent->absBounds.mins[node->axis] > node->dist) node = node->children[0]; else if (ent->absBounds.maxs[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in areanode_t *node2 = node; if (ent->solid == SOLID_TRIGGER) { InsertLinkBefore(ent->area, node->trigEdicts); for ( ; node2; node2 = node2->parent) node2->numTrigEdicts++; } else { InsertLinkBefore(ent->area, node->solidEdicts); for ( ; node2; node2 = node2->parent) node2->numSolidEdicts++; } ex.area = node; unguard; }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; int retval; vec3_t oldpos; // BEGIN: Xatrix/Ridah vec3_t old_vel; // END: Xatrix/Ridah // Joseph if (ent->fallerflag) { // Fix if sitting off center think_checkedges(ent); } // airborn monsters should always check for ground if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value*-0.1) hitsound = true; // Ridah, 1-may-99, disabled this to prevent guys getting stuck in water // if (ent->waterlevel == 0) SV_AddGravity (ent); } /* // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } */ // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } // BEGIN: Xatrix/Ridah // JOSEPH 26-APR-99 if ((ent->svflags & SVF_MONSTER) || (ent->monsterprop)) // END JOSEPH { // if (ent->cast_info.aiflags & AI_PLAYERCLIP) mask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP; // else // mask = MASK_MONSTERSOLID; } else mask = MASK_SOLID; VectorCopy (ent->velocity, old_vel); // END: Xatrix/Ridah VectorCopy (ent->s.origin, oldpos ); retval = SV_FlyMove (ent, FRAMETIME, mask); #if 0 // leave this here for now. // Ridah, HACK... sometimes they get stuck, we should debug this properly when we get the time if (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID )) { // move back to old position and clear velocity int iter=0; VectorCopy (oldpos, ent->s.origin); VectorClear (ent->velocity); // find a good position while (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID )) { VectorAdd( ent->s.origin, tv((random()-0.5) * 64, (random()-0.5) * 64, (random()-0.5) * 64), ent->s.origin ); if (++iter > 10) break; } // if (iter <= 4) // { // make sure they're on the ground // M_droptofloor( ent ); // } goto exit_vel_check; // get out of here? } #endif // BEGIN: Xatrix/Ridah if (!ent->groundentity || (ent->flags & FL_FLY)) { node_t *land_node; // Ridah, prevent guys getting stuck trying to jump if (VectorDistance( ent->s.origin, oldpos ) < 1 && !ent->groundentity && (ent->last_onground < (level.time - 2))) { ent->velocity[0] = crandom() * 300; ent->velocity[1] = crandom() * 300; if (ent->velocity[2] < -200) ent->velocity[2] = -200; ent->velocity[2] += random() * 350; ent->nav_data.goal_index = 0; ent->last_onground = level.time; } if (ent->velocity[2] > 80 && retval != 20) { // while rising, maintain XY velocity ent->velocity[0] = old_vel[0]; ent->velocity[1] = old_vel[1]; } // see if we've gone passed the landing position if ( !(ent->flags & FL_FLY) && (retval == -1) && (ent->nav_data.goal_index) && (land_node = level.node_data->nodes[ent->nav_data.goal_index-1])) // && (land_node->node_type & NODE_LANDING)) { vec3_t unit_vel, goal_dir, goal_vec; float vel_scale, dist; VectorSubtract( land_node->origin, ent->s.origin, goal_vec ); goal_vec[2] = 0; dist = VectorNormalize2( goal_vec, goal_dir ); if (dist > 16) { VectorCopy( ent->velocity, unit_vel ); unit_vel[2] = 0; vel_scale = VectorNormalize( unit_vel ); if (DotProduct( unit_vel, goal_dir ) < 0.8) { // we've either gone passed, or need some correction vec3_t new_pos; float old_z; if (VectorLength( goal_vec ) < 40) { new_pos[0] = land_node->origin[0]; new_pos[1] = land_node->origin[1]; new_pos[2] = ent->s.origin[2]; if (ValidBoxAtLoc( new_pos, ent->mins, ent->maxs, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID )) { // move there, it's safe, and clear velocity VectorCopy( new_pos, ent->s.origin ); ent->velocity[0] = ent->velocity[1] = 0; goto exit_vel_check; } } // we need to adjust our velocity if (land_node->origin[2] < (ent->s.origin[2] - 64)) { old_z = ent->velocity[2]; VectorScale( goal_dir, vel_scale, ent->velocity ); ent->velocity[2] = old_z; } } } } if ( (ent->flags & FL_FLY) && ((land_node = level.node_data->nodes[ent->nav_data.goal_index-1]) || ((ent->flags &= ~FL_FLY) && false)) /*&& (land_node->node_type & NODE_LANDING)*/) { // if climbing ladder, and we're reached the landing position, stop // Ridah, 8-jun-99, make sure dog's don't climb ladders if (!ent->gender) { goto abort_climb; } if (ent->s.origin[2] > land_node->origin[2]) { //gi.dprintf( "-> end of climb\n" ); // VectorSubtract( land_node->origin, ent->s.origin, ent->velocity ); AngleVectors( ent->s.angles, ent->velocity, NULL, NULL ); ent->velocity[2] = 0; VectorNormalize( ent->velocity ); VectorScale( ent->velocity, 96, ent->velocity ); ent->velocity[2] = 200; ent->flags &= ~FL_FLY; ent->nav_data.goal_index = 0; // look for a new node ent->nav_data.cache_node = -1; if (ent->cast_info.move_end_climb) ent->cast_info.currentmove = ent->cast_info.move_end_climb; } else { trace_t tr; vec3_t end, goal_vec; VectorSubtract( land_node->origin, ent->s.origin, goal_vec ); ent->velocity[0] = goal_vec[0]; ent->velocity[1] = goal_vec[1]; ent->velocity[2] = 120; // if another character is above us, abort VectorCopy( ent->s.origin, end ); end[2] += 128; tr = gi.trace( ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID ); if ((tr.fraction < 1) && (tr.ent->svflags & SVF_MONSTER)) { abort_climb: AngleVectors( ent->s.angles, goal_vec, NULL, NULL ); VectorScale( goal_vec, -64, ent->velocity ); ent->flags &= ~FL_FLY; ent->nav_data.goal_index = 0; if (ent->cast_info.move_end_climb) { ent->cast_info.currentmove = ent->cast_info.move_end_climb; } else if (ent->cast_info.move_jump) { ent->cast_info.currentmove = ent->cast_info.move_jump; } } else if (ent->s.origin[2] > (land_node->origin[2] - 48)) { // we're near the top, stopping climbing anim //gi.dprintf( "near end of climb\n" ); if (ent->cast_info.move_end_climb) ent->cast_info.currentmove = ent->cast_info.move_end_climb; // add some forward momentum AngleVectors( ent->s.angles, goal_vec, NULL, NULL ); VectorMA( ent->velocity, 64, goal_vec, ent->velocity ); } } } } exit_vel_check: // END: Xatrix/Ridah gi.linkentity (ent); G_TouchTriggers (ent); // Note to Ryan: we can't use this because we are playing specific sounds elsewhere /* if (ent->groundentity) if (!wasonground) if (hitsound) // BEGIN: Xatrix/Ridah/Navigator/03-apr-1998 if (!(ent->cast_info.move_run)) // END: Xatrix/Ridah/Navigator/03-apr-1998 gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); */ } // regular thinking SV_RunThink (ent); }
bool AvHOrder::Update() { bool theOrderJustCompleted = false; ASSERT(this->GetReceiver() != -1 ); if(this->GetOrderActive()) { bool theOrderIsComplete = false; AvHPlayer* thePlayer = NULL; vec3_t theOrderLocation; this->GetLocation(theOrderLocation); EntityInfo theReceiver = this->GetReceiver(); float theDistance; const float kMoveToDistance = 90; const float kPickupDistance = 20; CBaseEntity* theTargetEntity = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(this->mTargetIndex)); AvHBaseBuildable* theTargetBuildable = dynamic_cast<AvHBaseBuildable*>(theTargetEntity); AvHPlayer* theTargetPlayer = dynamic_cast<AvHPlayer*>(theTargetEntity); AvHWeldable* theWeldable = dynamic_cast<AvHWeldable*>(theTargetEntity); switch(this->mOrderType) { case ORDERTYPE_UNDEFINED: default: break; case ORDERTYPEL_MOVE: // set true if all receivers are within a certain distance of move to order theTargetPlayer = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theReceiver))); if(theTargetPlayer) { theOrderIsComplete = true; theDistance = VectorDistance(theTargetPlayer->pev->origin, theOrderLocation); if(!theTargetPlayer->GetIsRelevant() || (theDistance > kMoveToDistance)) { theOrderIsComplete = false; } } if(theOrderIsComplete) { this->mOrderStatus = kOrderStatusComplete; } break; case ORDERTYPET_GET: // set true if all receivers are within a certain distance of item theTargetPlayer = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theReceiver))); if(theTargetPlayer) { // If one of the players in the group is near enough to pick it up theDistance = VectorDistance(theTargetPlayer->pev->origin, theOrderLocation); if(theTargetPlayer->GetIsRelevant() && (theDistance < kPickupDistance)) { theOrderIsComplete = true; } } // If the item is gone, the order is done if(!theTargetEntity) { this->mOrderStatus = kOrderStatusCancelled; } break; case ORDERTYPET_ATTACK: // set true if target is dead or not relevant if(!theTargetEntity || (theTargetPlayer && !theTargetPlayer->GetIsRelevant())) { this->mOrderStatus = kOrderStatusCancelled; theOrderIsComplete = true; } else if(theTargetEntity && !theTargetEntity->IsAlive()) { this->mOrderStatus = kOrderStatusComplete; theOrderIsComplete = true; } break; case ORDERTYPET_BUILD: if(!theTargetEntity || !theTargetEntity->IsAlive()) { this->mOrderStatus = kOrderStatusCancelled; theOrderIsComplete = true; } else if(theTargetBuildable && theTargetBuildable->GetIsBuilt()) { this->mOrderStatus = kOrderStatusComplete; theOrderIsComplete = true; } else { if(theTargetEntity) { bool theIsBuilding; bool theIsResearching; float thePercentage; AvHSHUGetBuildResearchState(theTargetEntity->pev->iuser3, theTargetEntity->pev->iuser4, theTargetEntity->pev->fuser1, theIsBuilding, theIsResearching, thePercentage); if(!theIsBuilding && (thePercentage == 1.0f)) { this->mOrderStatus = kOrderStatusComplete; theOrderIsComplete = true; } } } break; case ORDERTYPET_GUARD: theOrderIsComplete = false; if(!theTargetEntity ||!theTargetEntity->IsAlive()) { this->mOrderStatus = kOrderStatusCancelled; theOrderIsComplete = true; } break; case ORDERTYPET_WELD: //ALERT(at_console, "Checking weldables "); // set true when target is fully welded if(!theTargetEntity ||!theTargetEntity->IsAlive()) { this->mOrderStatus = kOrderStatusCancelled; theOrderIsComplete = true; } if(theWeldable && theWeldable->GetIsWelded()) { this->mOrderStatus = kOrderStatusComplete; theOrderIsComplete = true; } else if ( !theWeldable ) { if ( theTargetEntity->pev->iuser3 == AVH_USER3_MARINE_PLAYER ) { // Players are welded if they have full armour if ( theTargetEntity->pev->armorvalue == AvHPlayerUpgrade::GetMaxArmorLevel(theTargetEntity->pev->iuser4, (AvHUser3)theTargetEntity->pev->iuser3)) { this->mOrderStatus = kOrderStatusComplete; theOrderIsComplete = true; } } else { // Structures are welded if they have full health if ( theTargetEntity->pev->health == theTargetEntity->pev->max_health ) { this->mOrderStatus = kOrderStatusComplete; theOrderIsComplete = true; } } } break; } if(theOrderIsComplete) { this->SetOrderCompleted(); theOrderJustCompleted = true; } } return theOrderJustCompleted; }
void PreCalculate_Flag_Spawnpoints( int flagnum, vec3_t angles, vec3_t origin ) { vec3_t fwd, point; int tries = 0, tries2 = 0; qboolean visible = qfalse; VectorCopy(origin, point); AngleVectors( angles, fwd, NULL, NULL ); while (1)//visible == qfalse) {// In case we need to try a second spawnpoint. int wp = -1; vec3_t playerMins = {-15, -15, DEFAULT_MINS_2}; vec3_t playerMaxs = {15, 15, DEFAULT_MAXS_2}; playerMins[0] = -15; playerMins[1] = -15; playerMins[2] = -1; playerMaxs[0] = 15; playerMaxs[1] = 15; playerMaxs[2] = 96;//1; while (tries < 16) { tries++; tries2 = 0; while (tries2 < 64) { int num_tries; // For secondary spawns. (Behind point). tries2++; num_tries = tries2; if (tries2 <= 16) { } else if (tries2 <= 32) { num_tries-=16; } else if (tries2 <= 48) { num_tries-=32; } else { num_tries-=48; } if (wp == -1) VectorCopy(origin, point); else VectorCopy(gWPArray[wp]->origin, point); if (tries2 <= 8) { point[0] += 1+(tries*64); point[1] += 1+(num_tries*64); } else if (tries2 <= 16) { point[0] += 1+(tries*64); point[1] += 1-(num_tries*64); } else if (tries2 <= 24) { point[0] += 1-(tries*64); point[1] += 1+(num_tries*64); } else { point[0] -= 1+(tries*64); point[1] -= 1+(num_tries*64); } //if (CheckAboveOK_Player(point)) // point[2] += 32; //else // continue; point[2] += 16; if (wp == -1) { if (OrgVisibleBox(origin, playerMins, playerMaxs, point, flag_list[flagnum].flagentity->s.number) && CheckBelowOK(point) && !CheckEntitiesInSpot(point) && VectorDistance(point, origin) > 128 && !TooCloseToOtherSpawnpoint(flagnum, point)) { //G_Printf("Adding spawn at %f %f %f.\n", point[0], point[1], point[2]); AddFlag_Spawn(flagnum, point, angles); //G_Printf("Adding spawn %f %f %f\n", point[0], point[1], point[2]); visible = qtrue; } //else // G_Printf("Not adding spawn at %f %f %f.\n", point[0], point[1], point[2]); } else { if (OrgVisibleBox(gWPArray[wp]->origin, playerMins, playerMaxs, point, -1) && CheckBelowOK(point) && !CheckEntitiesInSpot(point) && VectorDistance(point, origin) > 128 && !TooCloseToOtherSpawnpoint(flagnum, point)) { //G_Printf("Adding spawn at %f %f %f.\n", point[0], point[1], point[2]); AddFlag_Spawn(flagnum, point, angles); //G_Printf("Adding wp spawn %f %f %f\n", point[0], point[1], point[2]); visible = qtrue; } } } } if (visible != qfalse) break; else { //if (wp == -1) wp = GetNearestVisibleWP(flag_list[flagnum].flagentity->s.origin, flag_list[flagnum].flagentity->s.number);//NAV_FindClosestWaypointForPoint2( flag_list[flagnum].flagentity->s.origin ); //else // wp = GetNearestVisibleWP(flag_list[flagnum].flagentity->s.origin, flag_list[flagnum].flagentity->s.number);//NAV_FindClosestWaypointForPoint( flag_list[flagnum].flagentity, flag_list[flagnum].flagentity->s.origin ); } } G_Printf("^3*** ^3DominancE^5: Added ^7%i^5 spawnpoints at flag #^7%i^5.\n", flag_list[flagnum].num_spawnpoints, flagnum); }
/* ============== AICast_PredictMovement Simulates movement over a number of frames, returning the end position ============== */ void AICast_PredictMovement( cast_state_t *cs, int numframes, float frametime, aicast_predictmove_t *move, usercmd_t *ucmd, int checkHitEnt ) { int frame, i; playerState_t ps; pmove_t pm; trace_t tr; vec3_t end, startHitVec, thisHitVec, lastOrg, projPoint; qboolean checkReachMarker; //int pretime = Sys_MilliSeconds(); //G_Printf("PredictMovement: %f duration, %i frames\n", frametime, numframes ); VectorCopy( vec3_origin, startHitVec ); if ( cs->bs ) { ps = cs->bs->cur_ps; } else { ps = g_entities[cs->entityNum].client->ps; } ps.eFlags |= EF_DUMMY_PMOVE; move->stopevent = PREDICTSTOP_NONE; if ( checkHitEnt >= 0 && !Q_stricmp( g_entities[checkHitEnt].classname, "ai_marker" ) ) { checkReachMarker = qtrue; VectorSubtract( g_entities[checkHitEnt].r.currentOrigin, ps.origin, startHitVec ); VectorCopy( ps.origin, lastOrg ); } else { checkReachMarker = qfalse; } // don't let the frametime be too high // while (frametime > 0.2) { // numframes *= 2; // frametime /= 2; // } for ( frame = 0; frame < numframes; frame++ ) { memset( &pm, 0, sizeof( pm ) ); pm.ps = &ps; pm.cmd = *ucmd; pm.oldcmd = *ucmd; pm.ps->commandTime = 0; pm.cmd.serverTime = (int)( 1000.0 * frametime ); pm.tracemask = g_entities[cs->entityNum].clipmask; //MASK_PLAYERSOLID; pm.trace = trap_TraceCapsule; //trap_Trace; pm.pointcontents = trap_PointContents; pm.debugLevel = qfalse; pm.noFootsteps = qtrue; // RF, not needed for prediction //pm.noWeapClips = qtrue; // (SA) AI's ignore weapon clips // perform a pmove Pmove( &pm ); if ( checkHitEnt >= 0 ) { // if we've hit the checkent, abort if ( checkReachMarker ) { VectorSubtract( g_entities[checkHitEnt].r.currentOrigin, pm.ps->origin, thisHitVec ); if ( DotProduct( startHitVec, thisHitVec ) < 0 ) { // project the marker onto the movement vec, and check distance ProjectPointOntoVector( g_entities[checkHitEnt].r.currentOrigin, lastOrg, pm.ps->origin, projPoint ); if ( VectorDistance( g_entities[checkHitEnt].r.currentOrigin, projPoint ) < 8 ) { move->stopevent = PREDICTSTOP_HITENT; goto done; } } // use this position as the base for the next test //VectorCopy( thisHitVec, startHitVec ); VectorCopy( pm.ps->origin, lastOrg ); } // if we didnt reach the marker, then check for something that blocked us for ( i = 0; i < pm.numtouch; i++ ) { if ( pm.touchents[i] == pm.ps->groundEntityNum ) { continue; } if ( pm.touchents[i] == checkHitEnt ) { move->stopevent = PREDICTSTOP_HITENT; goto done; } else if ( pm.touchents[i] < MAX_CLIENTS || ( pm.touchents[i] != ENTITYNUM_WORLD && ( g_entities[pm.touchents[i]].s.eType != ET_MOVER || g_entities[pm.touchents[i]].moverState != MOVER_POS1 ) ) ) { // we have hit another entity, so abort move->stopevent = PREDICTSTOP_HITCLIENT; goto done; } else if ( !Q_stricmp( g_entities[pm.touchents[i]].classname, "script_mover" ) ) { // avoid script_mover's move->stopevent = PREDICTSTOP_HITCLIENT; goto done; } } } } done: // hack, if we are above ground, chances are it's because we only did one frame, and gravity isn't applied until // after the frame, so try and drop us down some if ( move->groundEntityNum == ENTITYNUM_NONE ) { VectorCopy( move->endpos, end ); end[2] -= 32; trap_Trace( &tr, move->endpos, pm.mins, pm.maxs, end, pm.ps->clientNum, pm.tracemask ); if ( !tr.startsolid && !tr.allsolid && tr.fraction < 1 ) { VectorCopy( tr.endpos, pm.ps->origin ); pm.ps->groundEntityNum = tr.entityNum; } } // copy off the results VectorCopy( pm.ps->origin, move->endpos ); move->frames = numframes; //move->presencetype = cs->bs->presencetype; VectorCopy( pm.ps->velocity, move->velocity ); move->numtouch = pm.numtouch; memcpy( move->touchents, pm.touchents, sizeof( pm.touchents ) ); move->groundEntityNum = pm.ps->groundEntityNum; //G_Printf("PredictMovement: %i ms\n", -pretime + Sys_MilliSeconds() ); }
/* ================ CG_AddClientCritter ================ */ void CG_AddClientCritter( localEntity_t *le ) { vec3_t newOrigin; trace_t trace; int time, step = 25, i; vec3_t v, ang, v2, oDelta; localEntity_t backup; float oldSpeed, enemyDist, of; vec3_t enemyPos; float alpha; if (cg_entities[le->ownerNum].currentState.otherEntityNum2 == cg.snap->ps.clientNum) { VectorCopy( cg.snap->ps.origin, enemyPos ); enemyPos[2] += cg.snap->ps.viewheight; } else { VectorCopy( cg_entities[le->ownerNum].currentState.origin2, enemyPos ); } VectorCopy( le->pos.trDelta, oDelta ); // vary the enemyPos to create a psuedo-randomness of = (float)cg.time + le->startTime; enemyPos[0] += 12 * (sin(of/100) * cos(of/78)); enemyPos[1] += 12 * (sin(of/70) * cos(of/82)); enemyPos[2] += 12 * (sin(of/67) * cos(of/98)); time = le->lastTrailTime+step; while (time <= cg.time) { if (time > le->refEntity.fadeStartTime) { alpha = (float)(time - le->refEntity.fadeStartTime)/(float)(le->refEntity.fadeEndTime - le->refEntity.fadeStartTime); if (alpha < 0) alpha = 0; else if (alpha > 1) alpha = 1; } else { alpha = 1.0; } // calculate new position BG_EvaluateTrajectory( &le->pos, time, newOrigin ); VectorSubtract( enemyPos, le->refEntity.origin, v ); enemyDist = VectorNormalize( v ); // trace a line from previous position to new position CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, le->ownerNum, MASK_SHOT ); // if stuck, kill it if (trace.startsolid || (trace.fraction < 1.0)) { // kill it CG_FreeLocalEntity( le ); return; } // moved some distance VectorCopy( trace.endpos, le->refEntity.origin ); if (le->leType == LE_ZOMBIE_SPIRIT) { le->headJuncIndex = CG_AddTrailJunc( le->headJuncIndex, cgs.media.zombieSpiritTrailShader, time, STYPE_STRETCH, le->refEntity.origin, (int)le->effectWidth, // trail life 0.3 * alpha, 0.0, le->radius, 0, 0,//TJFL_FIXDISTORT, colorWhite, colorWhite, 1.0, 1 ); } // tracking factor if (le->leType == LE_ZOMBIE_BAT) le->bounceFactor = 3.0*(float)step/1000.0; else le->bounceFactor = 5.0*(float)step/1000.0; oldSpeed = VectorLength( le->pos.trDelta ); // track the enemy backup = *le; VectorSubtract( enemyPos, le->refEntity.origin, v ); enemyDist = VectorNormalize( v ); if (alpha > 0.5 && (le->lastSpiritDmgTime < time - 100) && enemyDist < 24) { // inflict the damage! CG_ClientDamage( cg_entities[le->ownerNum].currentState.otherEntityNum2, le->ownerNum, CLDMG_SPIRIT ); le->lastSpiritDmgTime = time; } VectorMA( le->pos.trDelta, le->bounceFactor*oldSpeed, v, le->pos.trDelta ); //VectorCopy( v, le->pos.trDelta ); if (VectorLength(le->pos.trDelta) < 1) { CG_FreeLocalEntity( le ); return; } le->bounceFactor = 5.0*(float)step/1000.0; // avoidance factor // the intersection is a fraction of the frametime le->pos.trTime = time; VectorCopy( le->refEntity.origin, le->pos.trBase ); VectorNormalize( le->pos.trDelta ); VectorScale( le->pos.trDelta, oldSpeed, le->pos.trDelta ); // now trace ahead of time, if we're going to hit something, then avoid it // only avoid dangers if we don't have direct sight to the enemy trap_CM_BoxTrace( &trace, le->refEntity.origin, enemyPos, NULL, NULL, 0, MASK_SOLID ); if (trace.fraction < 1.0) { BG_EvaluateTrajectory( &le->pos, time+1000, newOrigin ); // if we would go passed the enemy, don't bother if (VectorDistance( le->refEntity.origin, enemyPos) > VectorDistance( le->refEntity.origin, newOrigin )) { trap_CM_BoxTrace( &trace, le->refEntity.origin, newOrigin, NULL, NULL, 0, MASK_SOLID ); if (trace.fraction < 1.0) { // make sure we are not heading away from the enemy too much VectorNormalize2( le->pos.trDelta, v2 ); if (DotProduct( v, v2 ) > 0.7) { // avoid world geometry backup = *le; le->bounceFactor = (1.0 - trace.fraction)*10.0*(float)step/1000.0; // tracking and avoidance factor // reflect the velocity on the trace plane VectorMA( le->pos.trDelta, le->bounceFactor*oldSpeed, trace.plane.normal, le->pos.trDelta ); if (VectorLength(le->pos.trDelta) < 1) { CG_FreeLocalEntity( le ); return; } // the intersection is a fraction of the frametime le->pos.trTime = time; VectorCopy( le->refEntity.origin, le->pos.trBase ); VectorNormalize( le->pos.trDelta ); VectorScale( le->pos.trDelta, oldSpeed, le->pos.trDelta ); // // double check end velocity VectorNormalize2( le->pos.trDelta, v2 ); if (DotProduct( v, v2 ) <= 0.2) { // restore *le = backup; } } } } } // set the angles VectorNormalize2( le->pos.trDelta, v ); // HACK!!! skull model is back-to-front, need to fix if (le->leType == LE_ZOMBIE_SPIRIT) VectorInverse( v ); vectoangles( v, ang ); AnglesToAxis( ang, le->refEntity.axis ); // lean when turning if (le->leType == LE_ZOMBIE_BAT) { VectorSubtract( le->pos.trDelta, oDelta, v2 ); ang[ROLL] = -5.0 * DotProduct( le->refEntity.axis[1], v2 ); if (fabs(ang[ROLL]) > 80) { if (ang[ROLL] > 80) ang[ROLL] = 80; else ang[ROLL] = -80; } } AnglesToAxis( ang, le->refEntity.axis ); // HACK: the skull is slightly higher than the origin if (le->leType == LE_ZOMBIE_SPIRIT) { // set the size scale for (i=0; i<3; i++) VectorScale( le->refEntity.axis[i], 0.35, le->refEntity.axis[i] ); VectorMA( le->refEntity.origin, -10, le->refEntity.axis[2], le->refEntity.origin ); } le->lastTrailTime = time; time += step; } // Bats, set the frame if (le->leType == LE_ZOMBIE_BAT) { #define BAT_ANIM_FRAMETIME 30 le->refEntity.frame = (cg.time/BAT_ANIM_FRAMETIME+1)%19; le->refEntity.oldframe = (cg.time/BAT_ANIM_FRAMETIME)%19; le->refEntity.backlerp = 1.0 - ((float)(cg.time%BAT_ANIM_FRAMETIME)/(float)BAT_ANIM_FRAMETIME); } // add the sound if (le->loopingSound) { if (cg.time > le->refEntity.fadeStartTime) trap_S_AddLoopingSound( 0, le->refEntity.origin, vec3_origin, le->loopingSound, 255 - (int)(255.0 * (float)(cg.time - le->refEntity.fadeStartTime) / (float)(le->refEntity.fadeEndTime - le->refEntity.fadeStartTime)) ); else if (le->startTime + 1000 > cg.time) trap_S_AddLoopingSound( 0, le->refEntity.origin, vec3_origin, le->loopingSound, (int)(255.0 * (float)(cg.time - le->startTime) / 1000.0) ); else trap_S_AddLoopingSound( 0, le->refEntity.origin, vec3_origin, le->loopingSound, 255); } trap_R_AddRefEntityToScene( &le->refEntity ); /* // HACK: the skull is slightly higher than the origin if (le->leType == LE_ZOMBIE_SPIRIT) { // set the size scale for (i=0; i<3; i++) VectorScale( le->refEntity.axis[i], 1.0/0.35, le->refEntity.axis[i] ); VectorMA( le->refEntity.origin, 10, le->refEntity.axis[2], le->refEntity.origin ); } */ // Bats, add the flame if (le->leType == LE_ZOMBIE_BAT) { // float lightSize, alpha; // le->refEntity.shaderRGBA[3] = 255; VectorNormalize2( le->pos.trDelta, v ); VectorInverse( v ); v[2] += 1; VectorNormalize2( v, le->refEntity.fireRiseDir ); le->refEntity.customShader = cgs.media.onFireShader2; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity.shaderTime = 1434; trap_R_AddRefEntityToScene( &le->refEntity ); // le->refEntity.customShader = cgs.media.onFireShader; // le->refEntity.shaderTime = 0; // trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity.customShader = 0; le->refEntity.shaderTime = 0; /* // drop a dlight lightSize = 1.0 + 0.2*(sin(1.0*cg.time/50.0) * cos(1.0*cg.time/43.0)); alpha = 0.2 * (lightSize / 1.2); trap_R_AddLightToScene( le->refEntity.origin, 150.0 + 80.0*lightSize, 1.000000*alpha, 0.603922*alpha, 0.207843*alpha, 0 ); // add some sound trap_S_AddLoopingSound( -1, le->refEntity.origin, vec3_origin, cgs.media.flameSound, 100 ); trap_S_AddLoopingSound( -1, le->refEntity.origin, vec3_origin, cgs.media.flameBlowSound, 100 ); */ } }