1
0
forked from mirrors/0ad

Compare commits

...

50 Commits

Author SHA1 Message Date
phosit a56ffcfd25 Update appdata for next RC
(cherry picked from commit 45c3a03a2e)
Signed-off-by: phosit <phosit@autistici.org>
2026-02-04 20:16:52 +01:00
real_tabasco_sauce 72e0ace313 German balance emergency changes
-Seeresses "Soldier" class removed as they are support units.
-Seeresses given correct vision value.
-Seeresses are unaffected by healer discount.
-germans no longer access archery spread tech since they have no archers.

(cherry picked from commit 87ed9c8092)
Signed-off-by: phosit <phosit@autistici.org>
2026-02-04 20:16:52 +01:00
Atrik 7033b81ce6 Default hotkeys changes
Reassign 'Toggle mouse grab' to F3 to avoid conflicts with gameplay hotkeys

Unassign 'Show status bars' often toggled by mistake by new players and confused for a selection bug

Assign 'Bird eye view' to Shift+Tab

(cherry picked from commit 426693ebef)
Signed-off-by: phosit <phosit@autistici.org>
2026-02-04 20:16:52 +01:00
phosit 30b741f8ba Update appdata for next RC
(cherry picked from commit 72591b7608)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-29 21:56:19 +01:00
Ralph Sennhauser 2da2c3394f Cleanly fail autostart for invalid map type
As for any invalid argument reject them and cleanly exit with failure
status.

Fixes: #7687
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit 958e6de9d3)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-29 21:56:19 +01:00
Ralph Sennhauser f578a5b34d Readd JS API function Engine.Exit()
Requested in #8244 for scripting purposes and automated testing. Extend
the original design by adding a means to pass an exit status. This also
comes in handy in case one wants to cleanly error out from JS on parsing
errors of command line arguments as reported in #7967.

Fixes: #8244
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit 0d60bdfd2e)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-29 21:56:19 +01:00
Vantha 8fee4dbb76 Temporary workaround for font baseline issue
Quick temporary fix for #8505 for the release of R28.

(cherry picked from commit 2483e7172b)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-29 21:56:19 +01:00
Vantha baa18fd57d Temporary workaround for icon misalignment
Quick temporary fix for #8194 for the release of R28.

(cherry picked from commit 7fd788af0f)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-29 21:56:19 +01:00
Atrik 231750edf1 Fix errors if promoted units change attack range
While in combat, if units are promoted and the promotion results
in a change in their attack range, this could trigger some errors
as 'this.template[type]' had a chance to be undefined when performing
a 'RepeatRangeCheck'.

Fixes #8670

(cherry picked from commit 68e625ab7a)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-29 21:56:18 +01:00
Ralph Sennhauser 0d1cdc0eaa Workaround renamed property in gamereport
The gendered citizen feature changed stat counter names in
3592814aa8 which are submitted to echelon
for rated games with the game report, the change in name for the property
means it no longer matches the database column name effectively breaking
rated games.

Translate the property name on the fly.

Fixes: #8687
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit 0691e7f0ff)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-29 21:56:18 +01:00
phosit 63d4513ebf Serialize canPlay property in Petra
This was forgotten in 7b1d4426aa.

Fixes: #8674
(cherry picked from commit a6357322e9)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-22 20:43:57 +01:00
Dunedan a1cb3055d9 Fix string extraction of new game settings
5741f77c6e and b5256ce014 added new translatable strings for game
settings, but missed adding them to
binaries/data/mods/public/l10n/messages.json to get them properly
extracted into the PO-templates for translation. This commit fixes that.

(cherry picked from commit f4c52e49a7)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-15 18:06:48 +01:00
Dunedan 7fd034a2c0 Fix translatable strings in XML files
Some translatable strings in XML files have leading and trailing line
breaks and tabs. As these characters are significant in text in XML
files, they don't belong there.

Refs: #8649
(cherry picked from commit 8f8d1195c2)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-14 20:59:47 +01:00
phosit 0f21853bd8 Update appdata for next RC
(cherry picked from commit b77ee3c5dc)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-05 21:09:03 +01:00
phosit b7fe462045 Revert "Add myself to the community credits (for packaging work)"
This reverts commit 7f0486e18e.
2026-01-01 17:33:45 +01:00
phosit bf0034f694 Close register-page before opening login-page
The `onTick` of the register-page was still running when connecting to
the lobby. This lead to an error when the `connect` message was
received.
With this commit returning from the login-page will always return to the
entrance-page. Previously it returned to the register-page when it was
opened by through that page.

(cherry picked from commit 0b83e24065)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:46 +01:00
Olivier Tilloy b228b611de Add myself to the community credits (for packaging work)
(cherry picked from commit 7f0486e18e)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:46 +01:00
Olivier Tilloy 72b56d9fe5 Spidermonkey build: do not unpack unneeded test files
This change reduces the disk space requirement by 50%, from 1.1 GB down to 564 MB.
It is relevant when building 0AD in resource-constrained environments (e.g. in CI).

(cherry picked from commit 8bd0d0b84f)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:46 +01:00
Itms fb12d00c70 Build the Actor Editor during the nightly build
This is a regression of a fix in 7e481b73cd,
lost during the git migration. Refs #1819

(cherry picked from commit d1319179f8)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:46 +01:00
Vantha 1690efeb72 Complete the per-player pop cap implementation
The 'PopulationLimit' attribute of each player seems to have been
without effect for a long time, but this patch fixes it.

Fixes #7850

(cherry picked from commit 9b8ff77265)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:46 +01:00
Vantha 5c8cf9a470 Add fallback values for pop cap and pop cap type
Make InitGame.js responsible for providing proper (defined) values.

Refs #7850
Fixes #7695

(cherry picked from commit 3a73dffc1c)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:46 +01:00
Vantha d9ae2f8503 Remove inconsistent override in CDropdown.h
It was added in 670f1e5d42 and, while not illegal, was inconsistent with the
rest of the header file, which caused compiler warnings.
As a quick solution the override keyword is simply removed again.
In the long run, it would be good to still modernise the style of all files
in that directory (at once).

(cherry picked from commit 2e450f0f52)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
trompetin17 b71cd96d12 Fix exceeding input boundaries in console
After 734386ce9f the new font system calculate height and cap height,
previously was having some magic number. Now we are using cap height
divide 2 to give a more nice space.

Remove an extra pixel in the buffer and improves background color for
better reading and eye care.

This also support the change console font option added in d549cbeeaa

Fixes: #8351
(cherry picked from commit 8e820a988e)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
Vladislav Belov d93722a023 Fixes ProfilerViewer when drawing empty cells
Currently CalculateStringSize can't handle empty string (see #8630).
As a simple fix for RC just avoid drawing empty texts.

Refs: #8630
(cherry picked from commit df9c6f510c)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
Itms 7d2647d59a Fix NSIS auto-uninstall
The NSIS script incorrectly passes the default installation dir as
argument for the auto-uninstaller of previous installs.

This is supposed to avoid moving the uninstaller to a temp file, but it
is unclear why that was done, as this leaves the uninstaller behind.

More importantly, now that we have changed the default installation
directory, the auto-uninstall tries to remove the previous install from
the new location, which does nothing and leaves behind several GB on the
disk.

(cherry picked from commit 771bf0ba08)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
Vladislav Belov 1dff943455 Fixes TerrainTextureManager after refactoring
In fb98f5059a the manager was refactored
and the order of deinitialization was incorrectly changed.

(cherry picked from commit cea77c497c)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
real_tabasco_sauce ce7a180e73 update scenario map to account for changed template name for clubman
(cherry picked from commit 621b4f96cc)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
real_tabasco_sauce ca1ad508a4 mixed improvements to germans
-Make clubmen champion macemen and remove buiding ability to ensure they are not mistaken for CS units.
-Decrease obstruction size of houses (clunky to place in staff match)
-Encampents only allowed in own/neutral territory
-'fear' icon used for Lugius vision aura instead of movement speed.
- Make covered wagons unable to research house techs and train civilians.

(cherry picked from commit ec19e5d663)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
Vladislav Belov 6d531e0303 Fixes uninitialized GPUSkinning in Atlas
Currently CRenderingOptions are initialized only once on the application
start. It means changed m_GPUSkinning wasn't reset on the switch to Atlas.

Fixes #8596

(cherry picked from commit f43e98da09)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
phosit e6e5d61b22 Allow swapped in pages to close themselves
This wasn't possible because init functions are called inside each
other and the outer one overwrites the result of the inner one.
Now the outer result doesn't overwrite the inner result but stores it to
the pointed to location.

(cherry picked from commit e62eb96092)
Signed-off-by: phosit <phosit@autistici.org>
2026-01-01 16:08:45 +01:00
Vantha 7386a5d514 Improve Engine.GetTextSize deprecation message
(cherry picked from commit 4d08446285)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-23 20:18:16 +01:00
Vantha 4140858066 Fix warnings on the charts tab of summary screen
Engine.GetTextWidth has been deprecated since e845da025a

Idea:
If you look at a dropdown as just a text field (its header) that can
change caption like any other, then getPreferredHeaderTextSize is the
equivalent to getPreferredTextSize (present on buttons and text fields).

