Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* PassTheFlag
- * Copyright (c) 2010 squad.firing@gmail.com
- *
- * Published under version 3 of the GNU LESSER GENERAL PUBLIC LICENSE
- *
- * This package is free software; you can redistribute it and/or
- * modify it under the terms of the license found in the file
- * named lgpl.txt that should have accompanied this file.
- * Also available at http://www.gnu.org/licenses/lgpl.txt at the time this was created
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
- // PassTheFlag.cpp : a bzfs plugin to enable passing of flags (actually you throw them)
- //
- // PassTheFlag.cpp written by FiringSquad based loosely on the HTF plugin code by bullet_catcher that came with the BZFlag sources
- // Special thanks to mrapple for his help
- #include <assert.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include "bzfsAPI.h"
- // Note: including the following headers will mean that this plugin will not compile under Windows.
- // The only other option was modifying the server code to achieve the functionality I needed and that was not really an option.
- // Using these headers exposes internal workings of the server that you need to be careful with, so it should not be done lightly.
- // It does allow you to do some pretty cool stuff though. :-D
- #include "../../src/bzfs/bzfs.h"
- #include "../plugin_utils/plugin_utils.h"
- #include "BZDBCache.h"
- #include "../../src/bzfs/DropGeometry.h"
- #define PASSTHEFLAG_VER "1.00.02"
- #define DbgLevelAlways 1
- #define DbgLevelErr 1
- #define DbgLevelWarn 2
- #define DbgLevelInfo 3
- #define DbgLevelExtraInfo 4
- //#define DbgLevelDbgInfo 5
- #define DbgLevelDbgInfo 1
- #define kWorkStrLen 255
- #define kInvalidPlayerID -1
- //======================================= FPassHandler ================================================
- // Standard interface for communicating with the server
- class FPassHandler : public bz_EventHandler, public bz_CustomSlashCommandHandler
- {
- public:
- virtual void process ( bz_EventData *eventData );
- virtual bool handle ( int playerID, bzApiString, bzApiString, bzAPIStringList*);
- protected:
- private:
- };
- FPassHandler FlagPassHandler;
- //======================================= PlayerStats ================================================
- // Contains details I need to remember about active players that are not available elsewhere
- // It is filled during the bz_ePlayerUpdateEvent, bz_ePlayerSpawnEvent and bz_ePlayerDieEvent
- class PlayerStats {
- public:
- int thisPlayerID;
- bz_eTeamType playerTeam;
- bzApiString callsign;
- // Stuff I need to remember
- float velocity[3];
- bz_eTeamType KillerTeam;
- int KilledByPlayerID;
- void SetStats(int playerID, const float *velocity) {
- if (velocity && (this->thisPlayerID == playerID))
- {
- memcpy(this->velocity, velocity, sizeof(float[3]));
- }
- }
- void SetKiller(int KillerID, bz_eTeamType KillerTeam) {
- this->KilledByPlayerID = KillerID;
- this->KillerTeam = KillerTeam;
- }
- void InitialiseData(int playerID = kInvalidPlayerID, bz_eTeamType PlayerTeam = eNoTeam, const float *velocity = NULL, const bzApiString *callsign = NULL, int KillPlayerID = kInvalidPlayerID, bz_eTeamType KillerTeam = eNoTeam) {
- this->thisPlayerID = playerID;
- this->playerTeam = PlayerTeam;
- this->KillerTeam = KillerTeam;
- this->KilledByPlayerID = KillPlayerID;
- this->velocity[0] = velocity?velocity[0]:0.0;
- this->velocity[1] = velocity?velocity[1]:0.0;
- this->velocity[2] = velocity?velocity[2]:0.0;
- this->callsign = callsign?*callsign:bzApiString();
- }
- PlayerStats(int playerID, bz_eTeamType PlayerTeam, const float *velocity, const bzApiString *callsign) { InitialiseData(playerID, PlayerTeam, velocity, callsign); };
- PlayerStats(const PlayerStats& inData) {
- if (this != &inData)
- {
- InitialiseData(inData.thisPlayerID, inData.playerTeam, inData.velocity, &inData.callsign, inData.KilledByPlayerID, inData.KillerTeam);
- }
- };
- PlayerStats() { InitialiseData(kInvalidPlayerID, eNoTeam, NULL, NULL, kInvalidPlayerID, eNoTeam); };
- PlayerStats& operator=(const PlayerStats& other);
- bool operator==(const PlayerStats& other) const;
- bool operator!=(const PlayerStats& other) const { return !(*this == other); }
- };
- // operator ==
- inline bool PlayerStats::operator==(const PlayerStats& inData) const
- {
- return (thisPlayerID == inData.thisPlayerID);
- }
- PlayerStats& PlayerStats::operator=(const PlayerStats& other)
- {
- if (this != &other)
- {
- InitialiseData(other.thisPlayerID, other.playerTeam, other.velocity, &other.callsign, other.KilledByPlayerID, other.KillerTeam);
- }
- return *this;
- }
- // List of active players along with their recorded information
- // Players are added during the bz_ePlayerJoinEvent
- // and removed after a bz_ePlayerPartEvent
- std::vector <PlayerStats> gActivePlayers;
- //======================================= PassDetails ================================================
- // Contains all the information we need in order to calculate the pass
- // There are some times when a flag is dropped that we want to ignore
- // The problem is that the client first sends the flagdrop message and later sends the reason
- // We therefore need to remember that the flag was dropped and check later if we need to send it flying anywhere
- #define kDefault_MaxWaitForReason 0.7f
- class DropEvent {
- public:
- float TimeEventOccurred;
- int PlayerThatDroppedTheFlag;
- int DroppedFlagID;
- float DropPos[3];
- float PlayerPosAtThisTime[3];
- float PlayerVelocityAtThisTime[3];
- void InitialiseData(int playerID = kInvalidPlayerID, int flagID = -1, const float *DropPos = NULL, const float *PlayerPosAtThisTime = NULL, const float *PlayerVelocityAtThisTime = NULL, float EventTime = 0.0)
- {
- this->PlayerThatDroppedTheFlag = playerID;
- this->DroppedFlagID = flagID;
- this->TimeEventOccurred = EventTime;
- this->DropPos[0] = DropPos?DropPos[0]:0.0;
- this->DropPos[1] = DropPos?DropPos[1]:0.0;
- this->DropPos[2] = DropPos?DropPos[2]:0.0;
- this->PlayerPosAtThisTime[0] = PlayerPosAtThisTime?PlayerPosAtThisTime[0]:0.0;
- this->PlayerPosAtThisTime[1] = PlayerPosAtThisTime?PlayerPosAtThisTime[1]:0.0;
- this->PlayerPosAtThisTime[2] = PlayerPosAtThisTime?PlayerPosAtThisTime[2]:0.0;
- this->PlayerVelocityAtThisTime[0] = PlayerVelocityAtThisTime?PlayerVelocityAtThisTime[0]:0.0;
- this->PlayerVelocityAtThisTime[1] = PlayerVelocityAtThisTime?PlayerVelocityAtThisTime[1]:0.0;
- this->PlayerVelocityAtThisTime[2] = PlayerVelocityAtThisTime?PlayerVelocityAtThisTime[2]:0.0;
- }
- DropEvent(int playerID, int flagID, const float *DropPos, const float *PlayerPosAtThisTime, const float *PlayerVelocityAtThisTime) { InitialiseData(playerID, flagID, DropPos, PlayerPosAtThisTime, PlayerVelocityAtThisTime,TimeKeeper::getCurrent().getSeconds()); };
- DropEvent(const DropEvent& inData) {
- if (this != &inData)
- {
- InitialiseData(inData.PlayerThatDroppedTheFlag, inData.DroppedFlagID, inData.DropPos, inData.PlayerPosAtThisTime, inData.PlayerVelocityAtThisTime, inData.TimeEventOccurred);
- }
- };
- DropEvent() { InitialiseData(); };
- DropEvent& operator=(const DropEvent& other);
- bool operator==(const DropEvent& other) const;
- bool operator!=(const DropEvent& other) const { return !(*this == other); }
- };
- // operator ==
- inline bool DropEvent::operator==(const DropEvent& inData) const
- {
- return (PlayerThatDroppedTheFlag == inData.PlayerThatDroppedTheFlag);
- }
- DropEvent& DropEvent::operator=(const DropEvent& other)
- {
- if (this != &other)
- {
- InitialiseData(other.PlayerThatDroppedTheFlag, other.DroppedFlagID, other.DropPos, other.PlayerPosAtThisTime, other.PlayerVelocityAtThisTime, other.TimeEventOccurred);
- }
- return *this;
- }
- // List of pending drop events
- std::vector <DropEvent> gPendingDropEvents;
- //=======================================================================================
- enum tFumbleMsgOption {
- kFMO_NoMessages,
- kFMO_TellEveryone,
- kFMO_TellPlayer,
- kFMO_MaxVal // Never used as an option, just as a counter
- };
- const char *kFumbleMsgSettingDesc[kFMO_MaxVal] = {
- "No Fumble Messages",
- "Tell everbody about fumbles",
- "only inform the player that fumbled"
- };
- enum tPassOnDeathOption {
- kPOD_No,
- kPOD_Yes,
- kPOD_Hurts,
- kPOD_MaxVal // Never used as an option, just as a counter
- };
- const char *kPassOnDeathSettingDesc[kPOD_MaxVal] = {
- "Flag drops without being passed",
- "Flag flies in direction tank was moving",
- "Flag holder gets punished in accordance with \"hurt\""
- };
- enum tPassOption {
- kPassing_On,
- kPassing_Off,
- kPassing_Immediate,
- kPassing_MaxVal // Never used as an option, just as a counter
- };
- const char *kPassOptionDesc[kPassing_MaxVal] = {
- "Activated",
- "Disabled",
- "Immediate (No fancy stuff - let the flag fly)"
- };
- enum tHurtingPassOption {
- kHPO_ToKiller,
- kHPO_ToNonTeamKiller,
- kHPO_MaxVal // Never used as an option, just as a counter
- };
- const char *kHurtSettingDesc[kHPO_MaxVal] = {
- "Flag flies in direction of killer",
- "Flag flies in direction of killer unless it was a TK"
- };
- #define kMaxFumbledPassMessages 5
- const char *kFumbledPassMessages[kMaxFumbledPassMessages] = {
- "Woops! You need to be more careful passing",
- "You fumbled that pass!",
- "Watch where you're throwing that flag! Fumble!",
- "You tried to send flag where it can't go. Silly!",
- "I hope you shoot better than you pass."
- };
- //====================================== Configurable Options =================================================
- tPassOption FPassEnabled = kPassing_On;
- tFumbleMsgOption FumbleMsg = kFMO_TellPlayer;
- tPassOnDeathOption PassOnDeath = kPOD_No;
- tHurtingPassOption HurtOption = kHPO_ToNonTeamKiller;
- bool PassAllFlags = true;
- float FPassThrowDistance = 6.0;
- int MaxSafeZoneTests = 5;
- float MaxWaitForReason = kDefault_MaxWaitForReason;
- // Reset Values
- #define AssignResetVal(ConfigVal) ResetVal_##ConfigVal = ConfigVal
- #define ResetTheValue(ConfigVal) ConfigVal = ResetVal_##ConfigVal
- tPassOption AssignResetVal(FPassEnabled);
- tFumbleMsgOption AssignResetVal(FumbleMsg);
- tPassOnDeathOption AssignResetVal(PassOnDeath);
- tHurtingPassOption AssignResetVal(HurtOption);
- bool AssignResetVal(PassAllFlags);
- float AssignResetVal(FPassThrowDistance);
- int AssignResetVal(MaxSafeZoneTests);
- float AssignResetVal(MaxWaitForReason);
- bool AllowMaxWaitMod = false;
- //====================================== PlayerStats Utils =================================================
- // Return the PlayerStats information for player PlayerID
- PlayerStats *GetActivePlayerStatsByID(int PlayerID)
- {
- static PlayerStats UnKnown;
- UnKnown.InitialiseData();
- for(unsigned int i=0;i<gActivePlayers.size();i++)
- {
- if (gActivePlayers[i].thisPlayerID == PlayerID)
- {
- return &gActivePlayers[i];
- }
- }
- return &UnKnown;
- }
- // Locate PlayerStats information for player PlayerID in the gActivePlayers list and remove it
- bool RemovePlayerStatsForPlayerID(int PlayerID)
- {
- std::vector<PlayerStats>::iterator iter = gActivePlayers.begin();
- while( iter != gActivePlayers.end() )
- {
- if (iter->thisPlayerID == PlayerID)
- {
- iter = gActivePlayers.erase( iter );
- return true;
- }
- else
- ++iter;
- }
- return false;
- }
- //================================= fpass command utils ======================================================
- // Get the current value for velocity I have for this player
- bool getPlayerVelocity(int playerID, float vel[3])
- {
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(playerID);
- memcpy(vel, StatsForThisPlayer->velocity, sizeof(float[3]));
- return (StatsForThisPlayer->thisPlayerID == playerID);
- }
- // Get the current value for velocity I have for this player
- bool getPlayerKiller(int playerID, bz_eTeamType &playerTeam, int &KillerID, bz_eTeamType &KillerTeam)
- {
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(playerID);
- playerTeam = StatsForThisPlayer->playerTeam;
- KillerID = StatsForThisPlayer->KilledByPlayerID;
- KillerTeam = StatsForThisPlayer->KillerTeam;
- return (StatsForThisPlayer->thisPlayerID == playerID);
- }
- // Ask the server for the callsign for this player
- bzApiString &getPlayerCallsign(int playerID)
- {
- static bzApiString UnknownPlayer("some unknown player");
- bz_PlayerRecord* player = bz_getPlayerByIndex(playerID);
- if (player) {
- return player->callsign;
- }
- return UnknownPlayer;
- }
- // Ask the server for the location for this player
- bool getPlayerPosition(int playerID, float PlayerPos[3])
- {
- bz_PlayerRecord* player = bz_getPlayerByIndex(playerID);
- if (!player) {
- return false;
- }
- memcpy(PlayerPos, player->pos, sizeof(float[3]));
- return true;
- }
- // Ask the server if this player is an Admin
- bool playerIsAdmin(int playerID)
- {
- bz_PlayerRecord* player = bz_getPlayerByIndex(playerID);
- if (!player) {
- return false;
- }
- return player->admin;
- }
- // Check if this player has the appropriate permission to perform the command
- bool checkPerms (int playerID, const char *FPassCmd, const char *permName)
- {
- bool HasPerm = false;
- return true;//zxcv
- if ('\0' == *permName) // Needs Admin
- HasPerm = playerIsAdmin (playerID);
- else
- HasPerm = bz_hasPerm (playerID, permName);
- if (!HasPerm)
- bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "you need \"%s\" permission to do /FPass %s", *permName?permName:"Admin", FPassCmd);
- return HasPerm;
- }
- //================================= fpass command responses ======================================================
- // Send command format
- void sendHelp (int who)
- {
- bz_sendTextMessage(BZ_SERVER, who, "FPass commands: [help|stat|off|on|immediate|reset|allflags=[on|off]...");
- bz_sendTextMessage(BZ_SERVER, who, " ...|dist=< 0.0 .. 20.0>|steps=<0 .. 20>...|fmsg=[off|all|player]...");
- bz_sendTextMessage(BZ_SERVER, who, " ...|passondeath=[on|off|hurts]|hurt=[killr|nontker]");
- }
- // Send Details about setting MaxWaitForReason
- void sendMaxWaitMsg (int who)
- {
- 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");
- }
- // Reset All Configurable Variable back to their values at launchplugin time
- void ResetAllVariables (int who)
- {
- char msg[kWorkStrLen];
- const char *PlayerName;
- if (kInvalidPlayerID == who)
- return;
- ResetTheValue(FPassEnabled);
- ResetTheValue(FumbleMsg);
- ResetTheValue(PassOnDeath);
- ResetTheValue(HurtOption);
- ResetTheValue(PassAllFlags);
- ResetTheValue(FPassThrowDistance);
- ResetTheValue(MaxSafeZoneTests);
- ResetTheValue(MaxWaitForReason);
- //bz_setMaxWaitTime (MaxWaitForReason);
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
- if (StatsForThisPlayer->thisPlayerID == who)
- PlayerName = StatsForThisPlayer->callsign.c_str();
- else
- PlayerName = getPlayerCallsign(who).c_str();
- snprintf (msg, kWorkStrLen, "*** Flag Passing variables reset by %s", PlayerName);
- bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
- }
- // Show current settings
- void FPassStats (int who)
- {
- bz_sendTextMessagef(BZ_SERVER, who, "FPass plugin version %s", PASSTHEFLAG_VER);
- bz_sendTextMessagef(BZ_SERVER, who, " Flag Passing is %s" , kPassOptionDesc[(int) PassOnDeath]);
- bz_sendTextMessagef(BZ_SERVER, who, " Flag Throw Distance: %f" , FPassThrowDistance);
- bz_sendTextMessagef(BZ_SERVER, who, " Max Attempts to land flag: %d" , MaxSafeZoneTests);
- bz_sendTextMessagef(BZ_SERVER, who, " Fumble Messages are set to \"%s\"" , kFumbleMsgSettingDesc[(int) FumbleMsg]);
- bz_sendTextMessagef(BZ_SERVER, who, " Passing of non-team flags is turned %s" , PassAllFlags ? "ON":"OFF");
- bz_sendTextMessagef(BZ_SERVER, who, " Passing on Death set to \"%s\"" , kPassOnDeathSettingDesc[(int) PassOnDeath]);
- bz_sendTextMessagef(BZ_SERVER, who, " Current \"hurt\" option is \"%s\"" , kHurtSettingDesc[(int) HurtOption]);
- }
- // Send details about the PassTheFlag plugin
- void FPassSendDesc (int who)
- {
- bz_sendTextMessage(BZ_SERVER, who, "PassTheFlag plugin allows the user to throw the flag they are currently holding.");
- bz_sendTextMessage(BZ_SERVER, who, "Essentially the flag flies in the direction you are traveling and the faster you");
- bz_sendTextMessage(BZ_SERVER, who, "go the further it flies");
- bz_sendTextMessage(BZ_SERVER, who, "Jumping effects the distance too. If you are going up it travels twice as far,");
- bz_sendTextMessage(BZ_SERVER, who, "and if you are falling it travels half as far.");
- bz_sendTextMessage(BZ_SERVER, who, "A fumble occurs when you try to pass a flag to an unsafe location.");
- bz_sendTextMessage(BZ_SERVER, who, "For further information, check out the README.txt file accompanying the source.");
- bz_sendTextMessage(BZ_SERVER, who, "You need COUNTDOWN privileges to turn it ON/OFF.");
- bz_sendTextMessage(BZ_SERVER, who, "You need to be an Admin to change other settings.");
- bz_sendTextMessage(BZ_SERVER, who, "\"/fpass help\" and \"/fpass stat\" are available to all.");
- bz_sendTextMessage(BZ_SERVER, who, "Current Settings:");
- FPassStats(who);
- bz_sendTextMessage(BZ_SERVER, who, "Command options:");
- sendHelp(who);
- }
- // Check if the flag can be dropped at dropPos[] and return true if safe
- // landing[] will contain the eventual location where the flag would end up if dropped
- bool do_checkFlagDropAtPoint ( int flagID, float dropPos[3], float landing[3] )
- {
- assert(world != NULL);
- const float size = BZDBCache::worldSize * 0.5f;
- float pos[3];
- pos[0] = ((dropPos[0] < -size) || (dropPos[0] > size)) ? 0.0f : dropPos[0];
- pos[1] = ((dropPos[1] < -size) || (dropPos[1] > size)) ? 0.0f : dropPos[1];
- pos[2] = dropPos[2]; // maxWorldHeight should not be a problem since the flag can not be sent above the "passer"
- FlagInfo& thisFlag = *FlagInfo::get(flagID);
- int flagTeam = thisFlag.flag.type->flagTeam;
- const float waterLevel = world->getWaterLevel();
- float minZ = 0.0f;
- if (waterLevel > minZ) {
- minZ = waterLevel;
- }
- const float maxZ = MAXFLOAT;
- landing[0] = pos[0];
- landing[1] = pos[1];
- landing[2] = pos[2];
- bool safelyDropped = DropGeometry::dropTeamFlag(landing, minZ, maxZ, flagTeam); // Pretend we are dropping the team flag
- return safelyDropped;
- }
- // Turn passing on/off
- void FPassEnable (tPassOption PassingOption, int who)
- {
- char msg[kWorkStrLen];
- const char *PlayerName;
- if (PassingOption == FPassEnabled){
- bz_sendTextMessage(BZ_SERVER, who, "Flag Passing is already that way.");
- return;
- }
- FPassEnabled = PassingOption;
- if (kInvalidPlayerID == who)
- return;
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
- if (StatsForThisPlayer->thisPlayerID == who)
- PlayerName = StatsForThisPlayer->callsign.c_str();
- else
- PlayerName = getPlayerCallsign(who).c_str();
- snprintf (msg, kWorkStrLen, "*** Flag Passing set to %s by %s", kPassOptionDesc[(int) FPassEnabled], PlayerName);
- bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
- }
- // Set the PassingOnDeath option
- void SetPassingOnDeathOption (tPassOnDeathOption PassingOption, int who)
- {
- char msg[kWorkStrLen];
- const char *PlayerName;
- if (PassingOption == PassOnDeath){
- bz_sendTextMessage(BZ_SERVER, who, "Flag Passing on death is already that way.");
- return;
- }
- PassOnDeath = PassingOption;
- if (kInvalidPlayerID == who)
- return;
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
- if (StatsForThisPlayer->thisPlayerID == who)
- PlayerName = StatsForThisPlayer->callsign.c_str();
- else
- PlayerName = getPlayerCallsign(who).c_str();
- snprintf (msg, kWorkStrLen, "*** Passing on death set to %s by %s", kPassOnDeathSettingDesc[(int) PassingOption], PlayerName);
- bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
- }
- // Set the Hurt option
- void SetHurtingOption (tHurtingPassOption HurtingOption, int who)
- {
- char msg[kWorkStrLen];
- const char *PlayerName;
- if (HurtingOption == HurtOption){
- bz_sendTextMessage(BZ_SERVER, who, "Hurting option is already that way.");
- return;
- }
- HurtOption = HurtingOption;
- if (kInvalidPlayerID == who)
- return;
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
- if (StatsForThisPlayer->thisPlayerID == who)
- PlayerName = StatsForThisPlayer->callsign.c_str();
- else
- PlayerName = getPlayerCallsign(who).c_str();
- snprintf (msg, kWorkStrLen, "*** Hurting option set to %s by %s", kHurtSettingDesc[(int) HurtingOption], PlayerName);
- bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
- }
- // Set the Fumble Message option
- void FumbleMsgEnable (tFumbleMsgOption MsgOption, int who)
- {
- char msg[kWorkStrLen];
- const char *PlayerName;
- if (MsgOption == FumbleMsg){
- bz_sendTextMessage(BZ_SERVER, who, "Fumble Messaging is already that way.");
- return;
- }
- FumbleMsg = MsgOption;
- if (kInvalidPlayerID == who)
- return;
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
- if (StatsForThisPlayer->thisPlayerID == who)
- PlayerName = StatsForThisPlayer->callsign.c_str();
- else
- PlayerName = getPlayerCallsign(who).c_str();
- snprintf (msg, kWorkStrLen, "*** Fumble Messages changed to \"%s\" by %s", kFumbleMsgSettingDesc[(int) MsgOption], PlayerName);
- bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
- }
- // Set the option to pass only Team flags or all flags
- void AllFlagsEnable (bool onoff, int who)
- {
- char msg[kWorkStrLen];
- const char *PlayerName;
- if (onoff == PassAllFlags){
- bz_sendTextMessage(BZ_SERVER, who, "Flags effected are already that way.");
- return;
- }
- PassAllFlags = onoff;
- if (kInvalidPlayerID == who)
- return;
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(who);
- if (StatsForThisPlayer->thisPlayerID == who)
- PlayerName = StatsForThisPlayer->callsign.c_str();
- else
- PlayerName = getPlayerCallsign(who).c_str();
- snprintf (msg, kWorkStrLen, "*** Flag passing for non-team flags was turned %s by %s", onoff?"ON":"OFF", PlayerName);
- bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, msg);
- }
- // Set the "dist=" value
- bool SetThrowDistance(const char *FloatStr, int *CharsUsed)
- {
- float FloatVal = 0.0;
- char *EndOfNum = (char *) FloatStr;
- FloatVal = strtof (FloatStr, &EndOfNum);
- if (EndOfNum == FloatStr)
- return false;
- if (CharsUsed)
- *CharsUsed = (EndOfNum - FloatStr);
- if ((0.0 >= FloatVal) || (20.0 <= FloatVal))
- return false;
- bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "PassTheFlag: Flag Throw Distance: Chaged from %f to %f", FPassThrowDistance, FloatVal); fflush (stdout);
- FPassThrowDistance = FloatVal;
- return true;
- }
- // Set the maxwait value
- bool SetMaxWaitVal(const char *FloatStr, int *CharsUsed)
- {
- float FloatVal = 0.0;
- char *EndOfNum = (char *) FloatStr;
- FloatVal = strtof (FloatStr, &EndOfNum);
- if (EndOfNum == FloatStr)
- return false;
- if (CharsUsed)
- *CharsUsed = (EndOfNum - FloatStr);
- if ((0.0 >= FloatVal) || (3.0 <= FloatVal))
- return false;
- MaxWaitForReason = FloatVal;
- //bz_setMaxWaitTime (MaxWaitForReason);
- return true;
- }
- // Set the "steps=" value
- bool SetMaxIterations(const char *IntStr, int *CharsUsed)
- {
- int IntVal = 0;
- char *EndOfNum = (char *) IntStr;
- IntVal = strtol (IntStr, &EndOfNum, 10);
- if (EndOfNum == IntStr)
- return false;
- if (CharsUsed)
- *CharsUsed = (EndOfNum - IntStr);
- if ((0 >= IntVal) || (20 <= IntVal))
- return false;
- bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "PassTheFlag: Max Attempts to land flag: Chaged from %d to %d", MaxSafeZoneTests, IntVal);
- MaxSafeZoneTests = IntVal;
- return true;
- }
- //================================= Process this drop event ======================================================
- void ProcessDropEvent(DropEvent &PendingDropEvent)
- {
- bool NeedToCalculateLandingPos = true;
- bool ValidFlagThrow = false;;
- float FlagLandingPos[3];
- GameKeeper::Player *playerData = GameKeeper::Player::getPlayerByIndex(PendingDropEvent.PlayerThatDroppedTheFlag);
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (!playerData)"); fflush (stdout);
- if (!playerData)
- return; // player not known
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (playerData->isParting)"); fflush (stdout);
- if (playerData->isParting)
- return; // Player is being kicked - Just handle as a normal drop
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (!playerData->player.isHuman())"); fflush (stdout);
- if (!playerData->player.isHuman())
- return; // Not for this plugin to handle
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (playerData->player.isPaused())"); fflush (stdout);
- if (playerData->player.isPaused())
- return; // Dropped due to pause
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (!playerData->player.isAlive())"); fflush (stdout);
- if (!playerData->player.isAlive())
- {
- // Player Died - so there might be some special things to do
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (kPOD_No == PassOnDeath)"); fflush (stdout);
- if (kPOD_No == PassOnDeath)
- return;
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (kPOD_Hurts == PassOnDeath)"); fflush (stdout);
- if (kPOD_Hurts == PassOnDeath)
- {
- // Find out how player died
- int KillerID;
- bz_eTeamType KillerTeam;
- bz_eTeamType playerTeam;
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (getPlayerKiller)"); fflush (stdout);
- if (!getPlayerKiller(PendingDropEvent.PlayerThatDroppedTheFlag, playerTeam, KillerID, KillerTeam))
- return; // Not a standard kill, so just drop the flag
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent ((eNoTeam == KillerTeam) || (kInvalidPlayerID == KillerID) || (eNoTeam == playerTeam) || (kInvalidPlayerID == PendingDropEvent.PlayerThatDroppedTheFlag))"); fflush (stdout);
- if ((eNoTeam == KillerTeam) || (kInvalidPlayerID == KillerID) || (eNoTeam == playerTeam) || (kInvalidPlayerID == PendingDropEvent.PlayerThatDroppedTheFlag))
- return; // Not a standard kill, so just drop the flag
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (kHPO_ToNonTeamKiller == HurtOption)"); fflush (stdout);
- if (kHPO_ToNonTeamKiller == HurtOption)
- if (playerTeam == KillerTeam)
- return; // Just drop it, it was a TK
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessDropEvent (kHPO_ToKiller == HurtOption)"); fflush (stdout);
- if (kHPO_ToKiller == HurtOption)
- {
- float FlagDropPos[3];
- if (getPlayerPosition(KillerID, FlagDropPos))
- {
- bz_debugMessagef(DbgLevelDbgInfo, " KillerPos(HurtOption): %f, %f, %f", FlagDropPos[0], FlagDropPos[1], FlagDropPos[2]); fflush (stdout);
- }
- else
- {
- bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: KillerPos(HurtOption): ERR"); fflush (stdout);
- return;
- }
- ValidFlagThrow = do_checkFlagDropAtPoint(PendingDropEvent.DroppedFlagID, FlagDropPos, FlagLandingPos);
- if (!ValidFlagThrow)
- return; // Killer is not in a safe location for a flag
- NeedToCalculateLandingPos = false;
- }
- }
- // kPOD_Yes is active so just let things continue
- }
- if (NeedToCalculateLandingPos)
- {
- float FlagDropPos[3];
- float JumpBoost = 1.0;
- if (PendingDropEvent.PlayerVelocityAtThisTime[2]>0.0)
- JumpBoost = 2.0;
- else
- if (PendingDropEvent.PlayerVelocityAtThisTime[2]<0.0)
- JumpBoost = 0.5;
- FlagDropPos[0] = PendingDropEvent.PlayerPosAtThisTime[0] + FPassThrowDistance * PendingDropEvent.PlayerVelocityAtThisTime[0] * JumpBoost;
- FlagDropPos[1] = PendingDropEvent.PlayerPosAtThisTime[1] + FPassThrowDistance * PendingDropEvent.PlayerVelocityAtThisTime[1] * JumpBoost;
- FlagDropPos[2] = PendingDropEvent.DropPos[2];
- bool PassWasFumbled = false;
- int TriesLeft = MaxSafeZoneTests;
- float DeltaX, DeltaY ;
- DeltaX = DeltaY = 0.0;
- if (0 < MaxSafeZoneTests)
- {
- DeltaX = (PendingDropEvent.PlayerPosAtThisTime[0] - FlagDropPos[0])/MaxSafeZoneTests;
- DeltaY = (PendingDropEvent.PlayerPosAtThisTime[1] - FlagDropPos[1])/MaxSafeZoneTests;
- }
- do
- {
- ValidFlagThrow = do_checkFlagDropAtPoint(PendingDropEvent.DroppedFlagID, FlagDropPos, FlagLandingPos);
- // Check for flags that were left up high
- if (ValidFlagThrow)
- ValidFlagThrow = FlagLandingPos[2] <= FlagDropPos[2];
- // Check for flags that need to be moved
- if (ValidFlagThrow)
- ValidFlagThrow = (FlagLandingPos[0] == FlagDropPos[0]) && (FlagLandingPos[1] == FlagDropPos[1]); // Perhaps we should allow a tolerance here
- if (!PassWasFumbled)
- PassWasFumbled = !ValidFlagThrow;
- TriesLeft--;
- if ((!ValidFlagThrow) && (TriesLeft >= 0))
- {
- FlagDropPos[0] += DeltaX;
- FlagDropPos[1] += DeltaY;
- }
- }
- while ((!ValidFlagThrow) && (TriesLeft >= 0));
- if (PassWasFumbled && ValidFlagThrow)
- {
- if (kFMO_TellEveryone == FumbleMsg)
- {
- bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "%s fumbled the pass.", GetActivePlayerStatsByID(PendingDropEvent.PlayerThatDroppedTheFlag)->callsign.c_str());
- }
- else if (kFMO_TellPlayer == FumbleMsg)
- {
- int randomMsg = rand() % kMaxFumbledPassMessages;
- bz_sendTextMessagef(BZ_SERVER, PendingDropEvent.PlayerThatDroppedTheFlag, kFumbledPassMessages[randomMsg]);
- }
- }
- }
- if (ValidFlagThrow)
- {
- FlagInfo& flag = *FlagInfo::get(PendingDropEvent.DroppedFlagID);
- flag.dropFlag(PendingDropEvent.DropPos, FlagLandingPos, false);
- sendDrop(flag);
- sendFlagUpdate(flag);
- bz_debugMessagef(DbgLevelDbgInfo, " FlagLandingPos: %f, %f, %f", FlagLandingPos[0], FlagLandingPos[1], FlagLandingPos[2]); fflush (stdout);
- }
- }
- // Locate any pending drop events for player PlayerID and process them
- // Written to handle more than one, although since we call this on bz_eFlagGrabbedEvent it should not be possible
- void ProcessPendingEventsForPlayer(int PlayerID)
- {
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessPendingEventsForPlayer: Looking for=%d", PlayerID); fflush (stdout);
- std::vector<DropEvent>::iterator iter = gPendingDropEvents.begin();
- while( iter != gPendingDropEvents.end() )
- {
- if (iter->PlayerThatDroppedTheFlag == PlayerID)
- {
- bz_debugMessagef(DbgLevelDbgInfo, "ProcessPendingEventsForPlayer: found PlayerThatDroppedTheFlag=%d", iter->PlayerThatDroppedTheFlag); fflush (stdout);
- ProcessDropEvent( *iter );
- iter = gPendingDropEvents.erase( iter );
- }
- else
- ++iter;
- }
- }
- // If the user has a bad connection or is NR then we want to get rid of any drop events they have pending
- void RemoveOldEvents(float CurrentTime)
- {
- std::vector<DropEvent>::iterator iter = gPendingDropEvents.begin();
- while( iter != gPendingDropEvents.end() )
- {
- if ((CurrentTime - iter->TimeEventOccurred) > MaxWaitForReason)
- {
- 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);
- if (AllowMaxWaitMod)
- {
- // Give some feedback to allow some tweeking
- bz_sendTextMessagef(BZ_SERVER, iter->PlayerThatDroppedTheFlag, "Pass ignored! Your client took too long to respond. I waited %.3f seconds.", CurrentTime - iter->TimeEventOccurred);
- }
- iter = gPendingDropEvents.erase( iter );
- }
- else
- ++iter;
- }
- }
- //================================= Communication from the server ======================================================
- // handle events
- void FPassHandler::process ( bz_EventData *eventData )
- {
- if (AllowMaxWaitMod)
- {
- // Give some feedback to allow some tweeking
- bz_debugMessagef(0, "FPassHandler::process eventType=%d seconds= %f", eventData->eventType, TimeKeeper::getCurrent().getSeconds()); fflush (stdout);
- }
- // ***************************************
- // Flag Dropped (bz_eFlagDroppedEvent)
- // ***************************************
- if (bz_eFlagDroppedEvent == eventData->eventType)
- {
- bz_FlagDroppedEventData *dropData = (bz_FlagDroppedEventData*)eventData;
- FlagInfo& thisFlag = *FlagInfo::get(dropData->flagID);
- int flagTeam = thisFlag.flag.type->flagTeam;
- if ((kPassing_Off != FPassEnabled) && ((eNoTeam != flagTeam) || PassAllFlags))
- {
- // Find out why the flag is being dropped
- GameKeeper::Player *playerData = GameKeeper::Player::getPlayerByIndex(dropData->playerID);
- bz_debugMessagef(DbgLevelDbgInfo, "bz_eFlagDroppedEvent (!playerData)"); fflush (stdout);
- if (!playerData)
- return; // player not known
- bz_debugMessagef(DbgLevelDbgInfo, "bz_eFlagDroppedEvent (playerData->isParting)"); fflush (stdout);
- if (playerData->isParting)
- return; // Player is being kicked - Just handle as a normal drop
- bz_debugMessagef(DbgLevelDbgInfo, "bz_eFlagDroppedEvent (!playerData->player.isHuman())"); fflush (stdout);
- if (!playerData->player.isHuman())
- return; // Not for this plugin to handle
- // We will not know exactly why the flag was dropped until the client tells us
- // So remember this event and check later when we have better data to work with
- float PlayerPos[3];
- float PlayerVelocity[3];
- if (getPlayerVelocity(dropData->playerID, PlayerVelocity))
- {
- bz_debugMessagef(DbgLevelDbgInfo, " velocity: %f, %f, %f", PlayerVelocity[0], PlayerVelocity[1], PlayerVelocity[2]); fflush (stdout);
- }
- else
- {
- bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: velocity: ERR"); fflush (stdout);
- return;
- }
- if (getPlayerPosition(dropData->playerID, PlayerPos))
- {
- bz_debugMessagef(DbgLevelDbgInfo, " PlayerPos: %f, %f, %f", PlayerPos[0], PlayerPos[1], PlayerPos[2]); fflush (stdout);
- }
- else
- {
- bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: PlayerPos: ERR"); fflush (stdout);
- return;
- }
- DropEvent ThisFlagDrop(dropData->playerID, dropData->flagID, dropData->pos, PlayerPos, PlayerVelocity);
- if (kPassing_Immediate == FPassEnabled)
- {
- // We do not care about the fancy options we just want an immediate response
- ProcessDropEvent(ThisFlagDrop);
- }
- else
- {
- if ((0.0 == PlayerVelocity[0]) && (0.0 == PlayerVelocity[1]))
- if (kPOD_No == PassOnDeath)
- return; // Nothing to do here - It will just drop anyway
- // Fancy options come at a price. The can be a delay before flag starts to fly.
- // It just means there is more to learn for your flag-passing skills
- gPendingDropEvents.push_back(ThisFlagDrop);
- bz_debugMessagef(DbgLevelDbgInfo, "gPendingDropEvents added (player=%d Flag=%d)", dropData->playerID, dropData->flagID); fflush (stdout);
- }
- }
- }
- // ***************************************
- // Player Update (bz_ePlayerUpdateEvent)
- // ***************************************
- else if (bz_ePlayerUpdateEvent == eventData->eventType)
- {
- bz_PlayerUpdateEventData* playerupdatedata = (bz_PlayerUpdateEventData*)eventData;
- //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);
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(playerupdatedata->playerID);
- if (StatsForThisPlayer->thisPlayerID == playerupdatedata->playerID)
- {
- StatsForThisPlayer->SetStats(playerupdatedata->playerID, playerupdatedata->velocity);
- ProcessPendingEventsForPlayer(playerupdatedata->playerID);
- //bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler: PlayerUpdateEvent for player %d", playerupdatedata->playerID); fflush (stdout);
- }
- else
- {
- bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: PlayerUpdate: ERR"); fflush (stdout);
- }
- }
- // ***************************************
- // Player Spawned (bz_ePlayerSpawnEvent)
- // ***************************************
- else if (bz_ePlayerSpawnEvent == eventData->eventType)
- {
- bz_PlayerSpawnEventData* birthDetails = (bz_PlayerSpawnEventData*)eventData;
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(birthDetails->playerID);
- if (StatsForThisPlayer->thisPlayerID == birthDetails->playerID)
- {
- StatsForThisPlayer->SetKiller(kInvalidPlayerID, eNoTeam);
- }
- else
- {
- bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: PlayerUpdate(bz_ePlayerSpawnEvent): ERR"); fflush (stdout);
- }
- }
- // ***************************************
- // Player Died (bz_ePlayerDieEvent)
- // ***************************************
- else if (bz_ePlayerDieEvent == eventData->eventType)
- {
- bz_PlayerDieEventData* deathDetails = ( bz_PlayerDieEventData*)eventData;
- PlayerStats *StatsForThisPlayer = GetActivePlayerStatsByID(deathDetails->playerID);
- if (StatsForThisPlayer->thisPlayerID == deathDetails->playerID)
- {
- bz_debugMessagef(DbgLevelDbgInfo, "bz_ePlayerDieEvent (%d killed by %d of tesm %d)", deathDetails->playerID, deathDetails->killerID, deathDetails->killerTeam); fflush (stdout);
- StatsForThisPlayer->SetKiller(deathDetails->killerID, deathDetails->killerTeam);
- ProcessPendingEventsForPlayer(deathDetails->playerID);
- }
- else
- {
- bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: PlayerUpdate(bz_ePlayerDieEvent): ERR"); fflush (stdout);
- }
- }
- // ***************************************
- // Player Joined (bz_ePlayerJoinEvent)
- // ***************************************
- else if (bz_ePlayerJoinEvent == eventData->eventType)
- {
- bz_PlayerJoinPartEventData *joinData = (bz_PlayerJoinPartEventData*)eventData;
- if (joinData->team != eObservers)
- {
- float NoVelocity[3];
- NoVelocity[0] = NoVelocity[1] = NoVelocity[2] = 0.0;
- PlayerStats NewPlayer(joinData->playerID, joinData->team, NoVelocity, &joinData->callsign);
- gActivePlayers.push_back(NewPlayer);
- bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler: created PlayerStats for %d", joinData->playerID); fflush (stdout);
- }
- }
- // ***************************************
- // Player Left (bz_ePlayerPartEvent)
- // ***************************************
- else if (bz_ePlayerPartEvent == eventData->eventType)
- {
- bz_PlayerJoinPartEventData *partingData = (bz_PlayerJoinPartEventData*)eventData;
- if (partingData->team != eObservers)
- {
- if (RemovePlayerStatsForPlayerID(partingData->playerID))
- {
- bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler: removed PlayerStats for %d", partingData->playerID); fflush (stdout);
- }
- else
- {
- bz_debugMessagef(DbgLevelErr, "++++++ FPassHandler: ERR no PlayerStats for player %d", partingData->playerID); fflush (stdout);
- }
- }
- }
- // ***************************************
- // Player Left (bz_eFlagGrabbedEvent)
- // ***************************************
- else if (bz_eFlagGrabbedEvent == eventData->eventType)
- {
- bz_FlagGrabbedEventData *msgData = (bz_FlagGrabbedEventData*)eventData;
- // If the client has told us about grabbing a flag we know that we have enough information to process any pending drop event
- ProcessPendingEventsForPlayer(msgData->playerID);
- }
- // ***************************************
- // Player Left (bz_eTickEvent)
- // ***************************************
- else if (bz_eTickEvent == eventData->eventType)
- {
- bz_TickEventData *msgData = (bz_TickEventData*)eventData;
- RemoveOldEvents ((float)msgData->time);
- }
- }
- #define kMaxCmdParamSize kWorkStrLen
- #define kAdminPermission ""
- #define kCountdownPermission "COUNTDOWN"
- #define kCmdLine_Cmd "fpass"
- #define kOption_teamflagsonly "teamflagsonly"
- #define kOption_PassToNonTeamKiller "pass2nontkiller"
- #define kOption_PassToAnyKiller "pass2anykiller"
- #define kOption_PreventMaxWaitMofification "mwmodify"
- #define kOption_maxwait "maxwait"
- #define kCmdLineParam_maxwait kOption_maxwait"="
- #define kOption_dist "dist"
- #define kCmdLineParam_distance kOption_dist"="
- #define kOption_steps "steps"
- #define kCmdLineParam_SafeLandingAttempts kOption_steps"="
- #define kOption_FumbleMsg "fmsg"
- #define kCmdLineParam_FumbleMsg kOption_FumbleMsg"="
- #define kOption_AllFlags "allflags"
- #define kCmdLineParam_AllFlags kOption_AllFlags"="
- #define kOption_PassOnDeath "passondeath"
- #define kCmdLineParam_PassOnDeath kOption_PassOnDeath"="
- #define kOption_Hurt "hurt"
- #define kCmdLineParam_Hurt kOption_Hurt"="
- // handle /FPass command
- bool FPassHandler::handle ( int playerID, bzApiString cmd, bzApiString, bzAPIStringList* cmdParams )
- {
- char subCmd[kWorkStrLen];
- if (strcasecmp (cmd.c_str(), kCmdLine_Cmd)) // is it for me ?
- return false;
- if (cmdParams->get(0).c_str()[0] == '\0'){
- sendHelp (playerID);
- return true;
- }
- bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler::handle: cmdParams->get(0).c_str() = \"%s\"", cmdParams->get(0).c_str()); fflush (stdout);
- strncpy (subCmd, cmdParams->get(0).c_str(), kWorkStrLen-1);
- subCmd[kWorkStrLen-1] = '\0';
- bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler::handle: subCmd = \"%s\"", subCmd); fflush (stdout);
- // kCmdLineParam_distance
- if (strncasecmp (subCmd, kCmdLineParam_distance, strlen(kCmdLineParam_distance)) == 0)
- {
- if (checkPerms (playerID, kOption_dist, kAdminPermission))
- {
- if (!SetThrowDistance(cmdParams->get(0).c_str() + strlen(kCmdLineParam_distance), NULL))
- {
- sendHelp(playerID);
- }
- }
- }
- // kCmdLineParam_maxwait
- else if (strncasecmp (subCmd, kOption_maxwait, strlen(kOption_maxwait)) == 0)
- {
- if (checkPerms (playerID, kOption_maxwait, kAdminPermission))
- {
- if ((AllowMaxWaitMod) && ('=' == cmdParams->get(0).c_str()[strlen(kOption_maxwait)]))
- SetMaxWaitVal(cmdParams->get(0).c_str() + strlen(kCmdLineParam_maxwait), NULL);
- sendMaxWaitMsg(playerID);
- }
- }
- // kCmdLineParam_FumbleMsg
- else if (strncasecmp (subCmd, kCmdLineParam_FumbleMsg, strlen(kCmdLineParam_FumbleMsg)) == 0)
- {
- if (checkPerms (playerID, kOption_FumbleMsg, kAdminPermission))
- {
- char CmdParam[kMaxCmdParamSize];
- strncpy (CmdParam, cmdParams->get(0).c_str() + strlen(kCmdLineParam_FumbleMsg), kMaxCmdParamSize-1);
- if (strcasecmp (CmdParam, "off") == 0)
- FumbleMsgEnable (kFMO_NoMessages, playerID);
- else if (strcasecmp (CmdParam, "all") == 0)
- FumbleMsgEnable (kFMO_TellEveryone, playerID);
- else if (strcasecmp (CmdParam, "player") == 0)
- FumbleMsgEnable (kFMO_TellPlayer, playerID);
- else
- {
- sendHelp(playerID);
- }
- }
- }
- // kCmdLineParam_AllFlags
- else if (strncasecmp (subCmd, kCmdLineParam_AllFlags, strlen(kCmdLineParam_AllFlags)) == 0)
- {
- if (checkPerms (playerID, kOption_AllFlags, kAdminPermission))
- {
- char CmdParam[kMaxCmdParamSize];
- strncpy (CmdParam, cmdParams->get(0).c_str() + strlen(kCmdLineParam_AllFlags), kMaxCmdParamSize-1);
- if (strcasecmp (CmdParam, "off") == 0)
- AllFlagsEnable (false, playerID);
- else if (strcasecmp (CmdParam, "on") == 0)
- AllFlagsEnable (true, playerID);
- else
- {
- sendHelp(playerID);
- }
- }
- }
- // kCmdLineParam_SafeLandingAttempts
- else if (strncasecmp (subCmd, kCmdLineParam_SafeLandingAttempts, strlen(kCmdLineParam_SafeLandingAttempts)) == 0)
- {
- if (checkPerms (playerID, kOption_steps, kAdminPermission))
- {
- if (!SetMaxIterations(cmdParams->get(0).c_str() + strlen(kCmdLineParam_SafeLandingAttempts), NULL))
- {
- sendHelp(playerID);
- }
- }
- }
- // kCmdLineParam_PassOnDeath
- else if (strncasecmp (subCmd, kCmdLineParam_PassOnDeath, strlen(kCmdLineParam_PassOnDeath)) == 0)
- {
- if (checkPerms (playerID, kOption_PassOnDeath, kAdminPermission))
- {
- char CmdParam[kMaxCmdParamSize];
- strncpy (CmdParam, cmdParams->get(0).c_str() + strlen(kCmdLineParam_PassOnDeath), kMaxCmdParamSize-1);
- bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler::handle: subCmd = \"%s\" CmdParam=\"%s\"", kCmdLineParam_PassOnDeath, CmdParam); fflush (stdout);
- if (strcasecmp (CmdParam, "off") == 0)
- SetPassingOnDeathOption (kPOD_No, playerID);
- else if (strcasecmp (CmdParam, "on") == 0)
- SetPassingOnDeathOption (kPOD_Yes, playerID);
- else if (strcasecmp (CmdParam, "hurts") == 0)
- SetPassingOnDeathOption (kPOD_Hurts, playerID);
- else
- {
- sendHelp(playerID);
- }
- }
- }
- // hurt
- else if (strncasecmp (subCmd, kCmdLineParam_Hurt, strlen(kCmdLineParam_Hurt)) == 0)
- {
- if (checkPerms (playerID, kOption_Hurt, kAdminPermission))
- {
- char CmdParam[kMaxCmdParamSize];
- strncpy (CmdParam, cmdParams->get(0).c_str() + strlen(kCmdLineParam_Hurt), kMaxCmdParamSize-1);
- bz_debugMessagef(DbgLevelDbgInfo, "++++++ FPassHandler::handle: subCmd = \"%s\" CmdParam=\"%s\"", kCmdLineParam_Hurt, CmdParam); fflush (stdout);
- if (strcasecmp (CmdParam, "killr") == 0)
- SetHurtingOption (kHPO_ToKiller, playerID);
- else if (strcasecmp (CmdParam, "nontker") == 0)
- SetHurtingOption (kHPO_ToNonTeamKiller, playerID);
- else
- {
- sendHelp(playerID);
- }
- }
- }
- // off
- else if (strcasecmp (subCmd, "off") == 0)
- {
- if (checkPerms (playerID, "off", kCountdownPermission))
- FPassEnable (kPassing_Off, playerID);
- }
- // on
- else if (strcasecmp (subCmd, "on") == 0)
- {
- if (checkPerms (playerID, "on", kCountdownPermission))
- FPassEnable (kPassing_On, playerID);
- }
- // immediate
- else if (strcasecmp (subCmd, "immediate") == 0)
- {
- if (checkPerms (playerID, "immediate", kCountdownPermission))
- FPassEnable (kPassing_Immediate, playerID);
- }
- // reset
- else if (strcasecmp (subCmd, "reset") == 0)
- {
- if (checkPerms (playerID, "reset", kAdminPermission))
- ResetAllVariables (playerID);
- }
- // stat
- else if (strcasecmp (subCmd, "stat") == 0)
- FPassStats (playerID);
- // help
- else if (strcasecmp (subCmd, "help") == 0)
- FPassSendDesc (playerID);
- else
- sendHelp (playerID);
- return true;
- }
- //================================= Examine which options were set at loadplugin time ======================================================
- bool commandLineHelp (void){
- const char *help[] = {
- "Command line args: -loadplugin PLUGINNAME[,teamflagsonly][,passondeath|pass2nontkiller|pass2anykiller][,maxwait=<0.0 .. 3.0>][,mwmodify][,dist=<0.0 .. 20.0>][,steps=<0 .. 20>],",
- " The options are available to set things other than the default values.",
- " Specifying \"teamflagsonly\" is equivalent to /fpass allflags=off",
- " passondeath is equivalent to /fpass passondeath=on",
- " pass2nontkiller is equivalent to /fpass passondeath=hurt",
- " pass2anykiller is equivalent to /fpass passondeath=hurt and /fpass hurt=killr",
- " maxwait specifies how long we will wait to find out why the user dropped the flag",
- " mwmodify will enable \"/fpass maxwait\" command from modifying the value",
- "",
- " 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.",
- "",
- " Example: -loadplugin PassTheFlag,teamflagsonly,dist=6.0,steps=5 is fine",
- " but -loadplugin PassTheFlag,dist=6.0,teamflagsonly,steps=5 will result in an error.",
- NULL
- };
- bz_debugMessage (0, "+++ PassTheFlag plugin command-line error");
- for (int x=0; help[x]!=NULL; x++)
- bz_debugMessage (0, help[x]);
- return true;
- }
- bool parseCommandLine (const char *cmdLine)
- {
- int CharOffset = 0;
- if (cmdLine==NULL || *cmdLine=='\0')
- return false;
- //bz_debugMessagef(1, "parseCommandLine: parseCommandLine cmdLine = \"%s\"", cmdLine); fflush (stdout);
- //bz_debugMessagef(1, "parseCommandLine: parseCommandLine cmdLine + %d = \"%s\"", CharOffset, cmdLine + CharOffset); fflush (stdout);
- if (strncasecmp (cmdLine + CharOffset, kOption_teamflagsonly, strlen(kOption_teamflagsonly)) == 0)
- {
- AllFlagsEnable(false, kInvalidPlayerID);
- CharOffset += strlen(kOption_teamflagsonly) + 1;
- AssignResetVal(PassAllFlags);
- }
- if (strncasecmp (cmdLine + CharOffset, kOption_PassOnDeath, strlen(kOption_PassOnDeath)) == 0)
- {
- SetPassingOnDeathOption(kPOD_Yes, kInvalidPlayerID);
- CharOffset += strlen(kOption_PassOnDeath) + 1;
- AssignResetVal(PassOnDeath);
- }
- if (strncasecmp (cmdLine + CharOffset, kOption_PassToNonTeamKiller, strlen(kOption_PassToNonTeamKiller)) == 0)
- {
- SetPassingOnDeathOption(kPOD_Hurts, kInvalidPlayerID);
- SetHurtingOption(kHPO_ToNonTeamKiller, kInvalidPlayerID); // Is the default option, but set it anyway
- CharOffset += strlen(kOption_PassToNonTeamKiller) + 1;
- AssignResetVal(PassOnDeath);
- AssignResetVal(HurtOption);
- }
- if (strncasecmp (cmdLine + CharOffset, kOption_PassToAnyKiller, strlen(kOption_PassToAnyKiller)) == 0)
- {
- SetPassingOnDeathOption(kPOD_Hurts, kInvalidPlayerID);
- SetHurtingOption(kHPO_ToKiller, kInvalidPlayerID);
- CharOffset += strlen(kOption_PassToAnyKiller) + 1;
- AssignResetVal(PassOnDeath);
- AssignResetVal(HurtOption);
- }
- //bz_debugMessagef(1, "parseCommandLine: parseCommandLine cmdLine + %d = \"%s\"", CharOffset, cmdLine + CharOffset); fflush (stdout);
- if (strncasecmp (cmdLine + CharOffset, kCmdLineParam_maxwait, strlen(kCmdLineParam_maxwait)) == 0)
- {
- int CharsUsed = 0;
- if (!SetMaxWaitVal(cmdLine+CharOffset+strlen(kCmdLineParam_maxwait), &CharsUsed))
- return commandLineHelp ();
- else
- CharOffset += strlen(kCmdLineParam_maxwait) + 1 + CharsUsed;
- AssignResetVal(MaxWaitForReason);
- }
- if (strncasecmp (cmdLine + CharOffset, kOption_PreventMaxWaitMofification, strlen(kOption_PreventMaxWaitMofification)) == 0)
- {
- AllowMaxWaitMod = true;
- CharOffset += strlen(kOption_PreventMaxWaitMofification) + 1;
- }
- if (strncasecmp (cmdLine + CharOffset, kCmdLineParam_distance, strlen(kCmdLineParam_distance)) == 0)
- {
- int CharsUsed = 0;
- if (!SetThrowDistance(cmdLine+CharOffset+strlen(kCmdLineParam_distance), &CharsUsed))
- return commandLineHelp ();
- else
- CharOffset += strlen(kCmdLineParam_distance) + 1 + CharsUsed;
- AssignResetVal(FPassThrowDistance);
- }
- //bz_debugMessagef(1, "parseCommandLine: parseCommandLine cmdLine + %d = \"%s\"", CharOffset, cmdLine + CharOffset); fflush (stdout);
- if (strncasecmp (cmdLine + CharOffset, kCmdLineParam_SafeLandingAttempts, strlen(kCmdLineParam_SafeLandingAttempts)) == 0)
- {
- int CharsUsed = 0;
- if (!SetMaxIterations(cmdLine+CharOffset+strlen(kCmdLineParam_SafeLandingAttempts), &CharsUsed))
- return commandLineHelp ();
- else
- CharOffset += strlen(kCmdLineParam_SafeLandingAttempts) + 1 + CharsUsed;
- AssignResetVal(MaxSafeZoneTests);
- }
- if ('\0' != cmdLine[CharOffset])
- {
- // We did not process all the parameters
- bz_debugMessage (0, "+++ PassTheFlag plugin command-line error: Some parameters were not processed.");
- bz_debugMessage (0, &cmdLine[CharOffset]);
- return commandLineHelp ();
- }
- return false;
- }
- //================================= Required entry points called by the server ======================================================
- // Tells the server which version of the bzfsAPI.h this plugin was generated with
- BZ_GET_PLUGIN_VERSION
- // Called by the server when the plugin is loaded
- BZF_PLUGIN_CALL int bz_Load (const char* cmdLine)
- {
- // Check what options were set and complain if there was a problem
- if (parseCommandLine (cmdLine))
- return -1;
- /* initialize random seed: */
- srand ( time(NULL) );
- // Set up how we want to commmunicate with the server
- bz_registerCustomSlashCommand (kCmdLine_Cmd, &FlagPassHandler);
- bz_registerEvent(bz_ePlayerDieEvent,&FlagPassHandler);
- bz_registerEvent(bz_ePlayerSpawnEvent,&FlagPassHandler);
- bz_registerEvent(bz_eFlagDroppedEvent, &FlagPassHandler);
- bz_registerEvent(bz_ePlayerJoinEvent, &FlagPassHandler);
- bz_registerEvent(bz_ePlayerPartEvent, &FlagPassHandler);
- bz_registerEvent(bz_ePlayerUpdateEvent, &FlagPassHandler);
- bz_registerEvent(bz_eFlagGrabbedEvent, &FlagPassHandler);
- bz_registerEvent(bz_eTickEvent, &FlagPassHandler);
- bz_setMaxWaitTime (MaxWaitForReason);
- // Show everything loaded without a problem
- bz_debugMessagef(DbgLevelAlways, "PassTheFlag plugin loaded - v%s ApiVersion=v%d%s", PASSTHEFLAG_VER, BZ_API_VERSION, AllowMaxWaitMod?" maxwait modification enabled":" maxwait modification disabled");
- return 0;
- }
- // Called by the server when the plugin is unloaded
- BZF_PLUGIN_CALL int bz_Unload (void)
- {
- // Stop communications with the server
- bz_removeCustomSlashCommand (kCmdLine_Cmd);
- bz_removeEvent (bz_ePlayerDieEvent, &FlagPassHandler);
- bz_removeEvent (bz_ePlayerSpawnEvent, &FlagPassHandler);
- bz_removeEvent (bz_eFlagDroppedEvent, &FlagPassHandler);
- bz_removeEvent (bz_ePlayerJoinEvent, &FlagPassHandler);
- bz_removeEvent (bz_ePlayerPartEvent, &FlagPassHandler);
- bz_removeEvent (bz_ePlayerUpdateEvent, &FlagPassHandler);
- bz_removeEvent (bz_eFlagGrabbedEvent, &FlagPassHandler);
- bz_removeEvent (bz_eTickEvent, &FlagPassHandler);
- // Show that this plugin is no longer active
- bz_debugMessage(DbgLevelAlways, "PassTheFlag plugin unloaded");
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement