// Assign bitmask to each player to indicate what team they are in // Called at match start and also when a client connects void BotsAssignTeamFlags (void) { gedict_t *p, *p2; int teamflag = 1; char *s = ""; if (!teamplay) return; // Clear teamflag from all items for (p = world; (p = nextent (p)); ) p->fb.teamflag = 0; for ( p = world; (p = find_plr( p )); ) p->k_flag = 0; for ( p = world; (p = find_plr( p )); ) { if( p->k_flag || strnull( s = getteam( p ) ) ) continue; p->k_flag = 1; p->fb.teamflag = teamflag; for (p2 = p; (p2 = find_plr (p2)); ) { if (streq (s, getteam (p2))) { p2->k_flag = 1; p2->fb.teamflag = teamflag; } } teamflag <<= 1; } }
// convienence command for ctf admins // often times you play a game on non-symmetrical map as one color then swap teams and play again to be fair void AdminSwapAll() { gedict_t *p; if ( !is_adm( self ) ) return; if ( match_in_progress ) return; if ( !isCTF() ) return; for( p = world; (p = find_plr( p )); ) { if ( streq( getteam(p), "blue" ) ) stuffcmd_flags(p, STUFFCMD_IGNOREINDEMO, "team \"red\"\ncolor 4\n"); else if ( streq( getteam(p), "red" ) ) stuffcmd_flags(p, STUFFCMD_IGNOREINDEMO, "team \"blue\"\ncolor 13\n"); } G_bprint(2, "%s swapped the teams\n", getname( self ) ); }
void PlayerDropFlag( gedict_t *player, qbool tossed ) { gedict_t *flag; char *cn; if (!(player->ctf_flag & CTF_FLAG)) return; if ( streq(getteam(player), "red") ) cn = "item_flag_team2"; else cn = "item_flag_team1"; flag = find( world, FOFCLSN, cn ); if ( flag ) DropFlag( flag, tossed ); }
void GrappleAnchor() { gedict_t *owner = PROG_TO_EDICT( self->s.v.owner ); if (other == owner) return; // DO NOT allow the grapple to hook to any projectiles, no matter WHAT! // if you create new types of projectiles, make sure you use one of the // classnames below or write code to exclude your new classname so // grapples will not stick to them. if ( streq(other->s.v.classname, "rocket") || streq(other->s.v.classname, "grenade") || streq(other->s.v.classname, "spike" ) || streq(other->s.v.classname, "hook" )) return; if ( other->ct == ctPlayer ) { // grappling players in prewar is annoying if ( match_in_progress != 2 || (tp_num() == 4 && streq(getteam(other), getteam(owner))) ) { GrappleReset( self ); return; } sound ( self, CHAN_WEAPON, "player/axhit1.wav", 1, ATTN_NORM ); // previously 10 damage per hit, but at close range that could be exploited other->deathtype = dtHOOK; T_Damage ( other, self, owner, 1 ); // make hook invisible since we will be pulling directly // towards the player the hook hit. Quakeworld makes it // too quirky to try to match hook's velocity with that of // the client that it hit. setmodel ( self, "" ); } else { sound ( self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM ); // One point of damage inflicted upon impact. Subsequent // damage will only be done to PLAYERS... this way secret // doors and triggers will only be damaged once. if ( other->s.v.takedamage ) { other->deathtype = dtHOOK; T_Damage ( other, self, owner, 1 ); } SetVector( self->s.v.velocity , 0, 0, 0 ); SetVector( self->s.v.avelocity, 0, 0, 0 ); } // conveniently clears the sound channel of the CHAIN1 sound, // which is a looping sample and would continue to play. Tink1 is // the least offensive choice, as NULL.WAV loops and clogs the // channel with silence sound ( owner, CHAN_NO_PHS_ADD + CHAN_WEAPON, "weapons/tink1.wav", 1, ATTN_NORM ); if ( !owner->s.v.button0 ) { GrappleReset( self ); return; } if ( (int)owner->s.v.flags & FL_ONGROUND ) owner->s.v.flags -= FL_ONGROUND; owner->on_hook = true; sound ( owner, CHAN_WEAPON, "weapons/chain2.wav", 1, ATTN_NORM ); owner->ctf_sound = true; self->s.v.enemy = EDICT_TO_PROG( other ); self->s.v.think = (func_t) GrappleTrack; self->s.v.nextthink = g_globalvars.time; self->s.v.solid = SOLID_NOT; self->s.v.touch = (func_t) SUB_Null; }
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 CTF_Obituary( gedict_t *targ, gedict_t *attacker ) { qbool carrier_bonus = false; qbool flagdefended = false; gedict_t *head; char *attackerteam; if ( !isCTF() ) return; attackerteam = getteam(attacker); // 2 point bonus for killing enemy flag carrier if ( targ->ctf_flag & CTF_FLAG ) { attacker->ps.c_frags++; attacker->s.v.frags += 2; attacker->ps.ctf_points += 2; attacker->carrier_frag_time = g_globalvars.time; //G_sprint( attacker, 1, "Enemy flag carrier killed: 2 bonus frags\n" ); } // defending carrier from aggressive player if (( targ->carrier_hurt_time + CARRIER_DEFEND_TIME > g_globalvars.time ) && !( attacker->ctf_flag & CTF_FLAG ) ) { carrier_bonus = true; attacker->ps.c_defends++; attacker->s.v.frags += 2; attacker->ps.ctf_points += 2; // Yes, aggressive is spelled wrong.. but dont want to fix now and break stat parsers G_bprint( 2, "%s defends %s's flag carrier against an agressive enemy\n", attacker->s.v.netname, streq( getteam(attacker), "red" ) ? redtext("RED") : redtext("BLUE") ); } head = trap_findradius( world, targ->s.v.origin, 400 ); while ( head ) { if ( head->ct == ctPlayer ) { if ( (head->ctf_flag & CTF_FLAG) && ( head != attacker ) && streq(getteam(head), getteam(attacker)) && !carrier_bonus ) { attacker->ps.c_defends++; attacker->s.v.frags++; attacker->ps.ctf_points++; G_bprint( 2, "%s defends %s's flag carrier\n", attacker->s.v.netname, streq(getteam(attacker), "red") ? redtext("RED") : redtext("BLUE")); } } if ( (streq(getteam(attacker), "red") && streq(head->s.v.classname, "item_flag_team1")) || (streq(getteam(attacker), "blue") && streq(head->s.v.classname, "item_flag_team2")) ) { flagdefended = true; attacker->ps.f_defends++; attacker->s.v.frags += 2; attacker->ps.ctf_points += 2; G_bprint( 2, "%s defends the %s flag\n", attacker->s.v.netname, streq(getteam(attacker), "red") ? redtext("RED") : redtext("BLUE")); } head = trap_findradius( head, targ->s.v.origin, 400 ); } // Defend bonus if attacker is close to flag even if target is not head = trap_findradius( world, attacker->s.v.origin, 400 ); while ( head ) { if ( ( streq(head->s.v.classname, "item_flag_team1") && streq(attackerteam, "red" ) ) || ( streq(head->s.v.classname, "item_flag_team2") && streq(attackerteam, "blue") ) ) { if (!flagdefended) { attacker->ps.f_defends++; attacker->s.v.frags += 2; attacker->ps.ctf_points += 2; G_bprint( 2, "%s defends the %s flag\n", attacker->s.v.netname, streq(attackerteam, "red") ? redtext("RED") : redtext("BLUE")); } } head = trap_findradius( head, attacker->s.v.origin, 400 ); } }
void FlagStatus() { gedict_t *flag1, *flag2; if ( !isCTF() ) return; flag1 = find( world, FOFCLSN, "item_flag_team1" ); flag2 = find( world, FOFCLSN, "item_flag_team2" ); if (!flag1 || !flag2) return; if ( self->ct == ctSpec ) { switch ( (int) flag1->cnt ) { case FLAG_AT_BASE: G_sprint( self, 2, "The %s flag is in base.\n", redtext("RED") ); break; case FLAG_CARRIED: G_sprint( self, 2, "%s has the %s flag.\n", PROG_TO_EDICT( flag1->s.v.owner )->s.v.netname, redtext("RED") ); break; case FLAG_DROPPED: G_sprint( self, 2, "The %s flag is lying about.\n", redtext("RED") ); break; } switch ( (int) flag2->cnt ) { case FLAG_AT_BASE: G_sprint( self, 2, "The %s flag is in base. ", redtext("BLUE") ); break; case FLAG_CARRIED: G_sprint( self, 2, "%s has the %s flag. ", PROG_TO_EDICT( flag1->s.v.owner )->s.v.netname, redtext("BLUE") ); break; case FLAG_DROPPED: G_sprint( self, 2, "The %s flag is lying about. ", redtext("BLUE") ); break; } return; } // Swap flags so that flag1 is "your" flag if ( streq(getteam(self), "blue") ) { gedict_t *swap = flag1; flag1 = flag2; flag2 = swap; } switch ( (int) flag1->cnt ) { case FLAG_AT_BASE: G_sprint( self, 2, "Your flag is in base. " ); break; case FLAG_CARRIED: G_sprint( self, 2, "%s has your flag. ", PROG_TO_EDICT( flag1->s.v.owner )->s.v.netname ); break; case FLAG_DROPPED: G_sprint( self, 2, "Your flag is lying about. " ); break; } switch ( (int) flag2->cnt ) { case FLAG_AT_BASE: G_sprint ( self, 2, "The enemy flag is in their base.\n" ); break; case FLAG_CARRIED: if ( self == PROG_TO_EDICT( flag2->s.v.owner )) G_sprint ( self, 2, "You have the enemy flag.\n" ); else G_sprint ( self, 2, "%s has the enemy flag.\n", PROG_TO_EDICT( flag2->s.v.owner)->s.v.netname ); break; case FLAG_DROPPED: G_sprint ( self, 2, "The enemy flag is lying about.\n" ); break; default: G_sprint ( self, 2, "\n" ); } }
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 FlagTouch() { gedict_t *p, *owner; if( !k_practice ) if ( match_in_progress != 2 ) return; if ( other->ct != ctPlayer ) return; if ( other->s.v.health < 1 ) return; if ( self->cnt == FLAG_RETURNED ) return; // if owner of the flag, do nothing (probably toss in progress) if ( self->s.v.owner == EDICT_TO_PROG( other ) ) return; // touching their own flag if ((self->k_teamnumber == 1 && streq(getteam(other), "red")) || (self->k_teamnumber == 2 && streq(getteam(other), "blue")) ) { if ( self->cnt == FLAG_AT_BASE ) { if ( other->ctf_flag & CTF_FLAG ) { gedict_t *cflag = NULL; // capture other->ctf_flag -= ( (int) other->ctf_flag & CTF_FLAG ); other->s.v.effects -= ( (int) other->s.v.effects & (EF_FLAG1 | EF_FLAG2) ); sound( other, CHAN_VOICE, "misc/flagcap.wav", 1, ATTN_NONE); G_bprint( 2, "%s", other->s.v.netname ); if ( self->k_teamnumber == 1 ) { cflag = find( world, FOFCLSN, "item_flag_team2" ); G_bprint( 2, " %s the %s flag!\n", redtext("captured"), redtext("BLUE") ); } else { cflag = find( world, FOFCLSN, "item_flag_team1" ); G_bprint( 2, " %s the %s flag!\n", redtext("captured"), redtext("RED") ); } if ( cflag ) G_bprint( 2, "The capture took %.1f seconds\n", cflag->cnt2 ); other->s.v.frags += CAPTURE_BONUS; other->ps.ctf_points += CAPTURE_BONUS; other->ps.caps++; // loop through all players on team to give bonus for ( p = world; (p = find_plr( p )); ) { p->s.v.items -= ( (int) p->s.v.items & (IT_KEY1 | IT_KEY2) ); if ( streq(getteam(p), getteam(other)) ) { if ( p->return_flag_time + RETURN_ASSIST_TIME > g_globalvars.time ) { p->return_flag_time = -1; p->s.v.frags += RETURN_ASSIST_BONUS; p->ps.ctf_points += RETURN_ASSIST_BONUS; G_bprint( 2, "%s gets an assist for returning his flag!\n", p->s.v.netname ); } if ( p->carrier_frag_time + CARRIER_ASSIST_TIME > g_globalvars.time ) { p->carrier_frag_time = -1; p->s.v.frags += CARRIER_ASSIST_BONUS; p->ps.ctf_points += CARRIER_ASSIST_BONUS; G_bprint( 2, "%s gets an assist for fragging the flag carrier!\n", p->s.v.netname ); } if ( p != other ) { p->s.v.frags += TEAM_BONUS; p->ps.ctf_points += TEAM_BONUS; } } else p->carrier_hurt_time = -1; } RegenFlags( true ); k_nochange = 0; // Set it so it should update scores at next attempt. refresh_plus_scores (); return; } return; } else if ( self->cnt == FLAG_DROPPED ) { other->s.v.frags += RETURN_BONUS; other->ps.ctf_points += RETURN_BONUS; other->ps.returns++; other->return_flag_time = g_globalvars.time; sound (other, CHAN_ITEM, self->s.v.noise1, 1, ATTN_NONE); RegenFlag( self ); G_bprint( 2, "%s", other->s.v.netname); if ( self->k_teamnumber == 1) G_bprint( 2, " %s the %s flag!\n", redtext("returned"), redtext("RED") ); else G_bprint( 2, " %s the %s flag!\n", redtext("returned"), redtext("BLUE") ); k_nochange = 0; // Set it so it should update scores at next attempt. refresh_plus_scores (); return; } } if ( strneq(getteam(other), "red") && strneq(getteam(other), "blue")) return; refresh_plus_scores (); // update players status bar faster // Pick up the flag sound( other, CHAN_ITEM, self->s.v.noise, 1, ATTN_NONE ); other->ctf_flag |= CTF_FLAG; other->s.v.items = (int) other->s.v.items | (int) self->s.v.items; self->cnt = FLAG_CARRIED; self->s.v.solid = SOLID_NOT; self->s.v.owner = EDICT_TO_PROG( other ); owner = PROG_TO_EDICT( self->s.v.owner ); owner->ps.pickups++; G_bprint( 2, "%s", other->s.v.netname ); if ( streq(getteam(other), "red") ) { G_bprint( 2, " %s the %s flag!\n", redtext("got"), redtext("BLUE") ); owner->s.v.effects = (int) owner->s.v.effects | EF_FLAG2; } else { G_bprint( 2, " %s the %s flag!\n", redtext("got"), redtext("RED") ); owner->s.v.effects = (int) owner->s.v.effects | EF_FLAG1; } setmodel( self, "" ); }