Fixes #8493

(cherry picked from commit 670f1e5d42)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-23 20:18:16 +01:00
Vantha cc56bafc66 Fix oversight in 83f4d8789b
(cherry picked from commit fbb6052c30)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-23 20:18:16 +01:00
phosit 10408b46c2 Propagate error from autostart
The JavaScript error wasn't propagated leading to an infinite loop.

Fixes: #7967
(cherry picked from commit 14a5ccee52)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-23 20:18:16 +01:00
Itms e2764dcee1 Do not use Jenkins custom SVN client on Windows
It is extremely prone to timeouts and failures in this environment.

(cherry picked from commit ac36758b21)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-14 10:37:17 +01:00
phosit 5c333770ee Increase home island size on River Archipelago
With some settings mines weren't able to be placed.
Refs: #8579

(cherry picked from commit c02764e17a)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-14 10:37:17 +01:00
real_tabasco_sauce 3cba40b5c8 buff new carthage unique mercenary slinger with increased crush damage and greater accuracy.
(cherry picked from commit e96d981319)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-06 20:46:21 +01:00
cube002 2b85f5abf6 Fix carthage stone bonus
Add a civ restriction to make the bonus only apply to Carthage.

(cherry picked from commit 8d38ecda26)
(cherry picked from commit a03b01c935)
(cherry picked from commit f30271e955)
(cherry picked from commit 9c836d39e6)
(cherry picked from commit 91baeeb94e)
(cherry picked from commit cb3fecfce9)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-06 20:37:01 +01:00
phosit a6403f27d5 Update appdata for the next RC
(cherry picked from commit 759406dd77)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-03 18:15:06 +01:00
Ralph Sennhauser d90f4400ed Fix autostart-host
Commit b90280855f added support for
multiplayer saved games changing the signature of StartNetworkHost
without updating all callers.

Fixes: #7684
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit 31a262ff7e)
Signed-off-by: phosit <phosit@autistici.org>
2025-12-03 18:15:05 +01:00
Dunedan 7575a04305 Add Vietnamese as supported language
As 0 A.D. supports full unicode now and Vietnamese language coverage is
at a good level, let's include Vietnamese as supported language.

(cherry picked from commit 0086f005d4)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-30 14:24:26 +01:00
Dunedan 3e8f296c72 Re-add Catalan as supported language
While Catalan got removed for Alpha 27 because of low coverage, its
coverage is now good enough again to get re-added as supported language.

(cherry picked from commit ed1bd1d75b)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-30 14:24:26 +01:00
real_tabasco_sauce 1087e020d1 Add capture animations for citizens
Fixes #8557

(cherry picked from commit a32a28a5e3)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-30 14:24:26 +01:00
Vantha e961288e89 Correct some settings of the Germans' sandbox map
(cherry picked from commit 36e93989d4)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-30 14:24:26 +01:00
phosit 7ec2d3f0e0 Throw error when simulation script can't be loaded
When a script in "simulation/helpers/" contained an error. Files in
"simulation/components" aren't loaded. The return value of
`LoadDefaultScripts` indicated an error but was ignored. The simulation
still tried to start.

Now instead of returning a ignoreable error code the error is thrown. In
the common path the error is implicitly rethrown to the JS-function
which tried to start the game.

fixes: #8133
(cherry picked from commit 9a526bcae1)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-24 20:20:17 +01:00
phosit 97eca26d58 Don't pass the AppHooks as pointer
It's not permitted to pass a nullptr to the `app_hooks_update`. So a
reference should be used.

CppCheck says one shouldn't take pointer to a temporary.

(cherry picked from commit 977bf5c0d1)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-24 20:20:17 +01:00
phosit 2e4caf5d19 Use designatet initializers for AppHooks
CppCheck wasn't able to handle `{0}`. C++20 allows to use designated
initializers.

(cherry picked from commit b17c2fb80f)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-24 20:20:17 +01:00
Vantha 490434948d Remove some invalid entries from messages.json
'StatusName', 'ApplierTooltip' and 'ReceiverTooltip' are attributes of status
effects, which are defined in JSON files (and already extracted
correctly from there), not XMLs.

(cherry picked from commit 44984699f1)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-19 20:28:48 +01:00
Vantha 6a55830f1f Add context and comment attributes where useful
Add context and comment attributes to all translated XML elements in the
simulation that can specify any string -- unlike "Rank", which has to be
"Basic", "Advanced", or "Elite".
Most of them aren't used right now, but they can be in the
future and by mods, without touching the schemas again.

Fixes #8540

