agrip/misc.mqc

Go to the documentation of this file.
00001 /*  Copyright 2004 Matthew Tylee Atkinson
00002 
00003     This program is free software; you can redistribute it and/or modify
00004     it under the terms of the GNU General Public License as published by
00005     the Free Software Foundation; either version 2 of the License, or
00006     (at your option) any later version.
00007 
00008     This program is distributed in the hope that it will be useful,
00009     but WITHOUT ANY WARRANTY; without even the implied warranty of
00010     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011     GNU General Public License for more details.
00012 
00013     You should have received a copy of the GNU General Public License
00014     along with this program; if not, write to the Free Software
00015     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016 
00017     See file, 'COPYING', for details.
00018 */
00019 
00020 /* $AGRIP-START */
00021 /* AGRIP Misc Functions */
00022 
00023 // CONSTANTS
00024 
00025 // for misc...
00026 float SNAP_MISC_NORMYAW_OFFSET = 0;
00027 
00028 // for nav...
00029 float SNAP_NAV_STRUCT_WALL = 40;
00030 float SNAP_NAV_STRUCT_SLOPE = 41; 
00031 float SNAP_NAV_STRUCT_SLOPE_DOWN = 41.5;
00032 float SNAP_NAV_STRUCT_DOOR = 42;
00033 
00034 float SNAP_NAV_DIR_FWD = 1;
00035 float SNAP_NAV_DIR_BCK = 2;
00036 float SNAP_NAV_DIR_LFT = 4;
00037 float SNAP_NAV_DIR_RGT = 8;
00038 float SNAP_NAV_DIR_UP = 16;
00039 float SNAP_NAV_DIR_DN = 32;
00040 
00041 float SNAP_NAV_JMP_NRM = 1;
00042 float SNAP_NAV_JMP_RUN = 2;
00043 
00044 
00045 // PROTOTYPES
00046 
00047 // OBJECT UTILITY FUNCTIONS
00048 float snap_misc_ownervisible(vector targ_origin);
00049 void snap_misc_m2o(string msg_string);
00050 
00051 // PLAYER UTILITY FUNCTIONS
00052 void snap_misc_weaponswitch();
00053 void snap_misc_blockedtest();
00054 void snap_misc_blockedtest_propchg(float direction);
00055 void snap_misc_m2m(string msg_string);
00056 
00057 // GENERIC UTILITY FUNCTIONS
00058 float snap_misc_normalyaw(float init_yaw);
00059 void snap_misc_showpoint(vector point, string sprite, float ttl);
00060 float snap_misc_jumptest(vector jump_origin, vector move_dir);
00061 
00062 // BOT UTILITY FUNCTIONS
00063 void snap_misc_botspawner();
00064 
00065 // TEAM MANAGEMENT UTILITY FUNCTIONS
00066 float CountPlayers();
00067 float CountPlayersTeam(string team);
00068 float snap_misc_pickrndteam(float notmyteam);
00069 string  (float teamnum)                             snap_misc_nameforteamnum;
00070 float snap_misc_numforteamname(string teamname);
00071 float snap_misc_bottomforteamnum(float teamnum);
00072 float snap_misc_topforteamnum(float teamnum);
00073 
00074 
00075 // IMPLEMENTATIONS
00076 
00077 // OBJECT UTILITY FUNCTIONS
00079 
00089 float snap_misc_ownervisible(vector targ_origin)
00090 {
00091     traceline(self.owner.origin, targ_origin, true, self);
00092 
00093     if( trace_fraction == 1 )
00094     {
00095         local float obj_orig_yaw, player_normal_yaw;
00096         local float min_fov_yaw, max_fov_yaw;
00097     
00098         // Get yaw of targ's origin relative to player...
00099         obj_orig_yaw = vectoyaw(targ_origin - self.owner.origin);
00100         obj_orig_yaw = snap_misc_normalyaw(obj_orig_yaw);
00101     
00102         // Get yaw of player...
00103         player_normal_yaw = snap_misc_normalyaw(self.owner.angles_y);
00104     
00105         // Work out the bounds that will be used to test if the object is within
00106         // the player's FOV...
00107         
00108         // For min...
00109         min_fov_yaw = player_normal_yaw - 45;
00110         /*if( min_fov_yaw > 360 )
00111             min_fov_yaw = min_fov_yaw - 360;
00112         else if(min_fov_yaw < 0 )
00113             min_fov_yaw = min_fov_yaw + 360;*/
00114     
00115         // For max...
00116         max_fov_yaw = player_normal_yaw + 45;
00117         /*if( max_fov_yaw > 360 )
00118             max_fov_yaw = max_fov_yaw - 360;
00119         else if(max_fov_yaw < 0 )
00120             max_fov_yaw = max_fov_yaw + 360;*/
00121         
00122         // Is it within our FOV?
00123         if( min_fov_yaw <= obj_orig_yaw && max_fov_yaw >= obj_orig_yaw )
00124         {
00125             return true;
00126         }
00127         else
00128         {
00129             // Could be that annoying 360 bug...
00130             obj_orig_yaw = obj_orig_yaw - 360;
00131             if( min_fov_yaw <= obj_orig_yaw && max_fov_yaw >= obj_orig_yaw )
00132             {
00133                 return true;
00134             }
00135             else
00136             {
00137                 return false;
00138             }
00139         }
00140     }
00141     else
00142     {
00143         return false;
00144     }
00145 };
00146 
00155 void snap_misc_m2o(string msg_string)
00156 {
00157     if( ! self.owner.agrip_aux.state )
00158         sprint(self.owner, PRINT_MEDIUM, "!", msg_string);
00159     else
00160         sprint(self.owner, PRINT_MEDIUM, msg_string);
00161 };
00162 
00163 
00164 // PLAYER UTILITY FUNCTIONS
00166 
00172 void snap_misc_weaponswitch()
00173 {
00174     if( self.weapon == IT_AXE )
00175         snap_misc_m2m("Axe.\n");
00176     else if( self.weapon == IT_SHOTGUN )
00177         snap_misc_m2m("Shotgun.\n");
00178     else if( self.weapon == IT_SUPER_SHOTGUN )
00179         snap_misc_m2m("Double-Barrelled Shotgun.\n");
00180     else if (self.weapon == IT_NAILGUN )
00181         snap_misc_m2m("Nailgun.\n");
00182     else if (self.weapon == IT_SUPER_NAILGUN )
00183         snap_misc_m2m("Super Nailgun.\n");
00184     else if (self.weapon == IT_GRENADE_LAUNCHER )
00185         snap_misc_m2m("Grenade Launcher.\n");
00186     else if (self.weapon == IT_ROCKET_LAUNCHER )
00187         snap_misc_m2m("Rocket Launcher.\n");
00188     else if (self.weapon == IT_LIGHTNING )
00189         snap_misc_m2m("Lightning Gun.\n");
00190 };
00191 
00207 void snap_misc_blockedtest()
00208 {
00209     // Get our velocity vectors...
00210     makevectors(self.angles);
00211 
00212     // Tracebox and store the results in the bitfields.
00213     // BTW, Ada really loves bitfields _and_ makes them easy to use!
00214 
00215     // agrip_aux properties:
00216     //  * .ammo_shells  - ``just hit this''
00217     //  * .ammo_nails   - ``sustained touch''
00218     //  * .ammo_rockets - count of walls we're touching
00219 
00220     // Forward
00221     tracebox(self.origin, VEC_HULL_MIN, VEC_HULL_MAX, (self.origin + ( v_forward * 10 ) ), true, self);
00222     snap_misc_blockedtest_propchg(SNAP_NAV_DIR_FWD);
00223 
00224     // Backwards
00225     tracebox(self.origin, VEC_HULL_MIN, VEC_HULL_MAX, (self.origin - ( v_forward * 10 ) ), true, self);
00226     snap_misc_blockedtest_propchg(SNAP_NAV_DIR_BCK);
00227 
00228     // Left
00229     tracebox(self.origin, VEC_HULL_MIN, VEC_HULL_MAX, (self.origin - ( v_right * 10 ) ), true, self);
00230     snap_misc_blockedtest_propchg(SNAP_NAV_DIR_LFT);
00231 
00232     // Right
00233     tracebox(self.origin, VEC_HULL_MIN, VEC_HULL_MAX, (self.origin + ( v_right * 10 ) ), true, self);
00234     snap_misc_blockedtest_propchg(SNAP_NAV_DIR_RGT);
00235 
00236     // If we're in water...
00237     // AG_FIXME - clear the up/down flags if we're not in water.
00238     if( 0 )
00239     {
00240         // Up
00241         tracebox(self.origin, VEC_HULL_MIN, VEC_HULL_MAX, (self.origin + ( v_up * 10 ) ), true, self);
00242         snap_misc_blockedtest_propchg(SNAP_NAV_DIR_UP);
00243     
00244         // Down
00245         tracebox(self.origin, VEC_HULL_MIN, VEC_HULL_MAX, (self.origin - ( v_up * 10 ) ), true, self);
00246         snap_misc_blockedtest_propchg(SNAP_NAV_DIR_DN);
00247     }
00248 };
00249 
00250 /*
00251     This function is called by the one that tests if we are blocked in any
00252     direction and sets the properties of the agrip_aux object accordingly.
00253     
00254     @param direction    the direction we're currently processing
00255     \ingroup plr_util
00256 */
00257 void snap_misc_blockedtest_propchg(float direction)
00258 {
00259     /*if( direction == SNAP_NAV_DIR_FWD )
00260     {
00261         dprint("tracebox fraction: ");
00262         dprint(ftos(trace_fraction));
00263         dprint("\n");
00264     }*/
00265 
00266     // If we're touching a wall in this direction...
00267     if( trace_fraction == 0 )
00268     {
00269         // If the nav object has noticed we've hit the wall, it will have
00270         // cleared the ``just hit this'' flag and left the ``sustained touch''
00271         // one set.  We shouldn't set the ``just hit this'' if the other one
00272         // is still set...
00273         if( ! (self.agrip_aux.ammo_nails & direction) )
00274         {
00275             // Set both the ``just hit this'' and ``sustained hit'' flags...
00276             self.agrip_aux.ammo_shells = self.agrip_aux.ammo_shells + direction;
00277             self.agrip_aux.ammo_nails = self.agrip_aux.ammo_nails + direction;
00278 
00279             // Add this wall we're touching to the counter...
00280             self.agrip_aux.ammo_rockets = self.agrip_aux.ammo_rockets + 1;
00281         }
00282     }
00283     else
00284     {
00285         // If either of the flags are set...
00286         if(     (self.agrip_aux.ammo_nails & direction)
00287             ||  (self.agrip_aux.ammo_shells & direction) )
00288         {
00289             // Clear both flags...
00290             self.agrip_aux.ammo_shells = self.agrip_aux.ammo_shells - ( self.agrip_aux.ammo_shells & direction );
00291             self.agrip_aux.ammo_nails = self.agrip_aux.ammo_nails - ( self.agrip_aux.ammo_nails & direction );
00292 
00293             // Decrement the wall-touch counter...
00294             self.agrip_aux.ammo_rockets = self.agrip_aux.ammo_rockets - 1;
00295         }
00296     }
00297 };
00298 
00307 void snap_misc_m2m(string msg_string)
00308 {
00309     if( ! self.agrip_aux.state )
00310         sprint(self, PRINT_MEDIUM, "!", msg_string);
00311     else
00312         sprint(self, PRINT_MEDIUM, msg_string);
00313 };
00314 
00315 
00316 // GENERIC UTILITY FUNCTIONS
00318 
00331 float snap_misc_normalyaw(float init_yaw)
00332 {
00333     local float normal_yaw;
00334 
00335     // Normalise the incoming yaw...
00336     // There are 3 common situations in Quake 1 maps:
00337     //  1. Offset is   0
00338     //  2. Offset is  90
00339     //  3. Offest is -90
00340 
00341     // Apply our offset...
00342     // 1, 2 & 3
00343     normal_yaw = init_yaw - SNAP_MISC_NORMYAW_OFFSET;
00344 
00345     // Correct out-of-range...
00346     if( normal_yaw <= 0 )
00347         normal_yaw = normal_yaw + 360;
00348     else if( normal_yaw > 360 )
00349         normal_yaw = normal_yaw - 360;
00350 
00351     // Flip-Reverse it, lol...
00352     normal_yaw = 360 - normal_yaw;
00353   
00354     // Some debug info...
00355     /*dprint("NORMALYAW():\n");
00356     dprint("init yaw: ");dprint(ftos(init_yaw));dprint("\n");
00357     dprint("norm yaw: ");dprint(ftos(normal_yaw));dprint("\n");
00358     dprint("\n");*/
00359 
00360     // Return the normalised yaw...
00361     return normal_yaw;
00362 };
00363 
00372 void snap_misc_showpoint(vector point, string sprite, float ttl)
00373 {
00374     local entity temp_point_ent;
00375     temp_point_ent = spawn();
00376     setorigin(temp_point_ent, point);
00377     setmodel(temp_point_ent, sprite);
00378     //makestatic(temp_point_ent);
00379     temp_point_ent.think = SUB_Remove;
00380     temp_point_ent.nextthink = time + ttl;
00381 };
00382 
00392 float snap_misc_jumptest(vector jump_origin, vector move_dir)
00393 {
00394     local float retval;
00395     local vector jumptestpoint;
00396     // Not strictly needed but keeps things readable!
00397     
00398     // To find out if the player can make a jump.  We need to:
00399     //  * Look in front of the drop horizontally.
00400     //  * See if there is a floor to land on within a reasonable distance.
00401     //  * See if there is space above to provide room for the jump.
00402     //  * Work out if a running jump is needed.
00403 
00404     // Where's the point we need to test?
00405     // For a running jump...
00406     jumptestpoint = jump_origin + move_dir * 240; 
00407     //snap_misc_showpoint(jumptestpoint, "progs/s_light.spr", 3);
00408     
00409     // Could we make a running jump?
00410     traceline(jumptestpoint, jumptestpoint - '0 0 100', true, self);
00411     //snap_misc_showpoint(trace_endpos, "progs/s_light.spr", 3);
00412     if( trace_fraction != 1 )
00413     {
00414         // We can make the running jump...
00415         retval = SNAP_NAV_JMP_RUN;
00416     }
00417 
00418     // Where's the point we need to test?
00419     // For a normal jump...
00420     jumptestpoint = jump_origin + move_dir * 110; 
00421     //snap_misc_showpoint(jumptestpoint, "progs/s_bubble.spr", 3);
00422     
00423     // Could we make a normal jump?
00424     traceline(jumptestpoint, jumptestpoint - '0 0 100', true, self);
00425     //snap_misc_showpoint(trace_endpos, "progs/s_bubble.spr", 3);
00426     if( trace_fraction != 1 )
00427     {
00428         // We can make the normal jump...
00429         retval = SNAP_NAV_JMP_NRM;
00430     }
00431 
00432     return retval;
00433 };
00434 
00435 
00436 // BOT UTILITY FUNCTIONS
00438 
00461 void snap_misc_botspawner()
00462 {
00463     local string tteam;
00464     local float tbot, ttop;
00465  
00466     if( self.state == 0 )
00467     {
00468         if( self.items > 0 )  // at least 1 team
00469         {
00470             //dprint("spawning team 1...\n");
00471             if( self.lip < self.frags )
00472             {
00473                 //dprint("    team 1 member.\n");
00474                 if( teamplay )
00475                 {
00476                     // in teamplay we must get the right name for the team...
00477                     tteam = infokey(world, "ag_team1name");
00478                     tbot = snap_misc_bottomforteamnum(1);
00479                     ttop = snap_misc_topforteamnum(1);
00480                     create_bot(tbot, ttop, tteam, false);
00481                 }
00482                 else
00483                 {
00484                     // in DM we don't need teams...
00485                     // (we only need this test in team 1 as there is only
00486                     // one ``team'' of bots as far as we are concerned in DM)
00487                     tteam = "n/a";
00488                     create_bot(0, 12, tteam, false);
00489                 }
00490                 self.lip = self.lip + 1;
00491             }
00492             else
00493             {
00494                 self.lip = 0;  // reset for next team
00495                 self.state = 1;
00496             }
00497         }
00498         else
00499         {
00500             self.state = 1;
00501         }
00502         self.nextthink = time + 1;
00503     }
00504     else if( self.state == 1 )
00505     {
00506         if( self.items > 1 )  // at least 2 teams
00507         {
00508             //dprint("spawning team 2...\n");
00509             if( self.lip < self.frags )
00510             {
00511                 //dprint("    team 2 member.\n");
00512                 tteam = infokey(world, "ag_team2name");
00513                 tbot = snap_misc_bottomforteamnum(2);
00514                 ttop = snap_misc_topforteamnum(2);
00515                 create_bot(tbot, ttop, tteam, false);
00516                 self.lip = self.lip + 1;
00517             }
00518             else
00519             {
00520                 self.lip = 0;  // reset for next team
00521                 self.state = 2;
00522             }
00523         }
00524         else
00525         {
00526             self.state = 2;
00527         }
00528         self.nextthink = time + 1;
00529     }
00530     else if( self.state == 2 )
00531     {
00532         if( self.items > 2 )  // at least 3 teams
00533         {
00534             //dprint("spawning team 3...\n");
00535             if( self.lip < self.frags )
00536             {
00537                 //dprint("    team 3 member.\n");
00538                 tteam = infokey(world, "ag_team3name");
00539                 tbot = snap_misc_bottomforteamnum(3);
00540                 ttop = snap_misc_topforteamnum(3);
00541                 create_bot(tbot, ttop, tteam, false);
00542                 self.lip = self.lip + 1;
00543             }
00544             else
00545             {
00546                 self.lip = 0;  // reset for next team
00547                 self.state = 3;
00548             }
00549         }
00550         else
00551         {
00552             self.state = 3;
00553         }
00554         self.nextthink = time + 1;
00555     }
00556     else if( self.state == 3 )
00557     {
00558         if( self.items > 3 )  // ooh, four teams!
00559         {
00560             //dprint("spawning team 4...\n");
00561             if( self.lip < self.frags )
00562             {
00563                 //dprint("    team 4 member.\n");
00564                 tteam = infokey(world, "ag_team4name");
00565                 tbot = snap_misc_bottomforteamnum(4);
00566                 ttop = snap_misc_topforteamnum(4);
00567                 create_bot(tbot, ttop, tteam, false);
00568                 self.lip = self.lip + 1;
00569             }
00570             else
00571             {
00572                 // no need to reset for next team
00573                 self.state = 4;
00574             }
00575         }
00576         else
00577         {
00578             self.state = 4;
00579         }
00580         self.nextthink = time + 1;
00581     }
00582     else
00583     {
00584         // Reached state 4 -- remove...
00585         //dprint("About to remove botspawner...\n");
00586         remove(self);
00587     }
00588 }
00589 
00590 
00591 // TEAM MANAGEMENT UTILITY FUNCTIONS
00593 /***
00594     \ingroup team_util
00595 */
00596 float CountPlayers()
00597 {
00598     local entity plr;
00599     local float count;
00600 
00601     plr = find(world, classname, "player");
00602     while( plr != world )
00603     {
00604         if( plr.netname != "" )
00605             count = count + 1;
00606 
00607         plr = find(plr, classname, "player");
00608     }
00609 
00610     return count;
00611 }
00612 
00613 /***
00614     \ingroup team_util
00615 */
00616 float CountPlayersTeam(string team)
00617 {
00618     local entity plr;
00619     local float count;
00620 
00621     plr = find(world, classname, "player");
00622     while( plr != world )
00623     {
00624         if( plr.netname != "" )
00625         if( infokey(plr, "team") == team )
00626             count = count + 1;
00627 
00628         plr = find(plr, classname, "player");
00629     }
00630 
00631     return count;
00632 }
00633 
00645 float snap_misc_pickrndteam(float notmyteam)
00646 {
00647     local float numteams;
00648     local float rnd;
00649     local float okteam;  // allows us to loop if we picked a team
00650                          // that is same as calling client's team
00651                          // when they didn't want us to.
00652 
00653     numteams = stof(infokey(world, "ag_numteams"));
00654 
00655     if( notmyteam )
00656     {
00657         local float myteam;
00658         myteam = snap_misc_numforteamname(infokey(self, "team"));
00659         /*dprint("PRNDT: my team is ");
00660         dprint(ftos(myteam));
00661         dprint("\n");*/
00662     }
00663     
00664     okteam = 0;
00665     while( !okteam )
00666     {
00667         rnd = 1 + ( random() * ( numteams - 1 ) );
00668         rnd = rint(rnd);
00669         /*dprint("PRNDT: rnd team is ");
00670         dprint(ftos(rnd));
00671         dprint("\n");*/
00672 
00673         if( notmyteam )
00674         {
00675             if( rnd == myteam )
00676             {
00677                 //dprint("PRNDT: Not my team!\n");
00678                 okteam = 0;
00679             }
00680             else
00681             {
00682                 //dprint("PRNDT: found a good team.\n");
00683                 okteam = 1;
00684             }
00685         }
00686         else
00687         {
00688             //dprint("PRNDT: keep first team num.\n");
00689             okteam = 1;
00690         }
00691     }
00692 
00693     return rnd;
00694 }
00695 
00703 string (float teamnum) snap_misc_nameforteamnum =
00704 {
00705     if( teamnum == 1 )
00706         return infokey(world, "ag_team1name");
00707     else if( teamnum == 2 )
00708         return infokey(world, "ag_team2name");
00709     else if( teamnum == 3 )
00710         return infokey(world, "ag_team3name");
00711     else if( teamnum == 4 )
00712         return infokey(world, "ag_team4name");
00713     else
00714     {
00715         dprint("ERROR: Invalid team number ", ftos(teamnum), "!\n");
00716         error("snap_misc_nameforteamnum called with invalid team number!\n");
00717     }
00718 }
00719 
00730 float snap_misc_numforteamname(string teamname)
00731 {
00732     local string s_teamname;
00733     local float retval;
00734 
00735     // catch passed-in teamname...
00736     s_teamname = strzone(teamname);
00737 
00738     // compare team...
00739     if ( s_teamname == infokey(world, "ag_team1name") )
00740         retval = 1;
00741     else if ( s_teamname == infokey(world, "ag_team2name") )
00742         retval = 2;
00743     else if ( s_teamname == infokey(world, "ag_team3name") )
00744         retval = 3;
00745     else if ( s_teamname == infokey(world, "ag_team4name") )
00746         retval = 4;
00747     else
00748         retval = 0;
00749 
00750     // be tidy now
00751     strunzone(s_teamname);
00752     
00753     return retval;
00754 }
00755 
00763 float snap_misc_bottomforteamnum(float teamnum)
00764 {
00765     if( teamnum == 1 )
00766         return 4;
00767     else if( teamnum == 2 )
00768         return 13;
00769     else if( teamnum == 3 )
00770         return 12;
00771     else if (teamnum == 4 )
00772         return 3;
00773     else
00774     {
00775         dprint("ERROR: Invalid team number ", ftos(teamnum), "!\n");
00776         error("snap_misc_bottomforteamnum called with invalid team number!\n");
00777     }
00778 }
00779 
00787 float snap_misc_topforteamnum(float teamnum)
00788 {
00789     if( teamnum == 1 )
00790         return 0;
00791     else if( teamnum == 2 )
00792         return 0;
00793     else if( teamnum == 3 )
00794         return 0;
00795     else if( teamnum == 4 )
00796         return 0;
00797     else
00798     {
00799         dprint("ERROR: Invalid team number ", ftos(teamnum), "!\n");
00800         error("snap_misc_bottomforteamnum called with invalid team number!\n");
00801     }
00802 }
00803 
00804 /* $AGRIP-END */

Generated on Tue Jan 1 17:55:54 2008 for AudioQuake QuakeC by  doxygen 1.5.4