1
0
forked from mirrors/0ad

Compare commits

...

47 Commits

Author SHA1 Message Date
phosit d3406f4509 Extend appdata.xml for 0.28.0
(cherry picked from commit 354ed957dc)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-11 18:40:46 +01:00
joeybadz adb6a05ae7 Remove duplicate fertility festival tech in German tech tree
(cherry picked from commit c6b8593bdf)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-11 18:16:35 +01:00
Vladislav Belov e590a7cd4e Replaces choosedDeviceIt by chosenDeviceIt
(cherry picked from commit c0ea17f06e)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-11 18:16:35 +01:00
Vladislav Belov 8420377789 Disables Vulkan devices sorting by default
Currently we always choose the best device. But it's not always
desirable. A more safe approach is to use the default device (with
index 0). The only downside of that is if a user didn't adjust
settings then the game might run on an integrated GPU instead of a
discrete one. In the future it'll be solved by selecting GPU in
options: #8529

Fixes #8455

(cherry picked from commit 485200342d)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-11 18:16:34 +01:00
obelix fbc1b160e1 Change BuildTime of Gaul Arrow Ship
(cherry picked from commit 479995bc6f)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-11 18:16:34 +01:00
obelix e07aba6d37 Change BuildTime of Brit Arrow Ship
(cherry picked from commit 90847e0591)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-11 18:16:34 +01:00
Vantha 2de2084b5b Improve the SpecificName of Celtic civilians
While "Brogiacos" and "Tegesacos" fit in terms of meaning, they are only
reconstructed words, "Ambactos" on the other hand is attested and
actually historically relevant.

(cherry picked from commit 19f6dd031d)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-11 18:16:34 +01:00
Ralph Sennhauser 526deb30f0 Fix reloading config for cinema
This fixes 7df7566d7c, which added
automatic switching off silhouettes in cinema mode while resetting the
value when leaving cinema mode. Reloading can only be done for a given
config namespace.

Fixes: #7552
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit 32edc28cda)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-11 18:16:34 +01:00
Vladislav Belov 1e1db43854 Adds an option to destroy Vulkan old swapchain before
Now it's possible to destroy the old swapchain before creating a new
one. It might make the swapchain creation a bit slower but with a
lower memory peak.

(cherry picked from commit c4bc6c9627)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:31 +01:00
Vladislav Belov b08f2d1d33 Waits Vulkan device idle also on window resize
Fixes the case when a swapchain was recreated on resize rather than
by VK_ERROR_OUT_OF_DATE_KHR.

(cherry picked from commit 8a64182ca2)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:31 +01:00
Vladislav Belov d4736962ab Deletes Vulkan resources on swapchain recreation
The change tries to minimize a memory peak during a window resizing.

Refs #6864

(cherry picked from commit de36c75023)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:31 +01:00
Vantha 68a7d8a03a Provide context for the translation of "Germans"
(cherry picked from commit be83ba4029)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:31 +01:00
Vantha c0d569162b Improve the description of the Germans' civ bonus
Importantly, the word "Germans" is removed since it is prone to being
translated incorrectly and the other civ bonus descriptions don't
contain the civ's name either.

(cherry picked from commit 5d4eab73f9)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:31 +01:00
Vantha 6043ab248b Add SpecificNames to the Germanic units
The names are in Proto-Germanic and mostly taken from Wiktionary.
They can be confirmed by directly searching the individual
Proto-Germanic terms online.

Champion Cavalry: "Aþalaridjô" (noble+rider)
Cavalry Spearman: "Gaizaridjô" (spear+rider)
Cavalry Javelineer: "Skeutaridjô" (quick+rider)
Worker: "Būraz" (dweller, farmer) -- deliberately decided against the most literal translation,
	which would be "Arbijaz", because that seems to be more connected to serfdom and the unit
	rather represents a generic commoner.
Infantry Swordsman: "Swerdamannaz" (sword+man)
Infantry Spearman: "Gaizamannaz" (spear+man)
Infantry Clubman: "Kulbawigô" (staff/club+warrior)
Infantry Javelineer: "Gaizawerpanaz" (spear/javelin+thrower)
Infantry Slinger: "Slingwanaz" (swinger/slinger)
Scout Ship: "Skeutabaitaz" (quick+boat)
Fishing Boat: "Fiskārijaz" (fisherman)
Fire Ship: "Brandabaitaz" (fire+boat)
Arrow Ship: "Harjaskipą" (army/war+ship)
Wagon: "Wagnaz" (direct translation)
Priest: "Gudjô" (direct translation)
Ram: "Rammabagmaz" (strong+tree/beam)
Trader: "Kaupô" (direct translation, also part of the word used for the market)
Merchant(ship): "Mangārī" (direct translation, very similar to "Kaupô")

(cherry picked from commit f38bc89611)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:31 +01:00
Vantha 6958a5edd0 Correct an overlooked 'Women' to 'Workers'
(cherry picked from commit 05b1ac4559)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:31 +01:00
Vantha 86bcb03f6e Remove incorrect Germanic SpecificName
The SpecificName tag is meant to contain the name in the civ's native
language, Proto-Germanic for the Germans.
"Kriegsschiff", "Übungsbereich" and "Stadttor" on the other hand are
modern German words.

(cherry picked from commit a71688fc2c)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:31 +01:00
Vantha f6a6c19132 Convert wrong Germanic SpecificNames to GenericNames
SpecificNames are meant to contain the names in the civ's native
language. The English names are supposed to in be the GenericName tag.

(cherry picked from commit 4d9fc0bb53)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:30 +01:00
Vladislav Belov 76337efe76 Fixes missing Vulkan application version
Missing after dc830ccf55.

(cherry picked from commit 8b1b1d28f8)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:30 +01:00
Stan 93fecf3720 Add credits for Obskurias
(cherry picked from commit 93706ae37c)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-10 20:15:30 +01:00
Vantha df8b313a74 Add a sandbox map for the Germans
(cherry picked from commit 75feace618)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-05 14:20:35 +01:00
real_tabasco_sauce e65e031344 adjust corsica vs sard
(cherry picked from commit 83dba854e5)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-05 14:20:35 +01:00
phosit 83832545ae Add Boiorix as the codename for Release 28
(cherry picked from commit 9588da1d94)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-02 21:54:37 +01:00
real_tabasco_sauce 0b7323c096 Fix market exploit by basing the price change on the amount purchased.
Fix credit to Atrik
Credit for test fix goes to Itms

Fixes #6760

(cherry picked from commit 94d3699ce4)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
Ralph Sennhauser d503ae6da6 Replace boost::filesystem std::filyestem
Bumping the minimum version of macOS to 10.15 for spidermonky [1] also
allows us to use std::filesystem instead of boosts implementation.

[1] f14a98e26f

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit eba8439295)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
Ralph Sennhauser 48b9be5bb6 Require boost-1.69, drop boost_system lib
Boost 1.89 no longer offers the deprecated library for boost_system [1], so
drop it from the list of libraries to link against. This effectively
bumps the minimum required boost version to 1.69 [2].

[1] https://github.com/boostorg/system/commit/7a495bb46d7ccd808e4be2a6589260839b0fd3a3
[1] https://github.com/boostorg/system/commit/2fa0a00583a3a791092568d2ade793314181926e

Fixes: #8471
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit 618ffc7bf9)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
Ralph Sennhauser a7f6171063 Do not require literal message ids in Atlas
In >=wxWidgets-3.3 there is a new static check for literal message
ids[1] so that xgettext would reliable work to extract strings to
translate. As we don't translate Atlas at all nor use xgettext just
disable the check to allow building against >=wxWidgets-3.3.

[1] https://wxwidgets.org/help/msgid-literals/

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit e97f43b692)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
phosit 8f4750db15 Remove the relaypoint before training units
While not as efficient this order is easier to reason and let's player
pause.

(cherry picked from commit 75805f4b23)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
phosit 39a5a680d2 Rewrite the phrase about production availability
It's easier to understand and to translate in a language where a
formulation with "Respectively" is not common.

(cherry picked from commit e195c52e30)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
phosit 61af0a0c26 Rewrite the phrase about building multiple houses
It was hard to understand.

(cherry picked from commit c3727a6a79)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
phosit 53c806c0c4 Replace hunt by slaughter in phrase about chicken
It's not really hunting when nobody flees.
"Slaughter" is used later when talking about the same action.

(cherry picked from commit 727be2fb45)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
phosit b5bf9fd3e2 Replace civ by player in phrase about color
The color is not specivic to the civ but to the player.

(cherry picked from commit a6e4e22ca2)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:50 +01:00
phosit 7a72578517 Don't hardcode Shift as a hotkey in tutorial
It's not possible to format warnings. "a hotkey" is used instead.

Also when the hoplite icon is pressed, without using batches, the
warning doesn't restate that the hopplite should be pressed.

(cherry picked from commit 29ac569511)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:49 +01:00
phosit 1db46eaf9b Replace "I" with the hotkey in eco walkthrough
(cherry picked from commit 4f38600c39)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:49 +01:00
phosit 819a875fcc Only make existing Civilians invulnerable
On "Survival of the Fittest" the treasure-collector are made
invulnerable.
Thous Civilian might not exist when the player is removed.

Fixes: #8421
(cherry picked from commit e0481b283b)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:49 +01:00
Itms 1b50d731fc Store NSIS registry keys under a consistent root
Reviewed-At: https://gitea.wildfiregames.com/0ad/0ad/pulls/8476
(cherry picked from commit 4716a230ab)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:49 +01:00
Itms 621aa9d7a9 Wipe NSIS install preferences when uninstalling
The user language and start menu folder name were saved, which goes
against recommendations in the NSIS documentation.

The installation directory was also saved, which might make sense,
but prevents us from dropping the "alpha" label.

Reviewed-At: https://gitea.wildfiregames.com/0ad/0ad/pulls/8476
Fixes: #7594
(cherry picked from commit 18df61517c)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:49 +01:00
Itms 6a6712799c Fix install and Start Menu folder names on Windows
Those cannot end with a period.

Reviewed-At: https://gitea.wildfiregames.com/0ad/0ad/pulls/8476
(cherry picked from commit f772181501)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:49 +01:00
Itms a7f0678dad Add an engine "compatible" version
When a patch version is released, it must declare compatibility with the
previous patch versions of the same main release. This allows players to
keep replaying their games and to keep playing online with users of
other patches of the same main release.

