SHARE
TWEET

Current 1.0.2 PassTheFlag ReadME

a guest Sep 18th, 2010 107 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* PassTheFlag
  2.  * Copyright (c) 2010 squad.firing@gmail.com
  3.  *
  4.  * Published under version 3 of the GNU LESSER GENERAL PUBLIC LICENSE
  5.  *
  6.  * This package is free software;  you can redistribute it and/or
  7.  * modify it under the terms of the license found in the file
  8.  * named lgpl.txt that should have accompanied this file.
  9.  * Also available at http://www.gnu.org/licenses/lgpl.txt at the time this was created
  10.  *
  11.  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  12.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  13.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  14.  */
  15.  
  16. // PassTheFlag.cpp : a bzfs plugin to enable passing of flags (actually you throw them)
  17. //
  18. // PassTheFlag.cpp written by FiringSquad based loosely on the HTF plugin code by bullet_catcher that came with the BZFlag sources
  19. // Special thanks to mrapple for his help
  20.  
  21.  
  22. #include <assert.h>
  23. #include <stdio.h>
  24. #include <stdarg.h>
  25.  
  26. #include "bzfsAPI.h"
  27.  
  28. // Note: including the following headers will mean that this plugin will not compile under Windows.
  29. // The only other option was modifying the server code to achieve the functionality I needed and that was not really an option.
  30. // Using these headers exposes internal workings of the server that you need to be careful with, so it should not be done lightly.
  31. // It does allow you to do some pretty cool stuff though. :-D
  32. #include "../../src/bzfs/bzfs.h"
  33. #include "../plugin_utils/plugin_utils.h"
  34. #include "BZDBCache.h"
  35. #include "../../src/bzfs/DropGeometry.h"
  36.  
  37.  
  38.  
  39. #define PASSTHEFLAG_VER "1.00.02"
  40.  
  41. #define DbgLevelAlways  1
  42. #define DbgLevelErr     1
  43. #define DbgLevelWarn    2
  44. #define DbgLevelInfo    3
  45. #define DbgLevelExtraInfo       4
  46. //#define DbgLevelDbgInfo       5
  47. #define DbgLevelDbgInfo 1
  48.  
  49. #define kWorkStrLen 255
  50. #define kInvalidPlayerID -1
  51.  
  52. //======================================= FPassHandler ================================================
  53. // Standard interface for communicating with the server
  54.  
  55. class FPassHandler : public bz_EventHandler, public bz_CustomSlashCommandHandler
  56. {
  57. public:
  58.         virtual void process ( bz_EventData *eventData );
  59.         virtual bool handle ( int playerID, bzApiString, bzApiString, bzAPIStringList*);
  60.        
  61. protected:
  62.        
  63. private:
  64. };
  65.  
  66. FPassHandler FlagPassHandler;
  67.  
  68. //======================================= PlayerStats ================================================
  69. // Contains details I need to remember about active players that are not available elsewhere
  70. // It is filled during the bz_ePlayerUpdateEvent, bz_ePlayerSpawnEvent and bz_ePlayerDieEvent
  71.  
  72. class PlayerStats       {
  73.        
  74. public:
  75.        
  76.         int thisPlayerID;
  77.         bz_eTeamType playerTeam;
  78.         bzApiString callsign;
  79.  
  80.         // Stuff I need to remember
  81.         float velocity[3];
  82.         bz_eTeamType KillerTeam;
  83.         int KilledByPlayerID;
  84.        
  85.         void SetStats(int playerID, const float *velocity) {
  86.                 if (velocity && (this->thisPlayerID == playerID))
  87.                         {
  88.                                 memcpy(this->velocity, velocity, sizeof(float[3]));
  89.                         }
  90.         }
  91.  
  92.         void SetKiller(int KillerID, bz_eTeamType KillerTeam) {
  93.                 this->KilledByPlayerID = KillerID;
  94.                 this->KillerTeam = KillerTeam;
  95.         }
  96.        
  97.         void InitialiseData(int playerID = kInvalidPlayerID, bz_eTeamType PlayerTeam = eNoTeam, const float *velocity = NULL, const bzApiString *callsign = NULL, int KillPlayerID = kInvalidPlayerID, bz_eTeamType KillerTeam = eNoTeam) {
  98.                 this->thisPlayerID = playerID;
  99.                 this->playerTeam = PlayerTeam;
  100.                 this->KillerTeam = KillerTeam;
  101.                 this->KilledByPlayerID = KillPlayerID;
  102.                 this->velocity[0] = velocity?velocity[0]:0.0;
  103.                 this->velocity[1] = velocity?velocity[1]:0.0;
  104.                 this->velocity[2] = velocity?velocity[2]:0.0;
  105.                 this->callsign = callsign?*callsign:bzApiString();
  106.         }
  107.        
  108.         PlayerStats(int playerID, bz_eTeamType PlayerTeam, const float *velocity, const bzApiString *callsign) { InitialiseData(playerID, PlayerTeam, velocity, callsign);      };
  109.         PlayerStats(const PlayerStats& inData) {
  110.                 if (this != &inData)
  111.                         {
  112.                                 InitialiseData(inData.thisPlayerID, inData.playerTeam, inData.velocity, &inData.callsign, inData.KilledByPlayerID, inData.KillerTeam);
  113.                         }
  114.         };
  115.         PlayerStats() { InitialiseData(kInvalidPlayerID, eNoTeam, NULL, NULL, kInvalidPlayerID, eNoTeam);       };
  116.        
  117.         PlayerStats& operator=(const PlayerStats& other);
  118.        
  119.         bool operator==(const PlayerStats& other) const;
  120.         bool operator!=(const PlayerStats& other) const { return !(*this == other); }
  121.        
  122. };
  123.  
  124.  
  125.  
  126. // operator ==
  127. inline bool PlayerStats::operator==(const PlayerStats& inData) const
  128. {
  129.         return (thisPlayerID == inData.thisPlayerID);
  130. }
  131.  
  132.  
  133.  
  134. PlayerStats& PlayerStats::operator=(const PlayerStats& other)
  135. {
  136.         if (this != &other)
  137.                 {              
  138.                         InitialiseData(other.thisPlayerID, other.playerTeam, other.velocity, &other.callsign, other.KilledByPlayerID, other.KillerTeam);
  139.                 }
  140.         return *this;
  141. }
  142.  
  143.  
  144. // List of active players along with their recorded information
  145. // Players are added during the bz_ePlayerJoinEvent
  146. // and removed after a bz_ePlayerPartEvent
  147.  
  148. std::vector <PlayerStats> gActivePlayers;
  149.  
  150. //======================================= PassDetails ================================================
  151. // Contains all the information we need in order to calculate the pass
  152. // There are some times when a flag is dropped that we want to ignore
  153. // The problem is that the client first sends the flagdrop message and later sends the reason
  154. // We therefore need to remember that the flag was dropped and check later if we need to send it flying anywhere
  155.  
  156. #define kDefault_MaxWaitForReason       0.7f
  157.  
  158. class DropEvent {
  159.        
  160. public:
  161.        
  162.         float TimeEventOccurred;
  163.         int PlayerThatDroppedTheFlag;
  164.         int DroppedFlagID;
  165.         float DropPos[3];
  166.         float PlayerPosAtThisTime[3];
  167.         float PlayerVelocityAtThisTime[3];
  168.        
  169.         void InitialiseData(int playerID = kInvalidPlayerID, int flagID = -1, const float *DropPos = NULL, const float *PlayerPosAtThisTime = NULL, const float *PlayerVelocityAtThisTime = NULL,  float EventTime = 0.0)
  170.                 {
  171.                         this->PlayerThatDroppedTheFlag = playerID;
  172.                         this->DroppedFlagID = flagID;
  173.                         this->TimeEventOccurred = EventTime;
  174.                         this->DropPos[0] = DropPos?DropPos[0]:0.0;
  175.                         this->DropPos[1] = DropPos?DropPos[1]:0.0;
  176.                         this->DropPos[2] = DropPos?DropPos[2]:0.0;
  177.                         this->PlayerPosAtThisTime[0] = PlayerPosAtThisTime?PlayerPosAtThisTime[0]:0.0;
  178.                         this->PlayerPosAtThisTime[1] = PlayerPosAtThisTime?PlayerPosAtThisTime[1]:0.0;
  179.                         this->PlayerPosAtThisTime[2] = PlayerPosAtThisTime?PlayerPosAtThisTime[2]:0.0;
  180.                         this->PlayerVelocityAtThisTime[0] = PlayerVelocityAtThisTime?PlayerVelocityAtThisTime[0]:0.0;
  181.                         this->PlayerVelocityAtThisTime[1] = PlayerVelocityAtThisTime?PlayerVelocityAtThisTime[1]:0.0;
  182.                         this->PlayerVelocityAtThisTime[2] = PlayerVelocityAtThisTime?PlayerVelocityAtThisTime[2]:0.0;
  183.                 }
  184.        
  185.         DropEvent(int playerID, int flagID, const float *DropPos, const float *PlayerPosAtThisTime, const float *PlayerVelocityAtThisTime) { InitialiseData(playerID, flagID, DropPos, PlayerPosAtThisTime, PlayerVelocityAtThisTime,TimeKeeper::getCurrent().getSeconds());    };
  186.         DropEvent(const DropEvent& inData) {
  187.                 if (this != &inData)
  188.                         {
  189.                                 InitialiseData(inData.PlayerThatDroppedTheFlag, inData.DroppedFlagID, inData.DropPos, inData.PlayerPosAtThisTime, inData.PlayerVelocityAtThisTime, inData.TimeEventOccurred);
  190.                         }
  191.         };
  192.         DropEvent() { InitialiseData(); };
  193.        
  194.         DropEvent& operator=(const DropEvent& other);
  195.        
  196.         bool operator==(const DropEvent& other) const;
  197.         bool operator!=(const DropEvent& other) const { return !(*this == other); }
  198.        
  199. };
  200.  
  201.  
  202.  
  203. // operator ==
  204. inline bool DropEvent::operator==(const DropEvent& inData) const
  205. {
  206.         return (PlayerThatDroppedTheFlag == inData.PlayerThatDroppedTheFlag);
  207. }
  208.  
  209.  
  210.  
  211. DropEvent& DropEvent::operator=(const DropEvent& other)
  212. {
  213.         if (this != &other)
  214.                 {              
  215.                         InitialiseData(other.PlayerThatDroppedTheFlag, other.DroppedFlagID, other.DropPos, other.PlayerPosAtThisTime, other.PlayerVelocityAtThisTime, other.TimeEventOccurred);
  216.                 }
  217.         return *this;
  218. }
  219.  
  220.  
  221. // List of pending drop events
  222.  
  223. std::vector <DropEvent> gPendingDropEvents;
  224.  
  225.  
  226.  
  227. //=======================================================================================
  228.  
  229. enum tFumbleMsgOption {
  230.         kFMO_NoMessages,
  231.         kFMO_TellEveryone,
  232.         kFMO_TellPlayer,
  233.         kFMO_MaxVal             // Never used as an option, just as a counter
  234. };
  235.  
  236.  
  237. const char *kFumbleMsgSettingDesc[kFMO_MaxVal]  = {
  238.         "No Fumble Messages",
  239.         "Tell everbody about fumbles",
  240.         "only inform the player that fumbled"
  241. };
  242.  
  243.  
  244. enum tPassOnDeathOption {
  245.         kPOD_No,
  246.         kPOD_Yes,
  247.         kPOD_Hurts,
  248.         kPOD_MaxVal             // Never used as an option, just as a counter
  249. };
  250.  
  251. const char *kPassOnDeathSettingDesc[kPOD_MaxVal]  = {
  252. "Flag drops without being passed",
  253. "Flag flies in direction tank was moving",
  254. "Flag holder gets punished in accordance with \"hurt\""
  255. };
  256.  
  257.  
  258. enum tPassOption {
  259.         kPassing_On,
  260.         kPassing_Off,
  261.         kPassing_Immediate,
  262.         kPassing_MaxVal         // Never used as an option, just as a counter
  263. };
  264.  
  265. const char *kPassOptionDesc[kPassing_MaxVal]  = {
  266. "Activated",
  267. "Disabled",
  268. "Immediate (No fancy stuff - let the flag fly)"
  269. };
  270.  
  271.  
  272. enum tHurtingPassOption {
  273.         kHPO_ToKiller,
  274.         kHPO_ToNonTeamKiller,
  275.         kHPO_MaxVal             // Never used as an option, just as a counter
  276. };
  277.  
  278. const char *kHurtSettingDesc[kHPO_MaxVal]  = {
  279. "Flag flies in direction of killer",
  280. "Flag flies in direction of killer unless it was a TK"
  281. };
  282.  
  283.  
  284. #define kMaxFumbledPassMessages         5
  285. const char *kFumbledPassMessages[kMaxFumbledPassMessages]  = {
  286.         "Woops! You need to be more careful passing",
  287.         "You fumbled that pass!",
  288.         "Watch where you're throwing that flag! Fumble!",
  289.         "You tried to send flag where it can't go. Silly!",
  290.         "I hope you shoot better than you pass."
  291. };
  292.  
  293.  
  294. //====================================== Configurable Options =================================================
  295.  
  296. tPassOption FPassEnabled = kPassing_On;
  297. tFumbleMsgOption FumbleMsg = kFMO_TellPlayer;
  298. tPassOnDeathOption PassOnDeath = kPOD_No;
  299. tHurtingPassOption HurtOption = kHPO_ToNonTeamKiller;
  300. bool PassAllFlags = true;
  301. float FPassThrowDistance = 6.0;
  302. int MaxSafeZoneTests = 5;
  303.  
  304. float MaxWaitForReason = kDefault_MaxWaitForReason;
  305.  
  306. // Reset Values
  307. #define AssignResetVal(ConfigVal) ResetVal_##ConfigVal = ConfigVal
  308. #define ResetTheValue(ConfigVal) ConfigVal = ResetVal_##ConfigVal
  309.  
  310. tPassOption AssignResetVal(FPassEnabled);
  311. tFumbleMsgOption AssignResetVal(FumbleMsg);
  312. tPassOnDeathOption AssignResetVal(PassOnDeath);
  313. tHurtingPassOption AssignResetVal(HurtOption);
  314. bool AssignResetVal(PassAllFlags);
  315. float AssignResetVal(FPassThrowDistance);
  316. int AssignResetVal(MaxSafeZoneTests);
  317.  
  318. float AssignResetVal(MaxWaitForReason);
  319.  
  320. bool AllowMaxWaitMod = false;
  321.  
  322. //====================================== PlayerStats Utils =================================================
  323.  
  324.  
  325. // Return the PlayerStats information for player PlayerID
  326. PlayerStats *GetActivePlayerStatsByID(int PlayerID)
  327. {
  328.         static PlayerStats UnKnown;
  329.         UnKnown.InitialiseData();
  330.        
  331.         for(unsigned int i=0;i<gActivePlayers.size();i++)
  332.                 {
  333.                         if (gActivePlayers[i].thisPlayerID == PlayerID)
  334.                                 {
  335.                                         return &gActivePlayers[i];
  336.                                 }
  337.                 }
  338.         return &UnKnown;
  339. }
  340.  
  341.  
  342. // Locate PlayerStats information for player PlayerID in the gActivePlayers list and remove it
  343. bool RemovePlayerStatsForPlayerID(int PlayerID)
  344. {
  345.         std::vector<PlayerStats>::iterator iter = gActivePlayers.begin();
  346.         while( iter != gActivePlayers.end() )
  347.                 {
  348.                         if (iter->thisPlayerID == PlayerID)
  349.                                 {
  350.                                         iter = gActivePlayers.erase( iter );
  351.                                         return true;
  352.                                 }
  353.                         else
  354.                                 ++iter;
  355.                 }
  356.         return false;
  357. }
  358.  
  359.  
  360. //================================= fpass command utils ======================================================
  361.  
  362.  
  363.  
  364. // Get the current value for velocity I have for this player
  365. bool getPlayerVelocity(int playerID, float vel[3])
  366. {
  367.         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(playerID);
  368.         memcpy(vel, StatsForThisPlayer->velocity, sizeof(float[3]));
  369.         return (StatsForThisPlayer->thisPlayerID == playerID);
  370. }
  371.  
  372.  
  373.  
  374. // Get the current value for velocity I have for this player
  375. bool getPlayerKiller(int playerID, bz_eTeamType &playerTeam, int &KillerID, bz_eTeamType &KillerTeam)
  376. {
  377.         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(playerID);
  378.         playerTeam = StatsForThisPlayer->playerTeam;
  379.         KillerID = StatsForThisPlayer->KilledByPlayerID;
  380.         KillerTeam = StatsForThisPlayer->KillerTeam;
  381.         return (StatsForThisPlayer->thisPlayerID == playerID);
  382. }
  383.  
  384.  
  385.  
  386. // Ask the server for the callsign for this player
  387. bzApiString &getPlayerCallsign(int playerID)
  388. {
  389.         static bzApiString UnknownPlayer("some unknown player");
  390.         bz_PlayerRecord* player = bz_getPlayerByIndex(playerID);
  391.         if (player) {
  392.                 return player->callsign;
  393.         }
  394.         return UnknownPlayer;
  395. }
  396.  
  397.  
  398.  
  399. // Ask the server for the location for this player
  400. bool getPlayerPosition(int playerID, float PlayerPos[3])
  401. {
  402.         bz_PlayerRecord* player = bz_getPlayerByIndex(playerID);
  403.         if (!player) {
  404.                 return false;
  405.         }
  406.         memcpy(PlayerPos, player->pos, sizeof(float[3]));
  407.         return true;
  408. }
  409.  
  410.  
  411.  
  412. // Ask the server if this player is an Admin
  413. bool playerIsAdmin(int playerID)
  414. {
  415.         bz_PlayerRecord* player = bz_getPlayerByIndex(playerID);
  416.         if (!player) {
  417.                 return false;
  418.         }
  419.         return player->admin;
  420. }
  421.  
  422.  
  423. // Check if this player has the appropriate permission to perform the command
  424. bool checkPerms (int playerID, const char *FPassCmd, const char *permName)
  425. {
  426.         bool HasPerm = false;
  427.         return true;//zxcv
  428.         if ('\0' == *permName)  // Needs Admin
  429.                 HasPerm = playerIsAdmin (playerID);
  430.         else
  431.                 HasPerm = bz_hasPerm (playerID, permName);
  432.         if (!HasPerm)
  433.                 bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "you need \"%s\" permission to do /FPass %s", *permName?permName:"Admin", FPassCmd);
  434.         return HasPerm;
  435. }
  436.  
  437.  
  438. //================================= fpass command responses ======================================================
  439.  
  440.  
  441. // Send command format
  442. void sendHelp (int who)
  443. {
  444.         bz_sendTextMessage(BZ_SERVER, who, "FPass commands: [help|stat|off|on|immediate|reset|allflags=[on|off]...");
  445.         bz_sendTextMessage(BZ_SERVER, who, "   ...|dist=< 0.0 .. 20.0>|steps=<0 .. 20>...|fmsg=[off|all|player]...");
  446.         bz_sendTextMessage(BZ_SERVER, who, "   ...|passondeath=[on|off|hurts]|hurt=[killr|nontker]");
  447. }
  448.  
  449.  
  450. // Send Details about setting MaxWaitForReason
  451. void sendMaxWaitMsg (int who)
  452. {
  453.         bz_sendTextMessagef(BZ_SERVER, who, "FPass Maxwait Variable: e.g. \"/fpass maxwait=0.1\" : Valid Range (0.0 .. 3.0) : Current value is %f editing is %s", MaxWaitForReason, AllowMaxWaitMod?"allowed":"disabled");
  454. }
  455.  
  456.  
  457.  
  458.  
  459. // Reset All Configurable Variable back to their values at launchplugin time
  460. void ResetAllVariables (int who)
  461. {
  462.         char msg[kWorkStrLen];
  463.         const char *PlayerName;
  464.  
  465.         if (kInvalidPlayerID == who)
  466.                 return;
  467.        
  468.         ResetTheValue(FPassEnabled);
  469.         ResetTheValue(FumbleMsg);
  470.         ResetTheValue(PassOnDeath);
  471.         ResetTheValue(HurtOption);
  472.         ResetTheValue(PassAllFlags);
  473.         ResetTheValue(FPassThrowDistance);
  474.         ResetTheValue(MaxSafeZoneTests);
  475.         ResetTheValue(MaxWaitForReason);
  476.  
  477.         //bz_setMaxWaitTime (MaxWaitForReason);
  478.  
  479.         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
  480.         if (StatsForThisPlayer->thisPlayerID == who)
  481.                 PlayerName = StatsForThisPlayer->callsign.c_str();
  482.         else
  483.                 PlayerName = getPlayerCallsign(who).c_str();
  484.         snprintf (msg, kWorkStrLen, "*** Flag Passing variables reset by %s", PlayerName);
  485.         bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
  486. }
  487.  
  488.  
  489. // Show current settings
  490. void FPassStats (int who)
  491. {
  492.         bz_sendTextMessagef(BZ_SERVER, who, "FPass plugin version %s", PASSTHEFLAG_VER);
  493.         bz_sendTextMessagef(BZ_SERVER, who,  "  Flag Passing is %s" , kPassOptionDesc[(int) PassOnDeath]);
  494.         bz_sendTextMessagef(BZ_SERVER, who,  "  Flag Throw Distance: %f" , FPassThrowDistance);
  495.         bz_sendTextMessagef(BZ_SERVER, who,  "  Max Attempts to land flag: %d" , MaxSafeZoneTests);
  496.         bz_sendTextMessagef(BZ_SERVER, who,  "  Fumble Messages are set to \"%s\"" , kFumbleMsgSettingDesc[(int) FumbleMsg]);
  497.         bz_sendTextMessagef(BZ_SERVER, who,  "  Passing of non-team flags is turned %s" , PassAllFlags ? "ON":"OFF");
  498.         bz_sendTextMessagef(BZ_SERVER, who,  "  Passing on Death set to \"%s\"" , kPassOnDeathSettingDesc[(int) PassOnDeath]);
  499.         bz_sendTextMessagef(BZ_SERVER, who,  "  Current \"hurt\" option is \"%s\"" , kHurtSettingDesc[(int) HurtOption]);
  500. }
  501.  
  502.  
  503. // Send details about the PassTheFlag plugin
  504. void FPassSendDesc (int who)
  505. {
  506.         bz_sendTextMessage(BZ_SERVER, who, "PassTheFlag plugin allows the user to throw the flag they are currently holding.");
  507.         bz_sendTextMessage(BZ_SERVER, who, "Essentially the flag flies in the direction you are traveling and the faster you");
  508.         bz_sendTextMessage(BZ_SERVER, who, "go the further it flies");
  509.         bz_sendTextMessage(BZ_SERVER, who, "Jumping effects the distance too. If you are going up it travels twice as far,");
  510.         bz_sendTextMessage(BZ_SERVER, who, "and if you are falling it travels half as far.");
  511.         bz_sendTextMessage(BZ_SERVER, who, "A fumble occurs when you try to pass a flag to an unsafe location.");
  512.         bz_sendTextMessage(BZ_SERVER, who, "For further information, check out the README.txt file accompanying the source.");
  513.         bz_sendTextMessage(BZ_SERVER, who, "You need COUNTDOWN privileges to turn it ON/OFF.");
  514.         bz_sendTextMessage(BZ_SERVER, who, "You need to be an Admin to change other settings.");
  515.         bz_sendTextMessage(BZ_SERVER, who, "\"/fpass help\" and \"/fpass stat\" are available to all.");
  516.         bz_sendTextMessage(BZ_SERVER, who, "Current Settings:");
  517.         FPassStats(who);
  518.         bz_sendTextMessage(BZ_SERVER, who, "Command options:");
  519.         sendHelp(who);
  520. }
  521.  
  522.  
  523.  
  524. // Check if the flag can be dropped at dropPos[] and return true if safe
  525. // landing[] will contain the eventual location where the flag would end up if dropped
  526. bool do_checkFlagDropAtPoint ( int flagID, float dropPos[3], float landing[3] )
  527. {
  528.         assert(world != NULL);
  529.        
  530.         const float size = BZDBCache::worldSize * 0.5f;
  531.         float pos[3];
  532.         pos[0] = ((dropPos[0] < -size) || (dropPos[0] > size)) ? 0.0f : dropPos[0];
  533.         pos[1] = ((dropPos[1] < -size) || (dropPos[1] > size)) ? 0.0f : dropPos[1];
  534.         pos[2] = dropPos[2];            // maxWorldHeight should not be a problem since the flag can not be sent above the "passer"
  535.        
  536.         FlagInfo& thisFlag = *FlagInfo::get(flagID);
  537.         int flagTeam = thisFlag.flag.type->flagTeam;
  538.        
  539.         const float waterLevel = world->getWaterLevel();
  540.         float minZ = 0.0f;
  541.         if (waterLevel > minZ) {
  542.                 minZ = waterLevel;
  543.         }
  544.         const float maxZ = MAXFLOAT;
  545.        
  546.         landing[0] = pos[0];
  547.         landing[1] = pos[1];
  548.         landing[2] = pos[2];
  549.         bool safelyDropped = DropGeometry::dropTeamFlag(landing, minZ, maxZ, flagTeam);         // Pretend we are dropping the team flag
  550.        
  551.         return safelyDropped;
  552. }
  553.  
  554.  
  555.  
  556.  
  557. // Turn passing on/off
  558. void FPassEnable (tPassOption PassingOption, int who)
  559. {
  560.         char msg[kWorkStrLen];
  561.         const char *PlayerName;
  562.         if (PassingOption == FPassEnabled){
  563.                 bz_sendTextMessage(BZ_SERVER, who, "Flag Passing is already that way.");
  564.                 return;
  565.         }
  566.         FPassEnabled = PassingOption;
  567.         if (kInvalidPlayerID == who)
  568.                 return;
  569.         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
  570.         if (StatsForThisPlayer->thisPlayerID == who)
  571.                 PlayerName = StatsForThisPlayer->callsign.c_str();
  572.         else
  573.                 PlayerName = getPlayerCallsign(who).c_str();
  574.         snprintf (msg, kWorkStrLen, "*** Flag Passing set to %s by %s",  kPassOptionDesc[(int) FPassEnabled], PlayerName);
  575.         bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
  576. }
  577.  
  578.  
  579. // Set the PassingOnDeath option
  580. void SetPassingOnDeathOption (tPassOnDeathOption PassingOption, int who)
  581. {
  582.         char msg[kWorkStrLen];
  583.         const char *PlayerName;
  584.         if (PassingOption == PassOnDeath){
  585.                 bz_sendTextMessage(BZ_SERVER, who, "Flag Passing on death is already that way.");
  586.                 return;
  587.         }
  588.         PassOnDeath = PassingOption;
  589.         if (kInvalidPlayerID == who)
  590.                 return;
  591.         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
  592.         if (StatsForThisPlayer->thisPlayerID == who)
  593.                 PlayerName = StatsForThisPlayer->callsign.c_str();
  594.         else
  595.                 PlayerName = getPlayerCallsign(who).c_str();
  596.         snprintf (msg, kWorkStrLen, "*** Passing on death set to %s by %s", kPassOnDeathSettingDesc[(int) PassingOption], PlayerName);
  597.         bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
  598. }
  599.  
  600.  
  601.  
  602. // Set the Hurt option
  603. void SetHurtingOption (tHurtingPassOption HurtingOption, int who)
  604. {
  605.         char msg[kWorkStrLen];
  606.         const char *PlayerName;
  607.         if (HurtingOption == HurtOption){
  608.                 bz_sendTextMessage(BZ_SERVER, who, "Hurting option is already that way.");
  609.                 return;
  610.         }
  611.         HurtOption = HurtingOption;
  612.         if (kInvalidPlayerID == who)
  613.                 return;
  614.         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
  615.         if (StatsForThisPlayer->thisPlayerID == who)
  616.                 PlayerName = StatsForThisPlayer->callsign.c_str();
  617.         else
  618.                 PlayerName = getPlayerCallsign(who).c_str();
  619.         snprintf (msg, kWorkStrLen, "*** Hurting option set to %s by %s", kHurtSettingDesc[(int) HurtingOption], PlayerName);
  620.         bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
  621. }
  622.  
  623.  
  624.  
  625.  
  626.  
  627. // Set the Fumble Message option
  628. void FumbleMsgEnable (tFumbleMsgOption MsgOption, int who)
  629. {
  630.         char msg[kWorkStrLen];
  631.         const char *PlayerName;
  632.         if (MsgOption == FumbleMsg){
  633.                 bz_sendTextMessage(BZ_SERVER, who, "Fumble Messaging is already that way.");
  634.                 return;
  635.         }
  636.         FumbleMsg = MsgOption;
  637.         if (kInvalidPlayerID == who)
  638.                 return;
  639.         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
  640.         if (StatsForThisPlayer->thisPlayerID == who)
  641.                 PlayerName = StatsForThisPlayer->callsign.c_str();
  642.         else
  643.                 PlayerName = getPlayerCallsign(who).c_str();
  644.         snprintf (msg, kWorkStrLen, "*** Fumble Messages changed to \"%s\" by %s", kFumbleMsgSettingDesc[(int) MsgOption], PlayerName);
  645.         bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
  646. }
  647.  
  648.  
  649.  
  650.  
  651.  
  652. // Set the option to pass only Team flags or all flags
  653. void AllFlagsEnable (bool onoff, int who)
  654. {
  655.         char msg[kWorkStrLen];
  656.         const char *PlayerName;
  657.         if (onoff == PassAllFlags){
  658.                 bz_sendTextMessage(BZ_SERVER, who, "Flags effected are already that way.");
  659.                 return;
  660.         }
  661.         PassAllFlags = onoff;
  662.         if (kInvalidPlayerID == who)
  663.                 return;
  664.         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
  665.         if (StatsForThisPlayer->thisPlayerID == who)
  666.                 PlayerName = StatsForThisPlayer->callsign.c_str();
  667.         else
  668.                 PlayerName = getPlayerCallsign(who).c_str();
  669.         snprintf (msg, kWorkStrLen, "*** Flag passing for non-team flags was turned %s by %s", onoff?"ON":"OFF", PlayerName);
  670.         bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
  671. }
  672.  
  673.  
  674.  
  675. // Set the "dist=" value
  676. bool SetThrowDistance(const char *FloatStr, int *CharsUsed)
  677. {
  678.         float FloatVal = 0.0;
  679.         char *EndOfNum = (char *) FloatStr;
  680.         FloatVal = strtof (FloatStr, &EndOfNum);
  681.         if (EndOfNum == FloatStr)
  682.                 return false;
  683.         if (CharsUsed)
  684.                 *CharsUsed = (EndOfNum - FloatStr);
  685.         if ((0.0 >= FloatVal) || (20.0 <= FloatVal))
  686.                 return false;
  687.         bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "PassTheFlag: Flag Throw Distance: Chaged from %f to %f", FPassThrowDistance, FloatVal); fflush (stdout);
  688.         FPassThrowDistance = FloatVal;
  689.         return true;
  690. }
  691.  
  692.  
  693.  
  694. // Set the maxwait value
  695. bool SetMaxWaitVal(const char *FloatStr, int *CharsUsed)
  696. {
  697.         float FloatVal = 0.0;
  698.         char *EndOfNum = (char *) FloatStr;
  699.         FloatVal = strtof (FloatStr, &EndOfNum);
  700.         if (EndOfNum == FloatStr)
  701.                 return false;
  702.         if (CharsUsed)
  703.                 *CharsUsed = (EndOfNum - FloatStr);
  704.         if ((0.0 >= FloatVal) || (3.0 <= FloatVal))
  705.                 return false;
  706.         MaxWaitForReason = FloatVal;
  707.         //bz_setMaxWaitTime (MaxWaitForReason);
  708.         return true;
  709. }
  710.  
  711.  
  712. // Set the "steps=" value
  713. bool SetMaxIterations(const char *IntStr, int *CharsUsed)
  714. {
  715.         int IntVal = 0;
  716.         char *EndOfNum = (char *) IntStr;
  717.         IntVal = strtol (IntStr, &EndOfNum, 10);
  718.         if (EndOfNum == IntStr)
  719.                 return false;
  720.         if (CharsUsed)
  721.                 *CharsUsed = (EndOfNum - IntStr);
  722.         if ((0 >= IntVal) || (20 <= IntVal))
  723.                 return false;
  724.         bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "PassTheFlag: Max Attempts to land flag: Chaged from %d to %d", MaxSafeZoneTests, IntVal);
  725.         MaxSafeZoneTests = IntVal;
  726.         return true;
  727. }
  728.  
  729.  
  730.  
  731.  
  732. //================================= Process this drop event ======================================================
  733.  
  734.  
  735. void ProcessDropEvent(DropEvent &PendingDropEvent)
  736. {
  737.         bool NeedToCalculateLandingPos = true;
  738.         bool ValidFlagThrow = false;;
  739.         float FlagLandingPos[3];
  740.         GameKeeper::Player *playerData = GameKeeper::Player::getPlayerByIndex(PendingDropEvent.PlayerThatDroppedTheFlag);
  741.        
  742.         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (!playerData)"); fflush (stdout);
  743.         if (!playerData)
  744.                 return;         // player not known
  745.         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (playerData->isParting)"); fflush (stdout);
  746.         if (playerData->isParting)
  747.                 return;         // Player is being kicked - Just handle as a normal drop
  748.         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (!playerData->player.isHuman())"); fflush (stdout);
  749.         if (!playerData->player.isHuman())
  750.                 return;         // Not for this plugin to handle
  751.         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (playerData->player.isPaused())"); fflush (stdout);
  752.         if (playerData->player.isPaused())
  753.                 return;         // Dropped due to pause
  754.         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (!playerData->player.isAlive())"); fflush (stdout);
  755.         if (!playerData->player.isAlive())
  756.                 {
  757.                         // Player Died - so there might be some special things to do
  758.                         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (kPOD_No == PassOnDeath)"); fflush (stdout);
  759.                         if (kPOD_No == PassOnDeath)
  760.                                 return;
  761.                         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (kPOD_Hurts == PassOnDeath)"); fflush (stdout);
  762.                         if (kPOD_Hurts == PassOnDeath)
  763.                                 {
  764.                                         // Find out how player died
  765.                                         int                             KillerID;
  766.                                         bz_eTeamType    KillerTeam;
  767.                                         bz_eTeamType    playerTeam;
  768.                                         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (getPlayerKiller)"); fflush (stdout);
  769.                                         if (!getPlayerKiller(PendingDropEvent.PlayerThatDroppedTheFlag, playerTeam, KillerID, KillerTeam))
  770.                                                 return;         // Not a standard kill, so just drop the flag
  771.                                         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent ((eNoTeam == KillerTeam) || (kInvalidPlayerID == KillerID) || (eNoTeam == playerTeam) || (kInvalidPlayerID == PendingDropEvent.PlayerThatDroppedTheFlag))"); fflush (stdout);
  772.                                         if ((eNoTeam == KillerTeam) || (kInvalidPlayerID == KillerID) || (eNoTeam == playerTeam) || (kInvalidPlayerID == PendingDropEvent.PlayerThatDroppedTheFlag))
  773.                                                 return;         // Not a standard kill, so just drop the flag
  774.                                         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (kHPO_ToNonTeamKiller == HurtOption)"); fflush (stdout);
  775.                                         if (kHPO_ToNonTeamKiller == HurtOption)
  776.                                                 if (playerTeam == KillerTeam)
  777.                                                         return;         // Just drop it, it was a TK
  778.                                         bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (kHPO_ToKiller == HurtOption)"); fflush (stdout);
  779.                                         if (kHPO_ToKiller == HurtOption)
  780.                                                 {
  781.                                                         float FlagDropPos[3];
  782.                                                         if (getPlayerPosition(KillerID, FlagDropPos))
  783.                                                                 {
  784.                                                                         bz_debugMessagef(DbgLevelDbgInfo, "             KillerPos(HurtOption): %f, %f, %f", FlagDropPos[0], FlagDropPos[1], FlagDropPos[2]); fflush (stdout);
  785.                                                                 }
  786.                                                         else
  787.                                                                 {
  788.                                                                         bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: KillerPos(HurtOption): ERR"); fflush (stdout);
  789.                                                                         return;
  790.                                                                 }
  791.                                                         ValidFlagThrow = do_checkFlagDropAtPoint(PendingDropEvent.DroppedFlagID, FlagDropPos, FlagLandingPos);
  792.                                                         if (!ValidFlagThrow)
  793.                                                                 return;         // Killer is not in a safe location for a flag
  794.                                                         NeedToCalculateLandingPos = false;
  795.                                                 }
  796.                                 }
  797.                         // kPOD_Yes is active so just let things continue
  798.                 }
  799.        
  800.         if (NeedToCalculateLandingPos)
  801.                 {
  802.                         float FlagDropPos[3];
  803.                        
  804.                         float JumpBoost = 1.0;
  805.                         if (PendingDropEvent.PlayerVelocityAtThisTime[2]>0.0)
  806.                                 JumpBoost = 2.0;
  807.                         else
  808.                                 if (PendingDropEvent.PlayerVelocityAtThisTime[2]<0.0)
  809.                                         JumpBoost = 0.5;
  810.                         FlagDropPos[0] = PendingDropEvent.PlayerPosAtThisTime[0] + FPassThrowDistance * PendingDropEvent.PlayerVelocityAtThisTime[0] * JumpBoost;
  811.                         FlagDropPos[1] = PendingDropEvent.PlayerPosAtThisTime[1] + FPassThrowDistance * PendingDropEvent.PlayerVelocityAtThisTime[1] * JumpBoost;
  812.                         FlagDropPos[2] = PendingDropEvent.DropPos[2];
  813.                         bool PassWasFumbled = false;
  814.                         int TriesLeft = MaxSafeZoneTests;
  815.                         float DeltaX, DeltaY ;
  816.                         DeltaX = DeltaY = 0.0;
  817.                         if (0 < MaxSafeZoneTests)
  818.                                 {
  819.                                         DeltaX = (PendingDropEvent.PlayerPosAtThisTime[0] - FlagDropPos[0])/MaxSafeZoneTests;
  820.                                         DeltaY = (PendingDropEvent.PlayerPosAtThisTime[1] - FlagDropPos[1])/MaxSafeZoneTests;
  821.                                 }
  822.                         do
  823.                                 {
  824.                                         ValidFlagThrow = do_checkFlagDropAtPoint(PendingDropEvent.DroppedFlagID, FlagDropPos, FlagLandingPos);
  825.                                         // Check for flags that were left up high
  826.                                         if (ValidFlagThrow)
  827.                                                 ValidFlagThrow = FlagLandingPos[2] <= FlagDropPos[2];
  828.                                         // Check for flags that need to be moved
  829.                                         if (ValidFlagThrow)
  830.                                                 ValidFlagThrow = (FlagLandingPos[0] == FlagDropPos[0]) && (FlagLandingPos[1] == FlagDropPos[1]);                // Perhaps we should allow a tolerance here
  831.                                         if (!PassWasFumbled)
  832.                                                 PassWasFumbled = !ValidFlagThrow;
  833.                                         TriesLeft--;
  834.                                         if ((!ValidFlagThrow) && (TriesLeft >= 0))
  835.                                                 {
  836.                                                         FlagDropPos[0] += DeltaX;
  837.                                                         FlagDropPos[1] += DeltaY;
  838.                                                 }
  839.                                 }
  840.                         while ((!ValidFlagThrow) && (TriesLeft >= 0));
  841.                         if (PassWasFumbled && ValidFlagThrow)
  842.                                 {
  843.                                         if (kFMO_TellEveryone == FumbleMsg)
  844.                                                 {
  845.                                                         bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "%s fumbled the pass.", GetActivePlayerStatsByID(PendingDropEvent.PlayerThatDroppedTheFlag)->callsign.c_str());
  846.                                                 }
  847.                                         else if (kFMO_TellPlayer == FumbleMsg)
  848.                                                 {
  849.                                                         int randomMsg = rand() % kMaxFumbledPassMessages;      
  850.                                                         bz_sendTextMessagef(BZ_SERVER, PendingDropEvent.PlayerThatDroppedTheFlag, kFumbledPassMessages[randomMsg]);
  851.                                                 }
  852.                                 }
  853.                 }
  854.         if (ValidFlagThrow)
  855.                 {
  856.                         FlagInfo& flag = *FlagInfo::get(PendingDropEvent.DroppedFlagID);
  857.                        
  858.                         flag.dropFlag(PendingDropEvent.DropPos, FlagLandingPos, false);
  859.                         sendDrop(flag);
  860.                         sendFlagUpdate(flag);
  861.                         bz_debugMessagef(DbgLevelDbgInfo, "             FlagLandingPos:  %f, %f, %f", FlagLandingPos[0], FlagLandingPos[1], FlagLandingPos[2]); fflush (stdout);
  862.                 }
  863. }
  864.  
  865.  
  866. // Locate any pending drop events for player PlayerID and process them
  867. // Written to handle more than one, although since we call this on bz_eFlagGrabbedEvent it should not be possible
  868. void ProcessPendingEventsForPlayer(int PlayerID)
  869. {
  870.         bz_debugMessagef(DbgLevelDbgInfo, "ProcessPendingEventsForPlayer: Looking for=%d", PlayerID); fflush (stdout);
  871.         std::vector<DropEvent>::iterator iter = gPendingDropEvents.begin();
  872.         while( iter != gPendingDropEvents.end() )
  873.                 {
  874.                         if (iter->PlayerThatDroppedTheFlag == PlayerID)
  875.                                 {
  876.                                         bz_debugMessagef(DbgLevelDbgInfo, "ProcessPendingEventsForPlayer: found PlayerThatDroppedTheFlag=%d", iter->PlayerThatDroppedTheFlag); fflush (stdout);
  877.                                         ProcessDropEvent( *iter );
  878.                                         iter = gPendingDropEvents.erase( iter );
  879.                                 }
  880.                         else
  881.                                 ++iter;
  882.                 }
  883. }
  884.  
  885.  
  886.  
  887. // If the user has a bad connection or is NR then we want to get rid of any drop events they have pending
  888. void RemoveOldEvents(float CurrentTime)
  889. {
  890.         std::vector<DropEvent>::iterator iter = gPendingDropEvents.begin();
  891.         while( iter != gPendingDropEvents.end() )
  892.                 {
  893.                         if ((CurrentTime - iter->TimeEventOccurred) > MaxWaitForReason)
  894.                                 {
  895.                                         bz_debugMessagef(DbgLevelDbgInfo, "RemoveOldEvents: PlayerThatDroppedTheFlag=%d EvtTime=%f CurTime=%f diff=%f MaxWaitForReason=%f", iter->PlayerThatDroppedTheFlag, iter->TimeEventOccurred, CurrentTime, CurrentTime - iter->TimeEventOccurred, MaxWaitForReason); fflush (stdout);
  896.                                         if (AllowMaxWaitMod)
  897.                                                 {
  898.                                                         // Give some feedback to allow some tweeking
  899.                                                         bz_sendTextMessagef(BZ_SERVER, iter->PlayerThatDroppedTheFlag, "Pass ignored! Your client took too long to respond. I waited %.3f seconds.", CurrentTime - iter->TimeEventOccurred);
  900.                                                 }
  901.                                         iter = gPendingDropEvents.erase( iter );
  902.                                 }
  903.                         else
  904.                                 ++iter;
  905.                 }
  906. }
  907.  
  908.  
  909.  
  910.  
  911.  
  912. //================================= Communication from the server ======================================================
  913.  
  914.  
  915. // handle events
  916. void FPassHandler::process ( bz_EventData *eventData )
  917. {
  918.         if (AllowMaxWaitMod)
  919.                 {
  920.                         // Give some feedback to allow some tweeking
  921.                         bz_debugMessagef(0, "FPassHandler::process eventType=%d seconds= %f", eventData->eventType, TimeKeeper::getCurrent().getSeconds()); fflush (stdout);
  922.                 }
  923.         // ***************************************
  924.         //   Flag Dropped (bz_eFlagDroppedEvent)
  925.         // ***************************************
  926.         if (bz_eFlagDroppedEvent == eventData->eventType)
  927.                 {
  928.                         bz_FlagDroppedEventData *dropData = (bz_FlagDroppedEventData*)eventData;
  929.                         FlagInfo& thisFlag = *FlagInfo::get(dropData->flagID);
  930.                         int flagTeam = thisFlag.flag.type->flagTeam;
  931.                        
  932.                         if ((kPassing_Off != FPassEnabled) && ((eNoTeam != flagTeam) || PassAllFlags))
  933.                                 {
  934.                                         // Find out why the flag is being dropped
  935.                                         GameKeeper::Player *playerData = GameKeeper::Player::getPlayerByIndex(dropData->playerID);
  936.                                         bz_debugMessagef(DbgLevelDbgInfo, "bz_eFlagDroppedEvent (!playerData)"); fflush (stdout);
  937.                                         if (!playerData)
  938.                                                 return;         // player not known
  939.                                         bz_debugMessagef(DbgLevelDbgInfo, "bz_eFlagDroppedEvent (playerData->isParting)"); fflush (stdout);
  940.                                         if (playerData->isParting)
  941.                                                 return;         // Player is being kicked - Just handle as a normal drop
  942.                                         bz_debugMessagef(DbgLevelDbgInfo, "bz_eFlagDroppedEvent (!playerData->player.isHuman())"); fflush (stdout);
  943.                                         if (!playerData->player.isHuman())
  944.                                                 return;         // Not for this plugin to handle
  945.                                        
  946.                                         // We will not know exactly why the flag was dropped until the client tells us
  947.                                         // So remember this event and check later when we have better data to work with
  948.                                        
  949.                                         float PlayerPos[3];
  950.                                         float PlayerVelocity[3];
  951.                                         if (getPlayerVelocity(dropData->playerID, PlayerVelocity))
  952.                                                 {
  953.                                                         bz_debugMessagef(DbgLevelDbgInfo, "             velocity: %f, %f, %f", PlayerVelocity[0], PlayerVelocity[1], PlayerVelocity[2]); fflush (stdout);
  954.                                                 }
  955.                                         else
  956.                                                 {
  957.                                                         bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: velocity: ERR"); fflush (stdout);
  958.                                                         return;
  959.                                                 }
  960.                                         if (getPlayerPosition(dropData->playerID, PlayerPos))
  961.                                                 {
  962.                                                         bz_debugMessagef(DbgLevelDbgInfo, "             PlayerPos: %f, %f, %f", PlayerPos[0], PlayerPos[1], PlayerPos[2]); fflush (stdout);
  963.                                                 }
  964.                                         else
  965.                                                 {
  966.                                                         bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: PlayerPos: ERR"); fflush (stdout);
  967.                                                         return;
  968.                                                 }
  969.                                         DropEvent ThisFlagDrop(dropData->playerID, dropData->flagID, dropData->pos, PlayerPos, PlayerVelocity);
  970.                                         if (kPassing_Immediate == FPassEnabled)
  971.                                                 {
  972.                                                         // We do not care about the fancy options we just want an immediate response
  973.                                                         ProcessDropEvent(ThisFlagDrop);
  974.                                                 }
  975.                                         else
  976.                                                 {
  977.                                                         if ((0.0 == PlayerVelocity[0]) && (0.0 == PlayerVelocity[1]))
  978.                                                                 if (kPOD_No == PassOnDeath)
  979.                                                                         return; // Nothing to do here - It will just drop anyway
  980.                                                        
  981.                                                         // Fancy options come at a price. The can be a delay before flag starts to fly.
  982.                                                         // It just means there is more to learn for your flag-passing skills
  983.                                                         gPendingDropEvents.push_back(ThisFlagDrop);
  984.                                                         bz_debugMessagef(DbgLevelDbgInfo, "gPendingDropEvents added (player=%d Flag=%d)", dropData->playerID, dropData->flagID); fflush (stdout);
  985.                                                 }
  986.                                 }
  987.                 }
  988.         // ***************************************
  989.         //   Player Update (bz_ePlayerUpdateEvent)
  990.         // ***************************************
  991.         else if (bz_ePlayerUpdateEvent == eventData->eventType)
  992.                 {
  993.                         bz_PlayerUpdateEventData* playerupdatedata = (bz_PlayerUpdateEventData*)eventData;
  994.                         //bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler: PlayerUpdateEvent for player %d velocity = %f, %f, %f", playerupdatedata->playerID, playerupdatedata->velocity[0], playerupdatedata->velocity[1], playerupdatedata->velocity[2]); fflush (stdout);
  995.                         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(playerupdatedata->playerID);
  996.                         if (StatsForThisPlayer->thisPlayerID == playerupdatedata->playerID)
  997.                                 {
  998.                                         StatsForThisPlayer->SetStats(playerupdatedata->playerID, playerupdatedata->velocity);
  999.                                         ProcessPendingEventsForPlayer(playerupdatedata->playerID);
  1000.                                         //bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler: PlayerUpdateEvent for player %d", playerupdatedata->playerID); fflush (stdout);
  1001.                                 }
  1002.                         else
  1003.                                 {
  1004.                                         bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: PlayerUpdate: ERR"); fflush (stdout);
  1005.                                 }
  1006.                 }
  1007.         // ***************************************
  1008.         //   Player Spawned (bz_ePlayerSpawnEvent)
  1009.         // ***************************************
  1010.         else if (bz_ePlayerSpawnEvent == eventData->eventType)
  1011.                 {
  1012.                         bz_PlayerSpawnEventData* birthDetails = (bz_PlayerSpawnEventData*)eventData;
  1013.                         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(birthDetails->playerID);
  1014.                         if (StatsForThisPlayer->thisPlayerID == birthDetails->playerID)
  1015.                                 {
  1016.                                         StatsForThisPlayer->SetKiller(kInvalidPlayerID, eNoTeam);
  1017.                                 }
  1018.                         else
  1019.                                 {
  1020.                                         bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: PlayerUpdate(bz_ePlayerSpawnEvent): ERR"); fflush (stdout);
  1021.                                 }
  1022.                 }
  1023.         // ***************************************
  1024.         //   Player Died (bz_ePlayerDieEvent)
  1025.         // ***************************************
  1026.         else if (bz_ePlayerDieEvent == eventData->eventType)
  1027.                 {
  1028.                         bz_PlayerDieEventData* deathDetails = ( bz_PlayerDieEventData*)eventData;
  1029.                         PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(deathDetails->playerID);
  1030.                         if (StatsForThisPlayer->thisPlayerID == deathDetails->playerID)
  1031.                                 {
  1032.                                         bz_debugMessagef(DbgLevelDbgInfo, "bz_ePlayerDieEvent (%d killed by %d of tesm %d)", deathDetails->playerID, deathDetails->killerID, deathDetails->killerTeam); fflush (stdout);
  1033.                                         StatsForThisPlayer->SetKiller(deathDetails->killerID, deathDetails->killerTeam);
  1034.                                         ProcessPendingEventsForPlayer(deathDetails->playerID);
  1035.                                 }
  1036.                         else
  1037.                                 {
  1038.                                         bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: PlayerUpdate(bz_ePlayerDieEvent): ERR"); fflush (stdout);
  1039.                                 }
  1040.                 }
  1041.         // ***************************************
  1042.         //   Player Joined (bz_ePlayerJoinEvent)
  1043.         // ***************************************
  1044.         else if (bz_ePlayerJoinEvent == eventData->eventType)
  1045.                 {
  1046.                         bz_PlayerJoinPartEventData *joinData = (bz_PlayerJoinPartEventData*)eventData;
  1047.                         if (joinData->team != eObservers)
  1048.                                 {
  1049.                                         float NoVelocity[3];
  1050.                                         NoVelocity[0] = NoVelocity[1] = NoVelocity[2] = 0.0;
  1051.                                         PlayerStats NewPlayer(joinData->playerID, joinData->team, NoVelocity, &joinData->callsign);
  1052.                                         gActivePlayers.push_back(NewPlayer);
  1053.                                         bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler: created PlayerStats for %d", joinData->playerID); fflush (stdout);
  1054.                                 }
  1055.                 }
  1056.         // ***************************************
  1057.         //   Player Left (bz_ePlayerPartEvent)
  1058.         // ***************************************
  1059.         else if (bz_ePlayerPartEvent == eventData->eventType)
  1060.                 {
  1061.                         bz_PlayerJoinPartEventData *partingData = (bz_PlayerJoinPartEventData*)eventData;
  1062.                         if (partingData->team != eObservers)
  1063.                                 {
  1064.                                         if (RemovePlayerStatsForPlayerID(partingData->playerID))
  1065.                                                 {
  1066.                                                         bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler: removed PlayerStats for %d", partingData->playerID); fflush (stdout);
  1067.                                                 }
  1068.                                         else
  1069.                                                 {
  1070.                                                         bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: ERR no PlayerStats for player %d", partingData->playerID); fflush (stdout);
  1071.                                                 }
  1072.                                 }
  1073.                 }
  1074.         // ***************************************
  1075.         //   Player Left (bz_eFlagGrabbedEvent)
  1076.         // ***************************************
  1077.         else if (bz_eFlagGrabbedEvent == eventData->eventType)
  1078.                 {
  1079.                         bz_FlagGrabbedEventData *msgData = (bz_FlagGrabbedEventData*)eventData;
  1080.                         // If the client has told us about grabbing a flag we know that we have enough information to process any pending drop event
  1081.                         ProcessPendingEventsForPlayer(msgData->playerID);
  1082.                 }
  1083.         // ***************************************
  1084.         //   Player Left (bz_eTickEvent)
  1085.         // ***************************************
  1086.         else if (bz_eTickEvent == eventData->eventType)
  1087.                 {
  1088.                         bz_TickEventData *msgData = (bz_TickEventData*)eventData;
  1089.                         RemoveOldEvents ((float)msgData->time);
  1090.                 }
  1091. }
  1092.  
  1093. #define kMaxCmdParamSize                                                                kWorkStrLen
  1094.  
  1095. #define kAdminPermission                                                                ""
  1096. #define kCountdownPermission                                                    "COUNTDOWN"
  1097.  
  1098. #define kCmdLine_Cmd                                                                            "fpass"
  1099. #define kOption_teamflagsonly                                                   "teamflagsonly"
  1100. #define kOption_PassToNonTeamKiller                                     "pass2nontkiller"
  1101. #define kOption_PassToAnyKiller                                         "pass2anykiller"
  1102. #define kOption_PreventMaxWaitMofification              "mwmodify"
  1103. #define kOption_maxwait                                                                 "maxwait"
  1104. #define kCmdLineParam_maxwait                                                   kOption_maxwait"="
  1105. #define kOption_dist                                                                            "dist"
  1106. #define kCmdLineParam_distance                                          kOption_dist"="
  1107. #define kOption_steps                                                                   "steps"
  1108. #define kCmdLineParam_SafeLandingAttempts                       kOption_steps"="
  1109. #define kOption_FumbleMsg                                                               "fmsg"
  1110. #define kCmdLineParam_FumbleMsg                                         kOption_FumbleMsg"="
  1111. #define kOption_AllFlags                                                                "allflags"
  1112. #define kCmdLineParam_AllFlags                                          kOption_AllFlags"="
  1113. #define kOption_PassOnDeath                                                     "passondeath"
  1114. #define kCmdLineParam_PassOnDeath                                       kOption_PassOnDeath"="
  1115. #define kOption_Hurt                                                                            "hurt"
  1116. #define kCmdLineParam_Hurt                                                              kOption_Hurt"="
  1117.  
  1118.  
  1119.  
  1120. // handle /FPass command
  1121. bool FPassHandler::handle ( int playerID, bzApiString cmd, bzApiString, bzAPIStringList* cmdParams )
  1122. {
  1123.         char subCmd[kWorkStrLen];
  1124.         if (strcasecmp (cmd.c_str(), kCmdLine_Cmd))   // is it for me ?
  1125.                 return false;
  1126.         if (cmdParams->get(0).c_str()[0] == '\0'){
  1127.                 sendHelp (playerID);
  1128.                 return true;
  1129.         }
  1130.        
  1131.  
  1132.         bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler::handle:  cmdParams->get(0).c_str() = \"%s\"",  cmdParams->get(0).c_str()); fflush (stdout);
  1133.         strncpy (subCmd, cmdParams->get(0).c_str(), kWorkStrLen-1);
  1134.         subCmd[kWorkStrLen-1] = '\0';
  1135.         bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler::handle:  subCmd = \"%s\"",  subCmd); fflush (stdout);
  1136.         // kCmdLineParam_distance
  1137.         if (strncasecmp (subCmd, kCmdLineParam_distance, strlen(kCmdLineParam_distance)) == 0)
  1138.                 {
  1139.                         if (checkPerms (playerID, kOption_dist, kAdminPermission))
  1140.                                 {
  1141.                                         if (!SetThrowDistance(cmdParams->get(0).c_str() + strlen(kCmdLineParam_distance), NULL))
  1142.                                                 {
  1143.                                                         sendHelp(playerID);
  1144.                                                 }
  1145.                                 }
  1146.                 }
  1147.         // kCmdLineParam_maxwait
  1148.         else if (strncasecmp (subCmd, kOption_maxwait, strlen(kOption_maxwait)) == 0)
  1149.                 {
  1150.                         if (checkPerms (playerID, kOption_maxwait, kAdminPermission))
  1151.                                 {
  1152.                                         if ((AllowMaxWaitMod) && ('=' == cmdParams->get(0).c_str()[strlen(kOption_maxwait)]))
  1153.                                                 SetMaxWaitVal(cmdParams->get(0).c_str() + strlen(kCmdLineParam_maxwait), NULL);
  1154.                                         sendMaxWaitMsg(playerID);
  1155.                                 }
  1156.                 }
  1157.         // kCmdLineParam_FumbleMsg
  1158.         else if (strncasecmp (subCmd, kCmdLineParam_FumbleMsg, strlen(kCmdLineParam_FumbleMsg)) == 0)
  1159.                 {
  1160.                         if (checkPerms (playerID, kOption_FumbleMsg, kAdminPermission))
  1161.                                 {
  1162.                                         char CmdParam[kMaxCmdParamSize];
  1163.                                         strncpy (CmdParam, cmdParams->get(0).c_str() + strlen(kCmdLineParam_FumbleMsg), kMaxCmdParamSize-1);
  1164.                                         if (strcasecmp (CmdParam, "off") == 0)
  1165.                                                 FumbleMsgEnable (kFMO_NoMessages, playerID);
  1166.                                         else if (strcasecmp (CmdParam, "all") == 0)
  1167.                                                 FumbleMsgEnable (kFMO_TellEveryone, playerID);
  1168.                                         else if (strcasecmp (CmdParam, "player") == 0)
  1169.                                                 FumbleMsgEnable (kFMO_TellPlayer, playerID);
  1170.                                         else
  1171.                                                 {
  1172.                                                         sendHelp(playerID);
  1173.                                                 }
  1174.                                 }
  1175.                 }
  1176.         // kCmdLineParam_AllFlags
  1177.         else if (strncasecmp (subCmd, kCmdLineParam_AllFlags, strlen(kCmdLineParam_AllFlags)) == 0)
  1178.                 {
  1179.                         if (checkPerms (playerID, kOption_AllFlags, kAdminPermission))
  1180.                                 {
  1181.                                         char CmdParam[kMaxCmdParamSize];
  1182.                                         strncpy (CmdParam, cmdParams->get(0).c_str() + strlen(kCmdLineParam_AllFlags), kMaxCmdParamSize-1);
  1183.                                         if (strcasecmp (CmdParam, "off") == 0)
  1184.                                                 AllFlagsEnable (false, playerID);
  1185.                                         else if (strcasecmp (CmdParam, "on") == 0)
  1186.                                                 AllFlagsEnable (true, playerID);
  1187.                                         else
  1188.                                                 {
  1189.                                                         sendHelp(playerID);
  1190.                                                 }
  1191.                                 }
  1192.                 }
  1193.         // kCmdLineParam_SafeLandingAttempts
  1194.         else if (strncasecmp (subCmd, kCmdLineParam_SafeLandingAttempts, strlen(kCmdLineParam_SafeLandingAttempts)) == 0)
  1195.                 {
  1196.                         if (checkPerms (playerID, kOption_steps, kAdminPermission))
  1197.                                 {
  1198.                                         if (!SetMaxIterations(cmdParams->get(0).c_str() + strlen(kCmdLineParam_SafeLandingAttempts), NULL))
  1199.                                                 {
  1200.                                                         sendHelp(playerID);
  1201.                                                 }
  1202.                                 }
  1203.                 }
  1204.         // kCmdLineParam_PassOnDeath
  1205.         else if (strncasecmp (subCmd, kCmdLineParam_PassOnDeath, strlen(kCmdLineParam_PassOnDeath)) == 0)
  1206.                 {
  1207.                         if (checkPerms (playerID, kOption_PassOnDeath, kAdminPermission))
  1208.                                 {
  1209.                                         char CmdParam[kMaxCmdParamSize];
  1210.                                         strncpy (CmdParam, cmdParams->get(0).c_str() + strlen(kCmdLineParam_PassOnDeath), kMaxCmdParamSize-1);
  1211.                                         bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler::handle:  subCmd = \"%s\" CmdParam=\"%s\"",  kCmdLineParam_PassOnDeath, CmdParam); fflush (stdout);
  1212.                                         if (strcasecmp (CmdParam, "off") == 0)
  1213.                                                 SetPassingOnDeathOption (kPOD_No, playerID);
  1214.                                         else if (strcasecmp (CmdParam, "on") == 0)
  1215.                                                 SetPassingOnDeathOption (kPOD_Yes, playerID);
  1216.                                         else if (strcasecmp (CmdParam, "hurts") == 0)
  1217.                                                 SetPassingOnDeathOption (kPOD_Hurts, playerID);
  1218.                                         else
  1219.                                                 {
  1220.                                                         sendHelp(playerID);
  1221.                                                 }
  1222.                                 }
  1223.                 }
  1224.         // hurt
  1225.         else if (strncasecmp (subCmd, kCmdLineParam_Hurt, strlen(kCmdLineParam_Hurt)) == 0)
  1226.                 {
  1227.                         if (checkPerms (playerID, kOption_Hurt, kAdminPermission))
  1228.                                 {
  1229.                                         char CmdParam[kMaxCmdParamSize];
  1230.                                         strncpy (CmdParam, cmdParams->get(0).c_str() + strlen(kCmdLineParam_Hurt), kMaxCmdParamSize-1);
  1231.                                         bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler::handle:  subCmd = \"%s\" CmdParam=\"%s\"",  kCmdLineParam_Hurt, CmdParam); fflush (stdout);
  1232.                                         if (strcasecmp (CmdParam, "killr") == 0)
  1233.                                                 SetHurtingOption (kHPO_ToKiller, playerID);
  1234.                                         else if (strcasecmp (CmdParam, "nontker") == 0)
  1235.                                                 SetHurtingOption (kHPO_ToNonTeamKiller, playerID);
  1236.                                         else
  1237.                                                 {
  1238.                                                         sendHelp(playerID);
  1239.                                                 }
  1240.                                 }
  1241.                 }
  1242.         // off
  1243.         else if (strcasecmp (subCmd, "off") == 0)
  1244.                 {
  1245.                         if (checkPerms (playerID, "off", kCountdownPermission))
  1246.                                 FPassEnable (kPassing_Off, playerID);
  1247.                 }
  1248.         // on
  1249.         else if (strcasecmp (subCmd, "on") == 0)
  1250.                 {
  1251.                         if (checkPerms (playerID, "on", kCountdownPermission))
  1252.                                 FPassEnable (kPassing_On, playerID);
  1253.                 }
  1254.         // immediate
  1255.         else if (strcasecmp (subCmd, "immediate") == 0)
  1256.                 {
  1257.                         if (checkPerms (playerID, "immediate", kCountdownPermission))
  1258.                                 FPassEnable (kPassing_Immediate, playerID);
  1259.                 }
  1260.         // reset
  1261.         else if (strcasecmp (subCmd, "reset") == 0)
  1262.                 {
  1263.                         if (checkPerms (playerID, "reset", kAdminPermission))
  1264.                                 ResetAllVariables (playerID);
  1265.                 }
  1266.         // stat
  1267.         else if (strcasecmp (subCmd, "stat") == 0)
  1268.                 FPassStats (playerID);
  1269.         // help
  1270.         else if (strcasecmp (subCmd, "help") == 0)
  1271.                 FPassSendDesc (playerID);
  1272.         else
  1273.                 sendHelp (playerID);
  1274.         return true;
  1275. }
  1276.  
  1277.  
  1278. //================================= Examine which options were set at loadplugin time ======================================================
  1279.  
  1280.  
  1281. bool commandLineHelp (void){
  1282.         const char *help[] = {
  1283.                 "Command line args:  -loadplugin PLUGINNAME[,teamflagsonly][,passondeath|pass2nontkiller|pass2anykiller][,maxwait=<0.0 .. 3.0>][,mwmodify][,dist=<0.0 .. 20.0>][,steps=<0 .. 20>],",
  1284.                 "  The options are available to set things other than the default values.",
  1285.                 "  Specifying \"teamflagsonly\" is equivalent to /fpass allflags=off",
  1286.                 "  passondeath is equivalent to /fpass passondeath=on",
  1287.                 "  pass2nontkiller is equivalent to /fpass passondeath=hurt",
  1288.                 "  pass2anykiller is equivalent to /fpass passondeath=hurt and /fpass hurt=killr",
  1289.                 "  maxwait specifies how long we will wait to find out why the user dropped the flag",
  1290.                 "  mwmodify will enable \"/fpass maxwait\" command from modifying the value",
  1291.                 "",
  1292.                 "  The options do not have to be added at loadplugin time, but if they are added then they need to added in the order shown above.",
  1293.                 "",
  1294.                 "  Example:   -loadplugin PassTheFlag,teamflagsonly,dist=6.0,steps=5                is fine",
  1295.                 "  but        -loadplugin PassTheFlag,dist=6.0,teamflagsonly,steps=5                will result in an error.",
  1296.                 NULL
  1297.         };
  1298.         bz_debugMessage (0, "+++ PassTheFlag plugin command-line error");
  1299.         for (int x=0; help[x]!=NULL; x++)
  1300.                 bz_debugMessage (0, help[x]);
  1301.         return true;
  1302. }
  1303.  
  1304.  
  1305.  
  1306.  
  1307. bool parseCommandLine (const char *cmdLine)
  1308. {
  1309.         int CharOffset = 0;
  1310.         if (cmdLine==NULL || *cmdLine=='\0')
  1311.                 return false;
  1312.         //bz_debugMessagef(1, "parseCommandLine:  parseCommandLine cmdLine = \"%s\"",  cmdLine); fflush (stdout);
  1313.         //bz_debugMessagef(1, "parseCommandLine:  parseCommandLine cmdLine + %d = \"%s\"",  CharOffset, cmdLine + CharOffset); fflush (stdout);
  1314.         if (strncasecmp (cmdLine + CharOffset, kOption_teamflagsonly, strlen(kOption_teamflagsonly)) == 0)
  1315.                 {
  1316.                         AllFlagsEnable(false, kInvalidPlayerID);
  1317.                         CharOffset += strlen(kOption_teamflagsonly) + 1;
  1318.                         AssignResetVal(PassAllFlags);
  1319.                 }
  1320.         if (strncasecmp (cmdLine + CharOffset, kOption_PassOnDeath, strlen(kOption_PassOnDeath)) == 0)
  1321.                 {
  1322.                         SetPassingOnDeathOption(kPOD_Yes, kInvalidPlayerID);
  1323.                         CharOffset += strlen(kOption_PassOnDeath) + 1;
  1324.                         AssignResetVal(PassOnDeath);
  1325.                 }
  1326.         if (strncasecmp (cmdLine + CharOffset, kOption_PassToNonTeamKiller, strlen(kOption_PassToNonTeamKiller)) == 0)
  1327.                 {
  1328.                         SetPassingOnDeathOption(kPOD_Hurts, kInvalidPlayerID);
  1329.                         SetHurtingOption(kHPO_ToNonTeamKiller, kInvalidPlayerID);               // Is the default option, but set it anyway
  1330.                         CharOffset += strlen(kOption_PassToNonTeamKiller) + 1;
  1331.                         AssignResetVal(PassOnDeath);
  1332.                         AssignResetVal(HurtOption);
  1333.                 }
  1334.         if (strncasecmp (cmdLine + CharOffset, kOption_PassToAnyKiller, strlen(kOption_PassToAnyKiller)) == 0)
  1335.                 {
  1336.                         SetPassingOnDeathOption(kPOD_Hurts, kInvalidPlayerID);
  1337.                         SetHurtingOption(kHPO_ToKiller, kInvalidPlayerID);
  1338.                         CharOffset += strlen(kOption_PassToAnyKiller) + 1;
  1339.                         AssignResetVal(PassOnDeath);
  1340.                         AssignResetVal(HurtOption);
  1341.                 }
  1342.         //bz_debugMessagef(1, "parseCommandLine:  parseCommandLine cmdLine + %d = \"%s\"",  CharOffset, cmdLine + CharOffset); fflush (stdout);
  1343.         if (strncasecmp (cmdLine + CharOffset, kCmdLineParam_maxwait, strlen(kCmdLineParam_maxwait)) == 0)
  1344.                 {
  1345.                         int CharsUsed = 0;
  1346.                         if (!SetMaxWaitVal(cmdLine+CharOffset+strlen(kCmdLineParam_maxwait), &CharsUsed))
  1347.                                 return commandLineHelp ();
  1348.                         else
  1349.                                 CharOffset += strlen(kCmdLineParam_maxwait) + 1 + CharsUsed;
  1350.                         AssignResetVal(MaxWaitForReason);
  1351.                 }
  1352.         if (strncasecmp (cmdLine + CharOffset, kOption_PreventMaxWaitMofification, strlen(kOption_PreventMaxWaitMofification)) == 0)
  1353.                 {
  1354.                         AllowMaxWaitMod = true;
  1355.                         CharOffset += strlen(kOption_PreventMaxWaitMofification) + 1;
  1356.                 }
  1357.         if (strncasecmp (cmdLine + CharOffset, kCmdLineParam_distance, strlen(kCmdLineParam_distance)) == 0)
  1358.                 {
  1359.                         int CharsUsed = 0;
  1360.                         if (!SetThrowDistance(cmdLine+CharOffset+strlen(kCmdLineParam_distance), &CharsUsed))
  1361.                                 return commandLineHelp ();
  1362.                         else
  1363.                                 CharOffset += strlen(kCmdLineParam_distance) + 1 + CharsUsed;
  1364.                         AssignResetVal(FPassThrowDistance);
  1365.                 }
  1366.         //bz_debugMessagef(1, "parseCommandLine:  parseCommandLine cmdLine + %d = \"%s\"",  CharOffset, cmdLine + CharOffset); fflush (stdout);
  1367.         if (strncasecmp (cmdLine + CharOffset, kCmdLineParam_SafeLandingAttempts, strlen(kCmdLineParam_SafeLandingAttempts)) == 0)
  1368.                 {
  1369.                         int CharsUsed = 0;
  1370.                         if (!SetMaxIterations(cmdLine+CharOffset+strlen(kCmdLineParam_SafeLandingAttempts), &CharsUsed))
  1371.                                 return commandLineHelp ();
  1372.                         else
  1373.                                 CharOffset += strlen(kCmdLineParam_SafeLandingAttempts) + 1 + CharsUsed;
  1374.                         AssignResetVal(MaxSafeZoneTests);
  1375.                 }
  1376.        
  1377.         if ('\0' != cmdLine[CharOffset])
  1378.                 {
  1379.                         // We did not process all the parameters
  1380.                         bz_debugMessage (0, "+++ PassTheFlag plugin command-line error: Some parameters were not processed.");
  1381.                         bz_debugMessage (0, &cmdLine[CharOffset]);
  1382.                         return commandLineHelp ();
  1383.                 }
  1384.         return false;
  1385. }
  1386.  
  1387.  
  1388. //================================= Required entry points called by the server  ======================================================
  1389.  
  1390.  
  1391. // Tells the server which version of the bzfsAPI.h this plugin was generated with
  1392. BZ_GET_PLUGIN_VERSION
  1393.  
  1394.  
  1395. // Called by the server when the plugin is loaded
  1396. BZF_PLUGIN_CALL int bz_Load (const char* cmdLine)
  1397. {
  1398.         // Check what options were set and complain if there was a problem
  1399.         if (parseCommandLine (cmdLine))
  1400.                 return -1;
  1401.        
  1402.         /* initialize random seed: */
  1403.         srand ( time(NULL) );
  1404.        
  1405.         // Set up how we want to commmunicate with the server
  1406.         bz_registerCustomSlashCommand (kCmdLine_Cmd, &FlagPassHandler);
  1407.  
  1408.         bz_registerEvent(bz_ePlayerDieEvent,&FlagPassHandler);
  1409.         bz_registerEvent(bz_ePlayerSpawnEvent,&FlagPassHandler);
  1410.         bz_registerEvent(bz_eFlagDroppedEvent, &FlagPassHandler);
  1411.         bz_registerEvent(bz_ePlayerJoinEvent, &FlagPassHandler);
  1412.         bz_registerEvent(bz_ePlayerPartEvent, &FlagPassHandler);
  1413.         bz_registerEvent(bz_ePlayerUpdateEvent, &FlagPassHandler);
  1414.  
  1415.         bz_registerEvent(bz_eFlagGrabbedEvent, &FlagPassHandler);
  1416.         bz_registerEvent(bz_eTickEvent, &FlagPassHandler);
  1417.  
  1418.         bz_setMaxWaitTime (MaxWaitForReason);
  1419.        
  1420.         // Show everything loaded without a problem
  1421.         bz_debugMessagef(DbgLevelAlways, "PassTheFlag plugin loaded - v%s ApiVersion=v%d%s", PASSTHEFLAG_VER, BZ_API_VERSION, AllowMaxWaitMod?" maxwait modification enabled":" maxwait modification disabled");
  1422.         return 0;
  1423. }
  1424.  
  1425. // Called by the server when the plugin is unloaded
  1426. BZF_PLUGIN_CALL int bz_Unload (void)
  1427. {
  1428.         // Stop communications with the server
  1429.         bz_removeCustomSlashCommand (kCmdLine_Cmd);
  1430.  
  1431.         bz_removeEvent (bz_ePlayerDieEvent, &FlagPassHandler);
  1432.         bz_removeEvent (bz_ePlayerSpawnEvent, &FlagPassHandler);
  1433.         bz_removeEvent (bz_eFlagDroppedEvent, &FlagPassHandler);
  1434.         bz_removeEvent (bz_ePlayerJoinEvent, &FlagPassHandler);
  1435.         bz_removeEvent (bz_ePlayerPartEvent, &FlagPassHandler);
  1436.         bz_removeEvent (bz_ePlayerUpdateEvent, &FlagPassHandler);
  1437.  
  1438.         bz_removeEvent (bz_eFlagGrabbedEvent, &FlagPassHandler);
  1439.         bz_removeEvent (bz_eTickEvent, &FlagPassHandler);
  1440.        
  1441.         // Show that this plugin is no longer active
  1442.         bz_debugMessage(DbgLevelAlways, "PassTheFlag plugin unloaded");
  1443.         return 0;
  1444. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top