This commit is contained in:
bart
2026-11-08 17:06:47 +01:00
parent 17901ce25c
commit 408541c7e0
46 changed files with 1474 additions and 1057 deletions
+46 -10
View File
@@ -67,7 +67,9 @@ SOURCES = main.cpp \
city.cpp \
terrainyieldmanager.cpp \
gamemanager.cpp \
unitrenderer.cpp qrc_shaders.cpp \
unitrenderer.cpp \
localization.cpp \
terrainmovementmanager.cpp qrc_shaders.cpp \
moc_mainwindow.cpp
OBJECTS = main.o \
mainwindow.o \
@@ -85,6 +87,8 @@ OBJECTS = main.o \
terrainyieldmanager.o \
gamemanager.o \
unitrenderer.o \
localization.o \
terrainmovementmanager.o \
qrc_shaders.o \
moc_mainwindow.o
DIST = shaders/simple.vert \
@@ -194,7 +198,9 @@ DIST = shaders/simple.vert \
city.h \
terrainyieldmanager.h \
gamemanager.h \
unitrenderer.h main.cpp \
unitrenderer.h \
localization.h \
terrainmovementmanager.h main.cpp \
mainwindow.cpp \
qscenerenderer.cpp \
vertex.cpp \
@@ -209,7 +215,9 @@ DIST = shaders/simple.vert \
city.cpp \
terrainyieldmanager.cpp \
gamemanager.cpp \
unitrenderer.cpp
unitrenderer.cpp \
localization.cpp \
terrainmovementmanager.cpp
QMAKE_TARGET = tiletest
DESTDIR =
TARGET = tiletest
@@ -416,8 +424,8 @@ distdir: FORCE
$(COPY_FILE) --parents $(DIST) $(DISTDIR)/
$(COPY_FILE) --parents shaders.qrc $(DISTDIR)/
$(COPY_FILE) --parents /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/data/dummy.cpp $(DISTDIR)/
$(COPY_FILE) --parents mainwindow.h qscenerenderer.h vertex.h tile.h terrain.h tilevertexinfo.h matrix2d.h face.h player.h yamlparser.h unitconfig.h pathfinder.h unit.h city.h terrainyieldmanager.h gamemanager.h unitrenderer.h $(DISTDIR)/
$(COPY_FILE) --parents main.cpp mainwindow.cpp qscenerenderer.cpp vertex.cpp tile.cpp tilevertexinfo.cpp face.cpp player.cpp yamlparser.cpp unitconfig.cpp pathfinder.cpp unit.cpp city.cpp terrainyieldmanager.cpp gamemanager.cpp unitrenderer.cpp $(DISTDIR)/
$(COPY_FILE) --parents mainwindow.h qscenerenderer.h vertex.h tile.h terrain.h tilevertexinfo.h matrix2d.h face.h player.h yamlparser.h unitconfig.h pathfinder.h unit.h city.h terrainyieldmanager.h gamemanager.h unitrenderer.h localization.h terrainmovementmanager.h $(DISTDIR)/
$(COPY_FILE) --parents main.cpp mainwindow.cpp qscenerenderer.cpp vertex.cpp tile.cpp tilevertexinfo.cpp face.cpp player.cpp yamlparser.cpp unitconfig.cpp pathfinder.cpp unit.cpp city.cpp terrainyieldmanager.cpp gamemanager.cpp unitrenderer.cpp localization.cpp terrainmovementmanager.cpp $(DISTDIR)/
$(COPY_FILE) --parents mainwindow.ui $(DISTDIR)/
@@ -484,6 +492,7 @@ ui_mainwindow.h: mainwindow.ui \
unitrenderer.h \
unit.h \
unitconfig.h \
terrainmovementmanager.h \
player.h \
city.h \
gamemanager.h \
@@ -515,6 +524,7 @@ mainwindow.o: mainwindow.cpp mainwindow.h \
unitrenderer.h \
unit.h \
unitconfig.h \
terrainmovementmanager.h \
player.h \
city.h \
gamemanager.h \
@@ -531,11 +541,13 @@ qscenerenderer.o: qscenerenderer.cpp qscenerenderer.h \
unitrenderer.h \
unit.h \
unitconfig.h \
terrainmovementmanager.h \
player.h \
city.h \
gamemanager.h \
terrainyieldmanager.h \
pathfinder.h
pathfinder.h \
yamlparser.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o qscenerenderer.o qscenerenderer.cpp
vertex.o: vertex.cpp vertex.h \
@@ -553,6 +565,7 @@ tile.o: tile.cpp tile.h \
unitrenderer.h \
unit.h \
unitconfig.h \
terrainmovementmanager.h \
player.h \
city.h \
gamemanager.h \
@@ -576,16 +589,22 @@ yamlparser.o: yamlparser.cpp yamlparser.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o yamlparser.o yamlparser.cpp
unitconfig.o: unitconfig.cpp unitconfig.h \
terrainmovementmanager.h \
terrain.h \
matrix2d.h \
yamlparser.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o unitconfig.o unitconfig.cpp
pathfinder.o: pathfinder.cpp pathfinder.h \
terrain.h \
matrix2d.h
matrix2d.h \
terrainmovementmanager.h \
unitconfig.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o pathfinder.o pathfinder.cpp
unit.o: unit.cpp unit.h \
unitconfig.h \
terrainmovementmanager.h \
terrain.h \
matrix2d.h \
pathfinder.h
@@ -598,6 +617,7 @@ city.o: city.cpp city.h \
terrainyieldmanager.o: terrainyieldmanager.cpp terrainyieldmanager.h \
terrain.h \
matrix2d.h \
terrainmovementmanager.h \
yamlparser.h \
pathfinder.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o terrainyieldmanager.o terrainyieldmanager.cpp
@@ -605,24 +625,40 @@ terrainyieldmanager.o: terrainyieldmanager.cpp terrainyieldmanager.h \
gamemanager.o: gamemanager.cpp gamemanager.h \
player.h \
unitconfig.h \
unit.h \
terrainmovementmanager.h \
terrain.h \
matrix2d.h \
unit.h \
city.h \
terrainyieldmanager.h \
pathfinder.h \
yamlparser.h
yamlparser.h \
localization.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o gamemanager.o gamemanager.cpp
unitrenderer.o: unitrenderer.cpp unitrenderer.h \
unit.h \
unitconfig.h \
terrainmovementmanager.h \
terrain.h \
matrix2d.h \
player.h \
city.h
city.h \
pathfinder.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o unitrenderer.o unitrenderer.cpp
localization.o: localization.cpp localization.h \
yamlparser.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o localization.o localization.cpp
terrainmovementmanager.o: terrainmovementmanager.cpp terrainmovementmanager.h \
terrain.h \
matrix2d.h \
unitconfig.h \
pathfinder.h \
yamlparser.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o terrainmovementmanager.o terrainmovementmanager.cpp
qrc_shaders.o: qrc_shaders.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o qrc_shaders.o qrc_shaders.cpp
-1
View File
@@ -1 +0,0 @@
/home/bart/project/tiletest/AGENTS.md
+7
View File
@@ -29,6 +29,7 @@ public:
int inhabitants;
int inhabitantsPerPop;
int accumulatedLabor = 0; // Local resource (Arbeid)
std::vector<std::pair<int, int>> territory; // Owned hex coordinates
std::map<std::pair<int, int>, QString> workedTiles; // (x, y) -> resource name
@@ -36,6 +37,12 @@ public:
City(int cId, int pId, const QString &cName, int tx, int ty, const QVector3D &pos,
int initInhabitants = 1000, int initInhabitantsPerPop = 100000, int initRadius = 1);
bool addTerritory(int tx, int ty) {
if (ownsTile(tx, ty)) return false;
territory.emplace_back(tx, ty);
return true;
}
int getTotalPop() const {
return (int)std::ceil((float)inhabitants / (float)std::max(1, inhabitantsPerPop));
}
BIN
View File
Binary file not shown.
+22
View File
@@ -6,3 +6,25 @@ inhabitants_per_pop: 100000
initial_border_radius: 1
max_workable_radius: 3
default_tile_slots: 1
city_view_zoom: 4.8
# Per-tick resource generation & mechanics
base_resource_yield_per_tick: 500
tile_culture_cost: 10000
food_to_inhabitants_ratio: 1.0
# Base yield breakdown per resource (default 500 per tick)
base_yields:
voedsel: 500
arbeid: 500
kennis: 500
cultuur: 500
geloof: 500
goud: 500
# Initial player national resources
initial_national_resources:
cultuur: 10000
kennis: 0
geloof: 0
goud: 0
+7
View File
@@ -1 +1,8 @@
movement_tick_duration: 30.0
# Camera settings
camera:
min_zoom: 2.0
max_zoom: 16.0
pitch_min_deg: 45.0 # Pitch angle when close up (45° = 3D perspective)
pitch_max_deg: 75.0 # Pitch angle when zoomed out (75° = look downward, limiting rendered hexagons)
+61
View File
@@ -0,0 +1,61 @@
# English localization strings for UI, HUD, actions, and game messages
locale: en
ui:
general:
game_title: "RTS Civilization"
pause: "Pause"
resume: "Resume"
speed_1x: "1x Speed"
speed_2x: "2x Speed"
speed_4x: "4x Speed"
menu: "Menu"
settings: "Settings"
quit: "Quit"
hud:
gold: "Gold"
science: "Science"
culture: "Culture"
faith: "Faith"
food: "Food"
production: "Production"
population: "Population"
turn_time: "Time"
minimap: "Minimap"
actions:
move: "Move"
attack: "Attack"
found_city: "Found City"
build_farm: "Build Farm"
build_mine: "Build Mine"
build_lumber_mill: "Build Lumber Mill"
build_road: "Build Road"
cancel: "Cancel"
units:
settler: "Settler"
builder: "Builder"
warrior: "Warrior"
slinger: "Slinger"
archer: "Archer"
scout: "Scout"
galley: "Galley"
unit:
moving: "Moving"
impassable_terrain: "Impassable terrain!"
naval_only_water: "Ships can only sail on water!"
no_path: "No reachable path!"
tile_purchased: "Tile purchased! (-%1 Culture)"
out_of_range: "Out of range!"
defeated: "Defeated!"
city_already_here: "A city already exists here!"
unsuitable_terrain: "Unsuitable terrain!"
city:
center: "City Center"
produce_unit: "Produce Unit"
build_district: "Construct District"
population_growth: "Growth in {turns}s"
+36
View File
@@ -0,0 +1,36 @@
# Terrain movement rules, passability and costs configuration
# All gameplay values and parameters are fully configurable.
# Classification thresholds
water_height_threshold: 6 # Raw heightmap elevation value (< 6 is water)
mountain_rock_height_km: 2.3 # Height in km >= 2.3 is rocky mountain
snow_height_km: 3.1 # Altitude in km >= 3.1 is high peak snow
polar_snow_line_enabled: true # Whether latitude reduces snowline altitude
polar_snow_line_base_km: 2.5 # Base snowline at temperate latitudes
polar_snow_factor_start: 0.40 # Latitude distFromCenter where polar cooling starts
polar_snow_factor_end: 0.85 # Latitude distFromCenter where sea-level snowline is reached
# Movement costs per terrain type (1.0 = normal base cost, higher values = slower traversal)
movement_costs:
grasland: 1.0
bos: 2.0
steen: 2.5
sahara: 1.5
tundra: 1.5
red_canyon: 2.0
sneeuw: 3.0
water: 1.0
# Movement domains:
# - land: standard ground units (settler, builder, warrior, slinger, etc.)
# impassable_terrains: list of terrain types land units CANNOT enter or cross.
# - naval: ships and sea vessels (galley, etc.)
# passable_terrains: ships can ONLY move on these terrains (water).
domains:
land:
impassable_terrains:
- water
- sneeuw
naval:
passable_terrains:
- water
+1 -1
View File
@@ -98,7 +98,7 @@ water:
default_slots: 0
primary_resource: "geen"
yields:
voedsel: 0
voedsel: 1000
arbeid: 0
kennis: 0
cultuur: 0
+13
View File
@@ -0,0 +1,13 @@
id: galley
name: Galley
category: militair
domain: naval
health: 120
movement_speed: 3.0
cost: 60
attack_damage: 25
attack_range: 1
icon: images/units/galley.png
actions:
- verplaatsen
- aanvallen
+1
View File
@@ -1,6 +1,7 @@
id: settler
name: Settler
category: bouwen
domain: land
health: 100
movement_speed: 2.0
cost: 80
+1
View File
@@ -1,6 +1,7 @@
id: slinger
name: Slinger
category: militair
domain: land
health: 70
movement_speed: 2.0
cost: 35
+1
View File
@@ -1,6 +1,7 @@
id: warrior
name: Warrior
category: militair
domain: land
health: 100
movement_speed: 2.0
cost: 40
+21 -1
View File
@@ -16,7 +16,16 @@ enum class ActionMode {
None,
Move,
Attack,
BuildCity
BuildCity,
BuildFarm
};
struct TileImprovement {
QString improvementId; // "farm"
int tileX;
int tileY;
int playerId;
QVector3D worldPos;
};
struct FloatingText {
@@ -65,10 +74,20 @@ public:
void exitCityView();
CityYieldSummary calculateCityYields(const City &city, Matrix2D<TerrainPoint> *mapPoints, int numPoints05) const;
void processTickYields(Matrix2D<TerrainPoint> *mapPoints, int numPoints05);
bool isTileOwned(int tx, int ty, int *outOwnerCityId = nullptr) const;
bool buyTileForCity(int cityId, int tx, int ty);
void commandMoveSelected(int targetX, int targetY, Matrix2D<TerrainPoint> *mapPoints, int numPoints05);
void commandAttack(Unit *target);
void commandBuildCitySelected(Matrix2D<TerrainPoint> *mapPoints, int numPoints05);
void commandBuildFarmSelected(Matrix2D<TerrainPoint> *mapPoints, int numPoints05);
void completeUnitBuilding(Unit &unit, Matrix2D<TerrainPoint> *mapPoints, int numPoints05);
const std::map<std::pair<int, int>, TileImprovement>& getTileImprovements() const { return m_tileImprovements; }
const TileImprovement* getImprovementAt(int tx, int ty) const;
bool hasImprovementAt(int tx, int ty) const;
float getTickDuration() const { return m_movementTickDuration; }
void setTickDuration(float d) { m_movementTickDuration = std::max(1.0f, d); }
@@ -94,6 +113,7 @@ private:
std::vector<std::shared_ptr<Unit>> m_units;
std::vector<City> m_cities;
std::vector<FloatingText> m_floatingTexts;
std::map<std::pair<int, int>, TileImprovement> m_tileImprovements;
int m_selectedUnitId;
int m_activeCityViewId;
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

+49
View File
@@ -0,0 +1,49 @@
#include "localization.h"
#include "yamlparser.h"
#include <QDebug>
Localization& Localization::instance()
{
static Localization s_instance;
return s_instance;
}
Localization::Localization()
: m_loaded(false)
{
}
void Localization::flattenNode(const YamlNode &node, const QString &prefix)
{
if (!node.value.isEmpty()) {
m_strings[prefix] = node.value;
}
for (auto it = node.children.begin(); it != node.children.end(); ++it) {
QString nextPrefix = prefix.isEmpty() ? it.key() : (prefix + "." + it.key());
flattenNode(it.value(), nextPrefix);
}
}
bool Localization::loadFile(const QString &filePath)
{
YamlNode root = YamlParser::parseFile(filePath);
if (root.children.isEmpty() && root.value.isEmpty()) {
qWarning() << "Failed to parse localization file:" << filePath;
return false;
}
m_strings.clear();
flattenNode(root, "");
m_loaded = true;
qDebug() << "Localization loaded" << m_strings.size() << "keys from" << filePath;
return true;
}
QString Localization::get(const QString &key, const QString &defaultVal) const
{
auto it = m_strings.find(key);
if (it != m_strings.end()) {
return it.value();
}
return defaultVal.isEmpty() ? key : defaultVal;
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef LOCALIZATION_H
#define LOCALIZATION_H
#include <QString>
#include <QMap>
class YamlNode;
class Localization {
public:
static Localization& instance();
bool loadFile(const QString &filePath);
QString get(const QString &key, const QString &defaultVal = "") const;
private:
Localization();
~Localization() = default;
void flattenNode(const YamlNode &node, const QString &prefix);
QMap<QString, QString> m_strings;
bool m_loaded;
};
#endif // LOCALIZATION_H
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+17 -17
View File
@@ -1,4 +1,6 @@
#include "pathfinder.h"
#include "terrainmovementmanager.h"
#include "unitconfig.h"
#include <cmath>
#include <queue>
#include <unordered_map>
@@ -74,7 +76,9 @@ std::vector<std::pair<int, int>> Pathfinder::findPath(
int startX, int startY,
int goalX, int goalY,
Matrix2D<TerrainPoint> *mapPoints,
int numPoints05)
int numPoints05,
MovementDomain domain,
const UnitConfig *unitConfig)
{
std::vector<std::pair<int, int>> path;
if (startX == goalX && startY == goalY) {
@@ -86,6 +90,11 @@ std::vector<std::pair<int, int>> Pathfinder::findPath(
return path;
}
// Goal hex must be passable for this unit/domain
if (!TerrainMovementManager::instance().isHexPassable(goalX, goalY, domain, mapPoints, numPoints05, unitConfig)) {
return path;
}
std::priority_queue<Node, std::vector<Node>, std::greater<Node>> openSet;
std::unordered_map<int, float> gScore;
std::unordered_map<int, int> cameFrom;
@@ -94,7 +103,7 @@ std::vector<std::pair<int, int>> Pathfinder::findPath(
gScore[startPacked] = 0.0f;
openSet.push({startX, startY, 0.0f, (float)hexDistance(startX, startY, goalX, goalY)});
int maxIterations = 3000;
int maxIterations = 5000;
int iterations = 0;
bool found = false;
@@ -117,23 +126,14 @@ std::vector<std::pair<int, int>> Pathfinder::findPath(
if (nx < 0 || nx >= MAP_WIDTH || ny < 0 || ny >= MAP_HEIGHT) continue;
float stepCost = 1.0f;
// Elevation check if terrain points are available
if (mapPoints && numPoints05 > 0) {
float scaleX = numPoints05 * 2.0f;
float scaleY = numPoints05 / LOD_0_SIZE_Y;
QVector2D nCenter = hexToWorld(nx, ny);
int mapX = (int) std::round(nCenter.x() * scaleX);
int mapY = (int) std::round(nCenter.y() * scaleY);
if (mapX >= 0 && mapX < (int)mapPoints->getWidth() && mapY >= 0 && mapY < (int)mapPoints->getHeight()) {
unsigned char h = mapPoints->operator()(mapX, mapY).height;
// Slightly penalize water tiles or high mountains
if (h < 5) stepCost += 4.0f;
else if (h > 220) stepCost += 2.0f;
}
// Check if neighbor hex is passable for this unit's domain
if (!TerrainMovementManager::instance().isHexPassable(nx, ny, domain, mapPoints, numPoints05, unitConfig)) {
continue;
}
// Step cost from configurable terrain movement manager
float stepCost = TerrainMovementManager::instance().getHexMovementCost(nx, ny, mapPoints, numPoints05);
float tentativeG = current.g + stepCost;
int nPacked = packCoord(nx, ny);
+7 -1
View File
@@ -7,6 +7,10 @@
#include "terrain.h"
#include "matrix2d.h"
#include "terrainmovementmanager.h"
struct UnitConfig;
class Pathfinder {
public:
static QVector2D hexToWorld(int x, int y);
@@ -16,7 +20,9 @@ public:
int startX, int startY,
int goalX, int goalY,
Matrix2D<TerrainPoint> *mapPoints = nullptr,
int numPoints05 = 0
int numPoints05 = 0,
MovementDomain domain = MovementDomain::Land,
const UnitConfig *unitConfig = nullptr
);
};
BIN
View File
Binary file not shown.
+14 -3
View File
@@ -11,9 +11,19 @@ struct Player {
QColor primaryColor;
QColor secondaryColor;
Player() : id(0), name("Unknown"), primaryColor(Qt::blue), secondaryColor(Qt::white) {}
Player(int pId, const QString &pName, const QColor &primary, const QColor &secondary)
: id(pId), name(pName), primaryColor(primary), secondaryColor(secondary) {}
// National resources (shared across all cities of this nation)
int culture;
int science;
int gold;
int faith;
Player()
: id(0), name("Unknown"), primaryColor(Qt::blue), secondaryColor(Qt::white),
culture(10000), science(0), gold(0), faith(0) {}
Player(int pId, const QString &pName, const QColor &primary, const QColor &secondary,
int pCulture = 10000, int pScience = 0, int pGold = 0, int pFaith = 0)
: id(pId), name(pName), primaryColor(primary), secondaryColor(secondary),
culture(pCulture), science(pScience), gold(pGold), faith(pFaith) {}
};
class PlayerManager {
@@ -24,6 +34,7 @@ public:
const Player* getPlayer(int id) const;
Player* getPlayer(int id);
const std::vector<Player>& getPlayers() const { return m_players; }
std::vector<Player>& getPlayersMutable() { return m_players; }
bool isCombinationUnique(const QColor &primary, const QColor &secondary, int excludeId = -1) const;
BIN
View File
Binary file not shown.
+733 -683
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+22
View File
@@ -56,10 +56,21 @@ protected:
void drawFloatingTexts(QPainter &painter, const QMatrix4x4 &vMatrix);
// City & Territory Overlays
void drawCityBorders(QPainter &painter, const QMatrix4x4 &vMatrix);
void drawImprovementsOverlay(QPainter &painter, const QMatrix4x4 &vMatrix);
void drawCityViewOverlay(QPainter &painter, const QMatrix4x4 &vMatrix);
bool screenToHex(const QPoint &screenPos, const QMatrix4x4 &vMatrix, int &outX, int &outY);
QImage getTintedIcon(const QString &path, const QColor &color);
float getCameraPitchDeg() const;
float getCameraForwardDist() const;
QVector3D getCameraLookAt() const;
void loadCameraConfig();
float m_cameraMinZoom = 2.0f;
float m_cameraMaxZoom = 16.0f;
float m_cameraPitchMinDeg = 45.0f;
float m_cameraPitchMaxDeg = 75.0f;
float m_camera_x = 10.0f;
float m_camera_y = 0.0f;
QMatrix4x4 Projection;
@@ -81,6 +92,11 @@ protected:
bool m_draggingMinimap;
float m_minimapZoom;
// Saved camera state for restoring after City View
QVector3D m_savedCamPos;
float m_savedZoom = 8.0f;
float m_savedZRot = 90.0f;
// Units & UI state
UnitRenderer m_unitRenderer;
QMap<QString, QImage> m_iconCache;
@@ -107,6 +123,12 @@ protected:
};
std::vector<CitySlotHit> m_citySlotHits;
struct CityBuyTileHit {
QRect rect;
int tx, ty;
};
std::vector<CityBuyTileHit> m_cityBuyTileHits;
struct CityBannerHit {
QRect rect;
int cityId;
BIN
View File
Binary file not shown.
+222
View File
@@ -0,0 +1,222 @@
#include "terrainmovementmanager.h"
#include "unitconfig.h"
#include "pathfinder.h"
#include "yamlparser.h"
#include <QDebug>
#include <cmath>
#include <algorithm>
TerrainMovementConfig::TerrainMovementConfig()
: waterHeightThreshold(6),
mountainRockHeightKm(2.3f),
snowHeightKm(3.1f),
polarSnowLineEnabled(true),
polarSnowLineBaseKm(2.5f),
polarSnowFactorStart(0.40f),
polarSnowFactorEnd(0.85f)
{
movementCosts["grasland"] = 1.0f;
movementCosts["bos"] = 2.0f;
movementCosts["steen"] = 2.5f;
movementCosts["sahara"] = 1.5f;
movementCosts["tundra"] = 1.5f;
movementCosts["red_canyon"] = 2.0f;
movementCosts["sneeuw"] = 3.0f;
movementCosts["water"] = 1.0f;
DomainMovementRule landRule;
landRule.impassableTerrains = QStringList{"water", "sneeuw"};
domainRules["land"] = landRule;
DomainMovementRule navalRule;
navalRule.passableTerrains = QStringList{"water"};
domainRules["naval"] = navalRule;
}
TerrainMovementManager& TerrainMovementManager::instance()
{
static TerrainMovementManager s_instance;
return s_instance;
}
TerrainMovementManager::TerrainMovementManager()
: m_loaded(false)
{
}
bool TerrainMovementManager::loadConfig(const QString &filePath)
{
YamlNode root = YamlParser::parseFile(filePath);
if (root.children.isEmpty()) {
qWarning() << "Failed to parse terrain movement config YAML or empty:" << filePath;
return false;
}
if (root.hasChild("water_height_threshold")) {
m_config.waterHeightThreshold = root["water_height_threshold"].asInt(6);
}
if (root.hasChild("mountain_rock_height_km")) {
m_config.mountainRockHeightKm = root["mountain_rock_height_km"].asFloat(2.3f);
}
if (root.hasChild("snow_height_km")) {
m_config.snowHeightKm = root["snow_height_km"].asFloat(3.1f);
}
if (root.hasChild("polar_snow_line_enabled")) {
m_config.polarSnowLineEnabled = root["polar_snow_line_enabled"].asBool(true);
}
if (root.hasChild("polar_snow_line_base_km")) {
m_config.polarSnowLineBaseKm = root["polar_snow_line_base_km"].asFloat(2.5f);
}
if (root.hasChild("polar_snow_factor_start")) {
m_config.polarSnowFactorStart = root["polar_snow_factor_start"].asFloat(0.40f);
}
if (root.hasChild("polar_snow_factor_end")) {
m_config.polarSnowFactorEnd = root["polar_snow_factor_end"].asFloat(0.85f);
}
if (root.hasChild("movement_costs")) {
const YamlNode &costsNode = root["movement_costs"];
for (auto it = costsNode.children.begin(); it != costsNode.children.end(); ++it) {
m_config.movementCosts[it.key()] = it.value().asFloat(1.0f);
}
}
if (root.hasChild("domains")) {
const YamlNode &domainsNode = root["domains"];
for (auto it = domainsNode.children.begin(); it != domainsNode.children.end(); ++it) {
QString domainName = it.key().trimmed().toLower();
const YamlNode &dNode = it.value();
DomainMovementRule rule;
if (dNode.hasChild("impassable_terrains")) {
rule.impassableTerrains = dNode["impassable_terrains"].listValues;
}
if (dNode.hasChild("passable_terrains")) {
rule.passableTerrains = dNode["passable_terrains"].listValues;
}
m_config.domainRules[domainName] = rule;
}
}
m_loaded = true;
qDebug() << "TerrainMovementManager successfully loaded movement config from:" << filePath;
return true;
}
QString TerrainMovementManager::getTerrainType(int tx, int ty, Matrix2D<TerrainPoint> *mapPoints, int numPoints05) const
{
if (!mapPoints || numPoints05 <= 0) return "grasland";
QVector2D w = Pathfinder::hexToWorld(tx, ty);
float scaleX = numPoints05 * 2.0f;
float scaleY = numPoints05 / LOD_0_SIZE_Y;
int mapX = (int) std::round(w.x() * scaleX);
int mapY = (int) std::round(w.y() * scaleY);
if (mapX < 0) mapX = 0;
if (mapX >= (int)mapPoints->getWidth()) mapX = (int)mapPoints->getWidth() - 1;
if (mapY < 0) mapY = 0;
if (mapY >= (int)mapPoints->getHeight()) mapY = (int)mapPoints->getHeight() - 1;
TerrainPoint tp = mapPoints->operator()(mapX, mapY);
// 1. Water
if (tp.height < m_config.waterHeightThreshold) {
return "water";
}
float heightKm = (tp.height / 255.0f) * 3.5f + 1.0f;
// 2. High peak snow
if (heightKm >= m_config.snowHeightKm) {
return "sneeuw";
}
// 3. Polar latitude snowline
if (m_config.polarSnowLineEnabled) {
float normY = std::max(0.0f, std::min(1.0f, w.y() / 108.25f));
float distFromCenter = std::abs(normY - 0.5f) * 2.0f;
if (distFromCenter >= m_config.polarSnowFactorStart) {
float t = std::max(0.0f, std::min(1.0f,
(distFromCenter - m_config.polarSnowFactorStart) /
(m_config.polarSnowFactorEnd - m_config.polarSnowFactorStart)));
float poleFactor = t * t * (3.0f - 2.0f * t);
float snowLine = m_config.polarSnowLineBaseKm * (1.0f - poleFactor);
if (heightKm >= snowLine) {
return "sneeuw";
}
}
}
// 4. Rocky mountain
if (heightKm >= m_config.mountainRockHeightKm) {
return "steen";
}
// 5. Typemap biomes
switch (tp.type) {
case 0: return "grasland";
case 1: return "sahara";
case 2: return "tundra";
case 3: return "red_canyon";
case 4: return "bos";
default: return "grasland";
}
}
bool TerrainMovementManager::isTerrainPassable(
const QString &terrainType,
MovementDomain domain,
const UnitConfig *unitConfig) const
{
// Unit-specific whitelist overrides
if (unitConfig && !unitConfig->passableTerrains.isEmpty()) {
return unitConfig->passableTerrains.contains(terrainType);
}
// Unit-specific blacklist overrides
if (unitConfig && unitConfig->impassableTerrains.contains(terrainType)) {
return false;
}
// Domain-level rules
QString domainStr = movementDomainToString(domain);
auto it = m_config.domainRules.find(domainStr);
if (it != m_config.domainRules.end()) {
const DomainMovementRule &rule = it.value();
if (!rule.passableTerrains.isEmpty()) {
return rule.passableTerrains.contains(terrainType);
}
if (rule.impassableTerrains.contains(terrainType)) {
return false;
}
}
return true;
}
bool TerrainMovementManager::isHexPassable(
int tx, int ty,
MovementDomain domain,
Matrix2D<TerrainPoint> *mapPoints,
int numPoints05,
const UnitConfig *unitConfig) const
{
if (tx < 0 || tx >= MAP_WIDTH || ty < 0 || ty >= MAP_HEIGHT) {
return false;
}
QString tType = getTerrainType(tx, ty, mapPoints, numPoints05);
return isTerrainPassable(tType, domain, unitConfig);
}
float TerrainMovementManager::getTerrainMovementCost(const QString &terrainType) const
{
return m_config.movementCosts.value(terrainType, 1.0f);
}
float TerrainMovementManager::getHexMovementCost(int tx, int ty, Matrix2D<TerrainPoint> *mapPoints, int numPoints05) const
{
QString tType = getTerrainType(tx, ty, mapPoints, numPoints05);
return getTerrainMovementCost(tType);
}
+88
View File
@@ -0,0 +1,88 @@
#ifndef TERRAINMOVEMENTMANAGER_H
#define TERRAINMOVEMENTMANAGER_H
#include <QString>
#include <QStringList>
#include <QMap>
#include "terrain.h"
#include "matrix2d.h"
enum class MovementDomain {
Land,
Naval
};
inline QString movementDomainToString(MovementDomain domain) {
switch (domain) {
case MovementDomain::Land: return "land";
case MovementDomain::Naval: return "naval";
}
return "land";
}
inline MovementDomain stringToMovementDomain(const QString &str) {
QString s = str.trimmed().toLower();
if (s == "naval" || s == "water" || s == "zee" || s == "schip" || s == "sea") {
return MovementDomain::Naval;
}
return MovementDomain::Land;
}
struct DomainMovementRule {
QStringList impassableTerrains;
QStringList passableTerrains; // If non-empty, ONLY these terrains can be entered
};
struct TerrainMovementConfig {
int waterHeightThreshold;
float mountainRockHeightKm;
float snowHeightKm;
bool polarSnowLineEnabled;
float polarSnowLineBaseKm;
float polarSnowFactorStart;
float polarSnowFactorEnd;
QMap<QString, float> movementCosts;
QMap<QString, DomainMovementRule> domainRules;
TerrainMovementConfig();
};
struct UnitConfig; // Forward declaration
class TerrainMovementManager {
public:
static TerrainMovementManager& instance();
bool loadConfig(const QString &filePath);
QString getTerrainType(int tx, int ty, Matrix2D<TerrainPoint> *mapPoints, int numPoints05) const;
bool isTerrainPassable(
const QString &terrainType,
MovementDomain domain,
const UnitConfig *unitConfig = nullptr
) const;
bool isHexPassable(
int tx, int ty,
MovementDomain domain,
Matrix2D<TerrainPoint> *mapPoints,
int numPoints05,
const UnitConfig *unitConfig = nullptr
) const;
float getTerrainMovementCost(const QString &terrainType) const;
float getHexMovementCost(int tx, int ty, Matrix2D<TerrainPoint> *mapPoints, int numPoints05) const;
const TerrainMovementConfig& getConfig() const { return m_config; }
private:
TerrainMovementManager();
~TerrainMovementManager() = default;
TerrainMovementConfig m_config;
bool m_loaded;
};
#endif // TERRAINMOVEMENTMANAGER_H
Binary file not shown.
Binary file not shown.
+2
View File
@@ -69,6 +69,7 @@ protected:
static QOpenGLTexture * m_texture_redsand;
static QOpenGLTexture * m_texture_redrock;
static QOpenGLTexture * m_texture_forest;
static QOpenGLTexture * m_texture_farm;
static QImage * m_image_grass;
static QImage * m_image_rock;
static QImage * m_image_border;
@@ -81,6 +82,7 @@ protected:
static QImage * m_image_redsand;
static QImage * m_image_redrock;
static QImage * m_image_forest;
static QImage * m_image_farm;
};
#endif // TILE_H
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+6 -2
View File
@@ -28,7 +28,9 @@ SOURCES += main.cpp \
city.cpp \
terrainyieldmanager.cpp \
gamemanager.cpp \
unitrenderer.cpp
unitrenderer.cpp \
localization.cpp \
terrainmovementmanager.cpp
HEADERS += mainwindow.h \
qscenerenderer.h \
@@ -46,7 +48,9 @@ HEADERS += mainwindow.h \
city.h \
terrainyieldmanager.h \
gamemanager.h \
unitrenderer.h
unitrenderer.h \
localization.h \
terrainmovementmanager.h
FORMS += mainwindow.ui
+1 -334
View File
@@ -1,334 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.6.1, 2017-10-14T18:39:31. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{f0a66801-0dd7-42e1-b4c1-85787695328d}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.6.0 GCC 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.6.0 GCC 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.56.gcc_64_kit</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/bart/project/build-tiletest-Desktop_Qt_5_6_0_GCC_64bit-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/bart/project/build-tiletest-Desktop_Qt_5_6_0_GCC_64bit-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/bart/project/build-tiletest-Desktop_Qt_5_6_0_GCC_64bit-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">tiletest</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/bart/project/tiletest/tiletest.pro</value>
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">tiletest.pro</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">false</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>
+35 -1
View File
@@ -6,8 +6,10 @@
Unit::Unit(int uId, int pId, const UnitConfig &cfg, int startX, int startY, float groundZ)
: id(uId), playerId(pId), config(cfg), tileX(startX), tileY(startY),
health((float)cfg.health), maxHealth((float)cfg.health),
buildCharges(cfg.buildCharges),
state(UnitState::Idle), pathIndex(0), moveProgress(0.0f),
targetTileX(startX), targetTileY(startY), attackFlashTimer(0.0f)
targetTileX(startX), targetTileY(startY), attackFlashTimer(0.0f),
buildProgress(0.0f), buildDuration(0.0f), buildingImprovementId("")
{
QVector2D w = Pathfinder::hexToWorld(startX, startY);
worldPos = QVector3D(w.x(), w.y(), groundZ);
@@ -34,6 +36,10 @@ float Unit::getTerrainHeight(float worldX, float worldY, Matrix2D<TerrainPoint>
void Unit::setPath(const std::vector<std::pair<int, int>> &newPath)
{
if (state == UnitState::Building) {
cancelBuilding();
}
path = newPath;
pathIndex = 0;
moveProgress = 0.0f;
@@ -55,6 +61,27 @@ void Unit::stopMovement()
state = UnitState::Idle;
}
void Unit::startBuilding(const QString &impId, float duration)
{
path.clear();
pathIndex = 0;
moveProgress = 0.0f;
state = UnitState::Building;
buildingImprovementId = impId;
buildDuration = std::max(0.1f, duration);
buildProgress = 0.0f;
}
void Unit::cancelBuilding()
{
if (state == UnitState::Building) {
state = UnitState::Idle;
buildProgress = 0.0f;
buildDuration = 0.0f;
buildingImprovementId = "";
}
}
void Unit::update(float deltaTime, float tickDuration, float simSpeedMultiplier,
Matrix2D<TerrainPoint> *mapPoints, int numPoints05)
{
@@ -62,6 +89,13 @@ void Unit::update(float deltaTime, float tickDuration, float simSpeedMultiplier,
attackFlashTimer = std::max(0.0f, attackFlashTimer - deltaTime);
}
if (state == UnitState::Building) {
if (buildDuration > 0.001f) {
buildProgress += (deltaTime * simSpeedMultiplier) / buildDuration;
}
return;
}
if (state != UnitState::Moving || path.size() <= 1) {
return;
}
+14 -1
View File
@@ -12,7 +12,8 @@
enum class UnitState {
Idle,
Moving,
Attacking
Attacking,
Building
};
class Unit {
@@ -27,6 +28,7 @@ public:
QVector3D worldPos;
float health;
float maxHealth;
int buildCharges;
UnitState state;
// Movement Path
@@ -39,15 +41,26 @@ public:
// Attack cooldown / flash
float attackFlashTimer;
// Building State
float buildProgress; // 0.0 to 1.0
float buildDuration;
QString buildingImprovementId;
void update(float deltaTime, float tickDuration, float simSpeedMultiplier,
Matrix2D<TerrainPoint> *mapPoints, int numPoints05);
void setPath(const std::vector<std::pair<int, int>> &newPath);
void stopMovement();
void startBuilding(const QString &impId, float duration);
void cancelBuilding();
bool isBuilding() const { return state == UnitState::Building; }
bool canAttack(const Unit &other) const;
void performAttack(Unit &target);
void takeDamage(float damage);
bool isDead() const { return health <= 0.001f; }
bool isNaval() const { return config.isNaval(); }
bool isLand() const { return config.isLand(); }
static float getTerrainHeight(float worldX, float worldY, Matrix2D<TerrainPoint> *mapPoints, int numPoints05);
};
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+17 -1
View File
@@ -1,4 +1,5 @@
#include "unitrenderer.h"
#include "pathfinder.h"
#include <cmath>
#include <vector>
@@ -92,7 +93,10 @@ void UnitRenderer::renderUnits(
const QMatrix4x4 &projection,
const QMatrix4x4 &vMatrix,
const QVector3D &lightDir,
int selectedUnitId)
int selectedUnitId,
int cityViewRadius,
int cityViewTileX,
int cityViewTileY)
{
if (!m_initialized || !m_program) return;
@@ -103,6 +107,12 @@ void UnitRenderer::renderUnits(
// 1. Render Cities (as stylized hexagonal / cylindrical city bastions)
for (const auto &c : cities) {
if (cityViewRadius >= 0) {
if (c.tileX != cityViewTileX || c.tileY != cityViewTileY) {
continue;
}
}
const Player *p = players.getPlayer(c.playerId);
QColor col = p ? p->primaryColor : QColor(100, 100, 100);
@@ -125,6 +135,12 @@ void UnitRenderer::renderUnits(
for (const auto &unit : units) {
if (unit->isDead()) continue;
if (cityViewRadius >= 0) {
if (Pathfinder::hexDistance(cityViewTileX, cityViewTileY, unit->tileX, unit->tileY) > cityViewRadius) {
continue;
}
}
const Player *player = players.getPlayer(unit->playerId);
QColor col = player ? player->primaryColor : QColor(200, 200, 200);
+4 -1
View File
@@ -27,7 +27,10 @@ public:
const QMatrix4x4 &projection,
const QMatrix4x4 &vMatrix,
const QVector3D &lightDir,
int selectedUnitId
int selectedUnitId,
int cityViewRadius = -1,
int cityViewTileX = -1,
int cityViewTileY = -1
);
static QPointF projectToScreen(
BIN
View File
Binary file not shown.