void multi_touch( ) { gedict_t *te; if ( !other->s.v.classname ) return; if ( strneq( other->s.v.classname, "player" ) ) return; if ( !Activated( self, other ) ) { if ( self->else_goal ) { te = Findgoal( self->else_goal ); if ( te ) AttemptToActivate( te, other, self ); } return; } if ( !VectorCompareF( self->s.v.movedir, 0, 0, 0 ) ) { trap_makevectors( other->s.v.angles ); if ( DotProduct( g_globalvars.v_forward, self->s.v.movedir ) < 0 ) return; // not facing the right way } self->s.v.enemy = EDICT_TO_PROG( other ); multi_trigger( ); }
/* ==================================== FireSentryBulletsMTFL2 ==================================== */ static void sgAimMTFL2( gedict_t*self, gedict_t* targ, vec3_t src, vec3_t dir ) { vec3_t dst; trap_makevectors( self->s.v.v_angle ); VectorAdd( self->s.v.origin, self->s.v.view_ofs, src ); VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, dst ); VectorSubtract( dst, src, dir ); }
static void BotDodgeMovement(gedict_t* self, vec3_t dir_move, float dodge_factor) { if (dodge_factor) { if (dodge_factor < 0) { ++dodge_factor; } else { --dodge_factor; } trap_makevectors(self->s.v.v_angle); VectorMA(dir_move, g_random() * self->fb.skill.dodge_amount * dodge_factor, g_globalvars.v_right, dir_move); } }
static void BotOnGroundMovement(gedict_t* self, vec3_t dir_move) { float dodge_factor = 0; if ((int)self->s.v.flags & FL_ONGROUND) { if (!(self->fb.path_state & NO_DODGE)) { // Dodge a rocket our enemy is firing at us if (self->fb.missile_dodge && g_globalvars.time - self->fb.missile_dodge->fb.missile_spawntime >= self->fb.skill.missile_dodge_time) { if (PROG_TO_EDICT(self->fb.missile_dodge->s.v.owner)->ct == ctPlayer) { vec3_t rel_pos; VectorSubtract(self->s.v.origin, self->fb.missile_dodge->s.v.origin, rel_pos); if (DotProduct(rel_pos, self->fb.missile_dodge->fb.missile_forward) > 0.7071067) { vec3_t temp; normalize(rel_pos, temp); dodge_factor = DotProduct(temp, self->fb.missile_dodge->fb.missile_right); } } else { self->fb.missile_dodge = NULL; } } // Not dodging a missile, dodge away from the player instead if (self->fb.look_object && self->fb.look_object->ct == ctPlayer) { if (!dodge_factor) { vec3_t rel_pos; VectorSubtract (self->s.v.origin, self->fb.look_object->s.v.origin, rel_pos); trap_makevectors(self->fb.look_object->s.v.v_angle); if (DotProduct(rel_pos, g_globalvars.v_forward) > 0) { vec3_t temp; normalize(rel_pos, temp); dodge_factor = DotProduct(temp, g_globalvars.v_right); } } } BotDodgeMovement(self, dir_move, dodge_factor); } } // If we're not in water, cannot have vertical direction (think of markers heading up stairs) if (self->s.v.waterlevel <= 1) { dir_move[2] = 0; } }
//////////////// // GlobalParams: // time // self /////////////// void SpectatorThink() { gedict_t *wizard = self->wizard; if ( self->last_goal != self->s.v.goalentity ) { SpecGoalChanged(); self->last_goal = self->s.v.goalentity; } if ( self->autotrack ) DoAutoTrack(); if ( self->s.v.impulse ) SpectatorImpulseCommand(); if ( self->sc_stats && self->sc_stats_time && self->sc_stats_time <= g_globalvars.time && match_in_progress != 1 ) Print_Scores (); if ( self->wp_stats && self->wp_stats_time && self->wp_stats_time <= g_globalvars.time && match_in_progress != 1 ) Print_Wp_Stats (); if ( wizard ) { // set model angles wizard->s.v.angles[0] = -self->s.v.v_angle[0] / 2; wizard->s.v.angles[1] = self->s.v.v_angle[1]; // wizard model blinking at spectator screen - so move model behind spec camera a bit trap_makevectors( self->s.v.v_angle ); VectorMA (self->s.v.origin, -32, g_globalvars.v_forward, wizard->s.v.origin); // model bobbing wizard->s.v.origin[2] += sin( g_globalvars.time * 2.5 ); setorigin( wizard, PASSVEC3( wizard->s.v.origin ) ); if ( GetSpecWizard () ) { gedict_t *goal = PROG_TO_EDICT( self->s.v.goalentity ); if ( goal && goal->ct == ctPlayer ) // tracking player, so turn model off wizard->s.v.model = ""; else // turn model on setmodel( wizard, "progs/wizard.mdl" ); } else { wizard->s.v.model = ""; // turn model off } } }
/* ============= infront returns 1 if the entity is in front (in sight) of self ============= */ float infront( gedict_t *targ ) { vec3_t vec; float dot; trap_makevectors( self->s.v.angles ); VectorSubtract(targ->s.v.origin, self->s.v.origin, vec); VectorNormalize( vec ); dot = DotProduct( vec, g_globalvars.v_forward ); if ( dot > 0.3 ) { return true; } return false; }
// Called from weapons.c void GrappleThrow() { if ( self->hook_out ) // only throw once return; g_globalvars.msg_entity = EDICT_TO_PROG( self ); WriteByte( MSG_ONE, SVC_SMALLKICK ); // chain out sound (loops) sound ( self, CHAN_WEAPON, "weapons/chain1.wav", 1, ATTN_NORM ); newmis = spawn(); g_globalvars.newmis = EDICT_TO_PROG( newmis ); newmis->s.v.movetype = MOVETYPE_FLYMISSILE; newmis->s.v.solid = SOLID_BBOX; newmis->s.v.owner = EDICT_TO_PROG( self ); self->hook = newmis; newmis->s.v.classname = "hook"; trap_makevectors ( self->s.v.v_angle ); // Weapon velocitys should not be based on server maxspeed imo // Removing purectf velocity changes ( 2.5 * self->maxspeed ) if ( self->ctf_flag & CTF_RUNE_HST ) VectorScale( g_globalvars.v_forward, 1000, newmis->s.v.velocity ); else VectorScale( g_globalvars.v_forward, 800, newmis->s.v.velocity ); SetVector( newmis->s.v.avelocity, 0, 0, -500 ); newmis->s.v.touch = (func_t) GrappleAnchor; newmis->s.v.think = (func_t) BuildChain; newmis->s.v.nextthink = g_globalvars.time + 0.1; if ( k_ctf_custom_models ) setmodel ( newmis, "progs/star.mdl" ); else setmodel ( newmis, "progs/v_spike.mdl" ); setorigin(newmis, self->s.v.origin[0] + g_globalvars.v_forward[0] * 16, self->s.v.origin[1] + g_globalvars.v_forward[1] * 16, self->s.v.origin[2] + g_globalvars.v_forward[2] * 16 + 16); setsize( newmis, 0, 0, 0, 0, 0, 0 ); self->hook_out = true; }
// // GrappleTrack - Constantly updates the hook's position relative to // what it's hooked to. Inflicts damage if attached to // a player that is not on the same team as the hook's // owner. // void GrappleTrack() { gedict_t *enemy = PROG_TO_EDICT(self->s.v.enemy); gedict_t *owner = PROG_TO_EDICT(self->s.v.owner); // Release dead targets if ( enemy->ct == ctPlayer && ISDEAD( enemy ) ) owner->on_hook = false; // drop the hook if owner is dead or has released the button if ( !owner->on_hook || owner->s.v.health <= 0 ) { GrappleReset( self ); return; } if ( enemy->ct == ctPlayer ) { if ( !CanDamage(enemy, owner) ) { GrappleReset( self ); return; } // move the hook along with the player. It's invisible, but // we need this to make the sound come from the right spot setorigin( self, PASSVEC3(enemy->s.v.origin) ); sound ( self, CHAN_WEAPON, "blob/land1.wav", 1, ATTN_NORM ); enemy->deathtype = dtHOOK; T_Damage ( enemy, self, owner, 1 ); trap_makevectors ( self->s.v.v_angle ); SpawnBlood( enemy->s.v.origin, 1 ); } // If the hook is not attached to the player, constantly copy // the target's velocity. Velocity copying DOES NOT work properly // for a hooked client. if ( enemy->ct != ctPlayer ) VectorCopy( enemy->s.v.velocity, self->s.v.velocity ); self->s.v.nextthink = g_globalvars.time + 0.1; }
void ai_charge_side() { vec3_t tmpv; float heading; // aim to the left of the enemy for a flyby VectorSubtract( PROG_TO_EDICT( self->s.v.enemy )->s.v.origin, self->s.v.origin, tmpv ); self->s.v.ideal_yaw = vectoyaw( tmpv ); changeyaw( self ); trap_makevectors( self->s.v.angles ); VectorMA( PROG_TO_EDICT( self->s.v.enemy )->s.v.origin, -30, g_globalvars.v_right, tmpv ); VectorSubtract( tmpv, self->s.v.origin, tmpv ); heading = vectoyaw( tmpv ); walkmove( self, heading, 20 ); }
void sgAimNew( gedict_t* self, gedict_t* targ, vec3_t src, vec3_t dst, vec3_t norm_dir) { vec3_t dir, tmp; trap_makevectors( self->s.v.v_angle ); VectorAdd( self->s.v.origin, self->s.v.view_ofs, src ); VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, dst ); VectorSubtract( dst, src, dir ); normalize(dir, norm_dir); //чтобы не попадать в подставку traceline( PASSVEC3( src ), PASSVEC3( dst ), 0, self ); if( (PROG_TO_EDICT(g_globalvars.trace_ent) == self->trigger_field) && vlen(dir) > 100 ) { VectorScale( norm_dir, 60, tmp); VectorAdd(src,tmp,src); } }
void FireSentryLighting( gedict_t * targ ) { vec3_t src; vec3_t dst; vec3_t dir, end, norm_dir; gedict_t*trace_ent; switch( tfset_sg_sfire ) { case SG_SFIRE_NEW: VectorCopy( self->s.v.angles, self->s.v.v_angle ); sgAimNew( self, targ, src, dst, norm_dir ); VectorCopy(dst,end); break; case SG_SFIRE_MTFL2: VectorCopy( self->s.v.angles, self->s.v.v_angle ); sgAimMTFL2( self, targ, src, dir ); VectorNormalize( dir ); VectorScale( dir, 2048, end ); VectorAdd( end, src, end ); break; case SG_SFIRE_MTFL1: VectorCopy( self->s.v.angles, self->s.v.v_angle ); case SG_SFIRE_281: trap_makevectors( self->s.v.v_angle ); VectorScale( g_globalvars.v_forward, 10, src ); VectorAdd( self->s.v.origin, src, src ); src[2] = self->s.v.absmin[2] + self->s.v.size[2] * 0.7; VectorSubtract( targ->s.v.origin, self->s.v.origin, dir ); VectorScale( dir, 2048, end ); VectorAdd( end, src, end ); break; default: return; } g_globalvars.trace_ent = 0; traceline( PASSVEC3( src ), PASSVEC3( end ), 0, self ); trap_WriteByte( MSG_MULTICAST, SVC_TEMPENTITY ); trap_WriteByte( MSG_MULTICAST, TE_LIGHTNING2 ); WriteEntity( MSG_MULTICAST, self ); trap_WriteCoord( MSG_MULTICAST, src[0] ); trap_WriteCoord( MSG_MULTICAST, src[1] ); trap_WriteCoord( MSG_MULTICAST, src[2] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[0] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[1] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[2] ); trap_multicast( PASSVEC3( src ), 1 ); if ( g_globalvars.trace_ent ) { trace_ent = PROG_TO_EDICT(g_globalvars.trace_ent); if ( streq( trace_ent->s.v.classname, "player" ) ) { switch((int)( g_random( ) * 30) ) { case 0: sound( trace_ent, 2, "player/pain1.wav" , 1, 1 ); break; case 1: sound( trace_ent, 2, "player/pain1.wav" , 1, 1 ); break; case 2: sound( trace_ent, 2, "player/pain2.wav" , 1, 1 ); break; case 3: sound( trace_ent, 2, "player/pain3.wav" , 1, 1 ); break; case 4: sound( trace_ent, 2, "player/pain4.wav" , 1, 1 ); break; case 5: sound( trace_ent, 2, "player/pain5.wav" , 1, 1 ); break; case 6: sound( trace_ent, 2, "player/pain6.wav" , 1, 1 ); break; default:break; } } } }
void DropFlag( gedict_t *flag, qbool tossed ) { gedict_t *p = PROG_TO_EDICT( flag->s.v.owner ); gedict_t *p1; p->ctf_flag -= ( p->ctf_flag & CTF_FLAG ); p->s.v.effects -= ( (int) p->s.v.effects & ( EF_FLAG1 | EF_FLAG2 )); p->s.v.items -= ( (int) p->s.v.items & (int) flag->s.v.items ); setorigin( flag, PASSVEC3(p->s.v.origin) ); flag->s.v.origin[2] -= 24; flag->cnt = FLAG_DROPPED; if ( tossed ) { trap_makevectors( p->s.v.v_angle ); if ( p->s.v.v_angle[0] ) { flag->s.v.velocity[0] = g_globalvars.v_forward[0] * 300 + g_globalvars.v_up[0] * 200; flag->s.v.velocity[1] = g_globalvars.v_forward[1] * 300 + g_globalvars.v_up[1] * 200; flag->s.v.velocity[2] = g_globalvars.v_forward[2] * 300 + g_globalvars.v_up[2] * 200; } else { aim( flag->s.v.velocity ); VectorScale( flag->s.v.velocity, 300, flag->s.v.velocity ); flag->s.v.velocity[2] = 200; } } else { SetVector( flag->s.v.velocity, 0, 0, 300 ); } flag->s.v.flags = FL_ITEM; flag->s.v.solid = SOLID_TRIGGER; flag->s.v.movetype = MOVETYPE_TOSS; setmodel( flag, flag->mdl ); setsize ( flag, -16, -16, 0, 16, 16, 74 ); flag->super_time = g_globalvars.time + FLAG_RETURN_TIME; if ( tossed ) { flag->s.v.nextthink = g_globalvars.time + 0.75; flag->s.v.think = (func_t) FlagResetOwner; } else { flag->s.v.owner = EDICT_TO_PROG( flag ); } G_bprint( 2, "%s", p->s.v.netname ); if ( streq(getteam(p), "red") ) G_bprint( 2, " %s the %s flag!\n", tossed ? redtext("tossed") : redtext("lost"), redtext("BLUE") ); else G_bprint( 2, " %s the %s flag!\n", tossed ? redtext("tossed") : redtext("lost"), redtext("RED") ); for ( p1 = world; (p1 = find_plr( p1 )); ) { if ( strneq(getteam(p), getteam(p1)) ) p1->carrier_hurt_time = -1; } refresh_plus_scores (); // update players status bar faster }
void BotSetCommand (gedict_t* self) { extern float last_frame_time; float msec_since_last = (last_frame_time - self->fb.last_cmd_sent) * 1000; int cmd_msec = (int)msec_since_last; int weapon_script_impulse = 0; int impulse = 0; qbool jumping; qbool firing; vec3_t direction; BotPerformRocketJump (self); if (cmd_msec) { self->fb.cmd_msec_lost += (msec_since_last - cmd_msec); if (self->fb.cmd_msec_lost >= 1) { self->fb.cmd_msec_lost -= 1; cmd_msec += 1; } } else if (self->fb.cmd_msec_last) { // Probably re-sending after blocked(), re-use old number cmd_msec = self->fb.cmd_msec_last; } else { cmd_msec = 12; } //G_sprint(self, PRINT_HIGH, "Movement length @ %f: %d\n", last_frame_time, cmd_msec); // dir_move_ is the direction we want to move in, but need to take inertia into effect // ... as rough guide (and save doubling physics calculations), scale command > VectorNormalize (self->fb.dir_move_); VectorScale (self->fb.dir_move_, sv_maxspeed, self->fb.last_cmd_direction); trap_makevectors (self->fb.desired_angle); // During intermission, always do nothing and leave humans to change level if (intermission_running) { self->fb.firing = self->fb.jumping = false; } else if (teamplay && deathmatch == 1 && !self->fb.firing) { // Weaponscripts if (self->s.v.weapon != IT_SHOTGUN && self->s.v.weapon != IT_AXE) { weapon_script_impulse = (self->s.v.ammo_shells ? 2 : 1); } } impulse = self->fb.botchose ? self->fb.next_impulse : self->fb.firing ? self->fb.desired_weapon_impulse : weapon_script_impulse; if (self->fb.firing && BotUsingCorrectWeapon (self)) { impulse = 0; // we already have the requested weapon } jumping = self->fb.jumping || self->fb.waterjumping; firing = self->fb.firing; self->fb.waterjumping = false; if (self->fb.dbg_countdown > 0) { jumping = firing = false; VectorClear (direction); --self->fb.dbg_countdown; } else { if (jumping && ((int)self->s.v.flags & FL_ONGROUND)) { BestJumpingDirection (self); } else { ApplyPhysics (self); } if (self->s.v.waterlevel <= 1) { vec3_t hor; VectorCopy (self->fb.dir_move_, hor); hor[2] = 0; VectorNormalize (hor); VectorScale (hor, 800, hor); direction[0] = DotProduct (g_globalvars.v_forward, hor); direction[1] = DotProduct (g_globalvars.v_right, hor); direction[2] = 0; } else { direction[0] = DotProduct (g_globalvars.v_forward, self->fb.dir_move_) * 800; direction[1] = DotProduct (g_globalvars.v_right, self->fb.dir_move_) * 800; direction[2] = DotProduct (g_globalvars.v_up, self->fb.dir_move_) * 800; } #ifdef DEBUG_MOVEMENT if (self->fb.debug_path) { G_bprint (PRINT_HIGH, " : final direction sent [%4.1f %4.1f %4.1f]\n", PASSVEC3 (self->fb.dir_move_)); } #endif } self->fb.desired_angle[2] = 0; if (ISDEAD (self)) { firing = false; jumping = BotRequestRespawn (self); VectorClear (direction); impulse = 0; } else if (self->fb.min_move_time > g_globalvars.time) { VectorClear (direction); } // Keep bots on spawns before match start if (match_in_progress != 2 && cvar(FB_CVAR_FREEZE_PREWAR)) { jumping = firing = false; VectorClear(direction); impulse = 0; } trap_SetBotCMD ( NUM_FOR_EDICT (self), cmd_msec, PASSVEC3(self->fb.desired_angle), PASSVEC3(direction), (firing ? 1 : 0) | (jumping ? 2 : 0), impulse ); self->fb.next_impulse = 0; self->fb.botchose = false; self->fb.last_cmd_sent = last_frame_time; self->fb.cmd_msec_last = cmd_msec; VectorClear (self->fb.obstruction_normal); if (self->s.v.button0 && !firing) { // Stopped firing, randomise next time self->fb.last_rndaim_time = 0; } self->fb.prev_look_object = self->fb.look_object; VectorCopy (self->s.v.velocity, self->fb.prev_velocity); }
float AverageTraceAngle (gedict_t* self, qbool debug, qbool report) { vec3_t back_left, projection, incr; int angles[] = { 45, 30, 15, 0, -15, -30, -45 }; int i; float best_angle = 0; float best_angle_frac = 0; float total_angle = 0; float avg_angle; float distance = 320; if (self->fb.path_state & JUMP_LEDGE) return 0; if (debug) { trap_makevectors (self->s.v.angles); } else { trap_makevectors (self->fb.dir_move_); } VectorMA (self->s.v.origin, -VEC_HULL_MIN[0], g_globalvars.v_forward, back_left); VectorMA (back_left, VEC_HULL_MIN[1], g_globalvars.v_right, back_left); VectorScale (g_globalvars.v_right, (VEC_HULL_MAX[0] - VEC_HULL_MIN[0]) / (sizeof(angles) / sizeof(angles[0]) - 1), incr); if (debug) { G_bprint (2, "Current origin: %d %d %d\n", PASSINTVEC3 (self->s.v.origin)); G_bprint (2, "Current angles: %d %d\n", PASSINTVEC3 (self->s.v.angles)); } for (i = 0; i < sizeof (angles) / sizeof (angles[0]); ++i) { int angle = angles[i]; RotatePointAroundVector (projection, g_globalvars.v_up, g_globalvars.v_forward, angle); VectorMA (back_left, distance, projection, projection); traceline (PASSVEC3 (back_left), PASSVEC3 (projection), false, self); if (g_globalvars.trace_fraction == 1) { total_angle += angle * 1.5; // bonus for success } else if (g_globalvars.trace_fraction > 0.4) { total_angle += angle * g_globalvars.trace_fraction; } if (debug) { G_bprint (2, "Angle: %d => [%d %d %d] [%d %d %d] = %f\n", angle, PASSINTVEC3 (back_left), PASSINTVEC3 (projection), g_globalvars.trace_fraction); } if (i == 0 || g_globalvars.trace_fraction > best_angle_frac) { best_angle = angle; best_angle_frac = g_globalvars.trace_fraction; } VectorAdd (back_left, incr, back_left); } avg_angle = total_angle / (sizeof (angles) / sizeof (angles[0])); if (debug) { G_bprint (2, "Best angle: %d\n", best_angle); G_bprint (2, "Total angle: %f\n", avg_angle); } return avg_angle; }
void teleport_touch( ) { gedict_t *t, *te; vec3_t org; if ( self->s.v.targetname ) { if ( self->s.v.nextthink < g_globalvars.time ) { return; // not fired yet } } if ( ( int ) ( self->s.v.spawnflags ) & PLAYER_ONLY ) { if ( strneq( other->s.v.classname, "player" ) ) return; } if ( !Activated( self, other ) ) { if ( self->else_goal ) { te = Findgoal( self->else_goal ); if ( te ) AttemptToActivate( te, other, self ); } return; } // only teleport living creatures if ( other->s.v.health <= 0 || other->s.v.solid != SOLID_SLIDEBOX ) return; // activator = other; SUB_UseTargets( ); //put a tfog where the player was spawn_tfog( other->s.v.origin ); t = trap_find( world, FOFS( s.v.targetname ), self->s.v.target ); if ( !t ) G_Error( "couldn't find target" ); // spawn a tfog flash in front of the destination trap_makevectors( t->mangle ); org[0] = t->s.v.origin[0] + 32 * g_globalvars.v_forward[0]; org[1] = t->s.v.origin[1] + 32 * g_globalvars.v_forward[1]; org[2] = t->s.v.origin[2] + 32 * g_globalvars.v_forward[2]; spawn_tfog( org ); spawn_tdeath( t->s.v.origin, other ); // move the player and lock him down for a little while if ( !other->s.v.health ) { VectorCopy( t->s.v.origin, other->s.v.origin ); other->s.v.velocity[0] = ( g_globalvars.v_forward[0] * other->s.v.velocity[0] ) + ( g_globalvars.v_forward[0] * other->s.v.velocity[1] ); other->s.v.velocity[1] = ( g_globalvars.v_forward[1] * other->s.v.velocity[0] ) + ( g_globalvars.v_forward[1] * other->s.v.velocity[1] ); other->s.v.velocity[2] = ( g_globalvars.v_forward[2] * other->s.v.velocity[0] ) + ( g_globalvars.v_forward[2] * other->s.v.velocity[1] ); //other->s.v.velocity = (v_forward * other->s.v.velocity[0]) + (v_forward * other->s.v.velocity[1]); return; } setorigin( other, PASSVEC3( t->s.v.origin ) ); VectorCopy( t->mangle, other->s.v.angles ); // other.angles = t.mangle; if ( streq( other->s.v.classname, "player" ) ) { if ( other->s.v.weapon == 1 && other->hook_out ) { sound( other, 1, "weapons/bounce2.wav", 1, 1 ); other->on_hook = 0; other->hook_out = 0; other->fire_held_down = 0; other->s.v.weaponframe = 0; other->attack_finished = g_globalvars.time + 0.75; } other->s.v.fixangle = 1; // turn this way immediately other->s.v.teleport_time = g_globalvars.time + 0.7; if ( ( int ) other->s.v.flags & FL_ONGROUND ) other->s.v.flags = other->s.v.flags - FL_ONGROUND; VectorScale( g_globalvars.v_forward, 300, other->s.v.velocity ); // other->s.v.velocity = v_forward * 300; } other->s.v.flags -= ( int ) other->s.v.flags & FL_ONGROUND; }