mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Make rallypoints moddable.
Allow use of {civ} tags in templates to simplify mod dependencies and inheritance.
Reviewed-On: #8038
Reviewed-By: @phosit
This commit is contained in:
parent
92ef4ffa19
commit
03f7903fec
41 changed files with 420 additions and 166 deletions
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Athenian Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_greek.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Britonnic Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_celt.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Carthaginian Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_carthage.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Gaul Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_celt.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Han Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_han.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Iberian Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_iberians.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Kush Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_kushites.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Macedonians Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_macedonians.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Mauryan Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_mauryas.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Pers Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_persian.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Ptolemaic Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_ptolemies.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Roman Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_romans.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Seleucid Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_seleucids.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant file="others/waypoints/base.xml" frequency="1" name="Spartan Waypoint Flag">
|
||||
<textures>
|
||||
<texture file="props/banner_spartans.png" name="baseTex"/>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
<castshadow/>
|
||||
<float/>
|
||||
<group>
|
||||
<variant frequency="100">
|
||||
<animations>
|
||||
<animation file="mechanical/waypoint_flag_idle.dae" name="Idle" speed="30"/>
|
||||
</animations>
|
||||
<mesh>props/waypoint_flag.dae</mesh>
|
||||
<textures>
|
||||
<texture file="default_norm.png" name="normTex"/>
|
||||
<texture file="null_black.dds" name="specTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<group>
|
||||
<variant name="athen">
|
||||
<textures>
|
||||
<texture file="props/banner_athenians.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="brit">
|
||||
<textures>
|
||||
<texture file="props/banner_celt.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="cart">
|
||||
<textures>
|
||||
<texture file="props/banner_carthage.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="celt">
|
||||
<textures>
|
||||
<texture file="props/banner_celt.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="gaul">
|
||||
<textures>
|
||||
<texture file="props/banner_celt.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="han">
|
||||
<textures>
|
||||
<texture file="props/banner_han.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="hele">
|
||||
<textures>
|
||||
<texture file="props/banner_greek.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="iber">
|
||||
<textures>
|
||||
<texture file="props/banner_iberians.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="kush">
|
||||
<textures>
|
||||
<texture file="props/banner_kushites.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="mace">
|
||||
<textures>
|
||||
<texture file="props/banner_macedonians.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="maur">
|
||||
<textures>
|
||||
<texture file="props/banner_mauryas.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="pers">
|
||||
<textures>
|
||||
<texture file="props/banner_persian.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="ptol">
|
||||
<textures>
|
||||
<texture file="props/banner_ptolemies.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="rome">
|
||||
<textures>
|
||||
<texture file="props/banner_romans.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="sele">
|
||||
<textures>
|
||||
<texture file="props/banner_seleucids.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
<variant name="spart">
|
||||
<textures>
|
||||
<texture file="props/banner_spartans.png" name="baseTex"/>
|
||||
</textures>
|
||||
</variant>
|
||||
</group>
|
||||
<material>basic_trans_norm_spec.xml</material>
|
||||
</actor>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<variant name="Base">
|
||||
<animations>
|
||||
<animation file="mechanical/waypoint_flag_idle.dae" name="Idle" speed="30" />
|
||||
</animations>
|
||||
<mesh>props/waypoint_flag.dae</mesh>
|
||||
<textures>
|
||||
<texture file="default_norm.png" name="normTex" />
|
||||
<texture file="null_black.dds" name="specTex" />
|
||||
</textures>
|
||||
</variant>
|
||||
|
|
@ -161,7 +161,7 @@ export function* generateMap()
|
|||
"units/gaul/infantry_slinger_b",
|
||||
"units/gaul/infantry_javelineer_b",
|
||||
"units/gaul/champion_fanatic",
|
||||
"actor|props/special/common/waypoint_flag.xml",
|
||||
"actor|props/special/common/waypoint_flag_factions.xml",
|
||||
"actor|props/special/eyecandy/barrel_a.xml",
|
||||
"actor|props/special/eyecandy/basket_celt_a.xml",
|
||||
"actor|props/special/eyecandy/crate_a.xml",
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export function* generateMap(mapSettings)
|
|||
const aRockMedium = g_Decoratives.rockMedium;
|
||||
const aBushMedium = g_Decoratives.bushMedium;
|
||||
const aBushSmall = g_Decoratives.bushSmall;
|
||||
const aWaypointFlag = "actor|props/special/common/waypoint_flag.xml";
|
||||
const aWaypointFlag = "actor|props/special/common/waypoint_flag_factions.xml";
|
||||
|
||||
const pForest1 = [
|
||||
tForestFloor2 + TERRAIN_SEPARATOR + oTree1,
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@
|
|||
"campEntities": [
|
||||
"gaia/treasure/metal",
|
||||
"gaia/treasure/standing_stone",
|
||||
"actor|props/special/common/waypoint_flag.xml",
|
||||
"actor|props/special/common/waypoint_flag_factions.xml",
|
||||
"actor|props/special/eyecandy/barrel_a.xml",
|
||||
"actor|props/special/eyecandy/basket_celt_a.xml",
|
||||
"actor|props/special/eyecandy/crate_a.xml",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/actor">
|
||||
<Identity>
|
||||
<Civ>gaia</Civ>
|
||||
<GenericName>Rally point flag</GenericName>
|
||||
<Undeletable>true</Undeletable>
|
||||
<Icon/>
|
||||
</Identity>
|
||||
<Visibility>
|
||||
<AlwaysVisible>true</AlwaysVisible>
|
||||
</Visibility>
|
||||
<VisualActor>
|
||||
<Actor>props/special/common/waypoint_flag.xml</Actor>
|
||||
<Actor>props/special/common/{civ}_waypoint_flag.xml</Actor>
|
||||
</VisualActor>
|
||||
</Entity>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>athen</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>brit</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>cart</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>gaul</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>han</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>iber</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>kush</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>mace</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>maur</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>pers</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>ptol</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>rome</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>sele</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="special/rallypoint">
|
||||
<Identity>
|
||||
<Civ>spart</Civ>
|
||||
</Identity>
|
||||
</Entity>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
</Position>
|
||||
<RallyPoint/>
|
||||
<RallyPointRenderer>
|
||||
<MarkerTemplate>special/rallypoint</MarkerTemplate>
|
||||
<MarkerTemplate>special/rallypoints/{civ}</MarkerTemplate>
|
||||
<LineTexture>art/textures/misc/rallypoint_line.png</LineTexture>
|
||||
<LineTextureMask>art/textures/misc/rallypoint_line_mask.png</LineTextureMask>
|
||||
<LineThickness>0.25</LineThickness>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
<VisualActor>
|
||||
<SilhouetteDisplay>false</SilhouetteDisplay>
|
||||
<SilhouetteOccluder>true</SilhouetteOccluder>
|
||||
<Actor>props/special/common/waypoint_flag.xml</Actor>
|
||||
<Actor>props/special/common/waypoint_flag_factions.xml</Actor>
|
||||
<VisibleInAtlasOnly>true</VisibleInAtlasOnly>
|
||||
</VisualActor>
|
||||
</Entity>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -18,6 +18,10 @@
|
|||
#ifndef ALGORITHM_H
|
||||
#define ALGORITHM_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace PS
|
||||
{
|
||||
/**
|
||||
|
|
@ -34,6 +38,27 @@ bool contains(Range&& range, const T& value)
|
|||
return elem == value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces all occurrences of a substring within a string with a given value.
|
||||
*
|
||||
* This function searches the input string `base` for all instances of the specified
|
||||
* `tag` and replaces them with the provided `value`. The replacement is performed
|
||||
* in-place and modifies the original string.
|
||||
*
|
||||
* @param base The string in which to perform replacements. Modified in-place.
|
||||
* @param tag The substring to search for (e.g., a placeholder like L"{civ}").
|
||||
* @param value The string to replace each occurrence of `tag` with.
|
||||
*/
|
||||
inline void ReplaceSubrange(std::wstring& base, std::wstring_view tag, std::wstring_view value)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = base.find(tag, pos)) != std::wstring::npos)
|
||||
{
|
||||
base.replace(pos, tag.length(), value);
|
||||
pos += value.length();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PS
|
||||
#endif // ALGORITHM_H
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -17,7 +17,9 @@
|
|||
|
||||
#include "precompiled.h"
|
||||
#include "CCmpRallyPointRenderer.h"
|
||||
#include "ICmpIdentity.h"
|
||||
|
||||
#include "ps/algorithm.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "simulation2/components/ICmpRangeManager.h"
|
||||
#include "simulation2/helpers/Los.h"
|
||||
|
|
@ -218,69 +220,71 @@ void CCmpRallyPointRenderer::UpdateMessageSubscriptions()
|
|||
GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_RenderSubmit, this, m_Displayed && IsSet());
|
||||
}
|
||||
|
||||
void CCmpRallyPointRenderer::CreateMarkerEntity(size_t index, player_id_t ownerId)
|
||||
{
|
||||
if (m_MarkerTemplate.empty() || ownerId == INVALID_PLAYER)
|
||||
return;
|
||||
|
||||
CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSystemEntity());
|
||||
if (!cmpPlayerManager)
|
||||
return;
|
||||
|
||||
CmpPtr<ICmpPlayer> cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(ownerId));
|
||||
if (!cmpPlayer)
|
||||
return;
|
||||
|
||||
CmpPtr<ICmpIdentity> cmpIdentity(GetSimContext(), cmpPlayer->GetEntityId());
|
||||
if (!cmpIdentity)
|
||||
return;
|
||||
|
||||
// Create a copy we do not want to alter the marker template.
|
||||
std::wstring markerTemplate = m_MarkerTemplate;
|
||||
PS::ReplaceSubrange(markerTemplate, L"{civ}", cmpIdentity->GetCiv());
|
||||
|
||||
CComponentManager& componentMgr = GetSimContext().GetComponentManager();
|
||||
entity_id_t newMarker = componentMgr.AllocateNewLocalEntity();
|
||||
|
||||
if (newMarker != INVALID_ENTITY)
|
||||
newMarker = componentMgr.AddEntity(markerTemplate, newMarker);
|
||||
|
||||
m_MarkerEntityIds[index] = newMarker;
|
||||
}
|
||||
|
||||
void CCmpRallyPointRenderer::UpdateMarkers()
|
||||
{
|
||||
player_id_t previousOwner = m_LastOwner;
|
||||
CmpPtr<ICmpOwnership> cmpOwnership(GetEntityHandle());
|
||||
const player_id_t ownerId{cmpOwnership ? cmpOwnership->GetOwner() : 0};
|
||||
|
||||
for (size_t i = 0; i < m_RallyPoints.size(); ++i)
|
||||
{
|
||||
if (i >= m_MarkerEntityIds.size())
|
||||
m_MarkerEntityIds.push_back(INVALID_ENTITY);
|
||||
|
||||
if (m_MarkerEntityIds[i] == INVALID_ENTITY)
|
||||
{
|
||||
// No marker exists yet, create one first
|
||||
CComponentManager& componentMgr = GetSimContext().GetComponentManager();
|
||||
CreateMarkerEntity(i, ownerId);
|
||||
|
||||
// Allocate a new entity for the marker
|
||||
if (!m_MarkerTemplate.empty())
|
||||
{
|
||||
m_MarkerEntityIds[i] = componentMgr.AllocateNewLocalEntity();
|
||||
if (m_MarkerEntityIds[i] != INVALID_ENTITY)
|
||||
m_MarkerEntityIds[i] = componentMgr.AddEntity(m_MarkerTemplate, m_MarkerEntityIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// The marker entity should be valid at this point, otherwise something went wrong trying to allocate it
|
||||
if (m_MarkerEntityIds[i] == INVALID_ENTITY)
|
||||
{
|
||||
LOGERROR("Failed to create rally point marker entity");
|
||||
continue;
|
||||
}
|
||||
|
||||
CmpPtr<ICmpPosition> markerCmpPosition(GetSimContext(), m_MarkerEntityIds[i]);
|
||||
if (markerCmpPosition)
|
||||
{
|
||||
if (m_Displayed && IsSet())
|
||||
{
|
||||
markerCmpPosition->MoveTo(m_RallyPoints[i].X, m_RallyPoints[i].Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
markerCmpPosition->MoveOutOfWorld();
|
||||
}
|
||||
}
|
||||
|
||||
// Set rally point flag selection based on player civilization
|
||||
CmpPtr<ICmpOwnership> cmpOwnership(GetEntityHandle());
|
||||
if (!cmpOwnership)
|
||||
continue;
|
||||
|
||||
player_id_t ownerId = cmpOwnership->GetOwner();
|
||||
if (ownerId == INVALID_PLAYER || (ownerId == previousOwner && m_LastMarkerCount >= i))
|
||||
continue;
|
||||
|
||||
m_LastOwner = ownerId;
|
||||
CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSystemEntity());
|
||||
// cmpPlayerManager should not be null as long as this method is called on-demand instead of at Init() time
|
||||
// (we can't rely on component initialization order in Init())
|
||||
if (!cmpPlayerManager)
|
||||
continue;
|
||||
|
||||
CmpPtr<ICmpIdentity> cmpIdentity(GetSimContext(), cmpPlayerManager->GetPlayerByID(ownerId));
|
||||
if (!cmpIdentity)
|
||||
continue;
|
||||
|
||||
CmpPtr<ICmpVisual> cmpVisualActor(GetSimContext(), m_MarkerEntityIds[i]);
|
||||
if (cmpVisualActor)
|
||||
cmpVisualActor->SetVariant("civ", CStrW(cmpIdentity->GetCiv()).ToUTF8());
|
||||
}
|
||||
|
||||
m_LastMarkerCount = m_RallyPoints.size() - 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -194,6 +194,14 @@ private:
|
|||
*/
|
||||
void UpdateMarkers();
|
||||
|
||||
/**
|
||||
* @brief Creates a rally point marker entity for the specified index and owner.
|
||||
*
|
||||
* @param index The index in the rally point list for which to create a marker.
|
||||
* @param ownerId The ID of the player who currently owns the entity.
|
||||
*/
|
||||
void CreateMarkerEntity(size_t index, player_id_t ownerId);
|
||||
|
||||
/**
|
||||
* Recomputes all the full paths from this entity to the rally point and from the rally point to the next, and does all the necessary
|
||||
* post-processing to make them prettier.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#include "ICmpIdentity.h"
|
||||
#include "ICmpMirage.h"
|
||||
#include "ICmpOwnership.h"
|
||||
#include "ICmpPlayer.h"
|
||||
#include "ICmpPlayerManager.h"
|
||||
#include "ICmpPosition.h"
|
||||
#include "ICmpTemplateManager.h"
|
||||
#include "ICmpTerrain.h"
|
||||
|
|
@ -47,6 +49,7 @@
|
|||
#include "maths/Frustum.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "ps/algorithm.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "renderer/Scene.h"
|
||||
|
|
@ -560,7 +563,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// Replace {phenotype} with the correct value in m_ActorName
|
||||
// Replace {phenotype} and {civ} with the correct value in m_ActorName
|
||||
void ParseActorName(std::wstring base);
|
||||
|
||||
/// Helper function shared by component init and actor reloading
|
||||
|
|
@ -583,18 +586,13 @@ REGISTER_COMPONENT_TYPE(VisualActor)
|
|||
void CCmpVisualActor::ParseActorName(std::wstring base)
|
||||
{
|
||||
CmpPtr<ICmpIdentity> cmpIdentity(GetEntityHandle());
|
||||
const std::wstring pattern = L"{phenotype}";
|
||||
if (cmpIdentity)
|
||||
{
|
||||
size_t pos = base.find(pattern);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
base.replace(pos, pattern.size(), cmpIdentity->GetPhenotype());
|
||||
pos = base.find(pattern, pos + pattern.size());
|
||||
}
|
||||
PS::ReplaceSubrange(base, L"{phenotype}", cmpIdentity->GetPhenotype());
|
||||
PS::ReplaceSubrange(base, L"{civ}", cmpIdentity->GetCiv());
|
||||
}
|
||||
|
||||
m_ActorName = base;
|
||||
m_ActorName = std::move(base);
|
||||
}
|
||||
|
||||
void CCmpVisualActor::InitModel()
|
||||
|
|
|
|||
|
|
@ -340,22 +340,32 @@ class CheckRefs:
|
|||
and entity.find("VisualActor").find("Actor") is not None
|
||||
and entity.find("Identity") is not None
|
||||
):
|
||||
phenotype_tag = entity.find("Identity").find("Phenotype")
|
||||
phenotypes = (
|
||||
phenotype_tag.text.split()
|
||||
if (phenotype_tag is not None and phenotype_tag.text)
|
||||
else ["default"]
|
||||
)
|
||||
cmp_identity = entity.find("Identity")
|
||||
|
||||
actor = entity.find("VisualActor").find("Actor")
|
||||
if "{phenotype}" in actor.text:
|
||||
for phenotype in phenotypes:
|
||||
# See simulation2/components/CCmpVisualActor.cpp and Identity.js
|
||||
# for explanation.
|
||||
actor_path = actor.text.replace("{phenotype}", phenotype)
|
||||
self.deps.append((fp, Path(f"art/actors/{actor_path}")))
|
||||
if cmp_identity is not None:
|
||||
actor_path = actor.text
|
||||
if "{civ}" in actor_path:
|
||||
civ_tag = cmp_identity.find("Civ")
|
||||
civ = civ_tag.text if civ_tag is not None else "gaia"
|
||||
actor_path = actor_path.replace("{civ}", civ)
|
||||
|
||||
if "{phenotype}" in actor_path:
|
||||
phenotype_tag = cmp_identity.find("Phenotype")
|
||||
phenotypes = (
|
||||
phenotype_tag.text.split()
|
||||
if (phenotype_tag is not None and phenotype_tag.text)
|
||||
else ["default"]
|
||||
)
|
||||
for phenotype in phenotypes:
|
||||
# See simulation2/components/CCmpVisualActor.cpp and Identity.js
|
||||
# for explanation.
|
||||
phenotype_path = actor_path.replace("{phenotype}", phenotype)
|
||||
self.deps.append((fp, Path(f"art/actors/{phenotype_path}")))
|
||||
else:
|
||||
actor_path = actor.text
|
||||
self.deps.append((fp, Path(f"art/actors/{actor_path}")))
|
||||
|
||||
foundation_actor = entity.find("VisualActor").find("FoundationActor")
|
||||
if foundation_actor is not None:
|
||||
self.deps.append((fp, Path(f"art/actors/{foundation_actor.text}")))
|
||||
|
|
|
|||
Loading…
Reference in a new issue