static void PodiumPlacementThink(gentity_t * podium) { vec3_t vec; vec3_t origin; vec3_t f, r, u; podium->nextthink = level.time + 100; AngleVectors(level.intermission_angle, vec, NULL, NULL); VectorMA(level.intermission_origin, trap_Cvar_VariableIntegerValue("g_podiumDist"), vec, origin); origin[2] -= trap_Cvar_VariableIntegerValue("g_podiumDrop"); G_SetOrigin(podium, origin); if(podium1) { VectorSubtract(level.intermission_origin, podium->r.currentOrigin, vec); VectorToAngles(vec, podium1->s.apos.trBase); podium1->s.apos.trBase[PITCH] = 0; podium1->s.apos.trBase[ROLL] = 0; AngleVectors(podium1->s.apos.trBase, f, r, u); VectorMA(podium->r.currentOrigin, offsetFirst[0], f, vec); VectorMA(vec, offsetFirst[1], r, vec); VectorMA(vec, offsetFirst[2], u, vec); G_SetOrigin(podium1, vec); } if(podium2) { VectorSubtract(level.intermission_origin, podium->r.currentOrigin, vec); VectorToAngles(vec, podium2->s.apos.trBase); podium2->s.apos.trBase[PITCH] = 0; podium2->s.apos.trBase[ROLL] = 0; AngleVectors(podium2->s.apos.trBase, f, r, u); VectorMA(podium->r.currentOrigin, offsetSecond[0], f, vec); VectorMA(vec, offsetSecond[1], r, vec); VectorMA(vec, offsetSecond[2], u, vec); G_SetOrigin(podium2, vec); } if(podium3) { VectorSubtract(level.intermission_origin, podium->r.currentOrigin, vec); VectorToAngles(vec, podium3->s.apos.trBase); podium3->s.apos.trBase[PITCH] = 0; podium3->s.apos.trBase[ROLL] = 0; AngleVectors(podium3->s.apos.trBase, f, r, u); VectorMA(podium->r.currentOrigin, offsetThird[0], f, vec); VectorMA(vec, offsetThird[1], r, vec); VectorMA(vec, offsetThird[2], u, vec); G_SetOrigin(podium3, vec); } }
int CGameTarget::GTH_SetAngleToTarget( Fx_CHARACTER_t* pThisChar ) { Fx_CHARACTER_t* character; int i; vec3_t dir, angles; if( pThisChar->targetType < 0 || pThisChar->targetIdx < 0 ) return( 0 ); character = &g_charManager->m_Characters[0]; for( i = 0; i < g_charManager->m_iNumCharacters; i ++, character ++ ) { if( character->entityType == pThisChar->targetType && \ character->idxOnServer == pThisChar->targetIdx ) break; } if( i == g_charManager->m_iNumCharacters ) { return( 0 ); } VectorSubtract( dir, character->position, pThisChar->position ); dir[2] = 0.0f; VectorNormalize( dir ); VectorToAngles( dir , angles ); pThisChar->angles[ YAW ] = angles[ YAW ]; return( 1 ); }
/* ======================================================================================================================================= CG_ReflectVelocity ======================================================================================================================================= */ void CG_ReflectVelocity(localEntity_t *le, trace_t *trace) { vec3_t velocity; float dot; int hitTime; if (!trace->allsolid) { // reflect the velocity on the trace plane hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction; BG_EvaluateTrajectoryDelta(&le->pos, hitTime, velocity); dot = DotProduct(velocity, trace->plane.normal); VectorMA(velocity, -2 * dot, trace->plane.normal, le->pos.trDelta); VectorScale(le->pos.trDelta, le->bounceFactor, le->pos.trDelta); } VectorCopy(trace->endpos, le->pos.trBase); le->pos.trTime = cg.time; // check for stop, making sure that even on low FPS systems it doesn't bobble if (trace->allsolid || (trace->plane.normal[2] > 0 && (le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2]))) { le->pos.trType = TR_STATIONARY; VectorCopy(trace->endpos, le->refEntity.origin); VectorToAngles(le->refEntity.axis[0], le->angles.trBase); le->groundEntityNum = trace->entityNum; } else { } }
int GTH_IsValidTargetAngleForKeyMode( Fx_CHARACTER_t* pThisChar ) { Fx_CHARACTER_t* character; int i; vec3_t dir, angles; if( pThisChar->targetType < 0 || pThisChar->targetIdx < 0 ) return( 0 ); character = &g_charManager->m_Characters[0]; for( i = 0; i < g_charManager->m_iNumCharacters; i ++, character ++ ) { if( character->entityType == pThisChar->targetType && \ character->idxOnServer == pThisChar->targetIdx ) break; } if( i == g_charManager->m_iNumCharacters ) { return( 0 ); } VectorSubtract( dir, character->position, pThisChar->position ); dir[2] = 0.0f; VectorNormalize( dir ); VectorToAngles( dir , angles ); if( abs( pThisChar->angles[YAW] - angles[ YAW ] ) < 90.0f ) return( 1 ); else return( 0 ); }
/* ================ G_InvulnerabilityEffect ================ */ int G_InvulnerabilityEffect(gentity_t * targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir) { gentity_t *impact; vec3_t intersections[2], vec; int n; if(!targ->client) { return qfalse; } VectorCopy(dir, vec); VectorInverse(vec); // sphere model radius = 42 units n = RaySphereIntersections(targ->client->ps.origin, 42, point, vec, intersections); if(n > 0) { impact = G_TempEntity(targ->client->ps.origin, EV_INVUL_IMPACT); VectorSubtract(intersections[0], targ->client->ps.origin, vec); VectorToAngles(vec, impact->s.angles); impact->s.angles[0] += 90; if(impact->s.angles[0] > 360) impact->s.angles[0] -= 360; if(impactpoint) { VectorCopy(intersections[0], impactpoint); } if(bouncedir) { VectorCopy(vec, bouncedir); VectorNormalize(bouncedir); } return qtrue; } else { return qfalse; } }
// Attack movement routine // // NOTE: Very simple for now, just a basic move about avoidance. // Change this routine for more advanced attack movement. void ACEMV_Attack(gentity_t * self) { float c; vec3_t target, forward, right, up; float distance; vec3_t oldAimVec; float aimTremble[2] = { 0.11f, 0.11f }; //float slowness = 0.35; //lower is slower // randomly choose a movement direction c = random(); //if(self->s.groundEntityNum != ENTITYNUM_NONE) { if(c < 0.2 && ACEMV_CanMove(self, MOVE_LEFT)) self->client->pers.cmd.rightmove -= 127; else if(c < 0.4 && ACEMV_CanMove(self, MOVE_RIGHT)) self->client->pers.cmd.rightmove += 127; if(c < 0.6 && ACEMV_CanMove(self, MOVE_FORWARD)) self->client->pers.cmd.forwardmove += 127; else if(c < 0.8 && ACEMV_CanMove(self, MOVE_FORWARD)) self->client->pers.cmd.forwardmove -= 127; if(c < 0.95) self->client->pers.cmd.upmove -= 90; else self->client->pers.cmd.upmove += 90; } // aim if(self->enemy->client) VectorCopy(self->enemy->client->ps.origin, target); else VectorCopy(self->enemy->s.origin, target); // modify attack angles based on accuracy (mess this up to make the bot's aim not so deadly) // save the current angles VectorCopy(self->bs.moveVector, oldAimVec); VectorNormalize(oldAimVec); VectorSubtract(target, self->client->ps.origin, forward); distance = VectorNormalize(forward); PerpendicularVector(up, forward); CrossProduct(up, forward, right); VectorMA(forward, crandom() * aimTremble[0], up, forward); VectorMA(forward, crandom() * aimTremble[1], right, forward); VectorNormalize(forward); //VectorLerp(oldAimVec, forward, slowness, forward); //VectorMA(oldAimVec, slowness, forward, forward); //VectorNormalize(forward); VectorScale(forward, distance, self->bs.moveVector); //ACEMV_ChangeBotAngle(self); VectorToAngles(self->bs.moveVector, self->bs.viewAngles); // don't attack too much if(random() < 0.8 && ACEMV_CheckShot(self, target)) { switch (self->client->pers.cmd.weapon) { case WP_FLAK_CANNON: case WP_ROCKET_LAUNCHER: self->client->pers.cmd.buttons = (random() < 0.5) ? BUTTON_ATTACK : BUTTON_ATTACK2; break; default: self->client->pers.cmd.buttons = BUTTON_ATTACK; break; } } // if(ace_debug.integer) // trap_SendServerCommand(-1, va("print \"%s: attacking %s\n\"", self->client->pers.netname, self->enemy->client->pers.netname)); }
// Make the change in angles a little more gradual, not so snappy // Subtle, but noticeable. // // Modified from the original id ChangeYaw code... void ACEMV_ChangeBotAngle(gentity_t * ent) { #if 1 vec3_t ideal_angles; float ideal_yaw; float ideal_pitch; float current_yaw; float current_pitch; float move; float speed; // Normalize the move angle first VectorNormalize(ent->bs.moveVector); current_yaw = AngleNormalize360(ent->bs.viewAngles[YAW]); current_pitch = AngleNormalize360(ent->bs.viewAngles[PITCH]); VectorToAngles(ent->bs.moveVector, ideal_angles); ideal_yaw = AngleNormalize360(ideal_angles[YAW]); ideal_pitch = AngleNormalize360(ideal_angles[PITCH]); // yaw if(current_yaw != ideal_yaw) { move = ideal_yaw - current_yaw; speed = ent->bs.turnSpeed; if(ideal_yaw > current_yaw) { if(move >= 180) move = move - 360; } else { if(move <= -180) move = move + 360; } if(move > 0) { if(move > speed) move = speed; } else { if(move < -speed) move = -speed; } ent->bs.viewAngles[YAW] = AngleNormalize360(current_yaw + move); } // pitch if(current_pitch != ideal_pitch) { move = ideal_pitch - current_pitch; speed = ent->bs.turnSpeed; if(ideal_pitch > current_pitch) { if(move >= 180) move = move - 360; } else { if(move <= -180) move = move + 360; } if(move > 0) { if(move > speed) move = speed; } else { if(move < -speed) move = -speed; } ent->bs.viewAngles[PITCH] = AngleNormalize360(current_pitch + move); } #else #endif }
/* ================ G_MissileImpact ================ */ void G_MissileImpact(gentity_t * ent, trace_t * trace) { gentity_t *other; qboolean hitClient = qfalse; #ifdef MISSIONPACK vec3_t forward, impactpoint, bouncedir; int eFlags; #endif other = &g_entities[trace->entityNum]; // check for bounce if(!other->takedamage && (ent->s.eFlags & (EF_BOUNCE | EF_BOUNCE_HALF))) { G_BounceMissile(ent, trace); G_AddEvent(ent, EV_GRENADE_BOUNCE, 0); return; } if(ent->s.weapon == WP_FLAK_CANNON && ent->s.eType == ET_PROJECTILE2) { G_ExplodeIntoNails(ent); return; } #ifdef MISSIONPACK if(other->takedamage) { if(ent->s.weapon != WP_PROX_LAUNCHER) { if(other->client && other->client->invulnerabilityTime > level.time) { // VectorCopy(ent->s.pos.trDelta, forward); VectorNormalize(forward); if(G_InvulnerabilityEffect(other, forward, ent->s.pos.trBase, impactpoint, bouncedir)) { VectorCopy(bouncedir, trace->plane.normal); eFlags = ent->s.eFlags & EF_BOUNCE_HALF; ent->s.eFlags &= ~EF_BOUNCE_HALF; G_BounceMissile(ent, trace); ent->s.eFlags |= eFlags; } ent->target_ent = other; return; } } } #endif // impact damage if(other->takedamage) { // FIXME: wrong damage direction? if(ent->damage) { vec3_t velocity; 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 } G_Damage(other, ent, &g_entities[ent->r.ownerNum], velocity, ent->s.origin, ent->damage, 0, ent->methodOfDeath); } } #ifdef MISSIONPACK if(ent->s.weapon == WP_PROX_LAUNCHER) { if(ent->s.pos.trType != TR_GRAVITY) { return; } // if it's a player, stick it on to them (flag them and remove this entity) if(other->s.eType == ET_PLAYER && other->health > 0) { ProximityMine_Player(ent, other); return; } SnapVectorTowards(trace->endpos, ent->s.pos.trBase); G_SetOrigin(ent, trace->endpos); ent->s.pos.trType = TR_STATIONARY; VectorClear(ent->s.pos.trDelta); G_AddEvent(ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags); ent->think = ProximityMine_Activate; ent->nextthink = level.time + 2000; VectorToAngles(trace->plane.normal, ent->s.angles); ent->s.angles[0] += 90; // link the prox mine to the other entity ent->enemy = other; ent->die = ProximityMine_Die; VectorCopy(trace->plane.normal, ent->movedir); VectorSet(ent->r.mins, -4, -4, -4); VectorSet(ent->r.maxs, 4, 4, 4); trap_LinkEntity(ent); return; } #endif if(!strcmp(ent->classname, "hook")) { gentity_t *nent; vec3_t v; nent = G_Spawn(); if(other->takedamage && other->client) { G_AddEvent(nent, EV_PROJECTILE_HIT, DirToByte(trace->plane.normal)); nent->s.otherEntityNum = other->s.number; ent->enemy = other; v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5; v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5; v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5; SnapVectorTowards(v, ent->s.pos.trBase); // save net bandwidth } else { VectorCopy(trace->endpos, v); G_AddEvent(nent, EV_PROJECTILE_MISS, DirToByte(trace->plane.normal)); ent->enemy = NULL; } SnapVectorTowards(v, ent->s.pos.trBase); // save net bandwidth nent->freeAfterEvent = qtrue; // change over to a normal entity right at the point of impact nent->s.eType = ET_GENERAL; ent->s.eType = ET_GRAPPLE; G_SetOrigin(ent, v); G_SetOrigin(nent, v); ent->think = Weapon_HookThink; ent->nextthink = level.time + FRAMETIME; ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL; VectorCopy(ent->r.currentOrigin, ent->parent->client->ps.grapplePoint); trap_LinkEntity(ent); trap_LinkEntity(nent); return; } // 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) { G_AddEvent(ent, EV_PROJECTILE_HIT, DirToByte(trace->plane.normal)); ent->s.otherEntityNum = other->s.number; } else if(trace->surfaceFlags & SURF_METALSTEPS) { G_AddEvent(ent, EV_PROJECTILE_MISS_METAL, DirToByte(trace->plane.normal)); } else { G_AddEvent(ent, EV_PROJECTILE_MISS, DirToByte(trace->plane.normal)); } 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); // 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->splashMethodOfDeath)) { if(!hitClient) { g_entities[ent->r.ownerNum].client->accuracy_hits++; } } } trap_LinkEntity(ent); }
static gentity_t *SpawnModelOnVictoryPad(gentity_t * pad, vec3_t offset, gentity_t * ent, int place) { gentity_t *body; vec3_t vec; vec3_t f, r, u; body = G_Spawn(); if(!body) { G_Printf(S_COLOR_RED "ERROR: out of gentities\n"); return NULL; } body->classname = ent->client->pers.netname; body->client = ent->client; body->s = ent->s; body->s.eType = ET_PLAYER; // could be ET_INVISIBLE body->s.eFlags = 0; // clear EF_TALK, etc body->s.powerups = 0; // clear powerups body->s.loopSound = 0; // clear lava burning body->s.number = body - g_entities; body->timestamp = level.time; body->physicsObject = qtrue; body->physicsBounce = 0; // don't bounce body->s.event = 0; body->s.pos.trType = TR_STATIONARY; body->s.groundEntityNum = ENTITYNUM_WORLD; body->s.legsAnim = LEGS_IDLE; body->s.torsoAnim = TORSO_STAND; /* if(body->s.weapon == WP_NONE) { body->s.weapon = WP_MACHINEGUN; } if(body->s.weapon == WP_GAUNTLET) { body->s.torsoAnim = TORSO_STAND2; } */ body->s.event = 0; body->r.svFlags = ent->r.svFlags; VectorCopy(ent->r.mins, body->r.mins); VectorCopy(ent->r.maxs, body->r.maxs); VectorCopy(ent->r.absmin, body->r.absmin); VectorCopy(ent->r.absmax, body->r.absmax); body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP; body->r.contents = CONTENTS_BODY; body->r.ownerNum = ent->r.ownerNum; body->takedamage = qfalse; VectorSubtract(level.intermission_origin, pad->r.currentOrigin, vec); VectorToAngles(vec, body->s.apos.trBase); body->s.apos.trBase[PITCH] = 0; body->s.apos.trBase[ROLL] = 0; AngleVectors(body->s.apos.trBase, f, r, u); VectorMA(pad->r.currentOrigin, offset[0], f, vec); VectorMA(vec, offset[1], r, vec); VectorMA(vec, offset[2], u, vec); G_SetOrigin(body, vec); trap_LinkEntity(body); body->count = place; return body; }