//----------------------------------------------------------------------------- // Purpose: Deal with input //----------------------------------------------------------------------------- void C_VGuiScreen::ClientThink( void ) { int nButtonsChanged = m_nOldButtonState ^ m_nButtonState; m_nOldButtonState = m_nButtonState; // Debounced button codes for pressed/released // UNDONE: Do we need auto-repeat? m_nButtonPressed = nButtonsChanged & m_nButtonState; // The changed ones still down are "pressed" m_nButtonReleased = nButtonsChanged & (~m_nButtonState); // The ones not down are "released" BaseClass::ClientThink(); // FIXME: We should really be taking bob, shake, and roll into account // but if we did, then all the inputs would be generated multiple times // if the world was rendered multiple times (for things like water, etc.) vgui::Panel *pPanel = m_PanelWrapper.GetPanel(); if (!pPanel) return; C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); if (!pLocalPlayer) return; // Generate a ray along the view direction Vector vecEyePosition = pLocalPlayer->EyePosition(); QAngle viewAngles = pLocalPlayer->EyeAngles( ); // Compute cursor position... Ray_t lookDir; Vector endPos; float u, v; // Viewmodel attached screens that take input need to have a moving cursor // Do a pick under the cursor as our selection Vector viewDir; AngleVectors( viewAngles, &viewDir ); VectorMA( vecEyePosition, 1000.0f, viewDir, endPos ); lookDir.Init( vecEyePosition, endPos ); if (!IntersectWithRay( lookDir, &u, &v, NULL )) return; if ( ((u < 0) || (v < 0) || (u > 1) || (v > 1)) && !m_bLoseThinkNextFrame) return; // This will cause our panel to grab all input! g_pClientMode->ActivateInGameVGuiContext( pPanel ); // Convert (u,v) into (px,py) int px = (int)(u * m_nPixelWidth + 0.5f); int py = (int)(v * m_nPixelHeight + 0.5f); // Generate mouse input commands if ((px != m_nOldPx) || (py != m_nOldPy)) { g_InputInternal->InternalCursorMoved( px, py ); m_nOldPx = px; m_nOldPy = py; } if (m_nButtonPressed & IN_ATTACK) { g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_PRESSED ); g_InputInternal->InternalMousePressed(MOUSE_LEFT); } if (m_nButtonPressed & IN_ATTACK2) { g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_PRESSED ); g_InputInternal->InternalMousePressed( MOUSE_RIGHT ); } if ( (m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus { g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_RELEASED ); g_InputInternal->InternalMouseReleased( MOUSE_LEFT ); } if (m_nButtonReleased & IN_ATTACK2) { g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_RELEASED ); g_InputInternal->InternalMouseReleased( MOUSE_RIGHT ); } if ( m_bLoseThinkNextFrame == true ) { m_bLoseThinkNextFrame = false; SetNextClientThink( CLIENT_THINK_NEVER ); } g_pClientMode->DeactivateInGameVGuiContext( ); }
static qboolean InitFlyby(player_state_t *self, player_state_t *player, int checkvis) { float f, maxlen; vec3_t vec, vec2; vec3_t forward, right, up; VectorCopy(player->viewangles, vec); vec[0] = 0; AngleVectors (vec, forward, right, up); // for (i = 0; i < 3; i++) // forward[i] *= 3; maxlen = 1000; VectorAdd(forward, up, vec2); VectorAdd(vec2, right, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorAdd(forward, up, vec2); VectorSubtract(vec2, right, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorAdd(forward, right, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorSubtract(forward, right, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorAdd(forward, up, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorSubtract(forward, up, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorAdd(up, right, vec2); VectorSubtract(vec2, forward, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorSubtract(up, right, vec2); VectorSubtract(vec2, forward, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } // invert VectorNegate(forward, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorCopy(forward, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } // invert VectorNegate(right, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } VectorCopy(right, vec2); if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < maxlen) { maxlen = f; VectorCopy(vec2, vec); } // ack, can't find him if (maxlen >= 1000) { // Cam_Unlock(); return false; } locked = true; VectorCopy(vec, desired_position); return true; }
/** * @brief Create lights out of patches and entity lights * @sa LightWorld * @sa BuildPatch */ void BuildLights (void) { int i; light_t *l; /* surfaces */ for (i = 0; i < MAX_MAP_FACES; i++) { const patch_t *p = face_patches[i]; while (p) { /* iterate subdivided patches */ if (VectorEmpty(p->light)) continue; numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); VectorCopy(p->origin, l->origin); l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; l->type = emit_surface; l->intensity = ColorNormalize(p->light, l->color); l->intensity *= p->area * config.surface_scale; p = p->next; } } /* entities (skip the world) */ for (i = 1; i < num_entities; i++) { float intensity; const char *color; const char *target; const entity_t *e = &entities[i]; const char *name = ValueForKey(e, "classname"); if (!Q_strstart(name, "light")) continue; /* remove those lights that are only for the night version */ if (config.compile_for_day) { const int spawnflags = atoi(ValueForKey(e, "spawnflags")); if (!(spawnflags & 1)) /* day */ continue; } numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); GetVectorForKey(e, "origin", l->origin); /* link in */ l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; intensity = FloatForKey(e, "light"); if (!intensity) intensity = 300.0; color = ValueForKey(e, "_color"); if (color && color[0] != '\0'){ if (sscanf(color, "%f %f %f", &l->color[0], &l->color[1], &l->color[2]) != 3) Sys_Error("Invalid _color entity property given: %s", color); ColorNormalize(l->color, l->color); } else VectorSet(l->color, 1.0, 1.0, 1.0); l->intensity = intensity * config.entity_scale; l->type = emit_point; target = ValueForKey(e, "target"); if (target[0] != '\0' || Q_streq(name, "light_spot")) { l->type = emit_spotlight; l->stopdot = FloatForKey(e, "_cone"); if (!l->stopdot) l->stopdot = 10; l->stopdot = cos(l->stopdot * torad); if (target[0] != '\0') { /* point towards target */ entity_t *e2 = FindTargetEntity(target); if (!e2) Com_Printf("WARNING: light at (%i %i %i) has missing target '%s' - e.g. create an info_null that has a 'targetname' set to '%s'\n", (int)l->origin[0], (int)l->origin[1], (int)l->origin[2], target, target); else { vec3_t dest; GetVectorForKey(e2, "origin", dest); VectorSubtract(dest, l->origin, l->normal); VectorNormalize(l->normal); } } else { /* point down angle */ const float angle = FloatForKey(e, "angle"); if (angle == ANGLE_UP) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = 1.0; } else if (angle == ANGLE_DOWN) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = -1.0; } else { l->normal[2] = 0; l->normal[0] = cos(angle * torad); l->normal[1] = sin(angle * torad); } } } } /* handle worldspawn light settings */ { const entity_t *e = &entities[0]; const char *ambient, *light, *angles, *color; float f; int i; if (config.compile_for_day) { ambient = ValueForKey(e, "ambient_day"); light = ValueForKey(e, "light_day"); angles = ValueForKey(e, "angles_day"); color = ValueForKey(e, "color_day"); } else { ambient = ValueForKey(e, "ambient_night"); light = ValueForKey(e, "light_night"); angles = ValueForKey(e, "angles_night"); color = ValueForKey(e, "color_night"); } if (light[0] != '\0') sun_intensity = atoi(light); if (angles[0] != '\0') { VectorClear(sun_angles); if (sscanf(angles, "%f %f", &sun_angles[0], &sun_angles[1]) != 2) Sys_Error("wrong angles values given: '%s'", angles); AngleVectors(sun_angles, sun_normal, NULL, NULL); } if (color[0] != '\0') { GetVectorFromString(color, sun_color); ColorNormalize(sun_color, sun_color); } if (ambient[0] != '\0') GetVectorFromString(ambient, sun_ambient_color); /* optionally pull brightness from worldspawn */ f = FloatForKey(e, "brightness"); if (f > 0.0) config.brightness = f; /* saturation as well */ f = FloatForKey(e, "saturation"); if (f > 0.0) config.saturation = f; else Verb_Printf(VERB_EXTRA, "Invalid saturation setting (%f) in worldspawn found\n", f); f = FloatForKey(e, "contrast"); if (f > 0.0) config.contrast = f; else Verb_Printf(VERB_EXTRA, "Invalid contrast setting (%f) in worldspawn found\n", f); /* lightmap resolution downscale (e.g. 4 = 1 << 4) */ i = atoi(ValueForKey(e, "quant")); if (i >= 1 && i <= 6) config.lightquant = i; else Verb_Printf(VERB_EXTRA, "Invalid quant setting (%i) in worldspawn found\n", i); } Verb_Printf(VERB_EXTRA, "light settings:\n * intensity: %i\n * sun_angles: pitch %f yaw %f\n * sun_color: %f:%f:%f\n * sun_ambient_color: %f:%f:%f\n", sun_intensity, sun_angles[0], sun_angles[1], sun_color[0], sun_color[1], sun_color[2], sun_ambient_color[0], sun_ambient_color[1], sun_ambient_color[2]); Verb_Printf(VERB_NORMAL, "%i direct lights for %s lightmap\n", numlights[config.compile_for_day], (config.compile_for_day ? "day" : "night")); }
void C_ParticleSmokeGrenade::Update(float fTimeDelta) { m_LifetimeCounter += fTimeDelta; // Update the smoke trail. C_BaseEntity *pAimEnt = GetFollowedEntity(); if ( pAimEnt ) { Vector forward, right, up; // Update the smoke particle color. if(m_CurrentStage == 0) { m_SmokeTrail.m_StartColor = EngineGetLightForPoint(GetAbsOrigin()) * 0.5f; m_SmokeTrail.m_EndColor = m_SmokeTrail.m_StartColor; } // Spin the smoke trail. AngleVectors(pAimEnt->GetAbsAngles(), &forward, &right, &up); m_SmokeTrail.m_VelocityOffset = forward * 30 + GetAbsVelocity(); m_SmokeTrail.SetLocalOrigin( GetAbsOrigin() ); m_SmokeTrail.Update(fTimeDelta); } // Update our fade alpha. if(m_LifetimeCounter < m_FadeStartTime) { m_FadeAlpha = 1; } else if(m_LifetimeCounter < m_FadeEndTime) { float fadePercent = (m_LifetimeCounter - m_FadeStartTime) / (m_FadeEndTime - m_FadeStartTime); m_FadeAlpha = cos(fadePercent * 3.14159) * 0.5 + 0.5; } else { m_FadeAlpha = 0; } // Scale by the amount the sphere has grown. m_FadeAlpha *= m_ExpandRadius / SMOKESPHERE_MAX_RADIUS; if(m_CurrentStage == 1) { // Update the expanding sphere. m_ExpandTimeCounter += fTimeDelta; if(m_ExpandTimeCounter > SMOKESPHERE_EXPAND_TIME) m_ExpandTimeCounter = SMOKESPHERE_EXPAND_TIME; m_ExpandRadius = SMOKESPHERE_MAX_RADIUS * (float)sin(m_ExpandTimeCounter * 3.14159265358 * 0.5 / SMOKESPHERE_EXPAND_TIME); // Add our influence to the global smoke fog alpha. float testDist = (EngineGetVecRenderOrigin() - m_SmokeBasePos).Length(); float fadeEnd = m_ExpandRadius * 0.75; if(testDist < fadeEnd) { EngineGetSmokeFogOverlayAlpha() += 1 - testDist / fadeEnd; } // This is used to randomize the direction it chooses to move a particle in. int offsetLookup[3] = {-1,0,1}; // Update all the moving traders and establish new ones. int nTotal = m_xCount * m_yCount * m_zCount; for(int i=0; i < nTotal; i++) { SmokeParticleInfo *pInfo = &m_SmokeParticleInfos[i]; if(!pInfo->m_pParticle) continue; if(pInfo->m_TradeIndex == -1) { pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha; pInfo->m_pParticle->m_Color[0] = pInfo->m_Color[0]; pInfo->m_pParticle->m_Color[1] = pInfo->m_Color[1]; pInfo->m_pParticle->m_Color[2] = pInfo->m_Color[2]; // Is there an adjacent one that's not trading? int x, y, z; GetParticleInfoXYZ(i, x, y, z); int xCountOffset = rand(); int yCountOffset = rand(); int zCountOffset = rand(); bool bFound = false; for(int xCount=0; xCount < 3 && !bFound; xCount++) { for(int yCount=0; yCount < 3 && !bFound; yCount++) { for(int zCount=0; zCount < 3; zCount++) { int testX = x + offsetLookup[(xCount+xCountOffset) % 3]; int testY = y + offsetLookup[(yCount+yCountOffset) % 3]; int testZ = z + offsetLookup[(zCount+zCountOffset) % 3]; if(testX == x && testY == y && testZ == z) continue; if(IsValidXYZCoords(testX, testY, testZ)) { SmokeParticleInfo *pOther = GetSmokeParticleInfo(testX, testY, testZ); if(pOther->m_pParticle && pOther->m_TradeIndex == -1) { // Ok, this one is looking to trade also. pInfo->m_TradeIndex = GetSmokeParticleIndex(testX, testY, testZ); pOther->m_TradeIndex = i; pInfo->m_TradeClock = pOther->m_TradeClock = 0; pInfo->m_TradeDuration = FRand(TRADE_DURATION_MIN, TRADE_DURATION_MAX); bFound = true; break; } } } } } } else { SmokeParticleInfo *pOther = &m_SmokeParticleInfos[pInfo->m_TradeIndex]; assert(pOther->m_TradeIndex == i); // This makes sure the trade only gets updated once per frame. if(pInfo < pOther) { // Increment the trade clock.. pInfo->m_TradeClock = (pOther->m_TradeClock += fTimeDelta); int x, y, z; GetParticleInfoXYZ(i, x, y, z); Vector myPos = GetSmokeParticlePos(x, y, z); int otherX, otherY, otherZ; GetParticleInfoXYZ(pInfo->m_TradeIndex, otherX, otherY, otherZ); Vector otherPos = GetSmokeParticlePos(otherX, otherY, otherZ); // Is the trade finished? if(pInfo->m_TradeClock >= pInfo->m_TradeDuration) { pInfo->m_TradeIndex = pOther->m_TradeIndex = -1; pInfo->m_pParticle->m_Pos = otherPos; pOther->m_pParticle->m_Pos = myPos; SmokeGrenadeParticle *temp = pInfo->m_pParticle; pInfo->m_pParticle = pOther->m_pParticle; pOther->m_pParticle = temp; } else { // Ok, move them closer. float percent = (float)cos(pInfo->m_TradeClock * 2 * 1.57079632f / pInfo->m_TradeDuration); percent = percent * 0.5 + 0.5; pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * (1 - percent); pOther->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * percent; InterpColor(pInfo->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, 1-percent); InterpColor(pOther->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, percent); pInfo->m_pParticle->m_Pos = myPos + (otherPos - myPos) * (1 - percent); pOther->m_pParticle->m_Pos = myPos + (otherPos - myPos) * percent; } } } } } }
/* =============== CG_AttachmentDir Return the attachment direction =============== */ bool CG_AttachmentDir( attachment_t *a, vec3_t v ) { vec3_t forward; centity_t *cent; if ( !a ) { return false; } switch ( a->type ) { case AT_STATIC: return false; case AT_TAG: if ( !a->tagValid ) { return false; } VectorCopy( a->re.axis[ 0 ], v ); break; case AT_CENT: if ( !a->centValid ) { return false; } cent = &cg_entities[ a->centNum ]; AngleVectors( cent->lerpAngles, forward, nullptr, nullptr ); VectorCopy( forward, v ); break; case AT_PARTICLE: if ( !a->particleValid ) { return false; } if ( !a->particle->valid ) { a->particleValid = false; return false; } else { VectorCopy( a->particle->velocity, v ); } break; default: CG_Printf( S_ERROR "Invalid attachmentType_t in attachment\n" ); break; } VectorNormalize( v ); return true; }
void p_berserk_attack (edict_t *ent, int move_state) { int punch_dmg = BERSERK_PUNCH_INITIAL_DAMAGE + BERSERK_PUNCH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; int slash_dmg = BERSERK_SLASH_INITIAL_DAMAGE + BERSERK_SLASH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; int crush_dmg = BERSERK_CRUSH_INITIAL_DAMAGE + BERSERK_CRUSH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; vec3_t forward, right, up, angles; ent->client->idle_frames = 0; AngleVectors(ent->s.angles, NULL, right, up); AngleVectors(ent->client->v_angle, forward, NULL, NULL); VectorCopy(ent->client->v_angle, angles); if (move_state == BERSERK_RUN_FORWARD) { G_RunFrames(ent, BERSERK_FRAMES_RUNATTACK1_START, BERSERK_FRAMES_RUNATTACK1_END, false); // swing left-right if (ent->s.frame == 124) { angles[YAW] += 20; AngleCheck(&angles[YAW]); AngleVectors(angles, forward, NULL, NULL); p_berserk_melee(ent, forward, NULL, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } else if (ent->s.frame == 125) { p_berserk_melee(ent, forward, NULL, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } else if (ent->s.frame == 126) { angles[YAW] -= 20; AngleCheck(&angles[YAW]); AngleVectors(angles, forward, NULL, NULL); p_berserk_melee(ent, forward, NULL, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } } else if (move_state == BERSERK_RUN_BACKWARD) { G_RunFrames(ent, BERSERK_FRAMES_RUNATTACK1_START, BERSERK_FRAMES_RUNATTACK1_END, true); // swing left-right if (ent->s.frame == 124) { angles[YAW] += 20; AngleCheck(&angles[YAW]); AngleVectors(angles, forward, NULL, NULL); p_berserk_melee(ent, forward, NULL, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } else if (ent->s.frame == 125) { p_berserk_melee(ent, forward, NULL, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } else if (ent->s.frame == 126) { angles[YAW] -= 20; AngleCheck(&angles[YAW]); AngleVectors(angles, forward, NULL, NULL); p_berserk_melee(ent, forward, NULL, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } } else if (ent->client->weapon_mode == 1) // slash { G_RunFrames(ent, BERSERK_FRAMES_SLASH_START, BERSERK_FRAMES_SLASH_END, false); if ((ent->s.frame == 79) || (ent->s.frame == 80)) p_berserk_melee(ent, forward, up, slash_dmg, BERSERK_SLASH_KNOCKBACK, BERSERK_SLASH_RANGE, MOD_BERSERK_SLASH); } else if (ent->client->weapon_mode == 2) // crush { G_RunFrames(ent, BERSERK_FRAMES_SLAM_START, BERSERK_FRAMES_SLAM_END, false); if (ent->s.frame == 154) p_berserk_crush(ent, crush_dmg, BERSERK_CRUSH_RANGE, MOD_BERSERK_CRUSH); } else // punch { G_RunFrames(ent, BERSERK_FRAMES_PUNCH_START, BERSERK_FRAMES_PUNCH_END, false); // swing left-right if (ent->s.frame == 66) { angles[YAW] += 20;//45; AngleCheck(&angles[YAW]); AngleVectors(angles, forward, NULL, NULL); p_berserk_melee(ent, forward, right, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } else if (ent->s.frame == 67) { p_berserk_melee(ent, forward, right, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } else if (ent->s.frame == 68) { angles[YAW] -= 20;//45; AngleCheck(&angles[YAW]); AngleVectors(angles, forward, NULL, NULL); p_berserk_melee(ent, forward, right, punch_dmg, BERSERK_PUNCH_KNOCKBACK, BERSERK_PUNCH_RANGE, MOD_BERSERK_PUNCH); } } p_berserk_swing(ent); }
void EjectShell (edict_t *self, vec3_t start, int toggle ) { edict_t *shell; vec3_t forward, right, up; float r; float fix = 1.0; int left = 0; if (sv_shelloff->value) return; shell = G_Spawn(); ++shells; AngleVectors (self->client->v_angle, forward, right, up); if (self->client->pers.hand == LEFT_HANDED) { left = 1; fix = -1.0; } else if ( self->client->pers.hand == CENTER_HANDED) fix = 0; // zucc spent a fair amount of time hacking these until they look ok, // several of them could be improved however. if (self->client->curr_weap == MK23_NUM ) { VectorMA (start, left?-7:.4, right, start); VectorMA (start, left?5:2, forward, start); VectorMA (start, left?-10:-8 , up, start); } else if (self->client->curr_weap == M4_NUM) { VectorMA (start, left?-10:5, right, start); VectorMA (start, left?6:12, forward, start); VectorMA (start, left?-9:-11, up, start); } else if (self->client->curr_weap == MP5_NUM) { VectorMA (start, left?-10:6, right, start); VectorMA (start, left?6:8, forward, start); VectorMA (start, left?-9:-10, up, start); } else if (self->client->curr_weap == SNIPER_NUM) { VectorMA (start, fix*11, right, start); VectorMA (start, 2, forward, start); VectorMA (start, -11, up, start); } else if (self->client->curr_weap == M3_NUM) { VectorMA(start, left?-9:3, right, start); VectorMA(start, left?4:4, forward, start); VectorMA(start, left?-1:-1, up, start); } else if (self->client->curr_weap == DUAL_NUM) { if (self->client->pers.hand == LEFT_HANDED) VectorMA (start, ((toggle==1)?8:-8), right, start); else VectorMA (start, ((toggle==1)?-4:4), right, start); VectorMA (start, 6, forward, start); VectorMA (start, -9, up, start); } if ( (forward[2] >= -1) && (forward[2] < -0.99) ) { VectorMA (start, 5, forward, start); VectorMA (start, -0.5, up, start); } else if ( (forward[2] >= -0.99) && (forward[2] < -0.98) ) { VectorMA (start, 5, forward, start); VectorMA (start, -.1, up, start); } else if ( (forward[2] >= -0.98) && (forward[2] < -0.97) ) { VectorMA (start, 5.1, forward, start); VectorMA (start, 0.3, up, start); } else if ( (forward[2] >= -0.97) && (forward[2] < -0.96) ) { VectorMA (start, 5.2, forward, start); VectorMA (start, 0.7, up, start); } else if ( (forward[2] >= -0.96) && (forward[2] < -0.95) ) { VectorMA (start, 5.2, forward, start); VectorMA (start, 1.1, up, start); } else if ( (forward[2] >= -0.95) && (forward[2] < -0.94) ) { VectorMA (start, 5.3, forward, start); VectorMA (start, 1.5, up, start); } else if ( (forward[2] >= -0.94) && (forward[2] < -0.93) ) { VectorMA (start, 5.4, forward, start); VectorMA (start, 1.9, up, start); } else if ( (forward[2] >= -0.93) && (forward[2] < -0.92) ) { VectorMA (start, 5.5, forward, start); VectorMA (start, 2.3, up, start); } else if ( (forward[2] >= -0.92) && (forward[2] < -0.91) ) { VectorMA (start, 5.6, forward, start); VectorMA (start, 2.7, up, start); } else if ( (forward[2] >= -0.91) && (forward[2] < -0.9) ) { VectorMA (start, 5.7, forward, start); VectorMA (start, 3.1, up, start); } else if ( (forward[2] >= -0.9) && (forward[2] < -0.85) ) { VectorMA (start, 5.8, forward, start); VectorMA (start, 3.5, up, start); } else if ( (forward[2] >= -0.85) && (forward[2] < -0.8) ) { VectorMA (start, 6, forward, start); VectorMA (start, 4, up, start); } else if ( (forward[2] >= -0.8) && (forward[2] < -0.6) ) { VectorMA (start, 6.5, forward, start); VectorMA (start, 4.5, up , start); } else if ( (forward[2] >= -0.6) && (forward[2] < -0.4) ) { VectorMA (start, 8, forward, start); VectorMA (start, 5.5, up , start); } else if ( (forward[2] >= -0.4) && (forward[2] < -0.2) ) { VectorMA (start, 9.5, forward, start); VectorMA (start, 6, up , start); } else if ( (forward[2] >= -0.2) && (forward[2] < 0) ) { VectorMA (start, 11, forward, start); VectorMA (start, 6.5, up , start); } else if ( (forward[2] >= 0) && (forward[2] < 0.2) ) { VectorMA (start, 12, forward, start); VectorMA (start, 7, up, start); } else if ( (forward[2] >= 0.2) && (forward[2] < 0.4) ) { VectorMA (start, 14, forward, start); VectorMA (start, 6.5, up, start); } else if ( (forward[2] >= 0.4) && (forward[2] < 0.6) ) { VectorMA (start, 16, forward, start); VectorMA (start, 6, up, start); } else if ( (forward[2] >= 0.6) && (forward[2] < 0.8) ) { VectorMA (start, 18, forward, start); VectorMA (start, 5, up, start); } else if ( (forward[2] >= 0.8) && (forward[2] < 0.85) ) { VectorMA (start, 18, forward, start); VectorMA (start, 4, up, start); } else if ( (forward[2] >= 0.85) && (forward[2] < 0.9) ) { VectorMA (start, 18, forward, start); VectorMA (start, 2.5, up, start); } else if ( (forward[2] >= 0.9) && (forward[2] < 0.91) ) { VectorMA (start, 18.2, forward, start); VectorMA (start, 2.2, up, start); } else if ( (forward[2] >= 0.91) && (forward[2] < 0.92) ) { VectorMA (start, 18.4, forward, start); VectorMA (start, 1.9, up, start); } else if ( (forward[2] >= 0.92) && (forward[2] < 0.93) ) { VectorMA (start, 18.6, forward, start); VectorMA (start, 1.6, up, start); } else if ( (forward[2] >= 0.93) && (forward[2] < 0.94) ) { VectorMA (start, 18.8, forward, start); VectorMA (start, 1.3, up, start); } else if ( (forward[2] >= 0.94) && (forward[2] < 0.95) ) { VectorMA (start, 19, forward, start); VectorMA (start, 1, up, start); } else if ( (forward[2] >= 0.95) && (forward[2] < 0.96) ) { VectorMA (start, 19.2, forward, start); VectorMA (start, 0.7, up, start); } else if ( (forward[2] >= 0.96) && (forward[2] < 0.97) ) { VectorMA (start, 19.4, forward, start); VectorMA (start, 0.4, up, start); } else if ( (forward[2] >= 0.97) && (forward[2] < 0.98) ) { VectorMA (start, 19.6, forward, start); VectorMA (start, -0.2, up, start); } else if ( (forward[2] >= 0.98) && (forward[2] < 0.99) ) { VectorMA (start, 19.8, forward, start); VectorMA (start, -0.6, up, start); } else if ( (forward[2] >= 0.99) && (forward[2] <= 1) ) { VectorMA (start, 20, forward, start); VectorMA (start, -1, up , start); } VectorCopy (start , shell->s.origin); if (fix == 0) // we want some velocity on those center handed ones fix = 1; if (self->client->curr_weap == SNIPER_NUM) VectorMA (shell->velocity, fix*(-35 + random() * -60), right, shell->velocity); else if ( self->client->curr_weap == DUAL_NUM) { if (self->client->pers.hand == LEFT_HANDED) VectorMA (shell->velocity, (toggle==1?1:-1)*(35 + random() * 60), right, shell->velocity); else VectorMA (shell->velocity, (toggle==1?-1:1)*(35 + random() * 60), right, shell->velocity); } else VectorMA (shell->velocity, fix*(35 + random() * 60), right, shell->velocity); VectorMA (shell->avelocity, 500, right, shell->avelocity); if (self->client->curr_weap == SNIPER_NUM) VectorMA (shell->velocity, 60 + 40, up, shell->velocity); else VectorMA (shell->velocity, 60 + random() * 90, up, shell->velocity); shell->movetype = MOVETYPE_BOUNCE; shell->solid = SOLID_BBOX; if (self->client->curr_weap == M3_NUM) shell->s.modelindex = gi.modelindex ("models/weapons/shell/tris2.md2"); else if (self->client->curr_weap == SNIPER_NUM) shell->s.modelindex = gi.modelindex ("models/weapons/shell/tris3.md2"); else shell->s.modelindex = gi.modelindex ("models/weapons/shell/tris.md2"); r = random(); if (r < 0.1) shell->s.frame = 0; else if (r < 0.2) shell->s.frame = 1; else if (r < 0.3) shell->s.frame = 2; else if (r < 0.5) shell->s.frame = 3; else if (r < 0.6) shell->s.frame = 4; else if (r < 0.7) shell->s.frame = 5; else if (r < 0.8) shell->s.frame = 6; else if (r < 0.9) shell->s.frame = 7; else shell->s.frame = 8; shell->owner = self; shell->touch = ShellTouch; shell->nextthink = level.time + 1.2 - (shells * .05); shell->think = ShellDie; shell->classname = "shell"; gi.linkentity (shell); }
static void CG_OffsetThirdPersonView(void) { vec3_t forward, right, up; vec3_t view; vec3_t focusAngles; trace_t trace; static vec3_t mins = { -4, -4, -4 }; static vec3_t maxs = { 4, 4, 4 }; vec3_t focusPoint; float focusDist; float forwardScale, sideScale; cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight; VectorCopy(cg.refdefViewAngles, focusAngles); // if dead, look at killer if (cg.predictedPlayerState.stats[STAT_HEALTH] <= 0) { focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW]; cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW]; } if (focusAngles[PITCH] > 45) { focusAngles[PITCH] = 45; // don't go too far overhead } AngleVectors(focusAngles, forward, NULL, NULL); VectorMA(cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint); VectorCopy(cg.refdef.vieworg, view); view[2] += 8; cg.refdefViewAngles[PITCH] *= 0.5; AngleVectors(cg.refdefViewAngles, forward, right, up); forwardScale = cos(cg_thirdPersonAngle.value / 180 * M_PI); sideScale = sin(cg_thirdPersonAngle.value / 180 * M_PI); VectorMA(view, -cg_thirdPersonRange.value * forwardScale, forward, view); VectorMA(view, -cg_thirdPersonRange.value * sideScale, right, view); // trace a ray from the origin to the viewpoint to make sure the view isn't // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything if (!cg_cameraMode.integer) { CG_Trace(&trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID); if (trace.fraction != 1.0) { VectorCopy(trace.endpos, view); view[2] += (1.0 - trace.fraction) * 32; // try another trace to this position, because a tunnel may have the ceiling // close enough that this is poking out CG_Trace(&trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID); VectorCopy(trace.endpos, view); } } VectorCopy(view, cg.refdef.vieworg); // select pitch to look at focus point from vieword VectorSubtract(focusPoint, cg.refdef.vieworg, focusPoint); focusDist = sqrt(focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1]); if (focusDist < 1) { focusDist = 1; // should never happen } cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2(focusPoint[2], focusDist); cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value; }
static void CG_OffsetFirstPersonView(void) { float *origin; float *angles; float delta; float f; int timeDelta; if (cg.snap->ps.pm_type == PM_INTERMISSION) { return; } origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; // if dead, fix the angle and don't add any kick if (cg.snap->ps.stats[STAT_HEALTH] <= 0) { angles[ROLL] = 40; angles[PITCH] = -15; angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; origin[2] += cg.predictedPlayerState.viewheight; return; } // add view height origin[2] += cg.predictedPlayerState.viewheight; // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if (timeDelta < DUCK_TIME) { cg.refdef.vieworg[2] -= cg.duckChange * (DUCK_TIME - timeDelta) / DUCK_TIME; } // add fall height delta = cg.time - cg.landTime; if (delta < LAND_DEFLECT_TIME) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[2] += cg.landChange * f; } else if (delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME) { delta -= LAND_DEFLECT_TIME; f = 1.0 - (delta / LAND_RETURN_TIME); cg.refdef.vieworg[2] += cg.landChange * f; } // add step offset CG_StepOffset(); // pivot the eye based on a neck length #if 0 { #define NECK_LENGTH 8 vec3_t forward, up; cg.refdef.vieworg[2] -= NECK_LENGTH; AngleVectors(cg.refdefViewAngles, forward, NULL, up); VectorMA(cg.refdef.vieworg, 3, forward, cg.refdef.vieworg); VectorMA(cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg); } #endif }
/* * Tests whether the player entity ent is visible from the point origin. */ qboolean SV_IsPlayerVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, sharedEntity_t *ent, vec3_t diff) { int i,contents_mask,goal_ent,viewer_clnum,ent_clnum,tries; trace_t tr; vec3_t start,end,dir,entangles,angles,temp,forward; sharedEntity_t *viewer_ent; client_t *viewer_cl, *ent_cl; playerState_t *viewer_ps, *ent_ps; float pitch; viewer_clnum = frame->ps.clientNum; // get the client number of the viewer ent_clnum = ent->s.clientNum; // get the client number of the other player if (viewer_clnum == ent_clnum) { // in case the viewer is the player entity return qtrue; // we don't need to hide us from ourselves } viewer_ps = &frame->ps; ent_ps = SV_GameClientNum(ent_clnum); if (viewer_ps->pm_type != PM_NORMAL) { // if the viewer is dead or spectating return qtrue; // let every entity be visible } if (ent_ps->pm_type != PM_NORMAL || (ent->s.weapon == WP_NONE)) { // if the player entity is dead or spectating return qtrue; } viewer_cl = svs.clients+viewer_clnum; // get the client of the viewer ent_cl = svs.clients+ent_clnum; // get the client of the other player // if (viewer_clnum > ent_clnum) { // if viewer_clnum > ent_clnum, we have already tested whether ent_clnum is able to see viewer_clnum. // if (ent_cl->tracetimer[viewer_clnum] > sv.time) return qtrue; // and we could assume symmetry of SV_IsPlayerVisibleFromPoint // } if (viewer_cl->tracetimer[ent_clnum] > sv.time+MEMORY+10) { // if the sv.time has been reset viewer_cl->tracetimer[ent_clnum] = sv.time; // reset the tracetimer } else if (viewer_cl->tracetimer[ent_clnum] > (sv.time+MEMORY-10)) { // if we have recently seen this entity, we are lazy and assume it is still visible // Com_Printf(va("client: %i, seen: %i\n", ent_clnum, viewer_cl->tracetimer[ent_clnum])); return qtrue; } goal_ent = SV_NumForGentity(ent); // this might always be the same as ent_clnum viewer_ent = SV_GentityNum(viewer_clnum); contents_mask = CONTENTS_SOLID;// |CONTENTS_BODY will work for doors, but also for windows |CONTENTS_PLAYERCLIP|CONTENTS_SOLID|CONTENTS_MOVER|CONTENTS_PLAYERCLIP // if (seen->v.movetype == MOVETYPE_PUSH ) { //don't cull doors and plats :( // return false; // } // if (sv_antiwallhack.value == 1) //1 only check player models, 2 = check all ents // if (strcmp(pr_strings + seen->v.classname, "player")) // return qfalse; // get camera origin (according to \cg_drawdebug 1) start[0] = origin[0]; start[1] = origin[1]; start[2] = origin[2]+3.0f; VectorCopy(viewer_ps->viewangles, angles); AnglesNormalize180(angles); pitch = angles[PITCH]; angles[PITCH] = 0; angles[ROLL] = 0; AngleVectors(angles, forward, NULL, NULL); VectorScale(forward, (pitch/3.5f), temp); VectorAdd( start, temp, start); // if there is sufficient distance between viewer and player entity, check if player entity is within viewer's field of vision VectorSubtract(ent->r.currentOrigin, start, dir); // VectorAdd(ent->r.currentOrigin,dir,diff);// fill diff VectorCopy(viewer_ent->s.pos.trBase,diff);// fill diff vectoangles(dir, entangles); dir[2]=0; // pretend, players are on the same level (the height should no be taken into account) if (VectorLength(dir) > 1024) {// if it is not within close range (x,y-wise, not z-wise) if (!InFieldOfVision(viewer_ps->viewangles, 60.f, entangles, ent_clnum)) {// If the player entity is not in the field of vision of the viewer // Com_Printf( va("behind: %i vorg: %f,%f,%f vang: %f,%f,%f eorg: %f,%f,%f dir: %f,%f,%f eang: %f,%f,%f ent: %i\n", viewer_clnum,origin[0],origin[1],origin[2],viewer_ps->viewangles[0],viewer_ps->viewangles[1],viewer_ps->viewangles[2],ent->r.currentOrigin[0],ent->r.currentOrigin[1],ent->r.currentOrigin[2],dir[0],dir[1],dir[2],entangles[0],entangles[1],entangles[2],ent_clnum)); return qtrue; // if the player entity is behind the viewer, abstain from any computations (and transmit the entity to hear sounds) // } else { // Com_Printf( va("front: %i vorg: %f,%f,%f vang: %f,%f,%f eorg: %f,%f,%f dir: %f,%f,%f eang: %f,%f,%f ent: %i\n", viewer_clnum,origin[0],origin[1],origin[2],viewer_ps->viewangles[0],viewer_ps->viewangles[1],viewer_ps->viewangles[2],ent->r.currentOrigin[0],ent->r.currentOrigin[1],ent->r.currentOrigin[2],dir[0],dir[1],dir[2],entangles[0],entangles[1],entangles[2],ent_clnum)); } } // aim straight at the head of the entity from our eyes end[0] = ent->r.currentOrigin[0]; end[1] = ent->r.currentOrigin[1]; end[2] = ent->r.currentOrigin[2]+ent->r.maxs[2];// "+3.0f" doesn't do it. "+ent->r.maxs[2]" is at the top of the BBox VectorCopy(ent_ps->viewangles, angles); AnglesNormalize180(angles); pitch = angles[PITCH]; angles[PITCH] = 0; angles[ROLL] = 0; AngleVectors(angles, forward, NULL, NULL); VectorScale(forward, (pitch/3.5f), temp); VectorAdd( end, temp, end); memset (&tr, 0, sizeof(tr)); tr.fraction = 1; // check the head SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse); // Com_Printf(va("client: %i, trace: %f\n", ent->s.clientNum, tr.fraction)); if (tr.fraction == 1 || tr.entityNum==goal_ent) {// tr.fraction == 1 || if there is a line of sight to the entity viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units return qtrue;// and signal the entity is visible } // Com_Printf(va("origin(%f %f %f) min(%f %f %f) max(%f %f %f)\n", start[0], start[1], start[2], mins[0],mins[1],mins[2],maxs[0],maxs[1],maxs[2])); // check the last good offset VectorAdd(ent->r.currentOrigin,viewer_cl->lasttrace[ent_clnum],end); SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse); // Com_Printf(va("client: %i, trace: %f\n", ent->s.clientNum, tr.fraction)); if (tr.fraction == 1 || tr.entityNum==goal_ent) {// tr.fraction == 1 || if there is a line of sight to the entity viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units return qtrue;// and signal the entity is visible } // random tries = (viewer_cl->tracetimer[ent_clnum]+(MEMORY*20) > sv.time)?8:2;// if we have seen an entity recently, we try hard to locate it again for (i=0; i<tries; i++) {// Even if the head is not visible, other body parts might be. Let's check a few randomly selected points end[0] = ent->r.currentOrigin[0] + offsetrandom(ent->r.mins[0], ent->r.maxs[0]); end[1] = ent->r.currentOrigin[1] + offsetrandom(ent->r.mins[1], ent->r.maxs[1]); end[2] = ent->r.currentOrigin[2] + offsetrandom(ent->r.mins[2], ent->r.maxs[2]+3.f); SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse); if (tr.fraction == 1 || tr.entityNum==goal_ent) {// if there is a line of sight to the entity // Com_Printf(va("found ent in %i hits\n", i)); viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units VectorSubtract(end, ent->r.currentOrigin, viewer_cl->lasttrace[ent_clnum]);// remember the offset return qtrue;// and signal the entity is visible } } viewer_cl->lasttrace[ent_clnum][0] = offsetrandom(ent->r.mins[0], ent->r.maxs[0]); viewer_cl->lasttrace[ent_clnum][1] = offsetrandom(ent->r.mins[1], ent->r.maxs[1]); viewer_cl->lasttrace[ent_clnum][2] = offsetrandom(ent->r.mins[2], ent->r.maxs[2]+3.f); return (viewer_cl->tracetimer[ent_clnum] > sv.time);// returns true if the entity was visible within the last 200 time units }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void UTIL_FindPositionInRadius( positioninradius_t &info, CBaseEntity *navMeshEnt ) { Vector vecDir, vecTest; trace_t tr; for(; info.m_vFan.y < 360 - info.m_fStepSize; info.m_vFan.y += info.m_fStepSize ) { AngleVectors( info.m_vFan, &vecDir ); vecTest = info.m_vStartPosition + vecDir * info.m_fRadius; Vector vEndPos; #ifdef ENABLE_PYTHON if( RecastMgr().HasMeshes() ) { vEndPos = NavMeshGetPositionNearestNavArea( vecTest, info.m_fBeneathLimit, 128.0f, navMeshEnt ); if( vEndPos == vec3_origin ) continue; } else #endif // ENABLE_PYTHON { UTIL_TraceLine( vecTest, vecTest - Vector( 0, 0, MAX_TRACE_LENGTH ), MASK_SHOT, info.m_hIgnore.Get(), COLLISION_GROUP_NONE, &tr ); if( tr.fraction == 1.0 ) continue; vEndPos = tr.endpos; } if( info.m_bTestPosition ) { // Test position vEndPos.z += -info.m_vMins.z + info.m_fZOffset; UTIL_TraceHull( vEndPos, vEndPos + Vector( 0, 0, 10 ), info.m_vMins, info.m_vMaxs, info.m_iMask, info.m_hIgnore.Get(), COLLISION_GROUP_NONE, &tr ); if( tr.fraction == 1.0 ) { info.m_vPosition = tr.endpos; info.m_bSuccess = true; info.m_vFan.y += info.m_fStepSize; return; } } else { info.m_vPosition = vEndPos; info.m_vPosition.z += info.m_fZOffset; info.m_bSuccess = true; info.m_vFan.y += info.m_fStepSize; return; } } info.m_bSuccess = false; }
/** * @param[in] tile Tile to check (normally 0 - except in assembled maps) * @param[in] traceLine The start and stop vectors of the trace * @param[in] traceBox The box we shove through the world * @param[in] headnode if < 0 we are in a leaf node * @param[in] contentmask content flags the trace should stop at (see MASK_*) * @param[in] brushrejects brushes the trace should ignore (see MASK_*) * @param[in] origin center for rotating objects * @param[in] angles current rotation status (in degrees) for rotating objects * @param[in] rmaShift how much the object was shifted by the RMA process (needed for doors) * @param[in] fraction The furthest distance needed to trace before we stop. * @brief Handles offseting and rotation of the end points for moving and rotating entities * @sa CM_BoxTrace */ trace_t CM_HintedTransformedBoxTrace (MapTile& tile, const Line& traceLine, const AABB& traceBox, const int headnode, const int contentmask, const int brushrejects, const vec3_t origin, const vec3_t angles, const vec3_t rmaShift, const float fraction) { vec3_t start_l, end_l; vec3_t forward, right, up; vec3_t temp; bool rotated; /* subtract origin offset */ VectorSubtract(traceLine.start, origin, start_l); VectorSubtract(traceLine.stop, origin, end_l); /* rotate start and end into the models frame of reference */ if (headnode != tile.box_headnode && VectorNotEmpty(angles)) { rotated = true; } else { rotated = false; } if (rotated) { AngleVectors(angles, forward, right, up); VectorCopy(start_l, temp); start_l[0] = DotProduct(temp, forward); start_l[1] = -DotProduct(temp, right); start_l[2] = DotProduct(temp, up); VectorCopy(end_l, temp); end_l[0] = DotProduct(temp, forward); end_l[1] = -DotProduct(temp, right); end_l[2] = DotProduct(temp, up); } /* When tracing through a model, we want to use the nodes, planes etc. as calculated by ufo2map. * But nodes and planes have been shifted in case of an RMA. At least for doors we need to undo the shift. */ if (VectorNotEmpty(origin)) { /* only doors seem to have their origin set */ VectorAdd(start_l, rmaShift, start_l); /* undo the shift */ VectorAdd(end_l, rmaShift, end_l); } /* sweep the box through the model */ boxtrace_t traceData; traceData.init(&tile, contentmask, brushrejects, fraction); traceData.setLineAndBox(Line(start_l, end_l), traceBox); trace_t trace = TR_BoxTrace(traceData, Line(start_l, end_l), traceBox, headnode, fraction); trace.mapTile = tile.idx; if (rotated && trace.fraction != 1.0) { vec3_t a; /** @todo figure out how to do this with existing angles */ VectorNegate(angles, a); AngleVectors(a, forward, right, up); VectorCopy(trace.plane.normal, temp); trace.plane.normal[0] = DotProduct(temp, forward); trace.plane.normal[1] = -DotProduct(temp, right); trace.plane.normal[2] = DotProduct(temp, up); } VectorInterpolation(traceLine.start, traceLine.stop, trace.fraction, trace.endpos); return trace; }
void C_EnvProjectedTexture::UpdateLight( bool bForceUpdate ) { if ( m_bState == false ) { if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { ShutDownLightHandle(); } return; } Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); FlashlightState_t state; if ( m_hTargetEntity != NULL ) { if ( m_bCameraSpace ) { const QAngle &angles = GetLocalAngles(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if( pPlayer ) { const QAngle playerAngles = pPlayer->GetAbsAngles(); Vector vPlayerForward, vPlayerRight, vPlayerUp; AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); matrix3x4_t mRotMatrix; AngleMatrix( angles, mRotMatrix ); VectorITransform( vPlayerForward, mRotMatrix, vForward ); VectorITransform( vPlayerRight, mRotMatrix, vRight ); VectorITransform( vPlayerUp, mRotMatrix, vUp ); float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; VectorNormalize( vForward ); VectorNormalize( vRight ); VectorNormalize( vUp ); } } else { vForward = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize( vForward ); // JasonM - unimplemented Assert (0); //Quaternion q = DirectionToOrientation( dir ); // // JasonM - set up vRight, vUp // // VectorNormalize( vRight ); // VectorNormalize( vUp ); } } else { AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); } state.m_fHorizontalFOVDegrees = m_flLightFOV; state.m_fVerticalFOVDegrees = m_flLightFOV; state.m_vecLightOrigin = vPos; BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); state.m_fQuadraticAtten = 0.0; state.m_fLinearAtten = 100; state.m_fConstantAtten = 0.0f; state.m_Color[0] = m_LinearFloatLightColor.x; state.m_Color[1] = m_LinearFloatLightColor.y; state.m_Color[2] = m_LinearFloatLightColor.z; state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; state.m_NearZ = m_flNearZ; state.m_FarZ = m_flFarZ; state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); state.m_bEnableShadows = m_bEnableShadows; state.m_pSpotlightTexture = materials->FindTexture( m_SpotlightTextureName, TEXTURE_GROUP_OTHER, false ); state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE ) { m_LightHandle = g_pClientShadowMgr->CreateFlashlight( state ); } else { if ( m_hTargetEntity != NULL || bForceUpdate == true ) { g_pClientShadowMgr->UpdateFlashlightState( m_LightHandle, state ); } } if( m_bLightOnlyTarget ) { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, m_hTargetEntity ); } else { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, NULL ); } g_pClientShadowMgr->SetFlashlightLightWorld( m_LightHandle, m_bLightWorld ); if ( bForceUpdate == false ) { g_pClientShadowMgr->UpdateProjectedTexture( m_LightHandle, true ); } }
//----------------------------------------------------------------------------- // // Look for vgui screens, returns true if it found one ... // //----------------------------------------------------------------------------- C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &viewAngle, int nTeam ) { if ( IsX360() ) { // X360TBD: Turn this on if feature actually used return NULL; } C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); Assert( pLocalPlayer ); if ( !pLocalPlayer ) return NULL; // Get the view direction... Vector lookDir; AngleVectors( viewAngle, &lookDir ); // Create a ray used for raytracing Vector lookEnd; VectorMA( viewPosition, 2.0f * VGUI_SCREEN_MODE_RADIUS, lookDir, lookEnd ); Ray_t lookRay; lookRay.Init( viewPosition, lookEnd ); // Look for vgui screens that are close to the player CVGuiScreenEnumerator localScreens; partition->EnumerateElementsInSphere( PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens ); Vector vecOut, vecViewDelta; float flBestDist = 2.0f; C_VGuiScreen *pBestScreen = NULL; for (int i = localScreens.GetScreenCount(); --i >= 0; ) { C_VGuiScreen *pScreen = localScreens.GetVGuiScreen(i); if ( pScreen->IsAttachedToViewModel() ) continue; // Don't bother with screens I'm behind... // Hax - don't cancel backfacing with viewmodel attached screens. // we can get prediction bugs that make us backfacing for one frame and // it resets the mouse position if we lose focus. if ( pScreen->IsBackfacing(viewPosition) ) continue; // Don't bother with screens that are turned off if (!pScreen->IsActive()) continue; // FIXME: Should this maybe go into a derived class of some sort? // Don't bother with screens on the wrong team if (!pScreen->IsVisibleToTeam(nTeam)) continue; if ( !pScreen->AcceptsInput() ) continue; if ( pScreen->IsInputOnlyToOwner() && pScreen->GetPlayerOwner() != pLocalPlayer ) continue; // Test perpendicular distance from the screen... pScreen->GetVectors( NULL, NULL, &vecOut ); VectorSubtract( viewPosition, pScreen->GetAbsOrigin(), vecViewDelta ); float flPerpDist = DotProduct(vecViewDelta, vecOut); if ( (flPerpDist < 0) || (flPerpDist > VGUI_SCREEN_MODE_RADIUS) ) continue; // Perform a raycast to see where in barycentric coordinates the ray hits // the viewscreen; if it doesn't hit it, you're not in the mode float u, v, t; if (!pScreen->IntersectWithRay( lookRay, &u, &v, &t )) continue; // Barycentric test if ((u < 0) || (v < 0) || (u > 1) || (v > 1)) continue; if ( t < flBestDist ) { flBestDist = t; pBestScreen = pScreen; } } return pBestScreen; }
void SP_trigger_fog (edict_t *self) { fog_t *fog; if( !allow_fog->value ) { G_FreeEdict(self); return; } if(deathmatch->value || coop->value) { G_FreeEdict(self); return; } self->class_id = ENTITY_TRIGGER_FOG; if(!level.fogs) level.fogs = 1; // 1st fog reserved for console commands if(level.fogs >= MAX_FOGS) { gi.dprintf("Maximum number of fogs exceeded!\n"); G_FreeEdict(self); return; } self->fog_index = level.fogs+1; fog = &gfogs[level.fogs]; fog->Trigger = true; fog->Model = self->fog_model; if(fog->Model < 0 || fog->Model > 2) fog->Model = 0; fog->GL_Model = GLModels[fog->Model]; VectorCopy(self->fog_color,fog->Color); if(self->spawnflags & FOG_TURNOFF) { fog->Near = 4999; fog->Far = 5000; fog->Density = 0; fog->Density1 = 0; fog->Density2 = 0; } else { fog->Near = self->fog_near; fog->Far = self->fog_far; fog->Density = self->fog_density; fog->Density1 = self->fog_density; if(self->density == 0.) self->density = self->fog_density; else if(self->density < 0.) self->density = 0.; fog->Density2= self->density; } if(!(self->spawnflags & FOG_STARTOFF)) self->spawnflags |= FOG_ON; AngleVectors(self->s.angles,fog->Dir,0,0); VectorClear(self->s.angles); fog->ent = self; level.fogs++; level.trigger_fogs++; self->movetype = MOVETYPE_NONE; self->svflags |= SVF_NOCLIENT; self->solid = SOLID_NOT; gi.setmodel (self, self->model); gi.linkentity(self); }
/** * @brief Resolves ambient light, brightness, and contrast levels from Worldspawn. */ static void R_ResolveBspLightParameters(void) { const char *c; vec3_t tmp; // resolve ambient light if ((c = Cm_WorldspawnValue("ambient"))) { vec_t *f = r_bsp_light_state.ambient; sscanf(c, "%f %f %f", &f[0], &f[1], &f[2]); VectorScale(f, r_modulate->value, f); Com_Debug(DEBUG_RENDERER, "Resolved ambient: %s\n", vtos(f)); } else { VectorSet(r_bsp_light_state.ambient, 0.15, 0.15, 0.15); } // resolve sun light if ((c = Cm_WorldspawnValue("sun_light"))) { r_bsp_light_state.sun.diffuse = atof(c) * BSP_LIGHT_SUN_SCALE; Com_Debug(DEBUG_RENDERER, "Resolved sun_light: %1.2f\n", r_bsp_light_state.sun.diffuse); } else { r_bsp_light_state.sun.diffuse = 0.0; } // resolve sun angles and direction if ((c = Cm_WorldspawnValue("sun_angles"))) { VectorClear(tmp); sscanf(c, "%f %f", &tmp[0], &tmp[1]); Com_Debug(DEBUG_RENDERER, "Resolved sun_angles: %s\n", vtos(tmp)); AngleVectors(tmp, r_bsp_light_state.sun.dir, NULL, NULL); } else { VectorCopy(vec3_down, r_bsp_light_state.sun.dir); } // resolve sun color if ((c = Cm_WorldspawnValue("sun_color"))) { vec_t *f = r_bsp_light_state.sun.color; sscanf(c, "%f %f %f", &f[0], &f[1], &f[2]); Com_Debug(DEBUG_RENDERER, "Resolved sun_color: %s\n", vtos(f)); } else { VectorSet(r_bsp_light_state.sun.color, 1.0, 1.0, 1.0); } // resolve brightness if ((c = Cm_WorldspawnValue("brightness"))) { r_bsp_light_state.brightness = atof(c); } else { r_bsp_light_state.brightness = 1.0; } // resolve saturation if ((c = Cm_WorldspawnValue("saturation"))) { r_bsp_light_state.saturation = atof(c); } else { r_bsp_light_state.saturation = 1.0; } // resolve contrast if ((c = Cm_WorldspawnValue("contrast"))) { r_bsp_light_state.contrast = atof(c); } else { r_bsp_light_state.contrast = 1.0; } Com_Debug(DEBUG_RENDERER, "Resolved brightness: %1.2f\n", r_bsp_light_state.brightness); Com_Debug(DEBUG_RENDERER, "Resolved saturation: %1.2f\n", r_bsp_light_state.saturation); Com_Debug(DEBUG_RENDERER, "Resolved contrast: %1.2f\n", r_bsp_light_state.contrast); const vec_t brt = r_bsp_light_state.brightness; const vec_t sat = r_bsp_light_state.saturation; const vec_t con = r_bsp_light_state.contrast; // apply brightness, saturation and contrast to the colors ColorFilter(r_bsp_light_state.ambient, r_bsp_light_state.ambient, brt, sat, con); Com_Debug(DEBUG_RENDERER, "Scaled ambient: %s\n", vtos(r_bsp_light_state.ambient)); ColorFilter(r_bsp_light_state.sun.color, r_bsp_light_state.sun.color, brt, sat, con); Com_Debug(DEBUG_RENDERER, "Scaled sun color: %s\n", vtos(r_bsp_light_state.sun.color)); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPropAPC::Event_Killed( const CTakeDamageInfo &info ) { m_OnDeath.FireOutput( info.GetAttacker(), this ); Vector vecAbsMins, vecAbsMaxs; CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs ); Vector vecNormalizedMins, vecNormalizedMaxs; CollisionProp()->WorldToNormalizedSpace( vecAbsMins, &vecNormalizedMins ); CollisionProp()->WorldToNormalizedSpace( vecAbsMaxs, &vecNormalizedMaxs ); Vector vecAbsPoint; CPASFilter filter( GetAbsOrigin() ); for (int i = 0; i < 5; i++) { CollisionProp()->RandomPointInBounds( vecNormalizedMins, vecNormalizedMaxs, &vecAbsPoint ); te->Explosion( filter, random->RandomFloat( 0.0, 1.0 ), &vecAbsPoint, g_sModelIndexFireball, random->RandomInt( 4, 10 ), random->RandomInt( 8, 15 ), ( i < 2 ) ? TE_EXPLFLAG_NODLIGHTS : TE_EXPLFLAG_NOPARTICLES | TE_EXPLFLAG_NOFIREBALLSMOKE | TE_EXPLFLAG_NODLIGHTS, 100, 0 ); } // TODO: make the gibs spawn in sync with the delayed explosions int nGibs = random->RandomInt( 1, 4 ); for ( int i = 0; i < nGibs; i++) { // Throw a flaming, smoking chunk. CGib *pChunk = CREATE_ENTITY( CGib, "gib" ); pChunk->Spawn( "models/gibs/hgibs.mdl" ); pChunk->SetBloodColor( DONT_BLEED ); QAngle vecSpawnAngles; vecSpawnAngles.Random( -90, 90 ); pChunk->SetAbsOrigin( vecAbsPoint ); pChunk->SetAbsAngles( vecSpawnAngles ); int nGib = random->RandomInt( 0, APC_MAX_CHUNKS - 1 ); pChunk->Spawn( s_pChunkModelName[nGib] ); pChunk->SetOwnerEntity( this ); pChunk->m_lifeTime = random->RandomFloat( 6.0f, 8.0f ); pChunk->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); IPhysicsObject *pPhysicsObject = pChunk->VPhysicsInitNormal( SOLID_VPHYSICS, pChunk->GetSolidFlags(), false ); // Set the velocity if ( pPhysicsObject ) { pPhysicsObject->EnableMotion( true ); Vector vecVelocity; QAngle angles; angles.x = random->RandomFloat( -20, 20 ); angles.y = random->RandomFloat( 0, 360 ); angles.z = 0.0f; AngleVectors( angles, &vecVelocity ); vecVelocity *= random->RandomFloat( 300, 900 ); vecVelocity += GetAbsVelocity(); AngularImpulse angImpulse; angImpulse = RandomAngularImpulse( -180, 180 ); pChunk->SetAbsVelocity( vecVelocity ); pPhysicsObject->SetVelocity(&vecVelocity, &angImpulse ); } CEntityFlame *pFlame = CEntityFlame::Create( pChunk, false ); if ( pFlame != NULL ) { pFlame->SetLifetime( pChunk->m_lifeTime ); } } UTIL_ScreenShake( vecAbsPoint, 25.0, 150.0, 1.0, 750.0f, SHAKE_START ); if( hl2_episodic.GetBool() ) { // EP1 perf hit Ignite( 6, false ); } else { Ignite( 60, false ); } m_lifeState = LIFE_DYING; // Spawn a lesser amount if the player is close m_iRocketSalvoLeft = DEATH_VOLLEY_ROCKET_COUNT; m_flRocketTime = gpGlobals->curtime; }
void EV_FireSG552( event_args_t *args ) { int idx; vec3_t origin; vec3_t angles; vec3_t velocity; vec3_t ShellVelocity; vec3_t ShellOrigin; int shell; vec3_t vecSrc, vecAiming; vec3_t up, right, forward; idx = args->entindex; VectorCopy( args->origin, origin ); angles.x = (long double)args->iparam1 / 100 + args->angles[0]; angles.y = (long double)args->iparam2 / 100 + args->angles[1]; angles.z = args->angles[2]; VectorCopy( args->velocity, velocity ); AngleVectors( angles, forward, right, up ); if ( EV_IsLocal( idx ) ) { ++g_iShotsFired; EV_MuzzleFlash(); gEngfuncs.pEventAPI->EV_WeaponAnimation(gEngfuncs.pfnRandomLong(SG552_SHOOT1, SG552_SHOOT3), 2); if( !cl_righthand->value ) { EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20.0, -8.0, -10.0, 0); } else { EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20.0, -8.0, 10.0, 0); } } else { EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20.0, -12.0, 4.0, 0); } shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/rshell.mdl"); EV_EjectBrass(ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL); gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, gEngfuncs.pfnRandomLong( 0, 1 ) ? "weapons/sg552-1.wav" : "weapons/sg552-2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); EV_GetGunPosition( args, vecSrc, origin ); VectorCopy( forward, vecAiming ); Vector vSpread; int tracerCount; vSpread.x = args->fparam1; vSpread.y = args->fparam2; EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, vSpread, 8192.0, BULLET_PLAYER_556MM, 0, &tracerCount, 2 ); }
/* ================ R_DrawSprite ================ */ void R_DrawSprite (void) { int i; msprite_t *psprite; vec3_t tvec; float dot, angle, sr, cr; psprite = currententity->model->cache.data; r_spritedesc.pspriteframe = R_GetSpriteframe (psprite); sprite_width = r_spritedesc.pspriteframe->width; sprite_height = r_spritedesc.pspriteframe->height; // TODO: make this caller-selectable if (psprite->type == SPR_FACING_UPRIGHT) { // generate the sprite's axes, with vup straight up in worldspace, and // r_spritedesc.vright perpendicular to modelorg. // This will not work if the view direction is very close to straight up or // down, because the cross product will be between two nearly parallel // vectors and starts to approach an undefined state, so we don't draw if // the two vectors are less than 1 degree apart tvec[0] = -modelorg[0]; tvec[1] = -modelorg[1]; tvec[2] = -modelorg[2]; VectorNormalize (tvec); dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because // r_spritedesc.vup is 0, 0, 1 if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848 return; r_spritedesc.vup[0] = 0; r_spritedesc.vup[1] = 0; r_spritedesc.vup[2] = 1; r_spritedesc.vright[0] = tvec[1]; // CrossProduct(r_spritedesc.vup, -modelorg, r_spritedesc.vright[1] = -tvec[0]; // r_spritedesc.vright) r_spritedesc.vright[2] = 0; VectorNormalize (r_spritedesc.vright); r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; r_spritedesc.vpn[1] = r_spritedesc.vright[0]; r_spritedesc.vpn[2] = 0; // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, // r_spritedesc.vpn) } else if (psprite->type == SPR_VP_PARALLEL) { // generate the sprite's axes, completely parallel to the viewplane. There // are no problem situations, because the sprite is always in the same // position relative to the viewer for (i=0 ; i<3 ; i++) { r_spritedesc.vup[i] = vup[i]; r_spritedesc.vright[i] = vright[i]; r_spritedesc.vpn[i] = vpn[i]; } } else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) { // generate the sprite's axes, with vup straight up in worldspace, and // r_spritedesc.vright parallel to the viewplane. // This will not work if the view direction is very close to straight up or // down, because the cross product will be between two nearly parallel // vectors and starts to approach an undefined state, so we don't draw if // the two vectors are less than 1 degree apart dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because // r_spritedesc.vup is 0, 0, 1 if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848 return; r_spritedesc.vup[0] = 0; r_spritedesc.vup[1] = 0; r_spritedesc.vup[2] = 1; r_spritedesc.vright[0] = vpn[1]; // CrossProduct (r_spritedesc.vup, vpn, r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright) r_spritedesc.vright[2] = 0; VectorNormalize (r_spritedesc.vright); r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; r_spritedesc.vpn[1] = r_spritedesc.vright[0]; r_spritedesc.vpn[2] = 0; // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, // r_spritedesc.vpn) } else if (psprite->type == SPR_ORIENTED) { // generate the sprite's axes, according to the sprite's world orientation AngleVectors (currententity->angles, r_spritedesc.vpn, r_spritedesc.vright, r_spritedesc.vup); } else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) { // generate the sprite's axes, parallel to the viewplane, but rotated in // that plane around the center according to the sprite entity's roll // angle. So vpn stays the same, but vright and vup rotate angle = currententity->angles[ROLL] * (M_PI*2 / 360); sr = sin(angle); cr = cos(angle); for (i=0 ; i<3 ; i++) { r_spritedesc.vpn[i] = vpn[i]; r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr; r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr; } } else { Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type); } R_RotateSprite (psprite->beamlength); R_SetupAndDrawSprite (); }
void G_MissileImpact( gentity_t *ent, trace_t *trace ) { gentity_t *other; qboolean hitClient = qfalse; qboolean isKnockedSaber = qfalse; other = &g_entities[trace->entityNum]; // check for bounce if ( !other->takedamage && (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags & ( FL_BOUNCE | FL_BOUNCE_HALF ) ) ) { G_BounceMissile( ent, trace ); G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 ); return; } else if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF)) { //this is a knocked-away saber if (ent->bounceCount > 0 || ent->bounceCount == -5) { G_BounceMissile( ent, trace ); G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 ); return; } isKnockedSaber = qtrue; } // I would glom onto the FL_BOUNCE code section above, but don't feel like risking breaking something else if ( (!other->takedamage && (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags&(FL_BOUNCE_SHRAPNEL) ) ) || ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius&&(ent->bounceCount > 0 || ent->bounceCount == -5)) ) { G_BounceMissile( ent, trace ); if ( ent->bounceCount < 1 ) { ent->flags &= ~FL_BOUNCE_SHRAPNEL; } return; } /* if ( !other->takedamage && ent->s.weapon == WP_THERMAL && !ent->alt_fire ) {//rolling thermal det - FIXME: make this an eFlag like bounce & stick!!! //G_BounceRollMissile( ent, trace ); if ( ent->owner && ent->owner->s.number == 0 ) { G_MissileAddAlerts( ent ); } //gi.linkentity( ent ); return; } */ if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber) { //hit this person's saber, so.. gentity_t *otherOwner = &g_entities[other->r.ownerNum]; if (otherOwner->takedamage && otherOwner->client && otherOwner->client->ps.duelInProgress && otherOwner->client->ps.duelIndex != ent->r.ownerNum) { goto killProj; } } else if (!isKnockedSaber) { if (other->takedamage && other->client && other->client->ps.duelInProgress && other->client->ps.duelIndex != ent->r.ownerNum) { goto killProj; } } if (other->flags & FL_DMG_BY_HEAVY_WEAP_ONLY) { if (ent->methodOfDeath != MOD_REPEATER_ALT && ent->methodOfDeath != MOD_ROCKET && ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && ent->methodOfDeath != MOD_ROCKET_HOMING && ent->methodOfDeath != MOD_THERMAL && ent->methodOfDeath != MOD_THERMAL_SPLASH && ent->methodOfDeath != MOD_TRIP_MINE_SPLASH && ent->methodOfDeath != MOD_TIMED_MINE_SPLASH && ent->methodOfDeath != MOD_DET_PACK_SPLASH && ent->methodOfDeath != MOD_VEHICLE && ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT && ent->methodOfDeath != MOD_SABER && ent->methodOfDeath != MOD_TURBLAST) { vec3_t fwd; if (trace) { VectorCopy(trace->plane.normal, fwd); } else { //oh well AngleVectors(other->r.currentAngles, fwd, NULL, NULL); } G_DeflectMissile(other, ent, fwd); G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd); return; } } if ((other->flags & FL_SHIELDED) && ent->s.weapon != WP_ROCKET_LAUNCHER && ent->s.weapon != WP_THERMAL && ent->s.weapon != WP_TRIP_MINE && ent->s.weapon != WP_DET_PACK && ent->s.weapon != WP_DEMP2 && ent->s.weapon != WP_EMPLACED_GUN && ent->methodOfDeath != MOD_REPEATER_ALT && ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && ent->methodOfDeath != MOD_TURBLAST && ent->methodOfDeath != MOD_VEHICLE && ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT && !(ent->dflags&DAMAGE_HEAVY_WEAP_CLASS) ) { vec3_t fwd; if (other->client) { AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL); } else { AngleVectors(other->r.currentAngles, fwd, NULL, NULL); } G_DeflectMissile(other, ent, fwd); G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd); return; } if (other->takedamage && other->client && ent->s.weapon != WP_ROCKET_LAUNCHER && ent->s.weapon != WP_THERMAL && ent->s.weapon != WP_TRIP_MINE && ent->s.weapon != WP_DET_PACK && ent->s.weapon != WP_DEMP2 && ent->methodOfDeath != MOD_REPEATER_ALT && ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT && other->client->ps.saberBlockTime < level.time && !isKnockedSaber && WP_SaberCanBlock(other, ent->r.currentOrigin, 0, 0, qtrue, 0)) { //only block one projectile per 200ms (to prevent giant swarms of projectiles being blocked) vec3_t fwd; gentity_t *te; int otherDefLevel = other->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]; te = G_TempEntity( ent->r.currentOrigin, EV_SABER_BLOCK ); VectorCopy(ent->r.currentOrigin, te->s.origin); VectorCopy(trace->plane.normal, te->s.angles); te->s.eventParm = 0; te->s.weapon = 0;//saberNum te->s.legsAnim = 0;//bladeNum /*if (other->client->ps.velocity[2] > 0 || other->client->pers.cmd.forwardmove || other->client->pers.cmd.rightmove) */ if (other->client->ps.velocity[2] > 0 || other->client->pers.cmd.forwardmove < 0) //now we only do it if jumping or running backward. Should be able to full-on charge. { otherDefLevel -= 1; if (otherDefLevel < 0) { otherDefLevel = 0; } } AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL); if (otherDefLevel == FORCE_LEVEL_1) { //if def is only level 1, instead of deflecting the shot it should just die here } else if (otherDefLevel == FORCE_LEVEL_2) { G_DeflectMissile(other, ent, fwd); } else { G_ReflectMissile(other, ent, fwd); } other->client->ps.saberBlockTime = level.time + (350 - (otherDefLevel*100)); //200; //For jedi AI other->client->ps.saberEventFlags |= SEF_DEFLECTED; if (otherDefLevel == FORCE_LEVEL_3) { other->client->ps.saberBlockTime = 0; //^_^ } if (otherDefLevel == FORCE_LEVEL_1) { goto killProj; } return; } else if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber) { //hit this person's saber, so.. gentity_t *otherOwner = &g_entities[other->r.ownerNum]; if (otherOwner->takedamage && otherOwner->client && ent->s.weapon != WP_ROCKET_LAUNCHER && ent->s.weapon != WP_THERMAL && ent->s.weapon != WP_TRIP_MINE && ent->s.weapon != WP_DET_PACK && ent->s.weapon != WP_DEMP2 && ent->methodOfDeath != MOD_REPEATER_ALT && ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT /*&& otherOwner->client->ps.saberBlockTime < level.time*/) { //for now still deflect even if saberBlockTime >= level.time because it hit the actual saber vec3_t fwd; gentity_t *te; int otherDefLevel = otherOwner->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]; //in this case, deflect it even if we can't actually block it because it hit our saber //WP_SaberCanBlock(otherOwner, ent->r.currentOrigin, 0, 0, qtrue, 0); if (otherOwner->client && otherOwner->client->ps.weaponTime <= 0) { WP_SaberBlockNonRandom(otherOwner, ent->r.currentOrigin, qtrue); } te = G_TempEntity( ent->r.currentOrigin, EV_SABER_BLOCK ); VectorCopy(ent->r.currentOrigin, te->s.origin); VectorCopy(trace->plane.normal, te->s.angles); te->s.eventParm = 0; te->s.weapon = 0;//saberNum te->s.legsAnim = 0;//bladeNum /*if (otherOwner->client->ps.velocity[2] > 0 || otherOwner->client->pers.cmd.forwardmove || otherOwner->client->pers.cmd.rightmove)*/ if (otherOwner->client->ps.velocity[2] > 0 || otherOwner->client->pers.cmd.forwardmove < 0) //now we only do it if jumping or running backward. Should be able to full-on charge. { otherDefLevel -= 1; if (otherDefLevel < 0) { otherDefLevel = 0; } } AngleVectors(otherOwner->client->ps.viewangles, fwd, NULL, NULL); if (otherDefLevel == FORCE_LEVEL_1) { //if def is only level 1, instead of deflecting the shot it should just die here } else if (otherDefLevel == FORCE_LEVEL_2) { G_DeflectMissile(otherOwner, ent, fwd); } else { G_ReflectMissile(otherOwner, ent, fwd); } otherOwner->client->ps.saberBlockTime = level.time + (350 - (otherDefLevel*100));//200; //For jedi AI otherOwner->client->ps.saberEventFlags |= SEF_DEFLECTED; if (otherDefLevel == FORCE_LEVEL_3) { otherOwner->client->ps.saberBlockTime = 0; //^_^ } if (otherDefLevel == FORCE_LEVEL_1) { goto killProj; } return; } } // check for sticking if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK ) ) { laserTrapStick( ent, trace->endpos, trace->plane.normal ); G_AddEvent( ent, EV_MISSILE_STICK, 0 ); return; } // impact damage if (other->takedamage && !isKnockedSaber) { // FIXME: wrong damage direction? if ( ent->damage ) { vec3_t velocity; qboolean didDmg = qfalse; if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) { g_entities[ent->r.ownerNum].client->accuracy_hits++; hitClient = qtrue; } BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity ); if ( VectorLength( velocity ) == 0 ) { velocity[2] = 1; // stepped on a grenade } if (ent->s.weapon == WP_BOWCASTER || ent->s.weapon == WP_FLECHETTE || ent->s.weapon == WP_ROCKET_LAUNCHER) { if (ent->s.weapon == WP_FLECHETTE && (ent->s.eFlags & EF_ALT_FIRING)) { ent->think(ent); } else { G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, /*ent->s.origin*/ent->r.currentOrigin, ent->damage, DAMAGE_HALF_ABSORB, ent->methodOfDeath); didDmg = qtrue; } } else { G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, /*ent->s.origin*/ent->r.currentOrigin, ent->damage, 0, ent->methodOfDeath); didDmg = qtrue; } if (didDmg && other && other->client) { //What I'm wondering is why this isn't in the NPC pain funcs. But this is what SP does, so whatever. class_t npc_class = other->client->NPC_class; // If we are a robot and we aren't currently doing the full body electricity... if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE || npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE || npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY ) { // special droid only behaviors if ( other->client->ps.electrifyTime < level.time + 100 ) { // ... do the effect for a split second for some more feedback other->client->ps.electrifyTime = level.time + 450; } //FIXME: throw some sparks off droids,too } } } if ( ent->s.weapon == WP_DEMP2 ) {//a hit with demp2 decloaks people, disables ships if ( other && other->client && other->client->NPC_class == CLASS_VEHICLE ) {//hit a vehicle if ( other->m_pVehicle //valid vehicle ent && other->m_pVehicle->m_pVehicleInfo//valid stats && (other->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER//always affect speeders ||(other->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER && ent->classname && Q_stricmp("vehicle_proj", ent->classname ) == 0) )//only vehicle ion weapons affect a fighter in this manner && !FighterIsLanded( other->m_pVehicle , &other->client->ps )//not landed && !(other->spawnflags&2) )//and not suspended {//vehicles hit by "ion cannons" lose control if ( other->client->ps.electrifyTime > level.time ) {//add onto it //FIXME: extern the length of the "out of control" time? other->client->ps.electrifyTime += Q_irand(200,500); if ( other->client->ps.electrifyTime > level.time + 4000 ) {//cap it other->client->ps.electrifyTime = level.time + 4000; } } else {//start it //FIXME: extern the length of the "out of control" time? other->client->ps.electrifyTime = level.time + Q_irand(200,500); } } } else if ( other && other->client && other->client->ps.powerups[PW_CLOAKED] ) { Jedi_Decloak( other ); if ( ent->methodOfDeath == MOD_DEMP2_ALT ) {//direct hit with alt disables cloak forever //permanently disable the saboteur's cloak other->client->cloakToggleTime = Q3_INFINITE; } else {//temp disable other->client->cloakToggleTime = level.time + Q_irand( 3000, 10000 ); } } } } killProj: // is it cheaper in bandwidth to just remove this ent and create a new // one, rather than changing the missile into the explosion? if ( other->takedamage && other->client && !isKnockedSaber ) { G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) ); ent->s.otherEntityNum = other->s.number; } else if( trace->surfaceFlags & SURF_METALSTEPS ) { G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) ); } else if (ent->s.weapon != G2_MODEL_PART && !isKnockedSaber) { G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) ); } if (!isKnockedSaber) { ent->freeAfterEvent = qtrue; // change over to a normal entity right at the point of impact ent->s.eType = ET_GENERAL; } SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth G_SetOrigin( ent, trace->endpos ); ent->takedamage = qfalse; // splash damage (doesn't apply to person directly hit) if ( ent->splashDamage ) { if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, other, ent, ent->splashMethodOfDeath ) ) { if( !hitClient && g_entities[ent->r.ownerNum].client ) { g_entities[ent->r.ownerNum].client->accuracy_hits++; } } } if (ent->s.weapon == G2_MODEL_PART) { ent->freeAfterEvent = qfalse; //it will free itself } trap_LinkEntity( ent ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CFastZombie::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_FASTZOMBIE_VERIFY_ATTACK: // Simply ensure that the zombie still has a valid melee attack if( HasCondition( COND_CAN_MELEE_ATTACK1 ) ) { TaskComplete(); } else { TaskFail(""); } break; case TASK_FASTZOMBIE_JUMP_BACK: { SetActivity( ACT_IDLE ); RemoveFlag( FL_ONGROUND ); BeginAttackJump(); Vector forward; AngleVectors( GetLocalAngles(), &forward ); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetLocalOrigin() + Vector( 0 , 0 , 1 )); ApplyAbsVelocityImpulse( forward * -200 + Vector( 0, 0, 200 ) ); } break; case TASK_FASTZOMBIE_UNSTICK_JUMP: { RemoveFlag( FL_ONGROUND ); // Call begin attack jump. A little bit later if we fail to pathfind, we check // this value to see if we just jumped. If so, we assume we've jumped // to someplace that's not pathing friendly, and so must jump again to get out. BeginAttackJump(); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetLocalOrigin() + Vector( 0 , 0 , 1 )); CBaseEntity *pEnemy = GetEnemy(); Vector vecJumpDir; if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN ) { // Jump off the pipe backwards! Vector forward; GetVectors( &forward, NULL, NULL ); ApplyAbsVelocityImpulse( forward * -200 ); } else if( pEnemy ) { vecJumpDir = pEnemy->GetLocalOrigin() - GetLocalOrigin(); VectorNormalize( vecJumpDir ); vecJumpDir.z = 0; ApplyAbsVelocityImpulse( vecJumpDir * 300 + Vector( 0, 0, 200 ) ); } else { Msg("UNHANDLED CASE! Stuck Fast Zombie with no enemy!\n"); } } break; case TASK_WAIT_FOR_MOVEMENT: // If we're waiting for movement, that means that pathfinding succeeded, and // we're about to be moving. So we aren't stuck. So clear this flag. m_fJustJumped = false; BaseClass::StartTask( pTask ); break; case TASK_FACE_ENEMY: { // We don't use the base class implementation of this, because GetTurnActivity // stomps our landing scrabble animations (sjb) Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTarget( flEnemyLKP ); } break; case TASK_FASTZOMBIE_LAND_RECOVER: { // Set the ideal yaw Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTarget( flEnemyLKP ); // figure out which way to turn. float flDeltaYaw = GetMotor()->DeltaIdealYaw(); if( flDeltaYaw < 0 ) { SetIdealActivity( (Activity)ACT_FASTZOMBIE_LAND_RIGHT ); } else { SetIdealActivity( (Activity)ACT_FASTZOMBIE_LAND_LEFT ); } TaskComplete(); } break; case TASK_RANGE_ATTACK1: // Make melee attacks impossible until we land! m_flNextMeleeAttack = gpGlobals->curtime + 60; SetTouch( LeapAttackTouch ); break; case TASK_FASTZOMBIE_DO_ATTACK: SetActivity( (Activity)ACT_FASTZOMBIE_LEAP_SOAR ); break; default: BaseClass::StartTask( pTask ); break; } }
void hyperspace_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { gentity_t *ent; if (!other || !other->inuse || !other->client || other->s.number < MAX_CLIENTS || !other->m_pVehicle) { //only let vehicles touch return; } if ( other->client->ps.hyperSpaceTime && level.time - other->client->ps.hyperSpaceTime < HYPERSPACE_TIME ) {//already hyperspacing, just keep us moving if ( (other->client->ps.eFlags2&EF2_HYPERSPACE) ) {//they've started the hyperspace but haven't been teleported yet float timeFrac = ((float)(level.time-other->client->ps.hyperSpaceTime))/HYPERSPACE_TIME; if ( timeFrac >= HYPERSPACE_TELEPORT_FRAC ) {//half-way, now teleport them! vec3_t diff, fwd, right, up, newOrg; float fDiff, rDiff, uDiff; //take off the flag so we only do this once other->client->ps.eFlags2 &= ~EF2_HYPERSPACE; //Get the offset from the local position ent = G_Find (NULL, FOFS(targetname), self->target); if (!ent || !ent->inuse) { //this is bad trap->Error(ERR_DROP, "trigger_hyperspace has invalid target '%s'\n", self->target); return; } VectorSubtract( other->client->ps.origin, ent->s.origin, diff ); AngleVectors( ent->s.angles, fwd, right, up ); fDiff = DotProduct( fwd, diff ); rDiff = DotProduct( right, diff ); uDiff = DotProduct( up, diff ); //Now get the base position of the destination ent = G_Find (NULL, FOFS(targetname), self->target2); if (!ent || !ent->inuse) { //this is bad trap->Error(ERR_DROP, "trigger_hyperspace has invalid target2 '%s'\n", self->target2); return; } VectorCopy( ent->s.origin, newOrg ); //finally, add the offset into the new origin AngleVectors( ent->s.angles, fwd, right, up ); VectorMA( newOrg, fDiff, fwd, newOrg ); VectorMA( newOrg, rDiff, right, newOrg ); VectorMA( newOrg, uDiff, up, newOrg ); //trap->Print("hyperspace from %s to %s\n", vtos(other->client->ps.origin), vtos(newOrg) ); //now put them in the offset position, facing the angles that position wants them to be facing TeleportPlayer( other, newOrg, ent->s.angles ); if ( other->m_pVehicle && other->m_pVehicle->m_pPilot ) {//teleport the pilot, too TeleportPlayer( (gentity_t*)other->m_pVehicle->m_pPilot, newOrg, ent->s.angles ); //FIXME: and the passengers? } //make them face the new angle //other->client->ps.hyperSpaceIndex = ent->s.number; VectorCopy( ent->s.angles, other->client->ps.hyperSpaceAngles ); //sound G_Sound( other, CHAN_LOCAL, G_SoundIndex( "sound/vehicles/common/hyperend.wav" ) ); } } return; } else { ent = G_Find (NULL, FOFS(targetname), self->target); if (!ent || !ent->inuse) { //this is bad trap->Error(ERR_DROP, "trigger_hyperspace has invalid target '%s'\n", self->target); return; } if (!other->client->ps.m_iVehicleNum || other->m_pVehicle->m_iRemovedSurfaces) { //if a vehicle touches a boundary without a pilot in it or with parts missing, just blow the thing up G_Damage(other, other, other, NULL, other->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE); return; } //other->client->ps.hyperSpaceIndex = ent->s.number; VectorCopy( ent->s.angles, other->client->ps.hyperSpaceAngles ); other->client->ps.hyperSpaceTime = level.time; } }
//----------------------------------------------------------------------------- // Purpose: Catches the monster-specific messages that occur when tagged // animation frames are played. // Input : *pEvent - //----------------------------------------------------------------------------- void CNPC_Headcrab::HandleAnimEvent( animevent_t *pEvent ) { switch ( pEvent->event ) { case HC_AE_JUMPATTACK: { RemoveFlag( FL_ONGROUND ); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetAbsOrigin() + Vector( 0 , 0 , 1 )); Vector vecJumpDir; CBaseEntity *pEnemy = GetEnemy(); if ( pEnemy ) { Vector vecEnemyEyePos = pEnemy->EyePosition(); float gravity = sv_gravity.GetFloat(); if ( gravity <= 1 ) { gravity = 1; } // // How fast does the headcrab need to travel to reach my enemy's eyes given gravity? // float height = ( vecEnemyEyePos.z - GetAbsOrigin().z ); if ( height < 16 ) { height = 16; } else if ( height > 120 ) { height = 120; } float speed = sqrt( 2 * gravity * height ); float time = speed / gravity; // // Scale the sideways velocity to get there at the right time // vecJumpDir = vecEnemyEyePos - GetAbsOrigin(); vecJumpDir = vecJumpDir / time; // // Speed to offset gravity at the desired height. // vecJumpDir.z = speed; // // Don't jump too far/fast. // float distance = vecJumpDir.Length(); if ( distance > 650 ) { vecJumpDir = vecJumpDir * ( 650.0 / distance ); } } else { // // Jump hop, don't care where. // Vector forward, up; AngleVectors( GetAbsAngles(), &forward, NULL, &up ); vecJumpDir = Vector( forward.x, forward.y, up.z ) * 350; } int iSound = random->RandomInt( 0 , 1 ); if ( iSound != 0 ) { AttackSound(); } SetAbsVelocity( vecJumpDir ); m_flNextAttack = gpGlobals->curtime + 2; break; } default: { CAI_BaseNPC::HandleAnimEvent( pEvent ); break; } } }
void Touch_Multi( gentity_t *self, gentity_t *other, trace_t *trace ) { if( !other->client ) { return; } if ( self->flags & FL_INACTIVE ) {//set by target_deactivate return; } #ifdef _PHASE1 if (self->spawnflags & 32 && jkg_arearestrictions.integer) { return; // eezstreet: Pande's orders } #endif if( self->alliedTeam ) { if ( other->client->sess.sessionTeam != self->alliedTeam ) { return; } } // moved to just above multi_trigger because up here it just checks if the trigger is not being touched // we want it to check any conditions set on the trigger, if one of those isn't met, the trigger is considered to be "cleared" // if ( self->e_ThinkFunc == thinkF_trigger_cleared_fire ) // {//We're waiting to fire our target2 first // self->nextthink = level.time + self->speed; // return; // } if ( self->spawnflags & 1 ) { if ( other->s.eType == ET_NPC ) { return; } } else { if ( self->spawnflags & 16 ) {//NPCONLY if ( other->NPC == NULL ) { return; } } if ( self->NPC_targetname && self->NPC_targetname[0] ) { if ( other->script_targetname && other->script_targetname[0] ) { if ( Q_stricmp( self->NPC_targetname, other->script_targetname ) != 0 ) {//not the right guy to fire me off return; } } else { return; } } } if ( self->spawnflags & 2 ) {//FACING vec3_t forward; AngleVectors( other->client->ps.viewangles, forward, NULL, NULL ); if ( DotProduct( self->movedir, forward ) < 0.5 ) {//Not Within 45 degrees return; } } if ( self->spawnflags & 4 ) {//USE_BUTTON if( !( other->client->pers.cmd.buttons & BUTTON_USE ) ) {//not pressing use button return; } if ((other->client->ps.weaponTime > 0 && other->client->ps.torsoAnim != BOTH_BUTTON_HOLD && other->client->ps.torsoAnim != BOTH_CONSOLE1) || other->health < 1 || (other->client->ps.pm_flags & PMF_FOLLOW) || other->client->sess.sessionTeam == TEAM_SPECTATOR || other->client->ps.forceHandExtend != HANDEXTEND_NONE) { //player has to be free of other things to use. return; } if (self->genericValue7) { //we have to be holding the use key in this trigger for x milliseconds before firing if (!G_PointInBounds( other->client->ps.origin, self->r.absmin, self->r.absmax )) { return; } else if (other->client->isHacking != self->s.number && other->s.number < MAX_CLIENTS ) { //start the hack other->client->isHacking = self->s.number; VectorCopy(other->client->ps.viewangles, other->client->hackingAngles); other->client->ps.hackingTime = level.time + self->genericValue7; other->client->ps.hackingBaseTime = self->genericValue7; if (other->client->ps.hackingBaseTime > 60000) { //don't allow a bit overflow other->client->ps.hackingTime = level.time + 60000; other->client->ps.hackingBaseTime = 60000; } return; } else if (other->client->ps.hackingTime < level.time) { //finished with the hack, reset the hacking values and let it fall through other->client->isHacking = 0; //can't hack a client other->client->ps.hackingTime = 0; } else { //hack in progress // UQ1: Added this code from below... It would never have gotten there before... if (other->client->ps.torsoAnim != BOTH_BUTTON_HOLD && other->client->ps.torsoAnim != BOTH_CONSOLE1) { G_SetAnim( other, NULL, SETANIM_TORSO, BOTH_BUTTON_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); } else { other->client->ps.torsoTimer = 500; } other->client->ps.weaponTime = other->client->ps.torsoTimer; // UQ1: End added... return; } } } if ( self->spawnflags & 8 ) {//FIRE_BUTTON if( !( other->client->pers.cmd.buttons & BUTTON_ATTACK ) ) {//not pressing fire button or altfire button return; } } if ( self->radius ) { vec3_t eyeSpot; //Only works if your head is in it, but we allow leaning out //NOTE: We don't use CalcEntitySpot SPOT_HEAD because we don't want this //to be reliant on the physical model the player uses. VectorCopy(other->client->ps.origin, eyeSpot); eyeSpot[2] += other->client->ps.viewheight; if ( G_PointInBounds( eyeSpot, self->r.absmin, self->r.absmax ) ) { if( !( other->client->pers.cmd.buttons & BUTTON_ATTACK ) ) {//not attacking, so hiding bonus /* //FIXME: should really have sound events clear the hiddenDist other->client->hiddenDist = self->radius; //NOTE: movedir HAS to be normalized! if ( VectorLength( self->movedir ) ) {//They can only be hidden from enemies looking in this direction VectorCopy( self->movedir, other->client->hiddenDir ); } else { VectorClear( other->client->hiddenDir ); } */ //Not using this, at least not yet. } } } if ( self->spawnflags & 4 ) {//USE_BUTTON if (other->client->ps.torsoAnim != BOTH_BUTTON_HOLD && other->client->ps.torsoAnim != BOTH_CONSOLE1) { G_SetAnim( other, NULL, SETANIM_TORSO, BOTH_BUTTON_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); } else { other->client->ps.torsoTimer = 500; } other->client->ps.weaponTime = other->client->ps.torsoTimer; } if ( self->think == trigger_cleared_fire ) {//We're waiting to fire our target2 first self->nextthink = level.time + self->speed; return; } multi_trigger( self, other ); }
void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope ) { vec3_t slope; vec3_t nvf, ovf, ovr, startspot, endspot, new_angles = { 0, 0, 0 }; float pitch, mod, dot; float oldmins2; //if we don't have a slope, get one if( !pass_slope || VectorCompare( vec3_origin, pass_slope ) ) { trace_t trace; VectorCopy( forwhom->r.currentOrigin, startspot ); startspot[2] += forwhom->r.mins[2] + 4; VectorCopy( startspot, endspot ); endspot[2] -= 300; trap_Trace( &trace, forwhom->r.currentOrigin, vec3_origin, vec3_origin, endspot, forwhom->s.number, MASK_SOLID ); // if(trace_fraction>0.05&&forwhom.movetype==MOVETYPE_STEP) // forwhom.flags(-)FL_ONGROUND; if ( trace.fraction >= 1.0 ) return; if( !( &trace.plane ) ) return; if ( VectorCompare( vec3_origin, trace.plane.normal ) ) return; VectorCopy( trace.plane.normal, slope ); } else { VectorCopy( pass_slope, slope ); } AngleVectors( forwhom->r.currentAngles, ovf, ovr, NULL ); vectoangles( slope, new_angles ); pitch = new_angles[PITCH] + 90; new_angles[ROLL] = new_angles[PITCH] = 0; AngleVectors( new_angles, nvf, NULL, NULL ); mod = DotProduct( nvf, ovr ); if ( mod<0 ) mod = -1; else mod = 1; dot = DotProduct( nvf, ovf ); if ( forwhom->client ) { forwhom->client->ps.viewangles[PITCH] = dot * pitch; forwhom->client->ps.viewangles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod); oldmins2 = forwhom->r.mins[2]; forwhom->r.mins[2] = -24 + 12 * fabs(forwhom->client->ps.viewangles[PITCH])/180.0f; //FIXME: if it gets bigger, move up if ( oldmins2 > forwhom->r.mins[2] ) {//our mins is now lower, need to move up //FIXME: trace? forwhom->client->ps.origin[2] += (oldmins2 - forwhom->r.mins[2]); forwhom->r.currentOrigin[2] = forwhom->client->ps.origin[2]; trap_LinkEntity( forwhom ); } } else { forwhom->r.currentAngles[PITCH] = dot * pitch; forwhom->r.currentAngles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod); } }
void Fog (edict_t *ent) //vec3_t viewpoint) { edict_t *triggerfog; edict_t *player = ent; //&g_edicts[1]; vec3_t viewpoint; if (!gl_driver || !vid_ref) return; if (deathmatch->value || coop->value) return; if (!player->client || player->is_bot) return; VectorCopy(player->s.origin, viewpoint); viewpoint[2] += ent->viewheight; //Knightmare- also ref_kmgl.dll if(stricmp(vid_ref->string,"gl") && stricmp(vid_ref->string,"kmgl")) { last_software_frame = level.framenum; level.active_fog = 0; return; } InTriggerFog = false; if(level.trigger_fogs) { int i; int trigger; trigger=0; for(i=1; i<level.fogs; i++) { if(!gfogs[i].Trigger) continue; if(!gfogs[i].ent->inuse) continue; if(!(gfogs[i].ent->spawnflags & FOG_ON)) continue; if(viewpoint[0] < gfogs[i].ent->absmin[0]) continue; if(viewpoint[0] > gfogs[i].ent->absmax[0]) continue; if(viewpoint[1] < gfogs[i].ent->absmin[1]) continue; if(viewpoint[1] > gfogs[i].ent->absmax[1]) continue; if(viewpoint[2] < gfogs[i].ent->absmin[2]) continue; if(viewpoint[2] > gfogs[i].ent->absmax[2]) continue; trigger = i; break; } if(trigger) { InTriggerFog = true; triggerfog = gfogs[trigger].ent; if(level.last_active_fog != trigger+1) { if(triggerfog->delay) init_trigger_fog_delay(triggerfog); else memcpy(&level.fog,&gfogs[trigger],sizeof(fog_t)); level.active_fog = trigger+1; } else if(triggerfog->delay) memcpy(&level.fog,&trig_fade_fog,sizeof(fog_t)); } else { InTriggerFog = false; level.active_fog = level.active_target_fog; // if we are just coming out of a trigger_fog, force // level.fog to last active target_fog values if(level.active_fog && level.last_active_fog && gfogs[level.last_active_fog-1].Trigger) { edict_t *ent = gfogs[level.active_fog-1].ent; if(ent && (ent->think == fog_fade)) ent->think(ent); else memcpy(&level.fog,&gfogs[level.active_fog-1],sizeof(fog_t)); } } } if (!level.active_fog) { if (level.last_active_fog) Fog_Off(); level.last_active_fog = 0; return; } pfog = &level.fog; if((pfog->Density1 != pfog->Density2) && (game.maxclients == 1) && (pfog->Model)) { float density; float dp; vec3_t vp; AngleVectors(player->client->ps.viewangles,vp,0,0); dp = DotProduct(pfog->Dir,vp) + 1.0; density = ((pfog->Density1*dp) + (pfog->Density2*(2.0-dp)))/2.; if(pfog->Density != density) { pfog->Density = density; } } GLFog(); level.last_active_fog = level.active_fog; }
edict_t *LookingAt(edict_t *ent, int filter, vec3_t endpos, float *range) { edict_t *who; edict_t *trigger[MAX_EDICTS]; edict_t *ignore; trace_t tr; vec_t r; vec3_t end, forward, start; vec3_t dir, entp, mins, maxs; int i, num; if(!ent->client) { if(endpos) VectorClear(endpos); if(range) *range = 0; return NULL; } VectorClear(end); if (ent->client->chasetoggle) { AngleVectors(ent->client->v_angle, forward, NULL, NULL); VectorCopy(ent->client->chasecam->s.origin,start); ignore = ent->client->chasecam; } else if(ent->client->spycam) { AngleVectors(ent->client->ps.viewangles, forward, NULL, NULL); VectorCopy(ent->s.origin,start); ignore = ent->client->spycam; } else { AngleVectors(ent->client->v_angle, forward, NULL, NULL); VectorCopy(ent->s.origin, start); start[2] += ent->viewheight; ignore = ent; } VectorMA(start, 8192, forward, end); /* First check for looking directly at a pickup item */ VectorSet(mins,-4096,-4096,-4096); VectorSet(maxs, 4096, 4096, 4096); num = gi.BoxEdicts (mins, maxs, trigger, MAX_EDICTS, AREA_TRIGGERS); for (i=0 ; i<num ; i++) { who = trigger[i]; if (!who->inuse) continue; if (!who->item) continue; if (!visible(ent,who)) continue; if (!infront(ent,who)) continue; VectorSubtract(who->s.origin,start,dir); r = VectorLength(dir); VectorMA(start, r, forward, entp); if(entp[0] < who->s.origin[0] - 17) continue; if(entp[1] < who->s.origin[1] - 17) continue; if(entp[2] < who->s.origin[2] - 17) continue; if(entp[0] > who->s.origin[0] + 17) continue; if(entp[1] > who->s.origin[1] + 17) continue; if(entp[2] > who->s.origin[2] + 17) continue; if(endpos) VectorCopy(who->s.origin,endpos); if (range) *range = r; return who; } tr = gi.trace (start, NULL, NULL, end, ignore, MASK_SHOT); if (tr.fraction == 1.0) { // too far away gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); return NULL; } if(!tr.ent) { // no hit gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); return NULL; } if(!tr.ent->classname) { // should never happen gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); return NULL; } if((strstr(tr.ent->classname,"func_") != NULL) && (filter & LOOKAT_NOBRUSHMODELS)) { // don't hit on brush models gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); return NULL; } if((Q_stricmp(tr.ent->classname,"worldspawn") == 0) && (filter & LOOKAT_NOWORLD)) { // world brush gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); return NULL; } if(endpos) { endpos[0] = tr.endpos[0]; endpos[1] = tr.endpos[1]; endpos[2] = tr.endpos[2]; } if(range) { VectorSubtract(tr.endpos,start,start); *range = VectorLength(start); } return tr.ent; }
void SP_target_fog (edict_t *self) { fog_t *fog; if ( !allow_fog->value ) { G_FreeEdict(self); return; } if (deathmatch->value || coop->value) { G_FreeEdict(self); return; } self->class_id = ENTITY_TARGET_FOG; if(!level.fogs) level.fogs = 1; // 1st fog reserved for console commands if(level.fogs >= MAX_FOGS) { gi.dprintf("Maximum number of fogs exceeded!\n"); G_FreeEdict(self); return; } if( self->delay < 0.) self->delay = 0.; self->fog_index = level.fogs+1; fog = &gfogs[level.fogs]; fog->Trigger = false; fog->Model = self->fog_model; if(fog->Model < 0 || fog->Model > 2) fog->Model = 0; fog->GL_Model = GLModels[fog->Model]; VectorCopy(self->fog_color,fog->Color); if(self->spawnflags & FOG_TURNOFF) { fog->Near = 4999; fog->Far = 5000; fog->Density = 0; fog->Density1 = 0; fog->Density2 = 0; } else { fog->Near = self->fog_near; fog->Far = self->fog_far; fog->Density = self->fog_density; fog->Density1 = self->fog_density; if(self->density == 0.) self->density = self->fog_density; else if(self->density < 0.) self->density = 0.; fog->Density2= self->density; } AngleVectors(self->s.angles,fog->Dir,0,0); fog->ent = self; level.fogs++; self->use = target_fog_use; gi.linkentity(self); if(self->spawnflags & FOG_ON) { self->spawnflags &= ~FOG_ON; target_fog_use(self,NULL,NULL); } }
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles, qboolean spit ) { gentity_t *tent; // use temp events at source and destination to prevent the effect // from getting dropped by a second player event /*freeze if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { freeze*/ if ( (g_gametype.integer == GT_FREEZE && !is_spectator( player->client )) || (g_gametype.integer != GT_FREEZE && player->client->sess.sessionTeam != TEAM_SPECTATOR) ) { //freeze tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = player->s.clientNum; tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN ); tent->s.clientNum = player->s.clientNum; } // unlink to make sure it can't possibly interfere with G_KillBox //player->relink = 0; trap_UnlinkEntity (player); VectorCopy ( origin, player->client->ps.origin ); player->client->ps.origin[2] += 1; // spit the player out if (spit == qtrue) { AngleVectors( angles, player->client->ps.velocity, NULL, NULL ); VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity ); player->client->ps.pm_time = 160; // hold time player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; } // toggle the teleport bit so the client knows to not lerp player->client->ps.eFlags ^= EF_TELEPORT_BIT; //unlagged - backward reconciliation #3 // we don't want players being backward-reconciled back through teleporters G_ResetHistory( player ); //unlagged - backward reconciliation #3 // set angles if (player->client->pers.fixedTeleporterAngles == qfalse) SetClientViewAngle( player, angles ); // kill anything at the destination /*freeze if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { freeze*/ if ( (g_gametype.integer == GT_FREEZE && !is_spectator( player->client )) || (g_gametype.integer != GT_FREEZE && player->client->sess.sessionTeam != TEAM_SPECTATOR) ) { //freeze G_KillBox (player); } // save results of pmove BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue ); // use the precise origin for linking VectorCopy( player->client->ps.origin, player->r.currentOrigin ); /*freeze if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { freeze*/ if ( (g_gametype.integer == GT_FREEZE && !is_spectator( player->client )) || (g_gametype.integer != GT_FREEZE && player->client->sess.sessionTeam != TEAM_SPECTATOR) ) { //freeze trap_LinkEntity (player); } }
//--------------------------------------------------------- void WP_FireBryarPistol( gentity_t *ent, qboolean alt_fire ) //--------------------------------------------------------- { vec3_t start; int damage = !alt_fire ? weaponData[WP_BRYAR_PISTOL].damage : weaponData[WP_BRYAR_PISTOL].altDamage; int velocity = !alt_fire ? weaponData[WP_BRYAR_PISTOL].velocity : weaponData[WP_BRYAR_PISTOL].altVelocity; if (ent->s.number != 0 && ent->client->NPC_class != CLASS_BOBAFETT && ent->client->NPC_class != CLASS_MANDA) { damage *= weaponData[WP_BRYAR_PISTOL].npcDmgMult; } VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall if ( !(ent->client->ps.forcePowersActive&(1<<FP_SEE)) || ent->client->ps.forcePowerLevel[FP_SEE] < FORCE_LEVEL_2 ) {//force sight 2+ gives perfect aim //FIXME: maybe force sight level 3 autoaims some? if ( ent->NPC && ent->NPC->currentAim < 5 ) { vec3_t angs; vectoangles( forwardVec, angs ); if ( ent->client->NPC_class == CLASS_IMPWORKER ) {//*sigh*, hack to make impworkers less accurate without affecteing imperial officer accuracy angs[PITCH] += ( Q_flrand(-1.0f, 1.0f) * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angs[YAW] += ( Q_flrand(-1.0f, 1.0f) * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f } else { angs[PITCH] += ( Q_flrand(-1.0f, 1.0f) * ((5-ent->NPC->currentAim)*0.25f) ); angs[YAW] += ( Q_flrand(-1.0f, 1.0f) * ((5-ent->NPC->currentAim)*0.25f) ); } AngleVectors( angs, forwardVec, NULL, NULL ); } } WP_MissileTargetHint(ent, start, forwardVec); gentity_t *missile = CreateMissile( start, forwardVec, velocity, 10000, ent, alt_fire ); missile->classname = "bryar_proj"; if ( ent->s.weapon == WP_BLASTER_PISTOL || ent->s.weapon == WP_JAWA ) {//*SIGH*... I hate our weapon system... missile->s.weapon = ent->s.weapon; } else { missile->s.weapon = WP_BRYAR_PISTOL; } if ( alt_fire ) { int count = ( level.time - ent->client->ps.weaponChargeTime ) / BRYAR_CHARGE_UNIT; if ( count < 1 ) { count = 1; } else if ( count > 5 ) { count = 5; } damage *= count; missile->count = count; // this will get used in the projectile rendering code to make a beefier effect } // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // missile->flags |= FL_OVERCHARGED; // damage *= 2; // } missile->damage = damage; missile->dflags = DAMAGE_DEATH_KNOCKBACK; if ( alt_fire ) { missile->methodOfDeath = MOD_BRYAR_ALT; } else { missile->methodOfDeath = MOD_BRYAR; } missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; // we don't want it to bounce forever missile->bounceCount = 8; if ( ent->weaponModel[1] > 0 ) {//dual pistols, toggle the muzzle point back and forth between the two pistols each time he fires ent->count = (ent->count)?0:1; } }