bool addSingleVegetationConfig( TiXmlElement* elemRoot,  vector<VegetationConfiguration>* vegetationConfigs, vector<t_matgloss>& plantNames )
{
  const char* sheetIndexStr;
  t_SpriteWithOffset sprite;
  int basefile = -1;
  sprite.fileIndex=basefile;
  sprite.x=0;
  sprite.y=0;
  sprite.animFrames=ALL_FRAMES;
 
  const char* filename = elemRoot->Attribute("file");
	if (filename != NULL && filename[0] != 0)
	{
	  	basefile = loadConfigImgFile((char*)filename, elemRoot);
	}
	
	//kinda round about- looking to needing to shift the lot into the plant elem
	sprite.fileIndex=basefile;
	
  TiXmlElement* elemTree;
  for (elemTree = elemRoot->FirstChildElement("plant");
  	elemTree; elemTree = elemTree->NextSiblingElement("plant") ){
	const char* idstr = elemTree->Attribute("gameID");
  	int gameID = INVALID_INDEX;
  	if (idstr && idstr[0])
  	{
	  	gameID = lookupIndexedType(idstr,plantNames);
  		if (gameID == INVALID_INDEX)
  		{
	  		contentError("No matching plant type",elemTree);
	  		continue;
  		}
	}
    const char* deadstr = elemTree->Attribute("dead");
    bool dead = (deadstr && deadstr[0]);
    const char* saplingstr = elemTree->Attribute("sapling");
    bool sapling = (saplingstr && saplingstr[0]);
    sheetIndexStr = elemTree->Attribute("sheetIndex");
    /* No animated trees.
    	But we may repurpose it later to make a xyz variance?
    sprite.animFrames = getAnimFrames(elemProfession->Attribute("frames"));
	if (sprite.animFrames == 0)
		sprite.animFrames = ALL_FRAMES;*/
    
    //create profession config
    sprite.sheetIndex=atoi(sheetIndexStr);
    VegetationConfiguration vegetationConfiguration(gameID, sprite, !dead, !sapling);
    //add a copy to known creatures
    vegetationConfigs->push_back( vegetationConfiguration );
  }

  return true;
}
void c_sprite::set_by_xml(TiXmlElement *elemSprite)
{
	const char* sheetIndexStr;
	sheetIndexStr = elemSprite->Attribute("sheetIndex");
	if (sheetIndexStr != NULL && sheetIndexStr[0] != 0)
	{
		sheetindex=atoi(sheetIndexStr);
	}
	const char* spriteStr;
	spriteStr = elemSprite->Attribute("sprite");
	if (spriteStr != NULL && spriteStr[0] != 0)
	{
		sheetindex=atoi(spriteStr);
	}
	const char* indexStr;
	indexStr = elemSprite->Attribute("index");
	if (indexStr != NULL && indexStr[0] != 0)
	{
		sheetindex=atoi(indexStr);
	}
	const char* animoffStr;
	animoffStr = elemSprite->Attribute("random_anim_offset");
	if (animoffStr != NULL && animoffStr[0] != 0)
	{
		randomanimation=atoi(animoffStr);
	}
	const char* scaleStr;
	scaleStr = elemSprite->Attribute("zoom");
	if (scaleStr != NULL && scaleStr[0] != 0)
	{
		int scalev=atoi(scaleStr);
		spritescale=std::pow(2.0f,(float)scalev);
	}
	//load files, if any
	const char* filename = elemSprite->Attribute("file");
	if (filename != NULL && filename[0] != 0)
	{
		fileindex = loadConfigImgFile((char*)filename,elemSprite);
		if(fileindex == -1) return;
	}

	animframes = getAnimFrames(elemSprite->Attribute("frames"));
	if (animframes == 0)
		animframes = ALL_FRAMES;

	openborders = getBorders(elemSprite->Attribute("border_open_OR"));

	floorborders = getBorders(elemSprite->Attribute("border_floor_OR"));

	wallborders = getBorders(elemSprite->Attribute("border_wall_OR"));

	rampborders = getBorders(elemSprite->Attribute("border_ramp_OR"));

	upstairborders = getBorders(elemSprite->Attribute("border_upstair_OR"));

	downstairborders = getBorders(elemSprite->Attribute("border_downstair_OR"));

	darkborders = getUnBorders(elemSprite->Attribute("border_dark_OR"));

	lightborders = getBorders(elemSprite->Attribute("border_light_OR"));

	notopenborders = getUnBorders(elemSprite->Attribute("border_open_NOR"));

	notfloorborders = getUnBorders(elemSprite->Attribute("border_floor_NOR"));

	notwallborders = getUnBorders(elemSprite->Attribute("border_wall_NOR"));

	notrampborders = getUnBorders(elemSprite->Attribute("border_ramp_NOR"));

	notupstairborders = getUnBorders(elemSprite->Attribute("border_upstair_NOR"));

	notdownstairborders = getUnBorders(elemSprite->Attribute("border_downstair_NOR"));

	//check for randomised tiles
	const char* spriteVariationsStr = elemSprite->Attribute("variations");
	if (spriteVariationsStr == NULL || spriteVariationsStr[0] == 0)
	{
		variations = 0;
	}
	else 
	{
		variations=atoi(spriteVariationsStr);
	}


	const char* waterDirStr = elemSprite->Attribute("water_direction");
	if (waterDirStr == NULL || waterDirStr[0] == 0)
	{
		water_direction = -1;
	}
	else 
	{
		water_direction=atoi(waterDirStr);
	}

	//decide what the sprite should be shaded by.
	const char* spriteVarColorStr = elemSprite->Attribute("color");
	if (spriteVarColorStr == NULL || spriteVarColorStr[0] == 0)
	{
		shadeBy = ShadeNone;
	}
	else
	{
		shadeBy = getShadeType(spriteVarColorStr);
	}

	//some sprites should only be drawn when the tile is chopped in half
	const char* spriteChopStr = elemSprite->Attribute("halftile");
	if (spriteChopStr == NULL || spriteChopStr[0] == 0)
	{
		halftile = HALFTILECHOP;
	}
	else if( strcmp(spriteChopStr, "chop") == 0)
	{
		halftile = HALFTILECHOP;
	}
	else if( strcmp(spriteChopStr, "yes") == 0)
	{
		halftile = HALFTILEYES;
	}
	else if( strcmp(spriteChopStr, "no") == 0)
	{
		halftile = HALFTILENO;
	}
	else if( strcmp(spriteChopStr, "both") == 0)
	{
		halftile = HALFTILEBOTH;
	}

	//hidden in the shadows
	const char* spriteShadowStr = elemSprite->Attribute("dark");
	if (spriteShadowStr == NULL || spriteShadowStr[0] == 0)
	{
		light = LIGHTANY;
	}
	else if( strcmp(spriteShadowStr, "yes") == 0)
	{
		light = LIGHTNO;
	}
	else if( strcmp(spriteShadowStr, "no") == 0)
	{
		light = LIGHTYES;
	}
	else if( strcmp(spriteShadowStr, "both") == 0)
	{
		light = LIGHTANY;
	}

	//some sprites are actually tile borders.
	const char* spriteBorderStr = elemSprite->Attribute("tileborder");
	if (spriteBorderStr == NULL || spriteBorderStr[0] == 0)
	{
		isoutline = OUTLINENONE;
	}
	else if( strcmp(spriteBorderStr, "none") == 0)
	{
		isoutline = OUTLINENONE;
	}
	else if( strcmp(spriteBorderStr, "left") == 0)
	{
		isoutline = OUTLINELEFT;
	}
	else if( strcmp(spriteBorderStr, "right") == 0)
	{
		isoutline = OUTLINERIGHT;
	}
	else if( strcmp(spriteBorderStr, "bottom") == 0)
	{
		isoutline = OUTLINEBOTTOM;
	}

	//Grass states
	const char* grass_growth_string = elemSprite->Attribute("grass_state");
	if (grass_growth_string == NULL || grass_growth_string[0] == 0)
	{
		grass_growth = GRASS_GROWTH_ANY;
	}
	else if( strcmp(grass_growth_string, "any") == 0)
	{
		grass_growth = GRASS_GROWTH_ANY;
	}
	else if( strcmp(grass_growth_string, "green") == 0)
	{
		grass_growth = GRASS_GROWTH_NORMAL;
	}
	else if( strcmp(grass_growth_string, "dry") == 0)
	{
		grass_growth = GRASS_GROWTH_DRY;
	}
	else if( strcmp(grass_growth_string, "dead") == 0)
	{
		grass_growth = GRASS_GROWTH_DEAD;
	}

	//do bodyparts
	const char* bodyPartStr = elemSprite->Attribute("bodypart");
	//clear old bodypart string
	memset(bodypart, 0, sizeof(bodypart));
	//copy new, if found
	if (bodyPartStr != NULL && bodyPartStr[0] != 0)
	{
		strcpy(bodypart, bodyPartStr);
	}

	uint8_t red, green, blue, alpha;
	//do custom colors
	const char* spriteRedStr = elemSprite->Attribute("red");
	if (spriteRedStr == NULL || spriteRedStr[0] == 0)
	{
		red = 255;
	}
	else red=atoi(spriteRedStr);
	const char* spriteGreenStr = elemSprite->Attribute("green");
	if (spriteGreenStr == NULL || spriteGreenStr[0] == 0)
	{
		green = 255;
	}
	else green=atoi(spriteGreenStr);
	const char* spriteBlueStr = elemSprite->Attribute("blue");
	if (spriteBlueStr == NULL || spriteBlueStr[0] == 0)
	{
		blue = 255;
	}
	else blue=atoi(spriteBlueStr);
	const char* spriteAlphaStr = elemSprite->Attribute("alpha");
	if (spriteAlphaStr == NULL || spriteAlphaStr[0] == 0)
	{
		alpha = 255;
	}
	else alpha=atoi(spriteAlphaStr);
	shadecolor = al_map_rgba(red, green, blue, alpha);

	//Should the sprite be shown only when there is snow?
	const char* spriteSnowMinStr = elemSprite->Attribute("snow_min");
	if (spriteSnowMinStr == NULL || spriteSnowMinStr[0] == 0)
	{
		snowmin = 0;
	}
	else snowmin=atoi(spriteSnowMinStr);
	const char* spriteSnowMaxStr = elemSprite->Attribute("snow_max");
	if (spriteSnowMaxStr == NULL || spriteSnowMaxStr[0] == 0)
	{
		snowmax = -1;
	}
	else snowmax=atoi(spriteSnowMaxStr);

	//Should the sprite be shown only when there is grass?
	const char* spriteGrassMinStr = elemSprite->Attribute("grass_min");
	if (spriteGrassMinStr == NULL || spriteGrassMinStr[0] == 0)
	{
		grassmin = 0;
	}
	else grassmin=atoi(spriteGrassMinStr);
	const char* spriteGrassMaxStr = elemSprite->Attribute("grass_max");
	if (spriteGrassMaxStr == NULL || spriteGrassMaxStr[0] == 0)
	{
		grassmax = -1;
	}
	else grassmax=atoi(spriteGrassMaxStr);

	//does the sprite match a particular grass type?
	const char* idstr = elemSprite->Attribute("grass_type");
	if (idstr == NULL || idstr[0] == 0)
	{
		grasstype = INVALID_INDEX;
	}
	else grasstype = lookupIndexedType(idstr,contentLoader->organic);

	//Should the sprite be shown only when there is blood?
	const char* spritebloodMinStr = elemSprite->Attribute("blood_min");
	if (spritebloodMinStr == NULL || spritebloodMinStr[0] == 0)
	{
		bloodmin = 0;
	}
	else bloodmin=atoi(spritebloodMinStr);
	const char* spritebloodMaxStr = elemSprite->Attribute("blood_max");
	if (spritebloodMaxStr == NULL || spritebloodMaxStr[0] == 0)
	{
		bloodmax = -1;
	}
	else bloodmax=atoi(spritebloodMaxStr);

	//Should the sprite be shown only when there is mud?
	const char* spritemudMinStr = elemSprite->Attribute("mud_min");
	if (spritemudMinStr == NULL || spritemudMinStr[0] == 0)
	{
		mudmin = 0;
	}
	else mudmin=atoi(spritemudMinStr);
	const char* spritemudMaxStr = elemSprite->Attribute("mud_max");
	if (spritemudMaxStr == NULL || spritemudMaxStr[0] == 0)
	{
		mudmax = -1;
	}
	else mudmax=atoi(spritemudMaxStr);

	//Add user settable sprite offsets
	const char* strOffsetX = elemSprite->Attribute("offsetx");
	if (strOffsetX == NULL || strOffsetX[0] == 0)
	{
		offset_user_x = 0;
	}
	else offset_user_x=atoi(strOffsetX);
	const char* strOffsetY = elemSprite->Attribute("offsety");
	if (strOffsetY == NULL || strOffsetY[0] == 0)
	{
		offset_user_y = 0;
	}
	else offset_user_y=atoi(strOffsetY);

	//not all tiles work well with an outline
	const char* spriteOutlineStr = elemSprite->Attribute("outline");
	if (spriteOutlineStr != NULL && spriteOutlineStr[0] != 0)
		needoutline=(atoi(spriteOutlineStr) == 1);

	//get the possible offset for blood bools
	const char* spriteBloodStr = elemSprite->Attribute("blood_sprite");
	if (spriteBloodStr != NULL && spriteBloodStr[0] != 0)
		bloodsprite=(atoi(spriteBloodStr) == 1);

	subsprites.clear();
	//add subsprites, if any.
	TiXmlElement* elemSubSprite = elemSprite->FirstChildElement("subsprite");
	for(TiXmlElement* elemSubType = elemSprite->FirstChildElement("subsprite");
		elemSubType;
		elemSubType = elemSubType->NextSiblingElement("subsprite"))
	{
		c_sprite subsprite;
		subsprite.set_size(spritewidth, spriteheight);
		subsprite.set_by_xml(elemSubType, fileindex);
		subsprite.set_offset(offset_x, offset_y);
		subsprites.push_back(subsprite);
	}
}
bool addSingleCreatureConfig( TiXmlElement* elemCreature, vector<vector<CreatureConfiguration>*>& knownCreatures, int basefile ){
  int gameID = lookupIndexedType(elemCreature->Attribute("gameID"),contentLoader.creatureNameStrings);
  if (gameID == INVALID_INDEX)
  	return false;
  const char* sheetIndexStr;
  t_SpriteWithOffset sprite;
  sprite.fileIndex=basefile;
  sprite.x=0;
  sprite.y=0;
  sprite.animFrames=ALL_FRAMES;
  int baseShadow = DEFAULT_SHADOW;
  const char* shadowStr = elemCreature->Attribute("shadow");
  if (shadowStr != NULL && shadowStr[0] != 0)
  {
	baseShadow = atoi( shadowStr );	  
  }
  if (baseShadow < 0 || baseShadow > MAX_SHADOW)
  	baseShadow = DEFAULT_SHADOW;
  const char* filename = elemCreature->Attribute("file");
	if (filename != NULL && filename[0] != 0)
	{
	  	sprite.fileIndex = loadConfigImgFile((char*)filename,elemCreature);
	}
  TiXmlElement* elemVariant = elemCreature->FirstChildElement("variant");
  while( elemVariant ){
	int professionID = INVALID_INDEX;
    const char* profStr = elemVariant->Attribute("prof");
    if (profStr == NULL || profStr[0] == 0)
    {
	    profStr = elemVariant->Attribute("profession");
    }
   	professionID = translateProfession(profStr);

    const char* customStr = elemVariant->Attribute("custom");
    if (customStr != NULL && customStr[0] == 0)
    {
	    customStr = NULL;
    } 
      
	if (customStr != NULL)
	{
		WriteErr("custom: %s\n",customStr);	
	}
    
    const char* sexstr = elemVariant->Attribute("sex");
    sheetIndexStr = elemVariant->Attribute("sheetIndex");
    enumCreatureSex cresex = eCreatureSex_NA;
    if(sexstr){
      if(strcmp( sexstr, "M" ) == 0) cresex = eCreatureSex_Male;
      if(strcmp( sexstr, "F" ) == 0) cresex = eCreatureSex_Female;
    }
    const char* specstr = elemVariant->Attribute("special");
    enumCreatureSpecialCases crespec = eCSC_Any;
    if (specstr)
    {
      if(strcmp( specstr, "Normal" ) == 0) crespec = eCSC_Normal;
      if(strcmp( specstr, "Zombie" ) == 0) crespec = eCSC_Zombie;	      
      if(strcmp( specstr, "Skeleton" ) == 0) crespec = eCSC_Skeleton;	      
    }
    sprite.animFrames = getAnimFrames(elemVariant->Attribute("frames"));
	if (sprite.animFrames == 0)
		sprite.animFrames = ALL_FRAMES;

	int shadow = baseShadow;
	const char* shadowStr = elemVariant->Attribute("shadow");
	if (shadowStr != NULL && shadowStr[0] != 0)
	{
		shadow = atoi( shadowStr );	  
	}
	if (shadow < 0 || shadow > MAX_SHADOW)
		shadow = baseShadow;
		    
    //create profession config
    sprite.sheetIndex=atoi(sheetIndexStr);
    CreatureConfiguration cre( professionID, customStr , cresex, crespec, sprite, shadow);
    //add a copy to known creatures
    pushCreatureConfig(knownCreatures, gameID, cre);

    elemVariant = elemVariant->NextSiblingElement("variant");
  }

  //create default config
  baseShadow;
  sheetIndexStr = elemCreature->Attribute("sheetIndex");
  sprite.animFrames = ALL_FRAMES;
  if (sheetIndexStr)
  {
	sprite.sheetIndex = atoi( sheetIndexStr );
    CreatureConfiguration cre( INVALID_INDEX, NULL, eCreatureSex_NA, eCSC_Any, sprite, baseShadow);
  	//add a copy to known creatures
    pushCreatureConfig(knownCreatures, gameID, cre);
  }
  return true;
}