This should have anticipated for dae7a8c394

(cherry picked from commit 866d6f0527)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:49 +01:00
Itms 4fca5ed21c Use the PYROGENESIS_VERSION macro instead of a global
Reviewed-At: https://gitea.wildfiregames.com/0ad/0ad/pulls/8222
(cherry picked from commit 50f6da2a13)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:49 +01:00
Itms abc83a7dfb Address cppcheck uninitialized warning
Reviewed-At: https://gitea.wildfiregames.com/0ad/0ad/pulls/8222
(cherry picked from commit f0c8db6422)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-31 13:43:48 +01:00
Vladislav Belov 52e6d08e79 Fixes lseek for big files on Windows
It was broken in ef69c37f66, before that we were using _lseeki64.

Fixes #8459

(cherry picked from commit cb58116270)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-26 15:06:35 +01:00
Vantha 46e9585bce PetraBot: Never play when the region analysis fails
If the region analysis at the start of the game fails, the bot can't
actually play and the managers aren't initialised. And to prevent errors
from the update functions, the OnUpdate at the root had an early return
if the entity count was 0. However, in some edge cases the region
analysis can fail even if the AI has entities.
This patch fixes this potential error by storing the result of the
region analysis directly and checking that instead.

(cherry picked from commit 7b1d4426aa)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-26 15:05:49 +01:00
Itms 8d05176032 Lock Linux CI cbindgen version and dependencies
This allows us to keep testing building with the minimal supported
Rust version.

(cherry picked from commit 59d28fed9b)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-26 15:03:08 +01:00
abian 41dac8bb20 Hide Abort Unit Order button when idle or guarding
Reviewed-By: bb
Fixes #6854

(cherry picked from commit 95467c2327)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-26 15:02:34 +01:00
Timothy Pearson 9dee4e4617 Fix FTBFS on ppc64le systems
Tested to compile and function normally under Debian Trixie ppc64le / POWER9

Signed-off-by: Timothy Pearson <tpearson@raptorcs.com>
(cherry picked from commit 2c9928e4cb)
Signed-off-by: phosit <phosit@autistici.org>
2025-10-26 15:00:27 +01:00
Ralph Sennhauser 981b3b898e Support running individual tests or suites
Add back some functionality that got dropped with the move to a custom
runner in 39ea3b6ea5

Add option --list to print all available test grouped by suite.

Add option --suite to limit the run to a specific testsuite.

