From: <tz...@us...> - 2010-03-24 01:51:00
|
Revision: 3401 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=3401&view=rev Author: tzlaine Date: 2010-03-24 01:50:52 +0000 (Wed, 24 Mar 2010) Log Message: ----------- This patch addresses the longstanding question of how to affect ship part stats via Effects. It does this via three changes: - Added new Ship-only Meters that cover the Meter types that are ship-part specific. - Added SetShipPartMeter Effect to affect the new Ship Meters. - Added code to autogenerate EffectsGroups that adjust Ship Meters, just like the other part types already work (e.g. PC_SHILED parts, which increase a Ship's METER_SHIELD). What has not been done, and which will come in future commits: * Add parser code to allow SetShipPartMeter Effects to be specified in data files. * Adjust combat code to use the meter values instead of the nominal values straight out of the ShipDesign stats. Modified Paths: -------------- trunk/FreeOrion/universe/Effect.cpp trunk/FreeOrion/universe/Effect.h trunk/FreeOrion/universe/Enums.h trunk/FreeOrion/universe/Ship.cpp trunk/FreeOrion/universe/Ship.h trunk/FreeOrion/universe/ShipDesign.cpp trunk/FreeOrion/universe/Universe.cpp trunk/FreeOrion/universe/UniverseObject.cpp trunk/FreeOrion/universe/UniverseObject.h Modified: trunk/FreeOrion/universe/Effect.cpp =================================================================== --- trunk/FreeOrion/universe/Effect.cpp 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/Effect.cpp 2010-03-24 01:50:52 UTC (rev 3401) @@ -58,9 +58,9 @@ } /** Creates a new fleet at \a system and inserts \a ship into it. Used - * when a ship has been moved by the MoveTo effect separately from the - * fleet that previously held it. Also used by CreateShip effect to give - * the new ship a fleet. All ships need to be within fleets. */ + * when a ship has been moved by the MoveTo effect separately from the + * fleet that previously held it. Also used by CreateShip effect to give + * the new ship a fleet. All ships need to be within fleets. */ Fleet* CreateNewFleet(System* system, Ship* ship) { Universe& universe = GetUniverse(); if (!system || !ship) @@ -89,9 +89,9 @@ } /** creates a new fleet at a specified \a x and \a y location within the - * Universe, and and inserts \a ship into it. Used when a ship has been - * moved by the MoveTo effect separately from the fleet that previously - * held it. All ships need to be within fleets. */ + * Universe, and and inserts \a ship into it. Used when a ship has been + * moved by the MoveTo effect separately from the fleet that previously + * held it. All ships need to be within fleets. */ Fleet* CreateNewFleet(double x, double y, Ship* ship) { Universe& universe = GetUniverse(); if (!ship) @@ -130,9 +130,9 @@ } /** Resets the previous and next systems of \a fleet and recalcultes / - * resets the fleet's move route. Used after a fleet has been moved with - * the MoveTo effect, as its previous route was assigned based on its - * previous location, and may not be valid for its new location. */ + * resets the fleet's move route. Used after a fleet has been moved with + * the MoveTo effect, as its previous route was assigned based on its + * previous location, and may not be valid for its new location. */ void UpdateFleetRoute(Fleet* fleet, int new_next_system, int new_previous_system) { if (!fleet) { Logger().errorStream() << "UpdateFleetRoute passed a null fleet pointer"; @@ -192,6 +192,32 @@ return owner1 == owner2; } + + bool PartMatchesEffect(const PartType& part, + ShipPartClass part_class, + CombatFighterType fighter_type, + const std::string& part_name, + ShipSlotType slot_type) + { + if (slot_type != INVALID_SHIP_SLOT_TYPE && !part.CanMountInSlotType(slot_type)) + return false; + + if (part_name != "") + return part_name == part.Name(); + + switch (part.Class()) { + case PC_SHORT_RANGE: + case PC_MISSILES: + case PC_POINT_DEFENSE: + return part.Class() == part_class; + case PC_FIGHTERS: + return boost::get<FighterStats>(part.Stats()).m_type == fighter_type; + default: + break; + } + + return false; + } } /////////////////////////////////////////////////////////// @@ -456,6 +482,78 @@ /////////////////////////////////////////////////////////// +// SetShipPartMeter // +/////////////////////////////////////////////////////////// +SetShipPartMeter::SetShipPartMeter(MeterType meter, + ShipPartClass part_class, + const ValueRef::ValueRefBase<double>* value, + ShipSlotType slot_type/* = INVALID_SHIP_SLOT_TYPE*/) : + m_part_class(part_class), + m_fighter_type(INVALID_COMBAT_FIGHTER_TYPE), + m_part_name(), + m_slot_type(slot_type), + m_meter(meter), + m_value(value) +{ assert(m_part_class != PC_FIGHTERS); } + +SetShipPartMeter::SetShipPartMeter(MeterType meter, + CombatFighterType fighter_type, + const ValueRef::ValueRefBase<double>* value, + ShipSlotType slot_type/* = INVALID_SHIP_SLOT_TYPE*/) : + m_part_class(INVALID_SHIP_PART_CLASS), + m_fighter_type(fighter_type), + m_part_name(), + m_slot_type(slot_type), + m_meter(meter), + m_value(value) +{} + +SetShipPartMeter::SetShipPartMeter(MeterType meter, + const std::string& part_name, + const ValueRef::ValueRefBase<double>* value, + ShipSlotType slot_type/* = INVALID_SHIP_SLOT_TYPE*/) : + m_part_class(INVALID_SHIP_PART_CLASS), + m_fighter_type(INVALID_COMBAT_FIGHTER_TYPE), + m_part_name(part_name), + m_slot_type(slot_type), + m_meter(meter), + m_value(value) +{} + +SetShipPartMeter::~SetShipPartMeter() +{ delete m_value; } + +void SetShipPartMeter::Execute(const UniverseObject* source, UniverseObject* target) const +{ + if (Ship* ship = universe_object_cast<Ship*>(target)) { + for (std::size_t i = 0; i < ship->Design()->Parts().size(); ++i) { + if (Meter* meter = ship->GetMeter(m_meter, m_part_name)) { + const PartType* part = GetPartType(ship->Design()->Parts()[i]); + if (PartMatchesEffect(*part, m_part_class, m_fighter_type, m_part_name, m_slot_type)) { + double val = m_value->Eval(source, target, meter->Max()); + meter->SetMax(val); + meter->SetCurrent(val); + } + } + } + } +} + +std::string SetShipPartMeter::Description() const +{ + // TODO + return ""; +} + +std::string SetShipPartMeter::Dump() const +{ + std::string retval = DumpIndent() + "SetShipPartMeter"; + // TODO + return retval; +} + + +/////////////////////////////////////////////////////////// // SetEmpireStockpile // /////////////////////////////////////////////////////////// SetEmpireStockpile::SetEmpireStockpile(ResourceType stockpile, const ValueRef::ValueRefBase<double>* value) : Modified: trunk/FreeOrion/universe/Effect.h =================================================================== --- trunk/FreeOrion/universe/Effect.h 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/Effect.h 2010-03-24 01:50:52 UTC (rev 3401) @@ -22,6 +22,7 @@ class EffectsGroup; class EffectBase; class SetMeter; + class SetShipPartMeter; class SetEmpireStockpile; class SetEmpireCapitol; class SetPlanetType; @@ -136,6 +137,53 @@ void serialize(Archive& ar, const unsigned int version); }; +/** Sets the indicated meter on all ship parts in the indicated subset. This + has no effect on non-Ship targets. If slot_type is specified, only the + indicated (internal or external) parts are affected. */ +class Effect::SetShipPartMeter : public Effect::EffectBase +{ +public: + /** Affects the \a meter_type meters that belong to all parts of class \a + part_class. \a part_class must specify a class of parts for which + there is a ship meter (i.e. specifying PC_FUEL would be illegal). */ + SetShipPartMeter(MeterType meter_type, + ShipPartClass part_class, + const ValueRef::ValueRefBase<double>* value, + ShipSlotType slot_type = INVALID_SHIP_SLOT_TYPE); + + /** Affects the \a meter_type meters that belong to all PC_FIGHTERS parts + of type \a fighter_type. */ + SetShipPartMeter(MeterType meter_type, + CombatFighterType fighter_type, + const ValueRef::ValueRefBase<double>* value, + ShipSlotType slot_type = INVALID_SHIP_SLOT_TYPE); + + /** Affects the \a meter_type meters that belong to all parts named \a + part_name. */ + SetShipPartMeter(MeterType meter_type, + const std::string& part_name, + const ValueRef::ValueRefBase<double>* value, + ShipSlotType slot_type = INVALID_SHIP_SLOT_TYPE); + + virtual ~SetShipPartMeter(); + + virtual void Execute(const UniverseObject* source, UniverseObject* target) const; + virtual std::string Description() const; + virtual std::string Dump() const; + +private: + ShipPartClass m_part_class; + CombatFighterType m_fighter_type; + std::string m_part_name; + ShipSlotType m_slot_type; + MeterType m_meter; + const ValueRef::ValueRefBase<double>* m_value; + + friend class boost::serialization::access; + template <class Archive> + void serialize(Archive& ar, const unsigned int version); +}; + /** Sets the empire stockpile of the target's owning empire to \a value. If the target does not have exactly one owner, nothing is done. */ class Effect::SetEmpireStockpile : public Effect::EffectBase @@ -465,6 +513,7 @@ void serialize(Archive& ar, const unsigned int version); }; + // template implementations template <class Archive> void Effect::EffectsGroup::serialize(Archive& ar, const unsigned int version) @@ -490,6 +539,18 @@ } template <class Archive> +void Effect::SetShipPartMeter::serialize(Archive& ar, const unsigned int version) +{ + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(EffectBase) + & BOOST_SERIALIZATION_NVP(m_part_class) + & BOOST_SERIALIZATION_NVP(m_fighter_type) + & BOOST_SERIALIZATION_NVP(m_part_name) + & BOOST_SERIALIZATION_NVP(m_slot_type) + & BOOST_SERIALIZATION_NVP(m_meter) + & BOOST_SERIALIZATION_NVP(m_value); +} + +template <class Archive> void Effect::SetEmpireStockpile::serialize(Archive& ar, const unsigned int version) { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(EffectBase) Modified: trunk/FreeOrion/universe/Enums.h =================================================================== --- trunk/FreeOrion/universe/Enums.h 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/Enums.h 2010-03-24 01:50:52 UTC (rev 3401) @@ -201,6 +201,21 @@ METER_DETECTION, METER_SHIELD, METER_DEFENSE, + METER_BATTLE_SPEED, + METER_STARLANE_SPEED, + + // These meter enumerators only apply to ship part meters. + + METER_DAMAGE, + METER_ROF, + METER_RANGE, + METER_SPEED, + METER_CAPACITY, + METER_ANTI_SHIP_DAMAGE, + METER_ANTI_FIGHTER_DAMAGE, + METER_LAUNCH_RATE, + METER_FIGHTER_WEAPON_RANGE, + NUM_METER_TYPES }; @@ -221,6 +236,15 @@ GG_ENUM_MAP_INSERT(METER_DETECTION) GG_ENUM_MAP_INSERT(METER_SHIELD) GG_ENUM_MAP_INSERT(METER_DEFENSE) + GG_ENUM_MAP_INSERT(METER_DAMAGE) + GG_ENUM_MAP_INSERT(METER_ROF) + GG_ENUM_MAP_INSERT(METER_RANGE) + GG_ENUM_MAP_INSERT(METER_SPEED) + GG_ENUM_MAP_INSERT(METER_CAPACITY) + GG_ENUM_MAP_INSERT(METER_ANTI_SHIP_DAMAGE) + GG_ENUM_MAP_INSERT(METER_ANTI_FIGHTER_DAMAGE) + GG_ENUM_MAP_INSERT(METER_LAUNCH_RATE) + GG_ENUM_MAP_INSERT(METER_FIGHTER_WEAPON_RANGE) GG_ENUM_MAP_END } GG_ENUM_STREAM_IN(MeterType) @@ -476,6 +500,8 @@ /** Types of fighters. */ enum CombatFighterType { + INVALID_COMBAT_FIGHTER_TYPE, + /** A fighter that is better at attacking other fighters than at attacking ships. */ INTERCEPTOR, @@ -487,6 +513,7 @@ namespace GG { GG_ENUM_MAP_BEGIN(CombatFighterType) + GG_ENUM_MAP_INSERT(INVALID_COMBAT_FIGHTER_TYPE) GG_ENUM_MAP_INSERT(INTERCEPTOR) GG_ENUM_MAP_INSERT(BOMBER) GG_ENUM_MAP_END Modified: trunk/FreeOrion/universe/Ship.cpp =================================================================== --- trunk/FreeOrion/universe/Ship.cpp 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/Ship.cpp 2010-03-24 01:50:52 UTC (rev 3401) @@ -46,10 +46,12 @@ UniverseObject::Init(); - InsertMeter(METER_FUEL, Meter()); - InsertMeter(METER_SHIELD, Meter()); - InsertMeter(METER_DETECTION, Meter()); - InsertMeter(METER_HEALTH, Meter()); + InsertMeter(METER_FUEL, Meter()); + InsertMeter(METER_SHIELD, Meter()); + InsertMeter(METER_DETECTION, Meter()); + InsertMeter(METER_HEALTH, Meter()); + InsertMeter(METER_BATTLE_SPEED, Meter()); + InsertMeter(METER_STARLANE_SPEED, Meter()); const std::vector<std::string>& part_names = Design()->Parts(); for (std::size_t i = 0; i < part_names.size(); ++i) { @@ -59,17 +61,48 @@ Logger().errorStream() << "Ship::Ship couldn't get part with name " << part_names[i]; continue; } - if (part->Class() == PC_FIGHTERS) { - std::pair<std::size_t, std::size_t>& part_fighters = - m_fighters[part_names[i]]; - ++part_fighters.first; - part_fighters.second += boost::get<FighterStats>(part->Stats()).m_capacity; - } else if (part->Class() == PC_MISSILES) { + + switch (part->Class()) { + case PC_SHORT_RANGE: + case PC_POINT_DEFENSE: { + m_part_meters[std::make_pair(METER_DAMAGE, part->Name())]; + m_part_meters[std::make_pair(METER_ROF, part->Name())]; + m_part_meters[std::make_pair(METER_RANGE, part->Name())]; + break; + } + case PC_MISSILES: { std::pair<std::size_t, std::size_t>& part_missiles = m_missiles[part_names[i]]; ++part_missiles.first; part_missiles.second += boost::get<LRStats>(part->Stats()).m_capacity; + m_part_meters[std::make_pair(METER_DAMAGE, part->Name())]; + m_part_meters[std::make_pair(METER_ROF, part->Name())]; + m_part_meters[std::make_pair(METER_RANGE, part->Name())]; + m_part_meters[std::make_pair(METER_SPEED, part->Name())]; + m_part_meters[std::make_pair(METER_STEALTH, part->Name())]; + m_part_meters[std::make_pair(METER_HEALTH, part->Name())]; + m_part_meters[std::make_pair(METER_CAPACITY, part->Name())]; + break; } + case PC_FIGHTERS: { + std::pair<std::size_t, std::size_t>& part_fighters = + m_fighters[part_names[i]]; + ++part_fighters.first; + part_fighters.second += boost::get<FighterStats>(part->Stats()).m_capacity; + m_part_meters[std::make_pair(METER_ANTI_SHIP_DAMAGE, part->Name())]; + m_part_meters[std::make_pair(METER_ANTI_FIGHTER_DAMAGE, part->Name())]; + m_part_meters[std::make_pair(METER_LAUNCH_RATE, part->Name())]; + m_part_meters[std::make_pair(METER_FIGHTER_WEAPON_RANGE, part->Name())]; + m_part_meters[std::make_pair(METER_SPEED, part->Name())]; + m_part_meters[std::make_pair(METER_STEALTH, part->Name())]; + m_part_meters[std::make_pair(METER_HEALTH, part->Name())]; + m_part_meters[std::make_pair(METER_DETECTION, part->Name())]; + m_part_meters[std::make_pair(METER_CAPACITY, part->Name())]; + break; + } + default: + break; + } } } } @@ -108,9 +141,15 @@ this->m_design_id = copied_ship->m_design_id; this->m_fighters = copied_ship->m_fighters; this->m_missiles = copied_ship->m_missiles; + for (PartMeters::const_iterator it = copied_ship->m_part_meters.begin(); + it != copied_ship->m_part_meters.end(); + ++it) { + this->m_part_meters[it->first]; + } if (vis >= VIS_FULL_VISIBILITY) { this->m_ordered_scrapped = copied_ship->m_ordered_scrapped; + this->m_part_meters = copied_ship->m_part_meters; } } } @@ -211,6 +250,12 @@ } } +bool Ship::OrderedScrapped() const +{ return m_ordered_scrapped; } + +const Meter* Ship::GetMeter(MeterType type, const std::string& part_name) const +{ return const_cast<const Ship*>(this)->GetMeter(type, part_name); } + void Ship::SetFleetID(int fleet_id) { m_fleet_id = fleet_id; @@ -277,4 +322,28 @@ if (b == initial_status) return; m_ordered_scrapped = b; StateChangedSignal(); -} \ No newline at end of file +} + +Meter* Ship::GetMeter(MeterType type, const std::string& part_name) +{ + Meter* retval = 0; + PartMeters::iterator it = m_part_meters.find(std::make_pair(type, part_name)); + if (it != m_part_meters.end()) + retval = &it->second; + return retval; +} + +void Ship::CustomResetMaxMeters(MeterType meter_type/* = INVALID_METER_TYPE*/) +{ + for (PartMeters::iterator it = m_part_meters.begin(); it != m_part_meters.end(); ++it) { + if (meter_type == INVALID_METER_TYPE || it->first.first == meter_type) + it->second.ResetMax(); + } +} + +void Ship::CustomClampMeters() +{ + for (PartMeters::iterator it = m_part_meters.begin(); it != m_part_meters.end(); ++it) { + it->second.Clamp(); + } +} Modified: trunk/FreeOrion/universe/Ship.h =================================================================== --- trunk/FreeOrion/universe/Ship.h 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/Ship.h 2010-03-24 01:50:52 UTC (rev 3401) @@ -44,7 +44,11 @@ virtual double ProjectedCurrentMeter(MeterType type) const; ///< returns expected value of specified meter current value on the next turn - bool OrderedScrapped() const {return m_ordered_scrapped;} + bool OrderedScrapped() const; + + const Meter* GetMeter(MeterType type, const std::string& part_name) const; ///< returns the requested Meter, or 0 if no such Meter of that type is found in this object + + using UniverseObject::GetMeter; //@} /** \name Mutators */ //@{ @@ -61,14 +65,22 @@ virtual void MoveTo(double x, double y); void SetOrderedScrapped(bool b = true); ///< flags ship for scrapping + + Meter* GetMeter(MeterType type, const std::string& part_name); ///< returns the requested Meter, or 0 if no such Meter of that type is found in this object //@} private: + typedef std::map<std::pair<MeterType, std::string>, Meter> PartMeters; + + virtual void CustomResetMaxMeters(MeterType meter_type = INVALID_METER_TYPE); + virtual void CustomClampMeters(); + int m_design_id; int m_fleet_id; bool m_ordered_scrapped; ConsumablesMap m_fighters; ConsumablesMap m_missiles; + PartMeters m_part_meters; friend class boost::serialization::access; template <class Archive> @@ -84,7 +96,8 @@ & BOOST_SERIALIZATION_NVP(m_fleet_id) & BOOST_SERIALIZATION_NVP(m_ordered_scrapped) & BOOST_SERIALIZATION_NVP(m_fighters) - & BOOST_SERIALIZATION_NVP(m_missiles); + & BOOST_SERIALIZATION_NVP(m_missiles) + & BOOST_SERIALIZATION_NVP(m_part_meters); } #endif // _Ship_h_ Modified: trunk/FreeOrion/universe/ShipDesign.cpp =================================================================== --- trunk/FreeOrion/universe/ShipDesign.cpp 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/ShipDesign.cpp 2010-03-24 01:50:52 UTC (rev 3401) @@ -91,7 +91,7 @@ } boost::shared_ptr<const Effect::EffectsGroup> - IncreaseMax(MeterType meter_type, const std::string& meter_name, double increase) + IncreaseMeterMax(MeterType meter_type, double increase) { typedef boost::shared_ptr<const Effect::EffectsGroup> EffectsGroupPtr; typedef std::vector<Effect::EffectBase*> Effects; @@ -100,7 +100,7 @@ ValueRef::ValueRefBase<double>* vr = new ValueRef::Operation<double>( ValueRef::PLUS, - new ValueRef::Variable<double>(false, meter_name), + new ValueRef::Variable<double>(false, "Value"), new ValueRef::Constant<double>(increase) ); return EffectsGroupPtr( @@ -108,6 +108,24 @@ scope, activation, Effects(1, new Effect::SetMeter(meter_type, vr, true)))); } + boost::shared_ptr<const Effect::EffectsGroup> + IncreaseCurrentAndMax(MeterType meter_type, const std::string& part_name, double increase) + { + typedef boost::shared_ptr<const Effect::EffectsGroup> EffectsGroupPtr; + typedef std::vector<Effect::EffectBase*> Effects; + Condition::Self* scope = new Condition::Self; + Condition::Self* activation = new Condition::Self; + ValueRef::ValueRefBase<double>* vr = + new ValueRef::Operation<double>( + ValueRef::PLUS, + new ValueRef::Variable<double>(false, "Value"), + new ValueRef::Constant<double>(increase) + ); + return EffectsGroupPtr( + new Effect::EffectsGroup( + scope, activation, Effects(1, new Effect::SetShipPartMeter(meter_type, part_name, vr)), part_name)); + } + struct DescriptionVisitor : public boost::static_visitor<> { DescriptionVisitor(ShipPartClass part_class, std::string& description) : @@ -428,16 +446,57 @@ break; } - if (m_class == PC_SHIELD) - m_effects.push_back(IncreaseMax(METER_SHIELD, "MaxShield", boost::get<double>(m_stats))); - else if (m_class == PC_DETECTION) - m_effects.push_back(IncreaseMax(METER_DETECTION, "MaxDetection", boost::get<double>(m_stats))); - else if (m_class == PC_STEALTH) - m_effects.push_back(IncreaseMax(METER_STEALTH, "MaxStealth", boost::get<double>(m_stats))); - else if (m_class == PC_FUEL) - m_effects.push_back(IncreaseMax(METER_FUEL, "MaxFuel", boost::get<double>(m_stats))); - else if (m_class == PC_ARMOUR) - m_effects.push_back(IncreaseMax(METER_HEALTH, "MaxHealth", boost::get<double>(m_stats))); + switch (m_class) { + case PC_SHORT_RANGE: + case PC_POINT_DEFENSE: { + const DirectFireStats& stats = boost::get<DirectFireStats>(m_stats); + m_effects.push_back(IncreaseCurrentAndMax(METER_DAMAGE, m_name, stats.m_damage)); + m_effects.push_back(IncreaseCurrentAndMax(METER_ROF, m_name, stats.m_ROF)); + m_effects.push_back(IncreaseCurrentAndMax(METER_RANGE, m_name, stats.m_range)); + break; + } + case PC_MISSILES: { + const LRStats& stats = boost::get<LRStats>(m_stats); + m_effects.push_back(IncreaseCurrentAndMax(METER_DAMAGE, m_name, stats.m_damage)); + m_effects.push_back(IncreaseCurrentAndMax(METER_ROF, m_name, stats.m_ROF)); + m_effects.push_back(IncreaseCurrentAndMax(METER_RANGE, m_name, stats.m_range)); + m_effects.push_back(IncreaseCurrentAndMax(METER_SPEED, m_name, stats.m_speed)); + m_effects.push_back(IncreaseCurrentAndMax(METER_STEALTH, m_name, stats.m_stealth)); + m_effects.push_back(IncreaseCurrentAndMax(METER_HEALTH, m_name, stats.m_health)); + m_effects.push_back(IncreaseCurrentAndMax(METER_CAPACITY, m_name, stats.m_capacity)); + break; + } + case PC_FIGHTERS: { + const FighterStats& stats = boost::get<FighterStats>(m_stats); + m_effects.push_back(IncreaseCurrentAndMax(METER_ANTI_SHIP_DAMAGE, m_name, stats.m_anti_ship_damage)); + m_effects.push_back(IncreaseCurrentAndMax(METER_ANTI_FIGHTER_DAMAGE, m_name, stats.m_anti_fighter_damage)); + m_effects.push_back(IncreaseCurrentAndMax(METER_LAUNCH_RATE, m_name, stats.m_launch_rate)); + m_effects.push_back(IncreaseCurrentAndMax(METER_FIGHTER_WEAPON_RANGE, m_name, stats.m_fighter_weapon_range)); + m_effects.push_back(IncreaseCurrentAndMax(METER_SPEED, m_name, stats.m_speed)); + m_effects.push_back(IncreaseCurrentAndMax(METER_STEALTH, m_name, stats.m_stealth)); + m_effects.push_back(IncreaseCurrentAndMax(METER_HEALTH, m_name, stats.m_health)); + m_effects.push_back(IncreaseCurrentAndMax(METER_DETECTION, m_name, stats.m_detection)); + m_effects.push_back(IncreaseCurrentAndMax(METER_CAPACITY, m_name, stats.m_capacity)); + break; + } + case PC_SHIELD: + m_effects.push_back(IncreaseMeterMax(METER_SHIELD, boost::get<double>(m_stats))); + break; + case PC_DETECTION: + m_effects.push_back(IncreaseMeterMax(METER_DETECTION, boost::get<double>(m_stats))); + break; + case PC_STEALTH: + m_effects.push_back(IncreaseMeterMax(METER_STEALTH, boost::get<double>(m_stats))); + break; + case PC_FUEL: + m_effects.push_back(IncreaseMeterMax(METER_FUEL, boost::get<double>(m_stats))); + break; + case PC_ARMOUR: + m_effects.push_back(IncreaseMeterMax(METER_HEALTH, boost::get<double>(m_stats))); + break; + default: + break; + } for (std::vector<boost::shared_ptr<const Effect::EffectsGroup> >::const_iterator it = effects.begin(); it != effects.end(); ++it) m_effects.push_back(*it); @@ -569,9 +628,11 @@ m_effects(), m_graphic(graphic) { - m_effects.push_back(IncreaseMax(METER_FUEL, "MaxFuel", m_fuel)); - m_effects.push_back(IncreaseMax(METER_STEALTH, "MaxStealth", m_stealth)); - m_effects.push_back(IncreaseMax(METER_HEALTH, "MaxHealth", m_health)); + m_effects.push_back(IncreaseMeterMax(METER_FUEL, m_fuel)); + m_effects.push_back(IncreaseMeterMax(METER_STEALTH, m_stealth)); + m_effects.push_back(IncreaseMeterMax(METER_HEALTH, m_health)); + m_effects.push_back(IncreaseMeterMax(METER_BATTLE_SPEED, m_battle_speed)); + m_effects.push_back(IncreaseMeterMax(METER_STARLANE_SPEED, m_starlane_speed)); for (std::vector<boost::shared_ptr<const Effect::EffectsGroup> >::const_iterator it = effects.begin(); it != effects.end(); ++it) m_effects.push_back(*it); } @@ -598,9 +659,11 @@ m_effects(), m_graphic(graphic) { - m_effects.push_back(IncreaseMax(METER_FUEL, "MaxFuel", m_fuel)); - m_effects.push_back(IncreaseMax(METER_STEALTH, "MaxStealth", m_stealth)); - m_effects.push_back(IncreaseMax(METER_HEALTH, "MaxHealth", m_health)); + m_effects.push_back(IncreaseMeterMax(METER_FUEL, m_fuel)); + m_effects.push_back(IncreaseMeterMax(METER_STEALTH, m_stealth)); + m_effects.push_back(IncreaseMeterMax(METER_HEALTH, m_health)); + m_effects.push_back(IncreaseMeterMax(METER_BATTLE_SPEED, m_battle_speed)); + m_effects.push_back(IncreaseMeterMax(METER_STARLANE_SPEED, m_starlane_speed)); for (std::vector<boost::shared_ptr<const Effect::EffectsGroup> >::const_iterator it = effects.begin(); it != effects.end(); ++it) m_effects.push_back(*it); } Modified: trunk/FreeOrion/universe/Universe.cpp =================================================================== --- trunk/FreeOrion/universe/Universe.cpp 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/Universe.cpp 2010-03-24 01:50:52 UTC (rev 3401) @@ -1408,50 +1408,54 @@ } - // execute only the SetMeter effects in the EffectsGroup + // execute only the SetMeter and SetShipPartMeter effects in the EffectsGroup const std::vector<Effect::EffectBase*>& effects = effects_group->EffectsList(); for (unsigned int i = 0; i < effects.size(); ++i) { const Effect::SetMeter* meter_effect = dynamic_cast<Effect::SetMeter*>(effects[i]); - if (!meter_effect) continue; + if (!meter_effect && !dynamic_cast<Effect::SetShipPartMeter*>(effects[i])) + continue; // determine meter to be altered by this effect - MeterType meter_type = meter_effect->GetMeterType(); + MeterType meter_type = INVALID_METER_TYPE; + if (meter_effect) { + meter_type = meter_effect->GetMeterType(); - // record pre-effect meter values - for (Condition::ObjectSet::iterator target_it = targets.begin(); target_it != targets.end(); ++target_it) { - UniverseObject* target = *target_it; - const Meter* meter = target->GetMeter(meter_type); - if (!meter) continue; // some objects might match target conditions, but not actually have the relevant meter + // record pre-effect meter values + for (Condition::ObjectSet::iterator target_it = targets.begin(); target_it != targets.end(); ++target_it) { + UniverseObject* target = *target_it; + const Meter* meter = target->GetMeter(meter_type); + if (!meter) continue; // some objects might match target conditions, but not actually have the relevant meter - // accounting info for this effect on this meter - EffectAccountingInfo info; - info.cause_type = targets_and_cause.effect_cause.cause_type; - info.specific_cause = targets_and_cause.effect_cause.specific_cause; - info.source_id = sourced_effects_group.source_object_id; - info.running_meter_total = meter->Max(); + // accounting info for this effect on this meter + EffectAccountingInfo info; + info.cause_type = targets_and_cause.effect_cause.cause_type; + info.specific_cause = targets_and_cause.effect_cause.specific_cause; + info.source_id = sourced_effects_group.source_object_id; + info.running_meter_total = meter->Max(); - // add accounting for this effect to end of vector - m_effect_accounting_map[target->ID()][meter_type].push_back(info); + // add accounting for this effect to end of vector + m_effect_accounting_map[target->ID()][meter_type].push_back(info); + } } - // apply meter-altering effect to targets effects_group->Execute(sourced_effects_group.source_object_id, targets, i); + if (meter_effect) { + // find change in meter due to effect: equal to post-meter minus pre-meter value + for (Condition::ObjectSet::iterator target_it = targets.begin(); target_it != targets.end(); ++target_it) { + UniverseObject* target = *target_it; + const Meter* meter = target->GetMeter(meter_type); + if (!meter) continue; // some objects might match target conditions, but not actually have the relevant meter - // find change in meter due to effect: equal to post-meter minus pre-meter value - for (Condition::ObjectSet::iterator target_it = targets.begin(); target_it != targets.end(); ++target_it) { - UniverseObject* target = *target_it; - const Meter* meter = target->GetMeter(meter_type); - if (!meter) continue; // some objects might match target conditions, but not actually have the relevant meter + // retreive info for this effect + EffectAccountingInfo& info = m_effect_accounting_map[target->ID()][meter_type].back(); - // retreive info for this effect - EffectAccountingInfo& info = m_effect_accounting_map[target->ID()][meter_type].back(); - - // update accounting info with meter change and new total - info.meter_change = meter->Max() - info.running_meter_total; - info.running_meter_total = meter->Max(); + // update accounting info with meter change and new total + info.meter_change = meter->Max() - info.running_meter_total; + info.running_meter_total = meter->Max(); + } } } Modified: trunk/FreeOrion/universe/UniverseObject.cpp =================================================================== --- trunk/FreeOrion/universe/UniverseObject.cpp 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/UniverseObject.cpp 2010-03-24 01:50:52 UTC (rev 3401) @@ -363,6 +363,7 @@ else Logger().errorStream() << "UniverseObject::ResetMaxMeters called with MeterType this object does not have"; } + CustomResetMaxMeters(meter_type); } void UniverseObject::ApplyUniverseTableMaxMeterAdjustments(MeterType meter_type) @@ -372,6 +373,7 @@ { for (std::map<MeterType, Meter>::iterator it = m_meters.begin(); it != m_meters.end(); ++it) it->second.Clamp(); + CustomClampMeters(); } void UniverseObject::PopGrowthProductionResearchPhase() @@ -395,4 +397,3 @@ } return retval; } - Modified: trunk/FreeOrion/universe/UniverseObject.h =================================================================== --- trunk/FreeOrion/universe/UniverseObject.h 2010-03-24 01:39:31 UTC (rev 3400) +++ trunk/FreeOrion/universe/UniverseObject.h 2010-03-24 01:50:52 UTC (rev 3401) @@ -178,6 +178,12 @@ private: std::map<MeterType, Meter> CensoredMeters(Visibility vis) const; ///< returns set of meters of this object that are censored based on the specified Visibility \a vis + /** any actions that should be performed at the end of ResetMaxMeters() goes here */ + virtual void CustomResetMaxMeters(MeterType meter_type = INVALID_METER_TYPE) {} + + /** any actions that should be performed at the end of ClampMeters() goes here */ + virtual void CustomClampMeters() {} + int m_id; std::string m_name; double m_x; |