diff --git a/.travis.yml b/.travis.yml index 6a2ce24d13b0..7c82a2392d45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ compiler: env: - BUILD="-O0" - BUILD="-O2" - - BUILD="C++14 -O2" - BUILD="translations" matrix: @@ -47,7 +46,7 @@ before_install: - if [ "$BUILD" == "C++14 -O2" ]; then export WML_TEST_TIME=15; fi - if [ "$BUILD" == "C++14 -O2" ]; then export CXXSTD="1y"; fi - - if [ "$BUILD" == "-O0" ]; then export EXTRA_FLAGS_RELEASE="-O0 -Wno-literal-suffix -Wno-deprecated-declarations"; fi + - if [ "$BUILD" == "-O0" ]; then export EXTRA_FLAGS_RELEASE="-O0 -Wno-deprecated-declarations"; fi - if [[ "$BUILD" == "-O0" ]] && [[ "$CXX" == "clang++" ]]; then export EXTRA_FLAGS_RELEASE="-O0 -Wno-literal-suffix -Wno-deprecated-declarations -Wno-deprecated-register"; fi - if [ "$BUILD" == "-O0" ]; then export PLAY_TEST=false; fi - if [ "$BUILD" == "-O0" ]; then export MP_TEST=false; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index cd46110fbc81..5df802e1f62b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ endif(COMMAND cmake_policy) set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) # use our own version of FindBoost.cmake and other Find* scripts -set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") # # Options @@ -706,7 +706,7 @@ install(FILES l10n-track DESTINATION ${DATADIR}) # configure_file( - "${CMAKE_MODULE_PATH}/uninstall.cmake.in" + "${CMAKE_SOURCE_DIR}/cmake/uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/uninstall.cmake" IMMEDIATE @ONLY ) diff --git a/changelog b/changelog index da8f1a9f38cc..5054619911c6 100644 --- a/changelog +++ b/changelog @@ -4,6 +4,10 @@ Version 1.13.4+dev: * Removed support for SDL 1.2. SDL 2 is now the only supported version. * Terrains: * Changed terrain code of Desert Mountains from Mdy to Mdd. + * User Interface: + * Various design improvements to GUI2 widgets + * New simpler GUI2 loading screen + * New colored cursor graphics * WML engine: * Fix some issues with [foreach] * Fix some issues with backstab-like weapon specials @@ -16,6 +20,11 @@ Version 1.13.4+dev: * New ~SCALE_INTO_SHARP(w,h) IPF which preserves aspect ratio, using nearest neighbor scaling. * Support delayed_variable_substitution= in [on_undo], [on_redo] + Note that this means $unit.x and $unit.y may not reflect the unit's + true location, so using [unstore_unit] on $unit may have unexpected effects. + This applies to $second_unit too. The $x1, $y1, $x2, $y2 variables work fine + though, so in most cases they can be used instead. Anything else in $unit + or $second_unit is also fine. * formula= in SUF can now reference $other_unit via the formula variable "other" * formula= now supported in location, side, and weapon filters * Weapon filters now support number, parry, accuracy, and movement_used @@ -23,6 +32,9 @@ Version 1.13.4+dev: uses full weapon filter. * lua_function=var.member now works in SUF; however, 'var' still needs to be a global variable. + * Added new keys name_generator, male_name_generator and female_name_generator + for the [race] tag to declare a context-free grammar to describe how names + are derived * AiWML: * Simplified aspect syntax which works for all aspects, present and future: * All aspects with simple values can be specified as key=value @@ -120,6 +132,13 @@ Version 1.13.4+dev: of the time in the overall schedule (eg, 1 would be dawn in the default schedule). Optional second argument takes a time area ID, to set local instead of global time. + * New wesnoth.add_fog and wesnoth.remove_fog functions allow changing fog + on the map. The [lift_fog] and [clear_fog] tags now use this. + * New wesnoth.add_sound_source, wesnoth.remove_sound_source, and + wesnoth.get_sound_source functions to allow manipulation of sound + sources. The [sound_source] and [remove_sound_source] now use these. + * New wesnoth.log function for printing log messages. The [wml_message] + and [deprecated_message] tags now use this. * WML tables defined in Lua now accept string keys with array values (where "array" is a table whose keys are all integers). This joins the elements of the array with commas and produces a single string @@ -263,6 +282,8 @@ Version 1.13.4+dev: * Miscellaneous and bug fixes: * Resolve translated logo images not being used (bug #24357) * Ported the "hexometer" tool from Bash to Python 3 + * Recognize hotkey release events + * Allow changing keybindings for scrolling the map. Version 1.13.4: * Language and i18n: diff --git a/data/campaigns/Dead_Water/scenarios/10_The_Flaming_Sword.cfg b/data/campaigns/Dead_Water/scenarios/10_The_Flaming_Sword.cfg index 382203f6c391..16b855207bf0 100644 --- a/data/campaigns/Dead_Water/scenarios/10_The_Flaming_Sword.cfg +++ b/data/campaigns/Dead_Water/scenarios/10_The_Flaming_Sword.cfg @@ -233,7 +233,7 @@ # This is where the lich starts, so he will pick up this # object immediately: - {FLAMING_SWORD 37 3 flaming-sword1} + {FLAMING_SWORD 37 3 flaming_sword1} [recall] id=Caladon @@ -667,7 +667,7 @@ # (because he will be near the top of the screen). [/delay] - {FLAMING_SWORD $x1 $y1 flaming-sword2} + {FLAMING_SWORD $x1 $y1 flaming_sword2} [object] id=drop_staff silent=yes @@ -978,7 +978,7 @@ equals=yes [/variable] [then] - {FLAMING_SWORD $sword_x $sword_y flaming-sword3} + {FLAMING_SWORD $sword_x $sword_y flaming_sword3} {CLEAR_VARIABLE get_sword} {CLEAR_VARIABLE sword_x} {CLEAR_VARIABLE sword_y} @@ -1021,7 +1021,7 @@ equals=yes [/variable] [then] - {FLAMING_SWORD $sword_x $sword_y flaming-sword3} + {FLAMING_SWORD $sword_x $sword_y flaming_sword3} {CLEAR_VARIABLE get_sword} {CLEAR_VARIABLE sword_x} {CLEAR_VARIABLE sword_y} diff --git a/data/core/about.cfg b/data/core/about.cfg index 600794a3fa93..2de0c9bf0088 100644 --- a/data/core/about.cfg +++ b/data/core/about.cfg @@ -1058,6 +1058,9 @@ name = "Doug Rosvick (dlr365)" wikiuser = "dlr365" [/entry] + [entry] + name= "Dugi" + [/entry] [entry] name = "Duthlet" [/entry] @@ -1357,6 +1360,10 @@ [entry] name = "Ryan Henszey" [/entry] + [entry] + name = "Ryan Roden-Corrent (rcorre)" + comment = "Hotkey release and scroll key rebinding" + [/entry] [entry] name = "Sachith Seneviratne (sachith500)" email = "sachith500@gmail.com" @@ -1862,7 +1869,6 @@ [/entry] [entry] name = "Steven Panek (Espreon)" - comment = "Current maintainer" email = "Majora700_AT_gmail_DOT_com" wikiuser = "Espreon" [/entry] @@ -1870,6 +1876,9 @@ name = "Thomas Hockings (Deusite)" wikiuser = "Deusite" [/entry] + [entry] + name = "Wedge009" + [/entry] [/about] [about] diff --git a/data/core/hotkeys.cfg b/data/core/hotkeys.cfg index a9cc925b2fba..f3a5622ade6f 100644 --- a/data/core/hotkeys.cfg +++ b/data/core/hotkeys.cfg @@ -13,6 +13,23 @@ #endif #enddef +[hotkey] + command=scroll-up + key=UP +[/hotkey] +[hotkey] + command=scroll-down + key=DOWN +[/hotkey] +[hotkey] + command=scroll-left + key=LEFT +[/hotkey] +[hotkey] + command=scroll-right + key=RIGHT +[/hotkey] + [hotkey] button=1 command="selectmoveaction" diff --git a/data/core/macros/names.cfg b/data/core/macros/names.cfg index 582d59ac93b8..a06301d8d2f9 100644 --- a/data/core/macros/names.cfg +++ b/data/core/macros/names.cfg @@ -17,62 +17,226 @@ #define DRAKE_NAMES male_names= _ "Egar,Elch,Ga’ash,Gadé Ihn,Gakré Ohm,Galeck,Galsh,Garadin,Garchin,Gark,Garlan,Garlin Ohn,Garrutin,Gart’lo,Garushi,Gashinar,Gashol,Gaushii,Gaustun,Gegchi,Gelka Kon,Gelknick,Gillan,Gisharri,Gost,Grada,Græt Ihn,Grashen,Gravlan,Grag,Grelnit,Grenn Ohn,Greth,Gribbel,Gridda,Grish,Gron Ihn,Ka,Kahn Ih,Karigan,Karri Kon,Karron,Kask,Kegrid,Kerath Ihn,Kerath Kor,Klash,Kon Garashé,Kraag,Krall Ohn,Kran Kor,Krash,Kraslar,Krenli,Kruggen,Kun,Mah Toa,Margian,Mar’Ildian,Markan,Markinos,Mar Ohn,Marra Di’lek,Marrito,Marritos,Merkush,Merritos Gark,Morusté,Murr,Omataké,Reshan,Vashitt,Velnick,Veralon,Veramo,Verath,Verditt,Verkon,Verlinn,Vermad,Vertick,Vladnir" female_names= _ "Alen Ka,Alinash Mal,Ashirt,Auginet Ka,Auuglann,Damell,Dell,Demla,Dinsill,Eshi,Olath,Omage,Omagrra,Orra Ka,Orridan,Orrida,Oshibi,Vallin,Valnirra,Valnitt,Velisk,Verra,Vellin Ka,Veshtar,Vushtin" + male_name_generator= _ << +main={prefix}{suffix}|{prefix}’{suffix}|{prefix}{suffix} {short_name} +short_name=Ohm|Ihn|Ohn|Ka|Murr|Kon|Elch|Ko|Græt|Egar +prefix=Ga|Ge|Gel|Gi|Go|Gra|Gri|Ka|Ko|Kla|Mar|Di|Mer|Mor|Oma|Re|Vel|Vash|Ver|Vla +suffix=ash|kré|lsh|lin|rutin|shinar|rushi|ka|ash|ag|all|ash|slar|li|dian|ritos|rusté|shitt|nick|rath|ditt|kon|mad|tick|nir +>> + female_name_generator= _ << +main={prefix}{suffix}|{prefix}{suffix} {short_name} +prefix=Al|Ali|Ash|Aug|Auug|Da|De|Dem|Din|Ol|Oma|Orri|Oshi|Val|Ver|Vel|Vush +suffix=en|nash|irt|glann|ll|ge|lin|nitt|tin|tar|lisk|rida|grra|sill|la|mell +short_name=Mal|Ka|Emth|Dar|Eshi +>> #enddef #define DWARVISH_NAMES - male_names= _ "Aigaithas,Aigaithil,Aigaithing,Aigaithol,Aigalas,Aigaling,Aigalis,Aigalol,Aigalsil,Aigatas,Aigatis,Aigatlos,Aigatsil,Aigatsol,Aigatus,Aigcatas,Aigcatil,Aigcating,Aigcatis,Aigcatsil,Aigcatsol,Aigcatus,Aigdring,Aigdris,Aigdrlos,Aigdrsil,Aigdrsol,Aigduras,Aigdurlos,Aigdursol,Aigthaing,Aigthais,Aigthasil,Aigthaus,Alaithas,Alaithis,Alaithlos,Alaithol,Alaithsol,Alaithus,Alalas,Alalil,Alalol,Alalsol,Alalus,Alatas,Alatil,Alating,Alatlos,Alatsil,Alcatil,Alcatis,Alcatlos,Alcatsil,Aldras,Aldril,Aldring,Aldris,Aldrlos,Aldrol,Aldrsol,Alduras,Aldurlos,Aldurol,Althaas,Althail,Althalos,Althaol,Althasil,Althasol,Althaus,Anaithas,Anaithil,Anaithing,Anaithis,Anaithsil,Anaithus,Analil,Anallos,Analol,Analsil,Analus,Anatas,Anating,Anatis,Anatol,Anatsol,Ancatas,Ancatil,Ancatol,Ancatus,Andril,Andris,Andrlos,Andrus,Anduril,Andurol,Andursol,Andurus,Anthaas,Anthaing,Anthais,Anthaol,Anthasil,Anthasol,Anthaus,Augaithas,Augaithing,Augaithsil,Augaithus,Augalas,Augaling,Augalol,Augating,Augatlos,Augatol,Augatsil,Augatsol,Augcatas,Augcatil,Augcatis,Augcatol,Augcatsil,Augcatus,Augdras,Augdris,Augdrsil,Augdrus,Augduras,Augduril,Augduring,Augdurol,Augdursol,Augdurus,Augthail,Augthais,Augthalos,Augthaol,Dulaithil,Dulaithing,Dulaithlos,Dulaithsil,Dulaithsol,Dulalas,Dulaling,Dulalis,Dulalsil,Dulatil,Dulating,Dulatol,Dulatsol,Dulatus,Dulcatil,Dulcating,Dulcatlos,Dulcatol,Dulcatsil,Dulcatsol,Duldril,Duldris,Duldrlos,Duldrol,Duldrsil,Duldrus,Dulduras,Dulduring,Duldursil,Duldurus,Dulthalos,Dulthasil,Dulthasol,Dulthaus,Glamaithil,Glamaithis,Glamaithol,Glamaithsol,Glamalil,Glamaling,Glamalis,Glamallos,Glamalsil,Glamalus,Glamatil,Glamatus,Glamcatas,Glamcatil,Glamcating,Glamcatsil,Glamcatus,Glamdras,Glamdril,Glamdrlos,Glamdrsol,Glamduras,Glamduril,Glamduring,Glamduris,Glamdursol,Glamthaas,Glamthaol,Glamthasil,Glamthasol,Glamthaus,Glomin,Gomaithas,Gomaithil,Gomaithol,Gomaithsol,Gomalil,Gomalis,Gomalus,Gomatas,Gomatil,Gomating,Gomatis,Gomatlos,Gomatol,Gomcatil,Gomcatis,Gomcatlos,Gomdras,Gomdril,Gomdring,Gomdris,Gomdrol,Gomdrsil,Gomduris,Gomdurlos,Gomdursil,Gomdursol,Gomdurus,Gomthaas,Gomthalos,Gomthasol,Naraithil,Naraithing,Naraithol,Naraithsil,Naraithsol,Naraithus,Naralas,Naralil,Naralsil,Naralus,Naratlos,Naratol,Naratsil,Narcating,Narcatis,Narcatol,Narcatsil,Narcatsol,Nardras,Nardril,Nardring,Nardris,Nardrol,Nardrsil,Nardrsol,Nardrus,Narduras,Narduril,Nardurol,Narthalos,Narthaol,Pelaithas,Pelaithil,Pelaithing,Pelaithis,Pelaithlos,Pelaithol,Pelaithsil,Pelaithsol,Pelalil,Pelaling,Pelalis,Pelalsil,Pelalsol,Pelalus,Pelatil,Pelating,Pelatis,Pelatol,Pelatsil,Pelatus,Pelcating,Pelcatlos,Pelcatol,Pelcatsil,Peldras,Peldril,Peldrsol,Peldrus,Pelduril,Pelduring,Pelduris,Peldurol,Peldursol,Peldurus,Pelthaas,Pelthail,Pelthasil,Trithaithas,Trithaithil,Trithaithis,Trithaithlos,Trithaithol,Trithaithsil,Trithaithsol,Trithaithus,Trithalis,Trithalol,Trithatas,Trithatil,Trithatlos,Trithatsol,Trithcatlos,Trithcatsol,Trithcatus,Trithdril,Trithdring,Trithdris,Trithdrlos,Trithdrol,Trithdrsol,Trithdrus,Trithduril,Trithduring,Trithdurlos,Trithdurol,Trithdursil,Trithdurus,Triththaas,Triththail,Triththaing,Triththasol,Triththaus" + male_names= _ "Aigaithas,Aigaithil,Aigaithing,Aigaithol,Aigalas,Aigaling,Aigalis,Aigalol,Aigalsil,Aigatas,Aigatis,Aigatlos,Aigatsil,Aigatsol,Aigatus,Aigcatas,Aigcatil,Aigcating,Aigcatis,Aigcatsil,Aigcatsol,Aigcatus,Aigdring,Aigdris,Aigdrlos,Aigdrsil,Aigdrsol,Aigduras,Aigdurlos,Aigdursol,Aigthaing,Aigthais,Aigthasil,Aigthaus,Alaithas,Alaithis,Alaithlos,Alaithol,Alaithsol,Alaithus,Alalas,Alalil,Alalol,Alalsol,Alalus,Alatas,Alatil,Alating,Alatlos,Alatsil,Alcatil,Alcatis,Alcatlos,Alcatsil,Aldras,Aldril,Aldring,Aldris,Aldrlos,Aldrol,Aldrsol,Alduras,Aldurlos,Aldurol,Althaas,Althail,Althalos,Althaol,Althasil,Althasol,Althaus,Anaithas,Anaithil,Anaithing,Anaithis,Anaithsil,Anaithus,Analil,Anallos,Analol,Analsil,Analus,Anatas,Anating,Anatis,Anatol,Anatsol,Ancatas,Ancatil,Ancatol,Ancatus,Andril,Andris,Andrlos,Andrus,Anduril,Andurol,Andursol,Andurus,Anthaas,Anthaing,Anthais,Anthaol,Anthasil,Anthasol,Anthaus,Augaithas,Augaithing,Augaithsil,Augaithus,Augalas,Augaling,Augalol,Augating,Augatlos,Augatol,Augatsil,Augatsol,Augcatas,Augcatil,Augcatis,Augcatol,Augcatsil,Augcatus,Augdras,Augdris,Augdrsil,Augdrus,Augduras,Augduril,Augduring,Augdurol,Augdursol,Augdurus,Augthail,Augthais,Augthalos,Augthaol,Dulaithil,Dulaithing,Dulaithlos,Dulaithsil,Dulaithsol,Dulalas,Dulaling,Dulalis,Dulalsil,Dulatil,Dulating,Dulatol,Dulatsol,Dulatus,Dulcatil,Dulcating,Dulcatlos,Dulcatol,Dulcatsil,Dulcatsol,Duldril,Duldris,Duldrlos,Duldrol,Duldrsil,Duldrus,Dulduras,Dulduring,Duldursil,Duldurus,Dulthalos,Dulthasil,Dulthasol,Dulthaus,Glamaithil,Glamaithis,Glamaithol,Glamaithsol,Glamalil,Glamaling,Glamalis,Glamallos,Glamalsil,Glamalus,Glamatil,Glamatus,Glamcatas,Glamcatil,Glamcating,Glamcatsil,Glamcatus,Glamdras,Glamdril,Glamdrlos,Glamdrsol,Glamduras,Glamduril,Glamduring,Glamduris,Glamdursol,Glamthaas,Glamthaol,Glamthasil,Glamthasol,Glamthaus,Glomin,Gomaithas,Gomaithil,Gomaithol,Gomaithsol,Gomalil,Gomalis,Gomalus,Gomatas,Gomatil,Gomating,Gomatis,Gomatlos,Gomatol,Gomcatil,Gomcatis,Gomcatlos,Gomdras,Gomdril,Gomdring,Gomdris,Gomdrol,Gomdrsil,Gomduris,Gomdurlos,Gomdursil,Gomdursol,Gomdurus,Gomthaas,Gomthalos,Gomthasol,Naraithil,Naraithing,Naraithol,Naraithsil,Naraithsol,Naraithus,Naralas,Naralil,Naralsil,Naralus,Naratlos,Naratol,Naratsil,Narcating,Narcatis,Narcatol,Narcatsil,Narcatsol,Nardras,Nardril,Nardring,Nardris,Nardrol,Nardrsil,Nardrsol,Nardrus,Narduras,Narduril,Nardurol,Narthalos,Narthaol,Pelaithas,Pelaithil,Pelaithing,Pelaithis,Pelaithlos,Pelaithol,Pelaithsil,Pelaithsol,Pelalil,Pelaling,Pelalis,Pelalsil,Pelalsol,Pelalus,Pelatil,Pelating,Pelatis,Pelatol,Pelatsil,Pelatus,Pelcating,Pelcatlos,Pelcatol,Pelcatsil,Peldras,Peldril,Peldrsol,Peldrus,Pelduril,Pelduring,Pelduris,Peldurol,Peldursol,Peldurus,Pelthaas,Pelthail,Pelthasil,Trithaithas,Trithaithil,Trithaithis,Trithaithlos,Trithaithol,Trithaithsil,Trithaithsol,Trithaithus,Trithalis,Trithalol,Trithatas,Trithatil,Trithatlos,Trithatsol,Trithcatlos,Trithcatsol,Trithcatus,Trithdril,Trithdring,Trithdris,Trithdrlos,Trithdrol,Trithdrsol,Trithdrus,Trithduril,Trithduring,Trithdurlos,Trithdurol,Trithdursil,Trithdurus,Triththaas,Triththail,Triththaing,Triththasol,Triththaus" + name_generator= _ << +main={long_name} +long_name={prefix}{centre}{suffix}|{prefix}{centre}{centre}{suffix} +short_name={prefix}{suffix} +prefix=Ai|Al|A|Du|Glam|Dul|Gom|Nar|Pel|Tri|Dun|Do|Bar|Er|Tim|Al|Du|Bu|Bur|Nor|Der|Ur|Gar +suffix=sil|fur|bor|bus|bur|bor|gos|dor|rin|dur|ing|ras|this|tis|rol|sol|las|til|til|tol|los|rol|sol|ril|sil|as|us|lil|fur|mur|fur +centre=lal|mal|ra|dur|thal|thas|ma|gal|thau|ga|ith|ma|cat|la|ral|dur|bur +>> #enddef #define ELVISH_NAMES male_names= _ "Amadrieriand,Amáril,Amelad,Ameldor,Amendel,Ameng,Amilmaldur,Amilmalith,Amilmandir,Amind,Amiol,Amiorion,Amithrarion,Amóldor,Amorfimir,Amorfir,Amowyn,Amulas,Amundil,Anán,Anebrin,Anebrir,Anémbor,Anénduil,Anerion,Anilad,Anil-Gawyn,Anilmambor,Anilmariand,Anior,Anithranduil,Anol,Anon,Anorfing,Anundil,Belán,Belandil,Belarandel,Belel,Belén,Belil-Gandil,Belilmand,Belilmang,Beliondil,Beliril,Belithraldor,Belithrawyn,Belólad,Belómir,Belondel,Belyrion,Cadriembor,Cadrieriand,Cálad,Caladrielas,Calándel,Caldur,Cáldur,Calebrindel,Calebrindir,Calénduil,Calil-Gandir,Calil-Gawyn,Calioriand,Caliril,Calónduil,Caloril,Cándir,Canduil,Caraldur,Carang,Célad,Celadrieriand,Celang,Celaral,Celarandil,Celáriand,Celebririon,Celelas,Celendel,Celér,Celilmalas,Celiondir,Celior,Celiorion,Celong,Celór,Celóril,Celorion,Celundir,Celuwyn,Celyndel,Cénduil,Cindil,Ciong,Cithralad,Cithraldur,Cithrand,Cithrandel,Cithraril,Col,Corfil,Corfildur,Cówyn,Cun,Cundir,Cylas,Delán,Delánd,Delandel,Delaraldur,Deláril,Delawyn,Deléng,Delilmaldor,Deliol,Delithrar,Deliwyn,Delóldor,Delorfilad,Delorfilith,Delorion,Delundil,Eäradriendel,Eäradrier,Eäránduil,Eäraralad,Eärebrindel,Eäréldor,Eäreng,Eärérion,Eärithrandil,Eäromir,Eärorfiriand,Eäryldur,Eäryriand,Eladrieng,Elálith,Elánd,Elándil,Elebrildor,Elebrindel,Elebriril,Elélas,Elémbor,Elemir,Elen,Elil-Garil,Elilmaldur,Eliomir,Eliondil,Elolas,Elólas,Elor,Elorfilad,Elradrien,Elralith,Elran,Elreldur,Elrilmand,Elrioldor,Elriolith,Elrithralith,Elrithranduil,Elrorfir,Elval,Elvandir,Elvaramir,Elváwyn,Elvebrind,Elvebrindel,Elvélith,Elvémir,Elverion,Elvil-Garion,Elvilmaldur,Elvilmaril,Elvioldur,Elvombor,Elvónduil,Elvorfimir,Elvorfiriand,Elvorfiril,Elvóriand,Elvund,Elyldor,Elyrion,Eowambor,Eowanduil,Eowar,Eowaraldor,Eowaran,Eowarar,Eowariand,Eowarion,Eowebrind,Eowémir,Eowil-Garion,Eowimbor,Eowiomir,Eowithrawyn,Eowóldur,Eoworfildor,Eowówyn,Eowylas,Fadriendel,Fandel,Farandir,Fáwyn,Fendel,Fer,Filman,Fioril,Fithraril,Forfilas,Fyrion,Gadriendil,Gadrieng,Galadrieldor,Galálad,Galálas,Galalith,Galar,Galelas,Galeldur,Galelith,Galémbor,Galithrariand,Galoldur,Galuldur,Galur,Galurion,Gambor,Gán,Ganduil,Garaldor,Gararil,Gelad,Géril,Gil-Gandel,Gil-Gang,Giombor,Githral,Githralad,Gladriendil,Glal,Glámbor,Glandil,Glarang,Glararil,Glilmal,Glimir,Glior,Glólas,Gloldor,Glómir,Glon,Glul,Golad,Gor,Gumbor,Gyl,Gymbor,Gyn,Harariand,Háriand,Hebril,Hemir,Hénduil,Hilas,Hil-Garion,Hilmariand,Hiong,Hirion,Hithrandel,Horfilad,Horfindel,Hundel,Hymir,Hyrion,Hywyn,Isadrieng,Isándir,Isarandel,Isarar,Iselas,Isér,Isilmandel,Isirion,Isithral,Isól,Isóndel,Isóng,Isorfilad,Isorfindir,Isuwyn,Isyndel,Legal,Legaran,Legémir,Legéril,Legilad,Legil-Gal,Legiondel,Legithralith,Legorfindil,Legorfirion,Legówyn,Legyl,Legyn,Linduilas,Lómadrieril,Lómarand,Lómariand,Lómebrilad,Lómebrind,Lómémbor,Lómilmaril,Lómiriand,Lómorfindil,Lómowyn,Madrieril,Maldur,Mánduil,Maraldur,Mebrin,Méng,Mérion,Miolith,Miomir,Mithrand,Mondir,Móndir,Morfilas,Morfin,Morfiriand,Mylith,Nadrieldor,Nalith,Nán,Nél,Nil-Galas,Nil-Galith,Nil-Gar,Nilmar,Nóndel,Norfildor,Norfilith,Norfindil,Norfindir,Numbor,Nyldur,Padrieriand,Padrieril,Pamir,Paraldor,Parariand,Pilmalad,Pindir,Pór,Porfildur,Pumbor,Pyldur,Rebrir,Réndir,Rilmandil,Rithrandil,Ról,Róldor,Roldur,Róldur,Rorfilad,Rorfindil,Rówyn,Ryn,Sadrielas,Sebrin,Sebriril,Sénd,Sil-Gal,Sólad,Sorfind,Sóriand,Tadriendir,Taral,Taraldur,Táriand,Tendel,Téwyn,Thradrieriand,Thrambor,Thraral,Threbring,Thrélad,Thréldur,Thril-Gamir,Thril-Gandir,Thril-Gar,Thrilmandel,Thrimir,Thrion,Thrithran,Throlas,Thrón,Thróng,Thrund,Thryriand,Til-Gan,Tilmalad,Tilmalas,Tinandir,Tinarambor,Tinarariand,Tinén,Tinil-Ganduil,Tinilmand,Tinilmawyn,Tinimir,Tinindil,Tinithrar,Tinoldor,Tinond,Tinorfind,Tinorfiriand,Tinóriand,Tinowyn,Tinun,Tinyl,Tion,Tolas,Torfildur,Tówyn,Tylad,Unadrieldor,Unadrier,Unál,Unalas,Unálas,Unaraldur,Unaril,Unárion,Unebrin,Unebrind,Uneldor,Unil,Unil-Gan,Uniolith,Unioril,Unólith,Unombor,Unóndel,Unondir,Unorfildor,Unorfiril,Unorfiwyn,Unulad,Uradrielas,Uradrierion,Urálas,Urálith,Urambor,Urér,Uril-Gambor,Urilmalith,Uróldor,Urorfildor,Urul,Urymir,Válad,Ván,Vándel,Vandir,Varalas,Vararion,Vebril,Vebrilas,Vebrinduil,Vel,Vilith,Vol,Vólas,Vóldur,Vondel,Vorfin,Vorfindil,Vulas,Vuldur,Vunduil,Vylas,Vyldor" female_names= _ "Amadrielia,Amadrielindë,Amadriendra,Amadriewen,Amarang,Amebrilindë,Amedë,Améthien,Amewien,Amil-Gadith,Amil-Garith,Amilmadia,Amiolith,Amionia,Amithraniel,Amithrawien,Amiwen,Amodë,Amorfilith,Amorith,Amulia,Amuviel,Amuwen,Analia,Anang,Anaraclya,Anáthien,Anebriniel,Anilmarith,Aning,Aniorith,Anówien,Anundra,Anuthiel,Anuthien,Anylindë,Anythien,Anywien,Belaclya,Beladrielith,Beladriewen,Beladriewien,Belarania,Belaraviel,Belebrindra,Belendra,Beliolia,Belithraniel,Belithrawiel,Belithrawien,Belowen,Belulindë,Cádë,Cadriewen,Caladrieng,Calándra,Calang,Calánia,Calebriwien,Calewen,Calewiel,Calil-Galith,Calilmalith,Calithraclya,Calóniel,Calorfiniel,Calówien,Caluclya,Ceclya,Celadë,Celália,Celálindë,Celarandra,Celararith,Celárith,Celebriniel,Celebriviel,Celelith,Celéng,Celérith,Celidien,Celilith,Celindë,Celiodë,Celioniel,Celith,Celithradith,Celódith,Celorfilindë,Celorfing,Celorfiwien,Celówien,Celylia,Cethien,Cing,Cithralith,Cithrania,Cithrawen,Cólindë,Corfiviel,Cydia,Delararith,Delebrinia,Deléthien,Delil-Ganiel,Deliowen,Delithrathiel,Delóndra,Delorfilindë,Delorfithien,Deloviel,Delydien,Eäradriedien,Eärániel,Eärarawien,Eärélia,Eärenia,Eärewen,Eäréwiel,Eärilmadë,Eärilmathien,Eäriolith,Eärithrang,Eärorfiwien,Eärudë,Eladriedë,Eladrielia,Elarawiel,Elebrindra,Eledë,Elelith,Elil-Gang,Elilmalia,Elilmawien,Elithraclya,Elithradien,Elóndra,Elorfing,Elorfithien,Elradrierith,Elránia,Elrebridith,Elréthiel,Elrilindë,Elrilmandra,Elrilmathien,Elrithiel,Elrithradith,Elriwen,Elródith,Elrorfidia,Eluviel,Elvádia,Elvánia,Elvil-Gawien,Elvilmathiel,Elviniel,Elviondra,Elvithrang,Elvithrathien,Elvowien,Elvyniel,Elvyviel,Elynia,Elywen,Eowalia,Eowarawien,Eowathiel,Eowebridith,Eowedith,Eowidien,Eowil-Galindë,Eowilindë,Eowiowien,Eowylia,Eowyniel,Fadriedith,Fadrielia,Fadriendra,Fadrienia,Falindë,Fáthiel,Fathien,Fáwien,Feclya,Féthiel,Fil-Galia,Fil-Gathiel,Fil-Gawien,Filmaclya,Fioniel,Fódë,Fólindë,Fulindë,Gadrieclya,Gadrieviel,Galadriethien,Galándra,Galaraniel,Galebrilia,Galebrindra,Galédë,Galedien,Galéwiel,Galil-Gania,Galilmadia,Galiothiel,Galithrathien,Galólia,Galolindë,Galorfiwiel,Galothiel,Galowen,Galundra,Galyniel,Gathien,Gáviel,Gebririth,Gewen,Gil-Gawien,Gilia,Gioniel,Gioviel,Giowen,Githrania,Githrawiel,Glália,Glebrithien,Gléndra,Glilmadien,Glilmawiel,Glithiel,Gloclya,Glodith,Glorfilith,Gloviel,Glowiel,Goclya,Godien,Gólia,Golindë,Guviel,Harawiel,Haviel,Háwien,Héclya,Hedia,Helith,Hewen,Hil-Gania,Hiodë,Hiwien,Hodia,Hódia,Horfinia,Horfiwien,Hóthiel,Huclya,Hunia,Huthien,Hyclya,Hythiel,Hythien,Isadrieng,Isáwen,Isebridien,Isebrinia,Isendra,Iséng,Iseviel,Isil-Garith,Isilindë,Isithradë,Isithradien,Isithrarith,Isithrawiel,Isóthien,Legádë,Legadien,Legadrieclya,Legadriedë,Legadrieniel,Legaraclya,Legebrilia,Legelith,Legeng,Legéniel,Legethiel,Legidia,Legil-Galindë,Legilmadith,Legilmawiel,Legithralindë,Legithrandra,Legithrania,Legolith,Legondra,Legorfidë,Lómániel,Lómebriclya,Lómebriniel,Lómedia,Lómeniel,Lómiclya,Lómilindë,Lómilmathiel,Lómilmawiel,Lómithradë,Lómithrarith,Lómódë,Lómolith,Lómóndra,Lómorfing,Lómorith,Lómudia,Lómulindë,Lómuniel,Lómuthiel,Lómynia,Lómythien,Mádia,Madrieclya,Maraclya,Mebriwiel,Meclya,Medien,Mil-Gathiel,Mil-Gathien,Milindë,Milith,Miowen,Miowiel,Mithradë,Mithralindë,Módë,Módia,Moniel,Morfilindë,Munia,Myndra,Mywiel,Narania,Naraniel,Náviel,Nawen,Newen,Nil-Gang,Nilmadia,Niodien,Niolia,Niothien,Nithraniel,Nithrarith,Nowen,Nydith,Pádia,Padriedith,Paralindë,Parandra,Pawen,Pebridien,Pil-Gadia,Pil-Gadien,Pilindë,Pindra,Pong,Porfindra,Porfiwien,Póviel,Pulia,Puthien,Reniel,Réviel,Ril-Gawien,Rindra,Riothien,Róng,Rorfiviel,Sadrienia,Sadrierith,Sálindë,Sáng,Saradith,Sarandra,Sédith,Sendra,Sethien,Silmaclya,Silmathiel,Sioclya,Siorith,Sithrang,Sithrawen,Soniel,Sothiel,Sothien,Syniel,Tadrierith,Tang,Taradien,Tarathiel,Tathiel,Terith,Thradia,Thrália,Thraraviel,Threbriniel,Thredien,Thrérith,Thridith,Thrinia,Thrithradia,Thrithrandra,Thrithraniel,Throlith,Throng,Throthiel,Thrulith,Thruthien,Thryng,Til-Gandra,Tilmaclya,Tilmaviel,Tináclya,Tinadriethien,Tinálindë,Tinaraniel,Tinarathien,Tinawiel,Tinebrithiel,Tinerith,Tinil-Gania,Tinil-Gawiel,Tiniolith,Tinithrathiel,Tinóng,Tinorfilith,Tinorfithien,Tinudia,Tiorith,Tithrathien,Tówiel,Tuniel,Unadrieng,Unáthien,Unebridë,Unénia,Unil-Gadia,Unilmadia,Unindra,Uniodë,Uniolia,Uniong,Unionia,Unóndra,Unorfiwen,Unulindë,Unuviel,Unynia,Uraclya,Uradriedia,Uránia,Urárith,Urebriclya,Ureclya,Urilmadia,Urilmawiel,Uriolia,Urithralindë,Uruthien,Uryrith,Vadrierith,Vadrieviel,Vadriewen,Varawiel,Vebrithien,Vil-Gandra,Violindë,Viowiel,Vithrang,Vithraniel,Viwiel,Vódia,Vóng,Vorficlya,Vorfing,Vorfirith,Vorfiwiel,Vówien" + male_name_generator= _ << +main={generated_prefix}{consonnant}{suffix}|{prefix}{centre}{suffix} +generated_prefix={starting_consonnant}{vowel} +starting_consonnant=C|D|F|L|M|N|P|Qu|R|S|T|V +vowel=a|e|i|o|ae|é|ë +consonnant=n|l|r|m|s|v|th|nn +prefix={prefix_vc}{vowel}|{prefix_cv} +prefix_vc=Lon|Eon|Ad|Sar|Al|Tal|Tin|El|Leg|Or|Tir|Ol|Cál|Cán|Elv|Fan|Fad|Fith|Fil|Gal|Glad|Leg|Glar|Gli|Hár|Tad|Sór|Pyr +prefix_cv=Ama|Ami|Be|Ca|Ga|Isi|Ha|He|Le|Ló|Ny|Ni|Ma|Thu|Thri|Ti|Unu|Ve|Va +suffix=or|im|ian|in|ar|iel|as|eon|as|or|ion|al|and|ér|as|ir|el|al|ad|ael +centre={short_centre}|{short_centre}|-{short_centre}|{short_centre}- +short_centre=lol|febr|tom|lith|nal|lor|wón|rad|rien|mar|reb|riel|mal|ram|nil|nim|nol|bris|lad|rier|ra|fil|thran|man +>> + female_name_generator= _ << +main={generated_prefix_v}{centre_v}{suffix_v}|{generated_prefix_c}{centre_c}{suffix_c} +generated_prefix_v={starting_consonnant}{vowel} +generated_prefix_c={starting_consonnant}{vowel}{consonnant} +starting_consonnant=C|D|F|L|M|N|P|Qu|R|S|T|V +vowel=a|e|i|o|ae|é|ë +consonnant=n|l|r|m|s|v|th|p|d|f|t +prefix_c=Val|Ol|Am|An|El|Fa|El|Glo|Hu|Le|Mil|Nil|Pin|Por|Mot|Mor|Thral|Leg|Nam|Nym|Sim|Len|Is|Thal +prefix_v=La|Va|Tha|Ne|Ay|Ce|Fa|Phe|Ja|Que|Ma|Mi|Pa|Ri|Siu|Ga|Ca|De|Eä|Eo|No|Pó|Le|Ló|Isá|Pa|Sa|Ni|Ti|Uno|Uni|Vó|Gio +suffix_v=thea|nia|lia|kea|ni|ith|niel|wiel|ra|dë|lya|thiel|nna|nne +suffix_c=iel|ien|ya|a|ë|i|ia|ea +centre_v=|{short_centre_v} +short_centre_v=nna|lla|na|thi|saie|li|ma|lo|thra|ló|rá|bri|fi|mi|nio|wi|né|nu|wi +centre_c=|{short_centre_c} +short_centre_c=enn|all|an|ith|el|il|am|ol|arth|ól|ár|ir|if|im|ion|iw|én|un|iw +>> #enddef # Very restricted phonotactics on these for a reason: Gryphons have beaks. #define GRYPHON_NAMES male_names= _ "Graa,Greaa,Gree,Kaaa,Kassshh,Kessshh,Korro,Kraa,Kuu,Kzaaa,Kzuuu" female_names= _ "Kaasa,Kayya,Keyya,Kiira,Korra" + male_name_generator= _ << +main={prefix}{suffix}|{prefix}{centre}{suffix} +prefix=Gr|Ka|Ke|Ko|Kr|Kz +suffix=aa|eaa|ee|aaa|ssshh|rro|uu|uuu +centre=arr|aash|eez|ozz +>> + female_name_generator= _ << +main={prefix}{suffix}|{prefix}{centre}{suffix} +prefix=Kaa|Ka|Ke|Kuu|Ko +suffix=sa|yya|ra|rra +centre=err|aash|eez|azz +>> #enddef #define HUMAN_NAMES male_names= _ "Addraecyn,Addraenvan,Addraer,Addraercyn,Addraryn,Addreddry,Addredry,Addregwyn,Addrenyc,Addreoddry,Addreoddyn,Addreonyc,Addreorcyn,Addreran,Addribryn,Addriddyn,Addrocyn,Addroryn,Addrunvan,Addrurcyn,Addryllyn,Addrynvan,Aethacyn,Aethadry,Aethaec,Aethaeran,Aethaeryn,Aethagwyn,Aethanry,Aetharcyn,Aethec,Aethellyn,Aethenvan,Aetheoc,Aetheollyn,Aetheonyc,Aetheorcyn,Aethercyn,Aetherraent,Aethibryn,Aethiddry,Aethircyn,Aethobryn,Aethoddyn,Aethonnyn,Aethuc,Aethudry,Aethugwyn,Aethun,Aethunry,Aethydry,Aethynyc,Blac,Bladoc,Blaec,Blaedry,Blanry,Blebryn,Bledoc,Blemyr,Blennyn,Blenvan,Bleollyn,Blercyn,Blidd,Bliddry,Blillyn,Blinvan,Blollyn,Blubryn,Blucyn,Bludry,Blullyn,Bluran,Blybryn,Blydd,Blygwyn,Blymyr,Blyr,Bucyn,Cac,Cadry,Caebryn,Caedry,Caeran,Caercyn,Car,Carac,Caraddry,Caradoc,Caraedry,Caraennyn,Cararyn,Caredd,Careddry,Caregwyn,Caren,Careobryn,Careogwyn,Careonvan,Careorraent,Careoryn,Carercyn,Caric,Cariddry,Carocyn,Caroddyn,Caror,Caroran,Carraent,Carudoc,Carullyn,Carygwyn,Caryn,Cebryn,Cemyr,Cennyn,Ceoc,Ceoddry,Ceoddyn,Ceomyr,Ceonnyn,Ceonry,Ceoryn,Cicyn,Cin,Cinry,Coc,Convan,Corcyn,Cubryn,Cunry,Curyn,Cynyc,Cyryn,Dac,Dadd,Dadoc,Daeddry,Daedoc,Daellyn,Demyr,Denvan,Deodd,Deollyn,Deonyc,Derraent,Dibryn,Dinnyn,Dircyn,Dycyn,Dyddyn,Gaddry,Gaebryn,Gaedry,Gaercyn,Gagwyn,Gan,Gannyn,Gar,Gecyn,Geddyn,Gegwyn,Geodry,Ginvan,Glacyn,Gladoc,Glaercyn,Glarraent,Gleddry,Gleoddyn,Gleran,Gliddyn,Glillyn,Glinry,Glircyn,Gloddry,Gloddyn,Glonry,Glonvan,Glumyr,Glun,Glunry,Glunvan,Glyc,Glydd,Glydoc,Glynry,Glynvan,Glyran,Goc,Gor,Gubryn,Gudd,Gullyn,Gumyr,Gur,Gwadoc,Gwaec,Gwaeddyn,Gwan,Gweddyn,Gwegwyn,Gwellyn,Gwennyn,Gwenyc,Gweocyn,Gweodd,Gweodoc,Gweodry,Gweogwyn,Gweoran,Gwidoc,Gwilam,Gwodd,Gwoddyn,Gwollyn,Gwor,Gwucyn,Gwudoc,Gwumyr,Gwuran,Gwybryn,Gwycyn,Gwyddry,Gwydoc,Gwymyr,Gwynnyn,Gydoc,Gyllyn,Gymyr,Haldar,Labryn,Ladoc,Laellyn,Lan,Lannyn,Laran,Lec,Lemyr,Lenvan,Leogwyn,Lercyn,Ligwyn,Lin,Liryn,Lonnyn,Lorraent,Luddry,Ludoc,Lunnyn,Lunvan,Lurraent,Mac,Maddyn,Maennyn,Manry,Manyc,Marcyn,Mec,Menvan,Meollyn,Meon,Meonnyn,Meorraent,Middry,Midry,Mimyr,Modd,Moddry,Monry,Moran,Morcyn,Mubryn,Mudoc,Mugwyn,Murcyn,Mydoc,Mygwyn,Myn,Myrraent,Owac,Owadd,Owaddyn,Owaecyn,Owaedry,Owain,Owarcyn,Owaryn,Owecyn,Owedry,Oweomyr,Oweor,Oweorcyn,Oweran,Owercyn,Owidry,Owinvan,Owinyc,Owodd,Owoddry,Owogwyn,Owollyn,Oworan,Oworcyn,Oworraent,Owuddry,Owuddyn,Owugwyn,Owur,Owyran,Rabryn,Radd,Ranvan,Rar,Reoddyn,Reodry,Rhaecyn,Rhaedoc,Rhaemyr,Rhaerraent,Rhanry,Rharcyn,Rhenry,Rhenvan,Rhenyc,Rheodd,Rheoddyn,Rheollyn,Rheor,Rheoran,Rheorraent,Rheran,Rherraent,Rhobryn,Rhodry,Rhollyn,Rhonvan,Rhubryn,Rhugwyn,Rhunyc,Rhur,Rhygwyn,Rhyllyn,Rhynyc,Rhyrcyn,Rhyrraent,Rocyn,Roddyn,Romyr,Ron,Ronry,Rubryn,Ruddry,Rumyr,Run,Rurcyn,Rybryn,Rycyn,Ryddry,Rygwyn,Rynnyn,Rynry,Saec,Saellyn,Saemyr,Saenvan,Saercyn,Sanyc,Saran,Sarraent,Secyn,Seddyn,Sedry,Sellyn,Sennyn,Seoddry,Seorcyn,Sercyn,Siddry,Simyr,Siryn,Sodd,Sodry,Soran,Suc,Sudd,Surcyn,Sydd,Syran,Syryn,Tabryn,Taec,Taedd,Taedoc,Taemyr,Taenvan,Taercyn,Tanry,Tarcyn,Teddyn,Tegwyn,Ten,Tennyn,Tenvan,Teobryn,Teoddyn,Teor,Teorcyn,Terraent,Tinry,Tinvan,Tiryn,Todd,Tudd,Tuddry,Tudoc,Tunvan,Turraent,Tyddyn,Vaddyn,Vaeddyn,Vaedry,Vaennyn,Varcyn,Ven,Vennyn,Veocyn,Veoddyn,Veodry,Veogwyn,Veomyr,Vinvan,Vinyc,Virraent,Vobryn,Vogwyn,Vonry,Vuddyn,Vugwyn,Vyc,Vygwyn,Vyrcyn,Yracyn,Yraec,Yran,Yrannyn,Yranvan,Yraryn,Yredd,Yreddyn,Yregwyn,Yreryn,Yrinvan,Yrirraent,Yroddry,Yrullyn,Yrumyr,Yrunnyn,Yrunvan,Yryllyn,Yrymyr,Yrynyc,Yryrcyn" female_names= _ "Alabrylla,Alaebrylla,Alaeniver,Alalla,Alalonna,Alaryan,Aleacla,Aleaniver,Aleara,Alearka,Alena,Alengwen,Alilonna,Alingwen,Alolla,Alolonna,Alora,Alubrylla,Aluniver,Aluryan,Alussa,Alwcla,Alwllyra,Alwlyan,Alwna,Alybrylla,Alynoic,Alyra,Alyryan,Braedda,Brassa,Bravyan,Breabrylla,Breall,Brealla,Brealonna,Breana,Brell,Brellyra,Brera,Brerka,Breryan,Bricla,Brirka,Brobrylla,Brollyra,Brona,Bronoic,Brora,Brorka,Brungwen,Bruryan,Brwra,Brycla,Brynoic,Caella,Caena,Caengwen,Caevyan,Call,Calla,Cassa,Cealonna,Cera,Ceryan,Cibrylla,Cicla,Cinoic,Cira,Cissa,Clacla,Claella,Claelyan,Claenoic,Clalla,Clallyra,Clara,Clarka,Clavyan,Cleacla,Cleall,Clealyan,Cleana,Cleanoic,Clenoic,Clibrylla,Clill,Clillyra,Clilyan,Clinoic,Clissa,Clobrylla,Clollyra,Clona,Clongwen,Clungwen,Clurka,Cluvyan,Clwdda,Clwlla,Clwvyan,Clydda,Clylla,Cora,Coryan,Cucla,Cudda,Curyan,Cwdda,Cwlonna,Cwngwen,Cwvyan,Cydda,Cylla,Cyllyra,Cylyan,Cyniver,Cyvyan,Daedda,Daelyan,Daengwen,Daenoic,Dalla,Dallyra,Dangwen,Dara,Dassa,Deanoic,Deassa,Della,Devyan,Dicla,Diniver,Dissa,Dollyra,Dullyra,Dulonna,Dwbrylla,Dwdda,Dwna,Dwnoic,Dwra,Dybrylla,Dydda,Dyssa,Elacla,Elaedda,Elaell,Elaelonna,Elaessa,Elaevyan,Elallyra,Elalonna,Elara,Elavyan,Elealla,Eleanoic,Elearka,Elenoic,Elerka,Elivyan,Elulonna,Elurka,Elwllyra,Elwlonna,Elwngwen,Elwra,Elycla,Elyllyra,Elyngwen,Elyniver,Elyrka,Gwaera,Gwaessa,Gwangwen,Gweacla,Gwedda,Gwerka,Gwicla,Gwirka,Gwobrylla,Gwoll,Gwona,Gwongwen,Gwonoic,Gworyan,Gwullyra,Gwussa,Gwwcla,Gwwna,Gwwvyan,Gwycla,Gwydda,Heldra,Jacla,Jaena,Jaerka,Jaevyan,Jalyan,Jana,Jarka,Jassa,Jeabrylla,Jealla,Jeanoic,Jeniver,Jiryan,Jissa,Joll,Jolla,Jona,Jongwen,Jonoic,Jora,Jorka,Jovyan,Judda,Jull,Julonna,Jura,Jwll,Jwlyan,Jycla,Jyniver,Jynoic,Jyrka,Jyvyan,Laeniver,Laenoic,Laeryan,Langwen,Larka,Lassa,Lealonna,Lealyan,Ledda,Lelonna,Lelyan,Lengwen,Lerka,Lessa,Lidda,Lill,Lina,Lirka,Liryan,Livyan,Locla,Lodda,Lollyra,Lolonna,Lulla,Lulyan,Lungwen,Lunoic,Luryan,Lwcla,Lwlla,Lwnoic,Lwryan,Lycla,Lylla,Lylyan,Lyna,Lynoic,Maecla,Maeniver,Mavyan,Meacla,Mealyan,Meana,Meangwen,Meanoic,Medda,Melonna,Mengwen,Meniver,Meradda,Meraecla,Meraelyan,Merall,Merallyra,Meralonna,Merana,Meranoic,Merealonna,Mereangwen,Mereaniver,Merebrylla,Merella,Merengwen,Meressa,Merilyan,Merina,Merinoic,Merissa,Merivyan,Merolla,Merolyan,Merona,Meroniver,Merubrylla,Merudda,Merurka,Merwlla,Merwnoic,Merwryan,Merydda,Merylyan,Messa,Milonna,Molyan,Moniver,Mossa,Mudda,Mullyra,Mulyan,Muryan,Mwbrylla,Mwlyan,Mwngwen,Mwnoic,Mycla,Myll,Mylla,Myra,Myvyan,Nabrylla,Naebrylla,Naecla,Naell,Nalyan,Nangwen,Nealla,Neallyra,Nealonna,Neavyan,Nera,Nessa,Ninoic,Niryan,Nivyan,Nobrylla,Nolla,Nonoic,Norka,Noryan,Nucla,Nulla,Nulyan,Nungwen,Nuvyan,Nwllyra,Nwryan,Nwvyan,Nybrylla,Nyll,Nylyan,Nyryan,Nyssa,Nyvyan,Raebrylla,Raera,Raerka,Ralonna,Rara,Rarka,Rassa,Reacla,Realla,Reana,Reangwen,Rella,Relyan,Rengwen,Rerka,Revyan,Rilonna,Rilyan,Rirka,Rora,Rucla,Ruryan,Rwdda,Rwlla,Rwllyra,Rwlonna,Rwngwen,Rybrylla,Ryna,Ryngwen,Saell,Saellyra,Saeniver,Saerka,Saessa,Sallyra,Sanoic,Sara,Sassa,Searka,Sena,Senoic,Sera,Silonna,Sira,Siryan,Sona,Sorka,Subrylla,Sull,Sulonna,Sulyan,Sura,Sussa,Swlla,Swlyan,Swngwen,Swnoic,Swvyan,Syllyra,Sylyan,Syssa,Ysacla,Ysaenoic,Ysaerka,Ysanoic,Yseacla,Ysealonna,Ysealyan,Ysedda,Ysell,Yselonna,Ysilyan,Ysinoic,Ysodda,Ysongwen,Ysonoic,Ysura,Yswniver,Ysycla,Ysylla,Ysylyan,Ysyrka,Ysyssa" + male_name_generator= _ << +main={generated_prefix_c}{suffix_c}|{generated_prefix_v}{suffix_v}|{prefix_c}{centre_c}{suffix_c}|{prefix_v}{centre_v}{suffix_v} +generated_prefix_c={starting_consonnant}{vowel}{consonnant}|{starting_vowel}{consonnant} +generated_prefix_v={starting_consonnant}{vowel}|{starting_vowel} +starting_consonnant=B|C|D|G|H|L|M|R|Rh|S|T|V +starting_vowel=A|E|I|Y|Ae +vowel=a|e|i|o|u|y|eo|ae +consonnant=w|l|d|n|r|rc|ll|nn|dd|th +prefix_c=Add|Den|Derr|Gum|Mad|Mar|Ow|Tedd|T{vowel}n|Var|Vin|Vob|Vug|Yr|Rhyr +prefix_v=Ae|Bl{vowel}|C{vowel}|D{vowel}|Gl{vowel}|G{vowel}|Gw{vowel}|Ha|L{vowel}|M{vowel}|R{vowel}|Rh{vowel}|S{vowel}|S{vowel}|T{vowel}|V{vowel} +suffix_c=yn|er|yc|ec|oc|yr|in|aent +suffix_v=ry|ryn|ran|lyn|van|nyc +centre_c=redd|reor|og|thyn +centre_v=rae|ra|thar|gwy +>> + female_name_generator= _ << +main={generated_prefix_c}{suffix_c}|{generated_prefix_v}{suffix_v}|{prefix_c}{centre_c}{suffix_c}|{prefix_v}{centre_v}{suffix_v} +generated_prefix_c={starting_consonnant}{vowel}{consonnant}|{starting_vowel}{consonnant} +generated_prefix_v={starting_consonnant}{vowel}|{starting_vowel} +starting_consonnant=B|C|D|G|H|L|M|R|Rh|S|T|V +starting_vowel=A|E|I|Y|Ae +vowel=a|e|i|o|u|y|eo|ae +consonnant=w|l|d|n|r|rc|ll|nn|dd|th +prefix_c=Al|El|Mer|Mil|Rer|Ys|M{vowel}r|M{vowel}l +prefix_v=A|Br{vowel}|Cl{vowel}|C{vowel}|D{vowel}|Gw{vowel}|He|J{vowel}|L{vowel}|M{vowel}|N{vowel}|R{vowel}|S{vowel} +suffix_c=yan|oic|ell|yll +suffix_v=wyn|nna|lla|ra|la|wyan|ssa|ka|ven +centre_c=il|ing|ol|ur|ung|ean|eal|ong|al|iv +centre_v=na|lla|na|ry|li|ni|ri|rae|bry +>> #enddef #define KHALIFATE_NAMES male_names=_ "Aban,Abbas,Abbud,Abdul-ʿAdl,Abdul-Ahad,Abdul-Alim,Abdul-Aliyy,Abdul-Azim,Abdul-Aziz,Abdul-Badi,Abdul-Baʿith,Abdul-Baqi,Abdul-Bari,Abdul-Barr,Abdul-Basir,Abdul-Basit,Abdul-Fattah,Abdul-Ghaffar,Abdul-Ghafur,Abdul-Ghani,Abdul-Hadi,Abdul-Hafiz,Abdul-Hakam,Abdul-Hakim,Abdul-Halim,Abdul-Hamid,Abdul-Haqq,Abdul-Hasib,Abdul-Hayy,Abdul-Jabbar,Abdul-Jalil,Abdul-Karim,Abdul-Khabir,Abdul-Khaliq,Abdul-Latif,Abdul-Malik,Abdul-Majid,Abdul-Matin,Abdul-Mubdiʾ,Abdul-Mughni,Abdul-Muhaimin,Abdul-Muhsi,Abdul-Muhyi,Abdul-Muʿid,Abdul-Muʿizz,Abdul-Mujib,Abdul-Mumin,Abdul-Muqaddim,Abdul-Muqtadir,Abdul-Musawwir,Abdul-Mutaʿal,Abdul-Nafi,Abdul-Nasser,Abdul-Nasir,Abdul-Nur,Abdul-Qadir,Abdul-Qahhar,Abdul-Qawi,Abdul-Qayyum,Abdul-Quddus,Abdul-Rafi,Abdul-Rahim,Abdul-Rahman,Abdul-Rashid,Abdul-Raʿuf,Abdul-Razzaq,Abdul-Shakur,Abdul-Tawwab,Abdul-Wadud,Abdul-Wahhab,Abdul-Wahid,Abdul-Wajid,Abdul-Wakil,Abdul-Wali,Abdul-Waliy,Abdul-Warith,Abdul-Zahir,Abdullah,ʿAbid,ʿAbidin,Abu Bakr,Aby al-Khayr,Adil,Adham,Adib,ʿAdli,ʿAdnan,ʿAfif,Ahmad,ʿAjib,ʿAkif,Akil,Akram,Alaʾ,Alaʾ al-Din,Alʿ Abbas,Aladdin,al-Bara,al-Hakam,al-Harith,Alhasan,Alhusain,Ali,Alim,Almahdi,al-Safi,Altaf,Altair,al-Tayyib,al-Tijani,al-Tufail,Amid,ʿAmid,Amin,Amir,ʿAmir,Amjad,ʿAmmar,ʿAmro,Anas,Anis,ʿAntarah,Anwar,ʿAqil,Arfan,Arif,ʿArif,Asad,Asʿad,Asadel,Ashraf,Asif,ʿAsim,Aswad,Ataʿ,Ataʿ Allah,Ataʿ al-Rahman,Athil,Athir,ʿAtif,ʿAwad,ʿAwf,Aws,Awwab,Ayham,Ayman,Ayser,Ayyub,Aza,ʿAzab,Azhar,Azim,ʿAziz,ʿAzzam,Badi,Badi al-Zaman,Badr,Badr al-Din,Badri,Bahaʿ,Bahiyy al-Din,Bahij,Bahir,Bakr,Bakri,Baligh,Bandar,Barakah,Barir,Bashshar,Basil,Basim,Bassam,Bayezid,Bayhas,Bilal,Bishr,Boulos,Budail,Burhan,Bushr,Butrus,Dabir,Dani,Darwish,Daʿud,Dhakir,Dhakiy,Dhakwan,Dhul Fiqar,Dirar,Diya,Diya al-Din,Duqaq,Fadi,Fadil,Fadl,Fadl Allah,Fahd,Fahad,Fahmi,Faisal,Faʿiz,Fakhir,Fakhr al-Din,Fakhri,Fakih,Falah,Falih,Faraj,Farhan,Farid,Fariq,Fariq,Faris,Faruq,Fath,Fathi,Fatih,Fatin,Fawwaz,Fawzan,Fawzi,Fayyad,Ferran,Fida,Fikri,Firas,Fuʿad,Fudail,Gamal,Ghayth,Ghali,Ghalib,Ghanim,Ghassan,Ghawth,Ghazwan,Ghiyath,Habbab,Habib,Haddad,Hadi,Hafiz,Hakem,Hakim,Halim,Hamal,Hamas,Hamdan,Hamdi,Hamid,Hamim,Hamzah,Hana,Hanaʾi,Hanbal,Hani,Hanif,Hannad,Haris,Harith,Harun,Hashim,Hassan,Hatim,Haydar,Haytham,Hayyan,Hazim,Hilal,Hilmi,Hisham,Hud,Hudad,Hudhafah,Hudhayfah,Humam,Hussein,Husam,Husam al-Din,Ibrahim,ʿId,Idris,Ihsan,Ihtisham,ʿIkrimah,Ilias,ʿImad,Imad al-Din,Imran,Imtiyaz,Inʿam,Iqbal,ʿIrfan,ʿIsa,ʿIsam,Ishaq,Ismaʿil,Iyad,Iyas,Izz al-Din,Jabbar,Jabr,Jabir,Jad Allah,Jaʿfar,Jal,Jalal,Jalal al-Din,Jalil,Jamal,Jamal al-Din,Jamil,Jarir,Jasim,Jaul,Jaun,Jawad,Jawdah,Jawhar,Jibran,Jibril,Jubair,Jul,Jumah,Junayd,Juwain,Kadar,Kadin,Kadir,Kahil,Kaliq,Kamal,Kamil,Karam,Kardal,Karif,Karim,Kasib,Kasim,Katib,Kazim,Khalaf,Khaldun,Khalid,Khalil,Khalil al-Allah,Khalis,Khatib,Khair al-Din,Khairi,Khoury,Khulus,Khuzaymah,Kutaiba,Labib,Lablab,Latif,Layth,LuʿayLubayd,Luqman,Lut,Lutfi,Maʿd,Madani,Mahbub,Mahdi,Mahfuz,Mahir,Mahjub,Mahmud,Mahrus,Maimun,Majd,Majdy,Majd al-Din,Majid,Makin,Malik,Mamduh,Maʿmun,Maʿin,Mandhur,Mansur,Marghub,Marid,Maʿruf,Marwan,Marzuq,Mashʿal,Mashhur,Masrur,Masʿud,Masun,Maysarah,Mazhar,Mazin,Mehmed,Mihran,Mihyar,Mikaʾil,Miqdad,Misbah,Mishʿal,Miyaz,Muʾadh,Muʾawiyah,Muʾayyad,Mubarak,Mubin,Mudar,Muddaththir,Mufid,Muflih,Muhab,Muhayr,Muhammad,Muhanna,Muhannad,Muhib,Muhibb,Muhsin,Muhtadi,Muhyi al-Din,Muʿin,Muʿizz,Mujab,Mujahid,Mukarram,Mukhlis,Mukhtar,Mulham,Mulhim,Muʿmmar,Muʿmin,Mumtaz,Munahid,Mundhir,Munib,Munif,Munir,Muʿnis,Munjid,Munsif,Muntasir,Murad,Murid,Murshid,Murtada,Musa,Musʿab,Musaʿid,Mushtaq,Muslih,Muslim,Mutafa,Mutaʾ,Muʿtasim,Mutawalli,Muʿtazz,Muthanna,Muti,Muwaffaq,Muyassar,Muzaffar,Mussammil,Nabhan,Nabighah,Nabih,Nabil,Nadhir,Nadim,Nadir,Nafiʾ,Nahid,Naʾil,Naʾim,Naji,Najib,Najid,Najjar,Najm al-Din,Naʿaman,Namir,Nashʿah,Nashʿat,Nashwan,Nasib,Nasih,Nasim,Nasir,Nasir al-Din,Nasr,Nasri,Nasuh,Nawaf,Nawfal,Nayif,Nazih,Nazim,Nazmi,Nibras,Nidal,Nijad,Nimr,Nizar,Nuʿaym,Nuh,Nuhayd,Numair,Nuʿman,Nur al-Din,Nuri,Nusrah,Nusrat,Omar,Orhan,Osman,Qasim,Qays,Qudamah,Qusay,Qatadah,Qutaybah,Qutb,Qutuz,Rabah,Rabi,Radi,Rafi,Rafid,Rafiq,Raghib,Rahman,Raʿid,Raʿif,Rais,Rajaa,Rajab,Raji,Rajih,Rakin,Rami,Ramih,Ramiz,Ramzi,Rani,Rashad,Rashid,Rasil,Rasin,Rasmi,Rasul,Ratib,Raʿuf,Rayhan,Rayyan,Razin,Ridha,Ridwan,Rihab,Riyad,Rizq,Ruhi,Rushd,Rushdi,Ruwayd,Saad,Saʿadah,Sab,Sabih,Sabir,Sabri,Saʿd,Saʿd al-Din,Sadad,Sadid,Sadiq,Saʿdun,Saʿid,Safi,Safiy,Safiy al-Din,Safuh,Safwah,Safwat,Safwan,Sahib,Sahir,Sahl,Saʾib,Saif,Saif al-Din,Sajid,Sajjad,Sakhr,Salah,Salah al-Din,Salamah,Salih,Salim,Salman,Sami,Samih,Samir,Samman,Saqr,Sariyah,Sati,Saud,Sayyid,Shaʿban,Shadi,Shadin,Shafi,Shafiq,Shahid,Shahin,Shahir,Shakib,Shakir,Shams al-Din,Shamal,Shamil,Shamim,Sharaf,Sharif,Shawqi,Shihab,Shihab al-Din,Shihad,Shuʿayb,Shukri,Shumayl,Siddiq,Sinan,Siraj,Siraj al-Din,Sofian,Subhi,Sufyan,Suhayb,Suhayl,Suhaym,Sulaiman,Sumrah,Suraqah,Suʿud,Tahir,Tahsin,Taym Allah,Taj,Taj al-Din,Talal,Talib,Tamim,Tamir,Tamam,Tammam,Taqiy,Tarif,Tariq,Taslim,Tawfiq,Tawhid,Taymullah,Taysir,Tayyib,Thabit,Thamir,Thaqib,Thawab,Thawban,ʿUbaidah,Ubaid,Ubayy,ʿUdayl,ʿUday,ʿUmar,Umarah,Umair,ʾaUrwah,Usaym,Usama,ʿUtbah,Uthal,Uthman,Waddah,Wadi,Wadid,Wafiq,Wahab,Wahhab,Wahid,Waʾil,Wajdi,Wajid,Wajih,Wakil,Walid,Walif,Waliy Allah,Waliy al-Din,Waqar,Waqqas,Ward,Wasif,Wasil,Wasim,Wazir,Yahya,Yaman,Yaʿqub,Yasar,Yasin,Yasir,Yazan,Yazid,Yunus,Yushua,Yusri,Yusuf,Zafar,Zafir,Zahid,Zahir,Zayd,Zaim,Zayn,Zarif,Zakarriya,Zaki,Zakwan,Ziyad,Zubayr,Zuhayr" + name_generator= _ << +main={name_long}|{prefix}{suffix}|{name_mid}{connector}{name_mid} +name_mid={prefix}{suffix}|{name_short} +name_long={prefix}{suffix}|{prefix}{centre}{suffix} +name_short=Din|Sif|Din|Taj|Sud|Ali|Lut|Nuh|Qays|Nimr|Jad|Bushr|Lut|Maʿd|Nur|Fadl +prefix=Ab|Bas|Fat|Gha|Al|Ba|Ja|Ha|Mu|Ra|Raz|Abi|Am|La|ʿAj|Ala|ʿAk|Fa|Du|Im|Ju|Mun|Ma|Ni|Ji|Mu|Lab|Luf|Mih|Mi|Qu|Tal|Ta|Tha|Za|Zi|Yas|Wa|Su|Qa|ʿIkri|Lu|Su|Osa|Rag|Saf|Da|Fay|Nib|Nash +suffix=af|al|lih|bair|sur|bi|lah|at|sim|ma|ih|yl|iq|raj|mam|man|ya|zid|riya|ail|air|ah|en|in|ayd|ud|rah|wah|nan|as|ir|ba|ni|yad|ras|zuq|hid|mal|kib +connector= al-| bin | ibn +centre=ʿ|{centre_syllabe} +centre_syllabe=hi|sa|kar|da|na|ja|tay|ki|hai|saw +>> #enddef #define LIZARD_NAMES male_names= _ "Amprixta,Anexir,Anitraz,Arix,Axiz,Bzz’Kza,Chamil,Cleezi,Clezz,Fazzis,Fizztrax,Flixta,Flizzil,Frikes,Frizzle,Hasz,Heffez,Hertrazzir,Hesz,Hezzir,Hezzis,Hix,Inexis,Irix,Jezzix,Jizz,Kaliez,Kepzs,Kernix,Kersezz,Kertrasz,Kerx,Kerxenix,Kezz,Klexaz,Klezyx,Krarax,Krenarex,Krex,Krinex,Krisess,Laizix,Lazki,Lixeez,Merax,Mexiss,Moxanzz,Naxisz,Nix,Pekzs,Plaxis,Plesix,Presch,Sailik,Salanix,Salik,Sandix,Saprazz,Satras,Skalix,Skandix,Skazix,Skeely,Skeezix,Sklizle,Skrez,Slizilx,Sprizz,Ssexur,Ssizer,Ssorix,Sszasz,Sterizz,Talerez,Tarex,Tarnix,Tezzaz,Tirasch,Tirax,Tirix,Trezz,Venezz,Vriss,Waks,Xaffrasz,Xartrez,Xasz,Xaztex,Xerxix,Xirasz,Xirr,Xirtras,Xirtrez,Xirz,Zandler,Zedrix,Zilrix,Zizzasz,Zslap,Zzalkz,Zzupde" + name_generator= _ << +main={prefix}{suffix}|{prefix}{centre}{suffix} +prefix=Am|An|Ar|Bzz|Cha|Clee|Fa|Fi|Fli|Fri|Ha|He|In|Ir|In|Ka|Ke|Jezz|Ji|Ka|Ke|Lo|Ma|Ox|Po|Sa|Se|Li|Me|Na|Pre|Ska|Sse|Ssi|Sto|Ste|Szi|Sza|Ti|Ve|Vri|Xa|Xe|Xi|Zan|Zil|Zzu +suffix=ta|ir|az|ix|za|trax|il|le|esz|izs|ezz|irr|asch|ez|is|iss|azz +centre=ix|’Kza|tra|na|an|ex|ssa|zzi|’Usz +>> #enddef #define MERMAN_NAMES male_names= _ "Absu,Abzu,Aigaion,Alastyn,Apalala,Apam,Apsu,Aremata,Atlahua,Atlaua,Barinthus,Dhakhan,Dylan,Elcmar,Ember,Enki,Faro,Habaek,Ikatere,Jamm,Jin,Kinilau,Kulullu,Labuna,Laut,Lir,Llyr,Ludd,Makara,Maui,Melicertes,Mimir,Natat,Nechtan,Neptune,Nereus,Nethuns,Njord,Nuada,Nudd,Nudimmud,Nun,Oceanus,Okeanos,Phorcys,Pontus,Popoa,Poseidon,Proteus,Raja,Rau,Rorua,Ryujin,Scylla,Sinilau,Sisiutl,Tagaloa,Tanaoa,Tangaloa,Tangaroa,Thaumas,Tikitiki,Tini,Tinilau,Tinirau,Toniwha,Triton,Vizi,Vodnik,Vourukasa" female_names= _ "Aglaopheme,Amphitrite,Aphrodite,Ariel,Atargatis,Calypso,Delphine,Derceto,Diktynna,Electra,Galatea,Himeropa,Jengu,Leucosia,Ligia,Lori Lamaris,Mama Wata,Marina,Miranda,Miriam,Molpe,Parthenope,Pelagia,Pisinoe,Rân,Sedna,Stella Maris,Thelxiepia,Tirgata,Vatea,Ved-Ava,Veen emo,Vete-ema" + male_name_generator= _ << +main={prefix}{suffix}|{prefix}{centre}{suffix} +prefix=A|Ai|Apa|Bar|Atla|Dha|El|Fa|Ja|La|Ku|Li|Ma|Me|Mi|Na|Ne|Njo|Nua|Nu|Oce|Okre|Phor|Po|Pro|Ra|Ro|Ryu|Scy|Si|Ta|Thau|Ti|Vi|Tri|Vo|Vou +suffix=su|ion|la|ta|ua|mar|re|lau|lu|na|yr|ra|tes|nus|teus|tes|tan|mas|ki|ni|lau|nik|sa|loa|roa +centre=la|ma|ri|sei|te|ka|li|cer|tu|ni|ki|na|ga|si +>> + female_name_generator= _ << +main={prefix}{suffix}|{prefix}{centre}{suffix} +prefix=Agla|Amphi|A|Ca|Del|Der|Di|El|Ga|Je|Leu|Li|Lo|Ma|Wa|Ma|Mi|Mo|Par|Pel|Pi|Se|Ste|Ma|The|Ti|Va|Ve +suffix=me|pe|gia|noe|dna|la|ris|ta|tea|va|mo|pe|riam|riel|na|ra|tea +centre=ophe|phri|tri|phro|di|si|xie|ce|ty|la|me|ro|co|mar|ran|then|la|ga +>> #enddef #define NAGA_NAMES male_names= _ "Abraxas,Aleiss,Amail,Axmail,Blanal,Bleii,Blo,Bress,Briss,Gaxmol,Griam,Griss,Grissileii,Hailoss,Hainoss,Harxos,Huzel,Inaloss,Ineii,Issal,Klezel,Kras,Krezkps,Kzap,Lamaiss,Lameii,Lexpek,Liness,Lobor,Maissol,Malinos,Milbor,Mileii,Nildloss,Oxpeii,Poniaz,Psell,Pson,Pzakp,Reii,Sassal,Saxil,Saxrireii,Sekol,Silas,Skell,Skepz,Slell,Snol,Soill,Sorkol,Srell,Trixoz,Vilail,Vissal,Vlanis,Xabrak,Xamalel,Xinas,Xnamos,Xopkon,Zalsp,Zlek,Zpsek,Zsekp" female_names= _ "Aliasse,Amailis,Axmailia,Blai,Blanalai,Bli,Bliana,Brassas,Brissal,Gaxmail,Griama,Grissa,Grissilai,Haila,Haina,Harxias,Huzi,Inai,Inalai,Issalai,Klez,Kras,Krezkps,Kzap,Lamai,Lamaissa,Lexpek,Liabra,Lilin,Linassa,Maissa,Malina,Mila,Milbra,Nildlasi,Oxpel,Poniazal,Psal,Psen,Pzakp,Riaa,Sall,Sassalia,Saxiala,Saxririaa,Sek,Skal,Skepz,Sla,Snelia,Srak,Sral,Szak,Trixzed,Vilaila,Vissalai,Vlanissa,Xabrak,Xamalia,Xina,Xinasia,Xnamas,Xopkne,Zalsp,Zlek,Zpsek,Zsekp" + male_name_generator= _ << +main={prefix}{suffix} +prefix=Abra|Ale|Ama|Ax|Bla|Ble|Bre|Bri|Gri|Hai|Har|Hu|Ine|Kle|Krez|Lam|Lin|Lob|Mai|Lal|Nild|Pon|Pse|Pza|Sa|Se|Sle|So|Sor|Tri|Vi|Vla|Xa|Xi|Xna|Za|Zle|Zse +suffix=iss|ail|nal|eii|mol|loss|noss|xos|sal|zel|kps|pek|ness|or|sol|peii|iaz|on|sal|ol|kil|oz|ail|al|nis|rak|lel|nas|kon|ekp +>> + female_name_generator= _ << +main={prefix}{suffix} +prefix=Ali|Ama|Ax|Bla|Bli|Bra|Bri|Gax|Gri|Hai|Har|Hu|Ina|Iss|Krez|Kzap|Lam|Lex|Li|Lin|Mai|Mu|Nil|Ox|Pon|Pza|Ri|Sal|Sax|Sek|Snel|Sra|Trix|Vil|Vis|Blan|Xab|Xam|Xi|Xnam|Xop|Zal|Zle|Zse +suffix=asse|mailia|ilis|ana|ama|ssa|ssilai|zi|xias|lai|maissa|bra|lin|lina|na|bra|aa|lia|lai|laila|na|pkne|alsp|ekp +>> #enddef #define OGRE_NAMES male_names= _ "Akoark,Akort,Akzalk,Arkarm,Barkuk,Blokkar,Borkuk,Bukkak,Bulruk,Corkkar,Delkkak,Garkuk,Gnukk,Goruk,Grak,Gurk,Gurm,Kalknix,Karak,Karbuk,Kargnak,Karterak,Kayrak,Kelkrar,Kerta,Kilkrar,Kingrok,Kirk,Klud,Kokkan,Kolk,Komak,Korgnak,Kork,Koruck,Kramak,Krog,Krukrak,Krumuk,Kuknuk,Kurkur,Kurmak,Makron,Markaak,Markuk,Merknik,Nargak,Olk,Orkut,Reknak,Takolak,Trabuk,Trakkon,Urkar,Urkark" + name_generator= _ << +main={prefix}{suffix} +prefix=Ak|Ar|Bar|Blok|Bor|Bul|Cork|Del|Gar|Gnu|Gra|Gru|Gu|Kal|Kar|Kay|Kel|Ker|Kil|King|Kor|Kru|Kur|Mar|Mer|Nal|Trak|Urk +suffix=ark|ort|alk|arm|kuk|kak|ukk|nak|ta|k|rok|rar|kon|gak|nik +>> #enddef #define ORCISH_NAMES male_names= _ "Badush,Bagar,Bagdish,Barag,Barbag,Bart,Bashnak,Bidish,Bidush,Bik,Bilg,Bilo,Binak,Bink,Biol,Birt,Bogar,Bogdish,Bogdush,Bogor,Bok,Bolg,Bong,Borg,Bork,Bort,Boshnak,Budush,Bugdish,Buk,Bunak,Bung,Bunk,Burag,Burg,Burk,Buurk,Eradash,Eradish,Eragdish,Eragdush,Eragor,Eranak,Erang,Erarag,Erarg,Erart,Erigdush,Erik,Erinak,Eriol,Erirag,Erirbag,Erirg,Erirt,Erishnak,Eriurk,Erogdish,Erogdush,Erok,Erong,Eronk,Erorbag,Erudish,Erudush,Erugar,Erugdush,Erulo,Erunk,Eruol,Erurag,Eruurk,Gadash,Gagar,Gagdush,Gagor,Galo,Ganak,Gank,Gaol,Garag,Gashnak,Gigor,Ginak,Ging,Gink,Girt,Gogdish,Gogdush,Gong,Gork,Gort,Goshnak,Gradash,Gragar,Gragor,Grak,Gralg,Gralo,Granak,Graol,Grarbag,Gridash,Gridish,Gridush,Grigar,Grigor,Grilg,Grilo,Grink,Grirag,Grirg,Grirk,Grishnak,Grodish,Grogar,Grogdish,Grok,Grolg,Grong,Gronk,Grorag,Grorg,Grork,Grort,Groshnak,Grudash,Grugar,Grugdish,Grugdush,Gruk,Grulo,Grunk,Gruol,Grurg,Grurk,Grurt,Gruurk,Gugdish,Gugdush,Gulg,Gulo,Gunak,Gurbag,Gurt,Gushnak,Hadash,Hadish,Hadush,Hagar,Hagdush,Hagor,Hak,Halg,Hank,Hashnak,Hidash,Hidish,Hidush,Higdush,Hilg,Hinak,Hing,Hink,Hiol,Hirag,Hirg,Hodush,Hogar,Hogor,Hong,Hool,Horbag,Hork,Hort,Hoshnak,Hudash,Hudish,Hugor,Huk,Hulg,Hulo,Hunk,Huol,Hurag,Hurbag,Hurk,Hushnak,Huurk,Pagdish,Pagor,Palg,Palo,Paol,Parag,Pashnak,Pidush,Pigdish,Pigdush,Pilg,Pinak,Pink,Pirbag,Podash,Podish,Podush,Pogdish,Polg,Porbag,Porg,Pork,Port,Poshnak,Pradish,Pragdush,Pragor,Pralg,Pralo,Prang,Praol,Prarag,Prarbag,Prarg,Prark,Prart,Prashnak,Praurk,Pridish,Prigar,Prigdish,Prigor,Prilg,Prilo,Prinak,Priol,Prirbag,Prirg,Prirt,Priurk,Prodash,Prodish,Prodush,Prolg,Prolo,Pronak,Prong,Pronk,Prool,Prourk,Prudish,Prugar,Prugdish,Pruk,Prunak,Prunk,Prurg,Prurk,Pruurk,Puk,Pulg,Pulo,Punak,Pung,Punk,Purag,Purbag,Purg,Puurk,Radash,Ragar,Ragdish,Rak,Rang,Rank,Raol,Rarag,Rarbag,Rark,Rashnak,Raurk,Rigor,Rik,Rilg,Rinak,Rink,Rirg,Rirk,Rodish,Rodush,Rogdish,Rok,Rolo,Ronak,Rudash,Rugar,Rugdish,Ruk,Rung,Ruol,Rurag,Rushnak,Vadash,Vadish,Vadush,Vak,Valo,Vank,Varag,Varbag,Vigar,Vigdish,Vigor,Vilg,Vilo,Vink,Virag,Virt,Vishnak,Vogdish,Vogor,Vonak,Vong,Vorg,Vork,Voshnak,Vourk,Vradash,Vragar,Vragdush,Vragor,Vralo,Vrang,Vrarbag,Vrarg,Vrart,Vraurk,Vridash,Vridish,Vrigor,Vrik,Vrinak,Vring,Vrirt,Vrishnak,Vriurk,Vrodash,Vrodish,Vrogar,Vrogor,Vrolo,Vrong,Vrorg,Vrork,Vrudish,Vrugdush,Vrulg,Vrung,Vruol,Vrurg,Vrurt,Vruurk,Vudish,Vuk,Vulg,Vulo,Vunak,Vurag,Vurbag,Vurg,Vushnak" + name_generator= _ << +main={starting_consonnant}{vowel}{consonnant}{vowel}{ending_consonnant}|{starting_consonnant}{vowel}{consonnant}{ending_vowel}|{starting_vowel}{consonnant}{vowel}{ending_consonnant}|{starting_consonnant}{vowel}{ending_consonnant}|{starting_vowel}{consonnant}{ending_vowel} +starting_consonnant=B|Br|D|Dr|G|Gr|Gh|H|Kh|M|N|P|Pr|R|S|Sh|T|V +starting_vowel=A|I|O|U +consonnant=b|br|d|dr|g|gr|gh|kh|m|n|p|pr|r|s|sh|t|v|gz|zg|rb|br|dr|vr|khr|gd|shn +vowel=a|i|o|u +ending_consonnant=b|g|r|sh|k +ending_vowel=o|u +>> #enddef #define TROLL_NAMES male_names= _ "Äg,Agh,Bog Äh,Borb,Brag,Brag Goh,Brok,Dak,Drog,Frok,Ga,Gah,Gark,Gnarf,Grar,Grokk,Grumph,Gulk,Hak,Hask,Hoth,Hug Bah,Hu Kah,Kak,Krak,Krug,Kub,Kuh,Lok,Luk,Nak,Nuk Kar,Pag,Reck,Rok,Ruk,Sark,Shak,Shuf,Stuh,Targ,Thog,Thruf,Thur,Tohg,Torg,Trok,Tsok,Tuh,Tuk Ruh,Ugg,Üh,Urg,Urgh,Urk,Vak,Zog,Zuug" + name_generator= _ << +main={short_name}|{short_name}|{short_name}|{short_name} {short_name} +short_name={prefix}{middle}{suffix}|{prefix}{middle}{suffix}|{prefix}{middle}{suffix}|{beginning}{suffix} +prefix=B|Br|D|G|Gn|H|K|Kr|L|N|K|P|R|S|Sh|St|Th|Ts|T|V|Z +middle=a|o|u|uu|ä|ü +beginning=Ä|Ü|A|U +suffix=rb|g|gh|k|rf|kk|r|g|th|h|rg +>> #enddef #define WOSE_NAMES male_names= _ "Bludebalmen,Boladrumbadrum,Bolwuldelman,Bombempomgontor,Bomtanbomkenton,Bomtanbomtonum,Bregalad,Bremdebubde,Brenbasnudnem,Brendumadoak,Brommantendronnor,Brumbendublun,Brumennarunom,Brummdlebroak,Bumbadadabum,Buomdumdenlol,Carnimirië,Dabumdabumtam,Dammantongonnur,Danmonlulbam,Debundbemun,Delmduelmdelom,Diblembumnde,Dolmannumbil,Drongnoblemdu,Dulmandarook,Dulwulmendom,Dumdumdumatum,Elmaroomadrum,Grelmadrumbumadum,Gulladroamadoak,Gumabeladrelm,Laffalialomdium,Landunwonbam,Lassemista,Lefnublemdde,Libleddnumm,Lolmandindel,Monlamwimdan,Muldondindal,Mundionalafla,Mundumblemdum,Munnamdulbon,Nanmildaldum,Nunmaldildun,Orofarnië,Pambedrumne,Pomtamkomtrobum,Rithramcamhan,Tantondernintan,Temtundembenn,Temtunnongetem,Tondenkontenkon,Troombadoom,Tumtentantarun,Tumtonnongatum,Tumtumgamtomtom,Wonrunmaldin,Wudadoonopl" + name_generator= _ << +main={prefix}{centre}{centre}{suffix}|{prefix}{centre}{centre}{centre}{suffix} +prefix=Blu|Bo|Bre|Bro|Bru|Bu|Car|Da|Da|De|Dib|Dol|Dro|Dul|Dum|El|Gre|Gul|Gum|Laf|Lan|Las|Lef|Lib|Lol|Mon|Mul|Mun|Nan|Nun|Or|Pam|Pom|Rith|Tan|Tem|Ton|Troom|Tun|Tum|Won|Wun +centre=de|bal|drum|wul|del|bem|pom|gon|tan|bom|ken|tan|ton|man|ten|dron|dub|na|da|ni|mi|lul|mon|duel|lem|num|nob|mand|room|lad|roam|be|lom|sem|nub|di|wim|din|blem|nand|dul|dil|of|tam|kon|ton|tun|kon|ten|run|mal|do +suffix=men|drum|tor|num|lad|de|ak|lol|dum|tam|nur|dium|deum|bil|rook|relm|dium|numm|dan|doom|tum|din +>> #enddef #define VILLAGE_NAMES male_names= _ "Bal,Cam,Corn,Del,Earl,El,Fox,Fren,Gel,Hel,Hex,Hol,Hox,Il,Kin,Nam,Nes,New,Ol,Old,Olf,Oul,Ox,Rock,Rook,Sal,Sam,Sed,Sel,Sen,Sil,Tal,Water,Wet,York" + name_generator= _ << +main={prefix}{middle}{suffix} +prefix=B|C|D|E|F|Fr|Wat|G|H|K|N|O|R|S|T|W|Y|Ro +middle=a|e|o|u|i +suffix=l|m|rn|x|w|ld|ck|k|rk +>> #enddef diff --git a/data/gui/macros/_initial.cfg b/data/gui/macros/_initial.cfg index 5f93746827f4..db950ac1aa78 100644 --- a/data/gui/macros/_initial.cfg +++ b/data/gui/macros/_initial.cfg @@ -29,7 +29,7 @@ # If the text is too high it returns the top side. # Rounding happens to the bottom side. #define GUI__TEXT_VERTICALLY_CENTRED - "(if(text_height < height, (height - text_height - 2) / 2, 0))" + "(if(text_height < height, (height - text_height) / 2, 0))" #enddef #define GUI__CENTERED_TEXT FONT_SIZE FONT_STYLE FONT_COLOR @@ -279,6 +279,37 @@ [/row] #enddef +#define GUI_VERTICAL_SPACER_LINE + [column] + border = "all" + border_size = 10 + vertical_grow = true + + [drawing] + definition = "default" + + width = 1 + height = (height) + + [draw] + + [line] + x1 = 0 + y1 = 1 + x2 = 0 + y2 = (height - 1) + + color = {GUI__FONT_COLOR_DISABLED__DEFAULT} + thickness = 1 + [/line] + + [/draw] + + [/drawing] + + [/column] +#enddef + ############################################################################### ### ### ### Macros for the normal gui. ### @@ -307,5 +338,5 @@ #enddef #define GUI_NORMAL__FONT_SIZE__TITLE - 24 + 22 #enddef diff --git a/data/gui/macros/horizontal_scrollbar.cfg b/data/gui/macros/horizontal_scrollbar.cfg index 4f0d2d70ae77..08019cb2d01d 100644 --- a/data/gui/macros/horizontal_scrollbar.cfg +++ b/data/gui/macros/horizontal_scrollbar.cfg @@ -13,7 +13,7 @@ horizontal_grow = "true" # note we want a special button definition for this later. [repeating_button] id = "_half_page_up" - definition = "left_arrow" + definition = "scrollbar_left_arrow" [/repeating_button] [/column] @@ -34,7 +34,7 @@ horizontal_grow = "true" # note we want a special button definition for this later. [repeating_button] id = "_half_page_down" - definition = "right_arrow" + definition = "scrollbar_right_arrow" [/repeating_button] [/column] diff --git a/data/gui/widget/button_default.cfg b/data/gui/widget/button_default.cfg index a6b5b559da92..7d8e7f412aa4 100644 --- a/data/gui/widget/button_default.cfg +++ b/data/gui/widget/button_default.cfg @@ -148,8 +148,9 @@ [draw] {_GUI_STATE "background" - ({_GUI_BORDER_COLOR_ALPHA {ALPHA}}) - ({_GUI_BORDER_COLOR_DARK_ALPHA {ALPHA}}) ("1, 10, 16, 255") "~GS(){IPF}"} + ("128, 128, 128, {ALPHA}") # Same as GUI__FONT_COLOR_DISABLED__DEFAULT, but with an alpha componant + ("89, 89, 89, {ALPHA}") + ("1, 10, 16, 255") "~GS(){IPF}"} {GUI__CENTERED_TEXT ({FONT_SIZE}) () ({GUI__FONT_COLOR_DISABLED__TITLE})} diff --git a/data/gui/widget/horizontal_scrollbar_default.cfg b/data/gui/widget/horizontal_scrollbar_default.cfg index 4a9c720daf80..594123b47cda 100644 --- a/data/gui/widget/horizontal_scrollbar_default.cfg +++ b/data/gui/widget/horizontal_scrollbar_default.cfg @@ -3,43 +3,27 @@ ### Definition of a horizontal scrollbar. ### -#define _GUI_STATE GROOVE_LEFT GROOVE_RIGHT POSITIONER_LEFT POSITIONER_RIGHT IMAGE_SUFFIX IPF +#define _GUI_STATE POSITIONER_LEFT IMAGE_SUFFIX IPF [draw] # # Groove # - [image] - # 4 pixels wide + [rectangle] x = 0 y = 0 - name = "buttons/scrollbars/scrollgroove-left.png{IPF}" - [/image] - - [image] - x = {GROOVE_LEFT} - y = 0 - w = "(if(width - {GROOVE_LEFT} - {GROOVE_RIGHT} < 0 - , 0, width - {GROOVE_LEFT} - {GROOVE_RIGHT}))" - h = 0 - resize_mode = "stretch" - name = "buttons/scrollbars/scrollgroove-horizontal.png{IPF}" - [/image] - - [image] - # 5 pixels wide - x = "(width - {GROOVE_RIGHT})" - y = 0 - name = "buttons/scrollbars/scrollgroove-right.png{IPF}" - [/image] + w = "(width)" + h = "(height)" + fill_color = "4, 4, 4, 255" + [/rectangle] # # Positioner # [image] - # 5 pixels wide + # 5 pixels high x = "(positioner_offset)" y = 0 name = "buttons/scrollbars/scrollleft{IMAGE_SUFFIX}{IPF}" @@ -49,15 +33,15 @@ x = "(positioner_offset + {POSITIONER_LEFT})" y = 0 w = "( -if(positioner_length - {POSITIONER_LEFT} - {POSITIONER_RIGHT} < 0 - , 0, positioner_length - {POSITIONER_LEFT} - {POSITIONER_RIGHT}))" +if(positioner_length - {POSITIONER_LEFT} < 0 + , 0, positioner_length - {POSITIONER_LEFT}))" resize_mode = "stretch" name = "buttons/scrollbars/scrollhorizontal{IMAGE_SUFFIX}{IPF}" [/image] [image] - # 5 pixels wide - x = "(positioner_offset + positioner_length - {POSITIONER_RIGHT})" + # 5 pixels high + x = "(positioner_offset + positioner_length)" y = 0 name = "buttons/scrollbars/scrollright{IMAGE_SUFFIX}{IPF}" [/image] @@ -65,7 +49,7 @@ if(positioner_length - {POSITIONER_LEFT} - {POSITIONER_RIGHT} < 0 [/draw] #enddef -#define _GUI_RESOLUTION RESOLUTION WIDTH HEIGHT POSITIONER_LENGHT GROOVE_LEFT GROOVE_RIGHT POSITIONER_LEFT POSITIONER_RIGHT IPF +#define _GUI_RESOLUTION RESOLUTION WIDTH HEIGHT POSITIONER_LENGHT POSITIONER_LEFT IPF [resolution] {RESOLUTION} @@ -74,7 +58,7 @@ if(positioner_length - {POSITIONER_LEFT} - {POSITIONER_RIGHT} < 0 min_height = {HEIGHT} default_width = {WIDTH} - default_height = {HEIGHT} + default_height = 15 max_width = 0 max_height = {HEIGHT} @@ -85,19 +69,19 @@ if(positioner_length - {POSITIONER_LEFT} - {POSITIONER_RIGHT} < 0 right_offset = 0 [state_enabled] - {_GUI_STATE ({GROOVE_LEFT}) ({GROOVE_RIGHT}) ({POSITIONER_LEFT}) ({POSITIONER_RIGHT}) ".png" ({IPF}) } + {_GUI_STATE ({POSITIONER_LEFT}) ".png" ({IPF}) } [/state_enabled] [state_disabled] - {_GUI_STATE ({GROOVE_LEFT}) ({GROOVE_RIGHT}) ({POSITIONER_LEFT}) ({POSITIONER_RIGHT}) ".png~GS()" ({IPF}) } + {_GUI_STATE ({POSITIONER_LEFT}) ".png~GS()" ({IPF}) } [/state_disabled] [state_pressed] - {_GUI_STATE ({GROOVE_LEFT}) ({GROOVE_RIGHT}) ({POSITIONER_LEFT}) ({POSITIONER_RIGHT}) "-pressed.png" ({IPF}) } + {_GUI_STATE ({POSITIONER_LEFT}) "-pressed.png" ({IPF}) } [/state_pressed] [state_focused] - {_GUI_STATE ({GROOVE_LEFT}) ({GROOVE_RIGHT}) ({POSITIONER_LEFT}) ({POSITIONER_RIGHT}) "-active.png" ({IPF}) } + {_GUI_STATE ({POSITIONER_LEFT}) "-active.png" ({IPF}) } [/state_focused] [/resolution] #enddef @@ -109,7 +93,7 @@ if(positioner_length - {POSITIONER_LEFT} - {POSITIONER_RIGHT} < 0 # Note a scrollbar is normally sized by the item that "masters" it # that's why the default height is rather low. - {_GUI_RESOLUTION () 20 25 11 4 5 5 5 ()} + {_GUI_RESOLUTION () 20 25 11 2 ()} [/horizontal_scrollbar_definition] @@ -120,7 +104,7 @@ if(positioner_length - {POSITIONER_LEFT} - {POSITIONER_RIGHT} < 0 # Note a scrollbar is normally sized by the item that "masters" it # that's why the default height is rather low. - {_GUI_RESOLUTION () 20 25 11 4 5 5 5 "~O(65%)"} + {_GUI_RESOLUTION () 20 25 11 5 "~O(65%)"} [/horizontal_scrollbar_definition] diff --git a/data/gui/widget/unit_preview_pane.cfg b/data/gui/widget/unit_preview_pane.cfg index 2dc6bbe7cc45..1d638319c4f9 100644 --- a/data/gui/widget/unit_preview_pane.cfg +++ b/data/gui/widget/unit_preview_pane.cfg @@ -132,6 +132,24 @@ #define _GUI_UNIT_PREVIEW_PANE_MINIMAL [grid] + [row] + grow_factor = 0 + + [column] + border = "bottom" + border_size = 5 + horizontal_alignment = "center" + vertical_alignment = "center" + + [image] + id = "type_image" + definition = "default" + [/image] + + [/column] + + [/row] + [row] grow_factor = 0 @@ -153,51 +171,64 @@ [row] grow_factor = 0 - [column] + border = "bottom" + border_size = 5 + vertical_grow = "true" horizontal_grow = "true" - [grid] + [label] + id = "type_name" + wrap = "true" + [/label] - [row] - grow_factor = 1 + [/column] - [column] - border = "right,bottom" - border_size = 5 - horizontal_alignment = "left" + [/row] + + [row] + grow_factor = 0 - [label] - id = "type_level" - [/label] + [column] + border = "right,bottom" + border_size = 5 + horizontal_alignment = "left" - [/column] + [label] + id = "type_level" + [/label] - [column] - border = "right,bottom" - border_size = 5 - horizontal_alignment = "left" + [/column] - [image] - id = "type_race" - [/image] + [/row] - [/column] + [row] + grow_factor = 0 - [column] - border = "bottom" - border_size = 5 - horizontal_alignment = "left" + [column] + border = "right,bottom" + border_size = 5 + horizontal_alignment = "left" - [image] - id = "type_alignment" - [/image] + [label] + id = "type_race" + [/label] - [/column] + [/column] - [/row] + [/row] - [/grid] + [row] + grow_factor = 0 + + [column] + border = "right,bottom" + border_size = 5 + horizontal_alignment = "left" + + [label] + id = "type_alignment" + [/label] [/column] diff --git a/data/gui/window/campaign_dialog.cfg b/data/gui/window/campaign_dialog.cfg index e9f706e77be3..96e8a3667236 100644 --- a/data/gui/window/campaign_dialog.cfg +++ b/data/gui/window/campaign_dialog.cfg @@ -26,12 +26,6 @@ fixed_width = "true" [/linked_group] - [linked_group] - id = "tree_name" - fixed_width = "true" - fixed_height = "true" - [/linked_group] - [tooltip] id = "tooltip" [/tooltip] @@ -373,7 +367,7 @@ [label] id = "name" definition = "default" - linked_group = "tree_name" + linked_group = "name" [/label] [/column] diff --git a/data/gui/window/custom_tod.cfg b/data/gui/window/custom_tod.cfg index 74ec70884130..9951809a6b55 100644 --- a/data/gui/window/custom_tod.cfg +++ b/data/gui/window/custom_tod.cfg @@ -4,398 +4,406 @@ ### [window] - id = "custom_tod" - description = "Custom ToD schedules dialog." - - [resolution] - definition = "default" - - automatic_placement = "true" - vertical_placement = "center" - horizontal_placement = "center" - - [tooltip] - id = "tooltip" - [/tooltip] - - [helptip] - id = "tooltip" - [/helptip] - - [linked_group] - id = "labels" - fixed_width = "true" - [/linked_group] - - [linked_group] - id = "tod_index" - fixed_width = "true" - [/linked_group] - - [grid] - [row] - grow_factor = 0 - [column] - grow_factor = 1 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - definition = "title" - label = _ "Custom Time Schedule" - [/label] - [/column] - [/row] - [row] - grow_factor = 0 - [column] - horizontal_alignment = "left" - [grid] - [row] - grow_factor = 0 - [column] - horizontal_grow = "true" - [grid] - [row] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - definition = "default" - linked_group = "labels" - label = _ "Name:" - [/label] - [/column] - [column] - grow_factor = 1 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [text_box] - id = "tod_name" - definition = "default" - [/text_box] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "right" - [image] - id = "current_tod_image" - definition = "default" - [/image] - [/column] - [/row] - [row] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - definition = "default" - linked_group = "labels" - label = _ "ID:" - [/label] - [/column] - [column] - grow_factor = 1 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [text_box] - id = "tod_id" - definition = "default" - [/text_box] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "right" - [image] - id = "current_tod_mask" - definition = "default" - [/image] - [/column] - [/row] - [row] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - definition = "default" - linked_group = "labels" - label = _ "Metadata:" - [/label] - [/column] - [column] - horizontal_alignment = "left" - [grid] - [row] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [button] - id = "image_button" - definition = "default" - label = _ "Image" - [/button] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [button] - id = "mask_button" - definition = "default" - label = _ "Mask" - [/button] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [button] - id = "sound_button" - definition = "default" - label = _ "Sound" - [/button] - [/column] - [/row] - [/grid] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "right" - [label] - id = "current_sound" - definition = "default" - [/label] - [/column] - [/row] - [/grid] - [/column] - [/row] - [row] - [column] - [grid] - [row] - grow_factor = 0 - [column] - grow_factor = 1 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - definition = "default" - linked_group = "labels" - label = _ "Lawful Bonus:" - [/label] - [/column] - [column] - grow_factor = 1 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [slider] - id = "lawful_bonus" - definition = "default" - best_slider_length = 512 - minimum_value = -100 - maximum_value = 100 - step_size = 5 - [/slider] - [/column] - [/row] - [row] - [column] - grow_factor = 0 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - definition = "default" - linked_group = "labels" - label = _ "Red:" - [/label] - [/column] - [column] - grow_factor = 1 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [slider] - id = "tod_red" - definition = "default" - best_slider_length = 512 - minimum_value = -255 - maximum_value = 255 - step_size = 1 - [/slider] - [/column] - [/row] - [row] - [column] - grow_factor = 0 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - definition = "default" - linked_group = "labels" - label = _ "Green:" - [/label] - [/column] - [column] - grow_factor = 1 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [slider] - id = "tod_green" - definition = "default" - best_slider_length = 512 - minimum_value = -255 - maximum_value = 255 - step_size = 1 - [/slider] - [/column] - [/row] - [row] - [column] - grow_factor = 0 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - definition = "default" - linked_group = "labels" - label = _ "Blue:" - [/label] - [/column] - [column] - grow_factor = 1 - border = "all" - border_size = 5 - horizontal_alignment = "left" - [slider] - id = "tod_blue" - definition = "default" - best_slider_length = 512 - minimum_value = -255 - maximum_value = 255 - step_size = 1 - [/slider] - [/column] - [/row] - [/grid] - [/column] - [/row] - [/grid] - [/column] - [/row] - [row] - grow_factor = 1 - [column] - horizontal_grow = "true" - [grid] - [row] - grow_factor = 1 - [column] - horizontal_alignment = "left" - [grid] - [row] - grow_factor = 1 - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [button] - id = "previous_tod" - definition = "left_arrow" - linked_group = "tod_index" - label = _ "Previous" - [/button] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [label] - id = "tod_number" - definition = "default" - linked_group = "tod_index" - [/label] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "left" - [button] - id = "next_tod" - definition = "right_arrow" - linked_group = "tod_index" - label = _ "Next" - [/button] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "right" - [button] - id = "new" - definition = "add" - label = _ "New ToD" - [/button] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "right" - [button] - id = "delete" - definition = "delete" - label = _ "Delete ToD" - [/button] - [/column] - [/row] - [/grid] - [/column] - [column] - horizontal_alignment = "right" - [grid] - [row] - grow_factor = 1 - [column] - border = "all" - border_size = 5 - horizontal_alignment = "right" - [button] - id = "save" - definition = "default" - label = _ "OK" - [/button] - [/column] - [column] - border = "all" - border_size = 5 - horizontal_alignment = "right" - [button] - id = "cancel" - definition = "default" - label = _ "Cancel" - [/button] - [/column] - [/row] - [/grid] - [/column] - [/row] - [/grid] - [/column] - [/row] - [/grid] - [/resolution] + id = "custom_tod" + description = "Custom ToD schedules dialog." + + [resolution] + definition = "default" + + automatic_placement = "true" + vertical_placement = "center" + horizontal_placement = "center" + + [tooltip] + id = "tooltip" + [/tooltip] + + [helptip] + id = "tooltip" + [/helptip] + + [linked_group] + id = "labels" + fixed_width = "true" + [/linked_group] + + [linked_group] + id = "tod_index" + fixed_width = "true" + [/linked_group] + + [grid] + [row] + grow_factor = 0 + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "title" + label = _ "Custom Time Schedule" + [/label] + [/column] + [/row] + + [row] + grow_factor = 0 + [column] + horizontal_grow = "true" + [grid] + [row] + [column] + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "default" + linked_group = "labels" + label = _ "Name:" + [/label] + [/column] + + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [text_box] + id = "tod_name" + definition = "default" + [/text_box] + [/column] + + [column] + border = "all" + border_size = 5 + horizontal_alignment = "right" + [image] + id = "current_tod_image" + definition = "default" + [/image] + [/column] + [/row] + + [row] + [column] + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "default" + linked_group = "labels" + label = _ "ID:" + [/label] + [/column] + + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [text_box] + id = "tod_id" + definition = "default" + [/text_box] + [/column] + + [column] + border = "all" + border_size = 5 + horizontal_alignment = "right" + [image] + id = "current_tod_mask" + definition = "default" + [/image] + [/column] + [/row] + + [row] + [column] + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "default" + linked_group = "labels" + label = _ "Metadata:" + [/label] + [/column] + + [column] + horizontal_alignment = "left" + [grid] + [row] + [column] + border = "all" + border_size = 5 + horizontal_alignment = "left" + [button] + id = "image_button" + definition = "default" + label = _ "Image" + [/button] + [/column] + + [column] + border = "all" + border_size = 5 + horizontal_alignment = "left" + [button] + id = "mask_button" + definition = "default" + label = _ "Mask" + [/button] + [/column] + + [column] + border = "all" + border_size = 5 + horizontal_alignment = "left" + [button] + id = "sound_button" + definition = "default" + label = _ "Sound" + [/button] + [/column] + [/row] + [/grid] + [/column] + + [column] + border = "all" + border_size = 5 + horizontal_alignment = "right" + [label] + id = "current_sound" + definition = "default" + [/label] + [/column] + [/row] + [/grid] + [/column] + [/row] + [row] + [column] + [grid] + [row] + grow_factor = 0 + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "default" + linked_group = "labels" + label = _ "Lawful Bonus:" + [/label] + [/column] + + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [slider] + id = "lawful_bonus" + definition = "default" + best_slider_length = 512 + minimum_value = -100 + maximum_value = 100 + step_size = 5 + [/slider] + [/column] + [/row] + + [row] + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "default" + linked_group = "labels" + label = _ "Red:" + [/label] + [/column] + + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [slider] + id = "tod_red" + definition = "default" + best_slider_length = 512 + minimum_value = -255 + maximum_value = 255 + step_size = 1 + [/slider] + [/column] + [/row] + + [row] + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "default" + linked_group = "labels" + label = _ "Green:" + [/label] + [/column] + + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [slider] + id = "tod_green" + definition = "default" + best_slider_length = 512 + minimum_value = -255 + maximum_value = 255 + step_size = 1 + [/slider] + [/column] + [/row] + + [row] + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "default" + linked_group = "labels" + label = _ "Blue:" + [/label] + [/column] + + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [slider] + id = "tod_blue" + definition = "default" + best_slider_length = 512 + minimum_value = -255 + maximum_value = 255 + step_size = 1 + [/slider] + [/column] + [/row] + [/grid] + [/column] + [/row] + + [row] + grow_factor = 1 + [column] + horizontal_grow = "true" + [grid] + [row] + grow_factor = 1 + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [button] + id = "previous_tod" + definition = "left_arrow" + linked_group = "tod_index" + label = _ "Previous" + [/button] + [/column] + + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + id = "tod_number" + definition = "default" + linked_group = "tod_index" + [/label] + [/column] + + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [button] + id = "next_tod" + definition = "right_arrow" + linked_group = "tod_index" + label = _ "Next" + [/button] + [/column] + + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [button] + id = "new" + definition = "add" + label = _ "New ToD" + [/button] + [/column] + + [column] + grow_factor = 1 + border = "all" + border_size = 5 + horizontal_alignment = "left" + [button] + id = "delete" + definition = "delete" + label = _ "Delete ToD" + [/button] + [/column] + + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "right" + [button] + id = "ok" + definition = "default" + label = _ "OK" + [/button] + [/column] + + [column] + grow_factor = 0 + border = "all" + border_size = 5 + horizontal_alignment = "right" + [button] + id = "cancel" + definition = "default" + label = _ "Cancel" + [/button] + [/column] + [/row] + [/grid] + [/column] + [/row] + [/grid] + [/resolution] [/window] diff --git a/data/gui/window/loadscreen.cfg b/data/gui/window/loadscreen.cfg index 0da663c1151b..bfc28156f090 100644 --- a/data/gui/window/loadscreen.cfg +++ b/data/gui/window/loadscreen.cfg @@ -45,7 +45,7 @@ [column] [spacer] - height = "((screen_height - if(screen_height < 800, 400, 0)) / 4)" + height = "((screen_height - if(screen_height < 800, 200, 0)) / 3.5)" [/spacer] [/column] @@ -75,7 +75,7 @@ {_GUI_PADDING} [row] - grow_factor = 1 + grow_factor = 2 [column] grow_factor = 1 @@ -100,22 +100,20 @@ grow_factor = 1 border = "all" border_size = 5 - horizontal_grow = "true" + horizontal_alignment = "center" vertical_alignment = "center" - [label] - text_alignment = "center" - definition = "default_large" - id = "status" - label = _ "Loading..." - [/label] + [image] + definition = "decoration" + label = "misc/loadscreen_decor.png" + [/image] [/column] [/row] [row] - grow_factor = 0 + grow_factor = 1 [column] grow_factor = 1 @@ -142,13 +140,15 @@ grow_factor = 1 border = "all" border_size = 5 - horizontal_alignment = "center" + horizontal_grow = "true" vertical_alignment = "center" - [image] - definition = "decoration" - label = "misc/loadscreen_decor.png" - [/image] + [label] + text_alignment = "center" + definition = "default_large" + id = "status" + label = _ "Loading..." + [/label] [/column] diff --git a/data/gui/window/lobby_main.cfg b/data/gui/window/lobby_main.cfg index 77b6e6e3359c..a392e13ee102 100644 --- a/data/gui/window/lobby_main.cfg +++ b/data/gui/window/lobby_main.cfg @@ -104,7 +104,7 @@ #define GAMELISTBOX border = "all" border_size = 5 - + [listbox] id = "game_list" definition = "default" @@ -679,7 +679,7 @@ border_size = 5 border_size = 5 [button] id = "quit" - definition = "default" + definition = "large" label = _ "Log Out" [/button] {VERTICAL_SEP} @@ -687,7 +687,7 @@ border_size = 5 border_size = 5 [button] id = "show_preferences" - definition = "default" + definition = "large" label = _ "Preferences" [/button] {VERTICAL_SEP} @@ -695,7 +695,7 @@ border_size = 5 border_size = 5 [button] id = "refresh" - definition = "default" + definition = "large" label = _ "Refresh" [/button] {VERTICAL_SEP} @@ -703,7 +703,7 @@ border_size = 5 border_size = 10 [button] id = "create" - definition = "default" + definition = "large" label = _ "Create Game" [/button] {VERTICAL_SEP} @@ -711,7 +711,7 @@ border_size = 5 border_size = 5 [button] id = "join_global" - definition = "default" + definition = "large" label = _ "Join" [/button] {VERTICAL_SEP} @@ -719,7 +719,7 @@ border_size = 5 border_size = 5 [button] id = "observe_global" - definition = "default" + definition = "large" label = _ "Observe" [/button] {VERTICAL_SEP} @@ -727,7 +727,7 @@ border_size = 5 border_size = 5 [toggle_button] id = "skip_replay" - definition = "default" + definition = "large" label = _ "Quick replay" [/toggle_button] # wmlxgettext: [column] @@ -794,8 +794,10 @@ border_size = 5 [column] horizontal_grow = "true" vertical_grow = "true" + border = "all" + border_size = 5 {GUI_FORCE_OUTLINED_WIDGET_MINIMUM_SIZE - 0 "((screen_height * 30) / 100)" + 0 "((screen_height * if(screen_height < 800, 30, 50)) / 100)" 5 1 {GUI__BORDER_COLOR_BRIGHT} ( {GAMELISTBOX} )} diff --git a/data/gui/window/preferences/03_display.cfg b/data/gui/window/preferences/03_display.cfg index efe34cfac20d..d838993ccd67 100644 --- a/data/gui/window/preferences/03_display.cfg +++ b/data/gui/window/preferences/03_display.cfg @@ -253,7 +253,7 @@ [slider] id = "scaling_slider" definition = "minimal" - minimum_value,maximum_value=100,200 + minimum_value,maximum_value=80,200 step_size=5 tooltip= _ "Set the scaling factor of fonts" [/slider] diff --git a/data/gui/window/unit_attack.cfg b/data/gui/window/unit_attack.cfg index 6186bd6c3397..b040c7b2eb10 100644 --- a/data/gui/window/unit_attack.cfg +++ b/data/gui/window/unit_attack.cfg @@ -162,34 +162,7 @@ {_GUI_BIG_ATTACKER_PANEL} [/column] - [column] - border = "all" - border_size = 10 - vertical_grow = true - - [drawing] - definition = "default" - - width = 1 - height = (height) - - [draw] - - [line] - x1 = 0 - y1 = 1 - x2 = 0 - y2 = (height - 1) - - color = {GUI__FONT_COLOR_DISABLED__DEFAULT} - thickness = 1 - [/line] - - [/draw] - - [/drawing] - - [/column] + {GUI_VERTICAL_SPACER_LINE} [column] grow_factor = 1 diff --git a/data/hardwired/fonts.cfg b/data/hardwired/fonts.cfg index b6d850283709..435850e8b8b4 100644 --- a/data/hardwired/fonts.cfg +++ b/data/hardwired/fonts.cfg @@ -5,12 +5,19 @@ # provide different font orders: one just has to install the # missing fonts without needing to change the gmo files order=_ "DejaVuSans.ttf,Andagii.ttf,DroidSansJapanese.ttf,DroidSansFallbackFull.ttf,Junicode-Regular.ttf" - family_order=_ "DejaVu Sans,Andagii,Droid Sans Japanese,Droid Sans Fallback,Junicode" + family_order=_ "Lato" # Used by GUI2 only, hence no [font] blocks for these. The font files are # also automatically determined. family_order_monospace=_ "DejaVu Sans Mono" + [font] + name="Lato-Regular.ttf" + bold_name="Lato-Bold.ttf" + italic_name="Lato-Italic.ttf" + codepoints="32-126,160-831,834,837-879,885,890-893,900-902,904-906,908,910-929,931-974,976-1158,1160-1299,3647,7424-7626,7678-7835,7838,7840-7929,7936-7957,7960-7965,7968-8005,8008-8013,8016-8023,8025,8027,8029,8031-8048,8050,8052,8054,8056,8058,8060,8064-8116,8118-8122,8124-8125,8127-8132,8134-8136,8138,8140-8146,8150-8154,8157-8162,8164-8170,8172-8173,8178-8180,8182-8184,8186,8188,8190,8194-8208,8210-8226,8230,8239-8240,8242-8244,8249-8250,8252-8254,8260,8286-8287,8304-8305,8308-8340,8352-8373,8376-8378,8413,8453,8467,8470-8471,8480,8482,8494,8498,8525-8526,8531-8543,8579-8580,8592-8601,8616,8706,8710,8719,8721-8722,8725,8729-8730,8734-8735,8745,8747,8776,8800-8801,8804-8805,8962,8976,8992-8993,9312-9331,9450-9460,9471-9472,9474,9484,9488,9492,9496,9633,9642-9643,9674-9676,9679,9702,9728,9788,9833,10102-10111,11360-11372,11380-11383,11799,42775-42778,42784-42785,63743,64256-64260,65056-65059,65279" + [/font] + [font] name="DejaVuSans.ttf" bold_name="DejaVuSans-Bold.ttf" diff --git a/data/lua/wml-flow.lua b/data/lua/wml-flow.lua new file mode 100644 index 000000000000..8043129850bd --- /dev/null +++ b/data/lua/wml-flow.lua @@ -0,0 +1,259 @@ +local helper = wesnoth.require "lua/helper.lua" +local utils = wesnoth.require "lua/wml-utils.lua" +local wml_actions = wesnoth.wml_actions + +function wml_actions.command(cfg) + utils.handle_event_commands(cfg, "plain") +end + +-- we can't create functions with names that are Lua keywords (eg if, while) +-- instead, we store the following anonymous functions directly into +-- the table, using the [] operator, rather than by using the point syntax + +wml_actions["if"] = function(cfg) + if not (helper.get_child(cfg, 'then') or helper.get_child(cfg, 'elseif') or helper.get_child(cfg, 'else')) then + helper.wml_error("[if] didn't find any [then], [elseif], or [else] children.") + end + + if wesnoth.eval_conditional(cfg) then -- evaluate [if] tag + for then_child in helper.child_range(cfg, "then") do + local action = utils.handle_event_commands(then_child, "conditional") + if action ~= "none" then break end + end + return -- stop after executing [then] tags + end + + for elseif_child in helper.child_range(cfg, "elseif") do + if wesnoth.eval_conditional(elseif_child) then -- we'll evaluate the [elseif] tags one by one + for then_tag in helper.child_range(elseif_child, "then") do + local action = utils.handle_event_commands(then_tag, "conditional") + if action ~= "none" then break end + end + return -- stop on first matched condition + end + end + + -- no matched condition, try the [else] tags + for else_child in helper.child_range(cfg, "else") do + local action = utils.handle_event_commands(else_child, "conditional") + if action ~= "none" then break end + end +end + +wml_actions["while"] = function( cfg ) + if helper.child_count(cfg, "do") == 0 then + helper.wml_error "[while] does not contain any [do] tags" + end + + -- execute [do] up to 65536 times + for i = 1, 65536 do + if wesnoth.eval_conditional( cfg ) then + for do_child in helper.child_range( cfg, "do" ) do + local action = utils.handle_event_commands(do_child, "loop") + if action == "break" then + utils.set_exiting("none") + return + elseif action == "continue" then + utils.set_exiting("none") + break + elseif action ~= "none" then + return + end + end + else return end + end +end + +wml_actions["break"] = function(cfg) + utils.set_exiting("break") +end + +wml_actions["return"] = function(cfg) + utils.set_exiting("return") +end + +function wml_actions.continue(cfg) + utils.set_exiting("continue") +end + +wesnoth.wml_actions["for"] = function(cfg) + if helper.child_count(cfg, "do") == 0 then + helper.wml_error "[for] does not contain any [do] tags" + end + + local loop_lim = {} + local first + if cfg.array ~= nil then + if cfg.reverse then + first = wesnoth.get_variable(cfg.array .. ".length") - 1 + loop_lim.last = 0 + loop_lim.step = -1 + else + first = 0 + loop_lim.last = '$($' .. cfg.array .. ".length - 1)" + loop_lim.step = 1 + end + else + -- Get a literal config to fetch end and step; + -- this done is to delay expansion of variables + local cfg_lit = helper.literal(cfg) + first = cfg.start or 0 + loop_lim.last = cfg_lit["end"] or first + if cfg.step then loop_lim.step = cfg_lit.step end + end + loop_lim = wesnoth.tovconfig(loop_lim) + if loop_lim.step == 0 then -- Sanity check + helper.wml_error("[for] has a step of 0!") + end + if (first < loop_lim.last and loop_lim.step <= 0) or (first > loop_lim.last and loop_lim.step >= 0) then + -- Sanity check: If they specify something like start,end,step=1,4,-1 + -- then we do nothing + return + end + local i_var = cfg.variable or "i" + local save_i = utils.start_var_scope(i_var) + wesnoth.set_variable(i_var, first) + local function loop_condition() + local sentinel = loop_lim.last + if loop_lim.step then + sentinel = sentinel + loop_lim.step + elseif loop_lim.last < first then + sentinel = sentinel - 1 + else + sentinel = sentinel + 1 + end + if loop_lim.step > 0 then + return wesnoth.get_variable(i_var) < sentinel + else + return wesnoth.get_variable(i_var) > sentinel + end + end + while loop_condition() do + for do_child in helper.child_range( cfg, "do" ) do + local action = utils.handle_event_commands(do_child, "loop") + if action == "break" then + utils.set_exiting("none") + goto exit + elseif action == "continue" then + utils.set_exiting("none") + break + elseif action ~= "none" then + goto exit + end + end + wesnoth.set_variable(i_var, wesnoth.get_variable(i_var) + loop_lim.step) + end + ::exit:: + utils.end_var_scope(i_var, save_i) +end + +wml_actions["repeat"] = function(cfg) + if helper.child_count(cfg, "do") == 0 then + helper.wml_error "[repeat] does not contain any [do] tags" + end + + local times = cfg.times or 1 + for i = 1, times do + for do_child in helper.child_range( cfg, "do" ) do + local action = utils.handle_event_commands(do_child, "loop") + if action == "break" then + utils.set_exiting("none") + return + elseif action == "continue" then + utils.set_exiting("none") + break + elseif action ~= "none" then + return + end + end + end +end + +function wml_actions.foreach(cfg) + if helper.child_count(cfg, "do") == 0 then + helper.wml_error "[foreach] does not contain any [do] tags" + end + + local array_name = cfg.variable or helper.wml_error "[foreach] missing required variable= attribute" + local array = helper.get_variable_array(array_name) + if #array == 0 then return end -- empty and scalars unwanted + local item_name = cfg.item_var or "this_item" + local this_item = utils.start_var_scope(item_name) -- if this_item is already set + local i_name = cfg.index_var or "i" + local i = utils.start_var_scope(i_name) -- if i is already set + local array_length = wesnoth.get_variable(array_name .. ".length") + + for index, value in ipairs(array) do + -- Some protection against external modification + -- It's not perfect, though - it'd be nice if *any* change could be detected + if array_length ~= wesnoth.get_variable(array_name .. ".length") then + helper.wml_error("WML array length changed during [foreach] iteration") + end + wesnoth.set_variable(item_name, value) + -- set index variable + wesnoth.set_variable(i_name, index-1) -- here -1, because of WML array + -- perform actions + for do_child in helper.child_range(cfg, "do") do + local action = utils.handle_event_commands(do_child, "loop") + if action == "break" then + utils.set_exiting("none") + goto exit + elseif action == "continue" then + utils.set_exiting("none") + break + elseif action ~= "none" then + goto exit + end + end + -- set back the content, in case the author made some modifications + if not cfg.readonly then + array[index] = wesnoth.get_variable(item_name) + end + end + ::exit:: + + -- house cleaning + utils.end_var_scope(item_name, this_item) + utils.end_var_scope(i_name, i) + + --[[ + This forces the readonly key to be taken literally. + + If readonly=yes, then this line guarantees that the array + is unchanged after the [foreach] loop ends. + + If readonly=no, then this line updates the array with any + changes the user has applied through the $this_item + variable (or whatever variable was given in item_var). + + Note that altering the array via indexing (with the index_var) + is not supported; any such changes will be reverted by this line. + ]] + helper.set_variable_array(array_name, array) +end + +function wml_actions.switch(cfg) + local var_value = wesnoth.get_variable(cfg.variable) + local found = false + + -- Execute all the [case]s where the value matches. + for v in helper.child_range(cfg, "case") do + for w in utils.split(v.value) do + if w == tostring(var_value) then + local action = utils.handle_event_commands(v, "switch") + found = true + if action ~= "none" then goto exit end + break + end + end + end + ::exit:: + + -- Otherwise execute [else] statements. + if not found then + for v in helper.child_range(cfg, "else") do + local action = utils.handle_event_commands(v, "switch") + if action ~= "none" then break end + end + end +end \ No newline at end of file diff --git a/data/lua/wml-tags.lua b/data/lua/wml-tags.lua index 2cd194dc9cf5..3a2efde140bd 100644 --- a/data/lua/wml-tags.lua +++ b/data/lua/wml-tags.lua @@ -11,10 +11,16 @@ function wesnoth.game_events.on_save() return {} end +wesnoth.require "lua/wml-flow.lua" wesnoth.require "lua/wml/objectives.lua" wesnoth.require "lua/wml/items.lua" wesnoth.require "lua/wml/message.lua" wesnoth.require "lua/wml/object.lua" +wesnoth.require "lua/wml/modify_unit.lua" +wesnoth.require "lua/wml/harm_unit.lua" +wesnoth.require "lua/wml/find_path.lua" +wesnoth.require "lua/wml/endlevel.lua" +wesnoth.require "lua/wml/random_placement.lua" local helper = wesnoth.require "lua/helper.lua" local location_set = wesnoth.require "lua/location_set.lua" @@ -260,262 +266,6 @@ function wml_actions.music(cfg) wesnoth.set_music(cfg) end -function wml_actions.command(cfg) - utils.handle_event_commands(cfg, "plain") -end - --- we can't create functions with names that are Lua keywords (eg if, while) --- instead, we store the following anonymous functions directly into --- the table, using the [] operator, rather than by using the point syntax - -wml_actions["if"] = function(cfg) - if not (helper.get_child(cfg, 'then') or helper.get_child(cfg, 'elseif') or helper.get_child(cfg, 'else')) then - helper.wml_error("[if] didn't find any [then], [elseif], or [else] children.") - end - - if wesnoth.eval_conditional(cfg) then -- evaluate [if] tag - for then_child in helper.child_range(cfg, "then") do - local action = utils.handle_event_commands(then_child, "conditional") - if action ~= "none" then break end - end - return -- stop after executing [then] tags - end - - for elseif_child in helper.child_range(cfg, "elseif") do - if wesnoth.eval_conditional(elseif_child) then -- we'll evaluate the [elseif] tags one by one - for then_tag in helper.child_range(elseif_child, "then") do - local action = utils.handle_event_commands(then_tag, "conditional") - if action ~= "none" then break end - end - return -- stop on first matched condition - end - end - - -- no matched condition, try the [else] tags - for else_child in helper.child_range(cfg, "else") do - local action = utils.handle_event_commands(else_child, "conditional") - if action ~= "none" then break end - end -end - -wml_actions["while"] = function( cfg ) - if helper.child_count(cfg, "do") == 0 then - helper.wml_error "[while] does not contain any [do] tags" - end - - -- execute [do] up to 65536 times - for i = 1, 65536 do - if wesnoth.eval_conditional( cfg ) then - for do_child in helper.child_range( cfg, "do" ) do - local action = utils.handle_event_commands(do_child, "loop") - if action == "break" then - utils.set_exiting("none") - return - elseif action == "continue" then - utils.set_exiting("none") - break - elseif action ~= "none" then - return - end - end - else return end - end -end - -wml_actions["break"] = function(cfg) - utils.set_exiting("break") -end - -wml_actions["return"] = function(cfg) - utils.set_exiting("return") -end - -function wml_actions.continue(cfg) - utils.set_exiting("continue") -end - -wesnoth.wml_actions["for"] = function(cfg) - if helper.child_count(cfg, "do") == 0 then - helper.wml_error "[for] does not contain any [do] tags" - end - - local loop_lim = {} - local first - if cfg.array ~= nil then - if cfg.reverse then - first = wesnoth.get_variable(cfg.array .. ".length") - 1 - loop_lim.last = 0 - loop_lim.step = -1 - else - first = 0 - loop_lim.last = '$($' .. cfg.array .. ".length - 1)" - loop_lim.step = 1 - end - else - -- Get a literal config to fetch end and step; - -- this done is to delay expansion of variables - local cfg_lit = helper.literal(cfg) - first = cfg.start or 0 - loop_lim.last = cfg_lit["end"] or first - if cfg.step then loop_lim.step = cfg_lit.step end - end - loop_lim = wesnoth.tovconfig(loop_lim) - if loop_lim.step == 0 then -- Sanity check - helper.wml_error("[for] has a step of 0!") - end - if (first < loop_lim.last and loop_lim.step <= 0) or (first > loop_lim.last and loop_lim.step >= 0) then - -- Sanity check: If they specify something like start,end,step=1,4,-1 - -- then we do nothing - return - end - local i_var = cfg.variable or "i" - local save_i = utils.start_var_scope(i_var) - wesnoth.set_variable(i_var, first) - local function loop_condition() - local sentinel = loop_lim.last - if loop_lim.step then - sentinel = sentinel + loop_lim.step - elseif loop_lim.last < first then - sentinel = sentinel - 1 - else - sentinel = sentinel + 1 - end - if loop_lim.step > 0 then - return wesnoth.get_variable(i_var) < sentinel - else - return wesnoth.get_variable(i_var) > sentinel - end - end - while loop_condition() do - for do_child in helper.child_range( cfg, "do" ) do - local action = utils.handle_event_commands(do_child, "loop") - if action == "break" then - utils.set_exiting("none") - goto exit - elseif action == "continue" then - utils.set_exiting("none") - break - elseif action ~= "none" then - goto exit - end - end - wesnoth.set_variable(i_var, wesnoth.get_variable(i_var) + loop_lim.step) - end - ::exit:: - utils.end_var_scope(i_var, save_i) -end - -wml_actions["repeat"] = function(cfg) - if helper.child_count(cfg, "do") == 0 then - helper.wml_error "[repeat] does not contain any [do] tags" - end - - local times = cfg.times or 1 - for i = 1, times do - for do_child in helper.child_range( cfg, "do" ) do - local action = utils.handle_event_commands(do_child, "loop") - if action == "break" then - utils.set_exiting("none") - return - elseif action == "continue" then - utils.set_exiting("none") - break - elseif action ~= "none" then - return - end - end - end -end - -function wml_actions.foreach(cfg) - if helper.child_count(cfg, "do") == 0 then - helper.wml_error "[foreach] does not contain any [do] tags" - end - - local array_name = cfg.variable or helper.wml_error "[foreach] missing required variable= attribute" - local array = helper.get_variable_array(array_name) - if #array == 0 then return end -- empty and scalars unwanted - local item_name = cfg.item_var or "this_item" - local this_item = utils.start_var_scope(item_name) -- if this_item is already set - local i_name = cfg.index_var or "i" - local i = utils.start_var_scope(i_name) -- if i is already set - local array_length = wesnoth.get_variable(array_name .. ".length") - - for index, value in ipairs(array) do - -- Some protection against external modification - -- It's not perfect, though - it'd be nice if *any* change could be detected - if array_length ~= wesnoth.get_variable(array_name .. ".length") then - helper.wml_error("WML array length changed during [foreach] iteration") - end - wesnoth.set_variable(item_name, value) - -- set index variable - wesnoth.set_variable(i_name, index-1) -- here -1, because of WML array - -- perform actions - for do_child in helper.child_range(cfg, "do") do - local action = utils.handle_event_commands(do_child, "loop") - if action == "break" then - utils.set_exiting("none") - goto exit - elseif action == "continue" then - utils.set_exiting("none") - break - elseif action ~= "none" then - goto exit - end - end - -- set back the content, in case the author made some modifications - if not cfg.readonly then - array[index] = wesnoth.get_variable(item_name) - end - end - ::exit:: - - -- house cleaning - utils.end_var_scope(item_name, this_item) - utils.end_var_scope(i_name, i) - - --[[ - This forces the readonly key to be taken literally. - - If readonly=yes, then this line guarantees that the array - is unchanged after the [foreach] loop ends. - - If readonly=no, then this line updates the array with any - changes the user has applied through the $this_item - variable (or whatever variable was given in item_var). - - Note that altering the array via indexing (with the index_var) - is not supported; any such changes will be reverted by this line. - ]] - helper.set_variable_array(array_name, array) -end - -function wml_actions.switch(cfg) - local var_value = wesnoth.get_variable(cfg.variable) - local found = false - - -- Execute all the [case]s where the value matches. - for v in helper.child_range(cfg, "case") do - for w in utils.split(v.value) do - if w == tostring(var_value) then - local action = utils.handle_event_commands(v, "switch") - found = true - if action ~= "none" then goto exit end - break - end - end - end - ::exit:: - - -- Otherwise execute [else] statements. - if not found then - for v in helper.child_range(cfg, "else") do - local action = utils.handle_event_commands(v, "switch") - if action ~= "none" then break end - end - end -end - -- This is mainly for use in unit test macros, but maybe it can be useful elsewhere too function wml_actions.test_condition(cfg) local logger = cfg.logger or "warning" @@ -558,7 +308,7 @@ function wml_actions.test_condition(cfg) if tag == "variable" then explanation = string.format("%s\n\tNote: The variable %s currently has the value %q.", explanation, this_cfg.name, tostring(wesnoth.get_variable(this_cfg.name))) end - wesnoth.wml_actions.wml_message{message = explanation, logger = logger} + wesnoth.log(logger, explanation, true) return true end end @@ -748,77 +498,6 @@ function wml_actions.unhide_unit(cfg) wml_actions.redraw {} end -function wml_actions.modify_unit(cfg) - local unit_variable = "LUA_modify_unit" - - local function handle_attributes(cfg, unit_path, toplevel) - for current_key, current_value in pairs(helper.shallow_parsed(cfg)) do - if type(current_value) ~= "table" and (not toplevel or current_key ~= "type") then - wesnoth.set_variable(string.format("%s.%s", unit_path, current_key), current_value) - end - end - end - - local function handle_child(cfg, unit_path) - local children_handled = {} - local cfg = helper.shallow_parsed(cfg) - handle_attributes(cfg, unit_path) - - for current_index, current_table in ipairs(cfg) do - local current_tag = current_table[1] - local tag_index = children_handled[current_tag] or 0 - handle_child(current_table[2], string.format("%s.%s[%u]", - unit_path, current_tag, tag_index)) - children_handled[current_tag] = tag_index + 1 - end - end - - local filter = helper.get_child(cfg, "filter") or helper.wml_error "[modify_unit] missing required [filter] tag" - local function handle_unit(unit_num) - local children_handled = {} - local unit_path = string.format("%s[%u]", unit_variable, unit_num) - local this_unit = wesnoth.get_variable(unit_path) - wesnoth.set_variable("this_unit", this_unit) - handle_attributes(cfg, unit_path, true) - - for current_index, current_table in ipairs(helper.shallow_parsed(cfg)) do - local current_tag = current_table[1] - if current_tag == "filter" then - -- nothing - elseif current_tag == "object" or current_tag == "trait" or current_tag == "advancement" then - local unit = wesnoth.get_variable(unit_path) - unit = wesnoth.create_unit(unit) - wesnoth.add_modification(unit, current_tag, current_table[2]) - unit = unit.__cfg; - wesnoth.set_variable(unit_path, unit) - else - local tag_index = children_handled[current_tag] or 0 - handle_child(current_table[2], string.format("%s.%s[%u]", - unit_path, current_tag, tag_index)) - children_handled[current_tag] = tag_index + 1 - end - end - - if cfg.type then - if cfg.type ~= "" then wesnoth.set_variable(unit_path .. ".advances_to", cfg.type) end - wesnoth.set_variable(unit_path .. ".experience", wesnoth.get_variable(unit_path .. ".max_experience")) - end - wml_actions.kill({ id = this_unit.id, animate = false }) - wml_actions.unstore_unit { variable = unit_path } - end - - wml_actions.store_unit { {"filter", filter}, variable = unit_variable } - local max_index = wesnoth.get_variable(unit_variable .. ".length") - 1 - - local this_unit = utils.start_var_scope("this_unit") - for current_unit = 0, max_index do - handle_unit(current_unit) - end - utils.end_var_scope("this_unit", this_unit) - - wesnoth.set_variable(unit_variable) -end - function wml_actions.move_unit(cfg) local coordinate_error = "invalid coordinate in [move_unit]" local to_x = tostring(cfg.to_x or helper.wml_error(coordinate_error)) @@ -949,207 +628,6 @@ function wml_actions.unpetrify(cfg) end end -function wml_actions.harm_unit(cfg) - local filter = helper.get_child(cfg, "filter") or helper.wml_error("[harm_unit] missing required [filter] tag") - -- we need to use shallow_literal field, to avoid raising an error if $this_unit (not yet assigned) is used - if not helper.shallow_literal(cfg).amount then helper.wml_error("[harm_unit] has missing required amount= attribute") end - local variable = cfg.variable -- kept out of the way to avoid problems - local _ = wesnoth.textdomain "wesnoth" - -- #textdomain wesnoth - local harmer - - local function toboolean( value ) -- helper for animate fields - -- units will be animated upon leveling or killing, even - -- with special attacker and defender values - if value then return true - else return false end - end - - local this_unit = utils.start_var_scope("this_unit") - - for index, unit_to_harm in ipairs(wesnoth.get_units(filter)) do - if unit_to_harm.valid then - -- block to support $this_unit - wesnoth.set_variable ( "this_unit" ) -- clearing this_unit - wesnoth.set_variable("this_unit", unit_to_harm.__cfg) -- cfg field needed - local amount = tonumber(cfg.amount) - local animate = cfg.animate -- attacker and defender are special values - local delay = cfg.delay or 500 - local kill = cfg.kill - local fire_event = cfg.fire_event - local primary_attack = helper.get_child(cfg, "primary_attack") - local secondary_attack = helper.get_child(cfg, "secondary_attack") - local harmer_filter = helper.get_child(cfg, "filter_second") - local experience = cfg.experience - local resistance_multiplier = tonumber(cfg.resistance_multiplier) or 1 - if harmer_filter then harmer = wesnoth.get_units(harmer_filter)[1] end - -- end of block to support $this_unit - - if animate then - if animate ~= "defender" and harmer and harmer.valid then - wesnoth.scroll_to_tile(harmer.x, harmer.y, true) - wml_actions.animate_unit { - flag = "attack", - hits = true, - with_bars = true, - T.filter { id = harmer.id }, - T.primary_attack ( primary_attack ), - T.secondary_attack ( secondary_attack ), - T.facing { x = unit_to_harm.x, y = unit_to_harm.y }, - } - end - wesnoth.scroll_to_tile(unit_to_harm.x, unit_to_harm.y, true) - end - - -- the two functions below are taken straight from the C++ engine, utils.cpp and actions.cpp, with a few unuseful parts removed - -- may be moved in helper.lua in 1.11 - local function round_damage( base_damage, bonus, divisor ) - local rounding - if base_damage == 0 then return 0 - else - if bonus < divisor or divisor == 1 then - rounding = divisor / 2 - 0 - else - rounding = divisor / 2 - 1 - end - return math.max( 1, math.floor( ( base_damage * bonus + rounding ) / divisor ) ) - end - end - - local function calculate_damage( base_damage, alignment, tod_bonus, resistance, modifier ) - local damage_multiplier = 100 - if alignment == "lawful" then - damage_multiplier = damage_multiplier + tod_bonus - elseif alignment == "chaotic" then - damage_multiplier = damage_multiplier - tod_bonus - elseif alignment == "liminal" then - damage_multiplier = damage_multiplier - math.abs( tod_bonus ) - else -- neutral, do nothing - end - local resistance_modified = resistance * modifier - damage_multiplier = damage_multiplier * resistance_modified - local damage = round_damage( base_damage, damage_multiplier, 10000 ) -- if harmer.status.slowed, this may be 20000 ? - return damage - end - - local damage = calculate_damage( - amount, - cfg.alignment or "neutral", - wesnoth.get_time_of_day( { unit_to_harm.x, unit_to_harm.y, true } ).lawful_bonus, - wesnoth.unit_resistance( unit_to_harm, cfg.damage_type or "dummy" ), - resistance_multiplier - ) - - if unit_to_harm.hitpoints <= damage then - if kill == false then damage = unit_to_harm.hitpoints - 1 - else damage = unit_to_harm.hitpoints - end - end - - unit_to_harm.hitpoints = unit_to_harm.hitpoints - damage - local text = string.format("%d%s", damage, "\n") - local add_tab = false - local gender = unit_to_harm.__cfg.gender - - local function set_status(name, male_string, female_string, sound) - if not cfg[name] or unit_to_harm.status[name] then return end - if gender == "female" then - text = string.format("%s%s%s", text, tostring(female_string), "\n") - else - text = string.format("%s%s%s", text, tostring(male_string), "\n") - end - - unit_to_harm.status[name] = true - add_tab = true - - if animate and sound then -- for unhealable, that has no sound - wesnoth.play_sound (sound) - end - end - - if not unit_to_harm.status.unpoisonable then - set_status("poisoned", _"poisoned", _"female^poisoned", "poison.ogg") - end - set_status("slowed", _"slowed", _"female^slowed", "slowed.wav") - set_status("petrified", _"petrified", _"female^petrified", "petrified.ogg") - set_status("unhealable", _"unhealable", _"female^unhealable") - - -- Extract unit and put it back to update animation if status was changed - wesnoth.extract_unit(unit_to_harm) - wesnoth.put_unit(unit_to_harm) - - if add_tab then - text = string.format("%s%s", "\t", text) - end - - if animate and animate ~= "attacker" then - if harmer and harmer.valid then - wml_actions.animate_unit { - flag = "defend", - hits = true, - with_bars = true, - T.filter { id = unit_to_harm.id }, - T.primary_attack ( primary_attack ), - T.secondary_attack ( secondary_attack ), - T.facing { x = harmer.x, y = harmer.y }, - } - else - wml_actions.animate_unit { - flag = "defend", - hits = true, - with_bars = true, - T.filter { id = unit_to_harm.id }, - T.primary_attack ( primary_attack ), - T.secondary_attack ( secondary_attack ), - } - end - end - - wesnoth.float_label( unit_to_harm.x, unit_to_harm.y, string.format( "%s", text ) ) - - local function calc_xp( level ) -- to calculate the experience in case of kill - if level == 0 then return 4 - else return level * 8 end - end - - if experience ~= false and harmer and harmer.valid and wesnoth.is_enemy( unit_to_harm.side, harmer.side ) then -- no XP earned for harming friendly units - if kill ~= false and unit_to_harm.hitpoints <= 0 then - harmer.experience = harmer.experience + calc_xp( unit_to_harm.__cfg.level ) - else - unit_to_harm.experience = unit_to_harm.experience + harmer.__cfg.level - harmer.experience = harmer.experience + unit_to_harm.__cfg.level - end - end - - if kill ~= false and unit_to_harm.hitpoints <= 0 then - wml_actions.kill { id = unit_to_harm.id, animate = toboolean( animate ), fire_event = fire_event } - end - - if animate then - wesnoth.delay(delay) - end - - if variable then - wesnoth.set_variable(string.format("%s[%d]", variable, index - 1), { harm_amount = damage }) - end - - -- both units may no longer be alive at this point, so double check - if experience ~= false and unit_to_harm and unit_to_harm.valid then - unit_to_harm:advance(toboolean(animate), fire_event ~= false) - end - - if experience ~= false and harmer and harmer.valid then - harmer:advance(toboolean(animate), fire_event ~= false) - end - end - - wml_actions.redraw {} - end - - wesnoth.set_variable ( "this_unit" ) -- clearing this_unit - utils.end_var_scope("this_unit", this_unit) -end - function wml_actions.heal_unit(cfg) wesnoth.heal_unit(cfg) end @@ -1255,103 +733,6 @@ function wml_actions.add_ai_behavior(cfg) } end -function wml_actions.find_path(cfg) - local filter_unit = helper.get_child(cfg, "traveler") or helper.wml_error("[find_path] missing required [traveler] tag") - -- only the first unit matching - local unit = wesnoth.get_units(filter_unit)[1] or helper.wml_error("[find_path]'s filter didn't match any unit") - local filter_location = helper.get_child(cfg, "destination") or helper.wml_error( "[find_path] missing required [destination] tag" ) - -- support for $this_unit - local this_unit = utils.start_var_scope("this_unit") - - wesnoth.set_variable ( "this_unit" ) -- clearing this_unit - wesnoth.set_variable("this_unit", unit.__cfg) -- cfg field needed - - local variable = cfg.variable or "path" - local ignore_units = false - local ignore_teleport = false - - if cfg.check_zoc == false then --if we do not want to check the ZoCs, we must ignore units - ignore_units = true - end - if cfg.check_teleport == false then --if we do not want to check teleport, we must ignore it - ignore_teleport = true - end - - local allow_multiple_turns = cfg.allow_multiple_turns - local viewing_side - - if not cfg.check_visibility then viewing_side = 0 end -- if check_visiblity then shroud is taken in account - - local locations = wesnoth.get_locations(filter_location) -- only the location with the lowest distance and lowest movement cost will match. If there will still be more than 1, only the 1st maching one. - local max_cost = nil - if not allow_multiple_turns then max_cost = unit.moves end --to avoid wrong calculation on already moved units - local current_distance, current_cost = math.huge, math.huge - local current_location = {} - - local width,heigth,border = wesnoth.get_map_size() -- data for test below - - for index, location in ipairs(locations) do - -- we test if location passed to pathfinder is invalid (border); if is, do nothing, do not return and continue the cycle - if location[1] == 0 or location[1] == ( width + 1 ) or location[2] == 0 or location[2] == ( heigth + 1 ) then - else - local distance = helper.distance_between ( unit.x, unit.y, location[1], location[2] ) - -- if we pass an unreachable locations an high value will be returned - local path, cost = wesnoth.find_path( unit, location[1], location[2], { max_cost = max_cost, ignore_units = ignore_units, ignore_teleport = ignore_teleport, viewing_side = viewing_side } ) - - if ( distance < current_distance and cost <= current_cost ) or ( cost < current_cost and distance <= current_distance ) then -- to avoid changing the hex with one with less distance and more cost, or vice versa - current_distance = distance - current_cost = cost - current_location = location - end - end - end - - if #current_location == 0 then wesnoth.message("WML warning","[find_path]'s filter didn't match any location") - else - local path, cost = wesnoth.find_path( unit, current_location[1], current_location[2], { max_cost = max_cost, ignore_units = ignore_units, ignore_teleport = ignore_teleport, viewing_side = viewing_side } ) - local turns - - if cost == 0 then -- if location is the same, of course it doesn't cost any MP - turns = 0 - else - turns = math.ceil( ( ( cost - unit.moves ) / unit.max_moves ) + 1 ) - end - - if cost >= 42424242 then -- it's the high value returned for unwalkable or busy terrains - wesnoth.set_variable ( string.format("%s", variable), { hexes = 0 } ) -- set only length, nil all other values - -- support for $this_unit - wesnoth.set_variable ( "this_unit" ) -- clearing this_unit - utils.end_var_scope("this_unit", this_unit) - return end - - if not allow_multiple_turns and turns > 1 then -- location cannot be reached in one turn - wesnoth.set_variable ( string.format("%s", variable), { hexes = 0 } ) - -- support for $this_unit - wesnoth.set_variable ( "this_unit" ) -- clearing this_unit - utils.end_var_scope("this_unit", this_unit) - return end -- skip the cycles below - - wesnoth.set_variable ( string.format( "%s", variable ), { hexes = current_distance, from_x = unit.x, from_y = unit.y, to_x = current_location[1], to_y = current_location[2], movement_cost = cost, required_turns = turns } ) - - for index, path_loc in ipairs(path) do - local sub_path, sub_cost = wesnoth.find_path( unit, path_loc[1], path_loc[2], { max_cost = max_cost, ignore_units = ignore_units, ignore_teleport = ignore_teleport, viewing_side = viewing_side } ) - local sub_turns - - if sub_cost == 0 then - sub_turns = 0 - else - sub_turns = math.ceil( ( ( sub_cost - unit.moves ) / unit.max_moves ) + 1 ) - end - - wesnoth.set_variable ( string.format( "%s.step[%d]", variable, index - 1 ), { x = path_loc[1], y = path_loc[2], terrain = wesnoth.get_terrain( path_loc[1], path_loc[2] ), movement_cost = sub_cost, required_turns = sub_turns } ) -- this structure takes less space in the inspection window - end - end - - -- support for $this_unit - wesnoth.set_variable ( "this_unit" ) -- clearing this_unit - utils.end_var_scope("this_unit", this_unit) -end - function wml_actions.store_starting_location(cfg) local writer = utils.vwriter.init(cfg, "location") for possibly_wrong_index, side in ipairs(wesnoth.get_sides(cfg)) do @@ -1459,98 +840,6 @@ function wml_actions.end_turn(cfg) wesnoth.end_turn() end -function wml_actions.endlevel(cfg) - local parsed = helper.parsed(cfg) - if wesnoth.check_end_level_disabled() then - wesnoth.message("Repeated [endlevel] execution, ignoring") - return - end - - local next_scenario = cfg.next_scenario - if next_scenario then - wesnoth.set_next_scenario(next_scenario) - end - - local end_text = cfg.end_text - local end_text_duration = cfg.end_text_duration - if end_text or end_text_duration then - wesnoth.set_end_campaign_text(end_text or "", end_text_duration) - end - - local end_credits = cfg.end_credits - if end_credits ~= nil then - wesnoth.set_end_campaign_credits(end_credits) - end - - local side_results = {} - for result in helper.child_range(parsed, "result") do - local side = result.side or helper.wml_error("[result] in [endlevel] missing required side= key") - side_results[side] = result - end - local there_is_a_human_victory = false - local there_is_a_human_defeat = false - local there_is_a_local_human_victory = false - local there_is_a_local_human_defeat = false - local bool_int = function(b) - if b == true then - return 1 - elseif b == false then - return 0 - else - return b - end - end - for k,v in ipairs(wesnoth.sides) do - local side_result = side_results[v.side] or {} - local victory_or_defeat = side_result.result or cfg.result or "victory" - local victory = victory_or_defeat == "victory" - if victory_or_defeat ~= "victory" and victory_or_defeat ~= "defeat" then - return helper.wml_error("invalid result= key in [endlevel] '" .. victory_or_defeat .."'") - end - if v.controller == "human" or v.controller == "network" then - if victory then - there_is_a_human_victory = true - else - there_is_a_human_defeat = true - end - end - if v.controller == "human" then - if victory then - there_is_a_local_human_victory = true - else - there_is_a_local_human_defeat = true - end - end - if side_result.bonus ~= nil then - v.carryover_bonus = bool_int(side_result.bonus) - elseif cfg.bonus ~= nil then - v.carryover_bonus = bool_int(cfg.bonus) - end - if side_result.carryover_add ~= nil then - v.carryover_add = side_result.carryover_add - elseif cfg.carryover_add ~= nil then - v.carryover_add = cfg.carryover_add - end - if side_result.carryover_percentage ~= nil then - v.carryover_percentage = side_result.carryover_percentage - elseif cfg.carryover_percentage ~= nil then - v.carryover_percentage = cfg.carryover_percentage - end - end - local proceed_to_next_level = there_is_a_human_victory or (not there_is_a_human_defeat and cfg.result ~= "defeat") - local victory = there_is_a_local_human_victory or (not there_is_a_local_human_defeat and proceed_to_next_level) - wesnoth.end_level { - music = cfg.music, - carryover_report = cfg.carryover_report, - save = cfg.save, - replay_save = cfg.replay_save, - linger_mode = cfg.linger_mode, - reveal_map = cfg.reveal_map, - proceed_to_next_level = proceed_to_next_level, - result = victory and "victory" or "defeat", - } -end - function wml_actions.event(cfg) if cfg.remove then wml_actions.remove_event(cfg) @@ -1661,79 +950,6 @@ function wml_actions.unsynced(cfg) end) end -wesnoth.wml_actions.random_placement = function(cfg) - local dist_le = nil - - local parsed = helper.shallow_parsed(cfg) - -- TODO: In most cases this tag is used to place units, so maybe make include_borders=no the default for [filter_location]? - local filter = helper.get_child(parsed, "filter_location") or {} - local command = helper.get_child(parsed, "command") or helper.wml_error("[random_placement] missing required [command] subtag") - local distance = cfg.min_distance or 0 - local num_items = cfg.num_items or helper.wml_error("[random_placement] missing required 'num_items' attribute") - local variable = cfg.variable or helper.wml_error("[random_placement] missing required 'variable' attribute") - local allow_less = cfg.allow_less == true - local variable_previous = utils.start_var_scope(variable) - - if distance < 0 then - -- optimisation for distance = -1 - dist_le = function() return false end - elseif distance == 0 then - -- optimisation for distance = 0 - dist_le = function(x1,y1,x2,y2) return x1 == x2 and y1 == y2 end - else - -- optimisation: cloasure is faster than string lookups. - local math_abs = math.abs - -- same effect as helper.distance_between(x1,y1,x2,y2) <= distance but faster. - dist_le = function(x1,y1,x2,y2) - local d_x = math_abs(x1-x2) - if d_x > distance then - return false - end - if d_x % 2 ~= 0 then - if x1 % 2 == 0 then - y2 = y2 - 0.5 - else - y2 = y2 + 0.5 - end - end - local d_y = math_abs(y1-y2) - return d_x + 2*d_y <= 2*distance - end - end - - local locs = wesnoth.get_locations(filter) - if type(num_items) == "string" then - num_items = math.floor(loadstring("local size = " .. #locs .. "; return " .. num_items)()) - print("num_items=" .. num_items .. ", #locs=" .. #locs) - end - local size = #locs - for i = 1, num_items do - if size == 0 then - if allow_less then - print("placed only " .. i .. " items") - return - else - helper.wml_error("[random_placement] failed to place items. only " .. i .. " items were placed") - end - end - local index = wesnoth.random(size) - local point = locs[index] - wesnoth.set_variable(variable .. ".x", point[1]) - wesnoth.set_variable(variable .. ".y", point[2]) - wesnoth.set_variable(variable .. ".n", i) - for j = size, 1, -1 do - if dist_le(locs[j][1], locs[j][2], point[1], point[2]) then - -- optimisation: swapping elements and storing size in an extra variable is faster than table.remove(locs, j) - locs[j] = locs[size] - size = size - 1 - end - end - wesnoth.wml_actions.command (command) - end - utils.end_var_scope(variable, variable_previous) - -end - local function on_board(x, y) if type(x) ~= "number" or type(y) ~= "number" then return false @@ -1788,6 +1004,42 @@ wml_actions.teleport = function(cfg) wesnoth.teleport(unit, cfg.check_passability == false, cfg.clear_shroud ~= false, cfg.animate) end +function wml_actions.remove_sound_source(cfg) + wesnoth.remove_sound_source(cfg.id) +end + +function wml_actions.sound_source(cfg) + wesnoth.add_sound_source(cfg) +end + +function wml_actions.deprecated_message(cfg) + wesnoth.log('wml', cfg.message) +end + +function wml_actions.wml_message(cfg) + local logger = cfg.logger or '' + wesnoth.log(cfg.logger, cfg.message, cfg.to_chat) +end + +local function parse_fog_cfg(cfg) + -- Side filter + local ssf = helper.child(cfg, "filter_side") + local sides = wesnoth.get_sides(ssf or {}) + -- Location filter + local locs = wesnoth.get_locations(cfg) + return locs, sides +end + +function wml_actions.lift_fog(cfg) + local locs, sides = parse_fog_cfg(cfg) + wesnoth.remove_fog(sides, locs, not cfg.multiturn) +end + +function wml_actions.reset_fog(cfg) + local locs, sides = parse_fog_cfg(cfg) + wesnoth.add_fog(sides, locs, cfg.reset_view) +end + function wml_actions.set_variable(cfg) local name = cfg.name or helper.wml_error "trying to set a variable with an empty name" local var = wesnoth.get_variable(name) @@ -1920,3 +1172,4 @@ function wml_actions.set_variable(cfg) wesnoth.set_variable(name, table.concat(string_to_join, separator)) end end +end diff --git a/data/lua/wml/endlevel.lua b/data/lua/wml/endlevel.lua new file mode 100644 index 000000000000..67cdbbd3a52f --- /dev/null +++ b/data/lua/wml/endlevel.lua @@ -0,0 +1,93 @@ +local helper = wesnoth.require "lua/helper.lua" + +function wesnoth.wml_actions.endlevel(cfg) + local parsed = helper.parsed(cfg) + if wesnoth.check_end_level_disabled() then + wesnoth.message("Repeated [endlevel] execution, ignoring") + return + end + + local next_scenario = cfg.next_scenario + if next_scenario then + wesnoth.set_next_scenario(next_scenario) + end + + local end_text = cfg.end_text + local end_text_duration = cfg.end_text_duration + if end_text or end_text_duration then + wesnoth.set_end_campaign_text(end_text or "", end_text_duration) + end + + local end_credits = cfg.end_credits + if end_credits ~= nil then + wesnoth.set_end_campaign_credits(end_credits) + end + + local side_results = {} + for result in helper.child_range(parsed, "result") do + local side = result.side or helper.wml_error("[result] in [endlevel] missing required side= key") + side_results[side] = result + end + local there_is_a_human_victory = false + local there_is_a_human_defeat = false + local there_is_a_local_human_victory = false + local there_is_a_local_human_defeat = false + local bool_int = function(b) + if b == true then + return 1 + elseif b == false then + return 0 + else + return b + end + end + for k,v in ipairs(wesnoth.sides) do + local side_result = side_results[v.side] or {} + local victory_or_defeat = side_result.result or cfg.result or "victory" + local victory = victory_or_defeat == "victory" + if victory_or_defeat ~= "victory" and victory_or_defeat ~= "defeat" then + return helper.wml_error("invalid result= key in [endlevel] '" .. victory_or_defeat .."'") + end + if v.controller == "human" or v.controller == "network" then + if victory then + there_is_a_human_victory = true + else + there_is_a_human_defeat = true + end + end + if v.controller == "human" then + if victory then + there_is_a_local_human_victory = true + else + there_is_a_local_human_defeat = true + end + end + if side_result.bonus ~= nil then + v.carryover_bonus = bool_int(side_result.bonus) + elseif cfg.bonus ~= nil then + v.carryover_bonus = bool_int(cfg.bonus) + end + if side_result.carryover_add ~= nil then + v.carryover_add = side_result.carryover_add + elseif cfg.carryover_add ~= nil then + v.carryover_add = cfg.carryover_add + end + if side_result.carryover_percentage ~= nil then + v.carryover_percentage = side_result.carryover_percentage + elseif cfg.carryover_percentage ~= nil then + v.carryover_percentage = cfg.carryover_percentage + end + end + local proceed_to_next_level = there_is_a_human_victory or (not there_is_a_human_defeat and cfg.result ~= "defeat") + local victory = there_is_a_local_human_victory or (not there_is_a_local_human_defeat and proceed_to_next_level) + wesnoth.end_level { + music = cfg.music, + carryover_report = cfg.carryover_report, + save = cfg.save, + replay_save = cfg.replay_save, + linger_mode = cfg.linger_mode, + reveal_map = cfg.reveal_map, + proceed_to_next_level = proceed_to_next_level, + result = victory and "victory" or "defeat", + } +end \ No newline at end of file diff --git a/data/lua/wml/find_path.lua b/data/lua/wml/find_path.lua new file mode 100644 index 000000000000..654597c66159 --- /dev/null +++ b/data/lua/wml/find_path.lua @@ -0,0 +1,99 @@ +local helper = wesnoth.require "lua/helper.lua" +local utils = wesnoth.require "lua/wml-utils.lua" + +function wesnoth.wml_actions.find_path(cfg) + local filter_unit = helper.get_child(cfg, "traveler") or helper.wml_error("[find_path] missing required [traveler] tag") + -- only the first unit matching + local unit = wesnoth.get_units(filter_unit)[1] or helper.wml_error("[find_path]'s filter didn't match any unit") + local filter_location = helper.get_child(cfg, "destination") or helper.wml_error( "[find_path] missing required [destination] tag" ) + -- support for $this_unit + local this_unit = utils.start_var_scope("this_unit") + + wesnoth.set_variable ( "this_unit" ) -- clearing this_unit + wesnoth.set_variable("this_unit", unit.__cfg) -- cfg field needed + + local variable = cfg.variable or "path" + local ignore_units = false + local ignore_teleport = false + + if cfg.check_zoc == false then --if we do not want to check the ZoCs, we must ignore units + ignore_units = true + end + if cfg.check_teleport == false then --if we do not want to check teleport, we must ignore it + ignore_teleport = true + end + + local allow_multiple_turns = cfg.allow_multiple_turns + local viewing_side + + if not cfg.check_visibility then viewing_side = 0 end -- if check_visiblity then shroud is taken in account + + local locations = wesnoth.get_locations(filter_location) -- only the location with the lowest distance and lowest movement cost will match. If there will still be more than 1, only the 1st maching one. + local max_cost = nil + if not allow_multiple_turns then max_cost = unit.moves end --to avoid wrong calculation on already moved units + local current_distance, current_cost = math.huge, math.huge + local current_location = {} + + local width,heigth,border = wesnoth.get_map_size() -- data for test below + + for index, location in ipairs(locations) do + -- we test if location passed to pathfinder is invalid (border); if is, do nothing, do not return and continue the cycle + if location[1] == 0 or location[1] == ( width + 1 ) or location[2] == 0 or location[2] == ( heigth + 1 ) then + else + local distance = helper.distance_between ( unit.x, unit.y, location[1], location[2] ) + -- if we pass an unreachable locations an high value will be returned + local path, cost = wesnoth.find_path( unit, location[1], location[2], { max_cost = max_cost, ignore_units = ignore_units, ignore_teleport = ignore_teleport, viewing_side = viewing_side } ) + + if ( distance < current_distance and cost <= current_cost ) or ( cost < current_cost and distance <= current_distance ) then -- to avoid changing the hex with one with less distance and more cost, or vice versa + current_distance = distance + current_cost = cost + current_location = location + end + end + end + + if #current_location == 0 then wesnoth.message("WML warning","[find_path]'s filter didn't match any location") + else + local path, cost = wesnoth.find_path( unit, current_location[1], current_location[2], { max_cost = max_cost, ignore_units = ignore_units, ignore_teleport = ignore_teleport, viewing_side = viewing_side } ) + local turns + + if cost == 0 then -- if location is the same, of course it doesn't cost any MP + turns = 0 + else + turns = math.ceil( ( ( cost - unit.moves ) / unit.max_moves ) + 1 ) + end + + if cost >= 42424242 then -- it's the high value returned for unwalkable or busy terrains + wesnoth.set_variable ( string.format("%s", variable), { hexes = 0 } ) -- set only length, nil all other values + -- support for $this_unit + wesnoth.set_variable ( "this_unit" ) -- clearing this_unit + utils.end_var_scope("this_unit", this_unit) + return end + + if not allow_multiple_turns and turns > 1 then -- location cannot be reached in one turn + wesnoth.set_variable ( string.format("%s", variable), { hexes = 0 } ) + -- support for $this_unit + wesnoth.set_variable ( "this_unit" ) -- clearing this_unit + utils.end_var_scope("this_unit", this_unit) + return end -- skip the cycles below + + wesnoth.set_variable ( string.format( "%s", variable ), { hexes = current_distance, from_x = unit.x, from_y = unit.y, to_x = current_location[1], to_y = current_location[2], movement_cost = cost, required_turns = turns } ) + + for index, path_loc in ipairs(path) do + local sub_path, sub_cost = wesnoth.find_path( unit, path_loc[1], path_loc[2], { max_cost = max_cost, ignore_units = ignore_units, ignore_teleport = ignore_teleport, viewing_side = viewing_side } ) + local sub_turns + + if sub_cost == 0 then + sub_turns = 0 + else + sub_turns = math.ceil( ( ( sub_cost - unit.moves ) / unit.max_moves ) + 1 ) + end + + wesnoth.set_variable ( string.format( "%s.step[%d]", variable, index - 1 ), { x = path_loc[1], y = path_loc[2], terrain = wesnoth.get_terrain( path_loc[1], path_loc[2] ), movement_cost = sub_cost, required_turns = sub_turns } ) -- this structure takes less space in the inspection window + end + end + + -- support for $this_unit + wesnoth.set_variable ( "this_unit" ) -- clearing this_unit + utils.end_var_scope("this_unit", this_unit) +end \ No newline at end of file diff --git a/data/lua/wml/harm_unit.lua b/data/lua/wml/harm_unit.lua new file mode 100644 index 000000000000..30fbbb47c8e9 --- /dev/null +++ b/data/lua/wml/harm_unit.lua @@ -0,0 +1,204 @@ +local helper = wesnoth.require "lua/helper.lua" +local utils = wesnoth.require "lua/wml-utils.lua" +local wml_actions = wesnoth.wml_actions + +function wml_actions.harm_unit(cfg) + local filter = helper.get_child(cfg, "filter") or helper.wml_error("[harm_unit] missing required [filter] tag") + -- we need to use shallow_literal field, to avoid raising an error if $this_unit (not yet assigned) is used + if not helper.shallow_literal(cfg).amount then helper.wml_error("[harm_unit] has missing required amount= attribute") end + local variable = cfg.variable -- kept out of the way to avoid problems + local _ = wesnoth.textdomain "wesnoth" + -- #textdomain wesnoth + local harmer + + local function toboolean( value ) -- helper for animate fields + -- units will be animated upon leveling or killing, even + -- with special attacker and defender values + if value then return true + else return false end + end + + local this_unit = utils.start_var_scope("this_unit") + + for index, unit_to_harm in ipairs(wesnoth.get_units(filter)) do + if unit_to_harm.valid then + -- block to support $this_unit + wesnoth.set_variable ( "this_unit" ) -- clearing this_unit + wesnoth.set_variable("this_unit", unit_to_harm.__cfg) -- cfg field needed + local amount = tonumber(cfg.amount) + local animate = cfg.animate -- attacker and defender are special values + local delay = cfg.delay or 500 + local kill = cfg.kill + local fire_event = cfg.fire_event + local primary_attack = helper.get_child(cfg, "primary_attack") + local secondary_attack = helper.get_child(cfg, "secondary_attack") + local harmer_filter = helper.get_child(cfg, "filter_second") + local experience = cfg.experience + local resistance_multiplier = tonumber(cfg.resistance_multiplier) or 1 + if harmer_filter then harmer = wesnoth.get_units(harmer_filter)[1] end + -- end of block to support $this_unit + + if animate then + if animate ~= "defender" and harmer and harmer.valid then + wesnoth.scroll_to_tile(harmer.x, harmer.y, true) + wml_actions.animate_unit { + flag = "attack", + hits = true, + with_bars = true, + T.filter { id = harmer.id }, + T.primary_attack ( primary_attack ), + T.secondary_attack ( secondary_attack ), + T.facing { x = unit_to_harm.x, y = unit_to_harm.y }, + } + end + wesnoth.scroll_to_tile(unit_to_harm.x, unit_to_harm.y, true) + end + + -- the two functions below are taken straight from the C++ engine, utils.cpp and actions.cpp, with a few unuseful parts removed + -- may be moved in helper.lua in 1.11 + local function round_damage( base_damage, bonus, divisor ) + local rounding + if base_damage == 0 then return 0 + else + if bonus < divisor or divisor == 1 then + rounding = divisor / 2 - 0 + else + rounding = divisor / 2 - 1 + end + return math.max( 1, math.floor( ( base_damage * bonus + rounding ) / divisor ) ) + end + end + + local function calculate_damage( base_damage, alignment, tod_bonus, resistance, modifier ) + local damage_multiplier = 100 + if alignment == "lawful" then + damage_multiplier = damage_multiplier + tod_bonus + elseif alignment == "chaotic" then + damage_multiplier = damage_multiplier - tod_bonus + elseif alignment == "liminal" then + damage_multiplier = damage_multiplier - math.abs( tod_bonus ) + else -- neutral, do nothing + end + local resistance_modified = resistance * modifier + damage_multiplier = damage_multiplier * resistance_modified + local damage = round_damage( base_damage, damage_multiplier, 10000 ) -- if harmer.status.slowed, this may be 20000 ? + return damage + end + + local damage = calculate_damage( + amount, + cfg.alignment or "neutral", + wesnoth.get_time_of_day( { unit_to_harm.x, unit_to_harm.y, true } ).lawful_bonus, + wesnoth.unit_resistance( unit_to_harm, cfg.damage_type or "dummy" ), + resistance_multiplier + ) + + if unit_to_harm.hitpoints <= damage then + if kill == false then damage = unit_to_harm.hitpoints - 1 + else damage = unit_to_harm.hitpoints + end + end + + unit_to_harm.hitpoints = unit_to_harm.hitpoints - damage + local text = string.format("%d%s", damage, "\n") + local add_tab = false + local gender = unit_to_harm.__cfg.gender + + local function set_status(name, male_string, female_string, sound) + if not cfg[name] or unit_to_harm.status[name] then return end + if gender == "female" then + text = string.format("%s%s%s", text, tostring(female_string), "\n") + else + text = string.format("%s%s%s", text, tostring(male_string), "\n") + end + + unit_to_harm.status[name] = true + add_tab = true + + if animate and sound then -- for unhealable, that has no sound + wesnoth.play_sound (sound) + end + end + + if not unit_to_harm.status.unpoisonable then + set_status("poisoned", _"poisoned", _"female^poisoned", "poison.ogg") + end + set_status("slowed", _"slowed", _"female^slowed", "slowed.wav") + set_status("petrified", _"petrified", _"female^petrified", "petrified.ogg") + set_status("unhealable", _"unhealable", _"female^unhealable") + + -- Extract unit and put it back to update animation if status was changed + wesnoth.extract_unit(unit_to_harm) + wesnoth.put_unit(unit_to_harm) + + if add_tab then + text = string.format("%s%s", "\t", text) + end + + if animate and animate ~= "attacker" then + if harmer and harmer.valid then + wml_actions.animate_unit { + flag = "defend", + hits = true, + with_bars = true, + T.filter { id = unit_to_harm.id }, + T.primary_attack ( primary_attack ), + T.secondary_attack ( secondary_attack ), + T.facing { x = harmer.x, y = harmer.y }, + } + else + wml_actions.animate_unit { + flag = "defend", + hits = true, + with_bars = true, + T.filter { id = unit_to_harm.id }, + T.primary_attack ( primary_attack ), + T.secondary_attack ( secondary_attack ), + } + end + end + + wesnoth.float_label( unit_to_harm.x, unit_to_harm.y, string.format( "%s", text ) ) + + local function calc_xp( level ) -- to calculate the experience in case of kill + if level == 0 then return 4 + else return level * 8 end + end + + if experience ~= false and harmer and harmer.valid and wesnoth.is_enemy( unit_to_harm.side, harmer.side ) then -- no XP earned for harming friendly units + if kill ~= false and unit_to_harm.hitpoints <= 0 then + harmer.experience = harmer.experience + calc_xp( unit_to_harm.__cfg.level ) + else + unit_to_harm.experience = unit_to_harm.experience + harmer.__cfg.level + harmer.experience = harmer.experience + unit_to_harm.__cfg.level + end + end + + if kill ~= false and unit_to_harm.hitpoints <= 0 then + wml_actions.kill { id = unit_to_harm.id, animate = toboolean( animate ), fire_event = fire_event } + end + + if animate then + wesnoth.delay(delay) + end + + if variable then + wesnoth.set_variable(string.format("%s[%d]", variable, index - 1), { harm_amount = damage }) + end + + -- both units may no longer be alive at this point, so double check + if experience ~= false and unit_to_harm and unit_to_harm.valid then + unit_to_harm:advance(toboolean(animate), fire_event ~= false) + end + + if experience ~= false and harmer and harmer.valid then + harmer:advance(toboolean(animate), fire_event ~= false) + end + end + + wml_actions.redraw {} + end + + wesnoth.set_variable ( "this_unit" ) -- clearing this_unit + utils.end_var_scope("this_unit", this_unit) +end \ No newline at end of file diff --git a/data/lua/wml/message.lua b/data/lua/wml/message.lua index 8f5b3629bca9..16c36e51847c 100644 --- a/data/lua/wml/message.lua +++ b/data/lua/wml/message.lua @@ -5,10 +5,7 @@ local location_set = wesnoth.require "lua/location_set.lua" local _ = wesnoth.textdomain "wesnoth" local function log(msg, level) - wesnoth.wml_actions.wml_message({ - message = msg, - logger = level, - }) + wesnoth.log(level, msg, true) end local function get_image(cfg, speaker) @@ -24,6 +21,10 @@ local function get_image(cfg, speaker) image = speaker.portrait end + if image == "none" or image == nil then + return "", true + end + if image:find("~RIGHT%(%)") then left_side = false -- The percent signs escape the parentheses for a literal match @@ -38,10 +39,6 @@ local function get_image(cfg, speaker) image = image:gsub("~LEFT%(%)", "") end - if image == "none" or image == nil then - return "", true - end - return image, left_side end diff --git a/data/lua/wml/modify_unit.lua b/data/lua/wml/modify_unit.lua new file mode 100644 index 000000000000..10766719e23a --- /dev/null +++ b/data/lua/wml/modify_unit.lua @@ -0,0 +1,74 @@ +local helper = wesnoth.require "lua/helper.lua" +local utils = wesnoth.require "lua/wml-utils.lua" +local wml_actions = wesnoth.wml_actions + +function wml_actions.modify_unit(cfg) + local unit_variable = "LUA_modify_unit" + + local function handle_attributes(cfg, unit_path, toplevel) + for current_key, current_value in pairs(helper.shallow_parsed(cfg)) do + if type(current_value) ~= "table" and (not toplevel or current_key ~= "type") then + wesnoth.set_variable(string.format("%s.%s", unit_path, current_key), current_value) + end + end + end + + local function handle_child(cfg, unit_path) + local children_handled = {} + local cfg = helper.shallow_parsed(cfg) + handle_attributes(cfg, unit_path) + + for current_index, current_table in ipairs(cfg) do + local current_tag = current_table[1] + local tag_index = children_handled[current_tag] or 0 + handle_child(current_table[2], string.format("%s.%s[%u]", + unit_path, current_tag, tag_index)) + children_handled[current_tag] = tag_index + 1 + end + end + + local filter = helper.get_child(cfg, "filter") or helper.wml_error "[modify_unit] missing required [filter] tag" + local function handle_unit(unit_num) + local children_handled = {} + local unit_path = string.format("%s[%u]", unit_variable, unit_num) + local this_unit = wesnoth.get_variable(unit_path) + wesnoth.set_variable("this_unit", this_unit) + handle_attributes(cfg, unit_path, true) + + for current_index, current_table in ipairs(helper.shallow_parsed(cfg)) do + local current_tag = current_table[1] + if current_tag == "filter" then + -- nothing + elseif current_tag == "object" or current_tag == "trait" or current_tag == "advancement" then + local unit = wesnoth.get_variable(unit_path) + unit = wesnoth.create_unit(unit) + wesnoth.add_modification(unit, current_tag, current_table[2]) + unit = unit.__cfg; + wesnoth.set_variable(unit_path, unit) + else + local tag_index = children_handled[current_tag] or 0 + handle_child(current_table[2], string.format("%s.%s[%u]", + unit_path, current_tag, tag_index)) + children_handled[current_tag] = tag_index + 1 + end + end + + if cfg.type then + if cfg.type ~= "" then wesnoth.set_variable(unit_path .. ".advances_to", cfg.type) end + wesnoth.set_variable(unit_path .. ".experience", wesnoth.get_variable(unit_path .. ".max_experience")) + end + wml_actions.kill({ id = this_unit.id, animate = false }) + wml_actions.unstore_unit { variable = unit_path } + end + + wml_actions.store_unit { {"filter", filter}, variable = unit_variable } + local max_index = wesnoth.get_variable(unit_variable .. ".length") - 1 + + local this_unit = utils.start_var_scope("this_unit") + for current_unit = 0, max_index do + handle_unit(current_unit) + end + utils.end_var_scope("this_unit", this_unit) + + wesnoth.set_variable(unit_variable) +end \ No newline at end of file diff --git a/data/lua/wml/random_placement.lua b/data/lua/wml/random_placement.lua new file mode 100644 index 000000000000..6f4e1c66642e --- /dev/null +++ b/data/lua/wml/random_placement.lua @@ -0,0 +1,75 @@ +local helper = wesnoth.require "lua/helper.lua" +local utils = wesnoth.require "lua/wml-utils.lua" + +wesnoth.wml_actions.random_placement = function(cfg) + local dist_le = nil + + local parsed = helper.shallow_parsed(cfg) + -- TODO: In most cases this tag is used to place units, so maybe make include_borders=no the default for [filter_location]? + local filter = helper.get_child(parsed, "filter_location") or {} + local command = helper.get_child(parsed, "command") or helper.wml_error("[random_placement] missing required [command] subtag") + local distance = cfg.min_distance or 0 + local num_items = cfg.num_items or helper.wml_error("[random_placement] missing required 'num_items' attribute") + local variable = cfg.variable or helper.wml_error("[random_placement] missing required 'variable' attribute") + local allow_less = cfg.allow_less == true + local variable_previous = utils.start_var_scope(variable) + + if distance < 0 then + -- optimisation for distance = -1 + dist_le = function() return false end + elseif distance == 0 then + -- optimisation for distance = 0 + dist_le = function(x1,y1,x2,y2) return x1 == x2 and y1 == y2 end + else + -- optimisation: cloasure is faster than string lookups. + local math_abs = math.abs + -- same effect as helper.distance_between(x1,y1,x2,y2) <= distance but faster. + dist_le = function(x1,y1,x2,y2) + local d_x = math_abs(x1-x2) + if d_x > distance then + return false + end + if d_x % 2 ~= 0 then + if x1 % 2 == 0 then + y2 = y2 - 0.5 + else + y2 = y2 + 0.5 + end + end + local d_y = math_abs(y1-y2) + return d_x + 2*d_y <= 2*distance + end + end + + local locs = wesnoth.get_locations(filter) + if type(num_items) == "string" then + num_items = math.floor(loadstring("local size = " .. #locs .. "; return " .. num_items)()) + print("num_items=" .. num_items .. ", #locs=" .. #locs) + end + local size = #locs + for i = 1, num_items do + if size == 0 then + if allow_less then + print("placed only " .. i .. " items") + return + else + helper.wml_error("[random_placement] failed to place items. only " .. i .. " items were placed") + end + end + local index = wesnoth.random(size) + local point = locs[index] + wesnoth.set_variable(variable .. ".x", point[1]) + wesnoth.set_variable(variable .. ".y", point[2]) + wesnoth.set_variable(variable .. ".n", i) + for j = size, 1, -1 do + if dist_le(locs[j][1], locs[j][2], point[1], point[2]) then + -- optimisation: swapping elements and storing size in an extra variable is faster than table.remove(locs, j) + locs[j] = locs[size] + size = size - 1 + end + end + wesnoth.wml_actions.command (command) + end + utils.end_var_scope(variable, variable_previous) + +end \ No newline at end of file diff --git a/doc/man/CMakeLists.txt b/doc/man/CMakeLists.txt index 2eb79b622b5e..782f1e57b7e4 100644 --- a/doc/man/CMakeLists.txt +++ b/doc/man/CMakeLists.txt @@ -23,7 +23,7 @@ if(ENABLE_POT_UPDATE_TARGET) COMMAND ${CMAKE_COMMAND} -DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}" -DMANPAGES="${ALL_MANPAGES}" - -P "${CMAKE_MODULE_PATH}/po4a-man.cmake" + -P "${CMAKE_SOURCE_DIR}/cmake/po4a-man.cmake" DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/wesnoth.6 ${CMAKE_CURRENT_SOURCE_DIR}/wesnothd.6 diff --git a/doc/manual/CMakeLists.txt b/doc/manual/CMakeLists.txt index 3179de3ab612..7f193734303d 100644 --- a/doc/manual/CMakeLists.txt +++ b/doc/manual/CMakeLists.txt @@ -83,7 +83,7 @@ if(ENABLE_POT_UPDATE_TARGET) COMMAND ${CMAKE_COMMAND} -DSOURCE="manual.${LINGUA}.xml" -DCMD="${CMD}" - -P "${CMAKE_MODULE_PATH}/po4a-manual.cmake" + -P "${CMAKE_SOURCE_DIR}/cmake/po4a-manual.cmake" COMMAND ${CMAKE_COMMAND} -E remove manual.${LINGUA}.xml DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/manual.${LINGUA}.xml COMMENT "[update-po4a-manual ${LINGUA}] Building ${LINGUA}.html." diff --git a/fonts/Lato-Bold.ttf b/fonts/Lato-Bold.ttf new file mode 100644 index 000000000000..ef5ae3b43e99 Binary files /dev/null and b/fonts/Lato-Bold.ttf differ diff --git a/fonts/Lato-Italic.ttf b/fonts/Lato-Italic.ttf new file mode 100644 index 000000000000..b23256ff5326 Binary files /dev/null and b/fonts/Lato-Italic.ttf differ diff --git a/fonts/Lato-Regular.ttf b/fonts/Lato-Regular.ttf new file mode 100644 index 000000000000..adbfc467d2d0 Binary files /dev/null and b/fonts/Lato-Regular.ttf differ diff --git a/fonts/OFL b/fonts/OFL new file mode 100755 index 000000000000..6d2c4160b08f --- /dev/null +++ b/fonts/OFL @@ -0,0 +1,94 @@ +Copyright (c) 2010-2015, Łukasz Dziedzic (dziedzic@typoland.com), +with Reserved Font Name Lato. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/images/buttons/scrollbars/scrollgroove-bottom-minimal.png b/images/buttons/scrollbars/scrollgroove-bottom-minimal.png deleted file mode 100644 index ff5792c03ce2..000000000000 Binary files a/images/buttons/scrollbars/scrollgroove-bottom-minimal.png and /dev/null differ diff --git a/images/buttons/scrollbars/scrollgroove-mid-minimal.png b/images/buttons/scrollbars/scrollgroove-mid-minimal.png deleted file mode 100644 index 16be9b99050c..000000000000 Binary files a/images/buttons/scrollbars/scrollgroove-mid-minimal.png and /dev/null differ diff --git a/images/buttons/scrollbars/scrollgroove-top-minimal.png b/images/buttons/scrollbars/scrollgroove-top-minimal.png deleted file mode 100644 index 2a79bfadec50..000000000000 Binary files a/images/buttons/scrollbars/scrollgroove-top-minimal.png and /dev/null differ diff --git a/images/buttons/scrollbars/scrollhorizontal-active.png b/images/buttons/scrollbars/scrollhorizontal-active.png index 3dc98f743c18..ca5aefec1808 100644 Binary files a/images/buttons/scrollbars/scrollhorizontal-active.png and b/images/buttons/scrollbars/scrollhorizontal-active.png differ diff --git a/images/buttons/scrollbars/scrollhorizontal-pressed.png b/images/buttons/scrollbars/scrollhorizontal-pressed.png index bfdeeba4764c..2c2e5cca7555 100644 Binary files a/images/buttons/scrollbars/scrollhorizontal-pressed.png and b/images/buttons/scrollbars/scrollhorizontal-pressed.png differ diff --git a/images/buttons/scrollbars/scrollhorizontal.png b/images/buttons/scrollbars/scrollhorizontal.png index a965ddaa56bb..b079d701c73a 100644 Binary files a/images/buttons/scrollbars/scrollhorizontal.png and b/images/buttons/scrollbars/scrollhorizontal.png differ diff --git a/images/buttons/scrollbars/scrollleft-active.png b/images/buttons/scrollbars/scrollleft-active.png index 9b46a81a431e..004ed4a0bb07 100644 Binary files a/images/buttons/scrollbars/scrollleft-active.png and b/images/buttons/scrollbars/scrollleft-active.png differ diff --git a/images/buttons/scrollbars/scrollleft-pressed.png b/images/buttons/scrollbars/scrollleft-pressed.png index e50d2ebd2d19..50f0ede923d3 100644 Binary files a/images/buttons/scrollbars/scrollleft-pressed.png and b/images/buttons/scrollbars/scrollleft-pressed.png differ diff --git a/images/buttons/scrollbars/scrollleft.png b/images/buttons/scrollbars/scrollleft.png index 1b06489af3e5..4b6a097d3d6d 100644 Binary files a/images/buttons/scrollbars/scrollleft.png and b/images/buttons/scrollbars/scrollleft.png differ diff --git a/images/buttons/scrollbars/scrollmid-active.png b/images/buttons/scrollbars/scrollmid-active.png index 0920f4505b1f..893c7b59a1a5 100644 Binary files a/images/buttons/scrollbars/scrollmid-active.png and b/images/buttons/scrollbars/scrollmid-active.png differ diff --git a/images/buttons/scrollbars/scrollmid-pressed.png b/images/buttons/scrollbars/scrollmid-pressed.png index a62272bf0a7c..1b891113040e 100644 Binary files a/images/buttons/scrollbars/scrollmid-pressed.png and b/images/buttons/scrollbars/scrollmid-pressed.png differ diff --git a/images/buttons/scrollbars/scrollmid.png b/images/buttons/scrollbars/scrollmid.png index d1f7bedfdc65..0fd38fb2983e 100644 Binary files a/images/buttons/scrollbars/scrollmid.png and b/images/buttons/scrollbars/scrollmid.png differ diff --git a/images/buttons/scrollbars/scrollright-active.png b/images/buttons/scrollbars/scrollright-active.png index 3da73626448e..48b4f658c421 100644 Binary files a/images/buttons/scrollbars/scrollright-active.png and b/images/buttons/scrollbars/scrollright-active.png differ diff --git a/images/buttons/scrollbars/scrollright-pressed.png b/images/buttons/scrollbars/scrollright-pressed.png index dbd5e343db35..9c919791470c 100644 Binary files a/images/buttons/scrollbars/scrollright-pressed.png and b/images/buttons/scrollbars/scrollright-pressed.png differ diff --git a/images/buttons/scrollbars/scrollright.png b/images/buttons/scrollbars/scrollright.png index 9c71a84f5275..1f275c151826 100644 Binary files a/images/buttons/scrollbars/scrollright.png and b/images/buttons/scrollbars/scrollright.png differ diff --git a/images/buttons/scrollbars_large/scrollbottom-active.png b/images/buttons/scrollbars_large/scrollbottom-active.png new file mode 100644 index 000000000000..77ba8520324d Binary files /dev/null and b/images/buttons/scrollbars_large/scrollbottom-active.png differ diff --git a/images/buttons/scrollbars_large/scrollbottom-pressed.png b/images/buttons/scrollbars_large/scrollbottom-pressed.png new file mode 100644 index 000000000000..e766e3a1015b Binary files /dev/null and b/images/buttons/scrollbars_large/scrollbottom-pressed.png differ diff --git a/images/buttons/scrollbars_large/scrollbottom.png b/images/buttons/scrollbars_large/scrollbottom.png new file mode 100644 index 000000000000..1ad530bd4b08 Binary files /dev/null and b/images/buttons/scrollbars_large/scrollbottom.png differ diff --git a/images/buttons/scrollbars/scrollgroove-bottom.png b/images/buttons/scrollbars_large/scrollgroove-bottom.png similarity index 100% rename from images/buttons/scrollbars/scrollgroove-bottom.png rename to images/buttons/scrollbars_large/scrollgroove-bottom.png diff --git a/images/buttons/scrollbars/scrollgroove-horizontal.png b/images/buttons/scrollbars_large/scrollgroove-horizontal.png similarity index 100% rename from images/buttons/scrollbars/scrollgroove-horizontal.png rename to images/buttons/scrollbars_large/scrollgroove-horizontal.png diff --git a/images/buttons/scrollbars/scrollgroove-left.png b/images/buttons/scrollbars_large/scrollgroove-left.png similarity index 100% rename from images/buttons/scrollbars/scrollgroove-left.png rename to images/buttons/scrollbars_large/scrollgroove-left.png diff --git a/images/buttons/scrollbars/scrollgroove-mid.png b/images/buttons/scrollbars_large/scrollgroove-mid.png similarity index 100% rename from images/buttons/scrollbars/scrollgroove-mid.png rename to images/buttons/scrollbars_large/scrollgroove-mid.png diff --git a/images/buttons/scrollbars/scrollgroove-right.png b/images/buttons/scrollbars_large/scrollgroove-right.png similarity index 100% rename from images/buttons/scrollbars/scrollgroove-right.png rename to images/buttons/scrollbars_large/scrollgroove-right.png diff --git a/images/buttons/scrollbars/scrollgroove-top.png b/images/buttons/scrollbars_large/scrollgroove-top.png similarity index 100% rename from images/buttons/scrollbars/scrollgroove-top.png rename to images/buttons/scrollbars_large/scrollgroove-top.png diff --git a/images/buttons/scrollbars_large/scrollhorizontal-active.png b/images/buttons/scrollbars_large/scrollhorizontal-active.png new file mode 100644 index 000000000000..3dc98f743c18 Binary files /dev/null and b/images/buttons/scrollbars_large/scrollhorizontal-active.png differ diff --git a/images/buttons/scrollbars_large/scrollhorizontal-pressed.png b/images/buttons/scrollbars_large/scrollhorizontal-pressed.png new file mode 100644 index 000000000000..bfdeeba4764c Binary files /dev/null and b/images/buttons/scrollbars_large/scrollhorizontal-pressed.png differ diff --git a/images/buttons/scrollbars_large/scrollhorizontal.png b/images/buttons/scrollbars_large/scrollhorizontal.png new file mode 100644 index 000000000000..a965ddaa56bb Binary files /dev/null and b/images/buttons/scrollbars_large/scrollhorizontal.png differ diff --git a/images/buttons/scrollbars_large/scrollleft-active.png b/images/buttons/scrollbars_large/scrollleft-active.png new file mode 100644 index 000000000000..9b46a81a431e Binary files /dev/null and b/images/buttons/scrollbars_large/scrollleft-active.png differ diff --git a/images/buttons/scrollbars_large/scrollleft-pressed.png b/images/buttons/scrollbars_large/scrollleft-pressed.png new file mode 100644 index 000000000000..e50d2ebd2d19 Binary files /dev/null and b/images/buttons/scrollbars_large/scrollleft-pressed.png differ diff --git a/images/buttons/scrollbars_large/scrollleft.png b/images/buttons/scrollbars_large/scrollleft.png new file mode 100644 index 000000000000..1b06489af3e5 Binary files /dev/null and b/images/buttons/scrollbars_large/scrollleft.png differ diff --git a/images/buttons/scrollbars_large/scrollmid-active.png b/images/buttons/scrollbars_large/scrollmid-active.png new file mode 100644 index 000000000000..000f4f9659ea Binary files /dev/null and b/images/buttons/scrollbars_large/scrollmid-active.png differ diff --git a/images/buttons/scrollbars_large/scrollmid-pressed.png b/images/buttons/scrollbars_large/scrollmid-pressed.png new file mode 100644 index 000000000000..42414e203051 Binary files /dev/null and b/images/buttons/scrollbars_large/scrollmid-pressed.png differ diff --git a/images/buttons/scrollbars_large/scrollmid.png b/images/buttons/scrollbars_large/scrollmid.png new file mode 100644 index 000000000000..407eaf899355 Binary files /dev/null and b/images/buttons/scrollbars_large/scrollmid.png differ diff --git a/images/buttons/scrollbars_large/scrollright-active.png b/images/buttons/scrollbars_large/scrollright-active.png new file mode 100644 index 000000000000..3da73626448e Binary files /dev/null and b/images/buttons/scrollbars_large/scrollright-active.png differ diff --git a/images/buttons/scrollbars_large/scrollright-pressed.png b/images/buttons/scrollbars_large/scrollright-pressed.png new file mode 100644 index 000000000000..dbd5e343db35 Binary files /dev/null and b/images/buttons/scrollbars_large/scrollright-pressed.png differ diff --git a/images/buttons/scrollbars_large/scrollright.png b/images/buttons/scrollbars_large/scrollright.png new file mode 100644 index 000000000000..9c71a84f5275 Binary files /dev/null and b/images/buttons/scrollbars_large/scrollright.png differ diff --git a/images/buttons/scrollbars_large/scrolltop-active.png b/images/buttons/scrollbars_large/scrolltop-active.png new file mode 100644 index 000000000000..961297f7cc10 Binary files /dev/null and b/images/buttons/scrollbars_large/scrolltop-active.png differ diff --git a/images/buttons/scrollbars_large/scrolltop-pressed.png b/images/buttons/scrollbars_large/scrolltop-pressed.png new file mode 100644 index 000000000000..f6ecfa487b02 Binary files /dev/null and b/images/buttons/scrollbars_large/scrolltop-pressed.png differ diff --git a/images/buttons/scrollbars_large/scrolltop.png b/images/buttons/scrollbars_large/scrolltop.png new file mode 100644 index 000000000000..2ea0951b9089 Binary files /dev/null and b/images/buttons/scrollbars_large/scrolltop.png differ diff --git a/images/cursors/attack.png b/images/cursors/attack.png index b59b774b1eed..25fdd7491d7d 100644 Binary files a/images/cursors/attack.png and b/images/cursors/attack.png differ diff --git a/images/cursors/attack_drag.png b/images/cursors/attack_drag.png index 7257f0fa2cca..ffd216632b70 100644 Binary files a/images/cursors/attack_drag.png and b/images/cursors/attack_drag.png differ diff --git a/images/cursors/move.png b/images/cursors/move.png index 14606b12e4ea..7298be968c9f 100644 Binary files a/images/cursors/move.png and b/images/cursors/move.png differ diff --git a/images/cursors/move_drag.png b/images/cursors/move_drag.png index bdd335256f2a..1760d436a818 100644 Binary files a/images/cursors/move_drag.png and b/images/cursors/move_drag.png differ diff --git a/images/cursors/normal.png b/images/cursors/normal.png index d181bbdccf09..45898885ae70 100644 Binary files a/images/cursors/normal.png and b/images/cursors/normal.png differ diff --git a/images/cursors/select-illegal.png b/images/cursors/select-illegal.png index 744357d0ec83..2273edcdb040 100644 Binary files a/images/cursors/select-illegal.png and b/images/cursors/select-illegal.png differ diff --git a/images/cursors/select-location.png b/images/cursors/select-location.png index 3e124ae585b0..aaed99495a43 100644 Binary files a/images/cursors/select-location.png and b/images/cursors/select-location.png differ diff --git a/images/cursors/select.png b/images/cursors/select.png index 91a37b715596..a6c528c4056a 100644 Binary files a/images/cursors/select.png and b/images/cursors/select.png differ diff --git a/images/cursors/wait.png b/images/cursors/wait.png index 31ec10805a35..9c8e8bc653fa 100644 Binary files a/images/cursors/wait.png and b/images/cursors/wait.png differ diff --git a/images/icons/action/trash_25-active.png b/images/icons/action/trash_25-active.png new file mode 100644 index 000000000000..2fd98ec68d4c Binary files /dev/null and b/images/icons/action/trash_25-active.png differ diff --git a/images/icons/action/trash_25-pressed.png b/images/icons/action/trash_25-pressed.png new file mode 100644 index 000000000000..22ca8a21d4d5 Binary files /dev/null and b/images/icons/action/trash_25-pressed.png differ diff --git a/images/icons/action/trash_25.png b/images/icons/action/trash_25.png new file mode 100644 index 000000000000..556c4f258941 Binary files /dev/null and b/images/icons/action/trash_25.png differ diff --git a/images/icons/alignments/alignment_chaotic_30-pressed.png b/images/icons/alignments/alignment_chaotic_30-pressed.png new file mode 100644 index 000000000000..12280c6612b1 Binary files /dev/null and b/images/icons/alignments/alignment_chaotic_30-pressed.png differ diff --git a/images/icons/alignments/alignment_chaotic_30-pressed@2x.png b/images/icons/alignments/alignment_chaotic_30-pressed@2x.png new file mode 100644 index 000000000000..6cdc5d361c13 Binary files /dev/null and b/images/icons/alignments/alignment_chaotic_30-pressed@2x.png differ diff --git a/images/icons/alignments/alignment_chaotic_30.png b/images/icons/alignments/alignment_chaotic_30.png index 19f8d2446a1c..e2df68cc37fa 100644 Binary files a/images/icons/alignments/alignment_chaotic_30.png and b/images/icons/alignments/alignment_chaotic_30.png differ diff --git a/images/icons/alignments/alignment_chaotic_30@2x.png b/images/icons/alignments/alignment_chaotic_30@2x.png new file mode 100644 index 000000000000..92e1837c7347 Binary files /dev/null and b/images/icons/alignments/alignment_chaotic_30@2x.png differ diff --git a/images/icons/alignments/alignment_lawful_30-pressed.png b/images/icons/alignments/alignment_lawful_30-pressed.png new file mode 100644 index 000000000000..27dcd15e2824 Binary files /dev/null and b/images/icons/alignments/alignment_lawful_30-pressed.png differ diff --git a/images/icons/alignments/alignment_lawful_30-pressed@2x.png b/images/icons/alignments/alignment_lawful_30-pressed@2x.png new file mode 100644 index 000000000000..5e3240b87515 Binary files /dev/null and b/images/icons/alignments/alignment_lawful_30-pressed@2x.png differ diff --git a/images/icons/alignments/alignment_lawful_30.png b/images/icons/alignments/alignment_lawful_30.png index d423ef62caee..2fc66fb686c9 100644 Binary files a/images/icons/alignments/alignment_lawful_30.png and b/images/icons/alignments/alignment_lawful_30.png differ diff --git a/images/icons/alignments/alignment_lawful_30@2x.png b/images/icons/alignments/alignment_lawful_30@2x.png new file mode 100644 index 000000000000..200611de6e86 Binary files /dev/null and b/images/icons/alignments/alignment_lawful_30@2x.png differ diff --git a/images/icons/alignments/alignment_liminal_30-pressed.png b/images/icons/alignments/alignment_liminal_30-pressed.png new file mode 100644 index 000000000000..b0d528ced596 Binary files /dev/null and b/images/icons/alignments/alignment_liminal_30-pressed.png differ diff --git a/images/icons/alignments/alignment_liminal_30-pressed@2x.png b/images/icons/alignments/alignment_liminal_30-pressed@2x.png new file mode 100644 index 000000000000..3eb9cf44e71e Binary files /dev/null and b/images/icons/alignments/alignment_liminal_30-pressed@2x.png differ diff --git a/images/icons/alignments/alignment_liminal_30.png b/images/icons/alignments/alignment_liminal_30.png index 752639cf858d..025446c73fad 100644 Binary files a/images/icons/alignments/alignment_liminal_30.png and b/images/icons/alignments/alignment_liminal_30.png differ diff --git a/images/icons/alignments/alignment_liminal_30@2x.png b/images/icons/alignments/alignment_liminal_30@2x.png new file mode 100644 index 000000000000..d943efc8be65 Binary files /dev/null and b/images/icons/alignments/alignment_liminal_30@2x.png differ diff --git a/images/icons/alignments/alignment_neutral_30-pressed.png b/images/icons/alignments/alignment_neutral_30-pressed.png new file mode 100644 index 000000000000..f420db1c1a09 Binary files /dev/null and b/images/icons/alignments/alignment_neutral_30-pressed.png differ diff --git a/images/icons/alignments/alignment_neutral_30-pressed@2x.png b/images/icons/alignments/alignment_neutral_30-pressed@2x.png new file mode 100644 index 000000000000..5372251ff1dc Binary files /dev/null and b/images/icons/alignments/alignment_neutral_30-pressed@2x.png differ diff --git a/images/icons/alignments/alignment_neutral_30.png b/images/icons/alignments/alignment_neutral_30.png index 1a09ed7de928..553b42fa75b2 100644 Binary files a/images/icons/alignments/alignment_neutral_30.png and b/images/icons/alignments/alignment_neutral_30.png differ diff --git a/images/icons/alignments/alignment_neutral_30@2x.png b/images/icons/alignments/alignment_neutral_30@2x.png new file mode 100644 index 000000000000..2b058d998a02 Binary files /dev/null and b/images/icons/alignments/alignment_neutral_30@2x.png differ diff --git a/images/misc/loadscreen_decor.png b/images/misc/loadscreen_decor.png index 0ef7a1423967..2ed96051d069 100644 Binary files a/images/misc/loadscreen_decor.png and b/images/misc/loadscreen_decor.png differ diff --git a/players_changelog b/players_changelog index aa08524aedb4..2633a73a0b44 100644 --- a/players_changelog +++ b/players_changelog @@ -5,6 +5,8 @@ changelog: https://github.com/wesnoth/wesnoth/blob/master/changelog Version 1.13.4+dev: * Language and i18n: * Updated translations: + * Miscellaneous and bug fixes: + * Allow changing keybindings for scrolling the map. Version 1.13.4: * Language and i18n: diff --git a/projectfiles/CodeBlocks/wesnoth.cbp b/projectfiles/CodeBlocks/wesnoth.cbp index 804b86401c12..df0347a4a959 100644 --- a/projectfiles/CodeBlocks/wesnoth.cbp +++ b/projectfiles/CodeBlocks/wesnoth.cbp @@ -894,7 +894,6 @@ - diff --git a/projectfiles/Xcode/Wesnoth.xcodeproj/project.pbxproj b/projectfiles/Xcode/Wesnoth.xcodeproj/project.pbxproj index 3cb749247b6d..3ba884ad8a82 100644 --- a/projectfiles/Xcode/Wesnoth.xcodeproj/project.pbxproj +++ b/projectfiles/Xcode/Wesnoth.xcodeproj/project.pbxproj @@ -1555,6 +1555,7 @@ 912DCA6A1CA6F65A0019A6F9 /* manual.en.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = manual.en.html; path = manual/manual.en.html; sourceTree = ""; }; 9130A45E1C73BB6100852782 /* select_orb_colors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = select_orb_colors.cpp; sourceTree = ""; }; 9130A45F1C73BB6100852782 /* select_orb_colors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = select_orb_colors.hpp; sourceTree = ""; }; + 918056BE1CB1E4C0001A7F35 /* functional.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = functional.hpp; sourceTree = ""; }; 9190B73A1CA0554900B0EF66 /* lua_pathfind_cost_calculator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = lua_pathfind_cost_calculator.hpp; sourceTree = ""; }; 9190B73B1CA0564700B0EF66 /* register_widget.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = register_widget.hpp; sourceTree = ""; }; 919B37F71BAF789D00E0094C /* synced_user_choice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = synced_user_choice.cpp; sourceTree = ""; }; @@ -1699,7 +1700,6 @@ 91E3562D1CACA6E600774252 /* visitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = visitor.cpp; sourceTree = ""; }; 91ECD5D01BA11A5200B25CF1 /* unit_creator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unit_creator.cpp; sourceTree = ""; }; 91ECD5D11BA11A5200B25CF1 /* unit_creator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unit_creator.hpp; sourceTree = ""; }; - 91EF6BFB1C9E22E400E2A733 /* boost_function_guarded.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = boost_function_guarded.hpp; sourceTree = ""; }; 91EF6BFC1C9E22E400E2A733 /* const_clone.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = const_clone.hpp; sourceTree = ""; }; 91EF6BFF1C9E22E400E2A733 /* iterator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = iterator.hpp; sourceTree = ""; }; 91EF6C001C9E22E400E2A733 /* reference_counter.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = reference_counter.hpp; sourceTree = ""; }; @@ -1713,9 +1713,9 @@ 91F462871C7115C50050A9C9 /* combobox.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = combobox.hpp; sourceTree = ""; }; 91F462921C7117400050A9C9 /* drop_down_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = drop_down_list.cpp; sourceTree = ""; }; 91F462931C7117400050A9C9 /* drop_down_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = drop_down_list.hpp; sourceTree = ""; }; - 91FAC70B1C80168600DAB2C3 /* group.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = group.hpp; sourceTree = ""; }; 91FAC7081C7F931900DAB2C3 /* lua_formula_bridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = lua_formula_bridge.hpp; sourceTree = ""; }; 91FAC7091C7FBC2C00DAB2C3 /* lua_formula_bridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_formula_bridge.cpp; sourceTree = ""; }; + 91FAC70B1C80168600DAB2C3 /* group.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = group.hpp; sourceTree = ""; }; B504B94A1284C06B00261FE9 /* tips.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tips.cpp; sourceTree = ""; }; B504B94B1284C06B00261FE9 /* tips.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tips.hpp; sourceTree = ""; }; B508D13E10013BF900B12852 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = lib/Growl.framework; sourceTree = ""; }; @@ -2119,7 +2119,6 @@ B5951A831013BB0800C10B66 /* multiplayer_error_codes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = multiplayer_error_codes.hpp; sourceTree = ""; }; B5951A841013BB0800C10B66 /* resources.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = resources.cpp; sourceTree = ""; }; B5951A851013BB0800C10B66 /* resources.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = resources.hpp; sourceTree = ""; }; - B5951A871013BB0800C10B66 /* savegame_config.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = savegame_config.hpp; sourceTree = ""; }; B5951A931013BB3400C10B66 /* game_delete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = game_delete.cpp; sourceTree = ""; }; B5951A941013BB3400C10B66 /* game_delete.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = game_delete.hpp; sourceTree = ""; }; B5951A971013BB5A00C10B66 /* callable_objects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = callable_objects.cpp; sourceTree = ""; }; @@ -3033,7 +3032,6 @@ ECD39892194B830300CF2125 /* saved_game.hpp */, B52EE8C2121359A600CFBDAB /* savegame.cpp */, B52EE8C3121359A600CFBDAB /* savegame.hpp */, - B5951A871013BB0800C10B66 /* savegame_config.hpp */, B55999B50EC62181008DD061 /* scoped_resource.hpp */, B597EC060FC0832B00CE81F5 /* scripting */, 91B621A61B76A7CD00B00E0F /* sdl */, @@ -3566,8 +3564,8 @@ 91EF6BF01C9E217C00E2A733 /* utils */ = { isa = PBXGroup; children = ( - 91EF6BFB1C9E22E400E2A733 /* boost_function_guarded.hpp */, 91EF6BFC1C9E22E400E2A733 /* const_clone.hpp */, + 918056BE1CB1E4C0001A7F35 /* functional.hpp */, 911F471B1CAE5A7E00F47035 /* iterable_pair.hpp */, 91EF6BFF1C9E22E400E2A733 /* iterator.hpp */, EC53B04D1B23BB0E002F758F /* make_enum.cpp */, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca40fc0c7c48..c61b56db26f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -982,6 +982,7 @@ set(wesnoth-main_SRC units/map.cpp units/types.cpp utils/sha1.cpp + utils/context_free_grammar_generator.cpp variable.cpp variable_info.cpp whiteboard/action.cpp diff --git a/src/SConscript b/src/SConscript index d7bd2b41c1a1..67881dea8587 100644 --- a/src/SConscript +++ b/src/SConscript @@ -556,6 +556,7 @@ wesnoth_sources = Split(""" units/udisplay.cpp units/unit.cpp utils/sha1.cpp + utils/context_free_grammar_generator.cpp variable_info.cpp variable.cpp whiteboard/action.cpp diff --git a/src/actions/undo_action.cpp b/src/actions/undo_action.cpp index eac5b74b7233..89642a0d29ff 100644 --- a/src/actions/undo_action.cpp +++ b/src/actions/undo_action.cpp @@ -2,40 +2,188 @@ #include "scripting/game_lua_kernel.hpp" #include "resources.hpp" #include "variable.hpp" // vconfig -#include "game_events/pump.hpp" //game_events::queued_event +#include "game_data.hpp" +#include "units/unit.hpp" #include +#include +#include namespace actions { + +undo_event::undo_event(const config& cmds, const game_events::queued_event& ctx) + : commands(cmds) + , data(ctx.data) + , loc1(ctx.loc1) + , loc2(ctx.loc2) + , filter_loc1(ctx.loc1.filter_x(), ctx.loc1.filter_y()) + , filter_loc2(ctx.loc2.filter_x(), ctx.loc2.filter_y()) + , uid1(), uid2() +{ + unit_const_ptr u1 = ctx.loc1.get_unit(), u2 = ctx.loc2.get_unit(); + if(u1) { + id1 = u1->id(); + uid1 = u1->underlying_id(); + } + if(u2) { + id2 = u2->id(); + uid2 = u2->underlying_id(); + } +} + +undo_event::undo_event(const config& first, const config& second, const config& weapons, const config& cmds) + : commands(cmds) + , data(weapons) + , loc1(first["x"], first["y"]) + , loc2(second["x"], second["y"]) + , filter_loc1(first["filter_x"], first["filter_y"]) + , filter_loc2(second["filter_x"], second["filter_y"]) + , uid1(first["underlying_id"]) + , uid2(second["underlying_id"]) + , id1(first["id"]) + , id2(second["id"]) +{ +} + +undo_action::undo_action() + : undo_action_base() + , replay_data() + , unit_id_diff(synced_context::get_unit_id_diff()) +{ + auto& undo = synced_context::get_undo_commands(); + auto& redo = synced_context::get_redo_commands(); + auto command_transformer = [](const std::pair& p) { + return undo_event(p.first, p.second); + }; + std::transform(undo.begin(), undo.end(), std::back_inserter(umc_commands_undo), command_transformer); + std::transform(redo.begin(), redo.end(), std::back_inserter(umc_commands_redo), command_transformer); + undo.clear(); + redo.clear(); +} + +undo_action::undo_action(const config& cfg) + : undo_action_base() + , replay_data(cfg.child_or_empty("replay_data")) + , unit_id_diff(cfg["unit_id_diff"]) +{ + read_event_vector(umc_commands_undo, cfg, "undo_actions"); + read_event_vector(umc_commands_redo, cfg, "redo_actions"); +} + +namespace { + unit_ptr get_unit(size_t uid, const std::string& id) { + assert(resources::units); + auto iter = resources::units->find(uid); + if(!iter.valid() || iter->id() != id) { + return nullptr; + } + return iter.get_shared_ptr(); + } + void execute_event(const undo_event& e, std::string tag) { + assert(resources::lua_kernel); + assert(resources::gamedata); + + config::attribute_value& x1 = resources::gamedata->get_variable("x1"); + config::attribute_value& y1 = resources::gamedata->get_variable("y1"); + config::attribute_value& x2 = resources::gamedata->get_variable("x2"); + config::attribute_value& y2 = resources::gamedata->get_variable("y2"); + int oldx1 = x1, oldy1 = y1, oldx2 = x2, oldy2 = y2; + x1 = e.filter_loc1.x + 1; y1 = e.filter_loc1.y + 1; + x2 = e.filter_loc2.x + 1; y2 = e.filter_loc2.y + 1; + + int realx1 = 0, realy1 = 0, realx2 = 0, realy2 = 0; + boost::scoped_ptr u1, u2; + if(unit_ptr who = get_unit(e.uid1, e.id1)) { + realx1 = who->get_location().x; + realy1 = who->get_location().y; + who->set_location(e.loc1); + u1.reset(new scoped_xy_unit("unit", realx1, realy1, *resources::units)); + } + if(unit_ptr who = get_unit(e.uid2, e.id2)) { + realx2 = who->get_location().x; + realy2 = who->get_location().y; + who->set_location(e.loc2); + u2.reset(new scoped_xy_unit("unit", realx2, realy2, *resources::units)); + } + + scoped_weapon_info w1("weapon", e.data.child("first")); + scoped_weapon_info w2("second_weapon", e.data.child("second")); + + game_events::queued_event q(tag, map_location(x1, y1), map_location(x2, y2), e.data); + resources::lua_kernel->run_wml_action("command", vconfig(e.commands), q); + + if(u1) { + unit_ptr who = get_unit(e.uid1, e.id1); + who->set_location(map_location(realx1, realy1)); + } + if(u2) { + unit_ptr who = get_unit(e.uid2, e.id2); + who->set_location(map_location(realx2, realy2)); + } + + x1 = oldx1; y1 = oldy1; + x2 = oldx2; y2 = oldy2; + } +} + void undo_action::execute_undo_umc_wml() { - assert(resources::lua_kernel); - for(const config& c : umc_commands_undo) + for(const undo_event& e : umc_commands_undo) { - resources::lua_kernel->run_wml_action("command", vconfig(c), game_events::queued_event("undo", map_location(), map_location(), config())); + execute_event(e, "undo"); } } void undo_action::execute_redo_umc_wml() { assert(resources::lua_kernel); - for(const config& c : umc_commands_redo) + assert(resources::gamedata); + for(const undo_event& e : umc_commands_redo) { - resources::lua_kernel->run_wml_action("command", vconfig(c), game_events::queued_event("redo", map_location(), map_location(), config())); + execute_event(e, "redo"); } } -void undo_action::read_tconfig_vector(tconfig_vector& vec, const config& cfg, const std::string& tag) +void undo_action::write(config & cfg) const { - config::const_child_itors r = cfg.child_range(tag); - vec.insert(vec.end(), r.first, r.second); + cfg.add_child("replay_data", replay_data); + cfg["unit_id_diff"] = unit_id_diff; + write_event_vector(umc_commands_undo, cfg, "undo_actions"); + write_event_vector(umc_commands_redo, cfg, "redo_actions"); + undo_action_base::write(cfg); } -void undo_action::write_tconfig_vector(const tconfig_vector& vec, config& cfg, const std::string& tag) + +void undo_action::read_event_vector(event_vector& vec, const config& cfg, const std::string& tag) +{ + for(auto c : cfg.child_range(tag)) { + vec.emplace_back(c.child("filter"), c.child("filter_second"), c.child("filter_weapons"), c.child("commands")); + } +} + +void undo_action::write_event_vector(const event_vector& vec, config& cfg, const std::string& tag) { - for(const config& c : vec) + for(const auto& evt : vec) { - cfg.add_child(tag, c); + config& entry = cfg.add_child(tag); + config& first = entry.add_child("filter"); + config& second = entry.add_child("filter_second"); + entry.add_child("filter_weapons", evt.data); + entry.add_child("command", evt.commands); + // First location + first["filter_x"] = evt.filter_loc1.x; + first["filter_y"] = evt.filter_loc1.y; + first["underlying_id"] = evt.uid1; + first["id"] = evt.id1; + first["x"] = evt.loc1.x; + first["y"] = evt.loc1.y; + // Second location + second["filter_x"] = evt.filter_loc2.x; + second["filter_y"] = evt.filter_loc2.y; + second["underlying_id"] = evt.uid2; + second["id"] = evt.id2; + second["x"] = evt.loc2.x; + second["y"] = evt.loc2.y; } } diff --git a/src/actions/undo_action.hpp b/src/actions/undo_action.hpp index 8917bd21b8b3..3021a66ed723 100644 --- a/src/actions/undo_action.hpp +++ b/src/actions/undo_action.hpp @@ -4,14 +4,23 @@ #include "map/location.hpp" #include "units/ptr.hpp" #include "synced_context.hpp" +#include "game_events/pump.hpp" // for queued_event +#include "config.hpp" #include -#include #include + namespace actions { class undo_list; -} -namespace actions { + + struct undo_event { + config commands, data; + map_location loc1, loc2, filter_loc1, filter_loc2; + size_t uid1, uid2; + std::string id1, id2; + undo_event(const config& cmds, const game_events::queued_event& ctx); + undo_event(const config& first, const config& second, const config& weapons, const config& cmds); + }; /// Records information to be able to undo an action. /// Each type of action gets its own derived type. @@ -40,38 +49,13 @@ namespace actions { /// Default constructor. /// It is assumed that undo actions are contructed after the action is performed /// so that the unit id diff does not change after this contructor. - undo_action() - : undo_action_base() - , replay_data() - , unit_id_diff(synced_context::get_unit_id_diff()) - , umc_commands_undo() - , umc_commands_redo() - { - umc_commands_undo.swap(synced_context::get_undo_commands()); - umc_commands_redo.swap(synced_context::get_redo_commands()); - } - undo_action(const config& cfg) - : undo_action_base() - , replay_data(cfg.child_or_empty("replay_data")) - , unit_id_diff(cfg["unit_id_diff"]) - , umc_commands_undo() - , umc_commands_redo() - { - read_tconfig_vector(umc_commands_undo, cfg, "undo_actions"); - read_tconfig_vector(umc_commands_redo, cfg, "redo_actions"); - } + undo_action(); + undo_action(const config& cfg); // Virtual destructor to support derived classes. virtual ~undo_action() {} /// Writes this into the provided config. - virtual void write(config & cfg) const - { - cfg.add_child("replay_data", replay_data); - cfg["unit_id_diff"] = unit_id_diff; - write_tconfig_vector(umc_commands_undo, cfg, "undo_actions"); - write_tconfig_vector(umc_commands_redo, cfg, "redo_actions"); - undo_action_base::write(cfg); - } + virtual void write(config & cfg) const; /// Undoes this action. /// @return true on success; false on an error. @@ -87,14 +71,14 @@ namespace actions { /// TODO: does it really make sense to allow undoing if the unit id counter has changed? int unit_id_diff; /// actions wml (specified by wml) that should be executed when undoing this command. - typedef boost::ptr_vector tconfig_vector; - tconfig_vector umc_commands_undo; - tconfig_vector umc_commands_redo; + typedef std::vector event_vector; + event_vector umc_commands_undo; + event_vector umc_commands_redo; void execute_undo_umc_wml(); void execute_redo_umc_wml(); - static void read_tconfig_vector(tconfig_vector& vec, const config& cfg, const std::string& tag); - static void write_tconfig_vector(const tconfig_vector& vec, config& cfg, const std::string& tag); + static void read_event_vector(event_vector& vec, const config& cfg, const std::string& tag); + static void write_event_vector(const event_vector& vec, config& cfg, const std::string& tag); }; /// entry for player actions that do not need any special code to be performed when undoing such as right-click menu items. diff --git a/src/ai/actions.cpp b/src/ai/actions.cpp index 55fd2a42b459..1c4acb66b50c 100644 --- a/src/ai/actions.cpp +++ b/src/ai/actions.cpp @@ -52,6 +52,7 @@ #include "team.hpp" #include "units/unit.hpp" #include "units/ptr.hpp" +#include "whiteboard/manager.hpp" namespace ai { @@ -286,6 +287,7 @@ void attack_result::do_execute() //FIXME: find a way to 'ask' the ai which advancement should be chosen from synced_commands.cpp . if(!synced_context::is_synced()) //RAII block for set_scontext_synced { + wb::real_map rm; //we don't use synced_context::run_in_synced_context because that wouldn't allow us to pass advancements_ resources::recorder->add_synced_command("attack", replay_helper::get_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(), d_->type_id(), a_->level(), d_->level(), resources::tod_manager->turn(), diff --git a/src/ai/default/recruitment.cpp b/src/ai/default/recruitment.cpp index 3ecd8819fedd..ca9d54257e04 100644 --- a/src/ai/default/recruitment.cpp +++ b/src/ai/default/recruitment.cpp @@ -1786,12 +1786,11 @@ recruitment_aspect::recruitment_aspect(readonly_context &context, const config & parsed_cfg["pattern"] = true; parsed_cfg.add_child("recruit", pattern); } - parsed_cfg.clear_children("pattern"); for (config total : parsed_cfg.child_range("total")) { parsed_cfg["total"] = true; parsed_cfg.add_child("recruit", total); } - parsed_cfg.clear_children("total"); + parsed_cfg.clear_children("pattern", "total"); // Then, if there's no [recruit], add one. if (!parsed_cfg.has_child("recruit")) { parsed_cfg.add_child("recruit", config_of("importance", 0)); diff --git a/src/carryover.cpp b/src/carryover.cpp index 1b3d2f2b20cb..fa4ad1c683d7 100644 --- a/src/carryover.cpp +++ b/src/carryover.cpp @@ -34,11 +34,7 @@ carryover::carryover(const config& side) for(const config& u : side.child_range("unit")) { recall_list_.push_back(u); config& u_back = recall_list_.back(); - u_back.remove_attribute("side"); - u_back.remove_attribute("goto_x"); - u_back.remove_attribute("goto_y"); - u_back.remove_attribute("x"); - u_back.remove_attribute("y"); + u_back.remove_attributes("side", "goto_x", "goto_y", "x", "y"); } } diff --git a/src/config.hpp b/src/config.hpp index 701f6b45fb1b..9fc315c9b3f4 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -450,7 +450,9 @@ class config template config &child(const char(&key)[N], int n = 0) { return child_impl(key, N - 1, n); } +private: config &child_impl(const char* key, int len, int n = 0); +public: #endif /** * Returns the nth child with the given @a key, or @@ -564,6 +566,12 @@ class config void remove_attribute(const std::string &key); void merge_attributes(const config &); + template + void remove_attributes(T... keys) { + for(const std::string& key : {keys...}) { + remove_attribute(key); + } + } const_attr_itors attribute_range() const; @@ -579,6 +587,12 @@ class config { return const_cast(this)->find_child(key, name, value); } void clear_children(const std::string& key); + template + void clear_children(T... keys) { + for(std::string key : {keys...}) { + clear_children(key); + } + } /** * Moves all the children with tag @a key from @a src to this. @@ -660,7 +674,7 @@ class config * A function to get the differences between this object, * and 'c', as another config object. * I.e. calling cfg2.apply_diff(cfg1.get_diff(cfg2)) - * will make cfg1 identical to cfg2. + * will make cfg2 identical to cfg1. */ config get_diff(const config& c) const; void get_diff(const config& c, config& res) const; diff --git a/src/controller_base.cpp b/src/controller_base.cpp index ffe7ec5fb2f3..1a9e03d04e5b 100644 --- a/src/controller_base.cpp +++ b/src/controller_base.cpp @@ -34,6 +34,10 @@ controller_base::controller_base( : game_config_(game_config) , key_() , scrolling_(false) + , scroll_up_(false) + , scroll_down_(false) + , scroll_left_(false) + , scroll_right_(false) , joystick_manager_() { } @@ -61,13 +65,14 @@ void controller_base::handle_event(const SDL_Event& event) process_keydown_event(event); hotkey::key_event(event, get_hotkey_command_executor()); + process_keyup_event(event); } else { process_focus_keydown_event(event); - break; } - // intentionally fall-through + break; case SDL_KEYUP: process_keyup_event(event); + hotkey::key_event(event, get_hotkey_command_executor()); break; case SDL_JOYBUTTONDOWN: process_keydown_event(event); @@ -128,11 +133,10 @@ void controller_base::process_keyup_event(const SDL_Event& /*event*/) { //no action by default } -bool controller_base::handle_scroll(CKey& key, int mousex, int mousey, int mouse_flags, double x_axis, double y_axis) +bool controller_base::handle_scroll(int mousex, int mousey, int mouse_flags, double x_axis, double y_axis) { bool mouse_in_window = (SDL_GetAppState() & SDL_APPMOUSEFOCUS) != 0 || preferences::get("scroll_when_mouse_outside", true); - bool keyboard_focus = have_keyboard_focus(); int scroll_speed = preferences::scroll_speed(); int dx = 0, dy = 0; int scroll_threshold = (preferences::mouse_scroll_enabled()) @@ -142,26 +146,30 @@ bool controller_base::handle_scroll(CKey& key, int mousex, int mousey, int mouse scroll_threshold = 0; } } - if ((key[SDLK_UP] && keyboard_focus) || - (mousey < scroll_threshold && mouse_in_window)) - { - dy -= scroll_speed; - } - if ((key[SDLK_DOWN] && keyboard_focus) || - (mousey > get_display().h() - scroll_threshold && mouse_in_window)) - { - dy += scroll_speed; - } - if ((key[SDLK_LEFT] && keyboard_focus) || - (mousex < scroll_threshold && mouse_in_window)) - { - dx -= scroll_speed; - } - if ((key[SDLK_RIGHT] && keyboard_focus) || - (mousex > get_display().w() - scroll_threshold && mouse_in_window)) - { - dx += scroll_speed; + + // apply keyboard scrolling + dy -= scroll_up_ * scroll_speed; + dy += scroll_down_ * scroll_speed; + dx -= scroll_left_ * scroll_speed; + dx += scroll_right_ * scroll_speed; + + // scroll if mouse is placed near the edge of the screen + if (mouse_in_window) { + if (mousey < scroll_threshold) { + dy -= scroll_speed; + } + if (mousey > get_display().h() - scroll_threshold) { + dy += scroll_speed; + } + if (mousex < scroll_threshold) { + dx -= scroll_speed; + } + if (mousex > get_display().w() - scroll_threshold) { + dx += scroll_speed; + } } + + // scroll with middle-mouse if enabled if ((mouse_flags & SDL_BUTTON_MMASK) != 0 && preferences::middle_click_scrolls()) { const map_location original_loc = get_mouse_handler_base().get_scroll_start(); @@ -185,6 +193,7 @@ bool controller_base::handle_scroll(CKey& key, int mousex, int mousey, int mouse } } + // scroll with joystick dx += round_double( x_axis * scroll_speed); dy += round_double( y_axis * scroll_speed); @@ -238,7 +247,7 @@ void controller_base::play_slice(bool is_delay_enabled) mousey += values.second * 10; SDL_WarpMouse(mousex, mousey); */ - scrolling_ = handle_scroll(key, mousex, mousey, mouse_flags, joystickx, joysticky); + scrolling_ = handle_scroll(mousex, mousey, mouse_flags, joystickx, joysticky); map_location highlighted_hex = get_display().mouseover_hex(); @@ -341,3 +350,23 @@ const config& controller_base::get_theme(const config& game_config, std::string static config empty; return empty; } + +void controller_base::set_scroll_up(bool on) +{ + scroll_up_ = on; +} + +void controller_base::set_scroll_down(bool on) +{ + scroll_down_ = on; +} + +void controller_base::set_scroll_left(bool on) +{ + scroll_left_ = on; +} + +void controller_base::set_scroll_right(bool on) +{ + scroll_right_ = on; +} diff --git a/src/controller_base.hpp b/src/controller_base.hpp index 87df5cfe8a03..8512661ec688 100644 --- a/src/controller_base.hpp +++ b/src/controller_base.hpp @@ -64,6 +64,12 @@ class controller_base : public video2::draw_layering void play_slice(bool is_delay_enabled = true); static const config &get_theme(const config& game_config, std::string theme_name); + + void apply_keyboard_scroll(int x, int y); + void set_scroll_up(bool on); + void set_scroll_down(bool on); + void set_scroll_left(bool on); + void set_scroll_right(bool on); protected: virtual bool is_browsing() const { return false; } @@ -102,10 +108,10 @@ class controller_base : public video2::draw_layering /** * Handle scrolling by keyboard, joystick and moving mouse near map edges - * @see is_keyboard_scroll_active + * @see scrolling_, which is set if the display is being scrolled * @return true when there was any scrolling, false otherwise */ - bool handle_scroll(CKey& key, int mousex, int mousey, int mouse_flags, double joystickx, double joysticky); + bool handle_scroll(int mousex, int mousey, int mouse_flags, double joystickx, double joysticky); /** * Process mouse- and keypress-events from SDL. @@ -141,6 +147,10 @@ class controller_base : public video2::draw_layering const config& game_config_; CKey key_; bool scrolling_; + bool scroll_up_; + bool scroll_down_; + bool scroll_left_; + bool scroll_right_; joystick_manager joystick_manager_; }; diff --git a/src/display.cpp b/src/display.cpp index 8196908faadc..79d8a52a1c7a 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -1300,7 +1300,7 @@ inline display::drawing_buffer_key::drawing_buffer_key(const map_location &loc, SHIFT_Y = BITS_FOR_X_PARITY + SHIFT_X_PARITY, SHIFT_LAYER_GROUP = BITS_FOR_Y + SHIFT_Y }; - BOOST_STATIC_ASSERT(SHIFT_LAYER_GROUP + BITS_FOR_LAYER_GROUP == sizeof(key_) * 8); + static_assert(SHIFT_LAYER_GROUP + BITS_FOR_LAYER_GROUP == sizeof(key_) * 8, "Bit field too small"); // the parity of x must be more significant than the layer but less significant than y. // Thus basically every row is split in two: First the row containing all the odd x diff --git a/src/editor/controller/editor_controller.cpp b/src/editor/controller/editor_controller.cpp index 606501177a59..02210ba648e0 100644 --- a/src/editor/controller/editor_controller.cpp +++ b/src/editor/controller/editor_controller.cpp @@ -86,7 +86,6 @@ editor_controller::editor_controller(const config &game_config, CVideo& video) init_music(game_config); context_manager_->get_map_context().set_starting_position_labels(gui()); cursor::set(cursor::NORMAL); - image::set_color_adjustment(preferences::editor::tod_r(), preferences::editor::tod_g(), preferences::editor::tod_b()); gui().create_buttons(); gui().redraw_everything(); @@ -287,6 +286,10 @@ bool editor_controller::can_execute_command(const hotkey::hotkey_command& cmd, i case HOTKEY_PREFERENCES: case HOTKEY_HELP: case HOTKEY_QUIT_GAME: + case HOTKEY_SCROLL_UP: + case HOTKEY_SCROLL_DOWN: + case HOTKEY_SCROLL_LEFT: + case HOTKEY_SCROLL_RIGHT: return true; //general hotkeys we can always do case hotkey::HOTKEY_UNIT_LIST: @@ -585,12 +588,18 @@ hotkey::ACTION_STATE editor_controller::get_action_state(hotkey::HOTKEY_COMMAND } } -bool editor_controller::execute_command(const hotkey::hotkey_command& cmd, int index) +bool editor_controller::execute_command(const hotkey::hotkey_command& cmd, int index, bool press) { const int zoom_amount = 4; hotkey::HOTKEY_COMMAND command = cmd.id; SCOPE_ED; using namespace hotkey; + + // nothing here handles release; fall through to base implementation + if (!press) { + return hotkey::command_executor::execute_command(cmd, index, press); + } + switch (command) { case HOTKEY_NULL: switch (active_menu_) { @@ -973,7 +982,7 @@ bool editor_controller::execute_command(const hotkey::hotkey_command& cmd, int i gui().invalidate_all(); return true; default: - return hotkey::command_executor::execute_command(cmd, index); + return hotkey::command_executor::execute_command(cmd, index, press); } } @@ -1357,4 +1366,24 @@ hotkey::command_executor * editor_controller::get_hotkey_command_executor() { return this; } +void editor_controller::scroll_up(bool on) +{ + controller_base::set_scroll_up(on); +} + +void editor_controller::scroll_down(bool on) +{ + controller_base::set_scroll_down(on); +} + +void editor_controller::scroll_left(bool on) +{ + controller_base::set_scroll_left(on); +} + +void editor_controller::scroll_right(bool on) +{ + controller_base::set_scroll_right(on); +} + } //end namespace editor diff --git a/src/editor/controller/editor_controller.hpp b/src/editor/controller/editor_controller.hpp index ab4cce2a4a7c..88411d2b5188 100644 --- a/src/editor/controller/editor_controller.hpp +++ b/src/editor/controller/editor_controller.hpp @@ -107,7 +107,7 @@ class editor_controller : public controller_base, hotkey::ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND command, int index) const; /** command_executor override */ - bool execute_command(const hotkey::hotkey_command& command, int index = -1); + bool execute_command(const hotkey::hotkey_command& command, int index = -1, bool press=true); /** controller_base override */ void show_menu(const std::vector& items_arg, int xloc, int yloc, bool context_menu, display& disp); @@ -118,6 +118,12 @@ class editor_controller : public controller_base, /** Show the preferences dialog */ void preferences(); + /** Handle hotkeys to scroll map */ + void scroll_up(bool on); + void scroll_down(bool on); + void scroll_left(bool on); + void scroll_right(bool on); + /** Grid toggle */ void toggle_grid(); diff --git a/src/editor/editor_preferences.cpp b/src/editor/editor_preferences.cpp index 5e53172422b9..33e638cf7be2 100644 --- a/src/editor/editor_preferences.cpp +++ b/src/editor/editor_preferences.cpp @@ -50,51 +50,6 @@ namespace editor { preferences::set("editor_draw_hex_coordinates", value); } - namespace { - void normalize_editor_rgb(int rval) - { - if (rval < -255) { - rval = -255; - } - else if (rval > 255) { - rval = 255; - } - } - } - - void set_tod_r(int value) - { - normalize_editor_rgb(value); - preferences::set("editor_r",std::to_string(value)); - } - - void set_tod_g(int value) - { - normalize_editor_rgb(value); - preferences::set("editor_g",std::to_string(value)); - } - - void set_tod_b(int value) - { - normalize_editor_rgb(value); - preferences::set("editor_b",std::to_string(value)); - } - - int tod_r() - { - return lexical_cast_in_range(preferences::get("editor_r"), 0, -255, 255); - } - - int tod_g() - { - return lexical_cast_in_range(preferences::get("editor_g"), 0, -255, 255); - } - - int tod_b() - { - return lexical_cast_in_range(preferences::get("editor_b"), 0, -255, 255); - } - namespace { size_t editor_mru_limit() { diff --git a/src/editor/editor_preferences.hpp b/src/editor/editor_preferences.hpp index b229aeaa97c9..ae4e97e15c1c 100644 --- a/src/editor/editor_preferences.hpp +++ b/src/editor/editor_preferences.hpp @@ -42,21 +42,6 @@ namespace editor { bool draw_hex_coordinates(); void set_draw_hex_coordinates(bool value); - - /** Set editor red tint level. */ - void set_tod_r(int value); - /** Set editor green tint level. */ - void set_tod_g(int value); - /** Set editor blue tint level. */ - void set_tod_b(int value); - - /** Get editor red tint level. */ - int tod_r(); - /** Get editor green tint level. */ - int tod_g(); - /** Get editor blue tint level. */ - int tod_b(); - /** Retrieves the list of recently opened files. */ std::vector recent_files(); /** Adds an entry to the recent files list. */ diff --git a/src/events.cpp b/src/events.cpp index 1e422d473a38..0917720f3a38 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #define ERR_GEN LOG_STREAM(err, lg::general) @@ -332,9 +333,14 @@ static bool remove_on_resize(const SDL_Event &a) { return false; } - +// TODO: I'm uncertain if this is always safe to call at static init; maybe set in main() instead? +static const boost::thread::id main_thread = boost::this_thread::get_id(); void pump() { + if(boost::this_thread::get_id() != main_thread) { + // Can only call this on the main thread! + return; + } SDL_PumpEvents(); peek_for_resize(); pump_info info; diff --git a/src/formula/callable_objects.cpp b/src/formula/callable_objects.cpp index 83d9bbe3f574..248f22038ab1 100644 --- a/src/formula/callable_objects.cpp +++ b/src/formula/callable_objects.cpp @@ -528,7 +528,7 @@ void config_callable::get_inputs(std::vector* inputs) int config_callable::do_compare(const game_logic::formula_callable* callable) const { const config_callable* cfg_callable = dynamic_cast(callable); - if(cfg_callable == NULL) { + if(cfg_callable == nullptr) { return formula_callable::do_compare(callable); } diff --git a/src/game_classification.cpp b/src/game_classification.cpp index 2f220f93a189..a2aefa411fc2 100644 --- a/src/game_classification.cpp +++ b/src/game_classification.cpp @@ -30,7 +30,6 @@ static lg::log_domain log_engine("engine"); const std::string DEFAULT_DIFFICULTY("NORMAL"); game_classification::game_classification(): - savegame_config(), label(), version(), campaign_type(), @@ -50,7 +49,6 @@ game_classification::game_classification(): {} game_classification::game_classification(const config& cfg): - savegame_config(), label(cfg["label"]), version(cfg["version"]), campaign_type(cfg["campaign_type"].to_enum(game_classification::CAMPAIGN_TYPE::SCENARIO)), @@ -70,7 +68,6 @@ game_classification::game_classification(const config& cfg): {} game_classification::game_classification(const game_classification& gc): - savegame_config(), label(gc.label), version(gc.version), campaign_type(gc.campaign_type), diff --git a/src/game_classification.hpp b/src/game_classification.hpp index 8a8d5cdcb874..6e5522513e63 100644 --- a/src/game_classification.hpp +++ b/src/game_classification.hpp @@ -16,7 +16,7 @@ #define GAME_CLASSIFICATION_HPP_INCLUDED #include "utils/make_enum.hpp" -#include "savegame_config.hpp" + #include class config; @@ -25,7 +25,7 @@ class config; extern const std::string DEFAULT_DIFFICULTY; //meta information of the game -class game_classification : public savegame::savegame_config +class game_classification { public: game_classification(); diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index bc3b9a71227d..5fe11435b452 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -205,71 +205,8 @@ namespace { // Support functions } return path; } - - /** - * Implements the lifting and resetting of fog via WML. - * Keeping affect_normal_fog as false causes only the fog override to be affected. - * Otherwise, fog lifting will be implemented similar to normal sight (cannot be - * individually reset and ends at the end of the turn), and fog resetting will, in - * addition to removing overrides, extend the specified teams' normal fog to all - * hexes. - */ - void toggle_fog(const bool clear, const vconfig& cfg, const bool affect_normal_fog=false) - { - // Filter the sides. - const vconfig &ssf = cfg.child("filter_side"); - const side_filter s_filter(ssf.null() ? vconfig::empty_vconfig() : ssf, resources::filter_con); - const std::vector sides = s_filter.get_teams(); - - // Filter the locations. - std::set locs; - const terrain_filter t_filter(cfg, resources::filter_con); - t_filter.get_locations(locs, true); - - // Loop through sides. - for (const int &side_num : sides) - { - team &t = (*resources::teams)[side_num-1]; - if ( !clear ) - { - // Extend fog. - t.remove_fog_override(locs); - if ( affect_normal_fog ) - t.refog(); - } - else if ( !affect_normal_fog ) - // Force the locations clear of fog. - t.add_fog_override(locs); - else - // Simply clear fog from the locations. - for (const map_location &hex : locs) { - t.clear_fog(hex); - } - } - - // Flag a screen update. - resources::screen->recalculate_minimap(); - resources::screen->invalidate_all(); - } } // end anonymous namespace (support functions) -void handle_deprecated_message(const config& cfg) -{ - // Note: no need to translate the string, since only used for deprecated things. - const std::string& message = cfg["message"]; - lg::wml_error() << message << '\n'; -} - -void handle_wml_log_message(const config& cfg) -{ - const std::string& logger = cfg["logger"]; - const std::string& msg = cfg["message"]; - bool in_chat = cfg["to_chat"].to_bool(true); - - resources::game_events->pump().put_wml_message(logger,msg,in_chat); -} - - /** * Using this constructor for a static object outside action_wml.cpp * will likely lead to a static initialization fiasco. @@ -310,25 +247,20 @@ wml_action::wml_action(const std::string & tag, handler function) * } * \endcode */ -#define WML_HANDLER_FUNCTION(pname, pcfg) \ - static void wml_func_##pname(const vconfig &pcfg); \ +#define WML_HANDLER_FUNCTION(pname, pei, pcfg) \ + static void wml_func_##pname(const queued_event &pei, const vconfig &pcfg); \ static wml_action wml_action_##pname(#pname, &wml_func_##pname); \ - static void wml_func_##pname(const vconfig& pcfg) + static void wml_func_##pname(const queued_event& pei, const vconfig& pcfg) /// Experimental data persistence /// @todo Finish experimenting. -WML_HANDLER_FUNCTION(clear_global_variable,pcfg) +WML_HANDLER_FUNCTION(clear_global_variable,,pcfg) { if (!resources::controller->is_replay()) verify_and_clear_global_variable(pcfg); } -WML_HANDLER_FUNCTION(deprecated_message, cfg) -{ - handle_deprecated_message( cfg.get_parsed_config() ); -} - static void on_replay_error(const std::string& message, bool /*b*/) { ERR_NG << "Error via [do_command]:" << std::endl; @@ -337,7 +269,7 @@ static void on_replay_error(const std::string& message, bool /*b*/) // This tag exposes part of the code path used to handle [command]'s in replays // This allows to perform scripting in WML that will use the same code path as player actions, for example. -WML_HANDLER_FUNCTION(do_command, cfg) +WML_HANDLER_FUNCTION(do_command,, cfg) { // Doing this in a whiteboard applied context will cause bugs // Note that even though game_events::pump() will always apply the real unit map @@ -380,17 +312,12 @@ WML_HANDLER_FUNCTION(do_command, cfg) /// Experimental data persistence /// @todo Finish experimenting. -WML_HANDLER_FUNCTION(get_global_variable, pcfg) +WML_HANDLER_FUNCTION(get_global_variable,,pcfg) { verify_and_get_global_variable(pcfg); } -WML_HANDLER_FUNCTION(lift_fog, cfg) -{ - toggle_fog(true, cfg, !cfg["multiturn"].to_bool(false)); -} - -WML_HANDLER_FUNCTION(modify_turns, cfg) +WML_HANDLER_FUNCTION(modify_turns,, cfg) { config::attribute_value value = cfg["value"]; std::string add = cfg["add"]; @@ -417,7 +344,7 @@ WML_HANDLER_FUNCTION(modify_turns, cfg) /// Moving a 'unit' - i.e. a dummy unit /// that is just moving for the visual effect -WML_HANDLER_FUNCTION(move_unit_fake, cfg) +WML_HANDLER_FUNCTION(move_unit_fake,, cfg) { fake_unit_ptr dummy_unit(create_fake_unit(cfg)); if(!dummy_unit.get()) @@ -438,7 +365,7 @@ WML_HANDLER_FUNCTION(move_unit_fake, cfg) } } -WML_HANDLER_FUNCTION(move_units_fake, cfg) +WML_HANDLER_FUNCTION(move_units_fake,, cfg) { LOG_NG << "Processing [move_units_fake]\n"; @@ -491,7 +418,7 @@ WML_HANDLER_FUNCTION(move_units_fake, cfg) } /// If we should recall units that match a certain description. -WML_HANDLER_FUNCTION(recall, cfg) +WML_HANDLER_FUNCTION(recall,, cfg) { LOG_NG << "recalling unit...\n"; config temp_config(cfg.get_config()); @@ -573,10 +500,6 @@ WML_HANDLER_FUNCTION(recall, cfg) LOG_WML << "A [recall] tag with the following content failed:\n" << cfg.get_config().debug(); } -WML_HANDLER_FUNCTION(remove_sound_source, cfg) -{ - resources::soundsources->remove(cfg["id"]); -} namespace { struct map_choice : public mp_sync::user_choice { @@ -616,9 +539,10 @@ namespace { }; } + /// Experimental map replace /// @todo Finish experimenting. -WML_HANDLER_FUNCTION(replace_map, cfg) +WML_HANDLER_FUNCTION(replace_map,, cfg) { /* * When a hex changes from a village terrain to a non-village terrain, and @@ -676,20 +600,15 @@ WML_HANDLER_FUNCTION(replace_map, cfg) ai::manager::raise_map_changed(); } -WML_HANDLER_FUNCTION(reset_fog, cfg) -{ - toggle_fog(false, cfg, cfg["reset_view"].to_bool(false)); -} - /// Experimental data persistence /// @todo Finish experimenting. -WML_HANDLER_FUNCTION(set_global_variable, pcfg) +WML_HANDLER_FUNCTION(set_global_variable,,pcfg) { if (!resources::controller->is_replay()) verify_and_set_global_variable(pcfg); } -WML_HANDLER_FUNCTION(set_variables, cfg) +WML_HANDLER_FUNCTION(set_variables,, cfg) { const t_string& name = cfg["name"]; variable_access_create dest = resources::gamedata->get_variable_access_write(name); @@ -791,23 +710,10 @@ WML_HANDLER_FUNCTION(set_variables, cfg) } } -WML_HANDLER_FUNCTION(sound_source, cfg) -{ - config parsed = cfg.get_parsed_config(); - try { - soundsource::sourcespec spec(parsed); - resources::soundsources->add(spec); - } catch (bad_lexical_cast &) { - ERR_NG << "Error when parsing sound_source config: bad lexical cast." << std::endl; - ERR_NG << "sound_source config was: " << parsed.debug() << std::endl; - ERR_NG << "Skipping this sound source..." << std::endl; - } -} - /// Store the relative direction from one hex to another in a WML variable. /// This is mainly useful as a diagnostic tool, but could be useful /// for some kind of scenario. -WML_HANDLER_FUNCTION(store_relative_direction, cfg) +WML_HANDLER_FUNCTION(store_relative_direction,, cfg) { if (!cfg.child("source")) { WRN_NG << "No source in [store_relative_direction]" << std::endl; @@ -843,7 +749,7 @@ WML_HANDLER_FUNCTION(store_relative_direction, cfg) /// In increments of 60 degrees, clockwise. /// This is mainly useful as a diagnostic tool, but could be useful /// for some kind of scenario. -WML_HANDLER_FUNCTION(store_rotate_map_location, cfg) +WML_HANDLER_FUNCTION(store_rotate_map_location,, cfg) { if (!cfg.child("source")) { WRN_NG << "No source in [store_rotate_map_location]" << std::endl; @@ -880,7 +786,7 @@ WML_HANDLER_FUNCTION(store_rotate_map_location, cfg) /// Store time of day config in a WML variable. This is useful for those who /// are too lazy to calculate the corresponding time of day for a given turn, /// or if the turn / time-of-day sequence mutates in a scenario. -WML_HANDLER_FUNCTION(store_time_of_day, cfg) +WML_HANDLER_FUNCTION(store_time_of_day,, cfg) { const map_location loc = cfg_to_loc(cfg); int turn = cfg["turn"]; @@ -903,7 +809,7 @@ WML_HANDLER_FUNCTION(store_time_of_day, cfg) } /// Creating a mask of the terrain -WML_HANDLER_FUNCTION(terrain_mask, cfg) +WML_HANDLER_FUNCTION(terrain_mask,, cfg) { map_location loc = cfg_to_loc(cfg, 1, 1); @@ -934,7 +840,7 @@ WML_HANDLER_FUNCTION(terrain_mask, cfg) resources::screen->needs_rebuild(true); } -WML_HANDLER_FUNCTION(tunnel, cfg) +WML_HANDLER_FUNCTION(tunnel,, cfg) { const bool remove = cfg["remove"].to_bool(false); if (remove) { @@ -959,7 +865,7 @@ WML_HANDLER_FUNCTION(tunnel, cfg) } /// If we should spawn a new unit on the map somewhere -WML_HANDLER_FUNCTION(unit, cfg) +WML_HANDLER_FUNCTION(unit,, cfg) { config parsed_cfg = cfg.get_parsed_config(); @@ -1008,7 +914,7 @@ WML_HANDLER_FUNCTION(unit, cfg) } -WML_HANDLER_FUNCTION(volume, cfg) +WML_HANDLER_FUNCTION(volume,, cfg) { int vol; @@ -1036,26 +942,21 @@ WML_HANDLER_FUNCTION(volume, cfg) } -WML_HANDLER_FUNCTION(wml_message, cfg) -{ - handle_wml_log_message( cfg.get_parsed_config() ); -} - -WML_HANDLER_FUNCTION(on_undo, cfg) +WML_HANDLER_FUNCTION(on_undo, event_info, cfg) { if(cfg["delayed_variable_substitution"].to_bool(false)) { - synced_context::add_undo_commands(cfg.get_config()); + synced_context::add_undo_commands(cfg.get_config(), event_info); } else { - synced_context::add_undo_commands(cfg.get_parsed_config()); + synced_context::add_undo_commands(cfg.get_parsed_config(), event_info); } } -WML_HANDLER_FUNCTION(on_redo, cfg) +WML_HANDLER_FUNCTION(on_redo, event_info, cfg) { if(cfg["delayed_variable_substitution"].to_bool(false)) { - synced_context::add_redo_commands(cfg.get_config()); + synced_context::add_redo_commands(cfg.get_config(), event_info); } else { - synced_context::add_redo_commands(cfg.get_parsed_config()); + synced_context::add_redo_commands(cfg.get_parsed_config(), event_info); } } diff --git a/src/game_events/action_wml.hpp b/src/game_events/action_wml.hpp index 2389fd21b7fb..717f3a894fe5 100644 --- a/src/game_events/action_wml.hpp +++ b/src/game_events/action_wml.hpp @@ -48,7 +48,7 @@ namespace game_events class wml_action { public: - typedef void (*handler)(const vconfig &); + typedef void (*handler)(const queued_event &, const vconfig &); typedef std::map map; /// Using this constructor for a static object outside action_wml.cpp @@ -72,11 +72,6 @@ namespace game_events */ void change_terrain(const map_location &loc, const t_translation::t_terrain &t, terrain_type_data::tmerge_mode mode, bool replace_if_failed); - - /** Used for [deprecated_message]. */ - void handle_deprecated_message(const config& cfg); - /** Used for [wml_message]. */ - void handle_wml_log_message(const config& cfg); } #endif // GAME_EVENTS_ACTION_WML_H_INCLUDED diff --git a/src/game_events/entity_location.cpp b/src/game_events/entity_location.cpp index 75f6eed4526c..0a029d63229c 100644 --- a/src/game_events/entity_location.cpp +++ b/src/game_events/entity_location.cpp @@ -104,5 +104,20 @@ bool entity_location::matches_unit_filter(const unit_map::const_iterator & un_it matches_unit(un_it); } +unit_const_ptr entity_location::get_unit() const +{ + if(resources::units == nullptr) { + return nullptr; + } + if(id_ == 0) { + auto un_it = resources::units->find(*this); + if(un_it.valid()) { + return un_it.get_shared_ptr(); + } + return nullptr; + } + return resources::units->find(id_).get_shared_ptr(); +} + } // end namespace game_events diff --git a/src/game_events/entity_location.hpp b/src/game_events/entity_location.hpp index dd6bc6dc3c45..d8d07c5665e1 100644 --- a/src/game_events/entity_location.hpp +++ b/src/game_events/entity_location.hpp @@ -41,6 +41,7 @@ namespace game_events bool matches_unit(const unit_map::const_iterator & un_it) const; bool matches_unit_filter(const unit_map::const_iterator & un_it, const vconfig & filter) const; + unit_const_ptr get_unit() const; static const entity_location null_entity; diff --git a/src/game_initialization/connect_engine.cpp b/src/game_initialization/connect_engine.cpp index cd2819c587b5..0211aca50b89 100644 --- a/src/game_initialization/connect_engine.cpp +++ b/src/game_initialization/connect_engine.cpp @@ -988,11 +988,7 @@ config side_engine::new_config() const // Merge the faction data to res. config faction = flg_.current_faction(); res["faction_name"] = faction["name"]; - faction.remove_attribute("id"); - faction.remove_attribute("name"); - faction.remove_attribute("image"); - faction.remove_attribute("gender"); - faction.remove_attribute("type"); + faction.remove_attributes("id", "name", "image", "gender", "type"); res.append(faction); } diff --git a/src/game_launcher.cpp b/src/game_launcher.cpp index 29e619e91957..8ea22ba01c6e 100644 --- a/src/game_launcher.cpp +++ b/src/game_launcher.cpp @@ -883,14 +883,11 @@ bool game_launcher::play_multiplayer() start_wesnothd(); } catch(game::mp_server_error&) { - std::string path = preferences::show_wesnothd_server_search(video()); - - if (!path.empty()) - { - preferences::set_mp_server_program_name(path); + preferences::show_wesnothd_server_search(video()); + + try { start_wesnothd(); - } - else + } catch(game::mp_server_error&) { return false; } diff --git a/src/gui/auxiliary/field.hpp b/src/gui/auxiliary/field.hpp index 20ef5e5385fd..e7acae114e1a 100644 --- a/src/gui/auxiliary/field.hpp +++ b/src/gui/auxiliary/field.hpp @@ -31,8 +31,6 @@ #include "gui/widgets/window.hpp" #include "wml_exception.hpp" -#include - namespace gui2 { @@ -289,7 +287,7 @@ class tfield : public tfield_ , callback_load_value_(callback_load_value) , callback_save_value_(callback_save_value) { - BOOST_STATIC_ASSERT((!boost::is_same::value)); + static_assert((!boost::is_same::value), "Second template argument cannot be tcontrol"); } /** @@ -313,7 +311,7 @@ class tfield : public tfield_ , callback_load_value_(std::function()) , callback_save_value_(std::function()) { - BOOST_STATIC_ASSERT((!boost::is_same::value)); + static_assert((!boost::is_same::value), "Second template argument cannot be tcontrol"); } /** @@ -340,7 +338,7 @@ class tfield : public tfield_ , callback_load_value_(std::function()) , callback_save_value_(std::function()) { - BOOST_STATIC_ASSERT((boost::is_same::value)); + static_assert((boost::is_same::value), "Second template argument must be tcontrol"); } /** Inherited from tfield_. */ diff --git a/src/gui/auxiliary/formula.hpp b/src/gui/auxiliary/formula.hpp index 9d7a4ef43240..cbe4b9ed47cf 100644 --- a/src/gui/auxiliary/formula.hpp +++ b/src/gui/auxiliary/formula.hpp @@ -24,8 +24,6 @@ #include "util.hpp" #include "tstring.hpp" -#include - #include namespace gui2 @@ -235,7 +233,7 @@ tformula::execute(const game_logic::map_formula_callable& /*variables*/ { // Every type needs its own execute function avoid instantiation of the // default execute. - BOOST_STATIC_ASSERT(sizeof(T) == 0); + static_assert(sizeof(T) == 0, "tformula: Missing execute specialization"); return T(); } diff --git a/src/gui/core/timer.cpp b/src/gui/core/timer.cpp index 97f325e43212..ab31805cf59b 100644 --- a/src/gui/core/timer.cpp +++ b/src/gui/core/timer.cpp @@ -17,8 +17,6 @@ #include "events.hpp" #include "gui/core/log.hpp" -#include - #include #include @@ -115,7 +113,7 @@ size_t add_timer(const Uint32 interval, const std::function& callback, const bool repeat) { - BOOST_STATIC_ASSERT(sizeof(size_t) == sizeof(void*)); + static_assert(sizeof(size_t) == sizeof(void*), "Pointer and size_t are not the same size"); DBG_GUI_E << "Adding timer.\n"; diff --git a/src/gui/dialogs/addon/description.cpp b/src/gui/dialogs/addon/description.cpp index 15792bb740cb..f62282c99382 100644 --- a/src/gui/dialogs/addon/description.cpp +++ b/src/gui/dialogs/addon/description.cpp @@ -31,6 +31,8 @@ #include "utils/functional.hpp" +#include + namespace { std::string format_addon_time(time_t time) diff --git a/src/gui/dialogs/addon/list.cpp b/src/gui/dialogs/addon/list.cpp index e27328ed18a5..269c2df3716b 100644 --- a/src/gui/dialogs/addon/list.cpp +++ b/src/gui/dialogs/addon/list.cpp @@ -52,6 +52,7 @@ #include "utils/functional.hpp" #include +#include namespace gui2 { diff --git a/src/gui/dialogs/campaign_selection.cpp b/src/gui/dialogs/campaign_selection.cpp index 4f4cd1904183..d21d67ca3882 100644 --- a/src/gui/dialogs/campaign_selection.cpp +++ b/src/gui/dialogs/campaign_selection.cpp @@ -37,6 +37,7 @@ #include "serialization/string_utils.hpp" #include "utils/functional.hpp" +#include "video.hpp" namespace gui2 { diff --git a/src/gui/dialogs/editor/custom_tod.cpp b/src/gui/dialogs/editor/custom_tod.cpp index b89bcf5dd22c..e22ef7e1abb0 100644 --- a/src/gui/dialogs/editor/custom_tod.cpp +++ b/src/gui/dialogs/editor/custom_tod.cpp @@ -96,42 +96,32 @@ tcustom_tod::tcustom_tod(editor::editor_display* display, , current_tod_sound_(nullptr) , current_tod_number_(nullptr) , lawful_bonus_field_(register_integer("lawful_bonus", true)) - , tod_red_field_(register_integer("tod_red", - true, - &preferences::editor::tod_r, - &preferences::editor::set_tod_r)) - , tod_green_field_(register_integer("tod_green", - true, - &preferences::editor::tod_g, - &preferences::editor::set_tod_g)) - , tod_blue_field_(register_integer("tod_blue", - true, - &preferences::editor::tod_b, - &preferences::editor::set_tod_b)) + , tod_red_field_(nullptr) + , tod_green_field_(nullptr) + , tod_blue_field_(nullptr) , display_(display) { } void tcustom_tod::select_file(const std::string& filename, - const std::string& dir, - const std::string& vector_attrib, + const std::string& default_dir, + const std::string& attribute, twindow& window) { - std::string va = vector_attrib; std::string fn = filesystem::base_name(filename); std::string dn = filesystem::directory_name(fn); if(dn.empty()) { - dn = dir; + dn = default_dir; } int res = dialogs::show_file_chooser_dialog( display_->video(), dn, _("Choose File")); if(res == 0) { - if(va == "image") { + if(attribute == "image") { tods_[current_tod_].image = dn; - } else if(va == "mask") { + } else if(attribute == "mask") { tods_[current_tod_].image_mask = dn; - } else if(va == "sound") { + } else if(attribute == "sound") { tods_[current_tod_].sounds = dn; } } @@ -171,11 +161,6 @@ void tcustom_tod::do_delete_tod(twindow& window) update_selected_tod_info(window); } -const std::vector& tcustom_tod::do_save_schedule() const -{ - return tods_; -} - const time_of_day& tcustom_tod::get_selected_tod() const { assert(static_cast(current_tod_) < tods_.size()); @@ -184,15 +169,14 @@ const time_of_day& tcustom_tod::get_selected_tod() const void tcustom_tod::update_tod_display(twindow& window) { - image::set_color_adjustment(tod_red_field_->get_widget_value(window), - tod_green_field_->get_widget_value(window), - tod_blue_field_->get_widget_value(window)); + image::set_color_adjustment(tod_red_field_->get_value(), + tod_green_field_->get_value(), + tod_blue_field_->get_value()); if(!display_) { return; } - // Prevent a floating slice of window appearing alone over the // theme UI sidebar after redrawing tiles and before we have a // chance to redraw the rest of this window. @@ -209,6 +193,7 @@ void tcustom_tod::update_tod_display(twindow& window) // invalidate all tiles so they are redrawn with the new ToD tint next display_->invalidate_all(); + // redraw tiles display_->draw(false); @@ -221,11 +206,6 @@ void tcustom_tod::update_lawful_bonus(twindow& window) = lawful_bonus_field_->get_widget_value(window); } -void tcustom_tod::slider_update_callback(twindow& window) -{ - update_tod_display(window); -} - void tcustom_tod::update_selected_tod_info(twindow& window) { current_tod_name_->set_value(get_selected_tod().name); @@ -235,23 +215,31 @@ void tcustom_tod::update_selected_tod_info(twindow& window) current_tod_sound_->set_label(get_selected_tod().sounds); std::stringstream ss; - ss << (current_tod_ + 1); - ss << "/" << tods_.size(); + ss << (current_tod_ + 1) << "/" << tods_.size(); current_tod_number_->set_label(ss.str()); lawful_bonus_field_->set_widget_value(window, get_selected_tod().lawful_bonus); - tod_red_field_->set_widget_value(window, get_selected_tod().color.r); - tod_green_field_->set_widget_value(window, get_selected_tod().color.g); - tod_blue_field_->set_widget_value(window, get_selected_tod().color.b); + tod_red_field_->set_value(get_selected_tod().color.r); + tod_green_field_->set_value(get_selected_tod().color.g); + tod_blue_field_->set_value(get_selected_tod().color.b); update_tod_display(window); - window.invalidate_layout(); } void tcustom_tod::pre_show(twindow& window) { assert(!tods_.empty()); + + tod_red_field_ + = find_widget(&window, "tod_red", false, true); + + tod_green_field_ + = find_widget(&window, "tod_green", false, true); + + tod_blue_field_ + = find_widget(&window, "tod_blue", false, true); + current_tod_name_ = find_widget(&window, "tod_name", false, true); @@ -269,91 +257,75 @@ void tcustom_tod::pre_show(twindow& window) current_tod_number_ = find_widget(&window, "tod_number", false, true); - tbutton& image_button - = find_widget(&window, "image_button", false); - connect_signal_mouse_left_click(image_button, - std::bind(&tcustom_tod::select_file, - this, - get_selected_tod().image, - "data/core/images/misc", - "image", - std::ref(window))); - - tbutton& mask_button = find_widget(&window, "mask_button", false); - ; - connect_signal_mouse_left_click(mask_button, - std::bind(&tcustom_tod::select_file, - this, - get_selected_tod().image_mask, - "data/core/images", - "mask", - std::ref(window))); - - tbutton& sound_button - = find_widget(&window, "sound_button", false); - connect_signal_mouse_left_click(sound_button, - std::bind(&tcustom_tod::select_file, - this, - get_selected_tod().sounds, - "data/core/sounds/ambient", - "sound", - std::ref(window))); - - tbutton& next_tod_button = find_widget(&window, "next_tod", false); + connect_signal_mouse_left_click(find_widget(&window, "image_button", false), + std::bind(&tcustom_tod::select_file, + this, + get_selected_tod().image, + "data/core/images/misc", + "image", + std::ref(window))); + + connect_signal_mouse_left_click(find_widget(&window, "mask_button", false), + std::bind(&tcustom_tod::select_file, + this, + get_selected_tod().image_mask, + "data/core/images", + "mask", + std::ref(window))); + + connect_signal_mouse_left_click(find_widget(&window, "sound_button", false), + std::bind(&tcustom_tod::select_file, + this, + get_selected_tod().sounds, + "data/core/sounds/ambient", + "sound", + std::ref(window))); + connect_signal_mouse_left_click( - next_tod_button, + find_widget(&window, "next_tod", false), std::bind(&tcustom_tod::do_next_tod, this, std::ref(window))); - tbutton& prev_tod_button - = find_widget(&window, "previous_tod", false); connect_signal_mouse_left_click( - prev_tod_button, + find_widget(&window, "previous_tod", false), std::bind(&tcustom_tod::do_prev_tod, this, std::ref(window))); - tbutton& new_button = find_widget(&window, "new", false); connect_signal_mouse_left_click( - new_button, + find_widget(&window, "new", false), std::bind(&tcustom_tod::do_new_tod, this, std::ref(window))); - tbutton& delete_button = find_widget(&window, "delete", false); connect_signal_mouse_left_click( - delete_button, + find_widget(&window, "delete", false), std::bind(&tcustom_tod::do_delete_tod, this, std::ref(window))); - tbutton& save_button = find_widget(&window, "save", false); - connect_signal_mouse_left_click( - save_button, std::bind(&tcustom_tod::do_save_schedule, this)); - connect_signal_notify_modified( *(lawful_bonus_field_->widget()), std::bind(&tcustom_tod::update_lawful_bonus, - this, - std::ref(window))); + this, + std::ref(window))); connect_signal_notify_modified( - *(tod_red_field_->widget()), - std::bind(&tcustom_tod::slider_update_callback, - this, - std::ref(window))); + *tod_red_field_, + std::bind(&tcustom_tod::update_tod_display, + this, + std::ref(window))); connect_signal_notify_modified( - *(tod_green_field_->widget()), - std::bind(&tcustom_tod::slider_update_callback, - this, - std::ref(window))); + *tod_green_field_, + std::bind(&tcustom_tod::update_tod_display, + this, + std::ref(window))); connect_signal_notify_modified( - *(tod_blue_field_->widget()), - std::bind(&tcustom_tod::slider_update_callback, - this, - std::ref(window))); + *tod_blue_field_, + std::bind(&tcustom_tod::update_tod_display, + this, + std::ref(window))); for(size_t i = 0; i < tods_.size(); ++i) { - time_of_day& tod = tods_[i]; - const int r = tod_red_field_->get_widget_value(window); - const int g = tod_green_field_->get_widget_value(window); - const int b = tod_blue_field_->get_widget_value(window); + const int r = tod_red_field_->get_value(); + const int g = tod_green_field_->get_value(); + const int b = tod_blue_field_->get_value(); if(tod.color.r == r && tod.color.g == g && tod.color.b == b) { current_tod_ = i; update_selected_tod_info(window); @@ -367,6 +339,10 @@ void tcustom_tod::pre_show(twindow& window) void tcustom_tod::post_show(twindow& window) { update_tod_display(window); + + if(get_retval() == twindow::OK) { + // TODO: save ToD + } } } // namespace gui2 diff --git a/src/gui/dialogs/editor/custom_tod.hpp b/src/gui/dialogs/editor/custom_tod.hpp index cc186388c2fa..92dfdc7017fe 100644 --- a/src/gui/dialogs/editor/custom_tod.hpp +++ b/src/gui/dialogs/editor/custom_tod.hpp @@ -36,6 +36,7 @@ namespace gui2 class tlabel; class timage; +class tslider; class ttext_box; class tcustom_tod : public tdialog @@ -61,19 +62,16 @@ class tcustom_tod : public tdialog void do_new_tod(twindow& window); void do_delete_tod(twindow& window); - const std::vector& do_save_schedule() const; void select_file(const std::string& filename, - const std::string& dir, - const std::string& vector_attrib, + const std::string& default_dir, + const std::string& attribute, twindow& window); void update_tod_display(twindow& window); void update_lawful_bonus(twindow& window); - void slider_update_callback(twindow& window); - void set_selected_tod(time_of_day tod); const time_of_day& get_selected_tod() const; @@ -104,9 +102,9 @@ class tcustom_tod : public tdialog tlabel* current_tod_number_; tfield_integer* lawful_bonus_field_; - tfield_integer* tod_red_field_; - tfield_integer* tod_green_field_; - tfield_integer* tod_blue_field_; + tslider* tod_red_field_; + tslider* tod_green_field_; + tslider* tod_blue_field_; /** * The display to update when the ToD changes. diff --git a/src/gui/dialogs/game_cache_options.cpp b/src/gui/dialogs/game_cache_options.cpp index dea0b4de04ac..98784dcfcfd5 100644 --- a/src/gui/dialogs/game_cache_options.cpp +++ b/src/gui/dialogs/game_cache_options.cpp @@ -32,6 +32,7 @@ #include "utils/functional.hpp" #include "gettext.hpp" +#include "video.hpp" namespace gui2 { diff --git a/src/gui/dialogs/game_load.cpp b/src/gui/dialogs/game_load.cpp index db5693c7a1a8..122f8d6e9b3d 100644 --- a/src/gui/dialogs/game_load.cpp +++ b/src/gui/dialogs/game_load.cpp @@ -200,7 +200,7 @@ void tgame_load::list_item_clicked(twindow& window) display_savegame(window); } -bool tgame_load::filter_text_changed(ttext_* textbox, const std::string& text) +void tgame_load::filter_text_changed(ttext_* textbox, const std::string& text) { twindow& window = *textbox->get_window(); @@ -209,7 +209,7 @@ bool tgame_load::filter_text_changed(ttext_* textbox, const std::string& text) const std::vector words = utils::split(text, ' '); if(words == last_words_) - return false; + return; last_words_ = words; std::vector show_items(list.get_item_count(), true); @@ -243,8 +243,6 @@ bool tgame_load::filter_text_changed(ttext_* textbox, const std::string& text) } list.set_row_shown(show_items); - - return false; } void tgame_load::post_show(twindow& window) diff --git a/src/gui/dialogs/game_load.hpp b/src/gui/dialogs/game_load.hpp index 8dd3360d5ca0..6efc52358ff2 100644 --- a/src/gui/dialogs/game_load.hpp +++ b/src/gui/dialogs/game_load.hpp @@ -62,7 +62,7 @@ class tgame_load : public tdialog /** Inherited from tdialog, implemented by REGISTER_DIALOG. */ virtual const std::string& window_id() const; - bool filter_text_changed(ttext_* textbox, const std::string& text); + void filter_text_changed(ttext_* textbox, const std::string& text); void list_item_clicked(twindow& window); void delete_button_callback(twindow& window); diff --git a/src/gui/dialogs/gamestate_inspector.cpp b/src/gui/dialogs/gamestate_inspector.cpp index 6eeb828fd2fc..45dc36a7b814 100644 --- a/src/gui/dialogs/gamestate_inspector.cpp +++ b/src/gui/dialogs/gamestate_inspector.cpp @@ -563,8 +563,7 @@ class team_mode_controller : public single_mode_controller config c = resources::teams ? resources::teams->at(side_ - 1).to_config() : config(); - c.clear_children("ai"); - c.clear_children("village"); + c.clear_children("ai", "village"); model_.set_inspect_window_text(config_to_string(c)); return; } diff --git a/src/gui/dialogs/lua_interpreter.cpp b/src/gui/dialogs/lua_interpreter.cpp index 39cb0dbbdc2f..f48fa4b06cc3 100644 --- a/src/gui/dialogs/lua_interpreter.cpp +++ b/src/gui/dialogs/lua_interpreter.cpp @@ -321,7 +321,7 @@ class tlua_interpreter::input_model { #ifdef HAVE_HISTORY // Do history expansions char * cmd_cstr = new char [cmd.length()+1]; - std::strcpy (cmd_cstr, cmd.c_str()); + strcpy (cmd_cstr, cmd.c_str()); char * expansion; diff --git a/src/gui/dialogs/multiplayer/mp_connect.cpp b/src/gui/dialogs/multiplayer/mp_connect.cpp index f646b00c07a8..ea0ec3252c20 100644 --- a/src/gui/dialogs/multiplayer/mp_connect.cpp +++ b/src/gui/dialogs/multiplayer/mp_connect.cpp @@ -28,6 +28,7 @@ #include "gui/widgets/settings.hpp" #include "utils/functional.hpp" +#include "video.hpp" namespace gui2 { diff --git a/src/gui/dialogs/preferences_dialog.cpp b/src/gui/dialogs/preferences_dialog.cpp index e76de3a05b70..e3e5ed3e8e40 100644 --- a/src/gui/dialogs/preferences_dialog.cpp +++ b/src/gui/dialogs/preferences_dialog.cpp @@ -603,7 +603,7 @@ void tpreferences::initialize_members(twindow& window) /* SELECT THEME */ connect_signal_mouse_left_click( find_widget(&window, "choose_theme", false), - std::bind(&show_theme_dialog, + bind_void(&show_theme_dialog, std::ref(window.video()))); @@ -614,22 +614,22 @@ void tpreferences::initialize_members(twindow& window) /* SOUND FX */ setup_toggle_slider_pair("sound_toggle_sfx", "sound_volume_sfx", sound_on(), sound_volume(), - set_sound, set_sound_volume, window); + bind_void(set_sound, _1), set_sound_volume, window); /* MUSIC */ setup_toggle_slider_pair("sound_toggle_music", "sound_volume_music", music_on(), music_volume(), - set_music, set_music_volume, window); + bind_void(set_music, _1), set_music_volume, window); /* TURN BELL */ setup_toggle_slider_pair("sound_toggle_bell", "sound_volume_bell", turn_bell(), bell_volume(), - set_turn_bell, set_bell_volume, window); + bind_void(set_turn_bell, _1), set_bell_volume, window); /* UI FX */ setup_toggle_slider_pair("sound_toggle_uisfx", "sound_volume_uisfx", UI_sound_on(), UI_volume(), - set_UI_sound, set_UI_volume, window); + bind_void(set_UI_sound, _1), set_UI_volume, window); // diff --git a/src/gui/dialogs/screenshot_notification.cpp b/src/gui/dialogs/screenshot_notification.cpp index be50d95a18b6..e470047ee42a 100644 --- a/src/gui/dialogs/screenshot_notification.cpp +++ b/src/gui/dialogs/screenshot_notification.cpp @@ -96,12 +96,12 @@ void tscreenshot_notification::pre_show(twindow& window) tbutton& open_b = find_widget(&window, "open", false); connect_signal_mouse_left_click( - open_b, std::bind(&desktop::open_object, std::ref(path_))); + open_b, bind_void(&desktop::open_object, std::ref(path_))); tbutton& bdir_b = find_widget(&window, "browse_dir", false); connect_signal_mouse_left_click( bdir_b, - std::bind(&desktop::open_object, + bind_void(&desktop::open_object, std::ref(screenshots_dir_path_))); } } diff --git a/src/gui/dialogs/unit_create.cpp b/src/gui/dialogs/unit_create.cpp index a14163947e33..2def34929c97 100644 --- a/src/gui/dialogs/unit_create.cpp +++ b/src/gui/dialogs/unit_create.cpp @@ -226,7 +226,7 @@ void tunit_create::list_item_clicked(twindow& window) .set_displayed_type(units_[selected_row]); } -bool tunit_create::filter_text_changed(ttext_* textbox, const std::string& text) +void tunit_create::filter_text_changed(ttext_* textbox, const std::string& text) { twindow& window = *textbox->get_window(); @@ -235,7 +235,7 @@ bool tunit_create::filter_text_changed(ttext_* textbox, const std::string& text) const std::vector words = utils::split(text, ' '); if(words == last_words_) - return false; + return; last_words_ = words; std::vector show_items(list.get_item_count(), true); @@ -269,8 +269,6 @@ bool tunit_create::filter_text_changed(ttext_* textbox, const std::string& text) } list.set_row_shown(show_items); - - return false; } void tunit_create::gender_toggle_callback(twindow&) diff --git a/src/gui/dialogs/unit_create.hpp b/src/gui/dialogs/unit_create.hpp index a54ef9200db7..da0c27c5547a 100644 --- a/src/gui/dialogs/unit_create.hpp +++ b/src/gui/dialogs/unit_create.hpp @@ -78,7 +78,7 @@ class tunit_create : public tdialog /** Callbacks */ void list_item_clicked(twindow& window); - bool filter_text_changed(ttext_* textbox, const std::string& text); + void filter_text_changed(ttext_* textbox, const std::string& text); void gender_toggle_callback(twindow& window); tgroup gender_toggle; diff --git a/src/hotkey/command_executor.cpp b/src/hotkey/command_executor.cpp index 9f2a735d740f..982937f56dc9 100644 --- a/src/hotkey/command_executor.cpp +++ b/src/hotkey/command_executor.cpp @@ -58,7 +58,7 @@ void make_screenshot(const std::string& name, CVideo& video, const TFunc& func) const std::string ext = ".bmp"; #endif filename = filesystem::get_next_filename(filename, ext); - const bool res = func(filename); + const bool res = func(filename, video); if (res) { gui2::tscreenshot_notification::display(filename, video); } else { @@ -72,9 +72,45 @@ namespace hotkey { static void event_execute(const SDL_Event& event, command_executor* executor); -bool command_executor::execute_command(const hotkey_command& cmd, int /*index*/) +bool command_executor::execute_command(const hotkey_command& cmd, int /*index*/, bool press) { + // hotkey release handling + if (!press) { + switch(cmd.id) { + // release a scroll key, un-apply scrolling in the given direction + case HOTKEY_SCROLL_UP: + scroll_up(false); + break; + case HOTKEY_SCROLL_DOWN: + scroll_down(false); + break; + case HOTKEY_SCROLL_LEFT: + scroll_left(false); + break; + case HOTKEY_SCROLL_RIGHT: + scroll_right(false); + break; + default: + return false; // nothing else handles a hotkey release + } + + return true; + } + + // hotkey press handling switch(cmd.id) { + case HOTKEY_SCROLL_UP: + scroll_up(true); + break; + case HOTKEY_SCROLL_DOWN: + scroll_down(true); + break; + case HOTKEY_SCROLL_LEFT: + scroll_left(true); + break; + case HOTKEY_SCROLL_RIGHT: + scroll_right(true); + break; case HOTKEY_CYCLE_UNITS: cycle_units(); break; @@ -460,6 +496,7 @@ void basic_handler::handle_event(const SDL_Event& event) switch (event.type) { case SDL_KEYDOWN: + case SDL_KEYUP: // If we're in a dialog we only want to handle items that are explicitly // handled by the executor. // If we're not in a dialog we can call the regular key event handler. @@ -470,6 +507,7 @@ void basic_handler::handle_event(const SDL_Event& event) } break; case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: if (!gui::in_dialog()) { jbutton_event(event,exec_); } else if (exec_ != nullptr) { @@ -477,6 +515,7 @@ void basic_handler::handle_event(const SDL_Event& event) } break; case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: if (!gui::in_dialog()) { mbutton_event(event,exec_); } else if (exec_ != nullptr) { @@ -515,18 +554,25 @@ static void event_execute( const SDL_Event& event, command_executor* executor) return; } - execute_command(hotkey::get_hotkey_command(hk->get_command()), executor); + bool press = event.type == SDL_KEYDOWN || event.type == SDL_JOYBUTTONDOWN || event.type == SDL_MOUSEBUTTONDOWN; + + execute_command(hotkey::get_hotkey_command(hk->get_command()), executor, -1, press); executor->set_button_state(); } -void execute_command(const hotkey_command& command, command_executor* executor, int index) +void execute_command(const hotkey_command& command, command_executor* executor, int index, bool press) { if (executor != nullptr) { if (!executor->can_execute_command(command, index) - || executor->execute_command(command, index)) { + || executor->execute_command(command, index, press)) { return; } } + + if (!press) { + return; // none of the commands here respond to a key release + } + switch (command.id) { case HOTKEY_MINIMAP_DRAW_TERRAIN: @@ -553,7 +599,7 @@ void execute_command(const hotkey_command& command, command_executor* executor, executor->get_video().set_fullscreen(!preferences::fullscreen()); break; case HOTKEY_SCREENSHOT: - make_screenshot(_("Screenshot"), executor->get_video(), std::bind(&::screenshot, _1, std::ref(executor->get_video()))); + make_screenshot(_("Screenshot"), executor->get_video(), &::screenshot); break; case HOTKEY_ANIMATE_MAP: preferences::set_animate_map(!preferences::animate_map()); @@ -689,6 +735,6 @@ void command_executor_default::zoom_default() } void command_executor_default::map_screenshot() { - make_screenshot(_("Map-Screenshot"), get_video(), std::bind(&display::screenshot, &get_display(), _1, true)); + make_screenshot(_("Map-Screenshot"), get_video(), boost::bind(&display::screenshot, &get_display(), _1, true)); } } diff --git a/src/hotkey/command_executor.hpp b/src/hotkey/command_executor.hpp index 87257a5f2d33..8582e8ef635d 100644 --- a/src/hotkey/command_executor.hpp +++ b/src/hotkey/command_executor.hpp @@ -108,6 +108,10 @@ class command_executor virtual void left_mouse_click() {} virtual void right_mouse_click() {} virtual void toggle_accelerated_speed() {} + virtual void scroll_up(bool /*on*/) {} + virtual void scroll_down(bool /*on*/) {} + virtual void scroll_left(bool /*on*/) {} + virtual void scroll_right(bool /*on*/) {} virtual void lua_console(); virtual void zoom_in() {} virtual void zoom_out() {} @@ -132,7 +136,7 @@ class command_executor void execute_action(const std::vector& items_arg, int xloc, int yloc, bool context_menu, display& gui); virtual bool can_execute_command(const hotkey_command& command, int index=-1) const = 0; - virtual bool execute_command(const hotkey_command& command, int index=-1); + virtual bool execute_command(const hotkey_command& command, int index=-1, bool press=true); }; class command_executor_default : public command_executor { @@ -162,7 +166,7 @@ void mbutton_event(const SDL_Event& event, command_executor* executor); //TODO -void execute_command(const hotkey_command& command, command_executor* executor, int index=-1); +void execute_command(const hotkey_command& command, command_executor* executor, int index=-1, bool press=true); // Object which will ensure that basic keyboard events like escape // are handled properly for the duration of its lifetime. diff --git a/src/hotkey/hotkey_command.cpp b/src/hotkey/hotkey_command.cpp index 6d1a4f23b93b..0d53957698d6 100644 --- a/src/hotkey/hotkey_command.cpp +++ b/src/hotkey/hotkey_command.cpp @@ -35,6 +35,10 @@ namespace { hotkey::hk_scopes scope_main(1 << hotkey::SCOPE_MAIN_MENU); // this contains all static hotkeys hotkey::hotkey_command_temp hotkey_list_[] = { + { hotkey::HOTKEY_SCROLL_UP, "scroll-up", N_("Scroll Up"), false, scope_game | scope_editor, "" }, + { hotkey::HOTKEY_SCROLL_DOWN, "scroll-down", N_("Scroll Down"), false, scope_game | scope_editor, "" }, + { hotkey::HOTKEY_SCROLL_LEFT, "scroll-left", N_("Scroll Left"), false, scope_game | scope_editor, "" }, + { hotkey::HOTKEY_SCROLL_RIGHT, "scroll-right", N_("Scroll Right"), false, scope_game | scope_editor, "" }, { hotkey::HOTKEY_CANCEL, N_("cancel"), N_("Cancel"), false, scope_game | scope_editor | scope_main, "" }, { hotkey::HOTKEY_SELECT_HEX, "selecthex", N_("Select Hex"), false, scope_game, "" }, diff --git a/src/hotkey/hotkey_command.hpp b/src/hotkey/hotkey_command.hpp index 485a651eb746..d90134702618 100644 --- a/src/hotkey/hotkey_command.hpp +++ b/src/hotkey/hotkey_command.hpp @@ -65,6 +65,9 @@ enum HOTKEY_COMMAND { HOTKEY_SELECT_HEX, HOTKEY_DESELECT_HEX, HOTKEY_MOVE_ACTION, HOTKEY_SELECT_AND_ACTION, + // Camera movement + HOTKEY_SCROLL_UP, HOTKEY_SCROLL_DOWN, HOTKEY_SCROLL_LEFT, HOTKEY_SCROLL_RIGHT, + // Dialog control HOTKEY_CANCEL, HOTKEY_OKAY, diff --git a/src/hotkey/hotkey_handler.cpp b/src/hotkey/hotkey_handler.cpp index 573fc80d1738..689887aa1b34 100644 --- a/src/hotkey/hotkey_handler.cpp +++ b/src/hotkey/hotkey_handler.cpp @@ -218,7 +218,27 @@ void play_controller::hotkey_handler::toggle_accelerated_speed() } } -bool play_controller::hotkey_handler::execute_command(const hotkey::hotkey_command& cmd, int index) +void play_controller::hotkey_handler::scroll_up(bool on) +{ + play_controller_.set_scroll_up(on); +} + +void play_controller::hotkey_handler::scroll_down(bool on) +{ + play_controller_.set_scroll_down(on); +} + +void play_controller::hotkey_handler::scroll_left(bool on) +{ + play_controller_.set_scroll_left(on); +} + +void play_controller::hotkey_handler::scroll_right(bool on) +{ + play_controller_.set_scroll_right(on); +} + +bool play_controller::hotkey_handler::execute_command(const hotkey::hotkey_command& cmd, int index, bool press) { hotkey::HOTKEY_COMMAND command = cmd.id; if(index >= 0) { @@ -245,7 +265,7 @@ bool play_controller::hotkey_handler::execute_command(const hotkey::hotkey_comma gamestate().get_wml_menu_items().fire_item(name, hex, gamestate().gamedata_, gamestate(), gamestate().board_.units_); /// @todo Shouldn't the function return at this point? } - return command_executor::execute_command(cmd, index); + return command_executor::execute_command(cmd, index, press); } bool play_controller::hotkey_handler::can_execute_command(const hotkey::hotkey_command& cmd, int index) const @@ -302,6 +322,10 @@ bool play_controller::hotkey_handler::can_execute_command(const hotkey::hotkey_c case hotkey::HOTKEY_SAVE_REPLAY: case hotkey::HOTKEY_LABEL_SETTINGS: case hotkey::LUA_CONSOLE: + case hotkey::HOTKEY_SCROLL_UP: + case hotkey::HOTKEY_SCROLL_DOWN: + case hotkey::HOTKEY_SCROLL_LEFT: + case hotkey::HOTKEY_SCROLL_RIGHT: return true; // Commands that have some preconditions: diff --git a/src/hotkey/hotkey_handler.hpp b/src/hotkey/hotkey_handler.hpp index 2f6ffb114ccc..f24d8b8bf863 100644 --- a/src/hotkey/hotkey_handler.hpp +++ b/src/hotkey/hotkey_handler.hpp @@ -117,6 +117,10 @@ class play_controller::hotkey_handler : public hotkey::command_executor_default virtual void toggle_grid(); virtual void search(); virtual void toggle_accelerated_speed(); + virtual void scroll_up(bool on); + virtual void scroll_down(bool on); + virtual void scroll_left(bool on); + virtual void scroll_right(bool on); virtual void replay_skip_animation() override { return play_controller_.toggle_skipping_replay(); } @@ -125,7 +129,7 @@ class play_controller::hotkey_handler : public hotkey::command_executor_default virtual hotkey::ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND command, int index) const; /** Check if a command can be executed. */ virtual bool can_execute_command(const hotkey::hotkey_command& command, int index=-1) const; - virtual bool execute_command(const hotkey::hotkey_command& command, int index=-1); + virtual bool execute_command(const hotkey::hotkey_command& command, int index=-1, bool press=true); void show_menu(const std::vector& items_arg, int xloc, int yloc, bool context_menu, display& disp); /** diff --git a/src/mp_game_settings.cpp b/src/mp_game_settings.cpp index 63932a45d7ec..c42781625bad 100644 --- a/src/mp_game_settings.cpp +++ b/src/mp_game_settings.cpp @@ -29,7 +29,6 @@ static lg::log_domain log_engine("engine"); #define DBG_NG LOG_STREAM(debug, log_engine) mp_game_settings::mp_game_settings() : - savegame_config(), name(), password(), hash(), @@ -62,8 +61,7 @@ mp_game_settings::mp_game_settings() : {} mp_game_settings::mp_game_settings(const config& cfg) - : savegame_config() - , name(cfg["scenario"].str()) + : name(cfg["scenario"].str()) , password() , hash(cfg["hash"].str()) , mp_era(cfg["mp_era"].str()) diff --git a/src/mp_game_settings.hpp b/src/mp_game_settings.hpp index 4b6a84cea1d1..ac29c93fc4f9 100644 --- a/src/mp_game_settings.hpp +++ b/src/mp_game_settings.hpp @@ -20,12 +20,11 @@ #include "config.hpp" #include "gettext.hpp" #include "utils/make_enum.hpp" -#include "savegame_config.hpp" #include "version.hpp" #include -struct mp_game_settings : public savegame::savegame_config +struct mp_game_settings { mp_game_settings(); mp_game_settings(const config& cfg); diff --git a/src/pathfind/teleport.hpp b/src/pathfind/teleport.hpp index 1241324a40d5..efca976b85c2 100644 --- a/src/pathfind/teleport.hpp +++ b/src/pathfind/teleport.hpp @@ -16,8 +16,6 @@ #include "config.hpp" #include "map/location.hpp" -#include "savegame_config.hpp" - class team; class unit; @@ -32,7 +30,8 @@ typedef std::pair, std::set > /* * Represents the tunnel wml tag. */ -class teleport_group: public savegame::savegame_config { +class teleport_group +{ public: /* * Constructs the object from a saved file. @@ -141,7 +140,8 @@ class teleport_map { const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all = false, bool ignore_units = false); -class manager: public savegame::savegame_config { +class manager +{ public: manager(const config &cfg); diff --git a/src/play_controller.cpp b/src/play_controller.cpp index d231d0b9b956..58e35c82b3a5 100644 --- a/src/play_controller.cpp +++ b/src/play_controller.cpp @@ -149,7 +149,6 @@ play_controller::play_controller(const config& level, saved_game& state_of_game, CVideo& video, bool skip_replay) : controller_base(game_config, video) , observer() - , savegame_config() , quit_confirmation() , ticks_(SDL_GetTicks()) , tdata_(tdata) diff --git a/src/play_controller.hpp b/src/play_controller.hpp index 1778a834a0bb..894e2373efa1 100644 --- a/src/play_controller.hpp +++ b/src/play_controller.hpp @@ -76,7 +76,7 @@ namespace wb { // Holds gamestate related objects class game_state; -class play_controller : public controller_base, public events::observer, public savegame::savegame_config, quit_confirmation +class play_controller : public controller_base, public events::observer, public quit_confirmation { public: play_controller(const config& level, saved_game& state_of_game, diff --git a/src/preferences_display.cpp b/src/preferences_display.cpp index f40dee5f8999..c1c2fc0c0e97 100644 --- a/src/preferences_display.cpp +++ b/src/preferences_display.cpp @@ -150,7 +150,7 @@ bool show_theme_dialog(CVideo& video) return false; } -std::string show_wesnothd_server_search(CVideo& video) +void show_wesnothd_server_search(CVideo& video) { // Showing file_chooser so user can search the wesnothd std::string old_path = preferences::get_mp_server_program_name(); @@ -192,10 +192,9 @@ std::string show_wesnothd_server_search(CVideo& video) , &symbols); int res = dialogs::show_file_chooser_dialog(video, path, title, false, filename); - if (res == 0) - return path; - else - return ""; + if (res == 0) { + preferences::set_mp_server_program_name(path); + } } } // end namespace preferences diff --git a/src/preferences_display.hpp b/src/preferences_display.hpp index 9ea5c9b9201f..f15294f6c814 100644 --- a/src/preferences_display.hpp +++ b/src/preferences_display.hpp @@ -39,7 +39,7 @@ namespace preferences { void set_idle_anim(bool ison); void set_idle_anim_rate(int rate); - std::string show_wesnothd_server_search(CVideo&); + void show_wesnothd_server_search(CVideo&); void show_preferences_dialog(CVideo& disp, const config& game_cfg, const DIALOG_OPEN_TO initial_view = VIEW_DEFAULT); bool show_theme_dialog(CVideo& disp); diff --git a/src/race.cpp b/src/race.cpp index 5784eaa97fef..bde33dfadab9 100644 --- a/src/race.cpp +++ b/src/race.cpp @@ -191,6 +191,21 @@ unit_race::unit_race(const config& cfg) : name_[FEMALE] = (cfg["name"]); } + if (cfg.has_attribute("male_name_generator")) { + name_generator_[MALE].constructFromString(cfg["male_name_generator"]); + } + if (cfg.has_attribute("female_name_generator")) { + name_generator_[FEMALE].constructFromString(cfg["female_name_generator"]); + } + if (cfg.has_attribute("name_generator")) { + if (!name_generator_[MALE].is_initialized()) { + name_generator_[MALE].constructFromString(cfg["name_generator"]); + } + if (!name_generator_[FEMALE].is_initialized()) { + name_generator_[FEMALE].constructFromString(cfg["name_generator"]); + } + } + if(chain_size_ <= 0) chain_size_ = 2; @@ -202,6 +217,9 @@ unit_race::unit_race(const config& cfg) : std::string unit_race::generate_name( unit_race::GENDER gender) const { + if (name_generator_[gender].is_initialized()) { + return name_generator_[gender].generate(); + } return unicode_cast( markov_generate_name(next_[gender], chain_size_, 12)); } diff --git a/src/race.hpp b/src/race.hpp index b4c9abbebfc3..07b81491d1bc 100644 --- a/src/race.hpp +++ b/src/race.hpp @@ -17,8 +17,7 @@ #include "config.hpp" #include "serialization/unicode_types.hpp" - - +#include "utils/context_free_grammar_generator.hpp" typedef std::map markov_prefix_map; @@ -63,6 +62,7 @@ class unit_race unsigned int ntraits_; markov_prefix_map next_[NUM_GENDERS]; int chain_size_; + context_free_grammar_generator name_generator_[NUM_GENDERS]; config::const_child_itors traits_; config::const_child_itors topics_; diff --git a/src/savegame_config.hpp b/src/savegame_config.hpp deleted file mode 100644 index 08352838cc79..000000000000 --- a/src/savegame_config.hpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - Copyright (C) 2009 - 2016 by Eugen Jiresch - Part of the Battle for Wesnoth Project http://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -#ifndef SAVEGAME_CONFIG_HPP_INCLUDED -#define SAVEGAME_CONFIG_HPP_INCLUDED - -/* interface for building a config from savegame related objects */ -class config; - -namespace savegame { - -class savegame_config -{ -public: - virtual ~savegame_config() {} - virtual config to_config() const = 0; -}; - -} -#endif diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index 0efc286cd5ae..f8230f4b69b7 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -71,7 +71,6 @@ #include "recall_list_manager.hpp" // for recall_list_manager #include "replay.hpp" // for get_user_choice, etc #include "reports.hpp" // for register_generator, etc -#include "resources.hpp" #include "scripting/lua_api.hpp" // for luaW_toboolean, etc #include "scripting/lua_common.hpp" #include "scripting/lua_cpp_function.hpp" @@ -86,6 +85,7 @@ #include "sdl/utils.hpp" // for surface #include "side_filter.hpp" // for side_filter #include "sound.hpp" // for commit_music_changes, etc +#include "soundsource.hpp" #include "synced_context.hpp" // for synced_context, etc #include "synced_user_choice.hpp" #include "team.hpp" // for team, village_owner @@ -122,6 +122,7 @@ #include // for set #include // for operator<<, basic_ostream, etc #include // for pair +#include #include // for vector, etc #include // for SDL_GetTicks #include // for SDL_Color, SDL_Surface @@ -2918,8 +2919,8 @@ int game_lua_kernel::intf_deselect_hex(lua_State*) int game_lua_kernel::intf_is_skipping_messages(lua_State *L) { bool skipping = play_controller_.is_skipping_replay(); - if (!skipping && resources::game_events) { - skipping = resources::game_events->pump().context_skip_messages(); + if (!skipping) { + skipping = game_state_.events_manager_->pump().context_skip_messages(); } lua_pushboolean(L, skipping); return 1; @@ -2935,7 +2936,7 @@ int game_lua_kernel::intf_skip_messages(lua_State *L) if (!lua_isnone(L, 1)) { skip = luaW_toboolean(L, 1); } - resources::game_events->pump().context_skip_messages(skip); + game_state_.events_manager_->pump().context_skip_messages(skip); return 0; } @@ -4047,7 +4048,7 @@ int game_lua_kernel::intf_set_time_of_day(lua_State * L) size_t area_i; if (lua_isstring(L, 2)) { area_id = lua_tostring(L, 1); - std::vector area_ids = resources::tod_manager->get_area_ids(); + std::vector area_ids = tod_man().get_area_ids(); area_i = std::find(area_ids.begin(), area_ids.end(), area_id) - area_ids.begin(); if(area_i >= area_ids.size()) { return luaL_argerror(L, 1, "invalid time area ID"); @@ -4056,8 +4057,8 @@ int game_lua_kernel::intf_set_time_of_day(lua_State * L) int is_num = false; int new_time = lua_tonumberx(L, 1, &is_num) - 1; const std::vector& times = area_id.empty() - ? game_display_->get_tod_man().times() - : game_display_->get_tod_man().times(area_i); + ? tod_man().times() + : tod_man().times(area_i); int num_times = times.size(); if(!is_num) { std::string time_id = luaL_checkstring(L, 1); @@ -4077,9 +4078,9 @@ int game_lua_kernel::intf_set_time_of_day(lua_State * L) } if(area_id.empty()) { - resources::tod_manager->set_current_time(new_time); + tod_man().set_current_time(new_time); } else { - resources::tod_manager->set_current_time(new_time, area_i); + tod_man().set_current_time(new_time, area_i); } return 0; } @@ -4191,11 +4192,11 @@ int game_lua_kernel::intf_teleport(lua_State *L) bool clear_shroud = luaW_toboolean(L, 4); bool animate = luaW_toboolean(L, 5); - if (dst == u->get_location() || !resources::gameboard->map().on_board(dst)) { + if (dst == u->get_location() || !map().on_board(dst)) { return 0; } const map_location vacant_dst = find_vacant_tile(dst, pathfind::VACANT_ANY, check_passability ? u.get() : nullptr); - if (!resources::gameboard->map().on_board(vacant_dst)) { + if (!map().on_board(vacant_dst)) { return 0; } // Clear the destination hex before the move (so the animation can be seen). @@ -4211,10 +4212,10 @@ int game_lua_kernel::intf_teleport(lua_State *L) teleport_path.push_back(vacant_dst); unit_display::move_unit(teleport_path, u, animate); - resources::units->move(src_loc, vacant_dst); + units().move(src_loc, vacant_dst); unit::clear_status_caches(); - u = &*resources::units->find(vacant_dst); + u = &*units().find(vacant_dst); u->anim_comp().set_standing(); if ( clear_shroud ) { @@ -4222,18 +4223,151 @@ int game_lua_kernel::intf_teleport(lua_State *L) clearer.clear_unit(vacant_dst, *u); } - if (resources::gameboard->map().is_village(vacant_dst)) { + if (map().is_village(vacant_dst)) { actions::get_village(vacant_dst, u->side()); } - resources::screen->invalidate_unit_after_move(src_loc, vacant_dst); - resources::screen->draw(); + game_display_->invalidate_unit_after_move(src_loc, vacant_dst); + game_display_->draw(); // Sighted events. clearer.fire_events(); return 0; } +/** + * Removes a sound source by its ID + * Arg 1: sound source ID + */ +int game_lua_kernel::intf_remove_sound_source(lua_State *L) +{ + soundsource::manager* man = play_controller_.get_soundsource_man(); + std::string id = luaL_checkstring(L, 1); + man->remove(id); + return 0; +} + +/** + * Add a new sound source + * Arg 1: Table containing keyword arguments + */ +int game_lua_kernel::intf_add_sound_source(lua_State *L) +{ + soundsource::manager* man = play_controller_.get_soundsource_man(); + config cfg = luaW_checkconfig(L, 1); + try { + soundsource::sourcespec spec(cfg); + man->add(spec); + } catch (bad_lexical_cast &) { + ERR_LUA << "Error when parsing sound_source config: invalid parameter." << std::endl; + ERR_LUA << "sound_source config was: " << cfg.debug() << std::endl; + ERR_LUA << "Skipping this sound source..." << std::endl; + } + return 0; +} + +/** + * Get an existing sound source + * Arg 1: The sound source ID + * Return: Config of sound source info, or nil if it didn't exist + * This is a copy of the sound source info, so you need to call + * add_sound_source again after changing it. + */ +int game_lua_kernel::intf_get_sound_source(lua_State *L) +{ + soundsource::manager* man = play_controller_.get_soundsource_man(); + std::string id = luaL_checkstring(L, 1); + config cfg = man->get(id); + if(cfg.empty()) { + return 0; + } + // Sound sources do not know their own string ID + // Thus, we need to add this manually + cfg["id"] = id; + luaW_pushconfig(L, cfg); + return 1; +} + +/** + * Logs a message + * Arg 1: (optional) Logger; "wml" for WML errors or deprecations + * Arg 2: Message + * Arg 3: Whether to print to chat (always true if arg 1 is "wml") + */ +int game_lua_kernel::intf_log(lua_State *L) +{ + const std::string& logger = lua_isstring(L, 2) ? luaL_checkstring(L, 1) : ""; + const std::string& msg = lua_isstring(L, 2) ? luaL_checkstring(L, 2) : luaL_checkstring(L, 1); + + if(logger == "wml" || logger == "WML") { + lg::wml_error() << msg << '\n'; + } else { + bool in_chat = luaW_toboolean(L, -1); + game_state_.events_manager_->pump().put_wml_message(logger,msg,in_chat); + } + return 0; +} + +/** + * Implements the lifting and resetting of fog via WML. + * Keeping affect_normal_fog as false causes only the fog override to be affected. + * Otherwise, fog lifting will be implemented similar to normal sight (cannot be + * individually reset and ends at the end of the turn), and fog resetting will, in + * addition to removing overrides, extend the specified teams' normal fog to all + * hexes. + * + * Arg 1: (optional) Side number, or list of side numbers + * Arg 2: List of locations; each is a two-element array or a table with x and y keys + * Arg 3: (optional) boolean + */ +int game_lua_kernel::intf_toggle_fog(lua_State *L, const bool clear) +{ + bool affect_normal_fog = false; + if(lua_isboolean(L, -1)) { + affect_normal_fog = luaW_toboolean(L, -1); + } + std::set sides; + if(lua_isnumber(L, 1)) { + sides.insert(lua_tonumber(L, 1)); + } else if(lua_istable(L, 2)) { + const auto& v = lua_check>(L, 1); + sides.insert(v.begin(), v.end()); + } else { + for(const team& t : teams()) { + sides.insert(t.side()+1); + } + } + const auto& v_locs = lua_check>(L, lua_istable(L, 2) ? 2 : 1); + std::set locs(v_locs.begin(), v_locs.end()); + + for(const int &side_num : sides) { + if(side_num < 1 || static_cast(side_num) > teams().size()) { + continue; + } + team &t = teams()[side_num-1]; + if(!clear) { + // Extend fog. + t.remove_fog_override(locs); + if(affect_normal_fog) { + t.refog(); + } + } else if(!affect_normal_fog) { + // Force the locations clear of fog. + t.add_fog_override(locs); + } else { + // Simply clear fog from the locations. + for(const map_location &hex : locs) { + t.clear_fog(hex); + } + } + } + + // Flag a screen update. + game_display_->recalculate_minimap(); + game_display_->invalidate_all(); + return 0; +} + // END CALLBACK IMPLEMENTATION game_board & game_lua_kernel::board() { @@ -4326,8 +4460,10 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle { "unit_resistance", &intf_unit_resistance }, { "unsynced", &intf_do_unsynced }, { "add_event_handler", &dispatch<&game_lua_kernel::intf_add_event > }, + { "add_fog", &dispatch2<&game_lua_kernel::intf_toggle_fog, true > }, { "add_tile_overlay", &dispatch<&game_lua_kernel::intf_add_tile_overlay > }, { "add_time_area", &dispatch<&game_lua_kernel::intf_add_time_area > }, + { "add_sound_source", &dispatch<&game_lua_kernel::intf_add_sound_source > }, { "allow_end_turn", &dispatch<&game_lua_kernel::intf_allow_end_turn > }, { "allow_undo", &dispatch<&game_lua_kernel::intf_allow_undo > }, { "animate_unit", &dispatch<&game_lua_kernel::intf_animate_unit > }, @@ -4355,6 +4491,7 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle { "get_recall_units", &dispatch<&game_lua_kernel::intf_get_recall_units > }, { "get_selected_tile", &dispatch<&game_lua_kernel::intf_get_selected_tile > }, { "get_sides", &dispatch<&game_lua_kernel::intf_get_sides > }, + { "get_sound_source", &dispatch<&game_lua_kernel::intf_get_sound_source > }, { "get_starting_location", &dispatch<&game_lua_kernel::intf_get_starting_location > }, { "get_terrain", &dispatch<&game_lua_kernel::intf_get_terrain > }, { "get_terrain_info", &dispatch<&game_lua_kernel::intf_get_terrain_info > }, @@ -4372,6 +4509,7 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle { "kill", &dispatch<&game_lua_kernel::intf_kill > }, { "label", &dispatch<&game_lua_kernel::intf_label > }, { "lock_view", &dispatch<&game_lua_kernel::intf_lock_view > }, + { "log", &dispatch<&game_lua_kernel::intf_log > }, { "match_location", &dispatch<&game_lua_kernel::intf_match_location > }, { "match_side", &dispatch<&game_lua_kernel::intf_match_side > }, { "match_unit", &dispatch<&game_lua_kernel::intf_match_unit > }, @@ -4386,8 +4524,10 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle { "random", &dispatch<&game_lua_kernel::intf_random > }, { "redraw", &dispatch<&game_lua_kernel::intf_redraw > }, { "remove_event_handler", &dispatch<&game_lua_kernel::intf_remove_event > }, + { "remove_fog", &dispatch2<&game_lua_kernel::intf_toggle_fog, false > }, { "remove_tile_overlay", &dispatch<&game_lua_kernel::intf_remove_tile_overlay > }, { "remove_time_area", &dispatch<&game_lua_kernel::intf_remove_time_area > }, + { "remove_sound_source", &dispatch<&game_lua_kernel::intf_remove_sound_source > }, { "replace_schedule", &dispatch<&game_lua_kernel::intf_replace_schedule > }, { "scroll", &dispatch<&game_lua_kernel::intf_scroll > }, { "scroll_to_tile", &dispatch<&game_lua_kernel::intf_scroll_to_tile > }, @@ -4865,7 +5005,7 @@ int game_lua_kernel::cfun_wml_action(lua_State *L) (lua_touserdata(L, lua_upvalueindex(1))); vconfig vcfg = luaW_checkvconfig(L, 1); - h(vcfg); + h(get_event_info(), vcfg); return 0; } diff --git a/src/scripting/game_lua_kernel.hpp b/src/scripting/game_lua_kernel.hpp index 8d13b1a124ca..ebf599e5af91 100644 --- a/src/scripting/game_lua_kernel.hpp +++ b/src/scripting/game_lua_kernel.hpp @@ -164,6 +164,11 @@ class game_lua_kernel : public lua_kernel_base int intf_fire_event(lua_State *L); int intf_fire_wml_menu_item(lua_State *L); int intf_teleport(lua_State *L); + int intf_remove_sound_source(lua_State *L); + int intf_add_sound_source(lua_State *L); + int intf_get_sound_source(lua_State *L); + int intf_log(lua_State *L); + int intf_toggle_fog(lua_State *L, const bool clear); //private helpers std::string synced_state(); diff --git a/src/scripting/lua_formula_bridge.cpp b/src/scripting/lua_formula_bridge.cpp index 477570399132..409cd9961210 100644 --- a/src/scripting/lua_formula_bridge.cpp +++ b/src/scripting/lua_formula_bridge.cpp @@ -77,7 +77,7 @@ class lua_callable : public formula_callable { } int do_compare(const formula_callable* other) const { const lua_callable* lua = dynamic_cast(other); - if(lua == NULL) { + if(lua == nullptr) { return formula_callable::do_compare(other); } if(mState == lua->mState) { // Which should always be the case, but let's be safe here diff --git a/src/scripting/lua_formula_bridge.hpp b/src/scripting/lua_formula_bridge.hpp index f64b7f434b38..7fb4774dd986 100644 --- a/src/scripting/lua_formula_bridge.hpp +++ b/src/scripting/lua_formula_bridge.hpp @@ -36,9 +36,9 @@ namespace lua_formula_bridge { class fwrapper { boost::shared_ptr formula_ptr; public: - fwrapper(const std::string& code, game_logic::function_symbol_table* functions = NULL); + fwrapper(const std::string& code, game_logic::function_symbol_table* functions = nullptr); std::string str() const; - variant evaluate(const game_logic::formula_callable& variables, game_logic::formula_debugger* fdb = NULL) const; + variant evaluate(const game_logic::formula_callable& variables, game_logic::formula_debugger* fdb = nullptr) const; }; } // end namespace lua_formula_bridge diff --git a/src/serialization/unicode.hpp b/src/serialization/unicode.hpp index c02b75a55b94..cb024d7e8b7a 100644 --- a/src/serialization/unicode.hpp +++ b/src/serialization/unicode.hpp @@ -21,7 +21,6 @@ #include "ucs4_convert_impl.hpp" #include "unicode_cast.hpp" -#include #include #include diff --git a/src/server/server.cpp b/src/server/server.cpp index 86030c5c1dc8..802ec74231dd 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -1295,7 +1295,7 @@ void server::process_query(const network::connection sock, // Commands a player may issue. if (command == "status") { response << process_command(command + " " + pl->second.name(), pl->second.name()); - } else if (command.find("adminmsg") == 0 + } else if (command.find("adminmsg") == 0 || command.find("report") == 0 || command == "games" || command == "metrics" || command == "motd" diff --git a/src/soundsource.cpp b/src/soundsource.cpp index d3d3e08ac44f..64f42783bffd 100644 --- a/src/soundsource.cpp +++ b/src/soundsource.cpp @@ -32,7 +32,6 @@ unsigned int positional_source::last_id = 0; manager::manager(const display &disp) : observer(), - savegame_config(), sources_(), disp_(disp) { @@ -67,6 +66,16 @@ void manager::add(const sourcespec &spec) } } +config manager::get(const std::string &id) +{ + config cfg; + positional_source_iterator it = sources_.find(id); + if(it != sources_.end()) { + it->second->write_config(cfg); + } + return cfg; +} + void manager::remove(const std::string &id) { positional_source_iterator it; @@ -108,13 +117,6 @@ void manager::write_sourcespecs(config& cfg) const } } -config manager::to_config() const -{ - config cfg; - write_sourcespecs(cfg); - return cfg.child("sound_source"); -} - positional_source::positional_source(const sourcespec &spec) : last_played_(0), min_delay_(spec.minimum_delay()), diff --git a/src/soundsource.hpp b/src/soundsource.hpp index 4127104d14b4..481f88aa3b5f 100644 --- a/src/soundsource.hpp +++ b/src/soundsource.hpp @@ -18,7 +18,6 @@ #include "generic_event.hpp" #include "map/location.hpp" -#include "savegame_config.hpp" class config; class display; @@ -74,7 +73,8 @@ class positional_source { void write_config(config& cfg) const; }; -class manager : public events::observer, public savegame::savegame_config { +class manager : public events::observer +{ typedef std::map positional_source_map; typedef positional_source_map::iterator positional_source_iterator; @@ -93,6 +93,7 @@ class manager : public events::observer, public savegame::savegame_config { // add or replace a soundsource void add(const sourcespec &source); void remove(const std::string &id); + config get(const std::string &id); void update(); // checks which sound sources are visible @@ -103,8 +104,6 @@ class manager : public events::observer, public savegame::savegame_config { * "sound_source", appended to existing content. */ void write_sourcespecs(config& cfg) const; - - config to_config() const; }; /** diff --git a/src/storyscreen/controller.cpp b/src/storyscreen/controller.cpp index 49bb615e0c63..56b88bbf815b 100644 --- a/src/storyscreen/controller.cpp +++ b/src/storyscreen/controller.cpp @@ -26,8 +26,9 @@ #include "asserts.hpp" #include "variable.hpp" -#include "game_events/action_wml.hpp" #include "game_events/conditional_wml.hpp" +#include "game_events/manager.hpp" +#include "game_events/pump.hpp" #include "game_data.hpp" #include "gettext.hpp" #include "intro.hpp" @@ -129,13 +130,13 @@ void controller::resolve_wml(const vconfig& cfg) // [deprecated_message] else if(key == "deprecated_message") { // Won't appear until the scenario start event finishes. - game_events::handle_deprecated_message(node.get_parsed_config()); + lg::wml_error() << node["message"] << '\n'; } // [wml_message] else if(key == "wml_message") { - // Pass to game events handler. As with [deprecated_message], + // As with [deprecated_message], // it won't appear until the scenario start event is complete. - game_events::handle_wml_log_message(node.get_parsed_config()); + resources::game_events->pump().put_wml_message(node["logger"],node["message"],node["in_chat"]); } } } diff --git a/src/storyscreen/part.cpp b/src/storyscreen/part.cpp index ce292bacb85a..6dc4c974dc34 100644 --- a/src/storyscreen/part.cpp +++ b/src/storyscreen/part.cpp @@ -25,8 +25,9 @@ #include "config.hpp" #include "game_data.hpp" -#include "game_events/action_wml.hpp" #include "game_events/conditional_wml.hpp" +#include "game_events/manager.hpp" +#include "game_events/pump.hpp" #include "image.hpp" #include "serialization/string_utils.hpp" #include "util.hpp" @@ -349,13 +350,13 @@ void part::resolve_wml(const vconfig &cfg) // [deprecated_message] else if(key == "deprecated_message") { // Won't appear until the scenario start event finishes. - game_events::handle_deprecated_message(node.get_parsed_config()); + lg::wml_error() << node["message"] << '\n'; } // [wml_message] else if(key == "wml_message") { - // Pass to game events handler. As with [deprecated_message], + // As with [deprecated_message], // it won't appear until the scenario start event is complete. - game_events::handle_wml_log_message(node.get_parsed_config()); + resources::game_events->pump().put_wml_message(node["logger"],node["message"],node["in_chat"]); } } } diff --git a/src/synced_context.cpp b/src/synced_context.cpp index 0640d399d7ed..5b8a1e341a9c 100644 --- a/src/synced_context.cpp +++ b/src/synced_context.cpp @@ -53,8 +53,8 @@ static lg::log_domain log_replay("replay"); synced_context::synced_state synced_context::state_ = synced_context::UNSYNCED; int synced_context::last_unit_id_ = 0; -synced_context::tconfig_vector synced_context::undo_commands_ = synced_context::tconfig_vector(); -synced_context::tconfig_vector synced_context::redo_commands_ = synced_context::tconfig_vector(); +synced_context::event_list synced_context::undo_commands_; +synced_context::event_list synced_context::redo_commands_; bool synced_context::is_simultaneously_ = false; bool synced_context::run(const std::string& commandname, const config& data, bool use_undo, bool show, synced_command::error_handler_function error_handler) @@ -383,14 +383,24 @@ config synced_context::ask_server_choice(const server_choice& sch) } } -void synced_context::add_undo_commands(const config& commands) +void synced_context::add_undo_commands(const config& commands, const game_events::queued_event& ctx) { - undo_commands_.insert(undo_commands_.begin(), new config(commands)); + undo_commands_.emplace_front(commands, ctx); } -void synced_context::add_redo_commands(const config& commands) +void synced_context::add_redo_commands(const config& commands, const game_events::queued_event& ctx) { - redo_commands_.insert(redo_commands_.begin(), new config(commands)); + redo_commands_.emplace_front(commands, ctx); +} + +void synced_context::reset_undo_commands() +{ + undo_commands_.clear(); +} + +void synced_context::reset_redo_commands() +{ + redo_commands_.clear(); } set_scontext_synced_base::set_scontext_synced_base() diff --git a/src/synced_context.hpp b/src/synced_context.hpp index 5d23922d3208..e3c9cf56e2c3 100644 --- a/src/synced_context.hpp +++ b/src/synced_context.hpp @@ -20,11 +20,12 @@ #include "replay.hpp" #include "random_new.hpp" #include "random_new_synced.hpp" +#include "game_events/pump.hpp" // for queued_event #include "generic_event.hpp" #include "mouse_handler_base.hpp" #include #include -#include +#include class config; @@ -147,13 +148,13 @@ class synced_context */ static config ask_server_choice(const server_choice&); - typedef boost::ptr_vector tconfig_vector; - static tconfig_vector& get_undo_commands() { return undo_commands_; } - static tconfig_vector& get_redo_commands() { return redo_commands_; } - static void add_undo_commands(const config& commands); - static void add_redo_commands(const config& commands); - static void reset_undo_commands() { undo_commands_ = tconfig_vector(); } - static void reset_redo_commands() { redo_commands_ = tconfig_vector(); } + typedef std::deque> event_list; + static event_list& get_undo_commands() { return undo_commands_; } + static event_list& get_redo_commands() { return redo_commands_; } + static void add_undo_commands(const config& commands, const game_events::queued_event& ctx); + static void add_redo_commands(const config& commands, const game_events::queued_event& ctx); + static void reset_undo_commands(); + static void reset_redo_commands(); private: /* weather we are in a synced move, in a user_choice, or none of them @@ -175,11 +176,11 @@ class synced_context /** Actions wml to be executed when the current actio is undone. */ - static tconfig_vector undo_commands_; + static event_list undo_commands_; /** Actions wml to be executed when the current actio is redone. */ - static tconfig_vector redo_commands_; + static event_list redo_commands_; }; diff --git a/src/team.cpp b/src/team.cpp index db094951ba06..b48339ccb68b 100644 --- a/src/team.cpp +++ b/src/team.cpp @@ -276,7 +276,6 @@ void team::team_info::write(config& cfg) const } team::team() : - savegame_config(), gold_(0), villages_(), shroud_(), diff --git a/src/team.hpp b/src/team.hpp index c7d2e76572fd..6ef422f8a483 100644 --- a/src/team.hpp +++ b/src/team.hpp @@ -19,7 +19,6 @@ #include "utils/make_enum.hpp" #include "map/location.hpp" #include "recall_list_manager.hpp" -#include "savegame_config.hpp" #include "units/ptr.hpp" #include "util.hpp" #include "config.hpp" @@ -48,7 +47,7 @@ namespace wb { * This class stores all the data for a single 'side' (in game nomenclature). * E.g., there is only one leader unit per team. */ -class team : public savegame::savegame_config +class team { public: diff --git a/src/tod_manager.cpp b/src/tod_manager.cpp index 73713a880d84..8a09002900de 100644 --- a/src/tod_manager.cpp +++ b/src/tod_manager.cpp @@ -37,7 +37,6 @@ static lg::log_domain log_engine("engine"); #define LOG_NG LOG_STREAM(info, log_engine) tod_manager::tod_manager(const config& scenario_cfg): - savegame_config(), currentTime_(0), times_(), areas_(), @@ -91,7 +90,7 @@ void tod_manager::resolve_random(random_new::rng& r) //comma-separated string of integers >= 1 referring to the times_ array indices std::vector output; boost::copy( utils::split(random_tod_.str()) - | boost::adaptors::transformed(std::bind(lexical_cast_default, _1 , 0)) + | boost::adaptors::transformed(boost::bind(lexical_cast_default, _1 , 0)) | boost::adaptors::filtered(greater(0)) , std::back_inserter(output) ); diff --git a/src/tod_manager.hpp b/src/tod_manager.hpp index eb3a6485869e..8fe7d145a77a 100644 --- a/src/tod_manager.hpp +++ b/src/tod_manager.hpp @@ -17,7 +17,6 @@ #include "map/location.hpp" #include "config.hpp" #include "time_of_day.hpp" -#include "savegame_config.hpp" #include @@ -31,7 +30,7 @@ namespace random_new } //time of day and turn functionality -class tod_manager : public savegame::savegame_config +class tod_manager { public: explicit tod_manager(const config& scenario_cfg = config()); diff --git a/src/units/types.cpp b/src/units/types.cpp index 8582df2df7ff..36fb6064f6bf 100644 --- a/src/units/types.cpp +++ b/src/units/types.cpp @@ -34,7 +34,6 @@ #include "gui/auxiliary/formula.hpp" #include "gui/dialogs/loadscreen.hpp" -#include #include static lg::log_domain log_config("config"); @@ -830,7 +829,7 @@ MAKE_ENUM (ALIGNMENT_FEMALE_VARIATION, std::string unit_type::alignment_description(ALIGNMENT align, unit_race::GENDER gender) { - BOOST_STATIC_ASSERT(ALIGNMENT_FEMALE_VARIATION::count == ALIGNMENT::count); + static_assert(ALIGNMENT_FEMALE_VARIATION::count == ALIGNMENT::count, "ALIGNMENT_FEMALE_VARIATION and ALIGNMENT do not have the same number of values"); assert(align.valid()); std::string str = std::string(); if (gender == unit_race::FEMALE) { diff --git a/src/utils/context_free_grammar_generator.cpp b/src/utils/context_free_grammar_generator.cpp new file mode 100644 index 000000000000..f9733bb185ef --- /dev/null +++ b/src/utils/context_free_grammar_generator.cpp @@ -0,0 +1,123 @@ +/* + Copyright (C) 2016 by Ján Dugáček + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +/** + * @file + * Algorithm to generate names using a context-free grammar, which allows more control + * than the usual Markov chain generator + */ + +#include "context_free_grammar_generator.hpp" +#include "../log.hpp" +#include "../random_new.hpp" + +context_free_grammar_generator::context_free_grammar_generator() : + initialized_(false) +{ + +} + +context_free_grammar_generator::~context_free_grammar_generator() +{ + +} + +bool context_free_grammar_generator::constructFromString(const std::string &source) { + const char* reading = source.c_str(); + nonterminal* current = nullptr; + std::vector* filled = nullptr; + std::string buf; + + while (*reading != 0) { + if (*reading == '=') { + current = &nonterminals_[buf]; + current->possibilities_.push_back(std::vector()); + filled = ¤t->possibilities_.back(); + buf.clear(); + } else if (*reading == '\n') { + if (filled) filled->push_back(buf); + filled = nullptr; + current = nullptr; + buf.clear(); + } else if (*reading == '|') { + if (!filled || !current) { + lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced | symbol"; + return false; + } + filled->push_back(buf); + current->possibilities_.push_back(std::vector()); + filled = ¤t->possibilities_.back(); + buf.clear(); + } else if (*reading == '\\' && reading[1] == 'n') { + reading++; + buf.push_back('\n'); + } else if (*reading == '\\' && reading[1] == 't') { + reading++; + buf.push_back('\t'); + } else { + if (*reading == '{') { + if (!filled) { + lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced { symbol"; + return false; + } + filled->push_back(buf); + buf.clear(); + } + if (*reading == '}') { + if (!filled) { + lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced } symbol"; + return false; + } + filled->push_back(buf); + buf.clear(); + } else buf.push_back(*reading); + } + reading++; + } + if (filled) filled->push_back(buf); + + initialized_ = true; + return true; +} + +std::string context_free_grammar_generator::print_nonterminal(const std::string& name, uint32_t* seed, short seed_pos) const { + std::string result; + std::map::const_iterator found = nonterminals_.find(name); + if (found == nonterminals_.end()) { + lg::wml_error() << "[context_free_grammar_generator] Warning: needed nonterminal " << name << " not defined"; + return "!" + name; + } + const context_free_grammar_generator::nonterminal& got = found->second; + unsigned int picked = seed[seed_pos++] % got.possibilities_.size(); + if (seed_pos >= seed_size) seed_pos = 0; + if (picked == got.last_) { + picked = seed[seed_pos++] % got.possibilities_.size(); + if (seed_pos >= seed_size) seed_pos = 0; + } + const_cast(got.last_) = picked; /* The variable last_ can change, the rest must stay const */ + const std::vector& used = got.possibilities_[picked]; + for (unsigned int i = 0; i < used.size(); i++) { + if (used[i][0] == '{') result += print_nonterminal(used[i].substr(1), seed, seed_pos); + else result += used[i]; + } + return result; +} + +std::string context_free_grammar_generator::generate() const { + uint32_t seed[seed_size]; + for (unsigned short int i = 0; i < seed_size; i++) { + seed[i] = random_new::generator->next_random(); + } + return print_nonterminal("main", seed, 0); +} diff --git a/src/utils/context_free_grammar_generator.hpp b/src/utils/context_free_grammar_generator.hpp new file mode 100644 index 000000000000..a4465fbc8ac2 --- /dev/null +++ b/src/utils/context_free_grammar_generator.hpp @@ -0,0 +1,61 @@ +/* + Copyright (C) 2016 by Ján Dugáček + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#ifndef CONTEXT_FREE_GRAMMAR_GENERATOR_INCLUDED +#define CONTEXT_FREE_GRAMMAR_GENERATOR_INCLUDED + +#include +#include +#include +#include + +class context_free_grammar_generator +{ +private: + + struct nonterminal { + nonterminal() : last_(1) {} + std::vector > possibilities_; + unsigned int last_; + }; + + std::map nonterminals_; + bool initialized_; + std::string print_nonterminal(const std::string& name, uint32_t* seed, short int seed_pos) const; + static const short unsigned int seed_size = 20; + +public: + /** Default constructor */ + context_free_grammar_generator(); + + /** Initialisation + * @param source the definition of the context-free grammar to use + * @returns if the operation was successful + */ + bool constructFromString(const std::string& source); + + /** Generates a possible word in the grammar set before + * @returns the word + */ + std::string generate() const; + + ~context_free_grammar_generator(); + + /** Checks if the object is initialized + * @returns if it is initialized + */ + bool is_initialized() const {return initialized_; } +}; + +#endif diff --git a/src/utils/functional.hpp b/src/utils/functional.hpp index 90f5bcf4271e..10ec58b3bdf1 100644 --- a/src/utils/functional.hpp +++ b/src/utils/functional.hpp @@ -18,8 +18,114 @@ #ifndef INCL_FUNCTIONAL_HPP_ #define INCL_FUNCTIONAL_HPP_ +#include "global.hpp" #include +#include // Because std::bind is just not flexible enough -using namespace std::placeholders; +// We'd like to just say "using namespace std::placeholders", but unfortunately +// that clashes with Boost.Bind's placeholders in some cases (even if bind.hpp is not included). +// Instead, we specialize std::is_placeholder for the Boost placeholders, +// so that Boost placeholders can be passed to std::bind. + +namespace std { // Some compilers can't handle it being specialized in the global scope + template + struct is_placeholder> : public integral_constant {}; +} + +namespace detail { + template + struct apply { + using result_type = void; + apply(std::function fcn) : fcn(fcn) {} + void operator()(T... params) { + fcn(std::forward(params)...); + } + private: + std::function fcn; + }; + + template + apply make_apply(std::function fcn) { + return apply(fcn); + } + + template + struct function_base { + using type = typename function_base::type; + }; + + template + struct function_base { + typedef Ret type(P...); + }; + + template + struct function_base { + typedef Ret type(P...); + }; + + template + struct function_base { + typedef Ret type(Class,P...); + }; + + template + struct function_base { + typedef Ret type(const Class,P...); + }; + + template + struct function_base { + typedef Ret type(volatile Class,P...); + }; + + template + struct function_base { + typedef Ret type(const volatile Class,P...); + }; + + template + struct function_base> { + typedef Ret type(P...); + }; +} + +template +auto bind_void(F fcn, P... bindings) +#ifndef HAVE_CXX14 +-> decltype(boost::bind( + detail::make_apply(std::function::type>(fcn)), bindings...) +) +#endif +{ + using T = typename detail::function_base::type; + return boost::bind(detail::make_apply(std::function(fcn)), bindings...); +} + +template +auto bind_void_exact(F fcn, P... bindings) +#ifndef HAVE_CXX14 +-> decltype( + boost::bind(detail::make_apply(std::function::type>(fcn)), bindings...) +) +#endif +{ + using T = typename detail::function_base::type; + return std::bind(detail::make_apply(std::function(fcn)), bindings...); +} + +/* A note on why std::bind is not flexible enough: + +1. The functions produced do not silently consume extra parameters passed to them. +This is not a bad thing per se, but some of Wesnoth's code relied on it. +It's useful behaviour, as well. + +2. A function that returns a value cannot be bound in a function type that returns void. +This is also relied upon in several places. + +If behaviour #1 is needed, we need to use boost::bind. For behaviour #2, this won't work; +instead, the bind_void function is provided. (This also provides behaviour #1. +To get #2 without #1, use bind_void_exact.) +*/ #endif diff --git a/src/utils/reference_counter.hpp b/src/utils/reference_counter.hpp index 70f21c11d05f..995e638384f4 100644 --- a/src/utils/reference_counter.hpp +++ b/src/utils/reference_counter.hpp @@ -21,7 +21,6 @@ #include -#include namespace n_ref_counter { @@ -32,7 +31,7 @@ namespace n_ref_counter { So any negative count disables reference counting. **/ template class t_ref_counter { - BOOST_STATIC_ASSERT( std::numeric_limits::is_signed); + static_assert(std::numeric_limits::is_signed, "Reference counter must be a signed integer"); T_integral count_; diff --git a/src/whiteboard/manager.cpp b/src/whiteboard/manager.cpp index 7d312aaf7181..ef21f946bb92 100644 --- a/src/whiteboard/manager.cpp +++ b/src/whiteboard/manager.cpp @@ -480,7 +480,7 @@ namespace public: move_owners_finder(): move_owners_() { } - void operator()(action_ptr action) { + void operator()(action* action) { action->accept(*this); } @@ -513,7 +513,7 @@ namespace void manager::pre_draw() { - if (can_modify_game_state() && has_actions()) { + if (can_modify_game_state() && has_actions() && unit_map_lock_.unique()) { move_owners_finder move_finder; for_each_action(std::ref(move_finder)); units_owning_moves_ = move_finder.get_units_owning_moves(); diff --git a/src/whiteboard/utility.cpp b/src/whiteboard/utility.cpp index 30517e88d67a..5096ef0dd746 100644 --- a/src/whiteboard/utility.cpp +++ b/src/whiteboard/utility.cpp @@ -165,7 +165,7 @@ bool team_has_visible_plan(team &t) return !t.get_side_actions()->hidden(); } -void for_each_action(std::function function, team_filter team_filter) +void for_each_action(std::function function, team_filter team_filter) { bool end = false; for(size_t turn=0; !end; ++turn) { @@ -173,7 +173,9 @@ void for_each_action(std::function function, team_filter team_ for(team &side : *resources::teams) { side_actions &actions = *side.get_side_actions(); if(turn < actions.num_turns() && team_filter(side)) { - std::for_each(actions.turn_begin(turn), actions.turn_end(turn), function); + for(auto iter = actions.turn_begin(turn); iter != actions.turn_end(turn); ++iter) { + function(iter->get()); + } end = false; } } diff --git a/src/whiteboard/utility.hpp b/src/whiteboard/utility.hpp index 5c14eb39f180..ffa4ef24d415 100644 --- a/src/whiteboard/utility.hpp +++ b/src/whiteboard/utility.hpp @@ -126,7 +126,7 @@ bool team_has_visible_plan(team&); * @param function the function to execute. * @param team_filter select whether a team is visited (default to @ref team_has_visible_plan). */ -void for_each_action(std::function function, +void for_each_action(std::function function, team_filter team_filter = team_has_visible_plan); /** diff --git a/src/widgets/scrollbar.cpp b/src/widgets/scrollbar.cpp index ef1b85065def..d8f562127699 100644 --- a/src/widgets/scrollbar.cpp +++ b/src/widgets/scrollbar.cpp @@ -27,21 +27,21 @@ #include namespace { - const std::string scrollbar_top = "buttons/scrollbars/scrolltop.png"; - const std::string scrollbar_bottom = "buttons/scrollbars/scrollbottom.png"; - const std::string scrollbar_mid = "buttons/scrollbars/scrollmid.png"; + const std::string scrollbar_top = "buttons/scrollbars_large/scrolltop.png"; + const std::string scrollbar_bottom = "buttons/scrollbars_large/scrollbottom.png"; + const std::string scrollbar_mid = "buttons/scrollbars_large/scrollmid.png"; - const std::string scrollbar_top_hl = "buttons/scrollbars/scrolltop-active.png"; - const std::string scrollbar_bottom_hl = "buttons/scrollbars/scrollbottom-active.png"; - const std::string scrollbar_mid_hl = "buttons/scrollbars/scrollmid-active.png"; + const std::string scrollbar_top_hl = "buttons/scrollbars_large/scrolltop-active.png"; + const std::string scrollbar_bottom_hl = "buttons/scrollbars_large/scrollbottom-active.png"; + const std::string scrollbar_mid_hl = "buttons/scrollbars_large/scrollmid-active.png"; - const std::string scrollbar_top_pressed = "buttons/scrollbars/scrolltop-pressed.png"; - const std::string scrollbar_bottom_pressed = "buttons/scrollbars/scrollbottom-pressed.png"; - const std::string scrollbar_mid_pressed = "buttons/scrollbars/scrollmid-pressed.png"; + const std::string scrollbar_top_pressed = "buttons/scrollbars_large/scrolltop-pressed.png"; + const std::string scrollbar_bottom_pressed = "buttons/scrollbars_large/scrollbottom-pressed.png"; + const std::string scrollbar_mid_pressed = "buttons/scrollbars_large/scrollmid-pressed.png"; - const std::string groove_top = "buttons/scrollbars/scrollgroove-top.png"; - const std::string groove_mid = "buttons/scrollbars/scrollgroove-mid.png"; - const std::string groove_bottom = "buttons/scrollbars/scrollgroove-bottom.png"; + const std::string groove_top = "buttons/scrollbars_large/scrollgroove-top.png"; + const std::string groove_mid = "buttons/scrollbars_large/scrollgroove-mid.png"; + const std::string groove_bottom = "buttons/scrollbars_large/scrollgroove-bottom.png"; }