Add option --test to limit the run to a specific test.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit a7d65d4a34)
2025-10-17 13:31:20 +02:00
phosit d3239591b8 Bump copyright year for windows build 2025-10-15 17:58:23 +02:00
110 changed files with 22065 additions and 252 deletions
+4
View File
@@ -138,6 +138,10 @@ renderer.backend.gl.enableframebufferinvalidating = false
renderer.backend.vulkan.disabledescriptorindexing = false
renderer.backend.vulkan.deviceindexoverride = -1
renderer.backend.vulkan.destroyoldswapchainbefore = false
; In case index override isn't enough we might choose a device automatically.
renderer.backend.vulkan.choosebestdevice = false
renderer.backend.vulkan.debugbarrierafterframebufferpass = false
renderer.backend.vulkan.debugwaitidlebeforeacquire = false
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="German Waypoint Flag">
<variant file="others/waypoints/base.xml" frequency="1" name="Germanic Waypoint Flag">
<textures>
<texture file="props/banner_germans.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Longboat">
<variant frequency="1" name="Germanic Longboat">
<mesh>props/germ_boat_head.dae</mesh>
<textures>
<texture file="structural/germ_boat.png" name="baseTex"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Longboat">
<variant frequency="1" name="Germanic Longboat">
<mesh>props/germ_boat_props.dae</mesh>
<textures>
<texture file="structural/germ_boat.png" name="baseTex"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant name="German Karvi sail">
<variant name="Germanic Karvi sail">
<mesh>props/germ_karvi_sail.dae</mesh>
<animations>
<animation file="other/germ_sail_idle.dae" name="idle" speed="50"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German fishing boat prop">
<variant frequency="1" name="Germanic fishing boat prop">
<mesh>props/germ_dock_boat.dae</mesh>
<textures>
<texture file="structural/germ_fishing_boat.png" name="baseTex"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Karvi">
<variant frequency="1" name="Germanic Karvi">
<mesh>props/germ_karvi_props.dae</mesh>
<textures>
<texture file="structural/germ_snekkja.png" name="baseTex"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Karvi sail">
<variant frequency="1" name="Germanic Karvi sail">
<mesh>props/germ_karvi_sail.dae</mesh>
<animations>
<animation file="other/germ_sail_idle.dae" name="idle" speed="50"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Knarr Props">
<variant frequency="1" name="Germanic Knarr Props">
<mesh>props/germ_knarr_props.dae</mesh>
<textures>
<texture file="structural/germ_snekkja.png" name="baseTex"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Longboat">
<variant frequency="1" name="Germanic Longboat">
<mesh>props/germ_snekkja_head.dae</mesh>
<textures>
<texture file="structural/germ_snekkja.png" name="baseTex"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Longboat">
<variant frequency="1" name="Germanic Longboat">
<mesh>props/germ_snekkja_props.dae</mesh>
<textures>
<texture file="structural/germ_snekkja.png" name="baseTex"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant name="German Snekkja Sail">
<variant name="Germanic Snekkja Sail">
<mesh>props/germ_snekkja_sail.dae</mesh>
<animations>
<animation file="other/germ_sail_idle.dae" name="idle" speed="50"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant name="German wagon_unyoked">
<variant name="Germanic wagon_unyoked">
<mesh>props/germ_wagon_cc.dae</mesh>
<textures>
<texture file="structural/germ_struct.png" name="baseTex"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant name="German wagon_unyoked">
<variant name="Germanic wagon_unyoked">
<mesh>props/germ_wagon_cc.dae</mesh>
<textures>
<texture file="structural/germ_struct.png" name="baseTex"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant name="German wagon_unyoked">
<variant name="Germanic wagon_unyoked">
<mesh>props/germ_wagon_cc.dae</mesh>
<textures>
<texture file="structural/germ_struct.png" name="baseTex"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant name="German wagon_unyoked">
<variant name="Germanic wagon_unyoked">
<mesh>props/germ_wagon_cc.dae</mesh>
<textures>
<texture file="structural/germ_struct.png" name="baseTex"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant name="German wagon_unyoked">
<variant name="Germanic wagon_unyoked">
<mesh>props/germ_wagon_cc.dae</mesh>
<textures>
<texture file="structural/germ_struct.png" name="baseTex"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant name="German wagon_unyoked">
<variant name="Germanic wagon_unyoked">
<mesh>props/germ_wagon_cc.dae</mesh>
<textures>
<texture file="structural/germ_struct.png" name="baseTex"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant name="German Blacksmith">
<variant name="Germanic Blacksmith">
<mesh>structural/germans/blacksmith.dae</mesh>
<props>
<prop actor="props/structures/decals/dirt_4x4.xml" attachpoint="root"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant frequency="1" name="German Civic Center" file="structures/defensive_building.xml">
<variant frequency="1" name="Germanic Civic Center" file="structures/defensive_building.xml">
<mesh>structural/germans/cc.dae</mesh>
<props>
<prop actor="props/structures/decals/spart_5x5.xml" attachpoint="root"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="100" name="German fishing boat">
<variant frequency="100" name="Germanic fishing boat">
<mesh>structural/germans/fishing_boat.dae</mesh>
<props>
<prop actor="units/germans/fisherman.xml" attachpoint="fisherman"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant frequency="1" name="German House A">
<variant frequency="1" name="Germanic House A">
<mesh>structural/germans/house_a.dae</mesh>
<textures>
<texture file="structural/germ_struct_03.png" name="baseTex"/>
@@ -38,7 +38,7 @@
<prop actor="props/special/eyecandy/sack_1.xml" attachpoint="sack_2"/>
</props>
</variant>
<variant frequency="1" name="German House A 2">
<variant frequency="1" name="Germanic House A 2">
<mesh>structural/germans/house_a_2.dae</mesh>
<textures>
<texture file="structural/germ_struct.png" name="baseTex"/>
@@ -74,7 +74,7 @@
<prop actor="props/special/eyecandy/sack_1.xml" attachpoint="sack_2"/>
</props>
</variant>
<variant frequency="1" name="German House B">
<variant frequency="1" name="Germanic House B">
<mesh>structural/germans/house_b.dae</mesh>
<textures>
<texture file="structural/germ_struct_03.png" name="baseTex"/>
@@ -105,7 +105,7 @@
<prop actor="particle/smoke_blacksmith.xml" attachpoint="smoke"/>
</props>
</variant>
<variant frequency="1" name="German House C">
<variant frequency="1" name="Germanic House C">
<mesh>structural/germans/house_c.dae</mesh>
<textures>
<texture file="structural/germ_struct_03.png" name="baseTex"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant frequency="1" name="German Sentry Tower" file="structures/defensive_building.xml">
<variant frequency="1" name="Germanic Sentry Tower" file="structures/defensive_building.xml">
<mesh>structural/germans/wood_tower.dae</mesh>
<props>
<prop actor="props/structures/decals/dirt_1x1.xml" attachpoint="root"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Longboat">
<variant frequency="1" name="Germanic Longboat">
<mesh>structural/germans/ship_arrow.dae</mesh>
<props>
<prop actor="props/structures/germans/boat_props.xml" attachpoint="mast"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Longboat">
<variant frequency="1" name="Germanic Longboat">
<mesh>structural/germans/ship_karvi.dae</mesh>
<props>
<prop actor="props/units/weapons/bolt_tower.xml" attachpoint="projectile"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Merchant Ship">
<variant frequency="1" name="Germanic Merchant Ship">
<mesh>structural/germans/ship_knarr.dae</mesh>
<props>
<prop actor="props/structures/germans/knarr_props.xml" attachpoint="root"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Longboat">
<variant frequency="1" name="Germanic Longboat">
<mesh>structural/germans/ship_scout.dae</mesh>
<props>
<prop actor="props/units/weapons/bolt_tower.xml" attachpoint="projectile"/>
@@ -3,7 +3,7 @@
<castshadow/>
<float/>
<group>
<variant frequency="1" name="German Longboat">
<variant frequency="1" name="Germanic Longboat">
<mesh>structural/germans/ship_snekkja.dae</mesh>
<props>
<prop actor="props/units/weapons/bolt_tower.xml" attachpoint="projectile"/>
@@ -2,7 +2,7 @@
<actor version="1">
<castshadow/>
<group>
<variant name="German Wall Tower" file="structures/defensive_building.xml">
<variant name="Germanic Wall Tower" file="structures/defensive_building.xml">
<mesh>structural/germans/wooden_wall_tower.dae</mesh>
<textures>
<texture file="structural/germ_struct_03.png" name="baseTex"/>
@@ -44,6 +44,7 @@
{ "name": "Micha L. Rieser" },
{ "nick": "Nescio" },
{ "nick": "nifa" },
{ "nick": "Obskurias", "name": "Alejandro Liaño" },
{ "name": "Paul Maritz" },
{ "nick": "pedro_blanco", "name": "Pedro Blanco" },
{ "name": "Pete Unseth" },
@@ -146,6 +146,7 @@
{ "nick": "javiergodas", "name": "Javier Godas Vieitez" },
{ "nick": "JCWasmx86" },
{ "nick": "Jgwman" },
{ "nick": "joeybadz", "name": "Joe Badlato" },
{ "nick": "JonBaer", "name": "Jon Baer" },
{ "nick": "Josh", "name": "Joshua J. Bakita" },
{ "nick": "joskar", "name": "Johnny Oskarsson" },
@@ -24,7 +24,8 @@ class PersistentMatchSettings
Engine.FileExists(this.filename) &&
Engine.ReadJSONFile(this.filename);
const persistedSettings = data?.engine_info?.engine_version == this.engineInfo.engine_version &&
const persistedSettings = data?.engine_info?.engine_serialization_version &&
data.engine_info.engine_serialization_version == this.engineInfo.engine_serialization_version &&
hasSameMods(data?.engine_info?.mods, this.engineInfo.mods) &&
data.attributes || {};
@@ -174,8 +174,8 @@ class SavegameList
isCompatibleSavegame(metadata, engineInfo)
{
return engineInfo &&
metadata.engine_version &&
metadata.engine_version == engineInfo.engine_version &&
metadata.engine_serialization_version &&
metadata.engine_serialization_version == engineInfo.engine_serialization_version &&
hasSameMods(metadata.mods, engineInfo.mods);
}
@@ -24,9 +24,9 @@ class SavegameLoader
// Check compatibility before really loading it
const engineInfo = Engine.GetEngineInfo();
const sameMods = hasSameMods(metadata.mods, engineInfo.mods);
const sameEngineVersion = metadata.engine_version && metadata.engine_version == engineInfo.engine_version;
const compatibleEngineVersions = metadata.engine_serialization_version && metadata.engine_serialization_version == engineInfo.engine_serialization_version;
if (sameEngineVersion && sameMods)
if (compatibleEngineVersions && sameMods)
{
this.closePageCallback(gameId);
return;
@@ -35,14 +35,17 @@ class SavegameLoader
// Version not compatible ... ask for confirmation
let message = "";
if (!sameEngineVersion)
if (metadata.engine_version)
message += sprintf(translate("This savegame needs 0 A.D. version %(requiredVersion)s, while you are running version %(currentVersion)s."), {
"requiredVersion": metadata.engine_version,
"currentVersion": engineInfo.engine_version
if (!compatibleEngineVersions)
{
if (metadata.engine_serialization_version)
message += sprintf(translate("This savegame needs 0 A.D. version %(requiredCompatibleVersion)s or compatible. You are running version %(currentVersion)s, compatible down to %(compatibleVersion)s."), {
"requiredCompatibleVersion": metadata.engine_serialization_version,
"currentVersion": engineInfo.engine_version,
"compatibleVersion": engineInfo.engine_serialization_version,
}) + "\n";
else
message += translate("This savegame needs an older version of 0 A.D.") + "\n";
}
if (!sameMods)
{
@@ -15,7 +15,7 @@ export const projectInformation = {
"caption": getBuildString()
},
"productDescription": {
"caption": setStringTags(translate("Release XXVIII: B——"), { "font": "sans-bold-16" }) + "\n\n" +
"caption": setStringTags(translate("Release XXVIII: Boiorix"), { "font": "sans-bold-16" }) + "\n\n" +
translate("Notice: This game is under development and many features have not been added yet.")
}
};
@@ -84,7 +84,7 @@ function reallyStartVisualReplay(replayDirectory)
function displayReplayCompatibilityError(replay)
{
var errMsg;
if (replayHasSameEngineVersion(replay))
if (replayHasCompatibleEngineVersion(replay))
{
const gameMods = replay.attribs.mods || [];
errMsg = translate("This replay needs a different sequence of mods:") + "\n" +
@@ -93,8 +93,9 @@ function displayReplayCompatibilityError(replay)
else
{
errMsg = translate("This replay is not compatible with your version of the game!") + "\n";
errMsg += sprintf(translate("Your version: %(version)s"), { "version": g_EngineInfo.engine_version }) + "\n";
errMsg += sprintf(translate("Required version: %(version)s"), { "version": replay.attribs.engine_version });
errMsg += sprintf(translate("Your version: %(version)s, compatible down to %(compatibleVersion)s"), { "version": g_EngineInfo.engine_version, "compatibleVersion": g_EngineInfo.engine_serialization_version }) + "\n";
if (replay.attribs.engine_serialization_version)
errMsg += sprintf(translate("Replay version: %(version)s"), { "version": replay.attribs.engine_serialization_version });
}
messageBox(500, 200, errMsg, translate("Incompatible replay"));
@@ -360,13 +360,13 @@ function getReplayDuration(replay)
*/
function isReplayCompatible(replay)
{
return replayHasSameEngineVersion(replay) && hasSameMods(replay.attribs.mods, g_EngineInfo.mods);
return replayHasCompatibleEngineVersion(replay) && hasSameMods(replay.attribs.mods, g_EngineInfo.mods);
}
/**
* True if we can start the given replay with the currently loaded mods.
*/
function replayHasSameEngineVersion(replay)
function replayHasCompatibleEngineVersion(replay)
{
return replay.attribs.engine_version && replay.attribs.engine_version == g_EngineInfo.engine_version;
return replay.attribs.engine_serialization_version && replay.attribs.engine_serialization_version == g_EngineInfo.engine_serialization_version;
}
@@ -705,7 +705,7 @@ function updateCinemaPath()
{
// TODO: Keyboard shortcuts can still try to toggle silhouettes
// which would behave incorrectly on reset.
Engine.ConfigDB_Reload();
Engine.ConfigDB_Reload("user");
g_HasHiddenSilhouettes = false;
}
}
@@ -3,7 +3,7 @@
<!-- IMPORTANT: remember to update pregame/ProjectInformation.js in sync with this: -->
<object type="text" style="ModernLabelText" text_valign="top" ghost="true" size="0% 1 100% 100%">
<translatableAttribute id="caption">Release XXVIII: B——</translatableAttribute>
<translatableAttribute id="caption">Release XXVIII: Boiorix</translatableAttribute>
</object>
<!-- Displays build date and build version-->
@@ -1550,7 +1550,8 @@ var g_EntityCommands =
"stop": {
"getInfo": function(entStates)
{
if (entStates.every(entState => !entState.unitAI))
// Don't show generic option to abort if not applicable or in case of guard, which has its own abort action
if (entStates.every(entState => !entState.unitAI || entState.unitAI.isIdle || entState.unitAI.isGuarding))
return false;
return {
@@ -30,7 +30,7 @@ export function* generateMap()
const ePine = "gaia/tree/aleppo_pine";
const ePalmTall = "gaia/tree/cretan_date_palm_tall";
const eFanPalm = "gaia/tree/medit_fan_palm";
const eApple = "gaia/fruit/apple";
const eCypress = "gaia/tree/cypress";
const eBush = "gaia/fruit/berry_01";
const eFish = "gaia/fish/generic";
const ePig = "gaia/fauna_pig";
@@ -68,6 +68,7 @@ export function* generateMap()
const clCreek = g_Map.createTileClass();
const clWater = g_Map.createTileClass();
const clCliffs = g_Map.createTileClass();
const clFish = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clShore = g_Map.createTileClass();
const clPlayer = g_Map.createTileClass();
@@ -75,19 +76,19 @@ export function* generateMap()
const clPassage = g_Map.createTileClass();
const clSettlement = g_Map.createTileClass();
const radiusBeach = fractionToTiles(0.57);
const radiusCreeks = fractionToTiles(0.52);
const radiusIsland = fractionToTiles(0.4);
const radiusLevel1 = fractionToTiles(0.35);
const radiusPlayer = fractionToTiles(0.25);
const radiusLevel2 = fractionToTiles(0.2);
const radiusBeach = fractionToTiles(0.65);
const radiusCreeks = fractionToTiles(0.60);
const radiusIsland = fractionToTiles(0.46);
const radiusLevel1 = fractionToTiles(0.40);
const radiusPlayer = fractionToTiles(0.29);
const radiusLevel2 = fractionToTiles(0.20);
const creeksArea = () => randBool() ? randFloat(10, 50) : scaleByMapSize(75, 100) + randFloat(0, 20);
const nbCreeks = scaleByMapSize(6, 15);
const nbCreeks = scaleByMapSize(7, 9);
const nbSubIsland = 5;
const nbBeaches = scaleByMapSize(2, 5);
const nbPassagesLevel1 = scaleByMapSize(4, 8);
const nbBeaches = scaleByMapSize(6, 10);
const nbPassagesLevel1 = scaleByMapSize(6, 8);
const nbPassagesLevel2 = scaleByMapSize(2, 4);
g_Map.log("Creating Corsica and Sardinia");
@@ -183,9 +184,9 @@ export function* generateMap()
new Vector2D(radiusLevel1 + 10, 0).rotate(-angle)),
"end": Vector2D.add(islandLocations[island],
new Vector2D(radiusLevel1 - 4, 0).rotate(-angle)),
"startWidth": 10,
"endWidth": 6,
"smoothWidth": 3,
"startWidth": 20,
"endWidth": 20,
"smoothWidth": 2,
"tileClass": clPassage
});
}
@@ -212,8 +213,8 @@ export function* generateMap()
new Vector2D(radiusLevel2 + 3, 0).rotate(-angle)),
"end": Vector2D.add(islandLocations[island],
new Vector2D(radiusLevel2 - 6, 0).rotate(-angle)),
"startWidth": 4,
"endWidth": 6,
"startWidth": 20,
"endWidth": 20,
"smoothWidth": 2,
"tileClass": clPassage
});
@@ -409,7 +410,7 @@ export function* generateMap()
new SimpleObject(ePine, 3, 6, 1, 3),
new SimpleObject(ePalmTall, 1, 3, 1, 3),
new SimpleObject(eFanPalm, 0, 2, 0, 2),
new SimpleObject(eApple, 0, 1, 1, 2)
new SimpleObject(eCypress, 0, 1, 1, 2)
],
true,
clForest),
@@ -515,36 +516,34 @@ export function* generateMap()
50);
g_Map.log("Creating fish");
createObjectGroupsDeprecated(
new SimpleGroup([new SimpleObject(eFish, 1, 2, 0, 3)]),
0,
[
stayClasses(clWater, 3),
avoidClasses(clCreek, 3, clShore, 3)
],
scaleByMapSize(100, 150),
300);
createFood(
[
[new SimpleObject(eFish, 2, 3, 0, 2)]
],
[
50 * numPlayers
],
[
avoidClasses(clCreek, 2, clShore, 3, clFish, 8),
stayClasses(clWater, 3)
],
clFish);
g_Map.log("Creating shore fish");
createObjectGroupsDeprecated(
new SimpleGroup([new SimpleObject(eFish, 1, 2, 0, 3)]),
0,
[
stayClasses(clCreek, 1),
],
scaleByMapSize(200, 300),
500);
g_Map.log("Creating shore fish");
createObjectGroupsDeprecated(
new SimpleGroup([new SimpleObject(eFish, 1, 2, 0, 3)]),
0,
createFood(
[
stayClasses(clShore, 3)
[new SimpleObject(eFish, 2, 3, 0, 2)]
],
scaleByMapSize(200, 300),
500);
[
70 * numPlayers
],
[
avoidClasses(clFish, 6),
stayClasses(clWater, 3, clShore, 0)
],
clFish);
yield 95;
@@ -149,7 +149,11 @@ Trigger.prototype.InitStartingUnits = function()
{
this.playerCivicCenter[playerID] = TriggerHelper.GetPlayerEntitiesByClass(playerID, "CivilCentre")[0];
this.treasureCivilian[playerID] = TriggerHelper.GetPlayerEntitiesByClass(playerID, "Civilian")[0];
Engine.QueryInterface(this.treasureCivilian[playerID], IID_Resistance).SetInvulnerability(true);
if (this.treasureCivilian[playerID])
{
Engine.QueryInterface(this.treasureCivilian[playerID], IID_Resistance)
.SetInvulnerability(true);
}
}
};
File diff suppressed because it is too large Load Diff
@@ -16,12 +16,12 @@ Trigger.prototype.tutorialGoals = [
},
{
"instructions": [
markForTranslation("To start off, select your building, the Civic Center, by clicking on it. A selection ring in the color of your civilization will be displayed after clicking.")
markForTranslation("To start off, select your building, the Civic Center, by clicking on it. A selection ring in the color of your player will be displayed after clicking.")
]
},
{
"instructions": [
markForTranslation("Now that the Civic Center is selected, you will notice that a production panel will appear on the lower right of your screen detailing the actions that the buildings supports. For the production panel, available actions are not masked in any color, while an icon masked in either gray or red indicates that the action has not been unlocked or you do not have sufficient resources to perform that action, respectively. Additionally, you can hover the cursor over any icon to show a tooltip with more details.\n"),
markForTranslation("Now that the Civic Center is selected, you will notice that a production panel will appear on the lower right of your screen detailing the actions that the buildings supports. For the production panel, available actions are not masked in any color, while an icon masked in gray indicates that the action has not been unlocked and a red mask indicates that you do not have sufficient resources to perform that action. Additionally, you can hover the cursor over any icon to show a tooltip with more details.\n"),
markForTranslation("The top row of buttons contains portraits of units that may be trained at the building while the bottom one or two rows will have researchable technologies. Hover the cursor over the II icon. The tooltip will tell us that advancing to Town Phase requires both more constructed structures as well as more food and wood resources.")
]
},
@@ -40,7 +40,10 @@ Trigger.prototype.tutorialGoals = [
markForTranslation("At this point, food and wood are the most important resources for developing your economy, so let's start with gathering food. Civilians gather vegetables faster than other units.\n"),
markForTranslation("There are primarily three ways to select units:\n"),
markForTranslation("1) Hold the left mouse button and drag a selection rectangle that encloses the units you want to select.\n"),
markForTranslation("2) Click on one of them and then add additional units to your selection by holding Shift and clicking each additional unit (or also via the above selection rectangle).\n"),
{
"text": markForTranslation("2) Click on one of them and then add additional units to your selection by holding %(hotkey)s and clicking each additional unit (or also via the above selection rectangle).\n"),
"hotkey": "selection.add"
},
{
"text": markForTranslation("3) Double-click on a unit. This will select every unit of the same type as the specified unit in your visible window. %(hotkey)s+double-click will select all units of the same type on the entire map.\n"),
"hotkey": "selection.offscreen"
@@ -67,7 +70,7 @@ Trigger.prototype.tutorialGoals = [
},
{
"instructions": [
markForTranslation("Cavalry Citizen Soldiers are good for hunting. Select your Cavalry and order him to hunt the chickens around your Civic Center in similar fashion.")
markForTranslation("Cavalry Citizen Soldiers are good for hunting. Select your Cavalry and order him to slaughter the chickens around your Civic Center in similar fashion.")
],
"OnPlayerCommand": function(msg)
{
@@ -98,7 +101,10 @@ Trigger.prototype.tutorialGoals = [
{
"instructions": [
markForTranslation("Now that the rally point is set, we can produce additional units and they will do their assigned task automatically.\n"),
markForTranslation("Citizen Soldiers gather wood faster than Civilians. Select the Civic Center and, while holding Shift, click on the second unit icon, the Hoplites (holding Shift trains a batch of five units). You can also train units individually by simply clicking, but training 5 units together takes less time than training 5 units individually.")
{
"text": markForTranslation("Citizen Soldiers gather wood faster than Civilians. Select the Civic Center and, while holding %(hotkey)s, click on the second unit icon, the Hoplites (holding %(hotkey)s trains a batch of five units). You can also train units individually by simply clicking, but training 5 units together takes less time than training 5 units individually."),
"hotkey": "session.batchtrain"
}
],
"OnTrainingQueued": function(msg)
{
@@ -108,8 +114,8 @@ Trigger.prototype.tutorialGoals = [
const cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
cmpProductionQueue.ResetQueue();
const txt = +msg.count == 1 ?
markForTranslation("Do not forget to hold Shift while clicking to train several units.") :
markForTranslation("Hold Shift and click on the Hoplite icon.");
markForTranslation("Do not forget to hold the hotkey while clicking to train several units.") :
markForTranslation("The second icon represents the Hoplites.");
this.WarningMessage(txt);
return;
}
@@ -153,7 +159,24 @@ Trigger.prototype.tutorialGoals = [
{
"instructions": [
markForTranslation("When construction finishes, the builders default to gathering wood automatically.\n"),
markForTranslation("Let's train some Civilians to gather more food. Select the Civic Center, hold Shift and click on the Civilian icon to train five Civilians.")
markForTranslation("In the meantime, we seem to have enough workers gathering wood. We should remove the current rally point of the Civic Center away from gathering wood. For that purpose, right-click on the Civic Center when it is selected (and the flag icon indicating the rally point is crossed out).")
],
"OnPlayerCommand": function(msg)
{
if (msg.cmd.type == "unset-rallypoint")
this.NextGoal();
},
"OnTrainingFinished": function(msg)
{
this.trainingDone = true;
}
},
{
"instructions": [
{
"text": markForTranslation("Let's train some Civilians to gather more food. Select the Civic Center, hold %(hotkey)s and click on the Civilian icon to train five Civilians."),
"hotkey": "session.batchtrain"
}
],
"Init": function()
{
@@ -167,29 +190,14 @@ Trigger.prototype.tutorialGoals = [
const cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
cmpProductionQueue.ResetQueue();
const txt = +msg.count == 1 ?
markForTranslation("Do not forget to hold Shift and click to train several units.") :
markForTranslation("Hold shift and click on the Civilian icon.");
markForTranslation("Do not forget to hold the hotkey and click to train several units.") :
markForTranslation("The first icon represents the Civilians.");
this.WarningMessage(txt);
return;
}
this.NextGoal();
}
},
{
"instructions": [
markForTranslation("Let's wait for the units to be trained.\n"),
markForTranslation("In the meantime, we seem to have enough workers gathering wood. We should remove the current rally point of the Civic Center away from gathering wood. For that purpose, right-click on the Civic Center when it is selected (and the flag icon indicating the rally point is crossed out).")
],
"OnPlayerCommand": function(msg)
{
if (msg.cmd.type == "unset-rallypoint")
this.NextGoal();
},
"OnTrainingFinished": function(msg)
{
this.trainingDone = true;
}
},
{
"instructions": [
markForTranslation("The units should be ready soon.\n"),
@@ -212,8 +220,14 @@ Trigger.prototype.tutorialGoals = [
},
{
"instructions": [
markForTranslation("Select two of your newly-trained Civilians and ask them to build these Houses in the empty space to the east of the Civic Center. To do so, after selecting the Civilians, click on the House icon in the bottom right panel and, while holding Shift, click first on the position in the map where you want to build the first House, and then click on the position where you want to build the second House (when you give a command while holding Shift, you put the command in a queue; units automatically switch to the next command in their queue when they finish their current command). Press Escape to get rid of the House cursor so you don't spam Houses all over the map.\n"),
markForTranslation("Reminder: to select only two Civilians, click on the first one and then hold Shift and click on the second one.")
{
"text": markForTranslation("Select two of your newly-trained Civilians and order them to build these Houses in the empty space to the east of the Civic Center. Click on the House icon in the bottom right panel. While holding %(hotkey)s click on positions on the map where you want to build Houses. The Civilians will then start to build the houses in order. (When you give a command while holding %(hotkey)s, you put the command in a queue; units automatically switch to the next command in their queue when they finish their current command). Press Escape to get rid of the House cursor so you don't spam Houses all over the map.\n"),
"hotkey": "selection.queue"
},
{
"text": markForTranslation("Reminder: to select only two Civilians, click on the first one and then hold %(hotkey) and click on the second one."),
"hotkey": "selection.add"
}
],
"Init": function()
{
@@ -260,7 +274,10 @@ Trigger.prototype.tutorialGoals = [
"instructions": [
markForTranslation("Select the three remaining (idle) Civilians and order them to build a Farmstead in the center of the large open area to the west of the Civic Center.\n"),
markForTranslation("We will need a decent chunk of space around the Farmstead to build Fields. In addition, we can see goats on the west side to further improve our food gathering efficiency should we ever decide to hunt them.\n"),
markForTranslation("If you try to select the three idle Civilians by clicking and dragging a selection rectangle over them, you might accidentally select additional units. To avoid that, hold the I key while selecting so that only idle units are selected. If you accidentally select a cavalry unit, hold Ctrl and click on the cavalry unit icon of the selection panel at the bottom of the screen to remove the cavalry unit from the current selection.")
{
"text": markForTranslation("If you try to select the three idle Civilians by clicking and dragging a selection rectangle over them, you might accidentally select additional units. To avoid that, hold %(hotkey)s while selecting so that only idle units are selected. If you accidentally select a cavalry unit, hold Ctrl and click on the cavalry unit icon of the selection panel at the bottom of the screen to remove the cavalry unit from the current selection."),
"hotkey": "selection.idleonly"
}
],
"OnPlayerCommand": function(msg)
{
@@ -344,7 +361,7 @@ Trigger.prototype.tutorialGoals = [
const cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
cmpProductionQueue.ResetQueue();
const txt = +msg.count != 1 ?
markForTranslation("Click without holding Shift to train a single unit.") :
markForTranslation("Click without holding a hotkey to train a single unit.") :
markForTranslation("Click on the Civilian icon.");
this.WarningMessage(txt);
return;
@@ -415,7 +432,10 @@ Trigger.prototype.tutorialGoals = [
},
{
"instructions": [
markForTranslation("Thus, we should order them to deposit their wood in the Civic Center along the way. To do so, we will hold Shift while clicking to queue orders: select your soldiers, hold Shift and right-click on the Civic Center to deposit their wood and then hold Shift and right-click on the stone quarry to gather it.\n"),
{
"text": markForTranslation("Thus, we should order them to deposit their wood in the Civic Center along the way. To do so, we will hold %(hotkey)s while clicking to queue orders: select your soldiers, hold %(hotkey)s and right-click on the Civic Center to deposit their wood and then hold %(hotkey)s and right-click on the stone quarry to gather it.\n"),
"hotkey": "selection.queue"
},
markForTranslation("Perform a similar order queue with the remaining soldiers and the metal mine in the west.")
],
"Init": function()
@@ -84,8 +84,8 @@ PetraBot.prototype.CustomInit = function(gameState)
this.HQ.init(gameState, this.queues);
// Analyze our starting position and set a strategy
this.HQ.gameAnalysis(gameState);
// Try to analyze our starting position and set a strategy.
this.canPlay = this.HQ.gameAnalysis(gameState);
}
};
@@ -112,10 +112,10 @@ PetraBot.prototype.OnUpdate = function(sharedScript)
this.playedTurn++;
if (this.gameState.getOwnEntities().length === 0)
if (!this.canPlay)
{
Engine.ProfileStop();
return; // With no entities to control the AI cannot do anything
return;
}
this.HQ.update(this.gameState, this.queues, this.savedEvents);
@@ -17,7 +17,7 @@ Headquarters.prototype.gameAnalysis = function(gameState)
{
// Analysis of the terrain and the different access regions
if (!this.regionAnalysis(gameState))
return;
return false;
this.attackManager.init(gameState);
this.buildManager.init(gameState);
@@ -57,6 +57,8 @@ Headquarters.prototype.gameAnalysis = function(gameState)
// configure our first base strategy
if (this.hasPotentialBase())
this.configFirstBase(gameState);
return true;
};
/**
@@ -113,7 +113,7 @@ Barter.prototype.ExchangeResources = function(playerID, resourceToSell, resource
cmpStatisticsTracker.IncreaseResourcesBoughtCounter(resourceToBuy, amountToAdd);
}
const difference = this.DIFFERENCE_PER_DEAL * amount / this.DEAL_AMOUNT;
const difference = this.DIFFERENCE_PER_DEAL * amountToAdd / this.DEAL_AMOUNT;
// Overall price difference (dynamic +/- constant) can't exceed +-99%.
const maxDifference = this.DEAL_AMOUNT * 0.99;
@@ -100,7 +100,7 @@ cmpBarter.priceDifferences = { "wood": 0, "stone": 0, "metal": 0 };
cmpBarter.ExchangeResources(playerID, "wood", "stone", 100);
TS_ASSERT_EQUALS(cmpBarter.restoreTimer, 7);
TS_ASSERT(timerActivated);
TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -cmpBarter.DIFFERENCE_PER_DEAL, "stone": cmpBarter.DIFFERENCE_PER_DEAL, "metal": 0 });
TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -cmpBarter.DIFFERENCE_PER_DEAL * bought / 100, "stone": cmpBarter.DIFFERENCE_PER_DEAL * bought / 100, "metal": 0 });
TS_ASSERT_EQUALS(sold, 100);
TS_ASSERT_EQUALS(bought, Math.round(100 * (100 - cmpBarter.CONSTANT_DIFFERENCE + 0) / (100 + cmpBarter.CONSTANT_DIFFERENCE + 0)));
@@ -125,12 +125,12 @@ TS_ASSERT_EQUALS(bought, 0);
cmpBarter.priceDifferences = { "wood": 0, "stone": 99 - cmpBarter.CONSTANT_DIFFERENCE, "metal": 0 };
cmpBarter.ExchangeResources(playerID, "wood", "stone", 100);
TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -cmpBarter.DIFFERENCE_PER_DEAL, "stone": 99 - cmpBarter.CONSTANT_DIFFERENCE, "metal": 0 });
TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -cmpBarter.DIFFERENCE_PER_DEAL * bought / 100, "stone": 99 - cmpBarter.CONSTANT_DIFFERENCE, "metal": 0 });
TS_ASSERT_EQUALS(bought, Math.round(100 * (100 - cmpBarter.CONSTANT_DIFFERENCE + 0) / (100 + cmpBarter.CONSTANT_DIFFERENCE + 99 - cmpBarter.CONSTANT_DIFFERENCE)));
cmpBarter.priceDifferences = { "wood": -99 + cmpBarter.CONSTANT_DIFFERENCE, "stone": 0, "metal": 0 };
cmpBarter.ExchangeResources(playerID, "wood", "stone", 100);
TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -99 + cmpBarter.CONSTANT_DIFFERENCE, "stone": cmpBarter.DIFFERENCE_PER_DEAL, "metal": 0 });
TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -99 + cmpBarter.CONSTANT_DIFFERENCE, "stone": cmpBarter.DIFFERENCE_PER_DEAL * bought / 100, "metal": 0 });
TS_ASSERT_EQUALS(bought, Math.round(100 * (100 - cmpBarter.CONSTANT_DIFFERENCE - 99 + cmpBarter.CONSTANT_DIFFERENCE) / (100 + cmpBarter.CONSTANT_DIFFERENCE + 0)));
cmpBarter.priceDifferences = { "wood": 0, "stone": 0, "metal": 0 };
@@ -27,8 +27,8 @@
"CivBonuses": [
{
"Name": "Seeresses",
"History": "Seeresses accompanied the German armies and envisioned prophecies of victory from sacrifices.",
"Description": "Germans can access a Champion Healer unit in City Phase."
"History": "Seeresses accompanied the Germanic armies and envisioned prophecies of victory from sacrifices.",
"Description": "A unique Champion Healer unit is available in City Phase."
}
],
"WallSets":
@@ -1,7 +1,7 @@
{
"genericName": "Bovine Tradition",
"autoResearch": true,
"description": "German convoys brought livestock, in particular cattle, and placed great importance on these animals for religious sacrifices.",
"description": "Germanic convoys brought livestock, in particular cattle, and placed great importance on these animals for religious sacrifices.",
"requirements": { "civ": "germ" },
"icon": "meat.png",
"tooltip": "Civilians +100% meat gather rate.",
@@ -13,6 +13,7 @@
{ "notciv": "brit" },
{ "notciv": "cart" },
{ "notciv": "gaul" },
{ "notciv": "germ" },
{ "notciv": "han" },
{ "notciv": "iber" },
{ "notciv": "mace" },
@@ -1,6 +1,6 @@
{
"genericName": "Wagon Trains",
"description": "Long trains of wagons accompanied the Cimbri and German peoples to provide shelter and transport goods",
"description": "Long trains of wagons accompanied the Cimbri and Germanic peoples to provide shelter and transport goods",
"cost": {
"wood": 400,
"metal": 100
@@ -14,7 +14,7 @@
"requirementsTooltip": "Unlocked in Town Phase.",
"icon": "population.png",
"researchTime": 40,
"tooltip": "Supply Wagons +5 population space and Wagon Encampments +10 population space. Training German Women unlocked from the Supply Wagon as well.",
"tooltip": "Supply Wagons +5 population space and Wagon Encampments +10 population space. Training Germanic Workers unlocked from the Supply Wagon as well.",
"modifications": [
{ "value": "Promotion/RequiredXp", "replace": 0, "affects": "Wagon" },
{ "value": "Population/Bonus", "add": 10, "affects": "Colony" }
@@ -5,7 +5,7 @@
</Auras>
<Identity>
<Civ>germ</Civ>
<GenericName>Germans</GenericName>
<GenericName comment="Translation: This string does NOT refer to modern-day Germans, but rather to the ancient Germanic tribes such as the Cimbri.">Germans</GenericName>
<History>The largest migration in Europe of this period was that of the Cimbri people. The Cimbri were a large group of Germanic peoples originally from the Jutland region, in the north of modern-day Denmark. In the late 2nd century BC, their migration south into Italy and France would spark the decade-long Cimbrian War against the Roman Republic, bringing "Terror Germanicus" to the hearts of the Roman people.</History>
<Icon>emblems/emblem_germ.png</Icon>
</Identity>
@@ -2,7 +2,6 @@
<Entity parent="template_structure_military_range">
<Identity>
<Civ>germ</Civ>
<SpecificName>Übungsbereich</SpecificName>
</Identity>
<VisualActor>
<Actor>structures/germans/range.xml</Actor>
@@ -6,7 +6,6 @@
</Footprint>
<Identity>
<Civ>germ</Civ>
<SpecificName>Stadttor</SpecificName>
</Identity>
<Obstruction>
<Obstructions>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_ship_warship_arrow">
<Cost>
<BuildTime>40</BuildTime>
<BuildTime>24</BuildTime>
</Cost>
<Footprint>
<Square width="16.0" depth="32.0"/>
@@ -3,7 +3,7 @@
<Identity>
<Civ>brit</Civ>
<GenericName>Briton Countryman</GenericName>
<SpecificName>Brogiacos</SpecificName>
<SpecificName>Ambactos</SpecificName>
<Icon>units/celt/support_civilian.png</Icon>
</Identity>
<VisualActor>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_ship_warship_arrow">
<Cost>
<BuildTime>40</BuildTime>
<BuildTime>24</BuildTime>
</Cost>
<Footprint>
<Square width="16.0" depth="32.0"/>
@@ -8,7 +8,7 @@
<Identity>
<Civ>gaul</Civ>
<GenericName>Gallic Laborer</GenericName>
<SpecificName>Tegesacos</SpecificName>
<SpecificName>Ambactos</SpecificName>
<Icon>units/celt/support_civilian.png</Icon>
</Identity>
<VisualActor>
@@ -3,7 +3,8 @@
<Identity>
<Civ>germ</Civ>
<SelectionGroupName>units/germ/cavalry_javelineer_b</SelectionGroupName>
<SpecificName>Tigurinian Light Cavalry</SpecificName>
<GenericName>Tigurinian Light Cavalry</GenericName>
<SpecificName>Skeutazridjô</SpecificName>
<Icon>units/germ/cavalry_javelineer.png</Icon>
</Identity>
<Promotion>
@@ -3,6 +3,7 @@
<Identity>
<Civ>germ</Civ>
<GenericName>Cimbrian Spear Cavalry</GenericName>
<SpecificName>Gaizazridjô</SpecificName>
<SelectionGroupName>units/germ/cavalry_spearman_b</SelectionGroupName>
<Icon>units/germ/cavalry_spearman.png</Icon>
<Requirements>
@@ -2,7 +2,8 @@
<Entity parent="spec_champ|template_unit_champion_cavalry_swordsman">
<Identity>
<Civ>germ</Civ>
<SpecificName>Cimbrian Noble Cavalry</SpecificName>
<GenericName>Cimbrian Noble Cavalry</GenericName>
<SpecificName>Aþalazridjô</SpecificName>
<SelectionGroupName>units/germ/champion_cavalry</SelectionGroupName>
<Icon>units/germ/champion_cavalry.png</Icon>
<Requirements>
@@ -9,7 +9,8 @@
</Cost>
<Identity>
<Civ>germ</Civ>
<GenericName>Cimbrian Clubman Raider</GenericName>
<GenericName>Cimbrian Clubman</GenericName>
<SpecificName>Kulbawigô</SpecificName>
<VisibleClasses datatype="tokens">Club</VisibleClasses>
<Requirements>
<Techs datatype="tokens">phase_village</Techs>
@@ -3,6 +3,7 @@
<Identity>
<Civ>germ</Civ>
<GenericName>Ambronian Skirmisher</GenericName>
<SpecificName>Gaizawerpanaz</SpecificName>
<SelectionGroupName>units/germ/infantry_javelineer_b</SelectionGroupName>
<Icon>units/germ/infantry_javelineer.png</Icon>
<Requirements>
@@ -3,7 +3,8 @@
<Identity>
<Civ>germ</Civ>
<SelectionGroupName>units/germ/infantry_slinger_b</SelectionGroupName>
<SpecificName>Celto-German Slinger</SpecificName>
<GenericName>Celto-Germanic Slinger</GenericName>
<SpecificName>Slingwanaz</SpecificName>
<Icon>units/germ/infantry_slinger.png</Icon>
</Identity>
<Promotion>
@@ -3,7 +3,8 @@
<Identity>
<Civ>germ</Civ>
<SelectionGroupName>units/germ/infantry_spearman_b</SelectionGroupName>
<SpecificName>Cimbrian Spearman</SpecificName>
<GenericName>Cimbrian Spearman</GenericName>
<SpecificName>Gaizamannaz</SpecificName>
<VisibleClasses datatype="tokens">Guerilla</VisibleClasses>
<Icon>units/germ/infantry_spearman.png</Icon>
</Identity>
@@ -2,7 +2,8 @@
<Entity parent="template_unit_infantry_melee_swordsman">
<Identity>
<Civ>germ</Civ>
<SpecificName>Teutonic Swordsman</SpecificName>
<GenericName>Teutonic Swordsman</GenericName>
<SpecificName>Swerdamannaz</SpecificName>
<SelectionGroupName>units/germ/infantry_swordsman_b</SelectionGroupName>
<Requirements>
<Techs datatype="tokens">phase_town</Techs>
@@ -6,8 +6,8 @@
</Footprint>
<Identity>
<Civ>germ</Civ>
<SpecificName>Kriegsschiff</SpecificName>
<Icon>units/germ/ship_arrow.png</Icon>
<SpecificName>Harjaskipą</SpecificName>
</Identity>
<VisualActor>
<Actor>structures/germans/ship_arrow.xml</Actor>
@@ -2,7 +2,8 @@
<Entity parent="template_unit_ship_fire">
<Identity>
<Civ>germ</Civ>
<SpecificName>German Fire Ship</SpecificName>
<GenericName>Germanic Fire Ship</GenericName>
<SpecificName>Brandabaitaz</SpecificName>
<Icon>units/iber/ship_fire.png</Icon>
</Identity>
<VisualActor>
@@ -6,7 +6,8 @@
</Footprint>
<Identity>
<Civ>germ</Civ>
<SpecificName>German Fisherman</SpecificName>
<GenericName>Germanic Fisherman</GenericName>
<SpecificName>Fiskārijaz</SpecificName>
<Icon>units/germ/ship_fishing.png</Icon>
</Identity>
<VisualActor>
@@ -6,7 +6,8 @@
</Footprint>
<Identity>
<Civ>germ</Civ>
<SpecificName>Rhineland Merchantman</SpecificName>
<GenericName>Rhineland Merchantman</GenericName>
<SpecificName>Mangārī</SpecificName>
<Icon>units/germ/ship_merchant.png</Icon>
</Identity>
<VisualActor>
@@ -6,7 +6,7 @@
</Footprint>
<Identity>
<Civ>germ</Civ>
<SpecificName>Skipa</SpecificName>
<SpecificName>Skeutabaitaz</SpecificName>
<Icon>units/germ/ship_scout.png</Icon>
</Identity>
<VisualActor>
@@ -39,6 +39,7 @@
<Identity>
<Civ>germ</Civ>
<GenericName>Log Ram</GenericName>
<SpecificName>Rammabagmaz</SpecificName>
<Icon>units/germ/siege_ram.png</Icon>
<Requirements>
<Techs datatype="tokens">
@@ -2,7 +2,8 @@
<Entity parent="template_unit_support_civilian">
<Identity>
<Civ>germ</Civ>
<SpecificName>German Worker</SpecificName>
<GenericName>Germanic Worker</GenericName>
<SpecificName>Būraz</SpecificName>
<Icon>units/celt/support_civilian.png</Icon>
<SelectionGroupName>units/{civ}/support_civilian</SelectionGroupName>
</Identity>
@@ -3,7 +3,8 @@
<Identity>
<Civ>germ</Civ>
<SelectionGroupName>units/germ/support_healer_b</SelectionGroupName>
<SpecificName>German Priest</SpecificName>
<GenericName>Germanic Priest</GenericName>
<SpecificName>Gudjô</SpecificName>
<Icon>units/germ/support_healer.png</Icon>
<Rank>Basic</Rank>
</Identity>
@@ -2,7 +2,8 @@
<Entity parent="template_unit_support_trader">
<Identity>
<Civ>germ</Civ>
<SpecificName>German Trader</SpecificName>
<GenericName>Germanic Trader</GenericName>
<SpecificName>Kaupô</SpecificName>
<Icon>units/celt/support_trader.png</Icon>
</Identity>
<VisualActor>
@@ -12,5 +12,6 @@
</Promotion>
<Identity>
<Civ>germ</Civ>
<SpecificName>Wagnaz</SpecificName>
</Identity>
</Entity>
@@ -56,7 +56,7 @@ ENV RUSTUP_HOME=/usr/local/rust
ENV CARGO_HOME=/usr/local/rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.76.0 -y
# Install cbindgen for building SpiderMonkey
RUN /usr/local/rust/bin/cargo install cbindgen
RUN /usr/local/rust/bin/cargo install --locked cbindgen@0.29.0
ENV PATH="${RUSTUP_HOME}/bin:${PATH}"
ENV SHELL=/bin/bash
+1 -15
View File
@@ -224,21 +224,6 @@ extern_lib_defs = {
externalincludedirs { "/usr/local/include" }
end
end,
link_settings = function()
if os.istarget("windows") or os.istarget("macosx") then
if os.istarget("windows") then
defines { 'BOOST_LIB_TOOLSET="vc143"' }
end
add_default_lib_paths("boost")
end
add_default_links({
-- The following are not strictly link dependencies on all systems, but
-- are included for compatibility with different versions of Boost
android_names = { "boost_filesystem-gcc-mt", "boost_system-gcc-mt" },
unix_names = { os.findlib("boost_filesystem-mt") and "boost_filesystem-mt" or "boost_filesystem", os.findlib("boost_system-mt") and "boost_system-mt" or "boost_system" },
osx_names = { "boost_filesystem", "boost_system" },
})
end,
},
comsuppw = {
link_settings = function()
@@ -734,6 +719,7 @@ extern_lib_defs = {
-- so we have to use wxwidgets' own config tool
pkgconfig.add_includes(nil, wx_config_path(), "--unicode=yes --cxxflags")
end
defines({ "wxNO_REQUIRE_LITERAL_MSGIDS" })
end,
link_settings = function()
if os.istarget("windows") then
+16 -4
View File
@@ -18,15 +18,15 @@
<p>
0 A.D. is a real-time strategy (RTS) game of ancient warfare.
It's a historically-based war/economy game that allows players to relive
or rewrite the history of thirteen ancient civilizations, each depicted
or rewrite the history of fifteen ancient civilizations, each depicted
at their peak of economic growth and military prowess.
</p>
<p>
The fourteen factions are: Three of the Hellenic States (Athens, Sparta and
The fifteen factions are: Three of the Hellenic States (Athens, Sparta and
Macedonia), two of the kingdoms of Alexander the Great's successors
(Seleucids and Ptolemaic Egyptians), two Celtic tribes (Britons and
Gauls), the Romans, the Persians, the Iberians, the Carthaginians, the Han, the
Mauryas and the Kushites.
Gauls), the Germans, the Romans, the Persians, the Iberians, the Carthaginians,
the Han, the Mauryas and the Kushites.
Each civilization is complete with substantially unique artwork,
technologies and civilization bonuses.
</p>
@@ -40,6 +40,17 @@
<url type="translate">https://gitea.wildfiregames.com/0ad/0ad/wiki/Localization</url>
<url type="donation">https://play0ad.com/community/donate/</url>
<releases>
<release version="0.28.0" date="2025-11-12">
<url type="details">https://wildfiregames.com/forum/topic/137892-release-28-branch/</url>
<description>
<p>Wildfire Games proudly announces the release of 0 A.D. 0.28.0: "Boiorix".</p>
<ul>
<li>A new faction: the German tribes.</li>
<li>Gendered Civilians replace Female Citizens.</li>
<li>In some places JavaScript-Modules can be used to write mods.</li>
</ul>
</description>
</release>
<release version="0.27.1" date="2025-07-13">
<url type="details">https://play0ad.com/patch-release-27-1-for-0-a-d/</url>
<description>
@@ -108,6 +119,7 @@
<keyword>Britons</keyword>
<keyword>Carthaginians</keyword>
<keyword>Gauls</keyword>
<keyword>Germans</keyword>
<keyword>Han</keyword>
<keyword>Iberians</keyword>
<keyword>Kushites</keyword>
+4 -1
View File
@@ -6,7 +6,7 @@ set -e
cd "$(dirname "$0")"
PV=28209
LIB_VERSION=${PV}+wfg3
LIB_VERSION=${PV}+wfg4
fetch()
{
@@ -64,6 +64,9 @@ rm -Rf nvtt-${PV}
patch -d nvtt-${PV} -p1 <patches/0001-Don-t-overspecify-flags.patch
patch -d nvtt-${PV} -p1 <patches/0002-Bump-cmake-min-version-to-3.10.patch
patch -d nvtt-${PV} -p1 <patches/0003-Use-execute_process-insted-of-exec_program.patch
patch -d nvtt-${PV} -p1 <patches/0004-Properly-detect-ppc64le-systems.patch
patch -d nvtt-${PV} -p1 <patches/0005-Fix-compiler-flags-on-ppc64le-systems.patch
patch -d nvtt-${PV} -p1 <patches/0006-Fix-altivec-include-on-ppc64le-systems.patch
# build
(
@@ -0,0 +1,17 @@
--- a/src/cmake/DetermineProcessor.cmake
+++ a/src/cmake/DetermineProcessor.cmake
@@ -15,6 +15,14 @@
SET(NV_SYSTEM_PROCESSOR "powerpc")
ENDIF(NV_SYSTEM_PROCESSOR STREQUAL "Power Macintosh")
+ IF(NV_SYSTEM_PROCESSOR STREQUAL "ppc64le")
+ SET(NV_SYSTEM_PROCESSOR "ppc64")
+ ENDIF(NV_SYSTEM_PROCESSOR STREQUAL "ppc64le")
+
+ IF(NV_SYSTEM_PROCESSOR STREQUAL "ppc64el")
+ SET(NV_SYSTEM_PROCESSOR "ppc64")
+ ENDIF(NV_SYSTEM_PROCESSOR STREQUAL "ppc64el")
+
# processor may have double quote in the name, and that needs to be removed
STRING(REGEX REPLACE "\"" "" NV_SYSTEM_PROCESSOR "${NV_SYSTEM_PROCESSOR}")
STRING(REGEX REPLACE "/" "_" NV_SYSTEM_PROCESSOR "${NV_SYSTEM_PROCESSOR}")
@@ -0,0 +1,14 @@
--- a/src/cmake/OptimalOptions.cmake
+++ b/src/cmake/OptimalOptions.cmake
@@ -31,6 +31,11 @@
ENDIF(NV_SYSTEM_PROCESSOR STREQUAL "powerpc")
+ IF(NV_SYSTEM_PROCESSOR STREQUAL "ppc64")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=power8 -maltivec -mabi=altivec -mpowerpc64 -mvsx")
+ ENDIF(NV_SYSTEM_PROCESSOR STREQUAL "ppc64")
+
+
# IF(DARWIN)
# SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk")
# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk")
@@ -0,0 +1,22 @@
--- a/src/src/nvtt/squish/simd_ve.h
+++ b/src/src/nvtt/squish/simd_ve.h
@@ -27,7 +27,7 @@
#ifndef SQUISH_SIMD_VE_H
#define SQUISH_SIMD_VE_H
-#ifndef __APPLE_ALTIVEC__
+#if !defined(__APPLE_ALTIVEC__) || defined(__powerpc64__)
#include <altivec.h>
#undef bool
#endif
--- a/src/src/nvmath/SimdVector_VE.h
+++ b/src/src/nvmath/SimdVector_VE.h
@@ -27,7 +27,7 @@
#ifndef NV_SIMD_VECTOR_VE_H
#define NV_SIMD_VECTOR_VE_H
-#ifndef __APPLE_ALTIVEC__
+#if !defined(__APPLE_ALTIVEC__) || defined(__powerpc64__)
#include <altivec.h>
#undef bool
#endif
+65 -7
View File
@@ -1,21 +1,23 @@
// vim: set filetype=cpp :
#include <cstring>
#include <cxxtest/Descriptions.h>
#include <cxxtest/ErrorPrinter.h>
#include <cxxtest/XmlPrinter.h>
#include <ps/DllLoader.h>
#include <cstring>
#include <iostream>
#include <ps/DllLoader.h>
#include <string>
void usage(const char* prog) {
const std::string help = std::string("Usage: ") + prog + R"( [options]
--libdir dir Where to find extra shared libraries, used for running tests in staging area
--format junit|simple simple: default, good for cli - junit: for use by CI
--output file File to write to, defaults to stdout
--help This message
--libdir dir Where to find extra shared libraries, used for running tests in staging area
--list List available test by suite
--output file File to write to, defaults to stdout
--suite suite Only run named suite
--test test Only run named test of given suite
)";
std::printf("%s\n", help.c_str());
}
@@ -23,6 +25,8 @@ void usage(const char* prog) {
int main(int argc, char **argv)
{
char* suite = nullptr;
char* test = nullptr;
bool xml = false;
std::ostream* output = &std::cout;
std::ofstream out;
@@ -60,7 +64,6 @@ int main(int argc, char **argv)
std::exit(1);
}
}
else if (std::strcmp(argv[i], "--output") == 0)
{
if (++i >= argc)
@@ -73,6 +76,36 @@ int main(int argc, char **argv)
out.open(argv[i]);
output = &out;
}
else if (std::strcmp(argv[i], "--list") == 0)
{
for (CxxTest::SuiteDescription *sd = CxxTest::RealWorldDescription().firstSuite(); sd; sd = sd->next())
{
std::printf("%s\n", sd->suiteName());
for (CxxTest::TestDescription *td = sd->firstTest(); td; td = td->next())
std::printf(" %s\n", td->testName());
}
std::exit(0);
}
else if (std::strcmp(argv[i], "--suite") == 0)
{
if (++i >= argc)
{
std::printf("Option suite requires an optarg\n\n");
usage(argv[0]);
std::exit(1);
}
suite = argv[i];
}
else if (std::strcmp(argv[i], "--test") == 0)
{
if (++i >= argc)
{
std::printf("Option test requires an optarg\n\n");
usage(argv[0]);
std::exit(1);
}
test = argv[i];
}
else if (std::strcmp(argv[i], "--help") == 0)
{
usage(argv[0]);
@@ -86,6 +119,31 @@ int main(int argc, char **argv)
}
}
if (test)
{
if (!suite)
{
std::printf("test needs a suite specified\n\n");
usage(argv[0]);
std::exit(1);
}
if (!CxxTest::leaveOnly(suite, test))
{
std::printf("Unknown test '%s' in suite '%s'\n\n", test, suite);
usage(argv[0]);
std::exit(1);
}
}
else if (suite)
{
if (!CxxTest::leaveOnly(suite))
{
std::printf("Unknown suite '%s'\n\n", suite);
usage(argv[0]);
std::exit(1);
}
}
if (xml)
return CxxTest::XmlPrinter(*output).run();
+6
View File
@@ -56,8 +56,14 @@ Status LoadHeightmapImageOs(const OsPath& filepath, std::vector<u16>& heightmap)
File file;
RETURN_STATUS_IF_ERR(file.Open(OsString(filepath), O_RDONLY));
#if OS_WIN
// sizeof(long) == 4 on Windows so we can't use lseek.
size_t fileSize = _lseeki64(file.Descriptor(), 0, SEEK_END);
_lseeki64(file.Descriptor(), 0, SEEK_SET);
#else
size_t fileSize = lseek(file.Descriptor(), 0, SEEK_END);
lseek(file.Descriptor(), 0, SEEK_SET);
#endif
std::shared_ptr<u8> fileData;
RETURN_STATUS_IF_ERR(AllocateAligned(fileData, fileSize, maxSectorSize));
+3 -3
View File
@@ -43,9 +43,9 @@
#include <algorithm>
#include <array>
#include <boost/filesystem.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <chrono>
#include <filesystem>
#include <iterator>
#include <set>
#include <sstream>
@@ -792,11 +792,11 @@ public:
*/
CTextureConverter::Settings GetConverterSettings(const CTexturePtr& texture)
{
boost::filesystem::path srcPath = texture->m_Properties.m_Path.string();
std::filesystem::path srcPath = texture->m_Properties.m_Path.string();
std::vector<CTextureConverter::SettingsFile*> files;
VfsPath p;
for (boost::filesystem::path::iterator it = srcPath.begin(); it != srcPath.end(); ++it)
for (std::filesystem::path::iterator it = srcPath.begin(); it != srcPath.end(); ++it)
{
VfsPath settingsPath = p / "textures.xml";
m_HotloadFiles[settingsPath].insert(texture);
+45 -2
View File
@@ -20,6 +20,49 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define PYROGENESIS_VERSION "0.28.0"
#define PYROGENESIS_VERSION_WORD 0,28,0,0
#ifndef INCLUDED_BUILDVERSION
#define INCLUDED_BUILDVERSION
/*
* The version of the game is built as MAJOR.MINOR.PATCH, where
* - MAJOR is 0
* - MINOR is incremented for each main release
* - PATCH is incremented whenever we release a bugfix patch release
*
* TODO: This does not respect semver.
*/
#define PS_VERSION_MAJOR 0
#define PS_VERSION_MINOR 28
#define PS_VERSION_PATCH 0
/*
* When a patch version is released, it should stay simulation-compatible with
* all the previous patch releases of the same main release. This allows players
* to keep replaying their games and playing online against other versions of the
* same main release.
*
* The "compatible patch version" is the earliest patch version with which the
* current version is compatible. It should ideally stay at 0 all the time.
* If the compatible patch version is bumped:
* - a new lobby room must be opened
* - the version of the public '0ad' mod must be bumped
* - incompatible replays and savegames will be rotated as new folders are created
*
* This does not describe compatibility with the modding API. Modders are advised
* to rely on the actual engine version.
*/
#define PS_SERIALIZATION_COMPATIBLE_PATCH 0
#define STR(ver) #ver
#define DOTCONCAT(v1, v2, v3) STR(v1) "." STR(v2) "." STR(v3)
// See definition of PS_VERSION_* for details
#define PS_VERSION DOTCONCAT(PS_VERSION_MAJOR, PS_VERSION_MINOR, PS_VERSION_PATCH)
// Used in Windows .rc file
#define PS_VERSION_WORD PS_VERSION_MAJOR,PS_VERSION_MINOR,PS_VERSION_PATCH,0
// See definition of PS_SERIALIZATION_COMPATIBLE_PATCH for details
#define PS_SERIALIZATION_VERSION DOTCONCAT(PS_VERSION_MAJOR, PS_VERSION_MINOR, PS_SERIALIZATION_COMPATIBLE_PATCH)
extern wchar_t build_version[];
#endif // INCLUDED_BUILDVERSION
+6 -10
View File
@@ -32,10 +32,10 @@
#include "lib/sysdep/filesystem.h"
#include "lib/sysdep/os.h"
#include <boost/filesystem.hpp>
#include <boost/version.hpp>
#include <cerrno>
#include <cstring>
#include <filesystem>
#include <memory>
#include <string>
@@ -217,9 +217,9 @@ Status RenameFile(const OsPath& path, const OsPath& newPath)
try
{
boost::filesystem::rename(boost::filesystem::path(path.string()), boost::filesystem::path(newPath.string()));
std::filesystem::rename(std::filesystem::path(path.string()), std::filesystem::path(newPath.string()));
}
catch (boost::filesystem::filesystem_error& err)
catch (std::filesystem::filesystem_error& err)
{
debug_printf("RenameFile: failed to rename %s to %s.\n%s\n", path.string8().c_str(), path.string8().c_str(), err.what());
return ERR::EXCEPTION;
@@ -237,15 +237,11 @@ Status CopyFile(const OsPath& path, const OsPath& newPath, bool override_if_exis
try
{
if(override_if_exists)
#if BOOST_VERSION >=107400
boost::filesystem::copy_file(boost::filesystem::path(path.string()), boost::filesystem::path(newPath.string()), boost::filesystem::copy_options::overwrite_existing);
#else
boost::filesystem::copy_file(boost::filesystem::path(path.string()), boost::filesystem::path(newPath.string()), boost::filesystem::copy_option::overwrite_if_exists);
#endif
std::filesystem::copy_file(std::filesystem::path(path.string()), std::filesystem::path(newPath.string()), std::filesystem::copy_options::overwrite_existing);
else
boost::filesystem::copy_file(boost::filesystem::path(path.string()), boost::filesystem::path(newPath.string()));
std::filesystem::copy_file(std::filesystem::path(path.string()), std::filesystem::path(newPath.string()));
}
catch(boost::filesystem::filesystem_error& err)
catch(std::filesystem::filesystem_error& err)
{
debug_printf("CopyFile: failed to copy %s to %s.\n%s\n", path.string8().c_str(), path.string8().c_str(), err.what());
return ERR::EXCEPTION;
+5
View File
@@ -51,7 +51,12 @@ Status Issue(aiocb& cb, [[maybe_unused]] size_t queueDepth)
else
#endif
{
#if OS_WIN
// sizeof(long) == 4 on Windows so we can't use lseek.
ENSURE(_lseeki64(cb.aio_fildes, cb.aio_offset, SEEK_SET) == cb.aio_offset);
#else
ENSURE(lseek(cb.aio_fildes, cb.aio_offset, SEEK_SET) == cb.aio_offset);
#endif
void* buf = (void*)cb.aio_buf; // cast from volatile void*
const ssize_t bytesTransferred = (cb.aio_lio_opcode == LIO_WRITE)? write(cb.aio_fildes, buf, cb.aio_nbytes) : read(cb.aio_fildes, buf, cb.aio_nbytes);
+5 -5
View File
@@ -9,8 +9,8 @@
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION PYROGENESIS_VERSION_WORD
PRODUCTVERSION PYROGENESIS_VERSION_WORD
FILEVERSION PS_VERSION_WORD
PRODUCTVERSION PS_VERSION_WORD
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS VER_DEBUG
FILEOS VOS_NT_WINDOWS32
@@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Wildfire Games"
VALUE "FileDescription", "Pyrogenesis engine"
VALUE "FileVersion", PYROGENESIS_VERSION
VALUE "FileVersion", PS_VERSION
VALUE "InternalName", "pyrogenesis.rc"
VALUE "LegalCopyright", "Copyright (C) 2024 Wildfire Games"
VALUE "LegalCopyright", "Copyright (C) 2025 Wildfire Games"
VALUE "OriginalFilename", "pyrogenesis.rc"
VALUE "ProductName", "Pyrogenesis"
VALUE "ProductVersion", PYROGENESIS_VERSION
VALUE "ProductVersion", PS_VERSION
END
END
BLOCK "VarFileInfo"
@@ -53,6 +53,6 @@ typedef unsigned int mode_t; // defined by MinGW but not VC
#define S_ISREG(m) (m & S_IFREG)
#include <corecrt_io.h> // read, write, lseek
#include <corecrt_io.h> // read, write
#endif // #ifndef INCLUDED_WFILESYSTEM
+1 -1
View File
@@ -130,7 +130,7 @@ XmppClient::XmppClient(const ScriptInterface* scriptInterface, const std::string
m_client->registerConnectionListener(this);
m_client->setPresence(gloox::Presence::Available, -1);
m_client->disco()->setVersion("Pyrogenesis", engine_version);
m_client->disco()->setVersion("Pyrogenesis", PS_SERIALIZATION_VERSION);
m_client->disco()->setIdentity("client", "bot");
m_client->setCompression(false);
+3 -1
View File
@@ -561,7 +561,9 @@ static void RunGameOrAtlas(const std::span<const char* const> argv)
if (args.Has("version"))
{
debug_printf("Pyrogenesis %s\n", engine_version);
debug_printf("Pyrogenesis %s\n", PS_VERSION);
if (std::strcmp(PS_VERSION, PS_SERIALIZATION_VERSION) != 0)
debug_printf("Compatible down to patch %s\n", PS_SERIALIZATION_VERSION);
return;
}
+1 -1
View File
@@ -44,7 +44,7 @@ Message CreateHandshake() {
handshake.m_Magic = PS_PROTOCOL_MAGIC;
handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION;
handshake.m_EngineVersion = engine_version;
handshake.m_EngineVersion = PS_SERIALIZATION_VERSION;
for (const Mod::ModData* mod : Mod::Instance().GetEnabledModsData())
{
@@ -128,7 +128,7 @@ void StartNetworkHost(const CStrW& playerName, const u16 serverPort, const CStr&
* TODO: it should be possible to implement SRP or something along those lines to completely protect from this,
* but the cost/benefit ratio is probably not worth it.
*/
CStr hashedPass = HashCryptographically(password, hostJID + password + engine_version);
CStr hashedPass = HashCryptographically(password, hostJID + password + PS_SERIALIZATION_VERSION);
g_NetServer->SetPassword(hashedPass);
g_NetClient->SetHostJID(hostJID);
g_NetClient->SetGamePassword(hashedPass);
@@ -176,7 +176,7 @@ void StartNetworkJoinLobby(const CStrW& playerName, const CStr& hostJID, const C
ENSURE(!g_NetServer);
ENSURE(!g_Game);
CStr hashedPass = HashCryptographically(password, hostJID + password + engine_version);
CStr hashedPass = HashCryptographically(password, hostJID + password + PS_SERIALIZATION_VERSION);
g_Game = new CGame(true);
g_NetClient = new CNetClient(g_Game);
g_NetClient->SetUserName(playerName);
+2 -2
View File
@@ -77,8 +77,8 @@ CLogger::CLogger(std::ostream& mainLog, std::ostream& interestingLog, const bool
m_InterestingLog{interestingLog},
m_UseDebugPrintf{useDebugPrintf}
{
m_MainLog << html_header0 << engine_version << ") Main log" << html_header1;
m_InterestingLog << html_header0 << engine_version << ") Main log (warnings and errors only)" << html_header1;
m_MainLog << html_header0 << PS_VERSION << ") Main log" << html_header1;
m_InterestingLog << html_header0 << PS_VERSION << ") Main log (warnings and errors only)" << html_header1;
}
CLogger::~CLogger()

Some files were not shown because too many files have changed in this diff Show More