// Sets all undefined properties in the dictionary to their defaults. void PropertySpecification::SetPropertyDefaults(PropertyDictionary& dictionary) const { for (PropertyMap::const_iterator i = properties.begin(); i != properties.end(); ++i) { if (dictionary.GetProperty((*i).first) == NULL) dictionary.SetProperty((*i).first, *(*i).second->GetDefaultValue()); } }
GradientDecorator( const PropertyDictionary& properties ) { // fetch the properties from the dict String prop_dir = properties.GetProperty( "dir" )->Get<String>(); start = properties.GetProperty( "start" )->Get<Colourb>(); end = properties.GetProperty( "end" )->Get<Colourb>(); // enumerate direction property dir = ( prop_dir == "horizontal" ? HORIZONTAL : VERTICAL ); }
// Retrieves all the properties for a tile from the property dictionary. void DecoratorTiledInstancer::GetTileProperties(DecoratorTiled::Tile& tile, String& texture_name, String& rcss_path, const PropertyDictionary& properties, const String& name) { LoadTexCoord(properties, String(32, "%s-s-begin", name.CString()), tile.texcoords[0].x, tile.texcoords_absolute[0][0]); LoadTexCoord(properties, String(32, "%s-t-begin", name.CString()), tile.texcoords[0].y, tile.texcoords_absolute[0][1]); LoadTexCoord(properties, String(32, "%s-s-end", name.CString()), tile.texcoords[1].x, tile.texcoords_absolute[1][0]); LoadTexCoord(properties, String(32, "%s-t-end", name.CString()), tile.texcoords[1].y, tile.texcoords_absolute[1][1]); const Property* repeat_property = properties.GetProperty(String(32, "%s-repeat", name.CString())); if (repeat_property != NULL) tile.repeat_mode = (DecoratorTiled::TileRepeatMode) repeat_property->value.Get< int >(); const Property* texture_property = properties.GetProperty(String(32, "%s-src", name.CString())); texture_name = texture_property->Get< String >(); rcss_path = texture_property->source; }
// Get decorator-id property from properties or "" if not id is given. String DecoratorInstancer::GetDecoratorIdProperty(const PropertyDictionary& properties) { const Property* id_property = properties.GetProperty("decorator-id"); if (id_property) { String decorator_id = id_property->Get< String >(); return decorator_id; } return ""; }
// Updates a property dictionary of all properties for a single group. int ElementDefinition::BuildPropertyGroupDictionary(PropertyDictionary& group_properties, const String& ROCKET_UNUSED(group_type), const String& group_name, const PropertyDictionary& element_properties) { int num_properties = 0; PropertyMap::const_iterator property_iterator; for (property_iterator = element_properties.GetProperties().begin(); property_iterator != element_properties.GetProperties().end(); ++property_iterator) { const String& full_property_name = (*property_iterator).first; if (full_property_name.Length() > group_name.Length() + 1 && strncasecmp(full_property_name.CString(), group_name.CString(), group_name.Length()) == 0 && full_property_name[group_name.Length()] == '-') { String property_name = full_property_name.Substring(group_name.Length() + 1); // if (property_name == group_type) // continue; group_properties.SetProperty(property_name, (*property_iterator).second); num_properties++; } } return num_properties; }
// Loads a single texture coordinate value from the properties. void DecoratorTiledInstancer::LoadTexCoord(const PropertyDictionary& properties, const String& name, float& tex_coord, bool& tex_coord_absolute) { const Property* property = properties.GetProperty(name); if (property == NULL) return; tex_coord = property->value.Get< float >(); if (property->unit == Property::PX) tex_coord_absolute = true; else { tex_coord_absolute = false; if (property->unit == Property::PERCENT) tex_coord *= 0.01f; } }
// Returns the floating-point value of a numerical property from a dictionary of properties. float Decorator::ResolveProperty(const PropertyDictionary& properties, const String& name, float base_value) const { const Property* property = properties.GetProperty(name); if (property == NULL) { ROCKET_ERROR; return 0; } // Need to include em! if (property->unit & Property::RELATIVE_UNIT) return base_value * property->value.Get< float >() * 0.01f; if (property->unit & Property::NUMBER || property->unit & Property::PX) return property->value.Get< float >(); if (property->unit & Property::GSP) return property->value.Get< float >() * Rocket::Core::GetRenderInterface()->GetPixelScale(); // Values based on pixels-per-inch. if (property->unit & Property::PPI_UNIT) { float inch = property->value.Get< float >() * GetRenderInterface()->GetPixelsPerInch(); if (property->unit & Property::INCH) // inch return inch; if (property->unit & Property::CM) // centimeter return inch / 2.54f; if (property->unit & Property::MM) // millimeter return inch / 25.4f; if (property->unit & Property::PT) // point return inch / 72.0f; if (property->unit & Property::PC) // pica return inch / 6.0f; } ROCKET_ERROR; return 0; }
MapDonutRoom::MapDonutRoom(Map& m, PropertyDictionary const& s, GeoVector vec) : MapFeature{ m, s, vec } { unsigned int num_tries = 0; unsigned int minWidth = s.get("min_width", 7); unsigned int maxWidth = s.get("max_width", 20); unsigned int minHeight = s.get("min_height", 7); unsigned int maxHeight = s.get("max_height", 20); unsigned int min_hole_size = s.get("min_hole_size", 5); unsigned int max_retries = s.get("max_retries", 500); std::string floorMaterial = s.get("floor_type", "Dirt"); std::string wallMaterial = s.get("wall_type", "Stone"); IntVec2& starting_coords = vec.start_point; Direction& direction = vec.direction; while (num_tries < max_retries) { sf::IntRect rect; rect.width = the_RNG.pick_uniform(minWidth, maxWidth); rect.height = the_RNG.pick_uniform(minHeight, maxHeight); if (direction == Direction::North) { int offset = the_RNG.pick_uniform(0, rect.width - 1); rect.top = starting_coords.y - rect.height; rect.left = starting_coords.x - offset; } else if (direction == Direction::South) { int offset = the_RNG.pick_uniform(0, rect.width - 1); rect.top = starting_coords.y + 1; rect.left = starting_coords.x - offset; } else if (direction == Direction::West) { int offset = the_RNG.pick_uniform(0, rect.height - 1); rect.top = starting_coords.y - offset; rect.left = starting_coords.x - rect.width; } else if (direction == Direction::East) { int offset = the_RNG.pick_uniform(0, rect.height - 1); rect.top = starting_coords.y - offset; rect.left = starting_coords.x + 1; } else { throw MapFeatureException("Invalid direction passed to MapDonutRoom constructor"); } if ((getMap().isInBounds({ rect.left - 1, rect.top - 1 })) && (getMap().isInBounds({ rect.left + rect.width, rect.top + rect.height }))) { bool okay = true; okay = doesBoxPassCriterion({ rect.left - 1, rect.top - 1 }, { rect.left + rect.width, rect.top + rect.height }, [&](MapTile& tile) { return !tile.isPassable(); }); // Create the hole location. sf::IntRect hole; int x_hole_left = the_RNG.pick_uniform(rect.left + 1, rect.left + rect.width - 2); int x_hole_right = the_RNG.pick_uniform(rect.left + 1, rect.left + rect.width - 2); int y_hole_top = the_RNG.pick_uniform(rect.top + 1, rect.top + rect.height - 2); int y_hole_bottom = the_RNG.pick_uniform(rect.top + 1, rect.top + rect.height - 2); // Make sure the hole isn't TOO small. // GSL GRUMBLE: WHY does abs() return a signed value?!? if ((static_cast<unsigned int>(abs(x_hole_right - x_hole_left)) < min_hole_size - 1) || (static_cast<unsigned int>(abs(y_hole_bottom - y_hole_top)) < min_hole_size - 1)) { okay = false; } if (x_hole_right < x_hole_left) std::swap(x_hole_left, x_hole_right); if (y_hole_bottom < y_hole_top) std::swap(y_hole_top, y_hole_bottom); if (okay) { // Clear out the box EXCEPT FOR the hole. for (int x_coord = rect.left; x_coord <= rect.left + rect.width - 1; ++x_coord) { for (int y_coord = rect.top; y_coord <= rect.top + rect.height - 1; ++y_coord) { if (!((x_coord >= x_hole_left) && (x_coord <= x_hole_right) && (y_coord >= y_hole_top) && (y_coord <= y_hole_bottom))) { auto& tile = getMap().getTile({ x_coord, y_coord }); tile.setTileType({ "Floor", floorMaterial }, { "OpenSpace" }); } } } setCoords(rect); // Add the surrounding walls as potential connection points. // Horizontal walls... for (int x_coord = rect.left + 1; x_coord <= rect.left + rect.width - 1; ++x_coord) { addGrowthVector(GeoVector(x_coord, rect.top - 1, Direction::North)); addGrowthVector(GeoVector(x_coord, rect.top + rect.height, Direction::South)); } // Vertical walls... for (int y_coord = rect.top + 1; y_coord <= rect.top + rect.height - 1; ++y_coord) { addGrowthVector(GeoVector(rect.left - 1, y_coord, Direction::West)); addGrowthVector(GeoVector(rect.left + rect.width, y_coord, Direction::East)); } // Do the same for the hole walls. // Horizontal walls... for (int x_coord = x_hole_left + 1; x_coord < x_hole_right; ++x_coord) { addGrowthVector(GeoVector(x_coord, y_hole_bottom, Direction::North)); addGrowthVector(GeoVector(x_coord, y_hole_top, Direction::South)); } // Vertical walls... for (int y_coord = y_hole_top + 1; y_coord < y_hole_bottom; ++y_coord) { addGrowthVector(GeoVector(x_hole_right, y_coord, Direction::West)); addGrowthVector(GeoVector(x_hole_left, y_coord, Direction::East)); } /// @todo Put either a door or an open area at the starting coords. /// Right now we just make it an open area. auto& startTile = getMap().getTile(starting_coords); startTile.setTileType({ "Floor", floorMaterial }, { "OpenSpace" }); return; } } ++num_tries; } throw MapFeatureException("Out of tries attempting to make MapDonutRoom"); }
// Finds all propery declarations for a group. void ElementDefinition::BuildPropertyGroup(PropertyGroupMap& groups, const String& group_type, const PropertyDictionary& element_properties, const PropertyGroupMap* default_properties) { String property_suffix = "-" + group_type; PropertyMap::const_iterator property_iterator; for (property_iterator = element_properties.GetProperties().begin(); property_iterator != element_properties.GetProperties().end(); ++property_iterator) { const String& property_name = (*property_iterator).first; if (property_name.Length() > property_suffix.Length() && strcasecmp(property_name.CString() + (property_name.Length() - property_suffix.Length()), property_suffix.CString()) == 0) { // We've found a group declaration! String group_name = property_name.Substring(0, property_name.Length() - (group_type.Length() + 1)); String group_class = (*property_iterator).second.value.Get< String >(); PropertyDictionary* group_properties = NULL; // Check if we have an existing definition by this name; if so, we're only overriding the type. PropertyGroupMap::iterator existing_definition = groups.find(group_name); if (existing_definition != groups.end()) { (*existing_definition).second.first = group_class; group_properties = &(*existing_definition).second.second; } else { // Check if we have any default decorator definitions, and if the new decorator has a default. If so, // we make a copy of the default properties for the new decorator. if (default_properties != NULL) { PropertyGroupMap::const_iterator default_definition = default_properties->find(group_name); if (default_definition != default_properties->end()) group_properties = &(*groups.insert(PropertyGroupMap::value_type(group_name, PropertyGroup(group_class, (*default_definition).second.second))).first).second.second; } // If we still haven't got somewhere to put the properties for the new decorator, make a new // definition. if (group_properties == NULL) group_properties = &(*groups.insert(PropertyGroupMap::value_type(group_name, PropertyGroup(group_class, PropertyDictionary()))).first).second.second; } // Now find all of this decorator's properties. BuildPropertyGroupDictionary(*group_properties, group_type, group_name, element_properties); } } // Now go through all the default decorator definitions and see if the new property list redefines any properties // used by them. if (default_properties != NULL) { for (PropertyGroupMap::const_iterator default_definition_iterator = default_properties->begin(); default_definition_iterator != default_properties->end(); ++default_definition_iterator) { const String& default_definition_name = (*default_definition_iterator).first; // Check the list of new definitions hasn't defined this decorator already; if so, it overrode the // decorator type and so has inherited all the properties anyway. if (groups.find(default_definition_name) == groups.end()) { // Nope! Make a copy of the decorator's properties and see if the new dictionary overrides any of the // properties. PropertyDictionary decorator_properties = (*default_definition_iterator).second.second; if (BuildPropertyGroupDictionary(decorator_properties, group_type, default_definition_name, element_properties) > 0) groups[default_definition_name] = PropertyGroup((*default_definition_iterator).second.first, decorator_properties); } } } }
// Parses a property declaration, setting any parsed and validated properties on the given dictionary. bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value, const String& source_file, int source_line_number) const { String lower_case_name = property_name.ToLower(); // Attempt to parse as a single property. const PropertyDefinition* property_definition = GetProperty(lower_case_name); StringList property_values; if (!ParsePropertyValues(property_values, property_value, property_definition == NULL) || property_values.size() == 0) return false; if (property_definition != NULL) { Property new_property; new_property.source = source_file; new_property.source_line_number = source_line_number; if (property_definition->ParseValue(new_property, property_values[0])) { dictionary.SetProperty(lower_case_name, new_property); return true; } return false; } // Try as a shorthand. const PropertyShorthandDefinition* shorthand_definition = GetShorthand(lower_case_name); if (shorthand_definition != NULL) { // If this definition is a 'box'-style shorthand (x-top, x-right, x-bottom, x-left, etc) and there are fewer // than four values if (shorthand_definition->type == BOX && property_values.size() < 4) { switch (property_values.size()) { // Only one value is defined, so it is parsed onto all four sides. case 1: { for (int i = 0; i < 4; i++) { Property new_property; if (!shorthand_definition->properties[i].second->ParseValue(new_property, property_values[0])) return false; new_property.source = source_file; new_property.source_line_number = source_line_number; dictionary.SetProperty(shorthand_definition->properties[i].first, new_property); } } break; // Two values are defined, so the first one is parsed onto the top and bottom value, the second onto // the left and right. case 2: { // Parse the first value into the top and bottom properties. Property new_property; new_property.source = source_file; new_property.source_line_number = source_line_number; if (!shorthand_definition->properties[0].second->ParseValue(new_property, property_values[0])) return false; dictionary.SetProperty(shorthand_definition->properties[0].first, new_property); if (!shorthand_definition->properties[2].second->ParseValue(new_property, property_values[0])) return false; dictionary.SetProperty(shorthand_definition->properties[2].first, new_property); // Parse the second value into the left and right properties. if (!shorthand_definition->properties[1].second->ParseValue(new_property, property_values[1])) return false; dictionary.SetProperty(shorthand_definition->properties[1].first, new_property); if (!shorthand_definition->properties[3].second->ParseValue(new_property, property_values[1])) return false; dictionary.SetProperty(shorthand_definition->properties[3].first, new_property); } break; // Three values are defined, so the first is parsed into the top value, the second onto the left and // right, and the third onto the bottom. case 3: { // Parse the first value into the top property. Property new_property; new_property.source = source_file; new_property.source_line_number = source_line_number; if (!shorthand_definition->properties[0].second->ParseValue(new_property, property_values[0])) return false; dictionary.SetProperty(shorthand_definition->properties[0].first, new_property); // Parse the second value into the left and right properties. if (!shorthand_definition->properties[1].second->ParseValue(new_property, property_values[1])) return false; dictionary.SetProperty(shorthand_definition->properties[1].first, new_property); if (!shorthand_definition->properties[3].second->ParseValue(new_property, property_values[1])) return false; dictionary.SetProperty(shorthand_definition->properties[3].first, new_property); // Parse the third value into the bottom property. if (!shorthand_definition->properties[2].second->ParseValue(new_property, property_values[2])) return false; dictionary.SetProperty(shorthand_definition->properties[2].first, new_property); } break; default: break; } } else { size_t value_index = 0; size_t property_index = 0; for (; value_index < property_values.size() && property_index < shorthand_definition->properties.size(); property_index++) { Property new_property; new_property.source = source_file; new_property.source_line_number = source_line_number; if (!shorthand_definition->properties[property_index].second->ParseValue(new_property, property_values[value_index])) { // This definition failed to parse; if we're falling through, try the next property. If there is no // next property, then abort! if (shorthand_definition->type == FALL_THROUGH) { if (property_index + 1 < shorthand_definition->properties.size()) continue; } return false; } dictionary.SetProperty(shorthand_definition->properties[property_index].first, new_property); // Increment the value index, unless we're replicating the last value and we're up to the last value. if (shorthand_definition->type != REPLICATE || value_index < property_values.size() - 1) value_index++; } } return true; } // Can't find it! Store as an unknown string value. Property new_property(property_value, Property::UNKNOWN); new_property.source = source_file; new_property.source_line_number = source_line_number; dictionary.SetProperty(lower_case_name, new_property); return true; }