Updated to [allow_undo], because the hint message shouldn't block undoing a
recall. Recruiting can't be undone, even with [allow_undo], so this isn't
allowing a cheater's opportunity to recruit units with desired traits.
Anyone who prefers to be credited some other way (or whose name I misspelled) can feel free to open another PR
@Byteron @rrigby @DisherProject @Ferk @Konrad22 @lilinitsy @UnwiseOwl @bandita137@Ordoviz
previously the game would go into an infinite loop at
https://github.com/wesnoth/wesnoth/blob/1.14.4/src/gui/widgets/window.cpp#L1046
when a tooltip doesn't fit on screen, this could in particular happen in
the mp lobby when hovering over the 'i' of a game that uses a ridiculous
amount of modifications.
I currently don't see any case where the game is actually able to 'fix'
a bad height that was reported from reevaluate_best_size. so i just
disable reevaluate_best_size for floating tooltips.
If there exists such a case, an alternative fix could be to change the
reevaluate loop in window::layout to also stop when a new iteration
returned the same size as the previous iteration.
previously both were broken:
1) 'require_scenario' was only checked if the scenario was installed
which obviously doesn't make any sense at all.
2) 'require_scenario' was read from the local scenario data instead from
the remote scenario.
3) 'require_era' was only checked when the scenario was not installed,
so people who do have an outated version of the era installed could not
join bacause it assumed require_era=yes in that case.
4) the server tried to read 'require_scenario' from the wrong wml node,
'require_scenario' is an attribute of [scenario] and not of savefile
toplevel.
fixes#3017, assuming that the error is actually casued by the
'process_gamelist_diff failed'
As process_gamelist_diff simply returns after getting an error its quite
likeley that the gamelist is then in a corrupted state so we stop
processing it until we get a fresh gamelist.
previously it would happen that for example an attribute like
`side_name=_"female^Footpads"` in side would get its translatable mark (_)
removed after the game has started. This meant that observers that enterd
the game after it started would see the literal string "female^Footpads"
in the status side overview window.
The new code marks all translatable simple_wml attributes to make sure their
translatable mark is preserved along with their textdomain. It can still
happen though that attributes will appear in the the wrong textdomain area
after simple_wml processing though because in some cases note::output
might skip over textdomain markers. It is still not as bad as string like
"female^Footpads" appearing in the ui though.
An alterntive appraoch to fix this issue would be to carefully make sure
not to change any atributes of wml tags that can also contain translatable
attributes, which would probably imply not editing the wml objects received
by the client at all and instead storing the new information (in particular
side information like is_local=yes/no) in a seperate wml object. (that would
then be sended to the clients along with the original scenario wml objects.)
fixes#1420
as said in the comment, that get_special_bool might return the wrong value, as since 5f58cd7c6d the bc_vector no longer contains disabled attacks we can just remove this code.
fixes#3324
as the ingame ui is not shown yet, [delay] would only result in showing a black screen,
Also in the case of initial lua it might result in crashes because of the threaded loadingscren, or simply because parts of the ui are not initialized yet.
Also fixes a mistake from the 1.14.3 rules that caused "xxx MiB" to be
replaced with "xxx MB MiB" for all platforms. Oops. Nobody noticed
anyway (?).
[ci skip]
Uses an Orcish castle instead of destroyes human. Troll would maybe fit best,
but it doesn't fit well with the surrounding. Has now only 2 castle hexes.
On easy difficulty, reduced turns by two, it should be enought turns.
Also added one more enemy, as there are less wolves spawned on easy.
And income for Gryphons once again increased by 1, they are very expensive.
Reminding events have been adjusted to turns.
[ci skip]
The ability isn't needed in master because none of the unit tests call
deprecated functions here, but it may be useful in the future or make
cherry-picking of future changes easier.
Like @gfgtdf pointed out, loadstring() is still supported by Lua in the
name of backwards compatibility, even though it was deprecated in Lua 5.2
and is no longer mentioned in Lua manual. Thus, as of committing this it's
actually possible to load Lua bytecode.
Let's unit test this to ensure that we don't reintroduce this
vulnerability.
Side 3 was composed by enemy reinforcements. Since they were
spawned on the right corner of the map, and since side 2
was blocked inside Halstead by and [avoid] tag, it was
necessary to add a new hidden side which could move freely
on the map.
If we upgrade the AI, removing the [avoid] tag, this hidden
side becomes unnecessary.
All sides will now head to the central fortress. Orcs
should now be a bit smarter, and they should not suicide
during the morning or the afternoon. The humans in Halstead
will initially remain inside their fortress, until the enemy
arrival.
There are two layers of halos and they are applied in a somewhat
convoluted fashion. I should probably explain why.
The bottom halo is designed so it's drawn *below* the main unit sprite
so as to not muddle the colours on it. Halos are normally drawn *on top*
of sprites.
The back halo is specifically masked so it's drawn behind the main unit
sprite without overlapping any of its pixels, but it's asymmetrical and
supposed to flip along with the unit sprite depending on the direction
it's facing. Halos do not do that currently, at least not without using
animation WML conditionals. Unfortunately, for some reason, using a
standing animation that's nothing but conditionals causes the game to
crash at the moment.
Taking all this into consideration, using the blit IPF is a much easier
mechanism to avoid both issues at once, even if it makes the code
slightly awkward.
If someone can think of an alternative method, they're more than welcome
to change the code as long as the sprite's composition remains exactly
the same as it is now. I'm just the artist in this case.
[ci skip]
Monkey-patching has multiple problems. The biggest problem for a security
fix like this is that it's way too easy to forget to re-apply when we
update Lua to a newer version.
Instead, we now have the implementation of load() under our control and can
update Lua without risk of reintroducing CVE-2018-1999023.
this test whether we succesfully prevent the exceution and parsing of
precompiled lua chunks, which can be used to break the lua sandbox.
This test does not cover all affected functions in particular not the ai
code that loads lua chunks.
This could otherwise be used to escape the lua sandbox, as described in
multiple sources. For example one can use it to reenable the os.execute
function to do shell commands
The affected functions were
load,loadstring,wesnoth.dofile,wesnoth.require and various places in the
wesnoth source where lua chunks were loaded for example by the ai code.
This commit also changes the lua source to change luas load (which is
the same as loadstring), alternatively we could add a wrapper around the
original load function that always passes "t" as third parameter, i went
this way mostly because it was easier to implement, but also because i
was not 100% sure that is is impossible to query the upvalues of a
function via lua (wesnoth disables debug.getupvalue but still).
There is also an occurance in the application_lua_kernel that was not fixed
because i assumed that umc cannot contian application lua scipts.
As further security measure we might want to disable printing the function
adress in luas tostring for c functions, this cannot be exploited by itself
but it can be used to defeat ASLR in some cases.
Before:
20180724 17:21:37 error gui/layout: Failed to fit vertical list to requested rect; expected bottom edge was 277
20180724 17:21:37 error gui/layout: , actual bottom edge was 195
20180724 17:21:37 error gui/layout: (top edge is 113)
After:
20180724 17:34:30 error gui/layout: Failed to fit vertical list to requested rect; expected bottom edge was 277, actual bottom edge was 195 (top edge is 113)
This allows the sorting logic top be shared between the sidebar and the
unit preview pane. It also means that we no longer need to create a lambda
to sort them.
I also refactored the generation of movement cost data in help. In
particular, we're no longer extracting the struct to named local variables.
The previous condition was, "Win as soon as Aiglondur and Angarthing
have each touched the signpost". The new condition is, "Win as soon
as Aiglondur is on the signpost and Angarthing is next to him, or the
other way around".
[ci skip]
- Removed need for quick trait by spawning quantain next to Delfador
- Disabled movement point tracking due to #3344
- Use only one [label] tag to place both labels
- Removed id's of later quintains, as they are not used
- added some whitespaces
[ci skip]
Fixes#1584 1c - Delfador summons the puppet, you have 0 MP left but the
puppet is not adjacent to you, and can't attack or undo
Changed Delfador's initial position to match the quintain's, and made him
step away to summon in the original place next to us, so we don't need to
move again to attack after we reach him.
The movement points of the mage are now updated and he gained quick trait
to fit for the more movements he does.
Final movement also touched, so he does not seem to sidestep the new
enemies when leaving the map.
The terrain was deprecated in commit 64493b256f.
@Vultraz has said in comments of #2966 that deprecated terrains aren't
supposed to be shown in help.
Fixes#2966.
[ci skip]
Also moved the string_map alias into the GUI2 namespace and renamed it widget_item.
It's the same as utils::string_map, but this makes its purpose clearer.
Unlike other widgets where `this` is the event target, the tree nodes fire the event
with the tree widget itself as the target.
I had added a fire-event call in f97dc8ae12, but with
the target as the node. I don't think there was any way that would have worked...
changed.
Child nodes were still managed with unique_ptrs in 1.14, so we couldn't use make_unique
there. Child nodes are now managed with shared_ptrs here on master.
Regression from commit 36e9290.
As @gfgtdf pointed out in the bug report, because old_player was a
reference to the shared_ptr, resetting the shared_ptr in sides_ also
changed old_player, and thus 'the player lost his last side' check never
passed.
Thanks to @gfgtdf for figuring out the cause.
- the movement restriction won't be applied if the magican is not
in the caslte (due to the one exception).
- As for the exception, it's not enough if the magican has only one
unit left, but this unit has to be on the caslte.
To sum up, the magican never leaves the castle, unless he has
(before recruiting) one last unit which is on the castle. (Maybe
from last turn's recruiting).
In case he left the castle, he goes back next to the keep next turn,
as leaders usually do.
[ci skip]
gui/widgets/settings.hpp was rendered unnecessary in almost all dialog and widget files
as of 6759f41b1e, since it was no longer needed to implement
the internal functions wrapped by the REGISTER_DIALOG and REGISTER_WIDGET macros. Those
were register_window() and register_widget(), respectively.
The player can all the time view the stats of any unit in the sidebar. This allowed to
see that he doesn't attack because he has only one move. There is no way to see the
movement costs directly, and as long as they are higher than the max_moves it's not
possible to figure out that this is not AI behavior but a game restriction.
Additionally, as the player has to kill both leaders to continue, try to not let the
player camp around the castle for the rest of the game, by giving the leader a possiblity
to attack if he recruited last turn a unit.
[ci skip]
In the case in bug #3321, damage prediction code somehow receives a
combatant whose probability to be slowed is very close to one of those
values but not quite it. I couldn't figure out how it's possible because
only damage prediction code itself is supposed to emit slow probabilities,
and it's not producing such a probability in this case.
Without more information, I'm simply fixing the bug by force. If the
probability is in the problematic area, we simply round it to 0 or 1. This
way such probabilities are impossible later on when we try to scale the HP
distributions so that they add to 1.
Fixes#3321.
Instead of having another ToD, the image of the current ToD is used,
but illuminated. This is a visual change, no gameplay changes included.
For the always dark one exists no immage, uses one from after the fall,
with slightly adjusted ToD shifting as it looked to weak.
The 1 hex small campfires look best with dusk.
part of #3056
[ci skip]
Instead of having another ToD, the image of the current ToD is used,
but illuminated. This is an visual change, no gameplay changes included.
Due to the lack of a save I could not view the result myself,
I chose the ToD shifting colors based on the other scenarios.
part of #3056
[ci skip]
Instead of having another ToD, the image of the current ToD is used,
but illuminated. This is a visual change, no gameplay changes included.
The ToD shifting for 'dawn' looked better than for 'dusk', and was
conidered better looking than having no ToD shift compared to the
surrounding.
part of #3056
[ci skip]
Fixing the lack of stars on the remote client when sending a team/observer message.
This commit didn't modify the necessary lines in replay.cpp:
6aa3b3b
(of which the chat_msg::chat_msg one has already been fixed)
Fixes#3119
Don't bother carrying them through the whole campaign.
This scenario seems like a good time, because there begins a new episide in the story
and all the level 1 advancement are available now too.
closes#3074
[ci skip]
This is generally a problem with most leaders, but here it's worse.
Also changed his keep to the ruined version.
(Not the ajdacent castle tiles as it looks better that way.)
[ci skip]
In case the player goes south and runs away fromt he bandits, and defeats
the lich first, then the choice to side or not with the bandits would
happen very late.
In case he allied with them and the other undead leader still lived, he
could end the scenario still by triggering "enemies defeated". If they were
already defeated, the scenario could not end anymore. Furthermore, the
storytext doesn't make sense anymore, at least the ending dilogue would
miss,
In case of siding with the elves one can still win by defeating Urza Afalas.
and the story still makes sense,
To solve this, in this special situation the player has no choice anymore,
the path of the elves is chosen.
(the diff may be hard to read; a good part has been wrappend with an [if])
[ci skip]
This was never finished, is not maintained, suffers from a lack of features the "old" listbox
class now has, and seems (according to the logs) to be have been superceded by the pane widget.
At the very least, the pane widget seems to be what mordante was working with in his early
prototype of a new addon manager, and not this 2010 list class.
Need to sort out the problems with dispatching events to the HUD or the gamemap, respectively.
Disabling the HUD for now so it should be possible to interact with the map in case someone
wants to work on its rendering.
this also fixes a bug where the side number in the initial flg dialog would be off by one.
This is also a slight behviour change where not finding [era] in mp_join_game::fetch_game_config no longer throws config::error but just returns false (=cannot join game)
we cannnot call show_flg_select from inside the select_leader_buttons callback because that select_leader_buttons might be deleted/recreated while that dialog is open whihc leads to crashes, so what we do is executing the show_flg_select
in a seperate callstack by using a 0 ms non-repeating timer
in the non-host case the clients might get updates that change the [side] config while the flg dialog is open which might result in invalid pointers, note that flg_manager::default_leader_cfg_ is still there but this is no problm because that is never dereferenced it's only compared to other pointers.
we also make a copy of all [multiplayer_side] on the non hosts side for the same reason.
previously players had to leave an rejoin the game to change their faction.
this was most annoying in coop games where you want might want to choose
your faction in consultation with the other players. Also you previously could
not even checkout the different available factions again after you joined
the game.
"Fake interactive" mode seems like it was meant to be an interactive version of fake mode.
However, since we're using it to stop the UI drawing and the unit tests (which use it)
don't seem to display a window at all (not entirely sure why), it's weird that "fake interactive"
mode would be considered interactive.
[ci skip]
For some reason, this made the entire page stack thinner than it should be. I have
no idea why, and I'm not sure wrap= here instead does anything (namely, wrap if it
gets too long), but it's better than what was happening before.
There's really no reason to have this anymore. It was (AFAIK) introduced years ago
as a performance-saving measure, then was moved to Advanced Preferences in 1.13 since
modern PCs mostly have no issues. With accelerated rendering, there's even less of a
reason to have this.
Also dropped some unused code in unit_type.
And there's still one in language.cpp, but I'm not entirely sure if it's safe to
drop the last empty entry there so I left it.
This avoids an issue where people could still apply formatting by using an older client.
Granted, any formatting would still appear in-lobby to anyone using an older client, but
this at least prevents the possibility of formatting appearing indefinitely if a game host
happens to never update their own client.
This is a good point since it ensures any place that might use the title before the lobby
(don't think there's any such places right now) won't inadvertently get formatted.
Also might be worth looking into a way to just strip formatting completely.
Fixes wmllint crashing like this upon encountering a gzip tarball in an
add-on:
Traceback (most recent call last):
File "/home/shadowm/bin/wmllint-1.14", line 3188, in <module>
for fn in allcfgfiles(directory):
File "/home/shadowm/bin/wmllint-1.14", line 2944, in allcfgfiles
if interesting(os.path.join(root, name)):
File "/home/shadowm/bin/wmllint-1.14", line 2927, in interesting
return fn.endswith(".cfg") or is_map(fn) or issave(fn)
File "/home/shadowm/src/wesnoth-1.14/data/tools/wesnoth/wmltools3.py", line 270, in issave
return firstline.startswith("label=")
TypeError: startswith first arg must be bytes or a tuple of bytes, not str
[ci skip]
this would bring the whiteboard data of the differnt clients out of sync which could be a problem since the wb network protocoll identifies the actions to be removed ot replaced by index.
Fixes: https://forums.wesnoth.org/viewtopic.php?f=21&t=48370
In the tutorial when we occupy the first village the message tells us the
village count got incremented, but in the old version it was incremented
only afterwards. Non-narrator messages were updated properly. By adding the
redraw, narrator messages triggered by capture event produce the same
result as other speakers.
We're going to be using NN scaling for the map, and that's already handled automatically
by SDL (and in the future, OGL). We don't need these settings for surface SCALED_TO_ZOOM
and SCALED_TO_HEX scaling. In any case, if we want to scale a surface to zoom or hex, it
will almost certainly be for map rendering (such scaling methods don't make sense in the
UI, for example), so just defaulting to NN is simplest.
As for why I've decided to stick with nearest-neighbor scaling for zoom, it happens to look
a lot better when done on the GPU than on the CPU for some reason (perhaps having to do with
the old rendering pipeline in which we were doing surface scaling), and it's better to have
a consistent scaling look as you zoom in, especially if we wanted to do animated zoom-ins.
This change drops the option to use Linear or xBRZ scaling for map zooming. This was already
the practical case due to me converting map rendering to use textures. NN was used for all
zoom levels, and it's fast and looks good.
This makes it so addon metadata (title, version) will be fetched from _server.pbl if
present and _info.cfg if not (see #3278).
This also eliminates the temporary addon_source struct and unifies the metadata parsing
and actual loading stages. They used to be separate since single-file addons were a
thing, but those were removed in 3f640b8e71.
Also a bunch of minor code cleanup.
This makes 'scons dist' work, although the resulting tarballs are not
yet identical to cmake tarballs.
Remove awk usage made obsolete by the git transition
(7f85fa000c).
Update src/revision.hpp reference to use src/revision.h. The former
name is unused since at least 7625b1e079.
The documentation indicates you're not really meant to use the walker directly.
They're part of the implementation of the iterators. They could be used directly,
as shown here, but this is shorter.
As per sigurd's trial and error: RELRO's options are unknown entirely and -fstack-protector-strong results in compile errors. Building with just PIE and _FORTIFY_SOURCE enabled does then compile, but results in a broken executable.
Half-fix for issue #1634 and issue #1924.
The issue that remains to be solved is that on subsequent sessions after
a campaign has failed to load, it is possible for the game to generate a
cache entry for it that only contains the main menu WML for it.
Apparently the config cache transactions mechanism causes the game to
try to generate a cache entry with the wrong defines (a define set that
doesn't include the campaign's symbol, for instance) instead of the ones
that are actually needed and used to match the cache entry's filename
via checksumming. As a result, on subsequent sessions the failed
campaign is aborted with "failed to load the scenario" instead of
displaying the real WML error again (since the error is not hit again if
it depends on the campaign's symbol being defined).
In the meantime, this at least removes the red herring error and makes
the underlying issue a bit more visible. It's a very crude hack but it
does the job.
For lobby messages, there was a length cap in place already, but the
truncated message was lost in processing because it ended up in a WML
document that isn't the one relayed to listening clients.
On the other hand, whisper messages were missing the truncate logic
entirely. Oops.
(The logic for in-game messages does truncate messages correctly as far
as I can tell, and additionally the client UI doesn't allow overlong
messages.)
Thanks to Soliton for pointing me towards the faulty code.
menu_button doesn't even actually inherit from clickable_item. The only reason
[dis]connect_click_handler was declared in this class is the original implementation
was copied extensively from the Button widget.
Using NOTIFY_MODIFIED also means callbacks can fire if set_value/set_selected is used
on a menu_button.
The [dis]connect_click_handler functions were also removed from multimenu_button. All
callbacks for this widget type already used NOTIFY_MODIFIED signals.
Retvals are only relevant for widgets that are supposed to trigger something
like a window closure, and that makes sense for neither of these widgets. The
only reason the Menu Button widget has it is its original implementation was
largely copied from the Button widget, and the Multimenu Button widget copied
from the Menu Button widget.
This commit excludes changes to S05 Tirigaz, I think changing the dialogue
there is going to be more complicated, and it's better for that to have a
separate PR.
The problem was introduced by commit 0f511e8 due to the [modify_unit] tag apparently causing prisoners to disappear because technically they were duplicates as they had merely been unstored and still existed on the recall list as well.
DW 5 Tirigaz - Changes to orc leader death event
Fixes#3092 - Updates objectives if orc leader is killed first, and gives additional dialogue
Fixes#3903 - Gold event doesn't fire if ghosts kill the orc leader
This was due to the change in the MP initialization process wherein the lobby wouldn't
show up until the initial gamelist was received. Since the admin auth message is sent
after [join_game] and before the initial gamelist, and the chatbox widget handled parsing
the auth message, the client was never marked as authenticated and therefor couldn't
observe private games. This fixes that by adding auth parsing to the MP initialization
process.
Note this doesn't fix the issue of the auth confirmation not showing up in the lobby chat
(issue #2920). I'll have to think of a way to fix that separately.
This is a script to take a changelog section (provided in the command
line as such: `steam-changelog changelog.md X.Y.Z`) and convert it to
BBCode for posting on Steam.
[ci skip]
[ci skip]
These were all mentioned between 1.13.13 and 1.14.3, meaning the remaining changes
are everything new in 1.15.0-dev so far. Also removed one entry that was mentioned
twice in the WML Engine section.
Makes it easier for translators to do something specific with this label if needs
be. I remember the reason the count (NUMx) label was moved prior to the name had
to do with language conventions too, so this should alleviate any other such issues.
Also made the name label default size instead of small.
Automatically checking the path relative to a maps/ directory without binary
path support results in an invalid path almost every single time. If I remember
correctly from my testing, the only time that worked was if I added a data/maps
folder.
ee50171d13 broke some codes that relied on
unique save ids, that is in particular the statistic code and
scoped_recall_unit, so now these codes fallback to the side number if
the save id is empty.
The variable **always** changed when event handlers were run, and thus the
optimizations to avoid updating some status after WML/Lua has run weren't
doing anything. In addition, commit 62ec3b3951 removed the most
important optimization that relied on wml_tracking().
Resolves#2578.
Since there were weapons included that weren't shown, it was possible for the best
weapon selection to be a hidden one (in which case, the initial selection would be
wrong, and it was possible for the returned index to point to a hidden, disabled
weapon.
This resolves both issues by excluding these disabled attacks from the weapon choices
list altogether. They aren't considered when calculating the best attack either.
mouse_handler::fill_weapon_choices is also used in mouse_handler::attack_enemy_, but
I don't foresee this change should cause any issues there, since you aren't supposed
to be able to actually attack with disabled weapons anyway.
* UtBS 5: changes to scenario locations
Fixes#3077:
* Moved AI leader spawns to keeps
* Changed spawn of trolls that were spawning in walls
* Sanity-checked village ownership in cavern
Fixes#3078:
* Changed spawn of Eastern Troll Flamecaster
* Fixed entry routes of Troll Flamecasters
From author notes:
* Made 'Wounded Dwarf' a wounded unit
This commit is the followup to a similar one I did regarding window initialization. Instead
of widgets being created on the heap and not being managed by a smart pointer until they're
added to a grid, they are now always managed by a shared_ptr. To that end, this commit covers
bunch of things:
* builder_widget::build (both overloads) and all its overrides (which have now been marked
as such) now return shared_ptr<widget>.
* The builder_grid::build() override now returns the same instead of grid* since you can't
use covariant return types with smart pointers.
* The two implementation build helpers in builder_grid have been combined with an optional
replacement map as the second parameter. Uses of the version that took a grid pointer could
be easily converted to pass a reference instead.
* The pane, matrix, and viewport build() functions were removed in favor of making the ctor
public. In case there was a deprecated ctor, that was removed.
* The viewport now keeps a widget shared_ptr instead of a reference that was then deleted
by address-of. This was both better design and necessary to fix a crash.
* build_single_widget_instance_helper and build_single_widget_instance were renamed to
build_single_widget and build_single_widget_and_cast_to to better represent their roles
and to indicate the latter was more a convenience extension for the latter than the other
way around.
There were two overlapping problems: 1) the branching was written incorrectly (due to combining top-level and [if] filters) and 2) the first [defend] tag getting merged with the base WC/Soulless defense animation.
Another efficiency improvement. This ensures that the side of the unit
is checked first before the potentially complex rest of the filter is
evaluated.
The old method is very slightly faster in some circumstances (e.g. for
simple filters and when all units have moves/attacks/etc. left), but we
are talking fractions of micro seconds. By contrast, depending on the
filter used, the new method can save large amounts of evaluation time
once some units have move or attacked.
If dc happens during asio read that would call server::add_player
then a "ghost" player will appear in games_and_users_list_. Fix works by
moving the list update into the handler, it will be called only if read is
successful.
This should prevent issue #2989 unless it has some other mechanism
This is a debug mode-only dialog. If I want to spawn a unit, the game
had better allow me to spawn any unit I want. do_not_list was created
for use by wmlunits anyway.
This time I added an option to disable the feature to allow the currently
playing track to finish when changing the playlist. This allows more
fine-grained control of distinct use cases.
In wesnoth.cpp:do_gameloop(), I reversed the order of the title screen
music and default music because otherwise adding the default music would
enable play_once for the title screen music and prevent instant music
change when the player loads a save. I play title screen music with
immediate=yes, so it's still played first.
* now the situation can appear that spiders can attack Malifor,
this handles it.
* add *^Xo Terrain to the filter. While there is no bug to fix,
it looks like it belongs there too.
* work around a tile glitching with an [item] at 22,4
* remove code referring to removed variables
* and run wmlindent
[ci skip]
NR S5a: bugfixes
* Fixes#3117 - Malifor damage event now occurs on defence as well on attack
* Fixes#3116: - Doors to the study can now be opened from inside
[ci skip]
This reverts commit 6d0b7c8424. Turns out there's
a better way to fix this problem without using mutexes, which have a noticeable
performance hit (5.2% of the execution time of game_display::draw_invalidated()
according to @jyrkive).
This is workaround for windows style path confusing scons if they appear
in CPPATH etc. Paths without prefix still happen to be valid and they
start with "/", not "c:".
Didn't use this in the window widget since that doesn't specify front_child as
the queue position. I need to evaluate whether draw callbacks need to be in that
position anyway. AFAIR I only started adding them there since I noticed the one
in the debug clock dialog used that.
One_strike_fight() assumed that if HP distribution hadn't been calculated,
the unit is alive. It would normally be a valid assumption, but the Wesnoth
engine allows units with negative HP (although things aren't guaranteed to
work correctly in the presence of such units).
The assumption, together with a completely wrong calculation for the
probability that the opponent will counterattack, resulted in badly
incorrect results. That, in turn, caused the calculated probability that
the opponent to kill us to become negative (I observed -75 % when
debugging), making the calculated probability to be poisoned/slowed to
exceed 100 %, and that finally caused an assert if the AI simulated another
fight for the same unit.
I have now fixed those issues. I also noticed that rounding error allowed
the probability to be killed to still become slightly negative, and thus
changed std::min() to utils::clamp() to limit the value to the allowed
range.
This reverts commit ef60deaa2b.
@ln-zookeeper pointed out that units with negative HP are documented in
the wiki, and thus disallowing them is an API
change.
volatile draw had to do with drawing map labels pre-accelerated rendering. They're unused
now and I don't foresee using them again since they don't offer anything the regular draw
functions don't and they aren't needed for the map labels anymore.
Tooltips are handled by handled by GUI2. There are no more help strings since the related
interface in CVideo got removed.
Namely complete_redraw_event(), recalculate_minimap(), and redraw_minimap(). I had
been keeping the last around for reference (see f5ec886cb5) but I
figure it's not really worth it since this isn't the drawing method we'll want to
be using in the end anyway.
This list in the connect engine was passed to each of its side engine's flg managers,
where it was then sorted by update_choosable_factions(). Basically, a whole bunch of
unnecessary sorting. This makes it so the list is already sorted when it's passed to
each side engine.
None of the post-processing of the faction list (in populating available_leaders_)
should mess with the order, as far as I can tell.
the line above does exactly the same as the line inside that if(){..} so it has no effect.
Also, what the comment says is wrong. We do not want to keep the old recall cost if it is different from the original recall cost because doing that would break removing objects that change recall cost.
* to enable playing the path in debug mode
* set the betrayed friend variable in S5
* overwrite redruits and gold
* use lua for unit transformations
* clean up code in S5
* fix ellipse change having no effect (probably since 1.12)
* work around bug 3172
[ci skip]
It didn't make much sense to have these since there's really no situation you'd want
the "default" sorting order, which is however the server decided to send the list.
This has the advantage that they use the same help page as newwly
recruited ons, and their advancement options are correctly shown there.
The transformation code is taken from SotA S18
[ci_skip]
this removes a hack in connect_engine.cpp that set save_id to a value to make sure that other connect_engine.cpp code does not chnge it later to the plyers id, (it did so at some point iirc).
Instead we update carryover.cpp to make sure that a side with no save_id (or id since save_id defaults to id) is not carried over to the next scenario,
fixes#3152
This was only needed for the minimap since each canvas had its own texture, and the
minimap widget's canvas texture needed to be passed to image::render_minimap (that
function operated on the current render target, in this case, the canvas texture).
As of 02858f2259 we render directly to the screen instead,
so this isn't needed anymore.
These were added in 8f945cf235, but since the "new" listbox
implementation never came to be, these have just been unused clutter. There was one place
they were used as parameters in a manual call to calculate_blitting_rectangle, but that was
refactored out in 3332ae9757.
This also removes an overload of widget::draw_debug_border, since without the offsets, both
functions now did the same thing.
This affects:
* widget::draw_background
* widget::draw_children
* widget::draw_foreground
* widget::impl_draw_background (offset overload removed)
* widget::impl_draw_children
* widget::impl_draw_foreground
* widget::calculate_blitting_rectangle
* widget::calculate_clipping_rectangle
* widget::draw_debug_border
This is a lot more efficient since it allows the GPU to parallelize draws AND it magically
fixes the bad alpha rendering we've been having!
Fixes#1568Fixes#1744
This will make enemies recruit equally many lvl1 and lvl2 units, thus decreasing the amount of units overall and making it less feasible to last indefinitely due to hordes of lvl1 units blocking better damage-dealers from reaching player units.
This merely patches the worst problems (multiple successive [endlevel] calls, inconsistent [endlevel] contents, recursive elf die event, lava fills visually broken); ideally the whole scenario should be rewritten and redesigned.
The mask changes only consist of re-sizing them to match the map size.
This reverts commit a3ef80853c.
Vector reallocation cost is logarithmic. Assuming that a vector
starts at a size of one and doubles its size in each allocation, the
result is 11 allocations - completely negligible compared with, you
know, loading 20 000 images from disk.
[color_adjust] needs to be able to use absolute values as large as
2*255 in certain edge cases to set the screen a single solid colour when
interacting with time of day colour shifts.
Fixes#3144.
Leaving theme= unspecified ought to have the same effect as providing it
and setting it to an empty string. Without the check for a nil value,
however, it would result in a crash like this:
20180519 22:31:54 error scripting/lua: lua/wml-tags.lua:922: bad argument #3 to '__newindex' (string expected, got nil)
stack traceback:
[C]: in metamethod '__newindex'
lua/wml-tags.lua:922: in local 'cmd'
lua/wml-utils.lua:145: in field 'handle_event_commands'
lua/wml-flow.lua:6: in function <lua/wml-flow.lua:5>
this fixes require_scenario=yes for scenarios that use map_generation or
scenario_generation, the problem was that create_engine does not call
saved_game::expand_scenario for random maps, (which is the function that
checks require_scenario=yes)
fixes#3105
See https://forums.wesnoth.org/viewtopic.php?f=32&t=47721&start=450#p625660
All images but the young roc/roc would remain under the GPL, since Kwandulin based them on images by Sleepwalker and I wasn't able to contact him about using the CC BY-SA for them. The young roc base and attack sprites are under the CC BY-SA, and are by Vyncyn(forum username).
[ci skip]
These are incorporated into the objectives dialog automatically. They lack a deprecation
notice, but they should be given level 3 status on the 1.14 branch.
Instead of throwing a WML error. This allows the UMC author to get a stack
trace if the unit creation was triggered from Lua.
Requested by @gfgtdf in a comment of #3042.
* castle of the southwestern leader has been moved down a bit
* fixup for gate event and troll die event not properly working
* give dwarves more gold if they are in trouble, increased income of trolls
* added micro AIs, currently not working as expected
* other minor map edits
* removed patch 9b9aa13 for #3073, the village had been moved down one hex
for visual reasons
[ci skip]
This allows player 3 to send more enemies against the human player sooner. If this is an issue, may be necessary to consider changing the scenario wml to delay this player spawning by a turn.
* removing horses from text strings - replaced with dustboks
* adding a riderless dustbok to monsters race, needs description and probably other adjustments
* removing disengage ability and translation mark from dustbok unit file
* adding #po translation hint for name
* make north gate obvious to players
* mitigate bridges transition
* use less human castles
* don't break northern train line
* move the bridges in the Trolls keep farther behind, to be less
vulnerabe to the northern leader
[ci skip]
shared_ptr::unique() is equivalent to use_count() == 1. A few of these checks should probably
be > 1 to account for 0, but this is a direct logical translation.
Without this, I get the error "syntax error: '<'" and a reference to the function's
opening bracket... No idea why. It build fine on VS 15.7.1 with C++14.
Technically, all this code should work on Vista, (including the recent switch to using
SHGetKnownFolderPath), but since we're also considering requiring Visual Studio 2017
for building, we need Windows 7.
The specific case that brought this to our attention was color=100. In case such values
are used, the color reverts back to the default color for that side, as before.
The new codepath (team::get_side_color_id_from_config) is essentially the same as the old
one but more robust (range checking, for example, the lack of which was causing the crash
before).
This reverts commit 5fd833a91a. It was causing the lobby to
lag up to *three minutes* behind current activity due to multiple data packets being queued
(see #3046). It seems 100 ms was enough to mask this issue.
If a unit had for example 3 other formation units adjacent but only needed 1 to reach 70% defense, it didn't receive any benefit at all (as the corresponding [chance_to_hit] tag remained inactive).
Spotted and fix provided by beetlenaut.
Several reports on Steam and our forums point at std::bad_cast being
thrown when accessing Preferences and the Multiplayer menu amongst
others. It's possible that the locale configuration on those systems is
not quite right, and compare() and icompare() are able to throw
std::bad_cast when this happens as they both use std::use_facet().
Note that much like the macOS/iOS version of icompare(), this stopgap
patch doesn't attempt to provide any form of case-insensitive fallback
and just uses a case-sensitive comparison instead.
Thanks to @ProditorMagnus for the suggestion. Note that here on master, this code isn't
really used right now, so it's mostly here for completeness if it turns out to be needed.
There isn't much point in doing more expensive ban look ups first.
(Also, yes, I am aware that as it is there's still two SELECT queries
that could be coalesced into a single one -- namely, the ones for the
user_email and user_id columns.)
This enables reporting back to the client the specific type of ban that
affects the account. This information is already normally provided by
phpBB when trying to view a page while banned, so we are not leaking any
new information here.
There isn't an API to retrieve the (user-visible) ban reason from the
ban list yet. It's probably not worth worrying about it since affected
users can see it when navigating to forums.wesnoth.org anyway.
This adds a user_is_banned() method to the user_handler classes that
returns whether a given username (and optionally IP address) is banned
by the user_handler platform. Obviously right now this is only intended
to work with forum_user_handler and phpBB.
Forum bans are checked against entries in the banlist table using
username (actually user id), IP address, and email address where
applicable. A user matching a ban on any of those three items will not
be permitted into the server *unless* they have the moderator flag set.
It might be worth making an exception for board founders as well,
although that is probably orthogonal to this patchset.
Right now there are a few missing items:
* The server sends clients an error that allows them to try again with
a different username/password combination immediately. Nothing stops
them from causing noise in the server logs this way, so we probably
need to ensure this counts as an authentication failure for the
purpose of temporarily and automatically banning the IP address.
* The user handler doesn't allow retrieving details about the ban, so
all that the main server code can do is report back to the client as
their nickname being banned, when this is not necessarily the case
(email or IP address bans). I need to figure out a better API for
retrieving this info.
* Likewise, the server does not log the specifics about the matched ban
yet unless the mp_user_handler log domain is set to the info log
level.
* There's no i18n support on the client side for the error message sent
by the server -- which is going to change anyway.
* Testing this patch uncovered an issue with the MP client not
displaying messages sent during the login sequence, including the mod
authentication notice.
This fixes issues reported on the forums where the weapons list now
includes weapon specials even when they aren't active, a regression from
1.12.x.
Closes#3033.
the wb recruit actions store temp units with fake ids and live longer
than a turn, so resetting the underlying id counter between turns might
result in dublicate id errors in wb recruit actions ( #1517 ), which
might lead to errors later.
With this it is of course possible to get erros when more than 2^31 (or
2^63 on a 64 bit wesnoth version.) fake units are generated during a
game, but that is less likely.
previously having a planned recall action could change the order of
units in the recall list, which might for example change which unit is
recalled by a [recall].
The firstproblem was that:
apply_temp_modifier adds the temp_unit_ to the map, then
remove_temp_modifier adds the temp_unit_ from the map to the recall
list, which resulted in the original recall unit beeing replaced by the
temp_unit_ of the recall_action We fix that by making sure that
temp_unit_ is always the same as athe recall unti not just a copy.
The second problem was that remove_temp_modifier reset the unit mp/ap to
a value differnt form the original mp/ap which could casue OOS later
since the ap/mp might be changed form that unsynced context, we fix that
by resetting the mp/ap in remove_temp_modifier
turned out 8bdccca7 was not enough because the mapbuilder erroneously
reset the units movement to full directly before it was applied. Since
the `resetters_` code in mapbuilder.cpp does not apply to
recruited/recalled units, we also have to reset the units mp in
remove_temp_modifier.
[ci skip]
Height isn't the problem. The default lobby can display fine even at 600 px h. Width is
the problem the default layout faces at low resolutions, and it was quite odd to have a
really wide window use the low resolution layout, despite there obviously being enough
horizontal space to fit the sidebar.
This is similar to the change made for spacers in da5f00c2b6.
It also fixes an issue with the MP Lobby chat box (and other such widgets that use formulas
for their fixed dimensions) where it would stay too small after a window resize (the chat
box formulas in all three dialogs it appears in are a percentage of window height).
as is done in rest of wesnothd. This also fixes crash from self-kick
due to it trying to continue processing looking for further tags
after /query kick kicked the user in quesion.
Besides replacing the "End of file" error when getting disconnected from
the server under unexpected circumstances (e.g. because the server died)
with a translatable and more intuitive message, this also makes it so
other network error messages ("Connection refused", "Host not found",
etcetera) are displayed in the UI in a slightly clearer fashion, and in
an error dialog that must be dismissed with a click on a button, instead
of a transient message that can be easily missed due to an accidental
misclick.
Closes#3005.
the for those moves get_unit() might return nullptr when it is
when the future map is not applied and some codes deduced from
that that the action is invalid. So we make sure that code does
not rely on get_unit().
i don't really know why the old code had a special case for
`get_turn(next) != turn_of_position`, from what i see `turn_end(0)`
would basicially return the same value as `next`. The new code removes
that special case which resulted in assertion failures before (#1841)
and also consiers the case where `position` appears multiple times in
`turn_beginnings_`
the assumption
(turn_beginnings_[num] == it) => (get_turn(it) == num)
might be wrong in case that we have a turn with no actions, in which
case turn_beginnings_ contains duplicates and we actually want the upper
bound of (x <= it) in turn_beginnings_
[ci skip]
This is currently only the case on the 1.14 server, but it's easiest just to
remove the line completely rather than constantly adding or re-adding it based
on whether you're using a or dev series.
I had to move the implementations of certain context-related functions into the cpp
file since the result types were incomplete in the header, which doesn't work with a
unique_ptr (you get errors about being unable to delete an incomplete type).
commit 3effecd added an "if" block in CMakeLists with a variable that
does not exist ("NLS"). This breaks running translation updates for
every cmake user. Changed the variable to the existing "ENABLE_NLS".
@Pentarctagon I don't know if the travis script has to be adjusted as
well. Please test.
This work since vector::at throws if i < size(), and the current check was for
> size() - 1, which equated to >= size(), which is equivalent to not < size().
It does lose the error message, though.
Because updating and sending messages to lobby in staging screen hasn't
been implemented, showing lobby history there would be confusing
(it would look as if everyone had stopped talking).
Two of these strings were not a fix, just a removed string, so no need for pofix.
The other was not specific enough for pofix to match unambiguously.
Also, someone forgot a comma somewhere, causing a syntax error.
This reverts commit fb866c6d13.
This fix is specific to master and translators aren't supposed to be
touching master at this time. There is no point to its existence.
Three cases could not use emplace_back since the ctor they use is private... :(
Which sucks since unit_animation looks like it'd be a bit expensive to copy.
This commit does a few things:
First, it moves the hotkey category names out of the preferences dialog and into
the more appropriate hotkey file. Each name is now properly mapped to its corresponding
category enum, so we don't have to worry about that anymore.
Second, it adds a new mapping of hotkey categories to commands so one can easily fetch
a list of hotkeys in a given category.
Third, it excludes categories with no hotkeys from the filter dropdown in the Prefs
dialog (this is the part that actually fixes the bug above).
This also includes a slight behavior change to hotkey type filtering. Previously, if a
hotkey's category didn't match any of the ones listed in the dropdown, that hotkey's
row visibility would be set to the toggle state of the first row in the filter dropdown.
Now it gets set to false.
Reported in https://forums.wesnoth.org/viewtopic.php?p=626344#p626344
Regression from commit a3d5b9d603.
The crash occurred when
* the attacker had only one weapon
* the said weapon was disabled, and
- the defender had no weapons
- the defender had only one weapon, or
- all defender's weapons were disabled
These are only the ones were it's sufficiently unambiguous that the
description is referring to the merfolk race at whole. There are a few
instances I didn't touch were it's possible that the text refers
exclusively to mermen fighters (e.g. "the mermen armies").
See issue #2940.
[ci skip]
The comment at the start of 01_Tutorial_part_1.cfg wasn't immediately
before a string, so the hint for translators wasn't in the file that
goes to the translators. Fix it so that the tutorial shows working
usage of "# po:" style comments; this is probably more help to people
using the tutorial as a reference for WML, rather than the translators
themselves.
Travis now also makes use of this to set the optimization level for the -O0 builds, rather than extra_flags_*. This additionally fixes an issue where using -O0 in the release build with LTO resulted in the individual *.o files being compiled with -O0, but LTO then still linked with release's default -O3.
previously, if people wanted to make use of mp leader selection in mp
campaign they had to sxplicitly set no_leader=no and faction_lock=no,
with the new code its clear that no_leader= is just an alias for
faction_lock with type
Includes a minor cleanup of the Game Stats dialog to not use a game_board reference.
Dunno why I was taking a game_board reference in the show() function anyway... the
class held a display_context reference and didn't use any functions exclusive to
game_board.
This is to avoid confusion with filter_context::get_disp_context. display used to
inherit from filter_context, but that was refactored out a while back. I left
get_disp_context since it was used and useful, but I realize now it causes more
confusion than not.
Also converted help::load_terrain_types_data to use get_map() directly since I
noticed it.
And changed a stray use of `thedisp` to `disp` in unit_drawer. Doesn't do anything
but it was bugging me.
This was essentially only needed for the affects_side() helper. THAT'S IT. All this code just for
one single line... Anyway...
Utilized the display singleton's display_context getter instead. This also means fewer explicit
uses of resources::gameboard as the display_context object, meaning more compatibility with the
editor (not that that's relevant for most of the changed usecases, such as the AI, but it does
affect unit::get_abilities, which might be useful there in the future).
This also removes the display_context parameter from unit::invisible() since it was only passed to
unit::get_ability_bool().
unit::is_visible_to_team() also had its display_context parameter removed. It was used once as an
argument for invisible() and the other case was replaced with display::get_map().
Instead of a pointer to a member of a derived class, used a virtual function implemented
in both derived classes (game_display and editor_display) that return an reference to the
appropriate object.
Also removed the overlay.hpp include from display.hpp. We can forward-declare the overlay
struct.
After some discussion, we concluded that this code was unmaintained, not even used in
some places (display.cpp, units/frame.cpp), leaving the only area that really used it
at all the image surface cache. Considering there was never really a conclusive benchmark
of its benefits and because said surface cache will be used a lot less going forward,
we're just removing it and simplifying everything for everyone.
Closes#1260 since it's now irrelevant.
Closes#2914.
This doesn't break the string freeze since it reuses a format string
from the same textdomain required by gui2/game_version for the exact
same purpose.
This covers several things:
Instead of creating a new worker thread manually and having it set class member state flags,
I instead utilized std::future and std::async. As far as I can tell, this should avoid the
(albeit unlikely) potential race condition wherein the ls could close before loading at all
if the thread was delayed in starting.
Removed the timer interface and split it into two components:
* A drawing callback that handles the animation. This has its granularity retained at 100 ms,
but can be easily adjusted if we want it to go faster.
* A pump monitor that runs much more frequently (every time events::run_event_loop is called,
technically). This handles checking the state of the std::future object and will then close
the window. This makes the loading screen a bit speedier compared to the previous iteration
since it no longer wastes time waiting for the next timer callback to close.
The one bit I'm not 100% sure about is the check for the future object's ready state in the dtor.
Though, relatedly, I wonder if perhaps we should wait for the worker thread to complete in that
case instead of exiting....
Also shuffled a few things around, such as immediately setting enter/esc disabled in pre_show
instead of waiting for everything there to finish.
Do note there occasionally seem to be a few odd issues with the dot animation after this commit.
Will look into that. But it may be some texture cache-related issue...
This also cleans up some unused log defines and a VS 2013 conditional include.
Turns out remove_const alone only removes the const from the pointer, not from the type
itself, so the expression wasn't returning true. This strips the pointer out before removing
const and matches against char instead of char*
The code was checking that the From type was either char* or const char*. Replaced it
with an equality check against char* with the const stripped from From so both match.
dispatcher::has_event called the private find() function, which after a whole bunch of
jumping around essentially checked that the signal queue for the given event was not
empty. This was a run-time op, yet the code was set up using SFINAE in order to for
has_handler::oper() to call the event_signal function corresponding to the event's queue
(ie, the mouse queue for a mouse-type event).
Since this code was written before the era of constexpr, event type validation was done
using boost::mpl, which, in this case, resulted in a monstrous amalgamation of build-time
template specialization for a run-time check. I'm not certain, but I believe it might
have resulted in an specialization of find() (or at least, implementation::find()) for
every single event type (each member of the ui_event enum).
This converts the code to a purely run-time check and throws out all the template stuff.
It also removes the relevant event_signal overload dealing with events in a set. The
version dealing with function types is preserved as it's used in the fire_event()
implementation and is a fairly standard usecase of SFINAE.
The has_handler class has also been converted to a static function since it's no longer
needed for template specializations in find().
And finally, is_raw_event had to be renamed to is_raw_event_event to allow simple name
completion in IMPLEMENT_RUNTIME_EVENT_SIGNAL_CHECK. I could have also renamed the raw event
queue to signal_raw_queue but I figured keeping the name as signal_raw_event_queue made
its purpose clearer.
These are used to hide an add-on from listings and deny the author the
ability to upload or delete it or change its passphrase. This is
meant to be used when enforcing add-ons server rules that do not justify
deleting all of the add-on's metadata (for example, issues with icons or
descriptions).
This changes the order in which the hook_post_erase hook (currently
unused in production and fully untested) is fired so it will be run
*before* displaying the confirmation message to clients. This might need
to be changed at a later point if the hook functionality ever gets used
again, but for now it'll do.
Turns out that commit broke TC on unit images in messages since it broke the equality
check in lua_unit.cpp. Added the XBRZ IPF as part of the Lua unit portrait attribute
instead.
I *think* this is the proper place to do it.
The intent behind this is that, if there most likely wouldn't be enough time left to complete the unit tests anyway, then just fail the job after compiling so the cache can be updated. Otherwise, if the unit tests were run and the job timed out, then the cache would not be uploaded at all and the next time the job ran it would be from scratch again.
[[noreturn]] is supported on all the compilers we support. Still need to decide
the exact minimum versions and figure out what to do with DEPRECATED and FALLTHROUGH,
so leaving those for now.
And since we require VS 2015 and up we can enable C99 unconditionally.
This is no longer needed with the compilers we support. It is needed on VS 2013, but
we dropped that. Don't know when GCC or Clang stopped needed it (if they ever did).
I'm guessing the "function that returns a value cannot be bound in a function type
that returns void" behavior wasn't an intentional design. Additionally, I don't believe
point 1 raised in the accompanying comment has ever been true... if so, pretty sure
we wouldn't have been able to build at all.
Also removed unnecessary global.hpp include from functional.hpp.
This was never fully implemented and has been essentially abandoned. If we want to
add this again, we should look to adding full game controller support (Steam controller,
for example), though I don't know how suited this game is for controller support. As for
as I can tell, the only working part was ever map scrolling.
Includes a sqrt -> std::sqrt conversion I forgot in this file awhile back.
Locale doesn't rely on boost, so it must have been some other issue in Boost 1.60
that was incidentally fixed by including that file. If anyone ever happens to build
with 1.60 again we can revisit this.
For the record, there are no issues with VS 2017 and Boost 1.66.
It was broken by b95c9996bf because
ignoring SIGCHLD makes it impossible to query exit status of wesnothd
subprocess. Fix this by spawning a thread to wait for the browser
instead of ignoring SIGCHLD.
I originally did this in 699047766a and then reverted it in
08a866dc20 due to @gfgtdf pointing out the object was never
actually destroyed since io_service::stop was never called (issue #1927).
This new method foregoes the custom wrapper class and instead waits for the worker thread
to terminate in the wesnothd_connection dtor. The use of the wrapper class is also why using
thread::detach alone worked (@jyrkive) and using join did not.
Additionally, the ptr alias is now of a unique_ptr instead of a shared_ptr.
I have verified that the connection dtor is actually called. This new method makes it clearer
what's actually going on.
We use both SDL_KEYDOWN and SDL_TEXTINPUT events for hotkeys. It's possible
for both events (caused by the same keypress) to trigger the hotkey command
and we don't want that. Hence, let's drop duplicate commands.
Fixes#1736.
Also covers uses of boost::this_thread.
Turns out std::thread calls std::terminate if it's destroyed while still joinable.
thread::detach needs to be called or else the program will crash.
There's also no standard library equivalent of boost:🧵:timed_join so I just
replaced it with the is_worker_running_ variable.
In scenarios 06 and 14 I turned the opening narrator message into story text instead. The image for 03 isn't used yet as there's no text to accompany it.
Closes#2873.
(This is part of a commented-out block in master because Vultraz hasn't
updated the code yet. He said I could forward-port the patch into it
anyway. For the time being unit descriptions are just completely missing
because of this.)
This reverts commit c42401a8de.
As @CelticMinstrel pointed out, that commit made it impossible to input characters which require
AltGr to type (e.g. @, € and $ in Finnish keyboard).
Reopens#1736.
This reverts afaa75842c and replaces it with a more general
no-assert-during-events check. This is because there are other instances besides [inspect]
where this function can be called mid-event, and it wouldn't be convenient to add nested
'strict' parameters to multiple functions just to handle them.
Fixes#2750.
This results in the same behavior as before (default color outside a scenario, side's
chosen color during one) and is more consistent with other places in the code. They
both end up accessing `game_config::team_rgb_range` anyway, this is just in a slightly
more roundabout way.
I also updated the filenames for the images, changed the recommended
format for screenshots other than "fullscreen" screenshots to PNG,
and removed the (no longer true) claim that the example places to create
the screenshots match where the English screenshots were taken.
Resolves#2856.
[ci skip]
This isn't used anywhere yet. Right now it only takes a directory and generates one
sheet for all the images in that directory and its sub-directories. The sheets are
fully-functional textures, and a path -> rect mapping exists, but I haven't added anything
that uses it yet.
This will definitely need some improvements and changes to properly integrate with @jyrkive 's
OGL work.
I had been unconditionally selecting the first entry after setting the active
sorting option. This overrode the previous unit selection.
Regression from 6b52d16fae.
The problem with them is that the "libraries" into which Wesnoth is split
have circular dependencies, and linking of the game succeeds only by chance
(everything just happens to be used by the time the linker encounters it).
Fixed by allowing the linker to use multiple passes over the libraries
until all references are resolved.
* The one case of get_side_color_range().mid() was converted to get_side_color();
These are equivalent
* get_side_rgb() was removed. Before color_range was refactored to use color_t
(f2ab245e8d), the only difference between it and
get_side_color() was that the former used to return uint32_t (the color they returned
was the same.
* get_side_rgb_min() and get_side_rgb_max() were renamed to get_side_color_min() and
get_side_color_max(), respectively. Both were unused in any case.
* get_side_highlight_pango() was renamed get_side_color_pango() and now takes a 1-indexed
side like the other color functions instead of taking 0-indexed and adding 1.
This changes:
utf8::char_t -> char
utf8::string -> std::string
utf16::char_t -> char16_t
utf16::string -> std::u16string
ucs4::char_t -> char32_t
ucs4::string -> std::u32string
utf16::string and ucs4::string are now proper strings instead of vectors of characters too.
In order to get this change to compile at all, I needed to add a ucs4_convert_impl::convert_impl
specialization for wchar_t alongside the new char16_t specialization; both point to the same
conversion implementation type.
This commit doesn't do any additional cleanup. I'm sure if we looked, we could get rid of a
lot of the custom conversion code and probably a bunch of stuff that might have had to do with
supporting utf16::string and ucs4::string being vectors instead of basic_string specializations.
Either way, I don't know the code (or encoding handling in general) to make a call as to what's
needed or not. I'll let someone else do that.
They're still in the game_config namespace but are now in a more logical header.
game_config::version has been replaced with wesnoth_version.str(), save for one case
where it was replaced with wesnoth_version directly (it was a comparison against another
version_info object; no need to compare against a string...).
Also cleaned up a bunch of game_config.hpp includes.
See https://forums.wesnoth.org/viewtopic.php?p=625159#p625159
Since this problem can also be solved with make_neutral_surface, and is_neutral already
check a surface's alpha mask, I moved the is-not-indexed check to is_neutral and made use
of it for the on-load standardization check.
This ensures the window object is managed by a smart pointer from the moment of its
creation, instead of being passed around as a raw pointer first. If an exception were
thrown during window creation, it would have resulted in a memory leak.
* Moved window_ member assignment to build_window() in both modal_dialog and modeless_dialog.
* Added an assertion after window creation in modeless_dialog.
* Renamed the global build() function to build_window_impl() to avoid confusion with
builder_widget::build.
The problem was that the specials_context was not set during those
two get_special_bool calls
This removes what seems to be a rather useless optimisation in
battle_context::battle_context since choose_attacker_weapon would
just return 0 in that case.
fixes#2801
The problm was that the old code tried to use `undo_stack().can_undo()`
to check whether the current action can be undone. But
`undo_stack().can_undo()` uses the undo stack which is only updated at
the end of each action, so it cannot be used to check whether the action
that is currently executed can be undone.
This code removes some assertion that were wrong due to the
justmentioned.
I didn't realize that is_valid_id was only meant to check IDs provided in the help config and
not IDs generated dynamically; the latter are always correct. Granted, the old code did actually
call its analogous codepath for race and era generation, but it did not for unit sections. My
refactor made it so this check happened *any* time a section was created, regardless of its source.
To rectify that, I moved ID validation for sections into the static section generation loop like
for topics. I also moved the topic id validation prior to the ToD generation, tweaked the invalid
id message, and renamed a variable for clarity and consistency.
* Updated changelog style
I have to do that because maximum size for textfield is 1000x1000 so full changelog doesn't fit there
* Disaled Spell Checking and bumped to 1.13.13
If no display_context was passed to the display ctor (such as is the case in the editor),
the terrain_builder's gamemap pointer would be null. Really not sure why this didn't cause
a crash n the 1.14 branch, but oh well.
I just removed the ctor call to rebuild_all() since it's not really needed. The map is
rebuilt when change_display_context is called anyway, which both the editor_controller and
play_controller do.
This basically splits all the stuff in help/help_impl.*pp into multiple files by their
function, and refactors the entire workflow into a proper object-oriented interface in
modern C++.
There are still a features missing (such as hidden section parsing in the manager) that
I'll get back to.
Few incidental changes and fixes:
* Terrain topics now sorted alphabetically.
* Help text now small
* Fixed wrong toggle button id in browser. This is what was making it impossible to expand
any sections.
The GUI2 help browser is now back in working order, inasmuch as you can view all sections'
and topics' text (save units').
Taking the chest south of the start hid the door and chest that are
north of the start.
The sneak-door opened much earlier in the level, allowing the undead
from the south-east lich to go north to the spider room. The ghosts
and nightstalkers that are supposed to ambush the player's forces in
the south (after opening the 3-hex door) instead go north and end up
joining the spider fight. The slower-moving undead also go north,
and are easily fought one-by-one in the sneak passage instead of the
south-east.
[ci skip]
[ci skip]
This happened incidentally with the current help implementation, but that no longer happens
with my in-progress refactor. We still want these sections sorted, though.
The removal of the "sort_sections=generated" key from the Eras section is a forward-port of
6b20ccdb62 from 1.14.
This matches with the "Another old caved-in passageway..." event
around line 835, the trigger is on 55,33 and the walls that open are
[terrain]
x=55,55
y=34,35
terrain=Uu
[/terrain]
Debian bug #483893, for which the original fix in
4c473187e6 changed the wrong digit.
This is a cherry-pick from 1.14 to master (fixes#2804) of
bcaac1ef (the change) and 5b7aca97 (the changelog).
[ci skip]
this mainly effects wesnoth.synchronize_choices:
previously the client would not process incoming choices from other
players while it was exeucting its own local choice (usually a dialog).
The problem this commit fixes is that with the old behaviour any choice
from another player would block the incoming queue, in particular
chatmessages after that command would be delayed until the
wesnoth.synchronize_choices is finished.
* sun-shyde standing animations, draft
* additions to sun-shyde floating animation
* singer defense animation
* defense animations for sun-singer and sun-shyde
* try to make scout less leaning backwards
* champion defense animation
* fixing and rounding out basic animations (esp. wrt to floating/standing) for sun_shyde
This makes it simpler in the future to have branches that have dependencies that are different from master, rather than having a single image with all necessary dependencies installed, which may at some point end up not being possible to do.
Commit dfc42e8a8d removed said code since
Wesnoth can use IMG_SavePNG() from SDL_image 2.0 instead. However, the
author left the build-time configuration options intact, and also part
of the necessary code for CMake to link Wesnoth against libpng.
Note that this change also eliminates an unnecessary direct link-time
dependency on libpng when using both CMake and SCons.
Otherwise there are too many repetitive strings for translators to work
with, which is rather unfair for an exception like this during the 1.14
RC phase. It also makes for better code.
Also added an article "The" at the start of the strings for :command
notifications.
Storing it in a regular string results in issues with the game getting
stuck with the translation for the locale that was set during GUI2
initialization and not reflecting changes when switching languages later
on.
Used to be a surface drawing helper for blitting on the framebuffer surface.
I made it work with accelerated rendering by forwarding it to render_copy,
but we don't need it anymore. All but one of its usecases have been removed.
This removes all functions related to:
* GUI1 font formatting
* GUI1 font rendering
* Manual text surface size calculations
* The font description interface. While it wasn't exclusive to the TTF rendering system,
it was unused by Pango/Cairo rendering.
A huge chunk of the help browser code was commented out since we don't have font::line_width anymore.
Likewise, a hack was added to the GUI2 text box since we don't have have get_max_height anymore.
font::is_cjk_char was retained (as well as some related helpers) since they might be useful
later.
I'll leave it to someone else to update the CMake/Scons files to remove TTF as a build
dependency.
There's a gettext call but there was nothing to mark the strings as
translatable in xgettext's view. Additionally, fixed a minor case of
missing the colon before the command name, replaced ASCII apostrophes,
and rewrote a notification with awkward wording.
Previously, I had implemented the hint text ("Search)" and image (the magnifying glass)
as a custom text box definition. This caused some problems, though. Since the string was
hard-coded as part of a WFL formula, it couldn't be translated (see #2709 and #2732). It
also wasn't expandable to any other usecase.
Instead, I've added two new hint_text= and hint_image= keys to [text_box], wrapped the
"Search" text and magnifying image path in a helper macro, and refactored the default
definition to display the hint text and image when appropriate.
This also fixes a minor issue where selected text wouldn't remain highlighted when the
box wasn't focused when using the filter definition (it did with the default one).
This should fix the untranslatable "Search" text issue mentioned in both issues above.
The new string is in the wesnoth-lib textdomain.
Resolves#2748.
Essentially, all this did was tell users to go use the forum, so it wasn't worth
it to keep it and solve the infinite loading screen issues it was causing.
The server backend still needs to be cleaned up.
Also removed a dead reference to some "Change Username" button in the Login dialog's
code.
in linger mode.
playmp_controller::play_linger_turn calls play_slice after processing
end_linger/[notify_next_scenario] which would (after 'fix chat in
[delay]' commit) then read more data from the network in particular data
for the next scenario which will then be lost.
with the 'fix chat not working during delay/animation' it could happen
that play_slice_catch would process a incoming controller change in
which case that while loop would end without the code inside that 'if
(player_type_changed_)' being executed, which woudl lead to oos errors
since that client woudl have made moves that other players don't have.
[ci skip]
Source: https://dejavu-fonts.github.io/Download.html
I haven't done any codepoint list updates in data/hardwired/fonts.cfg, but that's
not relevant anymore since it's for the legacy TTF rendering system which is in
the process of being removed.
[ci skip]
Source: http://arkandis.tuxfamily.org/adffonts.html. Previous version was 1.006 (FFEdit).
Also includes the italic and bold variants we didn't have before.
Thanks to @sevu for finding this updated version. :)
This is the current default, and even though the job uses scons this also sets the osx version to use. Therefore it's better to set it explicitly in case the default changes at some point.
These were never intended to go in that commit at all. I accidentally included them.
This reverts the semantic changes. The rest was just formatting so I'm leaving it.
The Boost unit tests have been failing since I removed the GUI2 event context since the
code expects both that A: the topmost context is the global one and B: that you can't
use join() to join the global context. Removing the UI event context meant the test's
fake_display event_context became the only (and global) context, causing an assert.
Textures can't be created with faked video. That's pretty much the only
reason why creating that texture can ever fail (other cases, such as
credits, stress the text rendering system much more than floating labels).
utils/travis/install_deps.sh - no longer executes anything outside of the osx if block.
utils/travis/exit_wrapper.sh - I honestly don't know why this exists.
utils/travis/test_wrapper.sh - No longer used as of 7ca5a0df64.
This removes the -g option from the xcode travis build, since debugging information isn't needed and the increased size was causing the cache to timeout when compressing and uploading it. ccache max cache size is also decreased from 2 GBs to 200 MBs, which matches the linux+cmake builds. Fixes#2670.
This replaces the use of the boost::mpl::set lists. It replaces those damn things with simple
constexpr functions that check the template parameter against an accepted list for each event
type. This is a *lot* simpler.
These helpers are also used in the runtime checks in dispatcher::fire.
I've had to leave the mpl sets in, though, since I can't figure out how to convert the last
place where they're used. The presence of a type is required for SFINAE in
dispatcher_implementation::event_signal, and I can't figure out a new design that avoids the
need for the template parameters.
This function only ever had an implementation when building the i18n API
to use libintl instead of Boost.Locale was possible, in which case its
implementation would be a std::setlocale() call specific to POSIX
systems.
I'm not backporting this to 1.14 since it's an inconsequential cosmetic
thing, or so I'd like to think. Last time someone tried to remove a
similarly empty "init" function elsewhere, things went south pretty
quickly.
This drops a preprocessor conditional branch that is dead code now that
the file pulls gettext.hpp and the GETTEXT_DOMAIN defaults with it.
See also PR #2711.
There are cases (deprecation.cpp for one) where string_utils.hpp is
included first, which causes the VGETTEXT/VNGETTEXT definition to use
the textdomain-less (a.k.a. forced wesnoth-lib textdomain) overloads of
vgettext() and vngettext(), because GETTEXT_DOMAIN has not yet been
defined by anything. This again results in strings being looked up in
catalogues where xgettext is not adding them.
This is a companion for PR #2711 I should've noticed sooner. Without it,
there were still cases where interpolated strings would not be
translated due to vgettext() using the wrong textdomain for them.
I ran a quick scan on the codebase to make sure there aren't any files
including formula/string_utils.hpp before defining their own
GETTEXT_DOMAIN instead of the gettext.hpp default.
The vgettext() function, while declared in src/formula/string_utils.hpp,
actually has its implementation out-of-line in
src/formula/string_utils.cpp where GETTEXT_TEXTDOMAIN is defined to
"wesnoth-lib". Because vgettext() is implemented in terms of the _()
function (an inline wrapper around translation::dsgettext()), it passes
the textdomain defined in the file where it was implemented as a
parameter.
This means that every case of vgettext() being used in other code units
where GETTEXT_TEXTDOMAIN is not defined to "wesnoth-lib", is broken if
the string being looked upon doesn't coincidentally exist in the
wesnoth-lib textdomain.
Ages ago, to work around this limitation, an overload of vgettext() that
takes the textdomain name as a parameter was introduced (see commit
0ba3d05204). Since this form of vgettext()
is rather unwieldy to use (and in particular, the xgettext message
extraction tool mistakes the first argument for the msgid, see below), a
VGETTEXT() macro was also added that uses the GETTEXT_TEXTDOMAIN symbol
defined in the file where the call is made, and thus we get the correct
string from the correct textdomain.
Switching all cases of naked vgettext() in mainline to VGETTEXT() fixes
a myriad of situations where an interpolated string that has an extant
translation does not actually get translated in practice because of the
mismatched textdomain reference (see issue #2709 for an example with MP
game titles). I couldn't find any cases of the companion vngettext()
function (which handles plurals) being used in the wild naked, but for
future reference it also has a companion VNGETTEXT() macro to pass the
correct textdomain to its textdomain-parameter overload.
One caveat is that this commit DOES break the string freeze in one
particular case -- src/units/unit.cpp has a case where the
textdomain-parameter version of naked vgettext() was in use with
"wesnoth" as the first parameter, and xgettext misidentified this as a
translation entry for a "wesnoth" string in the file's assigned
textdomain (which is the default textdomain, wesnoth). So this will
result in the next pot-update both removing the spurious "wesnoth"
string AND adding the correct string to the relevant catalogue template
("<span color=\"$color\">$number_or_percent</span> HP").
to that textdomain.
Other than that, I believe this does not break the string freeze in any
other fashion and it shouldn't result in any regressions for i18n.
It might be worth considering in the future renaming vgettext() and
vngettext() to names that make people less likely to misidentify them as
functions they can freely call directly without regard to the textdomain
assignment issue.
Report drawing was handled in draw_sidebar, so that function was also removed. The display
class won't be handling sidebar drawing anymore anyway.
Also removed display::invalidate_game_status and game_display::invalidate_unit which were
both used to set a flag dealing with report drawing.
This should finally get the display class close to map drawing only.
This reverts commit 29ee9a7150. It broke GUI2 schema validation
for keys with formulas. Also, it seems std::regex does have a form of match_not_dot_null
(std::regex_constants::match_not_null). Will need to rethink.
StackOverflow tells me boost::regex used Perl regex, whereas the stdlib regex does not. Shall
have to confer with @celticminstrel...
This was put off when we first transitioned to C++11 since GCC 4.8 didn't have full
regex support. Since we now support at least GCC 5, we can commit this.
This covers:
* boost::regex
* boost::regex_match
* boost::smatch
* boost::sregex_iterator
* boost::sregex_token_iterator
boost::regex_constants::match_not_dot_null doesn't have a stdlib counterpart, but according to
@celticminstrel it should be alright to remove it.
Made use of them where applicable. There are a whole bunch of cases where the dialog
object only exists to check its return value, but I'll update those separately.
Design change from 075a9bac34.
After discussion with @celticminstrel, we decided it better for the controller to
own the UI object as well as the display object, instead of the display owning the UI.
I've added a pure virtual function declaration to controller_base to ensure all controllers
implement this.
Unit tests (WML and C++ alike) require that the fake screen has nonzero
size. Thus, we again report a nonzero screen size with a fake screen.
Unfortunately, this didn't fix the unit test I was testing
(test_end_turn). The problem is that the null theme is returning that
the game area has zero size; however, I haven't found any differences
between 1.13 and master that would explain why the problem occurs in
master but not 1.13. I'll need to debug 1.13 separately later on...
This almost completely removes GUI1, save for the button widget (will remove once I get
all the Theme handling sorted out) and the editor's own GUI1 widgets.
This includes the GUI1 textbox, scrollbar, scrollarea, and menu widgets, as well as the
dialog_frame and dialog_manager classes. I've also removed floating_textbox. It was only
kept around for reference (it's unused as of the inclusion of the GUI2 command console).
gui::in_dialog has been replaced by GUI2's is_in_dialog directly now that we have no more
GUI1 dialogs.
\o/
* Switch libeay32 to libcrypto for OpenSSL 1.1.0 update in https://github.com/aquileia/external/
* Added recent source additions not yet present in MSVC projects.
* Miscellaneous minor tidying/sorting in filters and build configurations.
[ci skip]
Attempting to launch it crashes the game (probably to do with a null video surface),
and since it's being replaced there's no point in restoring it to functionality.
The implementation details (help_menu, etc) have been left for now. Will remove soon.
This also means the GUI2 help browser is shown by default now.
I decided to go with a modular approach, where both in-game and editor UI dialogs inherit
from a single base class, a pointer of which is owned by the display class. That can be
used for common functionality that needs be shared by all in-game dialogs.
Right now the new UI is just static. It works with most stuff, but not key presses. Working
on that...
This was the core of the surface-based drawing engine. Unused now. The drawing_queue_add()
calls throughout the code have been left, but commented out, for reference while reimplementing
things. The actual drawing_queue code has been left to, since its layers are referenced in
places. Need to remove them.
We can't use deprecated functions. If you want to replace it, replace it and delete the old function. But don't do half the job and expect a clean build!
The purpose of the shape caching is essentially to allow multiple draws to consecutively add to
previously drawn content. It essentially adds another condition for clearing the texture prior
to rendering.
I also moved the shape list handling into the draw function itself so it's only executed once
if needed instead multiple times when calling functions like set_variable - not that it actually
would have done anything after the first call, but this allows me to keep the clearing-the-texture
code in one place.
Not completely done yet, still need to get some stuff working, but this gets rid of the old commented-out
code and puts stuff mostly in the right place.
Instead of using the minimap surface method (which was getting converted from surface to texture every
draw cycle since the caching mechanism the canvas implemented wasn't available and the weird custom
cache the widget implemented itself didn't seem to do actually do anything) we use the new render-to-
canvas-texture method which is a lot cleaner and should be a lot faster. This also means we no longer
override styled_widget::impl_draw_background.
Do note I might use the design of the removed cache here to add some age functionality to the
font::pango_text cache.
Previously widgets that wanted to implement custom drawing behavior overrode styled_widget::impl_draw_background
or impl_draw_foreground. Those functions in the base class simply called the canvas render methods. Some widgets
such as the minimap ignored that rendered the contents on their own.
This new method allows rendering directly to the canvas's texture, meaning all the caching and sizing is already
handled by the canvas and doesn't need to be done by the widget; everything's always the right size and redrawn
when necessary.
I've left the old getMinimap function alone and added a new function that will eventually replace it
that utilizes texture rendering to a given texture instead of relying on surface blits and scaling.
This has the benefit of, well, reducing surface ops, for one, as well as removing the need to create
a new texture from the minimap surface every time it's updated.
Instead of throwing out the cached texture every time the canvas was dirty, I've added a flag so that
only happens if its size has actually changed. There still seem to be some issues in GUI2 where canvas
objects keep getting reset, but I'm not sure why. Will have to look into that.
Anyway, the addition of the SDL_RenderClear call also seems to have fixed the weird graphics bleed-through
I was getting when running the game with the OGL driver.
I don't know if the canvas copy or move ctors are needed for anything. I added them for a test, but I'll
leave them for now in case I need them later.
* Removed display::screen_area(), display::w(), and display::h().
* Moved the global screen_area() function into the CVideo class.
* Renamed CVideo::getx() and gety() to get_width() and get_height()
* Made those two functions return the result of screen_area() instead of the other way around.
* Added preliminary support for high-DPI rendering to screen_area()
Note on the last point: When I fixed bug #1772 (aa8f6c7e7 right now but will probably change with rebasing)
I noted that SDL_GetWindowSize and SDL_GetRendererOutputSize returned the same results for me (even with
Window's automatic scaling for non-high-DPI-enabled apps disabled) but that the SDL documentation stated the
former returned screen coordinates and the latter pixels. In that same commit I changed the dimension functions
to use SDL_GetWindowSize. I've now reversed that decision and gone back to using SDL_GetRendererOutputSize so
I can guarantee output in pixels. If use_pixels is false, the code will return coordinates in 96 DPI, so I need
to have pixel measurements for the calculations.
Again, though, I do not know if SDL_GetWindowSize returns a different value that pixel size (which it's said
to do) on macOS or iOS. I'll need to do some testing. It's possible on those platforms I won't need the 96 DPI
measurements, but it's also possible it will be needed on on platforms, since all of our code relies on pixel
measurements.
This is primarily focused on getting various areas of the game display drawing, such as footstep images
and the terrain defense indicators.
To facilitate the last, I've refactored draw_text_in_hex to utilize floating labels instead of drawing
to hex directly with surfaces. This probably isn't the most optimal solution, since labels are continuously
created and destroyed, but since their text is usually short and cached in the rendered text cache it
does for now.
Also includes some cleanup of deprecated functions in display, and slight reordering of drawing order of
certain elements.
I've moved the terrain hex drawing code directly into draw_visible_hexes instead of relying on get_terrain_images
to return a vector of all the necessary images for each visible hex and then drawing them. Instead, we now draw
each hex's images immediately without any intermediary container.
With the old method, after about 10 to 15 seconds of drawing we had already allocated (and destroyed) almost 180,000
temporary vectors (a new one was created for each hex, twice per draw cycle). It's obvious how quickly that would add
up over a normal play session, and though in this case the performance hit for creating each vector was probably tiny,
creating them likely would have added up.
* Made reset() a public function
* Added an assign() function
* Don't try to destroy null textures
* Updated doc comments
I left assign() as just taking an SDL_Texture ptr since having it take a texture ref would be
functionally equivalent to operator=.
Previously, every visible hex was iterated over and every element in that hex draw. This was inefficient
for two reasons: First, it meant the performance footprint for many operations like unit drawing was O(n²),
since the list of elements had to be checked for every single hex. Second, it meant the renderer had to
switch active textures many more times than necessary.
My new system involved drawing every element of a specific type at once - ie, all background terrains at
once, all units, all items, etc. This reduces lookup time from O(n²) to O(n) and results in a noticeable
performance increase. It also reduces the number of times the renderer needs to switch active textures,
since bulk draws such as the map grid overlay are now done all at once while that specific texture is
active.
There are still some layering issues and missing elements that need to be sorted, especially in game_display.
This no longer actually does anything now that location invalidation is removed. If you follow the code
animation_component::invalidate called unit_animation::invalidate which was responsible for generating
the overlaped_hex_ set. Previously, this is what locations were invalidated. Now it didn't do anything.
This removes all the code related to invalidating locations, any functions used to set, modify, or propagate
location invalidation, and several functions that no longer serve any purpose anymore since their only purpose
was to handle invalidated locations.
NOTE: for some reason, if I remove the `SDL_RENDERER_TARGETTEXTURE` flag from sdl::window's ctor
render_flags argument, this assertion still doesn't throw. Not sure if that means by GPU supports
it by default, or what.
Previously, drawing was handled with custom DRAW and DRAW_ALL events which individual event handlers
managed. DRAW was used for only-as-needed draws, and DRAW_ALL for drawing everything. As we've switched
to accelerated rendering, we've switched to the latter model all the time; everything is always drawn.
Both DRAW and DRAW_ALL events aren't needed anymore and have been removed. Instead, we simply call each
handler's draw() function directly from events::pump. The two main cases that handled draw events - the
display class and GUI2 - just forwarded the event handler calls to their respective draw() functions anyway.
Awhile back to unconditionally send draw events to the event queue constantly every 20 ms. However, to prevent
draw calls from becoming backed up, the queue already had code to remove all but 1 draw event from the queue
anyway, so the actual rate of drawing was still reliant on the rate at which events::pump was called. Therefor
this commit should result in no change at the rate the screen is drawn.
* Store label as a texture instead of creating a texture from a surface every draw cycle
* Restored expired label removal and alpha fadeout (was accidentally removed earlier in my refactoring)
* Use alpha field of bg_color member for background color
* Draw tooltip backgrounds procedurally instead of with surfaces and part of the label texture itself.
See included comment for small caveat.
The old floating textbox was extremely entwined with the controller_base, play_controller, and menu_handler
classes. controller_base::have_keyboard_focus essentially controlled whether some events were executed based
on whether the floating textbox was open or not. Additionally, those events weren't even reached if a UI dialog
was open at all.
The new design features a singleton console class that can be called from anywhere, not just the game. I've also
decoupled the execution object from play_controller. The relevant functions in menu_handler are now passed to
the console as callbacks.
To work around map events such as clicking not being available if the console was open, I removed the exclusionary
is-in-dialog check from controller_base::handle_event and instead exit early out certain types of events using
controller_base::have_keyboard_focus. As mentioned in the accompanying comment, this isn't the best solution, but
it will do for now.
The new console also isn't fully feature-comparable with the old GUI1 one. The following are still missing:
* The checkbox, for use when sending messages.
* Tab completion.
* A crash occurs when existing the app if a game was exited with the console open.
I'm leaving the old floating_textbox code around for now for reference.
The reason I added this was so I can refactor some temporary pango_text objects out of the display class.
styled_widget doesn't use this for reasons explained in the comment.
With textures, you can't change render scale quality once they've been created. To rectify this, I've
made the texture caches a map of caches, sorted by scale quality. This should result in no performance
overhead, since an image is simply added to the appropriate quality cache on creation instead of in
a single cache. If a different version of a texture is needed it will be loaded later.
By default, load_texture will return images using nearest neighbor scaling. GUI2 always fetches images
using linear scaling. This is consistent with the old software rendering method. Plus, we don't have
any way (as of now) to specify the render quality on a per-image basis.
This basically rips out all the unrendering and invalidation code. Neither is needed anymore.
Instead, we can have a simple, clean, "just draw the managed halos" interface.
Note there's an issue unrelated to this where halos aren't removed when a unit is killed with
the debug kill menu command.
The one in Outro was unnecessary since set_variable already calls set_is_dirty.
The one in the Story Viewer was there to deal with some background redraw issues which no longer appear
with the new drawing methods.
Originally was going to do this as workaround for the background tiling over the borders,
but I fixed the root cause of that instead. Still, this just makes more sense.
In the interests of getting this all done faster, I've decided to postpone work on the OGL implementation for now
and focus on the SDL_Renderer version. This contains some basic code (include-guarded) for setting up an OGL context
for the main SDL window.
The only real reason to keep using a surface was in order to have resize mode manipulations. I've now added
texture-only handling methods (the tiling one was borrowed from display.cpp's draw_background function).
Instead of always loading a surface at the same time, textures are now loaded directly from disk if applicable.
Instead, surfaces are only loaded if applicable to apply some effect that cannot as of now be done with texture
manipulation since we dont have shader support yet.
In that vein, I've also added two new texture caches, one for masked-to-hex images and one for ToD colored images.
Again, useless since there's no more window surface with accelerated rendering.
getSurface() remains since it's still used in quite a lot of places. Will removed ASAP.
This allows multiple texture objects to refer to the same texture without destroying them prematurely.
This is different from the SDL_Surface wrapper's implementation since surfaces have their own internal
refcounting system; textures do not.
Do note that setting an empty rect in render_raii_rect_setter_base is not the same as passing nullptr.
If an empty rect is passed to SDL_RenderGetClipRect, for example, you can end up with nothing drawing
since everything is being clipped.
It turns out I had removed the clip rect setting in error; it prevented items in, say, a listbox from drawing
outside the widget's boundaries. I've re-added that now.
I've also moved viewport setting to the same place. It turns out it didn't need to be set every canvas draw.
The only reason the old code was passing the blitting rect to the canvas was it was needed for the sdl_blit call.
Since I can now set the viewport independent of a canvas state, there's no longer a need to set the viewport in
the canvas.
This is no longer needed since we redraw everything every frame. The dirty flag in the canvas remains
as that controls whether the cached texture is used or recreated.
This entirely refactors surface blitting out of the canvas. Instead, each canvas owns a texture. This texture
is completely redrawn any time the canvas if marked dirty, else the result is cached and drawn to the screen
each draw cycle.
All windows are now redrawn every draw cycle. The use of the cached canvas textures means there's no noticeable
performance difference (likely a performance gain, actually) from using surface blitting.
There's still some code to clean up and a few things to fix.
This completely removes the wrappers for aliases included in c++14. It also enables
use of the value alias wrappers, since we now have variable templates.
('extra_flags_profile', 'Extra compiler and linker flags to use for profile builds', ""),
BoolVariable('enable_lto', 'Whether to enable Link Time Optimization for build=release', False),
('arch', 'What -march option to use for build=release, will default to pentiumpro on Windows', ""),
('opt', 'override for the build\'s optimization level', ""),
BoolVariable('harden', 'Whether to enable options to harden the executables', True),
BoolVariable('glibcxx_debug', 'Whether to define _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC for build=debug', False),
EnumVariable('profiler', 'profiler to be used for build=profile', "gprof", ["gprof", "gcov", "gperftools", "perf"]),
EnumVariable('pgo_data', 'whether to generate profiling data for PGO, or use existing profiling data', "", ["", "generate", "use"]),
@ -79,7 +81,6 @@ opts.AddVariables(
PathVariable('python_site_packages_dir', 'sets the directory where python modules are installed', "lib/python/site-packages/wesnoth", PathVariable.PathAccept),
BoolVariable('notifications', 'Enable support for desktop notifications', True),
BoolVariable('nls','enable compile/install of gettext message catalogs',True),
BoolVariable('png', 'Clear to disable writing png files for screenshots, images', True),
description=_ "Number of seconds to wait for a ping reply before timing out. Set to 0 to disable"
type=int
default=0
min=0
max=60
step=5
[/advanced_preference]
[advanced_preference]
field=lobby_auto_open_whisper_windows
name=_ "Auto-open whisper windows in lobby"
@ -150,12 +139,6 @@
default=yes
[/advanced_preference]
[advanced_preference]
field=advanced_graphic_options
name=_ "Graphics scaling options"
type=custom
[/advanced_preference]
[advanced_preference]
field=orb_color
name=_ "Customize orb colors"
@ -177,207 +160,22 @@
[/advanced_preference]
[advanced_preference]
field=show_halos
name=_ "Show haloing effects"
description=_ "Show special unit graphical effects"
field=show_deprecation
name=_ "Show deprecation messages in-game"
description=_ "Show warnings about deprecated API in the in-game chat area. These messages will still be shown in the log, even if this is disabled. In addition, the deprecation log-domain controls how many messages are printed."
type=boolean
default=yes
default=no
[/advanced_preference]
[advanced_preference]
field=use_prng
name=_ "Use experimental PRNG combat"
description=_ "Enables more determinstic chance-to-hit calculations. This is an experimental feature designed to bring the observed hit/miss rate more in line with the displayed percentages.
Note: this option only affects singleplayer, and the ‘Save random seed’ option must also be enabled when creating a game for this to work."
type=boolean
default=no
[/advanced_preference]
#ifdef __UNUSED__
[advanced_preference]
field=show_deprecation
# TODO: Add translation marks and enable this after 1.14
name="Show deprecation messages in-game"
description="Show warnings about deprecated API in the in-game chat area. These messages will still be shown in the log, even if this is disabled. In addition, the deprecation log-domain controls how many messages are printed."
type=boolean
default=no
[/advanced_preference]
[advanced_preference]
field=joystick_support_enabled
name=_ "Joystick support"
type=boolean
default=no
[/advanced_preference]
[advanced_preference]
field=joystick_num_scroll_xaxis
name=_ "Joystick: number of the scroll X-axis joystick"
type=int
default=0
min=-1
max=3
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_scroll_xaxis_num
name=_ "Joystick: number of the scroll X-axis"
type=int
default=0
min=0
max=7
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_num_scroll_yaxis
name=_ "Joystick: number of the scroll Y-axis joystick"
type=int
default=0
min=-1
max=3
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_scroll_yaxis_num
name=_ "Joystick: number of the scroll Y-axis"
type=int
default=1
min=0
max=7
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_scroll_deadzone
name=_ "Joystick: deadzone of the scrolling stick"
type=int
default=1500
min=0
max=16000
step=500
[/advanced_preference]
[advanced_preference]
field=joystick_num_cursor_xaxis
name=_ "Joystick: number of the cursor X-axis joystick"
type=int
default=0
min=-1
max=3
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_cursor_xaxis_num
name=_ "Joystick: number of the cursor X-axis"
type=int
default=3
min=0
max=7
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_num_cursor_yaxis
name=_ "Joystick: number of the cursor Y-axis joystick"
type=int
default=0
min=-1
max=3
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_cursor_yaxis_num
name=_ "Joystick: number of the cursor Y-axis"
type=int
default=4
min=-1
max=7
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_cursor_deadzone
name=_ "Joystick: deadzone of the cursor stick"
type=int
default=1500
min=0
max=16000
step=500
[/advanced_preference]
[advanced_preference]
field=joystick_num_mouse_xaxis
name=_ "Joystick: number of the mouse X-axis joystick"
type=int
default=-1
min=-1
max=3
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_mouse_xaxis_num
name=_ "Joystick: number of the mouse X-axis"
type=int
default=0
min=0
max=7
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_num_mouse_yaxis
name=_ "Joystick: number of the mouse Y-axis joystick"
type=int
default=-1
min=-1
max=3
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_mouse_yaxis_num
name=_ "Joystick: number of the mouse Y-axis"
type=int
default=1
min=0
max=7
step=1
[/advanced_preference]
[advanced_preference]
field=joystick_mouse_deadzone
name=_ "Joystick: deadzone of the mouse stick"
type=int
default=1500
min=0
max=16000
step=500
[/advanced_preference]
[advanced_preference]
field=joystick_num_thrusta_axis
name=_ "Joystick: number of the thrust axis joystick"
W.message {speaker=hunter.id,message='I made it home - resting now until the end of Turn '..hunter_vars.resting_until..' or until fully healed.'}
wesnoth.wml_actions.message {speaker=hunter.id,message='I made it home - resting now until the end of Turn '..hunter_vars.resting_until..' or until fully healed.'}
end
end
@ -185,7 +184,7 @@ function ca_hunter:execution(cfg)
message=_ "There are too many to fight, far too many. We must escape!"
[/message]
# wmllint: unbalanced-on
{MESSAGE narrator "wesnoth-icon.png" "" _"This is a reenactment of scenario The Elves Besieged of the mainline campaign Heir to the Throne, just that the AI is playing Konrad's side here. The goal is to move Konrad to the signpost in the northwest, while keeping both Konrad and Delfador alive. The same AI as in scenario Protect Unit is used.
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "This is a reenactment of scenario The Elves Besieged of the mainline campaign Heir to the Throne, just that the AI is playing Konrad's side here. The goal is to move Konrad to the signpost in the northwest, while keeping both Konrad and Delfador alive. The same AI as in scenario Protect Unit is used.
Note: The Protect Unit AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
Note: The Protect Unit AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
{MESSAGE narrator "wesnoth-icon.png" "" _"Well, that was that."}
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "Well, that was that."
[/message]
[endlevel]
result=victory
@ -335,14 +339,27 @@
[event]
name=start
{MESSAGE narrator "wesnoth-icon.png" "Important Note" _"<span color='#A00000'>Important:</span> The animal Micro AIs in this scenario are written for a number of animal unit types that do not exist in Wesnoth mainline, such as bears, sheep and sheep dogs, or deer. In this test scenario, these units have been replaced by mainline units."}
[message]
speaker=narrator
image=wesnoth-icon.png
caption="Important Note"
message=_ "<span color='#A00000'>Important:</span> The animal Micro AIs in this scenario are written for a number of animal unit types that do not exist in Wesnoth mainline, such as bears, sheep and sheep dogs, or deer. In this test scenario, these units have been replaced by mainline units."
[/message]
# wmlindent: start ignoring
{MESSAGE narrator "wesnoth-icon.png" "" _"This is a fun little scenario with a bunch of different animal AIs, mostly for watching only. The animal AIs behave as follows:
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "This is a fun little scenario with a bunch of different animal AIs, mostly for watching only. The animal AIs behave as follows:
Note that there is no end to this scenario. For demonstration purposes, any unit that is killed is replaced by another unit of the same type at the beginning of the next turn. In order to end the scenario, there's a right-click option - but that only works in human-controlled mode. In AI-only mode, you have to press 'Esc' or reload a previous savefile.
Also note: The Animal AIs are coded as Micro AIs. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information." # wmllint: no spellcheck
Also note: The Animal AIs are coded as Micro AIs. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information." # wmllint: no spellcheck
# wmlindent: stop ignoring
# wmllint: unbalanced-off
[option]
@ -410,8 +427,11 @@ Also note: The Animal AIs are coded as Micro AIs. A Micro AI can be added and ad
[/filter_second]
# wmlindent: start ignoring
{MESSAGE $second_unit.id "" "" _"Yowl!
Translation: Those Ogres are mean! We better stay away from them and their young."}
[message]
speaker=$second_unit.id
message=_ "Yowl!
Translation: Those Ogres are mean! We better stay away from them and their young."
{MESSAGE LuaAI "" "" _"All right, chaps. Those orcs need to be stopped."}
[message]
speaker=LuaAI
message=_ "All right, chaps. Those orcs need to be stopped."
[/message]
{STORE_UNIT_VAR (id=Big Bad Orc) profile profile}
{MESSAGE (Big Bad Orc) "$profile~FL()~RIGHT()" "" _"They there! We them get!"}
[message]
speaker=Big Bad Orc
image=$profile~FL()~RIGHT()
message=_ "They there! We them get!"
[/message]
{CLEAR_VARIABLE profile}
# wmllint: unbalanced-on
{MESSAGE LuaAI "" "" _"We need to hold that pass for as long as we can. Let's put our strongest fighters on the front line and bring injured units to the back for healing. If we're careful enough, we might even win this battle. I'll join you as soon as I'm done recruiting and do my share of the fighting.
[message]
speaker=LuaAI
message=_ "We need to hold that pass for as long as we can. Let's put our strongest fighters on the front line and bring injured units to the back for healing. If we're careful enough, we might even win this battle. I'll join you as soon as I'm done recruiting and do my share of the fighting.
Note: The Bottleneck Defense AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
Note: The Bottleneck Defense AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
# wmllint: local spellings AIs RCA
@ -148,7 +158,10 @@ Note: The Bottleneck Defense AI is coded as a Micro AI. A Micro AI can be added
side=1
[/have_unit]
[then]
{MESSAGE LuaAI "" "" _"I may have fallen, but we will continue to defend the pass to the last man!"}
[message]
speaker=LuaAI
message=_ "I may have fallen, but we will continue to defend the pass to the last man!"
[/message]
[/then]
[/if]
[/event]
@ -181,7 +194,11 @@ Note: The Bottleneck Defense AI is coded as a Micro AI. A Micro AI can be added
controller=human
[/modify_side]
{MESSAGE narrator "wesnoth-icon.png" "" _"Well, that was that."}
{MESSAGE (Dreadful Bat) "" "" _"Be careful to stay out of the way of that dragon. He's a mean one."}
[message]
speaker=Dreadful Bat
message=_ "Be careful to stay out of the way of that dragon. He's a mean one."
[/message]
{CLEAR_VARIABLE profile}
# wmllint: unbalanced-on
{MESSAGE Rowck "" "" _"Hi there. I am Rowck and here is what I do:
[message]
speaker=Rowck
message=_ "Hi there. I am Rowck and here is what I do:
When hungry, I move around part of the map in a random wander until I get into range of an enemy. If enemies are within range, I attack and devour the weakest of them. After that, I retreat to my rest location, where I stay for a certain number of turns or until fully healed.
A few details (features, not bugs, but can be changed if desired):
- If my way home is blocked on the return, the normal RCA AI takes over my behavior.
@ -89,7 +94,8 @@ A few details (features, not bugs, but can be changed if desired):
- A kill only makes me go home when I am the attacker, not as defender.
- Occasionally I will not move at all while wandering (a dragon has to rest sometimes!)
Note: The Hunter AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
Note: The Hunter AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[objectives]
@ -136,7 +142,10 @@ Note: The Hunter AI is coded as a Micro AI. A Micro AI can be added and adapted
[event]
name=end_scenario
{MESSAGE (Dreadful Bat) "" "" _"I'm out of here."}
{MESSAGE narrator "wesnoth-icon.png" "" _"This scenario presents a situation with so many units on the map, that there is a noticeable delay (a few seconds or so) before each move by the default AI. By contrast, the Fast Micro AI has a much shorter delay. To demonstrate the difference, side 1 is played by the Fast Micro AI and side 2 by the default (RCA) AI.
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "This scenario presents a situation with so many units on the map, that there is a noticeable delay (a few seconds or so) before each move by the default AI. By contrast, the Fast Micro AI has a much shorter delay. To demonstrate the difference, side 1 is played by the Fast Micro AI and side 2 by the default (RCA) AI.
There is nothing to do here, just watch or use this scenario as a template or for your own tests."}
There is nothing to do here, just watch or use this scenario as a template or for your own tests."
{MESSAGE narrator "wesnoth-icon.png" "" _"Well, that was that."}
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "Well, that was that."
[/message]
[endlevel]
result=victory
@ -407,14 +411,17 @@
[event]
name=start
#{MESSAGE narrator "wesnoth-icon.png" "" _"Text"}
# wmllint: unbalanced-on
{MESSAGE narrator "wesnoth-icon.png" "" _"This scenario demonstrates a variety of different uses of the Goto Micro AI. All AI sides are controlled by this MAI in one way or another (except for the saurians, which are run by the Lurkers Micro AI). Messages will be displayed throughout the scenario to point out what the units are doing.
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "This scenario demonstrates a variety of different uses of the Goto Micro AI. All AI sides are controlled by this MAI in one way or another (except for the saurians, which are run by the Lurkers Micro AI). Messages will be displayed throughout the scenario to point out what the units are doing.
The player controls Side 1. There are right-click context menu options for adding Side 1 units to the map and for taking them off again. This is useful mostly for testing how the Side 3 guardians react.
Note: The Goto AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
Note: The Goto AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[objectives]
@ -472,10 +479,18 @@ Note: This is a demonstration of how the Goto Micro AI can be used to code guard
name=side 8 turn
{UNIT 8 Ghost 29 1 id=ghost1}
{MESSAGE ghost1 "" "" _"Aaiiieeeeeee !!!"}
{MESSAGE messenger2 "" "" _"O no, a ghost!"}
{MESSAGE messenger1 "" "" _"Don't worry, those are really shy ghosts. Nobody knows why, but they always appear in the north this time of year and move through to the south. Also, very unusually for ghosts, they seem to be scared of everybody and avoid other units as much as possible -- except for the bats and saurians, with which they seem to get along just fine for some reason. So as long as we don't corner them, they'll leave us alone."}
[message]
speaker=ghost1
message=_ "Aaiiieeeeeee !!!"
[/message]
[message]
speaker=messenger2
message=_ "O no, a ghost!"
[/message]
[message]
speaker=messenger1
message=_ "Don't worry, those are really shy ghosts. Nobody knows why, but they always appear in the north this time of year and move through to the south. Also, very unusually for ghosts, they seem to be scared of everybody and avoid other units as much as possible -- except for the bats and saurians, with which they seem to get along just fine for some reason. So as long as we don't corner them, they'll leave us alone."
{MESSAGE narrator "portraits/dwarves/guard.png" _"Standard WML Guardian" _"This is the built-in WML guardian coded using 'ai_special=guardian'. These guardians attack if there is an enemy within their movement range, otherwise they do nothing (except maybe retreating to a village for healing)."}
[message]
speaker=narrator
image=portraits/dwarves/guard.png
caption=_ "Standard WML Guardian"
message=_ "This is the built-in WML guardian coded using 'ai_special=guardian'. These guardians attack if there is an enemy within their movement range, otherwise they do nothing (except maybe retreating to a village for healing)."
{MESSAGE narrator "portraits/trolls/troll.png" _"Return Guardian" _"A 'return guardian' is a variation of the standard Wesnoth guardian. It has an assigned guard position (GP) to which it returns after attacks on approaching enemies:
[message]
speaker=narrator
image=portraits/trolls/troll.png
caption=_ "Return Guardian"
message=_ "A 'return guardian' is a variation of the standard Wesnoth guardian. It has an assigned guard position (GP) to which it returns after attacks on approaching enemies:
- If at GP with no enemy in reach, do nothing.
- If at GP with enemy in reach, leave attack to default AI (note that this may include not attacking if the enemy is deemed too strong).
- If not at GP, return there, no matter whether an enemy is in reach or not.
- If enemies are blocking your way back, do your best to get there anyway.
- If you end up next to an enemy on the way back, attack after the move."}
- If you end up next to an enemy on the way back, attack after the move."
{MESSAGE narrator "portraits/trolls/troll.png" _"Home Guard" _"A 'home guard' is a variant on the 'guardian' AI special. With this variant, the unit has an assigned 'home' location, and will return there if not involved in combat and if not going to a village, whether for healing or to capture it this turn. (By contrast, the standard guardian AI will cause the unit to stay where it last attacked.) This differs from 'return guardian' in that a home guard will press the attack, possibly getting drawn quite far from 'home', rather than returning after each attack. (It can also be lured away by a string of closely-placed villages, but that is something a map builder can control.)
This also demonstrates how to combine candidate actions from Formula AI and Lua AI in one side. The home guard is written in Formula AI, while the return and stationed guardians and the cowards are written in Lua AI. In addition the non-guardian units of the side follow the default AI behavior."}
[message]
speaker=narrator
image=portraits/trolls/troll.png
caption=_ "Home Guard"
message=_ "A 'home guard' is a variant on the 'guardian' AI special. With this variant, the unit has an assigned 'home' location, and will return there if not involved in combat and if not going to a village, whether for healing or to capture it this turn. (By contrast, the standard guardian AI will cause the unit to stay where it last attacked.) This differs from 'return guardian' in that a home guard will press the attack, possibly getting drawn quite far from 'home', rather than returning after each attack. (It can also be lured away by a string of closely-placed villages, but that is something a map builder can control.)
This also demonstrates how to combine candidate actions from Formula AI and Lua AI in one side. The home guard is written in Formula AI, while the return and stationed guardians and the cowards are written in Lua AI. In addition the non-guardian units of the side follow the default AI behavior."
[/message]
[/command]
[/set_menu_item]
[set_menu_item]
@ -467,13 +482,18 @@ This also demonstrates how to combine candidate actions from Formula AI and Lua
{MESSAGE narrator "portraits/undead/archer.png" _"Stationed Guardian" _"A 'stationed guardian' is another variation of the standard Wesnoth guardian with a somewhat more complex behavior than that of the 'return guardian'. Two positions are defined for it, a 'station' and a 'guarded location', as well as a 'distance'. The behavior is as follows:
[message]
speaker=narrator
image=portraits/undead/archer.png
caption=_ "Stationed Guardian"
message=_ "A 'stationed guardian' is another variation of the standard Wesnoth guardian with a somewhat more complex behavior than that of the 'return guardian'. Two positions are defined for it, a 'station' and a 'guarded location', as well as a 'distance'. The behavior is as follows:
- If no enemy is within 'distance' of the guard's current position, do nothing.
- Otherwise: If an enemy is within 'distance' of the guard, but not also within the same distance of the guarded location and the station (all of this simultaneously), move the guard in the direction of the station.
- Otherwise:
- Pick the enemy unit that is closest to the guarded location.
- If we can reach it, pick the adjacent hex with the highest defense rating and attack from there.
- If not in reach, move toward this unit."}
- If not in reach, move toward this unit."
[/message]
[/command]
[/set_menu_item]
[set_menu_item]
@ -484,11 +504,16 @@ This also demonstrates how to combine candidate actions from Formula AI and Lua
{MESSAGE narrator "units/monsters/giant-rat.png" _"Coward" _"Cowards are units that, like guardians, sit around doing nothing until an enemy comes into range. Unlike guardians, however, they run away once enemies approach. Applications might be wild animals, unarmed civilians getting in the way of a battle, etc. The coward macro can be called with two optional locations, 'seek' and 'avoid':
[message]
speaker=narrator
image=units/monsters/giant-rat.png
caption=_ "Coward"
message=_ "Cowards are units that, like guardians, sit around doing nothing until an enemy comes into range. Unlike guardians, however, they run away once enemies approach. Applications might be wild animals, unarmed civilians getting in the way of a battle, etc. The coward macro can be called with two optional locations, 'seek' and 'avoid':
- If neither is given, the coward retreats to the position farthest away from the approaching enemies.
- If 'seek' is given, it preferentially goes toward that location (but getting away from enemies takes priority).
- If 'avoid' is given, it in addition tries to avoid that location (with both maximizing distance from enemies and going toward 'seek' taking priority).
- Both 'seek' and 'avoid' may consist of only one coordinate ('x' or 'y'), in which case not a single hex, but a line of hexes is sought or avoided."}
- Both 'seek' and 'avoid' may consist of only one coordinate ('x' or 'y'), in which case not a single hex, but a line of hexes is sought or avoided."
[/message]
[/command]
[/set_menu_item]
[set_menu_item]
@ -499,9 +524,14 @@ This also demonstrates how to combine candidate actions from Formula AI and Lua
{MESSAGE narrator "portraits/nagas/fighter.png" _"Zone Guardian" _"A zone guardian is a unit that, as the name says, guards a zone. It moves randomly inside this zone until an enemy enters it (or a separately defined enemy zone, see below). Applications might be the defense of a castle or a nesting area. The zone macro can be called with an optional enemy zone:
[message]
speaker=narrator
image=portraits/nagas/fighter.png
caption=_ "Zone Guardian"
message=_ "A zone guardian is a unit that, as the name says, guards a zone. It moves randomly inside this zone until an enemy enters it (or a separately defined enemy zone, see below). Applications might be the defense of a castle or a nesting area. The zone macro can be called with an optional enemy zone:
- If not specified, the zone guard attacks any enemy coming inside its guard zone.
- Otherwise, it attacks any enemy entering the enemy zone and once there are no more enemies, it goes back to patrol in its basic zone."}
- Otherwise, it attacks any enemy entering the enemy zone and once there are no more enemies, it goes back to patrol in its basic zone."
[/message]
[/command]
[/set_menu_item]
[/event]
@ -510,14 +540,25 @@ This also demonstrates how to combine candidate actions from Formula AI and Lua
{MESSAGE (Another Bad Orc) "" "" _"They there! We them get!"}
[message]
speaker=Kraa
image=$profile~FL()~RIGHT()
message=_ "Kraahhh!!!!"
[/message]
[message]
speaker=Another Bad Orc
message=_ "They there! We them get!"
[/message]
# wmllint: unbalanced-on
{MESSAGE Kraa "$profile~FL()~RIGHT()" "" _"Gryphons of the High Plains, look at all these enemies. They don't behave normally. Most of them don't move at all unless we get close. Let's check out how they react to us.
[message]
speaker=Kraa
image=$profile~FL()~RIGHT()
message=_ "Gryphons of the High Plains, look at all these enemies. They don't behave normally. Most of them don't move at all unless we get close. Let's check out how they react to us.
Note to the player: the right-click context menu provides information about each of the units' behavior.
Another note: Most of the Guardian AIs are coded as Micro AIs. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
Another note: Most of the Guardian AIs are coded as Micro AIs. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
{CLEAR_VARIABLE profile}
@ -591,7 +632,10 @@ Another note: Most of the Guardian AIs are coded as Micro AIs. A Micro AI can be
[event]
name=end_scenario
{MESSAGE Kraa "" "" _"Gryphons of the High Plains, it is time to return to said plains. Follow me."}
[message]
speaker=Kraa
message=_ "Gryphons of the High Plains, it is time to return to said plains. Follow me."
{MESSAGE (Good Bandit) "" "" _"That outlaw over there is going to run for the keep in the southeast. He's only going to recruit for three rounds before he'll start moving and he and his footpads are much faster than we are. Let's make haste or we'll never catch him.
[message]
speaker=Good Bandit
message=_ "That outlaw over there is going to run for the keep in the southeast. He's only going to recruit for three rounds before he'll start moving and he and his footpads are much faster than we are. Let's make haste or we'll never catch him.
Note: This scenario uses a combination of two Micro AIs, the Hang Out Micro AI which makes the Side 2 units remain around the keep for two turns (while moving off castle tiles to allow for recruiting) and the Messenger Escort AI which takes over after that. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
Note: This scenario uses a combination of two Micro AIs, the Hang Out Micro AI which makes the Side 2 units remain around the keep for two turns (while moving off castle tiles to allow for recruiting) and the Messenger Escort AI which takes over after that. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[objectives]
@ -141,7 +144,10 @@ Note: This scenario uses a combination of two Micro AIs, the Hang Out Micro AI w
id=Bad Outlaw
[/filter]
{MESSAGE (Good Bandit) "" "" _"We got him! Now whatever it is we are fighting for is safe."}
[message]
speaker=Good Bandit
message=_ "We got him! Now whatever it is we are fighting for is safe."
[/message]
# So that game goes on to next scenario
[modify_side]
@ -165,7 +171,10 @@ Note: This scenario uses a combination of two Micro AIs, the Hang Out Micro AI w
x,y=36,19
[/filter]
{MESSAGE (Bad Outlaw) "" "" _"I made it! Now we can keep fighting for whatever it is that we are fighting for."}
[message]
speaker=Bad Outlaw
message=_ "I made it! Now we can keep fighting for whatever it is that we are fighting for."
{MESSAGE Rebels1 "" "" _"In this scenario, we demonstrate the use of the Healer Support Micro AI. This AI configures the healers of a side to stay behind the battle lines and heal injured and/or threatened units rather than participate in the attacks under all circumstances. It includes several configurable options (which are set differently for the two sides in this scenario) that determine how aggressive/careful the healers are, whether they also attack, how much risk they are willing to take, etc.
[message]
speaker=Rebels1
message=_ "In this scenario, we demonstrate the use of the Healer Support Micro AI. This AI configures the healers of a side to stay behind the battle lines and heal injured and/or threatened units rather than participate in the attacks under all circumstances. It includes several configurable options (which are set differently for the two sides in this scenario) that determine how aggressive/careful the healers are, whether they also attack, how much risk they are willing to take, etc.
For clarity, each healer announces her upcoming support move. If you don't want to see that each time, just hit 'esc' when it happens the first time.
Note: The Healer Support AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
Note: The Healer Support AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[/event]
@ -92,7 +95,10 @@ Note: The Healer Support AI is coded as a Micro AI. A Micro AI can be added and
{MESSAGE Pekzs "" "" _"In this scenario we demonstrate the Lurker Micro AI. A lurker is a unit that is capable of moving across most terrains, but that only stops on and attacks from specific terrain. It might also have the ability to hide on this terrain (which is the reason why this is called the Lurker AI).
[message]
speaker=Pekzs
message=_ "In this scenario we demonstrate the Lurker Micro AI. A lurker is a unit that is capable of moving across most terrains, but that only stops on and attacks from specific terrain. It might also have the ability to hide on this terrain (which is the reason why this is called the Lurker AI).
Lurkers move individually without any strategy and always attack the weakest enemy within their reach. If no enemy is in reach, the lurker does a random move instead - or it just sits and waits (lurks)."}
Lurkers move individually without any strategy and always attack the weakest enemy within their reach. If no enemy is in reach, the lurker does a random move instead - or it just sits and waits (lurks)."
[/message]
# wmllint: unbalanced-on
{MESSAGE Pekzs "" "" _"Three different lurker behaviors are set up here using the [micro_ai] tag with different parameters:
[message]
speaker=Pekzs
message=_ "Three different lurker behaviors are set up here using the [micro_ai] tag with different parameters:
Side 2 (blue): saurians attacking only from swamp. If no enemy is in range, they do not move.
@ -460,13 +465,19 @@ Side 3 (green): saurians attacking only from swamp. If no enemy is in range, the
Side 4 (purple): nagas wandering only on water terrain, but attacking from both water and swamp.
We also added two other sides, which demonstrate lurker behavior coded in WML (Side 5, gray) and Formula AI (Side 6, brown)."}
We also added two other sides, which demonstrate lurker behavior coded in WML (Side 5, gray) and Formula AI (Side 6, brown)."
[/message]
{MESSAGE narrator "wesnoth-icon.png" _"Notes" _"You can use the right-click context menu to add additional lurkers.
[message]
speaker=narrator
image="wesnoth-icon.png"
caption=_ "Notes"
message=_ "You can use the right-click context menu to add additional lurkers.
Any unit not adjacent to swamp (and water, for the nagas) is safe from the lurkers, thus it is easy to keep Pekzs from being attacked.
The Lua Lurker AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
The Lua Lurker AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[objectives]
@ -530,7 +541,10 @@ The Lua Lurker AI is coded as a Micro AI. A Micro AI can be added and adapted to
[event]
name=end_scenario
{MESSAGE Pekzs "" "" _"Zzanksss for helping me wizz zzossse lurkerss. Hope to sssee you again ssometime."}
[message]
speaker=Pekzs
message=_ "Zzanksss for helping me wizz zzossse lurkerss. Hope to sssee you again ssometime."
{MESSAGE Vanak "$profile~FL()~RIGHT()" "" _"They there! We them get!"}
[message]
speaker=Vanak
image=$profile~FL()~RIGHT()
message=_ "They there! We them get!"
[/message]
{CLEAR_VARIABLE profile}
{MESSAGE messenger "" "" _"Men, I need to get to that signpost in the north, to get the message to our leader. Let's head up there as quickly as we can."}
[message]
speaker=messenger
message=_ "Men, I need to get to that signpost in the north, to get the message to our leader. Let's head up there as quickly as we can."
[/message]
# wmllint: unbalanced-on
{MESSAGE narrator "wesnoth-icon.png" _"Notes" _"The Messenger Escort AI will try to move the dragoon messenger to the signpost in the north, while protecting him as well as possible with the other units. Vanak's orcs need to stop him.
[message]
speaker=narrator
image=wesnoth-icon.png
caption=_ "Notes"
message=_ "The Messenger Escort AI will try to move the dragoon messenger to the signpost in the north, while protecting him as well as possible with the other units. Vanak's orcs need to stop him.
Note that the messenger route is set up through a series of waypoints here simply to demonstrate how to use waypoints. On this map, using only a single waypoint at the end of the route would work just as well (or probably even better).
Also note that the messenger does not have to get exactly to each signpost (except for the last one), getting close is good enough.
The Messenger Escort AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
The Messenger Escort AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[objectives]
@ -170,7 +182,10 @@ The Messenger Escort AI is coded as a Micro AI. A Micro AI can be added and adap
x,y=28,1
[/filter]
{MESSAGE messenger "" "" _"I made it! Now our people will be safe."}
[message]
speaker=messenger
message=_ "I made it! Now our people will be safe."
[/message]
[endlevel]
result=defeat
[/endlevel]
@ -182,7 +197,10 @@ The Messenger Escort AI is coded as a Micro AI. A Micro AI can be added and adap
[filter]
id=messenger
[/filter]
{MESSAGE messenger "" "" _"Nooo! All is lost. We will never stop the orcs now!"}
[message]
speaker=messenger
message=_ "Nooo! All is lost. We will never stop the orcs now!"
{MESSAGE Konrad "$profile~FL()~RIGHT()" "" _"Hello! I'm a Konrad impostor. We are going to demonstrate the Patrol AI to you in this scenario.
[message]
speaker=Konrad
image=$profile~FL()~RIGHT()
message=_ "Hello! I'm a Konrad impostor. We are going to demonstrate the Patrol AI to you in this scenario.
I am heading for the keep east of the central mountain via a couple waypoints in the south. I will stay there once I get there. By contrast, those two fellas in the center are perpetually circling the mountain, one of them always in the same direction, the other changing directions after every lap.
All of this is implemented by use of the Patrol [micro_ai] tag."}
All of this is implemented by use of the Patrol [micro_ai] tag."
[/message]
# wmllint: unbalanced-off
{CLEAR_VARIABLE profile}
{MESSAGE guard1 "" "" _"By contrast, I am a zone guardian patrolling, in a way, the southernmost part of the map. This AI is implemented via the Guardian [micro_ai] tag. It is here mostly to demonstrate how to set up different Micro AIs for the same side. For more details on different types of guardian AIs, there is a separate test scenario specializing on those."}
{MESSAGE Urudin "" "" _"And I am Urudin. I will attack my enemies for a few turns, but will retreat toward the right edge of the map if my hitpoints are below half of maximum or by Turn 5, whatever happens first.
[message]
speaker=guard1
message=_ "By contrast, I am a zone guardian patrolling, in a way, the southernmost part of the map. This AI is implemented via the Guardian [micro_ai] tag. It is here mostly to demonstrate how to set up different Micro AIs for the same side. For more details on different types of guardian AIs, there is a separate test scenario specializing on those."}
[/message]
[message]
speaker=Urudin
message=_ "And I am Urudin. I will attack my enemies for a few turns, but will retreat toward the right edge of the map if my hitpoints are below half of maximum or by Turn 5, whatever happens first.
This is an AI separate from the Patrols of Side 2."}
This is an AI separate from the Patrols of Side 2."
[/message]
# wmllint: unbalanced-on
{MESSAGE narrator "wesnoth-icon.png" _"Notes" _"You, as the player, are in charge of Gertburt's bandits in this scenario. You can either simply watch the patrols move around, or you can move units into their way. The three patrol units are instructed to behave differently when facing enemy units:
[message]
speaker=narrator
image=wesnoth-icon.png
caption=_ "Notes"
message=_ "You, as the player, are in charge of Gertburt's bandits in this scenario. You can either simply watch the patrols move around, or you can move units into their way. The three patrol units are instructed to behave differently when facing enemy units:
Konrad only attacks Gertburt, or any enemy unit that blocks his final waypoint.
@ -224,7 +238,8 @@ The Longbowman attacks any enemy unit he ends up next to at the end of his move.
They all have in common, however, that getting to their next waypoint takes priority over attacking. They will thus prefer to move around enemies rather than straight for them. Also, if a waypoint is occupied by a unit they are not instructed to attack, they will (eventually) abandon that waypoint once they get close enough and move on to the next one.
The Patrol AI controlling all Side 2 units is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
The Patrol AI controlling all Side 2 units is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[objectives]
@ -253,7 +268,10 @@ The Patrol AI controlling all Side 2 units is coded as a Micro AI. A Micro AI ca
x,y=25,15
[/filter]
{MESSAGE Konrad "" "" _"Well, that was fun! I'll just hang out here now and watch those two guys walk and walk and ..."}
[message]
speaker=Konrad
message=_ "Well, that was fun! I'll just hang out here now and watch those two guys walk and walk and ..."
[/message]
[/event]
# The events finishing the scenario
@ -294,7 +312,10 @@ The Patrol AI controlling all Side 2 units is coded as a Micro AI. A Micro AI ca
{MESSAGE Koorzhar "$profile~FL()~RIGHT()" "" _"There's that traitor wizard. Let's get him."}
[message]
speaker=Koorzhar
image="$profile~FL()~RIGHT()"
message=_ "There's that traitor wizard. Let's get him."
[/message]
{CLEAR_VARIABLE profile}
{MESSAGE Langzhar "" "" _"Men, you know the deal. We must protect Rossauba under all circumstances. Even my survival is not as important."}
{MESSAGE Rossauba "" "" _"That's very kind of you, but ..."}
{MESSAGE Langzhar "" "" _"No buts! You stay behind the lines and do not engage in battle unless there is no risk to your life, is that understood? And get to that signpost in the northwest if it is safe."}
[message]
speaker=Langzhar
message=_ "Men, you know the deal. We must protect Rossauba under all circumstances. Even my survival is not as important."
[/message]
[message]
speaker=Rossauba
message=_ "That's very kind of you, but ..."
[/message]
[message]
speaker=Langzhar
message=_ "No buts! You stay behind the lines and do not engage in battle unless there is no risk to your life, is that understood? And get to that signpost in the northwest if it is safe."
[/message]
[message]
speaker=narrator
@ -137,7 +150,7 @@
# wmllint: unbalanced-on
message=_ "In this scenario, the AI playing the humans in the east (Langzhar) is instructed to protect the wizard Rossauba, while moving him safely to the signpost. On the other side, Koorzhar's units (in the west) will primarily attack Rossauba, even if a better target is available. Do you want to play either of the sides or let the AIs battle it out among themselves?
Note: The Protect Unit AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information." # wmllint: no spellcheck
Note: The Protect Unit AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information." # wmllint: no spellcheck
# wmllint: unbalanced-off
[option]
label=_ "<span font='16'>I'll watch the two AIs fight it out</span>" # wmllint: no spellcheck
@ -213,7 +226,11 @@ Note: The Protect Unit AI is coded as a Micro AI. A Micro AI can be added and ad
id=Rossauba
[/filter]
{MESSAGE Rossauba "" "" _"I held out for as long as I could."}
[message]
speaker=Rossauba
message=_ "I held out for as long as I could."
[/message]
[fire_event]
name=end_scenario
[/fire_event]
@ -227,7 +244,10 @@ Note: The Protect Unit AI is coded as a Micro AI. A Micro AI can be added and ad
{MESSAGE Koorzhar "$profile~FL()~RIGHT()" "" _"This is a very simple scenario that can be used to test out different recruiting patterns."}
[message]
speaker=Koorzhar
image=$profile~FL()~RIGHT()
message=_ "This is a very simple scenario that can be used to test out different recruiting patterns."
[/message]
{CLEAR_VARIABLE profile}
{MESSAGE Langzhar "" "" _"Just watch the recruiting of both sides and see if it is what you would expect. The recruitment lists cover level 0 to level 2 units, in order to make differences more obvious."}
[message]
speaker=Langzhar
message=_ "Just watch the recruiting of both sides and see if it is what you would expect. The recruitment lists cover level 0 to level 2 units, in order to make differences more obvious."
[/message]
# wmllint: unbalanced-on
{MESSAGE narrator "wesnoth-icon.png" "Notes" _"If you have not changed anything in the scenario code, Side 1 uses the Random Recruitment Micro AI, with swordsmen and peasants having been given higher probability than the other units, and mages a middling probability. This is not meant as a good recruitment pattern, it simply serves as a demonstration how to use the AI.
[message]
speaker=narrator
image=wesnoth-icon.png
caption=_ "Notes"
message=_ "If you have not changed anything in the scenario code, Side 1 uses the Random Recruitment Micro AI, with swordsmen and peasants having been given higher probability than the other units, and mages a middling probability. This is not meant as a good recruitment pattern, it simply serves as a demonstration how to use the AI.
Side 2 uses the Rush Recruitment Micro AI (which is also used in the Experimental AI).
A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[/event]
@ -108,7 +120,11 @@ A Micro AI can be added and adapted to the need of a scenario easily using only
[/have_unit]
[/not]
[then]
{MESSAGE narrator "wesnoth-icon.png" "" _"Well, that was that."}
{MESSAGE Grnk "" _"Bottleneck Defense Micro AI Demo" _"In the Bottleneck Defense Micro AI scenario, a small group of human soldiers is instructed to hold a pass against a large horde of orcs. You can either watch them fight it out against the standard RCA AI or take over the orc side."}
[message]
speaker=Grnk
caption=_ "Bottleneck Defense Micro AI Demo"
message=_ "In the Bottleneck Defense Micro AI scenario, a small group of human soldiers is instructed to hold a pass against a large horde of orcs. You can either watch them fight it out against the standard RCA AI or take over the orc side."
{MESSAGE Grnk "" _"Swamp Lurker Micro AI demo" _"Swamp lurkers are dumb, impulse-driven creatures which can move across most terrain, but only stop on swamp. They move individually without any strategy and always attack the weakest enemy within their reach. If no enemy is in reach, the lurker does a random move instead."}
[message]
speaker=Grnk
caption=_ "Swamp Lurker Micro AI demo"
message=_ "Swamp lurkers are dumb, impulse-driven creatures which can move across most terrain, but only stop on swamp. They move individually without any strategy and always attack the weakest enemy within their reach. If no enemy is in reach, the lurker does a random move instead."
{MESSAGE Grnk "" _"Guardian Micro AI demo" _"In 'Guardians', several variations of the standard Wesnoth guardian are shown, including a ""coward"" unit that runs away from any approaching unit (an ""inverse guardian"", in a way)."}
[message]
speaker=Grnk
caption=_ "Guardian Micro AI demo"
message=_ "In 'Guardians', several variations of the standard Wesnoth guardian are shown, including a ""coward"" unit that runs away from any approaching unit (an ""inverse guardian"", in a way)."
{MESSAGE Grnk "" _"Protect Unit Micro AI Demo" _"This scenario demonstrates one side protecting a wizard while moving him to a goal location. At the same time, the other side is modified to do priority attacks on the wizard, even if a better target (by the default AI criteria) is available. You can watch the two AIs fight it out, or take control of either side to explore how the opposing AI behaves."}
[message]
speaker=Grnk
caption=_ "Protect Unit Micro AI Demo"
message=_ "This scenario demonstrates one side protecting a wizard while moving him to a goal location. At the same time, the other side is modified to do priority attacks on the wizard, even if a better target (by the default AI criteria) is available. You can watch the two AIs fight it out, or take control of either side to explore how the opposing AI behaves."
{MESSAGE Grnk "" _"HttT: The Elves Besieged Micro AI demo" _"This is a reenactment of scenario ""The Elves Besieged"" of the mainline campaign ""Heir to the Throne"", just that the AI is playing Konrad's side here. The same algorithm as for scenario ""Protect Unit"" is used."}
[message]
speaker=Grnk
caption=_ "HttT: The Elves Besieged Micro AI demo"
message=_ "This is a reenactment of scenario ""The Elves Besieged"" of the mainline campaign ""Heir to the Throne"", just that the AI is playing Konrad's side here. The same algorithm as for scenario ""Protect Unit"" is used."
{MESSAGE Grnk "" _"Messenger Escort Micro AI demo" _"'Messenger Escort' has the AI actively protect a messenger while he makes his way to the edge of the map. The escort will also try to open the path for the messenger if there are enemies in the way."}
[message]
speaker=Grnk
caption=_ "Messenger Escort Micro AI demo"
message=_ "'Messenger Escort' has the AI actively protect a messenger while he makes his way to the edge of the map. The escort will also try to open the path for the messenger if there are enemies in the way."
{MESSAGE Grnk "" _"Animals Micro AI demo" _"This scenario demonstrates a number of different animals following customized AI behavior, including wolves hunting deer in packs; dogs herding sheep; bears, spiders, yetis, boar and rabbits wandering and hunting/avoiding each other."}
[message]
speaker=Grnk
caption=_ "Animals Micro AI demo"
message=_ "This scenario demonstrates a number of different animals following customized AI behavior, including wolves hunting deer in packs; dogs herding sheep; bears, spiders, yetis, boar and rabbits wandering and hunting/avoiding each other."
{MESSAGE Grnk "" _"Wolves Micro AI demo" _"Another demonstration of wolves wandering and attacking in packs, with a different behavior from that in 'Animals'."}
[message]
speaker=Grnk
caption=_ "Wolves Micro AI demo"
message=_ "Another demonstration of wolves wandering and attacking in packs, with a different behavior from that in 'Animals'."
{MESSAGE Grnk "" _"Healer Support Micro AI demo" _"This scenario contains a simple demonstration of setting up the Healer Support Micro AI, which uses the healers of a side to back up injured or threatened units rather than having them participate in combat under all circumstances."}
[message]
speaker=Grnk
caption=_ "Healer Support Micro AI demo"
message=_ "This scenario contains a simple demonstration of setting up the Healer Support Micro AI, which uses the healers of a side to back up injured or threatened units rather than having them participate in combat under all circumstances."
{MESSAGE Grnk "" _"Goto Micro AI demo" _"This scenario contains several example usages of the Goto Micro AI, which is a highly configurable method of sending a unit (or units) to a location or set of locations. The units to be moved are defined using a Standard Unit Filter, while the goto locations are given in a Standard Location Filter."}
[message]
speaker=Grnk
caption=_ "Goto Micro AI demo"
message=_ "This scenario contains several example usages of the Goto Micro AI, which is a highly configurable method of sending a unit (or units) to a location or set of locations. The units to be moved are defined using a Standard Unit Filter, while the goto locations are given in a Standard Location Filter."
{MESSAGE Grnk "" _"Combined Hang Out and Messenger Escort Micro AI demo" _"This scenario is a demonstration of the Hang Out Micro AI which keeps units around a (customizable) location until a (customizable) condition is met. After that the units are released to follow other AI behavior. The scenario also shows how to combine two Micro AIs on the same side by having the Messenger Escort Micro AI take over at that point."}
[message]
speaker=Grnk
caption=_ "Combined Hang Out and Messenger Escort Micro AI demo"
message=_ "This scenario is a demonstration of the Hang Out Micro AI which keeps units around a (customizable) location until a (customizable) condition is met. After that the units are released to follow other AI behavior. The scenario also shows how to combine two Micro AIs on the same side by having the Messenger Escort Micro AI take over at that point."
{MESSAGE Grnk "" _"Simple Attack Micro AI demo" _"This scenario demonstrates how certain attacks can be executed with higher priority than the standard Wesnoth attacks and how the AI can be forced to do attacks that it would otherwise avoid."}
[message]
speaker=Grnk
caption=_ "Simple Attack Micro AI demo"
message=_ "This scenario demonstrates how certain attacks can be executed with higher priority than the standard Wesnoth attacks and how the AI can be forced to do attacks that it would otherwise avoid."
{MESSAGE Grnk "" _"Fast Micro AI demo" _"A simple demonstration of the calculation time advantage of the Fast Micro AI over the default AI in scenarios with many units."}
[message]
speaker=Grnk
caption=_ "Fast Micro AI demo"
message=_ "A simple demonstration of the calculation time advantage of the Fast Micro AI over the default AI in scenarios with many units."
[/message]
[/command]
[/set_menu_item]
[/event]
@ -357,9 +425,12 @@
{SCROLL_TO 13 11}
{MESSAGE Grnk "" "" _"Move me to any of the signposts to go to a Micro AI demonstration.
[message]
speaker=Grnk
message=_ "Move me to any of the signposts to go to a Micro AI demonstration.
Information about each demonstration can be accessed by right-clicking on the respective signpost."}
Information about each demonstration can be accessed by right-clicking on the respective signpost."
{MESSAGE sergeant "" "" _"General Grospur, what do we do? These undead will surely wipe us out."}
{MESSAGE Grospur "" "" _"Don't be such a chicken, Sergeant! I have placed units with lots of experience around the perimeter. The undead will not dare to attack them. And those few that sneak through... we can easily dispose of them once they make it inside.
[message]
speaker=sergeant
message=_ "General Grospur, what do we do? These undead will surely wipe us out."
[/message]
[message]
speaker=Grospur
message=_ "Don't be such a chicken, Sergeant! I have placed units with lots of experience around the perimeter. The undead will not dare to attack them. And those few that sneak through... we can easily dispose of them once they make it inside.
<i>In other words, the Wesnoth AI does generally not attack units one XP from leveling if there is no chance of killing the unit with a single attack. However, some of the attacks by the undead are handled by the Simple Attack Micro AI in this scenario. General Grospur might be in for a surprise.</i>"}
<i>In other words, the Wesnoth AI does generally not attack units one XP from leveling if there is no chance of killing the unit with a single attack. However, some of the attacks by the undead are handled by the Simple Attack Micro AI in this scenario. General Grospur might be in for a surprise.</i>"
[/message]
[objectives]
summary=_ "Watch the undead take care of business"
@ -161,10 +167,16 @@
lua_function="close_to_advancing"
[/filter_second]
{MESSAGE $second_unit.id "" "" _"What the ... ?!? They are not supposed to attack me. That just doesn't happen in Wesnoth!"}
{MESSAGE Uralt "" "" _"Hahahahaha !! I have given special instruction to my Soulless to attack all you almost-advanced units first. Also watch how those same Soulless will throw themselves mercilessly at your pitiful soldiers after that, saving my more valuable skeleton minions for later. I have taken the term 'disposable units' to a whole new level. Watch in awe !!
[message]
speaker=$second_unit.id
message=_ "What the ... ?!? They are not supposed to attack me. That just doesn't happen in Wesnoth!"
[/message]
[message]
speaker=Uralt
message=_ "Hahahahaha !! I have given special instruction to my Soulless to attack all you almost-advanced units first. Also watch how those same Soulless will throw themselves mercilessly at your pitiful soldiers after that, saving my more valuable skeleton minions for later. I have taken the term 'disposable units' to a whole new level. Watch in awe !!
<i>Translation: The undead side includes two instances of the Simple Attack Micro AI. The first makes the Soulless attack all units 1 XP from leveling up, such that they can be eliminated afterward. The second executes all remaining attacks possible by Soulless (and Walking Corpses), without regard for their own safety. Only after that does the default Wesnoth attack mechanism kick in to attack with the remaining units (skeletons).</i>"}
<i>Translation: The undead side includes two instances of the Simple Attack Micro AI. The first makes the Soulless attack all units 1 XP from leveling up, such that they can be eliminated afterward. The second executes all remaining attacks possible by Soulless (and Walking Corpses), without regard for their own safety. Only after that does the default Wesnoth attack mechanism kick in to attack with the remaining units (skeletons).</i>"
[/message]
[/event]
# Put more undead out there when less than 25 left
{MESSAGE narrator "wesnoth-icon.png" "" _"Well, that was that."}
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "Well, that was that."
[/message]
# So that game goes on to next scenario
[modify_side]
@ -134,11 +138,15 @@
name=start
# wmllint: unbalanced-on
{MESSAGE narrator "wesnoth-icon.png" "" _"This scenario features bats moving around in a swarm. Without adjacent enemies, they simply try to stay together and at a certain distance from enemies. However, if an enemy unit is close to any bat, the swarm scatters. This is particular fun to watch when one places an enemy unit in the middle of the swarm. After being scattered, the swarm members slowly rejoin, but not in a very organized way. Sub-swarms or individual bats might roam around for quite some time before they find their way back. It is also possible that individual bats (or small groups) split off from the larger swarm at times.
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "This scenario features bats moving around in a swarm. Without adjacent enemies, they simply try to stay together and at a certain distance from enemies. However, if an enemy unit is close to any bat, the swarm scatters. This is particular fun to watch when one places an enemy unit in the middle of the swarm. After being scattered, the swarm members slowly rejoin, but not in a very organized way. Sub-swarms or individual bats might roam around for quite some time before they find their way back. It is also possible that individual bats (or small groups) split off from the larger swarm at times.
The player controls a side of gryphons, each of which is given 99 moves so that the reaction of the swarm to enemies can be tested easily. There are also several right-click options, for example for adding bats or gryphons or for taking units off the map.
Note: The Swarm AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
Note: The Swarm AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information."
[/message]
# wmllint: unbalanced-off
[objectives]
@ -174,7 +182,11 @@ Note: The Swarm AI is coded as a Micro AI. A Micro AI can be added and adapted t
[/have_unit]
[/not]
[then]
{MESSAGE narrator "wesnoth-icon.png" "" _"Well, that was that."}
{MESSAGE narrator "wesnoth-icon.png" "" _"Well, that was that."}
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "Well, that was that."
[/message]
# So that game goes on to next scenario
[modify_side]
@ -185,11 +189,15 @@
[event]
name=start
{MESSAGE narrator "wesnoth-icon.png" "" _"This scenario features a different kind of wolf behavior from 'Animals'. First, there can be an arbitrary number of wolf packs and the pack size on each side is a free parameter (set to 3 for Side 2 and 4 for Side 3 in this scenario). At the beginning of the scenario, close wolves are grouped into packs in a semi-methodical way. Wolves of the same pack begin by joining each other on the map. After that, they stay together until only one wolf is left, which then tries to join up with an incomplete pack or with other single wolves. Individual wolves entering the map during the scenario behave in that way as well.
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "This scenario features a different kind of wolf behavior from 'Animals'. First, there can be an arbitrary number of wolf packs and the pack size on each side is a free parameter (set to 3 for Side 2 and 4 for Side 3 in this scenario). At the beginning of the scenario, close wolves are grouped into packs in a semi-methodical way. Wolves of the same pack begin by joining each other on the map. After that, they stay together until only one wolf is left, which then tries to join up with an incomplete pack or with other single wolves. Individual wolves entering the map during the scenario behave in that way as well.
Second, wolves do not actively hunt here. For the most part they just wander (often long distance). However, the pack ferociously (and without regard for its own health) attacks any enemy units that come into range, as long as that does not mean separating the pack by more than a few hexes. Staying together, or joining with a new wolf assigned to the pack, is the only thing that takes priority over satisfying the wolves' thirst for blood.
To emphasize which wolf belongs to which pack, the pack number will be displayed below each wolf in this scenario once the AI takes control of a side the first time."}
To emphasize which wolf belongs to which pack, the pack number will be displayed below each wolf in this scenario once the AI takes control of a side the first time."
[/message]
[message]
speaker=narrator
@ -200,7 +208,7 @@ To emphasize which wolf belongs to which pack, the pack number will be displayed
Note that the leader of the human-controlled side, Rutburt, can move 99 hexes per turn, so that it is always possible to keep him out of harm's way.
Also note that the wolves AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information." # wmllint: no spellcheck
Also note that the wolves AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at https://wiki.wesnoth.org/Micro_AIs for more information." # wmllint: no spellcheck
# wmllint: unbalanced-off
[option]
label=_ "<span font='16'>I'll just watch the two wolf sides.</span>"
@ -259,7 +267,11 @@ Also note that the wolves AI is coded as a Micro AI. A Micro AI can be added and
[/have_unit]
[/not]
[then]
{MESSAGE narrator "wesnoth-icon.png" "" _"Well, that was that."}