Here is a compilable C++ example using bitflags:
#include <iostream>
using namespace std;
namespace SF
{
enum Enums {None, CanStore = 1, CanRest = 2, CanTrain = 4, OnWater = 8, OnLand = 16, CanProduce = 32, CanOperate = 64, OnWaterAndLand = OnWater|OnLand};
}
typedef unsigned int StructFlags;
int main()
{
StructFlags structureFlags = SF::None;
structureFlags |= SF::CanStore;
structureFlags |= (SF::CanOperate | SF::CanProduce);
structureFlags |= SF::OnWaterAndLand;
if(structureFlags & SF::CanStore)
std::cout << "This building can store stuff." << std::endl;
if(structureFlags & SF::CanOperate)
std::cout << "This building requires people to operate it." << std::endl;
// |--- Notice the '!' to negate the result.
// v
if( !(structureFlags & SF::CanTrain))
std::cout << "This building can NOT train people." << std::endl;
if(structureFlags & SF::OnWaterAndLand)
{
std::cout << "This building is on both water and land." << std::endl;
}
else if(structureFlags & SF::OnWater)
{
std::cout << "This building is only on water." << std::endl;
}
else if(structureFlags & SF::OnLand)
{
std::cout << "This building is only on land." << std::endl;
}
else
{
std::cout << "This building is not on water or land." << std::endl;
}
return 0;
}
[Execute it and play around with it] - ideone.com
I wouldn't use component-based design for this situation. Just because objects have components, that doesn't mean they need to be built out of components.
Component-based design (also called ECS - entity component systems) is useful for many games, but in this situation he's asking for flags to branch his logic. Most ECS architectures are designed for graphics components, physic components, logic components, and so on. What's he's doing is dozens of Logic component, Logic component, Logic component, Logic component. That makes it closer to a finite-state machine that a component-based architecture.
It's not the correct fit in my opinion, and if he looked into component based design, it'd lead him on a wild goose chase to implement or learn how to use something that solves a problem he's not currently having.
Example: ALL his structures will have appearances. ALL his structures will have locations on the map. There's no need for components in this situation. It's not different pieces of the engine being composed together. Just because it's composable at runtime doesn't mean we need to make it into components.
ECS architectures are really cool and I'm really excited about them. I personally feel that they'll stick around as one of our most-used architectures, at least where games are concerned - but they shouldn't be applied everywhere.
In this case, I think the OP was actually correct that this best fits the idea of flags. Whether those flags are implemented using bools, std::set<std::string>, std::bitsets, bitflag enums, or any of another implementation, it doesn't particularly matter.
If we take the OP's structure:
SFStorage = 0x01,//Used to drop resources
SFRest = 0x02,//Used to sleep at night
SFTownHall = 0x04,//Used to get actions from
SFBarrack = 0x08,//Used for training/ getting battle/scout/guard actions for day
SFOnWater = 0x10,//This structure is on water
SFOnLand = 0x20,//This structure is on land
SFOperationable = 0x40,//Uses people to operate, instead of automatic
SFProduces = 0x80,//Produces resources
What we actually see is that the flags are all logic-based, and fit into several categories:
[where they can be located] (SFOnLand, SFOnWater)
[what they can do] (SFStorage, SFRest, SFBarrack, SFTownhall(?))
[whether they produce or not] (SFProduces)
[what they require] (SFOperationable)
I feel the simplest way to describe the structures would be to design the class around those categories:
//If using C++11, this should be an 'enum class'
namespace GroundType
{
//Since there are only three states, I wouldn't use bitflags here.
enum Enum {Water, Land, WaterAndLand};
}
//Even if using C++11, this *shouldn't* be an 'enum class'.
namespace Action
{
//I'm using bitflags here, plain ol' bools would also work just fine.
enum Enum {None, CanStore, CanRest, CanTrain, CanShelterInside};
};
typedef unsigned int Actions;
struct Stats
{
int currentHealth;
int maxHealth;
int defense;
int rangedDefense;
};
struct Production
{
int actionPoints; //For town-halls, for example.
int iron;
int copper;
int food;
int wood;
//...etc...
};
struct Structure
{
std::string name; //For example, "Town hall".
std::string description; //"The place where villagers come to hang out after a hard day's work."
Stats stats;
GroundType groundType; //The type of ground the structure can exist on.
//Per turn, or per minute, or whatever. Non-producing structures just produce '0'. No flag needed.
Production production;
//No flags needed for operation.
int numPeopleOperating;
int minPeopleRequiredToOperate;
//The actions the player can use this building for.
Actions actions;
};