(cherry picked from commit 7032293207)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-19 20:28:48 +01:00
Ralph Sennhauser bf314cbb4c Add Atlas support to Appimage
Include the shared library libAtlasUI.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
(cherry picked from commit 5609492731)
Signed-off-by: phosit <phosit@autistici.org>
2025-11-19 20:28:48 +01:00
95 changed files with 448 additions and 216 deletions
+3 -3
View File
@@ -216,7 +216,7 @@ togglefullscreen = "Alt+Return" ; Toggle fullscreen/windowed mode
screenshot.watermark = "Alt+K" ; Toggle product/company watermark for official screenshots
wireframe = "Alt+Shift+W" ; Toggle wireframe mode
silhouettes = "Alt+Shift+S" ; Toggle unit silhouettes
mousegrabtoggle = "Ctrl+Alt" ; Toggle mouse grabbing mode
mousegrabtoggle = F3 ; Toggle mouse grabbing mode
; > DIALOG HOTKEYS
summary = "Ctrl+Tab" ; Toggle in-game summary
@@ -252,7 +252,7 @@ reset = "R" ; Reset camera rotation to default
follow = "" ; Follow the first unit in the selection
rallypointfocus = "" ; Focus the camera on the rally point of the selected building
lastattackfocus = "Space" ; Focus the camera on the last notified attack
togglebirdseyeview = "" ; Toggle bird's eye view
togglebirdseyeview = "Shift+Tab" ; Toggle bird's eye view
zoom.in = Plus, NumPlus ; Zoom camera in (continuous control)
zoom.out = Minus, NumMinus ; Zoom camera out (continuous control)
zoom.wheel.in = WheelUp ; Zoom camera in (stepped control)
@@ -392,7 +392,7 @@ flareactivate = "" ; Modifier to activate the mode to send a flare to
calltoarms = "" ; Modifier to call the selected units to the arms.
focusfire = "F" ; Modifier to control exclusively a building's arrows if it can attack
; Overlays
showstatusbars = Tab ; Toggle display of status bars
showstatusbars = "" ; Toggle display of status bars
devcommands.toggle = "Alt+D" ; Toggle developer commands panel
highlightguarding = PageDown ; Toggle highlight of guarding units
highlightguarded = PageUp ; Toggle highlight of guarded units
@@ -32,6 +32,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -32,6 +32,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -48,6 +48,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -48,6 +48,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/attack_capture.xml"/>
@@ -32,6 +32,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -68,6 +68,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/attack_capture.xml"/>
@@ -63,6 +63,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -48,6 +48,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -73,6 +73,7 @@
</group>
<group>
<variant name="Idle" frequency="1"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -75,6 +75,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/attack_capture.xml"/>
@@ -36,6 +36,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -36,6 +36,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/attack_capture.xml"/>
@@ -32,6 +32,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -17,6 +17,7 @@
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -54,6 +54,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -58,6 +58,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -139,6 +139,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -79,6 +79,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -51,6 +51,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -97,6 +97,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/attack_capture.xml"/>
@@ -54,6 +54,7 @@
</group>
<group>
<variant name="Idle" frequency="1"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -77,6 +77,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -35,6 +35,7 @@
<group>
<!-- In this group, define overloads for other animation types, since they presumably do not collide with each other -->
<variant name="Idle" frequency="1"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -32,6 +32,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -40,6 +40,7 @@
<group>
<!-- In this group, define overloads for other animation types, since they presumably do not collide with each other -->
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -32,6 +32,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -45,6 +45,7 @@
<group>
<!-- In this group, define overloads for other animation types, since they presumably do not collide with each other -->
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -75,6 +75,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/attack_capture.xml"/>
@@ -78,6 +78,7 @@
<group>
<!-- In this group, define overloads for other animation types, since they presumably do not collide with each other -->
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/female_death.xml"/>
@@ -48,6 +48,7 @@
</group>
<group>
<variant frequency="1" name="Idle"/>
<variant file="biped/attack_capture.xml"/>
<variant file="biped/attack_melee_female.xml"/>
<variant file="biped/attack_slaughter.xml"/>
<variant file="biped/gather_tree.xml"/>
@@ -14,7 +14,7 @@ class AutoStartHost
const port = +(cmdLineArgs['autostart-port'] ?? 5073);
// Password not implemented for autostart.
Engine.StartNetworkHost(playerName, port, "", !('autostart-disable-replay' in cmdLineArgs));
Engine.StartNetworkHost(playerName, port, "", false, !('autostart-disable-replay' in cmdLineArgs));
}
catch (e)
{
@@ -66,11 +66,20 @@ function parseCmdLineArgs(settings, cmdLineArgs)
{
// eslint-disable-next-line dot-notation
const mapType = cmdLineArgs['autostart'].substring(0, cmdLineArgs['autostart'].indexOf('/'));
settings.map.setType({
"scenarios": "scenario",
"random": "random",
"skirmishes": "skirmish",
}[mapType]);
switch (mapType)
{
case "random":
settings.map.setType("random");
break;
case "scenarios":
settings.map.setType("scenario");
break;
case "skirmishes":
settings.map.setType("skirmish");
break;
default:
throw new Error(`Unknown map type ${mapType}`);
}
// eslint-disable-next-line dot-notation
settings.map.selectMap("maps/" + cmdLineArgs['autostart']);
@@ -8,7 +8,5 @@
<translatableAttribute id="caption">Saved game</translatableAttribute>
<translatableAttribute id="tooltip">
The controller loaded a saved game.
</translatableAttribute>
<translatableAttribute id="tooltip">The controller loaded a saved game.</translatableAttribute>
</object>
@@ -42,4 +42,6 @@ async function cancelButton()
await new Promise(resolve => { Engine.GetGUIObjectByName("cancel").onPress = resolve; });
if (Engine.HasXmppClient())
Engine.StopXmppClient();
return false;
}
@@ -13,7 +13,8 @@ function loginButton()
Engine.OpenChildPage("page_prelobby_login.xml");
}
function registerButton()
async function registerButton()
{
Engine.OpenChildPage("page_prelobby_register.xml");
if (await Engine.OpenChildPage("page_prelobby_register.xml"))
Engine.OpenChildPage("page_prelobby_login.xml");
}
@@ -40,6 +40,5 @@ async function onRegistered()
setFeedback(translate("Registered"));
Engine.StopXmppClient();
Engine.OpenChildPage("page_prelobby_login.xml");
return true;
}
@@ -1,7 +1,8 @@
/**
* Override style so we can get a bigger primary name.
*/
g_TooltipTextFormats.namePrimaryBig.font = "sans-bold-20";
// Temporarily overwritten in order to hide a baseline issue in the font engine.
g_TooltipTextFormats.namePrimaryBig.font = /* "sans-bold-20" */ "sans-bold-16";
g_TooltipTextFormats.namePrimarySmall.font = "sans-bold-16";
g_TooltipTextFormats.nameSecondary.font = "sans-bold-16";
@@ -23,25 +23,19 @@
<object>
<object name="icon1" type="image" sprite="stretched:pregame/icons/experimental.png"/>
<object name="text1" type="text" textcolor="white" font="sans-16">
<translatableAttribute id="caption">
This game is still in development. You may encounter bugs, and some features are not as fleshed out as we would like.
</translatableAttribute>
<translatableAttribute id="caption">This game is still in development. You may encounter bugs, and some features are not as fleshed out as we would like.</translatableAttribute>
</object>
</object>
<object>
<object name="icon2" type="image" sprite="stretched:pregame/icons/lag.png"/>
<object name="text2" type="text" textcolor="white" font="sans-16">
<translatableAttribute id="caption">
The game can have performance problems, especially with large maps and a great number of units.
</translatableAttribute>
<translatableAttribute id="caption">The game can have performance problems, especially with large maps and a great number of units.</translatableAttribute>
</object>
</object>
<object>
<object name="icon3" type="image" sprite="stretched:pregame/icons/map.png"/>
<object name="text3" type="text" textcolor="white" font="sans-16">
<translatableAttribute id="caption">
0 A.D. is Free Software: you can participate in its development. If you want to help with art, sound, gameplay or programming, make sure to join our official forum.
</translatableAttribute>
<translatableAttribute id="caption">0 A.D. is Free Software: you can participate in its development. If you want to help with art, sound, gameplay or programming, make sure to join our official forum.</translatableAttribute>
</object>
</object>
</object>
@@ -265,8 +265,8 @@ function initGUICharts()
function resizeDropdown(dropdown)
{
dropdown.size.bottom = dropdown.size.top +
(Engine.GetTextWidth(dropdown.font, dropdown.list[dropdown.selected]) >
dropdown.size.right - dropdown.size.left - 28 &&
(dropdown.getPreferredHeaderTextSize().width >
dropdown.size.right - dropdown.size.left - dropdown.button_width &&
dropdown.list[dropdown.selected].indexOf(" ") !== -1 ? 42 : 28);
}
+26 -18
View File
@@ -480,15 +480,6 @@
"AttackName": {
"customContext": "Name of an attack, usually the weapon."
},
"StatusName": {
"customContext": "status effect"
},
"ApplierTooltip": {
"customContext": "status effect"
},
"ReceiverTooltip": {
"customContext": "status effect"
},
"GenericName": {},
"SpecificName": {},
"History": {},
@@ -523,15 +514,6 @@
"AttackName": {
"customContext": "Name of an attack, usually the weapon."
},
"StatusName": {
"customContext": "status effect"
},
"ApplierTooltip": {
"customContext": "status effect"
},
"ReceiverTooltip": {
"customContext": "status effect"
},
"GenericName": {},
"SpecificName": {},
"History": {},
@@ -774,6 +756,32 @@
}
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/settings/player_placements.json"
],
"options": {
"keywords": {
"Name": {},
"Description": {}
}
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/settings/population_capacities.json"
],
"options": {
"keywords": {
"Title": {},
"Tooltip": {},
"CapTitle": {},
"CapTooltip": {}
}
}
},
{
"extractor": "json",
"filemasks": [
@@ -136,7 +136,7 @@ export function* generateMap(mapSettings)
const playerIDs = randBool() ? sortAllPlayers() : primeSortAllPlayers();
g_Map.log("Ensuring player territory");
const playerRadius = scaleByMapSize(12, 20);
const playerRadius = scaleByMapSize(15, 20);
for (let i = 0; i < numPlayers; ++i)
createArea(
new ChainPlacer(1, 6, 40, 1, playerPosition[i], 0, [Math.floor(playerRadius)]),
@@ -47,18 +47,16 @@
"PlayerData": [
null,
{
"Civ": "germ",
"Color": {
"b": 0,
"g": 92,
"r": 183
}
},
{}
}
],
"Preview": "sandbox-thegermans.png",
"VictoryConditions": [
"conquest"
]
"VictoryConditions": []
}
]]></ScriptSettings>
<Entities>
@@ -20458,98 +20456,98 @@
<Actor seed="23588"/>
</Entity>
<Entity uid="3473">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="332.12186" z="451.66132"/>
<Orientation y="-2.40531"/>
<Actor seed="43656"/>
</Entity>
<Entity uid="3474">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="330.28055" z="448.46393"/>
<Orientation y="-2.4396"/>
<Actor seed="22449"/>
</Entity>
<Entity uid="3475">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="327.54374" z="452.57486"/>
<Orientation y="2.35621"/>
<Actor seed="58505"/>
</Entity>
<Entity uid="3476">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="326.51185" z="448.19327"/>
<Orientation y="-2.08526"/>
<Actor seed="21275"/>
</Entity>
<Entity uid="3477">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="325.30298" z="451.8647"/>
<Orientation y="-2.21181"/>
<Actor seed="35836"/>
</Entity>
<Entity uid="3478">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="328.28318" z="446.60975"/>
<Orientation y="-2.25087"/>
<Actor seed="62149"/>
</Entity>
<Entity uid="3479">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="323.6949" z="443.73194"/>
<Orientation y="-2.2695"/>
<Actor seed="52899"/>
</Entity>
<Entity uid="3480">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="318.79917" z="444.40821"/>
<Orientation y="-2.38955"/>
<Actor seed="31384"/>
</Entity>
<Entity uid="3481">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="317.27378" z="439.22846"/>
<Orientation y="-2.40764"/>
<Actor seed="46504"/>
</Entity>
<Entity uid="3482">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="338.14426" z="456.2815"/>
<Orientation y="-2.43624"/>
<Actor seed="46566"/>
</Entity>
<Entity uid="3483">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="334.72394" z="458.05823"/>
<Orientation y="-2.39664"/>
<Actor seed="48744"/>
</Entity>
<Entity uid="3484">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="314.81849" z="440.92362"/>
<Orientation y="-2.31492"/>
<Actor seed="37975"/>
</Entity>
<Entity uid="3485">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="322.47095" z="438.82441"/>
<Orientation y="-2.41076"/>
<Actor seed="15798"/>
</Entity>
<Entity uid="3486">
<Template>units/germ/infantry_clubman</Template>
<Template>units/germ/champion_infantry_maceman</Template>
<Player>1</Player>
<Position x="334.34528" z="448.38428"/>
<Orientation y="-2.42885"/>
@@ -21560,4 +21558,4 @@
</Entity>
</Entities>
<Paths/>
</Scenario>
</Scenario>
@@ -9,9 +9,9 @@ export function aiWarn(output)
/**
* Useful for simulating consecutive AI matches.
*/
export function exit()
export function exit(exitStatus)
{
Engine.Exit();
Engine.Exit(exitStatus);
}
export function VectorDistance(a, b)
@@ -31,6 +31,7 @@ PetraBot.prototype.CustomInit = function(gameState)
if (this.isDeserialized)
{
// WARNING: the deserializations should not modify the metadatas infos inside their init functions
this.canPlay = this.data.canPlay;
this.turn = this.data.turn;
this.playedTurn = this.data.playedTurn;
this.elapsedTime = this.data.elapsedTime;
@@ -151,6 +152,7 @@ PetraBot.prototype.Serialize = function()
}
return {
"canPlay": this.canPlay,
"uniqueIDs": this.uniqueIDs,
"turn": this.turn,
"playedTurn": this.playedTurn,
@@ -105,12 +105,17 @@ Attack.prototype.Schema =
"<element>" +
"<anyName a:help='Currently one of Melee, Ranged, Capture or Slaughter.'/>" +
"<interleave>" +
"<element name='AttackName' a:help='Name of the attack, to be displayed in the GUI. Optionally includes a translate context attribute.'>" +
"<element name='AttackName' a:help='Name of the attack, to be displayed in the GUI.'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<text/>" +
"</element>" +
AttackHelper.BuildAttackEffectsSchema() +
@@ -444,7 +449,7 @@ Attack.prototype.GetSplashData = function(type)
Attack.prototype.GetRange = function(type)
{
if (!type)
if (!type || !this.template[type])
return this.GetFullAttackRange();
let max = +this.template[type].MaxRange;
@@ -44,6 +44,16 @@ BuildRestrictions.prototype.Schema =
"<element name='Distance' a:help='Specifies distance restrictions on this building, relative to buildings from the given category.'>" +
"<interleave>" +
"<element name='FromClass'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<text/>" +
"</element>" +
"<optional><element name='MinDistance'><data type='positiveInteger'/></element></optional>" +
@@ -9,6 +9,16 @@ Formation.prototype.Schema =
"</data>" +
"</element>" +
"<element name='DisabledTooltip' a:help='Tooltip shown when the formation is disabled.'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<text/>" +
"</element>" +
"<element name='SpeedMultiplier' a:help='The speed of the formation is determined by the minimum speed of all members, multiplied with this number.'>" +
@@ -25,10 +25,30 @@ Identity.prototype.Schema =
"</element>" +
"</optional>" +
"<element name='GenericName' a:help='Generic English-language name for this entity.'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<text/>" +
"</element>" +
"<optional>" +
"<element name='SpecificName' a:help='Specific native-language name for this entity.'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<text/>" +
"</element>" +
"</optional>" +
@@ -39,16 +59,46 @@ Identity.prototype.Schema =
"</optional>" +
"<optional>" +
"<element name='Tooltip'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<text/>" +
"</element>" +
"</optional>" +
"<optional>" +
"<element name='History'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<text/>" +
"</element>" +
"</optional>" +
"<optional>" +
"<element name='Rank'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<choice>" +
"<value>Basic</value>" +
"<value>Advanced</value>" +
@@ -66,6 +116,16 @@ Identity.prototype.Schema =
"</optional>" +
"<optional>" +
"<element name='VisibleClasses' a:help='Optional list of space-separated classes applying to this entity. These classes will also be visible in various GUI elements. Choices include: Academy, Amphitheater, Archer, ArmyCamp, ArrowShip, Arsenal, ArtilleryTower, Auxiliary, Axeman, Barracks, BoltShooter, BoltTower, Bribable, Builder, Camel, Cataphract, Cavalry, Centurion, Champion, Chariot, Citizen, City, Civilian, Civic, CivilCentre, Colony, Corral, Council, Crossbowman, Defensive, Dock, Dog, Economic, Elephant, ElephantStable, Embassy, Farmstead, Field, Fireship, FishingBoat, Forge, Fortress, Gate, Gladiator, GreatTower, Gymnasium, Hall, Healer, Heavy, Hero, House, IceHouse, Ignited, Immortal, ImperialCourt, ImperialMinistry, Infantry, Javelineer, Kennel, LaoziGate, Legionary, Library, Lighthouse, Longsword, Maceman, Melee, Market, Mercenary, Military, Minister, Monument, Naval, NavalRam, NavalSiege, Outpost, Palace, Palisade, Pikeman, Pillar, Pirate, Pyramid, Ram, Range, Ranged, Relic, Resource, RotaryMill, ScoutShip, SentryTower, Ship, Shipyard, Shrine, Siege, SiegeTower, SiegeWall, Slave, Slinger, Soldier, Spearman, Stable, Stoa, StoneThrower, StoneTower, Storehouse, Support, Swordsman, Syssiton, Temple, TempleOfAmun, TempleOfApedemak, TempleOfIsis, TempleOfMars, TempleOfVesta, Tent, Theater, Tower, Town, Trade, Trader, TriumphalArch, Trumpeter, Village, Wall, Warship, Wonder, Worker.'>" +
"<optional>" +
"<attribute name='context'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<optional>" +
"<attribute name='comment'>" +
"<text/>" +
"</attribute>" +
"</optional>" +
"<attribute name='datatype'>" +
"<value>tokens</value>" +
"</attribute>" +
@@ -17,13 +17,11 @@ PopulationCapManager.prototype.Init = function()
*/
PopulationCapManager.prototype.SetPopulationCapType = function(type)
{
if ([this.CAPTYPE_PLAYER_POPULATION, this.CAPTYPE_TEAM_POPULATION, this.CAPTYPE_WORLD_POPULATION].includes(type))
this.popCapType = type;
else
{
warn(`Attempted to set an unknown population capacity type: '${type}'. Continuing with type 'Player Population'...`);
this.popCapType = this.CAPTYPE_PLAYER_POPULATION;
}
if (![this.CAPTYPE_PLAYER_POPULATION, this.CAPTYPE_TEAM_POPULATION, this.CAPTYPE_WORLD_POPULATION].includes(type))
error("Invalid population cap type specified: " + type);
this.popCapType = type;
if (this.popCap)
this.InitializePopCaps();
};
@@ -48,6 +46,13 @@ PopulationCapManager.prototype.SetPopulationCap = function(cap)
this.InitializePopCaps();
};
PopulationCapManager.prototype.SetPerPlayerPopulationCaps = function(playerCaps)
{
this.perPlayerPopCaps = playerCaps;
this.popCapType = this.CAPTYPE_PLAYER_POPULATION;
this.InitializePopCaps();
};
/**
* Get the current pop cap.
* @returns {number}
@@ -86,10 +91,10 @@ PopulationCapManager.prototype.InitializePopCaps = function()
*/
PopulationCapManager.prototype.InitializePlayerPopCaps = function()
{
const players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetActivePlayers();
for (const player of players)
QueryPlayerIDInterface(player, IID_Player)
.SetMaxPopulation(this.popCap);
const players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNonGaiaPlayers();
for (const i in players)
QueryPlayerIDInterface(players[i], IID_Player)
.SetMaxPopulation(this.perPlayerPopCaps ? this.perPlayerPopCaps[i] : this.popCap);
};
/**
@@ -11,5 +11,5 @@
],
"auraName": "Terror Cimbricus",
"auraDescription": "Enemy Soldiers, Ships, Siege, and Structures -20 meters vision range.",
"overlayIcon": "art/textures/ui/session/auras/speed_bonus.png"
}
"overlayIcon": "art/textures/ui/session/auras/fear.png"
}
@@ -10,6 +10,7 @@
{ "tech": "phase_town" },
{ "notciv": "brit" },
{ "notciv": "gaul" },
{ "notciv": "germ" },
{ "notciv": "iber" },
{ "notciv": "rome" },
{ "notciv": "spart" }
@@ -4,7 +4,8 @@
"description": "Hire servants to help quarry stone. Increases stone gathering rates.",
"requirements": {
"all": [
{ "tech": "phase_village" }
{ "tech": "phase_village" },
{ "civ": "cart" }
]
},
"icon": "mining_stone_01.png",
@@ -4,7 +4,8 @@
"description": "Hire servants to help quarry stone. Increases stone gathering rates.",
"requirements": {
"all": [
{ "tech": "phase_town" }
{ "tech": "phase_town" },
{ "civ": "cart"}
]
},
"icon": "mining_stone_02.png",
@@ -4,7 +4,8 @@
"description": "Hire servants to help quarry stone. Increases stone gathering rates.",
"requirements": {
"all": [
{ "tech": "phase_city" }
{ "tech": "phase_city" },
{ "civ": "cart"}
]
},
"icon": "mining_stone_03.png",
@@ -15,6 +15,6 @@
{ "value": "Cost/Resources/metal", "replace": 0 },
{ "value": "Loot/metal", "replace": 0 }
],
"affects": ["Healer"],
"affects": ["Healer !Champion !Hero"],
"soundComplete": "interface/alarm/alarm_upgradearmory.xml"
}
@@ -64,9 +64,22 @@ function InitGame(settings)
Engine.QueryInterface(cmpPlayer.entity, IID_TechnologyManager)?.ResearchTechnology(Engine.QueryInterface(cmpPlayer.entity, IID_Diplomacy).template.SharedLosTech);
}
const cmpPopulationCapManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PopulationCapManager);
cmpPopulationCapManager.SetPopulationCapType(settings.PopulationCapType);
cmpPopulationCapManager.SetPopulationCap(settings.PopulationCap);
{
const popCap = settings.PopulationCap || 300;
const cmpPopulationCapManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PopulationCapManager);
const nonGaiaPlayers = settings.PlayerData.slice(1);
if (nonGaiaPlayers.some(player => player.PopulationLimit))
cmpPopulationCapManager.SetPerPlayerPopulationCaps(nonGaiaPlayers.map(player => player.PopulationLimit || popCap));
else
{
if ([cmpPopulationCapManager.CAPTYPE_PLAYER_POPULATION, cmpPopulationCapManager.CAPTYPE_TEAM_POPULATION,
cmpPopulationCapManager.CAPTYPE_WORLD_POPULATION].includes(settings.PopulationCapType))
cmpPopulationCapManager.SetPopulationCapType(settings.PopulationCapType);
else
cmpPopulationCapManager.SetPopulationCapType(cmpPopulationCapManager.CAPTYPE_PLAYER_POPULATION);
cmpPopulationCapManager.SetPopulationCap(popCap);
}
}
// Update the grid with all entities created for the map init.
Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder).UpdateGrid();
@@ -3,7 +3,7 @@
<Attack disable=""/>
<BuildingAI disable=""/>
<BuildRestrictions>
<Territory>own neutral enemy</Territory>
<Territory>own neutral</Territory>
<Category>Encampment</Category>
<Distance>
<FromClass>CivilCentre</FromClass>
@@ -12,7 +12,7 @@
<SpecificName>Hūsą</SpecificName>
</Identity>
<Obstruction>
<Static width="18.0" depth="18.0"/>
<Static width="16.0" depth="16.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/germans/house.xml</Actor>
@@ -25,7 +25,7 @@
</Health>
<Identity>
<GenericName>Champion Healer</GenericName>
<VisibleClasses datatype="tokens">Healer</VisibleClasses>
<VisibleClasses datatype="tokens">Healer -Soldier</VisibleClasses>
<Requirements>
<Techs datatype="tokens">phase_city</Techs>
</Requirements>
@@ -45,10 +45,13 @@
<Resistance>
<Entity>
<Damage>
<Hack>3</Hack>
<Pierce>3</Pierce>
<Hack>2</Hack>
<Pierce>4</Pierce>
<Crush>20</Crush>
</Damage>
</Entity>
</Resistance>
</Entity>
<Vision>
<Range>60</Range>
</Vision>
</Entity>
@@ -2,11 +2,15 @@
<Entity parent="merc_inf|template_unit_infantry_ranged_slinger">
<Attack>
<Ranged>
<Damage>
<Damage>
<Pierce op="mul">1.15</Pierce>
<Crush op="mul">1.15</Crush>
</Damage>
<MaxRange>50</MaxRange>
<RepeatTime>1750</RepeatTime>
<Projectile>
<Spread op="mul">0.85</Spread>
</Projectile>
</Ranged>
</Attack>
<Builder>
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_infantry_melee_maceman">
<Builder disable=""/>
<Cost>
<Resources>
<food>50</food>
@@ -11,7 +12,7 @@
<Civ>germ</Civ>
<GenericName>Cimbrian Clubman</GenericName>
<SpecificName>Kulbawigô</SpecificName>
<VisibleClasses datatype="tokens">Club</VisibleClasses>
<VisibleClasses datatype="tokens">Champion</VisibleClasses>
<Requirements>
<Techs datatype="tokens">phase_village</Techs>
</Requirements>
@@ -27,6 +28,14 @@
</Entity>
</Resistance>
<ResourceGatherer disable=""/>
<Selectable>
<Overlay>
<Texture>
<MainTexture>256x256/arrow.png</MainTexture>
<MainTextureMask>256x256/arrow_mask.png</MainTextureMask>
</Texture>
</Overlay>
</Selectable>
<UnitMotion>
<WalkSpeed op="mul">1.2</WalkSpeed>
</UnitMotion>
@@ -14,18 +14,6 @@
<Civ>germ</Civ>
<Icon>units/germ/support_wagon_covered.png</Icon>
</Identity>
<ProductionQueue/>
<Researcher>
<Technologies datatype="tokens">
health_females_01
unlock_females_house
</Technologies>
</Researcher>
<Trainer>
<Entities datatype="tokens">
units/{civ}/support_female_citizen_house
</Entities>
</Trainer>
<VisualActor>
<Actor>structures/germans/wagon_house.xml</Actor>
</VisualActor>
+10 -14
View File
@@ -203,11 +203,10 @@ pipeline {
}
}
steps {
checkout changelog: false, poll: false, scm: [
$class: 'SubversionSCM',
locations: [[local: '.', remote: "https://svn.wildfiregames.com/nightly-build/trunk@${NIGHTLY_REVISION}"]],
quietOperation: false,
workspaceUpdater: [$class: 'UpdateWithCleanUpdater']]
bat "svn co https://svn.wildfiregames.com/nightly-build/trunk@${NIGHTLY_REVISION} ."
bat 'svn revert -R .'
bat 'svn cleanup --remove-unversioned'
copyArtifacts projectName: '0ad-patch-release', selector: upstream()
bat "svn patch ${params.BUNDLE_VERSION}.patch"
@@ -225,8 +224,7 @@ pipeline {
}
post {
cleanup {
bat 'svn revert -R .'
bat 'svn cleanup --remove-unversioned'
bat 'svn cleanup'
}
}
}
@@ -255,11 +253,10 @@ pipeline {
HOSTTYPE = 'amd64'
}
steps {
checkout changelog: false, poll: false, scm: [
$class: 'SubversionSCM',
locations: [[local: '.', remote: "https://svn.wildfiregames.com/nightly-build/trunk@${NIGHTLY_REVISION}"]],
quietOperation: false,
workspaceUpdater: [$class: 'UpdateWithCleanUpdater']]
bat "svn co https://svn.wildfiregames.com/nightly-build/trunk@${NIGHTLY_REVISION} ."
bat 'svn revert -R .'
bat 'svn cleanup --remove-unversioned'
script {
if (params.PATCH_BUILD) {
copyArtifacts projectName: '0ad-patch-release', selector: upstream()
@@ -281,8 +278,7 @@ pipeline {
}
post {
cleanup {
bat 'svn revert -R .'
bat 'svn cleanup --remove-unversioned'
bat 'svn cleanup'
}
}
}
@@ -18,7 +18,7 @@
// This pipeline is used to generate the nightly builds.
def visualStudioPath = '"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe"'
def buildOptions = '/p:PlatformToolset=v143 /t:pyrogenesis /t:AtlasUI %JOBS% /nologo -clp:Warningsonly -clp:ErrorsOnly'
def buildOptions = '/p:PlatformToolset=v143 /t:pyrogenesis /t:AtlasUI /t:ActorEditor %JOBS% /nologo -clp:Warningsonly -clp:ErrorsOnly'
def gitHash = ''
def buildSPIRV = false
+3 -2
View File
@@ -40,14 +40,15 @@
<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>
<release version="0.28.0" date="2026-02-05">
<url type="details">https://play0ad.com/new-release-0-a-d-release-28-boiorix/</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>
<li>Font Rendering: CJK languages are bundled with the game, not as separate mods.</li>
</ul>
</description>
</release>
+8 -2
View File
@@ -9,7 +9,7 @@ cd "$(dirname "$0")"
PV=128.13.0
FOLDER="mozjs-${PV}"
# If same-version changes are needed, increment this.
LIB_VERSION="${PV}+wfg3"
LIB_VERSION="${PV}+wfg4"
LIB_NAME="mozjs128"
build_archive()
@@ -69,7 +69,13 @@ fi
# unpack
rm -Rf "${FOLDER}"
"${TAR}" xfJ "${FOLDER}.tar.xz"
"${TAR}" xfJ "${FOLDER}.tar.xz" \
--exclude=js/src/tests/non262 \
--exclude=js/src/tests/test262 \
--exclude=js/src/jit-test \
--exclude=python/mozperftest \
--exclude=testing/web-platform \
--exclude=third_party/rust/mp4parse/link-u-avif-sample-images
# patch
(
+1 -1
View File
@@ -56,7 +56,7 @@ void CFontMetrics::CalculateStringSize(const wchar_t* string, float& w, float& h
m_Font->CalculateStringSize(string, w, h);
}
float CFontMetrics::GetCapHeight()
float CFontMetrics::GetCapHeight() const
{
if (!m_Font)
return 0.0f;
+1 -1
View File
@@ -33,7 +33,7 @@ public:
CFontMetrics(CStrIntern font, CStrIntern locale);
float GetHeight() const;
float GetCapHeight();
float GetCapHeight() const;
float GetCharacterWidth(wchar_t c) const;
void CalculateStringSize(const wchar_t* string, float& w, float& h) const;
+1 -1
View File
@@ -68,8 +68,8 @@ CTerrainTextureManager::~CTerrainTextureManager()
void CTerrainTextureManager::UnloadTerrainTextures()
{
m_TerrainGroups.clear();
m_TextureEntries.clear();
m_TerrainGroups.clear();
m_LastGroupIndex = 0;
}
+6 -2
View File
@@ -256,11 +256,15 @@ void CGUIManager::SGUIPage::LoadPage(ScriptContext& scriptContext)
if (hotloadData)
Script::ReadStructuredClone(rq, hotloadData, &hotloadDataVal);
sendingPromise = std::make_shared<JS::PersistentRootedObject>(rq.cx);
// Assigning to `sendingPromise` isn't possible after `init` has been called because `init` might
// replace this page. So a local copy has to be made.
const std::shared_ptr<JS::PersistentRootedObject> localPromise{sendingPromise};
JS::RootedObject returnObject{rq.cx, gui->CallPageInit(rq, initData, hotloadDataVal,
utf8_from_wstring(m_Name))};
sendingPromise = std::make_shared<JS::PersistentRootedObject>(rq.cx,
returnObject ? returnObject : JS::NewPromiseObject(rq.cx, nullptr));
*localPromise = returnObject ? returnObject : JS::NewPromiseObject(rq.cx, nullptr);
}
JS::Value CGUIManager::SGUIPage::ReplacePromise(ScriptInterface& scriptInterface)
+1
View File
@@ -49,6 +49,7 @@ void CGUI::AddObjectTypes()
m_ProxyData.insert(JSI_GUIProxy<IGUIObject>::CreateData(*m_ScriptInterface));
m_ProxyData.insert(JSI_GUIProxy<CText>::CreateData(*m_ScriptInterface));
m_ProxyData.insert(JSI_GUIProxy<CList>::CreateData(*m_ScriptInterface));
m_ProxyData.insert(JSI_GUIProxy<CDropDown>::CreateData(*m_ScriptInterface));
m_ProxyData.insert(JSI_GUIProxy<CMiniMap>::CreateData(*m_ScriptInterface));
m_ProxyData.insert(JSI_GUIProxy<CButton>::CreateData(*m_ScriptInterface));
m_ProxyData.insert(JSI_GUIProxy<CScrollPanel>::CreateData(*m_ScriptInterface));
+2 -1
View File
@@ -26,6 +26,7 @@
#include "maths/Rect.h"
#include "maths/Size2D.h"
#include <limits>
#include <vector>
CButton::CButton(CGUI& pGUI)
@@ -76,7 +77,7 @@ CSize2D CButton::GetTextSize()
CSize2D CButton::GetPreferredTextSize()
{
return CGUIText{m_pGUI, m_Caption, m_Font, m_pGUI.GetWindowSize().Width, m_BufferZone, m_TextAlign, this}.GetSize();
return CGUIText{m_pGUI, m_Caption, m_Font, std::numeric_limits<float>::max(), m_BufferZone, m_TextAlign, this}.GetSize();
}
void CButton::HandleMessage(SGUIMessage& Message)
+9
View File
@@ -34,6 +34,7 @@
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <vector>
CDropDown::CDropDown(CGUI& pGUI)
@@ -501,3 +502,11 @@ float CDropDown::GetBufferedZ() const
else
return bz;
}
CSize2D CDropDown::GetPreferredHeaderTextSize() const
{
if (m_Selected == -1)
return CSize2D{0.0f, 0.0f};
return CGUIText{m_pGUI, m_List->m_Items[m_Selected], m_Font, std::numeric_limits<float>::max(), m_BufferZone, m_TextAlign, this}.GetSize();
}
+7
View File
@@ -74,6 +74,8 @@ public:
*/
virtual void Draw(CCanvas2D& canvas);
virtual void CreateJSObject();
// This is one of the few classes we actually need to redefine this function
// this is because the size of the control changes whether it is open
// or closed.
@@ -81,6 +83,11 @@ public:
virtual float GetBufferedZ() const;
/**
* Calculate the preferred text size of the currently selected item displayed in the header.
*/
virtual CSize2D GetPreferredHeaderTextSize() const;
protected:
/**
* If the size changed, the texts have to be updated as
@@ -22,6 +22,7 @@
#include "gui/ObjectBases/IGUIObject.h"
#include "gui/ObjectTypes/CButton.h"
#include "gui/ObjectTypes/CDropDown.h"
#include "gui/ObjectTypes/CList.h"
#include "gui/ObjectTypes/CMiniMap.h"
#include "gui/ObjectTypes/CScrollPanel.h"
@@ -69,6 +70,13 @@ template<> void JSI_GUIProxy<CList>::CreateFunctions(const ScriptRequest& rq, GU
}
DECLARE_GUIPROXY(CList);
// CDropDown
template<> void JSI_GUIProxy<CDropDown>::CreateFunctions(const ScriptRequest& rq, GUIProxyProps* cache)
{
CreateFunction<&CDropDown::GetPreferredHeaderTextSize>(rq, cache, "getPreferredHeaderTextSize");
}
DECLARE_GUIPROXY(CDropDown);
// CMiniMap
template<> void JSI_GUIProxy<CMiniMap>::CreateFunctions(const ScriptRequest& rq, GUIProxyProps* cache)
{
+4 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -149,6 +149,9 @@ void CGUIString::GenerateTextCall(const CGUI& pGUI, SFeedback& Feedback, CStrInt
TextCall.m_Size = size;
SpriteCall.m_Area = size;
// Temporary workaround for a fundamental misalignment issue.
SpriteCall.m_Area += CSize2D{0.f, -3.f};
// Handle additional attributes
for (const TextChunk::Tag::TagAttribute& tagAttrib : tag.m_TagAttributes)
{
+2 -4
View File
@@ -76,11 +76,9 @@ static AppHooks default_ah = ah;
// register the specified hook function pointers. any of them that
// are non-zero override the previous function pointer value
// (these default to the stub hooks which are functional but basic).
void app_hooks_update(AppHooks* new_ah)
void app_hooks_update(const AppHooks& new_ah)
{
ENSURE(new_ah);
#define OVERRIDE_IF_NONZERO(HOOKNAME) if(new_ah->HOOKNAME) ah.HOOKNAME = new_ah->HOOKNAME;
#define OVERRIDE_IF_NONZERO(HOOKNAME) if(new_ah.HOOKNAME) ah.HOOKNAME = new_ah.HOOKNAME;
OVERRIDE_IF_NONZERO(get_log_dir)
OVERRIDE_IF_NONZERO(bundle_logs)
OVERRIDE_IF_NONZERO(display_error)
+1 -1
View File
@@ -153,7 +153,7 @@ struct AppHooks
* override the previous function pointer value
* (these default to the stub hooks which are functional but basic).
**/
void app_hooks_update(AppHooks* ah);
void app_hooks_update(const AppHooks& ah);
/**
* was the app hook changed via app_hooks_update from its default value?
+11 -1
View File
@@ -394,11 +394,21 @@ void XmppClient::SendIqGameReport(const ScriptRequest& rq, JS::HandleValue data)
// Iterate through all the properties reported and add them to the stanza.
std::vector<std::string> properties;
Script::EnumeratePropertyNames(rq, data, true, properties);
// https://gitea.wildfiregames.com/0ad/0ad/issues/8687
const std::map<std::string, std::string> mappings{
{ "civilianUnitsLost", "femaleCitizenUnitsLost" },
{ "civilianUnitsTrained", "femaleCitizenUnitsTrained" },
{ "enemyCivilianUnitsKilled", "enemyFemaleCitizenUnitsKilled"}
};
for (const std::string& p : properties)
{
std::wstring value;
Script::GetProperty(rq, data, p.c_str(), value);
report->addAttribute(p, utf8_from_wstring(value));
if (mappings.contains(p))
report->addAttribute(mappings.at(p), utf8_from_wstring(value));
else
report->addAttribute(p, utf8_from_wstring(value));
}
// Add stanza to IQ
+8 -7
View File
@@ -166,6 +166,7 @@ enum ShutdownType
};
static ShutdownType g_Shutdown = ShutdownType::None;
static int g_ExitStatus{EXIT_SUCCESS};
// to avoid redundant and/or recursive resizing, we save the new
// size after VIDEORESIZE messages and only update the video mode
@@ -182,9 +183,10 @@ bool IsQuitRequested()
return g_Shutdown == ShutdownType::Quit;
}
void QuitEngine()
void QuitEngine(int exitStatus)
{
g_Shutdown = ShutdownType::Quit;
g_ExitStatus = exitStatus;
}
void RestartEngine()
@@ -210,7 +212,7 @@ static InReaction MainInputHandler(const SDL_Event_* ev)
break;
case SDL_QUIT:
QuitEngine();
QuitEngine(EXIT_SUCCESS);
break;
case SDL_DROPFILE:
@@ -236,7 +238,7 @@ static InReaction MainInputHandler(const SDL_Event_* ev)
std::string hotkey = static_cast<const char*>(ev->ev.user.data1);
if (hotkey == "exit")
{
QuitEngine();
QuitEngine(EXIT_SUCCESS);
return IN_HANDLED;
}
else if (hotkey == "screenshot")
@@ -506,7 +508,7 @@ static void NonVisualFrame()
g_Profiler.Frame();
if (g_Game->IsGameFinished())
QuitEngine();
QuitEngine(EXIT_SUCCESS);
}
static void MainControllerInit()
@@ -826,7 +828,6 @@ int main(int argc, char* argv[])
EarlyInit(); // must come at beginning of main
int returnValue{EXIT_SUCCESS};
try
{
// static_cast is ok, argc is never negative.
@@ -834,7 +835,7 @@ int main(int argc, char* argv[])
}
catch (const RL::SetupError&)
{
returnValue = EXIT_FAILURE;
g_ExitStatus = EXIT_FAILURE;
}
// Shut down profiler initialised by EarlyInit
@@ -848,5 +849,5 @@ int main(int argc, char* argv[])
wutil_Shutdown();
#endif
return returnValue;
return g_ExitStatus;
}
+12 -11
View File
@@ -118,13 +118,14 @@ void CConsole::Init()
UpdateScreenSize(g_xres, g_yres);
// Calculate and store the line spacing
// Calculate and store the line spacing.
const CFontMetrics font{CStrIntern(m_consoleFont)};
m_FontHeight = font.GetHeight();
m_FontWidth = font.GetCharacterWidth(L'C');
m_CharsPerPage = static_cast<size_t>(g_xres / m_FontWidth);
// Offset by an arbitrary amount, to make it fit more nicely
m_FontOffset = 7.0f;
// Fonts constains two dimensions: the full height, and the cap height.
// We are adding some offset to move the text up a bit, so it looks better in the console.
m_FontOffset = font.GetCapHeight() / 2.f;
m_CursorBlinkRate = g_ConfigDB.Get("gui.cursorblinkrate", 0.5);
}
@@ -249,18 +250,18 @@ void CConsole::DrawWindow(CCanvas2D& canvas)
for (CVector2D& point : points)
point += CVector2D{m_X, m_Y - (1.0f - m_VisibleFrac) * m_Height};
canvas.DrawRect(CRect(points[1], points[3]), CColor(0.0f, 0.0f, 0.5f, 0.6f));
canvas.DrawLine(points, 1.0f, CColor(0.5f, 0.5f, 0.0f, 0.6f));
canvas.DrawRect(CRect(points[1], points[3]), CColor(0.05f, 0.05f, 0.2f, 0.85f));
canvas.DrawLine(points, 1.0f, CColor(0.5f, 0.5f, 0.0f, 0.85f));
if (m_Height > m_FontHeight + 4)
if (m_Height > m_FontHeight + 2.0f * m_FontOffset)
{
points = {
CVector2D{0.0f, m_Height - m_FontHeight - 4.0f},
CVector2D{m_Width, m_Height - m_FontHeight - 4.0f}
CVector2D{0.0f, m_Height - m_FontHeight - 2.0f * m_FontOffset},
CVector2D{m_Width, m_Height - m_FontHeight - 2.0f * m_FontOffset}
};
for (CVector2D& point : points)
point += CVector2D{m_X, m_Y - (1.0f - m_VisibleFrac) * m_Height};
canvas.DrawLine(points, 1.0f, CColor(0.5f, 0.5f, 0.0f, 0.6f));
canvas.DrawLine(points, 1.0f, CColor(0.5f, 0.5f, 0.0f, 0.85f));
}
}
@@ -283,7 +284,7 @@ void CConsole::DrawHistory(CTextRenderer& textRenderer)
{
textRenderer.Put(
9.0f,
m_Height - m_FontOffset - m_FontHeight * (i - m_MsgHistPos + 1),
m_Height - 3.0f * m_FontOffset - m_FontHeight * (i - m_MsgHistPos + 1),
it->c_str());
}
@@ -299,7 +300,7 @@ void CConsole::DrawBuffer(CTextRenderer& textRenderer)
const CVector2D savedTranslate = textRenderer.GetTranslate();
textRenderer.Translate(2.0f, m_Height - m_FontOffset + 1.0f);
textRenderer.Translate(2.0f, m_Height - m_FontOffset);
textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 0.0f, 1.0f));
textRenderer.PutAdvance(L"]");
+19 -11
View File
@@ -208,11 +208,11 @@ void InitVfs(const CmdLineArgs& args)
psSetLogDir(logs);
// desired location for crashlog is now known. update AppHooks ASAP
// (particularly before the following error-prone operations):
AppHooks hooks = {0};
hooks.bundle_logs = psBundleLogs;
hooks.get_log_dir = psLogDir;
hooks.display_error = psDisplayError;
app_hooks_update(&hooks);
app_hooks_update({
.get_log_dir = psLogDir,
.bundle_logs = psBundleLogs,
.display_error = psDisplayError
});
g_VFS = CreateVfs();
@@ -594,11 +594,18 @@ bool Init(const CmdLineArgs& args, int flags)
// on anything else.)
if (args.Has("dumpSchema"))
{
CSimulation2 sim{NULL, *g_ScriptContext, NULL};
sim.LoadDefaultScripts();
std::ofstream f("entity.rng", std::ios_base::out | std::ios_base::trunc);
f << sim.GenerateSchema();
debug_printf("Generated entity.rng\n");
try
{
CSimulation2 sim{NULL, *g_ScriptContext, NULL};
sim.LoadDefaultScripts();
std::ofstream f("entity.rng", std::ios_base::out | std::ios_base::trunc);
f << sim.GenerateSchema();
debug_printf("Generated entity.rng\n");
}
catch (const CSimulation2::LoadScriptError& e)
{
LOGERROR("%s", e.what());
}
return false;
}
@@ -848,7 +855,8 @@ bool Autostart(const CmdLineArgs& args)
while (!shouldQuit)
{
g_NetClient->Poll();
ScriptFunction::Call(rq, global, "onTick", shouldQuit);
if (!ScriptFunction::Call(rq, global, "onTick", shouldQuit))
return false;
std::this_thread::sleep_for(std::chrono::microseconds(200));
}
}
+10 -8
View File
@@ -240,15 +240,17 @@ void CProfileViewer::RenderProfile(CCanvas2D& canvas)
float rowColX = 0.0f;
for (size_t col = 0; col < columns.size(); ++col)
{
CStrW text = table->GetCellText(row, col).FromUTF8();
float w, h;
font.CalculateStringSize(text.c_str(), w, h);
float x = rowColX;
if (col > 0) // right-align all but the first column
x += columns[col].width - w;
textRenderer.Put(x, 0.0f, text.c_str());
const CStrW text{table->GetCellText(row, col).FromUTF8()};
if (!text.empty())
{
float w, h;
font.CalculateStringSize(text.c_str(), w, h);
float x = rowColX;
if (col > 0) // right-align all but the first column
x += columns[col].width - w;
textRenderer.Put(x, 0.0f, text.c_str());
}
rowColX += columns[col].width;
}
+14 -4
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -47,6 +47,8 @@
class ScriptInterface;
extern void QuitEngine(int exitStatus);
namespace JSI_Main
{
bool AtlasIsAvailable()
@@ -98,9 +100,8 @@ int GetFps()
return g_frequencyFilter->StableFrequency();
}
CSize2D GetTextSize(const std::string& fontName, const std::wstring& text)
CSize2D CalculateTextSize(const std::string& fontName, const std::wstring& text)
{
ONCE(LOGWARNING("Engine.GetTextSize is deprecated and will be removed in a future version.Use guiObject.GetPreferedTextSize for accurate text sizing or guiObject.getTextSize for sizing within GUI objects."));
float width = 0;
float height = 0;
CStrIntern _fontName(fontName);
@@ -109,9 +110,17 @@ CSize2D GetTextSize(const std::string& fontName, const std::wstring& text)
return CSize2D(width, height);
}
CSize2D GetTextSize(const std::string& fontName, const std::wstring& text)
{
ONCE(LOGWARNING("Engine.GetTextSize is deprecated and will be removed in a future version. Instead use guiObject.getPreferredTextSize and dropdown.getPreferredHeaderTextSize for more convenient text sizing or guiObject.getTextSize for sizing within an object."));
return CalculateTextSize(fontName, text);
}
int GetTextWidth(const std::string& fontName, const std::wstring& text)
{
return GetTextSize(fontName, text).Width;
ONCE(LOGWARNING("Engine.GetTextWidth is deprecated and will be removed in a future version. Instead use guiObject.getPreferredTextSize and dropdown.getPreferredHeaderTextSize for more convenient text sizing or guiObject.getTextSize for sizing within an object."));
return CalculateTextSize(fontName, text).Width;
}
std::string CalculateMD5(const std::string& input)
@@ -127,6 +136,7 @@ std::string CalculateMD5(const std::string& input)
void RegisterScriptFunctions(const ScriptRequest& rq)
{
ScriptFunction::Register<&QuitEngine>(rq, "Exit");
ScriptFunction::Register<&AtlasIsAvailable>(rq, "AtlasIsAvailable");
ScriptFunction::Register<&IsAtlasRunning>(rq, "IsAtlasRunning");
ScriptFunction::Register<&OpenURL>(rq, "OpenURL");
+2 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -25,7 +25,7 @@ bool IsQuitRequested()
return false;
}
void QuitEngine()
void QuitEngine(int)
{
}
+3 -1
View File
@@ -243,7 +243,6 @@ void CRenderingOptions::ReadConfigAndSetupHooks()
m_ConfigHooks->Setup("silhouettes", m_Silhouettes);
m_ConfigHooks->Setup("gpuskinning", [this]() {
;
const Renderer::Backend::IDevice::Capabilities& capabilities{
g_VideoMode.GetBackendDevice()->GetCapabilities()};
if (!g_ConfigDB.Get("gpuskinning", false))
@@ -252,7 +251,10 @@ void CRenderingOptions::ReadConfigAndSetupHooks()
if (capabilities.computeShaders && capabilities.storage)
m_GPUSkinning = true;
else
{
m_GPUSkinning = false;
LOGMESSAGE("GPU skinning isn't supported on the current hardware.");
}
if (CRenderer::IsInitialised())
g_Renderer.MakeShadersDirty();
+14 -18
View File
@@ -114,8 +114,8 @@ public:
componentManager.AddSystemComponents(skipScriptedComponents, skipAI);
}
static bool LoadDefaultScripts(CComponentManager& componentManager, std::set<VfsPath>* loadedScripts);
static bool LoadScripts(CComponentManager& componentManager, std::set<VfsPath>* loadedScripts, const VfsPath& path);
static void LoadDefaultScripts(CComponentManager& componentManager, std::set<VfsPath>* loadedScripts);
static void LoadScripts(CComponentManager& componentManager, std::set<VfsPath>* loadedScripts, const VfsPath& path);
static bool LoadTriggerScripts(CComponentManager& componentManager, JS::HandleValue mapSettings, std::set<VfsPath>* loadedScripts);
Status ReloadChangedFile(const VfsPath& path);
@@ -193,31 +193,27 @@ public:
}
};
bool CSimulation2Impl::LoadDefaultScripts(CComponentManager& componentManager, std::set<VfsPath>* loadedScripts)
void CSimulation2Impl::LoadDefaultScripts(CComponentManager& componentManager, std::set<VfsPath>* loadedScripts)
{
return (
LoadScripts(componentManager, loadedScripts, L"simulation/components/interfaces/") &&
LoadScripts(componentManager, loadedScripts, L"simulation/helpers/") &&
LoadScripts(componentManager, loadedScripts, L"simulation/components/")
);
LoadScripts(componentManager, loadedScripts, L"simulation/components/interfaces/");
LoadScripts(componentManager, loadedScripts, L"simulation/helpers/");
LoadScripts(componentManager, loadedScripts, L"simulation/components/");
}
bool CSimulation2Impl::LoadScripts(CComponentManager& componentManager, std::set<VfsPath>* loadedScripts, const VfsPath& path)
void CSimulation2Impl::LoadScripts(CComponentManager& componentManager, std::set<VfsPath>* loadedScripts, const VfsPath& path)
{
VfsPaths pathnames;
if (vfs::GetPathnames(g_VFS, path, L"*.js", pathnames) < 0)
return false;
throw CSimulation2::LoadScriptError{"Error enumerating " + path.string8()};
bool ok = true;
for (const VfsPath& scriptPath : pathnames)
{
if (loadedScripts)
loadedScripts->insert(scriptPath);
LOGMESSAGE("Loading simulation script '%s'", scriptPath.string8());
if (!componentManager.LoadScript(scriptPath))
ok = false;
throw CSimulation2::LoadScriptError{"Error loading " + scriptPath.string8()};
}
return ok;
}
bool CSimulation2Impl::LoadTriggerScripts(CComponentManager& componentManager, JS::HandleValue mapSettings, std::set<VfsPath>* loadedScripts)
@@ -425,7 +421,7 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
m_SecondaryComponentManager->LoadComponentTypes();
m_SecondaryLoadedScripts = std::make_unique<std::set<VfsPath>>();
ENSURE(LoadDefaultScripts(*m_SecondaryComponentManager, m_SecondaryLoadedScripts.get()));
LoadDefaultScripts(*m_SecondaryComponentManager, m_SecondaryLoadedScripts.get());
ResetComponentState(*m_SecondaryComponentManager, false, false);
ScriptRequest rq(scriptInterface);
@@ -782,14 +778,14 @@ float CSimulation2::GetLastFrameOffset() const
return m->m_LastFrameOffset;
}
bool CSimulation2::LoadScripts(const VfsPath& path)
void CSimulation2::LoadScripts(const VfsPath& path)
{
return m->LoadScripts(m->m_ComponentManager, &m->m_LoadedScripts, path);
m->LoadScripts(m->m_ComponentManager, &m->m_LoadedScripts, path);
}
bool CSimulation2::LoadDefaultScripts()
void CSimulation2::LoadDefaultScripts()
{
return m->LoadDefaultScripts(m->m_ComponentManager, &m->m_LoadedScripts);
m->LoadDefaultScripts(m->m_ComponentManager, &m->m_LoadedScripts);
}
void CSimulation2::SetStartupScript(const std::string& code)
+7 -2
View File
@@ -53,6 +53,11 @@ class CSimulation2
NONCOPYABLE(CSimulation2);
public:
struct LoadScriptError : std::runtime_error
{
using std::runtime_error::runtime_error;
};
// TODO: CUnitManager should probably be handled automatically by this
// module, but for now we'll have it passed in externally instead
CSimulation2(CUnitManager* unitManager, ScriptContext& cx, CTerrain* terrain);
@@ -68,13 +73,13 @@ public:
* should be called immediately after constructing the CSimulation2 object.
* @return false on failure
*/
bool LoadScripts(const VfsPath& path);
void LoadScripts(const VfsPath& path);
/**
* Call LoadScripts for each of the game's standard simulation script paths.
* @return false on failure
*/
bool LoadDefaultScripts();
void LoadDefaultScripts();
/**
* Loads the player settings script (called before map is loaded)
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -87,7 +87,7 @@
#include <utility>
#include <vector>
extern void QuitEngine();
extern void QuitEngine(int exitStatus);
/**
* @file
+3 -3
View File
@@ -65,7 +65,7 @@ public:
{
CXeromycesEngine xeromycesEngine;
CSimulation2 sim{nullptr, *g_ScriptContext, &m_Terrain};
TS_ASSERT(sim.LoadScripts(L"simulation/components/addentity/"));
sim.LoadScripts(L"simulation/components/addentity/");
sim.ResetState(true, true);
@@ -86,7 +86,7 @@ public:
{
CXeromycesEngine xeromycesEngine;
CSimulation2 sim{nullptr, *g_ScriptContext, &m_Terrain};
TS_ASSERT(sim.LoadScripts(L"simulation/components/addentity/"));
sim.LoadScripts(L"simulation/components/addentity/");
sim.ResetState(true, true);
@@ -149,7 +149,7 @@ public:
copyFile(L"simulation/components/test-hotload1.js", L"simulation/components/hotload/hotload.js");
TS_ASSERT_OK(g_VFS->RemoveFile(L"simulation/components/hotload/hotload.js"));
TS_ASSERT_OK(g_VFS->RepopulateDirectory(L"simulation/components/hotload/"));
TS_ASSERT(sim.LoadScripts(L"simulation/components/hotload/"));
sim.LoadScripts(L"simulation/components/hotload/");
sim.ResetState(true, true);
@@ -320,7 +320,14 @@ ActorViewer::ActorViewer()
}
// Prepare the simulation
m.Simulation2.LoadDefaultScripts();
try
{
m.Simulation2.LoadDefaultScripts();
}
catch (const CSimulation2::LoadScriptError& e)
{
LOGERROR("%s", e.what());
}
m.Simulation2.ResetState();
// Set player data
+3 -1
View File
@@ -90,6 +90,7 @@
!insertmacro MUI_LANGUAGE "English" ; The first language is the default language
!insertmacro MUI_LANGUAGE "Asturian"
!insertmacro MUI_LANGUAGE "Basque"
!insertmacro MUI_LANGUAGE "Catalan"
!insertmacro MUI_LANGUAGE "Czech"
!insertmacro MUI_LANGUAGE "Dutch"
!insertmacro MUI_LANGUAGE "Finnish"
@@ -113,6 +114,7 @@
!insertmacro MUI_LANGUAGE "TradChinese"
!insertmacro MUI_LANGUAGE "Turkish"
!insertmacro MUI_LANGUAGE "Ukrainian"
!insertmacro MUI_LANGUAGE "Vietnamese"
;--------------------------------
;Installer Sections
@@ -227,7 +229,7 @@ Function .onInit
;Run the uninstaller
uninst:
ClearErrors
ExecWait '$R0 _?=$INSTDIR' ;Do not copy the uninstaller to a temp file
ExecWait '$R0'
done:
+2 -1
View File
@@ -76,7 +76,8 @@ for lib in \
patchelf --set-rpath "${lib}:${ROOT}/binaries/system" "${APPDIR}/usr/bin/pyrogenesis" || die
done
# dlopen lib
# dlopen libs
doins binaries/system/libAtlasUI.so "${APPDIR}/usr/lib"
doins binaries/system/libCollada.so "${APPDIR}/usr/lib"
doins binaries/data/config/default.cfg "${APPDIR}/usr/data/config"
+1 -1
View File
@@ -16,7 +16,7 @@ echo "Filtering languages"
# Included languages
# Note: Needs to be edited manually at each release.
# Keep in sync with the installer languages in 0ad.nsi.
LANGS="ast cs de el en_GB es eu fi fr gl hu id it ja ko nl pl pt_BR pt_PT ru sk sv tr uk zh zh_TW"
LANGS="ast ca cs de el en_GB es eu fi fr gl hu id it ja ko nl pl pt_BR pt_PT ru sk sv tr uk vi zh zh_TW"
# shellcheck disable=SC2086
REGEX=$(printf "\|%s" ${LANGS} | cut -c 2-)