// // 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 T_Damage( gedict_t * targ, gedict_t * inflictor, gedict_t * attacker, float damage ) { vec3_t dir; gedict_t *oldself; float save; float take; int i, c1 = 8, c2 = 4, hdp; float dmg_dealt = 0, virtual_take = 0; float non_hdp_damage; // save damage before handicap apply for kickback calculation float native_damage = damage; // save damage before apply any modificator char *attackerteam, *targteam, *attackername, *victimname; qbool tp4teamdmg = false; //midair and instagib float playerheight = 0, midheight = 0; qbool midair = false, inwater = false, do_dmg = false, rl_dmg = false, stomp_dmg = false; // can't apply damage to dead if ( !targ->s.v.takedamage || ISDEAD( targ ) ) return; // can't damage other players in race if ( isRACE() && ( attacker != targ ) ) { if ( targ->ct == ctPlayer || attacker->ct == ctPlayer ) return; } // ignore almost all damage in CA while coutdown if ( isCA() && match_in_progress && ra_match_fight != 2 ) { if ( !( dtTELE1 == targ->deathtype // always do tele damage || dtTELE2 == targ->deathtype // always do tele damage || dtTELE3 == targ->deathtype // always do tele damage || dtSUICIDE == targ->deathtype // do suicide damage anyway ) ) return; } // used by buttons and triggers to set activator for target firing damage_attacker = attacker; damage_inflictor = inflictor; attackerteam = getteam( attacker ); targteam = getteam( targ ); if ( (int)cvar("k_midair") ) midair = true; // in bloodfest boss damage factor. if ( k_bloodfest && attacker->bloodfest_boss ) { damage *= 4; } // check for quad damage powerup on the attacker // midair quad makes rockets fast, but no change to damage if ( attacker->super_damage_finished > g_globalvars.time && strneq( inflictor->s.v.classname, "door" ) && dtSTOMP != targ->deathtype && !midair ) damage *= ( deathmatch == 4 ? 8 : 4 ); // in dmm4 quad is octa actually // ctf strength rune if ( attacker->ctf_flag & CTF_RUNE_STR ) damage *= 2; // ctf resistance rune if ( targ->ctf_flag & CTF_RUNE_RES ) { damage /= 2; ResistanceSound( targ ); } // did we hurt enemy flag carrier? if ( (targ->ctf_flag & CTF_FLAG) && (!streq(targteam, attackerteam)) ) { attacker->carrier_hurt_time = g_globalvars.time; } // in teamplay 4 we do no armor or health damage to teammates (unless telefrag), but do apply velocity changes if ( tp_num() == 4 && streq(targteam, attackerteam) && ( isCA() || targ != attacker ) && !TELEDEATH(targ) ) { tp4teamdmg = true; } if ( midair || cvar("k_instagib") ) { traceline( PASSVEC3(targ->s.v.origin), targ->s.v.origin[0], targ->s.v.origin[1], targ->s.v.origin[2] - 2048, true, targ ); playerheight = targ->s.v.absmin[2] - g_globalvars.trace_endpos[2] + ( cvar("k_instagib") ? 1 : 0 ); } // get some data before apply damage in mid air mode if ( midair ) { inwater = ( ((int)targ->s.v.flags & FL_INWATER) && targ->s.v.waterlevel > 1 ); if ( streq( inflictor->s.v.classname, "rocket" )) midheight = targ->s.v.origin[2] - inflictor->s.v.oldorigin[2]; rl_dmg = ( targ->ct == ctPlayer && dtRL == targ->deathtype ); stomp_dmg = ( targ->ct == ctPlayer && dtSTOMP == targ->deathtype ); if ( !rl_dmg ) { // damage types which ignore "lowheight" do_dmg = targ->ct != ctPlayer // always do damage to non player, secret doors etc... || dtWATER_DMG == targ->deathtype // always do water damage || dtLAVA_DMG == targ->deathtype // always do lava damage || dtSLIME_DMG == targ->deathtype // always do slime damage || dtSTOMP == targ->deathtype // always do stomp damage || dtTELE1 == targ->deathtype // always do tele damage || dtTELE2 == targ->deathtype // always do tele damage || dtTELE3 == targ->deathtype // always do tele damage || dtSUICIDE == targ->deathtype; // do suicide damage anyway } } non_hdp_damage = damage; // save damage before handicap apply for kickback calculation // #handicap# if ( attacker != targ ) // attack no self if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) // player vs player if ( ( hdp = GetHandicap(attacker) ) != 100 ) // skip checks if hdp == 100 if ( dtAXE == targ->deathtype || dtSG == targ->deathtype || dtSSG == targ->deathtype || dtNG == targ->deathtype || dtSNG == targ->deathtype || dtGL == targ->deathtype || dtRL == targ->deathtype || dtLG_BEAM == targ->deathtype || dtLG_DIS == targ->deathtype || dtLG_DIS_SELF == targ->deathtype // even that impossible ) { damage *= 0.01f * hdp; } // save damage based on the target's armor level save = newceil( targ->s.v.armortype * damage ); if ( tp4teamdmg ) save = 0; // we do not touch armor if ( save >= targ->s.v.armorvalue ) { save = targ->s.v.armorvalue; targ->s.v.armortype = 0; // lost all armor targ->s.v.items -= ( ( int ) targ->s.v.items & ( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 ) ); } dmg_dealt += save; if ( match_in_progress == 2 ) targ->s.v.armorvalue = targ->s.v.armorvalue - save; take = newceil( damage - save ); // mid air damage modificators if ( midair ) { int k_midair_minheight, midair_minheight; k_midair_minheight = (int)cvar("k_midair_minheight"); if ( k_midair_minheight == 1 ) midair_minheight = 128; else if ( k_midair_minheight == 2 ) midair_minheight = 256; else if ( k_midair_minheight == 3 ) midair_minheight = 512; else if ( k_midair_minheight == 4 ) midair_minheight = 1024; else midair_minheight = 64; if ( rl_dmg || stomp_dmg ) take = 9999; if ( playerheight < midair_minheight && rl_dmg ) take = 0; // no dmg done if target is not high enough if ( playerheight < 45 && !inwater && rl_dmg ) take = 0; // no rl dmg in such case if ( !rl_dmg && !do_dmg ) take = 0; // unknown damage for midair, so do not damage if ( rl_dmg && targ == attacker ) take = 0; // no self rl damage } // instagib damage modificators if ( cvar("k_instagib") ) { if ( inflictor->ct == ctPlayer ) take = 5000; if ( attacker == targ ) take = 0; } // helps kill player in prewar at "wrong" places if ( match_in_progress != 2 && native_damage > 450 ) take = 99999; // team play damage avoidance and godmode or invincibility check virtual_take = max(0, take); // virtual_take used for calculating dmg_dealt only in case of k_dmgfrags // ignore this checks for suicide damage if ( dtSUICIDE != targ->deathtype ) { if ( ( int ) targ->s.v.flags & FL_GODMODE ) { take = 0; // what if god was one of us } else if ( targ->invincible_finished >= g_globalvars.time ) { if ( targ->invincible_sound < g_globalvars.time ) { sound( targ, CHAN_AUTO, "items/protect3.wav", 1, ATTN_NORM ); targ->invincible_sound = g_globalvars.time + 2; } take = 0; } else if ( ( tp_num() == 1 || ( tp_num() == 3 && targ != attacker ) ) && !strnull( attackerteam ) && streq( targteam, attackerteam ) && attacker->ct == ctPlayer && strneq( inflictor->s.v.classname, "door" ) && !TELEDEATH( targ ) // do telefrag damage in tp ) { // teamplay == 1 don't damage self and mates (armor affected anyway) // teamplay == 3 don't damage mates, do damage to self (armor affected anyway) take = 0; } else if ( tp4teamdmg ) { take = 0; // we do not touch health } } take = max(0, take); // avoid negative take, if any if ( cvar("k_dmgfrags") ) { if ( TELEDEATH( targ ) ) { // tele doesn't count for any dmgfrags damage dmg_dealt = 0; } else if ( targ->invincible_finished >= g_globalvars.time ) { // damage dealt _not_ capped by victim's health if victim has pent dmg_dealt += virtual_take; } else { // damage dealt capped by victim's health dmg_dealt += bound( 0, virtual_take, targ->s.v.health ); } } else { // damage dealt capped by victim's health dmg_dealt += bound( 0, take, targ->s.v.health ); } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // FIXME: remove after combining shotgun blasts? if ( targ->ct == ctPlayer ) { targ->s.v.dmg_take += take; targ->s.v.dmg_save += save; targ->s.v.dmg_inflictor = EDICT_TO_PROG( inflictor ); } if ( save ) { if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname )) || ( targ->deathtype == dtWATER_DMG ) || ( targ->deathtype == dtEXPLO_BOX ) || ( targ->deathtype == dtFALL ) || ( targ->deathtype == dtSQUISH ) || ( targ->deathtype == dtCHANGELEVEL ) || ( targ->deathtype == dtFIREBALL ) || ( targ->deathtype == dtSLIME_DMG ) || ( targ->deathtype == dtLAVA_DMG ) || ( targ->deathtype == dtTRIGGER_HURT ) ) attackername = "world"; else attackername = attacker->s.v.netname; victimname = targ->s.v.netname; log_printf( "\t\t<event>\n" "\t\t\t<damage>\n" "\t\t\t\t<time>%f</time>\n" "\t\t\t\t<attacker>%s</attacker>\n" "\t\t\t\t<target>%s</target>\n" "\t\t\t\t<type>%s</type>\n" "\t\t\t\t<quad>%d</quad>\n" "\t\t\t\t<splash>%d</splash>\n" "\t\t\t\t<value>%d</value>\n" "\t\t\t\t<armor>1</armor>\n" "\t\t\t</damage>\n" "\t\t</event>\n", g_globalvars.time - match_start_time, cleantext(attackername), cleantext(victimname), death_type( targ->deathtype ), (int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ), dmg_is_splash, (int)save ); } // figure momentum add if ( inflictor != world && ( targ->s.v.movetype == MOVETYPE_WALK || ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) ) ) ) { float nailkick; for ( i = 0; i < 3; i++ ) dir[i] = targ->s.v.origin[i] - ( inflictor->s.v.absmin[i] + inflictor->s.v.absmax[i] ) * 0.5; VectorNormalize( dir ); dir[2] = ((dtLG_DIS_SELF == targ->deathtype || dtLG_DIS == targ->deathtype) && dir[2] < 0) ? -dir[2] : dir[2]; if ( midair && non_hdp_damage < 60 && attacker != targ ) { c1 = 11; c2 = 6; } // Yawnmode: nails increases kickback // - Molgrum if ( k_yawnmode && streq( inflictor->s.v.classname, "spike" ) ) nailkick = 1.2; else nailkick = 1.0; for ( i = 0; i < 3; i++ ) targ->s.v.velocity[i] += dir[i] * non_hdp_damage * c1 * nailkick * ( midair && playerheight >= 45 ? ( 1 + ( playerheight - 45 ) / 64 ) : 1 ); if ( midair && playerheight < 45 ) targ->s.v.velocity[2] += dir[2] * non_hdp_damage * c2 * nailkick; // only for z component if ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) ) { targ->s.v.flags = (int)targ->s.v.flags & ~FL_ONGROUND; } } if ( match_in_progress == 2 && (int)cvar("k_dmgfrags") ) { if ( attacker->ct == ctPlayer && targ->ct == ctPlayer && attacker != targ ) { if ( isDuel() || isFFA() || strneq(attackerteam, targteam) ) { int dmg_frags; attacker->ps.dmg_frags += dmg_dealt; // add dealt dmg_frags = attacker->ps.dmg_frags / 100; // 1 frag = 100 damage attacker->s.v.frags = (int)(attacker->s.v.frags + dmg_frags); attacker->ps.dmg_frags -= dmg_frags * 100; } } } // do the damage if ( match_in_progress == 2 || dtSUICIDE == targ->deathtype // do suicide damage anyway || TELEDEATH( targ ) || ( k_practice && targ->ct != ctPlayer ) // #practice mode# || take >= 99999 // do such huge damage even in prewar, prewar because indirectly here match_in_progress != 2 ) { targ->s.v.health -= take; // G_bprint( 2, "%s %f\n", targ->s.v.classname, targ->s.v.health ); if ( take ) { if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname )) || ( targ->deathtype == dtWATER_DMG ) || ( targ->deathtype == dtEXPLO_BOX ) || ( targ->deathtype == dtFALL ) || ( targ->deathtype == dtSQUISH ) || ( targ->deathtype == dtCHANGELEVEL ) || ( targ->deathtype == dtFIREBALL ) || ( targ->deathtype == dtSLIME_DMG ) || ( targ->deathtype == dtLAVA_DMG ) || ( targ->deathtype == dtTRIGGER_HURT ) ) attackername = "world"; else attackername = attacker->s.v.netname; victimname = targ->s.v.netname; log_printf( "\t\t<event>\n" "\t\t\t<damage>\n" "\t\t\t\t<time>%f</time>\n" "\t\t\t\t<attacker>%s</attacker>\n" "\t\t\t\t<target>%s</target>\n" "\t\t\t\t<type>%s</type>\n" "\t\t\t\t<quad>%d</quad>\n" "\t\t\t\t<splash>%d</splash>\n" "\t\t\t\t<value>%d</value>\n" "\t\t\t\t<armor>0</armor>\n" "\t\t\t</damage>\n" "\t\t</event>\n", g_globalvars.time - match_start_time, cleantext(attackername), cleantext(victimname), death_type( targ->deathtype ), (int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ), dmg_is_splash, (int)take ); } if ( !targ->s.v.health || dtSUICIDE == targ->deathtype ) targ->s.v.health = -1; // qqshka, no zero health, heh, imo less bugs after this } // show damage in sbar if ( match_in_progress != 2 && ISLIVE( targ ) && !k_matchLess ) { if ( !midair || ( (int)targ->s.v.flags & FL_ONGROUND ) ) { if ( targ->ct == ctPlayer ) targ->s.v.currentammo = 1000 + Q_rint(damage); if ( attacker != targ && attacker->ct == ctPlayer) attacker->s.v.health = 1000 + Q_rint(damage); } } // update damage stats like: give/taked/team damage if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) { if ( attacker == targ ) { // self damage attacker->ps.dmg_self += dmg_dealt; } else { int items = targ->s.v.items; // damage to enemy weapon if ( items & (IT_ROCKET_LAUNCHER | IT_LIGHTNING) ) { attacker->ps.dmg_eweapon += dmg_dealt; } if ( tp_num() && streq(attackerteam, targteam) ) { attacker->ps.dmg_team += dmg_dealt; } else { attacker->ps.dmg_g += dmg_dealt; targ->ps.dmg_t += dmg_dealt; } // real hits if ( take || save ) { if ( dtRL == targ->deathtype ) attacker->ps.wpn[wpRL].rhits++; if ( dtGL == targ->deathtype ) attacker->ps.wpn[wpGL].rhits++; } // virtual hits if ( virtual_take || save ) { if ( dtRL == targ->deathtype ) { attacker->ps.wpn[wpRL].vhits++; // virtual given rl damage attacker->ps.dmg_g_rl += ( virtual_take + save ); } if ( dtGL == targ->deathtype ) attacker->ps.wpn[wpGL].vhits++; } } } // mid air bonuses if ( midair && match_in_progress == 2 && attacker != targ && take && rl_dmg) MidairDamageBonus(attacker, midheight); if ( midair && match_in_progress == 2 && stomp_dmg ) { attacker->ps.mid_stomps++; targ->s.v.frags -= 3; } // if targed killed, do appropriate action and return if ( ISDEAD( targ ) ) { Killed( targ, attacker, inflictor ); return; } // react to the damage - call pain function oldself = self; self = targ; if ( (int)self->s.v.flags & FL_MONSTER ) { GetMadAtAttacker( attacker ); } if ( self->th_pain ) { self->th_pain( attacker, take ); } self = oldself; }
void PainSound() { int rs; if ( ISDEAD( self ) ) return; // water pain sounds if ( (self->s.v.watertype == CONTENT_WATER || self->s.v.watertype == CONTENT_SLIME) && self->s.v.waterlevel == 3 ) { DeathBubbles( 1 ); if ( match_in_progress != 2 ) return; if ( g_random() > 0.5 ) sound( self, CHAN_VOICE, "player/drown1.wav", 1, ATTN_NORM ); else sound( self, CHAN_VOICE, "player/drown2.wav", 1, ATTN_NORM ); return; } // slime pain sounds if ( self->s.v.watertype == CONTENT_SLIME ) { // FIX ME put in some steam here if ( match_in_progress != 2 ) return; if ( g_random() > 0.5 ) sound( self, CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM ); else sound( self, CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM ); return; } if ( self->s.v.watertype == CONTENT_LAVA ) { if ( match_in_progress != 2 ) return; if ( g_random() > 0.5 ) sound( self, CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM ); else sound( self, CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM ); return; } if ( self->pain_finished > g_globalvars.time ) { self->axhitme = 0; return; } self->pain_finished = g_globalvars.time + 0.5; // don't make multiple pain sounds right after each other // ax pain sound if ( self->axhitme == 1 ) { self->axhitme = 0; sound( self, CHAN_VOICE, "player/axhit1.wav", 1, ATTN_NORM ); return; } rs = ( g_random() * 5 ) + 1; self->noise = ""; if ( rs == 1 ) self->noise = "player/pain1.wav"; else if ( rs == 2 ) self->noise = "player/pain2.wav"; else if ( rs == 3 ) self->noise = "player/pain3.wav"; else if ( rs == 4 ) self->noise = "player/pain4.wav"; else if ( rs == 5 ) self->noise = "player/pain5.wav"; else self->noise = "player/pain6.wav"; sound( self, CHAN_VOICE, self->noise, 1, ATTN_NORM ); return; }
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); }
void SCR_SetupAutoID (void) { int i, view[4]; float model[16], project[16], winz, *origin; entity_t *state; autoid_player_t *id; vec3_t OurViewPoint; vec3_t ThisClientPoint; vec3_t stop; vec3_t edist; void TraceLine (vec3_t start, vec3_t end, vec3_t impact); autoid_count = 0; if (!scr_autoid.value || cls.state != ca_connected || !cls.demoplayback) return; glGetFloatv (GL_MODELVIEW_MATRIX, model); glGetFloatv (GL_PROJECTION_MATRIX, project); glGetIntegerv (GL_VIEWPORT, view); for (i = 0 ; i < cl.maxclients ; i++) { state = &cl_entities[1+i]; if (!state->model->name) // NULL model continue; if (!(state->modelindex == cl_modelindex[mi_player])) // Not a player model continue; if (ISDEAD(state->frame)) // Dead continue; // if (strcmp(state->model->name, "progs/player.mdl")) // continue; if (R_CullSphere(state->origin, 0)) continue; // Logic // Fill in one value with our viewpoint and the next value with target // Do traceline VectorCopy (r_refdef.vieworg, OurViewPoint); VectorCopy (state->origin, ThisClientPoint); TraceLine (OurViewPoint, ThisClientPoint, stop); if (stop[0] != 0 || stop[1] != 0 || stop[2] != 0) // Quick and dirty traceline continue; #if 1 if (!CL_Visible_To_Client(OurViewPoint, ThisClientPoint)) { // We can't see it //Con_Printf("Cannot see it\n"); continue; } #endif id = &autoids[autoid_count]; id->player = &cl.scores[i]; #if 0 Con_Printf("Player %s\n", id->player->name); // Print name of seen player Con_Printf("Client num %i\n", i); Con_Printf("modelname is %s\n", state->model->name); Con_Printf("modelindex is %i\n", state->modelindex); //Con_Printf("modelname char one is %i\n", state->model->name[0]); Con_Printf("playermodel index is %i\n", cl_modelindex[mi_player]); #endif origin = state->origin; if (qglProject(origin[0], origin[1], origin[2] + 28, model, project, view, &id->x, &id->y, &winz)) autoid_count++; } }
/* ============= ai_run The monster has an enemy it is trying to kill ============= */ void ai_run( float dist ) { vec3_t tmpv; if ( k_bloodfest ) { if ( (int)self->s.v.flags & FL_SWIM ) { dist *= 5; // let fish swim faster in bloodfest mode. } else if ( self->bloodfest_boss ) { dist *= 2; // let boss move faster } } movedist = dist; // see if the enemy is dead if ( ISDEAD( PROG_TO_EDICT( self->s.v.enemy ) ) || ( (int)PROG_TO_EDICT( self->s.v.enemy )->s.v.flags & FL_NOTARGET ) ) { self->s.v.enemy = EDICT_TO_PROG( world ); // FIXME: look all around for other targets if ( self->oldenemy && ISLIVE( self->oldenemy ) && !( (int)self->oldenemy->s.v.flags & FL_NOTARGET ) ) { self->s.v.enemy = EDICT_TO_PROG( self->oldenemy ); HuntTarget (); } else { if ( !self->movetarget || self->movetarget == world ) { if ( self->th_stand ) self->th_stand(); } else { if ( self->th_walk ) self->th_walk(); } return; } } self->show_hostile = g_globalvars.time + 1; // wake up other monsters // check knowledge of enemy enemy_vis = visible( PROG_TO_EDICT( self->s.v.enemy ) ); if ( enemy_vis ) self->search_time = g_globalvars.time + 5; // does not search for enemy next 5 seconds // look for other coop players if ( coop && self->search_time < g_globalvars.time ) { if ( FindTarget() ) { // this is fix for too frequent enemy sighting, required for bloodfest mode. if ( !visible( PROG_TO_EDICT( self->s.v.enemy ) ) ) { self->search_time = g_globalvars.time + 5; // does not search for enemy next 5 seconds } return; } } enemy_infront = infront( PROG_TO_EDICT( self->s.v.enemy ) ); enemy_range = range( PROG_TO_EDICT( self->s.v.enemy ) ); VectorSubtract( PROG_TO_EDICT( self->s.v.enemy )->s.v.origin, self->s.v.origin, tmpv); enemy_yaw = vectoyaw( tmpv ); if ( self->attack_state == AS_MISSILE ) { //dprint ("ai_run_missile\n"); ai_run_missile(); return; } if ( self->attack_state == AS_MELEE ) { //dprint ("ai_run_melee\n"); ai_run_melee(); return; } if ( CheckAnyAttack() ) return; // beginning an attack if ( self->attack_state == AS_SLIDING ) { ai_run_slide(); return; } // head straight in movetogoal( dist ); // done in C code... }