We no longer use the GUI2 draw events. We should implement the appropriate interface provided by top_level_drawable instead. DRAW is still a valid event for now, but would probably be removed in the future.
Added code to convert all `[side]type=` to `[side][leader]` when the `[scenario]` is read, and the rest of the engine code to only work with [leader], this should fix all possible problems with `[leader]` and also simplify the code a bit
Fixes#7985Fixes#3742
This was unique to this class, since the base class only implemented the const version. It was only needed for the whiteboard, and on closer inspection none of of the mutable references therein actually needed to be mutable. Marked them all const and removed the offending getter from game_board.
Note that the non-const overload had the same functionality as the const overload in the base class, only implemented via `find_visible_unit`.
Little hacky, since this supports the case of manually hiding the grids instead of simply not populating them (see #9499), but it prevents needing to change widget::get_best_size while I figure out a more comprehensive solution.
previously the leader= attribute in [side] could be used to
make the engine choose a faction by its leader, similar to how
[side]faction_from_recruit worked.
However this was not documented in the wiki, and the name clash
with the [side][leader] subtag could also cause problems
and is also a litte confusing.
So it was decided to remove it. an alternative approach to fix the
name clash would be to rename it, but i can't think of
real usecases of this feature currently.
Instead, return the number of rows shown from filter_rows_by. We might re-add any_rows_shown in the future, but for now this covers the intended usecase.
This matches the behavior on the client where the events that
happen after end_turn (the "turn end" wml events) happen during
the last sides turn not the next sides turn. In particular this
fixes#2563. It also fixes#3899 because the new logic
automaticially skips empty sides already in init_side and not on
end_turn.
It also changes how description is updated, since carrying that
return value arround specifying whether it was updated was becoming
annoying.
With a few code improvements from soliton.
We now use a modified default carryover calculation,
the main advantage is it now uses the normal carryover
message on endlevel, and shows how it is calculated.
The idea is to make it easier for umc devs to implement
their own carryover / early finish bonus mechanics. Maybe
we can also make use of it in Worls Conquest.
previously it was unclear what the trailing number meant,
also the order couldn't be changed in the translation.
Also the player number was shown 2 times in the savefile name,
resulting in names like 'WC1-WCII 1 -Start-Auto-Save.gz' so i
removed it from the scenario name.
This returns true when the user is currently replaying the scenario
This not only includes the classic 'replay safefiles' but for
example also the 'replay turn' feature (field name suggested by celmin)
Don't animate unit advancements during a prestart event.
It woudl be better it u:advance() would automaticialyl not waste time animating advancements that can't be seen (during prestart events) but for this scenario this is already an improvement
Increases GCC requirement to 11 for Charconv support (which is part of c++17)
Technicially it also builds with older gcc versions when boost 1.85 is available but that combination seems unlikely and i didn't want to make INSTALL.md too complicated.
The upcoming clang 20 will also support charconv by itself, but again it felt silly to mention something that is not available yet.
* Re-added the ability to set a single sorter, this time by ID.
* Multi-sorter setting now uses the magic sort_N IDs.
* Cleaned up internal handling to remove reliance on header grid columns.
Sorters will still be looked for in the header, but rely on the specified ID.
This did (I'm pretty sure) work before, but now it's explicit.
* The order_pair typedef has been removed
* set_active_sorting_option has been removed set_active_sorter and now takes its arguments separately instead of as a pair.
* set_active_sorter will use the bound sorter header on-modified handler
instead of calling order_by_column directly
* set_sorting_options has been renamed to set_sorters
* get_active_sorting_option has been renamed get_sorter
This unifies handling of the scrollbar modes without having to manually set them in the builders. At one point, this wasn't too common, but it's become common enough that having a separate builder is cleaner
This makes attribute_value and lexical_cast use the "new" to/from_chars api.
Its main advantages are:
- It's guaranteed to be locale independent, hopefully fixing all cases of #3945 and similar
- It fixes some cases config serialization, in particular the test
```
cfg["x"] = "9.87654321";
BOOST_CHECK_EQUAL(cfg["x"], 9.87654321);
```
- Previously the lexical_cast implementation used exception
handling for invalid formats (catching std::invalid_argument)
which made noise during debugging (and is also slower if it
is not optimized out).
- It's faster
So far afaik the only compiler which has a complete and proper to/from_chars implementation is msvc, gccs implementation of from_chars sometimes uses strtod under the hood and clang simply hasn't implemented from_chars for floating point numbers yet at all (actually the upcomig clang 20 will have it). Luckily for us, there is now also boost::charconv that can be used. So this raises to minimum build requirement to have at least one of:
- msvc 2019 update 5
- gcc 11
- clang 14 (i have added a fallback implementation of from_chars for this case, that doesn't support all of its features, and is probably certainly not as fast as the boost version, but supports the features that we use from it)
- boost 1.85
Since in particular the gcc implementation isn't that good (at least it on gcc11), boost charconv is the preferred implementation that is used if available.
This also removes a strange overload for
pointers to integers in lexical_cast while changing lexical_cast to use the new api.
Fixed map editor crashing when creating or opening scenario after played local scenario before opening map editor. Resolves#9563. The cause of the bug was that the ai manager singleton pointer was not set to nullptr after it was destructed. Fixed this by making ai manager destructor set singleton to nullptr. Before this the ai_map_ map member has to be cleared in destructor because it might try to access the singleton when destructed.
---------
Co-authored-by: SomeName42 <>
These were added by clang-tidy's autofix, which both tried to convert
the parameters to const references and std::move them. The correct
behaviour is to convert only to a const reference.
Instead of two functions for translatable and non-translatable options, comparison will be determined by the return value of the sorter. Existing translatable sorting options have been adjusted to return t_string rather than string.
When Hahid dies, Grug or Dolburras, if present, say the "eulogy". There were problems in scenarios where they first appear (S06a for Dolburras and S07b for Grug) - they say it even before joining the player's side, which makes no sense. I changed the message tags in utils/deaths.cfg to use "id" and "side" instead of "speaker", so they only say it when they are on the same side as Hahid.
Also in S07b, Hahid's herodeath macro was duplicated, so the dialogue was displayed twice.
Also I changed Grug's herodeath to "id" and "side" and re-included it into S07b, so now Gweddry says the eulogy for Grug after Grug joins, but not before.
For whatever reason, callback_save_value had type
std::function<void(int)> in the .cpp file but
std::function<void(const int)> in the header file. This reconciles them
to both take in an integer as a parameter.
This was the last use of lg::format_timespan, which was only ever used in server code anyway. The server probably shouldn't be formatting this anyway, but as long as it is, we don't need a dedicated function or fancy formatting.
Bad design to return mutable reference to static object. This method has the possibility of creating a new default entry in the by_name map, but the remove call will be a no-op in that case (as it was before), so no harm done.
previously the game would return to titlescreen here if mp_info_
but was null but
`game_config::debug && state_.classification().is_multiplayer()`
returned true which happend when a multiplayer game was reloaded
via the sp loadgame dialog.
This fixes the issue by simply removing the "always show mp staging
between scenarios in debug mode" feature, which imo never was that
useful anyways.
This not only removes duplicate information which can always cause bugs if it's out of sync,
this can also be used an an easy way to detect the old undo stack format
this way even when enter/exit_hex events with [on_undo] are involved, undoing happens
in reverse order of the gamestate changes during the original action
This commit splits undo actions into multiple smaller steps. The main advantages:
- Its allows us always undo the parts of an action in the reverse order of which
they originally happen, preventing bugs that could be caused if the parts
interact with each other in a way where the order matters (like for example
an [on_undo] resetting a units moves, when the event happend in a move action
which would then also reset the units moves on undoing).
- It's easier to add (c++) undo steps for specific steps even if they are used
from wml, like spending gold.
- [do_command] no longer confused the undo stack (in fact it's by default now undoable).
- All actions are put onto the undo stack in the same way, previously it was
often unclear whether the undo stack is empty during a specific step during
the execution of an action, in particular when people tried to use
`undo_stack->empty()` to check whether an action could still be undone.
This also adjusts the periods for years and months. Previously, we were using values of 30 days for a month and 12 months for year. Now, we use the chrono values of a month as 1/12 of a year and a year as 365.2425 days.
In S04a, the event is added within his original "last breath" event - the one which switches him to the player's side. Without this additional event, he will die silently if killed by the elves after being "captured".
In S11, it looks like the event for him was simply forgotten (HERODEATH events are added for all other heroes).
Instead of simply returning a string, `is_ip_banned` now returns a struct with an error code, ban reason, and ban time remaining. This avoids doing time duration formatting on the server and allows the error message to be localized on the client. It also makes the ban handling interface more generic in server_base, which should hopefully allow forum bans to be handled this way as well.
* new ships Derelict Hulk and Fireship
* new "race" Ships - includes Transport Galleon, Pirate Galleon, Derelict Hulk, and Fireship
* Pirate Galleon chaotic
* animations for all four touched ships
* ship portraits for Derelict Hulk and Fireship
* crew portraits by LordBob for Boat, Galleon, Transport Galleon, and Pirate Galleon
* old (non-pixel art) transport galleon and pirate galleon images moved to scenery
Fixes#8488.
This is a simple setenv trick. Ideally we would instead figure out how
to fix Oldania ADF Std to work on newer macOS, but since we know the
Fontconfig backend works for us on Windows and Linux, we may as well
stick to it and hope there will never be a situation where CoreText
would prove superior somehow.
Fixed palette button not being clickable after scrolling in palette widget without moving the cursor. Resolves#1335. The cause of the bug was that scrolling doesnt change the highlighted state of the palette buttons and not highlighted buttons didnt process being clicked. Solved the bug by making not highlighted buttons process being clicked.
previously block_undo would clear the undo stack and send data even when its parameter is false
this commit also fixes a possible crash when dsu changed the gamestate during formula evauluation
also removed a is_simultanious_ since it basicialyl did the same thing as undo_blocked_
With this, finally all actions run though synced context::run,
so that we not only have a central place that happens before/after
synced actions, we also guarantee that there is no difference between
the original and the replay codepath for all actions.
This should also make upcoming changed to the undo code easier.
- Removed the now unused 'undo' parameter
- Removed the rareley used 'show' parameter, the actions now
check whether they should skip in replays
Replaced the error handler with the more generic 'spectator' parameter,
the idea is to use it also for the move_spectator so that the move action
can also go through synced_context::run()
- use_undo is not used anymore
- ignore_error_function has no effect since to_check()
already checks whether the unit exists
- show in whiteboard code was the default value.
- show is now determined inside the actions handler, this
has the advantage that the skip_ai_moves preference now
also works for networked ai sides.
-the attack code now used run_in_synced_context_if_not_already
just like the other commands
The comments said undo is disabled during ai turns to speed things up,
but since all the undo code does is adding a simple object once to a vector, its impact
on performance is really nonexistent.
Internal escaping causing markup failure when tags are nested.
See #9569 and #9572 for example. Functions in markup will no longer
escape their contents, and those should be escaped by caller if needed.
The outposts are east of River Weldyn in the campaign map. Also, in scenario 1, the castle is east of the river. The heartland of Wesnoth country is west of that river, so the eastern bank is the "far" one.
These words date back to the original campaign design by Eric S. Raymond. Back then, the campaign map had the outposts on the western bank of Weldyn.
But in aeb9ec7 the map was replaced with a newer one, with outpost on the eastern bank, which persists to this day with some minor changes (like the southern outpost was moved futher south).
In the existing code, on HARD difficulty, creating a unit with id="Hur" is done twice, first as a Troll Whelp, then as a Troll Rocklobber. As a result, the former unit is replaced with the latter one. As they are created at the same coordinates, I believe this is the intended behavior.
But according to https://wiki.wesnoth.org/SingleUnitWML , reusing the id "may produce unpredictable results in many cases". For example, (I tested it) if you create the new unit at the different coordinates, it instead appears at the former unit's coordinates.
I've added another preprocessor directive, so the unit with this id is created only once on both NORMAL and HARD.
If we need this, it should, as the comment says, be implemented as part of the draw manager. But it also seems like any optimizations on this front are better left to the OS and its compositor.
previously in `undoable_action->undo(side_) ` the undo stack was not in sync with the relpay stack because the code called `undos_.pop_back();` before that and `resources::recorder->undo_cut` after that, this could confuse the code which sends replay commands to the other clients.
In moving recursion_guard from matches_filter() to special_unit_matches() i has forgotten what [leadership] abilities called directly matches_filter().
hitpoints from 42 to 48
movement from 9 to 7
claws from 5x4 to 6x4, now usable on offense
bite from 15x2 to 9x2 charge, now usable in defense
arcane resistance from 20% to 10%
price from 21 to 30
This reverts commit b3802f44ea.
Since commit 70df290 restores the Elvish Outrider to essentially its original stats, the 1.18 balance fix for this one campaign scenario is no longer useful.
Redesigns the Naga Guard, Shield Guard, and High Guard to make their shield bash attack less redundant.
Also adds the new Unwieldy and Guard specials, and deprecates the Absorb special.
This is way more readable and more semantically correct. Essentially, instead of truncating the current and last timestamps to seconds and checking if we were "in" a different second, actually check the duration between the current frame and our last lap point .
Since we're relying on free functions to parse and serialize time_points, it makes more sense to do likewise for durations rather than relying on a config_attribute_value member function. Leaves the assignment support for now.
Includes adjustments to client code to likewise use chrono types. I decided to keep using time_t
(which is just an alias for long_long) for serializing time points. This avoids compatibility issues,
since we keep the same resolution (seconds since Unix epoch), and unless we're going to "properly"
store time points in config, the time_t's unitless value is a good a representation as any.
The pre-processing for --max-fps was basically identical to what draw_manager::get_frame_length does.
This replaces the draw_delay preference with a new refresh_rate preference that more accurately describes
what is being set. video::current_refresh_rate will now take this preference into account, meaning the
build info report will correctly report player-set FPS limits.
The Limit FPS option in the prefs UI was also removed. When it was first introduced (cca79afe4b)
it specifically affected the map rendering code, not the rendering pipeline as a whole. With the 1.17
rendering refactor, this is no longer the case, and so its current usage as the lower bound for frametime
calculations did nothing (all it did was change the lower bound from 0 to -1 when enabled).
It might be worth adding a slider to the UI to dynamically set max fps, but that's a separate change.
Only two places actually made use of the only thing it was useful for (the current tick count),
the countdown clock and the music thinker. The former was simpler to do without, and though it
was slightly useful for the latter, the music thinker really needs to be rethought.
The only thing this could be useful for is providing a stable timestamp for every process call.
That wasn't how it was designed, however. ticks() would populate its value the first time it was
called. Even if (as I considered doing) you change it to register the tick when constructing the
pump_info object, it's still easier (and easier to read) to just call steady_clock::now directly
as needed.
* Functions that return time values now return proper std::chrono::duration units (milliseconds,
seconds, etc.). This removes the need to do manual unit conversions.
* Simple time-to-execute logging was replaced with `utils::optimer`.
* Most uses of `SDL_GetTicks()` have been replaced with `std::chrono::steady_clock`.
* Uses of events::pump_info::ticks() have been replaced with direct calls to steady_clock::now().
This made the countdown_clock code significantly simpler. As for the music_tinker, that needs
to be rethought wholesale.
In special_id/type without the _'active' suffix only the encoding of the special in the attack is checked, and therefore the specials encoded in the [abilities] tags are de facto excluded, except that I forgot this logic in [filter_special] and I have to fix my error before updating the wikia.
uses portraits in the character selection and single click selection on pictures instead of buttons
also adds a dark background to hint messages to make them easier to read
adds arrow markers in the beginning on the units
Addresses https://github.com/wesnoth/wesnoth/issues/9309
when used, the amlas in [unit_type] are replaced by list of amlas in [modify_unit_type],i cannot done add [advancement] without erase amla already present.
GUI2 still does its own handling with double clicks. This doesn't touch that. The default SDL handling is either 500ms (unchanged) or queried from the OS on Windows (an improvement). The click radius defaults to 32, which honestly seems like an acceptable adjustment.
This interface was extremely confusing. pum_info is designed to set `ticks_` only once. This can lead to a situation (exemplified by the music code) where if ticks() is called multiple times in a row, the subsequent times with a counter, that counter would never be incremented since the condition that tests them short circuits on the is-ticks-not-set check.
Also, giving ticks() multiple side effects was very confusing.
These aren't used anymore as of #9332 (save one place, which has been inlined here), and they're not good to rely on, since they don't handle utf8 properly.
This removes `get_teams()`, `get_units()`, and `get_map()` from the display class. These only served as one of the many, many ways to access this data held by the display_context, and that shouldn't be the first-class responsibility of display. Instead, we either access them through the display_context pointer that display holds (whose getter has been renamed to `context()`) or through other more convenient paths (such as play_controller). The editor_display function `map()` has now taken up the mantle of `get_map()`, mostly because both `display::get_map()` and `editor_display::map()` are used, and the former outnumbered the latter.
Removed:
- debug_highlight et al. Unused, and we have the main "display coordinates" debug flag in the base class
- current_team_name. Only used in one place, clearer to just call team_name directly.
- get_terrain_on. Unimplemented
... to fix compile issues with boost 1.86.
Commit 9c665ae3c4 does the same
for wesnothd, but campaignd still fails to compile with
overload resolution failure.
References #9284
I have no idea what's going on with the transition from ubuntu-latest from 22.04 to 24.04. It switched to 24.04, and now it looks like it's back to 22.04...
See https://github.com/actions/runner-images/issues/10636
Rename location_palette::can_swap() to the correct name so that it
overrides as intended, thus making the UI disable the "swap fg and bg
items" button.
The class structure doesn't match the responsibilities here, as part
of UX isn't part of the palette, rather it's part of the tool that
decides whether there are fg and bg items - alternatively, the tool
decides whether right-click is "place bg item", "delete items", or
"show unit tool options". However, this change seems to be enough to
make the UX correct.
The "virtual" is redundant, but add it for consistency with the other
code in these classes.
When I use an ability id=A and include [filter][filter_adjacent]ability_id_active=A, the more units with the adjacent ability I add to it, the slower the game becomes, and at the third unit the game freezes, whereas with the direct comparison of the configs the game only slows down significantly after the 5th unit added.
The only place that used these was the lua show_dialog implementation. We can just construct the window object directly instead. Since this skips out on the finalize_build step (which in the case of modal/modeless_dialog was being called by those respective ctors), I've removed that function and merged it into the window ctor. No need to do it separately.
Builds on work in af81bba53b and 247e5ff055
Note that location_palette::get_help_string is not virtual as it does not inherit from editor_palette (where the pure virtual get_help_string is defined) but rather common_palette.
Resolves https://github.com/wesnoth/wesnoth/issues/7926
[filter_ability] and [filter_ability_active] have been merged into a single filter equipped with the 'active' attribute which when the value is 'true' checks the units affected by the sought ability and when the value is 'false' or unset will check the units carrying the ability even if they are not affected by it.
Because of the attribute strategy, I'm afraid that the developer will be mistaken about its function and that's why I'm not at all keen on it but I want to get out of this impasse.
all_directions better reflects the purpose of the former. Also made it return a value,
since the only places that used it immediately assigned it to a local variable.
The first SDL_KEY_DOWN handler is being called twice, while the second one is being called once.
The tab order handling is done by the first handler, which caused the focus to move *twice*, resulting in the erratic behavior when tab was pressed.
Moving the tab handling to the second one stops this and now focus moves only once when Tab is pressed.
With custom gui2 theme support in #9057, it is now possible to create addons that supply UI Themes or Skins.
This adds support so such addons are properly recognized and validated.
Resolves#9009, closes#9384. Besides the issues that came from having both int and bool conversions (even with bool marked explicit), it doesn't make sense to use int for all numeric assignments. I didn't test whether it would be an issue in practice, but it seems better to let callers be explicit about what type they want for numeric values than risking overflow or wrapping for very large values.
* Removed duplicate map_location hasher, removed unused teleport_id variable, dst_node reference is used at other possible locations, teleport destination heuristic distance now calculated before path finding loop only once, teleport source heuristic distance now stored in nodes, only calculated once and reused.
---------
Co-authored-by: SomeName42 <>
Change Jumpcat from level 1 to level 2
Increase HP from 32 to 40.
Reduce MP from 9 to 7.
Reduce arcane resist from 20 to 10.
Increase cost from 15 to 26
Replace claws' parry with backstab, but reduce damage from 6-3 to 5-3
Remove accuracy from tail, but increase damage from 11-2 to 13-2
2024-10-07 14:27:45 -05:00
2031 changed files with 293637 additions and 247296 deletions
@ -171,6 +171,7 @@ option(GLIBCXX_ASSERTIONS "Whether to define _GLIBCXX_ASSERTIONS" OFF)
option(GLIBCXX_DEBUG "Whether to define _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC. Requires a version of Boost's program_options that's compiled with __GLIBCXX_DEBUG too." OFF)
option(ENABLE_POT_UPDATE_TARGET "Enables the tools to update the pot files and manuals. This target has extra dependencies." OFF)
option(FORCE_COLOR_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." FALSE)
#po: The River Guard posts had been built in 470 YW; they were abandoned in 544 YW.
#po: The wave of colonization had begun around 530 YW.
#po: This intro starts in 625 YW; the king's forces arrive at the outposts in 626 YW.
story=_ "In the days of King Garard I, two strong points had been built along the near bank of the River Weldyn, south of Soradoc, to stop bandits and orcish raiders out of the Estmarks from entering Wesnoth. In later years, the river guard posts had been abandoned as colonists spread into the Estmarks and the orcs were driven in retreat north of the Great River."
story=_ "In the days of King Garard I, two strong points had been built along the far bank of the River Weldyn, south of Soradoc, to stop bandits and orcish raiders out of the Estmarks from entering Wesnoth. In later years, the river guard posts had been abandoned as colonists spread into the Estmarks and the orcs were driven in retreat north of the Great River."
message=_ "(You may now recruit Horsemen and Cavalrymen!)"
[/message]
[set_extra_recruit] # need to set recruits per-unit (instead of per-side) so we don't mess up the plague staff
id=Gweddry
extra_recruit={REGULAR_RECRUIT_LIST}
[/set_extra_recruit]
[set_extra_recruit]
id=Owaec
extra_recruit={REGULAR_RECRUIT_LIST}
[/set_extra_recruit]
[/event]
[event]
name=capture
first_time_only=no
@ -718,34 +750,9 @@
speaker=Owaec
message=_ "Huzzah!! At last, these villagers are liberated! Gweddry, thank you for your aid. I place my Clansmen and myself at your service."
[/message]
[capture_village]
owner_side=2
side=1
[/capture_village]
[modify_unit]
[filter]
side=2
[/filter]
side=1
moves=$($this_unit.max_moves)
attacks_left=1
{TEAM_COLOR_OVERRIDE () blue}
[/modify_unit]
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "(You may now recruit Horsemen and Cavalrymen!)"
[/message]
[set_extra_recruit] # need to set recruits per-unit (instead of per-side) so we don't mess up the plague staff
id=Gweddry
extra_recruit={REGULAR_RECRUIT_LIST}
[/set_extra_recruit]
[set_extra_recruit]
id=Owaec
extra_recruit={REGULAR_RECRUIT_LIST}
[/set_extra_recruit]
[fire_event]
name=owaec_joins
[/fire_event]
[if]
[not]
[have_unit]
@ -879,33 +886,9 @@
speaker=Owaec
message=_ "Huzzah!! May these be the first of many undead to fall before our hooves! Gweddry, thank you for your aid. I place my Clansmen and myself at your service."
[/message]
[capture_village]
owner_side=2
side=1
[/capture_village]
[modify_unit]
[filter]
side=2
[/filter]
side=1
moves=$($this_unit.max_moves)
attacks_left=1
{TEAM_COLOR_OVERRIDE () blue}
[/modify_unit]
[message]
speaker=narrator
image=wesnoth-icon.png
message=_ "(You may now recruit Horsemen and Cavalrymen!)"
[/message]
[set_extra_recruit] # need to set recruits per-unit (instead of per-side) so we don't mess up the plague staff
id=Gweddry
extra_recruit={REGULAR_RECRUIT_LIST}
[/set_extra_recruit]
[set_extra_recruit]
id=Owaec
extra_recruit={REGULAR_RECRUIT_LIST}
[/set_extra_recruit]
[fire_event]
name=owaec_joins
[/fire_event]
[message]
speaker=Owaec
message=_ "Now let us free these villagers from the outlaws terrorizing them!"
message=_ "Dolburras, Owaec has told me of the help you provided his men; both your skill at arms and your tenacious spirit. We wish to offer you this finely crafted shield — an heirloom of my line — and an honor guard as you return to Knalga."
#po: the player chose to give Dolburras the plague staff
message=_ "Dwarf, <i>necromancer</i>, know that Wesnoth will never tolerate your kind. You shall surrender that accursed stave to be destroyed, you shall foreswear the practice of all magic on penalty of death, and you are hereby exiled from Wesnoth. Be grateful for Our mercy."
[/message]
[message]
speaker=Dolburras
#po: "Yeah, fair enough. I don't think my kinsmen will look kindly upon necromancies either."
message=_ "Aye, fair enough. I dinnae think my kinsmen will look kindly upon necromancies either."
#po: "Aye, I am honored. You have my sincerest thanks, your Majesty."
message=_ "Aye, I be honored. Ye have my sincerest thanks, yer Majesty."
[/message]
{CLEAR_VARIABLE plague_staff_wielder_id}
[/then]
[else]
[message]
speaker=Konrad
image=portraits/konrad_II.webp
message=_ "Dolburras, Owaec has told me of the help you provided his men; both your skill at arms and your tenacious spirit. We wish to offer you this finely crafted shield — an heirloom of my line — and an honor guard as you return to Knalga."
speaker=Dolburras
#po: Owaec's dead
message=_ "Aye, I be honored. I only wish he were here to see the Clans avenged."
[/message]
[if]
[have_unit]
id=Owaec
[/have_unit]
[then]
[message]
speaker=Dolburras
#po: "Aye, I am honored. You have my sincerest thanks, your Majesty."
message=_ "Aye, I be honored. Ye have my sincerest thanks, yer Majesty."
[/message]
[/then]
[else]
[message]
speaker=Dolburras
#po: Owaec's dead
message=_ "Aye, I be honored. I only wish he were here to see the Clans avenged."
#po: the player chose to give Hahid the plague staff
message=_ "Southerner, <i>necromancer</i>, know that Wesnoth will never tolerate your kind. You shall surrender that accursed stave to be destroyed, you shall foreswear the practice of all magic on penalty of death, and you are hereby exiled back to the desert wastes. Be grateful for Our mercy."
[/message]
[message]
speaker=Hahid al-Ali
message=_ "Bah, I save you barbarians from an invasion, and this is the thanks I get! What happened to being paid thrice what I’m owed? So much for northerner generosity!"
[/message]
{CLEAR_VARIABLE plague_staff_wielder_id}
[/then]
[else]
[message]
speaker=Konrad
image=portraits/konrad_II.webp
message=_ "Hahid al-Ali, We know of your far-off people, but great distance has caused little contact between us. May it be thus no longer. If you accept, We would appoint you as ambassador between our two realms."
[/message]
[message]
speaker=Hahid al-Ali
message=_ "Me, ambassador to the barbarian kingdoms, what a thought! I am honored, and would be even more honored to learn that the job comes with... excellent pay I hope?"
[/message]
[/else]
[/if]
[message]
speaker=Konrad
image=portraits/konrad_II.webp
message=_ "Hahid al-Ali, We know of your far-off people, but great distance has caused little contact between us. May it be thus no longer. If you accept, We would appoint you as ambassador between our two realms."
[/message]
[message]
speaker=Hahid al-Ali
message=_ "Me, ambassador to the barbarian kingdoms, what a thought! I am honored, and would be even more honored to learn that the job comes with... excellent pay I hope?"
message=_ "Hurt... grarrgghh..." # wmllint: no spellcheck
[/message]
[message]
speaker=Gweddry
id=Gweddry
side=$unit.side
message=_ "Though he was not one of us, he served bravely alongside Wesnoth’s best. We must carry on the good fight."
[/message]
[/event]
@ -171,11 +172,13 @@
message=_ "Alas, my long, storied, and exceedingly profitable career has at last come to an end, so far from home! I only... wish I could have died on the soft sands... instead of among these primitive barbarians..."
[/message]
[message]
speaker=Grug
id=Grug
side=$unit.side
message=_ "Bar... ber... bears? Die why?"
[/message]
[message]
speaker=Dolburras
id=Dolburras
side=$unit.side
message=_ "Aye, ‘tis a sad place for one o’ us foreigners to fall. We’ll miss ye, that’s for sure."
_"Arrows from this crystalline quiver glimmer with a pale magical light, <i><b>illuminating</b></i> the surrounding area and making your bow or crossbow attacks <i><b>arcane</b></i>."
{NOTE_REUSEABLE}
""
()
(
[effect]
apply_to=new_ability
@ -181,7 +178,7 @@ holy_amulet_3 #enddef
_"Holy Amulet"
_"Engraved with a consecrated symbol, this amulet will bless both your <i><b>melee</b></i> and <i><b>ranged</b></i> attacks with <i><b>arcane</b></i> damage."
{NOTE_REUSEABLE}
""
()
(
[effect]
apply_to=new_ability
@ -216,7 +213,7 @@ sentinel #enddef
_"Shield of the Sentinel"
_"Deep within this shield’s towering bulk, enchanted machinery whirrs faintly. Whenever an adjacent ally is hit by an attack, <i><b>this shield’s bearer is hit instead</b></i>."
{NOTE_REUSEABLE}
""
()
(
[effect]
apply_to=overlay
@ -568,7 +565,7 @@ yeti_steak #enddef
_"Yetiburger"
_"Eating this funny tasting meat <i><b>doubles your hitpoints</b></i> and grants <i><b>immunity to cold</b></i>."
_"This incorporeal sword resembles those wielded by undead wraiths. Any mortal brave enough to wield it becomes <i><b>chaotic</b></i> and lashes out at their foes with reckless abandon.
_"This potion bubbles as though over an open flame, yet is cool to the touch. Its drinker gains the <i><b>steadfast</b></i> ability and can <i><b>heal 2 hitpoints each turn</b></i>, like dwarves with the ‘healthy’ trait."
{NOTE_SINGLE_USE}
""
()
(
[effect]
apply_to=new_ability
@ -728,7 +725,7 @@ ring_of_invisibility #enddef
_"Ring of Invisibility"
_"This plain gold ring looks unremarkable, but its wearer gains <i><b>skirmisher</b></i> and <i><b>nightstalk</b></i>, becoming invisible in the dark."
# messes with existing recruiting, and messes with the S18 cutscene
# if Dacyn gets this, it also breaks his scripted advancements (and his S17a recruitment)
@ -784,8 +781,83 @@ plague_staff #enddef
_"Looted from a dead necromancer, the wielder of this dark staff becomes <i><b>chaotic</b></i>, and can <i><b>recruit and recall</b></i> Walking Corpses and Soulless.
<i><b>6x3 impact</b></i> damage, <i>plague</i>."
{NOTE_REUSEABLE}
_"I will not wield such a dark magical artifact, though I shall not begrudge its use by my companions."
# this message makes no sense for Dacyn (his entire quest is to get a dark magical artifact), but I couldn't think of something good and generic that works for everyone.
(
[switch]
variable=unit.id
[case]
value=Owaec
[message]
speaker=unit
message=_"Do not insult me! No clansman will ever stoop to such black magic."
[/message]
[/case]
[case]
value=Gweddry
[message]
speaker=unit
message=_"I already have an army of human soldiers — living soldiers. Let someone else use this staff."
[/message]
[/case]
[case]
value=Dacyn
[message]
speaker=unit
message=_"Tempting! Most tempting... but I fear it would be unwise for me to wield such a thing. That privilege passes onto another."
[/message]
[/case]
[case]
value=Hahid al-Ali
[message]
speaker=unit
message=_"Ha! Good joke! I’m not about to mess around with any of your foul northerner magic; necromancy was the cause of all this trouble in the first place."
[/message]
[/case]
[case]
value=Terraent
[message]
speaker=unit
message=_"I serve the light, not this staff of foul darkness! We should cast away this thing and be done with it."
[/message]
[/case]
[case]
value=Konrad
[message]
speaker=unit
message=_"...what foul thing is this? Remove it from my presence; necromancy shall not take root in Wesnoth, not under my watch."
[/message]
[/case]
[else]
[switch]
variable=unit.type
[case]
value=White Mage,Mage of Light,Paladin
[message]
speaker=unit
message=_"No. I serve that which is good and light, and will not wield such a dark magical artifact."
[/message]
[/case]
[else]
[switch]
variable=unit.race
[case]
value=dunefolk
[message]
speaker=unit
message=_"Fighting your northerners’ foul magic is bad enough. Don’t expect me to wield that — civilized cultures don’t mess around with magic."
[/message]
[/case]
[else]
[message]
speaker=unit
message=_"I will not wield such a dark magical artifact, though I shall not begrudge its use by my companions."
description=_ "Don’t ask where the Dawarf came from. You really don’t want to know. It is a secret well guarded by the great lore-masters of Wesnoth. And it isn’t pretty. Hint: it involves lots of sherbet."
◦ inside the <span face='monospace'>[scenario]</span> element, use <span face='monospace'>map_file="first.map"</span> to load the map file
◦ inside the <span face='monospace'>[scenario]</span> element, use <span face='monospace'>include_file="other.cfg"</span> to load the additional cfg file"
@ -436,7 +436,7 @@ If your add-on will only be used on 1.18 and later, it is instead recommended to
[topic]
id=editor_masks
title=_ "Editor Mask Usage"
text=_ "Masks can be applied to a base map for reusal in several scenarios playing at the same locations."
text=_ "Masks can be applied to a base map for reuse in several scenarios playing at the same locations."
[/topic]
# wmllint: markcheck on
@ -463,9 +463,9 @@ In scenario mode, the button accesses an editor for individual schedules for <re
There is a filter function to show only a subset of the available items — this is the leftmost of the four buttons at the top of the palette, and the graphic changes depending on what is selected. Examples:" +
"<table>" +
"<row><col><img src=icons/terrain/terrain_group_all_30.png align=left /></col><col>" + _ "Show all kinds of terrain</col></row>" +
"<row><col><img src=icons/terrain/terrain_group_water_deep_30.png align=left /></col><col>" + _ "Show only water terrains</col></row>" +
"<row><col><img src=icons/terrain/terrain_group_village_30.png align=left /></col><col>" + _ "Show only villages</col></row>" +
"<row><col><img src=icons/terrain/terrain_group_all_30.png align=left /></col><col>" + _ "Show all kinds of terrain" + "</col></row>" +
"<row><col><img src=icons/terrain/terrain_group_water_deep_30.png align=left /></col><col>" + _ "Show only water terrains" + "</col></row>" +
@ -483,7 +483,7 @@ There is a filter function to show only a subset of the available items — this
" + _ "<header>Native</header>
A map file consists of rows with commaseparated terrain code strings. The only non-terrain information provided by the map syntax is the set of locations created by the <ref dst='editor_tool_starting'>Starting Locations Tool</ref>. The files can be edited with a general purpose text editor like notepad.
A map file consists of rows with comma-separated terrain code strings. The only non-terrain information provided by the map syntax is the set of locations created by the <ref dst='editor_tool_starting'>Starting Locations Tool</ref>. The files can be edited with a general purpose text editor.
These files can be used directly for multiplayer games, the number of players is automatically determined by the number of starting positions. When saved in the default directory, the map can be found in the “Custom Maps” game type of the multiplayer “Create Game” dialog; you may need to refresh the cache (press F5 on the title screen) before a newly-created map appears.
@ -496,7 +496,7 @@ The <italic>map_file</italic> method is preferred over using a preprocessor incl
" + _ "<header>Embedded</header>
The map data can stored as part of a scenario’s .cfg file, directly in the <italic>map_data</italic> attribute. In other words, in the place that the preprocessor would include it when using the preprocessor-include method.
The map data can be stored as part of a scenario’s .cfg file, directly in the <italic>map_data</italic> attribute. In other words, in the place that the preprocessor would include it when using the preprocessor-include method.
<header>Using Embedded Format in Terrain Mode</header>
text="<img>src=misc/logo-bg.png~BLIT(misc/logo.png) align=middle</img>" + _ "<br/><italic>text='Battle for Wesnoth'</italic> is a turn-based fantasy strategy game somewhat unusual among modern strategy games. While other games strive for complexity, <italic>text='Battle for Wesnoth'</italic> strives for simplicity of both rules and gameplay. This does not make the game simple, however — from these simple rules arises a wealth of strategy, making the game easy to learn but a challenge to master.
text="<img src=misc/logo-bg.png~BLIT(misc/logo.png) align=middle /><br/>" + _ "<italic>Battle for Wesnoth</italic> is a turn-based fantasy strategy game somewhat unusual among modern strategy games. While other games strive for complexity, <italic>Battle for Wesnoth</italic> strives for simplicity of both rules and gameplay. This does not make the game simple, however — from these simple rules arises a wealth of strategy, making the game easy to learn but a challenge to master.
The following pages outline all you need to know to play Wesnoth. As you play, new information is added to the various categories as you come across new aspects of the game. For more detailed information on special situations and exceptions, follow the included links."
[/topic]
@ -575,7 +575,7 @@ Mixed terrain types share the properties of multiple basic terrain types — uni
" + "<img src='terrain/hills/regular.png~BLIT(terrain/forest/pine-tile.png)'/>" + "<img src='terrain/hills/desert.png'/>" + "<img src='terrain/cave/hills-variation.png'/><br/>" + _ "One notable exception is bridge terrains, such as <italic>bridges over shallow water</italic>, <italic>fords</italic>, and <italic>bridges over chasms</italic>. Fords are easily passable to both merfolk and humans — all units moving on a ford enjoy the best defense and best movement out of flat and shallow water, rather than the worse movement of the two. Similarly, bridges over chasms are passable to nonfliers (unsurprisingly).
" + "<img src='terrain/water/coast-tile.png~BLIT(terrain/bridge/wood-se-nw.png)'/>" + "<img src='terrain/water/ford-tile.png'/>" + "<img src='terrain/chasm/regular-tile.png~BLIT(terrain/cave/chasm-stone-bridge-sw-ne-tile.png)'/>" + _ "<br/>Land-based villages generally give the best defense and movement as well. These villages are mixed terrains, based on the village terrain type, together with hill, swamp, and cave, respectively.
" + "<img src='terrain/water/coast-tile.png~BLIT(terrain/bridge/wood-se-nw.png)'/>" + "<img src='terrain/water/ford-tile.png'/>" + "<img src='terrain/chasm/regular-tile.png~BLIT(terrain/cave/chasm-stone-bridge-sw-ne-tile.png)'/><br/>" + _ "Land-based villages generally give the best defense and movement as well. These villages are mixed terrains, based on the village terrain type, together with hill, swamp, and cave, respectively.
" + "<img src='terrain/hills/regular.png~BLIT(terrain/village/human-hills-tile.png)'/>" + "<img src='terrain/swamp/water-tile.png~BLIT(terrain/village/swampwater-tile.png)'/>" + "<img src='terrain/cave/floor6.png~BLIT(terrain/village/cave-tile.png)'/><br/>" + _ "Finally, water villages are generally inhospitable to land units, and do not give defense or movement benefits associated with the village terrain type. Instead, they count only as water tiles.