//////////////////////////////////////////////////////////////////////////////// // Scorched3D (c) 2000-2003 // // This file is part of Scorched3D. // // Scorched3D is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Scorched3D is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include static OptionEntryEnum::EnumEntry scoreEnum[] = { { "ScoreWins", 0 }, { "ScoreKills", 1 }, { "ScoreMoney", 2 }, { "", -1 } }; static OptionEntryEnum::EnumEntry turnEnum[] = { { "TurnSimultaneous", 0 }, { "TurnSequentialLooserFirst", 1 }, { "TurnSequentialRandom", 2 }, { "", -1 } }; static OptionEntryEnum::EnumEntry windForceEnum[] = { { "WindRandom", 0 }, { "WindNone", 1 }, { "Wind1", 2 }, { "Wind2", 3 }, { "Wind3", 4 }, { "Wind4", 5 }, { "Wind5", 6 }, { "WindBreezy", 7 }, { "WindGale", 8 }, { "", -1 } }; static OptionEntryEnum::EnumEntry windTypeEnum[] = { { "WindOnRound", 0 }, { "WindOnMove", 1 }, { "", -1 } }; static OptionEntryEnum::EnumEntry wallEnum[] = { { "WallRandom", 0 }, { "WallConcrete", 1 }, { "WallBouncy", 2 }, { "WallWrapAround", 3 }, { "WallNone", 4 }, { "", -1 } }; static OptionEntryEnum::EnumEntry weapScaleEnum[] = { { "ScaleSmall", 0 }, { "ScaleMedium", 1 }, { "ScaleLarge", 2 }, { "", -1 } }; static OptionEntryEnum::EnumEntry resignEnum[] = { { "ResignStart", 0 }, { "ResignEnd", 1 }, { "ResignDueToHealth", 2 }, { "", -1 } }; static OptionEntryEnum::EnumEntry movementRestrictionEnum[] = { { "MovementRestrictionNone", 0 }, { "MovementRestrictionLand", 1 }, { "MovementRestrictionLandOrAbove", 2 }, { "", -1 } }; static OptionEntryEnum::EnumEntry teamBallanceEnum[] = { { "TeamBallanceNone", 0 }, { "TeamBallanceAuto", 1 }, { "TeamBallanceBotsVs", 2 }, { "TeamBallanceAutoByScore", 3 }, { "TeamBallanceAutoByBots", 4 }, { "", -1 } }; static OptionEntryStringEnum::EnumEntry economyEnum[] = { { "EconomyFreeMarket" }, { "EconomyNone" }, { "" } }; OptionsGame::OptionsGame() : physicsFPS_(options_, "PhysicsFPS", "The speed at which the physics engine will calculate steps", 0, 66, 20, 100, 1), tutorial_(options_, "Tutorial", "The tutorial to load for this game", 0, ""), scorePerMoney_(options_, "ScorePerMoney", "The amount of score awarded for 100 money units earned", 0, 0, 0, 100, 2), scorePerAssist_(options_, "ScorePerAssist", "The amount of score awarded for each kill assist", 0, 2, 0, 50, 1), scorePerKill_(options_, "ScorePerKill", "The amount of score awarded for each kill", 0, 10, 0, 50, 1), scoreWonForRound_(options_, "ScoreWonForRound", "The amount of score awarded for round won", 0, 250, 0, 1000, 50), scoreWonForLives_(options_, "ScoreWonForLives", "The amount of score awarded for lives left", 0, 250, 0, 1000, 50), teams_(options_, "Teams", "The number of teams (1 == no teams)", 0, 1, 1, 4, 1), startArmsLevel_(options_, "StartArmsLevel", "The largest weapon type allowed (on round 1)", 0, 10, 0, 10, 1), endArmsLevel_(options_, "EndArmsLevel", "The largest weapon type allowed (on the last round)", 0, 10, 0, 10, 1), maxNumberWeapons_(options_, "MaxNumberWeapons", "The number of each weapon the player is allowed", 0, 90, 0, 500, 10), maxLandscapeSize_(options_, "MaxLandscapeSize", "The largest landscape (in bytes) that will be sent to the clients", 0, 200000), startTime_(options_, "StartTime", "The amount of time before a new game starts", 0, 0, 0, 90, 5), shotTime_(options_, "ShotTime", "The amount of time each player has for each shot", 0, 0, 0, 90, 5), buyingTime_(options_, "BuyingTime", "The amount of time each player has to buy weapons and use auto defense", 0, 0, 0, 90, 5), allowedMissedMoves_(options_, "AllowedMissedMoves", "The number of moves a player is allowed to miss (due to the shot timer)", 0, 3, 0, 10, 1), roundScoreTime_(options_, "RoundScoreTime", "The amount of time to show the end of each round for", 0, 5, 0, 30, 1), scoreTime_(options_, "ScoreTime", "The amount of time to show the end of match scores for", 0, 15, 0, 90, 5), keepAliveTime_(options_, "KeepAliveTime", "The amount of time between each client keep alive message", 0, 2, 0, 30, 1), keepAliveTimeoutTime_(options_, "KeepAliveTimeoutTIme", "The amount of time the server will allow without receiving a keep alive message", 0, 0, 0, 90, 5), idleKickTime_(options_, "IdleKickTime", "The amount of time to give clients to respond after level loading before kicking them", 0, 60, 0, 90, 5), idleShotKickTime_(options_, "IdleShotKickTime", "The amount of time to give clients to respond after shots before kicking them", 0, 45, 0, 90, 5), minFallingDistance_(options_, "MinFallingDistance", "The minimum distance that can be made with no damage (value is divided by 10)", 0, 5, 0, 100, 5), maxClimbingDistance_(options_, "MaxClimbingDistance", "The maximum distance that a tank can climb per movement square (divided by 10)", 0, 8, 0, 20, 1), playerLives_(options_, "PlayerLives", "The number of lives that each player tank has", 0, 1, 0, 10, 1), gravity_(options_, "Gravity", "The gravity used by the physics engine", 0, -10, -25, 0, 1), maxRoundTurns_(options_, "MaxNumberOfRoundTurns", "The maximum number of turns all players are allowed in each round (0 = infinite)", 0, 15, 0, 50, 1), numberOfRounds_(options_, "NumberOfRounds", "The number of rounds to play in each game", 0, 5, 1, 50, 1), numberOfPlayers_(options_, "NumberOfPlayers", "The maximum number of players to allow", 0, 2, 2, 24, 1), numberOfMinPlayers_(options_, "NumberOfMinPlayers", "The minimum number of players to allow", 0, 2, 2, 24, 1), removeBotsAtPlayers_(options_, "RemoveBotsAtPlayers", "The number of players to allow before remvoing bots", 0, 0, 0, 24, 1), limitPowerByHealth_(options_, "LimitPowerByHealth", "Show power is limited by the amount of health a player has", 0, true), residualPlayers_(options_, "ResidualPlayers", "Players that leave will have the same state when reconnecting", 0, true), resignMode_(options_, "ResignMode", "When does a players resign take place", 0, int(ResignEnd), resignEnum), movementRestriction_(options_, "MovementRestriction", "Where a tank is allowed to move to", 0, int(MovementRestrictionNone), movementRestrictionEnum), teamBallance_(options_, "TeamBallance", "The mode of team auto-ballancing performed for team games", 0, int(TeamBallanceNone), teamBallanceEnum), turnType_(options_, "TurnType", "The player turn mode", 0, int(TurnSequentialLooserFirst), turnEnum), // Data, default, min, max moneyBuyOnRound_(options_, "MoneyBuyOnRound", "The first round players are allowed to buy on", 0 ,2, 1, 50, 1), moneyWonForRound_(options_, "MoneyWonForRound", "The money awarded for each won round", 0, 5000, 0, 100000, 1000), moneyWonForLives_(options_, "MoneyWonForLives", "The money awarded for each life remaining", 0, 5000, 0, 100000, 1000), moneyPerKillPoint_(options_, "MoneyWonPerKillPoint", "The money awarded for each person killed * weapon used", 0, 750, 0, 2000, 50), moneyPerMultiKillPoint_(options_, "MoneyWonPerMultiKillPoint", "The extra money awarded for each person multi-killed * weapon used * multi-kill", 0, 0, 0, 2000, 50), moneyPerAssistPoint_(options_, "MoneyWonPerAssistPoint", "The money awarded for each kill assist * weapon used", 0, 250, 0, 2000, 50), moneyPerHitPoint_(options_, "MoneyWonPerHitPoint", "The money awarded for each person hit * weapon used", 0, 250, 0, 2000, 50), moneyPerRound_(options_, "MoneyPerRound", "The money given at the end of each round", 0, 0, 0, 250000, 5000), moneyPerHealthPoint_(options_, "MoneyPerHealthPoint", "The money awarded is proportional to the amount of health removed", 0, true), moneyStarting_(options_, "MoneyStarting", "The money each player starts with", 0, 10000, 0, 500000, 10000), moneyInterest_(options_, "MoneyInterest", "The interest awarded at the end of each round", 0, 15, 0, 100, 5), freeMarketAdjustment_(options_, "FreeMarketAdjustment", "The scale of the adjustment changes made by the free market", 0, 100), windForce_(options_, "WindForce", "The force of the wind", 0, int(WindRandom), windForceEnum), windType_(options_, "WindType", "When the wind changes", 0, int(WindOnRound), windTypeEnum), wallType_(options_, "WallType", "The type of walls allowed", 0, int(WallRandom), wallEnum), weapScale_(options_, "WeaponScale", "The scale of the weapons used", 0, int(ScaleMedium), weapScaleEnum), statsLogger_(options_, "StatsLogger", "The type of player stats to be logged (none, pgsql, mysql, file)", 0, "none"), serverFileLogger_(options_, "ServerLogger", "The type of server events to be logged to file (none, file)", 0, "none"), portNo_(options_, "PortNo", "The port to start the server on", 0, ScorchedPort), managementPortNo_(options_, "ManagementPortNo", "The port to start the managament web server on (0 = management off)", 0, 0), serverName_(options_, "ServerName", "The name of the server to start", 0, "No Name"), mod_(options_, "Mod", "The name of currently running Scorched3D mod", 0, "none"), motd_(options_, "MOTD", "The message of the day", 0, "Scorched3D : Copyright 2004 Gavin Camp\n" "For updates and news visit:\n" "http://www.scorched3d.co.uk", true), modDownloadSpeed_(options_, "ModDownloadSpeed", "Max download speed of mods in bytes per second (0 == no mod download)", 0, 0, 0, 250000, 5000), maxAvatarSize_(options_, "MaxAvatarSize", "Max size allowed for avatars in bytes (0 == no avatars)", 0, 5000), economy_(options_, "Economy", "Speicifies the name of the economy to use", 0, "EconomyFreeMarket", economyEnum), landscapes_(options_, "Landscapes", "Colon seperated list of landscape names", 0, ""), serverPassword_(options_, "ServerPassword", "The password for this server (empty password = no password)", OptionEntry::DataProtected, ""), allowSameIP_(options_, "AllowSameIP", "Allow scorched clients from same machine/NAT router to connect.", 0, true), allowSameUniqueId_(options_, "AllowSameUniqueId", "Allow scorched clients with same unique id to connect.", 0, true), publishServer_(options_, "PublishServer", "Allow other scorched net clients to see this server. Do not use for LAN games.", 0, false), publishAddress_(options_, "PublishAddress", "IP address to publish to scorched net clients (auto-detected if not given).", 0, "AutoDetect"), botNamePrefix_(options_, "BotNamePrefix", "Prepend and bot name with the specified text", 0, "(Bot) "), giveAllWeapons_(options_, "GiveAllWeapons", "Start the game will all the weapons", 0, false), registeredUserNames_(options_, "RegisteredUserNames", "Only allow authenticated players to use their own player names", 0, false), authHandler_(options_, "AuthHandler", "Only allow authenticated players to connect", 0, "none"), cycleMaps_(options_, "CycleMaps", "Cycle through the maps instead of choosing them using a random probablity", 0, false), delayedDefenseActivation_(options_, "DelayedDefenseActivation", "Changes to shields and parachutes are only seen after the aiming phase", 0, false), randomizeBotNames_(options_, "RandomizeBotNames", "Choose random bot names instread of sequential names", 0, false), computersDeathTalk_(options_, "ComputersDeathTalk", "The percentage chance the computers will say something when killed", 0, 100, 0, 100, 10), computersAttackTalk_(options_, "ComputersAttackTalk", "The percentage chance the computers will say something when shooting", 0, 25, 0, 100, 10), // Deprecated options depricatedMasterListServer_(options_, "MasterListServer", "The master list server for scorched3d", OptionEntry::DataDepricated, "scorched3d.sourceforge.net"), depricatedMasterListServerURI_(options_, "MasterListServerURI", "The URI on the master list server for scorched3d", OptionEntry::DataDepricated, "/scorched"), depricatedServerAdminPassword_(options_, "ServerAdminPassword", "The admin password for this server (empty password = no access)", OptionEntry::DataDepricated, ""), depricatedMaxArmsLevel_(options_, "MaxArmsLevel", "", OptionEntry::DataDepricated, 10, 0, 10, 1), depricatedAutoBallanceTeams_(options_, "AutoBallanceTeams", "", OptionEntry::DataDepricated, true), depricatedScoreType_(options_, "ScoreType", "How the winnder is choosen", OptionEntry::DataDepricated, 0, scoreEnum) { char buffer[128]; for (int i=0; i<24; i++) { snprintf(buffer, 128, "PlayerType%i", i+1); playerType_[i] = new OptionEntryString(playerTypeOptions_, buffer, "The type of the player e.g. human, computer etc..", 0, "Human"); } } OptionsGame::~OptionsGame() { } bool OptionsGame::writeToBuffer(NetBuffer &buffer, bool useProtected, bool usePlayerTypes) { std::list saveOptions; if (usePlayerTypes) saveOptions = playerTypeOptions_; std::list::iterator itor; for (itor = options_.begin(); itor != options_.end(); itor++) { OptionEntry *entry = *itor; saveOptions.push_back(entry); } if (!OptionEntryHelper::writeToBuffer( saveOptions, buffer, useProtected)) return false; return true; } bool OptionsGame::readFromBuffer(NetBufferReader &reader, bool useProtected, bool usePlayerTypes) { std::list saveOptions; if (usePlayerTypes) saveOptions = playerTypeOptions_; std::list::iterator itor; for (itor = options_.begin(); itor != options_.end(); itor++) { OptionEntry *entry = *itor; saveOptions.push_back(entry); } if (!OptionEntryHelper::readFromBuffer( saveOptions, reader, useProtected)) return false; return true; } bool OptionsGame::writeOptionsToXML(XMLNode *node) { if (!OptionEntryHelper::writeToXML(options_, node)) return false; return true; } bool OptionsGame::readOptionsFromXML(XMLNode *node) { if (!OptionEntryHelper::readFromXML(options_, node)) return false; return true; } bool OptionsGame::writeOptionsToFile(char *filePath) { std::list saveOptions = playerTypeOptions_; // Note: The players are also saved std::list::iterator itor; for (itor = options_.begin(); itor != options_.end(); itor++) { OptionEntry *entry = *itor; saveOptions.push_back(entry); } if (!OptionEntryHelper::writeToFile(saveOptions, filePath)) return false; return true; } bool OptionsGame::readOptionsFromFile(char *filePath) { std::list saveOptions = playerTypeOptions_; // Note: The players are also saved std::list::iterator itor; for (itor = options_.begin(); itor != options_.end(); itor++) { OptionEntry *entry = *itor; saveOptions.push_back(entry); } if (!OptionEntryHelper::readFromFile(saveOptions, filePath)) return false; return true; } std::list &OptionsGame::getPlayerTypeOptions() { return playerTypeOptions_; } std::list &OptionsGame::getOptions() { return options_; } OptionsGameWrapper::OptionsGameWrapper() { } OptionsGameWrapper::~OptionsGameWrapper() { } void OptionsGameWrapper::updateChangeSet() { NetBufferDefault::defaultBuffer.reset(); writeToBuffer(NetBufferDefault::defaultBuffer, true, true); NetBufferReader reader(NetBufferDefault::defaultBuffer); changedOptions_.readFromBuffer(reader, true, true); } bool OptionsGameWrapper::commitChanges() { // Setup buffers static NetBuffer testBuffer; testBuffer.reset(); NetBufferDefault::defaultBuffer.reset(); // Write to buffers writeToBuffer(NetBufferDefault::defaultBuffer, true, true); changedOptions_.writeToBuffer(testBuffer, true, true); // Compare buffers if (memcmp(testBuffer.getBuffer(), NetBufferDefault::defaultBuffer.getBuffer(), MIN(testBuffer.getBufferUsed(), NetBufferDefault::defaultBuffer.getBufferUsed())) != 0) { std::list &options = getOptions(); std::list &otheroptions = changedOptions_.getOptions(); std::list::iterator itor; std::list::iterator otheritor; for (itor=options.begin(), otheritor=otheroptions.begin(); itor!=options.end() && otheritor!=options.end(); itor++, otheritor++) { OptionEntry *entry = *itor; OptionEntry *otherentry = *otheritor; if (!(entry->getData() & OptionEntry::DataProtected) && !(otherentry->getData() & OptionEntry::DataProtected)) { std::string str = entry->getValueAsString(); std::string otherstr = otherentry->getValueAsString(); if (str != otherstr) { if (strlen(str.c_str()) < 20 && strlen(otherstr.c_str()) < 20) { Logger::log(formatString("Option %s has been changed from %s to %s", entry->getName(), str.c_str(), otherstr.c_str())); } else { Logger::log(formatString("Option %s has been changed.", entry->getName())); } } } } NetBufferReader reader(testBuffer); readFromBuffer(reader, true, true); return true; } return false; }