From: <geo...@us...> - 2009-05-10 01:15:23
|
Revision: 3020 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=3020&view=rev Author: geoffthemedio Date: 2009-05-10 01:15:17 +0000 (Sun, 10 May 2009) Log Message: ----------- -Added a PredefinedShipDesignManager class to load and keep track of ship designs defined in premade_ship_designs.txt so they can be used during empire generation. They aren't actually used yet, but they are loaded and validated. -Modified ShipDesign::ValidDesign to output to log file the reason it rejects a design -Modified ReportError in ParseUtils to output to logger and std::cerr instead of taking a std::ostream parameter that was always set to be std::cerr -Added stringtable entries for existing premade ship designs' names and descriptions -Modified ShipDesign constructor to expand its passed list of parts to the size of the set of slots the hull has, allowing a smaller number of parts to be specified than the hull has slots. Previously the passed parts array had to exactly match the size of the slots array, to avoid issues of how to reconsile the difference, but I think this concession to convenience shouldn't be a problem. -Minor grooming Modified Paths: -------------- trunk/FreeOrion/Empire/Empire.h trunk/FreeOrion/default/eng_stringtable.txt trunk/FreeOrion/default/premade_ship_designs.txt trunk/FreeOrion/universe/Building.cpp trunk/FreeOrion/universe/Building.h trunk/FreeOrion/universe/ParserUtil.cpp trunk/FreeOrion/universe/ParserUtil.h trunk/FreeOrion/universe/ShipDesign.cpp trunk/FreeOrion/universe/Special.cpp trunk/FreeOrion/universe/Tech.cpp trunk/FreeOrion/universe/TopLevelParsers.cpp trunk/FreeOrion/universe/Universe.cpp Modified: trunk/FreeOrion/Empire/Empire.h =================================================================== --- trunk/FreeOrion/Empire/Empire.h 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/Empire/Empire.h 2009-05-10 01:15:17 UTC (rev 3020) @@ -16,10 +16,11 @@ class ShipDesign; class Empire; -/** A human readable name for, and set of human non-readable names of predefined - * ShipDesigns in premade_ship_designs.txt to put together to make a fleet. - * Useful for saving or specifying prearranged combinations of prearranged ShipDesigns - * to automatically put together, such as during universe creation. */ +/** A combination of names of ShipDesign that can be put together to make a + * fleet of ships, and a name for such a fleet, loaded from starting_fleets.txt + * ShipDesign names refer to designs listed in premade_ship_designs.txt. + * Useful for saving or specifying prearranged combinations of prearranged + * ShipDesigns to automatically put together, such as during universe creation.*/ struct FleetPlan { FleetPlan(const std::string& fleet_name, const std::vector<std::string>& ship_design_names, Modified: trunk/FreeOrion/default/eng_stringtable.txt =================================================================== --- trunk/FreeOrion/default/eng_stringtable.txt 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/default/eng_stringtable.txt 2009-05-10 01:15:17 UTC (rev 3020) @@ -89,6 +89,48 @@ Interceptor +########################### +# Predefined Ship Designs # +########################### +# in premade_ship_designs.txt + +SD_SCOUT +Scout + +SD_SCOUT_DESC +Small and cheap unarmed vessel designed for recon and exploration. + +SD_COLONY_SHIP +Colony Ship + +SD_COLONY_SHIP_DESC +Huge unarmed vessel capable of delivering millions of citizens safely to new colony sites. + +SD_MARK1 +Mark I + +SD_MARK1_DESC +Affordable armed patrol frigate. + +SD_MARK2 +Mark II + +SD_MARK2_DESC +Cruiser with strong defensive and offensive capabilities. + +SD_MARK3 +Mark III + +SD_MARK3_DESC +Advanced cruiser with heavy weaponry and armor to do the dirty work. + +SD_MARK4 +Mark IV + +SD_MARK4_DESC +Massive state-of-art warship armed and protected with the latest technolgy. Priced accordingly. + + ########################## # Status Update Messages # ########################## Modified: trunk/FreeOrion/default/premade_ship_designs.txt =================================================================== --- trunk/FreeOrion/default/premade_ship_designs.txt 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/default/premade_ship_designs.txt 2009-05-10 01:15:17 UTC (rev 3020) @@ -12,7 +12,13 @@ description = "SD_COLONY_SHIP_DESC" lookup_strings = true hull = "SH_MEDIUM" - parts = "CO_COLONY_POD" + parts = [ + "" + "" + "" + "" + "CO_COLONY_POD" + ] graphic = "misc/colony1.png" model = "" @@ -57,10 +63,10 @@ model = "" ShipDesign - name = "SD_LARGE" + name = "SD_MARK4" description = "SD_MARK4_DESC" lookup_strings = true - hull = "SH_SMALL" + hull = "SH_LARGE" parts = [ "DT_OPTICAL_SENSORS" "SR_ION_CANNON" Modified: trunk/FreeOrion/universe/Building.cpp =================================================================== --- trunk/FreeOrion/universe/Building.cpp 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/Building.cpp 2009-05-10 01:15:17 UTC (rev 3020) @@ -283,7 +283,7 @@ >> end_p, skip_p); if (!result.full) - ReportError(std::cerr, input.c_str(), result); + ReportError(input.c_str(), result); } BuildingTypeManager::~BuildingTypeManager() Modified: trunk/FreeOrion/universe/Building.h =================================================================== --- trunk/FreeOrion/universe/Building.h 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/Building.h 2009-05-10 01:15:17 UTC (rev 3020) @@ -114,7 +114,8 @@ typedef std::map<std::string, BuildingType*>::const_iterator iterator; /** \name Accessors */ //@{ - /** returns the building type with the name \a name; you should use the free function GetBuildingType() instead */ + /** returns the building type with the name \a name; you should use the + * free function GetBuildingType() instead, mainly to save some typing. */ const BuildingType* GetBuildingType(const std::string& name) const; /** iterator to the first building type */ Modified: trunk/FreeOrion/universe/ParserUtil.cpp =================================================================== --- trunk/FreeOrion/universe/ParserUtil.cpp 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/ParserUtil.cpp 2009-05-10 01:15:17 UTC (rev 3020) @@ -2,6 +2,7 @@ #include "ParserUtil.h" #include "ValueRefParser.h" +#include "../util/AppInterface.h" #include <cstring> @@ -150,7 +151,7 @@ bool dummy = Init(); } -void ReportError(std::ostream& os, const char* input, const parse_info<const char*>& result) +void ReportError(const char* input, const parse_info<const char*>& result) { int line = 1; const char* line_first = result.stop; @@ -167,8 +168,12 @@ while (line_last < input + input_length && *line_last != '\n') { ++line_last; } - os << "error at or after the indicated point on line " << line << ":\n" - << std::string(line_first, line_last) << "\n" - << std::string(result.stop - line_first, ' ') << "^\n" - << std::endl; + std::cerr << "error at or after the indicated point on line " << line << ":" << std::endl; + std::cerr << std::string(line_first, line_last) << "" << std::endl; + std::cerr << std::string(result.stop - line_first, ' ') << "^" << std::endl << std::endl; + + Logger().errorStream() << "error at or after the indicated point on line " << line << ":"; + Logger().errorStream() << std::string(line_first, line_last) << ""; + Logger().errorStream() << std::string(result.stop - line_first, ' ') << "^"; + Logger().errorStream() << " "; } Modified: trunk/FreeOrion/universe/ParserUtil.h =================================================================== --- trunk/FreeOrion/universe/ParserUtil.h 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/ParserUtil.h 2009-05-10 01:15:17 UTC (rev 3020) @@ -57,6 +57,6 @@ extern boost::spirit::symbols<ShipPartClass> part_class_p; extern boost::spirit::symbols<ShipSlotType> slot_type_p; -void ReportError(std::ostream& os, const char* input, const boost::spirit::parse_info<const char*>& result); +void ReportError(const char* input, const boost::spirit::parse_info<const char*>& result); #endif // _ParserUtil_h_ Modified: trunk/FreeOrion/universe/ShipDesign.cpp =================================================================== --- trunk/FreeOrion/universe/ShipDesign.cpp 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/ShipDesign.cpp 2009-05-10 01:15:17 UTC (rev 3020) @@ -291,7 +291,7 @@ >> end_p, skip_p); if (!result.full) - ReportError(std::cerr, input.c_str(), result); + ReportError(input.c_str(), result); } PartTypeManager::~PartTypeManager() @@ -598,7 +598,7 @@ >> end_p, skip_p); if (!result.full) - ReportError(std::cerr, input.c_str(), result); + ReportError(input.c_str(), result); } HullTypeManager::~HullTypeManager() @@ -685,8 +685,16 @@ m_max_non_PD_weapon_range(0.0), m_name_desc_in_stringtable(name_desc_in_stringtable) { - if (!ValidDesign(m_hull, m_parts)) + // expand parts list to have empty values if fewer parts are given than hull has slots + if (const HullType* hull = GetHullType(m_hull)) { + if (m_parts.size() < hull->NumSlots()) + m_parts.resize(hull->NumSlots(), ""); + } + + if (!ValidDesign(m_hull, m_parts)) { Logger().errorStream() << "constructing an invalid ShipDesign!"; + Logger().errorStream() << Dump(); + } BuildStatCaches(); } @@ -913,12 +921,16 @@ bool ShipDesign::ValidDesign(const std::string& hull, const std::vector<std::string>& parts) { // ensure hull type exists and has exactly enough slots for passed parts const HullType* hull_type = GetHullTypeManager().GetHullType(hull); - if (!hull_type) + if (!hull_type) { + Logger().debugStream() << "ShipDesign::ValidDesign: hull not found: " << hull; return false; + } unsigned int size = parts.size(); - if (size != hull_type->NumSlots()) + if (size > hull_type->NumSlots()) { + Logger().debugStream() << "ShipDesign::ValidDesign: given " << size << " parts for hull with " << hull_type->NumSlots() << " slots"; return false; + } const std::vector<HullType::Slot>& slots = hull_type->Slots(); @@ -930,13 +942,17 @@ continue; // if part slot is empty, ignore - doesn't invalidate design const PartType* part = part_manager.GetPartType(part_name); - if (!part) + if (!part) { + Logger().debugStream() << "ShipDesign::ValidDesign: part not found: " << part_name; return false; + } // verify part can mount in indicated slot ShipSlotType slot_type = slots[i].type; - if (!(part->CanMountInSlotType(slot_type))) + if (!(part->CanMountInSlotType(slot_type))) { + Logger().debugStream() << "ShipDesign::ValidDesign: part " << part_name << " can't be mounted in " << boost::lexical_cast<std::string>(slot_type) << " slot"; return false; + } } return true; @@ -1029,8 +1045,8 @@ { std::string retval = DumpIndent() + "ShipDesign\n"; ++g_indent; - retval += DumpIndent() + "name = \"" + Name() + "\"\n"; - retval += DumpIndent() + "description = \"" + Description() + "\"\n"; + retval += DumpIndent() + "name = \"" + m_name + "\"\n"; + retval += DumpIndent() + "description = \"" + m_description + "\"\n"; retval += DumpIndent() + "lookup_strings = " + (m_name_desc_in_stringtable ? "true" : "false") + "\n"; retval += DumpIndent() + "hull = \"" + m_hull + "\"\n"; retval += DumpIndent() + "parts = "; Modified: trunk/FreeOrion/universe/Special.cpp =================================================================== --- trunk/FreeOrion/universe/Special.cpp 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/Special.cpp 2009-05-10 01:15:17 UTC (rev 3020) @@ -81,7 +81,7 @@ >> end_p, skip_p); if (!result.full) - ReportError(std::cerr, input.c_str(), result); + ReportError(input.c_str(), result); } std::map<std::string, Special*> m_specials; std::set<std::string> m_planet_special_names; Modified: trunk/FreeOrion/universe/Tech.cpp =================================================================== --- trunk/FreeOrion/universe/Tech.cpp 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/Tech.cpp 2009-05-10 01:15:17 UTC (rev 3020) @@ -443,7 +443,7 @@ >> end_p, skip_p); if (!result.full) - ReportError(std::cerr, input.c_str(), result); + ReportError(input.c_str(), result); std::set<std::string> empty_defined_categories; for (std::map<std::string, TechCategory*>::iterator map_it = m_categories.begin(); map_it != m_categories.end(); ++map_it) { Modified: trunk/FreeOrion/universe/TopLevelParsers.cpp =================================================================== --- trunk/FreeOrion/universe/TopLevelParsers.cpp 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/TopLevelParsers.cpp 2009-05-10 01:15:17 UTC (rev 3020) @@ -296,8 +296,7 @@ val(0), // creation turn ship_design_p.hull, ship_design_p.parts, ship_design_p.graphic, ship_design_p.model, - ship_design_p.name_desc_in_stringtable - )]; + ship_design_p.name_desc_in_stringtable)]; fleet_plan_p = (str_p("fleet") Modified: trunk/FreeOrion/universe/Universe.cpp =================================================================== --- trunk/FreeOrion/universe/Universe.cpp 2009-05-09 10:18:06 UTC (rev 3019) +++ trunk/FreeOrion/universe/Universe.cpp 2009-05-10 01:15:17 UTC (rev 3020) @@ -2109,15 +2109,162 @@ } namespace { + struct store_ship_design_impl + { + template <class T1, class T2> + struct result {typedef void type;}; + template <class T> + void operator()(std::map<std::string, ShipDesign*>& ship_designs, const T& ship_design) const + { + if (ship_designs.find(ship_design->Name()) != ship_designs.end()) { + std::string error_str = "ERROR: More than one predefined ship design in predefined_ship_designs.txt has the name " + ship_design->Name(); + throw std::runtime_error(error_str.c_str()); + } + ship_designs[ship_design->Name()] = ship_design; + } + }; - /** externally defined ship classes to give to new empires */ - std::vector<const ShipDesign*> new_empire_ship_designs; + const phoenix::function<store_ship_design_impl> store_ship_design_; - /** externally defined combinations of externally defined ship classes, or - * fleet plans, to give to new empires */ - std::vector<FleetPlan> new_empire_fleets; + + class PredefinedShipDesignManager { + public: + typedef std::map<std::string, ShipDesign*>::const_iterator iterator; + + /** \name Accessors */ //@{ + /** returns new copy of ShipDesign with name \a name. caller gains + * ownership of returned pointer. returned ShipDesign can be + * inserted into an empire using Empire::AddShipDesign(ShipDesign*) + * which also inserts it into the Universe, which takes ownership. */ + ShipDesign* CopyShipDesign(const std::string& name, int designing_empire_id = ALL_EMPIRES) const; + + /** returns iterator pointing to first ship design. */ + iterator begin() const { return m_ship_designs.begin(); } + + /** returns iterator pointing one past last ship design. */ + iterator end() const { return m_ship_designs.end(); } + + /** returns iterator pointing to ship design with indicated \a name or + * returns end() if no ship design exists with that name. */ + iterator find(const std::string& name) const { return m_ship_designs.find(name); } + + /** returns true iff a ship design with the indicated \a name exists. */ + bool contains(const std::string& name) const { return find(name) != end(); }; + //@} + + /** Adds designs in this manager between specified \a begin_it and + * \a end_it iterators to the specified \a empire using that Empire's + * AddShipDesign(ShipDesign*) function. */ + void AddShipDesignsToEmpire(Empire* empire) const; + + /** returns the instance of this singleton class; you should use the + * free function GetPredefinedShipDesignManager() instead */ + static const PredefinedShipDesignManager& GetPredefinedShipDesignManager(); + + private: + PredefinedShipDesignManager(); + ~PredefinedShipDesignManager(); + + std::map<std::string, ShipDesign*> m_ship_designs; + + static PredefinedShipDesignManager* s_instance; + }; + // static(s) + PredefinedShipDesignManager* PredefinedShipDesignManager::s_instance = 0; + + const PredefinedShipDesignManager& PredefinedShipDesignManager::GetPredefinedShipDesignManager() { + static PredefinedShipDesignManager manager; + return manager; + } + + PredefinedShipDesignManager::PredefinedShipDesignManager() { + if (s_instance) + throw std::runtime_error("Attempted to create more than one PredefinedShipDesignManager."); + + s_instance = this; + + Logger().debugStream() << "Initializing PredefinedShipDesignManager"; + + std::string file_name = "premade_ship_designs.txt"; + std::string input; + + boost::filesystem::ifstream ifs(GetSettingsDir() / file_name); + if (ifs) { + std::getline(ifs, input, '\0'); + ifs.close(); + } else { + Logger().errorStream() << "Unable to open data file " << file_name; + return; + } + + using namespace boost::spirit; + using namespace phoenix; + parse_info<const char*> result = + parse(input.c_str(), + as_lower_d[*ship_design_p[store_ship_design_(var(m_ship_designs), arg1)]] + >> end_p, + skip_p); + if (!result.full) + ReportError(input.c_str(), result); + +//#ifdef OUTPUT_DESIGNS_LIST + Logger().debugStream() << "Predefined Ship Designs:"; + for (iterator it = begin(); it != end(); ++it) { + const ShipDesign* d = it->second; + Logger().debugStream() << " ... " << d->Name(); + } +//#endif + } + + PredefinedShipDesignManager::~PredefinedShipDesignManager() { + for (std::map<std::string, ShipDesign*>::iterator it = m_ship_designs.begin(); it != m_ship_designs.end(); ++it) + delete it->second; + } + + ShipDesign* PredefinedShipDesignManager::CopyShipDesign(const std::string& name, int designing_empire_id) const { + ShipDesign* retval = NULL; + if (m_ship_designs.empty()) + return retval; + + std::map<std::string, ShipDesign*>::const_iterator it = m_ship_designs.find(name); + if (it == m_ship_designs.end()) + return retval; + + ShipDesign* d = it->second; + + retval = new ShipDesign(d->Name(), d->Description(), designing_empire_id, + d->DesignedOnTurn(), d->Hull(), d->Parts(), + d->Graphic(), d->Model(), false); + + return retval; + } + + void PredefinedShipDesignManager::AddShipDesignsToEmpire(Empire* empire) const { + if (!empire) + return; + + for (iterator it = begin(); it != end(); ++it) { + ShipDesign* d = it->second; + + ShipDesign* copy = new ShipDesign(d->Name(), d->Description(), empire->EmpireID(), + d->DesignedOnTurn(), d->Hull(), d->Parts(), + d->Graphic(), d->Model(), false); + + int design_id = empire->AddShipDesign(copy); + + if (design_id == UniverseObject::INVALID_OBJECT_ID) { + delete copy; + Logger().errorStream() << "PredefinedShipDesignManager::AddShipDesignsToEmpire couldn't add a design to an empire"; + } + } + } + + /** returns the singleton building type manager */ + const PredefinedShipDesignManager& GetPredefinedShipDesignManager() { + return PredefinedShipDesignManager::GetPredefinedShipDesignManager(); + } }; -#endif +#endif // FREEORION_BUILD_SERVER (although the following functions should also only be used on the server) void Universe::CreateUniverse(int size, Shape shape, Age age, StarlaneFrequency starlane_freq, PlanetDensity planet_density, SpecialsFrequency specials_freq, int players, int ai_players, const std::map<int, PlayerSetupData>& player_setup_data) @@ -3016,6 +3163,8 @@ std::vector<GG::Clr> colors = EmpireColors(); + const PredefinedShipDesignManager& predefined_ship_designs = GetPredefinedShipDesignManager(); + for (ServerNetworking::const_established_iterator it = ServerApp::GetApp()->Networking().established_begin(); it != ServerApp::GetApp()->Networking().established_end(); ++it, ++i) { std::string empire_name = ""; @@ -3057,6 +3206,8 @@ } } + Logger().debugStream() << "creating empire: " << empire_name; + int home_planet_id = homeworlds[i]; // create new Empire object through empire manager |