forked from townforge/townforge
game: add a named areas page to the city maps
This commit is contained in:
parent
0feee23f0d
commit
660e78acea
@ -80,6 +80,7 @@ TBLayout: axis: y, distribution-position: "left top", distribution: "gravity"
|
||||
TBLayout: axis: y
|
||||
TBTabContainer: id: "maps", gravity: "all"
|
||||
tabs
|
||||
TBButton: text: "Places"
|
||||
TBButton: text: "Elevation"
|
||||
TBButton: text: "Stability"
|
||||
TBButton: text: "Agriculture"
|
||||
@ -90,6 +91,9 @@ TBLayout: axis: y, distribution-position: "left top", distribution: "gravity"
|
||||
TBButton: text: "Stone quantity"
|
||||
TBButton: text: "Gemstone"
|
||||
TBButton: text: "Manual"
|
||||
TBLayout: axis: y, gravity: "all", size: "available"
|
||||
TBTextField: text: "Hover mouse to see area names"
|
||||
UITBAnimatedImageWidget: id: "places-map"
|
||||
TBLayout: axis: y, gravity: "all", size: "available"
|
||||
TBTextField: text: "Higher score denotes higher elevation, water area in blue"
|
||||
TBTextField: text: "Preview only available at zoom level 5 or less"
|
||||
|
@ -88,24 +88,6 @@ static uint32_t index_data_template[36] = {
|
||||
|
||||
static inline int is_power_of_2(unsigned n) { return n && (n & (n-1)) == 0; }
|
||||
|
||||
// https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
||||
static Color GetRandomColor(size_t n, float alpha = 1.0f)
|
||||
{
|
||||
static constexpr float s = .85f;
|
||||
static constexpr float v = .95f;
|
||||
static constexpr float golden_ratio_conjugate = 0.618033988749895;
|
||||
float h = 0;
|
||||
while (n--)
|
||||
{
|
||||
h += golden_ratio_conjugate;
|
||||
h -= trunc(h);
|
||||
}
|
||||
Color c;
|
||||
c.FromHSV(h, s, v);
|
||||
c.a_ = alpha;
|
||||
return c;
|
||||
}
|
||||
|
||||
static uint16_t get_material_for_block(const std::shared_ptr<Flag> &flag, uint8_t block)
|
||||
{
|
||||
const uint16_t variant = block < flag->palette.size() ? flag->palette[block] : (uint16_t)cc::BLOCK_VARIANT_NONE;
|
||||
@ -2020,7 +2002,7 @@ void CityMeshSection::AddAreas(const std::shared_ptr<Flag> &flag)
|
||||
Technique *technique = cache->GetResource<Technique>("MaterialEffects/Techniques/DiffEmissiveGlow.xml");
|
||||
material->SetTechnique(0, technique);
|
||||
}
|
||||
material->SetShaderParameter("MatDiffColor", GetRandomColor(flag->owner, 1.0f));
|
||||
material->SetShaderParameter("MatDiffColor", game_util::GetRandomColor(flag->owner, 1.0f));
|
||||
resources.ownership_materials[std::make_pair(flag->owner, is_burning)] = material;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <memory>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <Urho3D/Math/Color.h>
|
||||
#include "reg_exp_definer.h"
|
||||
#include "common/util.h"
|
||||
#include "common/ipfs.h"
|
||||
@ -826,4 +827,22 @@ void update_accrual(std::vector<cryptonote::matchable_order_as_string_t> &orders
|
||||
});
|
||||
}
|
||||
|
||||
// https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
||||
Urho3D::Color GetRandomColor(size_t n, float alpha)
|
||||
{
|
||||
static constexpr float s = .85f;
|
||||
static constexpr float v = .95f;
|
||||
static constexpr float golden_ratio_conjugate = 0.618033988749895;
|
||||
float h = 0;
|
||||
while (n--)
|
||||
{
|
||||
h += golden_ratio_conjugate;
|
||||
h -= trunc(h);
|
||||
}
|
||||
Urho3D::Color c;
|
||||
c.FromHSV(h, s, v);
|
||||
c.a_ = alpha;
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,11 @@
|
||||
#include <map>
|
||||
#include "cryptonote_basic/cc_command_defs.h"
|
||||
|
||||
namespace Urho3D
|
||||
{
|
||||
class Color;
|
||||
}
|
||||
|
||||
class GameState;
|
||||
class GameWallet;
|
||||
class Flag;
|
||||
@ -37,5 +42,6 @@ uint64_t get_role_bonus_adjusted_shares(const GameState *game, uint64_t shares,
|
||||
bool get_resource_deltas(const GameState *game, const std::shared_ptr<Flag> &flag, uint32_t cartography_level, uint32_t logging_level, uint32_t quarrying_level, uint32_t management_level, int64_t &delta_gold, std::map<uint32_t, int32_t> &delta_items, int32_t &delta_food, int32_t &delta_heating);
|
||||
std::tuple<std::string, uint64_t, std::string> get_scarcest_resource(uint64_t balance, const std::map<uint32_t, uint32_t> &item_balances, int64_t delta_gold, int32_t delta_sandstone, int32_t delta_pine, int32_t delta_labour, int32_t delta_food, int32_t delta_heating);
|
||||
void update_accrual(std::vector<cryptonote::matchable_order_as_string_t> &orders, uint64_t height, bool ascending);
|
||||
Urho3D::Color GetRandomColor(size_t n, float alpha = 1.0f);
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ UICityMapsDialog::UICityMapsDialog(Context *ctx, const GameState *game, mode_t m
|
||||
mode(mode),
|
||||
refresh(true),
|
||||
cost(0),
|
||||
placesMap(NULL),
|
||||
elevationMap(NULL),
|
||||
stabilityMap(NULL),
|
||||
agricultureMap(NULL),
|
||||
@ -56,6 +57,7 @@ UICityMapsDialog::UICityMapsDialog(Context *ctx, const GameState *game, mode_t m
|
||||
seedWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("seed"));
|
||||
nameWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("name"));
|
||||
mapsWidget = GetWidgetByIDAndType<TBTabContainer>(TBIDC("maps"));
|
||||
placesMapWidget = GetWidgetByIDAndType<UITBAnimatedImageWidget>(TBIDC("places-map"));
|
||||
elevationMapWidget = GetWidgetByIDAndType<UITBAnimatedImageWidget>(TBIDC("elevation-map"));
|
||||
stabilityMapWidget = GetWidgetByIDAndType<UITBAnimatedImageWidget>(TBIDC("stability-map"));
|
||||
agricultureMapWidget = GetWidgetByIDAndType<UITBAnimatedImageWidget>(TBIDC("agriculture-map"));
|
||||
@ -116,8 +118,22 @@ UICityMapsDialog::UICityMapsDialog(Context *ctx, const GameState *game, mode_t m
|
||||
if (!game->debug)
|
||||
{
|
||||
TBButton *button = TBSafeCast<TBButton>(mapsWidget->GetTabLayout()->GetLastChild());
|
||||
if (button)
|
||||
TBWidget *widget = TBSafeCast<TBWidget>(mapsWidget->GetContentRoot()->GetLastChild());
|
||||
if (button && widget)
|
||||
{
|
||||
mapsWidget->GetTabLayout()->RemoveChild(button);
|
||||
mapsWidget->GetContentRoot()->RemoveChild(widget);
|
||||
}
|
||||
}
|
||||
if (mode == mode_found)
|
||||
{
|
||||
TBButton *button = TBSafeCast<TBButton>(mapsWidget->GetTabLayout()->GetFirstChild());
|
||||
TBWidget *widget = TBSafeCast<TBWidget>(mapsWidget->GetContentRoot()->GetFirstChild());
|
||||
if (button && widget)
|
||||
{
|
||||
mapsWidget->GetTabLayout()->RemoveChild(button);
|
||||
mapsWidget->GetContentRoot()->RemoveChild(widget);
|
||||
}
|
||||
}
|
||||
|
||||
offsetsContainer->SetValue(game->debug);
|
||||
@ -143,6 +159,7 @@ UICityMapsDialog::UICityMapsDialog(Context *ctx, const GameState *game, mode_t m
|
||||
|
||||
UICityMapsDialog::~UICityMapsDialog()
|
||||
{
|
||||
delete[] placesMap;
|
||||
delete[] elevationMap;
|
||||
delete[] stabilityMap;
|
||||
delete[] agricultureMap;
|
||||
@ -310,27 +327,14 @@ void UICityMapsDialog::UpdateManualParameters()
|
||||
|
||||
void UICityMapsDialog::UpdateValue()
|
||||
{
|
||||
const int selected = mapsWidget->GetValue();
|
||||
const int selected_offset = (mode == mode_found ? 1 : 0); // in found mode, the first page (areas) is removed
|
||||
const int selected = mapsWidget->GetValue() + selected_offset;
|
||||
|
||||
const int32_t dx = dxWidget->GetValue();
|
||||
const int32_t dy = dyWidget->GetValue();
|
||||
const int zoom = zoomWidget->GetValue();
|
||||
auto update_map = [zoom, dx, dy](UITBAnimatedImageWidget *widget, uint8_t *rgb, const std::function<uint32_t(uint32_t, uint32_t)> &f)
|
||||
auto draw_town_square = [zoom](uint8_t *rgb)
|
||||
{
|
||||
for (uint32_t y = 0; y < map_size; ++y)
|
||||
{
|
||||
uint32_t pidx = (map_size - 1 - y) * map_size;
|
||||
const uint32_t mapy = dy + (y - map_size / 2) * (1 << zoom);
|
||||
for (uint32_t x = 0; x < map_size; ++x, ++pidx)
|
||||
{
|
||||
const uint32_t mapx = dx + (x - map_size / 2) * (1 << zoom);
|
||||
const uint32_t value = f(mapx, mapy);
|
||||
rgb[pidx*4+0] = value >> 16;
|
||||
rgb[pidx*4+1] = value >> 8;
|
||||
rgb[pidx*4+2] = value;
|
||||
rgb[pidx*4+3] = 0xff;
|
||||
}
|
||||
}
|
||||
const uint32_t town_square_half_width = 128 / (1 << zoom);
|
||||
const uint32_t town_square_half_height = 128 / (1 << zoom);
|
||||
for (uint32_t y = map_size / 2 - town_square_half_height; y <= map_size / 2 + town_square_half_height; ++y)
|
||||
@ -351,6 +355,80 @@ void UICityMapsDialog::UpdateValue()
|
||||
rgb[pidx*4+0] = 0xff;
|
||||
rgb[pidx*4+1] = 0;
|
||||
}
|
||||
};
|
||||
auto update_map = [zoom, dx, dy, &draw_town_square](UITBAnimatedImageWidget *widget, uint8_t *rgb, const std::function<uint32_t(uint32_t, uint32_t)> &f)
|
||||
{
|
||||
for (uint32_t y = 0; y < map_size; ++y)
|
||||
{
|
||||
uint32_t pidx = (map_size - 1 - y) * map_size;
|
||||
const uint32_t mapy = dy + (y - map_size / 2) * (1 << zoom);
|
||||
for (uint32_t x = 0; x < map_size; ++x, ++pidx)
|
||||
{
|
||||
const uint32_t mapx = dx + (x - map_size / 2) * (1 << zoom);
|
||||
const uint32_t value = f(mapx, mapy);
|
||||
rgb[pidx*4+0] = value >> 16;
|
||||
rgb[pidx*4+1] = value >> 8;
|
||||
rgb[pidx*4+2] = value;
|
||||
rgb[pidx*4+3] = 0xff;
|
||||
}
|
||||
}
|
||||
draw_town_square(rgb);
|
||||
std::shared_ptr<tb::TBBitmap> bitmap(UTBRendererBatcher::Singleton().CreateBitmap(map_size, map_size, (uint32_t*)rgb));
|
||||
widget->SetAnimation(std::vector<std::pair<std::shared_ptr<tb::TBBitmap>, unsigned int>>(1, std::make_pair(std::move(bitmap), 1)));
|
||||
};
|
||||
auto update_places_map = [this, zoom, dx, dy, &draw_town_square](UITBAnimatedImageWidget *widget, uint8_t *rgb, const std::vector<std::shared_ptr<cc::place_t>> &places)
|
||||
{
|
||||
for (uint32_t pidx = 0; pidx < map_size * map_size; ++pidx)
|
||||
{
|
||||
rgb[pidx*4+0] = 0;
|
||||
rgb[pidx*4+1] = 0;
|
||||
rgb[pidx*4+2] = 0;
|
||||
rgb[pidx*4+3] = 0xff;
|
||||
}
|
||||
for (const std::shared_ptr<cc::place_t> &place: places)
|
||||
{
|
||||
if (place->name.empty())
|
||||
continue;
|
||||
const int32_t px0 = (int32_t)((place->x0 - ox + dx)) / (1 << zoom) + map_size / 2;
|
||||
const int32_t py0 = (int32_t)((place->y0 - oy + dy)) / (1 << zoom) + map_size / 2;
|
||||
const int32_t px1 = (int32_t)((place->x1 - ox + dx)) / (1 << zoom) + map_size / 2;
|
||||
const int32_t py1 = (int32_t)((place->y1 - oy + dy)) / (1 << zoom) + map_size / 2;
|
||||
if (px0 < 0) continue;
|
||||
if (py0 < 0) continue;
|
||||
if (px1 > (int32_t)map_size) continue;
|
||||
if (py1 > (int32_t)map_size) continue;
|
||||
|
||||
uint32_t c = 0;
|
||||
auto i = area_colors.find(place->name);
|
||||
if (i == area_colors.end())
|
||||
{
|
||||
const Urho3D::Color color = game_util::GetRandomColor(area_colors.size());
|
||||
const uint8_t r = (uint8_t)(color.r_ * 255.0f);
|
||||
const uint8_t g = (uint8_t)(color.g_ * 255.0f);
|
||||
const uint8_t b = (uint8_t)(color.b_ * 255.0f);
|
||||
c = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
i = area_colors.insert(std::make_pair(place->name, c)).first;
|
||||
color_areas[c] = place->name;
|
||||
}
|
||||
else
|
||||
c = i->second;
|
||||
|
||||
const uint8_t r = c >> 16;
|
||||
const uint8_t g = c >> 8;
|
||||
const uint8_t b = c;
|
||||
for (int32_t y = py0; y < py1; ++y)
|
||||
{
|
||||
uint32_t pidx = (map_size - 1 - y) * map_size + px0;
|
||||
for (int32_t x = px0; x < px1; ++x, ++pidx)
|
||||
{
|
||||
rgb[pidx*4+0] = r;
|
||||
rgb[pidx*4+1] = g;
|
||||
rgb[pidx*4+2] = b;
|
||||
rgb[pidx*4+3] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
draw_town_square(rgb);
|
||||
std::shared_ptr<tb::TBBitmap> bitmap(UTBRendererBatcher::Singleton().CreateBitmap(map_size, map_size, (uint32_t*)rgb));
|
||||
widget->SetAnimation(std::vector<std::pair<std::shared_ptr<tb::TBBitmap>, unsigned int>>(1, std::make_pair(std::move(bitmap), 1)));
|
||||
};
|
||||
@ -371,6 +449,23 @@ void UICityMapsDialog::UpdateValue()
|
||||
switch (selected)
|
||||
{
|
||||
case 0:
|
||||
if (!placesMap)
|
||||
{
|
||||
placesMap = new uint8_t[4 * map_size * map_size];
|
||||
std::set<std::shared_ptr<cc::place_t>> places;
|
||||
game->map.get_all_places(expected_city_id, places);
|
||||
std::vector<std::shared_ptr<cc::place_t>> sorted_places;
|
||||
sorted_places.reserve(places.size());
|
||||
for (const std::shared_ptr<cc::place_t> &place: places)
|
||||
sorted_places.push_back(place);
|
||||
std::sort(sorted_places.begin(), sorted_places.end(), [](const std::shared_ptr<cc::place_t> &p0, const std::shared_ptr<cc::place_t> &p1){
|
||||
return p0->priority < p1->priority;
|
||||
});
|
||||
update_places_map(placesMapWidget, placesMap, sorted_places);
|
||||
}
|
||||
rgb = placesMap;
|
||||
break;
|
||||
case 1:
|
||||
if (!elevationMap)
|
||||
{
|
||||
if (zoom <= 5)
|
||||
@ -405,39 +500,39 @@ void UICityMapsDialog::UpdateValue()
|
||||
}
|
||||
rgb = elevationMap;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
UPDATE_MAP(stability, cc::get_cc_stability);
|
||||
rgb = stabilityMap;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
UPDATE_MAP(agriculture, cc::get_cc_agricultural_potential);
|
||||
rgb = agricultureMap;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
UPDATE_MAP(geothermalHeating, cc::get_cc_geothermal_heating);
|
||||
rgb = geothermalHeatingMap;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
UPDATE_MAP(woodType, cc::get_cc_wood_type_potential);
|
||||
rgb = woodTypeMap;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
UPDATE_MAP(woodQuantity, cc::get_cc_wood_quantity_potential);
|
||||
rgb = woodQuantityMap;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
UPDATE_MAP(stoneType, cc::get_cc_stone_type_potential);
|
||||
rgb = stoneTypeMap;
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
UPDATE_MAP(stoneQuantity, cc::get_cc_stone_quantity_potential);
|
||||
rgb = stoneQuantityMap;
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
UPDATE_MAP(gemstone, cc::get_cc_gemstone_potential);
|
||||
rgb = gemstoneMap;
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
{
|
||||
if (!manualMap)
|
||||
{
|
||||
@ -481,10 +576,23 @@ void UICityMapsDialog::UpdateValue()
|
||||
valueWidget->SetText("");
|
||||
return;
|
||||
}
|
||||
|
||||
xWidget->SetText(std::to_string((int32_t)(dx + mouse_x - map_size / 2)).c_str());
|
||||
yWidget->SetText(std::to_string((int32_t)(dy + mouse_y - map_size / 2)).c_str());
|
||||
const uint8_t value = rgb[4 * (mouse_x + mouse_y * map_size) + 2];
|
||||
valueWidget->SetText(String((unsigned)value).CString());
|
||||
if (selected == 0)
|
||||
{
|
||||
const uint8_t r = rgb[4 * (mouse_x + mouse_y * map_size) + 0];
|
||||
const uint8_t g = rgb[4 * (mouse_x + mouse_y * map_size) + 1];
|
||||
const uint8_t b = rgb[4 * (mouse_x + mouse_y * map_size) + 2];
|
||||
const uint32_t c = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
const auto i = color_areas.find(c);
|
||||
valueWidget->SetText(i == color_areas.end() ? "" : i->second.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t value = rgb[4 * (mouse_x + mouse_y * map_size) + 2];
|
||||
valueWidget->SetText(String((unsigned)value).CString());
|
||||
}
|
||||
}
|
||||
|
||||
void UICityMapsDialog::UpdateMaps()
|
||||
@ -497,6 +605,7 @@ void UICityMapsDialog::UpdateMaps()
|
||||
state = cc::get_cc_potential_state(id == -1 ? expected_city_id : id, seed);
|
||||
cc::get_city_origin(id == -1 ? expected_city_id : id, ox, oy);
|
||||
|
||||
delete[] placesMap; placesMap = NULL;
|
||||
delete[] elevationMap; elevationMap = NULL;
|
||||
delete[] stabilityMap; stabilityMap = NULL;
|
||||
delete[] agricultureMap; agricultureMap = NULL;
|
||||
@ -599,6 +708,7 @@ void UICityMapsDialog::HandleTBMessage(StringHash eventType, VariantMap& eventDa
|
||||
}
|
||||
else if (ev->type == EVENT_TYPE_POINTER_MOVE)
|
||||
{
|
||||
CONNECT("places-map", HandleMouseMotion);
|
||||
CONNECT("elevation-map", HandleMouseMotion);
|
||||
CONNECT("stability-map", HandleMouseMotion);
|
||||
CONNECT("agriculture-map", HandleMouseMotion);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef UI_CITY_MAPS_H
|
||||
#define UI_FOUND_CITY_H
|
||||
#define UI_CITY_MAPS_H
|
||||
|
||||
#include <Urho3D/Core/Object.h>
|
||||
#include <Urho3D/Container/Str.h>
|
||||
@ -82,6 +82,7 @@ private:
|
||||
tb::TBEditField *seedWidget;
|
||||
tb::TBEditField *nameWidget;
|
||||
tb::TBTabContainer *mapsWidget;
|
||||
UITBAnimatedImageWidget *placesMapWidget;
|
||||
UITBAnimatedImageWidget *elevationMapWidget;
|
||||
UITBAnimatedImageWidget *stabilityMapWidget;
|
||||
UITBAnimatedImageWidget *agricultureMapWidget;
|
||||
@ -118,6 +119,7 @@ private:
|
||||
uint64_t cost;
|
||||
uint32_t expected_city_id;
|
||||
|
||||
uint8_t *placesMap;
|
||||
uint8_t *elevationMap;
|
||||
uint8_t *stabilityMap;
|
||||
uint8_t *agricultureMap;
|
||||
@ -147,6 +149,9 @@ private:
|
||||
uint32_t ox;
|
||||
uint32_t oy;
|
||||
std::shared_ptr<cc::cc_potential_state_t> state;
|
||||
|
||||
std::map<std::string, uint32_t> area_colors;
|
||||
std::map<uint32_t, std::string> color_areas;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user